Ух ты, мой коммент был упомянут. Я на прошлой неделе разбирался с блютуз протоколом BMS, и поскольку не знал размерность пакетов, пришлось разобраться в IDLE. Все делал также. Я не стал использовать RxCpltCallback, просто увеличив размер буффера.
Пройдет примерно пол года с момента выхода этого видео и функционал библиотеки hal(Release Notes for STM32F7xx HAL Drivers v1.2.9/ 12-February-2021) обзаведется функцией HAL_UARTEx_ReceiveToIdle и коллбеком HAL_UARTEx_RxEventCallback . С помощью этого всего ,микроконтроллер будет принимать весь пакет ,ни больше, ни меньше ,плюс подскажет о количестве принятых байт .Если указанный буффер будет меньше принятого пакета, то функция начнет перезаписывать буффер сначала . Функционал базируется как раз на проверке таймингов между байтами(если задержка минимальна-то пакет еще продолжается, если задержка больше- пакет закончен ,грубо говоря) ,быть может инженеры подсмотрели принципы реализации именно тут, как знать..)
Ещё раз модифицировал код. Теперь в переменной Recieved - количество принятых байт. Изначально мне не было нужно, но подумал - вдруг кому пригодится. Перед входом в главный цикл (или перед входом в бесконечный цикл задачи FreeRTOS): __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); //Включаем прерывание IDLE HAL_UART_Receive_DMA(&huart1, (uint8_t*)Request, Rx_BuffSize); //Заряжаем DMA (или HAL_UART_Receive_IT, если без DMA) Обработчик прерываний USART: void USART1_IRQHandler(void) { /* USER CODE BEGIN USART1_IRQn 0 */ /* USER CODE END USART1_IRQn 0 */ HAL_UART_IRQHandler(&huart1); /* USER CODE BEGIN USART1_IRQn 1 */ if (huart1.Instance->SR & USART_SR_IDLE_Msk) //Проверяем что прерывание произошло по IDLE { __HAL_UART_CLEAR_IDLEFLAG(&huart1); //Очищаем флаг IDLE HAL_UART_DMAStop(&huart1); //Останавливаем DMA Recived = Rx_BuffSize - DMA1_Channel5->CNDTR; //В переменной Recived - количество принятых байт HAL_UART_Receive_DMA(&huart1, (uint8_t*)Request, Rx_BuffSize); //Перезаряжаем DMA } /* USER CODE END USART1_IRQn 1 */ } Обработку пакета запроса, формирование пакета ответа и отправку ответа можно было тоже сделать здесь, но я делаю это в главном цикле по флагу Recived чтобы обработка прерывания происходила как можно быстрей. В принципе остановку DMA и перезапуск DMA тоже можно было бы вынести в главный цикл. Но мы же урок делаем ;-)
Олег, когда вы включаете для USART разрешение на обработку глобальных прерываний, Cube создает в файле stm32f1xx_it.c процедуру void USART1_IRQHandler(void), в которой происходит вызов процедуры HAL_UART_IRQHandler(&huart1), в которой Вы и делали правку, вызывающую вашу HAL_UART_IDLE_Callback. Правильнее обработку прерывания делать именно в USART1_IRQHandler и тогда не возникнет проблемы удаления кода кубом при следующих изменениях в проекте.
@@Solderingironspb У меня сделан прием через DMA выглядит вот так void USART1_IRQHandler(void) { /* USER CODE BEGIN USART1_IRQn 0 */ /* USER CODE END USART1_IRQn 0 */ HAL_UART_IRQHandler(&huart1); /* USER CODE BEGIN USART1_IRQn 1 */ if(huart1.Instance->SR & 0x10) //Проверяем что прерывание произошло по IDLE { __HAL_UART_DISABLE_IT(&huart1, UART_IT_IDLE); //Отключаем прерывания __HAL_UART_CLEAR_IDLEFLAG(&huart1); //Очищаем флаг IDLE HAL_UART_DMAStop(&huart1); //Останавливаем DMA __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); //Включаем прерывание HAL_UART_Receive_DMA(&huart1, (uint8_t*)Request, Rx_BuffSize); //Перезаряжаем DMA Recived = 1; //По этому флагу у меня обрабатывается пакет запроса в главном цикле } /* USER CODE END USART1_IRQn 1 */ }
@@Solderingironspb Кстати - разрешаю сделать ролик об этом с использованием моего кода. Сам в своё время долго искал как это сделать. Таких роликов на ютюбе нет.
@@Solderingironspb И я об этом. Собственно - очень тебе благодарен. Благодаря тебе пошел в нужном направлении и сделал. Весь проект прислать не могу - у меня там целое большое изделие. Но ролик такой, считаю, надо сделать. Готов ответить на все вопросы, подключиться и согласовать до публикации.
Еще поэкспериментировал. Оказывается отключать прерывания перед сбросом флага IDLE , а затем, включать нет необходимости. Конечный код прекрасно работает и выглядит вот так: Перед входом в главный цикл (или перед входом в бесконечный цикл задачи FreeRTOS): __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); //Включаем прерывание IDLE HAL_UART_Receive_DMA(&huart1, (uint8_t*)Request, Rx_BuffSize); //Заряжаем DMA (или HAL_UART_Receive_IT, если без DMA) Обработчик прерываний USART: void USART1_IRQHandler(void) { /* USER CODE BEGIN USART1_IRQn 0 */ /* USER CODE END USART1_IRQn 0 */ HAL_UART_IRQHandler(&huart1); /* USER CODE BEGIN USART1_IRQn 1 */ if (huart1.Instance->SR & USART_SR_IDLE_Msk) //Проверяем что прерывание произошло по IDLE { __HAL_UART_CLEAR_IDLEFLAG(&huart1); //Очищаем флаг IDLE HAL_UART_DMAStop(&huart1); //Останавливаем DMA (или HAL_UART_Abort_IT если без DMA) HAL_UART_Receive_DMA(&huart1, (uint8_t*)Request, Rx_BuffSize); //Перезаряжаем DMA
(или HAL_UART_Receive_IT, если без DMA) Recived = 1; //По этому флагу у меня обрабатывается пакет запроса в главном цикле (или в задаче FreeRTOS). } /* USER CODE END USART1_IRQn 1 */ } Обработку пакета запроса, формирование пакета ответа и отправку ответа можно было тоже сделать здесь, но я делаю это в главном цикле по флагу Recived чтобы обработка прерывания происходила как можно быстрей. В принципе остановку DMA и перезапуск DMA тоже можно было бы вынести в главный цикл. Но мы же урок делаем ;-)
я ничего не понял. idle это режим простоя. каким образом добавили новый флаг прерываний в стм? или это обработка флага который там есть? а почему его не было? Почему длина принимаемого буфера равна 20 - принятые байты? это ж если 5 байтов придет то буфер будет 15 а зачем нам 15 если у нас 5 байт пришло и нам нужен буфер 5
Здравствуйте. И по spi и по i2c планируются уроки. Только для начала нужно эти темы самому освоить. Сейчас с али едут датчики BME280(на них буду пробовать осваивать i2c). Тему с spi начну наверное с каких-нибудь 7сегментных индикаторов с микросхемой от maxim. Все будет)
Здравствуйте) Данные функции появились уже после того, как я выложил данное видео. Раньше их в HAL не было. Даже человек тут в комментариях писал: "Пройдет примерно пол года с момента выхода этого видео и функционал библиотеки hal(Release Notes for STM32F7xx HAL Drivers v1.2.9/ 12-February-2021) обзаведется функцией HAL_UARTEx_ReceiveToIdle и коллбеком HAL_UARTEx_RxEventCallback ."
Ух ты, мой коммент был упомянут. Я на прошлой неделе разбирался с блютуз протоколом BMS, и поскольку не знал размерность пакетов, пришлось разобраться в IDLE. Все делал также. Я не стал использовать RxCpltCallback, просто увеличив размер буффера.
Пройдет примерно пол года с момента выхода этого видео и функционал библиотеки hal(Release Notes for STM32F7xx HAL Drivers v1.2.9/ 12-February-2021) обзаведется функцией HAL_UARTEx_ReceiveToIdle и коллбеком HAL_UARTEx_RxEventCallback .
С помощью этого всего ,микроконтроллер будет принимать весь пакет ,ни больше, ни меньше ,плюс подскажет о количестве принятых байт .Если указанный буффер будет меньше принятого пакета, то функция начнет перезаписывать буффер сначала .
Функционал базируется как раз на проверке таймингов между байтами(если задержка минимальна-то пакет еще продолжается, если задержка больше- пакет закончен ,грубо говоря) ,быть может инженеры подсмотрели принципы реализации именно тут, как знать..)
Подскажите, пожалуйста, это уже произошло?
Ещё раз модифицировал код. Теперь в переменной Recieved - количество принятых байт. Изначально мне не было нужно, но подумал - вдруг кому пригодится.
Перед входом в главный цикл (или перед входом в бесконечный цикл задачи FreeRTOS):
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); //Включаем прерывание IDLE
HAL_UART_Receive_DMA(&huart1, (uint8_t*)Request, Rx_BuffSize); //Заряжаем DMA
(или HAL_UART_Receive_IT, если без DMA)
Обработчик прерываний USART:
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
if (huart1.Instance->SR & USART_SR_IDLE_Msk) //Проверяем что прерывание произошло по IDLE
{
__HAL_UART_CLEAR_IDLEFLAG(&huart1); //Очищаем флаг IDLE
HAL_UART_DMAStop(&huart1); //Останавливаем DMA
Recived = Rx_BuffSize - DMA1_Channel5->CNDTR; //В переменной Recived - количество принятых байт
HAL_UART_Receive_DMA(&huart1, (uint8_t*)Request, Rx_BuffSize); //Перезаряжаем DMA
}
/* USER CODE END USART1_IRQn 1 */
}
Обработку пакета запроса, формирование пакета ответа и отправку ответа можно было тоже сделать здесь, но я делаю это в главном цикле по флагу Recived чтобы обработка прерывания происходила как можно быстрей. В принципе остановку DMA и перезапуск DMA тоже можно было бы вынести в главный цикл. Но мы же урок делаем ;-)
Олег, когда вы включаете для USART разрешение на обработку глобальных прерываний, Cube создает в файле stm32f1xx_it.c процедуру void USART1_IRQHandler(void), в которой происходит вызов процедуры HAL_UART_IRQHandler(&huart1), в которой Вы и делали правку, вызывающую вашу HAL_UART_IDLE_Callback. Правильнее обработку прерывания делать именно в USART1_IRQHandler и тогда не возникнет проблемы удаления кода кубом при следующих изменениях в проекте.
Хм...спасибо, попробую)
@@Solderingironspb У меня сделан прием через DMA выглядит вот так
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
if(huart1.Instance->SR & 0x10) //Проверяем что прерывание произошло по IDLE
{
__HAL_UART_DISABLE_IT(&huart1, UART_IT_IDLE); //Отключаем прерывания
__HAL_UART_CLEAR_IDLEFLAG(&huart1); //Очищаем флаг IDLE
HAL_UART_DMAStop(&huart1); //Останавливаем DMA
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); //Включаем прерывание
HAL_UART_Receive_DMA(&huart1, (uint8_t*)Request, Rx_BuffSize); //Перезаряжаем DMA
Recived = 1; //По этому флагу у меня обрабатывается пакет запроса
в главном цикле
}
/* USER CODE END USART1_IRQn 1 */
}
@@Solderingironspb Кстати - разрешаю сделать ролик об этом с использованием моего кода. Сам в своё время долго искал как это сделать. Таких роликов на ютюбе нет.
Такой информации не то, что на ютубе нет, ее и в сети-то фиг найдешь...
@@Solderingironspb И я об этом. Собственно - очень тебе благодарен. Благодаря тебе пошел в нужном направлении и сделал. Весь проект прислать не могу - у меня там целое большое изделие. Но ролик такой, считаю, надо сделать. Готов ответить на все вопросы, подключиться и согласовать до публикации.
Еще поэкспериментировал. Оказывается отключать прерывания перед сбросом флага IDLE , а затем, включать нет необходимости. Конечный код прекрасно работает и выглядит вот так:
Перед входом в главный цикл (или перед входом в бесконечный цикл задачи FreeRTOS):
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); //Включаем прерывание IDLE
HAL_UART_Receive_DMA(&huart1, (uint8_t*)Request, Rx_BuffSize); //Заряжаем DMA
(или HAL_UART_Receive_IT, если без DMA)
Обработчик прерываний USART:
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
if (huart1.Instance->SR & USART_SR_IDLE_Msk) //Проверяем что прерывание произошло по IDLE
{
__HAL_UART_CLEAR_IDLEFLAG(&huart1); //Очищаем флаг IDLE
HAL_UART_DMAStop(&huart1); //Останавливаем DMA
(или HAL_UART_Abort_IT если без DMA)
HAL_UART_Receive_DMA(&huart1, (uint8_t*)Request, Rx_BuffSize); //Перезаряжаем DMA
(или HAL_UART_Receive_IT, если без DMA)
Recived = 1; //По этому флагу у меня обрабатывается пакет запроса
в главном цикле (или в задаче FreeRTOS).
}
/* USER CODE END USART1_IRQn 1 */
}
Обработку пакета запроса, формирование пакета ответа и отправку ответа можно было тоже сделать здесь, но я делаю это в главном цикле по флагу Recived чтобы обработка прерывания происходила как можно быстрей. В принципе остановку DMA и перезапуск DMA тоже можно было бы вынести в главный цикл. Но мы же урок делаем ;-)
я ничего не понял. idle это режим простоя. каким образом добавили новый флаг прерываний в стм? или это обработка флага который там есть? а почему его не было?
Почему длина принимаемого буфера равна 20 - принятые байты? это ж если 5 байтов придет то буфер будет 15 а зачем нам 15 если у нас 5 байт пришло и нам нужен буфер 5
Здравствуйте, скажите пожалуйста, урок по SPI планируется? И если да, то скоро ли?
Здравствуйте. И по spi и по i2c планируются уроки. Только для начала нужно эти темы самому освоить. Сейчас с али едут датчики BME280(на них буду пробовать осваивать i2c). Тему с spi начну наверное с каких-нибудь 7сегментных индикаторов с микросхемой от maxim. Все будет)
@@SolderingironspbПонял, благодарю. Ещё интересует тема встроенных часов реального времени, надеюсь по ним тоже в планах
и по ним, и по работе с энкодером, и по замеру времени в микросекундах. Тем много. Все освоим, надеюсь)
Другой, боле простой пример прием данных не зная их размер: ruclips.net/video/mXT3Hjae64s/видео.html
Здравствуйте) Данные функции появились уже после того, как я выложил данное видео. Раньше их в HAL не было. Даже человек тут в комментариях писал: "Пройдет примерно пол года с момента выхода этого видео и функционал библиотеки hal(Release Notes for STM32F7xx HAL Drivers v1.2.9/ 12-February-2021) обзаведется функцией HAL_UARTEx_ReceiveToIdle и коллбеком HAL_UARTEx_RxEventCallback ."