STM32F103的W25Q64的DMA高效数据访问实现

2019-09-11来源: eefocus关键字:STM32F103  W25Q64  DMA  数据访问

1. 关于DMA

首先任何FLASH的写操作都是非常耗时的,体现在擦除FLASH上,且写操作不能太频繁,故而用DMA方式实现写操作程序逻辑会非常复杂,程序逻辑在各种中断处理中容易乱,与之相反采用DMA读大批量数据时及具有优势.

比如36MHzSPI时种,采用轮询方式读一页数据需要花费250us时间,二用了DMA后只需要80us时间,提高了三倍还多,且启动DMA只需要5us,节省了245us时间.


2. W25Q64实用的函数

① 读ID号,用于确定芯片是否能正常访问

② 轮询方式读数据

③ 擦除指令

④ 写一页数据指令,(事先要擦除)

⑤ DMA方式读取一块数据


3. 程序正文W25Q64.c

/*********************************Copyright (c)*********************************

**                               

**                                 FIVE工作组

**

**---------------------------------File Info------------------------------------

** File Name:               w25q64.c

** Last modified Date:      2013/9/10 9:32:33

** Last Version:            V1.2   

** Description:             none

**

**------------------------------------------------------------------------------

** Created By:              wanxuncpx

** Created date:            2013/8/6 21:12:35

** Version:                 V1.2

** Descriptions:            none

**------------------------------------------------------------------------------

** HW_CMU:                  STM32F103ZET6

** Libraries:               STM32F10x_StdPeriph_Driver

** version                  V3.5

*******************************************************************************/

 

 

/******************************************************************************

更新说明:

******************************************************************************/

 

 

 

 

/******************************************************************************

*********************************  应 用 资 料 ********************************

******************************************************************************/

 

 

 

 

/******************************************************************************

********************************* 文件引用部分 ********************************

******************************************************************************/

#include "w25q64.h"

 

 

/******************************************************************************

********************************* 数 据 声 明 *********************************

******************************************************************************/

/*---------------------* 

*     数据定义(输出)

*----------------------*/

uint8_t W25X_Buffer[W25X_SECTOR_SIZE];

volatile bool sem_W25X_DMA_Busy = true;

volatile bool sem_W25X_DMA_RxRdy= false;

 

 

/*---------------------* 

*       数据定义(内部用) 

*----------------------*/

static uint8_t  W25X_TX_Byte=0xFF;

 

 

 

 

 

 

/******************************************************************************

********************************* 函 数 声 明 *********************************

******************************************************************************/

/******************************************************************************

/ 函数功能:初始化W25Q64的GPIO口连接

/ 修改日期:2013/9/10 19:04:15

/ 输入参数:none

/ 输出参数:none

/ 使用说明:none

******************************************************************************/

void W25X_GPIO_Config(void)

{

/* Private typedef ---------------------------------------------------------*/

GPIO_InitTypeDef GPIO_InitStruct;

 

 

 

 

/** SPI1 GPIO Configuration

PA5 ------> SPI1_SCK

PA6 ------> SPI1_MISO

PA7 ------> SPI1_MOSI

*/

/*Enable or disable APB2 peripheral clock */

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

 

 

/*Configure GPIO pin */

GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;

GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA, &GPIO_InitStruct);

 

 

/** Configure pins as GPIO

PA4 ------> GPIO_Output

PB0 ------> GPIO_Output

*/

/*Enable or disable APB2 peripheral clock */

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE);

    W25X_WP_EN();

W25X_CS_H();

/*Configure GPIO pin */

GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4;

GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA, &GPIO_InitStruct);

 

 

/*Configure GPIO pin */

GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;

GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOB, &GPIO_InitStruct); 

    /*Lock of the gpio */

GPIO_PinLockConfig(GPIOA,GPIO_Pin_4);

GPIO_PinLockConfig(GPIOB,GPIO_Pin_0);

}

 

 

/******************************************************************************

/ 函数功能:初始化W25Q64

/ 修改日期:2013/9/10 19:04:16

/ 输入参数:none

/ 输出参数:none

/ 使用说明:none

******************************************************************************/

void W25X_Init(void)

{

SPI_InitTypeDef  SPI_InitStructure ;

DMA_InitTypeDef  DMA_InitStructure;

NVIC_InitTypeDef NVIC_InitStructure;

    

    //配置DMA通道,DMA1_CH2收

    //读取SPI FLASH时多数为空数据故而数据地址无需增加

    //启动DMA1的时钟

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    DMA_DeInit(DMA1_Channel2);

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

    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)W25X_Buffer;

    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;

    DMA_InitStructure.DMA_BufferSize = 0;

    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;

    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

    DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;

    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

    DMA_Init(DMA1_Channel2, &DMA_InitStructure);

 

 

    //配置DMA通道,DMA1_CH3发送

    DMA_DeInit(DMA1_Channel3);

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

    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)(&W25X_TX_Byte);

    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;

    DMA_InitStructure.DMA_BufferSize = 0;

    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;

    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;

    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;

    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

    DMA_Init(DMA1_Channel3, &DMA_InitStructure);

    

    //关闭DMA,清DMA标记,使能DMA1_CH2的传输完成中断

    DMA_Cmd(DMA1_Channel3, DISABLE);            //关闭发送DMA

    DMA_Cmd(DMA1_Channel2, DISABLE);            //关闭接收DMA

    DMA_ClearFlag(DMA1_FLAG_GL3|DMA1_FLAG_TC3|DMA1_FLAG_HT3|DMA1_FLAG_TE3);

    DMA_ClearFlag(DMA1_FLAG_GL2|DMA1_FLAG_TC2|DMA1_FLAG_HT2|DMA1_FLAG_TE2);

    DMA_ITConfig(DMA1_Channel2,DMA_IT_TC,ENABLE);

    

//初始化SPI时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);

 

 

// SPI配置

SPI_Cmd(SPI1,DISABLE);

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

SPI_InitStructure.SPI_NSS = SPI_NSS_Soft ;

SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2 ;    //72MHz分频

SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB ; //SPI设置成LSB模式

SPI_InitStructure.SPI_CRCPolynomial = 7 ;

SPI_Init( SPI1, &SPI_InitStructure ) ;

SPI_Cmd(SPI1,ENABLE);           //启动SPI

    //打开SPI1的DMA发送接收请求

    SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx, ENABLE);

    SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);

    

    //清DMA忙信号

    sem_W25X_DMA_Busy = false;

    

    //使能NVIC中断

    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel2_IRQn;

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = W25X_DMA_TC_PRIO;

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStructure);

}

 

 

/*********************************************

[1] [2] [3] [4] [5]
关键字:STM32F103  W25Q64  DMA  数据访问 编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/ic474153.html 本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:STM32F103C8T6 Standby低功耗模式
下一篇:STM32L151C8T6 的IAP实现方案

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

stm32入门——跑马灯(基于stm32f103zet6)
的驱动都要使能相应的时钟,首先看stm32系统的时钟框图经查阅资料可知,GPIO的时钟在APB2的外设时钟使能寄存器上,相关函数的定义在stm32f10x_rcc.h中 void   RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)其源代码为:void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState){  /* Check the parameters */ //检查值的有效性&nbs
发表于 2019-10-21
stm32入门——跑马灯(基于stm32f103zet6)
stm32入门——跑马灯(基于stm32f103zet6)
的驱动都要使能相应的时钟,首先看stm32系统的时钟框图经查阅资料可知,GPIO的时钟在APB2的外设时钟使能寄存器上,相关函数的定义在stm32f10x_rcc.h中 void   RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)其源代码为:void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState){  /* Check the parameters */ //检查值的有效性&nbs
发表于 2019-10-21
stm32入门——跑马灯(基于stm32f103zet6)
STM32F103流水灯实验
#include "led.h"//初始化PB5和PE5为输出口.并使能这两个口的时钟     //LED IO初始化void LED_Init(void){  GPIO_InitTypeDef  GPIO_InitStructure;  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOD, ENABLE); //使能PB,PE端口时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8
发表于 2019-10-19
STM32F4 SPI2初始化及收发数据【使用库函数】
我的STM32F4 Discovery上边有一个加速度传感器LIS302DL。在演示工程中,ST的工程师使用这个传感器做了个很令人羡慕的东西:解算开发板的姿态。当开发板倾斜时候,处于最上边的LED点亮,其他LED不亮。同时,用MicroUSB数据线将开发板连接电脑时,开发板就会虚拟成一个鼠标。倾斜开发板时,鼠标指针会向倾斜的方向移动。归根结底,就是牛B的ST工程师用加速度传感器完成了姿态解算。在开发板上,加速度传感器使用了SPI方式用STM32F4芯片进行通信。STM32F4的SPI1 作为主机,与LIS302Dl进行通信,读取或者写入数据。由于我没有使用过STM32的SPI口,因此在板子的空余资源中找到了SPI2接口来做实验
发表于 2019-10-19
使用STM32CubeMX,生成STM32F103ZE SPI3 HAL 工程
1,选择芯片型号为STM32F103ZET6,开始工程,引脚配置如下:主要是RCC,SPI3,和SYS三个模块2,时钟配置,可按下图进行:3,SPI3配置,如下图,配完这一步其它可以不管,直接生成工程。4,生成工程,打开工程手动输入红框中内容。运行:成功输出波形。
发表于 2019-10-18
使用STM32CubeMX,生成STM32F103ZE SPI3 HAL 工程
STM32F103xC 之 SPI 引脚分解
芯片:STM32F103RCT6 (64pin ,256K ,LQFP ,-40~85)对象:spiSPI1连接在APB2总线上;SPI2/3连接在APB1总线上;串行外设接口(SPI)在全双工和单工通信模式下,多达三个SPI能够在从属模式和主模式下以高达18 Mbits / s的速度进行通信。 3位预分频器提供8个主模式频率,并且帧可配置为8位或16位。 硬件CRC生成/验证支持基本的SD卡/ MMC模式。所有SPI都可以由DMA控制器提供服务。内部集成I2S两个标准的I2S接口(与SPI2和SPI3复用)可用,可以在主模式或从模式下运行。 这些接口可以配置为以16/32位分辨率工作,作为输入或输出通道。 支持8 kHz至48
发表于 2019-10-18
小广播
何立民专栏 单片机及嵌入式宝典

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

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