Over-The-Air programmer for VSDSquadron-Mini board using NodeMCU 1.0

  • VSDSquadron-Mini CH32V003F4U6
  • ESP8266 NodeMCU 1.0 (ESP-12E)
  • Bread Board
  • Power Supply
  • Jumper Wires

Pinout Diagram for OTA Programmer:

Table for Pin connection:

VSDSquadron-Mini boardNodeMCU 1.0 (ESP-12E)
PD5 (Blue wire)D1
PD6 (Orange wire)D2
PD0 (Green wire)D5
GND (Black wire)GND
5V (Red wire)VIN

CH32V003_IAP Program:

// Importing header files
#include "debug.h"
#include "string.h"
#include "iap.h"

// Function which jumps from BOOT area (1920B) to USER area (16K)
void IAP_2_APP(void)
RCC_ClearFlag();                        // Clearing all the reset and clock control flags
SystemReset_StartMode(Start_Mode_USER); // Setting the Start mode to USER
NVIC_SystemReset();                     // Performing a System reset

int main(void)
    // Enable GPIOD,USART1 clock

    // Setting the UART baud rate to 38400

    // A temporary count variable used for creating delay
    u32 count = 0;

    // Loop
        // If no data is recieved through UART, keep on counting
while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) != SET){
            // If the count exceeds this threshold, then the execution will be redirected to USER area
if(count >= 3000000){

        // If the above loop terminates, it means data is recieved through UART
        count = 0;          // Resetting the counter
UART_Rx_Deal();     // Deal with the incoming data
#include "debug.h"

// Initializes GPIO pins for programming
void GPIO_Toggle_INIT(void){
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
GPIO_InitTypeDefGPIO_InitStructure = {0};
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOD, &GPIO_InitStructure);

// This function performs System reset with the Start mode BOOT, which
// basically starts the execution from BOOT AREA after the reset.
void APP_2_IAP(void){

// *** IMPORTANT ***
// This function initiates the External interrupt functionality to the pin PD0.
// This has to be called in order to detect the reset signal and branch the execution
// to the BOOT AREA for OTA programming
void EXTI0_INT_INIT(void){
GPIO_InitTypeDefGPIO_InitStructure = {0};
EXTI_InitTypeDefEXTI_InitStructure = {0};
NVIC_InitTypeDefNVIC_InitStructure = {0};

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOD, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOD, &GPIO_InitStructure);

    /* GPIOA ----> EXTI_Line0 */
GPIO_EXTILineConfig(GPIO_PortSourceGPIOD, GPIO_PinSource0);
EXTI_InitStructure.EXTI_Line = EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;

NVIC_InitStructure.NVIC_IRQChannel = EXTI7_0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

// Main function
int main(void){
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);     // Interrupt settings
SystemCoreClockUpdate();                            // Clock settings
    #if (SDI_PRINT == SDI_PR_OPEN)
printf("SystemClk:%d\r\n", SystemCoreClock);
printf( "ChipID:%08x\r\n", DBGMCU_GetCHIPID() );
printf("GPIO Toggle TEST\r\n");


        // Main code goes here
GPIO_WriteBit(GPIOD, GPIO_Pin_4, Bit_SET);
GPIO_WriteBit(GPIOD, GPIO_Pin_3, Bit_RESET);
GPIO_WriteBit(GPIOD, GPIO_Pin_4, Bit_RESET);
GPIO_WriteBit(GPIOD, GPIO_Pin_3, Bit_SET);


// *** IMPORTANT ***
// This is the external interrupt handler which detects reset signal through PD0
// and branches the execution to BOOT_AREA for OTA programming.
void EXTI7_0_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));

void EXTI7_0_IRQHandler(void){
printf("Run at EXTI\r\n");
EXTI_ClearITPendingBit(EXTI_Line0);     /* Clear Flag */
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266mDNS.h>
#include <ESP8266WebServer.h>
#include <SoftwareSerial.h>
#include <FS.h>   // Include the SPIFFS library

#define VSD_RESET_PIN D5
SoftwareSerialmySerial(D1,D2);   // RX , TX

ESP8266WiFiMulti wifiMulti;     // Create an instance of the ESP8266WiFiMulti class, called 'wifiMulti'
ESP8266WebServer server(80);    // Create a webserver object that listens for HTTP request on port 80

File fsUploadFile;              // a File object to temporarily store the received file
String file_name = "";

byte data[] = {
  0x57,   // Uart_Sync_Head1
  0xab,   // Uart_Sync_Head2
  0x83,   // IAP end command
  0x00,   // length
  0x00,   // Rev 0
  0x00,   // Rev 1
  0x83   // Checksum

byte data2[] = {
  0x57,   // Uart_Sync_Head1
  0xab,   // Uart_Sync_Head2
  0x81,   // IAP chip erase command
  0x00,   // length
  0x00,   // Rev 0
  0x00,   // Rev 1
  0x81   // Checksum

byte data3[64];

byte checksum = 0;

String getContentType(String filename); // convert the file extension to the MIME type
bool handleFileRead(String path);       // send the right file to the client (if it exists)
void handleFileUpload();                // upload a new file to the SPIFFS

void setup() {
Serial.begin(115200);         // Start the Serial communication to send messages to the computer
pinMode(D0, OUTPUT);

digitalWrite(D0, HIGH);
digitalWrite(VSD_RESET_PIN, HIGH);

wifiMulti.addAP("your_ssid", "your_password");   // add Wi-Fi networks you want to connect to

Serial.println("Connecting ...");
  int i = 0;
  while (wifiMulti.run() != WL_CONNECTED) { // Wait for the Wi-Fi to connect
Serial.print(++i); Serial.print(' ');
Serial.print("Connected to ");
Serial.println(WiFi.SSID());              // Tell us what network we're connected to
Serial.print("IP address:\t");
Serial.println(WiFi.localIP());           // Send the IP address of the ESP8266 to the computer

  if (MDNS.begin("esp8266")) {              // Start the mDNS responder for esp8266.local
Serial.println("mDNS responder started");
  } else {
Serial.println("Error setting up MDNS responder!");

SPIFFS.begin();                           // Start the SPI Flash Files System

server.on("/upload", HTTP_GET, []() {                 // if the client requests the upload page
    if (!handleFileRead("/upload.html"))                // send it if it exists
server.send(404, "text/plain", "404: Not Found"); // otherwise, respond with a 404 (Not Found) error

server.on("/upload", HTTP_POST,                       // if the client posts to the upload page
handleFileUpload                                    // Receive and save the file

server.onNotFound([]() {                              // If the client requests any URI
    if (!handleFileRead(server.uri()))                  // send it if it exists
server.send(404, "text/plain", "404: Not Found"); // otherwise, respond with a 404 (Not Found) error

server.on("/list", handleFileList);
server.on("/flash_vsd", handleFileName);

server.begin();                           // Actually start the server
Serial.println("HTTP server started");

void loop() {

void handleFileName(){
file_name = "/" + server.arg("file_name");
//  server.send(200,"text/plain", file_name);
server.send(200, "text/plain", file_name + " is being flashed. Please do not refresh the browser.");

// Handle File lists
void handleFileList(){
  String path = "/";
  uint8_t count = 0;
  Dir dir = SPIFFS.openDir(path);
  String output = "<!DOCTYPE html>";
  output += "<html><head><title> Files </title></head><body>";
  output += "<h3>Select a file to flash :</h3>";
  output += "<form method=\"get\" action=\"/flash_vsd\">";
    File entry = dir.openFile("r");
      count += 1;

      output += "<input type=\"radio\" id=\"file"+ String(count)+"\" name=\"file_name\" value=\"";
      output += String(entry.name()).substring(1);
      output += "\">";
      output += "<label for=\"file"+ String(count) +"\"> " + String(entry.name()).substring(1)+ "</label><br>";

  output += "<input type=\"submit\" value=\"Submit\"></form></body></html>";
server.send(200, "text/html", output);

String getContentType(String filename) { // convert the file extension to the MIME type
  if (filename.endsWith(".html")) return "text/html";
  else if (filename.endsWith(".css")) return "text/css";
  else if (filename.endsWith(".js")) return "application/javascript";
  else if (filename.endsWith(".ico")) return "image/x-icon";
  else if (filename.endsWith(".gz")) return "application/x-gzip";
  return "text/plain";

bool handleFileRead(String path) { // send the right file to the client (if it exists)
Serial.println("handleFileRead: " + path);
  if (path.endsWith("/")) path += "index.html";          // If a folder is requested, send the index file
  String contentType = getContentType(path);             // Get the MIME type
  String pathWithGz = path + ".gz";
  if (SPIFFS.exists(pathWithGz) || SPIFFS.exists(path)) { // If the file exists, either as a compressed archive, or normal
    if (SPIFFS.exists(pathWithGz))                          // If there's a compressed version available
      path = pathWithGz;                                      // Use the compressed verion
    File file = SPIFFS.open(path, "r");                    // Open the file
size_t sent = server.streamFile(file, contentType);    // Send it to the client
file.close();                                          // Close the file again
Serial.println(String("\tSent file: ") + path);
    return true;
Serial.println(String("\tFile Not Found: ") + path);   // If the file doesn't exist, return false
  return false;

void handleFileUpload(){ // upload a new file to the SPIFFS
HTTPUpload& upload = server.upload();
if(upload.status == UPLOAD_FILE_START){
    String filename = upload.filename;
    if(!filename.startsWith("/")) filename = "/"+filename;
Serial.print("handleFileUpload Name: "); Serial.println(filename);
fsUploadFile = SPIFFS.open(filename, "w");            // Open the file for writing in SPIFFS (create if it doesn't exist)
  } else if(upload.status == UPLOAD_FILE_WRITE){
fsUploadFile.write(upload.buf, upload.currentSize); // Write the received bytes to the file
  } else if(upload.status == UPLOAD_FILE_END){
    if(fsUploadFile) {                                    // If the file was successfully created
fsUploadFile.close();                               // Close the file again
Serial.print("handleFileUpload Size: "); Serial.println(upload.totalSize);
server.sendHeader("Location","/success.html");      // Redirect the client to the success page
    } else {
Serial.println("File upload failed");
server.send(500, "text/plain", "500: couldn't create file");

// Chip erase command
void iap_chip_erase() {
Serial.println("Starting Chip erase command");
Serial.println("Sending commands");
for(int i = 0; i< 7; i++){
Serial.print(" ");
Serial.print("Response: ");
  if (mySerial.available())
Serial.println("\nChip erase command successful !");

// IAP Program command
void iap_program() {
Serial.println("Starting Chip program command");
Serial.println("Sending commands");
mySerial.write(0x57); delay(50);
mySerial.write(0xab); delay(50);

mySerial.write(0x80); delay(50);  // cmd
mySerial.write(0x40); delay(50);  // len
mySerial.write((byte) 0x00); delay(50);  // rev0
mySerial.write((byte) 0x00); delay(50);  // rev1

  checksum = 0x80 + 0x40;
for(int i = 0; i< 64; i++){
Serial.print(data3[i], HEX);
Serial.print(" ");
    checksum += data3[i];

  // Send checksum
Serial.print("Checksum: ");
Serial.println(checksum, HEX);


Serial.print("Response: ");
  if (mySerial.available())

Serial.println("\nChip program command successful !");


// IAP end command
void iap_end(){
Serial.println("Starting IAP end command");
Serial.println("Sending commands");
for(int i = 0; i< 7; i++){
Serial.print(" ");
Serial.print("Response: ");
  if (mySerial.available())

Serial.println("\nIAP end command successful !");

// Resetting the VSDSM board
void reset_vsdsm(){
Serial.println("Resetting VSDSquadron-Mini board");
digitalWrite(VSD_RESET_PIN, LOW);
digitalWrite(VSD_RESET_PIN, HIGH);
Serial.println("Done resetting");

// Flash
void flash_file(){
digitalWrite(D0, LOW);
  File file = SPIFFS.open(file_name, "r");
Serial.println("Failed to open file for reading");

Serial.println("\nClearing RX buffer");
while(mySerial.available() > 0)

  uint32_t count = 0;
for(int i = 0; i< 64; i++){
      data3[i] = (file.available()) ? file.read() : 0xFF;

digitalWrite(D0, HIGH);

server.sendHeader("Location","/success2.html");      // Redirect the client to the success page
  • In the OTA programmer project, the CH32V003_IAP program is uploaded to the BOOT section (1920B starting from addr: 0x1FFF0000) using the WCH-LinkUtility software.
  • The pin connections are made as shown in the pin out diagram.
  • The NodeMCU is flashed with the above NodeMCU sketch. Modify the “your_ssid” and “your_password” with your Hotspot’s ssid and password (note that the html files are not shown here, but can be referred from the github repository mentioned at the end of this document).
  • Generate the “.bin” file for the program that needs to be flashed on CH32V003.

After the above steps,

  • Connect the NodeMCU and a Host like smartphone or laptop, to a common Hotspot.
  • Then, go to the NodeMCU’s IP address in any web browser.
  • Click on the “upload” link to go to the file upload page. Choose your “.bin” file and hit the upload button. After a successful upload, it will say that the file is uploaded successfully.
  • Go back to home page. Click on the “flash file” link to go to the flash file page.
  • You should be able to see the uploaded “.bin” file. Select that and hit the Submit button.
  • You should see a message that the file is being flashed.
  • The NodeMCU’s blue LED will turn on indicating that the VSDSquadron-Mini is being programmed. Wait for a while, for the flashing process to complete.
  • After the flashing process is completed, the board automatically reboots and you should be able to see that newly uploaded flash file is being executed.

Uploading code from a laptop

Uploading code from a smartphone


Registration for Ethical RISC-V IoT Workshop

Welcome to Ethical RISC-V IoT Workshop

The “Ethical RISC-V IoT Workshop” at IIIT Bangalore, organized in collaboration with VSD, is a structured, educational competition aimed at exploring real-world challenges in IoT and embedded systems. Participants progress through three stages: building an application, injecting and managing faults, and enhancing application security. The event spans from May 9 to June 15, 2024, culminating in a showcase of top innovations and an award ceremony. This hands-on hackathon emphasizes learning, testing, and securing applications in a collaborative and competitive environment.

Rules :
  1. Only for Indian Student whose college is registered under VTU
  2. Only team of 2 members can Register
  3. Use only VSDSquadron Mini resources for product development
Awards :
  1. Prize money for final 10 Team
  2. 3 Winner team’s Product will be evaluated for Incubation
  3. 7 consolation prizes
  4. Completion Certificate to final round qualifier
  5. Chance to build a Proud Secured RISC-V Platform for India

Date for Registration : 9th May - 22nd May, 2024
Hackathon Inauguration : 23rd May 2024

VSDSquadron (Educational Board)

VSDSquadron, a cutting-edge development board based on the RISC-V architecture that is fully open-source. This board presents an exceptional opportunity for individuals to learn about RISC-V and VLSI chip design utilizing only open-source tools, starting from the RTL and extending all the way to the GDSII. The possibilities for learning and advancement with this technology are limitless.

Furthermore, the RISC-V chips on these boards should be open for VLSI chip design learning, allowing you to explore PNR, standard cells, and layout design. And guess what? vsdsquadron is the perfect solution for all your needs! With its comprehensive documentation and scalable labs, thousands of students can learn and grow together.

VSD HDP (Hardware Design Program) Duration-10 Week

With VSD Hardware Design Program (VSD-HDP),  you have the opportunity to push the boundaries of what exist in open source and establish the new benchmark for tomorrow.

It will leverage your degree in Electrical or Computer Engineering to work with

  • Programmable logic
  • Analog/ digital IP
  • RISC-V
  • Architecture & microprocessors
  • ASICs and SoCs on high-density digital or RF circuit cards
  • Gain hands-on knowledge during design validation and system integration.

Sounds exciting to just get started with expert mentors, doesn’t it? But we are looking for the next generation of learners, inventors, rebels, risk takers, and pioneers.

“Spend your summer working in the future !!”

Outcomes of VSD Online Research IP Design Internship Program

  1. Job opportunities in Semiconductor Industry
  2. Research work can be submitted to VLSI International journals
  3. Participate in Semiconductor International Conference with Internship Research Work
  4. Paper Publications in IEEE Conference and SIG groups
  5. Tape out opportunity and IP Royalty
  6. Interact with world class Semiconductor designer and researchers
  7. Academic professions where more research projects are encouraged.
  8. All the above research and publication work will help colleges and institutes to improve accreditation levels.

Know More Information

VSD – Intelligent Assessment Technology (VSD-IAT)

VSD – Intelligent Assessment Technology (VSD-IAT) is expertly built training platform and is suited for designer requirements. Semiconductor companies understand the value of training automation and Engineer performance enhancement, and do not need to be convinced of the impact of a virtual platform for learning. VSD trainings are quick, relevant, and easy to access from any device at any time zone.

VSD Intern Webinars

VSD Interns made it happen !!

VSD is working towards creating innovative talent pool who are ready to develop design and products for the new tech world. VSD believes in “Learning by doing principle” , and always prepare the student to apply the knowledge learned in the workshops, webinars and courses. We always push our students to work on new designs, test it and work continuously till it becomes the best performing design. Any student who enrolls to VSD community starts working with small design and grows with us and develops a tapeout level design with complete honesty and dedication towards the Work !!

Check out VSD Interns Achievement!

VSDOpen Online Conference

Welcome to the World’s only online conference in Semiconductor Industry VSDOpen Conference. With enormous support and global presence of audience from different segments of industrial lobby and academia made a highly successful event. Evolution is change in the genetic makeup of a population over time, online conference is one kind evaluation everyone adapt soon. 

  • VSDOpen 2022 is an online conference to share open-source research with the community and promote  hardware design mostly done by the student community.
  • VSDOpen 2022 is based on the theme “How to lower the cost to learn, build, and tapeout chips ?”  , which will provide a platform to community to build stronger designs and strengthen the future of Chip design.
  • VSDOpen is envisioned to create a community based revolution in semiconductor hardware technology.
  • The open source attitude is required to bring out the talent and innovation from the community who are in remote part of world and have least access to the technologies.  And now Google support will help to bring the vision to execution by VSD team

VSD Online Course by Kunal Ghosh

VSD offers online course in complete spectrum of vlsi backend flow from RTL design, synthesis and Verification, SoC planning and design, Sign-off analysis, IP Design, CAD/EDA automation and basic UNIX/IT, Introduction to latest technology – RISC-V, Machine intelligence in EDA/CAD, VLSI Interview FAQ’s.

Current Reach – As of 2021, VSD and its partners have released 41 online VLSI courses and was successfully able to teach  ~35900 Unique students around 151 countries in 47 different languages, through its unique info-graphical and technology mediated learning methods.

Enquiry Form