ch10.16.htm
来自「介绍asci设计的一本书」· HTM 代码 · 共 545 行 · 第 1/2 页
HTM
545 行
<HTML>
<HEAD>
<META NAME="GENERATOR" CONTENT="Adobe PageMill 2.0 Mac">
<TITLE> 10.16 An Engine Controller</TITLE>
</HEAD><!--#include file="top.html"--><!--#include file="header.html"--><br><!--#include file="AmazonAsic.html"-->
<P><A NAME="pgfId=65561"></A><A HREF="CH10.htm">Chapter start</A> <A
HREF="CH10.15.htm">Previous page</A> <A HREF="CH10.17.htm">Next page</A></P>
<H2>10.16 An Engine Controller</H2>
<P><P CLASS="BodyAfterHead"><A NAME="pgfId=426080"></A>This section describes
part of a controller for an automobile engine. Table 10.21 shows a
temperature converter that converts digitized temperature readings from
a sensor from degrees Centigrade to degrees Fahrenheit.</P>
<P><TABLE BORDER="1" CELLSPACING="2" CELLPADDING="2">
<TR>
<TH COLSPAN="2" ALIGN="LEFT"><P ALIGN=LEFT><P CLASS="TableTitle"><A NAME="pgfId=428261"></A>TABLE 10.21 A
temperature converter.</TH></TR>
<TR>
<TD ROWSPAN="2" VALIGN="TOP"><PRE><B>library</B> IEEE;
<B>use</B> IEEE.STD_LOGIC_1164.<B>all</B>; -- type STD_LOGIC, rising_edge
<B>use</B> IEEE.NUMERIC_STD.<B>all</B> ; -- type UNSIGNED, "+", "/"
<B>entity</B> tconv <B>is generic </B>TPD : TIME:= 1 ns;
<B>port</B> (T_in : <B>in</B> UNSIGNED(11 <B>downto</B> 0);
clk, rst : <B>in</B> STD_LOGIC; T_out : <B>out</B> UNSIGNED(11 <B>downto</B> 0));
<B>end</B>;
<B>architecture</B> rtl <B>of</B> tconv <B>is</B>
<B>signal</B> T : UNSIGNED(7 <B>downto</B> 0);
<B>constant</B> T2 : UNSIGNED(1 <B>downto</B> 0) := "10" ;
<B>constant</B> T4 : UNSIGNED(2 <B>downto</B> 0) := "100" ;
<B>constant</B> T32 : UNSIGNED(5 <B>downto</B> 0) := "100000" ;
<B>begin</B>
<B> process</B>(T) <B>begin</B> T_out <= T + T/T2 + T/T4 + T32 <B>after</B> TPD;
<B> end</B> <B>process</B>;
<B>end</B> rtl;</PRE>
</TD>
<TD ROWSPAN="2"><P><P CLASS="TableLeft"><A NAME="pgfId=463945"></A><CODE>T_in</CODE> = temperature
in degC</P>
<P><P CLASS="TableLeft"><A NAME="pgfId=463911"></A> </P>
<P><P CLASS="TableLeft"><A NAME="pgfId=463912"></A><CODE>T_out</CODE> =
temperature in degF</P>
<P><P CLASS="TableLeft"><A NAME="pgfId=428335"></A> </P>
<P><P CLASS="TableLeft"><A NAME="pgfId=464581"></A>The conversion formula
from Centigrade to Fahrenheit is:</P>
<P><P CLASS="TableLeft"><A NAME="pgfId=465025"></A>T(degF) = (9/5) x T(degC)
+ 32</P>
<P><P CLASS="TableLeft"><A NAME="pgfId=464585"></A> </P>
<P><P CLASS="TableLeft"><A NAME="pgfId=463931"></A>This converter uses the
approximation:</P>
<P><P CLASS="TableLeft"><A NAME="pgfId=463932"></A>9/5 = 1.75 = 1 + 0.5
+ 0.25</TD></TR>
<TR></TR>
</TABLE>
<P CLASS="Body"><A NAME="pgfId=445069"></A>To save area the temperature
conversion is approximate. Instead of multiplying by 9/5 and adding 32 (so
0 degC becomes 32 degF and 100 degC becomes 212 degF) we multiply by 1.75
and add 32 (so 100 degC becomes 207 degF). Since 1.75 = 1 + 0.5 + 0.25,
we can multiply by 1.75 using shifts (for divide by 2, and divide by 4)
together with a very simple constant addition (since 32 = "100000").
Using shift to multiply and divide by powers of 2 is free in hardware (we
just change connections to a bus). For large temperatures the error approaches
0.05/1.8 or approximately 3 percent. We play these kinds of tricks often
in hardware computation. Notice also that temperatures measured in degC
and degF are defined as unsigned integers of the same width. We could have
defined these as separate types to take advantage of VHDL's type checking.</P>
<P><P CLASS="Body"><A NAME="pgfId=464464"></A>Table 10.22 describes
a digital filter to compute a "moving average" over four successive
samples in time (i(0), i(1), i(2), and i(3), with <CODE>i(0)</CODE> being
the first sample).</P>
<P><TABLE BORDER="1" CELLSPACING="2" CELLPADDING="2">
<TR>
<TH COLSPAN="2" ALIGN="LEFT"><P ALIGN=LEFT><P CLASS="TableTitle"><A NAME="pgfId=464962"></A>TABLE 10.22 A
digital filter.</TH></TR>
<TR>
<TD ROWSPAN="2" VALIGN="TOP"><PRE><B>library</B> IEEE;
<B>use</B> IEEE.STD_LOGIC_1164.<B>all</B>; -- STD_LOGIC type, rising_edge
<B>use</B> IEEE.NUMERIC_STD.<B>all</B>; -- UNSIGNED type, "+" and "/"
<B>entity</B> filter <B>is </B>
<B>generic </B>TPD : TIME := 1 ns;
<B>port</B> (T_in : <B>in</B> UNSIGNED(11 <B>downto</B> 0);
rst, clk : <B>in</B> STD_LOGIC;
T_out: <B>out</B> UNSIGNED(11 <B>downto</B> 0));
<B>end</B>;
<B>architecture</B> rtl <B>of</B> filter <B>is</B>
<B>type</B> arr <B>is</B> <B>array</B> (0 <B>to</B> 3) <B>of</B> UNSIGNED(11 <B>downto</B> 0);
<B>signal</B> i : arr ;
<B>constant</B> T4 : UNSIGNED(2 <B>downto</B> 0) := "100";
<B>begin</B>
<B>process</B>(rst, clk) <B>begin</B>
<B>if</B> (rst = '1') <B>then</B>
<B>for</B> n <B>in</B> 0 <B>to</B> 3 <B>loop </B>i(n) <= (<B>others</B> =>'0') <B>after</B> TPD;
<B> end</B> <B>loop</B>;
<B>else</B>
<B> if</B>(rising_edge(clk)) <B>then</B>
i(0) <= T_in <B>after</B> TPD;i(1) <= i(0) <B>after</B> TPD;
i(2) <= i(1) <B>after</B> TPD;i(3) <= i(2) <B>after</B> TPD;
<B>end</B> <B>if</B>;
<B>end</B> <B>if</B>;
<B>end</B> <B>process</B>;
<B>process</B>(i) <B>begin</B>
T_out <= ( i(0) + i(1) + i(2) + i(3) )/T4 <B>after</B> TPD;
<B>end</B> <B>process</B>;
<B>end</B> rtl;</PRE>
</TD>
<TD ROWSPAN="2"><P><P CLASS="TableLeft"><A NAME="pgfId=465002"></A>The filter computes a
moving average over four successive samples in time.</P>
<P><P CLASS="TableLeft"><A NAME="pgfId=503071"></A> </P>
<P><P CLASS="TableLeft"><A NAME="pgfId=503051"></A>Notice</P>
<P><P CLASS="TableLeft"><A NAME="pgfId=503052"></A>i(0) i(1) i(2) i(3)</P>
<P><P CLASS="TableLeft"><A NAME="pgfId=503069"></A>are each 12 bits wide.</P>
<P><P CLASS="TableLeft"><A NAME="pgfId=503072"></A> </P>
<P><P CLASS="TableLeft"><A NAME="pgfId=503070"></A>Then the sum</P>
<P><P CLASS="TableLeft"><A NAME="pgfId=503073"></A>i(0) + i(1) + i(2) +
i(3)</P>
<P><P CLASS="TableLeft"><A NAME="pgfId=503082"></A>is 14 bits wide, and
the</P>
<P><P CLASS="TableLeft"><A NAME="pgfId=503124"></A>average</P>
<P><P CLASS="TableLeft"><A NAME="pgfId=503083"></A> </P>
<P><P CLASS="TableLeft"><A NAME="pgfId=503084"></A>( i(0) + i(1) + i(2)
+ i(3) )/T4</P>
<P><P CLASS="TableLeft"><A NAME="pgfId=503089"></A> </P>
<P><P CLASS="TableLeft"><A NAME="pgfId=503090"></A>is 12 bits wide.</P>
<P><P CLASS="TableLeft"><A NAME="pgfId=503095"></A> </P>
<P><P CLASS="TableLeft"><A NAME="pgfId=503096"></A> </P>
<P><P CLASS="TableLeft"><A NAME="pgfId=503097"></A> </P>
<P><P CLASS="TableLeft"><A NAME="pgfId=503098"></A>All delays are generic
<CODE>TPD</CODE> .</P>
<P> </TD></TR>
<TR></TR>
</TABLE>
<P CLASS="Body"><A NAME="pgfId=538672"></A>The filter uses the following
formula:</P>
<P><P CLASS="EqnNmbrdAlign"><A NAME="pgfId=538673"></A><CODE>T_out <=
( i(0) + i(1) + i(2) + i(3) )/T4</CODE></P>
<P><P CLASS="Body"><A NAME="pgfId=538674"></A>Division by <CODE>T4 = "100"</CODE>
is free in hardware. If instead, we performed the divisions before the additions,
this would reduce the number of bits to be added for two of the additions
and saves us worrying about overflow. The drawback to this approach is round-off
errors. We can use the register shown in Table 10.23 to register the
inputs.</P>
<P><TABLE BORDER="1" CELLSPACING="2" CELLPADDING="2">
<TR>
<TH COLSPAN="2" ALIGN="LEFT"><P ALIGN=LEFT><P CLASS="TableTitle"><A NAME="pgfId=538682"></A>TABLE 10.23 The
input register.</TH></TR>
<TR>
<TD ROWSPAN="2"><PRE><B>library</B> IEEE;
<B>use</B> IEEE.STD_LOGIC_1164.<B>all</B>; -- type STD_LOGIC, rising_edge
<B>use</B> IEEE.NUMERIC_STD.<B>all</B> ; -- type UNSIGNED
<B>entity</B> register_in <B>is</B>
<B>generic</B> ( TPD : TIME := 1 ns);
<B>port</B> (T_in : <B>in</B> UNSIGNED(11 downto 0);
clk, rst : <B>in</B> STD_LOGIC; T_out : <B>out</B> UNSIGNED(11 <B>downto</B> 0)); <B>end</B>;
<B>architecture</B> rtl <B>of</B> register_in <B>is</B>
<B>begin</B>
<B> process</B>(clk, rst) <B>begin</B>
<B> if</B> (rst = '1') <B>then </B>T_out <= (<B>others</B> => '0') <B>after</B> TPD;
<B>else</B>
<B>if</B> (rising_edge(clk)) <B>then</B> T_out <= T_in <B>after</B> TPD; <B>end</B> <B>if</B>;
<B> end</B> <B>if</B>;
<B> end</B> <B>process</B>;
<B>end</B> rtl ;</PRE>
</TD>
<TD ROWSPAN="2"><P><P CLASS="TableLeft"><A NAME="pgfId=538707"></A>12-bit-wide register
for the temperature input</P>
<P><P CLASS="TableLeft"><A NAME="pgfId=538708"></A>signals.</P>
<P><P CLASS="TableLeft"><A NAME="pgfId=538709"></A> </P>
<P><P CLASS="TableLeft"><A NAME="pgfId=538710"></A>If the input is asynchronous
(from an A/D</P>
<P><P CLASS="TableLeft"><A NAME="pgfId=538711"></A>converter with a separate
clock, for example), we would need to worry about metastability.</P>
<P><P CLASS="TableLeft"><A NAME="pgfId=538712"></A> </P>
<P><P CLASS="TableLeft"><A NAME="pgfId=538713"></A>All delays are generic
<CODE>TPD</CODE> .</TD></TR>
<TR></TR>
</TABLE>
<P CLASS="Body"><A NAME="pgfId=464940"></A>Table 10.24 shows a first-in,
first-out stack (FIFO). This allows us to buffer the signals coming from
the sensor until the microprocessor has a chance to read them. The depth
of the FIFO will depend on the maximum amount of time that can pass without
the microcontroller being able to read from the bus. We have to determine
this with statistical simulations taking into account other traffic on the
bus.</P>
<P><TABLE BORDER="1" CELLSPACING="2" CELLPADDING="2">
<TR>
<TH COLSPAN="2" ALIGN="LEFT"><P ALIGN=LEFT><P CLASS="TableTitle"><A NAME="pgfId=464866"></A>TABLE 10.24 A
first-in, first-out stack (FIFO).</TH></TR>
<TR>
<TD ROWSPAN="2" VALIGN="TOP"><PRE><B>library</B> IEEE; <B>use</B> IEEE.NUMERIC_STD.<B>all</B> ; -- UNSIGNED type
<B>use</B> ieee.std_logic_1164.<B>all</B>; -- STD_LOGIC type, rising_edge
<B>entity</B> fifo <B>is</B>
<B> generic</B> (width : INTEGER := 12; depth : INTEGER := 16);
<B>port</B> (clk, rst, push, pop : STD_LOGIC;
Di : <B>in</B> UNSIGNED (width-1 <B>downto</B> 0);
Do : <B>out</B> UNSIGNED (width-1 <B>downto</B> 0);
empty, full : <B>out</B> STD_LOGIC);
<B>end</B> fifo;
<B>architecture</B> rtl <B>of</B> fifo <B>is</B>
<B>subtype</B> ptype <B>is</B> INTEGER <B>range</B> 0 <B>to</B> (depth-1);
<B>signal</B> diff, Ai, Ao : ptype; <B>signal</B> f, e : STD_LOGIC;
<B>type</B> a <B>is</B> <B>array</B> (ptype) <B>of</B> UNSIGNED(width-1 <B>downto</B> 0);
<B>signal</B> mem : a ;
<B>function</B> bump(<B>signal</B> ptr : INTEGER <B>range</B> 0 <B>to</B> (depth-1))
<B>return</B> INTEGER <B>is</B> <B>begin</B>
<B>if</B> (ptr = (depth-1)) <B>then</B> <B>return</B> 0;
<B>else</B> <B>return</B> (ptr + 1);
<B>end</B> <B>if</B>;
<B>end</B>;
<B>begin</B>
<B>process</B>(f,e) <B>begin</B> full <= f ; empty <= e; <B>end</B> <B>process</B>;
<B>process</B>(diff) <B>begin</B>
<B>if</B> (diff = depth -1) <B>then</B> f <= '1'; <B>else</B> f <= '0'; <B>end</B> <B>if</B>;
<B>if</B> (diff = 0) <B>then</B> e <= '1'; <B>else</B> e <= '0'; <B>end</B> <B>if</B>;
<B>end</B> <B>process</B>;
<B>process</B>(clk, Ai, Ao, Di, mem, push, pop, e, f) <B>begin</B>
<B>if</B>(rising_edge(clk)) <B>then</B>
<B>if</B>(push='0')<B>and</B>(pop='1')<B>and</B>(e = '0') <B>then</B> Do <= mem(Ao); <B>end</B> <B>if</B>;
<B>if</B>(push='1')<B>and</B>(pop='0')<B>and</B>(f = '0') <B>then</B> mem(Ai) <= Di; <B>end</B> <B>if</B>;
<B>end</B> <B>if</B> ;
<B>end</B> <B>process</B>;
<B>process</B>(rst, clk) <B>begin</B>
<B>if</B>(rst = '1') <B>then</B> Ai <= 0; Ao <= 0; diff <= 0;
<B>else</B> <B>if</B>(rising_edge(clk)) <B>then</B>
<B>if</B> (push = '1') <B>and</B> (f = '0') <B>and</B> (pop = '0') <B>then</B>
Ai <= bump(Ai); diff <= diff + 1;
<B>elsif</B> (pop = '1') <B>and</B> (e = '0') <B>and</B> (push = '0') <B>then</B>
Ao <= bump(Ao); diff <= diff - 1;
<B>end</B> <B>if</B>;
<B>end</B> <B>if</B>;
<B>end</B> <B>if</B>;
<B>end</B> <B>process</B>;
<B>end</B>;</PRE>
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?