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

nRF52, 1-4 MHz clock needed

I am using the nRF52 Preview board, PCA 10036. I need to provide a high-frequency clock signal to a peripheral. Anything between 1 and 4 MHz will work. However, I don't need and don't want the CPU to receive an interrupt on every clock pulse.

I think that the GPIOTE example in the SDK is relevant to my needs. (I'm using SDK 0.9.2.) However: the code has a function called timer_dummy_handler(). While this function does nothing, the code does connect it to a timer event, with a call to nrf_drv_timer_init(). The documentation for nrf_drv_timer_init() says that an event handler function is a required argument.

The GPIOTE example code has a timer frequency of 200 milliseconds. Calling a quick and useless function five times/second is harmless. Calling that same function 1-4 million times / second would be a nightmare.

Is that function call actually used?

Can I avoid attaching a function call to a timer event, if I program at a lower level?

  • Following up to myself:

    I am looking for something similar to this example for the nRF51822, but for the nRF52 series.

    devzone.nordicsemi.com/.../

    I know that there have been some significant changes between the two devices. I don't want to start following an outdated example, only to find that it doesn't work for me. Thanks.

  • seems pretty simple - run one of the TIMERs, set the COMPARE to whatever gives you 1-4MHz, enable the short between COMPARE and CLEAR and set up a PPI to toggle a GPIO pin on the COMPARE event. Now you have a 1-4MHz toggling GPIO pin with no CPU involvement, just the power use from the HKCLK running.

  • Thanks for your reply, RK. You may not recognize my name, but I'm rather new to embedded systems programming, and you have helped me several times.

    I think you are telling me that I guessed correctly when I said that I need to program at a lower level. I won't use the timer driver, instead I use the hardware abstraction layer. This may apply to other parts of the program too, I'm not sure yet.

    I am reading through the hardware specification for the chip and trying to grasp all that it can do. The SDK examples do not show any of this low-level programming. If you know where I can see and learn more, I would appreciate a link. Thanks.

  • yeah you don't need the hardware drivers for this - it should be no more than about 20 lines of code to set it up and make it run.

    Break it down. Job #1, configure a TIMER to count at 16MHz (no scaler) and set COMPARE[0], or another COMPARE to '4' for 4MHz or '16' for 1MHz. Enable the SHORTS for COMPARE[0] and CLEAR. That's all chapter 24 of the manual. Now you have a timer which counts at the right rate.

    Next look up GPIOTE, chapter 21. Configure one of those to Task mode, on a pin you select, with polarity == TOGGLE. Each time you trigger GPIOTE->TASKS_OUT[your task number] the pin will toggle. Test that.

    Now hook those two up with PPI, chapter 22. CH[].TEP is the task address, that's the GPIOTE, CH[].EEP is the event, that's the TIMER COMPARE event, set those, enable the channel, now everytime the timer gets to 4, it will clear and trigger, via the PPI, the pin to toggle.

  • Hi,

    I wrote some code for this earlier, for 4 MHz output on pin 18 set NRF_TIMER1->CC[0] = 2;.

    int main(void)
    {
        // Set up GPIO as output
        nrf_gpio_range_cfg_output(17, 18);
        nrf_gpio_pin_clear(17); // Light LED 1 to indicate that the code is running
        
        // Start high frequency clock
        NRF_CLOCK->TASKS_HFCLKSTART = 1;
        while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0)
        {
            // Wait for clock to start
        }
        NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
        
        // Configure GPIOTE to toggle pin 18 
        NRF_GPIOTE->CONFIG[0] = GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos |
                                GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos |
                                18 << GPIOTE_CONFIG_PSEL_Pos | 
                                GPIOTE_CONFIG_OUTINIT_Low << GPIOTE_CONFIG_OUTINIT_Pos;
                                
        // Set up timer
        NRF_TIMER1->PRESCALER = 0;
        NRF_TIMER1->CC[0] = 2; // Adjust the output frequency by adjusting the CC.
        NRF_TIMER1->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos;
        NRF_TIMER1->TASKS_START = 1;
            
        // Set up PPI to connect the timer compare event with the GPIOTE toggle task
        NRF_PPI->CH[0].EEP = (uint32_t) &NRF_TIMER1->EVENTS_COMPARE[0];
        NRF_PPI->CH[0].TEP = (uint32_t) &NRF_GPIOTE->TASKS_OUT[0];
        
        NRF_PPI->CHENSET = PPI_CHENSET_CH0_Enabled << PPI_CHENSET_CH0_Pos;
        
        while (true)
        {
           
        }
    }
    

    The principle is well described by RKs post. You can find relevant documentation in the infocenter:

    Best regards,

    Øyvind

Related