I2C是我们常用的外设功能之一,CSK6 SDK I2C外设驱动采用标准的I2C总线协议,本节我们将通过示例演示如何使用 MCU 的 i2c 通信功能,通过 i2c 控制器向从设备的寄存器地址写数据和读数据。
CSK6 芯片有两个I2C 硬件外设。
CSK6 I2C驱动功能特性如下:
int i2c_configure(const struct device *dev, uint32_t dev_config);
I2C主控制器的配置操作,成功返回0,失败返回非0。
参数说明
字段 | 说明 |
---|---|
dev | 指向I2C Device的指针 |
dev_config | I2C运行时的配置值,32位 |
dev_config可取以下选项
宏定义 | 作用 | |
---|---|---|
I2C_SPEED_STANDARD | 标准模式:100 kHz | |
I2C_SPEED_FAST | 快速模式:400 kHz | |
I2C_SPEED_FAST_PLUS | 快速模式+:1 MHz | |
I2C_SPEED_HIGH | 高速模式:3.4 MHz | |
I2C_SPEED_ULTRA | 超快速模式:5 MHz | |
I2C_MODE_MASTER | 使当前控制器作为主控制器 | |
I2C_ADDR_10_BITS | 使用10位寻址。(不推荐使用-改用I2C_MSG_ADDR_10_BITS) |
static int i2c_write(const struct device *dev, const uint8_t *buf, uint32_t num_bytes, uint16_t addr);
将数据写入I2C设备,此函数写入一次会产生起始与终止信号,成功返回0,失败返回非0。
参数说明
参数名 | 介绍 |
---|---|
dev | 指向I2C Device的指针 |
buf | 传输数据的buf内存池 |
num_bytes | 传输数据的buf大小 |
addr | I2C设备地址 |
static int i2c_read(const struct device * dev, uint8_t *buf, uint32_t num_bytes, uint16_t addr);
从I2C设备读取数据,此函数读取一次会产生起始与终止信号,成功返回0,失败返回非0。
参数说明
参数名 | 介绍 |
---|---|
dev | 指向I2C Device的指针 |
buf | 存储数据的buf内存池 |
num_bytes | 存储数据的buf大小 |
addr | I2C设备地址 |
更多I2C API接口请访问zephyr官网I2C Interface。
演示如何使用 MCU 的 i2c 通信功能,通过 i2c 控制器向从设备的寄存器地址写数据和读数据。
{SDK}\.sdk\csk\samples\driver\i2c\i2c_master
适用开发板:大模型开发套件
编译版型:csk6_duomotai_devkit
使用引脚:
在 SDK 根目录(duomotai_ap
)下可通过执行以下指令进行对该示例工程的编译:
lisa zep build -b csk6_duomotai_devkit .sdk/csk/samples/driver/i2c/i2c_master -p
编译完成后,编译产物二进制文件位于 build\zephyr\zephyr.bin
使用 Type-C 数据线连接开发套件的 DAP_USB
接口,选中以下其中一种方式对固件进行烧录:
cskburn desktop
是一款聆思推出的桌面烧录工具,在下载并安装 cskburn desktop 烧录工具后,双击图标运行软件:
1.点击串口下拉框,选择连接开发套件后识别到的串口编号;
2.将编译输出的.bin
文件拖拽进烧录区域;
3.点击开始烧录,等待烧录完成。
若您已按照 《环境搭建》 教程完成开发环境的安装,可在编译完成后执行 lisa zep exec cskburn
指令完成烧录。
lisa zep exec cskburn -s \\.\COMxx -C 6 -b 1500000 0x000000 --verify-all .\build\zephyr\zephyr.bin
请将命令行中的的 COMx 替换为开发套件在 PC 上对应的串口号(可通过设备管理器查看)。例如:
COM3
。
lisa zep exec cskburn -s PORT -C 6 0x000000 --verify-all ./build/zephyr/zephyr.bin -b 1500000
请将命令行中的 PORT 替换为开发套件连接在 PC 上对应的串口号。例如:
/dev/ttyUSB0
。
烧录完成后,连接串口终端,按下开发板复位按钮,可看到串口有对应的信息输出。
以下代码与注释已省略一部分非关键接口代码,主要呈现示例的主业务流程与主要接口的使用。
在工程目录prj.conf
文件中需配置以下模块:
# I2C配置
CONFIG_I2C=y
CONFIG_I2C_LOG_LEVEL_INF=y
csk6_duomotai_devkit
开发板提供了多组I2C。本示例使用I2C1_SCL:GPIOB_09 / I2C1_SDA:GPIOB_08
这组GPIO口,因此需要在设备树中将这两组GPIO复用为I2C引脚功能,可通过boards
目录下 overlay 文件的方式完成 I2C 引脚的设备树配置。
设备树文件csk6_duomotai_devkit.overlay
配置如下:
/*
* SPDX-License-Identifier: Apache-2.0
*/
&pinctrl {
/* 将GPIOA_09配置为i2c1 scl */
pinctrl_i2c1_scl_default: i2c1_scl_default{
pinctrls = <I2C1_SCL_GPIOB_09>;
};
/* 将GPIOA_08配置为i2c1 sda */
pinctrl_i2c1_sda_default: i2c1_sda_default{
pinctrls = <I2C1_SDA_GPIOB_08>;
};
};
&i2c1 {
status = "okay";
pinctrl-0 = <&pinctrl_i2c1_scl_default &pinctrl_i2c1_sda_default>;
pinctrl-names = "default";
};
如果需要修改 I2C 引脚或通道,可在SDK的.sdk\csk\dts\arm\csk\csk6-pinctrl.h
文件中查看可使用的IO口,该文件定义了芯片所有IO口可用外设功能,开发者仅需要选择对应的 IO 即可,例如:
// i2c1
#define I2C1_SDA_GPIOA_00 CSK6_PINMUX(a, 0, 9)
#define I2C1_SCL_GPIOA_01 CSK6_PINMUX(a, 1, 9)
#define I2C1_SDA_GPIOA_02 CSK6_PINMUX(a, 2, 9)
#define I2C1_SCL_GPIOA_03 CSK6_PINMUX(a, 3, 9)
#define I2C1_SDA_GPIOA_04 CSK6_PINMUX(a, 4, 9)
#define I2C1_SCL_GPIOA_05 CSK6_PINMUX(a, 5, 9)
#define I2C1_SDA_GPIOA_06 CSK6_PINMUX(a, 6, 9)
#define I2C1_SCL_GPIOA_07 CSK6_PINMUX(a, 7, 9)
#define I2C1_SDA_GPIOA_08 CSK6_PINMUX(a, 8, 9)
#define I2C1_SCL_GPIOA_09 CSK6_PINMUX(a, 9, 9)
#define I2C1_SDA_GPIOA_10 CSK6_PINMUX(a, 10, 9)
#define I2C1_SCL_GPIOA_11 CSK6_PINMUX(a, 11, 9)
#define I2C1_SDA_GPIOA_12 CSK6_PINMUX(a, 12, 9)
…
如果您想了解更多关于设备树的信息,请学习设备树章节。
1.从设备树中获取 i2c 控制器设备
i2c_dev = device_get_binding(I2C_DEV_LABEL);
2.配置i2c控制器
ret = i2c_configure(i2c_dev, I2C_SPEED_SET(I2C_SPEED_STANDARD) | I2C_MODE_CONTROLLER);
3.读取寄存器原始数据
ret = i2c_reg_read_byte(i2c_dev,TARGET_DEVICE_ADDR,TARGET_REG_ADDR,&i2c_reg_data_raw);
4.写数据到寄存器
ret = i2c_reg_write_byte(i2c_dev,TARGET_DEVICE_ADDR,TARGET_REG_ADDR,data);
5.读取修改后的寄存器数据
ret = i2c_reg_read_byte(i2c_dev,TARGET_DEVICE_ADDR,TARGET_REG_ADDR,&i2c_reg_data_modi);
按下开发板复位按钮,运行程序,观察串口信息。
int main(void)
{
const struct device *i2c_dev;
uint8_t i2c_reg_data_raw;
uint8_t i2c_reg_data_modify;
uint8_t data = 0x99;
int ret;
i2c_dev = DEVICE_DT_GET(I2C1_NODE);
if (!i2c_dev) {
printk("No I2C device found");
return -1;
}
ret = i2c_configure(i2c_dev, I2C_SPEED_SET(I2C_SPEED_STANDARD) | I2C_MODE_CONTROLLER);
if (ret < 0) {
printk("i2c config failed\n");
return -1;
}
ret = i2c_reg_read_byte(i2c_dev,TARGET_DEVICE_ADDR,TARGET_REG_ADDR,&i2c_reg_data_raw);
if(ret < 0){
printk("i2c_reg_read_byte failed!\n");
return -1;
}
printk("i2c_reg_data_raw: %d\n",i2c_reg_data_raw);
ret = i2c_reg_write_byte(i2c_dev,TARGET_DEVICE_ADDR,TARGET_REG_ADDR,data);
if(ret < 0){
printk("i2c_reg_write_byte failed!\n");
return -1;
}
ret = i2c_reg_read_byte(i2c_dev,TARGET_DEVICE_ADDR,TARGET_REG_ADDR,&i2c_reg_data_modify);
if(ret < 0){
printk("i2c_reg_read_byte failed!\n");
return -1;
}
printk("i2c_reg_data_modify: %d\n",i2c_reg_data_modify);
return 0;
}
}