硬汉嵌入式论坛

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

[SPI/QSPI] SPI从机接收OVERRUN溢出怎么改进?

[复制链接]

3

主题

3

回帖

12

积分

新手上路

积分
12
发表于 2025-7-1 00:10:15 | 显示全部楼层 |阅读模式
用SPI从机接收50byte数据,时钟16M,周期1ms,硬件NSS。采用了DMA接收,运行之后不定期(1-10分钟不等 )出现SPI接收OVR错误。像是来不及收,目前软件只有这个SPI和DMA,没有其它中断了,还有什么办法能加快接收的速度吗?SPI和DMA配置如下:


hspi1.Instance               = SPI1;                                   /* 例化SPI */
        hspi1.Init.BaudRatePrescaler = _BaudRatePrescaler;                     /* 设置波特率 */
        hspi1.Init.Direction         = SPI_DIRECTION_2LINES_RXONLY;         /* 全双工 */
        hspi1.Init.CLKPhase          = _CLKPhase;                             /* 配置时钟相位 */
        hspi1.Init.CLKPolarity       = _CLKPolarity;                           /* 配置时钟极性 */
       
        hspi1.Init.DataSize          = SPI_DATASIZE_8BIT;                       /* 设置数据宽度 */
        hspi1.Init.FirstBit          = SPI_FIRSTBIT_MSB;                 /* 数据传输先传高位 */
        hspi1.Init.TIMode            = SPI_TIMODE_DISABLE;                     /* 禁止TI模式  */
        hspi1.Init.CRCCalculation    = SPI_CRCCALCULATION_DISABLE;         /* 禁止CRC */
        hspi1.Init.CRCPolynomial     = 7;                                       /* 禁止CRC后,此位无效 */
        hspi1.Init.CRCLength         = SPI_CRC_LENGTH_8BIT;                     /* 禁止CRC后,此位无效 */
        hspi1.Init.FifoThreshold     = SPI_FIFO_THRESHOLD_08DATA;        /* 设置FIFO大小是一个数据项 */
       
        hspi1.Init.NSS         = SPI_NSS_HARD_INPUT;                         /*  片选引脚 */
        hspi1.Init.NSSPMode    = SPI_NSS_PULSE_DISABLE;                            /* 关闭脉冲输出 */
        hspi1.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;               /* 低电平有效 */
        hspi1.Init.MasterSSIdleness        = SPI_MASTER_SS_IDLENESS_00CYCLE;        /* MSS, 插入到NSS有效边沿和第一个数据开始之间的额外延迟,单位SPI时钟周期个数 */
        hspi1.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE; /* MIDI, 两个连续数据帧之间插入的最小时间延迟,单位SPI时钟周期个数 */
       
        hspi1.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE; /* 禁止SPI后,SPI相关引脚保持当前状态 */  
        hspi1.Init.Mode                                  = SPI_MODE_SLAVE;                     /* SPI工作在从模式 */

        /* 复位配置 */
        if (HAL_SPI_DeInit(&hspi1) != HAL_OK)
        {
                Error_Handler(__FILE__, __LINE__);
        }       

        /* 初始化配置 */
        if (HAL_SPI_Init(&hspi1) != HAL_OK)
        {
                Error_Handler(__FILE__, __LINE__);
        }



                /* SPI DMA接收配置 */       
                DMA1_CLK_ENABLE();   
                hdma_rx.Instance                 = SPI1_RX_DMA_STREAM;     /* 例化使用的DMA数据流 */
                hdma_rx.Init.FIFOMode            = DMA_FIFOMODE_ENABLE;    /* FIFO*/
                hdma_rx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;/* 禁止FIFO此位不起作用,用于设置阀值 */
                hdma_rx.Init.MemBurst            = DMA_MBURST_INC4;           /* 禁止FIFO此位不起作用,用于存储器突发 */
                hdma_rx.Init.PeriphBurst         = DMA_MBURST_INC4;           /* 禁止FIFO此位不起作用,用于外设突发 */
                hdma_rx.Init.Request             = SPI1_RX_DMA_REQUEST;    /* 请求类型 */  
                hdma_rx.Init.Direction           = DMA_PERIPH_TO_MEMORY;   /* 传输方向从外设到存储器 */  
                hdma_rx.Init.PeriphInc           = DMA_PINC_DISABLE;       /* 外设地址自增禁止 */   
                hdma_rx.Init.MemInc              = DMA_MINC_ENABLE;        /* 存储器地址自增使能 */   
                hdma_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;    /* 外设数据传输位宽选择字节,即8bit */
                hdma_rx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;    /* 存储器数据传输位宽选择字节,即8bit */   
                hdma_rx.Init.Mode                = DMA_NORMAL;             /* 正常模式 */
                //hdma_rx.Init.Mode                = DMA_CIRCULAR;
                hdma_rx.Init.Priority            = DMA_PRIORITY_VERY_HIGH;      /* 优先级高 */

                 /* 复位DMA */
                if(HAL_DMA_DeInit(&hdma_rx) != HAL_OK)
                {
                        Error_Handler(__FILE__, __LINE__);     
                }
               
                 /* 初始化DMA */
                if(HAL_DMA_Init(&hdma_rx) != HAL_OK)
                {
                        Error_Handler(__FILE__, __LINE__);     
                }

                /* 关联DMA句柄到SPI */
           __HAL_LINKDMA(&hspi1, hdmarx, hdma_rx);       
                               
                /* 配置DMA接收中断 */
                HAL_NVIC_SetPriority(SPI1_DMA_RX_IRQn, 1, 0);
                HAL_NVIC_EnableIRQ(SPI1_DMA_RX_IRQn);
               
                /* 配置SPI中断 */

                HAL_NVIC_SetPriority(SPI1_IRQn, 1, 0);
                HAL_NVIC_EnableIRQ(SPI1_IRQn);

        }       

回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117512
QQ
发表于 2025-7-1 09:06:14 | 显示全部楼层
SPI主机对SPI从机操作,写操作可以50MHz,这个是确定没问题,而需读取只有10几MHz,这个要注意。

根据楼主位的描述是写操作16MHz就出错了,可以考虑简单做个应答,
回复

使用道具 举报

3

主题

3

回帖

12

积分

新手上路

积分
12
 楼主| 发表于 2025-7-1 10:35:33 来自手机 | 显示全部楼层
老师我理解是从机读spi的FIFO慢了.是读操作出错了吧?如果主机写入可以到50mhz.这些数据从机总得读走才算通信正常吧?如果读取只有10几m.岂不是要限制主机发送速度?另外这种溢出错误采用双缓冲也没有用吧?目前spi和dma中断服务程序都是Hal库标准的.是不是自己写个简洁的会更好?
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117512
QQ
发表于 2025-7-2 07:57:11 | 显示全部楼层
hhonly 发表于 2025-7-1 10:35
老师我理解是从机读spi的FIFO慢了.是读操作出错了吧?如果主机写入可以到50mhz.这些数据从机总得读走才算通 ...

STM32H7做从机,主机对其写入速度快,读取慢,如果是单向通信,可以读写分开。

另外你说的溢出错误我没遇到过。用HAL的就可以了,稳定性还行。
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-8-12 06:54 , Processed in 0.040726 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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