Как избежать дублирования кода между похожими ISR? - PullRequest
0 голосов
/ 24 марта 2009

У меня есть две подпрограммы обработки прерываний (ISR), которые в основном делают то же самое вещь, но каждый обрабатывает прерывание от другого устройства (хотя устройства того же типа). Следовательно, логика одинакова, но они обращаются к разным регистрам ЦП и ячейкам памяти.

В качестве простого примера рассмотрим следующий код:

extern volatile unsigned int dev1_rx_buffer;
extern volatile unsigned int dev2_rx_buffer;

volatile unsigned char data;

void __attribute__((__interrupt__)) _dev1_interrupt(void)
{
    /* Clear interrupt flag */
    dev1.IF = 0;

    if (dev1.IS_FULL) {
         /* Read data from device */
         data = dev1_rx_buffer;
    } else {
         /* do something else using registers of device 1 */
    }
    /* More stuff using registers of device 1 */
}

void __attribute__((__interrupt__)) _dev2_interrupt(void)
{
    /* Clear interrupt flag */
    dev2.IF = 0;

    if (dev2.IS_FULL) {
         /* Read data from device */
         data = dev2_rx_buffer;
    } else {
         /* do something else using registers of device 2 */
    }
    /* More stuff using registers of device 2 */
}

Как я могу избежать дублирования кода с ограничениями, которые применяются к ISR (т.е. я не могу передать параметры в ISR, и следует избегать вызовов функций из-за их накладных расходов).

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

Ответы [ 4 ]

6 голосов
/ 24 марта 2009

В таких случаях у меня обычно есть интерфейс ISR (точка входа вектора), устанавливающий указатель на специфический для устройства блок, а затем вызывающий общий код с указателем на этот блок.

Грубо (не заботясь о синтаксисе ISR и т. Д.)

void __attribute__((__interrupt__)) Isr1(void)
{
   CommonISR(&dev1info);
}

void __attribute__((__interrupt__)) Isr2(void)
{
   CommonISR(&dev2info);
}

void CommonISR(Foo *devptr)
{
    devptr->count = 0;
    devptr->reset();
    etc...
}

dev1info и dev2info настраиваются / инициализируются при запуске; у них могут быть указатели на регистры HW и т. д.

2 голосов
/ 24 марта 2009

Почему бы вам не использовать встроенную вспомогательную функцию, которая получает указатели на устройство и буфер?

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

Вы также можете использовать макрос, но, имхо, это нехорошо делать для функций так долго.

2 голосов
/ 24 марта 2009

Если они обрабатывают устройство одного типа, вполне разумно иметь только один обработчик прерываний, обрабатывающий несколько прерываний. Вы можете проверить, какой флаг был установлен в верхней части и продолжить оттуда. Однако я не рекомендовал бы это, если два обработчика прерываний предназначены для разных типов устройств и имеют одинаковый логический поток.

1 голос
/ 24 марта 2009

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

#define __CONCAT(a,b)    a ## b

#define ISR_DECLARE(name) \
\
void __attribute__((__interrupt__)) _CONCAT(name,_interrupt)(void) \
{ \         
    /* Clear interrupt flag */ \
    name.IF = 0; \
    \
    if (name.IS_FULL) \
    { \
        /* Read data from device */ \
        data = _CONCAT(name, _rx_buffer); \
    } \
    else \
    { \
        /* do something else using registers of device 1 */ \
    }\ 
    /* More stuff using registers of device 1 */ \

}

и затем:

ISR_DECLARE(dev_1)

ISR_DECLARE(dev_2)

Но я бы настоятельно рекомендовал сначала проверить, оптимизирует ли ваш компилятор код, используя inline, как предлагалось в предыдущих постах.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...