//等待SD卡写入完成 //返回值:0,成功; // 其他,错误代码; u8 SD_WaitDataReady(void) { u8 r1=MSD_DATA_OTHER_ERROR; u32 retry; retry=0; do { r1=SPIx_ReadWriteByte(0xFF)&0X1F;//读到回应 if(retry==0xfffe)return 1; retry++; switch (r1) { case MSD_DATA_OK://数据接收正确了 r1=MSD_DATA_OK; break; case MSD_DATA_CRC_ERROR: //CRC校验错误 return MSD_DATA_CRC_ERROR; case MSD_DATA_WRITE_ERROR://数据写入错误 return MSD_DATA_WRITE_ERROR; default://未知错误 r1=MSD_DATA_OTHER_ERROR; break; } } while(r1==MSD_DATA_OTHER_ERROR); //数据错误时一直等待 retry=0; while(SPIx_ReadWriteByte(0XFF)==0)//读到数据为0,则数据还未写完成 { retry++; //delay_us(10);//SD卡写等待需要较长的时间 if(retry>=0XFFFFFFFE)return 0XFF;//等待失败了 }; return 0;//成功了 }
//写入MSD/SD数据 //pBuffer:数据存放区 //ReadAddr:写入的首地址 //NumByteToRead:要写入的字节数 //返回值:0,写入完成 // 其他,写入失败 u8 MSD_WriteBuffer(u8* pBuffer, u32 WriteAddr, u32 NumByteToWrite) { u32 i,NbrOfBlock = 0, Offset = 0; u32 sector; u8 r1; NbrOfBlock = NumByteToWrite / BLOCK_SIZE;//得到要写入的块的数目 SD_CS=0; while (NbrOfBlock--)//写入一个扇区 { sector=WriteAddr+Offset; if(SD_Type==SD_TYPE_V2HC)sector>>=9;//执行与普通操作相反的操作 r1=SD_SendCommand_NoDeassert(CMD24,sector,0xff);//写命令 if(r1) { SD_CS=1; return 1;//应答不正确,直接返回 } SPIx_ReadWriteByte(0xFE);//放起始令牌0xFE //放一个sector的数据 for(i=0; i<512; i++)SPIx_ReadWriteByte(*pBuffer++); //发2个Byte的dummy CRC SPIx_ReadWriteByte(0xff); SPIx_ReadWriteByte(0xff); if(SD_WaitDataReady())//等待SD卡数据写入完成 { SD_CS=1; return 2; } Offset += 512; } //写入完成,片选置1 SD_CS=1; SPIx_ReadWriteByte(0xff); return 0; }
//写SPI_FLASH状态寄存器 //只有SPR,TB,BP2,BP1,BP0(bit 7,5,4,3,2)可以写!!! void SPI_FLASH_Write_SR(u8 sr) { SPI_FLASH_CS=0; //使能器件 SPIx_ReadWriteByte(W25X_WriteStatusReg); //发送写取状态寄存器命令 SPIx_ReadWriteByte(sr); //写入一个字节 SPI_FLASH_CS=1; //取消片选 }
//在指定位置读出指定长度的数据 //reg:寄存器(位置) //*pBuf:数据指针 //len:数据长度 //返回值,此次读到的状态寄存器值 u8 NRF24L01_Read_Buf(u8 reg,u8 *pBuf,u8 len) { u8 status,u8_ctr; Clr_NRF24L01_CSN; //使能SPI传输 status=SPIx_ReadWriteByte(reg);//发送寄存器值(位置),并读取状态值 for(u8_ctr=0;u8_ctr<len;u8_ctr++)pBuf[u8_ctr]=SPIx_ReadWriteByte(0XFF);//读出数据 Set_NRF24L01_CSN; //关闭SPI传输 return status; //返回读到的状态值 }
//在指定位置写指定长度的数据 //reg:寄存器(位置) //*pBuf:数据指针 //len:数据长度 //返回值,此次读到的状态寄存器值 u8 NRF24L01_Write_Buf(u8 reg, u8 *pBuf, u8 len) { u8 status,u8_ctr; NRF24L01_CSN = 0; //使能SPI传输 status = SPIx_ReadWriteByte(reg);//发送寄存器值(位置),并读取状态值 for(u8_ctr=0; u8_ctr<len; u8_ctr++)SPIx_ReadWriteByte(*pBuf++); //写入数据 NRF24L01_CSN = 1; //关闭SPI传输 return status; //返回读到的状态值 }
//读取SPI_FLASH的状态寄存器 //BIT7 6 5 4 3 2 1 0 //SPR RV TB BP2 BP1 BP0 WEL BUSY //SPR:默认0,状态寄存器保护位,配合WP使用 //TB,BP2,BP1,BP0:FLASH区域写保护设置 //WEL:写使能锁定 //BUSY:忙标记位(1,忙;0,空闲) //默认:0x00 u8 SPI_Flash_ReadSR(void) { u8 byte=0; SPI_FLASH_CS=0; //使能器件 SPIx_ReadWriteByte(W25X_ReadStatusReg); //发送读取状态寄存器命令 byte=SPIx_ReadWriteByte(0Xff); //读取一个字节 SPI_FLASH_CS=1; //取消片选 return byte; }
//SPI写寄存器 //reg:指定寄存器地址 //value:写入的值 u8 NRF24L01_Write_Reg(u8 reg,u8 value) { u8 status; Clr_NRF24L01_CSN; //使能SPI传输 status =SPIx_ReadWriteByte(reg);//发送寄存器号 SPIx_ReadWriteByte(value); //写入寄存器的值 Set_NRF24L01_CSN; //禁止SPI传输 return(status); //返回状态值 }
//读取SPI_FLASH的状态寄存器 //BIT7 6 5 4 3 2 1 0 //SPR RV TB BP2 BP1 BP0 WEL BUSY //SPR:默认0,状态寄存器保护位,配合WP使用 //TB,BP2,BP1,BP0:FLASH区域写保护设置 //WEL:写使能锁定 //BUSY:忙标记位(1,忙;0,空闲) //默认:0x00 u8 SPI_Flash_ReadSR(void) { u8 byte=0; W25Q16_CS_LOW(); //使能器件 SPIx_ReadWriteByte(0x05); //发送读取状态寄存器命令 byte=SPIx_ReadWriteByte(0Xff); //读取一个字节 W25Q16_CS_HIGH(); //取消片选 return byte; }
//读取SPI寄存器值 //reg:要读的寄存器 u8 NRF24L01_Read_Reg(u8 reg) { u8 reg_val; Clr_NRF24L01_CSN; //使能SPI传输 SPIx_ReadWriteByte(reg); //发送寄存器号 reg_val=SPIx_ReadWriteByte(0XFF);//读取寄存器内容 Set_NRF24L01_CSN; //禁止SPI传输 return(reg_val); //返回状态值 }
//擦除一个扇区 //Dst_Addr:扇区地址 0~511 for w25x16 //擦除一个山区的最少时间:150ms void SPI_Flash_Erase_Sector(u32 Dst_Addr) { Dst_Addr*=4096; SPI_FLASH_Write_Enable(); //SET WEL SPI_Flash_Wait_Busy(); SPI_FLASH_CS=0; //使能器件 SPIx_ReadWriteByte(W25X_SectorErase); //发送扇区擦除指令 SPIx_ReadWriteByte((u8)((Dst_Addr)>>16)); //发送24bit地址 SPIx_ReadWriteByte((u8)((Dst_Addr)>>8)); SPIx_ReadWriteByte((u8)Dst_Addr); SPI_FLASH_CS=1; //取消片选 SPI_Flash_Wait_Busy(); //等待擦除完成 }
//SPI在一页(0~65535)内写入少于256个字节的数据 //在指定地址开始写入最大256字节的数据 //pBuffer:数据存储区 //WriteAddr:开始写入的地址(24bit) //NumByteToWrite:要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!! void SPI_Flash_Write_Page(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite) { u16 i; SPI_FLASH_Write_Enable(); //SET WEL SPI_FLASH_CS=0; //使能器件 SPIx_ReadWriteByte(W25X_PageProgram); //发送写页命令 SPIx_ReadWriteByte((u8)((WriteAddr)>>16)); //发送24bit地址 SPIx_ReadWriteByte((u8)((WriteAddr)>>8)); SPIx_ReadWriteByte((u8)WriteAddr); for(i=0;i<NumByteToWrite;i++)SPIx_ReadWriteByte(pBuffer[i]);//循环写数 SPI_FLASH_CS=1; //取消片选 SPI_Flash_Wait_Busy(); //等待写入结束 }
//写入SD卡的N个block(未实际测试过) //输入:u32 sector 扇区地址(sector值,非物理地址) // u8 *buffer 数据存储地址(大小至少512byte) // u8 count 写入的block数目 //返回值:0: 成功 // other:失败 u8 SD_WriteMultiBlock(u32 sector, const u8 *data, u8 count) { u8 r1; u16 i; //SPIx_SetSpeed(SPI_SPEED_HIGH);//设置为高速模式 if(SD_Type != SD_TYPE_V2HC)sector = sector<<9;//如果不是SDHC,给定的是sector地址,将其转换成byte地址 if(SD_Type != SD_TYPE_MMC) r1 = SD_SendCommand(ACMD23, count, 0x00);//如果目标卡不是MMC卡,启用ACMD23指令使能预擦除 r1 = SD_SendCommand(CMD25, sector, 0x00);//发多块写入指令 if(r1 != 0x00)return r1; //应答不正确,直接返回 SD_CS=0;//开始准备数据传输 SPIx_ReadWriteByte(0xff);//先放3个空数据,等待SD卡准备好 SPIx_ReadWriteByte(0xff); //--------下面是N个sector写入的循环部分 do { //放起始令牌0xFC 表明是多块写入 SPIx_ReadWriteByte(0xFC); //放一个sector的数据 for(i=0; i<512; i++) { SPIx_ReadWriteByte(*data++); } //发2个Byte的dummy CRC SPIx_ReadWriteByte(0xff); SPIx_ReadWriteByte(0xff); //等待SD卡应答 r1 = SPIx_ReadWriteByte(0xff); if((r1&0x1F)!=0x05) { SD_CS=1; //如果应答为报错,则带错误代码直接退出 return r1; } //等待SD卡写入完成 if(SD_WaitDataReady()==1) { SD_CS=1; //等待SD卡写入完成超时,直接退出报错 return 1; } } while(--count);//本sector数据传输完成 //发结束传输令牌0xFD r1 = SPIx_ReadWriteByte(0xFD); if(r1==0x00) { count = 0xfe; } if(SD_WaitDataReady()) //等待准备好 { SD_CS=1; return 1; } //写入完成,片选置1 SD_CS=1; SPIx_ReadWriteByte(0xff); return count; //返回count值,如果写完则count=0,否则count=1 }
//读取SPI FLASH //在指定地址开始读取指定长度的数据 //pBuffer:数据存储区 //ReadAddr:开始读取的地址(24bit) //NumByteToRead:要读取的字节数(最大65535) void SPI_Flash_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead) { u16 i; SPI_FLASH_CS=0; //使能器件 SPIx_ReadWriteByte(W25X_ReadData); //发送读取命令 SPIx_ReadWriteByte((u8)((ReadAddr)>>16)); //发送24bit地址 SPIx_ReadWriteByte((u8)((ReadAddr)>>8)); SPIx_ReadWriteByte((u8)ReadAddr); for(i=0;i<NumByteToRead;i++) { pBuffer[i]=SPIx_ReadWriteByte(0XFF); //循环读数 } SPI_FLASH_CS=1; //取消片选 }
//向SD卡发送一个命令 //输入: u8 cmd 命令 // u32 arg 命令参数 // u8 crc crc校验值 //返回值:SD卡返回的响应 u8 SD_SendCommand(u8 cmd, u32 arg, u8 crc) { u8 r1; u8 Retry=0; SD_CS=1; SPIx_ReadWriteByte(0xff);//高速写命令延时 SPIx_ReadWriteByte(0xff); SPIx_ReadWriteByte(0xff); //片选端置低,选中SD卡 SD_CS=0; //发送 SPIx_ReadWriteByte(cmd | 0x40);//分别写入命令 SPIx_ReadWriteByte(arg >> 24); SPIx_ReadWriteByte(arg >> 16); SPIx_ReadWriteByte(arg >> 8); SPIx_ReadWriteByte(arg); SPIx_ReadWriteByte(crc); //等待响应,或超时退出 while((r1=SPIx_ReadWriteByte(0xFF))==0xFF) { Retry++; if(Retry>200)break; } //关闭片选 SD_CS=1; //在总线上额外增加8个时钟,让SD卡完成剩下的工作 SPIx_ReadWriteByte(0xFF); //返回状态值 return r1; }
/* * 函数名:SPIx_Init * 描述 :SPI1的初始化 * 输入 :无 * 输出 :无 * 调用 :外部调用 */ void SPIx_Init(void) { GPIO_InitTypeDef GPIO_InitStructure;//定义IO口配置 结构体 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_SPI1,ENABLE);//SPI GPIOA 时钟使能 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;//选中引脚5,6,7 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//IO输出速度50Hz GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出 GPIO_Init(GPIOA,&GPIO_InitStructure);//配置引脚 GPIO_SetBits(GPIOA, GPIO_Pin_5 | GPIO_Pin_6| GPIO_Pin_7);//PA 5,6,7 输出高 SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//SPI设置为双线双向全双工 SPI_InitStructure.SPI_Mode = SPI_Mode_Master;//设置为主 SPI SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;//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 位开始 SPI_InitStructure.SPI_CRCPolynomial = 7;//SPI_CRCPolynomial定义了用于 CRC值计算的多项式 SPI_Init(SPI1, &SPI_InitStructure); //配置SPI1 SPI_Cmd(SPI1, ENABLE);//SPI1使能 SPIx_ReadWriteByte(0xFF);//启动传输 }
//等待SD卡回应 //Response:要得到的回应值 //返回值:0,成功得到了该回应值 // 其他,得到回应值失败 u8 SD_GetResponse(u8 Response) { u16 Count=0xFFF;//等待次数 while ((SPIx_ReadWriteByte(0XFF)!=Response)&&Count)Count--;//等待得到准确的回应 if (Count==0)return MSD_RESPONSE_FAILURE;//得到回应失败 else return MSD_RESPONSE_NO_ERROR;//正确回应 }
//以下是SPI模块的初始化代码,配置成主机模式,访问SD Card/W25X16/24L01/JF24C //SPI口初始化 //这里针是对SPI1的初始化 void SPIx_Init(void) { RCC->APB2RSTR|=1<<12; //SPI1复位 RCC->APB2RSTR&=~(1<<12); //SPI1结束复位 RCC->APB2ENR|=1<<2; //PORTA时钟使能 RCC->APB2ENR|=1<<12; //SPI1时钟使能 //这里只针对SPI口初始化 GPIOA->CRL&=0X000FFFFF; GPIOA->CRL|=0XBBB00000;//PA5.6.7复用 GPIOA->ODR|=0X7<<5; //PA5.6.7上拉 SPI1->CR1|=0<<10;//全双工模式 SPI1->CR1|=1<<9; //软件nss管理 SPI1->CR1|=1<<8; SPI1->CR1|=1<<2; //SPI主机 SPI1->CR1|=0<<11;//8bit数据格式 //对24L01要设置 CPHA=0;CPOL=0; SPI1->CR1|=1<<1; //CPOL=0时空闲模式下SCK为1 SPI1->CR1|=1<<0; //第一个时钟的下降沿,CPHA=1 CPOL=1 SPI1->CR1|=7<<3; //Fsck=Fcpu/256 SPI1->CR1|=0<<7; //MSBfirst SPI1->CR1|=1<<6; //SPI设备使能 SPIx_ReadWriteByte(0xff);//启动传输 }
//唤醒 void SPI_Flash_WAKEUP(void) { SPI_FLASH_CS=0; //使能器件 SPIx_ReadWriteByte(W25X_ReleasePowerDown); // send W25X_PowerDown command 0xAB SPI_FLASH_CS=1; //取消片选 delay_us(3); //等待TRES1 }
void SPIx_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外设 SPIx_ReadWriteByte(0xff);//启动传输 }
//进入掉电模式 void SPI_Flash_PowerDown(void) { SPI_FLASH_CS=0; //使能器件 SPIx_ReadWriteByte(W25X_PowerDown); //发送掉电命令 SPI_FLASH_CS=1; //取消片选 delay_us(3); //等待TPD }
//读取MSD/SD数据 //pBuffer:数据存放区 //ReadAddr:读取的首地址 //NumByteToRead:要读出的字节数 //返回值:0,读出完成 // 其他,读出失败 u8 MSD_ReadBuffer(u8* pBuffer, u32 ReadAddr, u32 NumByteToRead) { u32 NbrOfBlock=0,Offset=0; u32 sector=0; u8 r1=0; NbrOfBlock=NumByteToRead/BLOCK_SIZE; SD_CS=0; while (NbrOfBlock --) { sector=ReadAddr+Offset; if(SD_Type==SD_TYPE_V2HC)sector>>=9;//执行与普通操作相反的操作 r1=SD_SendCommand_NoDeassert(CMD17,sector,0xff);//读命令 if(r1)//命令发送错误 { SD_CS=1; return r1; } r1=SD_ReceiveData(pBuffer,512,RELEASE); if(r1)//读数错误 { SD_CS=1; return r1; } pBuffer+=512; Offset+=512; } SD_CS=1; SPIx_ReadWriteByte(0xff); return 0; }
/** *名称:SPI_Flash_Erase_Chip *输入:无 *输出:无 *返回:无 *功能:擦除整个芯片整片擦除时间: W25X16:25s W25X32:40s W25X64:40s 等待时间超长... *说明:擦除时间来源于手册,有待验证 **/ void SPI_Flash_Erase_Chip(void) { SPI_FLASH_Write_Enable(); //SET WEL SPI_Flash_Wait_Busy(); W25Q16_CS_LOW(); //使能器件 SPIx_ReadWriteByte(W25X_ChipErase); //发送片擦除命令 W25Q16_CS_HIGH(); //取消片选 SPI_Flash_Wait_Busy(); //等待芯片擦除结束 }
//擦除整个芯片 //整片擦除时间: //W25X16:25s //W25X32:40s //W25X64:40s //等待时间超长... void SPI_Flash_Erase_Chip(void) { SPI_FLASH_Write_Enable(); //SET WEL SPI_Flash_Wait_Busy(); SPI_FLASH_CS=0; //使能器件 SPIx_ReadWriteByte(W25X_ChipErase); //发送片擦除命令 SPI_FLASH_CS=1; //取消片选 SPI_Flash_Wait_Busy(); //等待芯片擦除结束 }
//在指定扇区,从offset开始读出bytes个字节 //输入:u32 sector 扇区地址(sector值,非物理地址) // u8 *buf 数据存储地址(大小<=512byte) // u16 offset 在扇区里面的偏移量 // u16 bytes 要读出的字节数 //返回值:0: 成功 // other:失败 u8 SD_Read_Bytes(unsigned long address,unsigned char *buf,unsigned int offset,unsigned int bytes) { u8 r1; u16 i=0; r1=SD_SendCommand(CMD17,address<<9,0);//发送读扇区命令 if(r1)return r1; //应答不正确,直接返回 SD_CS=0;//选中SD卡 if(SD_GetResponse(0xFE))//等待SD卡发回数据起始令牌0xFE { SD_CS=1; //关闭SD卡 return 1;//读取失败 } for(i=0; i<offset; i++)SPIx_ReadWriteByte(0xff); //跳过offset位 for(; i<offset+bytes; i++)*buf++=SPIx_ReadWriteByte(0xff); //读取有用数据 for(; i<512; i++) SPIx_ReadWriteByte(0xff); //读出剩余字节 SPIx_ReadWriteByte(0xff);//发送伪CRC码 SPIx_ReadWriteByte(0xff); SD_CS=1;//关闭SD卡 return 0; }
//从SD卡中读回指定长度的数据,放置在给定位置 //输入: u8 *data(存放读回数据的内存>len) // u16 len(数据长度) // u8 release(传输完成后是否释放总线CS置高 0:不释放 1:释放) //返回值:0:NO_ERR // other:错误信息 u8 SD_ReceiveData(u8 *data, u16 len, u8 release) { // 启动一次传输 SD_CS=0; if(SD_GetResponse(0xFE))//等待SD卡发回数据起始令牌0xFE { SD_CS=1; return 1; } while(len--)//开始接收数据 { *data=SPIx_ReadWriteByte(0xFF); data++; } //下面是2个伪CRC(dummy CRC) SPIx_ReadWriteByte(0xFF); SPIx_ReadWriteByte(0xFF); if(release==RELEASE)//按需释放总线,将CS置高 { SD_CS=1;//传输结束 SPIx_ReadWriteByte(0xFF); } return 0; }
/** *名称:SPI_Flash_ReadID *功能:读取芯片ID W25X16的ID:0XEF14 **/ u16 SPI_Flash_ReadID(void) { u16 Temp = 0; W25Q16_CS_LOW(); SPIx_ReadWriteByte(0x90); /*发送读取ID命令*/ SPIx_ReadWriteByte(0x00); SPIx_ReadWriteByte(0x00); SPIx_ReadWriteByte(0x00); Temp|=SPIx_ReadWriteByte(0xFF)<<8; Temp|=SPIx_ReadWriteByte(0xFF); W25Q16_CS_HIGH(); return Temp; }
//读取芯片ID W25X16的ID:0XEF14 u16 SPI_Flash_ReadID(void) { u16 Temp = 0; SPI_FLASH_CS=0; SPIx_ReadWriteByte(0x90);//发送读取ID命令 SPIx_ReadWriteByte(0x00); SPIx_ReadWriteByte(0x00); SPIx_ReadWriteByte(0x00); Temp|=SPIx_ReadWriteByte(0xFF)<<8; Temp|=SPIx_ReadWriteByte(0xFF); SPI_FLASH_CS=1; return Temp; }
//把SD卡设置到挂起模式 //返回值:0,成功设置 // 1,设置失败 u8 SD_Idle_Sta(void) { u16 i; u8 retry; for(i=0; i<0xf00; i++); //纯延时,等待SD卡上电完成 //先产生>74个脉冲,让SD卡自己初始化完成 for(i=0; i<10; i++)SPIx_ReadWriteByte(0xFF); //-----------------SD卡复位到idle开始----------------- //循环连续发送CMD0,直到SD卡返回0x01,进入IDLE状态 //超时则直接退出 retry = 0; do { //发送CMD0,让SD卡进入IDLE状态 i = SD_SendCommand(CMD0, 0, 0x95); retry++; } while((i!=0x01)&&(retry<200)); //跳出循环后,检查原因:初始化成功?or 重试超时? if(retry==200)return 1; //失败 return 0;//成功 }
//读SD卡的多个block(实际测试过) //输入:u32 sector 扇区地址(sector值,非物理地址) // u8 *buffer 数据存储地址(大小至少512byte) // u8 count 连续读count个block //返回值:0: 成功 // other:失败 u8 SD_ReadMultiBlock(u32 sector, u8 *buffer, u8 count) { u8 r1; //SPIx_SetSpeed(SPI_SPEED_HIGH);//设置为高速模式 //如果不是SDHC,将sector地址转成byte地址 if(SD_Type!=SD_TYPE_V2HC)sector = sector<<9; //SD_WaitDataReady(); //发读多块命令 r1 = SD_SendCommand(CMD18, sector, 0);//读命令 if(r1 != 0x00)return r1; do//开始接收数据 { if(SD_ReceiveData(buffer, 512, NO_RELEASE) != 0x00)break; buffer += 512; } while(--count); //全部传输完毕,发送停止命令 SD_SendCommand(CMD12, 0, 0); //释放总线 SD_CS=1; SPIx_ReadWriteByte(0xFF); if(count != 0)return count; //如果没有传完,返回剩余个数 else return 0; }
//以下是SPI模块的初始化代码,配置成主机模式,访问SD Card/W25X16/24L01/JF24C //SPI口初始化 //这里针是对SPI1的初始化 void SPIx_Init(void) { RCC->APB2ENR|=1<<2; //PORTA时钟使能 RCC->APB2ENR|=1<<12; //SPI1时钟使能 //这里只针对SPI口初始化 GPIOA->CRL&=0X000FFFFF; GPIOA->CRL|=0XBBB00000;//PA5.6.7复用 GPIOA->ODR|=0X7<<5; //PA5.6.7上拉 SPI1->CR1|=0<<10;//全双工模式 SPI1->CR1|=1<<9; //软件nss管理 SPI1->CR1|=1<<8; SPI1->CR1|=1<<2; //SPI主机 SPI1->CR1|=0<<11;//8bit数据格式 SPI1->CR1|=1<<1; //空闲模式下SCK为1 CPOL=1 SPI1->CR1|=1<<0; //数据采样从第二个时间边沿开始,CPHA=1 SPI1->CR1|=7<<3; //Fsck=Fcpu/256 SPI1->CR1|=0<<7; //MSBfirst SPI1->CR1|=1<<6; //SPI设备使能 SPIx_ReadWriteByte(0xff);//启动传输 }