C
Chuck McManis
Guest
State machines and synchronization.
The background is that I'm working on this PWM unit that uses a serial shift
register to hold the pulse "width" data. The original code goes something
like:
-- process to manage clocking in the data
sr: process (sdata_in, sclock, reset) is
begin
if (reset = '1') then
serial_data <= "00000000";
elsif rising_edge(sclock) then
serial_data <= sdata_in & serial_data(serial_data'length-1 downto
0);
end if;
end process;
-- concurrent assignment of serial data out.
sdata_out <= serial_data(0);
-- process to manage pwm output
pwm: process is (pwm_count) is
begin
if (pwm_count < serial_data) then
pwm_out <= '1';
else
pwm_out <= '0';
end if;
end process;
Things that aren't here is that the architecture for this thing calls for a
current PWM count as input (same width as serial_data), pwm_out as output,
and our shift register, serial_data, defined with a signal define in the
behavioral section.
This works as I would expect, and I can clock in different bit streams and
get different wave forms. However, a couple of problems persist:
1) I don't get "full" PWM. This is because the pwm process is forced to use
either < or > If I want to support both 0% on (output stays low) and 100%
on, (output stays high), I need an additional statement to cover that.
I can modify pwm as follows:
pwm: process is (pwm_count, serial_data) is
begin
if (serial_data = "11111111") then
pwm_out <= '1';
elsif (pwm_count < serial_data) then
pwm_out <= '1';
else
pwm_out <= '0';
end if;
end process;
Assuming the original code inferred an 8 bit comparator, I'd guess the above
code would then infer an 8 bit and gate whose output is OR'd into the output
of the comparator (at least that is what I'd do). But it seems like I should
be able to save the two macrocells this is going to eat by changing the
logic of the inferred comparator to include an output of '1' when all inputs
are 1.
2) The second problem is that I would really like the pwm output to change
exactly on the period boundary. Now I started this with a simple state
machine where a new input set a latch to tell me to change, and then added
that into the sensitivity list of the pwm function like so:
ld: process (serial_load) is
begin
if rising_edge(serial_load) then
new_data <= '1';
end if;
end process;
pwm: process is (pwm_count, pwm_data, new_data) is
begin
if (new_data = '1') and (pwm_count = "11111111") then
pwm_data <= serial_data;
new_data <= '0';
elsif (pwm_data = "11111111") then
pwm_out <= '1';
elsif (pwm_count < pwm_data) then
pwm_out <= '1';
else
pwm_out <= '0';
end if;
end process;
This is designed to create a simple state machine between the ld and pwm
processes such that if there is new data, then that data is loaded when the
count is full. However I'm getting errors trying to synthesize this.
Basically XST doesn't like the way I'm assigning new_data in different
processes (although as an engineer it makes sense to me, I'd like to infer
and R/S flip flop and have pwm_count & new_data drive its "R" input and
"serial load" drive its "S" input. Trying to use this:
ld: process (serial_load) is
begin
if serial_load = '1' then
new_data <= '1';
end if;
end process;
Leads to the case where holding serial load high through a full PWM cyle
would cause both R/S to be asserted. So I tried to infer something like a
modified T flip flop to set it on the clock edge. Thoughts anyone?
--
--Chuck McManis
Email to the devnull address is discarded
http://www.mcmanis.com/chuck/robotics/
The background is that I'm working on this PWM unit that uses a serial shift
register to hold the pulse "width" data. The original code goes something
like:
-- process to manage clocking in the data
sr: process (sdata_in, sclock, reset) is
begin
if (reset = '1') then
serial_data <= "00000000";
elsif rising_edge(sclock) then
serial_data <= sdata_in & serial_data(serial_data'length-1 downto
0);
end if;
end process;
-- concurrent assignment of serial data out.
sdata_out <= serial_data(0);
-- process to manage pwm output
pwm: process is (pwm_count) is
begin
if (pwm_count < serial_data) then
pwm_out <= '1';
else
pwm_out <= '0';
end if;
end process;
Things that aren't here is that the architecture for this thing calls for a
current PWM count as input (same width as serial_data), pwm_out as output,
and our shift register, serial_data, defined with a signal define in the
behavioral section.
This works as I would expect, and I can clock in different bit streams and
get different wave forms. However, a couple of problems persist:
1) I don't get "full" PWM. This is because the pwm process is forced to use
either < or > If I want to support both 0% on (output stays low) and 100%
on, (output stays high), I need an additional statement to cover that.
I can modify pwm as follows:
pwm: process is (pwm_count, serial_data) is
begin
if (serial_data = "11111111") then
pwm_out <= '1';
elsif (pwm_count < serial_data) then
pwm_out <= '1';
else
pwm_out <= '0';
end if;
end process;
Assuming the original code inferred an 8 bit comparator, I'd guess the above
code would then infer an 8 bit and gate whose output is OR'd into the output
of the comparator (at least that is what I'd do). But it seems like I should
be able to save the two macrocells this is going to eat by changing the
logic of the inferred comparator to include an output of '1' when all inputs
are 1.
2) The second problem is that I would really like the pwm output to change
exactly on the period boundary. Now I started this with a simple state
machine where a new input set a latch to tell me to change, and then added
that into the sensitivity list of the pwm function like so:
ld: process (serial_load) is
begin
if rising_edge(serial_load) then
new_data <= '1';
end if;
end process;
pwm: process is (pwm_count, pwm_data, new_data) is
begin
if (new_data = '1') and (pwm_count = "11111111") then
pwm_data <= serial_data;
new_data <= '0';
elsif (pwm_data = "11111111") then
pwm_out <= '1';
elsif (pwm_count < pwm_data) then
pwm_out <= '1';
else
pwm_out <= '0';
end if;
end process;
This is designed to create a simple state machine between the ld and pwm
processes such that if there is new data, then that data is loaded when the
count is full. However I'm getting errors trying to synthesize this.
Basically XST doesn't like the way I'm assigning new_data in different
processes (although as an engineer it makes sense to me, I'd like to infer
and R/S flip flop and have pwm_count & new_data drive its "R" input and
"serial load" drive its "S" input. Trying to use this:
ld: process (serial_load) is
begin
if serial_load = '1' then
new_data <= '1';
end if;
end process;
Leads to the case where holding serial load high through a full PWM cyle
would cause both R/S to be asserted. So I tried to infer something like a
modified T flip flop to set it on the clock edge. Thoughts anyone?
--
--Chuck McManis
Email to the devnull address is discarded
http://www.mcmanis.com/chuck/robotics/