Monthly Archives: July 2024

VoCore2: Serial Port Transfer Small File

When I develop, sometimes wifi or network not working, or ssh can not connect, only way to fix it to use serial port, but serial port do not support transfer file…there are no way to transfer small files, like a simple driver or small application, have to reboot and use uboot to reload everything, and kermit load new firmware to uboot is really slow.

PS: I know somebody can use kermit or sz/lz, but first of all, you need to have them in firmware already, that is a chicken-and-egg problem 🙂

I find default busybox shell(sh) support command “echo -ne”, this is a amazing way to transfer binary data by serial port, and do not need any depends, so I write a simple application, hope this helps.

Usage Example, save TEST.ko to VoCore2 /tmp/TEST.ko: sspdt TEST.ko /dev/ttyACM0

Note: after transfer, remember to run md5sum to check if the data transfer is correct and complete, serial port do not guarantee that. From my test, < 100KB file normally do not have problem, and speed approx 1.5KB/s

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libserialport.h>

// apt install libserialport-dev
// gcc sspdt.c -o sspdt -lserialport
// speed is approx 1.5KB/s

#define min(a, b) ((a) < (b) ? (a) : (b))

uint8_t *alloc_from_file(const char *name, int *size)
    FILE *fp = fopen(name, "rb");
    if (fp == NULL)
        return NULL;

    fseek(fp, 0, SEEK_END);

    *size = ftell(fp);
    fseek(fp, 0, SEEK_SET);

    uint8_t *buf = malloc(*size);
    if (buf)
        fread(buf, 1, *size, fp);

    return buf;

struct sp_port *ssport_open(const char *name)
    struct sp_port *port;
    int baudrate = 115200, res;

    res = sp_get_port_by_name(name, &port);
    if (SP_OK != res)
        return NULL;

    res = sp_open(port, SP_MODE_READ_WRITE);
    if (SP_OK != res) {
        printf("sp_open=%d, %s\n", res, sp_last_error_message());
        return NULL;

    // clear input/output buffer.
    sp_flush(port, SP_BUF_BOTH);

    // gd32f150 supported protocol 115200, 8n1.
    sp_set_baudrate(port, baudrate);
    sp_set_bits(port, 8);
    sp_set_parity(port, SP_PARITY_NONE);
    sp_set_stopbits(port, 1);

    // necessary, or system will drop 0x11 and 0x13.
    sp_set_flowcontrol(port, SP_FLOWCONTROL_NONE);

    return port;

void ssport_close(struct sp_port *port)
    sp_flush(port, SP_BUF_BOTH);

int ssport_write(struct sp_port *port, const void *buf, size_t count)
    int wbyte;
    wbyte = sp_blocking_write(port, buf, count, 600);
    //print_hex("wr", buf, wbyte);
    return wbyte;

int ssport_read(struct sp_port *port, void *buf, size_t count)
    int rbyte;
    rbyte = sp_blocking_read(port, buf, count, 600);
    //print_hex("rd", buf, rbyte);
    return rbyte;

void process(int cur, int total)
    printf("%9dB / %9dB [%3.1f%%]", cur, total, (float)cur / total * 100);

void get_file_name(const char *name, char *out)
    int i = strlen(name) - 1;
    for (; i >= 0; i--) {
        if (name[i] == '/' || name[i] == '\\')
    strcpy(out, name + i);

int main(int argc, char *argv[])
    if (argc != 3) {
        printf("sspdt [input file] [serial port]\r\n");
        printf("send small files to device term by serial port.\r\n");
        return 0;

    int size = 0;
    uint8_t *buf = alloc_from_file(argv[1], &size);
    struct sp_port *sp = ssport_open(argv[2]);

    ssport_write(sp, "\n\n", 2);

    char name[128] = {0};
    get_file_name(argv[1], name);
    printf("file %s will save to device /tmp/%s\r\n", argv[1], name);

    // each time read 16 bytes
    for (int i = 0; i < size; i += 16) {
        char cmd[0x100] = {0};
        sprintf(cmd, "echo -ne '");
        for (int j = 0; j < min(size - i, 16); j++) {
            char tmp[16];
            sprintf(tmp, "\\x%02x", buf[i + j]);
            strcat(cmd, tmp);
        strcat(cmd, "' >> /tmp/");
        strcat(cmd, name);
        strcat(cmd, "\n");

        ssport_write(sp, cmd, strlen(cmd));
        process(i, size);
    process(size, size);

    return 1;

MPro: Support 60Hz FPS

We are proud to announce that MPRO now supports a refresh rate of 60Hz.

show jpeg on 5inch screen

Please download and try the following: Use the latest firmware and the screen_test.c file.

The main upgrade is that the MPRO firmware now supports baseline JPEG compression, which is typically much smaller than bitmap. For example, an 800×480 16-bit bitmap is approximately 800KB, but a high-quality JPEG image is only 100~200KB. This reduction in size can increase the refresh speed by 300%~500%, allowing us to easily achieve a 60Hz refresh rate.

Note: The software part(like Simhub) may still need some time to adjust, so this feature will take some time to be implemented for dashboard users.