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

Привет 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.

Reply to
Alex Kekin
Loading thread data ...

Привет, 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емного наворочено, зато универсально.

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

Reply to
Vladimir Chekin

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.