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

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

Я после настроек USART делаю

NVIC_ClearPendingIRQ(USART3_IRQn);

потом

NVIC_EnableIRQ(USART3_IRQn);

Не знаю, надо ли. Может, прерывание возникает при освобождении буфера, а не когда он пустой.

Да, когда нужно послать массив, посылаю байт, разрешаю прерывание TXE. Остальные байты посылаются по прерыванию. При передаче последнего байта запрещаю прерывание TXE.

Ну так дело именно в запрещении/разрешении TXE, а не магических пассах с ClearPending.

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

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


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

Странно, если в обработчике прерываний вставляю условие

(USART_GetITStatus(UART5, USART_IT_TXE) != RESET)

то все работает

а если делаю так

((UART5->SR & USART_SR_TXE) != 0)

то не работает

что-то не так разве?

раньше у меня было

((UART5->SR & USART_SR_TC) != 0)

и работало...

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


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

Ну так дело именно в запрещении/разрешении TXE, а не магических пассах с ClearPending.

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

Да. Значит, очищать отложенный запрос не нужно.

Прерывание возникает не при пустом буфере. Вот что написано в документации на STM32F2xx.

This bit is set by hardware when the content of the TDR register has been transferred into

the shift register. An interrupt is generated if the TXEIE bit =1 in the USART_CR1 register. It

is cleared by a write to the USART_DR register.

0: Data is not transferred to the shift register

1: Data is transferred to the shift register)

Поэтому в начале, когда буфер пустой, прерывание не возникает.

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


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

а если делаю так

((UART5->SR & USART_SR_TXE) != 0)

то не работает

Потому что надо делать вот так:

if ((UART5->SR & USART_SR_TXE) && (UART5->CR1 & USART_CR1_TXEIE))

 

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


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

Потому что надо делать вот так:

if ((UART5->SR & USART_SR_TXE) && (UART5->CR1 & USART_CR1_TXEIE))

спасибо, заработало)

USB у меня заместился UART-ом, поэтому есть желание перейти на чистый CMSIS, тем более в прерываниях почти нигде не использую SPL функции

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


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

После перехода на прерывание TXE стало нормально работать на скорости 2 Мбит/с.

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

Как теперь этот глюк выловить, непонятно...

 

Обнаружил пропуски отправок данных. То есть приходит запрос "Передать данные", а их вдруг почему то нет (вычисляю наличие данных по неравенству указателей записи и чтения из буфера)

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


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

По поводу прерываний.

Вы говорили что у вас есть прерывания с меньшим приоритетом.

По умолчанию вложенные прерывания запрещены.

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

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

Именно здесь приоритеты начинают работать. Обслужены они будут в порядке приоритетов.

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


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

По умолчанию вложенные прерывания запрещены.

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

Разве? По-моему, вы ошибаетесь.

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


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

Хотел найти подтверждение того что вложенные прерывания запрещены по-умолчанию.

Не могу найти. Неужели и правда неправильно отложилось в голове.

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


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

Потеря данных оказалась в другом контроллере.

 

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

Еще раз обрисую ситуацию. Есть кольцевой буфер, на 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

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


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

...

Есть кольцевой буфер, на 512 байт. В него раз в 1,125 мс пишут 4 DMA.

...

Нельзя тупо писать в кольцевой буфер через DMA. Если в буфер пишут (и, соответственно, читают) несколько источников, а уж, тем более, разные канала DMA, необходима блокировка операций чтения/записи от наложений, а само DMA этого сделать не может.

 

Т.е., перед началом операции чтения/записи (неважно, по DMA или нет) необходимо заблокировать другим доступ к буферу (кто первый встал - того и тапки, пусть другие ждут освобождения пока я не закончил), а по завершении операции - разблокировать. Т.е. сделать стандартный Lock|Unlock, причем аккуратно - с запретом прерываний на время чтения и изменения Lock|Unlock.

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


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

Нельзя тупо писать в кольцевой буфер через DMA. Если в буфер пишут (и, соответственно, читают) несколько источников, а уж, тем более, разные канала DMA, необходима блокировка операций чтения/записи от наложений, а само DMA этого сделать не может.

 

Т.е., перед началом операции чтения/записи (неважно, по DMA или нет) необходимо заблокировать другим доступ к буферу (кто первый встал - того и тапки, пусть другие ждут освобождения пока я не закончил), а по завершении операции - разблокировать. Т.е. сделать стандартный Lock|Unlock.

Если я правильно понял, то у меня все правильно.

DMA пишут в свои, отдельные, массивы. А в процедуре обработки прерывания от DMA я копирую из этих массивов в кольцевой буфер.

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


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

DMA пишут в свои, отдельные, массивы. А в процедуре обработки прерывания от DMA я копирую из этих массивов в кольцевой буфер.

У DMA есть хорошее прерывание на половину буфера.

Т.е. настраиваешь DMA на запись всего буфера, пока DMA пишет в первую половину, разрешаешь чтение из второй половины.

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

Главное чтобы чтение было быстрее записи :)

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


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

DMA пишут в свои, отдельные, массивы. А в процедуре обработки прерывания от DMA я копирую из этих массивов в кольцевой буфер.

Если просто копируете, без какой-либо обработки/переупаковки, то это дерьмовая реализация.

Зачем эти копирования туда-сюда, если DMA уже предназначен для перемещения память<->периферия? Никто не мешает писать DMA прямо в кольцевой буфер.

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


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

Если просто копируете, без какой-либо обработки/переупаковки, то это дерьмовая реализация.

Зачем эти копирования туда-сюда, если DMA уже предназначен для перемещения память<->периферия? Никто не мешает писать DMA прямо в кольцевой буфер.

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

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


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

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

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

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

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

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

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

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

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

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