基于S32K144的FlexIO模拟I2C通信代码实现
一、核心配置流程
-
FlexIO模块初始化
-
引脚功能映射(SDA/SCL)
-
定时器与移位器配置
-
I2C协议时序生成
-
中断/轮询模式实现
二、完整代码实现
#include "s32k144.h"
#include "flexio_i2c.h"
/* 定义硬件参数 */
#define I2C_CLOCK_FREQ 100000 // 100kHz
#define SDA_PIN 24 // PTA24 (FlexIO0_SDA)
#define SCL_PIN 25 // PTA25 (FlexIO0_SCL)
#define BUFFER_SIZE 16
/* FlexIO句柄结构体 */
typedef struct {
FLEXIO_Type *base;
flexio_shifter_config_t shifterCfg[2];
flexio_timer_config_t timerCfg[2];
} flexio_i2c_handle_t;
/* 全局变量 */
flexio_i2c_handle_t flexioI2cHandle;
uint8_t txBuffer[BUFFER_SIZE] = "Hello I2C";
uint8_t rxBuffer[BUFFER_SIZE];
/* 中断服务例程 */
void FLEXIO_IRQHandler(void) {
FLEXIO_ClearStatusFlags(FLEXIO0, kFLEXIO_ShiftIntFlag0 | kFLEXIO_ShiftIntFlag1);
// 在此添加数据接收完成处理逻辑
}
/* FlexIO I2C初始化 */
void FlexIO_I2C_Init(void) {
flexio_config_t flexioConfig;
// 1. 初始化FlexIO模块
FLEXIO_GetDefaultConfig(&flexioConfig);
flexioConfig.enableHighSpeed = false;
flexioConfig.enableRunInDebug = false;
FLEXIO_Init(FLEXIO0, &flexioConfig);
// 2. 配置引脚映射
FLEXIO_SetPinMux(FLEXIO0, kFLEXIO_PinMux_ShiftBuf0, kFLEXIO_PinAlt0, SDA_PIN);
FLEXIO_SetPinMux(FLEXIO0, kFLEXIO_PinMux_ShiftBuf1, kFLEXIO_PinAlt0, SCL_PIN);
// 3. 配置定时器0(时钟生成)
FLEXIO_SetupTimer(FLEXIO0, 0, kFLEXIO_TimerMode_I2cMaster,
kFLEXIO_TimerSource_InternalClk, I2C_CLOCK_FREQ);
// 4. 配置移位器0(发送)
FLEXIO_SetupShifter(FLEXIO0, 0, kFLEXIO_ShifterMode_Transmit,
kFLEXIO_ShifterDir_Output, kFLEXIO_PinPolarity_ActiveHigh);
// 5. 配置移位器1(接收)
FLEXIO_SetupShifter(FLEXIO0, 1, kFLEXIO_ShifterMode_Receive,
kFLEXIO_ShifterDir_Input, kFLEXIO_PinPolarity_ActiveHigh);
// 6. 启用中断
FLEXIO_EnableInterrupts(FLEXIO0, kFLEXIO_ShiftIntEnable0 | kFLEXIO_ShiftIntEnable1);
EnableIRQ(FLEXIO_IRQn);
}
/* I2C写操作 */
status_t FlexIO_I2C_Write(uint8_t devAddr, uint8_t *data, uint32_t size) {
flexio_transfer_t xfer;
xfer.data = data;
xfer.dataSize = size;
xfer.flags = kFLEXIO_TransferDefaultFlag;
return FLEXIO_TransferNonBlocking(FLEXIO0, &xfer);
}
/* I2C读操作 */
status_t FlexIO_I2C_Read(uint8_t devAddr, uint8_t *data, uint32_t size) {
flexio_transfer_t xfer;
xfer.data = data;
xfer.dataSize = size;
xfer.flags = kFLEXIO_TransferReadFlag;
return FLEXIO_TransferNonBlocking(FLEXIO0, &xfer);
}
/* 主函数示例 */
int main(void) {
BOARD_InitBootClocks();
BOARD_InitDebugConsole();
FlexIO_I2C_Init();
// 写入数据到从设备
FlexIO_I2C_Write(0x50 << 1, txBuffer, BUFFER_SIZE);
while(1) {
// 主循环处理
}
}
三、关键配置说明
-
时钟配置
// 设置FlexIO时钟源为系统时钟(假设系统时钟为60MHz) SIM->SOPT2 |= SIM_SOPT2_FLEXIOSRC(1); -
定时器参数计算
// I2C时钟频率计算公式: // FlexIO时钟频率 = 系统时钟 / (预分频因子 + 1) // 示例:系统时钟60MHz,预分频19 → 3.125MHz → 100kHz I2C FLEXIO_SetupTimer(FLEXIO0, 0, kFLEXIO_TimerMode_I2cMaster, kFLEXIO_TimerSource_InternalClk, 3125000); -
中断处理优化
// 在启动文件中添加中断向量 void FLEXIO_IRQHandler(void) { if (FLEXIO_GetStatusFlags(FLEXIO0) & kFLEXIO_ShiftIntFlag0) { // 处理发送完成事件 } if (FLEXIO_GetStatusFlags(FLEXIO0) & kFLEXIO_ShiftIntFlag1) { // 处理接收完成事件 } }
四、协议时序验证
通过逻辑分析仪观察关键信号:
SCL: 高→低→高(起始条件)
SDA: 高→低(数据位传输)
SCL: 低→高(时钟上升沿采样)
参考代码 S32K144 配置FLEXIO 模拟I2C通信代码 www.youwenfan.com/contentcnq/69652.html
五、常见问题解决
| 问题现象 | 解决方案 |
|---|---|
| 通信失败(NACK) | 检查从设备地址(7位左移1位) |
| 数据错误 | 验证时钟频率匹配(±5%容差) |
| 总线冲突 | 添加总线仲裁逻辑 |
| 中断未触发 | 检查NVIC中断优先级配置 |
六、扩展应用场景
-
EEPROM读写
// AT24C256写入示例 uint8_t addr = 0x50 << 1; FlexIO_I2C_Write(addr, (uint8_t*)0x0000, 256); -
传感器通信
// BME280配置 uint8_t config[] = {0xF4, 0x27}; // 0x27=OSR=16x, Filter=1x FlexIO_I2C_Write(0x76 << 1, config, 2);
浙公网安备 33010602011771号