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

Как-то сложновато...

Если отказаться от счётчика (а зачем он нужен?) и оперировать только указателями на "голову" и "хвост" буфера, то и флаг не понадобиться, и прерывания можно не трогать, один раз только разрешить при инициализации и всё.

Если оба указателя равны друг другу, буфер пуст или полон?

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


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

Если оба указателя равны друг другу, буфер пуст или полон?
Принять на веру что пуст.

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

По сути те же самые ограничения на производительность что и у вас, но у вас всё гавкнется гораздо раньше...

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


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

Я сделал драйвер для USART, который работает через DMA, может быть пригодится кому нибудь. Извлекал его потом из реального проекта, так что мог что то упустить, но надеюсь не упустил.

Длайвер работает через USART1, адаприровать под другие порты, думаю не составит труда.

Основной прием данных производится в буфер через DMA канал. По заполнению половинок буфера данные извлекаются и передаются в обработчик. В случае применения RTOS данные передаются в предусмотренный для данных queue (или в другой терминологии - в "message box"). Буфер может быть достаточно большого размера - 128 и более байт и в случае, если передача остановилась где то посередине и DMA прерывание не возникает, то через несколько пустых временных окон приема символов возникает прерывание "IDLE line" от USART, в данном прерывании вытаскивается хвост данных и DMA канал сбрасывается в стартовое состояние.

Дан проект-пример. Основные файлы - main.c и STM32F10x_it.c. В main.c производится вся настрока периферии. В во втором прерывании все необходимые обработчики, а именно - от DMA и от USART.

Ссылка

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


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

А есть ли возможность аппаратно увидеть что начался приём данных?, что бы не начать новую передачу в случае RS-485 и не подгонять тайм ауты посылок. А то принимать всю посылку по IDLE удобно, но не знаешь есть она или нет в данный момент. Проверка флага RXNE в регистре USARTx_SR не помогла, этот флаг иногда ловится на несколько приходящих посылок, причём сбрасывался он сам, наверное DMA когда забирает байт данных очищает его.

Мк ST32F407.

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


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

Отвечу сам на свой вопрос. Экспериментально проверил, если использовать режим IDLE и при этом DMA забирает всю посылку, то и флаг RXNE очищается когда его забрало DMA и прерывание по приёму USART_IT_RXNE никогда не произойдёт. Вижу только 2 выхода что бы определить старт приёма: Принять 1-ый байт и подключить потом DMA для приёма оставшейся посылки, 2-ой использовать ещё один бит порта как внешнее прерывание (поймать старт бит и отключить потом внешнее прерывания, до приёма полной посылки).

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


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

Если я правильно понимаю в чем проблема - то можно контроллировать счетчик передачи DMA. Если он не равен одному из 2 указателей, то передача в процессе.

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


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

Задача такая: хотелось бы контролировать что начался приём. Как я понял вы предлагаете периодически опрашивать счётчик байтов DMA, и если он не равен 0, то значит идёт прём данных. Как то не подумал о таком, попробую при случае, спасибо за идею.

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


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

В этой идее есть недостаток. Счётчик ДМА может ещё не измениться а приём байта быть в процессе.

Байты же не мгновенно принимаются, а по-битно...

 

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


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

В этой идее есть недостаток. Счётчик ДМА может ещё не измениться а приём байта быть в процессе.

Байты же не мгновенно принимаются, а по-битно...

Вероятность потери байта предельно низка, так как сначала достаются все байты из массива ДМА, затем еще раз проверяется счетчик ДМА и если он не изменился за время вытаскивания данных, то ДМА ресетится. Процедура сброса ДМА занимает доли микросекунды. В принципе, можно на время сброса ДМА переключать прием на прерывание, а затем назад. Но как показывает практика, и без этого все хорошо. По крайней мере через GPRS модем на 115200 (при скорости HCLK всего лишь 4МГц) удается принимать массивы несколько сот кБ без потерь (больше просто не пробовал). При этом контроллер под управлением freertos обслуживает около 10 задач и еще эпизодически работают 4 канала того же ДМА.

Изменено пользователем kan35

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


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

А зачем вообще что-то ресетить? Ведь у дма есть циркулярный режим...

 

//=============================================================================
int uart_getc(uart_t* const uart)
{
    dma_t* const dma = &uart->dma.rx;

    if (dma->size - dma->sfr->CNDTR != dma->idx)
    {
        int x = dma->buf[dma->idx];

        if (++dma->idx >= dma->size)
        {
            dma->idx = 0;
        }

        return (x);
    }

    return (-1);
}

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


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

Он итак в циркулярном режиме.

Вы просто проверяете наличие данных в ДМА памяти, но не это цель. А цель сделать все максимально аппаратно. То есть без участия процессора.

В моем варианте при зполнении половинок буфера ДМА (или как вариант разных буферов в процессорах F2 и F4) возникают прерывания, в которых данные забираются. При паузе в передаче - данные так же успешно забираются из прерывания IDLE line. Никаких поллингов!

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


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

Понятно. У вас под ОС видимо заточка, а у меня под луп.

Вы просто проверяете наличие данных в ДМА памяти
Да. Я ДМА как фифо использую.

Кстати, на передачу у вас тоже ДМА задействовано?

У меня нет. Красивого решения не придумалось...

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


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

Понятно. У вас под ОС видимо заточка, а у меня под луп.Да. Я ДМА как фифо использую.

Кстати, на передачу у вас тоже ДМА задействовано?

У меня нет. Красивого решения не придумалось...

Да, под ОСь.

На передачу не сделал, но надо бы, руки не дошли пока. Для Оси передача получится просто красиво: задача уснет до окончания выполнения передачи. Для лупа не так просто будет, придумывать надо что то...

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


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

А есть ли возможность аппаратно увидеть что начался приём данных?, что бы не начать новую передачу в случае RS-485 и не подгонять тайм ауты посылок
От коллизий в RS485 вы так не защититесь. Это поможет сделать только протокол обмена.

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

 

Вероятность потери байта предельно низка, так как сначала достаются все байты из массива ДМА, затем еще раз проверяется счетчик ДМА и если он не изменился за время вытаскивания данных, то ДМА ресетится. Процедура сброса ДМА занимает доли микросекунды.
Если вероятность потери !=0, то на помойку такое ПО. Которое может работать с некоторой вероятностью в зависимости от фазы луны.

А если между проверкой и сбросом DMA как раз и придёт байт? И что значит "ресет DMA"? Это именно сброс канала или запрет его работы? Есть-ли у DMA каналов в STM32 FIFO? Знаю что у многих других контроллеров - есть, что будет приводить к потерям байт (при сбросе DMA) или появлению лишних байт (при его запрете) - сам лично сталкивался с такой проблемой.

 

Должен быть алгоритм, позволяющий работать с 100% вероятностью. Иначе - зачем нужен STM32 если есть другие процессоры (например LPC или от TI) где есть нормальное FIFO на UARTах работающее со 100% вероятностью и не нужны пляски с бубном с DMA?

Пишу не с целью разжигания религиозной войны STM vs LPC, а с целью понять плюсы и минусы STM32, как замены хорошо знакомым ядрам от NXP. Мои задачи подразумевают интенсивное использование UART-ов (несколько одновременно, до 5и) под ОС. Я пытаюсь понять во что это выльется при переходе с LPC на STM32?

Очень настораживает сложность работы с UART на STM32 через DMA. Работа с частотами прерываний от одного UART порядка 11кГц/11кГц (TX/RX) на 115200 и суммарной эквивалентной частотой от 5-ти UART на 115200 порядка 110кГц очень напрягает, особенно под ОС.

Прочитал сообщения этой ветки и возникли у меня большие сомнения в целесообразности использования STM32 вообще при работе с UART...

 

В частности вопрос: если работать на приём так:

Получаю IDLE-прерывание, в его обработчике запрещаю канал DMA, копирую данные из буфера DMA в программное FIFO, настраиваю канал DMA заново на приём в буфер DMA, разрешаю DMA, выхожу из ISR. Могут-ли в таком алгоритме быть потери байт или другие проблемы?

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


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

Всё прекрасно работает на stm32. Не паникуйте!:)

Кстати, у stm32f0 много вкусностей в модуле uart появилось относительно stm32f1. Так-что не надо всех под одну гребёнку....

Вы всё равно не составите адекватного мнения, пока не попробуете лично. ИМХО.

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


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

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

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

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

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

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

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

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

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

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