Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of DISCO-L072CZ-LRWAN1_LoRa_PingPong by
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 Wed Jul 13 2022 21:19:47 by
1.7.2
