基于zynq的micro SD卡的控制

一、SD基础知识

1.SD卡的类型、协议规范、容量等级及支持的文件系统
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

Micro SD卡,是一种极细小的快闪存储器卡,MicroSD 卡插入适配器(Adapter)可以转换成 SD 卡,其操作时序和 SD卡是一样的。
在这里插入图片描述
开发板原理图如下,可知本开发板使用的是SDIO模式的SD卡。
在这里插入图片描述

标准 SD 卡 2.0 版本中,工作时钟频率可以达到 50Mhz。
在 SDIO 模式下采用 4 位数据位宽,理论上可以达到 200Mbps(50Mx4bit)的传输速率;
在 SPI 模式下采用 1 位数据位宽,理论上可以达到 50Mbps 的传输速率。
因此 SD 卡在 SDIO 模式下的传输速率更快,同时其操作时序也更复杂。

二、SD卡控制器

ZYNQ 中的 SD 卡控制器符合 SD2.0 协议规范,接口兼容 eMMC、MMC3.31、SDIO2.0、SD2.0、SPI,
支持 SDHC、SDHS 器件。SD 卡控制器支持 SDMA(单操作 DMA)、ADMA1(4K 边界限制 DMA)和
ADMA2(在 32 位系统中允许任何位置和任意大小)。ARM 处理器通过 AHB 总线访问 SD 卡控制器,SD
控制器采用读和写通道各自双缓冲 FIFO 的机制提高吞吐带宽。其内部框图如下图所示:
在这里插入图片描述
值得一提的是,ZYNQ 内部集成了两个 SD 卡控制器,并且 Xilinx SDK 的 standalone 已经移植好了 FATFS(SDK 软件中叫做 xilffs)文件系统,因此在 SDK 中添加 xilffs 库后,就可以在程序中使用 FATFS 中的 API 函数来操作 SD 卡。
在这里插入图片描述
SD 控制器读写通道采用独立的 512 字节深度的双缓冲 FIFO 执行读和写操作
在写操作时,处理器向其中一个 FIFO 写数据,将另一个 FIFO 的数据写到 SD 总线;
在读操作时,SD 总线上的数据向其中一个FIFO 写数据,处理器将数据从另一个 FIFO 读出数据。
SD 卡控制器通过双缓冲机制以保证最大带宽。

三、文件系统(FATFS)

FATFS 是一个完全开源免费的 FAT 文件系统模块,专门为小型的嵌入式系统而设计。它完全用标准 C语言编写,所以具有良好的硬件平台独立性,可以很方便的移植到各种嵌入式处理器中。Xilinx SDK 的standalone 已经移植好了 FATFS 文件系统,因此在 SDK 中添加 xilffs 后,就可以在程序中使用 FATFS 中的 API 函数来操作 SD 卡。

FATFS 的特点如下:
1、 结构清晰,代码量少,文件系统和 IO 底层分开,特别适合新手入门学习;
2、 支持最多 10个逻辑盘符和两级文件夹;
3、 支持 FAT12/FAT16 和 FAT32 文件系统;
4、 支持长文件名称。
在这里插入图片描述

四、 SD卡控制实例:

FATFS文件系统设计参考

4.1 txt文本任务:

通过Xilinx SDK自带的FATFS库,完成对TF卡中TXT文本读写的功能,并将读写测试结果通过串口打印出来。

4.1.1 硬件部分:

UART、SD接口、DDR3存储器
在这里插入图片描述

4.1.2 软件部分:
1.板级支持包中加入FATFS文件系统

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
出现下列bsp则说明添加成功,里面包含各种需要的函数:
在这里插入图片描述

2.C设计

流程:
在这里插入图片描述
代码:

#include "xparameters.h"
#include "xil_printf.h"
#include "ff.h"								//FATFS
#include "xdevcfg.h"						//参数

#define FILE_NAME "ZDYZ.txt"                //定义文件名

const char src_str[30] = "www.openedv.com"; //定义文本内容
static FATFS fatfs;                         //文件系统

//初始化文件系统
int platform_init_fs()
{
	FRESULT status;
	TCHAR *Path = "0:/";
	BYTE work[FF_MAX_SS];

    //注册一个工作区(挂载分区文件系统)
    //在使用任何其它文件函数之前,必须使用f_mount函数为每个使用卷注册一个工作区
	status = f_mount(&fatfs, Path, 1);  //挂载SD卡
	if (status != FR_OK) {
		xil_printf("Volume is not FAT formated; formating FAT\r\n");
		//格式化SD卡
		status = f_mkfs(Path, FM_FAT32, 0, work, sizeof work);
		if (status != FR_OK) {
			xil_printf("Unable to format FATfs\r\n");
			return -1;
		}
		//格式化之后,重新挂载SD卡
		status = f_mount(&fatfs, Path, 1);
		if (status != FR_OK) {
			xil_printf("Unable to mount FATfs\r\n");
			return -1;
		}
	}
	return 0;
}

//挂载SD(TF)卡
int sd_mount()
{
    FRESULT status;
    //初始化文件系统(挂载SD卡,如果挂载不成功,则格式化SD卡)
    status = platform_init_fs();
    if(status){
        xil_printf("ERROR: f_mount returned %d!\n",status);
        return XST_FAILURE;
    }
    return XST_SUCCESS;
}

//SD卡写数据
int sd_write_data(char *file_name,u32 src_addr,u32 byte_len)
{
    FIL fil;         //文件对象
    UINT bw;         //f_write函数返回已写入的字节数

    //打开一个文件,如果不存在,则创建一个文件
    f_open(&fil,file_name,FA_CREATE_ALWAYS | FA_WRITE);
    //移动打开的文件对象的文件读/写指针     0:指向文件开头
    f_lseek(&fil, 0);
    //向文件中写入数据
    f_write(&fil,(void*) src_addr,byte_len,&bw);
    //关闭文件
    f_close(&fil);
    return 0;
}

//SD卡读数据
int sd_read_data(char *file_name,u32 src_addr,u32 byte_len)
{
	FIL fil;         //文件对象
    UINT br;         //f_read函数返回已读出的字节数

    //打开一个只读的文件
    f_open(&fil,file_name,FA_READ);
    //移动打开的文件对象的文件读/写指针     0:指向文件开头
    f_lseek(&fil,0);
    //从SD卡中读出数据
    f_read(&fil,(void*)src_addr,byte_len,&br);
    //关闭文件
    f_close(&fil);
    return 0;
}

//main函数
int main()
{
    int status,len;
    char dest_str[30] = "";

    status = sd_mount();           //挂载SD卡
    if(status != XST_SUCCESS){
		xil_printf("Failed to open SD card!\n");
		return 0;
    }
    else
        xil_printf("Success to open SD card!\n");

    len = strlen(src_str);         //计算字符串长度
    //SD卡写数据
    sd_write_data(FILE_NAME,(u32)src_str,len);
    //SD卡读数据
    sd_read_data(FILE_NAME,(u32)dest_str,len);

    //比较写入的字符串和读出的字符串是否相等
    if (strcmp(src_str, dest_str) == 0)
    	xil_printf("src_str is equal to dest_str,SD card test success!\n");
    else
    	xil_printf("src_str is not equal to dest_str,SD card test failed!\n");

    return 0;
  }

结果:运行程序后,SD卡中存在名为ZDYZ的txt文件,且文件中的字符串就是我们自定义的内容。
在这里插入图片描述

4.2 SD卡BMP拍照功能

将图像数据从DDR3内存当中写入到SD卡当中,并通过添加BMP图片的文件头和信息头,生成一张BMP图片,存储在SD卡当中。

4.2.1 BMP文件结构组成:

位图文件头+位图信息头+图像数据

在这里插入图片描述

  • 16位图:常见有两种格式,即 555 格式和 565 格式。555 格式只使用了 15 位,最后一位保留设为 0。
  • 24位图:使用 3 字节保存颜色值,每一个字节代表一种颜色,按红、绿、蓝排列。
  • 32位图:使用 4 字节保存颜色值,每一个字节代表一种颜色,红、绿、蓝,还有 Alpha 通道,即透明色。

这里以 24 位位图为例作为设计对象

4.2.2 SD卡中生成BMP文件的核心步骤
  1. 从DDR3读取32位图像数据

    • 通过直接访问内存地址从DDR3中读取一帧32位的图像数据。
    • 假设这些图像数据已经被存储在某个固定的内存地址(例如 0x2000000)。
  2. 将32位图像数据处理成24位图像数据

    • 直接从源地址读取32位图像数据。
    • 处理数据,去除每个像素中的Alpha通道,只保留红色、绿色和蓝色通道,生成24位图像数据。
    • 将处理后的24位图像数据存储到DDR3的另一个缓存区(例如 0x3800000)。
  3. 将24位图像数据加上BMP文件头写入到SD卡

    • 创建并填写BMP文件头和信息头。
    • 打开SD卡文件系统,并创建一个新的BMP文件。
    • 将BMP文件头、信息头和24位图像数据依次写入到SD卡中的文件。

32位图像数据处理成24位图像数据代码:

int get24BitPixelDirect(u8* imgSrc, u8* imgDst, int width, int height) {
    int r, c, rgb;
    for (r = 0; r < height; r++) {
        for (c = 0; c < width; c++) {
            for (rgb = 0; rgb < 4; rgb++) {
                if (rgb < 3) {
                    *imgDst = *imgSrc; // 复制R, G, B通道
                    imgDst++;
                }
                imgSrc++; // 跳过A通道
            }
        }
    }
    return 0;
}

效果:实际存储的bmp照片为上下颠倒的,
在这里插入图片描述
原因是:DDR3中图像数据是从上到下存储的,而BMP文件格式要求图像数据从下到上存储
因此这里可以在将图像数据写入BMP文件之前,对图像数据进行上下翻转。(修改之前的get24BitPixelDirect代码)

int get24BitPixelDirect(u8* imgSrc, u8* imgDst, int width, int height) {
    int r, c, rgb;
    u8 *tempBuffer = (u8 *)malloc(width * height * 3); // 临时缓冲区用于存储翻转后的数据
    if (tempBuffer == NULL) {
        return -1; // 内存分配失败
    }

    u8 *dstPtr = tempBuffer + (height - 1) * width * 3; // 指向临时缓冲区的最后一行

    for (r = 0; r < height; r++) {
        for (c = 0; c < width; c++) {
            for (rgb = 0; rgb < 4; rgb++) {
                if (rgb < 3) {
                    *dstPtr = *imgSrc; // 复制R, G, B通道
                    dstPtr++;
                }
                imgSrc++; // 跳过A通道
            }
        }
        dstPtr -= 2 * width * 3; // 每处理完一行,移动指针到临时缓冲区的上一行
    }

    // 将翻转后的数据复制到目标缓冲区
    memcpy(imgDst, tempBuffer, width * height * 3);

    free(tempBuffer); // 释放临时缓冲区

    return 0;
}

  • 29
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: ZYNQ 可以通过以下步骤安装 Ubuntu: 1. 在电脑上下载 Ubuntu 镜像文件。 2. 使用工具将 Ubuntu 镜像文件刻录到一张 SD 卡中。你可以使用 Etcher 等工具来完成这个步骤。 3. 将 SD 卡插入 ZYNQSD 卡插槽中。 4. 将 ZYNQ 连接到电脑,并使用工具(如 Xilinx Vivado)来下载系统启动镜像(FSBL)到 ZYNQ。 5. 启动 ZYNQ,它会从 SD 卡中启动并安装 Ubuntu 系统。 6. 在安装过程中,你可能需要通过键盘和显示器来输入一些信息,如用户名和密码。 7. 安装完成后,你就可以在 ZYNQ 上使用 Ubuntu 系统了。 注意:这些步骤是大致的,具体的安装过程可能会有所不同,请仔细阅读安装文档。 ### 回答2: 将ZYNQ安装Ubuntu分为以下几个步骤: 1. 准备必要的硬件和软件环境:为了安装Ubuntu,我们需要准备好一台工作站电脑、一根Micro USB线和一张MicroSD卡。确保工作站电脑已经正确安装了Vivado设计套件和Petalinux。 2. 下载Ubuntu的根文件系统:从PetaLinux安装文件夹中下载合适版本的根文件系统。根文件系统包含了ZYNQ所需的软件和必要的驱动程序。通常,这个文件应该是一个名为"Image.ub"的文件。 3. 准备MicroSD卡:将MicroSD卡插入工作站电脑的读卡器,并确保它能够被识别。使用磁盘工具将卡片格式化为ext4格式。 4. 写入根文件系统:在终端中使用以下命令,将根文件系统写入MicroSD卡: sudo dd if=<Path to the root filesystem image> of=<Path to the MicroSD card> 替换<根文件系统image路径>和< MicroSD卡路径>为实际的文件路径。请注意,写入MicroSD卡将会格式化卡片并删除其中所有的数据,请确保没有重要的数据存储在MicroSD卡中。 5. 插入MicroSD卡ZYNQ开发板:将MicroSD卡插入到ZYNQ开发板的MicroSD插槽中。 6. 设置ZYNQ启动引导:在终端中使用以下命令,将ZYNQ开发板的引导选项设置为从MicroSD卡启动: petalinux-boot --jtag --quad-boot 7. 开启ZYNQ开发板:将ZYNQ开发板与工作站电脑通过Micro USB线连接。在终端中使用以下命令,去启动ZYNQ开发板: petalinux-boot --jtag --prebuilt 3 8. 连接到Ubuntu系统:使用终端连接到ZYNQ的Ubuntu系统: connect-tbot -c "root@192.168.1.10" 替换"192.168.1.10"为ZYNQ实际的IP地址。 随后,您将能够通过连接远程终端来与ZYNQ开发板上安装的Ubuntu系统进行交互。 ### 回答3: 在ZYNQ平台上安装Ubuntu的过程如下: 1. 准备SD卡:首先需要一张SD卡作为存储介质。格式化SD卡并将其分区,至少需要两个分区:一个用于存储启动文件,另一个用于存储Ubuntu系统。 2. 获取引导文件:从Xilinx官方网站或第三方网站下载ZYNQ的引导文件,例如U-Boot和FSBL。将这些引导文件复制到SD卡的启动分区中。 3. 获取Ubuntu系统:从官方网站下载ZYNQ适用的Ubuntu系统的镜像文件。将镜像文件解压缩,并将其中的文件复制到SD卡的系统分区中。 4. 设置启动选项:在启动分区中创建一个uEnv.txt文件,并设置引导选项。例如,指定引导文件的路径、设备树文件的路径等。 5. 连接开发板:将SD卡插入到ZYNQ开发板中,并通过网线将开发板与主机连接。 6. 启动开发板:打开开发板的电源,并通过串口连接到开发板的控制台。通过控制台配置开发板的启动选项,例如设置引导阶段的串口输出、设置引导文件路径等。 7. 开始安装:重启开发板,根据设置的启动选项加载引导文件。系统会自动引导至Ubuntu安装界面,按照界面指示进行安装。 8. 完成安装:安装完成后,系统会自动重启。此时,就可以通过串口连接到ZYNQ的Ubuntu系统了。 需要注意的是,安装Ubuntu的具体步骤可能因不同的ZYNQ型号和版本而有所差异,建议参考相关的官方文档或社区资源获取更详细的安装步骤。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值