TWI(I2C) чёрти что творится

Программирование микроконтроллеров AVR, PIC, ARM.
Разработка и изготовление печатных плат для модулей.

TWI(I2C) чёрти что творится

Сообщение Fox89 » 23 июл 2008, 02:08

вобщем по окончании можно перенести в раздел граблей.
Делаю большие наружные часы с термометром. Железо сделал, софт часовой сделал (учитывает високосные года, автоматически время переводит на зимнее/летнее). Часы с термометром DS1621. Вот тут и начались проблемы. В CVAVR подключил встроенные программный i2c, библиотеку работы с термомером. красота, почти ничего писать не пришлось. Но часы почему то перезагружались в случайный момент времени. Чаще всего в районе 3:10 - 3:11, но иногда в 3:00, а если проскакивал этот момент, то уже спустя пару часов. Ломал голову в чем дело, и код перетряхнул, и железо. Оказалось - не поверете, в подключенном #include <i2c.h> из комплекта CVAVR. Причем достаточно было просто подключить и не использовать что бы так глючило.
Ну да ладно. Термометр к своей меге 16 я подключал на аппаратный TWI порт, поэтому решил воспользоваться этим. причем мне прерывания не нужны, чисто раз в минуту байтиками перекинуться. А вот с этим проблемы.

начнем с того, что как сказано в даташите флаг TWINT регистра TWCR сбрасывается записью единицы. Когда флаг установлен железом - начинка ждет указаний от программы. Программой записываем единичку - и у нас начинка делает определенную операцию, по завершении которой снова ставит флаг (ноль). тогда непонятно, почему в том же даташите такой кусок:
Код: Выделить всё
while (!(TWCR & (1<<TWINT)));
//Wait for TWINT Flag set. This indicates that the START condition has been transmitted

Или я чего то не понимаю, или цикл будет выполняться когда TWINT равен 0.
и это никак не вяжется с примером из апноута AVR315
Код: Выделить всё
unsigned char TWI_Transceiver_Busy( void )
{
  return ( TWCR & (1<<TWIE) );                  // IF TWI Interrupt is enabled then the Transceiver is busy
}


затем я решил написать свою библиотеку i2c и подменить. не тут то было, оказалось что i2c библиотека зашита в компилятор, поэтому функции везде называются fi2c, т.к. на i2c ругается.
вот они, коменты надерганы из апноута и с доков CVAVR:

Код: Выделить всё
#define  TWINT  7
#define  TWEA   6
#define  TWSTA  5
#define  TWSTO  4
#define  TWWC   3
#define  TWEN   2
#define  TWIE   0

void fi2c_init(void)
      TWBR = 20;
      TWSR &= 0x03;   
  TWCR = (1<<TWEN)|                                 // Enable TWI-interface and release TWI pins.
         (0<<TWIE)|(0<<TWINT)|                      // Disable Interupt.
         (0<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|           // No Signal requests.
         (0<<TWWC); 
};

unsigned char fi2c_start(void)/*issues a START condition.
Returns 1 if bus is free or 0 if the I2C bus is busy or error.*/
{   

  TWCR = (1<<TWEN)|                             // TWI Interface enabled.
         (1<<TWIE)|(1<<TWINT)|                  // Enable TWI Interupt and clear the flag.
         (0<<TWEA)|(1<<TWSTA)|(0<<TWSTO)|       // Initiate a START condition.
         (0<<TWWC);                             //

   while (!(TWCR & (1<<TWINT)));
   if (((TWSR & 0xF8) ==  0x08) || ((TWSR & 0xF8) ==  0x10)) //$ 08 - start condition has been transmitted, $ 10 repeated start condition has been transmitted
   {
      return 1;
   }
   else
   {
      return 0;
   };
};


void fi2c_stop(void)//issues a STOP condition.   
{
   TWCR = (1<<TWEN)|                                 // TWI Interface enabled
               (0<<TWIE)|(1<<TWINT)|                      // Disable TWI Interrupt and clear the flag
               (0<<TWEA)|(0<<TWSTA)|(1<<TWSTO)|           // Initiate a STOP condition.
               (0<<TWWC);
       
};

unsigned char fi2c_read(unsigned char ack)
/*reads a byte from the bus.
The ack parameter specifies if an acknowledgement is to be issued after the byte was read.
Set ack to 0 for no acknowledgement or 1 for acknowledgement.*/
{
   unsigned char data;
   
   if (ack == 0)         
        TWCR = (1<<TWEN)|                                 // TWI Interface enabled
               (1<<TWIE)|(1<<TWINT)|                      // Enable TWI Interupt and clear the flag to read next byte
               (0<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|           // Send NACK after reception
               (0<<TWWC);  //TWCR &= 0x40; //TWEA = 0
   else
   TWCR = (1<<TWEN)|                                 // TWI Interface enabled
               (1<<TWIE)|(1<<TWINT)|                      // Enable TWI Interupt and clear the flag to read next byte
               (1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|           // Send ACK after reception
               (0<<TWWC);                                 // //TWCR |= 0x40; //TWEA =1
   //while (TWI_Transceiver_Busy()); //waits until TWINT set (=0) 
   while (!(TWCR & (1<<TWINT)));
   data = TWDR;
   return data;
};


unsigned char fi2c_write(unsigned char data)
/*writes the byte data to the bus.
Returns 1 if the slave acknowledges or 0 if not.
*/
{
   TWDR = data;
   TWCR &= 0xcf; //TWSTA, TWSTO =0
   TWCR |= 0x84; //TWNT TWEN =1
   while (!(TWCR & (1<<TWINT)));
   if (((TWSR & 0xF8) ==  0x18) || ((TWSR & 0xF8) ==  0x28) || ((TWSR & 0xF8) ==  0x40)) //$ 40 SLA+R transmiteed, $18 SLA+W transmitted, $ 28 DATA transmitted ACK received
   {
      return 1;
   };
   if (((TWSR & 0xF8) ==  0x20) || ((TWSR & 0xF8) ==  0x30) || ((TWSR & 0xF8) ==  0x48)) //$20 SLA+W transmited, $ 30 - DATA transmited NOT ACK received $ 48 SLA+R transmitted
   {
      return 0;
   };
   
   
};   


не работает. причем AVR Studio вообще паршиво себя ведет - TWI не эмулирует. В конструкции

Код: Выделить всё
TWCR = (1<<TWEN)|                                 // TWI Interface enabled
               (0<<TWIE)|(1<<TWINT)|                      // Disable TWI Interrupt and clear the flag
               (0<<TWEA)|(0<<TWSTA)|(1<<TWSTO)|           // Initiate a STOP condition.
               (0<<TWWC);

указанные биты устанавливает, кроме TWINT, который просто игнорирует. В протеусе еще интереснее. если у меня идет

Код: Выделить всё
fi2c_start();
fi2c_stop();

у меня i2c debagger пишет S P. но еслия повторю иснтрукции 2 раза, т.е.
Код: Выделить всё
fi2c_start();
fi2c_stop();fi2c_start();
fi2c_stop();
while(1);

у меня идет бесконечный Sr Sr Sr.. Непонятно почему, ведь иснтрукции всего 4 а после этого должен уходить в бесконечный цикл. Прерывания TWI не задействованы.

при подмене CVAVR i2c на мою fi2c интересное происходит. Байт в термометр отправляет, ACK от него получает, но дальше дело не двигается, причем часы почему то перезагружаются в момент переключения с режима индикации температуры на режим индикации часов. В чём дело - непонятно, тот же код отлично работал. В меню часов выключаю опрос термометра - всё отлично работает.

кто натыкался на такое? буду признателен, если кто -нибудь опубликует свою реализацию i2c через аппаратный TWI для CVAVR, что б всего 4 функции как выше, иначе много переписывать придется((
Fox89
 
Сообщения: 57
Зарегистрирован: 11 ноя 2007, 20:12
Откуда: урал

Re: TWI(I2C) чёрти что творится

Сообщение Fox89 » 28 июл 2008, 16:11

вобщем заработали у меня мои функции, переписал работу с термометром, т.е. от родных библиотек CVAVR не осталось ничего. Но проблема та же - перезагружается в случайный момент времени. Ночью я смог воспроизвести 3 раза подряд перезагрузку в 3:11, но утром такое не получилось. Причем общения по i2c в это время не происходило. в чем баг - не пойму. Щас вычислил код полностью от i2c - вроде работает без перезагрузок, посмотрим сколько проработает.
Fox89
 
Сообщения: 57
Зарегистрирован: 11 ноя 2007, 20:12
Откуда: урал

Re: TWI(I2C) чёрти что творится

Сообщение Fox89 » 18 авг 2008, 13:23

баг видимо был в МК, т.к. я взял другую мегу 16, залил ТУ ЖЕ прошивку и часы нормально работают который день.
Fox89
 
Сообщения: 57
Зарегистрирован: 11 ноя 2007, 20:12
Откуда: урал

Re: TWI(I2C) чёрти что творится

Сообщение Scorpio » 30 сен 2008, 18:56

Fox89 писал(а):вобщем заработали у меня мои функции

А можно работающие функции опубликовать? Я тоже с TWI сейчас бьюсь. Пока не работает. :(
Аватара пользователя
Scorpio
 
Сообщения: 2681
Зарегистрирован: 30 сен 2008, 18:49
Откуда: Где-то в Латинской Америке

Re: TWI(I2C) чёрти что творится

Сообщение Krik99 » 01 окт 2008, 11:24

Хотелось увидить работающие либы для TWI. Вот готовая либа софтового i2c может работать только как master и из-за этого не возможна связь 2 МК между собой, а вот с использованием TWI это возможно?
Аватара пользователя
Krik99
 
Сообщения: 17
Зарегистрирован: 02 янв 2008, 22:03
Откуда: Одесса
прог. языки: Си

Re: TWI(I2C) чёрти что творится

Сообщение MiBBiM » 12 ноя 2009, 14:41

Если слейв адресован SLA+R пакетом, но передать ему нечего, то что выставлять на шине (писать в регистры)?
Tomorrow will be. Better
Аватара пользователя
MiBBiM
 
Сообщения: 1866
Зарегистрирован: 29 окт 2007, 18:11
Откуда: Пермь
прог. языки: Brainfuck/Basic/Delphi/C++/Lisp/x86asm/JavaScript

Re: TWI(I2C) чёрти что творится

Сообщение Crushor » 12 ноя 2009, 19:50

Fox89 выложите пожалуйста свои рабочие функции, тоже давно парюсь с TWI, испробывал свои функции и описаные в AVR315, флаг прерывания не сбрасывается при установке в него 1.
Crushor
 
Сообщения: 9
Зарегистрирован: 24 окт 2009, 22:43
Откуда: Феодосия

Re: TWI(I2C) чёрти что творится

Сообщение MiBBiM » 05 дек 2009, 17:52

MiBBiM писал(а):Если слейв адресован SLA+R пакетом, но передать ему нечего, то что выставлять на шине (писать в регистры)?

эта ситуация не предусмотрена, возможно лишь загрузить данные (напр, TWDR = 0xFF), выставить состояние TWCR.TWSTO = 0 и TWCR.TWEA = 0 и уже на мастере проверять, а не пустая ли пришла посылка. кстати, при отключении ведомого-передатчика (когда ему нечего передать после очередного байта данных) ведущий также будет получать 0xFF.
Код: Выделить всё
Twdr = &HFF                                           
Reset Twcr.twsto
Reset Twcr.twea
Tomorrow will be. Better
Аватара пользователя
MiBBiM
 
Сообщения: 1866
Зарегистрирован: 29 окт 2007, 18:11
Откуда: Пермь
прог. языки: Brainfuck/Basic/Delphi/C++/Lisp/x86asm/JavaScript


Вернуться в Микроконтроллеры

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 22