2014-11-27 2 views
1

Я работаю над проектом, который требует USB-связи. Я использую Nuvoton NUC123, который запускает ядро ​​M0 с сердечником ARM со скоростью 48 МГц, 20 КБ оперативной памяти и флэш-памятью 64 КБ. Микроконтроллер реализует аппаратное прерывание всякий раз, когда конечная точка USB получает данные, переданные ему от хоста, будь то Ack, Nak или установочный пакет. Образец кода, предоставленный производителем, довольно грязный, он включает в себя коммутатор с конечной точкой, к которой относится прерывание, и если это пакет установки, содержащий запрос на конкретный класс, он создает случай переключения для каждого интерфейса или конечной точкой, которая может быть объектом запроса.Каков правильный способ обработки прерываний?

Я полагал, что я могу сделать вещи красивее, определив массив структуры:

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]; 

, а затем, в обратном вызове прерывания я:

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; 

Мои вопросы: ли это лучше на самом деле не принимать все эти решения и не вызывать все эти другие функции во время прерывания? Лучше ли просто сохранить данные прерывания и переключить флаг, требуя, чтобы основной поток обрабатывал прерывание? Насколько важно вернуться с обратного вызова как можно скорее?

Как вы думаете, правильная архитектура для такой программы?

Спасибо

+0

Вы можете рассмотреть отступы своего кода, чтобы одна строка не превышала 100 символов или даже лучше 80;) –

ответ

3

Трудно сказать, не зная точно, ваше приложение, но ваш обработчик прерываний выглядит вполне разумным.

Как правило, для систем с несколькими задачами рекомендуется выполнять минимальные действия в обработчиках прерываний, поскольку во время обработки прерывания различные задачи в системах уже не планируются. Это может быть намного сложнее, особенно при использовании приоритетов прерываний и вложенности прерываний, но все же общая идея заключается в том, чтобы избежать слишком длительного использования в обработчиках прерываний.

Для вашего USB-драйвера я бы выбрал подходящую конечную точку/интерфейс в обработчике прерываний, затем записывал данные, полученные в соответствующей очереди/массиве, и, наконец, запускал флаг/семафор, чтобы сигнализировать, что некоторые данные были получены. Затем я проанализировал данные, полученные в обычной задаче, а не непосредственно в обработчике прерываний, чтобы минимальный обработчик прерывания.

1

Не уверен, что важно сохранить занятый ISR в вашем проекте, но в принципе обработчик прерывания должен как можно скорее вернуться. Если бы я был вами, я бы сделал после него безрезультатную ситуацию.

Проанализировать протокол в ISR, а затем передать данные в кольцевой буфер в виде разобранных пакетов. В кольцевом буфере может потребоваться функция peek/push/pop переменной длины в соответствии с протоколом. Затем продолжим работу в основном.

Смежные вопросы