NXP RT1021 FlexIO应用笔记:主机篇

以下内容为工作应用中的小笔记,有利于自己将来使用,也提供给有需要的人参考。
主要讲述的是FlexIO在串行数据收发上的应用。
本笔记基于官方SDK,https://mcuxpresso.nxp.com/zh/welcome
其中的 fsl_flexio.c fsl_flexio.h的结构体和函数进行初始化

初始化用到的两个结构体(结构体内容说明请参考fsl_flexio.h)
flexio_shifter_config_t 数据线配置结构体
flexio_timer_config_t 时钟线配置结构体
初始化用到的两个函数(结构体内容说明请参考fsl_flexio.c)
数据线配置函数:

void FLEXIO_SetShifterConfig(FLEXIO_Type *base, uint8_t index, const flexio_shifter_config_t *shifterConfig)

时钟线备注函数:

void FLEXIO_SetTimerConfig(FLEXIO_Type *base, uint8_t index, const flexio_timer_config_t *timerConfig)
	/* Enable FlexIO */
	CLOCK_EnableClock(s_flexioClocks[FLEXIO_GetInstance(FLEXIO1)]);//使能FlexIO时钟 必须先使能,否则后面操作无法正常进行
	
	uint32_t ctrlReg = FLEXIO1->CTRL;
	ctrlReg &= ~(FLEXIO_CTRL_DOZEN_MASK | FLEXIO_CTRL_DBGE_MASK | FLEXIO_CTRL_FASTACC_MASK | FLEXIO_CTRL_FLEXEN_MASK);
	ctrlReg |= (FLEXIO_CTRL_DBGE(true) | FLEXIO_CTRL_FASTACC(false) |
                FLEXIO_CTRL_FLEXEN(true) | FLEXIO_CTRL_DOZEN_MASK);
	FLEXIO1->CTRL = ctrlReg;//初始化FlexIO的状态 可以不进行初始化
	shifterConfig.timerSelect	=	0U;										//选中时钟计数器(0-3)时钟源
	shifterConfig.timerPolarity	=	kFLEXIO_ShifterTimerPolarityOnNegitive;	//时钟极性(在时钟的 上升沿/*下降沿 进行写入读取)
	
	shifterConfig.pinConfig	=	kFLEXIO_PinConfigOutput; 					//FlexIO 类型(禁止输出/开漏输出/双向输出/*推挽输出)
	shifterConfig.pinSelect	=	TX_PIN; 									//FlexIO 位号(0-31)
	shifterConfig.pinPolarity	=	kFLEXIO_PinActiveHigh; 					//FlexIO 极性(*正极性/负极性)
	
	shifterConfig.shifterMode	=	kFLEXIO_ShifterModeTransmit;				//定义位移器工作模式(禁用/接收/*发送/匹配存储/匹配连续)
	shifterConfig.parallelWidth	=	0;										//并行模式带宽
	shifterConfig.inputSource	=	kFLEXIO_ShifterInputFromPin;			//选择移位器的输入源 (*从引脚输入/从移位器输入)
	shifterConfig.shifterStop	=	kFLEXIO_ShifterStopBitDisable;			//移位器停止条件(*禁用/逻辑低电平/逻辑高电平)
	shifterConfig.shifterStart	=	kFLEXIO_ShifterStartBitDisabledLoadDataOnEnable;//移位器开始条件(*禁用移位器启动位,发送器在启动时加载数据/禁用移位器启动位,发射机在第一次移位时加载数据/逻辑低电平/逻辑高电平)
	FLEXIO_SetShifterConfig(FLEXIO1, 0U, &shifterConfig);//index (0-3)数据移位器源

以上初始化了一根发送数据线,在时钟的下降沿改变数据(PS:数据长度由时钟决定)

	shifterConfig.timerSelect	=	0U;										//选中时钟计数器(0-3)时钟源
	shifterConfig.timerPolarity	=	kFLEXIO_ShifterTimerPolarityOnPositive;	//时钟极性(在时钟的 *上升沿/下降沿 进行写入读取)
	
	shifterConfig.pinConfig	=	kFLEXIO_PinConfigOutputDisabled; 			//FlexIO 类型(禁止输出/开漏输出/*双向输出/推挽输出)
	shifterConfig.pinSelect	=	RX_PIN; 									//FlexIO 位号(0-31)
	shifterConfig.pinPolarity	=	kFLEXIO_PinActiveHigh; 					//FlexIO 极性(*正极性/负极性)
	
	shifterConfig.shifterMode	=	kFLEXIO_ShifterModeReceive;				//定义位移器工作模式(禁用/*接收/发送/匹配存储/匹配连续)
	shifterConfig.parallelWidth	=	0;										//并行模式带宽
	shifterConfig.inputSource	=	kFLEXIO_ShifterInputFromPin;			//选择移位器的输入源 (*从引脚输入/从移位器输入)
	shifterConfig.shifterStop	=	kFLEXIO_ShifterStopBitDisable;			//移位器停止条件(*禁用/逻辑低电平/逻辑高电平)
	shifterConfig.shifterStart	=	kFLEXIO_ShifterStartBitDisabledLoadDataOnEnable;//移位器开始条件(*禁用移位器启动位,发送器在启动时加载数据/禁用移位器启动位,发射机在第一次移位时加载数据/逻辑低电平/逻辑高电平)
	FLEXIO_SetShifterConfig(FLEXIO1, 0U, &shifterConfig);//index (0-3)数据移位器源

以上初始化了一根接收数据线,在时钟的下降沿读取数据(PS:在时钟上升沿改变数据在下降沿读取数据,所以发送线和接收线时钟极性刚好相反)

	timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(0U);//触发源选择,即满足触发条件定时器开始工作(Pin/*移位寄存器/定时器)
	timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveLow;	//触发极性(高/*低)
	timerConfig.triggerSource = kFLEXIO_TimerTriggerSourceInternal;			//触发源 (*内部/外部)
	
	timerConfig.pinConfig = kFLEXIO_PinConfigOutput; 						//FlexIO 类型(禁止输出/开漏输出/双向输出/*推挽输出)
	timerConfig.pinSelect = SCK_PIN; 										//FlexIO 位号(0-31)
	timerConfig.pinPolarity = kFLEXIO_PinActiveHigh; 						//FlexIO 极性(*正极性/负极性)
	
	timerConfig.timerMode = kFLEXIO_TimerModeDual8BitBaudBit;					//定时器工作模式(禁用/*双8位波特模式/双八位PWM模式/单16位模式)
	timerConfig.timerOutput = kFLEXIO_TimerOutputZeroNotAffectedByReset;	//定时器初始状态(逻辑1,并且不受计时器重置的影响/*逻辑0,并且不受计时器重置的影响/在启动和重置时为逻辑1/在启动和重置时为逻辑0)
	timerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput;//配置定时器递减源(*FlexIO时钟,移位时钟等于计时器输出/触发输入,移位时钟等于计时器输出/Pin输入,移位时钟等于管脚输入/触发输入,移位时钟等于触发器输入)
	timerConfig.timerReset = kFLEXIO_TimerResetNever;						//定时器复位条件(*禁用/定时器引脚等于定时器输出时/定时器触发器等于定时器输出时/定时器Pin上升沿/触发源上升沿/触发上升或下降缘)
	timerConfig.timerDisable = kFLEXIO_TimerDisableOnTimerCompare;			//定时器失能条件(禁用/定时器N-1禁用/*定时器比较匹配/定时器比较匹配和触发低/Pin上升或下降沿/触发高且Pin上升或下降缘/触发下降沿)
	timerConfig.timerEnable = kFLEXIO_TimerEnableOnTriggerHigh;				//定时器使能条件(始终启动/定时器N-1启动/*触发高/触发高且Pin高/Pin上升沿/Pin上升沿并触发高/触发上升沿/触发上升或下降缘)
	timerConfig.timerStop = kFLEXIO_TimerStopBitEnableOnTimerDisable;		//定时器停止位生成(禁用/定时器比较匹配时/*定时器失能时/定时器比较匹配或失能时)
	timerConfig.timerStart = kFLEXIO_TimerStartBitEnabled;					//定时器开始位生成(禁用/*启用)
	uint16_t timerDiv = 0;
	timerDiv = srcClock_Hz / baudRate_Bps;				//srcClock_Hz:FlexIO频率  baudRate_Bps:定时器波特率
    timerDiv = timerDiv / 2 - 1;						//时钟翻转两次为一个周期 
    uint16_t timerCmp = 0;
    timerCmp = ((uint32_t)(dataMode * 2 - 1U)) << 8U;	//dataMode:数据长度
    timerCmp |= timerDiv;								//高8位和低8位合并
	timerConfig.timerCompare = timerCmp ;				//两个定时器嵌套工作 
	//类似:
	//for(timerCmp=0;timerCmp<(dataMode*2-1);dataMode++){
	//	while(timerDiv++<(srcClock_Hz/baudRate_Bps/2-1));
	//	timerDiv=0;
	//	SCK_PIN=~SCK_PIN;
	//}
	FLEXIO_SetTimerConfig(FLEXIO1, 0U, &timerConfig);//index(0-3)定时器源

以上初始化了一根时钟线,在移位寄存器装载数据时启动,比特率为baudRate_Bps,数据长度为dataMode

timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_TIMn(0U);//触发源选择,即满足触发条件定时器开始工作(Pin/移位寄存器/*定时器)
	timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveHigh;	//触发极性(*高/低)
	timerConfig.triggerSource = kFLEXIO_TimerTriggerSourceInternal;			//触发源 (*内部/外部)
	
	timerConfig.pinConfig = kFLEXIO_PinConfigOutput; 						//FlexIO 类型(禁止输出/开漏输出/双向输出/*推挽输出)
	timerConfig.pinSelect = START_PIN; 										//FlexIO 位号(0-31)
	timerConfig.pinPolarity = kFLEXIO_PinActiveHigh; 						//FlexIO 极性(*正极性/负极性)
	
	timerConfig.timerMode = kFLEXIO_TimerModeSingle16Bit;					//定时器工作模式(禁用/双8位波特模式/双八位PWM模式/*单16位模式)
	timerConfig.timerOutput = kFLEXIO_TimerOutputOneNotAffectedByReset;		//定时器初始状态(*逻辑1,并且不受计时器重置的影响/逻辑0,并且不受计时器重置的影响/在启动和重置时为逻辑1/在启动和重置时为逻辑0)
	timerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput;//配置定时器递减源(*FlexIO时钟,移位时钟等于计时器输出/触发输入,移位时钟等于计时器输出/Pin输入,移位时钟等于管脚输入/触发输入,移位时钟等于触发器输入)
	timerConfig.timerReset = kFLEXIO_TimerResetNever;						//定时器复位条件(*禁用/定时器引脚等于定时器输出时/定时器触发器等于定时器输出时/定时器Pin上升沿/触发源上升沿/触发上升或下降缘)
	timerConfig.timerDisable = kFLEXIO_TimerDisableOnPreTimerDisable;		//定时器失能条件(禁用/*定时器N-1禁用/定时器比较匹配/定时器比较匹配和触发低/Pin上升或下降沿/触发高且Pin上升或下降缘/触发下降沿)
	timerConfig.timerEnable = kFLEXIO_TimerEnableOnPrevTimerEnable;			//定时器使能条件(始终启动/*定时器N-1启动/触发高/触发高且Pin高/Pin上升沿/Pin上升沿并触发高/触发上升沿/触发上升或下降缘)
	timerConfig.timerStop = kFLEXIO_TimerStopBitDisabled;					//定时器停止位生成(*禁用/定时器比较匹配时/定时器失能时/定时器比较匹配或失能时)
	timerConfig.timerStart = kFLEXIO_TimerStartBitDisabled;					//定时器开始位生成(*禁用/启用)
	timerConfig.timerCompare = dataMode * 2 - 1U;							//只输出1个周期的波
	FLEXIO_SetTimerConfig(FLEXIO1, 0U, &timerConfig);//index(0-3)定时器源

以上初始化了一根时钟线,在定时器0启动时启动,数据为1个周期,用于给从机判断数据开始

开始发送数据只要在FLEXIO1->SHIFTBUFBBS[0]=Data;把数据装载到寄存器中。
判断完成while(!(FLEXIO_GetShifterStatusFlags(FLEXIO1)&0x01u));//0x01u为对应定时器0=0x01 1=0x02 2=0x04 3=0x08
函数原型:

static inline uint32_t FLEXIO_GetShifterStatusFlags(FLEXIO_Type *base)
{
    return ((base->SHIFTSTAT) & FLEXIO_SHIFTSTAT_SSF_MASK);
}

有7个移位器缓冲区寄存器

__IO uint32_t SHIFTBUF[8];
__IO uint32_t SHIFTBUFBIS[8];
__IO uint32_t SHIFTBUFBYS[8];
__IO uint32_t SHIFTBUFBBS[8];
__IO uint32_t SHIFTBUFNBS[8];
__IO uint32_t SHIFTBUFHWS[8];
__IO uint32_t SHIFTBUFNIS[8];

其中关如下:

INPUT       0x87654321‭ 1000 0111 0110 0101 0100 0011 0010 0001‬
SHIFTBUF    0x84C2A6E1 1000 0100 1100 0010 1010 0110 1110 0001‬
SHIFTBUFBIS 0x87654321 1000 0111 0110 0101 0100 0011 0010 0001‬
SHIFTBUFBYS 0xE1A6C284 1110 0001 1010 0110 1100 0010 1000 0100‬
SHIFTBUFBBS 0x21436587 0010 0001 0100 0011 0110 0101 1000 0111‬
SHIFTBUFNBS 0x482C6A1E 0100 1000 0010 1100 0110 1010 0001 1110‬
SHIFTBUFHWS 0xA6E184C2‭ 1010 0110 1110 0001 1000 0100 1100 0010‬
SHIFTBUFNIS 0x1E6A2C48 0001 1110 0110 1010 0010 1100 0100 1000‬

以上为一个四线协议
分别是
START_PIN:用于发送数据开始位
SCK_PIN:用于同步时钟
TX_PIN:发送数据,在时钟下降沿发送
RX_PIN:接收数据,在时钟上升沿读取
dataMode =8时,输出波形为

START ────┐     ┌─────────────────────────────────────────┐     ┌──
     	  └─────┘                                         └─────┘
SCK	┌──┐  ┌──┐  ┌──┐  ┌──┐  ┌──┐  ┌──┐  ┌──┐  ┌──┐  ┌──┐  ┌──┐  ┌──
  ──┘07└──┘00└──┘01└──┘02└──┘03└──┘04└──┘05└──┘06└──┘07└──┘00└──┘01
TX  ┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬──
    W─────W─────W─────W─────W─────W─────W─────W─────W─────W─────W──
RX  ───┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────
    ───R─────R─────R─────R─────R─────R─────R─────R─────R─────R─────

以上。

  • 5
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值