基于S32K144的FlexIO模拟I2C通信代码实现

一、核心配置流程

  1. FlexIO模块初始化

  2. 引脚功能映射(SDA/SCL)

  3. 定时器与移位器配置

  4. I2C协议时序生成

  5. 中断/轮询模式实现


二、完整代码实现

#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) {
        // 主循环处理
    }
}

三、关键配置说明

  1. 时钟配置

    // 设置FlexIO时钟源为系统时钟(假设系统时钟为60MHz)
    SIM->SOPT2 |= SIM_SOPT2_FLEXIOSRC(1);
    
  2. 定时器参数计算

    // I2C时钟频率计算公式:
    // FlexIO时钟频率 = 系统时钟 / (预分频因子 + 1)
    // 示例:系统时钟60MHz,预分频19 → 3.125MHz → 100kHz I2C
    FLEXIO_SetupTimer(FLEXIO0, 0, kFLEXIO_TimerMode_I2cMaster,
                      kFLEXIO_TimerSource_InternalClk, 3125000);
    
  3. 中断处理优化

    // 在启动文件中添加中断向量
    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中断优先级配置

六、扩展应用场景

  1. EEPROM读写

    // AT24C256写入示例
    uint8_t addr = 0x50 << 1;
    FlexIO_I2C_Write(addr, (uint8_t*)0x0000, 256);
    
  2. 传感器通信

    // BME280配置
    uint8_t config[] = {0xF4, 0x27}; // 0x27=OSR=16x, Filter=1x
    FlexIO_I2C_Write(0x76 << 1, config, 2);
    
posted @ 2026-02-05 10:56  小前端攻城狮  阅读(5)  评论(0)    收藏  举报