Страница 1 из 1
i2c на прерываниях не отправляется адрес.
Добавлено: Ср авг 17, 2022 11:05:16
vdv22
Здравствуйте, хочу написать функцию на прерываниях для i2c. Формирую условие старта . в прерываниях ловлю код 0х08 ,далее в регистр данных посылаю адрес , но в этом месте все зависает в прерывании ... что не так? Контроллер ATMEGA 328 AVRStudio 7. все по даташиту дела.
void i2c_transmit(void) // функция передачи инициирует условие старта далее все должно происходить в прерывани.
{
TWCR= (1<<TWINT)|(1<<TWEN)|(1<<TWSTA)|(1<<TWIE);
}
вектор прерывания
ISR (TWI_vect) // прерывание по i2c
{
switch((TWSR & 0xF8))
{
case 8: // если старт прошел зависает на этом кейсе
{
TWDR = i2c_SlaveAddress; // в дата регистр пишем адрес подчиненного (он уже сдвинут на 1 в лево!)
TWCR = 1<<TWINT|0<<TWSTA|0<<TWSTO|1<<TWEN|1<<TWIE; // команда напередачу
break;
}
case 0x18: // если аск от ведомого получен
{
TWDR=200; // передаем например 200
TWCR = (1<<TWINT)|(1<<TWEN);
}
}
}
Re: i2c на прерываниях не отправляется адрес.
Добавлено: Ср авг 17, 2022 11:16:47
Martian
vdv22 писал(а):TWCR= (1<<TWINT)|(1<<TWEN)|(1<<TWSTA)|(1<<TWIE);
vdv22 писал(а):TWCR = 1<<TWINT|0<<TWSTA|0<<TWSTO|1<<TWEN|1<<TWIE; // команда напередачу
какой разный стиль... а вот я бы везде ставил скобки, потому что, к стыду своему, приоритетность плохо помню.
а зачем при команде на передачу ещё раз включать и интерфейс, и прерывание, это действительно по даташиту так у атмелов?
Добавлено after 4 minutes 49 seconds:
а, TWCR-у всё заново присваивается... ну. так некрасиво. Это портит логику работы.
Re: i2c на прерываниях не отправляется адрес.
Добавлено: Ср авг 17, 2022 11:19:57
vdv22
по даташиту TWCR = (1<<TWINT) | (1<<TWEN); так тоже не работает
А разность написания это все результат экспериментов- целый день убил на это . Без прерываний все отлично работает.
Re: i2c на прерываниях не отправляется адрес.
Добавлено: Ср авг 17, 2022 11:26:01
uldemir
В AVR-ах ни бум-бум, но так делать, пожалуй, не стоит:
Вы уверены, что в регистре будет стоять только один этот бит
А то что не выходите из прерывания - какой-то флаг обработки его не сбрасываете.
Re: i2c на прерываниях не отправляется адрес.
Добавлено: Ср авг 17, 2022 11:44:06
VNS
[uquote="vdv22",url="/forum/viewtopic.php?p=4274288#p4274288"]Здравствуйте, хочу написать функцию на прерываниях для i2c. Формирую условие старта . в прерываниях ловлю код 0х08[/uquote]
Я в Си не понимаю, но вот что бросилось в глаза... пишете что ловите 0х08 а в коде пишете
0хF8...
switch((TWSR & 0xF8))
а ведь нужно проверять после команды старт именно 0x08 а не 0хF8

Re: i2c на прерываниях не отправляется адрес.
Добавлено: Ср авг 17, 2022 11:47:13
vdv22
если перед выходом из прерывания добавить TWCR = (1<<TWINT); то зависания нет ,но адрес упороно не передается (по осциллнографу и лог анализатору.
SR (TWI_vect) // прерывание по i2c
{
switch((TWSR & 0xF8))
{
case 8: // если старт прошел
{ out=(TWSR & 0xF8);
TWDR = i2c_SlaveAddress; // в дата регистр пишем адрес подчиненного (он уже сдвинут на 1 в лево!)
TWCR = (1<<TWINT)|(0<<TWSTA)|(0<<TWSTO)|(1<<TWEN); // команда напередачу
break;
}
case 0x18: // если аск от ведомого получен
{
TWDR=200; // передаем например 200
TWCR = (1<<TWINT)|(1<<TWEN);
}
}
TWCR = (1<<TWINT); // если добавить сброс флага ,то зависания нет ,но адрес упороно не передается (по осциллнографу и лог анализатору.)
}
Добавлено after 1 minute 6 seconds:
[uquote="VNS",url="/forum/viewtopic.php?p=4274309#p4274309"][uquote="vdv22",url="/forum/viewtopic.php?p=4274288#p4274288"]Здравствуйте, хочу написать функцию на прерываниях для i2c. Формирую условие старта . в прерываниях ловлю код 0х08[/uquote]
Я в Си не понимаю, но вот что бросилось в глаза... пишете что ловите 0х08 а в коде пишете
0хF8...
switch((TWSR & 0xF8))
[/uquote]
F8 это маска . она накладывается на регистр и смотрим какое число получилось
Re: i2c на прерываниях не отправляется адрес.
Добавлено: Ср авг 17, 2022 11:53:24
VNS
[uquote="vdv22",url="/forum/viewtopic.php?p=4274311#p4274311"]F8 это маска[/uquote]
Теперь понял... извиняюсь что отвлёк...

Re: i2c на прерываниях не отправляется адрес.
Добавлено: Ср авг 17, 2022 11:56:40
uldemir
Ну если вы так упорствуете:
vdv22 писал(а):case 8: // если старт прошел
case 0x18: // если аск от ведомого получен
То где кейсы для 0x38, 0x48, 0x58 ... 0xF8? Каждый флаг должен обрабатываться.
В моём драйвере для силикон-лабовского кристалла обработчик выглядит так:
Спойлер
Код: Выделить всё
void I2C_IRQHandler(void) {
if ((I2C_DEV->IEN & I2C_IEN_ARBLOST) && (I2C_DEV->IF & I2C_IF_ARBLOST)) {// Arbitration lost; Interrupt Flag: UCALIFG; Interrupt
i2c_error_code = I2C_ERROR;
i2c_state = i2c_idle;
I2C_DEV->IFC = I2C_IFC_ARBLOST;
}
if ((I2C_DEV->IEN & I2C_IEN_NACK) && (I2C_DEV->IF & I2C_IF_NACK)) { // Not acknowledgment; Interrupt Flag: UCNACKIFG
i2c_error_code = I2C_ERROR;
i2c_state = i2c_stop;
I2C_DEV->IFC = I2C_IFC_NACK;
BUS_RegMaskedClear(&I2C_DEV->IEN, I2C_IEN_TXBL);
I2C_DEV->CMD = I2C_CMD_STOP;
}
if ((I2C_DEV->IEN & I2C_IEN_START) && (I2C_DEV->IF & I2C_IF_START)) { // Start condition received; Interrupt Flag: UCSTTIFG
I2C_DEV->IFC = I2C_IFC_START;
I2C_DEV->TXDATA = i2c_addr;
if (i2c_state != rcv_data) {
BUS_RegMaskedSet(&I2C_DEV->IEN, I2C_IEN_TXBL);
}
}
if ((I2C_DEV->IEN & I2C_IEN_RXFULL) && (I2C_DEV->IF & I2C_IF_RXFULL)) { // Check errata race condition
if (((I2C_DEV->STATUS & I2C_STATUS_RXDATAV) == 0) && (I2C_DEV->STATUS & I2C_STATUS_RXFULL)) {
I2C_DEV->RXDATA; // make dummy read.
}
}
итд...
И, заметьте, после каждого обработанного флага, соответствующий флаг сбрасывается (в регистре IFC). А вы сбрасывая глобальный флаг, возможно оставдяете, что-то необработанным.
Re: i2c на прерываниях не отправляется адрес.
Добавлено: Ср авг 17, 2022 12:06:38
veso74
Ждете, пока шина будет готова, проверьте код состояния для отправленного условия запуска:
Было бы хорошо обработать все возможные состояния.
Re: i2c на прерываниях не отправляется адрес.
Добавлено: Ср авг 17, 2022 12:11:06
vdv22
Обработчик всех флагов будет, но мне сейчас дадо чтоб он хоть адрес отправит - я в свиче обычно делаю default чтоб другое не нужное отсечь. Сейчас в прерывание он заходит только один раз (отслеживаю через uart ) то есть после получения 0x08.
Добавлено after 1 minute 45 seconds:
[uquote="veso74",url="/forum/viewtopic.php?p=4274319#p4274319"]Ждете, пока шина будет готова, проверьте код состояния для отправленного условия запуска:
Было бы хорошо обработать все возможные состояния.[/uquote]
то что вы предлогаете это блокирующий режим -он у меня прекрасно работает . Но я не хочу в цикле жать -мне нужен режим с прерываниями.
Re: i2c на прерываниях не отправляется адрес.
Добавлено: Ср авг 17, 2022 12:30:23
veso74
Отключите возможности для прерывание в прерывании.
Обработайте все возможные команды/состояния.
Поставьте break; след второй выбор.
Спойлер
Код: Выделить всё
Вариант:
--------------------------
ISR(TWI_vect){
static unsigned char state = 0, lastVal = 0;
// Disable Global Interrupt
cli();
switch(TW_STATUS){
case TW_START: // 0x08
case TW_REP_START: // 0x10
case TW_MT_SLA_ACK: // 0x18
case TW_MT_SLA_NACK: // 0x20
case TW_MT_DATA_ACK: // 0x28
case TW_MT_DATA_NACK: // 0x30
case TW_MR_SLA_ACK: // 0x40
case TW_MR_SLA_NACK: // 0x48
case TW_MR_DATA_ACK: // 0x50
case TW_MR_DATA_NACK: // 0x58
case TW_ST_ARB_LOST_SLA_ACK: // 0xB0
case TW_SR_ARB_LOST_SLA_ACK: // 0x68
case TW_SR_GCALL_ACK: //0x70
case TW_SR_ARB_LOST_GCALL_ACK: // 0x78
case TW_SR_GCALL_DATA_ACK: // 0x90
case TW_SR_GCALL_DATA_NACK: // 0x98
case TW_NO_INFO: // 0xF8
TWCR |= (1<<TWINT); // Clear TWINT Flag
break;
case TW_SR_SLA_ACK: // 0x60: SLA+W received, ACK returned
TWCR |= (1<<TWINT); // Clear TWINT Flag
break;
case TW_SR_DATA_ACK: // data received
state = TWDR;
if(lastVal == 'S'){
targetTemp = state;
state = 0;
}
lastVal = state;
TWCR |= (1<<TWINT); // Clear TWINT Flag
break;
case TW_SR_STOP: // 0xA0: stop or repeated start condition received while selected
TWCR |= (1<<TWINT); // Clear TWINT Flag
break;
case TW_ST_SLA_ACK: // 0xA8: SLA+R received, ACK returned
if(state == 'T'){
TWDR = temperature; // Fill TWDR register whith the data to be sent
}else if(state == 'H'){
TWDR = humidity;
}else{
TWDR = -1;
}
TWCR = ((1 << TWEA) | (1 << TWINT) | (1 << TWEN) | (1 << TWIE)); // Enable TWI, Clear TWI interrupt flag
break;
case TW_ST_DATA_ACK: // 0xB8: data transmitted, ACK received
TWCR |= (1<<TWINT); // Clear TWINT Flag
break;
case TW_ST_DATA_NACK: // 0xC0: data transmitted, NACK received
TWCR |= (1<<TWINT); // Clear TWINT Flag
break;
case TW_ST_LAST_DATA: // 0xC8: last data byte transmitted, ACK received
case TW_BUS_ERROR: // 0x00: illegal start or stop condition
default:
TWCR |= (1<<TWINT); // Clear TWINT Flag
break;
}
sei();
}