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

Stm32: Cubemx+Uart_Dma


verlaty

Рекомендуемые сообщения

Реклама: ООО ТД Промэлектроника, ИНН: 6659197470, Тел: 8 (800) 1000-321

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

Я там еще пробелы добавляю и конец строки (перевод каретки + ноль символ) чтобы удобнее читать было

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

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

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

Нужно делать то, что нужно. А то, что не нужно, делать не нужно. (С) Винни Пух

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

20% скидка на весь каталог электронных компонентов в ТМ Электроникс!

Акция "Лето ближе - цены ниже", успей сделать выгодные покупки!

Плюс весь апрель действует скидка 10% по промокоду APREL24 + 15% кэшбэк и бесплатная доставка!

Перейти на страницу акции

Реклама: ООО ТМ ЭЛЕКТРОНИКС, ИНН: 7806548420, info@tmelectronics.ru, +7(812)4094849

Кажется выловил ошибку.

huart1.ErrorCode выдает 8.

а это HAL_UART_ERROR_ORE ((uint32_t)0x00000008) /*!< Overrun error

ORE — ошибка: переполнение входного буфера — приняты новые данные, а старые ещё не прочитаны

во всяком случае есть куда капать.

Буду разбираться. Если есть дельные советы - внимательно слушаю

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

Выбираем схему BMS для корректной работы литий-железофосфатных (LiFePO4) аккумуляторов

 Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ, также как и для других, очень важен контроль процесса заряда и разряда, а специализированных микросхем для этого вида аккумуляторов не так много. Инженеры КОМПЭЛ подготовили список имеющихся микросхем и возможных решений от разных производителей. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

для начала попробовать

__HAL_UART_FLUSH_DRREGISTER(&huart1);

первой строчкой в колбэке

Нужно делать то, что нужно. А то, что не нужно, делать не нужно. (С) Винни Пух

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

Пробую сбрасывать флаг

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
E_CODE = HAL_UART_GetError (huart);
switch (E_CODE)
{
case HAL_UART_ERROR_ORE:
 __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_OREF);
 CLEARFL = HAL_UART_GetError (huart);
break;
}

сделал переменную CLEARFL для контроля

Ну в общем не сбрасывает. Кто сталкивался с этой бедой?

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

возможно прежде чем сбросить флаг, надо устранить причину его возникновения, иначе следующим же тактом он опять будет поднят

см. предыдущий пост

ну и сам подход неверен. Сбросить флаг в железе может быть совсем не одно и то же для HAL. Лучше использовать макрос сброса (для F1 и F0)

для трешки еще можно попробовать вот эти вот макросы

UART Advanced Feature Overrun Disable

UART_ADVFEATURE_OVERRUN_ENABLE

UART_ADVFEATURE_OVERRUN_DISABLE

IS_UART_OVERRUN

единственное я на них доки не нашел, лучше посмотреть что там в них за код и покумекать как их поставить раком

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

Нужно делать то, что нужно. А то, что не нужно, делать не нужно. (С) Винни Пух

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

Точно. Надо сначала очистить буфер.

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
E_CODE = HAL_UART_GetError (huart);
switch (E_CODE)
{
 case HAL_UART_ERROR_ORE:
  __HAL_UART_FLUSH_DRREGISTER(huart);
  __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_OREF);
  CLEARFL = HAL_UART_GetError (huart);
 break;
}
}

Не прокатило

Изменено пользователем verlaty
Ссылка на комментарий
Поделиться на другие сайты

отписал в добавку постом выше. Возможно не тот метод

возможно еще надо сделать status_reset после сброса флага

есть макрос очистки флага без функции

UART_CLEAR_OREF

OverRun Error Clear Flag

поставь в код и почитай чего там написано. (у меня либы F3 нет)

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

Нужно делать то, что нужно. А то, что не нужно, делать не нужно. (С) Винни Пух

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

вот это уже хз. не проверял

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

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

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

Нужно делать то, что нужно. А то, что не нужно, делать не нужно. (С) Винни Пух

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

I ran into a similar problem as yours a few months ago on a Cortex M4 (SAM4S). I have a function that gets called at 100 Hz based on a Timer Interrupt.

In the meantime I had a UART configured to interrupt on char reception. The expected data over UART was 64 byte long packets and interrupting on every char caused latency such that my 100 Hz update function was running at about 20 Hz. 100 Hz is relatively slow on this particular 120 MHz processor but interrupting on every char was causing massive delays.

I decided to configure the UART to use PDC (Peripheral DMA controller) and my problems disappeared instantly.

DMA allows the UART to store data in memory WITHOUT interrupting the processor until the buffer is full saving lots of overhead.

In my case, I told PDC to store UART data into an buffer (byte array) and specified the length. When UART via PDC filled the buffer the PDC issued an interrupt.

In PDC ISR:

  1. Give PDC new empty buffer
  2. Restart UART PDC (so can collect data while we do other stuff in isr)
  3. memcpy full buffer into RINGBUFFER
  4. Exit ISR

As swineone recommended above, implement DMA and you'll love life.

короче говоря, убирай ожидание первого байта по прерыванию и читай все по ДМА. Попробовать так

там еще написано следующее

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

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

Нужно делать то, что нужно. А то, что не нужно, делать не нужно. (С) Винни Пух

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

тема изначально назвалась Cubemx + uart_dma. Заметил такую вещь. Один уарт у меня принимает пачки по 8 байт второй по 3. Тот который по 8 практически не зависает, а вот по 3 постоянно. Хотя все реализовано аналогично, на одной плате, на оном камне, но факт на лице.

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

почитал буржуев. В общем оверран возникает тогда, когда не успеваешь прочитать предыдущий байт, а следующий уже начал приниматься (откапитанил). Флаг оверрана может не сбрасываться программно, до тех пор пока байт не будет физически прочитан из буфера (то есть он не затирается, а ждет чтения). Очистка регистра данных может и поможет, а может и нет. Судя по всему не помогает. Или следующий оверран просто перетирает флаг быстрее чем оклимается контроллер.

Выводы.

Надо делать непрерывный прием в некий буфер в памяти. У меня таким буфером была очередь, поэтому видимо все и успевало, хотя принимал я по одному символу и камень был F103. Очевидно надо думать как ускорить чтение или организовывать буфер. Костыли типа сброса флага не помогут.

Возможно на первом канале приоритет прерываний или канала DMA выше, поэтому он и не глючит так.

Печалька

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

Нужно делать то, что нужно. А то, что не нужно, делать не нужно. (С) Винни Пух

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

вот так вот происходила обработка из очереди в операциоке. В принципе обрабатывалось по одному байту. Можно попробовать сделать прием в буфер длинной 1 байт и обрабатывать на лету прямо в колбэке приема. До 0,9 мегабита работает железобетонно на камне F051 и F103 (частотки 48 и 72 МГц соответственно)

void StartUserTask01(void const * argument)
{
char lReceivedValue;
portBASE_TYPE xStatus;
const portTickType xTicksToWait = 1000 / portTICK_RATE_MS;
short int rxindex = 0;
uint8_t ErrorFlag = UART_PACKET_OK;
char rxString[MAXSTRING];

for( ;; )
{
UBaseType_t i = 0;
i = uxQueueMessagesWaiting( myQueue01Handle );
while (i != 0)
{
xStatus = xQueueReceive( myQueue01Handle, &lReceivedValue, xTicksToWait );
 if( xStatus == pdPASS )
 {
 if (lReceivedValue == 8 || lReceivedValue == 127) // If Backspace or del
{
rxindex--;
if (rxindex < 0) rxindex = 0;
}
else if (lReceivedValue == '\n') // If Enter
{
if (ErrorFlag == UART_PACKET_OK)
{
 rxString[rxindex] = '\n';
 rxindex++;
 rxString[rxindex] = 0;

 rxindex = 0;

 command_processor(rxString); // command handler
}
else
{
 //TODO - UART Error handler
 ErrorFlag = UART_PACKET_OK; // reset error state
}
}
else
{
if (lReceivedValue != '\r' && ErrorFlag == UART_PACKET_OK) // Ignore return
{
 rxString[rxindex] = lReceivedValue; // Add that character to the string
 rxindex++;
 if (rxindex >= MAXSTRING) // User typing too much, we can't have commands that big
 {
 ErrorFlag = UART_PACKET_TOO_LONG;
 rxindex = 0;
 rxString[rxindex] = '\000';
 }
}
}
 }
 else
 {
 taskYIELD();
 }
i--;
}
}
}

счас нарою проект с голым уартом на эту тему

вот, делал просто голыш без использования операционки, работал неделями, ни разу не сбоил

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
static short int rxindex = 0;
static uint8_t ErrorFlag = UART_PACKET_OK;
//__HAL_UART_FLUSH_DRREGISTER(&huart1); // Clear the buffer to prevent overrun
if (rxBuffer == 8 || rxBuffer == 127) // If Backspace or del
{
rxindex--;
if (rxindex < 0) rxindex = 0;
}
else if (rxBuffer == '\n') // If Enter
{
if (ErrorFlag == UART_PACKET_OK)
{
rxString[rxindex] = rxBuffer; // Add that character to the string
rxindex++;
rxString[rxindex] = 0;
rxindex = 0;
if (huart->State != HAL_UART_STATE_BUSY_TX_RX) UART_Send (rxString);
}
else
{
if (huart->State != HAL_UART_STATE_BUSY_TX_RX) UART_Send ("ERROR > UART packet too long\n");
ErrorFlag = UART_PACKET_OK; // reset eeror state
}
}
else
{
if (rxBuffer != '\r' && ErrorFlag == UART_PACKET_OK) // Ignore return
{
rxString[rxindex] = rxBuffer; // Add that character to the string
rxindex++;
if (rxindex >= MAXSTRING) // User typing too much, we can't have commands that big
{
ErrorFlag = UART_PACKET_TOO_LONG;
rxindex = 0;
rxString[rxindex] = '\000';
}
}
}
}

могу прям проектами в почту отправить целиком. (все под Keil правда)

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

Нужно делать то, что нужно. А то, что не нужно, делать не нужно. (С) Винни Пух

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

да, именно так. Буфер на один символ. Принимает все подряд до тех пор пока не примет \n. Дальше передает принятое в обработчик строки. Работало 100%

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

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

суть в чем - даже если прерывания не будут поспевать за приемом, то оверрана не будет. Просто потеряется символ и все на этапе обработки. Но до 0,9М такого не происходило. Реальные потери начинаются гдето в районе 1,3...1,5Мб/с. На 3,5 Мб/с теряется примерно каждый 3-й символ

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

Нужно делать то, что нужно. А то, что не нужно, делать не нужно. (С) Винни Пух

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

Запустил UART в режим DMA circular. Слегка подправил свой код для работы в этом режиме, без постоянных запусков HAL_UART_Receive_DMA . Все проблемы снялись, все работает. Отдельное спасибо mail_robot за активную помощь и участие.

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

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

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

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Ответить в этой теме...

×   Вставлено с форматированием.   Восстановить форматирование

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

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

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

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

Загрузка...
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу

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