华大HC32F460初使用及串口测试
前言
因工作需求,上手了一块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,符合理论值。