1. 前言
本文介紹如何編寫符合AliOS Things標準的I2C master設備驅動程序。
2. 頭文件
在程序中使用本文提及的功能應包含頭文件aos/i2c_core.h。
3. 數據結構
AliOS Things提供I2C master設備的抽象基礎結構:
typedef struct aos_i2c aos_i2c_t;
采用結構體嵌套的方式從基礎結構派生出具體的硬件結構。派生類型應包含具體硬件操作所需的各種變量。例如:
typedef struct {
aos_i2c_t i2c;
/* private data */
void *reg_base;
int irq_num;
} i2c_abc_t;
使用宏aos_container_of
實現從基礎結構指針到派生結構指針的轉換。例如:
aos_i2c_t *i2c_dev = foo();
i2c_abc_t *i2c_abc = aos_container_of(i2c_dev, i2c_abc_t, i2c);
4. 注冊及注銷
4.1. 注冊
AliOS Things提供如下函數用于注冊I2C master設備:
aos_status_t aos_i2c_register(aos_i2c_t *i2c);
調用注冊函數之前,BSP開發者應自行分配一個aos_i2c_t
類型或其派生類型的變量并對包含的如下變量賦值:
dev.id
:uint32_t
類型,表示該設備的ID。不同I2C master設備不能擁有相同的ID。ops
:const aos_i2c_ops_t *
類型,指向一組面向硬件的回調函數:
typedef struct {
void (*unregister)(aos_i2c_t *i2c);
aos_status_t (*startup)(aos_i2c_t *i2c);
void (*shutdown)(aos_i2c_t *i2c);
aos_status_t (*start_xfer)(aos_i2c_t *i2c);
void (*finish_xfer)(aos_i2c_t *i2c);
void (*abort_xfer)(aos_i2c_t *i2c);
} aos_i2c_ops_t;
flags
:uint32_t
類型,可包含如下字段,各字段使用按位或運算連接:AOS_I2C_F_ADDR_10
:表示支持10位地址模式。hz
:uint32_t
類型,表示該設備傳輸數據時的時鐘頻率。
調用注冊函數之前,BSP開發者應初始化派生類型中的私有變量,并執行具體硬件相關的注冊時初始化工作(例如映射寄存器地址等)。
4.2. 注銷
AliOS Things提供如下函數用于注銷I2C master設備:
aos_status_t aos_i2c_unregister(uint32_t id);
調用此函數之后,BSP開發者可回收相關聯的aos_i2c_t
類型或其派生類型的變量。
5. 工作模式
一次完整的I2C數據傳輸(以START(或repeated START)信號開始,隨后是slave地址和讀寫標志,隨后是一定長度的數據,以STOP(或repeated)信號結束)在AliOS Things中稱為一個message。
相鄰的同slave地址的一個或多個message在AliOS Things中稱為一個sequence。同一個sequence中的第一個message以START信號開始,最后一個message以STOP信號結束,中間各message用repeated START信號連接。
每個message根據AliOS Things I2C設備驅動數據緩沖區的尺寸拆分為transfer。每個transfer的最大數據長度為AOS_I2C_BUF_SIZE
。AliOS Things I2C設備驅動以transfer為單位傳輸數據。
6. 回調函數
驅動程序應實現aos_i2c_ops_t
定義的一組面向硬件的回調函數。
6.1. unregister
void (*unregister)(aos_i2c_t *i2c);
unregister
回調函數在設備注銷時被調用,可在該函數中執行具體硬件相關的注銷時反初始化工作(例如解除寄存器地址映射等)。
6.2. startup
aos_status_t (*startup)(aos_i2c_t *i2c);
startup
回調函數在設備引用計數從0增加到1時被調用,可在該函數中執行具體硬件相關的運行時初始化工作。初始化成功時應返回0;失敗時應返回errno(負值)。
6.3. shutdown
void (*shutdown)(aos_i2c_t *i2c);
shutdown
回調函數在設備引用計數從1減小到0時被調用,可在該函數中執行具體硬件相關的運行時反初始化工作。
6.4. start_xfer
aos_status_t (*start_xfer)(aos_i2c_t *i2c);
start_xfer
回調函數在設備開始發起一次transfer傳輸時被調用,可在該函數中控制硬件發起傳輸(例如操作FIFO或DMA)。發起成功后返回0;失敗時應返回errno(負值)。該函數不需等待數據全部傳輸完成后再返回,可在硬件中斷處理程序中處理后續工作。
start_xfer
回調函數或中斷處理程序可訪問i2c
指向的如下成員變量獲取或修改傳輸信息:
x.flags
:uint32_t
類型,可包含如下字段,各字段使用按位或運算連接:AOS_I2C_XF_MSG_HEAD
:表示當前transfer是message中的第一個transfer。硬件在傳輸數據之前應依次發出START信號(如果當前也是sequence中的第一個transfer)或repeated START信號(如果當前不是sequence中的第一個transfer)、slave地址、傳輸方向標志。AOS_I2C_XF_MSG_TAIL
:表示當前transfer是message中的最后一個transfer。此標志有效且當前傳輸方向為接收時,最后一個字節接受后應發出NACK信號。AOS_I2C_XF_SEQ_HEAD
:表示當前transfer是sequence中的第一個transfer。AOS_I2C_XF_SEQ_TAIL
:表示當前transfer是sequence中的最后一個transfer。如果此硬件可指定傳輸結束后自動發出STOP信號,應在此標志有效時指定發出STOP信號。x.cfg
:uint32_t
類型,可包含如下字段,各字段使用按位或運算連接:AOS_I2C_MCFG_RX
:該標志有效時表示傳輸方向為接收,否則為發送。AOS_I2C_MCFG_ADDR_10
:該標志有效時表示10位地址模式,否則為7位地址模式。x.addr
:uint16_t
類型,表示slave地址。x.timeout
:uint32_t
類型,表示此次傳輸的超時時間,單位為毫秒。start_xfer
回調函數可修改該變量來指定超時時間,默認值為1000。中斷處理程序不應修改該變量。
硬件基于FIFO或DMA的一次傳輸稱為硬件傳輸。一次硬件傳輸的最大長度等于FIFO深度或DMA數據最大長度,考慮到硬件傳輸最大長度有限,一個transfer可能包含一次或多次硬件傳輸。
AliOS Things提供如下函數操作硬件傳輸。這些函數可以在start_xfer
回調函數或中斷處理程序中調用,支持在關中斷或者自旋鎖加鎖環境下調用。
size_t aos_i2c_hard_push(aos_i2c_t *i2c, void *tx_buf, size_t count);
使用aos_i2c_hard_push
獲取下一次硬件傳輸的實際長度。參數count
為硬件傳輸最大長度;返回值為下一次硬件傳輸的實際長度。如果當前傳輸方向為發送,下一次硬件傳輸的數據將被復制到tx_buf
指向的空間,驅動程序可將這些數據送給FIFO或DMA并發起下一次硬件傳輸。
bool aos_i2c_hard_pull(aos_i2c_t *i2c, const void *rx_buf, size_t count);
一次硬件傳輸成功后(例如FIFO或DMA操作完成并產生中斷),使用aos_i2c_hard_pull
通知設備已完成本次硬件傳輸。參數count
為本次硬件傳輸的實際長度。如果當前傳輸方向為接收,驅動程序應在調用該函數之前從FIFO或DMA獲取數據并存放到rx_buf
指向的空間。如果當前transfer已全部完成,該函數返回true
;否則返回false
,驅動程序應再次調用aos_i2c_hard_push
并發起下一次硬件傳輸。
void aos_i2c_hard_fail(aos_i2c_t *i2c);
如果硬件傳輸過程中出現異常,使用aos_i2c_hard_fail
通知設備傳輸失敗。
6.5. finish_xfer
void (*finish_xfer)(aos_i2c_t *i2c);
finish_xfer
回調函數在設備完成一次transfer傳輸時被調用。如果AOS_I2C_XF_SEQ_TAIL
標志有效且此硬件需手動發出STOP信號,應在此時發出STOP信號。
6.6. abort_xfer
void (*abort_xfer)(aos_i2c_t *i2c);
abort_xfer
回調函數在設備傳輸超時或失敗時被調用,應在該函數中取消FIFO或DMA操作,禁用相關中斷,恢復總線空閑狀態。