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

Исключение Hard Fault на Cortex-M3

Дааа, всякого говнокода я конечно повидал, но вот чтобы вот так вот, чисто наугад рандомно копипастить строчки - это чето впервые встречаю 🙂 
И самое смешное, что "аутор" сей малявы упорно не желает ничего понимать. Твердит про какой-то шум. Но флаг Noise Error в его коде вообще никак не задействован. NE выставляется вместе с RXNE, и перед считыванием RDR нужно проверить флаг NE (и FE тоже!), чтобы убедиться в корректности принятого байта. Эти два флага - Noise Error и Framing Error указывают на зашумленность линии и рассинхронизацию битовой скорости принимаемого потока. Именно поэтому, когда вместе с RXNE выставились NE и/или FE, передавать прочитанный из RDR байт дальше в программу нельзя. 

Самое смешное, что проблема то решается очень просто. Но "аутор текста" настолько замусорил его рандомными командами, что увидеть что-то можно только с пятой попытки. Боюсь себе представить, что там за "нацпроект" то, при таком ужасе в тексте (это не код, это просто текст, рандомный текст).

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


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

14 минут назад, EdgeAligned сказал:

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

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

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


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

Ага, иногда в виде бесплатного цирка на такое посмотреть можно, за одним разобрать "вредный пример" из раздела "как нельзя делать".
Вот смотрите, там представлен самый простейший случай коммуникации, судя по скринам состояния регистров CR1, CR2, CR3: базовый UART с включенным передатчиком и приемником, однобайтовая коммуникация без FIFO и DMA, разрешен запрос прерывания только по приему байта (RXNE) и запрещена реакция на переполнение приемника. Всё.
Каким образом должна работать такая конфигурация - при приёме байта выставляется запрос RXNE и вызывается обработчик прерываний USART. То есть, исходя из показанных настроек, должен вестись только прием байтов в однобайтовом режиме.

Но что у автора написано в тексте обработчика прерывания? А там начинается цирковая дичь: безусловная проверка всех подряд флагов, в том числе и самая фатальная ошибка - проверка флага TXE, который всегда, за исключением одного случая, = 1. Следствием этого будет непрерывная передача TX, как я показывал на осциллограмме ранее.
Для решения этой проблемы что делает автор - он просто переносит программную переменную tx_flag = 1 в другое место, под проверку флага завершения передачи TC. По умолчанию после сброса модуля USART этот флаг присутствует, поэтому так же возможен ложный запуск в таких условиях, и это вторая ошибка. Однако, появление TC можно предотвратить, если его предварительно сбросить и ничего не передавать, тогда он больше не будет появляться.
Эта часть кода в блоке if(tx_flag), к сожалению, не показана.

Теперь что касается RXNE.
Автор придумал цирк такого плана:
usart_sr_my = UART5->ISR - то есть, получил независимую копию ISR с флагами. 
Далее, он без проверки флагов читает usart_rdr_my = UART5->RDR. При этом в исходном ISR сбрасывается флаг RXNE. Остальные флаги этим действием не сбрасываются. Однако, перед этим участком присутствует блок со сбросом большинства флагов, которые могли выставиться, в том числе и ключевых для приема - NE, FE, PE. То есть, фактически уже неоткуда взять информацию об ошибках приема.

Далее, несмотря на фактический сброс RXNE при чтении RDR, в независимой копии usart_sr_my, полученной ранее, срабатывает if((usart_sr_my & USART_ISR_RXNE). Дальнейшие действия с принятым байтом в представленном коде не показаны.
И после этого следует еще один блок с двухкратным сбросом всех флагов в ISR, сначала записью 0xFFFF, затем "контрольный выстрел в голову" в виде дополнительного сброса уже сброшенных флагов. Про |= уже не говорю, это мелочи.

Что нужно сделать в этой ситуации. Как в анекдоте - оставить скобки {  }, а между ними вложить новый код обработчика прерывания. В коде: для передачи - проверка флага TXE совместно с битом разрешения запросов TXEIE, при истинном результате - запись в TDR очередного байта;
для приема - проверка флага RXNE, и затем, после проверки отсутствия NE, FE, PE - считывание байта из RDR и складирование его в массив. При выставленных NE и FE - сброс RXNE и, либо запуск автодетектирования скорости, либо сообщение об ошибке приема. При PE - либо продолжить прием, сбросив PE, а считанный байт пометить как поврежденный, либо остановить прием и вывести сообщение о помехах в связи.
Таким образом будут отсечены большинство коммутационных помех и ошибок неверной скорости.
Так же следует реализовать обработку флага Idle для обнаружения начала блока принимаемых данных.
Про реализацию аппаратной поддержки таймингов модбаса тут пока что речь не идет. Автору нужно научиться правильно управляться с базовым функционалом.

Например, вот, работа с обнаружением коммутационных шумов в линии (петля TX-RX) и остановка передачи TX с завершающим сигналом Break (он же Framing Error на приемной стороне):


 

Снимок экрана 2024-08-29 202315.jpg

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


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

3 hours ago, EdgeAligned said:

Ага, иногда в виде бесплатного цирка на такое посмотреть можно, за одним разобрать "вредный пример" из раздела "как нельзя делать".
Вот смотрите, там представлен самый простейший случай коммуникации, судя по скринам состояния регистров CR1, CR2, CR3: базовый UART с включенным передатчиком и приемником, однобайтовая коммуникация без FIFO и DMA, разрешен запрос прерывания только по приему байта (RXNE) и запрещена реакция на переполнение приемника. Всё.
Каким образом должна работать такая конфигурация - при приёме байта выставляется запрос RXNE и вызывается обработчик прерываний USART. То есть, исходя из показанных настроек, должен вестись только прием байтов в однобайтовом режиме.

Но что у автора написано в тексте обработчика прерывания? А там начинается цирковая дичь: безусловная проверка всех подряд флагов, в том числе и самая фатальная ошибка - проверка флага TXE, который всегда, за исключением одного случая, = 1. Следствием этого будет непрерывная передача TX, как я показывал на осциллограмме ранее.
Для решения этой проблемы что делает автор - он просто переносит программную переменную tx_flag = 1 в другое место, под проверку флага завершения передачи TC. По умолчанию после сброса модуля USART этот флаг присутствует, поэтому так же возможен ложный запуск в таких условиях, и это вторая ошибка. Однако, появление TC можно предотвратить, если его предварительно сбросить и ничего не передавать, тогда он больше не будет появляться.
Эта часть кода в блоке if(tx_flag), к сожалению, не показана.

Теперь что касается RXNE.
Автор придумал цирк такого плана:
usart_sr_my = UART5->ISR - то есть, получил независимую копию ISR с флагами. 
Далее, он без проверки флагов читает usart_rdr_my = UART5->RDR. При этом в исходном ISR сбрасывается флаг RXNE. Остальные флаги этим действием не сбрасываются. Однако, перед этим участком присутствует блок со сбросом большинства флагов, которые могли выставиться, в том числе и ключевых для приема - NE, FE, PE. То есть, фактически уже неоткуда взять информацию об ошибках приема.

Далее, несмотря на фактический сброс RXNE при чтении RDR, в независимой копии usart_sr_my, полученной ранее, срабатывает if((usart_sr_my & USART_ISR_RXNE). Дальнейшие действия с принятым байтом в представленном коде не показаны.
И после этого следует еще один блок с двухкратным сбросом всех флагов в ISR, сначала записью 0xFFFF, затем "контрольный выстрел в голову" в виде дополнительного сброса уже сброшенных флагов. Про |= уже не говорю, это мелочи.

Что нужно сделать в этой ситуации. Как в анекдоте - оставить скобки {  }, а между ними вложить новый код обработчика прерывания. В коде: для передачи - проверка флага TXE совместно с битом разрешения запросов TXEIE, при истинном результате - запись в TDR очередного байта;
для приема - проверка флага RXNE, и затем, после проверки отсутствия NE, FE, PE - считывание байта из RDR и складирование его в массив. При выставленных NE и FE - сброс RXNE и, либо запуск автодетектирования скорости, либо сообщение об ошибке приема. При PE - либо продолжить прием, сбросив PE, а считанный байт пометить как поврежденный, либо остановить прием и вывести сообщение о помехах в связи.
Таким образом будут отсечены большинство коммутационных помех и ошибок неверной скорости.
Так же следует реализовать обработку флага Idle для обнаружения начала блока принимаемых данных.
Про реализацию аппаратной поддержки таймингов модбаса тут пока что речь не идет. Автору нужно научиться правильно управляться с базовым функционалом.

Например, вот, работа с обнаружением коммутационных шумов в линии (петля TX-RX) и остановка передачи TX с завершающим сигналом Break (он же Framing Error на приемной стороне):


 

Снимок экрана 2024-08-29 202315.jpg

image.png.46aa3d2e60db38f0eba73ade9b446573.png

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


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

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

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


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

49 минут назад, MrYuran сказал:

и четко огороженный юзер-спейс.

Вы хотели сказать: "чётко огороженная песочница"?

Чтобы карапузы за её пределы не лезли и шишек, по недомыслию, не набили.  :wink:

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


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

Именно. Если карапузу нужны read() и write() или даже printf(), зачем забивать голову разной шелухой.

Я вот тоже не знаю наизусть регистры и флаги STM32. ИЧСХ, знать не хочу. Потому что эти "знания" на хлеб не намажешь.

За 20 лет практики наелся этих регистров до тошноты.

В 28.08.2024 в 19:09, x893 сказал:

А можно взять текст от HAL и ...

ничего там не трогать )

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


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

Думаете, ардуинщики меньше косячат? 🙂 Малограмотный чел может где угодно накосячить. Тем более, что ардуинщики, поскольку не разбираются в железе, когда что-то не работает, они просто меняют скетчи до тех пор, пока не заработает. Доводилось видеть и у них перлы. Цирка там не меньше. 

Тем более, что микроконтроллеры весьма различны по аппаратным реализациям. Вот даже взять рассматриваемый здесь пример - модуль USART имеет аппаратное распознавание таймингов Модбаса, аппаратное распознавание адреса на линии и прием по соответствию адреса (Modbus RTU), аппаратное распознавание символов завершения посылки в Modbus ASCII. Использование этих возможностей позволит сэкономить вычислительные мощности ЦП ядра. А если использовать базовый ардуино-скетч, да еще недайбох с программной реализацией UART через ногодрыг - это ж будет трэш дикий. Некоторое время назад нередкостью был программный I2C на ногодрыге.

Знания - как раз на хлеб и намажешь. Правда, боюсь вот что не в нашей стране. У нас всё через вот такой цирк, как был показан выше на 6-й странице этой темы. Тот мессаг довольно хорошо иллюстрирует состояние дел в российской инженерии разработок. 

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

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


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

Если разработчик Вася (или Петя) - то да. А вокруг одни манагеры.

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

К жестяным "свистоперделкам" "с перламутровыми пуговицами" у меня отношение ещё хуже.

Это чисто маркетинговые фишки, не имеющие отношения к "экономии вычислительной мощности ядра". Особенно если это ядро M7

Я и не знал о таком изврате, как "аппаратное распознавание таймингов Модбаса" и далее по тексту. Видимо, фантазия креативных директоров ST совсем иссякла )

По-моему, куда логичнее было положить верифицированный стек в раздел Middleware куба

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


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

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

Говорят, MPU здорово помогает. Надо раскурить.

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


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

Ну нет, почему же, например, детектирование адреса (модбас ведь адресный) - вещь хорошая. До тех пор, пока в линии не появился адрес целевого устройства с этим микроконтроллером, UART ничего не принимает, прерывания и ДМА не дергает, ЦП не отвлекает. Более того, МК может находиться в режиме пониженного потребления, а выходить из него именно по совпадению адреса. Это касается RTU-вида модбаса. 

А программная часть в протоколе не настолько уж и сложна. Опять же, включаем в себе ардуинщика и просто ищем готовый скетч. Если не работает - ищем другой. Ведь кто-то же их пишет как то же.

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


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

1 hour ago, MrYuran said:

Я и не знал о таком изврате, как "аппаратное распознавание таймингов Модбаса" и далее по тексту. Видимо, фантазия креативных директоров ST совсем иссякла )

Это начинается с времён STM32F0.

2 hours ago, EdgeAligned said:

аппаратное распознавание символов завершения посылки в Modbus ASCII

Это относится вообще к любому протоколу, имеющему ограничение посылки специальными символами, например, DCON или Мицубиси.

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


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

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

все валилось в конструкторах классов

Искать следует в статически глобально создаваемых объектах. Их конструкторы запускаются в __libc_init_array.

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

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


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

4 minutes ago, EdgeAligned said:

Искать следует в статически создаваемых объектах. Их конструкторы запускаются в __libc_init_array.

Любители С++ плакали, кололись, но продолжали  строчить на С++

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


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

А что делать, я сам до недавнего времени писал на базовом Си. Но время не стоит на месте, пришлось продвигаться. Поначалу тоже плевался и кололся, несколько раз отказывался, но всё равно продолжал. Шас более-менее освоился. Конечно, плеваться продолжаю, поскольку язык весьма корявый, многословный. В том плане, что вместо совершенствования ядра языка, его просто залатывают поверх различными заплатками и нашлепками. Удручающее зрелище. Такое впечатление, что в комитете по языку сидят такие же "цыркачи", как и автор той цирковой портяны с 6-й страницы.

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


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

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

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

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

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

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

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

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

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