FreeRTOS任务切换导致SPI(FLASH)读写错误问题解决记录--转载

FreeRTOS任务切换导致SPI(FLASH)读写错误问题解决记录--转载

情景

在一个任务里面,使用 for 或者 while 循环调用 SPI 操作[读写] FLASH(W25Q128),但是该循环操作未超过看门狗复位时间。

问题

FreeRTOS系统重启(看门狗),调试发现在任务切换函数和SPI读写函数循环。

	{
		if( ( xTicksToWait == portMAX_DELAY ) && ( xCanBlockIndefinitely != pdFALSE ) )
		{
			/* Add the task to the suspended task list instead of a delayed task
			list to ensure it is not woken by a timing event.  It will block
			indefinitely. */
			vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xStateListItem ) );
		}
		else
		{
			/* Calculate the time at which the task should be woken if the event
			does not occur.  This may overflow but this doesn't matter, the
			kernel will manage it correctly. */
			xTimeToWake = xConstTickCount + xTicksToWait;
 
			/* The list item will be inserted in wake time order. */
			listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake );
 
			if( xTimeToWake < xConstTickCount )
			{
				/* Wake time has overflowed.  Place this item in the overflow
				list. */
				vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
			}
			else
			{
				/* The wake time has not overflowed, so the current block list
				is used. */
				vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
 
				/* If the task entering the blocked state was placed at the
				head of the list of blocked tasks then xNextTaskUnblockTime
				needs to be updated too. */
				if( xTimeToWake < xNextTaskUnblockTime )
				{
					xNextTaskUnblockTime = xTimeToWake;
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}
			}
		}
	}
uint8_t SPI_ReadWriteByte(SPI_TypeDef* SPIx,uint8_t TxData)
{		
	uint8_t RxData = 0;
 
	while(SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET);	//等待发送缓冲区空 
	SPI_I2S_SendData(SPIx, TxData);			//发送一个字节
 
    while(SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_RXNE) == RESET);	//等待数据接收完成
	RxData = SPI_I2S_ReceiveData(SPIx);		//返回接收到的数据
 
    return (uint8_t)RxData;			
}

原因

思考原因,可能是任务切换导致SPI读写错误。

解决

开关任务级临界段,在SPI操作时阻止任务调度。

uint8_t SPI_ReadWriteByte(SPI_TypeDef* SPIx,uint8_t TxData)
{		
	uint8_t RxData = 0;
	
    taskENTER_CRITICAL();	
	
	while(SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET);	//等待发送缓冲区空 
	SPI_I2S_SendData(SPIx, TxData);			//发送一个字节
 
    while(SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_RXNE) == RESET);	//等待数据接收完成
	RxData = SPI_I2S_ReceiveData(SPIx);		//返回接收到的数据
	
    taskEXIT_CRITICAL();	
    return (uint8_t)RxData;		
}

后面发现使用以上方法后不会再卡死循环了,但是读取数据会出现全FF的情况,于是把临界段放在整体读写FLASH的函数。就没在出现读取错误的情况。

void W25QXX_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
{	
	taskENTER_CRITICAL();		//进入临界区
	/*
    具体写入操作
    */
	taskEXIT_CRITICAL();
}
 
 
void W25QXX_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead)   
{
	taskENTER_CRITICAL();		//进入临界区
	/*
    具体读取操作
    */
	taskEXIT_CRITICAL();
}

或者使用调度锁:

void W25QXX_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
{	
	vTaskSuspendAll(); /* 开启调度锁 */	
	/*
    具体写入操作
    */
	xTaskResumeAll (); /* 关闭调度锁 */
}
 
 
void W25QXX_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead)   
{
	vTaskSuspendAll(); /* 开启调度锁 */	
	/*
    具体读取操作
    */
	xTaskResumeAll (); /* 关闭调度锁 */
}

原文链接:
https://blog.csdn.net/p1279030826/article/details/109741257

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值