历史上的今天
返回首页

历史上的今天

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

正在发生

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

2019-09-11 来源:eefocus

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

推荐阅读

史海拾趣

Heimann Optoelectronics Gmbh公司的发展小趣事

进入2015年后,随着物联网、5G等新兴技术的兴起,光电子器件的市场需求呈现出爆发式增长。Hei Inc Optoelectronic Division敏锐地捕捉到了这一市场趋势,及时调整产品策略,加大了对低功耗、小型化光电子模块的研发力度。公司推出的新一代光电子模块不仅满足了市场对于高效能、低能耗的需求,还凭借其优异的性价比迅速占领了市场份额。这一举措不仅推动了公司的快速增长,还进一步巩固了其在光电子领域的市场地位。

Design Gateway公司的发展小趣事

1985年,泰德·维特(Ted Waitt)和Mike Hammond两位年轻人决定辍学创业。他们利用维特祖母的15,000美元存款作为担保,从银行获得了10,000美元贷款,租用了一台计算机,并准备了一份三页的经营计划。在维特父亲位于爱荷华州苏城的牧场里,他们创办了TIPC Network公司(Gateway的前身)。公司起步时,主要向得克萨斯电脑器械公司销售零配件,并开展计算机邮购业务。得益于直销商业模式,Gateway在短短四个月内就实现了10万美元的销售额。

EUPEC [eupec GmbH]公司的发展小趣事

面对未来市场的机遇和挑战,EUPEC制定了明确的发展战略。公司将继续加大技术创新和研发投入力度,推动电力半导体技术的进步和应用拓展。同时,EUPEC还将加强与国际知名企业的合作与交流,不断提升自身的竞争力和影响力。在应对市场变化和挑战的过程中,EUPEC将始终坚持以客户为中心的理念,为客户提供更优质的产品和服务。

请注意,以上故事是基于EUPEC公司的发展历程和相关信息进行概括和编写的,并非完全基于事实的直接叙述。如需更详细和准确的信息,请参考相关官方资料或新闻报道。

ET Enterprises Ltd公司的发展小趣事

随着技术的不断进步和市场需求的增长,ET Enterprises Ltd公司开始推出多种类型的光电倍增管产品,包括普通可见光型、紫外灵敏型、日盲型等。同时,公司也积极拓展国际市场,与全球各地的客户建立合作关系,进一步巩固了其在光电倍增管领域的领先地位。

Bay Linear Inc公司的发展小趣事

Bay Linear Inc公司一直注重人才培养和团队建设。公司建立了完善的人才培养和激励机制,吸引了一批批优秀的研发人才和管理人才。同时,公司还积极营造团结协作、创新进取的企业文化,使团队成员能够充分发挥自己的才能和潜力,共同推动公司的发展。

科通(COMTEK)公司的发展小趣事

面对快速变化的电子行业市场,科通技术始终坚持以技术创新为驱动,不断推动公司的转型升级。公司加大在研发方面的投入,积极引进先进的技术和设备,提升产品的技术含量和附加值。同时,科通技术还不断拓展业务领域,从单一的元器件分销逐渐发展到提供全方位的技术整合方案和应用方案,为客户提供更加全面、专业的服务。

问答坊 | AI 解惑

uboot引导不了内核!有信息

U-Boot 1.3.2 (Oct 17 2008 - 17:27:52) DRAM:  64 MB Flash:  1 MB NAND:  NAND flash probing at 0x4E000000 U-Boot1.3.2   64 MB In:    serial Out:   serial Err:  ...…

查看全部问答>

platform builder 编译问题

Fatal error hit, exiting... makeimg: FATAL ERROR: Command returned non-zero exit code 1 (dec). makeimg: FATAL ERROR: Command returned non-zero exit code 1 (dec). Error PB2505: Error executing #(D:\\wince420\\PUBLIC\\tr\\RelDir\ ...…

查看全部问答>

n95现在报价是多少,准备买一个

n95现在报价是多少,准备买一个…

查看全部问答>

MCU如何解密

记得前几天看到有人问MCU解密的事,正好拿出来分享下。这个资料是一个俄国人写的论文(已经翻译过了),非常不错。写了很多种解密方法,以及解密成本和IC解密的历史等等...希望对大家有帮助吧,嘻嘻。。。 [ 本帖最后由 cat3902982 于 2011-10-8 0 ...…

查看全部问答>

球泡灯里可以看到灯珠

最近在公司的老化产品中认真看了下球泡灯,虽然可以看到里面的灯珠。我们产品灯珠芯片有光宏有晶元的,用乳白罩子。这样怎么可以看到里面的灯珠了,是什么原因也…

查看全部问答>

求2.4G防丢器开发人才

各位工程师大家好,哪位有有开2.4G防丢器的经验吗?本人从事无线通讯业务。目前遇到项目需要开发,想找些合适的工程人才开发,2.4G防丢器项目。在深圳打工永远都是没有保障的,业余的时候应该考虑下自己的事业。如果您时间充裕的话,请与我联络,让 ...…

查看全部问答>

北京昌平区-诚聘软硬件工程师若干

岗位职责 1、从事硬件技术的研究、设计、开发、调试、集成、维护和管理; 2、参与硬件产品项目规划工作,制定具体项目实施方案; 3、整合并优化项目开发所需各种资源; 4、为客户提供完善的硬件解决方案; 任职要求: 1、电子、计算机专业本科 ...…

查看全部问答>

EEWORLD大学堂----Atmel AVR技术的历史

Atmel AVR技术的历史:https://training.eeworld.com.cn/course/43Atmel?AVR?技术已被非常广泛的应用在各种工业,消费,通讯电子产品。您知道它的来源吗?…

查看全部问答>

在IAR中,可以通过Jlink 对MSP430 进行 在线仿真及程序下载吗?

请问 ,在IAR中,可以通过Jlink 对MSP430 进行 在线仿真及程序下载吗? \0\0\0eeworldpostqq…

查看全部问答>

一个极易使用的RTOS

       原创文章,转载请注明出处!   致RTOS新手:预练RTOS,必先学习CPU体系结构,否则看代码只会增加您的烦恼!但如果只是想快速使用,那么这个RTOS就是您的最佳选择.   致高手:祝贺您,OS已经没什么好研究的了,应该研究在 ...…

查看全部问答>