Цитата(rushack @ Feb 16 2009, 21:34)

Код
case TW_SR_DATA_ACK:
case TW_SR_GCALL_DATA_ACK:
i2crxbuffer[i2crxindex++] = TWDR;
if(i2crxindex < TWI_RX_BUFFER_SIZE)
TWCR |= (1 << TWINT) | (1 << TWEA);
else
TWCR |= (1 << TWINT);
break;
Пробежался по диагонали не вникая толком в суть (я пока слейва не писал и по этой части докумнтацию не читал).
Вот что мне в этом коде не нравится, так это то, что вся работа с TWCR идёт через
|=Оставил небольшой фрагмент.
В предыдущем прерывании (
TW_SR_SLA_ACK) бит
TWEA был установлен (собственно, он и раньше был установлен, иначе прерывание не прошло бы).
А в данном перывании этот бит никогда не будет сброшен, так как
TWCR |= (1 << TWINT); не изменит его.
Лучше бы каждый раз записывать в регистр константу (и кода меньше, и надёжнее).
Можно для уменьшения писанины что-то в духе
Код
#define TWCR_DEFAULT ((1<<TWINT) | (1<<TWEN) | (1 << TWIE) | (1<<TWEA)) // таки TWEA чаще в 1-ке нужен
...
if(i2crxindex < TWI_RX_BUFFER_SIZE)
TWCR = TWCR_DEFAULT;
else
TWCR = TWCR_DEFAULT & ~(1 << TWEA);
break;
...
case TW_BUS_ERROR:
TWCR = TWCR_DEFAULT | (1 << TWSTO);
break;
И ещё сразу маленькая подсказка по GCC. Лучше так:
Код
uint8_t twi_sr = TWSR & TW_STATUS_MASK;
switch (twi_sr) {
При этом лишний регистр занят не будет, компилятор видит, что дальше переменная не используется и регистр идёт под другие нужды. Но в случае
switch(TWSR & TW_STATUS_MASK) результат переключающего выражения по стандарту имеет тип
int, дальше идут константы тоже типа
int и тут оптимизатор, к сожалению, не замечет, то старший байт выражения гарантированно нулевой, как и старшие байты констант. По крайней мере когда я заглядывал в скомпиированный код - было так.
Идёт 16-битное сравнение вместо 8-битного, что раздувает код и замедляет работу.
А подсказка в виде переключения по 8-битной переменной ему помогает.