zoukankan      html  css  js  c++  java
  • 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中读数了!

  • 相关阅读:
    JAVA关键字Volatile的特性
    深入理解JAVA虚拟机之JVM性能篇---垃圾回收
    深入理解JAVA虚拟机之JVM性能篇---基础知识点(运行时数据区域)
    Oracle Rac创建表空间及用户
    数据库的事务隔离(转)
    数据库的三大范式和五大约束(转)
    一些常用的操作命令及知识点
    基于tomcat+springMVC搭建基本的前后台交互系统
    MYSQL注入天书之开天辟地
    MYSQL注入天书之前言
  • 原文地址:https://www.cnblogs.com/sankye/p/2459264.html
Copyright © 2011-2022 走看看