硬汉嵌入式论坛

 找回密码
 立即注册
查看: 459|回复: 10
收起左侧

[SPI/QSPI] SPI双机通信从机偶尔接收错误,如何从新复位SPI接收

[复制链接]

44

主题

562

回帖

699

积分

金牌会员

积分
699
发表于 2023-10-27 10:12:55 | 显示全部楼层 |阅读模式
SPI双机通信,主机大概100ms发送一次数据一直发,从机DMA接收,SPI 接收完后发送一个消息给任务拷贝数据,数据拷贝完成后开启下一帧DMA接收数据(HAL_SPI_Receive_DMA(&hspi1, (uint8_t *)g_spiRxBuf, sizeof(SPI_Data));),数据拷贝任务优先级最高死等接收完成消息。现在发现问题从机偶尔(半个钟,一两个钟都可能)接收错误,进入HAL_SPI_ErrorCallback这里,现在不知道什么原因导致接收错误。现在想进入错误后如何复位SPI重新接收数据。




0x38000000地址mpu配置参考V7的SPI双机通信(从机):

        MPU_InitStruct.Enable                = MPU_REGION_ENABLE;
        MPU_InitStruct.BaseAddress       = 0x38000000;
        MPU_InitStruct.Size                    = MPU_REGION_SIZE_64KB;
        MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
        MPU_InitStruct.IsBufferable        = MPU_ACCESS_NOT_BUFFERABLE;
        MPU_InitStruct.IsCacheable       = MPU_ACCESS_NOT_CACHEABLE;
        MPU_InitStruct.IsShareable        = MPU_ACCESS_NOT_SHAREABLE;
        MPU_InitStruct.Number             = MPU_REGION_NUMBER6;
        MPU_InitStruct.TypeExtField      = MPU_TEX_LEVEL0;
        MPU_InitStruct.SubRegionDisable = 0x00;
        MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
        HAL_MPU_ConfigRegion(&MPU_InitStruct);



接收完成发送消息操作

void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
        SPI_MSG_T MSG;
               
        MSG.type = SPI_CMD_TYPE_READ_DATA;
        osMessageQueuePut(Spi1_RxHandle, (void *)&MSG, 0, 0);
       
        wTransferState = TRANSFER_COMPLETE;
}



这样操作没法复位让SPI重新接收正确的数据,就是一直都是进入这个函数了

void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
        wTransferState = TRANSFER_ERROR;
       
        if(hspi->Instance==SPI1)
        {
                __disable_irq();
               
                 __HAL_DMA_DISABLE(hspi->hdmarx);
                SCB_InvalidateDCache_by_Addr((uint32_t *)g_spiRxBuf, sizeof(SPI_Data));      //g_spiRxBuf 地址在0x38000000。
                HAL_SPI_Receive_DMA(&hspi1, (uint8_t *)g_spiRxBuf, sizeof(SPI_Data));
               
                 __enable_irq();
        }
}




回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106734
QQ
发表于 2023-10-27 10:17:17 | 显示全部楼层
调用SPI的DeInit函数就行,然后此函数会调用那个MspDeInit函数,这个里面做好DMA的复位。

然后你重新初始化,应该是没问题的。
回复

使用道具 举报

44

主题

562

回帖

699

积分

金牌会员

积分
699
 楼主| 发表于 2023-10-27 10:34:12 | 显示全部楼层
eric2013 发表于 2023-10-27 10:17
调用SPI的DeInit函数就行,然后此函数会调用那个MspDeInit函数,这个里面做好DMA的复位。

然后你重新初 ...
就这个函数吗?

HAL_StatusTypeDef HAL_SPI_DeInit(SPI_HandleTypeDef *hspi)

就是
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
        wTransferState = TRANSFER_ERROR;
        
        if(hspi->Instance==SPI1)
        {
                __disable_irq();         //这关中断还需要不?
               
                HAL_SPI_DeInit(hspi);

                SCB_InvalidateDCache_by_Addr((uint32_t *)g_spiRxBuf, sizeof(SPI_Data));
                HAL_SPI_Receive_DMA(&hspi1, (uint8_t *)g_spiRxBuf, sizeof(SPI_Data));

               __enable_irq();
        }

}


回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106734
QQ
发表于 2023-10-27 11:09:07 | 显示全部楼层
ou513 发表于 2023-10-27 10:34
就这个函数吗?

HAL_StatusTypeDef HAL_SPI_DeInit(SPI_HandleTypeDef *hspi)

你的DMA复位操作了没,这个代码里面没有体现出来。
回复

使用道具 举报

44

主题

562

回帖

699

积分

金牌会员

积分
699
 楼主| 发表于 2023-10-27 11:30:11 | 显示全部楼层
eric2013 发表于 2023-10-27 11:09
你的DMA复位操作了没,这个代码里面没有体现出来。

上面是没有DAM相关的操作,那就是还需要DAM 的DeInit函数了哦,如下操作是否可行了

void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
        wTransferState = TRANSFER_ERROR;
        
        if(hspi->Instance==SPI1)
        {
                __disable_irq();         //这关中断还需要不?
               
                HAL_DMA_DeInit(hspi->hdmarx);       //DMA 复位
                HAL_SPI_DeInit(hspi);                     //SPI 复位

                SCB_InvalidateDCache_by_Addr((uint32_t *)g_spiRxBuf, sizeof(SPI_Data));
                HAL_SPI_Receive_DMA(&hspi1, (uint8_t *)g_spiRxBuf, sizeof(SPI_Data));

               __enable_irq();
        }

}



回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106734
QQ
发表于 2023-10-27 11:34:20 | 显示全部楼层
ou513 发表于 2023-10-27 11:30
上面是没有DAM相关的操作,那就是还需要DAM 的DeInit函数了哦,如下操作是否可行了

void HAL_SPI_Erro ...

简单省事些,你的DMA INIT前,先调用DMA DeInit,然后调用DMA INIT即可
回复

使用道具 举报

44

主题

562

回帖

699

积分

金牌会员

积分
699
 楼主| 发表于 2023-10-27 11:44:07 | 显示全部楼层
eric2013 发表于 2023-10-27 11:34
简单省事些,你的DMA INIT前,先调用DMA DeInit,然后调用DMA INIT即可

不太理解什么意思,指的是在HAL_SPI_ErrorCallback函数内操作吗?还是说在main函数内的DMA INIT前调用DMA DeInit函数。(假设DMA在main函数下初始化)
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106734
QQ
发表于 2023-10-27 12:15:03 | 显示全部楼层
这样调用就可以了,这样的DMA就不用再单独DeInit了。

下载 (6).png
回复

使用道具 举报

44

主题

562

回帖

699

积分

金牌会员

积分
699
 楼主| 发表于 2023-10-27 13:29:55 | 显示全部楼层
eric2013 发表于 2023-10-27 12:15
这样调用就可以了,这样的DMA就不用再单独DeInit了。

明白了,谢谢!修改测试看看情况
回复

使用道具 举报

44

主题

562

回帖

699

积分

金牌会员

积分
699
 楼主| 发表于 2023-10-30 09:57:27 | 显示全部楼层
经过两天的测试,视乎发现了问题所在。
1、DMA配置为正常模式的时候,就发不定时的发送偶发性接收错误(频率大概半个钟到一个钟之间就会发送)。(解决办法进入错误HAL_SPI_ErrorCallback函数内按照硬汉的方法复位后又能够正确接收数据)
2、DMA配置为循环模式的时候,经过两天的测试暂时还没有发现接收错误了。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106734
QQ
发表于 2023-10-30 12:29:41 | 显示全部楼层
ou513 发表于 2023-10-30 09:57
经过两天的测试,视乎发现了问题所在。
1、DMA配置为正常模式的时候,就发不定时的发送偶发性接收错误(频 ...

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-3 00:50 , Processed in 0.490233 second(s), 29 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表