i2c на прерываниях не отправляется адрес.

Обсуждаем контроллеры компании Atmel.
Ответить
Первый раз сказал Мяу!
Аватара пользователя
Сообщения: 39
Зарегистрирован: Чт июн 08, 2017 17:52:33

Сообщение 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);
}
}

}
Реклама
Друг Кота
Сообщения: 12867
Зарегистрирован: Сб дек 18, 2021 19:25:32

Сообщение 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-у всё заново присваивается... ну. так некрасиво. Это портит логику работы.
Контактная информация:
Реклама
Первый раз сказал Мяу!
Аватара пользователя
Сообщения: 39
Зарегистрирован: Чт июн 08, 2017 17:52:33

Сообщение vdv22 »

по даташиту TWCR = (1<<TWINT) | (1<<TWEN); так тоже не работает

А разность написания это все результат экспериментов- целый день убил на это . Без прерываний все отлично работает.
Друг Кота
Аватара пользователя
Сообщения: 7362
Зарегистрирован: Пт авг 28, 2009 21:34:30
Откуда: 845-й км.

Сообщение uldemir »

В AVR-ах ни бум-бум, но так делать, пожалуй, не стоит:

Код: Выделить всё

switch((TWSR & 0xF8))
Вы уверены, что в регистре будет стоять только один этот бит А то что не выходите из прерывания - какой-то флаг обработки его не сбрасываете.
Реклама
Эиком - электронные компоненты и радиодетали
VNS
Говорящий с текстолитом
Аватара пользователя
Сообщения: 1633
Зарегистрирован: Пт дек 10, 2021 12:48:46
Откуда: Тюмень

Сообщение VNS »

[uquote="vdv22",url="/forum/viewtopic.php?p=4274288#p4274288"]Здравствуйте, хочу написать функцию на прерываниях для i2c. Формирую условие старта . в прерываниях ловлю код 0х08[/uquote]
Я в Си не понимаю, но вот что бросилось в глаза... пишете что ловите 0х08 а в коде пишете 0хF8... :dont_know:
switch((TWSR & 0xF8))
а ведь нужно проверять после команды старт именно 0x08 а не 0хF8 :)
Последний раз редактировалось VNS Ср авг 17, 2022 11:46:29, всего редактировалось 1 раз.
Реклама
Первый раз сказал Мяу!
Аватара пользователя
Сообщения: 39
Зарегистрирован: Чт июн 08, 2017 17:52:33

Сообщение 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... :dont_know:
switch((TWSR & 0xF8))
[/uquote]

F8 это маска . она накладывается на регистр и смотрим какое число получилось
Реклама
VNS
Говорящий с текстолитом
Аватара пользователя
Сообщения: 1633
Зарегистрирован: Пт дек 10, 2021 12:48:46
Откуда: Тюмень

Сообщение VNS »

[uquote="vdv22",url="/forum/viewtopic.php?p=4274311#p4274311"]F8 это маска[/uquote]
Теперь понял... извиняюсь что отвлёк... :)
Друг Кота
Аватара пользователя
Сообщения: 7362
Зарегистрирован: Пт авг 28, 2009 21:34:30
Откуда: 845-й км.

Сообщение 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). А вы сбрасывая глобальный флаг, возможно оставдяете, что-то необработанным.
Поставщик валерьянки для Кота
Сообщения: 1925
Зарегистрирован: Сб май 05, 2012 20:24:52
Откуда: KN34PC, Болгария

Сообщение veso74 »

Ждете, пока шина будет готова, проверьте код состояния для отправленного условия запуска:

Код: Выделить всё

while(!(TWCR & (1<<TWINT)));
Было бы хорошо обработать все возможные состояния.
Контактная информация:
Первый раз сказал Мяу!
Аватара пользователя
Сообщения: 39
Зарегистрирован: Чт июн 08, 2017 17:52:33

Сообщение vdv22 »

Обработчик всех флагов будет, но мне сейчас дадо чтоб он хоть адрес отправит - я в свиче обычно делаю default чтоб другое не нужное отсечь. Сейчас в прерывание он заходит только один раз (отслеживаю через uart ) то есть после получения 0x08.

Добавлено after 1 minute 45 seconds:
[uquote="veso74",url="/forum/viewtopic.php?p=4274319#p4274319"]Ждете, пока шина будет готова, проверьте код состояния для отправленного условия запуска:

Код: Выделить всё

while(!(TWCR & (1<<TWINT)));
Было бы хорошо обработать все возможные состояния.[/uquote]
то что вы предлогаете это блокирующий режим -он у меня прекрасно работает . Но я не хочу в цикле жать -мне нужен режим с прерываниями.
Поставщик валерьянки для Кота
Сообщения: 1925
Зарегистрирован: Сб май 05, 2012 20:24:52
Откуда: KN34PC, Болгария

Сообщение 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();
}
Контактная информация:
Ответить

Вернуться в «AVR»