Запись на внешнюю ЕЕПРОМку по i2c
- Войдите на сайт для отправки комментариев
Пнд, 09/04/2018 - 15:02
Всем бобра!
Попытался писать данные на еепромку AT24C32 фреймами.
Собсно код:
#define EEPROM_ADDR_WRITE 0b10100000 #define EEPROM_ADDR_READ 0b10100001 unsigned int counter = 0; byte buffer[128] = {0}; void setup() { Serial.begin(9600); TWBR = 72; // i2c 100kHz, CPU 16MHz Serial.println("setup"); for(uint8_t i = 0; i<128; i++)buffer[i] = i; } void loop() { Serial.println("loop"); uint32_t time = micros(); i2c_writePage(0,0,&buffer[0],32);//записываем первые 32байта time = micros()-time; Serial.println(time); delayMicroseconds(600); i2c_writePage(0,32,&buffer[32],32);//записываем вторые 32байта delayMicroseconds(600); i2c_readPage(0,0,32); //читаем первые 32байта delayMicroseconds(600); i2c_readPage(0,32,32);//читаем вторые 32байта Serial.println("Stop"); while(1) ; } void i2c_start(){ TWCR = 0b10100100;// TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN) while(! (TWCR&(1<<7))); } void i2c_stop(){ TWCR = 0b10010100;// TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN) } void i2c_sendByte (unsigned char b){ TWDR = b; TWCR = 0b10000100; //TWCR = (1<<TWINT)|(1<<TWEN) while(! (TWCR&(1<<7))); } uint8_t i2c_readByte(){ // TWCR = 0b11000100;// TWCR = (1<<TWINT)|(1<<TWEA)|(1<<TWEN); TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA); while(! (TWCR&(1<<7))); return TWDR; } uint8_t i2c_readLastByte(){ TWCR = 0b10000100;// TWCR = (1<<TWINT)|(1<<TWEN); while(! (TWCR&(1<<7))); return TWDR; } void i2c_writePage(uint8_t a, uint8_t b, uint8_t * buf, uint8_t len){ i2c_start(); i2c_sendByte(EEPROM_ADDR_WRITE); i2c_sendByte(a); i2c_sendByte(b); for (uint8_t i = 0; i<len; i++) { i2c_sendByte(*(buf+i)); } i2c_stop(); } void i2c_readPage(uint8_t a, uint8_t b, uint8_t len){ uint8_t zzz; i2c_start(); i2c_sendByte(EEPROM_ADDR_WRITE); i2c_sendByte(a); i2c_sendByte(b); i2c_start(); i2c_sendByte(EEPROM_ADDR_READ); for(uint8_t i = 0;i<len-1;i++) {Serial.print(i2c_readByte()); Serial.print(" ");} Serial.println(i2c_readLastByte()); i2c_stop(); }
Первый фрейм пишется и читается ОК, а второй - фигня какая-то. В мониторе наблюдаю:
setup loop 3224 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 Stop
В первую очередь я подозреваю неправильную адресацию фрейма. Главное в даташите ничего про адресацию фреймов не сказано, ну я и подумал, что адрес следующего фрейма 0 (старший байт адреса памяти) 32 (младший байт адреса). Подскажите, кто с проблемой такой сталкивался!
Как оказалось, код был почти правильный. Проблема была не в адресации, а в том, что ЕЕПРОМка была недоступна, т.к., скорее всего, не окончила записывать. Адресация страниц, как я и думал, 1ая - адрес 0, вторая - 32, третья 64... Младший байт адресации имеет 8 бит, старший - только 4 младших бита.
Добавил делеи перед обращением к шине ай2си , и все заработало стабильно.
Потом уже обнаружил, что такой же вопрос уже подымался на этом форуме, но остался без ответа.
Монитор:
Одно плохо: для записи 32х байт тратить 5мсек - чрезчур жирно ...
Byte Write: A Write operation requires two 8-bit data word addresses following the device address word and acknowledgment. Upon receipt of this address, the EEPROM will again respond with a zero then clock in the first 8-bit data word. Following receipt of the 8-bit data word, the EEPROM will output a zero. The addressing device, such as a microcontroller, must then terminate the write sequence with a Stop condition. At this time, the EEPROM enters an internally-timed Write cycle, tWR, to the nonvolatile memory (See Figure 6-5). All inputs are disabled during this Write cycle and the EEPROM will not respond until the Write is complete (See Figure 8-1).
Delay надо делать после записи каждой страницы - это так. Но ведь вместо delay() можно воткнуть полезное мигание светодиодом, например. Читать же можно не страницами, а тупо блоком на длину массива.
Гораздо интереснее, если писать этот код на Wire.h (поэкспериментировал - думал, что проще будет ;). С ним, например, в дефолтовом состоянии невозможно записать 32 байта. 30 - пожалуйста. Почему? Потому что мы сначала делаем write() двух байт стартовой ячейки, потом данные пишем. Но пишем-то не в устройство, а в буфер Wire. А потом только отправляем по endTransmission(). Т.е. данных мы может послать только 30 байта (если не править Wire.h), а следовательно - в кажной странице EEPROM будет неиспользуемая дырка в конце. Но этого как бы мало - если мы попросим у requestFrom() больше, чем размер буфера, а потом начнем читать, то нам будут отдавать ожидаемые... 0xFF. Всегда. Пока не начнем просить меньше.
Нечестный этот Си, ох нечестный...
Читать же можно не страницами, а тупо блоком на длину массива.
Читать же можно не страницами, а тупо блоком на длину массива.
Если в буфер скидывать, то да. А в Serial... не знаю, он еще том монстр. Может бsть начнутся затыки и входящие с i2c данные порастеряются.
Код у вас, полагаю, менее подвержен всяким зависимостям от буферов, но больно уж непонятный. Я поэтому и решил на Wire.h глянуть, что и как. По ячейке-то читаю, а вот со страничной записью не было нужды связываться.
Я жду FRAM для экспериментов - в ней, пишут, запись без задержек идет, на скорости интерфейса.
Код у вас, полагаю, менее подвержен всяким зависимостям от буферов, но больно уж непонятный.
- условие старта
- условие стопа
-записать байт
-считать байт
-считать последний байт
И просто комбинируя этими пятью функциями удобно строить нужный формат, как сделано у меня в функциях i2c_readPage и i2c_writePage. Только по-хорошему нужно еще таймауты прописать, а то можно всю прогу подвесить из-за отвалившегося устройства.
Я жду FRAM для экспериментов - в ней, пишут, запись без задержек идет, на скорости интерфейса.
Я жду FRAM для экспериментов - в ней, пишут, запись без задержек идет, на скорости интерфейса.
Если вы в столицах и любите паять, а не ждать, то берите на electronshik.ru. Судя по каталогу - там есть (FM24C04).
Если вы в столицах и любите паять, а не ждать, то берите на electronshik.ru. Судя по каталогу - там есть (FM24C04).
Не пролетите с питанием. дешевые и ёмкие - низковольтные.
Накатал еще один вариант, с SoftwareWire. Нельзя сказать, что библиотека летает, как самолет, но вешается на любые две ноги и использует только один внутренний буфер (32 байта) +имеет таймаут на операции (судя по коду). Почти совместима по синтаксису с обычной Wire. При небольшом хачинге (поэтому подключена из src) допускает переконфигурирование на лету - один глобальный объект на несколько пар SDA/SCL, естественно по-очереди.