First
This commit is contained in:
@@ -0,0 +1 @@
|
||||
build
|
||||
Vendored
+23
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Zephyr Remote Cortex-Debug (OpenOCD)",
|
||||
"type": "cortex-debug",
|
||||
"request": "launch",
|
||||
|
||||
"executable": "${workspaceFolder}/build/zephyr/zephyr.elf",
|
||||
|
||||
"servertype": "external",
|
||||
"gdbTarget": "192.168.1.154:3333",
|
||||
|
||||
"gdbPath": "/usr/bin/arm-none-eabi-gdb",
|
||||
|
||||
"runToEntryPoint": "main",
|
||||
|
||||
"preLaunchCommands": [
|
||||
"monitor reset halt"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
# Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
# 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(meditation)
|
||||
|
||||
FILE(GLOB app_sources src/*.c)
|
||||
target_sources(app PRIVATE ${app_sources})
|
||||
Executable
+26
@@ -0,0 +1,26 @@
|
||||
# nRF52840 Dongle NRF52840 board configuration
|
||||
|
||||
# Copyright (c) 2018-2023 Nordic Semiconductor ASA
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
if BOARD_NRF52840_QALMARI
|
||||
|
||||
config BOARD_ENABLE_DCDC
|
||||
bool "DCDC mode"
|
||||
select SOC_DCDC_NRF52X
|
||||
default n
|
||||
|
||||
config BOARD_ENABLE_DCDC_HV
|
||||
bool "High Voltage DCDC converter"
|
||||
select SOC_DCDC_NRF52X_HV
|
||||
default n
|
||||
|
||||
|
||||
config BOARD_HAS_NRF5_BOOTLOADER
|
||||
bool "Board has nRF5 bootloader"
|
||||
default n
|
||||
help
|
||||
If selected, applications are linked so that they can be loaded by Nordic
|
||||
nRF5 bootloader.
|
||||
|
||||
endif # BOARD_NRF52840_QALMARI
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
# nRF52840 Dongle NRF52840 board configuration
|
||||
#
|
||||
# Copyright (c) 2018-2023 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
if BOARD_NRF52840_QALMARI
|
||||
|
||||
config BOARD
|
||||
default "nrf52840_qalmari"
|
||||
|
||||
config FLASH_LOAD_OFFSET
|
||||
default 0x12000
|
||||
depends on BOARD_HAS_NRF5_BOOTLOADER && (MCUBOOT || !USE_DT_CODE_PARTITION)
|
||||
|
||||
endif # BOARD_NRF52840_QALMARI
|
||||
@@ -0,0 +1,7 @@
|
||||
# nRF52840 Dongle NRF52840 board configuration
|
||||
|
||||
# Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config BOARD_NRF52840_QALMARI
|
||||
select SOC_NRF52840_QIAA
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
board_runner_args(jlink "--device=nRF52840_xxAA" "--speed=4000")
|
||||
board_runner_args(pyocd "--target=nrf52840" "--frequency=4000000")
|
||||
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)
|
||||
include(${ZEPHYR_BASE}/boards/common/nrfutil.board.cmake)
|
||||
include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)
|
||||
include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake)
|
||||
include(${ZEPHYR_BASE}/boards/common/openocd-nrf5.board.cmake)
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
board:
|
||||
name: nrf52840_qalmari
|
||||
full_name: nRF52840 Qalmari
|
||||
vendor: qalmari
|
||||
socs:
|
||||
- name: nrf52840
|
||||
Executable
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/* Flash partition table without support for Nordic nRF5 bootloader */
|
||||
|
||||
&flash0 {
|
||||
partitions {
|
||||
compatible = "fixed-partitions";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
/* The size of this partition ensures that MCUBoot can be built
|
||||
* with an RTT console, CDC ACM support, and w/o optimizations.
|
||||
*/
|
||||
boot_partition: partition@0 {
|
||||
label = "mcuboot";
|
||||
reg = <0x00000000 0x00087000>;
|
||||
};
|
||||
|
||||
// slot0_partition: partition@12000 {
|
||||
// label = "image-0";
|
||||
// reg = <0x00012000 0x00075000>;
|
||||
// };
|
||||
slot1_partition: partition@87000 {
|
||||
label = "image-1";
|
||||
reg = <0x00087000 0x00075000>;
|
||||
};
|
||||
storage_partition: partition@fc000 {
|
||||
label = "storage";
|
||||
reg = <0x000fc000 0x00004000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Nordic Semiconductor
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
&pinctrl {
|
||||
uart0_default: uart0_default {
|
||||
group1 {
|
||||
psels = <NRF_PSEL(UART_TX, 0, 17)>;
|
||||
};
|
||||
group2 {
|
||||
psels = <NRF_PSEL(UART_RX, 0, 15)>;
|
||||
bias-pull-up;
|
||||
};
|
||||
};
|
||||
|
||||
uart0_sleep: uart0_sleep {
|
||||
group1 {
|
||||
psels = <NRF_PSEL(UART_TX, 0, 16)>,
|
||||
<NRF_PSEL(UART_RX, 0, 24)>,
|
||||
<NRF_PSEL(UART_RTS, 0, 14)>,
|
||||
<NRF_PSEL(UART_CTS, 0, 22)>;
|
||||
low-power-enable;
|
||||
};
|
||||
};
|
||||
|
||||
i2c0_default: i2c0_default {
|
||||
group1 {
|
||||
psels = <NRF_PSEL(TWIM_SDA, 0, 21)>, <NRF_PSEL(TWIM_SCL, 0, 19)>;
|
||||
};
|
||||
};
|
||||
|
||||
i2c0_sleep: i2c0_sleep {
|
||||
group1 {
|
||||
psels = <NRF_PSEL(TWIM_SDA, 0, 21)>, <NRF_PSEL(TWIM_SCL, 0, 19)>;
|
||||
low-power-enable;
|
||||
};
|
||||
};
|
||||
|
||||
i2c1_default: i2c1_default {
|
||||
group1 {
|
||||
psels = <NRF_PSEL(TWIM_SCL, 0, 19)>, <NRF_PSEL(TWIM_SDA, 0, 21)>;
|
||||
};
|
||||
};
|
||||
|
||||
i2c1_sleep: i2c1_sleep {
|
||||
group1 {
|
||||
psels = <NRF_PSEL(TWIM_SCL, 0, 19)>, <NRF_PSEL(TWIM_SDA, 0, 21)>;
|
||||
low-power-enable;
|
||||
};
|
||||
};
|
||||
|
||||
i2s0_default: i2s0_default {
|
||||
group1 {
|
||||
psels = <NRF_PSEL(I2S_SCK_M, 1, 11)>,
|
||||
<NRF_PSEL(I2S_LRCK_M, 1, 12)>,
|
||||
<NRF_PSEL(I2S_SDOUT, 0, 25)>,
|
||||
<NRF_PSEL(I2S_SDIN, 1, 14)>;
|
||||
};
|
||||
};
|
||||
|
||||
pwm0_default: pwm0_default {
|
||||
group1 {
|
||||
psels = <NRF_PSEL(PWM_OUT0, 0, 13)>,
|
||||
<NRF_PSEL(PWM_OUT1, 0, 6)>;
|
||||
};
|
||||
};
|
||||
|
||||
pwm0_sleep: pwm0_sleep {
|
||||
group1 {
|
||||
psels = <NRF_PSEL(PWM_OUT0, 0, 13)>,
|
||||
<NRF_PSEL(PWM_OUT1, 0, 6)>;
|
||||
low-power-enable;
|
||||
};
|
||||
};
|
||||
|
||||
pwm1_leds_default: pwm1_leds_default {
|
||||
group1 {
|
||||
psels = <NRF_PSEL(PWM_OUT0, 0, 30)>,
|
||||
<NRF_PSEL(PWM_OUT1, 0, 8)>,
|
||||
<NRF_PSEL(PWM_OUT2, 0, 20)>,
|
||||
<NRF_PSEL(PWM_OUT3, 1, 15)>;
|
||||
nordic,invert;
|
||||
};
|
||||
};
|
||||
|
||||
pwm1_leds_sleep: pwm1_leds_sleep {
|
||||
group1 {
|
||||
psels = <NRF_PSEL(PWM_OUT0, 0, 30)>,
|
||||
<NRF_PSEL(PWM_OUT1, 0, 8)>,
|
||||
<NRF_PSEL(PWM_OUT2, 0, 20)>,
|
||||
<NRF_PSEL(PWM_OUT3, 1, 15)>;
|
||||
nordic,invert;
|
||||
low-power-enable;
|
||||
};
|
||||
};
|
||||
|
||||
pwm2_leds_default: pwm2_leds_default {
|
||||
group1 {
|
||||
psels = <NRF_PSEL(PWM_OUT0, 1, 13)>,
|
||||
<NRF_PSEL(PWM_OUT1, 1, 10)>,
|
||||
<NRF_PSEL(PWM_OUT2, 0, 29)>,
|
||||
<NRF_PSEL(PWM_OUT3, 0, 31)>;
|
||||
nordic,invert;
|
||||
};
|
||||
};
|
||||
|
||||
pwm2_leds_sleep: pwm2_leds_sleep {
|
||||
group1 {
|
||||
psels = <NRF_PSEL(PWM_OUT0, 1, 13)>,
|
||||
<NRF_PSEL(PWM_OUT1, 1, 10)>,
|
||||
<NRF_PSEL(PWM_OUT2, 0, 29)>,
|
||||
<NRF_PSEL(PWM_OUT3, 0, 31)>;
|
||||
nordic,invert;
|
||||
low-power-enable;
|
||||
};
|
||||
};
|
||||
|
||||
spi0_default: spi0_default {
|
||||
group1 {
|
||||
psels = <NRF_PSEL(SPIM_SCK, 0, 27)>,
|
||||
<NRF_PSEL(SPIM_MOSI, 0, 25)>,
|
||||
<NRF_PSEL(SPIM_MISO, 1, 10)>;
|
||||
};
|
||||
};
|
||||
|
||||
spi0_sleep: spi0_sleep {
|
||||
group1 {
|
||||
psels = <NRF_PSEL(SPIM_SCK, 0, 27)>,
|
||||
<NRF_PSEL(SPIM_MOSI, 0, 25)>,
|
||||
<NRF_PSEL(SPIM_MISO, 1, 10)>;
|
||||
low-power-enable;
|
||||
};
|
||||
};
|
||||
|
||||
spi1_default: spi1_default {
|
||||
group1 {
|
||||
psels = <NRF_PSEL(SPIM_SCK, 0, 31)>,
|
||||
<NRF_PSEL(SPIM_MOSI, 0, 30)>,
|
||||
<NRF_PSEL(SPIM_MISO, 1, 13)>;
|
||||
};
|
||||
};
|
||||
|
||||
spi1_sleep: spi1_sleep {
|
||||
group1 {
|
||||
psels = <NRF_PSEL(SPIM_SCK, 0, 31)>,
|
||||
<NRF_PSEL(SPIM_MOSI, 0, 30)>,
|
||||
<NRF_PSEL(SPIM_MISO, 1, 13)>;
|
||||
low-power-enable;
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
+357
@@ -0,0 +1,357 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2023 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2017 Linaro Limited
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
#include <nordic/nrf52840_qiaa.dtsi>
|
||||
#include "nrf52840_qalmari-pinctrl.dtsi"
|
||||
#include <zephyr/dt-bindings/input/input-event-codes.h>
|
||||
#include <zephyr/dt-bindings/led/led.h>
|
||||
|
||||
#include "fstab.dtsi"
|
||||
|
||||
/ {
|
||||
model = "Nordic NRF52840 QALMARI";
|
||||
compatible = "nordic,nrf52840-qalmari";
|
||||
|
||||
chosen {
|
||||
zephyr,console = &cdc_acm_uart;
|
||||
zephyr,shell-uart = &cdc_acm_uart;
|
||||
zephyr,uart-mcumgr = &cdc_acm_uart;
|
||||
zephyr,bt-mon-uart = &cdc_acm_uart;
|
||||
zephyr,bt-c2h-uart = &cdc_acm_uart;
|
||||
zephyr,sram = &sram0;
|
||||
zephyr,flash = &flash0;
|
||||
zephyr,code-partition = &boot_partition;
|
||||
zephyr,ieee802154 = &ieee802154;
|
||||
};
|
||||
|
||||
leds {
|
||||
compatible = "gpio-leds";
|
||||
led1: led_1 {
|
||||
gpios = <&gpio0 30 GPIO_ACTIVE_LOW>;
|
||||
label = "LED 1";
|
||||
status = "okay";
|
||||
};
|
||||
led2: led_2 {
|
||||
gpios = <&gpio0 8 GPIO_ACTIVE_LOW>;
|
||||
label = "LED 2";
|
||||
status = "okay";
|
||||
};
|
||||
led3: led_3 {
|
||||
gpios = <&gpio0 20 GPIO_ACTIVE_LOW>;
|
||||
label = "LED 3";
|
||||
status = "okay";
|
||||
};
|
||||
led4: led_4 {
|
||||
gpios = <&gpio1 15 GPIO_ACTIVE_LOW>;
|
||||
label = "LED 4";
|
||||
status = "okay";
|
||||
};
|
||||
led5: led_5 {
|
||||
gpios = <&gpio1 13 GPIO_ACTIVE_LOW>;
|
||||
label = "LED 5";
|
||||
status = "okay";
|
||||
};
|
||||
led6: led_6 {
|
||||
gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
|
||||
label = "LED 6";
|
||||
status = "okay";
|
||||
};
|
||||
led7: led_7 {
|
||||
gpios = <&gpio0 29 GPIO_ACTIVE_LOW>;
|
||||
label = "LED 7";
|
||||
status = "okay";
|
||||
};
|
||||
led8: led_8 {
|
||||
gpios = <&gpio0 31 GPIO_ACTIVE_LOW>;
|
||||
label = "LED 8";
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
|
||||
pwmleds {
|
||||
compatible = "pwm-leds";
|
||||
pwm_led1: pwm_led_1 {
|
||||
pwms = <&pwm1 0 PWM_MSEC(20) PWM_POLARITY_INVERTED>;
|
||||
label = "PWM LED 1";
|
||||
};
|
||||
pwm_led2: pwm_led_2 {
|
||||
pwms = <&pwm1 1 PWM_MSEC(20) PWM_POLARITY_INVERTED>;
|
||||
label = "PWM LED 2";
|
||||
};
|
||||
pwm_led3: pwm_led_3 {
|
||||
pwms = <&pwm1 2 PWM_MSEC(20) PWM_POLARITY_INVERTED>;
|
||||
label = "PWM LED 3";
|
||||
};
|
||||
pwm_led4: pwm_led_4 {
|
||||
pwms = <&pwm1 3 PWM_MSEC(20) PWM_POLARITY_INVERTED>;
|
||||
label = "PWM LED 4";
|
||||
};
|
||||
pwm_led5: pwm_led_5 {
|
||||
pwms = <&pwm2 0 PWM_MSEC(20) PWM_POLARITY_INVERTED>;
|
||||
label = "PWM LED 5";
|
||||
};
|
||||
pwm_led6: pwm_led_6 {
|
||||
pwms = <&pwm2 1 PWM_MSEC(20) PWM_POLARITY_INVERTED>;
|
||||
label = "PWM LED 6";
|
||||
};
|
||||
pwm_led7: pwm_led_7 {
|
||||
pwms = <&pwm2 2 PWM_MSEC(20) PWM_POLARITY_INVERTED>;
|
||||
label = "PWM LED 7";
|
||||
};
|
||||
pwm_led8: pwm_led_8 {
|
||||
pwms = <&pwm2 3 PWM_MSEC(20) PWM_POLARITY_INVERTED>;
|
||||
label = "PWM LED 8";
|
||||
};
|
||||
};
|
||||
|
||||
pwm {
|
||||
compatible = "pwm-leds";
|
||||
pwm_vibration: pwm_vibration {
|
||||
pwms = <&pwm0 0 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
|
||||
label = "PWM vibration motor";
|
||||
};
|
||||
pwm_buzzer: pwm_buzzer {
|
||||
pwms = <&pwm0 1 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
|
||||
label = "PWM buzzer";
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
buttons {
|
||||
compatible = "gpio-keys";
|
||||
debounce-interval-ms = <100>;
|
||||
button1: button_1 {
|
||||
gpios = <&gpio0 17 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
|
||||
label = "Push button switch 1";
|
||||
zephyr,code = <INPUT_KEY_0>;
|
||||
};
|
||||
button2: button_2 {
|
||||
gpios = <&gpio0 15 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
|
||||
label = "Push button switch 2";
|
||||
zephyr,code = <INPUT_KEY_1>;
|
||||
};
|
||||
};
|
||||
|
||||
interrupts {
|
||||
compatible = "gpio-keys";
|
||||
interrupt_head: interrupt_head {
|
||||
gpios = <&gpio0 23 (GPIO_ACTIVE_HIGH)>;
|
||||
label = "head interrupt pin";
|
||||
};
|
||||
};
|
||||
|
||||
aliases {
|
||||
btn1 = &button1;
|
||||
btn2 = &button2;
|
||||
int-head = &interrupt_head;
|
||||
int-btn-1 = &button1;
|
||||
int-btn-2 = &button2;
|
||||
led1 = &led1;
|
||||
led2 = &led2;
|
||||
led3 = &led3;
|
||||
led4 = &led4;
|
||||
led5 = &led5;
|
||||
led6 = &led6;
|
||||
led7 = &led7;
|
||||
led8 = &led8;
|
||||
pwm-led1 = &pwm_led1;
|
||||
pwm-led2 = &pwm_led2;
|
||||
pwm-led3 = &pwm_led3;
|
||||
pwm-led4 = &pwm_led4;
|
||||
pwm-led5 = &pwm_led5;
|
||||
pwm-led6 = &pwm_led6;
|
||||
pwm-led7 = &pwm_led7;
|
||||
pwm-led8 = &pwm_led8;
|
||||
buzzer = &pwm_buzzer;
|
||||
vibration = &pwm_vibration;
|
||||
mcuboot-button0 = &button1;
|
||||
mcuboot-button1 = &button2;
|
||||
mcuboot-led0 = &led1;
|
||||
watchdog0 = &wdt0;
|
||||
pwm0 = &pwm0;
|
||||
pwm-leds = &pwm1;
|
||||
led-strip = &led_strip;
|
||||
i2c-1 = &i2c1;
|
||||
uart-0 = &uart0;
|
||||
};
|
||||
|
||||
vbatt {
|
||||
status = "okay";
|
||||
compatible = "voltage-divider";
|
||||
io-channels = <&adc 2>;
|
||||
output-ohms = <100000>;
|
||||
full-ohms = <(100000 + 100000)>;
|
||||
//power-gpios = <&gpio0 11 GPIO_PULL_UP>;
|
||||
};
|
||||
};
|
||||
|
||||
&pwm0 {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&pwm0_default>;
|
||||
pinctrl-1 = <&pwm0_sleep>;
|
||||
pinctrl-names = "default", "sleep";
|
||||
};
|
||||
|
||||
&pwm1 {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&pwm1_leds_default>;
|
||||
pinctrl-1 = <&pwm1_leds_sleep>;
|
||||
pinctrl-names = "default", "sleep";
|
||||
};
|
||||
|
||||
&pwm2 {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&pwm2_leds_default>;
|
||||
pinctrl-1 = <&pwm2_leds_sleep>;
|
||||
pinctrl-names = "default", "sleep";
|
||||
};
|
||||
|
||||
&uart0 {
|
||||
compatible = "nordic,nrf-uarte";
|
||||
status = "okay";
|
||||
current-speed = <115200>;
|
||||
pinctrl-0 = <&uart0_default>;
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
|
||||
&spi0 {
|
||||
compatible = "nordic,nrf-spi";
|
||||
/* Cannot be used together with i2c0. */
|
||||
status = "okay";
|
||||
pinctrl-0 = <&spi0_default>;
|
||||
pinctrl-1 = <&spi0_sleep>;
|
||||
pinctrl-names = "default", "sleep";
|
||||
led_strip: ws2812-spi@0 {
|
||||
compatible = "worldsemi,ws2812-spi";
|
||||
reg = <0x0>;
|
||||
|
||||
chain-length = <2>;
|
||||
color-mapping = <LED_COLOR_ID_GREEN
|
||||
LED_COLOR_ID_RED
|
||||
LED_COLOR_ID_BLUE>;
|
||||
spi-one-frame = <0x70>;
|
||||
spi-zero-frame = <0x40>;
|
||||
spi-max-frequency = <4000000>;
|
||||
};
|
||||
};
|
||||
|
||||
&spi1 {
|
||||
compatible = "nordic,nrf-spi";
|
||||
//status = "okay";
|
||||
status = "disabled";
|
||||
pinctrl-0 = <&spi1_default>;
|
||||
pinctrl-1 = <&spi1_sleep>;
|
||||
pinctrl-names = "default", "sleep";
|
||||
};
|
||||
|
||||
&i2c0 {
|
||||
/* Cannot be used together with spi0. */
|
||||
status = "disabled";
|
||||
pinctrl-0 = <&i2c0_default>;
|
||||
pinctrl-names = "default";
|
||||
clock-frequency = <I2C_BITRATE_STANDARD>;
|
||||
};
|
||||
|
||||
&i2c1 {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&i2c1_default>;
|
||||
pinctrl-names = "default";
|
||||
clock-frequency = <I2C_BITRATE_STANDARD>;
|
||||
};
|
||||
|
||||
zephyr_udc0: &usbd {
|
||||
compatible = "nordic,nrf-usbd";
|
||||
status = "okay";
|
||||
|
||||
cdc_acm_uart: cdc_acm_uart {
|
||||
compatible = "zephyr,cdc-acm-uart";
|
||||
};
|
||||
};
|
||||
|
||||
&ieee802154 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&adc {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&gpiote {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&uicr {
|
||||
nfct-pins-as-gpios;
|
||||
gpio-as-nreset;
|
||||
};
|
||||
|
||||
&gpio0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&gpio1 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&systick {
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
&nfct {
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
&egu0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&ccm {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&cryptocell {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&ecb {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&rng {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&ppi {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&clock {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
// RTC0 is not okay anymore! v.4.3.99
|
||||
// &rtc0 {
|
||||
// status = "okay";
|
||||
// };
|
||||
|
||||
&mwu {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&power {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&acl {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
// ITM is used for printf debugging and tracing on the SWO pin
|
||||
&itm {
|
||||
status = "okay";
|
||||
};
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
identifier: nrf52840_qalmari
|
||||
name: NRF52840-QALMARI
|
||||
type: mcu
|
||||
arch: arm
|
||||
ram: 256
|
||||
flash: 1024
|
||||
toolchain:
|
||||
- zephyr
|
||||
- gnuarmemb
|
||||
- xtools
|
||||
supported:
|
||||
- adc
|
||||
- usb_device
|
||||
- usb_cdc
|
||||
- ble
|
||||
- pwm
|
||||
- spi
|
||||
- watchdog
|
||||
- counter
|
||||
- netif:openthread
|
||||
- gpio
|
||||
vendor: qalmari
|
||||
@@ -0,0 +1,22 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# CONFIG_SOC_SERIES_NRF52X=y
|
||||
# CONFIG_SOC_NRF52840_QIAA=y
|
||||
# CONFIG_BOARD_NRF52840_QALMARI=y
|
||||
|
||||
# Disable DCDC converter
|
||||
CONFIG_BOARD_ENABLE_DCDC=n
|
||||
CONFIG_BOARD_ENABLE_DCDC_HV=n
|
||||
|
||||
# 32K clock
|
||||
CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y
|
||||
CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC_CALIBRATION=y
|
||||
|
||||
# Enable MPU
|
||||
CONFIG_ARM_MPU=y
|
||||
|
||||
# enable GPIO
|
||||
CONFIG_GPIO=y
|
||||
|
||||
# Enable Zephyr application to be booted by MCUboot
|
||||
# CONFIG_BOOTLOADER_MCUBOOT=y
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
# Copyright (c) 2022 Nordic Semiconductor
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# Suppress "unique_unit_address_if_enabled" to handle the following overlaps:
|
||||
# - power@40000000 & clock@40000000 & bprot@40000000
|
||||
# - acl@4001e000 & flash-controller@4001e000
|
||||
list(APPEND EXTRA_DTC_FLAGS "-Wno-unique_unit_address_if_enabled")
|
||||
@@ -0,0 +1,45 @@
|
||||
CONFIG_GPIO=y
|
||||
|
||||
# PWM
|
||||
CONFIG_PWM=y
|
||||
|
||||
# LED Strip
|
||||
CONFIG_LED_STRIP=y
|
||||
CONFIG_SPI=y
|
||||
|
||||
# Serial
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_CONSOLE=y
|
||||
CONFIG_USB_DEVICE_STACK=y
|
||||
# CONFIG_USB_DEVICE_STACK_NEXT=y
|
||||
CONFIG_USB_CDC_ACM=y
|
||||
CONFIG_CDC_ACM_SERIAL_INITIALIZE_AT_BOOT=n
|
||||
CONFIG_USBD_LOOPBACK_CLASS=y
|
||||
CONFIG_UDC_BUF_POOL_SIZE=4096
|
||||
|
||||
# Shell
|
||||
CONFIG_SHELL=y
|
||||
CONFIG_USBD_SHELL=y
|
||||
|
||||
# Storage
|
||||
CONFIG_NVS=y
|
||||
CONFIG_FLASH=y
|
||||
CONFIG_FLASH_MAP=y
|
||||
|
||||
# I2C
|
||||
CONFIG_I2C=y
|
||||
CONFIG_I2C_TARGET=y
|
||||
|
||||
# LOG
|
||||
CONFIG_LOG=y
|
||||
CONFIG_LOG_DEFAULT_LEVEL=3
|
||||
CONFIG_LOG_MODE_IMMEDIATE=y
|
||||
CONFIG_USBD_LOG_LEVEL_WRN=y
|
||||
CONFIG_UDC_DRIVER_LOG_LEVEL_WRN=y
|
||||
|
||||
#ZBUS
|
||||
CONFIG_ZBUS=y
|
||||
CONFIG_ZBUS_LOG_LEVEL_INF=n
|
||||
CONFIG_ZBUS_CHANNEL_NAME=y
|
||||
CONFIG_ZBUS_OBSERVER_NAME=y
|
||||
CONFIG_ZBUS_MSG_SUBSCRIBER=y
|
||||
@@ -0,0 +1,49 @@
|
||||
#include "buttons.hpp"
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
LOG_MODULE_REGISTER(buttons, CONFIG_LOG_MAX_LEVEL);
|
||||
K_WORK_DELAYABLE_DEFINE(debounce_work_btn, Buttons::debounce_cb);
|
||||
#define DEBOUNCE_TIME_MS 100
|
||||
|
||||
static const struct gpio_dt_spec Buttons::buttons[Buttons::NR_BUTTONS] = {
|
||||
GPIO_DT_SPEC_GET_OR(DT_ALIAS(int_btn_1), gpios, {0}),
|
||||
GPIO_DT_SPEC_GET_OR(DT_ALIAS(int_btn_2), gpios, {0})
|
||||
};
|
||||
static struct gpio_callback Buttons::buttons_cb_data[Buttons::NR_BUTTONS];
|
||||
|
||||
Buttons::Buttons() {
|
||||
buttons_init();
|
||||
}
|
||||
|
||||
int Buttons::buttons_init() {
|
||||
// BUTTON 1
|
||||
gpio_pin_configure_dt(&buttons[BUTTON1], GPIO_INPUT);
|
||||
gpio_pin_interrupt_configure_dt(&(buttons[BUTTON1]), GPIO_INT_EDGE_TO_ACTIVE);
|
||||
gpio_init_callback(&buttons_cb_data[0], buttons_cb, BIT(buttons[BUTTON1].pin));
|
||||
gpio_add_callback(buttons[BUTTON1].port, &buttons_cb_data[0]);
|
||||
|
||||
// BUTTON 2
|
||||
gpio_pin_configure_dt(&buttons[BUTTON2], GPIO_INPUT);
|
||||
gpio_pin_interrupt_configure_dt(&buttons[BUTTON2], GPIO_INT_EDGE_TO_ACTIVE);
|
||||
gpio_init_callback(&buttons_cb_data[1], buttons_cb, BIT(buttons[BUTTON2].pin));
|
||||
gpio_add_callback(buttons[BUTTON2].port, &buttons_cb_data[1]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void Buttons::debounce_cb(struct k_work *work) {
|
||||
if ( gpio_pin_get_dt(&buttons[BUTTON1]) == GPIO_ACTIVE_HIGH ||
|
||||
gpio_pin_get_dt(&buttons[BUTTON2]) == GPIO_ACTIVE_HIGH) {
|
||||
LOG_DBG("Callback");
|
||||
}
|
||||
}
|
||||
|
||||
static void Buttons::buttons_cb(const struct device *dev, struct gpio_callback *cb, uint32_t pins) {
|
||||
LOG_DBG("Button:");
|
||||
if (k_work_delayable_is_pending(&debounce_work_btn)) {
|
||||
} else {
|
||||
k_work_schedule(&debounce_work_btn, K_MSEC(DEBOUNCE_TIME_MS));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <zephyr/drivers/gpio.h>
|
||||
|
||||
|
||||
class Buttons {
|
||||
public:
|
||||
|
||||
enum Buttons_e {
|
||||
BUTTON1,
|
||||
BUTTON2,
|
||||
NR_BUTTONS,
|
||||
};
|
||||
|
||||
Buttons();
|
||||
~Buttons();
|
||||
int buttons_init();
|
||||
static void buttons_cb(const struct device *dev, struct gpio_callback *cb, uint32_t pins);
|
||||
static void debounce_cb(struct k_work *work);
|
||||
|
||||
private:
|
||||
static const struct gpio_dt_spec buttons[NR_BUTTONS];
|
||||
static struct gpio_callback buttons_cb_data[NR_BUTTONS];
|
||||
};
|
||||
@@ -0,0 +1,64 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <zephyr/drivers/flash.h>
|
||||
#include <zephyr/fs/nvs.h>
|
||||
#include <zephyr/storage/flash_map.h>
|
||||
|
||||
#define NVS_ID_CONFIG 1
|
||||
|
||||
static struct nvs_fs nvs;
|
||||
static app_config_t ram_config;
|
||||
|
||||
#define CONFIG_ID 0xDEADBEEF
|
||||
#define CONFIG_VERSION 1
|
||||
|
||||
static const app_config_t default_config = {
|
||||
.id = CONFIG_ID,
|
||||
.version = CONFIG_VERSION,
|
||||
.device_name = "my-device",
|
||||
.baud_rate = 115200,
|
||||
.log_level = 3,
|
||||
.feature_enabled = false,
|
||||
};
|
||||
|
||||
int config_init(void)
|
||||
{
|
||||
struct flash_pages_info page;
|
||||
const struct device *dev = FIXED_PARTITION_DEVICE(storage_partition);
|
||||
|
||||
flash_get_page_info_by_offs(dev, FIXED_PARTITION_OFFSET(storage_partition), &page);
|
||||
|
||||
nvs.flash_device = dev;
|
||||
nvs.offset = FIXED_PARTITION_OFFSET(storage_partition);
|
||||
nvs.sector_size = page.size;
|
||||
nvs.sector_count = FIXED_PARTITION_SIZE(storage_partition) / page.size;
|
||||
|
||||
int rc = nvs_mount(&nvs);
|
||||
if (rc) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
ssize_t ret = nvs_read(&nvs, NVS_ID_CONFIG, &ram_config, sizeof(ram_config));
|
||||
if (ret != sizeof(ram_config) || ram_config.id != CONFIG_ID || ram_config.version != CONFIG_VERSION) {
|
||||
ram_config = default_config;
|
||||
nvs_write(&nvs, NVS_ID_CONFIG, &ram_config, sizeof(ram_config));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_save(const app_config_t *cfg)
|
||||
{
|
||||
ram_config = *cfg;
|
||||
return nvs_write(&nvs, NVS_ID_CONFIG, &ram_config, sizeof(ram_config));
|
||||
}
|
||||
|
||||
void config_update(void)
|
||||
{
|
||||
nvs_read(&nvs, NVS_ID_CONFIG, &ram_config, sizeof(ram_config));
|
||||
}
|
||||
|
||||
void config_get(app_config_t *cfg)
|
||||
{
|
||||
*cfg = ram_config;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct {
|
||||
uint32_t id;
|
||||
uint16_t version;
|
||||
char device_name[32];
|
||||
uint32_t baud_rate;
|
||||
uint8_t log_level;
|
||||
bool feature_enabled;
|
||||
} app_config_t;
|
||||
|
||||
int config_init(void);
|
||||
int config_save(const app_config_t *cfg);
|
||||
void config_update(void);
|
||||
void config_get(app_config_t *cfg);
|
||||
|
||||
#endif /* CONFIG_H */
|
||||
@@ -0,0 +1,62 @@
|
||||
#include <zephyr/shell/shell.h>
|
||||
#include "config.h"
|
||||
|
||||
|
||||
static int cmd_config_read(const struct shell *sh, size_t argc, char **argv)
|
||||
{
|
||||
ARG_UNUSED(argc);
|
||||
ARG_UNUSED(argv);
|
||||
|
||||
app_config_t cfg;
|
||||
config_get(&cfg);
|
||||
|
||||
shell_print(sh, "device_name: %s", cfg.device_name);
|
||||
shell_print(sh, "baud_rate: %u", cfg.baud_rate);
|
||||
shell_print(sh, "log_level: %u", cfg.log_level);
|
||||
shell_print(sh, "feature_enabled: %s", cfg.feature_enabled ? "true" : "false");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_config_update(const struct shell *sh, size_t argc, char **argv)
|
||||
{
|
||||
ARG_UNUSED(argc);
|
||||
ARG_UNUSED(argv);
|
||||
|
||||
config_update();
|
||||
shell_print(sh, "Config refreshed from NVS");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_config_baud(const struct shell *sh, size_t argc, char **argv)
|
||||
{
|
||||
if (argc != 2) {
|
||||
shell_error(sh, "Usage: config baud <rate>");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
uint32_t baud = (uint32_t)strtoul(argv[1], NULL, 10);
|
||||
if (baud == 0) {
|
||||
shell_error(sh, "Invalid baud rate");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
app_config_t cfg;
|
||||
config_get(&cfg);
|
||||
cfg.baud_rate = baud;
|
||||
config_save(&cfg);
|
||||
|
||||
shell_print(sh, "Baud rate updated to %u", baud);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SHELL_STATIC_SUBCMD_SET_CREATE(config_cmds,
|
||||
SHELL_CMD(read, NULL, "Print config from RAM", cmd_config_read),
|
||||
SHELL_CMD(update, NULL, "Refresh RAM config from NVS", cmd_config_update),
|
||||
SHELL_CMD(baud, NULL, "Set baud rate: config baud <rate>", cmd_config_baud),
|
||||
SHELL_SUBCMD_SET_END
|
||||
);
|
||||
|
||||
SHELL_CMD_REGISTER(config, &config_cmds, "Config commands", NULL);
|
||||
@@ -0,0 +1,148 @@
|
||||
#include "imu.h"
|
||||
#include "zbus_channels.h"
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/drivers/i2c.h>
|
||||
|
||||
LOG_MODULE_REGISTER(imu, CONFIG_LOG_MAX_LEVEL);
|
||||
K_WORK_DELAYABLE_DEFINE(debounce_work_imu, debounce_cb);
|
||||
|
||||
#define DEBOUNCE_TIME_MS 100
|
||||
#define DOUBLE_TAP_TIME_MS 500
|
||||
|
||||
/* Starting register for X-axis data (e.g., OUT_X_L register) */
|
||||
#define ACCEL_REG_OUT_X_L 0x3B
|
||||
|
||||
static const uint8_t i2c_address = 0b1101001;
|
||||
|
||||
static const struct gpio_dt_spec imu_int = GPIO_DT_SPEC_GET_OR(DT_ALIAS(int_head), gpios, {0});
|
||||
static struct gpio_callback imu_cb_data;
|
||||
static const struct device *const i2c_dev = DEVICE_DT_GET(DT_ALIAS(i2c_1));
|
||||
|
||||
static uint32_t last_tap = 0;
|
||||
|
||||
void imu_reset() {
|
||||
const uint8_t PWR_MGMT_1[2] = {0x6B, (uint8_t)(1 << 7)};
|
||||
i2c_write(i2c_dev, PWR_MGMT_1, sizeof(PWR_MGMT_1), i2c_address);
|
||||
k_sleep(K_MSEC(100));
|
||||
|
||||
}
|
||||
|
||||
int imu_init() {
|
||||
if (!device_is_ready(i2c_dev)) {
|
||||
LOG_ERR("I2C device %s is not ready.\n", i2c_dev->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// imu_reset();
|
||||
|
||||
// Ensure that Accelerometer is running
|
||||
const uint8_t PWR_MGMT_1[2] = {0x6B, 0x00};
|
||||
const uint8_t PWR_MGMT_2[2] = {0x6C, 0x00};
|
||||
|
||||
// Accelerometer Configuration
|
||||
const uint8_t ACCEL_CONFIG_1[2] = {0x1C, 0b00011000};
|
||||
const uint8_t ACCEL_CONFIG_2[2] = {0x1D, 0b00000000};
|
||||
|
||||
// Enable Motion Interrupt
|
||||
const uint8_t INT_ENABLE[2] = {0x38, 0b00100000};
|
||||
|
||||
// Set Motion Threshold
|
||||
const uint8_t ACCEL_WOM_X_THR[2] = {0x20, 0xff};
|
||||
const uint8_t ACCEL_WOM_Y_THR[2] = {0x21, 0x8f};
|
||||
const uint8_t ACCEL_WOM_Z_THR[2] = {0x22, 0xff};
|
||||
|
||||
// Set Interrupt Mode & Enable Accelerometer Hardware Intelligence
|
||||
const uint8_t ACCEL_INTEL_CTRL[2] = {0x69, 0xc0};
|
||||
|
||||
// Set Frequency of Wake-Up
|
||||
const uint8_t SMPLRT_DIV[2] = {0x19, 0x00};
|
||||
|
||||
// Enable Cycle Mode (Accelerometer Low-Power Mode)
|
||||
const uint8_t PWR_MGMT_1_A[2] = {0x6B, 0x20};
|
||||
|
||||
int ret;
|
||||
i2c_write(i2c_dev, PWR_MGMT_1, sizeof(PWR_MGMT_1), i2c_address);
|
||||
k_sleep(K_MSEC(1));
|
||||
i2c_write(i2c_dev, PWR_MGMT_2, sizeof(PWR_MGMT_2), i2c_address);
|
||||
k_sleep(K_MSEC(1));
|
||||
i2c_write(i2c_dev, ACCEL_CONFIG_1, sizeof(ACCEL_CONFIG_1), i2c_address);
|
||||
k_sleep(K_MSEC(1));
|
||||
i2c_write(i2c_dev, ACCEL_CONFIG_2, sizeof(ACCEL_CONFIG_2), i2c_address);
|
||||
k_sleep(K_MSEC(1));
|
||||
i2c_write(i2c_dev, INT_ENABLE, sizeof(INT_ENABLE), i2c_address);
|
||||
k_sleep(K_MSEC(1));
|
||||
// // i2c_write(i2c_dev, ACCEL_WOM_X_THR, sizeof(ACCEL_WOM_X_THR), i2c_address);
|
||||
// // k_sleep(K_MSEC(1));
|
||||
// i2c_write(i2c_dev, ACCEL_WOM_Y_THR, sizeof(ACCEL_WOM_Y_THR), i2c_address);
|
||||
// k_sleep(K_MSEC(1));
|
||||
i2c_write(i2c_dev, ACCEL_WOM_Z_THR, sizeof(ACCEL_WOM_Z_THR), i2c_address);
|
||||
k_sleep(K_MSEC(1));
|
||||
i2c_write(i2c_dev, ACCEL_INTEL_CTRL, sizeof(ACCEL_INTEL_CTRL), i2c_address);
|
||||
k_sleep(K_MSEC(1));
|
||||
i2c_write(i2c_dev, SMPLRT_DIV, sizeof(SMPLRT_DIV), i2c_address);
|
||||
k_sleep(K_MSEC(1));
|
||||
i2c_write(i2c_dev, PWR_MGMT_1_A, sizeof(PWR_MGMT_1_A), i2c_address);
|
||||
k_sleep(K_MSEC(100));
|
||||
|
||||
gpio_pin_configure_dt(&(imu_int), GPIO_INPUT);
|
||||
gpio_pin_interrupt_configure_dt(&(imu_int), GPIO_INT_EDGE_TO_ACTIVE);
|
||||
gpio_init_callback(&imu_cb_data, imu_cb, BIT(imu_int.pin));
|
||||
gpio_add_callback(imu_int.port, &imu_cb_data);
|
||||
|
||||
last_tap = k_uptime_get();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void imu_read(struct accel_data_t *buf) {
|
||||
uint8_t raw_accel_data[6];
|
||||
|
||||
// LIGHT
|
||||
uint16_t reg = ACCEL_REG_OUT_X_L;
|
||||
|
||||
/* Write register address, then read consecutive data bytes */
|
||||
int ret = i2c_write_read(i2c_dev,
|
||||
i2c_address,
|
||||
®,
|
||||
sizeof(reg),
|
||||
raw_accel_data,
|
||||
sizeof(raw_accel_data));
|
||||
|
||||
if (ret) {
|
||||
printk("Error: I2C burst read failed (%d)\n", ret);
|
||||
} else {
|
||||
/* Combine low and high bytes for each axis */
|
||||
buf->x = (int16_t)((raw_accel_data[1] << 8) | raw_accel_data[0]);
|
||||
buf->y = (int16_t)((raw_accel_data[3] << 8) | raw_accel_data[2]);
|
||||
buf->z = (int16_t)((raw_accel_data[5] << 8) | raw_accel_data[4]);
|
||||
}
|
||||
}
|
||||
|
||||
static void debounce_cb(struct k_work *work) {
|
||||
if (gpio_pin_get_dt(&imu_int) == GPIO_ACTIVE_HIGH) {
|
||||
if (k_uptime_get() - last_tap > DOUBLE_TAP_TIME_MS) {
|
||||
LOG_INF("Tap");
|
||||
}
|
||||
else {
|
||||
LOG_INF("Double tap");
|
||||
struct button_msg_t msg;
|
||||
msg.button = IMU;
|
||||
msg.function = DOUBLE_TAP;
|
||||
zbus_chan_pub(&buttons_data_chan, &msg, K_NO_WAIT);
|
||||
}
|
||||
last_tap = k_uptime_get();
|
||||
}
|
||||
}
|
||||
|
||||
static void imu_cb(const struct device *dev, struct gpio_callback *cb, uint32_t pins) {
|
||||
|
||||
/* Check if the work item is already running */
|
||||
if (k_work_delayable_is_pending(&debounce_work_imu)) {
|
||||
/* Do nothing, as the work item is already running */
|
||||
} else {
|
||||
k_work_schedule(&debounce_work_imu, K_MSEC(DEBOUNCE_TIME_MS));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef IMU_H
|
||||
#define IMU_H
|
||||
|
||||
#include <zephyr/drivers/gpio.h>
|
||||
|
||||
|
||||
struct accel_data_t {
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
int16_t z;
|
||||
};
|
||||
|
||||
|
||||
int imu_init();
|
||||
void imu_read(struct accel_data_t *buf);
|
||||
static void imu_cb(const struct device *dev, struct gpio_callback *cb, uint32_t pins);
|
||||
static void debounce_cb(struct k_work *work);
|
||||
|
||||
|
||||
|
||||
#endif // IMU_H
|
||||
@@ -0,0 +1,211 @@
|
||||
// LOCAL
|
||||
#include "led.h"
|
||||
|
||||
// ZEPHYR
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/drivers/pwm.h>
|
||||
#include <zephyr/drivers/led_strip.h>
|
||||
|
||||
LOG_MODULE_REGISTER(leds, LOG_LEVEL_INF);
|
||||
|
||||
#define STRIP_NODE DT_ALIAS(led_strip)
|
||||
#define STRIP_NUM_PIXELS DT_PROP(STRIP_NODE, chain_length)
|
||||
#define STRIP_MAX_BRIGHTNESS 255
|
||||
|
||||
static const struct device *const strip = DEVICE_DT_GET(STRIP_NODE);
|
||||
static struct led_rgb pixels[STRIP_NUM_PIXELS];
|
||||
|
||||
#define NR_LEDS 8
|
||||
#define PWM_RESOLUTION 255
|
||||
|
||||
static const struct pwm_dt_spec led1 = PWM_DT_SPEC_GET(DT_ALIAS(pwm_led1));
|
||||
static const struct pwm_dt_spec led2 = PWM_DT_SPEC_GET(DT_ALIAS(pwm_led2));
|
||||
static const struct pwm_dt_spec led3 = PWM_DT_SPEC_GET(DT_ALIAS(pwm_led3));
|
||||
static const struct pwm_dt_spec led4 = PWM_DT_SPEC_GET(DT_ALIAS(pwm_led4));
|
||||
static const struct pwm_dt_spec led5 = PWM_DT_SPEC_GET(DT_ALIAS(pwm_led5));
|
||||
static const struct pwm_dt_spec led6 = PWM_DT_SPEC_GET(DT_ALIAS(pwm_led6));
|
||||
static const struct pwm_dt_spec led7 = PWM_DT_SPEC_GET(DT_ALIAS(pwm_led7));
|
||||
static const struct pwm_dt_spec led8 = PWM_DT_SPEC_GET(DT_ALIAS(pwm_led8));
|
||||
|
||||
static const struct pwm_dt_spec *leds[NR_LEDS] = {&led1, &led2, &led3, &led4, &led5, &led6, &led7, &led8};
|
||||
|
||||
|
||||
int set_pwm(const struct pwm_dt_spec *dev, uint32_t value, uint32_t max_brightness) {
|
||||
if ((value <= max_brightness) && (max_brightness > 0)) {
|
||||
uint32_t pulse_width_ns = value * (dev->period / max_brightness);
|
||||
int ret = pwm_set_pulse_dt(dev, pulse_width_ns);
|
||||
|
||||
return ret;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int led_init(void) {
|
||||
// Checking if devices are ready
|
||||
for (int i = 0; i < NR_LEDS; i++) {
|
||||
if (!device_is_ready(leds[i]->dev)) {
|
||||
LOG_ERR("PWM LEDs not ready");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_INF("PWM LEDs initialized");
|
||||
|
||||
if (!device_is_ready(strip)) {
|
||||
LOG_ERR("LED strip device not ready");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
LOG_INF("LED strip initialized with %d pixels", STRIP_NUM_PIXELS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int led_fade(uint32_t duration) {
|
||||
uint32_t step_duration = (duration * 1000) / (PWM_RESOLUTION * 2);
|
||||
|
||||
for (int i = 0; i < PWM_RESOLUTION; i++) {
|
||||
for (int j = 0; j < NR_LEDS; j++) {
|
||||
set_pwm(leds[j], i, PWM_RESOLUTION);
|
||||
}
|
||||
k_sleep(K_USEC(step_duration));
|
||||
}
|
||||
for (int i = 0; i < PWM_RESOLUTION; i++) {
|
||||
for (int j = 0; j < NR_LEDS; j++) {
|
||||
set_pwm(leds[j], (PWM_RESOLUTION - i - 1), PWM_RESOLUTION);
|
||||
}
|
||||
k_sleep(K_USEC(step_duration));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int led_fade_in(uint32_t duration) {
|
||||
uint32_t step_duration = (duration * 1000) / (PWM_RESOLUTION);
|
||||
|
||||
for (int i = 0; i < PWM_RESOLUTION; i++) {
|
||||
for (int j = 0; j < NR_LEDS; j++) {
|
||||
set_pwm(leds[j], i, PWM_RESOLUTION);
|
||||
}
|
||||
k_sleep(K_USEC(step_duration));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int led_fade_out(uint32_t duration) {
|
||||
uint32_t step_duration = (duration * 1000) / (PWM_RESOLUTION);
|
||||
|
||||
for (int i = 0; i < PWM_RESOLUTION; i++) {
|
||||
for (int j = 0; j < NR_LEDS; j++) {
|
||||
set_pwm(leds[j], (PWM_RESOLUTION - i - 1), PWM_RESOLUTION);
|
||||
}
|
||||
k_sleep(K_USEC(step_duration));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int led_set_progress(float progress) {
|
||||
uint32_t total_progress = (progress * NR_LEDS * PWM_RESOLUTION);
|
||||
|
||||
for (int i = 0; i < NR_LEDS; i++) {
|
||||
if (total_progress > PWM_RESOLUTION) {
|
||||
set_pwm(leds[i], PWM_RESOLUTION, PWM_RESOLUTION);
|
||||
total_progress -= PWM_RESOLUTION;
|
||||
}
|
||||
else {
|
||||
set_pwm(leds[i], total_progress, PWM_RESOLUTION);
|
||||
total_progress = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* LED strip */
|
||||
|
||||
int leds_set_color(uint8_t led_index, float r, float g, float b) {
|
||||
if (led_index >= STRIP_NUM_PIXELS) {
|
||||
LOG_ERR("LED index %d out of range (max %d)", led_index, STRIP_NUM_PIXELS - 1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pixels[led_index].r = r * STRIP_MAX_BRIGHTNESS;
|
||||
pixels[led_index].g = g * STRIP_MAX_BRIGHTNESS;
|
||||
pixels[led_index].b = b * STRIP_MAX_BRIGHTNESS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int leds_set_all(float r, float g, float b) {
|
||||
for (int i = 0; i < STRIP_NUM_PIXELS; i++) {
|
||||
pixels[i].r = r * STRIP_MAX_BRIGHTNESS;
|
||||
pixels[i].g = g * STRIP_MAX_BRIGHTNESS;
|
||||
pixels[i].b = b * STRIP_MAX_BRIGHTNESS;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int leds_update(void) {
|
||||
int ret = led_strip_update_rgb(strip, pixels, STRIP_NUM_PIXELS);
|
||||
if (ret) {
|
||||
LOG_ERR("Failed to update LED strip: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int leds_clear(void) {
|
||||
return leds_set_all(0, 0, 0) || leds_update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int leds_fade(uint32_t duration, float r, float g, float b) {
|
||||
uint32_t step_duration = (duration * 1000) / (STRIP_MAX_BRIGHTNESS * 2);
|
||||
|
||||
for (int i = 0; i < STRIP_MAX_BRIGHTNESS; i++) {
|
||||
float value = (float)i / STRIP_MAX_BRIGHTNESS;
|
||||
leds_set_all((value * r), (value * g), (value * b));
|
||||
leds_update();
|
||||
k_sleep(K_USEC(step_duration));
|
||||
}
|
||||
for (int i = STRIP_MAX_BRIGHTNESS - 1; i >= 0; i--) {
|
||||
float value = (float)i / STRIP_MAX_BRIGHTNESS;
|
||||
leds_set_all((value * r), (value * g), (value * b));
|
||||
leds_update();
|
||||
k_sleep(K_USEC(step_duration));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int leds_fade_in(uint32_t duration, float r, float g, float b) {
|
||||
uint32_t step_duration = (duration * 1000) / (STRIP_MAX_BRIGHTNESS);
|
||||
|
||||
for (int i = 0; i < STRIP_MAX_BRIGHTNESS; i++) {
|
||||
float value = (float)i / STRIP_MAX_BRIGHTNESS;
|
||||
leds_set_all((value * r), (value * g), (value * b));
|
||||
leds_update();
|
||||
k_sleep(K_USEC(step_duration));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int leds_fade_out(uint32_t duration, float r, float g, float b) {
|
||||
uint32_t step_duration = (duration * 1000) / (STRIP_MAX_BRIGHTNESS);
|
||||
|
||||
for (int i = STRIP_MAX_BRIGHTNESS - 1; i >= 0; i--) {
|
||||
float value = (float)i / STRIP_MAX_BRIGHTNESS;
|
||||
leds_set_all((value * r), (value * g), (value * b));
|
||||
leds_update();
|
||||
k_sleep(K_USEC(step_duration));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifndef LED_H
|
||||
#define LED_H
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
int led_init(void);
|
||||
int led_fade(uint32_t duration);
|
||||
int led_fade_in(uint32_t duration);
|
||||
int led_fade_out(uint32_t duration);
|
||||
int led_set_progress(float progress);
|
||||
int leds_set_color(uint8_t led_index, float r, float g, float b);
|
||||
int leds_set_all(float r, float g, float b);
|
||||
int leds_update(void);
|
||||
int leds_clear(void);
|
||||
int leds_fade(uint32_t duration, float r, float g, float b);
|
||||
int leds_fade_in(uint32_t duration, float r, float g, float b);
|
||||
int leds_fade_out(uint32_t duration, float r, float g, float b);
|
||||
|
||||
|
||||
#endif // LED_H
|
||||
@@ -0,0 +1,54 @@
|
||||
#include <zephyr/shell/shell.h>
|
||||
#include "led.h"
|
||||
|
||||
/* single led */
|
||||
|
||||
static int cmd_led_fade(const struct shell *sh, size_t argc, char **argv)
|
||||
{
|
||||
if (argc != 2) { shell_error(sh, "Usage: led fade <ms>"); return -EINVAL; }
|
||||
return led_fade(atoi(argv[1]));
|
||||
}
|
||||
|
||||
static int cmd_led_progress(const struct shell *sh, size_t argc, char **argv)
|
||||
{
|
||||
if (argc != 2) { shell_error(sh, "Usage: led progress <0-100>"); return -EINVAL; }
|
||||
return led_set_progress(atoi(argv[1]) / 100.0f);
|
||||
}
|
||||
|
||||
SHELL_STATIC_SUBCMD_SET_CREATE(led_cmds,
|
||||
SHELL_CMD(fade, NULL, "Fade over <ms>", cmd_led_fade),
|
||||
SHELL_CMD(progress, NULL, "Set progress <0.0-1.0>", cmd_led_progress),
|
||||
SHELL_SUBCMD_SET_END
|
||||
);
|
||||
SHELL_CMD_REGISTER(led, &led_cmds, "Single LED commands", NULL);
|
||||
|
||||
/* addressable leds */
|
||||
|
||||
static int cmd_leds_all(const struct shell *sh, size_t argc, char **argv)
|
||||
{
|
||||
if (argc != 4) { shell_error(sh, "Usage: leds all <r> <g> <b> (0-255)"); return -EINVAL; }
|
||||
leds_set_all(atoi(argv[1]) / 255.0f, atoi(argv[2]) / 255.0f, atoi(argv[3]) / 255.0f);
|
||||
return leds_update();
|
||||
}
|
||||
|
||||
static int cmd_leds_fade(const struct shell *sh, size_t argc, char **argv)
|
||||
{
|
||||
if (argc != 5) { shell_error(sh, "Usage: leds fade <ms> <r> <g> <b> (0-255)"); return -EINVAL; }
|
||||
return leds_fade(atoi(argv[1]),
|
||||
atoi(argv[2]) / 255.0f,
|
||||
atoi(argv[3]) / 255.0f,
|
||||
atoi(argv[4]) / 255.0f);
|
||||
}
|
||||
|
||||
static int cmd_leds_clear(const struct shell *sh, size_t argc, char **argv)
|
||||
{
|
||||
return leds_clear();
|
||||
}
|
||||
|
||||
SHELL_STATIC_SUBCMD_SET_CREATE(leds_cmds,
|
||||
SHELL_CMD(all, NULL, "Set all <r> <g> <b>", cmd_leds_all),
|
||||
SHELL_CMD(clear, NULL, "Clear all", cmd_leds_clear),
|
||||
SHELL_CMD(fade, NULL, "Fade to <ms> <r> <g> <b>", cmd_leds_fade),
|
||||
SHELL_SUBCMD_SET_END
|
||||
);
|
||||
SHELL_CMD_REGISTER(leds, &leds_cmds, "Addressable LED commands", NULL);
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
#include <stdio.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/usb/usb_device.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
// LOCAL
|
||||
#include "led.h"
|
||||
#include "config.h"
|
||||
#include "imu.h"
|
||||
|
||||
/* 1000 msec = 1 sec */
|
||||
#define SLEEP_TIME_MS 1000
|
||||
|
||||
LOG_MODULE_REGISTER(main, LOG_LEVEL_INF);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = usb_enable(NULL);
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Failed to enable USB: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = config_init();
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Failed to init config: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = led_init();
|
||||
ret = imu_init();
|
||||
|
||||
while (1) {
|
||||
// for (int i = 0; i < 10000; i++) {
|
||||
// led_set_progress((float)i / 10000.0);
|
||||
// k_msleep(1);
|
||||
// }
|
||||
// leds_fade(1000, 0.1, 0.0, 0.05);
|
||||
k_msleep(SLEEP_TIME_MS);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/shell/shell.h>
|
||||
#include "config.h"
|
||||
|
||||
LOG_MODULE_REGISTER(commands);
|
||||
|
||||
void foo(const struct shell *sh, size_t argc, char **argv)
|
||||
{
|
||||
LOG_INF("info message");
|
||||
LOG_WRN("warning message");
|
||||
LOG_ERR("err message");
|
||||
ARG_UNUSED(argc);
|
||||
ARG_UNUSED(argv);
|
||||
shell_print(sh, "foo executed");
|
||||
}
|
||||
|
||||
SHELL_CMD_REGISTER(foo, NULL, "foo command", foo);
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
#include "zbus_channels.h"
|
||||
|
||||
|
||||
ZBUS_CHAN_DEFINE(buttons_data_chan, /* Name */
|
||||
struct button_msg_t, /* Message type */
|
||||
|
||||
NULL, /* Validator */
|
||||
NULL, /* User data */
|
||||
ZBUS_OBSERVERS(), /* observers */
|
||||
ZBUS_MSG_INIT(.button = ERROR, .function = NONE) /* Initial value */
|
||||
);
|
||||
|
||||
ZBUS_CHAN_DEFINE(geiger_data_chan, /* Name */
|
||||
struct geiger_msg_t, /* Message type */
|
||||
|
||||
NULL, /* Validator */
|
||||
NULL, /* User data */
|
||||
ZBUS_OBSERVERS(), /* observers */
|
||||
ZBUS_MSG_INIT(.cps = 0) /* Initial value */
|
||||
);
|
||||
@@ -0,0 +1,39 @@
|
||||
#ifndef ZBUS_CHANNEL
|
||||
#define ZBUS_CHANNEL
|
||||
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/zbus/zbus.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
typedef enum {
|
||||
NONE,
|
||||
TAP,
|
||||
DOUBLE_TAP
|
||||
} function_e;
|
||||
|
||||
typedef enum {
|
||||
ERROR = -1,
|
||||
BTN1,
|
||||
BTN2,
|
||||
IMU
|
||||
} buttons_e;
|
||||
|
||||
struct button_msg_t {
|
||||
buttons_e button;
|
||||
function_e function;
|
||||
};
|
||||
|
||||
struct geiger_msg_t {
|
||||
uint32_t cps; // clicks per second
|
||||
};
|
||||
|
||||
|
||||
ZBUS_CHAN_DECLARE(buttons_data_chan);
|
||||
ZBUS_CHAN_DECLARE(geiger_data_chan);
|
||||
|
||||
|
||||
|
||||
#endif // ZBUS_CHANNEL
|
||||
Reference in New Issue
Block a user