硬汉嵌入式论坛

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

[SPI/QSPI] DMA+SPI的初始化问题

[复制链接]

1

主题

11

回帖

14

积分

新手上路

积分
14
发表于 4 天前 | 显示全部楼层 |阅读模式
大家好,我希望用双缓冲数组实现SPI的DMA传输,硬件方式,驱动24位数据的DAC。SPI设置如下:



  /* USER CODE END SPI4_Init 1 */
  hspi4.Instance = SPI4;
  hspi4.Init.Mode = SPI_MODE_MASTER;
  hspi4.Init.Direction = SPI_DIRECTION_2LINES_TXONLY;
  hspi4.Init.DataSize = SPI_DATASIZE_24BIT;//ds:
  hspi4.Init.CLKPolarity = SPI_POLARITY_LOW;//下降沿
  hspi4.Init.CLKPhase = SPI_PHASE_2EDGE;
  hspi4.Init.NSS = SPI_NSS_HARD_OUTPUT;//// 硬件控制NSS(SYNC)
  hspi4.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
  hspi4.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi4.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi4.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi4.Init.CRCPolynomial = 0x0;//
  hspi4.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;//// 传输完成后自动拉高NSS
  hspi4.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;// NSS低电平有效
  hspi4.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
  hspi4.Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
  hspi4.Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
  hspi4.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
  hspi4.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_01CYCLE;
  hspi4.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
  hspi4.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
  hspi4.Init.IOSwap = SPI_IO_SWAP_DISABLE;
  if (HAL_SPI_Init(&hspi4) != HAL_OK)
  {
    Error_Handler();
  }



现在会发现进入Error_Handler();即初始化失败, 我看大佬eric2013的代码中  可以设置hspi4.Init.FifoThreshold = SPI_FIFO_THRESHOLD_05DATA;都没问题。请教下该如何解决。
回复

使用道具 举报

1

主题

11

回帖

14

积分

新手上路

积分
14
 楼主| 发表于 4 天前 | 显示全部楼层
用官方的代码,初始化也没过:
{
       
        /* 设置SPI参数 */
        hspi4.Instance               = SPI4;                                   /* 例化SPI */
        hspi4.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;                     /* 设置波特率 */
        hspi4.Init.Direction         = SPI_DIRECTION_2LINES_TXONLY;  /* 全双工 */
        hspi4.Init.CLKPhase          = SPI_PHASE_2EDGE;                            /* 配置时钟相位 */
        hspi4.Init.CLKPolarity       = SPI_POLARITY_LOW;                           /* 配置时钟极性 */
        hspi4.Init.DataSize          = SPI_DATASIZE_24BIT;                       /* 设置数据宽度 */
        hspi4.Init.FirstBit          = SPI_FIRSTBIT_MSB;                 /* 数据传输先传高位 */
        hspi4.Init.TIMode            = SPI_TIMODE_DISABLE;                     /* 禁止TI模式  */
        hspi4.Init.CRCCalculation    = SPI_CRCCALCULATION_DISABLE;         /* 禁止CRC */
        hspi4.Init.CRCPolynomial     = 7;                                       /* 禁止CRC后,此位无效 */
        hspi4.Init.CRCLength         = SPI_CRC_LENGTH_8BIT;                     /* 禁止CRC后,此位无效 */
        hspi4.Init.FifoThreshold     = SPI_FIFO_THRESHOLD_05DATA;        /* 设置FIFO大小是一个数据项 */
       
        hspi4.Init.NSS         = SPI_NSS_HARD_OUTPUT;                         /* 使用软件方式管理片选引脚 */
        hspi4.Init.NSSPMode    = SPI_NSS_PULSE_ENABLE;                            /* 使能脉冲输出 */
        hspi4.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;               /* 低电平有效 */
        hspi4.Init.MasterSSIdleness        = SPI_MASTER_SS_IDLENESS_00CYCLE;        /* MSS, 插入到NSS有效边沿和第一个数据开始之间的额外延迟,单位SPI时钟周期个数 */
        hspi4.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_10CYCLE; /* MIDI, 两个连续数据帧之间插入的最小时间延迟,单位SPI时钟周期个数 */
       
        hspi4.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE; /* 禁止SPI后,SPI相关引脚保持当前状态 */  
        hspi4.Init.Mode                                  = SPI_MODE_MASTER;                     /* SPI工作在主控模式 */

        /* 复位配置 */
        if (HAL_SPI_DeInit(&hspi4) != HAL_OK)
        {
                Error_Handler();
        }       

        /* 初始化配置 */
        if (HAL_SPI_Init(&hspi4) != HAL_OK)
        {
                Error_Handler();
        }       
}
回复

使用道具 举报

1

主题

11

回帖

14

积分

新手上路

积分
14
 楼主| 发表于 4 天前 | 显示全部楼层
  hspi4.Init.DataSize = SPI_DATASIZE_16BIT;//ds:
  hspi4.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA; 在这个配置下,初始化成功。
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117512
QQ
发表于 4 天前 | 显示全部楼层
使用我们原始例子DAC8563的驱动,测试是否正常,这个驱动是没问题的。也是做的24bit配置。

https://forum.anfulai.cn/forum.p ... &extra=page%3D1
回复

使用道具 举报

1

主题

11

回帖

14

积分

新手上路

积分
14
 楼主| 发表于 4 天前 | 显示全部楼层
eric2013 发表于 2025-8-7 18:34
使用我们原始例子DAC8563的驱动,测试是否正常,这个驱动是没问题的。也是做的24bit配置。

https://foru ...

好像是SPI4不支持24位传输,SPI1 2 3 可以,哈哈哈,乌龙了
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117512
QQ
发表于 3 天前 | 显示全部楼层
lsmy126 发表于 2025-8-7 18:54
好像是SPI4不支持24位传输,SPI1 2 3 可以,哈哈哈,乌龙了


回复

使用道具 举报

1

主题

11

回帖

14

积分

新手上路

积分
14
 楼主| 发表于 3 天前 | 显示全部楼层

大佬好,现在遇到了个问题,想要通过例程V7-011和V7-052实现SPI的DMA传输,双buffer模式,用函数HAL_DMAEx_MultiBufferStart_IT,但是现在配置有些问题,麻烦指导下,谢谢



----------------------------------------------
void DMA_Init(void)
{
       
        MX_SPI1_Init();
//---------------------------------------------------------------------------------------------------------------------------------       
                        /* 使能DMA时钟 */
        __HAL_RCC_DMA1_CLK_ENABLE();  // 根据实际DMA流选择     
  //HAL_DMA_MuxRequestGeneratorConfigTypeDef dmamux_ReqGenParams = {0};
        /* SPI DMA发送配置 */               
        hdma_spi1_tx.Instance                 = DMA1_Stream0;      /* 例化使用的DMA数据流 */
        hdma_spi1_tx.Init.FIFOMode            = DMA_FIFOMODE_ENABLE;     /* 使能FIFO*/
        hdma_spi1_tx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL; /* 用于设置阀值, 如果禁止FIFO此位不起作用*/
        hdma_spi1_tx.Init.MemBurst            = DMA_MBURST_SINGLE;            /* 用于存储器突发,如果禁止FIFO此位不起作用*/
        hdma_spi1_tx.Init.PeriphBurst         = DMA_PBURST_SINGLE;            /* 用于外设突发,禁止FIFO此位不起作用 */
        hdma_spi1_tx.Init.Request             = DMA_REQUEST_SPI1_TX;     /* 请求类型 */  
        hdma_spi1_tx.Init.Direction           = DMA_MEMORY_TO_PERIPH;    /* 传输方向是从存储器到外设 */  
        hdma_spi1_tx.Init.PeriphInc           = DMA_PINC_DISABLE;        /* 外设地址自增禁止 */
        hdma_spi1_tx.Init.MemInc              = DMA_MINC_ENABLE;         /* 存储器地址自增使能 */  
        hdma_spi1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;     /* 外设数据传输位宽选择字节,即32bit */
        hdma_spi1_tx.Init.MemDataAlignment    = DMA_MDATAALIGN_WORD;     /* 存储器数据传输位宽选择字节,即32bit */   
        hdma_spi1_tx.Init.Mode                = DMA_CIRCULAR;            /* 正常模式 */
        hdma_spi1_tx.Init.Priority            = DMA_PRIORITY_MEDIUM;        /* 优先级低 */
//----------------------------------------------------------------------------------------------------------

       
         /* 初始化DMA */
        if(HAL_DMA_Init(&hdma_spi1_tx) != HAL_OK)
        {
                Error_Handler();     
        }

        /* 关联DMA句柄到SPI */
        __HAL_LINKDMA(&hspi1, hdmatx, hdma_spi1_tx);       


        /* 使能DMA发送中断 */
        HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 5, 0);
        HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);


        /* 同步触发配置 */
        dmamux_syncParams.EventEnable   = ENABLE;                                                        
        dmamux_syncParams.SyncPolarity  = HAL_DMAMUX_SYNC_RISING;         
        dmamux_syncParams.RequestNumber = 1;                  
        dmamux_syncParams.SyncSignalID  = HAL_DMAMUX1_SYNC_TIM12_TRGO; /* HAL_DMAMUX1_SYNC_TIM12_TRGO HAL_DMAMUX1_SYNC_LPTIM1_OUT*/
        dmamux_syncParams.SyncEnable    = ENABLE;   
       
        HAL_DMAEx_ConfigMuxSync(&hdma_spi1_tx, &dmamux_syncParams);
       
          
       
       
         /*##-4- 启动DMA双缓冲传输 ################################################*/
    /*
        1、此函数会开启DMA的TC,TE和DME中断
        2、如果用户配置了回调函数DMA_Handle.XferHalfCpltCallback,那么函数HAL_DMA_Init会开启半传输完成中断。
        3、如果用户使用了DMAMUX的同步模式,此函数会开启同步溢出中断。
        4、如果用户使用了DMAMUX的请求发生器,此函数会开始请求发生器溢出中断。
    */
        if (HAL_DMAEx_MultiBufferStart_IT(&hdma_spi1_tx,
                                (uint32_t)dac_buffer1,  // 缓冲区1地址
                                (uint32_t)&hspi1.Instance->TXDR, // SPI数据寄存器地址
                                            (uint32_t)dac_buffer2,  // 缓冲区2地址                             
                                BUFFER_SIZE)!= HAL_OK) {
    Error_Handler();
}               

                /* 用不到的中断可以直接关闭 */
    DMA1_Stream0->CR &= ~DMA_IT_DME;
    DMA1_Stream0->CR &= ~DMA_IT_TE;
    //DMAMUX1_RequestGenerator0->RGCR &= ~DMAMUX_RGxCR_OIE;
    DMAMUX的同步模式的同步溢出中断如何关闭?

                TIM12_Config();                                                                                                       
   //HAL_SPI_Transmit_DMA(&hspi1, (uint8_t*)dac_buffer1, BUFFER_SIZE);        该函数通过例程运行成功                                                                                               
}
回复

使用道具 举报

1

主题

11

回帖

14

积分

新手上路

积分
14
 楼主| 发表于 3 天前 | 显示全部楼层

void MX_SPI1_Init(void)
{

  /* USER CODE BEGIN SPI1_Init 0 */

  /* USER CODE END SPI1_Init 0 */

  /* USER CODE BEGIN SPI1_Init 1 */

  /* USER CODE END SPI1_Init 1 */
          /* 设置SPI参数 */
        hspi1.Instance               = SPI1;                                   /* 例化SPI */
        hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32;                     /* 设置波特率 -4*/
        hspi1.Init.Direction         = SPI_DIRECTION_2LINES_TXONLY;  /* 半双工 */
        hspi1.Init.CLKPhase          = SPI_PHASE_2EDGE;                             /* 配置时钟相位 */
        hspi1.Init.CLKPolarity       = SPI_POLARITY_LOW;                           /* 配置时钟极性 */
        hspi1.Init.DataSize          = SPI_DATASIZE_24BIT;                       /* 设置数据宽度 */
        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_05DATA;        /* 设置FIFO大小是一个数据项 */
       
        hspi1.Init.NSS         = SPI_NSS_HARD_OUTPUT;                         /* 使用软件方式管理片选引脚 */
        hspi1.Init.NSSPMode    = SPI_NSS_PULSE_ENABLE;                            /* 使能脉冲输出 */
        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_10CYCLE; /* MIDI, 两个连续数据帧之间插入的最小时间延迟,单位SPI时钟周期个数 */
       
        hspi1.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE; /* 禁止SPI后,SPI相关引脚保持当前状态 */  
        hspi1.Init.Mode                                  = SPI_MODE_MASTER;                     /* SPI工作在主控模式 */



        /* 初始化配置 */
        if (HAL_SPI_Init(&hspi1) != HAL_OK)
        {
                Error_Handler();
        }
  /* USER CODE BEGIN SPI1_Init 2 */

  /* USER CODE END SPI1_Init 2 */

}
回复

使用道具 举报

1

主题

11

回帖

14

积分

新手上路

积分
14
 楼主| 发表于 3 天前 | 显示全部楼层

void TIM12_Config(void)
{
          /* 使能时钟 */  
  __HAL_RCC_TIM12_CLK_ENABLE();
      
  htim12.Instance = TIM12;
        htim12.Init.Period            = 16000 - 1;
        htim12.Init.Prescaler         = 0;
        htim12.Init.ClockDivision     = 0;
        htim12.Init.CounterMode       = TIM_COUNTERMODE_UP;
        htim12.Init.RepetitionCounter = 0;


       
        if(HAL_TIM_Base_Init(&htim12) != HAL_OK)
        {
                Error_Handler();               
        }

    sConfig.OCMode     = TIM_OCMODE_PWM1;
    sConfig.OCPolarity = TIM_OCPOLARITY_LOW;
    sConfig.Pulse = 8000;     /* 占空比50% */
    if(HAL_TIM_OC_ConfigChannel(&htim12, &sConfig, TIM_CHANNEL_1) != HAL_OK)
    {
                Error_Handler();
    }

    /* 启动OC1 */
    if(HAL_TIM_OC_Start(&htim12, TIM_CHANNEL_1) != HAL_OK)
    {
                Error_Handler();
    }

    /* TIM12的TRGO用于触发DMAMUX的请求发生器 */
        sMasterConfig.MasterOutputTrigger = TIM_TRGO_OC1REF;
  sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
        sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
       
        HAL_TIMEx_MasterConfigSynchronization(&htim12, &sMasterConfig);
}
回复

使用道具 举报

1

主题

11

回帖

14

积分

新手上路

积分
14
 楼主| 发表于 3 天前 | 显示全部楼层
void DMA1_Stream0_IRQHandler(void)
{
    // 调用HAL库的DMA中断处理函数,传入DMA句柄
   // HAL_DMA_IRQHandler(&hdma_spi1_tx);
                /* 清除标志 */
        /* 传输完成中断 */
       
        __HAL_DMA_CLEAR_FLAG(&hdma_spi1_tx,DMA_FLAG_TCIF0_4);

}                                  仅仅复位标志位,先实现重复发送两个数组
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117512
QQ
发表于 前天 09:39 | 显示全部楼层
lsmy126 发表于 2025-8-8 21:27
void DMA1_Stream0_IRQHandler(void)
{
    // 调用HAL库的DMA中断处理函数,传入DMA句柄

中断处理修改下,就用
HAL_DMA_IRQHandler(&hdma_spi1_tx);

然后就在传输完成回调里面处理
回复

使用道具 举报

1

主题

11

回帖

14

积分

新手上路

积分
14
 楼主| 发表于 前天 11:13 | 显示全部楼层
eric2013 发表于 2025-8-9 09:39
中断处理修改下,就用
HAL_DMA_IRQHandler(&hdma_spi1_tx);

HAL_DMAEx_MultiBufferStart_IT 这个函数没有跑起来,还没到中断函数那一步,应该是哪里没有配置好
回复

使用道具 举报

1

主题

11

回帖

14

积分

新手上路

积分
14
 楼主| 发表于 前天 11:28 | 显示全部楼层
eric2013 发表于 2025-8-9 09:39
中断处理修改下,就用
HAL_DMA_IRQHandler(&hdma_spi1_tx);

你好,我DMA请求配置的是hdma_spi1_tx.Init.Request             = DMA_REQUEST_SPI1_TX; ,函数HAL_DMAEx_MultiBufferStart_IT(&hdma_spi1_tx,
                                (uint32_t)dac_buffer1,  // 缓冲区1地址
                                (uint32_t)&hspi1.Instance->TXDR, // SPI数据寄存器地址
                                            (uint32_t)dac_buffer2,  // 缓冲区2地址                             
                                20)   这样使用有问题吗?
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117512
QQ
发表于 11 小时前 | 显示全部楼层
lsmy126 发表于 2025-8-9 11:28
你好,我DMA请求配置的是hdma_spi1_tx.Init.Request             = DMA_REQUEST_SPI1_TX; ,函数HAL_DMAE ...

你看下你的DMA缓冲是不是开到DTCM空间了,这个空间不支持通用DMA
回复

使用道具 举报

1

主题

11

回帖

14

积分

新手上路

积分
14
 楼主| 发表于 2 小时前 | 显示全部楼层
eric2013 发表于 2025-8-11 09:31
你看下你的DMA缓冲是不是开到DTCM空间了,这个空间不支持通用DMA

就普通的定义: uint8_t dac_buffer4[20];     HAL_DMAEx_MultiBufferStart_IT(&hdma_spi1_tx,
                                (uint32_t)dac_buffer3,  // 缓冲区1地址
                                (uint32_t)&hspi1.Instance->TXDR, // SPI数据寄存器地址
                                            (uint32_t)dac_buffer4,  // 缓冲区2地址                             
                                8)
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-8-11 20:58 , Processed in 0.046046 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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