硬汉嵌入式论坛

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

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

[复制链接]

1

主题

20

回帖

23

积分

新手上路

积分
23
发表于 2025-8-7 15:04:05 | 显示全部楼层 |阅读模式
大家好,我希望用双缓冲数组实现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

主题

20

回帖

23

积分

新手上路

积分
23
 楼主| 发表于 2025-8-7 16:01:36 | 显示全部楼层
用官方的代码,初始化也没过:
{
       
        /* 设置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

主题

20

回帖

23

积分

新手上路

积分
23
 楼主| 发表于 2025-8-7 16:36:59 | 显示全部楼层
  hspi4.Init.DataSize = SPI_DATASIZE_16BIT;//ds:
  hspi4.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA; 在这个配置下,初始化成功。
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

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

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

使用道具 举报

1

主题

20

回帖

23

积分

新手上路

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

https://foru ...

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

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

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


回复

使用道具 举报

1

主题

20

回帖

23

积分

新手上路

积分
23
 楼主| 发表于 2025-8-8 21:21:11 | 显示全部楼层

大佬好,现在遇到了个问题,想要通过例程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

主题

20

回帖

23

积分

新手上路

积分
23
 楼主| 发表于 2025-8-8 21:21:47 | 显示全部楼层

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

主题

20

回帖

23

积分

新手上路

积分
23
 楼主| 发表于 2025-8-8 21:22:32 | 显示全部楼层

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

主题

20

回帖

23

积分

新手上路

积分
23
 楼主| 发表于 2025-8-8 21:27:03 | 显示全部楼层
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

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

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

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

使用道具 举报

1

主题

20

回帖

23

积分

新手上路

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

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

使用道具 举报

1

主题

20

回帖

23

积分

新手上路

积分
23
 楼主| 发表于 2025-8-9 11:28:08 | 显示全部楼层
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

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

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

使用道具 举报

1

主题

20

回帖

23

积分

新手上路

积分
23
 楼主| 发表于 2025-8-11 18:33:13 | 显示全部楼层
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)
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
118335
QQ
发表于 2025-8-12 09:19:48 | 显示全部楼层
lsmy126 发表于 2025-8-11 18:33
就普通的定义: uint8_t dac_buffer4[20];     HAL_DMAEx_MultiBufferStart_IT(&hdma_spi1_tx,
        ...

务必看下map文件,看下这个变量dac_buffer4的地址是是多少
回复

使用道具 举报

1

主题

20

回帖

23

积分

新手上路

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

g_spiTxBuf                               0x2400047c   Data        4000  spi.o(.bss) ,应该不是在DTCM里。

感觉还是哪里设置不对

void DMA_Init(void)
{
        HAL_DMA_MuxRequestGeneratorConfigTypeDef dmamux_ReqGenParams = {0};
  //MX_SPI1_Init();
//---------------------------------------------------------------------------------------------------------------------------------       
                        /* 使能DMA时钟 */
        __HAL_RCC_DMA1_CLK_ENABLE();  // 根据实际DMA流选择     
        /* SPI DMA发送配置 */               
        hdma_spi1_tx.Instance                 = DMA1_Stream0;      /* 例化使用的DMA数据流 */
        hdma_spi1_tx.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;     /* shi能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此位  bu起作用 */
        hdma_spi1_tx.Init.Request             = DMA_REQUEST_GENERATOR0;     /* 请求类型 */  
        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_HIGH;        /* 优先级低 */
        hdma_spi1_tx.XferCpltCallback         =HAL_DMA_XferCpltCallback;
        hdma_spi1_tx.XferHalfCpltCallback     =HAL_DMA_XferHalfCpltCallback;
//----------------------------------------------------------------------------------------------------------

         /* 初始化DMA */
        if(HAL_DMA_Init(&hdma_spi1_tx) != HAL_OK)
        {
                Error_Handler();     
        }
   
        MX_SPI1_Init();
       
        /* 关联DMA句柄到SPI */
        __HAL_LINKDMA(&hspi1, hdmatx, hdma_spi1_tx);       


    /*##-4- 配置DMAMUX ###########################################################*/
    dmamux_ReqGenParams.SignalID  = HAL_DMAMUX1_REQ_GEN_TIM12_TRGO;         /* 请求触发器选择LPTIM2_OUT */
    dmamux_ReqGenParams.Polarity  = HAL_DMAMUX_REQ_GEN_RISING;              /* 上升沿触发  */
    dmamux_ReqGenParams.RequestNumber = 1;                                  /* 触发后,传输进行1次DMA传输 */

    HAL_DMAEx_ConfigMuxRequestGenerator(&hdma_spi1_tx, &dmamux_ReqGenParams); /* 配置DMAMUX */
    HAL_DMAEx_EnableMuxRequestGenerator (&hdma_spi1_tx);                      /* 使能DMAMUX请求发生器 */            
                                       
    SET_BIT(hspi1.Instance->CFG1, SPI_CFG1_TXDMAEN);       
    HAL_DMA_Start_IT(&hdma_spi1_tx, (uint32_t)g_spiTxBuf, (uint32_t )&hspi1.Instance->TXDR, 1000);  // 启动带中断的DMA
   
          DMA1_Stream0->CR &= ~DMA_IT_DME;
    DMA1_Stream0->CR &= ~DMA_IT_TE;
          DMA1_Stream0->CR &= ~DMA_IT_FE;
       
          /* 使能DMA发送中断 */
          HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 5, 0);
          HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);
  
          TIM12_Config();
}
回复

使用道具 举报

1

主题

20

回帖

23

积分

新手上路

积分
23
 楼主| 发表于 2025-8-13 08:53:18 | 显示全部楼层
eric2013 发表于 2025-8-12 09:19
务必看下map文件,看下这个变量dac_buffer4的地址是是多少

按照网上的DMA+spi初始化了一下,还是不行

void DMA_Init(void)
{
        HAL_DMA_MuxRequestGeneratorConfigTypeDef dmamux_ReqGenParams = {0};
  MX_SPI1_Init();
//---------------------------------------------------------------------------------------------------------------------------------       
                        /* 使能DMA时钟 */
        __HAL_RCC_DMA1_CLK_ENABLE();  // 根据实际DMA流选择
  DMA_HandleTypeDef  DMA_InitStructure;
        //清空DMA1_Stream0上所有中断标志
    __HAL_DMA_CLEAR_FLAG(&DMA_InitStructure,DMA_FLAG_FEIF0_4  |
                         DMA_FLAG_DMEIF0_4 | DMA_FLAG_TEIF0_4 |
                         DMA_FLAG_HTIF0_4 | DMA_FLAG_TCIF0_4);
        /* SPI DMA发送配置 */               
        hdma_spi1_tx.Instance                 = DMA1_Stream0;      /* 例化使用的DMA数据流 */
        hdma_spi1_tx.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;     /* shi能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此位  bu起作用 */
        hdma_spi1_tx.Init.Request             = DMA_REQUEST_GENERATOR0;     /* 请求类型 */  
        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_HIGH;        /* 优先级低 */
       
//----------------------------------------------------------------------------------------------------------

         /* 初始化DMA */
        if(HAL_DMA_Init(&hdma_spi1_tx) != HAL_OK)
        {
                Error_Handler();     
        }
       
        /* 关联DMA句柄到SPI */
        __HAL_LINKDMA(&hspi1, hdmatx, hdma_spi1_tx);       
       
        hdma_spi1_tx.XferCpltCallback         =HAL_DMA_XferCpltCallback;
  hdma_spi1_tx.XferM1CpltCallback       =HAL_DMA_XferM1CpltCallback;
  
       
    /*##-4- 配置DMAMUX ###########################################################*/
    dmamux_ReqGenParams.SignalID  = HAL_DMAMUX1_REQ_GEN_TIM12_TRGO;         /* 请求触发器选择LPTIM2_OUT */
    dmamux_ReqGenParams.Polarity  = HAL_DMAMUX_REQ_GEN_RISING;              /* 上升沿触发  */
    dmamux_ReqGenParams.RequestNumber = 1;                                  /* 触发后,传输进行1次DMA传输 */

    HAL_DMAEx_ConfigMuxRequestGenerator(&hdma_spi1_tx, &dmamux_ReqGenParams); /* 配置DMAMUX */
    HAL_DMAEx_EnableMuxRequestGenerator (&hdma_spi1_tx);                      /* 使能DMAMUX请求发生器 */            
                /*##-4- 配置DMAMUX ###########################################################*/                       
       
    HAL_DMAEx_MultiBufferStart_IT(&hdma_spi1_tx,(uint32_t)g_spiTxBuf,(uint32_t)&(SPI1->TXDR),(uint32_t)g_spiTxBuf[2000],10);
   
   
               
   
//          DMA1_Stream0->CR &= ~DMA_IT_DME;
//    DMA1_Stream0->CR &= ~DMA_IT_TE;
//          DMA1_Stream0->CR &= ~DMA_IT_FE;
       

                              /* 使能DMA发送中断 */
    HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 5, 0);
          HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);
          
                TIM12_Config();
               
                SET_BIT(hspi1.Instance->CFG1, SPI_CFG1_TXDMAEN);
}
回复

使用道具 举报

1

主题

20

回帖

23

积分

新手上路

积分
23
 楼主| 发表于 2025-8-13 08:54:30 | 显示全部楼层
eric2013 发表于 2025-8-12 09:19
务必看下map文件,看下这个变量dac_buffer4的地址是是多少

网上参考https://doc.embedfire.com/mcu/st ... _0/chapter36_0.html
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
118335
QQ
发表于 2025-8-13 09:10:00 | 显示全部楼层
lsmy126 发表于 2025-8-12 11:45
g_spiTxBuf                               0x2400047c   Data        4000  spi.o(.bss) ,应该不是在DT ...

看不出来那里还有问题了。
回复

使用道具 举报

1

主题

20

回帖

23

积分

新手上路

积分
23
 楼主| 发表于 2025-8-13 09:55:08 | 显示全部楼层
eric2013 发表于 2025-8-13 09:10
看不出来那里还有问题了。

找了一些人,发表了如下看法:“如果是H7的,用DMA会更麻烦、

需要提前配好MPU,同时规划好数据定义的区域。

你的数组定义在那一片的ram里,都是有讲究的,需要对着手册去定。”

这个应该和您说的内存分配是一个意思吧,buffer不能在DTCM里
回复

使用道具 举报

1

主题

20

回帖

23

积分

新手上路

积分
23
 楼主| 发表于 2025-8-13 11:32:14 | 显示全部楼层
eric2013 发表于 2025-8-13 09:10
看不出来那里还有问题了。

可能是以下原因:


已深度思考(用时37秒)
根据MAP文件信息,g_spiTxBuf数组位于0x2400047c地址,属于.bss段(未初始化数据段)。STM32H723的地址空间
划分如下:
1.Ox20000000-Ox2001FFFFTCMRAM(64KB),紧耦合内存,无缓存
2. Ox24000000-Ox2407FFFF:AXI SRAM(512KB),带D-Cache(默认配置下)
因此,Ox2400047c地址位于AXISRAM区域,默认情况下该区域是使能D-Cache(数据缓存)的。
关键点:
-该内存区域是否被缓存取决于MPU(内存保护单元)配置。默认情况下(如使用HAL库初始化),AXISRAM是启用
缓存的。
-在DMA操作中,如果源地址或目标地址位于缓存区域,必须进行缓存维护操作(Clean/Invalidate)以确保数据一致
性。
解决方案:
1. 如果使用DMA将g_spiTxBuf(内存)发送到SPI外设:
-在启动DMA传输前,调用SCB_CleanDCache_by_Addr0清理缓存,确保数据已写入物理内存。
2. 如果使用DMA接收数据到g_spiTxBuf:
-在DMA传输完成后,调用SCB_InvalidateDCache_by_Addr0使缓存无效,确保CPU读取到最新数据。
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
118335
QQ
发表于 2025-8-14 08:59:59 | 显示全部楼层
lsmy126 发表于 2025-8-13 11:32
可能是以下原因:

根据你前面这个描述:

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


你这个是程序完全没有跑起来,而Cache仅仅是影响数据一致性,并不会影响你的DMA运行
回复

使用道具 举报

1

主题

20

回帖

23

积分

新手上路

积分
23
 楼主| 发表于 2025-8-14 17:32:32 | 显示全部楼层
eric2013 发表于 2025-8-14 08:59
根据你前面这个描述:

你好,请问下循环模式改为normal模式,怎么代码就跑不起来了。应该传输一次数组才对,请指导,谢谢/


SPI 的初始化为: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_128;                     /* 设置波特率 -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_01DATA;        /* 设置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();
        }     DMA的初始化为:void DMA_Init(void)
{
  MX_SPI1_Init();
//---------------------------------------------------------------------------------------------------------------------------------       
                        /* 使能DMA时钟 */
        __HAL_RCC_DMA1_CLK_ENABLE();  // 根据实际DMA流选择     
        /* 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;     /* 外设数据传输位宽选择字节,即8bit */
        hdma_spi1_tx.Init.MemDataAlignment    = DMA_MDATAALIGN_WORD;     /* 存储器数据传输位宽选择字节,即8bit */   
        hdma_spi1_tx.Init.Mode                = DMA_CIRCULAR;            /* 正常模式 */
        hdma_spi1_tx.Init.Priority            = DMA_PRIORITY_LOW;        /* 优先级低 */
       
//----------------------------------------------------------------------------------------------------------

         /* 初始化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;//DISABLE;//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_buffer3,  // 缓冲区1地址
//                                (uint32_t)&hspi1.Instance->TXDR, // SPI数据寄存器地址
//                                            (uint32_t)dac_buffer4,  // 缓冲区2地址                             
//                                8)!= HAL_OK) {
//    Error_Handler();
//}               
    //HAL_DMA_Start(&hdma_spi1_tx, (uint32_t )dac_buffer4, (uint32_t )&SPI1->TXDR,8);
                /* 用不到的中断可以直接关闭 */
//    DMA1_Stream0->CR &= ~DMA_IT_DME;
//    DMA1_Stream0->CR &= ~DMA_IT_TE;
    //DMAMUX1_RequestGenerator0->RGCR &= ~DMAMUX_RGxCR_OIE;   HAL_DMA_Start_IT(&hdma, src, dst, length);  // 启动带中断的DMA
   
   
         TIM12_Config();                                                                                                       
   HAL_SPI_Transmit_DMA(&hspi1, (uint8_t*)g_spiTxBuf, 1000);        //该函数通过例程运行成功                g_spiLen/4               
  
         
},为何仅仅改变DMA_CIRCULAR为normal以后,就不正常传输数组一次了?
回复

使用道具 举报

1

主题

20

回帖

23

积分

新手上路

积分
23
 楼主| 发表于 2025-8-15 08:49:16 | 显示全部楼层
eric2013 发表于 2025-8-14 08:59
根据你前面这个描述:

你好,我有个疑问#define SPI_DIRECTION_2LINES                          (0x00000000UL)
#define SPI_DIRECTION_2LINES_TXONLY                   SPI_CFG2_COMM_0
#define SPI_DIRECTION_2LINES_RXONLY                   SPI_CFG2_COMM_1
#define SPI_DIRECTION_1LINE                           SPI_CFG2_COMM,

这是H7的SPI工作模式,一般的情况是收发都用,然后开两个DMA流来匹配收发。  我现在只需要发送,但是选择以上四种不知道选择除了SPI_DIRECTION_2LINES_RXONLY以外三个的哪一个,感觉比较摸棱两可,是不是保守一点就选择传统的define SPI_DIRECTION_2LINES   ,然后配置两个流,实际只使用发的流,即使我的MISO管脚没配置更没连接。   AI说在双向模式下即使只发,也需要配置收,即使只用发,因为有接收数据溢出中断啥的。
回复

使用道具 举报

1

主题

20

回帖

23

积分

新手上路

积分
23
 楼主| 发表于 2025-8-15 21:21:47 | 显示全部楼层
lsmy126 发表于 2025-8-15 08:49
你好,我有个疑问#define SPI_DIRECTION_2LINES                          (0x00000000UL)
#define SPI_ ...

用单数组+DMA循环SPI+半完成中断+全完成中断就行了;在全双工normal模式下,用T记得R也要初始化;毕业撒花
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
118335
QQ
发表于 2025-8-16 09:12:54 | 显示全部楼层
lsmy126 发表于 2025-8-15 08:49
你好,我有个疑问#define SPI_DIRECTION_2LINES                          (0x00000000UL)
#define SPI_ ...

仅TX ONLY就行

123.png
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-9-26 19:35 , Processed in 0.066037 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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