CN / EN
文档反馈
感谢关注汇顶文档,期待您的宝贵建议!
感谢您的反馈,祝您愉快!

I2C Master & Slave

I2C Master & Slave示例实现了I2C模块之间的通信,其中一端为Master,另一端为Slave。

I2C Master & Slave示例的源代码和工程文件位于SDK_Folder\projects\peripheral\i2c\i2c_master_slave,其中工程文件在文件夹Keil_5下。

代码理解

示例工程流程图如图 17

图 17 I2C Master & Slave示例工程流程图
  1. 配置I2C模块。

    I2C详细配置参数请参考I2C DMA UART。此示例工程中,speed选择I2C_SPEED_400K,addressing_mode选择I2C_ADDRESSINGMODE_7BIT,general_call_mode选择I2C_GENERALCALL_DISABLE。

    Master和Slave需设置各自不同的设备地址:

    #define MASTER_DEV_ADDR                 0x4D
    #define SLAVE_DEV_ADDR                  0x55
    
    g_i2cs_handle.init.own_address  = SLAVE_DEV_ADDR;
    
    g_i2cm_handle.init.own_address = MASTER_DEV_ADDR;
    
  2. I2C硬件初始化。

    void hal_i2c_msp_init(i2c_handle_t *p_i2c)
    {
        gpio_init_t gpio_config = GPIO_DEFAULT_CONFIG;
        msio_init_t msio_config = MSIO_DEFAULT_CONFIG;
    
        if (p_i2c->p_instance == I2C_MASTER_MODULE)
        {
            msio_config.pin  = I2C_MASTER_SCL_PIN | I2C_MASTER_SDA_PIN;
            msio_config.pull = MSIO_PULLUP;
            msio_config.mux  = I2C_MASTER_GPIO_MUX;
            hal_msio_init(&msio_config);
        }
        else if (p_i2c->p_instance == I2C_SLAVE_MODULE)
        {
           gpio_config.mode = GPIO_MODE_MUX;
           gpio_config.pull = GPIO_PULLUP;
           gpio_config.pin  = I2C_SLAVE_SCL_PIN | I2C_SLAVE_SDA_PIN;
           gpio_config.mux  = I2C_SLAVE_GPIO_MUX;
           hal_gpio_init(I2C_SLAVE_GPIO_PORT, &gpio_config);
        }
        NVIC_ClearPendingIRQ(I2C_GET_IRQNUM(p_i2c->p_instance));
        NVIC_EnableIRQ(I2C_GET_IRQNUM(p_i2c->p_instance));
    	
        if (p_i2c->p_instance == I2C_MASTER_MODULE)
        {
            __HAL_LINKDMA(p_i2c, p_dmatx, s_i2cm_dma_tx_handle);
            __HAL_LINKDMA(p_i2c, p_dmarx, s_i2cm_dma_rx_handle);
            s_i2cm_dma_tx_handle.p_parent = p_i2c;
            s_i2cm_dma_rx_handle.p_parent = p_i2c;
            s_i2cm_dma_tx_handle.channel  = DMA_Channel0;
            s_i2cm_dma_rx_handle.channel  = DMA_Channel1;
        }
        else if (p_i2c->p_instance == I2C_SLAVE_MODULE)
        {
            __HAL_LINKDMA(p_i2c, p_dmatx, s_i2cs_dma_tx_handle);
            __HAL_LINKDMA(p_i2c, p_dmarx, s_i2cs_dma_rx_handle);
            s_i2cs_dma_tx_handle.p_parent = p_i2c;
            s_i2cs_dma_rx_handle.p_parent = p_i2c;
            s_i2cs_dma_tx_handle.channel  = DMA_Channel2;
            s_i2cs_dma_rx_handle.channel  = DMA_Channel3;
        }
        p_i2c->p_dmatx->init.src_request = DMA_REQUEST_MEM;
        p_i2c->p_dmarx->init.dst_request = DMA_REQUEST_MEM;
        if (p_i2c->p_instance == I2C0)
        {
            p_i2c->p_dmatx->init.dst_request = DMA_REQUEST_I2C0_TX;
            p_i2c->p_dmarx->init.src_request = DMA_REQUEST_I2C0_RX;
        }
        else if (p_i2c->p_instance == I2C1)
        {
            p_i2c->p_dmatx->init.dst_request = DMA_REQUEST_I2C1_TX;
            p_i2c->p_dmarx->init.src_request = DMA_REQUEST_I2C1_RX;
        }
    	
        p_i2c->p_dmatx->init.direction           = DMA_MEMORY_TO_PERIPH;
        p_i2c->p_dmatx->init.src_increment       = DMA_SRC_INCREMENT;
        p_i2c->p_dmatx->init.dst_increment       = DMA_DST_NO_CHANGE;
        p_i2c->p_dmatx->init.src_data_alignment  = DMA_SDATAALIGN_BYTE;
        p_i2c->p_dmatx->init.dst_data_alignment  = DMA_DDATAALIGN_BYTE;
        p_i2c->p_dmatx->init.mode  = DMA_NORMAL;
        p_i2c->p_dmatx->init.priority  = DMA_PRIORITY_LOW;
    	
        p_i2c->p_dmarx->init.direction           = DMA_PERIPH_TO_MEMORY;
        p_i2c->p_dmarx->init.src_increment       = DMA_SRC_NO_CHANGE;
        p_i2c->p_dmarx->init.dst_increment       = DMA_DST_INCREMENT;
        p_i2c->p_dmarx->init.src_data_alignment  = DMA_SDATAALIGN_BYTE;
        p_i2c->p_dmarx->init.dst_data_alignment  = DMA_DDATAALIGN_BYTE;
        p_i2c->p_dmarx->init.mode  = DMA_NORMAL;
        p_i2c->p_dmarx->init.priority  = DMA_PRIORITY_LOW;
    	
        hal_dma_init(p_i2c->p_dmatx);
        hal_dma_init(p_i2c->p_dmarx);
    	
        hal_nvic_clear_pending_irq(DMA_IRQn);
        hal_nvic_enable_irq(DMA_IRQn);
    }
    各个函数以及参数的具体意义,请参考I2C ADXL345
  3. Slave以中断方式接收数据,Master以轮询方式发送数据,因slave采用非阻塞方式,故在后续步骤中用while判断Slave是否接收完成。代码如下:
    hal_i2c_slave_receive_it(&g_i2cs_handle, rdata, 256);
    hal_i2c_master_transmit(&g_i2cm_handle, SLAVE_DEV_ADDR, wdata, 256, 5000);
    while (hal_i2c_get_state(&g_i2cs_handle) != HAL_I2C_STATE_READY);
    
  4. Slave以中断方式发送数据,Master以轮询方式接收数据,因slave采用非阻塞方式,故在后续步骤中用while判断Slave是否发送完成。代码如下:
    hal_i2c_slave_transmit_it(&g_i2cs_handle, wdata, 256);
    hal_i2c_master_receive(&g_i2cm_handle, SLAVE_DEV_ADDR, rdata, 256, 5000);
    while (hal_i2c_get_state(&g_i2cs_handle) != HAL_I2C_STATE_READY);
    
  5. Master和Slave分别以DMA方式进行数据的收发操作。因采用非阻塞方式,故在后续步骤中用while判断是否发送/接收完成。代码如下:
    hal_i2c_slave_receive_dma(&g_i2cs_handle, rdata, 256);
    hal_i2c_master_transmit_dma(&g_i2cm_handle, SLAVE_DEV_ADDR, wdata, 256);
    while (hal_i2c_get_state(&g_i2cs_handle) != HAL_I2C_STATE_READY);
     
    hal_i2c_slave_transmit_dma(&g_i2cs_handle, wdata, 256);
    hal_i2c_master_receive_dma(&g_i2cm_handle, SLAVE_DEV_ADDR, rdata, 256);
    while (hal_i2c_get_state(&g_i2cs_handle) != HAL_I2C_STATE_READY);
    

测试验证

  1. 用GProgrammer下载i2c_master_slave.bin至开发板。
  2. 连接主从设备开发板上对应的IO引脚。
  3. 将开发板串口连接至PC端,打开并配置GRUart。
  4. 在GRUart的Receive Data窗口中将会显示I2C模块之间的数据交互结果。

扫描关注

打开微信,使用“扫一扫”即可关注。