0% found this document useful (0 votes)
64 views

Beginning FPGA Programming - Partie58

This document describes a temperature sensor design example that uses a PC to send commands to an FPGA board via UART to control a temperature sensor and retrieve temperature readings. It defines three 32-bit registers for writing commands and reading status. Code is provided for the top-level design and UART to I2C conversion module. The UART to I2C module decodes commands, controls the I2C master to interface with the temperature sensor, and shifts the sensor readings to calculate the temperature in Celsius degrees for reporting back to the PC.

Uploaded by

ali alilou
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
64 views

Beginning FPGA Programming - Partie58

This document describes a temperature sensor design example that uses a PC to send commands to an FPGA board via UART to control a temperature sensor and retrieve temperature readings. It defines three 32-bit registers for writing commands and reading status. Code is provided for the top-level design and UART to I2C conversion module. The UART to I2C module decodes commands, controls the I2C master to interface with the temperature sensor, and shifts the sensor readings to calculate the temperature in Celsius degrees for reporting back to the PC.

Uploaded by

ali alilou
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 5

Chapter 13 ■ Temperature Sensors: Is It Hot in Here, or Is It Just Me?

Figure 13-21.  Enter output clock frequency equal to 29.5 MHz

13.5 PC Control Temperature Sensor Design Example


In this example, the PC can send commands to the BeMicro MAX10 board though the UART interface. Using
the same interface, the board can report back to the PC. The UART 16550 wrapper module is used to handle
the UART interface. As mentioned earlier, it is a third-party IP from opencores.org.
The VHDL code in the control logic module is used to translate the message from the UART 16550
wrapper to another module called i2C_master. It is another third-party IP module from eewiki.net. The I2C
Master Module works as a bridge between temperature sensor and control logic.
Figure 13-22 shows a block diagram with the final design. It will have two third-party IP blocks (i2c
master and UART 16650 wrapper), one Altera IP which is the 29.5 MHz output PLL and user logic/control
logic. In the Quartus, the design hierarchy will show up as in Figure 13-23.

282
Chapter 13 ■ Temperature Sensors: Is It Hot in Here, or Is It Just Me?

Figure 13-22.  Temperature sensor design block diagram

Figure 13-23.  Temperature sensor design structure

283
Chapter 13 ■ Temperature Sensors: Is It Hot in Here, or Is It Just Me?

Figure 1223 shows that temperature_sensor_top is the top-level design. It includes two modules:
pll_29p5M and uartTOi2c. Under the uartTOi2c module, there are another two modules: i2c_master and
uart_16550_wrapper. Both of them are third-party IPs.
Based on the temperature sensor design block diagram, we will need to create two more modules. One
is temperature_sensor_top.vhd and the other one is uartTOi2c.vhd. The temperature_sensor_top provides
all of the connections from outside the FPGA and connects all the ports to the right modules. The uartTOi2c.
vhd is a little bit more complicated. Not only is it connecting the upper-level module (temperature_sensor_
top) to the i2c_master and uart_16550_wrapper, but it also has a state machine to generate data for the
UART_16550_wrapper to send to the PC and decode the command from the uart_16550_wrapper. All the
command and status definitions are in the next section, “Define What Needs to Be Done—Command and
Status Registers.”
The example code section will have both new design .vhdl files (temperature_sensor_top.vhd and
uartTOi2c.vhd) and simulation test bench files for ModelSim to do the simulation. This is the first time we
are using .vhdl files as a test bench.

13.5.1 Define What Needs to Be Done—Command and Status


Registers
We know that we are planning to use the PC to send commands to the FPGA and the UART 16650 wrapper
can decode the UART protocol to a memory map. Memory mapping means defining a memory address
location for each register, which means each register has one and only one memory address location. The
UART IP section already mentions the 6-byte command format. In this design we need to configure the
temperature sensor with the correct value through the I2C master. It is a write process to a memory address
in the temperature sensor (I2C slave). We need to read back the configuration and temperature data and
send to the PC too. This is a read process.
Let's define the three 32-bit registers so we can write to and read from the three registers.

Table 13-2.  PC UART 6-Byte Write Command Register

Address Bit 31 downto 24 Bit 23 downto 16 Bit 15 downto 8 Bit 7 downto 0


0x0000 Not use LED 7 downto 0
0x0010 Bit 31 Bit 30 Not Bit 23 Bit 22 downto 16 Second Byte to write First Byte to
I2C ena 2Bytes used I2C rw I2C 7 Bit Address "I2C Register Value" write
I2C 1= Read = 0x48 (ADT7420) "I2C Register
CMD 0 = Write Address"
(Figure 13-5a)

0x8000 Need to set to all zeroes to read back three registers

Table 13-3.  PC UART 6-Byte Read Status Registers

Address Bit 31 down to 24 Bit 23 down to 16 Bit 15 down to 8 Bit 7 downto 0


0x0000 Not use LED 7 downto 0
0x0010 Last command to I2C Master
0x0011 Temperature value in degrees Celsius  Raw temperature value read
from ADT7420

284
Chapter 13 ■ Temperature Sensors: Is It Hot in Here, or Is It Just Me?

In the command register table, we defined that the register at memory address location 0x0000 can turn
on or off the external 8 LED lights.
The register at memory address location 0x0010 (Table 13-2) is used to send a command to the I2C
Master to create I2C commands to ADT7420. The IC2 command includes read/write (bit 23), I2C slave
address (bit 22 to 16), and two bytes (bit 15 to 0). The I2C slave address for ADT7420 is 0x48, which is from
the ADT7420 datasheet. We will have examples later to show you how to use this command.
The last command at memory address location 0x8000 is used to request that all of the status registers
(Table 13-3) are read back from the BeMicro MAX 10.

13.5.2 Example Design Codes


13.5.2.1 Temperature_sensor_top.vhd Code
The code in Listing 13-1 is a top-level design file for this project. It has the system clock (50 MHz) input,
ADT7420 IC interfaces (which include I2C SCL and SDA wire), USER_LED, which is included for fun, and
UART TX and RX pins. The purpose of this module is to connect all the external wires to the correct modules
and generate the correct clock (29.5 MHz) for the uartTOi2c module. Please read the comments to get
a more detailed feel of the design. We will simulate the design later, which will give you some hands-on
experience with how it works.

Listing 13-1.  Temperature Sensor Top-Level Design vhdl File


library ieee;
use ieee.std_logic_1164.all;

entity temperature_sensor_top is
port(
-- Clock ins, SYS_CLK = 50MHz
SYS_CLK : in std_logic;

-- Temperature sensor, I2C interface (ADT7420)


ADT7420_CT : in std_logic; -- NOT USE
ADT7420_INT : in std_logic; -- NOT USE
ADT7420_SCL : inout std_logic;
ADT7420_SDA : inout std_logic;

-- LED outs
USER_LED : out std_logic_vector(8 downto 1);

GPIO_J3_39 : out std_logic; -- UART TX


GPIO_J3_40 : in std_logic -- UART RX
);

end entity temperature_sensor_top;

architecture arch of temperature_sensor_top is

signal locked, clk_uart_29MHz_i, uart_rst_i : std_logic:= '0';


signal delay_8: std_logic_vector(7 downto 0);

begin

285
Chapter 13 ■ Temperature Sensors: Is It Hot in Here, or Is It Just Me?

clk : entity work.pll_29p5M


port map
(
inclk0 => SYS_CLK, -- 50MHz clock input
c0 => clk_uart_29MHz_i,-- 29.5MHz clock output
locked => locked -- Lock condition, 1 = Locked
);

dealy_p: process(SYS_CLK)
begin
if(rising_edge(SYS_CLK) )THEN
delay_8 <= delay_8(6 downto 0)&locked; -- create active LOW reset
END IF;
END PROCESS;

uart_rst_i <= delay_8(7);


uartTOi2c_pm : entity work.uartTOi2c
port map(
clk_uart_29MHz_i => clk_uart_29MHz_i,
uart_rst_i => uart_rst_i,
uart_leds_o => USER_LED,
clk_uart_monitor_o => open,
uart_dout_o => GPIO_J3_39, -- yellow color wire
uart_din_i => GPIO_J3_40, -- orange color wire
i2c_scl => ADT7420_SCL,
i2c_dat => ADT7420_SDA);

end architecture arch;

13.5.2.2 uartTOi2c.vhd Code
This is the major design in this example (Listing 13-2). This is because it does all of the decoding of
commands from the UART and generates status updates to the UART. It also translates the commands from
the PC and sends the correct operation sequence for the i2C Master module. There are three processes in
this module: register_map, i2c_data_p, and register_update.
The register_map process works as a command decoder. It decodes the s_uart_rx_add when s_uart_
rx_rdy is high and copies the 32-bit s_uart_rx_data to the correct registers (e.g., 0x0000 is mapped to
r_leds).
The second process is i2c_data_p. It copies data from the I2C Master byte read output to reg02 in the
lower 16 bits (15 down to 0). It is a special shift register, which is similar to the 8-bit shift register which shifts
1 bit at a time in Chapter 10. This special shift register shifts 8 bits at a time such that two 8 bytes (16 bits)
from the i2c_Master can be stored in one 32-bit register. This process will translate the 13-bit ADC data from
the temperature sensor to degrees Celsius. This simple bit shift to the left for 9 bits happens every clock
cycles. Figure 13-14 shows that the 25̊C digital output bit (15:3) is "0000110010000." The 2-byte (16 bits)
output bits should look like "0000110010000000." If we shift the 2-byte version 9 bits to left, then we will get
a 4-byte "0000000000011001 0000000000000000." The higher 2-byte binary value is "0000000000011001,"
which equals 25 in unsigned value. This shows that we can use the shift register to do the math.
The last process is register_update. It is actually a small state machine. It is used to generate a sequence
of register reads by the command address in 0x8000 with the value all zero and to send the Table 13-3 values
to the uart_16550_wrapper.

286

You might also like