{"id":2050,"date":"2023-10-14T04:45:01","date_gmt":"2023-10-14T04:45:01","guid":{"rendered":"https:\/\/blog.embeddedexpert.io\/?p=2050"},"modified":"2023-10-14T04:47:59","modified_gmt":"2023-10-14T04:47:59","slug":"working-with-stm32-and-at24c32-eeprom-part2-read-write-multibyte","status":"publish","type":"post","link":"https:\/\/blog.embeddedexpert.io\/?p=2050","title":{"rendered":"Working with STM32 and AT24C32 EEPROM Part2: Read\/Write Multibyte"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"768\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/10\/AdobeStock_90169450-1-1024x768.jpeg\" alt=\"\" class=\"wp-image-2051\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/10\/AdobeStock_90169450-1-1024x768.jpeg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/10\/AdobeStock_90169450-1-300x225.jpeg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/10\/AdobeStock_90169450-1-768x576.jpeg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/10\/AdobeStock_90169450-1-1536x1152.jpeg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/10\/AdobeStock_90169450-1-2048x1536.jpeg 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/10\/AdobeStock_90169450-1-1150x863.jpeg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/10\/AdobeStock_90169450-1-750x563.jpeg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/10\/AdobeStock_90169450-1-400x300.jpeg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/10\/AdobeStock_90169450-1-250x188.jpeg 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>In part one of this guide series, we took a look at the EEPROM and type of memory. Also we took a look at  AT24C32 and it&#8217;s features and how to read and write single byte of data.<\/p>\n\n\n\n<p>In part two, we shall see how develop a driver that will allow use to read\/write to\/from multiple memory locations within AT24C32.<\/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\"><li>Sequential write process.<\/li><li>Sequential read process.<\/li><li>Main code.<\/li><li>Results.<\/li><\/ul>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">1. Sequential Write Process:<\/h2>\n\n\n\n<p>A page write is initiated the same way as a byte write, but the microcontroller does not send a stop condition after the first data word is clocked in. Instead, after the EEPROM acknowledges receipt of the first data word, the microcontroller can transmit up to 31 more data words. The EEPROM will respond with a zero after each data word received. The microcontroller must terminate the page write sequence with a stop condition (refer to figure below).<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/user-images.githubusercontent.com\/4484755\/169166644-95f6f14c-22be-4bde-8dd6-ba570b908c0a.png\" alt=\"\" \/><\/figure>\n\n\n\n<ol class=\"wp-block-list\"><li>Send start condition and the slave address with the R\/W bit set to WRITE.<\/li><li>Wait for an acknowledge<\/li><li>Send the first word address<\/li><li>Wait for ACK<\/li><li>Send second word address<\/li><li>Wait for ACK<\/li><li>Send one byte of data<\/li><li>Wait for ACK<\/li><li>Repeat steps 8 &amp; 9 until we are ready to stop sending bytes or we&#8217;ve reached our 32 byte limit<\/li><li>Send STOP condition<\/li><\/ol>\n\n\n\n<p>Hence, the code as 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;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void AT24C32_WritePage(uint16_t address, uint8_t *data, uint8_t len)\n{\n\twhile (I2C1-&gt;SR2 &amp; I2C_SR2_BUSY);           \/\/wait until bus not busy\n\n\tI2C1-&gt;CR1 |= I2C_CR1_START;                 \/\/generate start\n\n\twhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_SB)){;}\t    \/\/wait until start is generated\n\n\tI2C1-&gt;DR = AT24C32Address&lt;&lt; 1;              \/\/ Send slave address\n\n\twhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_ADDR)){;}        \/\/wait until address flag is set\n\n\t(void) I2C1-&gt;SR2; \t\t\t\t\t\t      \/\/Clear SR2\n\n\twhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_TXE));           \/\/Wait until Data register empty\n\n\tI2C1-&gt;DR=address&gt;&gt;8;\t\t\t\t\t\t\/\/Send MSB of the address\n\n\twhile(!(I2C1-&gt;SR1&amp;I2C_SR1_TXE)){;}\t\t\t\/\/Wait until Data register empty\n\n\tI2C1-&gt;DR=address&amp;0x0F;\t\t\t\t\t\t\/\/ send LSB of the address\n\n\tfor (int i=0;i&lt;len;i++)\n\t{\n\t\twhile(!(I2C1-&gt;SR1&amp;I2C_SR1_TXE)){;}\t\t\t\/\/Wait until Data register empty\n\n\t\tI2C1-&gt;DR = *data++; \t\t\t\t\t\t\/\/Write the data to the EEPROM\n\t}\n\twhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_BTF));      \t\/\/wait until transfer finished\n\n\tI2C1-&gt;CR1 |=I2C_CR1_STOP;\t\t\t\t\t\/\/Generate Stop\n\n}<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">2. Sequential Read Process:<\/h2>\n\n\n\n<p>Sequential reads are initiated by either a current address read or a random address read. After the microcontroller receives a data word, it responds with an acknowledge. As long as the EEPROM receives an acknowledge, it will continue to increment the data word address and serially clock out sequential data words. When the memory address limit is reached, the data word address will \u201croll over\u201d and the sequential read will continue. The sequential read operation is terminated when the microcontroller does not respond with a zero but does generate a following stop condition (refer to Figure below).<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/user-images.githubusercontent.com\/4484755\/169166878-d92b2130-4ea2-4d2f-9452-e7afab654a10.png\" alt=\"\" \/><\/figure>\n\n\n\n<p>Explained with words, that will look like this:<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>Send start condition and the slave address with the R\/W bit set to WRITE.<\/li><li>Wait for an acknowledge<\/li><li>Send the first word address<\/li><li>Wait for ACK<\/li><li>Send second word address<\/li><li>Wait for ACK<\/li><li>Send another start condition and the slave address with the R\/W bit set to READ (Wire.requestFrom does this for us as explained earlier)<\/li><li>Wait for ACK<\/li><li>Receive the byte of data from the AT24cxx<\/li><li>Send ACK to AT24cxx<\/li><li>Repeat steps 9 &amp; 10 until we are finished reading as many bytes as we want to<\/li><li>Send a NACK. This tells the AT24cxx to stop sending us data<\/li><li>Send a STOP condition to end communication.<\/li><\/ol>\n\n\n\n<p>Hence, the read sequence as 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;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void AT24C32_ReadPage(uint16_t address, uint8_t *data, uint8_t len)\n{\n\twhile (I2C1-&gt;SR2 &amp; I2C_SR2_BUSY);           \/\/wait until bus not busy\n\n\tI2C1-&gt;CR1 |= I2C_CR1_START;                 \/\/generate start\n\n\twhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_SB)){;}\t    \/\/wait until start is generated\n\n\tI2C1-&gt;DR = AT24C32Address&lt;&lt; 1;              \/\/ Send slave address\n\n\twhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_ADDR)){;}        \/\/wait until address flag is set\n\n\t(void) I2C1-&gt;SR2; \t\t\t\t\t\t      \/\/Clear SR2\n\n\twhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_TXE));           \/\/Wait until Data register empty\n\n\tI2C1-&gt;DR=address&gt;&gt;8;\t\t\t\t\t\t\/\/Send MSB of the address\n\n\twhile(!(I2C1-&gt;SR1&amp;I2C_SR1_TXE)){;}\t\t\t\/\/Wait until Data register empty\n\n\tI2C1-&gt;DR=address&amp;0x0F;\t\t\t\t\t\t\/\/ send LSB of the address\n\n\twhile(!(I2C1-&gt;SR1&amp;I2C_SR1_TXE)){;}\t\t\t\/\/Wait until Data register empty\n\n\tI2C1-&gt;CR1 |= I2C_CR1_START;                 \/\/generate start\n\n\twhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_SB)){;}\t    \/\/wait until start is generated\n\n\tI2C1-&gt;DR = (AT24C32Address&lt;&lt; 1)|1;          \/\/ Send slave address with read operation\n\n\twhile(!(I2C1-&gt;SR1&amp;I2C_SR1_ADDR)){;}\t\t\t\/\/Wait for address flag to set\n\n\t(void) I2C1-&gt;SR2; \t\t\t\t\t\t      \/\/Clear SR2\n\n\tI2C1-&gt;CR1|=I2C_CR1_ACK;\t\t\t\t\t\t\/\/Enable acknowledgment\n\n\twhile(len &gt; 0U)\n\t{\n\t\t\/*if one byte*\/\n\t\tif(len == 1U)\n\t\t{\n\t\t\t\/* Disable Acknowledge *\/\n\t\t\tI2C1-&gt;CR1 &amp;= ~I2C_CR1_ACK;\n\n\t\t\t\/* Generate Stop *\/\n\t\t\tI2C1-&gt;CR1 |= I2C_CR1_STOP;\n\n\t\t\t\/* Wait for RXNE flag set *\/\n\t\t\twhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_RXNE)){}\n\n\t\t\t\/* Read data from DR *\/\n\t\t\t*data++ = I2C1-&gt;DR;\n\t\t\tbreak;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t\/* Wait until RXNE flag is set *\/\n\t\t\twhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_RXNE)){}\n\n\t\t\t\/* Read data from DR *\/\n\t\t\t(*data++) = I2C1-&gt;DR;\n\n\t\t\tlen--;\n\t\t}\n\t}\n\n}<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Hence, the updated source file as 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;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#include &quot;AT24C32.h&quot;\n\n#include &quot;stm32f4xx.h&quot;\n\n#define AT24C32Address 0x57\n\n\n\nvoid AT24C32_ReadByte(uint16_t address, uint8_t *data)\n{\n\twhile (I2C1-&gt;SR2 &amp; I2C_SR2_BUSY);           \/\/wait until bus not busy\n\n\tI2C1-&gt;CR1 |= I2C_CR1_START;                 \/\/generate start\n\n\twhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_SB)){;}\t    \/\/wait until start is generated\n\n\tI2C1-&gt;DR = AT24C32Address&lt;&lt; 1;              \/\/ Send slave address\n\n\twhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_ADDR)){;}        \/\/wait until address flag is set\n\n\t(void) I2C1-&gt;SR2; \t\t\t\t\t\t      \/\/Clear SR2\n\n\twhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_TXE));           \/\/Wait until Data register empty\n\n\tI2C1-&gt;DR=address&gt;&gt;8;\t\t\t\t\t\t\/\/Send MSB of the address\n\n\twhile(!(I2C1-&gt;SR1&amp;I2C_SR1_TXE)){;}\t\t\t\/\/Wait until Data register empty\n\n\tI2C1-&gt;DR=address&amp;0x0F;\t\t\t\t\t\t\/\/ send LSB of the address\n\n\twhile(!(I2C1-&gt;SR1&amp;I2C_SR1_TXE)){;}\t\t\t\/\/Wait until Data register empty\n\n\n\tI2C1-&gt;CR1 |= I2C_CR1_START;                 \/\/generate start\n\n\twhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_SB)){;}\t    \/\/wait until start is generated\n\n\tI2C1-&gt;DR = (AT24C32Address&lt;&lt; 1)|1;          \/\/ Send slave address with read operation\n\n\twhile(!(I2C1-&gt;SR1&amp;I2C_SR1_ADDR)){;}\t\t\t\/\/Wait for address flag to set\n\n\tI2C1-&gt;CR1&amp;=~I2C_CR1_ACK;\t\t\t\t\t\/\/Disable acknowledgment\n\n\t(void)I2C1-&gt;SR2;\t\t\t\t\t\t\t\/\/ Clear SR2\n\n\tI2C1-&gt;CR1|=I2C_CR1_STOP;\t\t\t\t\t\/\/ Generate stop condition\n\n\twhile(!(I2C1-&gt;SR1&amp;I2C_SR1_RXNE)){;}\t\t\t\/\/Wait for receiver buffer to be filled\n\n\t*data=I2C1-&gt;DR;\t\t\t\t\t\t\t\t\/\/Store the I2C bus.\n\n}\n\n\nvoid AT24C32_WriteByte(uint16_t address, uint8_t data)\n{\n\twhile (I2C1-&gt;SR2 &amp; I2C_SR2_BUSY);           \/\/wait until bus not busy\n\n\tI2C1-&gt;CR1 |= I2C_CR1_START;                 \/\/generate start\n\n\twhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_SB)){;}\t    \/\/wait until start is generated\n\n\tI2C1-&gt;DR = AT24C32Address&lt;&lt; 1;              \/\/ Send slave address\n\n\twhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_ADDR)){;}        \/\/wait until address flag is set\n\n\t(void) I2C1-&gt;SR2; \t\t\t\t\t\t      \/\/Clear SR2\n\n\twhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_TXE));           \/\/Wait until Data register empty\n\n\tI2C1-&gt;DR=address&gt;&gt;8;\t\t\t\t\t\t\/\/Send MSB of the address\n\n\twhile(!(I2C1-&gt;SR1&amp;I2C_SR1_TXE)){;}\t\t\t\/\/Wait until Data register empty\n\n\tI2C1-&gt;DR=address&amp;0x0F;\t\t\t\t\t\t\/\/ send LSB of the address\n\n\twhile(!(I2C1-&gt;SR1&amp;I2C_SR1_TXE)){;}\t\t\t\/\/Wait until Data register empty\n\n\tI2C1-&gt;DR = data; \t\t\t\t\t\t\t\/\/Write the data to the EEPROM\n\n\twhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_BTF));      \t\/\/wait until transfer finished\n\n\tI2C1-&gt;CR1 |=I2C_CR1_STOP;\t\t\t\t\t\/\/Generate Stop\n\n}\n\n\nvoid AT24C32_ReadPage(uint16_t address, uint8_t *data, uint8_t len)\n{\n\twhile (I2C1-&gt;SR2 &amp; I2C_SR2_BUSY);           \/\/wait until bus not busy\n\n\tI2C1-&gt;CR1 |= I2C_CR1_START;                 \/\/generate start\n\n\twhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_SB)){;}\t    \/\/wait until start is generated\n\n\tI2C1-&gt;DR = AT24C32Address&lt;&lt; 1;              \/\/ Send slave address\n\n\twhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_ADDR)){;}        \/\/wait until address flag is set\n\n\t(void) I2C1-&gt;SR2; \t\t\t\t\t\t      \/\/Clear SR2\n\n\twhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_TXE));           \/\/Wait until Data register empty\n\n\tI2C1-&gt;DR=address&gt;&gt;8;\t\t\t\t\t\t\/\/Send MSB of the address\n\n\twhile(!(I2C1-&gt;SR1&amp;I2C_SR1_TXE)){;}\t\t\t\/\/Wait until Data register empty\n\n\tI2C1-&gt;DR=address&amp;0x0F;\t\t\t\t\t\t\/\/ send LSB of the address\n\n\twhile(!(I2C1-&gt;SR1&amp;I2C_SR1_TXE)){;}\t\t\t\/\/Wait until Data register empty\n\n\tI2C1-&gt;CR1 |= I2C_CR1_START;                 \/\/generate start\n\n\twhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_SB)){;}\t    \/\/wait until start is generated\n\n\tI2C1-&gt;DR = (AT24C32Address&lt;&lt; 1)|1;          \/\/ Send slave address with read operation\n\n\twhile(!(I2C1-&gt;SR1&amp;I2C_SR1_ADDR)){;}\t\t\t\/\/Wait for address flag to set\n\n\t(void) I2C1-&gt;SR2; \t\t\t\t\t\t      \/\/Clear SR2\n\n\tI2C1-&gt;CR1|=I2C_CR1_ACK;\t\t\t\t\t\t\/\/Enable acknowledgment\n\n\twhile(len &gt; 0U)\n\t{\n\t\t\/*if one byte*\/\n\t\tif(len == 1U)\n\t\t{\n\t\t\t\/* Disable Acknowledge *\/\n\t\t\tI2C1-&gt;CR1 &amp;= ~I2C_CR1_ACK;\n\n\t\t\t\/* Generate Stop *\/\n\t\t\tI2C1-&gt;CR1 |= I2C_CR1_STOP;\n\n\t\t\t\/* Wait for RXNE flag set *\/\n\t\t\twhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_RXNE)){}\n\n\t\t\t\/* Read data from DR *\/\n\t\t\t*data++ = I2C1-&gt;DR;\n\t\t\tbreak;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t\/* Wait until RXNE flag is set *\/\n\t\t\twhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_RXNE)){}\n\n\t\t\t\/* Read data from DR *\/\n\t\t\t(*data++) = I2C1-&gt;DR;\n\n\t\t\tlen--;\n\t\t}\n\t}\n\n}\n\nvoid AT24C32_WritePage(uint16_t address, uint8_t *data, uint8_t len)\n{\n\twhile (I2C1-&gt;SR2 &amp; I2C_SR2_BUSY);           \/\/wait until bus not busy\n\n\tI2C1-&gt;CR1 |= I2C_CR1_START;                 \/\/generate start\n\n\twhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_SB)){;}\t    \/\/wait until start is generated\n\n\tI2C1-&gt;DR = AT24C32Address&lt;&lt; 1;              \/\/ Send slave address\n\n\twhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_ADDR)){;}        \/\/wait until address flag is set\n\n\t(void) I2C1-&gt;SR2; \t\t\t\t\t\t      \/\/Clear SR2\n\n\twhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_TXE));           \/\/Wait until Data register empty\n\n\tI2C1-&gt;DR=address&gt;&gt;8;\t\t\t\t\t\t\/\/Send MSB of the address\n\n\twhile(!(I2C1-&gt;SR1&amp;I2C_SR1_TXE)){;}\t\t\t\/\/Wait until Data register empty\n\n\tI2C1-&gt;DR=address&amp;0x0F;\t\t\t\t\t\t\/\/ send LSB of the address\n\n\tfor (int i=0;i&lt;len;i++)\n\t{\n\t\twhile(!(I2C1-&gt;SR1&amp;I2C_SR1_TXE)){;}\t\t\t\/\/Wait until Data register empty\n\n\t\tI2C1-&gt;DR = *data++; \t\t\t\t\t\t\/\/Write the data to the EEPROM\n\t}\n\twhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_BTF));      \t\/\/wait until transfer finished\n\n\tI2C1-&gt;CR1 |=I2C_CR1_STOP;\t\t\t\t\t\/\/Generate Stop\n\n}\n<\/pre><\/div>\n\n\n\n<p>Also, the header file:<\/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;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#ifndef AT24C32_H_\n#define AT24C32_H_\n\n#include &quot;stdint.h&quot;\n\n\n\n\nvoid AT24C32_ReadByte(uint16_t address, uint8_t *data);\n\nvoid AT24C32_WriteByte(uint16_t address, uint8_t data);\n\nvoid AT24C32_ReadPage(uint16_t address, uint8_t *data, uint8_t len);\n\nvoid AT24C32_WritePage(uint16_t address, uint8_t *data, uint8_t len);\n\n\n#endif \/* AT24C32_H_ *\/\n<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3. Main code:<\/h2>\n\n\n\n<p><\/p>\n\n\n\n<p>In main.c:<\/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;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#include &quot;i2c.h&quot;\n#include &quot;time_base.h&quot;\n#include &quot;uart.h&quot;\n#include &quot;stdio.h&quot;\n#include &quot;AT24C32.h&quot;\n\nuint8_t data_read[4];\n\nuint8_t data_write[4]={100,200,50,30};\n\nuint16_t address=100;\n\n\nint main(void)\n{\n\tTicks_Init(16000000);\n\n\tuart2_rxtx_init();\n\n\ti2c_init();\n\n\tAT24C32_WritePage(address,data_write,4);\n\n\tprintf(&quot;Data written to address %d are: \\r\\n&quot;,address);\n\n\tfor (int i=0;i&lt;4;i++)\n\t{\n\t\tprintf(&quot;%d \\t&quot;,data_write[i]);\n\t}\n\tprintf(&quot;\\r\\n&quot;);\n\n\tdelay(100);\n\n\tAT24C32_ReadPage(address,data_read,4);\n\n\tprintf(&quot;Data read from address %d are: \\r\\n&quot;,address);\n\n\tfor (int i=0;i&lt;4;i++)\n\t{\n\t\tprintf(&quot;%d \\t&quot;,data_read[i]);\n\t}\n\tprintf(&quot;\\r\\n&quot;);\n\n\tdelay(100);\n\n\n\twhile(1)\n\t{\n\t}\n\n}\n<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">4. Results:<\/h2>\n\n\n\n<p>Open serial terminal and set the buadrate to be 115200 and you should get the following results:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"870\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/10\/Screenshot-2023-10-14-at-7.36.05-AM-1024x870.png\" alt=\"\" class=\"wp-image-2052\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/10\/Screenshot-2023-10-14-at-7.36.05-AM-1024x870.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/10\/Screenshot-2023-10-14-at-7.36.05-AM-300x255.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/10\/Screenshot-2023-10-14-at-7.36.05-AM-768x652.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/10\/Screenshot-2023-10-14-at-7.36.05-AM-1150x977.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/10\/Screenshot-2023-10-14-at-7.36.05-AM-750x637.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/10\/Screenshot-2023-10-14-at-7.36.05-AM-400x340.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/10\/Screenshot-2023-10-14-at-7.36.05-AM-250x212.png 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/10\/Screenshot-2023-10-14-at-7.36.05-AM.png 1286w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Happy coding \ud83d\ude42<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In part one of this guide series, we took a look at the EEPROM and type of memory. Also we took a look at AT24C32 and it&#8217;s features and how to read and write single byte of data. In part two, we shall see how develop a driver that will allow use to read\/write to\/from [&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-2050","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\/2050"}],"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=2050"}],"version-history":[{"count":2,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/2050\/revisions"}],"predecessor-version":[{"id":2054,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/2050\/revisions\/2054"}],"wp:attachment":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2050"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2050"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2050"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}