Hello,
I am trying to use PWM to control two LEDS, one red and one green (referred to as blueled in the code) to produce different colours. I have had a look at the example _fade-led-sample provided by Nordic and based my changes on this. However, I am seeing some errors when I try to build my project in Segger Embedded Studio.
9> zephyr/include/generated/devicetree_unfixed.h:1949:33: error: 'DT_N_S_pwmleds_S_pwm_led_0_P_gpios_IDX_0_PH_P_label' undeclared (first use in this function); did you mean 'DT_N_S_pwmleds_S_pwm_led_0_P_pwms_IDX_0_VAL_channel'?
9> zephyr/include/generated/devicetree_unfixed.h:1949:33: error: 'DT_N_S_pwmleds_S_pwm_led_0_P_gpios_IDX_0_VAL_pin' undeclared (first use in this function); did you mean 'DT_N_S_leds_S_led_0_P_gpios_IDX_0_VAL_pin'?
9> zephyr/include/generated/devicetree_unfixed.h:2002:33: error: 'DT_N_S_pwmleds_S_pwm_led_1_P_gpios_IDX_0_PH_P_label' undeclared (first use in this function); did you mean 'DT_N_S_pwmleds_S_pwm_led_1_P_pwms_IDX_0_PH'?
9> zephyr/include/generated/devicetree_unfixed.h:2002:33: error: 'DT_N_S_pwmleds_S_pwm_led_1_P_gpios_IDX_0_VAL_pin' undeclared (first use in this function); did you mean 'DT_N_S_leds_S_led_1_P_gpios_IDX_0_VAL_pin'?
Note, I am using the following development environment.
- Zephyr OS build v2.6.99-ncs1
- SEGGER Embedded Studio for ARM
Release 5.60 Build 2021081102.47262
Nordic Edition
Windows x64
I am attaching the build error logs, my overlay file and snippets of my C code. The file prj.conf contains the line CONFIG_PWM=y.
Thank you for your help.
0676.nrf52833dk_nrf52833.overlay
#include <stdio.h>
#include <zephyr.h>
#include <arch/cpu.h>
#include <sys/printk.h>
#include <device.h>
#include <devicetree.h>
#include <drivers/gpio.h>
#include <drivers/pwm.h>
#include <drivers/i2c.h>
#include <drivers/spi.h>
#include <drivers/adc.h>
#include <logging/log.h>
#include <logging/log_ctrl.h>
[snip]
...
#define PWM_OFF (0U)
#define PWM_PERCENTAGE_ORANGE (23U)
#define LED_TEST 0
#define FADING_TEST 1
static result_t io_PWM_initialise (uint8_t percentage);
static void pwm_stop(void);
//static void registers_read(void);
//static void LED_test(void);
static void fading_test(void);
/*
-----------------------------------------------------------------------------------------------------
!GLOBAL VARIABLES
-----------------------------------------------------------------------------------------------------
*/
//Leds
const struct device *io_redled_dev;
const struct device *io_blueled_dev;
const struct device *pwm_dev;
[snip]
...
///////////////////////////////////////////////////////////////////////////////
void io_led_initialise(void)
{
uint8_t ret;
/* Initialise IO ports attached to the LEDs */
io_redled_dev = device_get_binding( DT_GPIO_LABEL(DT_ALIAS( redled ), gpios ) );
if ( io_redled_dev )
{
ret = gpio_pin_configure( io_redled_dev,
DT_GPIO_PIN( DT_ALIAS( redled ), gpios ),
GPIO_OUTPUT_INACTIVE | DT_GPIO_FLAGS( DT_ALIAS(redled ), gpios ) );
if ( ret )
{
LOG_ERR( "RedLed not configured" );
}
}
else
{
LOG_ERR( "RedLed not bound" );
}
io_blueled_dev = device_get_binding( DT_GPIO_LABEL( DT_ALIAS( blueled ), gpios ) );
if ( io_blueled_dev )
{
ret = gpio_pin_configure( io_blueled_dev,
DT_GPIO_PIN(DT_ALIAS(blueled), gpios),
GPIO_OUTPUT_INACTIVE | DT_GPIO_FLAGS( DT_ALIAS( blueled ), gpios ) );
if ( ret )
{
LOG_ERR( "Green not configured" );
}
}
else
{
LOG_ERR( "GreenLed not bound" );
}
#ifdef SALEAE
io_buzzerP_dev = device_get_binding(DT_GPIO_LABEL(DT_ALIAS(buz_p), gpios));
if ( io_buzzerP_dev == NULL )
{
LOG_ERR( "BuzzerP not bound" );
}
gpio_pin_configure(io_buzzerP_dev, DT_GPIO_PIN(DT_ALIAS(buz_p), gpios), GPIO_OUTPUT_INACTIVE | DT_GPIO_FLAGS(DT_ALIAS(buz_p), gpios));
if ( ret )
{
LOG_ERR( "BuzzerP not configured" );
}
io_buzzerN_dev = device_get_binding(DT_GPIO_LABEL(DT_ALIAS(buz_n), gpios));
if ( io_buzzerN_dev == NULL )
{
LOG_ERR( "BuzzerN not bound" );
}
gpio_pin_configure(io_buzzerN_dev, DT_GPIO_PIN(DT_ALIAS(buz_n), gpios), GPIO_OUTPUT_INACTIVE | DT_GPIO_FLAGS(DT_ALIAS(buz_n), gpios));
if ( ret )
{
LOG_ERR( "BuzzerN not configured" );
}
#endif
}
///////////////////////////////////////////////////////////////////////////////
void io_led_on(uint8_t colour)
{
if ( colour & GREEN_LED )
{
io.led.state |= GREEN_LED;
gpio_pin_set( io_blueled_dev, DT_GPIO_PIN(DT_ALIAS(blueled),gpios), 1 );
}
if ( colour & RED_LED )
{
io.led.state |= RED_LED;
gpio_pin_set( io_redled_dev, DT_GPIO_PIN(DT_ALIAS(redled),gpios), 1 );
}
}
void io_led_off(uint8_t colour)
{
if ( colour & GREEN_LED )
{
io.led.state &= ~GREEN_LED;
gpio_pin_set( io_blueled_dev, DT_GPIO_PIN(DT_ALIAS(blueled),gpios), 0 );
}
if ( colour & RED_LED )
{
io.led.state &= ~RED_LED;
gpio_pin_set( io_redled_dev, DT_GPIO_PIN(DT_ALIAS(redled),gpios), 0 );
}
}
// New PWM code
#define PWM_LED0_NODE DT_ALIAS(pwm_led0)
#if DT_NODE_HAS_STATUS(PWM_LED0_NODE, okay)
#define PWM_CTLR DT_PWMS_CTLR(PWM_LED0_NODE)
#define PWM_CHANNEL DT_PWMS_CHANNEL(PWM_LED0_NODE)
#define PWM_FLAGS DT_PWMS_FLAGS(PWM_LED0_NODE)
#else
#error "Unsupported board: pwm-led0 devicetree alias is not defined"
#define PWM_CTLR DT_INVALID_NODE
#define PWM_CHANNEL 0
#define PWM_FLAGS 0
#endif
result_t io_PWM_initialise (uint8_t percentage)
{
uint32_t period = 1000; /* 1000us = 1 ms 1000 Hz */
uint32_t pwm_percentage ;
int ret;
result_t result = RESULT_ERROR;
static boolean_t initialised = FALSE;
pwm_dev = DEVICE_DT_GET(PWM_CTLR);
if (device_is_ready(pwm_dev)) /* Check that the structure in ROM containing settings exists */
{
if ( percentage > 100)
{
percentage = 100; /* Limit maximum value to 100% */
}
pwm_percentage = ( (uint32_t) percentage * period) / 100; /* Scale percentage to 0 to 1000 */
/* The function pwm_pin_set_usec() is used to setup the PWM and takes 4 arguments:
* pwm_dev = pointer to structure in ROM containing settings for PWM0 to PWM3
* PWM_CHANNEL = 0 for PWM0.
* period = 1000us = 1ms.
* pwm_percentage = % of time PWM is active, 0 = 0% off 100 = 100% full on.
* PWM_FLAGS = 0. Not used.
*/
ret = pwm_pin_set_usec(pwm_dev, PWM_CHANNEL, period, pwm_percentage, PWM_FLAGS);
if ( ret == 0)
{
result = RESULT_OK;
if ( percentage > 0 )
{
initialised = TRUE; /* Running some value of PWM rather than being off */
}
}
if ( percentage == 0 && initialised == TRUE )
{
/* Do this after the green LED has been set to 0% and was previously running PWM */
pwm_stop(); /* Only expecuted if PWM percentage was previously 1% or greater */
initialised = FALSE;
}
}
else
{
LOG_ERR( "PWM Device not bound" );
}
return (result);
}
///////////////////////////////////////////////////////////////////////////////
void io_led_on( uint8_t colour, uint32_t pulse_width )
{
if ( ( pwm_dev == NULL ) || ( pwm_dev == NULL ) )
{
return;
}
if ( colour & GREEN_LED )
{
io.led.state |= GREEN_LED;
pwm_pin_set_usec( pwm_dev, /* Pointer to the Green LED dev struct */
DT_PWMS_CHANNEL(DT_ALIAS(blueled)), /* PWM pin/channel */
PERIOD_USEC, /* PWM period in USEC */
pulse_width, /* PWM pulse width in USEC */
DT_PWMS_FLAGS(DT_ALIAS(blueled)) ); /* PWM Flags for pin config (polarity)*/
}
if ( colour & RED_LED )
{
io.led.state |= RED_LED;
pwm_pin_set_usec( pwm_dev, /* Pointer to the Red LED dev struct */
DT_PWMS_CHANNEL(DT_ALIAS(redled)), /* PWM pin/channel */
PERIOD_USEC, /* PWM period in USEC */
pulse_width, /* PWM pulse width in USEC */
DT_PWMS_FLAGS(DT_ALIAS(redled)) ); /* PWM Flags for pin config (polarity)*/
}
}
///////////////////////////////////////////////////////////////////////////////
void io_led_off( uint8_t colour )
{
if ( ( pwm_dev == NULL ) || ( pwm_dev == NULL ) )
{
return;
}
if ( colour & GREEN_LED )
{
io.led.state &= ~GREEN_LED;
pwm_pin_set_usec(pwm_dev, DT_PWMS_CHANNEL(DT_ALIAS(blueled)), PERIOD_USEC,0,0);
}
if ( colour & RED_LED )
{
io.led.state &= ~RED_LED;
pwm_pin_set_usec(pwm_dev, DT_PWMS_CHANNEL(DT_ALIAS(redled)), PERIOD_USEC,0,0);
}
}
/**
*******************************************************************************
* Fading test. Cycles through all the PWM values from 0% to 100%
*******************************************************************************
**/
/* Used to determine which PWM percentage gives the best orange */
#ifdef FADING_TEST
static void fading_test(void)
{
static uint8_t counter = 0;
io_PWM_initialise(counter);
if ( counter >= 100)
{
counter = 0;
}
else
{
counter++;
}
}
#endif
/**
*******************************************************************************
* New Function to turn off PWM. PTC 82496
*******************************************************************************
* The original blinky_pwm code did not provide a global function to turn off
* the PWM. Use low level code to directly write to the PWM_TASKS_STOP register
* at address 0x4001C004.
* There is also the PWM0_ENABLE register, but this is best not used as it does
* not re-enable the next time used.
*******************************************************************************
**/
static void pwm_stop(void)
{
registers_read(); /* Check status of PWM registers while running */
PWM0_TASKS_STOP = TRIGGER_TASK;
/* PWM0_ENABLE = DISABLE; Do not use this. Does not re-enable the next time through */
registers_read(); /* Check status of PWM registers when stopped */
}
///////////////////////////////////////////////////////////////////////////////
/*
* This function needs to be called every 250 ms as was the case in the
* Homestation firmware.
*
*/
///////////////////////////////////////////////////////////////////////////////
void io_update(void)
{
...
[snip]
#if ( LED_TEST )
LED_test(); /* Test for contention between GPIO and PWM driving LEDS */
#endif
#if ( FADING_TEST )
fading_test(); /* Cycles through PWM percentage between 0% and 100% */
#endif
}
void main( void )
{
...
[snip]
io_update();
}
Kind regards
Mohamed