Контроллер MSP430F5152 сидит на шине I2C в режиме slave и спит в LPM3. При старте транзакции I2C (мастер - центральный процессор) контроллер просыпается и начинает обмен.
Все работает нормально кроме одного случая - когда в контроллер передается посылка длинной один байт. В этом случае не приходит прерывание "Start condition". Т.е. оно совсем пропускается - первое приходит "Data received", потом "Stop condition" и всё.
При этом, во всех остальных случаях все работает корректно - при посылке больше одного байта, при отключении засыпания и даже если после однобайтной посылки послать Restart (придет первый старт, данные и второй старт).
Код инициализации I2C:
Код
/* ---- Init I2C in slave mode ---- */
UCB0CTL1 |= UCSWRST;
UCB0CTL0 = UCMM | UCMODE_3 | UCSYNC;
UCB0CTL1 = UCSSEL_3 | UCSWRST;
UCB0BRW = 12;
UCB0I2COA = I2C_OWN_ADDRESS;
UCB0CTL1 &= ~UCSWRST;
UCB0IE = UCTXIE | UCRXIE | UCSTTIE | UCSTPIE;
UCB0CTL1 |= UCSWRST;
UCB0CTL0 = UCMM | UCMODE_3 | UCSYNC;
UCB0CTL1 = UCSSEL_3 | UCSWRST;
UCB0BRW = 12;
UCB0I2COA = I2C_OWN_ADDRESS;
UCB0CTL1 &= ~UCSWRST;
UCB0IE = UCTXIE | UCRXIE | UCSTTIE | UCSTPIE;
Код прерывания:
Код
#pragma vector = USCI_B0_VECTOR
__interrupt void i2c_interrupt(void)
{
uint8_t rdata;
switch (__even_in_range(UCB0IV, 12)) {
case 0: break; // no interrupt
case 2: break; // arbitration lost
case 4: break; // not acknowledgement
/* ---- START Condition ---- */
case 6:
if (state == IIC_STATE_STOP)
state = IIC_STATE_RCMD;
break;
/* ---- STOP Condition ---- */
case 8:
state = IIC_STATE_STOP;
break;
/* ---- Data Received ---- */
case 10:
rdata = UCB0RXBUF;
if (state == IIC_STATE_RCMD) {
state = IIC_STATE_DATA;
/* COMMAND handler */
} else {
/* DATA handler */
}
break;
/* ---- Transmit Buffer Ready ---- */
case 12:
UCB0TXBUF = EMPTY_BYTE;
break;
/* ---- UNKNOWN ---- */
default:
break;
}
}
__interrupt void i2c_interrupt(void)
{
uint8_t rdata;
switch (__even_in_range(UCB0IV, 12)) {
case 0: break; // no interrupt
case 2: break; // arbitration lost
case 4: break; // not acknowledgement
/* ---- START Condition ---- */
case 6:
if (state == IIC_STATE_STOP)
state = IIC_STATE_RCMD;
break;
/* ---- STOP Condition ---- */
case 8:
state = IIC_STATE_STOP;
break;
/* ---- Data Received ---- */
case 10:
rdata = UCB0RXBUF;
if (state == IIC_STATE_RCMD) {
state = IIC_STATE_DATA;
/* COMMAND handler */
} else {
/* DATA handler */
}
break;
/* ---- Transmit Buffer Ready ---- */
case 12:
UCB0TXBUF = EMPTY_BYTE;
break;
/* ---- UNKNOWN ---- */
default:
break;
}
}
Дополнение:
Контроллер тактируется от внутреннего генератора REFO 32768Гц, ядро от FLL, которая выдает 1МГц.
Описанная проблема возникает в режимах сна LPM2 и ниже (в LPM0 и LPM1 всё работает), т.е. тогда, когда отключается генератор DCO.
Обратно DCO включается, судя по даташиту, за 150мкс (в режиме Low Side). Если учесть, что транзакция сейчас занимает 170мкс, запуск DCO приходится на конец приема байта данных.
Получается, что из-за того, что DCO долго просыпается, контроллер забывает про start condition?
Почему он тогда не забывает про start если передается два байта?
Надо попробовать на более высокой скорости.