aht.getEvent causes crash before it's executed?

I am troubleshooting a project that uses a XIAO nRF52840, SSD1306, AHT20, and HC05 on one breadboard, and a Pro Micro, AHT20, and HC05 on another. The idea is to display the temp and humidity from both the local (master) and remote (slave) locations on the master OLED display. Both the AHT20 and the SSD1306 are on the I2C bus of the local board. Almost everything works: I can retrieve and display the remote data on the local display.

When I add the same code that is used on the remote device to sample the temp and humidity from the AHT20 to the local code, the sketch stops. If I comment out the aht.getEvent statement, the sketch runs. It doesn't sample the data, but it doesn't crash.

What's very weird (to me at least) is that un-commenting the aht.getEvent statement causes the sketch to crash BEFORE the statement is executed. I demonstrated this by inserting print statements before the aht.getEvent statement. Without the aht.getEvent statement, all of the Serial.println statements print normally. With the statement, only "Serial monitor set to 9600" appears in the serial monitor. Also, with the statement, double-tapping the reset button is required or the upload gives errors related to the com port.

How can a line of code cause a problem before it's executed?

Also, should the AHT20 library be able to handle having 2 devices on the I2C bus, or do I need to access the AHT20 directly with hex code?

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_AHTX0.h>
#include <math.h>

const int button = 2;
int buttonState = 0;
int rtemp, rhumidity; //data from remote sensor
int ltemp, lhumidity; //data from local sensor
float lctemp,lftemp;
int lroundtemp, lroundhumidity;

Adafruit_AHTX0 aht;

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
// The pins for I2C are defined by the Wire-library. 
// On an arduino UNO:       A4(SDA), A5(SCL)
// On an arduino MEGA 2560: 20(SDA), 21(SCL)
// On an arduino LEONARDO:   2(SDA),  3(SCL), ...
#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C 
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

void setup() 
{
  pinMode(button,INPUT); // button wired to gnd
  delay(3000);
  Serial.begin(9600);// Set data rate for the serial monitor 
  delay(3000);
  Serial.println("Serial Monitor set to 9600");
  delay(3000);
  
  Serial1.begin(38400);// set the data rate for the Serial1 port to match the UART baud on HC05
  delay(5);
  Serial.println("Serial1 is now set to 38400\n");
  Serial.println("line 46");
  //delay(3000);
Serial.println("line 48");
  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) 
    {
      Serial.println(F("SSD1306 allocation failed"));
      for(;;); // Don't proceed, loop forever
    }

  Serial.println("line 56");
}
void loop() 
{
 */ /******************************************************************* 
        This section gets Local data from the on-board AHT20
        ********************************************************************/
        Serial.println("line 89");
        sensors_event_t humidity, temp;
        Serial.println("line 91");
        aht.getEvent(&humidity, &temp); // populate temp and humidity objects
        Serial.println("line 93");
        delay(100);
        //lctemp=temp.temperature;
        lftemp=(lctemp*9.0/5.0)+32.0;
        lroundtemp=(int)roundf(lftemp);
        Serial.print("Temperature: ");
        Serial.print(lroundtemp);
        Serial.println(" °F");
        delay(2000);
        //lroundhumidity=(int)roundf(humidity.relative_humidity);

The I2C bus is a multi sensor bus, each device has to have a unique address.

That is a true statement, but doesn't answer my questions.

The sketch does NOT compile, I get

fork/exec /Users/ronalexander/Library/Arduino15/packages/Seeeduino/hardware/nrf52/1.1.10/tools/adafruit-nrfutil/macos/adafruit-nrfutil: permission denied

Also, your debug statements are out by 5, where it says
line 46 is only 41 in the sketch above

Sorry, I don't understand all that is going on. Just post the code that fails as a single sketch so we can copy/paste it.

I fixed the compile error, but since I don't have a XIAO nRF52840 can't do more. The second code snippet says line 89 but there is nowhere near that many lines, something is amiss.

I think you need to produce a minimum reproducible example, and if possible, with a more common board.

Make that line global and see what happens.

Somewhere in void setup() I would have expected to see:

aht.begin())

which would initialize the aht object with the default references to Wire, sensor ID and sensor I2C address. That last item ties in with comment #2 from sonofcy about I2C addressing.

Same principle as has been done for the screen object.
See the example here:

`Adafruit_AHTX0/examples/adafruit_aht_test/adafruit_aht_test.ino at master · adafruit/Adafruit_AHTX0 · GitHub

See also the library header:

`Adafruit_AHTX0/Adafruit_AHTX0.h at master · adafruit/Adafruit_AHTX0 · GitHub

I left out a bunch of commented-out code, in the interest of space. I am trying to debug only the part that involves the aht.getEvent command. But if you think it will help, here's the whole thing:

/*******************************************************************************************
This sketch for the Local waits for a button push, then sends a command to
the Remote.  Upon receiving the command, the Remote sends temperature and humidity data back.
Local then displays the values on the mini OLED screen, which times out and turns off after a period.
****************************************************************************************/
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_AHTX0.h>
#include <math.h>

const int button = 2;
int buttonState = 0;
int rtemp, rhumidity; //data from remote sensor
int ltemp, lhumidity; //data from local sensor
float lctemp,lftemp;
int lroundtemp, lroundhumidity;

Adafruit_AHTX0 aht;

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
// The pins for I2C are defined by the Wire-library. 
// On an arduino UNO:       A4(SDA), A5(SCL)
// On an arduino MEGA 2560: 20(SDA), 21(SCL)
// On an arduino LEONARDO:   2(SDA),  3(SCL), ...
#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C 
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

void setup() 
{
  pinMode(button,INPUT); // button wired to gnd
  delay(3000);
  Serial.begin(9600);// Set data rate for the serial monitor 
  delay(3000);
  Serial.println("Serial Monitor set to 9600");
  delay(3000);
  
  Serial1.begin(38400);// set the data rate for the Serial1 port to match the UART baud on HC05
  delay(5);
  Serial.println("Serial1 is now set to 38400\n");
  Serial.println("line 46");
  //delay(3000);
Serial.println("line 48");
  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) 
    {
      Serial.println(F("SSD1306 allocation failed"));
      for(;;); // Don't proceed, loop forever
    }

  Serial.println("line 56");
}
void loop() 
{
  /****************************************************************************
  This section checks if the button has been pushed.  If it has, a '1' is sent to the Remote.
  The Remote responds by sending the latest temp and humidity.
  *****************************************************************************
    // Reading the button
    buttonState = digitalRead(button);// becomes LOW when button is pushed
    //Serial.print("buttonState=");
    //Serial.println(buttonState);
    //delay(2000);
    if(buttonState == LOW)
      {
        Serial1.write('1'); // Sends '1' to the Slave 
        delay(1000);
        while (Serial1.available()>0)
        {
          //delay(2000);
          rtemp = Serial1.read();
          delay(50);
          Serial.print("Temp from Remote =");
          Serial.println(rtemp);
          //delay(50);
          rhumidity = Serial1.read();
          Serial.print("Humidity from Remote =");
          Serial.println(rhumidity);
          Serial.println();
        }*/ 
       /******************************************************************* 
        This section gets Local data from the on-board AHT20
        ********************************************************************/
        Serial.println("line 89");
        sensors_event_t humidity, temp;
        Serial.println("line 91");
        aht.getEvent(&humidity, &temp); // populate temp and humidity objects
        Serial.println("line 93");
        delay(100);
        //lctemp=temp.temperature;
        lftemp=(lctemp*9.0/5.0)+32.0;
        lroundtemp=(int)roundf(lftemp);
        Serial.print("Temperature: ");
        Serial.print(lroundtemp);
        Serial.println(" °F");
        delay(2000);
        //lroundhumidity=(int)roundf(humidity.relative_humidity);
        
      
      


/****************************************************************************************
This section displays the temp and humidity on the OLED display
******************************************************************************************/
      /*  display.clearDisplay();// Clear the buffer
        // Show the display buffer on the screen. You MUST call display() after
        // drawing commands to make them visible on screen!
        //display.display();
        //delay(2000);
        // display.display() is NOT necessary after every single drawing command,
        // unless that's what you want...rather, you can batch up a bunch of
        // drawing operations and then update the screen all at once by calling
        // display.display(). 
        display.cp437(true);         // Use full 256 char 'Code Page 437' font
        display.setTextSize(1);             // Normal 1:1 pixel scale
        display.setTextColor(SSD1306_WHITE);        // Draw white text
        display.setCursor(27,2);             // Start at top-left corner
        display.println(F("G'day Mate!"));
        display.println();
        //display.setTextColor(SSD1306_BLACK, SSD1306_WHITE); // Draw 'inverse' text
        //display.println("3.141592");
        // display.println();
        display.setTextSize(1);             // Draw 2X-scale text
        display.setTextColor(SSD1306_WHITE);
        //display.print(F("0x")); display.println(0xDEADBEEF, HEX);
        display.print("Local Temp:      ");
        display.print(lroundtemp);
        display.write(248);//ascii code for a degree symbol
        display.println("F");
        display.print("Local Humidity:  ");
        display.print(lroundhumidity);
        display.write(37);//ascii code for percent sign
        display.println();
        display.println();
        display.print("Remote Temp:     ");
        display.print(rtemp);
        display.write(248);//ascii code for a degree symbol
        display.println("F");
        display.print("Remote Humidity: ");
        display.print(rhumidity);
        display.write(37);//ascii code for percent sign
        display.display();
        delay(5000);
        display.clearDisplay();
        display.display();
      }
      */
}
}    

@BitSeeker Thanks! I copied this code into Setup and it is not crashing anymore:

if (! aht.begin()) {
    Serial.println("Could not find AHT? Check wiring");
    while (1) delay(10);
  }
  Serial.println("AHT10 or AHT20 found");

Still not getting data from the AHT20, but now I can continue troubleshooting.
Still curious about my first question in post 1, but that can wait.
Thanks so much!

AHT20 is now giving me data, so the problem seems to be solved. Thanks to you guys!

I think that statement consumes memory every time through the loop, either make it global, or make it local static.

Now some SWAG. By NOT having the begin coded for the aht object, there was no memory management for the local declaration. The better way would be to code the declaration either global or, if local, then static, so it does not use more memory each pass through the loop.

You mean this question? It can't. However, Serial.println() takes some time to run and complete printing output to screen, but the function is designed to be "non-blocking", which means that the program can continue to run while Serial.println() is still doing its stuff. What is happening is that the program continues until it reaches the point where it crashes before Serial.println() has been able to send all characters in the serial buffer to the terminal. If you were to put Serial.flush() at the end of void setup(), you would probably see all of the Serial.println() lines in void setup() because this forces Serial.println() to complete its task to that point before executing further code.

@BitSeeker That is a great explanation and I'm much less confused now. I'm used to program debugging by putting in print statements. Now I know there's a caveat to that here. Thanks again!