1. 程式人生 > >Zephyr GPIO驅動及使用方法

Zephyr GPIO驅動及使用方法

1. 說明
參考的單板: stm32f429i_disc1
zephyr版本: zephyr v1.10.0

2. 驅動載入方法 
// 檔案: gpio_stm32.c (drivers\gpio)
static const struct gpio_driver_api gpio_stm32_driver = {
/* 以下為GPIO驅動操作函式,它們會最終呼叫soc_gpio.c(arch\arm\soc\st_stm32\stm32f4)中的GPIO配置底層函式,直接操作暫存器*/
.config = gpio_stm32_config,
.write = gpio_stm32_write,
.read = gpio_stm32_read,
.manage_callback = gpio_stm32_manage_callback,
.enable_callback = gpio_stm32_enable_callback,
.disable_callback = gpio_stm32_disable_callback,
};

#define GPIO_DEVICE_INIT(__name, __suffix, __base_addr, __port, __cenr, __bus) \   // 驅動註冊
static const struct gpio_stm32_config gpio_stm32_cfg_## __suffix = {\
.base = (u32_t *)__base_addr,\
.port = __port,\
.pclken = { .bus = __bus, .enr = __cenr }\
};\
static struct gpio_stm32_data gpio_stm32_data_## __suffix;\
DEVICE_AND_API_INIT(gpio_stm32_## __suffix,\
__name,\
gpio_stm32_init, /* 使能對應的GPIO時鐘*/\
&gpio_stm32_data_## __suffix,\
&gpio_stm32_cfg_## __suffix,\
POST_KERNEL,\
CONFIG_KERNEL_INIT_PRIORITY_DEVICE,\
&gpio_stm32_driver);   /*真正的GPIO操作函式 */

#define GPIO_DEVICE_INIT_STM32(__suffix, __SUFFIX)\
GPIO_DEVICE_INIT("GPIO" #__SUFFIX, __suffix,\
GPIO##__SUFFIX##_BASE, STM32_PORT##__SUFFIX,\
STM32_PERIPH_GPIO##__SUFFIX,\
STM32_CLOCK_BUS_GPIO)
 
#ifdef CONFIG_GPIO_STM32_PORTA    // 如果定義CONFIG_GPIO_STM32_PORTA,則載入GPIOA的驅動
GPIO_DEVICE_INIT_STM32(a, A);
#endif /* CONFIG_GPIO_STM32_PORTA */

2. 使用方法

1) 配置

# stm32f429i_disc1_defconfig (boards\arm\stm32f429i_disc1)

# enable pinmux

CONFIG_PINMUX=y
# enable GPIO ports G
CONFIG_GPIO=y
CONFIG_GPIO_STM32_PORTG=y
2) 使用
#define PORT   "GPIOG"
#define PIN    13
struct device *dev;
dev = device_get_binding(PORT);
/* a. 用作輸出,參考samples/basic/blinky */
gpio_pin_configure(dev, GPIO_PIN, GPIO_DIR_OUT);
gpio_pin_write(dev, GPIO_PIN, 1);
/* b. 用作輸入,參考samples/basic/button */
#define EDGE   (GPIO_INT_EDGE | GPIO_INT_ACTIVE_LOW)
#define PULL_UP 0
void button_pressed(struct device *gpiob, struct gpio_callback *cb, u32_t pins) {
printk("Button pressed at %d\n", k_cycle_get_32());
}
static struct gpio_callback gpio_cb;
struct device *gpiob;
gpiob = device_get_binding(PORT);
gpio_pin_configure(gpiob, PIN, GPIO_DIR_IN | GPIO_INT |  PULL_UP | EDGE);
gpio_init_callback(&gpio_cb, button_pressed, BIT(PIN));
gpio_add_callback(gpiob, &gpio_cb);
gpio_pin_enable_callback(gpiob, PIN);
u32_t val = 0;
gpio_pin_read(gpiob, PIN, &val);

3. API說明
1) 常用API
gpio_pin_configure
gpio_pin_write
gpio_init_callback
gpio_add_callback
gpio_pin_enable_callback
gpio_pin_read
2) 說明
GPIO相關API是面向使用者最上層操作函式,它們均來自gpio.h (include)檔案,函式較為簡單,且都具有相似的格式。
此處以gpio_pin_write為例做簡要說明:
static inline int _impl_gpio_write(struct device *port, int access_op, u32_t pin, u32_t value)
{
// 獲取驅動api,對應gpio_stm32.c (drivers\gpio)中的 static const struct gpio_driver_api gpio_stm32_driver 結構體
const struct gpio_driver_api *api = port->driver_api;
// 若是gpio_pin_read函式,則替換為api->read即可
return api->write(port, access_op, pin, value);

}

4. GPIO按鍵中斷

#define EDGE_LOW    (GPIO_INT_EDGE | GPIO_INT_ACTIVE_LOW)

void button_pressed(struct device *gpiob, struct gpio_callback *cb,  u32_t pins)
{
printk("pin=%d Button pressed at %d\n", find_lsb_set(pins) - 1, k_cycle_get_32());
}
const u32_t button_pins[] = {7, 8}; 
#define BUTTON_TOTAL sizeof(button_pins)

struct gpio_callback button_cb[BUTTON_TOTAL];

void button_init(void)
{
int i;
struct device *gpio;
gpio = device_get_binding("gpio");
if (!gpio) {
printk("error\n");
return;
}
for (i = 0; i < BUTTON_TOTAL; i++) {
gpio_pin_configure(gpio, button_pins[i], GPIO_DIR_IN | GPIO_INT | GPIO_PUD_PULL_UP | EDGE_LOW);
gpio_init_callback(&button_cb[i], button_pressed, BIT(button_pins[i]));
gpio_add_callback(gpio, &button_cb[i]);
gpio_pin_enable_callback(gpio, button_pins[i]);
}
}