SparkFun_MLX90640_Arduino_Example icon indicating copy to clipboard operation
SparkFun_MLX90640_Arduino_Example copied to clipboard

Modifications to work with the ESP32

Open PeterAJansen opened this issue 6 years ago • 18 comments

Thanks for creating this!

Here are a few issues and fixes I noted when getting this to compile for the ESP32 (Arduino IDE 1.8.5), in case anyone else attempts the same:

  1. MLX90640_I2C_Driver.cpp: Add #include<Arduino.h> at the top, or it will throw errors on Serial() for the debug print statements. (Alternatively, these can be commented out).

  2. Setup() functions of example code: Wire.setClock(400000): This seems to make communication unreliable, possibly due to some potential issues with the ESP32 Arduino I2C library itself (I noted some issues mentioned on github, but didn't dig too deep). Commenting this out so that it uses the default 100khz speed seems to get it working. A speed of 200Khz also seems to work some of the time.

  3. I2C reliability: Sometimes it gives a 'failure to find the MLX90640 at the default I2C address' error, and sometimes it doesn't -- when this happens, resetting the ESP32 (using the reset button) seems to get things working after some number of resets. I still haven't figured this one out yet.

PeterAJansen avatar Jun 23 '18 07:06 PeterAJansen

Oh, also! 4. The sensor is physically rotated on the SparkX breakout board, so all the pictures that come off it are rotated if it's mounted as-is. That one took me a while to figure out. Turns out my monitor isn't making the air beside it glow with heat (phew).

PeterAJansen avatar Jun 23 '18 07:06 PeterAJansen

@PeterAJansen thanks for the info! I had a question about what version of the arduino-esp32 toolkit you're using and what method you used to install it? I wasn't able to get this to work properly with an esp32, but swapping my project with an esp8266 worked ok.

I was wondering if I just maybe have an incorrect version or some other toolchain issue.

nburnett avatar Aug 08 '18 06:08 nburnett

For anyone that runs into trouble with this sensor and the ESP32, I found right now the ESP32 Arduino I2C core has some issues with timing sensitive sensors. However I did get it to work and read pixel data from this MLX90640 sensor using the fork of the ESP32 Arduino core here: https://github.com/stickbreaker/arduino-esp32 There's a ton of background info in the thread here on what this fork does and why it's necessary: https://github.com/espressif/arduino-esp32/issues/811 The root issue is that calling Wire.endTransmission(false) and then Wire.read() is far too slow and throws off the I2C system on the ESP32. The fork adds a new Wire.transact call that does all this at once and keeps the I2C system working, among other things.

So to work with the ESP32 and this really slick sensor replace your ESP32 Arduino core with the fork mentioned above. Then modify your sketch's MLX90650_I2C_Driver.cpp's MLX90650_I2CRead function to look like (notice the commented out endTransmission and replacement with the new transact call):

//Read a number of words from startAddress. Store into Data array.
//Returns 0 if successful, -1 if error
int MLX90640_I2CRead(uint8_t _deviceAddress, unsigned int startAddress, unsigned int nWordsRead, uint16_t *data)
{

  //Caller passes number of 'unsigned ints to read', increase this to 'bytes to read'
  uint16_t bytesRemaining = nWordsRead * 2;

  //It doesn't look like sequential read works. Do we need to re-issue the address command each time?

  uint16_t dataSpot = 0; //Start at beginning of array

  //Setup a series of chunked I2C_BUFFER_LENGTH byte reads
  while (bytesRemaining > 0)
  {
    Wire.beginTransmission(_deviceAddress);
    Wire.write(startAddress >> 8); //MSB
    Wire.write(startAddress & 0xFF); //LSB
    // Don't use the following code on ESP32, currently its Arduino I2C core is broken for this usage:
    //if (Wire.endTransmission(false) != 0) //Do not release bus
    //{
    //  Serial.println("No ack read");
    //  return (0); //Sensor did not ACK
    //}
    // Instead use the Wire.transact further below.

    uint16_t numberOfBytesToRead = bytesRemaining;
    if (numberOfBytesToRead > I2C_BUFFER_LENGTH) numberOfBytesToRead = I2C_BUFFER_LENGTH;
    
    // Make a new buffer to hold the Wire.transact result.
    uint8_t _transact_buffer[I2C_BUFFER_LENGTH];
    int err = Wire.transact(_transact_buffer, numberOfBytesToRead);
    if (err != numberOfBytesToRead) {
      Serial.print("Failed to read expected I2C bytes!");
      return (0);
    }

    // Now copy the transaction data out of the buffer and into the result.
    for (uint16_t x = 0 ; x < numberOfBytesToRead; x += 2)
    {
      //Store data into array
      data[dataSpot] = _transact_buffer[x] << 8; //MSB
      data[dataSpot] |= _transact_buffer[x+1]; //LSB
      dataSpot++;
    }
    
    bytesRemaining -= numberOfBytesToRead;

    startAddress += numberOfBytesToRead / 2;
  }

  return (0); //Success
}

With this I'm getting great data from this (very cool) sensor on an ESP32 (the M5Stack system, a ESP32 + case + ILI9341 TFT... perfect platform for a little IR sensor camera). Here's an example of the basic test sketch output:

MLX90640 IR Array Example
MLX90640 online!
Pixel 0: 20.35C
Pixel 1: 20.68C
Pixel 2: 21.12C
Pixel 3: 21.31C
Pixel 4: 20.87C
Pixel 5: 20.62C
Pixel 6: 21.28C
Pixel 7: 21.41C
Pixel 8: 21.33C
Pixel 9: 21.38C

Hopefully this helps someone else! And hopefully at some point the ESP32 Arduino core matures so that the I2C bus works well without the need for the fork and transact changes.

tdicola avatar Oct 13 '18 19:10 tdicola

Thank you for this! I have a project that has five I2C peripherals and three of them don't work on with the current espressif32 platform (or any of the older ones), what a bummer. Hopefully, this gets worked out soon as I2S is such an important protocol in many hardware products.

ThingEngineer avatar Oct 20 '18 00:10 ThingEngineer

Very useful! Using ESP32 fork referenced above with "transact" and I2C driver.cpp mods to the MLX90640 works for me on ESP32 but still get no ack serial message from the 2nd wire.begin in the original .cpp code which is not mentioned, so I left unchanged? Is there a complete working code example for the Sparkfun MLX read example somewhere for newbies?
I assume you have run one the basic Sparkfun example since the other "maxrefresh" one seems to need a faster I2C clock than 100kHz to try higher speed reading, like 1MHz clock suggested on the Teensy? For info I have tried the MLX90640 read on ESP8266-12 and Teensy 3.6, the Teensy failed for me; it did not go beyond the parameter extraction error referenced, the 8266 gave the same error but continued to read though the corner pixels in the data were weird numbers, like 10C warmer. Again not seen any working code examples. I did also just try the ESP32 at 400kHz clock and max refresh example my best rate seems a stable 4Hz read rate, anyone got faster reads?

Is this nicely working fork likely to be merged with the regular code as mentioned in Nov. 2017?

Melmac2 avatar Dec 10 '18 17:12 Melmac2

so this project can work with nodemcu ?

thresholdout avatar Dec 18 '18 08:12 thresholdout

Nodemcu is ESP8266 is ESP-12 not -32 so not quite the same topic? My experience with Wemos D1 mini ESP-12 (above) was not the best; it sorta worked. Others who created this thread might advise whether these I2C mods would help; the MLX read seems generally tricky with I2C reads.

Melmac2 avatar Dec 19 '18 17:12 Melmac2

@Melmac2 This is updated code for V1.0.1 of the Arduion-Esp32, my fork (stickbreaker/arduino-esp32) is outdated, and will be updated to follow the main repo.


int MLX90640_I2CRead(uint8_t _deviceAddress, unsigned int startAddress, unsigned int nWordsRead, uint16_t *data)
{
	// nWordsRead must be <= 32767
    Wire.beginTransmission(_deviceAddress);
    Wire.write(startAddress >> 8); //MSB
    Wire.write(startAddress & 0xFF); //LSB
    Wire.endTransmission(false);
    i2c_err_t error = Wire.readTransmission(_deviceAddress, (uint8_t*) data, nWordsRead*2);
    if(error != 0){//problems
        Serial.printf("Block read from sensor(0x%02X) at address=%d of %d uint16_t's failed=%d(%s)\n",
	      _deviceAddress,startAddress,nWordsRead,error,Wire.getErrorText(error));
    }
    else { // reverse byte order, sensor Big Endian, ESP32 Little Endian
        for(auto a = 0; a<nWordsRead; a++){
            data[a] = ((data[a] & 0xff)<<8) | (( data[a]>>8)&0xff);
        }
    }
    return 0;
}

Chuck.

stickbreaker avatar Feb 04 '19 21:02 stickbreaker

Does there modifications still work or is there better way to get this working by now?

I have tried to make this to work for 4 weeks now without luck. I have two different GY-MCU90640 modules for the sensor,55 FOV and 110FOV. I have tried 3 different ESP32 boards(lOLIN32,ESP-32S and bare ESP32 module) . Arduino IDE is version 1.8.10 I have tried this with and without these modifications and with official and with stickbreaker core. The nearest working condition is output to the serial from the BasicReadings sketch :


MLX90640 IR Array Example MLX90640 online! Parameter extraction failed Pixel 0: 2895.16C Pixel 1: 2571.75C Pixel 2: nanC Pixel 3: 2319.59C Pixel 4: nanC Pixel 5: nanC Pixel 6: 2646.03C Pixel 7: 2614.28C Pixel 8: 1277.65C Pixel 9: 2614.38C


But these might be nonsese after all. I would like if winter in Finland was that hot, but no.
every else sketch results in Error -8. I can use an i2c scanning sketch and can see a device at 0x33. The jamesdanielv's Arduino code can read the calibration data from the sensor, but does not show any results in any other sketch. So the I2C transfer should be working? Are some of these sensors defective? I have seen multiple cases where sensor just refuses to work.

PPiirainen avatar Nov 22 '19 20:11 PPiirainen

I think your readings are that high because Finland is either in hell or you're on way there for taking pictures in the sauna:)

I got two sensors working well on basic ESP32 dev modules about 10 months ago, one Sparkfun board, one raw sensor.Neither defective. Are you using 3.3V; GY modules don't seem to have the RC circuitry of Sparkfun or mfr? Mine failed on the parameter extraction step until made the Stickbreaker I2C code mods. Is it possible later versions of Arduino or ESP32 library don't have the same code (left stranded?) and maybe ;you have to go back to earlier versions to work?

Notice more recent tutorials and other comments such as: https://www.instructables.com/id/Infrared-Thermal-Imaging-Camera-With-MLX90640-and-/

And M5stick module/code.

Hopefully useful Mel

On Fri, Nov 22, 2019 at 3:33 PM Perttu Piirainen [email protected] wrote:

Does there modifications still work or is there better way to get this working by now?

I have tried to make this to work for 4 weeks now without luck. I have two different GY-MCU90640 modules for the sensor,55 FOV and 110FOV. I have tried 3 different ESP32 boards(lOLIN32,ESP-32S and bare ESP32 module) . Arduino IDE is version 1.8.10 I have tried this with and without these modifications and with official and with stickbreaker core. The nearest working condition is output to the serial from the BasicReadings sketch :

MLX90640 IR Array Example MLX90640 online! Parameter extraction failed Pixel 0: 2895.16C Pixel 1: 2571.75C Pixel 2: nanC Pixel 3: 2319.59C Pixel 4: nanC Pixel 5: nanC Pixel 6: 2646.03C Pixel 7: 2614.28C Pixel 8: 1277.65C Pixel 9: 2614.38C

But these might be nonsese after all. I would like if winter in Finland was that hot, but no. every else sketch results in Error -8. I can use an i2c scanning sketch and can see a device at 0x33. The jamesdanielv's Arduino code can read the calibration data from the sensor, but does not show any results in any other sketch. So the I2C transfer should be working? Are some of these sensors defective? I have seen multiple cases where sensor just refuses to work.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/sparkfun/SparkFun_MLX90640_Arduino_Example/issues/2?email_source=notifications&email_token=AK4UD7UYSQ2UA4Q4IG5ZCW3QVA63NA5CNFSM4FGSXVM2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEE6ZK6Y#issuecomment-557684091, or unsubscribe https://github.com/notifications/unsubscribe-auth/AK4UD7UVTX4RR5FC7NNX6BLQVA63NANCNFSM4FGSXVMQ .

Melmac2 avatar Nov 23 '19 00:11 Melmac2

@PPiirainen ,@melmac2 my personal branch stickbreaker/arduino-esp32 is moribund. All of its functionality has been incorporated into the main espressif/arduino-esp32 since version 1.0.1.

Included in the low level Hardware Abstraction Layer is a comprehensive suite of debugging code. This debugging code is documented in the Wire() library here. If you enable these compile time defines, the Serial log will list complete i2c flow failures.

I am willing to help you diagnose the actual faults.

Chuck.

stickbreaker avatar Nov 23 '19 03:11 stickbreaker

Thank you for your fast response and generous ansvers!

@Melmac2

"GY modules don't seem to have the RC circuitry of Sparkfun or mfr?

I have no idea about this. I basically do exactly as in the stoppi71 Instructables says. I have the exact same parts as he does, in the same configuration.

Mine failed on the parameter extraction step until made the Stickbreaker I2C code mods. Is it possible later versions of Arduino or ESP32 library don't have the same code (left stranded?) and maybe ;you have to go back to earlier versions to work?

I tried to install esp32 board package from 1.0.0 to 1.0.4 from the Boards manager and by git install. None of these worked. I also tried make the modifications suggesed by @tdicola. The normal libary did not compile, and with the @stickbreaker branch, the problem remains the same. I got my hands on a logic analyser and checked the I2C line. In the I2C address checker I can see the ACK bit working correctly. espi2cscannerresulACK In the Basic_readings and the program from the instructables the I2C seems to try something first and always get to a point where after h10 there would be NAK and after the signal gets into a loop. (and also every time I saw h10 there would be NAK and re-start) in the loop the signal is repeating the last bit. basicreadingsH10NAK In oscilloscope my attention caught the two extremely narrow lines in the signal line that seems out of place.
scope1

@ stickbreaker Included in the low level Hardware Abstraction Layer is a comprehensive suite of debugging code. This debugging code is documented in the Wire() library here. If you enable these compile time defines, the Serial log will list complete i2c flow failures.

This went high-level in a hurry :o I enabled the debug buffer and set the core debug level to verbose. but didn't have time to dig deeper. The documentation seems intimidating and i probably need some direct examples of this code and work to get this working.

PPiirainen avatar Nov 27 '19 12:11 PPiirainen

The narrow pulses could just be the ACK hand over between the master and slave. You will have to match the spike on SDA to the Clock on SCL if the spike happens after the SCL goes low at the start of the ACK bit period, you are just seeing the hand over. If the Master is sending data (Write) it has to release drive of SDA after the 8th data bit cycle has completed (SCL goes Low), then the Slave waits a few micro seconds after it sees SCL Low then it starts driving SDA Low to form the ACK bit. Between the Master Releasing SDA and the Slave starting to drive SDA for the ACK you may see this spike. It is norrmal.

The spike only appears if the 8th bit is Low.

Chuck.

stickbreaker avatar Nov 27 '19 16:11 stickbreaker

@PPiirainen You are going to need to debug the failing transaction. I would connect 4 channels to the ESP32 SDA,SCL, and two debug pins, lets call them TransStart and Error. In your code I would toggle TransStart evertime you do a sample capture, then if you detect an error trigger Error. Look for the Error pulse in your logic analyzer capture then backup until you see the TransStart pulse decode the I2C data between the markers. That would be a good starting place.

SparkFun Sells a simple USB 25Mhz 8 channel Logic Analyzer cheap, you can also get copies from Ali/Banggood. It is well worth the $20.

Chuck.

stickbreaker avatar Nov 27 '19 16:11 stickbreaker

Hi . For I2c to work you need the pull-up resistors on the data lines, and supply line caps of the MLX datasheet application, or as per Sparkfun board schematic. Should be able to tell visually if they are on your board I expect?

Good luck Mel

On Wed, Nov 27, 2019 at 7:45 AM Perttu Piirainen [email protected] wrote:

Thank you for your fast response and generous ansvers!

@Melmac2 https://github.com/Melmac2

"GY modules don't seem to have the RC circuitry of Sparkfun or mfr?

I have no idea about this. I basically do exactly as in the stoppi71 Instructables says. I have the exact same parts as he does, in the same configuration.

Mine failed on the parameter extraction step until made the Stickbreaker I2C code mods. Is it possible later versions of Arduino or ESP32 library don't have the same code (left stranded?) and maybe ;you have to go back to earlier versions to work?

I tried to install esp32 board package from 1.0.0 to 1.0.4 from the Boards manager and by git install. None of these worked. I also tried make the modifications suggesed by @tdicola https://github.com/tdicola. The normal libary did not compile, and with the @stickbreaker https://github.com/stickbreaker branch, the problem remains the same. I got my hands on a logic analyser and checked the I2C line. In the I2C address checker I can see the ACK bit working correctly. [image: espi2cscannerresulACK] https://user-images.githubusercontent.com/35927392/69722866-d34ebd80-1120-11ea-9d30-c54ba890629d.jpg In the Basic_readings and the program from the instructables the I2C seems to try something first and always get to a point where after h10 there would be NAK and after the signal gets into a loop. (and also every time I saw h10 there would be NAK and re-start) in the loop the signal is repeating the last bit. [image: basicreadingsH10NAK] https://user-images.githubusercontent.com/35927392/69723633-bc10cf80-1122-11ea-9855-d00431757787.jpg In oscilloscope my attention caught the two extremely narrow lines in the signal line that seems out of place. [image: scope1] https://user-images.githubusercontent.com/35927392/69723418-26754000-1122-11ea-8866-88be1dd7aa5d.jpg

@ stickbreaker Included in the low level Hardware Abstraction Layer is a comprehensive suite of debugging code. This debugging code is documented in the Wire() library here. If you enable these compile time defines, the Serial log will list complete i2c flow failures.

This went high-level in a hurry :o I enabled the debug buffer and set the core debug level to verbose. but didn't have time to dig deeper. The documentation seems intimidating and i probably need some direct examples of this code and work to get this working.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/sparkfun/SparkFun_MLX90640_Arduino_Example/issues/2?email_source=notifications&email_token=AK4UD7WLDPUMBJEWN6STPGDQVZTVPA5CNFSM4FGSXVM2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEFJMMCI#issuecomment-559072777, or unsubscribe https://github.com/notifications/unsubscribe-auth/AK4UD7RF4SQHLFHOD5H5PZTQVZTVPANCNFSM4FGSXVMQ .

Melmac2 avatar Nov 28 '19 00:11 Melmac2

hi,

i tried with the latest Arduino 1.8.15, and the stickbreaker fork (from 2018?), and seems not working on ESP32. Compiling with wire.transact is ok (means the fork was installed successfully).

The ESP32 keep on rebooting after uploading the code.

Anyone know how to solve this?

calvfoo avatar Aug 28 '21 12:08 calvfoo

error msg

20:36:20.182 -> Rebooting... 20:36:20.182 -> ets Jun 8 2016 00:22:57 20:36:20.182 -> 20:36:20.182 -> rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) 20:36:20.229 -> configsip: 0, SPIWP:0xee 20:36:20.229 -> clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 20:36:20.229 -> mode:DIO, clock div:1 20:36:20.229 -> load:0x3fff0018,len:4 20:36:20.229 -> load:0x3fff001c,len:956 20:36:20.229 -> load:0x40078000,len:0 20:36:20.229 -> load:0x40078000,len:13076 20:36:20.229 -> entry 0x40078a58 20:36:20.323 -> assertion "false && "item should have been present in cache"" failed: file "/Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/nvs_flash/src/nvs_item_hash_list.cpp", line 85, function: void nvs::HashList::erase(size_t) 20:36:20.323 -> abort() was called at PC 0x400d43c3 on core 0 20:36:20.323 -> 20:36:20.323 -> Backtrace: 0x400881c0:0x3ffc9ca0 0x400882bf:0x3ffc9cc0 0x400d43c3:0x3ffc9ce0 0x400d69e4:0x3ffc9d10 0x400d6d52:0x3ffc9d30 0x400d7081:0x3ffc9d80 0x400d67f8:0x3ffc9de0 0x400d663a:0x3ffc9e30 0x400d66d3:0x3ffc9e50 0x400d671e:0x3ffc9e70 0x400d2cf8:0x3ffc9e90 0x400e6d4f:0x3ffc9eb0 0x400d528e:0x3ffc9ee0 20:36:20.370 -> 20:36:20.370 -> Rebooting... 20:36:20.370 -> ets Jun 8 2016 00:22:57 20:36:20.370 -> 20:36:20.370 -> rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) 20:36:20.370 -> configsip: 0, SPIWP:0xee 20:36:20.370 -> clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 20:36:20.370 -> mode:DIO, clock div:1 20:36:20.370 -> load:0x3fff0018,len:4 20:36:20.370 -> load:0x3fff001c,len:956 20:36:20.370 -> load:0x40078000,len:0 20:36:20.370 -> load:0x40078000,len:13076 20:36:20.417 -> entry 0x40078a58 20:36:20.464 -> assertion "false && "item should have been present in cache"" failed: file "/Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/nvs_flash/src/nvs_item_hash_list.cpp", line 85, function: void nvs::HashList::erase(size_t) 20:36:20.510 -> abort() was called at PC 0x400d43c3 on core 0 20:36:20.510 -> 20:36:20.510 -> Backtrace: 0x400881c0:0x3ffc9ca0 0x400882bf:0x3ffc9cc0 0x400d43c3:0x3ffc9ce0 0x400d69e4:0x3ffc9d10 0x400d6d52:0x3ffc9d30 0x400d7081:0x3ffc9d80 0x400d67f8:0x3ffc9de0 0x400d663a:0x3ffc9e30 0x400d66d3:0x3ffc9e50 0x400d671e:0x3ffc9e70 0x400d2cf8:0x3ffc9e90 0x400e6d4f:0x3ffc9eb0 0x400d528e:0x3ffc9ee0 20:36:20.557 ->

calvfoo avatar Aug 28 '21 12:08 calvfoo

ok, got it working with codes from here https://github.com/Samox1/ESP_Thermal_Camera_WebServer

use Arduino IDE standard ESP32 board

bought a simple MLX90640 board from Aliexpress

calvfoo avatar Aug 29 '21 11:08 calvfoo