简体   繁体   中英

What is the proper way to process interrupts?

I am working on a project that requires USB communication. I'm using a Nuvoton NUC123 which runs an ARM cortex M0 core, with a speed of 48MHz, 20kb RAM and 64kb flash memory. The microcontroller implements a hardware interrupt whenever a USB endpoint gets data transmitted to it from the host, whether it's an Ack, Nak or a setup packet. The sample code supplied by the manufacturer is rather dirty, it involves switch-case-ing the endpoint to which the interrupt belongs and if it is a setup packet containing a class-specific request, it make a switch-case for every interface or endpoint that may be the target of the request.

I figured I can make things prettier by defining an array of structure:

typedef void UsbEventCallback(uint32_t u32IntFlag, uint32_t u32EPSTS);
typedef uint32_t UsbClassReqCallback(void);

typedef struct
{
    uint8_t ep_address;
    uint32_t config;
    uint32_t buff_offset;
    UsbClassReqCallback *usb_classreq_cb;
    UsbEventCallback *usb_event_cb;
} ATTR_PACKED EP_Config_Struct;

typedef struct
{
    uint8_t interface_id;
    UsbClassReqCallback *usb_classreq_cb;
} ATTR_PACKED Interface_Config_Struct;

extern const EP_Config_Struct EP_config_settings[TOTAL_NUM_ENDPOINTS];
extern const Interface_Config_Struct interfaces_config_settings[TOTAL_NUM_INTERFACES];

and then, in the interrupt callback I do:

switch(  req_destination )
{
case 1: //interface
    for ( uint8_t interface_index = 0 ; interface_index < TOTAL_NUM_INTERFACES ; interface_index++ )
    {
        if ( interfaces_config_settings[interface_index].interface_id == UsbDev.Setup.wIndex )
        {
            if ( interfaces_config_settings[interface_index].usb_classreq_cb == NULL )
                return FALSE;
            else
                return (*interfaces_config_settings[interface_index].usb_classreq_cb)();
        }
    }
    break;
case 2: //endpoint
    for ( uint8_t ep_index = 0 ; ep_index < TOTAL_NUM_ENDPOINTS ; ep_index++ )
    {
        if ( EP_config_settings[ep_index].ep_address == UsbDev.Setup.wIndex )
        {
            if ( EP_config_settings[ep_index].usb_classreq_cb == NULL )
                return FALSE;
            else
                return (*EP_config_settings[ep_index].usb_classreq_cb)();
        }
    }
    break;
}
return FALSE;

My questions are: Is it better to not actually make all these decisions and calling all these other functions in interrupt time? Am I better to just save the interrupt data and switch some flag on requiring the main thread to process the interrupt? How important is it to return from the callback as soon as possible?

What do you think is the correct architecture for such a program?

Thank you

It is hard to say without knowing precisely your application, but your interrupt handler looks quite reasonable.

Generally for multi-tasks systems it is advised to do the least possible in interrupt handlers, because while an interrupt is being handled the different tasks on the systems are not being scheduled any more. This can be a lot more complicated than that, especially when using interrupt priorities and interrupt nesting, but still the general idea is to avoid staying too long in interrupt handlers.

For your USB driver, I would select the appropriate endpoint/interface in the interrupt handler, then write the data received in the appropriate queue/array and finally trigger a flag/semaphore to signal that some data has been received. I would then parse the data received in a normal task rather than directly in the interrupt handler, to keep the interrupt handler minimal.

Not sure whether it's critical to keep busy ISR in your project but in principle interrupt handler should return as soon as possible. If i were you I would do following regarless of the situation.

Parse protocol in ISR and then feed data to a ring buffer as a parsed packets. Ring buffer may require the ability of variable length data peek/push/pop according the protocol. Then proceed time consuming work in main.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM