合宙AIR105(二): 時鐘設定和延遲函數

2022-06-18 18:01:03

目錄

Air105 的時鐘

高頻振盪源

  • 晶片支援使用內部振盪源, 或使用外接12MHz晶體
    • 晶片上電覆位後 ROM boot 啟動過程基於內部12MHz的振盪器
    • 晶片內部整合的12MHz振盪源精度為±2%, 精度一般
    • 使用外接12MHz晶體, 需要軟體切換
  • 經過PLL倍頻後為系統提供輸入
  • 倍頻後的PLL時脈頻率可通過暫存器進行設定,可選頻率為:108MHz, 120MHz, 132MHz, 144MHz, 156MHz, 168MHz, 180MHz, 192MHz, 204MHz

分頻結構

  • PLL_CLK
    • 外部 XTAL12M 或 內部 OSC12M -> 直通, 或PLL產生 108MHz - 204MHz
  • FCLK / CPU_CLK
    • PLL_CLK -> 2bit分頻(0, 2分頻, 4分頻) -> FCLK
    • FCLK就是主程式迴圈的時鐘
  • HCLK
    • FCLK -> 1bit分頻(預設=1, 2分頻) -> HCLK
    • 當 FCLK 小於 102MHz 時不分頻, 否則2分頻
  • PCLK
    • HCLK -> 1bit分頻(預設=0, 不分頻) -> PCLK (外設頻率)
    • PCLK 是大部分外設 TIMER, ADC, SPI, WDT, GPIO, I2C, UART 的時鐘
  • QSPI
    • FCLK -> 3bit分頻(預設=3, 4分頻) -> QSPI

低頻振盪源

  • 晶片安全區基於內部32KHz,RTC預設基於內部OSC 32K, 使用外部XTAL 32K需要軟體切換
  • 支援內部或外部32KHz輸出

時鐘結構

  • (外部或內部 32K RTC OSC) -> SYSTICK
  • 內部 32K OSC -> Security

時鐘設定

以下程式碼基於 air105_project 的庫函數

暫存器

暫存器手冊 Air105晶片資料手冊_1.1.pdf

暫存器的基礎地址, 定義在 air105.h

#define AIR105_FLASH_BASE                       (0x01000000UL)                /*!< (FLASH     ) Base Address */
#define AIR105_SRAM_BASE                        (0x20000000UL)                /*!< (SRAM      ) Base Address */
#define AIR105_PERIPH_BASE                      (0x40000000UL)                /*!< (Peripheral) Base Address */

#define AIR105_AHB_BASE                         (AIR105_PERIPH_BASE)
#define AIR105_APB0_BASE                        (AIR105_PERIPH_BASE + 0x10000)

#define SYSCTRL_BASE                            (AIR105_APB0_BASE + 0xF000)

SYSCTRL_BASE

  • 地址 = 外設基礎地址 0x40000000UL + APB0 偏移 0x10000 + SYSCTRL 偏移 0xF000
  • 範圍 [0x4001_F000, 0x4001_FFFF]

時鐘振盪源

振盪源選擇

SYSCTRL_SYSCLKSourceSelect(SELECT_EXT12M);

12MHz 時鐘來源選擇: 0:片外 XTAL, 1:片內 OSC

void SYSCTRL_SYSCLKSourceSelect(SYSCLK_SOURCE_TypeDef source)
{
    assert_param(IS_SYSCLK_SOURCE(source));
    
    switch (source)
    {
    case SELECT_EXT12M:
        // FREQ_SEL 是一個32bit的暫存器, 先與二補數(清零第12位元), 然後寫入值(0)
        SYSCTRL->FREQ_SEL = ((SYSCTRL->FREQ_SEL & (~SYSCTRL_FREQ_SEL_CLOCK_SOURCE_Mask)) | SYSCTRL_FREQ_SEL_CLOCK_SOURCE_EXT);
        break;
    
    case SELECT_INC12M:
        // 先與二補數(清零第12位元), 然後寫入值(1)
        SYSCTRL->FREQ_SEL = ((SYSCTRL->FREQ_SEL & (~SYSCTRL_FREQ_SEL_CLOCK_SOURCE_Mask)) | SYSCTRL_FREQ_SEL_CLOCK_SOURCE_INC);
        break;
    }
}

時脈頻率

設定使用預設的內部時鐘HSI(Internal clock)

void SystemClock_Config_HSI(void)
{
    // 設定CPU頻率, 直接選擇, 不需要計算
    SYSCTRL_PLLConfig(SYSCTRL_PLL_204MHz);
    // 分頻後產生 FCLK -> 這是主程式的時鐘
    SYSCTRL_PLLDivConfig(SYSCTRL_PLL_Div_None);
    // 分頻產生 HCLK, 如果 FCLK > 102MHz 則無論如何設定, 都會被二分頻
    SYSCTRL_HCLKConfig(SYSCTRL_HCLK_Div2);
    // 分頻產生 PCLK -> 這是大部分外設的時鐘
    SYSCTRL_PCLKConfig(SYSCTRL_PCLK_Div2);
    QSPI_SetLatency((uint32_t)0);
}

PLL分頻的選項

#define SYSCTRL_PLL_Div_None                       ((uint32_t)0x00)
#define SYSCTRL_PLL_Div2                           ((uint32_t)0x01)
#define SYSCTRL_PLL_Div4                           ((uint32_t)0x10)

設定 SysTick

void Delay_Init(void)
{
    SYSCTRL_ClocksTypeDef clocks;

    SYSCTRL_GetClocksFreq(&clocks);
    SysTick_Config(clocks.CPU_Frequency / 1000000);   ///< 1us
}

呼叫 SysTick_Config 將單個 SysTick 設定為 1 us.

也可以直接使用SYSCTRL->HCLK_1MS_VAL * 2 / 1000這個變數代表了當前時鐘設定下, 1ms需要的HCLK時鐘週期, 根據當前FCLK是否大於108MHz 確定是否要乘以2.

之後就會每隔1us呼叫 SysTick_Handler(void), 在這裡設定 32bit g_current_tick 遞增, 可以用於延時控制. 因為32bit數的限制, 1.2個小時後會溢位, 所以這裡有一個延遲的極限.

void SysTick_Handler(void)
{
    g_current_tick++;
}

延遲函數

為避免溢位造成的延遲錯誤, 需要做一個判斷

uint32_t get_diff_tick(uint32_t cur_tick, uint32_t prior_tick)
{
    if (cur_tick < prior_tick)
    {
        // 如果當前值比前值還小, 說明發生了溢位, 用當前值加上原值取反(即原值離溢位的距離)
        return (cur_tick + (~prior_tick));
    }
    else
    {
        return (cur_tick - prior_tick);
    }
}

延遲的函數

void Delay_us(uint32_t usec)
{
    uint32_t old_tick;

    old_tick = g_current_tick;
    while (get_diff_tick(g_current_tick, old_tick) < usec);
}

void Delay_ms(uint32_t msec)
{
    uint32_t old_tick;

    old_tick = g_current_tick;
    while (get_diff_tick(g_current_tick, old_tick) < (msec * 1000));
}

程式碼

程式碼地址: https://gitee.com/iosetting/air105_project

可以使用Keil5 MDK 直接開啟 Demos 目錄下的範例專案, 與Air105開發板接線參考前一篇合宙AIR105(一): Keil MDK開發環境, DAP-Link 燒錄和偵錯