The IRQ's seem to work only when the supporting OS code is removed (CH_IRQ_PROLOGUE & CH_IRQ_EPILOGUE). I have tested the code by disabling the interrupts and it seems to work fine without any issues. The moment i enable the interrupts with the supporting os code it causes a HardFault. i have tried increasing the PORT_INT_REQUIRED STACK macro to 128. To ensure that there is no stack overflow, i enabled the thread fill option and checked the entire stack at the instance of HardFault and only about 1/3rd of the allotted stack was being used. Both the stack pointed to by msp and psp do not overflow. I will give you a complete run down of the registers so that you may be able to help me zero in on the issue. Right now i'm using a dummy ISR which just clears the interrupt flag and does nothing else. This is the result of "info reg" at the instance of HardFault.
Code: Select all
r0 0x20001370 536875888
r1 0x2000172c 536876844
r2 0x1c094710 470370064
r3 0x0 0
r4 0x0 0
r5 0x0 0
r6 0xffffffcb -53
r7 0x8 8
r8 0x0 0
r9 0x0 0
r10 0x0 0
r11 0x0 0
r12 0x8000000 134217728
sp 0x20000800 0x20000800
lr 0xffffffed -19
pc 0x1c094710 0x1c094710
xPSR 0x3 3
Weirdly PC gets set to an out of bound address. I suppose this happens during the exception exit sequence. Since the value in r0 is a reference to a thread
Code: Select all
0x20001370 <_ZN2AX12motor_threadE+864>: 0x00000000
Now if i set the breakpoint at the HardFault_Handler code, i get the following output
Code: Select all
r0 0x0 0
r1 0x0 0
r2 0x0 0
r3 0x0 0
r4 0x0 0
r5 0x0 0
r6 0xffffffbc -68
r7 0x8 8
r8 0x0 0
r9 0x0 0
r10 0x0 0
r11 0x0 0
r12 0x8000000 134217728
sp 0x20000800 0x20000800
lr 0xffffffed -19
pc 0x8001bee 0x8001bee <HardFault_Handlerimpl>
xPSR 0x41000003 1090519043
The Process and stack sizes are 0x800 each.
I dont understand what is happening. Initially i thought its my code with all the delegates and IRQ callback trickery, but even a simple ISR such as below is causing issues.
Code: Select all
void USART3_IRQHandlertemp(void)
{
if(USART_GetITStatus(USART3,USART_IT_IDLE))
{
USART_ClearITPendingBit(USART3,USART_IT_IDLE);
}
}
I thought maybe interrupts have high priority than the OS SVC_Call interrupt. But setting the priority to above 4 doesnt seem to make any difference whatsoever.
Here is how my main function looks like.
Code: Select all
int main()
{
board::init();
chibios_rt::System::init();
AX::init();
chibios_rt::BaseThread::setPriority(LOWPRIO);
while(1)
{
GPIOG->ODR ^= GPIO_Pin_14;
chThdSleep(MS2ST(1000));
}
}
Here is the board::init function and the AX::init refers to the thread init function defined in the last code block at the end.
Code: Select all
namespace board
{
void init()
{
//Initializing the Systick Timer
SysTick->LOAD = SYSTEM_CLOCK / CH_CFG_ST_FREQUENCY - (systime_t)1;
SysTick->VAL = (uint32_t)0;
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk |
SysTick_CTRL_TICKINT_Msk;
}
}
Here is the uart and dma thread.
Code: Select all
class : public chibios_rt::BaseStaticThread<1024>
{
protected:
using LEDgreen=GpioG<DefaultDigitalOutputFeature<13>>;
using LEDred=GpioG<DefaultDigitalOutputFeature<14>>;
using serial_parameters=
UsartPeripheral<Usart3DefaultPinPackage,PERIPHERAL_USART3>::Parameters;
using dma_inst=Dma1Channel4Stream1<Usart3RxDmaChannelInterruptFeature,
UsartDmaReaderFeature<Usart3PeripheralTraits>>;
using uart=Usart3<Usart3InterruptFeature>;
public:
void main() override
{
serial_parameters params;
//default baudrate is 9600
params.usart_parity=USART_Parity_Even;
SerialObj<uart,dma_inst> serial_obj(params);
AX2550<SerialObj<uart,dma_inst>> driver(serial_obj);
while(true)
{
GPIOG->ODR ^= GPIO_Pin_13;
chThdSleep(MS2ST(1000));
}
}
}motor_thread;
void init()
{
motor_thread.start(HIGHPRIO);
}
The above is just some sample code that i'm trying to test with. It works perfectly without the OS calls in the ISR but hangs when the ISR is enabled with the supporting os calls. I enabled all the debug checks in chconf and the ch.dbg.panic_msg doesnt report anything it just stays at 0x0. I presume something fishy is happening during the exception return sequence. Because when i set the breakpoint at the beginning of the HardFault_Handler shown below all the registers are zero except r6 which is loaded with "0xffffffbc" and upon continuing the execution from this point gdb reports this error "0x1c094710 in ?? ()". Could it be that the PC is being loaded with a wrong value instead of the exc_return.
Code: Select all
void __attribute__((naked)) HardFault_Handlerimpl(void) {
__asm volatile
(
" tst lr, #4 \n"
" ite eq \n"
" mrseq r0, msp \n"
" mrsne r0, psp \n"
" ldr r1, [r0, #24] \n"
" ldr r2, handler2_address_const \n"
" bx r2 \n"
" handler2_address_const: .word prvGetRegistersFromStack \n"
);
}
void prvGetRegistersFromStack(uint32_t *pulFaultStackAddress) {
volatile uint32_t r0 __attribute__((unused));
volatile uint32_t r1 __attribute__((unused));
volatile uint32_t r2 __attribute__((unused));
volatile uint32_t r3 __attribute__((unused));
volatile uint32_t r12 __attribute__((unused));
volatile uint32_t lr __attribute__((unused)); /* Link register. */
volatile uint32_t pc __attribute__((unused)); /* Program counter. */
volatile uint32_t psr __attribute__((unused)); /* Program status register. */
r0=pulFaultStackAddress[0];
r1=pulFaultStackAddress[1];
r2=pulFaultStackAddress[2];
r3=pulFaultStackAddress[3];
r12=pulFaultStackAddress[4];
lr=pulFaultStackAddress[5];
pc=pulFaultStackAddress[6];
psr=pulFaultStackAddress[7];
/* When the following line is hit, the variables contain the register values. */
for(;;) ;
}
Bear in mind that i am unable to execute the HardFault handler code as well by single stepping through the routine. It just gets stuck the "__asm volatile" line.
Probably the kernel is being preempted by an IRQ? is it possible for an IRQ with NVIC priority 8 to preempt the kernel? Although the Systick interrupt runs fine without any issues for hours.