打印
[STM32H7]

STM32H743 SPI DMA 数据收发问题

[复制链接]
672|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
xad74|  楼主 | 2023-1-5 09:03 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
STM32H743 通过SPI DMA进行数据收发,在使用SP1/2时能够进入中断并进入回调函数,当改为SPI3/SPI4时出错,无法进入中断回调函数

使用特权

评论回复
沙发
xad74|  楼主 | 2023-1-5 09:06 | 只看该作者
附上SPI代码
/*
*********************************************************************************************************
*                                    时钟,引脚,DMA,中断等宏定义
*********************************************************************************************************
*/
#define SPIx                                                        SPI3
#define SPIx_CLK_ENABLE()                                __HAL_RCC_SPI3_CLK_ENABLE()
#define DMAx_CLK_ENABLE()                                __HAL_RCC_DMA2_CLK_ENABLE()

#define SPIx_FORCE_RESET()                                __HAL_RCC_SPI3_FORCE_RESET()
#define SPIx_RELEASE_RESET()                        __HAL_RCC_SPI3_RELEASE_RESET()

#define SPIx_SCK_CLK_ENABLE()                        __HAL_RCC_GPIOB_CLK_ENABLE()
#define SPIx_SCK_GPIO                                        GPIOB
#define SPIx_SCK_PIN                                        GPIO_PIN_3
#define SPIx_SCK_AF                                                GPIO_AF5_SPI3

#define SPIx_MISO_CLK_ENABLE()                        __HAL_RCC_GPIOB_CLK_ENABLE()
#define SPIx_MISO_GPIO                                        GPIOB
#define SPIx_MISO_PIN                                         GPIO_PIN_4
#define SPIx_MISO_AF                                        GPIO_AF5_SPI3

#define SPIx_MOSI_CLK_ENABLE()                        __HAL_RCC_GPIOB_CLK_ENABLE()
#define SPIx_MOSI_GPIO                                        GPIOB
#define SPIx_MOSI_PIN                                         GPIO_PIN_5
#define SPIx_MOSI_AF                                        GPIO_AF5_SPI3

/* CS片选 */       
#define SPIx_NSS_CLK_ENABLE()                         __HAL_RCC_GPIOG_CLK_ENABLE()
#define SPIx_NSS_GPIO                                        GPIOG
#define SPIx_NSS_PIN                                        GPIO_PIN_10
#define SPIx_NSS_AF                                                GPIO_AF5_SPI3

#define SPIx_TX_DMA_STREAM               DMA2_Stream3
#define SPIx_RX_DMA_STREAM               DMA2_Stream2

#define SPIx_TX_DMA_REQUEST              DMA_REQUEST_SPI3_TX
#define SPIx_RX_DMA_REQUEST              DMA_REQUEST_SPI3_RX

#define SPIx_DMA_TX_IRQn                 DMA2_Stream3_IRQn
#define SPIx_DMA_RX_IRQn                 DMA2_Stream2_IRQn

#define SPIx_DMA_TX_IRQHandler           DMA2_Stream3_IRQHandler
#define SPIx_DMA_RX_IRQHandler           DMA2_Stream2_IRQHandler

#define SPIx_IRQn                        SPI3_IRQn
#define SPIx_IRQHandler                  SPI3_IRQHandler

enum {
        TRANSFER_WAIT,
        TRANSFER_COMPLETE,
        TRANSFER_ERROR
};

/*
*********************************************************************************************************
*                                                   变量
*********************************************************************************************************
*/
static SPI_HandleTypeDef hspi = {0};
static DMA_HandleTypeDef hdma_tx;
static DMA_HandleTypeDef hdma_rx;
static uint32_t s_BaudRatePrescaler;
static uint32_t s_CLKPhase;
static uint32_t s_CLKPolarity;
uint32_t g_spiLen;       
uint8_t  g_spi_busy; /* SPI忙状态,0表示不忙,1表示忙 */
__IO uint32_t wTransferState = TRANSFER_WAIT;


/* 查询模式 */
#if defined (USE_SPI_POLL)

uint8_t g_spiTxBuf[SPI_BUFFER_SIZE];  
uint8_t g_spiRxBuf[SPI_BUFFER_SIZE];

/* 中断模式 */
#elif defined (USE_SPI_INT)

uint8_t g_spiTxBuf[SPI_BUFFER_SIZE];   
uint8_t g_spiRxBuf[SPI_BUFFER_SIZE];

/* DMA模式使用的SRAM4 */
#elif defined (USE_SPI_DMA)
    #if defined ( __CC_ARM )    /* IAR *******/
        __attribute__((section (".RAM_D3"))) uint8_t g_spiTxBuf[SPI_BUFFER_SIZE];   
        __attribute__((section (".RAM_D3"))) uint8_t g_spiRxBuf[SPI_BUFFER_SIZE];
    #elif defined (__ICCARM__)   /* MDK ********/
        #pragma location = ".RAM_D3"
        uint8_t g_spiTxBuf[SPI_BUFFER_SIZE];   
        #pragma location = ".RAM_D3"
        uint8_t g_spiRxBuf[SPI_BUFFER_SIZE];
    #endif
#endif


/*
*********************************************************************************************************
*        函 数 名: bsp_InitSPIBus
*        功能说明: 配置SPI总线。
*        形    参: 无
*        返 回 值: 无
*********************************************************************************************************
*/
void bsp_InitSPIBus(void)
{       
        g_spi_busy = 0;
       
        bsp_InitSPIParam(SPI_BAUDRATEPRESCALER_16, SPI_PHASE_1EDGE, SPI_POLARITY_LOW);
}

/*
*********************************************************************************************************
*        函 数 名: bsp_InitSPIParam
*        功能说明: 配置SPI总线参数,时钟分频,时钟相位和时钟极性。
*        形    参: _BaudRatePrescaler  SPI总线时钟分频设置,支持的参数如下:
*                                 SPI_BAUDRATEPRESCALER_2    2分频
*                                 SPI_BAUDRATEPRESCALER_4    4分频
*                                 SPI_BAUDRATEPRESCALER_8    8分频
*                                 SPI_BAUDRATEPRESCALER_16   16分频
*                                 SPI_BAUDRATEPRESCALER_32   32分频
*                                 SPI_BAUDRATEPRESCALER_64   64分频
*                                 SPI_BAUDRATEPRESCALER_128  128分频
*                                 SPI_BAUDRATEPRESCALER_256  256分频
*                                                        
*             _CLKPhase           时钟相位,支持的参数如下:
*                                 SPI_PHASE_1EDGE     SCK引脚的第1个边沿捕获传输的第1个数据
*                                 SPI_PHASE_2EDGE     SCK引脚的第2个边沿捕获传输的第1个数据
*                                 
*             _CLKPolarity        时钟极性,支持的参数如下:
*                                 SPI_POLARITY_LOW    SCK引脚在空闲状态处于低电平
*                                 SPI_POLARITY_HIGH   SCK引脚在空闲状态处于高电平
*
*        返 回 值: 无jiben
*********************************************************************************************************
*/
void bsp_InitSPIParam(uint32_t _BaudRatePrescaler, uint32_t _CLKPhase, uint32_t _CLKPolarity)
{
        /* 提高执行效率,只有在SPI硬件参数发生变化时,才执行HAL_Init */
        if (s_BaudRatePrescaler == _BaudRatePrescaler && s_CLKPhase == _CLKPhase && s_CLKPolarity == _CLKPolarity)
        {               
                return;
        }

        s_BaudRatePrescaler = _BaudRatePrescaler;       
        s_CLKPhase = _CLKPhase;
        s_CLKPolarity = _CLKPolarity;

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

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

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

/*
*********************************************************************************************************
*        函 数 名: bsp_InitSPIParam
*        功能说明: 配置SPI总线时钟,GPIO,中断,DMA等
*        形    参: SPI_HandleTypeDef 类型指针变量
*        返 回 值: 无
*********************************************************************************************************
*/
void HAL_SPI_MspInit(SPI_HandleTypeDef *_hspi)
{
        /* 配置 SPI总线GPIO : SCK MOSI MISO */
        {
                GPIO_InitTypeDef  GPIO_InitStruct;
                       
                /* SPI和GPIP时钟 */
                SPIx_SCK_CLK_ENABLE();
                SPIx_MISO_CLK_ENABLE();
                SPIx_MOSI_CLK_ENABLE();
                SPIx_CLK_ENABLE();

                /* SPI SCK */
                GPIO_InitStruct.Pin       = SPIx_SCK_PIN;
                GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
                GPIO_InitStruct.Pull      = GPIO_PULLUP;
                GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_HIGH;
                GPIO_InitStruct.Alternate = SPIx_SCK_AF;
                HAL_GPIO_Init(SPIx_SCK_GPIO, &GPIO_InitStruct);

                /* SPI MISO */
                GPIO_InitStruct.Pin = SPIx_MISO_PIN;
                GPIO_InitStruct.Alternate = SPIx_MISO_AF;
                HAL_GPIO_Init(SPIx_MISO_GPIO, &GPIO_InitStruct);

                /* SPI MOSI */
                GPIO_InitStruct.Pin = SPIx_MOSI_PIN;
                GPIO_InitStruct.Alternate = SPIx_MOSI_AF;
                HAL_GPIO_Init(SPIx_MOSI_GPIO, &GPIO_InitStruct);

        /* SPI NSS */
        GPIO_InitStruct.Pin = SPIx_NSS_PIN;
        GPIO_InitStruct.Alternate = SPIx_NSS_AF;
        HAL_GPIO_Init(SPIx_NSS_GPIO, &GPIO_InitStruct);
        }

        /* 配置DMA和NVIC */
        #ifdef USE_SPI_DMA
        {
                /* 使能DMA时钟 */
                DMAx_CLK_ENABLE();      

                /* SPI DMA发送配置 */               
                hdma_tx.Instance                 = SPIx_TX_DMA_STREAM;      /* 例化使用的DMA数据流 */
                hdma_tx.Init.FIFOMode            = DMA_FIFOMODE_ENABLE;     /* FIFO*/
                hdma_tx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL; /* 禁止FIFO此位不起作用,用于设置阀值 */
                hdma_tx.Init.MemBurst            = DMA_MBURST_SINGLE;            /* 禁止FIFO此位不起作用,用于存储器突发 */
                hdma_tx.Init.PeriphBurst         = DMA_PBURST_SINGLE;            /* 禁止FIFO此位不起作用,用于外设突发 */
                hdma_tx.Init.Request             = SPIx_TX_DMA_REQUEST;     /* 请求类型 */  
                hdma_tx.Init.Direction           = DMA_MEMORY_TO_PERIPH;    /* 传输方向是从存储器到外设 */  
                hdma_tx.Init.PeriphInc           = DMA_PINC_DISABLE;        /* 外设地址自增禁止 */
                hdma_tx.Init.MemInc              = DMA_MINC_ENABLE;         /* 存储器地址自增使能 */  
                hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;     /* 外设数据传输位宽选择字节,即8bit */
                hdma_tx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;     /* 存储器数据传输位宽选择字节,即8bit */   
                hdma_tx.Init.Mode                = DMA_NORMAL;              /* 正常模式 */
                hdma_tx.Init.Priority            = DMA_PRIORITY_LOW;        /* 优先级低 */

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

                /* 关联DMA句柄到SPI */
                __HAL_LINKDMA(_hspi, hdmatx, hdma_tx);       

                /* SPI DMA接收配置 */       
                hdma_rx.Instance                 = SPIx_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_SINGLE;           /* 禁止FIFO此位不起作用,用于存储器突发 */
                hdma_rx.Init.PeriphBurst         = DMA_PBURST_SINGLE;           /* 禁止FIFO此位不起作用,用于外设突发 */
                hdma_rx.Init.Request             = SPIx_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.Priority            = DMA_PRIORITY_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(_hspi, hdmarx, hdma_rx);       

                /* 配置DMA发送中断 */
                HAL_NVIC_SetPriority(SPIx_DMA_TX_IRQn, 1, 0);
                HAL_NVIC_EnableIRQ(SPIx_DMA_TX_IRQn);
               
                /* 配置DMA接收中断 */
                HAL_NVIC_SetPriority(SPIx_DMA_RX_IRQn, 1, 0);
                HAL_NVIC_EnableIRQ(SPIx_DMA_RX_IRQn);
               
                /* 配置SPI中断 */
                HAL_NVIC_SetPriority(SPIx_IRQn, 1, 0);
                HAL_NVIC_EnableIRQ(SPIx_IRQn);
        }
        #endif
       
        #ifdef USE_SPI_INT
                /* 配置SPI中断优先级并使能中断 */
                HAL_NVIC_SetPriority(SPIx_IRQn, 1, 0);
                HAL_NVIC_EnableIRQ(SPIx_IRQn);
        #endif
}
       
/*
*********************************************************************************************************
*        函 数 名: bsp_spiTransfer
*        功能说明: 启动数据传输
*        形    参: 无
*        返 回 值: 无
*********************************************************************************************************
*/
void bsp_spiTransfer(void)
{
        if (g_spiLen > SPI_BUFFER_SIZE)
        {
                return;
        }
       
        /* DMA方式传输 */
#ifdef USE_SPI_DMA
        wTransferState = TRANSFER_WAIT;
       
    if(HAL_SPI_TransmitReceive_DMA(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen) != HAL_OK)       
    {
        Error_Handler(__FILE__, __LINE__);
    }

//    if(HAL_SPI_Transmit_DMA(&hspi, (uint8_t*)g_spiTxBuf, g_spiLen) != HAL_OK)       
//    {
//        Error_Handler(__FILE__, __LINE__);
//    }
       
        while (wTransferState == TRANSFER_WAIT)
        {
                ;
        }
#endif

        /* 中断方式传输 */       
#ifdef USE_SPI_INT
        wTransferState = TRANSFER_WAIT;

    if(HAL_SPI_TransmitReceive_IT(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen) != HAL_OK)       
    {
        Error_Handler(__FILE__, __LINE__);
    }
       
        while (wTransferState == TRANSFER_WAIT)
        {
                ;
        }
#endif

        /* 查询方式传输 */       
#ifdef USE_SPI_POLL
        if(HAL_SPI_TransmitReceive(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen, 1000000) != HAL_OK)       
        {
                Error_Handler(__FILE__, __LINE__);
        }       
#endif
}

/*
*********************************************************************************************************
*        函 数 名: HAL_SPI_TxRxCpltCallback,HAL_SPI_ErrorCallback
*        功能说明: SPI数据传输完成回调和传输错误回调
*        形    参: SPI_HandleTypeDef 类型指针变量
*        返 回 值: 无
*********************************************************************************************************
*/
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
        HAL_SPI_DMAStop(hspi);
        HAL_SPI_DMAPause(hspi);
        wTransferState = TRANSFER_COMPLETE;
}

//void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
//{
//        wTransferState = TRANSFER_COMPLETE;
//}


void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
        wTransferState = TRANSFER_ERROR;
}

/*
*********************************************************************************************************
*        函 数 名: bsp_SpiBusEnter
*        功能说明: 占用SPI总线
*        形    参: 无
*        返 回 值: 0 表示不忙  1表示忙
*********************************************************************************************************
*/
void bsp_SpiBusEnter(void)
{
        g_spi_busy = 1;
}

/*
*********************************************************************************************************
*        函 数 名: bsp_SpiBusExit
*        功能说明: 释放占用的SPI总线
*        形    参: 无
*        返 回 值: 0 表示不忙  1表示忙
*********************************************************************************************************
*/
void bsp_SpiBusExit(void)
{
        g_spi_busy = 0;
}

/*
*********************************************************************************************************
*        函 数 名: bsp_SpiBusBusy
*        功能说明: 判断SPI总线忙,方法是检测其他SPI芯片的片选信号是否为1
*        形    参: 无
*        返 回 值: 0 表示不忙  1表示忙
*********************************************************************************************************
*/
uint8_t bsp_SpiBusBusy(void)
{
        return g_spi_busy;
}

/*
*********************************************************************************************************
*        函 数 名: SPIx_IRQHandler,SPIx_DMA_RX_IRQHandler,SPIx_DMA_TX_IRQHandler
*        功能说明: 中断服务程序
*        形    参: 无
*        返 回 值: 无
*********************************************************************************************************
*/
#ifdef USE_SPI_INT
        void SPIx_IRQHandler(void)
        {
                HAL_SPI_IRQHandler(&hspi);
        }       
#endif

#ifdef USE_SPI_DMA
        void SPIx_DMA_RX_IRQHandler(void)
        {
                HAL_SPI_DMAStop(&hspi);
                HAL_SPI_DMAPause(&hspi);
                HAL_DMA_IRQHandler(hspi.hdmarx);
               
                wTransferState = TRANSFER_COMPLETE;
        }

        void SPIx_DMA_TX_IRQHandler(void)
        {
                HAL_SPI_DMAStop(&hspi);
                HAL_SPI_DMAPause(&hspi);
                HAL_DMA_IRQHandler(hspi.hdmatx);
               
                wTransferState = TRANSFER_COMPLETE;
        }
       
        void SPIx_IRQHandler(void)
        {
                HAL_SPI_IRQHandler(&hspi);
        }       
#endif
       

使用特权

评论回复
板凳
tpgf| | 2023-2-3 09:22 | 只看该作者
具体的话楼主修改哪方面的代码了呢

使用特权

评论回复
地板
nawu| | 2023-2-3 09:30 | 只看该作者
改串口之后存在引脚功能上的冲突吗 需要注意一下这方面

使用特权

评论回复
5
aoyi| | 2023-2-3 09:39 | 只看该作者
我不是很明白 楼主是一下子就使用了两个串口同时进行通讯吗

使用特权

评论回复
6
zljiu| | 2023-2-3 09:54 | 只看该作者
在中断向量的里边是不是指向的地址不相符啊

使用特权

评论回复
7
gwsan| | 2023-2-3 10:24 | 只看该作者
软件更改配置的话  要确认硬件上是否已经同步更改

使用特权

评论回复
8
tfqi| | 2023-2-3 10:39 | 只看该作者
肯定是小细节没有处理好啊  硬件和软件都要检查

使用特权

评论回复
9
SantaBunny| | 2023-2-13 15:45 | 只看该作者
软件更改配置的话,检查一下硬件有没有更改

使用特权

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

本版积分规则

27

主题

168

帖子

3

粉丝