Hi,
I’m really new to zephyr and nrf SDK (I currently use nrf connect on vscode) and I have a project which consist in remotely controling the brightness of the 4 LEDs built in my nrf52840 dk using bluetooth mesh (I have 3 kits). I apologize in advance if I’m asking stupid questions but I’m writing this post after looking on the forum for some answers.
For now I’m just trying to understand how to control the brightness with the “led_pwm” sample included and I would like in the first place to do some tests on the same board (without any bluetooth). The thing is that :
In one hand, i’ve managed to turn on and off the LEDs of my board with that code :
#include <drivers/gpio.h> #include <settings/settings.h> #include <random/rand32.h> // #include <bluetooth/bluetooth.h> // #include <bluetooth/mesh.h> // #include <bluetooth/mesh/proxy.h> //GPIOs for Buttons // Button 1 #define SW0_NODE DT_ALIAS(sw0) #if !DT_NODE_HAS_STATUS(SW0_NODE, okay) #error "Unsupported board: sw0 devicetree alias is not defined" #endif static const struct gpio_dt_spec button1 = GPIO_DT_SPEC_GET_OR(SW0_NODE, gpios, {0}); static struct gpio_callback gpio_btn1_cb; #ifndef SW0_GPIO_FLAGS #ifdef SW0_GPIO_PIN_PUD #define SW0_GPIO_FLAGS SW0_GPIO_PIN_PUD #else #define SW0_GPIO_FLAGS 0 #endif #endif // Button 2 #define SW1_NODE DT_ALIAS(sw1) #if !DT_NODE_HAS_STATUS(SW1_NODE, okay) #error "Unsupported board: sw1 devicetree alias is not defined" #endif static const struct gpio_dt_spec button2 = GPIO_DT_SPEC_GET_OR(SW1_NODE, gpios, {0}); static struct gpio_callback gpio_btn2_cb; #ifndef SW1_GPIO_FLAGS #ifdef SW1_GPIO_PIN_PUD #define SW1_GPIO_FLAGS SW1_GPIO_PIN_PUD #else #define SW1_GPIO_FLAGS 0 #endif #endif // Button 3 #define SW2_NODE DT_ALIAS(sw2) #if !DT_NODE_HAS_STATUS(SW2_NODE, okay) #error "Unsupported board: sw2 devicetree alias is not defined" #endif static const struct gpio_dt_spec button3 = GPIO_DT_SPEC_GET_OR(SW2_NODE, gpios, {0}); static struct gpio_callback gpio_btn3_cb; #ifndef SW2_GPIO_FLAGS #ifdef SW2_GPIO_PIN_PUD #define SW2_GPIO_FLAGS SW2_GPIO_PIN_PUD #else #define SW2_GPIO_FLAGS 0 #endif #endif // Button 4 #define SW3_NODE DT_ALIAS(sw3) #if !DT_NODE_HAS_STATUS(SW3_NODE, okay) #error "Unsupported board: sw3 devicetree alias is not defined" #endif static const struct gpio_dt_spec button4 = GPIO_DT_SPEC_GET_OR(SW3_NODE, gpios, {0}); static struct gpio_callback gpio_btn4_cb; #ifndef SW3_GPIO_FLAGS #ifdef SW3_GPIO_PIN_PUD #define SW3_GPIO_FLAGS SW3_GPIO_PIN_PUD #else #define SW3_GPIO_FLAGS 0 #endif #endif #define BUTTON_DEBOUNCE_DELAY_MS 250 // for debouncing the four buttons static uint32_t btn_time[4] = { 0,0,0,0}; static uint32_t btn_last_time[4] = { 0,0,0,0}; static struct gpio_callback gpio_btn1_cb; static struct gpio_callback gpio_btn2_cb; static struct gpio_callback gpio_btn3_cb; static struct gpio_callback gpio_btn4_cb; // GPIO for LEDs #define LED1_NODE DT_ALIAS(led0) static struct gpio_dt_spec ledN1 = GPIO_DT_SPEC_GET_OR(LED1_NODE, gpios, {0}); #define LED2_NODE DT_ALIAS(led1) static struct gpio_dt_spec ledN2 = GPIO_DT_SPEC_GET_OR(LED2_NODE, gpios, {0}); #define LED3_NODE DT_ALIAS(led2) static struct gpio_dt_spec ledN3 = GPIO_DT_SPEC_GET_OR(LED3_NODE, gpios, {0}); #define LED4_NODE DT_ALIAS(led3) static struct gpio_dt_spec ledN4 = GPIO_DT_SPEC_GET_OR(LED4_NODE, gpios, {0}); // for use with k_work_submit which we use to handle button presses in a background thread to avoid holding onto an IRQ for too long static struct k_work button1_work; static struct k_work button2_work; static struct k_work button3_work; static struct k_work button4_work; void ledOn(struct gpio_dt_spec led_nbr) { gpio_pin_set(led_nbr.port, led_nbr.pin, 1); } void ledOff(struct gpio_dt_spec led_nbr) { gpio_pin_set(led_nbr.port, led_nbr.pin, 0); } // Buttons // ------- void button1_work_handler(struct k_work *work) { ledOn(ledN1); k_msleep(200); ledOff(ledN1); k_msleep(200); ledOn(ledN1); k_msleep(200); ledOff(ledN1); k_msleep(200); } void button2_work_handler(struct k_work *work) { ledOn(ledN2); k_msleep(200); ledOff(ledN2); k_msleep(200); ledOn(ledN2); k_msleep(200); ledOff(ledN2); k_msleep(200); } void button3_work_handler(struct k_work *work) { } void button4_work_handler(struct k_work *work) { } bool debounce(int btn_inx) { bool ignore = false; btn_time[btn_inx] = k_uptime_get_32(); if (btn_time[btn_inx] < (btn_last_time[btn_inx] + BUTTON_DEBOUNCE_DELAY_MS)) { ignore = true; } else { ignore = false; } btn_last_time[btn_inx] = btn_time[btn_inx]; return ignore; } void button_1_pressed(const struct device *gpiob, struct gpio_callback *cb, uint32_t pins) { // printk("Button 1 pressed at %d\n", k_cycle_get_32()); if (!debounce(0)) { k_work_submit(&button1_work); } } void button_2_pressed(const struct device *gpiob, struct gpio_callback *cb, uint32_t pins) { // printk("Button 2 pressed at %d\n", k_cycle_get_32()); if (!debounce(1)) { k_work_submit(&button2_work); } } void button_3_pressed(const struct device *gpiob, struct gpio_callback *cb, uint32_t pins) { // printk("Button 3 pressed at %d\n", k_cycle_get_32()); if (!debounce(2)) { k_work_submit(&button3_work); } } void button_4_pressed(const struct device *gpiob, struct gpio_callback *cb, uint32_t pins) { // printk("Button 4 pressed at %d\n", k_cycle_get_32()); if (!debounce(3)) { k_work_submit(&button4_work); } } // ------------------------------------------------------------------------------------------------------- // LED // ------- /** * @brief This function sets up GPIO to allow the board’s built-in LED to be switched on or off and switches it off to begin with. */ void configureLED(void) { // Led 1 printk("configureLED1\n"); int ret1 = 0; int ret2 = 0; if (ledN1.port && !device_is_ready(ledN1.port)) { printk("Error %d: LED device %s is not ready; ignoring it\n", ret1, ledN1.port->name); ledN1.port = NULL; } if (ledN1.port) { ret1 = gpio_pin_configure_dt(&ledN1, GPIO_OUTPUT); if (ret1 != 0) { printk("Error %d: failed to configure LED device %s pin %d\n", ret1, ledN1.port->name, ledN1.pin); ledN1.port = NULL; } else { printk("Set up LED at %s pin %d\n", ledN1.port->name, ledN1.pin); } } ledOff(ledN1); printk("configureLED1\n"); if (ledN2.port && !device_is_ready(ledN2.port)) { printk("Error %d: LED device %s is not ready; ignoring it\n", ret2, ledN2.port->name); ledN2.port = NULL; } if (ledN2.port) { ret2 = gpio_pin_configure_dt(&ledN2, GPIO_OUTPUT); if (ret2 != 0) { printk("Error %d: failed to configure LED device %s pin %d\n", ret2, ledN2.port->name, ledN2.pin); ledN2.port = NULL; } else { printk("Set up LED at %s pin %d\n", ledN2.port->name, ledN2.pin); } } ledOff(ledN2); } // ------------------------------------------------------------------------------------------------------- // Buttons // ------- /** * @brief This sets up GPIO so that pressing any of the four buttons on the board results in a callback to an associated handler function */ void configureButtons(void) { printk("configureButtons\n"); int ret; // Button 1 k_work_init(&button1_work, button1_work_handler); ret = gpio_pin_configure_dt(&button1, GPIO_INPUT); if (ret != 0) { printk("Error %d: failed to configure %s pin %d\n", ret, button1.port->name, button1.pin); return; } ret = gpio_pin_interrupt_configure_dt(&button1, GPIO_INT_EDGE_TO_ACTIVE); if (ret != 0) { printk("Error %d: failed to configure interrupt on %s pin %d\n", ret, button1.port->name, button1.pin); return; } gpio_init_callback(&gpio_btn1_cb, button_1_pressed, BIT(button1.pin)); gpio_add_callback(button1.port, &gpio_btn1_cb); printk("Set up button at %s pin %d\n", button1.port->name, button1.pin); // Button 2 k_work_init(&button2_work, button2_work_handler); ret = gpio_pin_configure_dt(&button2, GPIO_INPUT); if (ret != 0) { printk("Error %d: failed to configure %s pin %d\n", ret, button2.port->name, button2.pin); return; } ret = gpio_pin_interrupt_configure_dt(&button2, GPIO_INT_EDGE_TO_ACTIVE); if (ret != 0) { printk("Error %d: failed to configure interrupt on %s pin %d\n", ret, button2.port->name, button2.pin); return; } gpio_init_callback(&gpio_btn2_cb, button_2_pressed, BIT(button2.pin)); gpio_add_callback(button2.port, &gpio_btn2_cb); printk("Set up button at %s pin %d\n", button2.port->name, button2.pin); // Button 3 k_work_init(&button3_work, button3_work_handler); ret = gpio_pin_configure_dt(&button3, GPIO_INPUT); if (ret != 0) { printk("Error %d: failed to configure %s pin %d\n", ret, button3.port->name, button3.pin); return; } ret = gpio_pin_interrupt_configure_dt(&button3, GPIO_INT_EDGE_TO_ACTIVE); if (ret != 0) { printk("Error %d: failed to configure interrupt on %s pin %d\n", ret, button3.port->name, button3.pin); return; } gpio_init_callback(&gpio_btn3_cb, button_3_pressed, BIT(button3.pin)); gpio_add_callback(button3.port, &gpio_btn3_cb); printk("Set up button at %s pin %d\n", button3.port->name, button3.pin); // Button 4 k_work_init(&button4_work, button4_work_handler); ret = gpio_pin_configure_dt(&button4, GPIO_INPUT); if (ret != 0) { printk("Error %d: failed to configure %s pin %d\n", ret, button4.port->name, button4.pin); return; } ret = gpio_pin_interrupt_configure_dt(&button4, GPIO_INT_EDGE_TO_ACTIVE); if (ret != 0) { printk("Error %d: failed to configure interrupt on %s pin %d\n", ret, button4.port->name, button4.pin); return; } gpio_init_callback(&gpio_btn4_cb, button_4_pressed, BIT(button4.pin)); gpio_add_callback(button4.port, &gpio_btn4_cb); printk("Set up button at %s pin %d\n", button4.port->name, button4.pin); } void main(void) { printk("switch\n"); configureButtons(); configureLED(); }
And on the other hand, I run another program which increase and decrease the brightness of 1 led (without buttons) :
/* * Copyright (c) 2020 Seagate Technology LLC * * SPDX-License-Identifier: Apache-2.0 */ #include <device.h> #include <errno.h> #include <drivers/led.h> #include <sys/util.h> #include <zephyr.h> #include <logging/log.h> LOG_MODULE_REGISTER(main, CONFIG_LOG_DEFAULT_LEVEL); #if DT_NODE_HAS_STATUS(DT_INST(0, pwm_leds), okay) #define LED_PWM_NODE_ID DT_INST(0, pwm_leds) #define LED_PWM_DEV_NAME DEVICE_DT_NAME(LED_PWM_NODE_ID) #else #error "No LED PWM device found" #endif #define LED_PWM_LABEL(led_node_id) DT_PROP_OR(led_node_id, label, NULL), const char *led_label[] = { DT_FOREACH_CHILD(LED_PWM_NODE_ID, LED_PWM_LABEL) }; const int num_leds = ARRAY_SIZE(led_label); #define MAX_BRIGHTNESS 100 #define FADE_DELAY_MS 10 #define FADE_DELAY K_MSEC(FADE_DELAY_MS) /** * @brief Run tests on a single LED using the LED API syscalls. * * @param led_pwm LED PWM device. * @param led Number of the LED to test. */ static void run_led_test(const struct device *led_pwm, uint8_t led) { int err; uint16_t level; LOG_INF("Testing LED %d - %s", led, led_label[led] ? : "no label"); /* Increase LED brightness gradually up to the maximum level. */ LOG_INF("%s"," Increasing brightness gradually"); for (level = 0; level <= MAX_BRIGHTNESS; level++) { err = led_set_brightness(led_pwm, led, level); if (err < 0) { LOG_ERR("err=%d brightness=%d\n", err, level); return; } k_sleep(FADE_DELAY); } k_sleep(K_MSEC(1000)); /* Turn LED off. */ err = led_off(led_pwm, led); if (err < 0) { LOG_ERR("err=%d", err); return; } LOG_INF("%s"," Turned off, loop end"); } void main(void) { const struct device *led_pwm; uint8_t led; led_pwm = device_get_binding(LED_PWM_DEV_NAME); if (led_pwm) { LOG_INF("Found device %s", LED_PWM_DEV_NAME); } else { LOG_ERR("Device %s not found", LED_PWM_DEV_NAME); return; } if (!num_leds) { LOG_ERR("No LEDs found for %s", LED_PWM_DEV_NAME); return; } do { for (led = 0; led < num_leds; led++) { run_led_test(led_pwm, led); } } while (true); }
Now I need to “merge” these two codes (if it’s possible) but I have now idea how considering that the “led_set_brightness” function doesn’t seem to use gpios like the on/off function does. And also, I don’t understand what this part means (the #defines are different from the way I used them in the first program :
LOG_MODULE_REGISTER(main, CONFIG_LOG_DEFAULT_LEVEL); #if DT_NODE_HAS_STATUS(DT_INST(0, pwm_leds), okay) #define LED_PWM_NODE_ID DT_INST(0, pwm_leds) #define LED_PWM_DEV_NAME DEVICE_DT_NAME(LED_PWM_NODE_ID) #else #error "No LED PWM device found" #endif #define LED_PWM_LABEL(led_node_id) DT_PROP_OR(led_node_id, label, NULL), const char *led_label[] = { DT_FOREACH_CHILD(LED_PWM_NODE_ID, LED_PWM_LABEL) }; const int num_leds = ARRAY_SIZE(led_label);
So I can’t make the led_pwm sample run on the 4 LEDs of my DK since I can’t figure out how to define the other leds.
I hope that I’ve been clear and that someone will be able to help me.
Kind regards,
Bastien