#include "uart.h" /***************************System Registers*******************************/ #define CMCTR_BASE 0x38094000 #define DIV_SYS1_CTR (*(volatile unsigned int*)(CMCTR_BASE + 0x040)) #define DIV_SYS2_CTR (*(volatile unsigned int*)(CMCTR_BASE + 0x044)) #define GATE_SYS_CTR (*(volatile unsigned int*)(CMCTR_BASE + 0x04c)) #define CLK_UART3_EN (1 << 15) #define CLK_UART2_EN (1 << 14) #define CLK_UART1_EN (1 << 13) #define CLK_UART0_EN (1 << 12) #define SEL_SPLL (*(volatile unsigned int*)(CMCTR_BASE + 0x10c)) #define GPIO0_BASE 0x38034000 #define GPIO0(a) (*(volatile unsigned int*)(GPIO0_BASE + (a))) #define SWPORTA_DR 0x00 #define SWPORTA_DDR 0x04 #define SWPORTA_CTL 0x08 #define SWPORTB_DR 0x0c #define SWPORTB_DDR 0x10 #define SWPORTB_CTL 0x14 #define SWPORTC_DR 0x18 #define SWPORTC_DDR 0x1c #define SWPORTC_CTL 0x20 #define SWPORTD_DR 0x24 #define SWPORTD_DDR 0x28 #define SWPORTD_CTL 0x2c #define GPIOA18_UART0_SIN (1 << 18) #define GPIOA19_UART0_SOUT (1 << 19) #define GPIOA20_UART0_CTSn (1 << 20) #define GPIOA21_UART0_RTSn (1 << 21) #define GPIOD0_UART1_SIN (1 << 0) #define GPIOD1_UART1_SOUT (1 << 1) #define GPIOD2_UART1_CTSn (1 << 2) #define GPIOD3_UART1_RTSn (1 << 3) #define GPIOD4_UART2_SIN (1 << 4) #define GPIOD5_UART2_SOUT (1 << 5) #define GPIOD6_UART3_SIN (1 << 6) #define GPIOD7_UART3_SOUT (1 << 7) #define GIC_UART0_INTR (96) #define GIC_UART1_INTR (97) #define GIC_UART2_INTR (98) #define GIC_UART3_INTR (99) #define UART0_BASE 0x38028000 #define UART1_BASE 0x38029000 #define UART2_BASE 0x3802a000 #define UART3_BASE 0x3802b000 #define FCR_FEWO (1 << 0) #define FCR_RCVR (1 << 1) #define FCR_XFIFOR (1 << 2) #define MCR_RTS (1 << 1) #define MCR_AFCE (1 << 5) #define LSR_THRE (1 << 5) #define LSR_RDR (1 << 0) #define IER_ERBFI (1 << 0) #define IER_ETBEI (1 << 1) #define IER_PTIME (1 << 7) #define UART_SET_TET(val,tet) (((val) & ~(3U << 4)) | (tet << 4)) #define LINE_FEED 0xA #define CARET_RETURN 0xD const unsigned int UART_GPIO[4][5] __attribute__ ((aligned(8))) = { { SWPORTA_CTL, GPIOA18_UART0_SIN, GPIOA19_UART0_SOUT, GPIOA20_UART0_CTSn, GPIOA21_UART0_RTSn}, { SWPORTD_CTL, GPIOD0_UART1_SIN, GPIOD1_UART1_SOUT, GPIOD2_UART1_CTSn, GPIOD3_UART1_RTSn}, { SWPORTD_CTL, GPIOD4_UART2_SIN, GPIOD5_UART2_SOUT, 0, 0}, { SWPORTD_CTL, GPIOD6_UART3_SIN, GPIOD7_UART3_SOUT, 0, 0}, }; typedef struct { volatile unsigned int RBR_THR_DLL; volatile unsigned int DLH_IER; union { volatile unsigned int IIR; volatile unsigned int FCR; }; union { volatile unsigned int value; struct { volatile unsigned int DLS : 2; volatile unsigned int STOP : 1; volatile unsigned int PARITY : 2; volatile unsigned int STP : 1; volatile unsigned int BC : 1; volatile unsigned int DLAB : 1; volatile unsigned int reserve : 24; }; }LCR; volatile unsigned int MCR; volatile unsigned int LSR; volatile unsigned int MSR; volatile unsigned int SCR; volatile unsigned int reserve0[4]; volatile unsigned int SRBR_STHR[16]; volatile unsigned int reserve1[3]; volatile unsigned int USR; volatile unsigned int TFL; volatile unsigned int RFL; volatile unsigned int SRR; volatile unsigned int SRTS; volatile unsigned int SBCR; volatile unsigned int reserve2[1]; volatile unsigned int SFE; volatile unsigned int SRT; volatile unsigned int STET; volatile unsigned int HTX; }uart_reg_t; typedef struct { unsigned int read_position; unsigned int write_position; int overflow; int lock; unsigned char buffer[UART_SOFT_BUFFER_LENGTH]; }uart_buffer_t; uart_buffer_t rx_buffer[UART_PORT_COUNT]; uart_buffer_t tx_buffer[UART_PORT_COUNT]; void uart_write_to_buffer(uart_buffer_t* buffer, char ch); void uart_write_to_buffer_safe(uart_buffer_t* buffer, char ch); int uart_get_available_read(uart_buffer_t* buffer); int uart_read_from_buffer(uart_buffer_t* buffer, void* dst, int size, int linesplit); int uart_read_from_buffer_safe(uart_buffer_t* buffer, void* dst, int size, int linesplit); void uart_data_transfer(unsigned int uartNum); void uart_data_transfer_safe(unsigned int uartNum); void uart_data_read(unsigned int uartNum); uart_reg_t* getUartHandler(unsigned int uartNum) { uartNum &= 0x3; return (uart_reg_t*)(UART0_BASE + 0x1000 * uartNum); } void uart_config(unsigned int uartNum, uart_baudrate_t baud, uart_data_len_t bits, uart_stop_bit stopBit, uart_parity_t parity) { unsigned divisor; uartNum &= 0x3; divisor = ((baud * (1 + (SEL_SPLL & 0xFF))) >> DIV_SYS1_CTR) >> DIV_SYS2_CTR; GATE_SYS_CTR |= (CLK_UART0_EN << uartNum); //Enable CLK GPIO0(UART_GPIO[uartNum][0]) |= UART_GPIO[uartNum][1] | UART_GPIO[uartNum][2] | UART_GPIO[uartNum][3] | UART_GPIO[uartNum][4]; //Set pins uart_reg_t* uart = getUartHandler(uartNum); //Check busy if(uart->USR & 0x1) { uart->SRR = 7; while(uart->USR & 0x1); } //Disable receiving uart->MCR = 0; //Setup UART uart->LCR.DLS = bits; uart->LCR.STOP = stopBit; uart->LCR.PARITY = parity; //Setup divisor uart->LCR.DLAB = 1; uart->DLH_IER = divisor >> 8; uart->RBR_THR_DLL = divisor & 0xFF; uart->LCR.DLAB = 0; //Clear errors uart->LSR = 0; uart->SCR = 0; //Disable interrupts uart->DLH_IER = 0; uart->MSR = 0; //Configure FIFO uart->FCR = FCR_FEWO | FCR_RCVR | FCR_XFIFOR; //Disable auto RTS signal uart->MCR = MCR_RTS; } void uart_disable(unsigned int uartNum) { uartNum &= 0x3; uart_reg_t* uart = getUartHandler(uartNum); //Disable interrupts uart->DLH_IER = 0; GPIO0(UART_GPIO[uartNum][0]) &= ~(UART_GPIO[uartNum][1] | UART_GPIO[uartNum][2] | UART_GPIO[uartNum][3] | UART_GPIO[uartNum][4]); //Unset pins GATE_SYS_CTR &= ~(CLK_UART0_EN << uartNum); //Disable CLK } void uart_putchar (unsigned int uartNum, short c) { uartNum &= 0x3; uart_reg_t* uart = getUartHandler(uartNum); while(1) { while (!(uart->LSR & LSR_THRE)) continue; uart->RBR_THR_DLL = c; #if UART_CARET_FIX if (c == '\n') c = '\r'; else #endif break; } } void uart_putstr (unsigned int uartNum, const char* str) { if(str == 0) return; //uart_reg_t* uart = getUartHandler(uartNum); while(*str) uart_putchar (uartNum, *str++); //while (!(uart->LSR & LSR_THRE)); } unsigned int uart_getchar (unsigned int uartNum) { unsigned int c; uart_reg_t* uart = getUartHandler(uartNum); while(!(uart->LSR & LSR_RDR)); c = uart->RBR_THR_DLL; return c; } int uart_send_data(unsigned int uartNum, const char* src, int size) { int i; uartNum &= 0x3; for(i = 0; i < size && !tx_buffer[uartNum].overflow; i++) { #if UART_CARET_FIX if(*src == '\n' && *(src - 1) != '\r' && *(src + 1) != '\r') { uart_write_to_buffer(&tx_buffer[uartNum], '\r'); } #endif uart_write_to_buffer(&tx_buffer[uartNum], *src++); } uart_reg_t* uart = getUartHandler(uartNum); if(uart->TFL < UART_FIFO_LENGTH) uart_data_transfer(uartNum); return i; } int uart_receive_data(unsigned int uartNum, void* dst, int size, int linesplit) { uartNum &= 0x3; uart_data_read(uartNum); return uart_read_from_buffer(&rx_buffer[uartNum], (void*)dst, size, linesplit); } void uart_write_to_buffer(uart_buffer_t* buffer, char ch) { buffer->lock = 1; buffer->buffer[buffer->write_position++] = ch; if(buffer->write_position >= UART_SOFT_BUFFER_LENGTH) { buffer->write_position = 0; } if(!buffer->overflow && buffer->write_position == buffer->read_position) { buffer->overflow = 1; } buffer->lock = 0; } void uart_write_to_buffer_safe(uart_buffer_t* buffer, char ch) { if(buffer->lock) return; uart_write_to_buffer(buffer, ch); } int uart_get_available_read(uart_buffer_t* buffer) { if(buffer->overflow) { return UART_SOFT_BUFFER_LENGTH; } register unsigned int rp = buffer->read_position; register unsigned int wp = buffer->write_position; if(rp == wp) { return 0; } if(rp < wp) { return wp - rp; } else { return wp + (UART_SOFT_BUFFER_LENGTH - rp); } } int uart_read_from_buffer(uart_buffer_t* buffer, void* dst, int size, int linesplit) { int i; unsigned char ch; char* ptr = (char*)dst; buffer->lock = 1; for(i = 0; i < size; i++) { if(buffer->overflow) { buffer->overflow = 0; buffer->read_position = buffer->write_position; } else if(buffer->read_position == buffer->write_position) { break; } ch = buffer->buffer[buffer->read_position++]; *ptr++ = ch; if(buffer->read_position >= UART_SOFT_BUFFER_LENGTH) { buffer->read_position = 0; } if(linesplit && (ch == LINE_FEED || ch == CARET_RETURN)) { break; } } buffer->lock = 0; return (int)((unsigned int)ptr - (unsigned int)dst); } int uart_read_from_buffer_safe(uart_buffer_t* buffer, void* dst, int size, int linesplit) { if(buffer->lock) return 0; return uart_read_from_buffer(buffer, dst, size, linesplit); } int uart_init_interrupt(unsigned int uartNum, unsigned int rftl) { if(uartNum >= UART_PORT_COUNT) { return 1; } //Reset buffers rx_buffer[uartNum].read_position = 0; rx_buffer[uartNum].write_position = 0; rx_buffer[uartNum].lock = 0; rx_buffer[uartNum].overflow = 0; tx_buffer[uartNum].read_position = 0; tx_buffer[uartNum].write_position = 0; tx_buffer[uartNum].lock = 0; tx_buffer[uartNum].overflow = 0; uart_reg_t* uart = getUartHandler(uartNum); uart->FCR = FCR_FEWO | FCR_RCVR | FCR_XFIFOR | (1 << 4) //TET 2 bytes | (rftl << 6) //RFTL ; uart->DLH_IER = IER_ERBFI //Receive interrupt //| IER_ETBEI //Empty THR //| IER_PTIME //Custom size THR ; return 0; } void uart_interrupt_handler(int ulICCIAR, void(*callback)(int, int, int) ) { if(ulICCIAR < GIC_UART0_INTR || ulICCIAR > (GIC_UART0_INTR + UART_PORT_COUNT)) { return; } //Get UART number int uartNum = (ulICCIAR - GIC_UART0_INTR) & 0x3; uart_reg_t* uart = getUartHandler(uartNum); //Get ID interrupt int int_id = uart->IIR & 0xF; volatile int status = 0; switch(int_id) { case UART_INT_MODEM_STATUS: status = uart->MSR; break; case UART_INT_THR_EMPTY: uart_data_transfer_safe(uartNum); break; case UART_INT_CHAR_TIMEOUT: case UART_INT_DATA_RECIEVE: uart_data_read(uartNum); break; case UART_INT_RECEIVER_LINE_STATUS: status = uart->LSR; break; case UART_INT_BUSY_DETECT: status = uart->USR; case UART_INT_NO_INTERRUPT: default: //Error state break; } if(callback != 0) callback(uartNum, int_id, status); } void uart_data_transfer(unsigned int uartNum) { uart_reg_t* uart = getUartHandler(uartNum); while(uart_read_from_buffer(&tx_buffer[uartNum], (void*)&uart->RBR_THR_DLL, 1, 0) && uart->TFL < UART_FIFO_LENGTH ) { //while(uart->TFL == 32); }; //if(uart_get_available_read(&tx_buffer[uartNum]) > 0) if(uart->TFL == UART_FIFO_LENGTH) { uart->DLH_IER = IER_ERBFI //Receive interrupt | IER_ETBEI //Empty THR | IER_PTIME; //Custom size THR } asm volatile("dsb; isb;"); } void uart_data_transfer_safe(unsigned int uartNum) { uart_reg_t* uart = getUartHandler(uartNum); if(tx_buffer[uartNum].lock) { uart->DLH_IER = IER_ERBFI //Receive interrupt //| IER_ETBEI //Empty THR //| IER_PTIME //Custom size THR ; return; } while(uart_read_from_buffer_safe(&tx_buffer[uartNum], (void*)&uart->RBR_THR_DLL, 1, 0) && uart->TFL < UART_FIFO_LENGTH ) { //while(uart->TFL == 32); }; if(uart_get_available_read(&tx_buffer[uartNum]) > 0) { uart->DLH_IER = IER_ERBFI //Receive interrupt | IER_ETBEI //Empty THR | IER_PTIME; //Custom size THR } else { uart->DLH_IER = IER_ERBFI //Receive interrupt //| IER_ETBEI //Empty THR //| IER_PTIME //Custom size THR ; } asm volatile("dsb; isb;"); } void uart_data_read(unsigned int uartNum) { uart_reg_t* uart = getUartHandler(uartNum); while(uart->RFL > 0) { uart_write_to_buffer(&rx_buffer[uartNum], uart->RBR_THR_DLL); } } int is_tx_empty(unsigned int uartNum) { uart_reg_t* uart = getUartHandler(uartNum); return !(uart_get_available_read(&tx_buffer[uartNum]) > 0 || uart->TFL > 0); } int is_rx_empty(unsigned int uartNum) { uart_reg_t* uart = getUartHandler(uartNum); return !(uart_get_available_read(&rx_buffer[uartNum]) > 0 || uart->RFL > 0); }