Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: SAM7 + Mega8 и I2C
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
beer_warrior
Работаю со связкой - SAM7 + Mega8. SAM7 пишет управляющий байт и читает байт статуса.
И вот интересная картина получается. Поставил как возврат статуса константу 0x55.
1. После включения питания первое чтение 0x55, второе 0xFF, все последующие - 0x55.
2. После записи первое чтение 0xFF, все последующие - 0x55.

На код грешить боюсь - для связки мега-мега обкатан многократно. SAM7 без особых проблем работает с 24с02 на той же шине.

Мне кажется допускаю какую-то логическую неувязку в работе с шиной.(Не закрываю обмен или что-то подобное)
singlskv
Цитата(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 и на МЕГА может разберемся вместе.
beer_warrior
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
beer_warrior
Еще интересный эффект всплыл. Попробовал в промежутках обращаться к EEPROM. Получается что после операции записи все равно куда - первое чтение битое. Но если писать в Мегу и делать сначала чтение из памяти, а потом из меги - все пучком. Последовательная запись и чтение из памяти - без проблем.
singlskv
Цитата(beer_warrior @ Mar 10 2007, 19:40) *
Еще интересный эффект всплыл. Попробовал в промежутках обращаться к EEPROM. Получается что после операции записи все равно куда - первое чтение битое. Но если писать в Мегу и делать сначала чтение из памяти, а потом из меги - все пучком. Последовательная запись и чтение из памяти - без проблем.

Покажите инициализацию на SAM

Правильно ли я понял что у Вас обмен всегда по 1 байту ?
и с EEPROM тоже ?
beer_warrior
Код
//--------------------------------------------------------------------------
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;
//clock config
AT91C_BASE_TWI->TWI_CWGR =    ((0x22 << 0)    |    //clk_lo
                            (0x22 << 8)    |    //clk_hi
                            (3 << 16));
}
//--------------------------------------------------------------------------



Вроде нашел зацепку. После изменения константы старая была прочитана еще раз, а потом пошла новая. Т.е. похоже нелады с THR/RHR, что-то там в эррате было на эту тему - сейчас сяду читать.
singlskv
для начала попробуйте вот так:
Цитата(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));
}
//--------------------------------------------------------------------------


Но это только для начала.......
даже если заработает!!!
beer_warrior
Цитата
TWI_RHR; // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Не понял смысла.
singlskv
Цитата(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 нет смысла, нужно искать пути как заставить его работать smile.gif
Особенно повеселило вот это из даташита:
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 ?
это все имеет значение sad.gif
beer_warrior
Цитата
Так что искать логику в TWI на SAM7 нет смысла, нужно искать пути как заставить его работать

a14.gif a14.gif a14.gif


Вы указали правильное направление. Там что-то с установекой статусных битов.
Сделал не совсем по совету, но близко. Экспериментально установлено - чтение отставало на одну транзакцию. Ввел упреждающее чтение RHR перед подачей команды старт. Чтение исправилось, зато запись вешает SAM вглухую. Сейчас сделаю отладочный вывод из регистра статуса и буду шаманить.


PS. К Меге вопросов нет, так что модераторы могут смело переносить тему в АРМы.
singlskv
Цитата(beer_warrior @ Mar 10 2007, 21:47) *
Цитата
Так что искать логику в TWI на SAM7 нет смысла, нужно искать пути как заставить его работать

a14.gif a14.gif a14.gif


Вы указали правильное направление. Там что-то с установекой статусных битов.
Сделал не совсем по совету, но близко. Экспериментально установлено - чтение отставало на одну транзакцию. Ввел упреждающее чтение RHR перед подачей команды старт. Чтение исправилось, зато запись вешает SAM вглухую. Сейчас сделаю отладочный вывод из регистра статуса и буду шаманить.


PS. К Меге вопросов нет, так что модераторы могут смело переносить тему в АРМы.

Я думаю что переносить пока рано smile.gif
С мегой там тоже есть кое-какие вопросы
Ответьте на вопросы прошлого поста про мегу!
Это ВАЖНО!!!
>>Чтение исправилось, зато запись вешает SAM вглухую
Если есть возможность пришлите мне весь код который касается i2c и на АРМ и на меге
Если не хотите публиковать здесь то шлите на PM
Обещаю не выкладывать на всеобщее обсуждение !
Мне это тоже очень нужно, особенно интересует последовательности
при которых у Вас работает с EEPROM и не работает с мега.
У меня подключена только мега, но нужно чтобы и с EEPROM тоже работало
Кстати, а EEPROM какой ?
beer_warrior
Значит так, проблема решена следующим образом:
Код
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 , если будете проездом в Киеве, смело рассчитывайте на пиво cheers.gif
beer_warrior
Цитата
Я думаю что переносить пока рано С мегой там тоже есть кое-какие вопросы Ответьте на вопросы прошлого поста про мегу!Это ВАЖНО!!!

О меге:
Код
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;
}


Долгое шаманство с использованием фич автоинкремента адреса приводило к плохо предсказуемым сбоям.
singlskv
Цитата(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 , если будете проездом в Киеве, смело рассчитывайте на пиво cheers.gif

Пыво это с удовольствием cheers.gif

Но, такое решение:
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*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. Кстати на счет Меги
Я бы в Вашем коде тоже кое-что поменял.
beer_warrior
Цитата
Я бы в Вашем коде тоже кое-что поменял.

Согласен, код писан 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;
}


Честно признаюсь, что этот фрагмент содран где-то на Сахаре.
Благополучно прожил в нескольких проектах. А вот запись повела себя ненадежно поэтому была переделана под байтовый обмен.

А какой формат обмена у вас?
адрес -> внутренний адрес-> данные
или
адрес -> вычитывание большого блока
singlskv
Цитата
Цитата

основная проблема TWI на SAM7 это то, что он работает в "синхронном" режиме То есть ему глубоко наплевать на то что мега держит линию SCL в 0(пока данные не готовы)и у него (SAM7) весь трансфер происходит "синхронно"то есть SAM7 вобще не мониторит состояние линии SCL перед тем как начать передачу!

Опс! Спасибо за наколку. Как-то внимания не обращал.

А они(Atmel) нигде об этом прямо и не пишут
У них есть только одна фраза на этот счет в документации:
"Модуль TWI прекрасно подходит для обмена информацией с EEPROM производства Atmel"
примерно так smile.gif

>> if(hTimer_1ms) hTimer_1ms();
>> if(hTimer_1s) hTimer_1s();
Насколько бысторо выполняются эти 2 функции ?
Цитата
Цитата

Я бы в Вашем коде тоже кое-что поменял.

Согласен, код писан 3 года назад и с тех пор кочует по проектам. Вижу косяки, только руки не доходят преписать.

Код
        case TWS_DATAW_ACK:
            //SLAVE has been transmit a byte and got ACK
            //SLAVE transmit next byte
            {
            break;
            }

любая транзакция(прерывание) по i2c должна заканчиваться записью TWINT в TWCR
иначе будем бесконечно ловить прерывания
по этому в конце switch обязательно должно быть:
default:
TWCR=(1<<TWINT)|(1<<TWEN)|(1<<TWEA)|(1<<TWIE);

так же обязательно ловить код
#define I2C_BUS_ERROR 0xF8

примерно так:
case (I2c_BUS_ERROR):
TWCR= (1<<TWINT)|(1<<TWSTO)|(1<<TWEN)|(1<<TWEA)|(1<<TWIE);

продолжение следует ....
singlskv
Цитата(beer_warrior @ Mar 10 2007, 23:34) *
А какой формат обмена у вас?
адрес -> внутренний адрес-> данные
или
адрес -> вычитывание большого блока

скорее вот этот
адрес -> вычитывание большого блока

на самом деле много байтиков туда(SAM->mega)
и много байтиков обратно (SAM<-mega)
внутреняя адресация в SAM не используется

SAM->mega вобще без проблем
mega->SAM с вышеописанным глюком
beer_warrior
Цитата
"Модуль TWI прекрасно подходит для обмена информацией с EEPROM производства Atmel"примерно так

Это заметно И пожалуй больше не для чего. sad.gif Насколько хорош TWI у мег, настолько паскуден у АРМов. А казалось бы одна контора, могли использовать одинаковый IP-блок.

Цитата
>> if(hTimer_1ms) hTimer_1ms();>> if(hTimer_1s) hTimer_1s();Насколько бысторо выполняются эти 2 функции ?

в милисекундном стоит счетчик на 50 мс. В нем сдвиг бегущего бита и чтение порта. В секундном - мигание светодиодом.


Цитата
любая транзакция(прерывание) по i2c должна заканчиваться записью TWINT в TWCRиначе будем бесконечно ловить прерыванияпо этому в конце switch обязательно должно быть:

Вы об этом? Так я ж сказал - поскипано для ясности. Отрабатываются все возможные состояния - general call,arbitration lost итд, default тоже есть. Предусмотрена работа с раздельными буферами приема и передачи, софтовый байт статуса с флагами занятости и ошибки. А вот написано местами весьма неоптимально - весь файл представляет собой switch на 300 строк.

Цитата
скорее вот этот адрес -> вычитывание большого блока

Мне кажется это генетическое. В прошлом году делал проект, где из EEPROM вытягивалась программа в эдаком байт-коде и передавалась на исполнение. Я на вытягивание программы убил вдвое больше времени, чем на отладку интепретатора. Терялись биты в конце. Было два решения - либо ставить холостой байт в конце каждого блока либо брать меньшими порциями. Побил вычитку на блоки по 32 байта - все работает без вопросов и живет в серии.
singlskv
Цитата(beer_warrior @ Mar 11 2007, 11:18) *
Это заметно И пожалуй больше не для чего. sad.gif Насколько хорош TWI у мег, настолько паскуден у АРМов. А казалось бы одна контора, могли использовать одинаковый IP-блок.
в милисекундном стоит счетчик на 50 мс. В нем сдвиг бегущего бита и чтение порта. В секундном - мигание светодиодом.
Вы об этом? Так я ж сказал - поскипано для ясности. Отрабатываются все возможные состояния - general call,arbitration lost итд, default тоже есть. Предусмотрена работа с раздельными буферами приема и передачи, софтовый байт статуса с флагами занятости и ошибки. А вот написано местами весьма неоптимально - весь файл представляет собой switch на 300 строк.
Мне кажется это генетическое. В прошлом году делал проект, где из EEPROM вытягивалась программа в эдаком байт-коде и передавалась на исполнение. Я на вытягивание программы убил вдвое больше времени, чем на отладку интепретатора. Терялись биты в конце. Было два решения - либо ставить холостой байт в конце каждого блока либо брать меньшими порциями. Побил вычитку на блоки по 32 байта - все работает без вопросов и живет в серии.

Код
//SLAVE TRANSMIT
        case TWS_SLAR_ACK:
            //SLAVE device has been addressed by SLAR
            {
            TWDR = 0x55;
            TWCR;                              // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            TWCR = TW_EXE_NACK;    //generate NACK
            break;
            }

Это то же такое "специальное" знание smile.gif

Вероятно в режиме мастера в каком-то состоянии нужно сделать нечто подобное
_dem
Кстати, решение по остановке TWI у SAM есть - просто выключаем его в PMC на необходимое время.

Если конкретно, то в таком цикле вычитки из EEPROM :

Код
    while (size-- >1){

        // Wait THR Holding register to be empty
        while (!(pTwi->TWI_SR & AT91C_TWI_TXRDY));
        /*
        AT91C_BASE_PMC->PMC_PCDR = (1<< AT91C_ID_TWI);
        sleep(10);
        AT91C_BASE_PMC->PMC_PCER = (1<< AT91C_ID_TWI);    
        */
        // Send first byte
        pTwi->TWI_THR = *(data2send++);
        
    }


приведенный финт ушами прекрасно работает
SasaVitebsk
Забавно иногда смотреть. Разные программисты в разных городах и часовых поясах используют очень близкие решения. smile.gif

Я недавно бился со связкой двух мег по I2C. m640+m48. Где м48 использовалась в качестве часов+чтение датчиков, а с точки зрения м640 была 24с01. smile.gif И проблемы всплыли толь при уходе от байтового режима в страничный. На этой же шине сидели 2 микрухи 24с512.

Так вот вычислил такой момент. У меня м48 практически постоянно находилась в IDLE. Просыпалась по часам и TWI. Работала от внутреннего генератора 8MHz. Процедуры обработки - минимальны.

У меня м48 не успевала правильно обработать шину i2c в режиме слэйв с частотой свыше 150кГц. Наверное где-то не успевала просыпаться и что-то упускала. Как результат мешала работе 24с512. При снижении частоты ниже 150 - всё прекрасно заработало.

К сожалению подробности не выяснял. Как обычно - некогда. 05.gif


Кстати. Один раз я использовал для связи двух AVR SPI обмен. Плотность 8000 байт в секунду. smile.gif Всё работало совершенно устойчиво. Никаких сбоев и коллизий. Правда микрухи стояли с двух сторон одной и той же платы. То есть длина проводников - 1см. smile.gif В серию не пошло. Мы потом всё таки выкинули вторую и впёрли всю обработку в одну.
singlskv
Цитата(SasaVitebsk @ Aug 3 2007, 23:04) *
Кстати. Один раз я использовал для связи двух AVR SPI обмен. Плотность 8000 байт в секунду. smile.gif Всё работало совершенно устойчиво. Никаких сбоев и коллизий. Правда микрухи стояли с двух сторон одной и той же платы. То есть длина проводников - 1см. smile.gif В серию не пошло. Мы потом всё таки выкинули вторую и впёрли всю обработку в одну.

В том проекте по связке SAM7+mega8 мне удалось получить устойчивую связь даже
на частоте i2c 600KHz при этом реальный(полезный) поток получился ~27000 байт/сек.
При 400KHz i2c трансфер был ~22Kb/sek
Быстрее мега не успевала готовить данные, она там еще много чем полезным занималась
(до 16 дискретных вxодов/выходов с фильтрацией, SPI, PWM, запись во
внутреннюю EEPROM, и тд ) smile.gif
И все работало на частоте меги 8MHz. smile.gif
На 16Mhz трансфер наверное был бы повыше, правда SAM7 начинал уже подтормаживать smile.gif
SasaVitebsk
Мужчина! biggrin.gif
singlskv
Цитата(SasaVitebsk @ Aug 4 2007, 22:52) *
Мужчина! biggrin.gif
Это Вы о чем ? 07.gif
Познакомиться ? biggrin.gif biggrin.gif biggrin.gif
Kirill Frolov
Цитата(beer_warrior @ Mar 10 2007, 21:35) *
Работаю со связкой - SAM7 + Mega8.


Мне сабж всю душу вымотал. Вот именно в аналогичной конфигурации.
Если вкратцее -- у at91sam7x256 недоделанный и глючый TWI. Сбоит и
зависает от любой помехи на шине. И без костылей и подпорок ™ в виде
таймаутов, принудительных сбросов и принудительной же, ручной, манипуляции сигналами с целью освободить шину от "зависших" в таком состоянии slave -- зависает вусмерть. Благо что программно сбрасывается (причём где-то за несколько десятков микросекунд -- какие там процессы при этом внутри происходят, одному Билу Гейцу известно).
При том, что сам протокол I2C так интересно устроен, что отвалившийся
невовремя мастер в свою очередь вводит в неадекватное состояние
подчинённых (TWC если когда пропал невовремя), см. выше. С AVR проще, за ним
неадекватностей не замечено, за исключением того (у меня их много),
что арбитраж в режиме slave они "умеют" (именно, что в кавычках) только
на байтовом уровне. Требуют аккуратного обращения с флагом подтверждения обработки прерывания (ВНИМАНИЕ!) и, похоже, запись в CR без паузы в пару тактов иногда не имеет действия. В итоге -- у меня работает, вроде...

А, да, ещё в догонку. AR91SAM7 не умеет "repeated start condition" (для SMBUS),
впрочем ARV их толком и не распознаёт...

Цитата
SAM7 пишет управляющий байт и читает байт статуса.
И вот интересная картина получается. Поставил как возврат статуса константу 0x55.
1. После включения питания первое чтение 0x55, второе 0xFF, все последующие - 0x55.
2. После записи первое чтение 0xFF, все последующие - 0x55.


90%, что забыл, что в конце последнего байта NACK давать надо.

А, ещё одно. Перед установкой MREAD прочитай RHR...
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.