first
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
build/
|
||||
|
||||
# tmp
|
||||
reference/
|
||||
notes.md
|
||||
tmp/
|
||||
__pycache__/
|
||||
logs/
|
||||
|
||||
# doxygen
|
||||
doxygen/
|
||||
@@ -0,0 +1,10 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
set(BOARD_ROOT ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
project(servo2350)
|
||||
|
||||
FILE(GLOB app_sources src/*.c)
|
||||
target_sources(app PRIVATE ${app_sources})
|
||||
@@ -0,0 +1,97 @@
|
||||
.. 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>`.
|
||||
@@ -0,0 +1,51 @@
|
||||
|
||||
if BOARD_SERVO2350
|
||||
|
||||
menu "USB sample options"
|
||||
depends on USB_DEVICE_STACK_NEXT
|
||||
|
||||
config USBD_MANUFACTURER
|
||||
string "USB device sample manufacturer string"
|
||||
default "Zephyr Project"
|
||||
help
|
||||
USB device sample manufacturer string.
|
||||
|
||||
config USBD_PRODUCT
|
||||
string "USB device sample product string"
|
||||
default "USBD sample"
|
||||
help
|
||||
USB device sample product stringa.
|
||||
|
||||
config USBD_PID
|
||||
hex "USB device sample Product ID"
|
||||
default 0x0001
|
||||
help
|
||||
USB device sample Product ID.
|
||||
|
||||
config USBD_SELF_POWERED
|
||||
bool "USB device sample Self-powered attribute"
|
||||
default y
|
||||
help
|
||||
Set the Self-powered attribute in the sample configuration.
|
||||
|
||||
config USBD_REMOTE_WAKEUP
|
||||
bool "USB device sample Remote Wakeup attribute"
|
||||
help
|
||||
Set the Remote Wakeup attribute in the sample configuration.
|
||||
|
||||
config USBD_MAX_POWER
|
||||
int "USB device sample bMaxPower value"
|
||||
default 125
|
||||
range 0 250
|
||||
help
|
||||
bMaxPower value in the sample configuration in 2 mA units.
|
||||
|
||||
config USBD_20_EXTENSION_DESC
|
||||
bool "Use default USB 2.0 Extension Descriptor"
|
||||
depends on USBD_BOS_SUPPORT
|
||||
help
|
||||
Set bcdUSB value to 0201 and use default USB 2.0 Extension Descriptor.
|
||||
|
||||
endmenu
|
||||
|
||||
endif # BOARD_SERVO2350
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
config BOARD_SERVO2350
|
||||
select SOC_RP2350B_HAZARD3 if BOARD_SERVO2350_RP2350B_HAZARD3
|
||||
select SOC_RP2350B_M33 if BOARD_SERVO2350_RP2350B_M33
|
||||
@@ -0,0 +1,20 @@
|
||||
|
||||
board_runner_args(openocd --cmd-pre-init "source [find interface/cmsis-dap.cfg]")
|
||||
if(CONFIG_ARM)
|
||||
board_runner_args(openocd --cmd-pre-init "source [find target/rp2350.cfg]")
|
||||
else()
|
||||
board_runner_args(openocd --cmd-pre-init "source [find target/rp2350-riscv.cfg]")
|
||||
endif()
|
||||
|
||||
board_runner_args(probe-rs "--chip=RP235x")
|
||||
|
||||
# The adapter speed is expected to be set by interface configuration.
|
||||
# The Raspberry Pi's OpenOCD fork doesn't, so match their documentation at
|
||||
# https://www.raspberrypi.com/documentation/microcontrollers/debug-probe.html#debugging-with-swd
|
||||
board_runner_args(openocd --cmd-pre-init "set_adapter_speed_if_not_set 5000")
|
||||
|
||||
board_runner_args(uf2 "--board-id=RP2350")
|
||||
|
||||
include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake)
|
||||
include(${ZEPHYR_BASE}/boards/common/probe-rs.board.cmake)
|
||||
include(${ZEPHYR_BASE}/boards/common/uf2.board.cmake)
|
||||
@@ -0,0 +1,6 @@
|
||||
board:
|
||||
name: servo2350
|
||||
full_name: Servo2350
|
||||
vendor: arm
|
||||
socs:
|
||||
- name: rp2350b
|
||||
@@ -0,0 +1,75 @@
|
||||
#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>;
|
||||
input-enable;
|
||||
input-schmitt-enable;
|
||||
};
|
||||
};
|
||||
|
||||
spi0_default: spi0_default {
|
||||
group1 {
|
||||
pinmux = <SPI0_CSN_P17>, <SPI0_SCK_P18>, <SPI0_TX_P19>;
|
||||
};
|
||||
|
||||
group2 {
|
||||
pinmux = <SPI0_RX_P16>;
|
||||
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>;
|
||||
};
|
||||
};
|
||||
|
||||
adc_default: adc_default {
|
||||
group1 {
|
||||
pinmux = <ADC_CH0_P40>, <ADC_CH1_P41>, <ADC_CH2_P42>, <ADC_CH3_P43>;
|
||||
input-enable;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,406 @@
|
||||
#include <freq.h>
|
||||
|
||||
#include <zephyr/dt-bindings/i2c/i2c.h>
|
||||
#include <zephyr/dt-bindings/pwm/pwm.h>
|
||||
#include <zephyr/dt-bindings/input/input-event-codes.h>
|
||||
|
||||
#include "servo2350-pinctrl.dtsi"
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
zephyr,sram = &sram0;
|
||||
zephyr,flash = &flash0;
|
||||
zephyr,console = &cdc_acm_uart0;
|
||||
zephyr,shell-uart = &cdc_acm_uart0;
|
||||
zephyr,code-partition = &code_partition;
|
||||
};
|
||||
|
||||
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 */
|
||||
};
|
||||
|
||||
leds {
|
||||
compatible = "gpio-leds";
|
||||
|
||||
led0: led_0 {
|
||||
gpios = <&gpio0 24 GPIO_ACTIVE_LOW>;
|
||||
label = "LED0";
|
||||
};
|
||||
led1: led_1 {
|
||||
gpios = <&gpio0 25 GPIO_ACTIVE_LOW>;
|
||||
label = "LED1";
|
||||
};
|
||||
};
|
||||
|
||||
imu_int1_pin {
|
||||
compatible = "gpio-keys";
|
||||
|
||||
imu_int1: imu_int1 {
|
||||
gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>;
|
||||
label = "IMU_INT1";
|
||||
};
|
||||
};
|
||||
|
||||
digital_inputs {
|
||||
compatible = "gpio-keys";
|
||||
|
||||
digital1: digital_1 {
|
||||
gpios = <&gpio0 16 GPIO_ACTIVE_HIGH>;
|
||||
label = "DIGITAL_1";
|
||||
};
|
||||
digital2: digital_2 {
|
||||
gpios = <&gpio0 17 GPIO_ACTIVE_HIGH>;
|
||||
label = "DIGITAL_2";
|
||||
};
|
||||
digital3: digital_3 {
|
||||
gpios = <&gpio0 18 GPIO_ACTIVE_HIGH>;
|
||||
label = "DIGITAL_3";
|
||||
};
|
||||
digital4: digital_4 {
|
||||
gpios = <&gpio0 19 GPIO_ACTIVE_HIGH>;
|
||||
label = "DIGITAL_4";
|
||||
};
|
||||
digital5: digital_5 {
|
||||
gpios = <&gpio0 20 GPIO_ACTIVE_HIGH>;
|
||||
label = "DIGITAL_5";
|
||||
};
|
||||
digital6: digital_6 {
|
||||
gpios = <&gpio0 21 GPIO_ACTIVE_HIGH>;
|
||||
label = "DIGITAL_6";
|
||||
};
|
||||
};
|
||||
|
||||
digital_outputs {
|
||||
compatible = "gpio-leds";
|
||||
|
||||
leg0_enable: leg0_enable {
|
||||
gpios = <&gpio0 29 GPIO_ACTIVE_HIGH>;
|
||||
label = "LEG0_ENABLE";
|
||||
};
|
||||
leg1_enable: leg1_enable {
|
||||
gpios = <&gpio0 30 GPIO_ACTIVE_HIGH>;
|
||||
label = "LEG1_ENABLE";
|
||||
};
|
||||
leg2_enable: leg2_enable {
|
||||
gpios = <&gpio0 31 GPIO_ACTIVE_HIGH>;
|
||||
label = "LEG2_ENABLE";
|
||||
};
|
||||
leg3_enable: leg3_enable {
|
||||
gpios = <&gpio0_hi 11 GPIO_ACTIVE_HIGH>;
|
||||
label = "LEG3_ENABLE";
|
||||
};
|
||||
leg4_enable: leg4_enable {
|
||||
gpios = <&gpio0_hi 12 GPIO_ACTIVE_HIGH>;
|
||||
label = "LEG4_ENABLE";
|
||||
};
|
||||
leg5_enable: leg5_enable {
|
||||
gpios = <&gpio0_hi 13 GPIO_ACTIVE_HIGH>;
|
||||
label = "LEG5_ENABLE";
|
||||
};
|
||||
};
|
||||
|
||||
pwm_servos {
|
||||
compatible = "pwm-leds";
|
||||
|
||||
servo1: servo_1 {
|
||||
pwms = <&pwm 0 PWM_USEC(20000) PWM_POLARITY_NORMAL>;
|
||||
label = "SERVO_1";
|
||||
};
|
||||
servo2: servo_2 {
|
||||
pwms = <&pwm 1 PWM_USEC(20000) PWM_POLARITY_NORMAL>;
|
||||
label = "SERVO_2";
|
||||
};
|
||||
servo3: servo_3 {
|
||||
pwms = <&pwm 2 PWM_USEC(20000) PWM_POLARITY_NORMAL>;
|
||||
label = "SERVO_3";
|
||||
};
|
||||
servo4: servo_4 {
|
||||
pwms = <&pwm 3 PWM_USEC(20000) PWM_POLARITY_NORMAL>;
|
||||
label = "SERVO_4";
|
||||
};
|
||||
servo5: servo_5 {
|
||||
pwms = <&pwm 4 PWM_USEC(20000) PWM_POLARITY_NORMAL>;
|
||||
label = "SERVO_5";
|
||||
};
|
||||
servo6: servo_6 {
|
||||
pwms = <&pwm 5 PWM_USEC(20000) PWM_POLARITY_NORMAL>;
|
||||
label = "SERVO_6";
|
||||
};
|
||||
servo7: servo_7 {
|
||||
pwms = <&pwm 6 PWM_USEC(20000) PWM_POLARITY_NORMAL>;
|
||||
label = "SERVO_7";
|
||||
};
|
||||
servo8: servo_8 {
|
||||
pwms = <&pwm 7 PWM_USEC(20000) PWM_POLARITY_NORMAL>;
|
||||
label = "SERVO_8";
|
||||
};
|
||||
servo9: servo_9 {
|
||||
pwms = <&pwm 8 PWM_USEC(20000) PWM_POLARITY_NORMAL>;
|
||||
label = "SERVO_9";
|
||||
};
|
||||
servo10: servo_10 {
|
||||
pwms = <&pwm 9 PWM_USEC(20000) PWM_POLARITY_NORMAL>;
|
||||
label = "SERVO_10";
|
||||
};
|
||||
servo11: servo_11 {
|
||||
pwms = <&pwm 10 PWM_USEC(20000) PWM_POLARITY_NORMAL>;
|
||||
label = "SERVO_11";
|
||||
};
|
||||
servo12: servo_12 {
|
||||
pwms = <&pwm 11 PWM_USEC(20000) PWM_POLARITY_NORMAL>;
|
||||
label = "SERVO_12";
|
||||
};
|
||||
servo13: servo_13 {
|
||||
pwms = <&pwm 12 PWM_USEC(20000) PWM_POLARITY_NORMAL>;
|
||||
label = "SERVO_13";
|
||||
};
|
||||
servo14: servo_14 {
|
||||
pwms = <&pwm 13 PWM_USEC(20000) PWM_POLARITY_NORMAL>;
|
||||
label = "SERVO_14";
|
||||
};
|
||||
servo15: servo_15 {
|
||||
pwms = <&pwm 14 PWM_USEC(20000) PWM_POLARITY_NORMAL>;
|
||||
label = "SERVO_15";
|
||||
};
|
||||
servo16: servo_16 {
|
||||
pwms = <&pwm 15 PWM_USEC(20000) PWM_POLARITY_NORMAL>;
|
||||
label = "SERVO_16";
|
||||
};
|
||||
servo17: servo_17 {
|
||||
pwms = <&pwm 16 PWM_USEC(20000) PWM_POLARITY_NORMAL>;
|
||||
label = "SERVO_17";
|
||||
};
|
||||
servo18: servo_18 {
|
||||
pwms = <&pwm 17 PWM_USEC(20000) PWM_POLARITY_NORMAL>;
|
||||
label = "SERVO_18";
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
aliases {
|
||||
watchdog0 = &wdt0;
|
||||
led0 = &led0;
|
||||
led1 = &led1;
|
||||
imu = &icm45686;
|
||||
imu-int1 = &imu_int1;
|
||||
digital1 = &digital1;
|
||||
digital2 = &digital2;
|
||||
digital3 = &digital3;
|
||||
digital4 = &digital4;
|
||||
digital5 = &digital5;
|
||||
digital6 = &digital6;
|
||||
leg0-enable = &leg0_enable;
|
||||
leg1-enable = &leg1_enable;
|
||||
leg2-enable = &leg2_enable;
|
||||
leg3-enable = &leg3_enable;
|
||||
leg4-enable = &leg4_enable;
|
||||
leg5-enable = &leg5_enable;
|
||||
servo1 = &servo1;
|
||||
servo2 = &servo2;
|
||||
servo3 = &servo3;
|
||||
servo4 = &servo4;
|
||||
servo5 = &servo5;
|
||||
servo6 = &servo6;
|
||||
servo7 = &servo7;
|
||||
servo8 = &servo8;
|
||||
servo9 = &servo9;
|
||||
servo10 = &servo10;
|
||||
servo11 = &servo11;
|
||||
servo12 = &servo12;
|
||||
servo13 = &servo13;
|
||||
servo14 = &servo14;
|
||||
servo15 = &servo15;
|
||||
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 */
|
||||
};
|
||||
};
|
||||
|
||||
&flash0 {
|
||||
/* W25Q16JVUXIQ_TR: 16M-bit (2MB) NOR Flash */
|
||||
reg = <0x10000000 DT_SIZE_M(2)>;
|
||||
|
||||
partitions {
|
||||
compatible = "fixed-partitions";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
/* Code partition: 256KB for application code (starts at beginning of flash) */
|
||||
code_partition: partition@0 {
|
||||
label = "code";
|
||||
reg = <0x00000000 DT_SIZE_K(256)>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
/* Settings partition: 64KB for settings data */
|
||||
settings_partition: partition@40000 {
|
||||
label = "settings";
|
||||
reg = <0x00040000 DT_SIZE_K(64)>;
|
||||
};
|
||||
|
||||
/* Data partition: 1728KB for data storage (largest partition) */
|
||||
data_partition: partition@50000 {
|
||||
label = "data";
|
||||
reg = <0x00050000 DT_SIZE_K(1728)>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&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";
|
||||
};
|
||||
};
|
||||
|
||||
gpio0_lo: &gpio0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&gpio0_hi {
|
||||
status = "okay";
|
||||
|
||||
};
|
||||
|
||||
&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 {
|
||||
compatible = "invensense,icm42688";
|
||||
reg = <0x68>;
|
||||
status = "okay";
|
||||
|
||||
int1-gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>;
|
||||
int2-gpios = <&gpio0 23 GPIO_ACTIVE_HIGH>;
|
||||
|
||||
accel-pwr-mode = <3>;
|
||||
accel-ord = <9>;
|
||||
accel-fs = <16>;
|
||||
accel-lpf = <0>;
|
||||
|
||||
gyro-pwr-mode = <0>; /* turn off */
|
||||
gyro-ord = <9>;
|
||||
gyro-fs = <2000>;
|
||||
};
|
||||
};
|
||||
|
||||
adc0: &adc {
|
||||
pinctrl-0 = <&adc_default>;
|
||||
pinctrl-names = "default";
|
||||
status = "okay";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
adc1: channel@0 {
|
||||
reg = <0>;
|
||||
zephyr,gain = "ADC_GAIN_1";
|
||||
zephyr,reference = "ADC_REF_INTERNAL";
|
||||
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
|
||||
zephyr,resolution = <12>;
|
||||
};
|
||||
|
||||
adc2: channel@1 {
|
||||
reg = <1>;
|
||||
zephyr,gain = "ADC_GAIN_1";
|
||||
zephyr,reference = "ADC_REF_INTERNAL";
|
||||
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
|
||||
zephyr,resolution = <12>;
|
||||
};
|
||||
|
||||
adc3: channel@2 {
|
||||
reg = <2>;
|
||||
zephyr,gain = "ADC_GAIN_1";
|
||||
zephyr,reference = "ADC_REF_INTERNAL";
|
||||
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
|
||||
zephyr,resolution = <12>;
|
||||
};
|
||||
};
|
||||
|
||||
&pwm {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&pwm_default>;
|
||||
pinctrl-names = "default";
|
||||
divider-int-0 = <64>;
|
||||
};
|
||||
|
||||
&timer0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
pico_spi: &spi0 {};
|
||||
|
||||
pico_i2c0: &i2c0 {};
|
||||
|
||||
pico_i2c1: &i2c1 {};
|
||||
|
||||
pico_serial: &uart0 {};
|
||||
|
||||
zephyr_i2c: &i2c0 {};
|
||||
|
||||
imu: &icm45686 {};
|
||||
@@ -0,0 +1,12 @@
|
||||
/dts-v1/;
|
||||
|
||||
/* The build system assumes that there's a cpucluster-specific file.
|
||||
*
|
||||
* This file provides composition of the device tree:
|
||||
* 1. The common features of the SoC
|
||||
* 2. Core-specific configuration.
|
||||
* 3. Board-specific configuration.
|
||||
*/
|
||||
#include <raspberrypi/rpi_pico/rp2350b.dtsi>
|
||||
#include <riscv/raspberrypi/hazard3.dtsi>
|
||||
#include "servo2350.dtsi"
|
||||
@@ -0,0 +1,20 @@
|
||||
identifier: servo2350/rp2350b/hazard3
|
||||
name: Servo2350 (Hazard3)
|
||||
type: mcu
|
||||
arch: riscv
|
||||
flash: 16384
|
||||
ram: 8192
|
||||
toolchain:
|
||||
- zephyr
|
||||
supported:
|
||||
- adc
|
||||
- clock
|
||||
- counter
|
||||
- dma
|
||||
- gpio
|
||||
- hwinfo
|
||||
- i2c
|
||||
- pwm
|
||||
- spi
|
||||
- usbd
|
||||
- uart
|
||||
@@ -0,0 +1,10 @@
|
||||
CONFIG_BUILD_OUTPUT_HEX=y
|
||||
CONFIG_BUILD_OUTPUT_UF2=y
|
||||
CONFIG_CLOCK_CONTROL=y
|
||||
CONFIG_CONSOLE=y
|
||||
CONFIG_GPIO=y
|
||||
CONFIG_RESET=y
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_UART_CONSOLE=y
|
||||
CONFIG_UART_INTERRUPT_DRIVEN=y
|
||||
CONFIG_USE_DT_CODE_PARTITION=y
|
||||
@@ -0,0 +1,12 @@
|
||||
/dts-v1/;
|
||||
|
||||
/* The build system assumes that there's a cpucluster-specific file.
|
||||
*
|
||||
* This file provides composition of the device tree:
|
||||
* 1. The common features of the SoC
|
||||
* 2. Core-specific configuration.
|
||||
* 3. Board-specific configuration.
|
||||
*/
|
||||
#include <raspberrypi/rpi_pico/rp2350b.dtsi>
|
||||
#include <raspberrypi/rpi_pico/m33.dtsi>
|
||||
#include "servo2350.dtsi"
|
||||
@@ -0,0 +1,21 @@
|
||||
identifier: servo2350/rp2350b/m33
|
||||
name: Servo2350 (Cortex-M33)
|
||||
type: mcu
|
||||
arch: arm
|
||||
flash: 16384
|
||||
ram: 8192
|
||||
toolchain:
|
||||
- zephyr
|
||||
- gnuarmemb
|
||||
supported:
|
||||
- adc
|
||||
- clock
|
||||
- counter
|
||||
- dma
|
||||
- gpio
|
||||
- hwinfo
|
||||
- i2c
|
||||
- pwm
|
||||
- spi
|
||||
- usbd
|
||||
- uart
|
||||
@@ -0,0 +1,10 @@
|
||||
CONFIG_BUILD_OUTPUT_HEX=y
|
||||
CONFIG_BUILD_OUTPUT_UF2=y
|
||||
CONFIG_CLOCK_CONTROL=y
|
||||
CONFIG_CONSOLE=y
|
||||
CONFIG_GPIO=y
|
||||
CONFIG_RESET=y
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_UART_CONSOLE=y
|
||||
CONFIG_UART_INTERRUPT_DRIVEN=y
|
||||
CONFIG_USE_DT_CODE_PARTITION=y
|
||||
@@ -0,0 +1,8 @@
|
||||
# Checking and set 'adapter speed'.
|
||||
# Set the adaptor speed, if unset, and given as an argument.
|
||||
proc set_adapter_speed_if_not_set { speed } {
|
||||
puts "checking adapter speed..."
|
||||
if { [catch {adapter speed} ret] } {
|
||||
adapter speed $speed
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
add_subdirectory(multiplexer)
|
||||
@@ -0,0 +1,5 @@
|
||||
menu "Servo2350 Device Drivers"
|
||||
|
||||
rsource "multiplexer/Kconfig"
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1 @@
|
||||
add_subdirectory_ifdef(CONFIG_CD74HC4067 cd74hc4067)
|
||||
@@ -0,0 +1,5 @@
|
||||
menu "Multiplexer Drivers"
|
||||
|
||||
rsource "cd74hc4067/Kconfig"
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1,5 @@
|
||||
if(CONFIG_CD74HC4067)
|
||||
target_sources(app PRIVATE ${CMAKE_CURRENT_LIST_DIR}/cd74hc4067.c)
|
||||
target_include_directories(app PRIVATE ${CMAKE_CURRENT_LIST_DIR})
|
||||
endif()
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
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.
|
||||
|
||||
if CD74HC4067
|
||||
|
||||
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.
|
||||
|
||||
module = CD74HC4067
|
||||
module-str = cd74hc4067
|
||||
source "subsys/logging/Kconfig.template.log_config"
|
||||
|
||||
endif # CD74HC4067
|
||||
|
||||
@@ -0,0 +1,217 @@
|
||||
|
||||
#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);
|
||||
|
||||
#define CD74HC4067_CHANNEL_COUNT 16U
|
||||
#define CD74HC4067_SELECTION_PIN_COUNT 4U
|
||||
|
||||
struct cd74hc4067_config {
|
||||
struct gpio_dt_spec sel[CD74HC4067_SELECTION_PIN_COUNT];
|
||||
struct gpio_dt_spec enable;
|
||||
bool has_enable;
|
||||
};
|
||||
|
||||
struct cd74hc4067_data {
|
||||
struct k_mutex lock;
|
||||
uint8_t current_channel;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
static int cd74hc4067_sync_enable_state(const struct device *dev, bool enable)
|
||||
{
|
||||
const struct cd74hc4067_config *cfg = dev->config;
|
||||
struct cd74hc4067_data *data = dev->data;
|
||||
int ret = 0;
|
||||
|
||||
if (!cfg->has_enable) {
|
||||
if (!enable) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
data->enabled = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!device_is_ready(cfg->enable.port)) {
|
||||
LOG_ERR("%s enable GPIO not ready", dev->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = gpio_pin_set_dt(&cfg->enable, enable ? 0 : 1);
|
||||
if (ret == 0) {
|
||||
data->enabled = enable;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cd74hc4067_configure_gpios(const struct device *dev)
|
||||
{
|
||||
const struct cd74hc4067_config *cfg = dev->config;
|
||||
int ret;
|
||||
|
||||
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;
|
||||
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);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
data->current_channel = channel;
|
||||
|
||||
out:
|
||||
k_mutex_unlock(&data->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cd74hc4067_enable(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, 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);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(CD74HC4067_DEFINE)
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
#ifndef SERVO2350_DRIVERS_MULTIPLEXER_CD74HC4067_H_
|
||||
#define SERVO2350_DRIVERS_MULTIPLEXER_CD74HC4067_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <zephyr/device.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.
|
||||
*/
|
||||
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
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SERVO2350_DRIVERS_MULTIPLEXER_CD74HC4067_H_ */
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
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.
|
||||
|
||||
compatible: "cd74hc4067"
|
||||
|
||||
include: base.yaml
|
||||
|
||||
properties:
|
||||
sel-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 1: S1
|
||||
- Index 2: S2
|
||||
- Index 3: S3 (MSB)
|
||||
|
||||
enable-gpios:
|
||||
type: phandle-array
|
||||
description: |
|
||||
Optional GPIO for common enable pin (E).
|
||||
When low, enables the multiplexer. When high, disables it.
|
||||
@@ -0,0 +1,31 @@
|
||||
# Basic
|
||||
CONFIG_GPIO=y
|
||||
CONFIG_PWM=y
|
||||
|
||||
# Serial
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_CONSOLE=y
|
||||
CONFIG_UART_CONSOLE=y
|
||||
CONFIG_STDOUT_CONSOLE=y
|
||||
CONFIG_UART_LINE_CTRL=y
|
||||
|
||||
# USB
|
||||
CONFIG_USB_DEVICE_STACK_NEXT=y
|
||||
CONFIG_CDC_ACM_SERIAL_INITIALIZE_AT_BOOT=y
|
||||
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_DEFAULT_LEVEL=3
|
||||
CONFIG_UART_CONSOLE=y
|
||||
CONFIG_LOG_BACKEND_UART=y
|
||||
|
||||
# Shell
|
||||
CONFIG_SHELL=y
|
||||
CONFIG_USBD_SHELL=y
|
||||
CONFIG_SHELL_HISTORY=y
|
||||
|
||||
# ZBUS Configuration
|
||||
CONFIG_ZBUS=y
|
||||
CONFIG_ZBUS_RUNTIME_OBSERVERS=y
|
||||
@@ -0,0 +1,12 @@
|
||||
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,103 @@
|
||||
#include "led.h"
|
||||
#include "zbus_message.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/zbus/zbus.h>
|
||||
|
||||
LOG_MODULE_REGISTER(led, LOG_LEVEL_INF);
|
||||
|
||||
#define LED0_NODE DT_ALIAS(led0)
|
||||
#define LED1_NODE DT_ALIAS(led1)
|
||||
|
||||
static const struct gpio_dt_spec led0_gpio = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
|
||||
static const struct gpio_dt_spec led1_gpio = GPIO_DT_SPEC_GET(LED1_NODE, gpios);
|
||||
|
||||
static bool led0_state = false;
|
||||
static bool led1_state = false;
|
||||
|
||||
/* ZBUS handler - update LED state */
|
||||
static void leds_zbus_handler(const struct zbus_channel *chan)
|
||||
{
|
||||
const struct leds_message *msg;
|
||||
int ret;
|
||||
const struct gpio_dt_spec *target_gpio;
|
||||
bool *target_state;
|
||||
|
||||
msg = zbus_chan_const_msg(chan);
|
||||
if (msg == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg->led_id == 0) {
|
||||
target_gpio = &led0_gpio;
|
||||
target_state = &led0_state;
|
||||
} else if (msg->led_id == 1) {
|
||||
target_gpio = &led1_gpio;
|
||||
target_state = &led1_state;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
*target_state = msg->led_value;
|
||||
ret = gpio_pin_set_dt(target_gpio, msg->led_value ? 1 : 0);
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Failed to set LED%d: %d", msg->led_id, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_DBG("LED%d updated: %s (LED0=%s, LED1=%s)",
|
||||
msg->led_id, msg->led_value ? "ON" : "OFF",
|
||||
led0_state ? "ON" : "OFF", led1_state ? "ON" : "OFF");
|
||||
}
|
||||
|
||||
ZBUS_LISTENER_DEFINE(leds_listener, leds_zbus_handler);
|
||||
|
||||
int led_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!device_is_ready(led0_gpio.port)) {
|
||||
LOG_ERR("LED0 GPIO device not ready");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = gpio_pin_configure_dt(&led0_gpio, GPIO_OUTPUT_INACTIVE);
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Failed to configure LED0 GPIO: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!device_is_ready(led1_gpio.port)) {
|
||||
LOG_ERR("LED1 GPIO device not ready");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = gpio_pin_configure_dt(&led1_gpio, GPIO_OUTPUT_INACTIVE);
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Failed to configure LED1 GPIO: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = zbus_chan_add_obs(&leds_chan, &leds_listener, K_MSEC(200));
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Failed to add LED listener: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = gpio_pin_set_dt(&led0_gpio, 0);
|
||||
ret |= gpio_pin_set_dt(&led1_gpio, 0);
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Failed to initialize LEDs");
|
||||
return ret;
|
||||
}
|
||||
|
||||
LOG_INF("LED driver initialized (LED0: GPIO %d, LED1: GPIO %d)",
|
||||
led0_gpio.pin, led1_gpio.pin);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
#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 */
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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);
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* LED driver - status indicators */
|
||||
ret = led_init();
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Failed to initialize LED driver: %d", ret);
|
||||
}
|
||||
|
||||
|
||||
while (1) {
|
||||
k_msleep(1000);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
#include "zbus_message.h"
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/shell/shell.h>
|
||||
#include <zephyr/zbus/zbus.h>
|
||||
|
||||
LOG_MODULE_REGISTER(led_shell, LOG_LEVEL_INF);
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
struct leds_message msg;
|
||||
int ret;
|
||||
|
||||
/* Parse LED id */
|
||||
char *endptr;
|
||||
long id = strtol(argv[1], &endptr, 10);
|
||||
|
||||
if (*endptr != '\0' || id < 0 || id > 1) {
|
||||
shell_error(shell, "Invalid LED id '%s'. Use 0 or 1.", argv[1]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Parse state */
|
||||
if (strcmp(argv[2], "on") == 0) {
|
||||
msg.led_value = true;
|
||||
} else if (strcmp(argv[2], "off") == 0) {
|
||||
msg.led_value = false;
|
||||
} else {
|
||||
shell_error(shell, "Invalid state '%s'. Use 'on' or 'off'.", argv[2]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
msg.led_id = (uint8_t)id;
|
||||
|
||||
ret = zbus_chan_pub(&leds_chan, &msg, K_MSEC(200));
|
||||
if (ret != 0) {
|
||||
shell_error(shell, "Failed to publish LED command: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
shell_print(shell, "LED%d turned %s", msg.led_id, msg.led_value ? "ON" : "OFF");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Turn on all LEDs.
|
||||
*/
|
||||
static int cmd_led_all_on(const struct shell *shell, size_t argc, char **argv)
|
||||
{
|
||||
struct leds_message msg;
|
||||
int ret;
|
||||
|
||||
for (uint8_t i = 0; i <= 1; i++) {
|
||||
msg.led_id = i;
|
||||
msg.led_value = true;
|
||||
|
||||
ret = zbus_chan_pub(&leds_chan, &msg, K_MSEC(200));
|
||||
if (ret != 0) {
|
||||
shell_error(shell, "Failed to turn on LED%d: %d", i, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
shell_print(shell, "All LEDs turned ON");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Turn off all LEDs.
|
||||
*/
|
||||
static int cmd_led_all_off(const struct shell *shell, size_t argc, char **argv)
|
||||
{
|
||||
struct leds_message msg;
|
||||
int ret;
|
||||
|
||||
for (uint8_t i = 0; i <= 1; i++) {
|
||||
msg.led_id = i;
|
||||
msg.led_value = false;
|
||||
|
||||
ret = zbus_chan_pub(&leds_chan, &msg, K_MSEC(200));
|
||||
if (ret != 0) {
|
||||
shell_error(shell, "Failed to turn off LED%d: %d", i, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
shell_print(shell, "All LEDs turned OFF");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Subcommands for the "led" root command */
|
||||
SHELL_STATIC_SUBCMD_SET_CREATE(sub_led,
|
||||
SHELL_CMD_ARG(set, NULL,
|
||||
"Set a single LED state.\n"
|
||||
"Usage: led set <id> <on|off>\n"
|
||||
" id : 0 or 1\n"
|
||||
" state: on | off",
|
||||
cmd_led_set, 3, 0),
|
||||
SHELL_CMD(allon, NULL,
|
||||
"Turn all LEDs on.\n"
|
||||
"Usage: led allon",
|
||||
cmd_led_all_on),
|
||||
SHELL_CMD(alloff, NULL,
|
||||
"Turn all LEDs off.\n"
|
||||
"Usage: led alloff",
|
||||
cmd_led_all_off),
|
||||
SHELL_SUBCMD_SET_END
|
||||
);
|
||||
|
||||
SHELL_CMD_REGISTER(led, &sub_led,
|
||||
"LED control commands.\n"
|
||||
" led set <id> <on|off> - Set LED state\n"
|
||||
" led allon - Turn all LEDs on\n"
|
||||
" led alloff - Turn all LEDs off",
|
||||
NULL);
|
||||
@@ -0,0 +1,16 @@
|
||||
#include "zbus_message.h"
|
||||
|
||||
#include <zephyr/zbus/zbus.h>
|
||||
|
||||
/**
|
||||
* @brief ZBUS channel definition for LED control.
|
||||
*
|
||||
* No validator is used; any leds_message value is accepted.
|
||||
* Observers are registered at runtime via zbus_chan_add_obs().
|
||||
*/
|
||||
ZBUS_CHAN_DEFINE(leds_chan, /* channel name */
|
||||
struct leds_message, /* message type */
|
||||
NULL, /* validator */
|
||||
NULL, /* user data */
|
||||
ZBUS_OBSERVERS_EMPTY,
|
||||
ZBUS_MSG_INIT(.led_id = 0, .led_value = false));
|
||||
@@ -0,0 +1,30 @@
|
||||
#ifndef ZBUS_MESSAGE_H
|
||||
#define ZBUS_MESSAGE_H
|
||||
|
||||
/**
|
||||
* @file zbus_message.h
|
||||
* @brief ZBUS channel and message definitions for LED control
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <zephyr/zbus/zbus.h>
|
||||
|
||||
/**
|
||||
* @brief Message published to leds_chan to control an LED.
|
||||
*
|
||||
* @param led_id LED index (0 or 1)
|
||||
* @param led_value true = ON, false = OFF
|
||||
*/
|
||||
struct leds_message {
|
||||
uint8_t led_id;
|
||||
bool led_value;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief ZBUS channel for LED control messages.
|
||||
*
|
||||
* Publish a struct leds_message to this channel to set an LED state.
|
||||
*/
|
||||
ZBUS_CHAN_DECLARE(leds_chan);
|
||||
|
||||
#endif /* ZBUS_MESSAGE_H */
|
||||
Reference in New Issue
Block a user