• Arduino 官方的SD卡库 使用起来体验很差主要表现为: 每次使用重新进行初始化 不能保留多个文件 代码冗余 这里对此进行了优化首先是 sdsun.h(内容不多就全写在头文件里了)int sd_t=1; File root; File myFile; ...

    Arduino 官方的SD卡库 使用起来体验很差

    主要表现为:

    1. 每次使用重新进行初始化 不能保留多个文件
    2. 代码冗余

    这里对此进行了优化

    首先是 sdsun.h(内容不多就全写在头文件里了)

    int sd_t=1;
    File root;
    File myFile;
    String ss;
    int printDirectory(File dir, int numTabs);
    void setSD();
    void write_SD(String ss,String s);
    void setSD(){
        Serial.print("Initializing SD card...");
        if (!SD.begin(4)) {
            Serial.println("initialization failed!");
           return;
        }
        Serial.println("initialization done.");
        root = SD.open("/DATA/");
        int r=printDirectory(root, 0);
        String sd_x="/DATA/0";
        sd_x.concat(r);
        ss=sd_x+".TXT";
        Serial.println(ss);
        myFile = SD.open(ss, FILE_WRITE);
        myFile.close();
        Serial.println("done!"); 
    }
    
    void writeSD(String s){
        myFile = SD.open(ss, FILE_WRITE);
        myFile.println(s);//将输出参数写到括号里即可
        myFile.close();
      }
    
    
    
    int printDirectory(File dir, int numTabs) {
      while (true) {
        File entry =  dir.openNextFile();
        if (! entry) {
          break;
        }
        for (uint8_t i = 0; i < numTabs; i++) {
          Serial.print('\t');
        }
        Serial.print(entry.name());
        if (entry.isDirectory()) {
          Serial.println("/");
          printDirectory(entry, numTabs + 1);
        } else {
          sd_t=sd_t+1;
          Serial.print("\t\t");
          Serial.println(entry.size(), DEC);
        }
        entry.close();
      }
      return sd_t;
    }

    测试程序中 调用sdsun.h API即可,变成了这个样子:

    #include <SPI.h>
    #include <SD.h>
    #include "sdsun.h"
    void setup() {
        Serial.begin(9600);
        setSD()  ;
    
    }
    void loop() {
        writeSD("hhhhh");
    }
    

    可以说是心旷神怡,唯一需要注意的是SD卡 初始需要新建DATA文件夹 便可以一劳永逸 每次产生的新文件 以新数字命名

    展开全文
  • SD

    2017-11-09 20:26:22
    2.SD卡的时序访问有两种方式,SPI协议和SD卡协议,SPI协议是老协议,早于SD卡出现,所以SD卡使用这个协议只是为了兼容以前的软件,SPI协议特点是低速,时序操作简单,多用于老的单片机SD卡另一个协议是SD协议,SD...

    SD卡基础知识

    1. SD卡来源于Flash,是对Flash进行了统一的封装。所以SD卡还是块设备,还是使用时序通信。
    2.SD卡的时序访问有两种方式,SPI协议和SD卡协议,SPI协议是老协议,早于SD卡出现,所以SD卡使用这个协议只是为了兼容以前的软件,SPI协议特点是低速,时序操作简单,多用于老的单片机。SD卡另一个协议是SD协议,SD协议的特点是高速,时序操作复杂,并且主频不能太慢。
    3.SD卡的时序通信复杂,但好在已经有人写好了相应的库。
    4.谈谈块设备
    块设备最早源于磁盘
    由于硬件原因,磁盘的最小读写单位是扇区,那时规定的扇区大小是512字节,后来硬件技术升级,可以制造更大的扇区,但是由于以前的软件都是用512为一个扇区,所以为了兼容以前的软件,现在默认扇区大小是512字节。
    后来的其他块设备都是用一个块512字节。
    5.使用SD卡启动的难点
    由于SD卡是时序操作,所以SOC不能直接读写SD卡,而只有norflash是总线操作的存储设备,所以以前的启动其实是用一个大的norflash装下整个程序,或者用个中等大小的norflash加个nandflash,后来三星出了个steppingstone技术,就只用一个小的norflash加个小的SRAM就行了。使用norflash装BL0,BL0会判断启动方式并且初始化相关控制器(如SD卡控制器),如果是SD卡启动就将SD卡中的16kb程序BL1拷贝到SRAM中,再用BL1将剩余的BL2拷贝到SRAM中,BL2再去初始化DDR并拷贝OS。
    steppingstone的关键是用了个64kb的iROM,和96kb的SRAM,并且iROM中的BL0只能拷贝16kb大小的程序进SRAM
    所以
    当bin文件小于16kb时,拷贝了就完成
    当bin文件大于16kb时,拷贝了第一部分还需要再拷贝剩余部分,拷贝剩下的部分需要都SD卡,这部分程序在BL0中已经有了,所以只需要调用即可。


    编程测试
    查询210手册可以得到写好了得时序通信库函数
    对于库函数的使用有两种方法,宏定义,函数指针
    宏定义的坏处
    1.代码不可复用
    2.编译器不能做参数的静态类型检查
    所以使用函数指针才是王道
    typedef ((bool(*CopySDMMCtoMem)(int, unsigned int, unsigned short, unsigned int*, bool)));
    CopySDMMCtoMem p1 = (CopySDMMCtoMem)0xD0037F98;
    (*p1)();//注意 优先级 * < (); 当然也可以使用 p1()调用


    编程目的:
    使用SD卡运行16kb以上的程序
    分析:
    由于irom中BL0会拷贝16kb的BL1,所以我们需要做的只是用BL1初始化DDR,并拷贝将剩下的程序拷贝到DDR,然后跳转到BL2执行。
    细节:
    1.BL1应该拷贝到SD卡的什么位置?
    因为是BL0拷贝BL1,所以BL1的位置是定死了的,查阅手册晓得BL0是跳过block0,从block1开始拷贝16KB,由于512B是一个块,所以一共拷贝32个块,那么BL1就该放到block1
    2.BL2应该在SD卡的什么位置?
    BL2是BL1拷贝的,BL1是自己写的,所以BL2的位置随意。
    3.BL1完成什么
    BL1管看门狗,设置栈,开icache,初始化clock,初始化DDR,拷贝BL2到DDR
    4.BL2需要注意
    链接地址的设置




    最后谈谈如何将BL1,BL2拷贝到SD卡上
    这里使用的是linux的dd命令,BL1,BL2作为两个独立的程序被拷贝
    #!/bin/sh   
    sudo dd iflag=dsync oflag=dsync if=./BL1/BL1.bin of=/dev/sdb seek=1
    sudo dd iflag=dsync oflag=dsync if=./BL2/BL2.bin of=/dev/sdb seek=45


    #!/bin/sh中 
    #!是特殊符号,相当于C中的include,用于指定shell的路径,
    seek = 1,就是从block1开始拷贝
    seek = 45,就是从block45开始拷贝




    最后再说下分文件的 makefile
    all:
    make -C ./BL1
    make -C ./BL2


    clean:
    make clean -C ./BL1
    make clean -C ./BL2

    展开全文
  • 为了能够将数据上传到PC机,我计划将该设备的存储模块做成一个类似于U盘的东西------只要插PC机就可以识别,并能够把里面数据文件拷贝出来。 所以需要外加一个存储模块。 存储:一个256MB的 nand flash...

    最近有一个项目是 一个嵌入式系统设备。

    功能:信号采集,数据存储,数据传输(USB+蓝牙)。

    主控MCU:一个M0核的单片机;

    由于需要存储的数据有点大(大概130MB)。为了能够将数据上传到PC机,我计划将该设备的存储模块做成一个类似于U盘的东西------只要插上PC机就可以识别,并能够把里面数据文件拷贝出来。

    所以需要外加一个存储模块。

    存储:一个256MB的 nand flash 芯片;

    但是由于该MCU没有USB接口,为了缩短数据上传的时间,计划加一个 nand flash 控制器(通常控制器都带USB接口),专门用来读取nand flash 中的数据,写flash 不要求高速。

    这样的话,就等于是通过 单片机和 “nand 控制器” 同时控制nand flash芯片了。
    单片机负责写入,花费15个I/O口与nand flash 的各管脚相连。”nand flash 控制器“负责 PC机与nand flash 之间的数据传输。

    那么问题来了:

    1,如何实现,通过单片机写,通过控制器读的切换?互相之间不能影响。   

    2,单片机要对nand flash 进行读写,并且创建文件,就需要有一套文件系统。但是专用与nand flash 的文件系统YAFFS好像只用于LINUX,而 windows 不支持,不知道IOS支不支持。

    3,通过单片机来读写同样得涉及到 ECC校验,坏块管理,垃圾搜集,负载均衡,这个算法是否很复杂,应该添加在哪一层。用FAT文件系统的话,该如何解决这些问题。

    解决方案:

    针对嵌入式领域小容量上非常多变的应用场景,把小容量的SLC NAND跟SD的controller包在一起,然后定制的FW。

    SD NAND是怎样的芯片?不就是SD卡吗?

    不一样,T卡用的wafer很多是ink die,T卡是一个模组,很多坏掉就换新的。我们这个是贴在板子上,都是用good die做的,而且我们封装形式比较小,焊在板子上稳定性比较高,T卡是插上去的由于震动可以能引起接触不良,会脱落。                           

    SD NAND是一个嵌入式存储解决方案设计的LGA8(WSON)小封装,尺寸只有8mm*6mm, SD卡的操作与SD卡类似,是行业标准。
    SD NAND由高可靠性的SLC Nand闪存和高性能控制器组成, NAND区域(VCC)需要3.3V的供电电压,能够支持class10的访问速度。
    SD NAND完全兼容SD2.0接口,它允许大多数CPU使用,具有高性价比、高质量、低功耗的特点。
    可穿戴设备、智能硬件:
    手环、手表、运动MP3耳机、智能音箱、智能门铃、智能监控、语音模块等
    4.优点:缩小PCB面积  质量更有保障 兼容性高   耐高温可以过回流焊

    有兴趣的朋友和需要规格书的,可以随时联系我们  T:13691982107  QQ 2852826868  官网:www.longsto.com

    展开全文
  • 本测试采用SPI模式读写SD卡,相关引脚配置如下: 片选:SD_CS->PB13,对应SD卡的1脚,低电平有效 时钟:SPI1_SCK->PA5,对应SD卡的5脚  主入从出:MISO->PA6,对应SD卡的7脚  主出从入:MOSI->PA7,对应SD卡的2脚 2...

    1.硬件引脚介绍:

    本测试采用SPI模式读写SD卡,相关引脚配置如下:

    片选:SD_CS->PB13,对应SD卡的1脚,低电平有效

    时钟:SPI1_SCK->PA5,对应SD卡的5脚 

    主入从出:MISO->PA6,对应SD卡的7脚 

    主出从入:MOSI->PA7,对应SD卡的2脚


    2.初始化步骤:

    while(SD_Initialize())

    {

    //提示检查SD卡

    }

    //初始化SD卡
    u8 SD_Initialize(void)
    {
      u8 r1;      // 存放SD卡的返回值
      u16 retry;  // 用来进行超时计数
      u8 buf[4];  
    	u16 i;
    	SD_SPI_Init();		//初始化IO
     	SD_SPI_SpeedLow();	//设置到低速模式 
     	for(i=0;i<10;i++)SD_SPI_ReadWriteByte(0XFF);//发送最少74个脉冲
    	retry=20;
    	do
    	{
    		r1=SD_SendCmd(CMD0,0,0x95);//进入IDLE状态
    	}while((r1!=0X01) && retry--);
     	SD_Type=0;//默认无卡
    	if(r1==0X01)
    	{
    		if(SD_SendCmd(CMD8,0x1AA,0x87)==1)//SD V2.0
    		{
    			for(i=0;i<4;i++)buf[i]=SD_SPI_ReadWriteByte(0XFF);	//Get trailing return value of R7 resp
    			if(buf[2]==0X01&&buf[3]==0XAA)//卡是否支持2.7~3.6V
    			{
    				retry=0XFFFE;
    				do
    				{
    					SD_SendCmd(CMD55,0,0X01);	//发送CMD55
    					r1=SD_SendCmd(CMD41,0x40000000,0X01);//发送CMD41
    				}while(r1&&retry--);
    				if(retry&&SD_SendCmd(CMD58,0,0X01)==0)//鉴别SD2.0卡版本开始
    				{
    					for(i=0;i<4;i++)buf[i]=SD_SPI_ReadWriteByte(0XFF);//得到OCR值
    					if(buf[0]&0x40)SD_Type=SD_TYPE_V2HC;    //检查CCS
    					else SD_Type=SD_TYPE_V2;   
    				}
    			}
    		}else//SD V1.x/ MMC	V3
    		{
    			SD_SendCmd(CMD55,0,0X01);		//发送CMD55
    			r1=SD_SendCmd(CMD41,0,0X01);	//发送CMD41
    			if(r1<=1)
    			{		
    				SD_Type=SD_TYPE_V1;
    				retry=0XFFFE;
    				do //等待退出IDLE模式
    				{
    					SD_SendCmd(CMD55,0,0X01);	//发送CMD55
    					r1=SD_SendCmd(CMD41,0,0X01);//发送CMD41
    				}while(r1&&retry--);
    			}else//MMC卡不支持CMD55+CMD41识别
    			{
    				SD_Type=SD_TYPE_MMC;//MMC V3
    				retry=0XFFFE;
    				do //等待退出IDLE模式
    				{											    
    					r1=SD_SendCmd(CMD1,0,0X01);//发送CMD1
    				}while(r1&&retry--);  
    			}
    			if(retry==0||SD_SendCmd(CMD16,512,0X01)!=0)SD_Type=SD_TYPE_ERR;//错误的卡
    		}
    	}
    	SD_DisSelect();//取消片选
    	SD_SPI_SpeedHigh();//高速
    	if(SD_Type)return 0;
    	else if(r1)return r1; 	   
    	return 0xaa;//其他错误
    }
    如果返回值为正常类型,则跳出初始化循环,接下来介绍该函数中的SD_SPI_Init()函数及其内部调用的SPI_Init()函数
    SD_SPI_Init()配置片选引脚PB13并拉低电平设置片选有效,然后调用SPI_Init()函数,代码略

    SPI_Init()函数初始化单片机的SPI1外设,具体配置为PA5.6.7三个引脚的设置

    //以下是SPI模块的初始化代码,配置成主机模式,访问SD Card							  
    
    SPI_InitTypeDef  SPI_InitStructure;
    
    void SPI1_Init(void)
    {
    	GPIO_InitTypeDef GPIO_InitStructure;
      
    	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOA|RCC_APB2Periph_SPI1, ENABLE );	
     
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA, &GPIO_InitStructure);
    
     	GPIO_SetBits(GPIOA,GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);
    
    	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
    	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;		//设置SPI工作模式:设置为主SPI
    	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;		//设置SPI的数据大小:SPI发送接收8位帧结构
    	SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;		//选择了串行时钟的稳态:时钟悬空高
    	SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;	//数据捕获于第二个时钟沿
    	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;		//NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
    	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;		//定义波特率预分频的值:波特率预分频值为256
    	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;	//指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
    	SPI_InitStructure.SPI_CRCPolynomial = 7;	//CRC值计算的多项式
    	SPI_Init(SPI1, &SPI_InitStructure);  //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
     
    	SPI_Cmd(SPI1, ENABLE); //使能SPI外设
    	
    	SPI1_ReadWriteByte(0xff);//启动传输		 
    }   

    3.主函数部分:

    int main(void)
     { 
     	u32 total,free;
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2 
    	delay_init();	    	 //延时函数初始
    	LED_Init();
    	uart_init(19200);	 	//串口初始化为19200
     	exfuns_init();		//为fatfs相关变量申请内存				 				
     	mem_init();			//初始化内存池	
    	printf ("程序初始化结束:->\r\n");	
    	if(SD_Initialize())					//检测SD卡
    	{
    		printf ("未检测到SD卡:->\r\n");
    		while(SD_Initialize())
    		{
    			printf("别看着了,滚去找原因,根本没插卡:\r\n");
    			LED1=!LED1;
    			delay_ms(500);
    		}
    		LED1=1;
    	}								   	
    	printf("SD卡正常加载:\r\n");
    	printf("申请内存结果:%d\r\n",(unsigned int)exfuns_init());//为fatfs相关变量申请内存,返回0成功				 
      	f_mount(fs[0],"0:",1); 					//挂载SD卡 
    	exf_getfree((u8*)"0",&total,&free);//得到SD卡的总容量和剩余容量
    	printf("SD卡的容量是:%d\r\n",free);
    	printf("开始扫描串口数据**************************\r\n");
    	while(1)	//测试使用串口输入函数名是成功的
    	{
    	if(USART_RX_STA&0x8000)//不断检测串口接收完成?这里可以去串口中断服务函数中做一些if判断来限制串口的数据格式,数据大小
    	{			
    		WriteData();	//串口接收完成开始写入SD卡,该函数是自己封装的,详细请看下面介绍的SD卡写入步骤
    		USART_RX_STA=0;		//清零标志位
    	}
    	LED0=!LED0;//程序运行指示灯
    	delay_ms(500);
    	}
    }

    4.向SD卡中写入的步骤:(采用库函数)

    由于里面的函数都是SD驱动函数封装起来的,所以要了解底层写入过程,还要参考SD卡的通讯时序等等,不在此赘述,以后会另做记录

    void WriteData(void)			//一旦在串口中断标志置位,则调用该函数,开始启动创建文件的步骤:
    {
    	//*********写入SD卡****************************
    	mf_mount(0,1);	//注册工作区域
    	mf_open(fileName,4);	//创建文件
    	mf_close();
    	mf_open(fileName,2);										//以可写方式打开文件
    	mf_lseek(mf_size());										//将指针移动到文件末尾,以便追加数据
    	mf_write(USART_RX_BUF,142);											//追加写入串口发来的数据到SD卡
    	mf_close();															//关闭文件
    	printf("WriteData()执行完毕,数据写入成功\r\n");
    }



    
    
    展开全文
  • S5PV210-SD卡启动

    2018-01-16 16:20:36
    SD卡是带有控制器和封装的NANDFLASH,各种型号SD卡的接口都是通用的。 SD卡支持SD协议和SPI协议,支持SPI协议可以方便单片机的使用。虽然支持两种协议,但是用相同的硬件接口(两根地线,一根电源线,六根信号线)。...

    1. SD卡介绍

    • SD卡是带有控制器和封装的NANDFLASH,各种型号SD卡的接口都是通用的。
    • SD卡支持SD协议和SPI协议,支持SPI协议可以方便单片机的使用。虽然支持两种协议,但是用相同的硬件接口(两根地线,一根电源线,六根信号线)。
    • SD卡是一种ROM,不能按地址读写,只能按块读写。(块/扇区:Block, 一个扇区一般包含512B的内容,使用块来存储的设备称作块设备)
    • SD卡、TF卡、MMC卡之间的区别。MMC卡是支持MMC协议的卡,MMC协议出现地比SD协议早,现在基本被淘汰,但SD协议兼容MMC协议。TF卡与SD卡大同小异,体积小一些。

    2. SD卡启动流程

    以bootloader的启动为例说明。


    S5PV210启动流程

    1. 首先S5PV210内置的iROM上电直接运行(能直接上电运行不需初始化的是Norflash),执行一系列初始化操作,最重要的是将会根据OM引脚判别出启动方式,然后初始化外部的存储器(图中的“Booting Device”),并将其中bootloader的前16KB(即BL1)复制到内部的SRAM中执行。这一步,就是三星的启动方式“Steppingstone技术”
    2. 然后BL1就为所欲为,将bootlaoder全部(即BL2)复制到SDRAM中进行执行。完成启动过程。(与图中所画有不同之处。)

    在上面的讲述中,有几个地方值得注意:

    1. BL2是bootloader的全部内容,而不是除了BL1之外的其他内容,这将在下面讲述SD卡的分散加载与整体加载时说道。
    2. 上面操作的第二步可以看到跟图上的不同,图上是把剩下的bootloader加载到SRAM中的,而我说的则是把bootloader整体加载到内存SDRAM中,这是因为现在bootloader实际上已经远大于96K了,SRAM中放不下!
    3. 上述操作的第二步是将程序从外部的“Booting Device”复制到SDRAM中,这一过程使用的是IROM中提供的 Device Copy Function来完成的。

    3. SD卡启动方式-分散加载

    这里我要讨论的情况是需要大于96K的情况(一定要分为两部分的情况)。
    分散加载的意思就是把一个程序分成完全独立的两个部分,注意是完全独立,两个文件夹,各自有各自的makefile,如下图所示。


    分散加载示意图

    为了编译链接方便,在顶层文件夹有一个总的makefile:

    all:
        make -C ./BL1
        make -C ./BL2
    clean:
        make clean -C ./BL1
        make clean -C ./BL2
    • BL1与BL2烧写到SD卡的不同位置。一般BL1(16K)是1-32扇区(16K = 32*512B),BL2则选择留一点空隙,从49等扇区开始烧写。注意,BL1不是从扇区0开始烧写的,因为三星有规定,如下所示。
      SD卡内存分配
    • 程序在实际执行时,执行BL1,将BL2复制到SDRAM中,然后就跳转到SDRAM中去执行,这个跳转指令很有意思。由于BL1和BL2是两个程序,不能再用诸如ldr pc, = main这种跳转指令来跳转,而是需要直接使用BL2在SDRAM中的地址,以函数指针的形式来使用。

    4. SD启动方式-整体加载

    同样这里讨论程序大于96K时的情况。
    整体加载是相对于上面的分散加载而言的,在这里不再将程序分为两个部分,而是作为一个整体。
    整体加载示意图
    由于在这里BL1和BL2是一个程序的,所以在执行完BL1之后可以使用ldr pc, = main这样的代码跳转到BL2中执行。
    使用整体加载方式的一个实例就是:uboot的加载。程序代码仍然包括BL1和BL2两部分,但是组织形式上不分为2部分而是作为一个整体来组织。它的实现方式是:iROM启动然后从SD卡的扇区1开始读取16KB的BL1然后去执行BL1,BL1负责初始化DDR,然后从SD卡中读取整个程序(BL1+BL2)到DDR中,然后从DDR中执行(利用ldr pc, =main这种方式以远跳转从SRAM中运行的BL1跳转到DDR中运行的BL2)。
    以上3、4部分就是SD卡启动两种方式,目前使用的基本为方式4,因为更简洁方便

    NOTE: 当SD卡接在Linux系统中后,其地址为 /dev/sdb

    5. Device Copy Function

    设备复制函数可以在三星的iROM的Application Note中找到,以SD卡的为例。
    SD卡设备复制函数

    /**
    * This Function copy MMC(MoviNAND/iNand) Card Data to memory.
    * Always use EPLL source clock.
    * This function works at 20Mhz.
    * @z : 这个参数是SD卡的通道号,在我的开发板中通道0连接的是内部的iNAND,通道2是我要用的。
    * @a : param u32 StartBlkAddress : Source card(MoviNAND/iNand MMC)) Address.(It must block address.) 起始的block号。
    * @b : param u16 blockSize : Number of blocks to copy. 共复制的block数目。
    * @c : param u32* memoryPtr : Buffer to copy from. 复制到SDRAM中的地址。
    * @e : param bool with_init : determined card initialization. 一般置0,不做处理。
    * @return bool(u8) - Success or failure.
    */
    #define CopySDMMCtoMem(z,a,b,c,e)(((bool(*)(int, unsigned int, unsigned short, unsigned int*, bool))(*((unsigned int *)0xD0037F98)))(z,a,b,c,e))

    上面给出了SD卡复制函数的宏定义,以及相关参数的含义。
    分析一下上面的宏定义右边的内容,0xD0037F98是函数指针的指针,这基于两个事实,一个是0xD0037F98是iRAM上的地址,而块设备复制函数本体一定是写在iROM中的,所以(*((unsigned int *)0xD0037F98) 代表的就是设备复制函数的指针,(bool(*)(int, unsigned int, unsigned short, unsigned int*, bool))是函数指针类型的强制数据类型转换。

    展开全文
  • 单片机驱动DM9000网卡芯片(详细调试过程)【】 2009-03-04 11:13 和其它网卡芯片不同,DM9000系列网卡芯片在嵌入式开发板很常见,尤其是有关ARM-Linux的开发板的网络连接部分几乎都是采用该芯片完成的...
  • LPC1768FBD100原理图符号PCB封装
  • SD卡启动详解

    2016-10-16 20:33:29
    把ROM(read only memory,只读存储器,类似于Flash SD卡之类的,用来存储东西,掉电不丢失,不能随机地址访问,只能以块为单位来访问)叫外存。 1.软盘、硬盘、光盘、CD、磁带 1、存储原理大部分为磁存
  • 把ROM(read only memory,只读存储器,类似于Flash SD卡之类的,用来存储东西,掉电不丢失,不能随机地址访问,只能以块为单位来访问)叫外存。 1.软盘、硬盘、光盘、CD、磁带 1、存储原理大部分为磁存
  • 单片机驱动DM9000网卡芯片(详细调试过程)【和下】   和其它网卡芯片不同,DM9000系列网卡芯片在嵌入式开发板很常见,尤其是有关ARM-Linux的开发板的网络连接部分几乎都是采用该芯片完成的。当然,其它...
  • NandFlash、NorFlash缺点:时序复杂,无坏块处理机制,接口不统一NandFlash:MLC(可靠性差,容量大)、SLC(可靠性高、容量小)扩展卡式Flash:SD卡、MMC卡、MicroSD(TF卡)内部为NnadFlash存储颗粒,外部封装了...
  • 修改RTC电池座封装  在绘制完RTC电池座封装并导入到PCB设计界面中后发现正负极反了。最简单的修改方法是在PCB设计界面中找到RTC电池座,右键并选中在封装编辑器中打开。修改1,2两脚的焊盘编号,然后更新当前电路...
  • 深入理解SD卡基础原理以及内部结构的总结
  • 2006-04-30 18:48:25 第1372篇:如何让单片机轻松读写U盘发布时间:2006年3月27日 点击次数:436 详细内容:如何让单片机轻松读写U盘 如何让单片机轻松读写U盘 单片机系统大容量数据存储已经是大家非常迫切的...
  • 这周调试了一个spi总线的sd卡驱动,学习了一下sd卡的硬件命令时序以及内核中sd卡驱动的框架。 这片文章主要总结一下我从网上搜集的sd卡资料,以备后用。 SD卡支持两种总线方式:SD方式与SPI方式。其中SD方式...
  • 顺便发个广告从SD卡更新固件" title="STM32的BootLoader 从SD卡更新固件" style="margin:0px; padding:0px; border:0px; list-style:none; line-height:1.5"> 工程源代码等资料,欢迎大家索取:
  • SD卡、MMC卡、MicroSD、TF卡:这些卡其实内部就是Flash存储颗粒,比直接的Nand芯片多了统一的外部封装和接口。卡都有统一的标准,譬如SD卡都是遵照SD规范来发布的。这些规范规定了SD卡的读写速度、读写接口时序、...
  • 1、 简介:    SD卡(Secure Digital Memory Card)...
  • 这几天几种地看了一下SD卡的相关内容,总结了一些体会,感觉也没有那么恐怖了。我决定从分层上来讨论SD的驱动和应用,因为这样可以构建一个清晰的逻辑,且不知哪位计算机大师曾说过:一切计算机问题都可以用分层的...
1 2 3 4 5 ... 20
收藏数 1,376
精华内容 550