【联盛德W806上手笔记】七、I2C
目錄
- WM_SDK_W806_v0.6.0的庫函數
- 函數
- 參數
- 宏
- 應用示例
- 初始化
- 使用
- 測試
- I2C 控制器
- 功能概述
- 主要特性
- 功能描述
- 傳輸速率選擇
- 中斷及啟動停止可控
- 快速輸出及檢測信號
- 寄存器描述
- 寄存器列表
- 時鐘分頻寄存器_1
- 時鐘分頻寄存器_2
- 控制寄存器
- 數據寄存器
- 收發控制寄存器
- TXR 讀出寄存器
- CR 讀出寄存器
- iosetting大佬 維護的wm-sdk-w806
- 函數
- 參數
- 應用示例
- 初始化
- 引腳復用
- 使用
- 測試
Windows 10 20H2
HLK-W806-V1.0-KIT
WM_SDK_W806_v0.6.0
???????摘自《W806 芯片設計指導書 V1.0》、《W806 MCU 芯片規格書 V2.0》、《WM_W800_寄存器手冊 V2.1》
WM_SDK_W806_v0.6.0的庫函數
我們打開wm_i2c.h,有如下的函數聲明:
函數
HAL_StatusTypeDef HAL_I2C_Init(I2C_HandleTypeDef *hi2c); //用于配置所用I2C的引腳HAL_StatusTypeDef HAL_I2C_DeInit(I2C_HandleTypeDef *hi2c); //將初始化之后的I2C引腳恢復成默認的狀態–各個寄存器復位時的值HAL_StatusTypeDef HAL_I2C_Write(I2C_HandleTypeDef *hi2c, uint8_t DevAddress, uint8_t MemAddress, uint8_t *pData, uint16_t Size); //用于向從器件某地址寫入數據HAL_StatusTypeDef HAL_I2C_Read(I2C_HandleTypeDef *hi2c, uint8_t DevAddress, uint8_t MemAddress, uint8_t *pData, uint16_t Size); //用于由從器件某地址讀取數據參數
結構體和枚舉類型
typedef struct {GPIO_TypeDef *SCL_Port;uint32_t SCL_Pin;GPIO_TypeDef *SDA_Port;uint32_t SDA_Pin; } I2C_HandleTypeDef;宏
(看著是不是有點怪
#define I2C_SDA_H(HANDLE) HAL_GPIO_WritePin(HANDLE->SDA_Port, HANDLE->SDA_Pin, GPIO_PIN_SET)#define I2C_SDA_L(HANDLE) HAL_GPIO_WritePin(HANDLE->SDA_Port, HANDLE->SDA_Pin, GPIO_PIN_RESET)#define I2C_SCL_H(HANDLE) HAL_GPIO_WritePin(HANDLE->SCL_Port, HANDLE->SCL_Pin, GPIO_PIN_SET)#define I2C_SCL_L(HANDLE) HAL_GPIO_WritePin(HANDLE->SCL_Port, HANDLE->SCL_Pin, GPIO_PIN_RESET)#define I2C_SDA_OUT(HANDLE) SET_BIT(HANDLE->SDA_Port->DIR, HANDLE->SDA_Pin)#define I2C_SDA_IN(HANDLE) CLEAR_BIT(HANDLE->SDA_Port->DIR, HANDLE->SDA_Pin)#define I2C_SDA_GET(HANDLE) HAL_GPIO_ReadPin(HANDLE->SDA_Port, HANDLE->SDA_Pin)應用示例
初始化
I2C_HandleTypeDef hi2c; //... static void I2C_Init(void); //... static void I2C_Init(void) {hi2c.SCL_Port = GPIOA;hi2c.SCL_Pin = GPIO_PIN_1;hi2c.SDA_Port = GPIOA;hi2c.SDA_Pin = GPIO_PIN_4;HAL_I2C_Init(&hi2c); }使用
I2C_Init();//...HAL_I2C_Write(&hi2c, DEVICE_ADDR, 地址, 數據緩沖區首地址, 數據長度);//...HAL_I2C_Read(&hi2c, DEVICE_ADDR, 地址, 數據緩沖區首地址, 數據長度)測試
這里用的測試程序見【0.96寸 OLED屏實現1500Fps的幀率】STM32 軟件、硬件SPI、I2C驅動總結
我們再打開wm_i2c.c:
可以看到 WM_SDK_W806_v0.6.0 庫函數里i2c的實現竟然是模擬i2c
但在數據手冊中是有硬件i2c相關的描述的:
I2C 控制器
功能概述
???????I2C 總線是一種簡單、雙向二線制同步串行總線。它只需要兩根線即可在連接于總線上的器件之間傳送信息。
???????主器件用于啟動總線傳送數據,并產生時鐘以開放傳送的器件,此時任何被尋址的器件均被認為是從器件.在總線上主和從、發和收的關系不是恒定的,而取決于此時數據傳送方向。如果主機要發送數據給從器件,則主機首先尋址從器件,然后主動發送數據至從器件,最后由主機終止數據傳送;如果主機要接收從器件的數據,首先由主器件尋址從器件.然后主機接收從器件發送的數據,最后由主機終止接收過程。在這種情況下.主機負責產生定時時鐘和終止數據傳送。
主要特性
APB 總線協議標準接口
只可作為主設備控制器使用
I2C 工作速率可配,100KHz~400KHz
多路 GPIO 可復用成 I2C 的通信接口
可快速輸出和檢測時序信號
功能描述
傳輸速率選擇
???????通過設置寄存器 PRERlo 和寄存器 PRERhi 就可以將 I2C 總線上的數據傳輸速率配置在 100KHz 到400KHz 之間的任意總線頻率整數分頻值。
中斷及啟動停止可控
???????通過設置寄存器 CTR 的 Bit6 允許或者禁止 I2C 控制器產生中斷,并且還可以通過設置 Bit7 來隨時啟動或者停止 I2C 控制器的工作。
快速輸出及檢測信號
???????通過設置寄存器 CR_SR 的相應位可以使控制器快速輸出或者檢測總線 START 信號,總線 STOP 信號,總線 ACK 信號,總線 NACK 信號。在主模式下,I2C 接口啟動數據傳輸并生成時鐘信號。 一個串行數據傳輸始終以啟動信號開始,以停止信號結束。一旦在總線上生成啟動信號,就選擇了主設備模式。
寄存器描述
寄存器列表
時鐘分頻寄存器_1
時鐘分頻寄存器_2
控制寄存器
數據寄存器
收發控制寄存器
TXR 讀出寄存器
CR 讀出寄存器
iosetting大佬 維護的wm-sdk-w806
IOsetting的CSDN主頁
git clone https://gitee.com/iosetting/wm-sdk-w806.git可以看到,已有硬件I2C的實現:
打開wm_i2c.h,有如下聲明:
函數
HAL_StatusTypeDef HAL_I2C_Init(I2C_HandleTypeDef *hi2c); //用于配置I2C接口的引腳、速率、優先級等HAL_StatusTypeDef HAL_I2C_DeInit(I2C_HandleTypeDef *hi2c); //將初始化之后的I2C接口恢復成默認的狀態–各個寄存器復位時的值void HAL_I2C_MspInit(I2C_HandleTypeDef *hi2c); //用于啟用I2C時鐘,選擇復用引腳void HAL_I2C_MspDeInit(I2C_HandleTypeDef *hi2c); //用于禁用I2C時鐘,將對應引腳恢復成默認的狀態HAL_StatusTypeDef HAL_I2C_Write(I2C_HandleTypeDef *hi2c, uint8_t DevAddress, uint8_t MemAddress, uint8_t *pData, uint16_t Size); //用于向從器件某地址寫入數據HAL_StatusTypeDef HAL_I2C_Read(I2C_HandleTypeDef *hi2c, uint8_t DevAddress, uint8_t MemAddress, uint8_t *pData, uint16_t Size); //用于由從器件某地址讀取數據參數
結構體和枚舉類型
typedef struct __I2C_HandleTypeDef {I2C_TypeDef *Instance; /*!< I2C registers base address */uint32_t Frequency;HAL_LockTypeDef Lock; /*!< Object lock */__IO uint32_t ErrorCode; /*!< I2C Error code */ } I2C_HandleTypeDef;宏參數
#define I2C ((I2C_TypeDef *)I2C_BASE)應用示例
初始化
I2C_HandleTypeDef hi2c; #define DEVICE_ADDR 0xA0 //八位地址static void I2C_Init(void); static void GPIO_Init(void);//...static void I2C_Init(void) {hi2c.Instance = I2C;hi2c.Frequency = 400000;HAL_I2C_Init(&hi2c); }static void GPIO_Init(void) {GPIO_InitTypeDef GPIO_InitStruct = {0};__HAL_RCC_GPIO_CLK_ENABLE();GPIO_InitStruct.Pin = GPIO_PIN_1;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT;GPIO_InitStruct.Pull = GPIO_PULLUP;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_4;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT;GPIO_InitStruct.Pull = GPIO_PULLUP;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); }引腳復用
void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c) {__HAL_RCC_I2C_CLK_ENABLE();__HAL_AFIO_REMAP_I2C_SCL(GPIOA, GPIO_PIN_1);__HAL_AFIO_REMAP_I2C_SDA(GPIOA, GPIO_PIN_4); }void HAL_I2C_MspDeInit(I2C_HandleTypeDef* hi2c) {__HAL_RCC_I2C_CLK_DISABLE();HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1);HAL_GPIO_DeInit(GPIOA, GPIO_PIN_4); }使用
GPIO_Init();I2C_Init();//...HAL_I2C_Write(&hi2c, DEVICE_ADDR, 地址, 數據緩沖區首地址, 數據長度);//...HAL_I2C_Read(&hi2c, DEVICE_ADDR, 地址, 數據緩沖區首地址, 數據長度)測試
經過一晚上的測試,我發現兩個引腳存在互相干擾的現象,已經嚴重影響正常通訊(原因暫時未知)
即使是使用 iosetting大佬的OLED Demo(見聯盛德 HLK-W806 (六): I2C驅動SSD1306 128x64 OLED液晶屏 —— IOsetting),我也只在通訊速率為1MHz下能跑通:
盡管我已在運行Demo前事先延時5s以跳過電平不穩定階段:
但在其他速率下仍難以通訊
400kHz:
100kHz:此情況下為完全黑屏
總結
以上是生活随笔為你收集整理的【联盛德W806上手笔记】七、I2C的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [原创]FineUI秘密花园(二十七)
- 下一篇: 前端案例:飞机大战( js+dom 操作