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
TFT J2 | Nucleo |
---|---|
VCC | 3V3 |
GND | GND |
CS | PB_5(D4) |
Reset | PA_10(D2) Pull Up(100k) |
D/C | PA_8(D7) |
MOSI | PA_7(D11) |
SCK | PA_5(D13) |
LED | LED-100ohm-3V3 |
MISO | PA_6(D12) |
TFT J4 | Nucleo |
---|---|
SD_CS | PA_9 |
SD_MOSI | PB_15 |
SD_MISO | PB_14 |
SD_SCK | PB_13 |
Audio | Nucleo |
---|---|
TIP | PA_4(A2) |
USB con. | Nucleo |
---|---|
GND | GND |
+ | PA_12 |
- | PA_11 |
5V | 5V |
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
- SDFileSystem by Neil Thiessen
- F401RE-USBHost by Norimasa Okamoto
- USBHostGamepad by Yuuichi Akagawa
TFT/spidma.cpp
- Committer:
- beaglescout007
- Date:
- 2016-04-03
- Revision:
- 0:3dac1f1bc9e0
File content as of revision 0:3dac1f1bc9e0:
/*===================================================================*/ /* */ /* spidma.cpp : SPI DMA function */ /* */ /* 2016/1/20 Racoon */ /* */ /*===================================================================*/ #include "mbed.h" #include "stm32f4xx_hal.h" SPI_HandleTypeDef SpiHandle; /*-------------------------------------------------------------------*/ /* callback */ /*-------------------------------------------------------------------*/ extern "C" { void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi) { static DMA_HandleTypeDef hdma_tx; GPIO_InitTypeDef GPIO_InitStruct; __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_SPI1_CLK_ENABLE(); __HAL_RCC_DMA2_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_5; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; GPIO_InitStruct.Alternate = GPIO_AF5_SPI1; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_6; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_7; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); hdma_tx.Instance = DMA2_Stream3; hdma_tx.Init.Channel = DMA_CHANNEL_3; hdma_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; hdma_tx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_tx.Init.MemInc = DMA_MINC_ENABLE; hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_tx.Init.Mode = DMA_NORMAL; hdma_tx.Init.Priority = DMA_PRIORITY_HIGH; hdma_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; hdma_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; hdma_tx.Init.MemBurst = DMA_MBURST_SINGLE; hdma_tx.Init.PeriphBurst = DMA_PBURST_SINGLE; HAL_DMA_Init(&hdma_tx); __HAL_LINKDMA(hspi, hdmatx, hdma_tx); HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 0, 1); HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn); } void DMA2_Stream3_IRQHandler(void) { HAL_DMA_IRQHandler(SpiHandle.hdmatx); } } // extern "C" /*-------------------------------------------------------------------*/ /* Write a byte data */ /*-------------------------------------------------------------------*/ void spi_write(uint8_t data) { HAL_SPI_Transmit(&SpiHandle, &data, 1, 100); } /*-------------------------------------------------------------------*/ /* Write a word data */ /*-------------------------------------------------------------------*/ void spi_writew(uint16_t data) { HAL_SPI_Transmit(&SpiHandle, (uint8_t *)&data, 2, 100); } /*-------------------------------------------------------------------*/ /* Initialize SPI DMA */ /*-------------------------------------------------------------------*/ void spi_init() { SpiHandle.Instance = SPI1; SpiHandle.Init.Mode = SPI_MODE_MASTER; SpiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; SpiHandle.Init.Direction = SPI_DIRECTION_2LINES; SpiHandle.Init.CLKPhase = SPI_PHASE_1EDGE; SpiHandle.Init.CLKPolarity = SPI_POLARITY_HIGH; SpiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; SpiHandle.Init.CRCPolynomial = 7; SpiHandle.Init.DataSize = SPI_DATASIZE_8BIT; SpiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB; SpiHandle.Init.NSS = SPI_NSS_SOFT; SpiHandle.Init.TIMode = SPI_TIMODE_DISABLE; if (HAL_SPI_Init(&SpiHandle) != HAL_OK) while(1); }