/**********************************************************************
|
* Copyright: (C)2023 LingYun IoT System Studio
|
* Author: GuoWenxue<guowenxue@gmail.com> QQ: 281143292
|
* Description: ISKBoard Serial Number Hardware Abstract Layer driver
|
*
|
* ChangeLog:
|
* Version Date Author Description
|
* V1.0.0 2023.04.3 GuoWenxue Release initial version
|
***********************************************************************/
|
|
#include <stdio.h>
|
#include <string.h>
|
#include "stm32l4xx_hal.h"
|
#include "miscdev.h"
|
#include "devsn.h"
|
|
//#define CONFIG_TEST_DEVSN_FLASH
|
|
#ifdef CONFIG_TEST_DEVSN_FLASH
|
#define FLASH_USER_START_ADDR ( FLASH_BASE + FLASH_PAGE_SIZE * 62 ) //写Flash的地址,这里从第62页开始
|
#define FLASH_USER_END_ADDR ( FLASH_BASE + FLASH_PAGE_SIZE * 64 ) //写Flash的地址,这里以第64页结束
|
|
#define SN_START_ADDR FLASH_USER_START_ADDR
|
|
#else
|
|
#define OTP_BASEADDR 0x1FFF7000 /* OTP memory base address */
|
#define OTP_ENDADDR 0x1FFF3FFU /* OTP memory address */
|
#define OTP_BLOCKSIZE 32 /* OTP memory block size is 32 bytes */
|
#define SN_OTP_BLOCK 15 /* OTP memory get 16 blocks, and SN saved in the 16th block */
|
#define SN_OTP_ADDR (OTP_BASEADDR + SN_OTP_BLOCK*OTP_BLOCKSIZE)
|
|
#define SN_START_ADDR SN_OTP_ADDR
|
#endif
|
|
#define FlashGetChar(addr) *((char*)(addr))
|
|
#ifdef CONFIG_TEST_DEVSN_FLASH
|
static inline uint32_t flash_getpage(uint32_t addr)
|
{
|
uint32_t page = 0;
|
|
if (addr < (FLASH_BASE + FLASH_BANK_SIZE)) /* Bank 1 */
|
{
|
page = (addr - FLASH_BASE) / FLASH_PAGE_SIZE;
|
}
|
else /* Bank 2 */
|
{
|
page = (addr - (FLASH_BASE + FLASH_BANK_SIZE)) / FLASH_PAGE_SIZE;
|
}
|
|
return page;
|
}
|
|
void flash_erase(void)
|
{
|
static FLASH_EraseInitTypeDef EraseInitStruct;
|
uint32_t FirstPage = 0, NbOfPages = 0, BankNumber = 0,PAGEError = 0;
|
|
/* Erase the user Flash area (already defined by FLASH_USER_START_ADDR and FLASH_USER_END_ADDR) */
|
HAL_FLASH_Unlock();
|
|
/* Clear OPTVERR bit set on virgin samples */
|
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR);
|
|
/* Get the 1st page to erase */
|
FirstPage = flash_getpage(FLASH_USER_START_ADDR);
|
/* Get the number of pages to erase from 1st page */
|
NbOfPages = flash_getpage(FLASH_USER_END_ADDR) - FirstPage + 1;
|
/* Get the bank */
|
BankNumber = FLASH_BANK_1;
|
/* Fill EraseInit structure*/
|
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
|
EraseInitStruct.Banks = BankNumber;
|
EraseInitStruct.Page = FirstPage;
|
EraseInitStruct.NbPages = NbOfPages;
|
|
if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK)
|
{
|
printf("Flash erase failed\r\n");
|
}
|
|
HAL_FLASH_Lock();
|
}
|
#endif
|
|
|
int read_devsn(char *devsn, int size)
|
{
|
int i;
|
|
if( !devsn || size<DEVSN_LEN )
|
{
|
printf("%s(): Invalid input arugments\r\n", __func__);
|
return -1;
|
}
|
|
memset(devsn, 0, size);
|
for(i=0; i<size; i++)
|
{
|
devsn[i] = FlashGetChar(SN_START_ADDR+i);
|
}
|
|
if( !strncmp(devsn, "ISK", 3) )
|
return 0;
|
else
|
return -2;
|
}
|
|
int write_devsn(char *devsn, int bytes)
|
{
|
uint8_t i;
|
uint64_t dword[2] = {0};
|
char buf[DEVSN_LEN+1];
|
char *byte;
|
|
if( !devsn || bytes!=DEVSN_LEN || strncmp(devsn, "ISK", 3) )
|
{
|
printf("%s(): Invalid input arugments\r\n", __func__);
|
return -1;
|
}
|
|
if( !read_devsn(buf, sizeof(buf)) )
|
{
|
printf("%s(): S/N writen already!\r\n", __func__);
|
return 0;
|
}
|
|
printf("Start write S/N: %s\n", devsn);
|
|
/* Convert S/N to 2 double words */
|
byte = (char *)dword;
|
for(i=0; i<DEVSN_LEN; i++)
|
{
|
*byte = devsn[i];
|
byte++;
|
}
|
|
#ifdef CONFIG_TEST_DEVSN_FLASH
|
flash_erase();
|
#endif
|
|
/* Start write SN into flash */
|
HAL_FLASH_Unlock();
|
for(i=0; i<2; i++)
|
{
|
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, SN_START_ADDR+i*8, dword[i]) != HAL_OK)
|
{
|
printf("%s(): Flash program S/N failed!\r\n", __func__);
|
return -2;
|
}
|
}
|
HAL_FLASH_Lock();
|
|
return 0;
|
}
|