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

Работа кольцевого буфера

С трудом это представляю. При настройке DMA надо указать адреса в кольцевом буфере. Для 4-х DMA то есть будет 4 адреса со смещением на длину пакета. А если вдруг не придут данные от одной из DMA?

Не понял что такое "4 DMA"? У Вас в первом сообщении написано про приём с UART посредством DMA, а всю переписку мне читать лень что там навыдумывали.

Для приёма с UART посредством DMA в кольцевой буфер достаточно одного DMA канала. Так как в STM32, в силу его ущербности отсутствует UART-FIFO, а скорости UART Вы хотите большие, то перепрограммировать DMA

на новую передачу при завершении предыдущей каждый раз опасно - можно не успеть запрограммировать DMA на очередную порцию и будет потеря байт.

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

Не знаю как в STM32, но почти на всех МК с которыми я работал DMA-контроллер позволял работать в режиме связных списков.

 

Условно говоря алгоритм следущий:

1. Программируем первый DMA-блок на приём в первую треть кольцевого буфера, второй DMA-блок программируем на приём во вторую треть кольцевого буфера. В первом блоке ставим ссылку на второй блок, во втором - на первый.

В каждом блоке ставим флаг - выдать прерывание по окончании блока.

2. Запускаем DMA.

3. При получении первого прерывания (нечётного) знаем что сейчас закончился приём первого блока и начался приём 2-го блока. В этом ISR корректируем указатели целевого адреса и размера в первом блоке на следующее свободное место в кольцевом буфере (в первом полученном прерывании это будет 3-я часть кольцевого буфера) и выходим из ISR.

4. При получении второго прерывания (чётного) знаем что сейчас закончился приём 2-го блока и начался приём 1-го блока. Корректируем указатель и размер во 2-ом блоке.

5. .... и так далее опять с шага 3. На каждом полученном прерывании завершения DMA-блока корректируем след. блок определяя доступный размер непрерывного блока в циклическом буфере.

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

 

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

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


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

Не знаю как в STM32

... ну очень плохо.

 

Переименуйте ответ в "для сферического DMA в достаточно разреженной среде можно сделать вот так:", и всё будет хорошо.

А для ST-шек оно не работает. Там и DMA не очень-то навороченный...

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


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

Переименуйте ответ в "для сферического DMA в достаточно разреженной среде можно сделать вот так:", и всё будет хорошо.

А для ST-шек оно не работает. Там и DMA не очень-то навороченный...

И что вы хотели этим сказать? Что кроме STM32 больше ничего не знаете?

Такой алгоритм работает на любом DMA-контроллере с поддержкой связных списков, а реализована она по-разному в разных МК.

Связные списки есть в DMA-контроллерах LPC разных линеек, в Tiva TM4C129, в OMAP-L137 и думаю многих других.

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


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

Это все теория...менять контроллер сейчас нет смысла.

Я пока вот это никак отловить не могу.

Теперь иногда вылазит такой баг - конец одного пакета как бы затирает начало первого.

Еще раз обрисую ситуацию. Есть кольцевой буфер, на 512 байт. В него раз в 1,125 мс пишут 4 DMA. Размер одной посылки по DMA - 19 байт. Обработка прерывания одного DMA занимает примерно 22 мкс. Раз в 1 мс приходит запрос данных и если есть данные - они передаются по UART. Прерывания DMA и UART имеют одинаковый приоритет, поэтому вычисление количества данных и манипуляции с указателями выполняются вроде как атомарно.

Смотрел осциллографом - скорость передачи такова, что частота опроса в 1 мс нормальна. Данные передаются самое большее где то за 0,5 - 0,6 мс.

Тем не менее, по истечению какого то времени (минут 15-20) возникает непонятный баг - конец одного пакета затирает начало другого. И еще более странно, затирает не предыдущий пакет! Я добавил в начало и конец каждого пакета байтовый счетчик. Прикладываю скрин с этим багом, разложил все по пакетам. 7 пакетов, начало первого пакета затер конец 7-го пакета.

Может быть у кого то есть идеи из-за чего такое может быть?

post-65102-1449045667_thumb.png

 

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


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

Это все теория...менять контроллер сейчас нет смысла.

Я пока вот это никак отловить не могу.

Вставить в каждое прерывание индикаторы срабатывания - в начале взводить какой-нибудь пин, в конце сбрасывать,

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

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


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

Я пока вот это никак отловить не могу.

Самое интересное, что индекс начала одного пакета 0, а другого 128. Можно было бы предположить, что гдето в индексе массива используется I8 вместо U16 или U32, но тогда бы эта ошибка вылезала каждый раз. Более того, чтобы получить две копии одного и того же пакета нужно дважды скопировать один массив в два места, что не возможно, если верить Вашей логике - для этого нужно дважды влететь в прерывание от ДМА, при этом второй раз там уже будет совсем другой пакет.

У Вас точно не вложенные прерывания?

И еще проверьте, чтобы не было функций, которые используются в прерывании и в основном теле.

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


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

Самое интересное, что индекс начала одного пакета 0, а другого 128. Можно было бы предположить, что гдето в индексе массива используется I8 вместо U16 или U32, но тогда бы эта ошибка вылезала каждый раз. Более того, чтобы получить две копии одного и того же пакета нужно дважды скопировать один массив в два места, что не возможно, если верить Вашей логике - для этого нужно дважды влететь в прерывание от ДМА, при этом второй раз там уже будет совсем другой пакет.

У Вас точно не вложенные прерывания?

И еще проверьте, чтобы не было функций, которые используются в прерывании и в основном теле.

В какой уже раз при нарушении работы я ищу ошибку в STM32, а она на самом деле в C8051F320. У меня там задействован Endpoint 2, размер которого 256 байт и в дескрипторах объявлен размер эндпойнта 256 байт. Но еще включена двойная буферизация, поэтому писать в USB FIFO больше 128 байт нельзя, а я писал и 133 байта и 152, чаще 133. Причем никаких ошибок и наложений в большинстве случаев такой записи не было. Я не знаю, как работает FIFO и куда он пишет, если писать некуда. Но в какой то момент, видимо, при попытке записи больше, чем влезает он накладывал не вошедшие данные поверх уже записанных. Отсюда видимо и количество наложенных байт - 5, это не что иное как 133 - 128.

Может кто-нибудь знает как работает USB FIFO у C8051F320 ?

 

Еще, не знаю насколько это корректно, но я ограничил количество данных вычитываемых из кольцевого буфера. Посмотрел осциллографом - получалось так, что по запросу отправлялось 133 байта, а на следующий запрос - данных было мало или, чаще, совсем не было. В общем я добавил условие, что если вычисленная длина равна 133 байта (или больше), то присваиваем ей значение 114 (на один пакет меньше).

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

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


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

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

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

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

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

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

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

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

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