Есть код, который использует внешние прерывания. Примерно такой
CODE
template<class T>
constexpr T* bitbandAddr(T *addr, unsigned bit); // возвращает адрес в bitband-области для адреса addr и бита bit
struct ExternalInterrupt {
unsigned no;
// ...
static bool checkIfInterrupt(unsigned no) { return *bitbandAddr(&EXTI->PR, no); }
bool checkIfInterruptAndClear() {
bool r = checkIfInterrupt(no);
if ®
*bitbandAddr(&EXTI->PR, no) = 1;
return r;
}
};
extern "C" void EXTI9_5_IRQHandler() {
/* 1 */
for (unsigned i = 5; i < 10; ++i)
if (ExternalInterrupt::checkIfInterrupt(i))
interrupts.exti[i].fire(); // вызов коллбэка, если он есть
}
void onIntA() { // этот коллбэк связан с interrupts.exti[8]
if (ei[0].checkIfInterruptAndClear()) {
/* 2 */
}
}
void onIntB() { // этот коллбэк связан с interrupts.exti[9]
if (ei[1].checkIfInterruptAndClear()) {
/* 3 */
}
}
Оба прерывания настроены на изменение фронта на входе.
По факту иногда код пропускает изменение фронта. Сделал инвертирование контролек в некоторых местах, оказалось что иногда в /* 1 */ оно попадает, а в /* 2 */ или /* 3 */ - нет.
Переписал функции checkIfInterruptXXX без использования bitband (и больше ничего не трогал) - все стало хорошо. Регистр EXTI->PR типа rc_w1 (чтение, сброс бита записью 1). bitband тут собственно не нужен, поставил в свое время по инерции. Но не ясно, почему с ним работает как-то избирательно.
Никто с подобным не сталкивался?
Сообщение отредактировал IgorKossak - Jul 1 2015, 06:01
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!