Создание собственной системы стабилизации

rual
oleg70:

Один вопрос : запускаю дебаг эмуляцию, вывожу просмотр состояния регистров View->System Viewer->RCC

версия какая ? у меня 4.70 отладчик для ф3 отсутсвует. Странно что у Вас вообще показывает перифирию, в настройках проекта в Target стоит STM32F303?

oleg70
rual:

Target стоит STM32F303?

Да стоит: STM32F303VC (без Т), версия вроде тоже 4.70.0.0 (вчера качнул),
лезу в “View”->“System Viewer” после начала дебага, а не в “Peripherals”…
может не то смотрю…?

SergDoc

по поводу всего этого дела:

SergDoc:

Уряя заработало!!! rev 2.9.1rc1 скомпилировалась!!!

нашел практически всё - i2c, SPI, Usartы, ну и т.д. порты все практически,
нашел где программируются таймеры, но так и не нашел где же всё-таки порты (входы выходы) назначаются ибо как-то странно - таймер запускается если указан канал, а он в свою очередь берётся из номера порта, а вот где он прописан пока так и не нашел, так же у меня возникнут в следствии этого проблемы с таймерами, т.к. они у меня на другие порты запланированы (в часности 1-й и 5-тый) ну да ладно с этим разберусь, ещё посмотрел - помоему FPU отключен - знаю где включается, надо условия пересмотреть, в общем копать не перекопать 😃

нашел - пойду застрелюсь - шутка, буду разбираться как это всё переназначит на нужные мне таймеры…

по моему вот для начала что мне надо переписать под себя:


extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = {

    /* Top header */

    {_GPIOB,   NULL, NULL, 10, 0, ADCx}, /* D0/PB10 */
    {_GPIOB,   NULL, NULL,  2, 0, ADCx}, /* D1/PB2 */
    {_GPIOB,   NULL, NULL, 12, 0, ADCx}, /* D2/PB12 */
    {_GPIOB,   NULL, NULL, 13, 0, ADCx}, /* D3/PB13 */
    {_GPIOB,   NULL, NULL, 14, 0, ADCx}, /* D4/PB14 */
    {_GPIOB,   NULL, NULL, 15, 0, ADCx}, /* D5/PB15 */
    {_GPIOC,   NULL, _ADC1,  0, 0,   10}, /* D6/PC0 */
    {_GPIOC,   NULL, _ADC1,  1, 0,   11}, /* D7/PC1 */
    {_GPIOC,   NULL, _ADC1,  2, 0,   12}, /* D8/PC2 */
    {_GPIOC,   NULL, _ADC1,  3, 0,   13}, /* D9/PC3 */
    {_GPIOC,   NULL, _ADC1,  4, 0,   14}, /* D10/PC4 */
    {_GPIOC,   NULL, _ADC1,  5, 0,   15}, /* D11/PC5 */
    {_GPIOC, TIMER8, NULL,  6, 1, ADCx}, /* D12/PC6 */
    {_GPIOC, TIMER8, NULL,  7, 2, ADCx}, /* D13/PC7 */
    {_GPIOC, TIMER8, NULL,  8, 3, ADCx}, /* D14/PC8 */
    {_GPIOC, TIMER8, NULL,  9, 4, ADCx}, /* D15/PC9 */
    {_GPIOC,   NULL, NULL, 10, 0, ADCx}, /* D16/PC10 */
    {_GPIOC,   NULL, NULL, 11, 0, ADCx}, /* D17/PC11 */
    {_GPIOC,   NULL, NULL, 12, 0, ADCx}, /* D18/PC12 */
    {_GPIOC,   NULL, NULL, 13, 0, ADCx}, /* D19/PC13 */
    {_GPIOC,   NULL, NULL, 14, 0, ADCx}, /* D20/PC14 */
    {_GPIOC,   NULL, NULL, 15, 0, ADCx}, /* D21/PC15 */
    {_GPIOA, TIMER1, NULL,  8, 1, ADCx}, /* D22/PA8 */
    {_GPIOA, TIMER1, NULL,  9, 2, ADCx}, /* D23/PA9 */
    {_GPIOA, TIMER1, NULL, 10, 3, ADCx}, /* D24/PA10 */
    {_GPIOB, TIMER4, NULL,  9, 4, ADCx}, /* D25/PB9 */

    /* Bottom header */
    /* Note: D{48, 49, 50, 51} are also TIMER2_CH{1, 2, 3, 4}, respectively. */
    /* TODO remap timer 2 in boardInit(); make the appropriate changes here */

    {_GPIOD,   NULL, NULL,  2, 0, ADCx}, /* D26/PD2 */
    {_GPIOD,   NULL, NULL,  3, 0, ADCx}, /* D27/PD3 */
    {_GPIOD,   NULL, NULL,  6, 0, ADCx}, /* D28/PD6 */
    {_GPIOG,   NULL, NULL, 11, 0, ADCx}, /* D29/PG11 */
    {_GPIOG,   NULL, NULL, 12, 0, ADCx}, /* D30/PG12 */
    {_GPIOG,   NULL, NULL, 13, 0, ADCx}, /* D31/PG13 */
    {_GPIOG,   NULL, NULL, 14, 0, ADCx}, /* D32/PG14 */
    {_GPIOG,   NULL, NULL,  8, 0, ADCx}, /* D33/PG8 */
    {_GPIOG,   NULL, NULL,  7, 0, ADCx}, /* D34/PG7 */
    {_GPIOG,   NULL, NULL,  6, 0, ADCx}, /* D35/PG6 */
    {_GPIOB, TIMER3, NULL,  5, 2, ADCx}, /* D36/PB5 */
    {_GPIOB, TIMER4, NULL,  6, 1, ADCx}, /* D37/PB6 */
    {_GPIOB, TIMER4, NULL,  7, 2, ADCx}, /* D38/PB7 */
    {_GPIOF,   NULL, _ADC3,  6, 0,    4}, /* D39/PF6 */
    {_GPIOF,   NULL, _ADC3,  7, 0,    5}, /* D40/PF7 */
    {_GPIOF,   NULL, _ADC3,  8, 0,    6}, /* D41/PF8 */
    {_GPIOF,   NULL, _ADC3,  9, 0,    7}, /* D42/PF9 */
    {_GPIOF,   NULL, _ADC3, 10, 0,    8}, /* D43/PF10 */
    {_GPIOF,   NULL, NULL, 11, 0, ADCx}, /* D44/PF11 */
    {_GPIOB, TIMER3, _ADC1,  1, 4,    9}, /* D45/PB1 */
    {_GPIOB, TIMER3, _ADC1,  0, 3,    8}, /* D46/PB0 */
    {_GPIOA, TIMER5, _ADC1,  0, 1,    0}, /* D47/PA0 */
    {_GPIOA, TIMER2, _ADC1,  1, 2,    1}, /* D48/PA1 */
    {_GPIOA, TIMER2, _ADC1,  2, 3,    2}, /* D49/PA2 */
    {_GPIOA, TIMER2, _ADC1,  3, 4,    3}, /* D50/PA3 */
    {_GPIOA,   NULL, _ADC1,  4, 0,    4}, /* D51/PA4 */
    {_GPIOA,   NULL, _ADC1,  5, 0,    5}, /* D52/PA5 */
    {_GPIOA, TIMER3, _ADC1,  6, 1,    6}, /* D53/PA6 */
    {_GPIOA, TIMER3, _ADC1,  7, 2,    7}, /* D54/PA7 */

    /* FSMC (triple) header */

    {_GPIOF,   NULL, NULL,  0, 0, ADCx}, /* D55/PF0 */
    {_GPIOD,   NULL, NULL, 11, 0, ADCx}, /* D56/PD11 */
    {_GPIOD, TIMER4, NULL, 14, 3, ADCx}, /* D57/PD14 */
    {_GPIOF,   NULL, NULL,  1, 0, ADCx}, /* D58/PF1 */
    {_GPIOD, TIMER4, NULL, 12, 1, ADCx}, /* D59/PD12 */
    {_GPIOD, TIMER4, NULL, 15, 4, ADCx}, /* D60/PD15 */
    {_GPIOF,   NULL, NULL,  2, 0, ADCx}, /* D61/PF2 */
    {_GPIOD, TIMER4, NULL, 13, 2, ADCx}, /* D62/PD13 */
    {_GPIOD,   NULL, NULL,  0, 0, ADCx}, /* D63/PD0 */
    {_GPIOF,   NULL, NULL,  3, 0, ADCx}, /* D64/PF3 */
    {_GPIOE,   NULL, NULL,  3, 0, ADCx}, /* D65/PE3 */
    {_GPIOD,   NULL, NULL,  1, 0, ADCx}, /* D66/PD1 */
    {_GPIOF,   NULL, NULL,  4, 0, ADCx}, /* D67/PF4 */
    {_GPIOE,   NULL, NULL,  4, 0, ADCx}, /* D68/PE4 */
    {_GPIOE,   NULL, NULL,  7, 0, ADCx}, /* D69/PE7 */
    {_GPIOF,   NULL, NULL,  5, 0, ADCx}, /* D70/PF5 */
    {_GPIOE,   NULL, NULL,  5, 0, ADCx}, /* D71/PE5 */
    {_GPIOE,   NULL, NULL,  8, 0, ADCx}, /* D72/PE8 */
    {_GPIOF,   NULL, NULL, 12, 0, ADCx}, /* D73/PF12 */
    {_GPIOE,   NULL, NULL,  6, 0, ADCx}, /* D74/PE6 */
    {_GPIOE,   NULL, NULL,  9, 0, ADCx}, /* D75/PE9 */
    {_GPIOF,   NULL, NULL, 13, 0, ADCx}, /* D76/PF13 */
    {_GPIOE,   NULL, NULL, 10, 0, ADCx}, /* D77/PE10 */
    {_GPIOF,   NULL, NULL, 14, 0, ADCx}, /* D78/PF14 */
    {_GPIOG,   NULL, NULL,  9, 0, ADCx}, /* D79/PG9 */
    {_GPIOE,   NULL, NULL, 11, 0, ADCx}, /* D80/PE11 */
    {_GPIOF,   NULL, NULL, 15, 0, ADCx}, /* D81/PF15 */
    {_GPIOG,   NULL, NULL, 10, 0, ADCx}, /* D82/PG10 */
    {_GPIOE,   NULL, NULL, 12, 0, ADCx}, /* D83/PE12 */
    {_GPIOG,   NULL, NULL,  0, 0, ADCx}, /* D84/PG0 */
    {_GPIOD,   NULL, NULL,  5, 0, ADCx}, /* D85/PD5 */
    {_GPIOE,   NULL, NULL, 13, 0, ADCx}, /* D86/PE13 */
    {_GPIOG,   NULL, NULL,  1, 0, ADCx}, /* D87/PG1 */
    {_GPIOD,   NULL, NULL,  4, 0, ADCx}, /* D88/PD4 */
    {_GPIOE,   NULL, NULL, 14, 0, ADCx}, /* D89/PE14 */
    {_GPIOG,   NULL, NULL,  2, 0, ADCx}, /* D90/PG2 */
    {_GPIOE,   NULL, NULL,  1, 0, ADCx}, /* D91/PE1 */
    {_GPIOE,   NULL, NULL, 15, 0, ADCx}, /* D92/PE15 */
    {_GPIOG,   NULL, NULL,  3, 0, ADCx}, /* D93/PG3 */
    {_GPIOE,   NULL, NULL,  0, 0, ADCx}, /* D94/PE0 */
    {_GPIOD,   NULL, NULL,  8, 0, ADCx}, /* D95/PD8 */
    {_GPIOG,   NULL, NULL,  4, 0, ADCx}, /* D96/PG4 */
    {_GPIOD,   NULL, NULL,  9, 0, ADCx}, /* D97/PD9 */
    {_GPIOG,   NULL, NULL,  5, 0, ADCx}, /* D98/PG5 */
    {_GPIOD,   NULL, NULL, 10, 0, ADCx}, /* D99/PD10 */
    {_GPIOB,   NULL, NULL, 11, 0, ADCx}, /* D100/PB11 */
    {_GPIOB, TIMER4, NULL,  8, 3, ADCx}, /* D101/PB8 */
};

extern const uint8_t boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = {
    13, 14, 15, 16, 23, 24, 25, 26, 38, 39, 46, 47, 48, 49, 50, 51, 54, 55
};

extern const uint8_t boardADCPins[BOARD_NR_ADC_PINS] __FLASH__ = {
    7, 8, 9, 10, 11, 12, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
    54, 55
};

extern const uint8_t boardUsedPins[BOARD_NR_USED_PINS] __FLASH__ = {
    BOARD_LED_PIN, BOARD_BUTTON_PIN, BOARD_JTMS_SWDIO_PIN,
    BOARD_JTCK_SWCLK_PIN, BOARD_JTDI_PIN, BOARD_JTDO_PIN, BOARD_NJTRST_PIN,
    56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 78, 79, 81,
    82, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100
};


#endif

файл laserlab_MP32V1F4.cpp

SergDoc

Таак начались проблемы, не все нужные мне порты есть (заняты возможно usart и spi, а у меня они на других портах)… значит придётся закапываться ещё глубже… начну с портов их самых i2c, usart-ты spi…

SergDoc

блин, ну как же так, половина стандартные библиотеки STM, а половина, я так понимаю - maple, иначе зачем изврат такой с портами? вот и сиди кури этот бамбук, хоть ты с нуля всё начинай, а то получается в двадцати местах меняй всё, ну переименовали порты, так давайте все, а то щас ищи блин что родное, а что переименованое. Да ещё - эклипс подсвечивает, я так понял, “неиспоьзуемые” - невыполняющиеся функции, но потом смотрю и то что надо, тоже частенько подсвечено?

oleg70

Вот вот… И я о том же… Начал с нуля копать родные библиотеки и понял, что написаны они довольно в произвольной форме даже на уровне “дефайнов”, и нахаляву взять кусок кода из одного проекта и присобачить к своему - проблема. (поэтому пошел по пути работы прямо с регистрами и как следствие обошелся всего лишь одним stm32F30x.h файлом пока!).

А теперь по теме ветки: не кажется ли Вам странным что при использовании кватернионов мы на входе (функции расчета) имеем углы с гиры и акса и на выходе тоже получаем углы…??? В чем смысл то ?

HikeR
oleg70:

на выходе тоже получаем углы

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

oleg70

Тогда что ж мы рассчитываем? , подаем на ПИД не их ли ?
Я то думал что как раз на ПИД подаются углы “уставки” с RC приемника и углы текущего положения “тела”, а на выходе получаем заветное значение управляющего воздействия на моторы…

HikeR

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

а кватернион (либо матрица) всего лишь более компактный (либо менее ресурсоемкий) метод хранения текущего положения.

rual
SergDoc:

по моему вот для начала что мне надо переписать под себя:

Сергей, найди функцию которая получает в параметре тип stm32_pin_info , вот она должна настраивать порты и перефирию.

oleg70:

Начал с нуля копать родные библиотеки и понял, что написаны они довольно в произвольной форме даже на уровне “дефайнов”, и нахаляву взять кусок кода из одного проекта и присобачить к своему - проблема.

Не факт, мне очень помогли с Ф1 на Ф3 перелезть.

oleg70:

А теперь по теме ветки: не кажется ли Вам странным что при использовании кватернионов мы на входе (функции расчета) имеем углы с гиры и акса и на выходе тоже получаем углы…??? В чем смысл то ?

Не так, ДУС (гира) даёт мгновенную угловую скорость, аксель дает вектор суммы всех ускорений.
Углы ДУСа и углы на выходе кватерниона не одно и тоже, представьте что самоль летит левым крылом к земле и перекладывает рули высоты на кабрирование, что измениться тангаж или курс?

HikeR:

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

Всё правильно, вот только в этом этом режиме АППАРАТ не знает своё положение в пространстве, а просто пытается удерживать заданные Р/У угловые скорости.

SergDoc
rual:

найди функцию которая получает в параметре тип stm32_pin_info , вот она должна настраивать порты и перефирию.

она там же, кстати не смотрел раньше есть ли такая беда в кеил, но в эклипсе - выделяешь функцию или дефайн какой-нибудь, жмёшь f3 и опля нашлась 😃

oleg70
rual:

Всё правильно, вот только в этом этом режиме АППАРАТ не знает своё положение в пространстве,.

Предлагаю тогда поделиться общими соображениями об организации основного рабочего цикла программы стабилизации по типу:
0.чтение Р/У
1.чтение ДУС.
2.Чтение Акселя.
3.Усреднение ДУС (по желанию)
4.Вычисление углов
и т.д. ,
а то кажется есть разночтения на этот счет.

HikeR
rual:

в этом этом режиме АППАРАТ не знает своё положение в пространстве

так ему и не нужно его знать )

oleg70:

общими соображениями об организации основного рабочего цикла программы стабилизации по типу

вы какие величины стабилизировать хотите и на каком аппарате? а то пример только один напрашивается:

  1. читаем датчики
  2. ничего не делаем
  3. конец цикла
rual
oleg70:

Предлагаю тогда поделиться общими соображениями об организации основного рабочего цикла программы стабилизации по типу:

у меня в основном цикле только терминальный ввод-вывод, всё остальное вычисляется “параллельно” в прерываниях:

  1. готовность ДУС->чтение ДУС -> вычисление текущего положения (цикл 400Гц)
  2. готовность акселя -> чтение акселя -> чтение компаса -> коррекция положения по акселю и компасу
  3. прерывание от ШИМ-> вычисление разностей между задающим и текущим положением -> вычисление ПИД стабилизатора-> расшивка управления на геометрию рамы
  4. прерывание от входного ППМ-> чтение получение параметров от каналов РУ -> формирование задающего кватерниона\
    И ещё несколько менее приорететных потоков (АЦП, УСАРТ и пр.).
oleg70

Поправьте если не прав:
Коррекция положения происходит все же по акселю (компас опционально) и при ручном управлении скорректированная ориентация рамы стремится к ориентации заданной Р/У (приведенной например к диапазону 0-45 грд. по крену и тангажу)
И еще, Александр, как реализовали оцифровку ППМ (аппаратно, программно)?? Хочу попробовать на Capture от таймеров.

rual
oleg70:

Коррекция положения происходит все же по акселю (компас опционально) и при ручном управлении скорректированная ориентация рамы стремится к ориентации заданной Р/У (приведенной например к диапазону 0-45 грд. по крену и тангажу)

Да. Да, я не делал отдельный АКРО режим , смысла в этом не увидел, аппрат всегда знает своё положение (в рамках допустимой ошибки 😃), при желании можно дать РУ вращать заданое положение по всем осям на 360 градусов.

oleg70:

как реализовали оцифровку ППМ (аппаратно, программно)?? Хочу попробовать на Capture от таймеров.

Всё работает в прерывании, в режиме захвата таймером

uint16_t ppm1_buf[4];  /* буфер для значений каналов ППМ */
uint8_t  ppm1_nimp[4]; /* значения счетчиков пропусков ППМ */
/* прерывание по ППМ сигналу */
void TIM_PPM1_IRQHandler(void) /* ППМ 1-4 */
{
 static uint16_t ccr_buf[4]; /* буфер для временного хранения начала импульса */

 uint16_t port = TIM_PPM1->CCER;
 uint16_t ccr;
 if (TIM_GetFlagStatus(TIM_PPM1,TIM_FLAG_CC1) == SET) /* 1 канал */
 {
  ccr = TIM_GetCapture1(TIM_PPM1);
  if((port & TIM_CCER_CC1P) == 0) {
   ccr_buf[0] = ccr;
   TIM_OC1PolarityConfig(TIM_PPM1,TIM_ICPolarity_Falling);
  } else {
   TIM_OC1PolarityConfig(TIM_PPM1,TIM_ICPolarity_Rising);
   if (TIM_GetFlagStatus(TIM_PPM1,TIM_FLAG_CC1OF) == RESET)
    ppm1_buf[0] = ccr - ccr_buf[0];
   else TIM_ClearFlag(TIM_PPM1,TIM_FLAG_CC1OF);
  }
  ppm1_nimp[0] = 0;
  TIM_ClearITPendingBit(TIM_PPM1, TIM_IT_CC1);
 }

 if (TIM_GetFlagStatus(TIM_PPM1,TIM_FLAG_CC2) == SET) /* 2 канал */
 {
  ccr = TIM_GetCapture2(TIM_PPM1);
  if ((port & TIM_CCER_CC2P) == 0) {
   ccr_buf[1] = ccr;
   TIM_OC2PolarityConfig(TIM_PPM1,TIM_ICPolarity_Falling);
  } else {
   TIM_OC2PolarityConfig(TIM_PPM1,TIM_ICPolarity_Rising);
   if (TIM_GetFlagStatus(TIM_PPM1,TIM_FLAG_CC2OF) == RESET)
    ppm1_buf[1] = ccr - ccr_buf[1];
   else TIM_ClearFlag(TIM_PPM1,TIM_FLAG_CC2OF);
  }
  ppm1_nimp[1] = 0;
  TIM_ClearITPendingBit(TIM_PPM1, TIM_IT_CC2);
 }

 if (TIM_GetFlagStatus(TIM_PPM1,TIM_FLAG_CC3) == SET) /* 3 канал */
 {
  ccr = TIM_GetCapture3(TIM_PPM1);
  if((port & TIM_CCER_CC3P) == 0) {
   ccr_buf[2] = ccr;
   TIM_OC3PolarityConfig(TIM_PPM1,TIM_ICPolarity_Falling);
  } else {
   TIM_OC3PolarityConfig(TIM_PPM1,TIM_ICPolarity_Rising);
   if (TIM_GetFlagStatus(TIM_PPM1,TIM_FLAG_CC3OF) == RESET)
    ppm1_buf[2] = ccr - ccr_buf[2];
   else TIM_ClearFlag(TIM_PPM1,TIM_FLAG_CC3OF);
  }
  ppm1_nimp[2] = 0;
  TIM_ClearITPendingBit(TIM_PPM1, TIM_IT_CC3);
 }

 if (TIM_GetFlagStatus(TIM_PPM1,TIM_FLAG_CC4) == SET) /* 4 канал */
 {
  ccr = TIM_GetCapture4(TIM_PPM1);
  if((port & TIM_CCER_CC4P) == 0) {
   ccr_buf[3] = ccr;
   TIM_OC4PolarityConfig(TIM_PPM1,TIM_ICPolarity_Falling);
  } else {
   TIM_OC4PolarityConfig(TIM_PPM1,TIM_ICPolarity_Rising);
   if (TIM_GetFlagStatus(TIM_PPM1,TIM_FLAG_CC4OF) == RESET)
    ppm1_buf[3] = ccr - ccr_buf[3];
   else TIM_ClearFlag(TIM_PPM1,TIM_FLAG_CC4OF);
  }
  ppm1_nimp[3] = 0;
  TIM_ClearITPendingBit(TIM_PPM1, TIM_IT_CC4);
 }

 if (TIM_GetFlagStatus(TIM_PPM1,TIM_FLAG_Update) == SET)
 {
  if (ppm1_nimp[0]< PPM_NCNT) ppm1_nimp[0]++;
  if (ppm1_nimp[1]< PPM_NCNT) ppm1_nimp[1]++;
  if (ppm1_nimp[2]< PPM_NCNT) ppm1_nimp[2]++;
  if (ppm1_nimp[3]< PPM_NCNT) ppm1_nimp[3]++;
  Rdy_PPM1();
  TIM_ClearITPendingBit(TIM_PPM1, TIM_IT_Update);
 }
}
SergDoc

Блин совсем запутался, порты выведеные обозначены как D-тра-ля-ля, а порты не выведеные обозначены цыфирками - а вот где они так обозначаются, наверно одним разрабам известно. Что пишут:

To add a new board type, add a new pair of files to
/wirish/boards/, update the section below with a new “BOARD” type,
and update /wirish/rules.mk to include your boards/your_board.cpp
file in the top-level Makefile build.

тоесть переписать всё под свою плату(создать новую) но всё равно мне надо знать где прячутся порты под цыфрами…

ага, пофиг как, все можно просто цыфирками обозвать или d+цыфирка - без разницы и убрать ненужные добавить нужные, эх понеслась душа в рай 😃

SergDoc

вот как оно это делается:

typedef struct stm32_pin_info {
    gpio_dev *gpio_device;      /**< Maple pin's GPIO device */
    timer_dev *timer_device;    /**< Pin's timer device, if any. */
    adc_dev* adc_device;       /**< ADC device, if any. */
    uint8 gpio_bit;             /**< Pin's GPIO port bit. */
    uint8 timer_channel;        /**< Timer channel, or 0 if none. */
    uint8 adc_channel;          /**< Pin ADC channel, or ADCx if none. */
} stm32_pin_info;

т. е. ненужные заменить нужными, но не удалять, а то нумерация испортится…

rual

d+цифирка эта маплавское (аля ардуинское) обозачение, полагаю такая ботва без маловского ИДЕ реткосный геморой, если только из ИДЕ соответсвующую функцию выдрать.