Перейти к содержанию
    

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

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

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

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

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

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

 

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

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

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ок, понял (пытаюсь). Читаю это:

https://m.habr.com/ru/company/otus/blog/444524/

 

Тогда это нужно было назвать "лямбда-функтором".

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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; }
    }
  ...
  }

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 часа назад, Nixon сказал:

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

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

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, Nixon сказал:

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...