From 53663ade65a4938384dc1b583d3dbcd211540725 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?King=20K=C3=A9vin?= Date: Sat, 2 Aug 2014 13:33:22 -0700 Subject: [PATCH] I2C corrected --- pic/MDR/I2C.c | 174 +++++++++++++++++++++++++++----------------------- pic/MDR/I2C.h | 3 +- 2 files changed, 96 insertions(+), 81 deletions(-) diff --git a/pic/MDR/I2C.c b/pic/MDR/I2C.c index c644dc9..3da593e 100644 --- a/pic/MDR/I2C.c +++ b/pic/MDR/I2C.c @@ -11,16 +11,7 @@ #define release_SDA() LATB |= SDA /* set data low */ #define hold_SDA() LATB &= ~SDA - /* a small delay for better clock */ -#define WAIT 1 -/* -void delay(void) -{ - uint8_t wait=WAIT; - while (wait--); -} -*/ #define delay() __asm\ nop\ nop\ @@ -29,12 +20,75 @@ void delay(void) __endasm /* read SDA - * don't forget to set SDA as input in the begining - * are set SDA as output in the end + * set SDA as input in the begining + * set SDA as output in the end */ -uint8_t read_SDA(void) +uint8_t read_ack(void) { + uint8_t ack; hold_SCL(); /* set clock to low for SDA to change */ + TRISB |= SDA; /* set as input */ + delay(); /* wait for SDA to change */ + release_SCL(); /* SDA should be valid when clock is high */ + delay(); + /* we don't verify the SCL state as only we can drive it */ + if (PORTB&SDA) { /* read bit */ + ack = 1; + } else { + ack = 0; + } + hold_SCL(); /* put clock to low, as safe state */ + release_SDA(); /* set data to default state */ + TRISB &= ~SDA; /* set back to output */ + /* leave the output value as it is */ + return ack; +} + +/* sent start condition + * falling SDA while SCL is high + */ +void send_start(void) +{ + release_SCL(); /* endure SCL is high */ + delay(); + release_SDA(); /* ensure SDA is high to be able to start */ + delay(); + hold_SDA(); /* send start signal */ +} + +/* send stop condition + * rising SDA while SCL is high + */ +void send_stop(void) +{ + hold_SDA(); /* be sure SDA is low for rising edge */ + delay(); + release_SCL(); /* be sure SCL is high */ + delay(); + release_SDA(); /* set SDA high while SCL is high */ +} + +/* send byte and get ack (0=ack) */ +uint8_t send_byte(uint8_t byte) +{ + uint8_t bit, ack; + /* send every bit, MSb first */ + for (bit = 0; bit < 8; bit++) { + hold_SCL(); /* value can change when SCL is low */ + delay(); + if (byte&0x80) { + release_SDA(); /* set high for 1 */ + } else { + hold_SDA(); /* set low for 0 */ + } + delay(); + release_SCL(); /* set clock high to indicate valid value */ + byte <<= 1; + } + /* read ack */ + delay(); + hold_SCL(); /* set clock to low for SDA to change */ + TRISB |= SDA; /* set as input */ delay(); /* wait for SDA to change */ delay(); delay(); @@ -42,85 +96,47 @@ uint8_t read_SDA(void) delay(); /* we don't verify the SCL state as only we can drive it */ if (PORTB&SDA) { /* read bit */ - return 1; + ack = 1; } else { - return 0; + ack = 0; } -} - -uint8_t read_ack(void) -{ - uint8_t ack = 0; - TRISB |= SDA; /* set as input */ - ack = read_SDA(); + hold_SCL(); /* put clock to low, as safe state */ + delay(); + release_SDA(); /* set output to high (default) */ TRISB &= ~SDA; /* set back to output */ - hold_SCL(); return ack; } -/* start bit is when SDA goes low while SCL is high */ -void send_start(void) -{ - release_SCL(); - delay(); - release_SDA(); /* ensure SDA is high on the beginning */ - delay(); - hold_SDA(); -} - -void send_stop(void) -{ - hold_SDA(); /* be sure SDA is low */ - release_SCL(); - delay(); - release_SDA(); /* set SDA high while SCL is high */ -} - -void send_1(void) -{ - hold_SCL(); /* value can change when SCL is low */ - delay(); - release_SDA(); /* set the right state */ - delay(); - release_SCL(); /* value will be read when SCL goes high */ -} - -void send_0(void) -{ - hold_SCL(); /* value can change when SCL is low */ - delay(); - hold_SDA(); /* set the right state */ - delay(); - release_SCL(); /* value will be read when SCL goes high */ -} - -/* send byte and get ack */ -uint8_t send_byte(uint8_t byte) -{ - uint8_t bit; - /* send every bit, MSb first */ - for (bit = 0; bit < 8; bit++) { - if (byte&0x80) { - send_1(); - } else { - send_0(); - } - byte <<= 1; - } - return read_ack(); -} - -uint8_t read_byte(void) +/* read one byte and send an ack + * send an ack if you want to read more bytes + * send a nack if this is the last byte read + */ +uint8_t read_byte(uint8_t ack) { uint8_t byte = 0; uint8_t bit; + hold_SCL(); /* set clock to low for SDA to change */ TRISB |= SDA; /* set as input */ - /* read 8 bits */ for (bit=0; bit<8; bit++) { - byte += read_SDA(); + delay(); /* wait for SDA to change */ + release_SCL(); /* SDA should be valid when clock is high */ + if (PORTB&SDA) { /* read bit */ + byte += 1; + } else { + byte += 0; + } byte <<= 1; + hold_SCL(); /* set clock to low for SDA to change */ } - TRISB &= ~SDA; /* set back to output */ - send_0(); /* send ack */ + if (ack) { + hold_SDA(); /* set low for ack */ + } else { + release_SDA(); /* set high for nack */ + } + TRISB &= ~SDA; /* set back to output */ + delay(); + release_SCL(); /* set clock high to indicate valid value */ + delay(); + hold_SCL(); /* set clock to low for SDA to change */ return byte; } diff --git a/pic/MDR/I2C.h b/pic/MDR/I2C.h index 19998ad..9e122cf 100644 --- a/pic/MDR/I2C.h +++ b/pic/MDR/I2C.h @@ -8,5 +8,4 @@ void send_start(void); void send_stop(void); uint8_t send_byte(uint8_t byte); -uint8_t read_byte(void); - +uint8_t read_byte(uint8_t ack);