Странности с TWI

Подключаю тут LM75A, накидал код:


void TWI_Apply(void)
{
  TWCR|=(1<<TWINT);

  PORTB|=(1<<PB1); //Debug LED
  while (!(TWCR & (1<<TWINT)));
  PORTB&=~(1<<PB1);
}

int8_t LM75_ReadTemp(void)
{
  uint8_t lm_hi, lm_lo;

  TWBR=0xFF; //Lowest speed

  TWCR=(1<<TWEN) | (1<<TWSTA); //START
  TWI_Apply();

  TWCR=(1<<TWEN); //SLA+R
  TWDR=SENSOR_ADDR | TWI_READ;
  TWI_Apply();

  if (TWSR!=TWI_SLA_SUCCESS)
    return LM75_ERROR; //No device or device error

  TWCR=(1<<TWEN) | (1<<TWEA); //Read 1st byte
  TWI_Apply();

  lm_hi=TWDR;

  TWCR=(1<<TWEN); //Read 2nd byte
  TWI_Apply();

  lm_lo=TWDR;

  TWCR=(1<<TWEN) | (1<<TWSTO); //STOP
  TWI_Apply();

  return (int8_t)((((uint16_t)lm_hi<<8) | lm_lo)/8);
}


и с удивлением обнаружил, что он не работает — виснет при первом же ожидании бита TWINT. Что я делаю не так? На линиях подтяжка 2K.
  • 0
  • 15 октября 2011, 23:35
  • _YS_

Комментарии (32)

RSS свернуть / развернуть
У меня как-то так:

uint16_t get_data(void)
{
	uint16_t a,b;
	i2c_Start(); 			//стартовый бит
	i2c_Write(LM75B_ADR);		//передача адреса датчика
	i2c_Write(0x00);		//запрос на прием температуры
	i2c_Start();			//рестарт, для приема данных
	i2c_Write(LM75B_ADR | 0x01);	//передача адреса датчика и бита начала приема
	a = i2c_Read(1);		//прием первого байта и запрос на прием следующего
	b = i2c_Read(0);		//прием второго байта
	i2c_Stop();			//стоповый бит
	return a*0x100+b; 
}
0
Это правда софт-i2c + msp430.
i2c_Read(1) — Acknowledge
i2c_Read(0) — No Acknowledge

Датчик — LM75B.
0
И да, частота ~5кГц, при 0.5кГц — не запустился.
0
Кстати, я склоняюсь к тому, что проблема в железе, хотя и не пойму, где. Если выдернуть датчик, то МК исправно рапортует об ошибке. Если воткнуть датчик — повисает.
0
  • avatar
  • _YS_
  • 16 октября 2011, 17:29
Воткни не датчик :)
0
Так у меня больше ничего I2C-шного нет.
0
Что-то в том куске, который ты отключаешь (шнурок с датчиком) замыкает на линии данных…
0
Скорее по симпотомам тогда SCL что-то держит на земле.

Прозванивал, ничего.
0
Курю аппнот. Вдруг там какая-то магия?
0
  • avatar
  • _YS_
  • 16 октября 2011, 18:19
Я в депрессии. xD Нифига не работает, в чем ошибка не понимаю. Может, и впрямь LM75 дохлая?

Немного перепилил код:


void WaitTWI(uint8_t step)
{
  //Step/error code
  DisplayTemp(50+step);

  while (!(TWCR & (1<<TWINT)));
}

int8_t LM75_ReadTemp(void)
{
  uint8_t lm_hi, lm_lo;

  //Turn on internal pull-up
  DDRC&=~((1<<PC4) | (1<<PC5));
  PORTC=(1<<PC4) | (1<<PC5);

  TWSR=0;
  //100KHz SCL
  TWBR=32;

  //START
  TWCR=(1<<TWEN) | (1<<TWSTA) | (1<<TWINT);
  WaitTWI(1);

  //SLA+R
  TWDR=SENSOR_ADDR | TWI_READ;
  TWCR=(1<<TWEN) | (1<<TWINT);
  WaitTWI(2);

  if (TWSR!=TWI_SLA_SUCCESS)
    return LM75_ERROR; //No device or device error

  //1st read + ACK
  TWCR=(1<<TWEN) | (1<<TWEA) | (1<<TWINT);
  WaitTWI(3);
  lm_hi=TWDR;

  //2nd read + NACK
  TWCR=(1<<TWEN) | (1<<TWINT);
  WaitTWI(4);
  lm_lo=TWDR;

  //STOP
  TWCR=(1<<TWEN) | (1<<TWSTO) | (1<<TWINT);
  WaitTWI(5); //<--- HANGS HERE

  //Turn TWI off
  TWCR=0;

  return (int8_t)(((((uint16_t)lm_hi << 8) | (uint16_t)lm_lo) >> 5)/8);
}


Повисает при выдаче стопового бита…
0
  • avatar
  • _YS_
  • 16 октября 2011, 18:36
Поменял микросхему. Повисает…
0
После стопового не надо ждать
0
Блин! Точно! Спасибо!

Перечитал даташит…

Note that TWINT is NOT set after a STOP condition has been sent.

стр. 218 п. 7

Убрал ожидание — заработало.
0
Всегда пожалуйста.
Ещё мне кажется, что такой правильно считает температуру только первый раз после подачи питания. Нужно указывать что мы хотим читать по адресу 0.
Т.е. делаем так: старт->SLA+W->посылаем 0->повторный старт->SLA+R->считываем первый байт, посылаем ACK->считываем второй байт, посылаем NACK->стоп
0
Ненене. В ДШ на LM75 написано, что по умолчанию в регистре-индексе записан ноль — адрес температурного регистра. И если не надо менять настроек, то можно просто подряд читать. Практика это подтверждает — термометр исправно показывает увеличение/уменьшение температуры если подогреть/охладить его.
0
Вот-вот, то самое «малоприметное примечание, учтенное в библиотеке», о котором я и говорил в споре о библиотеках.
0
Дыг да. Зато я теперь знаю, что оно есть и где оно. А кто-то, кто пользуется библиотекой — не знает.
0
Вот только ему оно и не требуется…
0
До определенного времени.
0
Ну разве что полезет работать с регистрами напрямую.
0
А ведь профит очевиден — вместо того, чтобы таскать с собой целую библиотеку, я ограничился всего парой функций, работающими с модулем TWI напрямую.
0
Ну и? Оно у тебя в МК не лезет с библиотекой?
0
Чем меньше код при том же функционале — тем лучше.
0
А вот это уже зависит от требований и условий.
Если кода полкило, а МК мега8 — пара сотен байт роли не играет. Зато «сразу поперло» или «полдня трахался, забил» оказывает огромное влияние на время изготовления (а иногда и на завершение проекта вообще) любительских поделок.
0
Я работаю не на количество, а на качество, ибо для себя. И если я использую какой-то модуль, я стараюсь изучить все его подводные камни.
0
На один мелкий и описанный в даташите подводный камень, причем проявляющийся немедленно и железно, ты потратил день.
А когда это нечто в духе «подсчет CRC средствами DMA-блока ENC28J60 иногда портит содержимое памяти» — такой камушек даже производитель заметил только после выпуска микросхемы в производство.
0
Так заметил и описал же.
0
День потратил, зато я теперь детально представляю работу модуля TWI.
0
Скорее, теперь ты детально представляешь его интерфейс. Это несколько другое. То, что тебе доступно от модуля TWI — аналог .h файла от библиотеки.
И не столь уж велика разница, какой интерфейс знать — библиотеки или самого модуля.
Так заметил и описал же.
Угу. В errat'e. Причем за 4 ревизии так и не пофиксили.
0
А любитель библиотек, когда у него что-то не заработает, полезет в код -> увидит что в конце нет ожидания -> пропишет задержку :)
+1
Если библиотека нормальная, то дальше своего кода лезть не придется. И прежде чем править готовое, нормальные люди стараются выяснить — а нет ли веской причины, по которой сделано именно так.
0
И кстати, примечания бывают и не такие категорические. В духе «делайте вот то-то, иначе содержимое буфера может быть испорчено». И лови потом, при какой фазе луны сеть отваливается и почему. К тому же плавающие баги имеют свойство проявляться тока в готовом изделии :)
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.