Jump to content

    

STM32СubeMX и подобные

При приеме вычитывается статусный регистр в течении таймаута, если пришел RXNE, то читаем RDR

 

Какого еще таймаута ? Вы что рассказывали мне все время не за работу HAL в прерываниях, а какую-то софт реализацию "hello world" на uarte ?

 

Конкретно я писал код на stm32f207 еще в 2009. Такой корявой обработки с флагами и нелинейного кода как там я даже в интернет хламе примеров не обнаруживал никогда. Вместо того чтобы просто когда пришел байт данных прочитать регистр USART_SR (не ISR !!!), а потом прочитать USART_DR, просто без каких либо условий и ветвлений - сделать два простых действия.

1. Там сразу по условиям внутренних своих флагов программа упетляла куда-то и не сбросивши прерывание по NOISE - вышло из обработчика.

2. Причём я ни NOISE ни FRAME реакции не заказывал для обработки в прерываниях.

3. Кроме того что оно их установило - оно их еще и не отработало.

4. Если бы там просто сделано было два шага по чтению регистров - БЕЗУСЛОВНО как положено для нормальной работы периферии - то я бы не возмущался и не предостерегал - что писал это человек далекого континента.

 

5. Один из крупный недостатков - это откат прогресса системы прерываний который появился в Кортексах - откачен корявостью и ленностью архитектуры - до уровня обработки прерываний ядра 7TDMI. Там индусы понасоздавали куча программных флагов вместо того чтобы использовать отдельные прерывания для каждой периферии - у них один общий обработчик для 6 уартов например, который потом разруливает програмно что кому надо.

6. Использование HAL - это необходимость использования вложенных прерываний, так как обработка очень медленная. Писать килобайты в контексте прерываний - это еще один ярлык.

 

 

Если не можете, то с вашими выводами всё понятно.

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

Edited by картошка

Share this post


Link to post
Share on other sites
Вы не поняли...

Тогда точно не понял: при чем здесь SPL? SPL — та же жестко зажатая в рамках "помигать диодиком при помощи таймера с DMA". А чуть захочешь что-то пошире сделать, как упираешься в ее тормознутость.

Вообще непонятно, зачем функционал для работы с железом выносили в отдельные функции вместо макросов или true inline. Ну и все эти ассерты и еще толпа ненужностей, в результате чего ничего по-человечески таким образом не сделать.

Share this post


Link to post
Share on other sites
Тогда точно не понял: при чем здесь SPL? SPL — та же жестко зажатая в рамках "помигать диодиком при помощи таймера с DMA". А чуть захочешь что-то пошире сделать, как упираешься в ее тормознутость.

Вообще непонятно, зачем функционал для работы с железом выносили в отдельные функции вместо макросов или true inline. Ну и все эти ассерты и еще толпа ненужностей, в результате чего ничего по-человечески таким образом не сделать.

На счет тормознутости вы загнули...

Уж HAL в этом сравнении не превзойден! Вершина тормознутости.... и прожорливости.

У вас превратное представление о SPL. В палитре разработчика любой регистр и любой бит.... В любой момент.

Share this post


Link to post
Share on other sites
Вместо того чтобы просто когда пришел байт данных прочитать регистр USART_SR (не ISR !!!), а потом прочитать USART_DR, просто без каких либо условий и ветвлений - сделать два простых действия.
в stm32l051 статус регистра уарта это USART_ISR (Interrupt and status register), для stm32f207 USART_SR, суть дела от этого не меняется.

смотрим прием уарта в хале на stm32f207

 

HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)

{

uint16_t* tmp;

uint32_t tmp1 = 0;

 

tmp1 = huart->State;

if((tmp1 == HAL_UART_STATE_READY) || (tmp1 == HAL_UART_STATE_BUSY_TX))

{

if((pData == NULL ) || (Size == 0))

{

return HAL_ERROR;

}

 

/* Process Locked */

__HAL_LOCK(huart);

 

huart->ErrorCode = HAL_UART_ERROR_NONE;

/* Check if a non-blocking transmit process is ongoing or not */

if(huart->State == HAL_UART_STATE_BUSY_TX)

{

huart->State = HAL_UART_STATE_BUSY_TX_RX;

}

else

{

huart->State = HAL_UART_STATE_BUSY_RX;

}

 

huart->RxXferSize = Size;

huart->RxXferCount = Size;

 

/* Check the remain data to be received */

while(huart->RxXferCount > 0)

{

huart->RxXferCount--;

if(huart->Init.WordLength == UART_WORDLENGTH_9B)

{

if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, Timeout) != HAL_OK)

{

return HAL_TIMEOUT;

}

tmp = (uint16_t*) pData ;

if(huart->Init.Parity == UART_PARITY_NONE)

{

*tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x01FF);

pData +=2;

}

else

{

*tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x00FF);

pData +=1;

}

 

}

else

{

if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, Timeout) != HAL_OK)

{

return HAL_TIMEOUT;

}

if(huart->Init.Parity == UART_PARITY_NONE)

{

*pData++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);

}

else

{

*pData++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x007F);

}

 

}

}

 

/* Check if a non-blocking transmit process is ongoing or not */

if(huart->State == HAL_UART_STATE_BUSY_TX_RX)

{

huart->State = HAL_UART_STATE_BUSY_TX;

}

else

{

huart->State = HAL_UART_STATE_READY;

}

/* Process Unlocked */

__HAL_UNLOCK(huart);

 

return HAL_OK;

}

else

{

return HAL_BUSY;

}

}

Какого еще таймаута ?

в аргументах таймаут. Красным вычитка статусного регистра (USART_SR/ISR) в течении таймаута, ждем флаг RXNE, если пришел, то вычитываем DR. Как вы и хотели.

 

еще в 2009
вы наверно не про хал говорите, его тогда не было.

 

 

ps в приеме по прерываниям в прерывании первой строчкой вычитка статус регистра. :laughing:

Share this post


Link to post
Share on other sites
У вас превратное представление о SPL. В палитре разработчика любой регистр и любой бит.... В любой момент.

Я начинал с этой дряни. Потом перешел на opencm3 — небо и земля!!! А после того, как меня достало то, что разработчики opencm3 периодически меняют API, да и документация там никакая — постоянно приходится в коде библиотеки ковыряться, я всю эту гадость решил больше не использовать, только "голый" CMSIS и сниппеты.

Share this post


Link to post
Share on other sites

Сказал же - что в прерывании и не раз ! Тут же чистый SOFTWARE "Hello India !".

 

ПРОБЛЕМЫ с HALL были у меня В ОБРАБОТЧИКЕ ПРЕРЫВАНИЙ а не в бредовом с архитектурной точки зрения софтваре коде. Не думал что програмисты вообще такое используют - это же детский сад.

Мда, когда-то лет так 25 назад я мог еще "додуматься" встраивать Delay-ки в программу или код с непрогнозируемыми или динамическими задержками . А ну да - RTOS нам поможет ;) - создаст за нас архитектуру что не надо будет вставлять __HAL_LOCK(huart); , он ВСЁ может :rolleyes:. Это бредовый код, НЕ АРХИТЕКТУРНЫЙ. Ожидать прием данных с тормозами - это ЖЕСТЬ.

 

Все делается по прерываниям и желательно с DMA настроенным, если конечно не лампочками моргать. А по поводу СРАНИ в реализации прерываний - это правда, виснет из-за неправильной реализации обработки.

Edited by картошка

Share this post


Link to post
Share on other sites
Я начинал с этой дряни. Потом перешел на opencm3 — небо и земля!!! А после того, как меня достало то, что разработчики opencm3 периодически меняют API, да и документация там никакая — постоянно приходится в коде библиотеки ковыряться, я всю эту гадость решил больше не использовать, только "голый" CMSIS и сниппеты.

:bb-offtopic: Уклонились от темы...

 

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

Share this post


Link to post
Share on other sites
Сказал же - что в прерывании и не раз
в прерывании в хале первой строчкой вычитка статус регистра. Тоже уже говорил. Да черт с ним.... с этой граблей... хал с 2014, вы в 2009 году что-то там у кого-то непонятное нашли....

 

Мда, когда-то лет так 25 назад я мог еще "додуматься" встраивать Delay-ки в программу
Так когда один поток, почему бы нет? Я пользую в простых проектах. Всякие read()/write() во всяких POSIX/winApi работают как в блокирующем так и не в блокирующем режиме. В хале (на 2018 год, а не в неких либах от 2009 года) есть и блокирующий режим, и IT, и DMA, я просто привел пример первой попавшейся функции приема из хала. А так-то их, этих функций и режимов приема вагон и тележка

 

    (#) Blocking mode APIs are:
        (++) HAL_UART_Transmit()
        (++) HAL_UART_Receive() 
        
    (#) Non Blocking mode APIs with Interrupt are:
        (++) HAL_UART_Transmit_IT()
        (++) HAL_UART_Receive_IT()
        (++) HAL_UART_IRQHandler()

    (#) Non Blocking mode functions with DMA are:
        (++) HAL_UART_Transmit_DMA()
        (++) HAL_UART_Receive_DMA()

    (#) A set of Transfer Complete Callbacks are provided in non blocking mode:
        (++) HAL_UART_TxCpltCallback()
        (++) HAL_UART_RxCpltCallback()
        (++) HAL_UART_ErrorCallback()

Даже с колбаками есть.

 

Share this post


Link to post
Share on other sites

С 2009 на SPL писал. На грабли хала напоролся где-то 2011-2012, не помню.

 

Сходу выбрал что мне больше подходит малыми кровями вот этот режим работы:

(#) A set of Transfer Complete Callbacks are provided in non blocking mode:

(++) HAL_UART_TxCpltCallback()

(++) HAL_UART_RxCpltCallback()

(++) HAL_UART_ErrorCallback()

Когда отлавливался тот глюк о котором я говорил. Никакой callBack по Error HAL_UART_ErrorCallback() - не вызывался вообще. Всё висло намертво, путём выхода из прерывания по uart и моментального туда захода, так как эфиопы не смогли его сбросить. Дебагер работал, отловил что не отработали сначала FE а потом NOISE попадалось в таком состоянии висячем.

Позже напарник отловил (через пару месяцев) с I2C траблы. В общем больше на нём не пишем.

Когда я фиксил код по UARTу то выкинул более 90 процентов того хлама который там был, ну еще и опасения были по неправильной кастрации кала, так как он со своими статусами постоянно манипулирует. ;), но обошлось . Такие дни никому не желаю ;), особенно когда что-то по срокам сдачи. Делали тогда устройства для диагностики автомобильной "периферии", по линии K-LINE. Там протокол основан на синхронизации пакета по фреймэрору, далее всё как обычно. На SPL без проблем можно было быстренько на лету перепрограмировать режими UARTA, хоть после каждого байта. А из-за тормознутости HALA пришлось использовать аппаратный режим детектировани K-LINE старта, хорошо что там он был на STMке. Не во всех уартах есть примочки, НО ВСЕМИ уартами можно прекрасно работать и без них, если не использовать "мегабайты" в прерывании ;).

 

По приему K-LINE пробуждения, надо было замерить интервалы старта, паузы и вымерять длительность бита на линии который присутствовал в синхробайте 0x55, чтобы не потерять ни одного байта в посылке, запрограмировать нужную скорость и включить аппаратно прием в конце синхробайта - на его стоповом бите. И всё это прекрасно работало на SPL, кое-что конечно переделал на CMSIS. На хале - нет, такое не сделаешь.

Edited by картошка

Share this post


Link to post
Share on other sites
По приему K-LINE пробуждения, надо было замерить интервалы старта, .....
Это всё ваша программа.... что там не получилось c халом... хал грамоздкий какой-то библиотекой..... Позже напарник отловил какие-то с I2C траблы....

 

Меня интересует имя файла и номер строчки в хале, где есть бага.

 

Сходу выбрал что мне больше подходит малыми кровями вот этот режим работы:

A set of Transfer Complete Callbacks are provided in non blocking mode:

Ну это всего лишь колбаки. А приём, судя по вашим постам, вы вели в этом режиме работы

Non Blocking mode APIs with Interrupt are:

Когда отлавливался тот глюк о котором я говорил. Никакой callBack по Error HAL_UART_ErrorCallback() - не вызывался вообще.

странно всё это....

 

void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
  uint32_t tmp1 = 0, tmp2 = 0;
  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_FE);
  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR);
  /* UART frame error interrupt occurred -------------------------------------*/
  if((tmp1 != RESET) && (tmp2 != RESET))
  { 
    __HAL_UART_CLEAR_FEFLAG(huart);
    
    huart->ErrorCode |= HAL_UART_ERROR_FE;
  }
  if(huart->ErrorCode != HAL_UART_ERROR_NONE)
  {
    /* Set the UART state ready to be able to start again the process */
    huart->State = HAL_UART_STATE_READY;
    
    HAL_UART_ErrorCallback(huart);
  }
}

Вот их обработчик. При приеме по прерываниям вы вызоваете HAL_UART_Receive_IT(), в ней разрешается прерывание обработка FE

/* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
    __HAL_UART_ENABLE_IT(huart, UART_IT_ERR);

Флаг FE не генерирует прерывание. Генерирует RXNE. В обработчике по приему проверяется FE и сбрасывается. Если был FE, то вызывается HAL_UART_ErrorCallback(huart).

 

Постоянно попадать в обработчик по несброшенному FE вы не могли, т.к. FE не генерирует прерывание. Может чего-то недонастроили/недопоняли с халом и была такая какая-то грабля? Я бы пошагал дебагером и выяснил бы.... или в хале есть баг конкретный, или же я где-то ошибся.

 

 

ps думаю, что далее бессмысленно ворошить.... у вас что-то не получилось на хале, какие-то прерывания от FE..... Вы сочли, что это ошибка в хале и он вам не понравился.

Share this post


Link to post
Share on other sites

Вы что на STM работаете, склалось такое впечатление ;).

 

ГДЕ В ФУНКЦИИ void HAL_UART_IRQHandler(UART_HandleTypeDef *huart) -- Выполняется ЖЕЛЕЗНОЕ ПРАВИЛО СБРОСА БЛОКИРОВКИ UARTА в случае ошибки ????????????????????? 0-0 . Хдееееее ?! Код похожий очень на тот что я правил, только меньше раз в 10. НО ошибки похоже те же. Тыкать не буду - тут просто банальная практика выявляет очень быстро эти огрехи. Здесь нет строки где есть ошибка - ТУТ строк НЕТ и Правильной последовательности сброса. Должен быть линейный код который без ВЕТВЛЕНИЙ делающий две базовые вещи о которых говорит мануал по UARTу.

Просто понять что чтение регистра флагов не сбрасывает некоторые ошибки - понять нельзя - нужно ЧИТАТЬ .

Я устал спорить на эту тему, если Вы считаете что там нету ошибок приводящих к фатальным зависаниям системы - ваше право ! Они там есть, потому что код хала ДЕТСКИЙ и технически неграмотный.

 

Просто сделайте генератор помех на линию UART - и результат не заставит себя ждать.

Edited by картошка

Share this post


Link to post
Share on other sites
Вы что на STM работаете, склалось такое впечатление ;).

 

ГДЕ В ФУНКЦИИ void HAL_UART_IRQHandler(UART_HandleTypeDef *huart) -- Выполняется ЖЕЛЕЗНОЕ ПРАВИЛО СБРОСА БЛОКИРОВКИ UARTА в случае ошибки ????????????????????? 0-0 . Хдееееее ?!

К каком месте хала и/или даташита говориться, что уарт блокируется при возникновении ошибки? Почему нужно сбрасывать БЛОКИРОВКУ уарта и что такое БЛОКИРОВКА УАРТА?

 

Есть флаг FE, он говорит что был Frame error. Если вы вошли в перывание по приему (а не по FE), то в HAL_UART_IRQHandler(UART_HandleTypeDef *huart) будет ЖЕЛЕЗНЫЙ сброс флага FE. Не будет ни каких сбросов БЛОКИРОВКИ УАРТА.

Где??? Я уже приводил где, вот ещё раз приведу

 

tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_FE); //чтение статусного регистра USART_SR, не сброс, просто чтение

tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR);

/* UART frame error interrupt occurred -------------------------------------*/

if((tmp1 != RESET) && (tmp2 != RESET))

{

__HAL_UART_CLEAR_FEFLAG(huart);//Сброс FE флага

 

huart->ErrorCode |= HAL_UART_ERROR_FE;

}

 

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

 

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

 

ТУТ строк НЕТ и Правильной последовательности сброса.

две базовые вещи о которых говорит мануал по UARTу.
Вместо постоянных переобуваний, переформулировок и каких-то мифических катастрофах в халехпустых разговоров про траблы колег в I2C, вам достаточно сделать ОДИН копипаст из даташита, с двумя базовыми вещами, которые вам говорит даташит и копипаст баги в хале и можно без хала сказать "В хале вот именно этих базовых вещей НЕТ". Какие именно базовые вещи в даташите по УАРТу отсутствуют в хале?

Пока всё, что вы требуете от хала - оно там есть.. Все сбросы, все последовательности, все вычитки регистров и заходы в HAL_UART_ErrorCallback().

 

 

Share this post


Link to post
Share on other sites

STM32F207

 

Ten interrupt sources with flags:

– CTS changes

– LIN break detection

– Transmit data register empty

– Transmission complete

– Receive data register full

– Idle line received

– Overrun error

– Framing error == EIE

– Noise error == EIE

– Parity error == EIE

 

Это по поводу источников прерываний. Они есть - просто в API кала их нет, но он их включает, ну и путается с правильностью аппаратных сбросов.

 

When the framing error is detected:

• The FE bit is set by hardware

• The invalid data is transferred from the Shift register to the USART_DR register.

• No interrupt is generated in case of single byte communication. However this bit rises

at the same time as the RXNE bit which itself generates an interrupt. In case of

multibuffer communication an interrupt will be issued if the EIE bit is set in the

USART_CR3 register. - при использовании API - этого прерывания я не заказывал, ну и естественно неадекватную реакцию на него.

 

 

In case of multibuffer communication if any error occurs during the transaction the error flag

will be asserted after the current byte. An interrupt will be generated if the interrupt enable

flag is set. For framing error, overrun error and noise flag which are asserted with RXNE in

case of single byte reception, there will be separate error flag interrupt enable bit (EIE bit in

the USART_CR3 register), which if set will issue an interrupt after the current byte with

either of these errors.

При обработке EIE - который был без разрешения включен, произошла "петляющая ошибка". Чтение регистра статуса БЫЛО, а другого важного действия ВТОРОГО ШАГА - не было. Вот и всё собственно.

The FE bit is reset by a USART_SR register read operation followed by a USART_DR

register read operation.

EIE: Error interrupt enable - при разрешенном прерывании оно срабатывает от 3 источников FE, NOISE, ORE.

Сброс каждой причины хоть индивидуален - но одинаков ;) - просто очень тупо был пропущен. Шо для технарей читающих мануалы просто - не приемлемо.

 

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

 

Edited by картошка

Share this post


Link to post
Share on other sites
Искать корявости или выкорчёвывание ненужных действий - занимает раз в 5 больше времени чем написание правильного кода с нуля.

Не следил за вашим спором, ибо в разных семействах STM32 УАРТы реализованы слегка по-разному, и тот HAL, что я применял, проблем не имел.

 

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

Для меня, например, "искать корявости или выкорчёвывать ненужные действия - занимает раз в 5 МЕНЬШЕ времени чем написание правильного кода с нуля" :)

 

Как говориться, "ломать - не строить". Если, конечно понимаешь, что ломать и как нужно строить...

Share this post


Link to post
Share on other sites
ну наконец-то предметный разговор, а не спор.

срезюмирую даташит

In case of multibuffer communication.... for framing error ..... error flag interrupt enable bit ..... will issue an interrupt.

(In case of multibuffer communication) == (USART_CR3.DMAR is set), т.е. FE даст прерывание только при приеме по DME.

 

есть картинка, в которой прерывание через И объединено с флагами (FE && EIE && DMAR)....

 

Всётаки я с первого поста нашего спора диалог я спрашивал и ещё раз спрашиваю, как вы вели прием при такой баге?

HAL_UART_Receive()

HAL_UART_Receive_IT()

HAL_UART_Receive_DMA()?

 

в HAL_UART_Receive_IT() разрешается обработка флага FE в прерывании, но не разрешается прерывание по FE, ибо DMAR не выставляется. Почему при приеме по прерываниям (по Receive_IT() ) у вас выставлен DMAR в "1"?

в HAL_UART_Receive_DMA() устанавливается DMAR, но ... тут да, может быть косяк, судя по коду хала... в HAL_UART_Receive_DMA() выставляется DMAR, но не выставляется обработка ошибок по FE, но нужно ещё проверить есть ли флаг EIE. Я с UARTом по дме не работал, ни чего не скажу. В очередном проекте, если подниму UART по DME, обращу на это внимание.

 

Для меня, например, "искать корявости или выкорчёвывать ненужные действия - занимает раз в 5 МЕНЬШЕ времени чем написание правильного кода с нуля"
согласен. Особенно если писать код по приему через ДМА.

 

ps

При обработке EIE - который был без разрешения включен
а как это так EIE без разрешения включился? Тут вообще весь код хала с усартом не причем, если EIE без разрешения включается.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this