在嵌入式中,UART是最常用的东西,作为串口输出和输入,是调试必不可少的东西。
S3C2440A Universal Asynchronous Receiver and Transmitter (UART) 提供3个独立的异步串口,每个均可运行在中断模式或者DMA模式。使用系统时钟,能支持最高921.6Kbps的波特率。如果外部设备提供EXTCLK时钟,则能运行在更高的速度。每个UART channel包含2个64字节的FIFO用于接收和发送。
包括可编程波特率,红外收发,一个或2个停止位,5/6/7/8位数据宽度,校验位。
每个UART包含一个baud-rate generator, transmitter, receiver和一个控制单元。波特率产生器可使用PCLK,FLCK/n 或者UEXTCLK。接收器和发送器包含64字节FIFO和data shifters。
Data Transmission
发送数据帧格式可编程。包含一个开始位,5-8位数据位,可选的校验位,和1-2位停止位。发送器可以产生break condition。
Data Reception
接收数据帧格式也是可编程的。接收器能检测overrun error, parity error, fram error, 和 break condtion,每一种都设置一个错误标志。
overrun error意味着新数据覆盖旧数据,在旧数据被读走之前。
parity error 意味着接收器检测到一个不期望的校验条件。
fram error 意味着接收数据没有一个合法的停止位。
break condition 意味着RxDn输入保持逻辑0状态超过一个传输帧时间。
当超过3个字时间没收到任何数据,或者FIFO模式下,Rx FIFO不为空时,接收超时条件发生。
Auto Flow Control (AFC)
UART0和UART1支持自动流控,通过nRTS和nCTS信号。发送者的nCTS接到接收者的nRTS,当nCTS由nRTS激活时,发送者才能发送数据。
Interrupt / DMA 请求产生
每个UART有7种状态信号:Overrun error, parity error, frame error, brea, receive buffer data ready, transmit buffer emty 和 transmit shifter empty。每一种都有对应的寄存器位。
overrun error, parity error, fram error, break condition 被当做是接收错误状态,每一个都产生接收错误状态中断请求。
当接收器将数据从receive shifter传送到Rx FIFO寄存器时,而且数量达到Rx FIFO触发水平,产生Rx中断。在非FIFO模式,将数据传送到接收保持寄存器引起Rx中断。
当发送器将数据从Tx FIFO寄存器传送到transmit shifter,而且FIFO中的数量少于Tx FIFO触发水平时,触发Tx中断。在非FIFO模式,从transmit holding register传送数据到transmit shifter将导致Tx中断。
如果是DMA模式,上述情况产生对应的DMA请求。
UART Error status FIFO
除了Rx FIFO,错误也有FIFO。error status FIFO表示FIFO寄存器中的哪个数据,以一个错误接收。错误中断只有在数据可以被读出时才产生。为了清除错误FIFO,必须读出UERSTATn和有错误的URXHn。
Buad-rate generation
波特率产生器位发送器和接收器提供串口时钟。波特率产生器的时钟源可以选择内部系统时钟,或者UEXTCLK。通过设置寄存器来获取对应的波特率:
UBRDIVn = (UART clock / (buad rate x 16)) - 1
UART Line control register
3个UART line控制寄存器,对应3个通道。
Register | address | R/W | desc | reset value |
ULCON0 | 0x50000000 | R/W | UART ch0 line control register | 0x0 |
ULCON1 | 0x50004000 | R/W | UART ch1 line control register | 0x0 |
ULCON2 | 0x50008000 | R/W | UART ch2 line control register | 0x0 |
ULCONn | Bit | Desc | Inisital state |
Reserved | [7] | 0 | |
Infrared Mode | [6] | Determine wether or not to use the Infrared mode. 0 = Normal mode operation 1 = Infrared Rx/Rx mode | |
Parity Mode | [5:3] | Specify the type of parity generation and checking during UART transmit and receive operation. 0xx = No parity 100 = Odd parity 101 = Even parity 110 = Parity forced / checked as 1 111 = Parity forced / checked as 0 | |
Number of stop bit | [2] | Specify how may stop bits are to be used for end-of-frame signal. 0 = One stop bit per frame 1 = Two stop bit per frame | |
Word length | [1:0] | Indiciate the number of data bits to be tx or rx per frame. 00 = 5-bits 01 = 6-bits 10 = 7-bits 11 = 8-bits |
UART control register
Register | address | R/W | desc | reset value |
UCON0 | 0x50000004 | R/W | UART ch0 control register | 0x0 |
UCON1 | 0x50004004 | R/W | UART ch1 control register | 0x0 |
UCON2 | 0x50008004 | R/W | UART ch2 control register | 0x0 |
UCONn | Bit | Desc | Initial state |
FCLK Divider | [15:12] | 设置是否使用FCLK/n,以及n的值。由3个通道的该字段共同决定。 UCON2[15] 是FCLK/n的开关。 n从7-21,使用UCON0[15:12] n从22-36,使用UCON1[15:12] n从37-43,使用UCON2[14:12] 使用一个时,其它两个必须为0. | |
Clock Selection | [11:10] | 00,10 = PCLK, 01 = UEXTCLK, 11 = FLCK/n 如果使用FCLK/n应当添加note中的代码。 | |
Tx Interrupt type | 9 | 0 = Pulse 1 = Level | |
Rx Interrupt type | 8 | 0 = Pulse 1 = Level | |
Rx Time out enable | 7 | Enable / disable Rx time out interrupt when UART FIFO is enable. The interrupt is a receive interrupt. 0 = disable 1 = enable | |
Rx error status interrupt enable | 6 | 0 = Do not generate 1 = generate | |
Loopback mode | 5 | 0 = NOrmal operation 1 = loopback mode | |
send break signal | 4 | 0 = Normal transmit 1 = send break signal | |
Transmit mode | 3:2 | 00 = Disable 01 = Interrupt request or polling mode 10 = DMA0 request for UART0 DMA3 request for UART2 11 = DMA1 request for UART1 | |
Receive Mode | 1:0 | 00 = Disable 01 = Interrupt request or polling mode 10 = DMA0 request for UART0 DMA3 request for UART2 11 = DMA1 request for UART1 |
UART FIFO control register
Register | address | R/W | desc | reset value |
UFCON0 | 0x50000008 | R/W | UART ch0 FIFO control register | 0x0 |
UFCON1 | 0x50004008 | R/W | UART ch1 FIFO control register | 0x0 |
UFCON2 | 0x50008008 | R/W | UART ch2 FIFO control register | 0x0 |
UFCONn | Bit | Desc | Initial state |
Tx FIFO Trigger Level | [7:6] | 00 = Empty 01 = 16Byte 10 = 32Byte 11 = 48Byte | |
Rx FIFO Trigger Level | [5:4] | 00 = 1Byte 01 = 8Byte 10 = 16Byte 11 = 32Byte | |
Reserved | 3 | ||
Tx FIFO reset | 2 | Auot-cleared after resetting FIFO 0 = Normal 1 = Tx FIFO Reset | |
Rx FIFO reset | 1 | Auot-cleared after resetting FIFO 0 = Normal 1 = Rx FIFO Reset | |
FIFO Enable | 0 | 0 = Disable 1 = Enable |
UART Modem control register
UART 2没有AFC功能。
Register | address | R/W | desc | reset value |
UMCON0 | 0x5000000C | R/W | UART ch0 FIFO control register | 0x0 |
UMCON1 | 0x5000400C | R/W | UART ch1 FIFO control register | 0x0 |
Reserved | 0x5000800C |
UMCONn | Bit | Desc | Initial State |
Reserved | [7:5] | Must be 0 | 0 |
Auto Flow Control (AFC) | [4] | 0 = disable, 1 = enable | 0 |
Reserved | [3:1] | must be 0 | 0 |
Request to send | [0] | If AFC bit is enabled, this value will be ignored. In this case the S3C2440A will control nRTS automatically. If AFC bit is disabled. nRTS must be controlled by software. 0 = H level (Inactivate nRTS) 1 = L level (Activate nRTS) | 0 |
UART TX/RX Status Register
Register | address | R/W | desc | reset value |
UTRSTAT0 | 0x50000010 | R | UART ch0 Tx/Rx status register | 0x6 |
UTRSTAT1 | 0x50004010 | R | UART ch1 Tx/Rx status register | 0x6 |
UTRSTAT2 | 0x50008010 | R | UART ch2 Tx/Rx status register | 0x6 |
UTRSTATn | Bit | Desc | Initial state |
Transmitter empty | [2] | Set to 1 automatically when the transmit buffer register has no valid data to transmit and the transmit shift register is empty. 0 = Not empty 1 = Transmitter (transmit buffer & shifter register) empty | 1 |
Transmit buffer empty | [1] | Set to 1 automatically when transmit buffer register is empty. 0 = The buffer register is not empty. 1 = Empty (In Non-FIFO mode, Interrupt or DMA is requested. In FIFO mode, Interrupt or DMA is requested, when Tx FIFO Trigger Level is set to 0) If the UART uses the FIFO, users should check Tx FIFO COunt bits and Tx FIFO Full bit in the UFSTAT register instead of this bit. | 1 |
Receive buffer data ready | [0] | Set to 1 automatically whenever receive buffer register contains valid data, received over the RXDn port. 0 = Empty 1 = The buffer resiger has a received data (In Non-FIFO mode, interrupt or DMA is requested) If the UART uses the FIFO, users should check Rx Fifo Count bits and Rx Fifo full bi in the UFSTAT register instead of this bit. | 0 |
UART Error Status register
Register | address | R/W | desc | reset value |
UERSTAT0 | 0x50000014 | R | UART ch0 Rx error register | 0x0 |
UERSTAT1 | 0x50004014 | R | UART ch1 Rx error register | 0x0 |
UERSTAT2 | 0x50008014 | R | UART ch2 Rx error register | 0x0 |
UERSTATn | Bit | Desc | Initial state |
Break Detect | [3] | 1 = Bread receive (Interrupt is requested) | 0 |
Frame Error | 2 | 1 = Frame error (Interrupt is requested) | 0 |
Parity Error | 1 | 1 = Parity error (Interrupt is requested) | 0 |
Overrun Error | 0 | 1 = Overrun error (Interrupt is requested) | 0 |
UART FIFO STATUS register
Register | address | R/W | desc | reset value |
UFSTAT0 | 0x50000018 | R | UART ch0 FIFO status register | 0x0 |
UFSTAT1 | 0x50004018 | R | UART ch1 FIFO status register | 0x0 |
UFSTAT2 | 0x50008018 | R | UART ch2 FIFO status register | 0x0 |
UFSTATn | Bit | Desc | Initial state |
Reserved | [15] | 0 | |
TX FIFO full | [14] | 0 = 0 <= Tx fifo data <= 63 1 = Full | 0 |
TX FIFO count | [13:8] | Number of data in Tx FIFO | 0 |
Reserved | 7 | 0 | |
RX FIFO FULL | 6 | 0 = 0 <= Tx fifo data <= 63 1 = Full | |
RX FIFO COUNT | [5:0] | Number of data in Rx FIFO |
UART modem status register
Register | address | R/W | desc | reset value |
UMSTAT0 | 0x5000001C | R | UART ch0 modem status register | 0x0 |
UMSTAT1 | 0x5000401C | R | UART ch1 modem status register | 0x0 |
Reserved | 0x5000801C |
UMSTATn | Bit | Desc | Initial state |
Delta CTS | [4] | Indicate that the nCTS input to the S3C2440A has changed state since that last time it was read by CPU. 0 = has not changed 1 = has changed | 0 |
reserved | [3:1] | ||
Clear to send | [0] | 0 = CTS signal is not activated (nCTS pin is high) 1 = CTS signal is actived (nCTS pin is low) |
UART transmit buffer register (Holading register & FIFO register)
Register | address | R/W | desc | reset value |
UTXH0 | 0x50000020(L) 0x50000023(H) | W (by byte) | UART ch0 transmit buffer register | |
UTXH1 | 0x50004020 0x50004023 | W (by byte) | UART ch1 transmit buffer register | |
UTXH2 | 0x50008020 0x50008023 | W (by byte) | UART ch2 transmit buffer register |
TXDATAn [7:0] Transmit data for UARTn
UART receive buffer register (Holding register & FIFO register)
Register | address | R/W | desc | reset value |
URXH0 | 0x50000024(L) 0x50000027(H) | W (by byte) | UART ch0 receive buffer register | |
URXH1 | 0x50004024 0x50004027 | W (by byte) | UART ch1 receive buffer register | |
URXH2 | 0x50008024 0x50008027 | W (by byte) | UART ch2 receive buffer register |
RXDATAn [7:0] receive data for UARTn
UART buad rate divisor register
Register | address | R/W | desc | reset value |
UBRDIV0 | 0x50000028 | R/W | Buad rate divisor register 0 | 0x0 |
UBRDIV1 | 0x50004028 | R/W | Buad rate divisor register 1 | 0x0 |
UBRDIV2 | 0x50008028 | R/W | Buad rate divisor register 2 |
UBRDIV [15:0] Baud rate division value UBRDIVn > 0
UBRDIVn = (clock / (baud rate x 16)) - 1
必须大于0,当时钟为UEXTCLK时,可以等于0.
使用中断,输入什么原封的显示到输出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 | // watchdog #define WTCON (*(volatile unsigned long *)0x53000000) #define WTDAT (*(volatile unsigned long *)0x53000004) #define WTCNT (*(volatile unsigned long *)0x53000008) #define GPFCON (*(volatile unsigned long *)0x56000050) #define GPFDAT (*(volatile unsigned char *)0x56000054) #define GPGCON (*(volatile unsigned long *)0x56000060) #define GPHCON (*(volatile unsigned long *)0x56000070) #define GPHUP (*(volatile unsigned long *)0x56000078) #define EINTMSK (*(volatile unsigned long *)0x560000a4) #define EINTPND (*(volatile unsigned long *)0x560000a8) #define EXTINT0 (*(volatile unsigned long *)0x56000088) #define EXTINT1 (*(volatile unsigned long *)0x5600008c) typedef unsigned long uint32_t; typedef unsigned char uint8_t; struct S3C2440_INT_CONT { uint32_t SRCPND; uint32_t INTMOD; uint32_t INTMSK; uint32_t PRIO; uint32_t INTPND; uint32_t INTOFFSET; uint32_t SUBSRCPND; uint32_t INTSUBMSK; }; volatile struct S3C2440_INT_CONT *intcont = ( volatile struct S3C2440_INT_CONT *)0x4a000000; struct S3C2440_CLK { uint32_t LOCKTIME; uint32_t MPLLCON; uint32_t UPLLCON; uint32_t CLKCON; uint32_t CLKSLOW; uint32_t CLKDIVN; uint32_t CAMDIVN; }; volatile struct S3C2440_CLK * clk = ( volatile struct S3C2440_CLK *)0x4c000000; struct S3C2440_UART { uint32_t ULCON; uint32_t UCON; uint32_t UFCON; uint32_t UMCON; uint32_t UTRSTAT; uint32_t UERSTAT; uint32_t UFSTAT; uint32_t UMSTAT; uint8_t UTXH; uint8_t unused1[3]; uint8_t URXH; uint8_t unused2[3]; uint32_t UBRDIV; }; volatile struct S3C2440_UART *uart_ch0 = ( volatile struct S3C2440_UART *)0x50000000; volatile struct S3C2440_UART *uart_ch1 = ( volatile struct S3C2440_UART *)0x50004000; volatile struct S3C2440_UART *uart_ch2 = ( volatile struct S3C2440_UART *)0x50008000; void disable_watchdog() { WTCON = 0; } void uart_init() { GPHCON = (2 << 4) | (2 << 6); // set gpio to RXD0/TXD0 GPHUP = (1 << 2) | (1 << 3); // SET PULL-up uart_ch0->ULCON = 0x3; // NO Parity | 1 Stop bit | 8N1 uart_ch0->UCON = (1<<7)|(1<<6)|(1<<2)|(1<<0); // Enable RX timeout, enable rx erro intr, uart_ch0->UFCON = (2<<6)|(2<<4)|(1<<0); uart_ch0->UMCON = 0; uart_ch0->UBRDIV = 400*1000*1000/6/16/115200; } void clk_init() { clk->CLKDIVN = (0x3 << 1) | 0x1; // HDIVN:11b, PDIVN, 1 asm volatile ( "mrc p15, 0, r1, c1, c0, 0\n\t" "orr r1, r1, #0xc0000000\n\t" "mcr p15, 0, r1, c1, c0, 0" : : : "r1" ); // according to datasheet, should set UPLLCON firstly. clk->UPLLCON = (56 << 12) | (2 << 4) | 2; // 48MHz clk->MPLLCON = (92 << 12) | (1 << 4) | 1; // 400MHz } void gpio_init() { #define set_gpio(r,v,n) r &= ~(3 << 2*n); r |= (v << 2*n) unsigned long r1 = GPFCON; unsigned long r2 = GPGCON; // 4,5,6 LED output mode set_gpio(r1,1,4); set_gpio(r1,1,5); set_gpio(r1,1,6); // 0(EINT0),2(EINT2) Button INT Mode set_gpio(r1,2,0); set_gpio(r1,2,2); // 3(EINT11) BUtton INT Mode set_gpio(r2,2,3); GPFCON = r1; GPGCON = r2; } int ledon[8]; void REVERT_LED( int led) { uint32_t reg = GPFDAT; if (ledon[led]) { ledon[led] = 0; reg |= (1 << led); } else { ledon[led] = 1; reg &= ~ (1 << led); } GPFDAT = reg; } void init_interrupt_controller() { // bit 28: INT_UART0 intcont->INTMSK = ~ (1 << 28); // INT_RXD0 : INT_TXD0 : INT_ERR0 intcont->INTSUBMSK = ~((1<<0)|(1<<1)|(1<<2)); } void init() { disable_watchdog(); clk_init(); init_interrupt_controller(); gpio_init(); uart_init(); GPFDAT = -1; asm volatile ( "msr cpsr_c, #0xd2\n\t" // enter IRQ mode "ldr sp, =3072\n\t" // set IRQ mode stack "msr cpsr_c, #0x53" ); // re-enter svc mode and enable IRQ and FIQ } #define DISABLE_IRQ() #define ENABLE_IRQ() char txbuf[100]; int tx_head = 0; int tx_tail = 0; char rxbuf[100]; int rx_head = 0; int rx_tail = 0; void schedule_w() { while ( tx_head != tx_tail && !(uart_ch0->UFSTAT & (1 << 14))) { uart_ch0->UTXH = txbuf[tx_tail]; tx_tail++; if (tx_tail == sizeof (txbuf)) tx_tail = 0; REVERT_LED(4); } } void schedule_r() { while ( ((rx_head == sizeof (rxbuf) -1 && rx_tail != 0) || (rx_head + 1 != rx_tail)) && (uart_ch0->UFSTAT & 0x1f)) { rxbuf[rx_head] = uart_ch0->URXH; rx_head++; if (rx_head == sizeof (rxbuf)) rx_head = 0; REVERT_LED(5); } } int read( char *buf, int len) { int n = 0; if (len <= 0) return len; DISABLE_IRQ(); while (n < len && rx_tail != rx_head) { buf[n] = rxbuf[rx_tail]; n++; rx_tail ++; if (rx_tail == sizeof (rxbuf)) rx_tail = 0; } schedule_r(); ENABLE_IRQ(); return n; } int write( char *buf, int len) { int n = 0; if (len <= 0) return len; DISABLE_IRQ(); while (n < len && ! ((tx_head == sizeof (txbuf)-1 && tx_tail == 0) || (tx_head + 1 == tx_tail))) { txbuf[tx_head] = buf[n]; n++; tx_head++; if (tx_head == sizeof (txbuf)) tx_head = 0; } schedule_w(); ENABLE_IRQ(); return n; } void main() { char buf[100]; write( "hello\r\n" , 6); for (;;) { int i = 0; int n = read(buf, sizeof (buf)); for (i = 0; i < n; i++) { if (buf [i] == '\n' || buf[i] == '\r' ) write( "\r\n# " , 4); else write(&buf[i], 1); } } } void irq_handler() { unsigned long off = intcont->INTOFFSET; if (off == 28) { if (intcont->SUBSRCPND & 1) { schedule_r(); } if (intcont->SUBSRCPND & 2){ schedule_w(); } if (intcont->SUBSRCPND & 4) ; } if (off == 28) intcont->SUBSRCPND = 7; intcont->SRCPND = 1 << off; intcont->INTPND = 1 << off; } |
效果如下: