Tiny6410裸机开发笔记(七)串口设置之输入输出字符

1. S3C6410 UART

S3C6410 的 UART 提供了四个独立的异步串行 I / O (SIO)端口。每个异步串行 I/O(SIO)端口通过中断或者直接存储器存取(DMA)模式来操作。该 UART 使用系统时钟的时间可以支持的比特率最高为 115.2kb/s。每个UART 的通道包含了两个 64 字节收发 FIFO 存储器。

每个UART包含波特率发生器、发送器、接收器和控制单元,波特率发生器的时钟源可以由PCLK, EXT_UCLK0或EXT_UCLK1产生。发送器和接收器包含64字节FIFO和数据移位器。数据写入FIFO,然后复制到发送移位之前被传输。然后数据被传输数据管脚(TxDn)移出。同时,对接收到的数据进行移位从接收数据引脚(RxDn),然后复制到FIFO从移位器。
UART
UART 使用标准的TTL/CMOS 逻辑电平来表示数据,为了增强数据抗干扰能力和提高传输长度,通常将TTL/CMOS 逻辑电平转换为RS-232 逻辑电平,查看原理图可知Tiny6410 使用的是SP3232 芯片,使用的是TX0 和RX0:
UART原理图
UART引脚连线图
通过设置UART 相关寄存器,我们就可以驱动UART 工作,达到发送和接收字符的目的。

2. 代码编写

2.1 start.S


.global _start

_start: 
		
	//外设基地址及大小告诉CPU
	ldr r0, =0x70000000							//ldr: load
	orr r0, r0, #0x13 							//0x13=b10011=256M, 参见arm1176jzfs内核参考手册Page3-130
	mcr p15,0,r0,c15,c2,4       				//把r0的值(包括了外设基地址+外设大小)告诉cpu
	
	//关看门狗
	ldr r0, =0x7E004000							//watch dog timer base address
	mov r1, #0
	str r1, [r0]								//disable watch dog.  str: Store
	
	//设置栈
	ldr sp, =0x0C002000							//S3C6410 的内部8K 的SRAM 被映射到0X0C000000,而ARM 默认的栈是递减的,所以可以让SP 指向0X0C002000
	
	//打开icache
	orr	r0, r0, #0x00001000						@ set bit 12 (I) I-cache
	mcr	p15, 0, r0, c1, c0, 0	
	
	// 设置时钟
	bl clock_init
	
	//调用C函数点灯
	bl  main
	
halt:
	b   halt
	

2.2 clock.c


#define APLL_LOCK (*((volatile unsigned long *)0x7E00F000))
#define MPLL_LOCK (*((volatile unsigned long *)0x7E00F004))
#define EPLL_LOCK (*((volatile unsigned long *)0x7E00F008))

#define OTHERS    (*((volatile unsigned long *)0x7e00f900))

#define CLK_DIV0  (*((volatile unsigned long *)0x7E00F020))

#define ARM_RATIO    0   						// ARMCLK 	= DOUTAPLL / (ARM_RATIO + 1)  	= 532/(0+1) = 532  MHz
#define MPLL_RATIO   0   						// DOUTMPLL = MOUTMPLL / (MPLL_RATIO + 1)   = 532/(0+1) = 532  MHz
#define HCLKX2_RATIO 1   						// HCLKX2 	= HCLKX2IN / (HCLKX2_RATIO + 1) = 532/(1+1) = 266  MHz
#define HCLK_RATIO   1   						// HCLK 	= HCLKX2   / (HCLK_RATIO + 1)   = 266/(1+1) = 133  MHz
#define PCLK_RATIO   3   						// PCLK   	= HCLKX2   / (PCLK_RATIO + 1)   = 266/(3+1) = 66.5 MHz

// ARMCLK:	CPU时钟
// HCLK:	AXI/AHB总线外设时钟(MFC、CAM、TV、LCD、MMC、USB、DMA、SDMA)
// PCLK: 	APB总线外设时钟(GPIO、WDT、UART、PCM、IrDA、ADC、IIC、KeyPAD、RTC)


#define CLK_DIV0_VAL	((ARM_RATIO) | (MPLL_RATIO << 4) | (HCLK_RATIO << 8) | (HCLKX2_RATIO << 9) | (PCLK_RATIO << 12))

//CLK_DIV0:
/*=====================================================================================================================================*/
/* [31:28]	[27:24]		[23:20]		[19:18]		[17:16]		[15:12]		[11:9]			[8]			[7:5]		[4]			[3:0]	   */
/* CLKMFC	CLKJPEG		CLKCAM		CLKSECUR	RESERVED	PCLK_RATIO	HCLKX2_RATIO	HCLK_RATIO	RESERVED	MPLL_RATIO	ARM_RATIO  */
/*=====================================================================================================================================*/


#define APLL_CON  (*((volatile unsigned long *)0x7E00F00C))
#define APLL_CON_VAL  ((1<<31) | (266 << 16) | (3 << 8) | (1))	//PLL=1, MDIV=266, PDIV=3, SDIV=1	

/*APLL_CON: 
/*============================================================================*/
/* [31] 		[30:26] 	[25:16] 	[15:14] 	[13:8] 	[7:3] 		[2:0] */
/* PLL enable	Reserved	MDIV		Reserved	PDIV	Reserved	SDIV  */
/*============================================================================*/

// Equation:
// FOUT = MDIV * FIN / (PDIV * 2^SDIV)

//Recommend Values:
/*========================================================*/
/* FIN(MHz)		Target FOUT(MHz)	MDIV	PDIV	SDIV  */
/* 12				   533			266		3		1	  */
/*========================================================*/

#define MPLL_CON  (*((volatile unsigned long *)0x7E00F010))
#define MPLL_CON_VAL  ((1<<31) | (266 << 16) | (3 << 8) | (1))  //PLL=1, MDIV=266, PDIV=3, SDIV=1

/*MPLL_CON: 
/*============================================================================*/
/* [31] 		[30:26] 	[25:16] 	[15:14] 	[13:8] 	[7:3] 		[2:0] */
/* PLL enable	Reserved	MDIV		Reserved	PDIV	Reserved	SDIV  */
/*============================================================================*/

// Equation:
// FOUT = MDIV * FIN / (PDIV * 2^SDIV)

//Recommend Values:
/*========================================================*/
/* FIN(MHz)		Target FOUT(MHz)	MDIV	PDIV	SDIV  */
/* 12				   533			266		3		1	  */
/*========================================================*/


#define CLK_SRC  (*((volatile unsigned long *)0x7E00F01C))


void clock_init(void)
{	
	/* 1. 设置各PLL的LOCK_TIME,使用默认值 */

	APLL_LOCK = 0xffff;							// APLL_LOCK,供cpu使用 
	MPLL_LOCK = 0xffff;							// MPLL_LOCK,供AHB(存储/中断/lcd等控制器)/APB(看门狗,定时器,SD等)总线上的设备使用
	EPLL_LOCK = 0xffff;							// EPLL_LOCK,供UART,IIS,IIC使用 

	/* 2. 设置为异步模式(Asynchronous mode) */

	OTHERS &= ~0xc0;							//《linux installation for u-boot》3.7中:用MPLL作为HCLK和PCLK的Source是异步(ASYNC)模式,用APLL是同步(SYNC)模式
	while ((OTHERS & 0xf00) != 0);


	/* 3. 设置分频系数 */

	CLK_DIV0 = CLK_DIV0_VAL;
	
	/* 4. 设置PLL,放大时钟 */ 

	APLL_CON = APLL_CON_VAL;  
	MPLL_CON = MPLL_CON_VAL;  
	
	/* 5. 选择PLL的输出作为时钟源 */

	CLK_SRC = 0x03;

}


2.3 uart

2.3.1 uart.h

void putchar(char c);
char getchar(void);
void putstr(char * str);
void uart_init(void);

2.3.2 uart.c

// 功能:初始化串口
#include "uart.h" 
#define GPACON  	(*((volatile unsigned long *)0x7F008000))
#define GPADAT  	(*((volatile unsigned long *)0x7F008004))

#define ULCON0  	(*((volatile unsigned long *)0x7F005000))
#define UCON0   	(*((volatile unsigned long *)0x7F005004))
#define UFCON0  	(*((volatile unsigned long *)0x7F005008))
#define UMCON0  	(*((volatile unsigned long *)0x7F00500C))

#define UFSTAT0 	(*((volatile unsigned long *)0x7F005018))
#define UTXH0 		(*((volatile unsigned long *)0x7F005020))
#define URXH0	 	(*((volatile unsigned long *)0x7F005024))
#define UBRDIV0	 	(*((volatile unsigned long *)0x7F005028))
#define UDIVSLOT0	(*((volatile unsigned long *)0x7F00502C))


void uart_init(void)
{
	/* 1. 配置引脚 */

	GPACON &= ~0xff;
	GPACON |= 0x22;					//GPA0=b0010=UART RXD[0]; GPA1=b0010=UART TXD[0]

	/* 2. 设置数据格式 */

	ULCON0 = 0x03;					//Normal mode,No Parity, 1 stop bit, 8-bit

	//ULCON0:
	/*===============================================================*/
	/* [7]			[6]			[5:3]		[2]			[1:0]		 */
	/* Reserved		Infra-Red	Parity		Stop Bit	Word Length	 */
	/*===============================================================*/
	// Infra-Red: 0=Normal, 1=Infra-Red Tx/Rx Mode
	// Parity: 0xx=No Parity, 100=Odd, 101=Even
	// Number of Stop Bit: 0=One Stop Bit, 1=Two Stop Bit
	// Word Length: 00=5-bit, 01=6-bit, 10=7-bit 11=8-bit

	/* 3. 设置时钟 */

	UCON0 = 0x05;					// b0000000000101, Clock = PCLK, Disalbe all interrupts, Interrupt or Polling mode

	//UCON0:
	/*===========================================================================================================*/
	/* [11:10]		[9]		[8]		[7]			[6]					[5]			[4]			[3:2]		[1:0]	 */
	/* Clock		Tx Int 	Rx Int  Rx Time 	Rx Error Status 	Loop-back	Send Break	Transmit	Receive	 */
	/* Selection	Type	Type	Out Enalbe	Interrupt Enable	Mode		Signal		Mode		Mode	 */
	/*===========================================================================================================*/

	// Clock Selection:
	// Select PCLK or EXT_UCLK04) or EXT_UCLK14) clock for the UART baud rate.
	// x0 = PCLK : DIV_VAL = (PCLK / (bps x 16) ) -1
	// 01 = EXT_UCLK0: DIV_VAL1) = (EXT_UCLK0 / (bps x 16) ) –1
	// 11 = EXT_UCLK1: DIV_VAL1) = (EXT_UCLK1 / (bps x 16) ) –1

	// Tx Interrupt Type:
	// Interrupt request type.
	// 0 = Pulse (Interrupt is requested as soon as the Tx buffer becomes empty in Non-FIFO mode or reaches Tx FIFO Trigger Level in FIFO mode.)
	// 1 = Level (Interrupt is requested while Tx buffer is empty in Non-FIFO mode or reaches Tx FIFO Trigger Level in FIFO mode.)

	// Rx Interrupt Type:
	// Interrupt request type.
	// 0 = Pulse (Interrupt is requested the instant Rx buffer receives the data in Non-FIFO mode or reaches Rx FIFO Trigger Level in FIFO mode.)
	// 1 = Level (Interrupt is requested while Rx buffer is receiving data in Non-FIFO mode or reaches Rx FIFO Trigger Level in FIFO mode.)

	// Rx Time Out Enable:
	// Enable/Disable Rx time-out interrupts when UART FIFO is enabled.
	// The interrupt is a receive interrupt. 
	// 0 = Disable 1 = Enable

	// Rx Error Status Interrupt Enable:
	// Enable the UART to generate an interrupt upon an exception, such as a break, frame error, parity error, or overrun error during a receive operation.
	// 0 = Do not generate receive error status interrupt.
	// 1 = Generate receive error status interrupt.

	// Loop-back Mode:
	// Setting loop-back bit to 1 cause the UART to enter the loop-back mode. This mode is provided for test purposes only.
	// 0 = Normal operation 1 = Loop-back mode

	// Send Break Signal:
	// Setting this bit causes the UART to send a break during 1 frame time. This bit is automatically cleared after sending the break signal.
	// 0 = Normal transmit 1 = Send break signal

	// Transmit Mode:
	// Determine which function is currently able to write Tx data to the UART transmit buffer register.
	// 00 = Disable
	// 01 = Interrupt request or polling mode
	// 10 = DMA request (DMA_UART0)
	// 11 = DMA request (DMA_UART1)

	// Receive Mode:
	// Determine which function is currently able to read data from UART receive buffer register.
	// 00 = Disable
	// 01 = Interrupt request or polling mode
	// 10 = DMA request (DMA_UART0)
	// 11 = DMA request (DMA_UART1)

	/* 4. 设置FIFO */

	UFCON0 = 0x01;					// b00000001, FIFO Enable

	//UFCON0:
	/*===============================================================================*/
	/* [7:6]			[5:4]			[3]			[2]			[1]			[0]	     */
	/* Tx FIFO			Rx FIFO			Reserved	Tx FIFO		Rx FIFO		FIFO	 */
	/* Trigger Level	Trigger Level				Reset		Reset		Enalbe   */
	/*===============================================================================*/

	// Tx FIFO Trigger Level:
	// Determine the trigger level of transmit FIFO.
	// 00 = Empty 01 = 16-byte
	// 10 = 32-byte 11 = 48-byte

	// Rx FIFO Trigger Level:
	// Determine the trigger level of receive FIFO.1)
	// 00 = 1-byte 01 = 8-byte
	// 10 = 16-byte 11 = 32-byte

	// Tx FIFO Reset:
	// Auto-cleared after resetting FIFO
	// 0 = Normal 1= Tx FIFO reset

	// Rx FIFO Reset:
	// Auto-cleared after resetting FIFO
	// 0 = Normal 1= Rx FIFO reset

	// FIFO Enable:
	// 0 = Disable 1 = Enable

	/* 5. 设置控制流 */

	UMCON0 = 0;					//无控制流

	/* 6. 设置波特率 */

	UBRDIV0 = 35;
	UDIVSLOT0 = 0x1;
	
	// PCLK : DIV_VAL	= (PCLK / (bps x 16) ) -1
	//					= (66.5M/(115200*16))-1
	//					= 36.08 -1
	//					= 35.08
	// UBRDIV0 = 35
	// (num of 1’s in UDIVSLOT0)/16 = 0.08
	// then, (num of 1’s in UDIVSLOT0) = 1.28 = 1
	// so, UDVISLOT0 = 0x1
	
	
}


/* 接收一个字符 */
char getchar(void)
{
	while ((UFSTAT0 & 0x7f) == 0);    // 如果RX FIFO空,等待; 否则,只要有数据,取出
	return URXH0;                     // 取数据 
}

//UFSTATn:
/*========================================================================================*/
/* [15]			[14] 			[13:8] 			[7] 		[6] 			[5:0]		  */
/* Reserved		Tx FIFO Full 	Tx FIFO Count	Reserved	Rx FIFO Full	Rx FIFO Count */
/*========================================================================================*/

// Tx FIFO Full
// Set to 1 automatically whenever transmit FIFO is full
// during transmit operation
// 0 = 0-byte ≤ Tx FIFO data ≤ 63-byte
// 1 = Full

// Rx FIFO Full
// Set to 1 automatically whenever receive FIFO is full during
// receive operation
// 0 = 0-byte ≤ Rx FIFO data ≤ 63-byte
// 1 = Full

// 当RX FIFO空时, 	Bit[6] == 0, Bit[5:0] == 000000, Bit[7:0]== b00000000 == 0x00
// 当Rx FIFO满时, 	Bit[6] == 1, Bit[5:0] == 111111,Bit[7:0]== b01111111 == 0x7f
// Rx FIFO非空非满:Bit[6] == 0, Bit[5:0] == 0xxxxx,Bit[7:0]== b00xxxxxx

/* 发送一个字符 */
void putchar(char c)
{
	while (UFSTAT0 & (1<<14)); 		// 如果TX FIFO满,等待; 否则,只要未满,继续发送数据
	UTXH0 = c;                      // 写数据 
}


/* 发送一个字符串 */

void putstr(char * str)
{
	while (*str) {
		putchar(*str++);
	}
}

2.4 main.c

#include "uart.h"

int main()
{
	char c;
	
	uart_init();

	putstr("Uart Initialized!\n\r");
	while (1)
	{
		c = getchar();
		putchar(c);
	}
	
	return 0;
}

2.5 Makefile

uart.bin: start.o main.o uart.o clock.o
	arm-linux-ld -Ttext 0x50000000 -o uart.elf $^
	arm-linux-objcopy -O binary uart.elf uart.bin
	arm-linux-objdump -D uart.elf > uart.dis

%.o : %.S
	arm-linux-gcc -o $@ $< -c

%.o : %.c
	arm-linux-gcc -o $@ $< -c -fno-builtin 

clean:
	rm *.o *.elf *.bin *.dis  -rf

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值