Evaluation of Domestic Development Board: Qinheng CH32V103 Reading Memory Card Font Display

Evaluation of Domestic Development Board: Qinheng CH32V103 Reading Memory Card Font Display

Thanks again to Qinheng for sending this CH32V103 development board, which integrates a simulation downloader, USB to serial converter, and is compatible with Arduino interfaces, making it very convenient to use.The FAT file system has evolved over the years (FAT, FAT12, FAT16, FAT32, exFAT) and is now widely used in small capacity storage media such as memory cards and USB drives.Due to maximum capacity limitations, FAT and FAT16 have gradually faded into history, while FAT32 is still widely used and is what I am currently using.This article uses FATFS to implement file directory retrieval and long file name reading and conversion, ultimately printing the results to the serial debugging assistant.First, let’s take a look at what is stored on the USB drive (accidentally revealing my age).Evaluation of Domestic Development Board: Qinheng CH32V103 Reading Memory Card Font DisplayEvaluation of Domestic Development Board: Qinheng CH32V103 Reading Memory Card Font DisplayWith FATFS, we can easily read the 8.3 short file names, 8-byte file names (4 characters for Chinese), and 3-byte extensions of these files.   Evaluation of Domestic Development Board: Qinheng CH32V103 Reading Memory Card Font DisplayEverything looks neat, but it feels like something is missing. Only the artist’s name is present without the song title? The lowercase mp3 extension has turned uppercase? And what does ~1 mean?If you want to understand short file names, you can search the forums for more information; we won’t repeat it here. Our goal is long file names, so let’s continue.In the FATFS configuration, enable support for Chinese long file names: #define _LFN_UNICODE 1, and enable Chinese support: #define _CODE_PAGE 936

Evaluation of Domestic Development Board: Qinheng CH32V103 Reading Memory Card Font Display

That’s half the battle won. However, since long file names are encoded in Unicode, reading them directly and printing them via the serial port results in garbled characters. This involves encoding conversion issues, as the serial assistant generally displays characters in GBK encoding. Different encodings lead to garbled text, requiring the use of encoding conversion functions in FATFS. However, since the conversion between GBK and Unicode is irregular, it can only be done through a lookup table. Why make it difficult for Chinese and non-English characters? This table is quite large and occupies over 170K of storage space…But I have a 64K Flash microcontroller???Evaluation of Domestic Development Board: Qinheng CH32V103 Reading Memory Card Font DisplayChallenges drive motivation. Should I add external Flash? If there is no Flash, I can only use a memory card, which is convenient since these songs are also stored on the memory card. So, I will create a directory, SYS, to store the Unicode and GBK conversion lookup table.When the memory card is inserted, mount the file system and read the Unicode and GBK conversion table.

        if(SD_Detect())            {                if(sd_status == 0)                {                    sd_status = 1;                    printf("Insert\r\n");                }            }            else            {                sd_status = 0;        }            if(sd_status == 1)            {                path[0] = '0';            path[1] = ':';            path[2] = 0;                res_sd = f_mount(&fs,path,1);                if(res_sd == FR_OK)                {                    sd_status = 2;                    printf("Mount Ok\r\n");                path[0] = '0';                path[1] = ':';                path[2]  = '/';                path[3]  = 'S';                path[4]  = 'Y';                path[5]  = 'S';                path[6]  = '/';                path[7]  = 'U';                path[8]  = 'N';                path[9]  = 'I';                path[10] = 'G';                path[11] = 'B';                path[12] = 'K';                path[13] = '.';                path[14] = 'B';                path[15] = 'I';                path[16] = 'N';                path[17] = 0;                res_sd = f_open(&gd_FileUNItoGBK,path,FA_READ);                if(res_sd == FR_OK)                    printf("Load UNIGBK.BIN Ok\r\n");                else                    printf("Load UNIGBK.BIN Fail\r\n");                path[2] = '/';                    path[3] = 0;                    scan_files(path);                }                else if(res_sd == FR_NO_FILESYSTEM)                {                printf("No File System\r\n");                }                else                {                printf("Mount Fail\r\n");            }            }

Rewrite the ff_convert function in cc936.c to read the lookup table information from the specified offset on the memory card.

WCHAR ff_convert (  /* Converted code, 0 means conversion error */    WCHAR   src,    /* Character code to be converted */    UINT    dir     /* 0: Unicode to OEMCP, 1: OEMCP to Unicode */){    WCHAR t[2];    WCHAR c;    DWORD i, li, hi;    WCHAR n;    UINT cout;    DWORD offset;    if(src < 0x80)  // ASCII        return src;    else    {        if(dir)     // GBK TO UNICODE        {            offset = gd_FileUNItoGBK.fsize >> 1;        }        else        // UNICODE TO GBK        {            offset = 0;        }        if(gd_FileUNItoGBK.fsize != 0)        {            hi = gd_FileUNItoGBK.fsize >> 1;            hi = (hi >> 2) - 1;            li = 0;            for(n=16; n; n--)            {                i = li + ((hi - li) >> 1);                f_lseek(&gd_FileUNItoGBK, (i << 2) + offset);                f_read(&gd_FileUNItoGBK, &t, 4, &cout);                if(src == t[0]) break;                if(src > t[0])                    li = i;                else                    hi = i;            }            c = n ? t[1] : 0;        }        else c = 0;    }    return c;}

The core part is basically complete. Next, read the long file names, convert them to GBK encoding, and print them.

                p = pt;                pth = *fno.lfname ? fno.lfname : fno.fname;                while(*pth != 0)                {                    ct = ff_convert(*pth, 0);                    if(ct > 255)                    {                        *p = (u8)(ct>>8);                        p++;                        *p = (u8)ct;                        p++;                    }                    else                    {                        *p = (u8)ct;                        p++;                    }                    pth++;                }                *p = 0;                printf("%s\r\n", pt);

Finally, we can display Chinese long file names.Evaluation of Domestic Development Board: Qinheng CH32V103 Reading Memory Card Font DisplaySince the memory card is read via SPI interface, the speed of Chinese encoding conversion is a bit slow. Without an SDIO interface, I can only increase the SPI speed and use DMA to improve read and write speeds.Displaying on the serial assistant is obviously not very convenient. Do I need to bring a computer just to check the directory? If I have a computer, why would I need to look at the directory this way?Evaluation of Domestic Development Board: Qinheng CH32V103 Reading Memory Card Font DisplayThis time, let’s change the display method.Let’s get to work.Evaluation of Domestic Development Board: Qinheng CH32V103 Reading Memory Card Font DisplayI found a 12864 display screen from the clutter, a very mini one, 0.96 inches, which can be found on various online stores for about 10 yuan.

Evaluation of Domestic Development Board: Qinheng CH32V103 Reading Memory Card Font Display

How to light up the screen is not covered in this article; the materials provided with the screen are sufficient to light it up.This time, the main goal is to read and display the font library from the memory card.Since the files stored on the memory card may have various names, to display any Chinese character, we need to generate a font library by taking a modulus of all Chinese characters.Why not just print all the Chinese characters and take a modulus one by one?Evaluation of Domestic Development Board: Qinheng CH32V103 Reading Memory Card Font DisplayThis involves two issues:1. There are tens of thousands of Chinese characters, with several thousand common ones. Taking a modulus and converting them one by one is too laborious.Evaluation of Domestic Development Board: Qinheng CH32V103 Reading Memory Card Font Display2. With so many Chinese characters, how do I quickly find the modulus for the character “我” among them?What? I forgot the position of the modulus for “我” when I took it?Evaluation of Domestic Development Board: Qinheng CH32V103 Reading Memory Card Font DisplayFor the first issue, thanks to some predecessors, there are already many software tools available for generating font libraries.For the second issue, there are many types of Chinese character encodings, such as GB2312 (which includes 6763 characters), GBK (which includes 21886 characters), Unicode (which includes over 60,000 characters), and UTF-32 (which includes 120,000 characters).With these various encodings, the encoding represents the order of the characters, so we can directly compare them. Here, we take GBK and Unicode as examples. The first Chinese character in GBK is “丂”, with a hexadecimal encoding of 8140, and each character is represented by 2 bytes.How to obtain the GBK encoding of a Chinese character? Here is a simple method using the serial assistant!Short the RX and TX pins, set the sending character to GBK encoding, and the receiving setting to hexadecimal. The received character encoding after sending will be:Evaluation of Domestic Development Board: Qinheng CH32V103 Reading Memory Card Font DisplayObtaining Unicode is similar; switch to Unicode encoding for sending and set receiving to hexadecimal:Evaluation of Domestic Development Board: Qinheng CH32V103 Reading Memory Card Font DisplayTaking a modulus, whether comparing GBK encoding or Unicode encoding, can achieve our goal. Just select an encoding and start taking the modulus:Evaluation of Domestic Development Board: Qinheng CH32V103 Reading Memory Card Font DisplayGenerate the binary font library file:Evaluation of Domestic Development Board: Qinheng CH32V103 Reading Memory Card Font DisplayThen place it on the memory card and use FATFS to read the font library file information: f_open(&gd_FileFontLib16, path, FA_READ);Offset the file read pointer: f_lseek(&gd_FileFontLib16, foffset);Read the font information: f_read(&gd_FileFontLib16, Buff, 32, &cout); When using a Unicode encoded font library, the foffset offset is the Chinese character encoding. When using a GBK encoded font library, the foffset offset is calculated as follows:

  qh = *Str;  ql = *(++Str);  if(qh<0x81 || ql<0x40 || ql==0xff || qh==0xff)        // Rarely used Chinese characters  {    for(i=0; i<(Size<<1) ;i++)      *Buff++ = 0x00;                                   // Fill    return 0;  }  if(ql < 0x7f)    ql-=0x40;  else    ql-=0x41;  qh -= 0x81;  foffset = ((u32)190 * qh + ql) * (Size&0x07 ? (Size>>3)+1 : Size>>3) * Size;    // Get the byte offset in the font library

Once the font information is obtained, it can be displayed, and I won’t elaborate further. Here is the image:

Evaluation of Domestic Development Board: Qinheng CH32V103 Reading Memory Card Font Display

ENDThis article is an original piece written by gtbestom, a senior member of 21ic.Recommended ReadingLighting Up the Onboard 0.91-inch OLED of HC32F460 Development BoardUsing TencentOS Tiny Operating System on STM32L431 to Connect to Tencent IoT Development PlatformTeach You a Trick: How to Efficiently Manage Memory on MCU?→ Follow for more updates ←

Leave a Comment