|
|
  |
Правильное запрещение прерываний в LPC176x, перенос кода с LPC2xxx и критические секции |
|
|
|
Aug 31 2011, 19:13
|
Местный
  
Группа: Свой
Сообщений: 249
Регистрация: 2-05-06
Из: Россия, Поволжье
Пользователь №: 16 686

|
Доброго времени суток. Переношу код с LPC2214 и LPC2132 на LPC176x, потихоньку разбираюсь с мощным блоком NVIC и всякой вкусной системной обвязкой в кортексе. В старых проектах есть ряд участков кода в основной программе (критические секции), где запрещались прерывания, для того, чтобы не произошло изменение блока нужных регистров или есть жёсткая привязка по таймингам. Выглядело это примерно так для LPC2xxx: CODE void func() { DWORD cpsr=INT_DISABLE(); //сохраняем текущее состояние, отключаем IRQ, FIQ //критическая секция //...код... INT_RESTORE(cpsr); //восстанавливаем состояние }
#define IRQ_FLAG 0x80 #define FIQ_FLAG 0x40
/************************************************************************* * Function Name: INT_RESTORE * Parameters: unsigned long IFlag * Return: void * Description: Restore F,I flag state * *************************************************************************/ void INT_RESTORE(unsigned long IFlag) { unsigned long tmp; tmp=__get_CPSR(); __set_CPSR(tmp & (IFlag | ~(IRQ_FLAG | FIQ_FLAG))); }
/************************************************************************* * Function Name: INT_DISABLE * Parameters: * Return: unsigned long * Description: Disable interrupts and return previous state state of flgas I * *************************************************************************/ unsigned long INT_DISABLE(void) { unsigned long tmp; tmp=__get_CPSR(); __set_CPSR(tmp | IRQ_FLAG | FIQ_FLAG); return tmp; } Сейчас использую CMSIS. В результате курения мануалов и экспериментов выяснил, что простое отключение прерываний через __disable_irq() (или CPSID I) приводит к Hard fault при возникновении прерывания, и, разумеется, радостно выставлен бит FORCED. Как я понял, это сообщает об отсутствии обработки прерывания. Естественно, мне же надо было отключить все разом. Насколько удалось из мануалов понять, требуется применение __disable_fault_irq() (или CPSID F), тогда перехода на fault-handlers не будет. Правильным ли будет следующий подход по аналогии со старым кодом для критических секций? Код void new_func() { DWORD prm, fm; prm = __get_PRIMASK(); //сохраняем состояние PRIMASK fm = __get_FAULTMASK(); //сохраняем состояние FAULTMASK __disable_fault_irq(); //критическая секция //...код... __set_PRIMASK(prm); //восстанавливаем состояния. Правильная ли очерёдность? Если наоборот, то не произойдёт ли переход на fault_handler? __set_FAULTMASK(fm); } Учитывая, что в PRIMASK и FAULTMASK используется только по одному биту, то можно обойтись одним временным регистром. И ещё. Пока мне непонятно: при переходе на hard_fault_handler считываю состояние HFSR, вижу установленный бит FORCED, а в BFSR - BFARVALID и PRECISERR, что указывает на возможность чтения Bus Fault Address Register (BFAR). Так вот, значение, которое лежит в этом регистре, равно 0x100175ED. Откуда такой адрес? По идее, там должен находиться адрес, откуда произошёл bus fault, но на карте памяти таких адресов нет в моём процессоре (LPC1767). Или я что-то недопонял?
|
|
|
|
|
Sep 1 2011, 05:47
|
Профессионал
    
Группа: Свой
Сообщений: 1 241
Регистрация: 15-11-05
Из: Челябинск
Пользователь №: 10 882

|
В IAR пользуюсь конструкцией Код unsigned long int_bak; int_bak = __get_interrupt_state(); __disable_interrupt(); ..... __set_interrupt_state(int_bak); все работает без проблем. PS И забудте вы про CMSIS - легче станет. Проще написать свой драйвер NVIC, чем адаптировать творчество ARM. Сейчас у меня одни и те же модули легко работают как под ARM7 (LPC 21хх и LPC23xx), так и под C-M3 (LPC17xx)
|
|
|
|
|
Sep 1 2011, 05:59
|
Местный
  
Группа: Свой
Сообщений: 249
Регистрация: 2-05-06
Из: Россия, Поволжье
Пользователь №: 16 686

|
Цитата(Alechek @ Sep 1 2011, 09:47)  все работает без проблем. Очень странно, т.к. данный интринсик: Цитата For Cortex-M devices, it raises the execution priority level to 0 by setting the priority mask bit, PRIMASK Т.е. на FAULTMASK не оказывает влияния, что в моём случае приведёт в fault_handler. Либо у вас изначально уже замаскирован регистр FAULTMASK. Цитата PS И забудте вы про CMSIS - легче станет. Проще написать свой драйвер NVIC, чем адаптировать творчество ARM. Сейчас у меня одни и те же модули легко работают как под ARM7 (LPC 21хх и LPC23xx), так и под C-M3 (LPC17xx) А мне ряд функций очень даже понравился, правда, сначала приходится пробегать глазами по ним и выделять нужные, корректировать ошибочные (ошибок там хватает). Поскольку это мой первый Cortex-M3, то заодно и проц изучается  По поводу работы одних и тех же программных модулей на разных процах - это следующий этап. Пока бы -М3 поднять.
|
|
|
|
|
Sep 1 2011, 08:00
|
Местный
  
Группа: Свой
Сообщений: 249
Регистрация: 2-05-06
Из: Россия, Поволжье
Пользователь №: 16 686

|
Цитата(Alechek @ Sep 1 2011, 10:58)  А Вы не пробовали разобраться с причиной возникновения fault? Пробовал. Написал же выше причину. Что ещё может быть не так?
|
|
|
|
|
Sep 5 2011, 04:38
|
Частый гость
 
Группа: Свой
Сообщений: 169
Регистрация: 10-11-05
Из: Воронеж
Пользователь №: 10 687

|
Цитата(Altemir @ Sep 1 2011, 09:59)  Очень странно, т.к. данный интринсик: Если речь идет про ИАР, то Вы путаете __disable_irq(), которое действительно вызовет проблему на кортексе, и __disable_interrupt(), о котором упоминал Alechek. Последнее на кортексе работает нормально.
|
|
|
|
|
Sep 5 2011, 04:58
|
Местный
  
Группа: Свой
Сообщений: 249
Регистрация: 2-05-06
Из: Россия, Поволжье
Пользователь №: 16 686

|
Цитата(gladov @ Sep 5 2011, 08:38)  Если речь идет про ИАР, то Вы путаете __disable_irq(), которое действительно вызовет проблему на кортексе, и __disable_interrupt(), о котором упоминал Alechek. Последнее на кортексе работает нормально. Подозревал, но тогда как понимать в файле cmsis_iar.h этот дефайн: Код #define __disable_irq __disable_interrupt Хм, не могу найти описание для __disable_interrupt. Может, Вы подскажете? В хэлпе IARа указано только то, что я привёл выше. Там ошибка?
|
|
|
|
|
Sep 6 2011, 04:05
|
Частый гость
 
Группа: Свой
Сообщений: 169
Регистрация: 10-11-05
Из: Воронеж
Пользователь №: 10 687

|
Цитата(Altemir @ Sep 5 2011, 08:58)  Подозревал, но тогда как понимать в файле cmsis_iar.h этот дефайн: Код #define __disable_irq __disable_interrupt Хм, не могу найти описание для __disable_interrupt. Может, Вы подскажете? В хэлпе IARа указано только то, что я привёл выше. Там ошибка? Никакой ошибки нет. __disable_irq() не предназначена для Cortex-M3, о чем и я Вам выше написал. А как устроена CMSIS не знаю, не пользовался. Все таки правильно тут советовали, что начинать знакомство с новой архитектурой используя чью-то библиотеку неправильно, т.к. наступаете не только на собственные грабли, но еще и на чужие. Я хелп редко читаю. А вот в файле <intrinsics.h> в комментах совершенно четко описано какие функции для чего можно/нужно использовать.
|
|
|
|
|
Sep 6 2011, 05:04
|
Местный
  
Группа: Свой
Сообщений: 249
Регистрация: 2-05-06
Из: Россия, Поволжье
Пользователь №: 16 686

|
Цитата(gladov @ Sep 6 2011, 08:05)  Все таки правильно тут советовали, что начинать знакомство с новой архитектурой используя чью-то библиотеку неправильно, т.к. наступаете не только на собственные грабли, но еще и на чужие. Зато сколько интересного можно откопать!  Во первых, есть неплохие примеры. Во вторых, длительный опыт ковыряния чужих некомментированных исходников позволяет адекватно воспринимать код и даже находить в нём ошибки (а в CMSIS-е их хватает). Я сначала пробегаюсь по используемым функциям, смотрю, что в них и как сделано, и что вообще стоит из этого использовать, и ТОЛЬКО ПОСЛЕ ЭТОГО подрубаю к своему проекту. Зато нескучно. И пусть в меня кинут тапком  З.Ы. а описания на асме __disable_interrupt я так и не раскопал
|
|
|
|
|
Sep 6 2011, 05:50
|

Профессионал
    
Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555

|
Цитата(Altemir @ Sep 6 2011, 09:04)  З.Ы. а описания на асме __disable_interrupt я так и не раскопал  у IAR это intrinsic, которая просто вставляет CPSID I Exceptions у этой инструкции нет! А может вы в непривилегированном режиме? тогда эта инструкция игнорируется. В любом случае лучше посмотреть содержимое регистров под отладчиком после запрещения прерываний, ну fault отловить. Для отладки достаточно такого обработчика: Код void fault(void) { __no_operation(); } и брекпоинт поставить, потом в асме сделать пару шагов и вы вернетесь в то место где случился fault
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|