Задача такая. Микроконтроллер STM32F1. На шине i2c две микросхемы датчиков, нужно опрашивать их 16 раз в секунду в фоне, не мешая основной задаче.
Для этого реализовал работу с i2c целиком через прерывания и DMA. На вход подаётся набор опкодов, которые управляют последовательностью действий на шине I2C (START, записать 7-битный адрес, читать N байт и так далее, в конце опкод STOP который на шине выставляет состояние STOP).
В конце последовательности должна вызываться указанная мной подпрограмма чтобы решить что дальше делатть.
Далее написал подпрограммы для работы с датчиками. На один датчик просто идёт последовательность чтения/записи регистров, в конце STOP. На второй датчик обмен идёт в два этапа, сначала читаем один регистр, потом STOP, анализируем что получили и в зависимости от этого генерируем новую последовательность опкодов, которую снова запускаем на выполнение.
И так 16 раз в секунду.
По отдельности каждая подпрограмма работает нормально. Проблемы начинаются когда начинаешь их вызывать сразу друг после друга.
Иногда это работает, иногда нет. Причина в том, что последнее прерывание (по которому выполняется опкод STOP и, соответственно, вызов моей подпрограммы) вызывается ДО того, как на шине выставилось состояние STOP. И если я прямо во время этого прерывания "заряжаю" автомат на выполнение следующей последовательности, то периферийный контроллер I2C сбивается с ритма и часто подвисает. То есть, в идеале, после выставления бита STOP в регистре CR1 нужно прождать какое-то время, пока этот STOP реально выполнится, и только после этого начинать следующий обмен по шине.
К сожалению, даташит меня огорчает.
Как видно, событие (прерывание) EV8_2 вызывается до выставления STOP, а после сигнала STOP никаких событий уже не возникает.
А мне бы хотелось выставить STOP, подождать какое-то время, затем начать следующий цикл обмена. Но такой аппаратной возможности, без тупого ожидания в цикле, я не нашёл. Можно припахать для этого один из таймеров, но хочется обойтись только I2C (библиотека работы с I2C общего плана, не заточенная под конкретный проект).
Кто-нибудь встречался с такой ситуацией?
Как выдержать интервал между пакетами на шине i2c
- zap
- Первый раз сказал Мяу!
- Сообщения: 23
- Зарегистрирован: Пн июл 20, 2009 01:17:05
- Откуда: Санкт-Петербург
- Контактная информация:
Как выдержать интервал между пакетами на шине i2c
С уважением,
Андрей
Андрей
- Реклама
Re: Как выдержать интервал между пакетами на шине i2c
[uquote="zap",url="/forum/viewtopic.php?p=3306551#p3306551"]А мне бы хотелось выставить STOP, подождать какое-то время, затем начать следующий цикл обмена. Но такой аппаратной возможности, без тупого ожидания в цикле, я не нашёл.[/uquote]
Создать отдельную задачу ОС для опроса по I2C. После STOP задачу ставить на паузу на несколько тиков системного таймера, после чего опрашивать следующее устройство.
Создать отдельную задачу ОС для опроса по I2C. После STOP задачу ставить на паузу на несколько тиков системного таймера, после чего опрашивать следующее устройство.
- zap
- Первый раз сказал Мяу!
- Сообщения: 23
- Зарегистрирован: Пн июл 20, 2009 01:17:05
- Откуда: Санкт-Петербург
- Контактная информация:
Re: Как выдержать интервал между пакетами на шине i2c
Ну это по сути то же самое, что задействовать ещё один таймер.
В общем, победил я её. Оказывается, между обращениями к разным чипам вовсе не обязательно выставлять на шину сигнал STOP. Достаточно подать повторный START, потом адрес второго чипа и всё отлично работает. Поэтому теперь все запросы к разным чипам идут одной пачкой, между запросами лишь повторный START. Так что на длительность STOP мне теперь уже плевать, он подаётся один в конце.
В общем, победил я её. Оказывается, между обращениями к разным чипам вовсе не обязательно выставлять на шину сигнал STOP. Достаточно подать повторный START, потом адрес второго чипа и всё отлично работает. Поэтому теперь все запросы к разным чипам идут одной пачкой, между запросами лишь повторный START. Так что на длительность STOP мне теперь уже плевать, он подаётся один в конце.
С уважением,
Андрей
Андрей
