imuncle.github.io
imuncle.github.io copied to clipboard
嵌入式视觉OpenOV研发(二) 读卡器功能
先把读卡器功能实现,相对于真正核心的嵌入式视觉代码来说,这种如同外设一般的存在就应该尽早被攻克掉。
SDIO协议及SD卡简介
这里推荐看正点原子的教程,讲的很详细。这里真心给正点原子点个赞!暑假的时候突然发现正点原子入驻B站了,可以直接在线观看高清的视频教程了!去他妈的限速百度云,保存到网盘在线看也没法高清,还时不时卡顿,入驻B站这一操作简直感动到哭!
- 【正点原子】 手把手教你学STM32 系列视频之 STM32F4-基于探索者F407-SDIO简介
- 【正点原子】 手把手教你学STM32 系列视频之 STM32F4-基于探索者F407-SD卡简介
- 【正点原子】 手把手教你学STM32 系列视频之 STM32F4-基于探索者F407-SD卡实验源码讲解
SD卡驱动
不得不说,STM32CubeMX帮我们省去了很多很多外设的操作步骤。按照正点原子的教程,我们需要首先把SD卡的时钟降下来,发送指令初始化SD卡,初始化成功之后再把时钟升上去,每次发送命令操作寄存器,处理SD卡长短响应之类的,完全不用我们去管,只管调用函数就行。
STM32CubeMX里面的配置也非常简单,直接使能,一步到位:
之后读写SD卡什么的直接调用函数就行了。
USB接口模拟大容量存储设备
USB接口真的有好多用处啊,基本上是可以模拟出所有USB接口的设备了,之前有写过一篇USB实现虚拟串口CDC的文章,这次实现模拟大容量存储设备,前几天还模拟了一下HID人体学输入设备,后面把HID的文章补上。说一句,HID比CDC好用多了!
限于篇幅,这里直接贴上cubemx的配置过程,在后面HID的文章中再稍微讲讲USB是怎么让电脑识别为大容量存储设备的。
首先使能USB_OTG_FS,这里OTG是On-The-Go
的缩写,实现了在没有Host的情况下,设备间的数据传送。FS代表全速(Full Speed),另外还要一个选项是HS(High Speed),速度比全速更快,但是需要外部高速芯片的支持,比如加一个高速PHY,这里选FS就行。
然后配置为Mass Storage Class
,即MSC,大容量存储设备。上图中我其实还使能了FATS,但那是方便我通过单片机操作文件,这里模拟U盘用不到。
在Device Descriptor
中可以设置自己的设备名称,但影响不大,因为Windows文件管理器里面分配的盘符和名称跟这个没啥关系。
最后要把堆栈空间给大一点:
完成这些之后直接生成代码,编译,烧写,然后把开发板USB插电脑上,就可以直接识别为U盘了,不过因为还没跟SD卡对接起来,所以电脑会提示是否格式化,而且打不开。
USB与SD卡对接
这一步也是非常easy!打开usbd_storage_if.c
,修改以下几个函数就行:
/**
* @brief .
* @param lun: .
* @param block_num: .
* @param block_size: .
* @retval USBD_OK if all operations are OK else USBD_FAIL
*/
int8_t STORAGE_GetCapacity_FS(uint8_t lun, uint32_t *block_num, uint16_t *block_size)
{
/* USER CODE BEGIN 3 */
HAL_SD_CardInfoTypeDef SDCardInfo;
HAL_SD_GetCardInfo(&hsd, &SDCardInfo);
*block_num = SDCardInfo.BlockNbr;
*block_size = SDCardInfo.BlockSize;
return (USBD_OK);
/* USER CODE END 3 */
}
/**
* @brief .
* @param lun: .
* @retval USBD_OK if all operations are OK else USBD_FAIL
*/
int8_t STORAGE_IsReady_FS(uint8_t lun)
{
/* USER CODE BEGIN 4 */
if(HAL_SD_GetState(&hsd) == HAL_SD_STATE_READY)
{
return (USBD_OK);
}
else
{
return (USBD_FAIL);
}
/* USER CODE END 4 */
}
/**
* @brief .
* @param lun: .
* @retval USBD_OK if all operations are OK else USBD_FAIL
*/
int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
/* USER CODE BEGIN 6 */
if(HAL_SD_GetCardState(&hsd) == HAL_SD_CARD_TRANSFER)
{
if(HAL_SD_ReadBlocks(&hsd, buf, blk_addr, blk_len, SDMMC_DATATIMEOUT) == HAL_OK)
{
return (USBD_OK);
}
else
{
return (USBD_FAIL);
}
}
else
return (USBD_BUSY);
/* USER CODE END 6 */
}
/**
* @brief .
* @param lun: .
* @retval USBD_OK if all operations are OK else USBD_FAIL
*/
int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
/* USER CODE BEGIN 7 */
if(HAL_SD_GetCardState(&hsd) == HAL_SD_CARD_TRANSFER)
{
if(HAL_SD_WriteBlocks(&hsd, buf, blk_addr, blk_len, SDMMC_DATATIMEOUT) == HAL_OK)
{
return (USBD_OK);
}
else
{
return (USBD_FAIL);
}
}
else
return (USBD_BUSY);
/* USER CODE END 7 */
}
这里要注意,读写SD卡的函数不要用DMA方式或者IT方式,一定要用最普通的阻塞方式,不然U盘内容会加载失败。
效果
最后,我的“读卡器”成功了!
不过我试了一下U盘的写速度,很稳定的355KB/s,速度慢到出乎我的意料,可能是没有外部高速芯片支持的缘故吧,而且耗电量贼大。
我的电路板上用的5V转3.3V的芯片是LP5907,最大电流为500mA,但我频繁读写SD卡后这个芯片就发烫了,而且F4芯片也在发烫,差TF卡资料发现原来TF卡读写真的很费电:
居然可以达到500mA!我以为我这系统上耗电大户是摄像头和LCD,没想到竟然是SD卡,失策失策!
参考
👍