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
Diff: TFT/spidma.cpp
- Revision:
- 0:3dac1f1bc9e0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TFT/spidma.cpp Sun Apr 03 07:45:29 2016 +0000 @@ -0,0 +1,107 @@ +/*===================================================================*/ +/* */ +/* 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); +} +