This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

High-frequency GPIO

Hello, all.

I am working on a project in which the ultimate goal is to read an 8-bit signal with 10kHz frequency.

To test if this would be possible, I tried to generate a digital signal using a timer. The timer is configured as below:

void digital_signal_event_init(void)
{
    ret_code_t err_code;

    nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
    timer_cfg.bit_width = NRF_TIMER_BIT_WIDTH_32;
    err_code = nrf_drv_timer_init(&TIMER_DIGITAL, &timer_cfg, digital_signal_handler);
    APP_ERROR_CHECK(err_code);

    // setup m_timer for compare event every 400ms 
    uint32_t ticks = nrf_drv_timer_us_to_ticks(&TIMER_DIGITAL, 1);
    nrf_drv_timer_extended_compare(&TIMER_DIGITAL,
                                   NRF_TIMER_CC_CHANNEL0,
                                   ticks,
                                   NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,
                                   true);
    nrf_drv_timer_enable(&TIMER_DIGITAL);
    
}

And the handle is as shown next:

void digital_signal_handler(nrf_timer_event_t event_type, void * p_context)
{
    switch (event_type)
        {
            case NRF_TIMER_EVENT_COMPARE0:                 
                if(currentSample < 10){
                  GPIO0_OUT_R = ((SineWave[currentSample])<<14);
                  sprintf(GPIO_Out_current_Value, "GPIO0_OUT register current value: %d\n", (GPIO0_OUT_R>>14)&0xFF);
                  SEGGER_RTT_WriteString(0, GPIO_Out_current_Value);
                  currentSample++;
                }
                else{
                  currentSample = 0;
                }               
                break;

            default:
                //Do nothing.
                break;
        }

}

The signal is in the array SineWave:

const uint16_t SineWave[10] = {12, 14, 14, 12, 8, 3, 1, 1, 3, 7};

The GPIO is initialized as follows:

#define IN1          NRF_GPIO_PIN_MAP(0,14)
#define IN2          NRF_GPIO_PIN_MAP(0,15)
#define IN3          NRF_GPIO_PIN_MAP(0,16)
#define IN4          NRF_GPIO_PIN_MAP(0,17)
#define IN5          NRF_GPIO_PIN_MAP(0,18)
#define IN6          NRF_GPIO_PIN_MAP(0,19)
#define IN7          NRF_GPIO_PIN_MAP(0,20)
#define IN8          NRF_GPIO_PIN_MAP(0,21)

#define IN_NUMBER                        8

static const uint8_t input_list[8] = {IN1, IN2, IN3, IN4, IN5, IN6, IN7, IN8};


for (i = 0; i < IN_NUMBER; ++i)
    {
        nrf_gpio_cfg_output(input_list[i]);  //Configure as Output
    }

But when I measure the generated signal using a DAC and an oscilloscope the frequency of the signal is as seen in the next image:

The achieved period is of 569us, which gives a 1.757kHz frequency.

I saw in other tickets people saying that GPIO frequency can go up to 16Mhz. Then, why can't I generate a high-frequency signal?

Parents
  • Hello,

    After following the suggestions above:

    I think sprintf() and SEGGER_RTT_WriteString() eat most of these 57 microseconds, try to comment them out. To achieve maximum frequency, use HAL module functions (nrf_timer.h) instead of nrf_drv_timer

    I got an improvement in the frequency of almost 18 times as seen in this image:

    +

    I used this code to initialize the clock and for the Interrupt service routine:

    #define TIMER_INSTANCE NRF_TIMER2
     /*---------------------------------------------------------------------------*/
     void
     timer2_init(void)
     {
        TIMER_INSTANCE->PRESCALER = 0;
    
        TIMER_INSTANCE->TASKS_STOP = 1;	/* Stop timer */
        TIMER_INSTANCE->MODE = TIMER_MODE_MODE_Timer;  /* taken from Nordic dev zone */
        TIMER_INSTANCE->BITMODE = TIMER_BITMODE_BITMODE_16Bit;
        TIMER_INSTANCE->CC[0] = 1;
        TIMER_INSTANCE->TASKS_CLEAR = 1; /* Clear timer */
        TIMER_INSTANCE->INTENSET = TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos;
        TIMER_INSTANCE->SHORTS = (TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos);
        
        NVIC_ClearPendingIRQ(TIMER2_IRQn);
        NVIC_SetPriority(TIMER2_IRQn, 6);
        NVIC_EnableIRQ(TIMER2_IRQn);
    
        
    
        TIMER_INSTANCE->TASKS_START = 1;
     }
    
    
     void
     TIMER2_IRQHandler(void)
     {
         if (TIMER_INSTANCE->EVENTS_COMPARE[0] != 0)
        {
        	TIMER_INSTANCE->EVENTS_COMPARE[0] = 0;
    
            if(currentSample < 10){
                GPIO0_OUT_R &= ~(0xFF<<18);   
                GPIO0_OUT_R |= ((SineWave[currentSample])<<18);   
                //sprintf(GPIO_Out_current_Value, "GPIO0_OUT register current value: %d\n", (GPIO0_OUT_R>>18)&0xFF);
                //SEGGER_RTT_WriteString(0, GPIO_Out_current_Value);
                currentSample++;
            }
            else{
                currentSample = 0;
            }
    
        	TIMER_INSTANCE->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Msk;
        }
     }

    The frequency improvement is great, but the module is not advertising anymore.

    If I don't make a call for the timer2_init() function in the main(), it advertises, but not otherwise.

    I wrote the code based on the ble_app_uart example. I changed nothing in the BLE configuration.

    The main function is looking like this now:

    /**@brief Application main function.
     */
    int main(void)
     {
        bool erase_bonds;   
    
        //NRF_CLOCK->TASKS_HFCLKSTART = 1;
    
        // Initialize.
        uart_init();
        log_init();
        timers_init();    
        leds_init(&erase_bonds);
        gpio_init();
        power_management_init();
        ble_stack_init();
        conn_evt_ext_enable();
        data_len_set(DATA_LENGTH_MAX);
        gap_params_init();
        gatt_init();
        services_init();
        timer2_init();
        //digital_signal_event_init();
    
        //saadc_init();
        //saadc_sampling_event_init();
        
    
        advertising_init();
        conn_params_init();
    
        // Start execution.
        printf("\r\nUART started.\r\n");
        NRF_LOG_INFO("Debug logging for UART over RTT started.");
        SEGGER_RTT_WriteString(0, "Debug logging for UART over RTT started.\n");
    
    
        advertising_start();
    
        //saadc_sampling_event_enable();
    
    
    
        // Enter main loop.
        for (;;)
        {
            idle_state_handle();
                  
        }
    }

    Would anyone have a clue why the advertising stops or what could I do to find out how to solve it?

  • Hi,

    you have set TIMER_INSTANCE->CC[0] = 1, so CPU spends all the time in TIMER2_IRQHandler, not leaving any time for low-priority processes.

Reply Children
Related