Щас вот нашёл интересное. Вот есть концепция "событие DMA". Это некий бит в некоем регистре - в каких-то периферийных модулях он логически совпадает с флагом какого-либо прерывания, в каких-то других он может и не иметь соответствующего прерывания. Когда бит устанавливается в 1, то это побуждает модуль DMA передвинуть очередную порцию данных. Если DMA не включен, но есть разрешённое прерывание, то вызовется его обработчик. А что будет, если одновременно включить и DMA, и прерывание?
А х.з. В каких-то случаях не сработает ни, то, ни другое. Но в других может сработать что-то одно из. Почему так - я не знаю.
Собсно, щас переделал процыдурку с циклов ожидания на прерывания. Сначала взводим прерывание от I2C, разрешая реакцию на флаги NACKF ("в ответ на наш байт получен NACK") и TXIS ("буфер передатчика пуст и готов к новым данным"). Т.е. алгоритм такой:
1) инициализируем
2) разрешаем прерывание
3) генерим START
4) ...
5) срабатывает прерывание I2C1_EV ("event"; для ошибок есть отдельный вектор I2C1_ER). В нём я смотрю, какой имеено флажок выставлен. Если NACK, то через глобальную переменную возвращается состояние ошибки. Если TXIS, то включается соответствующий поток DMA с его прерыванием.
6) ....
7) срабатывает прерывание DMA1_StreamX, тут уже смотрим на номер канала. Если это наш канал (для I2C1 это всегда номер 1), то после сбоса и отключения модуля DMA через ту же глобальную переменную возвращаем состояние успешной передачи.
Нюанс как раз в том, что TXIS это одновременно ещё и событие DMA, если про это забыть, то можно очень долго ждать срабатывания хоть чего-нибудь.
Теперь следующая итерация - заменить обмен данными через глобальную переменную на синхронизацию через семафоры или даже через очереди РТОС. Непонятно только, что будет с временем обработки - если цикл-крутилка на изменение переменной реагирует почти мгновенно, то у РТОС же есть какая-то гранулярность событий, быстрее чем за 1 тик она не реагирует.. или реагирует?