前言
因工作需求,上手了一塊HC32F460,網上資料不是很多,因此記錄下調試記錄供后人參考。
使用環境
- IDE: Keil v5.23.0
- DDL: hc32f46x_ddl_Rev1.3.1
- PROJECT: uart_irq_rx_tx
時鍾配置
簡單介紹
HC32提供了六個時鍾源,例程采用的是8M外部時鍾,因此這里也使用外部時鍾。內部時鍾配置暫時未搞明白,等后期更新。
外部晶振定義在system_hc32f46x.h
第103行
#if !defined (XTAL_VALUE)
#define XTAL_VALUE ((uint32_t)8000000) /*!< External high speed OSC freq. */
#endif
需要根據實際晶振大小配置。晶振錯誤時系統仍能運行,但是串口等需要時鍾的設備數據會出現錯誤。
我手上的開發板晶振是12Mhz,因此修改定義為12000000。
設置分頻
例程在main.c
的 static void ClkInit(void)
對系統時鍾進行了配置,采用的是Xtal to MPLL的方法。這里只關心分頻倍數。
/* Set bus clk div. */
stcSysClkCfg.enHclkDiv = ClkSysclkDiv1;
stcSysClkCfg.enExclkDiv = ClkSysclkDiv2;
stcSysClkCfg.enPclk0Div = ClkSysclkDiv1;
stcSysClkCfg.enPclk1Div = ClkSysclkDiv2;
stcSysClkCfg.enPclk2Div = ClkSysclkDiv4;
stcSysClkCfg.enPclk3Div = ClkSysclkDiv4;
stcSysClkCfg.enPclk4Div = ClkSysclkDiv2;
這里對工作時鍾進行分頻。通過系統框圖可以看到,這時輸入時鍾MPLL倍頻出來的MPLLP。
分頻時注意不要超過工作時鍾的上限即可。
通過下列結構體進行倍頻
/* MPLL config. */
stcMpllCfg.pllmDiv = 1u; /* XTAL 8M / 1 */
stcMpllCfg.plln = 50u; /* 8M*50 = 400M */
stcMpllCfg.PllpDiv = 4u; /* MLLP = 100M */
stcMpllCfg.PllqDiv = 4u; /* MLLQ = 100M */
stcMpllCfg.PllrDiv = 4u; /* MLLR = 100M */
MLLP為100M,可以計算出
/* Set bus clk div. */
stcSysClkCfg.enHclkDiv = ClkSysclkDiv1;//100M
stcSysClkCfg.enExclkDiv = ClkSysclkDiv2;//50M
stcSysClkCfg.enPclk0Div = ClkSysclkDiv1;//100M
stcSysClkCfg.enPclk1Div = ClkSysclkDiv2;//50M
stcSysClkCfg.enPclk2Div = ClkSysclkDiv4;//25M
stcSysClkCfg.enPclk3Div = ClkSysclkDiv4;//25M
stcSysClkCfg.enPclk4Div = ClkSysclkDiv2;//50M
由於我需要測試串口最大速率,所以需要修改系統頻率最高(200M)。
12M分 /倍頻
分頻和例程相同,倍頻如下
stcMpllCfg.pllmDiv = 12u; /* XTAL 12M / 3=4M */
stcMpllCfg.plln = 400u; /* 4M*100 = 400M */
stcMpllCfg.PllpDiv = 2u; /* MLLP = 200M */
stcMpllCfg.PllqDiv = 2u; /* MLLQ = 200M */
stcMpllCfg.PllrDiv = 2u; /* MLLR = 200M */
查看配置時鍾
SDK中提供了獲取時鍾頻率的APICLK_GetClockFreq
要使用它,需要先初始化時鍾頻率結構體。
stc_clk_freq_t stcClkFreq;//系統頻率
然后通過 CLK_GetClockFreq(&stcClkFreq);
獲取頻率值。
可以看到,頻率和設置相同。
配置串口
例程默認采用的USART3
/* USART channel definition */
#define USART_CH (M4_USART3)
/* USART baudrate definition */
#define USART_BAUDRATE (115200ul)
/* USART RX Port/Pin definition */
#define USART_RX_PORT (PortE)
#define USART_RX_PIN (Pin04)
#define USART_RX_FUNC (Func_Usart3_Rx)
/* USART TX Port/Pin definition */
#define USART_TX_PORT (PortE)
#define USART_TX_PIN (Pin05)
#define USART_TX_FUNC (Func_Usart3_Tx)
由於修改串口配置牽涉到的地方較多,這里直接采用USART3進行測試。
燒錄工程到板子上后,串口發送數據后會回顯到屏幕上,如果時鍾不對,會出現回顯數據和發送數據不一致的情況。
收發邏輯
在接收到數據后,系統跳轉到UsartRxIrqCallback
函數,讀取接收值,並且打開串口發送和TxEmpty中斷。
static void UsartRxIrqCallback(void)
{
m_u16RxData = USART_RecData(USART_CH);
USART_FuncCmd(USART_CH, UsartTxAndTxEmptyInt, Enable);
}
此時由於TxBuff為空,會進入UsartTxIrqCallback
,發送讀取的值出去,關閉TxEmpty中斷,打開UsartTxCmplt中斷。
static void UsartTxIrqCallback(void)
{
USART_SendData(USART_CH, m_u16RxData);
USART_FuncCmd(USART_CH, UsartTxEmptyInt, Disable);
USART_FuncCmd(USART_CH, UsartTxCmpltInt, Enable);
}
發送數據成功后,進入UsartTxCmpltIrqCallback
,關閉中斷和串口發送功能。
static void UsartTxCmpltIrqCallback(void)
{
USART_FuncCmd(USART_CH, UsartTxCmpltInt, Disable);
USART_FuncCmd(USART_CH, UsartTx, Disable);
}
這些中斷回調函數通過中斷號綁定到具體中斷上
/* Set USART RX IRQ */
stcIrqRegiCfg.enIRQn = Int000_IRQn;
stcIrqRegiCfg.pfnCallback = &UsartRxIrqCallback;
需要注意的是,由於關閉了UsartTx功能,后續無法發送任何數據出去,除非再次打開該功能。
DEBUG功能
SDK默認重定義printf函數到串口3上,不需要自己修改文件即可使用Printf。
相關的代碼實現在hc32f46x_utility.c
中,也同樣包括毫秒延時和微妙延時函數(秒延時未提供,但無傷大雅)。
把串口發送中斷關掉,只保留串口接收中斷
static void UsartRxIrqCallback(void)
{
m_u16RxData = USART_RecData(USART_CH);
// USART_FuncCmd(USART_CH, UsartTxAndTxEmptyInt, Enable);
}
然后打開串口發送功能(在while(1)上面)
/*Enable RX && RX interupt function*/
USART_FuncCmd(USART_CH, UsartRx, Enable);
USART_FuncCmd(USART_CH, UsartRxInt, Enable);
USART_FuncCmd(USART_CH, UsartTx, Enable);
然后就可以使用printf
或者USART_SendData
發送數據了。
while (1)
{
// printf("testing,[%d]\r\n",i);
USART_SendData(USART_CH,0xA5);
sysVar.txCount++;
Ddl_Delay1ms(1000);
}
波特率測試
理論上串口最高波特率為PCLK/32,PCLK為400MHz時,波特率為12.5Mhz
通過示波器抓數據得,2Bit為6.25MHz,符合理論值。