409 lines
12 KiB
C
409 lines
12 KiB
C
/****************************************************************************
|
|
|
|
Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED.
|
|
|
|
This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT
|
|
be copied by any method or incorporated into another program without
|
|
the express written consent of Aerospace C.Power. This Information or any portion
|
|
thereof remains the property of Aerospace C.Power. The Information contained herein
|
|
is believed to be accurate and Aerospace C.Power assumes no responsibility or
|
|
liability for its use in any way and conveys no license or title under
|
|
any patent or copyright and makes no representation or warranty that this
|
|
Information is free from patent or copyright infringement.
|
|
|
|
****************************************************************************/
|
|
|
|
#include "iot_io_api.h"
|
|
#include "iot_errno_api.h"
|
|
#include "iot_utils_api.h"
|
|
|
|
#include "spi_flash.h"
|
|
#include "iot_spi_api.h"
|
|
|
|
|
|
/************************* DEBUG START ************************/
|
|
#define SPI_FLASH_DEBUG_TEST 0
|
|
/************************* DEBUG END ************************/
|
|
|
|
#if SPI_FLASH_DEBUG_TEST
|
|
|
|
static char spi_flash_dump_buf[1024 + 16];
|
|
|
|
void spi_flash_dump_bin(void * buf, uint32_t len)
|
|
{
|
|
char *p = buf, *q = spi_flash_dump_buf;
|
|
uint32_t i, buf_len;
|
|
|
|
buf_len = iot_sprintf(q, "DUMP(%03d):", len);
|
|
|
|
for(i = 0; (i < len) && (buf_len < 1024); i++, p++) {
|
|
buf_len += iot_sprintf(q + buf_len, " %02x", ((int)*p) & 0xFF);
|
|
}
|
|
|
|
iot_cus_printf("\n[spi_DRV@%04d]:%s", __LINE__, spi_flash_dump_buf);
|
|
|
|
return;
|
|
}
|
|
|
|
void iot_cus_print_config(bool_t enable);
|
|
void iot_print_config(bool_t enable);
|
|
uint8_t test_buf[1024];
|
|
uint32_t cycle_count = 0;
|
|
char w_buf[SPI_FLASH_PAGE_SIZE];
|
|
char r_buf[SPI_FLASH_PAGE_SIZE];
|
|
|
|
char test_r_buf[SPI_FLASH_SECTOR_SIZE];
|
|
char test_w_buf[SPI_FLASH_SECTOR_SIZE];
|
|
char test_e_buf[SPI_FLASH_SECTOR_SIZE];
|
|
|
|
#define btm_rand_pattern(buf, buf_len, seed) \
|
|
do { \
|
|
int r_pttn; \
|
|
r_pttn = ((seed >> 24) & 0xFF) ^ \
|
|
((seed >> 16) & 0xFF) ^ ((seed >> 8) & 0xFF); \
|
|
for(int i = 0; i < buf_len; i++) { \
|
|
buf[i] = 0x5a ^ i ^ r_pttn; \
|
|
} \
|
|
} while (0)
|
|
|
|
/* Test pattern map from PUYA. */
|
|
#define btm_fix_pattern(buf, buf_len, pattern) \
|
|
do { \
|
|
int *pnt = (int *)buf, *pend = (int *)(buf + buf_len); \
|
|
while (pnt < pend) { \
|
|
*pnt = pattern; \
|
|
pnt += 2; \
|
|
} \
|
|
pnt = (int *)(buf + sizeof(*pnt)); \
|
|
while (pnt < pend) { \
|
|
*pnt = ~pattern; \
|
|
pnt += 2; \
|
|
} \
|
|
} while (0)
|
|
|
|
uint32_t iot_bootram_get_running_time(void)
|
|
{
|
|
return gp_timer_get_current_val(0);
|
|
}
|
|
|
|
static int btm_exe_tool_u32_data_cmp(void *d1, void *d2, int len_u32,
|
|
int *dif_idx)
|
|
{
|
|
uint32_t *p1 = d1, *p2 = d2, *p_end;
|
|
int ret = 0;
|
|
|
|
if ((NULL == p1 || NULL == p2)
|
|
|| (((int)p1 & 0x3) || ((int)p2 & 0x3))) {
|
|
return -1;
|
|
}
|
|
|
|
p_end = p1 + len_u32;
|
|
|
|
while(p1 < p_end) {
|
|
if (*p1 != *p2) {
|
|
ret = (*p1 < *p2) ? (-1) : (1);
|
|
break;
|
|
}
|
|
p1++;
|
|
p2++;
|
|
}
|
|
|
|
if (p1 < p_end) {
|
|
*dif_idx = ((int)p1 - (int)d1) / sizeof(*p1);
|
|
} else {
|
|
*dif_idx = 0;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int btm_executor_spi_flash_test_sector_rw_scan(uint32_t id, int offset,
|
|
int *err_offset, int *rd_data, int *exp_data, int auto_pattern, int pattern)
|
|
{
|
|
int page_s, page_e, page, i, cur_ptn;
|
|
|
|
os_mem_set(w_buf, 0xFF, SPI_FLASH_PAGE_SIZE);
|
|
|
|
page_s = offset & (~(SPI_FLASH_SECTOR_SIZE - 1));
|
|
page_e = page_s + SPI_FLASH_SECTOR_SIZE;
|
|
|
|
/* Erase sector */
|
|
spi_flash_raw_erase_sector(id, page_s, SPI_FLASH_SECTOR_SIZE);
|
|
os_delay(1);
|
|
|
|
/* Check erase. */
|
|
for (page = page_s; page < page_e; page += SPI_FLASH_PAGE_SIZE) {
|
|
if (ERR_OK != spi_flash_raw_read(id, page, (uint8_t*)r_buf,
|
|
SPI_FLASH_PAGE_SIZE)) {
|
|
iot_cus_printf("[%s][err] read failed!\n", __FUNCTION__);
|
|
goto err_out;
|
|
}
|
|
|
|
if (btm_exe_tool_u32_data_cmp(w_buf, r_buf,
|
|
SPI_FLASH_PAGE_SIZE / sizeof(uint32_t), &i)) {
|
|
iot_cus_printf("\r\n[%d] btm_exe_tool_u32_data_cmp failed\n", __LINE__);
|
|
goto err_out;
|
|
}
|
|
}
|
|
|
|
os_delay(1);
|
|
|
|
cur_ptn = pattern;
|
|
/* Write pattern for every page */
|
|
for (page = page_s; page < page_e; page += SPI_FLASH_PAGE_SIZE) {
|
|
if (auto_pattern) {
|
|
btm_rand_pattern(w_buf, SPI_FLASH_PAGE_SIZE, page);
|
|
} else {
|
|
btm_fix_pattern(w_buf, SPI_FLASH_PAGE_SIZE, cur_ptn);
|
|
cur_ptn = ~cur_ptn;
|
|
}
|
|
|
|
if (ERR_OK != spi_flash_raw_write_page(id, page, (uint8_t*)w_buf,
|
|
sizeof(w_buf))) {
|
|
iot_cus_printf("[%s][err] write failed!\n", __FUNCTION__);
|
|
goto err_out;
|
|
}
|
|
}
|
|
|
|
os_delay(1);
|
|
|
|
cur_ptn = pattern;
|
|
/* Verify data for every page. */
|
|
for (page = page_s; page < page_e; page += SPI_FLASH_PAGE_SIZE) {
|
|
if (auto_pattern) {
|
|
btm_rand_pattern(w_buf, SPI_FLASH_PAGE_SIZE, page);
|
|
} else {
|
|
btm_fix_pattern(w_buf, SPI_FLASH_PAGE_SIZE, cur_ptn);
|
|
cur_ptn = ~cur_ptn;
|
|
}
|
|
|
|
if (ERR_OK != spi_flash_raw_read(id, page, (uint8_t*)r_buf,
|
|
SPI_FLASH_PAGE_SIZE)) {
|
|
iot_cus_printf("[%s][err] read failed!\n", __FUNCTION__);
|
|
goto err_out;
|
|
}
|
|
|
|
if (btm_exe_tool_u32_data_cmp(w_buf, r_buf,
|
|
SPI_FLASH_PAGE_SIZE / sizeof(uint32_t), &i)) {
|
|
iot_cus_printf("\r\n[%d] btm_exe_tool_u32_data_cmp failed\n", __LINE__);
|
|
goto err_out;
|
|
}
|
|
}
|
|
|
|
os_delay(1);
|
|
|
|
iot_cus_printf("[%s][info] cycle %dth test 0x%x ok!\n", __FUNCTION__,
|
|
cycle_count, page_s);
|
|
|
|
return 0;
|
|
|
|
err_out:
|
|
|
|
*err_offset = page + i * sizeof(uint32_t);
|
|
*rd_data = *(int *)((int *)r_buf + i);
|
|
*exp_data = *(int *)((int *)w_buf + i);
|
|
|
|
return -1;
|
|
}
|
|
|
|
uint8_t spi_falsh_test_operate_sector(uint32_t id)
|
|
{
|
|
uint32_t time1, time2;
|
|
uint32_t cycle_count = 0;
|
|
|
|
os_mem_set(test_e_buf, 0xff, SPI_FLASH_SECTOR_SIZE);
|
|
|
|
iot_cus_printf("spi_falsh_test_ten_sector ...\n");
|
|
|
|
while(1) {
|
|
for (int i = 0; i < SPI_FLASH_SECTOR_SIZE;) {
|
|
if (cycle_count % 2) {
|
|
test_w_buf[i] = 0xaa;
|
|
test_w_buf[i+1] = 0x55;
|
|
} else {
|
|
test_w_buf[i] = 0x55;
|
|
test_w_buf[i+1] = 0xaa;
|
|
}
|
|
i += 2;
|
|
}
|
|
|
|
time1 = gp_timer_get_current_val(0);
|
|
for (int i = 0; i < 10; i++) {
|
|
if (ERR_OK != spi_flash_raw_erase_sector(id, i * SPI_FLASH_SECTOR_SIZE,
|
|
SPI_FLASH_SECTOR_SIZE)) {
|
|
iot_printf("\n[spi_DRV@%04d]:sec#0x%x erase failed!",
|
|
__LINE__, i * SPI_FLASH_SECTOR_SIZE);
|
|
}
|
|
}
|
|
|
|
while(ERR_OK != spi_flash_raw_write_start(id));
|
|
time2 = gp_timer_get_current_val(0);
|
|
if (time1 > time2) {
|
|
time1 = (((uint32_t)(-1)) - time1 + time2);
|
|
} else {
|
|
time1 = (time2 - time1);
|
|
}
|
|
|
|
for (int i = 0; i < 10; i++) {
|
|
if ( -1 != custom_ext_dev_seek(id, i * SPI_FLASH_SECTOR_SIZE, DEV_SEEK_SET)) {
|
|
if ( -1 == custom_ext_dev_read(id, test_r_buf, SPI_FLASH_SECTOR_SIZE)) {
|
|
iot_cus_printf("[test][err] test cycle_count[%d] - read [%dth] sec failed!!!\n",
|
|
cycle_count, i+1);
|
|
}
|
|
} else {
|
|
iot_cus_printf("[test][err] seek failed!!!\n");
|
|
}
|
|
if (0 != os_mem_cmp(test_e_buf, test_r_buf, SPI_FLASH_SECTOR_SIZE)) {
|
|
iot_cus_printf("[test][err] wirte is not match.!!!\n");
|
|
}
|
|
}
|
|
iot_cus_printf("test erase passed. Takes %u ns.\n", time1);
|
|
|
|
time1 = gp_timer_get_current_val(0);
|
|
for (int i = 0; i < 10; i++) {
|
|
if ( -1 != custom_ext_dev_seek(id, i * SPI_FLASH_SECTOR_SIZE, DEV_SEEK_SET)) {
|
|
if ( -1 == custom_ext_dev_write(id, test_w_buf, SPI_FLASH_SECTOR_SIZE)) {
|
|
iot_cus_printf("[test][err] test cycle_count[%d] - write [%dth] sec failed!!!\n",
|
|
cycle_count, i+1);
|
|
}
|
|
} else {
|
|
iot_cus_printf("[test][err] seek failed!!!\n");
|
|
}
|
|
}
|
|
time2 = gp_timer_get_current_val(0);
|
|
if (time1 > time2) {
|
|
time1 = (((uint32_t)(-1)) - time1 + time2);
|
|
} else {
|
|
time1 = (time2 - time1);
|
|
}
|
|
iot_cus_printf("test write passed. Takes %u ns.\n", time1);
|
|
|
|
time1 = gp_timer_get_current_val(0);
|
|
for (int i = 0; i < 10; i++) {
|
|
if ( -1 != custom_ext_dev_seek(id, i * SPI_FLASH_SECTOR_SIZE, DEV_SEEK_SET)) {
|
|
if ( -1 == custom_ext_dev_read(id, test_r_buf, SPI_FLASH_SECTOR_SIZE)) {
|
|
iot_cus_printf("[test][err] test cycle_count[%d] - read [%dth] sec failed!!!\n",
|
|
cycle_count, i+1);
|
|
}
|
|
} else {
|
|
iot_cus_printf("[test][err] seek failed!!!\n");
|
|
}
|
|
if (0 != os_mem_cmp(test_w_buf, test_r_buf, SPI_FLASH_SECTOR_SIZE)) {
|
|
iot_cus_printf("[test][err] wirte is not match.!!!\n");
|
|
}
|
|
}
|
|
time2 = gp_timer_get_current_val(0);
|
|
if (time1 > time2) {
|
|
time1 = (((uint32_t)(-1)) - time1 + time2);
|
|
} else {
|
|
time1 = (time2 - time1);
|
|
}
|
|
iot_cus_printf("test read passed. Takes %u ns.\n", time1);
|
|
|
|
cycle_count++;
|
|
}
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
uint8_t spi_falsh_test_whole_flash(uint32_t id, int in_addr1, int in_addr2)
|
|
{
|
|
int addr = in_addr1, addr2 = in_addr2, cyc_cnt = 0;
|
|
int rd_data, exp_data, sec_size, chip_size, err_offset;
|
|
uint32_t time1, time2;
|
|
uint32_t addr_start = in_addr1;
|
|
uint32_t addr_end = in_addr2;
|
|
|
|
iot_spi_flash_chip_info_t flash_info;
|
|
|
|
if (ERR_OK != spi_flash_get_chipinfo(id, &flash_info)) {
|
|
iot_cus_printf("[%s][err] get chip info failed!\n", __FUNCTION__);
|
|
goto err_out;
|
|
}
|
|
|
|
sec_size = flash_info.sec_size;
|
|
|
|
addr &= ~(sec_size - 1);
|
|
addr2 &= ~(sec_size - 1);
|
|
chip_size = flash_info.chip_size;
|
|
|
|
if (addr2 + sec_size > chip_size) {
|
|
cyc_cnt = chip_size - sec_size;
|
|
iot_cus_printf("\r\nEnd offset overflow, set to %p\n", addr2, cyc_cnt);
|
|
addr2 = cyc_cnt;
|
|
}
|
|
|
|
cyc_cnt = (addr2 - addr) / sec_size + 1;
|
|
|
|
iot_cus_printf("\r\n[%s]Start full scan from sector %p to %p. Total %d sectors. \
|
|
sec_size:0x%x\n", __FUNCTION__, addr, addr2, cyc_cnt, sec_size);
|
|
|
|
while(1) {
|
|
while ((cyc_cnt > 0) && (addr < g_spi_flash_obj.spi_flash_dev[id].chip.chip_size)) {
|
|
iot_cus_printf("\r\ncycle %dth sector %p scan...", cycle_count, addr);
|
|
time1 = gp_timer_get_current_val(0);
|
|
if (0 != btm_executor_spi_flash_test_sector_rw_scan(id, addr, &err_offset,
|
|
&rd_data, &exp_data, 1, 0)) {
|
|
iot_cus_printf("\r\nflash full scan failed, error offset = %p, \
|
|
read data %p, expect data = %p.\n",
|
|
err_offset, rd_data, exp_data);
|
|
break;
|
|
}
|
|
time2 = gp_timer_get_current_val(0);
|
|
if (time1 > time2) {
|
|
time1 = (((uint32_t)(-1)) - time1 + time2);
|
|
} else {
|
|
time1 = (time2 - time1);
|
|
}
|
|
addr += sec_size;
|
|
cyc_cnt--;
|
|
iot_cus_printf("passed. Takes %u ns.", time1);
|
|
}
|
|
|
|
cycle_count++;
|
|
cyc_cnt = (addr_end - addr_start) / sec_size + 1;
|
|
addr = addr_start;
|
|
os_delay(10);
|
|
}
|
|
|
|
iot_cus_printf("\r\nflash full scan done, all passed!\n", addr);
|
|
|
|
return ERR_OK;
|
|
err_out:
|
|
|
|
return ERR_FAIL;
|
|
|
|
}
|
|
|
|
extern void wdg_deinit(uint32_t cpu);
|
|
uint8_t test_spi_flash_go()
|
|
{
|
|
uint8_t flash_id = 0;
|
|
iot_cus_print_config(true);
|
|
iot_print_config(false);
|
|
|
|
wdg_deinit(0);
|
|
wdg_deinit(1);
|
|
|
|
if (ERR_OK != iot_spi_flash_init()) {
|
|
iot_cus_printf("[%s][err] flash init failed!\n", __FUNCTION__);
|
|
goto err_out;
|
|
}
|
|
|
|
if (-1 == (flash_id = custom_ext_dev_open())) {
|
|
iot_cus_printf("[%s][err] flash open failed!\n", __FUNCTION__);
|
|
goto err_out;
|
|
}
|
|
os_delay(10);
|
|
|
|
//spi_falsh_test_sector(flash_id, 0x3000);
|
|
//spi_falsh_test_whole_flash(flash_id, 0, g_spi_flash_obj.spi_flash_dev[0].chip.chip_size);
|
|
spi_falsh_test_operate_sector(flash_id);
|
|
|
|
return ERR_OK;
|
|
err_out:
|
|
return ERR_FAIL;
|
|
}
|
|
#endif
|
|
|