Код
AT91F_TWI_CfgPIO();
AT91F_TWI_Configure(AT91C_BASE_TWI);
*AT91C_TWI_CWGR = (F_MCK/F_TWI-6)/4 + ((F_MCK/F_TWI-6)/4 << 8) + (1<<16); //=0x17676
*AT91C_TWI_MMR = (2 << 8) | (TWIOp.dev->addr << 16);
*AT91C_TWI_IADR = 0x57;
...
//выдать start, адрес, данные
while (len--) {
*AT91C_TWI_THR = *buf++;
*AT91C_TWI_CR = AT91C_TWI_START;
do {
tmp = *AT91C_TWI_SR;
if (tmp & AT91C_TWI_NACK) {rprintf("NACK\r\n");break;}
if (tmp & AT91C_TWI_OVRE) {rprintf("OVRE\r\n");break;}
if (tmp & AT91C_TWI_UNRE) {rprintf("UNRE\r\n");break;}
} while (!(tmp & AT91C_TWI_TXRDY));
if (tmp & AT91C_TWI_NACK) break;
if (tmp & AT91C_TWI_OVRE) break;
if (tmp & AT91C_TWI_UNRE) break;
}
//выдать stop
*AT91C_TWI_CR = AT91C_TWI_STOP;
while (!(*AT91C_TWI_SR & AT91C_TWI_TXCOMP));
AT91F_TWI_Configure(AT91C_BASE_TWI);
*AT91C_TWI_CWGR = (F_MCK/F_TWI-6)/4 + ((F_MCK/F_TWI-6)/4 << 8) + (1<<16); //=0x17676
*AT91C_TWI_MMR = (2 << 8) | (TWIOp.dev->addr << 16);
*AT91C_TWI_IADR = 0x57;
...
//выдать start, адрес, данные
while (len--) {
*AT91C_TWI_THR = *buf++;
*AT91C_TWI_CR = AT91C_TWI_START;
do {
tmp = *AT91C_TWI_SR;
if (tmp & AT91C_TWI_NACK) {rprintf("NACK\r\n");break;}
if (tmp & AT91C_TWI_OVRE) {rprintf("OVRE\r\n");break;}
if (tmp & AT91C_TWI_UNRE) {rprintf("UNRE\r\n");break;}
} while (!(tmp & AT91C_TWI_TXRDY));
if (tmp & AT91C_TWI_NACK) break;
if (tmp & AT91C_TWI_OVRE) break;
if (tmp & AT91C_TWI_UNRE) break;
}
//выдать stop
*AT91C_TWI_CR = AT91C_TWI_STOP;
while (!(*AT91C_TWI_SR & AT91C_TWI_TXCOMP));
В отладочных целях организую постоянную запись в FRAM. Код работает, сигналы по SDA/SCL бегают. Касаюсь щупом SCL - код виснет в цикле do...while; в терминалке вижу, что ни один из проверяемых в нём битов регистра TWI_SR не срабатывает; помогает только сброс.
Как правильнее бороться с такой ситуацией? есть ли типовой способ ее разрешения? пока вижу только один способ - следить в фоне за работой TWI и сбрасывать его при зависании.