Announcement

Collapse
No announcement yet.

I2C Devices - expanding Picasso functionality ANALOG/DIGITAL CONVERSION

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • I2C Devices - expanding Picasso functionality ANALOG/DIGITAL CONVERSION

    The Picasso based 4D systems devices offer great flexability and functionality along with great Value for money.
    They do lack a few on board hardware options such as PWM or Analog to Digital conversion. They are however, equipped with an I2C interface which allows easy connectivity with various I2C based devices which can cover the small amount of on board short comings.... and more.

    For an explanation of the I2C bus see here :-
    I2C-Bus: What's that?
    http://www.i2c-bus.org/
    There are a wide range of I2C based devices available such as
    1. DAC's
    2. ADC's
    3. GPIO expander's
    4. PWM drivers
    5. Motor Controllers
    7. Motion and light Sensors
    8. Movement, Gyro and Accelerometers
    and many more..


    In this thread i will detail my adoption of a 10 channel Analog to digital converter I2C device to the Picasso.
    The device i Choose was a very good value for money 10 channel A/D converter with 10bit resolution.
    http://www.byvac.com/downloads/datasheets/BV4205%20DataSheet.pdf

    The device cost a Total of 3.60 UKP delivered which is great value.

    http://www.byvac.com/bv3/index.php?route=product/product&path=54&product_id=77


    The BV4205 is an I2C two wire compatible
    integrated circuit with a 10 channel 10 bit A to
    D converter. The IC works independently of
    the micro controller and can acquire analogue
    signals continuously until required.
    2. Features
    â I2C up to 400kHz
    â Simple command set
    â 10 channels x 10 bits
    â Differential input 1023
    â 2 us Conversion time
    â 5 us Acquisition time
    â Can continuously monitor all channels
    â Vref selectable
    â EEPROM for general use
    â Sleep mode to save power
    â Operating voltage 2.0 to 5.5V
    â Current 1.8mA @ 5V
    â Sleep current 200uA


    Our Current hardware is a VGA-II which is running a 5.6" TFT screen embedded in a car dashboard. Our Data being displayed is polled from an open source transmission ECU serially. We could have used CAN-BUS but this would have meant another slave device such as an MBED. We decided that as well as transmission data we would like various engine data to be displayed, a majority of which is derived from 5v sensors. The other sensors are Resistance based, and using voltage divider circuits we can obtain a variable voltage from these to obtain data.

    Our display at testing phase looks like this..


    we also use the Picasso's I/O pins to determine if devices like the lights are switch on, for example here we use the 4DGL replace colour command when we have an input on the headlight switch to change the dial outline from white to green (the colour of the stock illumination)



    Like many others on here i am an novice to electronics and embedded systems, so bare with me

    Through this Particular thread i will detail building a small carrier board for the BV4205, hardware wiring, 4dGL coding, and finally and example using a 5v throttle position sensor, a 5v pressure sensor/map sensor and a 3 axis accelerometer to show corning, acceleration and braking G-force.

    The first task was to contract a small board to carry the BV4205

    [img width=448 height=317]https://fbcdn-sphotos-f-a.akamaihd.net/hphotos-ak-prn1/557490_10151212892816138_1259337046_n.jpg[/img]

    [img width=603 height=804]https://fbcdn-sphotos-b-a.akamaihd.net/hphotos-ak-snc7/386981_10151212807856138_2083904362_n.jpg[/img]

    A few notes to mention on the BV4205...

    PIN4 (not labeled) - Must be connected to ground
    PIN 11(SCK) this is the I2C clock, a pull up resistor is required. I used 4k7
    pull up to power source (on pin1)
    PIN 13 (SDA) this is the I2c data, a pull up resistor is requiredI used 4k7
    pull up to power source (on pin1)

    When finished, connected up to the VGA-II and installed a MMA7361LC 3-Axis Analog Acceleration Sensor Module to the board, using just the X,Y inputs to A6 and A7 on the BV4205

    [img width=624 height=830]https://fbcdn-sphotos-d-a.akamaihd.net/hphotos-ak-snc7/383369_10151212808006138_1643264056_n.jpg[/img]


    Now for the Programming...

  • #2
    ..so the first step is to actually test the device, and the Data sheet specifies that :-

    Format: < S-addr><0x55><start><RAddr><Value..><NACK><Stop>
    Example
    0x42>s 55 r g-3 p
    The above command will return 1,2,3 if the
    device is connected and working correctly.
    This command simply returns an incrementing
    value until NACK is sent by the master prior to
    stop. This can be useful for testing the
    interface.
    It can be used for testing the presence or
    other wise of a device at a particular address.
    It is also useful during the development stage
    to ensure that the I2C is working for that
    device.

    My First try at implementing the code seems to have hit a brickwall. For some reason when using flags to trace each step, the program hangs at the I2C_Nack

    my simple code to test the device

    #platform "uVGA-II_GFX2"


    //------------------------------//
    // I2C Functions //
    //------------------------------//
    /*
    I2C_Open("speed"); // Configure the I2C module, speed can be I2C_SLOW, I2C_MED, I2C_FAST (100khz, 400khz, 1mhz)
    I2C_Close(); // Disable the I2C1 module.
    I2C_Start(); // Generate a Start condition.
    I2C_Stop(); // Generate a Stop condition.
    I2C_Restart(); // Generate a Restart condition.
    I2C_Read(); // Read a single byte from the I2C Bus.
    I2C_Write("byte"); // Write a byte to the I2C bus, Returns TRUE if ok
    I2C_Ack(); // Generate the acknowledge condition.
    I2C_Nack(); // Generate the negative acknowledge condition.
    I2C_DataRdy(); // Return TRUE if the I2C receive buffer is full.
    I2C_Idle(); // Wait until the I2C Bus is Inactive.
    I2C_Gets("buffer", "length"); // Read length bytes from the I2C device to a buffer
    I2C_Puts("buffer"); // Write an asciiz string to the I2C device
    */

    var resulta;
    var resultb;
    var resultc;



    func main()
    I2C_Open(I2C_SLOW); // 400khz medium speed
    I2C_Idle(); // Wait for bus Idle
    I2C_Start(); // Generate Start condition
    I2C_Write(0x62); // send BV4205 address
    I2C_Idle(); // Wait for bus Idle
    I2C_Write(0x55); // Send command for test
    I2C_Idle(); // Wait for bus Idle
    I2C_Start(); // Generate Start
    I2C_Write(0x63); // Send BV4205 memory read address
    I2C_Idle(); //Wait for the bus
    I2C_Restart(); // Generate start to initiate read
    resulta := I2C_Read(); //read byte1
    resultb := I2C_Read(); //read byte2
    resultc := I2C_Read(); //read byte3
    I2C_Nack(); // finished reading, send Not Ack
    I2C_Stop(); // Send Stop Condition
    I2C_Close();


    repeat

    txt_Set(3, 2);
    txt_Set(4, 2);
    gfx_MoveTo(140, 140);
    print("I2C ADC TEST\n");
    print ("Test data =",resulta," , ",resultb," , ",resultc ) ;

    forever
    endfunc


    I have been told that the address 0X62 is correct for 8bit addressing, but if using 7bit addressing it will be 0X31. I have tried with X031 as device address and 0x32 as read address but still program hangs at the Nack...


    Comment


    • #3


      UPDATE

      To eliminate any hardware errors i build a new board and fitted a new GPIO/PWM IC. The test command for this IC is the same, apart from a different hardware address.

      I2C_Open(I2C_SLOW);
      I2C_Idle(); // Wait for bus Idle
      I2C_Start(); // Generate Start condition
      flag[1]:=I2C_Write(0x42); // send harware ID address
      I2C_Idle(); // Wait for bus Idle
      flag[2]:=I2C_Write(0x55); // Send command for test
      I2C_Idle(); // Wait for bus Idle
      I2C_Start(); // Generate Start
      flag[3]:=I2C_Write(0x43); // Send memory read address
      I2C_Idle(); //Wait for the bus
      I2C_Restart(); // Generate start to initiate read
      resulta := I2C_Read(); //read byte1
      resultb := I2C_Read(); //read byte2
      resultc := I2C_Read(); //read byte3
      I2C_Nack(); // finished reading, send Not Ack
      I2C_Stop(); // Send Stop Condition
      I2C_Close();


      My flags are all returning a value of 1, BUT the code is hanging at the I2C_Nack() command. Any ideas???

      Comment


      • #4


        Ok, i have used the Following code, and now have 1,2,3 being returned in my results a,b,c

        I2C_Open(I2C_MED); // 100khz medium speed
        I2C_Idle(); // Wait for bus Idle
        I2C_Start(); // Generate Start condition
        flag[1]:=I2C_Write(0x62); // send BV4205 address
        I2C_Idle(); // Wait for bus Idle
        flag[2]:=I2C_Write(0x55); // Send command for test
        I2C_Idle(); // Wait for bus Idle
        I2C_Restart(); // Generate Start
        flag[3]:=I2C_Write(0x63); // Send BV4205 memory read address
        I2C_Idle(); //Wait for the bus
        resulta := I2C_Read(); //read byte1
        I2C_Ack();
        resultb := I2C_Read(); //read byte2
        I2C_Ack();
        resultc := I2C_Read(); //read byte3
        I2C_Nack(); // finished reading, send Not Ack
        I2C_Stop(); // Send Stop Condition
        I2C_Close();

        Comment


        • #5


          Just another quick note, I have used pullups on my boards, but according to the Specs anyone using a uVGA-II should not need these as they are already in place. See attachment

          Attached files

          Comment


          • #6


            Setting the IC to Autoscan free's up the Picasso to get on with other jobs.
            To do this we use Command 6 - Name: ADC Autoscan
            The Format for this command is :



            This is disabled (set to 0) at reset. When enabled the device will scan all the 10 channels and store the results internally to RAM in a round robin fashion.
            With this working there is no need to select (command
            1), convert (command 2) and then read command 4) a channel as they are being monitored on a continuous basis.
            Each channel takes approximately 25uS with an acquisition delay of 2 so all of the channels will be scanned in approximately 450uS.
            Reading any channel with therefore be a maximum of 450uS old.


            In this function we will use a variable of either 0 or 1 to switch the autoscan state....

            // function to Set ADC AutoScan on/off
            func setautoscanon (var switch) // 1=on 0=off
            I2C_Idle(); // Wait for bus
            I2C_Start(); // Generate Start condition
            I2C_Write(0x62); // send BV hardware address
            I2C_Idle(); // Wait for bus
            I2C_Write(6); // select 6 Command for autoscan
            I2C_Idle(); // Wait for bus
            I2C_Write(switch); // Switch Autoscan function on/off
            I2C_Idle(); // Wait for bus
            I2C_Stop(); // Stop I2C communication
            endfunc

            Comment


            • #7


              Reading the Value of the Analog input channels 0-9

              Command 7
              Name: Read Autoscan
              Format: : < S-addr>

              The Previous Command 6 will carry out a conversion and store the results to 20 bytes of RAM contained within the chip.
              This command will read one or more of those ram locations. Each read is 2 bytes followed by a ACK or NACK. If ACK is used it informs the IC that
              another two bytes will be read, if NACK is used it informs the IC that this will be the last byte pair.
              Using this method one or more locations can be read. Start is the first value (byte pair) to read.
              Example
              To read channels 4 to 6 use a start value of 8 and read 3 byte pairs (6 bytes). To read just channel 8, use a start value of 16 and read just one byte pair.

              In my example function, i will pass the channel to be read, and have the converion value returned. Note :- I have this code running fine at 1MHZ speed.

              func readadcchannel(var adcchannel)

              adcchannel:= adcchannel*2 ; // convert to 2byte step i.e. channel 8 = read from byte 16
              I2C_Idle(); // Wait for bus Idle
              I2C_Start ; // Generate Start condition
              I2C_Write(0x62); // send ADC address
              I2C_Idle(); // Wait for bus Idle
              I2C_Write(7); // Send command for read channel
              I2C_Idle(); // Wait for bus Idle
              I2C_Write(adcchannel); // send control byte for channel to be Read i.e. 6
              I2C_Idle(); //wait for bus Idle
              I2C_Restart(); // Generate reStart for read
              I2C_Write(0x63); // Send BV4205 memory read address
              I2C_Idle(); // Wait for Bus idle
              adcresult1hi:=I2C_Read(); // Read the Hi byte of channel (adcchannel)
              I2C_Ack(); // Send Ack that byte is read and another will follow
              adcresult1lo:=I2C_Read(); // Read the Low byte
              I2C_Nack(); // finished reading, so we send Not Ack
              I2C_Stop();
              r:= (adcresult1hi * 256) + adcresult1lo; // make a 10bit result from the H/L Bytes
              return r ;
              endfunc




              The code could be easily modified to read groups of channels, but as we are only intrested in any 1 particualar channel at any one time, this should surfice.

              Comment


              • #8


                Thanks Marty, we all appreciate your effort, keep up the good work
                Atilla

                Comment


                • #9


                  hi,

                  can i follow this similar solution, but use an uOLED-128-G1 instead of the Picasso?
                  thanks.

                  Comment


                  • #10


                    Goldelox has builtin ADC and onewire support, if that's what you want/need then you could certainly use that, but you wont quite get the number of inputs shown here
                    Mark

                    Comment


                    • #11


                      thanks...
                      could i use the uOLED-128-G1 to control & communicate with the BV4205?
                      so that i could use the BV4205 to capture 10 different analog feeds, then poll/read the data with the uOLED-128-G1 (instead of using a Picasso & BV4205) ?


                      thanks,
                      Brett

                      Comment


                      • #12


                        No, Goldelox doesn't have I2C.
                        Mark

                        Comment


                        • #13


                          is there an I2C IC i could put between the uOLED-128-G1 and BV4205 that the uOLED-128-G1 could communicate with? if so, any recommendations?

                          thanks

                          Comment


                          • #14


                            Brett you could try using one of the Texas Instruments MPS430 series mixed signal controllers, some have both i2c and serial i/o on separate pins. Depending on the version some have up to 8x 10bit ADCs as well so you may not even need the BV4250.

                            TI produce a very cheap dev board (LaunchPad) to help you get started - try RS or element14.

                            Comment

                            Working...
                            X