4. FLEXIO 定时器与移位器:工作原理与配置寄存器详解

FLEXIO 的核心执行单元由 定时器(Timer) 和 移位器(Shifter) 组成。定时器负责产生位时钟、帧同步信号以及控制移位操作的时序;移位器则负责数据的串行发送与接收。理解这两个模块的协同工作原理,是使用 FLEXIO 模拟 UART、SPI、I2C 等协议的基础。

核心概念: 在 FLEXIO 中,定时器是“指挥官”,决定何时移位;移位器是“士兵”,负责数据的进出。一个典型的通信协议(如 UART)通常需要 1 个定时器 + 2 个移位器(一个发送,一个接收)。

4.1 移位器(Shifter)工作原理

移位器本质上是一个可配置的移位寄存器,支持 8、16、24、32 位数据宽度。它可以从 FLEXIO 引脚(SHIFTBUF 与引脚直连)或软件缓冲区(SHIFTBUFBIS/SHIFTBUFBYS)加载数据,并在定时器的触发下逐位移出或移入。

移位器(Shifter)数据流架构 SHIFTBUFBIS SHIFTBUFBYS SHIFTBUF[0..3] 主数据缓冲区 SHIFTREG[0..3] 移位寄存器(核心) FLEXIO 引脚 (D/P) 定时器触发 数据流向: 软件写入 SHIFTBUFBIS/BYS → 硬件自动加载到 SHIFTBUF → 定时器触发后,数据从 SHIFTBUF 载入 SHIFTREG → 按位从引脚输出(发送模式) 接收模式则相反:引脚数据逐位移入 SHIFTREG → 满后自动转入 SHIFTBUF → 触发中断或 DMA。

4.1.1 移位器关键配置寄存器

寄存器名称 偏移地址 位域 功能描述
SHIFTCFG[0..3] 0x00C + n*4 INSRC, PWIDTH, SSTOP, SSTART 配置移位器输入源、数据宽度、停止/起始位逻辑
SHIFTCTL[0..3] 0x020 + n*4 TIMSEL, PINCFG, PIPPOL, PINPOL, SMOD 选择关联定时器、引脚配置、引脚极性、工作模式
SHIFTBUF[0..3] 0x100 + n*4 SHIFTBUF[31:0] 主数据缓冲区,CPU/DMA 读写接口
SHIFTBUFBIS[0..3] 0x120 + n*4 SHIFTBUFBIS[31:0] 按位交换缓冲区(Bit Swapped)
SHIFTBUFBYS[0..3] 0x140 + n*4 SHIFTBUFBYS[31:0] 按字节交换缓冲区(Byte Swapped)
实战要点:
  • SMOD(移位器模式): 配置为 0b001(发送)或 0b010(接收)。UART 全双工需要两个移位器分别配置为发送和接收。
  • PWIDTH(数据宽度): UART 通常配置为 8 位数据(PWIDTH = 7,因为宽度 = PWIDTH + 1)。
  • INSRC(输入源): 接收模式下必须选择引脚输入;发送模式下选择定时器输出或引脚输入(用于环回测试)。

4.2 定时器(Timer)工作原理

定时器是 FLEXIO 的时序核心。它内部包含一个 16 位计数器,可以配置为多种模式,用于产生移位时钟、帧同步信号或 PWM 波形。定时器的工作模式决定了它如何计数、何时复位以及如何与移位器交互。

定时器(Timer)内部结构 时钟源选择 16位计数器 比较器 输出控制逻辑 TIMCMP[15:0] → 移位器时钟 计数过程: 计数器从 0 开始递增,每个时钟源周期加 1。当计数值等于 TIMCMP 时,比较器触发事件: ① 输出引脚电平翻转(取决于 TIMOD 配置);② 计数器复位(取决于 TIMRST 配置);③ 触发关联移位器执行一次移位操作。

4.2.1 定时器工作模式(TIMOD)

定时器的工作模式决定了其计数行为与输出波形。对于 UART 模拟,最常用的是 双 8 位计数器模式(TIMOD=0b001) 和 单 16 位计数器模式(TIMOD=0b000)。

TIMOD[2:0] 模式名称 计数器宽度 典型应用
0b000 单 16 位计数器模式 16 位 产生固定频率的移位时钟(如 SPI 时钟)
0b001 双 8 位计数器模式 高 8 位 + 低 8 位 UART 波特率生成(低 8 位控制位周期,高 8 位控制停止位/帧间隔)
0b010 单 16 位计数器模式(带触发复位) 16 位 需要外部信号同步的时钟生成
0b100 PWM 输出模式 16 位 产生占空比可调的 PWM 波形

4.2.2 定时器关键配置寄存器

寄存器名称 偏移地址 位域 功能描述
TIMCFG[0..3] 0x040 + n*4 TIMRST, TIMDIS, TIMENA, TIMOUT, TIMDEC, TIMOD 配置定时器复位源、禁用源、使能源、输出极性、递减源、工作模式
TIMCTL[0..3] 0x060 + n*4 TIMERSEL, PINCFG, PINPOL, PINSEL 选择定时器触发源、引脚配置、引脚极性、引脚选择
TIMCMP[0..3] 0x080 + n*4 TIMCMP[15:0] 定时器比较值,决定计数周期
UART 波特率配置陷阱:
  • 在双 8 位模式下,TIMCMP[7:0] 控制数据位的长度(波特率分频),TIMCMP[15:8] 控制停止位/帧间隔的长度。
  • 波特率计算公式:波特率 = FLEXIO_CLK / ( (TIMCMP[7:0] + 1) * 2 )。例如,FLEXIO_CLK = 48 MHz,需要 115200 波特率,则 TIMCMP[7:0] = 48e6 / (115200 * 2) - 1 ≈ 207。
  • 停止位长度:停止位时间 = (TIMCMP[15:8] + 1) * 位时间。通常配置为 1 位停止位,即 TIMCMP[15:8] = 0。

4.3 定时器与移位器的协同工作

定时器和移位器通过内部硬件信号线直接连接,无需 CPU 干预。定时器每产生一个移位时钟脉冲,就会触发关联的移位器执行一次移位操作。这种硬件握手机制保证了高速数据传输的确定性。

定时器与移位器协同时序(UART 发送 1 字节) 移位时钟 (Timer Out) 移位数据 (Shifter Out) 起始位 (0) D0 D1 D2 D3 D4 D5 D6 STOP 协同流程: 1. 定时器配置为双 8 位模式,TIMCMP[7:0] 决定每个数据位的长度(时钟周期数)。 2. 每个时钟脉冲的上升沿,移位器将 SHIFTREG 中的最低位移出到引脚,同时 SHIFTREG 右移一位。 3. 8 个时钟脉冲后,移位器完成一个字节的发送,定时器自动插入停止位(高电平),然后等待下一个帧触发。

4.3.1 配置步骤总结

  1. 使能 FLEXIO 模块时钟:在 PCC 寄存器中配置 FLEXIO 时钟源和分频。
  2. 配置引脚功能:将 FLEXIO 引脚设置为 ALT9 功能,并配置为输出(发送)或输入(接收)。
  3. 配置移位器(发送):
    • SHIFTCTL.SMOD = 0b001(发送模式)
    • SHIFTCTL.PINCFG = 0b00(引脚输出)
    • SHIFTCFG.PWIDTH = 7(8 位数据)
    • SHIFTCFG.INSRC = 0(发送模式选择定时器输出)
  4. 配置移位器(接收):
    • SHIFTCTL.SMOD = 0b010(接收模式)
    • SHIFTCTL.PINCFG = 0b01(引脚输入)
    • SHIFTCFG.PWIDTH = 7(8 位数据)
    • SHIFTCFG.INSRC = 1(接收模式选择引脚输入)
  5. 配置定时器:
    • TIMCFG.TIMOD = 0b001(双 8 位模式)
    • TIMCMP = (stop_bits << 8) | baud_rate_div(设置波特率和停止位)
    • TIMCTL.TIMERSEL 选择触发源(通常选择引脚或软件触发)
  6. 使能 FLEXIO 模块:设置 FLEXIO_CTRL.FLEXEN = 1。
  7. 启动发送:向 SHIFTBUF 写入待发送数据,定时器自动开始工作。
代码示例:定时器与移位器初始化(伪代码)
// 假设使用 FLEXIO0,定时器 0,移位器 0(发送),移位器 1(接收)
// 波特率 115200,FLEXIO_CLK = 48 MHz

// 1. 使能时钟
PCC->PCCn[PCC_FLEXIO0_INDEX] |= PCC_PCCn_CGC_MASK;

// 2. 配置移位器 0(发送)
FLEXIO0->SHIFTCFG[0] = FLEXIO_SHIFTCFG_PWIDTH(7);   // 8 位数据
FLEXIO0->SHIFTCTL[0] = FLEXIO_SHIFTCTL_SMOD(1)      // 发送模式
                      | FLEXIO_SHIFTCTL_PINCFG(0)    // 引脚输出
                      | FLEXIO_SHIFTCTL_TIMSEL(0);   // 关联定时器 0

// 3. 配置移位器 1(接收)
FLEXIO0->SHIFTCFG[1] = FLEXIO_SHIFTCFG_PWIDTH(7)    // 8 位数据
                      | FLEXIO_SHIFTCFG_INSRC(1);    // 引脚输入
FLEXIO0->SHIFTCTL[1] = FLEXIO_SHIFTCTL_SMOD(2)      // 接收模式
                      | FLEXIO_SHIFTCTL_PINCFG(1)    // 引脚输入
                      | FLEXIO_SHIFTCTL_TIMSEL(0);   // 关联定时器 0

// 4. 配置定时器 0(双 8 位模式)
uint16_t baud_div = (48000000 / (115200 * 2)) - 1;  // ≈ 207
uint16_t stop_len = 0;                               // 1 位停止位
FLEXIO0->TIMCMP[0] = (stop_len << 8) | baud_div;
FLEXIO0->TIMCFG[0] = FLEXIO_TIMCFG_TIMOD(1)         // 双 8 位模式
                    | FLEXIO_TIMCFG_TIMRST(0)        // 定时器复位源:从不复位
                    | FLEXIO_TIMCFG_TIMDIS(2)        // 禁用源:比较器匹配时禁用
                    | FLEXIO_TIMCFG_TIMENA(2);       // 使能源:触发引脚上升沿
FLEXIO0->TIMCTL[0] = FLEXIO_TIMCTL_PINCFG(3)        // 引脚双向输出
                    | FLEXIO_TIMCTL_PINSEL(3);       // 使用 FLEXIO0_D3 作为定时器输出

// 5. 使能 FLEXIO
FLEXIO0->CTRL |= FLEXIO_CTRL_FLEXEN_MASK;

4.4 本章小结

  • 移位器 负责数据的串行化与反串行化,通过 SHIFTCFG 和 SHIFTCTL 配置数据宽度、模式与引脚。
  • 定时器 负责产生移位时钟与帧同步,通过 TIMCFG、TIMCTL 和 TIMCMP 配置工作模式、波特率与停止位。
  • 双 8 位模式 是模拟 UART 的关键,低 8 位控制位周期,高 8 位控制帧间隔。
  • 定时器与移位器通过内部硬件信号线直接耦合,无需 CPU 逐位干预,可实现高达数 Mbps 的通信速率。