当前位置:网站首页>2. GPIO related operations

2. GPIO related operations

2022-07-06 03:25:00 rou252051452

1、 summary

        STM32 Of GPIO Operations are classified into RTT Of pin In the device , In this paper, the reference RTT About PIN Relevant instructions of the equipment (RT-Thread Document center ) Write and test . It involves the following aspects

  •         GPIO Pin acquisition
  •         GPIO Output control
  •         GPIO Input to get
  •         GPIO External interrupt implementation of

2、 Acquisition of pin number

       RT-Thread The pin number provided should be distinguished from the pin number of the chip , They are not the same concept , The pin number is determined by PIN Device driver definition , Related to specific chips . The official provided 3 There are three ways to get the pin number : 

  • Use API
  • Use a macro to define
  • View driver file

2.1 Drive file update

        API Get the method through the function rt_pin_get Realization , The procedure is as follows

rt_base_t rt_pin_get(const char *name)
{
    RT_ASSERT(_hw_pin.ops != RT_NULL);
    RT_ASSERT(name[0] == 'P');

    if(_hw_pin.ops->pin_get == RT_NULL)
    {
        return -RT_ENOSYS;
    }

    return _hw_pin.ops->pin_get(name);
}

          Check the initialization phase pair _hw_pin->ops The settings of are as follows

const static struct rt_pin_ops _stm32_pin_ops =
{
    stm32_pin_mode,
    stm32_pin_write,
    stm32_pin_read,
    stm32_pin_attach_irq,
    stm32_pin_dettach_irq,
    stm32_pin_irq_enable,
};
struct rt_pin_ops
{
    void (*pin_mode)(struct rt_device *device, rt_base_t pin, rt_base_t mode);
    void (*pin_write)(struct rt_device *device, rt_base_t pin, rt_base_t value);
    int (*pin_read)(struct rt_device *device, rt_base_t pin);
    rt_err_t (*pin_attach_irq)(struct rt_device *device, rt_int32_t pin,
                      rt_uint32_t mode, void (*hdr)(void *args), void *args);
    rt_err_t (*pin_detach_irq)(struct rt_device *device, rt_int32_t pin);
    rt_err_t (*pin_irq_enable)(struct rt_device *device, rt_base_t pin, rt_uint32_t enabled);
    rt_base_t (*pin_get)(const char *name);
};

           Above ops Not in China pin_get How to implement the function , So we need to update drv_gpio Driver file . Use C:\RT-ThreadStudio\repo\Extract\Board_Support_Packages\RealThread\STM32H750-RT-ART-Pi\1.2.1\libraries\drivers Of drv_gpio.c Replace the driver file in the directory , Synchronize updates .h file . Check the updated content as follows

const static struct rt_pin_ops _stm32_pin_ops =
{
    stm32_pin_mode,
    stm32_pin_write,
    stm32_pin_read,
    stm32_pin_attach_irq,
    stm32_pin_dettach_irq,
    stm32_pin_irq_enable,
    stm32_pin_get,
};

2.2 Realization way

2.2.1 Use API


static rt_uint32_t reset_pin = 0;
reset_pin = rt_pin_get("PF.9");
rt_base_t rt_pin_get(const char *name)
{
    RT_ASSERT(_hw_pin.ops != RT_NULL);
    RT_ASSERT(name[0] == 'P');

    if(_hw_pin.ops->pin_get == RT_NULL)
    {
        return -RT_ENOSYS;
    }

    return _hw_pin.ops->pin_get(name);
}

As shown above ,rt_pin_get First, check whether the input string is a letter P start , The function finally called is _hw_pin.ops->pin_get(name); The contents are as follows :

static rt_base_t stm32_pin_get(const char *name)
{
    rt_base_t pin = 0;
    int hw_port_num, hw_pin_num = 0;
    int i, name_len;

    name_len = rt_strlen(name);    

    if ((name_len < 4) || (name_len >= 6))          // Perform string length verification PA.0   PA.15   The shortest 4, The longest 5
    {
        return -RT_EINVAL;
    }
    if ((name[0] != 'P') || (name[2] != '.'))      // The first string must be P    The third must be .
    {
        return -RT_EINVAL;
    }

    if ((name[1] >= 'A') && (name[1] <= 'Z'))      // The port range is A-Z
    {
        hw_port_num = (int)(name[1] - 'A');        // Port number calculation ,A-Z Convert to 0-25
    }
    else
    {
        return -RT_EINVAL;
    }

    for (i = 3; i < name_len; i++)                // According to the... Of the string 4 Number conversion PA.0=0  PA.15 = 15
    {
        hw_pin_num *= 10;
        hw_pin_num += name[i] - '0';
    }

    pin = PIN_NUM(hw_port_num, hw_pin_num);        // Process the last pin number 

    return pin;
}

  Finally, call the macro definition as follows to obtain the pin number

#define PIN_NUM(port, no) (((((port) & 0xFu) << 4) | ((no) & 0xFu)))

  The calculation results are shown in the following table , follow-up IO And so on

nameportnoresultnameportnoresult
PA.0000PC.02032
PA.1011PC.12133
PA.2022PC.22234
PA.3033PC.32335
PA.4044PC.42436
PA.5055PC.52537
PA.6066PC.62638
PA.7077PC.72739
PA.8088PC.82840
PA.9099PC.92941
PA.1001010PC.1021042
PA.1101111PC.1121143
PA.1201212PC.1221244
PA.1301313PC.1321345
PA.1401414PC.1421446
PA.1501515PC.1521547
PB.01016PD.03048
PB.11117PD.13149
PB.21218PD.23250
PB.31319PD.33351
PB.41420PD.43452
PB.51521PD.53553
PB.61622PD.63654
PB.71723PD.73755
PB.81824PD.83856
PB.91925PD.93957
PB.1011026PD.1031058
PB.1111127PD.1131159
PB.1211228PD.1231260
PB.1311329PD.1331361
PB.1411430PD.1431462
PB.1511531PD.1531563

2.2.2 Use a macro to define

#define LED0_PIN        GET_PIN(F,  9)
#define __STM32_PORT(port)  GPIO##port##_BASE

#if defined(SOC_SERIES_STM32MP1)
#define GET_PIN(PORTx,PIN) (GPIO##PORTx == GPIOZ) ? (176 + PIN) : ((rt_base_t)((16 * ( ((rt_base_t)__STM32_PORT(PORTx) - (rt_base_t)GPIOA_BASE)/(0x1000UL) )) + PIN))
#else
#define GET_PIN(PORTx,PIN) (rt_base_t)((16 * ( ((rt_base_t)__STM32_PORT(PORTx) - (rt_base_t)GPIOA_BASE)/(0x0400UL) )) + PIN)
#endif
Macro definition PORTx16 * ( ((rt_base_t)__STM32_PORT(PORTx) - (rt_base_t)GPIOA_BASE)/(0x0400UL) )PINresult
GET_PIN(A, 0)GPIOA_BASED3_AHB1PERIPH_BASE + 0x0000UL000
GET_PIN(A, 1)GPIOA_BASED3_AHB1PERIPH_BASE + 0x0000UL000
GET_PIN(A, 2)GPIOA_BASED3_AHB1PERIPH_BASE + 0x0000UL000
GET_PIN(A, 3)GPIOA_BASED3_AHB1PERIPH_BASE + 0x0000UL000
GET_PIN(B, 0)GPIOB_BASED3_AHB1PERIPH_BASE + 0x0400UL1016
GET_PIN(B, 1)GPIOB_BASED3_AHB1PERIPH_BASE + 0x0400UL1117
GET_PIN(B, 2)GPIOB_BASED3_AHB1PERIPH_BASE + 0x0400UL1218

        Results and API The implementation results are the same .

2.2.3 View driver file

        This method updates the driver file drv_gpio There is no official document description of the view drive mode , There is no detailed description here .

3、GPIO Output control

        We control the LED Light to verify GPIO The output function of .

#include "rtthread.h"
#include "rtdevice.h"
#include "board.h"

#define LED0    GET_PIN(B, 0)

void example_gpio()
{
    rt_pin_mode(LED0,PIN_MODE_OUTPUT);      // Set the pin to output 
    rt_pin_write(LED0,PIN_LOW);
}

MSH_CMD_EXPORT(example_gpio, example_gpio)

4、GPIO Input control

        Control the core board by on-board buttons LED The light is on and off , Press and the rear light will be on , The light goes out after loosening

#include "rtthread.h"
#include "rtdevice.h"
#include "board.h"

#define LED0    GET_PIN(B, 0)

void example_gpio()
{
    static rt_uint32_t key = 0;

    rt_pin_mode(LED0,PIN_MODE_OUTPUT);          // Set the pin to output 
    rt_pin_write(LED0,PIN_LOW);

    key = rt_pin_get("PA.0");                   // Get pin number 
    rt_pin_mode(key,PIN_MODE_INPUT);            // Set the pin as input 
    while(1)
    {
        if(rt_pin_read(key) == PIN_HIGH)        // Read input status 
        {
            rt_pin_write(LED0,PIN_LOW);
        }
        else
        {
            rt_pin_write(LED0,PIN_HIGH);
        }
        rt_thread_mdelay(1000);
    }
}
MSH_CMD_EXPORT(example_gpio, example_gpio)

 5、GPIO interrupt

         Control the core board by on-board buttons LED The light is on and off , Press to interrupt the rising edge , Light on . The falling edge is interrupted after loosening , The light goes out

6、 Detailed explanation of driving process

6.1 Mode setting

        The function called by mode setting is rt_pin_mode, The function finally called is ops->pin_mode, by drv_gpio.c Medium stm32_pin_mode function , The details are as follows

static void stm32_pin_mode(rt_device_t dev, rt_base_t pin, rt_base_t mode)
{
    GPIO_InitTypeDef GPIO_InitStruct;

    // Identify whether the port number is legal 
    if (PIN_PORT(pin) >= PIN_STPORT_MAX)        
    {
        return;
    }

    /*
         Conduct GPIO Initialize the relevant assignment of the structure 
         The default configuration is push-pull output , High speed , No up and down 
    */
    GPIO_InitStruct.Pin = PIN_STPIN(pin);   
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

    /*
         Modify relevant contents according to the input mode parameters .
    */
    if (mode == PIN_MODE_OUTPUT)
    {
        /* output setting */
        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
    }
    else if (mode == PIN_MODE_INPUT)
    {
        /* input setting: not pull. */
        GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
    }
    else if (mode == PIN_MODE_INPUT_PULLUP)
    {
        /* input setting: pull up. */
        GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
    }
    else if (mode == PIN_MODE_INPUT_PULLDOWN)
    {
        /* input setting: pull down. */
        GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
        GPIO_InitStruct.Pull = GPIO_PULLDOWN;
    }
    else if (mode == PIN_MODE_OUTPUT_OD)
    {
        /* output setting: od. */
        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
    }

    /*
         Conduct GPIO initialization , According to the macro definition PIN_STPORT Identify GPIOx The address of 
    */
    HAL_GPIO_Init(PIN_STPORT(pin), &GPIO_InitStruct);
}

6.2 Output level control

        The function called by the output level is rt_pin_write, The function finally called is ops->pin_write, by drv_gpio.c Medium stm32_pin_write function , The details are as follows

static void stm32_pin_write(rt_device_t dev, rt_base_t pin, rt_base_t value)
{
    GPIO_TypeDef *gpio_port;
    uint16_t gpio_pin;

    // Convert the pin serial number to port and pin Information , call HAL Library function for output 
    if (PIN_PORT(pin) < PIN_STPORT_MAX)
    {
        gpio_port = PIN_STPORT(pin);
        gpio_pin = PIN_STPIN(pin);

        HAL_GPIO_WritePin(gpio_port, gpio_pin, (GPIO_PinState)value);
    }
}

6.3 Input level acquisition

         The function called by the input level acquisition is rt_pin_read, The function finally called is ops->pin_read, by drv_gpio.c Medium stm32_pin_read function , The details are as follows

static int stm32_pin_read(rt_device_t dev, rt_base_t pin)
{
    GPIO_TypeDef *gpio_port;
    uint16_t gpio_pin;
    int value = PIN_LOW;
     // Convert the pin serial number to port and pin Information , call HAL Library function to obtain input information 
    if (PIN_PORT(pin) < PIN_STPORT_MAX)
    {
        gpio_port = PIN_STPORT(pin);
        gpio_pin = PIN_STPIN(pin);
        value = HAL_GPIO_ReadPin(gpio_port, gpio_pin);
    }

    return value;
}

6.4 Binding pin interrupt callback function

        The binding interrupt function calls rt_pin_attach_irq, The function finally called is ops->pin_attach_irq, by drv_gpio.c Medium stm32_pin_attach_irq function , The details are as follows

        It just went on rtt Next pin The interrupt pin mode of the device and the assignment of the interrupt callback function , No substantive STM32 The bottom of the HAL Library Configuration .

static rt_err_t stm32_pin_attach_irq(struct rt_device *device, rt_int32_t pin,
                                     rt_uint32_t mode, void (*hdr)(void *args), void *args)
{
    rt_base_t level;
    rt_int32_t irqindex = -1;

    // Identify whether the port is correct 
    if (PIN_PORT(pin) >= PIN_STPORT_MAX)
    {
        return -RT_ENOSYS;
    }

    // Identify the interrupt source   0-15
    irqindex = bit2bitno(PIN_STPIN(pin));
    if (irqindex < 0 || irqindex >= ITEM_NUM(pin_irq_map))
    {
        return RT_ENOSYS;
    }

    level = rt_hw_interrupt_disable();
    if (pin_irq_hdr_tab[irqindex].pin == pin &&
        pin_irq_hdr_tab[irqindex].hdr == hdr &&
        pin_irq_hdr_tab[irqindex].mode == mode &&
        pin_irq_hdr_tab[irqindex].args == args)
    {
        rt_hw_interrupt_enable(level);
        return RT_EOK;
    }
    if (pin_irq_hdr_tab[irqindex].pin != -1)
    {
        rt_hw_interrupt_enable(level);
        return RT_EBUSY;
    }
    pin_irq_hdr_tab[irqindex].pin = pin;
    pin_irq_hdr_tab[irqindex].hdr = hdr;
    pin_irq_hdr_tab[irqindex].mode = mode;
    pin_irq_hdr_tab[irqindex].args = args;
    rt_hw_interrupt_enable(level);

    return RT_EOK;
}

Concrete HAL The bottom driver of the library is configured in rt_pin_irq_enable Function , The final calling function of this function is stm32_pin_irq_enable The contents are as follows :

static rt_err_t stm32_pin_irq_enable(struct rt_device *device, rt_base_t pin,
                                     rt_uint32_t enabled)
{
    const struct pin_irq_map *irqmap;
    rt_base_t level;
    rt_int32_t irqindex = -1;
    GPIO_InitTypeDef GPIO_InitStruct;

    // distinguish IO Is it legal 
    if (PIN_PORT(pin) >= PIN_STPORT_MAX)
    {
        return -RT_ENOSYS;
    }

    // To interrupt , Carry out the configuration of yes .
    if (enabled == PIN_IRQ_ENABLE)
    {
        // Get pin serial number 
        irqindex = bit2bitno(PIN_STPIN(pin));
        if (irqindex < 0 || irqindex >= ITEM_NUM(pin_irq_map))
        {
            return RT_ENOSYS;
        }

        level = rt_hw_interrupt_disable();
        
        //pin_irq_hdr_tab The content is in stm32_pin_attach_irq Assignment was made .
        if (pin_irq_hdr_tab[irqindex].pin == -1)
        {
            rt_hw_interrupt_enable(level);
            return RT_ENOSYS;
        }

        // Get the interrupt sequence number according to the pin    EXTI0_IRQn-EXTI4_IRQn or EXTI9_5_IRQn
        irqmap = &pin_irq_map[irqindex];

        // To configure GPIO Initialize structure 
        /* Configure GPIO_InitStructure */
        GPIO_InitStruct.Pin = PIN_STPIN(pin);
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
        switch (pin_irq_hdr_tab[irqindex].mode)
        {
        case PIN_IRQ_MODE_RISING:
            GPIO_InitStruct.Pull = GPIO_PULLDOWN;
            GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
            break;
        case PIN_IRQ_MODE_FALLING:
            GPIO_InitStruct.Pull = GPIO_PULLUP;
            GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
            break;
        case PIN_IRQ_MODE_RISING_FALLING:
            GPIO_InitStruct.Pull = GPIO_NOPULL;
            GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;
            break;
        }
        HAL_GPIO_Init(PIN_STPORT(pin), &GPIO_InitStruct);

        // Set interrupt priority , To interrupt 
        HAL_NVIC_SetPriority(irqmap->irqno, 5, 0);
        HAL_NVIC_EnableIRQ(irqmap->irqno);
        pin_irq_enable_mask |= irqmap->pinbit;

        rt_hw_interrupt_enable(level);
    }
    // No interruptions 
    else if (enabled == PIN_IRQ_DISABLE)
    {
        irqmap = get_pin_irq_map(PIN_STPIN(pin));
        if (irqmap == RT_NULL)
        {
            return RT_ENOSYS;
        }

        level = rt_hw_interrupt_disable();
        // Reset GPIO
        HAL_GPIO_DeInit(PIN_STPORT(pin), PIN_STPIN(pin));

        pin_irq_enable_mask &= ~irqmap->pinbit;

        if ((irqmap->pinbit >= GPIO_PIN_5) && (irqmap->pinbit <= GPIO_PIN_9))
        {
            if (!(pin_irq_enable_mask & (GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9)))
            {
                HAL_NVIC_DisableIRQ(irqmap->irqno);
            }
        }
        else if ((irqmap->pinbit >= GPIO_PIN_10) && (irqmap->pinbit <= GPIO_PIN_15))
        {
            if (!(pin_irq_enable_mask & (GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15)))
            {
                HAL_NVIC_DisableIRQ(irqmap->irqno);
            }
        }
        else
        {
            HAL_NVIC_DisableIRQ(irqmap->irqno);
        }

        rt_hw_interrupt_enable(level);
    }
    else
    {
        return -RT_ENOSYS;
    }

    return RT_EOK;
}

原网站

版权声明
本文为[rou252051452]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/187/202207060319452184.html