I2C Status

This is where you talk about the NXJ software itself, installation issues, and programming talk.

Moderators: 99jonathan, roger, imaqine

I2C Status

Postby gloomyandy » Mon Oct 08, 2007 11:44 pm

Hi,
Can anyone provide any details on the status of I2C in LeJOS? The source code says that the send/write commands do not currently work, but I noticed that the compass sensor support uses them. Also I've been able to sort of make them work with the Ultrasonic sensor (using it in single ping mode), but with one or two rather odd results. So does anyone know what exactly the problems are with this support of I2C at the moment?

Thanks

Andy
User avatar
gloomyandy
leJOS Team Member
 
Posts: 4004
Joined: Fri Sep 28, 2007 2:06 pm
Location: UK

Postby gloomyandy » Tue Oct 09, 2007 7:57 pm

Oh well in reply to my own message....

I've been taking a closer look at this and I'm now pretty sure that writes to i2c are broken. What seems to happen is that when trying to write to a particular address within a device the code in i2c.c ends up sending an extra STOP message, which messes things up (i2c devices are supposed to treat a STOP command as an abort). So an example... To set the Ultrasonic sensor into single shot mode you need to write 0x1 to location 0x41 in device 0x2 (the Ultrasonic sensor). This should generate the following i2c command

<start><device address 0x2 (7 bits)><write 0x0 (1bit)><data1 0x41 - location><data 2 0x01 - command><stop>

What actually gets sent is...

<start><device address 0x2 (7 bits)><write 0x0 (1bit)><stop><data1 0x41 - location><data 2 0x01 - command><stop>

Note the extra stop.

This should probably be fixed in the vm by making changes to i2c.c but at the moment I'm not set up to build that code. Instead I've created a work around by making a change to the lejos.nxt.I2CSensor. Basically the change by-passes the automatic sending of the location and instead places it into the data....

Code: Select all
    public int sendData(int register, byte [] buf, int len) {
        // AS Fix to allow write to work correctly. Avoid using the
        // automatic internal address. Instead send the address as
        // part of the data
        if (len >= byteBuff.length) return -1;
        for(int i=0; i < len; i++ )
            byteBuff[i+1] = buf[i];
        byteBuff[0] = (byte)register;
        int ret = port.i2cStart(address, 0, 0, byteBuff, len+1, 1);
      
        if (ret != 0) return ret;
      
        while (port.i2cBusy() != 0) {
            Thread.yield();
        }
      
        return 0;
    }


I've only been able to test the above on an Ultrasonic sensor. I should have a compass arriving in a few days so I can try it with that. If anyone else has other I2C devices perhaps they could give it a try....

Andy
User avatar
gloomyandy
leJOS Team Member
 
Posts: 4004
Joined: Fri Sep 28, 2007 2:06 pm
Location: UK

Postby roger » Wed Oct 10, 2007 4:57 pm

Have you succeeded in getting the US sensor to return an array of distances to several objects ? If so, could you post the code?
Thanks
Roger
roger
Moderator
 
Posts: 359
Joined: Fri Jun 01, 2007 4:31 am
Location: Berkeley, CA

Postby gloomyandy » Wed Oct 10, 2007 8:20 pm

Hi Roger,
Yes I can use the single shot capability and get the set of 8 echo data. Here is my test program and re-implementation of the UltrasonicSensor class...
Code: Select all
import java.io.*;
import java.util.Vector;

import lejos.nxt.comm.*;
import lejos.nxt.*;

/**
 *
 * Abstraction for a NXT Ultrasonic Sensor.
 *
 */
class UltrasonicSensor extends I2CSensor
{
    byte[] buf = new byte[1];
   
    public UltrasonicSensor(SensorPort port)
    {
        super(port);
    }
   
    /**
     * Return distance of object.
     *
     * @return distance or 255 if no object in range
     */
    public int getDistance()
    {
        int ret = getData(0x42, buf, 1);
        return (ret == 0 ? (buf[0] & 0xff) : 255);
    }

    /**
     * Return array of 8 echo distances
     *
     * @return 0 for success <> 0 otherwise
     */
    public int getDistance(byte dist[])
    {
        if (dist.length < 8) return -1;
        int ret = getData(0x42, dist, 8);
        return ret;
    }
    /**
     * Send a single ping
     *
     * @return 0 if ok <> 0 otherwise
     *
     */
    public int ping()
    {
        buf[0] = 0x1;
        int ret = sendData(0x41, buf, 1);
        return ret;
    }

    /**
     * Switch to continuous ping mode
     *
     * @return 0 if ok <> 0 otherwise
     *
     */
    public int continuous()
    {
        buf[0] = 0x2;
        int ret = sendData(0x41, buf, 1);
        return ret;
    }
    /**
     * Turn off ping mode
     *
     * @return 0 if ok <> 0 otherwise
     *
     */
    public int off()
    {
        buf[0] = 0x0;
        int ret = sendData(0x41, buf, 1);
        return ret;
    }
    /**
     * Reset the device
     *
     * @return 0 if ok <> 0 otherwise
     *
     */
    public int reset()
    {
        buf[0] = 0x4;
        int ret = sendData(0x41, buf, 1);
        return ret;
    }
}


public class ustest
{
   
    public static void main(String[] args) throws Exception
    {
        UltrasonicSensor us = new UltrasonicSensor(SensorPort.S2);
        byte[] dist = new byte[8];
       
        // Turn things off for now
        us.off();
       
        while (!Button.LEFT.isPressed())
        {
            us.ping();
            try{Thread.sleep(20);}catch(Exception e){}
            us.getDistance(dist);
            for(int i = 0; i < 8; i++)
                LCD.drawInt(dist[i], 3, (i%4)*4, i/4);
            LCD.refresh();
            try{Thread.sleep(500);}catch(Exception e){}
        }
        LCD.drawString("Exit", 0, 4);
        LCD.refresh();
       
    }
}




Note 1: After a ping you need a small delay to allow the data to become available. I have not included the delay in the actual ping command so that the code can be used in applications that do not want to wait but which can do other things. However it may make sense to add this delay into the ping method...

Note 2: For the above code to work you will need that changes to the I2CSensor class detailed in my previous post.

All the best

Andy
User avatar
gloomyandy
leJOS Team Member
 
Posts: 4004
Joined: Fri Sep 28, 2007 2:06 pm
Location: UK

Postby lawrie » Thu Oct 11, 2007 9:23 pm

Its excellent that you have been able to make I2C writes work by just changing the Java.

No one has worked on I2C since Charles Manning wrote it 9 months ago. Charles reported problems getting the Ultrasonic sensor working reliably. He said he had writes working before he checked the i2c.c code in, but he then put the extra stop in to make the Ultrasonic sensor single read more reliable, and that broke the writes.

We are very short of programmers that can work on the C code in the firmware. Its really only me (with a bit of code donated by others) that has worked on the C code for the last 9 months, and I have not had time to look at i2c.

Do you plan to get the ARM toolchain working so that you can build the firmware?
lawrie
leJOS Team Member
 
Posts: 921
Joined: Mon Feb 05, 2007 1:27 pm

Postby CoBB » Fri Oct 19, 2007 11:18 am

This is quite interesting. If you look at the extra readings, it is possible to determine the relative angle of the surface to some extent, because the closer it is to being perpendicular to the line of sight, the more readings you get back and they seem to form a nearly arithmetic sequence if they are generated by the same object.
User avatar
CoBB
Novice
 
Posts: 73
Joined: Tue Apr 24, 2007 12:24 pm

Postby bbagnall » Sat Oct 20, 2007 6:46 pm

CoBB wrote:This is quite interesting. If you look at the extra readings, it is possible to determine the relative angle of the surface to some extent, because the closer it is to being perpendicular to the line of sight, the more readings you get back and they seem to form a nearly arithmetic sequence if they are generated by the same object.


That is pretty interesting. That type of info could be used by your robot to determine where it should move to, or when mapping out a floor plan.

BTW iCommand has a getDistances() method that returns up to 8 echoes. I haven't tested it in a while and seem to recall that it would work sometimes and not other times. It would be nice to have this method in leJOS NXJ.

EDIT: I updated Subversion with Andy's new code for I2C and UltrasonicSensor.
User avatar
bbagnall
Site Admin
 
Posts: 392
Joined: Fri Aug 04, 2006 4:03 pm

Postby gloomyandy » Sat Oct 20, 2007 9:46 pm

Hi Brian/folks,
Thanks for checking in the code. Just a quick update, I've got a complete update for the Ultrasonic class that I plan to check in over the next day or so. It contains code for all of the sensor functionality plus some adjustments to handle some of the rather "special" timing of the sensor.

I've also been taking a look at the problems with port 4, at the moment I have fixes for the light sensor floodlight not working and I've got some of the i2c sensors working on that port (so far the compass sensor seems to work). I'm trying to work out why the ultrasonic sensor is still not working and once I get that fixed I'll check the fixes in. These will need new firmware for the fixes to work.

One question do you think all of the methods should be in the one class, or do you think it is worth keeping some of the more esoteric methods (like the calibration functions etc.) in an extended class since it is likely that most people will not need them?

Andy
User avatar
gloomyandy
leJOS Team Member
 
Posts: 4004
Joined: Fri Sep 28, 2007 2:06 pm
Location: UK

Postby bbagnall » Sat Oct 27, 2007 4:22 pm

gloomyandy wrote:One question do you think all of the methods should be in the one class, or do you think it is worth keeping some of the more esoteric methods (like the calibration functions etc.) in an extended class since it is likely that most people will not need them?


If you mean the CompassSensor calibration function, that should definitely be available in the CompassSensor class for users.

I'd need to know what the other functions are that you are talking about. The "extended class" concept for rarely used methods doesn't really work for me. Generally if they are only used by your code internally then you would make them private (or protected if other classes in the same package need access to them). But if only 5% of users are going to use these esoteric methods, I would still include them in the class.
User avatar
bbagnall
Site Admin
 
Posts: 392
Joined: Fri Aug 04, 2006 4:03 pm

Postby gloomyandy » Sat Oct 27, 2007 7:43 pm

Hi Brian,
Well after more feedback, I've included all of the new functions in the updated class. The functions I was thinking about are the Ultrasonic sensor calibration functions, plus one or two to control things like ping interval when in continuous modes etc. My main concern was the memory usage of these extra functions since they are likely to be used very rarely by most users. Turns out that the system removes unused methods so this should not really be a problem. Hence they are all in the main class...

Andy
User avatar
gloomyandy
leJOS Team Member
 
Posts: 4004
Joined: Fri Sep 28, 2007 2:06 pm
Location: UK

Postby rganesh » Mon Apr 27, 2009 10:38 am

Hi Andy,

I am trying to get NXT communicate to an I2C Slave program running on a Parallax microcontroller. I am using lejos version 0.7. I can get the read working fine, but am up against a wall to get write running. I have tried various things for about 2 weeks now, and could am stuck. Using another parallax microcontroller running an I2C Master program I can get both read and write working. In both read/write case the device address is 0x10 (7 bit value), register address is 0x42. I would be thankful for any help.. here is what I have done:

1. As pointed out by you, sendData in the default lejos I2CSensor library ends up in sending an extra stop bit. To avoid this, I used the workaround suggested by you in the java code (i.e. keep number of internal bytes to zero..). But this still does not work.

2. I have an oscilloscope and hooked it up to see what happens (with the modified sendData). It turns out that an extra stop bit gets sent anyhow. I looked into the platform code for i2c.c and found that in the "third partial transaction" a stop bit is set:

<Quote>

if(n_internal_address_bytes == 0 || !write){
// Set up second partial transaction: restart and address
pt->start = (n_internal_address_bytes > 0) ? 0 : 1;
pt->restart = !pt->start;
pt->stop = 0;
pt->tx = 1;
p->addr = (address << 1) | (write ? 0 : 1);
pt->data = &p->addr;
pt->nbytes = 1;

pt++;
}

// Set up third partial transaction: data and stop
pt->start = 0;
pt->stop = 1; // <<<< A stop bit is set here??
pt->tx = (write ? 1 : 0);
pt->data = data;
pt->nbytes = nbytes;
pt->last_pt = 1;

// Start the transaction
p->state = I2C_BEGIN;

</Quote>

If I got it right, the workaround will result in the second and third partial transaction taking place. Is this right? Or do you think I am doing something wrong. The device address is 0x10 (7 bit value) and the internal register address is 0x42. As I said, the read of this register works fine. But trying to write to it is a failure.

Thanks for any help!

Ganesh
rganesh
New User
 
Posts: 4
Joined: Mon Apr 27, 2009 10:26 am
Location: Switzerland

Postby gloomyandy » Mon Apr 27, 2009 11:54 am

Hi,
This is a very old thread... In he latest version (0.7) of leJOS writes work fine (at least to the Lego spec). we use them to several different device types.... It is only read operations that the Lego way of doing things differs from the I2C standard so for a write things should be fine, you should just be able to use the standard sendData functions. If you have read working correctly I´m surprised that write does not work (as in effect you use a write to set up the read request). Is the Parallax system using hardware I2C or is it bit banged? How many bytes are you trying to send?

I´m pretty sure that an extra stop bit is not sent for a write operation, one is only sent at the end of the transaction (which is correct as it is releasing the bus).

Andy
User avatar
gloomyandy
leJOS Team Member
 
Posts: 4004
Joined: Fri Sep 28, 2007 2:06 pm
Location: UK

Postby rganesh » Mon Apr 27, 2009 1:37 pm

Hi Andy,

Thanks for the reply.

I am using the latest version 0.7 of lejos. The Parallax does not have native i2c hardware support but using bit banging on io pins. I am trying to send just one byte data. I will send you in a day or two the scanned image from oscilloscope printout when a sendData is called (I need to get a dso with printer, or make a photo of the screen.).
When I try to do a write to register 0x42 with value 0x12 with code like this:

setAddress(0x10);
sendData(0x42, 0x12);

The output on the bus ought to be:

<start><device address 0x10 (7 bits)><write 0x0 (1bit)><data1 0x42 - location><data 2 0x12 - command><stop>

Is this right?


Once again thanks for your help and tips!

Ganesh
rganesh
New User
 
Posts: 4
Joined: Mon Apr 27, 2009 10:26 am
Location: Switzerland

Postby gloomyandy » Mon Apr 27, 2009 2:27 pm

Hi,
The data you have is correct you should also see the device acknowledge the address and the data by pulling the SDA line low during the 9th bit clock. If you are still having problems then scans of the scope output would be good... If possible could you ensure that the scope output has the clock trace as well as the data trace. If you have a working connection (from another device), then a scan for that would also be good....

Andy
User avatar
gloomyandy
leJOS Team Member
 
Posts: 4004
Joined: Fri Sep 28, 2007 2:06 pm
Location: UK

Postby rganesh » Mon Apr 27, 2009 6:29 pm

Hi Andy,

I could finally determine the cause the problem - it was in the Propeller slave code. It was expecting the internal address to be two byte wide (!) and when it recieves one byte internal addr + one byte data the routine was resetting and during the reset it falsely generates the stop state on the sda pin. This got me confused and led me to think that the master was generating the stop bit. Finally I am happy that my project can go ahead!

Thanks for your patient replies.

Cheers

Ganesh
rganesh
New User
 
Posts: 4
Joined: Mon Apr 27, 2009 10:26 am
Location: Switzerland

Next

Return to NXJ Software

Who is online

Users browsing this forum: No registered users and 2 guests

more stuff