I2C Master & Slave
I2C Master & Slave示例实现了I2C模块之间的通信,其中一端为Master,另一端为Slave。
I2C Master & Slave示例的源代码和工程文件位于SDK_Folder\projects\peripheral\i2c\i2c_master_slave,其中工程文件在文件夹Keil_5下。
代码理解
示例工程流程图如图 17:
- 配置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; I2C硬件初始化。
各个函数以及参数的具体意义,请参考I2C ADXL345。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); }- 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); - 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); - 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);
测试验证
- 用GProgrammer下载i2c_master_slave.bin至开发板。
- 连接主从设备开发板上对应的IO引脚。
- 将开发板串口连接至PC端,打开并配置GRUart。
- 在GRUart的Receive Data窗口中将会显示I2C模块之间的数据交互结果。