Intel® Quartus® Prime Software
Intel® Quartus® Prime Design Software, Design Entry, Synthesis, Simulation, Verification, Timing Analysis, System Design (Platform Designer, formerly Qsys)
Announcements
FPGA community forums and blogs on community.intel.com are migrating to the new Altera Community and are read-only. For urgent support needs during this transition, please visit the FPGA Design Resources page or contact an Altera Authorized Distributor.
17267 Discussions

Simple SPI shift register, mismatch between simulation and real behavior

Altera_Forum
Honored Contributor II
2,173 Views

This is a shot in the dark, but I have what should be an essentially very simple shift register design, that should accept a byte from the SPI peripheral of a microcontroller. 

 

Ideally the device should work like this: 

 

 

  • The microcontroller selects the register by bringing cs_power low  

  • The microcontroller clocks out 8 bits. Data is asserted on spi_mosi on the falling edges of the clock, and data is read into the register on the rising edges  

  • The microcontroller deselects the register by bringing cs_power high  

  • On the deselct, the 8 data bits transmitted are latched into latch_reg. Bits are routed individually to other parts of the design for various functions (not shown here) - two of the bits, power_hv507 and ref_select are connected to bits 1 and 6 of that latch respectively. To test for proper operation of the register, I've connected these signals to pins on my MAXII CPLD, and am watching them on my oscilloscope.  

 

 

I've compiled this design in Quartus II 9.1 (our current production version) and 12, to the same effect. The 9.1 simulator doesn't make much sense of the design, but using modelsim 10.0d with a testbench written for this purpose, the waveforms look exactly as I would expect. I can observe the data bits changing in the taps of the shift register, and the correct data byte is latched into latch_reg when cs_power is deselected. The routing of the latch outputs to their respective signals is correct, as observed in the simulator.  

 

Loading the design into the CPLD however produces repeatable, but incorrect behavior. I'm only able to physically observe two bits of the latch_reg at a time (which I have wired by default to bits 1 and 6) - I can rearrange the bits of latch_reg I observe, but in none of the cases do asserting the bits of interest result in the correct outputs. 

 

This should be very straightforward, but it's been vexing me for days. Is there something obvious I've done incorrectly here? The mismatch between the simulation and the actual behavior of the device (especially for something so simple) is particularly frustrating. 

library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity effector_module is port ( spi_sclk : in std_logic := '0'; spi_mosi : in std_logic := '0'; cs_hv507 : in std_logic := '1'; cs_impedance : in std_logic := '1'; cs_cart : in std_logic := '1'; cs_vctl : in std_logic := '1'; cs_feedback : in std_logic := '1'; cs_hv507_clk : in std_logic := '1'; cs_power : in std_logic := '1'; hv507_fault : in std_logic := '0'; -- new 14 err : in std_logic := '0'; -- new 12 fault_cart : in std_logic := '0'; -- new 2 timer : inout std_logic := '0'; hv_suppress : inout std_logic := '0'; -- new 10 power_cart : inout std_logic := '0'; -- new 3 cart_present : inout std_logic := '0'; -- new 4 blank : inout std_logic := '0'; -- new 5 power_hv507 : out std_logic := '0'; -- new 13 ref_select : out std_logic := '0'; -- new 8 not_hv_shdn : out std_logic := '0'; -- new 9 bleed : out std_logic := '0'; -- new 11 cart_miso_dir : out std_logic := '0'; -- new 1 pol : out std_logic := '0'; -- new 6 sck_hv507 : out std_logic := '0'; -- new 7 spi_miso : out std_logic := 'Z'; tapsout : out std_logic_vector (7 downto 0) ); end effector_module; library ieee; use ieee.std_logic_1164.all; entity basic_shift_register is generic ( NUM_STAGES : natural := 256 ); port ( clk : in std_logic; enable : in std_logic; sr_in : in std_logic; sr_out : out std_logic; taps : inout std_logic_vector ((NUM_STAGES-1) downto 0) ); end entity; -- Shift register with active low enable architecture rtl of basic_shift_register is -- Build an array type for the shift register -- Declare the shift register signal begin process (clk, enable, taps) begin if (enable = '1') then taps((NUM_STAGES-1) downto 0) <= taps((NUM_STAGES-1) downto 0); elsif (rising_edge(clk)) then -- Shift data by one stage; data from last stage is lost taps((NUM_STAGES-1) downto 1) <= taps((NUM_STAGES-2) downto 0); -- Load new data into the first stage taps(0) <= sr_in; end if; end process; -- Capture the data from the last stage, before it is lost sr_out <= taps(NUM_STAGES-1); end rtl; architecture rtl of effector_module is signal delta : std_logic; signal clear_sticky : std_logic; signal dc_mode : std_logic; signal pwr : std_logic_vector(7 downto 0); signal latch_reg : std_logic_vector(7 downto 0); begin power_hv507 <= pwr(1); ref_select <= pwr(6); power_sr : entity work.basic_shift_register(rtl) generic map( NUM_STAGES => 8) port map( clk => spi_sclk, enable => cs_power, sr_in => spi_mosi, taps => pwr ); process (cs_power, pwr) begin if rising_edge(cs_power) then latch_reg <= pwr; end if; end process; end rtl;
0 Kudos
6 Replies
Altera_Forum
Honored Contributor II
954 Views

its probably the asynchronous enable. 

In simulation, it will only shift when enable goes high (eg on the rising edge), because of the way VHDL works but in the real hardware it will just shift whenever enable is one, so not on the rising edge. Sensitivity lists are ignored for synthesis and so you will have a shift register that is shifting whenever enable = '1' ie. do as many shifts as you can in infinitely small amount of time. 

 

Why do you have an async enable?
0 Kudos
Altera_Forum
Honored Contributor II
954 Views

The enable came with the Altera template code that I dropped in to do the shift register in the first place, so I left it there. I don't strictly need an enable at all, since I latch the output on my select, but it seemed like a better design not to be shifting except for when the select (enable) was low. 

 

I still don't follow. Even with the asynchronous enable, I still should not shift except for on rising edges of the clock, right? That's what the elsif clause says should happen? (if enable = 1, do nothing, if enable = 0 AND rising edge of clock, shift down) What's my alternative to an async enable, other than omitting it altogether? (or is omitting it altogether the thing to do?)
0 Kudos
Altera_Forum
Honored Contributor II
954 Views

After having removed the enable (simply always clocking data on the rising edge of the clock) the behavior is the same. One thing worth noting is that if I connect my observable pins to latch_reg(1) and latch_reg(6) - the bits that actually make them go high are bits 0 and bits 3, respectively. That is, if I shift out 0x02 or 0x40, I don't see either of my bits come on. If I shift out a 0x01 or an 0x08 however, I see the bits turn on in their respective locations

0 Kudos
Altera_Forum
Honored Contributor II
954 Views

Ok, sorry about that - must admit I only scanned it the first time - you're correct about the enable. 

But I do question why taps is an inout - why isnt it an internal signal, or just an output? 

 

Secondly are you sure the problem isnt related to using two different clocks? what is this cs_power? is it a real clock?
0 Kudos
Altera_Forum
Honored Contributor II
954 Views

No worries! I appreciate your help. 

 

cs_power isn't a clock, per se, it's a select signal. This is connected to the SPI port on a microcontroller. The idea is that the microcontroller selects the CPLD by bringing cs_power low, it clocks out the 8 bits (using sck for clock and mosi for data) and then deselects the CPLD by bringing cs_power high again. On the rising edge of the deselect the contents of the taps are latched into latch_reg. 

 

taps is declared as an inout so I can read it inside the process to do the shifting. There might be a better way to do it? 

 

http://en.wikipedia.org/wiki/serial_peripheral_interface_bus#clock_polarity_and_phase 

 

The diagram at the above link gives the general sense of how this should work. sr_in = MOSI, clk = sck and SS = cs_power 

 

Thank you so much for your help. I'm on a deadline here, and I've worked myself into a corner, I'm afraid!
0 Kudos
Altera_Forum
Honored Contributor II
954 Views

1. CS_POWER isn't a clock. 

 

BASIC_SHIFT_REGISTER latches TAPS using the SPI_CLK, which is then assigned to PWR. 

 

process (cs_power, pwr) begin if rising_edge(cs_power) then latch_reg <= pwr; end if; end process; 

This code generates a D-flipflop using CS_POWER as a clock input. Unless you can guarantee that the CS_POWER clock edges are synchronized with the SPI_CLK, you will have potential metastability problems due to setup/hold violations on this flipflop. 

 

I would recommend hitting up the fpga4fun.com website and looking at their clock crossing articles (including flag detection/generation). Once you have the SPI byte you are going to need to cross to your internal clock domain to do any processing. You need to generate a 1 internal-clock cycle pulse/flag that detects the low-hi transition on CS_POWER and use it as an enable to your latch (along with appropriate synchronizers).
0 Kudos
Reply