Foreword
This is the third part in the series where we try to get a SD Card reader to work on an Arty A7 board.
In the previous post we had a look at the FPGA core by Dan Gisselquist that can interface with an SD Card Reader.
A nice feature of Dan Gisselquist's core is the test bench that can simulate responses from an SD Card. Out the box this Test Bench works within the Verilator eco system. However, in the previous post we managed to use Gisselquist's SD Card response module with simulation in Vivado.
We concluded the previous post been able to issue an IDLE command to the SD Card response module, and got a response back.
In this post we will do the same exercise on the physical Arty A7 board, issuing an IDLE command to the SD Card and checking if we can also get a response back from an SD Card.
Attaching the SD Card module to the Arty A7
In the first part of this series I briefly shown a pic of a PMOD SD Card reader still in its packaging.
To be honest, this module was in its packaging up to now 😁 Well, I thought just to share a picture of the Sd Card module attached to the Arty A7 board:
There was one caveat I discovered straight away when inserting the SD Card module, which I didn't thought of before hand: This module occupies some space in front of the PMOD header next to it.
This might pose an issue when we want to use a VGA PMOD module later in the project, which uses both PMOD headers JB and JC.
To get around this issue, we might need to make use of a PMOD extension cord for inserting the SD Card module, freeing some space in front of header JB. But, we will tackle this issue when we get there.
Creating the constraints
## Pmod Header JA set_property -dict {PACKAGE_PIN G13 IOSTANDARD LVCMOS33} [get_ports cs] set_property -dict {PACKAGE_PIN B11 IOSTANDARD LVCMOS33} [get_ports mosi] set_property -dict {PACKAGE_PIN A11 IOSTANDARD LVCMOS33} [get_ports miso] set_property -dict {PACKAGE_PIN D12 IOSTANDARD LVCMOS33} [get_ports sclk] set_property -dict { PACKAGE_PIN D13 IOSTANDARD LVCMOS33 } [get_ports dat1]; #IO_L6N_T0_VREF_15 Sch=ja[7] set_property -dict { PACKAGE_PIN B18 IOSTANDARD LVCMOS33 } [get_ports dat2]; #IO_L10P_T1_AD11P_15 Sch=ja[8] set_property -dict {PACKAGE_PIN A18 IOSTANDARD LVCMOS33} [get_ports cd] set_property -dict {PACKAGE_PIN K16 IOSTANDARD LVCMOS33} [get_ports wp]Next, we should ensure that our top level module use the same port names:
module top( input wire CLK100MHZ, output wire cs, output wire mosi, input wire miso, output wire sclk, input wire cd, input wire wp ); ... endmoduleInside this top level module an instance will live of the Gisselquist SD Card core. We will also be implementing a state machine in this module for instruction the Gisselquist core for sending an IDLE command to the SD Card.
The State Machine
always @(posedge gen_clk) begin if (clk_locked) begin case (state) ... endcase end endSo, the state machine will only start changing states once the clock is locked. We start with a number of dummy states to give the Gisselquist core a chance to initialise, after which we de-assert the reset signal to the core:
... 0: state <= 1; 1: state <= 2; 2: state <= 3; 3: state <= 4; 4: begin state <= 5; reset_sd <= 0; end ...So, what next? We could go straight ahead and issue the IDLE command, but preferably we set the signal which we clock the SD Card at the desired initial frequency, which is 400KHz. I am clocking the Sd Card core at a frequency of 10MHZ, so we will need to bring it down by means of the internal clock divider provided by this core. To get to 400KHz we need to use a divider value of 11, which is 0b in hexadecimal. We set the value with the state machine as follows:
5: begin state <= 6; stb <= 1; wb_sel <= 4'hf; addr <= 1; we <= 1; data <= 32'h5556550b; end 6: begin state <= 7; stb <= 0; end 7: begin state <= 8; stb <= 1; wb_sel <= 4'hf; addr <= 0; we <= 1; data <= 32'hc0; endTo understand this snippet, we need to quickly look at the internal registers of the Gisselquist core:
- Register 0: Used for sending command bytes. SD Cards always expect a command command that starts with 01. For all the other bit combinations of the two significant bits of the command byte, we are free to use as command bytes operating on the Gisselquist core itself.
- Register 1: Data register containing four extra bytes of data associated with the command byte. If you want to issue a command byte containing multiple bytes, you need to set this register first before issuing the command.
8: begin state <= 9; stb <= 1; wb_sel <= 4'hf; addr <= 1; we <= 1; data <= 32'hffffffff; end 9: begin state <= 10; stb <= 1; wb_sel <= 4'hf; addr <= 0; we <= 1; data <= 32'h40; end 10: begin stb <= 0; endSo, we issue the command 40 to the SD Card, followed by 4 ff bytes.
Clocking the Sd Card
ODDR #( .DDR_CLK_EDGE("OPPOSITE_EDGE"), // "OPPOSITE_EDGE" or "SAME_EDGE" .INIT(1'b0), // Initial value of Q: 1'b0 or 1'b1 .SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC" ) ODDR_inst ( .Q(sclk), // 1-bit DDR output .C(o_sclk), // 1-bit clock input .CE(1), // 1-bit clock enable input .D1(1), // 1-bit data input (positive edge) .D2(0), // 1-bit data input (negative edge) .R(0), // 1-bit reset .S(0) // 1-bit setWith all this in place, we are now ready to do a test run on the Arty A7 board
Test Results
- cs (Chip Select)
- miso
- mosi
- o_sclk
No comments:
Post a Comment