VEXPro ARM9 I2C support

Is there any update on I2C support in libqwerk for the VEXPro ARM9 controller? There is an open issue (#17) addressing I2C support on the terkos project issues page at code.google.com/p/terkos/issues/list. There someone indicated on Feb 21 2012 they are working on I2C support along with support for the new I2C Encoder but there hasn’t been any update on the status of this effort.

Has anyone developed their own library routines for basic I2C or the I2C encoder for the VEXPro? If so, and you’re willing to share the code I would really appreciate it. I purchased Motor 269 Integrated Encoder Modules last February but have been unable to use them with my VEXPro ARM9 controller since I don’t have any library routines that even support basic I2C.

Thanks to anyone who can help on this.

Rocco

I have a VEXpro but, to be honest, have not really done too much with it yet. I did look into the I2C support when I first received it, the FPGA implements this rather that the cpu directly, unfortunately it’s just a register that allows simple bit banged output. I though about putting better support into the FPGA but there’s not much room left and I have not had the motivation to do that yet. I could probably port some existing I2C bit bang libraries I wrote for another project if you really need it, it would just be vanilla C code and would need enhancing to handle multiple encoders. I will look into this next week unless someone has already done this (Quazar?).

I can not locate the Message, but IIRC, Quazar was working on some I2C Interfacing with the Vex Pro. He’s a little tied up with work right now, but I know he will be getting back to working on it sometime soon…

Any communication protocol done in Hardware is a benifit when it comes to speed of the communication, and how much time you Main Processes spend dealing with Bit Twiddling… Once you get it setup, I like to think of it as Fire and Forget…

I have a working solution, I need to clean up the code and make it a bit more user friendly but should be able to post something in the next couple of days.

Well a couple of days became a couple of hours.

Here is a zipped demo project that you can import into the Terk IDE that shows how to work with two VEX IMEs. See the source for details but the most important points are as follows.

  1. Get a pointer to the hardware using the C9302Hardware class.
  2. Pass a pointer to the FPGA I2C register to I2C_Init()
  3. For each encoder you have connected call VexIMEAddEncoder with the encoder type and whether it is the last in the encoder chain. example code might be as follows, see the demo code for more detail.
#include "i2c.h"
#include "ime.h"

// two encoders in demo
#define ENC_COUNT

// encoder types for the demo
static int enc_types[ENC_COUNT] = {IME_393T, IME_269 };

// storage for the encoder data
static imeData *MyIme[ENC_COUNT];

void 
InitVexEncoders(void)
{
    int     i;

    // Reset
    VexIMEResetAll();

    // add all the encoders
    for( i = 0;i<ENC_COUNT;i++ )
        {
        // Add encoders
        if( i == (ENC_COUNT-1) )
            MyIme* = VexIMEAddEncoder( LAST_ENCODER, enc_types* );
        else
            MyIme* = VexIMEAddEncoder( NOT_LAST_ENCODER, enc_types* );
        }
}
  1. call VexIMEUpdateCounts periodically to read the current encoder count, velocity and rpm. Again see the demo code.

  2. use the encoder data however you wish.

I have not tested with other parts of the libquerk running, there may still be bugs.

The I2C communication is implemented in software, we call this bit banging and there are some limitations to this approach. The most serious is that we spend a lot of time waiting in tight loops to create the timing, polling one encoder take approximately 1mS of cpu time, interrupts can still occur and do not seem to have a serious effect but I was not running much else when testing. The only real way around this is to add hardware support for the I2C in the fpga, essentially a shift register for the data output and counters to handle the clock generation. I don’t have time to do this anytime soon but may one day, it’s not that hard but I mostly do VHDL rather than verilog so it needs a little more effort.

This code is also plain C rather than C++, I may wrap it in a class for another release but have spent enough time on this today already. Implementation was not difficult after I realized that the VEX encoder wants to use clock stretching which the original I2C code was not setup to do.

Anyway, hopefully this will get you going, let me know.

James.****

1 Like

Thanks James (jpearman), for your prompt response to this. You provided a very complete driver for the VEX IMEs. I just had a few minutes to skim over the code during lunch at work, but it looks like exactly what I was looking for. I’ll be trying this out over the next few days and get back with any questions.

Rocco

There’s still an issue with initialization, I tried with 4 encoders and it’s intermittent, something to do with the disabling of terminations. I need to put the scope on and see what’s happening then will post an update.

Edit:

Ok, here is an update, termination acts a little weird. This version sends an enable termination command to the default address before that encoder is changed to the new address. Termination does not seem to effect the clock lines and the data line has either crosstalk or some type of leakage that can cause (I’m guessing here) some issues with downstream encoders. Anyway, this version does away with the magic delays and seems to work much better. I also changed some of the I2C low level code to catch some errors and then terminate the communications more correctly, there was a situation where clock line was not being set high after a transaction. Main change to the initialization looks like this.

       // seems enabling the termination of the default devices help initialization
        VexIMEEnableTermination( ime->address );

        // Set new address
        VexIMESetAddr( &ime->address, nextImeAddress );
        nextImeAddress += 2;

        // Give a little time to set new address
        usleep(1000);

        // Get encoder information
        VexIMEGetVersion( ime->address, ime->version );
        VexIMEGetVendor( ime->address, ime->vendor );
        VexIMEGetDeviceId( ime->address, ime->deviceid );

        // clear encoder counters
        VexIMEClearCounters( ime->address );

        // if we are not the last encoder in the chain then disable termination
        if( !last_encoder ){
            VexIMEDisableTermination( ime->address );
            }

The VEXpro has to cope with the situation of re-initialization if the code is killed and restarted, this is not something the cortex has to worry about as initialization only needs to occur on power on.

Here’s the updated project. (original version has been deleted)
ImeDemoB.zip (125 KB)

1 Like

James,

I was able to get your ImeDemoB program to work with two 269 motors. From the IME LED flashes, I could tell that the motor directly connected to the VEXPro was initialized and not terminated and the motor daisy-chained to the first motor was initialized and terminated, as they should be. When I ran the motors, the counters and other data looked correct.

Thanks again for sharing you code. I now can remove the old quad encoders from my robot and start using the IMEs.

Rocco

I’m glad it worked out for you. Please remember there are some limitations to this software based approach. Don’t poll the encoders too often, perhaps 100Hz maximum rate for two encoders which will use up about 25% of your cpu bandwidth. Let me know if you run into any problems.

1 Like