From fe3733ac17e5a80bd3f0cdef0b4713284616937c Mon Sep 17 00:00:00 2001 From: songyanguang <345810377@qq.com> Date: Fri, 8 Aug 2025 21:04:41 +0800 Subject: [PATCH] Add spi flash --- Ubiquitous/XiZi_IIoT/board/ch569w/board.c | 5 + .../board/ch569w/third_party_driver/Kconfig | 7 + .../board/ch569w/third_party_driver/Makefile | 4 + .../ch569w/third_party_driver/spi/Kconfig | 3 + .../ch569w/third_party_driver/spi/Makefile | 5 + .../spi/connect_spi_flash.c | 450 ++++++++++++++++++ 6 files changed, 474 insertions(+) create mode 100644 Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/spi/Kconfig create mode 100644 Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/spi/Makefile create mode 100644 Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/spi/connect_spi_flash.c diff --git a/Ubiquitous/XiZi_IIoT/board/ch569w/board.c b/Ubiquitous/XiZi_IIoT/board/ch569w/board.c index b146dc3f2..293141fa1 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch569w/board.c +++ b/Ubiquitous/XiZi_IIoT/board/ch569w/board.c @@ -44,6 +44,11 @@ void InitBoardHardware() KPrintf("\nconsole init completed.\n"); #endif +#ifdef BSP_USING_SPI + int InitHwSpi(void); + InitHwSpi(); +#endif + KPrintf("memory address range: [0x%08x - 0x%08x] ssize: %x\n", (x_ubase)MEMORY_START_ADDRESS, (x_ubase)MEMORY_END_ADDRESS, MEMORY_STACK_SIZE); diff --git a/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/Kconfig b/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/Kconfig index 6fdbc2813..927598866 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/Kconfig +++ b/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/Kconfig @@ -5,3 +5,10 @@ menuconfig BSP_USING_UART if BSP_USING_UART source "$BSP_DIR/third_party_driver/uart/Kconfig" endif + +menuconfig BSP_USING_SPI + bool "Using SPI device" + default y + if BSP_USING_SPI + source "$BSP_DIR/third_party_driver/spi/Kconfig" + endif diff --git a/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/Makefile b/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/Makefile index 0bf187997..035498017 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/Makefile +++ b/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/Makefile @@ -6,4 +6,8 @@ ifeq ($(CONFIG_BSP_USING_UART),y) SRC_DIR += uart endif +ifeq ($(CONFIG_BSP_USING_SPI),y) + SRC_DIR += spi +endif + include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/spi/Kconfig b/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/spi/Kconfig new file mode 100644 index 000000000..701b1335d --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/spi/Kconfig @@ -0,0 +1,3 @@ +menuconfig BSP_USING_SPI0_FLASH + bool "Enable SPI0 FLASH" + default y diff --git a/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/spi/Makefile b/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/spi/Makefile new file mode 100644 index 000000000..73c862fab --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/spi/Makefile @@ -0,0 +1,5 @@ +ifeq ($(CONFIG_BSP_USING_SPI0_FLASH),y) + SRC_FILES += connect_spi_flash.c +endif + +include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/spi/connect_spi_flash.c b/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/spi/connect_spi_flash.c new file mode 100644 index 000000000..3aea6b50a --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/spi/connect_spi_flash.c @@ -0,0 +1,450 @@ +/* + * Copyright (c) 2020 AIIT XUOS Lab + * XiUOS is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan + * PSL v2. You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY + * KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO + * NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. See the + * Mulan PSL v2 for more details. + */ + +/** + * @file connect_spi.c + * @brief support ch569 spi function and register to bus framework + * @version 1.0 + * @author AIIT XUOS Lab + * @date 2025-04-07 + */ +/* + *@Note + *SPI0_FLASH routine + * SPI0 operation external FLASH + */ + +#include +#include "xsconfig.h" +#include "CH56x_common.h" +#include "board.h" +#include "shell.h" + + +#define CMD_STATUS1 0x05 +#define CMD_WR_ENABLE 0x06 +#define CMD_ERASE_4KBYTE 0x20 +#define CMD_ERASE_32KBYTE 0x52 +#define CMD_READ_DATA 0x03 +#define CMD_PAGE_PROG 0x02 +#define CMD_FAST_READ 0x0B +#define CMD_DEVICE_ID 0x90 + +/********************************* Pin Definitions ************************************ +* PA12 <===========> SCS0 +* PA13 <===========> SCK0 +* PA14 <===========> MOSI0 +* PA15 <===========> MISO0 +*******************************************************************************/ +#define SPI0_CS_LOW() R32_PA_CLR |= 1<<12 +#define SPI0_CS_HIGH() R32_PA_OUT |= 1<<12 + +/******************************************************************************* + * @fn DebugInit + * + * @brief Initializes the UART1 peripheral. + * + * @param baudrate - UART1 communication baud rate. + * + * @return None + */ +void DebugInit(UINT32 baudrate) +{ + UINT32 x; + UINT32 t = FREQ_SYS; + + x = 10 * t * 2 / 16 / baudrate; + x = ( x + 5 ) / 10; + R8_UART1_DIV = 1; + R16_UART1_DL = x; + R8_UART1_FCR = RB_FCR_FIFO_TRIG | RB_FCR_TX_FIFO_CLR | RB_FCR_RX_FIFO_CLR | RB_FCR_FIFO_EN; + R8_UART1_LCR = RB_LCR_WORD_SZ; + R8_UART1_IER = RB_IER_TXD_EN; + R32_PA_SMT |= (1<<8) |(1<<7); + R32_PA_DIR |= (1<<8); +} + +/******************************************************************************* + * @fn SPI_MASTER_INIT + * + * @brief SPI0 master mode initialization + * + * @return None + */ +void SPI_MASTER_INIT(void) +{ + R8_SPI0_CTRL_MOD = RB_SPI_MOSI_OE|RB_SPI_SCK_OE; /* MOSI, SCK output enable, host mode, mode 0 */ + R8_SPI0_CLOCK_DIV = 0x0a; /* 10 frequency division, 100/10=10M */ + R32_PA_DIR |= (1<<14 | 1<<13 | 1<<12); /* MOSI(PA14), SCK0(PA13), SCS(PA12) are the output*/ + R32_PA_PU |= 1<<12 ; + R8_SPI0_CTRL_CFG &= ~RB_SPI_DMA_ENABLE; +} + +/******************************************************************************* + * @fn SPI0_Trans + * + * @brief send a byte of data + * + * @param data - data to send + * + * @return None + */ +void SPI0_Trans(UINT8 data) +{ + +// R8_SPI0_CTRL_MOD &= ~RB_SPI_FIFO_DIR; +// R8_SPI0_BUFFER = data; +// while( !(R8_SPI0_INT_FLAG & RB_SPI_FREE) ); + + R32_SPI0_FIFO = data; + R16_SPI0_TOTAL_CNT = 0x01; + while( R8_SPI0_FIFO_COUNT != 0 ); /* Wait for the data to be sent */ +} + +/******************************************************************************* + * @fn SPI0_Recv + * + * @brief Receive a byte of data + * + * @return None + */ +UINT8 SPI0_Recv(void) +{ +// R8_SPI0_CTRL_MOD &= ~RB_SPI_FIFO_DIR; +// R8_SPI0_BUFFER = 0xFF; //start transfer +// while( !(R8_SPI0_INT_FLAG & RB_SPI_FREE) ); +// return ( R8_SPI0_BUFFER ); + + UINT8 data; + R32_SPI0_FIFO = 0xff; + R16_SPI0_TOTAL_CNT = 0x01; + while( R8_SPI0_FIFO_COUNT != 0 ); /* wait for data to come back */ + data = R8_SPI0_BUFFER; + return data; +} + +/******************************************************************************* + * @fn SPI0_RecvS + * + * @brief Receive multiple bytes continuously using FIFO + * + * @param pbuf - The first address of the data content to be sent + len - The length of the data sent by the request, the maximum is 4095 + + * @return None + */ +void SPI0_RecvS(UINT8 *pbuf, UINT16 len) +{ + UINT16 readlen; + + readlen = len; + R8_SPI0_CTRL_MOD |= RB_SPI_FIFO_DIR; //Set data direction to input + R16_SPI0_TOTAL_CNT = len; //Set the length of the data to be received, the FIFO direction will start the transmission if the input length is not 0 + R8_SPI0_INT_FLAG = RB_SPI_IF_CNT_END; + while( readlen ) + { + if( R8_SPI0_FIFO_COUNT ) + { + *pbuf = R8_SPI0_FIFO; + pbuf++; + readlen--; + } + } +} + +/******************************************************************************* + * @fn ReadExternalFlashStatusReg_SPI + * + * @brief Used to read the status register and return the value of the status register + * + * @return ExFlashRegStatus + */ +UINT8 ReadExternalFlashStatusReg_SPI(void) +{ + UINT8 ExFlashRegStatus; + + + SPI0_CS_LOW(); + SPI0_Trans( CMD_STATUS1 ); //Send a command to read the status register + ExFlashRegStatus = SPI0_Recv(); //read status register + SPI0_CS_HIGH(); + + return ExFlashRegStatus; +} + +/******************************************************************************* + * @fn WaitExternalFlashIfBusy + * + * @brief Wait for the chip to be free (after performing Byte-Program, Sector-Erase, Block-Erase, Chip-Erase operations) + * + * @return None + */ +void WaitExternalFlashIfBusy(void) +{ + while ((ReadExternalFlashStatusReg_SPI())&0x01 == 0x01 ) + { + ; //Waiting for Flash to be idle + } +} + +/******************************************************************************* + * @fn WriteExternalFlashEnable_SPI + * + * @brief Write enable, also can be used to enable write status register + * + * @return None + */ +void WriteExternalFlashEnable_SPI(void) +{ + SPI0_CS_LOW(); + SPI0_Trans( CMD_WR_ENABLE ); //Send write enable command + SPI0_CS_HIGH(); +} + +/******************************************************************************* + * @fn EraseExternal4KFlash_SPI + * + * @brief Erase 4K Flash Erase a sector + * + * @param Dst_Addr 0-1 ffff ffff, Clear the sector where any address is located + * + * @return None + */ +void EraseExternal4KFlash_SPI(UINT32 Dst_Addr) +{ + WriteExternalFlashEnable_SPI(); + WaitExternalFlashIfBusy(); + + SPI0_CS_LOW(); + SPI0_Trans(CMD_ERASE_4KBYTE); //sector erase command + SPI0_Trans(((Dst_Addr & 0xFFFFFF) >> 16)); //Send 3 byte address + SPI0_Trans(((Dst_Addr & 0xFFFF) >> 8)); + SPI0_Trans(Dst_Addr & 0xFF); + SPI0_CS_HIGH(); + + WaitExternalFlashIfBusy(); +} + +/******************************************************************************* + * @fn EraseExternalFlash_SPI + * + * @brief Erase 32K Flash Erase a sector + * + * @param Dst_Addr 0-1 ffff ffff, Clear the sector where any address is located + * + * @return None + */ +void EraseExternal32KFlash_SPI(UINT32 Dst_Addr) +{ + WriteExternalFlashEnable_SPI(); + WaitExternalFlashIfBusy(); + + SPI0_CS_LOW(); + SPI0_Trans(CMD_ERASE_32KBYTE); //32K erase command + SPI0_Trans(((Dst_Addr & 0xFFFFFF) >> 16)); //Send 3 byte address + SPI0_Trans(((Dst_Addr & 0xFFFF) >> 8)); + SPI0_Trans(Dst_Addr & 0xFF); + SPI0_CS_HIGH(); + + WaitExternalFlashIfBusy(); +} + +/******************************************************************************* + * @fn PageWriteExternalFlash_SPI + * + * @brief Page write, SPI writes less than 256 bytes of data in one page + * + * @param RcvBuffer - data storage area + * StarAddr - address to start writing + * Len - The number of bytes to write (up to 256), which should not exceed the number of bytes remaining on the page + * + * @returnNone + */ +void PageWriteExternalFlash_SPI(UINT32 StarAddr, UINT16 Len, PUINT8 RcvBuffer) +{ + UINT16 i; + + WriteExternalFlashEnable_SPI(); //SET WEL + + SPI0_CS_LOW(); + SPI0_Trans(CMD_PAGE_PROG); //send write page command + SPI0_Trans(((StarAddr & 0xFFFFFF) >> 16)); //Send 24bit address + SPI0_Trans(((StarAddr & 0xFFFF) >> 8)); + SPI0_Trans(StarAddr & 0xFF); + for(i=0; i!=Len; i++){ + SPI0_Trans(RcvBuffer[i]); //cycle write + } + SPI0_CS_HIGH(); + + WaitExternalFlashIfBusy(); //Wait for write to end +} + +/******************************************************************************* + * @fn BlukWriteExternalFlash_SPI + * + * @brief Write SPI FLASH without verification + * It must be ensured that the data in the address range to be written is all 0XFF, otherwise the data written at non-0XFF will fail + * + * @param SendBuffer - data storage area + * StarAddr - address to start writing + * Len - The number of bytes to write (max 65535) + * + * @return None + */ +void BlukWriteExternalFlash_SPI(UINT32 StarAddr, UINT16 Len, PUINT8 SendBuffer) +{ + UINT16 pageremain; + + pageremain = 256-StarAddr%256; //The remaining bytes of a single page + if(Len<=pageremain) + { + pageremain=Len; //No more than 256 bytes + } + while(1) + { + PageWriteExternalFlash_SPI(StarAddr,pageremain,SendBuffer); + if(Len==pageremain) + { + break; //end of writing + } + else + { + SendBuffer+=pageremain; + StarAddr+=pageremain; + Len-=pageremain; //Subtract the number of bytes already written + if(Len>256) + { + pageremain=256; //256 bytes can be written at a time + } + else + { + pageremain=Len; //Not enough 256 bytes + } + } + } +} + +/******************************************************************************* + * @fn ReadExternalFlash_SPI + * + * @brief read data from address + * + * @param StarAddr + * Len read data length + * RcvBuffer Receive buffer start address + * + * @return None + */ +void ReadExternalFlash_SPI(UINT32 StarAddr, UINT16 Len, PUINT8 RcvBuffer) +{ + SPI0_CS_LOW(); + SPI0_Trans(CMD_READ_DATA); //read command + SPI0_Trans(((StarAddr & 0xFFFFFF) >> 16)); //Send 3 byte address + SPI0_Trans(((StarAddr & 0xFFFF) >> 8)); + SPI0_Trans(StarAddr & 0xFF); + SPI0_RecvS( RcvBuffer, Len ); + SPI0_CS_HIGH(); +} + +/******************************************************************************* + * @fn BlukReadExternalFlash_SPI + * + * @brief Read the data of multiple bytes in the starting address and store it in the buffer + * + * @param StarAddr -Destination Address 000000H - 1FFFFFH + Len - read data length + RcvBuffer - Receive buffer start address + + * @return None + */ +void BlukReadExternalFlash_SPI(UINT32 StarAddr, UINT16 Len, PUINT8 RcvBuffer) +{ + SPI0_CS_LOW(); + SPI0_Trans(CMD_FAST_READ); //high speed + SPI0_Trans(((StarAddr & 0xFFFFFF) >> 16)); //Send 3 byte address + SPI0_Trans(((StarAddr & 0xFFFF) >> 8)); + SPI0_Trans(StarAddr & 0xFF); + SPI0_Trans(0x00); + SPI0_RecvS( RcvBuffer, Len ); + SPI0_CS_HIGH(); +} + +/******************************************************************************* + * @fn SPIFlash_ReadID + * + * @brief SPI Flash read chip ID + * + * @return 0XEF13 - Indicates that the chip model is W25Q80 + * 0XEF14 - Indicates that the chip model is W25Q16 + * 0XEF15 - Indicates that the chip model is W25Q32 + * 0XEF16 - Indicates that the chip model is W25Q64 + * 0XEF17 - Indicates that the chip model is W25Q128 + */ +UINT16 SPIFlash_ReadID(void) +{ + UINT16 temp = 0; + + R32_PA_CLR |= 1<<12 ; + + SPI0_Trans(0x90); //read ID command + SPI0_Trans(0x00); + SPI0_Trans(0x00); + SPI0_Trans(0x00); + temp = SPI0_Recv(); + temp = temp<<8; + temp |= SPI0_Recv(); + + R32_PA_OUT |= 1<<12 ; + + return temp; +} + +/********************************************************************* + * @fn InitHwSpi + * + * @brief InitHwSpi program. + * + * @return none + */ +int InitHwSpi(void) { + SPI_MASTER_INIT ( ); /* SPI0 master mode initialization */ + KPrintf("START SPI FLASH\n"); + return 0; +} + +int SpiFlashTest(int argc, char *argv[]) +{ + UINT8 buf[1024]; + UINT8 i; + + KPrintf("SpiFlashTest Start\n"); + + KPrintf("spi flash id:0x%04x\n", SPIFlash_ReadID() ); /*Read chip ID */ + + for(i=0; i!=255; i++){ + buf[i] = i; + } + + EraseExternal4KFlash_SPI(0); + BlukWriteExternalFlash_SPI(0,255,buf); + BlukReadExternalFlash_SPI( 0,255,buf ); + + for(i=0; i!=255; i++){ + KPrintf("%d ",(UINT16)buf[i]); + } + KPrintf("done\n"); + + return 0; +} + +SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), + test_spi, SpiFlashTest, test spi);