I've looked through both <avr/io.h>, and <avr/iom328p.h> for a macro which defines the ISR macro, as well as the datasheet for the ATmega328P and I have yet to find anything. All I can find is external sources saying that you make an interrupt service routine by writing
ISR (/*<ISR-vector>*/)
{
/* ISR code here */
}
but I haven't found its source/definition anywhere.
The macro is defined in avr/interrupt.h, which you can view for example here (github mirror, not an official source). In case you were looking for it to understand how it works i also recommend you read about interrupt and signal function attributes here, because all that the ISR macro does is define a function with a specific attribute and name.
Related
I am starting on learning programming Atmel SAMD devices using ASF, and trying to do a simple test interrupt application. I have found this source from Microchip about interrupts.
In this code snippet, it populates a configuration struct and then attaches it to the interrupt channel. Three macros, BUTTON_0_EIC_PIN, BUTTON_0_EIC_MUX and BUTTON_0_EIC_LINE, are predefined macros specific to the board. I want to attach interrupt to a regular, non-predefined pin, in such case, what the syntax would be?
void configure_extint_channel(void)
{
struct extint_chan_conf config_extint_chan;
extint_chan_get_config_defaults(&config_extint_chan);
config_extint_chan.gpio_pin = BUTTON_0_EIC_PIN;
config_extint_chan.gpio_pin_mux = BUTTON_0_EIC_MUX;
config_extint_chan.gpio_pin_pull = EXTINT_PULL_UP;
config_extint_chan.detection_criteria = EXTINT_DETECT_BOTH;
extint_chan_set_config(BUTTON_0_EIC_LINE, &config_extint_chan);
}
I cannot seem to find any sources that provides a general syntax as opposed to using predefined board pins for buttons and leds, and I couldn't find the related section on either ASF documentation or the datasheet of the device.
Say, for instance, I want to use PA18, the 18th pin of port-A, that is connected to 2nd interrupt channel, EXTINT[2], what would the corresponding terms be in place of those three macros?
After creating an example project using a known board template, and digging into an uncomfortable amount of macros expanding to other macros, I have found the actual definitions.
// v----- peripheral group A, where EIC resides
BUTTON_0_EIC_PIN --> PIN_P<X><#>A_EIC_EXTINT<#>
BUTTON_0_EIC_MUX --> MUX_P<X><#>A_EIC_EXTINT<#>
BUTTON_0_EIC_LINE --> <EXTINT channel number>
For instance PA18 connected to EXTINT2 would be:
PIN_PA18A_EIC_EXTINT2
MUX_PA18A_EIC_EXTINT2
2
My target device is an EFM32 Cortex-M3 based device. My toolchain is the official ARM GNU toolchain gcc-arm-none-eabi-8-2018-q4-major.
Everything works fine without LTO, but to make LTO work I have to mark all interrupt handler code with -fno-lto. I would like to get rid of this workaround.
The problem is, every interrupt handler is getting removed from the final binary. (I am checking with arm-none-eabi-nm --print-size --size-sort --radix=d -C -n file.out) This makes the resulting binary crash.
Digging deeper and after googling for similar problems:
I tried marking such functions as __attribute__((used)), __attribute((interrupt)) to no avail - the interrupt handlers are getting removed in spite of these attributes. (related Prevent GCC LTO from deleting function)
Found possibly related discussion https://bugs.launchpad.net/gcc-arm-embedded/+bug/1747966 - no solutions posted
Sample code from startup_efm32gg.c defines default interrupt handlers as such:
void DMA_IRQHandler(void) __attribute__ ((weak, alias("Default_Handler")));
/* many other interrupts */
void Default_Handler(void) { while (1); }
The same problem happens for regular interrupt handler definitions as well (as in, no aliases and not weak)
It might be related but it seems that weak symbols are misbehaving in LTO mode in the same way.
Thank you in advance for any ideas!
Edit: See my reply to the marked answer for a full solution!
Where are your interrupt handlers referenced from? Just like unreferenced static functions and objects will be removed from a single translation unit, external ones that are unused will be removed during LTO. In order to prevent this (and in order for your program to be valid anyway in the abstract model) there needs to be some chain of references, starting from the entry point, leading to the functions and objects; if none exists, then you're not actually using them in your program.
If the reference is from a linker script or asm source file, it's possible that this is a bug in LTO, and it's not seeing the references like it should. In this case you might be able to apply a hack like __attribute__((__used__)) to the affected function definitions. Alternatively you could make fake references to them, e.g. by storing their addresses to dummy volatile objects or using their addresses in input constraints to empty inline asm blocks. As yet another alternative, there may be a way to redo whatever you're doing with asm source files or linked scripts to make your interrupt table at the C level, with appropriate structs/arrays in special sections, so that the compiler can actually see the references without you having to fake them.
I have a STM32 BluePill Board (STM32F103C8 with 8Mhz Quarz) and tried to upload a small blink program made with LibOpenCM3 and FreeRTOS. But for some reason FreeRTOS hangs in vTaskStartScheduler() the sys_tick_handler also doesn't do anything.
I didn't use a debugger and just placed a gpio_reset inside the sys_tick_handler function and after the vTaskStartScheduler call to test if the code gets executed but it didn't seem to do anything and I can't figure out why.
The code is available here: https://gitlab.com/feldim2425/stm32-testing
UPDATE: I debugged with OpenOCD and fount out that it jumps into the hard_fault_handler
UPDATE 2: The UsageFault-Status-Register has the NOCP bit set
Ok I found the issue. Many examples seem to rely on compiler optimization to directly link the vPortSVCHandler, xPortPendSVHandler and xPortSysTickHandler from FreeRTOS into the vector table if you call them inside your own handler vector implementation for sv_call_handler, pend_sv_handler and sys_tick_handler. But that didn't work here, the functions have to be called directly by the processor.
Adding these 3 Lines to the bottom of the FreeRTOSConfig.h file and removing my own function declarations for the vectors fixed the problem:
#define vPortSVCHandler sv_call_handler
#define xPortPendSVHandler pend_sv_handler
#define xPortSysTickHandler sys_tick_handler
The fix is described here: https://www.freertos.org/FreeRTOS_Support_Forum_Archive/January_2012/freertos_LPC1768_FreeRTOS_4964917.html
It is described for CMSIS but the only difference (in this case) are just the names of the vectors/handler functions.
I'm using libopenCM3 for my project on STM32F4. I've used previously Standard Peripheral Library and newer Hardware Abstraction Layer developed by ST.
In these libraries you have assembly file (startup file) with the definition of vector table.
This is what I'm missing for libopenCM3. Can you please show me where to find this table? Or is it done some another way?
I really need to use interrupts in my project.
Thanks.
Can you please show me where to find this table?
Interrupt vector table is located in lib/cm3/vector.c:
__attribute__ ((section(".vectors")))
vector_table_t vector_table = {
...
.irq = {
IRQ_HANDLERS
}
};
And IRQ_HANDLERS for STM32F4 are defined in lib/stm32/f4/vector_nvic.c file. This file will be available after building the library (it's generated with irq2nvic_h script). In this file you can see something like this:
#define IRQ_HANDLERS \
[NVIC_DMA1_STREAM0_IRQ] = dma1_stream0_isr, \
[NVIC_ADC_IRQ] = adc_isr, \
...
Functions like dma1_stream0_isr() and adc_isr() are defined like this:
#pragma weak adc_isr = blocking_handler
So these functions are just blocking handlers by default. But they are defined as weak, so you can easily redefine them in your code.
Or is it done some another way?
As discussed above, it boils down to next: you just need to define interrupt handler function (ISR) with correct name in your code, and your function will be placed to interrupt vector table automatically.
For instance, if you want to handle UART2 interrupt, just implement usart2_isr() function somewhere in your code. For the whole list of ISR function names refer to include/libopencm3/stm32/f4/nvic.h. But those names are usually pretty straight-forward.
Also, check out the libopencm3-examples project. The chances are you will find just what you need there.
I'm working with FreeRTOS on an STM32 (Cortex-M3), and using the CMSIS library from ST to bootstrap everything.
The CMSIS library defines the weak symbol SVC_Handler in the startup ".s" file. It must be overridden somewhere in order to get your ISR in the interrupt vector table. FreeRTOS defines vPortSVCHandler, which is the ISR I want to have handle the SVC interrupt.
I would like to "glue" the two together using my application code (i.e. w/o modifyng FreeRTOS or the CMSIS source code). I thought an alias would be the right tool for the job, so I tried this (in a separate source file, main.c):
void SVC_Handler(void) __attribute__ ((alias ("vPortSVCHandler")));
That results in: error: 'SVC_Handler' aliased to undefined symbol 'vPortSVCHandler'
Turns out, according to GCC documentation here http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html, in order to use the alias attribute, you cannot alias a symbol outside of the translation unit. So I thought I'd try to extern the symbol into main.c like so:
extern void vPortSVCHandler( void ) __attribute__ (( naked ));
void SVC_Handler(void) __attribute__ ((alias ("vPortSVCHandler")));
This generates the same error. Any suggestions???
I would really like to avoid modifying either of the libraries. I know I could write a function SVC_Handler that simply calls vPortSVCHandler, but that could add unnecessary overhead to the ISR (possibly depending on optimization settings). Note: The FreeRTOS examples accomplish this via a custom startup file. I'm looking for a way to do this from C or my linker script.
Compiler Version: gcc version 4.5.2 (Sourcery G++ Lite 2011.03-42)
Target: arm-none-eabi
You should be able to do this either with a linker script, or by passing the appropriate option to the linker, eg. for ld, --defsym=SVC_Handler=vPortSVCHandler
See the binutils documentation for more information on the ld --defsym option, and assignments in linker scripts
I think the problem with alias is, that it expects a declared and defined function, since it is just an alias. You want to use it as a forward-declaration of another function. I got a similar thing to work like that:
void SVC_Handler(void) asm("vPortSVCHandler");
This renames the entry point of the SVC_Handler, and if you then do not define it, it should find vPortSVCHandler.
See: https://gcc.gnu.org/onlinedocs/gcc/Asm-Labels.html
Another solution that I gleaned from one of the FreeRTOS examples is to add the following to your FreeRTOSConfig.h ...
/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
standard names - or at least those used in the unmodified vector table. */
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
#define xPortSysTickHandler SysTick_Handler
The original file is from FreeRTOS/Demo/CORTEX_M0_LPC1114_LPCXpresso/RTOSDemo/Source/FreeRTOSConfig.h which also integrates the CMSIS system clock into the config. A very nice starting point for a CMSIS/FreeRTOS project.
I'm pretty sure SVC handler is only used by FreeRTOS
at initial startup, so adding an indirection exception
handler isn't going to hurt performance (but its
ugly). Best ask this on the FreeRTOS forum, response
there is usually great.
Hope this helps, Best Regards, Dave