SX1276GenericLib to support sx1276 bassed LoRa modules, including HopeRF RFM95, Murata CMWX1ZZABZ and Semtech SX1276MB1MAS/SX1276MB1LAS modules

Dependents:   DISCO-L072CZ-LRWAN1_LoRa_PingPong DISCO-L072CZ-LRWAN1_LoRa_PingPong DISCO-L072CZ-LRWAN1_LoRa_PingPong DISCO-L072CZ-LRWAN1_LoRa_USB_Rx ... more

Fork of SX1276Lib by Semtech

Committer:
Helmut Tschemernjak
Date:
Mon Jul 31 16:11:17 2017 +0200
Revision:
77:7f227a4dffe6
Child:
78:9d2cc07d9525
Moved SAMD timer and sleep code into new file arduino-d21.cpp

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Helmut Tschemernjak 77:7f227a4dffe6 1 /*
Helmut Tschemernjak 77:7f227a4dffe6 2 * The file is Licensed under the Apache License, Version 2.0
Helmut Tschemernjak 77:7f227a4dffe6 3 * (c) 2017 Helmut Tschemernjak
Helmut Tschemernjak 77:7f227a4dffe6 4 * 30826 Garbsen (Hannover) Germany
Helmut Tschemernjak 77:7f227a4dffe6 5 */
Helmut Tschemernjak 77:7f227a4dffe6 6
Helmut Tschemernjak 77:7f227a4dffe6 7 #ifdef ARDUINO
Helmut Tschemernjak 77:7f227a4dffe6 8
Helmut Tschemernjak 77:7f227a4dffe6 9 using namespace std;
Helmut Tschemernjak 77:7f227a4dffe6 10
Helmut Tschemernjak 77:7f227a4dffe6 11 #include "arduino-mbed.h"
Helmut Tschemernjak 77:7f227a4dffe6 12 #include "arduino-util.h"
Helmut Tschemernjak 77:7f227a4dffe6 13
Helmut Tschemernjak 77:7f227a4dffe6 14
Helmut Tschemernjak 77:7f227a4dffe6 15
Helmut Tschemernjak 77:7f227a4dffe6 16 #if defined(__SAMD21G18A__) || defined(__SAMD21J18A__)
Helmut Tschemernjak 77:7f227a4dffe6 17 /*
Helmut Tschemernjak 77:7f227a4dffe6 18 * __SAMD21J18A__ is the SamD21 Explained Board
Helmut Tschemernjak 77:7f227a4dffe6 19 * __SAMD21G18A__ is Genuino Zero-Board (compatible with the LoRa board)
Helmut Tschemernjak 77:7f227a4dffe6 20 */
Helmut Tschemernjak 77:7f227a4dffe6 21
Helmut Tschemernjak 77:7f227a4dffe6 22 /*
Helmut Tschemernjak 77:7f227a4dffe6 23 * see tcc.h is automatically included from:
Helmut Tschemernjak 77:7f227a4dffe6 24 * Arduino15/packages/arduino/tools/CMSIS-Atmel/1.1.0/CMSIS/
Helmut Tschemernjak 77:7f227a4dffe6 25 * Device/ATMEL/samd21/include/component/tcc.h
Helmut Tschemernjak 77:7f227a4dffe6 26 * See also tcc.c (ASF/mbed, e.g. Tcc_get_count_value)
Helmut Tschemernjak 77:7f227a4dffe6 27 */
Helmut Tschemernjak 77:7f227a4dffe6 28 static void initTimer(Tcc *t);
Helmut Tschemernjak 77:7f227a4dffe6 29 static uint32_t getTimerCount(Tcc *t);
Helmut Tschemernjak 77:7f227a4dffe6 30
Helmut Tschemernjak 77:7f227a4dffe6 31 /*
Helmut Tschemernjak 77:7f227a4dffe6 32 * The Atmel D21 has three TCC timer, other models have more.
Helmut Tschemernjak 77:7f227a4dffe6 33 */
Helmut Tschemernjak 77:7f227a4dffe6 34 const struct TCC_config {
Helmut Tschemernjak 77:7f227a4dffe6 35 Tcc *tcc_ptr;
Helmut Tschemernjak 77:7f227a4dffe6 36 IRQn_Type tcc_irq;
Helmut Tschemernjak 77:7f227a4dffe6 37 uint8_t nbits;
Helmut Tschemernjak 77:7f227a4dffe6 38 } TCC_data[] {
Helmut Tschemernjak 77:7f227a4dffe6 39 { TCC0, TCC0_IRQn, 24 },
Helmut Tschemernjak 77:7f227a4dffe6 40 { TCC1, TCC1_IRQn, 24 },
Helmut Tschemernjak 77:7f227a4dffe6 41 { TCC2, TCC2_IRQn, 16 },
Helmut Tschemernjak 77:7f227a4dffe6 42 { NULL, (IRQn_Type)NULL, 0 }
Helmut Tschemernjak 77:7f227a4dffe6 43 };
Helmut Tschemernjak 77:7f227a4dffe6 44
Helmut Tschemernjak 77:7f227a4dffe6 45 /*
Helmut Tschemernjak 77:7f227a4dffe6 46 * We preferably use the TCC timers because it supports 24-bit counters
Helmut Tschemernjak 77:7f227a4dffe6 47 * versus TC Timer which supports only 8 or 16 bit counters only.
Helmut Tschemernjak 77:7f227a4dffe6 48 * TCC0/1/2 timer work on the D21 using Arduino Zero.
Helmut Tschemernjak 77:7f227a4dffe6 49 */
Helmut Tschemernjak 77:7f227a4dffe6 50 #define USE_TCC_TIMEOUT 0 // 0=TCC0, 1=TTC1, 2=TTC2 (see TCC_data)
Helmut Tschemernjak 77:7f227a4dffe6 51 #define USE_TCC_TICKER 1
Helmut Tschemernjak 77:7f227a4dffe6 52
Helmut Tschemernjak 77:7f227a4dffe6 53
Helmut Tschemernjak 77:7f227a4dffe6 54 /*
Helmut Tschemernjak 77:7f227a4dffe6 55 * every 21333 ns equals one tick (1/(48000000/1024)) // prescaler 1024, 48 MHz
Helmut Tschemernjak 77:7f227a4dffe6 56 * every 61035 ns equals one tick (1/(32768/2)) // prescaler 2, 32 kHz
Helmut Tschemernjak 77:7f227a4dffe6 57 * COUNT*DIVIDER*SECS until interrupt
Helmut Tschemernjak 77:7f227a4dffe6 58 * CPU 48 MHz = (65536*1024)/1.398636s
Helmut Tschemernjak 77:7f227a4dffe6 59 * RTC 32 kHz = (65536*2)/4.0s
Helmut Tschemernjak 77:7f227a4dffe6 60 */
Helmut Tschemernjak 77:7f227a4dffe6 61 #define NS_PER_CLOCK_CPU 21333 // ns secs per clock
Helmut Tschemernjak 77:7f227a4dffe6 62 #define NS_PER_CLOCK_RTC 61035 // ns secs per clock
Helmut Tschemernjak 77:7f227a4dffe6 63
Helmut Tschemernjak 77:7f227a4dffe6 64 #define NS_PER_CLOCK NS_PER_CLOCK_RTC
Helmut Tschemernjak 77:7f227a4dffe6 65
Helmut Tschemernjak 77:7f227a4dffe6 66 /* ----------------- TICKER TIMER CODE ----------------------*/
Helmut Tschemernjak 77:7f227a4dffe6 67
Helmut Tschemernjak 77:7f227a4dffe6 68 /*
Helmut Tschemernjak 77:7f227a4dffe6 69 * The global ns_counter contains the time in ns from the last time
Helmut Tschemernjak 77:7f227a4dffe6 70 * the counter has been wrapped. It cannot be used directly because the
Helmut Tschemernjak 77:7f227a4dffe6 71 * current counter has to be added fore using it. Use instead
Helmut Tschemernjak 77:7f227a4dffe6 72 * ns_getTicker(), us_ ns_getTicker(), ms_getTicker()
Helmut Tschemernjak 77:7f227a4dffe6 73 */
Helmut Tschemernjak 77:7f227a4dffe6 74
Helmut Tschemernjak 77:7f227a4dffe6 75 uint64_t ticker_ns;
Helmut Tschemernjak 77:7f227a4dffe6 76 static bool initTickerDone = false;
Helmut Tschemernjak 77:7f227a4dffe6 77
Helmut Tschemernjak 77:7f227a4dffe6 78 uint64_t ns_getTicker(void)
Helmut Tschemernjak 77:7f227a4dffe6 79 {
Helmut Tschemernjak 77:7f227a4dffe6 80 Tcc *t = TCC_data[USE_TCC_TICKER].tcc_ptr;
Helmut Tschemernjak 77:7f227a4dffe6 81 if (!initTickerDone) {
Helmut Tschemernjak 77:7f227a4dffe6 82 initTimer(t);
Helmut Tschemernjak 77:7f227a4dffe6 83 initTickerDone = true;
Helmut Tschemernjak 77:7f227a4dffe6 84
Helmut Tschemernjak 77:7f227a4dffe6 85 // set counter top to max 16 bit for testing
Helmut Tschemernjak 77:7f227a4dffe6 86 // t->PER.bit.PER = 0xffff;
Helmut Tschemernjak 77:7f227a4dffe6 87 // while (t->SYNCBUSY.bit.PER == 1); // wait for sync
Helmut Tschemernjak 77:7f227a4dffe6 88
Helmut Tschemernjak 77:7f227a4dffe6 89 t->CTRLA.reg |= TCC_CTRLA_ENABLE ; // Enable TC
Helmut Tschemernjak 77:7f227a4dffe6 90 while (t->SYNCBUSY.bit.ENABLE == 1); // wait for sync
Helmut Tschemernjak 77:7f227a4dffe6 91 }
Helmut Tschemernjak 77:7f227a4dffe6 92
Helmut Tschemernjak 77:7f227a4dffe6 93 /*
Helmut Tschemernjak 77:7f227a4dffe6 94 * if we are called from the interrupt level, the counter contains
Helmut Tschemernjak 77:7f227a4dffe6 95 * somehow wrong data, therfore we needs to read it twice.
Helmut Tschemernjak 77:7f227a4dffe6 96 * Another option was to add a little wait (loop 500x)
Helmut Tschemernjak 77:7f227a4dffe6 97 * in the TCC_TIMEOUT interrupt handler.
Helmut Tschemernjak 77:7f227a4dffe6 98 */
Helmut Tschemernjak 77:7f227a4dffe6 99 if (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) // check if we are in the interrupt
Helmut Tschemernjak 77:7f227a4dffe6 100 getTimerCount(t);
Helmut Tschemernjak 77:7f227a4dffe6 101
Helmut Tschemernjak 77:7f227a4dffe6 102 uint64_t counter_us = (uint64_t)NS_PER_CLOCK * (uint64_t)getTimerCount(t);
Helmut Tschemernjak 77:7f227a4dffe6 103 uint64_t ns = ticker_ns + counter_us;
Helmut Tschemernjak 77:7f227a4dffe6 104
Helmut Tschemernjak 77:7f227a4dffe6 105 return ns;
Helmut Tschemernjak 77:7f227a4dffe6 106 }
Helmut Tschemernjak 77:7f227a4dffe6 107
Helmut Tschemernjak 77:7f227a4dffe6 108 #if USE_TCC_TICKER == 0
Helmut Tschemernjak 77:7f227a4dffe6 109 void TCC0_Handler()
Helmut Tschemernjak 77:7f227a4dffe6 110 #elif USE_TCC_TICKER == 1
Helmut Tschemernjak 77:7f227a4dffe6 111 void TCC1_Handler()
Helmut Tschemernjak 77:7f227a4dffe6 112 #elif USE_TCC_TICKER == 2
Helmut Tschemernjak 77:7f227a4dffe6 113 void TCC2_Handler()
Helmut Tschemernjak 77:7f227a4dffe6 114 #endif
Helmut Tschemernjak 77:7f227a4dffe6 115 {
Helmut Tschemernjak 77:7f227a4dffe6 116 Tcc *t = TCC_data[USE_TCC_TICKER].tcc_ptr;
Helmut Tschemernjak 77:7f227a4dffe6 117 /*
Helmut Tschemernjak 77:7f227a4dffe6 118 * Overflow means the timer top exeeded
Helmut Tschemernjak 77:7f227a4dffe6 119 */
Helmut Tschemernjak 77:7f227a4dffe6 120 if (t->INTFLAG.bit.OVF == 1) { // A overflow caused the interrupt
Helmut Tschemernjak 77:7f227a4dffe6 121 t->INTFLAG.bit.OVF = 1; // writing a one clears the flag ovf flag
Helmut Tschemernjak 77:7f227a4dffe6 122 // ser->println("T_OVF");
Helmut Tschemernjak 77:7f227a4dffe6 123
Helmut Tschemernjak 77:7f227a4dffe6 124 /*
Helmut Tschemernjak 77:7f227a4dffe6 125 * reading the count once is needed, otherwise
Helmut Tschemernjak 77:7f227a4dffe6 126 * it will not wrap correct.
Helmut Tschemernjak 77:7f227a4dffe6 127 */
Helmut Tschemernjak 77:7f227a4dffe6 128 getTimerCount(t);
Helmut Tschemernjak 77:7f227a4dffe6 129
Helmut Tschemernjak 77:7f227a4dffe6 130 int bits = TCC_data[USE_TCC_TICKER].nbits;
Helmut Tschemernjak 77:7f227a4dffe6 131 int maxCounts = (uint32_t)(1<<bits);
Helmut Tschemernjak 77:7f227a4dffe6 132
Helmut Tschemernjak 77:7f227a4dffe6 133 ticker_ns += (uint64_t)NS_PER_CLOCK * (uint64_t)maxCounts;
Helmut Tschemernjak 77:7f227a4dffe6 134 }
Helmut Tschemernjak 77:7f227a4dffe6 135 if (t->INTFLAG.bit.MC0 == 1) { // A compare to cc0 caused the interrupt
Helmut Tschemernjak 77:7f227a4dffe6 136 t->INTFLAG.bit.MC0 = 1; // writing a one clears the MCO (match capture) flag
Helmut Tschemernjak 77:7f227a4dffe6 137 // ser->println("T_MC0");
Helmut Tschemernjak 77:7f227a4dffe6 138 }
Helmut Tschemernjak 77:7f227a4dffe6 139 }
Helmut Tschemernjak 77:7f227a4dffe6 140
Helmut Tschemernjak 77:7f227a4dffe6 141 /* ----------------- SUPPORT CODE FOR TCC TIMERS----------------------*/
Helmut Tschemernjak 77:7f227a4dffe6 142
Helmut Tschemernjak 77:7f227a4dffe6 143 static bool initTimerDone = false;
Helmut Tschemernjak 77:7f227a4dffe6 144
Helmut Tschemernjak 77:7f227a4dffe6 145 static void initTimer(Tcc *t)
Helmut Tschemernjak 77:7f227a4dffe6 146 {
Helmut Tschemernjak 77:7f227a4dffe6 147
Helmut Tschemernjak 77:7f227a4dffe6 148 /*
Helmut Tschemernjak 77:7f227a4dffe6 149 * enable clock for TCC, see gclk.h
Helmut Tschemernjak 77:7f227a4dffe6 150 * GCLK_CLKCTRL_GEN_GCLK0 for 48 Mhz CPU
Helmut Tschemernjak 77:7f227a4dffe6 151 * GCLK_CLKCTRL_GEN_GCLK1 for 32k extern crystal XOSC32K (ifdef CRYSTALLESS)
Helmut Tschemernjak 77:7f227a4dffe6 152 * GCLK_CLKCTRL_GEN_GCLK1 for 32k internal OSC32K
Helmut Tschemernjak 77:7f227a4dffe6 153 * see Arduino: arduino/hardware/samd/1.6.15/cores/arduino/startup.c
Helmut Tschemernjak 77:7f227a4dffe6 154 * Use TCC_CTRLA_PRESCALER_DIV1024 for for 48 Mhz clock
Helmut Tschemernjak 77:7f227a4dffe6 155 * Use TCC_CTRLA_PRESCALER_DIV2 for 32k clock
Helmut Tschemernjak 77:7f227a4dffe6 156 */
Helmut Tschemernjak 77:7f227a4dffe6 157 if (t == TCC0 || t == TCC1) {
Helmut Tschemernjak 77:7f227a4dffe6 158 REG_GCLK_CLKCTRL = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK1 | GCLK_CLKCTRL_ID_TCC0_TCC1);
Helmut Tschemernjak 77:7f227a4dffe6 159 } else if (t == TCC2) {
Helmut Tschemernjak 77:7f227a4dffe6 160 REG_GCLK_CLKCTRL = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK1 | GCLK_CLKCTRL_ID_TCC2_TC3_Val);
Helmut Tschemernjak 77:7f227a4dffe6 161 }
Helmut Tschemernjak 77:7f227a4dffe6 162 while (GCLK->STATUS.bit.SYNCBUSY == 1); // wait for sync
Helmut Tschemernjak 77:7f227a4dffe6 163
Helmut Tschemernjak 77:7f227a4dffe6 164 t->CTRLA.reg &= ~TCC_CTRLA_ENABLE; // Disable TCC
Helmut Tschemernjak 77:7f227a4dffe6 165 while (t->SYNCBUSY.bit.ENABLE == 1); // wait for sync
Helmut Tschemernjak 77:7f227a4dffe6 166
Helmut Tschemernjak 77:7f227a4dffe6 167 t->CTRLA.reg |= (TCC_CTRLA_PRESCALER_DIV2 | TCC_CTRLA_RUNSTDBY); // Set perscaler
Helmut Tschemernjak 77:7f227a4dffe6 168
Helmut Tschemernjak 77:7f227a4dffe6 169 t->WAVE.reg |= TCC_WAVE_WAVEGEN_NFRQ; // Set wave form configuration
Helmut Tschemernjak 77:7f227a4dffe6 170 while (t->SYNCBUSY.bit.WAVE == 1); // wait for sync
Helmut Tschemernjak 77:7f227a4dffe6 171
Helmut Tschemernjak 77:7f227a4dffe6 172 t->PER.bit.PER = 0xffffff; // set counter top to max 24 bit
Helmut Tschemernjak 77:7f227a4dffe6 173 while (t->SYNCBUSY.bit.PER == 1); // wait for sync
Helmut Tschemernjak 77:7f227a4dffe6 174
Helmut Tschemernjak 77:7f227a4dffe6 175 // the compare counter TC->CC[0].reg will be set in the startTimer
Helmut Tschemernjak 77:7f227a4dffe6 176 // after the timeout calculation is known.
Helmut Tschemernjak 77:7f227a4dffe6 177
Helmut Tschemernjak 77:7f227a4dffe6 178 // Interrupts
Helmut Tschemernjak 77:7f227a4dffe6 179 t->INTENSET.reg = 0; // disable all interrupts
Helmut Tschemernjak 77:7f227a4dffe6 180 t->INTENSET.bit.OVF = 1; // enable overfollow
Helmut Tschemernjak 77:7f227a4dffe6 181 t->INTENSET.bit.MC0 = 1; // enable compare match to CC0
Helmut Tschemernjak 77:7f227a4dffe6 182
Helmut Tschemernjak 77:7f227a4dffe6 183 const struct TCC_config *cp = &TCC_data[0];
Helmut Tschemernjak 77:7f227a4dffe6 184 while (cp->tcc_ptr) {
Helmut Tschemernjak 77:7f227a4dffe6 185 if (cp->tcc_ptr == t) {
Helmut Tschemernjak 77:7f227a4dffe6 186 NVIC_EnableIRQ(cp->tcc_irq); // Enable InterruptVector
Helmut Tschemernjak 77:7f227a4dffe6 187 break;
Helmut Tschemernjak 77:7f227a4dffe6 188 }
Helmut Tschemernjak 77:7f227a4dffe6 189 cp++;
Helmut Tschemernjak 77:7f227a4dffe6 190 }
Helmut Tschemernjak 77:7f227a4dffe6 191 }
Helmut Tschemernjak 77:7f227a4dffe6 192
Helmut Tschemernjak 77:7f227a4dffe6 193
Helmut Tschemernjak 77:7f227a4dffe6 194 #if 0
Helmut Tschemernjak 77:7f227a4dffe6 195 // Atmel ASF Code
Helmut Tschemernjak 77:7f227a4dffe6 196 static uint32_t getTimerCount(Tcc *t)
Helmut Tschemernjak 77:7f227a4dffe6 197 {
Helmut Tschemernjak 77:7f227a4dffe6 198 uint32_t last_cmd;
Helmut Tschemernjak 77:7f227a4dffe6 199 /* Wait last command done */
Helmut Tschemernjak 77:7f227a4dffe6 200 do {
Helmut Tschemernjak 77:7f227a4dffe6 201 while (t->SYNCBUSY.bit.CTRLB); /* Wait for sync */
Helmut Tschemernjak 77:7f227a4dffe6 202
Helmut Tschemernjak 77:7f227a4dffe6 203 last_cmd = t->CTRLBSET.reg & TCC_CTRLBSET_CMD_Msk;
Helmut Tschemernjak 77:7f227a4dffe6 204 if (TCC_CTRLBSET_CMD_NONE == last_cmd) {
Helmut Tschemernjak 77:7f227a4dffe6 205 /* Issue read command and break */
Helmut Tschemernjak 77:7f227a4dffe6 206 t->CTRLBSET.bit.CMD = TCC_CTRLBSET_CMD_READSYNC_Val;
Helmut Tschemernjak 77:7f227a4dffe6 207 break;
Helmut Tschemernjak 77:7f227a4dffe6 208 } else if (TCC_CTRLBSET_CMD_READSYNC == last_cmd) {
Helmut Tschemernjak 77:7f227a4dffe6 209 /* Command have been issued */
Helmut Tschemernjak 77:7f227a4dffe6 210 break;
Helmut Tschemernjak 77:7f227a4dffe6 211 }
Helmut Tschemernjak 77:7f227a4dffe6 212 } while (1);
Helmut Tschemernjak 77:7f227a4dffe6 213
Helmut Tschemernjak 77:7f227a4dffe6 214 while (t->SYNCBUSY.bit.COUNT); /* Wait for sync */
Helmut Tschemernjak 77:7f227a4dffe6 215
Helmut Tschemernjak 77:7f227a4dffe6 216 return t->COUNT.reg;
Helmut Tschemernjak 77:7f227a4dffe6 217 }
Helmut Tschemernjak 77:7f227a4dffe6 218 #endif
Helmut Tschemernjak 77:7f227a4dffe6 219
Helmut Tschemernjak 77:7f227a4dffe6 220
Helmut Tschemernjak 77:7f227a4dffe6 221 static uint32_t getTimerCount(Tcc *t)
Helmut Tschemernjak 77:7f227a4dffe6 222 {
Helmut Tschemernjak 77:7f227a4dffe6 223
Helmut Tschemernjak 77:7f227a4dffe6 224 noInterrupts();
Helmut Tschemernjak 77:7f227a4dffe6 225
Helmut Tschemernjak 77:7f227a4dffe6 226 while (t->SYNCBUSY.bit.CTRLB); /* Wait for sync */
Helmut Tschemernjak 77:7f227a4dffe6 227
Helmut Tschemernjak 77:7f227a4dffe6 228 t->CTRLBSET.bit.CMD = TCC_CTRLBSET_CMD_READSYNC_Val; /* Issue read command and break */
Helmut Tschemernjak 77:7f227a4dffe6 229
Helmut Tschemernjak 77:7f227a4dffe6 230 while (t->SYNCBUSY.bit.COUNT); /* Wait for sync */
Helmut Tschemernjak 77:7f227a4dffe6 231
Helmut Tschemernjak 77:7f227a4dffe6 232 uint32_t count = t->COUNT.reg;
Helmut Tschemernjak 77:7f227a4dffe6 233
Helmut Tschemernjak 77:7f227a4dffe6 234 interrupts();
Helmut Tschemernjak 77:7f227a4dffe6 235
Helmut Tschemernjak 77:7f227a4dffe6 236 return count;
Helmut Tschemernjak 77:7f227a4dffe6 237 }
Helmut Tschemernjak 77:7f227a4dffe6 238
Helmut Tschemernjak 77:7f227a4dffe6 239
Helmut Tschemernjak 77:7f227a4dffe6 240 Tcc *getTimeout_tcc(void)
Helmut Tschemernjak 77:7f227a4dffe6 241 {
Helmut Tschemernjak 77:7f227a4dffe6 242 return TCC_data[USE_TCC_TIMEOUT].tcc_ptr;
Helmut Tschemernjak 77:7f227a4dffe6 243 }
Helmut Tschemernjak 77:7f227a4dffe6 244
Helmut Tschemernjak 77:7f227a4dffe6 245
Helmut Tschemernjak 77:7f227a4dffe6 246 void stopTimer(Tcc *t)
Helmut Tschemernjak 77:7f227a4dffe6 247 {
Helmut Tschemernjak 77:7f227a4dffe6 248 t->CTRLA.reg &= ~TCC_CTRLA_ENABLE; // Disable TC
Helmut Tschemernjak 77:7f227a4dffe6 249 while (t->SYNCBUSY.bit.ENABLE == 1); // wait for sync
Helmut Tschemernjak 77:7f227a4dffe6 250 }
Helmut Tschemernjak 77:7f227a4dffe6 251
Helmut Tschemernjak 77:7f227a4dffe6 252
Helmut Tschemernjak 77:7f227a4dffe6 253 /* ----------------- TIMEOUT TIMER CODE ----------------------*/
Helmut Tschemernjak 77:7f227a4dffe6 254
Helmut Tschemernjak 77:7f227a4dffe6 255 void startTimer(Tcc *t, uint64_t delay_ns)
Helmut Tschemernjak 77:7f227a4dffe6 256 {
Helmut Tschemernjak 77:7f227a4dffe6 257 if (!initTimerDone) {
Helmut Tschemernjak 77:7f227a4dffe6 258 initTimer(t); // initial setup with stopped timer
Helmut Tschemernjak 77:7f227a4dffe6 259 initTimerDone = true;
Helmut Tschemernjak 77:7f227a4dffe6 260 }
Helmut Tschemernjak 77:7f227a4dffe6 261
Helmut Tschemernjak 77:7f227a4dffe6 262 stopTimer(t); // avoid timer interrupts while calculating
Helmut Tschemernjak 77:7f227a4dffe6 263
Helmut Tschemernjak 77:7f227a4dffe6 264 /*
Helmut Tschemernjak 77:7f227a4dffe6 265 * every 21333 ns equals one tick (1/(48000000/1024))
Helmut Tschemernjak 77:7f227a4dffe6 266 * COUNT*DIVIDER*SECS until interrupt
Helmut Tschemernjak 77:7f227a4dffe6 267 * 48 Mhz = (65536*1024)/1.398636s
Helmut Tschemernjak 77:7f227a4dffe6 268 */
Helmut Tschemernjak 77:7f227a4dffe6 269 uint64_t nclocks = (uint64_t)delay_ns;
Helmut Tschemernjak 77:7f227a4dffe6 270 nclocks /= (uint64_t)NS_PER_CLOCK;
Helmut Tschemernjak 77:7f227a4dffe6 271 int nCounts = nclocks;
Helmut Tschemernjak 77:7f227a4dffe6 272
Helmut Tschemernjak 77:7f227a4dffe6 273 int bits = TCC_data[USE_TCC_TIMEOUT].nbits;
Helmut Tschemernjak 77:7f227a4dffe6 274 int maxCounts = (uint32_t)(1<<bits)-1;
Helmut Tschemernjak 77:7f227a4dffe6 275
Helmut Tschemernjak 77:7f227a4dffe6 276 if (nCounts > maxCounts) // if count exceeds timer capacity
Helmut Tschemernjak 77:7f227a4dffe6 277 nCounts = maxCounts; // set the largest posible count.
Helmut Tschemernjak 77:7f227a4dffe6 278 if (nCounts <= 0)
Helmut Tschemernjak 77:7f227a4dffe6 279 nCounts = 1;
Helmut Tschemernjak 77:7f227a4dffe6 280 t->CC[0].bit.CC = nCounts;
Helmut Tschemernjak 77:7f227a4dffe6 281 while (t->SYNCBUSY.bit.CC0 == 1); // wait for sync
Helmut Tschemernjak 77:7f227a4dffe6 282
Helmut Tschemernjak 77:7f227a4dffe6 283 t->CTRLA.reg |= TCC_CTRLA_ENABLE ; // Enable TC
Helmut Tschemernjak 77:7f227a4dffe6 284 while (t->SYNCBUSY.bit.ENABLE == 1); // wait for sync
Helmut Tschemernjak 77:7f227a4dffe6 285 #if 0
Helmut Tschemernjak 77:7f227a4dffe6 286 ser->print(ms_getTicker(), DEC);
Helmut Tschemernjak 77:7f227a4dffe6 287 ser->print(" startTimer: nCounts=");
Helmut Tschemernjak 77:7f227a4dffe6 288 ser->println(nCounts, DEC);
Helmut Tschemernjak 77:7f227a4dffe6 289 #endif
Helmut Tschemernjak 77:7f227a4dffe6 290 }
Helmut Tschemernjak 77:7f227a4dffe6 291
Helmut Tschemernjak 77:7f227a4dffe6 292
Helmut Tschemernjak 77:7f227a4dffe6 293 #if USE_TCC_TIMEOUT == 0
Helmut Tschemernjak 77:7f227a4dffe6 294 void TCC0_Handler()
Helmut Tschemernjak 77:7f227a4dffe6 295 #elif USE_TCC_TIMEOUT == 1
Helmut Tschemernjak 77:7f227a4dffe6 296 void TCC1_Handler()
Helmut Tschemernjak 77:7f227a4dffe6 297 #elif USE_TCC_TIMEOUT == 2
Helmut Tschemernjak 77:7f227a4dffe6 298 void TCC2_Handler()
Helmut Tschemernjak 77:7f227a4dffe6 299 #endif
Helmut Tschemernjak 77:7f227a4dffe6 300 {
Helmut Tschemernjak 77:7f227a4dffe6 301 Tcc *t = TCC_data[USE_TCC_TIMEOUT].tcc_ptr;
Helmut Tschemernjak 77:7f227a4dffe6 302 uint64_t nsecs = ns_getTicker();
Helmut Tschemernjak 77:7f227a4dffe6 303
Helmut Tschemernjak 77:7f227a4dffe6 304 /*
Helmut Tschemernjak 77:7f227a4dffe6 305 * Overflow means the max timer exeeded, we need restart the timer
Helmut Tschemernjak 77:7f227a4dffe6 306 * Interrupts and
Helmut Tschemernjak 77:7f227a4dffe6 307 */
Helmut Tschemernjak 77:7f227a4dffe6 308 if (t->INTFLAG.bit.OVF == 1) { // A overflow caused the interrupt
Helmut Tschemernjak 77:7f227a4dffe6 309 t->INTFLAG.bit.OVF = 1; // writing a one clears the flag ovf flag
Helmut Tschemernjak 77:7f227a4dffe6 310 }
Helmut Tschemernjak 77:7f227a4dffe6 311
Helmut Tschemernjak 77:7f227a4dffe6 312 if (t->INTFLAG.bit.MC0 == 1) { // A compare to cc0 caused the interrupt
Helmut Tschemernjak 77:7f227a4dffe6 313 //ser->print("MC0\r\n");
Helmut Tschemernjak 77:7f227a4dffe6 314 t->INTFLAG.bit.MC0 = 1; // writing a one clears the MCO (match capture) flag
Helmut Tschemernjak 77:7f227a4dffe6 315 }
Helmut Tschemernjak 77:7f227a4dffe6 316
Helmut Tschemernjak 77:7f227a4dffe6 317 t->CTRLA.reg &= ~TCC_CTRLA_ENABLE; // Disable TC
Helmut Tschemernjak 77:7f227a4dffe6 318 while (t->SYNCBUSY.bit.ENABLE == 1); // wait for sync
Helmut Tschemernjak 77:7f227a4dffe6 319
Helmut Tschemernjak 77:7f227a4dffe6 320 for (int i = 0; i < MAX_TIMEOUTS-1; i++) {
Helmut Tschemernjak 77:7f227a4dffe6 321 struct TimeoutVector *tvp = &TimeOuts[i];
Helmut Tschemernjak 77:7f227a4dffe6 322 if (tvp->timer && nsecs >= tvp->timer->_timeout) {
Helmut Tschemernjak 77:7f227a4dffe6 323 Timeout *saveTimer = tvp->timer;
Helmut Tschemernjak 77:7f227a4dffe6 324 tvp->timer = NULL;
Helmut Tschemernjak 77:7f227a4dffe6 325 Timeout::_irq_handler(saveTimer);
Helmut Tschemernjak 77:7f227a4dffe6 326 }
Helmut Tschemernjak 77:7f227a4dffe6 327 }
Helmut Tschemernjak 77:7f227a4dffe6 328 /*
Helmut Tschemernjak 77:7f227a4dffe6 329 * we need to restart the timer for remaining interrupts
Helmut Tschemernjak 77:7f227a4dffe6 330 * Another reason is that we stopped this counter, in case there are
Helmut Tschemernjak 77:7f227a4dffe6 331 * remaining counts, we need to re-schedule the counter.
Helmut Tschemernjak 77:7f227a4dffe6 332 */
Helmut Tschemernjak 77:7f227a4dffe6 333 Timeout::restart();
Helmut Tschemernjak 77:7f227a4dffe6 334 }
Helmut Tschemernjak 77:7f227a4dffe6 335
Helmut Tschemernjak 77:7f227a4dffe6 336
Helmut Tschemernjak 77:7f227a4dffe6 337 /* ----------------- D21 sleep() and deepsleep() code ----------------------*/
Helmut Tschemernjak 77:7f227a4dffe6 338
Helmut Tschemernjak 77:7f227a4dffe6 339 void sleep(void)
Helmut Tschemernjak 77:7f227a4dffe6 340 {
Helmut Tschemernjak 77:7f227a4dffe6 341 /*
Helmut Tschemernjak 77:7f227a4dffe6 342 * If we use the native USB port our Serial is SerialUSB
Helmut Tschemernjak 77:7f227a4dffe6 343 * and if the SerialUSB and connected we should
Helmut Tschemernjak 77:7f227a4dffe6 344 * not enter into sleep mode because this kills the Arduino USB emulation
Helmut Tschemernjak 77:7f227a4dffe6 345 */
Helmut Tschemernjak 77:7f227a4dffe6 346 if (ser && ser == (Stream *)&SerialUSB) {
Helmut Tschemernjak 77:7f227a4dffe6 347 __WFI();
Helmut Tschemernjak 77:7f227a4dffe6 348 return;
Helmut Tschemernjak 77:7f227a4dffe6 349 // USB->CTRLA.bit.ENABLE = 0;
Helmut Tschemernjak 77:7f227a4dffe6 350 // USB->HOST.CTRLA.reg = 0;
Helmut Tschemernjak 77:7f227a4dffe6 351 // USB->HOST.CTRLA.bit.ENABLE &= USB_CTRLA_ENABLE;
Helmut Tschemernjak 77:7f227a4dffe6 352 }
Helmut Tschemernjak 77:7f227a4dffe6 353
Helmut Tschemernjak 77:7f227a4dffe6 354
Helmut Tschemernjak 77:7f227a4dffe6 355 #if 1 // (SAMD20 || SAMD21)
Helmut Tschemernjak 77:7f227a4dffe6 356 /* Errata: Make sure that the Flash does not power all the way down
Helmut Tschemernjak 77:7f227a4dffe6 357 * when in sleep mode. */
Helmut Tschemernjak 77:7f227a4dffe6 358 NVMCTRL->CTRLB.bit.SLEEPPRM = NVMCTRL_CTRLB_SLEEPPRM_DISABLED_Val;
Helmut Tschemernjak 77:7f227a4dffe6 359 #endif
Helmut Tschemernjak 77:7f227a4dffe6 360 uint32_t saved_ms = ms_getTicker();
Helmut Tschemernjak 77:7f227a4dffe6 361 SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; // disbale SysTick
Helmut Tschemernjak 77:7f227a4dffe6 362
Helmut Tschemernjak 77:7f227a4dffe6 363 SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk; // clear deep sleep
Helmut Tschemernjak 77:7f227a4dffe6 364 PM->SLEEP.reg = 2; // SYSTEM_SLEEPMODE_IDLE_2 IDLE 2 sleep mode.
Helmut Tschemernjak 77:7f227a4dffe6 365
Helmut Tschemernjak 77:7f227a4dffe6 366 __DSB(); // ensures the completion of memory accesses
Helmut Tschemernjak 77:7f227a4dffe6 367 __WFI(); // wait for interrupt
Helmut Tschemernjak 77:7f227a4dffe6 368
Helmut Tschemernjak 77:7f227a4dffe6 369 int count = ms_getTicker() - saved_ms;
Helmut Tschemernjak 77:7f227a4dffe6 370 if (count > 0) { // update the Arduino Systicks
Helmut Tschemernjak 77:7f227a4dffe6 371 for (int i = 0; i < count; i++) {
Helmut Tschemernjak 77:7f227a4dffe6 372 SysTick_Handler();
Helmut Tschemernjak 77:7f227a4dffe6 373 }
Helmut Tschemernjak 77:7f227a4dffe6 374 }
Helmut Tschemernjak 77:7f227a4dffe6 375 SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; // enable SysTick
Helmut Tschemernjak 77:7f227a4dffe6 376 }
Helmut Tschemernjak 77:7f227a4dffe6 377
Helmut Tschemernjak 77:7f227a4dffe6 378 void deepsleep(void)
Helmut Tschemernjak 77:7f227a4dffe6 379 {
Helmut Tschemernjak 77:7f227a4dffe6 380 #if 1 // (SAMD20 || SAMD21)
Helmut Tschemernjak 77:7f227a4dffe6 381 /* Errata: Make sure that the Flash does not power all the way down
Helmut Tschemernjak 77:7f227a4dffe6 382 * when in sleep mode. */
Helmut Tschemernjak 77:7f227a4dffe6 383 NVMCTRL->CTRLB.bit.SLEEPPRM = NVMCTRL_CTRLB_SLEEPPRM_DISABLED_Val;
Helmut Tschemernjak 77:7f227a4dffe6 384 #endif
Helmut Tschemernjak 77:7f227a4dffe6 385
Helmut Tschemernjak 77:7f227a4dffe6 386 SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; // disbale SysTick
Helmut Tschemernjak 77:7f227a4dffe6 387
Helmut Tschemernjak 77:7f227a4dffe6 388 SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; // standby mode
Helmut Tschemernjak 77:7f227a4dffe6 389
Helmut Tschemernjak 77:7f227a4dffe6 390 __DSB(); // ensures the completion of memory accesses
Helmut Tschemernjak 77:7f227a4dffe6 391 __WFI(); // wait for interrupt
Helmut Tschemernjak 77:7f227a4dffe6 392
Helmut Tschemernjak 77:7f227a4dffe6 393 SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; // enable SysTick
Helmut Tschemernjak 77:7f227a4dffe6 394 }
Helmut Tschemernjak 77:7f227a4dffe6 395
Helmut Tschemernjak 77:7f227a4dffe6 396 #endif // D21 TCC Timer, sleep, etc-
Helmut Tschemernjak 77:7f227a4dffe6 397
Helmut Tschemernjak 77:7f227a4dffe6 398 #endif // ARDUINO