历史上的今天
今天是: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
史海拾趣
|
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: ...… 查看全部问答> |
|
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\ ...… 查看全部问答> |
|
各位工程师大家好,哪位有有开2.4G防丢器的经验吗?本人从事无线通讯业务。目前遇到项目需要开发,想找些合适的工程人才开发,2.4G防丢器项目。在深圳打工永远都是没有保障的,业余的时候应该考虑下自己的事业。如果您时间充裕的话,请与我联络,让 ...… 查看全部问答> |
|
岗位职责 1、从事硬件技术的研究、设计、开发、调试、集成、维护和管理; 2、参与硬件产品项目规划工作,制定具体项目实施方案; 3、整合并优化项目开发所需各种资源; 4、为客户提供完善的硬件解决方案; 任职要求: 1、电子、计算机专业本科 ...… 查看全部问答> |
|
Atmel AVR技术的历史:https://training.eeworld.com.cn/course/43Atmel?AVR?技术已被非常广泛的应用在各种工业,消费,通讯电子产品。您知道它的来源吗?… 查看全部问答> |
|
在IAR中,可以通过Jlink 对MSP430 进行 在线仿真及程序下载吗? 请问 ,在IAR中,可以通过Jlink 对MSP430 进行 在线仿真及程序下载吗? \0\0\0eeworldpostqq… 查看全部问答> |
|
原创文章,转载请注明出处! 致RTOS新手:预练RTOS,必先学习CPU体系结构,否则看代码只会增加您的烦恼!但如果只是想快速使用,那么这个RTOS就是您的最佳选择. 致高手:祝贺您,OS已经没什么好研究的了,应该研究在 ...… 查看全部问答> |




