源代码:STM32 SPI “DMA”操作W25QXX(16/32/64/128)系列芯片代码详解

本文介绍如何使用STM32的SPI接口结合DMA功能实现与W25Q64闪存芯片的高效数据交换。内容涵盖SPI配置、DMA配置及SPI闪存读写操作的具体实现。

系列文章目录



前言

框架:自己新建库文件夹 取名lib,并按顺序新建spi.c、w25q64.c(根据自己芯片型号)
使用开发板为正点原子mini板演示,开发板上芯片为W25Q64。


一、SPI.h

#ifndef _SPI_H
#define _SPI_H

#include "stm32f10x.h"
#include "system.h"

/*如果不使用SPI_DMA,屏蔽下面define*/
#define	SPI1_DMA

#ifdef	SPI1_DMA
extern u8 SPI_RX_BUFFER[4096];
extern u8 SPI_TX_BUFFER[4096];
#endif

void SPI1_Config(void);			 //初始化SPI1口
void SPI1_SetSpeed(u8 SpeedSet); //设置SPI1速度   
u8 SPI1_ReadWriteByte(u8 TxData);//SPI1总线读写一个字节
	
void SPI1_DMA_Config(void);
void SPI_transmission(u8 *rx_buf,u8 *tx_buf,u16 NumByte);
void SPI_DMA_Read(u8 *rx_buf,u8 *tx_data,u16 NumByte);
void SPI_DMA_Write(u8 *rx_data,u8 *tx_buf,u16 NumByte);
#endif


二、SPI.c

1.SPI配置

#include "SPI.h"
#include "stdio.h"

#define Rx_BFSize  (u8)20
#define Tx_BFSize  (u8)20
#define SPI1_DR_Addr ( (u32)0x4001300C )
u8 Rx_Addr[Rx_BFSize];
u8 Tx_Addr[Tx_BFSize];

/*长度一定要>=数据接收发送大小*/
u8 SPI_RX_BUFFER[4096];	
u8 SPI_TX_BUFFER[4096];

void SPI1_Config(void)
{
   
   	 
	u8 count=0;
	GPIO_InitTypeDef	GPIO_InitStructure;
	SPI_InitTypeDef		SPI_InitStructure;
	
	RCC_APB2PeriphClockCmd( RCC_APB2Periph_SPI1 , ENABLE);
	RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA , ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;	//SCK,MOSI
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);	
	//GPIO_Mode_IN_FLOATING
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;	//MISO
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;	
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);	
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;	//NSS 由软件控制 设置为普通推挽输出
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;	
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);		//初始化GPIOA
	
	GPIO_SetBits(GPIOA,GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);

	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;		//设置SPI工作模式:设置为主SPI
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;		//设置SPI的数据大小:SPI发送接收8位帧结构
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;		//串行同步时钟的空闲状态为高电平
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;	//串行同步时钟的第二个跳变沿(上升或下降)数据被采样
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;		//NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;		//定义波特率预分频的值:波特率预分频值为256
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;	//指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
	SPI_InitStructure.SPI_CRCPolynomial = 7;	//CRC值计算的多项式				//NSS由	软件控制
	
	SPI_Init(SPI1, &SPI_InitStructure);					//初始化SPI1
#ifdef	SPI1_DMA
	SPI_I2S_DMACmd(SPI1,SPI_I2S_DMAReq_Tx,ENABLE);	//使能DMA Tx通道
	SPI_I2S_DMACmd(SPI1,SPI_I2S_DMAReq_Rx,ENABLE);	//使能DMA Rx通道
#endif
	SPI_Cmd(SPI1, ENABLE);							//使能SPI
	SPI_TX_BUFFER[count++]=0xFF;
	SPI_transmission(SPI_RX_BUFFER, SPI_TX_BUFFER, count);	
	
}   

//SPI1速度设置函数
//SPI速度=fAPB2/分频系数
//@ref SPI_BaudRate_Prescaler:SPI_BaudRatePrescaler_2~SPI_BaudRatePrescaler_256  
//fAPB2时钟一般为84Mhz:
void SPI1_SetSpeed(u8 SPI_BaudRatePrescaler)
{
   
   
  assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));//判断有效性
	SPI1->CR1&=0XFFC7;//位3-5清零,用来设置波特率
	SPI1->CR1|=SPI_BaudRatePrescaler;	//设置SPI1速度 
	SPI_Cmd(SPI1,ENABLE); //使能SPI1
} 

2.DMA配置

#ifdef SPI1_DMA
void SPI1_DMA_Config(void)
{
   
   	
	DMA_InitTypeDef DMA_InitStructure;
	
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
	
	/*********************  DMA_Rx  *********************/
	DMA_DeInit(DMA1_Channel2);	//DMA1 通道2 SPI1_RX 
	
	DMA_InitStructure.DMA_BufferSize=Rx_BFSize; //传输数据量的大小
	DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC; 	//DMA传输方向,SRC 外设为数据源
	DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;			//非存储器到存储器传输模式
	DMA_InitStructure.DMA_MemoryBaseAddr=(u32)Rx_Addr;	//数据缓冲区地址
	DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte; //内存数据宽度 数据宽度 8位
	DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;  		//传输数据时候内存地址递增
	DMA_InitStructure.DMA_Mode=DMA_Mode_Normal; 		//内存不循环采集数据
	DMA_InitStructure.DMA_PeripheralBaseAddr=SPI1_DR_Addr;	//SPI1 外设基地址
	DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;  //外设数据宽度 数据宽度 8位
	DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable; 	//传输地址固定不变  ENABLE时下次发送数据地址递增+1
	DMA_InitStructure.DMA_Priority=DMA_Priority_Medium;		//通道优先级
	
	DMA_Init(DMA1_Channel2,&DMA_InitStructure);		//DMA1 通道2 SPI1_RX 
	
	/*********************  DMA_Tx  *********************/
	DMA_DeInit(DMA1_Channel3);	//DMA1 通道3 SPI1_TX 
	
	DMA_InitStructure.DMA_BufferSize=Tx_BFSize; //传输数据量的大小
	DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralDST; 	//DMA传输方向,DST 内存作为数据源
	DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;			//非存储器到存储器传输模式
	DMA_InitStructure.DMA_MemoryBaseAddr=(u32)Tx_Addr;	//数据缓冲区地址
	DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte; //内存数据宽度 数据宽度 8位
	DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;  		//传输数据时候内存地址递增
	DMA_InitStructure.DMA_Mode=DMA_Mode_Normal; 		//内存不循环采集数据
	DMA_InitStructure.DMA_PeripheralBaseAddr=SPI1_DR_Addr;	//SPI1 外设基地址
	DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;  //外设数据宽度 数据宽度 8位
	DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable; 	//传输地址固定不变  ENABLE时下次发送数据地址递增+1
	DMA_InitStructure.DMA_Priority=DMA_Priority_Medium;		//通道优先级
	
	DMA_Init
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小超电子笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值