Top.Mail.Ru
Уведомления
Очистить все

[Решено] UART прерывание, по событию IDLE, не срабатывает.

Страница 1 / 2
 stm
(@stm)
Level 4

В регистре CR1 активирую бит IDLEIE.
Это активация прерываний по событию отправки пакета данных.

Потом отправляю через терминал СОМ порта символы.
Вижу в Keil как флаг IDLE в регистре SR активируется.
Но прерывание не срабатывает, почему?
Прерывания активированы.

Есть 9 UART Callback функций, ни одна из них не срабатывает.
HAL_UART_TxCpltCallback
HAL_UART_TxHalfCpltCallback
HAL_UART_RxCpltCallback
HAL_UART_RxHalfCpltCallback
HAL_UART_ErrorCallback
HAL_UART_AbortCpltCallback
HAL_UART_AbortTransmitCpltCallback
HAL_UART_AbortReceiveCpltCallback
HAL_UARTEx_RxEventCallback
-----------------------------------------------------------------
HAL_UARTEx_RxEventCallback начинает срабатывать только тогда, когда в код добавляю это HAL_UARTEx_ReceiveToIdle_IT(&huart4, data, 5);

Какие настройки нужны для того, чтоб отрабатывал каллбек при активации флага IDLE в регистре SR?

Одна из этих настроек это активация бита IDLEIE в регистре CR1. Но видимо этого недостаточно.
Мне казалось только эта настройка нужна.

п.с. Скорость передачи по УАРТ правильная.

pr

 

Цитата
Создатель темы Размещено : 14.06.2023 02:29
Aveal
(@aveal)
Top level Admin

Посмотри внутри HAL_UARTEx_ReceiveToIdle_IT(), какие биты выставляются, раз при ее вызове callback срабатывает.

ОтветитьЦитата
Размещено : 14.06.2023 10:22
 stm
(@stm)
Level 4

Здесь UART_Start_Receive_IT активируется бит разрешающий прерывания по RXNE.
Здесь

__HAL_UART_CLEAR_IDLEFLAG(huart);
ATOMIC_SET_BIT(huart->Instance->CR1, USART_CR1_IDLEIE);

очищается и ставится бит разрешающий прерывания по IDLE.

Больше ничего я там не нашёл.
Чётность у меня отключена, прерывания по ней соответственно тоже.
--------------------------------
Может дело не в HAL_UARTEx_ReceiveToIdle_IT функции, а в том месте, откуда HAL_UARTEx_RxEventCallback вызывается.
Функция HAL_UARTEx_RxEventCallback вызывается из HAL_UART_IRQHandler(&huart3);

if ((huart->ReceptionType == HAL_UART_RECEPTION_TOIDLE)
     && ((isrflags & USART_SR_IDLE) != 0U)
     && ((cr1its & USART_SR_IDLE) != 0U))
{
    __HAL_UART_CLEAR_IDLEFLAG(huart);.
}

В переводе на CMSIS здесь написано это:

if (USART3->CR1&USART_CR1_IDLEIE && USART3->SR&USART_SR_IDLE)
{
    USART3->CR1&=~(USART_CR1_IDLEIE);
}

Кароче идёт какое то хитрое включение выключение IDLEIE бита в обоих функциях.
Надо разбираться. Такую же ситуацию в коде я создать не смог.

ОтветитьЦитата
Создатель темы Размещено : 14.06.2023 14:23
 stm
(@stm)
Level 4

Нет.
Думаю я ошибся насчёт __HAL_UART_CLEAR_IDLEFLAG(huart);

-------------------------------------------------------------------
An interrupt is generated if the IDLEIE=1 in the USART_CR1 register. It is cleared by a software sequence (an read to the USART_SR register followed by a read to the USART_DR register).

Кароче надо разобраться как очищать бит IDLE в SR регистре.
It is cleared by a software sequence (an read to the USART_SR register followed by a read to the USART_DR register).

ОтветитьЦитата
Создатель темы Размещено : 14.06.2023 14:30
 stm
(@stm)
Level 4

Да, чтоб очистить IDLE бит, надо сначала прочитать SR регистр, а потом DR регистр.

uint32_t dr=0;
uint32_t sr=0;
if (USART3->CR1&USART_CR1_IDLEIE && USART3->SR&USART_SR_IDLE)
{
    sr=USART3->SR;
    dr=USART3->DR;
}

Но проблему это не решило. Каллбек не вызывается.

ОтветитьЦитата
Создатель темы Размещено : 14.06.2023 14:40
Aveal
(@aveal)
Top level Admin

@stm а можешь проект выложить? Я посмотрю.

ОтветитьЦитата
Размещено : 16.06.2023 10:04
 stm
(@stm)
Level 4

Только если у Вас есть очень много свободного времени.
Я для себя нашёл объяснение, не подтверждённое, но мне сейчас достаточно.

Думаю есть какая то переменная, булевая или какая то ещё, в функции HAL_UARTEx_ReceiveToIdle_IT, которая обнуляется при вызове HAL_UARTEx_RxEventCallback.
И для того чтоб вызвать HAL_UARTEx_RxEventCallback снова, надо опять вызвать функцию HAL_UARTEx_ReceiveToIdle_IT.
Потому что дело точно не только во флагах и настройке битов.
Настройка функции HAL_UARTEx_ReceiveToIdle_IT производится конечно по флагам и битам, но внутри этой функции тоже что то меняется, что влияет на вызов Каллбека.

Проект несложный:

 
int main(void)
{
HAL_UARTEx_ReceiveToIdle_IT(&huart3,RxData,5); 
// Эта функция ничего не принимает, она служит лишь для настройки UART, флагов и как мне кажется переменной о которой выше писал(или что то подобное).                                                                    
}
 
//Это Каллбек функция, которая вызывается после того, как я введу что нибудь в СОМ порт терминале.
//Вызывается Каллбек только из за того, что выше в main был настроен UART, функцией HAL_UARTEx_ReceiveToIdle_IT.
 
 void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
HAL_UARTEx_ReceiveToIdle_IT(&huart3,RxData,5);
//Внутри Каллбек функции находится ReceiveToIdle функция, которая снова настраивает UART, после того как все флаги были сброшены в результате отработки Каллбек и отправки данных через СОМ порт.
//Получается рекурсия.
//Если сейчас отправить данные через СОМ порт, то Каллбек снова отработает, потому что UART опять настроен функцией HAL_UARTEx_ReceiveToIdle_IT.
//Эта функция уже принимает отправленное через СОМ порт.
}
ОтветитьЦитата
Создатель темы Размещено : 18.06.2023 03:32
 stm
(@stm)
Level 4

Дело именно в отработке функции HAL_UARTEx_ReceiveToIdle_IT.
Функция HAL_UARTEx_ReceiveToIdle_IT отработала, Каллбек вызовется, функция HAL_UARTEx_ReceiveToIdle_IT не отработала, Каллбек не вызовется.

ОтветитьЦитата
Создатель темы Размещено : 18.06.2023 03:40
Aveal
(@aveal)
Top level Admin

@stm Ну я и говорю, суть в коде внутри HAL_UARTEx_ReceiveToIdle_IT(). Я очень бегло пробежался, чтобы колбэк HAL_UARTEx_RxEventCallback() в принципе имел хоть какие-то шансы на выполнение, в huart->ReceptionType должно быть HAL_UART_RECEPTION_TOIDLE. Вот самый первый и очевидный маркер, почему вызов может не происходить.

 

 

ОтветитьЦитата
Размещено : 19.06.2023 16:20
 stm
(@stm)
Level 4

UART Регистры настраивает структура USART_TypeDef *Instance;
находящаяся в UART_HandleTypeDef;
Что настраивают остальные переменные, находящися в UART_HandleTypeDef ?
Вот они:
UART_InitTypeDef Init;
const uint8_t *pTxBuffPtr;
uint16_t TxXferSize;
__IO uint16_t TxXferCount;
uint8_t *pRxBuffPtr;
uint16_t RxXferSize;
__IO uint16_t RxXferCount;
__IO HAL_UART_RxTypeTypeDef ReceptionType;
DMA_HandleTypeDef *hdmatx;
DMA_HandleTypeDef *hdmarx;
HAL_LockTypeDef Lock;
__IO HAL_UART_StateTypeDef gState;
__IO HAL_UART_StateTypeDef RxState;
__IO uint32_t ErrorCode;

Или между периферийными устройствами есть место, где просто можно хранить информацию?
То есть разве есть регистры по этим адресам?

ОтветитьЦитата
Создатель темы Размещено : 21.06.2023 00:37
 stm
(@stm)
Level 4

Например регистры USART3 начинаются с адреса 0x4000 4800
А заканчиваются адресом 0x4000 481C.
Так вот то что выше написано, сохраняется после этого адреса 0x4000 481C

ОтветитьЦитата
Создатель темы Размещено : 21.06.2023 06:22
 stm
(@stm)
Level 4

huart->ReceptionType
находится в этом же списке. Поэтому спрашиваю.

ОтветитьЦитата
Создатель темы Размещено : 21.06.2023 12:55
Aveal
(@aveal)
Top level Admin

@stm это просто поля структуры, то есть переменные ОЗУ по своей сути.

ОтветитьЦитата
Размещено : 21.06.2023 18:45
 stm
(@stm)
Level 4

Эти поля структиры хранятся в пределах адресов, предназначенных для USART3
0x4000 4800 - 0x4000 4BFF
Между этих адресов есть только 7 регистров (SR;DR;BRR;CR1;CR2;CR3;GTPR;)?
А остальное место это просто пространство, где можно хранить любую информацию?

ОтветитьЦитата
Создатель темы Размещено : 22.06.2023 05:05
(@eduard)
Level 5 Moderator

@stm Это адресное пространство отведено под периферию. Там нет ОЗУ. Даже, если в адресации есть разрыв, там нет ничего, что могло бы хранить информацию.

 

ОтветитьЦитата
Размещено : 22.06.2023 06:23
Страница 1 / 2
Поделиться: