~foura/uxn900

b4c4d60b39f0d07d8b5335829b4a21f255464af8 — james palmer 5 months ago a41fd64
initial workings of i2c. just polling for now.

does not work, i think i need to set the speed or change some
io pin configuration. most annoying.
5 files changed, 223 insertions(+), 2 deletions(-)

M Makefile
A src/i2c.c
M src/inc/dat.h
M src/inc/fns.h
M src/main.c
M Makefile => Makefile +2 -1
@@ 2,8 2,9 @@ CC      = arm-none-eabi-gcc
OBJCOPY = arm-none-eabi-objcopy
MKIMAGE = mkimage

CFLAGS = -Wall -pedantic -O2 -mcpu=cortex-a8 -Isrc/inc -nostdlib -ffreestanding
CFLAGS = -Wall -pedantic -Og -g -mcpu=cortex-a8 -Isrc/inc -nostdlib -ffreestanding
OFILES = \
	src/i2c.o \
	src/l.o \
	src/main.o \
	src/timer.o \

A src/i2c.c => src/i2c.c +203 -0
@@ 0,0 1,203 @@
#include "uxn.h"
#include "dat.h"
#include "fns.h"

#include "dev/console.h"

enum {
	Rrev     = 0x00,
	Rie      = 0x04,
		Riexrdy = 1 << 4, /* tx ready */
		Rierrdy = 1 << 3, /* rx ready */
		Rieardy = 1 << 2, /* register access ready */
		Rienack = 1 << 1, /* no acknowledgment */
		Rieal   = 1 << 0, /* arbitration lost */
	Rstat    = 0x08,
		Rstatsbd  = 1 << 15, /* single byte data */
		Rstatbb   = 1 << 12, /* bus busy */
		Rstatrovr = 1 << 11, /* receive overrun */
		Rstatxudf = 1 << 10, /* transmit underflow */
		Rstataas  = 1 << 9,  /* address as slave */
		Rstatxrdy = 1 << 4, /* tx ready */
		Rstatrrdy = 1 << 3, /* rx ready */
		Rstatardy = 1 << 2, /* register access ready */
		Rstatnack = 1 << 1, /* no acknowledgment */
		Rstatal   = 1 << 0, /* arbitration lost */
	Rwe      = 0x0c,
	Rsyss    = 0x10,
		Rsyssrdone = 1 << 0, /* reset monitoring */
	Rbuf     = 0x14,
		Rbufrdma = 1 << 15,  /* recieve dma */
		Rbufxdma = 1 << 7,   /* transmit dma */
	Rcnt     = 0x18,
	Rdata    = 0x1c,
	Rsysc    = 0x20,
	Rcon     = 0x24,
		Rconen  = 1 << 15, /* module enable */
		Rconbe  = 1 << 14, /* big endian mode */
		Rconstb = 1 << 11, /* start byte mode */
		Rconmst = 1 << 10, /* master/slave mode */
		Rcontrx = 1 << 9,  /* transmitter/receiver mode */
		Rconxa  = 1 << 8,  /* expand address */
		Rconstp = 1 << 1,  /* stop condition */
		Rconstt = 1 << 0,  /* start condition */
	Roa      = 0x28,
	Rsa      = 0x2c,
	Rpsc     = 0x30,
	Rscll    = 0x34,
	Rsclh    = 0x38,
	Rsystest = 0x3c,
	Rbufstat = 0x40,
};

static Uint32
i2c_reg_read(Uint32 base, Uint8 r)
{
	volatile Uint32* reg = (Uint32*) (base + r);
	return *reg;
}

static void
i2c_reg_write(Uint32 base, Uint8 r, Uint32 value)
{
	volatile Uint32* reg = (Uint32*) (base + r);
	*reg = value;
}

static void
i2c_wait_for_bus(Uint32 base)
{
	while(i2c_reg_read(base, Rstat) & Rstatbb)
		;
}

static void
i2c_initiate_transfer(Uint32 base)
{
	Uint32 tmp;

	tmp = i2c_reg_read(base, Rcon);
	tmp |= Rconstt;
	tmp |= Rconstp;
}

static void
i2c_flush_fifo(Uint32 base)
{
	Uint16 stat;

	for(;;) {
		stat = i2c_reg_read(base, Rstat);
		if(stat == Rstatrrdy) {
			i2c_reg_read(base, Rdata);
			i2c_reg_write(base, Rstat, Rstatrrdy);
			timer_delay(PHYSTIMER2, 1000);
		} else {
			break;
		}
	}
}

static Uint32
i2c_wait_for_event(Uint32 base)
{
	int timeout;
	Uint32 status;

	timeout = 1000;
	do {
		status = i2c_reg_read(base, Rstat);
		timer_delay(PHYSTIMER2, 10);
	} while(status == 0 && timeout--);

	if(timeout <= 0) {
		console_putc('T');
		i2c_reg_write(base, Rstat, 0xFFFF);
	}

	return status;
}

void
i2c_init(Uint32 base)
{
	Uint32 tmp;

	if(i2c_reg_read(base, Rcon) & Rconen) {
		i2c_reg_write(base, Rcon, 0);
		timer_delay(PHYSTIMER2, 50000);
	}

	i2c_reg_write(base, Rsysc, 0x2);
	timer_delay(PHYSTIMER2, 1000);

	i2c_reg_write(base, Rcon, Rconen);
	while(!(i2c_reg_read(base, Rsyss) & 1))
		timer_delay(PHYSTIMER2, 1000);

	i2c_reg_write(base, Roa, 0x11);
	i2c_reg_write(base, Rie, Riexrdy
		| Rierrdy	
		| Rieardy
		| Rienack
		| Rieal);

	timer_delay(PHYSTIMER2, 1000);
	i2c_flush_fifo(base);
	i2c_reg_write(base, Rstat, 0xFFFF);
	i2c_reg_write(base, Rbuf, 0);

	tmp = i2c_reg_read(base, Rcon);
	tmp |= Rconen;
	tmp |= Rconmst;
	tmp |= Rcontrx;

	i2c_reg_write(base, Rcon, tmp);
}

void
i2c_write(Uint32 base, Uint8 chip, Uint8 *data, Uint8 count)
{
	Uint32 status;

	i2c_reg_write(base, Rsa, chip);
	i2c_reg_write(base, Rcnt, count);

	i2c_wait_for_bus(base);
	i2c_initiate_transfer(base);
	while(count) {
		status = i2c_wait_for_event(base);
		if(status == 0) {
			console_putc('0');
			goto error;
		}

		if(status & Rstatnack) {
			console_putc('N');
			goto error;
		}

		if(status & Rstatxrdy) {
			i2c_reg_write(base, Rdata, *data++);
			i2c_reg_write(base, Rstat, Rstatxrdy);
			count--;
		} else {
			console_putc('n');
			goto error;
		}
	}

	do {
		status = i2c_wait_for_event(base);
	} while(!(status & Rstatardy));

error:
	i2c_flush_fifo(base);
	i2c_reg_write(base, Rstat, 0xFFFF);
}

void
i2c_read(Uint32 base, Uint8 chip, Uint8 *data, Uint8 count)
{
	/* XXX: CODE THIS */
}

M src/inc/dat.h => src/inc/dat.h +0 -1
@@ 5,7 5,6 @@
#define PHYSUART   0x49020000
#define PHYSI2C1   0x48070000
#define PHYSI2C2   0x48072000
#define PHYSI2C3   0x48060000
#define PHYSTIMER1 0x48318000
#define PHYSTIMER2 0x49032000
#define PHYSTIMER3 0x49034000

M src/inc/fns.h => src/inc/fns.h +4 -0
@@ 1,3 1,7 @@
void   timer_init(Uint32 base);
Uint32 timer_get(Uint32 base);
void   timer_delay(Uint32 base, Uint32 usec);

void  i2c_init(Uint32 base);
void  i2c_write(Uint32 base, Uint8 addr, Uint8 *data, Uint8 count);
void  i2c_read(Uint32 base, Uint8 addr, Uint8 *data, Uint8 count);

M src/main.c => src/main.c +14 -0
@@ 37,6 37,16 @@ uxn_interrupt(void)
}

void
watchdog_init(void)
{
	Uint8 data;

	/* silence the twl4030 watchdog (i hope) */
	data = 0x5e; i2c_write(PHYSI2C1, 0x4a, &data, 1);
	data = 0;    i2c_write(PHYSI2C1, 0x4a, &data, 1);
}

void
main(void)
{
	Uxn u;


@@ 44,6 54,10 @@ main(void)
	timer_init(PHYSTIMER1);
	timer_init(PHYSTIMER2);
	timer_init(PHYSTIMER3);
	i2c_init(PHYSI2C1);
	i2c_init(PHYSI2C2);

	/* watchdog_init(); NOT WORKING */
	screen_init(&uxn_screen);

	uxn_init();