Pessoal,
Depois de muito penar com (PASMEM!) uma 24C02, eu decidi rever meu código de I2C e encontrei um problema que foi solucionado (com o auxilio do nosso amigo Arão, lá da Onipresente PICLIST!), nesta nova versão que apresento do meu código de I2C.
O problema básico é que não estava sendo resetando o BUS I2C a cada transação, o que as vezes ocasionava uma travada no BUS que só voltava após o reset do circuito.
Também notei (à duras penas!) que os Datasheets em sua maioria não falam sobre este Reset no BUS, o que confundiu um pouco. Mas vamos deixar e palavras e vamos ao código.
Primeiro um .C + .H para as 24C02:
- Inicio de 24C02.c ----------------------------------------------------------------------------
#include "sfr_r81b.h"
#include "24C02.h"
// ---------------------- Low Level Functions ---------------
void waitFactor(unsigned int factor) {
unsigned int fc=0;
factor*=waitUnit;
for(fc=0; fc<factor; fc++) asm("NOP");
}
unsigned char getSDAState(void) { _24C02_sda_d = 0; asm("NOP"); return(_24C02_sda); }
unsigned char getSCLState(void) { _24C02_scl_d = 0; asm("NOP"); return(_24C02_scl); }
void setSDAHigh(void) { _24C02_sda_d = 1; _24C02_sda = 1; }
void setSCLHigh(void) { _24C02_scl_d = 1; _24C02_scl = 1; }
void setSDALow(void) { _24C02_sda_d = 1; _24C02_sda = 0; }
void setSCLLow(void) { _24C02_scl_d = 1; _24C02_scl = 0; }
void clockToHigh(void) { setSCLHigh(); waitFactor(1); }
void clockToLow(void) { setSCLLow(); waitFactor(1); }
void clockPulse(void) { clockToHigh(); clockToLow(); }
void sendBit(unsigned char bit) {
if(bit) {
setSDAHigh();
} else {
setSDALow();
}
waitFactor(1);
setSCLHigh(); waitFactor(1);
setSCLLow(); waitFactor(1);
}
unsigned char resetBus (void) {
unsigned char sdaStatus;
clockToHigh();
sdaStatus=getSDAState();
clockToLow();
return(sdaStatus==0?BUSY:ONLINE);
}
void startCondition(void) {
setSDAHigh(); waitFactor(1);
setSCLHigh(); waitFactor(1);
setSDALow(); waitFactor(1);
setSCLLow(); waitFactor(1);
}
void stopCondition(void) {
setSDALow(); waitFactor(1);
setSCLHigh(); waitFactor(1);
setSDAHigh(); waitFactor(1);
setSCLHigh(); waitFactor(1);
}
void writeByte(unsigned char byte) {
unsigned char rotateLeft;
unsigned char tmp;
unsigned char toReturn;
rotateLeft = 0;
while(rotateLeft<8) {
tmp=byte;
tmp=(tmp << rotateLeft) >> 7;
rotateLeft++;
sendBit(tmp);
}
}
unsigned char readByte(void) {
unsigned char byte=0;
unsigned char pos=0;
_24C02_sda_d=0;
while(pos<8) {
clockToHigh();
byte|=getSDAState();
if(pos<7) byte<<=1;
pos++;
clockToLow();
}
return(byte);
}
unsigned char readAck (void) {
unsigned char sdaStatus;
clockToHigh();
sdaStatus=getSDAState();
clockToLow();
return(sdaStatus==0?OK:NOK);
}
// ---------------------- High Level Functions ---------------
void Write_24C02(unsigned char deviceAddress, unsigned char menAddress, unsigned char byte) {
unsigned char myAck=0;
reset_bus:
while(resetBus()==BUSY);
device_address:
startCondition();
writeByte(deviceAddress);
myAck=readAck();
if(myAck==NOK) goto reset_bus;
men_address:
writeByte(menAddress);
myAck=readAck();
if(myAck==NOK) goto reset_bus;
send_byte:
writeByte(byte);
myAck=readAck();
if(myAck==NOK) goto reset_bus;
stopCondition();
}
unsigned char Read_24C02(unsigned char deviceAddress, unsigned char menAddress) {
unsigned char myAck=0;
unsigned char byte=0;
reset_bus:
while(resetBus()==BUSY);
device_address:
startCondition();
writeByte(deviceAddress);
myAck=readAck();
if(myAck==NOK) goto reset_bus;
men_address:
writeByte(menAddress);
myAck=readAck();
if(myAck==NOK) goto reset_bus;
restart_condition:
startCondition();
device_address_read:
writeByte(deviceAddress | 0x01);
myAck=readAck();
if(myAck==NOK) goto reset_bus;
read_byte:
byte = readByte();
sendBit(1);
stopCondition();
return(byte);
}
- Final de 24C02.c ----------------------------------------------------------------------------
- Inicio de 24C02.h ----------------------------------------------------------------------------
#ifndef _24C02_H
#define _24C02_H
#define _24C02_sda_d pd3_4
#define _24C02_sda p3_4
#define _24C02_scl_d pd3_5
#define _24C02_scl p3_5
#define BUSY 0
#define ONLINE 1
#define OK 1
#define NOK 0
#define waitUnit 2
// ---------------------- High Level Functions ---------------
void Write_24C02(unsigned char deviceAddress, unsigned char menAddress, unsigned char byte);
unsigned char Read_24C02(unsigned char deviceAddress, unsigned char menAddress);
#endif
- Final de 24C02.h ----------------------------------------------------------------------------
E agora o mesmo para 24C256:
- Inicio de 24C256.c ----------------------------------------------------------------------------
#include "sfr_r81b.h"
#include "24C256.h"
// ---------------------- Low Level Functions ---------------
void waitFactor(unsigned int factor) {
unsigned int fc=0;
factor*=waitUnit;
for(fc=0; fc<factor; fc++) asm("NOP");
}
unsigned char getSDAState(void) { _24C256_sda_d = 0; asm("NOP"); return(_24C256_sda); }
unsigned char getSCLState(void) { _24C256_scl_d = 0; asm("NOP"); return(_24C256_scl); }
void setSDAHigh(void) { _24C256_sda_d = 1; _24C256_sda = 1; }
void setSCLHigh(void) { _24C256_scl_d = 1; _24C256_scl = 1; }
void setSDALow(void) { _24C256_sda_d = 1; _24C256_sda = 0; }
void setSCLLow(void) { _24C256_scl_d = 1; _24C256_scl = 0; }
void clockToHigh(void) { setSCLHigh(); waitFactor(1); }
void clockToLow(void) { setSCLLow(); waitFactor(1); }
void clockPulse(void) { clockToHigh(); clockToLow(); }
void sendBit(unsigned char bit) {
if(bit) {
setSDAHigh();
} else {
setSDALow();
}
waitFactor(1);
setSCLHigh(); waitFactor(1);
setSCLLow(); waitFactor(1);
}
unsigned char resetBus (void) {
unsigned char sdaStatus;
clockToHigh();
sdaStatus=getSDAState();
clockToLow();
return(sdaStatus==0?BUSY:ONLINE);
}
void startCondition(void) {
setSDAHigh(); waitFactor(1);
setSCLHigh(); waitFactor(1);
setSDALow(); waitFactor(1);
setSCLLow(); waitFactor(1);
}
void stopCondition(void) {
setSDALow(); waitFactor(1);
setSCLHigh(); waitFactor(1);
setSDAHigh(); waitFactor(1);
setSCLHigh(); waitFactor(1);
}
void writeByte(unsigned char byte) {
unsigned char rotateLeft;
unsigned char tmp;
unsigned char toReturn;
rotateLeft = 0;
while(rotateLeft<8) {
tmp=byte;
tmp=(tmp << rotateLeft) >> 7;
rotateLeft++;
sendBit(tmp);
}
}
unsigned char readByte(void) {
unsigned char byte=0;
unsigned char pos=0;
_24C256_sda_d=0;
while(pos<8) {
clockToHigh();
byte|=getSDAState();
if(pos<7) byte<<=1;
pos++;
clockToLow();
}
return(byte);
}
unsigned char readAck (void) {
unsigned char sdaStatus;
clockToHigh();
sdaStatus=getSDAState();
clockToLow();
return(sdaStatus==0?OK:NOK);
}
// ---------------------- High Level Functions ---------------
void Write_24C256(unsigned char deviceAddress, unsigned int menAddress, unsigned char byte) {
unsigned char myAck=0;
unsigned int tmsb,tlsb;
unsigned char msb, lsb;
tlsb = tmsb = menAddress;
tmsb = tmsb >> 8;
tlsb = (tlsb << 8) >> 8;
msb = (unsigned char) tmsb;
lsb = (unsigned char) tlsb;
reset_bus:
while(resetBus()==BUSY);
device_address:
startCondition();
writeByte(deviceAddress);
myAck=readAck();
if(myAck==NOK) goto reset_bus;
men_address:
writeByte(msb);
myAck=readAck();
if(myAck==NOK) goto reset_bus;
men_address1:
writeByte(lsb);
myAck=readAck();
if(myAck==NOK) goto reset_bus;
send_byte:
writeByte(byte);
myAck=readAck();
if(myAck==NOK) goto reset_bus;
stopCondition();
}
unsigned char Read_24C256(unsigned char deviceAddress, unsigned int menAddress) {
unsigned char myAck=0;
unsigned char byte=0;
unsigned int tmsb,tlsb;
unsigned char msb, lsb;
tlsb = tmsb = menAddress;
tmsb = tmsb >> 8;
tlsb = (tlsb << 8) >> 8;
msb = (unsigned char) tmsb;
lsb = (unsigned char) tlsb;
reset_bus:
while(resetBus()==BUSY);
device_address:
startCondition();
writeByte(deviceAddress);
myAck=readAck();
if(myAck==NOK) goto reset_bus;
men_address:
writeByte(msb);
myAck=readAck();
if(myAck==NOK) goto reset_bus;
men_address1:
writeByte(lsb);
myAck=readAck();
if(myAck==NOK) goto reset_bus;
restart_condition:
startCondition();
device_address_read:
writeByte(deviceAddress | 0x01);
myAck=readAck();
if(myAck==NOK) goto reset_bus;
read_byte:
byte = readByte();
sendBit(1);
stopCondition();
return(byte);
}
- Final de 24C256.c ----------------------------------------------------------------------------
- Inicio de 24C256.h ----------------------------------------------------------------------------
#ifndef _24C256_H
#define _24C256_H
#define _24C256_sda_d pd3_4
#define _24C256_sda p3_4
#define _24C256_scl_d pd3_5
#define _24C256_scl p3_5
#define BUSY 0
#define ONLINE 1
#define OK 1
#define NOK 0
#define waitUnit 2
// ---------------------- High Level Functions ---------------
void Write_24C256(unsigned char deviceAddress, unsigned int menAddress, unsigned char byte);
unsigned char Read_24C256(unsigned char deviceAddress, unsigned int menAddress);
#endif
- Final de 24C256.h ----------------------------------------------------------------------------
Para utilizar os códigos é bem simples.
Basta incluir o arquivo equivalente no header do programa onde vai usar, obviamente colocar o arquivo .C no projeto para ser compilado, e chamar as funções do que se deseja fazer, ler ou gravar.
Exemplo:
#include "24C02.h"
// Protótipos
void main(void);
// Variáveis Globais
unsigned char i=0;
unsigned char carToWrite;
unsigned char car;
unsigned char paraGravar;
unsigned char inicio, final;
unsigned char sdaState;
// Ponto de Entrada
void main(void) {
carToWrite=0;
car=0;
for(;;) {
inicio=0;
final=255;
for(i=inicio;i
Write_24C02(0xA0, i, i);
car=0xFF;
car=Read_24C02(0xA0, i);
if(i!=car) {
asm("nop");
}
}
asm("nop");
}
}
Bom é isso ...
Espero que o código ajude... se precisarem de algo, tipo um projeto pronto e rodando para o R8C/1A por exemplo.. é só me avisar que eu posto um link de download aqui!
Enjoy!