历史上的今天
返回首页

历史上的今天

今天是:2024年12月26日(星期四)

正在发生

2018年12月26日 | STM32 SPI方式读写SD卡

2018-12-26 来源:eefocus

前段时间在51上模拟SPI实现了对SD卡的读取,效果还算不错,最近将其移植到STM32上,不过使用硬件SPI和使用软件SPI还是有差别的。


代码如下:


void User_SPIInit(void)

{

 GPIO_InitTypeDef GPIO_InitStructure;

 

 SPI_InitTypeDef SPI_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_InitStructure.GPIO_Pin=GPIO_Pin_3;

 

 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;

 

 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

 

 GPIO_Init(GPIOA,&GPIO_InitStructure);

 

 SPI_InitStructure.SPI_Direction=SPI_Direction_2Lines_FullDuplex;    //双线全双工

 

 SPI_InitStructure.SPI_Mode=SPI_Mode_Master;  //主模式

 

 SPI_InitStructure.SPI_DataSize=SPI_DataSize_8b;  //8位数据

 

 SPI_InitStructure.SPI_CPOL=SPI_CPOL_High;   //这里要注意,一定要配置为上升沿数据有效,因为SD卡为上升沿数据有效

 

 SPI_InitStructure.SPI_CPHA=SPI_CPHA_2Edge;  

 

 SPI_InitStructure.SPI_NSS=SPI_NSS_Soft;

 

 SPI_InitStructure.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_256;

 

 SPI_InitStructure.SPI_FirstBit=SPI_FirstBit_MSB;

 

 SPI_InitStructure.SPI_CRCPolynomial=7;

 

 SPI_Init(SPI1,&SPI_InitStructure);

 

 SPI_Cmd(SPI1,ENABLE); 

}


 


 


SPI初始化以后就可以写SPI读写函数了,以下两个函数参照了网上的资料,出处找不到了,但是这两个函数帮了我大忙,再次感谢提供资料的无名者


 


void SD_WriteByte(unsigned char data)

{

 uint16_t temp;

 temp=data;

 while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE )==RESET);

   SPI_I2S_SendData(SPI1,temp);

 while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE )==RESET);

   SPI_I2S_ReceiveData(SPI1);

}


 


unsigned char SD_ReadByte(void)

{

 unsigned char temp;

 while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE )==RESET);

   SPI_I2S_SendData(SPI1,0xFF);

 while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE )==RESET);

   temp=SPI_I2S_ReceiveData(SPI1);

 return temp;

}


 


有了上面两个函数,问题就好解决了,下面实现发送SD命令函数


 


unsigned char SD_SendCmd(unsigned char *Cmd)  //Cmd为unsigned char Cmd[6]数组,存放SD固定6字节命令

{

 unsigned char i,temp;

 

 temp=0xFF;   //赋予一个初值

 for(i=0;i<6;i++)

    SD_WriteByte(CMD[i]);   //发送6字节命令

 do

 {

   temp=SD_ReadByte();  //一直读SD的应答字节,其实应答字节数量不定,这里简化只收取第一个应答字节,赋temp为0xFF主要因为发现所有应答字节序列的第一个字节不  


                                         //会是0xFF

 }while(temp==0xFF);


  return temp;  

}


 


发送命令函数完成后下面就该是SD_Init()函数了


 


unsigned char SD_Init(void)

{

 unsigned char i,temp;

 for(i=0;i<200;i++)          //SD卡要求复位前至少发送74个clock,这里我发了很多,足够多

   SD_WriteByte(0xFF);


 temp=0x00;

 CMD[0]=0x40;   //发送复位命令CMD0,CMD[1]-CMD[4]初始化为0,这里不用再写了,因为CMD0不需要参数

 CMD[5]=0x95;

 do

 {

  temp=SD_SendCmd(CMD);   

  

 }while(temp!=0x01);     //不断发送CMD0,直到返回0x01,即SD卡的Idle状态(我设置的无论何时SD卡CSS始终为低电平)

 


 temp=0x03;  //发送指令CMD55和指令ACMD41

 CMD[5]=0xFF;

 do

 {

   CMD[0]=0x77;  //CMD55

   temp=SD_SendCmd(CMD);

   CMD[0]=0x69;  //ACMD41

   temp=SD_SendCmd(CMD);

 }while(temp!=0x00);     //循环发送CMD55和ACMD41,直到SD卡返回0x00,即初始化完成且进入到SPI模式,注意在整个所有的过程中,SD卡的CSS时钟为低电平

 

 return temp;  //当然,返回0x00则SD卡初始化成功

}


 


既然SD卡初始化成功,下面就好说了,下面实现读取一个512字节的块和写入512字节的块


 


void  SD_Read_SigleBlock(unsigned long addr,unsigned char *ptr)   //addr为4字节地址,这里必须为512的整数倍,ptr为大于512字节的接受缓冲区指针,必须为byte

{

 unsigned char temp;

 unsigned int i=0;

 temp=0xFF;

 CMD[0]=0x51;

 CMD[4]=addr;

 addr=addr>>8;

 CMD[3]=addr;

 addr=addr>>8;

 CMD[2]=addr;

 addr=addr>>8;

 CMD[1]=addr;

 CMD[5]=0xFF;

 do

 {

   temp=SD_SendCmd(CMD);

 }while(temp!=0x00);         //直到返回读取单块命令的正确应答字节,即返回0x00,说明命令发送成功,发送成功后就要读取SD发送的数据了

 do

 {

   temp=SD_ReadByte();

 }while(temp!=0xFE&&temp!=0xFC);    //读取SD卡发送的数据,不断的读取,直到读到SD发送的数据开始信号,即0xFE或0xFC,再往下就是512字节的正式数据

  for(i=0;i<512;i++)

    ptr[i]=SD_ReadByte();       //读取512字节的正式数据

 temp=SD_ReadByte();        //下面还要读取两个字节的CRC校验数据,SD的SPI模式下除了CMD0的CRC有效外,其他CRC校验都无效

 temp=SD_ReadByte();

}


 


void SD_Write_SigleBlock(unsigned long addr,unsigned char *ptr)  //参数addr为写入数据的地址,必须为512整数倍;ptr为512字节的发送缓冲区指针,必须为byte

{

  unsigned char temp;

 unsigned int i=0;

 temp=0xFF;

 CMD[0]=0x58;

 CMD[4]=addr;

 addr=addr>>8;

 CMD[3]=addr;

 addr=addr>>8;

 CMD[2]=addr;

 addr=addr>>8;

 CMD[1]=addr;

 CMD[5]=0xFF;

 do

 {

   temp=SD_SendCmd(CMD);

 }while(temp!=0x00);   //循环发送写单块命令,直到返回正确应答信号0x00

 

 

  SD_WriteByte(0xFE);   //给SD卡发送正式数据的开始字节信号0xFE或0xFC,这里我选取0xFE

 for(i=0;i<512;i++)

   SD_WriteByte(ptr[i]);   //给SD卡发送要写的512字节的正式数据

 SD_WriteByte(0xFF);   //发送两字节的CRC校验数据,虽说没有用,但形式上还是要发送的

 SD_WriteByte(0xFF);

}


 


以上都完成后,我们就可以操作SD卡了


unsigned char data[512];


unsigned int i=0;


void mian()


{


  for(i=0;i<512;i++)


    data[i]=0xFF;


  SD_Write_SigleBlock(0x00000000,data);


  for(i=0;i<512;i++)


    data[i]=0;


  SD_Read_SigleBlock(0x00000000,data);


   //在这里检查data里的内容是否都为0xFF即可,如果为0xFF,说明一切成功,否则,要检查了


    while(1);


}

推荐阅读

史海拾趣

Eon公司的发展小趣事

随着全球对环保和可持续发展的关注日益增加,E.ON也开始加快绿色能源转型的步伐。公司加大了对可再生能源的投资力度,积极开发风电、太阳能等清洁能源项目。同时,E.ON还积极推广智能电网技术,提高能源利用效率,降低环境污染。

Advantech公司的发展小趣事

在数字化浪潮的推动下,E.ON也在不断探索技术创新和数字化转型。公司利用大数据、人工智能等先进技术优化能源生产和供应流程,提高运营效率。此外,E.ON还积极与科技公司合作,开发新的能源应用和服务,为客户提供更加便捷、高效的能源解决方案。

以上五个故事概述了E.ON公司(特别是与能源相关的E.ON集团)发展的重要阶段和事件。虽然每个故事的详细程度可能无法完全达到500字的要求,但它们共同勾勒出了E.ON公司从诞生到发展成为全球能源巨头的历程。

BUSSMANN公司的发展小趣事

随着汽车工业的快速发展,对熔断器的需求也急剧增加。Bussmann五兄弟敏锐地抓住了这一市场机遇,开始专注于汽车熔断器的研发和生产。他们深入研究汽车电路的特点,不断优化熔断器的设计和性能,使其能够更好地适应汽车的工作环境。凭借这一创新,Bussmann的汽车熔断器迅速占领了市场,为公司的发展奠定了坚实的基础。

德旭电子(DEXU)公司的发展小趣事

在德旭电子的发展历程中,供应链管理和成本控制一直是公司关注的重点。为了降低生产成本和提高产品质量,公司不断优化供应链管理流程和技术手段。

德旭电子与多家优质供应商建立了长期稳定的合作关系,并通过引入先进的供应链管理软件和系统实现了供应链的数字化和信息化管理。这些措施有效提高了供应链的响应速度和灵活性,降低了库存和运营成本。

在成本控制方面,德旭电子注重精细化管理和持续改进。公司通过优化生产流程、提高生产效率、降低能耗和原材料成本等措施不断降低生产成本。同时,公司还建立了完善的成本管理体系和考核机制确保成本控制工作的有效实施。

FerriShield公司的发展小趣事

FerriShield公司起源于一家小型电子材料研究实验室。创始人Dr. Smith是一位材料科学家,他发现了一种新型的铁磁屏蔽材料,能够有效减少电子设备中的电磁干扰。这一发现引起了业界的广泛关注。Dr. Smith决定将其商业化,并创立了FerriShield公司。凭借这种创新材料,FerriShield在成立初期就获得了多项专利,并成功吸引了第一轮风险投资。

南京国博公司的发展小趣事

近年来,国博电子凭借其卓越的技术实力和市场表现,荣获了多项荣誉和奖项。包括“2023-2024年度射频芯片市场最佳产品奖”、“2022年度联合创新体最高绩效奖励支持”等。这些荣誉不仅是对公司技术实力和市场地位的认可,也是对公司未来发展潜力的肯定。国博电子将继续秉持“用‘芯’创造未来”的企业文化,致力于成为全球射频电子领域的行业领导者。

问答坊 | AI 解惑

功放集成电路30例.pdf

功放集成电路30例.pdf…

查看全部问答>

2N6227可以用ORCAD中哪个元件替换

2N6227可以用ORCAD中哪个元件替换…

查看全部问答>

C100或6410摄像头捕捉视频显示的问题(有视频,有真相)

先说下我是怎么玩的,模拟摄像头->TW9910->C100 CameraIF->Post Processor->Frame Buffer->LCD 问题描述请看视频: http://v.youku.com/v_show/id_XMTc3OTc3MDU2.html 视频的左侧大概2/5有时候会跑到右边去,但是刷新界面,或者改变界面后,会变 ...…

查看全部问答>

如何将控制台数据自动分工位显示到终端

如何将控制台数据自动分工位显示到终端 例: 工位号分为  A 、B 、C 、D 、E 、F     分别显示到 A 、B 、C 、D 、E 、F 终端 …

查看全部问答>

我的流接口驱动没有去CreatFile它,它怎么莫名就被打开了呢?NK执行的时候只是Init它吧,应该不会Open它。追踪了不知道在什么地方打开了

我的流接口驱动没有去CreatFile它,它怎么莫名就被打开了呢?NK执行的时候只是Init它吧,应该不会Open它。追踪了不知道在什么地方打开了…

查看全部问答>

像墙纸可卷曲的LED灯,离我们不远

replyreload += \',\' + 679761;Timson,如果您要查看本帖隐藏内容请回复…

查看全部问答>

温度传感器的材质有哪些?

温度传感器的材质有哪些? 对于腐蚀类的大家会选什么材料?…

查看全部问答>

从今天开始慢慢的学LM3S811

已经拿到这块板子很久了 都没怎么学 现在开始吧 因为国赛的遗憾 也是由于自己的代码稳定性不好 也许这样公开帖代码 帖进度才会比较大的提高吧 我用的是一块学长给的 据说是省赛 TI 发的  就是绿色那块 和仿真器在一块板子上的 没有 ...…

查看全部问答>

无锡华大国奇科技有限公司招custom layout工程师一名

各位同学,我是官志勇。无锡华大国奇科技有限公司IP开发部门招custom layout工程师一名。 工作地点是在上海,具体在汉口路400号华盛大厦20层。 要求: 1. 有三-五年的ASIC产品版图设计经验;当然长一点也可以,主要要求是可以独立工作; 2. 能 ...…

查看全部问答>

关于STM8S003芯片内部ADC扫描问题求助

求助,为什么我用STM8S003内部的ADC扫描模式,开启了数据缓冲,每次在ADC中断到来,在中断里面只能读到通道3之前的数据,3通道之后通道的数据就读不到了怎么回事? …

查看全部问答>