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:
Sun Nov 19 17:51:27 2017 +0100
Revision:
101:50377edb21c6
Parent:
97:3d5d489206aa
Child:
105:6e6d141c3da8
Added a feature to preset the ns_ticker start value

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