AI嵌入式K210项目(14)-TF卡读取

这篇具有很好参考价值的文章主要介绍了AI嵌入式K210项目(14)-TF卡读取。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


前言

本章介绍一些读取TF卡的方法,本章内容和前面的项目非常类似,都是采用了SPI接口AI嵌入式K210项目(11)-SPI Flash读写

一、TF卡介绍

TF有4个数据传输端,DAT0,DAT1,DAT2,DAT3。还有一个CMD脚,是用来读取卡内信息的。

TF卡主要管脚的功能:

CLK:时钟信号,每个时钟周期传输一个命令或数据位,频率可在0~25MHz之间变化,TF卡的总线管理器可以不受任何限制的自由产生0~25MHz 的频率;

CMD:双向命令和回复线,命令是主机到从卡操作的开始,命令可以是从主机到单卡寻址,也可以是到所有卡;回复是对之前命令的回答,回复可以来自单 卡或所有卡;

DAT0~3:数据线,数据可以从TF卡传向主机也可以从主机传向TF卡。

TF卡传输数据一般有两种模式,SD模式和SPI模式,这里我们以SPI模式的方式传输数据。SPI模式引脚如下:1:CS,2:DI,3:VSS,4:VDD,5:SCLK,6:VSS2,7:DO,8:RSV,9:RSV。
AI嵌入式K210项目(14)-TF卡读取,K210开发板,人工智能,fpga开发,文件系统,TF卡,嵌入式AI,AI,嵌入式
AI嵌入式K210项目(14)-TF卡读取,K210开发板,人工智能,fpga开发,文件系统,TF卡,嵌入式AI,AI,嵌入式

二、K210的SPI接口

对应的头文件 spi.h

SPI是一种高速、高效率的串行接口技术。通常由一个主模块和一个或多个从模块组成,主模块选择一个从模块进行同步通信,从而完成数据的交换。SPI是一个环形结构,通信时需要至少4根线(事实上在单向传输时3根线也可以),它们是MISO(主设备数据输入)、MOSI(主设备数据输出)、SCLK(时钟)、CS(片选)。

(1)MISO– Master Input Slave Output,主设备数据输入,从设备数据输出;

(2)MOSI– Master Output Slave Input,主设备数据输出,从设备数据输入;

(3)SCLK – Serial Clock,时钟信号,由主设备产生;

(4)CS – Chip Select,从设备使能信号,由主设备控制。当有多个从设备的时候,因为每个从设备上都有一个片选引脚接入到主设备机中,当我们的主设备和某个从设备通信时将需要将从设备对应的片选引脚电平拉低或者是拉高。

AI嵌入式K210项目(14)-TF卡读取,K210开发板,人工智能,fpga开发,文件系统,TF卡,嵌入式AI,AI,嵌入式

为用户提供以下接口:

• spi_init:设置SPI工作模式、多线模式和位宽。

• spi_init_non_standard:多线模式下设置指令长度、地址长度、等待时钟数、指令地址传输模式。

• spi_send_data_standard:SPI标准模式传输数据。

• spi_send_data_standard_dma:SPI标准模式下使用DMA传输数据。

• spi_receive_data_standard:标准模式下接收数据。

• spi_receive_data_standard_dma:标准模式下通过DMA接收数据。

• spi_send_data_multiple:多线模式发送数据。

• spi_send_data_multiple_dma:多线模式使用DMA发送数据。

• spi_receive_data_multiple:多线模式接收数据。

• spi_receive_data_multiple_dma:多线模式通过DMA 接收。

• spi_fill_data_dma:通过DMA 始终发送同一个数据,可以用于刷新数据。

• spi_send_data_normal_dma:通过DMA 发送数据。不用设置指令地址。

• spi_set_clk_rate:设置SPI的时钟频率。

• spi_handle_data_dma:SPI 通过DMA 传输数据。

实验过程

代码比较多,demo会统一放到gitCode上(https://gitcode.com/bin_zhangg0n/K210/tree/main),这里只展示部分核心代码。

首先根据上面的硬件连接引脚图,完成硬件引脚和软件功能的映射关系
fpioa引脚映射

#include "fpioa.h"
#include <stdio.h>
#include "sysctl.h"
#include "dmac.h"
#include "fpioa.h"
#include "sdcard.h"
#include "ff.h"
#include "i2s.h"
#include "plic.h"
#include "uarths.h"
#include "bsp.h"

/*****************************HARDWARE-PIN*********************************/
// 硬件IO口,与原理图对应
#define PIN_TF_MISO            (26)
#define PIN_TF_CLK             (27)
#define PIN_TF_MOSI            (28)
#define PIN_TF_CS              (29)

/*****************************SOFTWARE-GPIO********************************/
// 软件GPIO口,与程序对应
#define TF_CS_GPIONUM          (2)


/*****************************FUNC-GPIO************************************/
// GPIO口的功能,绑定到硬件IO口
#define FUNC_TF_SPI_MISO        (FUNC_SPI1_D1)
#define FUNC_TF_SPI_CLK         (FUNC_SPI1_SCLK)
#define FUNC_TF_SPI_MOSI        (FUNC_SPI1_D0)
#define FUNC_TF_SPI_CS          (FUNC_GPIOHS0 + TF_CS_GPIONUM)

static int check_sdcard(void);
static int check_fat32(void);
FRESULT sd_write_file(TCHAR *path);
FRESULT sd_read_file(TCHAR *path);


/**
* Function       hardware_init
* @brief         硬件初始化,绑定GPIO口
* @param[in]     void
* @param[out]    void
* @retval        void
* @par History   无
*/
void hardware_init(void)
{
    /*
    ** io26--miso--d1
    ** io27--clk---sclk
    ** io28--mosi--d0
    ** io29--cs----cs
    */
    fpioa_set_function(PIN_TF_MISO, FUNC_TF_SPI_MISO);
    fpioa_set_function(PIN_TF_CLK,  FUNC_TF_SPI_CLK);
    fpioa_set_function(PIN_TF_MOSI, FUNC_TF_SPI_MOSI);
    fpioa_set_function(PIN_TF_CS,   FUNC_TF_SPI_CS);
}

/**
* Function       main
* @brief         主函数,程序的入口
* @param[in]     void
* @param[out]    void
* @retval        0
* @par History   无
*/
int main(void)
{
    // 硬件引脚初始化
    hardware_init();

    /* 设置系统时钟频率 */
    sysctl_pll_set_freq(SYSCTL_PLL0, 800000000UL);
    sysctl_pll_set_freq(SYSCTL_PLL1, 300000000UL);
    sysctl_pll_set_freq(SYSCTL_PLL2, 45158400UL);
    uarths_init();

    if (check_sdcard())
    {
        printf("SD card err\n");
        return -1;
    }

    if (check_fat32())
    {
        printf("FAT32 err\n");
        return -1;
    }

    sleep(1);
    if (sd_write_file(_T("0:test.txt")))
    {
        printf("SD write err\n");
        return -1;
    }

    if (sd_read_file(_T("0:test.txt")))
    {
        printf("SD read err\n");
        return -1;
    }
    
    while (1);
    return 0;
}

/**
* Function       check_sdcard
* @brief         检测TF是否正常
* @param[in]     void
* @param[out]    void
* @retval        0
* @par History   无
*/
static int check_sdcard(void)
{
    uint8_t status;

    printf("/******************check_sdcard*****************/\n");
    status = sd_init();
    printf("sd init :%d\n", status);
    if (status != 0)
    {
        return status;
    }

    printf("CardCapacity:%.1fG \n", (double)cardinfo.CardCapacity / 1024 / 1024 / 1024);
    printf("CardBlockSize:%d\n", cardinfo.CardBlockSize);
    return 0;
}

/**
* Function       check_fat32
* @brief         检测TF的格式是否FAT32
* @param[in]     void
* @param[out]    void
* @retval        0
* @par History   无
*/
static int check_fat32(void)
{
    static FATFS sdcard_fs;
    FRESULT status;
    DIR dj;
    FILINFO fno;

    printf("/********************check_fat32*******************/\n");
    status = f_mount(&sdcard_fs, _T("0:"), 1);
    printf("mount sdcard:%d\n", status);
    if (status != FR_OK)
        return status;

    printf("printf filename\n");
    status = f_findfirst(&dj, &fno, _T("0:"), _T("*"));
    while (status == FR_OK && fno.fname[0])
    {
        if (fno.fattrib & AM_DIR)
            printf("dir:%s\n", fno.fname);
        else
            printf("file:%s\n", fno.fname);
        status = f_findnext(&dj, &fno);
    }
    f_closedir(&dj);
    return 0;
}

/**
* Function       sd_write_file
* @brief         写入文件到TF卡
* @param[in]     void
* @param[out]    void
* @retval        0
* @par History   无
*/
FRESULT sd_write_file(TCHAR *path)
{
    FIL file;
    FRESULT ret = FR_OK;
    printf("/*******************sd_write_file*******************/\n");
    uint32_t v_ret_len = 0;

    /* 打开文件,如果文件不存在,则新建 */
    if ((ret = f_open(&file, path, FA_CREATE_ALWAYS | FA_WRITE)) != FR_OK)
    {
        printf("open file %s err[%d]\n", path, ret);
        return ret;
    }
    else
    {
        printf("Open %s ok\n", path);
    }

    /* 要写入的数据 */
    uint8_t data[] = {'H','e','l','l','o',',','W','o','r','l','d','!','T','e','s','t',',','O','k','!'};

    /* 写入数据 */
    ret = f_write(&file, data, sizeof(data), &v_ret_len);
    if (ret != FR_OK)
    {
        printf("Write %s err[%d]\n", path, ret);
    }
    else
    {
        printf("Write %d bytes to %s ok\n", v_ret_len, path);
    }
    /* 关闭文件 */
    f_close(&file);
    return ret;
}

/**
* Function       sd_read_file
* @brief         从TF卡读取文件
* @param[in]     void
* @param[out]    void
* @retval        0
* @par History   无
*/
FRESULT sd_read_file(TCHAR *path)
{
    FIL file;
    FRESULT ret = FR_OK;
    printf("/*******************sd_read_file*******************/\n");
    uint32_t v_ret_len = 0;

    /* 检测文件状态 */
    FILINFO v_fileinfo;
    if ((ret = f_stat(path, &v_fileinfo)) == FR_OK)
    {
        printf("%s length is %lld\n", path, v_fileinfo.fsize);
    }
    else
    {
        printf("%s fstat err [%d]\n", path, ret);
        return ret;
    }

    /* 只读方式打开文件 */
    if ((ret = f_open(&file, path, FA_READ)) == FR_OK)
    {
        char v_buf[64] = {0};
        ret = f_read(&file, (void *)v_buf, 64, &v_ret_len);
        if (ret != FR_OK)
        {
            printf("Read %s err[%d]\n", path, ret);
        }
        else
        {
            printf("Read :> %s \n", v_buf);
            printf("total %d bytes lenth\n", v_ret_len);
        }
        /* 关闭文件 */
        f_close(&file);
    }
    return ret;
}

代码完成后,进行编译

cd build

cmake .. -DPROJ=tf -G "MinGW Makefiles"

make

编译完成后,在build文件夹下会生成tf.bin文件。

使用type-C数据线连接电脑与K210开发板,打开kflash,选择对应的设备,再将程序固件烧录到K210开发板上。
AI嵌入式K210项目(14)-TF卡读取,K210开发板,人工智能,fpga开发,文件系统,TF卡,嵌入式AI,AI,嵌入式
烧录后重启开发板,实验结果如下:
AI嵌入式K210项目(14)-TF卡读取,K210开发板,人工智能,fpga开发,文件系统,TF卡,嵌入式AI,AI,嵌入式
AI嵌入式K210项目(14)-TF卡读取,K210开发板,人工智能,fpga开发,文件系统,TF卡,嵌入式AI,AI,嵌入式


总结

TF卡的读写和flash的读写类似,只不过TF卡的读写引入了文件系统文章来源地址https://www.toymoban.com/news/detail-816497.html

到了这里,关于AI嵌入式K210项目(14)-TF卡读取的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • AI嵌入式K210项目(19)-安装CanMV IDE开发软件

    前几章我们介绍K210使用C语言裸机开发方法,大家对K210内部的硬件和各种加速器有了初步的了解,但是开发人工智能相关程序,使用C语言的话复杂度比较高,因此接下来我们逐步学习基于K210芯片使用python开发人工智能相关程序,包含颜色识别,人脸识别,口罩识别等,也包

    2024年01月25日
    浏览(60)
  • [嵌入式AI从0开始到入土]14_orangepi_aipro小修补含yolov7多线程案例

    注:等我摸完鱼再把链接补上 可以关注我的B站号工具人呵呵的个人空间,后期会考虑出视频教程,务必催更,以防我变身鸽王。 第1期 昇腾Altas 200 DK上手 第2期 下载昇腾案例并运行 第3期 官方模型适配工具使用 第4期 炼丹炉的搭建(基于Ubuntu23.04 Desktop) 第5期 炼丹炉的搭建

    2024年02月19日
    浏览(32)
  • 嵌入式学习笔记(21)S5PV210的时钟域详解

    时钟域:MSYS、DSYS、PSYS 因S5PV210的时钟体系比较复杂,内部外设模块太多,因此把整个内部的时钟划分为3大块,叫做3个域。之所以分为3个域,是因为210内部的这些模块彼此工作时钟频率差异太大了,所以又必要把高速的放一起,相对低速的放在一起。 (1)MSYS:CPU(Cortex-

    2024年02月09日
    浏览(44)
  • 嵌入式学习笔记(32)S5PV210的向量中断控制器

    6.6.1异常处理的2个阶段 可以将异常处理分为2个阶段来理解。第一个阶段是异常向量表跳转;第二个阶段是进入了真正的异常处理程序irq_handler之后的部分。 6.6.2回顾:中断处理的第一个阶段(异常向量表跳转阶段)处理 (1)第一个阶段之所以能够进行,主要依赖于CPU设计时

    2024年02月07日
    浏览(58)
  • RK3588平台开发系列讲解(嵌入式AI篇)嵌入式AI的学习步骤

    沉淀、分享、成长,让自己和他人都能有所收获!😄 📢 本篇将给大家介绍什么是嵌入式AI。

    2024年02月04日
    浏览(50)
  • 什么是嵌入式AI

    人工智能概念: AI,英文的直译就是人工智能,什么是人工智能?计算机科学家们为我们定义了:就是希望计算机有类似人的意识,比如可以推理,自我学习,感情等能力,研究、开发用于模拟、延伸和扩展人智能的理论、方法、技术及应用系统的一门新技术科学。人工智能

    2024年04月23日
    浏览(38)
  • 在嵌入式Linux中使用C++读取 /proc/meminfo 文件来获取系统内存大小

    在嵌入式Linux中,可以使用C++编程语言通过读取  /proc/meminfo  文件来获取系统内存大小。以下是一个示例代码片段: 上述代码打开  /proc/meminfo  文件并逐行读取其中的内容。当找到以 \\\"MemTotal:\\\" 开头的行时,提取出内存大小信息并去除空格和单位(KB),然后将其转换为无符

    2024年02月10日
    浏览(42)
  • 嵌入式项目分享 stm32智能运动计步系统 - 物联网 嵌入式 单片机

    🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。 为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天

    2024年02月20日
    浏览(71)
  • 【嵌入式项目应用】__用于搭建调试输出、建立时间系统的嵌入式框架“Zorb Framework”

    目录 一、什么是Zorb? 二、嵌入式环境搭建 三、调试输出 四、实现断言 五、建立时间系统 六、结束语 (* ̄︶ ̄)创作不易!期待你们的 点赞、收藏和评论喔。 Zorb Framework是一个基于 面向对象 的思想来搭建一个 轻量级的嵌入式框架 。 搭建Zorb Framework的目的是为在不能运行

    2024年02月06日
    浏览(47)
  • Linux嵌入式项目-智能家居

    一、资料下载  二、框架知识  三、MQTT通信协议 1、上位机APP主要工作        1.wait for msg  / while(1)订阅等待消息        2.处理消息 客户端创建了两个线程,一个线程用于发布消息,一个线程用于监听订阅消息 (那我的仿真系统也可以啊,一个发送处理数据线程。一个监听

    2024年02月16日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包