test I2C: fails. same code produce similar result every 9 times

This commit is contained in:
King Kévin 2014-07-29 00:11:29 -07:00
parent d352167fb4
commit 03dfdc0737
3 changed files with 69 additions and 66 deletions

View File

@ -1,47 +1,44 @@
/* software bit banging implementation /* software bit banging implementation
* based on https://en.wikipedia.org/wiki/I2c example code * based on https://en.wikipedia.org/wiki/I2c example code
*
* there is no external pull-up on SCL, and the internal one is too weak
* SCL must be driven
* but that is ok as we are the only master
* there is an external pull-up on SDA, and the internal one is too weak
* SDA goes to 3V instead of 5V due to the external pull-up
* but the 24LC256 still seems to work
*/ */
#include "I2C.h" #include "I2C.h"
// Hardware-specific support functions that MUST be customized: // Hardware-specific support functions that MUST be customized:
#define I2CSPEED 100 /* even when doing nothing, the max speed will be 100kHz, while the chip supports 400kHz */
void I2C_delay() #define I2C_delay()
{
volatile int v = 0;
int i;
for (i=0; i < I2CSPEED/2; i++) {
v;
}
}
/* Set SCL as input and return current level of line, 0 or 1 */ /* Set SCL as input and return current level of line, 0 or 1 */
bool read_SCL(void) bool read_SCL(void)
{ {
PORTB |= SCL; /* set as input */ LATB |= SCL; /* set high (must be driven because no pull-up */
WPUB |= SCL; /* enable pull-up */ return 1;
return (PORTB&SCL);
} }
/* Set SDA as input and return current level of line, 0 or 1 */ /* Set SDA as input and return current level of line, 0 or 1 */
bool read_SDA(void) bool read_SDA(void)
{ {
PORTB |= SDA; /* set as input */ TRISB |= SDA; /* set as input */
WPUB |= SDA; /* enable pull-up */ return (PORTB&SDA)!=0;
return (PORTB&SDA);
} }
/* Actively drive SCL signal low */ /* Actively drive SCL signal low */
void clear_SCL(void) void clear_SCL(void)
{ {
PORTB &= ~SCL; /* set as output */ LATB &= ~SCL; /* set low */
PORTB &= ~SDA; /* set low */
} }
/* Actively drive SDA signal low */ /* Actively drive SDA signal low */
void clear_SDA(void) void clear_SDA(void)
{ {
PORTB &= ~SCL; /* set as output */ TRISB &= ~SDA; /* set as output */
PORTB &= ~SDA; /* set low */ LATB &= ~SDA; /* set low */
} }
void arbitration_lost(void) void arbitration_lost(void)
@ -111,51 +108,52 @@ void i2c_write_bit(bool bit) {
// Read a bit from I2C bus // Read a bit from I2C bus
bool i2c_read_bit(void) { bool i2c_read_bit(void) {
bool bit; bool bit;
// Let the slave drive data // Let the slave drive data
read_SDA(); read_SDA();
I2C_delay(); I2C_delay();
while (read_SCL() == 0) { // Clock stretching while (read_SCL() == 0) { // Clock stretching
// You should add timeout to this loop
} // You should add timeout to this loop
// SCL is high, now data is valid }
bit = read_SDA(); // SCL is high, now data is valid
I2C_delay(); bit = read_SDA();
clear_SCL(); I2C_delay();
return bit; clear_SCL();
return bit;
} }
// Write a byte to I2C bus. Return 0 if ack by the slave. // Write a byte to I2C bus. Return 0 if ack by the slave.
bool i2c_write_byte(bool send_start, bool i2c_write_byte(bool send_start, bool send_stop, unsigned char byte)
bool send_stop, {
unsigned char byte) { unsigned bit;
unsigned bit; bool nack;
bool nack; if (send_start) {
if (send_start) { i2c_start_cond();
i2c_start_cond(); }
} for (bit = 0; bit < 8; bit++) {
for (bit = 0; bit < 8; bit++) { i2c_write_bit((byte & 0x80) != 0);
i2c_write_bit((byte & 0x80) != 0); byte <<= 1;
byte <<= 1; }
} nack = i2c_read_bit();
nack = i2c_read_bit(); if (send_stop) {
if (send_stop) { i2c_stop_cond();
i2c_stop_cond(); }
} return nack;
return nack;
} }
// Read a byte from I2C bus // Read a byte from I2C bus
unsigned char i2c_read_byte(bool nack, bool send_stop) { unsigned char i2c_read_byte(bool nack, bool send_stop)
unsigned char byte = 0; {
unsigned bit; unsigned char byte = 0;
for (bit = 0; bit < 8; bit++) { unsigned bit;
byte = (byte << 1) | i2c_read_bit(); for (bit = 0; bit < 8; bit++) {
} byte = (byte << 1) | i2c_read_bit();
i2c_write_bit(nack); }
if (send_stop) { i2c_write_bit(nack);
i2c_stop_cond(); if (send_stop) {
} i2c_stop_cond();
return byte; }
return byte;
} }

View File

@ -42,8 +42,8 @@
/* pin 18 is for a secret function, set by jumper WJ2, Vdd per default */ /* pin 18 is for a secret function, set by jumper WJ2, Vdd per default */
/* simple functions */ /* simple functions */
#define led_off() PORTB |= LED #define led_off() LATB |= LED
#define led_on() PORTB &= ~(LED) #define led_on() LATB &= ~(LED)
#define sleep() __asm sleep __endasm #define sleep() __asm sleep __endasm
/* variables */ /* variables */
@ -69,11 +69,9 @@ uint16_t __at(_CONFIG2) __CONFIG2 = _LVP_ON & /* enable low voltage programming
_PLLEN_OFF & /* don't use 4X PLL, for longer timer */ _PLLEN_OFF & /* don't use 4X PLL, for longer timer */
_WRT_OFF; /* no flash write protect */ _WRT_OFF; /* no flash write protect */
/* initialize micro-conroller */ /* initialize micro-conroller */
void init (void) { void init (void) {
/* configure IO */ /* configure IO */
NOT_WPUEN = 0; /* enable individual pull-ups */
ANSELA = 0; /* all pins are digital */ ANSELA = 0; /* all pins are digital */
ANSELB = 0; /* all pins are digital */ ANSELB = 0; /* all pins are digital */
TRISA |= RADIO; /* radio signal is an input */ TRISA |= RADIO; /* radio signal is an input */
@ -118,6 +116,8 @@ void init (void) {
* this PIC16F1847 offers hardware I2C, but not on those pins * this PIC16F1847 offers hardware I2C, but not on those pins
* so we also have to use software bit banging I2C * so we also have to use software bit banging I2C
*/ */
TRISB &= ~SCL; /* set as output (it must be driven because there is no pull-up */
LATB |= SCL; /* set clock as high (default pull-up state) */
PEIE = 1; /* enable peripheral interrupt (for timer 2) */ PEIE = 1; /* enable peripheral interrupt (for timer 2) */
GIE = 1; /* golablly enable interrupts */ GIE = 1; /* golablly enable interrupts */
@ -161,6 +161,11 @@ static void interrupt(void) __interrupt 0
if (switches&SWITCH1) { /* switch 1 changed */ if (switches&SWITCH1) { /* switch 1 changed */
if (PORTB&SWITCH1) { /* switch 1 released */ if (PORTB&SWITCH1) { /* switch 1 released */
led_off(); /* reset LED */ led_off(); /* reset LED */
i2c_write_byte(1,0,0xa0);
i2c_write_byte(0,1,0xa0);
// i2c_write_byte(0,1,0x17);
// i2c_write_byte(1,0,0xa1);
// i2c_read_byte(0,0);
} else { /* switch 1 pressed */ } else { /* switch 1 pressed */
led_on(); /* test LED */ led_on(); /* test LED */
} }

View File

@ -15,9 +15,9 @@ OBJ := $(patsubst %.c,%.o,$(SRC))
all: compile flash all: compile flash
# flash program # flash program (the board needs to power externally)
flash: $(TARGET).hex flash: $(TARGET).hex
pk2cmd -PPIC$(PIC) -F$< -M -W -R pk2cmd -P PIC$(PIC) -F $< -M -W -R
# compile stages # compile stages
assembly: $(ASM) assembly: $(ASM)
@ -36,7 +36,7 @@ compile: hex
gpasm -I . -o $@ -c $< gpasm -I . -o $@ -c $<
$(TARGET).hex: $(OBJ) $(TARGET).hex: $(OBJ)
gplink -w -r -s /usr/share/gputils/lkr/$(PIC)_g.lkr -I/usr/share/sdcc/lib/pic14 -I/usr/share/sdcc/non-free/lib/pic14 -I. -o $@ libsdcce.lib pic$(PIC).lib $< gplink -w -r -s /usr/share/gputils/lkr/$(PIC)_g.lkr -I /usr/share/sdcc/lib/pic14 -I /usr/share/sdcc/non-free/lib/pic14 -I . -o $@ libsdcce.lib pic$(PIC).lib $(OBJ)
# remove temporary files # remove temporary files
clean: clean: