test

Dependents:   Telemetria_RX_SD_GPS_copy Telemetria_RX_SD_GPS Telemetria_TX Telemetria_TX ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers arduino-d21.cpp Source File

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