智融PD芯片I2C通信实战从零实现高效可靠的模拟I2C驱动 概述本文详细介绍了一个用于与智融PD芯片进行通信的模拟I2C驱动程序实现。该驱动通过GPIO模拟I2C协议实现了完整的I2C通信功能包括起始信号、停止信号、数据传输和应答检测等核心功能。️ 驱动程序基础函数1. GPIO引脚配置/* SDA引脚输出模式设置 */staticinlinevoidpd_sda_set_out_mode(structpd_i2c_bus_typedef*bus){gpio_init(PD_SDA_GPIO_PORT,GPIO_MODE_OUT_OD,GPIO_OSPEED_50MHZ,PD_SDA_PIN);}/* SDA引脚输入模式设置 */staticinlinevoidpd_sda_set_in_mode(structpd_i2c_bus_typedef*bus){gpio_init(PD_SDA_GPIO_PORT,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_50MHZ,PD_SDA_PIN);}/* 获取SDA引脚状态 */staticinlineuint8_tget_sda(structpd_i2c_bus_typedef*bus){returngpio_input_bit_get(bus-gpiox,bus-sda_gpio_pin);}/* SDA引脚电平控制 */staticinlinevoidPD_SDA_L(structpd_i2c_bus_typedef*bus){gpio_bit_reset(bus-gpiox,bus-sda_gpio_pin);}staticinlinevoidPD_SDA_H(structpd_i2c_bus_typedef*bus){gpio_bit_set(bus-gpiox,bus-sda_gpio_pin);}/* SCL引脚电平控制 */staticinlinevoidPD_SCL_L(structpd_i2c_bus_typedef*bus){gpio_bit_reset(bus-gpiox,bus-scl_gpio_pin);}staticinlinevoidPD_SCL_H(structpd_i2c_bus_typedef*bus){gpio_bit_set(bus-gpiox,bus-scl_gpio_pin);} 起始信号staticinlinevoidpd_i2c_start(structpd_i2c_bus_typedef*bus){pd_sda_set_out_mode(bus);PD_SDA_H(bus);bus-udelay(10);PD_SCL_H(bus);bus-udelay(10);PD_SDA_L(bus);bus-udelay(10);PD_SCL_L(bus);bus-udelay(10);}结束信号staticinlinevoidpd_i2c_stop(structpd_i2c_bus_typedef*bus){bus-udelay(6);PD_SDA_L(bus);bus-udelay(6);PD_SCL_H(bus);bus-udelay(6);PD_SDA_H(bus);bus-udelay(6);PD_SDA_H(bus);pd_sda_set_out_mode(bus);} 重启信号staticinlinevoidpd_i2c_restart(structpd_i2c_bus_typedef*bus){PD_SDA_H(bus);bus-udelay(6);PD_SCL_H(bus);bus-udelay(6);PD_SDA_L(bus);bus-udelay(6);PD_SCL_L(bus);bus-udelay(6);}判断从机回复/** * brief pd_iic 检测响应pd_iic * param struct pd_i2c_bus_typedef *bus * param NONE * retval 返回 0 从机接收成功; 返回1应答失败 */staticinlineuint8_tpd_i2c_check_ack(structpd_i2c_bus_typedef*bus){uint8_tack0;uint16_tpd_chip_timeout0;PD_SDA_H(bus);bus-udelay(5);PD_SCL_H(bus);bus-udelay(5);pd_sda_set_in_mode(bus);while(1get_sda(bus)){pd_chip_timeout;if(pd_chip_timeout250){pd_i2c_stop(pd_i2c_bus);ack1;break;}}pd_sda_set_out_mode(bus);PD_SCL_L(bus);bus-udelay(5);returnack;}发送检测响应/** * brief pd_iic 发送检测响应iic 协议第9位为应答 * param struct pd_i2c_bus_typedef *bus * param ack 需要继续通信拉低0, 不需要继续通信拉高1 * retval */staticinlinevoidpd_i2c_send_ack_Or_nack(structpd_i2c_bus_typedef*bus,intack){//int re_ack 0;PD_SCL_L(bus);bus-udelay(10);if(ack){PD_SDA_L(bus);//继续通信}else{PD_SDA_H(bus);}bus-udelay(10);PD_SCL_H(bus);bus-udelay(10);PD_SCL_L(bus);bus-udelay(10);}写单字节//写单字节staticvoidpd_i2c_write_byte(structpd_i2c_bus_typedef*bus,uint8_tdata){uint8_ti0;uint8_tdat0;uint8_ttemps0;dat0x80;tempsdata;for(i0;i8;i){PD_SCL_L(bus);if(dattemps)//对应位为一就发一{PD_SDA_H(bus);bus-udelay(WR_RD_DELAY_TIME);//延时一下PD_SCL_H(bus);bus-udelay(WR_RD_DELAY_TIME);//t(HIGH) Clock high period See Note 2 4.0~50 μs}else{PD_SDA_L(bus);bus-udelay(WR_RD_DELAY_TIME);//延时一下PD_SCL_H(bus);bus-udelay(WR_RD_DELAY_TIME);}datdat1;}PD_SCL_L(bus);bus-udelay(WR_RD_DELAY_TIME);PD_SDA_H(bus);//数据线拉高为等待响应做准备bus-udelay(WR_RD_DELAY_TIME);}读单字节//读单字节staticuint8_tpd_i2c_read_byte(structpd_i2c_bus_typedef*bus){uint8_tmask;uint8_tdata0;PD_SDA_H(bus);bus-udelay(10);pd_sda_set_in_mode(bus);for(mask0x80;mask!0;mask1){PD_SCL_H(bus);bus-udelay(10);if(get_sda(bus)){data|mask;}PD_SCL_L(bus);bus-udelay(10);}pd_sda_set_out_mode(bus);returndata;}读寄存器intpd_i2c_read_register(uint8_t*pd_data_buff,uint16_taddr,uint16_tlen){uint16_ti0;// uint16_t data 0;uint8_tsda_status0;uint16_tstart_addr0;// uint8_t start_temp 0;start_addraddr;pd_lock();//PD 读pd_i2c_start(pd_i2c_bus);//开始pd_i2c_write_byte(pd_i2c_bus,PD_I2C_WRITE_SLAVE_ADDR);//设备地址 0x3Cpd_i2c_bus.udelay(DLY_TIMER_1);sda_statuspd_i2c_check_ack(pd_i2c_bus);//等待响应if(1sda_status){pd_i2c_stop(pd_i2c_bus);pd_i2c_stop(pd_i2c_bus);pd_unlock();return(-1);}pd_i2c_bus.udelay(DLY_TIMER_1);pd_i2c_write_byte(pd_i2c_bus,(uint8_t)start_addr);//数据地址pd_i2c_bus.udelay(DLY_TIMER_1);sda_statuspd_i2c_check_ack(pd_i2c_bus);//等待响应if(1sda_status){pd_i2c_stop(pd_i2c_bus);pd_i2c_stop(pd_i2c_bus);pd_unlock();return(-1);}pd_i2c_bus.udelay(DLY_TIMER_1);pd_i2c_restart(pd_i2c_bus);//再次启动pd_i2c_write_byte(pd_i2c_bus,PD_I2C_READ_SLAVE_ADDR);//设备地址 0x3Dsda_statuspd_i2c_check_ack(pd_i2c_bus);//等待响应if(1sda_status){pd_i2c_stop(pd_i2c_bus);pd_i2c_stop(pd_i2c_bus);pd_unlock();return(-1);}for(i0;ilen;i){pd_data_buff[i]pd_i2c_read_byte(pd_i2c_bus);//pd_i2c_bus.udelay(DLY_TIMER_2);pd_i2c_send_ack_Or_nack(pd_i2c_bus,ACK_FLAG);}pd_i2c_bus.udelay(DLY_TIMER_1);pd_i2c_stop(pd_i2c_bus);//停止pd_unlock();return0;}写寄存器/** * brief PD 芯片写单字节 * param register PD 芯片写寄存器 * param p_data 数据指针 * retval 异常返回 1,正常返回 0 * note 软件模拟SMBUS协议 */uint8_tpd_i2c_write_register(uint8_t*pd_data_buff,uint16_taddr,uint16_tlen){uint16_ti0;//uint16_t data 0;uint8_tsda_status0;uint16_tstart_addr0;//uint8_t start_temp 0;pd_lock();start_addraddr;//PD 读pd_i2c_start(pd_i2c_bus);//开始pd_i2c_write_byte(pd_i2c_bus,PD_I2C_WRITE_SLAVE_ADDR);//设备地址 0x3Cpd_i2c_bus.udelay(DLY_TIMER_2);sda_statuspd_i2c_check_ack(pd_i2c_bus);//等待响应if(1sda_status){pd_unlock();returnsda_status;}pd_i2c_write_byte(pd_i2c_bus,(uint8_t)start_addr);//数据地址pd_i2c_bus.udelay(DLY_TIMER_2);sda_statuspd_i2c_check_ack(pd_i2c_bus);//等待响应if(1sda_status){pd_unlock();returnsda_status;}pd_i2c_bus.udelay(DLY_TIMER_2);for(i0;ilen;i){pd_i2c_write_byte(pd_i2c_bus,pd_data_buff[i]);pd_i2c_bus.udelay(DLY_TIMER_2);sda_statuspd_i2c_check_ack(pd_i2c_bus);}pd_i2c_stop(pd_i2c_bus);//停止pd_unlock();returnsda_status;} 结束语通过本文的详细讲解我们完成了智融PD芯片I2C通信驱动的完整实现。从GPIO引脚配置到I2C协议的核心时序控制再到读写寄存器的完整流程我们一步步构建了一个高效可靠的模拟I2C驱动。 核心要点回顾GPIO配置正确配置SDA和SCL引脚的输入输出模式是I2C通信的基础时序控制严格按照I2C协议的时序要求实现起始、停止、重启信号应答机制完善的应答检测和发送机制确保通信可靠性读写操作完整的读写寄存器函数封装了底层通信细节 实际应用建议时序调整根据实际硬件特性微调延时参数优化通信速度错误处理在生产环境中增加更完善的错误日志和重试机制性能优化对于频繁的I2C操作可以考虑使用DMA或硬件I2C外设希望本文能为您的嵌入式开发工作提供实用的参考。如果在实际应用中遇到问题欢迎在评论区交流讨论。祝您开发顺利本文代码已在多个实际项目中验证具有良好的稳定性和可靠性。建议在实际使用时根据具体硬件平台进行适当调整。