跳到主要内容

SD实验

前言

本章实验将介绍如何使用TuyaOpen让T5挂载SD卡设备,并测试读写速度。

文件系统介绍

概述

文件系统是为了存储和管理数据,而在存储设备上建立的一种组织结构。TuyaOpen的文件系统支持三种存储设备,内部flash、外部qspi flash和SD卡。

内部Flash和外部qspi flash使用的是LittleFS文件系统,而SD卡使用的是FatFS文件系统。

本章节,学会使用即可。

API 描述

1,tkl_fs_mount函数

文件系统挂载。

INT_T tkl_fs_mount(CONST CHAR_T *path, FS_DEV_TYPE_T dev_type);

1.1 参数描述

形参描述
path挂载路径名称
dev_type挂载设备类型

path:挂载路径名称

dev_type:挂载设备类型。

/* TuyaOpen/platform/T5AI/tuyaos/tuyaos_adapter/include/system/tkl_fs.h */
typedef enum {
DEV_INNER_FLASH, /* 挂载内部flash */
DEV_EXT_FLASH, /* 挂载外扩flash */
DEV_SDCARD, /* 挂载SD卡 */
} FS_DEV_TYPE_T;

1.2 返回值

0表示挂载成功,-1表示挂载失败。

2,tkl_fopen函数

打开文件。

TUYA_FILE tkl_fopen(const char *path, const char *mode);

2.1 参数描述

path:打开文件路径

mode:打开文件模式

2.2 返回值

返回文件句柄,为NULL,则打开失败。

3,tkl_fwrite函数

向文件写数据。

int tkl_fwrite(void *buf, int bytes, TUYA_FILE file);

3.1 参数描述

buf:写入缓存

bytes: 写入大小

file:文件句柄

3.2 返回值:

写入数据大小。

4,tkl_fread函数

向文件读数据。

int tkl_fread(void *buf, int bytes, TUYA_FILE file);

4.1 参数描述

buf:读取缓存

bytes:读取大小

file:文件句柄

4.2 返回值:

读取数据大小。

5,tkl_fclose函数

关闭文件操作。

int tkl_fclose(TUYA_FILE file);

5.1 参数描述

file:文件句柄

5.2 返回值:

0:关闭成功;其他:关闭失败。

本实验涉及了上述文件操作函数,其他相关函数可在TuyaOpen/tools/porting/adapter/system/tkl_fs.h路径下找到

硬件设计

例程功能

1,测试SD卡读写速率。

[!NOTE]

TuyaOpen不能读取SD卡上的中文名称文件。

硬件资源

1,RGBLCD

​ LCD_R3: P23

​ LCD_R4: P22

​ LCD_R5: P21

​ LCD_R6: P20

​ LCD_R7: P19

​ LCD_G2: P42

​ LCD_G3: P41

​ LCD_G4: P40

​ LCD_G5: P26

​ LCD_G6: P25

​ LCD_G7: P24

​ LCD_B3: P47

​ LCD_B4: P46

​ LCD_B5: P45

​ LCD_B6: P44

​ LCD_B7: P43

​ LCD_PCLK: P14

​ LCD_DE: P16

​ LCD_BL: P9

​ LCD_RST: P27

2,SPILCD

​ DC/WR: P42

​ RST: P43

​ CS: P45

​ SCK: P44

​ SDA: P46

​ BL/PWR: P9

3,SD卡

​ SD_SCK- P2

​ SD_CMD- P3

​ SD_D0- P4

​ SD_D1- P5

​ SD_D2- P36

​ SD_D3- P37

原理图

正点原子T5 AI开发板上TF卡的连接原理图,如下图所示。

程序设计

1,TF卡驱动代码

tfcard.c和tfcard.h

tfcard.h文件是TF卡函数声明。

#define SDCARD_MOUNT_PATH "/sdcard"

/* Function Declaration */
OPERATE_RET tfcard_init(void);

tfcard.c文件是对TF卡进行初始化。

static THREAD_HANDLE sg_sd_thrd_hdl;

OPERATE_RET tfcard_init(void)
{
OPERATE_RET rt = OPRT_OK;

/* Create a directory for SD card */
TUYA_CALL_ERR_LOG(tkl_fs_mount(SDCARD_MOUNT_PATH, DEV_SDCARD));
if (rt != OPRT_OK)
{
PR_ERR("Mount SD card failed: %d", rt);
tal_thread_delete(sg_sd_thrd_hdl);
sg_sd_thrd_hdl = NULL;
return OPRT_NOT_FOUND;
}

return rt;
}

上述源码中,tfcard_init函数通过调用tkl_fs_mount函数把TF卡挂载到文件系统中,进而可以使用文件操作。

2,CMakeLists.txt文件

CMakeLists.txt文件配置内容如下。

# Add Driver
set(src_dirs
TFTLCD # 添加驱动组件
TFCARD
)

foreach(dir ${src_dirs})
set(SRC_DIR ${APP_PATH}/components/BSP/${dir})
aux_source_directory(${SRC_DIR} DRIVE_SRC)
target_sources(${EXAMPLE_LIB}
PRIVATE
${DRIVE_SRC}
)
target_include_directories(${EXAMPLE_LIB}
PRIVATE
${SRC_DIR}
)
endforeach()

main.c驱动代码

在main.c里面编写如下代码。

#include "tal_api.h"
#include "tkl_output.h"
#include "tal_cli.h"
#include "test.h"
#include "tftlcd.h"
#include "tkl_fs.h"
#include "tkl_memory.h"
#include "tfcard.h"

#define TEST_FILE "/sdcard/speed_test.txt"
#define TEST_SIZE (1024 * 1024) /* 1MB */
#define BUF_SIZE (512) /* 512 */

void sdcard_test(void)
{
char wr_speed_str[32];
char rd_speed_str[32];

uint8_t *buffer = tkl_system_psram_malloc(BUF_SIZE);
if (buffer == NULL)
{
PR_ERR("malloc psram failed ");
return;
}
memset(buffer, 0xAA, BUF_SIZE);

TUYA_FILE fd;
uint32_t start_tick, end_tick;
int i;

fd = tkl_fopen(TEST_FILE, "w");
if (fd != NULL)
{
PR_DEBUG("write file %s...", TEST_FILE);
start_tick = tal_system_get_millisecond();
for (i = 0; i < TEST_SIZE / BUF_SIZE; i++)
{
tkl_fwrite(buffer, BUF_SIZE, fd);
}
tkl_fclose(fd);
end_tick = tal_system_get_millisecond();
PR_DEBUG("write file success");
PR_DEBUG("write file %s size: %.2f MB", TEST_FILE, TEST_SIZE / 1024.0 / 1024.0);
PR_DEBUG("write file %s time: %d ms | speed: %.2f KB/s", TEST_FILE, end_tick - start_tick, (TEST_SIZE / 1024.0) / ((end_tick - start_tick) / 1000.0));
snprintf(wr_speed_str, sizeof(wr_speed_str), "Write: %.2f KB/s", (TEST_SIZE / 1024.0) / ((end_tick - start_tick) / 1000.0));
tal_system_sleep(100);
}
else
{
PR_ERR("write file %s failed", TEST_FILE);
tkl_system_psram_free(buffer);
return;
}

fd = tkl_fopen(TEST_FILE, "rb");
if (fd != NULL)
{
PR_DEBUG("read file %s...", TEST_FILE);
start_tick = tal_system_get_millisecond();
for (i = 0; i < TEST_SIZE / BUF_SIZE; i++)
{
tkl_fread(buffer, BUF_SIZE, fd);
}
tkl_fclose(fd);
end_tick = tal_system_get_millisecond();
PR_DEBUG("read file %s success", TEST_FILE);
PR_DEBUG("read file %s size: %.2f MB", TEST_FILE, TEST_SIZE / 1024.0 / 1024.0);
PR_DEBUG("read file %s time: %d ms | speed: %.2f KB/s", TEST_FILE, end_tick - start_tick, (TEST_SIZE / 1024.0) / ((end_tick - start_tick) / 1000.0));
snprintf(rd_speed_str, sizeof(rd_speed_str), "Read: %.2f KB/s", (TEST_SIZE / 1024.0) / ((end_tick - start_tick) / 1000.0));
tal_system_sleep(100);
}
else
{
PR_ERR("read file %s failed", TEST_FILE);
tkl_system_psram_free(buffer);
return;
}

tkl_fs_remove(TEST_FILE);
tkl_system_psram_free(buffer);

/* Display all test results on LCD */
tal_system_sleep(500);
tftlcd_show_string(30, 150, 300, 16, 16, wr_speed_str, RED);
tftlcd_show_string(30, 170, 300, 16, 16, rd_speed_str, RED);

PR_DEBUG("SD card test completed!");
}

/**
* @brief user_main
*
* @param[in] none
* @return none
*/
void user_main(void)
{
tal_log_init(TAL_LOG_LEVEL_DEBUG, 1024, (TAL_LOG_OUTPUT_CB)tkl_log_output); /* Initialize log output */
tdd_disp_atk_tftlcd_register(); /* Register the TFTLCD LCD display */

tftlcd_show_string(30, 50, 200, 16, 16, "T5 MINI Board", RED);
tftlcd_show_string(30, 70, 200, 16, 16, "SD TEST", RED);
tftlcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);

while (tfcard_init())
{
tftlcd_show_string(30, 110, 200, 16, 16, "SD Mount Failed!", RED);
tal_system_sleep(500);
tftlcd_show_string(30, 130, 200, 16, 16, "Please Check!", RED);
tal_system_sleep(500);
}

tftlcd_show_string(30, 110, 200, 16, 16, "SD Card OK ", BLUE);
tftlcd_show_string(30, 130, 200, 16, 16, "sdcard_test...", BLUE);

sdcard_test();

while (1)
{
tal_system_sleep(1000); /* Sleep for 1000 ms */
}
}

/**
* @brief main
*
* @param argc
* @param argv
* @return none
*/
#if OPERATING_SYSTEM == SYSTEM_LINUX
void main(int argc, char *argv[])
{
user_main();

while (1) {
tal_system_sleep(500);
}
}
#else

/**
* @brief The application entry point
*
* @param[in] none
* @return none
*/
void tuya_app_main(void)
{
user_main();
}

#endif

从user_main函数可以看到,初始化硬件完成之后,就进行sdcard_test测试,操作SD卡的speed_test.txt进行读写,从而计算读写速率。

运行验证

程序下载完成后,测试SD卡读写速率。