Files
kunlun/dtest/spi_flash_test/dtest_spi_flash.c
2024-09-28 14:24:04 +08:00

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