uboot下的UART驱动

  • Post author:
  • Post category:其他



今天解决了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 版权协议,转载请附上原文出处链接和本声明。