Jump to content

    

Нетиповой вариативный шаблон класса. Помогите написать.

7 минут назад, ViKo сказал:

Будем смотреть, во что компилируется, а не сколько в нём этажей.

Ну, запись/чтение шины сложно будет оптимизировать, для случая произвольного расположения ножек. Без цикла, думаю, не обойтись.

А вот, например, конфигурирование группы ножек будет красивым:

template <char portLetter = 'A'>
class Port
{
	...
	// вложенный класс "шина"
	template<unsigned... Pins>
	struct Bus
	{
		static void setOutput() {
			getPortStruct()->pinDirs |= getMask();
		}
		...
	}
};

 

Share this post


Link to post
Share on other sites
21 час назад, ViKo сказал:

Не соглашусь, что лямбда-функция - это функтор. Лямбда-выражения в C++ используются именно в виде анонимных функций, без имени, адреса, используемых в месте определения.

Так функтор-то и нужен для того, чтобы иметь синтаксис использования функции - чтобы его можно было использовать так как обычную функцию. Но тем не менее он от этого функцией не становится. Это объект, который содержит данные и осуществляет вызов в своём контексте (что очень полезно, например, для создания замыканий (closure)). И лямбда в С++ - это просто анонимный функтор. 

 

21 час назад, ViKo сказал:

Насчет порядка функций - это, видимо, из питона и т.п. термин. В учебниках по C/C++/C# не встречал. Да и какой может быть порядок, если вложенные функции невозможны. Кроме этих лямбд.

Ни разу не из питона, это из computer science. Загуглите "объект первого класса", там всё достаточно просто. В более высокоуровневых языках, нежели С/С++, функции являются объектами исходно (типа "функторами" если по плюсовому), поэтому сразу обладают соответствующими свойствами. Хоть в том же легковесном Lua и множестве других ЯП.

21 час назад, ViKo сказал:

Нисколько не сомневаюсь, что вы продвинутый программист и в теории и на практике. Однако, лямбда-функция означает лямбда в форме функции. Или наоборот. И уж точно не было корректным ваше безоговорочное "не функции вообще". 

Уже подробно объяснил выше, в чём принципиальная разница: одно - это вызываемый код, процедура, второе - объект. И кстати, я не программист.

Share this post


Link to post
Share on other sites
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; }
    }
  ...
  }

 

Share this post


Link to post
Share on other sites
16 минут назад, Nixon сказал:

Цикл не нужен. Посмотрите как реализован SetDout и как определяются DOUTx_ADDR

Так вы через bitband биты устанавливаете, по одному.
Я, повторюсь, ради удобства использования не желаю терять оптимальность реализации.

Share this post


Link to post
Share on other sites

А это все равно быстрее будет чем формировать нужную маску

Share this post


Link to post
Share on other sites
14 минут назад, Nixon сказал:

А это все равно быстрее будет чем формировать нужную маску

Если работа по маске не выполняется на этапе компиляции, тогда я вручную её создам.

Share this post


Link to post
Share on other sites

Как вы создадите маску для произвольных данных?

Share this post


Link to post
Share on other sites
2 минуты назад, Nixon сказал:

Как вы создадите маску для произвольных данных?

Маску для битов порта. Данные - это аргументы функций порта.

Маска битов порта - по их номерам в структуре, описывающей пины порта.

Share this post


Link to post
Share on other sites

Я возможно неправильно вас понимаю, но имея порт шириной 4 на пинах, допустим, <1,3,5,7> и желая установить на него произвольное значение типа 0bxxxx вы не сможете предварительно создать маску этого самого произвольного значения для записи этого значения на нужные пины.   

Share this post


Link to post
Share on other sites
38 минут назад, Nixon сказал:

Я возможно неправильно вас понимаю, но имея порт шириной 4 на пинах, допустим, <1,3,5,7> и желая установить на него произвольное значение типа 0bxxxx вы не сможете предварительно создать маску этого самого произвольного значения для записи этого значения на нужные пины.   

Да, именно это я и имел в виду, когда написал, что без цикла не обойтись.

Хотя, если есть порт типа BSRR в STM32, то можно вычислить две маски - для сброса и для установки битов. В каких-то случаях это будет быстрее.

Share this post


Link to post
Share on other sites

Вряд ли. Вам нужно будет вычислить тот же объем работы для создания маски сколько и для прямой записи битбандингом плюс еще сохранение этой маски плюс запись этой маски в нужный регистр.

Единственно что может ускорить вывод в порт произвольного значения - это формирование таблицы перекодировки "Значение данных - Маска Set - Маска Reset" на этапе компиляции. Но как вы понимаете кушать память оно будет огого. 

Share this post


Link to post
Share on other sites
2 часа назад, Nixon сказал:

Цикл не нужен. Посмотрите как реализован SetDout и как определяются DOUTx_ADDR 

Здесь тоже есть цикл, только он, во-первых, по номерам ног шины, а во-вторых, развёрнут. В случае наличия бит-банда, это, конечно, самый оптимальный вариант. К сожалению, бит-банд на GPIO есть не у всех контроллеров, и даже не у всех STM-ок.

22 минуты назад, Nixon сказал:

Вряд ли. Вам нужно будет вычислить тот же объем работы для создания маски сколько и для прямой записи битбандингом плюс еще сохранение этой маски плюс запись этой маски в нужный регистр.

Единственно что может ускорить вывод в порт произвольного значения - это формирование таблицы перекодировки "Значение данных - Маска Set - Маска Reset" на этапе компиляции. Но как вы понимаете кушать память оно будет огого. 

Да, согласен. Но ещё подумаю, вдруг осенит:-)

Share this post


Link to post
Share on other sites
1 час назад, Nixon сказал:

Я возможно неправильно вас понимаю, но имея порт шириной 4 на пинах, допустим, <1,3,5,7> и желая установить на него произвольное значение типа 0bxxxx вы не сможете предварительно создать маску этого самого произвольного значения для записи этого значения на нужные пины.   

Чтение-модификация-запись. Я не планирую переупаковывать биты порта GPIO под ширину "виртуальной шины". Главное - чтобы было можно управлять выбранным набором битов.
И, да, я предпочитаю BSRR регистры. Записываю и стираю все биты порта одной командой.

Share this post


Link to post
Share on other sites
1 час назад, ViKo сказал:

Я не планирую переупаковывать биты порта GPIO под ширину "виртуальной шины".

Ну, переупаковывать в любом случае придётся. Скажем, если подцепить 8-битный дисплей на произвольные ноги порта. Либо это будет делать сам класс (суб)шины при записи/чтении, либо программист вручную перед этим. Лучше уж пусть это делается в самой (суб)шине, чем каждый раз переделывать свой код при смене порядка ножек.

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now