KEIL 5.38的ARM-CM3/4 ARM汇编设计学习笔记13 - STM32的SDIO学习5 - 卡的轮询读写擦

KEIL 5.38的ARM-CM3/4 ARM汇编设计学习笔记13 - STM32的SDIO学习5 - 卡的轮询读写擦

  • 一、前情提要
  • 二、目标
  • 三、技术方案
    • 3.1 读写擦的操作
      • 3.1.1 读卡操作
      • 3.1.2 写卡操作
      • 3.1.3 擦除操作
    • 3.2 一些技术点
      • 3.2.1 轮询标志位的选择不唯一
      • 3.2.2 写和擦的卡状态查询
      • 3.2.3 写的速度
  • 四、代码实现
    • 4.1 接口定义
    • 4.2 `read_block`接口的实现
    • 4.3 `write_block`接口的实现
    • 4.4 `erase_block`接口的实现
    • 4.5 `send_cmd`内部函数
  • 五、测试与结论
    • 5.1 测试用例
    • 5.2 运行结果
    • 5.3 其他测试结果
  • 六、总结

一、前情提要

在上一篇提到了要实现SDIO内存卡的读写擦,但是由于程序在调试的时候出现了一些bug,所以一直没有把这个坑填上。最近由于做了一些测试,把读写擦实现了。所以特此来把这个坑填上。

二、目标

  1. 实现读写擦的函数。
  2. 编写测试用例,将一个块擦除,写入内容,再读出来。

三、技术方案

3.1 读写擦的操作

读写擦的具体的指令其实很多帖子都有介绍,笔者就是参考的手册本身。但是具体的流程还是要说一下。

3.1.1 读卡操作

  1. 设置SDIO_DLEN和SDIO_DCTRL两个寄存器。在SDIO_DLEN设置块大小,一般是512字节;在SDIO_DCTRL里设置块大小是9(代表512)、数据传输方向是卡到MCU,暂不启动。必要的话CMD16设置卡的块大小。
  2. CMD7+RCA选中卡。
  3. 置位SDIO_DCTRL的Dten位,使能MCU的传输。
  4. CMD17+块地址要求卡发送数据
  5. 轮询SDIO_STA的SDIO_STA_RXFIFOHF位看看有没有数据到位;轮询SDIO_STA的SDIO_STA_DATAEND位检查卡是否已经发送完成。
  6. 轮询SDIO_STA的SDIO_STA_RXDAVL把管子里的数据都收拾出来。
  7. 通过复位SDIO_DCTRL的Dten位以关闭DPSM。
  8. 通过SDIO_ICR清了SDIO_STA。
  9. 收工

3.1.2 写卡操作

  1. 设置SDIO_DLEN和SDIO_DCTRL两个寄存器。在SDIO_DLEN设置块大小,一般是512字节;在SDIO_DCTRL里设置块大小是9(代表512)、数据传输方向是MCU到卡,暂不启动。必要的话CMD16设置卡的块大小。
  2. CMD7+RCA选中卡。
  3. 置位SDIO_DCTRL的Dten位,使能MCU的传输。
  4. CMD24+块地址通知卡MCU将要发送数据
  5. 轮询SDIO_STA的SDIO_STA_TXFIFOHE位看看是否管子里有空间发数据;轮询SDIO_STA的SDIO_STA_DATAEND位检查MCU是否已经发送完成。
  6. 轮询SDIO_STA的SDIO_STA_DBCKEND直至发送结束
  7. 通过复位SDIO_DCTRL的Dten位以关闭DPSM。
  8. CMD13轮询卡的状态。直至状态离开PROG状态。
  9. 收工

3.1.3 擦除操作

  1. CMD7+RCA选中卡。
  2. CMD32设置起始块、CMD33设置终止块和CMD38执行擦除。
  3. CMD13轮询卡的状态。直至离开PROG状态。
  4. 收工

3.2 一些技术点

3.2.1 轮询标志位的选择不唯一

由于没有采用DMA,所以读写的时候都必须手动轮询SDIO_STA的某些标志位来保证读写操作的顺利完成。但是参考手册会发现对于读写操作并没有规定操作规范。有的时候对于同一个目的可以有多个标志位可以使用。这里确实是有多个标志位可以采用。但是要通过测试去验证。

3.2.2 写和擦的卡状态查询

卡在执行写和擦的操作时候会处于PROG状态。这个时候必须要轮询至状态转移才可以保证操作的成功。

3.2.3 写的速度

按照卡的SDIO_STATUS,很多时候卡的速度都是24MBit/s或50MBit/s,但是在实际操作的时候会发现速度似乎只能开到6.7MBit/s左右,不论是单线模式还是4线模式都不行。看时钟信号发现是非常连续的,所以排除了发送数据的时候有延迟的原因。这个问题目前没有解决,如果未来找到了原因再记录。
请添加图片描述
从上面的这个图中可以看到,时钟信号SDIO_CLK(红色)其实是非常连贯的。但是频率只能达到6.8,也就是5+2分频。所以笔者认为其实换成DMA传输也不太可能改善这个。但是未来如果有机会试试再测试吧。

四、代码实现

4.1 接口定义

SDIO内存卡的接口定义如下所示:

#ifndef _SDIO_Memory_CARD_H_
#define _SDIO_Memory_CARD_H_#include "stdint.h"
typedef enum {waitRsp_noRsp     = 0,waitRsp_shortRsp = 1,waitRsp_longRsp  = 3,
}WaitRspKind;typedef struct {void  (*init)(void);uint32_t (*card_identification)(void);uint32_t (*read_SD_status)(void);uint32_t (*erase_block)(uint32_t, uint32_t);uint32_t (*read_block)(uint32_t, uint32_t*);uint32_t (*write_block)(uint32_t, uint32_t*);
}SDIO_Memory_Card_Def;extern const SDIO_Memory_Card_Def SDIO_Memory_Card;
#endif

添加了3个函数接口,分别是

	uint32_t (*erase_block)(uint32_t, uint32_t);uint32_t (*read_block)(uint32_t, uint32_t*);uint32_t (*write_block)(uint32_t, uint32_t*);

这三个接口的实现如下所示。但是由于前面说了逻辑,具体的每行的解释这里就不说了。

4.2 read_block接口的实现

; uint32_t read_block(uint32_t, uint32_t*);
; r0 is the address of the block,
; r1 is the read buffer.align  4
read_block	procpush   {r4 - r11, lr}ldr    rSDIO, =SDIO_BaseAddrldr	rCard_Info, =card_info_datasub    sp, #4 * 2ldrb	r4, card_isSDSClsl	r0, r4str	r0, [sp, #0]str	r1, [sp, #4]; Select the Card.	 	 mov	r0, #7:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMENldr	r1, card_rcabl		send_cmd
; Set the block size in case of SDSC.	 	 mov	r0, #16:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMENmov    r1, #512	 	 bl     send_cmdldr	r4, [sp, #0] ;  The address of the block in the SD Memory Cardldr	r5, [sp, #4] ;  The address of the buffer	 
; Send CMD17 to inform the card to start a data sending.mov    r0, #17:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMENmov    r1, r4bl     send_cmd 	mov	r0, #0str	r0, [rSDIO, #SDIO_DCTRL]mov 	r0, #512str	r0, [rSDIO, #SDIO_DLEN]mov	r0, #(9 :shl: 4):or:SDIO_DCTRL_DTDIR_Card2Controller \:or: SDIO_DCTRL_Dtenstr	r0, [rSDIO, #SDIO_DCTRL] reading_data_start	 ldr	r0, [rSDIO, #SDIO_STA]	tst	r0, #SDIO_STA_RXACTbeq	reading_data_start
reading_dataldr	r0, [rSDIO, #SDIO_STA]	tst	r0, #SDIO_STA_DATAENDbne	reading_clear_the_FIFOtst	r0, #SDIO_STA_RXFIFOHFbeq	reading_dataldr	r1, [rSDIO, #SDIO_FIFO]str	r1, [r5]add	r5, #4b		reading_data
reading_clear_the_FIFOldr	r0, [rSDIO, #SDIO_STA]tst	r0, #SDIO_STA_RXDAVLbeq	reading_completedldr	r1, [rSDIO, #SDIO_FIFO]str	r1, [r5]add	r5, #4b		reading_clear_the_FIFO
reading_completed	mov	r0, #0str	r0, [rSDIO, #SDIO_DCTRL]mov	r0, #0x7ffstr	r0, [rSDIO, #SDIO_ICR]mov	r0, #7:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMENmov	r1, #0bl		send_cmdmov	r0, #13:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMENldr	r1, card_rcabl		send_cmdldr 	r0, [rSDIO, #SDIO_RESP1]ubfx	r0, r0, #9, #4add	sp, #4 * 2pop    {r4 - r11, lr}bx     lrltorgendp

4.3 write_block接口的实现

; uint32_t write_block(uint32_t, uint32_t*);align	4
write_block	procpush   {r4 - r11, lr}	ldr    rSDIO, =SDIO_BaseAddrldr	rCard_Info, =card_info_dataldrb	r4, card_isSDSClsl	r0, r4sub	sp, #4 * 2str	r0, [sp, #0]str	r1, [sp, #4]mov	r0, #7:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMENldr	r1, card_rcabl		send_cmdmov	r0, #16:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMENmov    r1, #512	 	 bl     send_cmdldr	r4, [sp, #0] ;  The address of the block in the SD Memory Cardldr	r5, [sp, #4] ;  The address of the buffermov	r6, #0;mov    r0, #24:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMENmov    r1, r4bl     send_cmd mov	r0, #0str	r0, [rSDIO, #SDIO_DCTRL]mov 	r0, #512str	r0, [rSDIO, #SDIO_DLEN]mov	r0, #(9:shl:4):or:SDIO_DCTRL_Dtenstr	r0, [rSDIO, #SDIO_DCTRL]
writing_data_startldr	r0, [rSDIO, #SDIO_STA]tst	r0, #SDIO_STA_TXACTbeq	writing_data_startmov	r1, #SDIO_STA_DBCKEND:or:SDIO_STA_DCRCFAIL
writing_dataldr	r0, [rSDIO, #SDIO_STA]tst	r0, r1bne	writing_completedtst	r0, #SDIO_STA_TXFIFOEbeq	writing_dataldr	r0, [r5]str	r0, [rSDIO, #SDIO_FIFO]add	r5, #4add	r6, #1b		writing_data
writing_completedmov	r0, #0str	r0, [rSDIO, #SDIO_DCTRL]
;	 mov    r0, #12:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMEN
;	 ldr    r1, card_rca	 	 
;	 bl     send_cmd
write_block_the_card_is_programming	 mov    r0, #13:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMENldr    r1, card_rca	 	 bl     send_cmdldr	r0, [rSDIO, #SDIO_RESP1]ubfx	r1, r0, #9, #4cmp	r1, #7beq	write_block_the_card_is_programmingmov	r0, #0x7ffstr	r0, [rSDIO, #SDIO_ICR]mov    r0, #13:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMENldr    r1, card_rca	 	 bl     send_cmdldr	r0, [rSDIO, #SDIO_RESP1]add	sp, #4 * 2pop    {r4 - r11, lr}bx		lrendp

4.4 erase_block接口的实现

; uint32_t erase_block(uint32_t, uint32_t);		 
; r0: Start block
; r1: End blockalign  4
erase_block procpush   {r4 - r11, lr}ldr    rSDIO, =SDIO_BaseAddrldr	rCard_Info, =card_info_datasub	sp, #4 * 2ldrb	r4, card_isSDSClsl	r0, r4lsl	r1, r4str	r0, [sp, #0]; [sp, #0] is the start block str	r1, [sp, #4]; [sp, #4] is the end blockmov	r0, #7:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMENldr	r1, card_rcabl		send_cmd mov	r0, #13:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMENldr	r1, card_rcabl		send_cmdmov	r0, #32:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMENldr	r1, [sp, #0];bl	 	send_cmdmov	r0, #33:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMENldr	r1, [sp, #4];bl	 	send_cmdmov	r0, #38:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMENmov	r1, #0bl	 	send_cmderase_block_the_card_is_programmingmov    r0, #13:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMENldr    r1, card_rca	 	 bl     send_cmdldr	r0, [rSDIO, #SDIO_RESP1]ubfx	r1, r0, #9, #4cmp	r1, #7beq	erase_block_the_card_is_programmingmov	r0, #7:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMENldr	r1, card_rcabl		send_cmd mov	r0, #13:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMENldr	r1, card_rcabl		send_cmdldr 	r0, [rSDIO, #SDIO_RESP1]ubfx	r0, r0, #9, #4add	sp, #4 * 2pop    {r4 - r11, lr}bx     lrltorgendp

4.5 send_cmd内部函数

虽然前面的几个帖子中也讲到了这个内部函数的实现。但是为了方便阅读,这里还是把它粘过来了。

; 	 Priviate Function Name: Send_cmd
;	 Args:  r0 - cmd, r1 - arg
;	 实现这个函数align  4		 
send_cmd	procpush   {r4 - r11, lr}ldr    rSDIO, =SDIO_BaseAddrldr    rCard_Info, =card_info_datamov    r2, #0x7fstr    r2, [rSDIO, #SDIO_ICR]str    r1, [rSDIO, #SDIO_ARG]str    r0, [rSDIO, #SDIO_CMD]
wait_for_responseldr    r1, [rSDIO, #SDIO_STA]tst    r1, #SDIO_STA_CMDREND:or:SDIO_STA_CCRCFAIL:or:SDIO_STA_CTIMEOUTbeq    wait_for_responsebic	r0, #SDIO_CMD_CPSMENstr    r0, [rSDIO, #SDIO_CMD]pop    {r4 - r11, lr}	bx     lrendp

五、测试与结论

5.1 测试用例

#include "cmsis_os2.h"                          // CMSIS RTOS header file
#include "SDIO_TestCase.h"
#include "SDIO_Memory_Card.h"
#include "stdio.h"
/*----------------------------------------------------------------------------*      Thread 1 'Thread_Name': Sample thread*---------------------------------------------------------------------------*/static osThreadId_t tid_SDIO_Testcase;                        // thread idvoid SDIO_Testcase (void *argument);                   // thread functionint Init_SDIO_Testcase (void) {tid_SDIO_Testcase = osThreadNew(SDIO_Testcase, NULL, NULL);if (tid_SDIO_Testcase == NULL) {return(-1);}return(0);
}__NO_RETURN void SDIO_Testcase (void *argument) {static uint32_t resp = 0;static union{uint32_t buf32[512 / 4];char buf8[512];}rBuf, wBuf;(void)argument;sprintf(wBuf.buf8, "I love Miao! I love you, Da Miao");SDIO_Memory_Card.card_identification();SDIO_Memory_Card.read_SD_status();//	SDIO_Memory_Card.erase_block(0,0);SDIO_Memory_Card.read_block(0, rBuf.buf32);SDIO_Memory_Card.erase_block(10,15);SDIO_Memory_Card.read_block(10, rBuf.buf32);SDIO_Memory_Card.write_block(11, wBuf.buf32);SDIO_Memory_Card.read_block(11, rBuf.buf32);while (1) {resp = (resp + 1)%100;osDelay(101);}
}

5.2 运行结果

在这里插入图片描述

可以看到,笔者成功地向第11块中写入了一行英文,“I love you, Da Miao, Kitty and Andy!”。

5.3 其他测试结果

对于这种SDIO内存卡,用单线还是四线数据总线模式其实都是成立的。只要MCU和卡的设置都协调好就可以了。

我把程序换到了另一个pin都引出来的板子上,把波形打出来。请添加图片描述
单线模式下的波形。红线是SDIO_CLK,黄线是D0。也许有人会认为,这不就是个高速的I2C么。其实不是的。会看到,每一帧都没有ACK和NACK。所以不能替代I2C。

请添加图片描述

四线模式下的波形。红线是SDIO_CLK,其他是D0、D1和D2。由于这个示波器是借的,没有配数字探头,所以看不全所有的信号。

但是从调试上可以看到都能实现操作。
在这里插入图片描述

这里注明一下,因为HX32F4的开发板没有将SDIO有关的引脚引出,所以无法测量。我用另一个板子做了测试,但是用的IDE是Segger Embedded Studio做的,也就是上面的这个界面。

六、总结

这样,用轮询的方式实现读写擦SD卡的驱动就实现了。有若干的技术点:

  1. 读的速率可以根据卡的额定速度来,但是写入的速度不能高于6.8MBit/s。
  2. 写入和擦除之后要轮询卡的状态,确认卡已经从PROG状态中转出。
  3. 读写擦的轮询的标志位其实可以有多个选择。但是要测试确认。
  4. 管子的数据是32位的,但是发送的是按照8位的。所以可以认为是一次发4个字节。读写缓冲区都必须是字对齐(4字节对齐)。
  5. 要查询SDIO_STATUS,根据版本号确认如何读写。这里还是点一下,2GB以下的卡的寻址是以字节的,而以上的都是以块寻址的。当然,读写的时候都要以块为单位。比如,1GB的卡以字节寻址到第10块,但是还是要一次读1个整块。除非中途用CMD12打断。

这样就可以实现一套SDIO内存卡的驱动。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/320734.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unity之ShaderGraph入门简介与配置

前言 ShaderGraph是Unity的一个可视化着色器编辑工具,它允许开发者在不编写代码的情况下创建复杂的着色器效果。ShaderGraph提供了一个直观的图形界面,用户可以通过拖拽节点并连接它们来构建自定义的着色器。用户可以在ShaderGraph中使用各种节点,如数学运算、纹理采样、颜…

SeetaFace6人脸检测C++代码实现Demo

SeetaFace6包含人脸识别的基本能力:人脸检测、关键点定位、人脸识别,同时增加了活体检测、质量评估、年龄性别估计,并且顺应实际应用需求,开放口罩检测以及口罩佩戴场景下的人脸识别模型。 官网地址:https://github.co…

【漏洞复现】用友时空KSOA linkadd接口处存在 SQL注入漏洞

免责声明:文章来源互联网收集整理,请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失,均由使用者本人负责,所产生的一切不良后果与文章作者无关。该…

2024高校网络安全管理运维赛wp

文章目录 misc签到钓鱼邮件识别easyshellSecretDBGatewayzipApachef for r webphpsqlMessy Mongo misc 签到 钓鱼邮件识别 两部分解base64,各一个flag 后面没有什么地方有有用信息了,根据题目钓鱼邮件,可能第三段flag就跟DMARC、DKIM 和 SP…

母婴店运用商城小程序店铺的效果是什么

母婴市场规模高,还可与不少行业无缝衔接,尤其是以90后、00后为主的年轻人,在备孕生育和婴儿护理前后等整体流程往往不惜重金且时间长,母婴用品无疑是必需品,商家需要多方面拓展全面的客户及打通场景随时消费路径。 运…

视频号好物分享副业课,视频剪辑带货玩法(12节课)

详情介绍 课程内容: 第1节-为什么要做视频号好物分享.mp4 第2节-Tok海外素材好物分享号的变现逻辑.mp4 第3节-好物分享的细分赛道.mp4 第4节-视频号使用老号还是新号,mp4 第5节-开通橱窗的条件与挂车条件.mp4 第6节-好物分享账号的搭建设置,mp4 第7节-手机版…

数据结构——图的基础知识与其表示

一:定义 由顶点的集合和边的集合组成;常以 G(V,E) 表示,G 代表图,V代表 顶点的集合,E代表边的集合; 如图: 在G1图中,有 0~4 五个顶点,有 0-1,0-2&…

【LeetCode刷题记录】105. 从前序与中序遍历序列构造二叉树 106. 从中序与后序遍历序列构造二叉树

105 从前序与中序遍历序列构造二叉树 给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。 示例 1: 输入: preorder [3,9,20,15,7], inorder [9,3,1…

Java转Kotlin

Kotlin 是一种静态编程语言 2011JetBrains开始开发Kotlin,用于多平台应用(能脱离虚拟机,直接编译成可以在win,mac,linux运行的二进制代码) 2017获得谷歌官方支持 语法简洁(减少了大量的样板代码,语法糖&…

远程代码/命令执行(RCE)

远程代码执行/远程命令执行(remote/code/execute||remote/command/execute) 类似sql注入xss等漏洞,rce也是代码注入(用户可控),注入对象为操作系统命令、后端代码,用户参 数可控,且未…

jmeter后置处理器提取到的参数因为换行符导致json解析错误

现象: {"message":"JSON parse error: Illegal unquoted character ((CTRL-CHAR, code 10)): has to be escaped using backslash to be included in string value; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Ill…

hadoop学习---基于Hive的数仓搭建增量信息拉链表的实现

拉链表就是SCD2,它的优点是即满足了反应数据的历史状态,又能在最大程度上节省存储。 拉链表的实现需要在原始字段基础上增加两个新字段: start_time(表示该条记录的生命周期开始时间——周期快照时的状态)end_time(该条记录的生命周期结束时…

【Node.js工程师养成计划】之express中间件与接口规范

一、Express中间件的概念与基本应用 const express require(express)// 加一个注释,用以说明,本项目代码可以任意定制更改 const app express()const PORT process.env.PORT || 3000// // 挂载路由 // app.use(/api, router)// // 挂载统一处理服务端…

【CTF Web】XCTF GFSJ0475 get_post Writeup(HTTP协议+GET请求+POST请求)

get_post X老师告诉小宁同学HTTP通常使用两种请求方法,你知道是哪两种吗? 解法 用 Postman 发送一个 GET 请求,提交一个名为a,值为1的变量。 http://61.147.171.105:65402/?a1用 Postman 发送一个 POST 请求,提交一个名为b,值为…

C++ | Leetcode C++题解之第60题排列序列

题目&#xff1a; 题解&#xff1a; class Solution { public:string getPermutation(int n, int k) {vector<int> factorial(n);factorial[0] 1;for (int i 1; i < n; i) {factorial[i] factorial[i - 1] * i;}--k;string ans;vector<int> valid(n 1, 1);…

二叉树的中序遍历

目录 一、前言 二、中序遍历 三、递归 四、迭代 一、前言 本篇文章主要讲解二叉树的中序遍历&#xff0c;对前序遍历、后序遍历不熟悉的同学可以观看本专栏。 二、中序遍历 简单来说&#xff0c;前序遍历的遍历思想就是&#xff1a; 左子树 --->根结点 ---> 右子树。…

车牌号识别系统:PyQT5+QT Designe+crnn/PaddleOCR+YOLO+OpenCV矫正算法。

PyQT5&QT Designecrnn/PaddleOCRYOLO传统OpenCV矫正算法。可视化的车牌识别系统项目。 车牌号识别系统 项目绪论1.项目展示2.视频展示3.整体思路 一、PyQT5 和 QT Designer1.简介2.安装3.使用 二、YOLO检测算法三、OpenCV矫正算法四、crnn/PaddleOCR字符识别算法五、QT界面…

已解决 RuntimeError: No CUDA GPUs are available 亲测有效!!!

已解决 RuntimeError: No CUDA GPUs are available 亲测有效&#xff01;&#xff01;&#xff01; 亲测有效 报错问题解决思路解决方法 报错问题 RuntimeError: No CUDA GPUs are available 这个错误通常发生在尝试在没有CUDA支持的GPU或没有安装NVIDIA GPU的机器上运行基于C…

[Flutter]创建一个私有包并使用

在Flutter中创建一个自己的私有组件&#xff08;通常称为包或库&#xff09;&#xff0c;并通过Dart的包管理工具pub进行使用。 一、创建一个新的Flutter包 1.使用命令行创建 使用Flutter命令行工具来创建一个新的包&#xff1a; $ flutter create --templatepackage my_pri…

Make3D数据集相关介绍

一、参考资料 Make3d数据集使用方法 二、相关介绍 1. 简介 Make3D 数据集的每帧图像的深度值均由激光雷达进行采集&#xff0c;相较于 Kinect 相机采集的深度信息&#xff0c;该测距仪可以得到室外图像更加精确的深度信息&#xff0c;而且测距范围更大&#xff0c;与普通的…