AHTOXA 18 12 декабря, 2019 Опубликовано 12 декабря, 2019 · Жалоба 7 минут назад, ViKo сказал: Будем смотреть, во что компилируется, а не сколько в нём этажей. Ну, запись/чтение шины сложно будет оптимизировать, для случая произвольного расположения ножек. Без цикла, думаю, не обойтись. А вот, например, конфигурирование группы ножек будет красивым: template <char portLetter = 'A'> class Port { ... // вложенный класс "шина" template<unsigned... Pins> struct Bus { static void setOutput() { getPortStruct()->pinDirs |= getMask(); } ... } }; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 68 13 декабря, 2019 Опубликовано 13 декабря, 2019 · Жалоба 21 час назад, ViKo сказал: Не соглашусь, что лямбда-функция - это функтор. Лямбда-выражения в C++ используются именно в виде анонимных функций, без имени, адреса, используемых в месте определения. Так функтор-то и нужен для того, чтобы иметь синтаксис использования функции - чтобы его можно было использовать так как обычную функцию. Но тем не менее он от этого функцией не становится. Это объект, который содержит данные и осуществляет вызов в своём контексте (что очень полезно, например, для создания замыканий (closure)). И лямбда в С++ - это просто анонимный функтор. 21 час назад, ViKo сказал: Насчет порядка функций - это, видимо, из питона и т.п. термин. В учебниках по C/C++/C# не встречал. Да и какой может быть порядок, если вложенные функции невозможны. Кроме этих лямбд. Ни разу не из питона, это из computer science. Загуглите "объект первого класса", там всё достаточно просто. В более высокоуровневых языках, нежели С/С++, функции являются объектами исходно (типа "функторами" если по плюсовому), поэтому сразу обладают соответствующими свойствами. Хоть в том же легковесном Lua и множестве других ЯП. 21 час назад, ViKo сказал: Нисколько не сомневаюсь, что вы продвинутый программист и в теории и на практике. Однако, лямбда-функция означает лямбда в форме функции. Или наоборот. И уж точно не было корректным ваше безоговорочное "не функции вообще". Уже подробно объяснил выше, в чём принципиальная разница: одно - это вызываемый код, процедура, второе - объект. И кстати, я не программист. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 13 декабря, 2019 Опубликовано 13 декабря, 2019 · Жалоба Ок, понял (пытаюсь). Читаю это: https://m.habr.com/ru/company/otus/blog/444524/ Тогда это нужно было назвать "лямбда-функтором". Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Nixon 4 13 декабря, 2019 Опубликовано 13 декабря, 2019 · Жалоба 17 часов назад, AHTOXA сказал: Ну, запись/чтение шины сложно будет оптимизировать, для случая произвольного расположения ножек. Без цикла, думаю, не обойтись. Цикл не нужен. Посмотрите как реализован SetDout и как определяются DOUTx_ADDR // CLASS PORTPINS TEMPLATE template < char port, uint8_t... pins > class PortPins; template < char port, uint8_t pin0, uint8_t... pins> class PortPins<port, pin0, pins...> { private: enum { PIN_COUNT = sizeof...(pins) + 1 }; static constexpr uint8_t pinlist[16] = { pin0, pins... }; static constexpr bool NO_DOUBLED_PIN ( void ) { for (int i = 0; i < PIN_COUNT; i++) for (int j = i + 1; j < PIN_COUNT; j++) if (pinlist[i] == pinlist[j]) return false; return true; } static_assert((port >= 'A') && (port <= 'F'), "Error!!! Illegal GPIO port name!!!"); static_assert((sizeof...(pins) < 16), "Error!!! Illegal pins count!!!"); static_assert((pin0 < 16), "Error!!! Illegal pin number!!!"); static_assert(NO_DOUBLED_PIN(), "Error!!! Doubled pins found!!!"); enum { GPIOx_BASE = port_base_t<port>::GPIOx_BASE }; enum { DOUTBB_BASE = 0x42000000UL + (GPIOx_BASE + offsetof(GPIOxTypeDef, DOUT) - 0x40000000UL) * 32 }; enum { DOUT0_ADDR = (DOUTBB_BASE + pinlist[0] * 4) * ((0 < PIN_COUNT) ? 1 : 0) }; ... enum { DOUT15_ADDR = (DOUTBB_BASE + pinlist[15] * 4) * ((15 < PIN_COUNT) ? 1 : 0) }; ... private: INLINE static void SetDout ( int value ) { if constexpr (DOUT0_ADDR) { *(volatile uint32_t*)DOUT0_ADDR = value; value >>= 1; } ... if constexpr (DOUT15_ADDR) { *(volatile uint32_t*)DOUT15_ADDR = value; value >>= 1; } } ... } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 13 декабря, 2019 Опубликовано 13 декабря, 2019 · Жалоба 16 минут назад, Nixon сказал: Цикл не нужен. Посмотрите как реализован SetDout и как определяются DOUTx_ADDR Так вы через bitband биты устанавливаете, по одному. Я, повторюсь, ради удобства использования не желаю терять оптимальность реализации. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Nixon 4 13 декабря, 2019 Опубликовано 13 декабря, 2019 · Жалоба А это все равно быстрее будет чем формировать нужную маску Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 13 декабря, 2019 Опубликовано 13 декабря, 2019 · Жалоба 14 минут назад, Nixon сказал: А это все равно быстрее будет чем формировать нужную маску Если работа по маске не выполняется на этапе компиляции, тогда я вручную её создам. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Nixon 4 13 декабря, 2019 Опубликовано 13 декабря, 2019 · Жалоба Как вы создадите маску для произвольных данных? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 13 декабря, 2019 Опубликовано 13 декабря, 2019 · Жалоба 2 минуты назад, Nixon сказал: Как вы создадите маску для произвольных данных? Маску для битов порта. Данные - это аргументы функций порта. Маска битов порта - по их номерам в структуре, описывающей пины порта. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Nixon 4 13 декабря, 2019 Опубликовано 13 декабря, 2019 · Жалоба Я возможно неправильно вас понимаю, но имея порт шириной 4 на пинах, допустим, <1,3,5,7> и желая установить на него произвольное значение типа 0bxxxx вы не сможете предварительно создать маску этого самого произвольного значения для записи этого значения на нужные пины. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 18 13 декабря, 2019 Опубликовано 13 декабря, 2019 · Жалоба 38 минут назад, Nixon сказал: Я возможно неправильно вас понимаю, но имея порт шириной 4 на пинах, допустим, <1,3,5,7> и желая установить на него произвольное значение типа 0bxxxx вы не сможете предварительно создать маску этого самого произвольного значения для записи этого значения на нужные пины. Да, именно это я и имел в виду, когда написал, что без цикла не обойтись. Хотя, если есть порт типа BSRR в STM32, то можно вычислить две маски - для сброса и для установки битов. В каких-то случаях это будет быстрее. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Nixon 4 13 декабря, 2019 Опубликовано 13 декабря, 2019 · Жалоба Вряд ли. Вам нужно будет вычислить тот же объем работы для создания маски сколько и для прямой записи битбандингом плюс еще сохранение этой маски плюс запись этой маски в нужный регистр. Единственно что может ускорить вывод в порт произвольного значения - это формирование таблицы перекодировки "Значение данных - Маска Set - Маска Reset" на этапе компиляции. Но как вы понимаете кушать память оно будет огого. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 18 13 декабря, 2019 Опубликовано 13 декабря, 2019 · Жалоба 2 часа назад, Nixon сказал: Цикл не нужен. Посмотрите как реализован SetDout и как определяются DOUTx_ADDR Здесь тоже есть цикл, только он, во-первых, по номерам ног шины, а во-вторых, развёрнут. В случае наличия бит-банда, это, конечно, самый оптимальный вариант. К сожалению, бит-банд на GPIO есть не у всех контроллеров, и даже не у всех STM-ок. 22 минуты назад, Nixon сказал: Вряд ли. Вам нужно будет вычислить тот же объем работы для создания маски сколько и для прямой записи битбандингом плюс еще сохранение этой маски плюс запись этой маски в нужный регистр. Единственно что может ускорить вывод в порт произвольного значения - это формирование таблицы перекодировки "Значение данных - Маска Set - Маска Reset" на этапе компиляции. Но как вы понимаете кушать память оно будет огого. Да, согласен. Но ещё подумаю, вдруг осенит:-) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 13 декабря, 2019 Опубликовано 13 декабря, 2019 · Жалоба 1 час назад, Nixon сказал: Я возможно неправильно вас понимаю, но имея порт шириной 4 на пинах, допустим, <1,3,5,7> и желая установить на него произвольное значение типа 0bxxxx вы не сможете предварительно создать маску этого самого произвольного значения для записи этого значения на нужные пины. Чтение-модификация-запись. Я не планирую переупаковывать биты порта GPIO под ширину "виртуальной шины". Главное - чтобы было можно управлять выбранным набором битов. И, да, я предпочитаю BSRR регистры. Записываю и стираю все биты порта одной командой. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 18 13 декабря, 2019 Опубликовано 13 декабря, 2019 · Жалоба 1 час назад, ViKo сказал: Я не планирую переупаковывать биты порта GPIO под ширину "виртуальной шины". Ну, переупаковывать в любом случае придётся. Скажем, если подцепить 8-битный дисплей на произвольные ноги порта. Либо это будет делать сам класс (суб)шины при записи/чтении, либо программист вручную перед этим. Лучше уж пусть это делается в самой (суб)шине, чем каждый раз переделывать свой код при смене порядка ножек. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться