В прошлом месяце я трачу много времени на то, чтобы UART (для MIDI) работал с STM (STM32F103C8T6), используя прерывания, но без особого успеха.
Однако в этот вечер с использованием DMA все работало довольно быстро.
Поскольку, насколько я понимаю, DMA работает быстрее и освобождает процессор, почему бы не всегда использовать DMA в пользу прерываний? Тем более, что на STM32, похоже, довольно много проблем.
Я использую STM32CubeMx / HAL.
uart
dma
stm32cubemx
stm32f103c8t6
Мишель Кейзерс
источник
источник
Ответы:
Несмотря на то, что DMA освобождает ЦП и, таким образом, может снизить задержку других приложений, управляемых прерываниями, работающих на том же ядре, с этим связаны некоторые расходы:
Существует только ограниченное количество каналов DMA, и существуют ограничения на то, как эти каналы могут взаимодействовать с различными периферийными устройствами. Другое периферийное устройство в том же канале может быть более подходящим для использования DMA.
Например, если у вас массовая передача I2C каждые 5 мс, это кажется лучшим кандидатом на DMA, чем случайная команда отладки, поступающая на UART2.
Настройка и поддержка DMA - это сама по себе стоимость . (Как правило, настройка DMA считается более сложной, чем настройка обычной передачи на основе прерываний по символам, из-за управления памятью, использования большего количества периферийных устройств, использования DMA с использованием прерываний и возможности анализа первых нескольких символов вне DMA в любом случае, см. ниже.)
DMA может использовать дополнительную мощность , поскольку это еще один домен ядра, который необходимо синхронизировать. С другой стороны, вы можете приостановить процессор, пока идет передача DMA, если ядро это поддерживает.
DMA требует буферов памяти для работы (если вы не делаете периферийное-периферийное DMA), поэтому с ним связаны некоторые затраты памяти.
(Стоимость памяти также может быть там, когда используются прерывания по символам, но она также может быть намного меньше или вообще исчезать, если сообщения интерпретируются сразу внутри прерывания.)
DMA создает задержку, потому что процессор получает уведомление только тогда, когда передача завершена / наполовину завершена (см. Другие ответы).
За исключением потоковой передачи данных в / из кольцевого буфера, вам нужно заранее знать, сколько данных вы будете получать / отправлять.
Это может означать, что необходимо обрабатывать первые символы сообщения, используя прерывания для каждого символа: например, при взаимодействии с XBee сначала нужно прочитать тип и размер пакета, а затем запустить передачу DMA в выделенный буфер.
Для других протоколов это может быть вообще невозможно, если они используют только разделители конца сообщения: например, текстовые протоколы, которые используют в
'\n'
качестве разделителя. (Если только периферийное устройство DMA не поддерживает сопоставление для символа.)Как видите, здесь есть много компромиссов. Некоторые из них связаны с аппаратными ограничениями (количество каналов, конфликты с другими периферийными устройствами, сопоставление по символам), некоторые основаны на используемом протоколе (разделители, известная длина, буферы памяти).
Чтобы добавить некоторые неподтвержденные доказательства, я столкнулся со всеми этими компромиссами в хобби-проекте, который использовал много различных периферийных устройств с очень разными протоколами. Были некоторые компромиссы, в основном основанные на вопросе «сколько данных я передаю и как часто я собираюсь это делать?». По сути, это дает вам приблизительную оценку влияния простой передачи, управляемой прерываниями, на процессор. Таким образом, я отдавал приоритет вышеупомянутой передаче I2C каждые 5 мсек по сравнению с передачей UART каждые несколько секунд, которые использовали один и тот же канал DMA. Другая передача UART происходит чаще и с большим количеством данных, с другой стороны, имеет приоритет над другой передачей I2C, которая происходит реже. Это все компромиссы.
Конечно, использование DMA также имеет свои преимущества, но это не то, что вы просили.
источник
Использование DMA обычно означает, что вы больше не прерываете каждый символ, а только после того, как «полный буфер» символов был получен (или передан). Это увеличивает задержку обработки этих символов - первый символ не обрабатывается до тех пор, пока не будет получен последний символ в буфере.
Эта задержка может быть плохой, особенно в чувствительном к задержке приложении, таком как MIDI, где несколько мс здесь и там могут привести к серьезным проблемам с воспроизведением для живых выступлений.
источник
DMA не заменяет прерывания - они обычно используются вместе! Например, если вы используете DMA для отправки данных через UART, вам все еще нужно прерывание, чтобы сообщить вам, когда отправка завершена.
источник
Использование DMA ставит некоторые интересные вопросы и проблемы, выходящие за рамки всех других аспектов использования периферийных устройств UART. Я приведу несколько примеров: Предположим, что ваш УК находится на шине RS485 (или любой другой) с другими устройствами. В шине много сообщений, некоторые предназначены для вашего ОК, некоторые нет. Дополнительно предположим, что все эти соседи по шине говорят по другому протоколу данных, что означает, что длины сообщений различны.
Некоторые вопросы, которые возникают только при использовании DMA:
Во всяком случае, просто пища для размышлений.
источник
На приемной стороне (насколько я помню) DMA завершается либо при совпадении символов, либо при подсчете терминала. Некоторые протоколы и многие интерактивные приложения нелегко вписываются в эту модель, и вам действительно нужно обрабатывать вещи символ за символом. Методы DMA также могут быть хрупкими, если канал связи ненадежен, потеря одного символа в потоке может легко испортить ваш конечный автомат DMA.
источник
Я уже использовал STM32CubeMx / HAL в нескольких проектах и обнаружил, что генерируемая им программа обработки UART имеет определенные недостатки на стороне приема.
При передаче вы обычно хотите отправить блок данных или строку текста. В этом случае вы заранее знаете, сколько времени занимает передача данных, и поэтому использование DMA является очевидным решением. Вы получаете прерывание после завершения передачи и можете использовать функцию обратного вызова UART TX complete, чтобы указать вашему основному коду, что передача завершена, и вы можете отправить другой блок данных.
Когда дело доходит до получения данных, все функции, предоставляемые ST, предполагают, что вы знаете, сколько символов будет выдано отправляющим устройством, прежде чем оно начнет отправлять. Обычно это не известно. Функция прерывания помещает полученные данные в буфер и указывает только на то, что данные доступны, когда получено заранее определенное количество символов. Если вы попытаетесь использовать DMA или функцию прерывания для получения данных путем настройки последовательных односимвольных передач, то время установки для каждого из них будет означать, что вы потеряете символы с любой скоростью, кроме самой низкой скорости передачи данных (скорость передачи данных, которую вы будете потеря данных будет зависеть от тактовой частоты вашего процессора) и будет чрезмерно загружать процессор, не оставляя циклов команд для какой-либо другой обработки
Чтобы обойти это, я написал свою собственную функцию обработчика прерываний, которая хранит данные в небольшом локальном циклическом буфере и устанавливает счетчик, который читается основным кодом (семафор подсчета RTOS), чтобы указать, что полученные данные готовы. Затем основной код может собирать данные из этого буфера в свободное время, при этом не имеет значения, имеется ли некоторая задержка в сборе данных, при условии, что локальный буфер не переполняется до того, как данные собраны.
источник