在开篇还是要感谢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设备模型框架,具体框架如下图所示
/**
* 双向链表
*/
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设备调用关系图:
static struct rt_device_pin _hw_pin;
下面对每个函数进行讲解
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;
}
/**
* 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
}
程序中定义了一个全局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,
};
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,不能放在返回值中
}
/**
* 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;
}
追代码看一下:
/* 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,
}
追代码:
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设备代码的分析。