Stm32duino attachInterrupt(myISR) in my CAN library

Hi, I created a library for the STM32F103, bluepill CAN peripheral. I finally have the interrupt on RX working.

extern “C” void USB_LP_CAN1_RX0_IRQHandler(void) {
rxMsgLen = can.receive(&id, &fltIdx, rxData); // get CAN msg
};

For the last few days I have been trying to create a function similar to the Arduino ‘attachInterrupt(myISR)’. So that the user can name his own ISR function name.

void myISR(void) {
rxMsgLen = can.receive(&id, &fltIdx, rxData); // get CAN msg
};

Unfortunately, the solution remains elusive. Hopefully someone can help. Once this is worked out I will release the BP CAN lib to the public.

But won’t you conflict with STM32Duino’s USB driver layer then?

Also this function name is for the F1 series only, so keep that in mind.

Some ideas:

  • check the called HAL_PCD_IRQHandler() function and driver layer to see if there is already a easily user-definable function callback marked as weak, so that you don’t have to hook the interrupt and ‘coexist’ with the existing driver layer; many STM32 HAL drivers have such a feature
  • assuming USB is disabled in STM32Duino, statically override the USB_LP_CAN1_RX0_IRQHandler with your function, and in that function call into a user-provided function pointer (or better and more modern, a std::function object). This reproduces the attachInterrupt() function the closest. See the Arduino AVR implementation for reference.
  • more fancy: use the nested vectored interrupt controller (NVIC) functions to do run-time ISR reallocations. The interrupt vector table containing the function addresses of the interrupt service routines can be dynmically re-pointed to a section in RAM rather being hardcoded in flash at address 0. This allows maximum flexibility and changing the target ISR functions during runtime. Lookup functions like NVIC_SetVectorTable(), NVIC_SetVector() (example).

Thanks. I’ll research your suggestions.

maxgerhardt

After much todo I have finally been able to re-direct " USB_LP_CAN1_RX0_IRQHandler()" to a function of my naming. Thanks for your suggestions. It’s been quite an educational experience.

The technique I managed to finally get working is to move the vector table to SRAM and set the IRQ vector to my ISR.

I have another question. I declared a volatile array to preserve mem space for the new vector table. Is there a more ‘formal’ way to reserve memory for the table to keep new (future) variables from corrupting the it?

BTW, yes enabling CAN does mean no USB. My project is to implement a CAN bus on a 1985 Volkswagon Vanagon to send sensor data from a more modern Ford engine, etc. No need for USB. During development I’m using serial to USB adapter.

Thanks again for your help.

I now have it working as designed. No help is now needed on this.

By design this shouldn’t be necessary. If another driver decides to relocate the vector table to another SRAM buffer location, when everyone uses NVIC_SetVector, it will dynmically read out the current vector table address and write the function pointer at the correct address.

Geat :). This is also the most direct and straightforward way in my opinion.