I've been stuck for a while on how to set up a callback when an exception occurs.
I have this test code:
void main()
{
long * bad = (long*)0x0A000000; //Invalid address
//When the following line gets executed
//it causes an error and the debugger sends me to an assembly file.
*bad = 123456789;
}
The assembly file that I am sent to looks like this(fragment of the real file):
.macro DEFAULT_ISR_HANDLER name=
.thumb_func
.weak \name
\name:
1: b 1b /* endless loop */
.endm
DEFAULT_ISR_HANDLER SRC_IRQHandler /*Debugger stops on this line*/
As I understand DEFAULT_ISR_HANDLER is a macro that defines an endless loop.
What I want to do is define my own function in a C file, that I could call when an exception occurs, instead of calling whats defined in the DEFAULT_ISR_HANDLER macro.
My question is, How would I define a macro, in that assembly, that calls an specific C function?
Hopefully I explained myself. Any information or direction around this topic is appreciated.
In case it's relevant I am using GCC ARM compiler v5.4_2016q3
Thanks,
Isaac
EDIT
I am using a Cortex-M3.
Until now I realized I was talking about processor exceptions. According to the datasheet there is a list with 16 exception types.
Apparently, the way it works is that all the exception types are being redirected to the macro, which in turn calls some thumb function and afterwards an endless loop(according to DEFAULT_ISR_HANDLER above in code).
What I would like to do is define my own function in a C file, for convenience, so every time any type of processor exception appear, I could control how to proceed.
You have two options:
Just define a C function with the void SRC_IRQHandler(void) signature and since the macro is defining the default handler as weak, your function will override the default handler in the linking stage.
There should be a place in your project where SRC_IRQHandler is placed in what is called a Vector Table in the Cortex-M3 architecture. You can replace the name of this function with your own C function and your function will be called when this interrupt (exception) happens.
The cortex-m family in general has well more than 16 exceptions there are those plus as many interrupts are implemented by that core, 32, 64, 128, 256. But it is all fundamentally the same. The way the cortex-m family works is they perform the EABI call for you if you will, they preserve some of the registers and then start execution at the address called out in the vector table done in such a way that you can have the address of a normally compiled C function directly in the table. Historically you needed to wrap that function with some code to preserve and restore the state and often instruction sets have a special return from interrupt, but the cortex-m they did a bit different.
so knowing that then the next question is how do you get that address in the table, and that depends on your code, build system, etc. Those handlers might be setup to point to an address in ram and maybe you are running on an RTOS and there is a function you call runtime to register a function for an exception then the RTOS changes the code or some data value in ram that is tied into their handler which essentially wraps around yours. or you are making the vector table in assembly or some other tool specific thing (although assembly is there, works and easy) and you simply count down the right number of entries (or add a hundred more entries so you can count down to the right entry) and place the name of your C function.
good idea to disassemble or do some other check on the result before running to double check that you have placed the handler address at the right physical address for that interrupt/exception.
Related
In an embedded project, I need to handle two different external interrupts with the same IRQ handler.
I don't want to change the interrupt vector table entries in the startup assembly directly, so that I have to stick with the predefined function names for the IRQ-handler routines (EXTI9_5_IRQHandler and EXTI15_10_IRQHandler).
For both interrupts, I need the exact same code to handle the interrupt.
Of course, I can program this like this:
void realIRQHandler (void)
{
//do some magic interrupt handling here
return;
}
void EXTI9_5_IRQHandler(void)
{
realIRQHandler(); //calls the real IRQ handler function
}
void EXTI15_10_IRQHandler(void)
{
realIRQHandler(); //calls the real IRQ handler function
}
This will eventually do what I want, but it will have an ordinary function call with the overhead of pushing and restoring the registers to the stack in each interrupt invocation.
Is there a way to replace those function calls in EXTI9_5_IRQHandler and EXTI15_10_IRQHandlersomehow and replace it with some unconditional branch or jump?
What would be needed at the end of realIRQHandler when returning/exiting?
Thanks!
Regards,
Felix
I don't want to change the interrupt vector table entries in the startup assembly directly
This is the problem. The only correct solution to the table is to modify the vector table. Therefore, the vector table shouldn't be defined in some startup file but in a file of its own. Either a linker script or a .c file (array of function pointers).
If you can't modify the vector table you can't do microcontroller programming on your tool chain. So if your compiler/linker can't provide an easy way to do this, you will have to customize the start-up code.
You can hint the compiler to inline realIRQHandler.
Otherwise you don't have anything on the stack in EXTI9_5_IRQHandler or EXTI15_10_IRQHandler, and realIRQHandler doesn't take any parameter nor returns anything. The only thing you'll push on the stack is the frame pointer.
Or, you can use goto.
Edit : depending on the optimisation level you chose, the compiler might just do a simple Branch Exchange, which is more or less a goto.
Something is not consistent: it seems like your interrupt handling duration is very critical (since you want to avoid function calls overhead), but at the same time you want to use the same function for two interrupts. Which means this function will need to do the "extra work" of checking whether the interrupt EXTI9_5 or ETXI15_10 was asserted. Wouldn't it be more efficient to have two different functions, one for each interrupt line ? Or at least pass the interrupt number as a parameter to realIRQHandler ?
Have a try by disassembling the compiled code, but the comment of #Groo is completely correct.
I don't think there should be any meaningful overhead here
If your function has same prototype as the interrupt handler (aka void realIRQHandler(void)) the compiler will not do any overhead.
thank you for taking the time to read.
Problem I'm seeing
I have:
main.h
that declares:
uint8_t u_newVar
I also have
foo.h
that writes:
extern uint8_t u_newVar
The application sits in a infinite while loop in main.c until an ISR occurs.
In the foo.c, said ISR calls a function within foo.c.
In that function (foo_function() if you will): 0x01 is written to the u_newVar.
Finally, after returning from the interrupt and back into the infinite while, there is a single "if" statement:
while(1){
if(u_newVar == 0x01){
uartTX_sendArray(st_uartRX_MessageContents->u_command, (sizeof st_uartRX_MessageContents->u_command));
uartTX_sendButtonPressData(st_uartRX_MessageContents->u32_value);
u_newVar = 0x00;
}
}
However, the application never enters the if. This "if" block will work if it is in foo.c, after the
u_newVar = 0x01;
line.
Stuff I tried
I looked at the compiled assembly, and what I found kind of stumps me.
If I look at the "if" in main, this is what I see:
So it loads the value from address: 0x011D from SRAM, which I can confirm is 0x01.
Then "CPI" to compare R24 directly to 0x01, which should obviously work.
Then "BREQ", branch if equal, and increment program counter twice to the uart function below. Also makes sense.
However this part is weird. Otherwise, use "RJMP" to jump to the instruction which it is currently at. Unless I'm mistaken, this would lock here for eternity?
So, remember when I mentioned that when I put the if block into the foo.c after the write to u_newVar? Yeah, that's not too interesting:
The "if" is supposed to be after "u_newVar = 0x01", but the compiler is too smart and optimizes it how. Which is why it always works there.
You forgot to tell the compiler that the variable might be modified asynchronously. Such as in a ISR.
volatile uint8_t u_newVar;
what your looking at is the output from the assembler, not the linked code.
The linker has info in the relocation table for that offset in the code (the data byte(s) of the instruction and what the actual target offset is. during the linking process (or for certain environments during the load processing) those data bytes will be updated to contain the correct value
I am building one of the projects and I am looking at the generated list file.(target: x86-64) My code looks like:
int func_1(var1,var2){
asm_inline_(
)
func_2(var1,var2);
return_1;
}
void func_2(var_1,var_2){
asm __inline__(
)
func_3();
}
/**** Jump to kernel ---> System call stub in assembly. This func in .S file***/
void func_3(){
}
When I see the assembly code, I find "jmp" instruction is used instead of "call-return" pair when calling func_2 and func_3. I am sure it is one of the compiler optimization and I have not explored how to disable it. (GCC)
The moment I add some volatile variables to func_2 and func_3 and increment them then "jmp" gets replaced by "call-ret" pair.
I am bemused to see the behavior because those variables are useless and they don't serve any purpose.
Can someone please explain the behavior?
Thanks
If code jumps to the start of another function rather than calling it, when the jumped-to function returns, it will return back to the point where the outer function was called from, ignoring any more of the first function after that point. Assuming the behaviour is correct (the first function contributed nothing else to the execution after that point anyway), this is an optimisation because it reduces the number of instructions and stack manipulations by one level.
In the given example, the behaviour is correct; there's no local stack to pop and no value to return, so there is no code that needs to run after the call. (return_1, assuming it's not a macro for something, is a pure expression and therefore does nothing no matter its value.) So there's no reason to keep the stack frame around for the future when it has nothing more to contribute to events.
If you add volatile variables to the function bodies, you aren't just adding variables whose flow the compiler can analyse - you're adding slots that you've explicitly told the compiler could be accessed outside the normal control flow it can predict. The volatile qualifier warns the compiler that even though there's no obvious way for the variables to escape, something outside has a way to get their address and write to it at any time. So it can't reduce their lifetime, because it's been told that code outside the function might still try to write to that stack space; and obviously that means the stack frame needs to continue to exist for its entire declared lifespan.
void __attribute__((__interrupt__, no_auto_psv)) _T1Interrupt(void) // 5 Hz
__attribute__ directive or macro is from GCC but __interrupt__ and no_auto_psv is not , it's specific to a hardware. So, how does GCC Compiler understand __interrupt__ and no_auoto_psv, I searched and didn't find any declaration in anywhere else.
So basically the _T1Interrupt function takes no argument and return nothing but has the above attribute?
In particular, these attributes are platform-specific extensions used in the Microchip XC16 compiler for 16-bit PIC24 and dsPICs.
Attributes are essentially extra information added to the parse tree of a compiler. They exist outside the C language semantics and are there to provide additional information that the compiler uses to act consistently with your expectations. In this case __interrupt__ tells it to treat the function as an ISR (with slightly different function prolog and epilog than a normal function: dsPIC ISRs use the RETFIE return instruction, vs. RETURN for normal functions), and no_auto_psv controls whether the compiler sets the PSVPAG register:
The use of the no_auto_psv attribute omits code that will re-initialize the PSVPAG value to the default for auto psv variables (const or those placed into space auto_psv). If your code does not modify the PSVPAG register either explicitly or using the compiler managed psv or prog qualifiers then the use of no_auto_psv is safe. Also, if your interrupt service routine (or functions called by your interrupt service routine) does not use any const or space auto_psv variables, then it is safe to use no_auto_psv.
(from http://www.microchip.com/forums/m394382.aspx)
The documentation for __attribute__() says:
GCC plugins may provide their own attributes.
So perhaps that's how it's being used in your situation.
What unwind said is true and the attritbutes are defined by the MPLAB extension for gcc. It's been a while since i've worked with microcontrollers so i can't provide more details on this front. However for your specific application (embedded c on pic micro-controller). The above is the proper way of declaring a function that is meant to implement an interrupt subroutine for timer 1. Interrupt subroutines rarely return anything, If you need to capture the value in the register i recommend you use the following structure as a global variable:
typedef struct T1OUT
{
int timer_register_value;
int flag;
} T1InteruptCapture;
The timer_register_value is the value you want out of your subroutine. While the flag value is memory lock that prevents the subroutine from over-writing your previous value. There are different ways of getting values out of your subroutine. I found this to be the easiest and the most time efficient. You can also look into implementing a mini-buffer. I recommend you avoid pointer with embedded C. I don't know if things have changed, in the last couple of years.
edit 1: MPLAB has some of the best documentation i've ever seen. I recommend you have a look at the one for your specific microcontroller. They provide sample code with great explanations.
edit 2: I not sure why you're using gcc. I would recommend you get the pic compiler from MPLAB. I believe it was called C30. and the associated .h file.
This question is mostly academic. I ask out of curiosity, not because this poses an actual problem for me.
Consider the following incorrect C program.
#include <signal.h>
#include <stdio.h>
static int running = 1;
void handler(int u) {
running = 0;
}
int main() {
signal(SIGTERM, handler);
while (running)
;
printf("Bye!\n");
return 0;
}
This program is incorrect because the handler interrupts the program flow, so running can be modified at any time and should therefore be declared volatile. But let's say the programmer forgot that.
gcc 4.3.3, with the -O3 flag, compiles the loop body (after one initial check of the running flag) down to the infinite loop
.L7:
jmp .L7
which was to be expected.
Now we put something trivial inside the while loop, like:
while (running)
putchar('.');
And suddenly, gcc does not optimize the loop condition anymore! The loop body's assembly now looks like this (again at -O3):
.L7:
movq stdout(%rip), %rsi
movl $46, %edi
call _IO_putc
movl running(%rip), %eax
testl %eax, %eax
jne .L7
We see that running is re-loaded from memory each time through the loop; it is not even cached in a register. Apparently gcc now thinks that the value of running could have changed.
So why does gcc suddenly decide that it needs to re-check the value of running in this case?
In the general case it's difficult for a compiler to know exactly which objects a function might have access to and therefore could potentially modify. At the point where putchar() is called, GCC doesn't know if there might be a putchar() implementation that might be able to modify running so it has to be somewhat pessimistic and assume that running might in fact have been changed.
For example, there might be a putchar() implementation later in the translation unit:
int putchar( int c)
{
running = c;
return c;
}
Even if there's not a putchar() implementation in the translation unit, there could be something that might, for example, pass the address of the running object such that putchar might be able to modify it:
void foo(void)
{
set_putchar_status_location( &running);
}
Note that your handler() function is globally accessible, so putchar() might call handler() itself (directly or otherwise), which is an instance of the above situation.
On the other hand, since running is visible only to the translational unit (being static), by the time the compiler gets to the end of the file it should be able to determine that there is no opportunity for putchar() to access it (assuming that's the case), and the compiler could go back and 'fix up' the pessimization in the while loop.
Since running is static, the compiler might be able to determine that it's not accessible from outside the translation unit and make the optimization you're talking about. However, since it's accessible through handler() and handler() is accessible externally, the compiler can't optimize the access away. Even if you make handler() static, it's accessible externally since you pass the address of it to another function.
Note that in your first example, even though what I mentioned in the above paragraph is still true the compiler can optimize away the access to running because the 'abstract machine model' the C language is based on doesn't take into account asynchronous activity except in very limited circumstances (one of which is the volatile keyword and another is signal handling, though the requirements of the signal handling aren't strong enough to prevent the compiler being able to optimize away the access to running in your first example).
In fact, here's something the C99 says about the abstract machine behavior in pretty much these exact circumstances:
5.1.2.3/8 "Program execution"
EXAMPLE 1:
An implementation might define a one-to-one correspondence between abstract and actual semantics: at every sequence point, the values of the actual objects would agree with those specified by the abstract semantics. The keyword volatile would then be redundant.
Alternatively, an implementation might perform various optimizations within each translation unit, such that the actual semantics would agree with the abstract semantics only when making function calls across translation unit boundaries. In such an implementation, at the time of each function entry and function return where the calling function and the called function are in different translation units, the values of all externally linked objects and of all objects accessible via pointers therein would agree with the abstract semantics. Furthermore, at the time of each such function entry the values of the parameters of the called function and of all objects accessible via pointers therein would agree with the abstract semantics. In this type of implementation, objects referred to by interrupt service routines activated by the signal function would require explicit specification of volatile storage, as well as other implementation defined restrictions.
Finally, you should note that the C99 standard also says:
7.14.1.1/5 "The signal function`
If the signal occurs other than as the result of calling the abort or raise function, the behavior is undefined if the signal handler refers to any object with static storage duration other than by assigning a value to an object declared as volatile sig_atomic_t...
So strictly speaking the running variable may need to be declared as:
volatile sig_atomic_t running = 1;
Because the call to putchar() could change the value of running (GCC only knows that putchar() is an external function and does not know what it does - for all GCC knows putchar() could call handler()).
GCC probably assumes that the call to putchar can modify any global variable, including running.
Take a look at the pure function attribute, which states that the function does not have side-effects on the global state. I suspect if you replace putchar() with a call to a "pure" function, GCC will reintroduce the loop optimization.
Thank you all for your answers and comments. They have been very helpful, but none of them provide the full story. [Edit: Michael Burr's answer now does, making this somewhat redundant.] I'll sum up here.
Even though running is static, handler is not static; therefore it might be called from putchar and change running in that way. Since the implementation of putchar is not known at this point, it could conceivably call handler from the body of the while loop.
Suppose handler were static. Can we optimize away the running check then? The answer is no, because the signal implementation is also outside this compilation unit. For all gcc knows, signal might store the address of handle somewhere (which, in fact, it does), and putchar might then call handler through this pointer even though it has no direct access to that function.
So in what cases can the running check be optimized away? It seems that this is only possible if the loop body does not call any functions from outside this translation unit, so that it is known at compilation time what does and does not happen inside the loop body.
This explains why forgetting a volatile is not such a big deal in practice as it might seem at first.
putchar can change running.
Only link-time analysis could, in theory, determine that it doesn't.