/* ** Made by fabien le mentec <texane@gmail.com> ** ** Started on Sat Jan 30 15:43:29 2010 texane ** Last update Sun Feb 7 18:18:43 2010 texane */ #include <pic18fregs.h> #include "i2c.h" /* globals */ enum i2c_state { I2C_STATE_IDLE = 0, I2C_STATE_READ, I2C_STATE_WRITE }; static volatile enum i2c_state i2c_state = I2C_STATE_IDLE; static volatile unsigned char i2c_buffer[32]; static volatile unsigned int i2c_pos = 0; static volatile i2c_addr_t i2c_addr = 0; /* locking */ static void lock_i2c(void) { PIE1bits.SSPIE = 0; } static void unlock_i2c(void) { PIE1bits.SSPIE = 1; } /* exported */ int i2c_setup(void) { /* disable interrupts */ PIE1bits.SSPIE = 0; /* tris */ #define I2C_SDA_TRIS TRISBbits.TRISB0 #define I2C_SCL_TRIS TRISBbits.TRISB1 I2C_SCL_TRIS = 1; I2C_SDA_TRIS = 1; /* addressing */ #define I2C_SLAVE_ADDR 0x8 SSPADD = I2C_SLAVE_ADDR; /* enable module, slave mode 7 bit addressing, start and stop bits enabled */ /* SSPCON1 = 0x2e; */ SSPCON1 = 0x26; SSPSTAT = 0x00; /* enable general call, clock stretching */ SSPCON2 = 0x81; /* SSPCON2 = 0x01; */ /* enable interrupts */ IPR1bits.SSPIP = 0; PIR1bits.SSPIF = 0; PIE1bits.SSPIE = 1; return 0; } static void write_byte(unsigned char b) { PIE1bits.SSPIE = 1; PIR1bits.SSPIF = 0; SSPBUF = b; SSPCON1bits.CKP = 1; while (PIR1bits.SSPIF == 0) ; PIE1bits.SSPIE = 1; } unsigned int i2c_write(i2c_addr_t a, unsigned char* s, unsigned int n) { #if 0 /* async mode. tx at the next master read request. */ unsigned int i; if ((i2c_size + n) > sizeof(i2c_buffer)) n = sizeof(i2c_buffer) - i2c_pos; if (n == 0) return 0; lock_i2c(); for (i = 0; i < n; ++i, ++i2c_pos) i2c_buffer[i2c_pos] = s[i]; unlock_i2c(); return i; #else unsigned int i; write_byte((unsigned char)a); for (i = 0; i < n; ++i, ++s) write_byte(*s); return i; #endif } unsigned int i2c_read(unsigned char* s, unsigned int n) { /* non blocking mode. bugged testing version. */ unsigned int i; /* not safe, but will do for testing */ if (i2c_pos == 0) return 0; lock_i2c(); if (n > i2c_pos) n = i2c_pos; i2c_pos = 0; for (i = 0; i < n; ++i) s[i] = i2c_buffer[i]; unlock_i2c(); return i; } void i2c_handle_interrupt(void) { static unsigned char buf; static int is_avail; if (!PIR1bits.SSPIF) return ; PIR1bits.SSPIF = 0; switch (i2c_state) { case I2C_STATE_IDLE: i2c_state = I2C_STATE_READ; /* fallback */ case I2C_STATE_READ: is_avail = SSPSTATbits.BF | SSPCON1bits.SSPOV; buf = SSPBUF; if (is_avail) { if (SSPSTATbits.D_A == 1) { if (SSPSTATbits.R_W == 1) i2c_state = I2C_STATE_READ; else i2c_state = I2C_STATE_WRITE; if (i2c_pos < sizeof(i2c_buffer)) i2c_buffer[i2c_pos++] = buf; } else { i2c_addr = (i2c_addr_t)buf; } SSPSTATbits.BF = 0; SSPCON1bits.SSPOV = 0; } /* stop bit */ if (SSPSTATbits.P) i2c_state = I2C_STATE_IDLE; /* release the line on last bit */ SSPCON1bits.CKP = 1; break; case I2C_STATE_WRITE: /* stop bit */ if (SSPSTATbits.P) i2c_state = I2C_STATE_IDLE; /* release the line once data put in buffer */ SSPBUF = i2c_buffer[i2c_pos++]; SSPCON1bits.CKP = 1; i2c_state = I2C_STATE_IDLE; SSPCON1bits.WCOL = 0; break; default: i2c_state = I2C_STATE_IDLE; break; } }