历史上的今天

今天是:2024年09月11日(星期三)

正在发生

2019年09月11日 | STM32F103的W25Q64的DMA高效数据访问实现

发布者:心满意足 来源: 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);

}

 

 

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

/ 函数功能:SPI发送一个字节的数据

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

/ 输入参数:none

/ 输出参数:none

/ 使用说明:none

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

uint8_t W25X_ReadWriteByte(uint8_t dat)

{

    while ((SPI1->SR & SPI_I2S_FLAG_TXE) == (uint16_t)RESET);

    SPI1->DR = dat;

    while ((SPI1->SR & SPI_I2S_FLAG_RXNE) == (uint16_t)RESET);

    return (SPI1->DR);

}

 

 

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

/ 函数功能:读取SPI_FLASH的状态寄存器

/ 修改日期:2013/9/10 20:38:48

/ 输入参数:none

/ 输出参数:none

/ 使用说明:none

/   BIT7  6   5   4   3   2   1   0

/   SPR   RV  TB BP2 BP1 BP0 WEL BUSY

[1] [2] [3] [4] [5]
关键字:STM32F103  W25Q64  DMA  数据访问 引用地址:STM32F103的W25Q64的DMA高效数据访问实现

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

推荐阅读

不久前,比特大陆完成新一轮10亿美元融资,投前估值140亿美元,投后估值150亿美元。可以说,国内AI芯片已经成为了资本的宠儿,各路人马你方唱罢我登场。在英伟达统治着AI芯片市场的情况下,国内AI芯片在接连融资的情况下,却罕见一定规模的应用例子,这种现象是不正常的。而且人工智能概念过度炒作,一方面会将中国高校教育带偏,另一方面会使真正需要追赶...
  9月10日,工信部就《新能源汽车动力蓄电池回收服务网点建设和运营指南》公开征求意见。新能源汽车生产及梯次利用等企业应依托回收服务网点加强对本地区废旧动力蓄电池的跟踪。回收服务网点负责收集、分类、贮存及包装废旧动力蓄电池,不得擅自对收集的废旧动力蓄电池进行安全检查外的拆解处理。废旧动力蓄电池应规范移交至综合利用企业进行梯次利用...
专注于引入新品的全球电子元器件授权分销商贸泽电子 (Mouser Electronics) 即日起开始备货HARTING的T1 Industrial单对以太网 (SPE) 产品。HARTING充满创新的T1 Industrial产品被国际电工委员会 (IEC) 选为标准化的SPE插拔面 (IEC 63171-6),只需使用一对电缆就可以通过以太网传输数据,同时还能为使用数据线供电 (PoDL) 的端子提供电源。 贸泽电子分销...
智东西(公众号:zhidxcom)作者 | 健恩编辑 | 云鹏智东西9月11日报道,昨天,世界机器人大会再次在北京亦庄拉开帷幕,智东西记者一大早便跨越整个北京城来到这里打探这场大会的最新消息。世界机器人大会自2015年开始举办,迄今为止已成功举办过5次。它不仅是国内一年一度规模最大的机器人产业顶级展会,也是国内机器人产业风向的集中展示。智东西了解...

史海拾趣

问答坊 | AI 解惑

请问在Protel 99 SE中如何设置图纸尺寸呢?

我现在Protel 99 SE中画电路图,因为图纸很简单也很小,默认的尺寸太大。这样在后面制作印刷电路板不是太大了吗? 呵呵 我这么简单的电路 只需要个13CM*4CM的板子上就可以了。请问我该在哪里设置呢?是不是在画电路图的时候无所谓尺寸大小,而应该 ...…

查看全部问答∨

ADS配置文件.HFC是怎么生成的?

:D 请问各位高手,ADS配置文件.HFC是怎么生成的?用IAR好像是.ICF文件,这东西有什么作用?…

查看全部问答∨

最新电工实用经典线路范例

最新电工实用经典线路范例…

查看全部问答∨

DFT/IDFT Reference Design

Introduction The DFT reference design performs a discrete Fourier transform (DFT) or an inverse DFT (IDFT) of a complex input sequence and produces a complex output sequence. The reference design performs the functions for eith ...…

查看全部问答∨

继续请教workbench3.1的问题,8169驱动添加问题

请问各位在VxWorks6.7操作系统下,用Workbench开发工具怎么把8169 驱动添加进去,内核里看着有8169的选项,只添加那一个就可以了么?还需要其他什么配置啊??…

查看全部问答∨

问一个弱弱的问题,ucosii在初始化定义时 "1 < <20 "是什么意思?

问一个弱弱的问题,ucosii在初始化定义时 "1 < <20 "是什么意思? …

查看全部问答∨

我自己用AT89C51RC制作的工业级等精度频率计,成本只有30几块钱

最近本人利用AT89C51RC制作的等精度频率计,成本不过30几元 频率范围1Hz---20MHz 灵敏度>40mVrms 波形:正弦波,方波,三角波,TTL波 测量精度完全等于你用的晶振(在灵敏度范围内),晶振=10MHz 关于等精度概念请见 http://www.520ic.cn/di ...…

查看全部问答∨

makefsfile.exe软件的使用

  如何在dos环境下将网页文件编程c文件。   如,网页文件存在d盘的fs文件。   我该如何输入命令?谢谢了…

查看全部问答∨

电子工程师的薪资待遇怎么样?

本次调查仅针对电子工程师,看看大家每天顶着巨大工作压力,你尽心尽力的为老板做事,看看老板又是怎么对待我们同行业同事的。大家来说说吧。…

查看全部问答∨
小广播
设计资源 培训 开发板 精华推荐

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

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

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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