Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: с++ и прерывания
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Sirko
Есть желание написать класс USART для XMega, благо строение ядра способствует. Но вот как быть с прерываниями?
Не хочется для каждого объекта прописывать обработчики в ручную, а как реализовать шаблонно или с макросами, не представляю.

Есть идеи?
_Артём_
Цитата(Sirko @ Jan 23 2012, 14:16) *
Есть желание написать класс USART для XMega, благо строение ядра способствует. Но вот как быть с прерываниями?
Не хочется для каждого объекта прописывать обработчики в ручную, а как реализовать шаблонно или с макросами, не представляю.

Есть идеи?


Код
template<int INT_VECTOR>class Tuart_class {
public:
    #pragma vector=INT_VECTOR
    __interrupt static void UsartHandler()
    {

    }
    
};

Tuart_class<USARTC0_RXC_vect> usartc0;

prottoss
Может так?

Код
class clUSART
    {
   public:    
        usart_t *c;
        
        void Init(usart_t *p){ c = p;};
        ...
        static void isr(usart_t *p);
   }
  
   clUSART u0, u1, u2;
  
    static void clUSART::isr(clUSART *p)
   {
        ...
   }
  
   __interrupt void u0_isr()
   {
        clUSART::isr(u0.c);
   }
   __interrupt void u1_isr()
    {
         clUSART::isr(u1.c);
    }
   __interrupt void u2_isr()
    {
         clUSART::isr(u2.c);
    }
   ...
   main()
   {
       u1.Init(p_usart1);
       u2.Init(p_usart2);
       u3.Init(p_usart3);
       ...
   }
   }


sm.gif Чет туплю после работ... редактирую 5-ый раз. Ну, надеюсь смысл понятен.
_Артём_
Цитата(prottoss @ Jan 23 2012, 15:37) *
Может так?

Так конечно можно, но есть недостатки:
Код
class clUSART
    {
   public:    
        usart_t *c;

Обращение будет по указателю, а хотелось бы через STD/LDD (не путаю команды?)



Код
   __interrupt void u0_isr()
   {
        clUSART::isr(u0.c);
   }
   __interrupt void u1_isr()
    {
         clUSART::isr(u1.c);
    }
   __interrupt void u2_isr()
    {
         clUSART::isr(u2.c);
    }
   ...
   }

Каждый вектор отдельно прописывать?
И ещё вызов функции делать?
P.S. Не понял где вектор указывается.


Sirko
Откровенно говоря не хочется во "внутренностях" руками лазить.
Мысль - объявить некий енумерейт и подставлять его при инициализации.

Код
template <USART_ENUM E>
class Tuart_class {
    typedef enum{
        usartC0 = 25,
        usartC1 = 28
    }USART_ENUM;
};

ISR(E){}    // USARTE0_RXC_vect
ISR(E+1){}    // USARTE0_DRE_vect
ISR(E+2){}    // USARTE0_TXC_vect

void main(){

     Tuart_class<Tuart_class::USART_ENUM::usartC0> usartc0;

}


К сожалению, мой уровень знаний не велик для таких фокусов
demitar
омг
На днях за неимением достойного занятия тоже пытался нашаблонить такое для авр под иар
использовать предполагаю примерно так:

typedef usart<USART0, MyProtocol, 57600L> ext_us;

все нормально компилируется, в железе не проверял.
правда, все-время мучают два вопроса:
что за говнокод получается и нафига мне это надо wacko.gif
prottoss
Цитата(_Артём_ @ Jan 23 2012, 20:14) *
P.S. Не понял где вектор указывается.

Ну так
__interrupt void u0_isr();
__interrupt void u1_isr();
__interrupt void u2_isr();

и есть обработчики (векторы), которые подставляют указатель конкретного USART в общий для объектов обработчик clUSART::isr

Я просто не знаю, какие в xmega имена обработчиков определены в IAR.
_Артём_
Цитата(demitar @ Jan 23 2012, 16:55) *
омг
На днях за неимением достойного занятия тоже пытался нашаблонить такое для авр под иар
использовать предполагаю примерно так:

typedef usart<USART0, MyProtocol, 57600L> ext_us;

все нормально компилируется, в железе не проверял.
правда, все-время мучают два вопроса:
что за говнокод получается и нафига мне это надо wacko.gif

Да, выглядит страшно... но для xmeg должно быть гораздо проще (порты все одинаковые).
А что без enum и проч. никак нельзя?
И адрес порта не получается подсунуть.
demitar
Ну дык я букварь по цпп только в декабре приобрел rolleyes.gif
а адрес порта по первому параметру шаблона выбирается
типа для 128 меги:
usart<USART0,....> - нулевой порт
usart<USART1,....> - первый
_Артём_
Цитата(prottoss @ Jan 23 2012, 16:59) *
Ну так
__interrupt void u0_isr();
__interrupt void u1_isr();
__interrupt void u2_isr();

и есть обработчики (векторы), которые подставляют указатель конкретного USART в общий для объектов обработчик clUSART::isr

Я просто не знаю, какие в xmega имена обработчиков определены в IAR.

pragma не хватает.
Тогда так?
Код
  #pragma vector=USARTC0_RXC_vect
  __interrupt void u0_rxc_isr()
   {
        clUSART::isr(u0.c);
   }
  #pragma vector=USARTC1_RXC_vect
   __interrupt void u1__rxc_isr()
    {
         clUSART::isr(u1.c);
    }
   ..........

demitar
а правильно ли я понял, что IO регистры у атхмеги в одном адресном пространстве с памятью данных?
V_G
Вообще-то для UARTов в хmege есть очень эффективный механизм DMA, но ни одна из представленных сишных реализаций его не использует.
Во всяком случае, при передаче, когда длина буфера заранее известна, применять DMA очень эффективно и красиво, и не нужно никаких прерываний. При приеме посложнее. Но если протокол предусматривает передачу длины посылки, я по прерыванию RxC побайтно беру начало, пока не доберусь до длины, а потом настраиваю DMA на прием указанного числа байтов и реагирую только на прерывание окончания DMA.
Но это на ассемблере

По IO - да. Плюс к тому есть виртуальные порты, которые можно присвоить к любым портам, подключенным к внешним ногам, и обращаться к ним традиционно, через IN,OUT,CBI,SBI и т.д. А так, в общем случае до назначения виртуальных портов, внешние порты не входят в пространство IO
И это на ассемблере
demitar
Вчера бегло просматривал систему команд не нашел там IN/OUT, да и намекали здесь на LD
Не знаю как там ДМА организован, но с обычными прерываниями можно замутить нечто такое:
CODE

#define US0_BASE_ADDR //... Объявляем адреса устройств и векторов,
#define US1_BASE_ADDR //... вероятно, они уже где-то пределены
#define US0_VECTOR_BASE //...
#define US1_VECTOR_BASE //...

//структурка, которая описывает наши usart'ы

template<int US_BASE_ADDR>
struct us_descr {
static __no_init usart_t usart @ US_BASE_ADDR;

enum {
BASE_VECTOR_ADDR = US_BASE_ADDR == US0_BASE_ADDR? US0_VECTOR_BASE:
US_BASE_ADDR == US1_BASE_ADDR? US1_VECTOR_BASE:
//...
-1L,
RXC_VECTOR_ADDR = BASE_VECTOR_ADDR + RXC_VECTOR_OFFSET,
TXC_VECTOR_ADDR = BASE_VECTOR_ADDR + TXC_VECTOR_OFFSET,
DRE_VECTOR_ADDR = BASE_VECTOR_ADDR + DRE_VECTOR_OFFSET,
//...
};
};

/* базовый клас, в котором реализована вся низкоуровненвая работа,
типа конфигурирования, чтения/записи регистров и тп... */

class basic_usart {
protected:
usart_t &Us;
basic_usart(usart_t &us): Us(us) {}

public:
void do_something_with_us() { Us.REG_NAME = 10; }
//...
};

/* собственно наш класс, зависит от протокола и адреса порта,
с которыми мы хотим его связать. Реализует только обработчики
прерываний и интерфейс для создания экземпляра этого класса */

template <int US_BASE_ADDR, class PROTOCOL>
class usart: public basic_usart {
protected:
static PROTOCOL *protocol;

# pragma vector = us_descr<US_BASE_ADDR>::RXC_VECTOR_ADDR
static __interrupt void RXC_handler() {
protocol->OnRxChar( // в обработчиках делаем что надо с регистрами и
us_descr<US_BASE_ADDR>::usart.DATA_REG; // вызываем нужные методы протокола пусть он сам
); // разбирается с данными
}

# pragma vector = us_descr<US_BASE_ADDR>::TXC_VECTOR_ADDR
static __interrupt void TXC_handler() {
//...
}


# pragma vector = us_descr<US_BASE_ADDR>::DRE_VECTOR_ADDR
static __interrupt void DRE_handler() {
//...
}

//...
public:
usart(PROTOCOL *p): basic_usart(us_descr<US_BASE_ADDR>::usart) {
DRE_handler, RXC_handler, TXC_handler; // тут надо пнуть этих ребят иначе компилятор не создат
// их специализацию (IAR 4.12A)

protocol = p;
//...
}
};

template <int US_BASE_ADDR, class PROTOCOL>
PROTOCOL *usart<US_BASE_ADDR, PROTOCOL>::protocol = NULL;

template<int US_BASE_ADDR> usart_t us_descr<US_BASE_ADDR>::usart;


Классы протоколов тоже можно сделать шаблонными и наследовать их прямо от usart вроде этого


CODE
template <int US_BASE_ADDR>
class Protocol: public usart<US_BASE_ADDR, Protocol<US_BASE_ADDR> >
{
typedef usart<US_BASE_ADDR, Protocol<US_BASE_ADDR> > USART;

public:
void OnRxChar(int ch) {}
Protocol(): USART(this) {}
};


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

Правда мой динозавар о хмеге ничего не знает, так что в настройках целевой процессор - atmega128


Цитата
Вчера бегло просматривал систему команд не нашел там IN/OUT

хм странно, сегодня они там есть, а вчера их небыло cranky.gif
Navovvol
Цитата(V_G @ Jan 24 2012, 10:11) *
Вообще-то для UARTов в хmege есть очень эффективный механизм DMA...
Но это на ассемблере

Заинтересовал про DMA и USART sm.gif
Сколько не читал про DMA так и не понял как его использовать
Покажи плиз асм код USART+ DMA. sm.gif)
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.