newbie question: 2 processes modifying the same std_logic_ve

K

kristoff

Guest
Hi all,


I am sorry for this "newbie" question.

I bought a xula2 board last week so am now doing my first steps in VHDL
and learning the language and trying to master this (more "parallel"
way) of thinking.


I have this case:
you have an audiosensor that generates blockwaves when audio is received
(when the voltage of the audio is above a certain threshold, it
generates a "1", if not, it is "0").

The exercise it let the device detection audio in a certain frequency range.

In the MCU world,
one would implement this using interrrupts: generate an interrupt every
rising edge of audiosignal, count the number of edges per time-interval,
reset the counter to 0 and work from there on.

The problem in a FPGA is that the two threads (counting the edges and
timer-interval) work in parallel, so I guess there is a possible
conflict between the "increase number of samples by one" and the "reset
sample-counter" logic.
(in a MCU, you can configure the interrupts as such as this never
happens at the same time).


So, I am trying to understand how to do this is a FPGA.


I am sorry as I guess this is a FPGA 101 question, but can somebody
shine some light on this?



Cheerio! Kr. Bonne.
 
On 5/7/2016 9:51 AM, kristoff wrote:
Hi all,


I am sorry for this "newbie" question.

I bought a xula2 board last week so am now doing my first steps in VHDL
and learning the language and trying to master this (more "parallel"
way) of thinking.


I have this case:
you have an audiosensor that generates blockwaves when audio is received
(when the voltage of the audio is above a certain threshold, it
generates a "1", if not, it is "0").

The exercise it let the device detection audio in a certain frequency
range.

In the MCU world,
one would implement this using interrrupts: generate an interrupt every
rising edge of audiosignal, count the number of edges per time-interval,
reset the counter to 0 and work from there on.

The problem in a FPGA is that the two threads (counting the edges and
timer-interval) work in parallel, so I guess there is a possible
conflict between the "increase number of samples by one" and the "reset
sample-counter" logic.
(in a MCU, you can configure the interrupts as such as this never
happens at the same time).


So, I am trying to understand how to do this is a FPGA.


I am sorry as I guess this is a FPGA 101 question, but can somebody
shine some light on this?

First, I will say I think you are trying to measure the frequency of a
signal by a free running counter measuring the period of the waveform.
If that is not correct, the rest of this may not apply.

Yes, it can be difficult to think in terms of parallel hardware. But in
your case it is easier because your hardware is *not* parallel! I think
you are describing a counter that is incremented by the clock and read
and reset when the signal pulse edge is received, no?

One process will be triggered by the clock.

process (clk, reset) is
begin
if reset = '1' then
counter_val <= (others => '0');
elsif rising_edge(clk) then
counter_val <= counter_val + 1;
end if;
end process;

This just needs a section added to allow the counter to be reset when
the pulse edge is detected. To do that you first have to detect the
pulse edge. That can be in this same process or a different one. Then
that signal would be used by a conditional to instead of incrementing
the count, resetting it to zero.

Make sense? How would you do that?

--

Rick C
 
Hi Rickman,


(inline comments)


On 07-05-16 16:59, rickman wrote:
I have this case:
you have an audiosensor that generates blockwaves when audio is received
(when the voltage of the audio is above a certain threshold, it
generates a "1", if not, it is "0").
The exercise it let the device detection audio in a certain frequency
range.
In the MCU world,
one would implement this using interrrupts: generate an interrupt every
rising edge of audiosignal, count the number of edges per time-interval,
reset the counter to 0 and work from there on.
The problem in a FPGA is that the two threads (counting the edges and
timer-interval) work in parallel, so I guess there is a possible
conflict between the "increase number of samples by one" and the "reset
sample-counter" logic.
(in a MCU, you can configure the interrupts as such as this never
happens at the same time).

First, I will say I think you are trying to measure the frequency of a
signal by a free running counter measuring the period of the waveform.
If that is not correct, the rest of this may not apply.

Well, it's the other way around: count the number of rising-edges during
a certain interval; but the principe if of course the same.
:)


Yes, it can be difficult to think in terms of parallel hardware. But in
your case it is easier because your hardware is *not* parallel! I think
you are describing a counter that is incremented by the clock and read
and reset when the signal pulse edge is received, no?

Well, the reason I thought like that, is because that is how the design
was done on this particular MCU-based project: two "threads", one that
counts the number of rising edges and one that that "processes" this per
timeslot. (*)

And global data as a way for the two processes to communicate with
eachother.




* I know that counting rising edges of signals can be done in hardware
on a MCU.



One process will be triggered by the clock.

process (clk, reset) is
begin
if reset = '1' then
counter_val <= (others => '0');
elsif rising_edge(clk) then
counter_val <= counter_val + 1;
end if;
end process;

So, in fact, all code that change certain data need to be grouped in one
process?
Is this the conclussion?


> Make sense? How would you do that?

Yes. Makes sence.


Just wondering.

On the SPI interface of the STM32F1, there is a "TXNE" bit (part of the
"SR" register) which is set by the SPI hardware when data has been
received by the SPI interface.

And ... by just reading the received data from the SPI DR register, this
actually automatically resets that bit.


I wonder how you would describe this in VHDL.

Setting that bit is clearly done by one process (the process that drives
the SPI interface), ... but reading that data (and the result of
clearing that bit) is probaby done by code outside the SPI block.

Don't you have the same senario as I had: two processes trying to change
one piece of data (in this case, the TXNE bit).



Or am I seeing things to complicated here?



Cheerio!
Kr. Bonne.
 
On 5/8/2016 6:40 AM, kristoff wrote:
Hi Rickman,


(inline comments)


On 07-05-16 16:59, rickman wrote:
I have this case:
you have an audiosensor that generates blockwaves when audio is received
(when the voltage of the audio is above a certain threshold, it
generates a "1", if not, it is "0").
The exercise it let the device detection audio in a certain frequency
range.
In the MCU world,
one would implement this using interrrupts: generate an interrupt every
rising edge of audiosignal, count the number of edges per time-interval,
reset the counter to 0 and work from there on.
The problem in a FPGA is that the two threads (counting the edges and
timer-interval) work in parallel, so I guess there is a possible
conflict between the "increase number of samples by one" and the "reset
sample-counter" logic.
(in a MCU, you can configure the interrupts as such as this never
happens at the same time).


First, I will say I think you are trying to measure the frequency of a
signal by a free running counter measuring the period of the waveform.
If that is not correct, the rest of this may not apply.

Well, it's the other way around: count the number of rising-edges during
a certain interval; but the principe if of course the same.
:)

I see. You are describing two counters. One running from the clock to
measure the time period and another, running from the input signal to
count the number of transitions of the input signal.

BTW, just to point this out, it can be hard to get a digital signal that
corresponds to the frequency of an audio signal if that is what you are
doing. The audio signal can produce extraneous edges from the harmonic
and noise content.


Yes, it can be difficult to think in terms of parallel hardware. But in
your case it is easier because your hardware is *not* parallel! I think
you are describing a counter that is incremented by the clock and read
and reset when the signal pulse edge is received, no?

Well, the reason I thought like that, is because that is how the design
was done on this particular MCU-based project: two "threads", one that
counts the number of rising edges and one that that "processes" this per
timeslot. (*)

And global data as a way for the two processes to communicate with
eachother.

I don't see the need for global "data" exactly. IN VHDL there are
signals and variables. Variables exist only within a process because
they have meaning only in sequential code like a C variable and there is
no sequential code outside a process (or subprograms -
procedure/function). While true global variables exist in VHDL, signals
are what you would call global variables and are what you want to use
here. They are the heavy lifters in VHDL for the work of a signal you
would see on a wire in a hardware design. Because a variable does not
exist outside the process it is used in, a signal must be used to turn
that value into something that has "physical presence" if you will.


* I know that counting rising edges of signals can be done in hardware
on a MCU.



One process will be triggered by the clock.

process (clk, reset) is
begin
if reset = '1' then
counter_val <= (others => '0');
elsif rising_edge(clk) then
counter_val <= counter_val + 1;
end if;
end process;

So, in fact, all code that change certain data need to be grouped in one
process?
Is this the conclussion?

YES! If you assign a value to a signal from two processes it causes an
error because that corresponds to two logic outputs driving a voltage
onto the same wire.

<<Caution!>> One subtle error in VHDL comes from assigning part of a
vector in a process. There is a clause in the VHDL "contract" (read the
fine print in *all* contracts) that says if you assign part of a vector
in a process, you create drivers for all of it. Assign the rest of the
vector in another process and you now have two assignments to one signal
which equals <<error>>

I'm a bit fuzzy on the details of this. I've never run into this error
other than the mentions here. Perhaps someone else can flesh it out for
you?


Make sense? How would you do that?

Yes. Makes sence.


Just wondering.

On the SPI interface of the STM32F1, there is a "TXNE" bit (part of the
"SR" register) which is set by the SPI hardware when data has been
received by the SPI interface.

And ... by just reading the received data from the SPI DR register, this
actually automatically resets that bit.

TX usually means "transmit". Are you sure that is the right bit? Would
it be RX... maybe ready or not empty rather than TX..?


> I wonder how you would describe this in VHDL.

That is easy, I've done it many times. The flag is set by the data
being loaded into the receive data register. The address and control
bits are decoded as an enable. This enable is used to clear the flag.
What is critical is to deal with the condition of a new data being
received just as the old data is being read. So the address decode
needs to be registered as a one clock wide pulse to coincide with the
actual transfer of the data and not before. But that is only important
if you want to be able to receive new data while waiting for the old one
to be read and handle the flags without reporting overruns erroneously
to the exact clock cycle.


Setting that bit is clearly done by one process (the process that drives
the SPI interface), ... but reading that data (and the result of
clearing that bit) is probaby done by code outside the SPI block.

SPI is a multi clock "thing". The last time I designed one I coded the
shift register as one process using the external clock and the rest of
the logic on a separate clock. But each register was updated in *one
process*. It's ok for the address decode and state machine to be in a
different block. Just don't update any signals in both places.


Don't you have the same senario as I had: two processes trying to change
one piece of data (in this case, the TXNE bit).

No. Bring the address decode into the SPI as a "read" signal. This can
then be used to update the TXNE bit. Or the "data available" flag can
be brought into the bus interface module to update the flag there. Just
don't update the flag in both places.


> Or am I seeing things to complicated here?

You are thinking like software is all. Hardware is a little different.
I think in terms of the hardware and code to "describe" what I am
thinking of. That's why it's HDL, Hardware Description Language.
Others have shown me you can "think" in terms of the code as long as you
follow the rules. I've done this so long my rules are quite simpler
than the VHDL rules because there are plenty of things I just don't
consider doing. The result is I don't have to "think" about the
problems it causes as I'll never see those. But sometimes I forget the
details of why I do it that way.

A signal crossing a clock boundary is a bit ugly, but is important to be
done correctly. You can find a number of web pages on how to do this
correctly and a number of "correct" ways. This is a mistake that can
cause you a *lot* of debugging grief, so is best to just be done
correctly. If you want more info on that and can't find it with a
search, I can help. The important term is "metastability". I don't
think there is a software equivalent, but it is a bit like some of the
concerns with semaphores and interrupts.

--

Rick C
 
On 08.05.2016 12:40, kristoff wrote:
[...]
Well, the reason I thought like that, is because that is how the design
was done on this particular MCU-based project: two "threads", one that
counts the number of rising edges and one that that "processes" this per
timeslot. (*)

And global data as a way for the two processes to communicate with
eachother.

The problem you have here is not "thinking hardware". You have to keep
in mind that VHDL is a language that describes actual logic gates, not a
programming language.
A process describes a single piece of logic, with its inputs, outputs
and internal signals. Having several processes modify a single signal is
*exactly* connecting the outputs of different pieces together. As a
basic rule of electronics, you just Don't Do That (it has exceptions, of
course)


So, in fact, all code that change certain data need to be grouped in one
process?
Is this the conclussion?

Exactly.


Just wondering.
On the SPI interface of the STM32F1, there is a "TXNE" bit (part of the
"SR" register) which is set by the SPI hardware when data has been
received by the SPI interface.
And ... by just reading the received data from the SPI DR register, this
actually automatically resets that bit.
I wonder how you would describe this in VHDL.

Well the CPU bus must have a "read" signal somewhere so when the correct
address is presented and the read signal is active, the bit is cleared.


Setting that bit is clearly done by one process (the process that drives
the SPI interface), ... but reading that data (and the result of
clearing that bit) is probaby done by code outside the SPI block.

Don't you have the same senario as I had: two processes trying to change
one piece of data (in this case, the TXNE bit).

Or am I seeing things to complicated here?

I think you're confused by the term "process"
Your TXNE bit can be written as a set/reset flip flop in a single process:

process (clk, rst)
begin
if rst = '1' then
txne <= '0';
elsif rising_edge(clk) then
if set = '1' then
txne <= '1';
elsif reset = '1' then
txne <= '0';
end if;
end if;
end process;

I didn't think much about what should happen if both set and reset are
active at the same time. Here, set has precedence.

Nicolas
 
On Sun, 08 May 2016 10:56:57 -0400, rickman wrote:

On 5/8/2016 6:40 AM, kristoff wrote:
[snip]
YES! If you assign a value to a signal from two processes it causes an
error because that corresponds to two logic outputs driving a voltage
onto the same wire.

Caution!>> One subtle error in VHDL comes from assigning part of a
vector in a process. There is a clause in the VHDL "contract" (read
the
fine print in *all* contracts) that says if you assign part of a vector
in a process, you create drivers for all of it. Assign the rest of the
vector in another process and you now have two assignments to one
signal
which equals <<error

I'm a bit fuzzy on the details of this. I've never run into this error
other than the mentions here. Perhaps someone else can flesh it out
for
you?

I contend that it's not an error in the language. I would say it is hard
to understand, counterintuitive for beginners, PITA, etc., but not a
mistake for an HDL.

The search term to make you less fuzzy on the details is "longest static
prefix".
Basically if the compiler knows the bounds at compile time, it will do
what you want and only create drivers for the part of the vector that you
want to change.
If it doesn't know the bounds at compile time (e.g. if the bounds depend
on the value of a signal) then it will create drivers for all elements of
the vector (which is probably not what you want).

N.B. the drivers are part of the process. It doesn't matter if the
assignment statement in that process is never executed.

Regards,
Allan
 
On 5/9/2016 8:02 AM, Allan Herriman wrote:
On Sun, 08 May 2016 10:56:57 -0400, rickman wrote:

On 5/8/2016 6:40 AM, kristoff wrote:
[snip]
YES! If you assign a value to a signal from two processes it causes an
error because that corresponds to two logic outputs driving a voltage
onto the same wire.

Caution!>> One subtle error in VHDL comes from assigning part of a
vector in a process. There is a clause in the VHDL "contract" (read
the
fine print in *all* contracts) that says if you assign part of a vector
in a process, you create drivers for all of it. Assign the rest of the
vector in another process and you now have two assignments to one
signal
which equals <<error

I'm a bit fuzzy on the details of this. I've never run into this error
other than the mentions here. Perhaps someone else can flesh it out
for
you?

I contend that it's not an error in the language. I would say it is hard
to understand, counterintuitive for beginners, PITA, etc., but not a
mistake for an HDL.

The search term to make you less fuzzy on the details is "longest static
prefix".
Basically if the compiler knows the bounds at compile time, it will do
what you want and only create drivers for the part of the vector that you
want to change.
If it doesn't know the bounds at compile time (e.g. if the bounds depend
on the value of a signal) then it will create drivers for all elements of
the vector (which is probably not what you want).

N.B. the drivers are part of the process. It doesn't matter if the
assignment statement in that process is never executed.

N.B.??? Don't know what that means.

I wasn't trying to say it is an error of the tools or the language. It
is an error to assign a signal in two processes which is what happens if
the user is not aware that the full vector will be assigned.

--

Rick C
 
On Mon, 09 May 2016 09:53:47 -0400, rickman wrote:

On 5/9/2016 8:02 AM, Allan Herriman wrote:
On Sun, 08 May 2016 10:56:57 -0400, rickman wrote:

On 5/8/2016 6:40 AM, kristoff wrote:
[snip]
YES! If you assign a value to a signal from two processes it causes
an error because that corresponds to two logic outputs driving a
voltage onto the same wire.

Caution!>> One subtle error in VHDL comes from assigning part of a
vector in a process. There is a clause in the VHDL "contract" (read
the
fine print in *all* contracts) that says if you assign part of a
vector in a process, you create drivers for all of it. Assign the
rest of the vector in another process and you now have two assignments
to one
signal
which equals <<error

I'm a bit fuzzy on the details of this. I've never run into this
error other than the mentions here. Perhaps someone else can flesh it
out
for
you?

I contend that it's not an error in the language. I would say it is
hard to understand, counterintuitive for beginners, PITA, etc., but not
a mistake for an HDL.

The search term to make you less fuzzy on the details is "longest
static prefix".
Basically if the compiler knows the bounds at compile time, it will do
what you want and only create drivers for the part of the vector that
you want to change.
If it doesn't know the bounds at compile time (e.g. if the bounds
depend on the value of a signal) then it will create drivers for all
elements of the vector (which is probably not what you want).

N.B. the drivers are part of the process. It doesn't matter if the
assignment statement in that process is never executed.

N.B.??? Don't know what that means.

N.B. is the common abbreviation of the Latin "nota bene" - note well. I
assumed most English speakers would know it.

> I wasn't trying to say it is an error of the tools or the language.

I misunderstood.

It
is an error to assign a signal in two processes which is what happens if
the user is not aware that the full vector will be assigned.

The longest static prefix has drivers. This may or may not be the full
vector. Typically you would code it such that only the part you want to
have drivers, has drivers.

It's only an error if:
- you have multiple drivers on (a given slice of) an unresolved signal.
- you have multiple drivers on (a given slice of) a resolved signal that
doesn't match the synthesis template for a tri-state connection (in
synthesis only).


To the OP, Rick's advice is the one to follow for a "newbie" - only make
assignments to a signal from one process (or concurrent assignment, which
counts as process in this context). This will avoid many pitfalls.

It takes a while to get your head around concepts such as drivers and the
longest static prefix. You'll need to know them eventually if you
persist with the language though.

Allan
 
On 5/9/2016 11:52 AM, Allan Herriman wrote:
On Mon, 09 May 2016 09:53:47 -0400, rickman wrote:

On 5/9/2016 8:02 AM, Allan Herriman wrote:
On Sun, 08 May 2016 10:56:57 -0400, rickman wrote:

On 5/8/2016 6:40 AM, kristoff wrote:
[snip]
YES! If you assign a value to a signal from two processes it causes
an error because that corresponds to two logic outputs driving a
voltage onto the same wire.

Caution!>> One subtle error in VHDL comes from assigning part of a
vector in a process. There is a clause in the VHDL "contract" (read
the
fine print in *all* contracts) that says if you assign part of a
vector in a process, you create drivers for all of it. Assign the
rest of the vector in another process and you now have two assignments
to one
signal
which equals <<error

I'm a bit fuzzy on the details of this. I've never run into this
error other than the mentions here. Perhaps someone else can flesh it
out
for
you?

I contend that it's not an error in the language. I would say it is
hard to understand, counterintuitive for beginners, PITA, etc., but not
a mistake for an HDL.

The search term to make you less fuzzy on the details is "longest
static prefix".
Basically if the compiler knows the bounds at compile time, it will do
what you want and only create drivers for the part of the vector that
you want to change.
If it doesn't know the bounds at compile time (e.g. if the bounds
depend on the value of a signal) then it will create drivers for all
elements of the vector (which is probably not what you want).

N.B. the drivers are part of the process. It doesn't matter if the
assignment statement in that process is never executed.

N.B.??? Don't know what that means.

N.B. is the common abbreviation of the Latin "nota bene" - note well. I
assumed most English speakers would know it.

I wasn't trying to say it is an error of the tools or the language.

I misunderstood.

It
is an error to assign a signal in two processes which is what happens if
the user is not aware that the full vector will be assigned.

The longest static prefix has drivers. This may or may not be the full
vector. Typically you would code it such that only the part you want to
have drivers, has drivers.

This is one of the things I don't like about VHDL, the complexity. Just
looking up the term "longest static prefix" gives hard to understand
results. It is not a thing that is actually dealt with while coding a
typical program, so I just don't do things that trigger the problem and
I can ignore it. In other words, I work from mental templates rather
than trying to always remember all the details of the language. There's
just so much storage up there and I need to focus on the more useful
information.

That is what Kristoff should do. Learn the "right" way of thinking of
HDL programming rather than learning all the nuance of the language. I
don't think this necessarily means to think in terms of the hardware
produced (although that is what I do). However, it is important to
think in terms of concurrent (parallel) processes rather than sequential
code. Every concurrent statement is a process that runs in parallel
with all the others.

--

Rick C
 
Nicolas, (and Rickman)






On 08-05-16 19:21, Nicolas Matringe wrote:

Well, the reason I thought like that, is because that is how the design
was done on this particular MCU-based project: two "threads", one that
counts the number of rising edges and one that that "processes" this per
timeslot. (*)

And global data as a way for the two processes to communicate with
eachother.

The problem you have here is not "thinking hardware". You have to keep
in mind that VHDL is a language that describes actual logic gates, not a
programming language.

Well, the reason I am interested in FPGAs is to -from what I read about
it- it seams to requite a completely different way of thinking then I am
used when writing code.

And that is now my main problem.
If you look on the net, there is quite some information on FPGAs, on
VHDL and building your first "blinky", etc. So actually getting started
is not that difficult.

The next step, learning to get your brain into the correct "twist" and
learn to think hardware, will probably require doing a large number of
exercises. But this is a lot more difficult to find.

I was actually a bit surprised to see there are no courses on FPGA, VHDL
or verilog on any of the major MOOC flatforms (edx, coursera, ...) as I
hoped thse would have been the places to find the exercises I need.



A process describes a single piece of logic, with its inputs, outputs
and internal signals. Having several processes modify a single signal is
*exactly* connecting the outputs of different pieces together. As a
basic rule of electronics, you just Don't Do That (it has exceptions, of
course)

I know, and that I also told myself beforehand ... but you know, my
experience gave me a different feeling.


The first exercise I did for myself was PWM, based on the logic of how
an arduino does PWM: a counter that goes up in loops, a PWM output pin
that goes to "1" on counter=0 and "0" on couter=pwm-value.


So the logic I had was this:
--- cut here --- cut here --- cut here --- cut here ---

(...)
signal led_t : std_logic := '0';
signal pwm_r : std_logic_vector(18 downto 0) := "1000000000000000000";
(...)

process(clk_in,cnt_r,pwm_r) is
begin
if falling_edge(clk_in) then
if cnt_r = pwm_r then
led_t <= '0';
elsif cnt_r = 0 then
led_t <= '1';
end if;
end if;
end process;
led <= led_t;
--- cut here --- cut here --- cut here --- cut here ---


In fact, this seams to work, which was ... great.

Actually, my first thought was, ... well, this is not that much unlike
coding afterall.

Apparently, the language is intelligent enough to see that "led_t" is
changed under certain conditions, but there are also moments when it is
not changed; ... so by itself it seams to create a "memory-cell" for
that output pin. Nice! :)


However, I think this particular example kind-of gave me the wrong
impression. :-(






Just wondering.
On the SPI interface of the STM32F1, there is a "TXNE" bit (part of the
"SR" register) which is set by the SPI hardware when data has been
received by the SPI interface.
And ... by just reading the received data from the SPI DR register, this
actually automatically resets that bit.
I wonder how you would describe this in VHDL.

Well the CPU bus must have a "read" signal somewhere so when the correct
address is presented and the read signal is active, the bit is cleared.

Well, I have been thinking about this.


My "problem" is to image how a "read" action (which is for the actual
piece of hardware containing the data quite a "passive" thing) can
trigger a action (in this case, erase the RXNE bit).

But I guess "reading data from a register" this is not really the just
"reading data". It's probably a "write" action: copy the data from the
register to the internal bus of the processor and -once that is done-
clear it.
(althou, isn't this a "sequencial" action ???)




Setting that bit is clearly done by one process (the process that drives
the SPI interface), ... but reading that data (and the result of
clearing that bit) is probaby done by code outside the SPI block.

Don't you have the same senario as I had: two processes trying to change
one piece of data (in this case, the TXNE bit).

Or am I seeing things to complicated here?

I think you're confused by the term "process"
Your TXNE bit can be written as a set/reset flip flop in a single process:

process (clk, rst)
begin
if rst = '1' then
txne <= '0';
elsif rising_edge(clk) then
if set = '1' then
txne <= '1';
elsif reset = '1' then
txne <= '0';
end if;
end if;
end process;
I didn't think much about what should happen if both set and reset are
active at the same time. Here, set has precedence.

OK, my mind-problem is this:

Perhaps it is my "IT" mind, but I tend to look at information as "data".

In this case, there is a piece of information (the "clock counter") and
two actions ("increase the value by one" and "reset the value to zero").

Around this piece of information, there is a box to execute these
actions, which can be implemented in software or in hardware.



The main difference, as I see it, is that software and hardware work
with two different mechanisms:

- software is based on a "single-shot" event. Something or someone sends
a command to the black box managing the information (i.e. the command
"reset the counter to 0"), that command is executed and that is it.


- in contrast, hardware is based on a "state" (e.g. the nRST-line is set
low -> the value of the register is set to zero). This state remains
valid as long as the nRST is low. (so to make the counter "active"
again, the nRST line must to reset to 1).
(this is also how you implemented this in your VHDL example, no?)



So, if I am not wrong, I want to reset the counter to zero, I first need
to set the nRST line to 0, and then set it back to 1 again; ... which is
works ... except that this is a is a "sequencial" action.
And I just though that the whole idea of VHDL was that everything runs
in parallel, not in serie.


Or not?



> Nicolas

Cheerio! Kr. Bonne.
 
Hi Rickman,
(and everybody else that replied).



On 08-05-16 16:56, rickman wrote:
Well, it's the other way around: count the number of rising-edges during
a certain interval; but the principe if of course the same.
:)

I see. You are describing two counters. One running from the clock to
measure the time period and another, running from the input signal to
count the number of transitions of the input signal.

Correct.



BTW, just to point this out, it can be hard to get a digital signal that
corresponds to the frequency of an audio signal if that is what you are
doing. The audio signal can produce extraneous edges from the harmonic
and noise content.

Yes, but this is not a practicle example.

I give a arduino / microcontroller / programming course one a month in
our local ham-radio club here in Ostend (Belgium) and this was one of
the exercises we did on microcontrollers (actually an exercise on using
interrupts).

Last week, I gave a small demo on FPGAs in that course and we tried to
use that exercise as an example to try to find out what it would look
like on a FPGA instead of on e FPGA.



Yes, it can be difficult to think in terms of parallel hardware. But in
your case it is easier because your hardware is *not* parallel! I think
you are describing a counter that is incremented by the clock and read
and reset when the signal pulse edge is received, no?

Well, the reason I thought like that, is because that is how the design
was done on this particular MCU-based project: two "threads", one that
counts the number of rising edges and one that that "processes" this per
timeslot. (*)

And global data as a way for the two processes to communicate with
eachother.

I don't see the need for global "data" exactly. IN VHDL there are
signals and variables. Variables exist only within a process because
they have meaning only in sequential code like a C variable and there is
no sequential code outside a process (or subprograms -
procedure/function). While true global variables exist in VHDL, signals
are what you would call global variables and are what you want to use
here. They are the heavy lifters in VHDL for the work of a signal you
would see on a wire in a hardware design. Because a variable does not
exist outside the process it is used in, a signal must be used to turn
that value into something that has "physical presence" if you will.

Well, looking at this from a "conceptual" point of view, I am a bit
puzzled here.


From how I understand from FPGAs up to now, the main idea is that a lot
more is done in parallel then on a MCU based setup (which mainly uses a
sequencial approach).


Now i used to do some multithreaded programming on unix before and
interrupt-drive code on MCUs, and my experience is that the more you
make things runs in parallel, the more need there is for
interprocess-communication.


Or not ?


YES! If you assign a value to a signal from two processes it causes an
error because that corresponds to two logic outputs driving a voltage
onto the same wire.

So, if there is really a need for multiple processes driving a pin, you
need to "and" or "or" them.




Caution!>> One subtle error in VHDL comes from assigning part of a
vector in a process. There is a clause in the VHDL "contract" (read the
fine print in *all* contracts) that says if you assign part of a vector
in a process, you create drivers for all of it. Assign the rest of the
vector in another process and you now have two assignments to one signal
which equals <<error

I'm a bit fuzzy on the details of this. I've never run into this error
other than the mentions here. Perhaps someone else can flesh it out for
you?

OK. Noted.




On the SPI interface of the STM32F1, there is a "TXNE" bit (part of the
"SR" register) which is set by the SPI hardware when data has been
received by the SPI interface.
And ... by just reading the received data from the SPI DR register, this
actually automatically resets that bit.

TX usually means "transmit". Are you sure that is the right bit? Would
it be RX... maybe ready or not empty rather than TX..?

Yes, sorry. Typo. :-(



I wonder how you would describe this in VHDL.

That is easy, I've done it many times. The flag is set by the data
being loaded into the receive data register. The address and control
bits are decoded as an enable. This enable is used to clear the flag.

OK. I think I kind-of understand this.

(...)


Setting that bit is clearly done by one process (the process that drives
the SPI interface), ... but reading that data (and the result of
clearing that bit) is probaby done by code outside the SPI block.

SPI is a multi clock "thing". The last time I designed one I coded the
shift register as one process using the external clock and the rest of
the logic on a separate clock. But each register was updated in *one
process*. It's ok for the address decode and state machine to be in a
different block. Just don't update any signals in both places.

Interesting idea. So even inside one "thing", there can be multiple closks.




Or am I seeing things to complicated here?

You are thinking like software is all.

This could be very correct.

(and -as mentioned in my other message- it's actually the main reason I
bought this FPGA kit, to learn to think differently :) )



... Hardware is a little different.
I think in terms of the hardware and code to "describe" what I am
thinking of. That's why it's HDL, Hardware Description Language. Others
have shown me you can "think" in terms of the code as long as you follow
the rules. I've done this so long my rules are quite simpler than the
VHDL rules because there are plenty of things I just don't consider
doing. The result is I don't have to "think" about the problems it
causes as I'll never see those. But sometimes I forget the details of
why I do it that way.

I understand.

As mentioned in my other message, I probably could do with a lot more
exercises to get the hang of this.


My problem -I think- at this time is how to translate "sequencial"
processes into a "parallel" way of thinking.




A signal crossing a clock boundary is a bit ugly, but is important to be
done correctly. You can find a number of web pages on how to do this
correctly and a number of "correct" ways. This is a mistake that can
cause you a *lot* of debugging grief, so is best to just be done
correctly. If you want more info on that and can't find it with a
search, I can help. The important term is "metastability". I don't
think there is a software equivalent, but it is a bit like some of the
concerns with semaphores and interrupts.

OK. Thanks! :)



Cheerio! Kr. Bonne.
 
On 5/9/2016 4:54 PM, kristoff wrote:
Hi Rickman,
(and everybody else that replied).



On 08-05-16 16:56, rickman wrote:
Well, it's the other way around: count the number of rising-edges during
a certain interval; but the principe if of course the same.
:)

I see. You are describing two counters. One running from the clock to
measure the time period and another, running from the input signal to
count the number of transitions of the input signal.

Correct.



BTW, just to point this out, it can be hard to get a digital signal that
corresponds to the frequency of an audio signal if that is what you are
doing. The audio signal can produce extraneous edges from the harmonic
and noise content.

Yes, but this is not a practicle example.

I give a arduino / microcontroller / programming course one a month in
our local ham-radio club here in Ostend (Belgium) and this was one of
the exercises we did on microcontrollers (actually an exercise on using
interrupts).

Last week, I gave a small demo on FPGAs in that course and we tried to
use that exercise as an example to try to find out what it would look
like on a FPGA instead of on e FPGA.



Yes, it can be difficult to think in terms of parallel hardware.
But in
your case it is easier because your hardware is *not* parallel! I
think
you are describing a counter that is incremented by the clock and read
and reset when the signal pulse edge is received, no?

Well, the reason I thought like that, is because that is how the design
was done on this particular MCU-based project: two "threads", one that
counts the number of rising edges and one that that "processes" this per
timeslot. (*)

And global data as a way for the two processes to communicate with
eachother.

I don't see the need for global "data" exactly. IN VHDL there are
signals and variables. Variables exist only within a process because
they have meaning only in sequential code like a C variable and there is
no sequential code outside a process (or subprograms -
procedure/function). While true global variables exist in VHDL, signals
are what you would call global variables and are what you want to use
here. They are the heavy lifters in VHDL for the work of a signal you
would see on a wire in a hardware design. Because a variable does not
exist outside the process it is used in, a signal must be used to turn
that value into something that has "physical presence" if you will.


Well, looking at this from a "conceptual" point of view, I am a bit
puzzled here.


From how I understand from FPGAs up to now, the main idea is that a lot
more is done in parallel then on a MCU based setup (which mainly uses a
sequencial approach).


Now i used to do some multithreaded programming on unix before and
interrupt-drive code on MCUs, and my experience is that the more you
make things runs in parallel, the more need there is for
interprocess-communication.


Or not ?

Absolutely! Inter-process communication in an HDL is done by a wire,
also known as a signal. It can't get much simpler than that. A signal
can be a single bit, a vector or even an integer.

Parallel processes on a CPU are complicated because they aren't really
in parallel and the CPU has to be shared between them. In hardware,
processes are truly parallel because they have their own hardware to run
on. Here is an example.

ralph: process (A, B) is
begin
C <= A and B;
end process;

malph: process (C, D) is
begin
E <= C or D;
end process;

C is used to communicate between the process ralph and process malph.

Here is an interesting point. These two processes are scheduled by the
sensitivity list, the names in parentheses. Process ralph will run any
time there is a change on signal A or signal B. Process malph runs any
time there is a change on signals C or D. When they reach the end of
the process they are suspended.

A process can also have explicit wait statements, but they aren't
typically used in synthesized code.


YES! If you assign a value to a signal from two processes it causes an
error because that corresponds to two logic outputs driving a voltage
onto the same wire.

So, if there is really a need for multiple processes driving a pin, you
need to "and" or "or" them.

If you gate them together, the two process outputs (drivers) aren't
actually driving the same signal, so yes.


Caution!>> One subtle error in VHDL comes from assigning part of a
vector in a process. There is a clause in the VHDL "contract" (read the
fine print in *all* contracts) that says if you assign part of a vector
in a process, you create drivers for all of it. Assign the rest of the
vector in another process and you now have two assignments to one signal
which equals <<error

I'm a bit fuzzy on the details of this. I've never run into this error
other than the mentions here. Perhaps someone else can flesh it out for
you?


OK. Noted.




On the SPI interface of the STM32F1, there is a "TXNE" bit (part of the
"SR" register) which is set by the SPI hardware when data has been
received by the SPI interface.
And ... by just reading the received data from the SPI DR register, this
actually automatically resets that bit.

TX usually means "transmit". Are you sure that is the right bit? Would
it be RX... maybe ready or not empty rather than TX..?

Yes, sorry. Typo. :-(



I wonder how you would describe this in VHDL.

That is easy, I've done it many times. The flag is set by the data
being loaded into the receive data register. The address and control
bits are decoded as an enable. This enable is used to clear the flag.

OK. I think I kind-of understand this.

(...)


Setting that bit is clearly done by one process (the process that drives
the SPI interface), ... but reading that data (and the result of
clearing that bit) is probaby done by code outside the SPI block.

SPI is a multi clock "thing". The last time I designed one I coded the
shift register as one process using the external clock and the rest of
the logic on a separate clock. But each register was updated in *one
process*. It's ok for the address decode and state machine to be in a
different block. Just don't update any signals in both places.

Interesting idea. So even inside one "thing", there can be multiple closks.

SPI has a clock for the interface. You can use that clock to run the
shift registers input and output (or use the same register for both).
SPI doesn't guarantee any clock pulses on SCLK outside of the ones to
shift the data, so the controller normally has another clock which runs
separately. If it is fairly much faster than the SPI clock, you can
sample all the interface signals on the internal clock and run
everything on one clock. This can reduce the setup or hold time on the
I/O pins though so make sure you have plenty of it. Also, when sampling
the input signals which are from a different clock domain, you need to
run them through two FFs to deal with metastability. Metastability is a
whole topic in itself.


Or am I seeing things to complicated here?

You are thinking like software is all.


This could be very correct.

(and -as mentioned in my other message- it's actually the main reason I
bought this FPGA kit, to learn to think differently :) )



... Hardware is a little different.
I think in terms of the hardware and code to "describe" what I am
thinking of. That's why it's HDL, Hardware Description Language. Others
have shown me you can "think" in terms of the code as long as you follow
the rules. I've done this so long my rules are quite simpler than the
VHDL rules because there are plenty of things I just don't consider
doing. The result is I don't have to "think" about the problems it
causes as I'll never see those. But sometimes I forget the details of
why I do it that way.

I understand.

As mentioned in my other message, I probably could do with a lot more
exercises to get the hang of this.


My problem -I think- at this time is how to translate "sequencial"
processes into a "parallel" way of thinking.

That's easy for me, I visualize the logic.

RTL is register transfer language. It describes a level of coding where
the registers are described by sequential processes (ones triggered by a
clock) and combinatorial processes. These can be combined as well, with
both the register and the logic described together.

This is a simple register process.

smpl_reg: process (clk,reset) is
begin
if reset = '1' then
counter <= (others => '0');
elsif rising_edge(clk) then
counter <= next_counter;
end if;
end process smpl_reg;

Here is the logic as a concurrent statement which can also be written as
a process.

next_counter <= counter + 1;


This is a register with the logic together.

smpl_reg: process (clk,reset) is
begin
if reset = '1' then
counter <= (others => '0');
elsif rising_edge(clk) then
counter <= counter + 1;
end if;
end process smpl_reg;

All of this is RTL. Behavioral descriptions are a bit less to the point
of "this is a register" and are a bit more abstract, but fundamentally
the same flow.

Sequential is often used for combinatorial logic.

comb_logic: process (addr, r_w, stb) is
begin
reg_a <= '0';
reg_b <= '0';
...
case addr is
when "0000"
reg_a <= '1';
when "0001"
reg_b <= '1';
when "0010"
...
end case;
end process;

This would be a lot more messy and a lot less clear if done in
concurrent statements.

--

Rick C
 
On 5/9/2016 4:29 PM, kristoff wrote:
Nicolas, (and Rickman)

On 08-05-16 19:21, Nicolas Matringe wrote:

Well, the reason I thought like that, is because that is how the design
was done on this particular MCU-based project: two "threads", one that
counts the number of rising edges and one that that "processes" this per
timeslot. (*)

And global data as a way for the two processes to communicate with
eachother.

The problem you have here is not "thinking hardware". You have to keep
in mind that VHDL is a language that describes actual logic gates, not a
programming language.


Well, the reason I am interested in FPGAs is to -from what I read about
it- it seams to requite a completely different way of thinking then I am
used when writing code.

And that is now my main problem.
If you look on the net, there is quite some information on FPGAs, on
VHDL and building your first "blinky", etc. So actually getting started
is not that difficult.

The next step, learning to get your brain into the correct "twist" and
learn to think hardware, will probably require doing a large number of
exercises. But this is a lot more difficult to find.

I was actually a bit surprised to see there are no courses on FPGA, VHDL
or verilog on any of the major MOOC flatforms (edx, coursera, ...) as I
hoped thse would have been the places to find the exercises I need.

Chicken and egg I think. FPGAs are not as widely used as are MCUs and
CPUs, so they aren't taught as much, so they aren't as widely used.
They have a reputation for being much harder to program and for being
much harder to put on a board. But that depends on which one you
choose. There are FPGAs like MCUs, available in small packages for
small tasks. There are FPGAs like an Intel i7 which have a thousand
pins and need a heat sink. I don't use those in my designs.


A process describes a single piece of logic, with its inputs, outputs
and internal signals. Having several processes modify a single signal is
*exactly* connecting the outputs of different pieces together. As a
basic rule of electronics, you just Don't Do That (it has exceptions, of
course)

I know, and that I also told myself beforehand ... but you know, my
experience gave me a different feeling.


The first exercise I did for myself was PWM, based on the logic of how
an arduino does PWM: a counter that goes up in loops, a PWM output pin
that goes to "1" on counter=0 and "0" on couter=pwm-value.


So the logic I had was this:
--- cut here --- cut here --- cut here --- cut here ---

(...)
signal led_t : std_logic := '0';
signal pwm_r : std_logic_vector(18 downto 0) := "1000000000000000000";
(...)

process(clk_in,cnt_r,pwm_r) is
begin
if falling_edge(clk_in) then
if cnt_r = pwm_r then
led_t <= '0';
elsif cnt_r = 0 then
led_t <= '1';
end if;
end if;
end process;
led <= led_t;
--- cut here --- cut here --- cut here --- cut here ---


In fact, this seams to work, which was ... great.

Did you get any warnings at compile? The sensitivity list of a process
is not a list of inputs. It is the signals that need to trigger the
process to run. If the process were combinatorial, it would be
everything on the right of an assignment statement, but since this is
sequential, it is just the clock and the reset, which you didn't use, so
just the clock needs to be here.


Actually, my first thought was, ... well, this is not that much unlike
coding afterall.

Apparently, the language is intelligent enough to see that "led_t" is
changed under certain conditions, but there are also moments when it is
not changed; ... so by itself it seams to create a "memory-cell" for
that output pin. Nice! :)

Yes, if you wrote code like this in a combinatorial process it would
produce a latch rather than a register. Usually these are inadvertent,
leaving the ELSE off an IF statement, for example.


However, I think this particular example kind-of gave me the wrong
impression. :-(

Not sure why. I think you have the right view of it.


Just wondering.
On the SPI interface of the STM32F1, there is a "TXNE" bit (part of the
"SR" register) which is set by the SPI hardware when data has been
received by the SPI interface.
And ... by just reading the received data from the SPI DR register, this
actually automatically resets that bit.
I wonder how you would describe this in VHDL.

Well the CPU bus must have a "read" signal somewhere so when the correct
address is presented and the read signal is active, the bit is cleared.

Well, I have been thinking about this.


My "problem" is to image how a "read" action (which is for the actual
piece of hardware containing the data quite a "passive" thing) can
trigger a action (in this case, erase the RXNE bit).

Reads are *not* passive. Read is done via a bus just like a write. The
only difference is one or two of the control lines are in a different
state. To store data of a write, a register is enabled by logic driven
by the address and control lines. Do the same thing to clear a bit on a
read. The hardware works the same way.


But I guess "reading data from a register" this is not really the just
"reading data". It's probably a "write" action: copy the data from the
register to the internal bus of the processor and -once that is done-
clear it.
(althou, isn't this a "sequencial" action ???)

Clear what? The data or the RXNE bit? It can be done in parallel, but
sequential is a coding method that can be used. Registers can be
described in concurrent statements, but conventionally that is not used.


Setting that bit is clearly done by one process (the process that drives
the SPI interface), ... but reading that data (and the result of
clearing that bit) is probaby done by code outside the SPI block.

Don't you have the same senario as I had: two processes trying to change
one piece of data (in this case, the TXNE bit).

Or am I seeing things to complicated here?

I think you're confused by the term "process"
Your TXNE bit can be written as a set/reset flip flop in a single
process:

process (clk, rst)
begin
if rst = '1' then
txne <= '0';
elsif rising_edge(clk) then
if set = '1' then
txne <= '1';
elsif reset = '1' then
txne <= '0';
end if;
end if;
end process;
I didn't think much about what should happen if both set and reset are
active at the same time. Here, set has precedence.


OK, my mind-problem is this:

Perhaps it is my "IT" mind, but I tend to look at information as "data".

In this case, there is a piece of information (the "clock counter") and
two actions ("increase the value by one" and "reset the value to zero").

Around this piece of information, there is a box to execute these
actions, which can be implemented in software or in hardware.



The main difference, as I see it, is that software and hardware work
with two different mechanisms:

- software is based on a "single-shot" event. Something or someone sends
a command to the black box managing the information (i.e. the command
"reset the counter to 0"), that command is executed and that is it.


- in contrast, hardware is based on a "state" (e.g. the nRST-line is set
low -> the value of the register is set to zero). This state remains
valid as long as the nRST is low. (so to make the counter "active"
again, the nRST line must to reset to 1).
(this is also how you implemented this in your VHDL example, no?)



So, if I am not wrong, I want to reset the counter to zero, I first need
to set the nRST line to 0, and then set it back to 1 again; ... which is
works ... except that this is a is a "sequencial" action.
And I just though that the whole idea of VHDL was that everything runs
in parallel, not in serie.

No, everything in parallel is not "the whole idea". That is how it can
work. But sequential code can be turned into hardware just as well as
concurrent code. Everything inside a process is sequential code.
Everything at the top level of an architecture (outside a process and
including the process itself) is concurrent code and in parallel.

When you think of a bit being set to '1' and then back to '0', that can
all be specified by one command.

nRST <= '0' when cnt_r = pwm_r else '1'.

I think you are making this a bit harder than it needs to be. I
remember I had trouble thinking of this when I started. You need to
*not* compare it to software all the time just because it is different
and software is what you know. Focusing on the differences is
confusing. Instead just focus on how HDL works.

--

Rick C
 
Hi rickman,



On 10-05-16 03:59, rickman wrote:
(...)


Not that much time now (I'm on the train to work now).


Thanks for all the information. All very interesting.


I think, at this point, it boils down to one thing: make more exercises
and try it out.


Do you (or anymore else) happen to know a good website, online course
or book with actual exercises to learn this?




Cheerio! Kr. Bonne.
 
Whenever I start to explain VHDL to a new guy I start with explaining how the language is used as a simulator (its original purpose). That only takes ten minutes and then it is only another five to explain how the code is then synthesized. It would take much longer here but if you find an article on it it would speed up your understanding.

Colin
 
On 10.05.2016 08:32, kristoff wrote:
I think, at this point, it boils down to one thing: make more exercises
and try it out.

I think you need some digital electronics basic course (combinatorial
logic, flip-flops, counters) and then see how they are described in
VHDL, to make you feel how it works.

The fact that processes are called "sequential" is a bit confusing for
SW people. A process doesn't run, it just describes a piece of electronics.

Nicolas
 

Welcome to EDABoard.com

Sponsor

Back
Top