{"id":1957,"date":"2023-09-02T06:33:18","date_gmt":"2023-09-02T06:33:18","guid":{"rendered":"https:\/\/blog.embeddedexpert.io\/?p=1957"},"modified":"2023-09-02T06:33:20","modified_gmt":"2023-09-02T06:33:20","slug":"building-board-support-package-bsp-for-stm32f411-nucleo64-part14-2-i2c-full-duplex-communication","status":"publish","type":"post","link":"https:\/\/blog.embeddedexpert.io\/?p=1957","title":{"rendered":"Building Board Support Package (BSP) for STM32F411-Nucleo64 Part14.2: I2C Full duplex Communication"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"683\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/09\/AdobeStock_128586024-1024x683.jpeg\" alt=\"\" class=\"wp-image-1958\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/09\/AdobeStock_128586024-1024x683.jpeg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/09\/AdobeStock_128586024-300x200.jpeg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/09\/AdobeStock_128586024-768x512.jpeg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/09\/AdobeStock_128586024-1536x1024.jpeg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/09\/AdobeStock_128586024-2048x1365.jpeg 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/09\/AdobeStock_128586024-1150x767.jpeg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/09\/AdobeStock_128586024-750x500.jpeg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/09\/AdobeStock_128586024-400x267.jpeg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/09\/AdobeStock_128586024-250x167.jpeg 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>In the second section of the fourteenth part of I2C BSP, we shall develop functions that will communicate with slave devices to write\/read to\/from MPU9250.<\/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>Updating the header file.<\/li><li>Updating the source file.<\/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. Updating the header file:<\/h2>\n\n\n\n<p>In i2c_bps.h header file, include the following three functions.<\/p>\n\n\n\n<p>The first function:<\/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;}\">I2C_StatusTypedef BSP_I2C_Write(I2C_TypeDef *i2c, uint8_t address, uint8_t *data,uint16_t length, uint32_t timeout);<\/pre><\/div>\n\n\n\n<p>The function takes five parameters as following:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>I2C_Typedef to indicate which i2c to be used.<\/li><li>The address of the slave device.<\/li><li>Array that holds the data to be written to the slave device.<\/li><li>Length of the data to be written.<\/li><li>Timeout for time management.<\/li><\/ul>\n\n\n\n<p>Also, the function will return the I2C status as following:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Success <\/li><li>Failed.<\/li><li>Timeout<\/li><\/ul>\n\n\n\n<p>The second function:<\/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;}\">I2C_StatusTypedef BSP_I2C_Read_Memory(I2C_TypeDef *i2c, uint8_t address,uint8_t MemAddr, uint8_t *data,uint16_t length, uint32_t timeout);<\/pre><\/div>\n\n\n\n<p>This function will send the memory address to be read . It takes six parameters:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>I2C_Typedef to indicate which i2c to be used.<\/li><li>The address of the slave device.<\/li><li>The memory address within the slave.<\/li><li>Array which holds the data to be read.<\/li><li>Length of the data to be read.<\/li><li>Timeout for time management.<\/li><\/ul>\n\n\n\n<p>The function will return the status of I2C as mentioned earlier.<\/p>\n\n\n\n<p>The third and final function 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;}\">I2C_StatusTypedef BSP_I2C_Read(I2C_TypeDef *i2c, uint8_t address, uint8_t *data,uint16_t lenght, uint32_t timeout);<\/pre><\/div>\n\n\n\n<p>This function will read the slave directly without sending the memory to read first.<\/p>\n\n\n\n<p>Hence, the update header 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;}\">#ifndef I2C_BSP_H_\n#define I2C_BSP_H_\n\n#include &quot;stm32f4xx.h&quot;\n#include &quot;stdint.h&quot;\n#include &quot;bsp_debug.h&quot;\n#include &quot;bsp.h&quot;\n\n#define __I2C1_CLOCK_ENABLE()\t\tRCC-&gt;APB1ENR|=RCC_APB1ENR_I2C1EN\n#define __I2C2_CLOCK_ENABLE()\t\tRCC-&gt;APB1ENR|=RCC_APB1ENR_I2C2EN\n#define __I2C3_CLOCK_ENABLE()\t\tRCC-&gt;APB1ENR|=RCC_APB1ENR_I2C3EN\n\n\ntypedef enum\n{\n\tstandardSpeed=0,\n\tfastMode=1\n}I2C_MasterModeTypedef;\n\n\ntypedef enum\n{\n\tDuty_2=0,\n\tDuty_16_9=1\n}I2C_DutyModeTypedef;\n\n\ntypedef enum\n{\n\ti2c_success=0,\n\ti2c_failed=1,\n\ti2c_timeOut=2\n}I2C_StatusTypedef;\n\n\ntypedef struct\n{\n\n\tuint8_t PeripheralFrequency;\n\n\tuint8_t MasterMode;\n\n\tuint8_t DutyMode;\n\n\tuint16_t RiseTime;\n\n\tuint16_t Clock;\n\n}I2C_ConfigTypedef;\n\n\nvoid BSP_I2C_Init(I2C_TypeDef *i2c, I2C_ConfigTypedef *config);\n\nvoid BSP_I2C_Bus_Scan(I2C_TypeDef *i2c);\n\nI2C_StatusTypedef BSP_I2C_Write(I2C_TypeDef *i2c, uint8_t address, uint8_t *data ,uint16_t length, uint32_t timeout);\n\nI2C_StatusTypedef BSP_I2C_Read_Memory(I2C_TypeDef *i2c, uint8_t address,uint8_t MemAddr, uint8_t *data,uint16_t length, uint32_t timeout);\n\nI2C_StatusTypedef BSP_I2C_Read(I2C_TypeDef *i2c, uint8_t address, uint8_t *data,uint16_t lenght, uint32_t timeout);\n\n\n\n#endif \/* I2C_BSP_H_ *\/\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. Updating the source file:<\/h2>\n\n\n\n<p>Before heading into updating the source file, please refer to these two guide:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Writing multiple bytes (<a rel=\"noreferrer noopener\" href=\"https:\/\/blog.embeddedexpert.io\/?p=576\" data-type=\"URL\" data-id=\"https:\/\/blog.embeddedexpert.io\/?p=576\" target=\"_blank\">here<\/a>).<\/li><li>Reading multiple bytes (<a rel=\"noreferrer noopener\" href=\"https:\/\/blog.embeddedexpert.io\/?p=549\" data-type=\"URL\" data-id=\"https:\/\/blog.embeddedexpert.io\/?p=549\" target=\"_blank\">here<\/a>).<\/li><\/ul>\n\n\n\n<p><\/p>\n\n\n\n<p>The write function 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;}\">I2C_StatusTypedef BSP_I2C_Write(I2C_TypeDef *i2c, uint8_t address, uint8_t *data,uint16_t length, uint32_t timeout)\n{\n\n\tuint32_t start_timer=BSP_Get_Ticks();\n\n\twhile (i2c-&gt;SR2 &amp; I2C_SR2_BUSY)             \/\/wait until bus not busy\n\t{\n\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t{\n\t\t\treturn i2c_timeOut;\n\t\t}\n\t}\n\n\ti2c-&gt;CR1 |= I2C_CR1_START;                   \/\/generate start\n\n\twhile (!(i2c-&gt;SR1 &amp; I2C_SR1_SB))\t\t\t \/\/wait until start is generated\n\t{\n\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t{\n\t\t\treturn i2c_timeOut;\n\t\t}\n\t}\n\n\ti2c-&gt;DR = address&lt;&lt; 1;                 \t \t \/\/ Send slave address\n\n\twhile (!(i2c-&gt;SR1 &amp; I2C_SR1_ADDR))          \/\/wait until address flag is set\n\t{\n\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t{\n\t\t\treturn i2c_timeOut;\n\t\t}\n\t}\n\n\t(void) i2c-&gt;SR2; \t\t\t\t\t\t     \/\/Clear SR2\n\n\twhile (!(i2c-&gt;SR1 &amp; I2C_SR1_TXE))           \/\/Wait until Data register empty\n\t{\n\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t{\n\t\t\treturn i2c_timeOut;\n\t\t}\n\t}\n\n\n\tfor (uint16_t i=0;i&lt;length;i++)\n\t{\n\t\ti2c-&gt;DR=data[i]; \t\t\t\t\t\t\/\/filling buffer with command or data\n\t\twhile (!(i2c-&gt;SR1 &amp; I2C_SR1_BTF))\n\t\t{\n\t\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t\t{\n\t\t\t\treturn i2c_timeOut;\n\t\t\t}\n\t\t}\n\t}\n\ti2c-&gt;CR1 |= I2C_CR1_STOP;\n\n\treturn i2c_success;\n}<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>For the read from memory address:<\/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;}\">I2C_StatusTypedef BSP_I2C_Read_Memory(I2C_TypeDef *i2c, uint8_t address,uint8_t MemAddr, uint8_t *data,uint16_t length, uint32_t timeout)\n{\n\n\tuint32_t start_timer=BSP_Get_Ticks();\n\n\twhile (i2c-&gt;SR2 &amp; I2C_SR2_BUSY)\n\t{\n\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t{\n\t\t\treturn i2c_timeOut;\n\t\t}\n\t}\n\n\ti2c-&gt;CR1|=I2C_CR1_START;\n\n\twhile(!(i2c-&gt;SR1 &amp; I2C_SR1_SB))\n\t{\n\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t{\n\t\t\treturn i2c_timeOut;\n\t\t}\n\t}\n\n\ti2c-&gt;DR=address&lt;&lt;1;\n\n\twhile(!(i2c-&gt;SR1 &amp; I2C_SR1_ADDR))\n\t{\n\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t{\n\t\t\treturn i2c_timeOut;\n\t\t}\n\t}\n\n\t(void)i2c-&gt;SR2;\n\n\twhile(!(i2c-&gt;SR1&amp;I2C_SR1_TXE))\n\t{\n\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t{\n\t\t\treturn i2c_timeOut;\n\t\t}\n\t}\n\n\ti2c-&gt;DR = MemAddr;\n\n\twhile(!(i2c-&gt;SR1&amp;I2C_SR1_TXE))\n\t{\n\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t{\n\t\t\treturn i2c_timeOut;\n\t\t}\n\t}\n\n\ti2c-&gt;CR1|=I2C_CR1_START;\n\n\twhile(!(i2c-&gt;SR1 &amp; I2C_SR1_SB))\n\t{\n\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t{\n\t\t\treturn i2c_timeOut;\n\t\t}\n\t}\n\n\ti2c-&gt;DR=address&lt;&lt;1|1;\n\n\twhile(!(i2c-&gt;SR1 &amp; I2C_SR1_ADDR))\n\t{\n\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t{\n\t\t\treturn i2c_timeOut;\n\t\t}\n\t}\n\n\t(void)i2c-&gt;SR2;\n\n\ti2c-&gt;CR1|=I2C_CR1_ACK;\n\n\twhile(length&gt;0U)\n\t{\n\t\tif(length==1U)\n\t{\n\t\t\ti2c-&gt;CR1&amp;=~I2C_CR1_ACK;\n\t\t\ti2c-&gt;CR1|=I2C_CR1_STOP;\n\t\t\twhile(!(i2c-&gt;SR1&amp;I2C_SR1_RXNE))\n\t\t\t{\n\t\t\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t\t\t{\n\t\t\t\t\treturn i2c_timeOut;\n\t\t\t\t}\n\t\t\t}\n\t\t\t*data++=i2c-&gt;DR;\n\t\t\tbreak;\n\t}\n\telse\n\t{\n\t\twhile(!(i2c-&gt;SR1&amp;I2C_SR1_RXNE))\n\t\t{\n\t\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t\t{\n\t\t\t\treturn i2c_timeOut;\n\t\t\t}\n\t\t}\n\t\t(*data++)=i2c-&gt;DR;\n\t\tlength--;\n\n\t}\n\n\n\t}\n\n\treturn i2c_success;\n}<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>For reading the i2c slave only without memory:<\/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;}\">I2C_StatusTypedef BSP_I2C_Read(I2C_TypeDef *i2c, uint8_t address, uint8_t *data, uint16_t length,  uint32_t timeout)\n{\n\tuint32_t start_timer=BSP_Get_Ticks();\n\n\twhile (i2c-&gt;SR2 &amp; I2C_SR2_BUSY)\n\t{\n\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t{\n\t\t\treturn i2c_timeOut;\n\t\t}\n\t}\n\n\ti2c-&gt;CR1|=I2C_CR1_START;\n\n\twhile(!(i2c-&gt;SR1 &amp; I2C_SR1_SB))\n\t{\n\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t{\n\t\t\treturn i2c_timeOut;\n\t\t}\n\t}\n\n\ti2c-&gt;DR=address&lt;&lt;1|1;\n\n\twhile(!(i2c-&gt;SR1 &amp; I2C_SR1_ADDR))\n\t{\n\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t{\n\t\t\treturn i2c_timeOut;\n\t\t}\n\t}\n\n\t(void)i2c-&gt;SR2;\n\n\ti2c-&gt;CR1|=I2C_CR1_ACK;\n\n\twhile(length&gt;0U)\n\t{\n\t\tif(length==1U)\n\t\t{\n\t\t\ti2c-&gt;CR1&amp;=~I2C_CR1_ACK;\n\t\t\ti2c-&gt;CR1|=I2C_CR1_STOP;\n\t\t\twhile(!(i2c-&gt;SR1&amp;I2C_SR1_RXNE))\n\t\t\t{\n\t\t\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t\t\t{\n\t\t\t\t\treturn i2c_timeOut;\n\t\t\t\t}\n\t\t\t}\n\t\t\t*data++=i2c-&gt;DR;\n\t\t\tbreak;\n\t\t}\n\telse\n\t{\n\t\twhile(!(i2c-&gt;SR1&amp;I2C_SR1_RXNE))\n\t\t{\n\t\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t\t{\n\t\t\t\treturn i2c_timeOut;\n\t\t\t}\n\t\t}\n\t\t(*data++)=i2c-&gt;DR;\n\t\tlength--;\n\n\t}\n\n\t}\n\n\treturn i2c_success;\n}\n<\/pre><\/div>\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;i2c_bsp.h&quot;\n\n\nvoid BSP_I2C_Init(I2C_TypeDef *i2c, I2C_ConfigTypedef *config)\n{\n\n\ti2c-&gt;CR1=I2C_CR1_SWRST;\n\n\ti2c-&gt;CR1&amp;=~I2C_CR1_SWRST;\n\n\ti2c-&gt;CR2|= config-&gt;PeripheralFrequency;\n\n\ti2c-&gt;TRISE=config-&gt;RiseTime;\n\n\ti2c-&gt;CCR|=(config-&gt;MasterMode&lt;&lt;I2C_CCR_FS_Pos);\n\n\ti2c-&gt;CCR|=(config-&gt;DutyMode&lt;&lt;I2C_CCR_DUTY_Pos);\n\n\tif((config-&gt;Clock)==0)\n\t{\n\t\tfloat period =1.0\/(float)(config-&gt;PeripheralFrequency);\n\n\t\tif((config-&gt;MasterMode)==standardSpeed)\n\t\t{\n\n\t\t\tuint16_t tmp = 5\/period;\n\t\t\ti2c-&gt;CCR|=(tmp&lt;&lt;I2C_CCR_CCR_Pos);\n\t\t}\n\n\t\telse\n\t\t{\n\t\t\tif(config-&gt;DutyMode==Duty_2)\n\t\t\t{\n\t\t\t\tuint16_t tmp=5\/period;\n\t\t\t\ti2c-&gt;CCR|=(tmp&lt;&lt;I2C_CCR_CCR_Pos);\n\t\t\t}\n\n\t\t\telse\n\t\t\t{\n\t\t\t\tuint16_t tmp=13\/period;\n\t\t\t\ti2c-&gt;CCR|=(tmp&lt;&lt;I2C_CCR_CCR_Pos);\n\t\t\t}\n\t\t}\n\n\n\t}\n\telse\n\t{\n\t\ti2c-&gt;CCR|=(config-&gt;Clock&lt;&lt;I2C_CCR_CCR_Pos);\n\t}\n\n\ti2c-&gt;CR1|=I2C_CR1_PE;\n\n}\n\n\nvoid BSP_I2C_Bus_Scan(I2C_TypeDef *i2c)\n{\n\tchar data[100];\n\tuint8_t a=0;\n\tfor (uint8_t i=0;i&lt;128;i++)\n\t{\n\t\ti2c-&gt;CR1 |= I2C_CR1_START;\n\t\twhile(!(i2c-&gt;SR1 &amp; I2C_SR1_SB));\n\t\ti2c-&gt;DR=(i&lt;&lt;1|0);\n\t\twhile(!(i2c-&gt;SR1)|!(I2C1-&gt;SR2)){};\n\t\ti2c-&gt;CR1 |= I2C_CR1_STOP;\n\t\tBSP_Delay(1);\n\t\ta=(i2c-&gt;SR1&amp;I2C_SR1_ADDR);\n\t\tif (a==2)\n\t    {\n\t\t\tsprintf(data,&quot;Found I2C device at address 0x%X (hexadecimal), or %d (decimal)\\n\\r&quot;,i,i);\n\t\t\tlog_info(data);\n\t    }\n\t }\n}\n\n\nI2C_StatusTypedef BSP_I2C_Write(I2C_TypeDef *i2c, uint8_t address, uint8_t *data,uint16_t length, uint32_t timeout)\n{\n\n\tuint32_t start_timer=BSP_Get_Ticks();\n\n\twhile (i2c-&gt;SR2 &amp; I2C_SR2_BUSY)             \/\/wait until bus not busy\n\t{\n\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t{\n\t\t\treturn i2c_timeOut;\n\t\t}\n\t}\n\n\ti2c-&gt;CR1 |= I2C_CR1_START;                   \/\/generate start\n\n\twhile (!(i2c-&gt;SR1 &amp; I2C_SR1_SB))\t\t\t \/\/wait until start is generated\n\t{\n\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t{\n\t\t\treturn i2c_timeOut;\n\t\t}\n\t}\n\n\ti2c-&gt;DR = address&lt;&lt; 1;                 \t \t \/\/ Send slave address\n\n\twhile (!(i2c-&gt;SR1 &amp; I2C_SR1_ADDR))          \/\/wait until address flag is set\n\t{\n\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t{\n\t\t\treturn i2c_timeOut;\n\t\t}\n\t}\n\n\t(void) i2c-&gt;SR2; \t\t\t\t\t\t     \/\/Clear SR2\n\n\twhile (!(i2c-&gt;SR1 &amp; I2C_SR1_TXE))           \/\/Wait until Data register empty\n\t{\n\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t{\n\t\t\treturn i2c_timeOut;\n\t\t}\n\t}\n\n\n\tfor (uint16_t i=0;i&lt;length;i++)\n\t{\n\t\ti2c-&gt;DR=data[i]; \t\t\t\t\t\t\/\/filling buffer with command or data\n\t\twhile (!(i2c-&gt;SR1 &amp; I2C_SR1_BTF))\n\t\t{\n\t\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t\t{\n\t\t\t\treturn i2c_timeOut;\n\t\t\t}\n\t\t}\n\t}\n\ti2c-&gt;CR1 |= I2C_CR1_STOP;\n\n\treturn i2c_success;\n}\n\nI2C_StatusTypedef BSP_I2C_Read_Memory(I2C_TypeDef *i2c, uint8_t address,uint8_t MemAddr, uint8_t *data,uint16_t length, uint32_t timeout)\n{\n\n\tuint32_t start_timer=BSP_Get_Ticks();\n\n\twhile (i2c-&gt;SR2 &amp; I2C_SR2_BUSY)\n\t{\n\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t{\n\t\t\treturn i2c_timeOut;\n\t\t}\n\t}\n\n\ti2c-&gt;CR1|=I2C_CR1_START;\n\n\twhile(!(i2c-&gt;SR1 &amp; I2C_SR1_SB))\n\t{\n\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t{\n\t\t\treturn i2c_timeOut;\n\t\t}\n\t}\n\n\ti2c-&gt;DR=address&lt;&lt;1;\n\n\twhile(!(i2c-&gt;SR1 &amp; I2C_SR1_ADDR))\n\t{\n\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t{\n\t\t\treturn i2c_timeOut;\n\t\t}\n\t}\n\n\t(void)i2c-&gt;SR2;\n\n\twhile(!(i2c-&gt;SR1&amp;I2C_SR1_TXE))\n\t{\n\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t{\n\t\t\treturn i2c_timeOut;\n\t\t}\n\t}\n\n\ti2c-&gt;DR = MemAddr;\n\n\twhile(!(i2c-&gt;SR1&amp;I2C_SR1_TXE))\n\t{\n\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t{\n\t\t\treturn i2c_timeOut;\n\t\t}\n\t}\n\n\ti2c-&gt;CR1|=I2C_CR1_START;\n\n\twhile(!(i2c-&gt;SR1 &amp; I2C_SR1_SB))\n\t{\n\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t{\n\t\t\treturn i2c_timeOut;\n\t\t}\n\t}\n\n\ti2c-&gt;DR=address&lt;&lt;1|1;\n\n\twhile(!(i2c-&gt;SR1 &amp; I2C_SR1_ADDR))\n\t{\n\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t{\n\t\t\treturn i2c_timeOut;\n\t\t}\n\t}\n\n\t(void)i2c-&gt;SR2;\n\n\ti2c-&gt;CR1|=I2C_CR1_ACK;\n\n\twhile(length&gt;0U)\n\t{\n\t\tif(length==1U)\n\t{\n\t\t\ti2c-&gt;CR1&amp;=~I2C_CR1_ACK;\n\t\t\ti2c-&gt;CR1|=I2C_CR1_STOP;\n\t\t\twhile(!(i2c-&gt;SR1&amp;I2C_SR1_RXNE))\n\t\t\t{\n\t\t\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t\t\t{\n\t\t\t\t\treturn i2c_timeOut;\n\t\t\t\t}\n\t\t\t}\n\t\t\t*data++=i2c-&gt;DR;\n\t\t\tbreak;\n\t}\n\telse\n\t{\n\t\twhile(!(i2c-&gt;SR1&amp;I2C_SR1_RXNE))\n\t\t{\n\t\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t\t{\n\t\t\t\treturn i2c_timeOut;\n\t\t\t}\n\t\t}\n\t\t(*data++)=i2c-&gt;DR;\n\t\tlength--;\n\n\t}\n\n\n\t}\n\n\treturn i2c_success;\n}\n\nI2C_StatusTypedef BSP_I2C_Read(I2C_TypeDef *i2c, uint8_t address, uint8_t *data, uint16_t length,  uint32_t timeout)\n{\n\tuint32_t start_timer=BSP_Get_Ticks();\n\n\twhile (i2c-&gt;SR2 &amp; I2C_SR2_BUSY)\n\t{\n\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t{\n\t\t\treturn i2c_timeOut;\n\t\t}\n\t}\n\n\ti2c-&gt;CR1|=I2C_CR1_START;\n\n\twhile(!(i2c-&gt;SR1 &amp; I2C_SR1_SB))\n\t{\n\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t{\n\t\t\treturn i2c_timeOut;\n\t\t}\n\t}\n\n\ti2c-&gt;DR=address&lt;&lt;1|1;\n\n\twhile(!(i2c-&gt;SR1 &amp; I2C_SR1_ADDR))\n\t{\n\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t{\n\t\t\treturn i2c_timeOut;\n\t\t}\n\t}\n\n\t(void)i2c-&gt;SR2;\n\n\ti2c-&gt;CR1|=I2C_CR1_ACK;\n\n\twhile(length&gt;0U)\n\t{\n\t\tif(length==1U)\n\t\t{\n\t\t\ti2c-&gt;CR1&amp;=~I2C_CR1_ACK;\n\t\t\ti2c-&gt;CR1|=I2C_CR1_STOP;\n\t\t\twhile(!(i2c-&gt;SR1&amp;I2C_SR1_RXNE))\n\t\t\t{\n\t\t\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t\t\t{\n\t\t\t\t\treturn i2c_timeOut;\n\t\t\t\t}\n\t\t\t}\n\t\t\t*data++=i2c-&gt;DR;\n\t\t\tbreak;\n\t\t}\n\telse\n\t{\n\t\twhile(!(i2c-&gt;SR1&amp;I2C_SR1_RXNE))\n\t\t{\n\t\t\tif (BSP_Get_Ticks()- start_timer&gt;timeout)\n\t\t\t{\n\t\t\t\treturn i2c_timeOut;\n\t\t\t}\n\t\t}\n\t\t(*data++)=i2c-&gt;DR;\n\t\tlength--;\n\n\t}\n\n\t}\n\n\treturn i2c_success;\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\">3. Main code.<\/h2>\n\n\n\n<p>In main.c file:<\/p>\n\n\n\n<p>Include 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;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#include &quot;bsp.h&quot;\n#include &quot;uart_bsp.h&quot;\n#include &quot;exti_bsp.h&quot;\n#include &quot;bsp_debug.h&quot;\n#include &quot;spi_bsp.h&quot;\n#include &quot;dma_bsp.h&quot;\n#include &quot;i2c_bsp.h&quot;\n#include &quot;stdlib.h&quot;<\/pre><\/div>\n\n\n\n<p>Declare i2c configuration data structure:<\/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;}\">I2C_ConfigTypedef i2c1Config;<\/pre><\/div>\n\n\n\n<p>Declare an array of 6 bytes to hold the acceleration 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;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">uint8_t MPU9250_ACC_Data[6];<\/pre><\/div>\n\n\n\n<p>In main function:<\/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;}\">\t#if FPU_EN\n\t\tSCB-&gt;CPACR |= ((3UL &lt;&lt; 10*2)|(3UL &lt;&lt; 11*2));\n\t#endif\n\n\tclock_config();\n\tBSP_Ticks_Init(100000000);\n\n\tGPIO_Configure_Typedef I2C_PB8, I2C_PB9;\n\n\tGPIOB_CLOCK_ENABLE();\n\n\tI2C_PB8.PinNumber=8;\n\tI2C_PB8.OutputType=Open_Drain;\n\tI2C_PB8.Mode=Alternate_function;\n\tI2C_PB8.PullUp_PullDown=PullUp;\n\tI2C_PB8.AlternateType=AF4;\n\n\tI2C_PB9.PinNumber=9;\n\tI2C_PB9.OutputType=Open_Drain;\n\tI2C_PB9.Mode=Alternate_function;\n\tI2C_PB8.PullUp_PullDown=PullUp;\n\tI2C_PB9.AlternateType=AF4;\n\n\tGPIO_Initialization(GPIOB,&amp;I2C_PB8);\n\tGPIO_Initialization(GPIOB,&amp;I2C_PB9);\n\n\t__I2C1_CLOCK_ENABLE();\n\n\ti2c1Config.MasterMode=standardSpeed;\n\n\ti2c1Config.PeripheralFrequency=50;\n\n\ti2c1Config.RiseTime=9;\n\n\tBSP_I2C_Init(I2C1, &amp;i2c1Config);<\/pre><\/div>\n\n\n\n<p>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;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">\twhile(1)\n\t{\n\t\tBSP_I2C_Read_Memory(I2C1, 0x68, 0x3B, MPU9250_ACC_Data, 6, 200);\n\n\t}<\/pre><\/div>\n\n\n\n<p>Hence, the main 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;}\">#include &quot;bsp.h&quot;\n#include &quot;uart_bsp.h&quot;\n#include &quot;exti_bsp.h&quot;\n#include &quot;bsp_debug.h&quot;\n#include &quot;spi_bsp.h&quot;\n#include &quot;dma_bsp.h&quot;\n#include &quot;i2c_bsp.h&quot;\n#include &quot;stdlib.h&quot;\n\nvoid clock_config(void);\n\nI2C_ConfigTypedef i2c1Config;\n\nuint8_t MPU9250_ACC_Data[6];\n\n\nint main()\n{\n\n\n\t#if FPU_EN\n\t\tSCB-&gt;CPACR |= ((3UL &lt;&lt; 10*2)|(3UL &lt;&lt; 11*2));\n\t#endif\n\n\tclock_config();\n\tBSP_Ticks_Init(100000000);\n\n\tGPIO_Configure_Typedef I2C_PB8, I2C_PB9;\n\n\tGPIOB_CLOCK_ENABLE();\n\n\tI2C_PB8.PinNumber=8;\n\tI2C_PB8.OutputType=Open_Drain;\n\tI2C_PB8.Mode=Alternate_function;\n\tI2C_PB8.PullUp_PullDown=PullUp;\n\tI2C_PB8.AlternateType=AF4;\n\n\tI2C_PB9.PinNumber=9;\n\tI2C_PB9.OutputType=Open_Drain;\n\tI2C_PB9.Mode=Alternate_function;\n\tI2C_PB8.PullUp_PullDown=PullUp;\n\tI2C_PB9.AlternateType=AF4;\n\n\tGPIO_Initialization(GPIOB,&amp;I2C_PB8);\n\tGPIO_Initialization(GPIOB,&amp;I2C_PB9);\n\n\t__I2C1_CLOCK_ENABLE();\n\n\ti2c1Config.MasterMode=standardSpeed;\n\n\ti2c1Config.PeripheralFrequency=50;\n\n\ti2c1Config.RiseTime=9;\n\n\tBSP_I2C_Init(I2C1, &amp;i2c1Config);\n\n\n\n\n\twhile(1)\n\t{\n\t\tBSP_I2C_Read_Memory(I2C1, 0x68, 0x3B, MPU9250_ACC_Data, 6, 200);\n\n\t}\n}\n\nvoid clock_config(void)\n{\n\tClock_Config_Typedef clockConfig;\n\n\tclockConfig.PLL_M= 4;\n\tclockConfig.PLL_N= 200;\n\tclockConfig.PLL_P= 4;\n\n\tclockConfig.AHB1Prescaler=AHB1_Prescaler1;\n\tclockConfig.APB1Prescaler=APB1_Prescaler2;\n\tclockConfig.APB2Prescaler=APB2_Prescaler1;\n\n\tclockConfig.clockSourc=External_Oscillator;\n\tclockConfig.flash_latency= Three_wait_state;\n\n\tClock_Configuration(&amp;clockConfig);\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>Upload the code to your STM32 and connect MPU9250 and you should get the following:<\/p>\n\n\n\n<p><\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"600\" height=\"416\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/09\/ezgif-2-ee1a86ef39.gif\" alt=\"\" class=\"wp-image-1959\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Happy coding \ud83d\ude42<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the second section of the fourteenth part of I2C BSP, we shall develop functions that will communicate with slave devices to write\/read to\/from MPU9250. In this guide, we shall cover the following: Updating the header file. Updating the source file. Main code. Results. 1. Updating the header file: In i2c_bps.h header file, include the [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-1957","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/1957"}],"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=1957"}],"version-history":[{"count":1,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/1957\/revisions"}],"predecessor-version":[{"id":1960,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/1957\/revisions\/1960"}],"wp:attachment":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1957"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1957"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1957"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}