KEIL 5.38的ARM-CM3/4 ARM汇编设计学习笔记10 - STM32的SDIO学习2

news2025/2/27 16:17:59

KEIL 5.38的ARM-CM3/4 ARM汇编设计学习笔记10 - STM32的SDIO学习2

  • 一、问题回顾
  • 二、本次的任务
  • 三、 需要注意的问题
    • 3.1 Card Identification Mode时的时钟频率
    • 3.2 CMD0指令的疑似问题
    • 3.3 发送带参数的ACMD41时要注意时间时序和时效
    • 3.4 CPSM的指令发送问题
    • 3.5 调试过程中的SD卡的状态
  • 四、代码设计
  • 五、测试结果
  • 六、结论

一、问题回顾

根据上一篇中介绍的思路,我尝试调试了几次。笔者又发现了以下的问题:

问题原因解决
调试的时候如果一直插着卡,或者不将卡拔出而上电复位开发板再进入调试,会发现卡无法初始化开发板在上电的时候就会执行先前残留的程序。如果这部分程序中包含了初始化卡的代码,则会把卡初始化。当进入DEBUG后,卡已经处于DATA_TRANSFER状态,不再响应CMD41调试的时候就对卡进行重复插拔调试。或者先把里面的程序抹了再插卡进入调试
初始化命令序列,及CMD8->CMD41->CMD2->CMD3这个序列,用C语言发就好用,用汇编发就发生RESPx里面的数据无法用LDR语句读出不详。但是仿佛是CPSM在每次发完指令以后关闭一下就好了。可能要再研究一下CPSM的状态转换图。但是目前这个解决方案有效发送指令以后关闭CPSM

二、本次的任务

将所有的初始化卡的C代码用汇编实现并通过测试。

三、 需要注意的问题

3.1 Card Identification Mode时的时钟频率

在Card Identification Mode中,注意把频率先降下来到400kHz以内。参考《Physical Layer Simplified Specification》第67页

在这里插入图片描述《Physical Layer Simplified Specification》第67页

在进入了Data Transfer Mode以后,可以将时钟调到正常水平。参考《Physical Layer Simplified Specification》第76页

在这里插入图片描述《Physical Layer Simplified Specification》第76页

3.2 CMD0指令的疑似问题

用STM32F407发送CMD0的时候,明明SDIO_STA中已经提示了CMDSENT,但是可以确认的是,卡并没有初始化。但是由于笔者的示波器坏了,所以无法确认到底是指令没有发还是卡没有响应。所以我认为最好还是硬件上给卡的VDD引脚来个可控的设计。另外,上电复位以后,其实只要从CMD8开始往后操作就可以了。

3.3 发送带参数的ACMD41时要注意时间时序和时效

参考《Physical Layer Simplified Specification》第67页,发送ACMD41的时候你要么就一直在轮询发,要么就等一等。这里我采用的是轮询发。因为笔者在底层没有很好的延时理由。
在这里插入图片描述《Physical Layer Simplified Specification》第67页

这里简单说一下。在用汇编写驱动的时候不像在C的时候。只要有点风吹草动就可以怀疑是需要延时一下,加个HAL_Delay(ms)或者其他的什么函数延时一下就往往让程序跑通了。但是在汇编这里,所有的延时一般都是轮询某个标志位来的,都必须要有道理。比如这里,如果不发ACOM41,SD卡是不会在成功初始化后第一时间通知MCU的。所以就选择连续发送ACOM41的方法确认初始化完成状态。

3.4 CPSM的指令发送问题

很多资料都说,把CPSM一直开着,就发指令就好。但是所有的手册都没有体现这一点。笔者也发现,很多时候都是在C语言下好使,但是同样的逻辑用汇编做出来就会出现各种迷惑问题导致程序不能执行。这个跟前面说的时钟频率还真是没有什么关系。经过测试,笔者发现,每次发完指令都把这个CPSM关一下,这个问题就没了。所以笔者推断,这个CPSM状态机并不是希望你一直开着的。随用随开,用完就关。

3.5 调试过程中的SD卡的状态

在DEBUG的时候往往会把程序改好以后直接接入DEBUG,而忽略了卡目前可能处于的状态。根据《Physical Layer Simplified Specification》第50(76)页。已经被分配了RCA的卡不会响应识别指令,包括ACMD41,CMD2。所以DEBUG的时候,比如是先插卡后上电再调试的,还是调试了一次以后改了程序又调试的,其实卡可能一直处在被分配了RCA的状态,那么是不会响应识别指令的。
在这里插入图片描述《Physical Layer Simplified Specification》第50(76)页

四、代码设计

这里就不将peripherals.s里面的代码贴出了。其次,考虑到笔者操作的其实是memory card,不能算是combo card,所以将程序中的原来是combo card的名称改成memory card。

首先是修改了接口。取消了uint32_t (*send_cmd)(uint32_t cmdIndex, uint32_t arg, WaitRspKind waitRsp);方法,换成简单的void (*card_identification)(void);方法。

下面是SDIO_Memory_Card.h的源码

#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);
	void (*card_identification)(void);
}SDIO_Memory_Card_Def;

extern const SDIO_Memory_Card_Def SDIO_Memory_Card;
#endif

这个接口的实现文件是SDIO_Memory_Card.s。
在这个文件中单独把“发送命令”作为一个私有方法写出。因为如果不这么做,代码量很大,结构也会比较复杂。在这个方法中,每次发送完了命令都吧CPSM关掉。下次发的时候再打开。每个命令都由调用这个函数的的函数构造,send_cmd方法只是把把参数从r1装入SDIO_ARG命令从r0装入SDIO_CMD,

		get peripherals.s
	
rRCC   rn r8
rSDIO  rn r9
rGPIOC rn r10
rGPIOD rn r11

SDIO_GPIO_SPEED	equ	GPIOx_OSPEEDR_VERYHIGH
	 
	 area card_data_area, data
	 align 4 
rca	 space 4		 
	
	
	 area text, code
	 align 4
init proc
	 push {r4 - r11, lr}
	 ldr  r8, =RCC_BaseAddr
	 ldr  r0, [rRCC, #RCC_APB2ENR]
	 orr  r0, #RCC_APB2ENR_SDIOEN
	 str  r0, [rRCC, #RCC_APB2ENR]
	 ldr  r0, [rRCC, #RCC_AHB1ENR]
	 orr  r0, #RCC_AHB1ENR_GPIOCEN :or: RCC_AHB1ENR_GPIODEN
	 str  r0, [rRCC, #RCC_AHB1ENR]
	 ; CLK  	:  PC12
	 ; CMD  	:  PD2
	 ; DAT_0	:  PC8
	 ; DAT_1	:  PC9
	 ; DAT_2	:  PC10
	 ; DAT_3/CD	:  PC11
	 ;
	 ldr  rGPIOC, =GPIOC_BaseAddr
	 ldr  r0, [rGPIOC, #GPIOx_MODER]
	 bic  r0, #2_11:shl:(11*2)
	 orr  r0, #GPIOx_MODER_OUTPUT:shl:(11*2)
	 str  r0, [rGPIOC, #GPIOx_MODER]
	 ldr  r0, [rGPIOC, #GPIOx_PUPDR]
	 orr  r0, #GPIOx_PUPDR_PU:shl:(11*2)
	 str  r0, [rGPIOC, #GPIOx_PUPDR]
	 mov  r0, #1:shl:11
	 str  r0, [rGPIOC, #GPIOx_BSRR]
	 mov  r0, #1:shl:(11 + 16)
	 str  r0, [rGPIOC, #GPIOx_BSRR]
	 
	 ldr  rGPIOC, =GPIOC_BaseAddr
	 ldr  r0, [rGPIOC, #GPIOx_MODER]
GPIOC_MODER_BITs equ (2_11:shl:(12 * 2)) :or: \
					 (2_11:shl:(11 * 2)) :or: \
					 (2_11:shl:(10 * 2)) :or: \
					 (2_11:shl:(9  * 2)) :or: \
					 (2_11:shl:(8  * 2)) 
GPIOC_MODER_VAL	 equ (GPIOx_MODER_AFIO:shl:(12 * 2)) :or: \
					 (GPIOx_MODER_AFIO:shl:(11 * 2)) :or: \
					 (GPIOx_MODER_AFIO:shl:(10 * 2)) :or: \
					 (GPIOx_MODER_AFIO:shl:(9  * 2)) :or: \
					 (GPIOx_MODER_AFIO:shl:(8  * 2)) 					
	 ldr  r1, =GPIOC_MODER_BITs
	 bic  r0, r1
	 ldr  r1, =GPIOC_MODER_VAL
	 orr  r0, r1
	 str  r0, [rGPIOC, #GPIOx_MODER]	 
	 ldr  r0, [rGPIOC, #GPIOx_OTYPER]
GPIOC_OTYPER_BITs	 equ	2_11111:shl:12
	 bic  r0, #GPIOC_OTYPER_BITs
	 str  r0, [rGPIOC, #GPIOx_OTYPER]
	 
	 ldr  r0, [rGPIOC, #GPIOx_OSPEEDR]	 
GPIOC_OSPEEDR_BITs  equ (2_11:shl:(12 * 2)) :or: \
					    (2_11:shl:(11 * 2)) :or: \
					    (2_11:shl:(10 * 2)) :or: \
					    (2_11:shl:(9  * 2)) :or: \
					    (2_11:shl:(8  * 2)) 
GPIOC_OSPEEDR_VAL	equ (SDIO_GPIO_SPEED:shl:(12 * 2)) :or: \
					    (SDIO_GPIO_SPEED:shl:(11 * 2)) :or: \
					    (SDIO_GPIO_SPEED:shl:(10 * 2)) :or: \
					    (SDIO_GPIO_SPEED:shl:(9  * 2)) :or: \
					    (SDIO_GPIO_SPEED:shl:(8  * 2)) 	 
	 ldr  r1, =GPIOC_OSPEEDR_BITs
	 bic  r0, r1
	 ldr  r1, =GPIOC_OSPEEDR_VAL
	 orr  r0, r1
	 str  r0, [rGPIOC, #GPIOx_OSPEEDR]
	 
	 ldr  r0, [rGPIOC, #GPIOx_PUPDR]
GPIOC_PUPDR_BITs  equ   (2_11:shl:(12 * 2)) :or: \
					    (2_11:shl:(11 * 2)) :or: \
					    (2_11:shl:(10 * 2)) :or: \
					    (2_11:shl:(9  * 2)) :or: \
					    (2_11:shl:(8  * 2)) 
GPIOC_PUPDR_VAL	equ     (GPIOx_PUPDR_PU:shl:(12 * 2)) :or: \
					    (GPIOx_PUPDR_PU:shl:(11 * 2)) :or: \
					    (GPIOx_PUPDR_PU:shl:(10 * 2)) :or: \
					    (GPIOx_PUPDR_PU:shl:(9  * 2)) :or: \
					    (GPIOx_PUPDR_PU:shl:(8  * 2))	 
	 ldr  r1, =GPIOC_PUPDR_BITs
	 bic  r0, r1
	 ldr  r1, =GPIOC_PUPDR_VAL
	 orr  r0, r1
	 str  r0, [rGPIOC, #GPIOx_PUPDR]
GPIOC_AFIO_BITs		equ		(2_1111:shl:16) :or: \
							(2_1111:shl:12) :or: \
							(2_1111:shl:8 ) :or: \
							(2_1111:shl:4 ) :or: \
							(2_1111:shl:0 ) 
GPIOC_AFIO_VAL		equ		(12:shl:16) :or: \
							(12:shl:12) :or: \
							(12:shl:8 ) :or: \
							(12:shl:4 ) :or: \
							(12:shl:0 ) 							
	 ldr  r0, [rGPIOC, #GPIOx_AFRH]
	 ldr  r1, =GPIOC_AFIO_BITs
	 bic  r0, r1
	 ldr  r1, =GPIOC_AFIO_VAL
	 orr  r0, r1
	 str  r0, [rGPIOC, #GPIOx_AFRH]
	 
	 ldr  rGPIOD, =GPIOD_BaseAddr
	 ldr  r0, [rGPIOD, #GPIOx_MODER]
	 bic  r0, #2_11 :shl:(2 * 2)
	 orr  r0, #GPIOx_MODER_AFIO:shl:(2 * 2)
	 str  r0, [rGPIOD, #GPIOx_MODER]
	 ldr  r0, [rGPIOD, #GPIOx_OTYPER]
	 bic  r0, #2_1 :shl: 2
	 orr  r0, #GPIOx_OTYPER_PP:shl:2
	 str  r0, [rGPIOD, #GPIOx_OTYPER]
	 ldr  r0, [rGPIOD, #GPIOx_OSPEEDR]
	 bic  r0, #2_11:shl:(2*2)
	 orr  r0, #SDIO_GPIO_SPEED:shl:(2*2)
	 str  r0, [rGPIOD, #GPIOx_OSPEEDR]
	 ldr  r0, [rGPIOD, #GPIOx_PUPDR]
	 bic  r0, #2_11:shl:(2 * 2)
	 orr  r0, #GPIOx_PUPDR_PU:shl:(2 * 2)
	 str  r0, [rGPIOD, #GPIOx_PUPDR]
	 ldr  r0, [rGPIOD, #GPIOx_AFRL]
	 bic  r0, #2_1111:shl:8
	 orr  r0, #12:shl:8
	 str  r0, [rGPIOD, #GPIOx_AFRL]
	 
	 ; 因为HCLK被配置成了144MHz,APB2分频是2分频,所以APB2的时钟是72MHz。
	 ; 为了达到400kHz的初始时钟输出,这里的APB2分频器的数值应该是72M/400k = 180; 所以如果这里写180,那么实际的分频是182分频,那么就肯定是满足要求的
	 
	 ldr  rSDIO, =SDIO_BaseAddr
	 mov  r0, #SDIO_POWER_PWRCTRL_POWERON
	 str  r0, [rSDIO, #SDIO_POWER]
	 mov  r0, #SDIO_CLKCR_CLKEN:or:SDIO_CLKCR_PWRSAV:or:SDIO_CLKCR_WIDBUS_4WIDE:or:180
	 str  r0, [rSDIO, #SDIO_CLKCR]
	 pop  {r4 - r11, lr}
	 bx   lr
	 endp

card_identification proc
	 push {r4 - r11, lr}
	 ldr  rSDIO, =SDIO_BaseAddr
	 mov  r0, #SDIO_CMD_CPSMEN
	 str  r0, [rSDIO, #SDIO_CMD]
	 mov  r0, #0
	 str  r0, [rSDIO, #SDIO_CMD]
	 mov  r0, #8:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMEN
	 mov  r1, #1:shl:8
	 bl   send_cmd
	 mov  r0, #55:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMEN
	 mov  r1, #0
	 bl   send_cmd
	 mov  r0, #41:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMEN
	 mov  r1, #0
	 bl   send_cmd
	 ldr  r4, [rSDIO, #SDIO_RESP1]
set_voltage
	 mov  r0, #55:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMEN
	 mov  r1, #0
	 bl   send_cmd
	 mov  r0, #41:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMEN
	 mov  r1, r4
	 bl   send_cmd
	 ldr  r0, [rSDIO, #SDIO_RESP1]
	 tst  r0, #1:shl:31
	 beq  set_voltage
	 
Ask_the_Card_to_Publish_CID
	 mov  r0, #2:or:SDIO_CMD_WAITRESP_Long:or:SDIO_CMD_CPSMEN
	 mov  r1, #0
	 bl   send_cmd
	 
Ask_the_Card_to_Publish_RCA	
	 mov  r0, #3:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMEN
	 mov  r1, #0
	 bl   send_cmd
	 ldr  r0, [rSDIO, #SDIO_RESP1]	 
	 bfc  r0, #0, #16
	 ldr  r4, =rca
	 str  r0, [r4]
	 
; 目前已经进入了DATA_TRANSFER_MODE
; 将频率设置到高频。这里设置到36MHz
	 
	 ldr  r0, [rSDIO, #SDIO_CLKCR]
	 bfc  r0, #0, #8
	 str  r0, [rSDIO, #SDIO_CLKCR]
; 测试DATA_TRANSFER_MODE模式下的指令
	 
	 mov  r0, #9:or:SDIO_CMD_WAITRESP_Long:or:SDIO_CMD_CPSMEN
	 ldr  r1, =rca
	 ldr  r1, [r1]
	 bl   send_cmd
	 
	 mov  r0, #10:or:SDIO_CMD_WAITRESP_Long:or:SDIO_CMD_CPSMEN
	 ldr  r1, =rca
	 ldr  r1, [r1]
	 bl   send_cmd
	 
	 pop  {r4 - r11, lr}
	 bx   lr
	 endp
		 
; 	 Priviate Function Name: Send_cmd
;	 Args:  r0 - cmd, r1 - arg
;	 实现这个函数

	 align 4		 
send_cmd	proc
	push {r4 - r11, lr}
	ldr  rSDIO, =SDIO_BaseAddr
	mov  r2, #0x7f
	str  r2, [rSDIO, #SDIO_ICR]
	str  r1, [rSDIO, #SDIO_ARG]
	str  r0, [rSDIO, #SDIO_CMD]
wait_for_response
	ldr  r0, [rSDIO, #SDIO_STA]
	tst  r0, #SDIO_STA_CMDREND:or:SDIO_STA_DCRCFAIL:or:SDIO_STA_CTIMEOUT
	beq  wait_for_response
;	mov  r0, #0
;	str  r0, [rSDIO, #SDIO_CMD]
	pop  {r4 - r11, lr}	
	bx   lr
	endp
	
	align 4
SDIO_Memory_Card	
	 export SDIO_Memory_Card
	 dcd  init, card_identification
	 end
	

卡识别过程的流程就是基本按照手册上说的,

  1. 象征性发一下CMD0,不等回复。
  2. 发CMD8。这句目前看来是很重要的
  3. 发CMD55再发ACMD41,要回复的,且要记住返回值
  4. 发CMD55再发ACMD41,参数就是上一次的返回值。

注意看一下send_cmd(...)私有方法。这里面的流程是

  1. 用0x7f和SDIO_ICR清理一下SDIO_STA
  2. 先写SDIO_CMD,再写SDIO_ARG发送指令及其参数
  3. 忙等回复
  4. 关闭CPSM
  5. 返回

五、测试结果

测试用例这样就比较简单了,代码如下所示。

#include "cmsis_os2.h"                          // CMSIS RTOS header file
#include "SDIO_TestCase.h"
#include "SDIO_Memory_Card.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;
	(void)argument;

	// 在这里做一个测试
	SDIO_Memory_Card.card_identification(); 
  while (1) {
    osDelay(101);
  }
}

进DEBUG,插入SD卡,F5启动。在下面这个地方下断。

在这里插入图片描述
可以发现程序顺利执行,SD卡进入了DATA_TRANSFER_MODE, 并且读到了RCA。

六、结论

经过上面的程序源码设计和测试,可以看到程序顺利运行。有以下的体会。

  1. MCU本身都是有缺陷的。就看有没有暴露出来。如果出现了,能补救就补救。当然也要跟原厂反映。说不定下一版他们就改了。比如这个CMD0疑似发不出去;CPSM每发一个指令就得重启。这就只能用别的办法补救。
  2. 先用400kHz初始化,进入DATA_TRANSFER_MODE以后再改成高速。

这样初始化的任务就基本完成了。下一步就是测试DATA_TRANSFER_MODE中的指令和功能了。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

伪分布Hadoop的安装与部署

1.实训目标 (1)熟悉掌握使用在Linux下安装JDK。 (2)熟悉掌握使用在Linux下安装Hadoop。 (3)熟悉掌握使用配置SSH免密登录。 2.实训环境与软件 环境 版本 说明 Windows 10系统 64位 操作电脑配置 …

【ENVI精讲】处理专题五:基于像元二分模型的植被覆盖度反演

一、专题概述 植被覆盖度是指植被(包括叶、茎、枝)在地面的垂直投影面积占统计区总面积的百分比。植被覆盖度常用于植被变化、生态环境研究、水土保持、气候等方面。植被覆盖度数据来源于地理遥感生态网平台。 二、像元二分法模型 像元二分模型是一种…

什么是自动化测试?什么情况下使用?

什么是自动化测试? 自动化测试是指把以人为驱动的测试行为转化为机器执行的过程。实际上自动化测试往往通过一些测试工具或框架,编写自动化测试脚本,来模拟手工测试过程。比如说,在项目迭代过程中,持续的回归测试是一项非常枯燥…

蓝桥集训之序列

蓝桥集训之序列 核心思想&#xff1a;多路归并 每次将两个序列合并 –> 两序列n2个和中最小的n个 构成新序列 第一行都是加b1 每次在最外面的元素中取最小(优先队列) #include<iostream>#include<algorithm>#include<cstring>#include<queue>#incl…

ChatGPT 控制机器人的基本框架

过去的一年&#xff0c;OpenAI的chatGPT将自然语言的大型语言模型&#xff08;LLM&#xff09;推向了公众的视野&#xff0c;人工智能AI如一夜春风吹遍了巴黎&#xff0c;全世界都为AI而疯狂。 OpenAI ChatGPT是一个使用人类反馈进行微调的预训练生成文本模型。不像以前的模型主…

LoadBalancer (本地负载均衡)

1.loadbalancer本地负载均衡客户端 VS Nginx服务端负载均衡区别 Nginx是服务器负载均衡&#xff0c;客户端所有请求都会交给nginx&#xff0c;然后由nginx实现转发请求&#xff0c;即负载均衡是由服务端实现的。 loadbalancer本地负载均衡&#xff0c;在调用微服务接口时候&a…

云计算项目十一:构建完整的日志分析平台

检查k8s集群环境&#xff0c;master主机操作&#xff0c;确定是ready 启动harbor [rootharbor ~]# cd /usr/local/harbor [rootharbor harbor]# /usr/local/bin/docker-compose up -d 检查head插件是否启动&#xff0c;如果没有&#xff0c;需要启动 [rootes-0001 ~]# system…

VARMA(Vector Auto Regressive Moving Average) in Time Series Modelling

what is VARMA? ARIMA是针对单一变量进行建模的方法,当我们需要进行多变量时序建模时,需要使用VAR and VMA and VARMA模型。 VAR:Vector Auto-Regressive,a generalization of the auto-regressive model for multivariate time series where the time series is station…

【重新定义matlab强大系列十七】Matlab深入浅出长短期记忆神经网络LSTM

&#x1f517; 运行环境&#xff1a;Matlab &#x1f6a9; 撰写作者&#xff1a;左手の明天 &#x1f947; 精选专栏&#xff1a;《python》 &#x1f525; 推荐专栏&#xff1a;《算法研究》 #### 防伪水印——左手の明天 #### &#x1f497; 大家好&#x1f917;&#x1f91…

音视频按照时长分类小工具

应某用户的需求&#xff0c;编写了这款根据音视频时长分类小工具。 实际效果如下&#xff1a; 显示的是时分秒&#xff1a; 核心代码&#xff1a; MediaInfo MI; if (MI.Open(strPathInput.c_str()) 0){return -1;}_tstring stDuration MI.Get(stream_t::Stream_Audio,0,_T…

【Flink】Flink 的八种分区策略(源码解读)

Flink 的八种分区策略&#xff08;源码解读&#xff09; 1.继承关系图1.1 接口&#xff1a;ChannelSelector1.2 抽象类&#xff1a;StreamPartitioner1.3 继承关系图 2.分区策略2.1 GlobalPartitioner2.2 ShufflePartitioner2.3 BroadcastPartitioner2.4 RebalancePartitioner2…

手机APP测试——如何进行安装、卸载、运行?

手机APP测试——主要针对的是安卓( Android )和苹果IOS两大主流操作系统,主要考虑的就是功能性、兼容性、稳定性、易用性、性能等测试&#xff0c;今天先来讲讲如何进行安装、卸载、运行的内容。 一、App安装 1、点击运行APP安装包,检测安装包是否正常; . 2、进入[安装向导]…

Java17 --- SpringCloud之OpenFeign

目录 一、OpenFeign实现服务调用 1.1、创建openfeign微服务 二、Openfeign超时控制 2.1、全局默认配置 2.2、单个微服务配置 三、重试机制 四、替换openfeign默认的HttpClient 五、请求响应压缩 六、日志打印 一、OpenFeign实现服务调用 1.1、创建openfeign微服…

LLM长上下文外推方法

现在的LLM都集中在卷上下文长度了&#xff0c;最新的Claude3已经支持200K的上下文&#xff0c;见&#xff1a;cost-context。下面是一些提升LLM长度外推能力的方法总结&#xff1a; 数据工程 符尧大佬的最新工作&#xff1a;Data Engineering for Scaling Language Models to …

[虚拟机保护逆向] [HGAME 2023 week4]vm

[虚拟机保护逆向] [HGAME 2023 week4]vm 虚拟机逆向的注意点&#xff1a;具体每个函数的功能&#xff0c;和其对应的硬件编码的*长度* 和 *含义*&#xff0c;都分析出来后就可以编写脚本将题目的opcode转化位vm实际执行的指令 &#xff1a;分析完成函数功能后就可以编写脚本输出…

c++ primer plus 笔记 第十六章 string类和标准模板库

string类 string自动调整大小的功能&#xff1a; string字符串是怎么占用内存空间的&#xff1f; 前景&#xff1a; 如果只给string字符串分配string字符串大小的空间&#xff0c;当一个string字符串附加到另一个string字符串上&#xff0c;这个string字符串是以占用…

Spring web开发(入门)

1、我们在执行程序时&#xff0c;运行的需要是这个界面 2、简单的web接口&#xff08;127.0.0.1表示本机IP&#xff09; package com.example.demo;import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestCont…

代码学习记录15

随想录日记part15 t i m e &#xff1a; time&#xff1a; time&#xff1a; 2024.03.09 主要内容&#xff1a;今天的主要内容是二叉树的第四部分&#xff0c;主要涉及平衡二叉树的建立&#xff1b;二叉树的路径查找&#xff1b;左叶子之和&#xff1b;找树左下角的值&#xff…

考研复习C语言初阶(4)+标记和BFS展开的扫雷游戏

目录 1. 一维数组的创建和初始化。 1.1 数组的创建 1.2 数组的初始化 1.3 一维数组的使用 1.4 一维数组在内存中的存储 2. 二维数组的创建和初始化 2.1 二维数组的创建 2.2 二维数组的初始化 2.3 二维数组的使用 2.4 二维数组在内存中的存储 3. 数组越界 4. 冒泡…

3.DOM-事件进阶(事件对象、事件委托)

环境对象this 环境对象本质上是一个关键字 this this所在的代码区域不同&#xff0c;代表的含义不同 全局作用域中的this 全局作用域中this代表window对象 局部作用域中的this 在局部作用域中(函数中)this代表window对象 原因是函数调用的时候简写了&#xff0c;函数完整写…