Переношу код с 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;
}
{
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);
}
{
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). Или я что-то недопонял?