Files
beaglefw/uart.c
2013-06-22 17:01:05 +02:00

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;
}