Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TLV493d - ADC hang up in Master Controlled or Fast Mode #21

Open
Burke111-DEV opened this issue May 21, 2024 · 8 comments
Open

TLV493d - ADC hang up in Master Controlled or Fast Mode #21

Burke111-DEV opened this issue May 21, 2024 · 8 comments

Comments

@Burke111-DEV
Copy link

How are you guys getting around the ADC hangup issue for the magnetometer?

I'm constantly getting lockups making it unusable.

@geroulas
Copy link

Same here.. works for a few minutes, then stops. Any suggestions?

@geroulas
Copy link

geroulas commented May 22, 2024

@Burke111-DEV This code (https://github.com/Launcherspider/3D-Spacemouse) worked for me on Windows.. No hangups.
Still this projects feels a bit unusable, there is no smooth motion, no zoom..
It's a cool project but that's all, you cant work with this spacemouse.

@Burke111-DEV
Copy link
Author

@geroulas Thanks for sharing that project.
Unfortunately, that project just reposted precisely the same arduino sketch file that Salim created.
Any performance improvements are likely purely coincidental.
The hangup issue is unpredictably intermittent, so it may just be that you haven't experienced it yet...
My device sometimes lasts over an hour without issue, sometimes not even 10s. It's completely random.

I've made a lot of changes to Salim's original diy-spacemouse.ino file.
Key features I've added are

  • Switchable 3D/2D mouse modes
  • Unique sensitivities depending on the mode.
  • Dynamic speed based on how far you push the knob.
    • Uses logarithmic function which you can adjust the curve using two variables. (One for max, other for sensitivity)
  • A scroll wheel for scrolling (zoom in Fusion)

I'm quite happy with how it has turned out, and sounds like you might be interested in these features.

But I don't want to release my project details and files until I've got a solution to the intermittent hangup issue,,


For awareness, this is definitely a bug in the magnetometer, and not a quirk in the code.
See:

Additionally, the datasheet even mentions that it is a known issue, and comments in the official Infineon library for this sensor make reference to it.

Supposedly, the fix is to try to "reset" the device. But none of my attempts to do so have been successful. Was hoping someone might know something.

@geroulas
Copy link

@Burke111-DEV woww man.. I was sure that was a different code.. but you are right! I was comparing it to the code I was running and I have altered some things compared to the original. I've been running it all moring without issues. Now that i got back from work, it hangs if I leave it alone for some minutes.. I also noticed that it wont work If Serial Monitor is not open. Íf I plug in the device, it will run for a few seconds then stops, if I open Arduino and Serial Monitor it stars working again. I close serial monitor and stops working. Maybe I've done something wrong, or maybe that helps you in some way...

In my case, I use the Waveshare RP2040-Zero, and in order to make it work I changes this
Wire.begin(); mag.begin(Wire);
Wire1 didn't work for me.

I will follow your links and try the reset method, see if I come up with something. I'm not really familiar with Arduino projects, but I will experiment.

I would love to see your project when you decide to release it! It will give life to this device for sure!

@Burke111-DEV
Copy link
Author

Burke111-DEV commented May 23, 2024

@geroulas
Regarding your issues with Wire vs Wire1:

Salim uses the Adafruit QT PY RP2040 in the original design. In particular, it is good for this project because it has the STEMMA connector which makes connecting up to the Adafruit TLV493d magnetometer module much simpler.
It's not that either of those two are required, just that they're a good match for ease of use (i.e., no need to solder the I2C pins).
So you're free to use any board, just you may need to do some more soldering.

The Adafruit QT PY RP2040 has two I2C interfaces - i2c0 and i2c1. Both are usable, just two separate busses.
To communicate on i2c0 your code should use Wire. To communicate on i2c1 your code should use Wire1.

So presumably, the I2C bus you wired your magnetometer to on your RP2040uC board is the i2c0 one, so you need Wire instead of Wire1 :)


If I can't find a solution to the intermittent issue soon, I'll likely just publish the details of my project anyway and hope someone sees it and can help solve the I2C lockup on there.

@geroulas
Copy link

geroulas commented May 23, 2024

@Burke111-DEV Thanks for the input, I did read about all these, and now i'm in a good place now.

I think I have a something that might be working. I'm trying to re-initialize the sensor when it hangs.

I've added a code that compares the last values of the sensor with the previous ones. If xCurrent, yCurrent & zCurrent are exactly the same with xLast, yLast, zLast that must mean the sensor hang and reports the same values again and again.
It did work some times, I saw the code reporting back.

I've also remapped the two buttons. One button is jsut running the code to initialise the sensor. So when I see the knob not responding, I press the button and it's live again.

I read somewhere that by sending a 0x00 singal to the I2C it resets the sensor, so that's what i did here. I think it might be working even wihtout this and you just have initialize....

Also the entire code is doing Keyboard.press() and Keyboard.release all the time, I thinks that's bad for the controller. So I changed that part as well and I think it helps. Especially the shift key was not behaving well. The program was freezing and the Shift button was still pressed. For now I have it running only in Orbit mode (Fusion360).. just to see how it behaves.

Check the code, see if you can replicate this.

#include <TinyUSB_Mouse_and_Keyboard.h>
#include <OneButton.h>
#include <Tlv493d.h>
#include <SimpleKalmanFilter.h>
#include <Wire.h>


Tlv493d mag = Tlv493d();
SimpleKalmanFilter xFilter(1, 1, 0.2), yFilter(1, 1, 0.2), zFilter(1, 1, 0.2);

// Setup buttons
OneButton button1(26, true);
OneButton button2(27, true);

float xOffset = 0, yOffset = 0, zOffset = 0;
float xCurrent = 0, yCurrent = 0, zCurrent = 0;
float xLast = 0, yLast = 0, zLast = 0;
int unchangedCount = 0;
const int maxUnchangedCount = 100;

int calSamples = 500;
int sensivity = 30;
int magRange = 3;
int outRange = 127;      // 127 Max allowed in HID report
float xyThreshold = 0.4; // Center threshold

int inRange = magRange * sensivity;
float zThreshold = 3;

bool isOrbit = false;

void setup()
{

  button1.attachClick(leftButton);
  button1.attachLongPressStop(leftButton);

  button2.attachClick(rightButton);
  button2.attachLongPressStop(rightButton);

  // mouse and keyboard init
  Mouse.begin();
  Keyboard.begin();

  Serial.begin(9600);
  Wire.begin();

  // mag sensor init
  mag.begin(Wire);
  mag.setAccessMode(mag.MASTERCONTROLLEDMODE);
  mag.disableTemp();

  // crude offset calibration on first boot
  for (int i = 1; i <= calSamples; i++)
  {

    delay(mag.getMeasurementDelay());
    mag.updateData();

    xOffset += mag.getX();
    yOffset += mag.getY();
    zOffset += mag.getZ();

    //Serial.print(".");
  }

  xOffset = xOffset / calSamples;
  yOffset = yOffset / calSamples;
  zOffset = zOffset / calSamples;

  xCurrent = xFilter.updateEstimate(mag.getX() - xOffset);
  yCurrent = yFilter.updateEstimate(mag.getY() - yOffset);
  zCurrent = zFilter.updateEstimate(mag.getZ() - zOffset);

  //Serial.println();
  Serial.println(xOffset);
  Serial.println(yOffset);
  Serial.println(zOffset);
}

void loop()
{

  // keep watching the push buttons
  button1.tick();
  button2.tick();

  xLast = mag.getX();
  yLast = mag.getY();
  zLast = mag.getZ();

  // get the mag data
  delay(mag.getMeasurementDelay());
  mag.updateData();

  // update the filters
  xCurrent = xFilter.updateEstimate(mag.getX() - xOffset);
  yCurrent = yFilter.updateEstimate(mag.getY() - yOffset);
  zCurrent = zFilter.updateEstimate(mag.getZ() - zOffset);

  //mReset I2C if Sensor Hangs
  //Compare current Mag values with previous values
  if(xLast == mag.getX() && yLast == mag.getY() && zLast == mag.getZ())
  {
    unchangedCount++;
  }
  else
  {
    unchangedCount = 0;
  }

  if (unchangedCount >= maxUnchangedCount)
  {
    Serial.println();
    Serial.print("RESETING");
    
    Mouse.release(MOUSE_MIDDLE);
    Keyboard.releaseAll();

    Mouse.begin();
    Keyboard.begin();

    Wire.beginTransmission(0x00);
    Wire.write(0x00);
    Wire.endTransmission();
    delay(1000);
    Wire.begin();
    mag.begin(Wire);
    mag.setAccessMode(mag.MASTERCONTROLLEDMODE);
    mag.disableTemp();

    Serial.println();
    Serial.print("RESET DONE");
  }

  // check the center threshold
  if (abs(xCurrent) > xyThreshold || abs(yCurrent) > xyThreshold)
  {
    int xMove = 0;
    int yMove = 0;

    // map the magnetometer xy to the allowed 127 range in HID repports
    xMove = map(xCurrent, -inRange, inRange, -outRange, outRange);
    yMove = map(yCurrent, -inRange, inRange, -outRange, outRange);

    // press shift to orbit in Fusion 360 if the pan threshold is not corssed (zAxis)
    
    /*
    if (abs(zCurrent) < zThreshold && !isOrbit)
    {
      Keyboard.press(KEY_LEFT_SHIFT);
      isOrbit = true;
    }
    */

    // pan or orbit by holding the middle mouse button and moving propotionaly to the xy axis
    if (!Mouse.isPressed(MOUSE_MIDDLE))
    {
      Keyboard.press(KEY_LEFT_SHIFT);
      Mouse.press(MOUSE_MIDDLE);
      Serial.println();
      Serial.print("Mouse_Middle PRESSED");
    }
    
    Mouse.move(yMove, xMove, 0);
  }
  else
  {
    if (Mouse.isPressed(MOUSE_MIDDLE))
    {
      Mouse.release(MOUSE_MIDDLE);
      Keyboard.releaseAll();
      Serial.println();
      Serial.print("Mouse_Middle RELEASED");
    }
  }

  Serial.println();
  Serial.print(mag.getX());
  Serial.print(",");
  Serial.print(mag.getY());
  Serial.print(",");
  Serial.print(mag.getZ());
}

// go to home view in Fusion 360 by pressing  (CMD + SHIFT + H) shortcut assigned to the custom Add-in command
void leftButton()
{
  Mouse.press(MOUSE_MIDDLE);
  Mouse.release(MOUSE_MIDDLE);
  Mouse.press(MOUSE_MIDDLE);
  Mouse.release(MOUSE_MIDDLE);
}

// fit to view by pressing the middle mouse button twice
void rightButton()
{
  Serial.println();
  Serial.print("RESETING");

  Mouse.release(MOUSE_MIDDLE);
  Keyboard.releaseAll();

  Mouse.begin();
  Keyboard.begin();

  Wire.beginTransmission(0x00);
  Wire.write(0x00);
  Wire.endTransmission();
  delay(1000);
  Wire.begin();
  mag.begin(Wire);
  mag.setAccessMode(mag.MASTERCONTROLLEDMODE);
  mag.disableTemp();

  Serial.println();
  Serial.print("RESET DONE");
}

EDIT: I Changed to code to compare Last Values but over a period of iterations maxUnchangedCount=100. So If the sensor report the exact same values for 100 times it will reset.

@Burke111-DEV
Copy link
Author

@geroulas
Not sure if that would work, but the general idea isn't wrong.
Interested to know if it worked for you.

On my end, I think I may have solved it.
It requires a change to the code inside the Tlv493d library files.
I just put up a comment explaining it under an issue I made on the Infineon project's repo:
Infineon/TLV493D-A1B6-3DMagnetic-Sensor#25

Due to the completely random occurence of the bug, it's difficult to say with 100% certIainty that this is a definite fix.
But I have used my sensor for extended periods of time (4+ hrs) without issue for over a week now.

So I will post my code and 3D files when my free time permits :)

@Burke111-DEV
Copy link
Author

@geroulas

I made a fork of Infineon's lirbary, adding the required fix to get it working.
https://github.com/Burke111-DEV/TLV493D-3DMagnetic-Sensor-With-Hangup-Recovery

Also find a basic usage example on the readme.
Hope this helps :)

I'll also put the rest of my project code and files up when I get a chance to organise it.
For now, swapping infineon's ltlv493d library for mine should be enough to fix @sb-ocr 's code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants