02-12-2018 01:14 AM
Hi,
I am referring the BRAM example code that is available in Xilinx Vivado. I want to use BRAM with dual port such that PL compute some data and store it to some address location, from Port_in on PORT A of BRAM and PS can read that address and fetch data at its out pin on PORT B of BRAM..
I have simulated the code on Vivado to access the data on BRAM from PL end but I am confused that what changes I will have to perform to access it from PS and where should I write PS code to access BRAM specific address and sense the data out from BRAM output port to read it on PS and use that BRAM data in other computation..
If there's any demo code or any reference guide to refer and access the data written from PL to BRAM and access on PS then it will be helpful...
Thanks,
Dhara
03-04-2019 12:06 AM
I can see my memory contents..now..!did a mistake ..you can see 0a3d70a3,and 0e560618,values..in the middle
03-04-2019 02:02 AM
ok...i got ..it Poll means ..reading the address of the AXI GPIO...in Which the DONE signal is provided.and reading that Address through.. SDK..am i right?....if thats the case..can you give one example on how to write 'C' code for AXI gpio...initiazation,control..of signals and so on...
THANKS in advance @ronnywebers
03-04-2019 02:40 AM - edited 03-04-2019 02:42 AM
there's a few tutorials that you could go through :
1) Creating a custom IP block in Vivado
this one will learn you a lot, also the SDK side on how to talk to AXI registers (AXI GPIO is just a bunch of registers too).
this one I just searched on youtube with 'Vivado AXI GPIO', there's probably more of them :
2) Zedboard getting started with VIVADO and SDK Switch Buttons and Led Interfacing with AXI GPIO IP
3) This is a very good tutorial on the Zedboard, but a bit more complicated : https://github.com/Architech-Silica/Zynq-Zedboard-Vivado-Workshop
03-04-2019 03:30 AM
Thanks for the quick reply...can u please follow me up on PL part ...which u mentioned to share FSM,TB and RAM.
THANKS @ronnywebers
03-04-2019 05:10 AM
here DIN and address..are seen is whereas..dout is 0
03-04-2019 05:20 AM
try to put all signals of the bram on the ILA (we, en, ...), and make sure to inspect the write and read cycles. Is your WE toggling at the right moment, is your EN = '1', is the reset low, ... -> check every signal
03-05-2019 03:31 AM
hi,couldnt see the dout signal...we= 0 and en = 1...but dout is showing as zero...sir ..i knwo the gpio way u justed...is easy..but iam not getting..it..that is the part where i have to implement c code...its showing 32 bit 0 as out...can u suggest me a normal way ..in which i can configure via PL itself.that is use GO,rest as switches..and done as an led ..without use of axi GPIO..please help..the GPIO way..has given me a headache...please help..also..please verify this simulation, thanks @ronny webers
03-05-2019 05:04 AM
@sam007 , I think you try to go to fast ... did you go through the tutorials I gave you? Did you do these step by step? I think you first should go through some written out tutorials, that you know will work, try to understand these first, before you try to build something yourself.
the 3 tutorials I gave you are really helpfull, I learned from these before I tried something myself.
I searched on youtube for 'vivado bram simulation', and found for example these:
https://www.youtube.com/watch?v=pDw3MEoQF9Y
https://www.youtube.com/watch?v=SGvYkA87W20
https://www.youtube.com/watch?v=gfpE81yMBwQ
these will help you understand how a BRAM works, how to instantiate it, how to simulate it. With Vivado and Verilog, you must start simple, and understand every step. You might think you're going slow then, but it's the only way to learn it. And go for the Verilog book I gave you (Pong P. Chu).
03-06-2019 10:27 PM
hi,should the done,go,and reset..be 32 bit..and should i take create ports for go,reset...
03-06-2019 10:29 PM
iam sorry ..should i create ports like this!go signal is given to gpio..in which port is taken out and another gpio for reset
03-06-2019 10:35 PM
or just keep it like this..thanks @ronnywebers
03-06-2019 11:46 PM
sir,a favour can you re assess..my FSM code!i want to test it on true dual port block ram...just tell me ..the write and enable in my code...which i have wriiten....is it triggered at the right time? THANKS @ronnywebers
module FSM_DATA_ADDR_GENERATOR( input wire SYSCLK, input wire RESET, input wire GO, input wire RESET_SIGNAL, output wire WE, output wire EN, output wire DONE, output wire [9:0]ADDRESS, output wire[31:0]DATA_IN ); //////////////////////////////////////////////////////////////////// reg WE_SIG = 1'b0; reg EN_SIG = 1'b0; reg DONE_SIG = 1'b0; reg [9:0]ADDRESS_SIG = {3'b100,7'b0000000}; reg [31:0]DATA_IN_SIG = 32'h00000000; reg [1:0]STATE = 2'b00; ///////////////////////////////////////////////////////////////////////// parameter IDLE = 2'b00; parameter INCREMENT = 2'b01; parameter STOP_STATE = 2'b10; //////////////////////////////////////////////////////////////////////// assign WE = WE_SIG; assign EN = EN_SIG; assign ADDRESS = ADDRESS_SIG; assign DONE = DONE_SIG; assign DATA_IN = DATA_IN_SIG; ///////////////////////////////////////////////////////////////////////// always@(posedge SYSCLK) begin if(RESET) begin STATE <= IDLE; end else begin case(STATE) IDLE: begin if(RESET_SIGNAL == 0) STATE <= INCREMENT; else begin WE_SIG <= 1'b1; DONE_SIG <= 1'b0; EN_SIG <= 1'b1; ADDRESS_SIG <= {3'b100,7'b0000000}; DATA_IN_SIG <= 32'h00000000; STATE <= IDLE; end end INCREMENT: begin begin WE_SIG <= 1'b0; EN_SIG <= 1'b0; DONE_SIG <= 1'b0; ADDRESS_SIG <= ADDRESS_SIG + {7'b0000000,3'b100}; DATA_IN_SIG <= DATA_IN_SIG + 32'h04040404; STATE <= INCREMENT; end if(GO == 1) STATE <= STOP_STATE; end STOP_STATE: begin begin WE_SIG <= 1'b1; EN_SIG <= 1'b1; DONE_SIG <= 1'b1; DATA_IN_SIG <= 32'h0a3d70a3; ADDRESS_SIG <= {7'b0000000,3'b101}; STATE <= STOP_STATE; end if(RESET_SIGNAL == 1) STATE <= IDLE; end default: begin WE_SIG <= 1'b0; EN_SIG <= 1'b0; ADDRESS_SIG <= {3'b100,7'b0000000}; DATA_IN_SIG <= 32'h00000000; STATE <= IDLE; end endcase end end endmodule
03-07-2019 01:27 AM
@sam007 it's probably cleaner to use the 'slice' IP in the block diagram to split the 32-bit port of the GPIO into a few separate signals. Note that the 'concat' IP does the inverse of 'slice'.
about your FSM : please check UG901 - Synthesis first for the recommended coding of an FSM in Verilog. you can find a simple example in chapter 4, under FSM -> fsm_1.vhd
Notice how they don't use 'begin' and 'end' in UG901 ... -> get rid of this first, as IMHO it only pollutes your code and makes it less readable. Also try to use proper indentation, it's important to avoid mistakes. Use either all spaces or all tabs to indent, that probably helps alignment in a code snippet in a forum post.
Also notice in the fsm example that there is no 'default' section in that example template, they define all the output signals in every state. I guess a default state is legal in Verilog, but as they don't use it in the example template, I would start without one.. try to stay close to the UG901 recommended way of coding.
Also notice that you don't define your output signals during a reset -> again, take a look at UG901 ...
always@(posedge SYSCLK) begin if(RESET) begin STATE <= IDLE; ------------------> define all your outputs here too !!! <------------------------ end else begin case(STATE)
also try to use easy readable 'data' and 'address values' during test / simulation, like for example somewhere you use 'h0a3d70a3' -> I'd use 'h11223344' or 'h12345678' or something more readable in the simulator.
03-07-2019 03:53 AM
everything is fine apart from the fact that at start of dout ..i get x...what is that ..iam not able to figure..out..maybe memory should be initialized to some value!!!!but through text file i tried...it is showing as unknown..only in the first read...iam getting that issue...after that data in dout is valid...attched the waveform
THANKS @ronnywebers
03-07-2019 04:49 AM
@ronnywebers wrote:@sam007 it's probably cleaner to use the 'slice' IP in the block diagram to split the 32-bit port of the GPIO into a few separate signals. Note that the 'concat' IP does the inverse of 'slice'.
about your FSM : please check UG901 - Synthesis first for the recommended coding of an FSM in Verilog. you can find a simple example in chapter 4, under FSM -> fsm_1.vhd
Notice how they don't use 'begin' and 'end' in UG901 ... -> get rid of this first, as IMHO it only pollutes your code and makes it less readable. Also try to use proper indentation, it's important to avoid mistakes. Use either all spaces or all tabs to indent, that probably helps alignment in a code snippet in a forum post.
Also notice in the fsm example that there is no 'default' section in that example template, they define all the output signals in every state. I guess a default state is legal in Verilog, but as they don't use it in the example template, I would start without one.. try to stay close to the UG901 recommended way of coding.
Also notice that you don't define your output signals during a reset -> again, take a look at UG901 ...
always@(posedge SYSCLK) begin if(RESET) begin STATE <= IDLE; ------------------> define all your outputs here too !!! <------------------------ end else begin case(STATE)
also try to use easy readable 'data' and 'address values' during test / simulation, like for example somewhere you use 'h0a3d70a3' -> I'd use 'h11223344' or 'h12345678' or something more readable in the simulator.
here...i saw in a forum ..that we can assign values to memory..which prevents the dout going to x....thats good..but i want to assign for 1024 values!..how to do that? Sir i have extended this thread iam sorry for that...but here in my company..they have also put their hands up in terms of support...and this forum and your helps keeps me going..so THANKS @ronnywebers
03-07-2019 06:39 AM
I can see the 0x12345678 in your memory, 'something' is happening, but it's zoomed out where your simulation is actually writing, so I can't see the detals (where go goes to '1')
the easiest way to initialize them would be through a file I think, you should find that using google. Apparently it's also possible using code, see here
did you cleanup your FSM? did you correct the unasigned signals when you are resetting? did you compare your code with UG901?
you could make your memory much smaller to start with, like 16 entries, that way you can put 16 values in a file and read these in, instead of 1024. Once your whole system works, you can expand. Start simple.
I'd cleanup your fsm first. Clean code is the start of everything. Then post it here again.
in the testbench I can see you generate 2 resets : keep it simple, generate 1 clean reset, get rid of that second one. Also try and make the 'EN' line permanently '1', I don't think you should be toggling it anyway, not sure on what hardware you are, but in general EN works as follows:
'EN' : when inactive (= zero), no data is written to the block RAM and the output bus remains in its previous state.
03-11-2019 05:50 AM
hello sir,my spec has changed a little bit,it is as follows
1).In a Dual Port Ram for PORTB ....Generate an Address in this case at Address Location 0,assert "Read operation" and Collect Data_out at Port B.
2.) Then Generate an Address in this case, Address location 1,Put data inside the Data_in,and Assert "Write operation".
Thanks @ronnywebers
03-13-2019 10:36 PM
Accept as Solution....
03-14-2019 07:12 AM
@sam007 do you mean everything works fine now?
03-15-2019 04:40 AM
yeah it does..actually..got some change in spec..and some help...and the objective was to copy the memory ...That is write from PS and read from PL.
03-15-2019 05:07 AM
I have a question please need some help with this!!!....I have an SPI Module...in which i use to Run via FPGA Switches...First switch 1 would have loaded an inital frequency of 100mhz... and switch 2 would commence Frequency Hopping..from 100 mhz to 140mhz to 200 mhz to 330mhz...and then when in switch 3 it would go back to init 100mhz frequency again......
Now the spec given to me is as follows use a 32 bit internal register instead of these "SWITCHES" .......and when this 32 bit register....the Bit[0] -> 0(Falling Edge),the it should perform the operation of Switch 1
Next the 32 bit register..when Bit[1] -> 1(Rising Edge) then it should perform the Switch 2 operation ie; Frequency Hopping...
next the 32 bit Register ..when bit[2] -> 0 (Falling Edge),then it should perform the switch 3 operation..that is init DDS...same as switch 1
Here instead of using Switches...the PS will write the values to Port A(PS) and Port B(PL) will read those values
I TRIED TO USE reg[0] == 0
{Edge_det_sig[0]} == 1'b0,{Edge_det_sig[1]} == 1'b1..in PL..design...no effect..what should i do...for this kind of spec? i have attached the code please..
module Spi_Mod( input wire sysclk, output wire sclk, output wire sig1ms_sig, output wire cs, output wire[3:0]functional_pins, output wire master_reset, output wire io_update, output wire [2:0]ps, output wire[31:0] Edge_det, output mosi ); ////////////////////////////////////////////////////////////////////////////////////// parameter [2:0]idle_state = 3'b000; parameter [2:0]master_reset_state = 3'b001; parameter [2:0]wait_state = 3'b010; parameter [2:0]data_state = 3'b011; parameter [2:0]repeat_state = 3'b100; parameter [2:0]update_state = 3'b101; parameter [2:0]stop_state = 3'b110; ///////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// reg sclk_reg = 1'b0; reg cs_reg = 1'b1; reg [3:0]func_pins = 4'b0001; reg master_reset_reg = 1'b0; reg io_update_reg = 1'b0; reg [2:0]ps_reg = 3'b000; reg mosi_reg = 1'b0; reg [2:0]state = 3'b000; reg [2:0]update_cntr = 3'b000; reg [39:0]data = 40'd0; reg [5:0]cnt = 6'd0; reg [2:0]freq_cnt = 3'b000; reg [39:0]freq_ch = 40'd0; reg sig1ms = 1'b0; reg [31:0]Edge_det_sig = 32'h00000000;///for edge detect Ps logic. reg [31:0]cnt_1ms = 32'd0; /////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// assign sclk = sclk_reg; assign cs = cs_reg; assign functional_pins = func_pins; assign master_reset = master_reset_reg; assign io_update = io_update_reg; assign ps = ps_reg; assign sig1ms_sig = sig1ms; assign Edge_det = Edge_det_sig; assign mosi = mosi_reg; ////////////////////////////////////////// ////////////////////////////////////////////////// always @(posedge sysclk) begin if(cnt_1ms == 32'd100000)//1ms logic begin cnt_1ms <= 0; sig1ms <= 1; end else begin cnt_1ms <= cnt_1ms + 1; sig1ms <= 0; end case(state) idle_state: begin if({Edge_det_sig[0]} == 1'b0) begin state <= master_reset_state; data <= {8'h00,32'h0001010a}; end else if({Edge_det_sig[0]} == 1'b1) begin func_pins <= 4'b0001;//Serial_state io_update_reg <= 1'b0; master_reset_reg <= 1'b0; ps_reg <= 3'b000; sclk_reg <= 1'b0; cs_reg <= 1'b1; state <= idle_state; end end master_reset_state: begin func_pins <= 4'b0001;//Serial_state io_update_reg <= 1'b0; master_reset_reg <= 1'b1; ps_reg <= 3'b000; sclk_reg <= 1'b0; cs_reg <= 1'b1; state <= wait_state; end wait_state: begin func_pins <= 4'b0001; io_update_reg <= 1'b0; master_reset_reg <= 1'b0; ps_reg <= 3'b000; sclk_reg <= 1'b0; cs_reg <= 1'b0; state <= data_state; end data_state: begin func_pins <= 4'b0001; io_update_reg <= 1'b0; master_reset_reg <= 1'b0; ps_reg <= 3'b000; sclk_reg <= 1'b0; cs_reg <= 1'b0; mosi_reg <= {data[39]};//msb sent 1st to MOSI output. state <= repeat_state; end repeat_state: begin func_pins <= 4'b0001; io_update_reg <= 1'b0; master_reset_reg <= 1'b0; ps_reg <= 3'b000; sclk_reg <= 1'b1; cs_reg <= 1'b0; data <= {data[38:0],1'b0}; if(cnt > 6'd38) state <= update_state; else begin cnt <= cnt + 1; state <= data_state; end end update_state: begin func_pins <= 4'b0001; ps_reg <= 3'b000; cs_reg <= 1'b0; master_reset_reg<= 1'b0; io_update_reg <= 1'b1; sclk_reg <= 1'b0; cnt <= 6'd0; update_cntr <= update_cntr + 1; data <= freq_ch; if(update_cntr == 3'b000) begin data <= {8'h03,32'h01052120}; state <= wait_state; end if(update_cntr == 3'b001) begin data <= {8'h03,32'h00052120}; state <= wait_state; end else if(update_cntr == 3'b010) begin data <= {8'h01,32'h00800900}; state <= wait_state; end else if(update_cntr == 3'b011) begin data <= {8'h0c,32'h0fd70000}; state <= wait_state; end else if(update_cntr == 3'b100) begin data <= {8'h0b,32'h0a3d70a3};//amplitude with init freq,ie 100mhz state <= wait_state; update_cntr <= 3'b110; end else if(update_cntr == 3'b101) begin io_update_reg <= 1'b0; data <= freq_ch; state <= wait_state; end else if(update_cntr == 3'b110) begin mosi_reg <= 1'b0; state <= stop_state; end end stop_state: begin state <= stop_state; update_cntr <= 3'b000; io_update_reg <= 1'b0; master_reset_reg <= 1'b0; ps_reg <= 3'b000; sclk_reg <= 1'b0; cs_reg <= 1'b1; mosi_reg <= 1'b0; func_pins <= 4'b0001;//serial_state if({Edge_det_sig[0]} == 1'b0) begin state <= master_reset_state; data <= {8'h00,32'h0001010a};//amplitude phase update_cntr <= 3'b100; end else if({Edge_det_sig[0]} == 1'b0) begin freq_ch <= 40'h0; state <= stop_state; end if({Edge_det_sig[1]} == 1'b1 ) begin if(sig1ms == 1) begin freq_cnt <= freq_cnt + 1; if(freq_cnt == 3'b000) begin update_cntr <= 3'b101; freq_ch <= {8'h0b,32'h0e560418};// 140 mhz state <= update_state; end if(freq_cnt == 3'b001) begin update_cntr <= 3'b101; freq_ch <= {8'h0b,32'h147ae147}; //200 mhz state <= update_state; end if(freq_cnt == 3'b010) begin update_cntr <= 3'b101; freq_ch <= {8'h0b,32'h20c49ba5};//320 mhz state <= update_state; end if(freq_cnt == 3'b011) begin update_cntr <= 3'b101; freq_ch <= {8'h0b,32'h2219652b};//333 mhz state <= update_state; freq_cnt <= 3'b000; end else if({Edge_det_sig[1]} == 1'b0) begin update_cntr <= 3'b101; freq_ch <= {8'h0b,32'h0e560418};// init freq in hopping that is 140 mhz state <= update_state; freq_cnt <= 3'b000; end end end if({Edge_det_sig[0]} == 1'b0) begin update_cntr <= 3'b101; freq_ch <= {8'h0b,32'h0e560418}; state <= update_state; freq_cnt <= 3'b000; end else if({Edge_det_sig[0]} == 1'b1) begin update_cntr <= 3'b101; freq_ch <= 40'h0;//140mhz state <= update_state; end end default: begin io_update_reg <= 1'b0; master_reset_reg<= 1'b0; ps_reg <= 3'b000; sclk_reg <= 1'b0; cs_reg <= 1'b1; func_pins <= 4'b0001;//serial_state end endcase end endmodule
THANKS @ronnywebers
03-17-2019 10:43 PM
sir please help @ronnywebers
03-18-2019 03:51 AM
As this is a completely different question, you should create a new question on the forum. Each thread should limit itself to the question asked, otherwise the forum becomes useless.
Actually this post became too long anyway. Also it would be nice if you could post your final solution of your FSM and C-code here, or at least a stripped-down but working verison, that is the purpose of the forum : you can ask questions and people may try to help you, but you should also give back to other people.
03-18-2019 04:00 AM
will do so sir! @ronnywebers Thank you for your Assistance!
//DUT// module mem_new( input wire CLK, input wire RST, input wire [31:0]DOUTB, output wire ENB, output wire [31:0]DINB, output wire [31:0]ADDRB, output wire [3:0]WEB ); //////////////////////////////////////////////////////////////////////////////////////// reg [31:0]DATA_READ = 32'h00000000; reg ENB_SIG = 1'b0; reg [31:0]DINB_SIG = 32'h00000000; reg [31:0]ADDRB_SIG = 32'h00000000; reg [3:0]WEB_SIG = 4'b0000; reg [2:0]STATE = 3'b000; reg [2:0]WAIT_CYCLES = 3'b000; /////////////////////////////////////////////////////////////////////////////////////////// parameter IDLE_STATE = 3'b000; parameter ADDRESS_ZERO = 3'b001; parameter READ_ADDRESS = 3'b010; parameter ADDRESS_ONE = 3'b011; parameter SEND_DATA = 3'b100; parameter DONE_STATE = 3'b101; /////////////////////////////////////////////////////////////////////////////////////////////// parameter MAX_WAIT_CYCLES = 2'd2; /////////////////////////////////////////////////////////////////////////////////////////////// assign ENB = ENB_SIG; assign DINB = DINB_SIG; assign ADDRB = ADDRB_SIG; assign WEB = WEB_SIG; //////////////////////////////////////////////////////////////////////////////////////////////// always@(posedge CLK) begin case(STATE) IDLE_STATE: begin if(RST) begin STATE <= IDLE_STATE; ENB_SIG <= 1'b0; DINB_SIG <= 32'h00000000; ADDRB_SIG <= 32'h00000000; WEB_SIG <= 4'b0000; end else STATE <= ADDRESS_ZERO; end ADDRESS_ZERO: begin ENB_SIG <= 1'b1;//Enable BRAM port. ADDRB_SIG <= 32'h40000000;//First Address is Generated WAIT_CYCLES <= WAIT_CYCLES + 1; if(WAIT_CYCLES == MAX_WAIT_CYCLES)///wait for Max cycles ie;2 for Read cycles begin STATE <= READ_ADDRESS; WAIT_CYCLES <= 3'b000; end end READ_ADDRESS: begin DATA_READ <= DOUTB;//data at previous address is collected and Read. WAIT_CYCLES <= WAIT_CYCLES + 1; if(WAIT_CYCLES == MAX_WAIT_CYCLES)///wait for Max cycles ie;2 for Read cycles begin STATE <= ADDRESS_ONE; WAIT_CYCLES <= 3'b000; end end ADDRESS_ONE: begin ADDRB_SIG <= 32'h40000004;//Second Address is generated WAIT_CYCLES <= WAIT_CYCLES + 1; if(WAIT_CYCLES == MAX_WAIT_CYCLES) //wait for Max cycles ie;2 for Read cycles begin STATE <= SEND_DATA; WAIT_CYCLES <= 3'b000; end end SEND_DATA: begin DINB_SIG <= DATA_READ;//data is put in dinb WEB_SIG <= 4'b1111;///This Data is then Written into the Bram. WAIT_CYCLES <= WAIT_CYCLES + 1; if(WAIT_CYCLES == MAX_WAIT_CYCLES) //wait for Max cycles ie;2 for Read cycles begin STATE <= DONE_STATE; WAIT_CYCLES <= 3'b000; end end DONE_STATE: begin WEB_SIG <= 4'b0000;//Write disabled ENB_SIG <= 1'b0;//Bram disabled WAIT_CYCLES <= WAIT_CYCLES + 1; if(WAIT_CYCLES == MAX_WAIT_CYCLES)//wait for Max cycles ie;2 for Read cycles begin STATE <= IDLE_STATE; WAIT_CYCLES <= 3'b000; end end default: begin STATE <= IDLE_STATE; ENB_SIG <= 1'b0; DINB_SIG <= 32'h00000000; ADDRB_SIG <= 32'h00000000; WEB_SIG <= 4'b0000; end endcase end endmodule //TB// module test_mem_new(); reg CLK; reg RST; reg [31:0]DOUTB; wire ENB; wire [31:0]DINB; wire [31:0]ADDRB; wire [3:0]WEB; mem_new m1 (.CLK(CLK),.RST(RST),.DOUTB(DOUTB),.ENB(ENB),.DINB(DINB),.ADDRB(ADDRB),.WEB(WEB)); initial begin CLK = 1'b0; end always #5 CLK = ~CLK; initial begin RST = 1'b0; #10; RST = 1'b1; #30; RST = 1'b0; end initial begin DOUTB = 32'h00000000; #100; DOUTB = 32'h12345678; #100; DOUTB = 32'h0a3d70a3; #100; DOUTB = 32'h23456789; end endmodule //C code// #include <stdio.h> #include "platform.h" #include "xil_printf.h" #include "xil_io.h" #define BRAM_ADDR_0 0x40000000 #define BRAM_ADDR_1 0x40000004 uint32_t mem_data; int main() { init_platform(); print("Hello World\n\r"); Xil_Out32(BRAM_ADDR_0,55); mem_data = Xil_In32(BRAM_ADDR_1); xil_printf("Read Data = %d\n",mem_data); cleanup_platform(); return 0; }
01-16-2020 06:55 AM - edited 01-26-2020 03:35 AM
@Anonymous Hi, I hope you could help me, I am trying to write the BRAM from PL and read from PS (see block diagram)
code explanation:
I am writing three times in the ram, always from address 0 to 9 but from values from 0 to 29 (see signals file), after the three writes I put all the signals to 0, I am not writing anything and disable the port b of the ram, in the arm (see helloworld file) I make a 5 seconds pause and I use a signal from the PL to know when the ram is full ("ram full" signal - see the block diagram), and I read the ram one time from addresses 0 to 9 and print in the uart the results
what do I expect:
I have written the ram and I have wait enough time to could read it, so I expect to see in the terminal the last values written, I mean, addresses 0 to 9 with values from 20 to 29
what do I get?
random values (see the output file) (I pressed the board reset three times that is why I have three lectures)
note:
- if I always write the same values in the ram, when I read it works ok
- common clock enable in bram
- I read in your post that the bram reset signal must be low when you are writing because the ram reset is active high, I had an error here because I had the port b reset always in high when I was writing, now is fixed and always is low but it does not change anything, it does not work
thanks
01-27-2020 04:09 AM
@ronnywebersHi, could you explain to me this, please?
"your fsm will probably be finished by the time your PS code runs through it's main loop"
why?, in theory the ARM is running faster than the FPGA, for example in my block diagram I can see the clock frequency of the FPGA in 100MHz (fclk_clk0 pin) but inside SDK in the xparameters.h file I see:
XPAR_PS7_CORTEXA9_0_CPU_CLK_FREQ_HZ 500000000
thanks
01-28-2020 01:11 AM - edited 01-28-2020 01:12 AM
@jg_spitfire what I meant is that PL code will start to run earlier than you think ... if you don't take any measures. In some applications that's ok, in some other you want to have control over this.
For example take a custom IP with a simple counter in it, that just receives a PL clock (let's say 100MHz) from the Zynq IP, and a PL reset from the Processing System Reset IP. The IP also contains an AXI register that allows you to read the value of the counter from the PS.
As soon as the clock is there, and reset goes inactive, the counter starts counting. Immediately. At that time, I'm pretty sure your C application is still starting up (if I'm correct, FSBL will release the reset and enable the clock, even before it loads the actual application.elf file, but I should check this in more detail - maybe that is part of the application init, not sure of that). But anyway, details aside, by the time you read the AXI register with the counter value, it will not be zero anymore ... you can try that out if you want (but make the counter big enough, like 32-bit, so it does not wrap around too quickly). I'm pretty sure the counter value that you read right after the PS application starts will also vary slightly between successive resets / tests.
If you add an ILA, the above will even become more interesting, as you'll actually see what's happening at startup, and how many cycles everything takes ...
It's correct that (depending on the settings of course) PS runs in most cases at a higher clock speed (i.e. 500MHz) than the PL (i.e. 100MHz). However AXI transactions are also limited by the 100MHz PL clock, and take a few clock cycles to complete. So .. you'll never read '0' from the counter. Also keep in mind that the PS has startup code to run (init irq tables, C environment, ... before it enters the main() loop.
Unless ... unless you also add an enable to the counter, and connect it to an AXI register, so you can determine from the PS when it's ok for the counter to run.
In the forementioned case of an FSM and BRAM, this is just the same as the counter. Without enable, the FSM will be writing somewhere in the BRAM by the time PS is ready to read from it, or might even have finished, all depending of course on the number of addresses it should write.
So bottom line: never rely on startup times on either side (PS/PL), but make sure you are in control if needed.
01-28-2020 11:13 AM - edited 01-28-2020 11:17 AM
Thanks, @ronnywebers now I understand the problem better, where did you learn those things about the axi and the speeds of fpga and the arm?, could you share some link, pdf, or book about it please?, I would like to know more about this, for example, you said:
"Unless ... unless you also add an enable to the counter, and connect it to an AXI register, so you can determine from the PS when it's ok for the counter to run."
I tried that when I was trying to read the ram I was writing from PL( see the photo), In my PS side I create a signal to fire the FSM of my PL code, so once the PS is inside the main function the FSM starts writing the ram and when the ram is full I send the signal "ram_full" to the PS to start reading it, the problem is that even if I control the start of the FSM I can't read correctly the values written, for example I am writing 3 times the ram (in port b)
#1: from addresses 0 to 9 , values 0 to 9
#2: from addresses 0 to 9 , values 10 to 19
#3: from addresses 0 to 9 , values 20 to 29
but I am only able to read the third value written (20 to 29), that means that even if I can detect the "ram_full" signal the arm is too slow to read the first write in the ram and when starts reading it the ram already has been written three times, is that correct or I am wrong?
01-29-2020 01:08 AM - edited 01-29-2020 01:08 AM
@jg_spitfire not sure what your exact goal is with the FSM or writing multiple times to the same memory location.
There's quiet some things to learn, so know beforehand that it will take some time ... There aren't many hands-on books or tutorials, especially not from Xilinx (besides a few tutorials, which you should checkout of course, but will leave a lot of your questions unanswered).
However, the following are usefull documents/links to check:
If you are working with Zynq, the Zedboard is one of the best boards you can buy, you'll find a lot of examples on the web, and it's very complete. A similar but cheaper board is the Zybo board by Digilent. A microzed board is even cheaper I believe (but has limited interfacing), and might get you started also
After this, you should be able to develop many things. Make sure to get a good HDL book too, if you search on books on the forum, you'll probably find some good tips ...