ATmega 32U4 Port manipulation in button matrix

Hello fellow hobbyists!

I'm a simple sim racer trying to build my own sim racing steering wheel. Wheel is almost finished; got my PCB working with two 32U4s and a usb hub. One of the 32U4's im coding with the Joystick library, the other one is for controlling LEDs on the wheel, and is not relevant for this thread.

Connected to the 32U4 are a bunch of buttons and encoders in a 7x7 matrix. My current code is working great (posted below, work in progress) for buttons and toggle switches, but not so great for the encoders. The for loops scanning the matrix is simply not fast enough to catch the encoder states (2 bit incremental encoders, two signal pins and one ground pin, signal pins cycle through 00, 01, 11, 10) to make them useful. Also, two of my encoders (on 7-way switches) are sort of "pulse" encoders, that are in "11" and "00" on detents, and "01" or "10" between detents. The code doesnt even register the "01" and "10" states. When wiring the encoders to designated pins there are no issues, as expected, but I have to make this work with the matrix.

I've tried reading one of the encoders on every row loop (/*-ed out in the code), it is then able to catch the "01"s and the "10"s, but not optimal at all. And scanning all 6 encoders on every row (or even column) loop would likely slow it down too much.

I've read about port registers, and that pin setup and output setup can be done with ALOT less clock cycles that way. It could maybe speed things up so much that I could get the encoders working - or even afford to scan every encoder in the column loop. I'm having a hard time figuring out how to change my matrix scanning code to using port manipulation. Anyone got some pointers?

(I am aware of interrupts, but there are a limited number of pins on the MCU, and I have 6 encoders in the wheel. They have to be in the button matrix.)

Kind regards,
Andreas


/*
  Dahl Design SW1 Firmware v1.0. By Andreas Dahl July 2021
  Includes single function for all buttons and switches
*/

//4 bit encoder and button matrix

#include <Joystick.h>
#include <MultiMap.h>

#define BUTTONCOUNT 69

//Defining joystick parameters

Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_GAMEPAD,
                   BUTTONCOUNT,    //Button count
                   0,              //Hat switch count
                   true,           //X axis -> Clutch paddles
                   true,          //Y axis -> Clutch bite, only for dash visualization
                   false,          //Z axis
                   false,          //Rx axis
                   false,          //Ry axis
                   false,          //Rz axis
                   false,          //Rudder
                   false,          //Throttle
                   false,          //Accelerator
                   false,          //Brake
                   false);         //Steering

//Row and column pins

uint8_t row[] = {11, 3, 2, 30, 4, 12, 6};
const uint8_t rowCount = sizeof(row) / sizeof(row[0]);

uint8_t col[] = {7, A0, 13, 5, 10, 9, 8};
const uint8_t colCount = sizeof(col) / sizeof(col[0]);

//Analog pins

uint8_t rotRPin = A1;
uint8_t rotLPin = A4;
uint8_t clutchRPin = A2;
uint8_t clutchLPin = A5;
uint8_t bitePin = A3;

//Status of all buttons

uint8_t state[rowCount][colCount] = {
  {0, 0, 0, 0, 0, 0, 0}, //ROW 1,
  {0, 0, 0, 0, 0, 0, 0}, //ROW 2
  {0, 0, 0, 0, 0, 0, 0}, //ROW 3
  {0, 0, 0, 0, 0, 0, 0}, //ROW 4
  {0, 0, 0, 0, 0, 0, 0}, //ROW 5
  {0, 0, 0, 0, 0, 0, 0}, //ROW 6
  {0, 0, 0, 0, 0, 0, 0}, //ROW 7
};

/*
  Row 1, column 1 - 7
  status[0][0] --->  Right grip encoder A-channel *
  status[0][1] --->  Right grip encoder B-channel *
  status[0][2] --->  Right 3-way (ON)-OFF-(ON) push UP *
  status[0][3] --->  Right 3-way (ON)-OFF-(ON) push DOWN *
  status[0][4] --->  Right top 9N OFF-(ON) pushbutton *
  status[0][5] --->  Right middle 9N OFF-(ON) pushbutton *
  status[0][6] --->  Right lower 9N OFF-(ON) pushbutton *

  Row 2, column 1-7
  status[1][0] --->  Right 7-way down press
  status[1][1] --->  Right 7-way left press
  status[1][2] --->  Right 7-way encoder A-channel
  status[1][3] --->  Right 7-way right press
  status[1][4] --->  Right 7-way push button
  status[1][5] --->  Right 7-way encoder B-channel
  status[1][6] --->  Right 7-way up press

  Row 3, column 1-7
  status[2][0] --->  Middle top back-button *
  status[2][1] --->  Right top back-button *
  status[2][2] --->  Upshift paddle *
  status[2][3] --->  Right accessory paddle *
  status[2][4] --->  Launch control toggle *
  status[2][5] --->  Right thumb encoder A-channel *
  status[2][6] --->  Right thumb encoder B-channel *

  Row 4, column 1-7
  status[3][0] --->  Left grip encoder A-channel *
  status[3][1] --->  Left grip encoder B-channel *
  status[3][2] --->  Left 3-way (ON)-OFF-(ON) push UP *
  status[3][3] --->  Left 3-way (ON)-OFF-(ON) push DOWN *
  status[3][4] --->  Left top 9N OFF-(ON) pushbutton *
  status[3][5] --->  Left middle 9N OFF-(ON) pushbutton *
  status[3][6] --->  Left lower 9N OFF-(ON) pushbutton *

  Row 5, column 1-7
  status[4][0] --->  Left 7-way left press
  status[4][1] --->  Left 7-way encoder A-channel
  status[4][2] --->  Left 7-way encoder B-channel
  status[4][3] --->  Left 7-way up press
  status[4][4] --->  Left 7-way push button
  status[4][5] --->  Left 7-way down press
  status[4][6] --->  Left 7-way right press

  Row 6, column 1-7
  status[5][0] --->  Left thumb encoder A-channel *
  status[5][1] --->  Left thumb encoder B-channel *
  status[5][2] --->  Ignition toggle *
  status[5][3] --->  Left top back-button *
  status[5][4] --->  Left accessory paddle *
  status[5][5] --->  Downshift paddle *
  status[5][6] --->  Radio OFF-ON latching pushbutton *

  //ROW 7, column 1-7
  status[6][0] --->  Pit limiter 9N OFF-(ON) pushbutton *
  status[6][1] --->  Bite point lock toggle switch *
  status[6][2] --->  Engine start button *
  status[1][0] --->  Col 4 empty
  status[1][0] --->  Col 5 empty
  status[1][0] --->  Col 6 empty
  status[1][0] --->  Col 7 empty

*/

//List of buttons

//Button 1  ---> [0][4] --->  Right top 9N OFF-(ON) pushbutton
//Button 2  ---> [0][5] --->  Right middle 9N OFF-(ON) pushbutton
//Button 3  ---> [0][6] --->  Right lower 9N OFF-(ON) pushbutton
//Button 4  ---> [3][4] --->  Left top 9N OFF-(ON) pushbutton
//Button 5  ---> [3][5] --->  Left middle 9N OFF-(ON) pushbutton
//Button 6  ---> [3][6] --->  Left lower 9N OFF-(ON) pushbutton
//Button 7  ---> [2][3] --->  Right accessory paddle
//Button 8  ---> [5][4] --->  Left accessory paddle
//Button 9  ---> [2][2] --->  Upshift paddle
//Button 10 ---> [5][5] --->  Downshift paddle
//Button 11 ---> [0][2] --->  Right 3-way (ON)-OFF-(ON) push UP
//Button 12 ---> [0][3] --->  Right 3-way (ON)-OFF-(ON) push DOWN
//Button 13 ---> [3][2] --->  Left 3-way (ON)-OFF-(ON) push UP
//Button 14 ---> [3][3] --->  Left 3-way (ON)-OFF-(ON) push DOWN

//Button 15 ---> [0][0] --->  Right grip encoder A-channel (CW)
//Button 16 ---> [0][1] --->  Right grip encoder B-channel (CCW)
//Button 17 ---> [3][0] --->  Left grip encoder A-channel (CW)
//Button 18 ---> [3][1] --->  Left grip encoder B-channel (CCW)
//Button 19 ---> [2][5] --->  Right thumb encoder A-channel (CW)
//Button 20 ---> [2][6] --->  Right thumb encoder B-channel (CCW)
//Button 21 ---> [5][0] --->  Left thumb encoder A-channel (CW)
//Button 22 ---> [5][1] --->  Left thumb encoder B-channel (CCW)

//Button 23 ---> [6][0] --->  Pit limiter 9N OFF-(ON) pushbutton
//Button 24 ---> [5][6] --->  Radio OFF-ON latching pushbutton

//Button 25 ---> [1][6] --->  Right 7-way up press
//Button 26 ---> [1][3] --->  Right 7-way right press
//Button 27 ---> [1][0] --->  Right 7-way down press
//Button 28 ---> [1][1] --->  Right 7-way left press
//Button 29 ---> [1][4] --->  Right 7-way push button
//Button 30 ---> [1][2] --->  Right 7-way encoder A-channel (CW)
//Button 31 ---> [1][5] --->  Right 7-way encoder B-channel (CCW)

//Button 32 ---> [4][3] --->  Left 7-way up press
//Button 33 ---> [4][6] --->  Left 7-way right press
//Button 34 ---> [4][5] --->  Left 7-way down press
//Button 35 ---> [4][0] --->  Left 7-way left press
//Button 36 ---> [4][4] --->  Left 7-way push button
//Button 37 ---> [4][1] --->  Left 7-way encoder A-channel (CW)
//Button 38 ---> [4][2] --->  Left 7-way encoder B-channel (CCW)

//Button 39 ---> [2][1] --->  Right top back-button
//Button 40 ---> [2][0] --->  Middle top back-button
//Button 41 ---> [5][3] --->  Left top back-button
//Button 42 ---> [2][4] --->  Launch control toggle
//Button 43 ---> [5][2] --->  Ignition toggle
//Button 44 ---> [6][2] --->  Engine start button
//Button 45 ---> [6][1] --->  Bite point lock toggle switch


uint8_t enc1UpCounter = 0;    //Encoder 1 up
uint8_t enc1DownCounter = 0;  //Encoder 1 down
uint8_t enc1Active = 0;       //Encoder 1 active state
uint8_t enc1New = 0;          //Encoder 1 registered state

uint8_t enc2UpCounter = 0;    //Encoder 2 up
uint8_t enc2DownCounter = 0;  //Encoder 2 down
uint8_t enc2Active = 0;       //Encoder 2 active state
uint8_t enc2New = 0;          //Encoder 2 registered state

uint8_t enc3UpCounter = 0;    //Encoder 3 up
uint8_t enc3DownCounter = 0;  //Encoder 3 down
uint8_t enc3Active = 0;       //Encoder 3 active state
uint8_t enc3New = 0;          //Encoder 3 registered state

uint8_t enc4UpCounter = 0;    //Encoder 4 up
uint8_t enc4DownCounter = 0;  //Encoder 4 down
uint8_t enc4Active = 0;       //Encoder 4 active state
uint8_t enc4New = 0;          //Encoder 4 registered state

uint8_t enc5UpCounter = 0;    //Encoder 5 up
uint8_t enc5DownCounter = 0;  //Encoder 5 down

uint8_t enc6UpCounter = 0;    //Encoder 6 up
uint8_t enc6DownCounter = 0;  //Encoder 6 down

uint8_t b43Counter = 0;     //Button 43 counter
uint8_t b43Active = 3;      //Button 43 active state

  bool lastState;
  bool hit0;
  bool hit1;
  int countere5 = 0;

  

//Global parameters
const uint8_t debounceCount = 2;

//Clutch multiMap arrays
int inR [11] = {175, 180, 190, 205, 230, 270, 320, 370, 425, 490, 565};
int outR [11] = {0, 102, 204, 307, 409, 512, 614, 716, 819, 921, 1023};

int inL [11] = {536, 620, 680, 730, 780, 820, 840, 860, 869, 876, 882}; 
int outL [11] = {0, 102, 204, 307, 409, 512, 614, 716, 819, 921, 1023}; 

int inBite [11] = {3, 20, 40, 170, 400, 600, 900, 930, 960, 990, 1015};
int outBite [11] = {0, 102, 204, 307, 409, 512, 614, 716, 819, 921, 1023};

uint8_t mapSize = 11;

//-----------------------------------------------------------------------------
//-------------------------------SETUP-----------------------------------------
//-----------------------------------------------------------------------------

void setup () {

  for (int i = 0; i < colCount; i ++) {     //  Disable all column pins
    pinMode(col[i], INPUT);
  }

  for (int i = 0; i < rowCount; i ++) {     //  Disable all row pins
    pinMode(row[i], INPUT);
  }

  Joystick.begin(); //Start joystick library magic

}


//-----------------------------------------------------------------------------
//-------------------------------LOOP------------------------------------------
//-----------------------------------------------------------------------------

uint16_t bite = analogRead(bitePin);

void loop() {

  //Beginning with matrix logics, checking status on all button connectors.

  //Based on monitoring the flow to each row pin, setting the pin to GND
  for (int i = 0; i < rowCount; i++) { //Engaging row pin after row pin
    /*pinMode(row[1],OUTPUT);
    digitalWrite(row[1],LOW);
    pinMode(col[2], INPUT_PULLUP);
    if (digitalRead(col[2])) {state[1][2] = 1;} else {state[1][2] = 0;}
    pinMode(col[2], INPUT);
    pinMode(col[5], INPUT_PULLUP);
    if (digitalRead(col[5])) {state[1][5] = 1;} else {state[1][5] = 0;}
    pinMode(col[5], INPUT);
    pinMode(row[1],INPUT);
    */
    pinMode(row[i], OUTPUT);
    digitalWrite(row[i], LOW);

    for (int u = 0; u < colCount; u++) { //Checking all column pins on this row pin
      pinMode(col[u], INPUT_PULLUP);
      if (digitalRead(col[u]) == 0) {
        state[i][u] = 1;
      } else {
        state[i][u] = 0;
      }
      pinMode(col[u], INPUT); //Disengage the column pin
    }

    pinMode(row[i], INPUT); //Disengage the row pin
  }
  //------------------------------
  //Button debounce and activation
  //------------------------------

  //Button 1
  Joystick.setButton(0, state[0][4]);

  //Button 2
  Joystick.setButton(1, state[0][5]);

  //Button 3
  Joystick.setButton(2, state[0][6]);

  //Button 4
  Joystick.setButton(3, state[3][4]);

  //Button 5
  Joystick.setButton(4, state[3][5]);

  //Button 6
  Joystick.setButton(5, state[3][6]);

  //Button 7
  Joystick.setButton(6, state[2][3]);

  //Button 8
  Joystick.setButton(7, state[5][4]);

  //Button 9
  Joystick.setButton(8, state[2][2]);
  
  //Button 10
  Joystick.setButton(9, state[5][5]);

  //Button 11
  Joystick.setButton(10, state[0][2]);

  //Button 12
  Joystick.setButton(11, state[0][3]);

  //Button 13
  Joystick.setButton(12, state[3][2]);

  //Button 14
  Joystick.setButton(13, state[3][3]);

  //Button 23
  Joystick.setButton(22, state[6][0]);

  //Button 24
  Joystick.setButton(23, state[5][6]);

  //Button 25
  Joystick.setButton(24, state[1][6]);

  //Button 26
  Joystick.setButton(25, state[1][3]);

  //Button 27
  Joystick.setButton(26, state[1][0]);

  //Button 28
  Joystick.setButton(27, state[1][1]);

  //Button 29 (Right 7-Way pushbutton)
  if (state[1][6] + state[1][3] + state[1][0] + state[1][1] == 0 && state[1][4] == 1) {
    Joystick.pressButton(28);
  } else {
    Joystick.releaseButton(28);
  }

  //Button 32
  Joystick.setButton(31, state[4][3]);

  //Button 33
  Joystick.setButton(32, state[4][6]);

  //Button 34
  Joystick.setButton(33, state[4][5]);
  
  //Button 35
  Joystick.setButton(34, state[4][0]);

  //Button 36 (Left 7-Way pushbutton)
  if (state[4][3] + state[4][6] + state[4][5] + state[4][0] == 0 && state[4][4] == 1) {
    Joystick.pressButton(35);
  } else {
    Joystick.releaseButton(35);
  }

  //Button 39
  Joystick.setButton(38, state[2][1]);

  //Button 40
  Joystick.setButton(39, state[2][0]);

  //Button 41
  Joystick.setButton(40, state[5][3]);

  //Button 42
  Joystick.setButton(41, state[2][4]);

  //Button 43 (Pulsing toggle)
  if (state[5][2] != b43Active) {
    b43Counter++;
    Joystick.setButton(42,1);
  }
  
  if (b43Counter > debounceCount) {
    Joystick.setButton(42,0);
    b43Counter = 0;
    b43Active = state[5][2];
  }
  
  //Button 44
  Joystick.setButton(43, state[6][2]);

  //Button 45
  Joystick.setButton(44, state[6][1]);


  //Encoders

  //Encoder 1 -> Right grip encoder

  if (!state[0][0] && !state[0][1]) {enc1New = 1;}
  if (!state[0][0] && state[0][1]) {enc1New = 2;}
  if (state[0][0] && state[0][1]) {enc1New = 3;}
  if (state[0][0] && !state[0][1]) {enc1New = 4;}
  
  if (enc1Active == 0) {enc1Active = enc1New;}
  
  if ((enc1New > enc1Active && !(enc1New == 4 && enc1Active == 1)) || (enc1New == 1 && enc1Active == 4)) {
    Joystick.pressButton(14);
    Joystick.releaseButton(15);
    enc1UpCounter++;
  } 
  
  if ((enc1New < enc1Active && !(enc1New == 1 && enc1Active == 4)) || (enc1New == 4 && enc1Active == 1)) {
    Joystick.pressButton(15);
    Joystick.releaseButton(14);
    enc1DownCounter++;
  }
  
  if (enc1DownCounter > debounceCount || enc1UpCounter > debounceCount) {
    enc1Active = enc1New;
    enc1DownCounter = 0;
    enc1UpCounter = 0;
    Joystick.releaseButton(14);
    Joystick.releaseButton(15);
  }
  
  //Encoder 2 -> Left grip encoder

  if (!state[3][0] && !state[3][1]) {enc2New = 1;}
  if (!state[3][0] && state[3][1]) {enc2New = 2;}
  if (state[3][0] && state[3][1]) {enc2New = 3;}
  if (state[3][0] && !state[3][1]) {enc2New = 4;}
  
  if (enc2Active == 0) {enc2Active = enc2New;}
  
  if ((enc2New > enc2Active && !(enc2New == 4 && enc2Active == 1)) || (enc2New == 1 && enc2Active == 4)) {
    Joystick.pressButton(16);
    Joystick.releaseButton(17);
    enc2UpCounter++;
  } 
  
  if ((enc2New < enc2Active && !(enc2New == 1 && enc2Active == 4)) || (enc2New == 4 && enc2Active == 1)) {
    Joystick.pressButton(17);
    Joystick.releaseButton(16);
    enc2DownCounter++;
  }
  
  if (enc2DownCounter > debounceCount || enc2UpCounter > debounceCount) {
    enc2Active = enc2New;
    enc2DownCounter = 0;
    enc2UpCounter = 0;
    Joystick.releaseButton(16);
    Joystick.releaseButton(17);
  }

  //Encoder 3 -> Right thumb encoder

  if (!state[2][5] && !state[2][6]) {enc3New = 1;}
  if (!state[2][5] && state[2][6]) {enc3New = 2;}
  if (state[2][5] && state[2][6]) {enc3New = 3;}
  if (state[2][5] && !state[2][6]) {enc3New = 4;}
  
  if (enc3Active == 0) {enc3Active = enc3New;}
  
  if ((enc3New > enc3Active && !(enc3New == 4 && enc3Active == 1)) || (enc3New == 1 && enc3Active == 4)) {
    Joystick.pressButton(18);
    Joystick.releaseButton(19);
    enc3UpCounter++;
  } 
  
  if ((enc3New < enc3Active && !(enc3New == 1 && enc3Active == 4)) || (enc3New == 4 && enc3Active == 1)) {
    Joystick.pressButton(19);
    Joystick.releaseButton(18);
    enc3DownCounter++;
  }
  
  if (enc3DownCounter > debounceCount || enc3UpCounter > debounceCount) {
    enc3Active = enc3New;
    enc3DownCounter = 0;
    enc3UpCounter = 0;
    Joystick.releaseButton(18);
    Joystick.releaseButton(19);
  }
  
  //Encoder 4 -> Left thumb encoder

  if (!state[5][0] && !state[5][1]) {enc4New = 1;}
  if (!state[5][0] && state[5][1]) {enc4New = 2;}
  if (state[5][0] && state[5][1]) {enc4New = 3;}
  if (state[5][0] && !state[5][1]) {enc4New = 4;}
  
  if (enc4Active == 0) {enc4Active = enc4New;}
  
  if ((enc4New > enc4Active && !(enc4New == 4 && enc4Active == 1)) || (enc4New == 1 && enc4Active == 4)) {
    Joystick.pressButton(20);
    Joystick.releaseButton(21);
    enc4UpCounter++;
  } 
  
  if ((enc4New < enc4Active && !(enc4New == 1 && enc4Active == 4)) || (enc4New == 4 && enc4Active == 1)) {
    Joystick.pressButton(21);
    Joystick.releaseButton(20);
    enc4DownCounter++;
  }
  
  if (enc4DownCounter > debounceCount || enc4UpCounter > debounceCount) {
    enc4Active = enc4New;
    enc4DownCounter = 0;
    enc4UpCounter = 0;
    Joystick.releaseButton(20);
    Joystick.releaseButton(21);
  }
 
  // Encoder 5 -> Right 7-way encoder

  if(!state[1][2] && state[1][5]) {
    hit0 = 1;
  }
  if(state[1][2] && !state[1][5]) {
    hit1 = 1;
  }

  if(hit0 == 1 && lastState == 1 || (hit1 == 1 && lastState == 0)) {
    Joystick.pressButton(29);
    countere5++; 
  }
  
   if(hit0 == 1 && lastState == 0 || (hit1 == 1 && lastState == 1)) {
    Joystick.pressButton(30);
    countere5++;
  } 


   if (countere5 > debounceCount) {
    countere5 = 0;
    hit1 = 0;
    hit0 = 0;
    Joystick.releaseButton(29);
    Joystick.releaseButton(30);
   }
   
   if(state[1][2] && state[1][5]) {
    lastState = 1;
  }
  if(!state[1][2] && !state[1][5]) {
    lastState = 0;
  }
   
  

  // Encoder 6 -> Left 7-way encoder

  bool oneFetchE6;
  bool zeroFetchE6;

  String statusStringE6 = String(state[4][1]) + String(state[4][2]);

  if (statusStringE6 == "11") {
    oneFetchE6 == 1;
    zeroFetchE6 == 0;
    Joystick.releaseButton(36);
    Joystick.releaseButton(37);
  }
  if (statusStringE6 == "00") {
    zeroFetchE6 == 1;
    oneFetchE6 == 0;
    Joystick.releaseButton(36);
    Joystick.releaseButton(37);
  }

  if (statusStringE6 == "10" && oneFetchE6 == 1) {
    Joystick.pressButton(36);
    Joystick.releaseButton(37);
  }
  if (statusStringE6 == "10" && zeroFetchE6 == 1) {
    Joystick.pressButton(37);
    Joystick.releaseButton(36);
  }
  if (statusStringE6 == "01" && oneFetchE6 == 1) {
    Joystick.pressButton(37);
    Joystick.releaseButton(36);
  }
  if (statusStringE6 == "01" && zeroFetchE6 == 1) {
    Joystick.pressButton(36);
    Joystick.releaseButton(37);
  }

  //Analog inputs; clutches, bitepoint and 12-way switches

  uint16_t rotR = analogRead(rotRPin);        // Buttons 46 - 57 ---> 12-position switch right
  uint16_t rotL = analogRead(rotLPin);        // Buttons 58 - 69 ---> 12-position switch left
  uint16_t clutchR = analogRead(clutchRPin);
  uint16_t clutchL = analogRead(clutchLPin);
  if (state[6][1]) {bite = analogRead(bitePin);}

 

  //Right 12-way switch
  rotR = map (rotR, 0, 1015, 0, 11);
  if (rotR == 0) {
    Joystick.pressButton(45);
  } else {
    Joystick.releaseButton(45);
  }
  if (rotR == 1) {
    Joystick.pressButton(46);
  } else {
    Joystick.releaseButton(46);
  }
  if (rotR == 2) {
    Joystick.pressButton(47);
  } else {
    Joystick.releaseButton(47);
  }
  if (rotR == 3) {
    Joystick.pressButton(48);
  } else {
    Joystick.releaseButton(48);
  }
  if (rotR == 4) {
    Joystick.pressButton(49);
  } else {
    Joystick.releaseButton(49);
  }
  if (rotR == 5) {
    Joystick.pressButton(50);
  } else {
    Joystick.releaseButton(50);
  }
  if (rotR == 6) {
    Joystick.pressButton(51);
  } else {
    Joystick.releaseButton(51);
  }
  if (rotR == 7) {
    Joystick.pressButton(52);
  } else {
    Joystick.releaseButton(52);
  }
  if (rotR == 8) {
    Joystick.pressButton(53);
  } else {
    Joystick.releaseButton(53);
  }
  if (rotR == 9) {
    Joystick.pressButton(54);
  } else {
    Joystick.releaseButton(54);
  }
  if (rotR == 10) {
    Joystick.pressButton(55);
  } else {
    Joystick.releaseButton(55);
  }
  if (rotR == 11) {
    Joystick.pressButton(56);
  } else {
    Joystick.releaseButton(56);
  }

  //Left 12-way switch
  rotL = map (rotL, 0, 1015, 0, 11);
  if (rotL == 0) {
    Joystick.pressButton(57);
  } else {
    Joystick.releaseButton(57);
  }
  if (rotL == 1) {
    Joystick.pressButton(58);
  } else {
    Joystick.releaseButton(58);
  }
  if (rotL == 2) {
    Joystick.pressButton(59);
  } else {
    Joystick.releaseButton(59);
  }
  if (rotL == 3) {
    Joystick.pressButton(60);
  } else {
    Joystick.releaseButton(60);
  }
  if (rotL == 4) {
    Joystick.pressButton(61);
  } else {
    Joystick.releaseButton(61);
  }
  if (rotL == 5) {
    Joystick.pressButton(62);
  } else {
    Joystick.releaseButton(62);
  }
  if (rotL == 6) {
    Joystick.pressButton(63);
  } else {
    Joystick.releaseButton(63);
  }
  if (rotL == 7) {
    Joystick.pressButton(64);
  } else {
    Joystick.releaseButton(64);
  }
  if (rotL == 8) {
    Joystick.pressButton(65);
  } else {
    Joystick.releaseButton(65);
  }
  if (rotL == 9) {
    Joystick.pressButton(66);
  } else {
    Joystick.releaseButton(66);
  }
  if (rotL == 10) {
    Joystick.pressButton(67);
  } else {
    Joystick.releaseButton(67);
  }
  if (rotL == 11) {
    Joystick.pressButton(68);
  } else {
    Joystick.releaseButton(68);
  }

  
  //Clutch and bite logics
  clutchR = multiMap(clutchR, inR, outR, mapSize);
  clutchR = 1023-clutchR;
  
  clutchL = multiMap(clutchL, inL, outL, mapSize);
  
  bite = multiMap(bite,inBite,outBite, mapSize);
  Joystick.setYAxis(bite);

  float floatbite = bite;
  
  float fraction = floatbite/1023;
  


  clutchL = clutchL * fraction;

  if (clutchL > clutchR) {
    Joystick.setXAxis(clutchL);
  } else {Joystick.setXAxis(clutchR);}
  

}

int multiMap(int val, int* _in, int* _out, uint8_t size)
{
  // take care the value is within range
  // val = constrain(val, _in[0], _in[size-1]);
  if (val <= _in[0]) return _out[0];
  if (val >= _in[size-1]) return _out[size-1];

  // search right interval
  uint8_t pos = 1;  // _in[0] allready tested
  while(val > _in[pos]) pos++;

  // this will handle all exact "points" in the _in array
  if (val == _in[pos]) return _out[pos];

  // interpolate in the right segment for the rest
  return (val - _in[pos-1]) * (_out[pos] - _out[pos-1]) / (_in[pos] - _in[pos-1]) + _out[pos-1];
}
  

Each 'port' on the chip has a letter name and controls 8 pins. Each 'port' has three registers:
PORTx: Output
PINx: Input
DDRx: Data Direction Register (pinMode INPUT or OUTPUT).

Figure out what ports and pins your data lines are on. You can do that by looking in the /variant/leonardo/pins_arduino.h:

// ATMEL ATMEGA32U4 / ARDUINO LEONARDO
//
// D0				PD2					RXD1/INT2
// D1				PD3					TXD1/INT3
// D2				PD1		SDA			SDA/INT1
// D3#				PD0		PWM8/SCL	OC0B/SCL/INT0
// D4		A6		PD4					ADC8
// D5#				PC6		???			OC3A/#OC4A
// D6#		A7		PD7		FastPWM		#OC4D/ADC10
// D7				PE6					INT6/AIN0
//
// D8		A8		PB4					ADC11/PCINT4
// D9#		A9		PB5		PWM16		OC1A/#OC4B/ADC12/PCINT5
// D10#		A10		PB6		PWM16		OC1B/0c4B/ADC13/PCINT6
// D11#				PB7		PWM8/16		0C0A/OC1C/#RTS/PCINT7
// D12		A11		PD6					T1/#OC4D/ADC9
// D13#				PC7		PWM10		CLK0/OC4A
//
// A0		D18		PF7					ADC7
// A1		D19		PF6					ADC6
// A2		D20 	PF5					ADC5
// A3		D21 	PF4					ADC4
// A4		D22		PF1					ADC1
// A5		D23 	PF0					ADC0
//
// New pins D14..D17 to map SPI port to digital pins
//
// MISO		D14		PB3					MISO,PCINT3
// SCK		D15		PB1					SCK,PCINT1
// MOSI		D16		PB2					MOSI,PCINT2
// SS		D17		PB0					RXLED,SS/PCINT0
//
// TXLED	D30		PD5					XCK1
// RXLED	D17	    PB0
// HWB				PE2					HWB

Your row pins {11, 3, 2, 30, 4, 12, 6} are:
PB7, PD0, PD1, PD5, PD4, PD6, PD7

Your column pins {7, A0, 13, 5, 10, 9, 8} are:
PE6, PF7, PC7, PC6, PB6, PB5, PB4

That means you need PORTB and PORTD for the rows and PORTE, PORTF, PORTC, and PORTB for the columns.

You have to be careful not to change the state of any other pin when you change a bit in a register.

Thanks!

I've attempted to rebuild my code changing DDR and PORT-registers, seemed to compile fine, but now my MCU isnt recognized anymore:p Ill try to burn bootloader again and look over my code.

It's easy to disrupt pins 0 and 1 if you don't bitmask when you set the directions.

So this is the code I made, havent tried installing bootloader again. Is there anything fundamentally wrong in the way I do port manipulation here?

Just did the first 4 rows, and the 4th row writing to the same variables as row 3 (I got tired and just wanted to test the code), but that shouldnt make a difference?


/*
  Dahl Design SW1 Firmware v1.0. By Andreas Dahl July 2021
  Includes single function for all buttons and switches, debouncer for all momentary buttons/toggles and encoders.
*/

#include <Joystick.h>
#include <MultiMap.h>

#define BUTTONCOUNT 69
#define rotRPin A1
#define rotLPin A4
#define clutchRPin A2
#define clutchLPin A5
#define bitePin A3
#define rowCount 7
#define colCount 7

//Defining joystick parameters

Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_GAMEPAD,
                   BUTTONCOUNT,    //Button count
                   0,              //Hat switch count
                   true,           //X axis -> Clutch paddles
                   true,          //Y axis -> Clutch bite, only for dash visualization
                   false,          //Z axis
                   false,          //Rx axis
                   false,          //Ry axis
                   false,          //Rz axis
                   false,          //Rudder
                   false,          //Throttle
                   false,          //Accelerator
                   false,          //Brake
                   false);         //Steering


//Status of all buttons


//  Row 1, column 1 - 7
  uint8_t enc1A;  // ---> [0][0] --->  Right grip encoder A-channel *
  uint8_t enc1B;  // ---> [0][1] --->  Right grip encoder B-channel *
  uint8_t b11;    // ---> [0][2] --->  Right 3-way (ON)-OFF-(ON) push UP *
  uint8_t b12;    // ---> [0][3] --->  Right 3-way (ON)-OFF-(ON) push DOWN *
  uint8_t b1;     // ---> [0][4] --->  Right top 9N OFF-(ON) pushbutton *
  uint8_t b2;     // ---> [0][5] --->  Right middle 9N OFF-(ON) pushbutton *
  uint8_t b3;     // ---> [0][6] --->  Right lower 9N OFF-(ON) pushbutton *

//  Row 2, column 1-7
  uint8_t b27;    // ---> [1][0] --->  Right 7-way down press
  uint8_t b28;    // ---> [1][1] --->  Right 7-way left press
  uint8_t enc5A;  // ---> [1][2] --->  Right 7-way encoder A-channel
  uint8_t b26;    // ---> [1][3] --->  Right 7-way right press
  uint8_t b29;    // ---> [1][4] --->  Right 7-way push button
  uint8_t enc5B;  // ---> [1][5] --->  Right 7-way encoder B-channel
  uint8_t b25;    // ---> [1][6] --->  Right 7-way up press

//  Row 3, column 1-7
  uint8_t b40;    // ---> [2][0] --->  Middle top back-button *
  uint8_t b39;    // ---> [2][1] --->  Right top back-button *
  uint8_t b9;     // ---> [2][2] --->  Upshift paddle *
  uint8_t b7;     // ---> [2][3] --->  Right accessory paddle *
  uint8_t b42;    // ---> [2][4] --->  Launch control toggle *
  uint8_t enc3A;  // ---> [2][5] --->  Right thumb encoder A-channel *
  uint8_t enc3B;  // ---> [2][6] --->  Right thumb encoder B-channel *
/*
  Row 4, column 1-7
  status[3][0] --->  Left grip encoder A-channel *
  status[3][1] --->  Left grip encoder B-channel *
  status[3][2] --->  Left 3-way (ON)-OFF-(ON) push UP *
  status[3][3] --->  Left 3-way (ON)-OFF-(ON) push DOWN *
  status[4][0] --->  Left 7-way left press
  status[4][1] --->  Left 7-way encoder A-channel
  status[4][2] --->  Left 7-way encoder B-channel
  status[4][3] --->  Left 7-way up press
  status[4][4] --->  Left 7-way push button
  status[4][5] --->  Left 7-way down press 
  status[4][6] --->  Left 7-way right press

  Row 6, column 1-7
  status[5][0] --->  Left thumb encoder A-channel *
  status[5][1] --->  Left thumb encoder B-channel *
  status[5][2] --->  Ignition toggle *
  status[5][3] --->  Left top back-button *
  status[5][4] --->  Left accessory paddle *
  status[5][5] --->  Downshift paddle *
  status[5][6] --->  Radio OFF-ON latching pushbutton *

  //ROW 7, column 1-7
  status[6][0] --->  Pit limiter 9N OFF-(ON) pushbutton *
  status[6][1] --->  Bite point lock toggle switch *
  status[6][2] --->  Engine start button *
  status[1][0] --->  Col 4 empty
  status[1][0] --->  Col 5 empty
  status[1][0] --->  Col 6 empty
  status[1][0] --->  Col 7 empty
*/


//List of buttons and button debounce timers

//Button 1  ---> [0][4] --->  Right top 9N OFF-(ON) pushbutton
//Button 2  ---> [0][5] --->  Right middle 9N OFF-(ON) pushbutton
//Button 3  ---> [0][6] --->  Right lower 9N OFF-(ON) pushbutton
//Button 4  ---> [3][4] --->  Left top 9N OFF-(ON) pushbutton
//Button 5  ---> [3][5] --->  Left middle 9N OFF-(ON) pushbutton
//Button 6  ---> [3][6] --->  Left lower 9N OFF-(ON) pushbutton
//Button 7  ---> [2][3] --->  Right accessory paddle
//Button 8  ---> [5][4] --->  Left accessory paddle
//Button 9  ---> [2][2] --->  Upshift paddle
//Button 10 ---> [5][5] --->  Downshift paddle
//Button 11 ---> [0][2] --->  Right 3-way (ON)-OFF-(ON) push UP
//Button 12 ---> [0][3] --->  Right 3-way (ON)-OFF-(ON) push DOWN
//Button 13 ---> [3][2] --->  Left 3-way (ON)-OFF-(ON) push UP
//Button 14 ---> [3][3] --->  Left 3-way (ON)-OFF-(ON) push DOWN

//Button 15 ---> [0][0] --->  Right grip encoder A-channel (CW)
//Button 16 ---> [0][1] --->  Right grip encoder B-channel (CCW)
//Button 17 ---> [3][0] --->  Left grip encoder A-channel (CW)
//Button 18 ---> [3][1] --->  Left grip encoder B-channel (CCW)
//Button 19 ---> [2][5] --->  Right thumb encoder A-channel (CW)
//Button 20 ---> [2][6] --->  Right thumb encoder B-channel (CCW)
//Button 21 ---> [5][0] --->  Left thumb encoder A-channel (CW)
//Button 22 ---> [5][1] --->  Left thumb encoder B-channel (CCW)

//Button 23 ---> [6][0] --->  Pit limiter 9N OFF-(ON) pushbutton
//Button 24 ---> [5][6] --->  Radio OFF-ON latching pushbutton

//Button 25 ---> [1][6] --->  Right 7-way up press
//Button 26 ---> [1][3] --->  Right 7-way right press
//Button 27 ---> [1][0] --->  Right 7-way down press
//Button 28 ---> [1][1] --->  Right 7-way left press
//Button 29 ---> [1][4] --->  Right 7-way push button
//Button 30 ---> [1][2] --->  Right 7-way encoder A-channel (CW)
//Button 31 ---> [1][5] --->  Right 7-way encoder B-channel (CCW)

//Button 32 ---> [4][3] --->  Left 7-way up press
//Button 33 ---> [4][6] --->  Left 7-way right press
//Button 34 ---> [4][5] --->  Left 7-way down press
//Button 35 ---> [4][0] --->  Left 7-way left press
//Button 36 ---> [4][4] --->  Left 7-way push button
//Button 37 ---> [4][1] --->  Left 7-way encoder A-channel (CW)
//Button 38 ---> [4][2] --->  Left 7-way encoder B-channel (CCW)

//Button 39 ---> [2][1] --->  Right top back-button
//Button 40 ---> [2][0] --->  Middle top back-button
//Button 41 ---> [5][3] --->  Left top back-button
//Button 42 ---> [2][4] --->  Launch control toggle
//Button 43 ---> [5][2] --->  Ignition toggle
//Button 44 ---> [6][2] --->  Engine start button
//Button 45 ---> [6][1] --->  Bite point lock toggle switch


//Global parameters

//Clutch multiMap arrays
int inR [11] = {175, 180, 190, 205, 230, 270, 320, 370, 425, 490, 565};
int outR [11] = {0, 102, 204, 307, 409, 512, 614, 716, 819, 921, 1023};

int inL [11] = {536, 620, 680, 730, 780, 820, 840, 860, 869, 876, 882}; 
int outL [11] = {0, 102, 204, 307, 409, 512, 614, 716, 819, 921, 1023}; 

int inBite [11] = {3, 20, 40, 170, 400, 600, 900, 930, 960, 990, 1015};
int outBite [11] = {0, 102, 204, 307, 409, 512, 614, 716, 819, 921, 1023};

uint8_t mapSize = 11;

void setup() {
    
   
    
    //All ports are initialized as input without pullup resistor
    //No pin setup required
    //Serial.begin(9600);
    Joystick.begin();
    
}

void loop() {
    
    pinRegister();
    Joystick.setButton(1,b1);
}

void pinRegister () {
  
  //Port data direction registers: DDR --> 0 = INPUT, 1 = OUTPUT. Write 1 --> DDRB |= (1 << PB3) Write 0 --> DDRB &= ~(1 << PB3)
  //Port data registers: PORT --> 0 = LOW, 1 = HIGH. Write 1 --> PORTB |= (1 << PB3) Write 0 --> PORTB &= ~(1 << PB3)
  //Pullup resistors: Write PORT 1 to an INPUT pin (DDR = 0). 
  
  // col1 = PE6  --> pin 7
  // col2 = PF7  --> pin A0  
  // col3 = PC7  --> pin 13
  // col4 = PC6  --> pin 5
  // col5 = PB6  --> pin 10
  // col6 = PB5  --> pin 9
  // col7 = PB4  --> pin 8
  
  // row1 = PB7  --> pin 11
  // row2 = PD0  --> pin 3
  // row3 = PD1  --> pin 2
  // row4 = PD5  --> pin 30
  // row5 = PD4  --> pin 4
  // row6 = PD6  --> pin 12
  // row7 = PD7  --> pin 6
  
   byte b; //For reading pin register on PORT B
   byte c; //For reading pin register on PORT C
   byte e; //For reading pin register on PORT E
   byte f; //For reading pin register on PORT F
  
  //------------------------------
  //------------ROW 1-------------
  //------------------------------
  
  DDRB |= (1 << PB7);      // Set row pin as output, it will be LOW be default
  
  //All column pins are initialized as input, and will never have to be output. 
  
  //COL 1
  PORTE |= (1 << PE6);     // Set column pin as input_pullup
  e = PINE;                // Grab bit status on port
  e = e & B01000000;       // Compare to port with high pin
  if (e == 0) {
    enc1A = 1;
  } else {enc1A = 0;}
  PORTE &= ~(1 << PE6);     // Disable input_pullup
  
  //COL 2
  PORTF |= (1 << PF7);     // Set column pin as input_pullup
  f = PINF;                // Grab bit status on port
  f = f & B10000000;       // Compare to port with high pin
  if (f == 0) {
    enc1B = 1;
  } else {enc1B = 0;}
  PORTF &= ~(1 << PF7);     // Disable input_pullup
  
  //COL 3
  PORTC |= (1 << PC7);     // Set column pin as input_pullup
  c = PINC;                // Grab bit status on port
  c = c & B10000000;       // Compare to port with high pin
  if (c == 0) {
    b11 = 1;
  } else {b11 = 0;}
  PORTC &= ~(1 << PC7);     // Disable input_pullup
  
  //COL 4
  PORTC |= (1 << PC6);     // Set column pin as input_pullup
  c = PINC;                // Grab bit status on port
  c = c & B01000000;       // Compare to port with high pin
  if (c == 0) {
    b12 = 1;
  } else {b12 = 0;}
  PORTC &= ~(1 << PC6);     // Disable input_pullup
  
  //COL 5
  PORTB |= (1 << PB6);     // Set column pin as input_pullup
  b = PINB;                // Grab bit status on port
  b = b & B01000000;       // Compare to port with high pin
  if (b == 0) {
    b1 = 1;
  } else {b1 = 0;}
  PORTB &= ~(1 << PB6);     // Disable input_pullup
  
  //COL 6
  PORTB |= (1 << PB5);     // Set column pin as input_pullup
  b = PINB;                // Grab bit status on port
  b = b & B00100000;       // Compare to port with high pin
  if (b == 0) {
    b2 = 1;
  } else {b2 = 0;}
  PORTB &= ~(1 << PB5);     // Disable input_pullup
  
  //COL 7
  PORTB |= (1 << PB4);     // Set column pin as input_pullup
  b = PINB;                // Grab bit status on port
  b = b & B00010000;       // Compare to port with high pin
  if (b == 0) {
    b3 = 1;
  } else {b3 = 0;}
  PORTB &= ~(1 << PB4);     // Disable input_pullup

  //Set row pin back to output, PORT register is still 0, so it will be low
  DDRB &= ~(1 << PB7);     
  
  //------------------------------
  //------------ROW 2-------------
  //------------------------------
  
  DDRD |= (1 << PD0);      // Set row pin as output, it will be LOW be default
  
  //All column pins are initialized as input, and will never have to be output. 
  
  //COL 1
  PORTE |= (1 << PE6);     // Set column pin as input_pullup
  e = PINE;                // Grab bit status on port
  e = e & B01000000;       // Compare to port with high pin
  if (e == 0) {
    b27 = 1;
  } else {b27 = 0;}
  PORTE &= ~(1 << PE6);     // Disable input_pullup
  
  //COL 2
  PORTF |= (1 << PF7);     // Set column pin as input_pullup
  f = PINF;                // Grab bit status on port
  f = f & B10000000;       // Compare to port with high pin
  if (f == 0) {
    b28 = 1;
  } else {b28 = 0;}
  PORTF &= ~(1 << PF7);     // Disable input_pullup
  
  //COL 3
  PORTC |= (1 << PC7);     // Set column pin as input_pullup
  c = PINC;                // Grab bit status on port
  c = c & B10000000;       // Compare to port with high pin
  if (c == 0) {
    enc5A = 1;
  } else {enc5A = 0;}
  PORTC &= ~(1 << PC7);     // Disable input_pullup
  
  //COL 4
  PORTC |= (1 << PC6);     // Set column pin as input_pullup
  c = PINC;                // Grab bit status on port
  c = c & B01000000;       // Compare to port with high pin
  if (c == 0) {
    b26 = 1;
  } else {b26 = 0;}
  PORTC &= ~(1 << PC6);     // Disable input_pullup
  
  //COL 5
  PORTB |= (1 << PB6);     // Set column pin as input_pullup
  b = PINB;                // Grab bit status on port
  b = b & B01000000;       // Compare to port with high pin
  if (b == 0) {
    b29 = 1;
  } else {b29 = 0;}
  PORTB &= ~(1 << PB6);     // Disable input_pullup
  
  //COL 6
  PORTB |= (1 << PB5);     // Set column pin as input_pullup
  b = PINB;                // Grab bit status on port
  b = b & B00100000;       // Compare to port with high pin
  if (b == 0) {
    enc5B = 1;
  } else {enc5B = 0;}
  PORTB &= ~(1 << PB5);     // Disable input_pullup
  
  //COL 7
  PORTB |= (1 << PB4);     // Set column pin as input_pullup
  b = PINB;                // Grab bit status on port
  b = b & B00010000;       // Compare to port with high pin
  if (b == 0) {
    b25 = 1;
  } else {b25 = 0;}
  PORTB &= ~(1 << PB4);     // Disable input_pullup
  
  //Set row pin back to output, PORT register is still 0, so it will be low
  DDRD &= ~(1 << PD0); 
  
  //------------------------------
  //------------ROW 3-------------
  //------------------------------
  
  
  DDRD |= (1 << PD1);      // Set row pin as output, it will be LOW be default
  
  //All column pins are initialized as input, and will never have to be output. 
  
  //COL 1
  PORTE |= (1 << PE6);     // Set column pin as input_pullup
  e = PINE;                // Grab bit status on port
  e = e & B01000000;       // Compare to port with high pin
  if (e == 0) {
    b40 = 1;
  } else {b40 = 0;}
  PORTE &= ~(1 << PE6);     // Disable input_pullup
  
  //COL 2
  PORTF |= (1 << PF7);     // Set column pin as input_pullup
  f = PINF;                // Grab bit status on port
  f = f & B10000000;       // Compare to port with high pin
  if (f == 0) {
    b39 = 1;
  } else {b39 = 0;}
  PORTF &= ~(1 << PF7);     // Disable input_pullup
  
  //COL 3
  PORTC |= (1 << PC7);     // Set column pin as input_pullup
  c = PINC;                // Grab bit status on port
  c = c & B10000000;       // Compare to port with high pin
  if (c == 0) {
    b9 = 1;
  } else {b9 = 0;}
  PORTC &= ~(1 << PC7);     // Disable input_pullup
  
  //COL 4
  PORTC |= (1 << PC6);     // Set column pin as input_pullup
  c = PINC;                // Grab bit status on port
  c = c & B01000000;       // Compare to port with high pin
  if (c == 0) {
    b7 = 1;
  } else {b7 = 0;}
  PORTC &= ~(1 << PC6);     // Disable input_pullup
  
  //COL 5
  PORTB |= (1 << PB6);     // Set column pin as input_pullup
  b = PINB;                // Grab bit status on port
  b = b & B01000000;       // Compare to port with high pin
  if (b == 0) {
    b42 = 1;
  } else {b42 = 0;}
  PORTB &= ~(1 << PB6);     // Disable input_pullup
  
  //COL 6
  PORTB |= (1 << PB5);     // Set column pin as input_pullup
  b = PINB;                // Grab bit status on port
  b = b & B00100000;       // Compare to port with high pin
  if (b == 0) {
    enc3A = 1;
  } else {enc3A = 0;}
  PORTB &= ~(1 << PB5);     // Disable input_pullup
  
  //COL 7
  PORTB |= (1 << PB4);     // Set column pin as input_pullup
  b = PINB;                // Grab bit status on port
  b = b & B00010000;       // Compare to port with high pin
  if (b == 0) {
    enc3B = 1;
  } else {enc3B = 0;}
  PORTB &= ~(1 << PB4);     // Disable input_pullup
  
  //Set row pin back to output, PORT register is still 0, so it will be low
  DDRD &= ~(1 << PD1); 
  
  //------------------------------
  //------------ROW 4-------------
  //------------------------------
  
  
  DDRD |= (1 << PD5);      // Set row pin as output, it will be LOW be default
  
  //All column pins are initialized as input, and will never have to be output. 
  
  //COL 1
  PORTE |= (1 << PE6);     // Set column pin as input_pullup
  e = PINE;                // Grab bit status on port
  e = e & B01000000;       // Compare to port with high pin
  if (e == 0) {
    b40 = 1;
  } else {b40 = 0;}
  PORTE &= ~(1 << PE6);     // Disable input_pullup
  
  //COL 2
  PORTF |= (1 << PF7);     // Set column pin as input_pullup
  f = PINF;                // Grab bit status on port
  f = f & B10000000;       // Compare to port with high pin
  if (f == 0) {
    b39 = 1;
  } else {b39 = 0;}
  PORTF &= ~(1 << PF7);     // Disable input_pullup
  
  //COL 3
  PORTC |= (1 << PC7);     // Set column pin as input_pullup
  c = PINC;                // Grab bit status on port
  c = c & B10000000;       // Compare to port with high pin
  if (c == 0) {
    b9 = 1;
  } else {b9 = 0;}
  PORTC &= ~(1 << PC7);     // Disable input_pullup
  
  //COL 4
  PORTC |= (1 << PC6);     // Set column pin as input_pullup
  c = PINC;                // Grab bit status on port
  c = c & B01000000;       // Compare to port with high pin
  if (c == 0) {
    b7 = 1;
  } else {b7 = 0;}
  PORTC &= ~(1 << PC6);     // Disable input_pullup
  
  //COL 5
  PORTB |= (1 << PB6);     // Set column pin as input_pullup
  b = PINB;                // Grab bit status on port
  b = b & B01000000;       // Compare to port with high pin
  if (b == 0) {
    b42 = 1;
  } else {b42 = 0;}
  PORTB &= ~(1 << PB6);     // Disable input_pullup
  
  //COL 6
  PORTB |= (1 << PB5);     // Set column pin as input_pullup
  b = PINB;                // Grab bit status on port
  b = b & B00100000;       // Compare to port with high pin
  if (b == 0) {
    enc3A = 1;
  } else {enc3A = 0;}
  PORTB &= ~(1 << PB5);     // Disable input_pullup
  
  //COL 7
  PORTB |= (1 << PB4);     // Set column pin as input_pullup
  b = PINB;                // Grab bit status on port
  b = b & B00010000;       // Compare to port with high pin
  if (b == 0) {
    enc3B = 1;
  } else {enc3B = 0;}
  PORTB &= ~(1 << PB4);     // Disable input_pullup
  
  //Set row pin back to output, PORT register is still 0, so it will be low
  DDRD &= ~(1 << PD5); 
  
  

 
  
}

Check all instances of DDRD mutation to be sure you haven't changed 0 or 1.

Ok, so for instance

DDRD = B10000000;

To make PD7 output?

Correct, you've also set the direction of 0 and 1 to 0 as well.

Try DDRD = DDRD | B10000000;

Ok, Ill edit my code and try again this evening!

Had some coffee and came up with a more complete answer.
To turn on pins by port manipulation OR it with a bitmask:

DDRD = DDRD | B10010000; // Set only 4 and 7 to HIGH

To turn pins off AND it with a bitmask:

DDRD = DDRD & B01101111; //Set only 4 and 7 to LOW

That's what @johnwasser was saying about being careful not to change the wrong pins.

If you find yourself only changing one pin though, you may not need port manipulation for that. However I do see them as being hugely beneficial to your reads.

Cool project BTW, I'm more of a flight sim guy but who doesn't love a good driving sim.

Thanks​:blush::+1: Just hope I can make it work​:sweat_smile: Thats, a great way to do it. I presume it works the same way for PORTx commands?

Yup, that's universal enough for any Arduino port.

You could save time by leaving the column pins set to INPUT_PULLUP all the time. You can also save time by not copying the PINx register to a variable before testing a bit. Together they would reduce each column check to a single line:

    enc1A = ! (PINE & (1 << PE6));    //COL 1
    enc1B = ! (PINF & (1 << PF7));    //COL 2
    b11  =  ! (PINC & (1 << PC7));    //COL 3

Those are some great lines, I got my 32U4 working again, edited with your lines, seems to be working with a simple sketch. I'll do some more testing.

1 Like

I've gotten some more time for testing. Following code to check all the buttons on the matrix:

#include <Joystick.h>
#include <MultiMap.h>

#define BUTTONCOUNT 45

//Defining joystick parameters

Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_GAMEPAD,
                   BUTTONCOUNT,    //Button count
                   0,              //Hat switch count
                   true,           //X axis -> Clutch paddles
                   true,          //Y axis -> Clutch bite, only for dash visualization
                   false,          //Z axis
                   false,          //Rx axis
                   false,          //Ry axis
                   false,          //Rz axis
                   false,          //Rudder
                   false,          //Throttle
                   false,          //Accelerator
                   false,          //Brake
                   false);         //Steering


//Status of all buttons


//  Row 1, column 1 - 7
  uint8_t enc1A;  // --->  Right grip encoder A-channel 
  uint8_t enc1B;  // --->  Right grip encoder B-channel 
  uint8_t b11;    // --->  Right 3-way (ON)-OFF-(ON) push UP 
  uint8_t b12;    // --->  Right 3-way (ON)-OFF-(ON) push DOWN 
  uint8_t b1;     // --->  Right top 9N OFF-(ON) pushbutton 
  uint8_t b2;     // --->  Right middle 9N OFF-(ON) pushbutton 
  uint8_t b3;     // --->  Right lower 9N OFF-(ON) pushbutton 

//  Row 2, column 1-7
  uint8_t b27;    // --->  Right 7-way down press
  uint8_t b28;    // --->  Right 7-way left press
  uint8_t enc5A;     // --->  Right 7-way encoder A-channel
  uint8_t b26;    // --->  Right 7-way right press
  uint8_t b29;    // --->  Right 7-way push button
  uint8_t enc5B;     // --->  Right 7-way encoder B-channel
  uint8_t b25;    // --->  Right 7-way up press

//  Row 3, column 1-7
  uint8_t b40;    // --->  Middle top back-button 
  uint8_t b39;    // --->  Right top back-button 
  uint8_t b9;     // --->  Upshift paddle 
  uint8_t b7;     // --->  Right accessory paddle 
  uint8_t b42;    // --->  Launch control toggle 
  uint8_t enc3A;  // --->  Right thumb encoder A-channel 
  uint8_t enc3B;  // --->  Right thumb encoder B-channel 

//  Row 4, column 1-7
  uint8_t enc2A;  // --->  Left grip encoder A-channel 
  uint8_t enc2B;  // --->  Left grip encoder B-channel 
  uint8_t b13;    // --->  Left 3-way (ON)-OFF-(ON) push UP 
  uint8_t b14;    // --->  Left 3-way (ON)-OFF-(ON) push DOWN 
  uint8_t b4;     // --->  Left top 9N OFF-(ON) pushbutton 
  uint8_t b5;     // --->   Left middle 9N OFF-(ON) pushbutton 
  uint8_t b6;     // --->   Left lower 9N OFF-(ON) pushbutton 

//  Row 5, column 1-7
  uint8_t b35;    // --->  Left 7-way left press
  uint8_t enc6A;     // --->  Left 7-way encoder A-channel
  uint8_t enc6B;     // --->  Left 7-way encoder B-channel
  uint8_t b32;    // --->  Left 7-way up press
  uint8_t b36;    // --->  Left 7-way push button
  uint8_t b34;    // --->  Left 7-way down press
  uint8_t b33;    // --->  Left 7-way right press

//  Row 6, column 1-7
  uint8_t enc4A;  // --->  Left thumb encoder A-channel 
  uint8_t enc4B;  // --->  Left thumb encoder B-channel 
  uint8_t b43;    // --->  Ignition toggle 
  uint8_t b41;    // --->  Left top back-button 
  uint8_t b8;     // --->  Left accessory paddle 
  uint8_t b10;    // --->  Downshift paddle 
  uint8_t b24;    // --->  Radio OFF-ON latching pushbutton 

//  Row 7, column 1-7
  uint8_t b23;    // --->  Pit limiter 9N OFF-(ON) pushbutton 
  uint8_t b45;    // --->  Bite point lock toggle switch 
  uint8_t b44;    // --->  Engine start button 
                  // --->  Col 4 empty
                  // --->  Col 5 empty
                  // --->  Col 6 empty
                  // --->  Col 7 empty

//List of buttons

//Button 1  ---> [0][4] --->  Right top 9N OFF-(ON) pushbutton
//Button 2  ---> [0][5] --->  Right middle 9N OFF-(ON) pushbutton
//Button 3  ---> [0][6] --->  Right lower 9N OFF-(ON) pushbutton
//Button 4  ---> [3][4] --->  Left top 9N OFF-(ON) pushbutton
//Button 5  ---> [3][5] --->  Left middle 9N OFF-(ON) pushbutton
//Button 6  ---> [3][6] --->  Left lower 9N OFF-(ON) pushbutton
//Button 7  ---> [2][3] --->  Right accessory paddle
//Button 8  ---> [5][4] --->  Left accessory paddle
//Button 9  ---> [2][2] --->  Upshift paddle
//Button 10 ---> [5][5] --->  Downshift paddle
//Button 11 ---> [0][2] --->  Right 3-way (ON)-OFF-(ON) push UP
//Button 12 ---> [0][3] --->  Right 3-way (ON)-OFF-(ON) push DOWN
//Button 13 ---> [3][2] --->  Left 3-way (ON)-OFF-(ON) push UP
//Button 14 ---> [3][3] --->  Left 3-way (ON)-OFF-(ON) push DOWN

//Button 15 ---> [0][0] --->  Right grip encoder A-channel (CW)
//Button 16 ---> [0][1] --->  Right grip encoder B-channel (CCW)
//Button 17 ---> [3][0] --->  Left grip encoder A-channel (CW)
//Button 18 ---> [3][1] --->  Left grip encoder B-channel (CCW)
//Button 19 ---> [2][5] --->  Right thumb encoder A-channel (CW)
//Button 20 ---> [2][6] --->  Right thumb encoder B-channel (CCW)
//Button 21 ---> [5][0] --->  Left thumb encoder A-channel (CW)
//Button 22 ---> [5][1] --->  Left thumb encoder B-channel (CCW)

//Button 23 ---> [6][0] --->  Pit limiter 9N OFF-(ON) pushbutton
//Button 24 ---> [5][6] --->  Radio OFF-ON latching pushbutton

//Button 25 ---> [1][6] --->  Right 7-way up press
//Button 26 ---> [1][3] --->  Right 7-way right press
//Button 27 ---> [1][0] --->  Right 7-way down press
//Button 28 ---> [1][1] --->  Right 7-way left press
//Button 29 ---> [1][4] --->  Right 7-way push button
//Button 30 ---> [1][2] --->  Right 7-way encoder A-channel (CW)
//Button 31 ---> [1][5] --->  Right 7-way encoder B-channel (CCW)

//Button 32 ---> [4][3] --->  Left 7-way up press
//Button 33 ---> [4][6] --->  Left 7-way right press
//Button 34 ---> [4][5] --->  Left 7-way down press
//Button 35 ---> [4][0] --->  Left 7-way left press
//Button 36 ---> [4][4] --->  Left 7-way push button
//Button 37 ---> [4][1] --->  Left 7-way encoder A-channel (CW)
//Button 38 ---> [4][2] --->  Left 7-way encoder B-channel (CCW)

//Button 39 ---> [2][1] --->  Right top back-button
//Button 40 ---> [2][0] --->  Middle top back-button
//Button 41 ---> [5][3] --->  Left top back-button
//Button 42 ---> [2][4] --->  Launch control toggle
//Button 43 ---> [5][2] --->  Ignition toggle
//Button 44 ---> [6][2] --->  Engine start button
//Button 45 ---> [6][1] --->  Bite point lock toggle switch
 
 
unsigned long counter; //Code speed

/*
//Debouncing
uint8_t debounce = 50;
uint8_t encoderPulse = 200;

//Encoders
uint8_t enc1C = 0;
uint8_t enc1L = 0;
uint8_t enc2C = 0;
uint8_t enc2L = 0;
uint8_t enc3C = 0;
uint8_t enc3L = 0;
uint8_t enc4C = 0;
uint8_t enc4L = 0;
uint8_t enc5C = 0;
uint8_t enc5L = 0;
bool enc5S = 0;
uint8_t enc6C = 0;
uint8_t enc6L = 0;
bool enc6S = 0;

//Clutch multiMap arrays
int inR [11] = {175, 180, 190, 205, 230, 270, 320, 370, 425, 490, 565};
int outR [11] = {0, 102, 204, 307, 409, 512, 614, 716, 819, 921, 1023};

int inL [11] = {536, 620, 680, 730, 780, 820, 840, 860, 869, 876, 882}; 
int outL [11] = {0, 102, 204, 307, 409, 512, 614, 716, 819, 921, 1023}; 

int inBite [11] = {3, 20, 40, 170, 400, 600, 900, 930, 960, 990, 1015};
int outBite [11] = {0, 102, 204, 307, 409, 512, 614, 716, 819, 921, 1023};

uint8_t mapSize = 11;
*/

void setup() {
    
   
  //All ports are initialized as input without pullup resistor
  
  PORTE = PORTE | B01000000; //Setting pullup on PE6
  PORTF = PORTF | B10000000; //Setting pullup on PF7
  PORTC = PORTC | B11000000; //Setting pullup on PC6, PC7
  PORTB = PORTB | B01110000; //Setting pullup on PB4, PB5, PB6
  
    Joystick.begin();
    
}

void loop() {
    
    pinRegister();
    
    /*
    encoderFUNKY(29,30, enc5A, enc5B, enc6S, enc5C, enc5L);
    encoderFUNKY(36,37, enc6A, enc6B, enc6S, enc5C, enc5L);
    
    encoderCTS288 (14, 15, enc1A, enc1B, enc1L, enc1C);
    encoderCTS288 (16, 17, enc2A, enc2B, enc2L, enc2C);
    encoderCTS288 (18, 19, enc3A, enc3B, enc3L, enc3C);
    encoderCTS288 (20, 21, enc4A, enc4B, enc4L, enc4C);
    */
   
    buttons();
    
    counter++; //Checking code speed
    
}

void pinRegister () {
  
  // col1 = PE6  --> pin 7
  // col2 = PF7  --> pin A0  
  // col3 = PC7  --> pin 13
  // col4 = PC6  --> pin 5
  // col5 = PB6  --> pin 10
  // col6 = PB5  --> pin 9
  // col7 = PB4  --> pin 8
  
  // row1 = PB7  --> pin 11
  // row2 = PD0  --> pin 3
  // row3 = PD1  --> pin 2
  // row4 = PD5  --> pin 30
  // row5 = PD4  --> pin 4
  // row6 = PD6  --> pin 12
  // row7 = PD7  --> pin 6

  //------------------------------
  //------------ROW 1-------------
  //------------------------------
  
  DDRB = DDRB | B10000000;      // Set row pin as output, it will be LOW be default
  
  //All column pins are initialized as input, and will never have to be output. 
  
    enc1A = ! (PINE & (1 << PE6));  //COL 1
    enc1B = ! (PINF & (1 << PF7));  //COL 2
    b11 = ! (PINC & (1 << PC7));    //COL 3
    b12 = ! (PINC & (1 << PC6));    //COL 4
    b1 = ! (PINB & (1 << PB6));     //COL 5
    b2 = ! (PINB & (1 << PB5));     //COL 6
    b3 = ! (PINB & (1 << PB4));     //COL 7

  DDRB = DDRB ^ B10000000;     //Set row pin back to input, PORT register is still 0, so it will be w/o pullup
  
  //------------------------------
  //------------ROW 2-------------
  //------------------------------
  
  DDRD = DDRD | B00000001;      // Set row pin as output, it will be LOW be default
  
    b27 = ! (PINE & (1 << PE6));     //COL 1
    b28 = ! (PINF & (1 << PF7));     //COL 2
    enc5A = ! (PINC & (1 << PC7));   //COL 3
    b26 = ! (PINC & (1 << PC6));     //COL 4
    b29 = ! (PINB & (1 << PB6));     //COL 5
    enc5B = ! (PINB & (1 << PB5));   //COL 6
    b25 = ! (PINB & (1 << PB4));     //COL 7
    
  DDRD = DDRD ^ B00000001;  // Set row pin as input
  
  //------------------------------
  //------------ROW 3-------------
  //------------------------------
  
  DDRD = DDRD | B00000010;      // Set row pin as output, it will be LOW be default
  
    b40 = ! (PINE & (1 << PE6));    //COL 1
    b39 = ! (PINF & (1 << PF7));    //COL 2
    b9 = ! (PINC & (1 << PC7));     //COL 3
    b7 = ! (PINC & (1 << PC6));     //COL 4
    b42 = ! (PINB & (1 << PB6));    //COL 5
    enc3A = ! (PINB & (1 << PB5));  //COL 6
    enc3B = ! (PINB & (1 << PB4));  //COL 7

  DDRD = DDRD ^ B00000010;   // Set row pin as input  
  
  //------------------------------
  //------------ROW 4-------------
  //------------------------------
  
  DDRD = DDRD | B00100000;      // Set row pin as output, it will be LOW be default

    enc2A = ! (PINE & (1 << PE6));  //COL 1
    enc2B = ! (PINF & (1 << PF7));  //COL 2
    b13 = ! (PINC & (1 << PC7));    //COL 3
    b14 = ! (PINC & (1 << PC6));    //COL 4
    b4 = ! (PINB & (1 << PB6));     //COL 5
    b5 = ! (PINB & (1 << PB5));     //COL 6
    b6 = ! (PINB & (1 << PB4));     //COL 7

  DDRD = DDRD ^ B00100000;   // Set row pin as input  

  //------------------------------
  //------------ROW 5-------------
  //------------------------------
  
  DDRD = DDRD | B00010000;      // Set row pin as output, it will be LOW be default
  
    b35 = ! (PINE & (1 << PE6));    //COL 1
    enc6A = ! (PINF & (1 << PF7));  //COL 2
    enc6B = ! (PINC & (1 << PC7));  //COL 3
    b32 = ! (PINC & (1 << PC6));    //COL 4
    b36 = ! (PINB & (1 << PB6));    //COL 5
    b34 = ! (PINB & (1 << PB5));    //COL 6
    b33 = ! (PINB & (1 << PB4));    //COL 7
    
  DDRD = DDRD ^ B00010000;   // Set row pin as input  

  //------------------------------
  //------------ROW 6-------------
  //------------------------------
  
  DDRD = DDRD | B01000000;      // Set row pin as output, it will be LOW be default
  
    enc4A = ! (PINE & (1 << PE6));  //COL 1
    enc4B = ! (PINF & (1 << PF7));  //COL 2
    b43 = ! (PINC & (1 << PC7));    //COL 3
    b41 = ! (PINC & (1 << PC6));    //COL 4
    b8 = ! (PINB & (1 << PB6));     //COL 5
    b10 = ! (PINB & (1 << PB5));    //COL 6
    b24 = ! (PINB & (1 << PB4));    //COL 7

  DDRD = DDRD ^ B01000000;  // Set row pin as input  
  
  //------------------------------
  //------------ROW 7-------------
  //------------------------------
  
  DDRD = DDRD | B10000000;      // Set row pin as output, it will be LOW be default
  
    b23 = ! (PINE & (1 << PE6));    //COL 1
    b45 = ! (PINF & (1 << PF7));    //COL 2
    b44 = ! (PINC & (1 << PC7));    //COL 3

  DDRD = DDRD ^ B10000000;  // Set row pin as input  

}
/*
void encoderCTS288 (uint8_t bUp, uint8_t bDown, uint8_t aPin, uint8_t bPin, uint8_t encL, uint8_t encC) {

  uint8_t encN = aPin ^ ((aPin << 1) & bPin); // Converting AB grey to binary
  
  if (encN != encL) {
    if (encC > debounce) {
      encL = encN;
    } 
    else {encC++;}
  }
  
  if (encC > debounce) {
    if (encC > encoderPulse) {
      encC = 0;
    }
    else if( ((encN > encL) && !(encN == 3 && encL == 0)) || (encN == 0 && encL == 3) ) {
      Joystick.pressButton(bUp);
      Joystick.releaseButton(bDown);
    } else {
      Joystick.pressButton(bDown);
      Joystick.releaseButton(bUp);
      
    }
  }
}

void encoderFUNKY(uint8_t bUp, uint8_t bDown, uint8_t aPin, uint8_t bPin, bool start, uint8_t encC, uint8_t encL) {
  
  uint8_t encN = ((aPin << 1) | bPin);
  
  if (aPin == bPin && !start) {encL = ((aPin << 1) | bPin);}
  
  if ((aPin ^ bPin)) {
    start = 1;
  }
    
  if (start) {
    encC ++;
    if (encC > encoderPulse) {
      start = 0;
      encC = 0;
      Joystick.releaseButton(bUp);
      Joystick.releaseButton(bDown);
    }
    else {
      Joystick.setButton(bUp, !((encN ^ encL) >> 1));
      Joystick.setButton(bDown, (encN ^ encL) >> 1);
      
      
    }
  
  }
}
*/
void buttons () {
  Joystick.setButton(0, b1);
  Joystick.setButton(1, b2);
  Joystick.setButton(2, b3);
  Joystick.setButton(3, b4);
  Joystick.setButton(4, b5);
  Joystick.setButton(5, b6);
  Joystick.setButton(6, b7);
  Joystick.setButton(7, b8);
  Joystick.setButton(8, b9);
  Joystick.setButton(9, b10);
  Joystick.setButton(10, b11);
  Joystick.setButton(11, b12);
  Joystick.setButton(12, b13);
  Joystick.setButton(13, b14);
  
  Joystick.setButton(14, enc1A);
  Joystick.setButton(15, enc1B);
  
  Joystick.setButton(16, enc2A);
  Joystick.setButton(17, enc2B);
  
  Joystick.setButton(18, enc3A);
  Joystick.setButton(19, enc3B);
  
  Joystick.setButton(20, enc4A);
  Joystick.setButton(21, enc4B);
  
  Joystick.setButton(22, b23);
  Joystick.setButton(23, b24);
  Joystick.setButton(24, b25);
  Joystick.setButton(25, b26);
  Joystick.setButton(26, b27);
  Joystick.setButton(27, b28);
  Joystick.setButton(28, b29);
  
  Joystick.setButton(29, enc5A);
  Joystick.setButton(30, enc5B);
  
  Joystick.setButton(31, b32);
  Joystick.setButton(32, b33);
  Joystick.setButton(33, b34);
  Joystick.setButton(34, b35);
  Joystick.setButton(35, b36);
  
  Joystick.setButton(36, enc6A);
  Joystick.setButton(37, enc6B);
  
  Joystick.setButton(38, b39);
  Joystick.setButton(39, b40);
  Joystick.setButton(40, b41);
  Joystick.setButton(41, b42);
  Joystick.setButton(42, b43);
  Joystick.setButton(43, b44);
  Joystick.setButton(44, b45);
  
}
  
  
  

It ended up with some ghosting. For a few buttons, the button on the same column on the following row is triggered. So if button on row 1 col 1 is pushed, button on row 2 col 1 is also pushed. All buttons have diodes, and this is working perfectly with my old code, so I dont think it is wiring issues. I suspected the row pin not changing fast enough to input, so I edited to this:

  DDRD = DDRD | B01000000;      // Set row pin as output, it will be LOW be default
  PORTD = PORTD & B10111111;
   
    enc4A = ! (PINE & (1 << PE6));  //COL 1
    enc4B = ! (PINF & (1 << PF7));  //COL 2
    b43 = ! (PINC & (1 << PC7));    //COL 3
    b41 = ! (PINC & (1 << PC6));    //COL 4
    b8 = ! (PINB & (1 << PB6));     //COL 5
    b10 = ! (PINB & (1 << PB5));    //COL 6
    b24 = ! (PINB & (1 << PB4));    //COL 7

  PORTD = PORTD ^ B01000000;
  DDRD = DDRD ^ B01000000;  // Set row pin as input  
  

Setting the row pin low/high on each poll. This solved the issue with ghosting, however --> now all buttons on col 1 and col 3 are completely unresponsive. I tried keeping row pin as output and just changing high/low, same result: no ghosting, but no function on col1 and 3. Will keep trying different stuff, but anyone got any pointers to what might be happening?

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.