From 57e3d242b89b9db5bfc1503ef4c9657146f2dd33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98rn=20E=2E=20Hansen?= Date: Tue, 16 Apr 2013 20:20:42 +0000 Subject: [PATCH] Initial commit of fifo and i2c routines --- i2cspi_BaS_gcc/sources/exceptions.S | 4 +- i2cspi_BaS_gcc/sources/fifo.c | 109 ++++++++++++++++ i2cspi_BaS_gcc/sources/i2c_firebee.c | 185 +++++++++++++++++++++++++++ 3 files changed, 296 insertions(+), 2 deletions(-) create mode 100644 i2cspi_BaS_gcc/sources/fifo.c create mode 100644 i2cspi_BaS_gcc/sources/i2c_firebee.c diff --git a/i2cspi_BaS_gcc/sources/exceptions.S b/i2cspi_BaS_gcc/sources/exceptions.S index 396c5c6..e9688e5 100644 --- a/i2cspi_BaS_gcc/sources/exceptions.S +++ b/i2cspi_BaS_gcc/sources/exceptions.S @@ -626,9 +626,9 @@ acsi_dma: // atari dma move.l d1,-(a7) lea MCF_PSC0_PSCTB_8BIT,a1 // ++ vr - mchar move.l, 'D,'M','A,'\ ,(a1) + mchar move.l, 'D','M','A','\'' ,(a1) //move.l #"DMA ",(a1) - mchar move.l,'I,'N,'T,'!,(a1) + mchar move.l,'I','N','T','!',(a1) // move.l #'INT!',(a1) lea 0xf0020110,a5 // fifo daten diff --git a/i2cspi_BaS_gcc/sources/fifo.c b/i2cspi_BaS_gcc/sources/fifo.c new file mode 100644 index 0000000..11ca1e4 --- /dev/null +++ b/i2cspi_BaS_gcc/sources/fifo.c @@ -0,0 +1,109 @@ +/* + * fifo.c + * + * A general implementation of a fifo buffer + * + */ + +#include + +//This initializes the FIFO structure with the given buffer and size +void fifo_init(fifo_t * f, char * buf, int size) +{ + f->head = 0; + f->tail = 0; + f->size = size; + f->buf = buf; +} + +// Get one byte from the fifo buffer +uint8_t fifo_get(fifo_t *f) +{ + uint8_t ch = 0; + + if( f->tail != f->head && f->tail < f->size ) + { + ch = f->buf[f->tail++]; + if( f->tail >= f->size ) + f->tail = 0; + } + + return ch; +} + +// Put one byte into the buffer +void fifo_put(fifo_t *f, uint8_t byte) +{ + if( f->head == f->tail || f->head >= f->size ) + return; + f->buf[f->head] = byte; + fifo_advance(f,&f->head); +} + +void fifo_clear(fifo_t *f) +{ + f->head = f->tail = 0; +} + +int fifo_used(fifo_t *f) +{ + if( f->head > f->tail ) + return (f->head - f->tail); + return (f->size - f->tail + f->head); +} + +int fifo_unused(fifo_t *f) +{ + if( f->head > f->tail ) + return (f->size-f->head+f->tail); + return (f->tail-f->head); +} + +int fifo_full(fifo_t *f) +{ + if( f->head+1 >= f->size ) + return (f->tail == 0); + return (f->head+1 == f->tail); +} + +int fifo_empty(fifo_t *f) +{ + return (f->head == f->tail); +} + +void fifo_advance(fifo_t *f, int *ix) +{ + if( ++*ix > f->size ) + *ix=0; +} + +//This reads at most nbytes bytes from the FIFO +//The number of bytes read is returned +int fifo_read(fifo_t *f, char *buf, int nbytes){ + int n = 0; + + while( n < nbytes && !fifo_empty(f) ) + { + n++; + *buf++ = f->buf[f->tail]; + fifo_advance(f,&f->tail); + } + + return n; +} + +//This writes up to nbytes bytes to the FIFO +//If the head runs in to the tail, not all bytes are written +//The number of bytes written is returned +int fifo_write(fifo_t *f, const char *buf, int nbytes){ + int n = 0; + + while( n < nbytes && !fifo_full(f) ) + { + f->buf[f->head] = *buf++; + fifo_advance(f,&f->head); + n++; + } + + return n; +} diff --git a/i2cspi_BaS_gcc/sources/i2c_firebee.c b/i2cspi_BaS_gcc/sources/i2c_firebee.c new file mode 100644 index 0000000..6de80ac --- /dev/null +++ b/i2cspi_BaS_gcc/sources/i2c_firebee.c @@ -0,0 +1,185 @@ +/* + * i2c.c + * + */ + +#include +#include + +#include + +static struct { + uint8_t state; + long delay; + uint16_t len; + fifo_t fifo; + unsigned char *_buf; + uint16_t device; +} i2c_param; + +char local_buf[BUFSIZ]; + +#define FIFO &i2c_param.fifo + +/* + * I2Cinit: I2C initilazation as master + * + * Parameters: None. + * + * Return : None. + */ +void I2C_Init() +{ + i2c_param.fifo.buf = local_buf; + i2c_param.fifo.size = BUFSIZ; + i2c_param.delay = 133*10L; // We can safely ignore this + i2c_param.len = 0; + I2C_ioctl(0,0); +} + +void __attribute__ ((interrupt)) I2C_InterruptHandler(void) +{ + char ch; + + clear_bit(MCF_I2C_I2SR,MCF_I2C_I2SR_IIF); + if( MCF_I2C_I2CR & MCF_I2C_I2CR_MSTA ) + { // Masters of the known universe + if( MCF_I2C_I2SR & MCF_I2C_I2SR_ICF ) + { + switch( i2c_param.state ) + { + case I2C_MXRX: + if( fifo_used(&i2c_param.fifo)+1 == i2c_param.len ) { + clear_bit(MCF_I2C_I2CR,MCF_I2C_I2CR_MSTA); + i2c_param.state = I2C_READY; + } else if( fifo_used(&i2c_param.fifo)+2 == i2c_param.len ) { + set_bit(MCF_I2C_I2CR,MCF_I2C_I2CR_TXAK); + i2c_param.state = I2C_READY; + } + fifo_put(&i2c_param.fifo,MCF_I2C_I2DR); + break; + case I2C_ADDR: + if( fifo_empty(&i2c_param.fifo) ) + { + i2c_param.state = I2C_MXRX; + clear_bit(MCF_I2C_I2CR,MCF_I2C_I2CR_MTX); // Receive mode + set_bit(MCF_I2C_I2CR,MCF_I2C_I2CR_RSTA); + ch = MCF_I2C_I2DR; // Dummy read + break; + } + case I2C_MXTX: + if( fifo_empty(&i2c_param.fifo) || (MCF_I2C_I2SR&MCF_I2C_I2SR_RXAK) ) { + clear_bit(MCF_I2C_I2CR,MCF_I2C_I2CR_MSTA); + i2c_param.state = I2C_READY; + } else + MCF_I2C_I2DR = fifo_get(&i2c_param.fifo); + break; + } + } + } else { // Slave mode. + int set; + + if( set = (MCF_I2C_I2SR & MCF_I2C_I2SR_IAL) ) + clear_bit(MCF_I2C_I2SR,MCF_I2C_I2SR_IAL); + if( MCF_I2C_I2SR & MCF_I2C_I2SR_IAAS ) + { + if( MCF_I2C_I2SR & MCF_I2C_I2SR_SRW ) + { + set_bit(MCF_I2C_I2CR,MCF_I2C_I2CR_MTX); + fifo_put(&i2c_param.fifo,MCF_I2C_I2DR); + } else { + clear_bit(MCF_I2C_I2CR,MCF_I2C_I2CR_MTX); + ch = MCF_I2C_I2DR; + } + } else if( !set ) { + if( MCF_I2C_I2CR&MCF_I2C_I2CR_MTX ) + { + if( MCF_I2C_I2SR&MCF_I2C_I2SR_RXAK ) + MCF_I2C_I2DR = fifo_get(&i2c_param.fifo); + else { + clear_bit(MCF_I2C_I2CR,MCF_I2C_I2CR_MTX); + ch = MCF_I2C_I2DR; + } + } else { + fifo_put(&i2c_param.fifo,MCF_I2C_I2DR); + } + } + } +} + +void I2C_send(unsigned short device, unsigned char *buf, unsigned short len) +{ + if( len > i2c_param.fifo.size ) + return; + i2c_param.len = len; + fifo_clear(&i2c_param.fifo); + if( device > 127 ) // Use I2C 10 bit address + { + fifo_put(FIFO,0b11110|((device>>5)&6)|I2C_WRITE); + fifo_put(FIFO,device&255); + } else + fifo_put(FIFO,((device<<1)&0xFE)|I2C_WRITE); + fifo_write(FIFO,buf,len); + i2c_param.state = I2C_MXTX; +} + +void I2C_receive(unsigned short device, unsigned char *buf, unsigned short len) +{ + if( len > i2c_param.fifo.size ) + return; + i2c_param.len = len; + fifo_clear(FIFO); + if( device > 127 ) // Use I2C 10 bit address + { + fifo_put(FIFO,0b11110|((device>>5)&6)|I2C_READ); + fifo_put(FIFO,device&255); + } else + fifo_put(FIFO,((device<<1)&0xFE)|I2C_READ); + i2c_param.state = I2C_ADDR; +} + +int I2C_ioctl(unsigned int index, unsigned long val) +{ + unsigned short len = val; + uint8_t temp; + + // Set device as slave or + switch( index ) + { + case I2CTLINIT: // make me master + /* set the frequency near 400KHz */ + MCF_I2C_I2FDR = MCF_I2C_I2FDR_IC(0x10); + /* start the module */ + MCF_I2C_I2CR = MCF_I2C_I2CR_IIEN | MCF_I2C_I2CR_IEN; + /* if bit busy set, send a stop condition to slave module */ + if(MCF_I2C_I2SR & MCF_I2C_I2SR_IBB) + { + MCF_I2C_I2CR = 0; /* clear control register */ + MCF_I2C_I2CR = MCF_I2C_I2CR_IIEN|MCF_I2C_I2CR_IEN|MCF_I2C_I2CR_MSTA; /* enable module & send a START condition */ + temp = MCF_I2C_I2DR; /* dummy read */ + MCF_I2C_I2SR = 0; /* clear status register */ + MCF_I2C_I2CR = 0; /* clear control register */ + MCF_I2C_I2CR = MCF_I2C_I2CR_IIEN|MCF_I2C_I2CR_IEN; /* enable the module again */ + } + i2c_param.state = I2C_READY; + i2c_param._buf = 0; + break; + case I2CTLSBUF: + i2c_param._buf = (char *)val; + break; + case I2CTLDEV: + i2c_param.device = val; + break; + case I2CTLREAD: + if( i2c_param._buf == 0 || i2c_param.device == 0 ) + return -1; + I2C_receive(i2c_param.device,i2c_param._buf,len); + break; + case I2CTLWRITE: + if( i2c_param._buf == 0 || i2c_param.device == 0 ) + return -1; + I2C_send(i2c_param.device,i2c_param._buf,len); + break; + } +} +