- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
my device consists of MCU, MAX V CPLD and sensor device. MAX V CPLD is used to interface sensor to MCU.
I have a code in VHDL for MAX V CPLD:
entity Device is
port (
clk16: in std_logic; -- 16 MHz clock generated by MCU
start: inout std_logic; -- start pulse from MCU/operation complete from CPLD. This signal is normally high (pull up resistor). When MCU pulls it down, it tells CPLD to start reading data from sensor. CPLD pulls signal low during read. When it is finished CPLD stops pulling it low.
clk_out: buffer std_logic; -- output clock for sensor derived from clk16
start_pulse: out std_logic; -- start pulse for sensor (start command for sensor)
);
end Device;
architecture a of Device is
type T_STATE is (STOPPED, STARTING, ....another states....);
signal state: T_STATE := STOPPED;
begin
process (clk16)
begin
if rising_edge(clk16) then
clk_out <= not clk_out; -- create clk_out clock
end if;
if rising_edge(clk_out) then
case state is
when STOPPED =>
if start = '0' then
start_pulse <= '1';
state <= STARTING;
start <= '0' -- sometimes this doesn't happen
end if;
when STARTING =>
start_pulse <= '0';
-- code continues here....
The problem is that sometimes line 28 is not "executed" - CPLD doesn't start pulling line low. However, state machine goes to the next state (STARTING) and start_pulse is set to 1 (and then to 0 when it is in STARTING state).
Can you please help me debug this code?
Thanks
Martin
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You're doing a check for rising_edge(clk_out) inside a process that is only sensitive to clk16. Your next state logic should be in a separate process, sensitive to clk_out.
Also, you need to code your bidirectional (or is it supposed to be a tri-state?) correctly. It should look something like this (replace from_core and to_core with what the pin should be when it's an output and when it's an input:
start <= from_core WHEN oe='1'
ELSE 'Z';
to_core <= start;
There should be some type of output enable control signal for an inout.
Finally, you're doing an if check on start being 0, but then setting start to 0 as an action in that same if check. I'm not sure what you're trying to do.
#iwork4intel
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks. I will modify my code.
Also, you need to code your bidirectional (or is it supposed to be a tri-state?)
It is open drain output with external pull up resistor and at the same time it is input. Not sure what category should I choose. CPLD should be able to read the line and at the same it should be able to set the line to 0 or high impedance.
Finally, you're doing an if check on start being 0, but then setting start to 0 as an action in that same if check. I'm not sure what you're trying to do.
I'm checking, if the MCU pulled start low and if so CPLD pulls the signal also low signalling that it started doing its job. MCU can then release that signal. Later (this is not visible in the code) CPLD sets the start signal to high impedance 'Z' (releasing the line) signalling that it finished the job. Start then goes 1 (as there is external pull up) and MCU detect rising edge which means CPLD finished its job.
Is it wrong?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
FYI: with scope, I can see that the code doesn't work when MCU pulls the line low exactly at rising edge of clk_out. Then, CPLD correctly detects start = '0' but it doesn't set start to zero (line 28). CPLD then starts doing its job but the start line is released once MCU releases. That is not good as MCU detects rising edge (finished job) when CPLD is actually still working.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity Device is
port (
-- SRAM address, data, WE, CE
ram_a: out std_logic_vector(14 downto 0);
ram_ad: out std_logic_vector(15 downto 0);
ram_we: out std_logic;
ram_ce: out std_logic;
-- ADC data output
adc_d: in std_logic_vector(7 downto 0);
-- main clock generated by MCU
clk16: in std_logic;
-- divided clock
clk_out: buffer std_logic;
-- open drain output with external pull up resistor. Connected to MCU
start: inout std_logic;
-- reset. Connected to MCU
reset: in std_logic
);
end Device;
architecture b of Device is
type T_STATE is (STOPPED, STARTING, DUMMY_PERIOD, SAMPLING, FINISHING, WAITING_FOR_STOP);
type T_SAVINGSTATE is (NOTSAVING, SAVING, FINISHINGSAVING);
signal cnt: unsigned(9 downto 0);
signal address: std_logic_vector(14 downto 0);
signal state: T_STATE := STOPPED;
signal savingstate: T_SAVINGSTATE := SAVING;
-- timing for state machine:
constant DUMMY_CLOCKS: integer := 97;
constant START_SAVING_CLOCKS: integer := DUMMY_CLOCKS + 5;
constant STOP_SAMPLING_CLOCKS: integer := DUMMY_CLOCKS + 512;
constant FINISH_SAVING_CLOCKS: integer := START_SAVING_CLOCKS + 512;
constant STOP_SAVING_CLOCKS: integer := FINISH_SAVING_CLOCKS + 1;
begin
process (clk16, clk_out, reset)
begin
if reset = '0' then
address <= (others => '0');
state <= STOPPED;
savingstate <= NOTSAVING;
ram_a <= (others => 'Z');
ram_ad <= (others => 'Z');
ram_ce <= 'Z';
ram_we <= 'Z';
clk_out <= '0';
start_pulse <= '0';
start <= 'Z';
else
if rising_edge(clk16) then
clk_out <= not clk_out;
end if;
if falling_edge(clk16) then
if savingstate = SAVING then
if clk_out = '1' then
ram_a <= address;
ram_ad(7 downto 0) <= adc_d;
else
address <= unsigned(address) + 1;
ram_ad(15 downto 8) <= adc_d;
end if;
elsif savingstate = NOTSAVING then
ram_a <= (others => 'Z');
ram_ad <= (others => 'Z');
end if;
end if;
if rising_edge(clk_out) then
case state is
when STOPPED =>
if start = '0' then -- MCU started the job by pulling the line low
start <= '0'; -- pull it low to tell MCU the job is in progress
state <= STARTING;
end if;
when STARTING =>
cnt <= (others => '0');
state <= DUMMY_PERIOD;
when DUMMY_PERIOD =>
cnt <= cnt + 1;
if cnt = DUMMY_CLOCKS then
state <= SAMPLING;
end if;
when SAMPLING =>
cnt <= cnt + 1;
if cnt = START_SAVING_CLOCKS then
savingstate <= SAVING;
elsif cnt = STOP_SAMPLING_CLOCKS then
state <= FINISHING;
end if;
when FINISHING =>
cnt <= cnt + 1;
if cnt = FINISH_SAVING_CLOCKS then
savingstate <= FINISHINGSAVING;
elsif cnt = STOP_SAVING_CLOCKS then
savingstate <= NOTSAVING;
state <= WAITING_FOR_STOP;
start <= 'Z'; -- job done, release the line
end if;
when WAITING_FOR_STOP =>
cnt <= cnt + 1;
if cnt = STOP_SAVING_CLOCKS + 100 then
state <= STOPPED;
end if;
end case;
end if;
if savingstate = SAVING then
ram_ce <= cis_cp;
elsif savingstate = FINISHINGSAVING then
ram_ce <= '1';
else
ram_ce <= 'Z';
end if;
end if;
end process;
end b;
There is my MAX V that implements this code, ADC that converts data from sensor, MCU and SRAM.
MCU resets or starts the job (reset, start),.
When started, CPLD starts reading data from ADC's 8 bit data bus and saves it to SRAM which has 16 bit data bus.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Let me explain the start signal (for now I renamed it start/finished as it better describes it purpose).
Here is schematic:
Normally, no chip is pulling the line low - both chips sets the pin with start/finished line to high impedance input. When MCU wants CPLD to start its job it configures start/finished pin to output and writes 0 to it (pulls it low) for at least one clock period so the CPLD is able to catch that. CPLD detects this "start condition" and pulls the line low also to tell MCU that it is working. When the job is done, it again configures start/finished pin to high impedance input which means rising edge will happen on the line (as no chip is pulling it low) which can be detected by MCU...
If what I have written can't be implemented in CPLD then that is good news for me as it means the problem is solved. I can move start <= '0'; to the next state (that happens just one clock period after, that is perfectly OK) and extend MCU's start pulse to 2 clock periods (so there is no rising edge meaning false job done). But of course, I would like to be sure that this is the problem.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
This is pinout for start signal (output of Fitter):
Pin Name/Usage : Location : Dir. : I/O Standard : Voltage : I/O Bank : User Assignment
start: 44 : bidir : 3.3-V LVTTL : : 2 : Y
I simulated it and was not able to reproduce the issue. I tried to move falling edge of start signal relative to clk_out clock to several positions when simulating, but the issue never happened when simulating.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
But it is bidir which should be good for me as long as CPLD can set bidir pin to 0 and to high impedance state and is able to read its state.
So, can you confirm, that this implementation that is present in my code:
if start = '0' then
start <= '0';
end if;
is bad idea and I should do it in some official way?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Yes, I will do it this way and perform some testing to see if that was the cause of my problem.
Thank you
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I modified my VHDL and now testing. It seems it works, RTL looks simpler with new version of code but we have to monitor it for longer time. The issue happened months after we were using original code and only with two devices.

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