When I assess the reasonableness of the user interface of specialized microchips from STMicroelectronics, I am sometimes surprised by the fact that they are able to work at all. But they work the same. And they do not just work, but have a bunch of chips and an extremely low price. As a result, you have to choose them again and again ...The next day promised to be as simple and enjoyable
as possible when once again you save the “burning” project . According to the plan, it was necessary to revive the integrated combined temperature and humidity sensor until the evening. The tiny size of the board, the small number of legs and the absence of discrete components of the “strapping” allowed us to hope that you are dealing with the latest development, and modern sensors, despite their small size, are distinguished by intelligence and ingenuity. They give out the finished result without any extra questions. Often they do not just perform measurements, but produce very complex signal processing, have internal buffers for storing data, interrupt outputs
in order to wake up the microcontroller and many other pleasant features. All this greatly simplifies the task of writing code and reduces the resource requirements of the controlling microcontroller ... It is easy and pleasant to communicate with them. True, sometimes you have to tinker with a lot of settings. However, today it did not threaten me, because before me is just a banal capacitive moisture meter with temperature measurement function.
“A couple of hours for screwing the interface, a couple more for the configuration of registers and half a day ahead are free,” I thought. It will be possible to have lunch in the forest, if not on shish kebabs, then at least for a modest picnic.
The only thing that gave me a vague feeling of alarm was the manufacturer: STMicroelectronics. But discarding the memories of dances with a tambourine around their microcircuits for an electric meter, a PLC modem, an advanced inertial sensor ... I set to work.
')
Tying acquaintance
A quick acquaintance with the datasheet and the circuit showed that this time neither the circuit designer nor the tracer “nakosyachili” (of course, the blocking capacitor next to the case would have to be supplied and the power dissipated slightly differently, but this will affect the accuracy of measurements, and not performance). The exchange interface between the microcontroller and the I2C sensor was suspiciously similar to the standard one.
I will not describe in detail the standard I2C, decipher only the basic terms from the datasheet, which will be needed a little later.
Agree on terms. For mutual understanding
ST - start condition;
SR is the reset operation of the start condition, it serves to solve the read conflict from the register. We cannot perform a clean read operation — we first need to pass the register number that we read to the instrument;
SAD is the address of the slave device - our sensor (the low bit in it occupies the sign of the operation - ”+ W: or 0 for writing,“ + R ”or 1 for reading. Thus,“ SAD + W ”= 0xBE“ SAD + R ”= 0xBF;
SAC is a confirmation bit “sent” by the slave, in our case the sensor;
MAK - a confirmation bit from the microcontroller, which it sets in response to the fact that NMAK reads its absence, which is characterized by the last byte;
SUB is the actual address of the register
DATA - the actual data
SP - stop condition
Verification is done by closing the SDA bus to ground
It is hard to believe that STM inventors at this time refused to innovate, but suddenly they change their policy. Well, we begin to check.
The first steps. First problems
Nothing foreshadowed the difficulties when looking at this picture. In total, the business is to count a couple of 16 bit registers!

I am finalizing my I2C exchange pattern and after an hour to attempt to write to the register, the chip briskly responds with acknowledgment bits. Well, to teach the microcontroller to read data from the registers a little more difficult. Where are the registers in which the measurement results are stored? Yes, here they are, but give solid zeros. Well, you have to read more about the configuration. Half an hour behind the monitor screen and a cup of tea show that by default the chip is in an inactive state, but you can remove it from the stupor by changing just one byte in the configuration register. At the same time, we will push a couple more so that the measurements take place cyclically, the benefit of which is to avoid the severe energy saving in this project.
CTRL_REG1=0x86;
Hooray, data appeared in 16-bit registers of temperature and humidity, but somehow they look strange. In the case of temperature and humidity, both bytes are equal to each other. This is at least suspicious. Need to understand. Hour is spent looking for errors in the exchange protocol and checking for delays. Nothing helps, you have to go back to the datasheet. Bah ... yes, I was not mistaken. Well, the developers from STM could not not prepare a gift for the programmer. There are few registers in the sensor and one byte is enough to address them in excess. When you read or write one byte everything is fine. But according to the I2C specification, you can both read and write a few bytes at a time and I actively use this feature in my program. The main thing is, in the first case, after each byte, send a confirmation bit, and in the second, check whether the sensor returned it. But STM engineers have introduced their know-how.
It turns out that after reading or writing one byte the counter is incremented by one and passed to the next byte, you need to set the most significant bit to 1 in the register address byte (SUB)! Otherwise, you will work until the blue side to interact with the same register. Brilliant, and most importantly, how incomprehensible. Why is this?
Add a crutch to the standard protocol.
if (ByteCount>1) SUB[1]|=0x80;
No defeats no wins
The read data starts to delight with its diversity, only in what parrots do they measure them? It looks very strange read values. It looks like until you read this datasheet from cover to cover, you won't cook porridge with this sensor.
This is an ambush! It turns out that in order to get a tangible result in degrees and percents, you must still do the calculations. Retrieve calibration data from specific registers and use the piecewise linear approximation to calculate the values. Not that it is difficult to write a piece of code in C, but it is impossible to avoid a careful study of the datasheet. The amount of code increases, and as a result, I have drawn another problem - the memory of the microcontroller is running out. The circuit designer initially laid a stone with only sixteen kilobytes of FLASH, and polling the humidity sensor only a small fraction of the tasks assigned to it. Since the microcontroller is 32 bit, we have a total of 4K words for code and constants. Even with the fact that I do not use the heavy HALovskie firewood of this monstrously small. I was promised to buy a new version of microcontrollers with memory twice as large. How are you? I call the project manager. New stones have already arrived, but they are not soldered to the boards. It turns out they are waiting for me when I report that no errors were found in the board. Well, I report and get an answer - by the end of the week, maybe you will make a stone flower for you. Of course, the board is not complicated, you could solder it yourself, although the chips are very small and require painstaking soldering with a hair dryer. However, there are people who are specially trained in the project, why should they be left without work, especially since my schedule is very tight and I don’t have anything to do with the time spent.
In the current situation without debugging, do not move forward. We have to comment out a part of the code that has already been written to make room for calculations.
The problem of linear approximation does not look too complicated,
but knowing the magicians of STM is better to look for a ready-made solution. 10 minutes of surfing leads me to
Application with a description of the calculation method and even pieces of C code .
Why just do something that can be difficult?
I copy into my program. Here it is lunch time. With anguish I look at the strip of woods on the horizon, it seems not so much that kebabs, but even a picnic in nature is canceled today. Lunch is a little uplifting and forces emerge for a detailed study of the application. I understand the registers with calibration values. At first, their organization puzzles me, then it makes me laugh, almost hysterical. Even for STM products, brute force is felt. At this point, I want to stop in more detail.
We look at the picture and try to evaluate the flight of thought. In the first column of the table is the address in HEX format, in the second name, in the third data type, then the bit-by-bit description.
With the values ​​marked as s16, everything is clear - 16-bit signed, presented in a standard additional format.
With those that at addresses 30 and 31 all the fun. They are eight-bit. But in order to use them in the calculations it is necessary to divide their value into two. The low bit is insignificant. Was it really difficult to simply put the meaningful 7 bits into the register, and leave the high one at zero?
But it was still flowers. The berries went with 8-bit values ​​at addresses 32 and 33. It turns out that they lack two more bits - the ninth and tenth. For some reason they are stored in the register with the address 35. It contains 2 high-order bits from one register with the number 32 and two bits from the other with the number 33. Why? Isn't it simpler to allocate two bytes for each of them and calmly write down the values, because the register with address 35 is still empty!
But that's not all. As a result of the manipulations, we get 10 bit registers, but it turns out that we need only the older seven bits for computation. Therefore, the three low-order bits must be folded, the
value must be divided by 8, and only then substituted into the formulas.
In other words, we only need seven bits for calculations. Why all these manipulations were asked, when they would easily fit into an eight-bit register!
Really some kind of brain rupture. Information in registers with addresses 30-31 could look like this:
To extract information would not have to do unimaginable somersaults, but in the memory of registers also an extra bit remains.
Journey to Mercury

All right, I check the program given in aplikeyshine. It seems everything is very similar to the description. However, the penultimate line pleases:
If the relative humidity is more than 1000 percent, we take it for 1000 percent.
The class.
As a result, it does not pass even two hours, as I finally check the measurement result in practice. He scares me. The sensor shows that the weather conditions in my room are very close to the depression at the bottom of the imaginary Mercury ocean. The temperature is above 500 degrees Celsius, and the humidity is around 1000 percent. Looks like I was completely working and it's time to turn on the air conditioning.
When it turns out that the sensor readings and it affects weakly, I begin to check the code. I could not refrain from refining coarsely written template from ST, suddenly nakosyachil? A half-hour check does not give results. Again I go deep into datasheets in order to understand where this “10” odd multipliers come from in calculations using the linear interpolation method. Half an hour of careful reading gave the result - it turns out it was a move aimed at improving the accuracy of integer division. True, at the output we got the results not in percents, but in ppm for humidity and in Celsius degrees multiplied by 10 for temperature.
I try to throw them out of the code and suddenly move back to the middle lane - 29 degrees and 58 percent humidity. I press the sensor with my finger and very quickly the temperature reading rises to 34. Hurray, finally you can wrap up.
But it is already getting dark outside the window and the poor fellows are returning from work on Moscow electric trains on the sidewalks. Well, I will go at least to the park, take a walk, prepare mentally for tomorrow morning's conversation with the general from Kazan. Their firm decided to try their luck in import substitution for a couple with Bashneft, you need to think what they hope to get from me and how I can actually help them.
Dry residue
In the end, we have - ST did everything so that our brother, the developer, even for writing a simple driver, read the manual from cover to cover and with the appliqué also suffered:
- When writing or reading a few bytes, you must change the address of the register;
- The actual values ​​of the measured values ​​must be calculated using calibration values;
- The calibration values ​​themselves are located in a very strange way in memory, and they need to be collected from there by pieces conducting circus manipulations with bits;
- The program text from the application file contains errors;
- Gauge and reserve registers are open for free writing. Accidental recording of new values ​​in them will lead to a distortion of the results during the calculation;
- Relative humidity can easily go off scale for 100 percent and it doesn’t bother the manufacturer at all;
The above problems I encountered in the process of writing the simplest driver took away more than half of the working day from me, and a beginner could be provided with a solution for several days.
What can we say about creating a driver for some kind of PLC modem, when circuit faults, hardware problems, nuances of exchange protocols, quality of communication lines are added to the oddities of the chip and inaccuracies of the description. When the microcontroller has to read and encode / decode data on the fly and it is necessary to use the mechanism of interrupts and direct access to the memory at full speed Moreover, the code should be executed in the “shadow mode” and have a minimal impact on the course of the main program.
I'm not talking about the fact that some of the not very pleasant nuances of manufacturers sometimes deliberately silent, or provide not very reliable information.
In such conditions, without experience, good knowledge of circuit design and physics of the device, the developer is very difficult.
It's time to report on the results
Well, finally, I will try to make life easier for those who decide to use this sensor in their developments. I publish below the code of the corresponding program modules. Immediately, I’ll make a reservation that it does not include low-level I2C data exchange functions, since it strongly depends on the specific implementation - the microcontroller used for polling, the exchange bus and even the numbers of the connected ports.
Data exchange with the sensor is carried out via the I2C interface. Two functions supporting the standard protocol are used, you will have to write them yourself or search them in standard libraries.
One for recording data according to the protocol shown in the figure below.
int WRsubAddr(unsigned char SAD,unsigned char SUB, unsigned char *data,unsigned int ByteCount);
The second to read data
int RDsubAddr(unsigned char SAD,unsigned char SUB, unsigned char *data,unsigned int ByteCount);
data -
data buffer
ByteCount - number of bytes read or written.
The program code is very simple and richly supplied with comments. When the sensor driver is initialized, constants for calculations are read from it and placed in a separate structure. Measurements read and converted to a readable form are placed in it.
This program code has been modified after a hectic two-day discussion process. I tried to improve the accuracy of conversions by using the lower bits of the registers H0_rH_x2, H1_rH_x2, H0_T0_OUT, H1_T0_OUT. In the case of calculating the temperature, this did not greatly affect the result; in the case of humidity, it led to inadequate results. Significantly bring the readings to real ones by applying the type float for calculations. For 32-bit microcontrollers, the calculation of floating-point numbers is not a very resource-intensive task, and a high calculation speed is not required when working with this sensor. I offer our readers the program in this version.
I express my gratitude to all users who took part in the discussion, especially I would like to note
mdn-tech ,
olartamonov and
lorc . In addition, I express my gratitude to the Habra team for not including the possibility of editing articles after writing them among the innovations. This allows you to change the content of the discussion in the comments. I try to use this opportunity - I correct errors and sometimes add interesting information. After several iterations, the article becomes more interesting, more fully reflects the topic and most importantly does not contain errors.
Header File Code
#ifndef HTS221_H #define HTS221_H #include "i2c.h"
SI program code
#include "HTS221.h" int WRHTS221reg(unsigned char addrREG, unsigned char *data,unsigned char ByteCount) {
Useful materials
The link to the sensor page at the manufacturerFinal survey
The manufacturer stated that the sensor contains a digital signal processor for processing the results. Then why it was impossible to implement the simplest calculations to provide data in a user-friendly form. Well, well, he is too busy, but why not at least the calibration registers are not located in a normal way? Why does the simplest demo code contain errors? And still a lot of why.