[NES] From Template Project to NES Simulation | Technical Collection
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
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 !!)
After inserting the SD card, the serial tool output is normal.
Enter the command:nes_start sdcard/SuperMary.nes
Then you will see — an error again…
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.
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.
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.
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:
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.
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.
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.
By elimination:
● setting, rt-thread are clearly unrelated → eliminated
● application, libraries, and Debug show no differences → eliminated
● Other obviously unrelated files → eliminated
This leaves only a few files. Previously analyzed rtconfig.h again:
Several sections contain macro definitions related to TIMER. Considering that the LCD lights up but does not display the game, these can be eliminated.
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.
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.
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.
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).
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)
