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

Научите красиво дергать ножками STM32

Здравствуйте!

У меня на плате полно разных сигналов управления от STM32F429. В программе нужно ими всеми манипулировать. Использовать стандартные функции HAL неудобно, при написании программы придется часто отвлекаться на плату, чтобы посмотреть, где ножки реально расположены. Даже если дефайном присвоить имя какому то выводу, непонятно на каком он порте - надо смотреть плату.

HAL_GPIO_WritePin(GPIOA,DAC_RESET,GPIO_PIN_SET);

Коллега оборачивает такие вещи в функции

void gpioDACRESET(void)
{
    HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);
}

Но это тоже не дело. Подскажите, как вы решаете такие проблемы?

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


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

Определите понятные названия и используйте тот же 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);

 

Коллега оборачивает такие вещи в функции

Коллега не умеет пользоваться определениями, можно записать так:

#define gpioDACRESET HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET)

и потом просто вызывать:

gpioDACRESET;

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


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

Сильно доработанные напильником макросы имени Аскольда Волкова:

// 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).

STM32_pin_macros.zip

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


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

Юзаю регистры сброса и установки, можно даже одновременно (приоритет у сброса). Никакими дополнительными макросами-шмакросами не пользуюсь, кроме тех, которыми манипулирую битами регистра. Тем более, функциями-...

Читайте Референс мануал.

 

#define LED_ON()    (GPIOB->BSRR = 1 << 1 + 16)    //!< Включить светодиод (Low)
#define LED_OFF()    (GPIOB->BSRR = 1 << 1)        //!< Выключить светодиод (High)

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


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

Юзаю регистры сброса и установки, можно даже одновременно (приоритет у сброса). Никакими дополнительными макросами-шмакросами не пользуюсь, кроме тех, которыми манипулирую битами регистра. Тем более, функциями-...

Читайте Референс мануал.

 

#define LED_ON()    (GPIOB->BSRR = 1 << 1 + 16)    //!< Включить светодиод (Low)
#define LED_OFF()    (GPIOB->BSRR = 1 << 1)        //!< Выключить светодиод (High)

 

Особенно если надо код с HAL ужать или надо быстро - через BRR/BSRR самое то.

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


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

Определяю ножки и порты дефайнами:

#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])
               {
                ...
               }

 

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


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

Подскажите, как вы решаете такие проблемы?

У меня два подхода

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 использую более сложные макросы, определяющие назначение портов, их направление и т.д.

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

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


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

Вся плата описана в pinout.h и например, светодиод:

 

#define PIN_LED_GREEN GPIOA, GPIO_Pin_8

 

Есть макрос gpioSet(GPIO_TypeDef* GPIOx, PIN_TYPE pin, uint8_t state);

 

Вызываю соотв. gpioSet(PIN_LED_GREEN, true) или gpioSet(PIN_LED_GREEN, false).

 

В итоге манипулирую только объектами платы (PIN_LED_GREEN), м не портами и пинами (GPIOA, GPIO_Pin_8).

 

Также при новой версии железа достаточно поправить только pinout.h

 

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


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

Даже если дефайном присвоить имя какому то выводу, непонятно на каком он порте - надо смотреть плату.

 

Коллега оборачивает такие вещи в функции

Но это тоже не дело. Подскажите, как вы решаете такие проблемы?

Два экрана.

На одном всегда открыта плата.

Схема платы специально сделана так чтобы понятен был и порт, и функция, и аттрибуты порта.

 

На именах сигналов не зацикливаюсь, переназываю их в течении проекта много раз.

Могу в течении дня им несколько раз названия менять.

Вся программа пишется так чтобы выдерживать постоянный непрерывный рефакторинг.

 

Не память должна подстраиваться под программу, а программа под память.

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


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

На схеме использую названия вида SIGNAL_PIN - например BUTTON_LEFT_PA1

В программе

#define BUTTON_LEFT PA1

или

#define BUTTON_LEFT_PA1 PA1

(как обычно PA0 = 0, ..., PB0 = 0x10, ..., PC0 = 0x20 и т.д)

если через макрос делается инициализация (а таких 99.9%)

то простейшие макросы переделывают PA0 в нужные маски и порты

Если runtime - то тоже не проблема переделать в порт/маску или bit-banding.

Хотя это конечно даже обсуждения не стоит.

 

Дергать ногами большого ума не надо. Вот что то красивое изобразить - это да.

Например нормальную (irq/dma) поддержку CAN со всеми mailbox'ами и fifo, или i2c/i2s.

С spi/uart проще конечно.

 

Тут без школы танцев не обойтись.

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


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

На схеме использую названия вида 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);

 

 

 

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


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

https://github.com/antongus/stm32tpl - макросы Аскольда Волкова, которые творчески допилил АНТОХА.

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


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

Вся плата описана в 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) ?

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


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

Не память должна подстраиваться под программу, а программа под память.

Т.е. - если что-то забыли, то в проге этот кусок должен исчезнуть :biggrin:

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


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

Всегда и на всех архитектурах использую решение на основе "макросов Аскольда" - благодаря этому моя наработанная библиотека цепляется к любому проекту и постоянно пополняется.

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


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

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

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

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

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

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

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

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

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

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