433 lines
11 KiB
C
433 lines
11 KiB
C
|
|
#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;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int W25Q64_OTA_SetNewInfo(uint16_t version, uint32_t size, uint16_t crc16)
|
|||
|
|
{
|
|||
|
|
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;
|
|||
|
|
}
|