AltemirX 0 31 августа, 2011 Опубликовано 31 августа, 2011 · Жалоба Доброго времени суток. Переношу код с LPC2214 и LPC2132 на LPC176x, потихоньку разбираюсь с мощным блоком NVIC и всякой вкусной системной обвязкой в кортексе. В старых проектах есть ряд участков кода в основной программе (критические секции), где запрещались прерывания, для того, чтобы не произошло изменение блока нужных регистров или есть жёсткая привязка по таймингам. Выглядело это примерно так для LPC2xxx: 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). Или я что-то недопонял? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Alechek 0 1 сентября, 2011 Опубликовано 1 сентября, 2011 · Жалоба В 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) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AltemirX 0 1 сентября, 2011 Опубликовано 1 сентября, 2011 · Жалоба все работает без проблем. Очень странно, т.к. данный интринсик: 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 поднять. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Alechek 0 1 сентября, 2011 Опубликовано 1 сентября, 2011 · Жалоба А Вы не пробовали разобраться с причиной возникновения fault? :smile3009: В моем случае оно как-то не возникает :laughing: Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AltemirX 0 1 сентября, 2011 Опубликовано 1 сентября, 2011 · Жалоба А Вы не пробовали разобраться с причиной возникновения fault? Пробовал. Написал же выше причину. Что ещё может быть не так? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
gladov 0 5 сентября, 2011 Опубликовано 5 сентября, 2011 · Жалоба Очень странно, т.к. данный интринсик: Если речь идет про ИАР, то Вы путаете __disable_irq(), которое действительно вызовет проблему на кортексе, и __disable_interrupt(), о котором упоминал Alechek. Последнее на кортексе работает нормально. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AltemirX 0 5 сентября, 2011 Опубликовано 5 сентября, 2011 · Жалоба Если речь идет про ИАР, то Вы путаете __disable_irq(), которое действительно вызовет проблему на кортексе, и __disable_interrupt(), о котором упоминал Alechek. Последнее на кортексе работает нормально. Подозревал, но тогда как понимать в файле cmsis_iar.h этот дефайн: #define __disable_irq __disable_interrupt Хм, не могу найти описание для __disable_interrupt. Может, Вы подскажете? В хэлпе IARа указано только то, что я привёл выше. Там ошибка? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
gladov 0 6 сентября, 2011 Опубликовано 6 сентября, 2011 · Жалоба Подозревал, но тогда как понимать в файле cmsis_iar.h этот дефайн: #define __disable_irq __disable_interrupt Хм, не могу найти описание для __disable_interrupt. Может, Вы подскажете? В хэлпе IARа указано только то, что я привёл выше. Там ошибка? Никакой ошибки нет. __disable_irq() не предназначена для Cortex-M3, о чем и я Вам выше написал. А как устроена CMSIS не знаю, не пользовался. Все таки правильно тут советовали, что начинать знакомство с новой архитектурой используя чью-то библиотеку неправильно, т.к. наступаете не только на собственные грабли, но еще и на чужие. Я хелп редко читаю. А вот в файле <intrinsics.h> в комментах совершенно четко описано какие функции для чего можно/нужно использовать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AltemirX 0 6 сентября, 2011 Опубликовано 6 сентября, 2011 · Жалоба Все таки правильно тут советовали, что начинать знакомство с новой архитектурой используя чью-то библиотеку неправильно, т.к. наступаете не только на собственные грабли, но еще и на чужие. Зато сколько интересного можно откопать! :rolleyes: Во первых, есть неплохие примеры. Во вторых, длительный опыт ковыряния чужих некомментированных исходников позволяет адекватно воспринимать код и даже находить в нём ошибки (а в CMSIS-е их хватает). Я сначала пробегаюсь по используемым функциям, смотрю, что в них и как сделано, и что вообще стоит из этого использовать, и ТОЛЬКО ПОСЛЕ ЭТОГО подрубаю к своему проекту. Зато нескучно. И пусть в меня кинут тапком :smile3046: З.Ы. а описания на асме __disable_interrupt я так и не раскопал :( Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KRS 0 6 сентября, 2011 Опубликовано 6 сентября, 2011 · Жалоба З.Ы. а описания на асме __disable_interrupt я так и не раскопал :( у IAR это intrinsic, которая просто вставляет CPSID I Exceptions у этой инструкции нет! А может вы в непривилегированном режиме? тогда эта инструкция игнорируется. В любом случае лучше посмотреть содержимое регистров под отладчиком после запрещения прерываний, ну fault отловить. Для отладки достаточно такого обработчика: void fault(void) { __no_operation(); } и брекпоинт поставить, потом в асме сделать пару шагов и вы вернетесь в то место где случился fault Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться