Linux应用——I2C通信例程
背景需求
两块板子通过I2C连接,其中一块为Master角色,一块为Slave角色,可以实现双方的相互通信,包括传输文件。
本文描述Master角色的编码。
需求:
- 可以指定Slave地址
- 可以指定传输文件块大小
- 可以指定传输每个数据块间隔
- 可以指定I2C的端口名称
实现设计
- 读取命令行参数
- 初始化参数后,依照参数向I2C设备写入数据,并尝试读取一段定长的数据
文件组织
文件名 | 文件描述 | 备注 |
---|---|---|
main.c | 判断传入参数,并实现调用I2C读写接口 | |
i2c.c | I2C初始化、读写接口实现 | |
util.c | 其他接口 | |
typedef.h | 数据类型定义 | |
log.h | 日志接口头文件 |
代码
main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include "i2c.h"
#include "util.h"
static void usage(const char *program)
{
if (NULL == program) {
return;
}
printf("Usage: %s [OPTION]\n"
"\n"
" -h, --help\n"
" -f, --file file to send\n"
" -a, --address i2c slave address (0x%02X by default)\n"
" -b, --block transfer block size (%dB by default)\n"
" -d, --delay transfer delay us (%dus by default)\n"
" -p, --port i2c port name (%s by default)\n",
program, DFT_I2C_SLAVE_ADDR, MAX_DFU_PKT, DFT_I2C_INTERVAL, DFT_I2C_PORT);
}
static bool read_dfu_file(char *optarg, DFU *dfu)
{
if (NULL == optarg || NULL == dfu) {
return false;
}
dfu->file = fopen(optarg, "rb");
if (NULL == dfu->file) {
print("fail to open %s", optarg);
return false;
}
if (fseek(dfu->file, 0L, SEEK_END)) {
goto error;
}
dfu->total = dfu->toload = ftell(dfu->file);
if (fseek(dfu->file, 0L, SEEK_SET)) {
goto error;
}
return true;
error:
fclose(dfu->file);
return false;
}
static void check_param(I2C_CTX *i2c, DFU *dfu)
{
if (NULL == i2c || NULL == dfu) {
return;
}
if (NULL == dfu->file) {
print("No file to transfer...");
exit(EXIT_FAILURE);
}
if (dfu->blk_size < 1 || dfu->blk_size > MAX_DFU_PKT) {
dfu->blk_size = MAX_DFU_PKT;
}
if (dfu->delay_us < 1 || dfu->delay_us > (DFT_I2C_INTERVAL << 2)) {
dfu->delay_us = DFT_I2C_INTERVAL;
}
if (i2c->port[0] == '\0') {
strncpy(i2c->port, DFT_I2C_PORT, FILE_SIZE);
}
if (i2c->slave_addr == 0x00) {
i2c->slave_addr = DFT_I2C_SLAVE_ADDR;
}
/* master ----> slave, address right shift */
i2c->slave_addr >>= 1;
i2c->fd = i2c_dev_init(i2c);
if (i2c->fd <= 0) {
print("fail to init i2c device:%s", i2c->port);
exit(EXIT_FAILURE);
}
print("\n\nI2C port:%s\nslave address:0x%02X\nblock size:%d B\ninterval:%d us\n",
i2c->port, i2c->slave_addr, dfu->blk_size, dfu->delay_us);
}
static void init(int argc, char *argv[], I2C_CTX *i2c, DFU *dfu)
{
int opt = 0;
int opt_idx = 0;
const char *short_opts = "ha:p:f:b:d:";
const struct option long_opts[] = {
{
"help", no_argument, 0, 'h'},
{
"address", required_argument, 0, 'a'},