SZKH 2024-01-21 22:34 采纳率: 0%
浏览 21
已结题

STM32+SPI+DMA,数据传输经常出错

#include "SPI2_DMA.h"
#include "CRC16.h"
#include "string.h"
#include "main.h"
#include "ODContent_short.h"
unsigned char hex1, hex2;
int crc;

extern union structsend                     send;                    //控制指令帧-发送的数据        tx_data[12]
extern union structrec                         rec;                    //控制指令帧-接收的数据        rx_data[12]
extern union structReadr                     readr;                //读寄存器帧-发送的数据        Read_register[6]
extern union structReadr_back            readrb;                //读寄存器帧-接收的数据        Read_register_back[4]
extern union structWriter                 writer;                //写寄存器帧-发送的数据        Write_register[8]
extern union structWriter_back        writerb;            //写寄存器帧-接收的数据        Write_register_back[6]

unsigned char temparr[14] = {0};
unsigned char tempu;


void SPI2_DMA_Configuration(void)
{
 // 1. 配置SPI2
  GPIO_InitTypeDef GPIO_InitStruct;
    SPI_InitTypeDef SPI_InitStruct;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

    GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_SPI2);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_SPI2);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_SPI2);

    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStruct.GPIO_PuPd  = GPIO_PuPd_DOWN;
    GPIO_Init(GPIOB, &GPIO_InitStruct);

    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_12;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_Init(GPIOB, &GPIO_InitStruct);
    
    SPI2_SEL_DISABLE;

    SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
    SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
    SPI_InitStruct.SPI_CPOL = SPI_CPOL_High;                        //空闲为高电平
    SPI_InitStruct.SPI_CPHA = SPI_CPHA_2Edge;                        //第二个时钟沿开始采样数据        
    SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;
    SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64; //60/64
    SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
//    SPI_InitStruct.SPI_CRCPolynomial = 7;
    SPI_Init(SPI2, &SPI_InitStruct);

    SPI_Cmd(SPI2, ENABLE);


     // 中断结构体
    NVIC_InitTypeDef NVIC_InitStructure;        
    // DMA结构体
    DMA_InitTypeDef DMA_InitStructure;          
    /* 使能DMA时钟 */          
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);    
    /* 复位初始化DMA数据流 */  
    DMA_DeInit(DMA1_Stream4);                                
    /* 确保DMA数据流复位完成 */  
    while (DMA_GetCmdStatus(DMA1_Stream4) != DISABLE);    

    /* 配置 DMA Stream */
    /* 通道0,数据流4 */      
    DMA_InitStructure.DMA_Channel = DMA_Channel_0;
    /* 外设地址 */  
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI2->DR;
    /* 内存地址(要传输的变量的指针) ,DMA存储器0地址*/      
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)send.tx_data;    
    /* 方向:存储器到外设 */            
    DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
    /* 数据传输量 ,可设置为0, 实际发送时会重新设置*/        
    DMA_InitStructure.DMA_BufferSize = (uint32_t)12;        
    /* 外设非增量模式 */        
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    /* 存储器增量模式 */      
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    /* 外设数据长度:8位 */     
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    /* 内存数据长度:8位 */
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    /* DMA模式:正常模式 */          
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    /* 优先级:高 */             
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    /* 禁用FIFO */
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;                
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;   
    /* 外设突发单次传输 */  
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;            
    /* 存储器突发单次传输 */  
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; 
    /* 初始化DMA Stream */        
    DMA_Init(DMA1_Stream4, &DMA_InitStructure);
    /* 开启传输完成中断  */        
    DMA_ITConfig(DMA1_Stream4,DMA_IT_TC,ENABLE);

    // 中断初始化 
    /* DMA发送中断源 */  
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream4_IRQn;    
    /* 抢断优先级 */  
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    /* 响应优先级 */  
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;                
    /* 使能外部中断通道 */ 
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                         
    /* 配置NVIC */        
    NVIC_Init(&NVIC_InitStructure);


    // 配置DMA1 Stream3通道0用于SPI2的接收
    DMA_InitTypeDef dmaRxInitStruct;
    dmaRxInitStruct.DMA_Channel = DMA_Channel_0;
    dmaRxInitStruct.DMA_PeripheralBaseAddr = (uint32_t)&SPI2->DR;
    dmaRxInitStruct.DMA_Memory0BaseAddr = (uint32_t)rec.rx_data;
    dmaRxInitStruct.DMA_DIR = DMA_DIR_PeripheralToMemory;
    dmaRxInitStruct.DMA_BufferSize = DATA_SIZE;
    dmaRxInitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    dmaRxInitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
    dmaRxInitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    dmaRxInitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    dmaRxInitStruct.DMA_Mode = DMA_Mode_Normal;
    dmaRxInitStruct.DMA_Priority = DMA_Priority_High;
    dmaRxInitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable;
    dmaRxInitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
    dmaRxInitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    dmaRxInitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    DMA_Init(DMA1_Stream3, &dmaRxInitStruct);

    // 启用SPI2的DMA发送和接收
    SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE);
    SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Rx, ENABLE);

    // 启用DMA1 Stream4和Stream3
//    DMA_Cmd(DMA1_Stream4, ENABLE);
//    DMA_Cmd(DMA1_Stream3, ENABLE);
}


void DMA1_Stream4_IRQHandler(void)
{
    // DMA 发送完成
    if(DMA_GetITStatus(DMA1_Stream4, DMA_IT_TCIF4))    
    {
        // 清除DMA发送完成标志
        DMA_ClearITPendingBit(DMA1_Stream4, DMA_IT_TCIF4);    
        // 片选拉高,数据发送完毕    
            memset(send.tx_data,0,12);
            DMA_Cmd(DMA1_Stream4, DISABLE);
            while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_TXE) == RESET);
            while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_BSY) == 1);    //保证发送接收数据完整

            SPI2_SEL_DISABLE;
    }
}

//开启一次DMA传输
void MYDMA_TX_Enable(DMA_Stream_TypeDef*DMA_CHx, u32 arr,int len)
{ 
    DMA_Cmd(DMA_CHx, DISABLE );  //关闭SPI TX DMA1 所指示的通道   
    DMA_CHx->M0AR=(u32)arr;
     DMA_SetCurrDataCounter(DMA_CHx,len);//DMA通道的DMA缓存的大小
     DMA_Cmd(DMA_CHx, ENABLE);  //使能SPI TX DMA1 所指示的通道 
}    

//开启一次DMA传输
void MYDMA_RX_Enable(DMA_Stream_TypeDef*DMA_CHx,int len)
{ 
    DMA_Cmd(DMA_CHx, DISABLE );  //关闭SPI RX DMA1 所指示的通道  
    DMA_CHx->M0AR=(u32)temparr;
     DMA_SetCurrDataCounter(DMA_CHx,len);//DMA通道的DMA缓存的大小
     DMA_Cmd(DMA_CHx, ENABLE);  //使能SPI RX DMA1 所指示的通道 
}

uint8_t SPI2_ReadWriteByte(unsigned char data)
{                      
    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);    // 等待发送区空  
    SPI_I2S_SendData(SPI2, data);                                 // 通过外设SPI1发送一个byte数据
    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);// 等待接收完一个byte  
    return SPI_I2S_ReceiveData(SPI2);                                 // 返回通过SPIx最近接收的数据            
}

/////////////////////////////////////////////
在中断中不断调用此函数,中断1ms一次
////////////////////////////////////////////
void SPI_DMA_WriteReadByte(void)
{
    crc = do_crc(send.tx_data, 10);
    send.sendtype.crc_H = (unsigned char)(crc>>8);
    send.sendtype.crc_L = (unsigned char)(crc&0xff);

//    发送12B数据
    SPI2_SEL_ENABLE;//拉低片选        (放在此处为了节省0.5us的时间)
    SPI_I2S_DMACmd(SPI2,SPI_I2S_DMAReq_Tx, ENABLE);//SPI 发送DMA使能
    SPI_I2S_DMACmd(SPI2,SPI_I2S_DMAReq_Rx, ENABLE);//SPI 接收DMA使能
    MYDMA_TX_Enable(DMA1_Stream4,(u32)send.tx_data,12);//发送
    MYDMA_RX_Enable(DMA1_Stream3,12);//接收
    if(DMA_GetITStatus(DMA1_Stream4, DMA_IT_TCIF4) == RESET)
    {
        DMA_ClearFlag(DMA1_Stream4,DMA_FLAG_TCIF4);
    }                    
    while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_TXE) == RESET);    
    while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_BSY) == 1);    //保证发送接收数据完整

//接收16B数据    
#if 1
    tempu = SPI2_ReadWriteByte(0x00);
    tempu = SPI2_ReadWriteByte(0x00);
    tempu = SPI2_ReadWriteByte(0x00);
    tempu = SPI2_ReadWriteByte(0x00);
    for(int i=0;i<12;i++)
        rec.rx_data[i] = SPI2_ReadWriteByte(0x00);

#endif    
    
    SPI2_SEL_DISABLE;//拉高片选
}

​

SPI从机接收的数据如下:
​​

img


.

有规律的错误,不知道是什么原因造成的

  • 写回答

1条回答 默认 最新

  • CSDN-Ada助手 CSDN-AI 官方账号 2024-01-22 08:05
    关注

    【相关推荐】



    void spi_init(void)
    {
    	SPI_DMA_Config();
      SPI_InitTypeDef  SPI_InitStructure;
      /* 使能SPI 时钟 */
      RCC_APB1PeriphClockCmd(LCD_RCC_APBPeriph_SPI ,ENABLE);	
    	
      /* SPI配置 */ 
      SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
      SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
      SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
      SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
      SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
      SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
      SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
      SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
      SPI_InitStructure.SPI_CRCPolynomial = 7;
      SPI_Init(LCD_SPI, &SPI_InitStructure);
      
    	SPI2->CR2 |= 1<<1  ;	        //发送缓冲区DMA使能
    	SPI2->CR2 |= 1<<0  ;	        //接收缓冲区DMA使能
    	
      /* 使能SPI  */
      SPI_Cmd(LCD_SPI, ENABLE);   
    	
      SPI_CS(0);			//禁止片选
    }
    

    如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^
    评论

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 1月30日
  • 创建了问题 1月21日

悬赏问题

  • ¥15 两台交换机分别是trunk接口和access接口为何无法通信,通信过程是如何?
  • ¥15 C语言使用vscode编码错误
  • ¥15 用KSV5转成本时,如何不生成那笔中间凭证
  • ¥20 ensp怎么配置让PC1和PC2通讯上
  • ¥50 有没有适合匹配类似图中的运动规律的图像处理算法
  • ¥15 dnat基础问题,本机发出,别人返回的包,不能命中
  • ¥15 请各位帮我看看是哪里出了问题
  • ¥15 vs2019的js智能提示
  • ¥15 关于#开发语言#的问题:FDTD建模问题图中代码没有报错,但是模型却变透明了
  • ¥15 uniapp的h5项目写一个抽奖动画