Перейти к содержанию

    

I2C STM32F103

Интерфейс I2C МК STM32F103.

Пытаюсь подружить с пирометром MLX90614

 

Ни как не могу понять: После передачи адрес(W) + команда , нужно делать Stop Condition ? Или сразу ещё один Start Condition и дальше опять адрес( R ) ?

post-24702-1521238748_thumb.jpg

MLX90614.pdf

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Сразу старт и адрес. На картинке же показано. Всяко бывает.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Stop не нужен, это так называемый Repeated Start Condition, часто используется для продолжения обмена без освобождения шины.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В однозадачной системе с одним ведущим (master) на шине - без разницы. Можно передавать stop, можно не передавать. Единственный случай, когда обязательно нужно передать stop - это при записи в память (там stop запускает процесс записи). Во всех остальных случаях вместо stop-start можно передавать start, это будет т.н. repeated start. В многозадачной системе или при наличии нескольких независимых ведущих в данном случае нужно обязательно передавать repeated start, который гарантирует, что между записью адреса и чтением никто не влезет на шину и не перепишет установленный адрес.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
нужно обязательно передавать repeated start, который гарантирует, что между записью адреса и чтением никто не влезет на шину и не перепишет установленный адрес.

Полагаю, это мой случай. Т.к. передача команды это адрес в MLX90614 , а следующее за ним чтение - это чтение по этому адресу.

Так вот: если делать старт-стоп, то MLX90614 не работает.

А если пытаться передавать повторный старт из STM32F103 , то не работает он , а именно при последующей передаче адреса не выставляет бит "адрес передан". Да и в документации на МК написано, что "старт нужно передавать при сброшенном бите BUSY" , а когда обмен идёт, этот бит уже стоит. Хотя в STM32F429 этот же код работал, и там такой же I2C !

 

Может такое быть, что I2C в МК не умет передавать повторный старт ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Может такое быть, что I2C в МК не умет передавать повторный старт ?
Нет, не может. Для него что повторный, что обычный старт - без разницы.

Хотя в STM32F429 этот же код работал, и там такой же I2C !
Буквально позавчера столкнулся с такой же фигней - код, работавший на 407, отказался работать на 107. Код на прерываниях, естественно, никакого ожидания сброса BUSY в цикле в нем нет. Посмотрел лог. анализатором - увидел посылки по 14 бит (?) с совершенно не теми данными, которые я запихивал в регистр, плюнул, написал за час I2C ногодрыгом (благо мне при старте программы надо один раз считать MAC из внешней памяти). Тратить время на поиски блох в данном проекте посчитал непродуктивным.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
А если пытаться передавать повторный старт из STM32F103 , то не работает он , а именно при последующей передаче адреса не выставляет бит "адрес передан". Да и в документации на МК написано, что "старт нужно передавать при сброшенном бите BUSY" , а когда обмен идёт, этот бит уже стоит.

В 103 довольно капризный I2C, требующий точного соблюдения всей циклограммы, расписанной в даташите событийно (EV5-EV9), и правильной очистки статусных бит, как написано. Вот псевдо-код (псевдо - потому, что на бесконечных циклах ожидания), работающий на 103 в режиме мастера, с repeated start, без прерываний (чтение из регистра устройства с I2C адресом 0):

 

void CI2C1::ReadByte(u8 nOffset, u8* pData)
{
  u8 data;
  u16 sr1, sr2;

  I2C1->CR1 |= I2C_CR1_START;
  while (!(I2C1->SR1 & I2C_SR1_SB));

  I2C1->DR = 0x00;
  while (!(I2C1->SR1 & I2C_SR1_ADDR));
  sr1 = I2C1->SR1;
  sr1 = sr1; // prevent warning
  sr2 = I2C1->SR2;
  sr2 = sr2; // prevent warning
  
  I2C1->DR = nOffset;
  while (!(I2C1->SR1 & I2C_SR1_BTF));

  I2C1->CR1 |= I2C_CR1_START; // repeated start
  while (!(I2C1->SR1 & I2C_SR1_SB));

  I2C1->DR = 0x01;
  while (!(I2C1->SR1 & I2C_SR1_ADDR));
  sr1 = I2C1->SR1;
  sr2 = I2C1->SR2;

  while (!(I2C1->SR1 & I2C_SR1_RXNE));
  data = I2C1->DR;  
  I2C1->CR1 |= I2C_CR1_STOP;
  *pData = data;
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти
Авторизация