1. 前言
本文介紹如何編寫符合AliOS Things標準的GPIO控制器設備驅動程序。
2. 頭文件
在程序中使用本文提及的功能應包含頭文件aos/gpioc_core.h。
3. 數據結構
AliOS Things提供GPIO控制器設備的抽象基礎結構:
typedef struct aos_gpioc aos_gpioc_t;
采用結構體嵌套的方式從基礎結構派生出具體的硬件結構,注意基礎結構之后應緊接aos_gpioc_pin_t
類型數組。派生類型應包含具體硬件操作所需的各種變量。例如:
#define GPIOC_ABC_NUM_PINS 32
typedef struct {
aos_gpioc_t gpioc;
aos_gpioc_pin_t pins[GPIOC_ABC_NUM_PINS];
/* private data */
void *reg_base;
int irq_num;
} gpioc_abc_t;
使用宏aos_container_of
實現從基礎結構指針到派生結構指針的轉換。例如:
aos_gpioc_t *gpioc_dev = foo();
gpioc_abc_t *gpioc_abc = aos_container_of(gpioc_dev, gpioc_abc_t, gpioc);
4. 注冊及注銷
4.1. 注冊
AliOS Things提供如下函數用于注冊GPIO master設備:
aos_status_t aos_gpioc_register(aos_gpioc_t *gpioc);
調用注冊函數之前,BSP開發者應自行分配一個aos_gpioc_t
類型或其派生類型的變量并對包含的如下變量賦值:
dev.id
:uint32_t
類型,表示該設備的ID。不同GPIO控制器設備不能擁有相同的ID。ops
:const aos_gpioc_ops_t *
類型,指向一組面向硬件的回調函數:
typedef struct {
void (*unregister)(aos_gpioc_t *gpioc);
aos_status_t (*set_mode)(aos_gpioc_t *gpioc, uint32_t pin);
void (*enable_irq)(aos_gpioc_t *gpioc, uint32_t pin);
void (*disable_irq)(aos_gpioc_t *gpioc, uint32_t pin);
int (*get_value)(aos_gpioc_t *gpioc, uint32_t pin);
void (*set_value)(aos_gpioc_t *gpioc, uint32_t pin);
} aos_gpioc_ops_t;
num_pins
:uint32_t
類型,表示該設備包含的GPIO pin數目。
調用注冊函數之前,BSP開發者應初始化派生類型中的私有變量,并執行具體硬件相關的初始化工作(例如映射寄存器地址等)。
4.2. 注銷
AliOS Things提供如下函數用于注銷GPIO控制器設備:
aos_status_t aos_gpioc_unregister(uint32_t id);
調用此函數之后,BSP開發者可回收相關聯的aos_gpioc_t
類型或其派生類型的變量。
5. 回調函數
驅動程序應實現aos_gpioc_ops_t
定義的一組面向硬件的回調函數。
5.1. unregister
void (*unregister)(aos_gpioc_t *gpioc);
unregister
回調函數在設備注銷時被調用,可在該函數中執行具體硬件相關的反初始化工作(例如解除寄存器地址映射等)。
5.2. set_mode
aos_status_t (*set_mode)(aos_gpioc_t *gpioc, uint32_t pin);
set_mode
回調函數在修改GPIO控制器設備上某個pin的模式時被調用,驅動程序應在該函數中根據新模式修改硬件狀態。修改成功后返回0;失敗時應返回errno(負值),且驅動程序應將硬件狀態恢復到此函數被調用之前的狀態。
set_mode
回調函數可訪問gpioc->pins[pin].mode
變量獲取被操作的pin的新模式。該變量是uint32_t
類型,可包含如下字段,各字段使用按位或運算連接:
方向,掩碼為
AOS_GPIO_DIR_MASK
,取值必須為以下當中的一個:AOS_GPIO_DIR_NONE
:表示該pin不作為GPIO使用,可能讓出pin mux,具體由驅動程序實現決定。AOS_GPIO_DIR_INPUT
:表示該pin作為輸入。AOS_GPIO_DIR_OUTPUT
:表示該pin作為輸出。輸入配置,只在該pin作為輸入時有意義,掩碼為
AOS_GPIO_INPUT_CFG_MASK
,取值必須為以下當中的一個:AOS_GPIO_INPUT_CFG_DEFAULT
:表示輸入配置為默認模式,具體由驅動程序實現,一般為最常用模式或硬件支持的唯一模式。AOS_GPIO_INPUT_CFG_HI
:表示輸入配置為浮空模式。AOS_GPIO_INPUT_CFG_PU
:表示輸入配置為上拉模式。AOS_GPIO_INPUT_CFG_PD
:表示輸入配置為下拉模式。中斷觸發模式。注意
set_mode
回調函數只能設置硬件中斷模式但不能使能中斷。只在該pin作為輸入時有意義,掩碼為AOS_GPIO_IRQ_TRIG_MASK
,取值必須為以下當中的一個:AOS_GPIO_IRQ_TRIG_NONE
:表示不觸發中斷。AOS_GPIO_IRQ_TRIG_EDGE_RISING
:表示上升沿觸發中斷。AOS_GPIO_IRQ_TRIG_EDGE_FALLING
:表示下降沿觸發中斷。AOS_GPIO_IRQ_TRIG_EDGE_BOTH
:表示上升沿和下降沿都觸發中斷。AOS_GPIO_IRQ_TRIG_LEVEL_LOW
:表示低電平觸發中斷。AOS_GPIO_IRQ_TRIG_LEVEL_HIGH
:表示高電平觸發中斷。輸出配置,只在該pin作為輸出時有意義,掩碼為
AOS_GPIO_OUTPUT_CFG_MASK
,取值必須為以下當中的一個:AOS_GPIO_OUTPUT_CFG_DEFAULT
:表示輸出配置為默認模式,具體由驅動程序實現,一般為最常用模式或硬件支持的唯一模式。AOS_GPIO_OUTPUT_CFG_PP
:表示輸出配置為推挽模式。AOS_GPIO_OUTPUT_CFG_ODNP
:表示輸出配置為開漏無上拉模式。AOS_GPIO_OUTPUT_CFG_ODPU
:表示輸出配置為開漏上拉模式。輸出初始電平,只在該pin作為輸出時有意義,掩碼為
AOS_GPIO_OUTPUT_INIT_MASK
,取值必須為以下當中的一個:AOS_GPIO_OUTPUT_INIT_LOW
:表示輸出低電平。AOS_GPIO_OUTPUT_INIT_HIGH
:表示輸出高電平。
5.3. enable_irq
void (*enable_irq)(aos_gpioc_t *gpioc, uint32_t pin);
enable_irq
回調函數在使能某個pin的中斷時被調用,驅動程序應在該函數中將硬件配置為使能該pin的中斷。這里的使能中斷是指GPIO控制器級別而非中斷控制器級別。
5.4. disable_irq
void (*disable_irq)(aos_gpioc_t *gpioc, uint32_t pin);
disable_irq
回調函數在禁用某個pin的中斷時被調用,驅動程序應在該函數中將硬件配置為禁用該pin的中斷。這里的禁用中斷是指GPIO控制器級別而非中斷控制器級別。
5.5 get_value
int (*get_value)(aos_gpioc_t *gpioc, uint32_t pin);
get_value
回調函數在獲取某個pin的輸入電平時被調用,驅動程序應在該函數中從硬件獲取輸入電平。輸入電平為低電平時返回0,為高電平時返回1。
5.5 set_value
void (*set_value)(aos_gpioc_t *gpioc, uint32_t pin);
set_value
回調函數在設置某個pin的輸出電平時被調用,驅動函數應在該函數中向硬件配置輸出電平。gpioc->pins[pin].value
變量表示被輸出的電平,0表示低電平,1表示高電平。
6. 中斷處理
在GPIO控制器硬件中斷處理程序中調用宏aos_gpioc_hard_irq_handler
來觸發中斷處理流程。
aos_gpioc_hard_irq_handler(gpioc, pin, polarity)
polarity
是獲取雙沿觸發中斷極性的表達式,若本次是上升沿觸發則表達式的值應為true
,否則為false
。polarity
表達式只有在中斷模式為雙沿觸發時才會被求值。