ep1c3t144(【方法】Altera Cyclone系列的EP1C3T144C8N FPGA利用ALTASMI_PARALLEL IP核读写自身的EPCS Flash存储器「建议收藏」)

发布时间:2025-12-10 19:27:07 浏览次数:26

【方法】Altera Cyclone系列的EP1C3T144C8N FPGA利用ALTASMI_PARALLEL IP核读写自身的EPCS Flash存储器「建议收藏」-EP1C3T144C8N

【方法】Altera Cyclone系列的EP1C3T144C8N FPGA利用ALTASMI_PARALLEL IP核读写自身的EPCS Flash存储器「建议收藏」AlteraFPGA的程序是存储在外部的EPCSFlash里面的。EP1C3T144C8N的程序大小只有78422字节(76.5KB),剩余Flash空间可以用来存储其他数据。利用SerialFlashLoaderIP核,Verilog程序可以直接操作EPCSSPIFlash的片选、时钟和数据引脚,从而读写Flash数据。SPI通信协议和普通的SPIFlash(如W25Q128)差不多。不过还有更简单的方法,Quartus里面还有一个名叫ALTASMI_PARALLEL的IP核。利用这个_ep1c3144

Altera FPGA的程序是存储在外部的EPCS Flash里面的。EP1C3T144C8N的程序大小只有78422字节(76.5KB),剩余Flash空间可以用来存储其他数据。
利用Serial Flash Loader IP核,Verilog程序可以直接操作EPCS SPI Flash的片选、时钟和数据引脚,从而读写Flash数据。SPI通信协议和普通的SPI Flash(如W25Q128)差不多。
不过还有更简单的方法,Quartus里面还有一个名叫ALTASMI_PARALLEL的IP核。利用这个IP核,可以不需要实现SPI协议,直接读写SPI Flash的数据。

下面我们来尝试读取一下存储在EPCS16 SPI Flash内的前256字节数据:

module main(input clock,output uart_tx);localparam CLK_IN_FREQ = 48000000;/* 产生复位信号 */wire nrst;Reset reset(clock, nrst);/* 串口发送 */wire uart_tx_request;wire [7:0] uart_tx_data;wire uart_tx_ready;wire uart_sent;UARTTransmitter #(CLK_IN_FREQ) uart_transmitter(clock, nrst, uart_tx, uart_tx_request, uart_tx_data, uart_tx_ready, uart_sent);localparam UART_TX_MAXSIZE = 8'd32;reg [UART_TX_MAXSIZE * 8 - 1:0] uart_bytearray_tx_data;reg [1:0] uart_bytearray_tx_mode;reg uart_bytearray_tx_request;reg [7:0] uart_bytearray_tx_size;reg uart_bytearray_tx_endl;wire uart_bytearray_tx_ready;wire uart_bytearray_sent;ByteArrayTransmitter #(UART_TX_MAXSIZE) uart_bytearray_transmitter(clock, nrst, uart_tx_request, uart_tx_data, uart_tx_ready, uart_sent, uart_bytearray_tx_mode, uart_bytearray_tx_request, uart_bytearray_tx_data, uart_bytearray_tx_size, uart_bytearray_tx_endl, uart_bytearray_tx_ready, uart_bytearray_sent);/* EPCS Flash 读写 */wire altasmi_clkin;ClockDivider #(2) clock_pider(clock, nrst, altasmi_clkin);reg [23:0] altasmi_addr;reg altasmi_rden;reg altasmi_read;reg altasmi_read_rdid;reg altasmi_read_sid;wire altasmi_busy;wire altasmi_data_valid;wire [7:0] altasmi_dataout;wire [7:0] altasmi_epcs_id;wire [7:0] altasmi_rdid_out;wire [23:0] altasmi_read_address;ALTASMI_PARALLEL_0 ALTASMI_PARALLEL_0(.addr(altasmi_addr),.clkin(~altasmi_clkin),.rden(altasmi_rden),.read(altasmi_read),.read_rdid(altasmi_read_rdid),.read_sid(altasmi_read_sid),.reset(~nrst),.busy(altasmi_busy),.data_valid(altasmi_data_valid),.dataout(altasmi_dataout),.epcs_id(altasmi_epcs_id),.rdid_out(altasmi_rdid_out),.read_address(altasmi_read_address));// 交换一下位的顺序, 变成和jic文件里面一样的顺序// 注意: 编译程序, 生成*.jic文件, 用USB-Blaster固化到Flash后, 运行时串口里面的打印才和当前程序的jic文件内容一样// 不要去和rbf文件比较!rbf文件的内容和jic里面表示的Flash内容是不一样的!reg [7:0] altasmi_dataout_swapped;reg [3:0] altasmi_i;always @(*) beginfor (altasmi_i = 0; altasmi_i < 8; altasmi_i = altasmi_i + 1'b1)altasmi_dataout_swapped[altasmi_i] = altasmi_dataout[7 - altasmi_i];end// 十六进制数转字符串function reg [15:0] hex2str(input [7:0] num);beginif (num[7:4] <= 9)hex2str[15:8] = "0" + num[7:4];elsehex2str[15:8] = "a" + num[7:4] - 4'd10;if (num[3:0] <= 9)hex2str[7:0] = "0" + num[3:0];elsehex2str[7:0] = "a" + num[3:0] - 4'd10;endendfunctionlocalparam STATE_EPCS_REQ = 0;localparam STATE_EPCS_WAIT = 1;localparam STATE_UART_REQ = 2;localparam STATE_UART_WAIT = 3;reg [7:0] delay;reg [7:0] i;reg [7:0] j;reg k;reg [1:0] state;always @(posedge clock, negedge nrst) beginif (!nrst) beginaltasmi_addr <= 0;altasmi_rden <= 0;altasmi_read <= 0;altasmi_read_rdid <= 0;altasmi_read_sid <= 0;uart_bytearray_tx_request <= 0;delay <= 10;i <= 0;j <= 0;k <= 0;state <= STATE_EPCS_REQ;endelse if (delay != 0)delay <= delay - 1'b1;else begincase (state)STATE_EPCS_REQ: begincase (i)0: begin// 读IDif (!altasmi_read_rdid)altasmi_read_rdid <= 1;else if (altasmi_busy) beginaltasmi_read_rdid <= 0;state <= STATE_EPCS_WAIT;endend1: begin// 读SIDif (!altasmi_read_sid)altasmi_read_sid <= 1;else if (altasmi_busy) beginaltasmi_read_sid <= 0;state <= STATE_EPCS_WAIT;endend2: begin// 读一页 (256字节)if (!altasmi_rden) beginaltasmi_read <= 1;altasmi_rden <= 1;endelse if (altasmi_busy) beginaltasmi_read <= 0;if (!k) beginif (altasmi_data_valid) beginuart_bytearray_tx_data[{UART_TX_MAXSIZE - j - 1'b1, 3'b0}+:8] <= altasmi_dataout_swapped;if (j != UART_TX_MAXSIZE - 1'b1) beginj <= j + 1'b1;k <= 1; // 避免同一个data_valid脉冲触发多次读取endelse beginj <= 0;altasmi_rden <= 0;altasmi_addr <= altasmi_addr + UART_TX_MAXSIZE;state <= STATE_EPCS_WAIT; // 等待busy信号撤销endendendelse beginif (!altasmi_data_valid)k <= 0;endendendendcaseendSTATE_EPCS_WAIT: begincase (i)0: beginif (!altasmi_busy) beginuart_bytearray_tx_mode <= 1;uart_bytearray_tx_data <= {"ID: 0x", hex2str(altasmi_rdid_out)};uart_bytearray_tx_size <= UART_TX_MAXSIZE;uart_bytearray_tx_endl <= 1;i <= 1;state <= STATE_UART_REQ;endend1: beginif (!altasmi_busy) beginuart_bytearray_tx_mode <= 1;uart_bytearray_tx_data <= {"SID: 0x", hex2str(altasmi_epcs_id)};uart_bytearray_tx_size <= UART_TX_MAXSIZE;uart_bytearray_tx_endl <= 1;i <= 2;state <= STATE_UART_REQ;endend2: beginif (!altasmi_busy) beginuart_bytearray_tx_mode <= 2;uart_bytearray_tx_size <= UART_TX_MAXSIZE;state <= STATE_UART_REQ;if (altasmi_addr == 256) beginuart_bytearray_tx_endl <= 1;altasmi_addr <= 0;i <= 3;endelseuart_bytearray_tx_endl <= 0;endendendcaseendSTATE_UART_REQ: beginif (uart_bytearray_tx_ready) beginif (!uart_bytearray_tx_request)uart_bytearray_tx_request <= 1;endelsestate <= STATE_UART_WAIT;endSTATE_UART_WAIT: beginif (uart_bytearray_tx_ready && uart_bytearray_tx_request)uart_bytearray_tx_request <= 0; // 关闭发送请求else if (uart_bytearray_sent)state <= STATE_EPCS_REQ; // 发送完毕endendcaseendendendmodule

【正版授权,激活自己账号】:Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

module Reset(input clock,output nrst);reg [3:0] counter = 4'd15;assign nrst = (counter == 0);always @(posedge clock) beginif (!nrst)counter <= counter - 1'b1;endendmodule
module ClockDivider #(parameter N = 2)(input clk_in,input nrst,output reg clk_out);function integer clogb2(input integer depth);for (clogb2 = 0; depth > 0; clogb2 = clogb2 + 1)depth = depth >> 1;endfunctionreg [clogb2(N - 1) - 1:0] counter;always @(posedge clk_in, negedge nrst) beginif (!nrst) beginclk_out <= 0;counter <= 0;endelse if (counter == N - 1) begincounter <= 0;clk_out <= ~clk_out;endelsecounter <= counter + 1'b1;endendmodule
module UARTTransmitter #(parameter SYSCLK = 50000000,parameter BAUDRATE = 115200)(input clock, // 系统时钟input nrst, // 模块复位output reg tx, // 串口发送引脚input request, // 请求发送字符 (ready=1后应该及时撤销请求, 否则会再次发送同样的字符)input [7:0] data, // 发送的字符内容 (ready=0时必须保持不变)output ready, // 是否可以送入新字符output sent // 是否发送完毕);integer counter; // 波特率计数器reg [3:0] bit_i; // 当前正在发送第几位 (0为起始位, 1-8为数据位, 9为停止位, 10为空闲)wire bit_start = (counter == 0); // 位开始信号//wire bit_sample = (counter == SYSCLK / BAUDRATE / 2 - 1); // 接收端采样点信号wire bit_end = (counter == SYSCLK / BAUDRATE - 1); // 位结束信号/*ready引脚的真值表:bit_i   request    |  ready-------------------------------------------------------------0-8        X       |   0    (正在发送起始位和数据位)9         X       |   1    (正在发送停止位, 允许送入新字符)10         0       |   1    (空闲, 允许送入新字符)10         1       |   0    (已请求发送字符, 但还没开始发送)*/assign ready = (bit_i == 9 || sent);assign sent = (bit_i == 10 && !request);always @(posedge clock, negedge nrst) beginif (!nrst) begintx <= 1;counter <= 0;bit_i <= 10;endelse beginif (bit_i <= 9) beginif (bit_start) begincounter <= 1;if (bit_i == 0)tx <= 0; // 起始位else if (bit_i >= 1 && bit_i <= 8)tx <= data[bit_i - 1]; // 数据位elsetx <= 1; // 停止位endelse if (bit_end) begincounter <= 0;if (bit_i == 9 && request)bit_i <= 0; // 继续发送下一字符, 中间无停顿elsebit_i <= bit_i + 1'b1; // 继续发送下一位, 或停止发送endelsecounter <= counter + 1;endelse if (request)bit_i <= 0; // 开始发送elsecounter <= 0; // 空闲endendendmodule
`define BAT_MAXBIT (MAXSIZE * 8 - 1)/*** mode=0: 二进制模式**         输出数据个数为size** mode=1: 二进制模式 (用于发送字符串)**         传输时跳过所有'\0'字符, 输出数据个数小于或等于size** mode=2: 十六进制字符串模式**         将输入数据以十六进制字符串格式传输, 输出字符个数为2*size** mode=3: 十六进制字符串模式 (忽略0x00)**         传输时跳过所有为零的字节, 输出字符个数小于或等于2*size*/module ByteArrayTransmitter #(parameter MAXSIZE = 16)(input clock,input nrst,output reg byte_request,output reg [7:0] byte_out,input byte_ready,input byte_sent,input [1:0] mode, // 0:二进制模式, 1:字符串模式, 2: 十六进制字符串模式input request,input [`BAT_MAXBIT:0] data,input [7:0] size,input endl, // 是否在末尾加上"\r\n"output ready,output sent);// 当ready为高时, 允许模块外改变请求信号 (也就是mode, data和size这三项数据)// 发送过程中, ready拉高后, 本模块就停止工作了 (count已清零)// 而且ready比byte_ready后拉高, byte_ready为高时byte_out信号也可以撤销// 所以不需要缓存mode, data和size输入信号localparam STATE_LOAD = 0;localparam STATE_CHECK = 1;localparam STATE_REQUESTED = 2;localparam STATE_SENDING = 3;reg [7:0] count;reg [1:0] ending;assign ready = (count == 0 && ending == 0 && ((byte_ready && !byte_sent) || sent));assign sent = (byte_sent && !request);reg [7:0] data_c;reg i;always @(*) begincase (ending)0:data_c = data[{size - count, 3'b0}+:8];1:data_c = 8'h0d;2:data_c = 8'h0a;3:data_c = 8'h00;endcaseif (ending == 0) begincase (mode)0, 1:byte_out = data_c;2, 3: beginbyte_out = (i) ? data_c[3:0] : data_c[7:4];if (byte_out <= 9)byte_out = byte_out + "0";elsebyte_out = byte_out - 8'd10 + "A";endendcaseendelsebyte_out = data_c;endreg [1:0] state;always @(posedge clock, negedge nrst) beginif (!nrst) beginbyte_request <= 0;count <= 0;ending <= 0;state <= STATE_LOAD;endelse begincase (state)STATE_LOAD: beginif (byte_ready) beginif (count == 0 && ending == 0) beginif (byte_sent && request) begin// 开始发送i <= 0;if (size > 0 && size <= MAXSIZE) begin// 发送数据count <= 1;state <= STATE_CHECK;endelse if (size == 0 && endl) begin// 只发送换行符ending <= 1;state <= STATE_CHECK;endendendelse begin// 继续发送if ((mode == 2 || mode == 3) && ending == 0 && i == 0) begin// 继续发送另一个十六进制字符i <= 1;state <= STATE_CHECK;endelse begini <= 0;if (ending == 1) begin// 继续发送换行符ending <= 2;state <= STATE_CHECK;endelse if (count == size) begin// 数据输入结束, 但发送还没有结束if (endl && ending == 0) begin// 开始发送换行符ending <= 1;state <= STATE_CHECK;endelse begin// 发送结束, 拉高ready信号count <= 0;ending <= 0;endendelse begin// 继续发送下一个字节count <= count + 1'b1;state <= STATE_CHECK;endendendendendSTATE_CHECK: begin// 判断是否需要跳过零字符if ((mode == 1 || mode == 3) && data_c == 0)state <= STATE_LOAD;else beginbyte_request <= 1;state <= STATE_REQUESTED;endendSTATE_REQUESTED: begin// 等待发送开始if (!byte_ready)state <= STATE_SENDING;endSTATE_SENDING: begin// 等待发送结束if (byte_ready) beginbyte_request <= 0;state <= STATE_LOAD;endendendcaseendendendmodule

程序编译完成后,生成jic文件,并固化到Flash中。然后运行程序,程序的运行结果如下:

可以看到,EPCS16的Silicon ID为0x14,读出来的前256字节的数据和jic文件里面的一模一样。(注意程序里面做了位翻转)

值得注意的是,不要去和rbf文件比较。rbf文件的内容和jic文件的内容通常是不一样的。我们用USB-Blaster下载器下载进去的是jic文件,应该用jic文件去比较。
甚至,编译时自动生成的rbf文件(可在Device and Pin Options对话框里面勾选)的内容和Convert Programming Files菜单命令里面Generate的rbf文件内容也不一样!

需要做网站?需要网络推广?欢迎咨询客户经理 13272073477