|
|
  |
Научите красиво дергать ножками STM32 |
|
|
|
Jul 7 2016, 14:29
|
Местный
  
Группа: Участник
Сообщений: 491
Регистрация: 18-05-11
Пользователь №: 65 102

|
Почему то не получается сделать макрос Код #define SET(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) HAL_GPIO_WritePin(GPIOx,GPIO_Pin,GPIO_PIN_SET) компилятор ругается на знак * хедэр где прописан GPIO_TypeDef подключен
|
|
|
|
|
Jul 8 2016, 06:16
|
Местный
  
Группа: Свой
Сообщений: 340
Регистрация: 17-10-14
Пользователь №: 83 207

|
Цитата(Atlantis- @ Jul 7 2016, 10:35)  Не знал, что можно делать такие дефайны Можно конечно, ведь это просто кусок текста вставляемый препроцессором в заданное место перед компиляцией. Цитата(Atlantis- @ Jul 7 2016, 10:35)  Код #define PIN_LED_GREEN GPIOA, GPIO_Pin_8 это позволяет одному имени PIN_LED_GREEN присвоить сразу и порт GPIOA и ножку порта GPIO_Pin_8! Именно. Цитата(Atlantis- @ Jul 7 2016, 10:35)  HAL_GPIO_WritePin(PIN_LED_GREEN,GPIO_PIN_SET);[/code] а зачем Вам еще и макрос и как Вы его определяете gpioSet(GPIO_TypeDef* GPIOx, PIN_TYPE pin, uint8_t state) ? У меня единый gpio_utils.c для STM8/STM32, а в нем уже реализации (макросы) под каждый МК. Чтобы не вспоминать каждый раз у кого там GPIO_SetBits, а у кого GPIO_WriteHigh. Ну и появлется возможность передать в качестве значения пина булевое выражение, а не делать if
|
|
|
|
|
Jul 8 2016, 09:33
|
Местный
  
Группа: Участник
Сообщений: 491
Регистрация: 18-05-11
Пользователь №: 65 102

|
Цитата(jcxz @ Jul 8 2016, 00:50)  Жесть какая.... Откройте учебник по си! Макрос - это не функция: #define SET(GPIOx, GPIO_Pin) ... Извините, я макросами никогда не пользовался, просто у turnon было написано gpioSet(GPIO_TypeDef* GPIOx, PIN_TYPE pin, uint8_t state), поэтому я тоже начал типы вставлять. В общем, сделал так Код // Тестовые точки #define TEST_X1 GPIOC,GPIO_PIN_14 #define TEST_X2 GPIOG,GPIO_PIN_12 #define TEST_X3 GPIOG,GPIO_PIN_13
#define SET(port_pin) HAL_GPIO_WritePin(port_pin,GPIO_PIN_SET) #define RESET(port_pin) HAL_GPIO_WritePin(port_pin,GPIO_PIN_RESET) #define TOGGLE(port_pin) HAL_GPIO_TogglePin(port_pin)
//вызов TOGGLE(TEST_X1); SET(TEST_X2); RESET(TEST_X3);
|
|
|
|
|
Jul 8 2016, 11:20
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Вот теперь уже лучше. У меня в проектах примерно также, только пин я определяю короче: #define PIN_SSP1_SCLK F, 4 #define PIN_SSP1_TX 1, 4 #define PIN_SSP1_RX 1, 3 #define PIN_LCD_LED 6, 9 Если нужно, потом к ним можно приклеить необходимые префиксы/суффиксы (типа GPIO): GPIO##port внутри макросов Подобно: #define SET_(port, pin) GPIO##port, GPIO_PIN_##pin #define SET(port_pin) SET_(port_pin) И не пользуюсь никакими HAL-ами, а прямо внутри этих макросов обращаюсь к регистрам GPIO.
|
|
|
|
|
Jul 8 2016, 12:05
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(jcxz @ Jul 8 2016, 14:20)  только пин я определяю короче: И зря. Вы лишаете себя таких благ как: Код pin_init(PIN_RTC_SELECT); ... pin_drive(PIN_RTC_SELECT, 1); // do something pin_drive(PIN_RTC_SELECT, 0); Как видите, совсем не надо запариваться ни о инициализации, но о активном уровне.
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Jul 8 2016, 16:44
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(demiurg_spb @ Jul 8 2016, 18:05)  И зря. Вы лишаете себя таких благ как: Не понял чего именно я лишаюсь.... Инициализация пинов у меня делается примерно так: Код //Распределение SSI-портов #define nSSI_hsdc 1 //номер SSI для ADE.HSDC #define nSSI_storage 3 //номер SSI для FRAM, DFLASH0, DFLASH1 (система хранения) #define PIN_FRAM_CS F, 2 //CS для чипа FRAM #define PIN_ADE_IRQ0 P, 0 //прерывание 0 от ADE //Если скопом инитятся несколько пинов: static TPinSel const t_iocon[] = { PINSEL(PIN_FRAM_CS, GPIO, SL, 12mA), PINSEL(PIN_ADE_IRQ0, GPIO, PU); PINSEL(concat(PIN_SSI, nSSI_storage, _MOSI), concat(SSI, nSSI_storage, _XDAT0), PD, SL, 12mA), PINSEL(concat(PIN_SSI, nSSI_storage, _MISO), concat(SSI, nSSI_storage, _XDAT1), PD, SL, 12mA), ... }; PinSelN(t_iocon); //Если по одному пину: PinSel1(PIN_FRAM_CS, GPIO, SL, 12mA); PinSel1(PIN_ADE_IRQ0, GPIO, PU), PinSel1(concat(PIN_SSI, nSSI_storage, _MOSI), concat(SSI, nSSI_storage, _XDAT0), PD, SL, 12mA); PinSel1(concat(PIN_SSI, nSSI_storage, _MISO), concat(SSI, nSSI_storage, _XDAT1), PD, SL, 12mA); ... В списке аргументов макросов PINSEL и PinSel1 - опции доступные для данного пина (подтяжка: PU или PD; фильтр: SL; макс.ток: 2ma, 4ma, 8ma, 12ma, 18ma... и т.п.). Первый аргумент в списке - имя пина (заданное define), второй - функция (GPIO или одна из спец.функций доступных на этом пине), далее - опциональный список опций пина произвольной длины. PinSel1 и PinSelN конфигурят как опции пина(-ов) типа pullup, pulldown, opendrain и т.п., так и программируют мультиплексор пинов на нужную функцию. Здесь я привёл примеры для Tiva, но в других проектах на других МК у меня организовано подобным образом, только список опций пинов другой. И есть кучка макросов типа Pset(PIN_...), Pclr(PIN_...), Pval(PIN_...), Pin(PIN_...), Pout(PIN_...) и т.п. Такие имена макросов у меня тоже одинаковые для разных проектов на разных МК, только реализация внутри разная, зависящая от периферии. И совсем не запариваюсь о инициализации и т.п.  При добавлении нового пина просто добавляю ещё одну запись с описанием необходимых его опций. И очень легко переназначать пины, менять назначение портов (UART, SPI, ...).
|
|
|
|
|
Jul 8 2016, 20:00
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(jcxz @ Jul 8 2016, 19:44)  И совсем не запариваюсь о инициализации и т.п.  Не увидел у вас, где определяется активный уровень H или L и то, что вы привели, не выглядит для меня разумным. Есть драйвер чего бы то ни было и именно он в своей функции driver_init() вызывает pin_init(PIN_NAME) для своих линий ввода-вывода без каких либо дополнительных аргументов и дёргает ногами на своё усмотрение. Смысл абстракции именно в этом! А у вас куча совершенно лишних буков там, где их быть не должно. ГОРАЗДО разумнее в одной строке задефайнить всё сразу: и номер пина, и порт, и активный уровень, и все режимы работы порта, и ремапы, а не размазывать сопли по коду. Пример для STM32F37x Код #define PIN_BTN_USER A,0,H,REMAP_NONE,INPUT_PULL_DOWN,SPEED_NONE #define PIN_UART2_RTS A,1,H,REMAP_NONE,OUTPUT_PUSH_PULL,SPEED_2MHZ // # software_RTS #define PIN_UART2_TX A,2,L,REMAP_AF07,OUTPUT_PUSH_PULL,SPEED_2MHZ // # #define PIN_UART2_RX A,3,L,REMAP_AF07,INPUT_PULL_UP,SPEED_NONE // #
#define PIN_LAMP_BLUE E,12,H,REMAP_NONE,OUTPUT_PUSH_PULL,SPEED_2MHZ #define PIN_LAMP_RED E,13,H,REMAP_NONE,OUTPUT_PUSH_PULL,SPEED_2MHZ
pin_init(PIN_LAMP_RED);
for(;;) delay_ms(500), pin_toggle(PIN_LAMP_RED); Вы лишаетесь прозрачности и удобства описания таргета: одна нога - одна строка и НИКАКИХ завязок более. Даже если вы, например, поставили инвертор в цепи где его в прошлой плате не было, то НИЧЕГО в коде менять не надо. Заметьте, именно так выходит полностью абстрагироваться от таргета и в смысле схемотехники платы, и в смысле типа MCU: хотите AVR, хотите STM32, хотите чёрта в ступе. НИ один высокоуровневый драйвер патчить не придётся вовсе. Создал новое описание таргета lowlevel333.h и в путь, не меняя в проекте ни одной строчки. Предвосхищая ваши попытки сказать, что у меня, мол, тоже только один файл описания... Тоже, да не совсем - вы решили лишь половину задачи и ту не самым красивым способом. У каждого своё чувство прекрасного и я не хочу вас обидеть, но мне нередко смешно и грустно читать ваши безапелляционные посты, в которых, надо признать, часто много правильных мыслей... Цитата(arhiv6 @ Jul 8 2016, 19:54)  Не интересно смотреть. Своё уже давно написано. Но на первый взгляд не понравилась нотация макросов. Вы не учитываете некоторые весьма оправданные рекомендации, как то: если поведение макроса неотличимо от поведения функции, этот макрос должен быть назван с использованием строчных, а не ЗАГЛАВНЫХ букв, от которых рябит в глазах. Плюс выбраны не самые удачные имена HIGH, LOW - H,L достаточно на 100%. PIN_CONFIGURATION - очуметь как много букв!!! pin_init, pin_setup, pin_cfg - это синонимы не скрывающие смысла происходящего. В этом ключе, да и других направлениях есть куда расти... Чтобы стать профи никогда не стоит пренебрегать чтением профессиональной литературы - там зачастую есть чему поучиться. А про то, как правильно выбирать названия переменным и функциям, вообще в букварях пишут))) 2ALL: перечитайте название этого топика ещё раз, прежде чем сюда написать.
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Jul 8 2016, 21:42
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(demiurg_spb @ Jul 9 2016, 02:00)  ГОРАЗДО разумнее в одной строке задефайнить всё сразу: и номер пина, и порт, и активный уровень, и все режимы работы порта, и ремапы, а не размазывать сопли по коду. У меня как раз все режимы пина одной строкой и задаются. Но его номер и номер порта на котором он находится (или просто номер ноги корпуса) задаётся отдельно. Мне так удобнее, так как у нас обычно разрабатывается не одно устройство, а линейка устройств с подобным функционалом и, соответственно, с такими-же почти ногами, но с разной схемой, так что в одном из устройств линейки этот вывод находится на одной ноге, а в другом - на другой. И файлы работы с пинами - общие, свой только для каждого конкретного устройства, файл описания распределения пинов по реальным ногам чипа. Так что строки режимов для PIN_... - общие для всей линейки в одном файле, а вот файлы с присвоением PIN_.... номеров ног - разные. А где у меня лишние буквы? Вроде всё по минимуму...
|
|
|
|
|
Jul 10 2016, 07:01
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(demiurg_spb @ Jul 9 2016, 04:00)  ИМХО одна строка всегда яснее чем две. Но идея с разделением ясна и она действительно м.б. оправдана в случае действительно огромного кол-ва вариантов железа ИМЕННО c прыгающими ногами. Мне сложно такое вообразить (сегодня реле PORTA,2 завтра PORTB,3, а в пятницу первый отряд лагеря меняется бельём со вторым). У меня за более чем 15-ти летнюю поддержку разных линеек приборов КИП и ПЛК наблюдается максимум 6-ой вариант железа у одного из них. У вас что, это чаще происходит? Вы в какой сфере варитесь? И что же вы про задание активного уровня не говорите ничего - у вас он тоже в конфиг режимов задвинут и как же ж он работает?))) ИМХО у вас этого функционала просто нет. Блин - написал такое развёрнутое сообщение с описанием, и грёбаный сайт глюканул и всё потерялось  (((((((((((((((( Заново писать неохота. Но вкратце: новые вариации железа у нас появляются не только во время поддержки устройства, а уже при старте разработки: сразу запускается линейка устройств с примерно одинаковым ПО, но разных схемотехнически. Например: счётчик э/энергии 1-фазный прямого включения, счётчик э/энергии 3-фазный прямого включения, счётчик э/энергии 3-фазный трансформаторный, контроллер сбора данных, .... У каждого из этих устройств линейки отдельное ПО, но большая часть файлов этих отдельных проектов - одинакова (просто копируется из проекта в проект). И у каждого есть файл описания номеров пинов, а вот уже работа с этими пинами может находиться в общих файлах драйверов, которые одинаковые для всех этих проектов. Эти устройства в линейке могут быть построены даже на разных МК (в прошлой линейке использовались МК: LPC1758, LPC1778, а у них некоторая периферия совершенно разная (например - мультиплексор пинов)). Плюс ещё: у каждого из устройств линейки может быть несколько исполнений (в том числе и новых исполнений, появляющихся уже во время жизни устройства, если заказчик вдруг захотел другой набор аппаратных опций). Опции например такие: RS-485 (или несколько), ZigBee, GSM, Ethernet, PLC, RF, реле отключения фаз, осциллографирование, резервное питание и др. Разные исполнения - разная комбинация этих аппаратных опций. И количество файлов в проектах ПО очень большое. Так что и стараемся при добавлении нового функционала или при смене ног, минимально трогать готовые файлы например с драйверами устройств. Работаю я в сфере разработки устройств для э/энергетики: счётчики э/энергии, контроллеры присоединений, ... Сейчас новая линейка в разработке на базе МК Tiva (от TI), но тоже - разные устройства в линейке построены на разных МК Tiva, плюс имеют - разный набор периферии внутри: один или два чипа флешь, (одного или другого типа), разные чипы FRAM, наличие или отсутствие других чипов (в зависимости от необходимого функционала). Места на платах очень мало, да надо ещё подешевле. Так что есть более дешёвые устройства в линейке, есть дороже. На более дешёвых может и плата меньше слоёв иметь. К тому же - есть ограничения по размеру платы, ограничения накладываемые необходимостью гальванической развязки и т.п. Это приводит к тому, что распределение пинов получается разным (по портам и номерам), но драйвера периферии должны быть по возможности одинаковыми. Вот поэтому у нас для каждого устройства в линейке свой файл распределения пинов по номерам портов и разрядов, а инит их - общие файлы. Не понял вопрос про задание активного уровня. При инициализации пина ему задаётся некое начальное значение (если это GPIO-пин), а потом меняется драйвером по его алгоритму. Есть у меня макросы установки/сброса/... текущего состояния GPIO-пина. Описывал их выше.
|
|
|
|
|
Jul 10 2016, 08:31
|

Ally
     
Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050

|
Цитата(demiurg_spb @ Jul 8 2016, 23:00)  Не увидел у вас, где определяется активный уровень H или L и то, что вы привели, не выглядит для меня разумным. ГОРАЗДО разумнее в одной строке задефайнить всё сразу: и номер пина, и порт, и активный уровень, и все режимы работы порта, и ремапы, а не размазывать сопли по коду. Пример для STM32F37x Код #define PIN_BTN_USER A,0,H,REMAP_NONE,INPUT_PULL_DOWN,SPEED_NONE #define PIN_UART2_RTS A,1,H,REMAP_NONE,OUTPUT_PUSH_PULL,SPEED_2MHZ // # software_RTS И этого слишком мало! Если описывать то всё, включая все альтернативные функции. Вот так: Код // gpio port num irqc lock mux DSE SRE ODE PFE PUPD dir init { PTA_BASE_PTR, PORTA_BASE_PTR, 0, IRQ_DIS, 0, ALT7, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // *JTCLK/SWC 50 # PTA0 # Default=(JTAG_TCLK/SWD_CLK/EZP_CLK) ALT0=(TSI0_CH1) ALT1=(PTA0) ALT2=(UART0_CTS_b/UART0_COL_b) ALT3=(FTM0_CH5) ALT4=() ALT5=(LPUART0_CTS_b) ALT6=() ALT7=(JTAG_TCLK/SWD_CLK) EZPort=(EZP_CLK) { PTA_BASE_PTR, PORTA_BASE_PTR, 1, IRQ_DIS, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_OUT, 1 }, // *JTDI (LED) 51 # PTA1 # Default=(JTAG_TDI/EZP_DI) ALT0=(TSI0_CH2) ALT1=(PTA1) ALT2=(UART0_RX) ALT3=(FTM0_CH6) ALT4=(I2C3_SDA) ALT5=(LPUART0_RX) ALT6=() ALT7=(JTAG_TDI) EZPort=(EZP_DI) { PTA_BASE_PTR, PORTA_BASE_PTR, 2, IRQ_DIS, 0, ALT7, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // *JTDO/SWO 52 # PTA2 # Default=(JTAG_TDO/TRACE_SWO/EZP_DO) ALT0=(TSI0_CH3) ALT1=(PTA2) ALT2=(UART0_TX) ALT3=(FTM0_CH7) ALT4=(I2C3_SCL) ALT5=(LPUART0_TX) ALT6=() ALT7=(JTAG_TDO/TRACE_SWO) EZPort=(EZP_DO) { PTA_BASE_PTR, PORTA_BASE_PTR, 3, IRQ_DIS, 0, ALT7, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // *JTMS/SWD 53 # PTA3 # Default=(JTAG_TMS/SWD_DIO) ALT0=(TSI0_CH4) ALT1=(PTA3) ALT2=(UART0_RTS_b) ALT3=(FTM0_CH0) ALT4=() ALT5=(LPUART0_RTS_b) ALT6=() ALT7=(JTAG_TMS/SWD_DIO) EZPort=() { PTA_BASE_PTR, PORTA_BASE_PTR, 4, IRQ_DIS, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // - 54 # PTA4/LLWU_P3 # Default=(NMI_b/EZP_CS_b) ALT0=(TSI0_CH5) ALT1=(PTA4/LLWU_P3) ALT2=() ALT3=(FTM0_CH1) ALT4=() ALT5=() ALT6=() ALT7=(NMI_b) EZPort=(EZP_CS_b) { PTA_BASE_PTR, PORTA_BASE_PTR, 5, IRQ_DIS, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // - 55 # PTA5 # Default=(DISABLED) ALT0=() ALT1=(PTA5) ALT2=(USB0_CLKIN) ALT3=(FTM0_CH2) ALT4=(RMII0_RXER/MII0_RXER) ALT5=(CMP2_OUT) ALT6=(I2S0_TX_BCLK) ALT7=(JTAG_TRST_b) EZPort=() { PTA_BASE_PTR, PORTA_BASE_PTR, 6, IRQ_DIS, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // - 58 # PTA6 # Default=(DISABLED) ALT0=() ALT1=(PTA6) ALT2=() ALT3=(FTM0_CH3) ALT4=() ALT5=(CLKOUT) ALT6=() ALT7=(TRACE_CLKOUT) EZPort=() { PTA_BASE_PTR, PORTA_BASE_PTR, 7, IRQ_DIS, 0, ALT0, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // INP8 59 # PTA7 # Default=(ADC0_SE10) ALT0=(ADC0_SE10) ALT1=(PTA7) ALT2=() ALT3=(FTM0_CH4) ALT4=() ALT5=(RMII0_MDIO/MII0_MDIO) ALT6=() ALT7=(TRACE_D3) EZPort=() Тут немного искажено , поскольку включился автоматический перенос строк, но принцип понять можно. И эта таблица генерится прямо из PDF-а мануала на чип.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|