142 lines
3.7 KiB
C
142 lines
3.7 KiB
C
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <stdbool.h>
|
|
|
|
#include "cortexa8.h"
|
|
#include "omap35x_intc.h"
|
|
#include "uart.h"
|
|
|
|
static volatile uint8_t *const uart_data = (uint8_t*)0x49020000;
|
|
static volatile uint8_t *const uart_dll = (uint8_t*)0x49020000;
|
|
static volatile uint8_t *const uart_dlh = (uint8_t*)0x49020004;
|
|
static volatile uint8_t *const uart_ier = (uint8_t*)0x49020004;
|
|
static volatile uint8_t *const uart_fcr = (uint8_t*)0x49020008;
|
|
static volatile uint8_t *const uart_efr = (uint8_t*)0x49020008;
|
|
static volatile uint8_t *const uart_lcr = (uint8_t*)0x4902000c;
|
|
static volatile uint8_t *const uart_lsr = (uint8_t*)0x49020014;
|
|
static volatile uint8_t *const uart_ssr = (uint8_t*)0x49020044;
|
|
static volatile uint8_t *const uart_sysc = (uint8_t*)0x49020054;
|
|
static volatile uint8_t *const uart_wer = (uint8_t*)0x4902005C;
|
|
|
|
static volatile uint32_t *const prcm_wkst_per = (uint32_t*)0x483070b0;
|
|
|
|
|
|
#define RECVBUFFERSIZE 128
|
|
static volatile char recvbuffer[RECVBUFFERSIZE];
|
|
static volatile int recvbuffer_rdptr = (RECVBUFFERSIZE-1), recvbuffer_wrptr = 0;
|
|
static volatile bool newdata = false;
|
|
|
|
static bool echo = true;
|
|
|
|
static void _uart_wait_txnotfull() {
|
|
while(*uart_ssr & 0x1) {}
|
|
}
|
|
|
|
static void _uart_wait_rxnotempty() {
|
|
while(!(*uart_lsr & 0x1)) {}
|
|
}
|
|
|
|
void uart_sendb(char b) {
|
|
_uart_wait_txnotfull();
|
|
*uart_data = b;
|
|
}
|
|
|
|
char uart_recvb() {
|
|
_uart_wait_rxnotempty();
|
|
return *uart_data;
|
|
}
|
|
|
|
void uart_write(const char *data, int len) {
|
|
for(int i = 0;i < len;++i)
|
|
uart_sendb(*data++);
|
|
}
|
|
|
|
int uart_read(char *buf, int len) {
|
|
int pos = 0;
|
|
|
|
while(true) {
|
|
bool oldint = cortexa8_get_int();
|
|
cortexa8_dis_int();
|
|
|
|
// Data available in recvbuffer?
|
|
if(((recvbuffer_rdptr+1)%RECVBUFFERSIZE) != recvbuffer_wrptr) {
|
|
int avail = recvbuffer_wrptr - recvbuffer_rdptr;
|
|
if(avail < 0)
|
|
avail = RECVBUFFERSIZE+avail;
|
|
avail -= 1;
|
|
|
|
// Advance to first byte to read
|
|
recvbuffer_rdptr = (recvbuffer_rdptr+1)%RECVBUFFERSIZE;
|
|
|
|
int toread = (avail>len)?len:avail;
|
|
if(toread+recvbuffer_rdptr > RECVBUFFERSIZE) {
|
|
memcpy(buf+pos, (char*)recvbuffer+recvbuffer_rdptr, RECVBUFFERSIZE-(recvbuffer_rdptr));
|
|
toread -= RECVBUFFERSIZE-recvbuffer_rdptr;
|
|
pos += RECVBUFFERSIZE-recvbuffer_rdptr;
|
|
recvbuffer_rdptr = 0;
|
|
}
|
|
memcpy(buf+pos, (char*)recvbuffer+recvbuffer_rdptr, toread);
|
|
pos += toread;
|
|
recvbuffer_rdptr = (recvbuffer_rdptr+toread-1)%RECVBUFFERSIZE;
|
|
}
|
|
|
|
newdata = false;
|
|
|
|
// Try to read directly from UART if more data req'd than was in buffer
|
|
while((pos < len) && (*uart_lsr & 0x1)) {
|
|
char rd = *uart_data;
|
|
if(rd == '\r')
|
|
rd = '\n';
|
|
if(echo)
|
|
uart_sendb(rd);
|
|
buf[pos++] = rd;
|
|
}
|
|
|
|
if(oldint)
|
|
cortexa8_ena_int();
|
|
|
|
if(pos > 0)
|
|
return pos;
|
|
|
|
while(!newdata)
|
|
__asm__ __volatile__ ("wfi"); // If we didn't get any data, wait
|
|
}
|
|
}
|
|
|
|
void uart_recv_handler(void *unused) {
|
|
while(*uart_lsr & 0x1) { // while there are bytes
|
|
char rd = *uart_data;
|
|
if(rd == '\r')
|
|
rd = '\n';
|
|
if(echo)
|
|
uart_sendb(rd);
|
|
if(recvbuffer_wrptr == recvbuffer_rdptr) { // Overflow
|
|
} else {
|
|
recvbuffer[recvbuffer_wrptr] = rd;
|
|
recvbuffer_wrptr = (recvbuffer_wrptr+1)%RECVBUFFERSIZE;
|
|
}
|
|
}
|
|
|
|
newdata = true;
|
|
*prcm_wkst_per = (1<<11); // Clear UART3 wake bit
|
|
}
|
|
|
|
void uart_init() {
|
|
omap35x_intc_register(74, &uart_recv_handler, NULL, 1);
|
|
omap35x_intc_ena(74);
|
|
|
|
*uart_lcr = 0xBF; // Configuration mode B
|
|
uint8_t dllsave = *uart_dll, dlhsave = *uart_dlh;
|
|
*uart_dll = 0;
|
|
*uart_dlh = 0;
|
|
*uart_efr |= (1<<4);
|
|
*uart_lcr = 0x80; // Configuration mode A
|
|
*uart_fcr = 0x21;
|
|
*uart_sysc = 0x15;
|
|
*uart_wer |= (1<<5);
|
|
*uart_dll = dllsave;
|
|
*uart_dlh = dlhsave;
|
|
*uart_lcr = 0x03; // Operational mode
|
|
*uart_ier = 0x11;
|
|
}
|