Sitemap

[NES] From Template Project to NES Simulation | Technical Collection

7 min readSep 2, 2025

1. Prerequisites

For the NES game, we choose the classic Super Mary. First, create a sample project based on the 06_demo_nes_simulator example. Locate the SuperMary.nes file in the game directory and copy it to the SD card.

2. Software Package Settings

Create a new template project based on RT-Spark, enter RT setting, go to the detailed interface, select Hardware, and add (select) the following settings:

<Onboard Driver Devices>

1. SRAM

2. Onboard LCD (ST7789) → TIM14_CH1

3. File system → SDCARD

<Chip Driver Devices>

1. PWM14 channel1

2. SPI BUS → RW007 onboard

After completing the additions, press Ctrl+S to save the settings.

3. CubeMx Configuration

Navigate to the board → CubeMx_Config directory, locate the CubeMx_Config.ioc file, and double-click to open the STM32CubeMx interface.

Configuration is the same as LCD configuration:

Timers → TIM14 → PWM Generation CH1

Connectivity → FSMC → LCD1

Press enter or click to view image in full size

After completing the configuration, click the GENERATE CODE button in the upper right corner, then return to the RT-Studio interface.

4. Project Main Body

First, build the project. At this point, the CubeMx_Config directory will contain two additional folders: Drivers and MDK-ARM. The console will display many errors. Delete these two folders as well as the main.c file under the Src directory. Then, right-click the project file → Synchronize Scons configuration to project.

After synchronization, copy the code from the main.c file in the application directory of the sample project into the corresponding main.c file of the template project. Do the same for the nes folder, copying it into the template project. Rebuild the project. If errors occur, repeat the Scons synchronization and rebuild again.

Now, download the project to the development board, then open the serial port tool. (!! Remember to insert the SD card, otherwise the following error will occur !!)

Press enter or click to view image in full size

After inserting the SD card, the serial tool output is normal.

Press enter or click to view image in full size

Enter the command:nes_start sdcard/SuperMary.nes

Then you will see — an error again…

Press enter or click to view image in full size

The error prompt shows an assertion failure. Return to RT-Studio to analyze the code, search for small_mem, and locate the relevant code segment.

Press enter or click to view image in full size

After careful analysis, no obvious problems were found in the code. So where is the issue, and why is the assertion triggered?By consulting related materials, it was found that RT_ASSERT depends on the debug.h header file. In formal product releases, debugging functionality is usually disabled (i.e., the RT_DEBUG macro is undefined) to reduce code size and improve efficiency. However, there is no debug-related code used here.

Upon rechecking the code, no clear issues were identified, so BC was used to assist in the analysis.

Press enter or click to view image in full size

A comparison reveals differences between the template project and the sample project. Focus on various config files and the scons file, as these are all configuration-related.

Press enter or click to view image in full size

In the rtconfig.h file, it was discovered that the template project defined the DEBUG macro. Commenting out these two lines, synchronizing the scons configuration, rebuilding, downloading, and testing the LCD with the game command produced the following result:

Press enter or click to view image in full size

This time, no errors occurred, indicating the above operations worked correctly. However, the LCD still only displayed a white screen, and the game did not run as expected.Although no errors occurred, the LCD still did not function properly. Why? The LCD lights up, which indicates the LCD configuration itself is correct. In this project, the RT-Spark development board only uses the LCD, SD slot, and buttons. Obviously, the buttons are not related to the current issue. Therefore, the most likely problem lies in the SD-related components.

Following this line of reasoning, it can be inferred that the SD slot configuration may not be working correctly, preventing the SD slot from reading data from the SD card. Alternatively, the LCD may not be receiving the data from the SD card. Return to the code analysis to look for clues.

In the application/main.c file, the definition of the nes_start function can be found. This is precisely the command used when inputting instructions. From the command, it is evident that nes_start is responsible for reading data from the SD card.

Press enter or click to view image in full size

Thus, it can be boldly inferred that nes_start is related to the problem we are trying to solve. By analyzing the nes_start function, we can see that its role is to read the NES file address, load the NES file, and then check whether the loaded NES file is NULL. At this point, based on this code, a subtle clue emerges.

if(!nes){
return -1;
}

This section of code checks whether nes is NULL. If it is, the program exits early. This introduces another possibility: the SD read and LCD reception are both functioning correctly, but the NES file did not run because of the early exit. Add a line of log printing code inside this if:

rt_kprintf("create default!\n");

Rebuild the project, download it, and then enter the command.

Press enter or click to view image in full size

At this point, the issue becomes obvious: the program exits early, which causes the LCD not to display the game screen. But what causes the program to exit early? Returning to BC and comparing the main.c of the template project with that of the sample project —

No differences were found. Furthermore, the application folder showed no differences either.

Press enter or click to view image in full size

By elimination:

setting, rt-thread are clearly unrelated → eliminated

application, libraries, and Debug show no differences → eliminated

● Other obviously unrelated files → eliminated

Press enter or click to view image in full size

This leaves only a few files. Previously analyzed rtconfig.h again:

Press enter or click to view image in full size

Several sections contain macro definitions related to TIMER. Considering that the LCD lights up but does not display the game, these can be eliminated.

Press enter or click to view image in full size
Press enter or click to view image in full size
Press enter or click to view image in full size

The first two sections are hard to understand, but clearly unrelated to LCD or NES. The last one is related to network protocols → eliminated. Thus, rtconfig.h is excluded.

Next, analyze other files: .config and cconfig.h contain content similar to rtconfig.h, so also excluded. This leaves only the two files related to link.

Press enter or click to view image in full size

These are related to the board’s linker. Recalling an earlier possibility — that SD slot and LCD connection configuration issues prevent the LCD from receiving data from the SD slot, causing the program to exit early — code analysis confirmed this possibility.

Press enter or click to view image in full size

The following code segments are all related to nes. Copy them over, synchronize Scons, rebuild the project, download, enter the command, and check the result.

Press enter or click to view image in full size

The game runs normally, and no errors appear in the serial tool. This confirms the fix was correct. NES simulation successfully implemented!

5. Reflections

The process was a bit bumpy, but ultimately the problem was identified and resolved. The journey from template project to sample implementation felt like creating something from nothing — full of achievement, as if one step closer to the Bilibili masters ( ).

Sample projects are very convenient, but they give you the fish rather than teaching you how to fish. Starting from a template project and building step by step brings great satisfaction, but I still hope more tutorials will be made available (pushing through step by step really isn’t easy).

Press enter or click to view image in full size

In addition, when reviewing logs, I found that neither the sample project nor the template project printed the path log of this command. The reason for this has not been identified — if anyone knows, please explain.

(BC is really useful)

--

--

RT-Thread IoT OS
RT-Thread IoT OS

Written by RT-Thread IoT OS

An Open-Source Community-Powered Real-Time Operating System (RTOS) Project! Let’s develop, DIY, create, share, and explore this new IoT World together!

No responses yet