当前位置:网站首页>FPGA基于spi的flash读写
FPGA基于spi的flash读写
2022-07-23 16:41:00 【qq_44985628】
一、SPI
SPI的通信原理很简单,它以主从方式工作,这种模式通常有一个主设备和一个或多个从设备,需要至少4根线,事实上3根也可以(单向传输时)。也是所有基于SPI的设备共有的,它们是MISO(主设备数据输入)、MOSI(主设备数据输出)、SCLK(时钟)、CS(片选)。
(1)MISO– Master Input Slave Output,主设备数据输入,从设备数据输出;
(2)MOSI– Master Output Slave Input,主设备数据输出,从设备数据输入;
(3)SCLK – Serial Clock,时钟信号,由主设备产生;
(4)CS – Chip Select,从设备使能信号,由主设备控制。

二、看spi–flash手册找关键
1.描述
16Mbit的存储空间
单扇区擦除或者整块擦除
用spi协议与flash读写
2.flash接口信号

C是串行时钟
D是数据
S是片选信号
3.SPI模式选择
flash只支持mode0和mode3两种模式

CPOL时钟相位
时钟的极性(CPOL)用来决定在总线空闲时,同步时钟(SCK)信号线上的电位是高电平还是低电平。当时钟极性为0时(CPOL=0),SCK信号线在空闲时为低电平;当时钟极性为1时(CPOL=1),SCK信号线在空闲时为高电平;
CPHA时钟极性
当时钟相位为1时(CPHA=1),在SCK信号线的第二个跳变沿进行采样;这里的跳变沿究竟是上升沿还是下降沿?取决于时钟的极性。当时钟极性为0时,取下降沿;当时钟极性为1时,取上升沿
CPOL=0,CPHA=0
4.高字节MSB
MSB先,就是高字节先
5.指令

6. 写使能时序
7.读ID时序
8.读寄存器时序(我没用到)
判断WIP BIT是否为0才能进行下一步(我的代码里没有用到)
9.读数据时序
10.页编程
11.扇区擦除
12.重要的时间
三、状态机设计
1.spi接口状态机
2.flash读状态机
3.flash写状态机
四、代码部分
1.spi_interface.v
module spi_interface(
input clk,
input rst_n,
// 接口与主机
input [7:0] din,
input req,
output [7:0] dout,
output done,
// 接口与flash
input miso,// 主机采样从机发送
output mosi,// 主机发送从机
output sclk,// 串行时钟
output cs_n // 片选信号
);
parameter CPHA = 1,// 空闲状态高电平
CPOL = 1;// 下降沿发送,上升沿采样
// 16分频或8分频或4分频 不能2分频
parameter SCLK = 16,
SCLK_BEFORE = SCLK/4,
SCLK_AFTER = SCLK*3/4;
// 状态机
localparam IDLE = 4'b0001,
WAIT = 4'b0010,
DATA = 4'b0100,
DONE = 4'b1000;
reg [3:0] state_c;
reg [3:0] state_n;
wire idle2wait;
wire wait2data;
wire data2done;
wire done2idle;
// bit计数器
reg [2:0] cnt_bit;
wire add_cnt_bit;
wire end_cnt_bit;
// 分频串行时钟计数器
reg [4:0] cnt_sclk;
wire add_cnt_sclk;
wire end_cnt_sclk;
// 寄存要发送的数据
reg spi_sclk;
reg [7:0] rx_data;
reg [7:0] tx_data;
reg spi_cn_n;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
state_c <= IDLE;
end
else begin
state_c <= state_n;
end
end
always @(*)begin
case (state_c)
IDLE :begin
if(idle2wait)begin
state_n = WAIT;
end
else begin
state_n = state_c;
end
end
WAIT :begin
if(wait2data)begin
state_n = DATA;
end
else begin
state_n = state_c;
end
end
DATA :begin
if(data2done)begin
state_n = DONE;
end
else begin
state_n = state_c;
end
end
DONE :begin
if(done2idle)begin
state_n = IDLE;
end
else begin
state_n = state_c;
end
end
default: state_n = IDLE;
endcase
end
assign idle2wait = state_c == IDLE && (req);
assign wait2data = state_c == WAIT && (1'b1);
assign data2done = state_c == DATA && (end_cnt_bit);
assign done2idle = state_c == DONE && (1'b1);
// bit计数器
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_bit <= 0;
end
else if(add_cnt_bit)begin
if(end_cnt_bit)begin
cnt_bit <= 0;
end
else begin
cnt_bit <= cnt_bit + 1;
end
end
else begin
cnt_bit <= cnt_bit;
end
end
assign add_cnt_bit = end_cnt_sclk;
assign end_cnt_bit = add_cnt_bit && cnt_bit == 8 - 1;
// sclk计数器
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_sclk <= 0;
end
else if(add_cnt_sclk)begin
if(end_cnt_sclk)begin
cnt_sclk <= 0;
end
else begin
cnt_sclk <= cnt_sclk + 1;
end
end
else begin
cnt_sclk <= cnt_sclk;
end
end
assign add_cnt_sclk = (state_c == DATA);
assign end_cnt_sclk = add_cnt_sclk && cnt_sclk == SCLK - 1;
// 16分频串行时钟 CPHA=1,CPOL=1
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
if(CPHA == 0)begin
spi_sclk <= 1'b0;
end
else if(CPHA == 1)begin
spi_sclk <= 1'b1;
end
end
else if(add_cnt_sclk && cnt_sclk == SCLK_BEFORE - 1)begin
if(CPHA == 0)begin
spi_sclk <= 1'b1;
end
else if(CPHA == 1)begin
spi_sclk <= 1'b0;
end
end
else if(add_cnt_sclk && cnt_sclk == SCLK_AFTER - 1)begin
if(CPHA == 0)begin
spi_sclk <= 1'b0;
end
else if(CPHA == 1)begin
spi_sclk <= 1'b1;
end
end
end
// 发送的数据mosi 高位MSB先 CPHA=1,CPOL=1
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
tx_data <= 0;
end
else if(CPOL == 0)begin
if(add_cnt_sclk && cnt_sclk == SCLK_AFTER - 1)begin
tx_data <= din;
end
end
else if(CPOL == 1)begin
if(add_cnt_sclk && cnt_sclk == SCLK_BEFORE - 1)begin
tx_data <= din;
end
end
end
// 接收的数据miso 高位MSB先 CPHA=1,CPOL=1
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
rx_data <= 0;
end
else if(CPOL == 0)begin
if(add_cnt_sclk && cnt_sclk == SCLK_BEFORE - 1)begin
rx_data[7-cnt_bit] <= miso;
end
end
else if(CPOL == 1)begin
if(add_cnt_sclk && cnt_sclk == SCLK_AFTER - 1)begin
rx_data[7-cnt_bit] <= miso;
end
end
end
assign mosi = tx_data[7-cnt_bit];
assign sclk = spi_sclk;
assign cs_n = ~req;
assign dout = rx_data;
assign done = (state_c == DONE);
endmodule
2.spi_read_ctrl.v
module spi_read_ctrl(
input clk,
input rst_n,
input [2:0] key_out,
input [7:0] din,
input done,
output reg req,
output [7:0] dout,
output reg [23:0] seg_data
);
localparam RDID_CMD = 8'h9F,// 读ID指令
RDDA_CMD = 8'h03,// 读数据指令
RDDA_ADD = 24'h0;// 读数据地址
localparam IDLE = 7'b000_0001,
RDIDCMD = 7'b000_0010,
RDID = 7'b000_0100,
RDDACMD = 7'b000_1000,
RDDAADD = 7'b001_0000,
RDDATA = 7'b010_0000,
DONE = 7'b100_0000;
reg [6:0] state_c;
reg [6:0] state_n;
wire idle2rdidcmd ;
wire idle2rddacmd ;
wire rdidcmd2rdid ;
wire rdid2done ;
wire rddacmd2rddaadd;
wire rddaadd2rddata ;
wire rddata2done ;
wire done2idle ;
// 字节计数器
reg [2:0] cnt_byte;
wire add_cnt_byte;
wire end_cnt_byte;
// 读id和读数据请求
reg rdid_req;
reg rdda_req;
reg [7:0] tx_data;
// 状态机
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
state_c <= IDLE;
end
else begin
state_c <= state_n;
end
end
always @(*)begin
case (state_c)
IDLE :begin
if(idle2rdidcmd)begin
state_n = RDIDCMD;
end
else if(idle2rddacmd)begin
state_n = RDDACMD;
end
else begin
state_n = state_c;
end
end
RDIDCMD :begin
if(rdidcmd2rdid)begin
state_n = RDID;
end
else begin
state_n = state_c;
end
end
RDID :begin
if(rdid2done)begin
state_n = DONE;
end
else begin
state_n = state_c;
end
end
RDDACMD :begin
if(rddacmd2rddaadd)begin
state_n = RDDAADD;
end
else begin
state_n = state_c;
end
end
RDDAADD :begin
if(rddaadd2rddata)begin
state_n = RDDATA;
end
else begin
state_n = state_c;
end
end
RDDATA :begin
if(rddata2done)begin
state_n = DONE;
end
else begin
state_n = state_c;
end
end
DONE :begin
if(done2idle)begin
state_n = IDLE;
end
else begin
state_n = state_c;
end
end
default: state_n = IDLE;
endcase
end
assign idle2rdidcmd = state_c == IDLE && (rdid_req);
assign idle2rddacmd = state_c == IDLE && (rdda_req);
assign rdidcmd2rdid = state_c == RDIDCMD && (end_cnt_byte);
assign rdid2done = state_c == RDID && (end_cnt_byte);
assign rddacmd2rddaadd = state_c == RDDACMD && (end_cnt_byte);
assign rddaadd2rddata = state_c == RDDAADD && (end_cnt_byte);
assign rddata2done = state_c == RDDATA && (end_cnt_byte);
assign done2idle = state_c == DONE && (1'b1);
// 字节计数器
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_byte <= 0;
end
else if(add_cnt_byte)begin
if(end_cnt_byte)begin
cnt_byte <= 0;
end
else begin
cnt_byte <= cnt_byte + 1;
end
end
else begin
cnt_byte <= cnt_byte;
end
end
assign add_cnt_byte = (state_c != IDLE) && done;
assign end_cnt_byte = add_cnt_byte && cnt_byte == (((state_c == RDIDCMD) || (state_c == RDDACMD) || (state_c == RDDATA))?(1-1):(3-1));
// 读id和读数据请求
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
rdid_req <= 0;
rdda_req <= 0;
req <= 0;
end
else if(key_out[0])begin
rdid_req <= 1'b1;
req <= 1'b1;
end
else if(key_out[1])begin
rdda_req <= 1'b1;
req <= 1'b1;
end
else if(state_c == DONE)begin
req <= 1'b0;
rdid_req <= 1'b0;
rdda_req <= 1'b0;
end
end
// 指令
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
tx_data <= 0;
end
else if(idle2rdidcmd)begin
tx_data <= RDID_CMD;
end
else if(idle2rddacmd)begin
tx_data <= RDDA_CMD;
end
else if(rddacmd2rddaadd)begin
tx_data <= RDDA_ADD;
end
end
// seg_data
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
seg_data <= 0;
end
else if(state_c == RDID && add_cnt_byte)begin
case(cnt_byte)
0 : seg_data[23:16] <= din;
1 : seg_data[15:8] <= din;
2 : seg_data[7:0] <= din;
default: seg_data <= seg_data;
endcase
end
else if(state_c == RDDATA && add_cnt_byte)begin
case(cnt_byte)
0 : seg_data[23:16] <= din;
default: seg_data <= seg_data;
endcase
end
else begin
seg_data <= seg_data;
end
end
// assign req = rdid_req || rdda_req;
assign dout = tx_data;
endmodule
3.spi_write_ctrl.v
module spi_write_ctrl(
input clk,
input rst_n,
input [2:0] key_out,
input [7:0] din,
input done,
output req,
output [7:0] dout
);
parameter CMD_TIME = 10,// 第一个指令到下一个指令200ns等待时间
PP_TIME = 250_000,// PP可编程时间5ms
SE_TIME = 150_000_000;// SE擦除时间3s
parameter WREN_CMD = 8'h06,
SE_CMD = 8'hD8,
SE_ADD = 24'h000000,
RDSR_CMD = 8'h05,
PP_CMD = 8'h02,
PP_ADD = 24'h000000,
DATA = 8'h78;
// 状态机
localparam IDLE =10'b00000_00001,
FIRWRENCMD =10'b00000_00010,
SECMD =10'b00000_00100,
SEADD =10'b00000_01000,
RDSRCMD =10'b00000_10000,
SECWRENCMD =10'b00001_00000,
PPCMD =10'b00010_00000,
PPADD =10'b00100_00000,
PPDATA =10'b01000_00000,
DONE =10'b10000_00000;
reg [9:0] state_c;
reg [9:0] state_n;
wire idle2firwrencmd ;
wire firwrencmd2secmd ;
wire secmd2seadd ;
wire seadd2rdsrcmd ;
wire rdsrcmd2secwrencmd ;
wire secwrencmd2ppcmd ;
wire ppcmd2ppadd ;
wire ppadd2ppdata ;
wire ppdata2done ;
wire done2idle ;
// 字节计数器
reg [1:0] cnt_byte;
wire add_cnt_byte;
wire end_cnt_byte;
// 100ms一个命令到下一个命令的等待时间
reg [3:0] cnt_200ns;
wire add_cnt_200ns;
wire end_cnt_200ns;
// se擦除等待时间
reg [27:0] cnt_3s;
wire add_cnt_3s;
wire end_cnt_3s;
// pp页编程等待时间
// reg cnt_5ms;
// wire add_cnt_5ms;
// wire end_cnt_5ms;
// 一个命令到下一个命令的等待标志
reg delay_flag;
// 寄存req
reg req_r;
// 寄存要发送的数据
reg [7:0] tx_data;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
state_c <= IDLE;
end
else begin
state_c <= state_n;
end
end
always @(*)begin
case (state_c)
IDLE :begin
if(idle2firwrencmd)begin
state_n = FIRWRENCMD;
end
else begin
state_n = state_c;
end
end
FIRWRENCMD :begin
if(firwrencmd2secmd)begin
state_n = SECMD;
end
else begin
state_n = state_c;
end
end
SECMD :begin
if(secmd2seadd)begin
state_n = SEADD;
end
else begin
state_n = state_c;
end
end
SEADD :begin
if(seadd2rdsrcmd)begin
state_n = RDSRCMD;
end
else begin
state_n = state_c;
end
end
RDSRCMD :begin
if(rdsrcmd2secwrencmd)begin
state_n = SECWRENCMD;
end
else begin
state_n = state_c;
end
end
SECWRENCMD :begin
if(secwrencmd2ppcmd)begin
state_n = PPCMD;
end
else begin
state_n = state_c;
end
end
PPCMD :begin
if(ppcmd2ppadd)begin
state_n = PPADD;
end
else begin
state_n = state_c;
end
end
PPADD :begin
if(ppadd2ppdata)begin
state_n = PPDATA;
end
else begin
state_n = state_c;
end
end
PPDATA :begin
if(ppdata2done)begin
state_n = DONE;
end
else begin
state_n = state_c;
end
end
DONE :begin
if(done2idle)begin
state_n = IDLE;
end
else begin
state_n = state_c;
end
end
default: state_n = IDLE;
endcase
end
assign idle2firwrencmd = state_c == IDLE && (key_out[2]);
assign firwrencmd2secmd = state_c == FIRWRENCMD && (end_cnt_200ns);
assign secmd2seadd = state_c == SECMD && (end_cnt_byte);
assign seadd2rdsrcmd = state_c == SEADD && (end_cnt_3s);
assign rdsrcmd2secwrencmd = state_c == RDSRCMD && (end_cnt_200ns);
assign secwrencmd2ppcmd = state_c == SECWRENCMD && (end_cnt_200ns);
assign ppcmd2ppadd = state_c == PPCMD && (end_cnt_byte);
assign ppadd2ppdata = state_c == PPADD && (end_cnt_byte);
assign ppdata2done = state_c == PPDATA && (end_cnt_byte);
assign done2idle = state_c == DONE && (1'b1);
// 字节计数器
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_byte <= 0;
end
else if(add_cnt_byte)begin
if(end_cnt_byte)begin
cnt_byte <= 0;
end
else begin
cnt_byte <= cnt_byte + 1;
end
end
else begin
cnt_byte <= cnt_byte;
end
end
assign add_cnt_byte = ((state_c != IDLE) && done);
assign end_cnt_byte = add_cnt_byte && cnt_byte == (((state_c == FIRWRENCMD) || (state_c == SECMD) || (state_c == RDSRCMD) || (state_c == SECWRENCMD) || (state_c == PPCMD) || (state_c == PPDATA))?(1-1):(3-1));
// 100ms一个命令到下一个命令的等待时间计数器
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_200ns <= 0;
end
else if(add_cnt_200ns)begin
if(end_cnt_200ns)begin
cnt_200ns <= 0;
end
else begin
cnt_200ns <= cnt_200ns + 1;
end
end
else begin
cnt_200ns <= cnt_200ns;
end
end
assign add_cnt_200ns = (((state_c == FIRWRENCMD) || (state_c == RDSRCMD) || (state_c == SECWRENCMD)) && delay_flag);
assign end_cnt_200ns = add_cnt_200ns && cnt_200ns == CMD_TIME - 1;
// SE擦除时间2s
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_3s <= 0;
end
else if(add_cnt_3s)begin
if(end_cnt_3s)begin
cnt_3s <= 0;
end
else begin
cnt_3s <= cnt_3s + 1;
end
end
else begin
cnt_3s <= cnt_3s;
end
end
assign add_cnt_3s = ((state_c == SEADD) && delay_flag);
assign end_cnt_3s = add_cnt_3s && cnt_3s == SE_TIME - 1;
// 一个命令到下一个命令的等待延长标志
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
delay_flag <= 0;
end
else if(end_cnt_byte)begin
delay_flag <= 1'b1;
end
else if(end_cnt_200ns || end_cnt_3s)begin
delay_flag <= 1'b0;
end
else begin
delay_flag <= delay_flag;
end
end
// req信号
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
req_r <= 1'b0;
end
else if(idle2firwrencmd)begin
req_r <= 1'b1;
end
else if((state_c == FIRWRENCMD) && end_cnt_byte)begin
req_r <= 1'b0;
end
else if(firwrencmd2secmd)begin
req_r <= 1'b1;
end
else if(secmd2seadd)begin
req_r <= 1'b1;
end
else if((state_c == SEADD) && end_cnt_byte)begin
req_r <= 1'b0;
end
else if(seadd2rdsrcmd)begin
req_r <= 1'b1;
end
else if((state_c == RDSRCMD) && end_cnt_byte)begin
req_r <= 1'b0;
end
else if(rdsrcmd2secwrencmd)begin
req_r <= 1'b1;
end
else if((state_c == SECWRENCMD) && end_cnt_byte)begin
req_r <= 1'b0;
end
else if(secwrencmd2ppcmd)begin
req_r <= 1'b1;
end
else if(ppcmd2ppadd)begin
req_r <= 1'b1;
end
else if(ppadd2ppdata)begin
req_r <= 1'b1;
end
else if(ppdata2done)begin
req_r <= 1'b0;
end
end
// dout传输的数据
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
tx_data <= 0;
end
else if(state_c == FIRWRENCMD)begin
tx_data <= WREN_CMD;
end
else if(state_c == SECMD)begin
tx_data <= SE_CMD;
end
else if(state_c == SEADD)begin
tx_data <= SE_ADD;
end
else if(state_c == RDSRCMD)begin
tx_data <= RDSR_CMD;
end
else if(state_c == SECWRENCMD)begin
tx_data <= WREN_CMD;
end
else if(state_c == PPCMD)begin
tx_data <= PP_CMD;
end
else if(state_c == PPADD)begin
tx_data <= PP_ADD;
end
else if(state_c == PPDATA)begin
tx_data <= DATA;
end
end
assign req = req_r;
assign dout = tx_data;
endmodule
4.spi_control.v
module spi_control(
input clk,
input rst_n,
input [2:0] key_out,
input [7:0] din,
input done,
output [7:0] dout,
output req,
output [23:0] seg_data
);
wire rd_req;
wire wr_req;
wire [7:0] rd_tx_data;
wire [7:0] wr_tx_data;
assign req = rd_req | wr_req;
assign dout = ({
8{
rd_req}} & rd_tx_data) | ({
8{
wr_req}} & wr_tx_data);
// 读控制模块
spi_read_ctrl u_spi_read_ctrl(
/* input */.clk (clk ),
/* input */.rst_n (rst_n ),
/* input [2:0] */.key_out (key_out ),
/* input [7:0] */.din (din ),
/* input */.done (done ),
/* output */.req (rd_req ),
/* output [7:0] */.dout (rd_tx_data),
/* output reg [23:0]*/.seg_data(seg_data)
);
// 写控制模块
spi_write_ctrl u_spi_write_ctrl(
/* input */.clk (clk ),
/* input */.rst_n (rst_n ),
/* input [2:0] */.key_out (key_out),
/* input [7:0] */.din (din ),
/* input */.done (done ),
/* output */.req (wr_req ),
/* output [7:0] */.dout (wr_tx_data)
);
endmodule
5.top.v
module top(
input clk,
input rst_n,
input [2:0] key_in,
output [7:0] seg_dig,
output [5:0] seg_sel,
input miso,// 主机采样从机发送
output mosi,// 主机发送从机
output sclk,// 串行时钟
output cs_n // 片选信号
);
wire [2:0] key_out;
wire req;
wire done;
wire [7:0] rx_data;
wire [7:0] tx_data;
wire [23:0] seg_data;
// 按键消抖模块
key_filter u_key_filter(
/* input */.clk (clk ),
/* input */.rst_n (rst_n ),
/* input [KEY_W-1:0] */.key_in (key_in ),
/* output reg [KEY_W-1:0] */.key_out (key_out)
);
// 数码管驱动
seg_driver u_seg_driver(
/* input */.clk (clk ),
/* input */.rst_n (rst_n ),
/* input [23:0] */.data (seg_data),
/* output reg [7:0] */.seg_dig (seg_dig),
/* output reg [5:0] */.seg_sel (seg_sel)
);
spi_control u_spi_control(
/* input */.clk (clk ),
/* input */.rst_n (rst_n ),
/* input [2:0] */.key_out (key_out ),
/* input [7:0] */.din (rx_data ),
/* input */.done (done ),
/* output [7:0] */.dout (tx_data ),
/* output */.req (req ),
/* output [23:0] */.seg_data (seg_data)
);
spi_interface u_spi_interface(
/* input */.clk (clk ),
/* input */.rst_n (rst_n),
/* // 接口与主机 */
/* input [7:0] */.din (tx_data),
/* input */.req (req ),
/* output [7:0] */.dout (rx_data ),
/* output */.done (done ),
/* // 接口与flash */
/* input */.miso (miso ),// 主机采样从机发送
/* output */.mosi (mosi ),// 主机发送从机
/* output */.sclk (sclk ),// 串行时钟
/* output */.cs_n (cs_n ) // 片选信号
);
endmodule
6.其他模块
按键消抖模块
数码管驱动模块
边栏推荐
- 1259. Programmation dynamique de poignée de main disjointe
- Error reporting caused by the use of responsebodyadvice interface and its solution
- Where should we start to learn modeling from zero foundation? How to learn game modeling well?
- [2020] [paper notes] new terahertz detection - Introduction to terahertz characteristics, various terahertz detectors
- Detailed explanation: tmp1750 chip three channel linear LED driver
- [whole process of game modeling model production] ZBrush weapon model production: Crossbow
- [2020] [paper notes] optically controlled spectral ratio adjustable y based on two-dimensional photonic crystal——
- MySql【从了解到掌握 一篇就够】
- 如何成为建模师?工业建模和游戏建模哪一个更加吃香?
- 代码整洁,高效的系统方法
猜你喜欢

【重磅】聚焦券商终端业务,博睿数据发布新一代券商终端核心业务体验可观测平台

自学3D建模能不能成功?自学能就业吗?

Google正在改进所有产品中的肤色表现 践行“图像公平”理念

Crack WiFi password with Kail

As a senior 3D modeler, I give some suggestions to novice learning partners to use

作为3D资深建模师给刚入门学习伙伴的一些建议,用起来

基于 softether 搭建虚拟私有网络

How to become a modeler? Which is more popular, industrial modeling or game modeling?

Error reporting caused by the use of responsebodyadvice interface and its solution

Google is improving the skin color performance in all products and practicing the concept of "image fairness"
随机推荐
[whole process of game modeling model production] 3ds Max and ZBrush produce radio receivers
Gradle [graphic installation and use demonstration]
PCL:多直線擬合(RANSAC)
并非原创的原文路径【如有侵权 请原博主联系删除】
As a senior 3D modeler, I give some suggestions to novice learning partners to use
识别引擎ocropy-&gt;ocropy2-&gt;OCRopus3总结
建模刚学习很迷茫,次世代角色建模流程具体该怎么学习?
[2013] [paper notes] terahertz band nano particle surface enhanced Raman——
Multithreading and high concurrency Day11
Can self-study 3D modeling succeed? Can self-study lead to employment?
Foundation of class
入行3D建模有前景吗?就业高薪有保障还是副业接单赚钱多
【论文阅读】GETNext: Trajectory Flow Map Enhanced Transformer for Next POI Recommendation
ROS (27): the simple use of rosparam and the unsuccessful transfer of parameters through launch and its solution
[sharing 3D modeling and production skills] how ZBrush turns pictures into relief models
【2020】【论文笔记】基于Rydberg原子的——
Great God "magic change" airpods, equipped with usb-c interface, 3D printing shell makes maintenance easier
如何成为建模师?工业建模和游戏建模哪一个更加吃香?
PCL: multi line fitting (RANSAC)
[2020] [paper notes] new terahertz detection - Introduction to terahertz characteristics, various terahertz detectors



