‮Сдвиг по фазе (kincajou) wrote,
‮Сдвиг по фазе
kincajou

Category:

worklog: I2C в STM32F030 - почти победил (2)


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

Суть проблемы: после того, как мы получили и распознали адрес от ведущего устройства, мы должны (будучи в режиме slave transmitter) выложить наши данные в буфер. Предварительно убедившись в том, что буфер в самом деле пуст (для чего есть ажно два флага с очень схожим, прям до почти полного отсутствия различий, смыслом -- I2C_ISR_TXE и I2C_ISR_TXIS), кладём байтик в I2C1->TXDR и ждём взведения того же бита, что мы только что проверяли - как только он станет равен 1, это означает, что байт передан. Но! ...

И вот тут эта бомбачка как раз и лежит.

Взведение флага "байт передан" вовсе не означает, что мы получили ACK/NACK бит от принимающей стороны! Нихера подобного! Вообще всё не так! Флаг взводится (или нет) ПОТОМ, когда реальный бит реально прошёл по реальным проводам и перещёлкнул логику внутри I2C модуля. А это довольно-таки длительный промежуток времени по меркам 48-мегагерцового процессора. Задача осложняется тем, что ACK и NACK - это просто два разных значения одного и того же бита, и мы не можем никак но узнать в общем случае, пришёл ли он вообще. Да, можно, например, дождаться взведения флага I2C_ISR_NACKF - и это работает... только в том случае, если в самом деле пришёл именно NACK (потому что он равен 1). Но флаг не будет взведён, если пришёл бит ACK (ибо он равен 0) - значение флага останется нулевым и мы будем ждать его изменений вечно.

Без использования прерываний эту проблему почти никак не решить (топорные методы а-ля "поставить задержку и посмотреть заново состояние флагов" не предлагать). Причём обработчик должен ловить и событие "буфер передатчика опустошён", и "получен NACK", и "получен STOP"... эхохо.

Ладно. Я заранее знал, что совсем простой код не годится для чуточку более сложной задачи. Но всё равно как-то странно - что мешало проектировщикам железа добавить флаг ACK в тот регистр, не понимаю...


Upd Переписал на работу с прерываниями и наткнулся на очередной сюрприз. Он, канеш, упомянут в документации, но как-то без упора на необходимость аккуратного обхода: если вы кладёте данные по каждому прерыванию TXIS, то по получению состояния STOP регистр передатчика будет хранить предыдущий байт до посинения. И следующая транзакция начнётся с его передачи, а запись в TXDR будет проигнорирована (состояние overrun). Чтобы этого не случалось, при обработке STOPF нужно опорожнять буфер передатчика, выставляя бит I2C_ISR_TXE (и никак иначе).

Наконец-то, передача последовательности байт заработала как надо.
Tags: радио
Subscribe

  • Говорят, в Томске маньяка поймали.

    ... но явно не того. Пойманный -- какой-то бывший мент, а должен быть писатель, по образованию физик-теоретик, в космонавтике, так сказать,…

  • Кого бережёт милиция?..

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

  • Молвят, сегодня случилось CME

    Coronal Mass Ejection - весьма редкое событие, и вот оно, пожалста-неждали! Есть ненулевой риск веерных отключений искричества и прочих…

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 2 comments