xvr 12 28 февраля, 2020 Опубликовано 28 февраля, 2020 · Жалоба У меня дежавю, причем в тяжёлой форме Срач начнётся странице ко 2й, реальное обсуждение закончится чуть позже Пока ещё не начали мерятся пип.. делегатами, советую обратить внимание, что экземпляр любого класса создаётся в процессе исполнения программы (даже если вы его написали статическим объектом на верхнем уровне - ему всё равно надо выполнить свой конструктор, пусть даже и пустой, до того, как он будет готов обслуживать своих клиентов) А ресурс, к которому вы хотите его привязать (источник прерывания - это ресурс) - задан статически (он встроен в железе). Т.е. вам необходим какой то механизм привязки статичски выделенного ресурса к динамически созданному обработчику. Это могут быть делегаты, указатели и вообще что угодно. Либо можно сделать сам объект так, что бы любой его экземпляр был сразу связан с ресурсом. Это различные способы статически привязать экземпляр к ресурсу прямо в момент создания (или даже ещё раньше). Это могут быть статические методы объекта, намертво прописанные в теле метода объекта источники, шаблоны. В общем выбирайте - тут есть из чего выбирать. Но сначала определитесь, чего именно вы хотите (желательно максимально конкретно) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 18 28 февраля, 2020 Опубликовано 28 февраля, 2020 · Жалоба 23 минуты назад, xvr сказал: советую обратить внимание, что экземпляр любого класса создаётся в процессе исполнения программы Ну вообще-то уже есть constexpr-конструкторы. Так что теоретически можно даже получить встроенный вызов даже используя нелюбимые мной делегаты. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 61 28 февраля, 2020 Опубликовано 28 февраля, 2020 · Жалоба 2 hours ago, Forger said: Я сделал на делегатах, тогда любой метод любого класса может быть обработчиком прерывания. А не можете фрагмент дизассемблера (листинга) приветсти? Во что, всё-таки, это компилируется. Просто интересно, что за "минимальные расходы") 4 hours ago, Eddy_Em said: А не проще ли свой стартап написать? На С++, коль уж вы их используете. Зачем вам ассемблер? +1!!!! @ViKo, примеров в сети куча на тему написания стартапа на Си(++). Я сам это дело недавно освоил) Ничего особо сложного там нет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 26 28 февраля, 2020 Опубликовано 28 февраля, 2020 · Жалоба 16 minutes ago, haker_fox said: А не можете фрагмент дизассемблера (листинга) приветсти? Вызов делегата: Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 61 28 февраля, 2020 Опубликовано 28 февраля, 2020 · Жалоба 30 minutes ago, Forger said: Вызов делегата: В принципе действительно немного. Но вот на днях занимался отладкой системой сбора данных (на базе микроконтроллера с ядром Cortex-M4F). В прерывании, возникающим каждые 25 мкс, нужно было произвести некоторые расчёты (часть даже по таблицам). Так вот, не успевал. Пришлось делать всё, чтобы компилятор инлайнил функции, убирать все лишние проверки... Конечно, мой случай частный. Но именно в нём делегат бы был непозволительной роскошлью из 3 команд)))) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 183 28 февраля, 2020 Опубликовано 28 февраля, 2020 · Жалоба Ниче не понял. Чего опять затевает @ViKo? 40 минут назад, Forger сказал: Вызов делегата... А можно вопрос? Как я понял, делегат - это что-то похожее на указатель на функцию. Ну, допустим, привязали мы этот указатель на функцию обработчика прерывания. А тогда что такое "вызов делегата"? Ведь прерывания асинхронны... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 26 28 февраля, 2020 Опубликовано 28 февраля, 2020 · Жалоба Just now, haker_fox said: В принципе действительно немного. Но вот на днях занимался отладкой системой сбора данных (на базе микроконтроллера с ядром Cortex-M4F). В прерывании, возникающим каждые 25 мкс, нужно было произвести некоторые расчёты (часть даже по таблицам). Так вот, не успевал. Пришлось делать всё, чтобы компилятор инлайнил функции, убирать все лишние проверки... Конечно, мой случай частный. Но именно в нём делегат бы был непозволительной роскошлью из 3 команд)))) В прерываниях никогда ничего не считаю, только быстренко просимафорил и скорее наружу. Раньше делал так - копировал в ОЗУ таблицу векторов, и перенастраивал на нее VTOR (не ниже CM3). Так можно настроить вектор на любую статичную функцию класса. С другой стороны, даже если уже в этом месте возникает затык, то рано или поздно по мере развития проекта он вылезет даже без дегелатов. По сути уход в инлайн функции по максимуму - это некого рода костыль. Just now, Arlleex said: Ну, допустим, привязали мы этот указатель на функцию обработчика прерывания. А тогда что такое "вызов делегата"? Ведь прерывания асинхронны... И что? Где прервались туда же и вернемся, даже если прервали между заполнением указателя this и вызовом метода. Указатель на функцию - это по сути делегат на статическую функцию класса. Чуть-чуть быстрее работает, чем вызов метода класса. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 61 28 февраля, 2020 Опубликовано 28 февраля, 2020 · Жалоба 2 minutes ago, Forger said: это некого рода костыль. Согласен, и осознаю, что быстродействие нашей системы на пределе. Но это архитектурный косяк, на переделывание которого нет времени. Пока получается так пооптимизирвоать) 3 minutes ago, Forger said: В прерываниях никогда ничего не считаю, только быстренко просимафорил и скорее наружу. Здесь льётся довольно большое количество данных, поэтому читаю сразу в прерывании и пишу в кольцо. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 26 28 февраля, 2020 Опубликовано 28 февраля, 2020 · Жалоба Just now, haker_fox said: Согласен, и осознаю, что быстродействие нашей системы на пределе. Но это архитектурный косяк, на переделывание которого нет времени. Пока получается так пооптимизирвоать) Здесь льётся довольно большое количество данных, поэтому читаю сразу в прерывании и пишу в кольцо. Когда разработка железа и софта идет не совсем слаженно, то такое вполне возможно. Впрочем, это уже офф, и обсуждать причины именного такого построения того или иного проекта не стоит. Как говорится - что имеем, с тем и работаем :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 183 28 февраля, 2020 Опубликовано 28 февраля, 2020 · Жалоба 13 минут назад, Forger сказал: И что? Где прервались туда же и вернемся, даже если прервали между заполнением указателя this и вызовом метода... Ну как же. Асинхронный вызов обычно не зависит от написанного в коде, на то он и асинхронный. Большинство прерываний, реализованных в МК, именно такие - то есть процессор не знает, когда оно произойдет. А Вы говорите, что делегат вызывается. Вот я и хочу узнать, что значит вызывается? Ведь когда в МК возникает прерывание, никто ничего не вызывает. Как я понял (вот сейчас только): в таблицу векторов заносится адрес делегата. При возникновении прерывания управление передастся на вот этот код, который Вы привели в дизасме. А он уже в свою очередь вызовет прикрепленный обработчик прерывания в каком-нибудь классе. Так? P.S. Мне сам принцип понять главное Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 26 28 февраля, 2020 Опубликовано 28 февраля, 2020 · Жалоба Ну конечно ядро МК ничего не знает про такую штуку как делегат - это просто некая программная абстракция, по факту у меня это реализовано просто: вместо штатного startup.c у меня свой самописный vectors.cpp, где под каждое семейство создается своя таблица (массив) делегатов и равное им число экземпляров шаблонной статической функции, в которых производится вызов соотв делегата из таблицы по заранее известному индексу, так быстрее получается. В целом формируется целая груда примитивных статических функций, внутри которых происходит вызов нужного делегата из статической таблицы. И конечно предусмотрен ряд методов того же класса Interrupt, которые позволяют управлять тем или иным вектором и соотв. его делегатом. Векторам можно в коде давать нужные имена и использовать это в соотв. софте для мониторинга. Это, конечно, увеличивает оверхед, но в отладочной версии никак иначе . Разумеется, не системные векторы вызываются "классически", ибо их функции никогда не меняют и всегда известны еще на этапе компиляции. Короче: Intrrupt.hpp: ... class Interrupt final { public: using Vector = Delegate<void(void)>; .... Intrrupt.cpp: static ...... ::Interrupt::Vector __attribute__((used)) vectorTable[IRQ_VECTOR_TABLE_SIZE]; ... template<unsigned VECTOR> static void interruptHandler() { vectorTable[VECTOR](); } ... static void (* const __vectors[])() __attribute__((section("RESET"), used)) = { (void (*)())(&startupStack[kStartupStackSizeBytes/sizeof(StackItem)]), ResetHandler, NMI_Handler, // NMI, HardFault_Handler, // HardFault MemManage_Handler, // MemManage_Handler BusFault_Handler, // BusFault_Handler UsageFault_Handler, // UsageFault_Handler 0, // Reserved 0, // Reserved 0, // Reserved 0, // Reserved SVC_Handler, // Keil RTX RTOS Vector DebugMon_Handler, // DebugMon_Handler 0, // Reserved PendSV_Handler, // Keil RTX RTOS Vector SysTick_Handler, // Keil RTX RTOS Vector interruptHandler<0>, interruptHandler<1>, interruptHandler<2>, interruptHandler<3>, interruptHandler<4>, interruptHandler<5>, interruptHandler<6>, interruptHandler<7>, interruptHandler<8>, interruptHandler<9>, interruptHandler<10>, interruptHandler<11>, interruptHandler<12>, interruptHandler<13>, interruptHandler<14>, interruptHandler<15>, interruptHandler<16>, interruptHandler<17>, interruptHandler<18>, interruptHandler<19>, .... }; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 26 28 февраля, 2020 Опубликовано 28 февраля, 2020 · Жалоба 1 hour ago, Arlleex said: При возникновении прерывания управление передастся на вот этот код, который Вы привели в дизасме. А он уже в свою очередь вызовет прикрепленный обработчик прерывания в каком-нибудь классе. Так? Нет, вызов делегата - это УЖЕ вызов конкретного обработчика (void(void) метод ЛЮБОГО класса). Т.е. после кода дизасм коде выше при выполнении BX R1 происходит вызов конкретного ВАШЕГО обработчика, короче, в R1 - находится адрес вашего обработчика. Фактически если сравнивать с "классической" схемой к вызову каждого обработчика прерывания нужно просто добавить четыре эти команды. В принципе все )) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 183 28 февраля, 2020 Опубликовано 28 февраля, 2020 · Жалоба 43 минуты назад, Forger сказал: Нет, вызов делегата - это УЖЕ вызов конкретного обработчика... Гхм... Тогда как назвать ту ассемблерную прослойку, которую Вы привели? Я полагал, что те 4 команды и есть делегат. Делегат как бы "передает полномочия" реальному обработчику. Он является своего рода прослойкой. Вот, чтобы окончательно все устаканилось: полагаю, в таблице векторов прерываний в каком-то векторе хранится адрес 0x0800164D (см. дизасм). При возникновении прерывания управление передается по этому адресу. PC загружается адресом начала этой самой "прослойки" (см. дизасм), а она уже вызывает наш обработчик. Короче, как я понял, это синтаксически засахаренная вот такая штука void (*pfUserISR)(void); void I2C_Handler(void) // та самая прослойка (см. дизасм) { pfUserISR(); } void MyI2CHandler(void) { ... } int main(void) { pfUserISR = MyI2CHandler; } где в реальной таблице векторов по вектору периферии пропишется адрес I2C_Handler. При возникновении прерывания управление перейдет в эту функцию (дизасм выше), а из нее вызовется pfUserISR, который мы назначили в main() (а в плюсах, как я понял, вся эта шарманка скрыта за красивым словом DELEGATE, поэтому глобального указателя pfUserISR не требуется). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 18 28 февраля, 2020 Опубликовано 28 февраля, 2020 · Жалоба 30 минут назад, Arlleex сказал: Короче, как я понял, это синтаксически засахаренная вот такая штука Почти. Только у него ещё один уровень косвенности. Потому что в таблице векторов у него лежат функции, которые делают следующее: берут из массива адрес объекта класса Vector с заданным номером и вызывают его функцию operator(). А уже этот объект в себе может хранить либо просто указатель на функцию, либо указатель на функцию-член класса + указатель на экземпляр класса, либо лямбду. Так что товарищ Forger слегка слукавил, когда показал ассемблерный листинг :-) Кстати, не исключено (и даже почти наверняка), что operator() - виртуальный, и тогда товарищ Forger слукавил дважды, потому что виртуальные функции тоже вызываются косвенно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 26 28 февраля, 2020 Опубликовано 28 февраля, 2020 · Жалоба 37 minutes ago, Arlleex said: Гхм... Тогда как назвать ту ассемблерную прослойку, которую Вы привели? Прямо над ней написано: вызов делегата, это именно так. 37 minutes ago, Arlleex said: Я полагал, что те 4 команды и есть делегат. Делегат как бы "передает полномочия" реальному обработчику. Он является своего рода прослойкой. Так и есть, делегат - это типа указатель: размер указателя 4 байта, у указателя на метод класса (и делегата) - 8 байт (для наших 32-битников), т.к. помимо указателя нужно помнить еще и this на конретный класс владельца. Размер делегата и время его вызова не зависят от того, на кого он ссылается, точно так же как и указатель. 37 minutes ago, Arlleex said: Вот, чтобы окончательно все устаканилось: полагаю, в таблице векторов прерываний в каком-то векторе хранится адрес 0x0800164D (см. дизасм). При возникновении прерывания управление передается по этому адресу. PC загружается адресом начала этой самой "прослойки" (см. дизасм), а она уже вызывает наш обработчик. Да, типа того. По крайней мере по числу команд в ASM. 37 minutes ago, Arlleex said: Короче, как я понял, это синтаксически засахаренная вот такая штука Вы объявили указатель, выделили для него память в ОЗУ, вот там и будет хранится адрес вашей процедуры. Сама таблица векторов находится во FLASH. 37 minutes ago, Arlleex said: При возникновении прерывания управление перейдет в эту функцию (дизасм выше), а из нее вызовется pfUserISR, который мы назначили в main() (а в плюсах, как я понял, вся эта шарманка скрыта за красивым словом DELEGATE, поэтому глобального указателя pfUserISR не требуется). В плюсах используется указатель на метод конкретного класса, это не то же самое, что указатель на функцию. Но почти. А вот делегат позволяет указывать на метод ЛЮБОГО класса. Вообще, главное - совпадающая семантика метода - одинаковые типы и кол-во входных и тип выходного параметра. Для прерываний это - логичные void(void). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться