c++carduinospisamd21

Is possible to test SPI communication winhout external module


I have a very simple question, I suppose... I am programming on a SAMD21 board with two SPI communications (one classis SPI and second int SPI), In my opinion the int SPI does not work correctly. If i connect some senzor, it does print nothing to the serial monitor. I am quite sure, that my code is OK, but perhaps there can be some mistake...

So I need to know, if there is some way to test SPI winhout connecting external devices to the board. Please, do not hate that the code is too long, the code for SPI sensor I am using is marked with "//SPI".

PS: Sorry I deleted the SMUART and MICS6814 measuring and calibrating functions, to use only 30 000 characters. Full code is here: https://mega.nz/file/2QxG0ayZ#4UpEU17ogXnm2NK22zAowlDDRrXzksPzzs05zbuq23o

   #include <Adafruit_BME280.h>  // include Adafruit BME280 library
      #include <Adafruit_INA219.h>  // include INA219
      #include <SD.h>          // include Arduino SD library
      #include "Open_Cansat_GPS.h"
      #include <RTCZero.h>

      //include our new sensors
      #include <MICS6814.h>
      #include <MICS-VZ-89TE.h>
      #include "MQ131.h"

      #include <Wire.h>
      #include <SPI.h>

      #include "RFM69.h"       // include RFM69 library

      // Local
      #define PC_BAUDRATE       115200
      #define MS_DELAY    0  // Number of milliseconds between data sending and LED signalization
      #define LED_DELAY     100
      #define Serial SerialUSB
      RTCZero rtc;

      // RFM69
      #define NETWORKID       0        // Must be the same for all nodes (0 to 255)
      #define MYNODEID        1          // My node ID (0 to 255)
      #define TONODEID        2          // Destination node ID (0 to 254, 255 = broadcast)
      #define FREQUENCY       RF69_433MHZ   // Frequency set up
      #define FREQUENCYSPECIFIC 433000000  // Should be value in Hz, now 433 Mhz will be set
      #define CHIP_SELECT_PIN   43 //radio chip select
      #define INTERUP_PIN       9 //radio interrupt

      // BME280 SETTING
      #define BME280_ADDRESS_OPEN_CANSAT 0x77
      #define SEALEVELPRESSURE_HPA    1013.25

      //define our sensor pins
      //MICS6814
      #define PIN_CO  0
      #define PIN_NO2 0
      #define PIN_NH3 0
      #define MICS6814Pin 6
      //OZONE2CLICK
      const byte pinSS = 2; 
      const byte pinRDY = 12;
      const byte pinSCK = 13;
      const byte O2Pin = 10;
      //SMUART
      bool flag1 = false;
      bool flag2 = false;
      byte rxData[30];
      byte one, two;
      #define DcPin 8
      //MICSVZ89TE
      #define MICSVZ89TEPin 7
      int datas [7];
      bool MICS_status;
      int MICS_voc;
      int MICS_eqco2;
      //PHASES
      float CurrentTime;
      const byte day = 17;
      const byte month = 11;
      const byte year = 15;

      MICS6814 gas(PIN_CO, PIN_NO2, PIN_NH3);

      long accelX, accelY, accelZ;
      float gForceX, gForceY, gForceZ;

      long gyroX, gyroY, gyroZ;
      float rotX, rotY, rotZ;

      #define sd_cs_pin 35 // set SD's chip select pin (according to the circuit)

      RFM69 radio(CHIP_SELECT_PIN, INTERUP_PIN, true);


      typedef struct
      {
        int16_t messageId;
        uint16_t year;
        uint8_t month;
        uint8_t day;
        uint8_t hour;
        uint8_t minute;
        uint8_t sec;
        float longitude;
        float latitude;
        uint8_t num_of_satelites;
        float temperature;
        float pressure;
        float altitude;
        float humidity_bme280;
        float voltage_shunt;
        float voltage_bus;
        float current_mA;
        float voltage_load;
        int16_t rssi;
      } messageOut;

      messageOut cansatdata; //create the struct variable

      Adafruit_BME280 bme;


      Adafruit_INA219 ina219(0x40);


      OpenCansatGPS gps;


      File file; // SD library variable

      // LEDS
      #define D13_led_pin 42  // D13 LED
      #define M_led_pin 36  // MLED

      // Local variables
      int idCounter = 1;
      bool isBmeOk = true;
      bool isSdOk = true;
      bool isRadioOk = true;
      bool isGpsConnected = true;

      // My variables
      float NH3Data;
      float COData;
      float NO2Data;
      float PPMO2;
      float PPBO2;
      float MGM3O2;
      float UGM3O2;
      float SSmoke1;
      float SSmoke2;
      float SSmoke3; 
      float ESmoke1;
      float ESmoke2;
      float ESmoke3;
      int DataCounter = 0;

        void RTCBegin ()
      {
        rtc.begin();
      }

      void RTCSleep ()
    {

      digitalWrite(O2Pin, LOW);
      digitalWrite(MICS6814Pin, LOW);
      digitalWrite(MICSVZ89TEPin, LOW);
      digitalWrite(DcPin, LOW);
      digitalWrite(D13_led_pin, LOW);
      digitalWrite(M_led_pin, LOW);
      GyroscopeSleep();

      byte seconds = 0;
      byte minutes = 00;
      byte hours = 00;

      rtc.setTime(hours, minutes, seconds);
      rtc.setDate(day, month, year);

      rtc.setAlarmTime(00, 00, 10);
      rtc.enableAlarm(rtc.MATCH_HHMMSS);

      rtc.standbyMode();
      TerrestrialPhase();
       // Sleep until next alarm match
    }


//SPI


      void OZONE2CLICKCalibrate ()
      {
      Serial.println("2");
        //MQ131.begin(pinSS, pinRDY, O2Pin, LOW_CONCENTRATION, 10000);  //(int _pinCS, int _pinRDY, int _pinPower, MQ131Model _model, int _RL)
        Serial.println("99");
        Serial.println("Calibration in progress...");

        MQ131.calibrate();

        Serial.println("Calibration done!");
        Serial.print("R0 = ");
        Serial.print(MQ131.getR0());
        Serial.println(" Ohms");
        Serial.print("Time to heat = ");
        Serial.print(MQ131.getTimeToRead());
        Serial.println(" s");
        }

      void OZONE2CLICKMeasure ()
      {
        Serial.println("Sampling...");
        MQ131.sample();
        Serial.print("Concentration O3 : ");
        PPMO2 = MQ131.getO3(PPM);
        Serial.print(PPMO2);
        Serial.println(" ppm");
        Serial.print("Concentration O3 : ");
        PPBO2 = MQ131.getO3(PPB);
        Serial.print(PPBO2);
        Serial.println(" ppb");
        Serial.print("Concentration O3 : ");
        MGM3O2 = MQ131.getO3(MG_M3);
        Serial.print(MGM3O2);
        Serial.println(" mg/m3");
        Serial.print("Concentration O3 : ");
        UGM3O2 = MQ131.getO3(UG_M3);
        Serial.print(UGM3O2);
        Serial.println(" ug/m3");
      }

//SPI

      void MICSVZ89TEMeasure()
      {
        delay(5000);
          MICS_VZ_89TE myMICS;
          MICS_status = myMICS.begin();
          myMICS.readSensor();
          MICS_eqco2 = myMICS.getCO2();
          MICS_voc = myMICS.getVOC();
          Serial.print("MICS VOC PPB: ");
          Serial.println(MICS_voc);
          Serial.print("MICS CO2 PPM: ");
          Serial.println(MICS_eqco2);
          delay(1000);
      }

      void GyroscopeTurnOn() 
    {
      Wire.begin();
      setupMPU();
      }

    void GyroscopeMeasure() {
      recordAccelRegisters();
      recordGyroRegisters();
      printData();
    }

    void setupMPU(){
      Wire.beginTransmission(0b1101000); //This is the I2C address of the MPU (b1101000/b1101001 for AC0 low/high datasheet sec. 9.2)
      Wire.write(0x6B); //Accessing the register 6B - Power Management (Sec. 4.28)
      Wire.write(0b00000000); //Setting SLEEP register to 0. (Required; see Note on p. 9)
      Wire.endTransmission();  
      Wire.beginTransmission(0b1101000); //I2C address of the MPU
      Wire.write(0x1B); //Accessing the register 1B - Gyroscope Configuration (Sec. 4.4) 
      Wire.write(0x00000000); //Setting the gyro to full scale +/- 250deg./s 
      Wire.endTransmission(); 
      Wire.beginTransmission(0b1101000); //I2C address of the MPU
      Wire.write(0x1C); //Accessing the register 1C - Acccelerometer Configuration (Sec. 4.5) 
      Wire.write(0b00000000); //Setting the accel to +/- 2g
      Wire.endTransmission(); 
    }

    void GyroscopeSleep(){
      Wire.beginTransmission(0b1101000); //This is the I2C address of the MPU (b1101000/b1101001 for AC0 low/high datasheet sec. 9.2)
      Wire.write(0x6B); //Accessing the register 6B - Power Management (Sec. 4.28)
      Wire.write(0b01000000); //Setting SLEEP register to 0. (Required; see Note on p. 9)
      Wire.endTransmission();
    }

    void recordAccelRegisters() {
      Wire.beginTransmission(0b1101000); //I2C address of the MPU
      Wire.write(0x3B); //Starting register for Accel Readings
      Wire.endTransmission();
      Wire.requestFrom(0b1101000,6); //Request Accel Registers (3B - 40)
      while(Wire.available() < 6);
      accelX = Wire.read()<<8|Wire.read(); //Store first two bytes into accelX
      accelY = Wire.read()<<8|Wire.read(); //Store middle two bytes into accelY
      accelZ = Wire.read()<<8|Wire.read(); //Store last two bytes into accelZ
      processAccelData();
    }

    void processAccelData(){
      gForceX = accelX / 16384.0;
      gForceY = accelY / 16384.0; 
      gForceZ = accelZ / 16384.0;
    }

    void recordGyroRegisters() {
      Wire.beginTransmission(0b1101000); //I2C address of the MPU
      Wire.write(0x43); //Starting register for Gyro Readings
      Wire.endTransmission();
      Wire.requestFrom(0b1101000,6); //Request Gyro Registers (43 - 48)
      while(Wire.available() < 6);
      gyroX = Wire.read()<<8|Wire.read(); //Store first two bytes into accelX
      gyroY = Wire.read()<<8|Wire.read(); //Store middle two bytes into accelY
      gyroZ = Wire.read()<<8|Wire.read(); //Store last two bytes into accelZ
      processGyroData();
    }

    void processGyroData() {
      rotX = gyroX / 131.0;
      rotY = gyroY / 131.0; 
      rotZ = gyroZ / 131.0;
    }

    void printData() {
      Serial.print("Gyro (deg)");
      Serial.print(" X=");
      Serial.print(rotX);
      Serial.print(" Y=");
      Serial.print(rotY);
      Serial.print(" Z=");
      Serial.print(rotZ);
      Serial.print(" Accel (g)");
      Serial.print(" X=");
      Serial.print(gForceX);
      Serial.print(" Y=");
      Serial.print(gForceY);
      Serial.print(" Z=");
      Serial.println(gForceZ);
    }

    void TerrestrialPhase()
      {    
        Serial.println("------------------------------");
        Serial.println("TERRESTRIAL PHASE IN PROGRESS");
        Serial.println("------------------------------");
        Serial.println(" ");    
        digitalWrite(DcPin, HIGH);
        digitalWrite(MICS6814Pin, HIGH);
        digitalWrite(MICSVZ89TEPin, HIGH);
        digitalWrite(O2Pin, HIGH);
        delay(2000);
        MICSVZ89TEMeasure();
        MICSVZ89TEMeasure();
        MICSVZ89TEMeasure();
        MICSVZ89TEMeasure();
        MICS6814Calibrate();
        MICS6814Measure();
        SMUARTTurnOn();
        delay(10000);
        SMUARTMeasure();
        delay(10000);
        SMUARTMeasure();
        delay(1000);
        SMUARTMeasure();
        delay(1000);
        SMUARTMeasure();
        delay(1000);
        OZONE2CLICKCalibrate();
        OZONE2CLICKMeasure();
        SDSave();
        delay(10000);
        RTCBegin();
        RTCSleep();
      }

      void LandingChecker()
      {
        CurrentTime = millis();
        Serial.println(CurrentTime);
        if (CurrentTime >= 30000)
        {
          Serial.println("------------------------------");
          Serial.println("AIR PHASE DONE");
          Serial.println("------------------------------");
          Serial.println(" ");
          Serial.println("------------------------------");
          Serial.println("STARTING TESTING PHASE");
          Serial.println("------------------------------");
          Serial.println(" ");
          TestingPhase1();
        }
            else 
        {
          Serial.println("------------------------------");
          Serial.println("AIR PHASE IN PROGRESS");
          Serial.println("------------------------------");
          Serial.println(" ");
        }
      }

      void WaitingPhase()
      {  
      digitalWrite(O2Pin, LOW);
      digitalWrite(MICS6814Pin, LOW);
      digitalWrite(MICSVZ89TEPin, LOW);
      digitalWrite(DcPin, LOW);
      digitalWrite(D13_led_pin, LOW);
      digitalWrite(M_led_pin, LOW);
      GyroscopeSleep();

      byte seconds = 0;
      byte minutes = 00;
      byte hours = 00;

      rtc.setTime(hours, minutes, seconds);
      rtc.setDate(day, month, year);

      rtc.setAlarmTime(00, 00, 10);
      rtc.enableAlarm(rtc.MATCH_HHMMSS);

      rtc.standbyMode();
      TerrestrialPhase();
      }

      void TestingPhase2()
      {    
          Serial.println("------------------------------");
          Serial.println("TESTING PHASE DONE");
          Serial.println("------------------------------");
          Serial.println(" ");
          Serial.println("------------------------------");
          Serial.println("STARTING TERRESTRIAL PHASE");
          Serial.println("------------------------------");
          Serial.println(" ");
          TerrestrialPhase();
      }

      void TestingPhase1()
      {

        if (((gForceX >= 3.60) || (gForceX <= 0.40)) && ((gForceY >= 2.9) && (gForceY <= 3.20)))
        {
          Serial.println("------------------------------");
          Serial.println("SATELITE POSITION: VERY GOOD");
          Serial.println("------------------------------");
          Serial.println(" ");
          TestingPhase2();
        }

        else if (((gForceX >= 3.30) || (gForceX <= 0.70)) && ((gForceY >= 2.9) && (gForceY <= 3.30)))
        {
          Serial.println("------------------------------");
          Serial.println("SATELITE POSITION: GOOD");
          Serial.println("------------------------------");
          Serial.println(" ");
          TestingPhase2();
        }

        else if (((gForceX >= 3) || (gForceX <= 1)) && ((gForceY >= 2.9) && (gForceY <= 4)))
        {
          Serial.println("------------------------------");
          Serial.println("SATELITE POSITION: OK");
          Serial.println("------------------------------");
          Serial.println(" ");
          TestingPhase2();
        }

        else
        {
          Serial.println("------------------------------");
          Serial.println("SATELITE POSITION: BAD");
          Serial.println("------------------------------");
          Serial.println(" ");
          Serial.println("------------------------------");
          Serial.println("TESTING PHASE FAILED");
          Serial.println("------------------------------");
          Serial.println(" ");
          WaitingPhase();
        }
        }

      void SDSave()
      {
        while(!Serial);

        if (!SD.begin(sd_cs_pin))
        {
          Serial.println("SD card initialization failed!");
          return;
        }

        Serial.println("SD card initialized");

        file = SD.open("data.txt", FILE_WRITE); // Open test.txt for write

        // Rrite to the file and print info to serial
        // print an error to the serial in case it does not succeed
        if (file) 
        {
          file.println("--------------------------");
          file.println("GyKoVySAT terrestrial data");
          file.println("--------------------------");
            file.println("OZONE");
          file.println(PPMO2);
            file.print(" ppm");
          file.println(PPBO2);
            file.print(" ppb");
          file.println(MGM3O2);
            file.print(" mg/m³");

            file.println("SMOKE PARTICLES STANDART");
          file.println(UGM3O2);
             file.print(" μg/m³");
          file.println(SSmoke1);
            file.print(" μg/m³");
          file.println(SSmoke2);
            file.print(" μg/m³");
          file.println(SSmoke3);

            file.println("SMOKE PARTICLES ENVIROMENTAL");
          file.println(ESmoke1);
            file.print(" μg/m³");
          file.println(ESmoke2);
            file.print(" μg/m³");
          file.println(ESmoke3);
            file.print(" μg/m³");

            file.println("VOC");
          file.println(MICS_voc);
            file.print(" ppm");

            file.println("CO2");
          file.println(MICS_eqco2);
            file.print(" ppm");

            file.println("CO");
          file.println(COData);
            file.print(" ppm");

            file.println("NO2");
          file.println(NO2Data);
            file.print(" ppm");

            file.println("NH3");
          file.println(NH3Data);
            file.print(" ppm");


            file.println("DATA FOR ANALYZATION");
          file.println(PPMO2);
            file.print(";");
          file.print(PPBO2);
            file.print(";");
          file.print(MGM3O2);
            file.print(";");
          file.print(UGM3O2);
            file.print(";");
          file.print(SSmoke1);
            file.print(";");
          file.print(SSmoke2);
            file.print(";");
          file.print(SSmoke3);
            file.print(";");
          file.print(ESmoke1);
            file.print(";");
          file.print(ESmoke2);
            file.print(";");
          file.print(ESmoke3);
            file.print(";");
          file.print(MICS_voc);
            file.print(";");
          file.print(MICS_eqco2);
            file.print(";");
          file.print(COData);
            file.print(";");
          file.print(NO2Data);
            file.print(";");
          file.print(NH3Data);
            file.print(";");
          file.print(DataCounter);
            file.print(";");
          file.close();

          DataCounter =  DataCounter + 1;
        } 
        else 
        {
          Serial.println("Error opening data.txt for writing");
        }
        TerrestrialPhase();
      }

      void setup()
      {


        // wait for the Arduino serial (on your PC) to connect
        // please, open the Arduino serial console (right top corner)
        // note that the port may change after uploading the sketch
        // COMMENT OUT FOR USAGE WITHOUT A PC!
        // while(!Serial);

        Serial.println("openCanSat PRO");

        Serial.print("Node ");
        Serial.print(MYNODEID,DEC);
        Serial.println(" ready");

        // begin communication with the BME280 on the previously specified address
        // print an error to the serial in case the sensor is not found
        if (!bme.begin(BME280_ADDRESS_OPEN_CANSAT))
        {
          isBmeOk = false;
          Serial.println("Could not find a valid BME280 sensor, check wiring!");
          return;
        }

        // begin communication with the INA219
        ina219.begin();

        // check of Gps is connected
        Wire.beginTransmission(0x42); // 42 is addres of GPS
        int error = Wire.endTransmission();

        if (error != 0)
        {
          isGpsConnected = false;
        }

        // begin communication with gps
        gps.begin();

        // Uncomment when you want to see debug prints from GPS library
        // gps.debugPrintOn(57600);

        if(!radio.initialize(FREQUENCY, MYNODEID, NETWORKID))
        {
          isRadioOk = false;
          Serial.println("RFM69HW initialization failed!");
        }
        else
        {
          radio.setFrequency(FREQUENCYSPECIFIC);
          radio.setHighPower(true); // Always use this for RFM69HW
        }

        pinMode(D13_led_pin, OUTPUT);
        pinMode(DcPin, OUTPUT);
        pinMode(MICS6814Pin, OUTPUT);
        pinMode(MICSVZ89TEPin, OUTPUT);
        pinMode(O2Pin, OUTPUT);
        GyroscopeTurnOn();
      }

      void loop()
      {
        cansatdata.messageId = idCounter;
        GyroscopeMeasure();
        LandingChecker();    

        Serial.println("MessageId = " + static_cast<String>(cansatdata.messageId));

        cansatdata.temperature = 0;
        cansatdata.pressure = 0;
        cansatdata.altitude = 0;

        if(isBmeOk)
        {
          cansatdata.temperature += bme.readTemperature();
          cansatdata.pressure += bme.readPressure() / 100.0F;
          cansatdata.altitude += bme.readAltitude(SEALEVELPRESSURE_HPA);
          cansatdata.humidity_bme280 = bme.readHumidity();
        }

        Serial.println("Temperature = " + static_cast<String>(cansatdata.temperature) + " *C");
        Serial.println("Pressure = " + static_cast<String>(cansatdata.pressure) + " Pa");
        Serial.println("Approx altitude = " + static_cast<String>(cansatdata.altitude) + " m");
        Serial.println("Humidity = " + static_cast<String>(cansatdata.humidity_bme280) + " %");

        // read values from INA219 into structure
        cansatdata.voltage_shunt = ina219.getShuntVoltage_mV();
        cansatdata.voltage_bus = ina219.getBusVoltage_V();
        cansatdata.current_mA = ina219.getCurrent_mA();
        cansatdata.voltage_load = cansatdata.voltage_bus + (cansatdata.voltage_shunt / 1000);

        Serial.println("Shunt Voltage: " + static_cast<String>(cansatdata.voltage_shunt) + " mV");
        Serial.println("Bus Voltage: " + static_cast<String>(cansatdata.voltage_bus) + " V");
        Serial.println("Current: " + static_cast<String>(cansatdata.current_mA) + " mA");
        Serial.println("Load Voltage: " + static_cast<String>(cansatdata.voltage_load) + " V");

        // Initialize GPS
        cansatdata.year = 0;
        cansatdata.month = 0  ;
        cansatdata.day = 0;
        cansatdata.hour = 0;
        cansatdata.minute = 0;
        cansatdata.sec = 0;
        cansatdata.latitude = 0;
        cansatdata.longitude = 0;
        cansatdata.num_of_satelites = 0;

        // save start time in millisec
        uint32_t start = millis();

        // END LED BLINK
        digitalWrite(D13_led_pin, LOW);


        pinMode(M_led_pin, INPUT);
        // END LED BLINK

        if(isGpsConnected)
        {
          if (gps.scan(250))
          {
            cansatdata.year = gps.getYear();
            cansatdata.month = gps.getMonth();
            cansatdata.day = gps.getDay();
            cansatdata.hour = gps.getHour();
            cansatdata.minute = gps.getMinute();
            cansatdata.sec = gps.getSecond();
            cansatdata.latitude = gps.getLat();
            cansatdata.longitude = gps.getLon();
            cansatdata.num_of_satelites = gps.getNumberOfSatellites();
            Serial.println(String("Time to find fix: ") + (millis() - start) + String("ms"));
            Serial.println(String("Datetime: ") + String(cansatdata.year) + "/"+ String(cansatdata.month) + "/"+ String(cansatdata.day) + " " + String(cansatdata.hour) + ":"+ String(cansatdata.minute) + ":"+ String(cansatdata.sec));
            Serial.println(String("Lat: ") + String(cansatdata.latitude, 7));
            Serial.println(String("Lon: ") + String(cansatdata.longitude, 7));
            Serial.println(String("Num of sats: ") + String(cansatdata.num_of_satelites));
            Serial.println();
          }
          else
          {
            Serial.println("Gps have no satelit to fix.");
          }
        }

        // RFM69HW
        cansatdata.rssi = 0;

        if(isRadioOk)
        {
          cansatdata.rssi = radio.RSSI;
          Serial.println("Signal = " + static_cast<String>(radio.RSSI));

          radio.send(TONODEID, (const void*)&cansatdata, sizeof(cansatdata));
        }

        Serial.println();

        // START LED hart beat
        pinMode(M_led_pin, OUTPUT);

        digitalWrite(D13_led_pin, HIGH);

        digitalWrite(M_led_pin, HIGH);
        // START LED hart beat

        if(!isGpsConnected)
        {
        delay(200);
        }

        idCounter ++;

      }

Solution

  • most SPI interfaces can be placed in a 'loopback' mode, which makes it easy for the code to check the activity to verify the transmitted/received data

    regarding:

    if (error != 0)
    {
        isGpsConnected = false;
    }
    
    // begin communication with gps
    gps.begin();   
    

    should not be trying to communicate with the GPS if no GPS connected. suggest:

    if (error != 0)
    {
        isGpsConnected = false;
        return;
    }
    
    else
    {
        // begin communication with gps
        gps.begin();
    }