硬件I2C-GD32F4系列的實現
===初始化操作===
在初始化函數里執行以下代碼
uint32_t i2cx_scl_port_rcu = RCU_GPIOB;
uint32_t i2cx_scl_port = GPIOB;
uint32_t i2cx_scl_pin = GPIO_PIN_6;
uint32_t i2cx_scl_af = GPIO_AF_4;uint32_t i2cx_sda_port_rcu = RCU_GPIOB;
uint32_t i2cx_sda_port = GPIOB;
uint32_t i2cx_sda_pin = GPIO_PIN_7;
uint32_t i2cx_sda_af = GPIO_AF_4;uint32_t i2cx = I2C0;
uint32_t i2cx_rcu = RCU_I2C0;
uint32_t i2cx_speed = 400000;
/****************** GPIO config **********************/
// 時鐘配置
rcu_periph_clock_enable(i2cx_scl_port_rcu);
// 設置復用功能
gpio_af_set(i2cx_scl_port, i2cx_scl_af, i2cx_scl_pin);
// 設置輸出模式
gpio_mode_set(i2cx_scl_port, GPIO_MODE_AF, GPIO_PUPD_NONE, i2cx_scl_pin);
gpio_output_options_set(i2cx_scl_port, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, i2cx_scl_pin);// 時鐘配置
rcu_periph_clock_enable(i2cx_sda_port_rcu);
// 設置復用功能
gpio_af_set(i2cx_sda_port, i2cx_sda_af, i2cx_sda_pin);
// 設置輸出模式
gpio_mode_set(i2cx_sda_port, GPIO_MODE_AF, GPIO_PUPD_NONE, i2cx_sda_pin);
gpio_output_options_set(i2cx_sda_port, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, i2cx_sda_pin);/****************** I2C config **********************/
i2c_deinit(i2cx);
// 時鐘配置
rcu_periph_clock_enable(i2cx_rcu);
// I2C速率配置
i2c_clock_config(i2cx, i2cx_speed, I2C_DTCY_2);// 使能i2c
//i2c_mode_addr_config(i2cx, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0x00);
i2c_enable(i2cx);// i2c ack enable
i2c_ack_config(i2cx, I2C_ACK_ENABLE);
- 哪個I2C
- SCL是哪個引腳
- SDA是哪個引腳
- 速度是多快
準備兩個wait函數
等待指定外設的flag狀態變化的函數
#define TIMEOUT 50000
static uint8_t I2C_wait(uint32_t flag) {uint16_t cnt = 0;while(!i2c_flag_get(i2cx, flag)) {cnt++;if(cnt > TIMEOUT) return 1;}return 0;
}static uint8_t I2C_waitn(uint32_t flag) {uint16_t cnt = 0;while(i2c_flag_get(i2cx, flag)) {cnt++;if(cnt > TIMEOUT) return 1;}return 0;
}
===寫操作流程===
開始
/************* start ***********************/
// 等待I2C閑置
if(I2C_waitn(I2C_FLAG_I2CBSY)) return 1;
// start
i2c_start_on_bus(i2cx);
// 等待I2C主設備成功發送起始信號
if(I2C_wait(I2C_FLAG_SBSEND)) return 2;
發送設備地址
注意??,這里是設備的寫地址write_addr
/************* device address **************/
// 發送設備地址
i2c_master_addressing(i2cx, write_addr, I2C_TRANSMITTER);
// 等待地址發送完成
if(I2C_wait(I2C_FLAG_ADDSEND)) return 3;
i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);
發送寄存器地址
/************ register address ************/
// 寄存器地址
// 等待發送數據緩沖區為空
if(I2C_wait(I2C_FLAG_TBE)) return 4;// 發送數據
i2c_data_transmit(i2cx, reg);// 等待數據發送完成
if(I2C_wait(I2C_FLAG_BTC)) return 5;
數據發送
/***************** data ******************/
// 發送數據
uint32_t i;
for(i = 0; i < len; i++) {uint32_t d = data[i];// 等待發送數據緩沖區為空if(I2C_wait(I2C_FLAG_TBE)) return 6;// 發送數據i2c_data_transmit(i2cx, d);// 等待數據發送完成if(I2C_wait(I2C_FLAG_BTC)) return 7;
}
停止
/***************** stop ********************/
// stop
i2c_stop_on_bus(i2cx);if(I2C_waitn(I2C_CTL0(i2cx)&I2C_CTL0_STOP)) return 8;
===讀操作流程===
開始
/************* start ***********************/
// 等待I2C空閑
if(I2C_waitn(I2C_FLAG_I2CBSY)) return 1;
// 發送啟動信號
i2c_start_on_bus(i2cx);
// 等待I2C主設備成功發送起始信號
if(I2C_wait(I2C_FLAG_SBSEND)) return 2;
發送設備地址(寫)
/************* device address **************/
// 發送從設備地址
i2c_master_addressing(i2cx, address, I2C_TRANSMITTER);if(I2C_wait(I2C_FLAG_ADDSEND)) return 3;
i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);
發送寄存器地址
/********** register address **************/
// 等待發送緩沖區
if(I2C_wait(I2C_FLAG_TBE)) return 4;// 發送寄存器地址
i2c_data_transmit(i2cx, reg);// 等待發送數據完成
if(I2C_wait(I2C_FLAG_BTC)) return 5;
開始
/************* start ***********************/
// 發送再啟動信號
i2c_start_on_bus(i2cx);if(I2C_wait(I2C_FLAG_SBSEND)) return 7;
發送設備地址(讀)
/************* device address **************/
// 發送從設備地址
i2c_master_addressing(i2cx, address, I2C_RECEIVER);
if(I2C_wait(I2C_FLAG_ADDSEND)) return 8;
i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);
數據讀取
/************* data **************/
//ack
i2c_ack_config(i2cx, I2C_ACK_ENABLE);
// 接收一個數據后,自動發送ACK
i2c_ackpos_config(i2cx, I2C_ACKPOS_CURRENT);
// 確認ACK已啟用
if(I2C_wait(I2C_CTL0(i2cx) & I2C_CTL0_ACKEN)) return 11;// 讀取數據
uint32_t i;
for (i = 0; i < len; i++) {if (i == len - 1) {// 在讀取最后一個字節之前,禁用ACK,配置為自動NACKi2c_ack_config(i2cx, I2C_ACK_DISABLE);}// 等待接收緩沖區不為空if(I2C_wait(I2C_FLAG_RBNE)) return 10;data[i] = i2c_data_receive(i2cx);
}
停止
/***************** stop ********************/
i2c_stop_on_bus(i2cx);if(I2C_waitn(I2C_CTL0(i2cx)&I2C_CTL0_STOP)) return 12;
GD32F4寄存器
流程 | 功能 | 標記 | 描述 |
START |
| busy標記。I2C是否占用,沒有占用才可以使用。 | |
| 起始信號發送狀態標記。START成功或失敗。 | ||
數據 | 設備地址 |
| 地址發送狀態標記。成功或失敗。 |
發送 |
| 發送數據寄存器是否為空的標記。為空才可以繼續發送。 | |
| 發送數據寄存器中數據是否發送完成。 | ||
接收 |
| 接收緩沖區寄存器是否為空的標記。為空才可以繼續接收。 | |
STOP |
| 停止標記位。 |
完整代碼
//I2C0.h
#ifndef __I2C0_H__
#define __I2C0_H__#include "systick.h"
#include "gd32f4xx.h"void I2C0_init();uint8_t I2C0_read(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t len);uint8_t I2C0_write(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t len);uint8_t I2C0_write2(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t offset, uint32_t len);void I2C0_deinit();#endif
?
//I2C0.c
#include "I2C0.h"#define i2cx I2C0void I2C0_init() {uint32_t i2cx_scl_port_rcu = RCU_GPIOB;uint32_t i2cx_scl_port = GPIOB;uint32_t i2cx_scl_pin = GPIO_PIN_6;uint32_t i2cx_scl_af = GPIO_AF_4;uint32_t i2cx_sda_port_rcu = RCU_GPIOB;uint32_t i2cx_sda_port = GPIOB;uint32_t i2cx_sda_pin = GPIO_PIN_7;uint32_t i2cx_sda_af = GPIO_AF_4;uint32_t i2cx = I2C0;uint32_t i2cx_rcu = RCU_I2C0;uint32_t i2cx_speed = 400000;/****************** GPIO config **********************/// 時鐘配置rcu_periph_clock_enable(i2cx_scl_port_rcu);// 設置復用功能gpio_af_set(i2cx_scl_port, i2cx_scl_af, i2cx_scl_pin);// 設置輸出模式gpio_mode_set(i2cx_scl_port, GPIO_MODE_AF, GPIO_PUPD_NONE, i2cx_scl_pin);gpio_output_options_set(i2cx_scl_port, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, i2cx_scl_pin);// 時鐘配置rcu_periph_clock_enable(i2cx_sda_port_rcu);// 設置復用功能gpio_af_set(i2cx_sda_port, i2cx_sda_af, i2cx_sda_pin);// 設置輸出模式gpio_mode_set(i2cx_sda_port, GPIO_MODE_AF, GPIO_PUPD_NONE, i2cx_sda_pin);gpio_output_options_set(i2cx_sda_port, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, i2cx_sda_pin);/****************** I2C config **********************/i2c_deinit(i2cx);// 時鐘配置rcu_periph_clock_enable(i2cx_rcu);// I2C速率配置i2c_clock_config(i2cx, i2cx_speed, I2C_DTCY_2);// 使能i2ci2c_mode_addr_config(i2cx, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0x00);i2c_enable(i2cx);// i2c ack enablei2c_ack_config(i2cx, I2C_ACK_ENABLE);//i2c_ackpos_config(i2cx, I2C_ACKPOS_CURRENT);}static uint8_t I2C_wait(uint32_t flag) {uint16_t TIMEOUT = 50000;uint16_t cnt = 0;while(!i2c_flag_get(i2cx, flag)) {cnt++;if(cnt > TIMEOUT) return 1;}return 0;
}static uint8_t I2C_waitn(uint32_t flag) {uint16_t TIMEOUT = 50000;uint16_t cnt = 0;while(i2c_flag_get(i2cx, flag)) {cnt++;if(cnt > TIMEOUT) return 1;}return 0;
}uint8_t I2C0_write(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t data_len) {uint8_t address = addr << 1;/************* start ***********************/// 等待I2C閑置if(I2C_waitn(I2C_FLAG_I2CBSY)) return 1;// starti2c_start_on_bus(i2cx);// 等待I2C主設備成功發送起始信號if(I2C_wait(I2C_FLAG_SBSEND)) return 2;/************* device address **************/// 發送設備地址i2c_master_addressing(i2cx, address, I2C_TRANSMITTER);// 等待地址發送完成if(I2C_wait(I2C_FLAG_ADDSEND)) return 3;i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);/************ register address ************/// 寄存器地址// 等待發送數據緩沖區為空if(I2C_wait(I2C_FLAG_TBE)) return 4;// 發送數據i2c_data_transmit(i2cx, reg);// 等待數據發送完成if(I2C_wait(I2C_FLAG_BTC)) return 5;/***************** data ******************/// 發送數據uint32_t i;for(i = 0; i < data_len; i++) {uint32_t d = data[i];// 等待發送數據緩沖區為空if(I2C_wait(I2C_FLAG_TBE)) return 6;// 發送數據i2c_data_transmit(i2cx, d);// 等待數據發送完成if(I2C_wait(I2C_FLAG_BTC)) return 7;}/***************** stop ********************/// stopi2c_stop_on_bus(i2cx);if(I2C_waitn(I2C_CTL0(i2cx)&I2C_CTL0_STOP)) return 8;return 0;
}uint8_t I2C0_write2(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t offset, uint32_t len) {uint8_t address = addr << 1;/************* start ***********************/// 等待I2C閑置if(I2C_waitn(I2C_FLAG_I2CBSY)) return 1;// starti2c_start_on_bus(i2cx);// 等待I2C主設備成功發送起始信號if(I2C_wait(I2C_FLAG_SBSEND)) return 2;/************* device address **************/// 發送設備地址i2c_master_addressing(i2cx, address, I2C_TRANSMITTER);// 等待地址發送完成if(I2C_wait(I2C_FLAG_ADDSEND)) return 3;i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);/************ register address ************/// 寄存器地址// 等待發送數據緩沖區為空if(I2C_wait(I2C_FLAG_TBE)) return 4;// 發送數據i2c_data_transmit(i2cx, reg);// 等待數據發送完成if(I2C_wait(I2C_FLAG_BTC)) return 5;/***************** data ******************/// 發送數據do {// 等待發送數據緩沖區為空if(I2C_wait(I2C_FLAG_TBE)) return 6;// 發送數據i2c_data_transmit(i2cx, *data);data += offset;// 等待數據發送完成if(I2C_wait(I2C_FLAG_BTC)) return 7;} while(--len);/***************** stop ********************/// stopi2c_stop_on_bus(i2cx);if(I2C_waitn(I2C_CTL0(I2C0)&I2C_CTL0_STOP)) return 8;return 0;
}void I2C0_deinit() {}uint8_t I2C0_read(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t len) {uint32_t i2cx = I2C0;uint8_t address = addr << 1;/************* start ***********************/// 等待I2C空閑if(I2C_waitn(I2C_FLAG_I2CBSY)) return 1;// 發送啟動信號i2c_start_on_bus(i2cx);if(I2C_wait(I2C_FLAG_SBSEND)) return 2;/************* device address **************/// 發送從設備寫地址i2c_master_addressing(i2cx, address, I2C_TRANSMITTER);if(I2C_wait(I2C_FLAG_ADDSEND)) return 3;i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);/********** register address **************/// 等待發送緩沖區 if(I2C_wait(I2C_FLAG_TBE)) return 4;// 發送寄存器地址i2c_data_transmit(i2cx, reg);// 等待發送數據完成 if(I2C_wait(I2C_FLAG_BTC)) return 5; /************* start ***********************/// 發送再啟動信號i2c_start_on_bus(i2cx);if(I2C_wait(I2C_FLAG_SBSEND)) return 7;/************* device address **************/// 發送從設備讀地址i2c_master_addressing(i2cx, address + 1, I2C_RECEIVER);if(I2C_wait(I2C_FLAG_ADDSEND)) return 8;i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);/**************** 接收數據data *************///acki2c_ack_config(i2cx, I2C_ACK_ENABLE);// 接收一個數據后,自動發送ACKi2c_ackpos_config(i2cx, I2C_ACKPOS_CURRENT);// 確認ACK已啟用if(I2C_wait(I2C_CTL0(i2cx) & I2C_CTL0_ACKEN)) return 11;// 讀取數據uint32_t i;for (i = 0; i < len; i++) {if (i == len - 1) {// 在讀取最后一個字節之前,禁用ACK,配置為自動NACKi2c_ack_config(i2cx, I2C_ACK_DISABLE);}// 等待接收緩沖區不為空if(I2C_wait(I2C_FLAG_RBNE)) return 10;data[i] = i2c_data_receive(i2cx);}/***************************************//***************** stop ********************/i2c_stop_on_bus(i2cx);if(I2C_waitn(I2C_CTL0(i2cx)&I2C_CTL0_STOP)) return 12;return 0;
}