sd卡SDIO方式的读写

sd卡 secure digital memory card

nand flash 插入,清除,读写都要以块为单位。

nor flah 只要擦除时以块为单位,读取,写入可以以字节为单位。

sd卡知识

sd存储卡分为sd卡,sd hc卡,sdxc卡。

SDIO protocol

SDIO bus

SDIO的总线类型分为clock,cmd,data总线,其中data总线有1条或者4条。

时序逻辑是clock为上升沿时,cmd,data总线上的数据才有效,因此SDIO protocol 时同步通讯协议。

通信方式:host(主机)通过cmd总线向device发送命令,若device响应,则会执行该命令;若device不响应,则该命令无效。通过data block or data stream的方式在总线上传输数据,其中data block需要增加crc校验验证数据的正确与否。

      SDIO 传输1

                        SDIO 传输2

sd卡是存储器,存储器无论是清除,读取,创建数据都需要一定的时间,因此sd卡采用SDIO协议进行通信时会将D0总线拉低表示数据忙。

fat文件系统(file allocation table)

文件系统是使用存储器的抽象,提供了在存储器中创建文件,读取文件,删除文件,了解存储剩余容量等操作的接口。

相关定义

sectors:扇区,读写存储器的最小抽象存储单位,一般为512 byte,可以更大。

cluster(block): n个sectors组成了cluster(block)。在fat文件系统中,sectors组成存储单位叫做cluster,linux的文件系统叫做block。

fat文件系统的组成

fat文件系统由4个部分组成,分别是boot sector,fat region,root directory region, data region。

boot sector

boot sector引导扇区由Jump Instruction,OEM ID,BPB,end of sector marker组成。

OEM ID的全程是original equipment manufacturer identifier,用来记录系统设备制造商或是该volume创作者的信息。

BPB全程是BIOS parameter block。可能记录了总扇区数目,每个扇区拥有的字节数,每个簇有多少个扇区,保留扇区数,根目录项数,存储介质类型。

file allocation table

file allocation table指明了数据区每个簇分配的地址,每个簇之间的关系和每个簇的情况。

记录一个一个文件的分配情况,fat是映射到每个簇的条目列表,应该记录

  • 链中下一个簇的地址
  • 一个特殊的簇链结束符EOC,End Of Cluster-chain,或称End Of Chain)符号指示链的结束
  • 一个特殊的符号标示坏簇
  • 一个特殊的符号标示保留簇
  • 0来表示空闲簇

root directory

是一个表示目录的特殊类型文件(现今通常称为文件夹)。它里面保存的每个文件或目录使用表中的32字节条目表示。每个条目记录名字、扩展名、属性(文件、目录、隐藏、只读、系统和卷)、创建的日期和时间、文件/目录数据第一个簇的地址,最后是文件/目录的大小。

data region

由一些cluster组成

fat文件系统的调用

小项目

需求:

在240*320的lcd上一张名为bibi的图片。图片存储在sd卡上。

实际效果

核心代码

/*-----------------------------------------------------------------------*/
/* Low level disk I/O module skeleton for FatFs     (C)ChaN, 2007        */
/*-----------------------------------------------------------------------*/
/* This is a stub disk I/O module that acts as front end of the existing */
/* disk I/O modules and attach it to FatFs module with common interface. */
/*-----------------------------------------------------------------------*/

#include "diskio.h"
#include "bsp_sdio_sdcard.h"

/*-----------------------------------------------------------------------*/
/* Correspondence between physical drive number and physical drive.      */

#define ATA		0
#define MMC		1
#define USB		2
#define SD_BLOCKSIZE     512 



/*-----------------------------------------------------------------------*/
/* Inidialize a Drive                                                    */

DSTATUS disk_initialize (
	BYTE drv				/* Physical drive nmuber (0..) */
)
{
	SD_Error SD_Staus ;
	DSTATUS DEVICE_Staus = STA_NOINIT;
	
	
	if ( 0 != drv)
	{
		return DEVICE_Staus;
	}
	SD_Staus = SD_Init();
	
	if ( SD_OK == SD_Staus)
	{
		 DEVICE_Staus &= ~STA_NOINIT;
	}
	return DEVICE_Staus;
	
}



/*-----------------------------------------------------------------------*/
/* Return Disk Status                                                    */

DSTATUS disk_status (
	BYTE drv		/* Physical drive nmuber (0..) */
)
{
	DSTATUS DEVICE_Staus = STA_NOINIT;

	if ( 0 != drv)
	{
		return DEVICE_Staus;
	}
	else
	{
		DEVICE_Staus &= ~STA_NOINIT;
	}
	return DEVICE_Staus;
}



/*-----------------------------------------------------------------------*/
/* Read Sector(s)                                                        */

DRESULT disk_read (
	BYTE drv,		/* Physical drive nmuber (0..) */
	BYTE *buff,		/* Data buffer to store read data */
	DWORD sector,	/* Sector address (LBA) */
	BYTE count		/* Number of sectors to read (1..255) */
)
{
	SD_Error SD_Staus = 0;
	if (1 == count)
	{
		SD_Staus = SD_ReadBlock(buff, sector*SD_BLOCKSIZE, SD_BLOCKSIZE);//一个扇区为512字节,乘512字节为实际地址
	}
	else
	{
		SD_Staus = SD_ReadMultiBlocks(buff,sector*SD_BLOCKSIZE,SD_BLOCKSIZE, count);
	}
	
	SD_WaitReadOperation();
	while(SD_GetStatus() == SD_TRANSFER_BUSY);
	
	if (SD_OK == SD_Staus)
	{
		return RES_OK;
	}	
	else
	{
		return RES_ERROR;
	}
	
}



/*-----------------------------------------------------------------------*/
/* Write Sector(s)                                                       */

#if _READONLY == 0
DRESULT disk_write (
	BYTE drv,			/* Physical drive nmuber (0..) */
	const BYTE *buff,	/* Data to be written */
	DWORD sector,		/* Sector address (LBA) */
	BYTE count			/* Number of sectors to write (1..255) */
)
{
	 SD_Error SD_Staus = 0;
	
	if (count == 1)
	{
		SD_Staus = SD_WriteBlock((uint8_t*)buff,sector*SD_BLOCKSIZE, SD_BLOCKSIZE);
	}
	else
	{
		SD_Staus = SD_WriteMultiBlocks((uint8_t*)buff,sector*SD_BLOCKSIZE, SD_BLOCKSIZE,count);
	}
	
	
	SD_WaitReadOperation();
	while(SD_GetStatus() == SD_TRANSFER_BUSY);
	
	if (SD_OK == SD_Staus)
	{
		return RES_OK;
	}	
	else
	{
		return RES_ERROR;
	}
	
}
#endif /* _READONLY */



/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions                                               */

DRESULT disk_ioctl (
	BYTE drv,		/* Physical drive nmuber (0..) */
	BYTE ctrl,		/* Control code */
	void *buff		/* Buffer to send/receive control data */
)
{
	DRESULT res;
	int result;

	
	return RES_PARERR;
}


__weak DWORD get_fattime(void) {
	/* 返回当前时间戳 */
	return	  ((DWORD)(2015 - 1980) << 25)	/* Year 2015 */
			| ((DWORD)1 << 21)				/* Month 1 */
			| ((DWORD)1 << 16)				/* Mday 1 */
			| ((DWORD)0 << 11)				/* Hour 0 */
			| ((DWORD)0 << 5)				  /* Min 0 */
			| ((DWORD)0 >> 1);				/* Sec 0 */
}
#include "bmp.h"

uint8_t BMP_BGRA[4*LCD_Width];
uint16_t BMP_RGB565[LCD_Width];
uint8_t  BMP_Head[54];

uint16_t LCD_Display_BMP(char* PIC_Name)
{
	DWORD Offset = 0;
	BMP BMPS;
	int ROW_Offset;
	int COLUMN_Offset;
	int OFFSET_Flag;
	UINT NUMBER_Read;
	WORD DATA_Offset;
	FIL BMP_File;
	FRESULT FILE_Staus;
	int LCD_x;
	int LCD_y;
	int i;
	int j;
	
	
	FILE_Staus = f_open(&BMP_File,PIC_Name,FA_READ|FA_OPEN_EXISTING);
	if (FILE_Staus != FR_OK)//不存在该文件或者读取失败
	{
		return BMP_Errors;
	}
	
	
	f_read(&BMP_File,&BMP_Head,54,&NUMBER_Read);
	BMPS.DATA_Offset = (BMP_Head[13]<<24)+(BMP_Head[12]<<16)+(BMP_Head[11]<<8)+(BMP_Head[10]<<0);
	BMPS.BMP_Depth = (BMP_Head[29] << 8) + (BMP_Head[28] << 0);
	BMPS.BMP_Width = (BMP_Head[21]<<24)+(BMP_Head[20]<<16)+(BMP_Head[19]<<8)+(BMP_Head[18]<<0);
	BMPS.BMP_Height = (BMP_Head[25]<<24)+(BMP_Head[24]<<16)+(BMP_Head[23]<<8)+(BMP_Head[22]<<0);
	
	//判断是否满足该函数的读取格式
	//数据存储方式必须是从左上角到右上角,必须是bmo文件
	if ( BMPS.BMP_Height < 0)//数据存储方向不是从左上角到右上角,32位深度,无压缩,无颜色表
	{
		return BMP_Errors;
	}
	if ( BMPS.BMP_Depth != 32)//没有A
	{
		return BMP_Errors;
	}
	if ((BMP_Head[0] != 0x4) || (BMP_Head[1] != 0x2) || (BMP_Head[2] != 0x4) || (BMP_Head[3] != 0xd))//不是bmp文件
	{
		BMPS.IS_BMP = 1;
	}
	if ((BMP_Head[33] + BMP_Head[32] + BMP_Head[31] + BMP_Head[30]) != 0)//bmp文件有压缩
	{
		BMPS.IS_Compression = 1;
	}	
	if ((BMPS.DATA_Offset) != 54)
	{
		BMPS.IS_CorlorTable = 1;
	}
	if ((BMPS.IS_CorlorTable*BMPS.IS_Compression*BMPS.IS_BMP) >= 1)
	{
		return BMP_Errors;
	}
	Offset = Offset + 54;
	f_lseek(&BMP_File,Offset);
	
	
	
  //图像缩放处理
	ROW_Offset = (int)(BMPS.BMP_Width/LCD_Width);//某一行隔几个像素点作为像素点
	COLUMN_Offset = (int)(BMPS.BMP_Height/LCD_Height);//隔几列
	if (COLUMN_Offset == 0)
	{
		COLUMN_Offset = 1;
	}
	if (ROW_Offset == 0)
	{
		ROW_Offset = 1;
	}
	//lcd扫描方向
	ILI9341_GramScan(2);
	for(i = 0; i < LCD_Height;i = i + 1)
	{
		LCD_y = i;
		
		for(j = 0; j < LCD_Width; j = j + 1)
		{
			f_read(&BMP_File,&BMP_BGRA[4*j],1,&NUMBER_Read);
			Offset = Offset + 1;
			f_lseek(&BMP_File,Offset);
			f_read(&BMP_File,&BMP_BGRA[4*j+1],1,&NUMBER_Read);
			Offset = Offset + 1;
			f_lseek(&BMP_File,Offset);
			f_read(&BMP_File,&BMP_BGRA[4*j+2],1,&NUMBER_Read);		
			
			Offset = Offset + (ROW_Offset-1)*4 + 2;
			BGRA_to_RGB565(&BMP_BGRA[4*j], &BMP_BGRA[4*j+1], &BMP_BGRA[4*j+2], &BMP_RGB565[j]);
		}
		
		Offset = Offset + BMPS.BMP_Width*4 - 4*(ROW_Offset)*LCD_Width+ (COLUMN_Offset-1)*LCD_Width*4;
		f_lseek(&BMP_File,Offset);//跳过一些行,这些行不取像素点
		
		for(j = 0; j < LCD_Width; j = j + 1)
		{
			LCD_x = j;
			LCD_SetTextColor(BMP_RGB565[j]);
			ILI9341_SetPointPixel(LCD_x,LCD_y);
		}
		
	}
	f_close(&BMP_File);
	
}




void BGRA_to_RGB565(uint8_t* B,uint8_t*G, uint8_t* R, uint16_t* RGB565)
{
	
	*RGB565 = (((uint16_t)(*R))>>3)<<11 | (((uint16_t)(*B))>>3) | (((uint16_t)(*G))>>2 ) << 5;
	
}
#ifndef __BMP_H
#define __BMP_H

#include "stm32f10x.h"
#include "ff.h"
#include "bsp_ili9341_lcd.h"

#define LCD_Width 240
#define LCD_Height 320
#define BMP_Errors 0
#define BMP_Success (!0)


typedef struct _BMP
{
	uint16_t IS_BMP;
	uint16_t BMP_Depth;
	uint32_t IS_Compression;
	uint32_t IS_CorlorTable;
	uint32_t DATA_Offset;
	uint32_t BMP_Width;
	int32_t  BMP_Height;
}BMP;


uint16_t LCD_Display_BMP(char* PIC_Name);
void BGRA_to_RGB565(uint8_t* B,uint8_t*G, uint8_t* R, uint16_t* RGB565);

#endif

总结与评价

fat文件系统调用的逻辑可以参考野火ppt,ff.c文件调用diskio.c文件,diskio文件调用bsp_scdcard.c文件。

该工程不能读取像素很大的图片,如1600*800,否则会造成失真。本项目采用的是十分简单的图片缩放算法,隔几个点读一个点。

图片缩放算法会影响lcd上显示图片的质量

参考资料

SDIO协议

SDIO Protocol | Prodigy Technovations

Wiki - Secure digital input/output interface (SDIO)

野火ppt

fat系统

What is File Allocation Table (FAT)?

https://en.wikipedia.org/wiki/Design_of_the_FAT_file_system#Special_entries

https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-2000-server/cc976796(v=technet.10)

  • 25
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值