概述
本文主要介绍了HaaS100 I2C和I2C MUXer的硬件情况和如何使用。
适用范围
- 希望了解和学习HaaS和I2C外设的爱好者
- 希望使用HaaS I2C进行开发的开发人员
目标
- 基于I2C完成板上I2C MUXer的初始化,通道设置和读取
所需工具
- HaaS100 1块
- 随附电源 1套
- Micro USB线 1条
- 串口终端(这里使用的是Xshell 6 (build 0206))
外设简介
I²C(Inter-Integrated Circuit)是一种串行通信总线,使用多主从架构,由飞利浦公司在1980年代为了让主板、嵌入式系统或手机用以连接低速周边设备而发展。I²C的正确读法为“I方C”。
I²C只使用两条双向漏极开路(Open Drain)(串行资料(SDA)及串行时脉(SCL))并利用电阻将电位上拉。
I²C的参考设计使用一个7位元长度的位址空间但保留了16个位址,所以在一组汇流排最多可和112个节点通讯[a]。常见的I²C汇流排依传输速率的不同而有不同的模式:标准模式(100 kbit/s)、低速模式(10 kbit/s),但时脉频率可被允许下降至零,这代表可以暂停通讯。而新一代的I²C汇流排可以和更多的节点(支援10位元长度的位址空间)以更快的速率通讯:快速模式(400 kbit/s)、快速+模式(1 Mbit/s)高速模式(3.4 Mbit/s)超高速模式(5 Mbit/s)。(以上摘自维基百科)
以先为典型的I2C的总线连接图(图1):
图1 典型I2C总线连接
HaaS100的I2C情况
HaaS100使用的HaaS1000主控芯片支持2路I2C master,其中一路被UART2所复用连接到板上的扩展接口上,参考图2中黑色框中的Pin脚,暂时无法使用,为了有更多的I2C资源给到客户,我们使用了I2C MUXer将剩下的1路I2C扩展成了4路,其中两路已经在片上使用,另外两路连接到了扩展接口上,参考图2红色框中的Pin脚。
图2 HaaS扩展插槽
HaaS100板上的I2C连接,可以参考图3中高亮的部分,这些为I2C相关的扩展部分
图3 HaaS100 I2C扩展俯视图
HaaS100板上的I2C逻辑拓扑图如图4:
图4 HaaS100板上I2C逻辑拓扑图
I2C MUXer
HaaS100使用的是TI(德州仪器)的PCA9544A,是一个4 通道 I2C 和 SMBus 多路复用器,详细资料请参考官网。
使用指南
1、使用前环境准备可参考开发环境安装,如下为实际操作用的环境,仅供参考
- 本文所使用的系统为:UBuntu 16.04
- aos cube版本:0.5.10
- Python版本:3.5.2
2、本流程所涉及的相关文件:
I2C MUXer驱动
- components/peripherals/i2c_muxer/pca9544.c
- components/peripherals/i2c_muxer/pca9544.h
流程:
- 相关宏,结构体介绍
-
-
/* ===== Default Configuration Based on BSP ===== */
-
#ifdef HAAS_I2C
-
#define I2C_PORT 1
-
#define I2C_ADDR_W_8BIT 8
-
#define I2C_BR_100K 100000
-
#endif
-
-
/* ===== MACRO Definition ===== */
-
#define PCA9544_CHAN_CLEAN 0
-
#define PCA9544_CONFIG_REG_LEN 1U
-
#define PCA9544_IRQ_MASK 0xF0
-
#define PCA9544_BASE_ADDR 0x70
-
-
/* ===== Dev Type Definition ===== */
-
/* pca9544 channel list */
-
typedef enum
-
{
-
PCA9544_CH_NULL = 0,
-
PCA9544_CHO = 4,
-
PCA9544_CH1 = 5,
-
PCA9544_CH2 = 6,
-
PCA9544_CH3 = 7,
-
}PCA9544_CH_E;
-
-
/* pca9544 parameters configuration */
-
typedef struct
-
{
-
/* pca9544 i2c address */
-
uint8_t dev_addr;
-
/* pca9544 interrupt status */
-
uint8_t irq_status;
-
/* the current pca9544 channel */
-
PCA9544_CH_E pca9544_ch;
-
/* the sub dev addr for the selected pca9544 channel */
-
uint8_t subdev_addr;
-
//uint8_t control_reg;
-
/* the sub dev register address */
-
uint8_t reg_addr;
-
}PCA9544_DEV_CFG_T;
PCA9544有四个可选通道,原始选通值为4/5/6/7,这里已经使用枚举做了封装;
PCA9544的I2C Address通过硬件做了相关配置,这里是0x70;
详见components/peripherals/i2c_muxer/pca9544.h
-
- 初始化
-
i2c_dev_t i2c;
-
PCA9544_DEV_CFG_T dev_cfg;
-
-
dev_cfg.dev_addr = PCA9544_BASE_ADDR;
-
dev_cfg.pca9544_ch = test_chan;
-
dev_cfg.subdev_addr =
0x32;
-
dev_cfg.reg_addr =
0x10;
-
-
i2c.port =
1;
-
i2c.config.address_width =
8;
-
i2c.config.freq = I2C_BUS_BIT_RATES_100K;
-
i2c.config.dev_addr = dev_cfg.dev_addr;
-
-
/* I2C Initialization */
-
ret = hal_i2c_init(&i2c);
-
if (ret) {
-
printf(
"=====i2c test : i2c 1 dev init fail =====\r\n");
-
return
-1;
-
-
}
-
-
/* I2C MUXer PCA9544 Initialization */
-
ret = pca9544_init(&i2c, &dev_cfg);
-
if (ret) {
-
printf(
"=====pca9544 test : init fail =====\r\n");
-
return
-1;
-
-
}
- PCA9544初始化的具体实现:
-
/**********************************************************
-
* @fun PCA9544_init
-
* @breif pca9544 initialization
-
* @param i2c:the pointer for i2c configuration
-
* @param dev_cfg: the pointer for dev configuration
-
* @rtn
-
*********************************************************/
-
int pca9544_init(i2c_dev_t *i2c, PCA9544_DEV_CFG_T* dev_cfg)
-
{
-
int ret =
0;
-
-
if(i2c ==
NULL)
-
{
-
printf(
"PCA9544 i2c is null\n");
-
return
-1;
-
}
-
-
memset(&g_pca9544_i2c_cfg,
0,
sizeof(
i2c_dev_t));
-
memcpy(&g_pca9544_i2c_cfg, i2c,
sizeof(
i2c_dev_t));
-
-
ret = hal_i2c_init(&g_pca9544_i2c_cfg);
-
if(ret)
-
{
-
printf(
"Host I2C open failed\n");
-
hal_i2c_finalize(&g_pca9544_i2c_cfg);
-
return
-1;
-
}
-
-
if(dev_cfg ==
NULL)
-
{
-
printf(
"PCA9544 cfg is null\n");
-
return
-1;
-
}
-
memset(&g_pca9544_dev_cfg,
0,
sizeof(PCA9544_DEV_CFG_T));
-
memcpy(&g_pca9544_dev_cfg, dev_cfg,
sizeof(PCA9544_DEV_CFG_T));
-
-
printf(
"PCA9544 cfg is successful\n");
-
return ret;
-
-
}
- PCA9544的寄存器配置,这里是进行通道选择配置:
-
/* chan select */
-
printf(
"=====i2c test : set chan 2[%d] of PCA9544=====\r\n", test_chan);
-
ret = pca9544_set_chan(test_chan);
-
osDelay(
2);
-
read_chan = pca9544_read_chan();
-
-
printf(
"=====I2C Muxer test : read chan val of PCA9544 is %d=====\r\n", read_chan);
- 至此PCA9544的通道选通已经完成,下面进行回读验证:
-
osDelay(
2);
-
/*if((reg & reg_rtn) == reg)*/
-
if(test_chan == read_chan)
-
{
-
printf(
"=====I2C Muxer test : PCA9544 test: PASS=====\r\n");
-
}
-
else
-
{
-
printf(
"=====I2C Muxer test : PCA9544 test: FAIL=====\r\n");
-
ret =
-1;
-
}
如果回读值等于预设值则配置成功,反之则反。
实际测试
- 整体测试代码,可以基于helloworld_demo做修改,具体位置application/example/helloworld_demo/appdemo.c
完成测试代码如下
-
/*
-
* Copyright (C) 2015-2020 Alibaba Group Holding Limited
-
*/
-
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <aos/errno.h>
-
#include <aos/kernel.h>
-
#include "aos/init.h"
-
#include "board.h"
-
#include <k_api.h>
-
#include "pca9544.h"
-
#include "aos/hal/i2c.h"
-
-
static int32_t i2c_test_process()
-
{
-
int32_t ret;
-
-
char data[
7] = {
0x01,
1,
1,
1,
7,
9,
20};
-
char data_rtn[
7] = {
0};
-
uint16_t size =
7;
-
PCA9544_CH_E test_chan = PCA9544_CH1;
-
PCA9544_CH_E read_chan = PCA9544_CH_NULL;
-
uint8_t reg_rtn;
-
uint8_t chan_mask =
0x05;
-
-
i2c_dev_t i2c;
-
PCA9544_DEV_CFG_T dev_cfg;
-
-
dev_cfg.dev_addr = PCA9544_BASE_ADDR;
-
dev_cfg.pca9544_ch = test_chan;
-
dev_cfg.subdev_addr =
0x32;
-
dev_cfg.reg_addr =
0x10;
-
-
i2c.port =
1;
-
i2c.config.address_width =
8;
-
i2c.config.freq = I2C_BUS_BIT_RATES_100K;
-
i2c.config.dev_addr = dev_cfg.dev_addr;
-
-
ret = hal_i2c_init(&i2c);
-
if (ret) {
-
printf(
"=====i2c test : i2c 1 dev init fail =====\r\n");
-
return
-1;
-
-
}
-
-
ret = pca9544_init(&i2c, &dev_cfg);
-
if (ret) {
-
printf(
"=====pca9544 test : init fail =====\r\n");
-
return
-1;
-
-
}
-
-
/* chan select */
-
printf(
"=====i2c test : set chan 2[%d] of PCA9544=====\r\n", test_chan);
-
ret = pca9544_set_chan(test_chan);
-
osDelay(
2);
-
read_chan = pca9544_read_chan();
-
-
printf(
"=====I2C Muxer test : read chan val of PCA9544 is %d=====\r\n", read_chan);
-
-
osDelay(
2);
-
/*if((reg & reg_rtn) == reg)*/
-
if(test_chan == read_chan)
-
{
-
printf(
"=====I2C Muxer test : PCA9544 test: PASS=====\r\n");
-
}
-
else
-
{
-
printf(
"=====I2C Muxer test : PCA9544 test: FAIL=====\r\n");
-
ret =
-1;
-
}
-
-
-
hal_i2c_finalize(&i2c);
-
-
return
0;
-
-
}
-
-
static int i2c_autotest()
-
{
-
int32_t ret =
0;
-
-
printf(
"\r\n\r\n");
-
printf(
"***************************************************************\r\n");
-
printf(
"*************************** I2C&RTC Test **********************\r\n");
-
printf(
"***************************************************************\r\n");
-
printf(
"** Note: this test don't need to connect any external tool **\r\n");
-
printf(
"** How to test: this test is a autotest **\r\n");
-
printf(
"** Process 1.1 set chan1(0x05) for PCA9544 by i2c **\r\n");
-
printf(
"** Process 1.2 read_chan the selected chan no. from PCA9544 **\r\n");
-
printf(
"** Process 2.1 set 20.9.7 1:1:1 to RX8310CE **\r\n");
-
printf(
"** Process 2.2 read the current time from RX8310CE **\r\n");
-
printf(
"***************************************************************\r\n");
-
printf(
"=====i2c test : Start=====\r\n");
-
-
ret = i2c_test_process();
-
if(ret)
-
{
-
printf(
"\r\n=====i2c test : FAIL ===\r\n");
-
return
-1;
-
}
-
-
printf(
"\r\n=====i2c test : PASS===\r\n");
-
return
0;
-
}
-
-
-
int application_start(int argc, char *argv[])
-
{
-
int count =
0;
-
-
printf(
"nano entry here!\r\n");
-
-
i2c_autotest();
-
-
while(
1) {
-
printf(
"hello world! count %d \r\n", count++);
-
-
aos_msleep(
1000);
-
};
-
}
- 连接HaaS100电源,电源指示灯亮
- 编译代码:
-
aos make disclean
-
aos make clean
-
aos make helloworld_demo@haas100 -c config && aos make
注意:前两步是为了清理干净环境,避免引入其他问题
- 编译结果:部分
-
Making helloworld_demo@haas100.bin
-
Making helloworld_demo@haas100.hex
-
-
AOS MEMORY MAP
-
|=================================================================|
-
| MODULE | ROM | RAM |
-
|=================================================================|
-
| arch_armv7m | 2174 | 0 |
-
| board_haas100 | 2212 | 6815812 |
-
| cli | 6918 | 373 |
-
| debug | 9696 | 132 |
-
| helloworld_demo | 1807 | 12 |
-
| i2c_muxer | 632 | 25 |
-
| kernel_init | 359 | 12 |
-
| kv | 3297 | 36 |
-
| libc_nano | 20270 | 3911 |
-
| libgcc | 3612 | 0 |
-
| libhaas1000 | 597823 | 921102 |
-
| libm | 18820 | 1594 |
-
| lwip | 38935 | 3281 |
-
| mcu_haas1000 | 33057 | 3206 |
-
| newlib_stub | 614 | 0 |
-
| osal_aos | 1096 | 0 |
-
| osal_posix | 129 | 136 |
-
| rhino | 13739 | 18262 |
-
| ulog | 1519 | 331 |
-
| vfs | 1092 | 1113 |
-
| yloop | 1336 | 32 |
-
| *fill* | 4978950 | 71513 |
-
|=================================================================|
-
| TOTAL (bytes) | 5738087 | 7840883 |
-
|=================================================================|
-
gen signature and release image ...
-
OUTPUT_DIR is out/helloworld_demo@haas100
-
format wrong
-
/workspace/haas/test_senmu_0819/platform/mcu/haas1000/release/auto_build_tool
-
[
'chmod',
'777',
'/workspace/haas/test_senmu_0819/platform/mcu/haas1000/release/auto_build_tool/bes_sign_tool']
-
Start chmod sign dir...
-
chmod sign dir
done.
-
-
Start make littlefs
-
Debug output enabled
-
/demo
-
file size: 21
-
genfs
done.
-
Littlefs code size:4907008
-
Make littlefs
done
-
cp -f ../../prebuild/factory.bin ../release_bin/
-
cp -f ../../prebuild/littlefs.bin ../release_bin/
-
cp -f ../../prebuild/data ../release_bin/
-
cp -f ../../prebuild/pub_otp.bin ../release_bin/
-
cp -f ../../prebuild/ota_boot2a.bin ../release_bin/
-
cp -f ../../prebuild/boot_info.bin ../release_bin/
-
cp -f ../../prebuild/ota_boot1.bin ../release_bin/
-
cp -f ../../prebuild/ota_boot1_sec.bin ../release_bin/
-
cp -f ../../prebuild/programmer2001.bin ../release_bin/
-
cp /workspace/haas/test_senmu_0819/out/helloworld_demo@haas100/binary/*@haas100.bin ../release_bin/ota_rtos.bin
-
/workspace/haas/test_senmu_0819/out/helloworld_demo@haas100/binary/helloworld_demo@haas100.bin
-
cp -f ../write_flash_gui/dld_cfg/haas1000_dld_cfg.yaml ../write_flash_gui/
-
cp -f ../write_flash_gui/haas1000_dld_cfg.yaml ../write_flash_gui/haas1000_dld_cfg.yaml
-
cp -f ../release_bin/programmer2001.bin ../write_flash_tool/tools/
-
cp -f ../release_bin/programmer2001.bin ../write_flash_gui/
-
cp -f ../release_bin/factory.bin ../write_flash_tool/ota_bin/
-
cp -f ../release_bin/factory.bin ../write_flash_gui/ota_bin/
-
cp -f ../release_bin/littlefs.bin ../write_flash_tool/ota_bin/
-
cp -f ../release_bin/littlefs.bin ../write_flash_gui/ota_bin/
-
cp -f ../release_bin/ota_rtos.bin ../write_flash_tool/ota_bin/
-
cp -f ../release_bin/ota_rtos.bin ../write_flash_gui/ota_bin/
-
cp -f ../release_bin/pub_otp.bin ../write_flash_tool/ota_bin/
-
cp -f ../release_bin/pub_otp.bin ../write_flash_gui/ota_bin/
-
cp -f ../release_bin/ota_boot2a.bin ../write_flash_tool/ota_bin/
-
cp -f ../release_bin/ota_boot2a.bin ../write_flash_gui/ota_bin/
-
cp -f ../release_bin/boot_info.bin ../write_flash_tool/ota_bin/
-
cp -f ../release_bin/boot_info.bin ../write_flash_gui/ota_bin/
-
cp -f ../release_bin/ota_boot1.bin ../write_flash_tool/ota_bin/
-
cp -f ../release_bin/ota_boot1.bin ../write_flash_gui/ota_bin/
-
cp -f ../release_bin/ota_boot1_sec.bin ../write_flash_tool/ota_bin/
-
cp -f ../release_bin/ota_boot1_sec.bin ../write_flash_gui/ota_bin/
-
cp -f ../release_bin/ota_boot1_sec.bin ../write_flash_gui/ota_bin/
-
all files
done.
-
gen ota image ...
-
Build complete: helloworld_demo@haas100
- 使用图形化烧录工具烧录固件:
固件位置:./platform/mcu/haas1000/release/write_flash_gui
如果之前烧录过,可以直接替换上述文件夹中的ota_bin/ota_rtos.bin文件
- 烧录工具截图如下:
图5 HaaS100烧录截图
- 烧录完成后停止烧录工具串口连接,使用Micro USB线连接HaaS100到PC,这里连接的是Win10环境,打开串口工具,做如下设置,串口号根据实际情况,波特率需要设置到1500000(五个0)
图6 HaaS100串口设置
- 打开串口终端,并按下HaaS100重启键,打印出如下测试结果:
-
***************************************************************
-
*************************** I2C&RTC Test **********************
-
***************************************************************
-
** Note: this
test don
't need to connect any external tool **
-
** How to test: this test is a autotest **
-
** Process 1.1 set chan1(0x05) for PCA9544 by i2c **
-
** Process 1.2 read_chan the selected chan no. from PCA9544 **
-
** Process 2.1 set 20.9.7 1:1:1 to RX8310CE **
-
** Process 2.2 read the current time from RX8310CE **
-
***************************************************************
-
=====i2c test : Start=====
-
PCA9544 cfg is successful
-
=====i2c test : set chan 2[5] of PCA9544=====
-
=====I2C Muxer test : read chan val of PCA9544 is 5=====
-
=====I2C Muxer test : PCA9544 test: PASS=====
至此HaaS100的I2C初始化和PCA9544的通道选通就已经完成。
结语
HaaS100的I2C涉及到的细节相对多一些,在后面的系列文章里会逐步给大家介绍清楚,下次会介绍mux_i2c的通用接口。
小结
如需更多技术支持,可加入钉钉开发者群,或者关注微信公众号
更多技术与解决方案介绍,请访问阿里云AIoT首页https://iot.aliyun.com/
转载:https://blog.csdn.net/HaaSTech/article/details/112114152