Forum Rule: Always post complete source code & details to reproduce any issue!
Page 2 of 2 FirstFirst 1 2
Results 26 to 46 of 46

Thread: Teensy 4.0 with Newhaven display

  1. #26
    OK, let me add some more detail about what I'm trying to sort out…

    I have all the key parts of the project working separately, and have made everything (decoding TPMS, sensor inputs, output to display) work together with a different display, but can't yet achieve that with the Newhaven 4.3" display. My problem is getting the Teensy 4.0 talking properly to the CC1101 and the display at the same time.

    I am currently trying to get the two SPI devices working on the main SPI bus, so have:

    pin 11 - MOSI on both display and CC1101
    pin 12 - MISO on both display and CC1101
    pin 13 - SCK on both display and CC1101
    pin 10 - CS on display
    pin 27 - CS on CC1101

    Both CC1101 and display are hooked up to +3.3V and GND, and the backlight power on the display to +5V

    there's also a MicroSD card connected via an adapter, and a variable pot for an input to test analogue sensor inputs on A1, A2, A3 - these seem to be working OK

    With this wiring, I can run EITHER a sketch that makes the display work with the dummy/temporary sensor inputs, OR a sketch that receives and decodes the TPMS data (shows it on serial monitor), but I can't seem to combine the code from both to get everything working at once - I've had a few attempts, and the best I've managed is the Newhaven display working with a sensor input for a few tens of seconds, and the CC1101 reporting to the serial monitor that it's being recognised correctly (as in Part and Version number are not both reported as zero, but no TPMS data reported)

    I have an idea that it might be better to use separate SPI buses for the Newhaven display and the CC1101, but I'm not sure how to do this, and I clearly don't know how to get both these SPI devices working on the same bus properly.

    Any pointers would be appreciated - I suspect I'm just missing/unaware of something quite basic

    So this is the sketch for the display and test sensor inputs (thanks to TFTLCDCyg for writing the code that this is based on):


    Code:
    #include <GD23ZUTX.h>
    
    #include <MegunoLink.h>
    #include <Filter.h>
    
    
    // 20 is the weight (20 => 20%)
    // 0 is the initial value of the filter
    ExponentialFilter<float> FilteredBattery(20, 0);
    ExponentialFilter<float> FilteredBoost(8, 0);
    ExponentialFilter<float> FilteredOilTemp(20, 0);
    
    // uses serial 1 bus
    // current version uses serial 1 for RF, serial 2 for screen
    // will need to switch to serial 2 for RF
    
    //Indicator needle
      int Centro=150/2;  //AE8.png, 400x400 px, Centro=400/2
      float AnguloG=65;  //offset to scale dial
      float avance, rapidez;
    //Aguja indicadora
    float dato;
    
    // for boost pressure sensor
    int mapsen = A3; // Set MAP sensor input on Analog port 6, D4
    int boost = 0; // Set boost value to 0
    int mapval = 0; // Set raw map value to 0
    int remapval = 0; // remapped boost
    
    
    void setup()
    {
      GD.begin();
    
        GD.BitmapHandle(0);
        GD.cmd_loadimage(0, 0);
        GD.load("BG03_480_272_c.jpg");
    
        GD.BitmapHandle(1);
        GD.cmd_loadimage(-1, 0);
        GD.load("AE8_180v2.png");
    
    //  tacometro();
    }
    
    void loop(){
      
      mapval= analogRead(mapsen); //Reads the MAP sensor raw value on analog port 6 (D4)
    mapval = mapval - 60; //quick and dirty fix for sensor over-read
    // boost = (mapval*(.488)/(.022)+20); //Converts raw MAP value to Bar
    
      FilteredBoost.Filter(mapval);
      float SmoothBoost = FilteredBoost.Current();
      remapval = map(SmoothBoost, 0, 676, 1, 126); // remaps 10-bit value with 5v max to suit 3.3v range and number of images
    
      
    
    
    
      GD.Clear();
    // I think this moves position of BG
      GD.Begin(BITMAPS);
        GD.Vertex2ii(0, 0, 0);
      GD.End();
    
      GD.SaveContext();
      GD.Begin(BITMAPS);
    //    avance = (1.27*2)*dato;
        avance = remapval;
        dato = dato + rapidez;
       // if((AnguloG+avance)>=275){rapidez=-0.5;}
       // if((AnguloG+avance)<=66){rapidez=0.5;}
       rapidez = remapval;
        rotate_Center(DEGREES(1.2*(AnguloG+avance)), Centro);
        GD.cmd_setmatrix();
        // moves centre of rotation or position of needle
        GD.Vertex2ii(165, 50, 1);
        GD.cmd_loadidentity();
      GD.End();
      GD.RestoreContext();
    
      GD.SaveContext();
        
       // this stuff draws the numbers, penultimate variable sets decimal places
        GD.ColorA(100);  GD.ColorRGB(0,0,0); GD.printNfloat(405, 324, dato/10, 1, 29);  GD.ColorA(255);
        if (dato>=90){GD.ColorRGB(255,0,0);}else{GD.ColorRGB(255,255,255);}
            GD.printNfloat(40, 30, dato/10, 1, 29);
            GD.printNfloat(40, 55, dato, 0, 29);
            GD.printNfloat(40, 230, dato/4, 1, 29);
            GD.printNfloat(440, 30, dato/4, 1, 29);
    //        GD.printNfloat(440, 230, dato/4, 1, 29);
            GD.printNfloat(440, 230, remapval, 1, 29);
            Serial.println(mapval);
    
      GD.RestoreContext();
      
      GD.swap();
      
    }
    
    
    
    static void rotate_Center(float a, int CXY)
    {
      GD.cmd_translate(F16(CXY),F16(CXY));
      GD.cmd_rotate(a);
      GD.cmd_translate(F16(-CXY), F16(-CXY));
    }
    And this is the code for the TPMS sketch (which is receiving TPMS data and displaying it on the serial monitor... I've removed some code for the old Nextion display it was driving, but amongst other rubbish there's definitely some unnecessary code left over from the original version that drive a 128x64 OLED display, and also the next version that drove the Nextion display. Also, I haven't included display.h as it's no longer doing anything useful here):

    Code:
    // mostly working, but currently low temp is used as proxy fr low pressure, and pressure is x1000 to get into suitable rage for display
    
    #include <EEPROM.h>
    #include <Wire.h>
    #include <SPI.h>
    
    #include "globals.h"
    #include "CC1101.h"
    #include "Display.h"
    #include "ToyotaRead.h"
    
    
    #include <MegunoLink.h>
    #include <Filter.h>
    
    // 20 is the weight (20 => 20%)
    // 0 is the initial value of the filter
    ExponentialFilter<float> FilteredBattery(20, 0);
    ExponentialFilter<float> FilteredBoost(8, 0);
    ExponentialFilter<float> FilteredOilTemp(20, 0);
    
    
    // for oil temp sensor
    // which analog pin to connect
    #define THERMISTORPIN A1    
    // resistance at 25 degrees C, changed from 43300 after measuring!
    #define THERMISTORNOMINAL 63300      
    // temp. for nominal resistance (almost always 25 C)
    #define TEMPERATURENOMINAL 25   
    // The beta coefficient of the thermistor (usually 3000-4000)
    #define BCOEFFICIENT 3832
    // the value of the 'other' resistor
    #define SERIESRESISTOR 10000   
    
    float raw = 0;
    float steinhart;
    // for battery monitor, requires bridge with 4k7 and 980 resistors
    #define Vin A2
    const float Vref = 5.00;
    const float R1 = 100000.0;
    const float R2 = 22000.0;
    float volts = 0;
    const float resDiv = 1.095 * (R2/(R1 + R2)); // Resistor divider factor applied to measured voltage, constant added after calibration measurements
    
    int oiltemp = 0;
    String stringvolts = "";
    String buffer = "";
    
    int tempvalue = 1;
    int LEDvalue = 127;
    float oilaverage = 0;
    float battaverage = 0;
    int integervolts = 0;
    int temp=0; // for oil temp
    
    // for boost pressure sensor
    int mapsen = A3; // Set MAP sensor input on Analog port 6, D4
    int boost = 0; // Set boost value to 0
    int mapval = 0; // Set raw map value to 0
    int remapval = 0; // remapped boost
    
    int test;
    
    #include <MegunoLink.h>
    
    
    void SendDebug(String Mess)
    {
      Serial.println(Mess);
    }
    
    
    
    int DecodeBitArray()
    {
      //convert 1s and 0s array to byte array
      int i;
      int n = 0;
      byte b = 0;
    
      RXByteCount = 0;
      for (i = 0; i < BitCount; i++)
      {
        b = b << 1;
        b = b + IncomingBits[i];
        n++;
        if (n == 8)
        {
          RXBytes[RXByteCount] = b;
          RXByteCount++;
          n = 0;
          b = 0;
        }
    
      }
      return (RXByteCount);
    
    
    }
    
    void setup() {
    
    
    // analogReference(DEFAULT); // for oil temp and possibly other analogue pins
    
    pinMode(A2, INPUT); // Set A2 as INPUT to read battery voltage
    
    
      Serial1.begin(9600);
    
      myMP3.begin(Serial1);
      
      myMP3.volume(15);
     
    
      Serial2.begin(9600);  // Start Serial2 comunication at baud=9600
     
    
    
    // analogReference(DEFAULT); // for oil temp and possibly other analogue pins
    
    
      // I am going to change the Serial2 baud to a faster rate.
      delay(500);  // This delay is just in case the nextion display didn't start yet, to be sure it will receive the following command.
      Serial2.print("baud=115200");  // Set new baud rate of nextion to 115200, but it's temporal. Next time nextion is power on,
                                    // it will retore to default baud of 9600.
                                    // To take effect, make sure to reboot the arduino (reseting arduino is not enough).
                                    // If you want to change the default baud, send the command as "bauds=115200", instead of "baud=115200".
                                    // If you change the default baud, everytime the nextion is power ON is going to have that baud rate, and
                                    // would not be necessery to set the baud on the setup anymore.
      Serial2.write(0xff);  // We always have to send this three lines after each command sent to nextion.
      Serial2.write(0xff);
      Serial2.write(0xff);
    
      Serial2.end();  // End the Serial2 comunication of baud=9600
    
      Serial2.begin(115200);  // Start Serial2 comunication at baud=115200
    
    // sensor stuff ends
      byte resp;
      unsigned int t;
      int LEDState = LOW;
      int i;
      int mcount;
    
      //SPI CC1101 chip select set up
      pinMode(CC1101_CS, OUTPUT);
      digitalWrite(CC1101_CS, HIGH);
    
    
      Serial.begin(115200);
    
    
    
      pinMode(LED_RX, OUTPUT);
      pinMode(RXPin, INPUT);
    
    
      SPI.begin();
      //initialise the CC1101
      CC1101_reset();
    
      delay(2000);
    
      Serial.println("Starting...");
    
    
    
      setIdleState();
      digitalWrite(LED_RX, LED_OFF);
    
      resp = readStatusReg(CC1101_PARTNUM);
      Serial.print(F("Part no: "));
      Serial.println(resp, HEX);
    
      resp = readStatusReg(CC1101_VERSION);
      Serial.print(F("Version: "));
      Serial.println(resp, HEX);
    
    
    #if USE_ADAFRUIT
      if (!display.begin(SSD1306_EXTERNALVCC, I2C_ADDRESS)) {
        Serial.println(F("SSD1306 allocation failed"));
        for (;;); // Don't proceed, loop forever
      }
    #else
      Wire.begin();
      Wire.setClock(400000L);
      display.begin(&Adafruit128x64, I2C_ADDRESS);
      display.setFont(Adafruit5x7);
    
    #endif
    
    
    
      Serial.println(F("SSD1306 initialised OK"));
    
    
      digitalWrite(LED_RX, LED_ON);
      LEDState = HIGH;
    
      pinMode(DEBUGPIN, OUTPUT);
    
    #ifndef USE_PROGMEMCRC
      CalulateTable_CRC8();
    #endif
    
      // Clear the buffer
    #if USE_ADAFRUIT
      display.clearDisplay();
      display.display();
    #else
      display.clear();
    #endif
    
      InitTPMS();
    
    
      digitalWrite(LED_RX, LED_OFF);
    
      setRxState();
    }
    
    void loop() {
    
    
    // boost sensor stuff
    mapval= analogRead(mapsen); //Reads the MAP sensor raw value on analog port 6 (D4)
    mapval = mapval - 60; //quick and dirty fix for sensor over-read
    // boost = (mapval*(.488)/(.022)+20); //Converts raw MAP value to Bar
    
      FilteredBoost.Filter(mapval);
      float SmoothBoost = FilteredBoost.Current();
      remapval = map(SmoothBoost, 0, 676, 1, 126); // remaps 10-bit value with 5v max to suit 3.3v range and number of images
    
    
    
    
    //battery reading
    // raw += analogRead(Vin);
    // added 0.9133 fix to make reading accurate after checks
    float RawBattery = (analogRead(A2)/ 1024.0) * Vref;
    FilteredBattery.Filter(RawBattery);
    float SmoothBattery = FilteredBattery.Current();
    volts = (SmoothBattery / resDiv);
    float adjustedvolts = volts*10;
    int integervolts = int(10*volts);
    
    
    // oil temp stuff
    
    int oilaverage = analogRead(THERMISTORPIN);
    
      FilteredOilTemp.Filter(oilaverage);
      float SmoothOilTemp = FilteredOilTemp.Current();
      
      // convert the value to resistance
      SmoothOilTemp = 708 / SmoothOilTemp - 1;
      SmoothOilTemp = SERIESRESISTOR / SmoothOilTemp;
     
      float steinhart;
      steinhart = SmoothOilTemp / THERMISTORNOMINAL;     // (R/Ro)
      steinhart = log(steinhart);                  // ln(R/Ro)
      steinhart /= BCOEFFICIENT;                   // 1/B * ln(R/Ro)
      steinhart += 1.0 / (TEMPERATURENOMINAL + 273.15); // + (1/To)
      steinhart = 1.0 / steinhart;                 // Invert
      steinhart -= 273.15;                         // convert to C
    
    
    temp = round(steinhart);
    // temp = analogRead(A5);
    
    
      
    // listen for touch screen input  
    if(Serial2.available()) {
      String data_from_display="";
      delay(2);
      while (Serial2.available()){
        data_from_display += char(Serial2.read());
      }
      Serial.println(data_from_display);
      sendDisplayData(data_from_display);
      
    }
    
    
      if (warning == 1) {
      myMP3.play(1);
      delay(1700);
      }
      
      // put your main code here, to run repeatedly:
      int i;
      static long lastts = millis();
      float diff;
      int RXBitCount = 0;
      int ByteCount = 0;
      byte crcResult;
      boolean TPMS_Changed;
    
    
    
    
      TPMS_Changed = Check_TPMS_Timeouts();
    
      InitDataBuffer();
    
      //wait for carrier status to go low
      while (GetCarrierStatus() == true)
      {
      }
    
      //wait for carrier status to go high  looking for rising edge
      while (GetCarrierStatus() == false)
      {
      }
    
      if (GetCarrierStatus() == true)
      { //looks like some data coming in...
        RXBitCount = ReceiveMessage();
        if (RXBitCount == 72 )
        {
          ByteCount = DecodeBitArray();
    
          crcResult = Compute_CRC8(ByteCount);
    
          if (crcResult != 0)
          {
            //Serial.print(F("CRC: "));
            //Serial.println(crcResult, HEX);
            //Serial.println(F("CRC Check failed"));
            //PrintData(BitCount);
          }
          else
          {
            //decode the message...
            DecodeTPMS();
            TPMS_Changed = true;  //indicates the display needs to be updated.
          }
        }
    
        if (TPMS_Changed)
        {
      //    UpdateBigDisplay();
    
          TPMS_Changed = false;
        }
      }
    
    
    }
    
    
    void sendDisplayData(String data_from_display){
      Serial.println(data_from_display);
      if (data_from_display == "volchange") {
    
    if (warning == 0) {
      warning = 1;
    }
    if (warning == 1) {
      warning = 0;
    
    }
    
     }
    }
    cc1101.h:

    Code:
    enum RFSTATE
    {
      RFSTATE_IDLE = 0,
      RFSTATE_RX,
      RFSTATE_TX
    };
    
    
    
    
    
    // SPIClass spi;
    
    /**
     * Frequency channels
     */
    #define NUMBER_OF_FCHANNELS      10
    
    /**
     * Type of transfers
     */
    #define WRITE_BURST              0x40
    #define READ_SINGLE              0x80
    #define READ_BURST               0xC0
    
    /**
     * Type of register
     */
    #define CC1101_CONFIG_REGISTER   READ_SINGLE
    #define CC1101_STATUS_REGISTER   READ_BURST
    
    
    /**
     * Buffer and data lengths
     */
    #define CCPACKET_BUFFER_LEN        64
    #define CCPACKET_DATA_LEN          CCPACKET_BUFFER_LEN - 3
    
    /**
     * Class: CCPACKET
     * 
     * Description:
     * CC1101 data packet class
     */
    struct CCPACKET
    {
      public:
         //Data length
        unsigned char length;
         // Data buffer
        unsigned char data[CCPACKET_DATA_LEN];
         //* CRC OK flag
        bool crc_ok;
         // Received Strength Signal Indication
        unsigned char rssi;
         // Link Quality Index
        unsigned char lqi;
    };
    
    
    
    /**
     * Macros
     */
    
    #define wait_Miso()  delay(3)
    //while(digitalRead(PORT_SPI_MISO))
    // Get GDO0 pin state
    #define getGDO0state()  digitalRead(PORT_GDO0)
    // Wait until GDO0 line goes high
    #define wait_GDO0_high()  while(!getGDO0state()) {delay(1);}
    // Wait until GDO0 line goes low
    #define wait_GDO0_low()  while(getGDO0state()) {delay(1);}
    
    
    
    /**
     * PATABLE & FIFO's
     */
    #define CC1101_PATABLE           0x3E        // PATABLE address
    #define CC1101_TXFIFO            0x3F        // TX FIFO address
    #define CC1101_RXFIFO            0x3F        // RX FIFO address
    
    /**
     * Command strobes
     */
    #define CC1101_SRES              0x30        // Reset CC1101 chip
    #define CC1101_SFSTXON           0x31        // Enable and calibrate frequency synthesizer (if MCSM0.FS_AUTOCAL=1). If in RX (with CCA):
                                                 // Go to a wait state where only the synthesizer is running (for quick RX / TX turnaround).
    #define CC1101_SXOFF             0x32        // Turn off crystal oscillator
    #define CC1101_SCAL              0x33        // Calibrate frequency synthesizer and turn it off. SCAL can be strobed from IDLE mode without
                                                 // setting manual calibration mode (MCSM0.FS_AUTOCAL=0)
    #define CC1101_SRX               0x34        // Enable RX. Perform calibration first if coming from IDLE and MCSM0.FS_AUTOCAL=1
    #define CC1101_STX               0x35        // In IDLE state: Enable TX. Perform calibration first if MCSM0.FS_AUTOCAL=1.
                                                 // If in RX state and CCA is enabled: Only go to TX if channel is clear
    #define CC1101_SIDLE             0x36        // Exit RX / TX, turn off frequency synthesizer and exit Wake-On-Radio mode if applicable
    #define CC1101_SWOR              0x38        // Start automatic RX polling sequence (Wake-on-Radio) as described in Section 19.5 if
                                                 // WORCTRL.RC_PD=0
    #define CC1101_SPWD              0x39        // Enter power down mode when CSn goes high
    #define CC1101_SFRX              0x3A        // Flush the RX FIFO buffer. Only issue SFRX in IDLE or RXFIFO_OVERFLOW states
    #define CC1101_SFTX              0x3B        // Flush the TX FIFO buffer. Only issue SFTX in IDLE or TXFIFO_UNDERFLOW states
    #define CC1101_SWORRST           0x3C        // Reset real time clock to Event1 value
    #define CC1101_SNOP              0x3D        // No operation. May be used to get access to the chip status byte
    
    /**
     * CC1101 configuration registers
     */
    #define CC1101_IOCFG2            0x00        // GDO2 Output Pin Configuration
    #define CC1101_IOCFG1            0x01        // GDO1 Output Pin Configuration
    #define CC1101_IOCFG0            0x02        // GDO0 Output Pin Configuration
    #define CC1101_FIFOTHR           0x03        // RX FIFO and TX FIFO Thresholds
    #define CC1101_SYNC1             0x04        // Sync Word, High Byte
    #define CC1101_SYNC0             0x05        // Sync Word, Low Byte
    #define CC1101_PKTLEN            0x06        // Packet Length
    #define CC1101_PKTCTRL1          0x07        // Packet Automation Control
    #define CC1101_PKTCTRL0          0x08        // Packet Automation Control
    #define CC1101_ADDR              0x09        // Device Address
    #define CC1101_CHANNR            0x0A        // Channel Number
    #define CC1101_FSCTRL1           0x0B        // Frequency Synthesizer Control
    #define CC1101_FSCTRL0           0x0C        // Frequency Synthesizer Control
    #define CC1101_FREQ2             0x0D        // Frequency Control Word, High Byte
    #define CC1101_FREQ1             0x0E        // Frequency Control Word, Middle Byte
    #define CC1101_FREQ0             0x0F        // Frequency Control Word, Low Byte
    #define CC1101_MDMCFG4           0x10        // Modem Configuration
    #define CC1101_MDMCFG3           0x11        // Modem Configuration
    #define CC1101_MDMCFG2           0x12        // Modem Configuration
    #define CC1101_MDMCFG1           0x13        // Modem Configuration
    #define CC1101_MDMCFG0           0x14        // Modem Configuration
    #define CC1101_DEVIATN           0x15        // Modem Deviation Setting
    #define CC1101_MCSM2             0x16        // Main Radio Control State Machine Configuration
    #define CC1101_MCSM1             0x17        // Main Radio Control State Machine Configuration
    #define CC1101_MCSM0             0x18        // Main Radio Control State Machine Configuration
    #define CC1101_FOCCFG            0x19        // Frequency Offset Compensation Configuration
    #define CC1101_BSCFG             0x1A        // Bit Synchronization Configuration
    #define CC1101_AGCCTRL2          0x1B        // AGC Control
    #define CC1101_AGCCTRL1          0x1C        // AGC Control
    #define CC1101_AGCCTRL0          0x1D        // AGC Control
    #define CC1101_WOREVT1           0x1E        // High Byte Event0 Timeout
    #define CC1101_WOREVT0           0x1F        // Low Byte Event0 Timeout
    #define CC1101_WORCTRL           0x20        // Wake On Radio Control
    #define CC1101_FREND1            0x21        // Front End RX Configuration
    #define CC1101_FREND0            0x22        // Front End TX Configuration
    #define CC1101_FSCAL3            0x23        // Frequency Synthesizer Calibration
    #define CC1101_FSCAL2            0x24        // Frequency Synthesizer Calibration
    #define CC1101_FSCAL1            0x25        // Frequency Synthesizer Calibration
    #define CC1101_FSCAL0            0x26        // Frequency Synthesizer Calibration
    #define CC1101_RCCTRL1           0x27        // RC Oscillator Configuration
    #define CC1101_RCCTRL0           0x28        // RC Oscillator Configuration
    #define CC1101_FSTEST            0x29        // Frequency Synthesizer Calibration Control
    #define CC1101_PTEST             0x2A        // Production Test
    #define CC1101_AGCTEST           0x2B        // AGC Test
    #define CC1101_TEST2             0x2C        // Various Test Settings
    #define CC1101_TEST1             0x2D        // Various Test Settings
    #define CC1101_TEST0             0x2E        // Various Test Settings
    
    /**
     * Status registers
     */
    #define CC1101_PARTNUM           0x30        // Chip ID
    #define CC1101_VERSION           0x31        // Chip ID
    #define CC1101_FREQEST           0x32        // Frequency Offset Estimate from Demodulator
    #define CC1101_LQI               0x33        // Demodulator Estimate for Link Quality
    #define CC1101_RSSI              0x34        // Received Signal Strength Indication
    #define CC1101_MARCSTATE         0x35        // Main Radio Control State Machine State
    #define CC1101_WORTIME1          0x36        // High Byte of WOR Time
    #define CC1101_WORTIME0          0x37        // Low Byte of WOR Time
    #define CC1101_PKTSTATUS         0x38        // Current GDOx Status and Packet Status
    #define CC1101_VCO_VC_DAC        0x39        // Current Setting from PLL Calibration Module
    #define CC1101_TXBYTES           0x3A        // Underflow and Number of Bytes
    #define CC1101_RXBYTES           0x3B        // Overflow and Number of Bytes
    #define CC1101_RCCTRL1_STATUS    0x3C        // Last RC Oscillator Calibration Result
    #define CC1101_RCCTRL0_STATUS    0x3D        // Last RC Oscillator Calibration Result 
    
    
    #define CC1101_DEFVAL_IOCFG2     0x0D        // GDO2 Output Pin Configuration - Serial out
    #define CC1101_DEFVAL_IOCFG1     0x2E        // GDO1 Output Pin Configuration - not used
    //#define CC1101_DEFVAL_IOCFG0     0x0D        // GDO0 Output Pin Configuration
    #define CC1101_DEFVAL_IOCFG0     0x0E        // GDO0 Output Pin Configuration - Carrier Sense output
    #define CC1101_DEFVAL_FIFOTHR    0x0F        // RX FIFO and TX FIFO Thresholds - 64 bytes in FIFO
    #define CC1101_DEFVAL_SYNC1      0xD5        // Synchronization word, high byte  11010101 01001111
    #define CC1101_DEFVAL_SYNC0      0x4F        // Synchronization word, low byte
    #define CC1101_DEFVAL_PKTLEN     0x09        // Packet Length
    #define CC1101_DEFVAL_PKTCTRL1   0x00        // Packet Automation Control
    #define CC1101_DEFVAL_PKTCTRL0   0x30        // Packet Automation Control
    #define CC1101_DEFVAL_ADDR       0x00        // Device Address
    #define CC1101_DEFVAL_CHANNR     0x00        // Channel Number
    #define CC1101_DEFVAL_FSCTRL1    0x0F        // Frequency Synthesizer Control (was 0x06)
    #define CC1101_DEFVAL_FSCTRL0    0x00        // Frequency Synthesizer Control
    // Carrier frequency = 868 MHz (not used)
    //#define CC1101_DEFVAL_FREQ2_868  0x21        // Frequency Control Word, High Byte
    //#define CC1101_DEFVAL_FREQ1_868  0x65        // Frequency Control Word, Middle Byte
    //#define CC1101_DEFVAL_FREQ0_868  0xCC        // Frequency Control Word, Low Byte
    // Carrier frequency = 433.8798 MHz
    #define CC1101_DEFVAL_FREQ2_433  0x10        // Frequency Control Word, High Byte
    #define CC1101_DEFVAL_FREQ1_433  0xB0        // Frequency Control Word, Middle Byte
    #define CC1101_DEFVAL_FREQ0_433  0x0C        // Frequency Control Word, Low Byte
    
    #define CC1101_DEFVAL_MDMCFG4    0x59        // Modem Configuration (59 = data rate = 20kHz - actual data rate is 10kHz but due to bi-phase coding need to double the rate, RX bandwidth 325kHz)
    #define CC1101_DEFVAL_MDMCFG3    0x93        // Modem Configuration (now 93 = data rate = 20kHz)
    #define CC1101_DEFVAL_MDMCFG2    0x10        // Modem Configuration (GFSK, No Sync or Manchester coding)
    
    #define CC1101_DEFVAL_MDMCFG1    0x22        // Modem Configuration Channel spacing 200kHz
    #define CC1101_DEFVAL_MDMCFG0    0xF8        // Modem Configuration
    #define CC1101_DEFVAL_DEVIATN    0x41        // Modem Deviation Setting (+/-28.56kHz)
    #define CC1101_DEFVAL_MCSM2      0x07        // Main Radio Control State Machine Configuration
    //#define CC1101_DEFVAL_MCSM1      0x30        // Main Radio Control State Machine Configuration
    #define CC1101_DEFVAL_MCSM1      0x3C        // Main Radio Control State Machine Configuration
    #define CC1101_DEFVAL_MCSM0      0x18        // Main Radio Control State Machine Configuration
    #define CC1101_DEFVAL_FOCCFG     0x16        // Frequency Offset Compensation Configuration
    #define CC1101_DEFVAL_BSCFG      0x6C        // Bit Synchronization Configuration
    //#define CC1101_DEFVAL_AGCCTRL2   0x43        // AGC Control
    #define CC1101_DEFVAL_AGCCTRL2   0xC6        // AGC Control
    //#define CC1101_DEFVAL_AGCCTRL1   0x40        // AGC Control
    #define CC1101_DEFVAL_AGCCTRL1   0x50        // AGC Control
    #define CC1101_DEFVAL_AGCCTRL0   0x80        // AGC Control
    
    #define CC1101_DEFVAL_WOREVT1    0x87        // High Byte Event0 Timeout
    #define CC1101_DEFVAL_WOREVT0    0x6B        // Low Byte Event0 Timeout
    #define CC1101_DEFVAL_WORCTRL    0xFB        // Wake On Radio Control
    #define CC1101_DEFVAL_FREND1     0x56        // Front End RX Configuration
    #define CC1101_DEFVAL_FREND0     0x10        // Front End TX Configuration
    
    #define CC1101_DEFVAL_FSCAL3     0xE9        // Frequency Synthesizer Calibration
    #define CC1101_DEFVAL_FSCAL2     0x2A        // Frequency Synthesizer Calibration
    #define CC1101_DEFVAL_FSCAL1     0x00        // Frequency Synthesizer Calibration
    #define CC1101_DEFVAL_FSCAL0     0x1F        // Frequency Synthesizer Calibration
    
    #define CC1101_DEFVAL_RCCTRL1    0x41        // RC Oscillator Configuration
    #define CC1101_DEFVAL_RCCTRL0    0x00        // RC Oscillator Configuration
    
    #define CC1101_DEFVAL_FSTEST     0x59        // Frequency Synthesizer Calibration Control
    
    #define CC1101_DEFVAL_PTEST      0x7F        // Production Test
    #define CC1101_DEFVAL_AGCTEST    0x3F        // AGC Test
    
    #define CC1101_DEFVAL_TEST2      0x81        // Various Test Settings
    #define CC1101_DEFVAL_TEST1      0x35        // Various Test Settings
    #define CC1101_DEFVAL_TEST0      0x09        // Various Test Settings
    
    
    /**
     * Alias for some default values
     */
    #define CCDEF_CHANNR  CC1101_DEFVAL_CHANNR
    #define CCDEF_SYNC0  CC1101_DEFVAL_SYNC0
    #define CCDEF_SYNC1  CC1101_DEFVAL_SYNC1
    #define CCDEF_ADDR  CC1101_DEFVAL_ADDR
    
    /**
     * Macros
     */
    // Read CC1101 Config register
    #define readConfigReg(regAddr)    readReg(regAddr, CC1101_CONFIG_REGISTER)
    // Read CC1101 Status register
    #define readStatusReg(regAddr)    readReg(regAddr, CC1101_STATUS_REGISTER)
    // Enter Rx state
    //#define setRxState()              cmdStrobe(CC1101_SRX)
    // Enter Tx state
    //#define setTxState()              cmdStrobe(CC1101_STX)
    // Enter IDLE state
    #define setIdleState()            cmdStrobe(CC1101_SIDLE)
    // Flush Rx FIFO
    #define flushRxFifo()             cmdStrobe(CC1101_SFRX)
    // Flush Tx FIFO
    #define flushTxFifo()             cmdStrobe(CC1101_SFTX)
    // Disable address check
    #define disableAddressCheck()     writeReg(CC1101_PKTCTRL1, 0x04)
    // Enable address check
    #define enableAddressCheck()      writeReg(CC1101_PKTCTRL1, 0x06)
    // Disable CCA
    #define disableCCA()              writeReg(CC1101_MCSM1, 0)
    // Enable CCA
    #define enableCCA()               writeReg(CC1101_MCSM1, CC1101_DEFVAL_MCSM1)
    // Set PATABLE single byte
    #define setTxPowerAmp(setting)    paTableByte = setting
    // PATABLE values
    #define PA_LowPower               0x60
    #define PA_LongDistance           0xC0
    
    
    
    
    // Select (SPI) CC1101
    void cc1101_Select(){
    
      //delayMicroseconds(150);
      //spi.begin();
      SPI.beginTransaction(SPISettings(5000000,MSBFIRST,SPI_MODE0));
      digitalWrite(CC1101_CS, LOW);
    }
    
    void cc1101_Deselect(){
      //spi.end();
    
      //delayMicroseconds(50);
      digitalWrite(CC1101_CS, HIGH);
      SPI.endTransaction();
    
    
    }
    
    /**
     * wakeUp
     * 
     * Wake up CC1101 from Power Down state
     */
    void wakeUp(void)
    {
      cc1101_Select();                      // Select CC1101
      wait_Miso();                          // Wait until MISO goes low
      cc1101_Deselect();                    // Deselect CC1101
    }
    
    
    /**
     * writeReg
     * 
     * Write single register into the CC1101 IC via SPI
     * 
     * 'regAddr'  Register address
     * 'value'  Value to be writen
     */
    void writeReg(byte regAddr, byte value) 
    {
      cc1101_Select();                      // Select CC1101
      //wait_Miso();                          // Wait until MISO goes low
      SPI.transfer(regAddr);                    // Send register address
      SPI.transfer(value);                      // Send value
      cc1101_Deselect();                    // Deselect CC1101
    }
    
    /**
     * readReg
     * 
     * Read CC1101 register via SPI
     * 
     * 'regAddr'  Register address
     * 'regType'  Type of register: CC1101_CONFIG_REGISTER or CC1101_STATUS_REGISTER
     * 
     * Return:
     *  Data byte returned by the CC1101 IC
     */
    byte readReg(byte regAddr, byte regType)
    {
      byte addr, val;
    
      addr = regAddr | regType;
      cc1101_Select();                      // Select CC1101
      //wait_Miso();                          // Wait until MISO goes low
      SPI.transfer(addr);                       // Send register address
      val = SPI.transfer(0x00);                 // Read result
      cc1101_Deselect();                    // Deselect CC1101
    
      return val;
    }
    
    /**
     * setCCregs
     * 
     * Configure CC1101 registers
     */
    void setCCregs(void) 
    {
      writeReg(CC1101_IOCFG2,  CC1101_DEFVAL_IOCFG2);
      writeReg(CC1101_IOCFG1,  CC1101_DEFVAL_IOCFG1);
      writeReg(CC1101_IOCFG0,  CC1101_DEFVAL_IOCFG0);
      writeReg(CC1101_FIFOTHR,  CC1101_DEFVAL_FIFOTHR);
      writeReg(CC1101_PKTLEN,  CC1101_DEFVAL_PKTLEN);
      writeReg(CC1101_PKTCTRL1,  CC1101_DEFVAL_PKTCTRL1);
      writeReg(CC1101_PKTCTRL0,  CC1101_DEFVAL_PKTCTRL0);
    
      // Set default synchronization word
      //setSyncWord(syncWord);
    
      // Set default device address
      //setDevAddress(devAddress);
    
      // Set default frequency channel
      //setChannel(channel);
      
      writeReg(CC1101_FSCTRL1,  CC1101_DEFVAL_FSCTRL1);
      writeReg(CC1101_FSCTRL0,  CC1101_DEFVAL_FSCTRL0);
    
    //  // Set default carrier frequency = 868 MHz
    //  //setCarrierFreq(carrierFreq);
    //  writeReg(CC1101_FREQ2,  CC1101_DEFVAL_FREQ2_868);
    //  writeReg(CC1101_FREQ1,  CC1101_DEFVAL_FREQ1_868);
    //  writeReg(CC1101_FREQ0,  CC1101_DEFVAL_FREQ0_868);
    
      // Set default carrier frequency = 433 MHz
      //setCarrierFreq(carrierFreq);
      writeReg(CC1101_FREQ2,  CC1101_DEFVAL_FREQ2_433);
      writeReg(CC1101_FREQ1,  CC1101_DEFVAL_FREQ1_433);
      writeReg(CC1101_FREQ0,  CC1101_DEFVAL_FREQ0_433);
    
      writeReg(CC1101_MDMCFG4,  CC1101_DEFVAL_MDMCFG4);
      writeReg(CC1101_MDMCFG3,  CC1101_DEFVAL_MDMCFG3);
      writeReg(CC1101_MDMCFG2,  CC1101_DEFVAL_MDMCFG2);
      writeReg(CC1101_MDMCFG1,  CC1101_DEFVAL_MDMCFG1);
      writeReg(CC1101_MDMCFG0,  CC1101_DEFVAL_MDMCFG0);
      writeReg(CC1101_DEVIATN,  CC1101_DEFVAL_DEVIATN);
      writeReg(CC1101_MCSM2,  CC1101_DEFVAL_MCSM2);
      writeReg(CC1101_MCSM1,  CC1101_DEFVAL_MCSM1);
      writeReg(CC1101_MCSM0,  CC1101_DEFVAL_MCSM0);
      writeReg(CC1101_FOCCFG,  CC1101_DEFVAL_FOCCFG);
      writeReg(CC1101_BSCFG,  CC1101_DEFVAL_BSCFG);
      writeReg(CC1101_AGCCTRL2,  CC1101_DEFVAL_AGCCTRL2);
      writeReg(CC1101_AGCCTRL1,  CC1101_DEFVAL_AGCCTRL1);
      writeReg(CC1101_AGCCTRL0,  CC1101_DEFVAL_AGCCTRL0);
      writeReg(CC1101_WOREVT1,  CC1101_DEFVAL_WOREVT1);
      writeReg(CC1101_WOREVT0,  CC1101_DEFVAL_WOREVT0);
      writeReg(CC1101_WORCTRL,  CC1101_DEFVAL_WORCTRL);
      writeReg(CC1101_FREND1,  CC1101_DEFVAL_FREND1);
      writeReg(CC1101_FREND0,  CC1101_DEFVAL_FREND0);
      writeReg(CC1101_FSCAL3,  CC1101_DEFVAL_FSCAL3);
      writeReg(CC1101_FSCAL2,  CC1101_DEFVAL_FSCAL2);
      writeReg(CC1101_FSCAL1,  CC1101_DEFVAL_FSCAL1);
      writeReg(CC1101_FSCAL0,  CC1101_DEFVAL_FSCAL0);
      writeReg(CC1101_RCCTRL1,  CC1101_DEFVAL_RCCTRL1);
      writeReg(CC1101_RCCTRL0,  CC1101_DEFVAL_RCCTRL0);
      writeReg(CC1101_FSTEST,  CC1101_DEFVAL_FSTEST);
      writeReg(CC1101_PTEST,  CC1101_DEFVAL_PTEST);
      writeReg(CC1101_AGCTEST,  CC1101_DEFVAL_AGCTEST);
      writeReg(CC1101_TEST2,  CC1101_DEFVAL_TEST2);
      writeReg(CC1101_TEST1,  CC1101_DEFVAL_TEST1);
      writeReg(CC1101_TEST0,  CC1101_DEFVAL_TEST0);
      
      // Send empty packet
    //  CCPACKET packet;
    //  packet.length = 0;
    //  sendData(packet);
    }
    
    /**
     * cmdStrobe
     * 
     * Send command strobe to the CC1101 IC via SPI
     * 
     * 'cmd'  Command strobe
     */     
    void cmdStrobe(byte cmd) 
    {
      cc1101_Select();                      // Select CC1101
      //wait_Miso();                          // Wait until MISO goes low
      SPI.transfer(cmd);                        // Send strobe command
      cc1101_Deselect();                    // Deselect CC1101
    }
    
    
    /**
     * setRxState
     * 
     * Enter Rx state
     */
    void setRxState()
    {
      cmdStrobe(CC1101_SRX);
    
    }
    
    void setTxState()
    {
      cmdStrobe(CC1101_STX);
    
    }
    
    
    /**
     * reset
     * 
     * Reset CC1101
     */
    void CC1101_reset(void) 
    {
      cc1101_Deselect();                    // Deselect CC1101
      delayMicroseconds(5);
      cc1101_Select();                      // Select CC1101
      delayMicroseconds(10);
      cc1101_Deselect();                    // Deselect CC1101
      delayMicroseconds(41);
      cc1101_Select();                      // Select CC1101
    
      wait_Miso();                          // Wait until MISO goes low
      SPI.transfer(CC1101_SRES);                // Send reset command strobe
      wait_Miso();                          // Wait until MISO goes low
    
      cc1101_Deselect();                    // Deselect CC1101
    
      setCCregs();                          // Reconfigure CC1101
    }
    
    boolean GetCarrierStatus()
    {
      byte ret;
      ret = readStatusReg(CC1101_PKTSTATUS);
      if ((ret & 0x40) == 0)
      {
        return(false);
      }
      else
      {
        return(true);
      }
    }
    
    void WaitCarrierEnd()
    {
       while (GetCarrierStatus() == true)
       {
           //wait for carrier detect to change to low state
           delayMicroseconds(100);
       }
    }
    globals.h:
    Code:
    #define USE_PROGMEMCRC 1
    #define SHOWDEGUGINFO 1
    
    #define I2C_ADDRESS 0x3C
    
    #define LED_RX 17
    #define LED_OFF HIGH
    #define LED_ON LOW
    
    #define TPMS_TIMEOUT 900000 //(15 * 60 * 1000)  15 minutes
    
    #define FONTBAR_7 123
    #define FONTBAR_5 124
    #define FONTBAR_3 125
    #define FONTBAR_2 126
    #define FONTBAR_1 127
    #define FONTBAR_0 32
    
    int intpressure;
    int warning = 0;
    
    
    const int CC1101_CS = 27;  // Define the Chip Select pin
    const int RXPin = 6; // changed this from 7 to free that pin for Rx from display
    
    const int DEBUGPIN = 6;
    
    
    const int MAXBITS = 100;
    
    //const long Tlong_us = 100;
    //const long Tshort_us = Tlong_us/2;
    const int Ttol_l_us = 25;
    const int Ttol_s_us = 13;
    volatile static unsigned long LastEdgeTime_us = 0;
    
    volatile static bool ValidBlock = false;
    volatile static bool WaitingFirstEdge = true;
    volatile byte Timings[256];
    
    volatile uint8_t TimingsIndex = 0;
    uint8_t CheckIndex = 0;
    bool SyncFound = false;
    unsigned long CD_Width;
     byte StartDataIndex = 0;
    
    
    
    bool IncomingBits[MAXBITS]; 
    unsigned int BitIndex = 0;
    unsigned int BitCount = 0;
    
    unsigned int FreqOffset;
    unsigned int DemodLinkQuality;
    unsigned int RSSIvalue;
    
    
    int RawCount = 0;
    //byte ManchesterRX[64];  //holds received Manchester byte message (converted from the rawdata)
    byte RXBytes[10];  //holds the raw incoming databytes from the CC1101 serial port
    int RXByteCount;
    unsigned long IncomingAddress;
    
    
    //this table (and its order define known TPMS IDs so that they their values are always displayed in the same order
    const unsigned long PROGMEM IDLookup[]
    {
      0xF0117227, 0xF0117281,
      0xF0117204, 0xF0117255
    };
    
    
    
    #ifdef USE_PROGMEMCRC
      ////CRCTable
      const byte PROGMEM crctable2[] =
      {
      
          0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
          0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
          0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
          0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
          0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
          0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
          0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
          0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
          0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
          0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
          0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
          0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
          0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
          0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
          0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
          0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
      };
    #else
      static byte crctable[256];
      const byte PROGMEM crctable2[] =
      {
      
          0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
          0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
          0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
          0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
          0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
          0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
          0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
          0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
          0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
          0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
          0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
          0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
          0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
          0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
          0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
          0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
      };
    #endif
    
    struct TPMS_entry
    {
      unsigned long TPMS_ID;
      unsigned long lastupdated;
      unsigned int TPMS_Status;
      float TPMS_Pressure;
      float TPMS_Temperature;
      int TPMS_Intpressure;
    } TPMS[4];
    
    
    enum RXStates
    {
      Waiting_Byte33 = 0,
      Got_Byte33,
      Got_Byte55,
      Got_Byte53,
      Manch1,
      Manch2
    };
    toyotaread.h:



    Code:
    void ClearTPMSData(int i)
    {
      if (i > 4)
        return;
    
      TPMS[i].TPMS_ID = 0;
      TPMS[i].lastupdated = 0;
    
    }
    
    void PulseDebugPin(int width_us)
    {
      digitalWrite(DEBUGPIN, HIGH);
      delayMicroseconds(width_us);
      digitalWrite(DEBUGPIN, LOW);
    }
    
    
    int GetPreferredIndex(unsigned long ID)
    {
      int i;
    
      for (i = 0; i  < (sizeof(IDLookup) / sizeof(IDLookup[0])); i++)
      {
        if (IDLookup[i] == ID)
        {
          return (i);
        }
    
      }
      return (-1);
    }
    
    
    
    void PrintTimings(byte StartPoint, byte Count)
    {
      byte i;
      for (i = 0; i < Count; i++)
      {
        Serial.print(Timings[StartPoint + i]);
        Serial.print(F(","));
      }
      Serial.println(F(""));
      //    for (i = 0;i<Count;i++)
      //    {
      //          Serial.print(BitTimings[StartPoint + i]);
      //          Serial.print(",");
      //    }
      //    Serial.println("");
    
    
    }
    
    void PrintData(byte Count)
    {
      byte i;
      byte hexdata;
      for (i = 0; i < Count; i++)
      {
        Serial.print(IncomingBits[i]);
        hexdata = (hexdata << 1) + IncomingBits[i];
        if ((i + 1) % 8 == 0)
        {
          Serial.print(F(" ["));
          Serial.print(hexdata, HEX);
          Serial.print(F("] "));
          hexdata = 0;
        }
      }
      Serial.println(F(""));
    }
    
    
    
    void InitTPMS()
    {
      int i;
    
      for (i = 0; i < 4; i++)
      {
        ClearTPMSData(i);
      }
    
    UpdateBigDisplay();
    
    }
    
    void UpdateTPMSData(int index, unsigned long ID, unsigned int status, float Temperature, float Pressure, int intpressure)
    {
    
      if (index >= 4)
        return;
    
      TPMS[index].TPMS_ID = ID;
      TPMS[index].TPMS_Status = status;
      TPMS[index].lastupdated = millis();
      TPMS[index].TPMS_Temperature = Temperature;
      TPMS[index].TPMS_Pressure = Pressure;
      TPMS[index].TPMS_Intpressure = intpressure;
    }
    
    void DisplayStatusInfo()
    {
      Serial.print (F("FreqOffset: "));
      Serial.print (FreqOffset);
      Serial.print (F("  DemodLinkQuality: "));
      Serial.print (DemodLinkQuality);
      Serial.print (F("  RSSI: "));
      Serial.println (RSSIvalue);
    }
    
    boolean Check_TPMS_Timeouts()
    {
       byte i;
       boolean ret = false;
        
        //clear any data not updated in the last 5 minutes
      for (i = 0; i < 4; i++)
      {
        //    #ifdef SHOWDEGUGINFO
    //      Serial.print(TPMS[i].TPMS_ID, HEX);
    //      Serial.print(F("   "));
    //    #endif
    
        if ((TPMS[i].TPMS_ID != 0) && (millis() - TPMS[i].lastupdated > TPMS_TIMEOUT))
        {
    //      #ifdef SHOWDEGUGINFO
    //         Serial.print(F("Clearing ID "));
    //         Serial.println(TPMS[i].TPMS_ID, HEX);
    //      #endif
          ClearTPMSData(i);
          ret = true;
        }
    
      }
      return(ret);
    }
    
    void DecodeTPMS()
    {
      int i;
      unsigned long id = 0;
      unsigned int status, pressure1, pressure2, temp;
      float realpressure;
      float realtemp;
      bool IDFound = false;
      int prefindex;
    
      for (i = 0; i < 4; i++)
      {
        id = id << 8;
        id = id + RXBytes[i];
    
      }
    
      // id = (unsigned)RXBytes[0] << 24 | RXBytes[1] << 16 | RXBytes[2] << 8 | RXBytes[3];
    
      status = (RXBytes[4] & 0x80) | (RXBytes[6] & 0x7f); // status bit and 0 filler
    
      pressure1 = (RXBytes[4] & 0x7f) << 1 | RXBytes[5] >> 7;
    
      temp = (RXBytes[5] & 0x7f) << 1 | RXBytes[6] >> 7;
    
      pressure2 = RXBytes[7] ^ 0xff;
    
    
    
      if (pressure1 != pressure2)
      {
        Serial.println(F("Pressure check mis-match"));
        return;
      }
    
      realpressure = 1100 * (pressure1 * 0.25 - 7.0);
      realtemp = temp - 40.0;
        intpressure = (int) realpressure;
    
    #ifdef SHOWDEGUGINFO
      Serial.print(F("ID: "));
      Serial.print(id, HEX);
      Serial.print(F("   Status: "));
      Serial.print(status);
      Serial.print(F("   Temperature: "));
      Serial.print(realtemp);
      Serial.print(F("   Tyre Pressure: "));
      Serial.print(realpressure);
      Serial.print(F("   Adjusted Pressure: "));
      Serial.print(intpressure);
      if (realtemp < 23 && 1 < realtemp) {
        warning = 1;
      }
     
      Serial.println(F(""));
    
    
      
    
    
    #endif
    
      //DisplayStatusInfo();
    
      //update the array of tyres data
      for (i = 0; i < 4; i++)
      { //find a matching ID if it already exists
        if (id == TPMS[i].TPMS_ID)
        {
          UpdateTPMSData(i, id, status, realtemp, realpressure, intpressure);
          IDFound = true;
          break;
        }
    
      }
    
      //no matching IDs in the array, so see if there is an empty slot to add it into, otherwise, ignore it.
      if (IDFound == false)
      {
    
        prefindex = GetPreferredIndex(id);
        if (prefindex == -1)
        { //not found a specified index, so use the next available one..
          for (i = 0; i < 4; i++)
          {
            if (TPMS[i].TPMS_ID == 0)
            {
              UpdateTPMSData(i, id, status, realtemp, realpressure, intpressure);
            }
          }
        }
        else
        { //found a match in the known ID list...
          UpdateTPMSData(prefindex, id, status, realtemp, realpressure, intpressure);
        }
    
      }
    
    
      #ifdef SHOWDEGUGINFO
         Serial.println(F(""));
      #endif
    
    
    }
    
    
    #ifndef USE_PROGMEMCRC
      void CalulateTable_CRC8()
      {
        const byte generator = 0x07;
      
        /* iterate over all byte values 0 - 255 */
        for (int divident = 0; divident < 256; divident++)
        {
          byte currByte = (byte)divident;
          /* calculate the CRC-8 value for current byte */
          for (byte bit = 0; bit < 8; bit++)
          {
            if ((currByte & 0x80) != 0)
            {
              currByte <<= 1;
              currByte ^= generator;
            }
            else
            {
              currByte <<= 1;
            }
          }
          /* store CRC value in lookup table */
          crctable[divident] = currByte;
          Serial.print("0x");
          if (currByte < 16)
             Serial.print("0");
          Serial.print(currByte,HEX);
          Serial.print(", ");
        }
      }
    #endif
    
    byte Compute_CRC8( int bcount)
    {
      byte crc = 0x80;
      int c;
      for (c = 0; c < bcount; c++)
      {
        byte b = RXBytes[c];
        /* XOR-in next input byte */
        byte data = (byte)(b ^ crc);
        /* get current CRC value = remainder */
        #ifdef USE_PROGMEMCRC
            crc = (byte)(pgm_read_byte(&crctable2[data]));
        #else
            crc = (byte)(crctable[data]);
        #endif
    
      }
    
      return crc;
    }
    
    
    void ClearRXBuffer()
    {
      int i;
    
      for (i = 0; i < sizeof(RXBytes); i++)
      {
        RXBytes[i] = 0;
      }
    }
    
    void EdgeInterrupt()
    {
      unsigned long ts = micros();
      unsigned long BitWidth;
    
      if (TimingsIndex == 255)
      {
        return;
      }
    
    
      BitWidth = ts - LastEdgeTime_us;
      if (BitWidth <= 12)  //ignore glitches
      {
        return;
      }
      if (BitWidth > 255)
        BitWidth = 255;
    
      LastEdgeTime_us = ts;
      //    if ((BitWidth >= 38) && (BitWidth <= 250))
      //    {//ignore out of spec pulses
      Timings[TimingsIndex++] = (byte)BitWidth;
      //    }
    
      //    digitalWrite(DEBUGPIN,HIGH);
      //    delayMicroseconds(3);
      //    digitalWrite(DEBUGPIN,LOW);
    
    
    
    
    }
    
    bool IsValidSync(byte Width)
    {
      if (Width >=  175)
      {
        return (true);
      }
      else
      {
        return (false);
      }
    }
    
    bool IsValidShort(byte Width)
    {
      if ((Width >= 40) && (Width <= 60))
      {
        return (true);
      }
      else
      {
        return (false);
      }
    }
    
    
    bool IsValidLong(byte Width)
    {
      if ((Width >= 80) && (Width <= 120))
      {
        return (true);
      }
      else
      {
        return (false);
      }
    }
    
    int ValidateBit()
    {
      byte BitWidth = Timings[CheckIndex];
      byte BitWidthNext = Timings[CheckIndex + 1];
    
      if (IsValidLong(BitWidth))
      {
        return (1);
      }
    
      if (IsValidShort(BitWidth))
      {
        return (0);
      }
    
      if (IsValidSync(BitWidth))
      {
        return (2);
      }
    
    
      return (-1);
    
    }
    
    
    void ValidateTimings()
    {
    
    
      byte BitWidth;
      byte BitWidthNext;
      byte BitWidthNextPlus1;
      byte BitWidthPrevious;
      byte diff = TimingsIndex - CheckIndex;
      //unsigned long tmp;
      bool WaitingTrailingZeroEdge = false;
      int ret;
    
      StartDataIndex = 0;
    
      if (diff < 72)
      { //not enough in the buffer to consider a valid message
        Serial.println(F("Insufficient data in buffer"));
        return;
      }
    
      SyncFound = true;
    
      while ((diff > 0) && (BitCount < 72))
      { //something in buffer to process...
        diff = TimingsIndex - CheckIndex;
    
        BitWidth = Timings[CheckIndex];
    
        if (SyncFound == false)
        {
          if (IsValidSync(BitWidth))
          {
            SyncFound = true;
            BitIndex = 0;
            BitCount = 0;
            WaitingTrailingZeroEdge = false;
            StartDataIndex = CheckIndex + 1;
          }
    
        }
        else
        {
          ret = ValidateBit();
          switch (ret)
          {
            case -1:
              //invalid bit
              BitIndex = 0;
              BitCount = 0;
              WaitingTrailingZeroEdge = false;
              StartDataIndex = CheckIndex + 1;
              break;
    
            case 0:
              if (WaitingTrailingZeroEdge)
              {
                //BitTimings[BitIndex] = BitWidth;
                IncomingBits[BitIndex++] = 0;
                BitCount++;
                WaitingTrailingZeroEdge = false;
              }
              else
              {
                WaitingTrailingZeroEdge = true;
              }
              break;
    
            case 1:
              if (WaitingTrailingZeroEdge)
              { //shouldn't get a long pulse when waiting for the second short pulse (i.e. expecting bit = 0)
                //try to resync from here?
                BitIndex = 0;
                BitCount = 0;
                WaitingTrailingZeroEdge = false;
                CheckIndex--;  //recheck this entry
                StartDataIndex = CheckIndex + 1;
              }
              else
              {
                //BitTimings[BitIndex] = BitWidth;
                IncomingBits[BitIndex++] = 1;
                BitCount++;
              }
              break;
    
            case 2:
              SyncFound = true;
              BitIndex = 0;
              BitCount = 0;
              WaitingTrailingZeroEdge = false;
              StartDataIndex = CheckIndex + 1;
              break;
          }
        }
        CheckIndex++;
      }
    
    
    }
    
    
    
    void InitDataBuffer()
    {
      BitIndex = 0;
      BitCount = 0;
      ValidBlock = false;
      //WaitingTrailingZeroEdge = false;
      WaitingFirstEdge  = true;
      CheckIndex = 0;
      TimingsIndex = 0;
      SyncFound = false;
      //digitalWrite(DEBUGPIN, LOW);
    
    }
    
    void UpdateStatusInfo()
    {
      FreqOffset = readStatusReg(CC1101_FREQEST);
      DemodLinkQuality = readStatusReg(CC1101_LQI);
      RSSIvalue = readStatusReg(CC1101_RSSI);
    }
    
    int ReceiveMessage()
    {
    
      //Check bytes in FIFO
      int FIFOcount;
      int resp;
    
      //set up timing of edges using interrupts...
      LastEdgeTime_us = micros();
      CD_Width = micros();
    
      attachInterrupt(digitalPinToInterrupt(RXPin), EdgeInterrupt, CHANGE);
      while (GetCarrierStatus() == true)
      {
      }
      detachInterrupt(digitalPinToInterrupt(RXPin));
    
      //digitalWrite(DEBUGPIN,LOW);
    
      CD_Width = micros() - CD_Width;
      if ((CD_Width >= 7600) && (CD_Width <= 8200))
      {
        //Serial.println(F("Checking"));
        digitalWrite(LED_RX,LED_ON);
        CheckIndex = 0;
        ValidateTimings();
        //Serial.println(F("Checking complete"));
        digitalWrite(LED_RX,LED_OFF);
        return (BitCount);
      }
      else
      {
        return (0);
      }
    
    
    
    }

  2. #27
    Senior Member
    Join Date
    Jul 2020
    Posts
    174
    How come the code is in both French and Spanish?

    I don't see why both devices can't play nice on the same bus, as wired. I think that should be fine. You might want to check the documentation for both devices to see if they want you to put a pullup/pulldown resistor or a capacitor somewhere. (That is just off the top of my head.)

    Do they both support the same SPI bus speed, and is the controller running the bus at that speed?

    What are the actual symptoms you're seeing? Is either of the devices cutting out after "a few tens of seconds" or is it more like you're not sure how to adapt the code for both to work together?

    If the latter, a good solution would be to put the low-level code for the transceiver and LCD into separate .cpp files that do not know about each other, or the higher-level application itself, and then in the .ino file you do higher-level "bridging" between them.

    In other words, the .cpp file that reads the transceiver is indifferent to what the data is, or how it will be presented. You could plug that into a completely different app (weather station, plant moisture level reader, etc) and it would work just as well, without modification, because it has no idea what the application is. This is in line with the Single Responsibility and Open/Closed principles, which make software easier to write and maintain by making sure you don't mix code at higher levels of abstraction (more about logic) with code at lower levels of abstraction (more about concrete stuff, such as how to talk to a specific device.) These are two of the five letters of SOLID Principles, which you should study as much as you can.

    Similarly, your low-level LCD code knows nothing of your application. It doesn't know about MAP sensors, just that it's being asked to transmit a bitmap or a rotation command or whatever. It could be used for a VU meter by adding some kind of bar-drawing logic, but that would be it; none of the other logic in that class would have to be touched.

    One potential structure for your code could look like this:
    • CC1101.cpp - Lets other code talk to the transceiver, but knows nothing about the data format or what it contains.
    • Potentiometer.cpp - Behaves exactly like CC1101 as far as other modules are concerned. Internally, reads pots instead of the transceiver. CC1101 and Potentiometer use the same interface (that is, function signatures and outwardly-visible behavior) so that they can be swapped without any difficulty, and without having to change any external code (except for what specifically instantiates one or the other.) Interfaces are a pretty good design pattern for software development, and I encourage you to read up on them. I haven't told you here how to make one work in C++, but it's not hard to figure out.
    • Newhaven.cpp - Lets other code upload bitmaps, send rotation commands, and whatever else you need for the display, but has no knowledge of what the images are for.
    • View.cpp - Uses Newhaven to upload the background and needle images to the display, and to translate rotation commands. It can talk to CC1101, or it can talk to Potentiometer, because they both have the same interface and behavior. In other words, it really doesn't care where the data comes from, just that it's sensible.
    • Application.ino (whatever you want to call it) - Plugs View into CC1101 or Potentiometer, and Newhaven. Has a loop that polls the input (CC1101 or Potentiometer) and then forwards the data to Newhaven.


    Speaking of delays, you may have to insert some delayMicroseconds() somewhere to make sure the devices have enough time to recognize that the state of the CS lines has changed. Documentation for your devices (CC1101 and Newhaven) should be able to tell you if this is necessary. Obviously, the details of this would be in CC1101.cpp and Newhaven.cpp, since that's a low-level detail and not the responsibility of higher-level code.

  3. #28
    Thanks, that gives me some ideas to work with.

    Language-wise, like so much of the inconsistency or bad design here, it's because I've cut and pasted, and changed as little as I could get away with in order not to break stuff ;-)

    I should have mentioned that I did put 10k pull-up resistors on both CS pins, because this page said it was a good idea: https://www.pjrc.com/better-spi-bus-design-in-3-steps/

    Speed-wise, I'll have to look into that… I was under the impression that the bus is running at 115200 baud, and both devices are OK with that, but I really don't know

    The symptoms of the devices not working are:
    •*For the CC1101, it seems to report that it's there and responding correctly when the setup runs (as in, version number comes up as 14, rather than 0 which it will do when it's not properly connected), but when a TPMS sensor sends data it doesn't show up on the serial monitor (sensor ID, pressure and temperature, which show up in the serial monitor when this IS working properly. I have a sort of TPMS 'magic wand' tool that prompts the sensors to send data when they're sitting on my desk rather than installed in a rolling wheel)
    •*For the display, I get various behaviours, from freezing after maybe 30 seconds, to a blank display - but I haven't made good notes on what variables may have played into how the display behaves

    Timing-wise, I believe from the documentation of the TPMS project I copied (with permission) that the handling of data from the CC1101 is quite time-sensitive, and amongst other things is looking for quite small timing gaps in order to decide what to do with incoming low-level data. So I want to be quite careful about anything that will mess with that - but, on the outer hand, communication with the CC1101 is almost all slave-to-microprocessor, and communication with the display is almost all microprocessor-to-slave (leaving touchscreen control out of things for now), which might simplify things

  4. #29
    ps. and, yes, it's VERY likely that problems are happening because I'm not sure how to adapt the code for both to work together!

  5. #30
    Senior Member
    Join Date
    Jul 2020
    Posts
    174
    115200 is a typical UART speed that you will see in old-fashioned serial devices, primarily modems and ISDN terminal adapters. SPI doesn't adhere to that exact speed. I think it will run as fast as 10 megabits/sec.

    Does this work right when the sensors are in fixtures on your desk, but not when they're mounted in a vehicle?

    Regarding the CC1101, I have never used it and so have no experience with it, but make sure to follow the application notes closely (see datasheet.) If you are not getting it to reliably relay information that you know is correct to the Teensy, that is the first thing to investigate. Check application notes for the CC1101 and whatever you're hooking it up to. The device's data sheet suggests that it needs to receive a message that populates the correct values into its registers, and that it can typically be paired with a microcontroller "and a few additional passive components." It appears that numerous capacitors and inductors are expected between the IC and the antenna. They have very specific preferences: the top layer of the PCB is for digital signal routing, the back of the IC should be connected to the ground plane with several vias. They don't want you using sharp angles on traces in certain areas, etc., etc., etc. There are very good reasons why they tell you to do these things.

    You are getting it to report its version number, and that means you're talking to it at least sometimes, but that doesn't mean it's configured as well as it could be. As for configuring the thing, they strongly advise using the SmartRF Studio. During SPI transfers, you have to check the CC1101's SO (which is actually MISO) pin to see whether it's ready to receive. When it's pulled low, it means the IC's internal clock is ready, and you can transfer information over SPI. If you are not checking the SO pin, whether the CC1101 receives what you send is probably a matter of luck; and if there's one thing years of programming have taught me, it's that you never want to be accidentally right. The docs state that unless the chip is asleep or XOFF mode, SO will "immediately" go low, but what does that mean? 1 nanosecond? 100? Better you should wire it up to a digital input configured to pull itself high (I think... someone correct me if I'm wrong.) The crystal startup/ready time is listed as 150 microseconds, which is ~1,000 times longer than it takes for the MCU to execute a few instructions, so don't underestimate that! After setting CS low, wait for CC1101's MISO line to go low before transmitting.

    By the way, do this in isolation. Do NOT try to fix the display at the same time. Get one small module working completely and reliably. Hammer on it for as many hours or days as you have to so that you can trust it. Only after you trust it should you move on to fixing the next thing. Otherwise, your attention will split in two directions and you will exhaust your cognitive resources until all that's left is a bunch of cussing and an inclination to throw everything in the trashcan.

    I recently wrote a module that implements a very crude filesystem in flash. (It's so crude that all it stores is an identifying header, a file size, and the file itself; and there can be only one file which has no name.) I spent an entire day on writing just this, and I refrained from touching any other code. I didn't use the code that consumed it to test it, instead writing some separate code that only tests it. Because of this, I caught several bugs that I would've missed if I tried to hack it together only testing it from other code, and it's very predictable. This is the secret to writing incredibly complex software without going absolutely crazy and burning out: you work on one small thing at a time, in isolation, until you are REALLY SURE that it works. This project is tiny compared to some of the stuff I've written, but I would still focus on only the one thing, because I know that trying to screw around with multiple things at one will result in smoke coming from my ears.

  6. #31
    I'm sure the CC1101 stuff in isolation is OK - I think you're quite right about all that detail, but I had it working solidly with a different display (which didn't use the SPI bus), and also working with this wiring without trying to get the new display also working on the SPI bus.

    I copied this excellent and well-documented project, which had already done the hard work on configuring the CC1101… I started by reproducing it precisely, same components and code, and then evolved it to work with a Teensy 4 rather than Arduino Pro Micro, and with a second colour display:

    https://www.hackster.io/jsmsolns/ard...display-b6e544

    (I did, btw, start going down the SmartRF route, which was kinda frustrating, I won't go into details, but in the end I decided that it would be smarter and quicker to get a working system by perfectly copying that project, and work from there, as all the CC1101 heavy lifting was already done)

    When I say I had it working solidly, I mean that every time I sent TPMS data, it would appear on screen - incidentally, one early problem with this project was knowing when TPMS data was being sent (to eliminate one off the variables in the "why aren't I seeing data" equation). As it wasn't going to be practical to work in a moving vehicle, I acquired a garage tool that sends a signal to a nearby sensor to prompt it to send its data, which has been absolutely invaluable! (I'm doing all this on my desk, and the idea is to put it in the car when it's working - though I now have a bit of a deadline as I've booked it in for new tyres this weekend and was planning to put the new sensors in then)

    So I'm sure that my problem is in the higher-level integration of the CC1101 and display stuff

  7. #32
    Just to clarify on sensors: to prolong their battery life, they normally only send data in short bursts every 60-90 seconds, when they're in a rotating tyre. Also when they detect a sudden drop in pressure. No movement (and possibly no pressure above atmospheric, not sure about this), and they go to sleep - hence using the garage tool to prompt them to send data.

    They also randomise the gap between their data bursts, so that your car's TPMS doesn't repeatedly get data from all four tyres arriving at once and interfering - it's quite interesting stuff!

  8. #33
    Well, well!. We have again some issues with the SPI lines of the teensy 4.

    First I think we should know how to start SPI2 on the teensy 4. However, on this board, SPI2 is addressed to the SDIO lines and we already started with conflicts, because the SDIO reader is being used for multimedia in the FT813.

  9. #34
    Are there 3 SPI buses? Maybe SPI, SPI1 and SPI2?

    If I can't get this to work, I might try using an Arduino Pro Micro to handle the CC1101, and then have it send data to the Teensy via the RX/TX pins

  10. #35
    I'm also wondering whether maybe it's worth trying a Teensy 4.1 instead - if I understand correctly, the Micro SD card slot would simplify things, and I think there are hardware pins for two entirely separate SPI interfaces

  11. #36
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    7,629
    Yes there are 3 SPI busses on T4 and T4.1.

    On T4, the SPI2 buss is on the bottom SDIO pins.
    Click image for larger version. 

Name:	T4-Cardlike.jpg 
Views:	7 
Size:	178.8 KB 
ID:	21667

    On T4.1, again they are on the SDIO pins as well. In this case those pins are directly connected to the SDIO adapter on the T4.1. In addition these pins are also on the memory chip pads on the bottom of this board.

    Click image for larger version. 

Name:	T4.1-Cardlike.jpg 
Views:	11 
Size:	225.3 KB 
ID:	21668

    I believe I left the default pins for SPI2 to be the SDIO pins. So to use the other pins, you would need to do something like:
    SPI2.setMOSI(50); ...

    And you use these SPI busses the same as others. SPI2.begin()...

  12. #37
    Ah, thanks.

    For now I'm still trying to make things work with the 4.0 board, though I've ordered a 4.1 to play about with also.

    I have followed Pilot's suggestion of trying to keep elements separate, but so far no luck. Amongst other things I've been looking at the code that I think sets up the screen and the CC1101. For starters I've simply tried setting the speed of both SPI instances to the same value, as they appeared to be different to start with. Originally:

    In CC1101.h, included in the previous versions of this project with the TPMS stuff working, there's this:

    Code:
    // Select (SPI) CC1101
    void cc1101_Select(){
    
      //delayMicroseconds(150);
      //spi.begin();
      SPI.beginTransaction(SPISettings(5000000,MSBFIRST,SPI_MODE0));
      digitalWrite(CC1101_CS, LOW);
    }
    (It's the only code I can see that appears to set a speed)

    And the GD23ZUTX library has this:


    Code:
     #if defined(__IMXRT1052__) || defined(__IMXRT1062__)
      #define SetSPISpeed  47000000  //F_BUS/3       47000000 (47 MHz) Teensy 4
     #endif
    #endif
    I was hoping to find code for the screen and for the CC1101 that were more similar, as these chunks seem to be doing quite different things, but they do seem to be addressing the same property: speed

    I've tried setting both frequencies to 5000000 (5MHz), but that hasn't made any difference.

    Anyone have an idea whether I might be on the right track here? At least for part off the solution, I can imagine there could be other issues I haven't identified yet

  13. #38
    Senior Member
    Join Date
    Jul 2020
    Posts
    174
    That code looks like it assumes something about F_BUS, which might be right, but if you change the clock speed it probably breaks this. It looks like a code smell to me.

    These libraries may have hard-coded assumptions such as not having to play nice with other devices, always getting to initialize the bus (which might be troublesome if they both try to do it), possibly that they always have to use SPI0, etc. That might make them troublesome to integrate.

    Things to try: see if you can get one library to initialize the bus and after that successfully talk to both; make sure the speed doesn't exceed either device's capabilities; try moving one to another SPI bus (if the driver code even lets you); refactor one of the drivers to allow using an alternate bus if it isn't otherwise possible by extracting all SPI transactions to an adapter class that talks to (or provides a reference to) the correct bus; try using I2C with one of the devices instead of SPI (if either supports it.) I2C will be somewhat slower than SPI; but for this application, neither device needs massive bandwidth at runtime.

    Try moving one device to a separate SPI bus first. If that doesn't avail, the next easiest option is to see if one of them will speak I2C. If they're speaking different protocols on different buses, they won't have anything to fight over.

  14. #39
    I'm pretty sure that both devices are SPI only, but I like the idea of putting them on a different SPI buses if that's possible - I'm not sure how to do that, however. Had a quick before but couldn't work it out… maybe with a bit more digging

  15. #40
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    7,629
    Sorry again I have not studied everything here...

    And for example I don't know if these displays (like some of the RA8875) have issues with not playing nice with the MISO pin... That is the device assumes it is going to drive this line, which does not work well for others... Again I have not looked...

    As mentioned the cc1101_Select code does set the SPI speed each time it is called.


    Have not looked at the display library... as for the comment about F_BUS, not sure that really matters as that is simply on a comment on what speed to try to go at. The SPI library will map that speed to a value that should not exceed that speed. For T4.x... What internal clock and settings can be set by updating the CCM_CBCMR register. The SPI.begin code sets this to some specific setting, but the begin transaction code can handle this being changed after this point.
    That is:
    Code:
    	CCM_CBCMR = (CCM_CBCMR & ~(CCM_CBCMR_LPSPI_PODF_MASK | CCM_CBCMR_LPSPI_CLK_SEL_MASK)) |
    		CCM_CBCMR_LPSPI_PODF(2) | CCM_CBCMR_LPSPI_CLK_SEL(1); // pg 714
    //		CCM_CBCMR_LPSPI_PODF(6) | CCM_CBCMR_LPSPI_CLK_SEL(2); // pg 714
    Which again begin transaction looks at:
    Code:
    			static const uint32_t clk_sel[4] = {664615384,  // PLL3 PFD1
    						     720000000,  // PLL3 PFD0
    						     528000000,  // PLL2
    						     396000000}; // PLL2 PFD2				
    
    		    // First save away the new settings..
    		    _clock = settings.clock();
    
    			uint32_t cbcmr = CCM_CBCMR;
    			uint32_t clkhz = clk_sel[(cbcmr >> 4) & 0x03] / (((cbcmr >> 26 ) & 0x07 ) + 1);  // LPSPI peripheral clock
    As for moving one to SPI1... everything in the library and the like that uses the SPI object needs to change to SPI1...

    Normally when I muck with a library like this. I like to either have the constructor or the init/begin method, take an optional pointer/reference to which SPI object to use and have the class than store a pointer to that object and change everything to use that pointer... That way it is much easier to change and experiment. Many/most of the Adafruit libraries have been updated to do this.

  16. #41
    Senior Member
    Join Date
    Jul 2020
    Posts
    174
    This is the line I was talking about:

    Code:
    #define SetSPISpeed  47000000  //F_BUS/3       47000000 (47 MHz) Teensy 4
    The comment says where it comes from, but it's still a hard-coded literal. If the bus speed doesn't have to be in specific proportion to the processor speed, then it can be anything, but then how would the processor and bus talk to each other? The timing wouldn't line up.

  17. #42
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    7,629
    Quote Originally Posted by Pilot View Post
    This is the line I was talking about:

    Code:
    #define SetSPISpeed  47000000  //F_BUS/3       47000000 (47 MHz) Teensy 4
    The comment says where it comes from, but it's still a hard-coded literal. If the bus speed doesn't have to be in specific proportion to the processor speed, then it can be anything, but then how would the processor and bus talk to each other? The timing wouldn't line up.
    I totally understand... But a couple of simple points here...

    This comment is completely bogus here... That is the comment is more specific to T3.x boards and means nothing... Just a comment.

    Now where it originally came from was if you look at SPI.h for T3.x, you will see that the SPI Settings will take the value you pass in 47MHZ, the Actual SPI speed is some proportion of the F_BUS speed. That is if you look at the SPISettings object...

    It starts off like:
    Code:
    class SPISettings {
    public:
    	SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
    		if (__builtin_constant_p(clock)) {
    			init_AlwaysInline(clock, bitOrder, dataMode);
    		} else {
    			init_MightInline(clock, bitOrder, dataMode);
    		}
    	}
    	SPISettings() {
    		init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0);
    	}
    private:
    	void init_MightInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
    		init_AlwaysInline(clock, bitOrder, dataMode);
    	}
    	void init_AlwaysInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode)
    	  __attribute__((__always_inline__)) {
    		uint32_t t, c = SPI_CTAR_FMSZ(7);
    		if (bitOrder == LSBFIRST) c |= SPI_CTAR_LSBFE;
    		if (__builtin_constant_p(clock)) {
    			if	  (clock >= F_BUS / 2) {
    				t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR
    				  | SPI_CTAR_CSSCK(0);
    			} else if (clock >= F_BUS / 3) {
    				t = SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_DBR
    				  | SPI_CTAR_CSSCK(0);
    			} else if (clock >= F_BUS / 4) {
    				t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0);
    			} else if (clock >= F_BUS / 5) {
    				t = SPI_CTAR_PBR(2) | SPI_CTAR_BR(0) | SPI_CTAR_DBR
    				  | SPI_CTAR_CSSCK(0);
    			} else if (clock >= F_BUS / 6) {
    				t = SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0);
    			} else if (clock >= F_BUS / 8) {
    				t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1);
    			} else if (clock >= F_BUS / 10) {
    				t = SPI_CTAR_PBR(2) | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0);
    			} else if (clock >= F_BUS / 12) {
    				t = SPI_CTAR_PBR(1) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1);
    			} else if (clock >= F_BUS / 16) {
    				t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(3) | SPI_CTAR_CSSCK(2);
    Suppose this is a T3.6 running at 180mhz, which defaults to 60mhz F_BUS and you pass in 47000000 to SPISettings,
    You will find that the fastest SPI clock here is F_BUS/2 or 30mhz... Which is what will be used... Again this converts into the settings values to set the registers that control how fast the SPI buss runs.

    But with T4.x the calculations are different and done at a different time. I changed them from on T3.x does it to convert the speed at run time as the system allows 4 different clocks to be configured to be used to run SPI subsystem.

    If you wish to see how this clock is configured. Look at page 1072 (Figure 13-2 clock tree) There are 4 base clocks you can choose from
    static const uint32_t clk_sel[4] = {664615384, // PLL3 PFD1
    720000000, // PLL3 PFD0
    528000000, // PLL2
    396000000}; // PLL2 PFD2

    And you can choose then choose a divider on this to control then the main clock that is fed into SPI (marked on the right of the page as LPSPI...
    Again in Begin we initialize to: CCM_CBCMR_LPSPI_PODF(2) | CCM_CBCMR_LPSPI_CLK_SEL(1); // pg 714

    uint32_t clkhz = clk_sel[(cbcmr >> 4) & 0x03] / (((cbcmr >> 26 ) & 0x07 ) + 1); // LPSPI peripheral clock

    So Clock 1 720mhz/3 = 240mhz...
    So you pass in 47mhz... I believe it will compute this out to 40mhz.

    Again this then sets the correct registers in the LPSPI registers to get that speed... It is then up to the device to hopefully handle it. Most devices will give you some indication of what the fastest speed they can handle... So you usually use that as the value you pass into the SPISettings object.

  18. #43
    Thanks guys. Just to recap, I have had both the display and the CC1101 working in their own, it's just when I try to get them working together that things stop working. And my coding skills are really quite basic, so I'm struggling a bit to keep up here

    Regarding putting the two devices on different SPI buses, if I want to put the CC1101 on SPI1, would I change part of CC1101.h from this:

    Code:
    // Select (SPI) CC1101
    void cc1101_Select(){
    
      //delayMicroseconds(150);
      //spi.begin();
      SPI.beginTransaction(SPISettings(5000000,MSBFIRST,SPI_MODE0));
      digitalWrite(CC1101_CS, LOW);
    }
    
    void cc1101_Deselect(){
      //spi.end();
    
      //delayMicroseconds(50);
      digitalWrite(CC1101_CS, HIGH);
      SPI.endTransaction();
    to this:



    Code:
    // Select (SPI) CC1101
    void cc1101_Select(){
    
      //delayMicroseconds(150);
      //spi.begin();
      SPI1.beginTransaction(SPISettings(5000000,MSBFIRST,SPI_MODE0));
      digitalWrite(CC1101_CS, LOW);
    }
    
    void cc1101_Deselect(){
      //spi.end();
    
      //delayMicroseconds(50);
      digitalWrite(CC1101_CS, HIGH);
      SPI1.endTransaction();
    I'm guessing there'll be other code to change, but hopefully that's a start! Should have a Teensy 4.1 tomorrow to try it with

  19. #44
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    7,629
    Yes that is the idea..

    You also need to do all of the SPI.transfer functions to: SPI1.transfer

  20. #45
    Made some progress… changing those SPI statements and, crucially, also providing better power to both CC1101 and screen (ie. not via the Teensy), I was able to get both working at the same time! But only briefly - I think the mess of wiring I now have is probably to blame, and I think I've cracked the difficult problems.

  21. #46
    Will post some pics when I have a neater version working!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •