1. 程式人生 > >[HAL學習筆記] HAL庫原始檔stm32h7xx_hal.c學習筆記。

[HAL學習筆記] HAL庫原始檔stm32h7xx_hal.c學習筆記。

[HAL學習筆記]
HAL庫原始檔stm32h7xx_hal.c學習筆記,此檔案極其重要(2018-07-21 V1.0)
原文地址:forum.armfly.com/forum.php?mod=viewthread&tid=87760

說明:
1、在中斷裡面使用HAL_Delay要特別注意。
2、函式HAL_InitTick會被HAL_Init和HAL_RCC_ClockConfig呼叫。
3、這個檔案比較雜,像基準電壓大小配置,EXTI配置,IO補償配置等都在這個檔案裡面。

==============================================================================

初始化和復位初始化

==============================================================================
1、初始化NVIC配置,初始化時鐘(主要是滴答定時器)以及備份域的初始化。
2、復位HAL的部分配置。
3、配置一個1ms的時間基準。
(1)、預設的時間基準是來源於滴答定時器,也可以來自其他同通用定時器。
(2)、函式HAL_Init裡面會呼叫時間基準初a始化函式HAL_InitTick,而呼叫函式HAL_RCC_ClockConfig也會呼叫時間基準初始化函式HAL_InitTick
(3)、如果在中斷服務程式裡面呼叫延遲函式HAL_Delay要特別注意,因為這個函式的時間基準是基於滴答定時器或者其他通用定時器實現,實現方式是滴答定時器或者其他通用定時器裡面做了個變數計數。如此以來,結果是顯而易見的,如果其他中斷服務程式呼叫了此函式,且中斷優先順序高於滴答定時器,會導致滴答定時器中斷服務程式一直得不到執行,從而卡死在裡面。所以滴答定時器的中斷優先順序一定要比他們高。

1、函式HAL_StatusTypeDef HAL_Init(void)
(1)此函式用於初始化HAL庫,必須在main函式裡面優先呼叫。此函式主要實現如下功能
a、設定NVIC優先順序分組是4。
b、設定滴答定時器的每1ms中斷一次。
c、HAL庫不像之前的標準庫,在系統啟動函式SystemInit裡面做了RCC初始化,HAL庫是沒有做的,所以進入到main函式後,系統還在用內部高速時鐘HSI,對於H7來說,HSI主頻是64MHz。
d、函式HAL_Init裡面呼叫的HAL_MspInit一般在檔案stm32h7xx_hal_msp.c裡面做具體實現,主要用於底層初始化。當前此函式也在檔案stm32h7xx_hal.c裡面,只是做了弱定義。

(2)使用者務必保證每1ms一次滴答中斷。
(3)返回值,HAL_ERROR和HAL_OK。

HAL_StatusTypeDef HAL_Init(void)
{
  /* Set Interrupt Group Priority */
  HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);

  /* Use systick as time base source and configure 1ms tick (default clock after Reset is HSI) */
  if(HAL_InitTick(TICK_INT_PRIORITY) != HAL_OK)
  {
    return HAL_ERROR;
  }

  /* Init the low level hardware */
  HAL_MspInit();

  /* Return function status */
  return HAL_OK;
}

2、函式HAL_St

atusTypeDef HAL_DeInit(void)
(1)用於復位HAL庫和滴答時鐘
a、復位了AHB1,2,3,4的時鐘,APB1L,APB1H,APB2,3,4的時鐘。
b、函式HAL_DeInit裡面呼叫的HAL_MspDeInit一般在檔案stm32h7xx_hal_msp.c裡面做具體實現,主要用於底層初始化,跟函式HAL_Init裡面呼叫的HAL_MspInit是一對。當前此函式也在檔案stm32h7xx_hal.c裡面,只是做了弱定義。

  HAL_StatusTypeDef HAL_DeInit(void)
    {
      /* Reset of all peripherals */
      __HAL_RCC_AHB3_FORCE_RESET();
      __HAL_RCC_AHB3_RELEASE_RESET();
    
      __HAL_RCC_AHB1_FORCE_RESET();
      __HAL_RCC_AHB1_RELEASE_RESET();
    
      __HAL_RCC_AHB2_FORCE_RESET();
      __HAL_RCC_AHB2_RELEASE_RESET();
    
      __HAL_RCC_AHB4_FORCE_RESET();
     __HAL_RCC_AHB4_RELEASE_RESET();
    
      __HAL_RCC_APB3_FORCE_RESET();
      __HAL_RCC_APB3_RELEASE_RESET();
    
      __HAL_RCC_APB1L_FORCE_RESET();
      __HAL_RCC_APB1L_RELEASE_RESET();
    
      __HAL_RCC_APB1H_FORCE_RESET();
      __HAL_RCC_APB1H_RELEASE_RESET();
    
       __HAL_RCC_APB2_FORCE_RESET();
       __HAL_RCC_APB2_RELEASE_RESET();
    
      __HAL_RCC_APB4_FORCE_RESET();
      __HAL_RCC_APB4_RELEASE_RESET();
    
      /* De-Init the low level hardware */
      HAL_MspDeInit();
    
      /* Return function status */
      return HAL_OK;
    }

3、函式__weak HAL_StatusTypeDef

HAL_InitTick(uint32_t TickPriority)
(1)此函式有個字首__weak ,表示弱定義,使用者可以重定義。
(2)此函式用於初始化滴答時鐘1ms中斷一次,並且為滴答中斷配置一個使用者指定的優先順序。
(3)此函式由HAL_Init呼叫,或者任何其它地方呼叫函式HAL_RCC_ClockConfig配置RCC的時候也會呼叫HAL_InitTick。
(4)呼叫基於此函式實現HAL_Delay要特別注意,因為這個函式的時間基準是基於滴答定時器或者其他通用定時器實現,實現方式是滴答定時器或者其他通用定時器裡面做了個變數計數。如此以來,結果是顯而易見的,如果其他中斷服務程式呼叫了此函式,且中斷優先順序高於滴答定時器,會導致滴答定時器中斷服務程式一直得不到執行,從而卡死在裡面。所以滴答定時器的中斷優先順序一定要比他們高。
(5)形參TickPriority用於設定滴答定時器優先順序
(6)返回值HAL_ERROR和HAL_OK。

__weak HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
  /* Configure the SysTick to have interrupt in 1ms time basis*/
  if (HAL_SYSTICK_Config(SystemCoreClock / (1000U / uwTickFreq)) > 0U)
  {
    return HAL_ERROR;
  }

  /* Configure the SysTick IRQ priority */
  if (TickPriority < (1UL << __NVIC_PRIO_BITS))
  {
    HAL_NVIC_SetPriority(SysTick_IRQn, TickPriority, 0U);
    uwTickPrio = TickPriority;
  }
  else
  {
    return HAL_ERROR;
  }

  /* Return function status */
  return HAL_OK;
}

4、函式__weak voi

d HAL_IncTick(void)
(1)此函式有個字首__weak ,表示弱定義,使用者可以重定義。
(2)此函式在滴答定時器中斷裡面被呼叫,實現一個簡單的計數功能,因為一般滴答定時器中斷都是配置的1ms,所以計數全域性變數uwTick每秒加1.
__weak void HAL_IncTick(void)
{
uwTick += (uint32_t)uwTickFreq;
}複製程式碼

5、函式__weak void HAL_GetTick(void)
(1)此函式有個字首__weak ,表示弱定義,使用者可以重定義。
(2)此函式用於獲取當前系統計數。
__weak uint32_t HAL_GetTick(void)
{
return uwTick;
}複製程式碼

6、函式HAL_GetTickPrio
(1)此函式用於獲取滴答時鐘優先順序。
uint32_t HAL_GetTickPrio(void)
{
return uwTickPrio;
}複製程式碼

7、函式HAL_SetTickFreq
(1)此函式用於重新配置滴答中斷週期
HAL_StatusTypeDef HAL_SetTickFreq(HAL_TickFreqTypeDef Freq)
{
HAL_StatusTypeDef status = HAL_OK;
assert_param(IS_TICKFREQ(Freq));

if (uwTickFreq != Freq)
{
uwTickFreq = Freq;

/* Apply the new tick Freq  */
status = HAL_InitTick(uwTickPrio);

}

return status;
}複製程式碼

8、函式HAL_TickFreqTypeDef HAL_GetTickFreq(void)
(1)此函式用於獲取滴答中斷週期
HAL_TickFreqTypeDef HAL_GetTickFreq(void)
{
return uwTickFreq;
}複製程式碼

9、函式 __weak void HAL_Delay(uint32_t Delay)
(1)此函式有個字首__weak ,表示弱定義,使用者可以重定義。
(2)此函式用於阻塞式延遲,預設單位是ms。
__weak void HAL_Delay(uint32_t Delay)
{
uint32_t tickstart = HAL_GetTick();
uint32_t wait = Delay;

/* Add a freq to guarantee minimum wait */
if (wait < HAL_MAX_DELAY)
{
wait += (uint32_t)(uwTickFreq);
}

while ((HAL_GetTick() - tickstart) < wait)
{
}
}複製程式碼

10、函式__weak void HAL_SuspendTick(void)和__weak void HAL_ResumeTick(void)
(1)此函式有個字首__weak ,表示弱定義,使用者可以重定義。
(2)分別用於滴答定時器的掛起和恢復。
__weak void HAL_SuspendTick(void)
{
/* Disable SysTick Interrupt /
SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk;
}
__weak void HAL_ResumeTick(void)
{
/
Enable SysTick Interrupt */
SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;
}
複製程式碼

STM32H7自帶的電壓基準設定函式,主要是供自帶ADC和DAC使用。

1、函式void HAL_SYSCFG_VREFBUF_VoltageScalingConfig(uint32_t VoltageScaling)
(1)此函式用於配置內部電壓基準大小配置。
(2)當形參VoltageScaling = SYSCFG_VREFBUF_VOLTAGE_SCALE0時
輸出基準是2.048 V,條件是VDDA >= 2.4V。

    當形參VoltageScaling = SYSCFG_VREFBUF_VOLTAGE_SCALE1時
    輸出基準是2.5 V,條件是VDDA >= 2.8V。

    當形參VoltageScaling = SYSCFG_VREFBUF_VOLTAGE_SCALE2時
    輸出基準是1.5 V,條件是VDDA >= 1.8V。

    當形參VoltageScaling = SYSCFG_VREFBUF_VOLTAGE_SCALE3時
    輸出基準是1.8 V,條件是VDDA >= 2.1V。

void HAL_SYSCFG_VREFBUF_VoltageScalingConfig(uint32_t VoltageScaling)
{
/* Check the parameters */
assert_param(IS_SYSCFG_VREFBUF_VOLTAGE_SCALE(VoltageScaling));

MODIFY_REG(VREFBUF->CSR, VREFBUF_CSR_VRS, VoltageScaling);
}複製程式碼

2、函式void HAL_SYSCFG_VREFBUF_HighImpedanceConfig(uint32_t Mode)
(1)此函式用於配置內部電壓基準是否在晶片內部分VREF+引腳接通。
(2)形參為SYSCFG_VREFBUF_HIGH_IMPEDANCE_DISABLE時,表示導通。
形參為SYSCFG_VREFBUF_HIGH_IMPEDANCE_ENABLE時,表示高阻,即不導通。
void HAL_SYSCFG_VREFBUF_HighImpedanceConfig(uint32_t Mode)
{
/* Check the parameters */
assert_param(IS_SYSCFG_VREFBUF_HIGH_IMPEDANCE(Mode));

MODIFY_REG(VREFBUF->CSR, VREFBUF_CSR_HIZ, Mode);
}複製程式碼

3、函式void HAL_SYSCFG_VREFBUF_TrimmingConfig(uint32_t TrimmingValue)
(1)此函式用於內部電壓基準的的校準調節。
void HAL_SYSCFG_VREFBUF_TrimmingConfig(uint32_t TrimmingValue)
{
/* Check the parameters */
assert_param(IS_SYSCFG_VREFBUF_TRIMMING(TrimmingValue));

MODIFY_REG(VREFBUF->CCR, VREFBUF_CCR_TRIM, TrimmingValue);
}複製程式碼

4、函式HAL_StatusTypeDef HAL_SYSCFG_EnableVREFBUF(void)和void HAL_SYSCFG_DisableVREFBUF(void)
(1)分別用於內部電壓參考基準的禁止和使能。
HAL_StatusTypeDef HAL_SYSCFG_EnableVREFBUF(void)
{
uint32_t tickstart = 0;

SET_BIT(VREFBUF->CSR, VREFBUF_CSR_ENVR);

/* Get Start Tick*/
tickstart = HAL_GetTick();

/* Wait for VRR bit */
while(READ_BIT(VREFBUF->CSR, VREFBUF_CSR_VRR) == RESET)
{
if((HAL_GetTick() - tickstart) > VREFBUF_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}

return HAL_OK;
}
void HAL_SYSCFG_DisableVREFBUF(void)
{
CLEAR_BIT(VREFBUF->CSR, VREFBUF_CSR_ENVR);
}
複製程式碼

1、函式void HAL_SYSCFG_ETHInterfaceSelect(uint32_t SYSCFG_ETHInterface)
(1)此函式用於乙太網的MII和RMII介面選擇
void HAL_SYSCFG_ETHInterfaceSelect(uint32_t SYSCFG_ETHInterface)
{
/* Check the parameter */
assert_param(IS_SYSCFG_ETHERNET_CONFIG(SYSCFG_ETHInterface));

MODIFY_REG(SYSCFG->PMCR, SYCFG_PMCR_EPIS_SEL, (uint32_t)(SYSCFG_ETHInterface));
}複製程式碼

1、函式void HAL_SYSCFG_AnalogSwitchConfig(uint32_t SYSCFG_AnalogSwitch , uint32_t SYSCFG_SwitchState )
(1)對於引腳PA0,PA1,PC2和PC3用於ADC時,還有有一組對應的可選引腳PA0_C,PA1_C,PC2_C和PC3_C。此函式的作用就是切換可選引腳用的。關於這個問題的詳情可看此貼:http://forum.armfly.com/forum.php?mod=viewthread&tid=87707
void HAL_SYSCFG_AnalogSwitchConfig(uint32_t SYSCFG_AnalogSwitch , uint32_t SYSCFG_SwitchState )
{
/* Check the parameter */
assert_param(IS_SYSCFG_ANALOG_SWITCH(SYSCFG_AnalogSwitch));
assert_param(IS_SYSCFG_SWITCH_STATE(SYSCFG_SwitchState));

MODIFY_REG(SYSCFG->PMCR, (uint32_t) SYSCFG_AnalogSwitch, (uint32_t)(SYSCFG_SwitchState));
}複製程式碼

2、函式void HAL_SYSCFG_EnableBOOST(void)和void HAL_SYSCFG_DisableBOOST(void)
(1)這兩個函式用於使能或者禁止Booster。如果使能了booster的話,在供電電壓低於2.7V時,可以減少模擬開關總的諧波失真,這樣的話,模擬開關的效能跟正常供電電壓時的全範圍測量一樣。
void HAL_SYSCFG_EnableBOOST(void)
{
SET_BIT(SYSCFG->PMCR, SYSCFG_PMCR_BOOSTEN) ;
}
void HAL_SYSCFG_DisableBOOST(void)
{
CLEAR_BIT(SYSCFG->PMCR, SYSCFG_PMCR_BOOSTEN) ;
}複製程式碼

1、函式void HAL_SYSCFG_CM7BootAddConfig(uint32_t BootRegister, uint32_t BootAddress)
(1)用於配置boot = 0和boot = 1時的啟動地址,詳情看此貼:http://forum.armfly.com/forum.php?mod=viewthread&tid=87459
void HAL_SYSCFG_CM7BootAddConfig(uint32_t BootRegister, uint32_t BootAddress)
{
/* Check the parameters /
assert_param(IS_SYSCFG_BOOT_REGISTER(BootRegister));
assert_param(IS_SYSCFG_BOOT_ADDRESS(BootAddress));
if ( BootRegister == SYSCFG_BOOT_ADDR0 )
{
/
Configure CM7 BOOT ADD0 /
MODIFY_REG(SYSCFG->UR2, SYSCFG_UR2_BOOT_ADD0, ((BootAddress >> 16) << POSITION_VAL(SYSCFG_UR2_BOOT_ADD0)));
}
else
{
/
Configure CM7 BOOT ADD1 */
MODIFY_REG(SYSCFG->UR3, SYSCFG_UR3_BOOT_ADD1, (BootAddress >> 16));
}

}複製程式碼

IO補償相關的配置
1、函式void HAL_EnableCompensationCell(void)和void HAL_SYSCFG_EnableIOSpeedOptimize(void)
(1)這兩個函式用於使能或者禁止IO補償,只有在供電電壓範圍是2.4V到3.6V之間時,使用此功能才有意義。
void HAL_EnableCompensationCell(void)
{
SET_BIT(SYSCFG->CCCSR, SYSCFG_CCCSR_EN) ;
}
void HAL_DisableCompensationCell(void)
{
CLEAR_BIT(SYSCFG->CCCSR, SYSCFG_CCCSR_EN) ;
}複製程式碼

2、函式void HAL_SYSCFG_EnableIOSpeedOptimize(void)和void HAL_SYSCFG_DisableIOSpeedOptimize(void)
(1)這兩個函式用於優化IO速度或者禁止優化,不過僅在供電電壓低於2.5V時可用,高於2.5V是不可以使用的,另外使用這個功能的前提是使用者使能了PRODUCT_BELOW_25V(是可選位元組配置選項裡面的一個bit)
void HAL_SYSCFG_EnableIOSpeedOptimize(void)
{
SET_BIT(SYSCFG->CCCSR, SYSCFG_CCCSR_HSLV) ;
}
void HAL_SYSCFG_DisableIOSpeedOptimize(void)
{
CLEAR_BIT(SYSCFG->CCCSR, SYSCFG_CCCSR_HSLV) ;
}複製程式碼

3、函式void HAL_SYSCFG_CompensationCodeSelect(uint32_t SYSCFG_CompCode)
(1)IO補償單元的選擇,可以是SYSCFG_CELL_CODE,即暫存器SYSCFG_CCVR,也可以是SYSCFG_REGISTER_CODE,即暫存器SYSCFG_CCCR
void HAL_SYSCFG_CompensationCodeSelect(uint32_t SYSCFG_CompCode)
{
/* Check the parameter */
assert_param(IS_SYSCFG_CODE_SELECT(SYSCFG_CompCode));
MODIFY_REG(SYSCFG->CCCSR, SYSCFG_CCCSR_CS, (uint32_t)(SYSCFG_CompCode));
}複製程式碼

4、函式void HAL_SYSCFG_CompensationCodeConfig(uint32_t SYSCFG_PMOSCode, uint32_t SYSCFG_NMOSCode )
(1)用於設定補償值,兩個形參的範圍都是0-15。根據使用者呼叫函式HAL_SYSCFG_CompensationCodeSelect選擇的暫存器,這裡會僅有一個形參的設定是有效的。
void HAL_SYSCFG_CompensationCodeConfig(uint32_t SYSCFG_PMOSCode, uint32_t SYSCFG_NMOSCode )
{
/* Check the parameter */
assert_param(IS_SYSCFG_CODE_CONFIG(SYSCFG_PMOSCode));
assert_param(IS_SYSCFG_CODE_CONFIG(SYSCFG_NMOSCode));
MODIFY_REG(SYSCFG->CCCR, SYSCFG_CCCR_NCC|SYSCFG_CCCR_PCC, (((uint32_t)(SYSCFG_PMOSCode)<< 4)|(uint32_t)(SYSCFG_NMOSCode)) );
}複製程式碼

下面的函式主要用於低功耗模式下的除錯。

/**

  • @brief Enable the Debug Module during Domain1 SLEEP mode
  • @retval None
    */
    void HAL_EnableDBGSleepMode(void)
    {
    SET_BIT(DBGMCU->CR, DBGMCU_CR_DBG_SLEEPD1);
    }

/**

  • @brief Disable the Debug Module during Domain1 SLEEP mode
  • @retval None
    */
    void HAL_DisableDBGSleepMode(void)
    {
    CLEAR_BIT(DBGMCU->CR, DBGMCU_CR_DBG_SLEEPD1);
    }

/**

  • @brief Enable the Debug Module during Domain1 STOP mode
  • @retval None
    */
    void HAL_EnableDBGStopMode(void)
    {
    SET_BIT(DBGMCU->CR, DBGMCU_CR_DBG_STOPD1);
    }

/**

  • @brief Disable the Debug Module during Domain1 STOP mode
  • @retval None
    */
    void HAL_DisableDBGStopMode(void)
    {
    CLEAR_BIT(DBGMCU->CR, DBGMCU_CR_DBG_STOPD1);
    }

/**

  • @brief Enable the Debug Module during Domain1 STANDBY mode
  • @retval None
    */
    void HAL_EnableDBGStandbyMode(void)
    {
    SET_BIT(DBGMCU->CR, DBGMCU_CR_DBG_STANDBYD1);
    }

/**

  • @brief Disable the Debug Module during Domain1 STANDBY mode
  • @retval None
    */
    void HAL_DisableDBGStandbyMode(void)
    {
    CLEAR_BIT(DBGMCU->CR, DBGMCU_CR_DBG_STANDBYD1);
    }

/**

  • @brief Enable the Debug Module during Domain3 STOP mode
  • @retval None
    */
    void HAL_EnableDomain3DBGStopMode(void)
    {
    SET_BIT(DBGMCU->CR, DBGMCU_CR_DBG_STOPD3);
    }

/**

  • @brief Disable the Debug Module during Domain3 STOP mode
  • @retval None
    */
    void HAL_DisableDomain3DBGStopMode(void)
    {
    CLEAR_BIT(DBGMCU->CR, DBGMCU_CR_DBG_STOPD3);
    }

/**

  • @brief Enable the Debug Module during Domain3 STANDBY mode
  • @retval None
    */
    void HAL_EnableDomain3DBGStandbyMode(void)
    {
    SET_BIT(DBGMCU->CR, DBGMCU_CR_DBG_STANDBYD3);
    }

/**

  • @brief Disable the Debug Module during Domain3 STANDBY mode
  • @retval None
    */
    void HAL_DisableDomain3DBGStandbyMode(void)
    {
    CLEAR_BIT(DBGMCU->CR, DBGMCU_CR_DBG_STANDBYD3);
    }複製程式碼

FMC記憶體對映切換

1、函式void HAL_SetFMCMemorySwappingConfig(uint32_t BankMapConfig)
(1)此函式用於FMC記憶體對映切換配置、形參是FMC_SWAPBMAP_DISABLE, FMC_SWAPBMAP_SDRAM_SRAM, FMC_SWAPBMAP_SDRAMB2
void HAL_SetFMCMemorySwappingConfig(uint32_t BankMapConfig)
{
/* Check the parameter */
assert_param(IS_FMC_SWAPBMAP_MODE(BankMapConfig));
MODIFY_REG(FMC_Bank1->BTCR[0], FMC_BCR1_BMAP, BankMapConfig);
}複製程式碼

2、函式uint32_t HAL_GetFMCMemorySwappingConfig(void)
(1)此函式用於獲取當前的內容對映配置
uint32_t HAL_GetFMCMemorySwappingConfig(void)
{
return READ_BIT(FMC_Bank1->BTCR[0], FMC_BCR1_BMAP);
}複製程式碼

剩下的幾個函式是EXTI的,暫時不去學習了。
void HAL_EXTI_EdgeConfig(uint32_t EXTI_Line , uint32_t EXTI_Edge )
void HAL_EXTI_GenerateSWInterrupt(uint32_t EXTI_Line)
void HAL_EXTI_D1_ClearFlag(uint32_t EXTI_Line)
void HAL_EXTI_D1_EventInputConfig(uint32_t EXTI_Line , uint32_t EXTI_Mode, uint32_t EXTI_LineCmd )
void HAL_EXTI_D3_EventInputConfig(uint32_t EXTI_Line, uint32_t EXTI_LineCmd , uint32_t EXTI_ClearSrc )