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	proc
	 push   {r4 - r11, lr}
	 ldr    rSDIO, =SDIO_BaseAddr
	 ldr	rCard_Info, =card_info_data
	 sub    sp, #4 * 2
	 ldrb	r4, card_isSDSC
	 lsl	r0, r4
	 str	r0, [sp, #0]
	 str	r1, [sp, #4]

; Select the Card.	 	 
	 mov	r0, #7:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMEN
	 ldr	r1, card_rca
	 bl		send_cmd
; Set the block size in case of SDSC.	 	 
	 mov	r0, #16:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMEN
	 mov    r1, #512	 	 
	 bl     send_cmd
	 
	 ldr	r4, [sp, #0] ;  The address of the block in the SD Memory Card
	 ldr	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_CPSMEN
	 mov    r1, r4
	 bl     send_cmd 	
	 
	 mov	r0, #0
	 str	r0, [rSDIO, #SDIO_DCTRL]
	 mov 	r0, #512
	 str	r0, [rSDIO, #SDIO_DLEN]
	 mov	r0, #(9 :shl: 4):or:SDIO_DCTRL_DTDIR_Card2Controller \
					:or: SDIO_DCTRL_Dten
	 str	r0, [rSDIO, #SDIO_DCTRL] 
	 
reading_data_start	 
	 ldr	r0, [rSDIO, #SDIO_STA]	
	 tst	r0, #SDIO_STA_RXACT
	 beq	reading_data_start
reading_data
	 ldr	r0, [rSDIO, #SDIO_STA]	
	 tst	r0, #SDIO_STA_DATAEND
	 bne	reading_clear_the_FIFO
	 tst	r0, #SDIO_STA_RXFIFOHF
	 beq	reading_data
	 ldr	r1, [rSDIO, #SDIO_FIFO]
	 str	r1, [r5]
	 add	r5, #4
	 b		reading_data
reading_clear_the_FIFO
	 ldr	r0, [rSDIO, #SDIO_STA]
	 tst	r0, #SDIO_STA_RXDAVL
	 beq	reading_completed
	 ldr	r1, [rSDIO, #SDIO_FIFO]
	 str	r1, [r5]
	 add	r5, #4
	 b		reading_clear_the_FIFO
reading_completed	
	 mov	r0, #0
	 str	r0, [rSDIO, #SDIO_DCTRL]
	 mov	r0, #0x7ff
	 str	r0, [rSDIO, #SDIO_ICR]
	 mov	r0, #7:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMEN
	 mov	r1, #0
	 bl		send_cmd
	 mov	r0, #13:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMEN
	 ldr	r1, card_rca
	 bl		send_cmd
	 ldr 	r0, [rSDIO, #SDIO_RESP1]
	 ubfx	r0, r0, #9, #4
	 add	sp, #4 * 2
	 pop    {r4 - r11, lr}
	 bx     lr
	 ltorg
     endp

4.3 write_block接口的实现

; uint32_t write_block(uint32_t, uint32_t*);
	 align	4
write_block	proc
	 push   {r4 - r11, lr}	
	 ldr    rSDIO, =SDIO_BaseAddr
	 ldr	rCard_Info, =card_info_data
	 ldrb	r4, card_isSDSC
	 lsl	r0, r4
	 sub	sp, #4 * 2
	 str	r0, [sp, #0]
	 str	r1, [sp, #4]
	 
	 mov	r0, #7:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMEN
	 ldr	r1, card_rca
	 bl		send_cmd
	 	 
	 mov	r0, #16:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMEN
	 mov    r1, #512	 	 
	 bl     send_cmd
	 
	 ldr	r4, [sp, #0] ;  The address of the block in the SD Memory Card
	 ldr	r5, [sp, #4] ;  The address of the buffer
	 mov	r6, #0;
	 
	 mov    r0, #24:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMEN
	 mov    r1, r4
	 bl     send_cmd 
	 
	 mov	r0, #0
	 str	r0, [rSDIO, #SDIO_DCTRL]
	 mov 	r0, #512
	 str	r0, [rSDIO, #SDIO_DLEN]
	 mov	r0, #(9:shl:4):or:SDIO_DCTRL_Dten
	 str	r0, [rSDIO, #SDIO_DCTRL]
writing_data_start
	 ldr	r0, [rSDIO, #SDIO_STA]
	 tst	r0, #SDIO_STA_TXACT
	 beq	writing_data_start
	 mov	r1, #SDIO_STA_DBCKEND:or:SDIO_STA_DCRCFAIL
writing_data
	 ldr	r0, [rSDIO, #SDIO_STA]
	 tst	r0, r1
	 bne	writing_completed
	 tst	r0, #SDIO_STA_TXFIFOE
	 beq	writing_data
	 ldr	r0, [r5]
	 str	r0, [rSDIO, #SDIO_FIFO]
	 add	r5, #4
	 add	r6, #1
	 b		writing_data
writing_completed
	 mov	r0, #0
	 str	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_CPSMEN
	 ldr    r1, card_rca	 	 
	 bl     send_cmd
	 ldr	r0, [rSDIO, #SDIO_RESP1]
	 ubfx	r1, r0, #9, #4
	 cmp	r1, #7
	 beq	write_block_the_card_is_programming
	 
	 mov	r0, #0x7ff
	 str	r0, [rSDIO, #SDIO_ICR]
	 	 
	 mov    r0, #13:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMEN
	 ldr    r1, card_rca	 	 
	 bl     send_cmd
	 ldr	r0, [rSDIO, #SDIO_RESP1]
	 
	 add	sp, #4 * 2
	 pop    {r4 - r11, lr}
	 bx		lr
	 endp

4.4 erase_block接口的实现

; uint32_t erase_block(uint32_t, uint32_t);		 
; r0: Start block
; r1: End block
     align  4
erase_block proc
	 push   {r4 - r11, lr}
	 ldr    rSDIO, =SDIO_BaseAddr
	 ldr	rCard_Info, =card_info_data
	 sub	sp, #4 * 2
	 ldrb	r4, card_isSDSC
	 lsl	r0, r4
	 lsl	r1, r4
	 str	r0, [sp, #0]; [sp, #0] is the start block 
	 str	r1, [sp, #4]; [sp, #4] is the end block
	 
	 mov	r0, #7:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMEN
	 ldr	r1, card_rca
	 bl		send_cmd 
	 mov	r0, #13:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMEN
	 ldr	r1, card_rca
	 bl		send_cmd
	 
	 mov	r0, #32:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMEN
	 ldr	r1, [sp, #0];
	 bl	 	send_cmd
	 mov	r0, #33:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMEN
	 ldr	r1, [sp, #4];
	 bl	 	send_cmd
	 mov	r0, #38:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMEN
	 mov	r1, #0
	 bl	 	send_cmd

erase_block_the_card_is_programming
	 mov    r0, #13:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMEN
	 ldr    r1, card_rca	 	 
	 bl     send_cmd
	 ldr	r0, [rSDIO, #SDIO_RESP1]
	 ubfx	r1, r0, #9, #4
	 cmp	r1, #7
	 beq	erase_block_the_card_is_programming
	 
	 mov	r0, #7:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMEN
	 ldr	r1, card_rca
	 bl		send_cmd 
	 
	 mov	r0, #13:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMEN
	 ldr	r1, card_rca
	 bl		send_cmd
	 ldr 	r0, [rSDIO, #SDIO_RESP1]
	 ubfx	r0, r0, #9, #4
	 
	 add	sp, #4 * 2
	 pop    {r4 - r11, lr}
	 bx     lr
	 ltorg
     endp

4.5 send_cmd内部函数

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

; 	 Priviate Function Name: Send_cmd
;	 Args:  r0 - cmd, r1 - arg
;	 实现这个函数

	 align  4		 
send_cmd	proc
	 push   {r4 - r11, lr}
	 ldr    rSDIO, =SDIO_BaseAddr
	 ldr    rCard_Info, =card_info_data
	 mov    r2, #0x7f
	 str    r2, [rSDIO, #SDIO_ICR]
	 str    r1, [rSDIO, #SDIO_ARG]
	 str    r0, [rSDIO, #SDIO_CMD]
wait_for_response
	 ldr    r1, [rSDIO, #SDIO_STA]
	 tst    r1, #SDIO_STA_CMDREND:or:SDIO_STA_CCRCFAIL:or:SDIO_STA_CTIMEOUT
	 beq    wait_for_response
	 bic	r0, #SDIO_CMD_CPSMEN
	 str    r0, [rSDIO, #SDIO_CMD]
	 pop    {r4 - r11, lr}	
	 bx     lr
	 endp

五、测试与结论

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 id
 
void SDIO_Testcase (void *argument);                   // thread function
 
int 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内存卡的驱动。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

跟TED演讲学英文:What moral decisions should driverless cars make by Iyad Rahwan

What moral decisions should driverless cars make? Link: https://www.ted.com/talks/iyad_rahwan_what_moral_decisions_should_driverless_cars_make Speaker: Iyad Rahwan Date: September 2016 文章目录 What moral decisions should driverless cars make?Introduct…

【笔试训练】day20

1.经此一役小红所向无敌 默认小红血量无限。直接计算出经过几轮攻击后,会出现人员伤亡。 对于对立来说他最多承受n轮光的攻击,对于光来说,他最多承受立得m轮攻击。 所以在经过min(n,m)轮回合之后,他们两个人至少死一个。活下来的…

已解决Error: Could Not Find a Version That Satisfies the Requirement XXX

博主猫头虎的技术世界 🌟 欢迎来到猫头虎的博客 — 探索技术的无限可能! 专栏链接: 🔗 精选专栏: 《面试题大全》 — 面试准备的宝典!《IDEA开发秘籍》 — 提升你的IDEA技能!《100天精通鸿蒙》 …

大数据面试题(十):Hive的高频面试考点(二)

文章目录 Hive的高频面试考点 一、请说明Hive中 sort by ,order by ,cluster by ,distribute by各代表什么意思

Java多线程优化接口响应

同步查询 Override public MallOrder getById1(Long id) {long startTime System.currentTimeMillis();MallOrder mallOrder new MallOrder();mallOrder.setId(1L);mallOrder.setShopId(3L);mallOrder.setCustomerId(78L);mallOrder.setGoodsId(664L);mallOrder.setOrderTime…

java基础07(二维数组 方法)

目录 一. 二维数组 1. 声明 2. 初始化 3. 取值 赋值 4. 遍历 5. 一些细节 二. 方法 1. 方法的定义 1.1 无返回值方法 1.2 有返回值方法 2. 方法的调用 3. 动态参数 4. Overload 方法重载 一. 二维数组 二维数组的本质其实就是一维数组,只不过每个元素又是…

PCB光控打孔机第二版程序(一)

/*PCB机程序 XY同时启动 L9751 CODE61068 2018 6 19 08:00 固定位置释放吸盘*/ /*修正寻点第十二条结束调用计算坐标L5091,自动运行Y计算L6280 6281***/ /*** 开外部中断2关闭定时器2XY轴输出信号,自动运行循环检测外部中断高电平重启XY轴输出信号 增加寻…

node安装

1. node.js是用来干什么的? 简单来说,Node.js 是一个多功能的 JavaScript 运行环境,就像jdk是java的运行环境一样,不过node还提供了类似于tomcat一样的服务器功能,可以像后端一样运行起来拥有单独的地址和端口。 1.1…

Skywalking的重要功能详解

学习本篇文章之前首先要了解一下Sky walking的基础知识 分布式链路追踪工具Sky walking详解 一&#xff0c;Sky walking监控数据库 在admin服务中&#xff0c;连接数据库查询user表中所有数据 引入依赖 <dependency><groupId>mysql</groupId><artifactI…

Redis高级(Redis持久化,Redis主从模式,Redis哨兵模式,Redis分片集群)

目录 一、单机Redis 1. 问题说明 2. 安装Redis 1 解压安装Redis【备用】 2 配置Redis 3 启动Redis 3. 小结 二、Redis持久化 1. 持久化机制介绍 2. RDB模式 3. AOF模式 4. RDB和AOF对比 5. 小结 三、Redis主从模式 1. 介绍 2. 搭建Redis主从架构【备用】 3. 主…

软件测试与管理:黑盒测试-判定表驱动法

知识思维导图&#xff1a; 例题1&#xff1a;运用判定表驱动法设计测试用例。 某学生成绩管理系统&#xff0c;要求对“平均成绩在90分以上&#xff0c;且没有不及格科目的学生&#xff0c;或班级成绩排名在前5的学生&#xff0c;在程序中将学生的姓名用红色标识”&#xff0c;…

【前端】HTML实现个人简历信息展示页面

文章目录 前言一、 综合案例&#xff1a;个人简历信息展示页面 前言 这篇博客仅仅是对HTML的基本结构进行了一些说明&#xff0c;关于HTML的更多讲解以及CSS、Javascript部分的讲解可以关注一下下面的专栏&#xff0c;会持续更新的。 链接&#xff1a; Web前端学习专栏 下面我…

Python | Leetcode Python题解之第73题矩阵置零

题目&#xff1a; 题解&#xff1a; class Solution:def setZeroes(self, matrix: List[List[int]]) -> None:m, n len(matrix), len(matrix[0])flag_col0 Falsefor i in range(m):if matrix[i][0] 0:flag_col0 Truefor j in range(1, n):if matrix[i][j] 0:matrix[i]…

实时音视频通信的主要矛盾及解决方法

实时音视频通信的主要矛盾及解决方法 实时音视频通信的主要矛盾及解决方法实时音视频通信的主要矛盾矛盾的解决方法增加带宽减少数据量适当增加延时提高网络质量快速准确地评估带宽 总结参考 实时音视频通信的主要矛盾及解决方法 实时音视频通信的主要矛盾 实时音视频通信的主…

工厂模式+策略模式完成多种登录模式的实现

前提 &#xff08;简单工厂不属于设计模式&#xff0c;而是一种编程思想【抽象一层出来】&#xff09;工厂方法模式、抽象工厂模式 以上都是为了解耦&#xff0c;如果考虑多个纬度&#xff08;如需要同时考虑多种电器&#xff0c;多种品牌&#xff09;则优先考虑抽象工厂。 …

公网tcp转流

之前做过几次公网推流的尝试, 今天试了UDP推到公网, 再用TCP从公网拉下来, 发现不行, 就直接改用TCP转TCP了. 中间中转使用的python脚本, 感谢GPT提供技术支持: import socket import threadingdef tcp_receiver(port, forward_queue):"""接收TCP数据并将其放入…

Liunx磁盘管理(下)

中篇&#xff1a;https://blog.csdn.net/Lzcsfg/article/details/138355036 一.逻辑卷 逻辑卷&#xff08;Logical Volume&#xff09;是逻辑卷管理 (LVM) 中的一个概念&#xff0c;它为 Linux 系统中的存储管理提供了更大的灵活性和可扩展性。LVM 允许你将物理存储设备&…

用js代码实现贪吃蛇小游戏

js已经学了大部分了&#xff0c;现在就利用我所学的js知识试试做贪吃蛇小游戏吧 以下部分相关图片以及思路笔记均出自渡一陈老师的视频 首先制作简单的静态页面&#xff0c;添加贪吃蛇移动的背景和相关图片&#xff0c;比如开始游戏等等 将各个功能均封装在函数中&#xff0…

multipass launch失败:Could not generate a new UUID vboxmanage添加环境变量path

C:\WINDOWS\system32>multipass launch [2024-05-06T15:48:54.320] [error] [relished-jerboa] Could not unregister VM: Process failed to start: 系统找不到指定的文件。 launch failed: Could not generate a new UUID: Process failed to start: 系统找不到指定的文件…

服务攻防-数据库安全RedisCouchDBH2database未授权访问CVE漏洞

#知识点&#xff1a; 1、数据库-Redis-未授权RCE&CVE 2、数据库-Couchdb-未授权RCE&CVE 3、数据库-H2database-未授权RCE&CVE#章节点&#xff1a; 1、目标判断-端口扫描&组合判断&信息来源 2、安全问题-配置不当&CVE漏洞&弱口令爆破 3、复现对象-数…