{"id":3740,"date":"2025-09-04T14:03:15","date_gmt":"2025-09-04T14:03:15","guid":{"rendered":"https:\/\/blog.embeddedexpert.io\/?p=3740"},"modified":"2025-09-04T14:03:17","modified_gmt":"2025-09-04T14:03:17","slug":"emulating-i2c-sensors-part-4-slave-send-data-to-master","status":"publish","type":"post","link":"https:\/\/blog.embeddedexpert.io\/?p=3740","title":{"rendered":"Emulating I2C Sensors Part 4: Slave Send Data to Master"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"414\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/Untitled-1-2-1024x414.jpg\" alt=\"\" class=\"wp-image-3741\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/Untitled-1-2-1024x414.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/Untitled-1-2-300x121.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/Untitled-1-2-768x311.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/Untitled-1-2-1150x465.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/Untitled-1-2-750x303.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/Untitled-1-2-400x162.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/Untitled-1-2-250x101.jpg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/Untitled-1-2.jpg 1365w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>In this part of the guide, the emulated I\u00b2C sensor will act as a data source, sending predefined or dynamically generated values back to the master upon request. This simulates the behavior of real sensors, where the master first selects a register and then retrieves measurement or status data over the I\u00b2C bus.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>In this guide, we shall cover the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The need for Master to transmit data.<\/li>\n\n\n\n<li>Slave Firmware Development.<\/li>\n\n\n\n<li>Master Firmware Development.<\/li>\n\n\n\n<li>Results.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">1. The Need for Master to Transmit Data:<\/h2>\n\n\n\n<p>In I\u00b2C communication, the&nbsp;<strong>master always controls the bus<\/strong>. The slave cannot decide on its own which data to send \u2014 it only responds when the master addresses it. For this reason, the master must typically perform a&nbsp;<strong>short write operation before a read<\/strong>, to tell the slave&nbsp;<em>which register or memory location<\/em>&nbsp;it wants to read from. This is true for almost all register-based sensors and EEPROM devices.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h3 class=\"wp-block-heading\">1.&nbsp;<strong>Register Selection Mechanism<\/strong><\/h3>\n\n\n\n<p>Most sensors and memory devices internally store data in registers or memory cells, each identified by an address. The master doesn\u2019t automatically know which register the slave will send data from. By transmitting the register address first, the master tells the slave&nbsp;<em>\u201cI want to read from here\u201d<\/em>. Without this step, the slave would have no context and might return invalid or stale data.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h3 class=\"wp-block-heading\">2.&nbsp;<strong>Maintaining Data Consistency<\/strong><\/h3>\n\n\n\n<p>Sensors often contain multiple registers, such as configuration settings, measurement values, or status flags. If the master could only read blindly, it might receive unrelated or outdated information. The&nbsp;<strong>preceding write (register pointer)<\/strong>ensures that the returned data is consistent with the master\u2019s request.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h3 class=\"wp-block-heading\">3.&nbsp;<strong>Support for Sequential Reads<\/strong><\/h3>\n\n\n\n<p>Once the master transmits a starting register address, the slave can automatically increment its internal pointer. This allows the master to read multiple bytes in sequence (burst read) without having to send the address before every byte. For example, an accelerometer might send X, Y, and Z readings in one continuous transaction.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h3 class=\"wp-block-heading\">4.&nbsp;<strong>I\u00b2C Bus Protocol Rules<\/strong><\/h3>\n\n\n\n<p>By design, I\u00b2C requires that the master initiates every communication, whether read or write. A slave cannot just broadcast its data. Even when the master wants to read, it must send the slave address and specify direction. When combined with a short write phase (register pointer), this guarantees deterministic and orderly communication between multiple devices on the bus.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">2. Slave Firmware Development:<\/h2>\n\n\n\n<p>OPen main.c of slave project. In user code begin includes, include the following library:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#include &quot;stdlib.h&quot;<\/pre><\/div>\n\n\n\n<p>This will provide us access to random number generation.<\/p>\n\n\n\n<p>In user code begin PV, declare the following array:<\/p>\n\n\n\n<p><\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">uint8_t SensorData[3]={0};<\/pre><\/div>\n\n\n\n<p>This array will hold sensor data.<\/p>\n\n\n\n<p>Declare the following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#define ReadReg1 0x03<\/pre><\/div>\n\n\n\n<p>Here, ReadReg1 shall be transmitted by master to read the sensor data.<\/p>\n\n\n\n<p>In <strong>HAL_I2C_AddrCallback<\/strong> in the else condition, means the master needs to read data:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">if (RegisterData[0] == ReadReg1)   \n{\n  SensorData[0] = rand() % 255;\n  SensorData[1] = rand() % 255;\n  SensorData[2] = rand() % 255;\n  HAL_I2C_Slave_Seq_Transmit_IT(hi2c,SensorData, 3, I2C_FIRST_AND_LAST_FRAME);\n}\nelse\n{\n  \/\/TODO\n}\n<\/pre><\/div>\n\n\n\n<p>If the first byte of the transmitted data match ReadReg1, send three random data.<\/p>\n\n\n\n<p>Thats all for the slave configuration. Save the project and run it on your MCU as follows:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"34\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-03_17-48-35-1024x34.jpg\" alt=\"\" class=\"wp-image-3598\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-03_17-48-35-1024x34.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-03_17-48-35-300x10.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-03_17-48-35-768x25.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-03_17-48-35-1536x51.jpg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-03_17-48-35-2048x68.jpg 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-03_17-48-35-1150x38.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-03_17-48-35-750x25.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-03_17-48-35-400x13.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-03_17-48-35-250x8.jpg 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3. Master Firmware Development:<\/h2>\n\n\n\n<p>Open main.c of the Master project. In user code begin PV, declare the following array:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">uint8_t SensorData[3];<\/pre><\/div>\n\n\n\n<p>This will hold the transmitted data from the slave which is 3 data for now.<\/p>\n\n\n\n<p>In user code begin 3 in while 1 loop:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">\t  HAL_I2C_Mem_Read(&amp;hi2c1, (0x1D&lt;&lt;1), 0x03, 1, SensorData, 3, 100);\n\t  HAL_Delay(100);<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>That all for the master configuration. Save the project and start a debugging session as follows:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"43\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/image-1024x43.png\" alt=\"\" class=\"wp-image-3600\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/image-1024x43.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/image-300x13.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/image-768x32.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/image-1536x65.png 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/image-1150x48.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/image-750x31.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/image-400x17.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/image-250x10.png 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/image.png 2048w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">4. Results:<\/h2>\n\n\n\n<p>By adding SensorData to Live expressions in the debugging session, you should get 3 random numbers as follows:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"483\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/ezgif-14d403091b2b1c.gif\" alt=\"\" class=\"wp-image-3742\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>In next part, we shall use ADC with configuration data to set the sample rate and interrupt generation.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Stay tuned.<\/p>\n\n\n\n<p>Happy  coding \ud83d\ude09<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this part of the guide, the emulated I\u00b2C sensor will act as a data source, sending predefined or dynamically generated values back to the master upon request. This simulates the behavior of real sensors, where the master first selects a register and then retrieves measurement or status data over the I\u00b2C bus. In this [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,11,12],"tags":[],"class_list":["post-3740","post","type-post","status-publish","format-standard","hentry","category-embedded-systems","category-peripheral-drivers","category-stm32"],"_links":{"self":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/3740"}],"collection":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3740"}],"version-history":[{"count":1,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/3740\/revisions"}],"predecessor-version":[{"id":3743,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/3740\/revisions\/3743"}],"wp:attachment":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3740"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3740"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3740"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}