MARM M. Suchenek Laboratorium 1 system zegarów, porty wejścia/wyjścia Celem laboratorium jest zapoznanie się ze środowiskiem uruchomieniowym Keil µvision, w tym konfiguracja środowiska, systemu zegarów, portów wejścia/wyjścia. Strukturę systemu zegarów mikrokontrolera STM32F411 przedstawia diagram: 1
1. Konfigurację systemu zegarów Konfigurację systemu zegarów należy rozpocząć od inicjalizacji wartości domyślnych dla systemu zegarów funkcją: void RCC_DeInit(void) Ustawia ona: HSI włączone HSE, PLL wyłączone wyjścia MOC1-2 wyłączone, nie zmienia ustawień dla LSE i LSI. Następnie wybrać należy odpowiednie źródła zegara dla mikrokontrolera, to jest przynajmniej jeden z zegarów: HSE, HSI, LSE, LSI. Konfiguracja zewnętrznego źródła zegara HSE: RCC_HSEConfig(uint32_t RCC_HSE) parametry wejściowe: RCC_HSE_ON/RCC_HSE_OFF włącza/wyłącza zewnętrzny oscylator RCC_HSE_Bypass pozwala podać zewnętrzny zegar na wejście HSE Funkcja czeka na włączenie zegara HSE ErrorStatus RCC_WaitForHSEStartUp(void), funkcja zwraca: SUCCESS oscylator HSE jest stabilny i gotowy ERROR nie jest gotowy Włączenie/wyłączenie szybkiego wbudowanego zegara HSI: void RCC_HSICmd(FunctionalState NewState), parametr wejściowy przyjmuje wartości: ENABLE bądź DISABLE kalibracja wewnętrznego źródła zegara: void RCC_AdjustHSICalibrationValue(uint8_t HSICalibrationValue) dopuszczalne wartości: 0 0x1F Konfiguracja zewnętrznego wolnego zegara LSE: void RCC_LSEConfig(uint8_t RCC_LSE), parametry wejściowe: RCC_LSE_ON włącza źródło jako oscylator RCC_LSE_OFF wyłącza RCC_LSE_Bypass pozwala podać zewnętrzny zegar na wejście LSE Włączenie/wyłączenie wewnętrznego oscylatora LSI: void RCC_LSICmd(FunctionalState NewState), parametry wejściowe funkcji ENABLE lub DISABLE Oprócz włączenia zegara należy skonfigurować odpowiednio multiplekser System clock mux, który określa źródło zegara dla mikrokontrolera: void RCC_SYSCLKConfig(uint32_t RCC_SYSCLKSource) RCC_SYSCLKSource_HSI wewnętrzny zegar szybki HSI RCC_SYSCLKSource_HSE zewnętrzny zegar szybki HSE RCC_SYSCLKSource_PLLCLK zegar z pętli fazowej PLL 2
Do sprawdzenia poprawności konfiguracji systemu zegarów można skorzystać z funkcji sprawdzającej źródło zegara: uint8_t RCC_GetSYSCLKSource(void), funkcja zwraca: 0x00 - HSI used as system clock 0x04 - HSE used as system clock 0x08 - PLL used as system clock sprawdzającej częstotliwość pracy zegara głównego: void RCC_GetClocksFreq(RCC_ClocksTypeDef* RCC_Clocks) sprawdzającej gotowość zegara bądź oscylatora do pracy: FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG) RCC_FLAG_HSIRDY: gotowość zegara HSI RCC_FLAG_HSERDY: gotowość zegara HSE RCC_FLAG_PLLRDY: gotowość pętli fazowej PLL RCC_FLAG_PLLI2SRDY: PLLI2S RCC_FLAG_PLLSAIRDY: PLLSAI RCC_FLAG_LSERDY: gotowość zegara LSE RCC_FLAG_LSIRDY: gotowość zegara LSI oraz przyczynę wyzerowania mikrokontrolera: RCC_FLAG_BORRST: POR/PDR bądź BOR reset RCC_FLAG_PINRST: poprzez pin reset RCC_FLAG_PORRST: POR/PDR reset RCC_FLAG_SFTRST: Software reset RCC_FLAG_IWDGRST: reset poprzez niezależny watchdog RCC_FLAG_WWDGRST: reset poprzez watchdog okienkowy RCC_FLAG_LPWRRST: Low Power reset Funkcja zwracane FlagStatus, która może przyjąć wartość SET lub RESET Konfiguracja pętli fazowej PLL: void RCC_PLLConfig(uint32_t RCC_PLLSource, uint32_t PLLM, uint32_t PLLN, uint32_t PLLP, uint32_t PLLQ) RCC_PLLSource określa źródło zegara dla pętli fazowej: RCC_PLLSource_HSI RCC_PLLSource_HSE PLLM - dzielnik częstotliwości dla VCO: ustawiany w zakresie 0-63 PLLN - mnożnik częstotliwości dla VCO: ustawiany w zakresie 192-432 PLLP - dzielnik częstotliwości dla zegara mikrokontrolera SYSCLK (2,4,6,8) PLLQ - dzielnik zegara dla układów: OTG FS, SDIO i RNG 4-15 Uwaga: VCO pętli fazowej może pracować w zakresie częstotliwości od 192 do 432 MHz Włączenie pętli fazowej: void RCC_PLLCmd(FunctionalState NewState) NewState może przyjąć wartości określone jako ENABLE bądź DISABLE 3
Konfiguracja zegarów dla magistral AHB, APB1, APB2: konfiguracja zegarów dla magistrali AHB (HCLK) void RCC_HCLKConfig(uint32_t RCC_SYSCLK) RCC_SYSCLK_Div1: AHB clock = SYSCLK RCC_SYSCLK_Div2: AHB clock = SYSCLK/2 RCC_SYSCLK_Div4: AHB clock = SYSCLK/4 RCC_SYSCLK_Div8: AHB clock = SYSCLK/8 RCC_SYSCLK_Div16: AHB clock = SYSCLK/16 RCC_SYSCLK_Div64: AHB clock = SYSCLK/64 RCC_SYSCLK_Div128: AHB clock = SYSCLK/128 RCC_SYSCLK_Div256: AHB clock = SYSCLK/256 RCC_SYSCLK_Div512: AHB clock = SYSCLK/512 konfiguracja wolnych zegarów dla magistrali APB1 (PCLK1) void RCC_PCLK1Config(uint32_t RCC_HCLK) RCC_HCLK_Div1: APB1 clock = HCLK RCC_HCLK_Div2: APB1 clock = HCLK/2 RCC_HCLK_Div4: APB1 clock = HCLK/4 RCC_HCLK_Div8: APB1 clock = HCLK/8 RCC_HCLK_Div16: APB1 clock = HCLK/16 konfiguracja szybkich zegarów dla magistrali APB2 (PCLK2) void RCC_PCLK2Config(uint32_t RCC_HCLK) RCC_HCLK_Div1: APB2 clock = HCLK RCC_HCLK_Div2: APB2 clock = HCLK/2 RCC_HCLK_Div4: APB2 clock = HCLK/4 RCC_HCLK_Div8: APB2 clock = HCLK/8 RCC_HCLK_Div16: APB2 clock = HCLK/16 4
2. Konfiguracja portów wejścia/wyjścia Konfigurację portów wejściowych bądź wyjściowych należy rozpocząć od włączenia zegara dla poszczególnych portów, które mają być używane. Porty podłączone są do magistrali AHB1, stąd należy skorzystać z funkcji: void RCC_AHB1PeriphClockCmd(uint32_t RCC_AHB1Periph, FunctionalState NewState) gdzie: RCC_AHB1Periph określa port NewState stan ENABLE bądź DISABLE, włącza bądź wyłącza port np. RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE) Kolejnym etapem jest powołanie oraz uzupełnienie struktury odpowiedzialnej za konfigurację portu zdefiniowaną w pliku stm32f4xx_gpio.h: typedef struct { uint32_t GPIO_Pin; GPIOSpeed_TypeDef GPIO_Speed; GPIOMode_TypeDef GPIO_Mode; GPIOOType_TypeDef GPIO_OType; GPIOPuPd_TypeDef GPIO_PuPd; } GPIO_InitTypeDef; Do inicjalizacji struktury można użyć funkcji: void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct) Zapis do portu 16 bitów: void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal) np. GPIO_Write(GPIOA, 0xffff); Zapis do pojedynczego wyprowadzenia mikrokontrolera: void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal) np. GPIO_WriteBit(GPIOA, GPIO_Pin_1, 0); bądź alternatywna funkcja ustawiająca wartość logiczną 1 na wyjściu: void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) np. GPIO_SetBits(GPIOF, GPIO_Pin_6) bądź kilka wyprowadzeń z portu: GPIO_SetBits(GPIOF, GPIO_Pin_6 GPIO_Pin_7 GPIO_Pin_8 GPIO_Pin_9) bądź alternatywna funkcja ustawiająca wartość logiczną 0 na wyjściu: void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) np. GPIO_ResetBits(GPIOF, GPIO_Pin_6) bądź kilka wyprowadzeń z portu: np. GPIO_ResetBits(GPIOF, GPIO_Pin_6 GPIO_Pin_7 GPIO_Pin_8 GPIO_Pin_9) Można także bezpośrednio ustawiać wartości rejestrów ustawiającą wartość wyprowadzeń w stan logiczny 1 : np. GPIOA->BSRR = GPIO_Pin_10; // GPIOA.10 = 1 5
bądź ustawiającą wartość wyprowadzeń w stan logiczny 0 : np. GPIOA->BRR = GPIO_Pin_10; // GPIOA.10 = 0 Odczyt ustawionej wartości portu wyjściowego: uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx) np. readvalue = GPIO_ReadOutputData(GPIOC); Odczyt pojedynczego pinu portu wyjściowego: uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) np. readvalue = GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_0) Odczyt portu wejściowego, 16 bitów: uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx) np. portval = GPIO_ReadInputdata(GPIOA); Odczyt stanu pojedynczego wyprowadzenia: uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) np. if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_15) == 0) { } 6
3. Opis zestawu laboratoryjnego Do portów płytki uruchomieniowej, podłączone są: PA5 - zielona dioda LED, oznaczona jako LD2 PC13 przycisk niebieski oznaczony jako USER Złącze USB do programowania i diagnostyki USER LD2 Zdjęcie płytki uruchomieniowej z mikrokontrolerem STM32F411. 7