TWI (I2C) помогите разобраться с проблемой

Dpe3309
Offline
Зарегистрирован: 19.09.2022

Всем привет. 

Я осваиваю TWI. В Proteus у меня получилось связать Atmega328p и Atmega48. 

Теперь я кодом  мастера прошиваю Arduino UNO с Atmega328p, который соединен с мультисервошилдом v1 (общение у них происходит по TWI, и на мультисервошилде стоит atmega48 ), и код не работает (((

Я наставил дебагов через usart, и судя по всему код даже в прерывание по TWI_vect не заходит.

Код для прошивки ардуино компилирую через avrdude который идет в комплекте к Arduino IDE.

Подскажите, куда копать? в чем может быть проблема?

Вот мой код:

#include <avr/interrupt.h>
#include <util/delay.h>
#include "usart.h"

#define TW_START   0x08
#define TW_MT_SLA_ACK   0x18
#define TW_MT_DATA_ACK   0x28
#define TW_MR_SLA_ACK   0x40
#define TW_MR_DATA_ACK   0x50


//#define MULTISERVO_ADDR (0x40) 
#define SLAVE_ADDRESS (0x47)

uint8_t value;
uint8_t ongoing_transmission = 0;
uint8_t status;
uint8_t angle = 50, pin = 2;
uint8_t flag; 


//interrupt routine for the TWI interrupt
ISR(TWI_vect)
{
   status = TWSR & 0xFC;	//mask-out theprescaller bits

   switch(status)
   {
      case TW_START:		//start transmitted
         usart_set_message("start transmitted U1");
         usart_print();
         ongoing_transmission = 1;
         flag = 0;
         // write SLA+R, SLA=0x01
         //TWDR = (SLAVE_ADDRESS << 1) | 0x01;
         // write SLA+W, SLA=0x00
         TWDR = (SLAVE_ADDRESS << 1) | 0x00;
         TWCR &= ~((1<<TWSTA)); // clear TWSTA
      break;

      case TW_MT_SLA_ACK:   // own SLA+W received, acknoledge sent
         usart_set_message("own SLA+R received, acknoledge sent");
         usart_print();

         switch(flag)
         {
            case 0:
               usart_set_message("send pin");
               usart_print();
               TWDR = (pin & 0xFF);
               flag = 1;
            break;

            default:
               usart_set_message("ALARM! emergency stop");
               usart_print();
               TWCR |= (1<<TWSTO);  // write stop bit
               TWCR &= ~(1<<TWSTA); // clear start bit
               ongoing_transmission = !ongoing_transmission;
            break;
         }
        usart_print_number(TWDR);
      break;

      case TW_MT_DATA_ACK: // last byte transmitted ACK received    
         //TWCR |= (1<<TWEA); // set TWEA to enter slave mode
         usart_set_message("last byte transmitted ACK received");
         usart_print();

         switch(flag)
         {
            case 1:
               usart_set_message("send angle");
               usart_print();
               TWDR = (angle & 0xFF);
               flag = 2;
            break;
            case 2:
               TWCR |= (1<<TWSTO);  // write stop bit
               TWCR &= ~(1<<TWSTA); // clear start bit
               ongoing_transmission = !ongoing_transmission;
               flag = 0;
            break;
         }
         usart_print_number(TWDR);
         TWCR &= ~((1<<TWSTO) | (1<<TWEA));
      break;

       case TW_MR_SLA_ACK: // SLA+R transmitted, ACK received 
          usart_set_message("SLA+R transmitted, ACK received");
          usart_print();
          TWCR &= ~((1<<TWSTA) | (1<<TWSTO)); 
       break;
   }
   TWCR |=   (1<<TWINT);  // hand over to TWI hardware
}


int main()
{
   usart_init();
   usart_set_message("init usart U1");
   usart_print();

   value = 12;

   sei();
   TWCR |= (1<<TWEA) | (1<<TWEN) | (1<<TWIE);

   // Write your code here
   while (1)
   {
      if (!ongoing_transmission)
      {
    usart_set_message("!ongoing_transmission");
    usart_print();

    TWCR |= (1<<TWSTA);
      }

      _delay_ms(3000);
   }
   return 0;
}

Исследуя проблему, я дебажу значение в регистре TWCR. Как ни странно, после строки TWCR |= (1<<TWSTA); в регистре TWCR получаю 01100101. Если я правильно интерпретирую значение - в регистре  TWCR установлен флаг TWSTA, судя из описания из книги Евстифеева "Микроконтроллеры AVR семейств Tiny и Mega фирмы ATMEL"(стр 366) "Флаг состояния СТАРТ. При записи в разряд TWSTA лог. 1 модуль проверяет со стояние шины TWI и, если шина свободна, формирует состояние СТАРТ. Если шина занята, модуль TWI ожидает появления состояния СТОП, и только после этого формирует состояние СТАРТ. Флаг сбрасывается аппаратно по окончании формирования состояния СТАРТ", и дальше на протяжении работы программы значение в этом регистре не меняется. Значит что TWI занят? а чем? чет я не пойму.

Dpe3309
Offline
Зарегистрирован: 19.09.2022

Еще я в настройке фьюзов не уверен. в Proteus я устанавливаю фьюзы CKSEL3:0 в 0000, а с МК от ардуинки прочитав фьюзы CKSEL3:0 увидел 1111

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

В Proteus по умолчанию включен фьюз CLDIV8 - и частота в 8 раз ниже источника  тактирования !!!

Также если используется кварц, то CKSEL0:3, SUT0:1 должны быть все 1 или вернее они должны быть противоположны SPIEN

Dpe3309
Offline
Зарегистрирован: 19.09.2022

Фьюзы МК ардуинки я не трогал, на сколько мне известно в контексте Ардуино фьюзы "доступны чисто теоретически и достаточно сложным путем (через команды загрузчика avrdude)".

Дим-мычъ
Offline
Зарегистрирован: 20.03.2021

Dpe3309 пишет:

Я наставил дебагов через usart,

В обработчике ,перед использованием usart попробуйте установить флаг разр. прерывания sei(), а затем , по завершении работы с usart, сбросить cli();