直接上代码:
bsp_spi_flash.c
/**
******************************************************************************
* @file bsp_spi_flash.c
* @author STMicroelectronics
* @version V1.0
* @date 2019
* @brief SPI FLASH(W25Q64)应用函数bsp
******************************************************************************
*/
#include "bsp_spi_flash.h"
#include "./usart/bsp_usart.h"
static __IO uint32_t SPITimeout = SPIT_LONG_TIMEOUT;
static uint32_t SPI_TIMEOUT_UserCallback(uint8_t errorCode);
/**
* @brief SPI I/O配置
* @param 无
* @retval 无
*/
static void SPI_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* 使能与 SPI 有关的时钟 */
FLASH_SPI_APBxClock_FUN(FLASH_SPI_CLK, ENABLE);
FLASH_SPI_GPIO_APBxClock_FUN(FLASH_SPI_GPIO_CLK, ENABLE);
/* MISO MOSI SCK */
GPIO_InitStructure.GPIO_Pin = FLASH_SPI_SCK_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // SCK 推挽复用
GPIO_Init(FLASH_SPI_SCK_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MOSI_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // MOSI 推挽复用
GPIO_Init(FLASH_SPI_MOSI_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MISO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // MOSI 浮空输入
GPIO_Init(FLASH_SPI_MISO_PORT, &GPIO_InitStructure);
// 初始化CS引脚,使用软件控制,所以直接配置为推挽输出
GPIO_InitStructure.GPIO_Pin = FLASH_SPI_CS_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // CS 推挽输出
GPIO_Init(FLASH_SPI_CS_PORT, &GPIO_InitStructure);
// 拉高CS,使SPI处于空闲状态
FLASH_SPI_CS_HIGH;
}
/**
* @brief SPI 工作模式配置
* @param 无
* @retval 无
*/
static void SPI_Mode_Config(void)
{
SPI_InitTypeDef SPI_InitStructure;
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_High;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 0; // 不使用CRC功能,数值随便写
SPI_Init(FLASH_SPIx, &SPI_InitStructure);
SPI_Cmd(FLASH_SPIx, ENABLE);
}
/**
* @brief I2C 外设(EEPROM)初始化
* @param 无
* @retval 无
*/
void SPI_FLASH_Init(void)
{
SPI_GPIO_Config();
SPI_Mode_Config();
}
// 发送并接收一个字节
uint8_t SPI_FLASH_Send_Byte(uint8_t data)
{
SPITimeout = SPIT_FLAG_TIMEOUT;
// 检查并等待至TX缓冲区为空
while (SPI_I2S_GetFlagStatus(FLASH_SPIx, SPI_I2S_FLAG_TXE) == RESET)
{
if ((SPITimeout--) == 0)
{
return SPI_TIMEOUT_UserCallback(0);
}
}
// 程序执行到此处,TX缓冲区已空
SPI_I2S_SendData(FLASH_SPIx, data);
SPITimeout = SPIT_FLAG_TIMEOUT;
// 检查并等待至RX缓冲区非空
while (SPI_I2S_GetFlagStatus(FLASH_SPIx, SPI_I2S_FLAG_RXNE) == RESET)
{
if ((SPITimeout--) == 0)
{
return SPI_TIMEOUT_UserCallback(0);
}
}
// 程序执行到此处,说明数据发送完毕,并接收到一个字节
return SPI_I2S_ReceiveData(FLASH_SPIx);
}
// 接收一个字节
uint8_t SPI_FLASH_Read_Byte(void)
{
return SPI_FLASH_Send_Byte(DUMMY);
}
// 读取FLASH ID
uint32_t SPI_Read_ID(void)
{
uint32_t flash_id = 0;
// 片选使能
FLASH_SPI_CS_LOW;
SPI_FLASH_Send_Byte(JEDEC_ID); // 发送命令码
flash_id = SPI_FLASH_Read_Byte();
flash_id <<= 8;
flash_id |= SPI_FLASH_Read_Byte();
flash_id <<= 8;
flash_id |= SPI_FLASH_Read_Byte();
FLASH_SPI_CS_HIGH;
return flash_id;
}
// 写入
// Flash写入使能
void SPI_WriteEnable(void)
{
FLASH_SPI_CS_LOW;
SPI_FLASH_Send_Byte(WRITE_ENABLE); // 发送命令码
FLASH_SPI_CS_HIGH;
}
// 擦除Flash指定扇区
void SPI_Erase_Sector(uint32_t addr)
{
SPI_WriteEnable(); // 擦除之前先调用写使能
// 片选使能
FLASH_SPI_CS_LOW;
SPI_FLASH_Send_Byte(ERASE_SECTOR);
SPI_FLASH_Send_Byte((addr >> 16) & (0xFF)); // 发送命令码
SPI_FLASH_Send_Byte((addr >> 8) & (0xFF));
SPI_FLASH_Send_Byte((addr) & (0xFF));
FLASH_SPI_CS_HIGH;
// Flash的擦除需要时间,要通过读取状态寄存器,来判断是否擦除完成
SPI_WaitForWriteEnd();
}
// 读取Flash的内容
void SPI_Read_Data(uint32_t addr, uint8_t *read_buff, uint32_t numByteToRead)
{
// 片选使能
FLASH_SPI_CS_LOW;
SPI_FLASH_Send_Byte(READ_DATA);
SPI_FLASH_Send_Byte((addr >> 16) & (0xFF));
SPI_FLASH_Send_Byte((addr >> 8) & (0xFF));
SPI_FLASH_Send_Byte((addr) & (0xFF));
while (numByteToRead--)
{
*read_buff = SPI_FLASH_Read_Byte();
read_buff++;
}
FLASH_SPI_CS_HIGH;
}
// 向Flash中写入内容(一次最多写256字节)
void SPI_Write_Data(uint32_t addr, uint8_t *write_buff, uint32_t numByteToWrite)
{
SPI_WriteEnable(); // 写入之前先调用写使能
// 片选使能
FLASH_SPI_CS_LOW;
SPI_FLASH_Send_Byte(WRITE_DATA);
SPI_FLASH_Send_Byte((addr >> 16) & (0xFF));
SPI_FLASH_Send_Byte((addr >> 8) & (0xFF));
SPI_FLASH_Send_Byte((addr) & (0xFF));
while (numByteToWrite--)
{
SPI_FLASH_Send_Byte(*write_buff);
write_buff++;
}
FLASH_SPI_CS_HIGH;
SPI_WaitForWriteEnd();
}
// 等待Flash内部时序操作完成
void SPI_WaitForWriteEnd(void)
{
uint8_t status = 0;
// 片选使能
FLASH_SPI_CS_LOW;
SPI_FLASH_Send_Byte(STATUS); // 发送命令码
do
{
status = SPI_FLASH_Read_Byte();
}
while ((status & 0x01) == 1); // SPI 总线忙碌
FLASH_SPI_CS_HIGH;
}
/**
* @brief Basic management of the timeout situation.
* @param errorCode:错误代码,可以用来定位是哪个环节出错.
* @retval 返回0,表示SPI读取失败.
*/
static uint32_t SPI_TIMEOUT_UserCallback(uint8_t errorCode)
{
/* Block communication and all processes */
FLASH_ERROR("SPI 等待超时!errorCode = %d",errorCode);
return 0;
}
/*********************************************END OF FILE**********************/
bsp_spi_flash.h
#ifndef __BSP_SPI_FLASH_H
#define __BSP_SPI_FLASH_H
#include "stm32f10x.h"
/**************************I2C参数定义,I2C1或I2C2********************************/
#define FLASH_SPIx SPI1
#define FLASH_SPI_APBxClock_FUN RCC_APB2PeriphClockCmd
#define FLASH_SPI_CLK RCC_APB2Periph_SPI1
#define FLASH_SPI_GPIO_APBxClock_FUN RCC_APB2PeriphClockCmd
#define FLASH_SPI_GPIO_CLK (RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC)
#define FLASH_SPI_SCK_PORT GPIOA
#define FLASH_SPI_SCK_PIN GPIO_Pin_5
#define FLASH_SPI_MISO_PORT GPIOA
#define FLASH_SPI_MISO_PIN GPIO_Pin_6
#define FLASH_SPI_MOSI_PORT GPIOA
#define FLASH_SPI_MOSI_PIN GPIO_Pin_7
#define FLASH_SPI_CS_PORT GPIOC
#define FLASH_SPI_CS_PIN GPIO_Pin_0
#define DUMMY (0X00)
#define JEDEC_ID (0X9F)
#define ERASE_SECTOR (0X20)
#define STATUS (0X05)
#define READ_DATA (0X03)
#define WRITE_ENABLE (0X06)
#define WRITE_DATA (0X02)
/*等待超时时间*/
#define SPIT_FLAG_TIMEOUT ((uint32_t)0x1000)
#define SPIT_LONG_TIMEOUT ((uint32_t)(10 * SPIT_FLAG_TIMEOUT))
/* CS引脚配置 */
#define FLASH_SPI_CS_HIGH do{GPIO_SetBits(FLASH_SPI_CS_PORT,FLASH_SPI_CS_PIN);}while(0)
#define FLASH_SPI_CS_LOW do{GPIO_ResetBits(FLASH_SPI_CS_PORT,FLASH_SPI_CS_PIN);}while(0)
/*信息输出*/
#define FLASH_DEBUG_ON 0
#define FLASH_INFO(fmt,arg...) printf("<<-FLASH-INFO->> "fmt"n",##arg)
#define FLASH_ERROR(fmt,arg...) printf("<<-FLASH-ERROR->> "fmt"n",##arg)
#define FLASH_DEBUG(fmt,arg...) do{
if(EEPROM_DEBUG_ON)
printf("<<-FLASH-DEBUG->> [%d]"fmt"n",__LINE__, ##arg);
上一篇:stm32专题十八:详细分析SPI FLASH
下一篇:stm32专题十九:FatFs文件系统简介
推荐阅读
史海拾趣
ABCO公司初创时,电子市场竞争激烈,众多企业争夺市场份额。面对这样的环境,ABCO公司创始人凭借对电子技术的深刻理解,以及敏锐的市场洞察力,选择了专注于某一细分领域——高精度传感器的研发与生产。通过不断优化产品设计,提升产品性能,ABCO公司的传感器逐渐在市场上获得认可,为公司的起步奠定了坚实基础。
随着国内市场的饱和,ABCO公司开始将目光投向海外市场。公司制定了国际化战略,通过在海外设立分支机构、建立销售网络等方式,逐步拓展国际市场。同时,ABCO公司还积极与国际知名企业进行合作与交流,学习先进的管理经验和技术,为公司的国际化发展提供了有力支持。
这五个故事展示了ABCO公司在电子行业发展中不断挑战自我、追求卓越的过程。通过技术创新、市场拓展、质量管理以及国际化战略的实施,ABCO公司逐渐发展成为一家具有竞争力的电子企业。
进入80年代,随着电子技术的不断进步和应用领域的拓宽,Hokuriku Electric意识到单一产品线的局限性。于是,公司开始实施多元化产品战略,相继推出了传感器、贴片保险丝、机械零件、电路基板等一系列新产品。这些产品不仅丰富了公司的产品线,还进一步巩固了其在电子行业中的地位。通过多元化布局,Hokuriku Electric成功抵御了市场波动带来的风险,实现了持续稳定的增长。
随着公司业务的不断发展,Data Translation开始寻求全球扩张的机会。公司通过设立海外分支机构、与当地企业合作等方式,成功将产品推向全球市场。同时,公司还加大了品牌建设的力度,通过参加国际展会、发布新产品等方式提高品牌知名度。这些举措不仅为公司带来了更多的客户和合作伙伴,还进一步巩固了其在全球数据采集和处理领域的领先地位。
在经历了多次的收购与转手后,MACOM公司重新获得了独立地位,并开始了新的发展历程。公司推出了首个GaN功率器件,这一技术创新在行业内引起了广泛关注。随后,MACOM继续通过收购微波和射频公司MIMIX以及高速光通信公司Optomai来扩展其业务范围。这些举措不仅增强了公司的技术实力,也为其在全球市场上取得竞争优势奠定了基础。
随着公司规模的扩大,中汇瑞德意识到,要想在激烈的市场竞争中保持领先地位,必须不断进行科技创新。于是,公司加大了对研发的投入,引进了一批高素质的研发人才,并建立了完善的研发体系。在研发团队的努力下,公司成功开发出了多款具有自主知识产权的新型继电器产品,不仅提高了产品的性能和质量,还降低了生产成本,赢得了客户的广泛好评。
GPS系统在出租车行业的应用 GPS系统在出租车行业的应用主要体现在灵活的出租车调度系统中,用户只需要拨打调度中心电话,中心将自动寻找最近的空车,在电话还没挂断之前,便可以告诉乘客“车牌号为XXX的车将在X分钟之内到达。”这种"叫车服 ...… 查看全部问答∨ |
|
在调程序的时候老是出错,然后单步跟发现问题出在ldr伪指令上,于是专门写了个汇编文件在arm上跑了一下,发现一个奇怪的现象 开发环境ADS1.2 整个工程就这一个2410.s文件,全部代码如下: Usr_Size EQU 5 AREA  ...… 查看全部问答∨ |
当一个任务执行过程中出现问题,我想把这个任务的信息Copy到另一个任务中,然启动这个任务,让这个任务开始执行。这里涉及到任务的迁移问题,我知道每个任务的状态信息位于WIND_TCB当中,但是不知道需要保存那些信息的,有没有人做过这个,给些指点 ...… 查看全部问答∨ |
自定义链表是这样的 typedef struct ListNode { char data[20]; ListNode * next; }; 在初始化的时候报Access Violation错,不知从哪更改.有知道的指点一下吧. ListNode *h h = new ListNode; … 查看全部问答∨ |
|
小弟初学ZIGBEE,用的是CROSSO STUDIO的实验板,在刷SerialApp例程做PC串口透传时失败,请做过该例程的高手前辈指点迷津,现象如下: 1.显示屏无显示,(不知是否正常,文件中包含了OLED和LCD的初始化文件了) 2.COOD和router都是红色LED3灯常亮 ...… 查看全部问答∨ |
还没试试WEBENCH在滤波器方面的设计性能咋样呢,今天就试试低通滤波器的效果咋样。这一次要得到一个低通滤波器,截止频率300Hz, 阻带频率800Hz。 设计需求如下: 于是,生成的方案如下: 得到的原理图如下,是一个2阶低通滤波 ...… 查看全部问答∨ |