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

news2024/11/18 20:31:35

文章目录

  • 前言
  • 一、TF卡介绍
  • 二、K210的SPI接口
  • 实验过程
  • 总结


前言

本章介绍一些读取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。
在这里插入图片描述
在这里插入图片描述

二、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,从设备使能信号,由主设备控制。当有多个从设备的时候,因为每个从设备上都有一个片选引脚接入到主设备机中,当我们的主设备和某个从设备通信时将需要将从设备对应的片选引脚电平拉低或者是拉高。

image.png

为用户提供以下接口:

• 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会统一放到gitee上,这里只展示部分核心代码。

首先根据上面的硬件连接引脚图,完成硬件引脚和软件功能的映射关系
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开发板上。
在这里插入图片描述
烧录后重启开发板,实验结果如下:
在这里插入图片描述
在这里插入图片描述


总结

TF卡的读写和flash的读写类似,只不过TF卡的读写引入了文件系统

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1395602.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

多标签节点分类

Multi-Label Node Classification on Graph-Structured Data,TMLR’23 Code 学习笔记 图结构数据的多标签分类 节点表示或嵌入方法 通常会生成查找表&#xff0c;以便将相似的节点嵌入的更近。学习到的表示用作各种下游预测模块的输入特征。 表现突出的方法是基于随机游走(ran…

开发日记3(java面向对象)

&#xff08;一&#xff09;java面向对象 1、面向过程和面向对象 很久很久以前&#xff0c;系统学习过C语言&#xff0c;但也只是学过&#xff0c;没有产生过除了考试以外的其他价值。后来工作中很多伙伴都在使用java&#xff0c;虽然当时自己不写java&#xff0c;但很久之前…

Linux CentOS stream9 nmcli

nmcli命令是redhat7或者centos7之后的命令&#xff0c;该命令可以完成网卡上所有的配置工作&#xff0c;并且可以写入配置文件&#xff0c;永久生效。 一、前期准备 在讨论、学习与训练nmcli命令前&#xff0c;必须明确几点&#xff1a; 1.开启NetworkManager 使用nmcli命令…

数据结构--串

本文为复习的草稿笔记&#xff0c;&#xff0c;&#xff0c;有点乱 1. 串的基本概念和基本操作 串是由零个或多个字符组成的有限序列 2. 串的存储结构 3.串的应用 模式匹配 BF算法&#xff08;简单匹配算法 穷举法 算法思路&#xff1a;从子串的每一个字符开始依次与主串…

百度云网盘下载速度如何提升到正常速度

引入问题 我们在下载代码学习资料的时候大多数都是百度云网盘&#xff0c;但是限速&#xff01;下载的十分的慢&#xff0c;有什么办法能让我们不开通会员就能享受正常速度呢&#xff1f; 当然有&#xff01; 解决百度云网盘下载速度过慢&#xff0c;提高到正常速度 点击右…

SpringBoot + 自定义注解 + AOP 打造通用开关

前言 最近在工作中迁移代码的时候发现了以前自己写的一个通用开关实现&#xff0c;发现挺不错&#xff0c;特地拿出来分享给大家。 为了有良好的演示效果&#xff0c;我特地重新建了一个项目&#xff0c;把核心代码提炼出来加上了更多注释说明&#xff0c;希望xdm喜欢。 案例 …

编译FFmpeg4.3.1 、x264并移植到Android

1、前言 FFmpeg 既是一款音视频编解码工具&#xff0c;同时也是一组音视频编解码开发套件。 2、准备工作 系统&#xff1a;LinuxNDK&#xff1a;android-ndk-r21b-linux-x86_64.zipFFmpeg&#xff1a;ffmpeg-snapshot.tar.bz2x264&#xff1a;x264 3、下载NDK 在linux环境中…

触摸按键控制LED灯

目录 1.理论 2.代码 2.1 touch_ctrl_led.v 2.2 tb_touch_ctrl_led 1.理论 以上的波形图的touch_flag是采用组合逻辑的方式产生的。 以上的touch_flag是采用时序逻辑产生的&#xff0c;时序逻辑会延迟一拍。 以上是上升沿和下降沿的组合逻辑和时序逻辑实现&#xff0c;逻辑或…

Spring Boot - 利用Resilience4j-Circuitbreaker实现断路器模式_防止级联故障

文章目录 PreResilience4j概述Resilience4j官方地址Resilience4j-Circuitbreaker应用场景微服务演示Address servicePOMModelRepositoryServiceControllerData InitProperties测试 Order serviceModelRepositoryServiceSet UpProperties测试 探究断路器调用order-service API 2…

spring boot学习第八篇:kafka监听消费

为了实现监听器功能 pom.xml文件内容如下&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLoc…

.NetCore Flurl.Http 4.0.0 以上管理客户端

参考原文地址&#xff1a;Managing Clients - Flurl 管理客户端 Flurl.Http 构建在堆栈之上System.Net.Http。如果您熟悉HttpClient&#xff0c;那么您可能听说过这个建议&#xff1a;不要为每个请求创建一个新客户端&#xff1b;重复使用它们&#xff0c;否则将面临后…

navigateTo失效-跳转不了页面解决办法!uniapp\vue

改了一个小时多的错误&#xff0c;跳转页面无论怎么样都跳转不了&#xff0c;有2个问题&#xff1a; 注意&#xff1a;uniapp的报错可以在console里检查&#xff01; 1.pages.json文件没有配置路径&#xff0c; 在pages:[ ]里面加 &#xff08;根据自己的路径进行修改 {&qu…

Plane Geometry (Junior High School)

初中平面几何&#xff0c; ACBD, ∠CAD60&#xff0c;∠C40&#xff0c;求∠B Vertical Calculation-CSDN博客 Rectangular Area-CSDN博客

详细介绍IP 地址、网络号和主机号、ABC三类、ip地址可分配问题、子网掩码、子网划分

1、 IP 地址: 网络之间互连的协议&#xff0c;是由4个字节(32位二进制)组成的逻辑上的地址。 将32位二进制进行分组&#xff0c;分成4组&#xff0c;每组8位(1个字节)。【ip地址通常使用十进制表示】ip地址分成四组之后&#xff0c;在逻辑上&#xff0c;分成网络号和主机号 2…

Java多线程并发篇----第二十二篇

系列文章目录 文章目录 系列文章目录前言一、DelayQueue(缓存失效、定时任务 )二、SynchronousQueue(不存储数据、可用于传递数据)三、LinkedTransferQueue四、LinkedBlockingDeque前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家…

港科夜闻|香港科大团队研发多功能,可重构和抗破坏单线感测器阵列

关注并星标 每周阅读港科夜闻 建立新视野 开启新思维 1、香港科大团队研发多功能、可重构和抗破坏单线感测器阵列。研究人员开发出一种受人类听觉系统启发的感测器阵列设计技术。透过模仿人耳根据音位分布来区分声音的能力&#xff0c;这种新型感测器阵列方法可能优化感测器阵列…

Ansible-基础模块

目录 一 Ansible概述 1.Ansible是什么 2.为什么要学Ansible&#xff08;特点&#xff09; 二 Ansible的架构及运行机制 1.Ansible的架构 2.Ansible的运行机制 三 Ansible环境安装部署 1.控制节点安装ansible 2.Ansible目录结构 3.Ansible 命令行模块 &#xff08;1&a…

强化学习(二)多臂老虎机 “Multi-armed Bandits”——1

将强化学习与机器学习、深度学习区分开的最重要的特征为&#xff1a;它通过训练中信息来评估所采取的动作&#xff0c;而不是给出正确的动作进行指导&#xff0c;这极大地促进了寻找更优动作的需求。 1、多臂老虎机&#xff08;Multi-armed Bandits&#xff09;问题 赌场的老虎…

解析Transformer模型

原文地址&#xff1a;https://zhanghan.xyz/posts/17281/ 进入Transformer RNN很难处理冗长的文本序列&#xff0c;且很容易受到所谓梯度消失/爆炸的问题。RNN是按顺序处理单词的&#xff0c;所以很难并行化。 用一句话总结Transformer&#xff1a;当一个扩展性极佳的模型和一…

全链路压力测试:现代软件工程中的重要性

全链路压力测试不仅可以确保系统在高负载下的性能和稳定性&#xff0c;还能帮助企业进行有效的风险管理和性能优化。在快速发展的互联网时代&#xff0c;全链路压力测试已成为确保软件产品质量的关键步骤。 1、测试环境搭建 测试应在与生产环境尽可能相似的环境中进行&#xff…