One of things which helps us accelerate our development times is to leverage model based development. This enables us to work at a higher level of abstraction and then generate the RTL from the model. If changes are required the model is updated and the RTL regenerated, the model becomes the source of truth for that element or complete design depending upon how we have architected our system.

One of the things I have on my list of things to do, is to create a module which can determine a temperature from an ADC input. This will use a Negative Temperature Coefficient thermistor, arranged in a potential divider.

The conversion from this simple resistor divider circuit is, complicated. To work out the temperature the thermistor is detecting we need to know its resistance. As we are using a potential divider we know the voltage at the mid point between the resistor and the thermistor, not the resistance.

What we need to do is convert the ADC quantised voltage into a resistance, to do so we can use the equation below.

Knowing the resistance of the thermistor we are then able to determine the temperature. To do this we need to know a couple of parameters such as the nominal resistance (Ro) of the thermistor, and its beta coefficient. Knowing these we can use the equation below to convert the measured resistance to temperature.

Normally if I was to implement this algorithm one of the first things I would do is to plot the transfer function and determine the polynomial approximation which provides sufficient accuracy for a given ADC input.

However, for this blog I wanted to use the full capabilities presented by Simulink and HDL coder to implement the algorithm entirely. This provides a more accurate result, but will come at the cost of larger logic foot print. Like everything in life engineering is the art of compromise, do we want less accurate lower logic foot print or more accurate and larger logic foot print.

To get started with this I started a new Simulink project and created a subsystem which contained two additional subsystems. The first of these subsystems performs the conversion from the ADC voltage to the thermistor resistance. The block has been designed to work with a 12 bit ADC such as the XADC and its AXI Streaming output will be a perfect input.

This block contains two real divider blocks which implement the first conversion from ADC value to thermistor resistance. The first divider performs the division of the ADC resolution in this case 4096 by the measured ADC Value.

After the first division, the result, has one subtracted from it, before being used in the second divider. The result of this division gives the resistance value of the thermistor.

The system uses fixed point numbers throughout this block and the register stages (delays) are inserted between the divider, subtractor and divider. Of course, the RTL generation will also pipeline these functions as well but, it is better to registers the inputs and outputs directly.

It is the second block which takes the thermistor resistance and calculates the output temperature.

The first thing we do is register the input, and then perform the calculation of the 1/Rnom, to do this I use a multiplier and the reciprocal of the thermistors nominal resistance. Next up is to convert from fixed point to floating point and implement the logarithm, ln(Rntc/Rnom). The result of this is then multiplied by the reciprocal of the Beta (3950) and the reciprocal of T0 (298 Kelvin). The final step is to take the reciprocal of the result and then convert back to a fixed point number.

To test this I set several of the nets to be logged by the internal logic analyser in Simulink and ran the simulation with a range of input values to determine the output.

This shows the expected results one would expect e.g. for a input of 2048 from the ADC we should see a room temperature output in Kelvin which is 298 K.

The next step is to configure the code generation, I wanted the design to be able to connect to the XADC AXI stream output, I also wanted the result to be available in a AXI Memory map such that I could read the calculated result using the Zynq processor on a MicroZed.

Using the workflow advisor I configured the target device and tools chain settings.

I also used the workflow controller to define the interfaces I wanted.

Running the rest of the checks and generating the code gives me an IP core I can include in my Vivado project.

Within Vivado I created a project for the MicroZed and connected it to the IO Carrier card. The project included the XADC and the processing system. The final project looks as below, you can clearly see the Steinhart Hart IP core added which was created in Simulink.

The XADC is configured for only one output, and averaging of 256 samples. This is because the output will be a little noisy from the bread board implementation.

The utilisation of logic for the IP blocked created can be seen below.

A bread board was constructed with the Resistor, Thermistor etc connected to the XADC input.

Running a simple software program allows us to then read the temperature sensor, which is showing about the correct temperature. This correlates with the behaviour outlined in the Simulink model. The first value is the unscaled value supplied by the Steinhart Hart block the second is the scaled temperature in Kelvin.

Capturing the input from the XADC using the ILA we can grab the XADC value.

This can be entered into the model to ensure the outputs correlate also

We now have a simple Steinhart Hart thermistor conversion block I will upload the IP core and Simulink design to my __github__.

Workshops and Webinars

If you enjoyed the blog why not take a look at the free webinars, workshops and training courses we have created over the years. Highlights include

__Professional PYNQ__Learn how to use PYNQ in your developments__Introduction to Vivado__learn how to use AMD Vivado__Ultra96, MiniZed & ZU1__three day course looking at HW, SW and PetaLinux__Arty Z7-20 Class__looking at HW, SW and PetaLinux__Mastering MicroBlaze__learn how to create MicroBlaze solutions__HLS Hero Workshop__learn how to create High Level Synthesis based solutions__Perfecting Petalinux__learn how to create and work with PetaLinux OS

Boards

Get an Adiuvo development board

__Adiuvo Spartan 7 / RPi 2040__Embedded System Development Board

Embedded System Book

Do you want to know more about designing embedded systems from scratch? Check out our book on creating embedded systems. This book will walk you through all the stages of requirements, architecture, component selection, schematics, layout, and FPGA / software design. We designed and manufactured the board at the heart of the book! The schematics and layout are available in Altium __here__ Learn more about the board (see previous blogs on Bring up, DDR validation, USB, Sensors) and view the schematics here.

## Comments