minor changes
This commit is contained in:
@@ -1,3 +1,41 @@
|
||||
# servo2350
|
||||
|
||||
Custom PCB with RP2350. Mainly used for hexapods and driving servo motors.
|
||||
Custom PCB with RP2350. Mainly used for hexapods and driving 18x servo motors with 18x ADC feedback through multiplexer.
|
||||
|
||||

|
||||
|
||||
## Specs
|
||||
|
||||
* **CPU:** RP2350B with debug pins
|
||||
* **FLASH:** W25Q16JVUXIQ_TR 16Mbit NOR quad SPI memory
|
||||
* **OUTPUT:** 18x PWM, 6x digital output (3 pin header), 2x LEDs, extra pins in header
|
||||
* **INPUT:** 18x ADC though a CD74HC4067 multiplexer
|
||||
* **SENSORS:** ICM-45686 IMU
|
||||
* **SERIAL:** SPI, I2C, USB, UART
|
||||
|
||||
## Test code commands
|
||||
|
||||
> [!WARNING]
|
||||
> The zephyr sdk has bug in the [rp2350 pinctrl](https://github.com/zephyrproject-rtos/zephyr/blob/main/include/zephyr/dt-bindings/pinctrl/rpi-pico-rp2350-pinctrl-common.h) file. The `RP2_PINCTRL_GPIO_FUNC_UART_AUX` macro is defind, but `RP2_PINCTRL_GPIO_FUNC_UART_ALT` macro is used.
|
||||
|
||||
> [!NOTE]
|
||||
> While shell is over USB, the `adc scan_for` command uses uart. The UART uses spi1 pins, so the spi1 needs to be disabled and `extra_uart.overlay` needs to be used.
|
||||
|
||||
|
||||
| Command | Parameters | Description |
|
||||
| --------------------------- | ---------------------------- | --------------------------------------------------- |
|
||||
| `led set <id> <on\|off>` | `id`: `0-1` | Set LED state |
|
||||
| `led allon` | - | Turn all LEDs ON |
|
||||
| `led alloff` | - | Turn all LEDs OFF |
|
||||
| `servo set <id> <angle>` | Servo ID, angle in degrees | Set servo angle |
|
||||
| `adc read <id>` | ADC channel ID | Read a single ADC channel |
|
||||
| `adc read_for <id> <count>` | ADC channel ID, sample count | Read one ADC channel repeatedly |
|
||||
| `adc scan` | - | Read all ADC channels once |
|
||||
| `adc scan_for <count>` | `count ≤ 1024` | Read all ADC channels repeatedly and log timestamps |
|
||||
|
||||
### UART Output Formats
|
||||
|
||||
| Command | Output Format |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| `adc scan` | `ADC,<channel>,<value>` |
|
||||
| `adc scan_for` | `<sample>,ADC,<channel>,<value>,<timestamp_cycles>` |
|
||||
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 571 KiB |
Binary file not shown.
Binary file not shown.
Executable → Regular
BIN
Binary file not shown.
@@ -3,8 +3,14 @@
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
set(BOARD_ROOT ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
# set(EXTRA_DTC_OVERLAY_FILE extra_adc.overlay)
|
||||
set(EXTRA_DTC_OVERLAY_FILE extra_uart.overlay)
|
||||
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
project(servo2350)
|
||||
|
||||
|
||||
add_subdirectory(drivers)
|
||||
|
||||
FILE(GLOB app_sources src/*.c)
|
||||
target_sources(app PRIVATE ${app_sources})
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
source "Kconfig.zephyr"
|
||||
|
||||
rsource "drivers/Kconfig"
|
||||
@@ -1,97 +0,0 @@
|
||||
.. zephyr:code-sample:: blinky
|
||||
:name: Blinky
|
||||
:relevant-api: gpio_interface
|
||||
|
||||
Blink an LED forever using the GPIO API.
|
||||
|
||||
Overview
|
||||
********
|
||||
|
||||
The Blinky sample blinks an LED forever using the :ref:`GPIO API <gpio_api>`.
|
||||
|
||||
The source code shows how to:
|
||||
|
||||
#. Get a pin specification from the :ref:`devicetree <dt-guide>` as a
|
||||
:c:struct:`gpio_dt_spec`
|
||||
#. Configure the GPIO pin as an output
|
||||
#. Toggle the pin forever
|
||||
|
||||
See :zephyr:code-sample:`pwm-blinky` for a similar sample that uses the PWM API instead.
|
||||
|
||||
.. _blinky-sample-requirements:
|
||||
|
||||
Requirements
|
||||
************
|
||||
|
||||
Your board must:
|
||||
|
||||
#. Have an LED connected via a GPIO pin (these are called "User LEDs" on many of
|
||||
Zephyr's :ref:`boards`).
|
||||
#. Have the LED configured using the ``led0`` devicetree alias.
|
||||
|
||||
Building and Running
|
||||
********************
|
||||
|
||||
Build and flash Blinky as follows, changing ``reel_board`` for your board:
|
||||
|
||||
.. zephyr-app-commands::
|
||||
:zephyr-app: samples/basic/blinky
|
||||
:board: reel_board
|
||||
:goals: build flash
|
||||
:compact:
|
||||
|
||||
After flashing, the LED starts to blink and messages with the current LED state
|
||||
are printed on the console. If a runtime error occurs, the sample exits without
|
||||
printing to the console.
|
||||
|
||||
Build errors
|
||||
************
|
||||
|
||||
You will see a build error at the source code line defining the ``struct
|
||||
gpio_dt_spec led`` variable if you try to build Blinky for an unsupported
|
||||
board.
|
||||
|
||||
On GCC-based toolchains, the error looks like this:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
error: '__device_dts_ord_DT_N_ALIAS_led_P_gpios_IDX_0_PH_ORD' undeclared here (not in a function)
|
||||
|
||||
Adding board support
|
||||
********************
|
||||
|
||||
To add support for your board, add something like this to your devicetree:
|
||||
|
||||
.. code-block:: DTS
|
||||
|
||||
/ {
|
||||
aliases {
|
||||
led0 = &myled0;
|
||||
};
|
||||
|
||||
leds {
|
||||
compatible = "gpio-leds";
|
||||
myled0: led_0 {
|
||||
gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
The above sets your board's ``led0`` alias to use pin 13 on GPIO controller
|
||||
``gpio0``. The pin flags :c:macro:`GPIO_ACTIVE_LOW` mean the LED is on when
|
||||
the pin is set to its low state, and off when the pin is in its high state.
|
||||
|
||||
Tips:
|
||||
|
||||
- See :dtcompatible:`gpio-leds` for more information on defining GPIO-based LEDs
|
||||
in devicetree.
|
||||
|
||||
- If you're not sure what to do, check the devicetrees for supported boards which
|
||||
use the same SoC as your target. See :ref:`get-devicetree-outputs` for details.
|
||||
|
||||
- See :zephyr_file:`include/zephyr/dt-bindings/gpio/gpio.h` for the flags you can use
|
||||
in devicetree.
|
||||
|
||||
- If the LED is built in to your board hardware, the alias should be defined in
|
||||
your :ref:`BOARD.dts file <devicetree-in-out-files>`. Otherwise, you can
|
||||
define one in a :ref:`devicetree overlay <set-devicetree-overlays>`.
|
||||
@@ -1,74 +1,56 @@
|
||||
#include <zephyr/dt-bindings/pinctrl/rpi-pico-rp2350b-pinctrl.h>
|
||||
|
||||
&pinctrl {
|
||||
uart0_default: uart0_default {
|
||||
group1 {
|
||||
pinmux = <UART0_TX_P0>;
|
||||
};
|
||||
|
||||
group2 {
|
||||
pinmux = <UART0_RX_P1>;
|
||||
input-enable;
|
||||
};
|
||||
};
|
||||
|
||||
uart1_default: uart1_default {
|
||||
// These are the same pins as SPI
|
||||
group1 {
|
||||
pinmux = <UART1_TX_P26>;
|
||||
};
|
||||
|
||||
group2 {
|
||||
pinmux = <UART1_RX_P27>;
|
||||
input-enable;
|
||||
};
|
||||
};
|
||||
|
||||
i2c0_default: i2c0_default {
|
||||
group1 {
|
||||
pinmux = <I2C0_SDA_P36>, <I2C0_SCL_P37>;
|
||||
pinmux = <I2C0_SDA_P36>, // SDA
|
||||
<I2C0_SCL_P37>; // SCL
|
||||
input-enable;
|
||||
input-schmitt-enable;
|
||||
};
|
||||
};
|
||||
|
||||
spi0_default: spi0_default {
|
||||
spi1_default: spi1_default {
|
||||
group1 {
|
||||
pinmux = <SPI0_CSN_P17>, <SPI0_SCK_P18>, <SPI0_TX_P19>;
|
||||
pinmux = <SPI1_CSN_P29>, // D29
|
||||
<SPI1_SCK_P26>, // SPI_CLK
|
||||
<SPI1_TX_P27>; // SPI_MOSI
|
||||
};
|
||||
|
||||
group2 {
|
||||
pinmux = <SPI0_RX_P16>;
|
||||
pinmux = <SPI1_RX_P28>; // SPI_MISO
|
||||
input-enable;
|
||||
};
|
||||
};
|
||||
|
||||
pwm_default: pwm_default {
|
||||
group1 {
|
||||
pinmux = <PWM_0A_P0>,
|
||||
<PWM_0B_P1>,
|
||||
<PWM_1A_P2>,
|
||||
<PWM_1B_P3>,
|
||||
<PWM_2A_P4>,
|
||||
<PWM_2B_P5>,
|
||||
<PWM_3A_P6>,
|
||||
<PWM_3B_P7>,
|
||||
<PWM_4A_P8>,
|
||||
<PWM_4B_P9>,
|
||||
<PWM_5A_P10>,
|
||||
<PWM_5B_P11>,
|
||||
<PWM_6A_P12>,
|
||||
<PWM_6B_P13>,
|
||||
<PWM_7A_P14>,
|
||||
<PWM_7B_P15>,
|
||||
<PWM_8A_P32>,
|
||||
<PWM_8B_P33>;
|
||||
pinmux = <PWM_0A_P0>, // SERVO 1
|
||||
<PWM_0B_P1>, // SERVO 2
|
||||
<PWM_1A_P2>, // SERVO 3
|
||||
<PWM_1B_P3>, // SERVO 4
|
||||
<PWM_2A_P4>, // SERVO 5
|
||||
<PWM_2B_P5>, // SERVO 6
|
||||
<PWM_3A_P6>, // SERVO 7
|
||||
<PWM_3B_P7>, // SERVO 8
|
||||
<PWM_4A_P8>, // SERVO 9
|
||||
<PWM_4B_P9>, // SERVO 10
|
||||
<PWM_5A_P10>, // SERVO 11
|
||||
<PWM_5B_P11>, // SERVO 12
|
||||
<PWM_6A_P12>, // SERVO 13
|
||||
<PWM_6B_P13>, // SERVO 14
|
||||
<PWM_7A_P14>, // SERVO 15
|
||||
<PWM_7B_P15>, // SERVO 16
|
||||
<PWM_8A_P32>, // SERVO 17
|
||||
<PWM_8B_P33>; // SERVO 18
|
||||
};
|
||||
};
|
||||
|
||||
adc_default: adc_default {
|
||||
group1 {
|
||||
pinmux = <ADC_CH0_P40>, <ADC_CH1_P41>, <ADC_CH2_P42>, <ADC_CH3_P43>;
|
||||
pinmux = <ADC_CH0_P40>, // MUX_COMMON
|
||||
<ADC_CH1_P41>, // SERVO 17
|
||||
<ADC_CH2_P42>; // SERVO 18
|
||||
input-enable;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
};
|
||||
|
||||
zephyr,user {
|
||||
io-channels = <&adc 0>, /* ADC channel 1 (adc2) - connected to mux */
|
||||
<&adc 1>, /* ADC channel 0 (adc1) - direct channel 16 */
|
||||
<&adc 2>; /* ADC channel 2 (adc3) - direct channel 17 */
|
||||
io-channels = <&adc 0>,
|
||||
<&adc 1>,
|
||||
<&adc 2>;
|
||||
};
|
||||
|
||||
leds {
|
||||
@@ -41,6 +41,11 @@
|
||||
gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>;
|
||||
label = "IMU_INT1";
|
||||
};
|
||||
|
||||
imu_int2: imu_int2 {
|
||||
gpios = <&gpio0 23 GPIO_ACTIVE_HIGH>;
|
||||
label = "IMU_INT2";
|
||||
};
|
||||
};
|
||||
|
||||
digital_inputs {
|
||||
@@ -178,13 +183,22 @@
|
||||
};
|
||||
};
|
||||
|
||||
mux: mux {
|
||||
compatible = "cd74hc4067";
|
||||
status = "okay";
|
||||
select-gpios = <&gpio0_hi 2 GPIO_ACTIVE_HIGH>,
|
||||
<&gpio0_hi 3 GPIO_ACTIVE_HIGH>,
|
||||
<&gpio0_hi 6 GPIO_ACTIVE_HIGH>,
|
||||
<&gpio0_hi 7 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
|
||||
aliases {
|
||||
watchdog0 = &wdt0;
|
||||
led0 = &led0;
|
||||
led1 = &led1;
|
||||
imu = &icm45686;
|
||||
imu = &imu;
|
||||
imu-int1 = &imu_int1;
|
||||
imu-int2 = &imu_int2;
|
||||
digital1 = &digital1;
|
||||
digital2 = &digital2;
|
||||
digital3 = &digital3;
|
||||
@@ -215,45 +229,7 @@
|
||||
servo16 = &servo16;
|
||||
servo17 = &servo17;
|
||||
servo18 = &servo18;
|
||||
adc-mux = &adc1;
|
||||
adc0 = &adc1;
|
||||
adc2 = &adc2;
|
||||
adc3 = &adc3;
|
||||
uart0 = &uart0;
|
||||
uart-bridge = &uart1;
|
||||
};
|
||||
|
||||
pico_header: connector {
|
||||
compatible = "raspberrypi,pico-header";
|
||||
#gpio-cells = <2>;
|
||||
gpio-map-mask = <0xffffffff 0xffffffc0>;
|
||||
gpio-map-pass-thru = <0 0x3f>;
|
||||
gpio-map = <0 0 &gpio0 0 0>, /* GP0 */
|
||||
<1 0 &gpio0 1 0>, /* GP1 */
|
||||
<2 0 &gpio0 2 0>, /* GP2 */
|
||||
<3 0 &gpio0 3 0>, /* GP3 */
|
||||
<4 0 &gpio0 4 0>, /* GP4 */
|
||||
<5 0 &gpio0 5 0>, /* GP5 */
|
||||
<6 0 &gpio0 6 0>, /* GP6 */
|
||||
<7 0 &gpio0 7 0>, /* GP7 */
|
||||
<8 0 &gpio0 8 0>, /* GP8 */
|
||||
<9 0 &gpio0 9 0>, /* GP9 */
|
||||
<10 0 &gpio0 10 0>, /* GP10 */
|
||||
<11 0 &gpio0 11 0>, /* GP11 */
|
||||
<12 0 &gpio0 12 0>, /* GP12 */
|
||||
<13 0 &gpio0 13 0>, /* GP13 */
|
||||
<14 0 &gpio0 14 0>, /* GP14 */
|
||||
<15 0 &gpio0 15 0>, /* GP15 */
|
||||
<16 0 &gpio0 16 0>, /* GP16 */
|
||||
<17 0 &gpio0 17 0>, /* GP17 */
|
||||
<18 0 &gpio0 18 0>, /* GP18 */
|
||||
<19 0 &gpio0 19 0>, /* GP19 */
|
||||
<20 0 &gpio0 20 0>, /* GP20 */
|
||||
<21 0 &gpio0 21 0>, /* GP21 */
|
||||
<22 0 &gpio0 22 0>, /* GP22 */
|
||||
<26 0 &gpio0 26 0>, /* GP26 */
|
||||
<27 0 &gpio0 27 0>, /* GP27 */
|
||||
<28 0 &gpio0 28 0>; /* GP28 */
|
||||
mux = &mux;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -287,25 +263,11 @@
|
||||
};
|
||||
};
|
||||
|
||||
&uart0 {
|
||||
current-speed = <115200>;
|
||||
status = "okay";
|
||||
pinctrl-0 = <&uart0_default>;
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
|
||||
&uart1 {
|
||||
current-speed = <115200>;
|
||||
status = "okay";
|
||||
pinctrl-0 = <&uart1_default>;
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
|
||||
zephyr_udc0: &usbd {
|
||||
status = "okay";
|
||||
cdc_acm_uart0: cdc_acm_uart0 {
|
||||
compatible = "zephyr,cdc-acm-uart";
|
||||
label = "Zephyr USB CDC-ACM";
|
||||
label = "USB_CDC";
|
||||
};
|
||||
};
|
||||
|
||||
@@ -318,20 +280,13 @@ gpio0_lo: &gpio0 {
|
||||
|
||||
};
|
||||
|
||||
&spi0 {
|
||||
clock-frequency = <DT_FREQ_M(8)>;
|
||||
pinctrl-0 = <&spi0_default>;
|
||||
pinctrl-names = "default";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
&i2c0 {
|
||||
pinctrl-0 = <&i2c0_default>;
|
||||
pinctrl-names = "default";
|
||||
status = "okay";
|
||||
clock-frequency = <I2C_BITRATE_FAST>;
|
||||
|
||||
icm45686: icm45686@68 {
|
||||
imu: icm45686@68 {
|
||||
compatible = "invensense,icm42688";
|
||||
reg = <0x68>;
|
||||
status = "okay";
|
||||
@@ -350,14 +305,21 @@ gpio0_lo: &gpio0 {
|
||||
};
|
||||
};
|
||||
|
||||
adc0: &adc {
|
||||
&spi1 {
|
||||
clock-frequency = <DT_FREQ_M(8)>;
|
||||
pinctrl-0 = <&spi1_default>;
|
||||
pinctrl-names = "default";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
&adc {
|
||||
pinctrl-0 = <&adc_default>;
|
||||
pinctrl-names = "default";
|
||||
status = "okay";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
adc1: channel@0 {
|
||||
adc0: channel@0 {
|
||||
reg = <0>;
|
||||
zephyr,gain = "ADC_GAIN_1";
|
||||
zephyr,reference = "ADC_REF_INTERNAL";
|
||||
@@ -365,7 +327,7 @@ adc0: &adc {
|
||||
zephyr,resolution = <12>;
|
||||
};
|
||||
|
||||
adc2: channel@1 {
|
||||
adc1: channel@1 {
|
||||
reg = <1>;
|
||||
zephyr,gain = "ADC_GAIN_1";
|
||||
zephyr,reference = "ADC_REF_INTERNAL";
|
||||
@@ -373,7 +335,7 @@ adc0: &adc {
|
||||
zephyr,resolution = <12>;
|
||||
};
|
||||
|
||||
adc3: channel@2 {
|
||||
adc2: channel@2 {
|
||||
reg = <2>;
|
||||
zephyr,gain = "ADC_GAIN_1";
|
||||
zephyr,reference = "ADC_REF_INTERNAL";
|
||||
@@ -392,15 +354,3 @@ adc0: &adc {
|
||||
&timer0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
pico_spi: &spi0 {};
|
||||
|
||||
pico_i2c0: &i2c0 {};
|
||||
|
||||
pico_i2c1: &i2c1 {};
|
||||
|
||||
pico_serial: &uart0 {};
|
||||
|
||||
zephyr_i2c: &i2c0 {};
|
||||
|
||||
imu: &icm45686 {};
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
if(CONFIG_CD74HC4067)
|
||||
target_sources(app PRIVATE ${CMAKE_CURRENT_LIST_DIR}/cd74hc4067.c)
|
||||
target_include_directories(app PRIVATE ${CMAKE_CURRENT_LIST_DIR})
|
||||
endif()
|
||||
|
||||
target_sources(app PRIVATE ${CMAKE_CURRENT_LIST_DIR}/cd74hc4067.c)
|
||||
|
||||
target_include_directories(app PRIVATE ${CMAKE_CURRENT_LIST_DIR})
|
||||
@@ -2,8 +2,8 @@ menuconfig CD74HC4067
|
||||
bool "TI CD74HC4067 analog multiplexer"
|
||||
depends on GPIO
|
||||
help
|
||||
Enable support for the TI CD74HC4067 16-channel analog/digital
|
||||
multiplexer/demultiplexer controlled through GPIO selection pins.
|
||||
Enable support for the TI CD74HC4067 16-channel analog
|
||||
multiplexer controlled through GPIO selection pins.
|
||||
|
||||
if CD74HC4067
|
||||
|
||||
@@ -11,10 +11,10 @@ config CD74HC4067_INIT_PRIORITY
|
||||
int "Initialization priority"
|
||||
default 80
|
||||
help
|
||||
Device initialization priority for the CD74HC4067 driver. This should
|
||||
be higher (lower numeric value) than any clients that depend on the
|
||||
multiplexer being ready.
|
||||
Device initialization priority for the CD74HC4067 driver.
|
||||
|
||||
|
||||
# Creates "CONFIG_CD74HC4067_LOG_LEVEL"
|
||||
module = CD74HC4067
|
||||
module-str = cd74hc4067
|
||||
source "subsys/logging/Kconfig.template.log_config"
|
||||
|
||||
@@ -1,42 +1,74 @@
|
||||
|
||||
#define DT_DRV_COMPAT cd74hc4067
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/devicetree.h>
|
||||
#include <zephyr/drivers/gpio.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
|
||||
#include "cd74hc4067.h"
|
||||
|
||||
LOG_MODULE_REGISTER(cd74hc4067, CONFIG_CD74HC4067_LOG_LEVEL);
|
||||
LOG_MODULE_REGISTER(cd74hc4067);
|
||||
|
||||
#define CD74HC4067_CHANNEL_COUNT 16U
|
||||
#define CD74HC4067_SELECTION_PIN_COUNT 4U
|
||||
//-------------------------------------------------------------------------
|
||||
// Declarations
|
||||
|
||||
struct cd74hc4067_config {
|
||||
struct gpio_dt_spec sel[CD74HC4067_SELECTION_PIN_COUNT];
|
||||
struct gpio_dt_spec enable;
|
||||
bool has_enable;
|
||||
};
|
||||
static int cd74hc4067_init(const struct device *dev);
|
||||
static int cd74hc4067_enable_pin(const struct device *dev, bool state);
|
||||
|
||||
struct cd74hc4067_data {
|
||||
struct k_mutex lock;
|
||||
uint8_t current_channel;
|
||||
bool enabled;
|
||||
};
|
||||
//-------------------------------------------------------------------------
|
||||
// Private
|
||||
|
||||
static int cd74hc4067_sync_enable_state(const struct device *dev, bool enable)
|
||||
{
|
||||
const struct cd74hc4067_config *cfg = dev->config;
|
||||
|
||||
static int cd74hc4067_init(const struct device *dev) {
|
||||
int ret;
|
||||
|
||||
const struct cd74hc4067_cfg *cfg = dev->config;
|
||||
struct cd74hc4067_data *data = dev->data;
|
||||
|
||||
k_mutex_init(&data->lock);
|
||||
data->current_channel = 0U;
|
||||
data->enabled = !cfg->has_enable;
|
||||
|
||||
// Init the select pins
|
||||
for (int i = 0; i < CD74HC4067_SELECT_PIN_COUNT; i++) {
|
||||
const struct gpio_dt_spec *pin = &(cfg->select[i]);
|
||||
if (!gpio_is_ready_dt(pin)) {
|
||||
LOG_ERR("Select pin %d not ready.\r\n", i);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = gpio_pin_configure_dt(pin, GPIO_OUTPUT_INACTIVE);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Could not configure select pin %d as output\r\n", i);
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg->has_enable) {
|
||||
// Init the enable pin
|
||||
const struct gpio_dt_spec *enable = &cfg->enable;
|
||||
LOG_DBG("Initializing enable pin.\r\n");
|
||||
|
||||
if (!gpio_is_ready_dt(enable)) {
|
||||
LOG_ERR("Enable pin not ready.\r\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = gpio_pin_configure_dt(enable, GPIO_OUTPUT_INACTIVE);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Could not configure ENABLE pin as output\r\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cd74hc4067_enable_pin(const struct device *dev, bool state) {
|
||||
const struct cd74hc4067_cfg *cfg = dev->config;
|
||||
struct cd74hc4067_data *data = dev->data;
|
||||
int ret = 0;
|
||||
|
||||
if (!cfg->has_enable) {
|
||||
if (!enable) {
|
||||
if (!state) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
@@ -49,95 +81,68 @@ static int cd74hc4067_sync_enable_state(const struct device *dev, bool enable)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = gpio_pin_set_dt(&cfg->enable, enable ? 0 : 1);
|
||||
ret = gpio_pin_set_dt(&cfg->enable, state ? 0 : 1);
|
||||
if (ret == 0) {
|
||||
data->enabled = enable;
|
||||
data->enabled = state;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cd74hc4067_configure_gpios(const struct device *dev)
|
||||
{
|
||||
const struct cd74hc4067_config *cfg = dev->config;
|
||||
int ret;
|
||||
//-------------------------------------------------------------------------
|
||||
// Public
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(cfg->sel); i++) {
|
||||
const struct gpio_dt_spec *sel = &cfg->sel[i];
|
||||
|
||||
if (!device_is_ready(sel->port)) {
|
||||
LOG_ERR("%s sel%zu GPIO not ready", dev->name, i);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = gpio_pin_configure_dt(sel, GPIO_OUTPUT_INACTIVE);
|
||||
if (ret != 0) {
|
||||
LOG_ERR("%s failed to configure sel%zu GPIO (%d)", dev->name, i, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg->has_enable) {
|
||||
if (!device_is_ready(cfg->enable.port)) {
|
||||
LOG_ERR("%s enable GPIO not ready", dev->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = gpio_pin_configure_dt(&cfg->enable, GPIO_OUTPUT_HIGH);
|
||||
if (ret != 0) {
|
||||
LOG_ERR("%s failed to configure enable GPIO (%d)", dev->name, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cd74hc4067_init(const struct device *dev)
|
||||
{
|
||||
const struct cd74hc4067_config *cfg = dev->config;
|
||||
int cd74hc4067_enable(const struct device *dev) {
|
||||
struct cd74hc4067_data *data = dev->data;
|
||||
int ret;
|
||||
|
||||
k_mutex_init(&data->lock);
|
||||
data->current_channel = 0U;
|
||||
data->enabled = !cfg->has_enable;
|
||||
|
||||
ret = cd74hc4067_configure_gpios(dev);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Latch the default channel (0) */
|
||||
ret = cd74hc4067_select_channel(dev, 0U);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
LOG_INF("%s initialized (enable pin %s)", dev->name, cfg->has_enable ? "present" : "absent");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cd74hc4067_select_channel(const struct device *dev, uint8_t channel)
|
||||
{
|
||||
const struct cd74hc4067_config *cfg = dev->config;
|
||||
struct cd74hc4067_data *data = dev->data;
|
||||
int ret = 0;
|
||||
|
||||
if (channel >= CD74HC4067_CHANNEL_COUNT) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = k_mutex_lock(&data->lock, K_FOREVER);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(cfg->sel); i++) {
|
||||
ret = gpio_pin_set_dt(&cfg->sel[i], (channel >> i) & 0x1);
|
||||
if (ret != 0) {
|
||||
LOG_ERR("%s failed to drive sel%zu GPIO (%d)", dev->name, i, ret);
|
||||
ret = cd74hc4067_enable_pin(dev, true);
|
||||
|
||||
k_mutex_unlock(&data->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cd74hc4067_disable(const struct device *dev) {
|
||||
struct cd74hc4067_data *data = dev->data;
|
||||
int ret;
|
||||
|
||||
ret = k_mutex_lock(&data->lock, K_FOREVER);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = cd74hc4067_enable_pin(dev, false);
|
||||
|
||||
k_mutex_unlock(&data->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cd74hc4067_select_channel(const struct device *dev, uint8_t channel) {
|
||||
if (channel >= CD74HC4067_SELECT_CHANNEL_COUNT) {
|
||||
LOG_ERR("Channel not found.\r\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int ret;
|
||||
const struct cd74hc4067_cfg *cfg = dev->config;
|
||||
struct cd74hc4067_data *data = dev->data;
|
||||
|
||||
ret = k_mutex_lock(&data->lock, K_FOREVER);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Mutex error");
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (int i = 0; i < CD74HC4067_SELECT_PIN_COUNT; i++) {
|
||||
bool state = (channel >> i) & 0x1;
|
||||
ret = gpio_pin_set_dt(&cfg->select[i], state);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Unable to set channel pin: %d", ret);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -149,69 +154,38 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cd74hc4067_enable(const struct device *dev)
|
||||
{
|
||||
struct cd74hc4067_data *data = dev->data;
|
||||
int ret;
|
||||
//-------------------------------------------------------------------------
|
||||
// Devicetree
|
||||
|
||||
ret = k_mutex_lock(&data->lock, K_FOREVER);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
// static const struct cd74hc4067_api cd74hc4067_api_funcs = {
|
||||
// .enable = cd74hc4067_enable,
|
||||
// .disable = cd74hc4067_disable,
|
||||
// .select_channel = cd74hc4067_select_channel,
|
||||
// };
|
||||
|
||||
ret = cd74hc4067_sync_enable_state(dev, true);
|
||||
|
||||
k_mutex_unlock(&data->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cd74hc4067_disable(const struct device *dev)
|
||||
{
|
||||
struct cd74hc4067_data *data = dev->data;
|
||||
int ret;
|
||||
|
||||
ret = k_mutex_lock(&data->lock, K_FOREVER);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = cd74hc4067_sync_enable_state(dev, false);
|
||||
|
||||
k_mutex_unlock(&data->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t cd74hc4067_get_current_channel(const struct device *dev)
|
||||
{
|
||||
struct cd74hc4067_data *data = dev->data;
|
||||
uint8_t channel;
|
||||
|
||||
k_mutex_lock(&data->lock, K_FOREVER);
|
||||
channel = data->current_channel;
|
||||
k_mutex_unlock(&data->lock);
|
||||
|
||||
return channel;
|
||||
}
|
||||
|
||||
#define CD74HC4067_DEFINE(inst) \
|
||||
BUILD_ASSERT(DT_PROP_LEN(DT_DRV_INST(inst), sel_gpios) == CD74HC4067_SELECTION_PIN_COUNT, \
|
||||
"cd74hc4067 requires exactly 4 selection GPIOs"); \
|
||||
static const struct cd74hc4067_config cd74hc4067_config_##inst = { \
|
||||
.sel = { \
|
||||
GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), sel_gpios, 0), \
|
||||
GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), sel_gpios, 1), \
|
||||
GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), sel_gpios, 2), \
|
||||
GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), sel_gpios, 3), \
|
||||
}, \
|
||||
.enable = COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, enable_gpios), \
|
||||
(GPIO_DT_SPEC_GET(DT_DRV_INST(inst), enable_gpios)), \
|
||||
((struct gpio_dt_spec){0})), \
|
||||
.has_enable = DT_INST_NODE_HAS_PROP(inst, enable_gpios), \
|
||||
}; \
|
||||
static struct cd74hc4067_data cd74hc4067_data_##inst; \
|
||||
DEVICE_DT_INST_DEFINE(inst, cd74hc4067_init, NULL, &cd74hc4067_data_##inst, \
|
||||
&cd74hc4067_config_##inst, POST_KERNEL, \
|
||||
CONFIG_CD74HC4067_INIT_PRIORITY, NULL);
|
||||
#define CD74HC4067_DEFINE(inst) \
|
||||
\
|
||||
static const struct cd74hc4067_cfg cd74hc4067_cfg_##inst = { \
|
||||
.select = { \
|
||||
GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), select_gpios, 0), \
|
||||
GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), select_gpios, 1), \
|
||||
GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), select_gpios, 2), \
|
||||
GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), select_gpios, 3), \
|
||||
}, \
|
||||
.enable = COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, enable_gpio), \
|
||||
(GPIO_DT_SPEC_GET(DT_DRV_INST(inst), enable_gpio)), \
|
||||
((struct gpio_dt_spec){0})), \
|
||||
.has_enable = DT_INST_NODE_HAS_PROP(inst, enable_gpio), \
|
||||
}; \
|
||||
static struct cd74hc4067_data cd74hc4067_data_##inst; \
|
||||
DEVICE_DT_INST_DEFINE( inst, \
|
||||
cd74hc4067_init, \
|
||||
NULL, \
|
||||
&cd74hc4067_data_##inst, \
|
||||
&cd74hc4067_cfg_##inst, \
|
||||
POST_KERNEL, \
|
||||
CONFIG_CD74HC4067_INIT_PRIORITY, \
|
||||
NULL);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(CD74HC4067_DEFINE)
|
||||
|
||||
|
||||
@@ -3,58 +3,39 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/drivers/gpio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Select one of the 16 multiplexed channels.
|
||||
*
|
||||
* @param dev CD74HC4067 device instance.
|
||||
* @param channel Channel number to route (0-15).
|
||||
*
|
||||
* @retval 0 If the channel was selected.
|
||||
* @retval -EINVAL If the channel number is out of range.
|
||||
* @retval -ENODEV If one of the selection GPIOs is not ready.
|
||||
* @retval other Negative errno value from the GPIO driver.
|
||||
*/
|
||||
|
||||
// struct cd74hc4067_api {
|
||||
// int (*enable)(const struct device *dev);
|
||||
// int (*disable)(const struct device *dev);
|
||||
// int (*select_channel)(const struct device *dev, uint8_t channel);
|
||||
// };
|
||||
|
||||
struct cd74hc4067_data {
|
||||
struct k_mutex lock;
|
||||
uint8_t current_channel;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
#define CD74HC4067_SELECT_CHANNEL_COUNT 16U
|
||||
#define CD74HC4067_SELECT_PIN_COUNT 4U
|
||||
struct cd74hc4067_cfg {
|
||||
struct gpio_dt_spec select[CD74HC4067_SELECT_PIN_COUNT];
|
||||
struct gpio_dt_spec enable;
|
||||
bool has_enable;
|
||||
};
|
||||
|
||||
int cd74hc4067_enable(const struct device *dev);
|
||||
int cd74hc4067_disable(const struct device *dev);
|
||||
int cd74hc4067_select_channel(const struct device *dev, uint8_t channel);
|
||||
|
||||
/**
|
||||
* @brief Enable the multiplexer output (drives the /EN pin low).
|
||||
*
|
||||
* If the instance does not provide an enable GPIO, this call is a no-op.
|
||||
*
|
||||
* @param dev CD74HC4067 device instance.
|
||||
*
|
||||
* @retval 0 On success.
|
||||
* @retval -ENODEV If the enable GPIO is not ready.
|
||||
* @retval negative errno on GPIO failures.
|
||||
*/
|
||||
int cd74hc4067_enable(const struct device *dev);
|
||||
|
||||
/**
|
||||
* @brief Disable the multiplexer output (drives the /EN pin high).
|
||||
*
|
||||
* @param dev CD74HC4067 device instance.
|
||||
*
|
||||
* @retval 0 On success.
|
||||
* @retval -ENOTSUP If the instance does not expose an enable GPIO.
|
||||
* @retval -ENODEV If the enable GPIO is not ready.
|
||||
* @retval negative errno on GPIO failures.
|
||||
*/
|
||||
int cd74hc4067_disable(const struct device *dev);
|
||||
|
||||
/**
|
||||
* @brief Return the last channel value written to the device.
|
||||
*
|
||||
* @param dev CD74HC4067 device instance.
|
||||
*
|
||||
* @return Channel number in the range [0, 15].
|
||||
*/
|
||||
uint8_t cd74hc4067_get_current_channel(const struct device *dev);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -1,27 +1,23 @@
|
||||
description: |
|
||||
GPIO-controlled 16-channel analog/digital multiplexer/demultiplexer.
|
||||
|
||||
The CD74HC4067 has 4 selection pins (S0-S3) that select one of 16 channels.
|
||||
Supports optional common enable pin for power management.
|
||||
TI CD74HC4067 16-channel analog multiplexer.
|
||||
|
||||
compatible: "cd74hc4067"
|
||||
|
||||
include: base.yaml
|
||||
|
||||
properties:
|
||||
sel-gpios:
|
||||
select-gpios:
|
||||
type: phandle-array
|
||||
required: true
|
||||
description: |
|
||||
GPIO pins for channel selection (S0-S3).
|
||||
Array must contain exactly 4 GPIOs:
|
||||
- Index 0: S0 (LSB)
|
||||
- Index 0: S0
|
||||
- Index 1: S1
|
||||
- Index 2: S2
|
||||
- Index 3: S3 (MSB)
|
||||
- Index 3: S3
|
||||
|
||||
enable-gpios:
|
||||
type: phandle-array
|
||||
enable-gpio:
|
||||
type: phandle
|
||||
description: |
|
||||
Optional GPIO for common enable pin (E).
|
||||
When low, enables the multiplexer. When high, disables it.
|
||||
@@ -0,0 +1,68 @@
|
||||
/ {
|
||||
// Redefine the user io-channels (does not append)
|
||||
zephyr,user {
|
||||
io-channels = <&adc 0>,
|
||||
<&adc 1>,
|
||||
<&adc 2>,
|
||||
<&adc 3>,
|
||||
<&adc 4>,
|
||||
<&adc 5>,
|
||||
<&adc 6>,
|
||||
<&adc 7>;
|
||||
};
|
||||
};
|
||||
|
||||
// Add extra pins to pinctrl for the driver to configure the pins
|
||||
&adc_default {
|
||||
group2 {
|
||||
pinmux = <ADC_CH3_P43>, // ADC3
|
||||
<ADC_CH4_P44>, // ADC4
|
||||
<ADC_CH5_P45>, // ADC5
|
||||
<ADC_CH6_P46>, // D46
|
||||
<ADC_CH7_P47>; // D47
|
||||
input-enable;
|
||||
};
|
||||
};
|
||||
|
||||
// Add the extra channels to the ADC block
|
||||
&adc {
|
||||
adc3: channel@3 {
|
||||
reg = <3>;
|
||||
zephyr,gain = "ADC_GAIN_1";
|
||||
zephyr,reference = "ADC_REF_INTERNAL";
|
||||
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
|
||||
zephyr,resolution = <12>;
|
||||
};
|
||||
|
||||
adc4: channel@4 {
|
||||
reg = <4>;
|
||||
zephyr,gain = "ADC_GAIN_1";
|
||||
zephyr,reference = "ADC_REF_INTERNAL";
|
||||
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
|
||||
zephyr,resolution = <12>;
|
||||
};
|
||||
|
||||
adc5: channel@5 {
|
||||
reg = <5>;
|
||||
zephyr,gain = "ADC_GAIN_1";
|
||||
zephyr,reference = "ADC_REF_INTERNAL";
|
||||
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
|
||||
zephyr,resolution = <12>;
|
||||
};
|
||||
|
||||
adc6: channel@6 {
|
||||
reg = <6>;
|
||||
zephyr,gain = "ADC_GAIN_1";
|
||||
zephyr,reference = "ADC_REF_INTERNAL";
|
||||
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
|
||||
zephyr,resolution = <12>;
|
||||
};
|
||||
|
||||
adc7: channel@7 {
|
||||
reg = <7>;
|
||||
zephyr,gain = "ADC_GAIN_1";
|
||||
zephyr,reference = "ADC_REF_INTERNAL";
|
||||
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
|
||||
zephyr,resolution = <12>;
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,25 @@
|
||||
/ {
|
||||
aliases {
|
||||
uart1 = &uart1;
|
||||
};
|
||||
};
|
||||
|
||||
&pinctrl {
|
||||
uart_backup: uart_backup {
|
||||
group1 {
|
||||
pinmux = <UART1_TX_P26>; // SPI_CLK
|
||||
};
|
||||
group2 {
|
||||
pinmux = <UART1_RX_P27>; // SPI_MOSI
|
||||
input-enable;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
// Uses spi1 pins. Make sure to disable it
|
||||
&uart1 {
|
||||
current-speed = <115200>;
|
||||
status = "okay";
|
||||
pinctrl-0 = <&uart_backup>;
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
+8
-1
@@ -1,6 +1,7 @@
|
||||
# Basic
|
||||
CONFIG_GPIO=y
|
||||
CONFIG_PWM=y
|
||||
CONFIG_ADC=y
|
||||
|
||||
# Serial
|
||||
CONFIG_SERIAL=y
|
||||
@@ -16,7 +17,7 @@ CONFIG_CDC_ACM_SERIAL_PRODUCT_STRING="Servo2350"
|
||||
CONFIG_CDC_ACM_SERIAL_PID=0x0004
|
||||
|
||||
# Route console/logs to USB CDC ACM (configured via device tree)
|
||||
CONFIG_LOG=n
|
||||
CONFIG_LOG=y
|
||||
CONFIG_LOG_DEFAULT_LEVEL=3
|
||||
CONFIG_UART_CONSOLE=y
|
||||
CONFIG_LOG_BACKEND_UART=y
|
||||
@@ -29,3 +30,9 @@ CONFIG_SHELL_HISTORY=y
|
||||
# ZBUS Configuration
|
||||
CONFIG_ZBUS=y
|
||||
CONFIG_ZBUS_RUNTIME_OBSERVERS=y
|
||||
|
||||
# I2C Configuration
|
||||
CONFIG_I2C=y
|
||||
|
||||
# Multiplexer
|
||||
CONFIG_CD74HC4067=y
|
||||
@@ -1,12 +0,0 @@
|
||||
sample:
|
||||
name: Blinky Sample
|
||||
tests:
|
||||
sample.basic.blinky:
|
||||
tags:
|
||||
- LED
|
||||
- gpio
|
||||
filter: dt_enabled_alias_with_parent_compat("led0", "gpio-leds")
|
||||
depends_on: gpio
|
||||
harness: led
|
||||
integration_platforms:
|
||||
- frdm_k64f
|
||||
@@ -0,0 +1,122 @@
|
||||
#include "adc.h"
|
||||
#include "mux.h"
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/drivers/adc.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
LOG_MODULE_REGISTER(adc);
|
||||
|
||||
|
||||
#define ZEPHYR_USER_NODE DT_PATH(zephyr_user)
|
||||
static const struct adc_dt_spec adc_mux_spec = ADC_DT_SPEC_GET_BY_IDX(ZEPHYR_USER_NODE, 0);
|
||||
static const struct adc_dt_spec adc_ch16_spec = ADC_DT_SPEC_GET_BY_IDX(ZEPHYR_USER_NODE, 1);
|
||||
static const struct adc_dt_spec adc_ch17_spec = ADC_DT_SPEC_GET_BY_IDX(ZEPHYR_USER_NODE, 2);
|
||||
|
||||
int16_t adc_buffer;
|
||||
struct adc_sequence sequence = {
|
||||
.buffer = &adc_buffer,
|
||||
.buffer_size = sizeof(adc_buffer),
|
||||
};
|
||||
|
||||
int adc_init_all(void) {
|
||||
int ret;
|
||||
|
||||
ret = mux_init();
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Failed to setup multiplexer: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!adc_is_ready_dt(&adc_mux_spec)) {
|
||||
LOG_ERR("ADC mux channel not ready");
|
||||
return -1;
|
||||
}
|
||||
if (!adc_is_ready_dt(&adc_ch16_spec)) {
|
||||
LOG_ERR("ADC channel 17 not ready");
|
||||
return -1;
|
||||
}
|
||||
if (!adc_is_ready_dt(&adc_ch17_spec)) {
|
||||
LOG_ERR("ADC channel 18 not ready");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = adc_channel_setup_dt(&adc_mux_spec);
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Failed to setup ADC mux: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = adc_channel_setup_dt(&adc_ch16_spec);
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Failed to setup ADC channel 17: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = adc_channel_setup_dt(&adc_ch17_spec);
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Failed to setup ADC channel 18: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
adc_sequence_init_dt(&adc_mux_spec, &sequence);
|
||||
adc_sequence_init_dt(&adc_ch16_spec, &sequence);
|
||||
adc_sequence_init_dt(&adc_ch17_spec, &sequence);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int32_t adc_read_id(uint8_t id) {
|
||||
int ret;
|
||||
int32_t val_mv = 0;
|
||||
adc_buffer = 0;
|
||||
|
||||
if (id < MUX_CHANNELS) {
|
||||
// Read muxed channels
|
||||
(void)adc_sequence_init_dt(&adc_mux_spec, &sequence);
|
||||
|
||||
// Set mux
|
||||
ret = mux_select_channel(id);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Could not set multiplexer (%d)\n", ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = adc_read_dt(&adc_mux_spec, &sequence);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Could not read (%d)\n", ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
val_mv = (int32_t)adc_buffer;
|
||||
// ret = adc_raw_to_millivolts_dt(&adc_mux_spec, &val_mv);
|
||||
}
|
||||
else if (id == MUX_CHANNELS) {
|
||||
// Read unmuxed channel 17
|
||||
(void)adc_sequence_init_dt(&adc_ch16_spec, &sequence);
|
||||
|
||||
ret = adc_read_dt(&adc_ch16_spec, &sequence);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Could not read (%d)\n", ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
val_mv = (int32_t)adc_buffer;
|
||||
// ret = adc_raw_to_millivolts_dt(&adc_ch16_spec, &val_mv);
|
||||
}
|
||||
else if (id == (MUX_CHANNELS + 1)) {
|
||||
// Read unmuxed channel 18
|
||||
(void)adc_sequence_init_dt(&adc_ch17_spec, &sequence);
|
||||
|
||||
ret = adc_read_dt(&adc_ch17_spec, &sequence);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Could not read (%d)\n", ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
val_mv = (int32_t)adc_buffer;
|
||||
// ret = adc_raw_to_millivolts_dt(&adc_ch17_spec, &val_mv);
|
||||
}
|
||||
|
||||
|
||||
return val_mv;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef ADC_H
|
||||
#define ADC_H
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define NUM_ADC_CHANNELS 18
|
||||
|
||||
int adc_init_all(void);
|
||||
int32_t adc_read_id(uint8_t id);
|
||||
|
||||
|
||||
#endif /* ADC_H */
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/zbus/zbus.h>
|
||||
|
||||
LOG_MODULE_REGISTER(led, LOG_LEVEL_INF);
|
||||
LOG_MODULE_REGISTER(led);
|
||||
|
||||
#define LED0_NODE DT_ALIAS(led0)
|
||||
#define LED1_NODE DT_ALIAS(led1)
|
||||
|
||||
+3
-9
@@ -1,17 +1,11 @@
|
||||
#ifndef LED_H
|
||||
#define LED_H
|
||||
|
||||
/**
|
||||
* @file led.h
|
||||
* @brief LED control via GPIO and ZBUS
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Initialize LED driver
|
||||
*
|
||||
* @return 0 on success, negative errno on failure
|
||||
*/
|
||||
|
||||
int led_init(void);
|
||||
|
||||
|
||||
|
||||
#endif /* LED_H */
|
||||
|
||||
|
||||
+22
-10
@@ -1,26 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
LOG_MODULE_REGISTER(main, LOG_LEVEL_INF);
|
||||
#include "led.h"
|
||||
#include "servo.h"
|
||||
#include "adc.h"
|
||||
#include "uart.h"
|
||||
|
||||
LOG_MODULE_REGISTER(main);
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int main(void) {
|
||||
int ret;
|
||||
|
||||
/* LED driver - status indicators */
|
||||
ret = led_init();
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Failed to initialize LED driver: %d", ret);
|
||||
}
|
||||
|
||||
ret = servo_init();
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Failed to initialize SERVO driver: %d", ret);
|
||||
}
|
||||
|
||||
ret = adc_init_all();
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Failed to initialize ADC driver: %d", ret);
|
||||
}
|
||||
|
||||
ret = uart_init();
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Failed to initialize UART driver: %d", ret);
|
||||
}
|
||||
|
||||
|
||||
while (1) {
|
||||
k_msleep(1000);
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
#include "mux.h"
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
LOG_MODULE_REGISTER(mux);
|
||||
|
||||
#define MUX_NODE DT_ALIAS(mux)
|
||||
|
||||
static const struct device *mux_dev = DEVICE_DT_GET(MUX_NODE);
|
||||
|
||||
int mux_init(void) {
|
||||
int ret;
|
||||
|
||||
if (!DT_NODE_HAS_STATUS(MUX_NODE, okay)) {
|
||||
LOG_ERR("mux alias missing or disabled in devicetree");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!device_is_ready(mux_dev)) {
|
||||
LOG_ERR("Multiplexer device not ready");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = cd74hc4067_enable(mux_dev);
|
||||
if ((ret != 0) && (ret != -ENOTSUP)) {
|
||||
LOG_ERR("Failed to enable multiplexer: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = cd74hc4067_select_channel(mux_dev, 0U);
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Failed to select initial channel: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
LOG_INF("Multiplexer HAL initialized");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mux_select_channel(int channel) {
|
||||
return cd74hc4067_select_channel(mux_dev, channel);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef MUX_H
|
||||
#define MUX_H
|
||||
|
||||
|
||||
#include "cd74hc4067.h"
|
||||
|
||||
#define MUX_CHANNELS CD74HC4067_SELECT_CHANNEL_COUNT
|
||||
|
||||
int mux_init(void);
|
||||
int mux_select_channel(int channel);
|
||||
|
||||
|
||||
#endif // MUX_H
|
||||
@@ -0,0 +1,97 @@
|
||||
#include "servo.h"
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/zbus/zbus.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/devicetree.h>
|
||||
#include <zephyr/drivers/pwm.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
LOG_MODULE_REGISTER(servo);
|
||||
|
||||
static const struct pwm_dt_spec servo_pwm_specs[NUM_SERVO_CHANNELS] = {
|
||||
PWM_DT_SPEC_GET(DT_ALIAS(servo1)),
|
||||
PWM_DT_SPEC_GET(DT_ALIAS(servo2)),
|
||||
PWM_DT_SPEC_GET(DT_ALIAS(servo3)),
|
||||
PWM_DT_SPEC_GET(DT_ALIAS(servo4)),
|
||||
PWM_DT_SPEC_GET(DT_ALIAS(servo5)),
|
||||
PWM_DT_SPEC_GET(DT_ALIAS(servo6)),
|
||||
PWM_DT_SPEC_GET(DT_ALIAS(servo7)),
|
||||
PWM_DT_SPEC_GET(DT_ALIAS(servo8)),
|
||||
PWM_DT_SPEC_GET(DT_ALIAS(servo9)),
|
||||
PWM_DT_SPEC_GET(DT_ALIAS(servo10)),
|
||||
PWM_DT_SPEC_GET(DT_ALIAS(servo11)),
|
||||
PWM_DT_SPEC_GET(DT_ALIAS(servo12)),
|
||||
PWM_DT_SPEC_GET(DT_ALIAS(servo13)),
|
||||
PWM_DT_SPEC_GET(DT_ALIAS(servo14)),
|
||||
PWM_DT_SPEC_GET(DT_ALIAS(servo15)),
|
||||
PWM_DT_SPEC_GET(DT_ALIAS(servo16)),
|
||||
PWM_DT_SPEC_GET(DT_ALIAS(servo17)),
|
||||
PWM_DT_SPEC_GET(DT_ALIAS(servo18)),
|
||||
};
|
||||
|
||||
int servo_init(void) {
|
||||
int ret;
|
||||
|
||||
for (uint8_t ch = 0; ch < NUM_SERVO_CHANNELS; ch++) {
|
||||
if (!pwm_is_ready_dt(&servo_pwm_specs[ch])) {
|
||||
LOG_ERR("PWM device for servo %d is not ready", ch + 1);
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8_t ch = 0; ch < NUM_SERVO_CHANNELS; ch++) {
|
||||
ret = pwm_set_pulse_dt(&servo_pwm_specs[ch], PWM_USEC(0));
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Failed to initialize PWM for servo %d: %d", ch + 1, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t servo_angle_to_pulse_us(int angle_deg) {
|
||||
if (angle_deg > SERVO_MAX_ANGLE) {
|
||||
angle_deg = SERVO_MAX_ANGLE;
|
||||
} else if (angle_deg < SERVO_MIN_ANGLE) {
|
||||
angle_deg = SERVO_MIN_ANGLE;
|
||||
}
|
||||
|
||||
/* Convert: 0 deg = center, ±max_angle = ±half_pulse_range from center */
|
||||
int16_t half_pulse_range = ((int16_t)(SERVO_MAX_PULSE - SERVO_MIN_PULSE)) / 2;
|
||||
int16_t pulse_offset_us = (angle_deg * half_pulse_range) / SERVO_MAX_ANGLE;
|
||||
uint32_t pulse_us = (uint32_t)(SERVO_CENTER_PULSE + pulse_offset_us);
|
||||
|
||||
if (pulse_us < SERVO_MIN_PULSE) {
|
||||
pulse_us = SERVO_MIN_PULSE;
|
||||
} else if (pulse_us > SERVO_MAX_PULSE) {
|
||||
pulse_us = SERVO_MAX_PULSE;
|
||||
}
|
||||
|
||||
return pulse_us;
|
||||
}
|
||||
|
||||
int servo_set_angle(uint8_t channel, int angle_deg) {
|
||||
if (channel >= NUM_SERVO_CHANNELS) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int offset_deg = 0;
|
||||
int effective_angle_deg = angle_deg + offset_deg;
|
||||
|
||||
uint32_t pulse_us = servo_angle_to_pulse_us(effective_angle_deg);
|
||||
int ret = pwm_set_pulse_dt(&servo_pwm_specs[channel], PWM_USEC(pulse_us));
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Failed to set PWM pulse for servo %d: %d", channel + 1, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef SERVO_H
|
||||
#define SERVO_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
|
||||
#define NUM_SERVO_CHANNELS 18
|
||||
#define SERVO_CENTER_PULSE 1500
|
||||
#define SERVO_MIN_PULSE 750
|
||||
#define SERVO_MAX_PULSE 2500
|
||||
#define SERVO_MAX_ANGLE 135
|
||||
#define SERVO_MIN_ANGLE -135
|
||||
|
||||
int servo_init(void);
|
||||
uint32_t servo_angle_to_pulse_us(int angle_deg);
|
||||
int servo_set_angle(uint8_t channel, int angle_deg);
|
||||
|
||||
|
||||
#endif /* SERVO_H */
|
||||
|
||||
+173
-24
@@ -1,25 +1,20 @@
|
||||
#include "zbus_message.h"
|
||||
#include "servo.h"
|
||||
#include "adc.h"
|
||||
#include "uart.h"
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/shell/shell.h>
|
||||
#include <zephyr/zbus/zbus.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
LOG_MODULE_REGISTER(led_shell, LOG_LEVEL_INF);
|
||||
LOG_MODULE_REGISTER(shell);
|
||||
|
||||
/**
|
||||
* @brief Parse and publish an LED command to leds_chan.
|
||||
*
|
||||
* Usage:
|
||||
* led set <id> <on|off>
|
||||
*
|
||||
* @param shell Shell instance
|
||||
* @param argc Argument count (must be 3: "set", id, state)
|
||||
* @param argv Argument vector
|
||||
* @return 0 on success, negative errno on failure
|
||||
*/
|
||||
static int cmd_led_set(const struct shell *shell, size_t argc, char **argv)
|
||||
{
|
||||
// ---------------------------------------------------------------------
|
||||
// LEDs
|
||||
|
||||
static int cmd_led_set(const struct shell *shell, size_t argc, char **argv) {
|
||||
struct leds_message msg;
|
||||
int ret;
|
||||
|
||||
@@ -54,11 +49,7 @@ static int cmd_led_set(const struct shell *shell, size_t argc, char **argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Turn on all LEDs.
|
||||
*/
|
||||
static int cmd_led_all_on(const struct shell *shell, size_t argc, char **argv)
|
||||
{
|
||||
static int cmd_led_all_on(const struct shell *shell, size_t argc, char **argv) {
|
||||
struct leds_message msg;
|
||||
int ret;
|
||||
|
||||
@@ -77,11 +68,7 @@ static int cmd_led_all_on(const struct shell *shell, size_t argc, char **argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Turn off all LEDs.
|
||||
*/
|
||||
static int cmd_led_all_off(const struct shell *shell, size_t argc, char **argv)
|
||||
{
|
||||
static int cmd_led_all_off(const struct shell *shell, size_t argc, char **argv) {
|
||||
struct leds_message msg;
|
||||
int ret;
|
||||
|
||||
@@ -125,3 +112,165 @@ SHELL_CMD_REGISTER(led, &sub_led,
|
||||
" led allon - Turn all LEDs on\n"
|
||||
" led alloff - Turn all LEDs off",
|
||||
NULL);
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// SERVO
|
||||
|
||||
static int cmd_servo_set(const struct shell *shell, size_t argc, char **argv) {
|
||||
/* Parse SERVO id */
|
||||
char *endptr;
|
||||
long id = strtol(argv[1], &endptr, 10);
|
||||
|
||||
if (*endptr != '\0' || id < 0 || id > NUM_SERVO_CHANNELS) {
|
||||
shell_error(shell, "Invalid SERVO id '%s'.", argv[1]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
long value = strtol(argv[2], &endptr, 10);
|
||||
|
||||
if (*endptr != '\0' || value < SERVO_MIN_ANGLE || value > SERVO_MAX_ANGLE) {
|
||||
shell_error(shell, "Invalid SERVO value '%s'.(%d - %d)", argv[2], SERVO_MIN_ANGLE, SERVO_MAX_ANGLE);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
servo_set_angle((int)id, (int)value);
|
||||
|
||||
shell_print(shell, "SERVO%d turned %d", (int)id, (int)value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Subcommands for the "servo" root command */
|
||||
SHELL_STATIC_SUBCMD_SET_CREATE(sub_servo,
|
||||
SHELL_CMD_ARG(set, NULL,
|
||||
"Set a single SERVO state.\n"
|
||||
"Usage: servo set <id> <angle in deg>\n",
|
||||
cmd_servo_set, 3, 0),
|
||||
SHELL_SUBCMD_SET_END
|
||||
);
|
||||
|
||||
SHELL_CMD_REGISTER(servo, &sub_servo,
|
||||
"SERVO control commands.\n"
|
||||
" servo set <id> <angle in deg> - Set SERVO state\n",
|
||||
NULL);
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// ADC
|
||||
|
||||
static int cmd_adc_read(const struct shell *shell, size_t argc, char **argv) {
|
||||
/* Parse ADC id */
|
||||
char *endptr;
|
||||
long id = strtol(argv[1], &endptr, 10);
|
||||
|
||||
if (*endptr != '\0' || id < 0 || id > NUM_SERVO_CHANNELS) {
|
||||
shell_error(shell, "Invalid ADC id '%s'.", argv[1]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int value = adc_read_id((int)id);
|
||||
|
||||
shell_print(shell, "ADC%d value: %d", (int)id, (int)value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_adc_read_for(const struct shell *shell, size_t argc, char **argv) {
|
||||
/* Parse ADC id */
|
||||
char *endptr;
|
||||
long id = strtol(argv[1], &endptr, 10);
|
||||
|
||||
if (*endptr != '\0' || id < 0 || id > NUM_SERVO_CHANNELS) {
|
||||
shell_error(shell, "Invalid ADC id '%s'.", argv[1]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
long count = strtol(argv[2], &endptr, 10);
|
||||
|
||||
if (*endptr != '\0') {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
int value = adc_read_id((int)id);
|
||||
shell_print(shell, "ADC%d value: %d", (int)id, (int)value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_adc_scan(const struct shell *shell, size_t argc, char **argv) {
|
||||
for (int i = 0; i < NUM_ADC_CHANNELS; i++) {
|
||||
int value = adc_read_id(i);
|
||||
// shell_print(shell, "ADC%d value: %d", i, (int)value);
|
||||
char buf[16];
|
||||
snprintf(buf, sizeof(buf), "ADC,%d,%d\n\r", i, (int)value);
|
||||
print_uart(buf);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int buffer[18][1024];
|
||||
uint32_t tick_buffer[18][1024];
|
||||
uint32_t tick_speed;
|
||||
static int cmd_adc_scan_for(const struct shell *shell, size_t argc, char **argv) {
|
||||
/* Parse ADC id */
|
||||
char *endptr;
|
||||
|
||||
long count = strtol(argv[1], &endptr, 10);
|
||||
|
||||
if (*endptr != '\0' || count > 1024) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tick_speed = sys_clock_hw_cycles_per_sec();
|
||||
shell_print(shell, "Systick: %d", (int)tick_speed);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
for (int j = 0; j < NUM_ADC_CHANNELS; j++) {
|
||||
int value = adc_read_id(j);
|
||||
buffer[j][i] = value;
|
||||
tick_buffer[j][i] = k_cycle_get_32();
|
||||
// shell_print(shell, "ADC%d value: %d", j, (int)value);
|
||||
// char buf[16];
|
||||
// snprintf(buf, sizeof(buf), "%d,ADC,%d,%d\n\r", i, j, (int)value);
|
||||
// print_uart(buf);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
for (int j = 0; j < NUM_ADC_CHANNELS; j++) {
|
||||
char buf[32];
|
||||
snprintf(buf, sizeof(buf), "%d,ADC,%d,%d,%u\n\r", i, j, (int)buffer[j][i], tick_buffer[j][i]);
|
||||
print_uart(buf);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Subcommands for the "servo" root command */
|
||||
SHELL_STATIC_SUBCMD_SET_CREATE(sub_adc,
|
||||
SHELL_CMD_ARG(read, NULL,
|
||||
"Read a single ADC state.\n"
|
||||
"Usage: adc read <id>\n",
|
||||
cmd_adc_read, 2, 0),
|
||||
SHELL_CMD_ARG(read_for, NULL,
|
||||
"Read X amount of ADC states.\n"
|
||||
"Usage: adc read_for <id> <count>\n",
|
||||
cmd_adc_read_for, 3, 0),
|
||||
SHELL_CMD(scan, NULL,
|
||||
"Read all ADC channels.\n"
|
||||
"Usage: adc scan",
|
||||
cmd_adc_scan),
|
||||
SHELL_CMD_ARG(scan_for, NULL,
|
||||
"Read all ADC, X amount of ADC states.\n"
|
||||
"Usage: adc scan_for <count>\n",
|
||||
cmd_adc_scan_for, 2, 0),
|
||||
SHELL_SUBCMD_SET_END
|
||||
);
|
||||
|
||||
SHELL_CMD_REGISTER(adc, &sub_adc,
|
||||
"ADC control commands.\n"
|
||||
" adc read <id> - Read ADC\n"
|
||||
" adc read_for <id> <count> - Read ADC X amount of times\n"
|
||||
" adc scan - Read all ADC channels\n"
|
||||
" adc scan_for <count> - Read all ADC X amount of times\n",
|
||||
NULL);
|
||||
@@ -0,0 +1,32 @@
|
||||
#include "uart.h"
|
||||
|
||||
#include <zephyr/drivers/uart.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
LOG_MODULE_REGISTER(uart);
|
||||
|
||||
#define UART_DEVICE_NODE DT_ALIAS(uart1)
|
||||
static const struct device *const uart_dev = DEVICE_DT_GET(UART_DEVICE_NODE);
|
||||
|
||||
int uart_init(void) {
|
||||
int ret;
|
||||
|
||||
if (!device_is_ready(uart_dev)) {
|
||||
LOG_ERR("UART device not ready");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
LOG_INF("UART initialized");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void print_uart(char *buf) {
|
||||
int msg_len = strlen(buf);
|
||||
|
||||
for (int i = 0; i < msg_len; i++) {
|
||||
uart_poll_out(uart_dev, buf[i]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#ifndef UART_H
|
||||
#define UART_H
|
||||
|
||||
|
||||
int uart_init(void);
|
||||
void print_uart(char *buf);
|
||||
|
||||
|
||||
#endif // UART_H
|
||||
Reference in New Issue
Block a user