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 500msrt_pin_write(LED1_PIN, PIN_HIGH);rt_thread_delay(50); //delay 500msrt_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;
#endifvoid *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_MODULEvoid *module_id; /**< id of application module */
#endifrt_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时钟
中断使能和关闭
内部实质就是设置中断分组和中断的触发模式中断优先级