_pv 52 12 июня, 2017 Опубликовано 12 июня, 2017 · Жалоба есть базовый класс, пусть будет уарта, которому через шаблон задаётся базовый адрес регистров и размер фифо. template <int USARTx_BASE, int fifoSize = 32> class UartBase{ void ISRBase(); }; теперь делаем классы под каждый uart, так как немного разная инициализация (как минимум клоки включаются отдельно), и статический обработчик прерывания. template <int fifoSize = 32> class Uart0 : UartBase<LPC_USART0_BASE, fifoSize>{ Uart0(){...} static void ISR() { UartBase<LPC_USART0_BASE, fifoSize>::ISRBase(); } }; вопрос1: как теперь сделать Uart0::ISR() обработчиком прерывания? с шаблоном-то тип у него тип теперь к размеру FIFO привязан. void UART0_IRQHandler() { Uart0<?????????>::ISR(); } кроме как убрать шаблон можно по другому это как-то по-человечески сделать? class Uart0 : UartBase<LPC_USART0_BASE, UART0_FIFO_SIZE> вопрос2: метод базового класса UartBase<LPC_USART0_BASE, fifoSize>::ISR(); тоже вызываться не хочет из статического метода. error: cannot call member function 'void UartBase<USARTx_BASE, fifoSize>::ISR() [with int USARTx_BASE = 1074151424; int fifoSize = 32]' without object наверняка не раз уже обсуждалось, но что-то сходу не нашлось, ткните как с однотипной периферией на плюсах правильно работать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
conan 0 12 июня, 2017 Опубликовано 12 июня, 2017 (изменено) · Жалоба 2. Нестатический метод класса можно вызывать только для обьекта. UartBase::ISR (или ISRBase?) у вас метод нестатический и его можно вызывать только для существующего обьекта класса UartBase или обьекта производного класса. О чем компилятор самым явным образом вам сообщает. 1. Не понятно в чем вопрос. Значения для шаблонных аргументов становятся частью спецификации типа. Классы порожденные от одного и того же шаблона с разными значениями аргументов есть разные типы. Не понятно зачем нужна эта помойка Изменено 12 июня, 2017 пользователем conan Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_pv 52 12 июня, 2017 Опубликовано 12 июня, 2017 · Жалоба помойка нужна для, как мне казалось, упрощения кода. Uart <UART0> pc; Uart <UART1, 4> sensor; Uart <UART2, 100> asdf; ... sensor.read() pc.write() как похожее сделать некрасиво на С с препроцессором представляю или что при объявлении в конструктор можно передавать указатель на структуру со всей кучей индивидуальных для каждого уарта регистров. хотелось бы понять как можно сделать на плюсах. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 14 12 июня, 2017 Опубликовано 12 июня, 2017 · Жалоба Uart <UART0> pc; Uart <UART1, 4> sensor; Uart <UART2, 100> asdf; ... хотелось бы понять как можно сделать на плюсах. А в чём проблемы-то? Пишите: void UART0_IRQHandler() { pc.ISR(); } void UART1_IRQHandler() { sensor.ISR(); } void UART2_IRQHandler() { asdf.ISR(); } и всё. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
conan 0 12 июня, 2017 Опубликовано 12 июня, 2017 · Жалоба помойка нужна для, как мне казалось, упрощения кода. Uart <UART0> pc; Uart <UART1, 4> sensor; Uart <UART2, 100> asdf; ... sensor.read() pc.write() как похожее сделать некрасиво на С с препроцессором представляю или что при объявлении в конструктор можно передавать указатель на структуру со всей кучей индивидуальных для каждого уарта регистров. хотелось бы понять как можно сделать на плюсах. Можно сделать шаблон для общего случая, и к нему специализации: template<int USARTx_BASE, int FIFO_SIZE> class Uart {}; template<int FIFO_SIZE> class Uart<UART0, FIFO_SIZE> {}; template<int FIFO_SIZE> class Uart<UART1, FIFO_SIZE> {}; ... template<int FIFO_SIZE> class Uart<UART16, FIFO_SIZE> {}; Если для какого-то USARTx_BASE нет специализации, то будет использоваться общий вариант. Можно сделать специализации не только по одному аргументу, но и по нескольким: template<> class Uart<UART1, 32> {}; Но типы полученные от одного шаблона с разными значениями шаблонных аргументов -- разные типы. Нельзя объект от Uart<UART0, 16> передать в функцию, которая ждет Uart<UART1, 16>& или Uart<UART, 32>& (но можно сделать функцию тоже шаблонной). Еще есть подход Type erasure Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 17 19 июня, 2017 Опубликовано 19 июня, 2017 · Жалоба Нельзя объект от Uart<UART0, 16> передать в функцию, которая ждет Uart<UART1, 16>& или Uart<UART, 32>& (но можно сделать функцию тоже шаблонной). Еще есть подход Type erasure Можно проще: базовый абстрактный класс (с несколькими чисто виртуальными методами), от него наследуется шаблонный класс, в котором реализуются эти виртуальные методы из базового класса. Остальным, кто планирует обращаться к этим шаблонным классам, передаем ссылки на базовый класс. В таком решении прекрасно работает static_cast (если нужно), т. е. проблем с приведением типов нет никаких. Этот базовый класс по сути есть интерфейс. Также этот базовый класс может участвовать в списках (например, в конструкциях типа for_each). Разумеется, в реальных приложениях этих базовых классов может быть сколько угодно. Если двигаться в этом направлении, то не далеко и полноценного применения паттернов проектирования :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sigmaN 0 19 июня, 2017 Опубликовано 19 июня, 2017 · Жалоба Ну там в зависимости от везения может появляться небольшой оверхедик на разруливание этих виртуальных функций. Т.е. если статично известны все конкретные типы то компилятор может убрать рантайм обращение к VTable(это называется кажется статическая девиртуализация), в ином же случае будет рантайм девиртуализация и реальное обращение к VTable https://ru.wikipedia.org/wiki/%D0%A2%D0%B0%...%B4%D0%BE%D0%B2 Применяю подобные вещи даже на AVR, оверхед там не такой уж большой, во многих местах вполне прокатывает. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 17 20 июня, 2017 Опубликовано 20 июня, 2017 · Жалоба Ну там в зависимости от везения может появляться небольшой оверхедик на разруливание этих виртуальных функций. Да, "оверхедик" будет, но есть обратная сторона медали: подобный подход позволяет более грамотно спроектировать проект, объем текста программы сокращается, вырастает его читаемость. В сложных проектах последние пункты имеют неоспоримое преимущество перед эти символическим оверхедом. Тут уж каждый волен выбирать сам )) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_pv 52 20 июня, 2017 Опубликовано 20 июня, 2017 · Жалоба Можно сделать шаблон для общего случая, и к нему специализации: ... Но типы полученные от одного шаблона с разными значениями шаблонных аргументов -- разные типы. вот с этим и вопрос, как объявить обработчик прерывания, если тип этого конкретного уарта становится известным только при объявлении из-за шаблона. Можно проще: базовый абстрактный класс (с несколькими чисто виртуальными методами), от него наследуется шаблонный класс, в котором реализуются эти виртуальные методы из базового класса. а что делать с обработчиком прерывания? как получить статический метод шаблонного класса? завести отдельный глобальный указатель на функцию, которая передаётся обработчику прерывания, и в конструкторе pUART0ISRfunc = this->isr Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 17 20 июня, 2017 Опубликовано 20 июня, 2017 · Жалоба вот с этим и вопрос, как объявить обработчик прерывания, если тип этого конкретного уарта становится известным только при объявлении из-за шаблона. Опишу схему, которую реализовал для ARM процов (любые cortex). Перед стартом производится копирование таблицы векторов из флэш в озу. Копируются только главные вектора, относящиеся к ядру. startup свой, в нем нет обработчиков периферии (не ядра). В зависимости от семейства таблицы имеют разный размер (2 таблицы, есть еще третья - отладочная, для своих целей). Для создания класса нужно лишь знать номер вектора обработчика, т.е. индекс, который идет с файлом ARMCMxx.h. В качестве обработчиков использовать голую С-функцию неинтересно и проблематично (разумеется с допиской extern "C"), мне важно было при вызове функции обработчика вызывался соотв. класс обработчика (точнее его наследника), т.е. в стек должен класться соотв. this. Это дает простую возможность наделять класс Interrupt<> таким функционалом, который раньше было сделать крайне геморрно. Сам класс Interrupt может быть базовым для более высокооуровеных классов (например class SerialPort), либо быть полем в другом классе. template <class Owner, InterruptIndex INDEX, InterruptPriority PRIORITY = IRQ_DEFAULT_PRIORITY> class Interrupt : public AbstractInterrupt { ... private: static void userVector() { AbstractInterrupt::callVector(INDEX + IRQ_OFFSET); } ... } Вот так используется: class SerialPort : public Interrupt<CommunicationThread, USART3_IRQn> { public: SerialPort() : Interrupt<CommunicationThread, USART3_IRQn>("USART3") { port = USART3; } virtual void initialize(); .... private: virtual void body(); void doRecieveDataRegisterNotEmptyEvent(); void doTransmitDataRegisterEmptyEvent(); void doTransmissionCompleteEvent(); ... } serialPort; вот так выглядит обработчик: void SerialPort::body() { doRecieveDataRegisterNotEmptyEvent(); doTransmitDataRegisterEmptyEvent(); doTransmissionCompleteEvent(); } Цена этому - расход озу для хранения таблицы векторов, таблицы указателей на абстрактные классы С++ обработчиков и по мелочи. И небольшой оверхед, т.к. при вызове обработчика еще вызывается соотв. С++ класс-обертка, т.е. нужно совсем чуть-чуть больше стека. Делал сравнительные замеры по производительности - никакого криминала не узрел, теперь использую такую схему на всех своих проектах. В итоге в проекте нет НИ ОДНОГО ГЛОБАЛЬНО ОБЪЕКТА, даже с квалификатором static. Строгая и полностью контролируемая иерархия классов, никакой самодеятельности :) Забыл добавить, что использую полностью вытесняющую модель обработчиков, т. к. это тоже накладывает расходы на main стек. Еще раз - речь про ARM процы, у которых есть полный доступ к регистру VTOR. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sigmaN 0 20 июня, 2017 Опубликовано 20 июня, 2017 · Жалоба вот с этим и вопрос, как объявить обработчик прерывания В соответствии с мануалом на компилятор и HAL выбранного вами процессора. Для AVR обработчик прерывания объявляется вот так. ISR( TIM0_OVF_vect ) { } В этом обработчкие вы вольны делать всё что хотите. В том числе вызвать либо статический метод вашего шаблонного полностью статического класса. Либо инстанциировать класс и вызвать не статический метод. а что делать с обработчиком прерывания? как получить статический метод шаблонного класса? Из обработчика прерывания вы можете вызвать любой метод, хоть статичный хоть нет. ISR( TIM0_OVF_vect ) { SomeInstance.CallFromISR(); SomeFullyStaticClass::SomeStaticMethod(); } Вы немного путаетесь, вам надо теорию почитать что есть шаблон что статик что не статик. Шаблон не обязан быть стататиком. Всё что было сказано выше про виртуальные функции подразумевает не статичные методы и работу именно с экземплярами класса по ссылке(указателю) на родительский класс. Это называется полиморфизм. Опять же надо теорию почитать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_pv 52 20 июня, 2017 Опубликовано 20 июня, 2017 · Жалоба Из обработчика прерывания вы можете вызвать любой метод, хоть статичный хоть нет. ISR( TIM0_OVF_vect ) { SomeInstance.CallFromISR(); SomeFullyStaticClass::SomeStaticMethod(); } спасибо, капитан. хотелось немного красоты, то есть просто объявить Uart0 <64> pc; и после этого не лезть потом в обработчик прерывания чтобы указать там ещё разимя этого конкретного экзэмпляра этого uarta, он ведь всё равно один единственный. ну и ещё размер фифо, если сделать метод статическим ISR( TIM0_OVF_vect ){ Uart0<64>::pc.CallFromISR(); } в результате сделал просто глобальный указатель на функцию Uart0CallFromISR, который зовётся из прерывания и инициализируется как this->isr в конструкторе uart0. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sigmaN 0 20 июня, 2017 Опубликовано 20 июня, 2017 · Жалоба ну вот это вот Uart0<64> то зачем по всей программе размазывать? А если вы FIFO поменять захотите, то будете в 100500 местах это делать? typedef вам в помощь. Ибо шаблон это ТИП! Поэтому весь шаблон со всем своим сколько угодно длинным набором параметров можно просто обозвать как-то удачно. Например typedef UartDriver<Uart0, Fifo64, ParamsDefault> Uart0; Ну а дальше уже в зависимости от реализации. Если в шаблоне UartDriver<> вообще нет состояния и там все методы статичны то экземпляр вам не нужен. Сразу приступаем к использованию: Uart0::Tx("blablabla"); Uart0::ISR(); А если там есть какое-то состояние то потребуется инстанциировать этот класс(тип) путем объявления перменной Uart0 Uart0Instance; И дальше уже обращаться к Uart0Instance.Tx("blablabla"); и Uart0Instance.ISR(); У вас же тут ISR( TIM0_OVF_vect ){ Uart0<64>::pc.CallFromISR(); } Какое-то масло масленное...... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 17 21 июня, 2017 Опубликовано 21 июня, 2017 · Жалоба Какое-то масло масленное...... И не говорите :smile3046: хотелось немного красоты... Небольшой офф. Статические методы в классе нужны крайне редко и практически всегда они имеют квалификатор "private", но исключение составляет, пожалуй, лишь паттерн "Singleton" с его методом ::getInstance(). Все дело в том, что бездумное применение статичных методов где надо и не надо превращает любой объектно-ориентированный (C++) код в типичный процедурный (голый С). Конечно, если проект крохотный, то это не имеет особого значения, но для крохотных проектов не нужен C++. Вот неплохая статья на эту тему. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Lagman 1 21 июня, 2017 Опубликовано 21 июня, 2017 · Жалоба Вот посмотрите видео https://www.youtube.com/watch?v=gXo_kyE4t_w человек рассказывает про прерывания и различные варианты их реализации в С++ относительно embedded. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться