Published
Dependencies: BLE_API TLC5955 mbed nRF51822
Fork of BLE_LoopbackUART by
Diff: gsCLockGenerator.cpp
- Revision:
- 14:73923b07ae4a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsCLockGenerator.cpp Sat Jun 09 23:23:06 2018 +0000 @@ -0,0 +1,126 @@ +// https://devzone.nordicsemi.com/question/44628/maximum-clock-possible-on-gpio-pin-nrf51/ + +// Mbed doesn't support high speed clock output, so had to hack this using direct calls to the Nordic API + +#include "mbed.h" + +// Not to be confused with the output pin +#define GPIOTE_CHANNEL_NUMBER 0 + +/** + * @enum nrf_gpiote_polarity_t + * @brief Polarity for GPIOTE channel enumerator. + */ +typedef enum +{ + NRF_GPIOTE_POLARITY_LOTOHI = GPIOTE_CONFIG_POLARITY_LoToHi, ///< Low to high + NRF_GPIOTE_POLARITY_HITOLO = GPIOTE_CONFIG_POLARITY_HiToLo, ///< High to low + NRF_GPIOTE_POLARITY_TOGGLE = GPIOTE_CONFIG_POLARITY_Toggle ///< Toggle +} nrf_gpiote_polarity_t; + + + /** + * @enum nrf_gpiote_outinit_t + * @brief Initial output value for GPIOTE channel enumerator. + */ +typedef enum +{ + NRF_GPIOTE_INITIAL_VALUE_LOW = GPIOTE_CONFIG_OUTINIT_Low, ///< Low to high + NRF_GPIOTE_INITIAL_VALUE_HIGH = GPIOTE_CONFIG_OUTINIT_High ///< High to low +} nrf_gpiote_outinit_t; + + + +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 Config GPIOTE channel as output, setting the properly desired output level. + * + * + * @param channel_number specifies the GPIOTE channel [0:3] to configure as an output channel. + * @param pin_number specifies the pin number [0:30] to use in the GPIOTE channel. + * @param polarity specifies the desired polarity in the output GPIOTE channel. + * @param initial_value specifies the initial value of the GPIOTE channel input after the channel configuration. + */ +static __INLINE void nrf_gpiote_task_config(uint32_t channel_number, uint32_t pin_number, nrf_gpiote_polarity_t polarity, nrf_gpiote_outinit_t initial_value) +{ + /* Check if the output desired is high or low */ + if (initial_value == NRF_GPIOTE_INITIAL_VALUE_LOW) + { + /* Configure channel to Pin31, not connected to the pin, and configure as a tasks that will set it to proper level */ + NRF_GPIOTE->CONFIG[channel_number] = (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) | + (31UL << GPIOTE_CONFIG_PSEL_Pos) | + (GPIOTE_CONFIG_POLARITY_HiToLo << GPIOTE_CONFIG_POLARITY_Pos); + } + else + { + /* Configure channel to Pin31, not connected to the pin, and configure as a tasks that will set it to proper level */ + NRF_GPIOTE->CONFIG[channel_number] = (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[channel_number] = 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[channel_number] = (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) | + ((uint32_t)pin_number << GPIOTE_CONFIG_PSEL_Pos) | + ((uint32_t)polarity << GPIOTE_CONFIG_POLARITY_Pos) | + ((uint32_t)initial_value << GPIOTE_CONFIG_OUTINIT_Pos); + + /* Three NOPs are required to make sure configuration is written before setting tasks or getting events */ + __NOP(); + __NOP(); + __NOP(); +} + +void init_clock(PinName clkPin) { + + // configure TIMER2 + timer2_init(); + + // configure PPI + ppi_init(); + + nrf_gpiote_task_config(GPIOTE_CHANNEL_NUMBER, clkPin, \ + NRF_GPIOTE_POLARITY_TOGGLE , NRF_GPIOTE_INITIAL_VALUE_LOW); + + NRF_TIMER2->TASKS_START = 1; // Start event generation. +} \ No newline at end of file