wtorek, 22 listopada 2016

[1] STM32F7 - Porty GPIO

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:

  1. void SYSTEM_ON(void)
  2. {
  3.   MPU_Region_InitTypeDef MPU_InitStruct;
  4.   RCC_ClkInitTypeDef RCC_ClkInitStruct;
  5.   RCC_OscInitTypeDef RCC_OscInitStruct;
  6.   HAL_MPU_Disable(); //Wylaczenie MPU
  7.   //Konfiguracja MPU dla SRA
  8.   MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  9.   MPU_InitStruct.BaseAddress = 0x20010000;
  10.   MPU_InitStruct.Size = MPU_REGION_SIZE_256KB;
  11.   MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  12.   MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
  13.   MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
  14.   MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
  15.   MPU_InitStruct.Number = MPU_REGION_NUMBER0;
  16.   MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
  17.   MPU_InitStruct.SubRegionDisable = 0x00;
  18.   MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
  19.   HAL_MPU_ConfigRegion(&MPU_InitStruct);
  20.   //Wlaczenie MPU
  21.   HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
  22.   //Cache Enable
  23.   SCB_InvalidateICache();
  24.   //Wlaczenie branch prediction
  25.   //ustawienie bitu 18 w rejestrze CCR
  26.   //str. 199 PM0253
  27.   SCB->CCR |= (1 <<18);
  28.   __DSB();
  29.   //Wlaczenie I-Cache
  30.   SCB_EnableICache();
  31.   //Wlaczenie D-Cache
  32.   SCB_InvalidateDCache();
  33.   SCB_EnableDCache();
  34.   HAL_Init();
  35.   //Wlacz power control
  36.   __HAL_RCC_PWR_CLK_ENABLE();
  37.   //Voltage scalling pozwala na optymalizacje poboru prądu, dla urządzenia taktowanego poniżej
  38.   //wartosci maksymalnej
  39.   __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  40.   //Wlacz HSE i PLL
  41.   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  42.   RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  43.   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  44.   RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  45.   RCC_OscInitStruct.PLL.PLLM = 25;
  46.   RCC_OscInitStruct.PLL.PLLN = 400;
  47.   RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  48.   RCC_OscInitStruct.PLL.PLLQ = 8;
  49.   HAL_RCC_OscConfig(&RCC_OscInitStruct);
  50.   //Aktywuj OverDrive
  51.   HAL_PWREx_ActivateOverDrive();
  52.   //PLL jako zegar systemowy, konfiguracja HCLK, PCLK1, PCLK2
  53.   RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
  54.   RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  55.   RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  56.   RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  57.   RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
  58.   HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_6);
  59. }

Włączenie zegarów dla wszystkich portów:

  1. void WLACZ_WSZYSTKIE_ZEGARY()
  2. {
  3.     __GPIOA_CLK_ENABLE();
  4.     __GPIOB_CLK_ENABLE();
  5.     __GPIOC_CLK_ENABLE();
  6.     __GPIOD_CLK_ENABLE();
  7.     __GPIOE_CLK_ENABLE();
  8.     __GPIOF_CLK_ENABLE();
  9.     __GPIOG_CLK_ENABLE();
  10.     __GPIOH_CLK_ENABLE();
  11.     __GPIOI_CLK_ENABLE();
  12.     __GPIOJ_CLK_ENABLE();
  13.     __GPIOK_CLK_ENABLE();
  14. }

Inicjalizacja diody. Wbudowana jest podłączona do GPIOI_1. Oraz funkcja właczająca tylko wybrany z zegarów:

  1.  
  2. void PORT_CLOCK_ENABLE(GPIO_TypeDef* PORT)
  3. {
  4.   if(PORT==GPIOA) { __HAL_RCC_GPIOA_CLK_ENABLE(); }
  5.   if(PORT==GPIOB) { __HAL_RCC_GPIOB_CLK_ENABLE(); }
  6.   if(PORT==GPIOC) { __HAL_RCC_GPIOC_CLK_ENABLE(); }
  7.   if(PORT==GPIOD) { __HAL_RCC_GPIOD_CLK_ENABLE(); }
  8.   if(PORT==GPIOE) { __HAL_RCC_GPIOE_CLK_ENABLE(); }
  9.   if(PORT==GPIOF) { __HAL_RCC_GPIOF_CLK_ENABLE(); }
  10.   if(PORT==GPIOG) { __HAL_RCC_GPIOG_CLK_ENABLE(); }
  11.   if(PORT==GPIOH) { __HAL_RCC_GPIOH_CLK_ENABLE(); }
  12.   if(PORT==GPIOI) { __HAL_RCC_GPIOI_CLK_ENABLE(); }
  13.   if(PORT==GPIOJ) { __HAL_RCC_GPIOJ_CLK_ENABLE(); }
  14.   if(PORT==GPIOK) { __HAL_RCC_GPIOK_CLK_ENABLE(); }
  15. }
  16.  
  17. void GPIO_LED_INIT(void)
  18. {
  19.     GPIO_InitTypeDef GPIO_InitStruct;
  20.    
  21.     PORT_CLOCK_ENABLE(GPIOI);
  22.    
  23.     GPIO_InitStruct.Pin = GPIO_PIN_1;
  24.     GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  25.     GPIO_InitStruct.Pull = GPIO_NOPULL;
  26.     GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
  27.     HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);
  28. }

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:

  1. void LED_HIGH(GPIO_TypeDef *GPIOx, uint16_t Pin)
  2. {
  3.   Port->BSRR = Pin;
  4. }

Zgaszenie diody:

  1. void LED_LOW(GPIO_TypeDef *GPIOx, uint16_t Pin)
  2. {
  3.   GPIOx->BSRR = (Pin<<16);
  4. }

Mruganie:

  1. void LED_TOGGLE(GPIO_TypeDef *GPIOx, uint16_t Pin)
  2. {
  3.   GPIOx->ODR ^= Pin;
  4. }