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

Перезапись данных при передаче данных через UART DMA

Здравствуйте, уважаемые форумчане

возникла необходимость отправлять через USART отладочные сообщения с использованием DMA под контроллер STM32F103(на других контроллерах туже проблему наблюдал, например, на STM32L496)

Настройку и конфигурацию осуществлял через STMCube MX, считаю, что все верно сделано:

image.thumb.png.0d71542af0fb01e19c47aaf6829ef762.png

image.thumb.png.b70410efb63879b20abbb53029ae2f0f.png

image.thumb.png.b4005bfcd8c38540df52ed60c1f81c5f.png

затем переназначил функцию _write(), чтобы сообщения вылетали через USART1:

int _write (int fd, char *ptr, int len){
   HAL_UART_Transmit(&huart1, (uint8_t*) ptr, len,HAL_MAX_DELAY);
   return len;
}

int _read (int fd, char *ptr, int len){
    *ptr = 0x00; // Flush the character buffer
    HAL_UART_Receive(&huart1, (uint8_t*) ptr, 1, HAL_MAX_DELAY);
    return 1;
}

вот таким образом все корректно работает, т.е. все символы выводятся на консоль без перетираний и искажений, выполняя вот этот код:

  printf("\033c\r\n"); fflush(stdout);
  printf("|||||||||||||||||||||||||||||||||||||||\r\n"); fflush(stdout);
  printf("Init MCU_PWR Complete\r\n"); fflush(stdout);

  printf("Size of I2C_REG bitfield = %d)\r\n", sizeof(I2C_Work.Regs.bitfield));
  for(i = 0; i < I2C_BUF_SIZE; i++) printf("I2C_BUF[%d] = 0x%x\r\n", i, I2C_Work.Regs.I2C_BUF[i]);

  printf("Version Program STM32: %d.%d.%d (crc = 0x%x)", I2C_Work.Regs.bitfield.Version.bitfield.Major,
  I2C_Work.Regs.bitfield.Version.bitfield.Minor, I2C_Work.Regs.bitfield.Version.bitfield.Local, I2C_Work.Regs.bitfield.Version.bitfield.Crc);
  printf(" (0x%x)\r\n", I2C_Work.Regs.bitfield.Version.full_word);

вывод на консоли:

Quote


|||||||||||||||||||||||||||||||||||||||
Init MCU_PWR Complete
Size of I2C_REG bitfield = 20)
I2C_BUF[0] = 0x1
I2C_BUF[1] = 0x2
I2C_BUF[2] = 0x3
I2C_BUF[3] = 0x4
I2C_BUF[4] = 0x5
I2C_BUF[5] = 0x6
I2C_BUF[6] = 0x7
I2C_BUF[7] = 0x8
I2C_BUF[8] = 0x9
I2C_BUF[9] = 0xa
I2C_BUF[10] = 0xb
I2C_BUF[11] = 0xc
I2C_BUF[12] = 0xd
I2C_BUF[13] = 0xe
I2C_BUF[14] = 0xf
I2C_BUF[15] = 0x10
I2C_BUF[16] = 0x11
I2C_BUF[17] = 0x12
I2C_BUF[18] = 0x13
I2C_BUF[19] = 0x14
Version Program STM32: 4.3.2 (crc = 0x1) (0x4030201)
Calculate CRC Program STM32 = 0x8070605
Start ADC measure
Start Timer3 on 1 ms
Start Listen on I2C2(ADR = 0x60)
IMX_RESET_ON_START: Delay timer on 13000 ms
 

 

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

int _write (int fd, char *ptr, int len){
   while(huart1.gState != HAL_UART_STATE_READY);
   HAL_UART_Transmit_DMA(&huart1, (uint8_t*) ptr, len);
   return len;
}

вот вывод c DMA или по прерываниям:

Quote

||||it MCU_PWR Complete
||||||||||||||||
Inze of I2C_REG bitfielSiC_BUF[0] = 0x1
tfield = 20)
I2C_BUF[1] = 0x2
I2C_BUF[2] = 0x3
I2C_BUF[3] = 0x4
I2C_BUF[4] = 0x5
I2C_BUF[5] = 0x6
I2C_BUF[6] = 0x7
I2C_BUF[7] = 0x8
I2C_BUF[8] = 0x9
I2C_BUF[9] = 0xa
I2C_BUF[11] = 0xc
I2C_BUF[12] = 0xd
I2C_BUF[13] = 0xe
I2C_BUF[14] = 0xf
I2C_BUF[16] = 0x11
I2C_BUF[17] = 0x12
I2C_BUF[18] = 0x13
I2C_BUF[19] = 0x14
I2rsion Program STM3Velculate CRC Program STM32 = 0x8070605
(0x4030201)
Caart ADC measure
am STM32 = 0x8070605
Start Timer3 on 1 mStart Listen on I2C2(AStX_RESET_ON_START: Delay timer onIMX_R                                                                                                                                                             ESET_ON_START: Delay timer on 13000 ms
 

я пробовал дожидаться и состояния, когда и UART и DMA_TX_UART в состоянии READY, пробовал управлять флагом, который сигнализирует об окончании передачи, флаг выставлялся в функции void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart), но также не помогло

 

я думаю, проблема в каком-нибудь пустяке, но пока его не смог найти...

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

Спасибо, буду рад любой помощи

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


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

1 час назад, xxxmatrixxx сказал:

олностью ушли на стороне UART и мне можно заполнять буфер?

Вызывайте прерывание по завершениею передачи каналом ПДП. Это будет 100%-я гарантия.

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


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

3 minutes ago, MrBearManul said:

Вызывайте прерывание по завершениею передачи каналом ПДП. Это будет 100%-я гарантия.

я делал вот так:

volatile static uint8_t Uart_Tx_Cmpl = 1;
int _write (int fd, char *ptr, int len){
   while(Uart_Tx_Cmpl == 0);
   Uart_Tx_Cmpl = 0;
   HAL_UART_Transmit_DMA(&huart1, (uint8_t*) ptr, len);
   return len;
}

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
	Uart_Tx_Cmpl = 1;
}

 

не помогло...

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


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

1 час назад, xxxmatrixxx сказал:

я делал вот так:

Видимо, что такое HAL_UART_TxCpltCallback(), зачем оно и где у вас вызывается - предлагаете угадывать читателям?

Тогда уж хоть приз объявите угадавшему.  :dance4:

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


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

1 час назад, xxxmatrixxx сказал:

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)

Оно вызывается когда? Это какой-то коллбэк для прерывния последовательного порта? Если так, то неправильно. Прерывания от последовательно порта вызываются по завершению передачи одного (возможно нескольких байт для каких-то модификацийбайта, либо при загрузки этого байта из буфера в сдвиговый регистр. Но в любом случае не по завершению передачи N байт. Прерывание должно быть от ПДП по окончанию транзакции. И тогда всё будет работать ок.

1 минуту назад, jcxz сказал:

Видимо, что такое HAL_UART_TxCpltCallback(), зачем оно и где у вас вызывается - предлагаете угадывать читателям?

Блин... боюсь это произносить, чтобы в меня тапками не начали кидать, но я терпеть не могу куб...

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


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

45 minutes ago, MrBearManul said:

Оно вызывается когда? Это какой-то коллбэк для прерывния последовательного порта? Если так, то неправильно. Прерывания от последовательно порта вызываются по завершению передачи одного (возможно нескольких байт для каких-то модификацийбайта, либо при загрузки этого байта из буфера в сдвиговый регистр. Но в любом случае не по завершению передачи N байт. Прерывание должно быть от ПДП по окончанию транзакции. И тогда всё будет работать ок.

Блин... боюсь это произносить, чтобы в меня тапками не начали кидать, но я терпеть не могу куб...

STMCube все верно отрабатывает, прерывание возникает по окончании передачи всей пачки, а не одного байта (функция HAL_UART_TxCpltCallback)

модифицировал код следующим образом и все заработало:

volatile static uint8_t Uart_Tx_Cmpl = 1;
int _write (int fd, char *ptr, int len){
   Uart_Tx_Cmpl = 0;
   HAL_UART_Transmit_DMA(&huart1, (uint8_t*) ptr, len);
   while(Uart_Tx_Cmpl == 0);
   return len;
}

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
	Uart_Tx_Cmpl = 1;
}

но я при этом не добиваюсь того, что хотел, а именно освободить на время передачи по UART процессор от ожидания окончания транзакции по UART, как раз именно while(Uart_Tx_Cmpl == 0); когда стоял в самом начале функции int _write() позволял задерживать выполнение, если транзакция еще не завершена(например, идут 2 или 3 printf подряд), а когда этого не требуется, то просто пропускал...

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

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


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

Решил проблему следующим образом:

#define uart_printf(...) { while(huart1.gState != HAL_UART_STATE_READY); printf(__VA_ARGS__); }

int _write (int fd, char *ptr, int len){
   HAL_UART_Transmit_DMA(&huart1, (uint8_t*) ptr, len);
   return len;
}

вместо printf использую у себя в основной программе uart_printf, причина была в подмене данных printf, т.к. данные передавались в функцию int _write (int fd, char *ptr, int len) по указателю

 

всем спасибо за помощь!!!

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

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


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

28 минут назад, xxxmatrixxx сказал:

STMCube все верно отрабатывает

Печально. Не куб должен отрабатывать, а вы. Ну да ладно.

28 минут назад, xxxmatrixxx сказал:

а именно освободить на время передачи по UART процессор от ожидания окончания транзакции по UART

Используйте такую штуку как ОСРВ и всё получите.

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


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

Почему использование библиотек HAL считается постыдным?  В то же время использование ОСРВ  это норм?  ОСРВ это такой же уровень абстракций.  

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


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

54 минуты назад, Ozone сказал:

Почему использование библиотек HAL считается постыдным?  В то же время использование ОСРВ  это норм?  ОСРВ это такой же уровень абстракций.  

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

ОСРВ тоже нужно использовать не где попало и абы как...

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


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

1 час назад, Ozone сказал:

Почему использование библиотек HAL считается постыдным?

Не является. Я и сам их использовал в своё время немного. Вот только от необходимости понимания "физики процесса" это не освобождает. Особенно тогда, когда понимаешь, что либа содержит ошибку. А исправить её ты не можешь. Некоторые же люди надеются на "хал" как на нечто безошибочно работающее, но, главным образом, освобождающее от необходимости изучать тонны документации на сам процессор, микроархитектуру и периферию микроконтроллера. Это и приводит к тому, что задаётся масса вопросов, которые демонстрируют отсутствия понимания и желания разобраться самостоятельно. Я же, направившись с ошибками в "хале" и прочих подобных либах, понял, что проще писать драйвера периферии самостоятельно. В любом случае с документацией разбираться нужно. Зато есть плюсики:

1. Сможешь оперативно править ошибки.

2. Без проблем добавишь необходимые функции.

3. Ты растёшь профессионально и можешь оставаться конкурентноспособным, если это важно)

4. Ты можешь очень умно отвечать на форуме и своим коллегам)))))))

1 час назад, Ozone сказал:

В то же время использование ОСРВ  это норм?

ОСРВ и HAL не взаимоисключают другу друга. И вообще на друг друга не влияют. Если вы знаете, для чего используется ОСРВ и что она содержит, вы бы поняли, почему я посоветовал её автору топки. Тем не менее, я могу это сделать и без ОС . И делал. Но с ОСРВ гораздо удобнее!

1 час назад, Ozone сказал:

ОСРВ это такой же уровень абстракций.  

Нет. Это, прежде всего, инструмент, который позволят вам использовать многозадачность. Например, вытесняющую. А также несколько средств межпроцессного взаимодействия. Можете и без неё обходиться. Тут уж кто как считает нужным. И потом. Не каждую ОСРВ я советую на форуме: например, FreeRTOS и scmRTOS известны очень давно. С начала 2000-х годов. За это время они "вылизаны" до безобразной чистоты) И их код надёжен. Разработчики scmRTOS находятся на этом форуме, и, при необходимости, могут оперативно ответить на вопросы. Те, кто ковырялся в потрохах FreeRTOS и дорабатывал её, тоже здесь обитают) Так что...) Плюс эти системы идут даром, что немаловажно в некоторых случаях. В остальных я бы посоветовал ucOS/2.

 

15 минут назад, mantech сказал:

отсюда непонятки и глупые вопросы...

Люто, дико и громко плюсую!

 

15 минут назад, mantech сказал:

ОСРВ тоже нужно использовать не где попало и абы как...

+1.

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


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

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

я всегда буду его использовать, т.к. точка входа в программирование STM32, благодаря ему, у меня заняло около 30 мин, я начал практически сразу писать функционал, при этом:

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

2. изменение конфигурации и состава периферии при неизменном функциональном коде проходит за 1 мин

3. очень удобно, когда работаешь сразу с несколькими контроллерам STM32 разных семейств(у меня, например, STM32F103, STM32F107, STM32F407,STM32L496)

 

согласен, что надо понимать, что и откуда берется, но лезть туда надо:

1. когда не работает задуманое

2. работает, но с косяками, либо слишком медленно

к такому же подходу я стремлюсь при разработке IP Core на ПЛИС, чтобы была универсальность при написании драйвера под ОС для работы с модулями, реализованных на ПЛИС

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

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


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

3 часа назад, xxxmatrixxx сказал:

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

я всегда буду его использовать, т.к. точка входа в программирование STM32, благодаря ему, у меня заняло около 30 мин, я начал практически сразу писать функционал, при этом:

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

Вот потому и торчите который день на этом входе, в который "за 30 мин" вошли. Не умея решить даже такой элементарный вопрос. И так и будете торчать на входе, спотыкаясь на простейших вещах, если не будете изучать периферию.

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

3 часа назад, xxxmatrixxx сказал:

2. изменение конфигурации и состава периферии при неизменном функциональном коде проходит за 1 мин

Ну-ну... Оно и заметно как это "за 1 мин" у вас уже много дней продолжается.  :biggrin:

 

PS: Учите матчать! Без этого в программировании МК делать нечего.

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


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

9 часов назад, xxxmatrixxx сказал:

благодаря ему, у меня заняло около 30 мин, я начал практически сразу писать функционал

Да, да, мы тут сидим месяцами изучаем внутрянку МК, как с ней работать, а тут нате))))))))  

Еще раз - если вы за 30 минут установили прогу, скомпилировали демо-программку, которая умеет загружаться, мигать диодом и чего-то там выдавать в уарт или эзернет - это просто демо программа, и ни о каких ваших знаниях она не говорит, я уверен, что и после этого, МК для вас - это такой уменьшенный компьютер, который можно запрограммировать за полчаса, на чем угодно, типа визуалбейсика или какого-нить яваскрипта, или например, хочу с ДМА чтоб работало - так ерунда, просто ищем галочку "включить ДМА" и не паримся))), но это совсем не так...

Ну а если уж так хочется не думать о периферии, и программировать на более высоком и универсальном уровне - то надо выбирать какой-нить фреймворк или переходить на линукс, тут без вариантов, ИМХО.

5 часов назад, jcxz сказал:

Учите матчать! Без этого в программировании МК делать нечего.

+1

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

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


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

15 часов назад, xxxmatrixxx сказал:

у меня заняло около 30 мин

Это иллюзия, как опиумный дым.

15 часов назад, xxxmatrixxx сказал:

но лезть туда надо:

Самое интересное, что если залезть туда раньше, то, скорее всего, у вас ситуация "не работает как надо" встретится с вероятностью 10% вместо 80%. Из личного опыта и опыта коллег. Впрочем, вы взрослый человек и переубеждать вас нет смысла)))

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


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

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

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

Гость
Ответить в этой теме...

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

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

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

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

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

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