HaaS100 I2C使用之板上I2C MUXer

概述

本文主要介绍了HaaS100 I2C和I2C MUXer的硬件情况如何使用

适用范围

  • 希望了解和学习HaaS和I2C外设的爱好者
  • 希望使用HaaS I2C进行开发的开发人员

目标

  • 基于I2C完成板上I2C MUXer的初始化,通道设置和读取

所需工具

  • HaaS100                1块
  • 随附电源                1套
  • Micro USB线          1条
  • 串口终端(这里使用的是Xshell 6 (build 0206))                          

外设简介

I²CInter-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):

image.png

图1 典型I2C总线连接

HaaS100的I2C情况

HaaS100使用的HaaS1000主控芯片支持2路I2C master,其中一路被UART2所复用连接到板上的扩展接口上,参考图2中黑色框中的Pin脚,暂时无法使用,为了有更多的I2C资源给到客户,我们使用了I2C MUXer将剩下的1路I2C扩展成了4路,其中两路已经在片上使用,另外两路连接到了扩展接口上,参考图2红色框中的Pin脚。

image.png

图2 HaaS扩展插槽

HaaS100板上的I2C连接,可以参考图3中高亮的部分,这些为I2C相关的扩展部分

image.png

图3 HaaS100 I2C扩展俯视图

HaaS100板上的I2C逻辑拓扑图如图4:

image.png

图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

流程:

  • 相关宏,结构体介绍
  1. /* ===== 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文件

  • 烧录工具截图如下:

image.png

图5 HaaS100烧录截图

  • 烧录完成后停止烧录工具串口连接,使用Micro USB线连接HaaS100到PC,这里连接的是Win10环境,打开串口工具,做如下设置,串口号根据实际情况,波特率需要设置到1500000(五个0)

image.png

图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/

猜你喜欢

转载自blog.csdn.net/HaaSTech/article/details/112114152