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

maximum clock possible on GPIO pin nrf51

Hallo everyone. I'm working with the processor nRF51422 with S210 softdevice and I would like to use the HFCLK crystal oscillator for clocking another external periferal, only during the on-mode period of the system to reduce the overall power consumption. So my question is that it's possible to routing the signal "HCLK" or "PCLK16M" (16MHz) or at least "HCLK/2" (8MHz) into a General-purpose I/O pin (GPIO). Thank you.

  • you cannot get HFCLK bypassed to GPIO, you could probably get half of HFCLK if you configure Timers, GPIOTE and PPI correctly with shorts enabled. I will have to try this out myself tomorrow to confirm. If I succeed, i will give you the configuration for it.

    Update_14.07.2015

    Half of HFCLK can be routed to GPIO and This should work even with softdevice. Half of HFCLK

    anyways as we are now testing the limits of events and tasks I see that there are few gaps happening every millisecond as you can see below. I am not sure if we can do anything about it. clock gaps

    Update_ 21.10.2015

    The gaps found here in the diagram is a bug from Logic analyzer. Measuring this from oscilloscope showed that the given method gives clean 8MHz clock on pin number 5. I used this below code to test on PCA100028 on SDK9.0

    #include <stdbool.h>
    #include <stdint.h>
    #include "nrf_delay.h"
    #include "nrf_gpio.h"
    #include "nrf_gpiote.h"
    #include "boards.h"
    
    #define TEST_PIN               5
    #define GPIOTE_CHANNEL_NUMBER  0 
    
    static void gpiote_init(void)
    {
        // Configure GPIO_OUTPUT_PIN_NUMBER as an output.
        nrf_gpio_cfg_output(TEST_PIN);
    
        // Configure GPIOTE_CHANNEL_NUMBER to toggle the GPIO pin state with input.
        // @note Only one GPIOTE task can be coupled to an output pin.
        nrf_gpiote_task_configure(GPIOTE_CHANNEL_NUMBER, TEST_PIN, \
                               NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW);
    }
    
    static void timer2_init()
    {
        // Start 16 MHz crystal oscillator.
        NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
        NRF_CLOCK->TASKS_HFCLKSTART    = 1;
    
        // Wait for the external oscillator to start up.
        while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0)
        {
            // Do nothing.
        }
        NRF_TIMER2->MODE        = TIMER_MODE_MODE_Timer;       // Set the timer in Timer Mode.
        NRF_TIMER2->PRESCALER   = 0;                          
        NRF_TIMER2->BITMODE     = TIMER_BITMODE_BITMODE_16Bit; // 16 bit mode.
        NRF_TIMER2->TASKS_CLEAR = 1;
        NRF_TIMER2->CC[0]       = 1;
        NRF_TIMER2->EVENTS_COMPARE[0] = 0;
        NRF_TIMER2->SHORTS    =
            (TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos);
    }
    
    static void ppi_init(void)
    {
        // Configure PPI channel 0 to toggle GPIO_OUTPUT_PIN on every TIMER2 COMPARE[0] match (200 ms)
        NRF_PPI->CH[0].EEP = (uint32_t)&NRF_TIMER2->EVENTS_COMPARE[0];
        NRF_PPI->CH[0].TEP = (uint32_t)&NRF_GPIOTE->TASKS_OUT[GPIOTE_CHANNEL_NUMBER];
    
        // Enable PPI channel 0
        NRF_PPI->CHEN = (PPI_CHEN_CH0_Enabled << PPI_CHEN_CH0_Pos);
    }
    
    /**
     * @brief Function for application main entry.
     */
    int main(void)
    {
        // configure TIMER2
        timer2_init();
       
        // configure PPI
        ppi_init();
        
        // configure GPIOTE
        gpiote_init();
        
        NRF_TIMER2->TASKS_START = 1;  // Start event generation.
        
        while(1);
    }
    

    Update

    in SDK9.0 and SDK 8.1, nrf_gpiote.h nrf_gpiote_task_configure needs a fix for the above to work. update it with this code

    __STATIC_INLINE void nrf_gpiote_task_configure(uint32_t idx, uint32_t pin,
                                                    nrf_gpiote_polarity_t polarity,
                                                    nrf_gpiote_outinit_t  init_val)
    {
        /* Check if the output desired is high or low */
        if (init_val == NRF_GPIOTE_INITIAL_VALUE_LOW)
        {
            /* Workaround for the OUTINIT PAN. When nrf_gpiote_task_config() is called a glitch happens
            on the GPIO if the GPIO in question is already assigned to GPIOTE and the pin is in the 
            correct state in GPIOTE but not in the OUT register. */
            NRF_GPIO->OUTCLR = (1 << pin);
            
            /* Configure channel to Pin31, not connected to the pin, and configure as a tasks that will set it to proper level */
            NRF_GPIOTE->CONFIG[idx] = (GPIOTE_CONFIG_MODE_Task       << GPIOTE_CONFIG_MODE_Pos)     |
                                                 (31UL                          << GPIOTE_CONFIG_PSEL_Pos)     |
                                                 (GPIOTE_CONFIG_POLARITY_HiToLo << GPIOTE_CONFIG_POLARITY_Pos);                                    
        } 
        else 
        {
            /* Workaround for the OUTINIT PAN. When nrf_gpiote_task_config() is called a glitch happens
            on the GPIO if the GPIO in question is already assigned to GPIOTE and the pin is in the 
            correct state in GPIOTE but not in the OUT register. */
            NRF_GPIO->OUTSET = (1 << pin);
            
            /* Configure channel to Pin31, not connected to the pin, and configure as a tasks that will set it to proper level */
            NRF_GPIOTE->CONFIG[idx] = (GPIOTE_CONFIG_MODE_Task       << GPIOTE_CONFIG_MODE_Pos)     |
                                                 (31UL                          << GPIOTE_CONFIG_PSEL_Pos)     |
                                                 (GPIOTE_CONFIG_POLARITY_LoToHi << GPIOTE_CONFIG_POLARITY_Pos);
        }
    
        /* Three NOPs are required to make sure configuration is written before setting tasks or getting events */
        __NOP();
        __NOP();
        __NOP(); 
    
        /* Launch the task to take the GPIOTE channel output to the desired level */
        NRF_GPIOTE->TASKS_OUT[idx] = 1;
        
    
        /* Finally configure the channel as the caller expects. If OUTINIT works, the channel is configured properly. 
           If it does not, the channel output inheritance sets the proper level. */
        NRF_GPIOTE->CONFIG[idx] = (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos)     |
                                             ((uint32_t)pin    << GPIOTE_CONFIG_PSEL_Pos)     |
                                             ((uint32_t)polarity      << GPIOTE_CONFIG_POLARITY_Pos) |
                                             ((uint32_t)init_val << GPIOTE_CONFIG_OUTINIT_Pos);
    
        /* Three NOPs are required to make sure configuration is written before setting tasks or getting events */
        __NOP();
        __NOP();
        __NOP(); 
    }
    

    I have raised an internal ticket for this, it will be solved.

  • also the half of the HFCLK could be good. I'll wait for your test and answer. Thanks a lot.

  • Thanks a lot for your answer. Is it possible to find a solution for the gap problem? Because I need a continuous signal as carrier signal.

  • i will have to investigate more about it, ill come back to you in two days, lets keep this thread open until then

  • We can generate 4MHz of stable clock with GPIOS, this is recommended and anything out of this is outside the spec.

Related