DDR2 IP核调试记录1

一、IP核生成不成功可能原因

1、打开 Quartus II 软件时,请右键选择以管理员方式运行,切记,否则可能导致 IP 生成不成功。
2、创建工程时不要将工程创建在和 Quartus II 安装目录相同的盘符下,否则可能导致生产 IP 失败。
3、如果在生产 IP 界面长时间卡住,无法生成 IP,请关闭掉 Windows 系统的自动更新和防火墙后重新尝试。

二、modelsim仿真时出错可能原因

        IP 请直接创建在 Quartus 的工程根目录下,不要再创建子文件夹,否则仿真的时候会报错。提示找不到文件,实际是因为文件太多,IP 中有些文件路径包含时候处理不好导致的,属于 IP 核设计的小 bug。

三、信号分析

1. 功能

        循环写入255个数后再读出。再在接下来的地址写入、读出。

2. 关于代码中突发长度的几个信号区别
local_size(本地突发长度):

(个人理解:针对本地用户信号而言,发送一次本地地址连续传输的数据=local数据传输几个时钟才能填满DDR2 IC的一个内存单元)

        连续读或写到memory字的个数。

        如果选择memory burst length=4,half rate,则local burst size是1,所以local_zise总是1

        如果选择memory burst length=4,full rate,则local burst size是2,所以local_size应该设置为1或2对应每次的写读请求

        如果是local_size=2的时候,则一次写入2个local_wdata,两个64位

   burst length(存储器突发长度):

(个人理解:针对存储IC而言,预存取数=一次mem_addr地址连续读写的字个数)

        设置每个传输读取或写入字的数量。   单位:beats   范围:4 or 8

        存储器突发长度为4 等同于半速率设计中本地突发长度为1(四分之一),也等同于全速率设计中本地突发长度为2(二分之一)。

          half-rate模式下,memory burst length只能是8

          full-rate 模式下,memory burst length只能是4

       

在Avalon-MM接口上数据总线的位宽,full产生一个2X存储器数据位宽。half产生一个4X存储器数据位宽。

The full-rate state machine supports 1T address and command, and always issues memory burst length of 4. 

The half-rate state machine supports 2T address and command, and always issues memory burst length of 8.

参考下面博文更好理解burst_length 和local_size的区别:

[附源码]Quartus平台DDR2IP核讲解、仿真及其代码_:-O:-O:-O:-O:-O:-O:-O:-O:-O:-O的博客-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/csgola/article/details/129547505参考博文中的两种情况时序波形

FULL-RATE

HALF RATE

half rate/full rate :

这里的 half rate/full rate 指是 DDR IP 的  数据控制  和 device 器件接口间的时钟速率关系.    

数据控制:  指 DDR 数据传输控制部分。

device 接口: 指的是 DDR IP和 ddr device 的连接.

full rate时:    上述两者 clock 频率相同,  数据宽度  前者 = 后者 x2    如果device接口是16位,则数据接口是32位

half rate时:  上述两者 clock: 前者 = 后者 /2,  数据宽度: 前者 = 后者 x4    如果device接口是16位,则数据接口是64位

这一参数选项存在原因是为了, 降低时钟频率

同时为什么会出现full或half模式下,频率相同,但数据宽度不一样

因为DDR2内部是双边沿,但是控制是单边沿。

代码中信号

        rd/wr_burst_len=255 ,用户需要读写的数据量;  ( 与local_size和burst_legnth无关,后两者属于IP核和硬件IC的固有属性,与其位宽和full/half速率有关)

        burst_size=2  (local_size),用户访问DDR2一次连续访问的数据量,即提供一次地址,能连续读 burst_size长度的数据,然后下次的地址+ burst_size;

        burst_legnth是IC固有的属性,在IP核内部也可以看到IC的参数。

        length初始值=rd/wr_burst_len,用于状态的判断。

ip核信号:

        local_address:将访问SDRAM的地址作为输入,无论是读还是写。因此需要在各种状态下,对local_address进行赋值。

3. 程序状态示意图

四、代码

1. IP核封装
/*本模块完成对ddr2 IP的包装,方便后续模块使用,也方便程序的移植,如果更换平台,更新这个文件即可
*/
module mem_burst_v2
#(
	parameter MEM_DATA_BITS = 32,
	parameter ADDR_BITS = 24,
	parameter LOCAL_SIZE_BITS = 3
)
(
	input rst_n,                                 /*复位*/
	input mem_clk,                               /*接口时钟*/
	input rd_burst_req,                          /*读请求*/
	input wr_burst_req,                          /*写请求*/
	input[9:0] rd_burst_len,                     /*读数据长度*/
	input[9:0] wr_burst_len,                     /*写数据长度*/
	input[ADDR_BITS - 1:0] rd_burst_addr,        /*读首地址*/
	input[ADDR_BITS - 1:0] wr_burst_addr,        /*写首地址*/
	output rd_burst_data_valid,                  /*读出数据有效*/
	output wr_burst_data_req,                    /*写数据信号*/
	output[MEM_DATA_BITS - 1:0] rd_burst_data,   /*读出的数据*/
	input[MEM_DATA_BITS - 1:0] wr_burst_data,    /*写入的数据*/
	output rd_burst_finish,                      /*读完成*/
	output wr_burst_finish,                      /*写完成*/
	output burst_finish,                         /*读或写完成*/
	
	///
	/*以下是altera ddr2 IP的接口,可参考altera相关文档*/
	input local_init_done,
	output ddr_rst_n,
	input local_ready,
	output  local_burstbegin,
	output[MEM_DATA_BITS - 1:0] local_wdata,
	input local_rdata_valid,
	input[MEM_DATA_BITS - 1:0] local_rdata,
	output  local_write_req,
	output  local_read_req,
	output reg[23:0] local_address,
	output[MEM_DATA_BITS/8 - 1:0] local_be,
	output reg[LOCAL_SIZE_BITS - 1:0] local_size
);
parameter IDLE = 3'd0;
parameter MEM_READ = 3'd1;
parameter MEM_READ_WAIT = 3'd2;
parameter MEM_WRITE  = 3'd3;
parameter MEM_WRITE_BURST_BEGIN = 3'd4;
parameter MEM_WRITE_FIRST = 3'd5;
parameter burst_size = 10'd2;             
reg[2:0] state = 3'd0;
reg[2:0] next_state = 3'd0;	
reg[9:0] rd_addr_cnt = 10'd0;
reg[9:0] rd_data_cnt = 10'd0;

reg[9:0] length = 10'd0;
reg[11:0] cnt_timer = 12'd0;
reg[11:0] ddr_reset_timer = 12'd0;
reg ddr_rst_n_reg = 1'b1;


reg [LOCAL_SIZE_BITS - 1:0] burst_remain;
reg last_wr_burst_data_req;
reg[9:0] wr_remain_len;

/*写入数据请求信号*/
assign wr_burst_data_req = (state == MEM_WRITE_FIRST ) || (((state == MEM_WRITE_BURST_BEGIN) ||  (state == MEM_WRITE)) && local_ready && ~last_wr_burst_data_req);
assign burst_finish = rd_burst_finish | wr_burst_finish;

/*local写请求信号*/
assign local_write_req = ((state == MEM_WRITE_BURST_BEGIN) ||  (state == MEM_WRITE));


/*初始化计时器, 在本程序没有用到*/
always@(posedge mem_clk or negedge rst_n)
begin
	if(~rst_n)
		cnt_timer <= 12'd0;
	else if(state == IDLE || ~local_init_done)
		cnt_timer <= 12'd0;
	else
		cnt_timer <= cnt_timer + 12'd1;
end

/*DDR读等待计数器, 在本程序没有用到*/
always@(posedge mem_clk or negedge rst_n)
begin
	if(~rst_n)
		ddr_reset_timer <= 12'd0;
	else if(state == MEM_READ_WAIT)
		ddr_reset_timer <= ddr_reset_timer + 12'd1;
	else
		ddr_reset_timer <= 12'd0;	
	ddr_rst_n_reg <= (ddr_reset_timer !=12'd200);
end
assign ddr_rst_n = ddr_rst_n_reg;

/*状态锁存*/
always@(posedge	mem_clk or negedge rst_n)
	begin
		if(~rst_n)
			state <= IDLE;
		else if(~local_init_done ) //IP核的初始化结束信号
			state <= IDLE;
		else
			state <= next_state;
	end
	
/*burst读写处理程序*/	
always@(*)
	begin
		case(state)
			IDLE:
				begin
					if(rd_burst_req && rd_burst_len != 10'd0)         /*接收到burst读请求*/
						next_state <= MEM_READ;      /*状态转为发burst读命令*/
					else if(wr_burst_req && wr_burst_len != 10'd0)    /*接收到burst写请求*/
						next_state <= MEM_WRITE_FIRST;    /*状态转为第一次写*/
					else
						next_state <= IDLE;
				end
			MEM_READ:                         /*burst读命令*/
				begin
					if( (rd_addr_cnt + burst_size >= length) && local_read_req && local_ready) /*判断burst读请求的有效的长度*/
						next_state <= MEM_READ_WAIT;
					else
						next_state <= MEM_READ;
				end
			MEM_READ_WAIT:                   /*等待burst数据读完成*/
				begin 
					if(rd_data_cnt == length - 10'd1 && local_rdata_valid)     /*判断读出的有效数据长度*/
						next_state <= IDLE;
					else
						next_state <= MEM_READ_WAIT;
				end
			MEM_WRITE_FIRST:                /*第一次写状态, 用于准备写入的数据*/
				next_state <= MEM_WRITE_BURST_BEGIN;
			MEM_WRITE_BURST_BEGIN:         /*产生burst begin信号*/                      
				begin
					if(local_ready && wr_remain_len == 10'd1)     /*如果写的剩余数据长度为1, Burst写结束*/
						next_state <= IDLE;
					else if(burst_remain == 1 && local_ready)     /*一次local burst写完成, 重新回到burst begin */   
						next_state <= MEM_WRITE_BURST_BEGIN;
					else if(local_ready)
						next_state <= MEM_WRITE;    /*burst begin完成, 转到数据写入*/    
					else
						next_state <= MEM_WRITE_BURST_BEGIN;
				end
			MEM_WRITE:                   
				begin
					if(wr_remain_len == 10'd1 && local_ready)     /*如果写的剩余数据长度为1, Burst写结束*/
						next_state <= IDLE;
					else if(burst_remain == 1 && local_ready)     /*一次local burst写完成,重新回到burst begin */   
						next_state <= MEM_WRITE_BURST_BEGIN;
					else 
						next_state <= MEM_WRITE;
				end
			default:
				next_state <= IDLE;
		endcase
	end
	
	assign local_burstbegin = ((state == MEM_WRITE_BURST_BEGIN) ||  (state == MEM_READ)); /*产生local burst begin信号*/

/*计算最后一个burst数据写请求信号*/
always@(posedge	mem_clk)
	begin
		if(state == MEM_WRITE_BURST_BEGIN || state == MEM_WRITE)
			if(wr_remain_len == 10'd2 && local_ready)
				last_wr_burst_data_req <= 1'b1;
			else
				last_wr_burst_data_req <= last_wr_burst_data_req;
		else
			last_wr_burst_data_req <= 1'b0;
	end
	
/*计算外部burst写的剩余数据长度*/
always@(posedge	mem_clk)
	begin
		case(state)
			IDLE:
				if(wr_burst_req)
					wr_remain_len <= wr_burst_len;  /*wr_remain_len赋初值*/
				else
					wr_remain_len <= wr_remain_len;
			MEM_WRITE_BURST_BEGIN:      
				if(local_ready)
					wr_remain_len <= wr_remain_len - 10'd1;
				else
					wr_remain_len <= wr_remain_len;
			MEM_WRITE:
				if(local_ready)
					wr_remain_len <= wr_remain_len - 10'd1;
				else
					wr_remain_len <= wr_remain_len;
			default:
				wr_remain_len <= wr_remain_len;
		endcase
	end

/*计算一次local burst的剩余数*/	
always@(posedge	mem_clk)
	begin
		if(next_state == MEM_WRITE_BURST_BEGIN)
			burst_remain <= burst_size;        /*burst size is 2*/
		else if( ((state == MEM_WRITE_BURST_BEGIN) || (state == MEM_WRITE)) && local_ready)      /*一次数据写入有效*/
			burst_remain <= burst_remain - 1;
		else
			burst_remain <= burst_remain;
	end	
	
/*计算local size, 需要判断剩余的数据是否大于burst_size*/	
always@(posedge	mem_clk)
	begin
		if(state == IDLE && rd_burst_req)
			local_size <= (rd_burst_len >= burst_size) ?  burst_size : rd_burst_len ;
		else if(state == IDLE && wr_burst_req)
			local_size <= (wr_burst_len >= burst_size) ?  burst_size : wr_burst_len;
		else if(state == MEM_WRITE && (next_state == MEM_WRITE_BURST_BEGIN))
			if((wr_remain_len - 1) > burst_size)  /*判断剩余写数据长度是否大于burst_size*/
				local_size <= burst_size;
			else
				local_size <= wr_remain_len - 1;
		else if(state == MEM_WRITE_BURST_BEGIN && (next_state == MEM_WRITE_BURST_BEGIN) && local_ready)
			if((wr_remain_len - 1) > burst_size)  /*判断剩余写数据长度是否大于burst_size*/
				local_size <= burst_size;
			else
				local_size <= wr_remain_len - 1;
		else if(state == MEM_READ && local_ready )
			local_size <= (rd_addr_cnt + burst_size > length) ? 1 : burst_size; 
		else
			local_size <= local_size;
	end

/*计算地址local_address*/
always@(posedge	mem_clk)
	begin
		case(state)
			IDLE:
				begin
					if(rd_burst_req)     /*读burst请求有效*/
						begin
							local_address <= rd_burst_addr;
							rd_addr_cnt <= 10'd0;
						end
					else if(wr_burst_req) /*读burst请求有效*/
						begin
							local_address <= wr_burst_addr;
							rd_addr_cnt <= 10'd0;
						end
					else
						begin
							local_address <= local_address;
							rd_addr_cnt <= 10'd0;
						end
				end
			MEM_READ:
				begin
					if(local_ready)
						begin
							local_address <= local_address + {14'd0,burst_size};   /*Bust读,地址加burst_size*/
							rd_addr_cnt <= rd_addr_cnt + burst_size;
						end
					else
						begin
							local_address <= local_address;
							rd_addr_cnt <= rd_addr_cnt;
						end		
				end
			MEM_WRITE_BURST_BEGIN:
				begin
					if(local_ready && (next_state == MEM_WRITE_BURST_BEGIN))
						begin
							local_address <= local_address + {14'd0,burst_size};  /*Bust begin写,地址加burst_size*/
						end
					else
						begin
							local_address <= local_address;
						end	
				end	
			MEM_WRITE: 
				begin
					if(local_ready && (next_state == MEM_WRITE_BURST_BEGIN))    
						begin
							local_address <= local_address + {14'd0,burst_size};   /*Bust 写,地址加burst_size*/
						end
					else
						begin
							local_address <= local_address;
						end	
				end
			default:
				begin
					local_address <= local_address;
					rd_addr_cnt <= 10'd0;
				end
		endcase
	end
	
/*burst读长度*/	
always@(posedge	mem_clk)
	begin
		if(state == IDLE && rd_burst_req)
			length <= rd_burst_len;
		else
			length <= length; 
	end
	
/*统计读数据counter*/
always@(posedge	mem_clk)
	begin
		if(state == MEM_READ || state == MEM_READ_WAIT)
			if(local_rdata_valid)
				rd_data_cnt <= rd_data_cnt + 10'd1;
			else
				rd_data_cnt <= rd_data_cnt;
		else
			rd_data_cnt <= 10'd0;
	end

/*输出信号赋值*/
assign rd_burst_data_valid = local_rdata_valid;
assign rd_burst_data = local_rdata;
assign local_wdata = wr_burst_data;
assign local_read_req = (state == MEM_READ);
assign rd_burst_finish = (state == MEM_READ_WAIT) && (next_state == IDLE);
assign wr_burst_finish = (local_ready && wr_remain_len == 10'd1);
assign local_be = {MEM_DATA_BITS/8{1'b1}};
endmodule 
2. 顶层模块
module ddr_test(

	input  wire  source_clk,        //输入系统时钟50Mhz
	input rst_n,
	output err,                     //led1, 灯亮DDR读写正常, 灯灭DDR读写出错
   output  [ 14: 0] mem_addr,
   output  [  2: 0] mem_ba,
   output           mem_cas_n,
   output  [  0: 0] mem_cke,
   inout   [  0: 0] mem_clk,
   inout   [  0: 0] mem_clk_n,
   output  [  0: 0] mem_cs_n,
   output  [  1: 0] mem_dm,
   inout   [ 15: 0] mem_dq,
   inout   [  1: 0] mem_dqs,
   output  [  0: 0] mem_odt,
   output           mem_ras_n,
   output           mem_we_n  
);

parameter DATA_WIDTH = 32;           //总线数据宽度
parameter ADDR_WIDTH = 25;           //总线地址宽度

parameter IDLE = 3'd0;
parameter MEM_READ = 3'd1;
parameter MEM_WRITE  = 3'd2; 
reg[2:0] state;
reg[2:0] next_state;

//状态锁存///
always@(posedge	phy_clk)
	begin
		if(~local_init_done)          //等待初始化成功
			state <= IDLE;
		else	
			state <= next_state;
	end
	
//循环产生DDR Burst读,Burst写状态///
always@(*)
	begin 
		case(state)
			IDLE:
				next_state <= MEM_WRITE;  
			MEM_WRITE:                    //写入数据到DDR2
				if(wr_burst_finish)          
					next_state <= MEM_READ;
				else
					next_state <= MEM_WRITE;
			MEM_READ:                    //读出数据从DDR2
				if(rd_burst_finish)
					next_state <= MEM_WRITE;
				else
					next_state <= MEM_READ;
			default:
				next_state <= IDLE;
		endcase
end

reg  [ADDR_WIDTH - 1:0] wr_burst_addr;
wire [ADDR_WIDTH - 1:0] rd_burst_addr;
wire    wr_burst_data_req;
wire    rd_burst_data_valid;
reg  [9:0] wr_burst_len;
reg  [9:0] rd_burst_len;
reg     wr_burst_req;
reg     rd_burst_req;
reg  [9:0] wr_cnt;
reg  [9:0] rd_cnt;
wire [DATA_WIDTH - 1:0] wr_burst_data;
wire [DATA_WIDTH - 1:0] rd_burst_data;


//DDR的读写地址和DDR测试数据//
always@(posedge phy_clk)
	begin
		if(state == IDLE && next_state == MEM_WRITE)
			wr_burst_addr <= {ADDR_WIDTH{1'b0}};     //地址清零
		else if(state == MEM_READ && next_state == MEM_WRITE)                //一次Burst读写完成
			wr_burst_addr <= wr_burst_addr + {{(ADDR_WIDTH-8){1'b0}},8'd255}; //地址加burst长度255         
		else
			wr_burst_addr <= wr_burst_addr;           //锁存地址
	end
assign rd_burst_addr = wr_burst_addr;     
assign wr_burst_data = {(DATA_WIDTH/8){wr_cnt[7:0]}};     //写入DDR的数据

//产生burst写请求信号
always@(posedge phy_clk)
	begin
		if(next_state == MEM_WRITE && state != MEM_WRITE)
			begin
				wr_burst_req <= 1'b1;      //产生ddr burst写请求       
				wr_burst_len <= 10'd255;
				wr_cnt <= 10'd0;
			end
		else if(wr_burst_data_req)       //写入burst数据请求 
			begin
				wr_burst_req <= 1'b0;
				wr_burst_len <= 10'd255;
				wr_cnt <= wr_cnt + 10'd1;  //测试数据(每字节)加1
			end
		else
			begin
				wr_burst_req <= wr_burst_req;
				wr_burst_len <= 10'd255;
				wr_cnt <= wr_cnt;
			end
	end

//产生burst读请求信号	
always@(posedge phy_clk)
	begin
		if(next_state == MEM_READ && state != MEM_READ)
			begin
				rd_burst_req <= 1'b1;      //产生ddr burst读请求  
				rd_burst_len <= 10'd255;
				rd_cnt <= 10'd1;
			end
		else if(rd_burst_data_valid)     //检测到data_valid信号,burst读请求变0
			begin
				rd_burst_req <= 1'b0;
				rd_burst_len <= 10'd255;
				rd_cnt <= rd_cnt + 10'd1;
			end
		else
			begin
				rd_burst_req <= rd_burst_req;
				rd_burst_len <= 10'd255;
				rd_cnt <= rd_cnt;
			end
	end
	
assign err = rd_burst_data_valid &(rd_burst_data != {(DATA_WIDTH/8){rd_cnt[7:0]}});       //检查DDR读出的数据是否正确

wire	[ADDR_WIDTH - 1:0]	local_address;   
wire		local_write_req;
wire		local_read_req;
wire	[DATA_WIDTH - 1:0]	local_wdata;
wire	[DATA_WIDTH/8 - 1:0]	local_be;   
wire	[2:0]	local_size;
wire		local_ready;
wire	[DATA_WIDTH - 1:0]	local_rdata;
wire		local_rdata_valid;
wire		local_wdata_req;
wire		local_init_done;
wire		phy_clk;
wire		aux_full_rate_clk;
wire		aux_half_rate_clk;
wire     rd_burst_finish;
wire     wr_burst_finish;
//实例化mem_burst_v2
mem_burst_v2
#(
	.MEM_DATA_BITS(DATA_WIDTH)
)
mem_burst_m0(
	.rst_n(rst_n),
	.mem_clk(phy_clk),
	.rd_burst_req(rd_burst_req),
	.wr_burst_req(wr_burst_req),
	.rd_burst_len(rd_burst_len),
	.wr_burst_len(wr_burst_len),
	.rd_burst_addr(rd_burst_addr),
	.wr_burst_addr(wr_burst_addr),
	.rd_burst_data_valid(rd_burst_data_valid),
	.wr_burst_data_req(wr_burst_data_req),
	.rd_burst_data(rd_burst_data),
	.wr_burst_data(wr_burst_data),
	.rd_burst_finish(rd_burst_finish),
	.wr_burst_finish(wr_burst_finish),
	///
	.local_init_done(local_init_done),
	.local_ready(local_ready),
	.local_burstbegin(local_burstbegin),
	.local_wdata(local_wdata),
	.local_rdata_valid(local_rdata_valid),
	.local_rdata(local_rdata),
	.local_write_req(local_write_req),
	.local_read_req(local_read_req),
	.local_address(local_address),
	.local_be(local_be),
	.local_size(local_size)
);

//实例化ddr2.v
ddr2 ddr_m0(
	.local_address(local_address),
	.local_write_req(local_write_req),
	.local_read_req(local_read_req),
	.local_wdata(local_wdata),
	.local_be(local_be),
	.local_size(local_size),
	.global_reset_n(rst_n),
	//.local_refresh_req(1'b0), 
	//.local_self_rfsh_req(1'b0),
	.pll_ref_clk(source_clk),
	.soft_reset_n(1'b1),
	.local_ready(local_ready),
	.local_rdata(local_rdata),
	.local_rdata_valid(local_rdata_valid),
	.reset_request_n(),
	.mem_cs_n(mem_cs_n),
	.mem_cke(mem_cke),
	.mem_addr(mem_addr),
	.mem_ba(mem_ba),
	.mem_ras_n(mem_ras_n),
	.mem_cas_n(mem_cas_n),
	.mem_we_n(mem_we_n),
	.mem_dm(mem_dm),
	.local_refresh_ack(),
	.local_burstbegin(local_burstbegin),
	.local_init_done(local_init_done),
	.reset_phy_clk_n(),
	.phy_clk(phy_clk),
	.aux_full_rate_clk(),
	.aux_half_rate_clk(),
	.mem_clk(mem_clk),
	.mem_clk_n(mem_clk_n),
	.mem_dq(mem_dq),
	.mem_dqs(mem_dqs),
	.mem_odt(mem_odt)
	);
	
endmodule 

3. 测试代码

五、波形分析

 1. 写过程分析

        如下图所示,只有当 local_ready 为高和 local_write_req 信号都为高时,写入的数据才是有效的数据,如果 local_ready 信号为低,local_write_req 和数据需要一直保持,等待local_ready 信号为高才行。 DDR2 的 burst _length 为 2, 所以地址信号 local_address 是每写入 2 个数据就加 2, local_burstbegin 信号为第一个数据写的时候为高,第二个数据写的时候为低。

 2. 读过程分析

        只有当 local_ready 为高和 local_read_req 信号都为高时,burst 读才是有
效的,如果 local_ready 信号为低,local_ read _req 和地址 local_address 需要一直保持,等待 local_ready 信号为高才行。local_read_req 信号请求为高等待一段时间后,local_rddata_valid 信号会变高,才会有有效的读的数据输出。如下面第一张图所示,地址发出后,数据在第二张图片才发出。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值