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

28 минут назад, HardEgor сказал:

только тогда, когда заканчивается нормальная работа и начинаются проблемы с ответами и запросами.

В первом сообщении Ксения сообщает, что когда проблемы начинаются - виснет все. И вместо того, чтобы разобраться в коде куба, найти и исправить там ошибку (при правильной работе через регистры без куба там ничего не виснет, я уверяю), она с упорством, достойном лучшего применения, решила кубовый код обвешать костылями. Мы можем ей только посочувствовать - мешать не вправе.

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


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

1 час назад, HardEgor сказал:

Так это надо делать до включения i2ç. А когда i2c включился и заработал, то только тогда, когда заканчивается нормальная работа и начинаются проблемы с ответами и запросами.

Когда проблемы с ответами и запросами началась, уже поздно махать кулаками, т.к. имя этой проблеме - зависание. А после эксгумации по ватчдогу уже неясно, что случилось и в каком месте.

 

59 минут назад, Сергей Борщ сказал:

В первом сообщении Ксения сообщает, что когда проблемы начинаются - виснет все. И вместо того, чтобы разобраться в коде куба, найти и исправить там ошибку (при правильной работе через регистры без куба там ничего не виснет, я уверяю), она с упорством, достойном лучшего применения, решила кубовый код обвешать костылями. Мы можем ей только посочувствовать - мешать не вправе.

СлабО мне ту ошибку в Кубе сыскать, тем более когда на одних регистрах пользоваться I2C я  не умею.

Пыталась обновлять кубовые драйверы, т.к. после моей версии 1.8.0 уже вышли версии 1.8.3, 1.8.4 и 1.8.5. Причем в каждой из них в файле

stm32f1xx_hal_i2c.c

были подвижки (на 5 килобайт файл раздулся). Разбираться в нем - голову сломать.

Однако замена драйвера I2C на последнюю версию ситуацию не изменило - по-прежнему провисание.

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


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

17 минут назад, Xenia сказал:

Разбираться в нем - голову сломать.

"Мыши плакали, кололись, но продолжали жрать кактус" :dash1:

19 минут назад, Xenia сказал:

А после эксгумации по ватчдогу уже неясно, что случилось и в каком месте.

А отладчика нет, чтобы отправку по шагам пройти?

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


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

19 минут назад, Сергей Борщ сказал:

А отладчика нет, чтобы отправку по шагам пройти?

Отладчик есть, но с моей стороны выглядело целесообразнее не изобретать велосипед, а задать вопрос на форуме, поскольку речь идет о проблеме не в моей программе, а в программном продукте CubeMX, которым пользуется очень много народа. Т.е. расценила, что не я первая, кто использует I2C через Куб, а потому надеялась, что эта проблема кем-то уже была замечена, и от нее найдено противоядие.

Тогда как ваш совет из рода "найди место ошибки сама и сама же ее исправь" не кажется мне полезным.

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


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

В 15.02.2024 в 19:29, Xenia сказал:

Однако замена драйвера I2C на последнюю версию ситуацию не изменило - по-прежнему провисание.

https://istarik.ru/blog/stm32/123.html

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


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

35 минут назад, Xenia сказал:

Отладчик есть, но с моей стороны выглядело целесообразнее не изобретать велосипед, а задать вопрос на форуме

Раз есть отладчик, то что мешает запустить код под ним и, после зависания, посмотреть состояние различных регистров I2С после зависания?

Того же SR1.ARLO или других подозрительных битов?

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


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

Куб не панацея и решения в нем не проверялись при всех "нетепличных" условиях, как мне кажется.

Как в кубе сделаны таймауты на опрос флагов I2C? Банальным блокирующим ожиданием на while() с переменной-счетчиком цикло-попугаев?

3 часа назад, Xenia сказал:

Одно только плохо - для такого рода теста пришлось бы постоянно отключать I2C и переходить в режим обычного GPIO_MODE_INPUT, а после проведения теста вновь инициировать режим I2C.

Именно так и нужно делать... Мой опыт говорит именно о том, что в STM32 для надежной работы I2C нужно обвешивать работу с этой периферией дополнительными костылями, иначе это все до первой помехи или еще чего.

Как пример - все транзакции покрываются защитными таймутами аппаратного таймера (или таймерных служб ОСРВ), а при зависаниях ноги переводятся в режим GPIO и пытаются разрулить сбившиеся клоки. А еще лучше - сбросить слейв по питанию или выведенной ногой RESET, если такая есть.

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

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


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

1 час назад, HardEgor сказал:

Про это я читала раньше, но суть этой заметки в целом сводится к детализации реализации совета, который сама компания ST дала в Errara ("STM32F10xx8 and STM32F10xxB silicon limitations").

На мой взгляд этот способ плохой, т.к. он занимает много времени и срабатывает не всегда. По этому поводу я уже проводила собственные исследования и изобрела лучший способ :), который работает более надежно и к тому же гораздо более простой.

Однако в той статье описана борьба с другой проблемой - той, когда статус BUSY выдается ошибочно, в то время как с подтяжками на линиях I2C всё в порядке. Т.е. это отнюдь не моя проблема, поскольку там на операциях чтения и передачи контроллер не зависает, а честно выдает ошибку HAL_BUSY. Поэтому в том случае действительно возможен алгоритм, основанный на принятии мер , "взбадривающих" I2C, после того, как транзакция окончилась неудачей. Тогда как у меня проблема иная - неудачная транзакция приводит к зависанию с последующим ресетом по WаtchDog. Т.е. мне нечего лечить, т.к. наступает полный пипец. К этому стоит добавить, что мой контроллер по I2C-шине управляет силовыми ключами, вот такими (на ток 10А):

https://wiki.iarduino.ru/page/power-key-4n-i2c-datasheet/

А те, в свою очередь, переключают клапана на линиях, по которым перекачиваются "агрессивные" жидкости. Это, так называемый, "градиент низкого давления", когда клапаны поочередно пропускают жидкость из двух бутылей/ёмкостей, выдерживая нужное время для каждой фазы, для того, чтобы после смесителя получилась нужная концентрация. Абстрактный пример: качаем 4 секунды спирт из первой бутыли, а потом 6 секунд - воду из второй бутыли. И так в бесконечном цикле. В результате после смесителя получаем 40%-ный (по объему) спирт. И это должно надежно работать даже ночью. А теперь представим, что мой контроллер, который не только управляет клапанами, но и контролирует результат их работы по расходомеру, внезапно завис? Я со всеми неожиданностями знаю способы борьбы, но зависание контроллера это кранты.

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


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

2 минуты назад, x893 сказал:

Делаёте управление критическими блоками напрямую.

Именно так и сделала - заменила I2C-ключи на управляемые уровнем, вот такие:

https://wiki.iarduino.ru/page/silovoy-klyuch-trema-modul/

Но такого рода исправление касается только "критического блока", где переключение клапанов происходит часто (потому и вероятность сбоя там выше).

Однако есть там один датчик, который только по I2C способен работать. И если он вызовет зависание контроллера, то и "критическому блоку" тоже каюк, т.к. контроллер у них один и тот же.

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


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

2 часа назад, jcxz сказал:

Раз есть отладчик, то что мешает запустить код под ним и, после зависания, посмотреть состояние различных регистров I2С после зависания?

Потому что в данном случае "зависание" является не каким-то событием, наступление которого можно отследить трассировкой, а похоже, что является бесконечным циклом, по которому можно ходить трассировщиком бесконечно долго.

Но есть и короткие циклы типа:

while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET);

из которых не выходит никогда. И таких мест в этом файле 19 штук. Вот что нашел поиск по команде find:

---------- STM32F1XX_HAL_I2C.C
          while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == RESET);
    while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET);
    while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET);
    while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET);
    while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET);
          while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == RESET);
    while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET);
    while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET);
    while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET);
    while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET);
      while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET);
      while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET);
      while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET);
      while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET);
  while (__HAL_I2C_GET_FLAG(hi2c, Flag) == Status)
  while (__HAL_I2C_GET_FLAG(hi2c, Flag) == RESET)
  while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TXE) == RESET)
  while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == RESET)
  while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF) == RESET)
  while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_RXNE) == RESET)

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


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

2 часа назад, Arlleex сказал:

Именно так и нужно делать... Мой опыт говорит именно о том, что в STM32 для надежной работы I2C нужно обвешивать работу с этой периферией дополнительными костылями, иначе это все до первой помехи или еще чего.

У меня опыт с STM32 не особо богатый. Но в одном проекте на STM32F429 имеется I2C-мастер, на котором висят сразу 5шт. I2C-ведомых. И никаких таймаутов при работе с I2C я там не использую. И работает без каких-либо проблем (прерывания + DMA). Ничего не виснет. Правда Куба там нет. И подтяжки там внешние, довольно низкоомные.

54 минуты назад, Xenia сказал:

Потому что в данном случае "зависание" является не каким-то событием, наступление которого можно отследить трассировкой, а похоже, что является бесконечным циклом, по которому можно ходить трассировщиком бесконечно долго.

Брррр!... :wacko2: Ничего не понял.

Зачем ходить?? Вот вы (как пишете) поставили 2 бряка: перед функцией и после ней. И пишете, что "первый был пройден, а до 2-го никак не доходит управление". Вот здесь (пока не доходит до 2-го) жмёте в отладчике "стоп" и изучаете: состояние регистров I2C? где находится PC? состояние стека? состояние прочих рабочих переменных? ...)

54 минуты назад, Xenia сказал:

Но есть и короткие циклы типа:

while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET);

из которых не выходит никогда.

Ну вот нажмите "стоп" пока они выполняются и изучайте состояние регистров I2C. 

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


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

1 hour ago, Xenia said:

Потому что в данном случае "зависание" является не каким-то событием, наступление которого можно отследить трассировкой, а похоже, что является бесконечным циклом, по которому можно ходить трассировщиком бесконечно долго.

Но есть и короткие циклы типа:

while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET);

из которых не выходит никогда. И таких мест в этом файле 19 штук. Вот что нашел поиск по команде find:

---------- STM32F1XX_HAL_I2C.C
          while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == RESET);
    while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET);
    while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET);
    while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET);
    while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET);
          while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == RESET);
    while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET);
    while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET);
    while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET);
    while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET);
      while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET);
      while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET);
      while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET);
      while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET);
  while (__HAL_I2C_GET_FLAG(hi2c, Flag) == Status)
  while (__HAL_I2C_GET_FLAG(hi2c, Flag) == RESET)
  while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TXE) == RESET)
  while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == RESET)
  while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF) == RESET)
  while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_RXNE) == RESET)

А ничего что перед ним стоит ?
 

    do
    {
      count--;
      if (count == 0U)
      {
        hi2c->PreviousState       = I2C_STATE_NONE;
        hi2c->State               = HAL_I2C_STATE_READY;
        hi2c->Mode                = HAL_I2C_MODE_NONE;
        hi2c->ErrorCode           |= HAL_I2C_ERROR_TIMEOUT;

        return HAL_BUSY;
      }
    }
    while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET);

find функция хорошая, но бесполезная в данном контексте

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


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

2 часа назад, x893 сказал:

А ничего что перед ним стоит ?

Что-то стоит 🙂 .

2 часа назад, x893 сказал:

find функция хорошая, но бесполезная в данном контексте

Согласилась.

Впрочем решение своей проблемы я кажется нашла - это именно та функция, что стояла внутри while'ов. Она достаточно надежно определяет, когда шина I2C лишается подтяжки:

__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY)

Причем работает она максимально быстро, т.к. представляет собой дефайн, который при флаге I2C_FLAG_BUSY тождественен проверке бита:

SR2.BUSY

например, так:

if ((I2C1->SR2 & I2C_SR2_BUSY) != 0) { читать и писать нельзя, зависнет! }

Уже испытала: при обеих подтяжках (SCL и SDA) SR2.BUSY = 0, а если хотя бы от одной из них оторвать подтяжку, то SR2.BUSY > 0.

Правда после возвращения подтяжки на место, в ноль она возвращаться не хочет, но после "взбадривания" на ноль возвращается.

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


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

2 часа назад, jcxz сказал:

У меня опыт с STM32 не особо богатый. Но в одном проекте на STM32F429 имеется I2C-мастер, на котором висят сразу 5шт. I2C-ведомых. И никаких таймаутов при работе с I2C я там не использую. И работает без каких-либо проблем (прерывания + DMA). Ничего не виснет. Правда Куба там нет. И подтяжки там внешние, довольно низкоомные.

Год назад делал железяку с 10 микросхемами на I2C (на оставшихся 2 каналах тоже пачки микрух, но поменьше кол-вом). Весьма "жирная" регистровая модель под постоянный read-back со стороны МК и периодический write, т.е. обмены интенсивные, практически без "дыр" между транзакциями. Испытывал вплоть до ручного замыкания SDA/SCL пинцетом, с дребезгом, по-разному формировал условия "залипания" шины. Ловил BUSY в регистрах статуса, да такие, что только сбросом в RCC клоков I2C-модуля опускался. В итоге родился драйвер, работающий под присмотром защитного таймера (guard timer) на каждую транзакцию, с попытками восстановления через "проклокивание" SCL и сбросом всей периферии I2C.

Но то уже был спортивный интерес. Раком встающая периферия, особенно какого-то задрыпанного I2C, заставляла задумываться над полноценно программным ногодрыгом в простых проектах, где обмен не интенсивный - ради единократных настроек чего-нибудь набортного, например. Но когда обмениваться надо много - окучивал I2C-модуль, доводя общую стабильность до идеала.

У меня тоже поначалу была написана обработка всех флажков согласно даташиту - даже с DMA или по прерываниям (хотя связка I2C + DMA в STM32 - одно название) могло работать стабильно очень долго без нареканий. Потом, при "отлове" бага понимаешь, что, например, на команду выставления на шину старт-бита, подтверждение (установка SB в SR1) может никогда не произойти, как и на некоторые другие операции с шиной. Тут и начинается накручивание защитных таймаутов.

P.S. Никогда не приходилось цепляться по SMBus - слыхал, что там как раз аппаратные таймауты уже предусмотрены. Надо изучать вопрос.

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


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

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...