This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Integrate PWM into COAP simple server

Hello, I need to use PWM to control GPIO and integrate it to work on simple COAP server app using nrf52840 DK.

I used "pwm_simple" example from SDK (not Thread/Zigbie SDK) and when it was working already as I wanted I tried to integrate that code in simple COAP server app. ALl the need  includes are found but I get following error while trying to make it with GCC. Do you have any idea where to search for a problem?

In file included from ../../../../../../modules/nrfx/nrfx.h:45:0,
                 from ../../../../../../modules/nrfx/hal/nrf_gpio.h:44,
                 from ../../../../../../components/boards/boards.h:43,
                 from ../../../../../../components/libraries/bsp/bsp.h:58,
                 from ../../../../../../components/libraries/bsp/bsp_thread.h:54,
                 from ../../../../app_utils/thread_coap_utils.c:10:
../../../../../../modules/nrfx/drivers/include/nrfx_pwm.h:73:35: error: 'NRFX_PWM0_INST_IDX' undeclared here (not in a function)
     .drv_inst_idx = NRFX_CONCAT_3(NRFX_PWM, id, _INST_IDX), \
                                   ^
../../../../../../modules/nrfx/drivers/nrfx_common.h:117:37: note: in definition of macro 'NRFX_CONCAT_3_'
 #define NRFX_CONCAT_3_(p1, p2, p3)  p1 ## p2 ## p3
                                     ^~
../../../../../../modules/nrfx/drivers/include/nrfx_pwm.h:73:21: note: in expansion of macro 'NRFX_CONCAT_3'
     .drv_inst_idx = NRFX_CONCAT_3(NRFX_PWM, id, _INST_IDX), \
                     ^~~~~~~~~~~~~
../../../../../../integration/nrfx/legacy/nrf_drv_pwm.h:64:49: note: in expansion of macro 'NRFX_PWM_INSTANCE'
 #define NRF_DRV_PWM_INSTANCE                    NRFX_PWM_INSTANCE
                                                 ^~~~~~~~~~~~~~~~~
../../../../app_utils/thread_coap_utils.c:43:31: note: in expansion of macro 'NRF_DRV_PWM_INSTANCE'
 static nrf_drv_pwm_t m_pwm0 = NRF_DRV_PWM_INSTANCE(0);
                               ^~~~~~~~~~~~~~~~~~~~
make: *** [_build/nrf52840_xxaa/thread_coap_utils.c.o] Error 1

here is fragment of my code for inserted into simple COAP server app. That code is taken mainly from pwm_simple example and is fully working while using in directory with peripheral examples in generic SDK directory, but I try to build it in my Thread SDK COAP examples directory.

#include "thread_coap_utils.h"

#include "app_timer.h"
#include "bsp_thread.h"
#include "nrf_assert.h"
#include "nrf_log.h"
#include "sdk_config.h"
#include "thread_utils.h"

#include <openthread/ip6.h>
#include <openthread/link.h>
#include <openthread/thread.h>
#include <openthread/platform/alarm-milli.h>

// include GPIO
#include "nrf_gpio.h"

// includes for PWM
#include <stdio.h>
#include <string.h>
#include "nrf_drv_pwm.h"
#include "app_util_platform.h"
#include "app_error.h"
#include "boards.h"
#include "bsp.h"
#include "nrf_drv_clock.h"
#include "nrf_delay.h"

#define RESPONSE_POLL_PERIOD 100

#define GPIO_LED_OUT ( NRF_GPIO_PIN_MAP(0,31) )

APP_TIMER_DEF(m_provisioning_timer);
APP_TIMER_DEF(m_led_timer);

static uint32_t m_poll_period;

static nrf_drv_pwm_t m_pwm0 = NRF_DRV_PWM_INSTANCE(0);

// Declare variables holding PWM sequence values. In this example only one channel is used
nrf_pwm_values_individual_t seq_values[] = {{ 0, 0, 0, 0}};
nrf_pwm_sequence_t const seq =
{
    .values.p_individual = seq_values,
    .length          = NRF_PWM_VALUES_LENGTH(seq_values),
    .repeats         = 0,
    .end_delay       = 0
};

void thread_coap_utils_light_blinking_is_on_set(bool value)
{
    m_coap_status.led_blinking_is_on = value;
}

bool thread_coap_utils_light_blinking_is_on_get(void)
{
    return m_coap_status.led_blinking_is_on;
}

// SECTION FOR PWM OPERATIONS

// Set duty cycle between 0 and 100%
void pwm_update_duty_cycle(uint8_t duty_cycle)
{
	// Check if value is outside of range. If so, set to 100%
	if(duty_cycle >= 100)
	{
		seq_values->channel_0 = 100;
	}
	else
	{
		seq_values->channel_0 = duty_cycle;
	}

	nrf_drv_pwm_simple_playback(&m_pwm0, &seq, 1, NRF_DRV_PWM_FLAG_LOOP);
}

void pwm_init(void)
{
	nrf_drv_pwm_config_t const config0 =
	{
		.output_pins =
		{
			GPIO_LED_OUT,// | NRF_DRV_PWM_PIN_INVERTED, // channel 0
			NRF_DRV_PWM_PIN_NOT_USED,             // channel 1
			NRF_DRV_PWM_PIN_NOT_USED,             // channel 2
			NRF_DRV_PWM_PIN_NOT_USED,             // channel 3
		},
		.irq_priority = APP_IRQ_PRIORITY_LOWEST,
		.base_clock   = NRF_PWM_CLK_1MHz,
		.count_mode   = NRF_PWM_MODE_UP,
		.top_value    = 100,
		.load_mode    = NRF_PWM_LOAD_INDIVIDUAL,
		.step_mode    = NRF_PWM_STEP_AUTO
	};
nrf_drv_pwm_init(&m_pwm0, &config0, NULL);
}

#include "thread_coap_utils.h"

#include "app_timer.h"
#include "bsp_thread.h"
#include "nrf_assert.h"
#include "nrf_log.h"
#include "sdk_config.h"
#include "thread_utils.h"

#include <openthread/ip6.h>
#include <openthread/link.h>
#include <openthread/thread.h>
#include <openthread/platform/alarm-milli.h>

// include GPIO
#include "nrf_gpio.h"

// includes for PWM
#include <stdio.h>
#include <string.h>
#include "nrf_drv_pwm.h"
#include "app_util_platform.h"
#include "app_error.h"
#include "boards.h"
#include "bsp.h"
#include "nrf_drv_clock.h"
#include "nrf_delay.h"

#define RESPONSE_POLL_PERIOD 100

#define GPIO_LED_OUT ( NRF_GPIO_PIN_MAP(0,31) )

APP_TIMER_DEF(m_provisioning_timer);
APP_TIMER_DEF(m_led_timer);

static uint32_t m_poll_period;

static nrf_drv_pwm_t m_pwm0 = NRF_DRV_PWM_INSTANCE(0);

// Declare variables holding PWM sequence values. In this example only one channel is used
nrf_pwm_values_individual_t seq_values[] = {{ 0, 0, 0, 0}};
nrf_pwm_sequence_t const seq =
{
    .values.p_individual = seq_values,
    .length          = NRF_PWM_VALUES_LENGTH(seq_values),
    .repeats         = 0,
    .end_delay       = 0
};

// SECTION FOR PWM OPERATIONS

// Set duty cycle between 0 and 100%
void pwm_update_duty_cycle(uint8_t duty_cycle)
{
	// Check if value is outside of range. If so, set to 100%
	if(duty_cycle >= 100)
	{
		seq_values->channel_0 = 100;
	}
	else
	{
		seq_values->channel_0 = duty_cycle;
	}

	nrf_drv_pwm_simple_playback(&m_pwm0, &seq, 1, NRF_DRV_PWM_FLAG_LOOP);
}

void pwm_init(void)
{
	nrf_drv_pwm_config_t const config0 =
	{
		.output_pins =
		{
			GPIO_LED_OUT,// | NRF_DRV_PWM_PIN_INVERTED, // channel 0
			NRF_DRV_PWM_PIN_NOT_USED,             // channel 1
			NRF_DRV_PWM_PIN_NOT_USED,             // channel 2
			NRF_DRV_PWM_PIN_NOT_USED,             // channel 3
		},
		.irq_priority = APP_IRQ_PRIORITY_LOWEST,
		.base_clock   = NRF_PWM_CLK_1MHz,
		.count_mode   = NRF_PWM_MODE_UP,
		.top_value    = 100,
		.load_mode    = NRF_PWM_LOAD_INDIVIDUAL,
		.step_mode    = NRF_PWM_STEP_AUTO
	};
nrf_drv_pwm_init(&m_pwm0, &config0, NULL);
}

Thanks a lot for any advice

Parents
  • I have had a similar problem when I integrated the pwm driver example from the nRF5 SDK into the Bluetooth Mesh light switch example. The important error is this one: "NRFX_PWM0_INST_IDX' undeclared here". If you search for NRFX_PWM0_INST_IDX, you will most likely find a line similar to this:

    #if NRFX_CHECK(NRFX_PWM0_ENABLED)
        NRFX_PWM0_INST_IDX,
    #endif

    I am guessing these lines will be grayed out because the NRFX_PWM0_ENABLED has not been defined. In the mesh sdk, this is done via the apply_old_config.h header file, but it might be done in sdk_config.h in the thread sdk.

    I would check both of these header files & make sure that NRFX_PWM0_ENABLED is defined & enabled.

    Kind Regards,

    Bjørn

  • Thanks for that. I finally commented out this #ifdef macros to force NRFX_PWM0_ENABLED because despite NRFX_PWM0_ENABLED set to 1 in config it would not define  NRFX_PWM0_ENABLED, I don't know why.

     

    But it seems that it's not enough as I still get bunch of other errors, like "nrf_drv_pwm.h" is not included at all (undefined references to functions). I modified Makefile to include paths used by PWM driver demo (I made diff on those makefiles). I'm using functions from simple PWM example from this forum and it works flawlessly in directory of PWM driver example of Thread SDK. I tried different things for may hours but basically I always get undefined reference to functions during linking.

    Compiling file: main.c
    Linking target: _build/nrf52840_xxaa.out
    _build/nrf52840_xxaa/main.c.o: In function `pwm_init':
    C:\Nordic\nRF5_SDK_for_Thread_and_Zigbee_2.0.0_29775ac\examples\thread\simple_coap_server\pca10056\blank\armgcc/../../../main.c:247: undefined reference to `nrfx_pwm_init'
    _build/nrf52840_xxaa/main.c.o: In function `pwm_update_duty_cycle':
    C:\Nordic\nRF5_SDK_for_Thread_and_Zigbee_2.0.0_29775ac\examples\thread\simple_coap_server\pca10056\blank\armgcc/../../../main.c:225: undefined reference to `nrfx_pwm_simple_playback'
    C:\Nordic\nRF5_SDK_for_Thread_and_Zigbee_2.0.0_29775ac\examples\thread\simple_coap_server\pca10056\blank\armgcc/../../../main.c:225: undefined reference to `nrfx_pwm_simple_playback'
    C:\Nordic\nRF5_SDK_for_Thread_and_Zigbee_2.0.0_29775ac\examples\thread\simple_coap_server\pca10056\blank\armgcc/../../../main.c:225: undefined reference to `nrfx_pwm_simple_playback'
    collect2.exe: error: ld returned 1 exit status
    make: *** [_build/nrf52840_xxaa.out] Error 1
    

    This is my app code (main.c from simple COAP server with added PWM functions).

    #include <stdint.h>
    
    #include "app_scheduler.h"
    #include "app_timer.h"
    #include "bsp_thread.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log.h"
    #include "nrf_log_default_backends.h"
    
    #include "thread_coap_utils.h"
    #include "thread_utils.h"
    
    #include <openthread/thread.h>
    
    #include "nrf_drv_pwm.h"
    #include "app_error.h"
    #include "bsp.h"
    #include "nrf_delay.h"
    
    #define GPIO_LED_OUT ( NRF_GPIO_PIN_MAP(0,30) )
    #define SCHED_QUEUE_SIZE      32                              /**< Maximum number of events in the scheduler queue. */
    #define SCHED_EVENT_DATA_SIZE APP_TIMER_SCHED_EVENT_DATA_SIZE /**< Maximum app_scheduler event size. */
    
    /***************************************************************************************************
     * @section Buttons
     **************************************************************************************************/
    
    static void bsp_event_handler(bsp_event_t event)
    {
        switch(event)
        {
            case BSP_EVENT_KEY_3:
                thread_coap_utils_provisioning_enable(true);
                break;
    
            default:
                return;
        }
    }
    
    /***************************************************************************************************
     * @section Callbacks
     **************************************************************************************************/
    
    static void thread_state_changed_callback(uint32_t flags, void * p_context)
    {
        if (flags & OT_CHANGED_THREAD_ROLE)
        {
            switch (otThreadGetDeviceRole(p_context))
            {
                case OT_DEVICE_ROLE_CHILD:
                case OT_DEVICE_ROLE_ROUTER:
                case OT_DEVICE_ROLE_LEADER:
                    break;
    
                case OT_DEVICE_ROLE_DISABLED:
                case OT_DEVICE_ROLE_DETACHED:
                default:
                    thread_coap_utils_provisioning_enable(false);
                    break;
            }
        }
        NRF_LOG_INFO("State changed! Flags: 0x%08x Current role: %d\r\n",
                     flags,
                     otThreadGetDeviceRole(p_context));
    
    }
    
    /***************************************************************************************************
     * @section Initialization
     **************************************************************************************************/
    
    /**@brief Function for initializing the Application Timer Module.
     */
    static void timer_init(void)
    {
        uint32_t error_code = app_timer_init();
        APP_ERROR_CHECK(error_code);
    }
    
    
    /**@brief Function for initializing the nrf log module.
     */
    static void log_init(void)
    {
        ret_code_t err_code = NRF_LOG_INIT(NULL);
        APP_ERROR_CHECK(err_code);
    
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    }
    
    
    /**@brief Function for initializing the Thread Board Support Package.
     */
    static void thread_bsp_init(void)
    {
        uint32_t error_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, bsp_event_handler);
        APP_ERROR_CHECK(error_code);
    
        error_code = bsp_thread_init(thread_ot_instance_get());
        APP_ERROR_CHECK(error_code);
    }
    
    
    /**@brief Function for initializing the Thread Stack.
     */
    static void thread_instance_init(void)
    {
        thread_configuration_t thread_configuration =
        {
            .role                  = RX_ON_WHEN_IDLE,
            .autocommissioning     = true,
            .poll_period           = 2500,
            .default_child_timeout = 10,
        };
    
        thread_init(&thread_configuration);
        thread_cli_init();
        thread_state_changed_callback_set(thread_state_changed_callback);
    }
    
    
    /**@brief Function for initializing the Constrained Application Protocol Module.
     */
    static void thread_coap_init(void)
    {
        thread_coap_configuration_t thread_coap_configuration =
        {
            .coap_server_enabled               = true,
            .coap_client_enabled               = false,
            .coap_cloud_enabled                = false,
            .configurable_led_blinking_enabled = false,
        };
    
        thread_coap_utils_init(&thread_coap_configuration);
    }
    
    
    /**@brief Function for initializing scheduler module.
     */
    static void scheduler_init(void)
    {
        APP_SCHED_INIT(SCHED_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE);
    }
    
    ///////////////////////////////
    ///////////////////////////////
    ///////////////////////////////
    
    static nrf_drv_pwm_t m_pwm0 = NRF_DRV_PWM_INSTANCE(0);
    
    // Declare variables holding PWM sequence values. In this example only one channel is used
    nrf_pwm_values_individual_t seq_values[] = {{ 0, 0, 0, 0}};
    nrf_pwm_sequence_t const seq =
    {
        .values.p_individual = seq_values,
        .length          = NRF_PWM_VALUES_LENGTH(seq_values),
        .repeats         = 0,
        .end_delay       = 0
    };
    
    // Set duty cycle between 0 and 100%
    void pwm_update_duty_cycle(uint8_t duty_cycle)
    {
        // Check if value is outside of range. If so, set to 100%
        if(duty_cycle >= 100)
        {
            seq_values->channel_0 = 100;
        }
        else
        {
            seq_values->channel_0 = duty_cycle;
        }
    
        nrf_drv_pwm_simple_playback(&m_pwm0, &seq, 1, NRF_DRV_PWM_FLAG_LOOP);
    }
    
    static void pwm_init(void)
    {
        nrf_drv_pwm_config_t const config0 =
        {
            .output_pins =
            {
                GPIO_LED_OUT,						  // channel 0
                NRF_DRV_PWM_PIN_NOT_USED,             // channel 1
                NRF_DRV_PWM_PIN_NOT_USED,             // channel 2
                NRF_DRV_PWM_PIN_NOT_USED,             // channel 3
            },
            .irq_priority = APP_IRQ_PRIORITY_LOWEST,
            .base_clock   = NRF_PWM_CLK_1MHz,
            .count_mode   = NRF_PWM_MODE_UP,
            .top_value    = 100,
            .load_mode    = NRF_PWM_LOAD_INDIVIDUAL,
            .step_mode    = NRF_PWM_STEP_AUTO
        };
        // Init PWM without error handler
        APP_ERROR_CHECK(nrf_drv_pwm_init(&m_pwm0, &config0, NULL));
    }
    
    static void ledOutOff(void)
    {
    	pwm_update_duty_cycle(100); // values has to be inverted
    }
    
    static void ledOutDim(void)
    {
    	pwm_update_duty_cycle(95);
    }
    
    static void ledOutOn(void)
    {
    	pwm_update_duty_cycle(0);
    }
    
    int main(int argc, char * argv[])
    {
        log_init();
        scheduler_init();
        timer_init();
    
        // Initialize Thread CoAP utils.
        thread_coap_utils_led_timer_init();
        thread_coap_utils_provisioning_timer_init();
    
        // Initialize the Thread stack.
        thread_instance_init();
        thread_coap_init();
        thread_bsp_init();
    
        pwm_init();
    
        for (;;)
        {
    		int sleep_time  = 1000;
    
    		ledOutOff();
    		nrf_delay_ms(sleep_time);
    		ledOutDim();
    		nrf_delay_ms(sleep_time);
    		ledOutOn();
    		nrf_delay_ms(sleep_time);
        }
    
    //    while (true)
    //    {
    //        thread_process();
    //        app_sched_execute();
    //
    //        if (NRF_LOG_PROCESS() == false)
    //        {
    //            thread_sleep();
    //        }
    //    }
    }
    

  • Sorry for the delayed response. Have you made sure that the header files are included in the path? It seems some header files are missing. I would compare the header files in your example with the PWM driver example in the Thread SDK & see what the difference is.

  • Thanks for your answer. I managed to build it after manually commenting out all the ifdefs in nrf_drv_pwm.c file. It seems that due to some macros in config file, big part of C file was ignored at parsing and therefore function definitions weren't there.

Reply Children
No Data
Related