|
SAM7 + Mega8 и I2C |
|
|
|
Mar 10 2007, 18:07
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(beer_warrior @ Mar 10 2007, 17:35)  Работаю со связкой - SAM7 + Mega8. SAM7 пишет управляющий байт и читает байт статуса. И вот интересная картина получается. Поставил как возврат статуса константу 0x55. 1. После включения питания первое чтение 0x55, второе 0xFF, все последующие - 0x55. 2. После записи первое чтение 0xFF, все последующие - 0x55.
На код грешить боюсь - для связки мега-мега обкатан многократно. SAM7 без особых проблем работает с 24с02 на той же шине.
Мне кажется допускаю какую-то логическую неувязку в работе с шиной.(Не закрываю обмен или что-то подобное) а работа на SAM7 и на mega8 по прерываниям ? окончание обмена по NOT ACK или просто STOP от мастера ? обмен каждый раз по 1 байту ? P.S. Разбираюсь с той же связкой, так что то же очень интересует тема. Если приведете куски кода и на SAM и на МЕГА может разберемся вместе.
|
|
|
|
|
Mar 10 2007, 19:09
|

Профессионал
    
Группа: Свой
Сообщений: 1 065
Регистрация: 8-10-05
Из: Kiev, UA
Пользователь №: 9 380

|
SAM работает поллингом, проще некуда: Код bool ReadByteI2C(BYTE addr, BYTE* data) { //set device adr AT91C_BASE_TWI->TWI_MMR = (addr << 16)| AT91C_TWI_MREAD; //start TWI_START();//macros //write data while(!(AT91C_BASE_TWI->TWI_SR & AT91C_TWI_RXRDY)); *data = AT91C_BASE_TWI->TWI_RHR; //stop TWI_STOP();//macros while(!(AT91C_BASE_TWI->TWI_SR & AT91C_TWI_TXCOMP)); return true; }
bool WriteByteI2C(BYTE addr, BYTE data) { //set device adr AT91C_BASE_TWI->TWI_MMR = (addr << 16); AT91C_BASE_TWI->TWI_THR = data; //start TWI_START();//macros //write data while(!(AT91C_BASE_TWI->TWI_SR & AT91C_TWI_TXRDY)); //stop TWI_STOP();//macros while(!(AT91C_BASE_TWI->TWI_SR & AT91C_TWI_TXCOMP)); return true; } bool - потому что предполагается добавить обработку статуса транзакции. Мега живет на прерывании привожу только имеющее отношение к делу: Код SIGNAL(SIG_2WIRE_SERIAL) { //TEST0_ON(); TWCB.sta = TWSR & 0xf8; switch(TWCB.sta) { //SLAVE RECEIVE
case TWS_SLAW_ACK: //SLAVE device has been addressed by SLAW { TWCR = TW_EXE_ACK; //generate ACK break; } case TWS_DATAR_ACK_SLAW: //SLAVE has been got a byte, ACK will generated { //TEST1_ON(); data = TWDR; TWCR = TW_EXE_ACK; //switch to adressed mode break; } case TWS_STOP: //stop condition has been detected { TWCR = TW_EXE_ACK; //& generate ACK break; } //SLAVE TRANSMIT case TWS_SLAR_ACK: //SLAVE device has been addressed by SLAR { TWDR = 0x55; TWCR = TW_EXE_NACK; //generate NACK break; } case TWS_DATAW_ACK: //SLAVE has been transmit a byte and got ACK //SLAVE transmit next byte { break; } case TWS_DATAW_NACK: //SLAVE has been transmit a byte and got NACK //end of transmision { TWCR = TW_EXE_ACK; //switch to adressed mode break; } } }//switch } // // // //TW commands #define TW_EXE_STA (1<<TWINT)|(1<<TWIE)|(1<<TWEN)|(1<<TWSTA) //make start condition #define TW_EXE_STO (1<<TWINT)|(1<<TWIE)|(1<<TWEN)|(1<<TWSTO) //make stop condition #define TW_EXE_ACK (1<<TWINT)|(1<<TWIE)|(1<<TWEN)|(1<<TWEA) //transmit byte and wait ACK #define TW_EXE_NACK (1<<TWINT)|(1<<TWIE)|(1<<TWEN) //transmit byte and wait NACK
//SLAVE RECEIVER #define TWS_SLAW_ACK 0x60 #define TWS_ARB_LOST_SLAW 0x68 #define TWS_GEN_CALL 0x70 #define TWS_ARB_LOST_GC 0x78 #define TWS_DATAR_ACK_SLAW 0x80 #define TWS_DATAR_NACK_SLAW 0x88 #define TWS_DATAR_ACK_GC 0x90 #define TWS_DATAR_NACK_GC 0x98 #define TWS_STOP 0xa0
//SLAVE TRANSMITTER #define TWS_SLAR_ACK 0xa8 #define TWS_ARB_LOST_SLAR 0xb0 #define TWS_DATAW_ACK 0xb8 #define TWS_DATAW_NACK 0xc0 #define TWS_DATA_LAST 0xc8
--------------------
Вони шукають те, чого нема, Щоб довести, що його не існує.
|
|
|
|
|
Mar 10 2007, 20:02
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(beer_warrior @ Mar 10 2007, 19:40)  Еще интересный эффект всплыл. Попробовал в промежутках обращаться к EEPROM. Получается что после операции записи все равно куда - первое чтение битое. Но если писать в Мегу и делать сначала чтение из памяти, а потом из меги - все пучком. Последовательная запись и чтение из памяти - без проблем. Покажите инициализацию на SAM Правильно ли я понял что у Вас обмен всегда по 1 байту ? и с EEPROM тоже ?
|
|
|
|
|
Mar 10 2007, 20:28
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
для начала попробуйте вот так: Цитата(beer_warrior @ Mar 10 2007, 20:14)  Код //-------------------------------------------------------------------------- void InitI2C(void) { //device on AT91F_PMC_EnablePeriphClock(AT91C_BASE_PMC,(1 << AT91C_ID_TWI)); //enable device AT91C_BASE_TWI->TWI_CR = AT91C_TWI_SWRST; AT91C_BASE_TWI->TWI_CR = AT91C_TWI_MSEN; TWI_RHR; // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //clock config AT91C_BASE_TWI->TWI_CWGR = ((0x22 << 0) | //clk_lo (0x22 << 8) | //clk_hi (3 << 16)); } //-------------------------------------------------------------------------- Но это только для начала....... даже если заработает!!!
|
|
|
|
|
Mar 10 2007, 21:26
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(beer_warrior @ Mar 10 2007, 20:35)  Цитата TWI_RHR; // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Не понял смысла. Читаем мусор который с очень большой вероятностью возникнет в TWI_RHR после выставления AT91C_TWI_MSEN А еще после AT91C_TWI_MSEN 1 = As soon as data byte is transferred from TWI_THR to internal shifter or if a NACK error is detected, TXRDY is set at the same time as TXCOMP and NACK. TXRDY is also set when MSEN is set (enable TWI).Так что искать логику в TWI на SAM7 нет смысла, нужно искать пути как заставить его работать  Особенно повеселило вот это из даташита: In master read mode, if a NACK bit is received, the STOP is automatically performed. для байтового обмена Atmel рекомендует такие последовательности: чтение Код //* Set control register and send start *AT91C_TWI_CR = AT91C_TWI_START | AT91C_TWI_MSEN | AT91C_TWI_STOP;
//* Wait complete by TXCOMP or TXRDY Status = *AT91C_TWI_SR; while (!(status & AT91C_TWI_TXCOMP)){ Status = *AT91C_TWI_SR; }
//* Get data Value = *AT91C_TWI_RHR; запись Код //* Set control register *AT91C_TWI_CR = AT91C_TWI_START | AT91C_TWI_MSEN | AT91C_TWI_STOP;
//* Set Data register for start transmission *AT91C_TWI_THR = 0XAA;
//* Wait end transmission Status = *AT91C_TWI_SR; while (!(status & AT91C_TWI_TXCOMP)){ Status = *AT91C_TWI_SR; } то есть START и STOP выставляем одновременно перед приемом передачей 1 байта только ИМХО, там все равно не все чисто ! например при записи вы можете вобще не выставлять AT91C_TWI_START передача начнется в любом случае при записи *AT91C_TWI_THR = 0XAA; Кстати, а чем еще у Вас занята мега ? Разрешены ли какие-то прерывания еще ? Если разрешены, то сколько времени они занимают ? какая частота i2c ? это все имеет значение
|
|
|
|
|
Mar 10 2007, 22:06
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(beer_warrior @ Mar 10 2007, 21:47)  Цитата Так что искать логику в TWI на SAM7 нет смысла, нужно искать пути как заставить его работать Вы указали правильное направление. Там что-то с установекой статусных битов. Сделал не совсем по совету, но близко. Экспериментально установлено - чтение отставало на одну транзакцию. Ввел упреждающее чтение RHR перед подачей команды старт. Чтение исправилось, зато запись вешает SAM вглухую. Сейчас сделаю отладочный вывод из регистра статуса и буду шаманить. PS. К Меге вопросов нет, так что модераторы могут смело переносить тему в АРМы. Я думаю что переносить пока рано  С мегой там тоже есть кое-какие вопросы Ответьте на вопросы прошлого поста про мегу! Это ВАЖНО!!! >>Чтение исправилось, зато запись вешает SAM вглухую Если есть возможность пришлите мне весь код который касается i2c и на АРМ и на меге Если не хотите публиковать здесь то шлите на PM Обещаю не выкладывать на всеобщее обсуждение ! Мне это тоже очень нужно, особенно интересует последовательности при которых у Вас работает с EEPROM и не работает с мега. У меня подключена только мега, но нужно чтобы и с EEPROM тоже работало Кстати, а EEPROM какой ?
|
|
|
|
|
Mar 10 2007, 22:13
|

Профессионал
    
Группа: Свой
Сообщений: 1 065
Регистрация: 8-10-05
Из: Kiev, UA
Пользователь №: 9 380

|
Значит так, проблема решена следующим образом: Код bool ReadByteI2C(BYTE addr, BYTE* data) { //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! *data = AT91C_BASE_TWI->TWI_RHR; //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //set device & internal adr AT91C_BASE_TWI->TWI_MMR = (addr << 16)| AT91C_TWI_MREAD; //start TWI_START(); //write data while(!(AT91C_BASE_TWI->TWI_SR & AT91C_TWI_RXRDY)); *data = AT91C_BASE_TWI->TWI_RHR; //stop TWI_STOP(); while(!(AT91C_BASE_TWI->TWI_SR & AT91C_TWI_TXCOMP)); //*data = AT91C_BASE_TWI->TWI_RHR; return true; }
#define TWI_START() AT91C_BASE_TWI->TWI_CR = AT91C_TWI_START; #define TWI_STOP() AT91C_BASE_TWI->TWI_CR = AT91C_TWI_STOP; Весь остальной код, тот же, что и в начале топика. Закомментированное чтение в конце функции всегда возвращает 0. Неработающая запись в предыдущем посте - глюк РС-шного софта. Протестировано записью произвольных значений в PORTD работающий на выход и последующего чтения из PIND. Процесс перемежался с произвольными обращениями к памяти. Пока глюков не замечено. Следующим номером программы намечен запуск I2C LCD на той же шине. Ежели появятся глюки - сообщу. Уважаемый singlskv , если будете проездом в Киеве, смело рассчитывайте на пиво
--------------------
Вони шукають те, чого нема, Щоб довести, що його не існує.
|
|
|
|
|
Mar 10 2007, 22:37
|

Профессионал
    
Группа: Свой
Сообщений: 1 065
Регистрация: 8-10-05
Из: Kiev, UA
Пользователь №: 9 380

|
Цитата Я думаю что переносить пока рано С мегой там тоже есть кое-какие вопросы Ответьте на вопросы прошлого поста про мегу!Это ВАЖНО!!! О меге: Код int main(void) {
cli(); adr = eeprom_read_byte(ADR); DDRD = 0xff; PORTD = port; TWS_Init(0x10); //enable interrupts sei();
//-------------------------------------------------------------------------- //main loop for(;;) { //PORTD++; } return 0; }//main
__inline__ void TWS_Init(BYTE addr) { TWAR = (addr << 1); TWCR = (1 << TWEN) | (1 << TWIE) |(1 << TWEA); Фьюзы по умолчанию - живет от внутреннего генератора, слэйву это некритично. Работает в качестве внешнего контроллера клавиатуры - дабы не тратить драгоценные ножки SAMa. Пока писал пост подключил таймер для опроса клавиатуры - ситуация не изменилась. Код таймера Код //------------------------------------------------------------------------ #ifdef _MEGA8_ SIGNAL(SIG_OUTPUT_COMPARE2) #endif #ifdef _MEGA88_ SIGNAL(SIG_OUTPUT_COMPARE2A) #endif { //sinchronous timer operation, 100uS system_timer.timer_100us++; if(hTimer_100us) hTimer_100us(); if(system_timer.timer_100us >= 10) //100uS * 10 = 1uS { system_timer.timer_1ms++; system_timer.timer_100us = 0; if(hTimer_1ms) hTimer_1ms(); } if(system_timer.timer_1ms >= 1000) //1mS * 1000 = 1s { system_timer.timer_1s++; system_timer.timer_1ms = 0; if(hTimer_1s) hTimer_1s(); } } //------------------------------------------------------------------------ void InitSysTimer2(void) { TCNT2 = 0; #ifdef _MEGA8_ //OCR2 = 138; //OCR2 = 8; OCR2 = 14; TCCR2 = 0; TCCR2 = (1 << WGM21)|(1 << CS21);//CTC mode //TCCR2 = (1 << WGM21)|(1 << CS20);//CTC mode //TCCR2 = (1 << WGM21)|(1 << CS22)|(1 << CS20);//CTC mode TIMSK |= (1 << OCIE2); #endif #ifdef _MEGA88_ OCR2A = 138; TCCR2A = 0; TCCR2A = (1<< WGM21);//;//CTC mode TCCR2B = 0; //TCCR2B = (1 << CS21);//clk/8 TCCR2B = (1 << CS22)|(1 << CS20);//clk/128 TIMSK2 |= (1<<OCIE2A); #endif } //------------------------------------------------------------------------ EEPROM 24xx Работает так. Код void AT24WriteMem(DWORD addr, BYTE* src, DWORD len) { while(len) { AT24WriteByte(addr,*src); addr++; src++; len--; } }
bool AT24WriteByte(DWORD addr, BYTE data) { //set device & internal adr AT91C_BASE_TWI->TWI_MMR = (AT91C_TWI_IADRSZ_2_BYTE|(0x50 << 16)); AT91C_BASE_TWI->TWI_IADR = addr; AT91C_BASE_TWI->TWI_THR = data; //start TWI_START(); //write data while(!(AT91C_BASE_TWI->TWI_SR & AT91C_TWI_TXRDY)); //stop TWI_STOP(); while(!(AT91C_BASE_TWI->TWI_SR & AT91C_TWI_TXCOMP)); return true; } Долгое шаманство с использованием фич автоинкремента адреса приводило к плохо предсказуемым сбоям.
--------------------
Вони шукають те, чого нема, Щоб довести, що його не існує.
|
|
|
|
|
Mar 10 2007, 22:49
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(beer_warrior @ Mar 10 2007, 22:13)  Значит так, проблема решена следующим образом: Код bool ReadByteI2C(BYTE addr, BYTE* data) { //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! *data = AT91C_BASE_TWI->TWI_RHR; //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //set device & internal adr AT91C_BASE_TWI->TWI_MMR = (addr << 16)| AT91C_TWI_MREAD; //start TWI_START(); //write data while(!(AT91C_BASE_TWI->TWI_SR & AT91C_TWI_RXRDY)); *data = AT91C_BASE_TWI->TWI_RHR; //stop TWI_STOP(); while(!(AT91C_BASE_TWI->TWI_SR & AT91C_TWI_TXCOMP)); //*data = AT91C_BASE_TWI->TWI_RHR; return true; }
#define TWI_START() AT91C_BASE_TWI->TWI_CR = AT91C_TWI_START; #define TWI_STOP() AT91C_BASE_TWI->TWI_CR = AT91C_TWI_STOP; Весь остальной код, тот же, что и в начале топика. Закомментированное чтение в конце функции всегда возвращает 0. Неработающая запись в предыдущем посте - глюк РС-шного софта. Протестировано записью произвольных значений в PORTD работающий на выход и последующего чтения из PIND. Процесс перемежался с произвольными обращениями к памяти. Пока глюков не замечено. Следующим номером программы намечен запуск I2C LCD на той же шине. Ежели появятся глюки - сообщу. Уважаемый singlskv , если будете проездом в Киеве, смело рассчитывайте на пиво  Пыво это с удовольствием Но, такое решение: //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! *data = AT91C_BASE_TWI->TWI_RHR; //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! подходит только для байтового обмена !!! Если будет последовательное чтение с EEPROM или FRAM то это будет работать криво Давайте разбираться подробнее, если конечно есть желание... В двух словах моя проблема: i2c на меге работает по полингу i2c на АРМ работает по прерываниям основная проблема TWI на SAM7 это то, что он работает в "синхронном" режиме То есть ему глубоко наплевать на то что мега держит линию SCL в 0(пока данные не готовы) и у него (SAM7) весь трансфер происходит "синхронно" то есть SAM7 вобще не мониторит состояние линии SCL перед тем как начать передачу! С этой проблеммой я кое-как разобрался, НО, раз в секунду (2,3,5 секунд) у меня происходит следующее: мега получает правильный запрос, готовит ответ и передает его при запросе от мастера Ответ от меги ТОЧНО готовится правильный при этом (иногда) SAM7 получает первый байт ответа неправильным в нем установлен старший бит в 1 хотя должен быть 0 Так как у меня сейчас нет подключенного к i2c "железного" i2c девайса то поймать где проблемма не получается По этому просьба, перешлите мне последовательность обращения к eeprom Возможно это поможет понять все тонкости P.S. Кстати на счет Меги Я бы в Вашем коде тоже кое-что поменял.
|
|
|
|
|
Mar 10 2007, 23:34
|

Профессионал
    
Группа: Свой
Сообщений: 1 065
Регистрация: 8-10-05
Из: Kiev, UA
Пользователь №: 9 380

|
Цитата Я бы в Вашем коде тоже кое-что поменял. Согласен, код писан 3 года назад и с тех пор кочует по проектам. Вижу косяки, только руки не доходят преписать. Цитата основная проблема TWI на SAM7 это то, что он работает в "синхронном" режиме То есть ему глубоко наплевать на то что мега держит линию SCL в 0(пока данные не готовы)и у него (SAM7) весь трансфер происходит "синхронно"то есть SAM7 вобще не мониторит состояние линии SCL перед тем как начать передачу! Опс! Спасибо за наколку. Как-то внимания не обращал. Цитата По этому просьба, перешлите мне последовательность обращения к eeprom Возможно это поможет понять все тонкости Да вобщем то я уже дал запись. Дам и чтение - Код void AT24ReadMem(DWORD addr, BYTE* src, DWORD len) { //DWORD AT24_Read(BYTE* data, BYTE dadr, DWORD address, DWORD size) unsigned int status; // Set the TWI Master Mode Register AT91C_BASE_TWI->TWI_MMR = (0x50 << 16)| AT91C_TWI_IADRSZ_2_BYTE | AT91C_TWI_MREAD; // Set TWI Internal Address Register AT91C_BASE_TWI->TWI_IADR = addr; // Start transfer AT91C_BASE_TWI->TWI_CR = AT91C_TWI_START; status = AT91C_BASE_TWI->TWI_SR; while (len-- >1) { // Wait RHR Holding register is full while (!(AT91C_BASE_TWI->TWI_SR & AT91C_TWI_RXRDY)); // Read byte *(src++) = AT91C_BASE_TWI->TWI_RHR; } AT91C_BASE_TWI->TWI_CR = AT91C_TWI_STOP; status = AT91C_BASE_TWI->TWI_SR; // Wait transfer is finished while (!(AT91C_BASE_TWI->TWI_SR & AT91C_TWI_TXCOMP)); // Read last byte *src = AT91C_BASE_TWI->TWI_RHR; } Честно признаюсь, что этот фрагмент содран где-то на Сахаре. Благополучно прожил в нескольких проектах. А вот запись повела себя ненадежно поэтому была переделана под байтовый обмен. А какой формат обмена у вас? адрес -> внутренний адрес-> данные или адрес -> вычитывание большого блока
--------------------
Вони шукають те, чого нема, Щоб довести, що його не існує.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|