This is code is part of a Technion course project in advanced IoT, implementing a device to read and transmit sensors data from a Formula racing car built by students at Technion - Israel Institute of Technology.

Dependencies:   mbed Buffer

Fork of DISCO-L072CZ-LRWAN1_LoRa_PingPong by ST

This is code is part of a Technion course project in advanced IoT, implementing a device to read and transmit sensors data from a Formula racing car built by students at Technion - Israel Institute of Technology.

How to install

  • Create an account on Mbed: https://os.mbed.com/account/signup/
  • Import project into Compiler
  • In the Program Workspace select "Formula_Nucleo_Reader"
  • Select a Platform like so:
  1. Click button at top-left
  2. Add Board
  3. Search "B-L072Z-LRWAN1" and then "Add to your Mbed Compiler"
  • Finally click "Compile", if the build was successful, the binary would download automatically
  • To install it on device simply plug it in to a PC, open device drive and drag then drop binary file in it
Committer:
wardm
Date:
Sat May 19 11:41:10 2018 +0000
Revision:
12:02d779e8c4f6
Code for Technion Formula car sensors reader transmit

Who changed what in which revision?

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