![](https://electronix.ru/forum/uploads/set_resources_23/84c1e40ea0e759e3f1505eb1788ddf3c_pattern.png)
![](https://electronix.ru/forum/uploads/set_resources_23/84c1e40ea0e759e3f1505eb1788ddf3c_default_photo.png)
jcxz
Свой-
Постов
13 619 -
Зарегистрирован
-
Посещение
-
Победитель дней
38
Весь контент jcxz
-
"Периферийные регистры" объявлены с volatile? Если нет, то компилятор тут явно не при чём...
-
Плавный переход C -> C++ под МК
jcxz ответил Arlleex тема в Программирование
Знаете такую песню: "Не стоит прогибаться под изменчивый мир, пусть лучше мир прогнётся под нас!..." ? Так может действительно - не стоит прогибаться? -
Плавный переход C -> C++ под МК
jcxz ответил Arlleex тема в Программирование
.....а потом ещё окажется, что нужно графики в реальном времени качать и несколько каналов осц. на ним на лету строить. И чтобы маленький буфер в девайсе не успел переполниться. Даже при втыкании флешки в соседний разъём. Человек вроде про некое своё устройство пишет. Которое он же (или коллеги) разрабатывает. Значит деды могут спать спокойно. Вы ведь не храните свои исходники на перфокартах? А почему? Ведь деды с них начинали... -
Плавный переход C -> C++ под МК
jcxz ответил Arlleex тема в Программирование
Да уж... человек совсем зелёный.... -
Плавный переход C -> C++ под МК
jcxz ответил Arlleex тема в Программирование
Лучше для кого? Вас? Меня? Васи Пупкина из форума? Мира во всём мире? Для каждого "лучше" будет своё. Для меня, например, проще - на VS C++ или Python QT. У других будут свои предпочтения. PS: И если уже говорить про лучше, то это точно не Modbus. Лучше не-Modbus. Что-ж все начинающие так от него прутся-то?? -
Видимо предполагается, что девайс будет часто виснуть. ЗЫ: Очень неудачное расположение этой кнопки. Почти 100% юзер будет частенько промахиваться, желая нажать соседние кнпки, и цеплять кнопку RESET. Хотя - может в серийных девайсах она будет помечена как "неустанавливаемая"?
-
электроника Помогите решить две задачи, пожалуйста.
jcxz ответил Lera1382 тема в Решение задач
Не бойтесь, девушки в технические специальности идут совсем не для того, чтобы потом по ним работать. У них совсем иные цели. Главное - чтобы борщ вкусный варила! А уж с килоомами - муж разберётся. -
Умощнение выхода ОУ
jcxz ответил koluna тема в Схемотехника
Не плавно очевидно значит - дискретно. Да, переменные резисторы есть разные. И дело тут не в характеристике (линейной или логарифмической). А в том, что резисторы бывают проволочные и тогда, при переходе ползунка на другой виток, будет скачок сопротивления. Такова конструкционная особенность проволочных переменных резисторов. -
Адрес точки вызова SVC указан: "PC:XXXXXXX". Т.е. - это адрес, по которому находится команда SVC (для программных trap()). А для вторичных ловушек (порождённых HF, MPU, ...) это значение, которое было в PC в момент fault-a (не адрес fault-а!).
-
Ну если вам нравится текстом - кто ж вам мешает? А я буду делать как удобнее мне и пользователям моих устройств.
-
Не совсем. Если trap генерируется программный (например: в результате проверки каких-то переменных в программе обнаружено их недопустимое состояние), то делается вызов trap() (это не макрос и не функция в обычном виде, это возбуждение прерывания SVC, оформленное в виде функции (IAR умеет такое)). Внутри ISR SVC защёлкивается в ОЗУ дамп = id_trap+аргументы+регистры+стек, потом делается реинит всей периферии и CPU с активацией только нужной для trap-режима. МК можно рестартовать или не рестартовать. Главное - отключить все работающие DMA и перевести все интерфейсы работающие с внешней периферией в дефолтное выключенное состояние (выключить питание моторов, отключить Ethernet, USB, CAN и т.п.). Если trap не программный, а вход в ловушку идёт из ISR HF или ISR MPU или ISR шинных ошибок или ошибок чётности памяти (и т.п.), которые сами являются по факту событиями ошибки, то симулируется как будто была получена SVC (повышение приоритета прерывания до максимума и т.д.), и содержимое регистров и стека берётся таким, каким оно было до входа в этот ISR (HF, MPU, ...) Чтобы причина trap указывала на причину, вызвавшую исходный ISR, а не на код внутри ISR. Также для HF декодируется причина fault-а (по соответствующим регистрам), и эта инфа передаётся как номер и аргументы trap(). Для таких ловушек у меня есть целый класс номеров: #define TRAP_EXC_HARD 0x100 //исключение Hard Fault (неуточнённое) #define TRAP_EXC_HARD_VECTTBL 0x101 //ошибка при попытке считать содержимое таблицы векторов прерываний #define TRAP_EXC_HARD_FORCED 0x102 //произошла эскалациЯ прерываниЯ до HardFault (исходный fault неизвестен) #define TRAP_EXC_MPU 0x110 //MEMORY MANAGER FAULT (неуточнённое) #define TRAP_EXC_MPU_IERR 0x111 //MM FAULT: нарушение прав доступа к коду #define TRAP_EXC_MPU_DERR 0x112 //MM FAULT: нарушение прав доступа к данным #define TRAP_EXC_MPU_MUSTKE 0x113 //MM FAULT: при выходе из обработчика прерываниЯ возникло порождённое прерывание MemFault #define TRAP_EXC_MPU_MSTKE 0x114 //MM FAULT: при входе в обработчик прерываниЯ возникло порождённое прерывание MemFault #define TRAP_EXC_MPU_LSPE 0x115 //MM FAULT: при отложенном сохранении состоЯниЯ FPU возникла ошибка #define TRAP_EXC_BUS 0x120 //BUS FAULT (неуточнённое) #define TRAP_EXC_BUS_IBUS 0x121 //BUS FAULT: ошибка при попытке выборки инструкции #define TRAP_EXC_BUS_PRECISE 0x122 //BUS FAULT: точнаЯ ошибка при обращении к данным #define TRAP_EXC_BUS_IMPRECISE 0x123 //BUS FAULT: неточнаЯ ошибка при обращении к данным #define TRAP_EXC_BUS_USTK 0x124 //BUS FAULT: при попытке выхода из обработчика прерываниЯ #define TRAP_EXC_BUS_STK 0x125 //BUS FAULT: при попытке входа в обработчик прерываниЯ #define TRAP_EXC_BUS_LSPE 0x126 //BUS FAULT: при отложенном сохранении состоЯниЯ FPU #define TRAP_EXC_USAGE 0x130 //USAGE FAULT (неуточнённое) #define TRAP_EXC_USAGE_DIV0 0x131 //USAGE FAULT: попытка делениЯ на 0 #define TRAP_EXC_USAGE_UNALIGN 0x132 //USAGE FAULT: попытка невыровненного доступа к памЯти #define TRAP_EXC_USAGE_NOCP 0x133 //USAGE FAULT: попытка доступа к отсутствующему или отключенному сопроцессору #define TRAP_EXC_USAGE_INVPC 0x134 //USAGE FAULT: ошибочное значение в EXC_RETURN #define TRAP_EXC_USAGE_INVSTAT 0x135 //USAGE FAULT: попытка выполнениЯ инструкции при неверном значении бита T или полЯ IT регистра EPSR #define TRAP_EXC_USAGE_UNDEF 0x136 //USAGE FAULT: попытка выполнить неизвестную или привилегированную инструкцию у некоторых ещё есть аргументы. Вообще типичное содержимое trap.h из текущего проекта: А зачем его воспроизводить? Адрес есть, значит можно встать на этот адрес и проанализировать, что там не так. А дальше действовать по обстоятельствам.
-
Я вроде сразу в исходном посте ещё писал: Номер ловушки + набор аргументов (определяемый номером ловушки) как раз это и есть. Войду в режим ловушки. Аналог синего окна смерти винды. И функционал тот же - защёлкнуться в данном состоянии чтобы дать возможность пользователю найти причину. Ну т.е. - сделаете примерно то же самое, но только хуже (так как без предварительного реинита программы)? А почему тогда критикуете мой способ? Это не повисание. Это режим ловушки. Повиснуть - это значит молча и без какой-либо индикации войти в непонятное состояние устройства. Которое невозможно определить по внешним признакам. Вот это и есть повисание. А режим ловушки штатный и известный пользователям (на время отладки). Даёт возможность надёжно обнаружить ошибку (а не замести её под ковёр, перегрузившись) и дать возможность программисту устранить её. В вашем может ничего не говорил, а я по этому дампу неоднократно находил причину. Так как можно увидеть адрес, увидеть содержимое регистров. Этого чаще всего уже достаточно для нахождения причины. Не всегда конечно, но в большинстве случаев. Если следовать вашей логике, то непонятно зачем в отладчиках выводят содержимое регистров? или памяти, стека? Ведь там тоже - половина - мусор. Чтобы понять где мусор, а где полезные данные - на то у программиста есть голова. Вы бы исходный вопрос темы прочитали, что-ли. Где там про ваш цинк что-то написано?? Я предложил свой способ для решения вопроса ТС. Если вы с ним не согласны - предложите свой. Но к чему тут проблемы цинка (причём только определённые) - совсем не ясно. И всегда, для любого способа борьбы с багами, можно придумать такой сценарий, который не будет работать. Предложите свой способ, а мы придумаем кучу ситуаций, когда он не сработает.
-
В периферии nuvoton-ов не разбираюсь. Но копал бы WDT. Обычно во всех WDT с которыми я работал, была возможность сброса при записи недопустимого значения в какие-либо регистры WDT. Думаю и в nuvoton должно быть что-то подобное.
-
Вопрос был в том: Читали ли вообще что эта функция делает и как она работает? Прежде чем использовать её в ISR. И допустим ли её вызов из ISR? В результате - костылинг победил здравый смысл....
-
Хорошо - предположим перед ней 100 байт линейного кода. Достаточно? Причём такого, что даже нигде к памяти не обращается (иначе скорей всего случился бы вылет по MPU или HF из-за обращения по недопустимым адресам) - что само по себе очень редкий случай. Получаем: 100/2^32 = ~2.3e-8 - вероятность попадания в такой регион при переходе по случайному адресу. С такой вероятностью можно считать это событие вообще невероятным. Да ладно? Предположим - работаете вы не один, а есть другие люди, тестирующие ваш девайс или работающие над проектом. В девайсе несколько десятков настроек + довольно богатый функционал. Далее к вам обращается тестировщик: вот тестировал вчера вечером девайс, вдруг он завис (или перегрузился; а скорее даже скажет: "Контроллер крутил мотор и вдруг мотор остановился (девайс - инвертор для PMSM-моторов" (так как тестировщик даже не заметил, что девайс просто молча перезагрузился)). Спрашиваете его: "Какую последовательность действий выполнял перед этим событием?" В ответ - "Не помню, много что делал, параллельно ещё меня отвлекали". Т.е. - воспроизвести баг вы не можете. А если ещё девайс - мощный мотор на стенде, в несколько сотен кВт, который на своём столе просто не запустите. Как собираетесь искать баг? А в моём случае я просто попрошу его показать содержимое ловушки. И с большой вероятностью сразу найду причину. Опять не соглашусь. Как раз в последнее время много приходится отлаживать девайсов "за тридевять земель". В 9-и случаев из 10-и благодяря системе ловушек, баг нахожу сразу, за несколько секунд. Большинство из таких багов: 1. Впаяли не тот чип (например - не ту SPI-флешку). Драйвер SPI-флешь при старте читает ID флешки и падает в ловушку. Или читает регистры защиты флешь - и также падает в ловушку из-за установленной защиты, которой не должно быть. Причина определяется сразу по дампу ловушки. 2. Непропай - опять ошибка инициализации какого-либо драйвера и падение в ловушку. Опять определяется сразу по дампу ловушки. 3. Подали не то питание или что-то не подключили или подключили неправильно - опять ловушка. И опять причина находится сразу. 4. Сильный перегрев платы - уходит частота генератора на плате - падаем в ловушку. Причина находится быстро. ... и таких багов - большинство. И реально ловушки помогают. Так как проверками у меня обложены все потенциально опасные места. Я не понимаю вашу логику. Вы пытаетесь доказать, что моя система ловушек не пригодна по отдельным, частным случаям, когда она бы не сработала. Это примерно то же самое, что говорить: "Вот я вчера шёл не заметил кочку и споткнулся, упал. Получается - глаза мне не помогли её увидеть. Значит глаза не нужны". Это если следовать вашей логике. Странная логика.... Ок - раскомментировали вы отладочный вывод. Время выполнения кода изменилось, а также изменилось распредление памяти - проявление бага пропало. И будете искать баг до морковкина заговения. Так что такой способ - так себе способ. Хорошо, я понял - вы почему-то против моего способа. Тогда предложите ваше решение. Вот случай (исходя из вопроса ТС): Вызываете сервис ОС, он возвращает вам ошибку (например какой-то ресурс недоступен). Ваши дествия? Повиснуть? Перегрузиться? Что будете делать. Я просто вызову trap(TRAP_OS, ...) (и по выводу сразу найду место бага). Но что будете делать вы? Или другой случай: У меня есть множество функций с assert-ами (проверками входных аргументов на входе). Если проверка не проходит - trap(TRAP_ASSERT, регион_assert-а, ...). И сразу вижу причину и место. Каково ваше решение в этом случае (без механизма ловушек)? Повиснуть? Перегрузиться?
-
слабый линух + слабый прогер = гремучая смесь
-
Вызываете sysprintf() из ISR? А что внутри неё - смотрели? Рассчитана ли она на такой вызов?
-
Что-то странное рассказываете... При неконтролируемой передаче управления (например - вследствие разрушения стека) вероятность попасть в точку старта прошивки (это всего от 0 до нескольких байт после точки) - близка к вероятности выигрыша в лотерею суперприза. Просто достаточно посчитать - какова вероятность случайного выпадения заданного адреса в случайном 32-битном значении? "Разблокируется флешь" - вообще равно нулю. Так как в используемых мной сейчас XMC4xxx модифицировать внутреннюю флешь может только код, находящийся в ОЗУ. И копирует его туда бутлоадер после множества проверок и программирований MPU. Вероятность попасть в какой-то удачный адрес при неконтролируемой передаче управления - крайне мала. В 99% будет попадание в такое место, при котором будет сгенерирован HF (а соответственно - и последующий trap) или по недопустимой команде или по недопустимому обращению к памяти. Пишу это не от фонаря, а потому что использую это давно и много раз помогало. В том числе и при улётах неизвестно куда. Да, fault сработает не сразу, но по содержимому регистров CPU или дампов стеков как правило - можно быстро найти место начальной проблемы. Срабатывание сторожевика - это ещё один источник возбуждения trap(). И такой случай должен быть расследован программистом при отладке прошивки в обязательном порядке. Наличие внешнего WDT нисколько не мешает использовать и внутренний. Почти во всех проектах имею внешний WDT. И везде он у меня работает совместно с внутренним WDT.
-
В смысле? Очевидно - при помощи отладчика. А как же ещё? Запускаю отладчик и смотрю что там происходит. ни чего не понял... Что за "файл прерывания" и какое он имеет отношение к ошибкам инициализации железа, и почему "операционка валится" куда-то? Из вопроса ТС видно, что речь не только о вызове сервисов ОС, но и об "инициализации железа". А значит - речь о всех критических ошибках вообще, а не только об ошибках использования сервисов РТОС.
-
При возникновении критической ошибки (такой ошибки, выполнение программы после которой невозможно), все мои прошивки переходят в режим ловушки (trap): Запоминается номер trap, его аргументы, состояние регистров CPU и вершины текущего стека (это контекст trap); делается сброс всей периферии (возможно - с переключением CPU на более низкую частоту; а возможно и со сбросом всего устройства), инициализируется только минимально необходимый набор периферии (система тактирования, GPIO, MPU, WDT, отладочный UART, ...) и в отладочный UART начинается периодический вывод состояния ловушки (запомненного контекста) с индикацией режима ловушки через доступные средства индикации (лампочки и т.п.). Т.е. - реализую аналог "синего окна смерти" винды. Делаю примерно то же самое. В устройствах, где имеется FRAM, у меня также события критических ошибок (с контекстом) сохраняются в журнал критических ошибок (расположенный во FRAM). Но после предварительного сброса/рестарта CPU. В терминале вывод состояния ловушки выглядит так: По логу виден номер trap (3) + набор аргументов данного номера (в квадратных скобках) + регистры + вершина стека. PS: А почему вопрос в разделе "Операционные системы\FreeRTOS"? Обработка критических ошибок не имеет никакого отношения к ОС.
-
Умощнение выхода ОУ
jcxz ответил koluna тема в Схемотехника
Например тем, что если на любую цепь питания светодиодов где-то упадёт сетевой провод, то всё полученное с того провода прилетит в ваш управляющий контроллер. К чему вы должны быть готовы, разрабатывая его. -
Если задачи - независимы друг от друга, то критическая секция нужна. Потому как пишущая задача вполне может захотеть обновить данные до того, как предыдущие данные считаны читающей задачей. Так что = критическая секция (для сериализации доступа к данным) + какой-либо механизм нотификации (об обновлении данных) читающей задаче. Второе может быть как простым volatile-флажком, так и каким-то средством из арсенала ОС. А если предыдущие данные ещё не считаны, но пришли новые? Куда их девать? Вот для того и нужны критическая секция + нотификатор. Из контекста вопроса видно, что передаваемые данные - какие-то параметры, которые могут приходить в любое время, асинхронно работе системы. В том числе и прийти несколько раз подряд с коротким интервалом. Неправильный алгоритм. Сперва читающий процесс должен сбросить флажок-нотификатор, и только потом - считывать данные. Так как иначе он может сбросить флаг новых данных, даже не прочитав их. Это не так. Флажков в РТОС бывает много разных. И в любом случае всегда советовать весьма тяжёлый мьютекс - так себе совет. Мьютекс я бы советовал в самом последнем случае. PS: Если не нравится критическая секция или мьютекс (который весьма сложен внутри, намного сложнее критической секции, а потому требует много ресурсов от ОС; и применять его лишний раз в простых случаях - неоптимально), то есть множество других вариантов межзадачной синхронизации. Вместо критической секции (которая может запрещать все прерывания), можно останавливать шедулер ОС на время чтения/записи разделяемых данных (что является аналогом критической секции, но без помех работе прерываний). Кроме того - есть механизмы межзадачной синхронизации вне-РТОС функционала. Спин-блокировка например. Если у ТС процессор = Cortex-M, то для атомизации доступа к разделяемым данным можно использовать механизм эксклюзивного доступа. В случае, если объём передаваемых параметров небольшой (~десятки байт), то эксклюзивный доступ намного легче (по занимаемым ресурсам) чем мьютекс. И при этом совершенно не мешает работе прерываний. При выборе конкретного способа синхронизации в каждом конкретном случае, следует идти от простого к сложному: Сперва примерить самый простой способ. Если не подходит - переходим к более сложному, примеряем его. И так далее... Только так можно создавать оптимальные программы.
-
Умощнение выхода ОУ
jcxz ответил koluna тема в Схемотехника
Совершенно непонятно одно: зачем вообще нужен какой-то диммер, если управление осуществляет МК?? У вас нет программиста, способного написать нужный алгоритм управления ключами питания светодиодов? -
Прошу помощи в разработке энкодера колеса мыши
jcxz ответил Darmok тема в Схемотехника
Точно также - анализируя сигналы шин. Я выше уже писал: КР580ВМ80 - это не МК, у него все шины торчат наружу. Можно легко детектировать моменты чтения команд из памяти и адреса, по которым они выполняются. И останавливать в нужный момент (HLD или RDY). Простой схемой из нескольких логических элементов. Также легко можно реализовать бряк по обращению к данным по какому-либо адресу. Смотреть регистры CPU или содержимое памяти конечно сложнее. Тут без программы не обойтись. Написать программу на каком-нибудь ARM-е, подключив его к шинам КР580ВМ80 и следить за потоком команд, эмулируя внутри ход выполнения программы. Тогда, при остановке на бряке, внутри ARM-а будет всё содержимое ОЗУ и регистров КР580ВМ80. Но вот просто остановить на каком-то адресе - достаточно простой схемки из нескольких логических элементов. PS: Когда-то в середине 90-хх, будучи студиоузом, я придумал и спаял RAM-диск (на 256КБ) для своего тогдашнего домашнего компа на КР580ВМ80. "Контроллер" этого диска был построен на всего 4 или 5 простых логических ИС (логика, триггеры, 8-разрядный регистр вроде был). Он был подключен к шинам КР580ВМ80, перехватывал команды, выбираемые процессором из ОЗУ и, обнаружив определённый код команды (один из неиспользуемых кодов команд), переключал обращение к штатному ОЗУ компа на обращение к моему диску. Таким образом, чтобы прочитать или записать байт на этот диск, нужно было выполнить любую команду с операндом M, перед которой поставить этот код неиспользуемой команды. Помню, что встроить этот контроллер в шину КР580ВМ80 было несложно. Даже для студента всего недолго знакомого с электроникой. Почти все нужные сигналы там уже были. -
Прошу помощи в разработке энкодера колеса мыши
jcxz ответил Darmok тема в Схемотехника
Никаких "эмуляторов" никуда втыкать не надо. Я выше уже писал как можно сделать. Нужно только прочитать описание работы КР580ВМ80А. Обнаружить в описании сигналы HLD, RDY, HLDA, WAIT. Почитать как они работают. Далее можно с помощью этих сигналов останавливать CPU на нужном адресе памяти и с помощью них же шагать по командам. Т.е. - достаточно будем поднять пару ножек CPU (или перерезать пару дорожек), чтобы врезаться в эти цепи. Например здесь достаточно подробно описан КР580ВМ80А: https://elancev.narod.ru/texno/bm80/bm80.htm