​ ​ ​ ​ TLV493D-A1B6 3D Magnetic Sensor
Page 1 of 6 1 2 3 ... LastLast
Results 1 to 10 of 58

Thread: TLV493D-A1B6 3D Magnetic Sensor

  1. #1
    Senior Member
    Join Date
    Apr 2012
    Location
    Cēsis, Latvia
    Posts
    855

    Default TLV493D-A1B6 3D Magnetic Sensor

    Dear all,

    Season's greetings to all!

    I'm back with another interesting device, TLV493D-A1B6 3D Magnetic Sensor from Infineon. There would be several possible applications for this kind of device in my models - from linear position indicators to smallest servos seen so far if it works the way it looks/sounds from the data sheet. I have spent a couple of hours on this thing now and as it does happen to me with I2C devices, I just cannot get it to work. The code I have is dead simple and the device seems to acknowledge its address if I read the scope thingy correctly, but then I get only 255s for the data. Any ideas?

    Code:
    #picaxe 40x2
    
    #no_data
    #no_table
    
    Symbol Bx = b4
    Symbol By = b5
    Symbol Bz = b6
    Symbol Temp = b7
    
    Symbol SDApin = C.3
    Symbol SCLpin = C.4
    
    Symbol TLV493DA1B6 = %10111100
    
    init:
      hi2csetup i2cmaster, TLV493DA1B6, i2cslow, i2cbyte
      pause 100
      hi2cout (%00000000,%00000101)  'to exit power-down mode
      pause 100
    
    main:
      do
        hi2cin (Bx,By,Bz,Temp)
        debug Temp
        pause 1000
      loop
    The data sheet for the device is available here.


    Thank you for your input,

    Edmunds

  2. #2
    Senior Member
    Join Date
    Aug 2011
    Location
    US
    Posts
    521

    Default

    Quote Originally Posted by edmunds View Post
    Dear all,

    Season's greetings to all!

    I'm back with another interesting device, TLV493D-A1B6 3D Magnetic Sensor from Infineon. There would be several possible applications for this kind of device in my models - from linear position indicators to smallest servos seen so far if it works the way it looks/sounds from the data sheet. I have spent a couple of hours on this thing now and as it does happen to me with I2C devices, I just cannot get it to work. The code I have is dead simple and the device seems to acknowledge its address if I read the scope thingy correctly, but then I get only 255s for the data. Any ideas?

    Code:
    #picaxe 40x2
    
    #no_data
    #no_table
    
    Symbol Bx = b4
    Symbol By = b5
    Symbol Bz = b6
    Symbol Temp = b7
    
    Symbol SDApin = C.3
    Symbol SCLpin = C.4
    
    Symbol TLV493DA1B6 = %10111100
    
    init:
      hi2csetup i2cmaster, TLV493DA1B6, i2cslow, i2cbyte
      pause 100
      hi2cout (%00000000,%00000101)  'to exit power-down mode
      pause 100
    
    main:
      do
        hi2cin (Bx,By,Bz,Temp)
        debug Temp
        pause 1000
      loop
    The data sheet for the device is available here.


    Thank you for your input,

    Edmunds
    Silly question, but...do you have a pull-up resistor on pin 6 (data) of the device? Since the picaxe is getting the data from that pin on C.3, you MAY be able to get away with using a pullup command for that pin on the picaxe. Maybe. Also, I'm assuming (silly me), that the picaxe is also running on 3.3 volts.

    Also, the device is designed for 400KHz I2C, which is I2C fast. A quick glance at the data sheet shows its timing and initialization is pretty persnickety.

  3. #3
    Senior Member
    Join Date
    Feb 2012
    Location
    London
    Posts
    2,871

    Default

    Hi.

    I think we'll also need the User Manual as described in the data sheet "For further information and a detailed I2C bitmap please refer to user manual."

    But my first guesses are that you may need to send a "Reset" command because the power-on voltage requirements look quite critical. Also the registers don't appear to be buffered so you may need to send the HI2CIN command at exactly the correct time (i.e. between measurements).

    Bx, By and Bz probably need to be words (maybe loaded via individual bytes) because it appears to be sending 12-bit data and also you might need to use the HI2CIN location,(variable,...) format to specify a register address.

    Cheers, Alan.

  4. #4
    Senior Member
    Join Date
    Apr 2012
    Location
    Cēsis, Latvia
    Posts
    855

    Default

    Quote Originally Posted by AllyCat View Post
    Hi.

    I think we'll also need the User Manual as described in the data sheet "For further information and a detailed I2C bitmap please refer to user manual."
    Dear Alan,

    Thank you for your response. Bed time here, so no more testing tonight, but I think this is the manual. I fully understand it is designed for "fast" mode and beyond, however, reading both documents left me thinking slow should be ok, too. So, I reverted to "slow" for easier testing with the scope. For all I could figure out, it did not change a thing (apart from communication speed, of course).

    I understand the 12bit problem, but I thought some number, different from 255 or 0 would suffice to prove the device is working at all. I was going to solve the 12bit problem later on .

    Pullup(-s) are there as is a 3.3V supply, of course, but thanks for checking .

    Edmunds

  5. #5
    Senior Member
    Join Date
    Feb 2012
    Location
    London
    Posts
    2,871

    Default

    Hi,

    Hmm, a rather strange (and IMHO rather User-Unfriendly) I2C implementation. It appears that it doesn't "address" the I2C registers, you must sometimes read (and perhaps write) ALL of them in a single instruction, because it always starts from register #0. From the User Manual:

    "5.1 Power Up ......

    ..... byte 7, 8 & 9 have to be read out at least one time and stored for later use by the user. This is necessary for any write command later on in order not to change the internal configurations accidentally. This means, that the bits transferred at any write command and not used for configuration, needs to be set to the same values as you read them out before, otherwise configuration will be changed (a power down and up will reset the sensor to factory settings again) "


    Note that bit7 of Write register #1 is an Odd Parity bit for ALL the bits in the 4 registers, but some of the bits in register #3 are not defined: "Bits must correspond to bits 4:0 from read register 9H. (At) Reset: device specific".

    You could just try both P = 0 and P = 1 and see which works, but strictly you should first do an I2C read:
    hi2cin (Bx, By, Bz, Temp, Bx2, Bz2,Temp2, FactSet1, FactSet2, FactSet3) and then an hi2cout (%0, MOD1, Res, MOD2) where MOD1, Res and MOD2 contain your required mode bits, plus the reserved bits from FactSet1, FactSet2 and FactSet3 . If you don't need to change the flags in MOD2 then you might only write the first two registers with %0 and MOD1, provided that the Parity flag is correct for all 4 bytes.

    To ensure that the sensor resets correctly, you should probably either power it from a PICaxe pin, or reset it with an I2C "General call" (Slave address zero) command (but you may need to check how/if PICaxe supports this):

    "5.6.1 General reset

    A general reset is trigged by calling the address 0x00 in the I2C interface. This generates an internal reset,
    refreshes the fuse register settings and re-reads the SDA/ADR line to initialize the I2C bus address."


    Cheers, Alan.

  6. #6
    Senior Member
    Join Date
    Apr 2012
    Location
    Cēsis, Latvia
    Posts
    855

    Default

    Dear Alan,

    I agree about unfriendliness, but I have come to a conclusion that many interesting devices have 'strange' implementations of I2C. The only things that work at first try for me are most I/O expanders, some LED drivers and switches. More complex solutions normally have strange things to be figured out to get them to work .

    Anyway, I found a seemingly good Arduino implementation here. I'm not very fast with Arduino or C code as such, but I'm trying to work through this now to implement what it is doing on picaxe and see if that works any better.

    Code:
    // Define includes
    #include <Wire.h>        // Wire header file for I2C and 2 wire
    
    // 
    int HallAddressWrite = 0x1F;   // Device address
    byte X_Axis_Register1 = 0x1;  //
    
    // Declare some variables
    int const numOfBytes = 7;
    int baudRate = 9600;
    byte readByte[numOfBytes];
    float counter=0.0;
    
    byte configReg = 0x00;  // Address of Configuration
    byte powerMode = 0x05;   // Set to low power mode
    
    
    void setup() {
      Serial.begin(baudRate);            // Set Serial Port speed
      delay(1000);
      Wire.pins(4, 5);
      Wire.begin();                      // Join the I2C bus as a master
    
      Wire.beginTransmission(HallAddressWrite);       // Address the sensor
      Wire.write(configReg);              // Address the Configuration register
      Wire.write(powerMode);              // Set the Power Mode to Low
      Wire.endTransmission();             // Stop transmitting
      delay(100);
    }
    
    // Main Program Infinite loop
    void loop() {
    
    
      getBytes(HallAddressWrite, X_Axis_Register1, numOfBytes, readByte); //Read first 8 bytes
    
      float temp = getTemp();
      if(temp<-50){ //re-read address banks, bad measurement
        while(temp<-50){
          getBytes(HallAddressWrite, X_Axis_Register1, numOfBytes, readByte); //Read first 8 bytes
          temp = getTemp();
        }
      }
      Serial.print("\t");
      getMagX();
      Serial.print("\t");
      getMagY();
      Serial.print("\t");
      getMagZ();
    
      Serial.println("-----");
      delay(250);
    
    }
    
    float getFrameCounter() { //every ADC conversion the frame is incremented,this function captures that
                              //This would be needed probaly in fast mode to ensure data 
                              //was succesfully written to the registries
      int i;
      int a[8];
      int lsb = readByte[3];
      int tableI[8] = { 0, 0, 0, 0, 1, 1, 0, 0};
    
    
      for ( i = 7; i >= 0; i--)
      {
        if ( (1 << i) & lsb)
          a[7 - i] = 1*tableI[7-i];
        else
          a[7 - i] = 0;
        counter += a[7 - i];
      }
      Serial.print(counter);
      return counter;
    }
    
    float getTemp()
    {
      int i;
      int a[8];
      int b[8];
      int tableI[8] = { -2048, 1024, 512, 256, 0, 0, 0, 0};
      int tableII[8] = {128, 64, 32, 16, 8, 4, 2, 1};
      float Celsius = 0;
      int msb = readByte[3];
      int lsb = readByte[6];
    
      //msb conversion
      for ( i = 7; i >= 0; i--)
      {
        if ( (1 << i) & msb)
          a[7 - i] = 1 * tableI[7 - i];
        else
          a[7 - i] = 0;
        //    Serial.print(a[7 - i]);Serial.print(" ");
        Celsius += a[7 - i];
      }
      //  Serial.print("\t");
      a[8] = 0; // ascii terminating character
    
      //lsb conversion
      for ( i = 7; i >= 0; i--)
      {
        if ( (1 << i) & lsb)
          b[7 - i] = 1 * tableII[7 - i];
        else
          b[7 - i] = 0;
        //    Serial.print(b[7 - i]);Serial.print(" ");
        Celsius += b[7 - i];
      }
      //  Serial.print("\t");
      b[8] = 0; // ascii terminating character
    
      Celsius -= 320;
      Celsius *= 1.1;
      if(Celsius>-50){
        Serial.print(Celsius);
      }
      return Celsius;
    
    }
    
    void getBytes(byte address, byte registry, int numOfBytes, byte* readByte)
    {
      Wire.beginTransmission(address);  //Begin Transmission
      //Ask for data register
      Wire.write(registry);
      Wire.endTransmission();             //End Transmission
      delay(20);                        //at least 12msec for ADC conversion and storage
      Wire.requestFrom(address, numOfBytes);     //Request Transmission
      for (int i = 0; i < numOfBytes; i++) {
        readByte[i] = Wire.read();
      }
      Wire.endTransmission();
    
    }
    
    float getMagX()
    {
      int i;
      int a[8];
      int b[8];
      int tableI[8] = { -2048, 1024, 512, 256, 128, 64, 32, 16};
      int tableII[8] = {8, 4, 2, 1, 0, 0, 0, 0};
      float magX = 0;
      int msb = readByte[0];
      int lsb = readByte[4];
    
      //msb conversion
      for ( i = 7; i >= 0; i--)
      {
        if ( (1 << i) & msb)
          a[7 - i] = 1 * tableI[7 - i];
        else
          a[7 - i] = 0;
        //    Serial.print(a[7 - i]);Serial.print(" ");
        magX += a[7 - i];
      }
      //  Serial.print("\t");
      a[8] = 0; // ascii terminating character
    
      //lsb conversion
      for ( i = 7; i >= 0; i--)
      {
        if ( (1 << i) & lsb)
          b[7 - i] = 1 * tableII[7 - i];
        else
          b[7 - i] = 0;
        //    Serial.print(b[7 - i]);Serial.print(" ");
        magX += b[7 - i];
      }
      //  Serial.print("\t");
      b[8] = 0; // ascii terminating character
    
      magX *= 0.098 * 10.0; //0.098mT/LSB 10Gauss/mT
      if(abs(magX)<3)   //the sensor has about a 0.2mT | 2Gauss units drift
        magX = 0;       //this is a software filter that suppress most of the noise
      Serial.print(magX);
      return magX;
    
    }
    
    float getMagY()
    {
      int i;
      int a[8];
      int b[8];
      int tableI[8] = { -2048, 1024, 512, 256, 128, 64, 32, 16};
      int tableII[8] = {0, 0, 0, 0, 8, 4, 2, 1};
      float magY = 0;
      int msb = readByte[1];
      int lsb = readByte[4];
    
      //msb conversion
      for ( i = 7; i >= 0; i--)
      {
        if ( (1 << i) & msb)
          a[7 - i] = 1 * tableI[7 - i];
        else
          a[7 - i] = 0;
        //    Serial.print(a[7 - i]);Serial.print(" ");
        magY += a[7 - i];
      }
      //  Serial.print("\t");
      a[8] = 0; // ascii terminating character
    
      //lsb conversion
      for ( i = 7; i >= 0; i--)
      {
        if ( (1 << i) & lsb)
          b[7 - i] = 1 * tableII[7 - i];
        else
          b[7 - i] = 0;
        //    Serial.print(b[7 - i]);Serial.print(" ");
        magY += b[7 - i];
      }
      //  Serial.print("\t");
      b[8] = 0; // ascii terminating character
    
      magY *= 0.098 * 10.0; //0.098mT/LSB 10Gauss/mT
      if(abs(magY)<3)    //the sensor has about a 0.2mT | 2Gauss units drift
        magY = 0;        //this is a software filter that suppress most of the noise
      Serial.print(magY);
      return magY;
    
    }
    
    float getMagZ()
    {
      int i;
      int a[8];
      int b[8];
      int tableI[8] = { -2048, 1024, 512, 256, 128, 64, 32, 16};
      int tableII[8] = {0, 0, 0, 0, 8, 4, 2, 1};
      float magZ = 0;
      int msb = readByte[2];
      int lsb = readByte[5];
    
      //msb conversion
      for ( i = 7; i >= 0; i--)
      {
        if ( (1 << i) & msb)
          a[7 - i] = 1 * tableI[7 - i];
        else
          a[7 - i] = 0;
        //    Serial.print(a[7 - i]);Serial.print(" ");
        magZ += a[7 - i];
      }
      //  Serial.print("\t");
      a[8] = 0; // ascii terminating character
    
      //lsb conversion
      for ( i = 7; i >= 0; i--)
      {
        if ( (1 << i) & lsb)
          b[7 - i] = 1 * tableII[7 - i];
        else
          b[7 - i] = 0;
        //    Serial.print(b[7 - i]);Serial.print(" ");
        magZ += b[7 - i];
      }
      //  Serial.print("\t");
      b[8] = 0; // ascii terminating character
    
      magZ *= 0.098 * 10.0; //0.098mT/LSB 10Gauss/mT
      if(abs(magZ)<3) //the sensor has about a 0.2mT | 2Gauss units drift
        magZ = 0;     //this is a software filter that suppress most of the noise
      Serial.print(magZ);
      return magZ;
    
    }
    Happy New Year to all,

    Edmunds

  7. #7
    Senior Member
    Join Date
    Apr 2012
    Location
    Cēsis, Latvia
    Posts
    855

    Default

    I have now sipped through the arduino code and cannot find anything I had not tried yet. In a desperate attempt to understand what is going on, I tried I2C scanner that checks sspbuf register to see if the device has acknowledged from this very forum (thank you Phil!). To my surprise, this finds the sensor perfectly well at 0x5E. I have looked at the logic analyzer output for a good few hours by now, but I cannot see the ack happening. However, the picaxe has no prejudice the device is at 0x5E, but it does print this for an address found on the bus along with EEPROM and RTC addresses, so it must be I'm not seeing what I'm seeing or I don't know how to use a logic analyzer or both .

    I will continue trying for some time, but if anyone has any more ideas from the unfriendly manuals, I would be most grateful.


    Thank you for your time,

    Edmunds

  8. #8
    Senior Member
    Join Date
    Feb 2012
    Location
    London
    Posts
    2,871

    Default

    Hi,

    Sorry, no more ideas really. If the following doesn't work then I'm stumped:

    Power the TLV493D-A1B6 from a PICaxe pin, probably with only around 100 nF across the rails of the TLV493D-A1B6.*

    Use the PICaxe program to power up the TLV493D-A1B6 (to ensure it resets correctly) , Pause, then HI2CIN (..... ) ten bytes in a single read from Slave address $5E (or any other address that it might be using) and SERTXD the received data to the Terminal Emulator. Does that give any results that aren't 255?

    Another diagnostic method might be to use the Bit-Banging I2C code which is available for PICaxe chips.

    * BTW there's a snippet of code in Post #14 (para 3, and just after the second #no_data command) in my recent/current thread which checks the supply rail to avoid exceeding the external device's Vdd.

    Cheers, Alan.

  9. #9
    Technical Support
    Join Date
    Jan 1970
    Location
    UK
    Posts
    24,343

    Default

    Your original code in post #1 is what I would have expected to work, seems to fit with what the datasheet describes in a verbose fashion - Turn it on, it reads SDA, a high because it's pulled-up to 3V3, sets its address to $BC as the PICAXE would see it ( which is what you use ). Write two bytes, $00 then $05 should put it in the low power sampling mode, leave it at device address $BC, take a sample, set INT, then one can read up to 9 bytes from it.

    The only thing I would suggest is a PAUSE before the HI2CSETUP but, as it's set its address within 200us of power up, I wouldn't have thought that would be necessary.

    The datasheet is so verbose that it's hard to tell what it's saying without studying it, but my reading of it is that it's basically standard I2C; what you have should work. Just that reads and writes have to be done in one block. Never write more than 4 bytes and one doesn't have to have read the other bytes to be able to rewrite those. Writing the two bytes to initialise, reading just the first four data bytes as done should be fine.

    There's an oddity in the C code of post #6 in that it uses a device address of $1F ( $1E as it would be when used in a PICAXE HI2CSETUP command ). Fair enough if SDA is low at turn on ( though I would have expected $3F ), but if it were $1F then writing $05 to MOD1 should move its device address to $3F ( $3E for PICAXE ).

    That code however continues to use $1F as the device address. Also $1F is a read address in the C code, but is being used for the write. It's hard to figure out what that C code is actually doing. It could be the initialisation has no effect, but that doesn't explain how the chip would be taken out of power-down mode allowing measured results to be read.

    It might be the code doesn't actually work. It would be worth trying to find other example code which is clearer or more decipherable. Something which uses device address $BC/$BD would be more useful than anything using $1E/$1F or $3E/$3F.

    However it could be pointing to some oddity that writes are done to a read address and this is why the initialisation isn't working for the PICAXE; it's a recognised address, hence the initial ACK, but not actually writing, not taking it out of power-down, not enabling valid reads to be done.

    That could explain what looks to be a repeated start in the C code for reading. If so that might only be resolved by bit-banging the I2C.

    I'd be looking for additional example code at his point.

    Also take a look at the INT output. If you are enabling it then that would give an indication to show if it's ever initialised, ever sampling, ever getting a result.
    Last edited by hippy; 02-01-2018 at 13:45.

  10. #10
    Senior Member
    Join Date
    Apr 2012
    Location
    Cēsis, Latvia
    Posts
    855

    Default

    Thank you Alan and Hippy for taking a look.

    Alan - no, its all 255.

    Hippy - I thought about looking for the INT pulse, but two things put me off - INT is also an SCL line (and only while answering this do I understand how to work with it ), but even more so by INT pulse being just 1.5us, which sounds very short. No brainpower to attempt to detect that right now, but will try in a few days when I'm back from a road trip. I also found this github library, which contains ARM or Arduino code with a lot more comments and much better structure (IMHO) than what I linked to earlier. Again, no brainpower to dig it now, but soonish .


    Regards,

    Edmunds

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •