I2C Master for NESMini Controller

This FPGA project communicates with a Nintendo Classic Mini Controller by implementing an I2C master device in Verilog.

Preview of some waveforms discussed in detail further below:

Which Controller?

The controller I used this project looks like the original NES controller (up/down/left/right, select, start, A, and B only) but has a Wii-style connector. This controller is fundamentally different than the similar-looking USB controllers. NES Classic Mini retro controllers with the Wii connector communicate over an I2C interface, which is necessary for this project.

Here’s a pic of the controller I purchased:

I developed this on a Terasic DE10-Lite board using the Quartus Prime 20.1, Light Edition toolchain. Nothing about the Verilog code is very specific to this board or its Altera MAX10 FPGA, so it should be easy to adapt to other boards. The source code is well commented and is the best place to understand the assumptions and limitations. Additional Caveats are also in a separate section below.

Why?

I made this to support another project which is an FPGA-based 80’s retro video game. The game is all FPGA, i.e. no HPS, no soft MCU, no frame buffer, just on-the-fly generation of a VGA signal 800×600 at 60 Hz (40MHz pixel clock) and gameplay also implemented in the FPGA. A fun example of what FPGAs can do.

The game uses two instantiations of the code from this NES controller project. That provides fully independent communication with two controllers for the game’s two players. The fact that the off-the-shelf controllers have the same slave device address is no issue, since the two instantiations create completely separate I2C buses. The magic of FPGAs…

See more detail on that project here – Ganzvaders.

Some I2C Musings

The Nintendo Classic Mini controller acts as an I2C slave device, so my Verilog code implements an I2C master device.

I2C is a bidirectional, open-drain, synchronous serial protocol that’s used mostly on PCBs between IC’s, but as in this case, sometimes it’s also used with offboard devices.

This is not intended to be a full I2C tutorial. Many other sites online provide great detail on I2C, including:

Please check out those sites above for if you’re new to I2C. I won’t go in all the details they do, but will mention a few highlights:

  • I2C physically consists of a data line (SDA) and a clock line (SCL).
  • Typical data rates are 100 KHz and 400 KHz, though faster speeds exist but are fairly rare. This project uses 100 KHz.
  • SDA and SCL are both open-drain, meaning that devices drive the lines to ground for a LOW, but HIGH values are expressed by releasing the line and allowing pull-up resistors to bring it to the positive voltage rail. This makes bidirectional data straightforward, but the weak drive capability of the pull-up resistors also makes it difficult to run long distances.
  • I2C is synchronous, unlike a UART, and transactions are paced by the SCL (clock) line.
  • A I2C bus has at least one master device, who controls SCL, and one or more slave devices. Technically, a bus can have multiple masters and a slave device can control the clock under a special circumstance called “clock stretching“, but let’s keep it simple for now.
  • All communication is between a master device and a slave device. Slave devices cannot directly communicate with each other.
  • There are special conditions on the bus to indicate the beginning and end of a transaction called START and STOP conditions. These are the only time when SDA changes while the SCL is HIGH, allowing devices to easily detect these conditions
  • The master device controls all transactions, and begins each with a START condition, followed by an address indicating which slave device’s turn it is to talk on the bus.
  • Each slave device has its own 7 bit unique address on the bus. (10 bit address modes do exist, but are less common.)
  • When the slave device address is transmitted, it is always appended with an additional bit (making an 8 bit byte). That extra bit, the R/*W bit, indicates whether the master device is writing to the slave device or reading from the slave device
  • After some number of byte transfers between the master device and the slave device, the master creates a STOP condition on the bus, ending the transaction.

Caveats

A few caveats about my implementation:

  • my code does not check for ACK/NACKs from the slave device – if you want error checking you will have to add it!!
  • my code does not support clock stretching
  • I2C depends on open-drain connections for the SCL and SDA lines. To achieve this, the Verilog code infers tristate drivers on the toolchain and board mentioned above. If there are issues with other tools or FPGAs, verifying the driver for these lines may be necessary
  • if this code is used in a scenario where clock domain crossing is done, additional care naturally will be needed to manage that

The limitations above were not an issue in this NES controller application. See the source code for more details.

Protocol

As mentioned above, the Nintendo Classic Mini controller is the slave device, which means the Verilog code must implement a master device to communicate with it. In order to obtain the switch states from the controller, a sequences of writes and reads are necessary. The FPGA first writes to the controller, essentially saying “I’m ready for data”, then the FPGA reverses the direction of data on the I2C bus, and reads 6 bytes from the controller. Those bytes contains the button states. This set of transactions is defined by the firmware in the controller itself and is summarized on many websites, including Albert Gonzalez’s page here.

Verilog Code – Lower Layer

As mentioned above, my code has two main layers – a lower level that performs fundamental I2C operations and a higher level that sequences the set of transactions specific to this type of controller.

The lower-level can perform any of the following:

  • generate an I2C start condition
  • generate an I2C stop condition
  • transmit a byte from master to slave
  • receive a byte from slave to master

This is done in module gI2C_low_level_tx_rx.v and is implemented by a small finite state machine, seen below.

gI2C_low_level_tx.v state machine

Once the low level driver module (gI2C_low_level_tx_rx.v) has completed the commanded operation, it indicates this to the caller and returns to the IDLE state.

Header and I/O interface for gI2C_low_level_tx_rx.v (full code on GitHub):

//  ------------------------------------------------------------------------------
//
//  gI2C_low_level_tx_rx.v -- low level I2C comm for Nintendo Class Mini controller
//
//  Copyright (C) 2020 Michael Gansler
//
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program.  If not, see <https://www.gnu.org/licenses/>.
//
//  ------------------------------------------------------------------------------
//
//  Module:       gI2C_low_leveL_tx_rx.v
//
//  Objective:    Performs basic low-level I2C Master operations to 
//                support communications witha Nintendo Class Mini controller.
//
//  Assumptions:  - 40 MHz input clock
//                  Altera MAX10 FPGA
//                - Does not check for ACK's from slave
//                - Does not perform clock stretching
//                - Development done on Terasic DE10-Lite board with 
//                - No clock domain crossings accomodated.  If this module 
//                  were used in an actual situation with clock domain 
//                  crossings or asynchronous inputs, more attention 
//                  (i.e. code changes) would be necessary to manage the 
//                  situation.
//
//  Notes:
//
//  This module performs a number of low-level I2C Master activities.  The
//  intention is that a higher level module coordinates the overall
//  transaction, while this module is commanded by that module 
//  to perform any of the following operations:
//
//    1.  create a start condtion
//    2.  create a stop condtion
//    3.  transmit a byte from master to slave
//    4.  receive a byte from slave to master
//
//  Note that clock stretching is not implemented since this
//  appeared to not be necessary for the the Nintendo Classic Mini 
//  retro controller interfacing application.  Likewise, ACKs/NACKs
//  from the slave are not evaluated.
//
//  The diagram below shows typical  I2C SDA and SCL waverforms:
//
//      START                                                STOP 
//      COND                                                 COND
//      ____       __  __  __  __  __  __  __  __  __         ___
//  SDA     |_____/A6\/A5\/A4\/A3\/A2\/A1\/A0\/RW\/AK\_______|
//
//                  ^   ^   ^   ^   ^   ^   ^   ^   ^
//      ______       _   _   _   _   _   _   _   _   _      _____
//  SCL       |_____| |_| |_| |_| |_| |_| |_| |_| |_| |____|
//
//
// ^'s show SCL rising edge, where receiver samples SDA.
//
// The above shows the case of TX'ing the Address (7 bits) and the
// R/*W bit followed by receiving an ACK from the receiver.  
//
// Data byte transfers in the opposite direction are analogous, 
// 8 bits of data + an ACK/NACK bit.
//
`default_nettype none            // Require all nets to be declared before used.
                                 // --> typo'd net names get trapped

module gI2C_low_level_tx_rx
#(
   parameter TICKS_PER_I2C_CLK_PERIOD = 400   // Ticks of input clock per I2C SCL period (10 usec).
)
(
   //
   // INPUTS
   //
   input wire       clk,         // Input clock, tested with 40 MHz
   
   input wire       rst,         // Reset input
   
   input wire [2:0] command,     // Input command for which I2C operation to create
   
   input wire [7:0] tx_byte,     // Byte to transmit from master to slave (if requested)

   input wire       ACK,         // 1=Master ACKs after slave read, 0=Master NACKs
   
   //
   // OUTPUTS
   //
   output reg [7:0] read_byte,   // Byte read from slave (if requested)
   
   output reg       busy,        // Indicates that this module is busy performing a sequence of actions
   
   output reg       data_valid,  // Indicates that a byte has been read from the slave and is available
   
   output reg       done,        // Indicates that requested action is complete.
   
   //
   // I2C I/O
   //
   input wire       i_sda,       // Input from tristate driver output, connected externally to SDA line   
   
   output reg       o_sda,       // Output from this module indicating how to drive I2C SDA externally
   
   output reg       o_scl        // Output from this module indicating how to drive I2C SCL externally
);

Verilog Code – Top Layer

The higher level module (gI2C_mini_nes_read.v) sequences the specific transactions for this controller. This consists of a sort of command and response, where a byte is written to the controller, then 6 bytes are read from the controller. Sequencing of these controller-specific transactions is performed in this module by another finite state machine, seen below:

gI2C_mini_nes_read.v state machine

The higher level module (gI2C_mini_nes_read.v) instantiates the low-level Verilog module (gI2C_low_level_tx_rx.v). It then sends commands to the lower level module for each I2C action, and parses the responses from the controller. Button states are provided as individual flags and as a packed word.

Details of how this is implemented is documented in the Verilog source code.

Header and I/O interface for gI2C_mini_nes_read.v (full code on GitHub):

//  ------------------------------------------------------------------------------
//
//  gI2C_mini_nes_read.v -- I2C comm with Nintendo Class Mini controller
//
//  Copyright (C) 2020 Michael Gansler
//
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program.  If not, see <https://www.gnu.org/licenses/>.
//
//  ------------------------------------------------------------------------------
//
//  Module:       gI2C_mini_nes_read.v
//
//  Objective:    Performs basic I2C Master operations to communicate with
//                a Nintendo Class Mini controller and read all buttons.
//
//
//  Assumptions:  - 40 MHz input clock
//                - Development done on Terasic DE10-Lite board with 
//                  Altera MAX10 FPGA
//                - No clock domain crossings accomodated.  If this module 
//                  were used in an actual situation with clock domain 
//                  crossings or asynchronous inputs, more attention 
//                  (i.e. code changes) would be necessary to manage the 
//                  situation.
//  Notes:
//
//  This module communicates as a Master over an I2C bus and decodes 
//  button press status from a NES Classi Mini retro controller.  This is 
//  the sort of controller that looks like an original NES controller
//  (up/down/left/right/select/start/A/B), but has a completely different
//  interface than the original.  This updated retro controller has a Wii
//  style connector and an I2C bus.
//
//  The high-level module in this file coordinates the sequences of starts,
//  stops, transmits and reads for a full transaction with the controller.  
//  This obtains the status of all of the buttons: up, down, left, right,
//  select, start, A, and B.  Since this controller is a rendition of the 
//  original NES controller, this is the full set of buttons on the device.
//
//  This module also instantiates a lower level I2c module which handles 
//  the bit by bit signaling of each I2C operation.  The sequence of these
//  operations is coordinated by this upper level module, sending a
//  number of commands to the lower level driver for each operation, 
//  resulting in one full transaction with the device.
//
//  Once transaction consists of the following operations:
//
//   - generate start condition
//   - transmit address to slave, write mode
//   - write 0x00 to slave
//   - generate stop condition
//   - generate start condition
//   - transmit address to slave, read mode
//   - read 6 bytes from slave (the last two bytes contain the button data)
//   - generate a stop condition
//
//  This complete transaction requires less than 1.5 msec, allowing high
//  polling rates of the buttons, if needed.
//
//  The input clock used for testing and development was 40 MHz since this 
//  module was intended for a VGA project that has a 40 MHz pixel clock).  
//
//  Parameterization was done to allow other clock frequencies.  Comments are
//  included describing areas to be mindful of when changing the clock. 
//  The main concern is the counter in the lower-level module (ctr) that 
//  regulates SCL bit timing.  Make sure it has sufficient width if a 
//  faster input clock is used.
//
`default_nettype none                    // Require all nets to be declared before used.
                                         // --> typo'd net names get trapped

module gI2C_mini_nes_read
#( 
   parameter SLAVE_ADDR = 7'h52,         // This is the I2C address of the NES mini controller
   
   parameter TICKS_PER_I2C_CLK = 400     // For 40 MHz clock -> 400.   
                                         // 10 is useful for simulation.
                                         // Note: standard I2C is 100 KHz which means 10 usec/bit.  
                                         // Therefore, if input clk is 40 MHz, then:
                                         // TICKS_PER_I2C_CLK = 40MHz*10usec = 400 counts.
)
(
   //
   // INPUTS 
   //
   input  wire          clk_40,          // Input clock.  Tested with 40 MHz clock
   
   input  wire          rst,             // Active high reset line.
   
   input  wire          request_data,    // Pulse this high to initiate full data transfer sequence
                                         // which includes all Starts, Stops, Master Writes, and Master Reads
                                         // to obtain data from the controller.
   
   //
   // OUTPUTS
   //
   output reg           data_valid,      // Pulse that indicates controller_data was updated with new data.
   
   output reg           busy,            // Module is busy, i.e. transaction in progress

   output reg           btn_none,        // 
   output reg           btn_up,          //
   output reg           btn_down,        //
   output reg           btn_left,        //   Button states decoded from the
   output reg           btn_right,       //   NES mini controller I2C data (bytes 4 and 5).
   output reg           btn_select,      //
   output reg           btn_start,       //
   output reg           btn_B,           //            
   output reg           btn_A,           // 
   
   output reg  [8:0]    buttons,         // Same button state info as above, but as a packed word
   
   //
   // BIDIRECTIONAL
   //
   inout wire           io_sda,          // SDA line to outside world (implements a tristate driver)
   
   inout wire           io_scl           // SCL line to outside world (implements a tristate driver)
);

Protocol Examples

Two examples of the full sequence of transactions are included below:

In these diagrams, green circles show the START conditions and red squares show the STOP conditions. The slave device address (0x52) is seen after each START condition – the first time with the LSB LOW to indicate write mode, the second time with the LSB HIGH to indicate read mode.

The first transaction is a write of a single byte (0x00) from master device to slave device. The master device then creates a STOP condition, followed by another START condition to begin a second transaction but in the opposite direction – data flowing from slave device to master device. The next element is the slave device address (0x52) again, but with the R/W bit HIGH to indicate read mode. This follows with the master device reading 6 bytes from the slave device. This is the data that we want from the controller.

Bytes 0-3 of the 6 data bytes are not relevant for this controller, so they are discarded. Bytes 4 and 5 have the states for the 8 buttons on this controller (up/down/left/right, select, start, A, and B). The exact format is seen in the source code comments of gI2C_mini_nes_read.v. Once these transactions are complete, the high level code extracts the button information from these bytes and provides them as output.

Simulation Stuff

For development, I used ModelSim (free with Quartus Prime) to run a test bench I created that pings the top level module for one full transaction. Files on the GitHub site, and simulation waveform output below:

Tests on the Hardware

Once I had the basics working in simulation, I also created a synthesizable wrapper to request data ~19 Hz. This wrapper instantiates the higher-level module (gI2C_mini_nes_read.v) in a Quartus schematic and pings it using some Quartus timer and compare functions. This allowed me to do real tests on hardware with the Nintendo controller connected and communicating on the I2C bus.

Higher update rates than 19 Hz are possible since the I2C transactions only take about 1.5 msec total. Quartus files are up on GitHub. Wrapper schematic seen below:

Initialization Notes

Some websites mention a need to send some additional initialization bytes to the Nintendo Mini Class controller, while others say they are not necessary. I did not send any initialization bytes other than the 0x00 described above, since that worked fine with the controller I hand on hand for testing.

Source Code

The full Quartus project is on my GitHub site. The source code is well commented and is the best place to understand the assumptions and limitations. Additional Caveats are also in a separate section above.