打印
[STM32]

SPI用DMA模式接收数据错位。

[复制链接]
7731|30
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
any012|  楼主 | 2017-5-9 14:09 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
设置PC6为上升沿触发中断,触发后中断回调函数开启DMA读取9个数据,然后下降沿时关闭DMA,但是读取到的数据会发生右移,这是什么原因,怎么解决呢?


读取到的数据


接收到正确的数据是: Spi2 DMA recived OK. 3a08, 010a, 0200, 01ff, 03ff, 07ff, 0fff, 5d71, 0000
出错时有时是这样的: Spi2 DMA recived OK. 03a0, 8010, a020, 001f, f03f, f07f, f0ff, f5d7, 1000
这样是最后一个16位数据跑到了第一个位置,其他的依次后移了。算是右移了2个字节。

我用示波器表笔碰触SCL管脚,有时候出现右移1个字节的情况。
但也有时候出现的数据较乱,感觉像是移动了几个bit,而不是整个字节。


PC6上升沿和下降沿都离MOSI数据产生有很大的时间间隔。

SPI2初始化函数:





相关帖子

沙发
ningling_21| | 2017-5-9 14:33 | 只看该作者
不用DMA会不会错位

使用特权

评论回复
板凳
any012|  楼主 | 2017-5-10 10:40 | 只看该作者
ningling_21 发表于 2017-5-9 14:33
不用DMA会不会错位

示波器观测SCLK和MOSI波形,是正确的,应该还是接收方面的问题。准备改为SPI中断接收试下。

使用特权

评论回复
地板
ningling_21| | 2017-5-10 11:50 | 只看该作者
any012 发表于 2017-5-10 10:40
示波器观测SCLK和MOSI波形,是正确的,应该还是接收方面的问题。准备改为SPI中断接收试下。 ...

收发双方的设置可能不同

使用特权

评论回复
5
icecut| | 2017-5-10 13:08 | 只看该作者
竟然错半字节,真神

使用特权

评论回复
6
any012|  楼主 | 2017-5-10 13:55 | 只看该作者
icecut 发表于 2017-5-10 13:08
竟然错半字节,真神

主设备和从设备同时加电,从设备接收数据有可能出现位移,也有可能是正常的。

如果从设备接收数据正常,我用示波器表笔反复碰触sclk引脚,有可能引起接收数据位移,不过不是特别容易出现。

我分析出错数据,应该是移位。

使用特权

评论回复
7
icecut| | 2017-5-10 14:06 | 只看该作者
那你不用 dma, 用示波器表笔乱碰也移位

使用特权

评论回复
8
any012|  楼主 | 2017-5-10 14:41 | 只看该作者
icecut 发表于 2017-5-10 14:06
那你不用 dma, 用示波器表笔乱碰也移位

我的理解是,由于表笔乱碰,这次接收数据产生了移位。但下次接收是我重新调用DMA接收函数,应该重新指向源和目的地址,应该能重新接收正确的数据。结果却是以后每次接收的数据都产生了移位,这是我不理解的地方。

使用特权

评论回复
9
zodiacGu| | 2017-5-16 11:10 | 只看该作者
有没有 timing 图啊,感觉描述的很混乱啊

使用特权

评论回复
10
any012|  楼主 | 2017-5-16 14:23 | 只看该作者
zodiacGu 发表于 2017-5-16 11:10
有没有 timing 图啊,感觉描述的很混乱啊

用示波器看过,SPI主设备发送过来的信号是正确的。
就是SPI从设备接收的问题。

使用特权

评论回复
11
zodiacGu| | 2017-5-16 14:31 | 只看该作者
any012 发表于 2017-5-16 14:23
用示波器看过,SPI主设备发送过来的信号是正确的。
就是SPI从设备接收的问题。 ...

按你这么说的话,从设备没理由一会好一会儿不好啊
从描述来看像是SPI 传输前sclk line上的噪声影响啊
另外是否有将重设备CS pull high when idle来提高抗干扰能力

使用特权

评论回复
12
zodiacGu| | 2017-5-16 14:35 | 只看该作者
any012 发表于 2017-5-16 14:23
用示波器看过,SPI主设备发送过来的信号是正确的。
就是SPI从设备接收的问题。 ...

NSS 设置为HARD 模式是否尝试过?

使用特权

评论回复
13
any012|  楼主 | 2017-5-16 14:49 | 只看该作者
本帖最后由 any012 于 2017-5-16 14:58 编辑
zodiacGu 发表于 2017-5-16 14:35
NSS 设置为HARD 模式是否尝试过?

我现在改用SPI中断模式了。
结果还是有问题。
现在是这么实现的,PC6上升沿时,开启SPI中断接收函数。

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if (HAL_GPIO_ReadPin(EN_3V3_GPIO_Port, EN_3V3_Pin) == GPIO_PIN_SET)
    {
        HAL_SPI_Receive_IT(&hspi2, (uint8_t *) spi2RecvDate, 0x09);
    }
}
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
    printf(
            "\r\n Spi2 interruped recived OK. %04x, %04x, %04x, %04x, %04x, %04x, %04x, %04x, %04x",
            spi2RecvDate[0], spi2RecvDate[1], spi2RecvDate[2], spi2RecvDate[3],
            spi2RecvDate[4], spi2RecvDate[5], spi2RecvDate[6], spi2RecvDate[7],
            spi2RecvDate[8]);
//    HAL_GPIO_TogglePin(ERR_GPIO_Port, ERR_Pin);
}

现象是,主设备启动后,然后给从设备下载程序,则从设备接收正常,串口可输出正确的数据。
主从设备断电后同时重启,则从设备接收就不正常了,SPI数据溢出错误。


1秒时间到。
Spi2 interruped recived OK. 3a08, 010a, 0200, 01ff, 03ff, 07ff, 0fff, 5d71, 0000
1秒时间到。
Spi2 interruped recived OK. 3a08, 010a, 0200, 01ff, 03ff, 07ff, 0fff, 5d71, 0000
1秒时间到。
Spi2 interruped recived OK. 3a08, 010a, 0200, 01ff, 03ff, 07ff, 0fff, 5d71, 0000
1秒时间到。
Spi2 interruped recived OK. 3a08, 010a, 0200, 01ff, 03ff, 07ff, 0fff, 5d71, 0000
Version: 4DA 1.2.5
1秒时间到。spi ovr err.spi ovr err.spi ovr err.spi ovr err.spi ovr err.spi ovr err.spi ovr err.spi ovr err.spi ovr err.spi ovr err.spi ovr err.spi ovr err.spi ovr err.spi ovr err.spi ovr err.spi ovr err.spi ovr err.spi ovr err.spi ovr err.spi ovr err.
1秒时间到。spi ovr err.
1秒时间到。spi ovr err.
1秒时间到。spi ovr err.
1秒时间到。spi ovr err.
1秒时间到。spi ovr err.
1秒时间到。spi ovr err.
1秒时间到。spi ovr err.
1秒时间到。spi ovr err.



使用特权

评论回复
14
any012|  楼主 | 2017-5-16 15:02 | 只看该作者
本帖最后由 any012 于 2017-5-16 15:04 编辑

我也不明白上电时,会有这么多次的溢出错误。
查看了下中断程序部分,如果有溢出错误的话,会停止中断的。那么既然产生了这么多次溢出错误,我就怀疑上电时,主设备再PC6引脚上产生了不是预期的多次脉冲。

但还有问题解释不通。稳定后,为何还是每次接收都是溢出错误呢?中断函数里,如果产生溢出错误的话,在关闭中断前,是先清了溢出错误标志的。

if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_OVR) != RESET)
        {
            if (hspi->State != HAL_SPI_STATE_BUSY_TX)
            {
                SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_OVR);
                __HAL_SPI_CLEAR_OVRFLAG(hspi);
                printf("spi ovr err.");
            }
        }


使用特权

评论回复
15
any012|  楼主 | 2017-5-18 09:48 | 只看该作者
本帖最后由 any012 于 2017-5-18 17:30 编辑

找到问题了。
接收的时候,出现异常时,接收数据溢出,中断处理函数里,判断溢出错误后,就清掉溢出错误标志,然后转到错误处理部分。
错误处理部分里关闭了接收中断,但是在关闭接收中断之前,又有新的数据到来,结果又溢出错误了。
最后的结果就是下次开启接收中断时,直接就溢出错误了。以上,周而复始。

在错误处理部分,关闭接收中断后,再清一次溢出错误标志即可。
或者,开启SPI接收的时候,是否应该先把各标志位清一遍?

/* SPI Overrun error interrupt occurred -----------------------------------*/
        if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_OVR) != RESET)
        {
            if (hspi->State != HAL_SPI_STATE_BUSY_TX)
            {
                SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_OVR);
                __HAL_SPI_CLEAR_OVRFLAG(hspi);
                printf("spi ovr err.");
            }
        }

        /* Call the Error call Back in case of Errors */
        if (hspi->ErrorCode != HAL_SPI_ERROR_NONE)
        {
            __HAL_SPI_DISABLE_IT(hspi, SPI_IT_RXNE | SPI_IT_TXE | SPI_IT_ERR);
            __HAL_SPI_CLEAR_OVRFLAG(hspi);                                                         //关闭中断后,再清一次溢出错误标志。
            hspi->State = HAL_SPI_STATE_READY;
            HAL_SPI_ErrorCallback(hspi);
        }

**************************************************************
高兴的太早了...
溢出错误后关闭SPI中断后,再清一次溢出错误标志,这个只能解决同时开机时,主设备发送错误数据的问题。
稳定后,从设备接收的数据,如果SCLK受干扰的话,仍会产生位移,且一直保持。


使用特权

评论回复
16
any012|  楼主 | 2017-5-18 17:31 | 只看该作者
ningling_21 发表于 2017-5-9 14:33
不用DMA会不会错位

尝试过了用SPI中断,仍会错位。

使用特权

评论回复
17
any012|  楼主 | 2017-5-18 17:32 | 只看该作者
icecut 发表于 2017-5-10 14:06
那你不用 dma, 用示波器表笔乱碰也移位

不用DMA也会移位。
不理解的地方是,移位为什么会一直保持下去?


使用特权

评论回复
18
ningling_21| | 2017-5-18 17:38 | 只看该作者
any012 发表于 2017-5-18 17:32
不用DMA也会移位。
不理解的地方是,移位为什么会一直保持下去?

数据在内部存储时是对齐的,前面错了,后面也跟着错

使用特权

评论回复
19
any012|  楼主 | 2017-5-19 08:48 | 只看该作者
ningling_21 发表于 2017-5-18 17:38
数据在内部存储时是对齐的,前面错了,后面也跟着错

HAL_SPI_Receive_IT(&hspi2, (uint8_t *) spi2RecvDate, 0x09);
每次调用这个函数,接收9个数据,如果在接收过程中受干扰,产生错位,9个数据中剩下的部分都会跟着错位。这能理解。
不能理解的是,这个函数我是在PC6上升沿时会调用一次,按说会重新配置接收地址吧,怎会接着错?

使用特权

评论回复
20
zodiacGu| | 2017-5-25 11:10 | 只看该作者
any012 发表于 2017-5-19 08:48
HAL_SPI_Receive_IT(&hspi2, (uint8_t *) spi2RecvDate, 0x09);
每次调用这个函数,接收9个数据,如果在 ...

是不是你那边没有清从设备的Rx FIFO?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

35

主题

232

帖子

6

粉丝