0gpio使用测试
LED测试
#define LED1_PIN GET_PIN(C, 1)
void led1_thread_entry(void* parameter)
{
rt_pin_mode(LED1_PIN, PIN_MODE_OUTPUT);
while(1)
{
rt_thread_delay(50); //delay 500ms
rt_pin_write(LED1_PIN, PIN_HIGH);
rt_thread_delay(50); //delay 500ms
rt_pin_write(LED1_PIN, PIN_LOW);
}
}
key轮训测试
#define KEY1_PIN GET_PIN(A, 4)
#define KEY2_PIN GET_PIN(A, 5)
#define KEY3_PIN GET_PIN(A, 6)
#define KEY1 rt_pin_read(KEY1_PIN)
#define KEY2 rt_pin_read(KEY2_PIN)
#define KEY3 rt_pin_read(KEY3_PIN)
#define KEY1_PRES 1
#define KEY2_PRES 2
#define KEY3_PRES 3
uint8_t KEY_Scan(uint8_t mode)
{
static uint8_t key_up=1;
if(mode)
{
key_up = 1;
}
if(key_up && (KEY1 == 0 || KEY2 == 0 || KEY3 == 0))
{
rt_thread_delay(1);
key_up=0;
if(KEY1 == 0)
{
return KEY1_PRES;
}
else if(KEY2 == 0)
{
return KEY2_PRES;
}
else if(KEY3 == 0)
{
return KEY3_PRES;
}
} else if(KEY1 == 1 && KEY2 == 1 && KEY3 == 1)
{
key_up = 1;
}
return 0;
}
void key_test(void)
{
rt_uint8_t key;
rt_pin_mode(KEY1_PIN, PIN_MODE_INPUT_PULLUP);
rt_pin_mode(KEY2_PIN, PIN_MODE_INPUT_PULLUP);
while(1)
{
key = KEY_Scan(0);
switch(key)
{
case KEY1_PRES:
rt_kprintf("key1 pressed.\n");
break;
case KEY2_PRES:
rt_kprintf("key2 pressed.\n");
break;
case KEY3_PRES:
break;
default:
break;
}
rt_thread_delay(5);
}
}
key中断测试
#define KEY3_PIN GET_PIN(A, 6)
void key3_irq(void *args)
{
rt_kprintf("enter key3 interrupt callback.\n");
}
void key_test(void)
{
rt_pin_mode(KEY3_PIN, PIN_MODE_INPUT_PULLUP);
rt_pin_attach_irq(KEY3_PIN, PIN_IRQ_MODE_FALLING, key3_irq, RT_NULL);
rt_pin_irq_enable(KEY3_PIN, ENABLE);
}
1.设备抽象接口rt_device
struct rt_device
{
struct rt_object parent; /**< 继承至内核对象 */
enum rt_device_class_type type; /**< device type 设备类型 can uart 等*/
rt_uint16_t flag; /**< device flag */
rt_uint16_t open_flag; /**< device open flag */
rt_uint8_t ref_count; /**< reference count */
rt_uint8_t device_id; /**< 0 - 255 */
/* device call back 发送和接收的回调函数 */
rt_err_t (*rx_indicate)(rt_device_t dev, rt_size_t size);
rt_err_t (*tx_complete)(rt_device_t dev, void *buffer);
/* 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;
struct rt_wqueue wait_queue;
#endif
void *user_data; /**< device private data */
};
1.1.核对象
struct rt_object
{
char name[RT_NAME_MAX]; /**< name of kernel object */
rt_uint8_t type; /**< type of kernel object */
rt_uint8_t flag; /**< flag of kernel object */
#ifdef RT_USING_MODULE
void *module_id; /**< id of application module */
#endif
rt_list_t list; /**< list node of kernel object */
};
pin设备驱动框架
该框架主要包含内容有:
- 一个继承至设备驱动框架的rt_device 对象
- 一个pin相关的操作函数集
- gpio模式配置
- gpio 读写函数
- 中断绑定解绑函数
- 中断使能函数
- pin设备的注册函数int rt_device_pin_register(const char *name, const struct rt_pin_ops *ops, void *user_data);
//操作函数
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);
/* 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);
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);
};
//pin设备驱动核心结构
struct rt_device_pin
{
struct rt_device parent;
const struct rt_pin_ops *ops;
};
N32L40x 的驱动程序drv_driver.c 分析
1.gpio 到gpio id的映射关系
/*
这个宏 ## 就是连接符号
*/
#define __N32L40X_PORT(port) GPIO##port##_BASE
//gpioid 和 [gpio分组h和pin] 的关系 gpioid = (gpio分组-gpio_base)*16+pin
#define GET_PIN(PORTx,PIN) (rt_base_t)((16 * ( ((rt_base_t)__N32L40X_PORT(PORTx) - (rt_base_t)GPIOA_BASE)/(0x0400UL) )) + PIN)
2.如何实现注册pin设备
- 定义一个rt_pin_ops对象分别实现内部的 模式设置函数,读写函数,中断绑定和解绑函数,中断使能函数
- 注册rt_pin_ops对象到内核
3.外部中断的处理办法
- 外部中断统一调用N32L40X_GPIO_EXTI_IRQHandler处理函数
- 外部中断的回到函数统一放在一个 pin_irq_hdr_tab 数组内部
中断处理
中断绑定
绑定的实质就是给pin_irq_hdr_tab 内部的对象成员赋值操作
外部中断相关的结构
主要是存储用户注册中断处理函数
struct rt_pin_irq_hdr
{
rt_int16_t pin;
rt_uint16_t mode;//上升沿,下降沿等触发方式
void (*hdr)(void *args);//用户绑定的中断处理函数
void *args;//参数
};
gpio时钟分组
在rtconfig.h中可能涉及需要开启gpio时钟
中断使能和关闭
内部实质就是设置中断分组和中断的触发模式中断优先级