ARM DIY进程14:USB读卡器
此次练习结合USB口和SD卡,把开发板变成了名符其实的读卡器,可以在PC机上用鼠标直接操作来读写SD卡上的文件了.USB读卡器对比进程12的虚拟串口,需要支持的C文件多出了官方的usb_bot.c,usb_scsi.c,scsi_data.c,memory.c,msd.c.见图1.程序运行后windows XP系统资源里多出一个可移动磁盘,见图2.插入SD卡,就可以对SD卡进行读写操作了.我的卡只有32Mb,图3是可移动磁盘使用空间。卡内的文件夹“ARM DIY”(图4)就是上次做进程8(SD卡),预先在PC机的读卡器上建立的,那时看不到文件夹,这次可以看到全貌了。有了这个STM32的USB读卡器,从开发板上就可以直接进行FAT文件操作了.呵呵!
图1
图2
我用的SD卡存取速度较慢,在调试过程中发现初始化SD卡总是失败,经过摸索实验,发现在对SD卡初始化时加入延时等待即可解决问题,见图5.
部分代码
#include "hw_config.h"
#include "msd.h"
int main(void)
{
#ifdef DEBUG
debug();
#endif
Set_System();
Set_USBClock();
USB_Interrupts_Config();
Led_Config();
MSD_Init();
Get_Medium_Characteristics();
USB_Init();
while (1)
{
}
}
//HW_CONFIG.C
#include "stm32f10x_it.h"
#include "hw_config.h"
#include "usb_lib.h"
#include "msd.h"
u32 Mass_Memory_Size;
u32 Mass_Block_Size;
u32 Mass_Block_Count;
sMSD_CSD MSD_csd;
ErrorStatus HSEStartUpStatus;
void Set_System(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_DeInit();
RCC_HSEConfig(RCC_HSE_ON);
HSEStartUpStatus = RCC_WaitForHSEStartUp();
if(HSEStartUpStatus == SUCCESS)
{ FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
FLASH_SetLatency(FLASH_Latency_2);
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLK2Config(RCC_HCLK_Div1);
RCC_PCLK1Config(RCC_HCLK_Div2);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
RCC_PLLCmd(ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
{
}
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
while(RCC_GetSYSCLKSource() != 0x08)
{
}
}
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void Set_USBClock(void)
{
RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE);
}
void USB_Interrupts_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
#ifdef VECT_TAB_RAM
NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
#endif
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN_RX0_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = USB_HP_CAN_TX_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void Led_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
void Led_RW_ON(void)
{
GPIO_SetBits(GPIOB, GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);
}
void Led_RW_OFF(void)
{
GPIO_ResetBits(GPIOB, GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);
}
void USB_Cable_Config (FunctionalState NewState)
{
if (NewState != DISABLE)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_8);
}
else
{
GPIO_SetBits(GPIOA, GPIO_Pin_8);
}
}
void Get_Medium_Characteristics(void)
{
u32 temp1 = 0;
u32 temp2 = 0;
MSD_GetCSDRegister(&MSD_csd);
temp1 = MSD_csd.DeviceSize + 1;
temp2 = 1 << (MSD_csd.DeviceSizeMul + 2);
Mass_Block_Count = temp1 * temp2;
Mass_Block_Size = 1 << MSD_csd.RdBlockLen;
Mass_Memory_Size = (Mass_Block_Count * Mass_Block_Size);
}
//Msd.C
#include "msd.h"
/* Select MSD Card: ChipSelect pin low */
#define MSD_CS_LOW() GPIO_ResetBits(GPIOA, GPIO_Pin_4)
#define MSD_CS_HIGH() GPIO_SetBits(GPIOA, GPIO_Pin_4)
void Delay(void)
{u8 i=0xff;
while(--i);
}
static void SPI_Config(void);
u8 MSD_Init(void)
{
u32 i = 0;
SPI_Config();
MSD_CS_HIGH();
for (i = 0; i <= 9; i++)
{ Delay(); //加入延时
MSD_WriteByte(DUMMY);
}
return (MSD_GoIdleState());
}
u8 MSD_WriteBlock(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)
{
u32 i = 0;
u8 rvalue = MSD_RESPONSE_FAILURE;
MSD_CS_LOW();
MSD_SendCmd(MSD_WRITE_BLOCK, WriteAddr, 0xFF);
if (!MSD_GetResponse(MSD_RESPONSE_NO_ERROR))
{
MSD_WriteByte(DUMMY);
MSD_WriteByte(0xFE);
for (i = 0; i < NumByteToWrite; i++)
{
/* Send the pointed byte */
MSD_WriteByte(*pBuffer);
pBuffer++;
}
MSD_ReadByte();
MSD_ReadByte();
if (MSD_GetDataResponse() == MSD_DATA_OK)
rvalue = MSD_RESPONSE_NO_ERROR;
}
MSD_CS_HIGH();
MSD_WriteByte(DUMMY);
return rvalue;
}
u8 MSD_ReadBlock(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead)
{
u32 i = 0;
u8 rvalue = MSD_RESPONSE_FAILURE;
MSD_CS_LOW();
MSD_SendCmd(MSD_READ_SINGLE_BLOCK, ReadAddr, 0xFF);
if (!MSD_GetResponse(MSD_RESPONSE_NO_ERROR))
{
if (!MSD_GetResponse(MSD_START_DATA_SINGLE_BLOCK_READ))
{
for (i = 0; i < NumByteToRead; i++)
{
*pBuffer = MSD_ReadByte();
pBuffer++;
}
MSD_ReadByte();
MSD_ReadByte();
rvalue = MSD_RESPONSE_NO_ERROR;
}
}
MSD_CS_HIGH();
MSD_WriteByte(DUMMY);
return rvalue;
}
u8 MSD_WriteBuffer(u8* pBuffer, u32 WriteAddr, u32 NumByteToWrite)
{
u32 i = 0, NbrOfBlock = 0, Offset = 0;
u8 rvalue = MSD_RESPONSE_FAILURE;
NbrOfBlock = NumByteToWrite / BLOCK_SIZE;
MSD_CS_LOW();
while (NbrOfBlock --)
{
MSD_SendCmd(MSD_WRITE_BLOCK, WriteAddr + Offset, 0xFF);
if (MSD_GetResponse(MSD_RESPONSE_NO_ERROR))
{
return MSD_RESPONSE_FAILURE;
}
MSD_WriteByte(DUMMY);
MSD_WriteByte(MSD_START_DATA_SINGLE_BLOCK_WRITE);
for (i = 0; i < BLOCK_SIZE; i++)
{
MSD_WriteByte(*pBuffer);
pBuffer++;
}
Offset += 512;
MSD_ReadByte();
MSD_ReadByte();
if (MSD_GetDataResponse() == MSD_DATA_OK)
rvalue = MSD_RESPONSE_NO_ERROR;
else
rvalue = MSD_RESPONSE_FAILURE;
}
MSD_CS_HIGH();
MSD_WriteByte(DUMMY);
return rvalue;
}
u8 MSD_ReadBuffer(u8* pBuffer, u32 ReadAddr, u32 NumByteToRead)
{
u32 i = 0, NbrOfBlock = 0, Offset = 0;
u8 rvalue = MSD_RESPONSE_FAILURE;
NbrOfBlock = NumByteToRead / BLOCK_SIZE;
MSD_CS_LOW();
while (NbrOfBlock --)
{
MSD_SendCmd (MSD_READ_SINGLE_BLOCK, ReadAddr + Offset, 0xFF);
if (MSD_GetResponse(MSD_RESPONSE_NO_ERROR))
{
return MSD_RESPONSE_FAILURE;
}
if (!MSD_GetResponse(MSD_START_DATA_SINGLE_BLOCK_READ))
{
for (i = 0; i < BLOCK_SIZE; i++)
{
*pBuffer = MSD_ReadByte();
pBuffer++;
}
Offset += 512;
MSD_ReadByte();
MSD_ReadByte();
rvalue = MSD_RESPONSE_NO_ERROR;
}
else
rvalue = MSD_RESPONSE_FAILURE;
}
MSD_CS_HIGH();
MSD_WriteByte(DUMMY);
return rvalue;
}
u8 MSD_GetCSDRegister(sMSD_CSD* MSD_csd)
{
u32 i = 0;
u8 rvalue = MSD_RESPONSE_FAILURE;
u8 CSD_Tab[16];
MSD_CS_LOW();
MSD_SendCmd(MSD_SEND_CSD, 0, 0xFF);
if (!MSD_GetResponse(MSD_RESPONSE_NO_ERROR))
{
if (!MSD_GetResponse(MSD_START_DATA_SINGLE_BLOCK_READ))
{
for (i = 0; i < 16; i++)
{
CSD_Tab[i] = MSD_ReadByte();
}
}
MSD_WriteByte(DUMMY);
MSD_WriteByte(DUMMY);
rvalue = MSD_RESPONSE_NO_ERROR;
}
MSD_CS_HIGH();
MSD_WriteByte(DUMMY);
MSD_csd->CSDStruct = (CSD_Tab[0] & 0xC0) >> 6;
MSD_csd->SysSpecVersion = (CSD_Tab[0] & 0x3C) >> 2;
MSD_csd->Reserved1 = CSD_Tab[0] & 0x03;
MSD_csd->TAAC = CSD_Tab[1] ;
MSD_csd->NSAC = CSD_Tab[2];
MSD_csd->MaxBusClkFrec = CSD_Tab[3];
MSD_csd->CardComdClasses = CSD_Tab[4] << 4;
MSD_csd->CardComdClasses |= (CSD_Tab[5] & 0xF0) >> 4;
MSD_csd->RdBlockLen = CSD_Tab[5] & 0x0F;
MSD_csd->PartBlockRead = (CSD_Tab[6] & 0x80) >> 7;
MSD_csd->WrBlockMisalign = (CSD_Tab[6] & 0x40) >> 6;
MSD_csd->RdBlockMisalign = (CSD_Tab[6] & 0x20) >> 5;
MSD_csd->DSRImpl = (CSD_Tab[6] & 0x10) >> 4;
MSD_csd->Reserved2 = 0; /* Reserved */
MSD_csd->DeviceSize = (CSD_Tab[6] & 0x03) << 10;
MSD_csd->DeviceSize |= (CSD_Tab[7]) << 2;
MSD_csd->DeviceSize |= (CSD_Tab[8] & 0xC0) >> 6;
MSD_csd->MaxRdCurrentVDDMin = (CSD_Tab[8] & 0x38) >> 3;
MSD_csd->MaxRdCurrentVDDMax = (CSD_Tab[8] & 0x07);
MSD_csd->MaxWrCurrentVDDMin = (CSD_Tab[9] & 0xE0) >> 5;
MSD_csd->MaxWrCurrentVDDMax = (CSD_Tab[9] & 0x1C) >> 2;
MSD_csd->DeviceSizeMul = (CSD_Tab[9] & 0x03) << 1;
MSD_csd->DeviceSizeMul |= (CSD_Tab[10] & 0x80) >> 7;
MSD_csd->EraseGrSize = (CSD_Tab[10] & 0x7C) >> 2;
MSD_csd->EraseGrMul = (CSD_Tab[10] & 0x03) << 3;
MSD_csd->EraseGrMul |= (CSD_Tab[11] & 0xE0) >> 5;
MSD_csd->WrProtectGrSize = (CSD_Tab[11] & 0x1F);
MSD_csd->WrProtectGrEnable = (CSD_Tab[12] & 0x80) >> 7;
MSD_csd->ManDeflECC = (CSD_Tab[12] & 0x60) >> 5;
MSD_csd->WrSpeedFact = (CSD_Tab[12] & 0x1C) >> 2;
MSD_csd->MaxWrBlockLen = (CSD_Tab[12] & 0x03) << 2;
MSD_csd->MaxWrBlockLen |= (CSD_Tab[13] & 0xc0) >> 6;
MSD_csd->WriteBlockPaPartial = (CSD_Tab[13] & 0x20) >> 5;
MSD_csd->Reserved3 = 0;
MSD_csd->ContentProtectAppli = (CSD_Tab[13] & 0x01);
MSD_csd->FileFormatGrouop = (CSD_Tab[14] & 0x80) >> 7;
MSD_csd->CopyFlag = (CSD_Tab[14] & 0x40) >> 6;
MSD_csd->PermWrProtect = (CSD_Tab[14] & 0x20) >> 5;
MSD_csd->TempWrProtect = (CSD_Tab[14] & 0x10) >> 4;
MSD_csd->FileFormat = (CSD_Tab[14] & 0x0C) >> 2;
MSD_csd->ECC = (CSD_Tab[14] & 0x03);
MSD_csd->CRC = (CSD_Tab[15] & 0xFE) >> 1;
MSD_csd->Reserved4 = 1;
return rvalue;
}
u8 MSD_GetCIDRegister(sMSD_CID* MSD_cid)
{
u32 i = 0;
u8 rvalue = MSD_RESPONSE_FAILURE;
u8 CID_Tab[16];
MSD_CS_LOW();
MSD_SendCmd(MSD_SEND_CID, 0, 0xFF);
if (!MSD_GetResponse(MSD_RESPONSE_NO_ERROR))
{
if (!MSD_GetResponse(MSD_START_DATA_SINGLE_BLOCK_READ))
{
for (i = 0; i < 16; i++)
{
CID_Tab[i] = MSD_ReadByte();
}
}
MSD_WriteByte(DUMMY);
MSD_WriteByte(DUMMY);
rvalue = MSD_RESPONSE_NO_ERROR;
}
MSD_CS_HIGH();
MSD_WriteByte(DUMMY);
MSD_cid->ManufacturerID = CID_Tab[0];
MSD_cid->OEM_AppliID = CID_Tab[1] << 8;
MSD_cid->OEM_AppliID |= CID_Tab[2];
MSD_cid->ProdName1 = CID_Tab[3] << 24;
MSD_cid->ProdName1 |= CID_Tab[4] << 16;
MSD_cid->ProdName1 |= CID_Tab[5] << 8;
MSD_cid->ProdName1 |= CID_Tab[6];
MSD_cid->ProdName2 = CID_Tab[7];
MSD_cid->ProdRev = CID_Tab[8];
MSD_cid->ProdSN = CID_Tab[9] << 24;
MSD_cid->ProdSN |= CID_Tab[10] << 16;
MSD_cid->ProdSN |= CID_Tab[11] << 8;
MSD_cid->ProdSN |= CID_Tab[12];
MSD_cid->Reserved1 |= (CID_Tab[13] & 0xF0) >> 4;
MSD_cid->ManufactDate = (CID_Tab[13] & 0x0F) << 8;
MSD_cid->ManufactDate |= CID_Tab[14];
MSD_cid->CRC = (CID_Tab[15] & 0xFE) >> 1;
MSD_cid->Reserved2 = 1;
return rvalue;
}
void MSD_SendCmd(u8 Cmd, u32 Arg, u8 Crc)
{
u32 i = 0x00;
u8 Frame[6];
Frame[0] = (Cmd | 0x40);
Frame[1] = (u8)(Arg >> 24);
Frame[2] = (u8)(Arg >> 16);
Frame[3] = (u8)(Arg >> 8);
Frame[4] = (u8)(Arg);
Frame[5] = (Crc);
for (i = 0; i < 6; i++)
MSD_WriteByte(Frame[i]);
}
u8 MSD_GetDataResponse(void)
{
u32 i = 0;
u8 response, rvalue;
while (i <= 64)
{
response = MSD_ReadByte();
response &= 0x1F;
switch (response)
{
case MSD_DATA_OK:
{
rvalue = MSD_DATA_OK;
break;
}
case MSD_DATA_CRC_ERROR:
return MSD_DATA_CRC_ERROR;
case MSD_DATA_WRITE_ERROR:
return MSD_DATA_WRITE_ERROR;
default:
{
rvalue = MSD_DATA_OTHER_ERROR;
break;
}
}
if (rvalue == MSD_DATA_OK)
break;
i++;
}
while (MSD_ReadByte() == 0);
return response;
}
u8 MSD_GetResponse(u8 Response)
{
u32 Count = 0xFFF;
while ((MSD_ReadByte() != Response) && Count)
Count--;
if (Count == 0)
return MSD_RESPONSE_FAILURE;
else
return MSD_RESPONSE_NO_ERROR;
}
u16 MSD_GetStatus(void)
{
u16 Status = 0;
MSD_CS_LOW();
MSD_SendCmd(MSD_SEND_STATUS, 0, 0xFF);
Status = MSD_ReadByte();
Status |= (u16)(MSD_ReadByte() << 8);
MSD_CS_HIGH();
MSD_WriteByte(DUMMY);
return Status;
}
u8 MSD_GoIdleState(void)
{
MSD_CS_LOW();
MSD_SendCmd(MSD_GO_IDLE_STATE, 0, 0x95);
if (MSD_GetResponse(MSD_IN_IDLE_STATE))
{
return MSD_RESPONSE_FAILURE;
}
do
{
MSD_CS_HIGH();
Delay();
MSD_WriteByte(DUMMY);
Delay();
MSD_CS_LOW();
Delay(); //加入延时
MSD_SendCmd(MSD_SEND_OP_COND, 0, 0xFF);
}
while (MSD_GetResponse(MSD_RESPONSE_NO_ERROR));
MSD_CS_HIGH();
MSD_WriteByte(DUMMY);
return MSD_RESPONSE_NO_ERROR;
}
void MSD_WriteByte(u8 Data)
{
while (SPI_GetFlagStatus(SPI1, SPI_FLAG_TXE) == RESET);
SPI_SendData(SPI1, Data);
}
u8 MSD_ReadByte(void)
{
u8 Data = 0;
while (SPI_GetFlagStatus(SPI1, SPI_FLAG_TXE) == RESET);
SPI_SendData(SPI1, DUMMY);
while (SPI_GetFlagStatus(SPI1, SPI_FLAG_RXNE) == RESET);
Data = SPI_ReceiveData(SPI1);
return Data;
}
void SPI_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
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;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI1, &SPI_InitStructure);
SPI_Cmd(SPI1, ENABLE);
}
ARM DIY进程15:uCOS-II移植
要真正理解和掌握uCOS-II移植,并非易事。这里的uCOS-II的移植练习其实只是拷贝大王加补丁。移植中建立了4个任务:Task1_LED1-Task1_LED4,它们以不同的TS_TICKS_PER_SEC延时时长,点亮和熄灭LED1-LED4。我在移植中把原来的3.3V的I/O驱动5V的LCD代码加入,在每个任务执行中在屏幕上显示各个任务中LED的工作状态,并与开发板上的4只LED状态相对应,1代表亮,0代表灭。其实移植工作比较简 单,主要代码都是人家写好的,我们只是把自己的代码融合进去而已,体验体验uCOS-II移植实际效果。
回复
有奖活动 | |
---|---|
【有奖活动】分享技术经验,兑换京东卡 | |
话不多说,快进群! | |
请大声喊出:我要开发板! | |
【有奖活动】EEPW网站征稿正在进行时,欢迎踊跃投稿啦 | |
奖!发布技术笔记,技术评测贴换取您心仪的礼品 | |
打赏了!打赏了!打赏了! |
打赏帖 | |
---|---|
vscode+cmake搭建雅特力AT32L021开发环境被打赏30分 | |
【换取逻辑分析仪】自制底板并驱动ArduinoNanoRP2040ConnectLCD扩展板被打赏47分 | |
【分享评测,赢取加热台】RISC-V GCC 内嵌汇编使用被打赏38分 | |
【换取逻辑分析仪】-基于ADI单片机MAX78000的简易MP3音乐播放器被打赏48分 | |
我想要一部加热台+树莓派PICO驱动AHT10被打赏38分 | |
【换取逻辑分析仪】-硬件SPI驱动OLED屏幕被打赏36分 | |
换逻辑分析仪+上下拉与多路选择器被打赏29分 | |
Let'sdo第3期任务合集被打赏50分 | |
换逻辑分析仪+Verilog三态门被打赏27分 | |
换逻辑分析仪+Verilog多输出门被打赏24分 |