; Serial port I/O routines ; -==========================- ; Cambridge University Computer Laboratory ; Gordon Williams (gw235@cam.ac.uk) ; Version 1.000002c GET arm.s ; To get the address of the serial port + clock speed AREA text,CODE EXPORT UART_INIT,UART_TXD,UART_TXD_STR,UART_RXD,UART_RXD_COUNT,UART_RXD_HEX EXPORT UART_TXD_DECIMAL,UART_TXD_DECIMAL_X,UART_TXD_HEX_DIGIT,UART_TXD_HEX EXPORT UART_TXD_HEX_X ; Various exports ; ; These comply with the ARM standard calling convention EXCEPT UART_TXD_DECIMAL_X ; and UART_TXD_HEX_X. r0-r3 may be dirtied, but everything else will be saved. ; In UART_TXD_DECIMAL_X + UART_TXD_HEX_X's case, r4 is dirtied too. This is just ; to negate the need for a Stack to be set up for these functions to be used. ; ; UART_INIT - Initialize UART ; UART_TXD - Transmit the byte in r0 ; UART_TXD_STR - r0 points to a null-terminated string that will be transmitted ; UART_TXD_DECIMAL_X - Transmit r0 as an unsigned decimal value - DIRTIES R4 ; UART_TXD_DECIMAL - Transmit r0 as an unsigned decimal value - NEEDS STACK ; UART_TXD_HEX_DIGIT - transmits a value between 0 and 15 as a hex digit ; UART_TXD_HEX_X - transmits 8 hex digits - DIRTIES R4 ; UART_TXD_HEX - transmits 8 hex digits - NEEDS STACK ; UART_RXD - Recieves a byte which is returned in r0. blocks if there is no byte in the fifo ; UART_RXD_COUNT - Returns the amount of bytes in the recieve buffer. max=15 ; UART_RXD_HEX - Recieves one character and interprets it as a hex digit. if it is not valid hex, 0 is returned UART_BAUD EQU 38400 ; baud rate UART_DIVIDER EQU (EXC_AHB2_CLK_FREQUENCY/(16*UART_BAUD)) ; the divider for baud rate ; --------------------------------------------------------------- ; Initialise - dirties r0 and r1 UART_INIT ; DATA BITS mov r0,#3 ; 8 bit ldr r1,=(EXC_UART00_BASE+0x28) str r0,[r1] ; DIVIDER ldr r0,=UART_DIVIDER and r0,r0,#0xFF ldr r1,=(EXC_UART00_BASE+0x34) str r0,[r1] ; low 8 bits ldr r0,=UART_DIVIDER mov r0,r0,LSR #8 ldr r1,=(EXC_UART00_BASE+0x38) str r0,[r1] ; high 8 bits ; FIFOs mov r0,#0x07 ldr r1,=(EXC_UART00_BASE+0x14) str r0,[r1] ; Interrupt disable stuff in here? ; Return MOV r15,r14 ; --------------------------------------------------------------- ; Send a Byte (in r0). Dirties r1 ; Waits until sent UART_TXD ; wait until the fifo isn't full... ldr r1,=(EXC_UART00_BASE+0x0C) ldr r1,[r1] and r1,r1,#0x1F cmp r1,#15 bge UART_TXD ; send new byte ldr r1,=(EXC_UART00_BASE+0x10) str r0,[r1] ; Return mov r15,r14 ; --------------------------------------------------------------- ; Send a string - address in r0. Dirties r0..r3 ; Waits until sent UART_TXD_STR mov r2,r0 ; r2 = address mov r3,r14 ; r3 = return address UART_TXD_STR_START ldrb r0,[r2],#1 cmp r0,#0 beq UART_TXD_STR_END ; finish if the string contains 0 BL UART_TXD b UART_TXD_STR_START UART_TXD_STR_END ; Return mov r15,r3 ; --------------------------------------------------------------- ; Return a byte (in r0) ; Waits until a byte is recieved UART_RXD ldr r0,=(EXC_UART00_BASE+0x00) ldr r0,[r0] and r0,r0,#0x1F cmp r0,#0 beq UART_RXD ldr r0,=(EXC_UART00_BASE+0x08) ldr r0,[r0] mov r15,r14 ; --------------------------------------------------------------- ; Return a byte (in r0) (as hex, eg. 0..9,a..f => 0..15) ; Waits until a byte is recieved UART_RXD_HEX mov r3,r14 ; call original UART recieve bl UART_RXD mov r14,r3 cmp r0,#48 ; if <48 then NOT VALID blt UART_RXD_HEX_ERR cmp r0,#58 sublt r0,r0,#48 movlt r15,r14 ; return VALID if value is in the range 0..9 (48..57) cmp r0,#65 ; 'A' ; if <65 then NOT VALID blt UART_RXD_HEX_ERR cmp r0,#71 ; 'F'+1 sublt r0,r0,#55 movlt r15,r14 ; return VALID if value is in the range A..F (65..70) cmp r0,#97 ; 'a' blt UART_RXD_HEX_ERR cmp r0,#103 ; 'f'+1 sublt r0,r0,#87 movlt r15,r14 ; return VALID if value is in the range a..f (65..70) UART_RXD_HEX_ERR ; wrong digit - return 0 mov r0,#0 mov r15,r14 ; --------------------------------------------------------------- ; Return a byte (in r0) - the amount of bytes in the recieve buffer ; Waits until a byte is recieved UART_RXD_COUNT ldr r0,=(EXC_UART00_BASE+0x00) ldr r0,[r0] and r0,r0,#0x1F mov r15,r14 ; --------------------------------------------------------------- ; Transmit one hex digit. assumes it is within 0..15 or junk is ; transmitted UART_TXD_HEX_DIGIT cmp r0,#10 addlt r0,r0,#48 cmp r0,#16 addlt r0,r0,#55 mov r3,r14 ; call original UART transmit bl UART_TXD mov r15,r3 ; --------------------------------------------------------------- ; Transmits 8 hex digits representing r0 ; uses r0,r1,r2,r3 + stack UART_TXD_HEX stmfd sp!,{r4,lr} ; Push r4 and link register BL UART_TXD_HEX_X ldmfd sp!,{r4,pc} ; Pop r4, and set program counter ; --------------------------------------------------------------- ; Transmit 8 hex digits. DIRTIES R4 UART_TXD_HEX_X mov r4,r14 ; save return address mov r3,r0 ; save r0 mov r2,#32 UART_TXD_HEX_LOOP sub r2,r2,#4 mov r0,r3,LSR r2 and r0,r0,#15 cmp r0,#10 addlt r0,r0,#48 cmp r0,#16 addlt r0,r0,#55 bl UART_TXD cmp r2,#0 bne UART_TXD_HEX_LOOP mov r15,r4 ; go back ; --------------------------------------------------------------- ; takes a number in r0, and outputs its value ; in decimal. uses r0,r1,r2,r3 + stack UART_TXD_DECIMAL stmfd sp!,{r4,lr} ; Push r4 and link register BL UART_TXD_DECIMAL_X ldmfd sp!,{r4,pc} ; Pop r4, and set program counter ; --------------------------------------------------------------- ; takes a number in r0, and outputs its value ; in decimal. uses r0,r1,r2,r3,r4 UART_TXD_DECIMAL_X mov r4,r0 ; r4 now has our number... mov r3,#9 ; 10^9 = 1 billion ; top word used to indicate whether a non-zero digit ; has been found yet UART_TXD_DECIMAL_LOOP subs r3,r3,#1 and r0,r3,#0xFF mov r1,#1 mov r2,#10 UART_TXD_DECIMAL_MUL10 mul r1,r2,r1 subs r0,r0,#1 BNE UART_TXD_DECIMAL_MUL10 ; now r1 = 10^r3 ; Start Horrible divide (r4/r1) mov r2,#0 UART_TXD_DECIMAL_DIVIDE cmp r4,r1 BLT UART_TXD_DECIMAL_DIVIDE_END sub r4,r4,r1 add r2,r2,#1 B UART_TXD_DECIMAL_DIVIDE UART_TXD_DECIMAL_DIVIDE_END ; now r4 = remainder ; r2 = number ; r3 = digit number cmp r2,#0 orrne r3,r3,#0xFF00 add r0,r2,#48 ; convert digit to ASCII mov r2,r14 ; save calling address and trasmit data ands r1,r3,#0xFF00 ; only transmit if we have recieved a non-zero digit BLNE UART_TXD mov r14,r2 and r2,r3,#0xFF cmp r2,#1 BNE UART_TXD_DECIMAL_LOOP ; last digit! add r0,r4,#48 ; convert digit to ASCII mov r2,r14 ; save calling address and trasmit data BL UART_TXD mov r14,r2 mov r15,r14 ; return ; ---------- END OF FILE END