Published
Dependencies: BLE_API TLC5955 mbed nRF51822
Fork of BLE_LoopbackUART by
gsCLockGenerator.cpp@14:73923b07ae4a, 2018-06-09 (annotated)
- Committer:
- roysandberg
- Date:
- Sat Jun 09 23:23:06 2018 +0000
- Revision:
- 14:73923b07ae4a
Published
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
roysandberg | 14:73923b07ae4a | 1 | // https://devzone.nordicsemi.com/question/44628/maximum-clock-possible-on-gpio-pin-nrf51/ |
roysandberg | 14:73923b07ae4a | 2 | |
roysandberg | 14:73923b07ae4a | 3 | // Mbed doesn't support high speed clock output, so had to hack this using direct calls to the Nordic API |
roysandberg | 14:73923b07ae4a | 4 | |
roysandberg | 14:73923b07ae4a | 5 | #include "mbed.h" |
roysandberg | 14:73923b07ae4a | 6 | |
roysandberg | 14:73923b07ae4a | 7 | // Not to be confused with the output pin |
roysandberg | 14:73923b07ae4a | 8 | #define GPIOTE_CHANNEL_NUMBER 0 |
roysandberg | 14:73923b07ae4a | 9 | |
roysandberg | 14:73923b07ae4a | 10 | /** |
roysandberg | 14:73923b07ae4a | 11 | * @enum nrf_gpiote_polarity_t |
roysandberg | 14:73923b07ae4a | 12 | * @brief Polarity for GPIOTE channel enumerator. |
roysandberg | 14:73923b07ae4a | 13 | */ |
roysandberg | 14:73923b07ae4a | 14 | typedef enum |
roysandberg | 14:73923b07ae4a | 15 | { |
roysandberg | 14:73923b07ae4a | 16 | NRF_GPIOTE_POLARITY_LOTOHI = GPIOTE_CONFIG_POLARITY_LoToHi, ///< Low to high |
roysandberg | 14:73923b07ae4a | 17 | NRF_GPIOTE_POLARITY_HITOLO = GPIOTE_CONFIG_POLARITY_HiToLo, ///< High to low |
roysandberg | 14:73923b07ae4a | 18 | NRF_GPIOTE_POLARITY_TOGGLE = GPIOTE_CONFIG_POLARITY_Toggle ///< Toggle |
roysandberg | 14:73923b07ae4a | 19 | } nrf_gpiote_polarity_t; |
roysandberg | 14:73923b07ae4a | 20 | |
roysandberg | 14:73923b07ae4a | 21 | |
roysandberg | 14:73923b07ae4a | 22 | /** |
roysandberg | 14:73923b07ae4a | 23 | * @enum nrf_gpiote_outinit_t |
roysandberg | 14:73923b07ae4a | 24 | * @brief Initial output value for GPIOTE channel enumerator. |
roysandberg | 14:73923b07ae4a | 25 | */ |
roysandberg | 14:73923b07ae4a | 26 | typedef enum |
roysandberg | 14:73923b07ae4a | 27 | { |
roysandberg | 14:73923b07ae4a | 28 | NRF_GPIOTE_INITIAL_VALUE_LOW = GPIOTE_CONFIG_OUTINIT_Low, ///< Low to high |
roysandberg | 14:73923b07ae4a | 29 | NRF_GPIOTE_INITIAL_VALUE_HIGH = GPIOTE_CONFIG_OUTINIT_High ///< High to low |
roysandberg | 14:73923b07ae4a | 30 | } nrf_gpiote_outinit_t; |
roysandberg | 14:73923b07ae4a | 31 | |
roysandberg | 14:73923b07ae4a | 32 | |
roysandberg | 14:73923b07ae4a | 33 | |
roysandberg | 14:73923b07ae4a | 34 | static void timer2_init() |
roysandberg | 14:73923b07ae4a | 35 | { |
roysandberg | 14:73923b07ae4a | 36 | // Start 16 MHz crystal oscillator. |
roysandberg | 14:73923b07ae4a | 37 | NRF_CLOCK->EVENTS_HFCLKSTARTED = 0; |
roysandberg | 14:73923b07ae4a | 38 | NRF_CLOCK->TASKS_HFCLKSTART = 1; |
roysandberg | 14:73923b07ae4a | 39 | |
roysandberg | 14:73923b07ae4a | 40 | // Wait for the external oscillator to start up. |
roysandberg | 14:73923b07ae4a | 41 | while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0) |
roysandberg | 14:73923b07ae4a | 42 | { |
roysandberg | 14:73923b07ae4a | 43 | // Do nothing. |
roysandberg | 14:73923b07ae4a | 44 | } |
roysandberg | 14:73923b07ae4a | 45 | NRF_TIMER2->MODE = TIMER_MODE_MODE_Timer; // Set the timer in Timer Mode. |
roysandberg | 14:73923b07ae4a | 46 | NRF_TIMER2->PRESCALER = 0; |
roysandberg | 14:73923b07ae4a | 47 | NRF_TIMER2->BITMODE = TIMER_BITMODE_BITMODE_16Bit; // 16 bit mode. |
roysandberg | 14:73923b07ae4a | 48 | NRF_TIMER2->TASKS_CLEAR = 1; |
roysandberg | 14:73923b07ae4a | 49 | NRF_TIMER2->CC[0] = 1; |
roysandberg | 14:73923b07ae4a | 50 | NRF_TIMER2->EVENTS_COMPARE[0] = 0; |
roysandberg | 14:73923b07ae4a | 51 | NRF_TIMER2->SHORTS = |
roysandberg | 14:73923b07ae4a | 52 | (TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos); |
roysandberg | 14:73923b07ae4a | 53 | } |
roysandberg | 14:73923b07ae4a | 54 | |
roysandberg | 14:73923b07ae4a | 55 | static void ppi_init(void) |
roysandberg | 14:73923b07ae4a | 56 | { |
roysandberg | 14:73923b07ae4a | 57 | // Configure PPI channel 0 to toggle GPIO_OUTPUT_PIN on every TIMER2 COMPARE[0] match (200 ms) |
roysandberg | 14:73923b07ae4a | 58 | NRF_PPI->CH[0].EEP = (uint32_t)&NRF_TIMER2->EVENTS_COMPARE[0]; |
roysandberg | 14:73923b07ae4a | 59 | NRF_PPI->CH[0].TEP = (uint32_t)&NRF_GPIOTE->TASKS_OUT[GPIOTE_CHANNEL_NUMBER]; |
roysandberg | 14:73923b07ae4a | 60 | |
roysandberg | 14:73923b07ae4a | 61 | // Enable PPI channel 0 |
roysandberg | 14:73923b07ae4a | 62 | NRF_PPI->CHEN = (PPI_CHEN_CH0_Enabled << PPI_CHEN_CH0_Pos); |
roysandberg | 14:73923b07ae4a | 63 | } |
roysandberg | 14:73923b07ae4a | 64 | |
roysandberg | 14:73923b07ae4a | 65 | |
roysandberg | 14:73923b07ae4a | 66 | /** |
roysandberg | 14:73923b07ae4a | 67 | * @brief Config GPIOTE channel as output, setting the properly desired output level. |
roysandberg | 14:73923b07ae4a | 68 | * |
roysandberg | 14:73923b07ae4a | 69 | * |
roysandberg | 14:73923b07ae4a | 70 | * @param channel_number specifies the GPIOTE channel [0:3] to configure as an output channel. |
roysandberg | 14:73923b07ae4a | 71 | * @param pin_number specifies the pin number [0:30] to use in the GPIOTE channel. |
roysandberg | 14:73923b07ae4a | 72 | * @param polarity specifies the desired polarity in the output GPIOTE channel. |
roysandberg | 14:73923b07ae4a | 73 | * @param initial_value specifies the initial value of the GPIOTE channel input after the channel configuration. |
roysandberg | 14:73923b07ae4a | 74 | */ |
roysandberg | 14:73923b07ae4a | 75 | 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) |
roysandberg | 14:73923b07ae4a | 76 | { |
roysandberg | 14:73923b07ae4a | 77 | /* Check if the output desired is high or low */ |
roysandberg | 14:73923b07ae4a | 78 | if (initial_value == NRF_GPIOTE_INITIAL_VALUE_LOW) |
roysandberg | 14:73923b07ae4a | 79 | { |
roysandberg | 14:73923b07ae4a | 80 | /* Configure channel to Pin31, not connected to the pin, and configure as a tasks that will set it to proper level */ |
roysandberg | 14:73923b07ae4a | 81 | NRF_GPIOTE->CONFIG[channel_number] = (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) | |
roysandberg | 14:73923b07ae4a | 82 | (31UL << GPIOTE_CONFIG_PSEL_Pos) | |
roysandberg | 14:73923b07ae4a | 83 | (GPIOTE_CONFIG_POLARITY_HiToLo << GPIOTE_CONFIG_POLARITY_Pos); |
roysandberg | 14:73923b07ae4a | 84 | } |
roysandberg | 14:73923b07ae4a | 85 | else |
roysandberg | 14:73923b07ae4a | 86 | { |
roysandberg | 14:73923b07ae4a | 87 | /* Configure channel to Pin31, not connected to the pin, and configure as a tasks that will set it to proper level */ |
roysandberg | 14:73923b07ae4a | 88 | NRF_GPIOTE->CONFIG[channel_number] = (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) | |
roysandberg | 14:73923b07ae4a | 89 | (31UL << GPIOTE_CONFIG_PSEL_Pos) | |
roysandberg | 14:73923b07ae4a | 90 | (GPIOTE_CONFIG_POLARITY_LoToHi << GPIOTE_CONFIG_POLARITY_Pos); |
roysandberg | 14:73923b07ae4a | 91 | } |
roysandberg | 14:73923b07ae4a | 92 | |
roysandberg | 14:73923b07ae4a | 93 | /* Three NOPs are required to make sure configuration is written before setting tasks or getting events */ |
roysandberg | 14:73923b07ae4a | 94 | __NOP(); |
roysandberg | 14:73923b07ae4a | 95 | __NOP(); |
roysandberg | 14:73923b07ae4a | 96 | __NOP(); |
roysandberg | 14:73923b07ae4a | 97 | |
roysandberg | 14:73923b07ae4a | 98 | /* Launch the task to take the GPIOTE channel output to the desired level */ |
roysandberg | 14:73923b07ae4a | 99 | NRF_GPIOTE->TASKS_OUT[channel_number] = 1; |
roysandberg | 14:73923b07ae4a | 100 | |
roysandberg | 14:73923b07ae4a | 101 | /* Finally configure the channel as the caller expects. If OUTINIT works, the channel is configured properly. |
roysandberg | 14:73923b07ae4a | 102 | If it does not, the channel output inheritance sets the proper level. */ |
roysandberg | 14:73923b07ae4a | 103 | NRF_GPIOTE->CONFIG[channel_number] = (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) | |
roysandberg | 14:73923b07ae4a | 104 | ((uint32_t)pin_number << GPIOTE_CONFIG_PSEL_Pos) | |
roysandberg | 14:73923b07ae4a | 105 | ((uint32_t)polarity << GPIOTE_CONFIG_POLARITY_Pos) | |
roysandberg | 14:73923b07ae4a | 106 | ((uint32_t)initial_value << GPIOTE_CONFIG_OUTINIT_Pos); |
roysandberg | 14:73923b07ae4a | 107 | |
roysandberg | 14:73923b07ae4a | 108 | /* Three NOPs are required to make sure configuration is written before setting tasks or getting events */ |
roysandberg | 14:73923b07ae4a | 109 | __NOP(); |
roysandberg | 14:73923b07ae4a | 110 | __NOP(); |
roysandberg | 14:73923b07ae4a | 111 | __NOP(); |
roysandberg | 14:73923b07ae4a | 112 | } |
roysandberg | 14:73923b07ae4a | 113 | |
roysandberg | 14:73923b07ae4a | 114 | void init_clock(PinName clkPin) { |
roysandberg | 14:73923b07ae4a | 115 | |
roysandberg | 14:73923b07ae4a | 116 | // configure TIMER2 |
roysandberg | 14:73923b07ae4a | 117 | timer2_init(); |
roysandberg | 14:73923b07ae4a | 118 | |
roysandberg | 14:73923b07ae4a | 119 | // configure PPI |
roysandberg | 14:73923b07ae4a | 120 | ppi_init(); |
roysandberg | 14:73923b07ae4a | 121 | |
roysandberg | 14:73923b07ae4a | 122 | nrf_gpiote_task_config(GPIOTE_CHANNEL_NUMBER, clkPin, \ |
roysandberg | 14:73923b07ae4a | 123 | NRF_GPIOTE_POLARITY_TOGGLE , NRF_GPIOTE_INITIAL_VALUE_LOW); |
roysandberg | 14:73923b07ae4a | 124 | |
roysandberg | 14:73923b07ae4a | 125 | NRF_TIMER2->TASKS_START = 1; // Start event generation. |
roysandberg | 14:73923b07ae4a | 126 | } |