STM32F103的SPI2+DMA接收數據


需求:STM32F103作為從設備,通過SPI接收大量數據;

 

方案:1.STM32的SPI通過中斷接收(占用CPU資源,且長數據易丟失)

         2.STM32通過SPI+DMA實現大數據接收(占用資源少)

 

 

本次采用第二種方案實現

 

時序圖(見STM32F10XXX參考手冊第471頁):

主要思路:

1.      配置SPI外設

SPI2配置:雙線、只收、禁止CRC、16位數據、僅接收禁止發送、NSS由硬件控制、高位開始傳輸、配置為從設備、時鍾懸空低電平、第1個時鍾采集數據、關閉I2S

2.      配置DMA外設;

DMA配置:外設到內存、非循環模式、允許傳輸完成中斷

3.      配置SPI與DMA的連接;

使能SPI2->CR2第0位

需要編寫的文件:SPI.C  SPI.H  DMA.C  DMA.H文件

 

 

1.      SPI.H

#ifndef __SPI_H

#define __SPI_H    

#include "sys.h"    //沒有這個文件就屏蔽掉,定義時就不能寫u16,按規范定義;

 

void SPI2_Config(void);   //SPI2初始化函數

#endif

 

2.      SPI.C文件

 

#include "spi.h"                    

void SPI2_Config(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

NVIC_InitTypeDef NVIC_InitStructure;

SPI_InitTypeDef  SPI_InitStructure;

 

//掛載對應時鍾

RCC->APB1ENR  |=  1<<14;        //SPI2

RCC->APB2ENR  |=  1<<3;         //GPIOB

 

 //SPI2的GPIO配置

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15|GPIO_Pin_12;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOB, &GPIO_InitStructure);

 

//也可以使用庫函數定義,主要一定是雙線模式不然接收數據為0X0000;

SPI2->CR1  = 0X00;                  //復位SPI2->CR1控制寄存器

SPI2->CR1 &= ~(1<<15);              //雙線模式

SPI2->CR1 &= ~(1<<14);               //只收模式

SPI2->CR1 &= ~(1<<13);               //禁止CRC

SPI2->CR1 |= 1<<11;                    //16位數據模式

SPI2->CR1 |= 1<<10;                  //僅接收禁止發送

SPI2->CR1 &= ~(1<<9);                //NSS由硬件控制

SPI2->CR1 &= ~(1<<7);                //MSB傳輸

SPI2->CR1 &= ~(1<<2);             //配置為從設備

SPI2->CR1 |=  0<<1;               //時鍾懸空低

SPI2->CR1 |=  0<<0;               //第1個時鍾采樣

//可不配置以下兩句話,I2SCFGR默認復位為0X00

SPI2->I2SCFGR|=0<<11;             //選擇SPI模式

SPI2->I2SCFGR|=0<<10;             //關閉I2S模式

 

//要關閉SPI2接收中斷,允許產生DMA中斷,這是SPI與DMA連接的橋梁

SPI2->CR2  =0X00;           //¸SPI控制寄存器2配置

SPI2->CR2 |= 0<<6;

SPI2->CR2 |= 0<<7;

SPI2->CR2 |= 0<<1;

SPI2->CR2 |= 1<<0;                 //允許DMA接收數據

}     

 

3.      DMA.H

 

#ifndef __DMA_H

#define __DMA_H 

#include "sys.h"

 

#define SPI2_DR_addr 0x4000380C  //宏定義外設寄存器地址為SPI2->DR=0x4000380c

//其它外設查看STM32F1xx數據手冊

#define DMA1_MEM_LEN 52          //定義接收數據長度

extern u16 receive_dma[52];          //全局申明接收緩存數組,可在其它文件中調用

extern u8 DMA_RX_FLAG;            //聲明接收完成標志位

void dma_init(void);                   //初始化                                    

#endif

 

 

4.      DMA,C

 

 

#include "dma.h"

u16 receive_dma[52];

u8 DMA_RX_FLAG=0;

void dma_init(void)    //DMA初始化

{

DMA_InitTypeDef DMA_InitStructure;

NVIC_InitTypeDef NVIC_InitStructure;

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);

 

//具體含義查看STM32F1的說明書中關於這些寄存器的描述

//也可用庫函數寫

DMA1_Channel4->CCR   = 0x00000000;                    

       DMA1_Channel4->CPAR=SPI2_DR_addr;                                  DMA1_Channel4->CMAR = (u32)&receive_dma;            

DMA1_Channel4->CNDTR =  DMA1_MEM_LEN;                 

DMA1_Channel4->CCR   |= 0<<4;

DMA1_Channel4->CCR|=0<<5;                          

DMA1_Channel4->CCR|=0<<6;            

DMA1_Channel4->CCR|=1<<7;                          DMA1_Channel4->CCR|=2<<8;                           DMA1_Channel4->CCR|=1<<10;                          DMA1_Channel4->CCR|=1<<12;                         DMA1_Channel4->CCR |= 0<<14;

                        

DMA1_Channel4->CCR |= 1<<1;                   

DMA1_Channel4->CCR  |= 1<<2;                                                          

DMA1_Channel4->CCR  |= 0<<3;                               

 

DMA1_Channel4->CCR|=1<<0;   

           

 NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;

 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

 NVIC_Init(&NVIC_InitStructure);

}

 

void DMA1_Channel4_IRQHandler(void)

{

 if((DMA1->ISR & 0x00002000) == 0x00002000)

 {

DMA_RX_FLAG=1;

SPI2->CR1 &= ~(1<<6);              

DMA1_Channel4->CCR  &= ~(1<<0);            

DMA1->IFCR |=1<<12 ;                       

 }

}

 

 

5.      主函數(僅寫出相關部分)

本部分是判斷接收到一組數據后,將數據打印出來,然后再打開DMA與SPI中斷

       if(DMA_RX_FLAG==1){  

              BackLeakageSpotAnaysis();  //將數據打印或則做其它處理

              DMA_RX_FLAG=0;

              DMA1_Channel4->CNDTR = 52;

              DMA1_Channel4->CMAR  = (u32)&receive_dma;   //從寫接收緩存器地址

              DMA1_Channel4->CCR  |= 1<<0;                //使能DMA

              SPI2->CR1 |= 1<<6;                          //使能SPI2

       }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM