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

NRF52832 As to the usage of timer in Advertising mode

Hello, 

please help to grasp the problem, 

when using the timer to control gpio pin with constant period as shown below, if trying to do advertising for BLE communication, 

the gpio can't be stable, when checking the behavior of gpio pins in oscilloscope, can see shaking, 

if turning off the advertising, the problem is not happened, 

if you know the solution, please help to let me know it with detailed information or example code, 

I already considered the usage of PPI or GPIOTE, but in my opinion , the cases is not matched with what I want to do (in order to control gpio pin in diverse period).

thankful for your support in advance,

ref) my email is, [email protected]

Timer Handler ex :

void tcs_waveform_timer_event_handler_us(nrf_timer_event_t event_type, void* p_context)//love_1212 1 khz(1ms) t1/t2/t3 : 25 us
{
switch(event_type)
{
case NRF_TIMER_EVENT_COMPARE0:

if(tcs_on_count == 3333)
tcs_on_count = 1;
else
tcs_on_count++;

if(tcs_on_count == 1)
NRF_P0->OUTSET = (1 << TCS_ON2); ==> GPIO 1 PIN SET
else if(tcs_on_count == 51)
NRF_P0->OUTCLR = (1 << TCS_ON2); ==> GPIO 1  PIN RESET 
else if(tcs_on_count == 52)
NRF_P0->OUTSET = (1 << TCS_ON1); ==> GPIO 2 PIN SET
else if(tcs_on_count == 102)
NRF_P0->OUTCLR = (1 << TCS_ON1); ==> GPIO 2  PIN RESET 
break;
default:
//Do nothing.
break;
}
}

I set the timer as below,


void Hal_Tcs_1Khz_Timer_Init(void)
{
uint32_t time_in_us = 5;//love_1212 for 1 khz 25;//16666; //Time(in miliseconds) between consecutive compare events.
uint32_t time_ticks;
uint32_t err_code = NRF_SUCCESS;

nrf_gpio_cfg_output(TCS_ON1);
nrf_gpio_cfg_output(TCS_ON2);

tcs_on_count = 0;//love_1120
//Configure all leds on board.
err_code = nrf_drv_timer_init(&TIMER_1, NULL, tcs_waveform_timer_event_handler_us);
APP_ERROR_CHECK(err_code);

time_ticks = nrf_drv_timer_us_to_ticks(&TIMER_1, time_in_us);//love_1115

nrf_drv_timer_extended_compare(
&TIMER_1, NRF_TIMER_CC_CHANNEL0, time_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);
NVIC_SetPriority(TIMER2_IRQn, 2);
}

thanks.

Parents
  • Hello,

    This looks like a classic textbook example of a situation where a PPI would be suitable.

     

    This is because you have a timer with a timeout that is quite fast, meaning that the timeout handler is called very frequently (it looks like it is set to 5µs.

     

    While this may just work without the softdevice, but when you start using the softdevice (starting the advertisements), then the softdevice will take over the CPU at the advertising events, which means that you will not get the interrupts when the softdevice is doing it's advertising operations.

     

    If you set up the PPI with a timer this can run in the background, not using the CPU. This means that it will be executed even though the softdevice is doing advertisement operations.

     

    See the attached main.c file. This sets up the PPI with TIMER3, and controls the two LEDs LED_1 and LED_2 on the DK.

     

    /* Copyright (c) 2009 Nordic Semiconductor. All Rights Reserved.
     *
     * The information contained herein is property of Nordic Semiconductor ASA.
     * Terms and conditions of usage are described in detail in NORDIC
     * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
     *
     * Licensees are granted free, non-transferable use of the information. NO
     * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
     * the file.
     *
     */
    
    #include "nrf.h"
    #include <stdbool.h>
    #include <stdint.h>
    //#include "bsp.h"              //include if you want to use board defines (LED_1, BUTTON_1, etc.)
    #include "nrf_gpio.h"
    #include "nrf_delay.h"
    //#include "math.h"             //include if you want to use math.h functions.
    
    // Peripheral channel assignments
    #define GPIO_GPIOTE_CH_1    0
    #define GPIO_GPIOTE_CH_2    1
    #define GPIO_PPI_CH_A       0
    #define GPIO_PPI_CH_B       1
    #define GPIO_PPI_CH_C       2
    #define GPIO_PPI_CH_D       3
    #define GPIO_TIMER_CC_NUM_1 0
    #define GPIO_TIMER_CC_NUM_2 1
    #define GPIO_TIMER_CC_NUM_3 2
    #define GPIO_TIMER_CC_NUM_4 3
    
    
    // TIMER3 reload value. 
    #define TIMER_RELOAD        16665 // = 3333*5us
    // The timer CC register used to reset the timer. Be aware that not all timers in the nRF52 have 6 CC registers.
    #define TIMER_RELOAD_CC_NUM 5
    
    
    // This function initializes timer 3 with the following configuration:
    // 24-bit, base frequency 16 MHz, auto clear on COMPARE5 match (CC5 = TIMER_RELOAD)
    void timer_init()
    {
        NRF_TIMER3->BITMODE                 = TIMER_BITMODE_BITMODE_24Bit << TIMER_BITMODE_BITMODE_Pos;
        NRF_TIMER3->PRESCALER               = 4;
        NRF_TIMER3->SHORTS                  = TIMER_SHORTS_COMPARE0_CLEAR_Msk << TIMER_RELOAD_CC_NUM;
        NRF_TIMER3->MODE                    = TIMER_MODE_MODE_Timer << TIMER_MODE_MODE_Pos;
        NRF_TIMER3->CC[TIMER_RELOAD_CC_NUM] = TIMER_RELOAD;    
        
        NRF_TIMER3->CC[GPIO_TIMER_CC_NUM_1] = 15;  // The gpio will be set to high after the timer reaches CC[GPIO_GPIOTE_CH].
        NRF_TIMER3->CC[GPIO_TIMER_CC_NUM_2] = 255;  // The gpio will be set to low  after the timer reaches CC[GPIO_GPIOTE_CH].
        NRF_TIMER3->CC[GPIO_TIMER_CC_NUM_3] = 300;
        NRF_TIMER3->CC[GPIO_TIMER_CC_NUM_4] = 510;
    }
    
    
    // Starts TIMER3
    void timer_start()
    {
        NRF_TIMER3->TASKS_START = 1;
    }
    
    
    // This function sets up TIMER3, the PPI and the GPIOTE modules to configure a single GPIOTE channel
    // Timer CC num, PPI channel nums and GPIOTE channel num is defined at the top of this file
    void gpio_init(uint32_t pinselect)
    {  
        NRF_GPIOTE->CONFIG[GPIO_GPIOTE_CH_1] = GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos | 
                                             GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos | 
                                             pinselect << GPIOTE_CONFIG_PSEL_Pos | 
                                             GPIOTE_CONFIG_OUTINIT_High << GPIOTE_CONFIG_OUTINIT_Pos;
    
        NRF_PPI->CH[GPIO_PPI_CH_A].EEP = (uint32_t)&NRF_TIMER3->EVENTS_COMPARE[GPIO_TIMER_CC_NUM_1];
        NRF_PPI->CH[GPIO_PPI_CH_A].TEP = (uint32_t)&NRF_GPIOTE->TASKS_SET[GPIO_GPIOTE_CH_1];
        NRF_PPI->CH[GPIO_PPI_CH_B].EEP = (uint32_t)&NRF_TIMER3->EVENTS_COMPARE[GPIO_TIMER_CC_NUM_2];
        NRF_PPI->CH[GPIO_PPI_CH_B].TEP = (uint32_t)&NRF_GPIOTE->TASKS_CLR[GPIO_GPIOTE_CH_1];
        
    //    NRF_PPI->CHENSET               = (1 << GPIO_PPI_CH_A) | (1 << GPIO_PPI_CH_B);
        
        
        NRF_GPIOTE->CONFIG[GPIO_GPIOTE_CH_2] = GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos | 
                                             GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos | 
                                             pinselect+1 << GPIOTE_CONFIG_PSEL_Pos | 
                                             GPIOTE_CONFIG_OUTINIT_High << GPIOTE_CONFIG_OUTINIT_Pos;
        
        NRF_PPI->CH[GPIO_PPI_CH_C].EEP = (uint32_t)&NRF_TIMER3->EVENTS_COMPARE[GPIO_TIMER_CC_NUM_3];
        NRF_PPI->CH[GPIO_PPI_CH_C].TEP = (uint32_t)&NRF_GPIOTE->TASKS_SET[GPIO_GPIOTE_CH_2];
        NRF_PPI->CH[GPIO_PPI_CH_D].EEP = (uint32_t)&NRF_TIMER3->EVENTS_COMPARE[GPIO_TIMER_CC_NUM_4];
        NRF_PPI->CH[GPIO_PPI_CH_D].TEP = (uint32_t)&NRF_GPIOTE->TASKS_CLR[GPIO_GPIOTE_CH_2];
        
        NRF_PPI->CHENSET               = (1 << GPIO_PPI_CH_A) | (1 << GPIO_PPI_CH_B) | (1 << GPIO_PPI_CH_C) | (1 << GPIO_PPI_CH_D);    
        
    }
    
    
    
    //void gpio_set_ticks(uint32_t ticks)
    //{
    //    NRF_TIMER3->CC[GPIO_TIMER_CC_NUM_1] = ticks;
    //}
    
    
    int main(void)
    {
        
        NRF_CLOCK->TASKS_HFCLKSTART = 1;
        while (!NRF_CLOCK->EVENTS_HFCLKSTARTED)
        {
            //wait for the xtal to start.
            //(The HFINT is used in the meantime, so you don't really need to wait)
        }
        
        
        // Initialize the timer
        timer_init();
        
        
        //gpio_init(LED_1); // pin 17 is LED 1. include bsp.h to use the LED_1 macro. Removed to easier port to other IDEs.
        gpio_init(17); 
        
        // Start the timer
        timer_start();
    
        while (true)
        {
            // do nothing
        }
    }
    

     

    If you only intend to toggle pins, this is the way to go. If you intend to do bigger operations then you need a different approach.

     

    The main.c file was written in SDK14.0.0, but it is fairly simple, so it should run on any SDK with the nRF52832.

    If you want to change the time the LEDs/pins should be high during runtime, you can use the function that is commented out, gpio_set_ticks(). Just modify it to set the correct register.

     

    Best regards,
    Edvin

  • Hello, Edvin,

    Today I tested the code that you updated, but the result is not good,, compile is ok, but it can't be normally operated,

    system has reset status repeatedly, ....

    I think that I need to use the following example, because I am using the latest SDK(14.1.0) for nrf52832,

    if right, please help to provide the example by referring the code that I update...

    https://github.com/bjornspockeli/nRF52_ppi_timper_gpiote_example/blob/master/main.c

    thanks.

  • Hello,

     

    What IDE do you use?

    Can you see why it resets? Try to define DEBUG in your preprocessor defines, and disable optimization (set it to -O0). Then see if the error handler catches why it is resetting. 

     

    Did you get the waveform that you desire in your original project before starting the advertising? You will need some extra components to be able to get negative voltage.

     

    If you want me to look at your project, please send a zipped project folder.

     

    BR,

    Edvin

Reply
  • Hello,

     

    What IDE do you use?

    Can you see why it resets? Try to define DEBUG in your preprocessor defines, and disable optimization (set it to -O0). Then see if the error handler catches why it is resetting. 

     

    Did you get the waveform that you desire in your original project before starting the advertising? You will need some extra components to be able to get negative voltage.

     

    If you want me to look at your project, please send a zipped project folder.

     

    BR,

    Edvin

Children
  • Hello, Edvin,

    I don't give up following your opinion and trying to implement it with the example,

    and then finally I succeeded to make the waveform and when doing test with BLE communication,

    the waveform is not shaking any more, thankful for your kindness and tireless determination,

    I got some mistakes to define the timer, I tried to change the timer from 3 to 2....

    after using the example as it is, I didn't have any problem,...

    thanks.

  • Hello,

    That is great news. Timer 3 and Timer 2 has a different amount of CC registers, as you can see here, which may cause some issues when changing timers. 

    I don't know what implementation you went with, but I have also seen that there are some differences in the default configuration for the different timers, 

    Anyway, it's good that it is working now.

     

    Best regards,

    Edvin

Related