This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
I am using CCS 3.3 for the TMS320F28335. I also use the DSP-BIOS, TI's DPS library. The code is an adapted version of TI's example DC-AC single phase inverter (SPRC303.zip).
I have added code to handle CAN and SCI devices which use DSP-BIOS for intertask communication.
Everything works fine until I add a C function call to the PWM interrupt handler written in assembly code (DCAC-ISR.asm). I pass a pointer to a variable to the C function without any code in the body of the function (empty function). When an interrupt occurs, the function was called, with the variable being pushed in and popped out of ISR stack, then when the code exits this ISR, the stack pointer was wrong, and eventually it goes to BIOS function FXN_F_selfLoop().
In CAN and SCI interrupt handlers, which are written in C, I call other functions without any problem. Is there something peculiar to the DCAC-ISR.asm (ISR_Init(), ISR_Run()) that may have violated the C function's calling rules?
I don't have the source code but it seem that adding the C function inside the assembly hand coded ISR disrupts the C running environment. Usually two things can go wrong in such a case: some of the registers used by the ISR are not saved and their content is lost after returning from the ISR or the stack pointer is not properly aligned after entering the ISR.
When the ISR is written in C and declared using the interrupt keyword, the compiler takes care of everything under the hood, saving all the registers used within the ISR and restoring the proper alignment through the ASP/NASP instructions: I guess this is the reason why your C language ISRs are working. You can see this watching the assembler generated by the compiler inlined with your C code (mixed Source/ASM mode in Code Composer): before actually executing your code, the compiler adds a prologue in which it restores the stack pointer alignment (ASP instruction) and, if needed, pushes on the stack the registers which are going to be used inside the ISR. Of course an epilogue is equally added before executing IRET to restore things as they were upon entering into the ISR.
Being the C function empty and a pointer being pushed on the stack it seems that the problem lays in the stack alignment: when pushing a 32 bit value on the stack (like your pointer and the return address of the called function as well) the stack pointer must be aligned on an even address, failing to do so the subsequent pop will result in a incorrect value.
Check if values are pushed on the stack with the correct alignment and if all registers used within the ISR are saved and then properly restored. If not, use the assembly code generated by the C compiler as a hint and try to mimic the same behaviour in your own code: probably just setting the correct stack pointer alignment is enough to make the function call work.
Thank you for your detailed and knowledgeable reply.
I was thinking along the same line, so I did experiment with creating the interrupt handler in C, and configuring DSP/BIOS to take the interrupt using dispatcher (i.e., the bios would intercept the interrupt, did context switch (pushed all registers in stack) then called the ISR). The C ISR called the assembly code (with LRETR, instead of IRET at the end) which used no stack. The exact same problem occured.
And I suspected as you did, that there was stack alignment problem, but I assumed that the BIOS dispatcher should take care of that. Maybe I was wrong in that assumption.
I would really appreciate more input from you and others, especially those from TI who were more knowledgeable about the DSP/BIOS than me :-)!