{"id":2176,"date":"2023-12-10T03:56:32","date_gmt":"2023-12-10T03:56:32","guid":{"rendered":"https:\/\/blog.embeddedexpert.io\/?p=2176"},"modified":"2023-12-10T03:56:35","modified_gmt":"2023-12-10T03:56:35","slug":"w25qxx-in-spi-with-external-loader-part-1-environment-setup","status":"publish","type":"post","link":"https:\/\/blog.embeddedexpert.io\/?p=2176","title":{"rendered":"W25QXX in SPI with External Loader Part 1 : Environment setup"},"content":{"rendered":"\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"443\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/external-loader-diagram-1024x443.png\" alt=\"\" class=\"wp-image-2177\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/external-loader-diagram-1024x443.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/external-loader-diagram-300x130.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/external-loader-diagram-768x332.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/external-loader-diagram-1536x664.png 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/external-loader-diagram-1150x497.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/external-loader-diagram-750x324.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/external-loader-diagram-400x173.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/external-loader-diagram-250x108.png 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/external-loader-diagram.png 1674w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>In this guide series, we shall see how to develop external loader with combination of W25QXX to extend the size of the internal storage and store large data for your application.<\/p>\n\n\n\n<p>In part 1, we shall cover the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Brief introduction to external loader.<\/li><li>Environment setup.<\/li><li>System initialization function.<\/li><li>Delay setup.<\/li><li>W25QXX connection with STM32F4xx<\/li><li>SPI setup.<\/li><li>W25QXX header file.<\/li><li>Project Setup download<\/li><\/ul>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">1. Brief introduction to external loader:<\/h2>\n\n\n\n<p>The STM32CubeProgrammer\u2019s External Loader is a feature that allows a direct access to external memories by STM32CubeProgrammer and even by the STM32CubeIDE to read, program, and erase data without the use of any additional tool other than a regular STLINK and even without ever changing the internal flash memory of the STM32. It is a feasible way to accelerate the debug cycle and the manufacturing program process on applications that use external memory.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">2. Environment Setup:<\/h2>\n\n\n\n<p>To setup the STM32CubeIDE for this guide series, take a look at <a href=\"https:\/\/blog.embeddedexpert.io\/?p=1255\" data-type=\"URL\" data-id=\"https:\/\/blog.embeddedexpert.io\/?p=1255\" target=\"_blank\" rel=\"noreferrer noopener\">this guide<\/a> for how to obtain the header file, correct project setup etc.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3. System Initialization function:<\/h2>\n\n\n\n<p>Create new source file and name it with sys_init.c:<\/p>\n\n\n\n<p>Within the source file, include the following header file:<\/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;stm32f4xx.h&quot;<\/pre><\/div>\n\n\n\n<p>Declare the following 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 SystemInit (void)<\/pre><\/div>\n\n\n\n<p>This function will be called once the MCU is started. Hence, no need to call it from main.<\/p>\n\n\n\n<p>Within the function:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Enable float point uint.<\/li><li>Enable cell compensation.<\/li><\/ul>\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 SystemInit (void)\n{\n\n\t\/*Enable float point hardware*\/\n\tSCB-&gt;CPACR |= ((3UL &lt;&lt; 10*2)|(3UL &lt;&lt; 11*2));\n\n\t\/*Enable cell compensation*\/\n\tRCC-&gt;APB2ENR|=RCC_APB2ENR_SYSCFGEN ;\n\tSYSCFG-&gt;CMPCR|=SYSCFG_CMPCR_CMP_PD;\n\twhile(!((SYSCFG-&gt;CMPCR)&amp;(SYSCFG_CMPCR_READY))){;}\n\n}\n<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">4. Delay Setup:<\/h2>\n\n\n\n<p>Create new source and header file with name of delay.c and delay.h respectively:<\/p>\n\n\n\n<p>Within the header file:<\/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 __delay__H__\n#define __delay__H__\n\n#include &quot;stdint.h&quot;\n\n\/*\n * @brief This function will initialize SysTick\n * to generate 1ms interrupt.\n * @param freq source frequency of SysTick.\n * @return nothing.\n * @see Generic ARM CortexM4 user guide.\n * *\/\n\nvoid delay_init(uint32_t freq);\n\n\/*\n * @brief This function will return the current millis.\n * \n * @param nothing.\n * @return current millis.\n * *\/\nuint64_t millis();\n\n\n\/*\n * @brief This function will spin lock the CPU to delay for the required\n * amount\n * @param time to be delayed in milliseconds.\n * @return nothing.\n * *\/\nvoid delay(uint32_t time);\n\n\n#endif\n<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Within the source 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;}\">#include &quot;delay.h&quot;\n#include &quot;stm32f4xx.h&quot;\n\n\n#define\tCTRL_ENABLE\t\t\t\t\t(1U&lt;&lt;0) \/*Enable SysTick Timer*\/\n#define CTRL_CLKSRC\t\t\t\t\t(1U&lt;&lt;2) \/*Clock source selection*\/\n#define CTRL_COUNTFLAG\t\t\t\t(1U&lt;&lt;16) \/*Count flag bit*\/\n#define CTRL_TICKINT\t\t\t\t(1U&lt;&lt;1) \/*Interrupt enable bit*\/\n\n\nvolatile uint64_t mil; \/*volatile variable to hold the ms counter*\/\n\nvoid delay_init(uint32_t freq)\n{\n\n\t\/*Set period to be 1ms*\/\n\tSysTick-&gt;LOAD  = (freq\/1000) - 1;\n\n\t\/*Clear systick current value register *\/\n\tSysTick-&gt;VAL = 0;\n\n\t\/*Enable systick and select internal clk src*\/\n\tSysTick-&gt;CTRL = CTRL_ENABLE | CTRL_CLKSRC ;\n\n\t\/*Enable systick interrupt*\/\n\tSysTick-&gt;CTRL  |= CTRL_TICKINT;\n\n}\n\n\n\nuint64_t millis()\n\t{\n\n\t__disable_irq(); \/*Disable global interrupt*\/\n\n\tuint64_t ml=mil; \/*Get the current millis values and store in ml*\/\n\n\t__enable_irq(); \/*Enable global interrupt*\/\n\n\treturn ml;\t\t\/*Return the stored value*\/\n\t}\n\n\n\/*Spin lock the CPU to delay*\/\nvoid delay(uint32_t time)\n{\n\n\tuint64_t start=millis();\n\twhile((millis() - start) &lt; (time+1));\n}\n\n\/*Interrupt handler of SysTick*\/\nvoid SysTick_Handler(void)\n{\n\t\/*Increment the counter with every interrupt*\/\n\tmil++;\n}\n<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">5. Connection of W25QXX with STM32F4xx:<\/h2>\n\n\n\n<p>The connection as following:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"897\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-25-at-8.29.36\u202fAM-1024x897.png\" alt=\"\" class=\"wp-image-2146\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-25-at-8.29.36\u202fAM-1024x897.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-25-at-8.29.36\u202fAM-300x263.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-25-at-8.29.36\u202fAM-768x673.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-25-at-8.29.36\u202fAM-1536x1345.png 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-25-at-8.29.36\u202fAM-1150x1007.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-25-at-8.29.36\u202fAM-750x657.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-25-at-8.29.36\u202fAM-400x350.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-25-at-8.29.36\u202fAM-250x219.png 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-25-at-8.29.36\u202fAM.png 1754w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-table is-style-stripes\"><table><tbody><tr><td>STM32F411-Nucleo64<\/td><td>W25QXX<\/td><\/tr><tr><td>3V3<\/td><td>Vcc<\/td><\/tr><tr><td>GND<\/td><td>GND<\/td><\/tr><tr><td>PA0<\/td><td>CS<\/td><\/tr><tr><td>PA5<\/td><td>CLK<\/td><\/tr><tr><td>PA6<\/td><td>DO<\/td><\/tr><tr><td>PA7<\/td><td>DI<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">6. SPI setup:<\/h2>\n\n\n\n<p>Create new source and header file with name of SPI1.c and SPI1.h respectively.<\/p>\n\n\n\n<p>Within the header file:<\/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 SPI1_H_\n#define SPI1_H_\n\n#include &quot;stdint.h&quot;\n\n\n\/*\n * @brief This function will initialize SPI1 related pins.\n * @return nothing.\n * @see Pinout of datasheet for SPI pins.\n * *\/\nvoid SPI1_Pins_Init(void);\n\n\n\/*\n * @brief This function will initialize CS pin .\n * @return nothing.\n * *\/\nvoid W25QXX_CS_Pins_Init(void);\n\n\/*\n * @brief This function will initialize SPI1\n * and configure it.\n * @return nothing.\n * @see reference manual SPI section.\n * *\/\nvoid SPI1_Config(void);\n\n\/*\n * @brief This function will transmit data over SPI bus.\n * @param *data pointer to the data to be written.\n * @param size  size of the data to be written.\n * @return nothing.\n * *\/\nvoid SPI1_Transmit(uint8_t *data,uint32_t size);\n\n\/*\n * @brief This function will read data from SPI bus.\n * @param *data pointer to the data to be read.\n * @param size  size of the data to be read.\n * @return nothing.\n * *\/\nvoid SPI1_Receive(uint8_t *data,uint32_t size);\n\n\/*\n * @brief This function will set CS pin to Low .\n * @return nothing.\n * *\/\nvoid W25QXX_CS_LOW(void);\n\n\/*\n * @brief This function will set CS pin to High.\n * @return nothing.\n * *\/\nvoid W25QXX_CS_HIGH(void);\n\n#endif \/* SPI1_H_ *\/<\/pre><\/div>\n\n\n\n<p>For the source file:<\/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 &lt;SPI1.h&gt;\n#include &quot;stm32f4xx.h&quot;\n\n\nvoid SPI1_Pins_Init(void)\n{\n\tRCC-&gt;AHB1ENR|=RCC_AHB1ENR_GPIOAEN; \/\/enable clock for GPIOA\n\tGPIOA-&gt;MODER|=GPIO_MODER_MODE5_1|GPIO_MODER_MODE6_1|GPIO_MODER_MODE7_1; \/\/set PA5, PA6 and PA7 to alternate function mode\n\tGPIOA-&gt;MODER &amp;=~(GPIO_MODER_MODE5_0|GPIO_MODER_MODE6_0|GPIO_MODER_MODE7_0);\n\n\tGPIOA-&gt;OSPEEDR|=GPIO_OSPEEDER_OSPEEDR5|GPIO_OSPEEDER_OSPEEDR6|GPIO_OSPEEDER_OSPEEDR7;\n\n\tGPIOA-&gt;AFR[0]|=(0x05&lt;&lt;20)|(0x05&lt;&lt;24)|(0x05&lt;&lt;28);\n}\n\n\nvoid W25QXX_CS_Pins_Init(void)\n{\n\tRCC-&gt;AHB1ENR|=RCC_AHB1ENR_GPIOAEN; \/\/enable clock for GPIOA\n\t\/*Set PA0 as output*\/\n\tGPIOA-&gt;MODER|=GPIO_MODER_MODE0_0;\n\tGPIOA-&gt;MODER&amp;=~GPIO_MODER_MODE0_1;\n\n\t\/*Set pin high as initial state*\/\n\tGPIOA-&gt;BSRR =GPIO_BSRR_BS0;\n}\n\n\nvoid SPI1_Config(void)\n{\n\t\/*Enable clock access to SPI1 module*\/\n\tRCC-&gt;APB2ENR |= RCC_APB2ENR_SPI1EN;\n\n\t\/*Set clock to fPCLK\/2*\/\n\tSPI1-&gt;CR1 &amp;=~SPI_CR1_BR_0;\n\tSPI1-&gt;CR1 &amp;=~SPI_CR1_BR_1;\n\tSPI1-&gt;CR1 &amp;=~SPI_CR1_BR_2;\n\n\t\/*Set CPOL to 0 and CPHA to 0 (MODE0)*\/\n\tSPI1-&gt;CR1 &amp;=~(SPI_CR1_CPOL);\n\tSPI1-&gt;CR1 &amp;=~(SPI_CR1_CPHA);\n\n\t\/*Enable full duplex*\/\n\tSPI1-&gt;CR1 &amp;=~(SPI_CR1_RXONLY);\n\n\t\/*Set MSB first*\/\n\tSPI1-&gt;CR1 &amp;= ~(SPI_CR1_LSBFIRST);\n\n\t\/*Set mode to MASTER*\/\n\tSPI1-&gt;CR1 |= (SPI_CR1_MSTR);\n\n\t\/*Set 8 bit data mode*\/\n\tSPI1-&gt;CR1 &amp;= ~(SPI_CR1_DFF);\n\n\t\/*Select software slave management by\n\t* setting SSM=1 and SSI=1*\/\n\tSPI1-&gt;CR1 |= (SPI_CR1_SSM);\n\tSPI1-&gt;CR1 |= (SPI_CR1_SSI);\n\n\t\/*Enable SPI module*\/\n\tSPI1-&gt;CR1 |= (SPI_CR1_SPE);\n}\n\nvoid SPI1_Transmit(uint8_t *data,uint32_t size)\n{\n\tuint32_t i=0;\n\n\twhile(i&lt;size)\n\t{\n\t\t\/*Wait until TXE is set*\/\n\t\twhile(!(SPI1-&gt;SR &amp; (SPI_SR_TXE))){}\n\n\t\t\/*Write the data to the data register*\/\n\t\tSPI1-&gt;DR = data[i];\n\t\ti++;\n\t}\n\t\/*Wait until TXE is set*\/\n\twhile(!(SPI1-&gt;SR &amp; (SPI_SR_TXE))){}\n\n\t\/*Wait for BUSY flag to reset*\/\n\twhile((SPI1-&gt;SR &amp; (SPI_SR_BSY))){}\n\n\t\/*Clear OVR flag*\/\n\t(void)SPI1-&gt;DR;\n\t(void)SPI1-&gt;SR;\n}\n\nvoid SPI1_Receive(uint8_t *data,uint32_t size)\n{\n\twhile(size)\n\t{\n\t\t\/*Send dummy data*\/\n\t\tSPI1-&gt;DR =0;\n\n\t\t\/*Wait for RXNE flag to be set*\/\n\t\twhile(!(SPI1-&gt;SR &amp; (SPI_SR_RXNE))){}\n\n\t\t\/*Read data from data register*\/\n\t\t*data++ = (SPI1-&gt;DR);\n\t\tsize--;\n\t}\n}\n\n\n\nvoid W25QXX_CS_LOW(void)\n{\n\tGPIOA-&gt;BSRR =GPIO_BSRR_BR0;\n\n}\n\n\/*Pull high to disable*\/\nvoid W25QXX_CS_HIGH(void)\n{\n\tGPIOA-&gt;BSRR =GPIO_BSRR_BS0;\n}\n<\/pre><\/div>\n\n\n\n<p>For more information, please refer to the following <a href=\"https:\/\/blog.embeddedexpert.io\/?p=2142\" data-type=\"URL\" data-id=\"https:\/\/blog.embeddedexpert.io\/?p=2142\" target=\"_blank\" rel=\"noreferrer noopener\">guide<\/a>.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">7. W25QXX header file.<\/h2>\n\n\n\n<p>Since the functions needed for the external loader need to be in specific format, we shall use the following format as shown in the header file:<\/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 W25QXX_H_\n#define W25QXX_H_\n\n#define MEMORY_FLASH_SIZE\t\t\t\t0x400000 \/* 32Mbit =&gt;4Mbyte *\/\n#define MEMORY_BLOCK_SIZE\t\t\t\t0x10000   \/*  blocks of 64KBytes *\/\n#define MEMORY_SECTOR_SIZE\t\t\t\t0x1000    \/* 4kBytes *\/\n#define MEMORY_PAGE_SIZE\t\t\t\t0x100     \/* 256 bytes *\/\n\n#define W25Q_WRITE_ENABLE 0x06\n#define W25Q_WRITE_DISABLE 0x04\n\n#define W25Q_READ_SR1 0x05\n#define W25Q_READ_SR2 0x35\n#define W25Q_READ_SR3 0x15\n#define W25Q_WRITE_SR1 0x01\n#define W25Q_WRITE_SR2 0x31\n#define W25Q_WRITE_SR3 0x11\n\n#define W25Q_READ_DATA 0x03\n#define W25Q_READ_DATA_4B 0x13\n#define W25Q_FAST_READ 0x0B\n#define W25Q_FAST_READ_4B 0x0C\n\n#define W25Q_PAGE_PROGRAM 0x02\n#define W25Q_PAGE_PROGRAM_4B 0x12\n\n#define W25Q_SECTOR_ERASE 0x20\n#define W25Q_SECTOR_ERASE_4B 0x21\n#define W25Q_32KB_BLOCK_ERASE 0x52\n#define W25Q_64KB_BLOCK_ERASE 0xD8\n#define W25Q_64KB_BLOCK_ERASE_4B 0xDC\n#define W25Q_CHIP_ERASE 0xC7\n\n#define W25Q_ENABLE_RST 0x66\n#define W25Q_RESET 0x99\n\nvoid W25Q_Reset (void);\nvoid W25Q_Chip_Erase (void);\nuint32_t W25Q_ReadID (void);\n\nvoid W25Q_Read (uint32_t startPage, uint8_t offset, uint32_t size, uint8_t *rData);\nvoid W25Q_FastRead (uint32_t startPage, uint8_t offset, uint32_t size, uint8_t *rData);\n\nvoid W25Q_Erase_Sector (uint16_t numsector);\n\nvoid W25Q_Write_Clean(uint32_t page, uint16_t offset, uint32_t size, uint8_t *data);\nvoid W25Q_Write (uint32_t page, uint16_t offset, uint32_t size, uint8_t *data);\n\nvoid W25Q_Write_Byte (uint32_t Addr, uint8_t data);\nuint8_t W25Q_Read_Byte (uint32_t Addr);\n\nfloat W25Q_Read_NUM (uint32_t page, uint16_t offset);\nvoid W25Q_Write_NUM (uint32_t page, uint16_t offset, float data);\n\nvoid W25Q_Read_32B (uint32_t page, uint16_t offset, uint32_t size, uint32_t *data);\nvoid W25Q_Write_32B (uint32_t page, uint16_t offset, uint32_t size, uint32_t *data);\n\n\nvoid flash_WriteMemory(uint8_t* buffer, uint32_t address, uint32_t buffer_size);\nvoid flash_ReadMemory (uint32_t Addr, uint32_t Size, uint8_t* buffer);\nvoid flash_SectorErase(uint32_t EraseStartAddress, uint32_t EraseEndAddress);\nvoid flash_ChipErase (void);\nvoid flash_Reset (void);\n\n#endif \/* W25QXX_H_ *\/\n<\/pre><\/div>\n\n\n\n<p>In part 2, we shall fill the source file of W25QXX.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">8. Project setup download:<\/h2>\n\n\n\n<div class=\"wp-block-file\"><a href=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/ExternalLoader_F411RE.zip\">ExternalLoader_F411RE<\/a><a href=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/12\/ExternalLoader_F411RE.zip\" class=\"wp-block-file__button\" download>Download<\/a><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Stay tuned and happy coding \ud83d\ude42<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this guide series, we shall see how to develop external loader with combination of W25QXX to extend the size of the internal storage and store large data for your application. In part 1, we shall cover the following: Brief introduction to external loader. Environment setup. System initialization function. Delay setup. W25QXX connection with STM32F4xx [&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-2176","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\/2176"}],"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=2176"}],"version-history":[{"count":2,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/2176\/revisions"}],"predecessor-version":[{"id":2180,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/2176\/revisions\/2180"}],"wp:attachment":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2176"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2176"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2176"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}