123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234 |
- /*
- ** 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;
- }
- }
|