硬件SPI读写FLASH
SPI Flash 芯片(U6)
型号: W25Q80DVSNIG,这是一种串行外设接口(SPI)闪存芯片,常用于存储数据。
引脚功能:
- VCC (引脚 8): 电源输入,连接到 3.3V 电源。
- GND (引脚 4): 地线,连接到地(GND)。
- CS (引脚 1): 片选信号,用于选择该 SPI 设备。
- CLK (引脚 6): 时钟信号,由主设备(微控制器)提供,用于同步数据传输。
- DI/IQ0 (引脚 5): 数据输入(Master Out Slave In, MOSI),主设备向从设备发送数据。
- DO/IQ1 (引脚 2): 数据输出(Master In Slave Out, MISO),从设备向主设备发送数据。
- WP/IQ2 (引脚 3): 写保护信号,用于防止意外写入或擦除操作。
- HOLD/IQ3 (引脚 7): 持续信号,用于暂停当前操作。
2.dsp_spi.c
#include "dsp_spi.h"
#define SPI_FLASH_CS_H() SPI_CSInternalSelected(SPI1, DISABLE)
#define SPI_FLASH_CS_L() SPI_CSInternalSelected(SPI1, ENABLE)
volatile SPI_RxTx_TypeDef SPI_RxStruct;
volatile SPI_RxTx_TypeDef SPI_TxStruct;
void SPI_Configure(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
SPI_InitTypeDef SPI_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
SPI_StructInit(&SPI_InitStruct);
SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStruct.SPI_DataWidth = 8;
SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;
SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_Init(SPI1, &SPI_InitStruct);
SPI_BiDirectionalLineConfig(SPI1, SPI_Enable_RX);
SPI_BiDirectionalLineConfig(SPI1, SPI_Enable_TX);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_0);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_0);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_0);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_0);
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStruct);
NVIC_InitStruct.NVIC_IRQChannel = SPI1_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
SPI_ITCmd(SPI1, ENABLE);
SPI_Cmd(SPI1, ENABLE);
}
void SPI_RxData_Interrupt(uint8_t *Buffer, uint8_t Length)
{
uint8_t i = 0;
for (i = 0; i < Length; i++)
{
SPI_RxStruct.Buffer[i] = 0;
SPI_TxStruct.Buffer[i] = 0;
}
SPI_RxStruct.Length = Length;
SPI_RxStruct.CurrentCount = 0;
SPI_RxStruct.CompleteFlag = 0;
SPI_TxStruct.Length = Length;
SPI_TxStruct.CurrentCount = 0;
SPI_TxStruct.CompleteFlag = 0;
SPI_ITConfig(SPI1, SPI_IT_RX, ENABLE);
SPI_ITConfig(SPI1, SPI_IT_TX, ENABLE);
while (0 == SPI_TxStruct.CompleteFlag)
{
}
while (0 == SPI_RxStruct.CompleteFlag)
{
}
for (i = 0; i < Length; i++)
{
Buffer[i] = SPI_RxStruct.Buffer[i];
}
}
void SPI_TxData_Interrupt(uint8_t *Buffer, uint8_t Length)
{
uint8_t i = 0;
for (i = 0; i < Length; i++)
{
SPI_RxStruct.Buffer[i] = 0;
SPI_TxStruct.Buffer[i] = Buffer[i];
}
SPI_RxStruct.Length = Length;
SPI_RxStruct.CurrentCount = 0;
SPI_RxStruct.CompleteFlag = 0;
SPI_TxStruct.Length = Length;
SPI_TxStruct.CurrentCount = 0;
SPI_TxStruct.CompleteFlag = 0;
SPI_ITConfig(SPI1, SPI_IT_RX, ENABLE);
SPI_ITConfig(SPI1, SPI_IT_TX, ENABLE);
while (0 == SPI_TxStruct.CompleteFlag)
{
}
while (0 == SPI_RxStruct.CompleteFlag)
{
}
}
void SPI_FLASH_RxBuffer(uint8_t *Buffer, uint8_t Length)
{
if (Length)
{
SPI_RxData_Interrupt(Buffer, Length);
}
}
void SPI_FLASH_TxBuffer(uint8_t *Buffer, uint8_t Length)
{
if (Length)
{
SPI_TxData_Interrupt(Buffer, Length);
}
}
void SPI_FLASH_ReadDeviceID(void)
{
uint8_t Command[4] =
{
0x90, 0xFF, 0xFF, 0x00
};
uint8_t Buffer[2];
uint16_t DeviceID = 0;
SPI_FLASH_CS_L();
SPI_FLASH_TxBuffer(Command, 0x04);
SPI_FLASH_RxBuffer(Buffer, 0x02);
SPI_FLASH_CS_H();
DeviceID = Buffer[0];
DeviceID <<= 8;
DeviceID |= Buffer[1];
printf("\r\nSPI Flash DeviceID : 0x%04x", DeviceID);
}
void SPI_FLASH_ReadJEDEC_ID(void)
{
uint8_t Command = 0x9F;
uint8_t Buffer[3];
uint32_t JEDEC_ID = 0;
SPI_FLASH_CS_L();
SPI_FLASH_TxBuffer(&Command, 0x01);
SPI_FLASH_RxBuffer(Buffer, 0x03);
SPI_FLASH_CS_H();
JEDEC_ID = Buffer[0];
JEDEC_ID <<= 8;
JEDEC_ID |= Buffer[1];
JEDEC_ID <<= 8;
JEDEC_ID |= Buffer[2];
printf("\r\nSPI Flash JEDEC ID : 0x%06x", JEDEC_ID);
}
void SPI_FLASH_WaitBusy(void)
{
uint8_t Status = 0;
uint8_t Command[2] =
{
0x05, 0xFF
};
uint32_t Timeout = 0;
do
{
SPI_FLASH_CS_L();
SPI_FLASH_TxBuffer(Command, 0x02);
SPI_FLASH_RxBuffer(&Status, 0x01);
SPI_FLASH_CS_H();
if (Timeout++ > 0xFFFF)
{
break;
}
}
while (Status & 0x01);
}
void SPI_FLASH_WriteEnable(void)
{
uint8_t Command = 0x06;
SPI_FLASH_CS_L();
SPI_FLASH_TxBuffer(&Command, 0x01);
SPI_FLASH_CS_H();
}
void SPI_FLASH_SectorErase(uint16_t Index)
{
uint8_t Command[4] =
{
0x20, 0x00, 0x00, 0x00
};
uint32_t Address = Index * 4 * 1024;
Command[1] = (uint8_t)((Address >> 16) & 0x000000FF);
Command[2] = (uint8_t)((Address >> 8) & 0x000000FF);
Command[3] = (uint8_t)((Address >> 0) & 0x000000FF);
SPI_FLASH_WriteEnable();
SPI_FLASH_CS_L();
SPI_FLASH_TxBuffer(Command, 4);
SPI_FLASH_CS_H();
SPI_FLASH_WaitBusy();
}
void SPI_FLASH_FastRead(uint32_t Address, uint8_t *Buffer, uint32_t Length)
{
uint8_t Command[5] =
{
0x0B, 0x00, 0x00, 0x00, 0xFF
};
Command[1] = (uint8_t)((Address >> 16) & 0x000000FF);
Command[2] = (uint8_t)((Address >> 8) & 0x000000FF);
Command[3] = (uint8_t)((Address >> 0) & 0x000000FF);
SPI_FLASH_CS_L();
SPI_FLASH_TxBuffer(Command, 0x05);
SPI_FLASH_RxBuffer(Buffer, Length);
SPI_FLASH_CS_H();
}
void SPI_FLASH_PageProgram(uint32_t Address, uint8_t *Buffer, uint32_t Length)
{
uint8_t Command[4] =
{
0x02, 0x00, 0x00, 0x00
};
Command[1] = (uint8_t)((Address >> 16) & 0x000000FF);
Command[2] = (uint8_t)((Address >> 8) & 0x000000FF);
Command[3] = (uint8_t)((Address >> 0) & 0x000000FF);
SPI_FLASH_WriteEnable();
SPI_FLASH_CS_L();
SPI_FLASH_TxBuffer(Command, 0x04);
SPI_FLASH_TxBuffer(Buffer, Length);
SPI_FLASH_CS_H();
SPI_FLASH_WaitBusy();
}
void SPI_Master_FLASH_Interrupt_Sample(void)
{
uint8_t i = 0;
uint8_t WriteBuffer[100], ReadBuffer[100];
const char* helloStr = "Hello 21ic, Hello MM32F0121";
uint8_t strLen = strlen(helloStr);
printf("\r\nTest %s", __FUNCTION__);
SPI_Configure();
SPI_FLASH_ReadDeviceID();
SPI_FLASH_ReadJEDEC_ID();
printf("\r\nSPI FLASH Sector Erase...");
SPI_FLASH_SectorErase(0);
printf("\r\nWriting string: \"%s\"", helloStr);
for (i = 0; i < strLen; i++) {
WriteBuffer[i] = helloStr[i];
}
printf("\r\nSPI FLASH Page Program...");
SPI_FLASH_PageProgram(0, WriteBuffer, strLen);
printf("\r\nSPI FLASH Read...");
SPI_FLASH_FastRead(0, ReadBuffer, strLen);
printf("\r\nRead Data: \"");
for (i = 0; i < strLen; i++) {
printf("%c", ReadBuffer[i]);
}
printf("\"");
printf("\r\nHex Data:");
for (i = 0; i < strLen; i++) {
if (0 == (i % 10)) printf("\r\n");
printf("0x%02x ", ReadBuffer[i]);
}
}
void SPI1_IRQHandler(void)
{
uint8_t Data = 0;
if (SPI_RxStruct.CurrentCount != SPI_TxStruct.CurrentCount)
{
if (SET == SPI_GetITStatus(SPI1, SPI_IT_RX))
{
Data = SPI_ReceiveData(SPI1);
SPI_ClearITPendingBit(SPI1, SPI_IT_RX);
if (0 == SPI_RxStruct.CompleteFlag)
{
SPI_RxStruct.Buffer[SPI_RxStruct.CurrentCount++] = Data;
if (SPI_RxStruct.CurrentCount == SPI_RxStruct.Length)
{
SPI_RxStruct.CompleteFlag = 1;
SPI_ITConfig(SPI1, SPI_IT_TX, DISABLE);
SPI_ITConfig(SPI1, SPI_IT_RX, DISABLE);
}
}
}
}
else
{
if (SET == SPI_GetITStatus(SPI1, SPI_IT_TX))
{
SPI_ClearITPendingBit(SPI1, SPI_IT_TX);
if (0 == SPI_TxStruct.CompleteFlag)
{
SPI_SendData(SPI1, SPI_TxStruct.Buffer[SPI_TxStruct.CurrentCount++]);
if (SPI_TxStruct.CurrentCount == SPI_TxStruct.Length)
{
SPI_TxStruct.CompleteFlag = 1;
}
}
}
}
}
3.dsp_spi.h
#include <stdio.h>
#include "hal_conf.h"
typedef struct
{
uint8_t Buffer[255];
uint8_t Length;
uint8_t CurrentCount;
uint8_t CompleteFlag;
} SPI_RxTx_TypeDef;
extern volatile SPI_RxTx_TypeDef SPI_RxStruct;
extern volatile SPI_RxTx_TypeDef SPI_TxStruct;
void SPI_Master_FLASH_Interrupt_Sample(void);
4.实验现象
|
 共1人点赞
|