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

|
Здравствуйте! У меня на плате полно разных сигналов управления от STM32F429. В программе нужно ими всеми манипулировать. Использовать стандартные функции HAL неудобно, при написании программы придется часто отвлекаться на плату, чтобы посмотреть, где ножки реально расположены. Даже если дефайном присвоить имя какому то выводу, непонятно на каком он порте - надо смотреть плату. Код HAL_GPIO_WritePin(GPIOA,DAC_RESET,GPIO_PIN_SET); Коллега оборачивает такие вещи в функции Код void gpioDACRESET(void) { HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET); } Но это тоже не дело. Подскажите, как вы решаете такие проблемы?
|
|
|
|
|
Jul 6 2016, 15:57
|
Гуру
     
Группа: Свой
Сообщений: 2 223
Регистрация: 3-03-06
Из: Tomsk
Пользователь №: 14 925

|
Определите понятные названия и используйте тот же HAL_GPIO_WritePin: Код #define DACRESET GPIO_PIN_5 #define DACRESET_port GPIOA #define DACRESET_active GPIO_PIN_SET #define DACRESET_deactive GPIO_PIN_RESET
HAL_GPIO_WritePin(DACRESET_port, DACRESET, DACRESET_active); Цитата(Atlantis- @ Jul 6 2016, 22:40)  Коллега оборачивает такие вещи в функции Коллега не умеет пользоваться определениями, можно записать так: Код #define gpioDACRESET HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET) и потом просто вызывать: gpioDACRESET;
|
|
|
|
|
Jul 6 2016, 16:01
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Сильно доработанные напильником макросы имени Аскольда Волкова: CODE // pin define examples: // LED on GPIOA, bit 1, active level high, // key on GBIOB, bit 6, active level low #define LED A, 1, H #define KEY B, 6, L #define CS1 C, 1, L #define CS2 C, 2, L // usage example: #include "pin_macros.h" void send_spi(uint32_t volatile * cs_pin_bitband);
void test() { DRIVER(LED, OUTPUT); TOGGLE(LED); // toggle LED
if ( ACTIVE(KEY) ) // if key pressed { ON(LED); // turn LED on }
if ( !ACTIVE(KEY) ) // if key not pressed { OFF(LED); // turn LED off }
// works on Cortex-M3 and higher send_spi(BITBAND_OUT(CS1)); send_spi(BITBAND_OUT(CS2)); }
void send_spi(uint32_t volatile * cs_pin_bitband) { cs_pin_bitband = 0; ..... cs_pin_bitband = 1; } разумеется, определения всех ног и #include < pin_macros.h > вынесены в заголовочный файл (hardware.h).
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jul 6 2016, 18:12
|

Профессионал
    
Группа: Свой
Сообщений: 1 333
Регистрация: 27-10-08
Из: Планета Земля
Пользователь №: 41 226

|
Цитата(ViKo @ Jul 6 2016, 19:49)  Юзаю регистры сброса и установки, можно даже одновременно (приоритет у сброса). Никакими дополнительными макросами-шмакросами не пользуюсь, кроме тех, которыми манипулирую битами регистра. Тем более, функциями-... Читайте Референс мануал. Код #define LED_ON() (GPIOB->BSRR = 1 << 1 + 16) //!< Включить светодиод (Low) #define LED_OFF() (GPIOB->BSRR = 1 << 1) //!< Выключить светодиод (High) Особенно если надо код с HAL ужать или надо быстро - через BRR/BSRR самое то.
|
|
|
|
|
Jul 6 2016, 18:44
|
Группа: Участник
Сообщений: 11
Регистрация: 10-05-07
Пользователь №: 27 628

|
Определяю ножки и порты дефайнами: Код #define IPNUT_PIN_0 GPIO_PIN_0 #define IPNUT_PORT_0 GPIOA
#define IPNUT_PIN_1 GPIO_PIN_3 #define IPNUT_PORT_1 GPIOA
#define IPNUT_PIN_2 GPIO_PIN_0 #define IPNUT_PORT_2 GPIOB
#define IPNUT_PIN_3 GPIO_PIN_1 #define IPNUT_PORT_3 GPIOB
#define IPNUT_PIN_4 GPIO_PIN_0 #define IPNUT_PORT_4 GPIOC , объединяю их в массивы: Код const uint16_t inputPin[]={IPNUT_PIN_0, IPNUT_PIN_1, IPNUT_PIN_2, IPNUT_PIN_3, IPNUT_PIN_4, IPNUT_PIN_5, IPNUT_PIN_6, IPNUT_PIN_7, IPNUT_PIN_8, IPNUT_PIN_9, IPNUT_PIN_10, IPNUT_PIN_11, IPNUT_PIN_12, IPNUT_PIN_13, IPNUT_PIN_14, IPNUT_PIN_15};
const GPIO_TypeDef* inputPort[]={ IPNUT_PORT_0, IPNUT_PORT_1, IPNUT_PORT_2, IPNUT_PORT_3, IPNUT_PORT_4, IPNUT_PORT_5, IPNUT_PORT_6, IPNUT_PORT_7, IPNUT_PORT_8, IPNUT_PORT_9, IPNUT_PORT_10, IPNUT_PORT_11, IPNUT_PORT_12, IPNUT_PORT_13, IPNUT_PORT_14, IPNUT_PORT_15}; инициализацию делаю с помощью HAL: Код GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = inputPin[gpioNum]; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = gpioContext[gpioNum].pull; GPIO_InitStruct.Speed = GPIO_SPEED_LOW; HAL_GPIO_Init(inputPort[gpioNum], &GPIO_InitStruct); читаю и устанавливаю через bit-banding: Код #define GPIO_PIN_ISTATE(PORT,PIN) &(*(__I uint32_t *)(PERIPH_BB_BASE + ((((uint32_t)&((PORT)->IDR)) - PERIPH_BASE) << 5) + ((PIN) << 2))) #define GPIO_PIN_ISET(PORT,PIN) (*(__I uint32_t *)(PERIPH_BB_BASE + ((((uint32_t)&((PORT)->ODR)) - PERIPH_BASE) << 5) + ((PIN) << 2)))
#define IPNUT_PIN_STATE(a) GPIO_PIN_ISTATE(inputPorts[a], inputPin[a]) #define IPNUT_PIN_SET(a) GPIO_PIN_ISET(inputPorts[a], inputPin[a])
const uint32_t * inputState[]={ GPIO_PIN_ISTATE(IPNUT_PORT_0, (IPNUT_PIN_0)>>1), GPIO_PIN_ISTATE(IPNUT_PORT_1, (IPNUT_PIN_1)>>1), GPIO_PIN_ISTATE(IPNUT_PORT_2, (IPNUT_PIN_2)>>1), GPIO_PIN_ISTATE(IPNUT_PORT_3, (IPNUT_PIN_3)>>1), GPIO_PIN_ISTATE(IPNUT_PORT_4, (IPNUT_PIN_4)>>1), GPIO_PIN_ISTATE(IPNUT_PORT_5, (IPNUT_PIN_5)>>1), GPIO_PIN_ISTATE(IPNUT_PORT_6, (IPNUT_PIN_6)>>1), GPIO_PIN_ISTATE(IPNUT_PORT_7, (IPNUT_PIN_7)>>1), GPIO_PIN_ISTATE(IPNUT_PORT_8, (IPNUT_PIN_8)>>1), GPIO_PIN_ISTATE(IPNUT_PORT_9, (IPNUT_PIN_9)>>1), GPIO_PIN_ISTATE(IPNUT_PORT_10, (IPNUT_PIN_10)>>1), GPIO_PIN_ISTATE(IPNUT_PORT_11, (IPNUT_PIN_11)>>1), GPIO_PIN_ISTATE(IPNUT_PORT_12, (IPNUT_PIN_12)>>1), GPIO_PIN_ISTATE(IPNUT_PORT_13, (IPNUT_PIN_13)>>1), GPIO_PIN_ISTATE(IPNUT_PORT_14, (IPNUT_PIN_14)>>1), GPIO_PIN_ISTATE(IPNUT_PORT_15, (IPNUT_PIN_15)>>1)}; Код if (*inputState[i]) { ... }
--------------------
timurey.
|
|
|
|
|
Jul 6 2016, 19:12
|
Гуру
     
Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823

|
Цитата(Atlantis- @ Jul 6 2016, 18:40)  Подскажите, как вы решаете такие проблемы? У меня два подхода 1) В сложных контроллерах типа ARM использую осмысленные макросы. Код #define INIT_RS_DIR_PIN() do \ { PORTE_PCR16 = PORT_PCR_MUX(1) |PORT_PCR_DSE_MASK; \ GPIOE_PSOR = 0x01 << 16; \ GPIOE_PDDR |= 0x01 << 16; \ } while (0) #define SET_TRANSMIT() GPIOE_PCOR = 0x01 << 16 #define SET_RECEIVE() GPIOE_PSOR = 0x01 << 16 2) В простых контроллерах типа MSP430 использую более сложные макросы, определяющие назначение портов, их направление и т.д. Но этот вариант сложный, и он требует высшего уровня оптимизации, оправдан, если много проектов на одной плате.
--------------------
Уходя, оставьте свет...
|
|
|
|
|
Jul 6 2016, 19:40
|

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

|
Цитата(Atlantis- @ Jul 6 2016, 18:40)  Даже если дефайном присвоить имя какому то выводу, непонятно на каком он порте - надо смотреть плату.
Коллега оборачивает такие вещи в функции Но это тоже не дело. Подскажите, как вы решаете такие проблемы? Два экрана. На одном всегда открыта плата. Схема платы специально сделана так чтобы понятен был и порт, и функция, и аттрибуты порта. На именах сигналов не зацикливаюсь, переназываю их в течении проекта много раз. Могу в течении дня им несколько раз названия менять. Вся программа пишется так чтобы выдерживать постоянный непрерывный рефакторинг. Не память должна подстраиваться под программу, а программа под память.
|
|
|
|
|
Jul 7 2016, 02:12
|
self made
   
Группа: Свой
Сообщений: 855
Регистрация: 7-03-09
Из: Toronto, Canada
Пользователь №: 45 795

|
Цитата(x893 @ Jul 6 2016, 16:37)  На схеме использую названия вида SIGNAL_PIN - например BUTTON_LEFT_PA1 В программе #define BUTTON_LEFT PA1 или #define BUTTON_LEFT_PA1 PA1 (как обычно PA0 = 0, ..., PB0 = 0x10, ..., PC0 = 0x20 и т.д) Примерно также. #define B1_PIN (M_PORT0 | 13) #define B2_PIN (M_PORT1 | 30) #define B3_PIN (M_PORT0 | 12) #define B4_PIN (M_PORT1 | 31) #define NEW_BUZZ_PIN (M_PORT2 | 1) (т.е. В1 это PORT0.13 etc) Далее используются следующие функции для установки периферии и пуллапов и пулдаунов. ConfigPin2(NEW_VOL_PIN, 0x2, 0x00); ConfigPin2(NEW_BUZZ_PIN, BRIGHTNESS_PIN_PWM_MODE, PULL_DOWN); Включить пин на выход SetPinOut(NEW_BUZZ_PIN); И установить выходной уровень пина: SetPin(SENS_ENA); ClrPin(SENS_ENA);
|
|
|
|
|
Jul 7 2016, 07:35
|
Местный
  
Группа: Участник
Сообщений: 491
Регистрация: 18-05-11
Пользователь №: 65 102

|
Цитата(turnon @ Jul 6 2016, 22:33)  Вся плата описана в pinout.h и например, светодиод:
Также при новой версии железа достаточно поправить только pinout.h Не знал, что можно делать такие дефайны Код #define PIN_LED_GREEN GPIOA, GPIO_Pin_8 это позволяет одному имени PIN_LED_GREEN присвоить сразу и порт GPIOA и ножку порта GPIO_Pin_8! очень не хотелось писать отдельные дефайны типа такого: Код #define PIN_LED_GREEN GPIO_Pin_8 #define PORT_LED GPIOA и потом рулить не очень удобно Код HAL_GPIO_WritePin(PORT_LED,PIN_LED_GREEN,GPIO_PIN_SET); а тут получается намного проще можно сделать Код #define PIN_LED_GREEN GPIOA, GPIO_Pin_8
HAL_GPIO_WritePin(PIN_LED_GREEN,GPIO_PIN_SET); а зачем Вам еще и макрос и как Вы его определяете gpioSet(GPIO_TypeDef* GPIOx, PIN_TYPE pin, uint8_t state) ?
|
|
|
|
|
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-а мануала на чип.
|
|
|
|
|
Jul 10 2016, 09:05
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(AlexandrY @ Jul 10 2016, 14:31)  И этого слишком мало! Если описывать то всё, включая все альтернативные функции. Слишком громоздко. Я при описании предполагаю, что у пина есть некоторые дефолтные опции, и в строке описания пишу только отличия от дефолта. Например: PINSEL(PIN_DFLASH2_CS, GPIO, 12mA); От дефолтного отличается только задание повышенного вых. тока. Если например нужен OpenDrain, добавлю в список OD и т.п. Через запятую. Обязательные у меня только два первых аргумента: номер/порт пина и функция мультиплексора.
|
|
|
|
|
Jul 10 2016, 12:23
|

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

|
Цитата(AlexandrY @ Jul 10 2016, 11:31)  И этого слишком мало! Если описывать то всё, включая все альтернативные функции. Тут немного искажено , поскольку включился автоматический перенос строк, но принцип понять можно. Вы сюда локи и прерывания ещё вынесли - вполне себе... Главное, что читаемо и понятно! Цитата И эта таблица генерится прямо из PDF-а мануала на чип. Вот, а это уже интересно! Поделитесь механизмом! Сперва подумал, какой ацкий труд проделан по написанию каментов, а потом увидел, что и это автоматизировано - респект! Цитата(jcxz @ Jul 10 2016, 10:01)  Не понял вопрос про задание активного уровня. При инициализации пина ему задаётся некое начальное значение (если это GPIO-пин), а потом меняется драйвером по его алгоритму. Есть у меня макросы установки/сброса/... текущего состояния GPIO-пина. Описывал их выше. Смысл H и L в макросах не только в задании начального состояния, но и в том чтобы не думать о нём вовсе. pin_set(PIN_NAME); pin_clr(PIN_NAME); задают состояние ноги напрямую без учёта H и L, а pin_drive(PIN_NAME, VALUE) задаёт активное/пассивное состояние c учётом активного уровня. Поэтому в коде программы или коде драйвера я использую только pin_drive(PIN_NAME, VALUE), чтобы не думать о активном уровне. В ваших макросах явно напрашивается третий аргумент: А,12,H или B,5,L
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|