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

Задумал сделать класс типа Port, состоящий из объектов типа Pin. Чтобы манипулировать не по одной ножке, а целым портом. Правильно ли я думаю, что мне нужны шаблонные классы Pin, вложенные в шаблон Port?

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


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

13 minutes ago, ViKo said:

Задумал сделать класс типа Port, состоящий из объектов типа Pin. Чтобы манипулировать не по одной ножке, а целым портом. Правильно ли я думаю, что мне нужны шаблонные классы Pin, вложенные в шаблон Port?

Думаю, что лучше сделать свой отдельный шаблон под порт. Параметром шаблона будет базовый адрес порта (uint32_t), не указатель. Скорее всего это будет единственный параметр. Да и нужен ли тут шаблон?

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

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


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

Я так понимаю, если использовать только ссылку на объект шаблонного класса, сам объект не создается. А целый порт нужен для установки режимов всех битов порта одной командой. Я так давно делаю. А заодно и биты устанавливать - сбрасывать одновременно. Не хочу иметь никаких накладных расходов при работе с GPIO (как не имею и сейчас, пользуясь #define). 

Изменено пользователем ViKo

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


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

С портом так:

Спойлер

template<char port_name, 
	Mode_td m00, Type_td t00, Speed_td s00, Pull_td p00, Altf_td a00,
	Mode_td m01, Type_td t01, Speed_td s01, Pull_td p01, Altf_td a01,
	Mode_td m02, Type_td t02, Speed_td s02, Pull_td p02, Altf_td a02,
	Mode_td m03, Type_td t03, Speed_td s03, Pull_td p03, Altf_td a03,
	Mode_td m04, Type_td t04, Speed_td s04, Pull_td p04, Altf_td a04,
	Mode_td m05, Type_td t05, Speed_td s05, Pull_td p05, Altf_td a05,
	Mode_td m06, Type_td t06, Speed_td s06, Pull_td p06, Altf_td a06,
	Mode_td m07, Type_td t07, Speed_td s07, Pull_td p07, Altf_td a07,
	Mode_td m08, Type_td t08, Speed_td s08, Pull_td p08, Altf_td a08,
	Mode_td m09, Type_td t09, Speed_td s09, Pull_td p09, Altf_td a09,
	Mode_td m10, Type_td t10, Speed_td s10, Pull_td p10, Altf_td a10,
	Mode_td m11, Type_td t11, Speed_td s11, Pull_td p11, Altf_td a11,
	Mode_td m12, Type_td t12, Speed_td s12, Pull_td p12, Altf_td a12,
	Mode_td m13, Type_td t13, Speed_td s13, Pull_td p13, Altf_td a13,
	Mode_td m14, Type_td t14, Speed_td s14, Pull_td p14, Altf_td a14,
	Mode_td m15, Type_td t15, Speed_td s15, Pull_td p15, Altf_td a15>
class Port_c
{
	static constexpr GPIO_TypeDef *Port =
		port_name == 'A' ? GPIOA :
		port_name == 'B' ? GPIOB :
		port_name == 'C' ? GPIOC :
		port_name == 'D' ? GPIOD :
		port_name == 'E' ? GPIOE :
		port_name == 'G' ? GPIOG :
		GPIOH;

public:
	static void config()
	{
		Port->PUPDR =
			p15 << 30 | p14 << 28 | p13 << 26 | p12 << 24 |
			p11 << 22 | p10 << 20 | p09 << 18 | p08 << 16 |
			p07 << 14 | p06 << 12 | p05 << 10 | p04 <<  8 |
			p03 <<  6 | p02 <<  4 | p01 <<  2 | p00 <<  0 ;
		Port->OTYPER =
			t15 << 15 | t14 << 14 | t13 << 13 | t12 << 12 |
			t11 << 11 | t10 << 10 | t09 <<  9 | t08 <<  8 |
			t07 <<  7 | t06 <<  6 | t05 <<  5 | t04 <<  4 |
			t03 <<  3 | t02 <<  2 | t01 <<  1 | t00 <<  0 ;
		Port->AFR[0] =
			a07 << 28 | a06 << 24 | a05 << 20 | a04 << 16 |
			a03 << 12 | a02 <<  8 | a01 <<  4 | a00 <<  0 ;
		Port->AFR[1] =
			a15 << 28 | a14 << 24 | a13 << 20 | a12 << 16 |
			a11 << 12 | a10 <<  8 | a09 <<  4 | a08 <<  0 ;
		Port->MODER =
			m15 << 30 | m14 << 28 | m13 << 26 | m12 << 24 |
			m11 << 22 | m10 << 20 | m09 << 18 | m08 << 16 |
			m07 << 14 | m06 << 12 | m05 << 10 | m04 <<  8 |
			m03 <<  6 | m02 <<  4 | m01 <<  2 | m00 <<  0 ;
	}
};

 

 

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


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

8 minutes ago, ViKo said:

С портом так:

  Hide contents

 

 

 

Когда вижу три параметра в шаблоне или функции, уже начинаю нервничать. А тут аж 81 параметр!

Это серьезная заявка на рекорд Гиннеса ;)

 

Кроме шуток, покажите пример применения в реальном коде. Интересно, как это выглядит "вживую".

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


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

	__nop();
	GPIO_ns::PortA::config();
	
/*-----------------------------------------------------------------------------*/
	
	while (1) {
		__nop();  __nop();
	}
Спойлер

000048  bf00              NOP                            ;71
00004a  490c              LDR      r1,|L1.124|
00004c  480c              LDR      r0,|L1.128|
00004e  60c1              STR      r1,[r0,#0xc]          ;71
000050  2100              MOVS     r1,#0                 ;71
000052  6041              STR      r1,[r0,#4]            ;71
000054  490b              LDR      r1,|L1.132|
000056  6201              STR      r1,[r0,#0x20]         ;71
000058  490b              LDR      r1,|L1.136|
00005a  6241              STR      r1,[r0,#0x24]         ;71
00005c  490b              LDR      r1,|L1.140|
00005e  6001              STR      r1,[r0,#0]            ;71
                  |L1.96|
000060  bf00              NOP                            ;77
000062  bf00              NOP                            ;77
000064  e7fc              B        |L1.96|
;;;80     
                          ENDP

000066  0000              DCW      0x0000
                  |L1.104|
                          DCD      0xb2d05e00
                  |L1.108|
                          DCD      0x01c9c380
                  |L1.112|
                          DCD      0x20004000
                  |L1.116|
                          DCD      0x40020400
                  |L1.120|
                          DCD      0x40020418
                  |L1.124|
                          DCD      0x00285544
                  |L1.128|
                          DCD      0x40020000
                  |L1.132|
                          DCD      0x505510a0
                  |L1.136|
                          DCD      0x000aa17a
                  |L1.140|
                          DCD      0xaaaa8abb

 

 

То было с оптимизацией default. А это -O0:

Спойлер

;;;71     	__nop();
00005e  bf00              NOP      
;;;72     	GPIO_ns::PortA::config();
000060  bf00              NOP      
000062  480c              LDR      r0,|L1.148|
000064  490c              LDR      r1,|L1.152|
000066  60c8              STR      r0,[r1,#0xc]
000068  2000              MOVS     r0,#0
00006a  6048              STR      r0,[r1,#4]
00006c  480b              LDR      r0,|L1.156|
00006e  6208              STR      r0,[r1,#0x20]
000070  490b              LDR      r1,|L1.160|
000072  4809              LDR      r0,|L1.152|
000074  6241              STR      r1,[r0,#0x24]
000076  480b              LDR      r0,|L1.164|
000078  4907              LDR      r1,|L1.152|
00007a  6008              STR      r0,[r1,#0]
00007c  bf00              NOP      
;;;73     	
;;;74     /*-----------------------------------------------------------------------------*/
;;;75     	
;;;76     	while (1) {
00007e  e001              B        |L1.132|
                  |L1.128|
;;;77     		__nop();  __nop();
000080  bf00              NOP      
000082  bf00              NOP      
                  |L1.132|
000084  e7fc              B        |L1.128|

 

 

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


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

В 23.07.2019 в 18:38, AHTOXA сказал:

В моём примере точно не создаются - используются типы и их статические функции.

В вашем примере при хорошем уровне оптимизации - тоже не создаются, что вы и видите в листинге. А при -O0 создадутся.

Ну или если возьмёте адрес созданного объекта ( call_some_func(&Adc1s_n) ) - тоже создадутся.

Вот на засаду напоролся. Создал массив PinA[] из 16 Pin_st структур, описывающих биты порта (режим, тип, скорость и т.д - 5 параметров). Сделал шаблонную функцию, задающую режимы GPIO->MODER, и т.д.

template <char port_name>
static void Port_init(Pin_st Pin[])

И пытаюсь передать в шаблонную функцию адрес этого массива.

static inline void PortA_init(void) {
    Port_init<'A'>(&PinA[0]);
}

И получаю свой PinA[] массив в map размером на все 320 байтов (по слову на параметр). Видимо, никак от него не избавиться?

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

 

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


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

И все манипуляции с установкой режимов порта, какие показаны выше, идут в программе.

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


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

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

И пытаюсь передать в шаблонную функцию адрес этого массива.

Если берёте адрес, то компилятор обязан создать объект.

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


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

53 минуты назад, AHTOXA сказал:

Если берёте адрес, то компилятор обязан создать объект.

Я это уже процитировал. И иначе в функцию не передать массив. Почему нельзя ссылку передавать? Хотя, видимо, и тогда должен создаваться массив.

То есть, этот массив должен быть членом класса. В общем, всё пропало.

О, я же могу не массивом задавать выводы, а поотдельности!

Изменено пользователем ViKo

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


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

Решил я в реальном проекте продолжить когда-то начатое. И столкнулся со следующей проблемой. Возможно, решение простое, но я его не нахожу.

В одном заголовочном файле x.hpp описал выводы МК в виде структур. Все типы описаны как перечисления.
Там же описан и шаблон класса порта со всеми статическими функциями - config, lock, read, write...

/*! GPIO Pin structure  */
struct Pin {
    GpioName    name;            // port name
    GpioBitn    bitn;            // bit number
    GpioMode    mode;            // mode
    GpioType    type;            // output type
    GpioSpeed    speed;            // output speed
    GpioPull    pull;            // pull-up/pull-down
    GpioInit    init;            // initial output data
    GpioLock    lock;            // configuration lock
    GpioAltf    altf;            // alternate function
};
...
template <const Pin & ... PN>
class Gpio
{ ... }

В исходном файле x.cpp определяю выводы. И далее описываю порт целиком.

 static constexpr Pin SNSFLT        { GpioName::na, GpioBitn::bn00, GpioMode::in, GpioType::pp, GpioSpeed::lo, GpioPull::np, GpioInit::hi, GpioLock::lk, GpioAltf::af00 };
...
using GpioA = Gpio <SNSFLT, SNSFIR, TXL1, RXL, TXL2, LPL, ALERT_N, TAMP, 
				INSL, DBGTX, DBGRX, LEDR, LEDG, SWDIO, SWCLK, SNSEN_N>;

Но когда из main функции в файле y.cpp пытаюсь вызвать функцию для конфигурации, получаю ошибку, что SNSFLT не описан.

GpioA::config();

error: use of undeclared identifier 'SNSFLT'

Попробовал заменить на 

extern constexpr Pin SNSFLT        { GpioName::na, GpioBitn::bn00, GpioMode::in, GpioType::pp, GpioSpeed::lo, GpioPull::np, GpioInit::hi, GpioLock::lk, GpioAltf::af00 };

Ничего не меняется. В чем дело?
 

 

Когда же выводы определяются в том же файле y.cpp, компилируется без ошибок.

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


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

static constexpr Pin SNSFLT        { GpioName::na, GpioBitn::bn00, GpioMode::in, GpioType::pp, GpioSpeed::lo, GpioPull::np, GpioInit::hi, GpioLock::lk, GpioAltf::af00 };
...
using GpioA = Gpio <SNSFLT, SNSFIR, TXL1, RXL, TXL2, LPL, ALERT_N, TAMP, 
				INSL, DBGTX, DBGRX, LEDR, LEDG, SWDIO, SWCLK, SNSEN_N>;

Перенёс в x.hpp, всё компилируется. Не нравится, что определение класса и его использование сделано в одном файле. Но можно и на два разделить. Хотя, оставлю так.

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


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

Критикуешь - предлагай! (с)

56 минут назад, Arlleex сказал:

Переносить using в hpp почти всегда плохая идея.

Вообще не вижу проблем. Это же аналог typedef.

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


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

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

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

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

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

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

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

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

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

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