Обработку прерывания от FSMC и таймаут на то что PLL (не)заведётся
сделал? Я делал... Иногда срабатывало. Плохая пайка, плохой кварц и
т.п. Считал фатальной ошибкой. При фатальной ошибке МК пищит и
мигает диодом нужное число раз, означающее код ошибки, несколько
раз в цикле, потом перезапуск. Фатальные ошибки -- это когда
работать уж совсем никак (сбой генератора, нет внешней памяти,
ошибка CRC памяти программ). Другие ошибки, с которыми запуск и
выполнение хотя бы части функцинала возможны -- не фатальные.
Для ошибок в ПО в автономных приборах -- быстрый перезапуск, для работающих под управлением оператора -- через писк и мигание. Из ошибок ПО это обычно срабатывание assert'ов (которые, считаю, скорей полезно оставлять в релизных версиях) и абортов, исключение вызванное процессором (переполнение стека, порча стека обнаруживаемая компилятором -fstack-protector у GCC, деление на ноль, обращение вне существующей памяти, невыравненное обращение, срабатывание софтового ватчдога). Для разных случаев коды ошибок разные, при возможности более подробная информация выпечатывается в UART (чтоб на столе отладить) и сохраняется в ОЗУ, чтоб после перезапуска МК её оттуда достать (в специальной незануляемой секции) и записать во flash/eeprom последние несколько ошибок, которые потом можно сдампить. Сам МК может записать свои регистры, причину ошибки, минимальный бэктрейс. Да, на PIC18 тоже.
Единственное что -- ОЗУ никогда не проверял (на исправность). У Hitech-C для PIC18 проверка была встроенная в библиотеку, но конфликтовала с секцией которая не должна зануляться (причина программного сбоя). CRC программ он тоже сам умел считать, а для других нужно самому колхозить. Причём с CRC я много лет назад накололся, что массовое об-FF-чивание с конца позволяет совпадать CRC, теперь боюсь её. Обычную сумму так не обманешь, но она не замечает перестановки блоков. В конце маркер конца записывать что ли (AA, 55, что угодно)... Чтоб посчитать CRC нужно свой ассемблерный кусок, или на C без инициализации переменных, написать и воткнуть до C-библиотеки вообще. Ну и собственно обработка ошибок, аналогично: уметь мигать, пищать, выводить в UART, без библиотеки. И впихнуть это в 0-ю страницу flash. Для атмеловского ARM'а примерно так (http://caxapa.ru/301879 http://caxapa.ru/672102)
Подробней об обработке ошибок:
http://caxapa.ru/902079/
О сторожевом таймере (watchdog): http://caxapa.ru/955829
Сторожевой таймер -- про это как-то не сказано, но очень хочется от себя добавить. Сторожевой таймер должен присутствовать в любой embedded системе и быть включен в самый главный, самый верхний, основной, цикл обработки событий. Он не должен запускаться в отдельном потоке, в прерывании, ещё как-то независимо. В основной цикл обработки событий периодически (по факту истечения определённого периода внутреннего времени системы) должно включаться специальное событие, которое должно обрабатываться и сбрасывать таймер. Таким образом контролируется два факта: то, что система в состоянии обрабатывать события, и что внутреннее время системы идёт. Нельзя просто в цикле сбрасывать сторожевой таймер без проверки времени, потому, что возможны ошибки, когда цикл выполняется, а время не идёт или отсчитывается неправильно