f
Embed:
(wiki syntax)
Show/hide line numbers
arduino-d21.cpp
00001 /* 00002 * The file is Licensed under the Apache License, Version 2.0 00003 * (c) 2017 Helmut Tschemernjak 00004 * 30826 Garbsen (Hannover) Germany 00005 */ 00006 00007 #ifdef ARDUINO 00008 00009 using namespace std; 00010 00011 #include "arduino-mbed.h" 00012 #include "arduino-util.h" 00013 00014 00015 00016 #if defined(__SAMD21G18A__) || defined(__SAMD21J18A__) 00017 /* 00018 * __SAMD21J18A__ is the SamD21 Explained Board 00019 * __SAMD21G18A__ is Genuino Zero-Board (compatible with the LoRa board) 00020 */ 00021 00022 int 00023 CPUID(uint8_t *buf, int maxSize, uint32_t xorval) 00024 { 00025 int f1 = 0x55d5f559; // D21 128-bit UUID, first 32 bit. 00026 int f2 = 0x55d5f515; // D21 128-bit UUID, next 96 bit. 00027 00028 if (maxSize >= 16 ) { 00029 int cnt = 0; 00030 int fa = f1 ^ xorval; 00031 uint32_t *first = (uint32_t *)fa; 00032 uint8_t *dst = (uint8_t *)first; 00033 for (int i = 0; i < (int)sizeof(uint32_t); i++) 00034 *buf++ = *dst++; 00035 cnt += 4; 00036 int fb = f2 ^ xorval; 00037 uint32_t *next = (uint32_t *)fb; 00038 dst = (uint8_t *)next; 00039 for (int i = 0; i < (int)sizeof(uint32_t)*3; i++) 00040 *buf++ = *dst++; 00041 cnt += 12; 00042 return cnt; 00043 } 00044 00045 return 0; 00046 } 00047 00048 /* 00049 * see tcc.h is automatically included from: 00050 * Arduino15/packages/arduino/tools/CMSIS-Atmel/1.1.0/CMSIS/ 00051 * Device/ATMEL/samd21/include/component/tcc.h 00052 * See also tcc.c (ASF/mbed, e.g. Tcc_get_count_value) 00053 */ 00054 static void initTimer(Tcc *t); 00055 static uint32_t getTimerCount(Tcc *t); 00056 00057 /* 00058 * The Atmel D21 has three TCC timer, other models have more. 00059 */ 00060 const struct TCC_config { 00061 Tcc *tcc_ptr; 00062 IRQn_Type tcc_irq; 00063 uint8_t nbits; 00064 } TCC_data[] { 00065 { TCC0, TCC0_IRQn, 24 }, 00066 { TCC1, TCC1_IRQn, 24 }, 00067 { TCC2, TCC2_IRQn, 16 }, 00068 { NULL, (IRQn_Type)NULL, 0 } 00069 }; 00070 00071 /* 00072 * We preferably use the TCC timers because it supports 24-bit counters 00073 * versus TC Timer which supports only 8 or 16 bit counters only. 00074 * TCC0/1/2 timer work on the D21 using Arduino Zero. 00075 */ 00076 #define USE_TCC_TIMEOUT 0 // 0=TCC0, 1=TTC1, 2=TTC2 (see TCC_data) 00077 #define USE_TCC_TICKER 1 00078 00079 00080 /* 00081 * every 21333 ns equals one tick (1/(48000000/1024)) // prescaler 1024, 48 MHz 00082 * every 61035 ns equals one tick (1/(32768/2)) // prescaler 2, 32 kHz 00083 * COUNT*DIVIDER*SECS until interrupt 00084 * CPU 48 MHz = (65536*1024)/1.398636s 00085 * RTC 32 kHz = (65536*2)/4.0s 00086 */ 00087 #define NS_PER_CLOCK_CPU 21333 // ns secs per clock 00088 #define NS_PER_CLOCK_RTC 61035 // ns secs per clock 00089 00090 #define NS_PER_CLOCK NS_PER_CLOCK_RTC 00091 00092 /* ----------------- TICKER TIMER CODE ----------------------*/ 00093 00094 /* 00095 * The global ns_counter contains the time in ns from the last time 00096 * the counter has been wrapped. It cannot be used directly because the 00097 * current counter has to be added fore using it. Use instead 00098 * ns_getTicker(), us_ ns_getTicker(), ms_getTicker() 00099 */ 00100 00101 uint64_t ticker_ns; 00102 static bool initTickerDone = false; 00103 00104 uint64_t ns_getTicker(void) 00105 { 00106 Tcc *t = TCC_data[USE_TCC_TICKER].tcc_ptr; 00107 if (!initTickerDone) { 00108 initTimer(t); 00109 initTickerDone = true; 00110 00111 // set counter top to max 16 bit for testing 00112 // t->PER.bit.PER = 0xffff; 00113 // while (t->SYNCBUSY.bit.PER == 1); // wait for sync 00114 00115 t->CTRLA.reg |= TCC_CTRLA_ENABLE ; // Enable TC 00116 while (t->SYNCBUSY.bit.ENABLE == 1); // wait for sync 00117 } 00118 00119 /* 00120 * if we are called from the interrupt level, the counter contains 00121 * somehow wrong data, therfore we needs to read it twice. 00122 * Another option was to add a little wait (loop 500x) 00123 * in the TCC_TIMEOUT interrupt handler. 00124 */ 00125 if (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) // check if we are in the interrupt 00126 getTimerCount(t); 00127 00128 uint64_t counter_us = (uint64_t)NS_PER_CLOCK * (uint64_t)getTimerCount(t); 00129 uint64_t ns = ticker_ns + counter_us; 00130 00131 return ns; 00132 } 00133 00134 #if USE_TCC_TICKER == 0 00135 void TCC0_Handler() 00136 #elif USE_TCC_TICKER == 1 00137 void TCC1_Handler() 00138 #elif USE_TCC_TICKER == 2 00139 void TCC2_Handler() 00140 #endif 00141 { 00142 Tcc *t = TCC_data[USE_TCC_TICKER].tcc_ptr; 00143 /* 00144 * Overflow means the timer top exeeded 00145 */ 00146 if (t->INTFLAG.bit.OVF == 1) { // A overflow caused the interrupt 00147 t->INTFLAG.bit.OVF = 1; // writing a one clears the flag ovf flag 00148 // ser->println("T_OVF"); 00149 00150 /* 00151 * reading the count once is needed, otherwise 00152 * it will not wrap correct. 00153 */ 00154 getTimerCount(t); 00155 00156 int bits = TCC_data[USE_TCC_TICKER].nbits; 00157 int maxCounts = (uint32_t)(1<<bits); 00158 00159 ticker_ns += (uint64_t)NS_PER_CLOCK * (uint64_t)maxCounts; 00160 } 00161 if (t->INTFLAG.bit.MC0 == 1) { // A compare to cc0 caused the interrupt 00162 t->INTFLAG.bit.MC0 = 1; // writing a one clears the MCO (match capture) flag 00163 // ser->println("T_MC0"); 00164 } 00165 } 00166 00167 /* ----------------- SUPPORT CODE FOR TCC TIMERS----------------------*/ 00168 00169 static bool initTimerDone = false; 00170 00171 static void initTimer(Tcc *t) 00172 { 00173 00174 /* 00175 * enable clock for TCC, see gclk.h 00176 * GCLK_CLKCTRL_GEN_GCLK0 for 48 Mhz CPU 00177 * GCLK_CLKCTRL_GEN_GCLK1 for 32k extern crystal XOSC32K (ifdef CRYSTALLESS) 00178 * GCLK_CLKCTRL_GEN_GCLK1 for 32k internal OSC32K 00179 * see Arduino: arduino/hardware/samd/1.6.15/cores/arduino/startup.c 00180 * Use TCC_CTRLA_PRESCALER_DIV1024 for for 48 Mhz clock 00181 * Use TCC_CTRLA_PRESCALER_DIV2 for 32k clock 00182 */ 00183 if (t == TCC0 || t == TCC1) { 00184 REG_GCLK_CLKCTRL = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK1 | GCLK_CLKCTRL_ID_TCC0_TCC1); 00185 } else if (t == TCC2) { 00186 REG_GCLK_CLKCTRL = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK1 | GCLK_CLKCTRL_ID_TCC2_TC3_Val); 00187 } 00188 while (GCLK->STATUS.bit.SYNCBUSY == 1); // wait for sync 00189 00190 t->CTRLA.reg &= ~TCC_CTRLA_ENABLE; // Disable TCC 00191 while (t->SYNCBUSY.bit.ENABLE == 1); // wait for sync 00192 00193 t->CTRLA.reg |= (TCC_CTRLA_PRESCALER_DIV2 | TCC_CTRLA_RUNSTDBY); // Set perscaler 00194 00195 t->WAVE.reg |= TCC_WAVE_WAVEGEN_NFRQ; // Set wave form configuration 00196 while (t->SYNCBUSY.bit.WAVE == 1); // wait for sync 00197 00198 t->PER.bit.PER = 0xffffff; // set counter top to max 24 bit 00199 while (t->SYNCBUSY.bit.PER == 1); // wait for sync 00200 00201 // the compare counter TC->CC[0].reg will be set in the startTimer 00202 // after the timeout calculation is known. 00203 00204 // Interrupts 00205 t->INTENSET.reg = 0; // disable all interrupts 00206 t->INTENSET.bit.OVF = 1; // enable overfollow 00207 t->INTENSET.bit.MC0 = 1; // enable compare match to CC0 00208 00209 const struct TCC_config *cp = &TCC_data[0]; 00210 while (cp->tcc_ptr) { 00211 if (cp->tcc_ptr == t) { 00212 NVIC_EnableIRQ(cp->tcc_irq); // Enable InterruptVector 00213 break; 00214 } 00215 cp++; 00216 } 00217 } 00218 00219 00220 #if 0 00221 // Atmel ASF Code 00222 static uint32_t getTimerCount(Tcc *t) 00223 { 00224 uint32_t last_cmd; 00225 /* Wait last command done */ 00226 do { 00227 while (t->SYNCBUSY.bit.CTRLB); /* Wait for sync */ 00228 00229 last_cmd = t->CTRLBSET.reg & TCC_CTRLBSET_CMD_Msk; 00230 if (TCC_CTRLBSET_CMD_NONE == last_cmd) { 00231 /* Issue read command and break */ 00232 t->CTRLBSET.bit.CMD = TCC_CTRLBSET_CMD_READSYNC_Val; 00233 break; 00234 } else if (TCC_CTRLBSET_CMD_READSYNC == last_cmd) { 00235 /* Command have been issued */ 00236 break; 00237 } 00238 } while (1); 00239 00240 while (t->SYNCBUSY.bit.COUNT); /* Wait for sync */ 00241 00242 return t->COUNT.reg; 00243 } 00244 #endif 00245 00246 00247 static uint32_t getTimerCount(Tcc *t) 00248 { 00249 00250 noInterrupts(); 00251 00252 while (t->SYNCBUSY.bit.CTRLB); /* Wait for sync */ 00253 00254 t->CTRLBSET.bit.CMD = TCC_CTRLBSET_CMD_READSYNC_Val; /* Issue read command and break */ 00255 00256 while (t->SYNCBUSY.bit.COUNT); /* Wait for sync */ 00257 00258 uint32_t count = t->COUNT.reg; 00259 00260 interrupts(); 00261 00262 return count; 00263 } 00264 00265 00266 Tcc *getTimeout_tcc(void) 00267 { 00268 return TCC_data[USE_TCC_TIMEOUT].tcc_ptr; 00269 } 00270 00271 00272 void stopTimer(Tcc *t) 00273 { 00274 t->CTRLA.reg &= ~TCC_CTRLA_ENABLE; // Disable TC 00275 while (t->SYNCBUSY.bit.ENABLE == 1); // wait for sync 00276 } 00277 00278 00279 /* ----------------- TIMEOUT TIMER CODE ----------------------*/ 00280 00281 void startTimer(Tcc *t, uint64_t delay_ns) 00282 { 00283 if (!initTimerDone) { 00284 initTimer(t); // initial setup with stopped timer 00285 initTimerDone = true; 00286 } 00287 00288 stopTimer(t); // avoid timer interrupts while calculating 00289 00290 /* 00291 * every 21333 ns equals one tick (1/(48000000/1024)) 00292 * COUNT*DIVIDER*SECS until interrupt 00293 * 48 Mhz = (65536*1024)/1.398636s 00294 */ 00295 uint64_t nclocks = (uint64_t)delay_ns; 00296 nclocks /= (uint64_t)NS_PER_CLOCK; 00297 int nCounts = nclocks; 00298 00299 int bits = TCC_data[USE_TCC_TIMEOUT].nbits; 00300 int maxCounts = (uint32_t)(1<<bits)-1; 00301 00302 if (nCounts > maxCounts) // if count exceeds timer capacity 00303 nCounts = maxCounts; // set the largest posible count. 00304 if (nCounts <= 0) 00305 nCounts = 1; 00306 t->CC[0].bit.CC = nCounts; 00307 while (t->SYNCBUSY.bit.CC0 == 1); // wait for sync 00308 00309 t->CTRLA.reg |= TCC_CTRLA_ENABLE ; // Enable TC 00310 while (t->SYNCBUSY.bit.ENABLE == 1); // wait for sync 00311 #if 0 00312 ser->print(ms_getTicker(), DEC); 00313 ser->print(" startTimer: nCounts="); 00314 ser->println(nCounts, DEC); 00315 #endif 00316 } 00317 00318 00319 #if USE_TCC_TIMEOUT == 0 00320 void TCC0_Handler() 00321 #elif USE_TCC_TIMEOUT == 1 00322 void TCC1_Handler() 00323 #elif USE_TCC_TIMEOUT == 2 00324 void TCC2_Handler() 00325 #endif 00326 { 00327 Tcc *t = TCC_data[USE_TCC_TIMEOUT].tcc_ptr; 00328 uint64_t nsecs = ns_getTicker(); 00329 00330 /* 00331 * Overflow means the max timer exeeded, we need restart the timer 00332 * Interrupts and 00333 */ 00334 if (t->INTFLAG.bit.OVF == 1) { // A overflow caused the interrupt 00335 t->INTFLAG.bit.OVF = 1; // writing a one clears the flag ovf flag 00336 } 00337 00338 if (t->INTFLAG.bit.MC0 == 1) { // A compare to cc0 caused the interrupt 00339 //ser->print("MC0\r\n"); 00340 t->INTFLAG.bit.MC0 = 1; // writing a one clears the MCO (match capture) flag 00341 } 00342 00343 t->CTRLA.reg &= ~TCC_CTRLA_ENABLE; // Disable TC 00344 while (t->SYNCBUSY.bit.ENABLE == 1); // wait for sync 00345 00346 for (int i = 0; i < MAX_TIMEOUTS-1; i++) { 00347 struct TimeoutVector *tvp = &TimeOuts[i]; 00348 if (tvp->timer && nsecs >= tvp->timer->_timeout) { 00349 Timeout *saveTimer = tvp->timer; 00350 tvp->timer = NULL; 00351 Timeout::_irq_handler(saveTimer); 00352 } 00353 } 00354 /* 00355 * we need to restart the timer for remaining interrupts 00356 * Another reason is that we stopped this counter, in case there are 00357 * remaining counts, we need to re-schedule the counter. 00358 */ 00359 Timeout::restart(); 00360 } 00361 00362 00363 /* ----------------- D21 sleep() and deepsleep() code ----------------------*/ 00364 00365 void sleep(void) 00366 { 00367 /* 00368 * If we use the native USB port our Serial is SerialUSB 00369 * and if the SerialUSB and connected we should 00370 * not enter into sleep mode because this kills the Arduino USB emulation 00371 */ 00372 SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; // disbale SysTick 00373 uint32_t saved_ms = ms_getTicker(); 00374 00375 if (SerialUSB_active) { 00376 __DSB(); // ensures the completion of memory accesses 00377 __WFI(); // wait for interrupt 00378 } else { 00379 #if 0 // (SAMD20 || SAMD21) 00380 /* Errata: Make sure that the Flash does not power all the way down 00381 * when in sleep mode. */ 00382 NVMCTRL->CTRLB.bit.SLEEPPRM = NVMCTRL_CTRLB_SLEEPPRM_DISABLED_Val; 00383 #endif 00384 00385 SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk; // clear deep sleep 00386 PM->SLEEP.reg = 2; // SYSTEM_SLEEPMODE_IDLE_2 IDLE 2 sleep mode. 00387 00388 __DSB(); // ensures the completion of memory accesses 00389 __WFI(); // wait for interrupt 00390 } 00391 00392 int count = ms_getTicker() - saved_ms; 00393 if (count > 0) { // update the Arduino Systicks 00394 for (int i = 0; i < count; i++) { 00395 SysTick_Handler(); 00396 } 00397 } 00398 SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; // enable SysTick 00399 } 00400 00401 /* 00402 * TODO 00403 * Check if we need to disable the USB GCLK->CLKCTRL.reg (see USBCore.cpp) 00404 * Check what else we need to disable? 00405 */ 00406 00407 void deepsleep(void) 00408 { 00409 #if 0 // (SAMD20 || SAMD21) 00410 /* Errata: Make sure that the Flash does not power all the way down 00411 * when in sleep mode. */ 00412 NVMCTRL->CTRLB.bit.SLEEPPRM = NVMCTRL_CTRLB_SLEEPPRM_DISABLED_Val; 00413 #endif 00414 00415 SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; // standby mode 00416 //EIC->WAKEUP.bit.WAKEUPEN3 = 1; // enable wakeup on Pin 12/PA19/EXTINT[3] see variants.h 00417 00418 __DSB(); // ensures the completion of memory accesses 00419 __WFI(); // wait for interrupt 00420 } 00421 00422 #endif // D21 TCC Timer, sleep, etc- 00423 00424 #endif // ARDUINO
Generated on Tue Jul 12 2022 21:55:12 by 1.7.2