RT-Thread源码详解(一)-----PIN设备

在开篇还是要感谢RT-Thread开发团队,感谢他们开发出这么优秀的物联网操作系统,当听到国产的操作系统,总是有一种自豪感。
在学习潘多拉开发板的第一个关于RT-Thread的例程时候,在程序里遇到**rt_pin_mode(LED_PIN, PIN_MODE_OUTPUT); rt_pin_write(LED_PIN, PIN_LOW);**函数。然后就像刨根问底,经过查阅资料,发现这是RT-Thread操作系统中PIN设备模型的内容。
首先说明一点,PIN设备在RT-Thread操作系统中是隶属于I/O设备模型,从PIN设备控制块的定义就可以看出来:

/* pin device and operations for RT-Thread */
struct rt_device_pin
{
    struct rt_device parent;
    const struct rt_pin_ops *ops;
};

因此,PIN设备也遵循I/O设备模型框架,具体框架如下图所示
RT-Thread源码详解(一)-----PIN设备_第1张图片

一、设备对象继承关系

1、如下图所示,RT-Thread各控制块之间存在继承关系:

RT-Thread源码详解(一)-----PIN设备_第2张图片

2、PIN设备控制块详解

RT-Thread源码详解(一)-----PIN设备_第3张图片

/**
 * 双向链表
 */
struct rt_list_node
{
    struct rt_list_node *next;                          /**< 指向直接前去节点 */
    struct rt_list_node *prev;                          /**< 指向直接后继节点 */
};
typedef struct rt_list_node rt_list_t;                  /**< 双向链表节点指针 */
/**
 * 内核对象控制块
 */
struct rt_object
{
    char       name[RT_NAME_MAX];                       /**< 内核对象名字 */
    rt_uint8_t type;                                    /**< 内核对象类型 */
    rt_uint8_t flag;                                    /**< 内核对象参数 */

#ifdef RT_USING_MODULE
    void      *module_id;                               /**< 应用模块id */
#endif
    rt_list_t  list;                                    /**< 内核对象管理链表 */
};
typedef struct rt_object *rt_object_t;                  /**< Type for kernel objects. */
/**
 *  内核对象类型取值
 */
enum rt_object_class_type
{
    RT_Object_Class_Thread = 0,                         /**< 对象为线程 */
    RT_Object_Class_Semaphore,                          /**< 对象为信号量 */
    RT_Object_Class_Mutex,                              /**< 对象为互斥锁 */
    RT_Object_Class_Event,                              /**< 对象为事件 */
    RT_Object_Class_MailBox,                            /**< 对象为邮箱 */
    RT_Object_Class_MessageQueue,                       /**< 对象为消息队列 */
    RT_Object_Class_MemHeap,                            /**< 对象为内存堆 */
    RT_Object_Class_MemPool,                            /**< 内存池 */
    RT_Object_Class_Device,                             /**< 设备驱动 */
    RT_Object_Class_Timer,                              /**< 时钟 */
    RT_Object_Class_Module,                             /**< 模块 */
    RT_Object_Class_Unknown,                            /**< 位置对象类型 */
    RT_Object_Class_Static = 0x80                       /**< 标识是否为系统的对象 */
};
/**
 * 设备控制块
 */
struct rt_device
{
    struct rt_object          parent;                   /**< 继承 rt_object 结构体 */

    enum rt_device_class_type type;                     /**< 设备类型,USB、CAN等设备,这是一个枚举*/
    rt_uint16_t               flag;                     /**< 参数 */
    rt_uint16_t               open_flag;                /**< 设备开启标志,只读、读写等,具体在头文件rtdef中有定义,下面也有罗列 */

    rt_uint8_t                ref_count;                /**< 设备引用计数 */
    rt_uint8_t                device_id;                /**<设备ID号 0 - 255 */

    /* device call back */
    rt_err_t (*rx_indicate)(rt_device_t dev, rt_size_t size);//设备接收数据时,会调用该成员函数,该成员函数是通过rt_device_set_rx_indicate()函数进行注册。像串口的接收函数,网卡的接收函数等都会注册到该函数成员变量中
    rt_err_t (*tx_complete)(rt_device_t dev, void *buffer);

#ifdef RT_USING_DEVICE_OPS
    const struct rt_device_ops *ops;//设备操作方法,这里是一个包含多个函数指针的结构体,这些函数指针指向具体操作的设备
#else
    /* common device interface */
    rt_err_t  (*init)   (rt_device_t dev);
    rt_err_t  (*open)   (rt_device_t dev, rt_uint16_t oflag);
    rt_err_t  (*close)  (rt_device_t dev);
    rt_size_t (*read)   (rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
    rt_size_t (*write)  (rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
    rt_err_t  (*control)(rt_device_t dev, int cmd, void *args);
#endif

#if defined(RT_USING_POSIX)
    const struct dfs_file_ops *fops;//POSIX文件和目录操作接口
    struct rt_wqueue wait_queue;
#endif

    void                     *user_data;                /**< 设备的私有数据 */
};

/**
 * device flags defitions
 */
#define RT_DEVICE_FLAG_DEACTIVATE       0x000           /**< 未初始化设备 */
//
#define RT_DEVICE_FLAG_RDONLY           0x001           /**< 只读方式 */
#define RT_DEVICE_FLAG_WRONLY           0x002           /**< 只写方式 */
#define RT_DEVICE_FLAG_RDWR             0x003           /**< 读写方式 */

#define RT_DEVICE_FLAG_REMOVABLE        0x004           /**< 可移除设备 */
#define RT_DEVICE_FLAG_STANDALONE       0x008           /**< 独立设备 */
#define RT_DEVICE_FLAG_ACTIVATED        0x010           /**< 已激活设备 */
#define RT_DEVICE_FLAG_SUSPENDED        0x020           /**< 已挂起设备 */
#define RT_DEVICE_FLAG_STREAM           0x040           /**< 设备处于流模式 */

#define RT_DEVICE_FLAG_INT_RX           0x100           /**< 设备处于中断接收模式 */
#define RT_DEVICE_FLAG_DMA_RX           0x200           /**< 设备处于DMA接收模式 */
#define RT_DEVICE_FLAG_INT_TX           0x400           /**< 设备处于中断发送模式 */
#define RT_DEVICE_FLAG_DMA_TX           0x800           /**< 设备处于DMA发送模式 */


#define RT_DEVICE_OFLAG_CLOSE           0x000           /**< 设备关闭 */
#define RT_DEVICE_OFLAG_RDONLY          0x001           /**< 只读方式打开设备 */
#define RT_DEVICE_OFLAG_WRONLY          0x002           /**< 只写方式打开设备 */
#define RT_DEVICE_OFLAG_RDWR            0x003           /**< 读写方式打开设备 */
#define RT_DEVICE_OFLAG_OPEN            0x008           /**< 设备打开 */
#define RT_DEVICE_OFLAG_MASK            0xf0f           /**<  设备打开方式的掩码*/

从上面可以看出,根据RT_DEVICE_OFLAG_MASK设备打开方式掩码,可以判断,设备打开方式可以有以下几种:
RT_DEVICE_FLAG_INT_RX、
RT_DEVICE_FLAG_DMA_RX、
RT_DEVICE_FLAG_INT_TX、
RT_DEVICE_FLAG_DMA_TX、
RT_DEVICE_OFLAG_CLOSE、
RT_DEVICE_OFLAG_RDONLY、
RT_DEVICE_OFLAG_WRONLY、
RT_DEVICE_OFLAG_RDWR、
RT_DEVICE_OFLAG_OPEN,
再外加一个RT_DEVICE_FLAG_STREAM(以流模式打开)。

/* pin device and operations for RT-Thread */
struct rt_device_pin
{
    struct rt_device parent;//父类rt_device控制块,即设备基类
    const struct rt_pin_ops *ops;
};
//PIN设备管理接口,
struct rt_pin_ops//PIN设备管理接口
{
    void (*pin_mode)(struct rt_device *device, rt_base_t pin, rt_base_t mode);//PIN设备的工作模式
    void (*pin_write)(struct rt_device *device, rt_base_t pin, rt_base_t value);//设置PIN设备的输出电平
    int (*pin_read)(struct rt_device *device, rt_base_t pin);//读取PIN设备

    /* TODO: add GPIO interrupt */
    rt_err_t (*pin_attach_irq)(struct rt_device *device, rt_int32_t pin,
                      rt_uint32_t mode, void (*hdr)(void *args), void *args);//绑定PIN设备中断回调函数
    rt_err_t (*pin_detach_irq)(struct rt_device *device, rt_int32_t pin);//脱离PIN设备中断
    rt_err_t (*pin_irq_enable)(struct rt_device *device, rt_base_t pin, rt_uint32_t enabled);//使能PIN设备中断
};

二、函数解析

RT-Thread操作系统是怎样实现应用层程序只要通过统一的函数rt_pin_mode(LED_PIN, PIN_MODE_OUTPUT); rt_pin_write(LED_PIN, PIN_LOW); 就能够实现对硬件进行控制。
首先看一下设备启动时的函数调用(注意我这里使用的时MDK开发环境):
int S u b Sub Sub$main(void)---->rtthread_startup();---->rt_hw_board_init();---->rt_hw_pin_init();----->rt_device_pin_register(“pin”, &_stm32_pin_ops, RT_NULL);---->rt_device_register(&_hw_pin.parent, name, RT_DEVICE_FLAG_RDWR);
上面表示,操作系统在启动时,对PIN设备注册到系统内的函数调用关系。下图展示了,应用层调用统一的函数API接口之后,底层是怎么实现对硬件控制的。首先看一下下面的PIN设备调用关系图:

RT-Thread源码详解(一)-----PIN设备_第4张图片
定义全局静态变量_hw_pin:

static struct rt_device_pin _hw_pin;

下面对每个函数进行讲解

1、 rtthread_startup()


int rtthread_startup(void)
{
    rt_hw_interrupt_disable();

    /* 板级初始化,对应不同芯片的开发板
     */
    rt_hw_board_init();

    /* show RT-Thread version */
    rt_show_version();

    /* timer system initialization */
    rt_system_timer_init();

    /* scheduler system initialization */
    rt_system_scheduler_init();

#ifdef RT_USING_SIGNALS
    /* signal system initialization */
    rt_system_signal_init();
#endif

    /* create init_thread */
    rt_application_init();

    /* timer thread initialization */
    rt_system_timer_thread_init();

    /* idle thread initialization */
    rt_thread_idle_init();

#ifdef RT_USING_SMP
    rt_hw_spin_lock(&_cpus_lock);
#endif /*RT_USING_SMP*/

    /* start scheduler */
    rt_system_scheduler_start();

    /* never reach here */
    return 0;
}

2、 rt_hw_board_init();

/**
 * This function will initial STM32 board.
 */
void rt_hw_board_init()
{
    /* NVIC 配置 */
#define NVIC_VTOR_MASK              0x3FFFFF80
#ifdef  VECT_TAB_RAM
    /* Set the Vector Table base location at 0x10000000 */
    SCB->VTOR  = (0x10000000 & NVIC_VTOR_MASK);
#else  /* VECT_TAB_FLASH  */
    /* Set the Vector Table base location at 0x08000000 */
    SCB->VTOR  = (0x08000000 & NVIC_VTOR_MASK);
#endif

    /* HAL库初始化和系统时钟初始化
     */
    HAL_Init();

    SystemClock_Config();
		
    /* 硬件管脚初始化 */
#ifdef BSP_USING_GPIO
    rt_hw_pin_init();
#endif

    /* 串口初始化 */
#ifdef RT_USING_SERIAL
    stm32_hw_usart_init();
#endif

#ifdef RT_USING_CONSOLE
    rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
#endif

#if defined(RT_USING_MEMHEAP) && defined(RT_USING_MEMHEAP_AS_HEAP)
    rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);
    rt_memheap_init(&system_heap, "sram2", (void *)STM32_SRAM2_BEGIN, STM32_SRAM2_HEAP_SIZE);
#else
    rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);
#endif

#ifdef RT_USING_COMPONENTS_INIT
    rt_components_board_init();
#endif
}

3、 rt_hw_pin_init();

程序中定义了一个全局rt_pin_ops类型的变量_stm32_pin_ops,主要是面向PIN设备的管理接口,是面向底层硬件接口。该变量的成员函数是当应用程调用相应的读写等接口函数时,最终RT-Thread会调用下面的操作函数。

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,
};

4、int rt_hw_pin_init(void)

int rt_hw_pin_init(void)
{
    return rt_device_pin_register("pin", &_stm32_pin_ops, RT_NULL);
}

**int rt_device_pin_register(const char *name, const struct rt_pin_ops ops, void user_data)
该函数主要是初始化结构体rt_device_pin类型变量_hw_pin的各成员,将应用层的PIN设备的操作接口与真正对应的底层驱动函数相对应。

//在这里提醒一下,大家看着段代码的时候,要回去看一下上面介绍的个控制块包含关系
int rt_device_pin_register(const char *name, const struct rt_pin_ops *ops, void *user_data)
{
    _hw_pin.parent.type         = RT_Device_Class_Miscellaneous;//设置设备类型,PIN设备在RT-Thread认为是杂项设备
    _hw_pin.parent.rx_indicate  = RT_NULL;//没有设置接收函数
    _hw_pin.parent.tx_complete  = RT_NULL;//没有设置发送函数,注意对于上面两个一般会在串口设备、网卡设备中用到

#ifdef RT_USING_DEVICE_OPS
    _hw_pin.parent.ops          = &pin_ops;
#else
    _hw_pin.parent.init         = RT_NULL;
    _hw_pin.parent.open         = RT_NULL;
    _hw_pin.parent.close        = RT_NULL;
    _hw_pin.parent.read         = _pin_read;
    _hw_pin.parent.write        = _pin_write;
    _hw_pin.parent.control      = _pin_control;
#endif

    _hw_pin.ops                 = ops;//将rt_pin_ops赋值给成员变量ops
    _hw_pin.parent.user_data    = user_data;//存放用户数据的地址,PIN设备没有

    /* register a character device */
    rt_device_register(&_hw_pin.parent, name, RT_DEVICE_FLAG_RDWR);

    return 0;
}

从上面代码中会产生疑问。在代码中** _hw_pin.parent.read = _pin_read; ** 并且在下面代码**_hw_pin.ops = ops; 在这里面是将函数stm32_pin_read赋给成员** 发现两个函数感觉是有点多余,因此,追代码查看一下两者分别底层调用关系。
这里看一下_pin_read函数执行内容:
_pin_read函数

static rt_size_t _pin_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
    struct rt_device_pin_status *status;
    struct rt_device_pin *pin = (struct rt_device_pin *)dev;//将rt_device控制块转换成rt_device_pin控制块

    /* check parameters */
    RT_ASSERT(pin != RT_NULL);

    status = (struct rt_device_pin_status *) buffer;//将buffer转换成rt_device_pin_status
    if (status == RT_NULL || size != sizeof(*status)) return 0;

    status->status = pin->ops->pin_read(dev, status->pin);//调用ops中的成员函数,其实就是调用stm32_pin_read
    return size;//这里要强调的是读取的PIN设备的值是放在status,不能放在返回值中
}

5、函数*rt_err_t rt_device_register(rt_device_t dev, const char name, rt_uint16_t flags)

/**
 * This function registers a device driver with specified name.
 *
 * @param dev the pointer of device driver structure
 * @param name the device driver's name
 * @param flags the capabilities flag of device
 *
 * @return the error code, RT_EOK on initialization successfully.
 */
rt_err_t rt_device_register(rt_device_t dev,
                            const char *name,
                            rt_uint16_t flags)
{
    if (dev == RT_NULL)
        return -RT_ERROR;

    if (rt_device_find(name) != RT_NULL)//保证注册的设备中设备名不能够重复
        return -RT_ERROR;

    rt_object_init(&(dev->parent), RT_Object_Class_Device, name);//初始化内核对象
    dev->flag = flags;//设置设备类型 RT_DEVICE_FLAG_RDWR
    dev->ref_count = 0;
    dev->open_flag = 0;

#if defined(RT_USING_POSIX)
    dev->fops = RT_NULL;
    rt_wqueue_init(&(dev->wait_queue));
#endif

    return RT_EOK;
}
RTM_EXPORT(rt_device_register);

三、解答疑问

贴上主函数代码:

/* using RED LED in RGB */
#define LED_PIN              PIN_LED_R

int main(void)
{
    unsigned int count = 1;
    /* set LED pin mode to output */
    rt_pin_mode(LED_PIN, PIN_MODE_OUTPUT);

    while (count > 0)
    {
        /* led on */
        rt_pin_write(LED_PIN, PIN_LOW);
        rt_kprintf("led on, count: %d\n", count);
        rt_thread_mdelay(500);

        /* led off */
        rt_pin_write(LED_PIN, PIN_HIGH);
        rt_kprintf("led off\n");
        rt_thread_mdelay(500);

        count++;
    }

    return 0;
}

1、为什么程序中采用LED_PIN就可以控制板子的LED等,

追代码看一下:

/* using RED LED in RGB */
#define LED_PIN              PIN_LED_R
#define PIN_LED_R     38        // PE7 :  LED_R        --> LED

问题来了,为什么设置LED_PIN就能够改变硬件板子上面的LED等。换句话说,为什么能够识别数字38就是对应板子PE7引脚。这里以rt_pin_mode为例进行代码说明。前面说过rt_pin_mode底层代用的是stm32_pin_mode函数。数字38实际传给形参pin。

static void stm32_pin_mode(rt_device_t dev, rt_base_t pin, rt_base_t mode)
{
    const struct pin_index *index;
    GPIO_InitTypeDef GPIO_InitStruct;

    index = get_pin(pin);
    if (index == RT_NULL)
    {
        return;
    }

    /* GPIO Periph clock enable */
    index->rcc();//调用GPIOE_CLK_ENABLE,开启GPIOE的时钟

    /* Configure GPIO_InitStructure */
    GPIO_InitStruct.Pin = index->pin;//
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    //设置引脚的具体工作模式
    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;
    }
	//调用HAL库函数,进行硬件配置操作
    HAL_GPIO_Init(index->gpio, &GPIO_InitStruct);
}

接着继续追代码,进入函数get_pin:

#define ITEM_NUM(items) sizeof(items) / sizeof(items[0])
static const struct pin_index *get_pin(uint8_t pin)
{
    const struct pin_index *index;

    if (pin < ITEM_NUM(pins))//判断应用层传进来的PIN设备号是否超出,这里pins是pin_index类型的数组,具体代码下面已经贴出
    {
        index = &pins[pin];//
        if (index->index == -1)
            index = RT_NULL;
    }
    else
    {
        index = RT_NULL;
    }

    return index;
};

/* STM32 GPIO driver */
struct pin_index
{
    int index;
    void (*rcc)(void);
    GPIO_TypeDef *gpio;
    uint32_t pin;
};
//该数组就是把STM32的各引脚序号与相应的引脚名称进行了映射,因此,对于不同的硬件平台,映射是不一样的
static const struct pin_index pins[] =
{
    __STM32_PIN_DEFAULT,
    __STM32_PIN(1, E, 2),       // PE2 :  SAI1_MCLK_A  --> ES8388
    __STM32_PIN(2, E, 3),       // PE3 :  SAI1_SD_B    --> ES8388
    __STM32_PIN(3, E, 4),       // PE4 :  SAI1_FS_A    --> ES8388
    __STM32_PIN(4, E, 5),       // PE5 :  SAI1_SCK_A   --> ES8388
    __STM32_PIN(5, E, 6),       // PE6 :  SAI1_SD_A    --> ES8388
    __STM32_PIN_DEFAULT,        //     :  VBAT
    __STM32_PIN(7, C, 13),      // PC13:  SD_CS        --> SD_CARD
    __STM32_PIN(8, C, 14),      // PC14:  OSC32_IN
    __STM32_PIN(9, C, 15),      // PC15:  OSC32_OUT
    __STM32_PIN_DEFAULT,        //     :  VSS
    __STM32_PIN_DEFAULT,        //     :  VDD
    __STM32_PIN_DEFAULT,        // PH0 :  OSC_IN
    __STM32_PIN_DEFAULT,        // PH1 :  OSC_OUT
    __STM32_PIN_DEFAULT,        //     :  RESET
    __STM32_PIN(15, C, 0),      // PC0 :  I2C_SCL      --> ES8388
    __STM32_PIN(16, C, 1),      // PC1 :  I2C_SDA      --> ES8388
    __STM32_PIN(17, C, 2),      // PC2 :  GBC_LED      --> ATK MODULE
    __STM32_PIN(18, C, 3),      // PC3 :  GBC_KEY      --> ATK MODULE
    __STM32_PIN_DEFAULT,        //     :  VSSA
    __STM32_PIN_DEFAULT,        //     :  VREF-
    __STM32_PIN_DEFAULT,        //     :  VREF+
    __STM32_PIN_DEFAULT,        //     :  VDDA
    __STM32_PIN(23, A, 0),      // PA0 :  MOTOR_A      --> MOTOR
    __STM32_PIN(24, A, 1),      // PA1 :  MOTOR_B      --> MOTOR
    __STM32_PIN(25, A, 2),      // PA2 :  UART2_TX     --> EXTERNAL MODULE
    __STM32_PIN(26, A, 3),      // PA3 :  UART2_RX     --> EXTERNAL MODULE
    __STM32_PIN_DEFAULT,        //     :  VSS
    __STM32_PIN_DEFAULT,        //     :  VDD
    __STM32_PIN(29, A, 4),      // PA4 :  ADC12_IN9    --> EXTERNAL MODULE
    __STM32_PIN(30, A, 5),      // PA5 :  SPI1_SCK     --> SD_CARD
    __STM32_PIN(31, A, 6),      // PA6 :  SPI1_MISO    --> SD_CARD
    __STM32_PIN(32, A, 7),      // PA7 :  SPI1_MOSI    --> SD_CARD
    __STM32_PIN(33, C, 4),      // PC4 :  GBC_RX       --> ATK MODULE
    __STM32_PIN(34, C, 5),      // PC5 :  WIFI_INT     --> WIFI
    __STM32_PIN(35, B, 0),      // PB0 :  EMISSION     --> INFRARED EMISSION
    __STM32_PIN(36, B, 1),      // PB1 :  RECEPTION    --> INFRARED EMISSION
    __STM32_PIN(37, B, 2),      // PB2 :  BEEP         --> BEEP
    __STM32_PIN(38, E, 7),      // PE7 :  LED_R        --> LED
    __STM32_PIN(39, E, 8),      // PE8 :  LED_G        --> LED
    __STM32_PIN(40, E, 9),      // PE9 :  LED_B        --> LED
    __STM32_PIN(41, E, 10),     // PE10:  QSPI_BK1_CLK --> SPI_FLASH
    __STM32_PIN(42, E, 11),     // PE11:  QSPI_BK1_NCS --> SPI_FLASH
    __STM32_PIN(43, E, 12),     // PE12:  QSPI_BK1_IO0 --> SPI_FLASH
    __STM32_PIN(44, E, 13),     // PE13:  QSPI_BK1_IO1 --> SPI_FLASH
    __STM32_PIN(45, E, 14),     // PE14:  QSPI_BK1_IO2 --> SPI_FLASH
    __STM32_PIN(46, E, 15),     // PE15:  QSPI_BK1_IO3 --> SPI_FLASH
    __STM32_PIN(47, B, 10),     // PB10:  AP_INT       --> ALS&PS SENSOR
    __STM32_PIN(48, B, 11),     // PB11:  ICM_INT      --> AXIS SENSOR
    __STM32_PIN_DEFAULT,        //     :  VSS
    __STM32_PIN_DEFAULT,        //     :  VDD
    __STM32_PIN(51, B, 12),     // PB12:  SPI2_CS      --> EXTERNAL MODULE
    __STM32_PIN(52, B, 13),     // PB13:  SPI2_SCK     --> EXTERNAL MODULE
    __STM32_PIN(53, B, 14),     // PB14:  SPI2_MISO    --> EXTERNAL MODULE
    __STM32_PIN(54, B, 15),     // PB15:  SPI2_MOSI    --> EXTERNAL MODULE
    __STM32_PIN(55, D, 8),      // PD8 :  KEY0         --> KEY
    __STM32_PIN(56, D, 9),      // PD9 :  KEY1         --> KEY
    __STM32_PIN(57, D, 10),     // PD10:  KEY2         --> KEY
    __STM32_PIN(58, D, 11),     // PD11:  WK_UP        --> KEY
    __STM32_PIN(59, D, 12),     // PD12:  IO_PD12      --> EXTERNAL MODULEL
    __STM32_PIN(60, D, 13),     // PD13:  IO_PD13      --> EXTERNAL MODULE
    __STM32_PIN(61, D, 14),     // PD14:  IO_PD14      --> EXTERNAL MODULE
    __STM32_PIN(62, D, 15),     // PD15:  IO_PD15      --> EXTERNAL MODULE
    __STM32_PIN(63, C, 6),      // PC6 :  TIM3_CH1     --> EXTERNAL MODULE
    __STM32_PIN(64, C, 7),      // PC7 :  TIM3_CH2     --> EXTERNAL MODULE
    __STM32_PIN(65, C, 8),      // PC8 :  SDIO_D0      --> WIFI
    __STM32_PIN(66, C, 9),      // PC9 :  SDIO_D1      --> WIFI
    __STM32_PIN(67, A, 8),      // PA8 :  IO_PA8       --> EXTERNAL MODULE
    __STM32_PIN(68, A, 9),      // PA9 :  UART1_TX     --> STLINK_RX
    __STM32_PIN(69, A, 10),     // PA10:  UART1_RX     --> STLINK_RX
    __STM32_PIN(70, A, 11),     // PA11:  USB_D-       --> USB OTG && EXTERNAL MODULE
    __STM32_PIN(71, A, 12),     // PA12:  USB_D+       --> USB OTG && EXTERNAL MODULE
    __STM32_PIN(72, A, 13),     // PA13:  T_JTMS       --> STLINK
    __STM32_PIN_DEFAULT,        //     :  VDDUSB
    __STM32_PIN_DEFAULT,        //     :  VSS
    __STM32_PIN_DEFAULT,        //     :  VDD
    __STM32_PIN(76, A, 14),     // PA14:  T_JTCK       --> STLINK
    __STM32_PIN(77, A, 15),     // PA15:  AUDIO_PWR    --> AUDIO && POWER
    __STM32_PIN(78, C, 10),     // PC10:  SDIO_D2      --> WIFI
    __STM32_PIN(79, C, 11),     // PC11:  SDIO_D3      --> WIFI
    __STM32_PIN(80, C, 12),     // PC12:  SDIO_CLK     --> WIFI
    __STM32_PIN(81, D, 0),      //
    __STM32_PIN(82, D, 1),      // PD1 :  WIFI_REG_ON  --> WIFI
    __STM32_PIN(83, D, 2),      // PD2 :  SDIO_CMD     --> WIFI
    __STM32_PIN(84, D, 3),      // PD3 :  IO_PD3       --> EXTERNAL MODULE
    __STM32_PIN(85, D, 4),      // PD4 :  NRF_IRQ      --> WIRELESS
    __STM32_PIN(86, D, 5),      // PD5 :  NRF_CE       --> WIRELESS
    __STM32_PIN(87, D, 6),      // PD6 :  NRF_CS       --> WIRELESS
    __STM32_PIN(88, D, 7),      // PD7 :  LCD_CS       --> LCD
    __STM32_PIN(89, B, 3),      // PB3 :  LCD_SPI_SCK  --> LCD
    __STM32_PIN(90, B, 4),      // PB4 :  LCD_WR       --> LCD
    __STM32_PIN(91, B, 5),      // PB5 :  LCD_SPI_SDA  --> LCD
    __STM32_PIN(92, B, 6),      // PB6 :  LCD_RESET    --> LCD
    __STM32_PIN(93, B, 7),      // PB7 :  LCD_PWR      --> LCD
    __STM32_PIN_DEFAULT,        //     :  BOOT0
    __STM32_PIN(95, B, 8),      // PB8 :  I2C1_SCL     --> EXTERNAL MODULE
    __STM32_PIN(96, B, 9),      // PB9 :  I2C1_SDA     --> EXTERNAL MODULE
    __STM32_PIN(97, E, 0),      // PE0 :  IO_PE0       --> EXTERNAL MODULE
    __STM32_PIN(98, E, 1),      // PE1 :  IO_PE1       --> EXTERNAL MODULE
    __STM32_PIN_DEFAULT,        //     :  VSS
    __STM32_PIN_DEFAULT,        //     :  VDD
};

通过代码可以看出,由于传入的PIN设备号为38,因此函数get_pin返回的是__STM32_PIN(38, E, 7)。由下面代码:

#define __STM32_PIN(index, gpio, gpio_index)                                \
    {                                                                       \
        index, GPIO##gpio##_CLK_ENABLE, GPIO##gpio, GPIO_PIN_##gpio_index   \
    }

最后得出,返回的pin_index类型结构体的index的具体成员变量值如下:

{
	38,
	GPIOE_CLK_ENABLE,
	GPIOE,
	GPIO_PIN_7,
}

2、应用层调用rt_pin_write是怎么控制硬件接口电平变化的

追代码:

rt_pin_write(LED_PIN, PIN_LOW);
//调用如下代码
void rt_pin_write(rt_base_t pin, rt_base_t value)
{
    RT_ASSERT(_hw_pin.ops != RT_NULL);
    _hw_pin.ops->pin_write(&_hw_pin.parent, pin, value);
}
FINSH_FUNCTION_EXPORT_ALIAS(rt_pin_write, pinWrite, write value to hardware pin);

通过代码** _hw_pin.ops->pin_write(&_hw_pin.parent, pin, value); ** ,实际调用_stm32_pin_ops结构体内的stm32_pin_write函数,具体代码如下:

static void stm32_pin_write(rt_device_t dev, rt_base_t pin, rt_base_t value)
{
    const struct pin_index *index;

    index = get_pin(pin);
    if (index == RT_NULL)
    {
        return;
    }

    HAL_GPIO_WritePin(index->gpio, index->pin, (GPIO_PinState)value);//最终调用HAL中的引脚设置函数

以上是对PIN设备代码的分析。

你可能感兴趣的:(RT-Thread)