2026-08-10 21:18:36 +08:00
# include "w25q64.h"
# include "log.h"
# include "app_loop.h" /* storage_lock/unlock<63> <6B> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> ʻ <EFBFBD> <CABB> <EFBFBD> */
# include <string.h>
/* *******************************************
* <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> SPI λ <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> ꣨ <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> main . h <EFBFBD> ж <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> ţ <EFBFBD>
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# ifndef W25Q64_CS_L
# define W25Q64_CS_L() HAL_GPIO_WritePin(W25Q64_CS_PORT, W25Q64_CS_PIN, GPIO_PIN_RESET)
# define W25Q64_CS_H() HAL_GPIO_WritePin(W25Q64_CS_PORT, W25Q64_CS_PIN, GPIO_PIN_SET)
# define W25Q64_CLK_L() HAL_GPIO_WritePin(W25Q64_CLK_PORT, W25Q64_CLK_PIN, GPIO_PIN_RESET)
# define W25Q64_CLK_H() HAL_GPIO_WritePin(W25Q64_CLK_PORT, W25Q64_CLK_PIN, GPIO_PIN_SET)
# define W25Q64_DI_L() HAL_GPIO_WritePin(W25Q64_DI_PORT, W25Q64_DI_PIN, GPIO_PIN_RESET)
# define W25Q64_DI_H() HAL_GPIO_WritePin(W25Q64_DI_PORT, W25Q64_DI_PIN, GPIO_PIN_SET)
# define W25Q64_DO_READ() HAL_GPIO_ReadPin (W25Q64_DO_PORT, W25Q64_DO_PIN)
# endif
static void W25Q64_Delay ( void )
{
/* 72MHz <20> <> GPIO <20> <> ת<EFBFBD> <D7AA> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> 㹻<EFBFBD> <E3B9BB> ʱ<EFBFBD> <CAB1> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> ղ<EFBFBD> <D5B2> <EFBFBD> <EFBFBD> ȶ<EFBFBD> ʱ<EFBFBD> <CAB1> */
__NOP ( ) ; __NOP ( ) ; __NOP ( ) ; __NOP ( ) ;
}
static uint8_t W25Q64_SPI_TransferByte ( uint8_t tx )
{
uint8_t rx = 0 ;
for ( int i = 0 ; i < 8 ; i + + ) {
if ( tx & 0x80 ) W25Q64_DI_H ( ) ; else W25Q64_DI_L ( ) ;
tx < < = 1 ;
W25Q64_Delay ( ) ;
W25Q64_CLK_H ( ) ;
W25Q64_Delay ( ) ;
rx < < = 1 ;
if ( W25Q64_DO_READ ( ) = = GPIO_PIN_SET ) rx | = 0x01 ;
W25Q64_CLK_L ( ) ;
}
return rx ;
}
static void W25Q64_SPI_WriteByte ( uint8_t tx )
{
( void ) W25Q64_SPI_TransferByte ( tx ) ;
}
static uint8_t W25Q64_SPI_ReadByte ( void )
{
return W25Q64_SPI_TransferByte ( 0xFF ) ;
}
/* *******************************************
* <EFBFBD> <EFBFBD> ʼ <EFBFBD> <EFBFBD>
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
uint8_t W25Q64_Init ( void )
{
GPIO_InitTypeDef gpio = { 0 } ;
__HAL_RCC_GPIOA_CLK_ENABLE ( ) ;
__HAL_RCC_GPIOB_CLK_ENABLE ( ) ;
__HAL_RCC_AFIO_CLK_ENABLE ( ) ;
/* <20> ͷ<EFBFBD> PA15<31> <35> PB3<42> <33> PB4 <20> <> Ϊ GPIO<49> <4F> <EFBFBD> ر<EFBFBD> JTAG<41> <47> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> SWD<57> <44> */
__HAL_AFIO_REMAP_SWJ_NOJTAG ( ) ;
gpio . Mode = GPIO_MODE_OUTPUT_PP ;
gpio . Pull = GPIO_NOPULL ;
gpio . Speed = GPIO_SPEED_FREQ_HIGH ;
gpio . Pin = W25Q64_CS_PIN ; HAL_GPIO_Init ( W25Q64_CS_PORT , & gpio ) ;
gpio . Pin = W25Q64_CLK_PIN ; HAL_GPIO_Init ( W25Q64_CLK_PORT , & gpio ) ;
gpio . Pin = W25Q64_DI_PIN ; HAL_GPIO_Init ( W25Q64_DI_PORT , & gpio ) ;
gpio . Mode = GPIO_MODE_INPUT ;
gpio . Pull = GPIO_PULLUP ;
gpio . Pin = W25Q64_DO_PIN ; HAL_GPIO_Init ( W25Q64_DO_PORT , & gpio ) ;
W25Q64_CS_H ( ) ;
W25Q64_CLK_L ( ) ;
W25Q64_DI_L ( ) ;
uint8_t id [ 3 ] = { 0 } ;
W25Q64_ReadID ( id ) ;
uint32_t id32 = ( ( uint32_t ) id [ 0 ] < < 16 ) | ( ( uint32_t ) id [ 1 ] < < 8 ) | id [ 2 ] ;
if ( id32 ! = W25Q64_JEDEC_ID ) {
log_error ( " > W25Q64 <20> <> ʼ <EFBFBD> <CABC> ʧ<EFBFBD> <CAA7> ! ID=0x%06X " , ( unsigned ) id32 ) ;
return 1 ; /* ID <20> <> ƥ<EFBFBD> <C6A5> */
}
log_info ( " > W25Q64 <20> <> ʼ <EFBFBD> <CABC> <EFBFBD> ɹ<EFBFBD> , ID=0x%06X " , ( unsigned ) id32 ) ;
return 0 ;
}
void W25Q64_ReadID ( uint8_t * id3 )
{
W25Q64_CS_L ( ) ;
W25Q64_SPI_WriteByte ( W25Q64_CMD_READ_ID ) ;
id3 [ 0 ] = W25Q64_SPI_ReadByte ( ) ;
id3 [ 1 ] = W25Q64_SPI_ReadByte ( ) ;
id3 [ 2 ] = W25Q64_SPI_ReadByte ( ) ;
W25Q64_CS_H ( ) ;
}
uint8_t W25Q64_ReadStatus ( void )
{
uint8_t status ;
W25Q64_CS_L ( ) ;
W25Q64_SPI_WriteByte ( W25Q64_CMD_READ_STATUS1 ) ;
status = W25Q64_SPI_ReadByte ( ) ;
W25Q64_CS_H ( ) ;
return status ;
}
void W25Q64_WaitBusy ( void )
{
while ( W25Q64_ReadStatus ( ) & 0x01 ) {
__NOP ( ) ;
}
}
void W25Q64_WriteEnable ( void )
{
W25Q64_WaitBusy ( ) ;
W25Q64_CS_L ( ) ;
W25Q64_SPI_WriteByte ( W25Q64_CMD_WRITE_ENABLE ) ;
W25Q64_CS_H ( ) ;
}
static void W25Q64_WriteAddr ( uint32_t addr )
{
W25Q64_SPI_WriteByte ( ( uint8_t ) ( addr > > 16 ) ) ;
W25Q64_SPI_WriteByte ( ( uint8_t ) ( addr > > 8 ) ) ;
W25Q64_SPI_WriteByte ( ( uint8_t ) ( addr ) ) ;
}
void W25Q64_SectorErase ( uint32_t addr )
{
W25Q64_WriteEnable ( ) ;
W25Q64_WaitBusy ( ) ;
W25Q64_CS_L ( ) ;
W25Q64_SPI_WriteByte ( W25Q64_CMD_SECTOR_ERASE ) ;
W25Q64_WriteAddr ( addr ) ;
W25Q64_CS_H ( ) ;
W25Q64_WaitBusy ( ) ;
}
void W25Q64_BlockErase ( uint32_t addr )
{
W25Q64_WriteEnable ( ) ;
W25Q64_WaitBusy ( ) ;
W25Q64_CS_L ( ) ;
W25Q64_SPI_WriteByte ( W25Q64_CMD_BLOCK_ERASE ) ;
W25Q64_WriteAddr ( addr ) ;
W25Q64_CS_H ( ) ;
W25Q64_WaitBusy ( ) ;
}
void W25Q64_ChipErase ( void )
{
W25Q64_WriteEnable ( ) ;
W25Q64_WaitBusy ( ) ;
W25Q64_CS_L ( ) ;
W25Q64_SPI_WriteByte ( W25Q64_CMD_CHIP_ERASE ) ;
W25Q64_CS_H ( ) ;
W25Q64_WaitBusy ( ) ;
}
void W25Q64_PageProgram ( uint32_t addr , const uint8_t * data , uint16_t len )
{
if ( len = = 0 | | len > W25Q64_PAGE_SIZE ) return ;
W25Q64_WriteEnable ( ) ;
W25Q64_WaitBusy ( ) ;
W25Q64_CS_L ( ) ;
W25Q64_SPI_WriteByte ( W25Q64_CMD_PAGE_PROGRAM ) ;
W25Q64_WriteAddr ( addr ) ;
for ( uint16_t i = 0 ; i < len ; i + + ) {
W25Q64_SPI_WriteByte ( data [ i ] ) ;
}
W25Q64_CS_H ( ) ;
W25Q64_WaitBusy ( ) ;
}
void W25Q64_Read ( uint32_t addr , uint8_t * buf , uint32_t len )
{
storage_lock ( ) ;
W25Q64_CS_L ( ) ;
W25Q64_SPI_WriteByte ( W25Q64_CMD_READ_DATA ) ;
W25Q64_WriteAddr ( addr ) ;
for ( uint32_t i = 0 ; i < len ; i + + ) {
buf [ i ] = W25Q64_SPI_ReadByte ( ) ;
}
W25Q64_CS_H ( ) ;
storage_unlock ( ) ;
}
void W25Q64_EraseRegion ( uint32_t addr , uint32_t size )
{
if ( size = = 0 ) return ;
storage_lock ( ) ;
uint32_t end = addr + size - 1 ;
uint32_t pos = addr ;
/* <20> <> <EFBFBD> 뵽 64KB Block <20> ߽<EFBFBD> */
while ( ( pos & ( W25Q64_BLOCK_SIZE - 1 ) ) ! = 0 & & pos < = end ) {
W25Q64_SectorErase ( pos ) ;
pos + = W25Q64_SECTOR_SIZE ;
}
/* 64KB Block <20> <> <EFBFBD> <EFBFBD> */
while ( ( pos + W25Q64_BLOCK_SIZE - 1 ) < = end ) {
W25Q64_BlockErase ( pos ) ;
pos + = W25Q64_BLOCK_SIZE ;
}
/* ʣ<> <CAA3> 4KB Sector */
while ( pos < = end ) {
W25Q64_SectorErase ( pos ) ;
pos + = W25Q64_SECTOR_SIZE ;
}
storage_unlock ( ) ;
}
int W25Q64_WriteBuffer ( uint32_t addr , const uint8_t * data , uint32_t len )
{
storage_lock ( ) ;
while ( len ) {
uint32_t page_offset = addr & ( W25Q64_PAGE_SIZE - 1 ) ;
uint32_t page_remain = W25Q64_PAGE_SIZE - page_offset ;
uint16_t chunk = ( len > page_remain ) ? ( uint16_t ) page_remain : ( uint16_t ) len ;
W25Q64_PageProgram ( addr , data , chunk ) ;
addr + = chunk ;
data + = chunk ;
len - = chunk ;
}
storage_unlock ( ) ;
return 1 ;
}
int W25Q64_Verify ( uint32_t addr , const uint8_t * data , uint32_t len )
{
storage_lock ( ) ;
while ( len ) {
uint16_t chunk = ( len > 256 ) ? 256 : ( uint16_t ) len ;
uint8_t tmp [ 256 ] ;
W25Q64_Read ( addr , tmp , chunk ) ;
if ( memcmp ( tmp , data , chunk ) ! = 0 ) { storage_unlock ( ) ; return 0 ; }
addr + = chunk ;
data + = chunk ;
len - = chunk ;
}
storage_unlock ( ) ;
return 1 ;
}
/* *******************************************
* OTA <EFBFBD> <EFBFBD> Ϣ <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> ˫ <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> У <EFBFBD> <EFBFBD> <EFBFBD> ͣ <EFBFBD>
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static uint16_t W25Q64_InfoChecksum ( const W25Q64_OtaInfo * info )
{
const uint8_t * p = ( const uint8_t * ) info ;
uint16_t sum = 0 ;
for ( uint32_t i = 0 ; i < ( sizeof ( W25Q64_OtaInfo ) - 2 ) ; i + + ) {
sum + = p [ i ] ;
}
return sum ;
}
static int W25Q64_InfoValid ( const W25Q64_OtaInfo * info )
{
if ( info - > magic ! = W25Q64_INFO_MAGIC ) return 0 ;
return ( info - > checksum = = W25Q64_InfoChecksum ( info ) ) ? 1 : 0 ;
}
int W25Q64_OTA_ReadInfo ( W25Q64_OtaInfo * info )
{
W25Q64_OtaInfo a , b ;
int va = 0 , vb = 0 ;
storage_lock ( ) ;
W25Q64_Read ( W25Q64_INFO_SECTOR_A , ( uint8_t * ) & a , sizeof ( a ) ) ;
W25Q64_Read ( W25Q64_INFO_SECTOR_B , ( uint8_t * ) & b , sizeof ( b ) ) ;
va = W25Q64_InfoValid ( & a ) ;
vb = W25Q64_InfoValid ( & b ) ;
if ( ! va & & ! vb ) {
memset ( info , 0 , sizeof ( * info ) ) ;
storage_unlock ( ) ;
return - 1 ;
}
if ( va & & vb ) {
* info = ( a . sequence > = b . sequence ) ? a : b ;
} else if ( va ) {
* info = a ;
} else {
* info = b ;
}
storage_unlock ( ) ;
return 0 ;
}
int W25Q64_OTA_WriteInfo ( const W25Q64_OtaInfo * info )
{
W25Q64_OtaInfo tmp = * info ;
tmp . checksum = W25Q64_InfoChecksum ( & tmp ) ;
storage_lock ( ) ;
/* <20> <> д<EFBFBD> <D0B4> A <20> <> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> д<EFBFBD> <D0B4> B <20> <> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> ʱ<EFBFBD> <CAB1> <EFBFBD> ٱ<EFBFBD> <D9B1> <EFBFBD> һ <EFBFBD> <D2BB> <EFBFBD> <EFBFBD> Ч<EFBFBD> <D0A7> <EFBFBD> <EFBFBD> */
W25Q64_SectorErase ( W25Q64_INFO_SECTOR_A ) ;
W25Q64_WriteBuffer ( W25Q64_INFO_SECTOR_A , ( const uint8_t * ) & tmp , sizeof ( tmp ) ) ;
W25Q64_SectorErase ( W25Q64_INFO_SECTOR_B ) ;
W25Q64_WriteBuffer ( W25Q64_INFO_SECTOR_B , ( const uint8_t * ) & tmp , sizeof ( tmp ) ) ;
storage_unlock ( ) ;
return 0 ;
}
2026-08-19 23:10:15 +08:00
int W25Q64_OTA_SetNewInfo ( uint16_t version , uint32_t size , uint16_t crc16 )
2026-08-10 21:18:36 +08:00
{
int ret ;
storage_lock ( ) ;
W25Q64_OtaInfo info ;
if ( W25Q64_OTA_ReadInfo ( & info ) ! = 0 ) {
memset ( & info , 0 , sizeof ( info ) ) ;
info . magic = W25Q64_INFO_MAGIC ;
}
info . sequence + + ;
info . new_version = version ;
info . new_size = size ;
info . new_crc16 = crc16 ;
info . new_valid = 1 ;
info . update_state = W25Q64_STATE_DOWNLOADED ;
info . boot_trial_count = 0 ;
info . app_confirmed = 0 ;
info . backup_valid = 0 ; /* <20> <> <EFBFBD> <EFBFBD> <EFBFBD> غ<EFBFBD> <D8BA> <EFBFBD> <EFBFBD> <EFBFBD> һ <EFBFBD> θ<EFBFBD> <CEB8> <EFBFBD> <EFBFBD> <EFBFBD> Ҫ<EFBFBD> <D2AA> <EFBFBD> ±<EFBFBD> <C2B1> ݵ<EFBFBD> ǰ APP */
ret = W25Q64_OTA_WriteInfo ( & info ) ;
storage_unlock ( ) ;
return ret ;
}
int W25Q64_OTA_SetBackupInfo ( uint32_t size , uint16_t crc16 )
{
int ret = 0 ;
storage_lock ( ) ;
W25Q64_OtaInfo info ;
if ( W25Q64_OTA_ReadInfo ( & info ) ! = 0 ) { storage_unlock ( ) ; return - 1 ; }
info . sequence + + ;
info . backup_size = size ;
info . backup_crc16 = crc16 ;
info . backup_valid = 1 ;
ret = W25Q64_OTA_WriteInfo ( & info ) ;
storage_unlock ( ) ;
return ret ;
}
int W25Q64_OTA_ClearNew ( void )
{
int ret = 0 ;
storage_lock ( ) ;
W25Q64_OtaInfo info ;
if ( W25Q64_OTA_ReadInfo ( & info ) ! = 0 ) { storage_unlock ( ) ; return - 1 ; }
info . sequence + + ;
info . new_valid = 0 ;
info . update_state = W25Q64_STATE_IDLE ;
info . app_confirmed = 0 ;
info . backup_valid = 0 ; /* <20> <> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> ȷ<EFBFBD> ϣ<EFBFBD> <CFA3> ɱ<EFBFBD> <C9B1> ݲ<EFBFBD> <DDB2> <EFBFBD> <EFBFBD> <EFBFBD> Ч */
ret = W25Q64_OTA_WriteInfo ( & info ) ;
storage_unlock ( ) ;
return ret ;
}
int W25Q64_OTA_SetState ( uint8_t state )
{
int ret = 0 ;
storage_lock ( ) ;
W25Q64_OtaInfo info ;
if ( W25Q64_OTA_ReadInfo ( & info ) ! = 0 ) { storage_unlock ( ) ; return - 1 ; }
info . sequence + + ;
info . update_state = state ;
ret = W25Q64_OTA_WriteInfo ( & info ) ;
storage_unlock ( ) ;
return ret ;
}
int W25Q64_OTA_IncTrial ( void )
{
int ret = 0 ;
storage_lock ( ) ;
W25Q64_OtaInfo info ;
if ( W25Q64_OTA_ReadInfo ( & info ) ! = 0 ) { storage_unlock ( ) ; return - 1 ; }
info . sequence + + ;
info . boot_trial_count + + ;
ret = W25Q64_OTA_WriteInfo ( & info ) ;
storage_unlock ( ) ;
return ret ;
}
int W25Q64_OTA_SetConfirmed ( void )
{
int ret = 0 ;
storage_lock ( ) ;
W25Q64_OtaInfo info ;
if ( W25Q64_OTA_ReadInfo ( & info ) ! = 0 ) { storage_unlock ( ) ; return - 1 ; }
info . sequence + + ;
info . app_confirmed = 1 ;
ret = W25Q64_OTA_WriteInfo ( & info ) ;
storage_unlock ( ) ;
return ret ;
}
int W25Q64_OTA_ClearConfirmed ( void )
{
int ret = 0 ;
storage_lock ( ) ;
W25Q64_OtaInfo info ;
if ( W25Q64_OTA_ReadInfo ( & info ) ! = 0 ) { storage_unlock ( ) ; return - 1 ; }
info . sequence + + ;
info . app_confirmed = 0 ;
ret = W25Q64_OTA_WriteInfo ( & info ) ;
storage_unlock ( ) ;
return ret ;
}
uint16_t W25Q64_CRC16 ( const uint8_t * data , uint32_t len )
{
uint16_t crc = 0xFFFF ;
for ( uint32_t i = 0 ; i < len ; i + + ) {
crc ^ = data [ i ] ;
for ( int b = 0 ; b < 8 ; b + + ) {
if ( crc & 0x0001 ) crc = ( crc > > 1 ) ^ 0xA001 ;
else crc > > = 1 ;
}
}
return crc ;
}