sd2snes/mk1-src/uart.c
2010-09-06 23:51:48 +02:00

188 lines
4.3 KiB
C

/* sd2snes - SD card based universal cartridge for the SNES
Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
This file was adapted from sd2iec, written by Ingo Korb.
Original copyright header follows:
*/
/* sd2iec - SD/MMC to Commodore serial bus interface/controller
Copyright (C) 2007-2009 Ingo Korb <ingo@akana.de>
Inspiration and low-level SD/MMC access based on code from MMC2IEC
by Lars Pontoppidan et al., see sdcard.c|h and config.h.
FAT filesystem access based on code from ChaN and Jim Brain, see ff.c|h.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License only.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
uart.c: UART access routines
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <stdio.h>
#include "config.h"
#include "avrcompat.h"
#include "uart.h"
static uint8_t txbuf[1 << CONFIG_UART_BUF_SHIFT];
static volatile uint16_t read_idx;
static volatile uint16_t write_idx;
ISR(USART_UDRE_vect) {
if (read_idx == write_idx) return;
UDR = txbuf[read_idx];
read_idx = (read_idx+1) & (sizeof(txbuf)-1);
if (read_idx == write_idx)
UCSRB &= ~ _BV(UDRIE);
}
void uart_putc(char c) {
uint16_t t=(write_idx+1) & (sizeof(txbuf)-1);
#ifndef CONFIG_DEADLOCK_ME_HARDER // :-)
UCSRB &= ~ _BV(UDRIE); // turn off RS232 irq
#else
while (t == read_idx); // wait for free space
#endif
txbuf[write_idx] = c;
write_idx = t;
//if (read_idx == write_idx) PORTD |= _BV(PD7);
UCSRB |= _BV(UDRIE);
}
void uart_puthex(uint8_t num) {
uint8_t tmp;
tmp = (num & 0xf0) >> 4;
if (tmp < 10)
uart_putc('0'+tmp);
else
uart_putc('a'+tmp-10);
tmp = num & 0x0f;
if (tmp < 10)
uart_putc('0'+tmp);
else
uart_putc('a'+tmp-10);
}
void uart_puthexlong(uint32_t num) {
uart_puthex((num>>24)&0xff);
uart_puthex((num>>16)&0xff);
uart_puthex((num>>8)&0xff);
uart_puthex(num&0xff);
}
void uart_puthexshort(uint16_t num) {
uart_puthex((num>>8)&0xff);
uart_puthex(num&0xff);
}
void uart_trace(void *ptr, uint16_t start, uint16_t len) {
uint16_t i;
uint8_t j;
uint8_t ch;
uint8_t *data = ptr;
data+=start;
for(i=0;i<len;i+=16) {
uart_puthex(start>>8);
uart_puthex(start&0xff);
uart_putc('|');
uart_putc(' ');
for(j=0;j<16;j++) {
if(i+j<len) {
ch=*(data + j);
uart_puthex(ch);
} else {
uart_putc(' ');
uart_putc(' ');
}
uart_putc(' ');
}
uart_putc('|');
for(j=0;j<16;j++) {
if(i+j<len) {
ch=*(data++);
if(ch<32 || ch>0x7e)
ch='.';
uart_putc(ch);
} else {
uart_putc(' ');
}
}
uart_putc('|');
uart_putcrlf();
start+=16;
}
}
static int ioputc(char c, FILE *stream) {
if (c == '\n') uart_putc('\r');
uart_putc(c);
return 0;
}
uint8_t uart_getc(void) {
loop_until_bit_is_set(UCSRA,RXC);
return UDR;
}
void uart_flush(void) {
while (read_idx != write_idx) ;
}
void uart_puts_P(prog_char *text) {
uint8_t ch;
while ((ch = pgm_read_byte(text++))) {
uart_putc(ch);
}
}
void uart_putcrlf(void) {
uart_putc(13);
uart_putc(10);
}
static FILE mystdout = FDEV_SETUP_STREAM(ioputc, NULL, _FDEV_SETUP_WRITE);
void uart_init(void) {
/* Seriellen Port konfigurieren */
/* UBRRH = (int)((double)F_CPU/(16.0*CONFIG_UART_BAUDRATE)-1) >> 8;
UBRRL = (int)((double)F_CPU/(16.0*CONFIG_UART_BAUDRATE)-1) & 0xff;*/
UBRRH = (int)((double)F_CPU/(8.0*CONFIG_UART_BAUDRATE)-1) >> 8;
UBRRL = (int)((double)F_CPU/(8.0*CONFIG_UART_BAUDRATE)-1) & 0xff;
UCSRA |= _BV(U2X0);
UCSRB = _BV(RXEN) | _BV(TXEN);
// I really don't like random #ifdefs in the code =(
#if defined __AVR_ATmega32__
UCSRC = _BV(URSEL) | _BV(UCSZ1) | _BV(UCSZ0);
#else
UCSRC = _BV(UCSZ1) | _BV(UCSZ0);
#endif
stdout = &mystdout;
//UCSRB |= _BV(UDRIE);
read_idx = 0;
write_idx = 0;
}