Crashes with some modules connected

Hello,
I come across a crashes problem: I am working with an Arduino Nano with:

  • an I2C LCD (LiquidCrystal_I2C lib.),

  • a 24-bit ADS1220 ADC (SPI + modified Protocentral_ADS1220 lib.),

  • an HW-040 Encoder (Encoder lib. with pin 2 and 3 used with interruptions),

  • a DS3231 RTC clock (I2C + RTClib lib.),

  • a micro SD card module (Chinese) (SPI + SD lib.).
    All items have obviously been tested individually and in groups, however, when all the elements are validated and I turn the encoder knobs, the microcontroller crashes.
    Very strangely, after much much research and a little luck / chance, I found that the encoder worked fine again as long as I inserted a certain number of __asm __ ("nop"); or other instructions in the loop code. But this is not an acceptable solution.
    This problem also happens when I delete the single newPosition = myEnc.read (); line from code.
    Such crashes may be explaned by a stack problem, however I do not find any possible relation betwenn stack and code implantation (shifting a part of the code "solves" the problem!).
    I forgot to say that I use 92% of code memory and 66% of RAM, so more than 500 bytes of RAM are free (tested with freeRam).

    Any idea or help is welcome.

Everything points towards a interrupt/memory/stack problem.

The compiler does extreme optimizations. If you move some code, then the compiler can decide to use a completely different optimization and a bug with memory can suddenly appear. If you, for example, change some code in one part, then a bug in a other part of the sketch might appear.

Other possible problems:

  • Power. The LCD backlight requires some power. Can you measure the 5V pin ?
  • Wrong SD module. You need a module that converts the 5V signals from the Arduino Nano to 3.3V signals for the memory card.
  • Bad wiring. For example a bad GND connection via a breadboard.
  • Too much pullup resistors on the I2C bus or the I2C bus in a flat ribbon cable, or any other of the many problems with the I2C bus.
  • So the hardware interrupt from the encoder causes a crash ? Hmmm, I don't know yet what to think about that :thinking:

To be more helpful, we would like to have photo's, schematic, the sketch, links to the used library (or how you have installed them), links to all the modules, and so on.

Hello,
Thank you very much for your answer.

  • I have tested the 5V with an oscilloscope.
  • The SD module works fine if the RTC module is not activated or if the rotary encoder is not activated or if all modules are activated and I add some "nop" instructions in the loop code.
  • I have 2 montages : one with a breadboard and one with a pcb and both gives the same results.
  • I join the schematic. Sorry I am a new user not allowed to join files. I also would like to join photos and the "big" sketch ! However I do not think that it may be a hardware problem because all is working well if I add some "nop" instructions.
  • I think it is the Return from the interrupt causing problem because the crashes go some times back to setup ... but no idea how this may happens !

Hello,
I does one more test as following:
I put a Serial.print("AVR "); in the Encoder library. Here the concerned part:

  public:
    // update() is not meant to be called from outside Encoder,
    // but it is public to allow static interrupt routines.
    // DO NOT call update() directly from sketches.
    static void update(Encoder_internal_state_t *arg) {
#if defined(__AVR__)
      // The compiler believes this is just 1 line of code, so
      // it will inline this function into each interrupt
      // handler.  That's a tiny bit faster, but grows the code.
      // Especially when used with ENCODER_OPTIMIZE_INTERRUPTS,
      // the inline nature allows the ISR prologue and epilogue
      // to only save/restore necessary registers, for very nice
      // speed increase.

      Serial.print("AVR ");

      asm volatile (
        "ld	r30, X+"		"\n\t"
        "ld	r31, X+"		"\n\t"
        "ld	r24, Z"			"\n\t"	// r24 = pin1 input
        "ld	r30, X+"		"\n\t"
        "ld	r31, X+"		"\n\t"
        "ld	r25, Z"			"\n\t"  // r25 = pin2 input
        "ld	r30, X+"		"\n\t"  // r30 = pin1 mask
        "ld	r31, X+"		"\n\t"	// r31 = pin2 mask
        "ld	r22, X"			"\n\t"	// r22 = state
        "andi	r22, 3"			"\n\t"
        "and	r24, r30"		"\n\t"
        "breq	L%=1"			"\n\t"	// if (pin1)
        "ori	r22, 4"			"\n\t"	//	state |= 4
        "L%=1:"	"and	r25, r31"		"\n\t"
        "breq	L%=2"			"\n\t"	// if (pin2)
        "ori	r22, 8"			"\n\t"	//	state |= 8
        "L%=2:" "ldi	r30, lo8(pm(L%=table))"	"\n\t"
        "ldi	r31, hi8(pm(L%=table))"	"\n\t"
        "add	r30, r22"		"\n\t"
        "adc	r31, __zero_reg__"	"\n\t"
        "asr	r22"			"\n\t"
        "asr	r22"			"\n\t"
        "st	X+, r22"		"\n\t"  // store new state
        "ld	r22, X+"		"\n\t"
        "ld	r23, X+"		"\n\t"
        "ld	r24, X+"		"\n\t"
        "ld	r25, X+"		"\n\t"
        "ijmp"				"\n\t"	// jumps to update_finishup()
        // TODO move this table to another static function,
        // so it doesn't get needlessly duplicated.  Easier
        // said than done, due to linker issues and inlining
        "L%=table:"				"\n\t"
        "rjmp	L%=end"			"\n\t"	// 0
        "rjmp	L%=plus1"		"\n\t"	// 1
        "rjmp	L%=minus1"		"\n\t"	// 2
        "rjmp	L%=plus2"		"\n\t"	// 3
        "rjmp	L%=minus1"		"\n\t"	// 4
        "rjmp	L%=end"			"\n\t"	// 5
        "rjmp	L%=minus2"		"\n\t"	// 6
        "rjmp	L%=plus1"		"\n\t"	// 7
        "rjmp	L%=plus1"		"\n\t"	// 8
        "rjmp	L%=minus2"		"\n\t"	// 9
        "rjmp	L%=end"			"\n\t"	// 10
        "rjmp	L%=minus1"		"\n\t"	// 11
        "rjmp	L%=plus2"		"\n\t"	// 12
        "rjmp	L%=minus1"		"\n\t"	// 13
        "rjmp	L%=plus1"		"\n\t"	// 14
        "rjmp	L%=end"			"\n\t"	// 15
        "L%=minus2:"				"\n\t"
        "subi	r22, 2"			"\n\t"
        "sbci	r23, 0"			"\n\t"
        "sbci	r24, 0"			"\n\t"
        "sbci	r25, 0"			"\n\t"
        "rjmp	L%=store"		"\n\t"
        "L%=minus1:"				"\n\t"
        "subi	r22, 1"			"\n\t"
        "sbci	r23, 0"			"\n\t"
        "sbci	r24, 0"			"\n\t"
        "sbci	r25, 0"			"\n\t"
        "rjmp	L%=store"		"\n\t"
        "L%=plus2:"				"\n\t"
        "subi	r22, 254"		"\n\t"
        "rjmp	L%=z"			"\n\t"
        "L%=plus1:"				"\n\t"
        "subi	r22, 255"		"\n\t"
        "L%=z:"	"sbci	r23, 255"		"\n\t"
        "sbci	r24, 255"		"\n\t"
        "sbci	r25, 255"		"\n\t"
        "L%=store:"				"\n\t"
        "st	-X, r25"		"\n\t"
        "st	-X, r24"		"\n\t"
        "st	-X, r23"		"\n\t"
        "st	-X, r22"		"\n\t"
        "L%=end:"				"\n"
        : : "x" (arg) : "r22", "r23", "r24", "r25", "r30", "r31");

Results:

  • with the "nop" instructions inserted in the loop code, I got AVR messages each time I rotate the knob.
  • with no "nop" instructions inserted in the loop code, I got just one "AVR ".
    Unfortunately, I do not know assembler, however, I fear that ijump or rjump are "computed" jump, so I am not able to put a Serial.print after the assembler part.
    So I fear that the problem is in the compiler or perheaps in the library.
    What may I do to go forward ? ?

@gendner, you replied to a request for full information, with only partial information. We need everything that was asked for. See reply #2.

The forum does have some new limitations but I think they can be overcome. Perhaps there is more information about how to post in the forum guidelines...

If you're convinced that it can't be hardware, then please post all the software. However, your reason for committing to that belief is not that convincing. Much stranger things have happened when hardware and software interact. It's especially important because you appear to have multiple I2C devices.

Hello, I still have a message that new users are not able to add files. My english is very poor and I do not have found a way to overcome this limitation ?


Traitement de : Nano_Multi.zip…
Traitement de : Nano_Multi_LCD_2004.ino…
Hello,
Having successfully added the file of a photo, I thought I could add files now, but apparently neither the zip file of the .ino file and modified libraries nor the .ino file are accepted. If someone could tell me what to do, that would allow me to move forward.
The version of the .ino file I wanted attached works fine. However, it includes, from line 560, the following code:

#if 1
  __asm​​__ ("nop");
  __asm​​__ ("nop");
  __asm​​__ ("nop");
  __asm​​__ ("nop");
  __asm​​__ ("nop");
  __asm​​__ ("nop");
  __asm​​__ ("nop");
  __asm​__ ("nop");
  __asm​​__ ("nop");
  __asm​​__ ("nop");
  __asm​​__ ("nop");
  __asm​​__ ("nop");
  __asm​​__ ("nop");
  __asm​​__ ("nop");
  __asm​​__ ("nop");
  __asm​​__ ("nop");
  __asm​​__ ("nop");
  __asm​​__ ("nop");
  __asm​​__ ("nop");
#endif

If the first line is changed to #if 0, or if the second line is commented out:

#if 1
/ * __asm ​​__ ("nop"); * /
  __asm ​​__ ("nop");
  ...

which should be irrelevant, more than strange for me, a rotation of the rotary encoder crashes the microcontroller (it comes back somewhere in the setup and gets stuck)!
Inserting delay (xx) does not solve the problem!
Since inserting a nop instruction eliminates the crash means to me that it is not a hardware (electronic) problem. How can inserting 2 bytes in the code, i.e. shifting part of the code by 2 bytes, eliminate a crash?
Any idea or suggestion is welcome.

This sound like the problem I had for weeks. I'm using several modules like RTC, SD card, LCDs, FRAM,, IO expanders, I2C sensors and a ADS1115, in the code (I's a huge project). The controller crashed or start behaving strange when closing the logfile on the SD card and opened a new one.

I disabled more and more code in the sketch until the only module left - the ADS1115 but still got the problem. When disabling the code for the ADS1115, it worked.

When looking into the code/library for the ADC1115 I noticed it included the Adafruit_BusIO library. Updating this solved my problems.

So check if you libraries are up to date - ALL of them.

That was answered in detail, in reply #2.

thehardwareman So check if you libraries are up to date - ALL of them.
Hello, thank you very much for this suggestion. I rechecked the libraries one by one without finding any anomalies.
I still am not allowed to add the zip file of my sketch.
Regards

Must it be a zip file?

aarg
Must it be a zip file?

Hello,
I have tried a .zip file, an .ino file and a .jpg file and for the first two types of files I always get a message saying new users are not allowed to attach a file!

Hello,
As I still am not allowed to add files, I will try to add my codes and libraries in the message.
First the program code. This code works fine, BUT if I comment the line 561 "asm("nop");" then the programm crashes if I turn the rotary encoder button!

/*
    Programme pour montage multi-usages à base d'Arduino Nano
      par Jean-Paul Gendner, F5BU, 2021-07

    Ce programme permet simultanément et indépendament l'utilisation de :
    - Serial.print (faisant appel à la bibliothèque Arduino)
    - un afficheur LCD parallèle (en utilisant la bibliothèque LiquidCrystal) ou/et
        un afficheur LCD I2C (en utilisant la bibliothèque LiquidCrystal_I2C)
    - un convertisseur analogique numérique 24 bits ADS1220 (Protocentral_ADS1220_g)
    - un convertisseur numérique analogique 12 bits MCP4821 (MCP4821_g)
    - la bibliothèque SPI (utilisée pour la gestion des convertisseurs et carte SD)
    - du timer2 géré par interruptions
    - un Encodeur rotatif avec bouton poussoir SW dont les transitions
        sont gérées par interruptions (D2 et D3)
    - une horloge temps réel (RTC-DS3231) gérée par I2C (Wire, RTClib)
    - un module pour carte Micro SD (SD)

  | pin label       | Pin Function         |Arduino Connection|
  ADS1220
  |-----------------|:--------------------:|-----------------:|
  | DVDD            | Digital VDD          |  +5V             |
  | DGND            | Digital Gnd          |  GND             |
  | AN0-AN3         | Analog Input         |  Analog Inputs   |
  | AVDD            | Analog VDD           |  +2,5V or 5V     |
  | AGND            | Analog Gnd           |  -2,5V or GND    |
  | DRDY            | Data ready Output pin|  A5              |
  | CS              | Chip select barre    |  A3              |
  ADS1220, MCP4821 et SD (SPI)
  | MISO            | Slave Out            |  D12             |
  | MOSI            | Slave In             |  D11             |
  | SCLK            | Serial Clock         |  D13             |
  MCP4821 (SPI)
  | CS              | Chip select barre    |  D10             |
  | SHDN barre      | Shutdown             |  +5V             |
  | LDAC barre      | Latching DAC         |  GND             |
  SD (SPI)
  | CS              | Chip select barre    |  D9              |
  Encodeur rotatif avec interrupteur
  | SW              | Switch               |  D4              |
  | DT              | data pin for I2C     |  D3              |
  | CLK             | clock pin for I2C    |  D2              |
  Horloge RTC (I2C)
  | SDA             | Switch               |  A4              |
  | SCL             | Switch               |  A5              |
  LCD (I2C)
  | SDA             | Switch               |  A4              |
  | SCL             | Switch               |  A5              |

    Les bibliothèques pour l'ADS1220 et le MCP4882 sont d'origines des bibliothèques du MIT,
    et modifiées par l'auteur.

    The MIT software are licensed under the MIT License(http://opensource.org/licenses/MIT).
   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
   NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   For information on how to use, visit https://github.com/Protocentral/Protocentral_ADS1220

  ADS1220            Offset        (µV)  mesuré le 2021-05-14
  G=  1   PE=2048mV          6        1,46
  G=  2   PE=1024mV          0        0,00
  G=  4   PE= 512mV         12        0,73
  G=  8   PE= 256mV        -11       -0,34
  G= 16   PE= 128mV       -255       -3,89
  G= 32   PE=  64mV       -715       -5,46
  G= 64   PE=  32mV      -1887       -7,20
  G=128   PE=  16mV      -4425       -8,44
*/

#define Duree_AD 0        // durée en ms de l'AD ou 0 pour durée infinie
#define Int_Mes_Temp 0    // Interval mesures Température en ms
#define UGain -1          // Gain A/D : -1=>Auto, 1, 2, 4, 8, 16, 32, 64, 128
#define Rate DR_20SPS     // vitesse A/D sps : 20,45,90,175,330,600,1000
#define MoyBit 3          // 0->1, 1->2, 2->4, 3->8, 4->16, 5->32, 6->64, 7->128, 8->256, 9->512
#define RR5V 5.68         // Rapport résistances pour mesure du 5V (1er CI)
#define RR12V 23.6        // Rapport résistances pour mesure du 12V (Vin)
//#define RR5V 5.7        // Rapport résistances pour mesure du 5V (montage proto)
//#define RR12V 22.6      // Rapport résistances pour mesure du 12V (Vin)

#define Debug 0           // 2 pour Calibration; 1 pour tous les messages Serial.print sur moniteur série
#define LCD 'I'           // P pour parralèlle, I pour I2C, Mettre en commentaire si pas de LCD
#define ADS1220_Temp      // Mettre en commentaire pour ne pas utiliser la température de l'ADS1220
#define EEPROM_use        // Mettre en commentaire pour ne pas utiliser
#define Timer2            // Mettre en commentaire pour ne pas utiliser
#define MCP4821_P         // Mettre en commentaire si non utilisé/présent
#define RTC_Present 1     // 0 si absent; 1 utilisation; -1 initialisation date heure
#define SD_Present        // Mettre en commentaire si module Micro SD non utilisé

// LCD
#if defined LCD
  #if LCD=='P'
    // LCD paralèlle
    #include <LiquidCrystal.h>
    #define LCDcol 16        // Nombre de colonnes LCD
    #define LCDrow 2         // Nombre de lignes LCD
    const int rs = 9, en = 8, d4 = 7, d5 = 6, d6 = 5, d7 = 4;
    LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
  #else
    // LCD I2C
    #include <LiquidCrystal_I2C.h>
    #define LCDcol 20        // Nombre de colonnes LCD
    #define LCDrow 4         // Nombre de lignes LCD
    LiquidCrystal_I2C lcd(0x27, LCDcol, LCDrow);
  #endif
#endif
String str;
#if defined ADS1220_Temp
  String strTemp;
#endif

// EEPROM de l'Arduino
// 0-31 Offset du CAN pour les 8 valeurs de gain
#if defined EEPROM_use
  #include <EEPROM.h>
  #define EadOffset 0 //adresse du tableau des valeurs d'offset fonction du gain
#endif

// CAN de l'Arduino
#define AVref 1.12        // Arduino internal VRef typical =1.1V
int16_t AValue;

// DEL
#define LED A1

// CAN ADS1220 24 bits
#include <SPI.h>
#include "Protocentral_ADS1220_g.h"
#define VREF  2048        // en mVInternal reference of 2.048V
#define FULL_SCALE     (((int32_t)1<<23)-1)    // 8 388 607
#define Val_lsb VREF/FULL_SCALE                 // 0.00024414 pour PGA=1
#define ADS1220_DRDY_PIN  A2
#define ADS1220_CS_PIN    A3
#define nMoy (1<<MoyBit)  // Nombre de mesures pour faire une moyenne
#define NbSatAuto 5       // Nombre de mesures Saturantes Autorisées sur nMoy

// DAC MCP4821 12 bits
#if defined MCP4821_P
  #include <SPI.h>
  #include "MCP4821_g.h"
  #define DAC_GM 0x3000      // Gain et Masque : 0x1000 pour G=2, 0x3000 pour G=1
#endif
#define DAC_PIN_CS 10

// Encodeur avec bouton poussoir
#include <Encoder.h>       // by Paul Stoffregen
// Change these two numbers to the pins connected to your encoder.
//   Best Performance: both pins have interrupt capability
//   Good Performance: only the first pin has interrupt capability
//   Low Performance:  neither pin has interrupt capability
Encoder myEnc(2, 3); //   avoid using pins with LEDs attached
//Encoder myEnc(2, 5); // pour libérer la pin 3 pouvant générer des interruptions
int32_t oldPosition  = -999;
int32_t newPosition;
#define SW 4

// Timer2
#if defined Timer2
  #define T2_Counter int(256-125000/1000-.5)  // preload timer = 256-16MHz/128/1000Hz -> défini la fréquence
  int timer2_counter = T2_Counter;
#endif

// CAN 24 bits ADS1220
Protocentral_ADS1220 pc_ads1220;
int32_t OffsetG[8] = {0, 0, 0, 0, 0, 0, 0, 0};
byte GIndice;
int32_t adc_data;
int32_t sigma;
int32_t sigma0;
int32_t iad;
int32_t bit24;
byte PGA = 1;         // Programmable Gain
float xfloat;
float x2float;
uint16_t NbSat = 0;
boolean AD_F = false;
boolean AD_F_F = false;
boolean Cal_F = false;

// CNA 12 bit MCP4821
#if defined MCP4821_P
  MCP4821 dacChip;
  volatile int16_t DAC16;
#endif

// Carte SD
#define SD_CS_PIN 9
#if defined SD_Present
  #include <SPI.h>
  #include <SD.h>
  File myFile;
  // change this to match your SD shield or module;
  boolean SDOK = false;
  char NomFichier[13] = {'T', 'e', 's', 't', '.', 't', 'x', 't', '\0'};
#endif

// RTC Real Time Clock
#if RTC_Present!=0
  #include <Wire.h>
  #include <RTClib.h>
  RTC_DS3231 rtc;
  char daysOfTheWeek[7][12] = {"Di", "Lu", "Ma", "Me", "Je", "Ve", "Sa"};
  char cDateRTC[] = "YYYY-MM-DD";
  char cHeureRTC[] = "HH:II:SS";
#endif
unsigned long MillisDebut;    // max 49jours
#if defined ADS1220_Temp
  unsigned long MillisTemp;
#endif

//   * * *   Setup   * * * -------------------------------------------------------
void setup()
{
// Port COM
#if Debug!=0
  Serial.begin(115200);
  Serial.println();
#endif

  // LED
  pinMode(LED, OUTPUT);

  // Encodeur et bouton poussoir
  pinMode(SW, INPUT_PULLUP);

#if defined LCD
  #if LCD=='P'
    lcd.begin(LCDcol, LCDrow);
  #else
    lcd.init();
    lcd.clear();
    lcd.backlight();      // Make sure backlight is on
  #endif
  lcd.setCursor(2, 0);
  //  lcd.display();
  lcd.print(F("F5BU"));
#endif

// Micro SD
#if defined SD_CS_PIN
  pinMode(SD_CS_PIN, OUTPUT);
  digitalWrite(SD_CS_PIN, HIGH);
#endif

  // ADC
  pinMode(ADS1220_CS_PIN, OUTPUT);
  digitalWrite(ADS1220_CS_PIN, HIGH);
  analogReference(INTERNAL);// référence de 1,1V +/- 10%
  pc_ads1220.begin(ADS1220_CS_PIN, ADS1220_DRDY_PIN);
  pc_ads1220.set_data_rate(Rate);
  Set_Gain(1);
  pc_ads1220.set_conv_mode_single_shot(); //Set Single shot mode
#if defined EEPROM_use
  EEPROM.get(EadOffset, GIndice);   // récupération du tableau d'offsets dans l'EEPROM
  if (GIndice != 255) {             // uniquement si une calibration a déjà été faite
    for (int i = 0; i <= 7; i++) {
      EEPROM.get(EadOffset + i * 4, OffsetG[i]);
    }
  }
#endif

  // CNA
#if defined MCP4821_P
  dacChip.begin( DAC_PIN_CS, DAC_GM );
  DAC16 = 0;     //0x800;
  //  dacChip.writedata16(DAC16);     // initialisation de la valeur du DAC par valeur binaire
  dacChip.setVoltage(1.2);          // ou valeur en tension
#endif

  // Timer2 initialisation pour une période de 1ms (f = 1000Hz)
#if defined Timer2
  timer2_counter = T2_Counter;   // preload timer = 256-16MHz/128/1000Hz
  TCCR2A = 0;
  TCCR2B = 0;
  TCNT2 = timer2_counter;   // preload timer
  //  TCCR2B |= (1 << CS21) | (1 << CS20);    // 32 prescaler
  TCCR2B |= (1 << CS22) | (1 << CS20);    // 128 prescaler
#endif

  // Gestion RTC
#if RTC_Present!=0
  if (! rtc.begin()) {
    Serial.println(F("Pas de RTC"));
#if LCDrow>=4
    lcd.setCursor(9, 2);
    lcd.print(F("Pas de RTC"));
#endif
  } else {
    // Mettre date heure pour première utilisation
#if RTC_Present==-1
    if (rtc.lostPower()) {
#if Debug>=0
      Serial.println(F("RTC lost power, lets set the time!"));
#endif
      // Comment out below lines once you set the date & time.
      // Following line sets the RTC to the date & time this sketch was compiled
      // rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
      // OR sets the RTC with an explicit date & time
      // for example to set January 27 2017 at 12:56 you would call:
      // rtc.adjust(DateTime(2017, 1, 27, 12, 56, 0));
      while (digitalRead(SW) = HIGH); {}
      rtc.adjust(DateTime(2021, 8, 06, 16, 0, 0));
    }
#endif
    getDateHeure();
#if LCDrow>=4
    lcd.setCursor(0, 2);
    lcd.print(cDateRTC);
    lcd.setCursor(11, 2);
    lcd.print(cHeureRTC);
#endif
  }
#endif

  // Micro SD
#if defined SD_Present
  pinMode(SD_CS_PIN, OUTPUT);
  digitalWrite(SD_CS_PIN, 1);
  if (!SD.begin(SD_CS_PIN)) {
#if Debug>=0
    Serial.println(F("Pas de SD"));
#endif
#if defined LCD
#if LCDrow>=4
    lcd.setCursor(0, 3);
    lcd.print(F("Pas de SD"));
#endif
#endif
    SDOK = false;
  } else {
#if Debug>=0
    Serial.println(F("SD OK"));
#endif
#if defined LCD
#if LCDrow>=4
    lcd.setCursor(0, 3);
    lcd.print(F("SD OK"));
#endif
#endif
    SDOK = true;
  }
#endif

  // Gestion interruptions
  //  attachInterrupt(digitalPinToInterrupt(SW),ISRPoussoir,CHANGE);
  //  SPI.usingInterrupt(0);
  //  SPI.usingInterrupt(1);
  SPI.usingInterrupt(255);              // autorise les IT SPI durant ISR timer ?
  //  SPI.usingInterrupt(digitalPinToInterrupt(2));
  //  SPI.usingInterrupt(digitalPinToInterrupt(3));

  //do {
#if defined ADS1220_Temp
  MesAffTemp();
#endif

  //}while((bit24<576 || bit24>1056) && ((millis()-MillisDebut)<10000));
  //}while((bit24<576 || bit24>1056));

#if Debug>=0
  Serial.print(F("CAN Conf: "));
  PrintADS1220Config();
#endif

  // Affichage tension 5V et éventuellement Vin
#if defined LCD
  lcd.setCursor(0, 1);
  lcd.print(F("5V="));
#endif
  AValue = analogRead(A7);
  AValue = analogRead(A7);
  AValue = analogRead(A7);
  AValue = analogRead(A7);    // plusieurs lectures au début améliorent la précision
  xfloat = AValue * (AVref / 1023.0) * RR5V;
#if defined LCD
  lcd.print(xfloat, 1);
  lcd.print(F("V"));
  //    adc_data=pc_ads1220.Read_SingleShot_SingleEnded_WaitForData(MUX_AIN2_AIN3);
  lcd.setCursor(8, 1);
#endif
  AValue = analogRead(A6);
  AValue = analogRead(A6);
  if (AValue > 208) {
    xfloat = AValue * (AVref / 1023.0) * RR12V;
    #if defined LCD
      lcd.print(F(" <"));
      lcd.print(xfloat, 1);
      lcd.print(F("V"));
    #endif
  }

  delay(4000);

  // Configuration CAN
  pc_ads1220.select_mux_channels(MUX_AIN0_AIN3);  //Configure for differential measurement between AIN0 and AIN3
  //  pc_ads1220.select_mux_channels(MUX_AIN1_AIN3);  //Configure for differential measurement between AIN1 and AIN3
  pc_ads1220.set_data_rate(Rate);
#if UGain==-1
  Set_Gain(1);
#else
  Set_Gain(UGain);
#endif
  pc_ads1220.set_conv_mode_continuous();  //set continous mode
  pc_ads1220.Start_Conv();  //Start continuous conversion mode

  // Activation Interruptions Timer2
#if defined Timer2
  TIMSK2 |= (1 << TOIE2);   // enable timer2 overflow interrupt
#endif

#if defined LCD
#if LCDrow>=4
  lcd.setCursor(0, 2);
#else
  lcd.setCursor(0, 1);
#endif
  lcd.print(pc_ads1220.readRegister_gt(0), HEX);
  lcd.print(F(" "));
  lcd.print(pc_ads1220.readRegister_gt(1), HEX);
  lcd.print(F(" "));
  lcd.print(pc_ads1220.readRegister_gt(2), HEX);
  lcd.print(F(" "));
  lcd.print(pc_ads1220.readRegister_gt(3), HEX);
#endif
  delay(200);

#if Debug>=0
  Serial.print(F("Reg 0-3 : "));
  PrintADS1220Config();
#endif

#if defined LCD
  lcd.clear();
#endif
}

//   *   *   *   Boucle   *   *   *   *   *   *   *   *   *   *   *   *   *

void loop()
{
  if (AD_F == false) {
    digitalWrite(LED, !digitalRead(LED));
  }

#if defined SD_Present
  if (AD_F_F) {
    AD_F_F = false;
    AD_F = true;
    digitalWrite(LED, 1);           // Début AD = LED allumée
    #if RTC_Present!=0
      getDateHeure();
    #endif
    OpenFile();
    #if Debug==1 || RTC_Present!=0
      Serial.print(F("Debut AD :"));
      Serial.print(cDateRTC);
      Serial.print(F(" "));
      Serial.println(cHeureRTC);
    #endif
  }
#endif
  if (Cal_F) {
    if (!AD_F) {        // Interdit une calibration durant une acquisition de données
      Calibration();
    }
    Cal_F = false;
  }
#if UGain==-1
  do {}
  while ((digitalRead(ADS1220_DRDY_PIN)) == HIGH);
  adc_data = pc_ads1220.Read_Data_Samples();  // mesure avec gain=1
  adc_data = adc_data - OffsetG[GIndice];
  PGA_Auto();

  #if Debug==1
    Serial.print(F("G = 1"));
    Serial.print(F("\t"));
    Serial.print(adc_data);
    Serial.print(F("\n"));
  #endif
#endif

  sigma = 0;
  x2float = 0;
  NbSat = 0;
  for (int iad = 1; iad <= nMoy; iad++) {
    #if LCDrow>=4
      newPosition = myEnc.read();
      if (newPosition != oldPosition) {
        lcd.setCursor(2, 3);
        oldPosition = newPosition;
        lcd.print(-newPosition);
        lcd.print(F(" "));
      }
      lcd.setCursor(0, 3);
      if (digitalRead(SW) == LOW) {
        lcd.print(F("P"));
        switch (-newPosition) {
        case 2:
          #if defined SD_Present
            if (SDOK && !AD_F) {
              AD_F_F = true;
            }
          #endif
          break;
        case 4:
          #if defined SD_Present
            if (AD_F) {
              AD_F = false;
            }
          #endif
          break;
        case -2:
          Cal_F = true;
          break;
      }
    } else {
      lcd.print(F("N"));
    }
    #endif
    do {}
    while ((digitalRead(ADS1220_DRDY_PIN)) == HIGH);
    adc_data = pc_ads1220.Read_Data_Samples();  // mesure avec gain=GPA
    if (adc_data >= FULL_SCALE) {
      NbSat = NbSat + 1;
    }
    if (adc_data <= -FULL_SCALE) {
      NbSat = NbSat + 1;
    }
    adc_data = adc_data - OffsetG[GIndice];
    sigma = sigma + adc_data;
    //  x2float=(float)x2float + (float)adc_data*(float)adc_data;
    x2float = (float)x2float + (float)(adc_data << 1);
    //  if (Rmin>adc_data) { Rmin=adc_data; }
    //  if (Rmax<adc_data) { Rmax=adc_data; }

    /*  #if Debug==1
        Serial.print(nMoy);
        Serial.print(F("  "));
        Serial.print(sigma);
        Serial.print(F("  "));
        Serial.println(x2float);
      #endif*/
  }

  xfloat = 2 * (sqrt((abs(x2float - sigma * sigma) / nMoy) / (nMoy - 1))) / sqrt(nMoy);
  // fois 1, 2 ou 3 pour Inteval de confiance à 68, 95 ou 99.7%
  sigma = (sigma >> MoyBit);  // moyenne
  //  sigma = sigma/nMoy;   // pour des valeurs quelconques de nMoy

  /*  #if Debug==-1
    //    Serial.println(freeRam());
      Serial.print(F("G="));
      Serial.print(F("G="));
      Serial.print(F("G="));
      Serial.print(F("G="));
      Serial.print(F("G="));
      Serial.println(F("G="));
    #endif*/
#if 1
  __asm__("nop");
  __asm__("nop");
  __asm__("nop");
  __asm__("nop");
  __asm__("nop");
  __asm__("nop");
  __asm__("nop");
  __asm__("nop");
  __asm__("nop");
  __asm__("nop");
  __asm__("nop");
  __asm__("nop");
  __asm__("nop");
  __asm__("nop");
  __asm__("nop");
  __asm__("nop");
  __asm__("nop");
  __asm__("nop");
  __asm__("nop");
#endif

#if Debug==1
  Serial.print(F("G="));
  Serial.print(PGA);
  Serial.print(F("\t"));
  Serial.print(sigma);
  Serial.print(F("\t"));
  if (NbSat >= NbSatAuto) {
    Serial.print(F("Sat"));
  }
  Serial.print(convertToString(sigma));
  Serial.print(convertToString(FULL_SCALE));
  //    Serial.print(convertTodBV(sigma));
  Serial.print(F("\t"));
  Serial.print(xfloat + '\t');
  Serial.print(convertToString(xfloat) + '\t');
  Serial.print(convertTodBV(sigma) + '\t');
#if defined ADS1220_Temp
  Serial.println(strTemp);
#else
  Serial.println();
#endif
  //    Serial.println();
#endif

#if defined LCD
  lcd.setCursor(0, 0);
  lcd.print(convertToString(sigma));
  lcd.print(convertTodBV(sigma));
  if (NbSat >= NbSatAuto) {
    lcd.setCursor(0, 0);
    lcd.print(F("S"));
  }
  lcd.setCursor(0, 1);
  lcd.print(F("G"));
  lcd.print(PGA);
  lcd.print(F("  "));
  lcd.setCursor(4, 1);
  lcd.print(F(" IC95"));
  //    lcd.print(convertToString((Rmax-Rmin)/2,0));
#endif
  str = convertToString(xfloat);
#if defined LCD
  lcd.setCursor(9, 1);
  //    str.trim();
  lcd.print(str);
#endif

#if defined SD_Present
#if RTC_present!=0
  if (AD_F && (((millis() - MillisDebut) < Duree_AD) || Duree_AD == 0))
#else
  if (AD_F)
#endif
  {
    // if the file opened okay, write to it:
    if (myFile) {
#if RTC_present!=0
      myFile.print(millis() - MillisDebut);
      myFile.print(F(", "));
#endif
      myFile.print(convertToString(sigma));
      myFile.print(", " + str);
      myFile.print(F(", "));
      myFile.print(convertTodBV(sigma));
      myFile.print(F(", "));
      myFile.print(convertTodBV(xfloat));
      myFile.print(F(", "));
#if defined ADS1220_Temp
      myFile.println(strTemp);
      //      myFile.println(", "+strTemp); // nécessite plus de mémoire que 2 lignes ci-dessus
      //      myFile.flush();           // force l'écriture physique des données ATTENTION
      // mauvais pour la carte SD
#else
      myFile.println();
#endif
    }
  } else {
    // if the file opened okay, write to it:
    if (myFile) {
      myFile.print(F("'Fin="));
#if RTC_present!=0
      myFile.println(millis() - MillisDebut);
#else
      myFile.println();
#endif
      //      myFile.flush();             // force l'écriture physique des données
      // close the file:
      myFile.close();
      digitalWrite(LED, 0);           // Fin AD = LED éteinte
#if Debug==1
      Serial.println(F("Fin AD :"));
#endif
    }
  }
#endif

#if defined ADS1220_Temp
  //  if ((millis()-MillisTemp)>=Int_Mes_Temp) {
  //    noInterrupts();
  //do {
  MesAffTemp();
  //} while(1);
  //    interrupts();
  //  }
#endif

#if UGain==-1
  Set_Gain(1);
#endif

  //  delay(300);
}
//   *   *   *   FIN   Boucle   *   *   *   *   *   *   *   *   *   *   *   *   *

//   * * *   convertToMilliV   * * * -------------------------------------------------------
float convertToMilliV(int32_t i32data)
{
  return (float)(i32data * (float)Val_lsb / PGA);
}

//   * * *   ConvertToString   * * * -------------------------------------------------------
String convertToString(int32_t i32data)
{
  String strcts;
  float floatcts;
  floatcts = (float) i32data * Val_lsb / PGA;
  if (abs(floatcts) >= 1000) {
    strcts = (' ' + String(floatcts, 0) + "mV ");
    if (floatcts > 0) {
      strcts = ' ' + strcts;
    }
  }
  else if (abs(floatcts) >= 100) {
    strcts = (String(floatcts, 1) + "mV ");
    if (floatcts > 0) {
      strcts = ' ' + strcts;
    }
  }
  else if (abs(floatcts) >= 10) {
    strcts = (String(floatcts, 2) + "mV ");
    if (floatcts > 0) {
      strcts = ' ' + strcts;
    }
  }
  else if (abs(floatcts) >= 1) {
    strcts = (String(floatcts, 3) + "mV ");
    if (floatcts > 0) {
      strcts = ' ' + strcts;
    }
  }
  else if (abs(floatcts) >= .1) {
    strcts = (String(floatcts * 1000, 1) + "uV ");
    if (floatcts > 0) {
      strcts = " " + strcts;
    }
    if (strcts.length() == 8) {
      strcts = " " + strcts;
    }
    else if (strcts.length() == 7) {
      strcts = "  " + strcts;
    }
    else if (strcts.length() == 6) {
      strcts = "   " + strcts;
    }
  }
  else {
    strcts = (String(floatcts * 1000, 2) + "uV ");
    if (floatcts > 0) {
      strcts = " " + strcts;
    }
    if (strcts.length() == 8) {
      strcts = " " + strcts;
    }
    else if (strcts.length() == 7) {
      strcts = "  " + strcts;
    }
    else if (strcts.length() == 6) {
      strcts = "   " + strcts;
    }
  }
  return (strcts);
}

//   * * *   convertTodBV  //     *     *     *     *     *     *     *     *     *
String convertTodBV(int32_t i32data)
{
  float floatctd = (float) i32data * Val_lsb / PGA; // U crête en mvolts
  if (abs(floatctd) >= 2047) {
    floatctd = 20 * (log10(abs(floatctd))) - 60;   // en dBV
    str = (String(floatctd, 1) + ">>> ");
  }
  else if (abs(floatctd) <= 0.002) {
    if (floatctd != 0) {
      floatctd = 20 * (log10(abs(floatctd))) - 60;   // en dBV
      str = (' ' + String(floatctd, 0) + "<<< ");
    }
    else {
      str = (" -180<<< ");
    }
  }
  else {
    floatctd = 20 * (log10(abs(floatctd))) - 60;   // en dBV
    str = (String(floatctd, 1) + "dBV ");
  }
  return (str);
}

/*//   * * *   convertTodBm   * * * -------------------------------------------------------
  String convertTodBm(int32_t i32data)
  {
    float floatctd=(float) i32data*Val_lsb/PGA;      // U crête en mvolts
    if (abs(floatctd)>=2047) {
      floatctd=20*(log10(abs(floatctd)))-50;         // P en dBm  +30-20*log10(sqr(2))-10*log10(50)
      str=(String(floatctd,1)+">>> ");
      }
    else if (abs(floatctd)<=0.002) {
      floatctd=20*(log10(abs(floatctd)))-50;         // P en dBm  +30-20*log10(sqr(2))-10*log10(50)
      str=(' '+String(floatctd,0)+"<<< ");
      }
    else {
      floatctd=20*(log10(abs(floatctd)))-50;         // P en dBm  +30-20*log10(sqr(2))-10*log10(50)
      if (floatctd>-50) {str=(String(floatctd,1)+"dBm ");}
      else {str=(' '+String(floatctd,0)+"dBm ");}
    }
    return (str);
  }*/

//   * * *   PGA_Auto  //     *     *     *     *     *     *     *     *     *
/* PGA=gain  PEmV    data g=1    data bascule pour g=1
      1      2048    7F FF FF        1F FF FF -> 2
      2      1024    3F FF FF        0F FF FF -> 4
      4       512    1F FF FF        07 FF FF -> 8
      8       256    0F FF FF        03 FF FF -> 16
     16       128    07 FF FF        01 FF FF -> 32
     32        64    03 FF FF        00 FF FF -> 64
     64        32    01 FF FF        00 7F FF -> 128
    128        16    00 FF FF        00 3F FF -> 128
*/
void PGA_Auto()
{
  if (abs(adc_data) <= 0x3FFF) {           // version gain 1 à 128 (pas pb mode commun)
    pc_ads1220.set_pga_gain(PGA_GAIN_128);
    PGA = 128;
    GIndice = 7;
  }
  else if (abs(adc_data) <= 0x7FFF) {
    pc_ads1220.set_pga_gain(PGA_GAIN_64);
    PGA = 64;
    GIndice = 6;
  }
  else if (abs(adc_data) <= 0xFFFF) {
    pc_ads1220.set_pga_gain(PGA_GAIN_32);
    PGA = 32;
    GIndice = 5;
  }
  else if (abs(adc_data) <= 0x1FFFF) {
    pc_ads1220.set_pga_gain(PGA_GAIN_16);
    PGA = 16;
    GIndice = 4;
  }
  else if (abs(adc_data) <= 0x03FFFF) {
    pc_ads1220.set_pga_gain(PGA_GAIN_8);
    PGA = 8;
    GIndice = 3;
  }
  else if (abs(adc_data) <= 0x7FFFF) {
    pc_ads1220.set_pga_gain(PGA_GAIN_4);
    PGA = 4;
    GIndice = 2;
  }
  else if (abs(adc_data) <= 0xFFFFF) {
    pc_ads1220.set_pga_gain(PGA_GAIN_2);
    PGA = 2;
    GIndice = 1;
  }
  else {
    pc_ads1220.set_pga_gain(PGA_GAIN_1);
    PGA = 1;
    GIndice = 0;
  }
  return;
}

//   * * *   Set_Gain     //     *     *     *     *     *     *     *     *     *
void Set_Gain(byte Gain)
{
  switch (Gain) {
    case 1:
      pc_ads1220.set_pga_gain(PGA_GAIN_1);
      PGA = 1;
      GIndice = 0;
      break;
    case 2:
      pc_ads1220.set_pga_gain(PGA_GAIN_2);
      PGA = 2;
      GIndice = 1;
      break;
    case 4:
      pc_ads1220.set_pga_gain(PGA_GAIN_4);
      PGA = 4;
      GIndice = 2;
      break;
    case 8:
      pc_ads1220.set_pga_gain(PGA_GAIN_8);
      PGA = 8;
      GIndice = 3;
      break;
    case 16:
      pc_ads1220.set_pga_gain(PGA_GAIN_16);
      PGA = 16;
      GIndice = 4;
      break;
    case 32:
      pc_ads1220.set_pga_gain(PGA_GAIN_32);
      PGA = 32;
      GIndice = 5;
      break;
    case 64:
      pc_ads1220.set_pga_gain(PGA_GAIN_64);
      PGA = 64;
      GIndice = 6;
      break;
    case 128:
      pc_ads1220.set_pga_gain(PGA_GAIN_128);
      PGA = 128;
      GIndice = 7;
      break;
defaut:
      pc_ads1220.set_pga_gain(PGA_GAIN_1);
      PGA = 1;
  }
}

void Calibration(void)  //     *     *     *     *     *     *     *     *     *
{
#if defined LCD
  lcd.setCursor(0, 0);
  lcd.print(F("Calibration du 0 "));
#endif
  pc_ads1220.set_data_rate(Rate);
  for (int i = 0; i <= 7; i++) {
    sigma0 = 0;
    for (int iad = 1; iad <= (nMoy * 4); iad++) {
      Set_Gain((1 << i));
      do {}
      while ((digitalRead(ADS1220_DRDY_PIN)) == HIGH);
      adc_data = pc_ads1220.Read_Data_Samples();  // mesure avec gain=GPA
      sigma0 = sigma0 + adc_data;
    }
    sigma0 = sigma0 / (nMoy * 4);
    OffsetG[i] = sigma0;
#if defined EEPROM_use
    EEPROM.put(EadOffset + i * 4, sigma0);
#endif
#if defined LCD
    if (i == 0) {
      lcd.clear();
    }
    lcd.setCursor(0, 0);
    lcd.print(F("Cal G="));
    lcd.print(PGA);
    lcd.print(F(" "));
    lcd.print(sigma0);
    lcd.print(F("   "));
    lcd.setCursor(0, 1);
    lcd.print(convertToString(sigma0));
#endif
#if Debug>=0
    Serial.print(F("Cal G="));
    Serial.print(PGA);
    Serial.print(F(": "));
    Serial.print(sigma0);
    Serial.print(F(" "));
    Serial.println(convertToString(sigma0));
#endif
    delay(3000);
  }
}

#if RTC_Present!=0
void getDateHeure(void)  //     *     *     *     *     *     *     *     *     *
{
  DateTime now = rtc.now();
  //  cDateRTC[11] = now.toString(cDateRTC);
  //  cHeureRTC[9] = now.toString(cHeureRTC);
  sprintf(cDateRTC, "%04d-%02d-%02d ", now.year(), now.month(), now.day());
  sprintf(cHeureRTC, "%02d:%02d:%02d",  now.hour(), now.minute(), now.second());
}
#endif

#if defined SD_Present
void OpenFile(void)  //     *     *     *     *     *     *     *     *     *
{
#if RTC_Present!=0
  NomFichier[0] = cDateRTC[2];
  NomFichier[1] = cDateRTC[3];
  NomFichier[2] = cDateRTC[5];
  NomFichier[3] = cDateRTC[6];
  NomFichier[4] = cDateRTC[8];
  NomFichier[5] = cDateRTC[9];
  NomFichier[6] = '.';
  NomFichier[7] = 't';
  NomFichier[8] = 'x';
  NomFichier[9] = 't';
  NomFichier[10] = '\0';
#endif
  // Supprimer le fichier s'il existe
  //    SD.remove(NomFichier);
  // open the file. Note that only one file can be open at a time,
  // so you have to close this one before opening another.
  myFile = SD.open(NomFichier, FILE_WRITE);
#if RTC_Present!=0
  MillisDebut = millis();
#endif
  // if the file opened okay, write to it:
#if RTC_Present!=0
  if (myFile) {
    myFile.print(F("'"));
    myFile.print(cDateRTC);
    myFile.print(F(", "));
    myFile.print(cHeureRTC);
    myFile.print(F(", "));
    myFile.println(MillisDebut);
#if defined ADS1220_Temp
    myFile.println("'T=" + strTemp);
#endif
  }
#endif
}
#endif

int freeRam ()  //     *     *     *     *     *     *     *     *     *
{
  extern int __heap_start, *__brkval;
  int v;
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}

#if defined ADS1220_Temp
void MesAffTemp(void)   // Mesure et Affiche Température  //     *     *     *     *     *     *     *     *     *
{
  //   Mesure et affichage température du CAN
  AValue = pc_ads1220.Read_SingleShot_Temperature_Wait();
  strTemp = (String (float (AValue * 0.03125), 1) + "C ");
  MillisTemp = millis();
#if defined LCD
  lcd.setCursor(11, 3);
  lcd.print("  " + strTemp);
#endif

#if Debug>=0
  Serial.print(F("T= "));
  Serial.print(bit24);
  Serial.print(F(" "));
  Serial.println(strTemp);
#endif
}
#endif

void PrintADS1220Config(void)  //     *     *     *     *     *     *     *     *     *
{
#if Debug>=0
  Serial.print(pc_ads1220.readRegister_gt(0), HEX);
  Serial.print(F(" "));
  Serial.print(pc_ads1220.readRegister_gt(1), HEX);
  Serial.print(F(" "));
  Serial.print(pc_ads1220.readRegister_gt(2), HEX);
  Serial.print(F(" "));
  Serial.println(pc_ads1220.readRegister_gt(3), HEX);
#endif
}

// -   -   -   ISR Timer2     //     *     *     *     *     *     *     *     *     *
#if defined Timer2
ISR(TIMER2_OVF_vect)        // Timer2 interrupt service routine
{
  TCNT2 = timer2_counter;   // preload timer
  //      digitalWrite(LED, !digitalRead(LED));
  //    digitalWrite(LED,1);
  //    PORTC |= 0x8;
  #if defined MCP4821_P
    DAC16 ++;
    if (DAC16 >= 4095) {
      DAC16 = 0;
    }
//    dacChip.writedata16(DAC16);
  #endif
  //    PORTC &= ~0x8;        // pulse = 126ns, période = 375ns
  //    digitalWrite(LED,0);
}
#endif
 I am very aware that this code is very long, but if I delete something the problem goes away! 
 Herre now the modified library for the ADS1220 (I modified this library to be able to use the MCP4821 during an interruption).
//////////////////////////////////////////////////////////////////////////////////////////
//
//    Arduino library for the ADS1220 24-bit ADC breakout board
//
//    Author: Ashwin Whitchurch
//    Copyright (c) 2018 ProtoCentral
//
//    Based on original code from Texas Instruments
//
//    This software is licensed under the MIT License(http://opensource.org/licenses/MIT).
//
//   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
//   NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
//   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
//   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
//   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//   For information on how to use, visit https://github.com/Protocentral/Protocentral_ADS1220/
//
//   Modified 2021 by Jean-Paul Gendner (F5BU@orange.fr)
//
/////////////////////////////////////////////////////////////////////////////////////////


#include "Arduino.h"

#include "SPI.h"

//ADS1220 SPI commands
#define SPI_MASTER_DUMMY    0xFF
#define RESET               0x06   //Send the RESET command (06h) to make sure the ADS1220 is properly reset after power-up
#define START               0x08    //Send the START/SYNC command (08h) to start converting in continuous conversion mode
#define WREG  0x40
#define RREG  0x20

//Config registers
#define CONFIG_REG0_ADDRESS 0x00
#define CONFIG_REG1_ADDRESS 0x01
#define CONFIG_REG2_ADDRESS 0x02
#define CONFIG_REG3_ADDRESS 0x03

#define REG_CONFIG1_DR_MASK       0xE0
#define REG_CONFIG0_PGA_GAIN_MASK 0x0E
#define REG_CONFIG0_MUX_MASK      0xF0

#define DR_20SPS    0x00
#define DR_45SPS    0x20
#define DR_90SPS    0x40
#define DR_175SPS   0x60
#define DR_330SPS   0x80
#define DR_600SPS   0xA0
#define DR_1000SPS  0xC0

#define PGA_GAIN_1   0x00
#define PGA_GAIN_2   0x02
#define PGA_GAIN_4   0x04
#define PGA_GAIN_8   0x06
#define PGA_GAIN_16  0x08
#define PGA_GAIN_32  0x0A
#define PGA_GAIN_64  0x0C
#define PGA_GAIN_128 0x0E

#define MUX_AIN0_AIN1   0x00
#define MUX_AIN0_AIN2   0x10
#define MUX_AIN0_AIN3   0x20
#define MUX_AIN1_AIN2   0x30
#define MUX_AIN1_AIN3   0x40
#define MUX_AIN2_AIN3   0x50
#define MUX_AIN1_AIN0   0x60
#define MUX_AIN3_AIN2   0x70
#define MUX_AIN0_AVSS   0x80
#define MUX_AIN1_AVSS   0x90
#define MUX_AIN2_AVSS   0xA0
#define MUX_AIN3_AVSS   0xB0

#define MUX_SE_CH0      0x80
#define MUX_SE_CH1      0x90
#define MUX_SE_CH2      0xA0
#define MUX_SE_CH3      0xB0

#define _BVP(bit) (1<<(bit))

class Protocentral_ADS1220
{
private:
      uint8_t m_config_reg0;
      uint8_t m_config_reg1;
      uint8_t m_config_reg2;
      uint8_t m_config_reg3;

/*      uint8_t Config_Reg0;
      uint8_t Config_Reg1;
      uint8_t Config_Reg2;
      uint8_t Config_Reg3;
*/
      uint8_t m_drdy_pin=6;
      uint8_t m_cs_pin=7;
  public:
      uint8_t NewDataAvailable;

      Protocentral_ADS1220();
      void begin(uint8_t cs_pin, uint8_t drdy_pin);
      void Start_Conv(void);
      void ads1220_Reset(void);

      void SPI_Command(unsigned char data_in);
      void writeRegister(uint8_t address, uint8_t value);
      uint8_t readRegister(uint8_t address);
      uint8_t readRegister_gt(uint8_t address);
      uint8_t * Read_Data(void);
      int32_t Read_WaitForData();

      void get_config_reg(void);
//      void get_config_reg(uint8_t *array);

      void PGA_OFF(void);
      void PGA_ON(void);
      void set_conv_mode_continuous(void);
      void Single_shot_mode_ON(void);
      void set_data_rate(int datarate);
      void set_pga_gain(int pgagain);
      void select_mux_channels(int channels_conf);
      void set_conv_mode_single_shot(void);
      void Start_SingleShot_SingleEnded(uint8_t channel_no);
      int32_t Read_SingleShot_WaitForData(void);
      int32_t Read_SingleShot_SingleEnded_WaitForData(uint8_t channel_no);
      int16_t Read_SingleShot_Temperature_Wait(void);
      int32_t Read_Data_Samples();
};
 And
//////////////////////////////////////////////////////////////////////////////////////////
//
//    Arduino library for the ADS1220 24-bit ADC breakout board
//
//    Author: Ashwin Whitchurch
//    Copyright (c) 2018 ProtoCentral
//
//    Based on original code from Texas Instruments
//
//    This software is licensed under the MIT License(http://opensource.org/licenses/MIT).
//
//   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
//   NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
//   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
//   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
//   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//   For information on how to use, visit https://github.com/Protocentral/Protocentral_ADS1220/
//
//   Modified 2021 by Jean-Paul Gendner (F5BU@orange.fr)
//
/////////////////////////////////////////////////////////////////////////////////////////

#include <Arduino.h>
#include "Protocentral_ADS1220_g.h"
#include <SPI.h>

#if defined (SPI_HAS_TRANSACTION)
  static SPISettings ADCSPISettings;
#endif

//#define BOARD_SENSYTHING ST_1_3

Protocentral_ADS1220::Protocentral_ADS1220() 								// Constructors
{}

void Protocentral_ADS1220::writeRegister(uint8_t address, uint8_t value)
{
    digitalWrite(m_cs_pin,LOW);
    SPI.transfer(WREG|(address<<2));
    SPI.transfer(value);
    digitalWrite(m_cs_pin,HIGH);
}

uint8_t Protocentral_ADS1220::readRegister(uint8_t address)
{
    uint8_t data;

    digitalWrite(m_cs_pin,LOW);
    SPI.transfer(RREG|(address<<2));
    data = SPI.transfer(SPI_MASTER_DUMMY);
    digitalWrite(m_cs_pin,HIGH);
    return data;
}

uint8_t Protocentral_ADS1220::readRegister_gt(uint8_t address)
{
    uint8_t data;

#if defined (SPI_HAS_TRANSACTION)
  SPI.beginTransaction(ADCSPISettings);
#endif
    digitalWrite(m_cs_pin,LOW);
    SPI.transfer(RREG|(address<<2));
    data = SPI.transfer(SPI_MASTER_DUMMY);
    digitalWrite(m_cs_pin,HIGH);
#if defined (SPI_HAS_TRANSACTION)
  SPI.endTransaction();
#endif
    return data;
}

void Protocentral_ADS1220::SPI_Command(unsigned char data_in)
{
    digitalWrite(m_cs_pin, LOW);
    SPI.transfer(data_in);
    digitalWrite(m_cs_pin, HIGH);
}

void Protocentral_ADS1220::begin(uint8_t cs_pin, uint8_t drdy_pin)
{
#if defined (SPI_HAS_TRANSACTION)
  ADCSPISettings = SPISettings(6500000, MSBFIRST, SPI_MODE1); // min période de 150ns
  SPI.beginTransaction(ADCSPISettings);
#endif
    m_drdy_pin=drdy_pin;
    m_cs_pin=cs_pin;

    pinMode(m_cs_pin, OUTPUT);
    pinMode(m_drdy_pin, INPUT);

#if defined(BOARD_SENSYTHING)
    SPI.begin(18, 35, 23, 19);
#else
    SPI.begin();
#endif
    SPI.setBitOrder(MSBFIRST);
    SPI.setDataMode(SPI_MODE1);

    ads1220_Reset();

//    digitalWrite(m_cs_pin,LOW);

    m_config_reg0 = 0x00;   //Default settings: AINP=AIN0, AINN=AIN1, Gain 1, PGA enabled
//    m_config_reg0 = 0x01;   //Default settings: AINP=AIN0, AINN=AIN1, Gain 1, PGA dissabled
    m_config_reg1 = 0x04;   //Default settings: DR=20 SPS, Mode=Normal, Conv mode=continuous, Temp Sensor disabled, Current Source off
    m_config_reg2 = 0x10;   //Default settings: Vref internal, 50/60Hz rejection, power open, IDAC off
    m_config_reg3 = 0x00;   //Default settings: IDAC1 disabled, IDAC2 disabled, DRDY pin only

    writeRegister( CONFIG_REG0_ADDRESS , m_config_reg0);
    writeRegister( CONFIG_REG1_ADDRESS , m_config_reg1);
    writeRegister( CONFIG_REG2_ADDRESS , m_config_reg2);
    writeRegister( CONFIG_REG3_ADDRESS , m_config_reg3);

/*    Serial.print("m_Config: ");
    Serial.print(m_config_reg0,HEX);
    Serial.print(" ");
    Serial.print(m_config_reg1,HEX);
    Serial.print(" ");
    Serial.print(m_config_reg2,HEX);
    Serial.print(" ");
    Serial.println(m_config_reg3,HEX);
    Serial.println(" ");

    Config_Reg0 = readRegister(CONFIG_REG0_ADDRESS);
    Config_Reg1 = readRegister(CONFIG_REG1_ADDRESS);
    Config_Reg2 = readRegister(CONFIG_REG2_ADDRESS);
    Config_Reg3 = readRegister(CONFIG_REG3_ADDRESS);

    Serial.print("Config_Reg :  ");
    Serial.print(Config_Reg0,HEX);
    Serial.print(" ");
    Serial.print(Config_Reg1,HEX);
    Serial.print(" ");
    Serial.print(Config_Reg2,HEX);
    Serial.print(" ");
    Serial.println(Config_Reg3,HEX);
    Serial.println(" ");
*/
//    digitalWrite(m_cs_pin,HIGH);

    //Start_Conv();
#if defined (SPI_HAS_TRANSACTION)
  SPI.endTransaction();
#endif
}

void Protocentral_ADS1220::ads1220_Reset()
{
#if defined (SPI_HAS_TRANSACTION)
  SPI.beginTransaction(ADCSPISettings);
#endif
    SPI_Command(RESET);
    delayMicroseconds(100);
#if defined (SPI_HAS_TRANSACTION)
  SPI.endTransaction();
#endif
}

void Protocentral_ADS1220::Start_Conv()
{
#if defined (SPI_HAS_TRANSACTION)
  SPI.beginTransaction(ADCSPISettings);
#endif
    SPI_Command(START);
#if defined (SPI_HAS_TRANSACTION)
  SPI.endTransaction();
#endif
}

void Protocentral_ADS1220::PGA_ON(void)
{
#if defined (SPI_HAS_TRANSACTION)
  SPI.beginTransaction(ADCSPISettings);
#endif
    m_config_reg0 &= ~_BVP(0);
    writeRegister(CONFIG_REG0_ADDRESS,m_config_reg0);
#if defined (SPI_HAS_TRANSACTION)
  SPI.endTransaction();
#endif
}

void Protocentral_ADS1220::PGA_OFF(void)
{
#if defined (SPI_HAS_TRANSACTION)
  SPI.beginTransaction(ADCSPISettings);
#endif
    m_config_reg0 |= _BVP(0);
    writeRegister(CONFIG_REG0_ADDRESS,m_config_reg0);
#if defined (SPI_HAS_TRANSACTION)
  SPI.endTransaction();
#endif
}

void Protocentral_ADS1220::set_conv_mode_continuous(void)
{
#if defined (SPI_HAS_TRANSACTION)
  SPI.beginTransaction(ADCSPISettings);
#endif
    m_config_reg1 |= _BVP(2);
    writeRegister(CONFIG_REG1_ADDRESS,m_config_reg1);
#if defined (SPI_HAS_TRANSACTION)
  SPI.endTransaction();
#endif
}

void Protocentral_ADS1220::set_conv_mode_single_shot(void)
{
#if defined (SPI_HAS_TRANSACTION)
  SPI.beginTransaction(ADCSPISettings);
#endif
    m_config_reg1 &= ~_BVP(2);
    writeRegister(CONFIG_REG1_ADDRESS,m_config_reg1);
#if defined (SPI_HAS_TRANSACTION)
  SPI.endTransaction();
#endif
}

void Protocentral_ADS1220::set_data_rate(int datarate)
{
#if defined (SPI_HAS_TRANSACTION)
  SPI.beginTransaction(ADCSPISettings);
#endif
    m_config_reg1 &= ~REG_CONFIG1_DR_MASK;
    m_config_reg1 |= datarate;
    writeRegister(CONFIG_REG1_ADDRESS,m_config_reg1);
#if defined (SPI_HAS_TRANSACTION)
  SPI.endTransaction();
#endif
}

void Protocentral_ADS1220::select_mux_channels(int channels_conf)
{
#if defined (SPI_HAS_TRANSACTION)
  SPI.beginTransaction(ADCSPISettings);
#endif
    m_config_reg0 &= ~REG_CONFIG0_MUX_MASK;
    m_config_reg0 |= channels_conf;
    writeRegister(CONFIG_REG0_ADDRESS,m_config_reg0);
#if defined (SPI_HAS_TRANSACTION)
  SPI.endTransaction();
#endif
}

void Protocentral_ADS1220::set_pga_gain(int pgagain)
{
#if defined (SPI_HAS_TRANSACTION)
  SPI.beginTransaction(ADCSPISettings);
#endif
    m_config_reg0 &= ~REG_CONFIG0_PGA_GAIN_MASK;
    m_config_reg0 |= pgagain ;
    writeRegister(CONFIG_REG0_ADDRESS,m_config_reg0);
#if defined (SPI_HAS_TRANSACTION)
  SPI.endTransaction();
#endif
}

void Protocentral_ADS1220::get_config_reg()
//void Protocentral_ADS1220::get_config_reg(uint8_t *array)
{
    static uint8_t config_Buff[4];
#if defined (SPI_HAS_TRANSACTION)
  SPI.beginTransaction(ADCSPISettings);
#endif
/*    m_config_reg0 = readRegister(CONFIG_REG0_ADDRESS);
    m_config_reg1 = readRegister(CONFIG_REG1_ADDRESS);
    m_config_reg2 = readRegister(CONFIG_REG2_ADDRESS);
    m_config_reg3 = readRegister(CONFIG_REG3_ADDRESS);*/
    config_Buff[0] = readRegister(CONFIG_REG0_ADDRESS);
    config_Buff[1] = readRegister(CONFIG_REG1_ADDRESS);
    config_Buff[2] = readRegister(CONFIG_REG2_ADDRESS);
    config_Buff[3] = readRegister(CONFIG_REG3_ADDRESS);
#if defined (SPI_HAS_TRANSACTION)
  SPI.endTransaction();
#endif
/*    config_Buff[0] = m_config_reg0 ;
    config_Buff[1] = m_config_reg1 ;
    config_Buff[2] = m_config_reg2 ;
    config_Buff[3] = m_config_reg3 ;
    array[0] = m_config_reg0 ;
    array[1] = m_config_reg1 ;
    array[2] = m_config_reg2 ;
    array[3] = m_config_reg3 ;*/

//    return config_Buff;
    return;
}

void Protocentral_ADS1220::Start_SingleShot_SingleEnded(uint8_t channel_no)
{
#if defined (SPI_HAS_TRANSACTION)
  SPI.beginTransaction(ADCSPISettings);
#endif
//    select_mux_channels(channel_no);
    m_config_reg0 &= ~REG_CONFIG0_MUX_MASK;
    m_config_reg0 |= channel_no;
    writeRegister(CONFIG_REG0_ADDRESS,m_config_reg0);

//    delayMicroseconds(10);
    SPI_Command(START);
#if defined (SPI_HAS_TRANSACTION)
  SPI.endTransaction();
#endif
}

int32_t Protocentral_ADS1220::Read_WaitForData()
{
    static byte SPI_Buff[3];
    long int bit24;

#if defined (SPI_HAS_TRANSACTION)
  SPI.beginTransaction(ADCSPISettings);
#endif
    do {}
    while ((digitalRead(m_drdy_pin)) == HIGH);    //        Wait for DRDY to transition low
    {
        digitalWrite(m_cs_pin,LOW);                         //Take CS low
        for (int i = 0; i < 3; i++)
        {
          SPI_Buff[i] = SPI.transfer(SPI_MASTER_DUMMY);
        }
        digitalWrite(m_cs_pin,HIGH);                  //  Clear CS to high

        bit24 = SPI_Buff[0];
        bit24 = (bit24 << 8) | SPI_Buff[1];
        bit24 = (bit24 << 8) | SPI_Buff[2];                                 // Converting 3 bytes to a 24 bit int

        bit24 = (bit24 << 8);
        bit24 = (bit24 >> 8);                      // Converting 24 bit two's complement to 32 bit two's complement
    }
#if defined (SPI_HAS_TRANSACTION)
  SPI.endTransaction();
#endif
    return bit24;
}

int32_t Protocentral_ADS1220::Read_Data_Samples()
{
    static byte SPI_Buff[3];
    long int bit24;

#if defined (SPI_HAS_TRANSACTION)
  SPI.beginTransaction(ADCSPISettings);
#endif
    digitalWrite(m_cs_pin,LOW);                         //Take CS low
    for (int i = 0; i < 3; i++)
    {
      SPI_Buff[i] = SPI.transfer(SPI_MASTER_DUMMY);
    }
    digitalWrite(m_cs_pin,HIGH);                  //  Clear CS to high

    bit24 = SPI_Buff[0];
    bit24 = (bit24 << 8) | SPI_Buff[1];
    bit24 = (bit24 << 8) | SPI_Buff[2];                                 // Converting 3 bytes to a 24 bit int

    bit24 = (bit24 << 8);
    bit24 = (bit24 >> 8);                      // Converting 24 bit two's complement to 32 bit two's complement

#if defined (SPI_HAS_TRANSACTION)
  SPI.endTransaction();
#endif
    return bit24;
}

int32_t Protocentral_ADS1220::Read_SingleShot_WaitForData(void)
{
    static byte SPI_Buff[3];
    long int bit24;

#if defined (SPI_HAS_TRANSACTION)
  SPI.beginTransaction(ADCSPISettings);
#endif
    SPI_Command(START);

    do {}
    while ((digitalRead(m_drdy_pin)) == HIGH);    //        Wait for DRDY to transition low
    {
        digitalWrite(m_cs_pin,LOW);                         //Take CS low
        for (int i = 0; i < 3; i++)
        {
          SPI_Buff[i] = SPI.transfer(SPI_MASTER_DUMMY);
        }
        digitalWrite(m_cs_pin,HIGH);                  //  Clear CS to high

        bit24 = SPI_Buff[0];
        bit24 = (bit24 << 8) | SPI_Buff[1];
        bit24 = (bit24 << 8) | SPI_Buff[2];                                 // Converting 3 bytes to a 24 bit int

        bit24 = (bit24 << 8);
        bit24 = (bit24 >> 8);                      // Converting 24 bit two's complement to 32 bit two's complement
    }
#if defined (SPI_HAS_TRANSACTION)
  SPI.endTransaction();
#endif
    return bit24;
}

int32_t Protocentral_ADS1220::Read_SingleShot_SingleEnded_WaitForData(uint8_t channel_no)
{
    static byte SPI_Buff[3];
    long int bit24;

#if defined (SPI_HAS_TRANSACTION)
  SPI.beginTransaction(ADCSPISettings);
#endif
//    select_mux_channels(channel_no);
    m_config_reg0 &= ~REG_CONFIG0_MUX_MASK;
    m_config_reg0 |= channel_no;
    writeRegister(CONFIG_REG0_ADDRESS,m_config_reg0);
//    delayMicroseconds(10);
    SPI_Command(START);
    do {}
    while ((digitalRead(m_drdy_pin)) == HIGH);    //        Wait for DRDY to transition low
    {
        digitalWrite(m_cs_pin,LOW);                         //Take CS low
        for (int i = 0; i < 3; i++)
        {
          SPI_Buff[i] = SPI.transfer(SPI_MASTER_DUMMY);
        }
        digitalWrite(m_cs_pin,HIGH);                  //  Clear CS to high

        bit24 = SPI_Buff[0];
        bit24 = (bit24 << 8) | SPI_Buff[1];
        bit24 = (bit24 << 8) | SPI_Buff[2];                                 // Converting 3 bytes to a 24 bit int
        bit24 = (bit24 << 8);
        bit24 = (bit24 >> 8);                      // Converting 24 bit two's complement to 32 bit two's complement
    }
#if defined (SPI_HAS_TRANSACTION)
  SPI.endTransaction();
#endif
    return bit24;
}

int16_t Protocentral_ADS1220::Read_SingleShot_Temperature_Wait(void)
{
  static byte SPI_Buff[3];
  int16_t bit16=0;

#if defined (SPI_HAS_TRANSACTION)
  SPI.beginTransaction(ADCSPISettings);
#endif
//    SPI_Command(RESET);
//  m_config_reg1 |= 0x02;                     // T
  writeRegister(CONFIG_REG1_ADDRESS , 0xC6);
  SPI_Command(START);

  do {}
  while ((digitalRead(m_drdy_pin)) == HIGH);    //        Wait for DRDY to transition low
  digitalWrite(m_cs_pin,LOW);                  //Take CS low
  delayMicroseconds(1);
//SPI_Command(0x10);
  for (int i = 0; i < 2; i++)
  {
    SPI_Buff[i] = SPI.transfer(SPI_MASTER_DUMMY);
  }
  delayMicroseconds(1);
  digitalWrite(m_cs_pin,HIGH);          //  Clear CS to high

  bit16 = SPI_Buff[0];
  bit16 = (bit16 << 8) | SPI_Buff[1];
  bit16 = (bit16 >> 2);                 // 14 bits signés température
  
//  m_config_reg1 &= ~0x02;
  writeRegister(CONFIG_REG1_ADDRESS , m_config_reg1);
#if defined (SPI_HAS_TRANSACTION)
  SPI.endTransaction();
#endif
  return bit16;
}
 I do not put the MCP4821 modified library because the MCP4821 is initialized but not used in the loop.

 I'm stunned that adding a nop statement could have such an effect. It is no longer programming but alchemy! I compared the resulting assembly codes and found that there were huge differences and nowhere found the nop lines. 

 Any help will be welcome.
 Regards