韦东山ARM裸机学习笔记——S3C2440的串口驱动编程原理

前言

讲解韦东山JZ2440开发板的串口驱动原理,对韦东山在维基教程串口使用内容的一些补充,串口使用点击这里进入。这里主要讲的是串口驱动的编程思路,如何根据s3c2440的芯片手册编写出最简单的串口驱动。

一、串口的初始化

串口初始化包括引脚初始化、串口时钟初始化和中断模式、波特率配置以及参数配置等。

1、引脚初始化

(1)看JZ2440开发板的原理图,可知UART0的引脚是GPH2(TXD0)和GPH3(RXD0)。

韦东山ARM裸机学习笔记——S3C2440的串口驱动编程原理

(2)到s3c2440芯片手册295页,看GPHCON(GPH控制寄存器),可以需要把GPH2也就是GPHCON[5:4]配置为10,GPH3也就是GPHCON[7:6]配置为10。

韦东山ARM裸机学习笔记——S3C2440的串口驱动编程原理

(3)配置引脚为内部上拉,然引脚初始时为高电平,看s3c2440芯片手册的295页,可知需要把GPH[10:0]配置为0。

韦东山ARM裸机学习笔记——S3C2440的串口驱动编程原理

(4)编写程序实现引脚初始化,首先清零GPH2和GPH3引脚,然后在配置为TXD和RXD模式,接着将已经配置为内部上拉。

/* 配置GPH2、GPH3引脚为串口模式,GPH2-->TXD,GPH3-->RXD */
GPHCON &= ~((3<<4) | (3<<6));	/* 先清零GPH2和GPH3 */
GPHCON |=  ((2<<4) | (2<<6));	/* 配置为TXD,RXD模式 */
GPHUP  &= ~((1<<2) | (1<<3));	/* 配置内部上拉,让引脚初始时为1 */

 

2、串口时钟以及中断模式配置

在s3c2440芯片手册的342页,看到串口控制寄存器(UART CONTROL REGISTER),通过配置寄存器的位来配置时钟源和中断模式,有s3c2440的时钟体系可知串口是在APB总线,因此是用PCLK时钟源。

(1)时钟源选择,因为我们用的是PCLK时钟源,所以配置[15:10]为000000。

韦东山ARM裸机学习笔记——S3C2440的串口驱动编程原理

(2)中断模式以及回环等配置,不使用中断模式,不用回环模式, Normal transmit、Rx Time Out不使能、这些位配置为0,即[9:4]配置为000000。

韦东山ARM裸机学习笔记——S3C2440的串口驱动编程原理

(3)发送模式和接收模式配置,配置为轮询方式,[3:0]配置为0101。

韦东山ARM裸机学习笔记——S3C2440的串口驱动编程原理

(4)编写UCON0寄存器配置程序,二进制0000000000000101,16进制0x00000005。

/* 配置时钟PCLK(50M),查询模式 */
UCON0 = 0x00000005;

 

3、波特率配置

在s3c2440芯片手册352页,UBRDIV0(UART波特率除数寄存器),看到如下计算公式

韦东山ARM裸机学习笔记——S3C2440的串口驱动编程原理

根据该计算公式可以得出UBRDIV0的值,因此可编写UBRDIV0配置程序。

/* 配置串口波特率
** UBRDIVn = (int)( UART clock / ( buad rate x 16) ) –1
** UART clock = 50M,由时钟配置可知FCLK : HCLK : PCLK = 400m : 100m : 50m
** 有datasheet可知,如果波特率为115200,则
** UBRDIVn = (int)(50000000 / (115200 x 16)) - 1 = 26
*/
UBRDIV0 = 26;

 

4、配置参数

接下来配置串口参数,配置为8个数据位,1个停止位,无校验位,正常模式。在s3c2400的341页,看到UART线路控制寄存器ULCON0,如图所示,可在ULCON0配置为00000011,16进制0x00000003,

韦东山ARM裸机学习笔记——S3C2440的串口驱动编程原理

因此可编写程序配置ULCON0。

/* 配置参数,8个数据位,1个停止位,无校验位,正常模式 */
ULCON0 = 0x00000003;

 

5、完成的串口初始化程序

/**************************************************************
函数名称:uart_init
函数功能:S3C2440 UART0初始
输入参数:无
返 回 值:无
备    注:无
**************************************************************/
void uart_init(void)
{
	/* 配置GPH2、GPH3引脚为串口模式,GPH2-->TXD,GPH3-->RXD */
	GPHCON &= ~((3<<4) | (3<<6));	/* 先清零GPH2和GPH3 */
	GPHCON |=  ((2<<4) | (2<<6));	/* 配置为TXD,RXD模式 */
	GPHUP  &= ~((1<<2) | (1<<3));	/* 配置内部上拉,让引脚初始时为1 */

	/* 配置时钟PCLK(50M),查询模式 */
	UCON0 = 0x00000005;
	
	/* 配置串口波特率
	** UBRDIVn = (int)( UART clock / ( buad rate x 16) ) –1
	** UART clock = 50M,由时钟配置可知FCLK : HCLK : PCLK = 400m : 100m : 50m
	** 有datasheet可知,如果波特率为115200,则
	** UBRDIVn = (int)(50000000 / (115200 x 16)) - 1 = 26
	*/
	UBRDIV0 = 26;

	/* 配置参数,8个数据位,1个停止位,无校验位,正常模式 */
	ULCON0 = 0x00000003;

}

 

二、串口发送和函数实现

1、在s3c2440芯片手册347页,看到UART TX/RX状态寄存器,因为没有用到FIFO发送模式,所以这里用到bit2和bit0,分别对应发送和接收。

韦东山ARM裸机学习笔记——S3C2440的串口驱动编程原理

2、在s3c2440芯片手册351页,UART传输缓冲寄存器和UART接收缓冲寄存器,这里要注意的是发送和接收是有分为小端模式和大端模式的,这里用的是小端模式。

韦东山ARM裸机学习笔记——S3C2440的串口驱动编程原理

3、编写发送字符和接收字符函数

/**************************************************************
函数名称:send_char
函数功能:发送一个字符
输入参数:要发送的字符
返 回 值:无
备    注:无
**************************************************************/
void send_char(unsigned char c)
{
	while(!(UTRSTAT0 & (1<<2)));	/* 检查状态寄存器,如果不为空说明数据还没发送完则一直等待 */
	UTXH0 = c;			/* 如果状态寄存器为空,则将下一个数据传入传输缓冲寄存器 */
}

/**************************************************************
函数名称:receive_char
函数功能:接收一个字符
输入参数:无
返 回 值:获取到的字符
备     注:无
**************************************************************/
unsigned char receive_char(void)
{
	while(!(UTRSTAT0 & (1<<0)));	/* 检查状态寄存器,如果不为空说明数据还没接收完则一直等待 */
	return URXH0;			/* 状态寄存器为空,则将数据读取出来 */
}