OpenCores
URL https://opencores.org/ocsvn/igor/igor/trunk

Subversion Repositories igor

[/] [igor/] [trunk/] [avr/] [src/] [dev/] [usart.c] - Rev 4

Compare with Previous | Blame | View Log

#include <avr/io.h>
#include <avr/interrupt.h>
#include <global.h>
#include <stdint.h>
#include <device.h>
#include <dispatch.h>
#include <stdlib.h>
#include <string.h>
 
#define BAUD 9600
#define MUBRR ((FOSC/16/BAUD)-1)
 
static struct {
	struct buf readbuf;
	struct buf writebuf;
} usart_data;
 
#define XON	0x11
#define XOFF	0x13
/* Internal flow control. */
uint8_t xflow_local;
/* Internal flow control for transmit. */
uint8_t xflow_state_transmit;
/* External flow control. */
uint8_t xflow_remote;
 
static int8_t usart_send_data(void);
static igordev_read_fn_t usart_recv;
static igordev_write_fn_t usart_send;
static igordev_init_fn_t init;
static igordev_flush_fn_t usart_flush;
 
/* XXX: Not completed. */
struct igordev igordev_usart = {
	.init = init,
	.read = usart_recv,
	.write = usart_send,
	.flush = usart_flush,
	.read_status = 0,
	.write_status = 0,
	.priv = &usart_data
};
 
 
void init() {
	/* Set internal stuff first. */
	const char *uhello = "Hello, world from USART!\r\n";
	buf_init(&usart_data.readbuf);
	buf_init(&usart_data.writebuf);
	igordev_usart.read_status = igordev_usart.write_status = IDEV_STATUS_OK;
	xflow_local = xflow_remote = xflow_state_transmit = XON;
	igordev_usart.id = (CAN_READ | CAN_WRITE |
	    (DEVTYPE_SERIAL << DEVTYPE_OFFSET));
 
	// Disable powersaving
	PRR0 &= ~(1<<PRUSART0);
 
	// Set tranfser speed
	UBRR0L = (uint8_t)MUBRR;
	UBRR0H = (uint8_t)(MUBRR>>8);
 
	// Enable reciever, transmitter and interrupts ( Not active until global interrupts are enabled)
	UCSR0B = (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0);
 
	// Set format, stopbits, mode: 8n1
	UCSR0C = (0<<USBS0)|(0<<UPM01)|(0<<UPM00)|(0<<UMSEL01)|(0<<UMSEL00)|(3<<UCSZ00);
	buf_write(&usart_data.writebuf, (uint8_t *)uhello, strlen(uhello));
	// XXX: Return value not checked
	dispatch_request_make(&igordev_usart, REQ_TYPE_FLUSH, 0, 0, NULL);
}
 
// Received a word
ISR(SIG_USART0_RECV) {
        // Read UDR to reset interrupt flag
	struct buf *buf;
	uint8_t data;
 
	igordev_usart.read_status = IDEV_STATUS_INTR;
	/* Store in the buffers. */
	data = UDR0;
	/* If we received external flow control signal. */
	if (data == XOFF || data == XON) {
		xflow_remote = data;
		igordev_usart.read_status = IDEV_STATUS_OK;
		return;
	}
 
	buf = &usart_data.readbuf;
#define ONESQUARE (MAXBUFLEN / 4)
	if (buf_writesleft(buf) < (ONESQUARE - 1))
		xflow_local = XOFF;
 
	buf_write(buf, &data, 1);
	igordev_usart.read_status = IDEV_STATUS_OK;
#if 0
	// Check if we have a second byte buffered.
	if ( !(UCSR0A & ( 1>> RXC0 ) ) ) {
	    igordev_usart.read_status = IDEV_STATUS_INTR;
	    /* Store in the buffers. */
	    data = UDR0;
	    /* If we received external flow control signal. */
	    if (data == XOFF || data == XON) {
		xflow_remote = data;
		igordev_usart.read_status = IDEV_STATUS_OK;
		return;
	    }
	    if (buf_writesleft(buf) < (ONESQUARE - 1))
		xflow_local = XOFF;
 
	    buf_write(buf, &data, 1);
	    igordev_usart.read_status = IDEV_STATUS_OK;
	}
#endif
}
 
/*
 * Read num bytes from addr and place it into data.
 * Data assumed to be a buffer large enough for num bytes.
 * Addr here is ignored, since serial is a streaming device.
 */
uint8_t
usart_recv(uint64_t addr, uint8_t *data, uint8_t num)
{
	struct buf *buf;
	uint8_t byte;
	uint8_t i;
 
	buf = &usart_data.readbuf;
	/* Avoid making larger buffers for now. */
	for (i = 0; i < num; i++) {
		buf_read(buf, &byte, 1);
		if (BUF_EMPTY(buf))
			break;
		*(data + i) = byte;
	}
	return (i);
}
 
/* 
 * Example of transmit. Currently initiates the write and let the TX interrupt
 * handle the rest.
 */
uint8_t 
usart_send(uint64_t addr, uint8_t *data, uint8_t num)
{
	struct buf *buf;
	uint8_t i = 0;
	/* Transmit only once, and the buffer will be flushed anyway. */
	/* Only output data if we're provided with data. */
	if (num > 0 && data != NULL) {
		/* Copy data into write buffer. */
		buf = &usart_data.writebuf;
		i = buf_write(buf, data, num);
	}
	return (i);
}
 
/* Send whatever we have in the output buffer. */
static void
usart_flush(void)
{
	struct buf *buf;
	buf = &usart_data.writebuf;
 
	igordev_usart.write_status = IDEV_STATUS_BUSY;
	/* Flush as long as it is ok. */
	while (!BUF_EMPTY(buf) && usart_send_data() == 0);
	igordev_usart.write_status = IDEV_STATUS_OK;
}
 
/* Sends the next byte in the buffer. */
static int8_t
usart_send_data(void)
{
	struct buf *buf;
	uint8_t data;
 
	/* Cannot send data yet. */
	if (xflow_remote == XOFF)
		return (-1);
 
	buf = &usart_data.writebuf;
	switch (xflow_local) {
	case XON:
		/* If we have few reads left, make sure we can get more. */
		buf_read(buf, &data, 1);
		if (BUF_EMPTY(buf))
			return (-1);
		break;
	case XOFF:
		/* If we have not signalled OK again, do it. */
		if (buf_readsleft(buf) >= (MAXBUFLEN - ONESQUARE) &&
		    xflow_state_transmit == XOFF) {
			data = XON;
			xflow_state_transmit = XON;
			xflow_local = XON;
			break;
		}
		/* If we have not sent the xflow_state signal, do it. */
		if (xflow_state_transmit == XON) {
			data = XOFF;
			xflow_state_transmit = XOFF;
			break;
		}
		return (-1);
	default:
		return (-1);
	}
	while (!(UCSR0A & (1<<UDRE0)));
	UDR0 = data; /* Initiate transfer. */
	return (0);
}
 
#if 0
void
usart_loopback(void *arg)
{
	struct buf *in;
	uint8_t data[MAXBUFLEN];
	uint8_t i, num;
 
	cli();
	in = &usart_data.readbuf;
	/* Fill output buffer from input buffer. */
	i = 0;
	num = buf_read(in, data, MAXBUFLEN);
	usart_send(data, num);
	sei();
}
#endif
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.