Suppose I want to make a static library (.a file), which contains an ISR. That library should be used by many AVR MCUs, but each device has different ISR vector name, so it cannot be defined in .c file. Is it correct according to C conventions to define the ISR in the header file?
-
4\$\begingroup\$ @StefanWyss programming questions related to MCUs are often answered here. This one might be borderline as it could be reworded into a more general programming question. \$\endgroup\$– ArsenalAug 14, 2019 at 8:29
-
\$\begingroup\$ @StefanWyss It is perfectly on-topic here, see What topics can I ask about here?. "The writing of firmware for bare-metal or RTOS applications" is explicitly on-topic. As are questions about Verilog, VHDL etc. \$\endgroup\$– LundinAug 14, 2019 at 9:17
-
\$\begingroup\$ Precompiled libraries are severely disadvantageous, are you trying to hide code from your users? You can have multiple named ISRs call a common core, if there are no name conflicts the linker will use the one listed in the vector table. If there are name conflicts you either need to put #ifdef guarded wrappers in something read by the user's compiler, or if the differences go beyond that it may make sense to have a different build for each major target variety. But please reconsider the whole idea of making a static library! We're replacing a peripheral chip because it requires such. \$\endgroup\$– Chris StrattonAug 14, 2019 at 13:33
-
\$\begingroup\$ I'm voting to close this question as off-topic because it belongs to stackoverflow and the "belongs on the other site" button doesn't give a stackoverflow choice. \$\endgroup\$– Oleg MazurovAug 25, 2019 at 0:26
2 Answers
Your vector table will always be project-specific. The correct approach is to define the ISR inside the .c file of the relevant driver handling the hardware that the ISR belongs to.
If you need to expose the ISR name to the file containing the vector table, you should add a function declaration of the ISR in the .h file of the driver.
For example, if you are writing code that uses a UART peripheral of a specific MCU - lets call it "AVR123", then you should create a driver named something like "avr123_uart.h" + "avr123_uart.c". The ISR will be located in avr123_uart.c and all code communicating with the ISR will be there too.
If you need portable or platform-independent code, you can create a hardware abstraction layer (HAL) on top of the driver. Meaning you'll have a file "uart.h" which declares some functions uart_init, uart_read, uart_write and so on. These functions are then implemented in avr123_uart.c. We may say that "avr123_uart" inherits "uart.h" and that "uart.h" is an abstract base class.
The application call only includes uart.h but links the MCU-specific driver. That way you don't have to change a thing in the application code if changing hardware. Simply link the relevant driver.
Under no circumstances should you "splatter" ISR implementation all over the code, or place them in files that have nothing to do with the given hardware. No other code than the driver where the ISR resides should communicate with it.
See Avoiding global variables when using interrupts in embedded systems.
My answer doesn't answer the actual question but proposes a different solution.
I wouldn't try to include the link to the actual ISR into the library.
Instead write code which is supposed to be called by the actual ISR and let the people using your library handle the implementation of the ISR.
This could also mean, that your library is no longer device dependent, as you offload those parts to the outside of the library.
You must document the interface to your library very well, so people know what your function requires to work correctly - if you have any part where you think "Oh that's just logical" - write it down. You're so involved with the library that you don't realize how different it might be for a "simple" user.
-
\$\begingroup\$ And what if the content of the ISR is also device dependent (for example writing or reading registers)? \$\endgroup\$– Tekl7Aug 14, 2019 at 9:04
-
\$\begingroup\$ @Tekl7 Allow the people using your library to set
#define input_register portb
. This is how some other libraries work. The user connect things together while the library is a black box doing what it should do. The black box doesn't try to figure out what registers are outputs/inputs. \$\endgroup\$ Aug 14, 2019 at 12:34 -
\$\begingroup\$ @HarrySvensson If the ISR is inside .c file and then the static library is created, people using this library cannot set their register because the library code is already compiled. They could do so if they include .c file to their project and compile that together with the rest of their code. But this is not the case of static library. \$\endgroup\$– Tekl7Aug 14, 2019 at 16:58
-
\$\begingroup\$ @Tekl7 Slightly off topic, but I'd never use pre-compiled code mainly because of what you just described, and secondly because I don't know what's going on under the hood and I can't optimize it for speed/space (I don't know which you've optimized for). - I hope you can find people who want to use your code. Good luck. \$\endgroup\$ Aug 14, 2019 at 18:14
-
1\$\begingroup\$ @Tekl7 there is no real problem with that. Just tell the user which function they have to call for which device. Or you could go and create an initializing function which figures out which device is being used (some MCUs have identification) and then handle it in your function. It's a bit hard to give better advice as I don't know what layer you are targeting with your library (HAL, Device or Application layer). \$\endgroup\$– ArsenalAug 15, 2019 at 5:56