冗余原理:冗余备份10处,每次取重复值次数最多的那个值,比如备份了10处,8处的值都是各不相同,而2处的值都是123,则取123,但是有个问题:就是比如10份备份中只写入了3处最后保存时的值,这样最后的值不起作用,
也可以加时间挫的方法:读取10个备份中最大的时间挫,然后写入新数据时此挫加一后写入,
读取时,如果10份数据都一样,则读其中随便一份即可,
如果不一样,则读时间挫最大的那份(时间挫不一定读时钟芯片的值,可以从0开始计算,32位的值,每次加一,快到32位数的最大值时10份记录的时间挫全从0开始重新记录)
注意:初版源码,可能有bug,请测试和谨慎使用:
#include "../Middlewares/fatfs/w25q64.h"
#include "core/net.h"
#define rongyu_bak_canshu_bak_count 4 //ÈßÓ౸·Ý4´¦£¬Ã¿´ÎÈ¡ÖØ¸´Öµ×î¶àÇÒʱ¼ä´Á×î´óµÄÄǸöÖµ
#define rongyu_bak_canshu_unit_size 4096*200 //ÿ¸öÈßÓ౸·Ýµ¥Î» µÄ×Ü´óС
//×ܹ²ÐèÒª800K*4=3.2MµÄ´æ´¢¿Õ¼ä
//¼Ç¼¸ñʽ: 20×Ö½Úcanshu_Name£¬150×Ö½Úcanshu_str_value £¬1×Ö½Ú£º ÊÇ·ñÐèÒªÁ´±íʽÀ©Õ¹£¬4×Ö½Ú£ºÊ±¼ä´ì£¬4×Ö½Ú£ºÁ´±íÏÂÒ»ÔªËØµÄË÷Òý £¬1×Ö½Ú£ºÊÇ·ñ±»Á´±íÕ¼Ó㬱£ÁôÀ©Õ¹×Ö½Ú:20×Ö½Ú
#define save_unit_length 200
#define max_time_value 9999999
u8 unit_buf1[save_unit_length*rongyu_bak_canshu_bak_count];
u8 unit_buf1_for_write[save_unit_length];
void write_to_flash_do(int canshuo_index,u32 max_time_st,char* canshu_Name,char * canshu_value){
unsigned char i;
if(max_time_st>(max_time_value-3)){
max_time_st=0;
}
memset(unit_buf1_for_write,0,save_unit_length);
strcpy((char*)unit_buf1_for_write,canshu_Name);
strcpy((char*)&unit_buf1_for_write[20],canshu_value);
unit_buf1_for_write[170]=0;
unit_buf1_for_write[171]=max_time_st&0xff;
unit_buf1_for_write[172]=(max_time_st>>8)&0xff;
unit_buf1_for_write[173]=(max_time_st>>16)&0xff;
unit_buf1_for_write[174]=(max_time_st>>24)&0xff;
for( i=0;i<rongyu_bak_canshu_bak_count;i++){
SPI_Flash_Write_by_earse_ok((u8*)unit_buf1_for_write,i*rongyu_bak_canshu_unit_size+ canshuo_index*save_unit_length,save_unit_length,1);
}
}
//#include "lcd.h"
void save_a_canshu_with_bak(int canshuo_index,char* canshu_Name,char * canshu_value){
u32 max_time_st=0;
unsigned char i;
u8 is_all_same=1;
for( i=0;i<rongyu_bak_canshu_bak_count;i++){
SPI_FLASH_BufferRead(&unit_buf1[save_unit_length*i] , i*rongyu_bak_canshu_unit_size+ canshuo_index*save_unit_length,save_unit_length,1,0);
}
for( i=0;i<(rongyu_bak_canshu_bak_count-1);i++){//¶Ô±ÈÊÇ·ñ4´¦±¸·Ý¶¼Ò»Ñù£º
if(memcmp(&unit_buf1[save_unit_length*i],&unit_buf1[save_unit_length*(i+1)],save_unit_length)!=0){
is_all_same=0;
break;
}
//Èç¹ûÊÇδ²Á³ý¹ýµÄ,È«ÊÇ0xffffffff
if(unit_buf1[save_unit_length*i+171]==0xff && unit_buf1[save_unit_length*i+172]==0xff && unit_buf1[save_unit_length*i+173]==0xff && unit_buf1[save_unit_length*i+174]==0xff ){
is_all_same=2;
break;
}
//Èç¹ûÊÇδ²Á³ý¹ýµÄ,È«ÊÇ0xffffffff
if(unit_buf1[save_unit_length*(i+1)+171]==0xff && unit_buf1[save_unit_length*(i+1)+172]==0xff && unit_buf1[save_unit_length*(i+1)+173]==0xff && unit_buf1[save_unit_length*(i+1)+174]==0xff ){
is_all_same=2;
break;
}
}
if(is_all_same==2){ //Èç¹ûÊÇδ²Á³ý¹ýµÄ,È«ÊÇ0xffffffff
write_to_flash_do(canshuo_index,1,canshu_Name,canshu_value);
}
else
if(is_all_same==1){ //Èç¹ûȫһÑù
max_time_st=unit_buf1[171]+unit_buf1[171+1]*256+unit_buf1[171+2]*256*256+unit_buf1[171+3]*256*256*256;
max_time_st=max_time_st+1;
if(max_time_st>(max_time_value-3)){
max_time_st=0;
}
//LCD_ShowNum(44,55,max_time_st,4,16,RED);
write_to_flash_do(canshuo_index,max_time_st,canshu_Name,canshu_value);
}else{
for( i=0;i<rongyu_bak_canshu_bak_count;i++){
u32 cur_maxtime=0;
SPI_FLASH_BufferRead((u8*)unit_buf1,i*rongyu_bak_canshu_unit_size+ canshuo_index*save_unit_length,save_unit_length,1,0);
cur_maxtime=unit_buf1[171]+unit_buf1[171+1]*256+unit_buf1[171+2]*256*256+unit_buf1[171+3]*256*256*256;
if(cur_maxtime < max_time_value ){//Åųýµô0xffffffff
if(cur_maxtime>max_time_st){
max_time_st=cur_maxtime;
}
}
}
max_time_st=max_time_st+1;
if(max_time_st>(max_time_value-3)){
max_time_st=0;
}
write_to_flash_do(canshuo_index,max_time_st,canshu_Name,canshu_value);
}
}
int is_all_digit(char* str)
{
int i;
for (i = 0; str[i] != '\0'; i++)
{
if (!isdigit(str[i]))
{
return 0;
}
}
return 1;
}
void beep_error();
void test_destory_a_canshu(int canshuo_index){
memset(unit_buf1_for_write,0xff,save_unit_length);
SPI_Flash_Write_by_earse_ok((u8*)unit_buf1_for_write,1*rongyu_bak_canshu_unit_size+ canshuo_index*save_unit_length,save_unit_length,1);
}
void read_a_canshu_with_bak(int canshuo_index,char* canshu_Name,char * out_canshu_str_value,unsigned int * out_value){
u32 max_time_st=0;
unsigned char i;
u8 is_all_same=1;
for( i=0;i<rongyu_bak_canshu_bak_count;i++){
SPI_FLASH_BufferRead(&unit_buf1[save_unit_length*i] , i*rongyu_bak_canshu_unit_size+ canshuo_index*save_unit_length,save_unit_length,1,0);
}
for( i=0;i<(rongyu_bak_canshu_bak_count-1);i++){//¶Ô±ÈÊÇ·ñ4´¦±¸·Ý¶¼Ò»Ñù£º
if(memcmp(&unit_buf1[save_unit_length*i],&unit_buf1[save_unit_length*(i+1)],save_unit_length)!=0){
is_all_same=0;
break;
}
//Èç¹ûÊÇδ²Á³ý¹ýµÄ,È«ÊÇ0xffffffff
if(unit_buf1[save_unit_length*i+171]==0xff && unit_buf1[save_unit_length*i+172]==0xff && unit_buf1[save_unit_length*i+173]==0xff && unit_buf1[save_unit_length*i+174]==0xff ){
is_all_same=2;
break;
}
//Èç¹ûÊÇδ²Á³ý¹ýµÄ,È«ÊÇ0xffffffff
if(unit_buf1[save_unit_length*(i+1)+171]==0xff && unit_buf1[save_unit_length*(i+1)+172]==0xff && unit_buf1[save_unit_length*(i+1)+173]==0xff && unit_buf1[save_unit_length*(i+1)+174]==0xff ){
is_all_same=2;
break;
}
}
if(is_all_same==2){ //Èç¹ûÊÇδ²Á³ý¹ýµÄ,È«ÊÇ0xffffffff
out_canshu_str_value[0]=0;
*out_value=0;
}
else
if(is_all_same==1){ //Èç¹ûȫһÑù
memset(unit_buf1_for_write,0,save_unit_length);
strcpy((char*)unit_buf1_for_write,(char*)&unit_buf1[20]);
memcpy((char*)out_canshu_str_value,(char*)unit_buf1_for_write,strlen((char*)unit_buf1_for_write));
out_canshu_str_value[strlen((char*)unit_buf1_for_write)]=0;
if(is_all_digit(out_canshu_str_value)){
*out_value=atoi(out_canshu_str_value);
}
}else{
u8 i_at_max_time_st=0;
for( i=0;i<rongyu_bak_canshu_bak_count;i++){
u32 cur_maxtime=0;
SPI_FLASH_BufferRead((u8*)unit_buf1,i*rongyu_bak_canshu_unit_size+ canshuo_index*save_unit_length,save_unit_length,1,0);
cur_maxtime=unit_buf1[171]+unit_buf1[171+1]*256+unit_buf1[171+2]*256*256+unit_buf1[171+3]*256*256*256;
if(cur_maxtime < max_time_value ){//Åųýµô0xffffffff
if(cur_maxtime>max_time_st){
max_time_st=cur_maxtime;
i_at_max_time_st=i;
}
}
}
SPI_FLASH_BufferRead((u8*)unit_buf1,i_at_max_time_st*rongyu_bak_canshu_unit_size+ canshuo_index*save_unit_length,save_unit_length,1,0);
memset(unit_buf1_for_write,0,save_unit_length);
strcpy((char*)unit_buf1_for_write,(char*)&unit_buf1[20]);
memcpy((char*)out_canshu_str_value,(char*)unit_buf1_for_write,strlen((char*)unit_buf1_for_write));
out_canshu_str_value[strlen((char*)unit_buf1_for_write)]=0;
if(is_all_digit(out_canshu_str_value)){
*out_value=atoi(out_canshu_str_value);
}
}
}
#include "w25q64.h"
#include "core/net.h"
SemaphoreHandle_t read_write_locker;
u8 writing_or_reading=0;
static SPI_HandleTypeDef hspi;
u8 SPIx_ReadWriteByte(u8 txData)
{
uint8_t Rxdata;
HAL_SPI_TransmitReceive(&hspi,&txData,&Rxdata,1, 1000);
return Rxdata;
}
void SPI_FLASH_CS_LOW(unsigned char index_chip){
if(index_chip==0){//w25q128 for ftp file´æ´¢ºÍweb server ¸ùĿ¼(CS=PI9)
HAL_GPIO_WritePin(GPIOI, GPIO_PIN_7, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOI, GPIO_PIN_8, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOI, GPIO_PIN_10, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOI, GPIO_PIN_9, GPIO_PIN_RESET);
}
if(index_chip==1){//²ÎÊýÅäÖô洢ÓÃ(¶àÉÈÇøÈßÓ౸·Ý£¬·ÇfatÎļþϵͳ)
HAL_GPIO_WritePin(GPIOI, GPIO_PIN_7, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOI, GPIO_PIN_9, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOI, GPIO_PIN_10, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOI, GPIO_PIN_8, GPIO_PIN_RESET);
}
if(index_chip==2){//TF¿¨´¢´æÀúÊ·ÇúÏßÓ㬷ÇfatÎļþϵͳ£¬
HAL_GPIO_WritePin(GPIOI, GPIO_PIN_8, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOI, GPIO_PIN_9, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOI, GPIO_PIN_10, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOI, GPIO_PIN_7, GPIO_PIN_RESET);
}
}
void SPI_FLASH_CS_HIGH(unsigned char index_chip){
if(index_chip==0){//w25q128 for ftp file´æ´¢ºÍweb server ¸ùĿ¼(CS=PI9)
HAL_GPIO_WritePin(GPIOI, GPIO_PIN_7, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOI, GPIO_PIN_8, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOI, GPIO_PIN_10, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOI, GPIO_PIN_9, GPIO_PIN_SET);
}
if(index_chip==1){//²ÎÊýÅäÖô洢ÓÃ(¶àÉÈÇøÈßÓ౸·Ý£¬·ÇfatÎļþϵͳ)
HAL_GPIO_WritePin(GPIOI, GPIO_PIN_7, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOI, GPIO_PIN_9, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOI, GPIO_PIN_10, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOI, GPIO_PIN_8, GPIO_PIN_SET);
}
if(index_chip==2){//TF¿¨´¢´æÀúÊ·ÇúÏßÓ㬷ÇfatÎļþϵͳ£¬
HAL_GPIO_WritePin(GPIOI, GPIO_PIN_8, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOI, GPIO_PIN_9, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOI, GPIO_PIN_10, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOI, GPIO_PIN_7, GPIO_PIN_SET);
}
}
DMA_HandleTypeDef hdma_spi6_rx;
void HAL_SPI_6_MspInit()
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
//if(hspi->Instance==SPI2)
{
/* USER CODE BEGIN SPI2_MspInit 0 */
/* USER CODE END SPI2_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_SPI6_CLK_ENABLE();
__HAL_RCC_BDMA_CLK_ENABLE();
//__HAL_RCC_DMA2_CLK_ENABLE();
hdma_spi6_rx.Instance = BDMA_Channel0;
hdma_spi6_rx.Init.Request = BDMA_REQUEST_SPI6_RX;
hdma_spi6_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_spi6_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi6_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi6_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi6_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi6_rx.Init.Mode = DMA_NORMAL;
hdma_spi6_rx.Init.Priority = DMA_PRIORITY_MEDIUM;
hdma_spi6_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_spi6_rx) != HAL_OK)
{
}
__HAL_LINKDMA(&hspi,hdmarx,hdma_spi6_rx);
/* SPI2 interrupt Init */
HAL_NVIC_SetPriority(SPI6_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(SPI6_IRQn);
HAL_NVIC_SetPriority(BDMA_Channel0_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(BDMA_Channel0_IRQn);
HAL_DMA_MuxRequestGeneratorConfigTypeDef dmamux_ReqGenParams ={0};
dmamux_ReqGenParams.SignalID = HAL_DMAMUX2_REQ_GEN_SPI6_IT;
dmamux_ReqGenParams.Polarity = HAL_DMAMUX_REQ_GEN_RISING_FALLING;
dmamux_ReqGenParams.RequestNumber = 1; /* ???,????1?DMA?? */
HAL_DMAEx_ConfigMuxRequestGenerator(&hdma_spi6_rx, &dmamux_ReqGenParams); /* ??DMAMUX */
HAL_DMAEx_EnableMuxRequestGenerator (&hdma_spi6_rx); /* ??DMAMUX????? */
__HAL_SPI_ENABLE(&hspi);
}
}
u8 oked_recved=0;
void BDMA_Channel0_IRQHandler(void)
{
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_1);
HAL_DMA_IRQHandler(&hdma_spi6_rx);
SPI_FLASH_CS_HIGH(0);
oked_recved=1;
}
void SPI6_IRQHandler(){
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_1);
HAL_SPI_IRQHandler(&hspi);
SPI_FLASH_CS_HIGH(0);
oked_recved=1;
}
/*
*********************************************************************************************************
* ? ? ?: bsp_InitSPIBus
* ????: ??SPI???
* ? ?: ?
* ? ? ?: ?
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* ? ? ?: bsp_InitSPIParam
* ????: ??SPI????,????,??????????
* ? ?: _BaudRatePrescaler SPI????????,???????:
* SPI_BAUDRATEPRESCALER_2 2??
* SPI_BAUDRATEPRESCALER_4 4??
* SPI_BAUDRATEPRESCALER_8 8??
* SPI_BAUDRATEPRESCALER_16 16??
* SPI_BAUDRATEPRESCALER_32 32??
* SPI_BAUDRATEPRESCALER_64 64??
* SPI_BAUDRATEPRESCALER_128 128??
* SPI_BAUDRATEPRESCALER_256 256??
*
* _CLKPhase ????,???????:
* SPI_PHASE_1EDGE SCK????1?????????1???
* SPI_PHASE_2EDGE SCK????2?????????1???
*
* _CLKPolarity ????,???????:
* SPI_POLARITY_LOW SCK????????????
* SPI_POLARITY_HIGH SCK????????????
*
* ? ? ?: ?
*********************************************************************************************************
*/
void bsp_InitSPIParam(uint32_t _BaudRatePrescaler, uint32_t _CLKPhase, uint32_t _CLKPolarity)
{
/* ??SPI?? */
hspi.Instance = SPI6; /* ??SPI */
hspi.Init.BaudRatePrescaler = _BaudRatePrescaler; /* ????? */
hspi.Init.Direction = SPI_DIRECTION_2LINES; /* ??? */
hspi.Init.CLKPhase = _CLKPhase; /* ?????? */
hspi.Init.CLKPolarity = _CLKPolarity; /* ?????? */
hspi.Init.DataSize = SPI_DATASIZE_8BIT; /* ?????? */
hspi.Init.FirstBit = SPI_FIRSTBIT_MSB; /* ???????? */
hspi.Init.TIMode = SPI_TIMODE_DISABLE; /* ??TI?? */
hspi.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; /* ??CRC */
hspi.Init.CRCPolynomial = 7; /* ??CRC?,???? */
hspi.Init.CRCLength = SPI_CRC_LENGTH_8BIT; /* ??CRC?,???? */
hspi.Init.NSS = SPI_NSS_SOFT; /* ???????????? */
hspi.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA; /* ??FIFO???????? */
hspi.Init.NSSPMode = SPI_NSS_PULSE_DISABLE; /* ?????? */
hspi.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE; /* ??SPI?,SPI?????????? */
hspi.Init.Mode = SPI_MODE_MASTER; /* SPI??????? */
/* ???? */
//if (HAL_SPI_DeInit(&hspi) != HAL_OK)
{
//Error_Handler(__FILE__, __LINE__);
}
/* ????? */
if (HAL_SPI_Init(&hspi) != HAL_OK)
{
//Error_Handler(__FILE__, __LINE__);
}
SPIx_ReadWriteByte(0xff);
HAL_SPI_6_MspInit();
}
void bsp_InitSPIBus(void)
{
//g_spi_busy = 0;
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOI_CLK_ENABLE();
__HAL_RCC_SPI6_CLK_ENABLE(); // ??SPI1??
GPIO_InitStruct.Speed=GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Pin = GPIO_PIN_7| GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10; // CS
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOI, GPIO_PIN_7, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOI, GPIO_PIN_8, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOI, GPIO_PIN_9, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOI, GPIO_PIN_10, GPIO_PIN_SET);
GPIO_InitTypeDef GPIO_Initure;
RCC_PeriphCLKInitTypeDef SPI2ClkInit;
__HAL_RCC_GPIOG_CLK_ENABLE(); //ʹÄÜGPIOFʱÖÓ
//__HAL_RCC_SPI6_CLK_ENABLE(); //ʹÄÜSPI2ʱÖÓ
//ÉèÖÃSPI2µÄʱÖÓÔ´
SPI2ClkInit.PeriphClockSelection=RCC_PERIPHCLK_SPI6; //ÉèÖÃSPI6ʱÖÓÔ´
SPI2ClkInit.Spi123ClockSelection=RCC_SPI123CLKSOURCE_PLL; //SPI2ʱÖÓԴʹÓÃPLL1Q
HAL_RCCEx_PeriphCLKConfig(&SPI2ClkInit);
//PB13,14,15
GPIO_Initure.Pin=GPIO_PIN_13|GPIO_PIN_14;
GPIO_Initure.Mode=GPIO_MODE_AF_PP; //¸´ÓÃÍÆÍìÊä³ö
GPIO_Initure.Pull=GPIO_NOPULL;//old=GPIO_PULLUP; //ÉÏÀ
GPIO_Initure.Speed=GPIO_SPEED_FREQ_VERY_HIGH; //GPIO_SPEED_FREQ_VERY_HIGH; //¿ìËÙ
GPIO_Initure.Alternate=GPIO_AF5_SPI6; //¸´ÓÃΪSPI2
HAL_GPIO_Init(GPIOG,&GPIO_Initure); //³õʼ»¯
GPIO_Initure.Pin=GPIO_PIN_12; //MISO
GPIO_Initure.Mode=GPIO_MODE_AF_PP;
GPIO_Initure.Pull=GPIO_NOPULL;
GPIO_Initure.Alternate=GPIO_AF5_SPI6; //ÉÏÀ
GPIO_Initure.Speed=GPIO_SPEED_FREQ_VERY_HIGH ; //GPIO_SPEED_FREQ_VERY_HIGH; //¿ìËÙ
HAL_GPIO_Init(GPIOG,&GPIO_Initure); //³õʼ»¯
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_14, GPIO_PIN_SET);//MISO
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_13, GPIO_PIN_SET);//
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_12, GPIO_PIN_SET);//
read_write_locker = xSemaphoreCreateBinary();
xSemaphoreGive(read_write_locker);
bsp_InitSPIParam(SPI_BAUDRATEPRESCALER_16, SPI_PHASE_1EDGE, SPI_POLARITY_LOW); //old=SPI_PHASE_1EDGE ,SPI_POLARITY_LOW
}
/******************** (C) COPYRIGHT ********************
* ÎļþÃû £ºspi_flash.c
* ÃèÊö £ºspi µ×²ãÓ¦Óú¯Êý¿â
* Ó²¼þÁ¬½Ó ----------------------------
* | PC8-SPI2-NSS : W25X40-CS |
* | PD14-SPI2-SCK : W25X40-CLK |
* | PC7-SPI2-MISO : W25X40-DO |
* | PD13-SPI2-MOSI : W25X40-DIO |
* | PC6-WRITE : W25X40-DIO |
* | PD15-HOLD : W25X40-DIO |
* ----------------------------
* ¿â°æ±¾ £ºST3.0.0
*
* ×÷Õß £º
* ²©¿Í £º
**********************************************************************************/
/* Private typedef -----------------------------------------------------------*/
//#define SPI_FLASH_PageSize 4096
#define SPI_FLASH_PageSize 256
#define SPI_FLASH_PerWritePageSize 256
/* Private define ------------------------------------------------------------*/
#define W25X_WriteEnable 0x06
#define W25X_WriteDisable 0x04
#define W25X_ReadStatusReg 0x05
#define W25X_WriteStatusReg 0x01
#define W25X_ReadData 0x03
#define W25X_FastReadData 0x0B
#define W25X_FastReadDual 0x3B
#define W25X_PageProgram 0x02
#define W25X_BlockErase 0xD8
#define W25X_SectorErase 0x20
#define W25X_ChipErase 0xC7
#define W25X_PowerDown 0xB9
#define W25X_ReleasePowerDown 0xAB
#define W25X_DeviceID 0xAB
#define W25X_ManufactDeviceID 0x90
#define W25X_JedecDeviceID 0x9F
#define WIP_Flag 0x01 /* Write In Progress (WIP) flag */
#define Dummy_Byte 0xFF
void SPI_FLASH_Write_Protect_ENABLE(void)//flash ´ò¿ªÐ´±£»¤
{
SPI_FLASH_Write_Protect_Assert();
}
void SPI_FLASH_Write_Protect_DISABLE(void)//flash ¹Ø±Õд±£»¤
{
SPI_FLASH_Write_Protect_Deassert();
}
void SPI_FLASH_Hold_ENABLE(void)//flash HOLD ENABLE
{
SPI_FLASH_Hold_Assert();
}
void SPI_FLASH_Hold_DISABLE(void)//flash HOLD DISABLE
{
SPI_FLASH_Hold_Deassert();
}
/*******************************************************************************
* Function Name : SPI_FLASH_Init
* Description : Initializes the peripherals used by the SPI FLASH driver.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void SPI_FLASH_Init(void)
{
}
/*******************************************************************************
* Function Name : SPI_FLASH_SectorErase
* Description : Erases the specified FLASH sector.
* Input : SectorAddr: address of the sector to erase.
* Output : None
* Return : None
*******************************************************************************/
void SPI_FLASH_SectorErase(u32 SectorAddr,unsigned char index_chip)
{
/* Send write enable instruction */
SPI_FLASH_WriteEnable(index_chip);
SPI_FLASH_WaitForWriteEnd(index_chip);
/* Sector Erase */
/* Select the FLASH: Chip Select low */
SPI_FLASH_CS_LOW(index_chip);
/* Send Sector Erase instruction */
SPI_FLASH_SendByte(W25X_SectorErase);
/* Send SectorAddr high nibble address byte */
SPI_FLASH_SendByte((SectorAddr & 0xFF0000) >> 16);
/* Send SectorAddr medium nibble address byte */
SPI_FLASH_SendByte((SectorAddr & 0xFF00) >> 8);
/* Send SectorAddr low nibble address byte */
SPI_FLASH_SendByte(SectorAddr & 0xFF);
/* Deselect the FLASH: Chip Select high */
SPI_FLASH_CS_HIGH(index_chip);
/* Wait the end of Flash writing */
SPI_FLASH_WaitForWriteEnd(index_chip);
}
void SPI_Flash_Erase_SectorOK(u32 Dst_Addr,unsigned char index_chip)
{
Dst_Addr*=4096;
SPI_FLASH_WriteEnable(index_chip); //SET WEL
SPI_FLASH_WaitForWriteEnd(index_chip);
SPI_FLASH_CS_LOW(index_chip); //ʹÄÜÆ÷¼þ
SPI_FLASH_SendByte(W25X_SectorErase); //·¢ËÍÉÈÇø²Á³ýÖ¸Áî
SPI_FLASH_SendByte((u8)((Dst_Addr)>>16)); //·¢ËÍ24bitµØÖ·
SPI_FLASH_SendByte((u8)((Dst_Addr)>>8));
SPI_FLASH_SendByte((u8)Dst_Addr);
SPI_FLASH_CS_HIGH(index_chip); //È¡ÏûƬѡ
SPI_FLASH_WaitForWriteEnd(index_chip); //µÈ´ý²Á³ýÍê³É
}
/*******************************************************************************
* Function Name : SPI_FLASH_BulkErase
* Description : Erases the entire FLASH.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void SPI_FLASH_BulkErase(unsigned char index_chip)
{
/* Send write enable instruction */
SPI_FLASH_WriteEnable(index_chip);
/* Bulk Erase */
/* Select the FLASH: Chip Select low */
SPI_FLASH_CS_LOW(index_chip);
/* Send Bulk Erase instruction */
SPI_FLASH_SendByte(W25X_ChipErase);
/* Deselect the FLASH: Chip Select high */
SPI_FLASH_CS_HIGH(index_chip);
/* Wait the end of Flash writing */
SPI_FLASH_WaitForWriteEnd(index_chip);
}
/*******************************************************************************
* Function Name : SPI_FLASH_PageWrite
* Description : Writes more than one byte to the FLASH with a single WRITE
* cycle(Page WRITE sequence). The number of byte can't exceed
* the FLASH page size.
* Input : - pBuffer : pointer to the buffer containing the data to be
* written to the FLASH.
* - WriteAddr : FLASH's internal address to write to.
* - NumByteToWrite : number of bytes to write to the FLASH,
* must be equal or less than "SPI_FLASH_PageSize" value.
* Output : None
* Return : None
*******************************************************************************/
void SPI_FLASH_PageWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite,unsigned char index_chip)
{
/* Enable the write access to the FLASH */
SPI_FLASH_WriteEnable(index_chip);
/* Select the FLASH: Chip Select low */
SPI_FLASH_CS_LOW(index_chip);
/* Send "Write to Memory " instruction */
SPI_FLASH_SendByte(W25X_PageProgram);
/* Send WriteAddr high nibble address byte to write to */
SPI_FLASH_SendByte((WriteAddr & 0xFF0000) >> 16);
/* Send WriteAddr medium nibble address byte to write to */
SPI_FLASH_SendByte((WriteAddr & 0xFF00) >> 8);
/* Send WriteAddr low nibble address byte to write to */
SPI_FLASH_SendByte(WriteAddr & 0xFF);
if(NumByteToWrite > SPI_FLASH_PerWritePageSize)
{
NumByteToWrite = SPI_FLASH_PerWritePageSize;
//printf("\n\r Err: SPI_FLASH_PageWrite too large!");
}
/* while there is data to be written on the FLASH */
while (NumByteToWrite--)
{
/* Send the current byte */
SPI_FLASH_SendByte(*pBuffer);
/* Point on the next byte to be written */
pBuffer++;
}
/* Deselect the FLASH: Chip Select high */
SPI_FLASH_CS_HIGH(index_chip);
/* Wait the end of Flash writing */
SPI_FLASH_WaitForWriteEnd(index_chip);
}
/*******************************************************************************
* Function Name : SPI_FLASH_BufferWrite
* Description : Writes block of data to the FLASH. In this function, the
* number of WRITE cycles are reduced, using Page WRITE sequence.
* Input : - pBuffer : pointer to the buffer containing the data to be
* written to the FLASH.
* - WriteAddr : FLASH's internal address to write to.
* - NumByteToWrite : number of bytes to write to the FLASH.
* Output : None
* Return : None
*******************************************************************************/
void SPI_FLASH_BufferWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite,unsigned char index_chip)
{
u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;
Addr = WriteAddr % SPI_FLASH_PageSize;
count = SPI_FLASH_PageSize - Addr;
NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
if (Addr == 0) /* WriteAddr is SPI_FLASH_PageSize aligned */
{
if (NumOfPage == 0) /* NumByteToWrite < SPI_FLASH_PageSize */
{
SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite,index_chip);
}
else /* NumByteToWrite > SPI_FLASH_PageSize */
{
while (NumOfPage--)
{
SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize,index_chip);
WriteAddr += SPI_FLASH_PageSize;
pBuffer += SPI_FLASH_PageSize;
}
SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle,index_chip);
}
}
else /* WriteAddr is not SPI_FLASH_PageSize aligned */
{
if (NumOfPage == 0) /* NumByteToWrite < SPI_FLASH_PageSize */
{
if (NumOfSingle > count) /* (NumByteToWrite + WriteAddr) > SPI_FLASH_PageSize */
{
temp = NumOfSingle - count;
SPI_FLASH_PageWrite(pBuffer, WriteAddr, count,index_chip);
WriteAddr += count;
pBuffer += count;
SPI_FLASH_PageWrite(pBuffer, WriteAddr, temp,index_chip);
}
else
{
SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite,index_chip);
}
}
else /* NumByteToWrite > SPI_FLASH_PageSize */
{
NumByteToWrite -= count;
NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
SPI_FLASH_PageWrite(pBuffer, WriteAddr, count,index_chip);
WriteAddr += count;
pBuffer += count;
while (NumOfPage--)
{
SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize,index_chip);
WriteAddr += SPI_FLASH_PageSize;
pBuffer += SPI_FLASH_PageSize;
}
if (NumOfSingle != 0)
{
SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle,index_chip);
}
}
}
}
void SPI_Flash_Write_Page(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite,unsigned char index_chip)
{
u16 i;
SPI_FLASH_WriteEnable(index_chip); //SET WEL
SPI_FLASH_CS_LOW(index_chip); //ʹÄÜÆ÷¼þ
SPI_FLASH_SendByte(W25X_PageProgram); //·¢ËÍдҳÃüÁî
SPI_FLASH_SendByte((u8)((WriteAddr)>>16)); //·¢ËÍ24bitµØÖ·
SPI_FLASH_SendByte((u8)((WriteAddr)>>8));
SPI_FLASH_SendByte((u8)WriteAddr);
for(i=0;i<NumByteToWrite;i++){SPI_FLASH_SendByte(pBuffer[i]);}//Ñ»·Ð´Êý
SPI_FLASH_CS_HIGH(index_chip); //È¡ÏûƬѡ
SPI_FLASH_WaitForWriteEnd(index_chip); //µÈ´ýдÈë½áÊø
}
//ÎÞ¼ìÑéдSPI FLASH
//±ØÐëÈ·±£ËùдµÄµØÖ··¶Î§ÄÚµÄÊý¾ÝÈ«²¿Îª0XFF,·ñÔòÔÚ·Ç0XFF´¦Ð´ÈëµÄÊý¾Ý½«Ê§°Ü!
//¾ßÓÐ×Ô¶¯»»Ò³¹¦ÄÜ
//ÔÚÖ¸¶¨µØÖ·¿ªÊ¼Ð´ÈëÖ¸¶¨³¤¶ÈµÄÊý¾Ý,µ«ÊÇҪȷ±£µØÖ·²»Ô½½ç!
//pBuffer:Êý¾Ý´æ´¢Çø
//WriteAddr:¿ªÊ¼Ð´ÈëµÄµØÖ·(24bit)
//NumByteToWrite:ҪдÈëµÄ×Ö½ÚÊý(×î´ó65535)
//CHECK OK
void SPI_Flash_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite,unsigned char index_chip)
{
u16 pageremain;
pageremain=256-WriteAddr%256; //µ¥Ò³Ê£ÓàµÄ×Ö½ÚÊý
if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//²»´óÓÚ256¸ö×Ö½Ú
while(1)
{
SPI_Flash_Write_Page(pBuffer,WriteAddr,pageremain,index_chip);
if(NumByteToWrite==pageremain)break;//дÈë½áÊøÁË
else //NumByteToWrite>pageremain
{
pBuffer+=pageremain;
WriteAddr+=pageremain;
NumByteToWrite-=pageremain; //¼õÈ¥ÒѾдÈëÁ˵Ä×Ö½ÚÊý
if(NumByteToWrite>256)pageremain=256; //Ò»´Î¿ÉÒÔдÈë256¸ö×Ö½Ú
else pageremain=NumByteToWrite; //²»¹»256¸ö×Ö½ÚÁË
}
};
}
//дSPI FLASH
//ÔÚÖ¸¶¨µØÖ·¿ªÊ¼Ð´ÈëÖ¸¶¨³¤¶ÈµÄÊý¾Ý
//¸Ãº¯Êý´ø²Á³ý²Ù×÷!
//pBuffer:Êý¾Ý´æ´¢Çø
//WriteAddr:¿ªÊ¼Ð´ÈëµÄµØÖ·(24bit)
//NumByteToWrite:ҪдÈëµÄ×Ö½ÚÊý(×î´ó65535) £¬Ò»°ãÒ»¸öÇø512Byte,ÕýºÃСÓÚ2¸öSPI_FLASH_BUFµÄ³¤¶È£¬ËùÒÔÎȶ¨£¿£º
u8 SPI_FLASH_BUF[4096];
void SPI_Flash_Write_by_earse_ok(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite,unsigned char index_chip)
{
u32 secpos;
u16 secoff;
u16 secremain;
u16 i;
xSemaphoreTake(read_write_locker , portTICK_PERIOD_MS*4000);//·ÀÖ¹¶àÏ̶߳Áд³åÍ»
writing_or_reading=1;
secpos=WriteAddr/4096;//ÉÈÇøµØÖ· 0~511 for w25x16
secoff=WriteAddr%4096;//ÔÚÉÈÇøÄ򵀮«ÒÆ
secremain=4096-secoff;//ÉÈÇøÊ£Óà¿Õ¼ä´óС
if(NumByteToWrite<=secremain)secremain=NumByteToWrite;//²»´óÓÚ4096¸ö×Ö½Ú
while(1)
{
SPI_FLASH_BufferRead(SPI_FLASH_BUF,secpos*4096,4096,index_chip,1);//¶Á³öÕû¸öÉÈÇøµÄÄÚÈÝ
for(i=0;i<secremain;i++)//УÑéÊý¾Ý
{
if(SPI_FLASH_BUF[secoff+i]!=0XFF)break;//ÐèÒª²Á³ý
}
if(i<secremain)//ÐèÒª²Á³ý
{
SPI_Flash_Erase_SectorOK(secpos,index_chip);//²Á³ýÕâ¸öÉÈÇø
for(i=0;i<secremain;i++) //¸´ÖÆ
{
SPI_FLASH_BUF[i+secoff]=pBuffer[i];
}
SPI_Flash_Write_NoCheck(SPI_FLASH_BUF,secpos*4096,4096,index_chip);//дÈëÕû¸öÉÈÇø
}else SPI_Flash_Write_NoCheck(pBuffer,WriteAddr,secremain,index_chip);//дÒѾ²Á³ýÁ˵Ä,Ö±½ÓдÈëÉÈÇøÊ£ÓàÇø¼ä.
if(NumByteToWrite==secremain)break;//дÈë½áÊøÁË
else//дÈëδ½áÊø
{
secpos++;//ÉÈÇøµØÖ·Ôö1
secoff=0;//Æ«ÒÆÎ»ÖÃΪ0
pBuffer+=secremain; //Ö¸ÕëÆ«ÒÆ
WriteAddr+=secremain;//дµØÖ·Æ«ÒÆ
NumByteToWrite-=secremain; //×Ö½ÚÊýµÝ¼õ
if(NumByteToWrite>4096)secremain=4096; //ÏÂÒ»¸öÉÈÇø»¹ÊÇд²»Íê
else secremain=NumByteToWrite; //ÏÂÒ»¸öÉÈÇø¿ÉÒÔдÍêÁË
}
};
xSemaphoreGive(read_write_locker);
writing_or_reading=0;
}
#define W25X_ReadData 0x03
#define W25X_PageProgram 0x02
#define FLASH_PAGE_SIZE 256
#define FLASH_SECTOR_SIZE 4096
#define FLASH_SECTOR_COUNT 512
#define FLASH_BLOCK_SIZE 65536
#define FLASH_PAGES_PER_SECTOR FLASH_SECTOR_SIZE/FLASH_PAGE_SIZE
//Sector Read
void W25X_Read_Sector(uint32_t nSector, u8* pBuffer,unsigned char index_chip)
{
uint16_t i;
//ÉÈÇøºÅתΪµØÖ·
nSector *= FLASH_SECTOR_SIZE;
SPI_FLASH_CS_LOW(index_chip);
SPIx_ReadWriteByte(W25X_ReadData);
SPIx_ReadWriteByte(((nSector & 0xFFFFFF) >> 16));
SPIx_ReadWriteByte(((nSector & 0xFFFF) >> 8));
SPIx_ReadWriteByte(nSector & 0xFF);
for(i=0;i<FLASH_SECTOR_SIZE;i++)
{
pBuffer[i] = SPIx_ReadWriteByte(0xFF);
}
SPI_FLASH_CS_HIGH(index_chip);
SPI_FLASH_WaitForWriteEnd(index_chip);
}
//Sector Write
void W25X_Write_Sector(uint32_t nSector, u8* pBuffer,unsigned char index_chip)
{
int i,j;
//ÉÈÇøºÅתΪµØÖ·
nSector *= FLASH_SECTOR_SIZE;
//Ò»¸öÉÈÇøÐèÒª¼¸¸öÒ³
for(j=0;j<FLASH_PAGES_PER_SECTOR;j++)
{
SPI_FLASH_WriteEnable(index_chip); //SET WEL
SPI_FLASH_CS_LOW(index_chip);
SPIx_ReadWriteByte(W25X_PageProgram);
SPIx_ReadWriteByte(((nSector & 0xFFFFFF) >> 16));
SPIx_ReadWriteByte(((nSector & 0xFFFF) >> 8));
SPIx_ReadWriteByte(nSector & 0xFF);
for(i=0;i<FLASH_PAGE_SIZE;i++)
SPIx_ReadWriteByte(pBuffer[i]);
pBuffer += FLASH_PAGE_SIZE;
nSector += FLASH_PAGE_SIZE;
SPI_FLASH_CS_HIGH(index_chip);
SPI_FLASH_WaitForWriteEnd(index_chip);
}
}
/*
void SPI_FLASH_BufferRead_Piliang(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead,unsigned char index_chip)
{
SPI_FLASH_CS_LOW(index_chip);
SPI_FLASH_SendByte(W25X_ReadData);
SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);
SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8);
SPI_FLASH_SendByte(ReadAddr & 0xFF);
for(u32 ii=0;ii<NumByteToRead;ii++){
SPI_FLASH_BUF[ii]=0xff;
}
oked_recved=0;
HAL_SPI_TransmitReceive(&hspi,SPI_FLASH_BUF,pBuffer,NumByteToRead, 100);
//HAL_DMA_Start_IT(&hdma_spi6_rx, (uint32_t)SPI6->RXDR, (uint32_t)pBuffer, NumByteToRead);
//HAL_SPI_TransmitReceive_DMA(&hspi,SPI_FLASH_BUF,(u8*) pBuffer, NumByteToRead);
//while(oked_recved==0)
{
}
SPI_FLASH_CS_HIGH(index_chip);
}
*/
/*******************************************************************************
* Function Name : SPI_FLASH_BufferRead
* Description : Reads a block of data from the FLASH.
* Input : - pBuffer : pointer to the buffer that receives the data read
* from the FLASH.
* - ReadAddr : FLASH's internal address to read from.
* - NumByteToRead : number of bytes to read from the FLASH.
* Output : None
* Return : None
*******************************************************************************/
void SPI_FLASH_BufferRead(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead,unsigned char index_chip,u8 inner_read_write_locker)
{
if(inner_read_write_locker==0){
xSemaphoreTake(read_write_locker , portTICK_PERIOD_MS*4000);//·ÀÖ¹¶àÏ̶߳Áд³åÍ»
}
writing_or_reading=1;
/* Select the FLASH: Chip Select low */
SPI_FLASH_CS_LOW(index_chip);
/* Send "Read from Memory " instruction */
SPI_FLASH_SendByte(W25X_ReadData);
/* Send ReadAddr high nibble address byte to read from */
SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);
/* Send ReadAddr medium nibble address byte to read from */
SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8);
/* Send ReadAddr low nibble address byte to read from */
SPI_FLASH_SendByte(ReadAddr & 0xFF);
while (NumByteToRead--) /* while there is data to be read */
{
#ifdef SPI_FLASH_ANALOG
//SPI_FLASH_SendByte(Dummy_Byte);
*pBuffer = SPI_FLASH_ReadByte();//Ä£ÄâSPI ¶ÁÈ¡
#else
/* Read a byte from the FLASH */
*pBuffer = SPI_FLASH_SendByte(Dummy_Byte);
#endif
/* Point to the next location where the byte read will be saved */
pBuffer++;
}
/* Deselect the FLASH: Chip Select high */
SPI_FLASH_CS_HIGH(index_chip);
if(inner_read_write_locker==0){
xSemaphoreGive(read_write_locker);
}
writing_or_reading=0;
}
/*******************************************************************************
* Function Name : SPI_FLASH_ReadID
* Description : Reads FLASH identification.
* Input : None
* Output : None
* Return : FLASH identification
*******************************************************************************/
u32 SPI_FLASH_ReadID(unsigned char index_chip)
{
u32 Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0;
/* Select the FLASH: Chip Select low */
SPI_FLASH_CS_LOW(index_chip);
/* Send "RDID " instruction */
SPI_FLASH_SendByte(W25X_JedecDeviceID);
#ifdef SPI_FLASH_ANALOG
/* Read a byte from the FLASH */
//SPI_FLASH_SendByte(Dummy_Byte);
Temp0 = SPI_FLASH_ReadByte();//Ä£ÄâSPI ¶ÁÈ¡
/* Read a byte from the FLASH */
//SPI_FLASH_SendByte(Dummy_Byte);
Temp1 = SPI_FLASH_ReadByte();//Ä£ÄâSPI ¶ÁÈ¡
/* Read a byte from the FLASH */
//SPI_FLASH_SendByte(Dummy_Byte);
Temp2 = SPI_FLASH_ReadByte();//Ä£ÄâSPI ¶ÁÈ¡
#else
/* Read a byte from the FLASH */
Temp0 = SPI_FLASH_SendByte(Dummy_Byte);
/* Read a byte from the FLASH */
Temp1 = SPI_FLASH_SendByte(Dummy_Byte);
/* Read a byte from the FLASH */
Temp2 = SPI_FLASH_SendByte(Dummy_Byte);
#endif
/* Deselect the FLASH: Chip Select high */
SPI_FLASH_CS_HIGH(index_chip);
Temp = (Temp0 << 16) | (Temp1 << 8) | Temp2;
return Temp;
}
/*******************************************************************************
* Function Name : SPI_FLASH_ReadID
* Description : Reads FLASH identification.
* Input : None
* Output : None
* Return : FLASH identification
*******************************************************************************/
u32 SPI_FLASH_ReadDeviceID(unsigned char index_chip)
{
u32 Temp = 0;
/* Select the FLASH: Chip Select low */
SPI_FLASH_CS_LOW(index_chip);
/* Send "RDID " instruction */
SPI_FLASH_SendByte(W25X_DeviceID);
SPI_FLASH_SendByte(Dummy_Byte);
SPI_FLASH_SendByte(Dummy_Byte);
SPI_FLASH_SendByte(Dummy_Byte);
#ifdef SPI_FLASH_ANALOG
//SPI_FLASH_SendByte(Dummy_Byte);
Temp = SPI_FLASH_ReadByte();//Ä£ÄâSPI ¶ÁÈ¡
#else
/* Read a byte from the FLASH */
Temp = SPI_FLASH_SendByte(Dummy_Byte);
#endif
/* Deselect the FLASH: Chip Select high */
SPI_FLASH_CS_HIGH(index_chip);
return Temp;
}
/*******************************************************************************
* Function Name : SPI_FLASH_StartReadSequence
* Description : Initiates a read data byte (READ) sequence from the Flash.
* This is done by driving the /CS line low to select the device,
* then the READ instruction is transmitted followed by 3 bytes
* address. This function exit and keep the /CS line low, so the
* Flash still being selected. With this technique the whole
* content of the Flash is read with a single READ instruction.
* Input : - ReadAddr : FLASH's internal address to read from.
* Output : None
* Return : None
*******************************************************************************/
void SPI_FLASH_StartReadSequence(u32 ReadAddr,unsigned char index_chip)
{
/* Select the FLASH: Chip Select low */
SPI_FLASH_CS_LOW(index_chip);
/* Send "Read from Memory " instruction */
SPI_FLASH_SendByte(W25X_ReadData);
/* Send the 24-bit address of the address to read from -----------------------*/
/* Send ReadAddr high nibble address byte */
SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);
/* Send ReadAddr medium nibble address byte */
SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8);
/* Send ReadAddr low nibble address byte */
SPI_FLASH_SendByte(ReadAddr & 0xFF);
}
#ifdef SPI_FLASH_HAL
/*******************************************************************************
* Function Name : SPI_FLASH_ReadByte
* Description : Reads a byte from the SPI Flash.
* This function must be used only if the Start_Read_Sequence
* function has been previously called.
* Input : None
* Output : None
* Return : Byte Read from the SPI Flash.
*******************************************************************************/
u8 SPI_FLASH_ReadByte(void)
{
return (SPI_FLASH_SendByte(Dummy_Byte));
}
/*******************************************************************************
* Function Name : SPI_FLASH_SendByte
* Description : Sends a byte through the SPI interface and return the byte
* received from the SPI bus.
* Input : byte : byte to send.
* Output : None
* Return : The value of the received byte.
*******************************************************************************/
u8 SPI_FLASH_SendByte(u8 byte)
{
/* Loop while DR register in not emplty */
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);
/* Send byte through the SPI1 peripheral */
SPI_I2S_SendData(SPI2, byte);
/* Wait to receive a byte */
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);
/* Return the byte read from the SPI bus */
return SPI_I2S_ReceiveData(SPI2);
/*
while(SPI_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);
SPI_SendData(SPI2, byte);
while(SPI_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);
return SPI_ReceiveData(SPI2);
*/
}
/*******************************************************************************
* Function Name : SPI_FLASH_SendHalfWord
* Description : Sends a Half Word through the SPI interface and return the
* Half Word received from the SPI bus.
* Input : Half Word : Half Word to send.
* Output : None
* Return : The value of the received Half Word.
*******************************************************************************/
u16 SPI_FLASH_SendHalfWord(u16 HalfWord)
{
/* Loop while DR register in not emplty */
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);
/* Send Half Word through the SPI1 peripheral */
SPI_I2S_SendData(SPI2, HalfWord);
/* Wait to receive a Half Word */
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);
/* Return the Half Word read from the SPI bus */
return SPI_I2S_ReceiveData(SPI2);
}
#else
//Ä£ÄâSPI
/******************************************************************
- ¹¦ÄÜÃèÊö£ºIOÄ£ÄâSPI£¬·¢ËÍÒ»¸ö×Ö½Ú
- Á¥ÊôÄ£¿é£º
- º¯ÊýÊôÐÔ£ºÄÚ²¿
- ²ÎÊý˵Ã÷£ºdata ÊÇÒª·¢Ë͵Ä×Ö½Ú
- ·µ»ØËµÃ÷£ºÎÞ·µ»Ø
- //×¢£º
******************************************************************/
void SPI_FLASH_SendByte(u8 byt1e)
{
SPIx_ReadWriteByte(byt1e);
}
/******************************************************************
- ¹¦ÄÜÃèÊö£ºIOÄ£ÄâSPI£¬¶Áȡһ¸ö×Ö½Ú
- Á¥ÊôÄ£¿é£º
- º¯ÊýÊôÐÔ£ºÄÚ²¿
- ²ÎÊý˵Ã÷£ºÎÞ
- ·µ»ØËµÃ÷£º·µ»Ø¶Áµ½µÄ×Ö½Ú
******************************************************************/
u8 SPI_FLASH_ReadByte(void) //SPI¶ÁÒ»¸ö×Ö½Ú
{
return SPIx_ReadWriteByte(0xff);;
}
#endif
/*******************************************************************************
* Function Name : SPI_FLASH_WriteEnable
* Description : Enables the write access to the FLASH.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void SPI_FLASH_WriteEnable(unsigned char index_chip)
{
/* Select the FLASH: Chip Select low */
SPI_FLASH_CS_LOW(index_chip);
/* Send "Write Enable" instruction */
SPI_FLASH_SendByte(W25X_WriteEnable);
/* Deselect the FLASH: Chip Select high */
SPI_FLASH_CS_HIGH(index_chip);
}
/*******************************************************************************
* Function Name : SPI_FLASH_WaitForWriteEnd
* Description : Polls the status of the Write In Progress (WIP) flag in the
* FLASH's status register and loop until write opertaion
* has completed.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void SPI_FLASH_WaitForWriteEnd(unsigned char index_chip)
{
u8 FLASH_Status = 0;
/* Select the FLASH: Chip Select low */
SPI_FLASH_CS_LOW(index_chip);
/* Send "Read Status Register" instruction */
SPI_FLASH_SendByte(W25X_ReadStatusReg);
/* Loop as long as the memory is busy with a write cycle */
do
{
#ifdef SPI_FLASH_ANALOG
//SPI_FLASH_SendByte(Dummy_Byte);
FLASH_Status = SPI_FLASH_ReadByte();//Ä£ÄâSPI ¶ÁÈ¡
#else
/* Send a dummy byte to generate the clock needed by the FLASH
and put the value of the status register in FLASH_Status variable */
FLASH_Status = SPI_FLASH_SendByte(Dummy_Byte);
#endif
}
while ((FLASH_Status & WIP_Flag) == SET); /* Write in progress */
/* Deselect the FLASH: Chip Select high */
SPI_FLASH_CS_HIGH(index_chip);
}
//½øÈëµôµçģʽ
void SPI_Flash_PowerDown(unsigned char index_chip)
{
/* Select the FLASH: Chip Select low */
SPI_FLASH_CS_LOW(index_chip);
/* Send "Power Down" instruction */
SPI_FLASH_SendByte(W25X_PowerDown);
/* Deselect the FLASH: Chip Select high */
SPI_FLASH_CS_HIGH(index_chip);
}
//»½ÐÑ
void SPI_Flash_WAKEUP(unsigned char index_chip)
{
/* Select the FLASH: Chip Select low */
SPI_FLASH_CS_LOW(index_chip);
/* Send "Power Down" instruction */
SPI_FLASH_SendByte(W25X_ReleasePowerDown);
/* Deselect the FLASH: Chip Select high */
SPI_FLASH_CS_HIGH(index_chip); //µÈ´ýTRES1
}