Перейти к содержанию
    

С++, обработчик прерывания как статическая ф-я класса.

Пытаюсь запихать. Запихал:

class    TUart1 : public TCustomUart
{
    public:
        TUart1(uint32_t baudrate) {hw_init(baudrate);}
    protected:
        ...
        virtual void hw_init(uint32_t baudrate);
        virtual void write_tx_reg(char ch) { TXBUF0 = ch; }
        static interrupt(UART0RX_VECTOR) usart0_rx(void);
        static interrupt(UART0TX_VECTOR) usart0_tx(void);
};

...

interrupt(UART0TX_VECTOR) TUart1::usart0_tx(void)
{
    OS::TISRW ISR;
    char ch;
    if (Uart1.TxChannel.get_count())
    {
        Uart1.TxChannel.pop(ch);
        TXBUF0 = ch;
    }
    else
    {
        Uart1.tx_active = false;
    }
}

 

Делаю это для того, чтобы в прерывании обращаться к private-членам класса. Вроде всё получается. Единственное неудобство состоит в том, что пока я не напишу где-нибудь

void TUart1::hw_init(uint32_t baudrate)
{
    typedef void (* Handler)(void);
    volatile Handler ptr;
    ...
    ptr = &usart0_rx;
    ptr = &usart0_tx;
}

, обработчики прерываний не линкуются. Может есть какой-то более цивильный способ?

 

Ну и вообще, хотелось бы не статическую функцию, а просто функцию класса:)

 

ЗЫ. msp-gcc.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

ptr = &usart0_rx;

ptr = &usart0_tx;

А разве здесь нужен знак "&"?

По-моему, название функции является указателем, как с массивами...

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну и вообще, хотелось бы не статическую функцию, а просто функцию класса:)

 

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

Если сделать прерывания нестатичными, то как и куда им будет передаваться этот указатель??? :07:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А разве здесь нужен знак "&"?

По-моему, название функции является указателем, как с массивами...

Да тут без разницы, нужно просто обращение...

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

Не, не помогает.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Единственное неудобство состоит в том, что пока я не напишу где-нибудь
    ptr = &usart0_rx;
    ptr = &usart0_tx;
}

Фигня какая-то...
class adc_t
{
public:
    typedef uint16_t sample_t;
    static sample_t const MAX_VALUE = 4096;

    template<adc_channel_t channel>
    INLINE inline static sample_t digital();   // adc raw value
    template<adc_channel_t channel>
    INLINE inline static float analog();        // adc result converted to analog
........
private:
    static OS_INTERRUPT void IntHandler();

    static OS::TMutex Locker;
    static OS::TEventFlag Ready;
};


OS_INTERRUPT interrupt(ADC12_VECTOR) adc_t::IntHandler()
{
    OS::TISRW ISRWrapper;
    ADC12IV;
    Ready.SignalISR();
    Locker.UnlockISR();
    ADC12IE = 0;
}

Все линкуется...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Фигня какая-то...

 

Не то слово:) Похоже мне попалась какая-то неудачная сборка mspgcc:)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не то слово:) Похоже мне попалась какая-то неудачная сборка mspgcc:)
Возможно. Могу выслать свою или собери из cvs.

Я тут немного подумал, и пришел к выводу, что в исходном коде есть концептуальная ошибка: UARTов может быть несколько и вшивать конкретный вектор в класс неправильно. Там должен быть inline обработчик, который вызывается из реального обработчика. А реальный обработчик будет знать, с каким объектом вызывать. Примерно так:

 

class uart_t
{
public:
    inline INLINE void init(uint32_t const divider);
    inline INLINE bool hasinput() { return Rx.Buffer.has_data(); }
    bool get(uint8_t &data, timeout_t timeout = 0);
    void put(uint8_t data);
private:
....
    friend void UART0_RxHandler();
    friend void UART0_TxHandler();
    friend void UART1_RxHandler();
    friend void UART1_TxHandler();

    inline INLINE void RxHandler();
    inline INLINE void TxHandler();
};

OS_INTERRUPT interrupt(USCIAB0RX_VECTOR) UART0_RxHandler()
{
    OS::TISRW ISRW;
    UART0.RxHandler();
}

OS_INTERRUPT interrupt(USCIAB0TX_VECTOR) UART0_TxHandler()
{
    OS::TISRW ISRW;
    UART0.TxHandler();
}

OS_INTERRUPT interrupt(USCIAB1RX_VECTOR) UART1_RxHandler()
{
    OS::TISRW ISRW;
    UART1.RxHandler();
}

OS_INTERRUPT interrupt(USCIAB1TX_VECTOR) UART1_TxHandler()
{
    OS::TISRW ISRW;
    UART1.TxHandler();
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Возможно. Могу выслать свою или собери из cvs.

Вышлите пожалуйста, собирать пока не готов:)

UARTов может быть несколько и вшивать конкретный вектор в класс неправильно.

Я немного с другой стороны подхожу. У меня есть базовый TCustomUart, с pure virtual ф-ями доступа к аппаратуре. И от него наследники для каждого физического UARTа, с реализациями этих функций и со статическими обработчиками прерываний.

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

Можно и так, надо будет обмозговать:)

 

Вот кстати тестовый проектик:

problem.rar

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну и вообще, хотелось бы не статическую функцию, а просто функцию класса:)

Этого нельзя. Обработчик прерывания не может быть нестатической функцией-членом класса. При вызове нестатической функции-члена ей всегда неявно передается указатель this (понятно для чего :) ), что легко реализуется при обычном вызове, т.е. когда код выполняется "синхронно". А прерывание - это асинхронное событие, программа (компилятор, процессор) "не знает", когда оно произойдет (и не может знать), поэтому вызов функции с передачей this практически нереализуем - какой this передавать? Ведь нестатическая функция-член всегда вызвается для конкретного экземляра класса (объекта), его адрес четко известен в точке вызова. Чего нельзя сказать про случай с прерыванием - для какого объекта делается вызов?

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Этого нельзя.

 

Да это понятно:) Я так, на всякий случай, вдруг наука что-то придумала, а я не в курсе :biggrin:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Короче, разобрался я, в чём причина. Всё дело в шаблонах:)

Базовый класс у меня объявлен как шаблон:

template<uint16_t rx_buf_size, uint16_t tx_buf_size>
class    TCustomUart
{
    public:
        TCustomUart() : RxChannel(), TxChannel(), tx_active(false) { }

        void    putchar(char ch);
        void    puts(char * ch);
        char    getchar(void);
        ...
    protected:
        OS::channel<char, rx_buf_size> RxChannel;
        OS::channel<char, tx_buf_size> TxChannel;

        virtual void disable_tx_interrupt(void) = 0;
        virtual void enable_tx_interrupt(void) = 0;
        virtual void write_tx_reg(char ch) = 0;
        ...
};

 

соответственно, класс uart1:

template<uint16_t rx_buf_size, uint16_t tx_buf_size>
class    TUart1 : public TCustomUart<rx_buf_size, tx_buf_size>
{
        ...
        static OS_INTERRUPT void usart0_rx(void);
        static OS_INTERRUPT void usart0_tx(void);
};

- тоже шаблон.

Убрав шаблоны, получил нормальную линковку обработчиков прерываний.

Видимо, это так работает механизм шаблонирования - всё, что не вызывается, то не инстанцируется?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Видимо, это так работает механизм шаблонирования - всё, что не вызывается, то не инстанцируется?

Именно.

Можете попробовать явное инстанцирование (explicit instantiation):

// в синтаксисе возможны ошибки - сейчас точный синтаксис не вспомню  :(
template void TUart1<конкретные значения параметров шаблона>::usart0_rx(void);

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Можете попробовать явное инстанцирование (explicit instantiation):

 

То, что нужно, спасибо!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А можно конечный кусок кода увидеть
template  void TUart1<размер1, размер2>::usart0_rx();
template  void TUart1<размер1, размер2>::usart0_tx();

Страуструп, конец прилдожения B, явное инстанцирование.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...