类型转换 VHDL
type conversion VHDL
我正在尝试为 MS5541C pressure/temperature 传感器编写驱动程序,但我似乎做不到。
数据表提供了一些计算,如果我将它们放入 excel 似乎工作得很好。
但是,当我尝试为其编写 VHDL 代码并将其显示在 7 段显示器上时,它不起作用。
提供的计算是:
UT1 = 8 * C5 + 10000
其中 C5 是从 PROM 读取的校准数据
dT = D2 - UT1
其中 D2 是从 DAC 读取的温度
TEMP = 200 + dT*(C6+100)/2^11
其中 temp 是实际温度,单位为 0.1 摄氏度,C6 也是校准温度。
在我的例子中,C5 = 2223(dec),D2 = 28144(dec)和 C6 = 53。
根据这些数字,我得到 22.7 摄氏度的温度。
我在VHDL中使用的代码(MCVE)是:
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;
ENTITY MS5541C_CONVERTER IS
PORT(
CLK : IN STD_LOGIC;
RST : IN STD_LOGIC;
T_OUT : OUT STD_LOGIC_VECTOR(15 DOWNTO 0)
);
END ENTITY;
ARCHITECTURE MS5541C_CONVERTER OF MS5541C_CONVERTER IS
Constant C5 : STD_LOGIC_VECTOR(11 DOWNTO 0) := "100010101111"; -- Reference temperature
Constant C6 : STD_LOGIC_VECTOR( 6 DOWNTO 0) := "0110101"; -- Temp coefficient of the temperature
Constant D2 : STD_LOGIC_VECTOR(15 DOWNTO 0) := x"6df0"; -- temperature
BEGIN
PROCESS (CLK,RST)
VARIABLE UT1 : SIGNED(33 DOWNTO 0);
VARIABLE dT : SIGNED(33 DOWNTO 0);
VARIABLE TEMPE : SIGNED(33 DOWNTO 0);
VARIABLE C5_s : SIGNED(33 DOWNTO 0);
VARIABLE C6_s : SIGNED(33 DOWNTO 0);
BEGIN
C5_s := RESIZE(signed(C5),33);
C6_s := RESIZE(signed(C6),33);
IF RST = '1' THEN
ELSIF rising_edge(CLK) THEN
UT1 := 8 * C5_s + 10000;
dT := RESIZE(signed(D2),33) - UT1;
TEMPE := 200 + dT*(C6_s + 100)/ 2048;
T_OUT <= STD_LOGIC_VECTOR(RESIZE(TEMPE,16));
END If;
END PROCESS;
END ARCHITECTURE;
结果是 2674(dec) 或 a72(hex)(实际数字可能与 excel 略有不同,因为这是两个测量值,但这并不接近)
我重读了几次计算,甚至尝试了不同的方法,但结果总是不正确。我假设它与类型的转换有关,但我不知道是什么。
P.s。
对于想要阅读数据表的人:
http://media.digikey.com/pdf/Data%20Sheets/Measurement%20Specialties%20PDFs/MS5541-CM.pdf
至少有一个问题是,当您对 C5 进行有符号转换时,您得到的是 -4984,而不是 2223。然后您将这个负数扩展到 33 位宽。
如果这是唯一的问题,您的最终结果将类似于 4534,因此可能还有另一个问题,但是您转换为有符号的其他常量都没有前导 '1'
。
C5、C6、D2真的是有符号数吗?它们实际上是从舞会上读取的 12/7/16 位宽吗?
我希望你的时钟很慢或者这不是用于综合,尽管我怀疑你打算在真实系统中使用它。这种使用变量而不是信号的数学运算将有非常长的路径在一个时钟周期内完成。 33 位操作数(宽边)加剧了这个问题。
说到操作数长度,如果您计算出每个计算和操作数将保持的最大值并使用适当的长度,您的数学会更有效率。优化器可能会解决其中的一些问题,但它们并不总是完美的。
我正在尝试为 MS5541C pressure/temperature 传感器编写驱动程序,但我似乎做不到。 数据表提供了一些计算,如果我将它们放入 excel 似乎工作得很好。 但是,当我尝试为其编写 VHDL 代码并将其显示在 7 段显示器上时,它不起作用。
提供的计算是:
UT1 = 8 * C5 + 10000
其中 C5 是从 PROM 读取的校准数据
dT = D2 - UT1
其中 D2 是从 DAC 读取的温度
TEMP = 200 + dT*(C6+100)/2^11
其中 temp 是实际温度,单位为 0.1 摄氏度,C6 也是校准温度。
在我的例子中,C5 = 2223(dec),D2 = 28144(dec)和 C6 = 53。 根据这些数字,我得到 22.7 摄氏度的温度。
我在VHDL中使用的代码(MCVE)是:
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;
ENTITY MS5541C_CONVERTER IS
PORT(
CLK : IN STD_LOGIC;
RST : IN STD_LOGIC;
T_OUT : OUT STD_LOGIC_VECTOR(15 DOWNTO 0)
);
END ENTITY;
ARCHITECTURE MS5541C_CONVERTER OF MS5541C_CONVERTER IS
Constant C5 : STD_LOGIC_VECTOR(11 DOWNTO 0) := "100010101111"; -- Reference temperature
Constant C6 : STD_LOGIC_VECTOR( 6 DOWNTO 0) := "0110101"; -- Temp coefficient of the temperature
Constant D2 : STD_LOGIC_VECTOR(15 DOWNTO 0) := x"6df0"; -- temperature
BEGIN
PROCESS (CLK,RST)
VARIABLE UT1 : SIGNED(33 DOWNTO 0);
VARIABLE dT : SIGNED(33 DOWNTO 0);
VARIABLE TEMPE : SIGNED(33 DOWNTO 0);
VARIABLE C5_s : SIGNED(33 DOWNTO 0);
VARIABLE C6_s : SIGNED(33 DOWNTO 0);
BEGIN
C5_s := RESIZE(signed(C5),33);
C6_s := RESIZE(signed(C6),33);
IF RST = '1' THEN
ELSIF rising_edge(CLK) THEN
UT1 := 8 * C5_s + 10000;
dT := RESIZE(signed(D2),33) - UT1;
TEMPE := 200 + dT*(C6_s + 100)/ 2048;
T_OUT <= STD_LOGIC_VECTOR(RESIZE(TEMPE,16));
END If;
END PROCESS;
END ARCHITECTURE;
结果是 2674(dec) 或 a72(hex)(实际数字可能与 excel 略有不同,因为这是两个测量值,但这并不接近)
我重读了几次计算,甚至尝试了不同的方法,但结果总是不正确。我假设它与类型的转换有关,但我不知道是什么。
P.s。 对于想要阅读数据表的人:
http://media.digikey.com/pdf/Data%20Sheets/Measurement%20Specialties%20PDFs/MS5541-CM.pdf
至少有一个问题是,当您对 C5 进行有符号转换时,您得到的是 -4984,而不是 2223。然后您将这个负数扩展到 33 位宽。
如果这是唯一的问题,您的最终结果将类似于 4534,因此可能还有另一个问题,但是您转换为有符号的其他常量都没有前导 '1'
。
C5、C6、D2真的是有符号数吗?它们实际上是从舞会上读取的 12/7/16 位宽吗?
我希望你的时钟很慢或者这不是用于综合,尽管我怀疑你打算在真实系统中使用它。这种使用变量而不是信号的数学运算将有非常长的路径在一个时钟周期内完成。 33 位操作数(宽边)加剧了这个问题。
说到操作数长度,如果您计算出每个计算和操作数将保持的最大值并使用适当的长度,您的数学会更有效率。优化器可能会解决其中的一些问题,但它们并不总是完美的。