How to watch for NVIC interrupts in application code

I have a prototype that logs analog data on an SD card. I already implemented USBMSD functionality, so that the user can connect the device to a PC and read out the data.

Now i am trying to launch USBMSD only if the device is connected to the PC with an USB-cable.
For that purpose I can poll the USB register, which works… however i would really prefer using interrupts.
Turns out that USBPhy_Target.cpp already contains NVIC_EnableIRQ(USB_IRQn); So the board actually generates the interrupts i could use for my purpose.

But I simply can not find any documentation how to use interrupts from the NVIC table and got stuck.
Can anyone get me on the right track please?

Mbed OS can work together with HAL Library code in STM32, which you may need to set the hardware interrupt and NVIC. Please refer to this link for more details.

Hello Peter,

As I can see your target is a MAX32630FTHR board.
The associated startup assembly file mbed-os/targets/TARGET_Maxim/TARGET_MAX32630/device/TOOLCHAIN_GCC_ARM/startup_max3263x.S defines dummy interrupt handlers for all interrupts generated by the MCU hardware.

  • Since those functions are defined as weak, if you define your own handler with the same name then it will be called on the associated interrupt event rather than the dummy one.

  • Another way how to setup your interrupt handler is to register the intended function with the NVIC_SetVector function.

For exaple in case of the GPIO_P0_IRQn interrupt Maxim does it in the mbed-os/targets/TARGET_Maxim/TARGET_MAX32630/gpio_irq_api.c file as below:

...
static void handle_irq(unsigned int port)
{
    uint32_t intfl, in_val;
    uint32_t mask;
    unsigned int pin;

    /* Read pin state */
    in_val = MXC_GPIO->in_val[port];

    /* Read interrupts */
    intfl = MXC_GPIO->intfl[port] & MXC_GPIO->inten[port];

    mask = 1;

    for (pin = 0; pin < MXC_GPIO_MAX_PINS_PER_PORT; pin++) {
        if (intfl & mask) {
            MXC_GPIO->intfl[port] = mask;    /* clear interrupt */
            gpio_irq_event event = (in_val & mask) ? IRQ_RISE : IRQ_FALL;
            gpio_irq_t *obj = objs[port][pin];
            if (obj && obj->id) {
                if ((event == IRQ_RISE) && obj->rise_en) {
                    irq_handler(obj->id, IRQ_RISE);
                } else if ((event == IRQ_FALL) && obj->fall_en) {
                    irq_handler(obj->id, IRQ_FALL);
                }
            }
        }
        mask <<= 1;
    }
}
...

...
void gpio_irq_0(void) { handle_irq(0); }
...

int gpio_irq_init(gpio_irq_t *obj, PinName name, gpio_irq_handler handler, uint32_t id)
{
...
    /* register handlers */
...
    NVIC_SetVector(GPIO_P0_IRQn, (uint32_t)gpio_irq_0);
...
}
...

You can setup and register a handler for the USB_IRQn interrupt in similar way. The handler can then check the USB_DEV_INTFL flags and other registers and take actions as needed. Make sure the handler is executed (finished) as quickly as possible.
After the handler is setup you can enable the given interrupt by calling

 NVIC_EnableIRQ(USB_IRQn);

Best regards, Zoltan

Thanks for both of you for the answer! Those helped me to get started with NVIC in general.
However it seems that void USBPhyHw::init() inside USBPhy_Maxim.cpp file already utilizes NVIC_SetVector function to register the _usbisr function to the USB interrupt. Furthermore _usbisr is defined as private.

If i am right(?) an NVIC interrupt can have only one interrupt handler function registered. If that is true, then i just can not run also a second user-defined function in case an USB interrupt occurs. So it seems i can not make any use of the USB_DEV_INTEN.vbus register bit of the MAX32630 chip.

Turns out the MAX32630FTHR has an onboard MAX14690 PMIC which has a register bit that keeps track if USB power is detected AND if that is a valid USB voltage. The PMIC can also generate an interrupt connected to P3_7 of the board, however the state of this pin does not change even if the register value of the PMIC updates when i plug/unplug the cable. So for some reason also this way does not seem to work.

Found a third possible way here. However the MAX32630FTHR’s pin definition does not contain any name for the VBUS pin that is located on the board…so i just can not make that an interrupt source…

Seems like i need to stick with the polling variant. :confused:

Hello,

USB cable has 5V, D+, D- and GND. Where do you have 5V connected?
Maybe you can connect 5V of USB cable to a free pin where you can use InterruptIn.
If pins of your board are not 5V tolerant or just for sure you can also use trasnsistor between 5V from the cable and the pin.

BR, Jan

Thanks for all the suggestions! Meanwhile i could make it work at last. Turns out the default configuration of the PMIC was the problem, so after reading documentation/code i could find a proper setup for the on-board MAX14690 and now the MCU can detect the interrupt signal on P3_7.