DDR3应用总结(二)

接DDR3应用总结(一)

4.使用MIG IP核构建DDR3应用


截图取自Xilinx官方手册ug586,figure1-51,MIG IP核是一个逻辑模块,相当于是由它连接了DDR芯片,对内给用户封装了接口,便于用户使用。从图中可以看出,将用户侧和物理侧通过控制器进行了逻辑上的划分,由此也引出来用户侧的一系列问题。下面关于MIG IP核的接口和时序以及MIG IP的配置进行说明。

4.1MIG IP接口信号

init_calib_complete:output信号,板卡上电后,DDR3 IP核会对DDR初始化校正,完成之后IP核拉高此信号,因此用户只有监测到该信号为高电平后才能对DDR进行读写操作(PHY asserts init_calib_complete when calibration is finished)
app_addr:input信号,将DDR实际的行信号,列信号,bank信号转换为逻辑地址信号,这个信号应该等于30bit=1bit rank+3bit bank+16bit row address + 10bit row address(以MT41K512M16HA-125AIT为例),30bit中的最高位rank为是冗余位,并没有用到
app_cmd:input信号,3bit的IP核操作码输入,000为写命令,001为读命令
app_en:input信号,IP核的命令使能输入:This is the active-High strobe for the app_addr[], app_cmd[2:0] inputs
app_rdy:output信号,IP核输出的,命令ready信号:This output indicates that the UI is ready to accept commands. If the signal is deasserted when app_en is enabled, the current app_cmd and app_addr must be retried until app_rdy is asserted
app_rd_data:output信号,当前读取到的数据,与app_rd_data_valid同步。
app_rd_data_end:output信号,此高电平有效输出指示当前时钟周期是app_rd_data []上输出数据的最后一个周期。 仅当app_rd_data_valid为active-High时有效。(这个信号在用户逻辑中没用)This active-High output indicates that the current clock cycle is the last cycle of output data on app_rd_data[]. This is valid only when app_rd_data_valid is active-High。实际应用过程中,通常不用这个信号。
app_rd_data_valid:output信号,高电平表示当前的 app_rd_data 数据有效。This active-High output indicates that app_rd_data[] is valid.
app_wdf_data:input信号,当前将要写入的数据,This provides the data for write commands.
app_wdf_end:input信号,此高电平有效输入指示当前时钟周期是 app_wdf_data 上输入数据的最后一个周期。This active-High input indicates that the current clock cycle is the last cycle of input data on app_wdf_data[]。应用中通常与app_wdf_wren同步,如下:

assign app_wdf_end = app_wdf_wren;

app_wdf_mask[APP_MASK_WIDTH – 1:0]:input信号,当前输入数据的掩码,mask为1的位对应的数据将被屏蔽掉。This provides the mask for app_wdf_data[]。
app_wdf_rdy:output信号,该输出表明写数据FIFO已准备好接收数据。 当app_wdf_rdy = 1’b1和app_wdf_wren = 1’b1时,接受写入数据。This output indicates that the write data FIFO is ready to receive data. Write data is accepted when app_wdf_rdy = 1’b1 and app_wdf_wren = 1’b1.
app_wdf_wren:input信号,高电平表示 app_wdf_data 数据有效。 This is the active-High strobe for app_wdf_data[].
ui_clk:output信号,MIG输出的用户端时钟(注意与2.3节的核心时钟与工作时钟区分),在4:1(这个比例可以在IP核中配置)模式下是DDR主频的1/4。这个时钟是由MIG生成的,与同频的其他时钟也要做时钟域的隔离。
ui_clk_sync_rst:output信号,MIG输出的用户端复位信号,高电平复位。
sys_clk_i:输入MIG的时钟(注意区分,此处可以在IP核配置)。
clk_ref_i:输入MIG的参考时钟,值固定为200MHz。
sys_rst:输入MIG的复位信号,低电平有效。

4.2MIG IP接口时序

写入addr与cmd:

如上图所示①,②,③情况,只有在③时刻app_en和app_rdy同时为高电平app_cmd(命令)和(app_addr)地址才有效,所以当需要app_cmd,app_addr有效时app_en必须保持到app_rdy为高电平才有效。
写时序:

如上图所示①,②,③种情况,写命令和写数据直接存在三种逻辑关系。
①表示写命令(app_cmd),写当前地址(app_addr)和写数据(app_wdf_data)以及写控制信号(app_en,app_rdy,app_wdf_rdy,app_wdf_wren,app_wdf_end)同时有效。推荐采用这种时序。
②表示写数据(app_wdf_data)和写控制信号(app_wdf_wren,app_wdf_end)先于写命令(app_cmd)和写当前地址(app_addr)以及其他写控制信号(app_en,app_rdy,app_wdf_rdy)一个用户时钟(ui_clk)。
③表示写数据(app_wdf_data)和写控制信号(app_wdf_wren,app_wdf_end)迟于写命令(app_cmd)和写当前地址(app_addr)以及其他写控制信号(app_en,app_rdy,app_wdf_rdy)。最多两个用户时钟(ui_clk)。
读时序:

如上图所示,当读命令(app_cmd)和当前读地址(app_addr)以及读控制信号(app_en,app_rdy)同时有效时,等待读数据有效信号(app_rd_data_valid)有效时读数据(app_rd_data)有效。

4.3MIG IP配置

1.在 IP Catalog 中搜索 Memory Interface Generator,双击打开出现以下页面,点击 Next ,出现 MIG Output Options 。

2.选择A创建设计以创建新的内存控制器设计;在B“Component Name field”一栏中输入IP核组件名称;在C选择要生成的控制器数量;D处,DDR2和DDR3 SDRAM设计支持内存映射的AXI4接口。 AXI4接口仅支持Verilog语言。 如果需要AXI4接口,请在调用MIG工具之前在Vivado Design Suite中将语言选择为“ Verilog”。 如果未选择AXI4界面,则用户界面(UI)是主要界面。

3.引脚兼容的FPGA页面列出了所选系列中具有相同封装的FPGA。 如果从MIG工具生成的引脚需要与其他任何FPGA兼容,则应使用此选项来选择必须与引脚兼容的FPGA。

4.此页面显示所选FPGA系列支持的所有存储器类型。选择DDR3 SDRAM控制器类型,单击下一步以显示“控制器选项”页面。

5.此页面显示了可以选择的各种控制器选项。

A.时钟周期,频率范围受所选FPGA和器件速度等级等因素的限制。这里配置为400MHz这个是DDR3物理引脚的工作频率,即IO缓冲器的工作频率,这里配置为400MHz。
B.PHY与控制器时钟比率–此功能确定物理层(存储器)时钟频率与用户界面时钟频率的比率,例如选择4:1,工作频率为400MHz,那么用户时钟ui_clk为100MHz。由于FPGA逻辑时序的限制,2:1的比率降低了最大存储器接口频率。2:1比例的用户界面数据总线宽度是物理内存接口宽度的四倍,而4:1比例的总线宽度是物理内存接口宽度的八倍(若设置工作频率为400MHz,因为DDR,所以等效于每一个800MHz周期需要16bit数据,此处设置为2:1,则用户时钟ui_clk为200MHz,那么一个200M周期在时间上等于4个800M周期,由此一个用户时钟周期应提供4倍的16bit数据才能做到匹配,同理,设置为4:1时,那么用户数据应该是8倍的16bit)。2:1的比例具有较低的延迟。4:1的比率对于获得最高数据速率是必要的。通常配做4:1。
C.此功能选择设计中使用的内存部分的类型。使用默认
D.选择器件具体型号数据宽度–可以根据之前选择的存储类型在此处选择数据宽度值。 该列表显示了所选part的所有支持的数据宽度。如果列表中并没有自己的芯片类型,可以选择相似的(指容量、位宽一致),也可以点击下面的creat custom port设置自定义的型号。注意,应在select base part中选择与实际芯片位宽大小一样的已有的型号作为基础,修改以下时序参数(DDR datasheet中提供)以及实际的行列线宽,以及bank位宽,生成自定义的型号。

E.数据宽度–可以根据之前选择的存储类型在此处选择数据宽度值。 该列表显示了所选part的所有支持的数据宽度。如果只有一颗DDR3,则此处的值应等于颗粒的物理位宽。不由的想,如果有两颗DDR3,如何做呢?后续将会给出答案。

F.Data mask 视需要而定。
G.Bank Machines数量–列表显示所选设计配置支持的Bank Machines数量。一般设置为4。
H.排序–正常模式允许内存控制器将命令重新排序到内存,以获得最高的效率。 严格模式强制控制器以接收到的确切顺序执行命令。一般设置为Normal。
若是自定义的DDR3型号,应关注Memory Details,是否与DDR3实际情况一致,若不一致则应修改一致继续使用。此处描述的是一片DDR3的情况。
6.除第一个设置输入IP的时钟为200MHz之外(此处设置的是sys_clk_i),其余保持默认。该功能允许选择各种有关存储模式的寄存器值。在初始化期间,将模式寄存器的值加载到加载模式寄存器中。内存地址映射的选择选择红色框中内容。


7.除了这两个选择无缓冲区外,其余保持默认。

A系统时钟–此选项为sys_clk信号对选择时钟类型(单端,差分或无缓冲区)。 选择“无缓冲区”选项时,不会在RTL代码中实例化IBUF原语,并且不会为系统时钟分配引脚。如果在没有执行更改的情况下实现了从MIG为No Buffer选项生成的设计,则设计可能会由于未针对sys_clk_i信号实例化的IBUF而无法实现。 因此,对于无缓冲区方案,需要将sys_clk_i信号连接到内部时钟。
B系统复位电平–可以选择系统复位的电平(sys_rst)。 如果将选项选择为active-Low,则参数RST_ACT_LOW设置为1;如果设置为active-High,则参数RST_ACT_LOW设置为0。
降低I/O功耗–该选项通过在控制器处于空闲状态时自动禁用DQ和DQS IBUF来降低平均I/O功耗。
8.HR Bank的内部终端匹配电阻–内部终端选项可以设置为40、50或60Ω或禁用。 此选择仅适用于HR Bank。通常设置为50即可。

9.引脚模式选择第二个,之后导入UCF文件,进行引脚约束配置。

10.开始一个个的输入DDR3信号对应的管脚,如果事先写好了管脚约束文件,也可以直接载入。填写完成后,点击“Validate”检查,看写的是否有误。

其余的点next即可。
注:MIG输入一个200MHz的时钟sys_clk_i,再输入一个200MHz的参考时钟clk_ref_i。倍频出来DDR3的工作时钟400MHz(工作时钟,IO驱动时钟),分频出来一个100MHz的用户时钟ui_clk。加之前面的工作时钟,核心时钟,都务必分清楚。

5.一个IP控制两颗DDR3

如下原理图,可以清楚的看到,两颗DDR3的相同的控制线连在了一个控制器的相同引脚,而数据线是各自连的。那么也就是说,对于FPGA而言,把外部的位宽为16bit的两颗DDR当成了一个位宽为32bit的DDR3来控制。这种往往是为了扩大容量;或者为了匹配rank位宽;或者为了提升带宽,将两片或者四片甚至更多片DDR3放在一起。

对于这种场景,MIG配置的时候有啥注意事项呢?只需要将4.3节IP配置第5步中的data width设置为实际芯片加起来的位宽即可。如两片16bit位宽颗粒相连,则设置位宽为32bit即可。配置生成的IP核的接口中app_addr仍会多出一位,这一位仍然是rank的冗余位,并无实际意义。其余的用户逻辑且把他当作一片位宽为32bit的DDR3即可。
实际上,用户存入的32bit数据在实际存放时,高位16bit和低位16bit的数据被放到不同的两片DDR3中,唯一的关联就是,这两个位置的物理值是相等的而已。

6.DDR3的乒乓应用

以采集摄像头数据为例,把DDR3当作缓存芯片,那么乒乓操作的思想是在DDR中开辟两块大小为1帧图像的缓冲区,如果读取速度大于写入速度的时候,需要采用乒乓操作的方式发挥DDR弹性缓冲的作用。往缓冲区写的时候,1号缓冲区写满之后,切换到2号缓冲区写,2号写满之后,在往1号去写,如此往复。由于读取速度大于写入速度,因此,读一定是在与当前写不同的另一块缓冲区去读,在底层,可能会对同一块缓冲区的数据读取很多次,但是这并不影响人在视觉上对于画面流畅的影响。这就是通过乒乓操作实现了数据缓冲,匹配了读写两端的速度。如下图所示,

说明:1.每一个bank存储一帧图像数据,bank中每一行为图像的一行数据(即每一次读写的突发长度是一行像素数据),读和写彼此独立进行;2.bank之间的切换由状态机实现,由于读速度大于写速度,则每写完一个bank切换另一个bank去写;每读完一个bank,判断当前写bank,选择不同于写bank的bank进行读。3.由于读速度大于写速度,因此永远不会发生冲突,只是可能某一帧会被重复播放,但在视频应用中,这对用户的视觉不产生任何影响。那么问题来了,如果是读的速度小于写的速度,该如何发挥DDR3的作用呢?留给大家思考,后续的制作中会提及。

7.DDR3测试用例

以四颗MT41K512M16HA-125AIT颗粒为例,介绍如何在一块新制板卡上做关于DDR3的测试。
测试内容:除基本的读写测试之外,应对速度(如400MHz、800MHz)、容量进行测试。
测试策略:一个测试工程,对上述三项全部测试;在MIG的平面地址接口中,按照地址顺序写入确定的已知值,然后在按照相同顺序读出这些已知值做比较,相同则常亮led表示测试通过,否则led闪烁表示测试失败。应注意,当MIG app时序不正确时可能会导致app_rd_valid始终为低电平从而导致led指示灯常亮,出现错误的判断,为了避免这一情况的发生,添加led2指示已经读取了。因此只有led1与led2都常亮的情况下才能得出测试通过的结论。
4片DDR3 MIG的配置,除下图中data width应该设置为64bit外,其余均无需特殊配置。当然相应的ucf文件应含有相应管脚约束。此外,速度测试时应调整IP核中的工作频率分别为400MHz和800MHz。
测试若出现异常,应按照DDR是否初始化成功、MIG app接口时序是否正确、MIG ip配置是否正确、状态机运行状态是否异常方面入手分析。
附verilog测试代码,程序步骤解读如下:
①例化clk ip产生200MMIG参考电压输入
②例化MIG ip通过app接口读写ddr数据
③写两段式状态机,为进行容量测试,写至满容量的90%即可。写完切换至读状态,若读写无误则一直读写。Wr_addr_cnt或者rd_addr_cnt每计数一次,app_addr_begin自增8,这是因为,当工作频率配置为800MHz且用户时钟ui_clk与工作频率的比值配置为4:1时,ui_clk为200MHz。四片DDR3的数据位宽为64bit,由于”“DDR(double data rate)”,所以在每一个800MHz周期应该提供128bit数据,因此每一个200MHz周期应该向MIG提供512bit数据。而在单一内核中,每一个平面地址存储位数为16bit,四片即64bit,那512bit/64bit=8,即一个200MHz周期的512bit数据写入了8个平面地址,因此此处一次突发(即Wr_addr_cnt或者rd_addr_cnt每计数一次),app_addr_begin自增8。
该颗粒平面地址空间有16+10+3=29bit,上一段的描述提到一次突发需要8个地址,那么满容量可以进行多少次突发?即2^29(满地址)/8=67108864,将TEST_LENGTH设置为32’d60000000,即写了60000000/67108864=90%的空间,这样可以满足容量测试的要求。
④结合状态机运行状态和MIG返回的指示信号为app接口信号赋值,此处应结合各信号含义和接口时序核准。
⑤用户判错逻辑,写入和读出的都是从0开始递增的数据,当出错时指示灯闪烁。

module ddr_top(input              sys_clk,       inout  [63:0]      ddr3_dq          , inout  [7:0]       ddr3_dqs_n     , inout  [7:0]       ddr3_dqs_p     ,   output [15:0]      ddr3_addr        , output [2:0]       ddr3_ba            , output             ddr3_ras_n     , output             ddr3_cas_n     , output             ddr3_we_n      , output             ddr3_reset_n   , output [0:0]       ddr3_ck_p      , output [0:0]       ddr3_ck_n      , output [0:0]       ddr3_cke           , output [0:0]       ddr3_cs_n      , output [7:0]       ddr3_dm            , output [0:0]       ddr3_odt         , output reg         led1,              output reg         led2        );         wire                clk_rst;                            wire                clk_200;reg     [29:0]      app_addr_begin=0;wire                app_en;              //写命令使能wire    [2:0]       app_cmd;             //用户读写命令wire                app_wdf_wren;        //DDR3写使能wire                app_wdf_end;         //突发写最后一个数标识wire    [29:0]      app_addr;            //用户平面地址wire                app_rdy;             //设备接收准备就绪   wire                app_wdf_rdy;         //写响应wire    [511:0]     app_rd_data;         //用户读数据wire                app_rd_data_end;     //突发读当前时钟最后一个数据wire                app_rd_data_valid;   //读数据有效wire    [511:0]     app_wdf_data;        //用户写数据wire                app_sr_active;       //保留wire                app_ref_ack;         //刷新请求wire                app_zq_ack;          //ZQ 校准请求wire               init_calib_complete; //校准完成信号wire                ui_clk ;             //用户时钟wire                ui_clk_sync_rst;              clk_wiz_0 u_clk_wiz_0(.clk_out1(clk_200), .reset(1'b0), .locked(clk_rst), .clk_in1(sys_clk)); mig_7series_0 mig_JC (// Memory interface ports.ddr3_addr                      (ddr3_addr),        // output [15:0]    .ddr3_ba                        (ddr3_ba),          // output [2:0].ddr3_cas_n                     (ddr3_cas_n),        // output           .ddr3_ck_n                      (ddr3_ck_n),        // output [0:0]     .ddr3_ck_p                      (ddr3_ck_p),        // output [0:0]     .ddr3_cke                       (ddr3_cke),         // output [0:0]     .ddr3_ras_n                     (ddr3_ras_n),       // output       .ddr3_reset_n                   (ddr3_reset_n),     // output           .ddr3_we_n                      (ddr3_we_n),        // output       .ddr3_dq                        (ddr3_dq),          // inout [63:0] .ddr3_dqs_n                     (ddr3_dqs_n),       // inout [7:0]      .ddr3_dqs_p                     (ddr3_dqs_p),       // inout [7:0]      .init_calib_complete            (init_calib_complete),  // output       .ddr3_cs_n                      (ddr3_cs_n),        // output [0:0]     .ddr3_dm                        (ddr3_dm),          // output [7:0] .ddr3_odt                       (ddr3_odt),         // output [0:0]     // Application interface ports.app_addr                       (app_addr),        // input [29:0]        .app_cmd                        (app_cmd),           // input [2:0]     .app_en                         (app_en),            // input   .app_wdf_data                   (app_wdf_data),      // input [511:0]   .app_wdf_end                    (app_wdf_end),       // input           .app_wdf_wren                   (app_wdf_wren),      // input               .app_rd_data                    (app_rd_data),       // output [511:0]      .app_rd_data_end                (app_rd_data_end),   // output      .app_rd_data_valid              (app_rd_data_valid), // output  .app_rdy                        (app_rdy),           // output      .app_wdf_rdy                    (app_wdf_rdy),       // output          .app_sr_req                     (1'b0),             // input           .app_ref_req                    (1'b0),             // input       .app_zq_req                     (1'b0),              // input          .app_sr_active                  (app_sr_active),     // output          .app_ref_ack                    (app_ref_ack),       // output      .app_zq_ack                     (app_zq_ack),        // output      .ui_clk                         (ui_clk),            // output用户时钟输出,其实是通过IP配置自己配出来的      .ui_clk_sync_rst                (ui_clk_sync_rst),   // output     .app_wdf_mask                   (64'b0),            // input [63:0] //写数据屏蔽.sys_clk_i                      (clk_200),//输入IP的时钟// Reference Clock Ports.clk_ref_i                      (clk_200),//参考时钟     .sys_rst                        (clk_rst) // input sys_rst);parameter  TEST_LENGTH = 32'd60000000;
//**************1.先写后读状态机state machine
parameter  IDLE  = 2'd0;
parameter  WRITE = 2'd1;
parameter  WAIT  = 2'd2;
parameter  READ  = 2'd3;
reg [511:0]my_512_data;
reg [25:0] wr_addr_cnt;
reg [25:0] rd_addr_cnt;
reg [1:0]  state;always @(posedge ui_clk or negedge rst_n) beginif((~rst_n)||(error_flag)) begin state    <= IDLE;          my_512_data <= 512'd0;     wr_addr_cnt  <= 26'd0;      rd_addr_cnt  <= 26'd0;       app_addr_begin<= 30'd0;         endelse if(init_calib_complete)begin               //MIG IP核初始化完成case(state)IDLE:beginstate    <= WRITE;my_512_data <= 512'd0;   wr_addr_cnt  <= 26'd0;     rd_addr_cnt  <= 26'd0;       app_addr_begin     <= 30'd0; endWRITE:beginif((wr_addr_cnt == TEST_LENGTH-1) &&(app_rdy && app_wdf_rdy))state    <= WAIT;                  //写到设定的长度跳到等待状态else if(app_rdy && app_wdf_rdy)begin   //写条件满足my_512_data <= my_512_data + 1;  //写数据自增wr_addr_cnt  <= wr_addr_cnt + 1;   //写计数自增app_addr_begin<= app_addr_begin + 8;      //DDR3 地址自增end else begin          //写条件不满足,保持当前状态my_512_data <= my_512_data;      wr_addr_cnt  <= wr_addr_cnt;app_addr_begin<= app_addr_begin; endendWAIT:begin                                                 state   <= READ;                     //下一个时钟,跳到读状态rd_addr_cnt <= 26'd0;                //读地址复位app_addr_begin<= 30'd0;                //DDR3读从地址0endREAD:begin                               //读到设定的地址长度    if((rd_addr_cnt == TEST_LENGTH -1 ) && app_rdy)state   <= IDLE;                   //则跳到空闲状态 else if(app_rdy)begin                  //若MIG已经准备就绪,则开始读rd_addr_cnt <= rd_addr_cnt + 1'd1; //用户地址每次加一app_addr_begin    <= app_addr_begin + 8;       //DDR3地址加8end else begin   //若MIG没准备好,则保持原rd_addr_cnt <= rd_addr_cnt;app_addr_begin    <= app_addr_begin; endenddefault:beginstate    <= IDLE;my_512_data  <= 512'd0;wr_addr_cnt  <= 26'd0;rd_addr_cnt  <= 26'd0;app_addr_begin <= 30'd0;endendcaseendend
//**************2.根据状态机与MIG指示信号为app信号赋值assign app_en  =((state == WRITE && (app_rdy && app_wdf_rdy))||(state == READ && app_rdy)) ? 1'b1:1'b0;             assign app_cmd =(state == READ) ? 3'd1 :3'd0;  assign app_wdf_wren=(state == WRITE && (app_rdy && app_wdf_rdy)) ? 1'b1:1'b0;assign app_wdf_end =app_wdf_wren; assign app_addr    =app_addr_begin;assign app_wdf_data=my_512_data;
//*******************3.用户判错逻辑
reg     [25:0]   rd_cnt;
wire             rst_n;     //复位,低有效
reg              error_flag;
parameter  L_TIME = 28'd200_000_000;
reg     [27:0]   led_cnt;    //led计数
wire             error;     //读写错误标记
assign rst_n = ~ui_clk_sync_rst;//&&myrst
always @(posedge ui_clk or negedge rst_n) beginif(~rst_n) rd_cnt  <= 0;              //若计数到读写长度,且读有效,地址计数器则�?0                                    else if(app_rd_data_valid&&(rd_cnt == TEST_LENGTH - 1))rd_cnt <= 0;              //其他条件只要读有效,每个时钟自增1else if (app_rd_data_valid)rd_cnt <= rd_cnt + 1;end
//判断错误,读出数据应为计数递增数据
assign error = (app_rd_data_valid && (rd_cnt!=app_rd_data));
always @(posedge ui_clk or negedge rst_n) beginif(~rst_n)led2<=0;else if(rd_cnt==32'd50000000)led2<=1;
end
always @(posedge ui_clk or negedge rst_n) beginif(~rst_n) error_flag <= 0;else if(error)error_flag <= 1;end
//读写测试正确,指示灯led1常亮,反之则闪烁
always @(posedge ui_clk or negedge rst_n) beginif((~rst_n) || (~init_calib_complete )) beginled_cnt <= 28'd0;led1 <= 1'b0;endelse beginif(~error_flag)                              led1 <= 1'b1;                     else begin                            led_cnt <= led_cnt + 28'd1;if(led_cnt == L_TIME - 1'b1) beginled_cnt <= 25'd0;led1 <= ~led1;                     end                    endend
end
endmodule

F1--DDR3的应用总结(二)-2021.11.29相关推荐

  1. 史上最详细微信小程序授权登录与后端SprIngBoot交互操作说明,附源代码,有疑惑大家可以直接留言,蟹蟹 2021.11.29完善更新小程序代码,

    2021.11.29 更新文章 你好,我是博主宁在春,一起学习吧!!! 写这篇文章的原因,主要是因为最近在写毕业设计,用到了小程序,这中间曲曲折折,一言难尽啊.毕业设计真的让人麻脑阔

  2. 2021中石油程序设计平台新生热身赛7-挨打记录2021/11/29

    这期热身赛翘掉了,去看了院里的迎新晚会,得努力补啊...... 问题 A: 分组 时间限制: 1 Sec  内存限制: 128 MB 提交 状态 题目描述 一年一度的圣诞大联欢又要来临了.做为班长的小 ...

  3. Java学习日报—SQL基础—2021/11/29

    今天效率很低,就看了以下内容... 目录 1.1关键词DISTINCT 1.2 连表查询 1.2.1 内连接 1.2.2 外连接 1.3 查询执行顺序 1.1关键词DISTINCT DISTINCT  ...

  4. 叮~2021 CSDN年度报告已出炉;私信新增拉黑功能;创作助手支持错别字检测……【2021.12.29】

    hello,大家好,这里是「CSDN产品周报」第23期.本次更新主要涉及博客.问答及私信,欢迎大家详细了解和使用. 一.博客使用体验优化 1.优化复制按钮,复制代码无压力 优化前 优化后 2.优化博客 ...

  5. 读论文——Pre-Training with Whole Word Masking for Chinese BERT(2021 11.25)

    第一遍 标题以及作者(2021 11.25) 摘要 本文基于BERT,在RoBERTa上进行一系列改进,提出了用于中文的预训练模型MacBERT. 提出了一种新的掩码策略,MLM as correct ...

  6. 首页推荐流支持快捷修改兴趣标签,问答支持展示gif【2021.11.8】

    hello,大家好,这里是「CSDN产品周报」第17期.本次更新主要涉及首页和问答两个产品模块,具体细节请往下看. 一.首页优化 1.「推荐」信息流新增「修改兴趣标签」按钮 从用户需求的角度考虑,对内 ...

  7. 2021.11.8-11.14 AI行业周刊(第71期):AI行业经验

    篇章一:行业经验 不同的AI公司,对于AI产品的场景定位不同. 有的公司是面向C端产品.有的公司专门做B端用户. 当然大白所在的公司,也有具体的定位,主要面向智慧金融.智慧机场.智慧城市. 之前,一直 ...

  8. 第13期微生物组-宏基因组分析(线上/线下同时开课,2021.11)

    福利公告:为了响应学员的学习需求,经过易生信培训团队的讨论筹备,现决定安排扩增子16S分析.宏基因组.Python课程和转录组的线上直播课.报名参加线上直播课的老师可在1年内选择参加同课程的一次线下课 ...

  9. 微生物组-宏基因组分析(线上/线下同时开课,2021.11)

    福利公告:为了响应学员的学习需求,经过易生信培训团队的讨论筹备,现决定安排扩增子16S分析.宏基因组.Python课程和转录组的线上直播课.报名参加线上直播课的老师可在1年内选择参加同课程的一次线下课 ...

最新文章

  1. Java 内存查看与分析
  2. 离职后竟半夜偷溜回办公室写代码?一个为自由软件而战斗的程序员
  3. Thread concepts
  4. 5加载stm32 keil_KEIL 那些编辑技巧与方法
  5. vim+linux+ctags+taglist+winmanager+grep+cscope+supertab+visualmark--ctags
  6. HB-X打不开的解决办法
  7. 《Python Cookbook 3rd》笔记(5.15):打印不合法的文件名
  8. 如何dos中查看当前MySQL版本信息?
  9. 计算机二级mysql大题_2016年计算机二级MySQL练习题及答案
  10. C# Window Form解决播放amr格式音乐问题
  11. python词组语义相似度_语义相似度
  12. Leetcode刷题笔记 35.搜索插入位置(详细说明二分查找)
  13. nexus9刷机全记录
  14. 【mysql报错】Data truncation: Data too long for column ‘XXX‘ at row 1
  15. js实例之分解质因数
  16. Hotkeycontrol录制宏
  17. 如何解决flex:1撑开父元素问题
  18. codeforce_div3_round527_ABCDEF
  19. python--爬虫--爬虫学习路线指南
  20. Leek' music diary 1

热门文章

  1. 【paddlepaddle安装报错系列】DLL lond failed:找不到指定模块
  2. win7-32位系统SqlServer2014版本下载与安装
  3. BGP----工作工程,路由黑洞,防环机制,基本配置
  4. mysql 内存 优化_MySQL核心参数优化(内存优化)
  5. BGP边界网关路由协议
  6. 打印菱形图案c语言pta,C语言的考试题型
  7. Hamilton Jacobi
  8. 【.Net实用方法总结】 整理并总结System.IO中FileInfo类及其方法介绍
  9. 南方周末:股神炒股一周年祭 24万本金仅剩7千
  10. 较于微信红包,支付宝AR红包是个好产品吗?