{"id":2182,"date":"2023-12-13T04:26:12","date_gmt":"2023-12-13T04:26:12","guid":{"rendered":"https:\/\/blog.embeddedexpert.io\/?p=2182"},"modified":"2023-12-13T04:26:51","modified_gmt":"2023-12-13T04:26:51","slug":"w25qxx-in-spi-with-external-loader-part-2-flash-source-code","status":"publish","type":"post","link":"https:\/\/blog.embeddedexpert.io\/?p=2182","title":{"rendered":"W25QXX in SPI with External Loader Part 2: Flash Source Code"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"443\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/external-loader-diagram-1-1024x443.png\" alt=\"\" class=\"wp-image-2183\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/external-loader-diagram-1-1024x443.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/external-loader-diagram-1-300x130.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/external-loader-diagram-1-768x332.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/external-loader-diagram-1-1536x664.png 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/external-loader-diagram-1-1150x497.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/external-loader-diagram-1-750x324.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/external-loader-diagram-1-400x173.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/external-loader-diagram-1-250x108.png 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/external-loader-diagram-1.png 1674w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>In part 1, we setup the environment and created the header file for the required functions and symbolic to be hold.<\/p>\n\n\n\n<p>In the second part of the external loader, we shall develop the source file for W25QXX.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">9. W25QXX Source file:<\/h2>\n\n\n\n<p>We start off by creating new source file with name of W25QXX.c.<\/p>\n\n\n\n<p>Within the source file, 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;W25QXX.h&quot;\n\n#include &quot;SPI1.h&quot;\n\n#include &quot;delay.h&quot;<\/pre><\/div>\n\n\n\n<p>Then declare the number of blocks (In W25Q32 is 64 blocks):<\/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;}\">#define NumberOfBlocks 64  \/\/ number of total blocks for 32Mb flash<\/pre><\/div>\n\n\n\n<p>Now, we declare a function that will read the status register and check if the write\/eras is still in progress:<\/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;}\">static void W25Q_Waitforwrite()\n{\n\tuint8_t tData = W25Q_READ_SR1;\n\tW25QXX_CS_LOW();\n\tSPI1_Transmit(&amp;tData, 1);\n\tdo\n\t{\n\t\tSPI1_Receive(&amp;tData, 1);  \/\/keep reading status register\n\t} while (tData &amp; 0x01);  \/\/ until the bit to reset\n\tW25QXX_CS_HIGH();\n}\n<\/pre><\/div>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"640\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/Screenshot-2023-12-13-at-7.04.58\u202fAM-1024x640.png\" alt=\"\" class=\"wp-image-2184\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/Screenshot-2023-12-13-at-7.04.58\u202fAM-1024x640.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/Screenshot-2023-12-13-at-7.04.58\u202fAM-300x187.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/Screenshot-2023-12-13-at-7.04.58\u202fAM-768x480.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/Screenshot-2023-12-13-at-7.04.58\u202fAM-1536x960.png 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/Screenshot-2023-12-13-at-7.04.58\u202fAM-2048x1280.png 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/Screenshot-2023-12-13-at-7.04.58\u202fAM-1150x719.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/Screenshot-2023-12-13-at-7.04.58\u202fAM-750x469.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/Screenshot-2023-12-13-at-7.04.58\u202fAM-400x250.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/Screenshot-2023-12-13-at-7.04.58\u202fAM-250x156.png 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"523\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/Screenshot-2023-12-13-at-7.04.00\u202fAM-1024x523.png\" alt=\"\" class=\"wp-image-2185\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/Screenshot-2023-12-13-at-7.04.00\u202fAM-1024x523.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/Screenshot-2023-12-13-at-7.04.00\u202fAM-300x153.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/Screenshot-2023-12-13-at-7.04.00\u202fAM-768x392.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/Screenshot-2023-12-13-at-7.04.00\u202fAM-1536x785.png 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/Screenshot-2023-12-13-at-7.04.00\u202fAM-2048x1046.png 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/Screenshot-2023-12-13-at-7.04.00\u202fAM-1150x588.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/Screenshot-2023-12-13-at-7.04.00\u202fAM-750x383.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/Screenshot-2023-12-13-at-7.04.00\u202fAM-400x204.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/Screenshot-2023-12-13-at-7.04.00\u202fAM-250x128.png 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>For write enable\/disable functions:<\/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;}\">static void write_enable (void)\n{\n\tuint8_t tData = W25Q_WRITE_ENABLE;  \/\/ enable write\n\tW25QXX_CS_LOW();\n\tSPI1_Transmit(&amp;tData, 1);\n\tW25QXX_CS_HIGH();\n\tdelay(5);  \/\/ 5ms delay\n}\n\nstatic void write_disable(void)\n{\n\tuint8_t tData = W25Q_WRITE_ENABLE;  \/\/ disable write\n\tW25QXX_CS_LOW();\n\tSPI1_Transmit(&amp;tData, 1);\n\tW25QXX_CS_HIGH();\n\tdelay(5);  \/\/ 5ms delay\n}\n<\/pre><\/div>\n\n\n\n<p>For more details about this, please refer to <a href=\"https:\/\/blog.embeddedexpert.io\/?p=2160\" data-type=\"URL\" data-id=\"https:\/\/blog.embeddedexpert.io\/?p=2160\" target=\"_blank\" rel=\"noreferrer noopener\">this guide.<\/a><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Bytes to write and modify functions:<\/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;}\">static uint32_t bytestowrite (uint32_t size, uint16_t offset)\n{\n\tif ((size+offset)&lt;256) return size;\n\telse return 256-offset;\n}\n\nstatic uint32_t bytestomodify (uint32_t size, uint16_t offset)\n{\n\tif ((size+offset)&lt;4096) return size;\n\telse return 4096-offset;\n}\n<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Flash reset and get the ID:<\/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 W25Q_Reset (void)\n{\n\tuint8_t tData[2];\n\ttData[0] = W25Q_ENABLE_RST;  \/\/ enable Reset\n\ttData[1] = W25Q_RESET;  \/\/ Reset\n\tW25QXX_CS_LOW();\n\tSPI1_Transmit(tData, 2);\n\tW25QXX_CS_HIGH();\n\tdelay(100);\n}\n\nuint32_t W25Q_ReadID (void)\n{\n\tuint8_t tData = 0x9F;  \/\/ Read JEDEC ID\n\tuint8_t rData[3];\n\tW25QXX_CS_LOW();\n\tSPI1_Transmit(&amp;tData, 1);\n\tSPI1_Receive(rData, 3);\n\tW25QXX_CS_HIGH();\n\treturn ((rData[0]&lt;&lt;16)|(rData[1]&lt;&lt;8)|rData[2]);\n}\n<\/pre><\/div>\n\n\n\n<p>For more details about these two functions, please refer to <a href=\"https:\/\/blog.embeddedexpert.io\/?p=2142\" data-type=\"URL\" data-id=\"https:\/\/blog.embeddedexpert.io\/?p=2142\" target=\"_blank\" rel=\"noreferrer noopener\">this guide<\/a>.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Chip erase functions:<\/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 W25Q_Chip_Erase (void)\n{\n\tuint8_t tData = W25Q_CHIP_ERASE;\n\n\twrite_enable();\n\n\tW25QXX_CS_LOW();\n\tSPI1_Transmit(&amp;tData, 1);\n\tW25QXX_CS_HIGH();\n\n\tW25Q_Waitforwrite();\n\n\twrite_disable();\n}<\/pre><\/div>\n\n\n\n<p>The following steps are required:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Enable write.<\/li><li>Send chip erase command.<\/li><li>Wait until the operation is completed.<\/li><li>Disable write.<\/li><\/ul>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"849\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/Screenshot-2023-12-13-at-7.14.23\u202fAM-1024x849.png\" alt=\"\" class=\"wp-image-2186\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/Screenshot-2023-12-13-at-7.14.23\u202fAM-1024x849.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/Screenshot-2023-12-13-at-7.14.23\u202fAM-300x249.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/Screenshot-2023-12-13-at-7.14.23\u202fAM-768x637.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/Screenshot-2023-12-13-at-7.14.23\u202fAM-1536x1273.png 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/Screenshot-2023-12-13-at-7.14.23\u202fAM-1150x953.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/Screenshot-2023-12-13-at-7.14.23\u202fAM-750x622.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/Screenshot-2023-12-13-at-7.14.23\u202fAM-400x332.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/Screenshot-2023-12-13-at-7.14.23\u202fAM-250x207.png 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/Screenshot-2023-12-13-at-7.14.23\u202fAM.png 1568w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>For read and fast read functions:<\/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 W25Q_Read (uint32_t startPage, uint8_t offset, uint32_t size, uint8_t *rData)\n{\n\tuint8_t tData[5];\n\tuint32_t memAddr = (startPage*256) + offset;\n\n\tif (NumberOfBlocks&lt;512)   \/\/ Chip Size&lt;256Mb\n\t{\n\t\ttData[0] = W25Q_READ_DATA;  \/\/ enable Read\n\t\ttData[1] = (memAddr&gt;&gt;16)&amp;0xFF;  \/\/ MSB of the memory Address\n\t\ttData[2] = (memAddr&gt;&gt;8)&amp;0xFF;\n\t\ttData[3] = (memAddr)&amp;0xFF; \/\/ LSB of the memory Address\n\t}\n\telse  \/\/ we use 32bit memory address for chips &gt;= 256Mb\n\t{\n\t\ttData[0] = W25Q_READ_DATA_4B;  \/\/ Read Data with 4-Byte Address\n\t\ttData[1] = (memAddr&gt;&gt;24)&amp;0xFF;  \/\/ MSB of the memory Address\n\t\ttData[2] = (memAddr&gt;&gt;16)&amp;0xFF;\n\t\ttData[3] = (memAddr&gt;&gt;8)&amp;0xFF;\n\t\ttData[4] = (memAddr)&amp;0xFF; \/\/ LSB of the memory Address\n\t}\n\n\tW25QXX_CS_LOW();  \/\/ pull the CS Low\n\tif (NumberOfBlocks&lt;512)\n\t{\n\t\tSPI1_Transmit(tData, 4);  \/\/ send read instruction along with the 24 bit memory address\n\t}\n\telse\n\t{\n\t\tSPI1_Transmit(tData, 5);  \/\/ send read instruction along with the 32 bit memory address\n\t}\n\n\tSPI1_Receive(rData, size);  \/\/ Read the data\n\tW25QXX_CS_HIGH();  \/\/ pull the CS High\n}\n\nvoid W25Q_FastRead (uint32_t startPage, uint8_t offset, uint32_t size, uint8_t *rData)\n{\n\tuint8_t tData[6];\n\tuint32_t memAddr = (startPage*256) + offset;\n\n\tif (NumberOfBlocks&lt;512)   \/\/ Chip Size&lt;256Mb\n\t{\n\t\ttData[0] = W25Q_FAST_READ;  \/\/ enable Fast Read\n\t\ttData[1] = (memAddr&gt;&gt;16)&amp;0xFF;  \/\/ MSB of the memory Address\n\t\ttData[2] = (memAddr&gt;&gt;8)&amp;0xFF;\n\t\ttData[3] = (memAddr)&amp;0xFF; \/\/ LSB of the memory Address\n\t\ttData[4] = 0;  \/\/ Dummy clock\n\t}\n\telse  \/\/ we use 32bit memory address for chips &gt;= 256Mb\n\t{\n\t\ttData[0] = W25Q_FAST_READ_4B;  \/\/ Fast Read with 4-Byte Address\n\t\ttData[1] = (memAddr&gt;&gt;24)&amp;0xFF;  \/\/ MSB of the memory Address\n\t\ttData[2] = (memAddr&gt;&gt;16)&amp;0xFF;\n\t\ttData[3] = (memAddr&gt;&gt;8)&amp;0xFF;\n\t\ttData[4] = (memAddr)&amp;0xFF; \/\/ LSB of the memory Address\n\t\ttData[5] = 0;  \/\/ Dummy clock\n\t}\n\n\tW25QXX_CS_LOW();  \/\/ pull the CS Low\n\tif (NumberOfBlocks&lt;512)\n\t{\n\t\tSPI1_Transmit(tData, 5);  \/\/ send read instruction along with the 24 bit memory address\n\t}\n\telse\n\t{\n\t\tSPI1_Transmit(tData, 6);  \/\/ send read instruction along with the 32 bit memory address\n\t}\n\n\tSPI1_Receive(rData, size);  \/\/ Read the data\n\tW25QXX_CS_HIGH();  \/\/ pull the CS High\n}\n\n\n<\/pre><\/div>\n\n\n\n<p>For more details, please refer to <a href=\"https:\/\/blog.embeddedexpert.io\/?p=2151\" data-type=\"URL\" data-id=\"https:\/\/blog.embeddedexpert.io\/?p=2151\" target=\"_blank\" rel=\"noreferrer noopener\">this guide<\/a>.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Sector erase:<\/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 W25Q_Erase_Sector (uint16_t numsector)\n{\n\tuint8_t tData[6];\n\tuint32_t memAddr = numsector*16*256;   \/\/ Each sector contains 16 pages * 256 bytes\n\n\twrite_enable();\n\n\tif (NumberOfBlocks&lt;512)   \/\/ Chip Size&lt;256Mb\n\t{\n\t\ttData[0] = W25Q_SECTOR_ERASE;  \/\/ Erase sector\n\t\ttData[1] = (memAddr&gt;&gt;16)&amp;0xFF;  \/\/ MSB of the memory Address\n\t\ttData[2] = (memAddr&gt;&gt;8)&amp;0xFF;\n\t\ttData[3] = (memAddr)&amp;0xFF; \/\/ LSB of the memory Address\n\n\t\tW25QXX_CS_LOW();\n\t\tSPI1_Transmit(tData, 4);\n\t\tW25QXX_CS_HIGH();\n\t}\n\telse  \/\/ we use 32bit memory address for chips &gt;= 256Mb\n\t{\n\t\ttData[0] = W25Q_SECTOR_ERASE_4B;  \/\/ ERASE Sector with 32bit address\n\t\ttData[1] = (memAddr&gt;&gt;24)&amp;0xFF;\n\t\ttData[2] = (memAddr&gt;&gt;16)&amp;0xFF;\n\t\ttData[3] = (memAddr&gt;&gt;8)&amp;0xFF;\n\t\ttData[4] = memAddr&amp;0xFF;\n\n\t\tW25QXX_CS_LOW();  \/\/ pull the CS LOW\n\t\tSPI1_Transmit(tData, 5);\n\t\tW25QXX_CS_HIGH();  \/\/ pull the HIGH\n\t}\n\n\tW25Q_Waitforwrite();\n\n\twrite_disable();\n\n}<\/pre><\/div>\n\n\n\n<p>Write clean:<\/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 W25Q_Write_Clean (uint32_t page, uint16_t offset, uint32_t size, uint8_t *data)\n{\n\tuint8_t tData[266];\n\tuint32_t startPage = page;\n\tuint32_t endPage  = startPage + ((size+offset-1)\/256);\n\tuint32_t numPages = endPage-startPage+1;\n\n\tuint16_t startSector  = startPage\/16;\n\tuint16_t endSector  = endPage\/16;\n\tuint16_t numSectors = endSector-startSector+1;\n\tfor (uint16_t i=0; i&lt;numSectors; i++)\n\t{\n\t\tW25Q_Erase_Sector(startSector++);\n\t}\n\n\tuint32_t dataPosition = 0;\n\n\t\/\/ write the data\n\tfor (uint32_t i=0; i&lt;numPages; i++)\n\t{\n\t\tuint32_t memAddr = (startPage*256)+offset;\n\t\tuint16_t bytesremaining  = bytestowrite(size, offset);\n\t\tuint32_t indx = 0;\n\n\t\twrite_enable();\n\n\t\tif (NumberOfBlocks&lt;512)   \/\/ Chip Size&lt;256Mb\n\t\t{\n\t\t\ttData[0] = W25Q_PAGE_PROGRAM;  \/\/ page program\n\t\t\ttData[1] = (memAddr&gt;&gt;16)&amp;0xFF;  \/\/ MSB of the memory Address\n\t\t\ttData[2] = (memAddr&gt;&gt;8)&amp;0xFF;\n\t\t\ttData[3] = (memAddr)&amp;0xFF; \/\/ LSB of the memory Address\n\n\t\t\tindx = 4;\n\t\t}\n\n\t\telse \/\/ we use 32bit memory address for chips &gt;= 256Mb\n\t\t{\n\t\t\ttData[0] = W25Q_PAGE_PROGRAM_4B;  \/\/ page program with 4-Byte Address\n\t\t\ttData[1] = (memAddr&gt;&gt;24)&amp;0xFF;  \/\/ MSB of the memory Address\n\t\t\ttData[2] = (memAddr&gt;&gt;16)&amp;0xFF;\n\t\t\ttData[3] = (memAddr&gt;&gt;8)&amp;0xFF;\n\t\t\ttData[4] = (memAddr)&amp;0xFF; \/\/ LSB of the memory Address\n\n\t\t\tindx = 5;\n\t\t}\n\n\t\tuint16_t bytestosend  = bytesremaining + indx;\n\n\t\tfor (uint16_t i=0; i&lt;bytesremaining; i++)\n\t\t{\n\t\t\ttData[indx++] = data[i+dataPosition];\n\t\t}\n\n\t\tif (bytestosend &gt; 250)\n\t\t{\n\t\t\tW25QXX_CS_LOW();\n\t\t\tSPI1_Transmit(tData, 100);\n\t\t\tSPI1_Transmit(tData+100, bytestosend-100);\n\t\t\tW25QXX_CS_HIGH();\n\n\t\t}\n\n\t\telse\n\t\t{\n\t\t\tW25QXX_CS_LOW();\n\t\t\tSPI1_Transmit(tData, bytestosend);\n\t\t\tW25QXX_CS_HIGH();\n\t\t}\n\n\n\t\tstartPage++;\n\t\toffset = 0;\n\t\tsize = size-bytesremaining;\n\t\tdataPosition = dataPosition+bytesremaining;\n\n\t\tW25Q_Waitforwrite();\n\t\twrite_disable();\n\n\t}\n}<\/pre><\/div>\n\n\n\n<p>This function will erase the sector and write the new data.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>For W25QXX write 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;}\">void W25Q_Write (uint32_t page, uint16_t offset, uint32_t size, uint8_t *data)\n{\n\tuint16_t startSector  = page\/16;\n\tuint16_t endSector  = (page + ((size+offset-1)\/256))\/16;\n\tuint16_t numSectors = endSector-startSector+1;\n\n\tuint8_t previousData[4096];\n\tuint32_t sectorOffset = ((page%16)*256)+offset;\n\tuint32_t dataindx = 0;\n\n\tfor (uint16_t i=0; i&lt;numSectors; i++)\n\t{\n\t\tuint32_t startPage = startSector*16;\n\t\tW25Q_FastRead(startPage, 0, 4096, previousData);\n\n\t\tuint16_t bytesRemaining = bytestomodify(size, sectorOffset);\n\t\tfor (uint16_t i=0; i&lt;bytesRemaining; i++)\n\t\t{\n\t\t\tpreviousData[i+sectorOffset] = data[i+dataindx];\n\t\t}\n\n\t\tW25Q_Write_Clean(startPage, 0, 4096, previousData);\n\n\t\tstartSector++;\n\t\tsectorOffset = 0;\n\t\tdataindx = dataindx+bytesRemaining;\n\t\tsize = size-bytesRemaining;\n\t}\n}<\/pre><\/div>\n\n\n\n<p>This function will store the current data of the sector, erase the sector, write back the modified sector data back to the sector since write to any location of the sector requires entire sector to be erased and written again.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>For read\/write byte:<\/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 W25Q_Read_Byte (uint32_t Addr)\n{\n\tuint8_t tData[5];\n\tuint8_t rData;\n\n\tif (NumberOfBlocks&lt;512)   \/\/ Chip Size&lt;256Mb\n\t{\n\t\ttData[0] = W25Q_READ_DATA;  \/\/ enable Read\n\t\ttData[1] = (Addr&gt;&gt;16)&amp;0xFF;  \/\/ MSB of the memory Address\n\t\ttData[2] = (Addr&gt;&gt;8)&amp;0xFF;\n\t\ttData[3] = (Addr)&amp;0xFF; \/\/ LSB of the memory Address\n\t}\n\telse  \/\/ we use 32bit memory address for chips &gt;= 256Mb\n\t{\n\t\ttData[0] = W25Q_READ_DATA_4B;  \/\/ Read Data with 4-Byte Address\n\t\ttData[1] = (Addr&gt;&gt;24)&amp;0xFF;  \/\/ MSB of the memory Address\n\t\ttData[2] = (Addr&gt;&gt;16)&amp;0xFF;\n\t\ttData[3] = (Addr&gt;&gt;8)&amp;0xFF;\n\t\ttData[4] = (Addr)&amp;0xFF; \/\/ LSB of the memory Address\n\t}\n\n\tW25QXX_CS_LOW();  \/\/ pull the CS Low\n\tif (NumberOfBlocks&lt;512)\n\t{\n\t\tSPI1_Transmit(tData, 4);  \/\/ send read instruction along with the 24 bit memory address\n\t}\n\telse\n\t{\n\t\tSPI1_Transmit(tData, 5);  \/\/ send read instruction along with the 32 bit memory address\n\t}\n\n\tSPI1_Receive(&amp;rData, 1);  \/\/ Read the data\n\tW25QXX_CS_HIGH();  \/\/ pull the CS High\n\n\treturn rData;\n}\n\nvoid W25Q_Write_Byte (uint32_t Addr, uint8_t data)\n{\n\tuint8_t tData[6];\n\tuint8_t indx;\n\n\tif (NumberOfBlocks&lt;512)   \/\/ Chip Size&lt;256Mb\n\t{\n\t\ttData[0] = W25Q_PAGE_PROGRAM;  \/\/ page program\n\t\ttData[1] = (Addr&gt;&gt;16)&amp;0xFF;  \/\/ MSB of the memory Address\n\t\ttData[2] = (Addr&gt;&gt;8)&amp;0xFF;\n\t\ttData[3] = (Addr)&amp;0xFF; \/\/ LSB of the memory Address\n\t\ttData[4] = data;\n\t\tindx = 5;\n\t}\n\telse  \/\/ we use 32bit memory address for chips &gt;= 256Mb\n\t{\n\t\ttData[0] = W25Q_PAGE_PROGRAM_4B;  \/\/ Write Data with 4-Byte Address\n\t\ttData[1] = (Addr&gt;&gt;24)&amp;0xFF;  \/\/ MSB of the memory Address\n\t\ttData[2] = (Addr&gt;&gt;16)&amp;0xFF;\n\t\ttData[3] = (Addr&gt;&gt;8)&amp;0xFF;\n\t\ttData[4] = (Addr)&amp;0xFF; \/\/ LSB of the memory Address\n\t\ttData[5] = data;\n\t\tindx = 6;\n\t}\n\n\n\tif (W25Q_Read_Byte(Addr) == 0xFF)\n\t{\n\t\twrite_enable();\n\t\tW25QXX_CS_LOW();\n\t\tSPI1_Transmit(tData, indx);\n\t\tW25QXX_CS_HIGH();\n\n\t\tW25Q_Waitforwrite();\n\t\twrite_disable();\n\t}\n}<\/pre><\/div>\n\n\n\n<p>The following functions will allow you store variable data of 32-bit and float to the flash (not need though):<\/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 tempBytes[4];\n\nvoid float2Bytes(uint8_t * ftoa_bytes_temp,float float_variable)\n{\n    union {\n      float a;\n      uint8_t bytes[4];\n    } thing;\n\n    thing.a = float_variable;\n\n    for (uint8_t i = 0; i &lt; 4; i++) {\n      ftoa_bytes_temp[i] = thing.bytes[i];\n    }\n\n}\n\nfloat Bytes2float(uint8_t * ftoa_bytes_temp)\n{\n    union {\n      float a;\n      uint8_t bytes[4];\n    } thing;\n\n    for (uint8_t i = 0; i &lt; 4; i++) {\n    \tthing.bytes[i] = ftoa_bytes_temp[i];\n    }\n\n   float float_variable =  thing.a;\n   return float_variable;\n}\n\nvoid W25Q_Write_NUM (uint32_t page, uint16_t offset, float data)\n{\n\tfloat2Bytes(tempBytes, data);\n\n\t\/* Write using sector update function *\/\n\tW25Q_Write(page, offset, 4, tempBytes);\n}\n\nfloat W25Q_Read_NUM (uint32_t page, uint16_t offset)\n{\n\tuint8_t rData[4];\n\tW25Q_Read(page, offset, 4, rData);\n\treturn (Bytes2float(rData));\n}\n\nvoid W25Q_Write_32B (uint32_t page, uint16_t offset, uint32_t size, uint32_t *data)\n{\n\tuint8_t data8[size*4];\n\tuint32_t indx = 0;\n\n\tfor (uint32_t i=0; i&lt;size; i++)\n\t{\n\t\tdata8[indx++] = data[i]&amp;0xFF;   \/\/ extract LSB\n\t\tdata8[indx++] = (data[i]&gt;&gt;8)&amp;0xFF;\n\t\tdata8[indx++] = (data[i]&gt;&gt;16)&amp;0xFF;\n\t\tdata8[indx++] = (data[i]&gt;&gt;24)&amp;0xFF;\n\t}\n\n\tW25Q_Write(page, offset, indx, data8);\n}\n\nvoid W25Q_Read_32B (uint32_t page, uint16_t offset, uint32_t size, uint32_t *data)\n{\n\tuint8_t data8[size*4];\n\tuint32_t indx = 0;\n\n\tW25Q_FastRead(page, offset, size*4, data8);\n\n\tfor (uint32_t i=0; i&lt;size; i++)\n\t{\n\t\tdata[i] = (data8[indx++]) | (data8[indx++]&lt;&lt;8) | (data8[indx++]&lt;&lt;16) | (data8[indx++]&lt;&lt;24);\n\t}\n}\n<\/pre><\/div>\n\n\n\n<p>The following functions are needed by the external loader:<\/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 flash_WriteMemory(uint8_t* buffer, uint32_t address, uint32_t buffer_size)\n{\n\tuint32_t page = address\/256;\n\tuint16_t offset = address%256;\n\tuint32_t size = buffer_size;\n\tuint8_t tData[266];\n\tuint32_t startPage = page;\n\tuint32_t endPage  = startPage + ((size+offset-1)\/256);\n\tuint32_t numPages = endPage-startPage+1;\n\n\tuint32_t dataPosition = 0;\n\n\t\/\/ write the data\n\tfor (uint32_t i=0; i&lt;numPages; i++)\n\t{\n\t\tuint32_t memAddr = (startPage*256)+offset;\n\t\tuint16_t bytesremaining  = bytestowrite(size, offset);\n\t\tuint32_t indx = 0;\n\n\t\twrite_enable();\n\n\t\tif (NumberOfBlocks&lt;512)   \/\/ Chip Size&lt;256Mb\n\t\t{\n\t\t\ttData[0] = W25Q_PAGE_PROGRAM;  \/\/ page program\n\t\t\ttData[1] = (memAddr&gt;&gt;16)&amp;0xFF;  \/\/ MSB of the memory Address\n\t\t\ttData[2] = (memAddr&gt;&gt;8)&amp;0xFF;\n\t\t\ttData[3] = (memAddr)&amp;0xFF; \/\/ LSB of the memory Address\n\n\t\t\tindx = 4;\n\t\t}\n\n\t\telse \/\/ we use 32bit memory address for chips &gt;= 256Mb\n\t\t{\n\t\t\ttData[0] = W25Q_PAGE_PROGRAM_4B;  \/\/ page program with 4-Byte Address\n\t\t\ttData[1] = (memAddr&gt;&gt;24)&amp;0xFF;  \/\/ MSB of the memory Address\n\t\t\ttData[2] = (memAddr&gt;&gt;16)&amp;0xFF;\n\t\t\ttData[3] = (memAddr&gt;&gt;8)&amp;0xFF;\n\t\t\ttData[4] = (memAddr)&amp;0xFF; \/\/ LSB of the memory Address\n\n\t\t\tindx = 5;\n\t\t}\n\n\t\tuint16_t bytestosend  = bytesremaining + indx;\n\n\t\tfor (uint16_t i=0; i&lt;bytesremaining; i++)\n\t\t{\n\t\t\ttData[indx++] = buffer[i+dataPosition];\n\t\t}\n\n\t\tif (bytestosend &gt; 250)\n\t\t{\n\t\t\tW25QXX_CS_LOW();\n\t\t\tSPI1_Transmit(tData, 100);\n\t\t\tSPI1_Transmit(tData+100, bytestosend-100);\n\t\t\tW25QXX_CS_HIGH();\n\n\t\t}\n\n\t\telse\n\t\t{\n\t\t\tW25QXX_CS_LOW();\n\t\t\tSPI1_Transmit(tData, bytestosend);\n\t\t\tW25QXX_CS_HIGH();\n\t\t}\n\n\n\t\tstartPage++;\n\t\toffset = 0;\n\t\tsize = size-bytesremaining;\n\t\tdataPosition = dataPosition+bytesremaining;\n\n\t\tW25Q_Waitforwrite();\n\t\twrite_disable();\n\n\t}\n\n}\n\nvoid flash_ReadMemory (uint32_t Addr, uint32_t Size, uint8_t* buffer)\n{\n\tuint32_t page = Addr\/256;\n\tuint16_t offset = Addr%256;\n\n\tW25Q_FastRead(page, offset, Size, buffer);\n}\n\nvoid flash_SectorErase(uint32_t EraseStartAddress, uint32_t EraseEndAddress)\n{\n\tuint16_t startSector  = EraseStartAddress\/4096;\n\tuint16_t endSector  = EraseEndAddress\/4096;\n\tuint16_t numSectors = endSector-startSector+1;\n\tfor (uint16_t i=0; i&lt;numSectors; i++)\n\t{\n\t\tW25Q_Erase_Sector(startSector++);\n\t}\n}\n\nvoid flash_ChipErase (void)\n{\n\tW25Q_Chip_Erase();\n}\n\nvoid flash_Reset (void)\n{\n\tW25Q_Reset();\n}\n\n<\/pre><\/div>\n\n\n\n<p>Next, we shall start developing the source code for the external loader and get the data into our chip.<\/p>\n\n\n\n<p>Stay tuned and happy coding \ud83d\ude42<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In part 1, we setup the environment and created the header file for the required functions and symbolic to be hold. In the second part of the external loader, we shall develop the source file for W25QXX. 9. W25QXX Source file: We start off by creating new source file with name of W25QXX.c. Within 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":[2,11,12],"tags":[],"class_list":["post-2182","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\/2182"}],"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=2182"}],"version-history":[{"count":2,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/2182\/revisions"}],"predecessor-version":[{"id":2188,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/2182\/revisions\/2188"}],"wp:attachment":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2182"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2182"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2182"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}