{"id":1568,"date":"2023-09-07T16:02:18","date_gmt":"2023-09-07T23:02:18","guid":{"rendered":"http:\/\/visualgdb.com\/w\/?p=1568"},"modified":"2023-09-08T10:32:32","modified_gmt":"2023-09-08T17:32:32","slug":"adding-external-memories-to-embedded-projects","status":"publish","type":"post","link":"https:\/\/visualgdb.com\/tutorials\/arm\/memories\/","title":{"rendered":"Adding External Memories to Embedded Projects"},"content":{"rendered":"<p>This tutorial shows how to add support for an external off-chip memory, such as a NOR FLASH to a VisualGDB Embedded Project, place some code and data into it and configure VisualGDB to program it automatically. In this example we will use the QSPI memory on the STM32F7-Discovery board. We will map it to the microcontroller&#8217;s address space and show how to offload some code and data there to reduce the utilization of the on-chip FLASH memory.<\/p>\n<p>Before you begin, install Visual Studio and VisualGDB.<\/p>\n<ol>\n<li>Start Visual Studio and open the VisualGDB Embedded Project Wizard:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/01-embwiz.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8320\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/01-embwiz.png\" alt=\"\" width=\"890\" height=\"625\" \/><\/a><\/li>\n<li>Enter the name and location for your project:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/02-prjname.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8321\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/02-prjname.png\" alt=\"\" width=\"890\" height=\"625\" \/><\/a><\/li>\n<li>Proceed with the default &#8220;Embedded Binary&#8221; setting, but uncheck the &#8220;bin&#8221; checkbox, as trying to fit the contents of memories located far from each other would result in a very big binary file:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/03-app-1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8323\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/03-app-1.png\" alt=\"\" width=\"886\" height=\"693\" \/><\/a><\/li>\n<li>Select your device from the list. In this example we will use the STM32F746NG microcontroller that is installed on the STM32F7-Discovery board:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/04-device-1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8324\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/04-device-1.png\" alt=\"\" width=\"886\" height=\"693\" \/><\/a><\/li>\n<li>Select the &#8220;LEDBlink (HAL)&#8221; sample and select the LED group and port that corresponds to your board layout. For STM32F7-Discovery we select GPIO1 and port 1:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/05-blink.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8325\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/05-blink.png\" alt=\"\" width=\"886\" height=\"693\" \/><\/a><\/li>\n<li>Select the debugging method that works with your device. For most of the devices we recommend using OpenOCD. Connect your board (and external programmer if any) and allow VisualGDB to detect it. You can use the &#8220;Test&#8221; button to verify the connection: <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/06-debug-1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8326\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/06-debug-1.png\" alt=\"\" width=\"886\" height=\"693\" \/><\/a><\/li>\n<li>Click &#8220;Finish&#8221; to generate the basic project. Then add the QSPI FLASH driver file (<a href=\"https:\/\/github.com\/sysprogs\/flash_drivers\/blob\/master\/DemoProjects\/STM32F7Disco-QSPI\/QSPIRoutines.cpp\">QSPIRoutines.cpp<\/a>) to your project:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/07-routines.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8327\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/07-routines.png\" alt=\"\" width=\"1030\" height=\"691\" \/><\/a><\/li>\n<li>The <strong>QSPIRoutines.cpp<\/strong> file contains QSPI FLASH setup functions copied from the ST&#8217;s <strong>QSPI_ExecuteInPlace<\/strong> example. If you are using a different board, you may need to adjust those functions. You can use the VisualGDB&#8217;s Code Jumps popups to get a quick overview of the QSPI-related functions and relations between them:\n<ul>\n<li><strong>QSPI_EnableMemoryMappedMode()<\/strong> is the main function that maps the QSPI FLASH to address 0x90000000<\/li>\n<li>Functions like <strong>QSPI_DummyCyclesCfg()<\/strong> and <strong>QSPI_WriteEnable()<\/strong> configure the external FLASH memory chip by writing chip-specific commands<\/li>\n<li>Functions like <strong>HAP_QSPI_Transmit()<\/strong> are provided by the STM32 HAL library and are responsible for delivering the commands to the chip<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/08-calls.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8328\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/08-calls.png\" alt=\"\" width=\"1030\" height=\"691\" \/><\/a><\/li>\n<\/ul>\n<\/li>\n<li>Move the code responsible for the blinking LED to a function called FunctionInQSPIFLASH() and edit the main source file to call the <strong>QSPI_EnableMemoryMappedMode()<\/strong> function before calling the LED blinking function:\n<pre class=\"\">QSPI_HandleTypeDef QSPIHandle;\r\n\r\nint main(void)\r\n{\r\n    HAL_Init();\r\n  \u00a0 QSPI_EnableMemoryMappedMode(&amp;QSPIHandle, 0, 0x10000);\r\n    FunctionInQSPIFLASH();\r\n}<\/pre>\n<p><a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/10-mem.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8329\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/10-mem.png\" alt=\"\" width=\"1030\" height=\"691\" \/><\/a>Note that we have <strong>NOT<\/strong> placed the function to the QSPI FLASH yet, so the function will reside in normal FLASH memory. Build the project and note how the FunctionInQSPIFLASH got placed in the regular <strong>0x0800xxxx<\/strong> range.<\/li>\n<li>Set a breakpoint at the call to <strong>FunctionInQSPIFLASH()<\/strong> and hit F5 to start debugging. Once the breakpoint is hit verify that the address of <strong>FunctionInQSPIFLASH<\/strong> is still inside the main FLASH area (0x08xxxxxx) and that the memory at address 0x90000000 is readable (it should show contents of the actual QSPI FLASH memory programmed by any previous QSPI-based program that ran on the board):<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/mems-1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8331\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/mems-1.png\" alt=\"\" width=\"1121\" height=\"742\" \/><\/a><\/li>\n<li>Now we will actually configure the project to use the QSPI memory. Open VisualGDB Project Properties and go to the Additional Memories page. Add a new memory called QSPI at address 0x90000000. In this example we will limit the memory size to 64K (0x10000), however you can specify the actual QSPI FLASH chip size as well:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/11-external.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8333\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/11-external.png\" alt=\"\" width=\"1020\" height=\"597\" \/><\/a>Note that the &#8220;Additional Memories&#8221; feature is supported on VisualGDB Custom Edition and higher.<\/li>\n<li>Press OK to apply the settings. Note how VisualGDB has created a copy of the linker script file and inserted the memory definition lines there. When you edit the external memory settings, VisualGDB will replace the lines between &#8220;&#8212; begin generated xxx &#8212;&#8221; and &#8220;&#8212; end generated xxx &#8211;&#8221; lines, preserving the rest of the linker script:\u00a0 \u00a0 <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/12-lds.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8334\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/12-lds.png\" alt=\"\" width=\"1030\" height=\"691\" \/><\/a><\/li>\n<li>VisualGDB as also added an <strong>ExtraMemories.h<\/strong> file that defines macros for placing your functions and variables to the external memories: <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/13-extramem.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8332\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/13-extramem.png\" alt=\"\" width=\"1030\" height=\"691\" \/><\/a><\/li>\n<li>Include the &#8220;ExtraMemories.h&#8221; file from your main file and add the QSPI_TEXT macro to the declaration of FunctionInQSPIFLASH(). Then build your project:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/14-qspi.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8335\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/14-qspi.png\" alt=\"\" width=\"1030\" height=\"691\" \/><\/a>Note how the used FLASH size has reduced and the <strong>FunctionInQSPIFLASH<\/strong> got moved to a new memory called <strong>QSPI<\/strong>.<\/li>\n<li>If you try to start debugging your project now, you will see that although the main FLASH memory expects the FunctionInQSPIFLASH() to be at address 0x90000000, the actual data at this address is different. This happens because OpenOCD does not know how to program the QSPI FLASH. This can be fixed by <a href=\"https:\/\/github.com\/sysprogs\/flash_drivers\/blob\/master\/stm32f7disco_qspi.elf\">downloading<\/a> the QSPI FLASH plugin for OpenOCD, or building it as described in <a href=\"http:\/\/visualgdb.com\/tutorials\/arm\/stm32\/flash\/\">this tutorial<\/a> and adding the following command to the OpenOCD command line:\n<pre class=\"\">-c \"flash bank qspi plugin 0x90000000 0 0 0 0 $(ProjectDir.forwardslashes)\/stm32f7disco_qspi.elf\"<\/pre>\n<p><a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/15-cmd-1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8337\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/15-cmd-1.png\" alt=\"\" width=\"1211\" height=\"695\" \/><\/a><\/li>\n<li>Now you can simply press F5 to automatically program the chip and begin debugging it. As of September 2023, OpenOCD now properly supports setting hardware breakpoints in QSPI memories, so you can set a breakpoint in <strong>FunctionInQSPIFLASH()<\/strong> and wait for it to hit:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/16-pc.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8338\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/16-pc.png\" alt=\"\" width=\"1030\" height=\"744\" \/><\/a><\/li>\n<li>Now we will show how to place a pre-initialized array into the QSPI FLASH memory without increasing the utilization of the normal FLASH. Declare a static const array with the <strong>QSPI_DATA<\/strong> macro and change <strong>FunctionInQSPIFLASH()<\/strong> to use it:\n<pre class=\"\">static const int QSPI_DATA LargeArray[] = { 100, 200, 300, 400, 500, 600 };<\/pre>\n<p><a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/qspidelta.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8339\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/qspidelta.png\" alt=\"\" width=\"1121\" height=\"742\" \/><\/a>Build your program and observe how the QSPI utilization has increased while the FLASH and RAM utilizations were unchanged.<\/li>\n<li>You can launch debugging with F5 (don&#8217;t forget to re-program the QSPI memory using the ST-Link tool unless you have automated this using the OpenOCD plugin) and see that <strong>LargeArray<\/strong> got placed to QSPI FLASH after the <strong>FunctionInQSPIFLASH<\/strong>:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/17-data.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8340\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/17-data.png\" alt=\"\" width=\"1121\" height=\"742\" \/><\/a><\/li>\n<li>If you are using VisualGDB Custom Edition 6.0 or later, you can set tracepoints instead of breakpoints to quickly record what the program is doing without actually stopping it. Try enabling software tracing as shown <a href=\"https:\/\/visualgdb.com\/tutorials\/tracing\/embedded\/\">here<\/a> and setting a tracepoints on the calls to <strong>HAL_Delay()<\/strong> tracing the values of <strong>TickCount<\/strong> and <strong>i<\/strong>. If you run the program now, you will immediately see how these lines get executed in real time:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/18-trace.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8341\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/18-trace.png\" alt=\"\" width=\"1121\" height=\"742\" \/><\/a><\/li>\n<li>You can use the tracepoints\/trace data windows to review each recorded invocation of the <strong>HAL_Delay()<\/strong> line, or create a trace data view to quickly visualize how the variable values changed over time:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/19-graph.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8343\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/03\/19-graph.png\" alt=\"\" width=\"1241\" height=\"980\" \/><\/a><\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>This tutorial shows how to add support for an external off-chip memory, such as a NOR FLASH to a VisualGDB<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[27],"tags":[53,120,61],"_links":{"self":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts\/1568"}],"collection":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/comments?post=1568"}],"version-history":[{"count":7,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts\/1568\/revisions"}],"predecessor-version":[{"id":8344,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts\/1568\/revisions\/8344"}],"wp:attachment":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/media?parent=1568"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/categories?post=1568"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/tags?post=1568"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}