TLV493D-A1B6 3D Magnetic Sensor

edmunds

Senior Member
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
 

rq3

Senior Member
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.
 

AllyCat

Senior Member
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.
 

edmunds

Senior Member
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
 

AllyCat

Senior Member
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.
 

edmunds

Senior Member
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
 

edmunds

Senior Member
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
 

AllyCat

Senior Member
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.
 

hippy

Technical Support
Staff member
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:

edmunds

Senior Member
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
 

edmunds

Senior Member
Ok, I'm now looking into this again. One interesting thing I can find is the parity bit that Alan has mentioned earlier. How do I "calculate" if the sum of "all 32 bits of write registers is odd"? And do I understand correctly, this bit is used to force it odd? I.e. it would have to be set for even sum of all the other bits or clear for odd?


Thank you for your time,

Edmunds
 

AllyCat

Senior Member
Hi,

Yes, the parity bit simply determines whether the total number of bits set is Even or Odd. Odd parity has the advantage that it will catch "hardware-type" errors such as all zeros or all ones (255). But then it only gives a 50% chance of catching more complex (multi-bit) errors; a parity byte or CRC would be much better,

There might be faster X2 commands, but calculation is not difficult anyway, because much can be done in parallel. First combine the 4 bytes (or two words first, but it's hardly worth the added complication) and then combine the nibbles, pairs of bits and finally single bits. Not fully tested:

Code:
b1 = b1 xor b2 xor b3 xor b4
b1 = b1 * 16 xor b1     ; Or could /16 [I](or >> 4 with X2)[/I] but * faster
b1 = b1 * 4 xor b1
b1 = b1 + b1 xor b1
oddparity = not bit15      ; If parity bit originally was 0
Cheers, Alan.
 

edmunds

Senior Member
Are there any known I2C bit-banging examples I could borrow? I searched the forum for a couple of phrases and read through a lot of interesting posts, but none to provide exactly that.


Thank you for your time,

Edmunds
 

AllyCat

Senior Member
Hi,

I2C bit-banging code was suggested by Technical in post #2 of this thread but I didn't investigate it in detail because the HI2C method is about 300 times faster. ;)

Cheers, Alan.
 

hippy

Technical Support
Staff member
You don't need any code to determine the parity bit. When configuring the MOD1 and MOD2 registers you will know exactly which bits you want to set and clear and can determine the parity bit simply by counting how many bits are set. Or simply try it with 0 or 1 and see which works.
 

edmunds

Senior Member
You don't need any code to determine the parity bit. When configuring the MOD1 and MOD2 registers you will know exactly which bits you want to set and clear and can determine the parity bit simply by counting how many bits are set. Or simply try it with 0 or 1 and see which works.
Thanks, hippy. I agree I don't 'need' to do it, just trying to plug all the holes. As far as I understand, parity bit is not my problem, as long as I'm getting 255's from the sensor. Pretty much out of options by now, will take the last look with the logic analyser. If that does not show anything unexpected, "someday maybe drawer" it is.


Edmunds
 

AllyCat

Senior Member
Hi,

Yes I agree that you can't do much if the I2C only ever returns 255s; but are you sure you've tried every possible slave address? Also, the User Manual does contain quite a lot of "small print" and in particular are you sure that you've complied with this requirement from page 12 of the Data Sheet ? :

"...the chip does not use a classic (and current consuming) reset concept. The implemented reset focus is on ensuring a proper supply for the ADC operation only (so it inhibits the ADC reliably until the sensor supply is high enough). Thus, the sensor rely on a proper supply ramp incl. 3.7mA current consumption during power-on to ensure it is initialized correctly, typically a monotonic rise of Vdd from zero to 3.3V within less than 10&#956;s and without over/undershoots larger than 300mV. If such a supply can not be provided, the I2C reset feature of the sensor shall be used by the &#956;C after power-up."

Cheers, Alan.
 

edmunds

Senior Member
Dear Alan,

What you are referring to, could be one small spark of hope.

I checked the rise time for high B.0, which is how I have been powering the sensor and it is about 30us. Clearly, nowhere near 10us required as spotted by you. Now I tried to use the suggested workaround of calling I2C address 0x00 without checking all the relevant data sheets I should have checked first ;). This did not help at all and somehow seem to have 'hanged' picaxe process on the chip as I do not even get to the 'debug' part of the code. The execution seems to just halt after hi2cmaster, 0x00, i2cslow, i2cbyte.

Now, either this has to be issued manually i.e. bit-banged or I have to find a way to get the rise time of sub-10us. Probably possible both electronically and software-wise, but I will leave people in other time zones at that for a while, as it is too late for this kind of thing here now :).

Thank you for your input, I at least feel a have some thread to dig now.

I'm still not entirely sure about the address either, because the only thing logic analyser seems to show ack for is %1010000[0] and not 0x5E. I don't get at this with brainpower to actually collect the proper pictures for now, but the inadequate power supply is the first thing to sort anyway.

/Edmunds
 
Last edited:

hippy

Technical Support
Staff member
As the device is at least acknowledging the initial part of the I2C communications it would seem that it is working, even if not delivering the desired results.

I think using a $00 device address, bus slew rates, suspecting some sort of inadequate power supply are red herrings and blind alleyways.

Rather than digging ever deeper into the hole it would be worth posting how your code is now that some of the device's peculiarities have been determined.
 

edmunds

Senior Member
As the device is at least acknowledging the initial part of the I2C communications it would seem that it is working, even if not delivering the desired results.

I think using a $00 device address, bus slew rates, suspecting some sort of inadequate power supply are red herrings and blind alleyways.

Rather than digging ever deeper into the hole it would be worth posting how your code is now that some of the device's peculiarities have been determined.
Hippy, I don't want any red herrings! :)
So, lets try the sensible approach once again and see if something obvious was missed.

Below is the code I'm using as I2C scanner:

Code:
[color=Navy]#picaxe [/color][color=Black]40x2[/color]

[color=Navy]#no_data
#no_table[/color]

[color=Blue]symbol [/color][color=Black]sspbuf [/color][color=DarkCyan]= [/color][color=Navy]$C9

  [/color][color=Blue]high B.0 [/color][color=Green]'for magnetic sensor
  [/color][color=Blue]high C.4 [/color][color=Green]'for magnetic sensor
  
  [/color][color=Blue]pause [/color][color=Navy]5000
  [/color][color=Blue]sertxd (cr[/color][color=Black],[/color][color=Blue]lf[/color][color=Black],[/color][color=Red]"START PROGRAM"[/color][color=Blue])
  hi2csetup i2cmaster[/color][color=Black],[/color][color=Navy]2[/color][color=Black],[/color][color=Blue]i2cslow[/color][color=Black],[/color][color=Blue]i2cbyte
  for [/color][color=Purple]b2 [/color][color=DarkCyan]= [/color][color=Navy]%00000010 [/color][color=Blue]to [/color][color=Navy]%11111110 [/color][color=Blue]step [/color][color=Navy]2
    [/color][color=Blue]hi2cout [PLAIN][[/PLAIN][/color][color=Purple]b2[/color][color=Blue][PLAIN]][/PLAIN][/color][color=Black],[/color][color=Blue]([/color][color=Navy]0[/color][color=Blue])
    peeksfr [/color][color=Black]sspbuf,[/color][color=Purple]b0
    [/color][color=Blue]if [/color][color=Purple]b0 [/color][color=DarkCyan]= [/color][color=Navy]0 [/color][color=Blue]then
      [/color][color=Purple]b0 [/color][color=DarkCyan]= [/color][color=Purple]b2 [/color][color=DarkCyan]/ [/color][color=Navy]2
      [/color][color=Blue]sertxd (cr[/color][color=Black],[/color][color=Blue]lf[/color][color=Black],[/color][color=Red][PLAIN]"** i2c response @ ["[/PLAIN][/color][color=Black],#[/color][color=Purple]bit7[/color][color=Black],#[/color][color=Purple]bit6[/color][color=Black],#[/color][color=Purple]bit5[/color][color=Black],#[/color][color=Purple]bit4[/color][color=Black],#[/color][color=Purple]bit3[/color][color=Black],#[/color][color=Purple]bit2[/color][color=Black],#[/color][color=Purple]bit1[/color][color=Black],#[/color][color=Purple]bit0[/color][color=Black],[/color][color=Red][PLAIN]"] 0x"[/PLAIN][/color][color=Blue])
      
      [/color][color=Purple]b1 [/color][color=DarkCyan]= [/color][color=Purple]b0 [/color][color=DarkCyan]/ [/color][color=Navy]16 [/color][color=DarkCyan]+ [/color][color=Red]"0"
      [/color][color=Blue]if [/color][color=Purple]b1 [/color][color=DarkCyan]> [/color][color=Red]"9" [/color][color=Blue]then
        [/color][color=Purple]b1 [/color][color=DarkCyan]= [/color][color=Purple]b1 [/color][color=DarkCyan]+ [/color][color=Navy]7
      [/color][color=Blue]endif
      sertxd([/color][color=Purple]b1[/color][color=Blue])
      
      [/color][color=Purple]b1 [/color][color=DarkCyan]= [/color][color=Purple]b0 [/color][color=DarkCyan]& [/color][color=Navy]%00001111 [/color][color=DarkCyan]+ [/color][color=Red]"0"
      [/color][color=Blue]if [/color][color=Purple]b1 [/color][color=DarkCyan]> [/color][color=Red]"9" [/color][color=Blue]then
        [/color][color=Purple]b1 [/color][color=DarkCyan]= [/color][color=Purple]b1 [/color][color=DarkCyan]+ [/color][color=Navy]7
      [/color][color=Blue]endif
      sertxd([/color][color=Purple]b1[/color][color=Blue])
    else
      if [/color][color=Purple]b0 [/color][color=DarkCyan]<> [/color][color=Purple]b2 [/color][color=Blue]then
        sertxd (cr[/color][color=Black],[/color][color=Blue]lf[/color][color=Black],[/color][color=Red]"Something strange happened!"[/color][color=Blue])
      endif
    endif
  next
  sertxd (cr[/color][color=Black],[/color][color=Blue]lf[/color][color=Black],[/color][color=Red]"END PROGRAM"[/color][color=Blue])
  end[/color]
This returns:

I2CTesterPrtSc.JPG

So far so good.

/Edmunds
 

edmunds

Senior Member
Then, here is the code I'm using to try to get a response of sorts. Any sorts.

Code:
[color=Navy]#picaxe [/color][color=Black]40x2[/color]

[color=Navy]#no_data
#no_table[/color]

[color=Blue]Symbol [/color][color=Purple]Bx [/color][color=DarkCyan]= [/color][color=Purple]b4[/color]
[color=Blue]Symbol [/color][color=Purple]By [/color][color=DarkCyan]= [/color][color=Purple]b5[/color]
[color=Blue]Symbol [/color][color=Purple]Bz [/color][color=DarkCyan]= [/color][color=Purple]b6[/color]
[color=Blue]Symbol [/color][color=Purple]Temp [/color][color=DarkCyan]= [/color][color=Purple]b7[/color]

[color=Blue]Symbol SDApin [/color][color=DarkCyan]= [/color][color=Blue]C.3
Symbol SCLpin [/color][color=DarkCyan]= [/color][color=Blue]C.4

Symbol TLV493DA1B6 [/color][color=DarkCyan]= [/color][color=Navy]0x5E[/color]
[color=Blue]Symbol X_Axis_Register [/color][color=DarkCyan]= [/color][color=Navy]0x01[/color]

[color=Blue]Symbol configreg [/color][color=DarkCyan]= [/color][color=Navy]0x00[/color]
[color=Blue]Symbol powermode [/color][color=DarkCyan]= [/color][color=Navy]0x05[/color]

[color=Black]init:
  [/color][color=Blue]setfreq em64
  high B.0
  high SDApin
  pause [/color][color=Navy]1600      [/color][color=Green]'200us, so the sensor can set its I2C address
  [/color][color=Blue]hi2csetup i2cmaster[/color][color=Black],[/color][color=Blue]TLV493DA1B6[/color][color=Black],[/color][color=Blue]i2cfast64[/color][color=Black],[/color][color=Blue]i2cbyte
  hi2cout (configreg[/color][color=Black],[/color][color=Blue]powermode)  [/color][color=Green]'exit power-down mode[/color]

[color=Black]main:
  [/color][color=Blue]do[/color]
[color=Green];    hi2cout (X_Axis_Register)
    [/color][color=Blue]pause [/color][color=Navy]100
    [/color][color=Blue]hi2cin ([/color][color=Purple]Bx[/color][color=Black],[/color][color=Purple]By[/color][color=Black],[/color][color=Purple]Bz[/color][color=Black],[/color][color=Purple]Temp[/color][color=Black],[/color][color=Purple]b8[/color][color=Black],[/color][color=Purple]b9[/color][color=Black],[/color][color=Purple]b10[/color][color=Black],[/color][color=Purple]b11[/color][color=Black],[/color][color=Purple]b12[/color][color=Black],[/color][color=Purple]b13[/color][color=Blue])
    pause [/color][color=Navy]1000
    [/color][color=Blue]debug
  loop[/color]
Here is the result in the debug window:

I2CDebugPrtSc.JPG

/Edmunds
 
Last edited:

edmunds

Senior Member
Because of the 2 image limit per post, here come the logic analyser screenshots.

This is the init: part:

I2CNoACK0x5EInit.JPG

This is the main: part:

I2CNoACK0x5EMain.JPG

Admittedly, the scope screenshots were made with i2cslow64, while the code says i2cfast64. Since the data sheets do not state slow mode compatibility explicitly, I'm using fast mode for testing, but I don't have a scope fast enough to catch the entire communication. I can see, however, that there is still no ack pulse also for fast mode. Also, I'm using em64 to ramp up the power supply rise time, which seems to be the simplest solution to the possible problem.

/Edmunds
 
Last edited:

hippy

Technical Support
Staff member
In your first logic trace, sending the device address, there doesn't appear to be an ACK in response to that.

Probably because you are using a $5E address (7-bit?) when I thought we had established it was on $BC.

I2C.jpg - Click to enlarge

I would start by trying $BC, running at default PICAXE speed, having a PAUSE 1000 as the first line, using I2CSLOW, and seeing if that elicits any ACK response. I would also try with the module powered direct from the +V supply.

If there is a response then it is probably working just as well no matter how the datasheet may describe it as having special requirements.
 
Last edited:

hippy

Technical Support
Staff member
Code:
[color=Navy]#picaxe [/color][color=Black]40x2[/color]

[color=Blue]Symbol SDApin [/color][color=DarkCyan]= [/color][color=Blue]C.3
Symbol SCLpin [/color][color=DarkCyan]= [/color][color=Blue]C.4[/color]
On a 40X2 C.3 is SCL, C.4 is SDA. But it shouldn't matter because the pull-ups will keep SDA and SCL high at start up.
 

hippy

Technical Support
Staff member
This program identifies I2C devices on the bus using bit-banging. It was designed for identifying Wii controllers but should also find anything else. You will have to adjust all the SDA and SCL related pin numbers for a 40X2, plus #TERMINAL 9600, and you might have to comment out "Gosub VoltCheck" and PULLUP command.

Code:
; **************************************************************************
; *                                                                        *
; *  Find Devices on I2C Bus                                 IDENTIFY-003  *
; *                                                                        *
; **************************************************************************

#Picaxe 08M2
#No_Data
#Terminal 4800

;        .-----_-----.              To Controller
; 3V3 ---| V+     0V |--- 0V             .-.
;       -| SI    C.0 |-          .------>|O| PWR
;    .---| C.4   C.1 |--- SCL ---|-------|O| SCL
;    |  -| C.3   C.2 |--- SDA ---|-------|O| SDA
;    |   `-----------'           |   .---|O| 0V
;    `---------------------------'  _|_  `-'
;                    
; Nunchuck includes 1K8 pull-ups on SDA and SCL
; PICAXE uses internal pull-ups so externals are not needed

Symbol SCL = C.1 : Symbol pinSCL = pinC.1
Symbol SDA = C.2 : Symbol pinSDA = pinC.2
Symbol PWR = C.4

; **************************************************************************
; *                                                                        *
; *  Main Program                                                          *
; *                                                                        *
; **************************************************************************

PowerOnReset:
  Pause 2000
  Gosub VoltCheck
  PullUp %000110
  High PWR
  Pause 1000

MainLoop:
  Do
    SerTxd( CR, LF, "Looking for Devices ...", CR, LF )
    Gosub FindDevices
    Pause 5000
  Loop

; **************************************************************************
; *                                                                        *
; *  Check PSU Voltage                                                     *
; *                                                                        *
; **************************************************************************

VoltCheck:
  Do
    CalibAdc10 w0
    w0 = 52378 / w0 * 2
    BinToAscii w0, b15,b14,b13,b12,b11
    SerTxd( "Vpsu = ", b13,".",b12,b11, "V")
    Select Case w0
      Case < 320 : SerTxd( " : Voltage < 3.2V" ) : Pause 500
      Case > 340 : SerTxd( " : Voltage > 3.4V" ) : Pause 500
    End Select
    serTxd( CR, LF )
  Loop Until w0 >= 320 And w0 =< 340
  Return

; **************************************************************************
; *                                                                        *
; *  Search For Devices                                                    *
; *                                                                        *
; **************************************************************************

FindDevices:
  SerTxd( CR, LF, " ")
  For b0 = $00 To $1F Step 2
    If b0 = $10 Then
      SerTxd( "    " )
    End If
    SerTxd( "  " ) : Gosub HexLsd
  Next
  b10 = $00 ; Address to try
  b12 = $00 ; Address found
  Do
    b0 = b10 & $1F
    Select Case b0
      Case $00
        SerTxd( CR, LF )
        b0 = b10 / $10 : Gosub HexLsd
      Case $10
        SerTxd( "   " )
        b0 = b10 / $10 : Gosub HexLsd
    End Select
    If b10 < $10 Or b10 >= $F0 Then
      SerTxd( " XX" )
    Else
      Gosub CheckForDevice
    End If
    b10 = b10 + 2
  Loop Until b10 = 0
  SerTxd( CR, LF, CR, LF )
  b0 = b12
  Select Case b0
    Case $00 : SerTxd( "No devices found" )
    Case $01 : SerTxd( "Multiple devices found" )
    Else     : SerTxd( "Device found at " ) : Gosub Hex
               Select Case b0
                 Case $A0 : SerTxd( 9, "EEPROM" )
                 Case $A4 : SerTxd( 9, "Wii Controller" )
                 Case $A6 : SerTxd( 9, "Wii Motion Plus" )
                 Case $D0 : SerTxd( 9, "RTC" )
               End Select
  End Select
  SerTxd( CR, LF )
  Return

CheckForDevice:
  ; Gosub ResetBus
  Gosub SendStart
  b0 = b10 Or 1 ; Read bit
  Gosub SendByte
  Gosub ReadAck
  ; Gosub SendStop
  If b0 = 0 Then
    ; Ack
    If b12 = $00 Then
      b12 = b10
    Else
      b12 = $01
    End If
    SerTxd( " " ) : b0 = b10 : Gosub Hex
    ;If b10 = $A6 Then
    ;  ; Motion Plus - Power cycle
    ;  Input PWR : Pause 100
    ;  Low   PWR : Pause 100 
    ;  High  PWR : Pause 100 
    ;End If
  Else
    ; Nak
    SerTxd( " --" )
  End If
  Gosub ReadByte
  Gosub SendNack
  Gosub SendStop    
  Return

; **************************************************************************
; *                                                                        *
; *  Low-Level I2C Routines                                                *
; *                                                                        *
; **************************************************************************


SendStart:
  Input SCL ; SCL = 1
  Gosub Stretch
  Input SDA ; SDA = 1
  Low   SDA ; SDA = 0
  Low   SCL ; SCL = 0
  Return

ResetBus:
  Input SDA ; SDA = 1
  Low   SCL ; SCL = 0
  For b1 = 0 To 8
    Input SCL ; SCL = 1
    Low   SCL ; SCL = 0
  Next

SendStop:
  Low   SDA ; SDA = 0
  Low   SCL ; SCL = 0
  Input SCL ; SCL = 1
  Gosub Stretch
  Input SDA ; SDA = 1
  Return

SendByte:
  For b1 = 0 To 7
    If bit7 = 0 Then
      Low   SDA ; SDA = 0
    Else
      Input SDA ; SDA = 1
    End If
    Input   SCL ; SCL = 1
    Gosub   Stretch
    Low     SCL ; SCL = 0
    b0 = b0 * 2
  Next
  Return

ReadByte:
  Low   SCL ; SCL = 0
  Input SDA ; SDA = 1
  For b1 = 0 To 7
    Input   SCL ; SCL = 1
    Gosub   Stretch
    b0 = b0 * 2 + pinSDA
    Low     SCL ; SCL = 0
  Next
  Return

ReadAck:
  Input SDA ; SDA = 1
  Input SCL ; SCL = 1
  Gosub Stretch
  b0  = pinSDA
  Low   SCL ; SCL = 0
  Return

SendAck:
  Low   SDA ; SDA = 0
  Input SCL ; SCL = 1
  Gosub Stretch
  Low   SCL ; SCL = 0
  Return

SendNack:
  Input SDA ; SDA = 1
  Input SCL ; SCL = 1
  Gosub Stretch
  Low   SCL ; SCL = 0
  Return

Stretch:
  Do : Loop While pinSCL = 0
  Return

; **************************************************************************
; *                                                                        *
; *  Display Output Routines                                               *
; *                                                                        *
; **************************************************************************

Hex:
  b1 = b0 / $10 : Gosub Nibble
HexLsd:
  b1 = b0

Nibble:
  b1 = b1 & $0F + "0"
  If b1 > "9" Then : b1 = b1 + 7 : End If
  SerTxd( b1 )
  Return
  
; **************************************************************************
; *                                                                        *
; *  End Of Program                                                        *
; *                                                                        *
; **************************************************************************
 

edmunds

Senior Member
Thank you, hippy.

I will look into this on Friday again, don't have the device with me on the road.

I diverted away from BC back to 5E due to the I2C address finder reporting 5E and I don't remember if I tested for ACK with address BC. Will do.
I believe the SCL<->SDA mistake is cosmetic in this case, too, however not good not checking it on my part. Thanks for spotting this.
And finally, thank you for posting the code, I will certainly try it and I'm sure it will be useful to many on this forum.

Edmunds
 

hippy

Technical Support
Staff member
I diverted away from BC back to 5E due to the I2C address finder reporting 5E
That's quite probably the case. 5E (1011110) and BC (10111100) are equivalent. The first excludes the read/write bit (7-bit) and the second includes it as a default zero bit (8-bit).

What any particular number represents, 7 or 8-bit, can sometimes be difficult to figure out, though if an odd number it will be 7-bit., For the PICAXE 8-bit must be specified in HI2C commands and that would normally be how any device address would be reported, but some things may report using 7-bit formats.
 

AllyCat

Senior Member
Hi,

Another thing to try is to use the PICaxe pin to switch the ground line rather than the supply rail to the sensor. This gives two possible benefits:

The PICaxe N-channel (pull down) output transistors are normally "stronger" than the P-channel (pull ups) so the supply rise-time (or strictly voltage fall time) could be faster.

As this is an I2C chip, the resistor pullups may be delivering "phantom power" into the sensor chip, which might defeat the power-up strategy. As an alternative, the PICaxe pins could be commanded to pull SDA and SCL low before activating the power supply, but this would cause the chip to modify its Slave address.

Cheers, Alan.
 

edmunds

Senior Member
So, I have something different this morning, which is a good start. Maybe.

Here is the code I'm running:

Code:
[color=Navy]#picaxe [/color][color=Black]40x2[/color]

[color=Navy]#no_data
#no_table[/color]

[color=Blue]Symbol [/color][color=Purple]Bx [/color][color=DarkCyan]= [/color][color=Purple]b4[/color]
[color=Blue]Symbol [/color][color=Purple]By [/color][color=DarkCyan]= [/color][color=Purple]b5[/color]
[color=Blue]Symbol [/color][color=Purple]Bz [/color][color=DarkCyan]= [/color][color=Purple]b6[/color]
[color=Blue]Symbol [/color][color=Purple]Temp [/color][color=DarkCyan]= [/color][color=Purple]b7[/color]

[color=Blue]Symbol SCLpin [/color][color=DarkCyan]= [/color][color=Blue]C.3
Symbol SDApin [/color][color=DarkCyan]= [/color][color=Blue]C.4

Symbol TLV493DA1B6 [/color][color=DarkCyan]= [/color][color=Navy]0xBC[/color]
[color=Blue]Symbol X_Axis_Register [/color][color=DarkCyan]= [/color][color=Navy]0x01[/color]

[color=Blue]Symbol configreg [/color][color=DarkCyan]= [/color][color=Navy]0x00[/color]
[color=Blue]Symbol powermode [/color][color=DarkCyan]= [/color][color=Navy]0x05[/color]

[color=Black]init:
  [/color][color=Blue]high SDApin
  pause [/color][color=Navy]200      [/color][color=Green]'200us, so the sensor can set its I2C address
  [/color][color=Blue]hi2csetup i2cmaster[/color][color=Black],[/color][color=Blue]TLV493DA1B6[/color][color=Black],[/color][color=Blue]i2cslow[/color][color=Black],[/color][color=Blue]i2cbyte
  hi2cout (configreg[/color][color=Black],[/color][color=Blue]powermode)  [/color][color=Green]'exit power-down mode[/color]
[color=Blue]end[/color]
And here is the result on the logic analyser:
I2CAckNoWrite.JPG

If I read correctly what I'm seeing, then there is now an ACK pulse, but I cannot see data being sent. There is a stop condition later on that you cannot see in the screenshot. Is there some clue in the code+picture that picaxe does not see the ACK as ACK and does not send anything (0x00,0x05)?


Thank you for your time,

Edmunds
 

hippy

Technical Support
Staff member
It is definitely responding. And it looks like an ACK. Whether it is actually an ACK, is being seen as an ACK, is difficult to say.

When expecting the ACK, after SCL has been taken high, the PICAXE will then be looking for SDA to be pulled low by the chip. When that happens it is an ACK and the PICAXE will drop its SCL line back to low.

What I would expect is what's on the left of the diagram below. What the trace seems to show is what's on the right -

Code:
     _______     ___          _________   ___
SDA         \___/        SDA           \_/
         _____                    _____
SCL  ___/     \_____     SCL  ___/     \_____
It is hard to tell from the trace if SDA being pulled low is occurring before SCL is taken low, simultaneously with that or after that.

I would guess it is as on the left hand side just happening so quickly that the trace is showing it as being more coincidental with SCL going low. I don't know if you can increase the timebase so it's easier to tell which it is, have some option which can more clearly show rising and falling edges without the slew being shown.

Assuming not, and it's just too fast for your equipment to measure, then I would suggest running the code in #25 to see if that identifies the device, because that only will if the ACK is occurring while SCL is high.

At this point we need to determine if it's (1) not an ACK and that's what's causing things not to work after that, or (2) is an ACK and it's for some other reason things are not working.
 

hippy

Technical Support
Staff member
This is the code from post #25 modified to use a 40X2. It's untested but should work -

Code:
; **************************************************************************
; *                                                                        *
; *  Find Devices on I2C Bus using 40X2                                    *
; *                                                                        *
; **************************************************************************

#Picaxe 40X2
#No_Table
#No_Data
#Terminal 9600

Symbol SCL = C.3 : Symbol pinSCL = pinC.3
Symbol SDA = C.4 : Symbol pinSDA = pinC.4

; **************************************************************************
; *                                                                        *
; *  Main Program                                                          *
; *                                                                        *
; **************************************************************************

PowerOnReset:
  Pause 2000

MainLoop:
  Do
    SerTxd( CR, LF, "Looking for Devices ...", CR, LF )
    Gosub FindDevices
    Pause 5000
  Loop

; **************************************************************************
; *                                                                        *
; *  Search For Devices                                                    *
; *                                                                        *
; **************************************************************************

FindDevices:
  SerTxd( CR, LF, " ")
  For b0 = $00 To $1F Step 2
    If b0 = $10 Then
      SerTxd( "    " )
    End If
    SerTxd( "  " ) : Gosub HexLsd
  Next
  b10 = $00 ; Address to try
  b12 = $00 ; Address found
  Do
    b0 = b10 & $1F
    Select Case b0
      Case $00
        SerTxd( CR, LF )
        b0 = b10 / $10 : Gosub HexLsd
      Case $10
        SerTxd( "   " )
        b0 = b10 / $10 : Gosub HexLsd
    End Select
    If b10 < $10 Or b10 >= $F0 Then
      SerTxd( " XX" )
    Else
      Gosub CheckForDevice
    End If
    b10 = b10 + 2
  Loop Until b10 = 0
  SerTxd( CR, LF, CR, LF )
  b0 = b12
  Select Case b0
    Case $00 : SerTxd( "No devices found" )
    Case $01 : SerTxd( "Multiple devices found" )
    Else     : SerTxd( "Device found at " ) : Gosub Hex
  End Select
  SerTxd( CR, LF )
  Return

CheckForDevice:
  Gosub SendStart
  b0 = b10 Or 1 ; Read bit
  Gosub SendByte
  Gosub ReadAck
  If b0 = 0 Then
    ; Ack
    If b12 = $00 Then
      b12 = b10
    Else
      b12 = $01
    End If
    SerTxd( " " ) : b0 = b10 : Gosub Hex
  Else
    ; Nak
    SerTxd( " --" )
  End If
  Gosub ReadByte
  Gosub SendNack
  Gosub SendStop    
  Return

; **************************************************************************
; *                                                                        *
; *  Low-Level I2C Routines                                                *
; *                                                                        *
; **************************************************************************

SendStart:
  Input SCL ; SCL = 1
  Gosub Stretch
  Input SDA ; SDA = 1
  Low   SDA ; SDA = 0
  Low   SCL ; SCL = 0
  Return

ResetBus:
  Input SDA ; SDA = 1
  Low   SCL ; SCL = 0
  For b1 = 0 To 8
    Input SCL ; SCL = 1
    Low   SCL ; SCL = 0
  Next

SendStop:
  Low   SDA ; SDA = 0
  Low   SCL ; SCL = 0
  Input SCL ; SCL = 1
  Gosub Stretch
  Input SDA ; SDA = 1
  Return

SendByte:
  For b1 = 0 To 7
    If bit7 = 0 Then
      Low   SDA ; SDA = 0
    Else
      Input SDA ; SDA = 1
    End If
    Input   SCL ; SCL = 1
    Gosub   Stretch
    Low     SCL ; SCL = 0
    b0 = b0 * 2
  Next
  Return

ReadByte:
  Low   SCL ; SCL = 0
  Input SDA ; SDA = 1
  For b1 = 0 To 7
    Input   SCL ; SCL = 1
    Gosub   Stretch
    b0 = b0 * 2 + pinSDA
    Low     SCL ; SCL = 0
  Next
  Return

ReadAck:
  Input SDA ; SDA = 1
  Input SCL ; SCL = 1
  Gosub Stretch
  b0  = pinSDA
  Low   SCL ; SCL = 0
  Return

SendAck:
  Low   SDA ; SDA = 0
  Input SCL ; SCL = 1
  Gosub Stretch
  Low   SCL ; SCL = 0
  Return

SendNack:
  Input SDA ; SDA = 1
  Input SCL ; SCL = 1
  Gosub Stretch
  Low   SCL ; SCL = 0
  Return

Stretch:
  Do : Loop While pinSCL = 0
  Return

; **************************************************************************
; *                                                                        *
; *  Display Output Routines                                               *
; *                                                                        *
; **************************************************************************

Hex:
  b1 = b0 / $10 : Gosub Nibble
HexLsd:
  b1 = b0

Nibble:
  b1 = b1 & $0F + "0"
  If b1 > "9" Then : b1 = b1 + 7 : End If
  SerTxd( b1 )
  Return
  
; **************************************************************************
; *                                                                        *
; *  End Of Program                                                        *
; *                                                                        *
; **************************************************************************
 

hippy

Technical Support
Staff member
That's good news so it seems we are on a firm foundation, know where we are. The chip powers up, runs, acknowledges it's there. I would say the next thing is to determine what it does on a simple write -

Code:
#Picaxe 40X2
#no_data
#no_table
Pause 1000
HI2cSetup i2cmaster, $BC, i2cslow, i2cbyte
Do
   hi2cout ($00)
   Pause 1000
Loop
Something which shows the actual byte being written should indicate what is going on with that.
 

hippy

Technical Support
Staff member
That is interesting because, after the device address and what seems to be the ACK, the PICAXE is not sending any further SCL pulses at all.

It is as if the bit-banged code is detecting the ACK but the I2C hardware in the PICAXE is not.

It would be worth replacing "HI2cout ($00)" with "HI2cIn (b0)" to see if that exhibits the same behaviour or whether that causes further SCL pulses to be produced.

If it is the case that the chip is not compatible with the I2C hardware of the PICAXE then it may be that I2C communications has to be done through bit-banging.
 

hippy

Technical Support
Staff member
In the code used for identifying which devices there are, if you replace MainLoop with the following this should be the bit-banged equivalent of "HI2cOut ($00)" -

Code:
MainLoop:
  Do
    Gosub SendStart
    b0 = $BC Or 0 ; Write bit
    Gosub SendByte
    Gosub ReadAck
    b0 = $00
    Gosub SendByte
    Gosub ReadAck ; <-- Changed
    Gosub SendStop    
    Pause 1000
  Loop
This should be the bit-banged equivalent of "HI2cIn (b0)" which may be more useful to test as it should elicit an ACK which writing won't-

Code:
MainLoop:
  Do
    Gosub SendStart
    b0 = $BC Or 1 ; Read bit
    Gosub SendByte
    Gosub ReadAck
    Gosub ReadByte
    Gosub SendAck ; <-- Changed
    Gosub SendStop    
    Pause 1000
  Loop
 
Last edited:

AllyCat

Senior Member
Hi,

I would say the next thing is to determine what it does on a simple write -
IMHO the User Manual/Data Sheet is fairly specific that the first thing to do (after a Reset) is to Read the contents of the registers (so that the Parity bit can be set/changed to the required value).

If none of those registers can be read then there's clearly a problem still to be solved.

Cheers, Alan.
 
Top