概述
本文主要介绍了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 [email protected]
Making [email protected]
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/[email protected]
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/