[RISC-V MCU 应用开发]

【RISC-V MCU CH32V103测评】W25Q16 Flash存储器 Raw数据读写

[复制链接]
643|2
手机看帖
扫描二维码
随时随地手机跟帖
大头哥|  楼主 | 2020-12-3 22:07 | 显示全部楼层 |阅读模式
参考了不少前辈的例程,实践了一下。

测试效果如图所示:


主要更改3个源码文件,2个SPI Flash访问驱动,1个main函数,全部列在此处。
Hardware/spiflash.c
/*****************************************
*@Note
Winbond W25Qxx SPIFLASH
pins:
CS   —— PA2
DO   —— PA6(SPI1_MISO)
WP   —— 3.3V
DI   —— PA7(SPI1_MOSI)
CLK  —— PA5(SPI1_SCK)
HOLD —— 3.3V
*******************************************/
#include "debug.h"
#include "string.h"
#include "spiflash.h"

/* Global define */

/* Global Variable */
u8 SPI_FLASH_BUF[4096];

/*******************************************************************************
* Function Name  : SPI1_ReadWriteByte
* Description    : SPI1 read or write one byte.
* Input          : TxData: write one byte data.
* Return         : Read one byte data.
*******************************************************************************/
u8 SPI1_ReadWriteByte(u8 TxData)
{
    u8 i = 0;

    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET)
    {
        i++;
        if (i > 200)
            return 0;
    }

    SPI_I2S_SendData(SPI1, TxData);
    i = 0;

    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET)
    {
        i++;
        if (i > 200)
            return 0;
    }

    return SPI_I2S_ReceiveData(SPI1);
}

/*******************************************************************************
* Function Name  : SPI_Flash_Init
* Description    : Configuring the SPI for operation flash.
* Input          : None
* Return         : None
*******************************************************************************/
void SPI_Flash_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    SPI_InitTypeDef SPI_InitStructure;

    RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_SetBits(GPIOA, GPIO_Pin_2);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init( GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init( GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init( GPIOA, &GPIO_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_4;
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_InitStructure.SPI_CRCPolynomial = 7;
    SPI_Init(SPI1, &SPI_InitStructure);

    SPI_Cmd(SPI1, ENABLE);
}

/*******************************************************************************
* Function Name  : SPI_Flash_ReadSR
* Description    : Read W25Qxx status register.
*       ——BIT7  6   5   4   3   2   1   0
*       ——SPR   RV  TB  BP2 BP1 BP0 WEL BUSY
* Input          : None
* Return         : byte: status register value.
*******************************************************************************/
u8 SPI_Flash_ReadSR(void)
{
    u8 byte = 0;

    GPIO_WriteBit(GPIOA, GPIO_Pin_2, 0);
    SPI1_ReadWriteByte(W25X_ReadStatusReg);
    byte = SPI1_ReadWriteByte(0Xff);
    GPIO_WriteBit(GPIOA, GPIO_Pin_2, 1);

    return byte;
}

/*******************************************************************************
* Function Name  : SPI_FLASH_Write_SR
* Description    : Write W25Qxx status register.
* Input          : sr:status register value.
* Return         : None
*******************************************************************************/
void SPI_FLASH_Write_SR(u8 sr)
{
    GPIO_WriteBit(GPIOA, GPIO_Pin_2, 0);
    SPI1_ReadWriteByte(W25X_WriteStatusReg);
    SPI1_ReadWriteByte(sr);
    GPIO_WriteBit(GPIOA, GPIO_Pin_2, 1);
}

/*******************************************************************************
* Function Name  : SPI_Flash_Wait_Busy
* Description    : Wait flash free.
* Input          : None
* Return         : None
*******************************************************************************/
void SPI_Flash_Wait_Busy(void)
{
    while ((SPI_Flash_ReadSR() & 0x01) == 0x01)
        ;
}

/*******************************************************************************
* Function Name  : SPI_FLASH_Write_Enable
* Description    : Enable flash write.
* Input          : None
* Return         : None
*******************************************************************************/
void SPI_FLASH_Write_Enable(void)
{
    GPIO_WriteBit(GPIOA, GPIO_Pin_2, 0);
    SPI1_ReadWriteByte(W25X_WriteEnable);
    GPIO_WriteBit(GPIOA, GPIO_Pin_2, 1);
}

/*******************************************************************************
* Function Name  : SPI_FLASH_Write_Disable
* Description    : Disable flash write.
* Input          : None
* Return         : None
*******************************************************************************/
void SPI_FLASH_Write_Disable(void)
{
    GPIO_WriteBit(GPIOA, GPIO_Pin_2, 0);
    SPI1_ReadWriteByte(W25X_WriteDisable);
    GPIO_WriteBit(GPIOA, GPIO_Pin_2, 1);
}

/*******************************************************************************
* Function Name  : SPI_Flash_ReadID
* Description    : Read flash ID.
* Input          : None
* Return         : Temp: FLASH ID.
*******************************************************************************/
u16 SPI_Flash_ReadID(void)
{
    u16 Temp = 0;

    GPIO_WriteBit(GPIOA, GPIO_Pin_2, 0);
    SPI1_ReadWriteByte(W25X_ManufactDeviceID);
    SPI1_ReadWriteByte(0x00);
    SPI1_ReadWriteByte(0x00);
    SPI1_ReadWriteByte(0x00);
    Temp |= SPI1_ReadWriteByte(0xFF) << 8;
    Temp |= SPI1_ReadWriteByte(0xFF);
    GPIO_WriteBit(GPIOA, GPIO_Pin_2, 1);

    return Temp;
}

/*******************************************************************************
* Function Name  : SPI_Flash_Erase_Sector
* Description    : Erase one sector(4Kbyte).
* Input          : Dst_Addr:  0 —— 2047
* Return         : None
*******************************************************************************/
void SPI_Flash_Erase_Sector(u32 Dst_Addr)
{
    Dst_Addr *= 4096;
    SPI_FLASH_Write_Enable();
    SPI_Flash_Wait_Busy();
    GPIO_WriteBit(GPIOA, GPIO_Pin_2, 0);
    SPI1_ReadWriteByte(W25X_SectorErase);
    SPI1_ReadWriteByte((u8) ((Dst_Addr) >> 16));
    SPI1_ReadWriteByte((u8) ((Dst_Addr) >> 8));
    SPI1_ReadWriteByte((u8) Dst_Addr);
    GPIO_WriteBit(GPIOA, GPIO_Pin_2, 1);
    SPI_Flash_Wait_Busy();
}

/*******************************************************************************
* Function Name  : SPI_Flash_Read
* Description    : Read data from flash.
* Input          : pBuffer:
*                  ReadAddr:Initial address(24bit).
*                  size: Data length.
* Return         : None
*******************************************************************************/
void SPI_Flash_Read(u8* pBuffer, u32 ReadAddr, u16 size)
{
    u16 i;

    GPIO_WriteBit(GPIOA, GPIO_Pin_2, 0);
    SPI1_ReadWriteByte(W25X_ReadData);
    SPI1_ReadWriteByte((u8) ((ReadAddr) >> 16));
    SPI1_ReadWriteByte((u8) ((ReadAddr) >> 8));
    SPI1_ReadWriteByte((u8) ReadAddr);

    for (i = 0; i < size; i++)
    {
        pBuffer[i] = SPI1_ReadWriteByte(0XFF);
    }

    GPIO_WriteBit(GPIOA, GPIO_Pin_2, 1);
}

/*******************************************************************************
* Function Name  : SPI_Flash_Write_Page
* Description    : Write data by one page.
* Input          : pBuffer:
*                  WriteAddr:Initial address(24bit).
*                  size:Data length.
* Return         : None
*******************************************************************************/
void SPI_Flash_Write_Page(u8* pBuffer, u32 WriteAddr, u16 size)
{
    u16 i;

    SPI_FLASH_Write_Enable();
    GPIO_WriteBit(GPIOA, GPIO_Pin_2, 0);
    SPI1_ReadWriteByte(W25X_PageProgram);
    SPI1_ReadWriteByte((u8) ((WriteAddr) >> 16));
    SPI1_ReadWriteByte((u8) ((WriteAddr) >> 8));
    SPI1_ReadWriteByte((u8) WriteAddr);

    for (i = 0; i < size; i++)
    {
        SPI1_ReadWriteByte(pBuffer[i]);
    }

    GPIO_WriteBit(GPIOA, GPIO_Pin_2, 1);
    SPI_Flash_Wait_Busy();
}

/*******************************************************************************
* Function Name  : SPI_Flash_Write_NoCheck
* Description    : Write data to flash.(need Erase)
*                  All data in address rang is 0xFF.
* Input          : pBuffer:
*                  WriteAddr: Initial address(24bit).
*                  size: Data length.
* Return         : None
*******************************************************************************/
void SPI_Flash_Write_NoCheck(u8* pBuffer, u32 WriteAddr, u16 size)
{
    u16 pageremain;

    pageremain = 256 - WriteAddr % 256;

    if (size <= pageremain)
        pageremain = size;

    while (1)
    {
        SPI_Flash_Write_Page(pBuffer, WriteAddr, pageremain);

        if (size == pageremain)
        {
            break;
        }
        else
        {
            pBuffer += pageremain;
            WriteAddr += pageremain;
            size -= pageremain;

            if (size > 256)
                pageremain = 256;
            else
                pageremain = size;
        }
    }
}

/*******************************************************************************
* Function Name  : SPI_Flash_Write
* Description    : Write data to flash.(no need Erase)
* Input          : pBuffer:
*                  WriteAddr: Initial address(24bit).
*                  size: Data length.
* Return         : None
*******************************************************************************/
void SPI_Flash_Write(u8* pBuffer, u32 WriteAddr, u16 size)
{
    u32 secpos;
    u16 secoff;
    u16 secremain;
    u16 i;

    secpos = WriteAddr / 4096;
    secoff = WriteAddr % 4096;
    secremain = 4096 - secoff;

    if (size <= secremain)
        secremain = size;

    while (1)
    {
        SPI_Flash_Read(SPI_FLASH_BUF, secpos * 4096, 4096);

        for (i = 0; i < secremain; i++)
        {
            if (SPI_FLASH_BUF[secoff + i] != 0XFF)
                break;
        }

        if (i < secremain)
        {
            SPI_Flash_Erase_Sector(secpos);

            for (i = 0; i < secremain; i++)
            {
                SPI_FLASH_BUF[i + secoff] = pBuffer[i];
            }

            SPI_Flash_Write_NoCheck(SPI_FLASH_BUF, secpos * 4096, 4096);

        }
        else
        {
            SPI_Flash_Write_NoCheck(pBuffer, WriteAddr, secremain);
        }

        if (size == secremain)
        {
            break;
        }
        else
        {
            secpos++;
            secoff = 0;

            pBuffer += secremain;
            WriteAddr += secremain;
            size -= secremain;

            if (size > 4096)
            {
                secremain = 4096;
            }
            else
            {
                secremain = size;
            }
        }
    }
}

/*******************************************************************************
* Function Name  : SPI_Flash_Erase_Chip
* Description    : Erase all FLASH pages.
* Input          : None
* Return         : None
*******************************************************************************/
void SPI_Flash_Erase_Chip(void)
{
    SPI_FLASH_Write_Enable();
    SPI_Flash_Wait_Busy();
    GPIO_WriteBit(GPIOA, GPIO_Pin_2, 0);
    SPI1_ReadWriteByte(W25X_ChipErase);
    GPIO_WriteBit(GPIOA, GPIO_Pin_2, 1);
    SPI_Flash_Wait_Busy();
}

/*******************************************************************************
* Function Name  : SPI_Flash_PowerDown
* Description    : Enter power down mode.
* Input          : None
* Return         : None
*******************************************************************************/
void SPI_Flash_PowerDown(void)
{
    GPIO_WriteBit(GPIOA, GPIO_Pin_2, 0);
    SPI1_ReadWriteByte(W25X_PowerDown);
    GPIO_WriteBit(GPIOA, GPIO_Pin_2, 1);
    Delay_Us(3);
}

/*******************************************************************************
* Function Name  : SPI_Flash_WAKEUP
* Description    : Power down wake up.
* Input          : None
* Return         : None
*******************************************************************************/
void SPI_Flash_WAKEUP(void)
{
    GPIO_WriteBit(GPIOA, GPIO_Pin_2, 0);
    SPI1_ReadWriteByte(W25X_ReleasePowerDown);
    GPIO_WriteBit(GPIOA, GPIO_Pin_2, 1);
    Delay_Us(3);
}


Hardware/spiflash.h
#ifndef __SPIFLASH_H
#define __SPIFLASH_H


/* Winbond SPIFalsh ID */
#define W25Q80  0XEF13
#define W25Q16  0XEF14
#define W25Q32  0XEF15
#define W25Q64  0XEF16
#define W25Q128 0XEF17

/* Winbond SPIFalsh Instruction List */
#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

u8 SPI1_ReadWriteByte(u8 TxData);
void SPI_Flash_Init(void);
u8 SPI_Flash_ReadSR(void);
void SPI_FLASH_Write_SR(u8 sr);
void SPI_Flash_Wait_Busy(void);
void SPI_FLASH_Write_Enable(void);
void SPI_FLASH_Write_Disable(void);
u16 SPI_Flash_ReadID(void);
void SPI_Flash_Erase_Sector(u32 Dst_Addr);
void SPI_Flash_Read(u8* pBuffer,u32 ReadAddr,u16 size);
void SPI_Flash_Write_Page(u8* pBuffer,u32 WriteAddr,u16 size);
void SPI_Flash_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 size);
void SPI_Flash_Write(u8* pBuffer,u32 WriteAddr,u16 size);
void SPI_Flash_Erase_Chip(void);
void SPI_Flash_PowerDown(void);
void SPI_Flash_WAKEUP(void);

#endif



main.c
/********************************** (C) COPYRIGHT *******************************
* File Name          : main.c
* Author             : WCH
* Version            : V1.0.0
* Date               : 2020/04/30
* Description        : Main program body.
*******************************************************************************/

/*
*@Note
W25Q16串行 Flash存储器 Raw数据读写测试例程。
*/

#pragma message("short-cut R11 before programming")

#include <string.h>
#include "debug.h"
#include "../Hardware/spiflash.h"

/* Global typedef */

/* Global define */

/* Global Variable */
const u8 TEXT_Buf[] =
{ "CH32F103C8T6 SPI FLASH W25Qxx Read/Write raw data buffer content" };

#define SIZE sizeof(TEXT_Buf)

/*******************************************************************************
* Function Name  : main
* Description    : Main program.
* Input          : None
* Return         : None
*******************************************************************************/
int main(void)
{
    u8 datap[SIZE] =
    { };
    u16 Flash_Model = 0;

    Delay_Init();
    USART_Printf_Init(115200);
    printf("SystemClk: %d\r\n", SystemCoreClock);

    SPI_Flash_Init();

    Flash_Model = SPI_Flash_ReadID();
    printf("Flash_Model:%x\r\n", Flash_Model);
    switch (Flash_Model)
    {
    case W25Q80:
        printf("W25Q80 OK!\r\n");
        break;

    case W25Q16:
        printf("W25Q16 OK!\r\n");
        break;

    case W25Q32:
        printf("W25Q32 OK!\r\n");
        break;

    case W25Q64:
        printf("W25Q64 OK!\r\n");
        break;

    case W25Q128:
        printf("W25Q128 OK!\r\n");
        break;

    default:
        printf("Failed!\r\n");
        break;
    }

    printf("Start Erase W25Qxx ...\r\n");
    SPI_Flash_Erase_Sector(0);
    printf("W25Qxx Erase Finished!\r\n");

    Delay_Ms(500);
    printf("Start Read W25Qxx ...\r\n");
    SPI_Flash_Read(datap, 0x0, SIZE);
    printf("%s\r\n", datap);

    Delay_Ms(500);
    printf("Start Write W25Qxx ...\r\n");
    SPI_Flash_Write((u8*) TEXT_Buf, 0, SIZE);
    printf("W25Qxx Write Finished!\r\n");

    Delay_Ms(500);
    printf("Start Read W25Qxx ...\r\n");
    SPI_Flash_Read(datap, 0x0, SIZE);
    printf("%s\r\n", datap);

    while (1)
    {
        Delay_Ms(1000);

        printf("Start Read W25Qxx ...\r\n");
        SPI_Flash_Read(datap, 0x0, SIZE);
        printf("%s\r\n", datap);
    }

    return 0;
}



完整代码打包在此:

W25Q16.png

W25Q16.zip

140.24 KB

使用特权

评论回复

相关帖子

caizhiwei| | 2020-12-4 22:23 | 显示全部楼层
赞一个,辛苦了楼主

使用特权

评论回复
资深技术| | 2020-12-7 16:37 | 显示全部楼层
赞楼主,正准备试用在这个芯片

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

9

主题

57

帖子

0

粉丝