Раз проблемы нет с обычными прерываниями и появляются с аппаратными, значит регистры при прерываниях неправильно (или вообще не) сохраняются-восстанавливаются.
В регистре MSTATUS есть биты MPPOP и MPOP, которые отвечают за то, какое было выполнено прерывание - программное(0) или аппаратное(1).
Если ты для запрета/разрешения прерываний пишешь значения в MSTATUS со сброшенными MPPOP, MPOP - то это может сбить механизм возврата из прерывания. Например вошел в прерывание HPE, там как-то сбросил MPOP - и выход из прерывания будет уже программный (с извлечением регистров из программного стека).
Ну - я во всяком случае так понимаю работу этих MPPOP, MPOP
Я у себя для запрета/разрешения прерываний использую прямую запись в MSTATUS, при этом в MPPOP,MPOP напрямую пишу 0(Если в проекте поддержка программных прерываний) или 1(если прерывания HPE).
как-то так:
// Project CPU config:/**====================================================================================**
* @brief CH5xx PFIC and privilege configuration
**====================================================================================**/
#define CPU_CONF_PRIVILEGE_LEVEL 3 /**< @brief CPU privilege work mode (3(Machine), 0(User - do not use, this mode dont have glodal interrupt disable/enable control ???)) */
#define CPU_CONF_PFIC_NEST_LEVEL 2 /**< @brief Interrupt nesting level (1(No nesting), 2(2-level)) */
#define CPU_CONF_PFIC_HPE_ENABLE 1 /**< @brief Interrupt HPE(Hardware Prologue/Epilogue) (0(Disable), 1(Enable)) */
...
/**==========================================================================**
* @brief Static value for write to MSTATUS:
* bit 24,23 - MPPOP,MPOP - stack flags for sub-active and active(current/nested) interrupts
* bit 12,11 - MPP privileged mode
**==========================================================================**/
#define CPU_CONF_MSTATUS_STATIC_VAL (((CPU_CONF_PRIVILEGE_LEVEL)<<11) | ((CPU_CONF_PFIC_HPE_ENABLE)?0:0x18000000))
static C_INLINE void CPU_RT_Lock(void) /**< @brief Disable all interrupts (lock CPU) */
{
#if ( CPU_CONF_PRIVILEGE_LEVEL == 3 ) /* Machine level */
// __bitclr_MSTATUS(0x08);
__set_MSTATUS(CPU_CONF_MSTATUS_STATIC_VAL | 0x80);
#else
#error "Unsupported privilege level"
#endif
#if ( defined(DCPU_CORE_RISCV_WCH_V2A) || defined(DCPU_CORE_RISCV_WCH_V2C) )
__nop(); // Fill 2-level flow instruction line for QingKe V2A,V2C
#elif ( defined(DCPU_CORE_RISCV_WCH_V3A) || defined(DCPU_CORE_RISCV_WCH_V3B) || defined(DCPU_CORE_RISCV_WCH_V3C) \
|| defined(DCPU_CORE_RISCV_WCH_V4A) || defined(DCPU_CORE_RISCV_WCH_V4B) || defined(DCPU_CORE_RISCV_WCH_V4C) || defined(DCPU_CORE_RISCV_WCH_V4F) )
__nop(); __nop(); // Fill 3-level flow instruction line for QingKe V3A,V3B,V3C,V4A,V4B,V4C,V4F
#else
#error "Unsupported CPU core"
#endif
}
static C_INLINE void CPU_RT_Unlock(void) /**< @brief Enable all interrupts (unlock CPU) */
{
#if ( CPU_CONF_PRIVILEGE_LEVEL == 3 ) /* Machine level */
// __bitset_MSTATUS(0x08);
__set_MSTATUS(CPU_CONF_MSTATUS_STATIC_VAL | 0x88);
#else
#error "Unsupported privilege level"
#endif
}
static C_INLINE ufast_t CPU_RT_LockStatus(void) /**< @brief Get CPU lock status (0x08 - CPU unlocked (interrupts enabled), 0x00 - CPU locked (interrupts disabled)) */
{
#if ( CPU_CONF_PRIVILEGE_LEVEL == 3 ) /* Machine level */
return __get_MSTATUS() & 0x08;
#else
#error "Unsupported privilege level"
#endif
}
static C_INLINE void CPU_RT_LockRestore(ufast_t lock_state) /**< @brief Restore CPU lock state, gived by CPU_RT_LockStatus() */
{
#if ( CPU_CONF_PRIVILEGE_LEVEL == 3 ) /* Machine level */
if ( lock_state )
CPU_RT_Unlock();
else
CPU_RT_Lock();
#else
#error "Unsupported privilege level"
#endif
}
-
- Спасибо. Проверю. В этом проекте, использую два типа блокировки прерываний: Nikolay_Po(170 знак., Сегодня, 07:24)