Comments 41
Написано интересно и хорошо, мол, меняйте таблицу прерываний под себя, но у F0 меняется не только размер ОЗУ от серии к серии, но и периферия (переносишь с F030 под F042, скорей всего придется менять UART, DMA, и т.п., а значит, переносимость кода данные методы не гарантируют и код так и остается в рамках одной серии. А в рамках подсерии VL/MD/HD и так проблем нет.
+«рваное» ОЗУ у старших моделей.
Значит, все равно править под конкретный МК.
+«рваное» ОЗУ у старших моделей.
Значит, все равно править под конкретный МК.
0
а) во всём тексте нет ни единого упоминания таблицы прерываний
б) переносимость кода между двумя произвольными моделями контроллеров вам вообще ничто и никто в этом мире не гарантирует, хотя вообще-то при необходимости сделать программно определяемыми несколько адресов нужной периферии ничто не мешает
б) переносимость кода между двумя произвольными моделями контроллеров вам вообще ничто и никто в этом мире не гарантирует, хотя вообще-то при необходимости сделать программно определяемыми несколько адресов нужной периферии ничто не мешает
+2
Хорошая пасхалка про сову в коде :)
Вообще, спуск до ассемблера навевает воспоминания о MS-DOS и робких попытках писать код на асме с 80x87 FPU. «Когда железки были большими»…
Вообще, спуск до ассемблера навевает воспоминания о MS-DOS и робких попытках писать код на асме с 80x87 FPU. «Когда железки были большими»…
0
Ну там на самом деле после совы должен идти стандартный обработчик хардфолта, примеров которых в интернете десятки, если не сотни — обычно они просто регистры процессора печатают. Так что реальной шутки поменьше, чем в известной картинке.
+1
Мне больше интересно зачем прятать происходящее от компилятора и потом с ним «воевать».
То есть почему вторая функция выглядит как выглядит, а не как-то примерно так:
Есть какой-то тайный смысл в том, чтобы, вместо того, чтобы описать всё явно, опираться на знания API и прочего?
Не первый раз вижу вещи, написанные в подобном «хрупком» стиле и всегда удивляюсь: зачем?
То есть почему вторая функция выглядит как выглядит, а не как-то примерно так:
bool cpu_check_address(volatile const char *address) {
/* Cortex-M0 doesn't have BusFault so we need to catch HardFault */
/* R5 will be set to 0 by HardFault handler */
/* to indicate HardFault has occured */
register bool result __asm("r5") = 1; /* Set default return value */
register uint32_t sign1 __asm("r1") = 0xDEADF00D; /* set magic number */
register uint32_t sign2 __asm("r2") = 0xCAFEBABE; /* 2nd magic to be sure */
uint32_t scratch;
__asm__ (
"ldrb %[scratch], [%[address]] \n" /* probe address */
:"=r"(result),[scratch]"=l"(scratch)
:[address]"l"(address),"r"(result),"r"(sign1), "r"(sign2)
);
return result;
}
Есть какой-то тайный смысл в том, чтобы, вместо того, чтобы описать всё явно, опираться на знания API и прочего?
Не первый раз вижу вещи, написанные в подобном «хрупком» стиле и всегда удивляюсь: зачем?
+1
Никакого. Но в ближайшие лет десять-двадцать этот API никуда не денется.
0
Зато компилятор может какой-нибудь временный результат в r0 положить вдруг. Что превратит весь ваш пример в тыкву.
Или «в ближайшие лет десять-двадцать» вы и компилятор обновлять не будете?
Или «в ближайшие лет десять-двадцать» вы и компилятор обновлять не будете?
0
Во-первых, вот прямо в этом коде никаких «временных результатов» нет.
Во-вторых, если вы считаете, что ваш код всё описывает явно и не зависит от обновлений API и компилятора, то вы ошибаетесь.
Во-вторых, если вы считаете, что ваш код всё описывает явно и не зависит от обновлений API и компилятора, то вы ошибаетесь.
0
Во-первых, вот прямо в этом коде никаких «временных результатов» нет.Потому я назвал его не «неправильным», а «хрупким». Временные результаты легко могут появиться если компилятор решит его заинлацнить — и да, атрибут
inline
для этого не требуется.Во-вторых, если вы считаете, что ваш код всё описывает явно и не зависит от обновлений API и компилятора, то вы ошибаетесь.А конкретнее? Представить себе, что какой-то компилятор, после соответствующего обновления станет использовать, скажем, другую инструкцию
ldrb можно... нужно было использовать ldrb.n
для надёжности... Что-то ещё?
Так-то от ошибок в компилятора никто не застрахован... Но нарываться-то зачем?
0
LDRB.N или LDRB.W в явном виде, разумеется. И дело тут не в ошибках компилятора, а в том, что если вы не полагаетесь на использование им только нижних регистров, то надо либо все передаваемые в LDRB переменные надо привязать явно к конкретным регистрам, либо указать конкретную инструкцию LDRB — а то их в кортексе три разных.
0
Скажите, а насколько важно в подобном коде объявлять register? Это действительно нужно или дань традиции?
0
Это нужно, что бы GCC понял, что это не переменные, а алиасы регистров.
+1
Это совсем другая конструкция нежели стандартный модификатор
Она действительно немного похожа на обычный
register
.register typename varname __asm("registername");
— это цельная конструкция для описания переменной, живущей в определённом регистре.Она действительно немного похожа на обычный
register
— но имеет заметно другой смысл.+1
Если между сбросом флага bus fault и его проверкой произойдет какое-нибудь прерывание и в его ISR произойдет обращение к несуществующему адресу, то а) это факт будет пропущен системой, и б) основная процедура вернет ошибочный вердикт о валидности пробного адреса
+1
В такой статье надо перечислять на каких конкретно чипах тестировалось.
В Kinetis на Cortex-M хаотичное сканирование периферии не инициализированной должным образом приведет к сбросу, без всякого bus fault.
В Kinetis на Cortex-M хаотичное сканирование периферии не инициализированной должным образом приведет к сбросу, без всякого bus fault.
0
В общем случае размер инструкции на Cortex-M может быть не только 2, но и 4 байта. Поэтому проверку валидности адресов лучше выполнять в специальной функции, и убедиться в дизассемблере, что инструкция, выполняющая чтение по проверяемому адресу, действительно имеет размер 2 байта.
0
При чём тут вообще размер инструкции?
0
Из статьи:
читаем из стека значение PC (смещение 0x18), добавляем к нему 2 (2 байта — размер инструкции на Cortex-M) и сохраняем обратно в стек.
0
В данном случае вариативности в размере инструкции не будет, это ldrb, она 16-битная.
0
В той же таблице есть и 32-битный вариант ldrb. Если я правильно понял и правильно помню — это вариант той же инструкции с условным выполнением.
0
Не совсем. Там для регистров выше R7 инструкция 32-битная (LDRB.W), а с R0 по R7 — подходит и та, и другая, но ассемблер в этом случае обязан выбрать 16-битную, если автор в явном виде не указал LDRB.W.
P.S. Добавил в текст поста комментарий.
P.S. Добавил в текст поста комментарий.
+1
Ну вот — если компилятор использует для адресации регистр выше R7 — к PC нужно прибавлять 4. Получается inline — функции для проверки валидности использовать нельзя — в разных местах, куда они будут встроены компилятором, для адресации могут использоваться разные регистры. Нужно реализовывать это в одном месте, и отключать для этой функции оптимизацию, чтобы она компилировалась всегда одинаково.
0
Компилятор к инструкции «ldrb r3, [r0]» никакого отношения не имеет и ничего в ней использовать не может — в ней вообще компилировать нечего, это ассемблер.
Оптимизацию в связи с этим отключать не надо.
Оптимизацию в связи с этим отключать не надо.
0
Смутил такой способ сброса флага:
Тем более, что далее он проверяется:
SCB->CFSR |= BFARVALID_MASK;
Тем более, что далее он проверяется:
if ((SCB->CFSR & BFARVALID_MASK) != 0)
0
Это довольно частый способ сброса флагов в контроллерах — записью в них единицы. Так что нет, не опечатка.
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/Cihcfefj.html
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/Cihcfefj.html
The UFSR bits are sticky. This means as one or more fault occurs, the associated bits are set to 1. A bit that is set to 1 is cleared to 0 only by writing 1 to that bit, or by a reset.
+3
А какое у этой проверки практическое применение, помимо проверки размера RAM?
0
Определение объёмов ОЗУ, флэша, EEPROM, наличия периферии на лету.
Берём, например, STM32L1. У него после старта надо все ножки вручную перевести в режим аналогового входа.
Вот как определить, «все» — это какие конкретно, если у нас одна и та же прошивка работает на нескольких моделях контроллера с разным числом портов?
Берём, например, STM32L1. У него после старта надо все ножки вручную перевести в режим аналогового входа.
Вот как определить, «все» — это какие конкретно, если у нас одна и та же прошивка работает на нескольких моделях контроллера с разным числом портов?
0
Думаю, что про ножки не совсем корректно. Ведь у STM32F100 серии люди часто находят полнофункциональный третий UART или возможность принять 128 Кб прошивку при официальном наличии 64 Кб Flash. И ничто не мешает ножкам реально существовать, но остаться невыведенными наружу.
И, кстати, это я бухтел в комментариях про статьи о мигании светодиодом, поэтому спасибо за информативную статью!
И, кстати, это я бухтел в комментариях про статьи о мигании светодиодом, поэтому спасибо за информативную статью!
0
Но почему бы не использовать для этого регистры DBGMCU_IDCODE и FLASH_SIZE?
0
Потому что через полчаса попыток разобраться, что там чему соответствует и как это всё декодировать, а также таскать с собой, в вашем сердце будет ярким пламенем гореть ненависть к отделу разработки ST Microelectronics.
И это мы ещё не дошли до попытки без натурных экспериментов выяснить, можно ли вообще по даташитам и RM установить, в каких конкретно процессорах таки есть GPIOG и GPIOF, а в каких нет (короткий ответ: нельзя).
И это мы ещё не дошли до попытки без натурных экспериментов выяснить, можно ли вообще по даташитам и RM установить, в каких конкретно процессорах таки есть GPIOG и GPIOF, а в каких нет (короткий ответ: нельзя).
+1
Да, эти регистры не дают полной информации о контроллере. Но ненавидеть за это отдел разработки ST — это черезчур, ведь контроллеры в целом хорошие. Но я бы не стал полагаться на проверку корректности адресов — ведь в очередной ревизии ST может решить, что проще перемаркировать контроллер, урезав его там где выявлены дефекты — и тогда проверка введёт в заблуждение. Я бы использовал для идентификации сигнатуру во флэше, получаемую отдельно от прошивки.
0
Вопрос не в полноте информации, вопрос в том, что ST в своих чипах — не только в микроконтроллерах — очень непоследовательны в деталях реализации.
Вот здесь мы в одной только серии контроллеров для одного только элементарного параметра видим три варианта реализации, понять которые нельзя, их надо запомнить.
Вот здесь мы в одной только серии контроллеров для одного только элементарного параметра видим три варианта реализации, понять которые нельзя, их надо запомнить.
0
О, как раз по этому поводу засабмитил им несколько лет назад багрепорт
0
Sign up to leave a comment.
Проверка корректности адресов в памяти на Cortex-M0/M3/M4/M7