502 lines
14 KiB
C
502 lines
14 KiB
C
/**
|
||
******************************************************************************
|
||
* @file example_nand_flash.c
|
||
* @author august.yang
|
||
* @version V1.0.0
|
||
* @date 2020/10/13
|
||
******************************************************************************
|
||
*/
|
||
#include <stdio.h>
|
||
#include "ql_fs.h"
|
||
#include "ql_application.h"
|
||
#include "ql_rtos.h"
|
||
//#include "ql_spi_nor.h"
|
||
enum{
|
||
QL_SPI_DEV0 = 0,
|
||
QL_SPI_DEV2 = 2
|
||
};
|
||
enum{
|
||
QL_PIN_16_19 ,
|
||
QL_PIN_33_36 ,
|
||
QL_PIN_12_15
|
||
};
|
||
enum{
|
||
SPI_CLOCK_13M = 0x0,
|
||
SPI_CLOCK_26M = 0x1,
|
||
SPI_CLOCK_52M = 0x2,
|
||
};
|
||
|
||
typedef struct file {
|
||
unsigned int cnt;
|
||
unsigned char buf[64];
|
||
} file_contex;
|
||
|
||
static void list_dir(const char *path)
|
||
{
|
||
FILE_ID dp = NULL;
|
||
NandFs_info info = {0};
|
||
int ret;
|
||
|
||
dp = ql_nand_opendir(path);
|
||
if(dp == NULL)
|
||
{
|
||
printf("[FS] *** dir open fail: %s ***\r\n", path);
|
||
return;
|
||
}
|
||
printf("[FS] dir opened: %s\r\n", path);
|
||
|
||
printf("[FS] ----- start dir list -----\r\n");
|
||
printf("[FS] type\tsize\tname\r\n");
|
||
while(1)
|
||
{
|
||
ret = ql_nand_readddir(dp, &info);
|
||
if(ret < 0)
|
||
{
|
||
printf("[FS] *** dir read fail: %s ***\r\n", path);
|
||
break;
|
||
}
|
||
else if(ret == 0)
|
||
{
|
||
printf("[FS] ----- end of dir list -----\r\n");
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
printf("[FS] %-4d\t%-4d\t%s\r\n", info.type, info.size, info.name);
|
||
}
|
||
}
|
||
|
||
if(dp)
|
||
{
|
||
ql_nand_closedir(dp);
|
||
printf("[FS] dir closed: %s\r\n", path);
|
||
}
|
||
}
|
||
unsigned int crc32_test(const unsigned char *buf, int length)
|
||
{
|
||
unsigned int crc = 0xFFFFFFFF;
|
||
for (int i = 0; i < length; i++)
|
||
{
|
||
crc ^= buf[i];
|
||
for (int j = 0; j < 8; j++)
|
||
{
|
||
if (crc & 1)
|
||
crc = (crc >> 1) ^ 0xEDB88320;
|
||
else
|
||
crc >>= 1;
|
||
}
|
||
}
|
||
return crc ^ 0xFFFFFFFF;
|
||
}
|
||
#define TEST_ADDR 0x00000000
|
||
#define TEST_SIZE 4096 /* must equal page/block multiple */
|
||
#define TEST_PATTERN 0x5A
|
||
|
||
/*����4�ֽڶ���*/
|
||
__attribute__((aligned(32))) static uint8_t g_write_buf[4096];
|
||
static unsigned char g_read_buf[4096];
|
||
|
||
void nand_flash_api_test_task(void *argv)
|
||
{
|
||
int ret = 0,loop_count = 0;
|
||
unsigned int test_addr = 0, test_block_num = 0;
|
||
|
||
ql_spi_nand_flash_hndl_t hndl = NULL;
|
||
ql_spi_nand_flash_hw_info_t info = {0};
|
||
ql_rtos_task_sleep_s(10);
|
||
printf("nand flash api test task start\r\n");
|
||
for (unsigned int i = 0; i < sizeof(g_write_buf); i++) {
|
||
g_write_buf[i] = (unsigned char)(i & 0xFF); // 0,1,2,...,255,0,1,...
|
||
}
|
||
|
||
while (1)
|
||
{
|
||
int ret;
|
||
|
||
/* 1. �� NAND */
|
||
ret = ql_spi_nand_flash_open( QL_SPI_DEV2,
|
||
QL_PIN_12_15,
|
||
SPI_CLOCK_26M,
|
||
0,
|
||
&hndl);
|
||
if (ret != 0 || hndl == NULL) {
|
||
printf("[NAND] open failed (%d)\r\n", ret);
|
||
return;
|
||
}
|
||
|
||
/* 2. ��ѯӲ����Ϣ */
|
||
ret = ql_spi_nand_flash_get_hw_info(hndl, &info);
|
||
if (ret == 0) {
|
||
printf("[NAND] model=%s manufacturer=%s block_size=%u page_size=%u total=%u\r\n",
|
||
info.model_name,
|
||
info.manufacturer_name,
|
||
info.block_size,
|
||
info.page_size,
|
||
info.total_size);
|
||
}
|
||
|
||
/* 3. ��ѯ���� */
|
||
int blocks = ql_spi_nand_flash_get_block_num(hndl);
|
||
printf("[NAND] total blocks = %u\r\n", blocks);
|
||
|
||
test_addr = test_block_num * info.block_size;
|
||
if (test_addr >= info.total_size) {
|
||
test_addr = 0;
|
||
test_block_num = 0;
|
||
}
|
||
/* 4. ������� */
|
||
for (unsigned int i = 0; i < TEST_SIZE; i++)
|
||
g_write_buf[i] = TEST_PATTERN;
|
||
|
||
/* 5. �Ȳ���Ŀ����������룩 */
|
||
ret = ql_spi_nand_flash_erase(hndl, test_addr, info.block_size);
|
||
if (ret != 0) {
|
||
printf("[NAND] erase failed (%d)\r\n", ret);
|
||
goto exit;
|
||
}
|
||
|
||
/* 6. ����������������� spare�� */
|
||
ret = ql_spi_nand_flash_write(hndl,
|
||
test_addr,
|
||
g_write_buf,
|
||
TEST_SIZE,
|
||
QL_SPI_NAND_AREA_MAIN_ONLY);
|
||
if (ret != 0) {
|
||
printf("[NAND] write failed (%d)\r\n", ret);
|
||
goto exit;
|
||
}
|
||
|
||
/* 7. ��ȡ�������� */
|
||
memset(g_read_buf, 0, sizeof(g_read_buf));
|
||
ret = ql_spi_nand_flash_read(hndl,
|
||
test_addr,
|
||
g_read_buf,
|
||
TEST_SIZE,
|
||
QL_SPI_NAND_AREA_MAIN_ONLY);
|
||
if (ret != 0) {
|
||
printf("[NAND] read failed (%d)\r\n", ret);
|
||
goto exit;
|
||
}
|
||
|
||
/* 8. ������ */
|
||
if (memcmp(g_write_buf, g_read_buf, TEST_SIZE) == 0)
|
||
printf("[NAND] read-back OK\r\n");
|
||
else
|
||
printf("[NAND] data mismatch!\r\n");
|
||
|
||
exit:
|
||
ql_spi_nand_flash_close(hndl);
|
||
ql_rtos_task_sleep_ms(5000);
|
||
loop_count++;
|
||
test_block_num++;
|
||
if (test_block_num * info.block_size >= info.total_size)
|
||
{
|
||
test_block_num = 0;
|
||
}
|
||
|
||
printf("nand flash api test task loop count=%d\r\n",loop_count);
|
||
|
||
}
|
||
}
|
||
ql_task_t ql_test_task_ref;
|
||
int ql_nand_test_init(void *arg)
|
||
{
|
||
QlOSStatus status;
|
||
|
||
status =ql_rtos_task_create(&ql_test_task_ref, 4096, 100, "nandTest_task", nand_flash_api_test_task, NULL);
|
||
return 0;
|
||
}
|
||
void nand_flash_dir_test(void *argv)
|
||
{
|
||
int ret = 0;
|
||
|
||
FILE_ID filep;
|
||
size_t status = 0;
|
||
file_contex write_buffer={0};
|
||
ql_rtos_task_sleep_s(5);
|
||
ql_spi_nand_init(QL_SPI_DEV0, QL_PIN_33_36,SPI_CLOCK_26M);
|
||
ret = ql_nand_mkdir("quectel");
|
||
printf("ql_nand_mkdir %d\n",ret);
|
||
filep =ql_nand_fopen("quectel/TEST1.TXT", "wb");
|
||
write_buffer.cnt = 30965;
|
||
sprintf(write_buffer.buf,"QUECTEL_BUILED_A_SMARTER_WORLD");
|
||
status = ql_nand_fwrite( &write_buffer, 1, 68, filep);
|
||
/* Check the file write status. */
|
||
if (status != 68)
|
||
{
|
||
printf("fx_file_write is failede.!!\n");
|
||
/* Error writing to a file, break the loop. */
|
||
|
||
}
|
||
status = ql_nand_fsync(filep);
|
||
if (status != 0)
|
||
{
|
||
printf("ql_nand_fsync is failede.!!\n");
|
||
}
|
||
int cnt = 0;
|
||
char buf = 0;
|
||
file_contex read_buffer={0};
|
||
ql_nand_frewind(filep);
|
||
status = ql_nand_fread(&cnt,1,4,filep);
|
||
if(status != 4)
|
||
{
|
||
printf("ql_nand_fread.failed status = %d\r\n",status);
|
||
}
|
||
printf("ql_nand_fread.cnt= %d\r\n",cnt);
|
||
|
||
buf = ql_nand_fgetc(filep);
|
||
printf("ql_nand_fgetc.buf= %c\r\n",buf);
|
||
|
||
ql_nand_frewind(filep);
|
||
printf("ql_nand_feof = %d\r\n",ql_nand_feof(filep,"quectel/TEST1.TXT"));
|
||
|
||
if(ql_nand_fgets(&read_buffer,68,filep) != NULL);
|
||
{
|
||
printf("ql_nand_fgets.read_buffer.cnt= %d,read_buffer.buf = %s\r\n",read_buffer.cnt,read_buffer.buf);
|
||
}
|
||
printf("ql_nand_feof = %d\r\n",ql_nand_feof(filep,"quectel/TEST1.TXT"));
|
||
|
||
ql_nand_fclose(filep);
|
||
|
||
filep =ql_nand_fopen("quectel/TEST2.TXT", "wb");
|
||
write_buffer.cnt = 30966;
|
||
sprintf(write_buffer.buf,"QUECTEL_BUILED_A_SMARTER_WORLD");
|
||
status = ql_nand_fwrite( &write_buffer, 1, 68, filep);
|
||
/* Check the file write status. */
|
||
if (status != 68)
|
||
{
|
||
printf("fx_file_write is failede.!!\n");
|
||
/* Error writing to a file, break the loop. */
|
||
|
||
}
|
||
ql_nand_fclose(filep);
|
||
|
||
filep =ql_nand_fopen("quectel/TEST3.TXT", "wb");
|
||
write_buffer.cnt = 30967;
|
||
sprintf(write_buffer.buf,"QUECTEL_BUILED_A_SMARTER_WORLD");
|
||
status = ql_nand_fwrite( &write_buffer, 1, 68, filep);
|
||
/* Check the file write status. */
|
||
if (status != 68)
|
||
{
|
||
printf("fx_file_write is failede.!!\n");
|
||
/* Error writing to a file, break the loop. */
|
||
|
||
}
|
||
ql_nand_fclose(filep);
|
||
|
||
ret = ql_nand_mkdir("quectel/pony");
|
||
printf("ql_nand_mkdir1 %d\n",ret);
|
||
filep =ql_nand_fopen("quectel/pony/TEST4.TXT", "wb");
|
||
write_buffer.cnt = 30968;
|
||
sprintf(write_buffer.buf,"QUECTEL_BUILED_A_SMARTER_WORLD");
|
||
status = ql_nand_fwrite( &write_buffer, 1, 68, filep);
|
||
/* Check the file write status. */
|
||
if (status != 68)
|
||
{
|
||
printf("fx_file_write is failede.!!\n");
|
||
/* Error writing to a file, break the loop. */
|
||
|
||
}
|
||
ql_nand_fclose(filep);
|
||
|
||
filep =ql_nand_fopen("quectel/pony/TEST5.TXT", "wb");
|
||
write_buffer.cnt = 30969;
|
||
sprintf(write_buffer.buf,"QUECTEL_BUILED_A_SMARTER_WORLD");
|
||
status = ql_nand_fwrite( &write_buffer, 1, 68, filep);
|
||
/* Check the file write status. */
|
||
if (status != 68)
|
||
{
|
||
printf("fx_file_write is failede.!!\n");
|
||
/* Error writing to a file, break the loop. */
|
||
|
||
}
|
||
ql_nand_fclose(filep);
|
||
|
||
filep =ql_nand_fopen("quectel/pony/TEST6.TXT", "wb");
|
||
write_buffer.cnt = 30970;
|
||
sprintf(write_buffer.buf,"QUECTEL_BUILED_A_SMARTER_WORLD");
|
||
status = ql_nand_fwrite( &write_buffer, 1, 68, filep);
|
||
/* Check the file write status. */
|
||
if (status != 68)
|
||
{
|
||
printf("fx_file_write is failede.!!\n");
|
||
/* Error writing to a file, break the loop. */
|
||
|
||
}
|
||
ql_nand_fclose(filep);
|
||
|
||
list_dir("quectel");
|
||
ql_rtos_task_sleep_ms(50);
|
||
list_dir("quectel/pony");
|
||
}
|
||
|
||
void nand_flash_test(void *argv)
|
||
{
|
||
int ret = 0 ;
|
||
FILE_ID filep;
|
||
size_t status = 0;
|
||
file_contex local_buffer={0};
|
||
file_contex write_buffer={0};
|
||
unsigned int cnt = 35;
|
||
ql_rtos_task_sleep_s(5);
|
||
ql_spi_nand_init(QL_SPI_DEV0, QL_PIN_33_36,SPI_CLOCK_26M);
|
||
while(1)
|
||
{
|
||
ret = ql_nand_access("TEST.TXT");
|
||
if(ret != 1){//����ļ������ڿ�ס
|
||
filep = ql_nand_fopen("TEST.TXT", "wb");
|
||
ql_nand_fseek(filep, 0, SEEK_SET);
|
||
/* Write a string to the test file. */
|
||
memset(&write_buffer,0,sizeof(write_buffer));
|
||
write_buffer.cnt = 30965;
|
||
sprintf(write_buffer.buf,"QUECTEL_BUILED_A_SMARTER_WORLD");
|
||
status = ql_nand_fwrite( &write_buffer, 1, 68, filep);
|
||
/* Check the file write status. */
|
||
if (status != 68)
|
||
{
|
||
printf("fx_file_write is failede.!!\n");
|
||
/* Error writing to a file, break the loop. */
|
||
break;
|
||
}
|
||
/* Close the test file. */
|
||
status = ql_nand_fclose(filep);
|
||
if (status != NULL)
|
||
{
|
||
/* Error deleting the file, break the loop. */
|
||
printf("fx_file remove is failede.!!\n");
|
||
break;
|
||
}
|
||
printf("file is not exists");
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
printf("file exists");
|
||
filep = ql_nand_fopen("TEST.TXT", "rb+");
|
||
if (filep == NULL)
|
||
{
|
||
printf("fx_file_create is failede.!!\n");
|
||
/* Create error, break the loop. */
|
||
break;
|
||
}
|
||
ql_nand_fseek(filep, 0, SEEK_SET);
|
||
/* Read the first 28 bytes of the test file. */
|
||
status = ql_nand_fread(&local_buffer, 1, 68, filep);
|
||
printf("fx_file Reading[%d].!!\n", status);
|
||
/* Check the file read status. */
|
||
if (status != 68)
|
||
{
|
||
printf("fx_file checking is failede.!!\n");
|
||
}
|
||
else
|
||
{
|
||
cnt = local_buffer.cnt;
|
||
cnt++;
|
||
}
|
||
printf("File Context.[%d_%s].!!\n",local_buffer.cnt,local_buffer.buf );
|
||
/* Seek to the beginning of the test file. */
|
||
ql_nand_fseek(filep, 0, SEEK_SET);
|
||
/* Write a string to the test file. */
|
||
memset(&write_buffer,0,sizeof(write_buffer));
|
||
write_buffer.cnt = cnt;
|
||
sprintf(write_buffer.buf,"QUECTEL_BUILED_A_SMARTER_WORLD");
|
||
status = ql_nand_fwrite( &write_buffer, 1, 68, filep);
|
||
/* Check the file write status. */
|
||
if (status != 68)
|
||
{
|
||
printf("fx_file_write is failede.!!\n");
|
||
/* Error writing to a file, break the loop. */
|
||
break;
|
||
}
|
||
/* Close the test file. */
|
||
status = ql_nand_fclose(filep);
|
||
if (status != NULL)
|
||
{
|
||
/* Error deleting the file, break the loop. */
|
||
printf("fx_file remove is failede.!!\n");
|
||
break;
|
||
}
|
||
}
|
||
ql_rtos_task_sleep_ms(1);
|
||
}
|
||
|
||
|
||
}
|
||
|
||
#define QL_PCM_STATUS_FG_01 0x01
|
||
#define QL_PCM_STATUS_FG_02 0x02
|
||
#define QL_PCM_TASK_MASK_FG (QL_PCM_STATUS_FG_01|QL_PCM_STATUS_FG_02)
|
||
|
||
#define LOG_FILE "867862055278381-02-211124105928" //��־�ļ�
|
||
#define LOG_MANAGE_FILE "artc_manage.txt" //�����ļ�
|
||
|
||
ql_flag_t save_log_flag_ref = NULL; //������־��flag
|
||
ql_mutex_t log_rd_wr_mutex_lock; // ��дlog��־�Ļ�����
|
||
|
||
static void test_log_thread(void *argv)
|
||
{
|
||
unsigned int save_log_flag = 0;
|
||
while(1)
|
||
{
|
||
ql_rtos_flag_wait(save_log_flag_ref, QL_PCM_TASK_MASK_FG, QL_FLAG_OR_CLEAR, &save_log_flag, QL_WAIT_FOREVER);
|
||
ql_rtos_mutex_lock(log_rd_wr_mutex_lock,QL_WAIT_FOREVER); //������
|
||
|
||
log_write_file(); //ģ�ⵥ�ļ���д��־
|
||
|
||
ql_rtos_mutex_unlock(log_rd_wr_mutex_lock); //����
|
||
ql_rtos_task_sleep_ms(30);
|
||
}
|
||
}
|
||
|
||
void start_test_log_task(void) //����������־������
|
||
{
|
||
ql_task_t test_log_task = NULL;
|
||
ql_rtos_task_create(&test_log_task, 1024*10, 100, "save_log_task", test_log_thread, NULL);
|
||
}
|
||
|
||
void log_write_file()
|
||
{
|
||
FILE_ID fp_test;
|
||
char test_str[51] = "hardware03211124203908Terminal self-test completed";
|
||
|
||
if(ql_nand_access(LOG_FILE) == 1)
|
||
{
|
||
printf("before write log, file size:%d\r\n", ql_nand_fsize(LOG_FILE));
|
||
|
||
fp_test = ql_nand_fopen(LOG_FILE, "rb+");
|
||
if(fp_test == NULL)
|
||
{
|
||
printf("open LOG_FILE fail");
|
||
return;
|
||
}
|
||
|
||
ql_nand_fseek(fp_test, 0, SEEK_END); //ƫ�Ƶ��ļ�ĩ
|
||
|
||
ql_nand_fwrite(test_str, 1, strlen(test_str), fp_test);
|
||
|
||
ql_nand_fclose(fp_test);
|
||
|
||
printf("after write log, file size:%d\r\n", ql_nand_fsize(LOG_FILE));
|
||
}
|
||
else
|
||
{
|
||
printf("LOG_FILE NO EXIST AND CREATE\r\n");
|
||
fp_test = ql_nand_fopen(LOG_FILE, "wb");
|
||
ql_nand_fclose(fp_test);
|
||
}
|
||
printf("write log file end\r\n");
|
||
}
|
||
|
||
|
||
static void demo_main(void * argv)
|
||
{
|
||
ql_autosleep_enable(1);
|
||
}
|
||
//application_init(demo_main, "demo_main", 10, 1);
|
||
|
||
// application_init(nand_flash_dir_test, "nand_flash_test", 10, 6);
|
||
application_init(ql_nand_test_init, "ql_nand_test_init", 2, 6);
|
||
|
||
|
||
|