Глюк при чтении I2C EEPROM

Sep 16, 2003 1 Replies

Привет All !



Требуется помощь клуба... Проблема в следующем: при чтении I2C EEPROMки иногда считывается вместо нормального значения 0xFF... причем если потом еще раз прочесть этот же адрес, то приходит валидное значение... Память 24lc256, подключена к пику 16F877A к выводам RC3=SCL, RC4=SDA, подтянута к питанию +5В резисторами на 4.7к Запись и чтение осуществляется программной реализацией вне прерывания, при этом прерывания разрешены... Тактовая пика - 20МГц... Где могут быть зарыты грабли?


-------------------- Программная реализация I2C (HiTech C 8.01PL3) ------ void random_write(unsigned char dev_adr, unsigned int mem_adr, unsigned char dat) { i2c_start(); i2c_out_byte(0xa0 | (dev_adr << 1)); i2c_nack(); i2c_out_byte((mem_adr >> 8) & 0xff); // high unsigned char of memory address i2c_nack(); i2c_out_byte(mem_adr & 0xff); // low unsigned char of mem address i2c_nack(); i2c_out_byte(dat); // and finally the data i2c_nack(); i2c_stop(); delay_ms(6); // allow for the programming of the eeprom }



unsigned char random_read(unsigned char dev_adr, unsigned int mem_adr) { unsigned char y; i2c_start(); i2c_out_byte(0xa0 | (dev_adr << 1)); i2c_nack(); i2c_out_byte((mem_adr >> 8) & 0xff); i2c_nack(); i2c_out_byte(mem_adr & 0xff); i2c_nack(); i2c_start(); // no intermediate stop i2c_out_byte(0xa1 | (dev_adr << 1)); // read operation i2c_nack(); y = i2c_in_byte(); i2c_stop(); return(y); }



// Common I2C Routines



unsigned char i2c_in_byte(void) { unsigned char i_byte, n; i2c_high_sda(); for (n=0; n<8; n++) { i2c_high_scl(); if (SDA_PIN) { i_byte = (i_byte << 1) | 0x01; // msbit first } else { i_byte = i_byte << 1; } i2c_low_scl(); } return(i_byte); }



void i2c_out_byte(unsigned char o_byte) { unsigned char n; for(n=0; n<8; n++) { if(o_byte & 0x80) { i2c_high_sda(); } else { i2c_low_sda(); } i2c_high_scl(); i2c_low_scl(); o_byte = o_byte << 1; } i2c_high_sda(); }



void i2c_nack(void) { i2c_high_sda(); // data at one i2c_high_scl(); // clock pulse i2c_low_scl(); }



void i2c_ack(void) { i2c_low_sda(); // bring data low and clock i2c_high_scl(); i2c_low_scl(); i2c_high_sda(); }


void i2c_start(void) { i2c_low_scl(); i2c_high_sda(); i2c_high_scl(); // bring SDA low while SCL is high i2c_low_sda(); i2c_low_scl(); }



void i2c_stop(void) { i2c_low_scl(); i2c_low_sda(); i2c_high_scl(); i2c_high_sda(); // bring SDA high while SCL is high // idle is SDA high and SCL high }



void i2c_high_sda(void) { // bring SDA to high impedance SDA_DIR = 1; delay_uc(3); }



void i2c_low_sda(void) { SDA_PIN = 0; SDA_DIR = 0; // output a hard logic zero delay_uc(3); }



void i2c_high_scl(void) { SCL_DIR = 0; // high impedance SCL_PIN = 1; delay_uc(3); }



void i2c_low_scl(void) { SCL_PIN = 0; SCL_DIR = 0; delay_uc(3); }


-------------------------------------------------------------------------


До встречи, Alex.


Привет, Alex!

16 Sep 03 19:39, Alex Kekin >>> All по теме "Глюк при чтении I2C EEPROM"

AK> Требуется помощь клуба... AK> Проблема в следующем: при чтении I2C EEPROMки иногда считывается вместо AK> нормального значения 0xFF... причем если потом еще раз прочесть этот же AK> адрес,то приходит валидное значение... AK> Память 24lc256, подключена к пику 16F877A к выводам RC3=SCL, RC4=SDA, AK> подтянутак питанию +5В резисторами на 4.7к AK> Запись и чтение осуществляется программной реализацией вне прерывания, AK> при этомпрерывания разрешены... Тактовая пика - 20МГц... Где могут быть AK> зарыты грабли?

Ковырять твою кучу кода на предмет соответствия спецификации И2С, извини, просто некогда. Hо одна функция привлекла внимание:

AK> void i2c_nack(void) AK> { AK> i2c_high_sda(); // data at one AK> i2c_high_scl(); // clock pulse AK> i2c_low_scl(); AK> }

При записи в память любого байта в этой функции должен не только выдан 9-ый клок, а надо и линию SDA прочитать, т .е. сигнал ACK. Если 0, то slave проглотил этот байт и ответил, если 1, то или занят записью или вообще нет такого устройства на шине, чей адрес ты передаёшь в первом байте цикла доступа.

uchar i2c_nack(void) { uchar i;

SCL_HIGH (); i = SDA; //read the acknowledge SCL_LOW ();

return i; }

Второе, функции для записи и твоя i2c_nack(void) в И2С желательно делать не void, а с возвратом результата, чтоб после вызова можно было понять, отвечает тебе девайс или нет. А так ты просто вслепую кидаешь байты по шине.

uchar random_write(unsigned char dev_adr, unsigned int mem_adr, \ unsigned chardat) { i2c_start(); i2c_out_byte(0xa0 | (dev_adr << 1)); if (i2c_nack()) return 1; и тд.

Вызов: if (random_write(A,B,C)) Wait (TIME_EE_WRITE); // Может быть идёт запись

if (random_write(A,B,C)) SetError (EE_NO_ACK);

А функции чтения делать int, когда всё Ок, то в мл. байте возвращается считанное значение, если ошибка, то -1 (0xFFFF).

AK> -------------------- Программная реализация I2C (HiTech C 8.01PL3)

Кстати, в пакете этого компилятора есть готовый пример в директории samples/i2c. Посмотри как там функции реализованы. Hемного наворочено, зато универсально.

Владимир Чекин

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required