Re-ordering values of a 16 bit integer to reflect physical layout on interface

Hello all. I'm stumped with a problem due to lack of relevant knowledge and humbly come looking for assistance.

I have fabricated a custom PCB using the TTP229 capacitive touch IC. The device is a 16 step sequencer that will send MIDI eventually once I've figures out the current issue. I'm using an Arduino Nano. There are 16 capacitive touch pads and 16 neopixel LEDs arranged in a circle. The code below is based on the example given here Instruction: One or more 16-key capacitive keypads with Arduino Uno & SPI - #2 by Andreas_Gaunitz
The order in which the 16 electrodes are connected to the IC is different to the order in which the chip delivers the 16 bit integer value, and I want to re-order this somehow. I have a spreadsheet with a comparison of the values as they relate to the chip pins, the readings in the serial monitor and the interface layout.

The code below works in as far as I can read the states of the touch pads, and turn on leds that relate to how many times each pad has been pressed, they're just not in the right order (for instance, pressing electrode 5 turns on LED 1). I've re-ordered the 16 leds to light in the correct orientation using an array, and tried something similar in using a for loop to iterate through an array with the correct ordering of the touch pads, but it doesn't work (it's commented out but the array int buttonOrder[]).

From looking around the forum I now believe that I have to do some bit operations to reorder the values, but it's hurting my brain. Example topic: A better way to do my bit reordering? - #5 by graynomad

My current code:


#include <SPI.h>

const uint8_t MUX_A = 5;  // Used to select mux data channel
const uint8_t MUX_B = 6;


uint16_t key_map_8229_0;  // The scanned keys
uint16_t key_map_8229_1;


int stepNum[16];

#include <Adafruit_NeoPixel.h>
#define LED_PIN 4
#define LED_COUNT 16

// Declare our NeoPixel strip object:
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);


unsigned long pixelPrevious = 0;    // Previous Pixel Millis
unsigned long patternPrevious = 0;  // Previous Pattern Millis
int patternCurrent = 0;             // Current Pattern Number
int patternInterval = 5000;         // Pattern Interval (ms)
int pixelInterval = 50;             // Pixel Interval (ms)
int pixelQueue = 0;                 // Pattern Pixel Queue
int pixelCycle = 0;                 // Pattern Pixel Cycle
uint16_t pixelCurrent = 0;          // Pattern Current Pixel Number
uint16_t pixelNumber = LED_COUNT;   // Total Number of Pixels
const long interval = 400;          // interval at which to blink (milliseconds)
int count = -1;

int ledOrder[16] ={ 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5 };  // fixing layout of leds. First led in the chain is
//in position 13 in relation the touchPCB, and are also running anti-clockwise so this fixes that issue
// Variables will change:
int buttonPushCounter[16];  // counter for the number of button presses
int buttonOrder[16];// = { 12, 13, 14, 15, 0, 2, 3, 1, 7, 6, 5, 4, 8,  11, 10, 9 };
int buttonState[16];      // current state of the button
int lastButtonState[16];  // previous state of the button

unsigned long previousMillis = 0;  // will store last time LED was updated

// setup() function -- runs once at startup --------------------------------
void setup() {

  pinMode(MUX_A, OUTPUT);
  pinMode(MUX_B, OUTPUT);


  Serial.begin(115200);

  SPI.begin();
  SPI.beginTransaction(SPISettings(14000000, MSBFIRST, SPI_MODE3));
  delay(500);  // Allow 500ms for the 8229BSF to get ready after turn-on

  // These lines are specifically to support the Adafruit Trinket 5V 16 MHz.
  // Any other board, you can remove this part (but no harm leaving it):
#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000)
  clock_prescale_set(clock_div_1);
#endif
  // END of Trinket-specific code.

  strip.begin();            // INITIALIZE NeoPixel strip object (REQUIRED)
  strip.show();             // Turn OFF all pixels ASAP
  strip.setBrightness(50);  // Set BRIGHTNESS to about 1/5 (max = 255)
}

// loop() function -- runs repeatedly as long as board is on ---------------
void loop() {


  spi_scan_8229_0();  // Get data frpm the Keypads
  spi_scan_8229_1();


  //startStop = 0;
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;
    count++;
    strip.setPixelColor(ledOrder[count], strip.Color(150, 150, 150));
    strip.show();
    if (buttonPushCounter[ledOrder[count]] == 0) {
      // strip.setPixelColor(count - 1, strip.Color(0, 0, 0));
      strip.show();
    }

    if (count >= 15) {
      count = -1;
    }
  }


  for (int i = 0; i <= 15; i++) {
    buttonState[i] = bitRead(key_map_8229_0, i);
    //the above reads the 16 bit number into sequencial chunks from first bit to 16th bit. 
    //the order of this does not relate to the 
    //this needs to be re-ordered as the physical position of the touch pads isn't correct in relation to the reading
//Serial.println(buttonOrder[i]);
//delay(100);
    if (buttonState[i] != lastButtonState[i]) {
      // if the state has changed, increment the counter
      if (buttonState[i] == 0) {
        // if the current state is HIGH then the button went from off to on:
        buttonPushCounter[i]++;
        Serial.println("button number ");
        Serial.print(i);
        Serial.print("number of button pushes: ");
        Serial.println(buttonPushCounter[i]);
      }
    }
    // save the current state as the last state, for next time through the loop
    lastButtonState[i] = buttonState[i];

    if (buttonPushCounter[i] == 0) {
      strip.setPixelColor(ledOrder[i], strip.Color(0, 0, 0));
      strip.show();
    }
    if (buttonPushCounter[i] == 1) {
      strip.setPixelColor(ledOrder[i], strip.Color(0, 150, 0));
      strip.show();
    }
    if (buttonPushCounter[i] == 2) {
      strip.setPixelColor(ledOrder[i], strip.Color(0, 0, 150));
      strip.show();
    }
    if (buttonPushCounter[i] == 3) {
      strip.setPixelColor(ledOrder[i], strip.Color(150, 0, 0));
      strip.show();
    }
    if (buttonPushCounter[i] == 4) {
      buttonPushCounter[i] = 0;
    }
  }
  // set the LED with the ledState of the variable:
  //digitalWrite(ledPin, sequence[count]);

  // if (startStop == 1) {
  //   if (sequence[count] == 1) {
  //     usbMIDI.sendNoteOn(60, 99, channel);
  //   }

  //   if (sequence[count] == 0) {
  //     usbMIDI.sendNoteOff(60, 0, channel);  // 60 = C4
  //   }
  // }
}


void spi_scan_8229_0() {
  // Select MUX channel for 8229_0
  digitalWrite(MUX_A, 0);
  digitalWrite(MUX_B, 0);

  // Get state of all the keys as a 16 bit integer
  key_map_8229_0 = SPI.transfer16(0);
}

void spi_scan_8229_1() {
  // Select MUX channel for 8229_1
  digitalWrite(MUX_A, 1);
  digitalWrite(MUX_B, 0);

  // Get state of all the keys as a 16 bit integer
  key_map_8229_1 = SPI.transfer16(0);
}

If I understand you correctly, the below should help. Not tested, but should work. Ask if you have questions please.


// inputWord is your incoming 16-bit value
uint16_t inputWord;

// Remapped output value
uint16_t outputWord = 0;

// Relates input bit positions to outputs
// e.g., output bit 0 is input bit 3
const byte mapbit[16] = {3,4,5,6,7,8,9,10,11,12,13,14,15,0,1,2};

for (int i = 0; i < 16; i++)
{
    if (inputWord & (1 << mapbit[i]) )
    {
        outputWord |= (1 << i);
    }
}

thank you for this. I've tried to plug it into my code like below but am not getting any output. I've substituted the existing 16 bit integer name in place of your inputWord, and try to print outputWord, but perhaps this is the wrong approach?

for (int i = 0; i < 16; i++) {

    if (key_map_8229_0 & (1 << mapbit[i]) )
    {
        outputWord |= (1 << i);
    }
        buttonState[i] = bitRead(outputWord, i);

    if (buttonState[i] != lastButtonState[i]) {
      // if the state has changed, increment the counter
      if (buttonState[i] == 0) {
        // if the current state is HIGH then the button went from off to on:
        buttonPushCounter[i]++;
        Serial.println("button number ");
        Serial.print(i);
        Serial.print("number of button pushes: ");
        Serial.println(buttonPushCounter[i]);
      }
    }

I did not read your existing code, so I really don't know what the variable names are. I just answered the exact question that you asked.

Maybe it's easier if I show it as a function that you can call after you get the 16-bit value that you want to reorder. The only thing you should need to change is mapbit[] array, which relates the output bit positions to the input ones. e.g., in my example input bit 0 gets transformed to output bit 3.

uint16_t reorder(uint16_t inputWord)
{
    // Remapped output value
    uint16_t outputWord = 0;
    
    // Relates input bit positions to outputs
    // e.g., output bit 0 is input bit 3
    const byte mapbit[16] = {3,4,5,6,7,8,9,10,11,12,13,14,15,0,1,2};
    
    for (int i = 0; i < 16; i++)
    {
        if (inputWord & (1 << mapbit[i]) )
        {
            outputWord |= (1 << i);
        }
    }
    return outputWord;
}

ah brilliant, that works!!! Many many thanks, I was really stuck on that and your function above is exactly what was needed. Now onto the next issue :slight_smile:

Please post that here, don't create a new topic.

It may seem like a completely different problem to you, but forum members reading this thread are now a little familiar with your project, so are best placed to help. If they can't help, they may know which forum member has most relevant experience.

Don't worry, that was more a reference to the development process than an attempt to hijack my own thread with unrelated issues

1 Like

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