Hi,
I'm attempting to modify an existing project that uses an arduino to emulate the buttons on a racing wheel controller (Thrustmaster T150) so that the wheel can be replaced with my own but still communicate with the stock wheel base.
The Arduino sketch simulates three 8 bit shift registers which are used on the wheel to read the button states. The base station then polls 8 bytes from the wheel at a rate of 100 Hz, only using the first three bytes for data. The first byte is static and identifies the wheel. The next two bytes are populated with the button states.
The sketch sets up the arduino as an SPI slave. It loads the first static byte into SPDR making it ready to be sent accross the SPI connection. Once that byte is sent, the SPI interrupt is then used load up the next byte to be sent.
The problem I'm having is that in the SPI interrupt routine, I attempt to write the SPDR but this seems to have no effect. It always loads up all ones (11111111) in every byte after the first. This is confirmed by connecting a second arduino as an SPI master and logging the results via serial connection. The first, static byte is always correctly received but everything after that is always all ones.
I have confirmed that the interrupt routine is being called by logging via serial though this throws off the timing of the SPI so it's difficult to debug in this way.
I've modified the slave sketch below to not try and read any button states but simply send, hard-coded bytes from an array. As you can see in the serial output from the master, the first byte is always correct but the second (and subsequent) bytes are always 11111111.
Any insight would be appreciated.
Slave code:
volatile byte wheelState [8];
volatile byte pos;
void setup (void) {
DDRB |= B00001011; // digital pins 8,9,11 used as inputs with a pull-up to +VCC
PORTB |= B00001011;
DDRC |= B00111111; // pins 14-19 (A0 - A5) also used as digital inputs
PORTC |= B00111111; // pulled-up to +VCC via internal 100k resistors
DDRD |= B11111011; // digital pins 0,1,3,4,5,6,7 used as inputs
PORTD |= B11111011; // pulled-up to +VCC via internal 100k resistors
wheelState[0] = B11010001; // TX RW Ferrari 458 Italia Wheel first data byte
wheelState[1] = B10000001; // second data byte - buttons
wheelState[2] = B11111111; // third data byte - buttons
wheelState[3] = B11111111; // this and below - not used, but wheelbase reads all 8 bytes...
wheelState[4] = B11111111;
wheelState[5] = B11111111;
wheelState[6] = B11111111;
wheelState[7] = B11111111;
//Serial.begin(9600); // Arduino debug console - occupies pins RX (0) and TX (1) on Uno
pinMode(MISO, OUTPUT); // arduino is a slave device
SPCR |= _BV(SPE); // Enables the SPI when 1
SPCR |= _BV(SPIE); // Enables the SPI interrupt when 1
// interrupt for SS rising edge. Arduino Uno Pin10 must be connected to Pin2!!!
attachInterrupt (0, ss_rising, RISING);
}
// Interrupt0 (external, pin 2) - prepare to start the transfer
void ss_rising () {
SPDR = wheelState[0]; // load first byte into SPI data register
pos = 1;
}
// SPI interrupt routine
ISR (SPI_STC_vect) {
byte c = SPDR;
c = SPCR;
SPDR = wheelState[pos++]; // load the next byte to SPI output register and return.
}
void loop() {
// scan the button presses and save that to wheelState array. Data transfer to wheelbase is interrupt-driven above.
//wheelState[1] = ((PINB & B00000010) << 1) | (PIND & B11111011); // take bit 1 from PORTB + the rest from PORTD B11111x11
//wheelState[2] = ((PINB & B00001000) << 3) | (PINC & B00111111) | B10000000; // take bit 3 from PORTB + bits 0-5 from PORTC
}
Master Code:
/* This sketch provided "AS IS" under the BSD New license.
http://opensource.org/licenses/BSD-3-Clause
April 2015 © blog@rr-m.org
download tx_rw_wheel_reader.ino above - it has more comments */
#include <SPI.h>
#include <Arduino.h>
const int slaveSelectPin = 7;
void setup() {
Serial.begin(9600);
SPCR |= _BV(CPHA);
SPCR |= _BV(CPOL);
//SPI.beginTransaction(SPISettings(14000000, MSBFIRST, SPI_MODE0));
SPI.begin();
pinMode(slaveSelectPin, OUTPUT);
}
void loop() {
// tell the wheel, that we gonna read the data now
digitalWrite(slaveSelectPin, LOW);
// read 3 bytes and output them to Arduino Serial monitor
// as binaries 11000001 11111111 11111111
// last 17 bits are buttons. 1 - released, 0 - pressed.
for(int i=1; i<=8; i++) {
delayMicroseconds(1000);
printBinary(SPI.transfer(0x00));
}
Serial.println();
// release the wheel
digitalWrite(slaveSelectPin, HIGH);
// wait 1 second, then read data from wheel again
delay(1000);
}
// print byte as binary, zero padded if needed
// "127" -> "01111111"
void printBinary(byte data) {
for(int i=7; i>0; i--) {
if (data >> i == 0) {
Serial.print("0");
} else {
break;
}
}
Serial.print(data,BIN);
Serial.print(" ");
}
Serial output from master:
11010001 11111111 11111111 11111111 11111111 11111111 11111111 11111111
11010001 11111111 11111111 11111111 11111111 11111111 11111111 11111111
11010001 11111111 11111111 11111111 11111111 11111111 11111111 11111111
11010001 11111111 11111111 11111111 11111111 11111111 11111111 11111111
11010001 11111111 11111111 11111111 11111111 11111111 11111111 11111111
11010001 11111111 11111111 11111111 11111111 11111111 11111111 11111111