Upload
others
View
0
Download
0
Embed Size (px)
Citation preview
Lecture 9 A Design Example
Based on personal experience in S15
Design Process
Read the documentation
Realize it is incomplete ➙ make some guesses
Design Hardware Thread
Datapath + Controlling FSM
Interface + Testbench
Debug / Test / Repeat
NEXYS4 + Pmod Joystick
Joystick + 2 LEDs + 3 pBtn
Interface: microcontroller
SPI communication
4-wire, 2-way interface
X, Y position is 10-bits each
SPI Interface
4 wire-bus, single master, multiple slaves
Slave Select: Active low signal to choose a device (SS or SS_L)
SCK: clock, generated by the master, <1MHz
MOSI: Master-out, slave-in data
MISO: Master-in, slave-out data
0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
Master Slave
MOSI
MISO
SS_L
SCK
Timing Diagram
According to the documentation
Max 1MHz SCK
>15uS after SS_L until first bit shifts
Shift 5 bytes of data per transaction
>10uS between bytes
Issues:
Which bit first?
Clocking phase
Answers I’ve figured out:MOSI sends MSB of LED Control Byte first LED Control Byte’s MSB must be a 1 (easy to overlook)SPI Mode is 1, not 0 (i.e. Docs are WRONG)MISO sends MSB of Byte 1 (X-low) first
Tmin=1uS
SCK
SS_L
MOSI
>15uS >10uS
MISO
Datapath Hardware First
ShiftReg_PISO(RIGHT)
ShiftReg_SIPO(LEFT)
led[1:0]
loadclear
D[1:0]
Q[1:0]CLK_100M
load
CLK_100M
LED_REG
D[39:0]
serial_out
CLK_100M serial_inQ[39:0]
D[39:0]
Q[39:0]
loadclear
CLK_100M
1’b0
1’b0
ld_LED_reg
ld_shift
ld_results_reg
RESULTS_REG
MISO
MOSI
38’h3A5A5A5A5A
X, Y, btn
en
en
en_shift
en_shift
+ interval counters for 10uS, 15uS
+ operation counters for 8 bits, 5 bytes
+ divide-by-128 counter to generate
SCK (390KHz)
assign sck = CLK_390K & en_sck;
register #(2) LED_REG(.D(led), .Q(led_r), .load(ld_LED_reg), .clear(1'b0), .clock(CLK_100M), .*); logic [7:0] d_piso; assign d_piso = {led_r[0],led_r[1],6'b000001}; shift_PISO #(8) s1(.D(d_piso), .serial_out(mosi), .clock(CLK_100M), .load(ld_shift), .en(en_piso_shift), .*);
shift_SIPO #(40) s2(.Q(from_shift), .serial_in(miso), .clock(CLK_100M), .en(en_sipo_shift), .*);
register #(40) RESULTS_REG(.D(from_shift), .Q(results), .load(ld_results_reg), .clear(1'b0), .clock(CLK_100M), .*);
assign X = {results[25:24], results[39:32]}; assign Y = {results[9:8], results[23:16]}; assign btn = results[2:0];
Datapath SV
Control FSM
Inputs
CLK_100M, reset, start_reg, start_shift, end_shift
Outputs
slave select, reg_en, shift_load, reg_en
3 states, Mealy machine
HA!
START
WAIT_CLK_LOW
WAIT_15uS
reset~start_transaction /not_slave_select
start_transaction / ld_LED_reg, ld_15uS
~done_15uS /
done_15uS /
CLK_390K /
CLK_390K / ld_5Bytes, ld_8bits, en_sck, en_sipo_shift
CLOCKING_1 CLK_390K / en_sck
CLOCKING_0
INTRA_BYTE
~CLK_390K / en_sck, en_piso_shift
done_5Bytes / ld_results_reg
~done_5Bytes & ~CLK_390K / en_sck ~done_5Bytes &
CLK_390K & ~done_8bits / en_sck, en_shift, en_8bits, en_sipo_shift
~done_5Bytes & CLK_390K & done_8bits / ld_10uS
~done_10uS /
done_10uS /
WAIT_CLK_HIGH~CLK_390K / ld_shift
~CLK_390 /
INTRA_RESYNC
CLK_390K / ld_8bits, en_sipo_shift, en_5Bytes
~CLK_390K
Selected FSM SVmodule fsm (input logic start_transaction, done_15uS, CLK_390K, done_10uS, done_5Bytes, input logic done_8bits, output logic ld_results_reg, ld_shift, ld_LED_reg, slave_select_L, ld_10uS, output logic ld_15uS, ld_5Bytes, ld_8bits, en_sck, en_sipo_shift, output logic en_piso_shift, en_5Bytes, en_8bits, input logic clock, reset); // clk is 100MHz
enum logic [2:0] {START, WAIT_15uS, WAIT_CLK_LOW, WAIT_CLK_HIGH, CLOCKING_1, CLOCKING_0, INTRA_BYTE, INTRA_RESYNC} state, next_state;
always_ff @(posedge clock, posedge reset) if (reset) state <= START; else state <= next_state;
case (state) START : begin next_state = (start_transaction) ? WAIT_15uS : START; if (start_transaction) begin ld_LED_reg = 1'b1; ld_15uS = 1'b1; end else slave_select_L = 1'b1; // just about all other times it is active end WAIT_15uS : begin next_state = (done_15uS) ? WAIT_CLK_LOW : WAIT_15uS; end WAIT_CLK_LOW : begin next_state = (CLK_390K) ? WAIT_CLK_LOW : WAIT_CLK_HIGH; ld_shift = ~CLK_390K; end WAIT_CLK_HIGH : begin next_state = (CLK_390K) ? CLOCKING_1 : WAIT_CLK_HIGH; if (CLK_390K) begin ld_5Bytes = 1'b1; ld_8bits = 1'b1; en_sck = 1'b1; en_sipo_shift = 1'b1; end end CLOCKING_1 : begin next_state = (CLK_390K) ? CLOCKING_1 : CLOCKING_0; en_piso_shift = ~CLK_390K; en_sck = 1'b1;
Did It Work (V1.0)?
NO! ➙ LD2 turned on, no other response
Break out the logic analyzer (and the Test Point Header)
SCK looks good. Nothing else does
Integrated Logic Analyzer
Step 1: Mark some signals to be debugged
In your SV Code`default_nettype none
module JoystickPmod (input logic [1:0] led, input logic CLK_100M, reset, (* mark_debug = "true" *) input logic miso, output logic [9:0] X, Y, output logic [2:0] btn, // 2, 1, center (* mark_debug = "true" *) output logic mosi, ss, sck, output logic [3:0] debugger);
(* mark_debug = "true" *) logic [39:0] interrim_results; assign interrim_results = results;
Can also mark them in the Debug View ➙ Nets
Right click and select “Mark Debug”
This is AFTER synthesis
There is a way to mark them in the Constraints file
I don’t know how
ILA Step 2: Inserting Debug Core
In Synthesis Flow (on left), choose Setup Debug
A wizard will appear
You can add additional nets to debug on page 2
You can setup Trigger and Storage settings (pg 3)
I haven’t explored “Advanced Trigger” and “Capture Control” but they look promising
Step 3
Implement and Generate Bitstream
This will take significantly longer
You are including a complex ILA debug core on your FPGA, so it makes sense it will take longer
Step 4: Use ILA from Hardware Manager
And there was much rejoicing!!
I needed a lot of storage depth (32K samples), as SPI is rather slow and each sample is at the 100MHz clock rate
Documentation Error
PA7 is a NEXYS4 schematic name, as is PA8, PA9, PA10
SS is PA7, MOSI is PA8, MISO is PA9, SCK is PA10
Notice, no curly braces if signal isn’t a vector
Config file
Lessons Learned
Process
Documentation, Design, Datapath hardware, FSM
Test, Debug
Documentation is always insufficient
Sometimes because you haven’t read it right