在i.MX上有很多Flex的外设,他们都非常的Flexable,其中最为变态的应该是FlexIO,因为他什么协议都能做,发生个I2C,SPI,PWM,8080刷屏当然很轻松,驱动WS2812之类的也不在话下.
- 具有发送,接收和数据匹配模式的32位移位寄存器阵列
- 双缓冲区实现连续数据传输
- 支持大量数据传输
- 自动启动/停止位生成
- 支持并行或1,2,4,8,16,32位串行操作
- 中断,DMA或轮询收发操作
- 独立时钟,STOP模式下依然可以工作
- 高度灵活的16位定时器,支持各种触发
- 可编程状态机,8状态8输出3输入
如果之前接触过NXP家族的SGPIO,会发现,这是多么惊人的相似.
实际上,FlexIO是配置两个函数,一个是时基,一个是特定时刻需要发生的事情.
FLEXIO_SetShifterConfig和FLEXIO_SetTimerConfig 函数,对应两个关键结构体flexio_shifter_config_t和flexio_timer_config_t.
/*! @brief Define FlexIO timer configuration structure. */ typedef struct _flexio_timer_config { /* Trigger. */ uint32_t triggerSelect; //触发源选择,即满足触发条件定时器开始工作(Pin/移位寄存器/定时器) flexio_timer_trigger_polarity_t triggerPolarity; //触发极性(高/低) flexio_timer_trigger_source_t triggerSource; //触发源 (内部/外部) /* Pin. */ flexio_pin_config_t pinConfig; //FlexIO 类型(禁止输出/开漏输出/双向输出/推挽输出) uint32_t pinSelect; //FlexIO 位号(0-31) flexio_pin_polarity_t pinPolarity; //FlexIO 极性(*正极性/负极性) /* Timer. */ flexio_timer_mode_t timerMode; //定时器工作模式(禁用/双8位波特模式/双八位PWM模式/单16位模式) flexio_timer_output_t timerOutput; //定时器初始状态(逻辑1,并且不受计时器重置的影响/逻辑0,并且不受计时器重置的影响/在启动和重置时为逻辑1/在启动和重置时为逻辑0) flexio_timer_decrement_source_t timerDecrement; //配置定时器递减源(FlexIO时钟,移位时钟等于计时器输出/触发输入,移位时钟等于计时器输出/Pin输入,移位时钟等于管脚输入/触发输入,移位时钟等于触发器输入) flexio_timer_reset_condition_t timerReset; //定时器复位条件(禁用/定时器引脚等于定时器输出时/定时器触发器等于定时器输出时/定时器Pin上升沿/触发源上升沿/触发上升或下降缘) flexio_timer_disable_condition_t timerDisable; //定时器失能条件(禁用/定时器N-1禁用/定时器比较匹配/定时器比较匹配和触发低/Pin上升或下降沿/触发高且Pin上升或下降缘/触发下降沿) flexio_timer_enable_condition_t timerEnable; //定时器使能条件(始终启动/定时器N-1启动/触发高/触发高且Pin高/Pin上升沿/Pin上升沿并触发高/触发上升沿/触发上升或下降缘) flexio_timer_stop_bit_condition_t timerStop; //定时器停止位生成(禁用/定时器比较匹配时/定时器失能时/定时器比较匹配或失能时) flexio_timer_start_bit_condition_t timerStart; //定时器开始位生成(禁用/启用) uint32_t timerCompare; //定时器比较器源(N) } flexio_timer_config_t; /*! @brief Define FlexIO shifter configuration structure. */ typedef struct _flexio_shifter_config { /* Timer. */ uint32_t timerSelect; //选中时钟计数器(0-3)时钟源 flexio_shifter_timer_polarity_t timerPolarity; //时钟极性(在时钟的 低电平/高电平 进行写入读取) /* Pin. */ flexio_pin_config_t pinConfig; //FlexIO 类型(禁止输出/开漏输出/双向输出/推挽输出) uint32_t pinSelect; //FlexIO 位号(0-31) flexio_pin_polarity_t pinPolarity; //FlexIO 极性(*正极性/负极性) /* Shifter. */ flexio_shifter_mode_t shifterMode; //定义位移器工作模式(禁用/接收/发送/匹配存储/匹配连续) #if FSL_FEATURE_FLEXIO_HAS_PARALLEL_WIDTH uint32_t parallelWidth; //并行模式带宽 #endif /* FSL_FEATURE_FLEXIO_HAS_PARALLEL_WIDTH */ flexio_shifter_input_source_t inputSource; //选择移位器的输入源 (从引脚输入/从移位器输入) flexio_shifter_stop_bit_t shifterStop; //移位器停止条件(禁用/逻辑低电平/逻辑高电平) flexio_shifter_start_bit_t shifterStart; //移位器开始条件(禁用移位器启动位,发送器在启动时加载数据/禁用移位器启动位,发射机在第一次移位时加载数据/逻辑低电平/逻辑高电平) } flexio_shifter_config_t;
不过,如果要使用FlexIO实现标准协议,不需要记得上面的配置,因为fsl_flex_*.c提供了很多配置代码.
从这里已经可以扩展很多,比如说WS2812可以理解成是特殊波特率的SPI,PWM可以理解成FlexIO定时器比较输出,归零重置.