{"id":4309,"date":"2019-08-07T20:00:09","date_gmt":"2019-08-07T18:00:09","guid":{"rendered":"https:\/\/msalamon.pl\/?p=4309"},"modified":"2025-12-27T19:25:56","modified_gmt":"2025-12-27T18:25:56","slug":"are-an-i2c-converter-and-an-lcd-a-good-match","status":"publish","type":"post","link":"https:\/\/msalamon.pl\/en\/are-an-i2c-converter-and-an-lcd-a-good-match\/","title":{"rendered":"Are an I2C Converter and an LCD a Good Match?"},"content":{"rendered":"\n<p>I often come across the statement that it\u2019s better to connect an LCD display via an I\u00b2C expander because it \u201ceats\u201d only two microcontroller pins instead of a minimum of 6. It\u2019s true that it saves pins, but as we all know\u2014nothing comes for free. Today I\u2019ll check for you what you need to account for when you connect an LCD over I\u00b2C using popular modules based on PCF8574 chips.<\/p>\n\n\n\n<!--more-->\n\n\n\n<p>Previous posts about the 16\u00d72 LCD can be found here:<\/p>\n\n\n\n<p><a href=\"http:\/\/msalamon.pl\/wyswietlacz-lcd-16x2-na-stm32-hal-cz-1\/\">16\u00d72 LCD on STM32 + HAL part 1<\/a><\/p>\n\n\n\n<p><a href=\"http:\/\/msalamon.pl\/wyswietlacz-lcd-16x2-na-stm32-hal-cz-2\/\">16\u00d72 LCD on STM32 + HAL part 2<\/a><\/p>\n\n\n\n<h1 class=\"wp-block-heading\">LCD to I\u00b2C converter<\/h1>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"https:\/\/sklep.msalamon.pl\/produkt\/konwerter-i2c-dla-wyswietlacza-lcd-hd44780\/?utm_source=blog&amp;utm_medium=banner&amp;utm_campaign=lcdi2c&amp;utm_content=converter\"><img loading=\"lazy\" decoding=\"async\" width=\"1200\" height=\"400\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/08\/LCD_I2C_baner.jpg\" alt=\"\" class=\"wp-image-1103\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/08\/LCD_I2C_baner.jpg 1200w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/08\/LCD_I2C_baner-300x100.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/08\/LCD_I2C_baner-1024x341.jpg 1024w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/08\/LCD_I2C_baner-768x256.jpg 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/08\/LCD_I2C_baner-24x8.jpg 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/08\/LCD_I2C_baner-36x12.jpg 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/08\/LCD_I2C_baner-160x53.jpg 160w\" sizes=\"auto, (max-width: 1200px) 100vw, 1200px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<p>The LCD to I2C converter is very simple in construction. It includes the aforementioned <a href=\"https:\/\/sklep.msalamon.pl\/produkt\/konwerter-i2c-dla-wyswietlacza-lcd-hd44780\/?utm_source=blog&amp;utm_medium=article&amp;utm_campaign=lcdi2c&amp;utm_content=Text\">PCF8574 expander<\/a>, a few resistors, a contrast adjustment potentiometer, and a transistor. Let\u2019s take a look at the <a href=\"http:\/\/msalamon.pl\/download\/1029\/\">datasheet of the IC<\/a>.&nbsp;<\/p>\n\n\n\n<p>The first thing that stands out is that the available ports are bidirectional, meaning we can both write to outputs and read from them. That\u2019s good, because it gives us the option to work with the display\u2019s busy flag.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Powering the PCF8574<\/h3>\n\n\n\n<p>The <a href=\"https:\/\/sklep.msalamon.pl\/produkt\/konwerter-i2c-dla-wyswietlacza-lcd-hd44780\/?utm_source=blog&amp;utm_medium=article&amp;utm_campaign=lcdi2c&amp;utm_content=Text\">PCF8574<\/a> can be powered from as low as 2.5 V, which is also good news, but unfortunately the display needs 5 V for the contrast divider and for the backlight. While a dimmer backlight might be tolerable, with 3.3 V applied to the contrast there\u2019s practically no chance for the display to work correctly. The only rescue would be an LCD with a fixed contrast. They are less popular and harder to get. So it turns out the entire converter circuit should be powered from 5 V. OK, but what about the communication pins? After all, the STM32 runs at 3.3 V! Nothing to worry about, because almost all I\/O pins of the STM are <em>5V-tolerant<\/em>. All right, but in the other direction? Will the expander recognize a high level on the I\u00b2C lines? The high level on the <a href=\"https:\/\/sklep.msalamon.pl\/produkt\/konwerter-i2c-dla-wyswietlacza-lcd-hd44780\/?utm_source=blog&amp;utm_medium=article&amp;utm_campaign=lcdi2c&amp;utm_content=Text\">PCF8574<\/a> is interpreted from 0.7 * VDD, which at 5 V supply is 3.5 V. Ouch\u20140.2 V above what the STM32 can provide\u2026&nbsp;<\/p>\n\n\n\n<p>There are two solutions (actually 3 on deeper thought). First, you can use a level shifter and be sure the IC will always read what was sent to it. A good solution, but it introduces more components.<\/p>\n\n\n\n<p>The second solution is simply to try with what you have \ud83d\ude42 From my experience, chips interpret a high level at a slightly lower voltage than the datasheet states. Just a safety margin. Unfortunately, this can vary across IC batches, and for example, you can get a series that strictly adheres to the documented parameters. I don\u2019t recommend this when building a final device, e.g. for sale. It\u2019s better then to stick to what the manufacturer states on paper. It will help you avoid surprises that are your fault. It\u2019s different for a desk test or hobby\/amateur devices \ud83d\ude42 You can turn a blind eye once, and that\u2019s what I\u2019m doing now.<\/p>\n\n\n\n<p>And that\u2019s 100% true for push-pull outputs. Now recall what the outputs for the I\u00b2C interface look like. We\u2019re dealing with open-drain outputs. In short\u2014we have only one active state\u2014logical zero. The one is set by the pull-up resistor on the SDA and SCL lines. As you can see in the converter schematic, these resistors are connected to VDD, i.e. 5 V. Hence the high level on the communication lines will be at that level, regardless of the operating voltages of the communicating devices. It\u2019s important that the outputs of these devices tolerate such a high voltage for a logical one. Both the <a href=\"https:\/\/sklep.msalamon.pl\/produkt\/konwerter-i2c-dla-wyswietlacza-lcd-hd44780\/?utm_source=blog&amp;utm_medium=article&amp;utm_campaign=lcdi2c&amp;utm_content=Text\">PCF8574<\/a> and the STM32 tolerate 5 V on their inputs. It will work \ud83d\ude42<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">I\u00b2C communication speed<\/h3>\n\n\n\n<p>There\u2019s one parameter that doesn\u2019t put a smile on my face. It\u2019s the maximum I\u00b2C clock frequency. Unfortunately, the chip only supports Standard Mode, i.e. 100 kHz. You can try to overclock the bus, but there\u2019s no guarantee it will work correctly. This will have a huge impact on the results of my observations.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Converter schematic<\/h3>\n\n\n\n<p>I found a schematic of such a Chinese converter on the Internet.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hd44780_i2c_converter-schematic.gif\"><img loading=\"lazy\" decoding=\"async\" width=\"300\" height=\"146\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hd44780_i2c_converter-schematic-300x146.gif\" alt=\"\" class=\"wp-image-1035\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hd44780_i2c_converter-schematic-300x146.gif 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hd44780_i2c_converter-schematic-1024x497.gif 1024w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hd44780_i2c_converter-schematic-768x373.gif 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hd44780_i2c_converter-schematic-24x12.gif 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hd44780_i2c_converter-schematic-36x17.gif 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hd44780_i2c_converter-schematic-160x78.gif 160w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p>What interesting things can we read from it? The R\/W pin control is available. So you can read the busy flag, which significantly speeds up communication in classic control.<\/p>\n\n\n\n<p>Another curiosity is the backlight connected through a transistor and controlled by the expander\u2019s P3 port. So you can control the backlight, but I wouldn\u2019t count on PWM. Just simple on-off.<\/p>\n\n\n\n<p>There are address jumpers, so if you insist you can connect 8 displays to a single I\u00b2C bus.<\/p>\n\n\n\n<p>The expander is connected in the LCD\u2019s 4-bit mode. That\u2019s not a problem because I\u2019ve already shown that 8-bit operation makes no sense.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">STM32CubeMX schematic and configuration<\/h2>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"https:\/\/sklep.msalamon.pl\/kategoria-produktu\/dev-boardy\/stm32-nucleo\/?utm_source=blog&amp;utm_medium=banner&amp;utm_campaign=lcdi2c&amp;utm_content=nucleo\"><img loading=\"lazy\" decoding=\"async\" width=\"1200\" height=\"400\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2020\/07\/Nucleo-64-baner.jpg\" alt=\"\" class=\"wp-image-1593\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2020\/07\/Nucleo-64-baner.jpg 1200w, https:\/\/msalamon.pl\/wp-content\/uploads\/2020\/07\/Nucleo-64-baner-300x100.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2020\/07\/Nucleo-64-baner-1024x341.jpg 1024w, https:\/\/msalamon.pl\/wp-content\/uploads\/2020\/07\/Nucleo-64-baner-768x256.jpg 768w\" sizes=\"auto, (max-width: 1200px) 100vw, 1200px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<p>To compare I\u00b2C communication with classic display control, I\u2019ll need conditions as similar as possible. That\u2019s why I\u2019ll use the <a href=\"https:\/\/sklep.msalamon.pl\/produkt\/nucleo-f401re\/?utm_source=blog&amp;utm_medium=article&amp;utm_campaign=lcdi2c&amp;utm_content=Text\">Nucleo with STM32F401RE<\/a>, just like in the posts where I compared classic methods of controlling the HD44780 controller. Set the HCLK clock to 84 MHz. Connect the expander to I2C1 according to the schematic below.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_schematic.png\"><img loading=\"lazy\" decoding=\"async\" width=\"300\" height=\"191\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_schematic-300x191.png\" alt=\"\" class=\"wp-image-1032\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_schematic-300x191.png 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_schematic-1024x653.png 1024w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_schematic-768x490.png 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_schematic-24x15.png 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_schematic-36x23.png 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_schematic-125x80.png 125w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_schematic.png 1160w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p>As the IDE I\u2019ll use STM32CubeIDE, where I can configure the project right away. You need to set two things. First, I2C1 on pins PB8 and PB9 (by default it will be PB6 and PB7). Speed Mode as Standard Mode and 100 kHz clock. Leave the rest as default.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_cube_i2c.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"300\" height=\"188\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_cube_i2c-300x188.jpg\" alt=\"\" class=\"wp-image-1033\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_cube_i2c-300x188.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_cube_i2c-1024x641.jpg 1024w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_cube_i2c-768x480.jpg 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_cube_i2c-24x15.jpg 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_cube_i2c-36x23.jpg 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_cube_i2c-128x80.jpg 128w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_cube_i2c.jpg 1426w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<p>The second thing you need to set is a <em>timer<\/em>. You might very well ask why. If you remember the previous LCD posts, there was a delay used with a 1 \u00b5s resolution. Unfortunately, HAL doesn\u2019t provide a timer with such a small tick, so you have to create one yourself. Choose TIM3, select Internal Clock as the clock source. Enter 83 in the Prescaler field (this will bring the clock down to 1 MHz, which gives exactly 1 \u00b5s per tick) and set the maximum counter value to 0xFFFF (on the right side of the value field you can choose hexadecimal formatting).<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_cube_tim3.png\"><img loading=\"lazy\" decoding=\"async\" width=\"300\" height=\"265\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_cube_tim3-300x265.png\" alt=\"\" class=\"wp-image-1034\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_cube_tim3-300x265.png 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_cube_tim3-768x678.png 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_cube_tim3-24x21.png 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_cube_tim3-36x32.png 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_cube_tim3-91x80.png 91w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_cube_tim3.png 1020w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<p>Generate the project with peripheral files separated.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Code for the I2C converter<\/h2>\n\n\n\n<p>Most of the code I use for handling the LCD is already ready. I\u2019ll use what I wrote for the classic interfaces. The library is written so that the only thing I have to change is the functions that send data to the display and read from it.<\/p>\n\n\n\n<p>For convenience I created an 8-bit variable to hold the byte I send to the expander. Thanks to it I also have an overview of what was previously sent. Therefore, I won\u2019t have to wonder what state the control pins were previously in. I\u2019ll make all changes bitwise using masking.<\/p>\n\n\n\n<p>Because the control bits are also connected to the expander, I had to add functions that modify those pins on the converter. The function for setting data is similar to the classic version. Only at the end do you have to send the set data over I\u00b2C.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/\n\/\/ Send\/Read data to\/from expander function\n\/\/\nvoid LCD_SendDataToExpander(uint8_t *Data)\n{\n\tHAL_I2C_Master_Transmit(hi2c_lcd, LCD_I2C_ADDRESS, Data, 1, LCD_I2C_TIMEOUT);\n}\n\n\/\/\n\/\/ Set data port\n\/\/\nstatic inline void LCD_SetDataPort(uint8_t Data)\n{\n\tByteToExpander &amp;amp;= ~(0xF0); \/\/ Clear Data bits\n\n\tif(Data &amp;amp; (1&amp;lt;&amp;lt;0))\n\tByteToExpander |= D4_BIT_MASK;\n\n\tif(Data &amp;amp; (1&amp;lt;&amp;lt;1))\n\tByteToExpander |= D5_BIT_MASK;\n\n\tif(Data &amp;amp; (1&amp;lt;&amp;lt;2))\n\tByteToExpander |= D6_BIT_MASK;\n\n\tif(Data &amp;amp; (1&amp;lt;&amp;lt;3))\n\tByteToExpander |= D7_BIT_MASK;\n\n\tLCD_SendDataToExpander(&amp;amp;ByteToExpander);\n}\n\/\/\n\/\/ Control signals\n\/\/\nstatic inline void LCD_SetRS(void)\n{\n\tByteToExpander |= RS_BIT_MASK;\n\tLCD_SendDataToExpander(&amp;amp;ByteToExpander);\n}\n\nstatic inline void LCD_ClearRS(void)\n{\n\tByteToExpander &amp;amp;= ~(RS_BIT_MASK);\n\tLCD_SendDataToExpander(&amp;amp;ByteToExpander);\n}\n\nstatic inline void LCD_SetEN(void)\n{\n\tByteToExpander |= EN_BIT_MASK;\n\tLCD_SendDataToExpander(&amp;amp;ByteToExpander);\n}\n\nstatic inline void LCD_ClearEN(void)\n{\n\tByteToExpander &amp;amp;= ~(EN_BIT_MASK);\n\tLCD_SendDataToExpander(&amp;amp;ByteToExpander);\n}\n\nstatic inline void LCD_SetRW(void)\n{\n\tByteToExpander |= RW_BIT_MASK;\n\tLCD_SendDataToExpander(&amp;amp;ByteToExpander);\n}\n\nstatic inline void LCD_ClearRW(void)\n{\n\tByteToExpander &amp;amp;= ~(RW_BIT_MASK);\n\tLCD_SendDataToExpander(&amp;amp;ByteToExpander);\n}\n\nvoid LCD_BacklightOff(void)\n{\n\tByteToExpander &amp;amp;= ~(BL_BIT_MASK);\n\tLCD_SendDataToExpander(&amp;amp;ByteToExpander);\n}\n\nvoid LCD_BacklightOn(void)\n{\n\tByteToExpander |= BL_BIT_MASK;\n\tLCD_SendDataToExpander(&amp;amp;ByteToExpander);\n}<\/pre>\n\n\n\n<p>The rest remained almost unchanged, but more on that in a moment.<\/p>\n\n\n\n<p>As you remember, I had a special function for testing communication times. It cleared the LCD and wrote all the characters to the display.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">while (1)\n{\n\tHAL_GPIO_WritePin(TEST_GPIO_Port, TEST_Pin, 1);\n\t\/\/ Measurement start\n\tLCD_Cls();\n\tLCD_Locate(0,0);\n\tLCD_String(\" STM32 + HD44780\");\n\tLCD_Locate(0,1);\n\tLCD_String(\"www.msalamon.pl \");\n\t\/\/ Measurement end\n\tHAL_GPIO_WritePin(TEST_GPIO_Port, TEST_Pin, 0);\n\tHAL_Delay(500);\n}\n<\/pre>\n\n\n\n<p>As a reminder, I\u2019m posting the table with the previous results for 4- and 8-bit modes, with and without the busy flag.<\/p>\n\n\n\n<figure class=\"wp-block-table tablepress tablepress-id-1\"><table class=\"has-fixed-layout\"><thead><tr><th>Mode<\/th><th>Time<\/th><\/tr><\/thead><tbody><tr><td>4-bit HAL_Delay<\/td><td>67,29 ms<\/td><\/tr><tr><td>4-bit without BF<\/td><td>7,14 ms<\/td><\/tr><tr><td>4-bit with BF<\/td><td>2,74 ms<\/td><\/tr><tr><td>8-bit without BF<\/td><td>7,11 ms<\/td><\/tr><tr><td>8-bit with BF<\/td><td>2,74 ms<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Let\u2019s see if the test result will be similar. First up is handling without reading the busy flag. Delay implemented by a timer with a 1 \u00b5s tick. As I\u2019ve shown before, there\u2019s no point in using the HAL delay.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_write_full_frame.png\"><img loading=\"lazy\" decoding=\"async\" width=\"300\" height=\"32\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_write_full_frame-300x32.png\" alt=\"\" class=\"wp-image-1036\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_write_full_frame-300x32.png 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_write_full_frame-1024x110.png 1024w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_write_full_frame-768x82.png 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_write_full_frame-1536x165.png 1536w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_write_full_frame-24x3.png 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_write_full_frame-36x4.png 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_write_full_frame-160x17.png 160w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_write_full_frame.png 1920w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<p>Unfortunately, a time <strong>CATASTROPHE<\/strong>. As much as 55,72 ms. The same operation in 4-bit mode without the busy flag took 7,14 ms, which means the <strong>expander is 7.8 times slower<\/strong>. Those 55 ms are already so long that you can observe flicker on the second row during refresh.<\/p>\n\n\n\n<p>OK, but what about the busy flag? In earlier considerations it helped significantly. Well, I wrote busy-flag handling, but unfortunately it\u2019s pointless with the expander. Why? To get this flag you have to read data from the display. Each time you want to read from the PCF8574, you need to configure it accordingly (there are no registers). For a whole byte, you need to perform two such reads (4-bit mode). This means the time needed to read one byte from the LCD is ~1.79 ms.&nbsp;<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_readingbyte_100k.png\"><img loading=\"lazy\" decoding=\"async\" width=\"300\" height=\"33\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_readingbyte_100k-300x33.png\" alt=\"\" class=\"wp-image-1037\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_readingbyte_100k-300x33.png 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_readingbyte_100k-1024x114.png 1024w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_readingbyte_100k-768x86.png 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_readingbyte_100k-1536x171.png 1536w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_readingbyte_100k-24x3.png 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_readingbyte_100k-36x4.png 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_readingbyte_100k-160x18.png 160w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/hdd44780_i2c_readingbyte_100k.png 1920w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<p>Meanwhile, the wait for the display to process the data is at most about 100 \u00b5s. In that case, there\u2019s no point reading the busy flag, because by the time you retrieve it over I\u00b2C, it will have been set ages earlier. A similar situation occurs with command processing by the HD44780 controller. The maximum processing time is about 1.5 ms. Still less than reading one byte through the expander. Therefore, the <strong>procedure of reading the busy flag through the expander is a complete waste of time\u2026&nbsp;<\/strong><\/p>\n\n\n\n<p>That\u2019s why I decided to remove the functions responsible for reading from the display over I\u00b2C entirely. There\u2019s no point tempting fate and throwing the less experienced into potential trouble.<\/p>\n\n\n\n<p>If the chip supported higher I\u00b2C clock speeds, the result would be much better. Unfortunately, since it\u2019s an old chip, there\u2019s nothing to hope for. You would need to use newer and more efficient expanders. If there\u2019s interest, I\u2019ll test the LCD with, for example, the MCP23017 or a similar one.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Summary<\/h2>\n\n\n\n<p>It\u2019s worth saying something about what came out of my test.&nbsp;<\/p>\n\n\n\n<figure class=\"wp-block-table tablepress tablepress-id-13\"><table class=\"has-fixed-layout\"><thead><tr><th>Mode<\/th><th>Time<\/th><\/tr><\/thead><tbody><tr><td>4-bit HAL_Delay<\/td><td>67,29 ms<\/td><\/tr><tr><td>4-bit without BF<\/td><td>7,14 ms<\/td><\/tr><tr><td>4-bit with BF<\/td><td>2,74 ms<\/td><\/tr><tr><td>8-bit without BF<\/td><td>7,11 ms<\/td><\/tr><tr><td>8-bit with BF<\/td><td>2,74 ms<\/td><\/tr><tr><td>I2C expander<\/td><td>55,72 ms<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>The I2C expander reduces the number of MCU pins needed, and that is an undeniable advantage. You must remember, however, that <strong>you pay for fewer pins with communication time<\/strong> to the display. An almost 8x <strong>slowdown may not be insignificant<\/strong>.<\/p>\n\n\n\n<p>My library is not perfect and you must remember that it works in a blocking fashion. That\u2019s why it\u2019s important that these blocking times are as short as possible, and classic LCD connection ensures that.<\/p>\n\n\n\n<p>The very fact that a clear <strong>display flicker is visible can be a major drawback<\/strong>. So when is it worth using such a converter?<\/p>\n\n\n\n<p>In my opinion, in situations when you build a device <strong>with a very rarely refreshed<\/strong> <strong>display<\/strong>.<strong> Then such a connection makes sense<\/strong>. The data being displayed is not very dynamic and there\u2019s no need to constantly monitor it. These can often be low-power devices that have few pins available.&nbsp;<\/p>\n\n\n\n<p><strong>And what\u2019s your opinion about this type of expander? Share it in the comments.<\/strong><\/p>\n\n\n\n<p>You can find the full project along with the library on my GitHub as usual: <a href=\"https:\/\/github.com\/lamik\/LCD_I2C_STM32_HAL\" target=\"_blank\" rel=\"noopener\">link<\/a><\/p>\n\n\n\n<p><span>If you noticed any mistake, disagree with something, would like to add something important, or simply feel like discussing the topic, write a comment. Remember that the discussion should be polite and in accordance with the rules of the Polish language.<\/span><\/p>\n\n\n<div class=\"kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom\"\n    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;4309&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;0&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;0&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;0&quot;,&quot;greet&quot;:&quot;&quot;,&quot;legend&quot;:&quot;0\\\/5 - (0 votes)&quot;,&quot;size&quot;:&quot;24&quot;,&quot;title&quot;:&quot;Are an I2C Converter and an LCD a Good Match?&quot;,&quot;width&quot;:&quot;0&quot;,&quot;_legend&quot;:&quot;{score}\\\/{best} - ({count} {votes})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>\n            \n<div class=\"kksr-stars\">\n    \n<div class=\"kksr-stars-inactive\">\n            <div class=\"kksr-star\" data-star=\"1\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"2\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"3\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"4\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"5\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n    <\/div>\n    \n<div class=\"kksr-stars-active\" style=\"width: 0px;\">\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n    <\/div>\n<\/div>\n                \n\n<div class=\"kksr-legend\" style=\"font-size: 19.2px;\">\n            <span class=\"kksr-muted\"><\/span>\n    <\/div>\n    <\/div>\n","protected":false},"excerpt":{"rendered":"<p>I often come across the statement that it\u2019s better to connect an LCD display via an I\u00b2C expander because it \u201ceats\u201d only two microcontroller pins instead of a minimum of 6. It\u2019s true that it saves pins, but as we all know\u2014nothing comes for free. Today I\u2019ll check for you [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":3251,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_links_to":"","_links_to_target":""},"categories":[160],"tags":[175,178,176,174,177],"class_list":["post-4309","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-stm32","tag-electronics","tag-kursstm32","tag-programming","tag-stm32","tag-stm32cubemx"],"_links":{"self":[{"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/posts\/4309","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/comments?post=4309"}],"version-history":[{"count":3,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/posts\/4309\/revisions"}],"predecessor-version":[{"id":4415,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/posts\/4309\/revisions\/4415"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/media\/3251"}],"wp:attachment":[{"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/media?parent=4309"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/categories?post=4309"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/tags?post=4309"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}