/******************************************************************************* MODULE : main.c Simple scheduler. Wakes up about every 1ms by RTCC (0.976ms). When RTCC is running by internal LFRCO some jitter and inaccuracy is to be expected. From main loop tasks can be called every about 5ms, 10ms, 25ms.... Additionally iTask1s is set every 1s (RTC accuracy) for time keeping. After all tasks are completed EFM32 is switched to EM2 to minimize energy consumption. LED lits whenever core is out of EM2. When some pheriperal needs HFCLK switching to EM2 can be prohbited by signaling via f.i. TraceIsRunning(). In this case core is switched to EM1 instead. Core is woken up by RTCC interrupt or any other interrupt. 201xxxxx AB Initial 20150407 AB Adapted for USV_BatteryMonitor Slave, remove LEDs and Testpins. 20191212 AB JADE EFM32JG1B test, TRACE now needs HFCLK. RTCC instead RTC. *******************************************************************************/ #define LOGGING_TOKEN MAI_LOGGING #include "TraceLeUart.h" #include #include "em_chip.h" #include "em_cmu.h" #include "em_emu.h" #include "em_adc.h" #include "em_device.h" #include "em_gpio.h" #include "em_ldma.h" #include "em_prs.h" #include "em_rtcc.h" #include "command.h" #include "types.h" #include "adc.h" #include "leds.h" /* Defines for RTCC */ #define RTCC_WAKEUP_MS 1 #define RTCC_WAKEUP_COUNT (((32768 * RTCC_WAKEUP_MS) / 1000) - 1) #define TESTPIN_INIT(); { GPIO_PinModeSet(gpioPortD, 15, gpioModePushPull, 0);} #define TESTPIN( x ) { if ( x ) GPIO->P[gpioPortD].DOUT |= 1 << 15; else GPIO->P[gpioPortD].DOUT &= ~(1 << 15); } // --- PUBLIC Variables ------------------------------------------------------- extern int _STACK_START; extern int _STACK_END; // --- Variables -------------------------------------------------------------- uint32_t rtccFlag; static int iMsTicks = 0; // for counting real seconds static int iTaskTicks = 0; // for counting various tasks static int iTask5ms = 0; static int iTask10ms = 0; static int iTask25ms = 0; static int iTask50ms = 0; static int iTask100ms = 0; static int iTask200ms = 0; static int iTask500ms = 0; static int iTask1s = 0; static int iTaskClock1s = 0; // real seconds task /*static int iSec = 0; static int iMin = 0; static int iHours = 0; static int iDays = 0; static uint32_t Seconds = 0; // counts seconds from boot, wraps around in >130 years */ // --- Macros ----------------------------------------------------------------- // --- Functionprototypes ----------------------------------------------------- void RtcInit(void); /**************************************************************************//** * @brief Main function *****************************************************************************/ int main(void) { int Seconds = 0; /* Chip errata */ CHIP_Init(); TESTPIN_INIT(); TESTPIN(ON); LedInit(); /* // LFRCO Clock Output on Pin PD9 // only series 2 CMU_ClkOutPinConfig(0, cmuSelect_LFRCO, 1, gpioPortD, 9); CMU->CTRL = (CMU->CTRL | CMU_CTRL_CLKOUTSEL0_LFRCO); CMU->ROUTEPEN = (CMU->ROUTEPEN | 1 ); // CLKOUT0PEN CMU->ROUTELOC0 = (CMU->ROUTELOC0 | 4 ); // LOC4 CMU_ClockEnable(cmuClock_GPIO, true); // Enable GPIO clock GPIO_PinModeSet(gpioPortD, 9, gpioModePushPull, 1); */ RtcInit(); TraceInit(); TraceInit2(); CommandInit(); AdcInit(); while (1) { TESTPIN(OFF); // switch to EM2 except some module needs HFCLK __disable_irq(); // __asm("CPSID i"); if ( TraceIsRunning() /* | AdcIsRunning() */ ) { // if some module needs HFCLK switch to EM1 instead EM2 EMU_EnterEM1(); __enable_irq(); // __asm("CPSIE i"); } else {// go to EM2 LedOff(2); EMU_EnterEM2(true); __enable_irq(); // __asm("CPSIE i"); LedOn(2); // superflous here cause should be done in every IRQ handler } if ( iTask5ms ) { iTask5ms = FALSE; // tasks to be done every 5 milliseconds } if ( iTask10ms ) { iTask10ms = FALSE; // tasks to be done every 10 milliseconds LedOff(0); // switch of LED (was switched on in Task1s) } if ( iTask25ms ) { iTask25ms = FALSE; // tasks to be done every 25 milliseconds } if ( iTask50ms ) { iTask50ms = FALSE; // tasks to be done every 50 milliseconds AdcTicker50ms(); } if ( iTask100ms ) { iTask100ms = FALSE; // tasks to be done every 100 milliseconds AdcTicker100ms(); } if ( iTask200ms ) { iTask200ms = FALSE; // tasks to be done every 200 milliseconds AdcTicker200ms(); CommandProcessing(); } if ( iTask500ms ) { iTask500ms = FALSE; // tasks to be done every 500 milliseconds } if ( iTask1s ) { iTask1s = FALSE; // tasks to be be done every second (about) LedOn(0); // switch on LED once a second (alive) AdcTicker1s(); } if ( iTaskClock1s ) { iTaskClock1s = FALSE; // tasks to be done every real second // MaiUptimeInc(); Seconds++; // overflow in 136 years TraceTicker1s(); } } } /**************************************************************************//** * @brief Setup RTC *****************************************************************************/ void RtcInit(void) { RTCC_Init_TypeDef rtcc = RTCC_INIT_DEFAULT; // Configure the compare settings RTCC_CCChConf_TypeDef compare = RTCC_CH_INIT_COMPARE_DEFAULT; /* Enabling clock to the interface of the low energy modules */ CMU_ClockEnable(cmuClock_CORELE, true); /* Routing the LFRCO clock to the RTC */ CMU_ClockSelectSet(cmuClock_LFE, cmuSelect_LFRCO); CMU_ClockEnable(cmuClock_RTCC, true); // Configure the RTCC settings rtcc.enable = false; rtcc.presc = rtccCntPresc_1; rtcc.cntMode = _RTCC_CTRL_CNTMODE_NORMAL; rtcc.cntWrapOnCCV1 = true; /* Initialize the RTCC */ RTCC_Init(&rtcc); // Initialise RTCC compare with a date, the date when interrupt will occur RTCC_ChannelInit(1, &compare); RTCC_ChannelCompareValueSet(1, (((32768 * RTCC_WAKEUP_MS) / 1000) - 1) ); // Set channel 1 to cause an interrupt RTCC_IntEnable(RTCC_IEN_CC1); NVIC_SetPriority(RTCC_IRQn, 7); NVIC_ClearPendingIRQ(RTCC_IRQn); NVIC_EnableIRQ(RTCC_IRQn); // Start counter after all initialisations are complete RTCC_Enable(true); /* Setting up RTC for about 1ms */ // - 1 is needed for 32 count cycles => 0.9765625ms // let it run for 33 counts (without - 1) gives 1.007080078ms // ToDo: RTC_CompareSet(0, (RTC_FREQ / 1000) - 1); // wait for sync // while ( RTC->SYNCBUSY ) ; } /****************************************************************************** void RTC_IRQHandler(void) Called every ~976us. Set flags for various periodically tasks. Times are multiples of 976us so iTask50ms is set every ~48.828ms and iTask1s every 0.97656s. In addition iTaskClock1s is set every real seconds. ToDo: Check if still true with JADE RTCC ******************************************************************************/ //void RTC_IRQHandler(void) void RTCC_IRQHandler(void) { LedOn(2); // Read the interrupt source rtccFlag = RTCC_IntGet(); // Clear interrupt flag RTCC_IntClear(rtccFlag); iTaskTicks++; // prevent iTaskTicks overflow as this will produce glitches if ( iTaskTicks > 2147482999 ) // wraps around every 2199028s = 610.84h = 25 days { // then there's a little error for iTaskClock1s iTaskTicks = 1000; } if ( (iTaskTicks % 5) == 0 ) iTask5ms = TRUE; if ( (iTaskTicks % 10) == 0 ) iTask10ms = TRUE; if ( (iTaskTicks % 25) == 0 ) iTask25ms = TRUE; if ( (iTaskTicks % 50) == 0 ) iTask50ms = TRUE; if ( (iTaskTicks % 100) == 0 ) iTask100ms = TRUE; if ( (iTaskTicks % 200) == 0 ) iTask200ms = TRUE; if ( (iTaskTicks % 500) == 0 ) iTask500ms = TRUE; if ( (iTaskTicks % 1000) == 0 ) iTask1s = TRUE; // for counting real seconds iMsTicks++; if ( (iMsTicks % 1024) == 0 ) iTaskClock1s = TRUE; } /****************************************************************************** int StackCheck (void) Checks max usage of stack, searches from STACK_END upwards till other than initial value is found INITIALIZE_STACK must be defined for thumb_crt0.s in order to enable stack checking. ..\..\System\thumb_crt0.s is a modified version of Rowleys Returns unused bytes on stack left or -1 in case of error ******************************************************************************/ int StackCheck (void) { int i; BYTE *pB; // _STACK_START and _STACK_END is reversed in startup code pB = (BYTE *) _STACK_START; TRACE_L3("MAI: stack from 0x%0X to 0x%0X (%d bytes)", _STACK_END, _STACK_START, _STACK_END - _STACK_START); if (_STACK_START == _STACK_END) { TRACE_L2("MAI: stack not initialized, unable to perform stack check"); return -1; } for (i = 0; i < _STACK_END - _STACK_START; i++, pB++) { if (*pB != 0xCC) { TRACE_L3("MAI: stack - %d bytes free", i ); return i; } } return -1; }