硬汉嵌入式论坛

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

[DMA] spi+dma+w5500传输问题

[复制链接]

20

主题

38

回帖

98

积分

初级会员

积分
98
发表于 2024-10-8 15:27:18 | 显示全部楼层 |阅读模式
使用stm32f7+w5500实现网络通信,想使用spi+dma的模式来进行数据发送
以下是关于dma的部分代码



                 /*##-3- Configure the DMA streams ##########################################*/
                 /* Configure the DMA handler for Transmission process */
                 SPI1_HDMA_TX.Instance = DMA2_Stream5;          //SPI1_TX采用DMA2数据流5 通道3   
                 SPI1_HDMA_TX.Init.Channel = DMA_CHANNEL_3;
                 SPI1_HDMA_TX.Init.Direction = DMA_MEMORY_TO_PERIPH;
                 SPI1_HDMA_TX.Init.PeriphInc = DMA_PINC_DISABLE;
                 SPI1_HDMA_TX.Init.MemInc = DMA_MINC_ENABLE;
                 SPI1_HDMA_TX.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
                 SPI1_HDMA_TX.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
                 SPI1_HDMA_TX.Init.Mode = DMA_NORMAL;
                 SPI1_HDMA_TX.Init.Priority = DMA_PRIORITY_HIGH;
                 SPI1_HDMA_TX.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
                 SPI1_HDMA_TX.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
                 SPI1_HDMA_TX.Init.MemBurst = DMA_MBURST_SINGLE;
                 SPI1_HDMA_TX.Init.PeriphBurst = DMA_MBURST_SINGLE;
//                 SPI1_HDMA_TX.XferCpltCallback = W5500_TxCpltCallback_dma;
                 
                 HAL_DMA_Init(&SPI1_HDMA_TX);
                 /* Associate the initialized DMA handle to the the SPI handle */
                 __HAL_LINKDMA(hspi, hdmatx, SPI1_HDMA_TX);

                 /* Configure the DMA handler for Transmission process */
                 SPI1_HDMA_RX.Instance = DMA2_Stream0;           //SPI1_RX采用DMA2数据流0 通道3   
                 SPI1_HDMA_RX.Init.Channel = DMA_CHANNEL_3;
                 SPI1_HDMA_RX.Init.Direction = DMA_PERIPH_TO_MEMORY;
                 SPI1_HDMA_RX.Init.PeriphInc = DMA_PINC_DISABLE;
                 SPI1_HDMA_RX.Init.MemInc = DMA_MINC_ENABLE;
                 SPI1_HDMA_RX.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
                 SPI1_HDMA_RX.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
                 SPI1_HDMA_RX.Init.Mode = DMA_NORMAL;
                 SPI1_HDMA_RX.Init.Priority = DMA_PRIORITY_HIGH;
                 SPI1_HDMA_RX.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
                 SPI1_HDMA_RX.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
                 SPI1_HDMA_RX.Init.MemBurst = DMA_MBURST_SINGLE;
                 SPI1_HDMA_RX.Init.PeriphBurst = DMA_MBURST_SINGLE;
                 
                 HAL_DMA_Init(&SPI1_HDMA_RX);
                 /* Associate the initialized DMA handle to the the SPI handle */
                 __HAL_LINKDMA(hspi, hdmarx, SPI1_HDMA_RX);
                 


                 /*##-4- Configure the NVIC for DMA #########################################*/
                 /* NVIC configuration for DMA transfer complete interrupt (SPI3_TX) */
                 HAL_NVIC_SetPriority(DMA2_Stream5_IRQn, 8, 0);
                 HAL_NVIC_EnableIRQ(DMA2_Stream5_IRQn);

                /* NVIC configuration for DMA transfer complete interrupt (SPI3_RX) */
                 HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 8, 0);
                 HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);

}
...........
//SPI发送回调函数
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
            if  (hspi->Instance == SPI1)
            {
                W5500_TxCpltCallback();
           }
}

//SPI接收回调函数
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
        if  (hspi->Instance == SPI1)
        {
             W5500_RxCpltCallback();
       }
}
.........

void W5500_TxCpltCallback_dma(DMA_HandleTypeDef *hdma)
{
         osThreadFlagsSet(tid_app_osInterface, 0x04);
}

void W5500_RxCpltCallback_dma(DMA_HandleTypeDef *hdma)
{
         ;
}

...........

void SPIx_DMA_TX_IRQHandler(void)
{
        HAL_DMA_IRQHandler(&SPI1_HDMA_TX);
}

void SPIx_DMA_RX_IRQHandler(void)
{
       HAL_DMA_IRQHandler(&SPI1_HDMA_RX);
}



//w5500利用spi_dma发送
void W5500_DMA_Configuration(uint8_t* MemBaseAddr, uint32_t len)
{  
         uint8_t p_rxbuf = 0;
         if (HAL_SPI_TransmitReceive_DMA(&SPI1_Handle, MemBaseAddr,&p_rxbuf, len) != HAL_OK)
        {
                 bsp_os_printf("error: bsp_W5500_os: DMA HAL error \r\n");
//              Error_Handler();
        }  
       
        if ((osThreadFlagsWait(0x04,osFlagsWaitAny,1000)&0x04 )==0)
       {
             bsp_os_printf("error: bsp_W5500_os: DMA error \r\n");
       }
}

现在的现象是 进入调试模式  程序运行到 if ((osThreadFlagsWait(0x04,osFlagsWaitAny,1000)&0x04 )==0)卡死, 点击stop查看程序卡死在哪个地方
发现程序不断进出

void SPIx_DMA_TX_IRQHandler(void)
{
        HAL_DMA_IRQHandler(&SPI1_HDMA_TX);
}

void SPIx_DMA_RX_IRQHandler(void)
{
       HAL_DMA_IRQHandler(&SPI1_HDMA_RX);
}

这两个函数
进入HAL_DMA_IRQHandler 中断处理函数
发现会进入

/* FIFO Error Interrupt management ******************************************/
if ((tmpisr & (DMA_FLAG_FEIF0_4 << hdma->StreamIndex)) != RESET)
{
    if(__HAL_DMA_GET_IT_SOURCE(hdma, DMA_IT_FE) != RESET)
    {
      /* Clear the FIFO error flag */
      regs->IFCR = DMA_FLAG_FEIF0_4 << hdma->StreamIndex;

      /* Update error code */
      hdma->ErrorCode |= HAL_DMA_ERROR_FE;
    }
}

研究很久也没发现问题所在。请问下是什么原因导致的呀


评分

参与人数 1金币 +2 收起 理由
不吃鱼的猫大人 + 2 插个眼

查看全部评分

回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117530
QQ
发表于 2024-10-8 16:11:36 | 显示全部楼层
你的SPI配置贴一下,另外这两个关闭了先测试下

SPI1_HDMA_TX.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
SPI1_HDMA_RX.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
回复

使用道具 举报

20

主题

38

回帖

98

积分

初级会员

积分
98
 楼主| 发表于 2024-10-8 16:36:40 | 显示全部楼层
eric2013 发表于 2024-10-8 16:11
你的SPI配置贴一下,另外这两个关闭了先测试下

SPI1_HDMA_TX.Init.FIFOMode = DMA_FIFOMODE_ENABLE;

/* Set the SPI parameters */
   SPI1_Handle.Instance = SPI1;
   SPI1_Handle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
   SPI1_Handle.Init.Direction = SPI_DIRECTION_2LINES;
   SPI1_Handle.Init.CLKPhase = SPI_PHASE_1EDGE;
   SPI1_Handle.Init.CLKPolarity = SPI_POLARITY_LOW;
   SPI1_Handle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED;
   SPI1_Handle.Init.CRCPolynomial = 7;
   SPI1_Handle.Init.DataSize = SPI_DATASIZE_8BIT;
   SPI1_Handle.Init.FirstBit = SPI_FIRSTBIT_MSB;
   SPI1_Handle.Init.NSS = SPI_NSS_SOFT;
   SPI1_Handle.Init.TIMode = SPI_TIMODE_DISABLED;
   SPI1_Handle.Init.Mode = SPI_MODE_MASTER;

   if (HAL_SPI_Init(&SPI1_Handle) != HAL_OK)
   {
      /* Initialization Error */
      bsp_os_printf("error: bsp_W5500_os: SPI_Configuration: HAL_SPI_Init error\r\n");
      Error_Handler();
   }
          __HAL_SPI_ENABLE(&SPI1_Handle);                 //使能SPI1
//          SPI1_ReadWriteByte(0xff);
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117530
QQ
发表于 2024-10-9 09:40:57 | 显示全部楼层
marin0vv0 发表于 2024-10-8 16:36
/* Set the SPI parameters */
   SPI1_Handle.Instance = SPI1;
   SPI1_Handle.Init.BaudRatePresca ...

这个配置没什么问题。前面这两个配置DISABLE后,效果怎么样
SPI1_HDMA_TX.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
SPI1_HDMA_RX.Init.FIFOMode = DMA_FIFOMODE_ENABLE;

还是不行的话,这里继续加大分频,并使能GPIO配置时的上拉电阻,使能上拉电阻最重要。
回复

使用道具 举报

0

主题

3

回帖

3

积分

新手上路

积分
3
发表于 2025-2-8 11:24:47 | 显示全部楼层
最终调通了吗??
回复

使用道具 举报

0

主题

3

回帖

3

积分

新手上路

积分
3
发表于 2025-2-8 11:25:40 | 显示全部楼层
我这边一直没有调通,网上能寻找的资料比较少,不知道楼主是否全部调通并且是老化跑通过???
回复

使用道具 举报

20

主题

102

回帖

162

积分

初级会员

积分
162
QQ
发表于 2025-2-19 18:05:54 | 显示全部楼层
RD275Floda 发表于 2025-2-8 11:25
我这边一直没有调通,网上能寻找的资料比较少,不知道楼主是否全部调通并且是老化跑通过???

请问您调通了吗?
回复

使用道具 举报

20

主题

38

回帖

98

积分

初级会员

积分
98
 楼主| 发表于 2025-2-20 09:24:19 | 显示全部楼层
没有调通,用的SPI_IT模式  也能满足项目需求
回复

使用道具 举报

20

主题

102

回帖

162

积分

初级会员

积分
162
QQ
发表于 2025-2-20 10:54:08 | 显示全部楼层
marin0vv0 发表于 2025-2-20 09:24
没有调通,用的SPI_IT模式  也能满足项目需求

我用的H7+W5500之前调通过,但是我没有使用FIFO,这是我之前移植的 H750_W5500_DMA SPI1-8.9 (2).7z (2.41 MB, 下载次数: 27)
回复

使用道具 举报

20

主题

102

回帖

162

积分

初级会员

积分
162
QQ
发表于 2025-2-20 19:29:21 | 显示全部楼层
marin0vv0 发表于 2025-2-20 09:24
没有调通,用的SPI_IT模式  也能满足项目需求

方便问一下您的F7+W5500就是传输速率能有多少M吗?
回复

使用道具 举报

12

主题

63

回帖

99

积分

初级会员

积分
99
发表于 2025-5-15 16:00:42 | 显示全部楼层
刚刚测试完毕
socket收发缓存:16KB
单次数据:2048 Byte

STM32F407,
使用官方的方法
https://www.w5500.com/w5500/std/example28.html
使用 DMA 模式
SPI时钟配置为42MHz

[ ID] Interval       Transfer     Bandwidth
[424]  0.0- 1.0 sec  2.29 MBytes  19.2 Mbits/sec
SPI时钟配置为21MHz
[ ID] Interval       Transfer     Bandwidth
[432] 280.0-281.0 sec  1.55 MBytes  13.0 Mbits/sec

使用 普通阻塞模式
SPI时钟配置为42MHz

[ ID] Interval       Transfer     Bandwidth
[424]  0.0- 1.0 sec  2.16 MBytes  18.2 Mbits/sec

SPI时钟配置为21MHz
[ ID] Interval       Transfer     Bandwidth
[424]  0.0- 1.0 sec  0.79 MBytes  6.59 Mbits/sec

使用 IT 模式
当使用21MHz,会不能进入 HAL_SPI_TxRxCpltCallback,但在中断加上rtt的打印信息,就能进入,但会影响时序
要将时钟分频到 10.5MHz 才能收发正常,造成速率降低
[ ID] Interval       Transfer     Bandwidth
[372]  0.0- 1.0 sec  0.77 MBytes  6.44 Mbits/sec

回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-8-13 01:14 , Processed in 0.050769 second(s), 29 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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