打印
[STM32]

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

[复制链接]
8500|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初始化函数:





相关帖子

30
zodiacGu| | 2017-5-30 13:00 | 只看该作者
any012 发表于 2017-5-26 09:09
STM32的SPI没有硬件FIFO。
或者,你说的是SPI的移位寄存器?
我倒是想清移位寄存器,但不知道该如何清? ...

DR Register

使用特权

评论回复
29
icecut| | 2017-5-27 10:01 | 只看该作者
any012 发表于 2017-5-27 09:58
是软片选。
现在的解决办法也就是在下降沿初始化SPI,但总觉得初始化SPI操作太多了,应该有更有效的办法 ...

你还是查查你硬件吧.逻辑分析仪抓一下信号.不是cpu问题.

使用特权

评论回复
28
any012|  楼主 | 2017-5-27 09:58 | 只看该作者
icecut 发表于 2017-5-26 17:56
片选不是低电平有效么?如果是软片选,完全可以下降沿初始化所有,让发送端多延时一下 ...

是软片选。
现在的解决办法也就是在下降沿初始化SPI,但总觉得初始化SPI操作太多了,应该有更有效的办法吧。

使用特权

评论回复
27
icecut| | 2017-5-26 17:56 | 只看该作者
片选不是低电平有效么?如果是软片选,完全可以下降沿初始化所有,让发送端多延时一下

使用特权

评论回复
26
any012|  楼主 | 2017-5-26 13:43 | 只看该作者
icecut 发表于 2017-5-26 11:00
你是不是片选一直拉低了.接死了?

不是,PC6当作片选信号的输入,PC6上升沿中断,开启SPI的DMA接收,接收定长数据。PC6下降沿时,我现在的处理是重新初始化下SPI,这样做现在没事。

使用特权

评论回复
25
icecut| | 2017-5-26 11:00 | 只看该作者
any012 发表于 2017-5-26 10:53
当作SPI从设备。
现在是在片选信号失效后,重新初始化了SPI。目前没问题了,但感觉没必要完全初始化。 ...

你是不是片选一直拉低了.接死了?

使用特权

评论回复
24
any012|  楼主 | 2017-5-26 10:53 | 只看该作者
icecut 发表于 2017-5-26 10:05
这么久还没搞定?你spi是master还是device?

当作SPI从设备。
现在是在片选信号失效后,重新初始化了SPI。目前没问题了,但感觉没必要完全初始化。

使用特权

评论回复
23
icecut| | 2017-5-26 10:05 | 只看该作者
any012 发表于 2017-5-26 09:12
看了SPI的原理框图,应该是SCLK每收到8个或16个有效信号,就将移位寄存器里的数放到接收缓存里。
我的理 ...

这么久还没搞定?你spi是master还是device?

使用特权

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

看了SPI的原理框图,应该是SCLK每收到8个或16个有效信号,就将移位寄存器里的数放到接收缓存里。
我的理解是有个类似计数器的部分,来计算SCLK的有效信号。有没有办法将这个计数清零?

使用特权

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

看了SPI的原理框图,应该是SCLK每收到8个或16个有效信号,就将移位寄存器里的数放到接收缓存里。
我的理解是有个类似计数器的部分,来计算SCLK的有效信号。有没有办法将这个计数清零?

使用特权

评论回复
20
any012|  楼主 | 2017-5-26 09:09 | 只看该作者
zodiacGu 发表于 2017-5-25 11:10
是不是你那边没有清从设备的Rx FIFO?

STM32的SPI没有硬件FIFO。
或者,你说的是SPI的移位寄存器?
我倒是想清移位寄存器,但不知道该如何清?

使用特权

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

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

使用特权

评论回复
18
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上升沿时会调用一次,按说会重新配置接收地址吧,怎会接着错?

使用特权

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

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

使用特权

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

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


使用特权

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

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

使用特权

评论回复
14
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受干扰的话,仍会产生位移,且一直保持。


使用特权

评论回复
13
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.");
            }
        }


使用特权

评论回复
12
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.



使用特权

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

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

使用特权

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

本版积分规则

35

主题

232

帖子

6

粉丝