I have ported my old project “pNesX” game console emulator to the nucleo.

Dependencies:   SDFileSystem mbed

Intro

I have ported my old project “pNesX” to the STM32 Nucleo. The pNesX is a NES emulator for the PlayStation that I have created 16 years ago!

Emulation part was almost without change, the sound part was newly added.

Parts

STM32 Nucleo F446RE
QVGA 2.2 TFT SPI (with the SD card slot)
Audio jack(TS or TRS)
USB Connector
Register 100k, 10k, 4.7k, 100
Capacitor 0.01uF, 2.2uF
Breadboard
Wires
Computer Speakers
USB GamePad

Wiring diagram

/media/uploads/beaglescout007/nucleo_ex06_emu.png

TFT J2Nucleo
VCC3V3
GNDGND
CSPB_5(D4)
ResetPA_10(D2) Pull Up(100k)
D/CPA_8(D7)
MOSIPA_7(D11)
SCKPA_5(D13)
LEDLED-100ohm-3V3
MISOPA_6(D12)
TFT J4Nucleo
SD_CSPA_9
SD_MOSIPB_15
SD_MISOPB_14
SD_SCKPB_13
AudioNucleo
TIPPA_4(A2)
USB con.Nucleo
GNDGND
+PA_12
-PA_11
5V5V

https://youtu.be/jL24IjT6LnI

Limitations

  • Since the rest of the RAM is about 50kbyte, maximum capacity of the game ROM is about 50kbyte.
  • The length of the file name up to 32 characters.
  • The number of files in the folder is up to 100.

Used Library

Committer:
beaglescout007
Date:
Sun Apr 03 07:45:29 2016 +0000
Revision:
0:3dac1f1bc9e0
Release

Who changed what in which revision?

UserRevisionLine numberNew contents of line
beaglescout007 0:3dac1f1bc9e0 1 /*===================================================================*/
beaglescout007 0:3dac1f1bc9e0 2 /* */
beaglescout007 0:3dac1f1bc9e0 3 /* tft.cpp : TFT(ILI9341) function */
beaglescout007 0:3dac1f1bc9e0 4 /* */
beaglescout007 0:3dac1f1bc9e0 5 /* 2016/1/20 Racoon */
beaglescout007 0:3dac1f1bc9e0 6 /* */
beaglescout007 0:3dac1f1bc9e0 7 /*===================================================================*/
beaglescout007 0:3dac1f1bc9e0 8
beaglescout007 0:3dac1f1bc9e0 9 #include "mbed.h"
beaglescout007 0:3dac1f1bc9e0 10 #include "tft.h"
beaglescout007 0:3dac1f1bc9e0 11
beaglescout007 0:3dac1f1bc9e0 12 DigitalOut cs(PB_5, PullUp); // TFT chipselect pin
beaglescout007 0:3dac1f1bc9e0 13 DigitalOut dc(PA_8, PullUp); // TFT data command select pin
beaglescout007 0:3dac1f1bc9e0 14 DigitalOut rst(PA_10,PullUp); // TFT reset pin
beaglescout007 0:3dac1f1bc9e0 15
beaglescout007 0:3dac1f1bc9e0 16 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 17 /* Write command */
beaglescout007 0:3dac1f1bc9e0 18 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 19 void write_cmd(uint8_t cmd)
beaglescout007 0:3dac1f1bc9e0 20 {
beaglescout007 0:3dac1f1bc9e0 21 dc = 0;
beaglescout007 0:3dac1f1bc9e0 22 spi_write(cmd);
beaglescout007 0:3dac1f1bc9e0 23 }
beaglescout007 0:3dac1f1bc9e0 24
beaglescout007 0:3dac1f1bc9e0 25 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 26 /* Write data */
beaglescout007 0:3dac1f1bc9e0 27 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 28 void write_data(uint8_t data)
beaglescout007 0:3dac1f1bc9e0 29 {
beaglescout007 0:3dac1f1bc9e0 30 dc = 1;
beaglescout007 0:3dac1f1bc9e0 31 spi_write(data);
beaglescout007 0:3dac1f1bc9e0 32 }
beaglescout007 0:3dac1f1bc9e0 33
beaglescout007 0:3dac1f1bc9e0 34 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 35 /* TFT reset */
beaglescout007 0:3dac1f1bc9e0 36 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 37 void tft_reset()
beaglescout007 0:3dac1f1bc9e0 38 {
beaglescout007 0:3dac1f1bc9e0 39 wait_ms(200);
beaglescout007 0:3dac1f1bc9e0 40 cs = 1;
beaglescout007 0:3dac1f1bc9e0 41 dc = 1;
beaglescout007 0:3dac1f1bc9e0 42 rst = 1;
beaglescout007 0:3dac1f1bc9e0 43 wait_ms(200);
beaglescout007 0:3dac1f1bc9e0 44 rst = 0;
beaglescout007 0:3dac1f1bc9e0 45 wait_us(10);
beaglescout007 0:3dac1f1bc9e0 46 rst = 1;
beaglescout007 0:3dac1f1bc9e0 47 wait_ms(120);
beaglescout007 0:3dac1f1bc9e0 48 cs = 0;
beaglescout007 0:3dac1f1bc9e0 49 wait_ms(10);
beaglescout007 0:3dac1f1bc9e0 50
beaglescout007 0:3dac1f1bc9e0 51 write_cmd(0x3A); // Pixel Format
beaglescout007 0:3dac1f1bc9e0 52 write_data(0x55); // 16bit Color
beaglescout007 0:3dac1f1bc9e0 53
beaglescout007 0:3dac1f1bc9e0 54 write_cmd(0xB1); // Frame Control
beaglescout007 0:3dac1f1bc9e0 55 write_data(0);
beaglescout007 0:3dac1f1bc9e0 56 write_data(0x1f);
beaglescout007 0:3dac1f1bc9e0 57
beaglescout007 0:3dac1f1bc9e0 58 write_cmd(0x36); // Memory Access Control
beaglescout007 0:3dac1f1bc9e0 59 write_data(0xE8); // MY MX MV BGR
beaglescout007 0:3dac1f1bc9e0 60
beaglescout007 0:3dac1f1bc9e0 61 write_cmd(0x11); // Sleep Out
beaglescout007 0:3dac1f1bc9e0 62 wait_ms(5);
beaglescout007 0:3dac1f1bc9e0 63
beaglescout007 0:3dac1f1bc9e0 64 write_cmd(0x29); // Display On
beaglescout007 0:3dac1f1bc9e0 65 }
beaglescout007 0:3dac1f1bc9e0 66
beaglescout007 0:3dac1f1bc9e0 67 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 68 /* Set windows size, start memory write */
beaglescout007 0:3dac1f1bc9e0 69 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 70 void tft_set_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
beaglescout007 0:3dac1f1bc9e0 71 {
beaglescout007 0:3dac1f1bc9e0 72 write_cmd(0x2A); // Column Address Set
beaglescout007 0:3dac1f1bc9e0 73 write_data(x0 >> 8);
beaglescout007 0:3dac1f1bc9e0 74 write_data(x0);
beaglescout007 0:3dac1f1bc9e0 75 write_data(x1 >> 8);
beaglescout007 0:3dac1f1bc9e0 76 write_data(x1);
beaglescout007 0:3dac1f1bc9e0 77
beaglescout007 0:3dac1f1bc9e0 78 write_cmd(0x2B); // Page Address Set
beaglescout007 0:3dac1f1bc9e0 79 write_data(y0 >> 8);
beaglescout007 0:3dac1f1bc9e0 80 write_data(y0);
beaglescout007 0:3dac1f1bc9e0 81 write_data(y1 >> 8);
beaglescout007 0:3dac1f1bc9e0 82 write_data(y1);
beaglescout007 0:3dac1f1bc9e0 83
beaglescout007 0:3dac1f1bc9e0 84 write_cmd(0x2C); // Memory Write
beaglescout007 0:3dac1f1bc9e0 85
beaglescout007 0:3dac1f1bc9e0 86 wait_us(20);
beaglescout007 0:3dac1f1bc9e0 87
beaglescout007 0:3dac1f1bc9e0 88 dc = 1;
beaglescout007 0:3dac1f1bc9e0 89 }
beaglescout007 0:3dac1f1bc9e0 90
beaglescout007 0:3dac1f1bc9e0 91 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 92 /* Clear screen */
beaglescout007 0:3dac1f1bc9e0 93 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 94 void tft_clear(uint16_t color)
beaglescout007 0:3dac1f1bc9e0 95 {
beaglescout007 0:3dac1f1bc9e0 96 tft_set_window(0, 0, TFT_WIDTH, TFT_HEIGHT);
beaglescout007 0:3dac1f1bc9e0 97
beaglescout007 0:3dac1f1bc9e0 98 for (int i = 0; i < TFT_WIDTH * TFT_HEIGHT; ++i)
beaglescout007 0:3dac1f1bc9e0 99 {
beaglescout007 0:3dac1f1bc9e0 100 spi_writew(color);
beaglescout007 0:3dac1f1bc9e0 101 }
beaglescout007 0:3dac1f1bc9e0 102 }
beaglescout007 0:3dac1f1bc9e0 103
beaglescout007 0:3dac1f1bc9e0 104 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 105 /* Put char */
beaglescout007 0:3dac1f1bc9e0 106 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 107 void tft_put_char(int x, int y, char chr, uint16_t color, uint16_t bgcolor)
beaglescout007 0:3dac1f1bc9e0 108 {
beaglescout007 0:3dac1f1bc9e0 109 if (chr < 0x20 || chr > 0x7f)
beaglescout007 0:3dac1f1bc9e0 110 {
beaglescout007 0:3dac1f1bc9e0 111 chr = 0x3f;
beaglescout007 0:3dac1f1bc9e0 112 }
beaglescout007 0:3dac1f1bc9e0 113 else
beaglescout007 0:3dac1f1bc9e0 114 {
beaglescout007 0:3dac1f1bc9e0 115 chr = (chr < 0x60) ? chr - 0x20 : chr - 0x40;
beaglescout007 0:3dac1f1bc9e0 116 }
beaglescout007 0:3dac1f1bc9e0 117
beaglescout007 0:3dac1f1bc9e0 118 tft_set_window(x, y, x + 7, y + 6);
beaglescout007 0:3dac1f1bc9e0 119
beaglescout007 0:3dac1f1bc9e0 120 for (int dy = 0; dy < 7; ++dy)
beaglescout007 0:3dac1f1bc9e0 121 {
beaglescout007 0:3dac1f1bc9e0 122 unsigned char img = chrimg[chr][dy];
beaglescout007 0:3dac1f1bc9e0 123 for ( int dx = 0; dx < 8; ++dx)
beaglescout007 0:3dac1f1bc9e0 124 {
beaglescout007 0:3dac1f1bc9e0 125 if (img & 0x80)
beaglescout007 0:3dac1f1bc9e0 126 {
beaglescout007 0:3dac1f1bc9e0 127 spi_writew(color);
beaglescout007 0:3dac1f1bc9e0 128 }
beaglescout007 0:3dac1f1bc9e0 129 else
beaglescout007 0:3dac1f1bc9e0 130 {
beaglescout007 0:3dac1f1bc9e0 131 spi_writew(bgcolor);
beaglescout007 0:3dac1f1bc9e0 132 }
beaglescout007 0:3dac1f1bc9e0 133 img <<= 1;
beaglescout007 0:3dac1f1bc9e0 134 }
beaglescout007 0:3dac1f1bc9e0 135 }
beaglescout007 0:3dac1f1bc9e0 136
beaglescout007 0:3dac1f1bc9e0 137 }
beaglescout007 0:3dac1f1bc9e0 138
beaglescout007 0:3dac1f1bc9e0 139 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 140 /* Text out */
beaglescout007 0:3dac1f1bc9e0 141 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 142 void tft_text(int x, int y, char *text, uint16_t color, uint16_t bgcolor)
beaglescout007 0:3dac1f1bc9e0 143 {
beaglescout007 0:3dac1f1bc9e0 144 while (*text != 0)
beaglescout007 0:3dac1f1bc9e0 145 {
beaglescout007 0:3dac1f1bc9e0 146 tft_put_char(x, y, *text, color, bgcolor);
beaglescout007 0:3dac1f1bc9e0 147 x += 8;
beaglescout007 0:3dac1f1bc9e0 148 text++;
beaglescout007 0:3dac1f1bc9e0 149 }
beaglescout007 0:3dac1f1bc9e0 150 }
beaglescout007 0:3dac1f1bc9e0 151
beaglescout007 0:3dac1f1bc9e0 152 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 153 /* Horizontal Line */
beaglescout007 0:3dac1f1bc9e0 154 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 155 void tft_hline(int x1, int y, int x2, uint16_t color)
beaglescout007 0:3dac1f1bc9e0 156 {
beaglescout007 0:3dac1f1bc9e0 157 tft_set_window(x1, y, x2, y);
beaglescout007 0:3dac1f1bc9e0 158
beaglescout007 0:3dac1f1bc9e0 159 for (;x1 < x2; ++x1)
beaglescout007 0:3dac1f1bc9e0 160 {
beaglescout007 0:3dac1f1bc9e0 161 spi_writew(color);
beaglescout007 0:3dac1f1bc9e0 162 }
beaglescout007 0:3dac1f1bc9e0 163 }
beaglescout007 0:3dac1f1bc9e0 164
beaglescout007 0:3dac1f1bc9e0 165 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 166 /* Vertical Line */
beaglescout007 0:3dac1f1bc9e0 167 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 168 void tft_vline(int x, int y1, int y2, uint16_t color)
beaglescout007 0:3dac1f1bc9e0 169 {
beaglescout007 0:3dac1f1bc9e0 170 tft_set_window(x, y1, x, y2);
beaglescout007 0:3dac1f1bc9e0 171
beaglescout007 0:3dac1f1bc9e0 172 for (;y1 < y2; ++y1)
beaglescout007 0:3dac1f1bc9e0 173 {
beaglescout007 0:3dac1f1bc9e0 174 spi_writew(color);
beaglescout007 0:3dac1f1bc9e0 175 }
beaglescout007 0:3dac1f1bc9e0 176 }
beaglescout007 0:3dac1f1bc9e0 177
beaglescout007 0:3dac1f1bc9e0 178 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 179 /* Box */
beaglescout007 0:3dac1f1bc9e0 180 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 181 void tft_box(int x1, int y1, int x2, int y2, uint16_t color)
beaglescout007 0:3dac1f1bc9e0 182 {
beaglescout007 0:3dac1f1bc9e0 183 tft_hline(x1, y1, x2, color);
beaglescout007 0:3dac1f1bc9e0 184 tft_vline(x1, y1, y2, color);
beaglescout007 0:3dac1f1bc9e0 185 tft_vline(x2, y1, y2, color);
beaglescout007 0:3dac1f1bc9e0 186 tft_hline(x1, y2, x2, color);
beaglescout007 0:3dac1f1bc9e0 187 }
beaglescout007 0:3dac1f1bc9e0 188
beaglescout007 0:3dac1f1bc9e0 189 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 190 /* Box Fill */
beaglescout007 0:3dac1f1bc9e0 191 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 192 void tft_boxfill(int x1, int y1, int x2, int y2, uint16_t color)
beaglescout007 0:3dac1f1bc9e0 193 {
beaglescout007 0:3dac1f1bc9e0 194 tft_set_window(x1, y1, x2, y2);
beaglescout007 0:3dac1f1bc9e0 195
beaglescout007 0:3dac1f1bc9e0 196 for (int i = 0; i < (x2 - x1 + 1) * (y2 - y1 + 1); ++i)
beaglescout007 0:3dac1f1bc9e0 197 {
beaglescout007 0:3dac1f1bc9e0 198 spi_writew(color);
beaglescout007 0:3dac1f1bc9e0 199 }
beaglescout007 0:3dac1f1bc9e0 200 }
beaglescout007 0:3dac1f1bc9e0 201
beaglescout007 0:3dac1f1bc9e0 202 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 203 /* Draw 4bit BMP */
beaglescout007 0:3dac1f1bc9e0 204 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 205 bool draw_bmp_4bpp(const unsigned char *imgdata, int x, int y)
beaglescout007 0:3dac1f1bc9e0 206 {
beaglescout007 0:3dac1f1bc9e0 207 BITMAPFILEHEADER *bf = (BITMAPFILEHEADER *)imgdata;
beaglescout007 0:3dac1f1bc9e0 208 BITMAPINFOHEADER *bi = (BITMAPINFOHEADER *)(imgdata + sizeof(BITMAPFILEHEADER));
beaglescout007 0:3dac1f1bc9e0 209
beaglescout007 0:3dac1f1bc9e0 210 if (bi->biBitCount != 4)
beaglescout007 0:3dac1f1bc9e0 211 {
beaglescout007 0:3dac1f1bc9e0 212 return false;
beaglescout007 0:3dac1f1bc9e0 213 }
beaglescout007 0:3dac1f1bc9e0 214
beaglescout007 0:3dac1f1bc9e0 215 unsigned char *pRGBPal = (unsigned char*)imgdata + sizeof(BITMAPFILEHEADER) + bi->biSize;
beaglescout007 0:3dac1f1bc9e0 216 unsigned short palette[16];
beaglescout007 0:3dac1f1bc9e0 217
beaglescout007 0:3dac1f1bc9e0 218 for (int i = 0; pRGBPal < imgdata + bf->bfOffBits && i < 16; ++i)
beaglescout007 0:3dac1f1bc9e0 219 {
beaglescout007 0:3dac1f1bc9e0 220 unsigned short r,g,b;
beaglescout007 0:3dac1f1bc9e0 221 b = *pRGBPal++ >> 3;
beaglescout007 0:3dac1f1bc9e0 222 g = *pRGBPal++ >> 2;
beaglescout007 0:3dac1f1bc9e0 223 r = *pRGBPal++ >> 3;
beaglescout007 0:3dac1f1bc9e0 224 pRGBPal++;
beaglescout007 0:3dac1f1bc9e0 225 palette[i] = ((g & 7) << 13) | (b << 8) | (r << 3) | (g >> 3);
beaglescout007 0:3dac1f1bc9e0 226 }
beaglescout007 0:3dac1f1bc9e0 227
beaglescout007 0:3dac1f1bc9e0 228 unsigned short HLine[320];
beaglescout007 0:3dac1f1bc9e0 229 int linesize = (bi->biWidth / 2 + 3) & 0xfffc;
beaglescout007 0:3dac1f1bc9e0 230
beaglescout007 0:3dac1f1bc9e0 231 tft_set_window(x, y, x + bi->biWidth - 1, y + bi->biHeight - 1);
beaglescout007 0:3dac1f1bc9e0 232
beaglescout007 0:3dac1f1bc9e0 233 unsigned char *bmp;
beaglescout007 0:3dac1f1bc9e0 234
beaglescout007 0:3dac1f1bc9e0 235 for (int y = bi->biHeight - 1; y >= 0; --y)
beaglescout007 0:3dac1f1bc9e0 236 {
beaglescout007 0:3dac1f1bc9e0 237 bmp = (unsigned char *)imgdata + bf->bfOffBits + y * linesize;
beaglescout007 0:3dac1f1bc9e0 238
beaglescout007 0:3dac1f1bc9e0 239 for (int x = 0; x < bi->biWidth; ++x)
beaglescout007 0:3dac1f1bc9e0 240 {
beaglescout007 0:3dac1f1bc9e0 241 char pal;
beaglescout007 0:3dac1f1bc9e0 242 if (x & 1)
beaglescout007 0:3dac1f1bc9e0 243 {
beaglescout007 0:3dac1f1bc9e0 244 pal = *bmp & 0xf;
beaglescout007 0:3dac1f1bc9e0 245 bmp++;
beaglescout007 0:3dac1f1bc9e0 246 }
beaglescout007 0:3dac1f1bc9e0 247 else
beaglescout007 0:3dac1f1bc9e0 248 {
beaglescout007 0:3dac1f1bc9e0 249 pal = *bmp >> 4;
beaglescout007 0:3dac1f1bc9e0 250 }
beaglescout007 0:3dac1f1bc9e0 251
beaglescout007 0:3dac1f1bc9e0 252 HLine[x] = palette[pal];
beaglescout007 0:3dac1f1bc9e0 253 }
beaglescout007 0:3dac1f1bc9e0 254
beaglescout007 0:3dac1f1bc9e0 255 HAL_SPI_Transmit(&SpiHandle, (uint8_t *)HLine, bi->biWidth * 2, 100);
beaglescout007 0:3dac1f1bc9e0 256 }
beaglescout007 0:3dac1f1bc9e0 257
beaglescout007 0:3dac1f1bc9e0 258 return true;
beaglescout007 0:3dac1f1bc9e0 259 }
beaglescout007 0:3dac1f1bc9e0 260
beaglescout007 0:3dac1f1bc9e0 261 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 262 /* Initialize TFT */
beaglescout007 0:3dac1f1bc9e0 263 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 264 void tft_init(void)
beaglescout007 0:3dac1f1bc9e0 265 {
beaglescout007 0:3dac1f1bc9e0 266 spi_init();
beaglescout007 0:3dac1f1bc9e0 267
beaglescout007 0:3dac1f1bc9e0 268 tft_reset();
beaglescout007 0:3dac1f1bc9e0 269 }
beaglescout007 0:3dac1f1bc9e0 270
beaglescout007 0:3dac1f1bc9e0 271
beaglescout007 0:3dac1f1bc9e0 272
beaglescout007 0:3dac1f1bc9e0 273