今天解决了mini2440 uboot下的UART0串口驱动。本来在看过网上视频后,找到一段简单的代码即可实现,代码如下:
#include "s3c24xx.h"
#define TXD0READY (1<<2)
#define RXD0READY (1)
#define PCLK 50000000 // init.c中的clock_init函数设置PCLK为50MHz
#define UART_CLK PCLK // UART0的时钟源设为PCLK
#define UART_BAUD_RATE 115200 // 波特率
#define UART_BRD ((UART_CLK / (UART_BAUD_RATE * 16)) - 1)
/*
* 初始化UART0
* 115200,8N1,无流控
*/
void uart0_init(void)
{
GPHCON |= 0xa0; // GPH2,GPH3用作TXD0,RXD0
GPHUP = 0x0c; // GPH2,GPH3内部上拉
ULCON0 = 0x03; // 8N1(8个数据位,无较验,1个停止位)
UCON0 = 0x05; // 查询方式,UART时钟源为PCLK
UFCON0 = 0x00; // 不使用FIFO
UMCON0 = 0x00; // 不使用流控
UBRDIV0 = UART_BRD; // 波特率为115200
}
/*
* 发送一个字符
*/
void putc(unsigned char c)
{
/* 等待,直到发送缓冲区中的数据已经全部发送出去 */
while (!(UTRSTAT0 & TXD0READY));
/* 向UTXH0寄存器中写入数据,UART即自动将它发送出去 */
UTXH0 = c;
}
/*
* 接收字符
*/
unsigned char getc(void)
{
/* 等待,直到接收缓冲区中的有数据 */
while (!(UTRSTAT0 & RXD0READY));
/* 直接读取URXH0寄存器,即可获得接收到的数据 */
return URXH0;
}
/*
* 判断一个字符是否数字
*/
int isDigit(unsigned char c)
{
if (c >= '0' && c <= '9')
return 1;
else
return 0;
}
/*
* 判断一个字符是否英文字母
*/
int isLetter(unsigned char c)
{
if (c >= 'a' && c <= 'z')
return 1;
else if (c >= 'A' && c <= 'Z')
return 1;
else
return 0;
}
头文件s3c24x0.h:
/*UART registers*/
#define ULCON0 (*(volatile unsigned long *)0x50000000)
#define UCON0 (*(volatile unsigned long *)0x50000004)
#define UFCON0 (*(volatile unsigned long *)0x50000008)
#define UMCON0 (*(volatile unsigned long *)0x5000000c)
#define UTRSTAT0 (*(volatile unsigned long *)0x50000010)
#define UTXH0 (*(volatile unsigned char *)0x50000020)
#define URXH0 (*(volatile unsigned char *)0x50000024)
#define UBRDIV0 (*(volatile unsigned long *)0x50000028)
后来看了uboot中s3c4510b UART0驱动代码,我非常喜欢这种给寄存器赋值的方法,很直观,虽然有点费劲,充分展示了C语言的魅力,以下是根据s3c4510b_uart.c和s3c4510b_uart.h写的s3c2440的UART的驱动:
/*
* 相当经典的寄存器配置代码
* 根据s3c4510b代码改编
*/
#include "uart.h"
#define UART_BAUD_RATE 115200 //波特率
#define UART_CLK 50000000 //PCLK=50M,start.S中初始化
#define UART_BRD ((UART_CLK / (UART_BAUD_RATE * 16)) - 1) //计算分频寄存器的值
static UART *uart;
/* flush serial input queue. returns 0 on success or negative error
* number otherwise
*/
static int serial_flush_input(void)
{
volatile u32 tmp;
/* keep on reading as long as the receiver is not empty */
while( uart->m_stat.bf.rxBufReady) {
tmp = uart->m_rx;
}
return 0;
}
/* flush output queue. returns 0 on success or negative error number
* otherwise
*/
static int serial_flush_output(void)
{
/* wait until the transmitter is no longer busy */
while( !uart->m_stat.bf.txBufEmpty);
return 0;
}
void serial_setbrg (void)
{
UART_LINE_CTRL ulctrl;
UART_CTRL uctrl;
UART_BAUD_DIV ubd;
GPHCON |= 0xa0; // GPH2,GPH3用作TXD0,RXD0
GPHUP = 0x0c; // GPH2,GPH3内部上拉
serial_flush_output();
serial_flush_input();
/*
* refer to s3c2440 manual, and configure them
* some other register use default(initial) values
* some are readonly register such as, status register
*/
/* control register */
uctrl.ui = 0x0; //ui和bf共享内存,清零
uctrl.bf.rxMode = 0x1; //设置接收模式:中断请求或论询方式
uctrl.bf.txMode = 0x1; //设置发送模式:中断请求或论询方式
uctrl.bf.sendBreak = 0x0; //正常传输模式
uctrl.bf.loopBack = 0x0; //正常操作模式
uctrl.bf.rxError = 0x0; //不产生接收错误中断
uctrl.bf.rxTimeout = 0x0; //禁止接收超时中断
uctrl.bf.rxIntType = 0x0; //脉冲
uctrl.bf.txIntType = 0x0; //脉冲
uctrl.bf.clk = 0x0; //PCLK作波特率时钟源
uctrl.bf.fclkDiv = 0x0; //
uart->m_ctrl.ui = uctrl.ui;
/* line control register */
ulctrl.ui = 0x0; //ui和bf共享内存,清零
ulctrl.bf.wordLen = 0x3; //8bit 数据位
ulctrl.bf.nStop = 0x0; //1bit 停止位
ulctrl.bf.parity = 0x0; //无校验位
ulctrl.bf.infra_mod = 0x0; //常规模式
uart->m_lineCtrl.ui = ulctrl.ui;//设置好后,保存
/* baudrate set */
ubd.ui = 0x0;
ubd.bf.div = UART_BRD;
uart->m_baudDiv.ui = ubd.ui;
}
/*
* Initialise the serial port with the given baudrate. The settings
* are always 8 data bits, no parity, 1 stop bit, no start bits.
*
*/
int serial_init (void)
{
uart = (UART *)UART0_BASE; //UART有很多寄存器,只需要把UART0基址给,uart指针就行
serial_setbrg ();
return (0);
}
/*
* Output a single byte to the serial port.
*/
void serial_putc (const char c)
{
/* wait for room in the transmit FIFO */
while( !uart->m_stat.bf.txBufEmpty);
uart->m_tx = c;
/*
to be polite with serial console add a line feed
to the carriage return character
*/
if (c=='\n')
serial_putc('\r');
}
/*
* Test if an input byte is ready from the serial port. Returns non-zero on
* success, 0 otherwise.
*/
int serial_tstc (void)
{
return uart->m_stat.bf.rxBufReady;
}
/*
* Read a single byte from the serial port. Returns 1 on success, 0
* otherwise. When the function is succesfull, the character read is
* written into its argument c.
*/
int serial_getc (void)
{
int rv;
for(;;) {
rv = serial_tstc();
if (rv) {
return uart->m_rx & 0xFF;
}
}
}
void serial_puts (const char *s)
{
while (*s) {
serial_putc (*s++);
}
/* busy wait for tx complete */
while ( !uart->m_stat.bf.txBufEmpty);
/* clear break */
uart->m_ctrl.bf.sendBreak = 0;
}
头文件uart.h:
#ifndef __UART_H
#define __UART_H
#ifndef u16
#define u16 unsigned short
#endif
#ifndef u32
#define u32 unsigned int
#endif
#ifndef u8
#define u8 unsigned char
#endif
/*UART0基址,寄存器的配置按基址偏移来赋值的*/
#define UART0_BASE 0x50000000
/* UART0复用GPH口引脚,必须进行功能配置 */
#define GPHCON (*(volatile unsigned long *)0x56000070)
#define GPHDAT (*(volatile unsigned long *)0x56000074)
#define GPHUP (*(volatile unsigned long *)0x56000078)
/* UART LINE CONTROL register */
typedef struct __BF_UART_LINE_CTRL {
u32 wordLen: 2;
u32 nStop: 1;
u32 parity: 3;
u32 infra_mod: 1;
u32 unused:25;
} BF_UART_LINE_CTRL;//note:ocupy 4byte=32bits
typedef union _UART_LINE_CTRL {
u32 ui;
BF_UART_LINE_CTRL bf;
} UART_LINE_CTRL; //note:union 4bytes,利用联合体共享内存
/* UART CONTROL register */
typedef struct __BF_UART_CTRL {
u32 rxMode: 2;
u32 txMode: 2;
u32 sendBreak: 1;
u32 loopBack: 1;
u32 rxError: 1;
u32 rxTimeout: 1;
u32 rxIntType: 1;
u32 txIntType: 1;
u32 clk: 2;
u32 fclkDiv: 4;
u32 unused: 16;
} BF_UART_CTRL;
typedef union _UART_CTRL {
u32 ui;
BF_UART_CTRL bf;
} UART_CTRL;
/* UART FIFO register */
typedef struct __BF_UART_FIFO {
u32 fifoEnable: 1;
u32 rxFifoReset: 1;
u32 txFifoReset: 1;
u32 reserved: 1;
u32 rxFifoTriL: 2;
u32 txFifoTriL: 2;
u32 unused: 24;
} BF_UART_FIFO;
typedef union _UART_FIFO {
u32 ui;
BF_UART_FIFO bf;
} UART_FIFO;
/* UART MODE register */
typedef struct __BF_UART_MODE {
u32 reqToSend: 1;
u32 reserved1: 3;
u32 afc: 1;
u32 reserved2: 3;
u32 unused: 24;
} BF_UART_MODE;
typedef union _UART_MODE {
u32 ui;
BF_UART_MODE bf;
} UART_MODE;
/* UART rx/tx status register */
typedef struct __BF_UART_STAT {
u32 rxBufReady: 1;
u32 txBufEmpty: 1;
u32 txEmpty: 1;
u32 unused: 29;
} BF_UART_STAT;
typedef union _UART_STAT {
u32 ui;
BF_UART_STAT bf;
} UART_STAT;
/* UART error status register */
typedef struct __BF_UART_RX_ERR {
u32 overturn: 1;
u32 parity: 1;
u32 frame: 1;
u32 breakDec: 1;
u32 unused: 28;
} BF_UART_RX_ERR;
typedef union _UART_RX_ERR {
u32 ui;
BF_UART_RX_ERR bf;
} UART_RX_ERR;
/*UART FIFO status register*/
typedef struct __BF_UART_FIFO_STAT {
u32 rxcnt: 6;
u32 rxfull: 1;
u32 reserved1: 1;
u32 txcnt: 6;
u32 txfull: 1;
u32 reserved2: 1;
u32 unused: 16;
} BF_UART_FIFO_STAT;
typedef union _UART_FIFO_STAT {
u32 ui;
BF_UART_FIFO_STAT bf;
} UART_FIFO_STAT;
/*UART mode status register*/
typedef struct __BF_UART_MOD_STAT {
u32 clearSend: 1;
u32 reserved: 3;
u32 DeltaCTS: 1;
u32 unused: 27;
} BF_UART_MOD_STAT;
typedef union _UART_MOD_STAT {
u32 ui;
BF_UART_MOD_STAT bf;
} UART_MOD_STAT;
/* UART BAUD_DIV register */
typedef struct __BF_UART_BAUD_DIV {
u32 div: 16;
u32 unused:16;
} BF_UART_BAUD_DIV;
typedef union _UART_BAUD_DIV {
u32 ui;
BF_UART_BAUD_DIV bf;
} UART_BAUD_DIV;
/* UART register block */
typedef struct __UART {
volatile UART_LINE_CTRL m_lineCtrl;
volatile UART_CTRL m_ctrl;
volatile UART_FIFO m_fifo;
volatile UART_MODE m_mode;
volatile UART_STAT m_stat;
volatile UART_RX_ERR m_rx_err;
volatile UART_FIFO_STAT m_fifo_stat;
volatile UART_MOD_STAT m_mod_stat;
volatile u32 m_tx;
volatile u32 m_rx;
volatile UART_BAUD_DIV m_baudDiv;
} UART;
#define NL 0x0A
#define CR 0x0D
#define BSP 0x08
#define ESC 0x1B
#define CTRLZ 0x1A
#define RUBOUT 0x7F
#endif
版权声明:本文为psc928624742原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。