STM32F10XX中SPI的DMA发送数据

发布者:心满愿望最新更新时间:2019-04-27 来源: eefocus关键字:STM32F10XX  SPI  DMA  发送数据 手机看文章 扫描二维码
随时随地手机看文章

参考资料:


http://blog.csdn.net/jdh99/article/details/7603029


http://www.openedv.com/posts/list/3159.htm


    上面提到的两篇博文比较详细深刻的说明了DMA的工作方式以及SPI的DMA传输方式的特点。结合对Stm32F103VET6中SPI的DMA传输方式的配置和学习谈谈感受,在看下面的内容之前请先看上面的两篇参考博文,这里就不在说明。


    要使用SPI的DMA功能,首先配置好SPI外设,这里以SPI1为例子。下面的代码初始化了SPI1对应的GPIO以及SPI1工作的模式。


void SpiCC3000Init(void)

{

     SPI_InitTypeDef   SPI_InitStructure;

    GPIO_InitTypeDef  GPIO_InitStructure;

  /*!< Disable SPI */

  SPI_Cmd(SPI_USED, DISABLE);

  

  /*!< DeInitializes the SPI */

  SPI_I2S_DeInit(SPI_USED);

  

  /*!< SPI Periph clock disable */

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2 , DISABLE); 

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1 , DISABLE);   

/*Enable SPI2 Clock */

RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);

  RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE);

/*Enable SPI1 Clock */

RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1 |RCC_APB2Periph_GPIOA,ENABLE);

/*Config  SCLK and MOSI */

GPIO_InitStructure.GPIO_Pin = SPI_CLK_PIN| SPI_MOSI_PIN;// 

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//AF_PP

GPIO_Init(SPI_PORT, &GPIO_InitStructure);

  /*!< Configure SPI pins: MISO */

  GPIO_InitStructure.GPIO_Pin = SPI_MISO_PIN;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;

  GPIO_Init(SPI_PORT, &GPIO_InitStructure);

/*!< Configure SPI pins: CS output high */

GPIO_InitStructure.GPIO_Pin = SPI_CS_PIN;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_Init(SPI_PORT, &GPIO_InitStructure);

GPIO_SetBits(SPI_PORT,SPI_CS_PIN);

  /*!< CC3000 SPI Init */

  SPI_StructInit(&SPI_InitStructure);

  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_Low;  

  SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;

  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;

  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;/* The buadrate is a fraction of the 72MHz clock*/

  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;

SPI_InitStructure.SPI_CRCPolynomial = 7;

  SPI_Init(SPI_USED, &SPI_InitStructure);

  SPI_SSOutputCmd(SPI_USED,ENABLE);//NSS(CS) 

  SPI_Cmd(SPI_USED, ENABLE);

  

  /*Configure SPI for DMA Operation*/

#if defined(ENABLE_SPI_DMA)

  SpiCC3000DMAInit(); 

#else

  SpiRxInterruptClkInit();

#endif

}

    在配置好SPI1以后,配置DMA1功能(选择SPI1的Tx连接到DMA上),因为SPI1对应的DMA功能由DMA1来实现。  下面函数中的DMA时钟将在调用它的函数中开启。

void C3000_DMA_Config(SPI_DMADirection_TypeDef Direction, uint8_t* buffer, uint16_t NumData)

{

#if defined(ENABLE_SPI_DMA)

  DMA_InitTypeDef DMA_InitStructure;

  /* Initialize the DMA_PeripheralBaseAddr member */

  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t )&SPI1->DR; //SPI_DR_BASE; // 

//DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t )&SPI2->DR; //SPI_DR_BASE; // 

  /* Initialize the DMA_MemoryBaseAddr member */

  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)buffer;

   /* Initialize the DMA_PeripheralInc member */

  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

  /* Initialize the DMA_MemoryInc member */

  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

  /* Initialize the DMA_PeripheralDataSize member */

  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

  /* Initialize the DMA_MemoryDataSize member */

  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;

  /* Initialize the DMA_Mode member */

//yichuan

  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

//DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

  /* Initialize the DMA_Priority member */

  DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;

  /* Initialize the DMA_M2M member */

  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

  

  /* If using DMA for Reception */

  if (Direction == SPI_DMA_RX)

  {

    /* Initialize the DMA_DIR member */

    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;

    

    /* Initialize the DMA_BufferSize member */

    DMA_InitStructure.DMA_BufferSize = NumData;

    

    DMA_DeInit(SPI_DMA_RX_CHANNEL);

    

    DMA_Init(SPI_DMA_RX_CHANNEL, &DMA_InitStructure);

  }

   /* If using DMA for Transmission */

  else if (Direction == SPI_DMA_TX)

  { 

    /* Initialize the DMA_DIR member */

    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;

    

    /* Initialize the DMA_BufferSize member */

    DMA_InitStructure.DMA_BufferSize = NumData;

    

    DMA_DeInit(SPI_DMA_TX_CHANNEL);

 

    DMA_Init(SPI_DMA_TX_CHANNEL, &DMA_InitStructure);

  }

#endif

}

   配置好DMA1和SPI1后,要做的事情就是把二者联合起来,且配置DMA1的发送完成中断。

void SpiCC3000DMAInit(void)

  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

 

  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); 

  DMA_DeInit(SPI_DMA_RX_CHANNEL);

  DMA_DeInit(SPI_DMA_TX_CHANNEL);

 

  /* Configure and enable SPI DMA TX Channel interrupt */ 

 // NVIC_RxInt_InitStructure.NVIC_IRQChannel = DMA1_Channel5_IRQn; //SPI2 TX

  NVIC_RxInt_InitStructure.NVIC_IRQChannel = DMA1_Channel3_IRQn;//SPI1 TX // not config the Rx channel

  NVIC_RxInt_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

  NVIC_RxInt_InitStructure.NVIC_IRQChannelSubPriority = 0;//0

  NVIC_RxInt_InitStructure.NVIC_IRQChannelCmd = ENABLE;

  NVIC_Init(&NVIC_RxInt_InitStructure);

 

 

  /* Configure DMA Peripheral but don't send data*/

  C3000_DMA_Config(SPI_DMA_RX, (uint8_t*)wlan_rx_buffer,0); 

 //C3000_DMA_Config(SPI_DMA_TX, (uint8_t*)wlan_tx_buffer,0);

  C3000_DMA_Config(SPI_DMA_TX, (uint8_t*)wlan_tx_buffer,1700);  //buffer is 1700

 

 

    /* Enable SPI DMA request */

  SPI_I2S_DMACmd(SPI_USED,SPI_I2S_DMAReq_Tx, ENABLE);

  SPI_I2S_DMACmd(SPI_USED,SPI_I2S_DMAReq_Rx, ENABLE);

  /* Enable the DMA Channels Interrupts */

  /*It should be put after the DMA config  */

  DMA_ITConfig(SPI_DMA_TX_CHANNEL, DMA_IT_TC, ENABLE); 

 

  /* Enable DMA RX Channel */

  DMA_Cmd(SPI_DMA_RX_CHANNEL, ENABLE);  

/*Note: Enable the SPI_DMA Channel,it begin SPI translate*/

  /* Enable DMA TX Channel ,begin the dma translate*/  

  DMA_Cmd(SPI_DMA_TX_CHANNEL, ENABLE); 

}

  这里要强调的是:使能DMA中断标志的语句DMA_ITConfig(SPI_DMA_TX_CHANNEL, DMA_IT_TC, ENABLE); 应当放到DMA1配置完以后,不然发送数据完成以后,不会进入中断处理函数,就是相当于发送完成后产生中断的这个功能并没有配置成功,如果放到DMA1配置前面。下面的图片是参考手册中关于DMA的配置过程,其中中断的使能在第六步,所以应当在DMA初始化完成后,再使能中断功能。


 

    接下来就是中断处理函数了,响应传输完成中断的产生


void DMA1_Channel3_IRQHandler(void)

{

    if(DMA_GetITStatus(DMA1_IT_TC3)==SET)

    {

GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_Init(GPIOC, &GPIO_InitStructure);

GPIO_ResetBits(GPIOC,GPIO_Pin_6);

 

    }

   DMA_ClearITPendingBit(DMA1_IT_TC3);

 

}

最后启动DMA传输是通过DMA_Cmd(SPI_DMA_TX_CHANNEL, ENABLE) 这句话实现,当DMA通道被使能以后,它就自动开始传输数据,而不影响CPU其干其它事情,直到DMA传输完数据产生中断时,CPU才会去处理中断函数。


关键字:STM32F10XX  SPI  DMA  发送数据 引用地址:STM32F10XX中SPI的DMA发送数据

上一篇:谈谈STM32F051的 ADC DMA用法
下一篇:stm32的SPI总结

推荐阅读最新更新时间:2024-11-10 18:17

MSP430 SPI总线详解
SPI总线系统是一种同步串行外设接口;是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议。 许多的芯片都用这种协议通信:EEPROM、Flash、实时时钟、AD转换器、数字信号处理器等:MSP430的USART模块不仅能够实现异步模式(见:MSP430程序库 二 UART异步串口),而且支持同步串行通信(即SPI模式);其SPI支持3线、4线操作,支持主机模式和从机模式,字符长度可以7位或8位等。由于要用AD7708芯片完成AD采样,AD7708是通过SPI与其它设备通信的;本程序比较简化,
[单片机]
MSP430 <font color='red'>SPI</font>总线详解
STM32F10x_SPI (硬件接口 + 软件模拟)读写Flash(25Q16)
Ⅰ、写在前面 SPI(Serial Perripheral Interface)串行外设通信接口,主要实现设备(主从)之间的通信。硬件上由CS、SCK、MISO、MOSI四根通信线连接而成。关于SPI更多介绍不再详细描述,本文主要以STM32F103为主机、W25Q16为从机进行SPI通信实验。 本文将提供STM32硬件SPI、软件模拟SPI两实例工程代码供大家参考、掌握两种方式的区别。 STM32硬件SPI:控制简单、运行效率高、使用方便等。 软件模拟SPI:移植性强,只需要简单修改接口,就能在其他MCU芯片(如:51、430等)上使用。 实例实验效果: 两个实例SPI通信控制方式不一样,但实验效果是一样的。 W25Q16设
[单片机]
STM32F10x_<font color='red'>SPI</font> (硬件接口 + 软件模拟)读写Flash(25Q16)
stm32---SPI与外部FLASH
stm32外部flash是EN25QXX 芯片 使用 STM32F1 的 SPI 和外部 FLASH(EN25QXX)进行通信,实现数据的读写 操作。本章要实现的功能是:首先检测外部 FLASH 是否正常,然后使用 K__UP 和 K_DOWN 键控制 FLASH 的写入和读取,并将 数据显示在 串口助手上,同时控制 D1 指示灯不断闪烁,提示系统正常 运行 W25Q128 将 16M 的容量分为 256 个块( Block),每个块大小为 64K 字 节,每个块又分为 16 个扇区( Sector),每个扇区 4K 个字节。 W25Q128 的最小擦除单位为一个扇区,也就是每次必须擦除 4K 个字节。这样我们需要给 W2
[单片机]
STM32-DMA学习笔记
DMA,全称为:Direct Memory Access,即直接存储器访问。DMA传输方式无需CPU 直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为RAM 与I/O设备开辟一条直接传送数据的通路,能使CPU 的效率大为提高。 STM32中 DMA1有7个通道,DMA2有5个通道(DMA2 仅存在大容量产品中)。DMA挂载的时钟为AHB总线,其时钟为72Mhz,所以可以实现高速数据搬运。 STM32F103RBT6 只有1 个DMA控制器,DMA1 ,下面我们就针对DMA1 进行介绍。 从外设(TIMx、ADC、SPIx 、I2Cx 和USARTx )产生的DMA请求,通过逻辑
[单片机]
stm8s 开发SPI的两种方法
1: void GPIO_Configuration(void) Add GPIOA configuration void GPIO_Configuration(void) { GPIO_DeInit(GPIOD); /* Configure PD0 (LED1) as output push-pull low (led switched on) */ GPIO_Init(GPIOD, GPIO_PIN_0, GPIO_MODE_OUT_PP_LOW_FAST); /* GPIOD reset */ GPIO_DeInit(GPIOC); /* Configure PD0 (LED
[单片机]
stm8s 开发<font color='red'>SPI</font>的两种方法
STM32CUBEMX(3)--ADC通过DMA方式采样,USART打印
概述 直接存储器访问( DMA )用于在外设与存储器之间以及存储器与存储器之间提供高速数据传输。可以在无需任何 CPU 操作的情况下通过DMA快速传输传输。这样节省的CPU资源可供其它操作使用。 DMA允许在后台执行数据传输,无需Cortex-MO 处理器 干预。在此操作过程中,主处理器可以执行其它任务,仅当整个数据块需要处理时,才会中断主处理器。这样即使传输大量数据也不会对系统性能造成太大影响。 DMA主要用于为不同的外设模块实现集中数据缓冲存储(通常在系统S RAM 中)。与分布式解决方案(其中每个外设都需要实现自己的本地数据存储)相比,DMA解决方案在硅片成本和功耗方面的成本较低。 根据使用的 产品 型号的不同,有一个或
[单片机]
STM32CUBEMX(3)--ADC通过<font color='red'>DMA</font>方式采样,USART打印
STM32Cube-直接存储器访问(DMA
在USART章节讲解了串口的轮询和中断模式,这一章介绍一下通过DMA模式控制串口传输。 直接存储器访问 (DMA) 用于在外设与存储器之间以及存储器与存储器之间提供高速数据传输。可以在无需任何 CPU 操作的情况下通过 DMA 快速移动数据。这样节省的 CPU 资源可供其它操作使用。说白了DMA就是一个搬运工,将数据从一个地方搬到另一个地方而不需要CPU处理。 作为一个搬运工,要他正常工作必须要确定几个重要的参数。 1.传输模式:数据从哪里搬到哪里。三种可能的传输方向:存储器到外设、外设到存储器或存储器到存储器。 2.通道选择:就是数据传输的是走那条道路 3.仲裁器:多个DMA传输是优先级高的优先传输。 4
[单片机]
STM32Cube-直接存储器访问(<font color='red'>DMA</font>)
如何利用isoSPI数据链路实现高性能车载电池管理系统?
   引言   对于被设计到HEV、PHEV和EV动力传动系统中的电池组而言,实现高可靠性、高性能和长寿命的关键因素之一是电池管理系统(BMS)中所使用的电子组件。目前为止,大部分电池组设计采用了集中式的实用BMS硬件,局限于在规模较大的装配中。特别是,电池和相关设备的电气噪声工作环境对数据通信链路提出了非常严格的要求,而通信链路承载了车内关键信息的传输。应用广泛的CANbus能够处理这类噪声,但是原始BMS数据的数据吞吐量需求及其相关组件成本导致无法在结构化吸引的设计中采用模块化和分布式电池模块,特别是在提供好的分配重量上。运用标准芯片级串行外设接口(SPI)的isoSPI物理层自适应技术,从而释放成了本效益型分布式电池组架构
[电源管理]
如何利用isoSPI<font color='red'>数据</font>链路实现高性能车载电池管理系统?
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved