zoukankan      html  css  js  c++  java
  • TQ210裸机编程(6)——UART(1)

    S5PV210包含4个异步收发器(UART),提供4个独立的异步串行输入/输出(I/O)端口。所有端口可工作于中断模式或DMA模式。提供高达3Mbps的位速率。每个UART包含2个FIFO用于接收和发送数据。

    具有可编程的波特率、红外收发、1位或2位停止位、5~8位数据位、校验。


    UART框图如下:

    数据发送:要发送的数据帧是可编程的。它包含1位起始位,5~8位数据位,1个选项校验位,1或2位停止位,这些都通过ULCONn寄存器来设置。在FIFO模式下发送器将要发送的数据发送给Tx FIFO,在非FIFO模式下,发送器将要发送的数据发送给Tx保持寄存器

    数据接收:和数据发送类似。


    串口编程操作步骤:

    1、配置时钟,选择时钟源

    2、配置ULCONn寄存器:设置数据位、停止位校验位、模式

    3、配置UCONn寄存器:设置数据接收和发送模式、时钟源

    3、设置UFCONn:启用或静止FIFO

    4、配置UBRDIVn和UDIVSLOTn:计算波特率

    5、发送数据:等待发送器为空,将要发送的8位数据赋给发送缓存寄存器UTXHn

    6、接收数据:等待接收缓冲区有数据可读,从接收缓存寄存器URXHn中取出数据。


    波特率计算:

    DIV_VAL = UBRDIVn + (num of 1's in UDIVSLOTn)/16
    DIV_VAL = (PCLK / (bps x 16)) −1
    或者
    DIV_VAL = (SCLK_UART / (bps x 16)) −1

    比如配置波特率为115200bps,时钟源选择PCLK=66MHz

    DIV_VAL = (66000000/(115200 x 16))-1 = 35.8 - 1 = 34.8
    UBRDIV0 = 34 (DIV_VAL的整数部分)
    (num of 1's in UDIVSLOTn)/16 = 0.8 (DIV_VAL的小数部分)
    (num of 1's in UDIVSLOTn) = 12
    UDIVSLOT0 = 0xDDDD (查表)



    实验效果:

    按数字1则改变LED1的状态;按数字2改变LED2的状态。


    代码:

    start.S

    .global _start				/* 声明一个全局的标号 */
    _start:
    	bl clock_init			/* 时钟初始化 */
    	bl uart_init			/* 串口初始化 */
    	bl main					/* 跳转到C函数去执行 */
    halt:
    	b halt
    

    clock.c

    #define APLLCON0		*((volatile unsigned int *)0xE0100100)
    #define MPLLCON			*((volatile unsigned int *)0xE0100108)
    #define EPLLCON0		*((volatile unsigned int *)0xE0100110)
    #define VPLLCON			*((volatile unsigned int *)0xE0100120)
    #define CLK_SRC0 		*((volatile unsigned int *)0xE0100200)
    #define CLK_DIV0		*((volatile unsigned int *)0xE0100300)
    #define CLK_DIV1		*((volatile unsigned int *)0xE0100304)
    #define CLK_DIV2		*((volatile unsigned int *)0xE0100308)
    #define CLK_DIV3		*((volatile unsigned int *)0xE010030C)
    
    void clock_init()
    {
    	/* 1、设置PLL_LOCK寄存器(这里使用默认值) */
    	/* 2、设置PLL_CON寄存器(使用芯片手册推荐的值) */
    	APLLCON0	= (1 << 0) | (3 << 8) | (125 << 16) | (1 << 31);	/* FOUTAPLL = 1000MHz */
    	MPLLCON 	= (1 << 0) | (12 << 8) | (667 << 16) | (1 << 31);	/* FOUTMPLL = 667MHz */
    	EPLLCON0 	= (1 << 0) | (12 << 8) | (667 << 16) | (1 << 31);	/* FOUTEPLL = 96MHz */
    	VPLLCON 	= (3 << 0) | (6 << 8) | (108 << 16) | (1 << 31);	/* FOUTVPLL = 54MHz */
    	
    	/* 3、选择PLL为时钟输出 */
    	/* MOUT_MSYS = SCLKAPLL = 1000MHz
    	** MOUT_DSYS = SCLKMPLL = 667MHz
    	** MOUT_PSYS = SCLKMPLL = 667MHz
    	*/
    	CLK_SRC0 = (1 << 0) | (1 << 4) | (1 << 8) | (1 << 12);
    	
    	/* 4、设置系统时钟分频值 */
    	/* freq(ARMCLK) = MOUT_MSYS / (APLL_RATIO + 1) = 1000MHz / (0 + 1) = 1000MHz
    	** freq(HCLK_MSYS) = ARMCLK / (HCLK_MSYS_RATIO + 1) = 1000MHz / (4 + 1) = 200MHz
    	** freq(PCLK_MSYS) = HCLK_MSYS / (PCLK_MSYS_RATIO + 1) = 200MHz / (1 + 1) = 100MHz
    	** freq(HCLK_DSYS) = MOUT_DSYS / (HCLK_DSYS_RATIO + 1) = 667 / (3 + 1) = 166MHz
    	** freq(PCLK_DSYS) = HCLK_DSYS / (PCLK_DSYS_RATIO + 1) = 166 / (1 + 1) = 83MHz
    	** freq(HCLK_PSYS) = MOUT_PSYS / (HCLK_PSYS_RATIO + 1) = 667 / (4 + 1) = 133MHz
    	** freq(PCLK_PSYS) = HCLK_PSYS / (PCLK_PSYS_RATIO + 1) = 133 / (1 + 1) = 66MHz
    	*/
    	CLK_DIV0 = (0 << 0) | (4 << 8) | (1 << 12) | (3 << 16) | (1 << 20) | (4 << 24) | (1 << 28);
    }


    uart.c

    #define GPA0CON		*((volatile unsigned int *)0xE0200000)
    #define ULCON0 		*((volatile unsigned int *)0xE2900000)
    #define UCON0 		*((volatile unsigned int *)0xE2900004)
    #define UFCON0 		*((volatile unsigned int *)0xE2900008)
    #define UTRSTAT0 	*((volatile unsigned int *)0xE2900010)
    #define UTXH0  		*((volatile unsigned int *)0xE2900020)
    #define URXH0 		*((volatile unsigned int *)0xE2900024)
    #define UBRDIV0 	*((volatile unsigned int *)0xE2900028)
    #define UDIVSLOT0	*((volatile unsigned int *)0xE290002C)
    
    /*
    ** UART0初始化
    */
    void uart_init()
    {
    	/*
    	** 配置GPA0_0为UART_0_RXD
    	** 配置GPA0_1为UART_0_TXD
    	*/
    	GPA0CON &= ~0xFF;
    	GPA0CON |= 0x22;
    
    	/* 8-bits/One stop bit/No parity/Normal mode operation */
    	ULCON0 = 0x3 | (0 << 2) | (0 << 3) | (0 << 6);
    
    	/* Interrupt request or polling mode/Normal transmit/Normal operation/PCLK/*/
    	UCON0 = 1 | (1 << 2) | (0 << 10);
    
    	/* 静止FIFO */
    	UFCON0 = 0;
    
    	/*
    	** 波特率计算:115200bps
    	** PCLK = 66MHz
    	** DIV_VAL = (66000000/(115200 x 16))-1 = 35.8 - 1 = 34.8
    	** UBRDIV0 = 34 (DIV_VAL的整数部分)
    	** (num of 1's in UDIVSLOTn)/16 = 0.8
    	** (num of 1's in UDIVSLOTn) = 12
    	** UDIVSLOT0 = 0xDDDD (查表)
    	*/
    	UBRDIV0 = 34;
    	UDIVSLOT0 = 0xDDDD;
    }
    
    void uart_send_byte(unsigned char byte)
    {
    	while (!(UTRSTAT0 & (1 << 2)));	/* 等待发送缓冲区为空 */
    	UTXH0 = byte;					/* 发送一字节数据 */		
    }
    
    unsigned char uart_recv_byte()
    {
    	while (!(UTRSTAT0 & 1));	/* 等待接收缓冲区有数据可读 */
    	return URXH0;				/* 接收一字节数据 */		
    }
    
    void uart_send_string(char *str)
    {
    	char *p = str;
    	while (*p)
    		uart_send_byte(*p++);
    }


    main.c

    #define GPC0CON		*((volatile unsigned int *)0xE0200060)
    #define GPC0DAT		*((volatile unsigned int *)0xE0200064)
    
    void delay(volatile unsigned int t)
    {
    	volatile unsigned int t2 = 0xFFFF;
    	while (t--)
    		for (; t2; t2--);
    }
    
    int main()
    {
    	int byte;
    
    	GPC0CON &= ~(0xFF << 12);
    	GPC0CON |= 0x11 << 12;		// 配置GPC0_3和GPC0_4为输出
    	GPC0DAT &= ~(0x3 << 3);		// 熄灭LED1和LED2
    
    	uart_send_string("
    UART Test in S5PV210
    ");
    
    	while (1)
    	{
    		uart_send_string("
    1.LED1 Toggle
    ");
    		uart_send_string("
    2.LED2 Toggle
    ");
    		uart_send_string("
    Please select 1 or 2 to Toggle the LED
    ");
    		byte = uart_recv_byte();
    		uart_send_byte(byte);
    
    		if (byte == '1')
    			GPC0DAT ^= 1 << 3;		// 改变LED1的状态
    		else if (byte == '2')
    			GPC0DAT ^= 1 << 4;		// 改变LED2的状态
    	}
    	return 0;
    }


    Makefile

    uart.bin: start.o clock.o uart.o main.o
    	arm-linux-ld -Ttext 0xD0020010 -o uart.elf $^
    	arm-linux-objcopy -O binary uart.elf $@
    	arm-linux-objdump -D uart.elf > uart.dis
    	
    %.o : %.c
    	arm-linux-gcc -c $< -o $@
    %.o : %.S
    	arm-linux-gcc -c $< -o $@
    	
    clean:
    	rm *.o *.elf *.bin *.dis
    


    程序烧写步骤见前面章节。

    转载请注明来源:http://blog.csdn.net/zjhsucceed_329/

  • 相关阅读:
    centos添加图形桌面
    centos 复制并重命名文件
    山东省第八届ACM程序设计大赛总结
    RMQ
    图的深度优先搜索
    ACM知识点清单
    优先队列(priority_queue)
    Contest Print Server
    k8s之证书签发(二)
    k8s环境之bind 9 (一)
  • 原文地址:https://www.cnblogs.com/phisy/p/3371876.html
Copyright © 2011-2022 走看看