Published

Dependencies:   BLE_API TLC5955 mbed nRF51822

Fork of BLE_LoopbackUART by Bluetooth Low Energy

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