stm32 SPI DMA讀取ADS8345數據


研究了兩天的SPI通過DMA操作.

過程:怎樣啟用DMA?首先,眾所周知的是初始化,任何設備啟用前都要對其進行初始化,要對模塊初始化,還要先了解該模塊相應的結構及其函數,以便正確的設置;由於DMA較為復雜,我就只談談DMA的基本結構和和常用函數,這些都是ST公司提供在庫函數中的。

1、  下面代碼是一個標准DMA設置,當然實際應用中可根據實際情況進行裁減: 

  DMA_DeInit(DMA_Channel1);

  上面這句是給DMA配置通道,根據ST提供的資料,STM3210Fx中DMA包含7個通道(CH1~CH7),也就是說可以為外設或memory提供7座“橋梁”(請允許我使用橋梁一詞,我覺得更容易理解,哈哈,別“拍磚”呀!); 

  DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;

  上面語句中的DMA_InitStructure是一個DMA結構體,在庫中有聲明了,當然使用時就要先定義了;DMA_PeripheralBaseAddr是該結構體中一個數據成員,給DMA一個起始地址,好比是一個buffer起始地址,數據流程是:外設寄存器à DMA_PeripheralBaseAddàmemory中變量空間(或flash中數據空間等),ADC1_DR_Address是我定義的一個地址變量; 

  DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ADC_ConvertedValue;

  上面這句很顯然是DMA要連接在Memory中變量的地址,ADC_ConvertedValue是我自己在memory中定義的一個變量; 

  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;

  上面的這句是設置DMA的傳輸方向,就如前面我所說的,DMA可以雙向傳輸,也可以單向傳輸,這里設置的是單向傳輸,如果需要雙向傳輸:把DMA_DIR_PeripheralSRC改成DMA_DIR_PeripheralDST即可。 

 DMA_InitStructure.DMA_BufferSize = 2;

  上面的這句是設置DMA在傳輸時緩沖區的長度,前面有定義過了buffer的起始地址:ADC1_DR_Address ,為了安全性和可靠性,一般需要給buffer定義一個儲存片區,這個參數的單位有三種類型:Byte、HalfWord、word,我設置的2個half-word(見下面的設置);32位的MCU中1個half-word占16 bits。 

 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

  上面的這句是設置DMA的外設遞增模式,如果DMA選用的通道(CHx)有多個外設連接,需要使用外設遞增模式:DMA_PeripheralInc_Enable;我的例子里DMA只與ADC1建立了聯系,所以選用DMA_PeripheralInc_Disable

DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

上面的這句是設置DMA的內存遞增模式,DMA訪問多個內存參數時,需要使用DMA_MemoryInc_Enable,當DMA只訪問一個內存參數時,可設置成:DMA_MemoryInc_Disable。 

 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;

上面的這句是設置DMA在訪問時每次操作的數據長度。有三種數據長度類型,前面已經講過了,這里不在敘述。 

DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;

與上面雷同。在此不再說明。 

  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

  上面的這句是設置DMA的傳輸模式:連續不斷的循環模式,若只想訪問一次后就不要訪問了(或按指令操作來反問,也就是想要它訪問的時候就訪問,不要它訪問的時候就停止),可以設置成通用模式:DMA_Mode_Normal 

  DMA_InitStructure.DMA_Priority = DMA_Priority_High;

  上面的這句是設置DMA的優先級別:可以分為4級:VeryHigh,High,Medium,Low. 

  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

  上面的這句是設置DMA的2個memory中的變量互相訪問的 

  DMA_Init(DMA_Channel1,&DMA_InitStructure);

  前面那些都是對DMA結構體成員的設置,在次再統一對DMA整個模塊做一次初始化,使得DMA各成員與上面的參數一致。 

  /*DMA Enable*/

  DMA_Cmd(DMA_Channel1,ENABLE);

  哈哈哈!這一句我想我就不羅嗦了,大家一看就明白。 

至此,整個DMA總算設置好了,但是,DMA通道又是怎樣與外設聯系在一起的呢?哈哈,這也是我當初最想知道的一個事情,別急!容我想喝口茶~~~~~~哈哈哈!

要使DMA與外設建立有效連接,這不是DMA自身的事情,是各個外設的事情,每個外設都有 一個xxx_DMACmd(XXXx,Enable )函數,如果使DMA與SPI建立有效聯系,就使用SPI_I2S_DMACmd(SPI1,SPI_I2S_DMAReq_Rx,ENABLE);

具體代碼如下:

 

void DMA_Configuration_SPI1_RX(u16 bufsize)
{
  DMA_DeInit(DMA1_Channel2);
  DMA_InitStructure.DMA_PeripheralBaseAddr =(u32)&SPI1->DR;;
  DMA_InitStructure.DMA_MemoryBaseAddr = (u32)Usart_TX_Buf;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;   // DMA單向傳輸
  DMA_InitStructure.DMA_BufferSize = bufsize;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;   // DMA內存地址自動增加模式
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;     // 循環模式
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  DMA_Init(DMA1_Channel2, &DMA_InitStructure);
}

/* 使用軟件模擬SPI讀寫時序,進行初始化 */
void ADS8345_PORT_INIT( void ) 
{
  SPI_InitTypeDef SPI_InitStructure;
  GPIO_InitTypeDef GPIO_InitStructure;


 /*spi1 port_init*/
    /* Configure SPI1 pins: SCK, NSS and MOSI ---------------------------------*/
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7 ;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  GPIO_SetBits(GPIOA,GPIO_Pin_3);

  /*miso*/
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure) ;

          /* Configure SPI1 pins:  NSS ---------------------------------*/
  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_4 ;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  GPIO_SetBits(GPIOA,GPIO_Pin_4);

  /* SPI1 Configuration (Master Tx, 14 MBaud) --------------------------------*/
  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
  SPI_InitStructure.SPI_Mode =  SPI_Mode_Master;
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;
  SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; 
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; 
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
  SPI_InitStructure.SPI_CRCPolynomial = 7;  
  SPI_Init(SPI1, &SPI_InitStructure); 
  /* Enable SPI1 */
  SPI_Cmd(SPI1, ENABLE);
}

 

void RCC_Configuration(void)
{
  /* RCC system reset(for debug purpose) */
  RCC_DeInit();

  /* Enable HSE */
  RCC_HSEConfig(RCC_HSE_ON);

  /* Wait till HSE is ready */
  HSEStartUpStatus = RCC_WaitForHSEStartUp();

  if(HSEStartUpStatus == SUCCESS)
  {
    /* Enable Prefetch Buffer */
    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

    /* Flash 2 wait state */
    FLASH_SetLatency(FLASH_Latency_2);
 
    /* HCLK = SYSCLK */
    RCC_HCLKConfig(RCC_SYSCLK_Div1);
 
    /* PCLK2 = HCLK */
    RCC_PCLK2Config(RCC_HCLK_Div1);

    /* PCLK1 = HCLK/2 */
    RCC_PCLK1Config(RCC_HCLK_Div2);

    /* ADCCLK = PCLK2/4 */
    RCC_ADCCLKConfig(RCC_PCLK2_Div4);
 
    /* PLLCLK = 8MHz * 7 = 56 MHz */
    RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_7);

    /* Enable PLL */
    RCC_PLLCmd(ENABLE);

    /* Wait till PLL is ready */
    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
    {
    }

    /* Select PLL as system clock source */
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

    /* Wait till PLL is used as system clock source */
    while(RCC_GetSYSCLKSource() != 0x08)
    {
    }
  }

  /* Enable DMA clock */
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

  /* Periph clock enable */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_SPI1, ENABLE);                 
}

 

 在main中:

 

    RCC_Configuration();    
     /* System tick init */
    delay_init( 72);    
    ADS8345_PORT_INIT();
     /* SPI RX DMA enable */
    DMA_Configuration_SPI1_R( 2);
//      NVIC_Configuration();
    DMA_Cmd(DMA1_Channel2,ENABLE);    
    SPI_I2S_DMACmd(SPI1,SPI_I2S_DMAReq_Rx,ENABLE);
    DMA_ITConfig(DMA1_Channel2, DMA_IT_TC | DMA_IT_HT, ENABLE);
 

然后直接就可以去Usart_TX_Buf中讀數了!

 


免責聲明!

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



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