Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
firmware: add I2C software functions
  • Loading branch information
enjoy-digital committed Aug 21, 2015
1 parent ecc4ed5 commit 34e8d37
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 1 deletion.
2 changes: 1 addition & 1 deletion firmware/lm32/Makefile
Expand Up @@ -2,7 +2,7 @@
MSCDIR=../../build/misoc
include $(MSCDIR)/software/common.mak

OBJECTS=isr.o processor.o dvisampler0.o dvisampler1.o edid.o pll.o ci.o config.o encoder.o main.o
OBJECTS=isr.o processor.o dvisampler0.o dvisampler1.o edid.o pll.o ci.o config.o encoder.o i2c.o main.o

all: firmware.bin

Expand Down
113 changes: 113 additions & 0 deletions firmware/lm32/i2c.c
@@ -0,0 +1,113 @@
#include <generated/csr.h>
#ifdef CSR_I2C_BASE
#include "i2c.h"

/* I2C bit banging */
int i2c_started;

int i2c_init(void)
{
unsigned int timeout;

i2c_started = 0;
i2c_w_write(I2C_SCL);
/* Check the I2C bus is ready */
timeout = 1000;
while((timeout > 0) && (!(i2c_r_read() & I2C_SDAIN))) timeout--;

return timeout;
}

void i2c_delay(void)
{
unsigned int i;

for(i=0;i<1000;i++) __asm__("nop");
}

/* I2C bit-banging functions from http://en.wikipedia.org/wiki/I2c */
unsigned int i2c_read_bit(void)
{
unsigned int bit;

/* Let the slave drive data */
i2c_w_write(0);
i2c_delay();
i2c_w_write(I2C_SCL);
i2c_delay();
bit = i2c_r_read() & I2C_SDAIN;
i2c_delay();
i2c_w_write(0);
return bit;
}

void i2c_write_bit(unsigned int bit)
{
if(bit) {
i2c_w_write(I2C_SDAOE | I2C_SDAOUT);
} else {
i2c_w_write(I2C_SDAOE);
}
i2c_delay();
/* Clock stretching */
i2c_w_write(i2c_w_read() | I2C_SCL);
i2c_delay();
i2c_w_write(i2c_w_read() & ~I2C_SCL);
}

void i2c_start_cond(void)
{
if(i2c_started) {
/* set SDA to 1 */
i2c_w_write(I2C_SDAOE | I2C_SDAOUT);
i2c_delay();
i2c_w_write(i2c_w_read() | I2C_SCL);
i2c_delay();
}
/* SCL is high, set SDA from 1 to 0 */
i2c_w_write(I2C_SDAOE|I2C_SCL);
i2c_delay();
i2c_w_write(I2C_SDAOE);
i2c_started = 1;
}

void i2c_stop_cond(void)
{
/* set SDA to 0 */
i2c_w_write(I2C_SDAOE);
i2c_delay();
/* Clock stretching */
i2c_w_write(I2C_SDAOE | I2C_SCL);
/* SCL is high, set SDA from 0 to 1 */
i2c_w_write(I2C_SCL);
i2c_delay();
i2c_started = 0;
}

unsigned int i2c_write(unsigned char byte)
{
unsigned int bit;
unsigned int ack;

for(bit = 0; bit < 8; bit++) {
i2c_write_bit(byte & 0x80);
byte <<= 1;
}
ack = !i2c_read_bit();
return ack;
}

unsigned char i2c_read(int ack)
{
unsigned char byte = 0;
unsigned int bit;

for(bit = 0; bit < 8; bit++) {
byte <<= 1;
byte |= i2c_read_bit();
}
i2c_write_bit(!ack);
return byte;
}

#endif
19 changes: 19 additions & 0 deletions firmware/lm32/i2c.h
@@ -0,0 +1,19 @@
#ifndef __I2C_H
#define __I2C_H

#define I2C_SCL 0x01
#define I2C_SDAOE 0x02
#define I2C_SDAOUT 0x04

#define I2C_SDAIN 0x01

int i2c_init(void);
void i2c_delay(void);
unsigned int i2c_read_bit(void);
void i2c_write_bit(unsigned int bit);
void i2c_start_cond(void);
void i2c_stop_cond(void);
unsigned int i2c_write(unsigned char byte);
unsigned char i2c_read(int ack);

#endif /* __I2C_H */

0 comments on commit 34e8d37

Please sign in to comment.