Infineon / TLV493D-A1B6-3DMagnetic-Sensor

Library for the TLV493D-A1B6 3D magnetic sensor for Arduino.
Other
38 stars 26 forks source link

ADC hang up in Master Controlled or Fast Mode #25

Open Burke111-DEV opened 1 month ago

Burke111-DEV commented 1 month ago

Hello,

I'm constantly running up against the ADC hangup issue. I've tried a few ways to try and implement a general reset as suggested in section 5.61 of the User Manual, but nothing has worked for me yet.

Any advice on implementing the general reset?

Additionally,would you consider making it part of the library?

Thanks

julisNew commented 1 month ago

Hi, When hang up problem happened, please follow 5.6 Corrective action. And this issue only happen in 1st generation. You can use TLV493D-A2BW instead.

Burke111-DEV commented 1 month ago

@julisNew Thanks for your response.

Unfortunately, as the original post mentions, I've tried a few ways to try and implement a general reset as suggested in section 5.61 of the User Manual, but nothing has worked for me yet.

To be specific, here are two ways I've tried:

  1. Editing the Library to make the private reset() method public, and calling it within my code.

  2. With this method, which attempts to create the conditions described in section 5.6.1 of the user manual.

// Send general reset command to magnetometer. Intended to deal with the known lock-up issue. Doesn't work? void sendI2CReset() { delay(1000); Wire1.beginTransmission(0x00); // 0x00 is the general call address Wire1.write(0x00); // Sending 0x00 byte error = Wire1.endTransmission();

if (error == 0) { mag.end(); mag.begin(Wire1); mag.setAccessMode(mag.MASTERCONTROLLEDMODE); mag.disableTemp(); delay(50); Serial.println("General call sent successfully."); } else { Serial.print("Error sending general call: "); Serial.println(error); } }


In both cases, I get the same result.
Calling `Tlv493d.updateData()` returns the `TLV493D_FRAME_ERROR`

The only thing that actually "works" is using 
```cpp
watchdog_reboot(0,0,0);

To reboot the uC, which is problematic and not a realistic solution for my needs.

Regarding the suggestion to use the TLV493D-A2BW instead - in future projects, I will. Unfortunately for this project, it's not an option.


For some added context, I am using these two devices: rp2040 uC: https://www.adafruit.com/product/4900 TLV493D Board: https://www.adafruit.com/product/4366

9Volts9er commented 1 month ago

The easiest solution would be if you were able to control the VDD of the sensor with a pin from the uC. Then you could simply reset the sensor by pulling the VDD low, wait a bit, and setting it high again. But I guess this is not possible?

It's interesting that rebooting the uC works. Because if the VDD of the sensor is not controlled by the microcontroller, then rebooting the uC shouldn't change the hang-up state from the sensor. Except that when you reboot, the setup() is called again and within the mag.begin() . So that actually means, that calling the mag.begin() resets the sensor and recovers it from the hang-up. Have you tried to simply call the mag.begin() in your reset-function? So basically that your function would look like this:

void sendI2CReset() {
    mag.end(); //Not sure if this is necessary, you can try to outcomment it
    mag.begin(Wire1); //This function calls the internal (private) reset function of the library by default
    mag.setAccessMode(mag.MASTERCONTROLLEDMODE);
    mag.disableTemp();
    delay(50);
}
Burke111-DEV commented 1 month ago

@9Volts9er Thanks,

That was something I had tried before, without luck.

However, I may have found the missing factor. The lib contains this under Tlv493d::updateData(void)

// Todo: removed due to a lot of frame errors
//              // if received frame count does not match expected one (frame count from 0 to 3)
//              else if( getRegBits(tlv493d::R_FRAMECOUNTER) != (mExpectedFrameCount % 4) )
//              {
//                  ret = TLV493D_FRAME_ERROR;
//              }

Incomplete code for detecting framecount errors. In my earlier tests, I had not modified this section. In my later tests, I had uncommented this section.

The key is that the frame counter error can only be detected if the if statement is uncommented.

Fortunately, if this if condition is uncommented, then calling end and begin on the Tlv493d object does seem to allow recovery from the ADC hangup. 🎉🎉🎉

As a result, I think there is a solution that maintains current behaviour while also allowing users of the old sensor to recover from the hangup. A possible solution would be to introduce a new flag to the class to control whether the check on mExpectedFrameCount can set ret to TLV493D_FRAME_ERROR.

E.g., something like:

In the sketch:

void setup() {
  mag.begin(Wire1);
  mag.setAccessMode(mag.MASTERCONTROLLEDMODE);

  mag.setCheckFrameCountError(true); // Sets flag to true

  mag.disableTemp();
  calibrateSensor();
}

In the lib:

Tlv493d.h:

class Tlv493d
{
...
public:
...
    // read measurement results from sensor
    Tlv493d_Error_t updateData(void);
        void setCheckFrameCountError(bool state);    // Sets flag to state

...

private: 
    tlv493d::BusInterface_t mInterface;
    AccessMode_e mMode;
    int16_t mXdata;
    int16_t mYdata;
    int16_t mZdata;
    int16_t mTempdata;
    uint8_t mExpectedFrameCount;
    bool mCheckFrameCountError;    // Bool flag defaults to false

Tlv493d.cpp:

...
                // Todo: removed due to a lot of frame errors
                // if received frame count does not match expected one (frame count from 0 to 3)
                else if(mCheckFrameCountError && getRegBits(tlv493d::R_FRAMECOUNTER) != (mExpectedFrameCount % 4) )
                {
                    ret = TLV493D_FRAME_ERROR;
                }
            }
        }
    }
    mExpectedFrameCount = getRegBits(tlv493d::R_FRAMECOUNTER) + 1;
    return ret;
}

void Tlv493d::setCheckFrameCountError(bool state)
{
    mCheckFrameCountError = state;
}
...

Please let me know your thoughts, then I'll make a branch :)