// D režim spánku SLEEP s buzením libovolným přerušení bez povolení v NVIC (a bez rutiny IRQ) #include "stm32f0xx.h" // výstupy pro LEDku #define TEST_H GPIOA->BSRR = GPIO_Pin_5 #define TEST_L GPIOA->BRR = GPIO_Pin_5 void _delay_ms(uint32_t Delay); void init_test_output(void); void pull_unused_gpio(void); void init_exti(void); void clock_48(void); void clock_8(void); void clock_1(void); void clock_31k(void); int main(void){ clock_48(); // pracujeme například s 8MHz clockem pull_unused_gpio(); // ošetřit nevyužité GPIO init_test_output(); // PA5 jako výstup na LED init_exti(); // PA0 jako vstup NVIC_SystemLPConfig(NVIC_LP_SEVONPEND, ENABLE); // budit jakýmkoli přerušením while (1){ PWR_EnterSleepMode(PWR_SLEEPEntry_WFE); // Spi dokud nepřijde přerušení // tady by bylo na místě zkontrlovat si která periferie nás probudila ! // já ale vím že to bylo EXTI0 (jiný event jsem nepovolil) TEST_H; _delay_ms(500); TEST_L; EXTI_ClearITPendingBit(EXTI_Line0); // vymažu vlajku v periferii NVIC_ClearPendingIRQ(EXTI0_1_IRQn); // vymazat vlajku i v NVIC } } // EXTI z PA0 bude sloužit k buzení z režimů spánku // Na PA0 připojeno tlačítko proti VCC (interní pull down) void init_exti(void){ EXTI_InitTypeDef exti; GPIO_InitTypeDef gp; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); // kvůli PA0 RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); // kvůli EXTI // PA0 jako vstup s pull-down gp.GPIO_Pin = GPIO_Pin_0; gp.GPIO_Mode = GPIO_Mode_IN; gp.GPIO_OType = GPIO_OType_PP; gp.GPIO_PuPd = GPIO_PuPd_DOWN; gp.GPIO_Speed = GPIO_Speed_Level_1; GPIO_Init(GPIOA, &gp); // Přiřadíme Lince 0 port GPIOA (tedy mapujeme pin PA0) SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0); // povolíme externí přerušení z Linky 0 na vzestupnou hranu exti.EXTI_Line = EXTI_Line0; exti.EXTI_Mode=EXTI_Mode_Interrupt; exti.EXTI_Trigger=EXTI_Trigger_Rising; exti.EXTI_LineCmd=ENABLE; EXTI_Init(&exti); // vůbec nepovolujeme EXTI v NVIC } // PA5 je indikační výstup (k ověření že čip žije a pracuje) void init_test_output(void){ GPIO_InitTypeDef gp; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); gp.GPIO_Pin = GPIO_Pin_5; gp.GPIO_Mode = GPIO_Mode_OUT; gp.GPIO_OType = GPIO_OType_PP; gp.GPIO_PuPd = GPIO_PuPd_NOPULL; gp.GPIO_Speed = GPIO_Speed_Level_1; GPIO_Init(GPIOA, &gp); } void pull_unused_gpio(void){ GPIO_InitTypeDef gp; // nastavíme všem pinům že jsou to vstupy s pull-down rezistorem // ponecháme si jen konfiguraci pinů SWD, které mají interní pullup/pulldown rezistory // na našem čipu jsou jen GPIOA,GPIOB a GPIOF RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOB | RCC_AHBPeriph_GPIOF, ENABLE); gp.GPIO_Pin = GPIO_Pin_All; gp.GPIO_Mode = GPIO_Mode_IN; gp.GPIO_OType = GPIO_OType_PP; gp.GPIO_PuPd = GPIO_PuPd_DOWN; gp.GPIO_Speed = GPIO_Speed_Level_1; GPIO_Init(GPIOB, &gp); GPIO_Init(GPIOF, &gp); gp.GPIO_Pin = GPIO_Pin_All & (~(GPIO_Pin_13 | GPIO_Pin_14)); GPIO_Init(GPIOA, &gp); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOB | RCC_AHBPeriph_GPIOF, DISABLE); } void clock_48(void){ RCC_PLLConfig(RCC_PLLSource_HSI,RCC_PLLMul_12); // nastavit PLL na násobení 12x (8MHz / 2 * 12 = 48MHz) RCC_PLLCmd(ENABLE); // spustit PLL while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) != SET); // počkat na rozběh PLL RCC_HCLKConfig(RCC_SYSCLK_Div1); // SYSCLK z PLL nijak nedělit RCC_PCLKConfig(RCC_HCLK_Div1); // HCLK ze SYSCLK nijak nedělit (jedeme naplno) RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); // přepnout SYSCLK na PLL (jedeme na 48MHz) //SystemCoreClockUpdate(); // 0.14kB zbytečně... SystemCoreClock = 48000000; // clock je 48MHz } void clock_8(void){ RCC_HCLKConfig(RCC_SYSCLK_Div1); // SYSCLK nijak nedělit RCC_PCLKConfig(RCC_HCLK_Div1); // HCLK ze SYSCLK nijak nedělit (periferiím stejný takt jako jádru) RCC_SYSCLKConfig(RCC_SYSCLKSource_HSI); // zdrojem clocku je 8MHz HSI SystemCoreClock = 8000000; // clock je 8MHz } void clock_1(void){ RCC_HCLKConfig(RCC_SYSCLK_Div8); // SYSCLK dělit 8 => jádro jede na 1MHz... RCC_PCLKConfig(RCC_HCLK_Div1); // ...periferiím stejný takt jako jádru RCC_SYSCLKConfig(RCC_SYSCLKSource_HSI); // zdrojem clocku je 8MHz HSI SystemCoreClock = 1000000; // clock je 1MHz } void clock_31k(void){ RCC_HCLKConfig(RCC_SYSCLK_Div256); // SYSCLK dělit 256 => jádro jede na 31.25kHz... RCC_PCLKConfig(RCC_HCLK_Div1); // ...periferiím stejný takt jako jádru RCC_SYSCLKConfig(RCC_SYSCLKSource_HSI); // zdrojem clocku je 8MHz HSI SystemCoreClock = 31250; // clock je 31.25kHz } // Delay na bázi systicku (vyžaduje korektní nastavení SystemCoreClock) void _delay_ms(uint32_t Delay){ __IO uint32_t tmp = SysTick->CTRL; // Clear the COUNTFLAG first ((void)tmp); // init systick to us delays ... SysTick->LOAD = (SystemCoreClock/1000)-1; // 1us time SysTick->VAL = 0UL; SysTick->CTRL = SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_CLKSOURCE_Msk; if(Delay < 0xffffff){Delay++;} // Add a period to guaranty minimum wait while (Delay){ if((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) != 0U){Delay--;} } }