- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
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;
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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?- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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?)- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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?- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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!- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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).

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page