{"id":3915,"date":"2018-04-30T13:02:00","date_gmt":"2018-04-30T20:02:00","guid":{"rendered":"https:\/\/visualgdb.com\/w\/?p=3915"},"modified":"2025-09-09T19:29:34","modified_gmt":"2025-09-10T02:29:34","slug":"developing-cc-firmware-for-the-esp32-wrover-module","status":"publish","type":"post","link":"https:\/\/visualgdb.com\/tutorials\/esp32\/wrover\/","title":{"rendered":"Developing C\/C++ Firmware for the ESP32 WROVER Module"},"content":{"rendered":"<p>This tutorial shows how to create a basic project for the ESP32\u00a0WROVER-KIT-3 module,\u00a0program the FLASH memory\u00a0and debug it via the on-board JTAG. We will create a basic project\u00a0that will blink\u00a0the red, green and blue on-board LEDs from different FreeRTOS threads and will show how to debug it and change various configuration-related\u00a0settings.<\/p>\n<p>Before you begin, install VisualGDB 5.4 or later.<\/p>\n<ol>\n<li>Start Visual Studio and open the\u00a0ESP-IDF\u00a0project wizard:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/01-newprj.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3916\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/01-newprj.png\" alt=\"01-newprj\" width=\"941\" height=\"653\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/01-newprj.png 941w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/01-newprj-300x208.png 300w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/01-newprj-392x272.png 392w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/01-newprj-130x90.png 130w\" sizes=\"(max-width: 941px) 100vw, 941px\" \/><\/a><\/li>\n<li>Select &#8220;Create a new project based on a sample project&#8221;:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/02-newsample.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3917\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/02-newsample.png\" alt=\"02-newsample\" width=\"856\" height=\"693\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/02-newsample.png 856w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/02-newsample-300x243.png 300w\" sizes=\"(max-width: 856px) 100vw, 856px\" \/><\/a><\/li>\n<li>On the next page select\u00a0the location of your ESP32 toolchain. If you don&#8217;t have any toolchains installed yet, click &#8220;Download more toolchains&#8221; and VisualGDB will automatically install a compatible ESP32 toolchain:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/03-toolchain1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3918\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/03-toolchain1.png\" alt=\"03-toolchain\" width=\"856\" height=\"693\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/03-toolchain1.png 856w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/03-toolchain1-300x243.png 300w\" sizes=\"(max-width: 856px) 100vw, 856px\" \/><\/a><strong>Update:<\/strong> For better compatibility with the latest ESP32 tools, we recommend selecting the <a href=\"https:\/\/visualgdb.com\/documentation\/espidf\/consolidated\/\">consolidated toolchain<\/a> instead.<\/li>\n<li>The next step is to select the sample project that will be used as a template for our project. Pick the &#8220;Blink&#8221; project from the &#8220;get-started&#8221; folder and click &#8220;next&#8221;:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/04-blink.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3919\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/04-blink.png\" alt=\"04-blink\" width=\"856\" height=\"693\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/04-blink.png 856w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/04-blink-300x243.png 300w\" sizes=\"(max-width: 856px) 100vw, 856px\" \/><\/a><\/li>\n<li>In order to\u00a0enable the on-board JTAG debugging functionality, install the 7 jumpers (may not included with the board) as shown below:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/wroverconn.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3928\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/wroverconn.jpg\" alt=\"wroverconn\" width=\"1625\" height=\"1195\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/wroverconn.jpg 1625w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/wroverconn-300x221.jpg 300w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/wroverconn-1024x753.jpg 1024w\" sizes=\"(max-width: 1625px) 100vw, 1625px\" \/><\/a><strong>WARNING: the picture above shows the previous version of the ESP-WROVER board. If you are using ESP-WROVER v4.1 or later, see <a href=\"https:\/\/docs.espressif.com\/projects\/esp-idf\/en\/latest\/get-started\/get-started-wrover-kit.html#setup-options\">this page<\/a> for the exact names and locations of the jumpers<\/strong>. Once the jumpers are installed, connect the board via USB.<\/li>\n<li>VisualGDB should\u00a0automatically recognize the board as long as you are using the latest ESP32 toolchain:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/05-devkit.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3920\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/05-devkit.png\" alt=\"05-devkit\" width=\"856\" height=\"693\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/05-devkit.png 856w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/05-devkit-300x243.png 300w\" sizes=\"(max-width: 856px) 100vw, 856px\" \/><\/a><\/li>\n<li>Click &#8220;Test&#8221; to automatically test the JTAG connection. VisualGDB will automatically install all necessary drivers and will use the correct JTAG settings:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/06-test.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3921\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/06-test.png\" alt=\"06-test\" width=\"786\" height=\"593\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/06-test.png 786w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/06-test-300x226.png 300w\" sizes=\"(max-width: 786px) 100vw, 786px\" \/><\/a>Finally Press &#8220;Finish&#8221; to create the project.<\/li>\n<li>By default, the &#8220;ledblink&#8221; project will\u00a0toggle the GPIO #5\u00a0that is not connected to any on-board LEDs.\u00a0To change this, we will first need to look up the GPIO numbers for the RGB LED from the <a href=\"https:\/\/dl.espressif.com\/dl\/schematics\/ESP-WROVER-KIT_SCH-3.pdf\">ESP-WROVER-KIT schematic<\/a>:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/rgb.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3929\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/rgb.png\" alt=\"rgb\" width=\"537\" height=\"300\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/rgb.png 537w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/rgb-300x168.png 300w\" sizes=\"(max-width: 537px) 100vw, 537px\" \/><\/a>Then open VisualGDB Project Properties and set the &#8220;Blink GPIO Number&#8221; to 0, corresponding to the red LED:<br \/>\n<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/07-blink.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3922\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/07-blink.png\" alt=\"07-blink\" width=\"1175\" height=\"753\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/07-blink.png 1175w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/07-blink-300x192.png 300w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/07-blink-1024x656.png 1024w\" sizes=\"(max-width: 1175px) 100vw, 1175px\" \/><\/a><\/li>\n<li>If you build and run your project now, it\u00a0will\u00a0repeatedly blink the red LED.\u00a0To support 3 independent LED channels, we will now modify the <strong>KConfig.projbuild<\/strong> file\u00a0to have 3 separate configuration options instead of just 1:\n<pre class=\"\">menu \"Example Configuration\"\r\n\r\nconfig BLINK_GPIO_RED\r\n int \"Red LED GPIO number\"\r\n range 0 34\r\n default 5\r\n help\r\n GPIO number (IOxx) to blink on and off.\r\n Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to blink.\r\n GPIOs 35-39 are input-only so cannot be used as outputs.\r\n\r\nconfig BLINK_GPIO_GREEN\r\n int \"Green LED GPIO number\"\r\n range 0 34\r\n default 5\r\n help\r\n GPIO number (IOxx) to blink on and off.\r\n Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to blink.\r\n GPIOs 35-39 are input-only so cannot be used as outputs.\r\n\r\nconfig BLINK_GPIO_BLUE\r\n int \"Blue LED GPIO number\"\r\n range 0 34\r\n default 5\r\n help\r\n GPIO number (IOxx) to blink on and off.\r\n Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to blink.\r\n GPIOs 35-39 are input-only so cannot be used as outputs.\r\n\r\n\r\nendmenu<\/pre>\n<p><a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/08-rgbconfig.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3923\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/08-rgbconfig.png\" alt=\"08-rgbconfig\" width=\"1187\" height=\"724\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/08-rgbconfig.png 1187w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/08-rgbconfig-300x183.png 300w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/08-rgbconfig-1024x625.png 1024w\" sizes=\"(max-width: 1187px) 100vw, 1187px\" \/><\/a><\/li>\n<li>Save the file and reopen VisualGDB Project Properties. Now you can set the pin numbers for the red, green and blue LEDs\u00a0via the regular ESP-IDF configuration GUI:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/09-gpios.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3924\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/09-gpios.png\" alt=\"09-gpios\" width=\"1033\" height=\"622\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/09-gpios.png 1033w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/09-gpios-300x181.png 300w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/09-gpios-1024x617.png 1024w\" sizes=\"(max-width: 1033px) 100vw, 1033px\" \/><\/a><\/li>\n<li>Change the main file extension to .cpp and replace its contents with the following code:\n<pre class=\"\">struct BlinkParameters\r\n{\r\n    gpio_num_t Pin;\r\n    unsigned Period;\r\n};\r\n\r\nvoid blink_task(void *pvParameter)\r\n{\r\n    struct BlinkParameters *pBlinkParameters = (struct BlinkParameters *)pvParameter;\r\n \r\n    gpio_pad_select_gpio(pBlinkParameters-&gt;Pin);\r\n    \/* Set the GPIO as a push\/pull output *\/\r\n    gpio_set_direction(pBlinkParameters-&gt;Pin, GPIO_MODE_OUTPUT);\r\n    while(1) {\r\n        \/* Blink off (output low) *\/\r\n        gpio_set_level(pBlinkParameters-&gt;Pin, 0);\r\n        vTaskDelay(pBlinkParameters-&gt;Period \/ 2 \/ portTICK_PERIOD_MS);\r\n        \/* Blink on (output high) *\/\r\n        gpio_set_level(pBlinkParameters-&gt;Pin, 1);\r\n        vTaskDelay(pBlinkParameters-&gt;Period \/ 2 \/ portTICK_PERIOD_MS);\r\n    }\r\n}\r\n\r\nextern \"C\" void app_main()\r\n{\r\n    \/\/The period definitions must be static, as otherwise they would be located on the stack \r\n    \/\/and would get overwritten once the threads actually start up.\r\n    static struct BlinkParameters pins[] = {\r\n        { .Pin = (gpio_num_t)CONFIG_BLINK_GPIO_RED, .Period = 200}, \r\n        { .Pin = (gpio_num_t)CONFIG_BLINK_GPIO_GREEN, .Period = 500, },\r\n        { .Pin = (gpio_num_t)CONFIG_BLINK_GPIO_BLUE, .Period = 1000 }\r\n    };\r\n \r\n    for (auto &amp;pin : pins)\r\n        xTaskCreate(&amp;blink_task, \"blink_task\", configMINIMAL_STACK_SIZE, &amp;pin, 5, NULL);\r\n}<\/pre>\n<p>It will create 3 instances of the <strong>blink_task<\/strong> thread, each one targeting a different LED with a different period:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/10-code.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3925\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/10-code.png\" alt=\"10-code\" width=\"1187\" height=\"724\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/10-code.png 1187w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/10-code-300x183.png 300w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/10-code-1024x625.png 1024w\" sizes=\"(max-width: 1187px) 100vw, 1187px\" \/><\/a><\/li>\n<li>Press F5 to\u00a0start debugging and observe the RGB LED. You will see each channel\u00a0toggling with its own period:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/wroverled.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3930\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/wroverled.jpg\" alt=\"wroverled\" width=\"700\" height=\"570\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/wroverled.jpg 700w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/wroverled-300x244.jpg 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" \/><\/a><\/li>\n<li>Set a breakpoint after one of the gpio_set_level() calls. The\u00a0breakpoint will get\u00a0immediately triggered by one of the threads. You can see the other threads via the Debug-&gt;Windows-&gt;Threads command:<br \/>\n<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/11-stack.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3926\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/11-stack.png\" alt=\"11-stack\" width=\"1187\" height=\"724\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/11-stack.png 1187w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/11-stack-300x183.png 300w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/11-stack-1024x625.png 1024w\" sizes=\"(max-width: 1187px) 100vw, 1187px\" \/><\/a><\/li>\n<li>Another option to quickly view\u00a0various ESP-IDF threads would be via Debug-&gt;Parallel Stacks command. It will immediately show that 2 threads are waiting inside the vTaskDelay() function called from blink_task() while 1 thread is directly executing the blink_task():<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/12-pstack.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3927\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/12-pstack.png\" alt=\"12-pstack\" width=\"1187\" height=\"724\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/12-pstack.png 1187w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/12-pstack-300x183.png 300w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2018\/04\/12-pstack-1024x625.png 1024w\" sizes=\"(max-width: 1187px) 100vw, 1187px\" \/><\/a><\/li>\n<li><\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>This tutorial shows how to create a basic project for the ESP32\u00a0WROVER-KIT-3 module,\u00a0program the FLASH memory\u00a0and debug it via the<\/p>\n","protected":false},"author":1,"featured_media":3931,"comment_status":"closed","ping_status":"closed","sticky":true,"template":"","format":"standard","meta":{"footnotes":""},"categories":[142],"tags":[138,143,64],"_links":{"self":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts\/3915"}],"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=3915"}],"version-history":[{"count":4,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts\/3915\/revisions"}],"predecessor-version":[{"id":9045,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts\/3915\/revisions\/9045"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/media\/3931"}],"wp:attachment":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/media?parent=3915"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/categories?post=3915"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/tags?post=3915"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}