SAM4E单片机之旅——9、UART与MCK之MAINCK
为得到更高的带宽,需要使用更高的波特率。UART波特率的计算已经介绍过了,现在就尝试下调整外设的时钟频率。可以有多种方法调整外设时钟(MCK)的频率,这里先介绍先主要时钟(MAINCK)的设置,其中包括外部晶振的使用。
外设的时钟(MCK)可以在慢时钟(SLCK)、主要时钟(MAINCK)和MAINCK经锁相环升频后的时钟PLLACK三者中选择,并可以对选择的时钟进行分频。重置时,MCK使用的时钟为MAINCK,且不分频。
MAINCK可以选择使用一个嵌入的快速RC振荡器,或是一个晶体振荡器产生时钟。快速RC振荡器启动时间较短,但不是太精确;而晶体振荡器则相反。同时,RC振荡器可以选择输出时钟的频率(4/8/12 MHz)。重置时,MAINCK使用RC振荡器,频率为4 MHz。
一、 使用芯片嵌入的快速RC振荡器
在PMC时钟产生器主要振荡器寄存器(CKGR_MOR)中,可以对MAINCK进行一系列的设置。注意,在修改该寄存器的值时,需要同时往其KEY字段写入一个魔数:0x37,否则写入不生效。
使能快速RC振荡器。在设置RC振荡器的频率之前,需要先使能它,并且要等到它运行稳定(即不能同时使能RC振荡器和设置它的频率):
/* 使能RC震荡器 */
PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD /* 密码 */
| (PMC->CKGR_MOR| CKGR_MOR_MOSCRCEN)
;
/* 等待时钟稳定 */
while(!(PMC->PMC_SR & PMC_SR_MOSCRCS))
;
设置RC振荡器频率为12 Mhz。设置后同样需要等待它运行稳定。
/* 设置快速RC振荡器频率为12 MHz */
PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD
| (PMC->CKGR_MOR & ~CKGR_MOR_MOSCRCF_Msk)
| CKGR_MOR_MOSCRCF_12_MHz
;
/* 等待稳定 */
while(!(PMC->PMC_SR & PMC_SR_MOSCRCS))
;
为MAINCK选择快速RC振荡器。
/* 切换至RC振荡器 */
PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD
| (PMC->CKGR_MOR & ~CKGR_MOR_MOSCSEL)
;
/* 等待切换完成 */
while (!(PMC->PMC_SR & PMC_SR_MOSCSELS))
;
设置UART。此时,若将UART_BRGR中CD字段的值设为13,则理论的波特率值为 12M/(16 * 13) = 57692 Hz,若PC端选择使用57600 Hz的波特率,则误差约为0.16%。
1UART0->UART_BRGR = UART_BRGR_CD(13 );
接下来,将PC端串口的波特率设置为57600 Hz,尝试下通信是否正常。
若在PC端接收到的是乱码,可能就是RC振荡器不够精确引起的。其产生的时钟频率受工作温度和电压等因素的影响,所以需要校准。可以通过PMC振荡器校准寄存器(PMC_OCR)来进行校准,但在这里不做讨论。
二、 使用外部晶振
可以使用一个外部的晶振以提供更为精确的频率。使用的晶振是由开发板携带的,在芯片手册中,对其的介绍为“3~20 MHz晶振”,即表示具体的频率是由开发板的生产厂家决定的。晶振的一个缺点是需要一定的启动时间,而且由于芯片无法了解使用的芯片的具体信息,所以用户必须手动指定这个启动时间。
SAM4E_EK所携带的晶振的频率为12 MHz,启动时间为15625 us。具体可以查阅开发板的电路图:
或者也可以参考头文件“sam4e_ek.h”中相关的定义:
/** Board oscillator settings(晶振频率) */
#define BOARD_FREQ_MAINCK_XTAL (12000000U)
/** board main clock xtal statup time (主要时钟晶振启动时间)*/
#define BOARD_OSC_STARTUP_US 15625
接下来就可以进行具体的设置了。
使用新的头文件。现在需要了解开发板相关的信息,所以需要使用新的头文件:
//#include
#include
但是在新的头文件中,修改CKGR_MOR密码的宏没有定义,所以需要自己定义:
1#define CKGR_MOR_KEY_PASSWD CKGR_MOR_KEY(0x37)
禁用PB8和PB9引脚的输出。这一步是可选的。PB8和PB9的系统功能分别是XOUT和XIN,即是使用晶振时要用到的引脚。由于PIO控制器中的配置对引脚的输入没有影响,所以无需配置引脚的复用,只需禁用输出即可。
/* 禁用PB8和PB9引脚的输出 */
Pio* xtal_pio = PIOB;
const uint32_t pio_mask = PIO_PB8 | PIO_PB9;
xtal_pio->PIO_PER = pio_mask;
xtal_pio->PIO_ODR = pio_mask;
计算晶
- SAM4E单片机之旅——24、使用DSP库求向量数量积(05-08)
- SAM4E单片机之旅——23、在AS6(GCC)中使用FPU(05-02)
- SAM4E单片机之旅——22、GMAC和PHY的介绍与初始化(04-28)
- SAM4E单片机之旅——19、CAN间通信(04-19)
- SAM4E单片机之旅——20、DMAC之使用Multi-buffer进行内存拷贝(04-24)
- SAM4E单片机之旅——18、通过AFEC(ADC)获取输入的电压(04-17)