W tym poście chciałbym przedstawić podstawowe funkcje odpowiedzialne za obsługę portów WE/WY w układzie STM32F7. W tym przypadku biblioteki standardowe są już nie dostępne dlatego w całości posłużę się bibliotekami HAL'a oraz bezpośrednio rejestrami mikrokontrolera.
Funkcje:
Poniżej przedstawię kod dla poszczególnych części programu. Wszystkie ważne elementy zostały zawarte w kodzie.
Włączenie zegarów systemowych i bibliotek:
- void SYSTEM_ON(void)
- {
- MPU_Region_InitTypeDef MPU_InitStruct;
- RCC_ClkInitTypeDef RCC_ClkInitStruct;
- RCC_OscInitTypeDef RCC_OscInitStruct;
- HAL_MPU_Disable(); //Wylaczenie MPU
- //Konfiguracja MPU dla SRA
- MPU_InitStruct.Enable = MPU_REGION_ENABLE;
- MPU_InitStruct.BaseAddress = 0x20010000;
- MPU_InitStruct.Size = MPU_REGION_SIZE_256KB;
- MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
- MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
- MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
- MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
- MPU_InitStruct.Number = MPU_REGION_NUMBER0;
- MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
- MPU_InitStruct.SubRegionDisable = 0x00;
- MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
- HAL_MPU_ConfigRegion(&MPU_InitStruct);
- //Wlaczenie MPU
- HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
- //Cache Enable
- SCB_InvalidateICache();
- //Wlaczenie branch prediction
- //ustawienie bitu 18 w rejestrze CCR
- //str. 199 PM0253
- SCB->CCR |= (1 <<18);
- __DSB();
- //Wlaczenie I-Cache
- SCB_EnableICache();
- //Wlaczenie D-Cache
- SCB_InvalidateDCache();
- SCB_EnableDCache();
- HAL_Init();
- //Wlacz power control
- __HAL_RCC_PWR_CLK_ENABLE();
- //Voltage scalling pozwala na optymalizacje poboru prądu, dla urządzenia taktowanego poniżej
- //wartosci maksymalnej
- __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
- //Wlacz HSE i PLL
- RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
- RCC_OscInitStruct.HSEState = RCC_HSE_ON;
- RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
- RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
- RCC_OscInitStruct.PLL.PLLM = 25;
- RCC_OscInitStruct.PLL.PLLN = 400;
- RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
- RCC_OscInitStruct.PLL.PLLQ = 8;
- HAL_RCC_OscConfig(&RCC_OscInitStruct);
- //Aktywuj OverDrive
- HAL_PWREx_ActivateOverDrive();
- //PLL jako zegar systemowy, konfiguracja HCLK, PCLK1, PCLK2
- RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
- RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
- RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
- RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
- RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
- HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_6);
- }
Włączenie zegarów dla wszystkich portów:
- void WLACZ_WSZYSTKIE_ZEGARY()
- {
- __GPIOA_CLK_ENABLE();
- __GPIOB_CLK_ENABLE();
- __GPIOC_CLK_ENABLE();
- __GPIOD_CLK_ENABLE();
- __GPIOE_CLK_ENABLE();
- __GPIOF_CLK_ENABLE();
- __GPIOG_CLK_ENABLE();
- __GPIOH_CLK_ENABLE();
- __GPIOI_CLK_ENABLE();
- __GPIOJ_CLK_ENABLE();
- __GPIOK_CLK_ENABLE();
- }
Inicjalizacja diody. Wbudowana jest podłączona do GPIOI_1. Oraz funkcja właczająca tylko wybrany z zegarów:
- void PORT_CLOCK_ENABLE(GPIO_TypeDef* PORT)
- {
- if(PORT==GPIOA) { __HAL_RCC_GPIOA_CLK_ENABLE(); }
- if(PORT==GPIOB) { __HAL_RCC_GPIOB_CLK_ENABLE(); }
- if(PORT==GPIOC) { __HAL_RCC_GPIOC_CLK_ENABLE(); }
- if(PORT==GPIOD) { __HAL_RCC_GPIOD_CLK_ENABLE(); }
- if(PORT==GPIOE) { __HAL_RCC_GPIOE_CLK_ENABLE(); }
- if(PORT==GPIOF) { __HAL_RCC_GPIOF_CLK_ENABLE(); }
- if(PORT==GPIOG) { __HAL_RCC_GPIOG_CLK_ENABLE(); }
- if(PORT==GPIOH) { __HAL_RCC_GPIOH_CLK_ENABLE(); }
- if(PORT==GPIOI) { __HAL_RCC_GPIOI_CLK_ENABLE(); }
- if(PORT==GPIOJ) { __HAL_RCC_GPIOJ_CLK_ENABLE(); }
- if(PORT==GPIOK) { __HAL_RCC_GPIOK_CLK_ENABLE(); }
- }
- void GPIO_LED_INIT(void)
- {
- GPIO_InitTypeDef GPIO_InitStruct;
- PORT_CLOCK_ENABLE(GPIOI);
- GPIO_InitStruct.Pin = GPIO_PIN_1;
- GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
- HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);
- }
Jeśli chodzi o przycisk to jego obsługa jest taka sama jak w mikrokontrolerze STM32F4. Właściwie większość rzeczy się ze sobą pokrywa.
Zapalenie diody:
- void LED_HIGH(GPIO_TypeDef *GPIOx, uint16_t Pin)
- {
- Port->BSRR = Pin;
- }
Zgaszenie diody:
- void LED_LOW(GPIO_TypeDef *GPIOx, uint16_t Pin)
- {
- GPIOx->BSRR = (Pin<<16);
- }
Mruganie:
- void LED_TOGGLE(GPIO_TypeDef *GPIOx, uint16_t Pin)
- {
- GPIOx->ODR ^= Pin;
- }