Port manipulation and speed

I’m trying to emulate a Sega Megadrive controller with an Arduino Nano but feel like I’m having a timing issue.

The console apparently strobes the controller every 60th of a second though I think this very much depends on the game and how it’s programmed. The controller has a single (in 3 button controllers) 74HC157 multiplexer in it which according to the datasheet has a response time of 10ns!

up and down are direct and don’t go near the 157. left and right are low when the strobe is low to indicate a controller is present and the rest depend on the state of the strobe.

The issue I’m having is no matter how I organise this, the directions work ok but button A does nothing, nor does Start and button B seems to press A and B and C seems to press Start and C (so pressing C will pause and jump in sonic 2 for example).

Below is my code, I thought if I manipulated the ports directly this should make things as fast as possible yet it made no difference! Maybe I’m missing something? I might add I did try to poll the strobe (select line) every time I checked for a button press but this gave me the same result. radioSerial is my array of buttons by the way, this is a layer I plan to remove in order to troubleshoot further as it’s currently going to the arduino via a wifi module but honestly the latency on that seems pretty much non existant. That said it’s definitely another factor to consider.

if ((PINC & B00000010)<=1){
if (radioSerialr[2] == 1) {
  PORTC &=~(1<<PORTC0);
}
  if (radioSerialr[1] == 1){
    PORTD &=~(1<<PORTD6);
  }else{
    PORTD |= (1<<PORTD6);
  }
  if (radioSerialr[4] == 1){
    PORTD &=~(1<<PORTD4);
  }else{
    PORTD |= (1<<PORTD4);
  }
  if (radioSerialr[5] == 1){
    PORTD &=~(1<<PORTD5);
  }else{
    PORTD |= (1<<PORTD5);
  }
  if (radioSerialr[0] == 1){
    PORTC &=~(1<<PORTC2);
  }else{
    PORTC |= (1<<PORTC2);
  }
}
if ((PINC & B00000010)>=2){
  if (radioSerialr[1] == 1){
    PORTD &=~(1<<PORTD6);
  }else{
    PORTD |= (1<<PORTD6);
  }
  if (radioSerialr[4] == 1){
    PORTD &=~(1<<PORTD4);
  }else{
    PORTD |= (1<<PORTD4);
  }
  if (radioSerialr[2] == 1){
    PORTC &=~(1<<PORTC0);
  }else{
    PORTC |= (1<<PORTC0);
  }
  if (radioSerialr[3] == 1){
    PORTD &=~(1<<PORTD7);
  }else{
    PORTD |= (1<<PORTD7);
  }
  if (radioSerialr[6] == 1){
    PORTD &=~(1<<PORTD5);
  }else{
    PORTD |= (1<<PORTD5);
  }
  if (radioSerialr[7] == 1){
    PORTC &=~(1<<PORTC2);
  }else{
    PORTC |= (1<<PORTC2);
  }
}

Any help would be very much appreciated, I feel like something this simple really shouldn’t be giving me this much trouble!

This statement

if ((PINC & B00000010)<=1)

can only evaluate to 0 or 2 and then gets compared to <=1

This statement

if ((PINC & B00000010)>=2)

can only evaluate to 0 or 2 and then gets compared to >=2.

Typical use is just evaluate the expression as true (non zero) or false (0) and act accordingly.

//if ((PINC & B00000010)<=1)
if (!(PINC & B00000010))
...
//if ((PINC & B00000010)>=2)
if ((PINC & B00000010))

Not that that is the source of your issues but since you didn’t post your entire code, it’s hard to tell…

Oh excellent, thanks I wasn’t aware of that. I’ve a lot to learn!

There’s a lot of redundant elements in this code, it’s a bit of a mess at the moment too…

#include <PriUint64.h>
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <avr/io.h>

//Addresses
const uint64_t addressSetup[2] = { 0x1000000000LL, 0x100000000ALL }; //read pipe then write pipe
const uint64_t address1[2] = { 0x2000000000LL, 0x200000000ALL };
const uint64_t address2[2] = { 0x3000000000LL, 0x300000000ALL };

//Channels (2mhz apart, minimum @1mbps)
const int chanSetup = 102;
const int chan1 = 114;
const int chan2 = 106;

RF24 radio(9, 10); // CE, CSN
int radioSerialr[15] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; //third from last number is power LED status, last two are address/channel (01 etc)
int radioSerialw[15] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; //third from last number is power LED status, last two are address/channel (01 etc)
int led1=2;
int led2=3;
int led1State=LOW;
int led2State=LOW;
int a9999counter=0;
unsigned long previousMillis = 0;
const long setupBlinkPeriod = 1000;
const long initBlinkPeriod = 50;
const long pairedBlinkPeriod = 5;
bool ping=false;
int pingtimer=5000;
int up=4;
int down=6;
int left=A0;
int right=7;
int start=8;
int select=A6;
int buttona=5;
int buttonb=5;
int buttonc=8;
int buttond=A4;
bool initPair=false;
bool paired=false;
uint64_t rAddress=address1[0];
uint64_t wAddress=address1[1];
int channel=chan1;
int padSelect=A1;
int selectState=0;


void LEDcontrol() {
  if (radioSerialr[0]==1 || radioSerialr[1]==1 || radioSerialr[2]==1 || radioSerialr[3]==1 || radioSerialr[4]==1 || radioSerialr[5]==1 || radioSerialr[6]==1 || radioSerialr[7]==1){
    PORTD |= (1<<PORTD2);
    PORTD &=~(1<<PORTD3);
  }else{
    PORTD &=~(1<<PORTD2);
    PORTD &=~(1<<PORTD3);     
  }
//    unsigned long currentMillis = millis();
//    if (currentMillis - previousMillis >= setupBlinkPeriod){
//      previousMillis = currentMillis;
//      if (led1State == LOW){
//        led1State = HIGH;
//        led2State = LOW;
//      }else{
//        led1State = LOW;
//        led2State = LOW;
//      }
//      digitalWrite(led1, led1State);
//      digitalWrite(led2, led2State);
//    }
}


void setup() {

  // Initialize NRF24L01
//  Serial.begin(2000000); //for testing, can be removed later
  radio.begin();
  radio.setChannel(channel);
  radio.setDataRate(RF24_250KBPS);
  radio.setPALevel(RF24_PA_HIGH);
  radio.openWritingPipe(wAddress);
  radio.openReadingPipe(1, rAddress);
  radio.startListening();
  pinMode(padSelect, INPUT);
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(up, OUTPUT); //up
  pinMode(down, OUTPUT); //down
  pinMode(left, OUTPUT); //left
  pinMode(right, OUTPUT); //right
  pinMode(start, OUTPUT); //start
  pinMode(select, OUTPUT); //select
  pinMode(buttona, OUTPUT); //A
  pinMode(buttonb, OUTPUT); //B
  pinMode(buttonc, OUTPUT); //C
  pinMode(buttond, OUTPUT); //D
    digitalWrite(up, HIGH);
    digitalWrite(down, HIGH);
    digitalWrite(left, HIGH);
    digitalWrite(right, HIGH);
    digitalWrite(select, HIGH);
    digitalWrite(start, HIGH);
    digitalWrite(buttona, HIGH);
    digitalWrite(buttonb, HIGH);
    digitalWrite(buttonc, HIGH);
    digitalWrite(buttond, HIGH);  
  DDRD = B11111100; //PD4-PD7 OUTPUTS
  DDRC = B00000101; //PC0 OUTPUT, PC1 INPUT
}

// Last state of the buttons
int lastButtonState[12] = {0,0,0,0,0,0,0,0,0,0,0,0};

void loop() {
 if (radio.available()) {
    radio.read(&radioSerialr, sizeof(radioSerialr));
 }  
  LEDcontrol();
//  while (paired==false){
//    pair();
//  //    Serial.println(PriUint64<HEX>(wAddress));
//Serial.println((PINC&B00000010));
//char test[15];
//sprintf(test,"%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d",radioSerialr[0],radioSerialr[1],radioSerialr[2],radioSerialr[3],radioSerialr[4],radioSerialr[5],radioSerialr[6],radioSerialr[7],radioSerialr[8],radioSerialr[9],radioSerialr[10],radioSerialr[11],radioSerialr[12],radioSerialr[13],radioSerialr[14]);
//Serial.println(test);
//char test2[15];
//sprintf(test2,"%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d",radioSerialw[0],radioSerialw[1],radioSerialw[2],radioSerialw[3],radioSerialw[4],radioSerialw[5],radioSerialw[6],radioSerialw[7],radioSerialw[8],radioSerialw[9],radioSerialw[10],radioSerialw[11],radioSerialw[12],radioSerialw[13],radioSerialw[14]);
//Serial.println(test2);

if ((!PINC & B00000010)){
if (radioSerialr[2] == 1) {
  PORTC &=~(1<<PORTC0);
}
  if (radioSerialr[1] == 1){
    PORTD &=~(1<<PORTD6);
  }else{
    PORTD |= (1<<PORTD6);
  }
  if (radioSerialr[4] == 1){
    PORTD &=~(1<<PORTD4);
  }else{
    PORTD |= (1<<PORTD4);
  }
  if (radioSerialr[5] == 1){
    PORTD &=~(1<<PORTD5);
  }else{
    PORTD |= (1<<PORTD5);
  }
  if (radioSerialr[0] == 1){
    PORTC &=~(1<<PORTC2);
  }else{
    PORTC |= (1<<PORTC2);
  }
}
if ((PINC & B00000010)){
  if (radioSerialr[1] == 1){
    PORTD &=~(1<<PORTD6);
  }else{
    PORTD |= (1<<PORTD6);
  }
  if (radioSerialr[4] == 1){
    PORTD &=~(1<<PORTD4);
  }else{
    PORTD |= (1<<PORTD4);
  }
  if (radioSerialr[2] == 1){
    PORTC &=~(1<<PORTC0);
  }else{
    PORTC |= (1<<PORTC0);
  }
  if (radioSerialr[3] == 1){
    PORTD &=~(1<<PORTD7);
  }else{
    PORTD |= (1<<PORTD7);
  }
  if (radioSerialr[6] == 1){
    PORTD &=~(1<<PORTD5);
  }else{
    PORTD |= (1<<PORTD5);
  }
  if (radioSerialr[7] == 1){
    PORTC &=~(1<<PORTC2);
  }else{
    PORTC |= (1<<PORTC2);
  }
}


}

I’m thinking it just isn’t running fast enough, if I query the truth of the select pin every time I query the status of my buttons it behaves very erraticly. The A and Start buttons begin to work but not as the right buttons and everything is very unstable. Kind of at a loss as to what to try next really.

I would seriously abandon your attempts at port manipulation and get your code working using the more standard digitalRead() and digitalWrite() functions.

AFTER your code is working AND if, for some reason, it is not doing so fast enough, you might want to consider this. It almost never is the case...

if ((!PINC & B00000010)){

That's not going to work right. This will evaluate !PINC first, which will most likely end up 0 (or 1 if all pins are LOW) and then it will & with 2 which will always give 0.

The ! should be outside the parens:

if (!(PINC & B00000010)){

AFTER your code is working AND if, for some reason, it is not doing so fast enough, you might want to consider this.

This is good advice:
Step1) write code using digitalRead()/digitalWrite()
Step2) if too slow, download one of the digitalWriteFast libraries, and substitute those functions.
Step3) If still to slow, see if you can Optimize using direct Port IO (might be possible for certain multi-bit cases or something.)
(Somewhere in there should also be a "try a faster board." Probably around 1.5? If you are using the normal functions, switching boards should be trivial. Boards that run up to 180MHz or so are common.)