基于FPGA的AD5753(DAC数模转换器)的控制 II(SPI驱动)

2024-06-08 01:28

本文主要是介绍基于FPGA的AD5753(DAC数模转换器)的控制 II(SPI驱动),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

基于FPGA的AD5753(DAC数模转换器)的控制 II(已上板验证)

语言 :Verilg HDL
EDA工具:Vivado

      • 基于FPGA的AD5753(DAC数模转换器)的控制 II(已上板验证)
        • 一、引言
        • 二、基于FPGA的AD5753控制驱动实现
          • 1. 顶层模块
          • 2. 数据控制模块(AD5753_DATA_Ctrl模块)
          • 3、gen_crc8校验模块
        • 三、结尾

  • 关键词: AD5753 驱动,Verilog HDL,SPI驱动,DAC数模转换器,上板已验证成功
一、引言

本次分享DAC(AD5753) SPI驱动控制器的FPGA实现,可以借鉴到大部分DAC或者ADC的SPI驱动控制,是上篇基于FPGA的AD5753(DAC数模转换器)的控制 I(SPI驱动)文章的续篇。主要包括DAC(AD5753) FPGA的工程实现,仿真以及上板调试,实现了对DAC芯片的寄存器读写控制。

二、基于FPGA的AD5753控制驱动实现
1. 顶层模块

顶层模块代码如下所示,主要包括
(1)AD5753驱动模块:AD5753_driver模块负责与AD5753 DAC通信,发送数据和触发信号。
(2)数据控制模块:AD5753_DATA_Ctrl模块生成要发送给DAC的数据,并控制数据发送。
(3)逻辑分析仪(ILA):ila实例用于监视和记录信号,以便于调试。
(4)虚拟输入输出(VIO):vio_0实例用于虚拟探针,可以观察或驱动信号。

clk_wiz_0实例用于生成50MHz的时钟信号clk_50m,并且locked信号表示时钟锁定状态。dac_reset_n输出端口被设置为locked,用于DAC的复位。

module test_ADC5753(input           sys_clk,input           fault_n,output           sdi, // to ac5753output          sclk,input           sdo,  // from ad5753output          dac_reset_n,output          sync_n,   output          ldac_n,output          led);wire [32:0]   send_data;wire          send_trig;wire [32:0]   spi_rx_dat;wire          spi_rx_int;wire          send_done ;//wire          spi_clk_i2;wire          spi_clk_i;wire          locked;wire          clk_50m;wire          dat_gen_en;wire [15:0]   data;clk_wiz_0 clk_wiz_inst(.clk_out2(clk_50m),     .clk_out1( ),     .locked  (locked  ),      .clk_in1 (sys_clk    )     //50M);  assign  dac_reset_n = locked;assign  led = 1'b0; reg[4:0] cnt;   reg  clk_1M;always@(posedge clk_50m or negedge locked) beginif(!locked) begincnt = 5'b0;clk_1M = 1'b0;endelse beginif(cnt == 5'd24 ) beginclk_1M = !clk_1M;cnt = 5'd0;endelse begincnt = cnt +5'b1;endendendAD5753_driver AD5753_driver (.clk(clk_50m), .dac_reset_n(locked), .fault_n(fault_n), .send_data(send_data), .send_trig(send_trig), .send_done(send_done), .spi_clk_i(clk_1M),.spi_rx_dat(spi_rx_dat), .spi_rx_int(spi_rx_int), .ldac_n(ldac_n), .spi_clk(sclk), .sync_n(sync_n), .spi_mosi(sdi), .spi_miso(sdo));   AD5753_DATA_Ctrl AD5753_DATA_Ctrl (.clk(clk_50m), .spi_clk_i(clk_1M), .locked(locked), .data(data),.send_done(send_done), .send_trig(send_trig), .send_data(send_data), .dat_gen_en(1'b1), .spi_rx_int(spi_rx_int), .spi_rx_dat(spi_rx_dat));ila ila_inst (.clk(clk_50m), // input wire clk.probe0(send_data), // input wire [23:0]  probe0  .probe1(send_trig), // input wire [0:0]  probe1 .probe2(spi_rx_dat), // input wire [23:0]  probe2 .probe3(spi_rx_int), // input wire [0:0]  probe3 .probe4(send_done), // input wire [0:0]  probe4 .probe5(locked), // input wire [0:0]  probe5 .probe6(dac_reset_n), // input wire [0:0]  probe6 .probe7(fault_n), // input wire [0:0]  probe7 .probe8(sdi), // input wire [0:0]  probe8 .probe9(sclk), // input wire [0:0]  probe9 .probe10(sync_n), // input wire [0:0]  probe10 .probe11(ldac_n), // input wire [0:0]  probe11 .probe12(sdo) // input wire [0:0]  probe12
);vio_0 vio_0 (.clk(clk_50m),                // input wire clk.probe_in0( ),    // input wire [0 : 0] probe_in0.probe_out0(),  // output wire [0 : 0] probe_out0.probe_out1(data)  // output wire [0 : 0] probe_out0 
);endmodule
2. 数据控制模块(AD5753_DATA_Ctrl模块)

AD5753_DATA_Ctrl 模块,设计用于控制与AD5753数字到模拟转换器(DAC)的数据传输。通过定义一系列的输入输出端口、内部状态、计数器和标志位来实现对数据发送过程的精确控制。
模块内部实现了一个状态机,通过不同的状态(如 DATA_IDLE、DATA_FAULT、DATA_Key 等)来管理数据传输流程。状态机根据当前状态和输入信号(例如 dat_gen_en、send_done)来决定下一个状态,并通过 spi_clk_i 来同步数据的发送。
模块还包括了CRC校验逻辑,通过 gen_crc8 子模块生成数据的CRC校验码,确保数据传输的可靠性。在不同的状态下,模块会设置相应的发送触发信号 send_trig 和发送数据 send_data,以及实现特定操作的500us延时,从而完成对AD5753 DAC的命令设置和数据更新。

module AD5753_DATA_Ctrl(input            clk,        //50Minput            spi_clk_i,input            locked,input            send_done,output   reg        send_trig,output [31:0]    send_data,input            dat_gen_en,input           spi_rx_int,input [15:0]    data,input  [31:0]   spi_rx_dat);// device adress   localparam[2:0] DEVICE_ADRESS=3'b011;   // registerlocalparam[4:0] NOP=5'h00;localparam[4:0] Key=5'h00;   //   STATElocalparam[4:0] DATA_IDLE  =    5'd0;localparam[4:0] DATA_FAULT  =   5'd1;     localparam[4:0] DATA_Key   =    5'd2;  localparam[4:0] DATA_Key_wait = 5'd3;       localparam[4:0] DATA_CLEAR =    5'd4; localparam[4:0] DATA_REQ =      5'd5;     localparam[4:0] DATA_DC_SET =   5'd6;       localparam[4:0] DATA_DC_SET_WAIT =  5'd7; localparam[4:0] DATA_DC_MOD =       5'd8;       localparam[4:0] DATA_DC_MOD_WAIT =  5'd9;     localparam[4:0] DATA_DAC_SET =      5'd10;                  localparam[4:0] DATA_DAC_SET_WAIT = 5'd11; localparam[4:0] DATA_DAC_MOD =      5'd12;   localparam[4:0] DATA_DAC_MOD_WAIT = 5'd13;    localparam[4:0] DATA_LDAC =         5'd14;      localparam[4:0] DATA_OUTPUT =       5'd15;localparam[4:0] DATA_REQ_DAC =      5'd16;   localparam[4:0] DATA_REQ_DAC_WAIT = 5'd17;       localparam[4:0] DAC_read =          5'd18;localparam[4:0] DAC_nop =           5'd19;               reg [13:0]       cnt_500us;reg              FLAG;reg [4:0]        state;reg [4:0]        next_state;reg             send_trig_tem;reg [23:0]      send_data_tem;reg             spi_clk_dly;wire            spi_clk_pos;wire            spi_clk_neg;   reg             send_done_dly;wire            send_done_pos;reg             FLAG2;wire[7:0]      nextCRC8_D24;wire           crc_out_en;reg [15:0]       data_reg;reg [15:0]       data_reg2;  always @ ( posedge spi_clk_i ) beginif( ~locked ) begindata_reg <= 16'b0;data_reg2 <= 16'b0;endelse begindata_reg <= data;data_reg2 <= data_reg; endend  always @ ( posedge spi_clk_i ) beginif( ~locked )state <= DATA_IDLE;else state <= next_state; endalways @ (*) beginif( ~locked )	next_state = DATA_IDLE;else case ( state )DATA_IDLE:       if( dat_gen_en )next_state = DATA_FAULT;else next_state = DATA_IDLE; DATA_FAULT:          if( send_done )  next_state = DATA_Key;else next_state = DATA_FAULT;                            DATA_Key:if( send_done )  next_state = DATA_Key_wait;else next_state = DATA_Key;                          DATA_Key_wait:if( FLAG ) next_state = DATA_CLEAR;else next_state = DATA_Key_wait;  DATA_CLEAR:if( send_done ) next_state = DATA_REQ;else next_state = DATA_CLEAR; DATA_REQ:if( send_done ) next_state = DATA_DC_SET;else next_state = DATA_REQ;                     DATA_DC_SET:if( send_done ) next_state = DATA_DC_SET_WAIT;else next_state = DATA_DC_SET;                       DATA_DC_SET_WAIT:if( FLAG ) next_state = DATA_DC_MOD;else next_state = DATA_DC_SET_WAIT; DATA_DC_MOD:if( send_done ) next_state = DATA_DC_MOD_WAIT;else next_state = DATA_DC_MOD;                     DATA_DC_MOD_WAIT:if( FLAG ) next_state = DATA_DAC_SET;else next_state = DATA_DC_MOD_WAIT;                    DATA_DAC_SET:if( send_done ) next_state = DATA_DAC_SET_WAIT;else next_state = DATA_DAC_SET;                       DATA_DAC_SET_WAIT:if( FLAG ) next_state = DATA_LDAC ;else next_state = DATA_DAC_SET_WAIT;     
//             DATA_DAC_MOD:
//                  if( send_done ) 
//                     next_state = DATA_DAC_MOD_WAIT ;
//                  else 
//                     next_state = DATA_DAC_MOD;                     
//             DATA_DAC_MOD_WAIT:
//                  if( FLAG ) 
//                     next_state = DATA_LDAC ;
//                  else 
//                     next_state = DATA_DAC_MOD_WAIT;                      DATA_LDAC:if( send_done ) next_state =  DATA_OUTPUT ;else next_state = DATA_LDAC;   DATA_OUTPUT:if( send_done ) next_state =  DATA_REQ_DAC ;else next_state = DATA_OUTPUT;                      DATA_REQ_DAC:if( send_done) next_state =  DATA_REQ_DAC_WAIT ;else next_state = DATA_REQ_DAC;  DATA_REQ_DAC_WAIT:       if( FLAG ) next_state =  DATA_LDAC ;else next_state = DATA_REQ_DAC_WAIT;                                                                                                     DAC_read:if( send_done ) next_state = DAC_nop;else next_state = DAC_read;                     DAC_nop:if( send_done ) next_state = DATA_REQ_DAC;else next_state = DAC_nop;                       default :next_state = DATA_IDLE; endcaseendalways @ ( posedge clk ) beginif(~locked) beginspi_clk_dly <= 1'b0;send_done_dly <= 1'b0;endelse beginspi_clk_dly <=spi_clk_i;send_done_dly <= send_done;      endendassign spi_clk_neg = spi_clk_dly && ~spi_clk_i;
assign spi_clk_pos = (~spi_clk_dly )&& spi_clk_i;
assign send_done_pos =( ~send_done_dly) && send_done;
reg[7:0] nextCRC8_D24_tem;
//assign send_trig =crc_out_en;
assign send_data ={send_data_tem,nextCRC8_D24_tem};always@( posedge clk) beginif( ~locked ) beginsend_trig <= 1'b0;nextCRC8_D24_tem <=8'b0;endif(crc_out_en) beginsend_trig <= 1'b1;nextCRC8_D24_tem <= nextCRC8_D24;endelse if(send_done)send_trig <= 1'b0;   elsesend_trig <=send_trig;endalways @ ( posedge clk ) beginif( ~locked ) beginsend_trig_tem <= 1'b0;send_data_tem <= 24'b0;endelse beginif( state == DATA_IDLE && ~send_done ) beginsend_trig_tem <= 1'b0;send_data_tem <= 24'b0; endelse if( state == DATA_FAULT && ~send_done  ) beginsend_trig_tem <= 1'b1;send_data_tem <= {DEVICE_ADRESS,5'h10,16'h005c};    //   end       else if( state == DATA_Key  && ~send_done) beginsend_trig_tem <= 1'b1;send_data_tem <= {DEVICE_ADRESS,5'h08,16'hFCBA};         endelse if( state == DATA_CLEAR && ~send_done  ) beginsend_trig_tem <= 1'b1;send_data_tem <= {DEVICE_ADRESS,5'h14,16'h2000};    //     endelse if( state == DATA_REQ && ~send_done ) beginsend_trig_tem <= 1'b1;send_data_tem <= {DEVICE_ADRESS,5'h09,16'h0644};        endelse if( state == DATA_DC_SET && ~send_done ) beginsend_trig_tem <= 1'b1;send_data_tem <= {DEVICE_ADRESS,5'h0C,16'h010E};        end   else if( state == DATA_DC_MOD && ~send_done ) beginsend_trig_tem <= 1'b1;send_data_tem <= {DEVICE_ADRESS,5'h0B,16'h0020};        end    else if( state == DATA_DAC_SET && ~send_done ) beginsend_trig_tem <= 1'b1;send_data_tem <= {DEVICE_ADRESS,5'h06,16'h01a8};        end   else if( state == DATA_DAC_MOD && ~send_done ) beginsend_trig_tem <= 1'b1;send_data_tem <= {DEVICE_ADRESS,5'h01,16'h0000};        end    else if( state == DATA_LDAC && ~send_done ) beginsend_trig_tem <= 1'b1;send_data_tem <= {DEVICE_ADRESS,5'h07,16'h1DAC};        end   else if( state == DATA_OUTPUT && ~send_done ) beginsend_trig_tem <= 1'b1;send_data_tem <= {DEVICE_ADRESS,5'h06,16'h01E8};       //D6 = 1end    else if( state == DATA_REQ_DAC && ~send_done ) beginsend_trig_tem <= 1'b1;send_data_tem <= {DEVICE_ADRESS,5'h01,data_reg2};        end            else if( state == DAC_read && ~send_done ) beginsend_trig_tem <= 1'b1;send_data_tem <= {DEVICE_ADRESS,5'h13,16'h02};     //读output寄存器  endelse if( state == DAC_nop && ~send_done ) beginsend_trig_tem <= 1'b1;send_data_tem <= {DEVICE_ADRESS,NOP,16'h00};        end   else   beginsend_trig_tem <= 1'b0;   endendend// 延时500usalways@( posedge spi_clk_i or negedge locked)beginif( ~locked)  begincnt_500us <= 14'b0;FLAG <= 1'b0;endelse beginif(state == DATA_Key_wait ) beginif(cnt_500us == 14'd1010 ) begincnt_500us <= 1'b1;FLAG  <= 1'b1;endelse begincnt_500us <= cnt_500us +14'b1;FLAG <= 1'b0;endend  else if(state == DATA_DC_SET_WAIT ) beginif(cnt_500us == 14'd1010 ) begincnt_500us <= 1'b0;FLAG  <= 1'b1;endelse begincnt_500us <= cnt_500us +14'b1;FLAG <= 1'b0;endend        else if(state == DATA_DC_MOD_WAIT ) beginif(cnt_500us == 14'd1010 ) begincnt_500us <= 1'b0;FLAG  <= 1'b1;endelse begincnt_500us <= cnt_500us +14'b1;FLAG <= 1'b0;endend           else if(state == DATA_REQ_DAC_WAIT ) beginif(cnt_500us == 14'd16 ) begincnt_500us <= 1'b0;FLAG  <= 1'b1;endelse begincnt_500us <= cnt_500us +14'b1;FLAG <= 1'b0;endend   else if(state == DATA_DAC_SET_WAIT ) beginif(cnt_500us == 14'd1010 ) begincnt_500us <= 1'b0;FLAG  <= 1'b1;endelse begincnt_500us <= cnt_500us +14'b1;FLAG <= 1'b0;endend          else if(state == DATA_DAC_MOD_WAIT ) beginif(cnt_500us == 14'd16 ) begincnt_500us <= 1'b0;FLAG  <= 1'b1;endelse begincnt_500us <= cnt_500us +14'b1;FLAG <= 1'b0;endend         else beginFLAG  <= 1'b0; endend  endgen_crc8 gen_crc8 (.clk(clk), .rst_n(locked), .crc_in_en(send_trig_tem), .Data(send_data_tem), .nextCRC8_D24(nextCRC8_D24), .crc_out_en(crc_out_en));endmodule
3、gen_crc8校验模块

gen_crc8 的模块用于生成8位循环冗余校验(CRC)码,模块包含时钟输入 clk,复位信号 rst_n,CRC输入使能 crc_in_en,待处理数据 Data(24位宽),以及CRC校验码输出 nextCRC8_D24 和输出使能 crc_out_en。
模块使用一个寄存器 crc_in_en_d0 来检测 crc_in_en 的边沿,即从0到1的跳变,这通常表示一个新数据块的到来。
在检测到 crc_in_en 的上升沿后,模块根据输入数据 Data 和当前的CRC寄存器值 nextCRC8_D24 来计算新的CRC校验码。CRC的计算使用了一系列异或(XOR)操作,这些操作定义了CRC的多项式。

`timescale 1ns / 1psmodule gen_crc8(input clk,
input rst_n,input crc_in_en,
input [23:0] Data,
output reg [7:0] nextCRC8_D24,
output reg crc_out_en);reg crc_in_en_d0=0;always @(posedge clk or negedge rst_n)beginif(!rst_n)crc_in_en_d0 <= 1'b0;elsecrc_in_en_d0 <= crc_in_en;
end      always @(posedge clk or negedge rst_n)beginif(!rst_n)nextCRC8_D24 <= 'd0;else if(!crc_in_en_d0 && crc_in_en)begin    nextCRC8_D24[0] <= Data[23] ^ Data[21] ^ Data[19] ^ Data[18] ^ Data[16] ^ Data[14] ^ Data[12] ^ Data[8] ^ Data[7] ^ Data[6] ^ Data[0] ^ nextCRC8_D24[0] ^ nextCRC8_D24[2] ^ nextCRC8_D24[3] ^ nextCRC8_D24[5] ^ nextCRC8_D24[7];nextCRC8_D24[1] <= Data[23] ^ Data[22] ^ Data[21] ^ Data[20] ^ Data[18] ^ Data[17] ^ Data[16] ^ Data[15] ^ Data[14] ^ Data[13] ^ Data[12] ^ Data[9] ^ Data[6] ^ Data[1] ^ Data[0] ^ nextCRC8_D24[0] ^ nextCRC8_D24[1] ^ nextCRC8_D24[2] ^ nextCRC8_D24[4] ^ nextCRC8_D24[5] ^ nextCRC8_D24[6] ^ nextCRC8_D24[7];nextCRC8_D24[2] <= Data[22] ^ Data[17] ^ Data[15] ^ Data[13] ^ Data[12] ^ Data[10] ^ Data[8] ^ Data[6] ^ Data[2] ^ Data[1] ^ Data[0] ^ nextCRC8_D24[1] ^ nextCRC8_D24[6];nextCRC8_D24[3] <= Data[23] ^ Data[18] ^ Data[16] ^ Data[14] ^ Data[13] ^ Data[11] ^ Data[9] ^ Data[7] ^ Data[3] ^ Data[2] ^ Data[1] ^ nextCRC8_D24[0] ^ nextCRC8_D24[2] ^ nextCRC8_D24[7];nextCRC8_D24[4] <= Data[19] ^ Data[17] ^ Data[15] ^ Data[14] ^ Data[12] ^ Data[10] ^ Data[8] ^ Data[4] ^ Data[3] ^ Data[2] ^ nextCRC8_D24[1] ^ nextCRC8_D24[3];nextCRC8_D24[5] <= Data[20] ^ Data[18] ^ Data[16] ^ Data[15] ^ Data[13] ^ Data[11] ^ Data[9] ^ Data[5] ^ Data[4] ^ Data[3] ^ nextCRC8_D24[0] ^ nextCRC8_D24[2] ^ nextCRC8_D24[4];nextCRC8_D24[6] <= Data[21] ^ Data[19] ^ Data[17] ^ Data[16] ^ Data[14] ^ Data[12] ^ Data[10] ^ Data[6] ^ Data[5] ^ Data[4] ^ nextCRC8_D24[0] ^ nextCRC8_D24[1] ^ nextCRC8_D24[3] ^ nextCRC8_D24[5];nextCRC8_D24[7] <= Data[22] ^ Data[20] ^ Data[18] ^ Data[17] ^ Data[15] ^ Data[13] ^ Data[11] ^ Data[7] ^ Data[6] ^ Data[5] ^ nextCRC8_D24[1] ^ nextCRC8_D24[2] ^ nextCRC8_D24[4] ^ nextCRC8_D24[6];end
endalways @(posedge clk)begincrc_out_en <= !crc_in_en_d0 && crc_in_en;
end  endmodule

这个模块是数据传输中确保数据完整性的一个重要组件,通过CRC校验可以检测数据在传输过程中是否出现错误。如果CRC校验失败,系统可以采取相应的措施来纠正或重新发送数据。

三、结尾

本文主要描述如何使用FPGA驱动DAC芯片AD5753,已经在开发板上验证成功。使得配置完成之后,可以正常的控制dac的输出。

这篇关于基于FPGA的AD5753(DAC数模转换器)的控制 II(SPI驱动)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1040860

相关文章

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统         在产品将要上线之前,需要制作不同类型格式的根文件系统         在产品研发阶段,我们还是需要使用nfs的方式挂载根文件系统         优点:可以直接在上位机中修改文件系统内容,延长EMMC的寿命         【1】重启上位机nfs服务         sudo service nfs-kernel-server resta

【STM32】SPI通信-软件与硬件读写SPI

SPI通信-软件与硬件读写SPI 软件SPI一、SPI通信协议1、SPI通信2、硬件电路3、移位示意图4、SPI时序基本单元(1)开始通信和结束通信(2)模式0---用的最多(3)模式1(4)模式2(5)模式3 5、SPI时序(1)写使能(2)指定地址写(3)指定地址读 二、W25Q64模块介绍1、W25Q64简介2、硬件电路3、W25Q64框图4、Flash操作注意事项软件SPI读写W2

AI基础 L9 Local Search II 局部搜索

Local Beam search 对于当前的所有k个状态,生成它们的所有可能后继状态。 检查生成的后继状态中是否有任何状态是解决方案。 如果所有后继状态都不是解决方案,则从所有后继状态中选择k个最佳状态。 当达到预设的迭代次数或满足某个终止条件时,算法停止。 — Choose k successors randomly, biased towards good ones — Close

从0到1,AI我来了- (7)AI应用-ComfyUI-II(进阶)

上篇comfyUI 入门 ,了解了TA是个啥,这篇,我们通过ComfyUI 及其相关Lora 模型,生成一些更惊艳的图片。这篇主要了解这些内容:         1、哪里获取模型?         2、实践如何画一个美女?         3、附录:               1)相关SD(稳定扩散模型的组成部分)               2)模型放置目录(重要)

STM32(十一):ADC数模转换器实验

AD单通道: 1.RCC开启GPIO和ADC时钟。配置ADCCLK分频器。 2.配置GPIO,把GPIO配置成模拟输入的模式。 3.配置多路开关,把左面通道接入到右面规则组列表里。 4.配置ADC转换器, 包括AD转换器和AD数据寄存器。单次转换,连续转换;扫描、非扫描;有几个通道,触发源是什么,数据对齐是左对齐还是右对齐。 5.ADC_CMD 开启ADC。 void RCC_AD

控制反转 的种类

之前对控制反转的定义和解释都不是很清晰。最近翻书发现在《Pro Spring 5》(免费电子版在文章最后)有一段非常不错的解释。记录一下,有道翻译贴出来方便查看。如有请直接跳过中文,看后面的原文。 控制反转的类型 控制反转的类型您可能想知道为什么有两种类型的IoC,以及为什么这些类型被进一步划分为不同的实现。这个问题似乎没有明确的答案;当然,不同的类型提供了一定程度的灵活性,但

学习记录:js算法(二十八):删除排序链表中的重复元素、删除排序链表中的重复元素II

文章目录 删除排序链表中的重复元素我的思路解法一:循环解法二:递归 网上思路 删除排序链表中的重复元素 II我的思路网上思路 总结 删除排序链表中的重复元素 给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。 图一 图二 示例 1:(图一)输入:head = [1,1,2]输出:[1,2]示例 2:(图

深入解析秒杀业务中的核心问题 —— 从并发控制到事务管理

深入解析秒杀业务中的核心问题 —— 从并发控制到事务管理 秒杀系统是应对高并发、高压力下的典型业务场景,涉及到并发控制、库存管理、事务管理等多个关键技术点。本文将深入剖析秒杀商品业务中常见的几个核心问题,包括 AOP 事务管理、同步锁机制、乐观锁、CAS 操作,以及用户限购策略。通过这些技术的结合,确保秒杀系统在高并发场景下的稳定性和一致性。 1. AOP 代理对象与事务管理 在秒杀商品

PostgreSQL中的多版本并发控制(MVCC)深入解析

引言 PostgreSQL作为一款强大的开源关系数据库管理系统,以其高性能、高可靠性和丰富的功能特性而广受欢迎。在并发控制方面,PostgreSQL采用了多版本并发控制(MVCC)机制,该机制为数据库提供了高效的数据访问和更新能力,同时保证了数据的一致性和隔离性。本文将深入解析PostgreSQL中的MVCC功能,探讨其工作原理、使用场景,并通过具体SQL示例来展示其在实际应用中的表现。 一、