Страница 1 из 1

WinAVR, c++ и прерывания

Добавлено: Чт май 12, 2011 09:51:27
apwork
Подскажите как прикрутить обработчик прерывания к классу c++.
Компилятор - avr-gcc из WinAVR.

Re: WinAVR, c++ и прерывания

Добавлено: Чт май 12, 2011 10:04:25
avreal
Обработчик прерывания в любом случае должен быть статической функцией (если это функция класса), так как некому ему передать this.

У avr-gcc проблема в декораци имён функций классов в С++ и в способе задания обработчиков с фиксироанными именами __vector_NUMBER. Что-то пробовали сделать, чтобы можно было обработчик в классе делать, но, вроде бы, в релизах это так и не работает.

Надёжно -- только как дружественную фцнкцию. Тогда она и будет статическая и с нужными атрибутами и именем, а «классовый» обработчик может уже быть каким нужно.

Код: Выделить всё

#include <avr/interrupt.h>

ISR(TIMER0_OVF_vect);

class Foo {
    ...
private:
    friend void TIMER0_OVF_vect();
    inline void Isr();

    uint8_t cnt;
};

Foo foo;

void Foo::Isr() { ++cnt; }

void TIMER0_OVF_vect()
{
    foo.Isr();
}

Re: WinAVR, c++ и прерывания

Добавлено: Чт май 12, 2011 10:16:35
apwork
Спасибо за информацию. Буду пробовать. Хотя со статичной функцией класса было бы интереснее.

Re: WinAVR, c++ и прерывания

Добавлено: Чт май 12, 2011 10:21:26
Мастер Ломастер
а в чем смысл впихивания обработчика в класс?

Re: WinAVR, c++ и прерывания

Добавлено: Чт май 12, 2011 10:28:56
avreal
apwork писал(а):Спасибо за информацию. Буду пробовать. Хотя со статичной функцией класса было бы интереснее.
На avrfreaks поищите C++ interrupt, там несколько тем было год-два назад.
Что-то я пробовал, но у меня толи не пошло, толи выглядело не ровнее дружественных функций.

Если нароете что-то свежее-рабочее, отпишитесь тут :-)

Re: WinAVR, c++ и прерывания

Добавлено: Чт май 12, 2011 10:31:36
avreal
Мастер Ломастер писал(а):а в чем смысл впихивания обработчика в класс?
В том же в чём и впихивание всего остального -- «приватизация» того, что не должно быть видно снаружи при сохранении быстрого доступа, некоторое разделение интерфейса и реализации, ...

Re: WinAVR, c++ и прерывания

Добавлено: Чт май 12, 2011 10:50:59
Мастер Ломастер
разделение - самоцель? всегда считал, что ООП имеет цель упрощение построения сложных проектов, в которых одновременное существование нескольких экземпляров одного и того же класса является непременным условием... или проект состоит из хитрой иерархии классов для обеспечения некоей "стройности" кода...
существование двух экземпляров класса со встроенными обработчиками одного и того же прерывания в AVR я не представляю... выглядит это, как костыли... стройности программе тоже вряд ли прибавляет...
получается, смысл только в загонянии части переменных под private ? оно того на самом деле стоит?

Re: WinAVR, c++ и прерывания

Добавлено: Чт май 12, 2011 11:19:29
avreal
А в С -- если какой-то модуль выделяется в отдельный файл со спрятанными там (через static) переменными и функциями внутреннего употребления -- тоже «непременным условием» будет применение в программе двух экземпляров этого модуля? Иначе программа «нестройная», выделение модуля было «самоцелью» ?

На мой взгляд, класс, от которого в программе существует в принципе единственный экземпляр -- вполне нормальное явление.

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

У меня сейчас в меге64 подобным образом работает 5-канальный приёмник пакетов (односторонняя передача, эта штука только принимает, анализирует и в UART на комп). Впрочем, там вместе с float-статистикой, fprintf, кучей текстовых строк -- килов 7 кода. Было бы у меги168 нужное количество COMPARE, в ней бы и было сделано. Да и платки с мегой64 завалялись.

Каждый канал - единственный экземпляр «себя» с двумя собственными обработчиками прерываний (внешнее прерывание и таймерное COMPARE). Но все одни -- потомки общего PaсketReceiver и уровнем выше все думают, что вот в этом массиве -- указатели именно на задействованные PacketReceiver, а не на те, нарушающие «непременное условие», единственные экземпляры производных классов.

Re: WinAVR, c++ и прерывания

Добавлено: Чт май 12, 2011 11:41:39
Мастер Ломастер
avreal писал(а):Каждый канал - единственный экземпляр «себя» с двумя собственными обработчиками прерываний (внешнее прерывание и таймерное COMPARE). Но все одни -- потомки общего PaсketReceiver и уровнем выше все думают, что вот в этом массиве -- указатели именно на задействованные PacketReceiver, а не на те, нарушающие «непременное условие», единственные экземпляры производных классов.
возможно, пока я корректировал свое сообщение - вы как раз отвечали :) ибо я добавил в свой текст упоминание об улучшении стройности программы за счет иерархии классов - это как раз ваш случай. это я понимаю и могу с этим согласиться без возражений.

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

Re: WinAVR, c++ и прерывания

Добавлено: Чт май 12, 2011 13:09:29
avreal
Мастер Ломастер писал(а):упоминание об улучшении стройности программы за счет иерархии классов - это как раз ваш случай. это я понимаю и могу с этим согласиться без возражений.
Но каждый «листовой» класс при этом имеет единственный экземпляр, а топикстартер не упоминал, его классы самостоятельные, или чьи-то потомки :-)

Мастер Ломастер писал(а):меня смутил единственный экземпляр единственного класса с обработчиком прерываний - по сравнению с отдельным модулем никаких преимуществ не имееющий, как мне кажется, но требующий перехода на заведомо более сложный инструмент С++. т.е. налицо возрастание сложности решения без заметной выгоды...
Если остальная программа и так на плюсах (а это отдельный разговор, который шире обсуждения одного какого-то модуля-класса), то никакого специального перехода не будет.
Пусть нужен UART (в упомянутом выше приёмнике-анализаторе пакетов) или там I2C -- если не в микроконтроллере, то в программе вполне может быть в единственном экземпляре.
В программе, использующей scmRTOS, оформление «драйвера I2C» в виде модуля С-стиля только сделает программу «неоднородной», проще она точно от этого не станет.

А класс один без иерархии (ОП, а не ООП, если я правильно терминологию понимаю) и с единственным экземпляром -- вполне ляжет в стиль. Всякие там mutex-ы с event-ами будут не отдельно стоящими статическими объектами в отдельном файле, а полями (возможно, тоже статическими) класса «драйвера», конструкторы вызовутся, то-сё. Где тут усложнение -- уже не видно. Да и вообще не видно, после того, как инструмент освоен. А применять удобно.

Код: Выделить всё

fprintf_P( uart, ...... );
И по барабану, что этот uart -- единственный экземпляр единственного класса.
Он имеет operator FILE* () специально для этого случая, а внутри и экземпляр класса очереди, и разные сервисы scmRTOS использует. Поток просто уснёт (а не будет в цикле поллить флаги UART), если в очереди места нет, будет разбужен, когда появится.
Выписать тот же функционал в чисто С-шном стиле через

Код: Выделить всё

FILE uart_file = FDEV_SETUP_STREAM(uart_putchar, ...);
#define uart (&uart_file)
и что спрятать в модуле в static, что описать как uart_lock() вместо uart.lock() -- проще не будет, пользоваться тоже проще не будет.
Зато inline-доступ к приватным полям будет быстр, а для использования такого же доступа к «приватным» переменным С-шного модуля придётся таки делать их глобальными, а не в файловой области видимости прятать.
Просто в h-файле не описывать на верхнем уровне, а прятать внутрь функций, чтобы скрыть их существование и не дать туда что-то записать минуя опубликованный интерфейс модуля:

Код: Выделить всё

static inline unsigned GetSystemTimer()
{
        extern volatile unsigned sys_timer;
        return sys_timer;
}

Re: WinAVR, c++ и прерывания

Добавлено: Чт май 12, 2011 18:29:00
apwork
На avrfreaks и подобных сайтах все рекомендации сводятся к применению friend функций-прерываний. Объясняют это ограничениями и недостатками avr-gcc. Все надеются, что в будущем будет что-то придумано.
Попробую поискать еще, иначе буду лепить friend'a :)

Re: WinAVR, c++ и прерывания

Добавлено: Чт май 12, 2011 18:50:20
apwork
Такое еще нарыл ( пост от Ron Kreymborg на [avr-chat] ) :

Он предлагает с помощью директивы asm сделать так:
1. Объявить макрос

Код: Выделить всё

#define CLASS_IRQ(name, vector) \
    static void name(void) asm(__STRINGIFY(vector)) \
    __attribute__ ((signal, __INTR_ATTRS))

2. Объявить класс прерывания

Код: Выделить всё

class CTimer0Interrupt
{
public:
    CTimer0Interrupt();
    ~CTimer0Interrupt();
private:
    CLASS_IRQ(OverflowInterrupt, TIMER0_OVF_vect);
};

Макрос объявляет обработчик прерывания статическим.
Далее приводится текст файла с имплементацией класса прерывания:

Код: Выделить всё

//***************************************************************
// Timer0Interrupt.cpp
//
#include "Timer0.h"
#include "Timer0Interrupt.h"

extern CTimer0 Timer0;

//----------
CTimer0Interrupt::CTimer0Interrupt()
{
    TCNT0 = TIMER0_TIMEOUT;
    TCCR0 = 0x04;
    TIMSK |= (1<<TOIE0);        // enable overflow interrupts
}

//----------
CTimer0Interrupt::~CTimer0Interrupt()
{
    TIMSK &= ~(1<<TOIE0);       // disable Timer0 timeout interrupt
}

//----------
void CTimer0Interrupt::OverflowInterrupt(void)
{
    TCNT0 = TIMER0_TIMEOUT;     // restart the timeout
    Timer0.SetOverflowFlag();   // tell our friend of the event
}

А вот и класс устройства ( в данном случае это таймер )

Код: Выделить всё

class CTimer0
{
    friend class CTimer0Interrupt;
public:
    CTimer0();
    ~CTimer0();
    int GetTimer0Flags(void);
private:
    void SetOverflowFlag(void);
private:
    volatile int        mTimer0Flags;
    CTimer0Interrupt    mTimer0Interrupt;
};

void CTimer0Interrupt::OverflowInterrupt(void)
{
    TCNT0 = TIMER0_TIMEOUT;     // restart the timeout
    Timer0.mTimer0Flags |= TIMER0_OVERFLOW;
}

От себя скажу, что это решение весьма заинтересовало. На практике еще не пробовал, но в ближайшее время попробую.

Re: WinAVR, c++ и прерывания

Добавлено: Чт май 12, 2011 19:17:12
YS
а в чем смысл впихивания обработчика в класс?


Даже шире: в чем смысл применения ООП при создании firmware?

На мой взгляд, класс, от которого в программе существует в принципе единственный экземпляр -- вполне нормальное явление.


Ну, не все так однозначно. Например, мне это кажется жутким извращением. :)

Re: WinAVR, c++ и прерывания

Добавлено: Чт май 12, 2011 19:40:42
apwork
Э-э-э... товарищи, давайте не устраивать холивар. Личные предубеждения оставляем при себе и оперируем фактами. Есть проблема - ищем решение! Не надо говорить, что проблема плохая - находим себе "хорошую" проблему и решаем в свое удовольствие!

Re: WinAVR, c++ и прерывания

Добавлено: Чт май 12, 2011 22:06:29
neiver
Я предпочитаю обработчики прерываний делать обычными статическими функциями-членами. Причем встраиваемыми для эффективности. И вызывать их из обычным образом написанного обработчика.

Код: Выделить всё

class Usart
{
...
static void RxHandler()
{
char byte = UDR;
...
}
...
};
...
ISR(USART_RXC_vect)
{
        Usart::RxHandler();
}

Это более гибкий и переносимый подход. Подробнее можно почитать тут:
http://we.easyelectronics.ru/Soft/kolcevoy-bufer-na-s-dlya-mk.html

Re: WinAVR, c++ и прерывания

Добавлено: Пт май 13, 2011 09:43:21
BCluster
Не люблю плюсы. Да и необходимость использования ООП на авр весьма сомнительна. Программы не настолько сложны. Ну эт ИМХО все канечно :)