/**************************************************************************//** * @brief Energy Mode 3 demonstration, GPIO wake up - will restart application *****************************************************************************/ void Demo_EM3_GPIO(void) { /* Disable systick timer */ SysTick->CTRL = 0; /* Keep GPIO and EBI active, do not disable peripherals */ /* Disable LF peripherals */ CMU->LFACLKEN0 = 0x00000000; CMU->LFBCLKEN0 = 0x00000000; /* Enter Energy Mode 3 - wake up on GPIO interrupt */ /* Press AEM button again to read EFM, and then any PB/Joystick button */ EMU_EnterEM3(false); /* Setup SysTick Timer for 1 msec interrupts */ if (SysTick_Config(SystemCoreClockGet() / 1000)) while (1) ; /* Show LED pattern after wake up, to show we're alive */ while(1) { BSP_LedsSet(0xf00f); Delay(200); BSP_LedsSet(0x0ff0); Delay(200); } }
/*============================================================================== hal_delay_us() =============================================================================*/ void hal_delay_us( uint32_t i_delay ) { volatile int i = 0; uint32_t l_ticks = ((SystemCoreClockGet() / 1000000) * i_delay) / 10; for( i = 0; i < l_ticks; i++ ); } /* hal_delay_us() */
/***************************************************************************//** * @brief * Configure the SysTick for OS tick. * * @details * * @note * ******************************************************************************/ void SysTick_Configuration(void) { rt_uint32_t core_clock; rt_uint32_t cnts; core_clock = SystemCoreClockGet(); cnts = core_clock / RT_TICK_PER_SECOND; SysTick_Config(cnts); SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK); }
/**************************************************************************//** * @brief TFT initialize or reinitialize * Assumes EBI has been configured correctly in BSP_Init(BSP_INIT_DK_EBI) * * @param[in] tftInit Pointer to EBI TFT initialization structure * * @return true if we should redraw into buffer, false if BC has control * over display *****************************************************************************/ bool TFT_DirectInit(const EBI_TFTInit_TypeDef *tftInit) { bool ret; uint32_t i, freq; EMSTATUS stat; /* If we are in BC_UIF_AEM_EFM state, we can redraw graphics */ if (BSP_RegisterRead(&BC_REGISTER->UIF_AEM) == BC_UIF_AEM_EFM) { /* If we're not BC_ARB_CTRL_EBI state, we need to reconfigure display controller */ if ((BSP_RegisterRead(&BC_REGISTER->ARB_CTRL) != BC_ARB_CTRL_EBI) || runOnce) { /* Enable SSD2119 Serial Port Interface */ BSP_PeripheralAccess(BSP_TFT, true); /* Enable EBI mode of operation on SSD2119 controller */ BSP_DisplayControl(BSP_Display_EBI); BSP_DisplayControl(BSP_Display_ResetAssert); BSP_DisplayControl(BSP_Display_PowerDisable); freq = SystemCoreClockGet(); for (i = 0; i < (freq / 100); i++) { __NOP(); } /* Configure display for Direct Drive "Mode Generic" + 3-wire SPI mode */ BSP_DisplayControl(BSP_Display_ModeGeneric); BSP_DisplayControl(BSP_Display_PowerEnable); BSP_DisplayControl(BSP_Display_ResetRelease); /* Configure GPIO for EBI and TFT */ TFT_DirectGPIOConfig(); /* Initialize display */ stat = DMD_init(0); if (DMD_OK == stat) stat = DMD_selectFramebuffer((void*)EBI_BankAddress(EBI_BANK2)); if (DMD_OK != stat) while (1) ; /* Configure EBI TFT direct drive */ EBI_TFTInit(tftInit); runOnce = false; } ret = true; } else { ret = false; } return ret; }
/**************************************************************************//** * @brief * Set low frequency crystal oscillator clock frequency for target system. * * @note * This function is mainly provided for being able to handle target systems * with different HF crystal oscillator frequencies run-time. If used, it * should probably only be used once during system startup. * * @note * This is an EFM32 proprietary function, not part of the CMSIS definition. * * @param[in] freq * LFXO frequency in Hz used for target. *****************************************************************************/ void SystemLFXOClockSet(uint32_t freq) { /* External crystal oscillator present? */ #if (EFM32_LFXO_FREQ > 0) SystemLFXOClock = freq; /* Update core clock frequency if LFXO is used to clock core */ if (CMU->STATUS & CMU_STATUS_LFXOSEL) { /* The function will update the global variable */ SystemCoreClockGet(); } #else (void)freq; /* Unused parameter */ #endif }
/***************************************************************************//** * @brief * Enables the flash controller for writing. * @note * IMPORTANT: This function must be called before flash operations when * AUXHFRCO clock has been changed from default 14MHz band. * @note * This function calls SystemCoreClockGet in order to set the global variable * SystemCoreClock which is used in subseqent calls of MSC_WriteWord to make * sure the frequency is sufficiently high for flash operations. If the clock * frequency is changed then software is responsible for calling MSC_Init or * SystemCoreClockGet in order to set the SystemCoreClock variable to the * correct value. ******************************************************************************/ void MSC_Init(void) { #if defined( _MSC_TIMEBASE_MASK ) uint32_t freq, cycles; #endif /* Unlock the MSC */ MSC->LOCK = MSC_UNLOCK_CODE; /* Disable writing to the flash */ MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN; /* Call SystemCoreClockGet in order to set the global variable SystemCoreClock which is used in MSC_LoadWriteData to make sure the frequency is sufficiently high. If the clock frequency is changed then software is responsible for calling MSC_Init or SystemCoreClockGet in order to set the SystemCoreClock variable to the correct value. */ SystemCoreClockGet(); #if defined( _MSC_TIMEBASE_MASK ) /* Configure MSC->TIMEBASE according to selected frequency */ freq = CMU_ClockFreqGet(cmuClock_AUX); if (freq > 7000000) { /* Calculate number of clock cycles for 1us as base period */ freq = (freq * 11) / 10; cycles = (freq / 1000000) + 1; /* Configure clock cycles for flash timing */ MSC->TIMEBASE = (MSC->TIMEBASE & ~(_MSC_TIMEBASE_BASE_MASK | _MSC_TIMEBASE_PERIOD_MASK)) | MSC_TIMEBASE_PERIOD_1US | (cycles << _MSC_TIMEBASE_BASE_SHIFT); } else { /* Calculate number of clock cycles for 5us as base period */ freq = (freq * 5 * 11) / 10; cycles = (freq / 1000000) + 1; /* Configure clock cycles for flash timing */ MSC->TIMEBASE = (MSC->TIMEBASE & ~(_MSC_TIMEBASE_BASE_MASK | _MSC_TIMEBASE_PERIOD_MASK)) | MSC_TIMEBASE_PERIOD_5US | (cycles << _MSC_TIMEBASE_BASE_SHIFT); } #endif }
/**************************************************************************//** * @brief TFT initialize or reinitialize to Address Mapped Mode * Assumes EBI has been configured correctly in BSP_Init(BSP_INIT_DK_EBI) * * @return true if we should redraw into buffer, false if BC has control * over display *****************************************************************************/ bool TFT_AddressMappedInit(void) { bool ret; EMSTATUS status; uint32_t i, freq; /* If we are in BC_UIF_AEM_EFM state, we can redraw graphics */ if (BSP_RegisterRead(&BC_REGISTER->UIF_AEM) == BC_UIF_AEM_EFM) { /* If we're not BC_ARB_CTRL_EBI state, we need to reconfigure display controller */ if ((BSP_RegisterRead(&BC_REGISTER->ARB_CTRL) != BC_ARB_CTRL_EBI) || runOnce) { /* Configure for EBI mode and reset display */ BSP_DisplayControl(BSP_Display_EBI); BSP_DisplayControl(BSP_Display_ResetAssert); BSP_DisplayControl(BSP_Display_PowerDisable); /* Short reset delay */ freq = SystemCoreClockGet(); for (i = 0; i < (freq / 100); i++) { __NOP(); } /* Configure display for Direct Drive + SPI mode */ BSP_DisplayControl(BSP_Display_Mode8080); BSP_DisplayControl(BSP_Display_PowerEnable); BSP_DisplayControl(BSP_Display_ResetRelease); /* Initialize graphics - abort on failure */ status = DMDIF_init(BC_SSD2119_BASE, BC_SSD2119_BASE + 2); if (status == DMD_OK) status = DMD_init(0); if ((status != DMD_OK) && (status != DMD_ERROR_DRIVER_ALREADY_INITIALIZED)) while (1) ; /* Make sure display is configured with correct rotation */ if ((status == DMD_OK)) DMD_flipDisplay(1, 1); runOnce = false; } ret = true; } else { ret = false; } return ret; }
MSC_RAMFUNC_DEFINITION_END /* Undef the define from em_assert.h and redirect to local ramfunc version. */ #undef EFM_ASSERT #if defined(DEBUG_EFM) || defined(DEBUG_EFM_USER) #define EFM_ASSERT(expr) ((expr) ? ((void)0) : mscRfAssertEFM(__FILE__, __LINE__)) #else #define EFM_ASSERT(expr) ((void)(expr)) #endif /* defined(DEBUG_EFM) || defined(DEBUG_EFM_USER) */ #endif /* !EM_MSC_RUN_FROM_FLASH */ /** @endcond */ /***************************************************************************//** * @addtogroup emlib * @{ ******************************************************************************/ /***************************************************************************//** * @addtogroup MSC * @{ ******************************************************************************/ /******************************************************************************* ************************** GLOBAL FUNCTIONS ******************************* ******************************************************************************/ /***************************************************************************//** * @brief * Enables the flash controller for writing. * @note * This function must be called before flash operations when * AUXHFRCO clock has been changed from default band. * @note * This function calls SystemCoreClockGet in order to set the global variable * SystemCoreClock which is used in subseqent calls of MSC_WriteWord to make * sure the frequency is sufficiently high for flash operations. If the clock * frequency is changed then software is responsible for calling MSC_Init or * SystemCoreClockGet in order to set the SystemCoreClock variable to the * correct value. ******************************************************************************/ void MSC_Init(void) { #if defined( _MSC_TIMEBASE_MASK ) uint32_t freq, cycles; #endif #if defined( _EMU_STATUS_VSCALE_MASK ) /* VSCALE must be done and flash erase and write requires VSCALE2 */ EFM_ASSERT(!(EMU->STATUS & _EMU_STATUS_VSCALEBUSY_MASK)); EFM_ASSERT((EMU->STATUS & _EMU_STATUS_VSCALE_MASK) == EMU_STATUS_VSCALE_VSCALE2); #endif /* Unlock the MSC */ MSC->LOCK = MSC_UNLOCK_CODE; /* Disable writing to the flash */ MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN; /* Call SystemCoreClockGet in order to set the global variable SystemCoreClock which is used in MSC_LoadWriteData to make sure the frequency is sufficiently high. If the clock frequency is changed then software is responsible for calling MSC_Init or SystemCoreClockGet in order to set the SystemCoreClock variable to the correct value. */ SystemCoreClockGet(); #if defined( _MSC_TIMEBASE_MASK ) /* Configure MSC->TIMEBASE according to selected frequency */ freq = CMU_ClockFreqGet(cmuClock_AUX); /* Timebase 5us is used for the 1/1.2MHz band only. Note that the 1MHz band is tuned to 1.2MHz on newer revisions. */ if (freq > 1200000) { /* Calculate number of clock cycles for 1us as base period */ freq = (freq * 11) / 10; cycles = (freq / 1000000) + 1; /* Configure clock cycles for flash timing */ MSC->TIMEBASE = (MSC->TIMEBASE & ~(_MSC_TIMEBASE_BASE_MASK | _MSC_TIMEBASE_PERIOD_MASK)) | MSC_TIMEBASE_PERIOD_1US | (cycles << _MSC_TIMEBASE_BASE_SHIFT); } else { /* Calculate number of clock cycles for 5us as base period */ freq = (freq * 5 * 11) / 10; cycles = (freq / 1000000) + 1; /* Configure clock cycles for flash timing */ MSC->TIMEBASE = (MSC->TIMEBASE & ~(_MSC_TIMEBASE_BASE_MASK | _MSC_TIMEBASE_PERIOD_MASK)) | MSC_TIMEBASE_PERIOD_5US | (cycles << _MSC_TIMEBASE_BASE_SHIFT); } #endif }
/**************************************************************************//** * @brief Main function *****************************************************************************/ int main(void) { int value, delayCount = 0, hfrcoband = 0; float current, voltage; bool vboost; char buffer[8]; /* Chip errata */ CHIP_Init(); /* If first word of user data page is non-zero, enable eA Profiler trace */ BSP_TraceProfilerSetup(); /* Initialize board support package */ BSP_Init(BSP_INIT_BCC); /* Setup SysTick Timer for 1 msec interrupts */ if (SysTick_Config(SystemCoreClockGet() / 1000)) while (1) ; /* Initialize voltage comparator, to check supply voltage */ VDDCHECK_Init(); /* Check if voltage is below 3V, if so use voltage boost */ if (VDDCHECK_LowVoltage(2.9)) { vboost = true; } else { vboost = false; } /* Disable Voltage Comparator */ VDDCHECK_Disable(); /* Initialize segment LCD */ SegmentLCD_Init(vboost); /* Infinite loop */ while (1) { /* Read and display current */ current = BSP_CurrentGet(); value = (int)(1000 * current); /* Check that we fall within displayable value */ if ((value > 0) && (value < 10000)) { SegmentLCD_Number(value); } else { SegmentLCD_Number(-1); } /* Alternate between voltage and clock frequency */ if (((delayCount / 10) & 1) == 0) { voltage = BSP_VoltageGet(); value = (int)(voltage * 100); SegmentLCD_Symbol(LCD_SYMBOL_DP6, 1); sprintf(buffer, "Volt%3d", value); SegmentLCD_Write(buffer); } else { SegmentLCD_Symbol(LCD_SYMBOL_DP6, 0); sprintf(buffer, "%3u MHz", (int)(SystemCoreClockGet() / 1000000)); SegmentLCD_Write(buffer); } /* After 5 seconds, use another HFRCO band */ if (delayCount % 50 == 0) { switch (hfrcoband) { case 0: CMU_HFRCOBandSet(cmuHFRCOBand_11MHz); break; case 1: CMU_HFRCOBandSet(cmuHFRCOBand_14MHz); break; case 2: CMU_HFRCOBandSet(cmuHFRCOBand_21MHz); break; default: CMU_HFRCOBandSet(cmuHFRCOBand_28MHz); /* Restart iteartion */ hfrcoband = -1; break; } hfrcoband++; /* Recalculate delay tick count and baudrate generation */ if (SysTick_Config(SystemCoreClockGet() / 1000)) while (1) ; BSP_Init(BSP_INIT_BCC); } Delay(100); delayCount++; } }
__ramfunc #endif #endif /* !EM_MSC_RUN_FROM_FLASH */ __STATIC_INLINE MSC_Status_TypeDef MSC_LoadWriteData(uint32_t* data, uint32_t numWords, MSC_WriteStrategy_Typedef writeStrategy) { uint32_t timeOut; uint32_t wordIndex; uint32_t wordsPerDataPhase; MSC_Status_TypeDef retval = mscReturnOk; #if defined(_MSC_WRITECTRL_LPWRITE_MASK) && defined(_MSC_WRITECTRL_WDOUBLE_MASK) /* If LPWRITE (Low Power Write) is NOT enabled, set WDOUBLE (Write Double word) */ if (!(MSC->WRITECTRL & MSC_WRITECTRL_LPWRITE)) { /* If the number of words to be written are odd, we need to align by writing a single word first, before setting the WDOUBLE bit. */ if (numWords & 0x1) { /* Wait for the MSC to become ready for the next word. */ timeOut = MSC_PROGRAM_TIMEOUT; while ((!(MSC->STATUS & MSC_STATUS_WDATAREADY)) && (timeOut != 0)) { timeOut--; } /* Check for timeout */ if (timeOut == 0) { return mscReturnTimeOut; } /* Clear double word option, in order to write the initial single word. */ MSC->WRITECTRL &= ~MSC_WRITECTRL_WDOUBLE; /* Write first data word. */ MSC->WDATA = *data++; MSC->WRITECMD = MSC_WRITECMD_WRITEONCE; /* Wait for the operation to finish. It may be required to change the WDOUBLE config after the initial write. It should not be changed while BUSY. */ timeOut = MSC_PROGRAM_TIMEOUT; while((MSC->STATUS & MSC_STATUS_BUSY) && (timeOut != 0)) { timeOut--; } /* Check for timeout */ if (timeOut == 0) { return mscReturnTimeOut; } /* Subtract this initial odd word for the write loop below */ numWords -= 1; retval = mscReturnOk; } /* Now we can set the double word option in order to write two words per data phase. */ MSC->WRITECTRL |= MSC_WRITECTRL_WDOUBLE; wordsPerDataPhase = 2; } else #endif /* defined( _MSC_WRITECTRL_LPWRITE_MASK ) && defined( _MSC_WRITECTRL_WDOUBLE_MASK ) */ { wordsPerDataPhase = 1; } /* Write the rest as double word write if wordsPerDataPhase == 2 */ if (numWords > 0) { /**** Write strategy: mscWriteIntSafe ****/ if (writeStrategy == mscWriteIntSafe) { /* Requires a system core clock at 1MHz or higher */ EFM_ASSERT(SystemCoreClockGet() >= 1000000); wordIndex = 0; while(wordIndex < numWords) { MSC->WDATA = *data++; wordIndex++; if (wordsPerDataPhase == 2) { while (!(MSC->STATUS & MSC_STATUS_WDATAREADY)); MSC->WDATA = *data++; wordIndex++; } MSC->WRITECMD = MSC_WRITECMD_WRITEONCE; /* Wait for the transaction to finish. */ timeOut = MSC_PROGRAM_TIMEOUT; while ((MSC->STATUS & MSC_STATUS_BUSY) && (timeOut != 0)) { timeOut--; } /* Check for timeout */ if (timeOut == 0) { retval = mscReturnTimeOut; break; } #if defined( _EFM32_GECKO_FAMILY ) MSC->ADDRB += 4; MSC->WRITECMD = MSC_WRITECMD_LADDRIM; #endif } } /**** Write strategy: mscWriteFast ****/ else { #if defined( _EFM32_GECKO_FAMILY ) /* Gecko does not have auto-increment of ADDR. */ EFM_ASSERT(0); #else /* Requires a system core clock at 14MHz or higher */ EFM_ASSERT(SystemCoreClockGet() >= 14000000); wordIndex = 0; INT_Disable(); while(wordIndex < numWords) { /* Wait for the MSC to be ready for the next word. */ while (!(MSC->STATUS & MSC_STATUS_WDATAREADY)) { /* If the write to MSC->WDATA below missed the 30us timeout and the following MSC_WRITECMD_WRITETRIG command arrived while MSC_STATUS_BUSY is 1, then the MSC_WRITECMD_WRITETRIG could be ignored by the MSC. In this case, MSC_STATUS_WORDTIMEOUT is set to 1 and MSC_STATUS_BUSY is 0. A new trigger is therefore needed here to complete write of data in MSC->WDATA. If WDATAREADY became high since entry into this loop, exit and continue to the next WDATA write. */ if ((MSC->STATUS & (MSC_STATUS_WORDTIMEOUT | MSC_STATUS_BUSY | MSC_STATUS_WDATAREADY)) == MSC_STATUS_WORDTIMEOUT) { MSC->WRITECMD = MSC_WRITECMD_WRITETRIG; } } MSC->WDATA = *data; if ((wordsPerDataPhase == 1) || ((wordsPerDataPhase == 2) && (wordIndex & 0x1))) { MSC->WRITECMD = MSC_WRITECMD_WRITETRIG; } data++; wordIndex++; } INT_Enable(); /* Wait for the transaction to finish. */ timeOut = MSC_PROGRAM_TIMEOUT; while ((MSC->STATUS & MSC_STATUS_BUSY) && (timeOut != 0)) { timeOut--; } /* Check for timeout */ if (timeOut == 0) { retval = mscReturnTimeOut; } #endif } /* writeStrategy */ } #if defined( _MSC_WRITECTRL_WDOUBLE_MASK ) /* Clear double word option, which should not be left on when returning. */ MSC->WRITECTRL &= ~MSC_WRITECTRL_WDOUBLE; #endif return retval; }
/**************************************************************************//** * @brief Main function *****************************************************************************/ int main(void) { const int msDelay = 100; /* Chip errata */ CHIP_Init(); /* If first word of user data page is non-zero, enable eA Profiler trace */ BSP_TraceProfilerSetup(); /* Power down special RAM blocks to reduce current consumption with some nA. */ CMU_ClockEnable(cmuClock_CORELE, true); LESENSE->POWERDOWN = LESENSE_POWERDOWN_RAM; CMU_ClockEnable(cmuClock_CORELE, false); /* Configure push button interrupts */ gpioSetup(); /* Setup SysTick Timer for 1 msec interrupts */ if (SysTick_Config(SystemCoreClockGet() / 1000)) while (1) ; /* Initialize LCD controller */ SegmentLCD_Init(false); /* Run countdown for user to select energy mode */ msCountDown = 4000; /* milliseconds */ while (msCountDown > 0) { switch (eMode) { case 0: SegmentLCD_Write("EM0 32M"); break; case 1: SegmentLCD_Write("EM1 32M"); break; case 2: SegmentLCD_Write("EM2 32K"); break; case 3: SegmentLCD_Write("EM3"); break; case 4: SegmentLCD_Write("EM4"); break; case 5: SegmentLCD_Write("EM2+RTC"); break; case 6: SegmentLCD_Write("RTC+LCD"); break; case 7: SegmentLCD_Write("EM3+RTC"); break; case 8: SegmentLCD_Write("USER"); break; } SegmentLCD_Number(msCountDown); Delay(msDelay); msCountDown -= msDelay; } /* Disable components, reenable when needed */ SegmentLCD_Disable(); RTC_Enable(false); /* GPIO->ROUTE = 0x00000000; */ /* Go to energy mode and wait for reset */ switch (eMode) { case 0: /* Disable pin input */ GPIO_PinModeSet(gpioPortB, 10, gpioModeDisabled, 1); /* Disable systick timer */ SysTick->CTRL = 0; /* 32Mhz primes demo - running off HFXO */ CMU_ClockSelectSet(cmuClock_HF, cmuSelect_HFXO); /* Disable HFRCO, LFRCO and all unwanted clocks */ CMU->OSCENCMD = CMU_OSCENCMD_HFRCODIS; CMU->OSCENCMD = CMU_OSCENCMD_LFRCODIS; CMU->HFPERCLKEN0 = 0x00000000; CMU->HFCORECLKEN0 = 0x00000000; CMU->LFACLKEN0 = 0x00000000; CMU->LFBCLKEN0 = 0x00000000; CMU->LFCLKSEL = 0x00000000; /* Supress Conditional Branch Target Prefetch */ MSC->READCTRL = MSC_READCTRL_MODE_WS1SCBTP; { #define PRIM_NUMS 64 uint32_t i, d, n; uint32_t primes[PRIM_NUMS]; /* Find prime numbers forever */ while (1) { primes[0] = 1; for (i = 1; i < PRIM_NUMS;) { for (n = primes[i - 1] + 1;; n++) { for (d = 2; d <= n; d++) { if (n == d) { primes[i] = n; goto nexti; } if (n % d == 0) break; } } nexti: i++; } } } case 1: /* Disable pin input */ GPIO_PinModeSet(gpioPortB, 10, gpioModeDisabled, 1); /* Disable systick timer */ SysTick->CTRL = 0; CMU_ClockSelectSet(cmuClock_HF, cmuSelect_HFXO); /* Disable HFRCO, LFRCO and all unwanted clocks */ CMU->OSCENCMD = CMU_OSCENCMD_HFRCODIS; CMU->OSCENCMD = CMU_OSCENCMD_LFRCODIS; CMU->HFPERCLKEN0 = 0x00000000; CMU->HFCORECLKEN0 = 0x00000000; CMU->LFACLKEN0 = 0x00000000; CMU->LFBCLKEN0 = 0x00000000; CMU->LFCLKSEL = 0x00000000; EMU_EnterEM1(); break; case 2: /* Enable LFRCO */ CMU->OSCENCMD = CMU_OSCENCMD_LFRCOEN; /* Disable everything else */ CMU->OSCENCMD = CMU_OSCENCMD_LFXODIS; CMU->HFPERCLKEN0 = 0x00000000; CMU->HFCORECLKEN0 = 0x00000000; CMU->LFACLKEN0 = 0x00000000; CMU->LFBCLKEN0 = 0x00000000; /* Disable LFB clock select */ CMU->LFCLKSEL = 0x00000000; EMU_EnterEM2(false); break; case 3: /* Disable all clocks */ CMU->OSCENCMD = CMU_OSCENCMD_LFXODIS; CMU->OSCENCMD = CMU_OSCENCMD_LFRCODIS; CMU->HFPERCLKEN0 = 0x00000000; CMU->HFCORECLKEN0 = 0x00000000; CMU->LFACLKEN0 = 0x00000000; CMU->LFBCLKEN0 = 0x00000000; CMU->LFCLKSEL = 0x00000000; EMU_EnterEM3(false); break; case 4: /* Go straight down to EM4 */ EMU_EnterEM4(); break; case 5: /* EM2 + RTC - only briefly wake up to reconfigure every 2 seconds */ /* Disable LFB clock select */ CMU->LFCLKSEL &= ~(_CMU_LFCLKSEL_LFB_MASK); RTCDRV_Setup(cmuSelect_LFRCO, cmuClkDiv_32); while (1) { RTCDRV_Trigger(2000, NULL); EMU_EnterEM2(false); } case 6: /* EM2 + RTC + LCD (if battery slips below 3V vboost should be enabled) */ /* Disable LFB clock select */ CMU->LFCLKSEL &= ~(_CMU_LFCLKSEL_LFB_MASK); SegmentLCD_Init(false); RTCDRV_Setup(cmuSelect_LFRCO, cmuClkDiv_32); while (1) { SegmentLCD_Write("Silicon"); /* Sleep in EM2 */ RTCDRV_Trigger(2000, NULL); EMU_EnterEM2(false); SegmentLCD_Write(" Labs"); /* Sleep in EM2 */ RTCDRV_Trigger(2000, NULL); EMU_EnterEM2(false); } case 7: /* EM3 + RTC - only briefly wake up to reconfigure every ~5 seconds */ while (1) { /* Disable LFB clock select */ CMU->LFCLKSEL &= ~(_CMU_LFCLKSEL_LFB_MASK); /* This RTCDRV_Setup will configure LFCLK A as ULFRCO */ RTCDRV_Setup(cmuSelect_ULFRCO, cmuClkDiv_1); RTCDRV_Trigger(5000, NULL); /* Sleep in EM3, wake up on RTC trigger */ EMU_EnterEM3(false); /* SegmentLCD_Init will configure LFCLK A as LFRCO */ SegmentLCD_Init(false); SegmentLCD_Write("ULFRCO"); Delay(1000); SegmentLCD_Disable(); } case 8: default: /* User defined */ break; } return 0; }
/***************************************************************************//** * @brief * Initialize LCD device * * @details * * @note * ******************************************************************************/ void efm32_spiLcd_init(void) { struct efm32_usart_device_t *usart; rt_uint32_t flag; DMD_DisplayGeometry *geometry; rt_uint32_t ret; do { USART_InitSync_TypeDef init = USART_INITSYNC_DEFAULT; /* Find SPI device */ lcd = rt_device_find(LCD_USING_DEVICE_NAME); if (lcd == RT_NULL) { lcd_debug("LCD err: Can't find %s!\n", LCD_USING_DEVICE_NAME); break; } lcd_debug("LCD: Find device %s\n", LCD_USING_DEVICE_NAME); /* Config CS pin */ usart = (struct efm32_usart_device_t *)(lcd->user_data); if (!(usart->state & USART_STATE_AUTOCS)) { GPIO_PinModeSet(LCD_CS_PORT, LCD_CS_PIN, gpioModePushPull, 1); lcdAutoCs = false; } /* TFT initialize or reinitialize. Assumes EBI has been configured correctly in DVK_init(DVK_Init_EBI) */ rt_uint32_t freq = SystemCoreClockGet(); rt_uint32_t i; rt_bool_t warning = RT_FALSE; /* If we are in BC_UIF_AEM_EFM state, we can redraw graphics */ while (DVK_readRegister(&BC_REGISTER->UIF_AEM) != BC_UIF_AEM_EFM) { if (!warning) { lcd_debug("LCD: Please press AEM button!!!\n"); warning = RT_TRUE; } } lcd_debug("LCD: Got LCD control\n"); /* If we're not BC_ARB_CTRL_EBI state, we need to reconfigure display controller */ if (DVK_readRegister(&BC_REGISTER->ARB_CTRL) != BC_ARB_CTRL_EBI) { lcd_debug("LCD: Set to EBI mode\n"); /* Configure for EBI mode and reset display */ DVK_displayControl(DVK_Display_EBI); DVK_displayControl(DVK_Display_ResetAssert); DVK_displayControl(DVK_Display_PowerDisable); /* Short delay */ freq = SystemCoreClockGet(); for(i = 0; i < (freq / 100); i++) { __NOP(); } #if defined(LCD_MAPPED) /* Configure display for address mapped method + 3-wire SPI mode */ DVK_displayControl(DVK_Display_Mode8080); DVK_displayControl(DVK_Display_PowerEnable); DVK_displayControl(DVK_Display_ResetRelease); /* Initialize graphics - abort on failure */ ret = DMD_init(BC_SSD2119_BASE, BC_SSD2119_BASE + 2); if (ret == DMD_OK) { /* Make sure display is configured with correct rotation */ DMD_flipDisplay(1, 1); } else if (ret != DMD_ERROR_DRIVER_ALREADY_INITIALIZED) { lcd_debug("LCD err: driver init failed %x\n", ret); break; } #elif defined(LCD_DIRECT) /* Configure TFT direct drive method from EBI BANK2 */ const EBI_TFTInit_TypeDef tftInit = { ebiTFTBank2, /* Select EBI Bank 2 */ ebiTFTWidthHalfWord, /* Select 2-byte (16-bit RGB565) increments */ ebiTFTColorSrcMem, /* Use memory as source for mask/blending */ ebiTFTInterleaveUnlimited, /* Unlimited interleaved accesses */ ebiTFTFrameBufTriggerVSync, /* VSYNC as frame buffer update trigger */ false, /* Drive DCLK from negative edge of internal clock */ ebiTFTMBDisabled, /* No masking and alpha blending enabled */ ebiTFTDDModeExternal, /* Drive from external memory */ ebiActiveLow, /* CS Active Low polarity */ ebiActiveHigh, /* DCLK Active High polarity */ ebiActiveLow, /* DATAEN Active Low polarity */ ebiActiveLow, /* HSYNC Active Low polarity */ ebiActiveLow, /* VSYNC Active Low polarity */ 320, /* Horizontal size in pixels */ 1, /* Horizontal Front Porch */ 30, /* Horizontal Back Porch */ 2, /* Horizontal Synchronization Pulse Width */ 240, /* Vertical size in pixels */ 1, /* Vertical Front Porch */ 4, /* Vertical Back Porch */ 2, /* Vertical Synchronization Pulse Width */ 0x0000, /* Frame Address pointer offset to EBI memory base */ 4, /* DCLK Period */ 0, /* DCLK Start cycles */ 0, /* DCLK Setup cycles */ 0, /* DCLK Hold cycles */ }; DVK_enablePeripheral(DVK_TFT); /* Configure display for Direct Drive + 3-wire SPI mode */ DVK_displayControl(DVK_Display_ModeGeneric); DVK_displayControl(DVK_Display_PowerEnable); DVK_displayControl(DVK_Display_ResetRelease); /* Configure GPIO for EBI and TFT */ /* EBI TFT DCLK/Dot Clock */ GPIO_PinModeSet(gpioPortA, 8, gpioModePushPull, 0); /* EBI TFT DATAEN */ GPIO_PinModeSet(gpioPortA, 9, gpioModePushPull, 0); /* EBI TFT VSYNC */ GPIO_PinModeSet(gpioPortA, 10, gpioModePushPull, 0); /* EBI TFT HSYNC */ GPIO_PinModeSet(gpioPortA, 11, gpioModePushPull, 0); /* Initialize display */ DMD_init(0, (rt_uint32_t)EBI_BankAddress(EBI_BANK2)); /* Configure EBI TFT direct drive */ EBI_TFTInit(&tftInit); #endif } /* Get LCD geometry */ ret = DMD_getDisplayGeometry(&geometry); if (ret != DMD_OK) { lcd_debug("LCD err: get geometry failed!\n"); break; } /* Init LCD info */ flag = RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_DMA_TX; lcd_info.pixel_format = RTGRAPHIC_PIXEL_FORMAT_RGB565P; lcd_info.bits_per_pixel = 16; lcd_info.width = geometry->xSize; lcd_info.height = geometry->ySize; #if defined(LCD_MAPPED) lcd_info.framebuffer = RT_NULL; efm32_spiLcd_register(&lcd_device, LCD_DEVICE_NAME, flag, (void *)&lcd_ops); #elif defined(LCD_DIRECT) lcd_info.framebuffer = (rt_uint8_t *)EBI_BankAddress(EBI_BANK2); efm32_spiLcd_register(&lcd_device, LCD_DEVICE_NAME, flag, RT_NULL); #endif /* Set clipping area */ ret = DMD_setClippingArea(0, 0, geometry->xSize, geometry->ySize); if (ret != DMD_OK) { lcd_debug("LCD err: set clipping area failed!\n"); break; } /* Read device code */ rt_uint16_t code = 0xFFFF; #if defined(LCD_MAPPED) code = DMDIF_readDeviceCode(); #endif /* Set as rtgui graphic driver */ rtgui_graphic_set_device(&lcd_device); lcd_debug("LCD: H/W init OK!\n"); return; } while(0); lcd_debug("LCD err: H/W init failed!\n"); }
/**************************************************************************//** * @brief Main function *****************************************************************************/ int main(void) { int msCountDown; const int msDelay = 100; char displayString[8]; LCD_AnimInit_TypeDef anim = { true, 0x00, lcdAnimShiftNone, 0x03, lcdAnimShiftLeft, lcdAnimLogicOr }; LCD_FrameCountInit_TypeDef fc = { true, 2, /* Update each 2nd frame */ lcdFCPrescDiv1, }; /* Chip errata */ CHIP_Init(); /* If first word of user data page is non-zero, enable eA Profiler trace */ BSP_TraceProfilerSetup(); /* Configure push button interrupts */ gpioSetup(); /* Setup SysTick Timer for 1 msec interrupts */ if (SysTick_Config(SystemCoreClockGet() / 1000)) while (1) ; /* Initialize LCD controller */ SegmentLCD_Init(false); /* Run countdown for user to select energy mode */ msCountDown = 4000; /* milliseconds */ while(msCountDown > 0) { if ( eMode >=3 && eMode<=4) { sprintf(displayString, "EM%d", eMode); SegmentLCD_Write(displayString); } switch( eMode ) { case 0: SegmentLCD_Write("EM0 32M"); break; case 1: SegmentLCD_Write("EM1 32M"); break; case 2: SegmentLCD_Write("EM2 32K"); break; case 5: SegmentLCD_Write("EM2+RTC"); break; case 6: SegmentLCD_Write("RTC+LCD"); break; } SegmentLCD_Number(msCountDown); Delay(msDelay); msCountDown -= msDelay; } /* Disable components, reenable when needed */ SegmentLCD_Disable(); RTC_Enable(false); /* Go to energy mode and wait for reset */ switch(eMode) { case 0: /* Disable pin input */ GPIO_PinModeSet(gpioPortB, 10, gpioModeDisabled, 1); /* Disable systick timer */ SysTick->CTRL = 0; /* 32Mhz primes demo - running off HFXO */ CMU_ClockSelectSet(cmuClock_HF, cmuSelect_HFXO); /* Disable HFRCO, LFRCO and all unwanted clocks */ CMU->OSCENCMD = CMU_OSCENCMD_HFRCODIS; CMU->OSCENCMD = CMU_OSCENCMD_LFRCODIS; CMU->HFPERCLKEN0 = 0x00000000; CMU->HFCORECLKEN0 = 0x00000000; CMU->LFACLKEN0 = 0x00000000; CMU->LFBCLKEN0 = 0x00000000; CMU->LFCLKSEL = 0x00000000; /* Supress Conditional Branch Target Prefetch */ MSC->READCTRL = MSC_READCTRL_MODE_WS1SCBTP; { #define PRIM_NUMS 64 uint32_t i, d, n; uint32_t primes[PRIM_NUMS]; /* Find prime numbers forever */ while (1) { primes[0] = 1; for (i = 1; i < PRIM_NUMS;) { for (n = primes[i - 1] + 1; ;n++) { for (d = 2; d <= n; d++) { if (n == d) { primes[i] = n; goto nexti; } if (n%d == 0) break; } } nexti: i++; } } } case 1: /* Disable pin input */ GPIO_PinModeSet(gpioPortB, 10, gpioModeDisabled, 1); /* Disable systick timer */ SysTick->CTRL = 0; CMU_ClockSelectSet(cmuClock_HF, cmuSelect_HFXO); /* Disable HFRCO, LFRCO and all unwanted clocks */ CMU->OSCENCMD = CMU_OSCENCMD_HFRCODIS; CMU->OSCENCMD = CMU_OSCENCMD_LFRCODIS; CMU->HFPERCLKEN0 = 0x00000000; CMU->HFCORECLKEN0 = 0x00000000; CMU->LFACLKEN0 = 0x00000000; CMU->LFBCLKEN0 = 0x00000000; CMU->LFCLKSEL = 0x00000000; EMU_EnterEM1(); break; case 2: /* Enable LFRCO */ CMU->OSCENCMD = CMU_OSCENCMD_LFRCOEN; /* Disable everything else */ CMU->OSCENCMD = CMU_OSCENCMD_LFXODIS; CMU->HFPERCLKEN0 = 0x00000000; CMU->HFCORECLKEN0 = 0x00000000; CMU->LFACLKEN0 = 0x00000000; CMU->LFBCLKEN0 = 0x00000000; CMU->LFCLKSEL = 0x00000000; EMU_EnterEM2(false); break; case 3: /* Disable all clocks */ CMU->OSCENCMD = CMU_OSCENCMD_LFXODIS; CMU->OSCENCMD = CMU_OSCENCMD_LFRCODIS; CMU->HFPERCLKEN0 = 0x00000000; CMU->HFCORECLKEN0 = 0x00000000; CMU->LFACLKEN0 = 0x00000000; CMU->LFBCLKEN0 = 0x00000000; EMU_EnterEM3(false); break; case 4: EMU_EnterEM4(); break; case 5: /* EM2 + RTC - only briefly wake up to reconfigure each second */ CMU->LFCLKSEL = CMU_LFCLKSEL_LFA_LFRCO; while(1) { RTCDRV_Trigger(2000, NULL); EMU_EnterEM2(false); } case 6: default: /* EM2 + RTC + LCD (if battery slips below 3V vboost should be */ /* enabled) */ CMU->LFCLKSEL = CMU_LFCLKSEL_LFA_LFRCO; SegmentLCD_Init(false); /* Animate LCD */ LCD_FrameCountInit(&fc); LCD_AnimInit(&anim); while(1) { SegmentLCD_Write("Energy"); /* Sleep in EM2 */ RTCDRV_Trigger(2000,NULL); EMU_EnterEM2(false); SegmentLCD_Write("Micro"); /* Sleep in EM2 */ RTCDRV_Trigger(2000,NULL); EMU_EnterEM2(false); } } return 0; }