Verdex + Robostix - Combining I2C with a Controller?

View: New views
5 Messages — Rating Filter:   Alert me  

Verdex + Robostix - Combining I2C with a Controller?

by p.g.adamczyk :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi, List,

Using a Verdex XM4BT and a Robostix, I have long had the i2c-io code (by Dave Hylands) working, with some modifications for time-regular data logging to the gumstix (~100 hz).

A separate project uses the Robostix as a servo controller, operating based on some analog sensors. The code is extremely simple, just a couple dozen lines.

I am now trying to combine these two functions, so I can use i2c-io and my data logging modifications while the controller is running.

However, when I combine the controller code (based on the Simple-Servo example) with the i2c-io code, I get i2c failures - specifically, the robostix no longer passes the correct i2c commands to the i2c-io "ProcessCommand" function.

I know this because when my gumstix code sends command 11 (0x0b, case "I2C-IO-Get-ADCs"), the i2c-io function "ProcessCommand" receives command 3 (0x03, which is case "I2C-IO-SET-GPIO") [tested by turning LEDs uniquely within various commands until I found the one that was receiving it]. Then I assume there is an error, and what gets returned must be junk of some kind to cause these error messages:

I get errors back such as:
1) [for a call for a single ADC channel]
root@gumstix-custom-verdex:~$ i2c-io 0x0b get ADC.0
ERROR: I2cTransfer: length is too big: 3 max: 2
ERROR: I2cTransfer: CRC failed: Rcvd: 0xff, expecting: 0x24
ERROR: I2C_IO_GetADC: I2cProcessBlock failed: Success (0)
ERROR: Failed to retrieve value for ADC.0

2) [for a call to get multiple ADC channels per my special i2c command "I2C_IO_GET_ADCs", asking for 5 channels (10 bytes)]
ERROR: I2cTransfer: length is too big: 188 max: 10
ERROR: I2cTransfer: CRC failed: Rcvd: 0xff, expecting: 0xf5
ERROR: I2C_IO_GetADCs: I2cProcessBlock failed: Inappropriate ioctl for device (25)


The Question is: Is there any known reason that the PWM outputs, Timers, Analog inputs, or any other normal controller code would interfere with i2c communications?

My code below, based on i2c-io and Simple-Servo. This code interfaces to other standard functions in the Robostix sample libraries.

Thanks for any help anyone can offer,
Peter

Code:
/**

*

*   @file   RNL_Controller

*

*   @brief  This file implements (1) a Controller for the RNL, and (2) a set of I2C commands which allows the

*           robostix I/O to be controlled by the gumstix.
*
*   Modified from i2c-io, by Dave Hylands

*

*****************************************************************************/



/* ---- Include Files ----------------------------------------------------- */



#include <avr/io.h>

#if defined( __AVR_LIBC_VERSION__ )

#   include <avr/interrupt.h>

#else

#   include <avr/signal.h>

#endif

#include <compat/twi.h>

#include <stdio.h>

#include <inttypes.h>



#include "i2c-io.h"

#include "Hardware.h"

#include "i2c-slave-boot.h"

#include "Log.h"

#include "Delay.h"

#include "Timer.h"

#include "UART.h"

//#include "Config.h"
//#include "Config-LED.h"
//#include "Robostix.h"

#include "svn-version.h"



//Peter's

#include "a2d.h"

//#include "Config.h"

#include "PinPulse.h"

// //Peter's



/* ---- Public Variables -------------------------------------------------- */



/* ---- Private Constants and Types --------------------------------------- */



/* ---- Private Variables ------------------------------------------------- */

//--------------------------------------------------------------------------

//

// Servo pins (relies on definitions from Timer.h)

//



#define SERVO_1 3A



#define SERVO__( ocr, reg )     TIMER_ ## ocr ## _ ## reg

#define SERVO_( ocr, reg )      SERVO__( ocr, reg )

#define SERVO( num, reg )       SERVO_( SERVO_ ## num, reg )





//--------------------------------------------------------------------------

// Program Constants

//

#define numpts 15u // Points to average in the moving average

#define walkingmovavgthresh 14u // Number of bits away from the 2.5V Nominal Output that the "numpts" -point moving average should be to indicate Walking mode.

#define walkmode_usec 900u // Microseconds for the Servo Pulse that commands Walking mode

#define standmode_usec 2100u // Microseconds for the Servo Pulse that commands Standing mode

#define decisiondelay 100 // Number of Cycles (at 100Hz) to wait after changing the state before it can change again.

// //Peter's
#define TCNT2DIVISOR   TIMER2_CLOCK_SEL_DIV_1024   // Set the Timer2 Clock Divisor (divisor for 16 MHz clock)
#define TCNT2RESETVALUE      99 // With 1024 Divisor, setting the Reset value to be 99 yields 100 Hz interrupts on Timer2:  16e6/1024/(255-99) = 100.1603


//Peter's

// Output (Interrupt Pulse on PORTE.2)

// Make pin 2 on Port E an output, ready to Interrupt the Gumstix

#define GumInt_DDR   DDRE

#define GumInt_PORT  PORTE

#define GumInt_PIN   PINE

#define GumInt_PIN_MASK  ( 1 << DDE2 ) // Pin 0: 1 is a bit that selects a channel. DDE2 shifts it left (<<) DDE2 positions.

// //Peter's
#define TCNT2RESET   99



// Fake out ports that don't exist

#define NUM_PORTS   7



#if !defined( PORTA )

#define PORTA   PORTB

#define DDRA    DDRB

#define PINA    PINB

#endif



#if !defined( PORTE )

#define PORTE   PORTB

#define DDRE    DDRB

#define PINE    PINB

#endif



#if !defined( PORTF )

#define PORTF   PORTB

#define DDRF    DDRB

#define PINF    PINB

#endif



#if !defined( PORTG )

#define PORTG   PORTB

#define DDRG    DDRB

#define PING    PINB

#endif



volatile uint8_t *gPORT[ NUM_PORTS ] =

{

    &PORTA, &PORTB, &PORTC, &PORTD, &PORTE, &PORTF, &PORTG

};



volatile uint8_t *gDDR[ NUM_PORTS ] =

{

    &DDRA, &DDRB, &DDRC, &DDRD, &DDRE, &DDRF, &DDRG

};



volatile uint8_t *gPIN[ NUM_PORTS ] =

{

    &PINA, &PINB, &PINC, &PIND, &PINE, &PINF, &PING

};



/* ---- Private Function Prototypes --------------------------------------- */



#undef  LED_ON

#undef  LED_OFF



#define LED_OFF()   do { CFG_BOOTLOADER_BEAT_PORT &= ~CFG_BOOTLOADER_BEAT_MASK; } while (0)

#define LED_ON()    do { CFG_BOOTLOADER_BEAT_PORT |=  CFG_BOOTLOADER_BEAT_MASK; } while (0)





#define IO_LOG_ENABLED  0



#if IO_LOG_ENABLED

#   define  IO_LOG0( fmt )                      LogBuf0( "IO: " fmt )

#   define  IO_LOG1( fmt, arg1 )                LogBuf1( "IO: " fmt, arg1 )

#   define  IO_LOG2( fmt, arg1, arg2 )          LogBuf2( "IO: " fmt, arg1, arg2 )

#   define  IO_LOG3( fmt, arg1, arg2, arg3 )    LogBuf3( "IO: " fmt, arg1, arg2, arg3 )

#else

#   define  IO_LOG0( fmt )

#   define  IO_LOG1( fmt, arg1 )

#   define  IO_LOG2( fmt, arg1, arg2 )

#   define  IO_LOG3( fmt, arg1, arg2, arg3 )

#endif



int ProcessCommand( I2C_Data_t *packet );



/* ---- Functions --------------------------------------------------------- */



//***************************************************************************

/**

*   Main loop for the I2C I/O program.

*/



int main(void)

{

    uint8_t     i = 0;

    uint8_t     j = 0;

    uint8_t k = 0;



    uint16_t AnalogBuffer[ numpts ];



    for (i=0; i<numpts; i++)

    {  AnalogBuffer[i]=0;  }





    InitHardware();



//    CFG_BOOTLOADER_BEAT_DDR |= CFG_BOOTLOADER_BEAT_MASK;



    // The first handle opened for read goes to stdin, and the first handle

    // opened for write goes to stdout. So u0 is stdin, stdout, and stderr



#if IO_LOG_ENABLED



#if defined( __AVR_LIBC_VERSION__ )

    fdevopen( UART0_PutCharStdio, UART0_GetCharStdio );

#else

    fdevopen( UART0_PutCharStdio, UART0_GetCharStdio, 0 );

#endif

    LogInit( stdout );



    Log( "*****\n" );

    Log( "***** I2C I/O program (I2C addr: 0x%02x\n", TWAR >> 1 );

    Log( "*****\n" );



#endif // IO_LOG_ENABLED



    if ( !I2C_SlaveBootInit( ProcessCommand ))

    {

        LogError( "I2C_SlaveBootInit failed\n" );


        while ( 1 )

        {

            ;

        }

    }



//Peter's

// GumInt Pin Initialization

        GumInt_DDR |= GumInt_PIN_MASK; // Configure as an output by setting the relevant pin's direction (DDR) high

        GumInt_PORT &= ~GumInt_PIN_MASK; // Set the pin state Low to begin

       

       

        // Clock for Encoder Interrupts

    // Setup Timer2 to overflow about 61 times per second  (8 bit = 256 counts, at [16MHz]/[1024 prescaler]).  

        TCCR2 = TIMER2_CLOCK_SEL_DIV_1024;    //This line sets the clock speed for the Timer2 (= 16000000 / 1024)

        //TCCR2 = TIMER2_CLOCK_SEL_DIV_256;  // Wisit's, test for 61*4 = ~ 244 Hz. (in reality, results in ~106 Hz.)

        //TCCR2 = TIMER2_CLOCK_SEL_DIV_64;

        TIMSK |= ( 1 << TOIE2 );           //Set Timer Interrupt MaSK (one byte, all zeros initially) to have a 1 in spot TOIE2 (Timer Overflow Interrupt Enable 2), which is Bit 6 of TIMSK.

       

       

        // toe_pot_neutral = toe_pot_neutral + (uint16_t)gADC[ 0 ]; // Not sure what the (uint16_t) part does...maybe a type conversion?

       



       

        // Initialize LEDs

// LED_ON( );

// //Peter's

    sei();



    // If we run Timer 3 (a 16 bit timer) at 2 MHz (divide by 8 prescalar)

    // then it will overflow every 32.7 msec which is suitable for driving

    // R/C servos.

    //

    // However, we can do better. If we set TOP to 40,000, we get

    // 40,000 1/2 usec (i.e. 2 MHz) counts or about 20 msec between pulses

    // (50 Hz) which is an even better pulse rate for R/C servos.

    //

    // We use WGM mode 14, Fast PWM with the TOP value supplied by ICR3.

    // We use COM mode 2, which causes the OC3x pin to be cleared (0) on a match

    // with OCR3x and set (1) when the timer reaches TOP.

 

    ICR3 = 40000u;

    SERVO( 1, OCR ) = 1500u * 2;   // 1500 usec is servo mid point; //This statement goes through Macros above to become "TIMER_3A_OCR = 1500u*2". After Timer.h, it is "OCR3A = 1500u*2"

    TCNT3 = 0;



    // Set the WGM mode & prescalar  (Waveform Generation Mode): WGM = 0b1110 = 14 in decimal: Fast PWM using ICR3 (Input Compare Register value) as TOP



    TCCR3A = ( 1 << WGM31 ) | ( 0 << WGM30 ); // WGM31 and WGM30 are the rightmost bits of TCCR3A (p133 of ATMega 128 manual)

    TCCR3B = ( 1 << WGM33 )  | ( 1 << WGM32 ) | TIMER3_CLOCK_SEL_DIV_8; // WGM33 and WGM32 are in the middle of TCCR3B

                                                                        // TIMER3_CLOCK_SEL_DIV_8 sets the Right 3 bits.  These three bits control the Prescaler.

                                                                        // The Left two bits are for Input Capture options. Bit 6 is unused.



    // Set the servo pins to COM (Compare Output Mode) mode 2 (COM_1 = 1, COM_0 = 0): ATMega 128 manual p134

    // This causes the OCR pin to fall when the counter reaches the value

    // stored in the OCR register and causes the OCR pin to rise when the

    // counter reaches TOP (gets reset to zero).



    SERVO( 1, TCCRA ) |= ( 1 << SERVO( 1, COM_1 )); // Calls the Macros defined above to become: "TIMER_3A_TCCRA |= TIMER_3A_COM_1;". Further definitions of these variables are in Timer.h. End result is: "TCCR3A |=

                 

    // Set the servo pins to be outputs



    SERVO( 1, DDR ) |= SERVO( 1, MASK ); // Calls the Macros defined above to become: "TIMER_3A_DDR |= TIMER_3A_MASK". Further definitions in Timer.h give "DDRE |= 0b00001000": that is, set Pin 3 of Port E to be an Output.







    uint16_t sample = 0;

    uint16_t movingsum = 0;

    uint16_t walkingmovsumthresh = numpts*walkingmovavgthresh ;

    uint16_t    pulse1_usec;



  while( 1 )

    {

  ;



        for (j=0; j<numpts; j++) // Adamczyk's loop for getting an Analog sample to fill a buffer, and update a moving average

        {



        // Read the ADC's



                sample = a2d_10( 0 ) ; // read Channel 0 through functions in a2d_10.c, as included by a2d.h

                movingsum -= AnalogBuffer[ j ] ; // Remove the obsolete sample from the Moving Sum

                AnalogBuffer[ j ] = abs( sample - 511u) ; // Store in the Buffer the absolute value of the difference between the Sample and 511 (where 511 bits == 2.5V)

                movingsum += AnalogBuffer[ j ] ; // Add the new Sample to the Moving Sum

       

                if ( k >= decisiondelay) // Only allow a state switch if the decision delay counter "k" has exceeded the specified delay.

                {

                  if (movingsum > walkingmovsumthresh) // IF the moving sum of absolute deviations from 0 angular velocity (in bits) is greater than the threshold value... THEN we are in Walking.

                        { if (pulse1_usec == standmode_usec) // detect if current mode setting is Stand

                          { k = 0; } // If so, then the present setting to WALK is a Switch; reset the delay counter.



                          pulse1_usec = walkmode_usec; // Set the control to Walking mode.

//  LED_ON(YELLOW);

//  LED_OFF(BLUE);

                        }

                        else // ELSE we are in Standing.

                        { if (pulse1_usec == walkmode_usec) // detect if current mode setting is Walk

                          { k = 0; } // If so, then the present setting to STAND is a Switch; reset the delay counter.



                          pulse1_usec = standmode_usec; // Set the control to Standing mode.

//  LED_OFF(YELLOW);

//  LED_ON(BLUE);

                          k = 0;

                        } //end of "if-else"

                } //end of "if k >= decisiondelay"

          else // else k < decisiondelay

                { k++; }  // increment k only if it is not over the "decisiondelay" threshold

       



        // We then need to multiply the pulse in usec by 2, since our timer

        // runs with 1/2 usec ticks.  

                // Note that The OCR3x registers are double buffered so we can set them at any

        // time.



        SERVO( 1, OCR ) = pulse1_usec * 2;    // * 2 is because timer ticks every 1/2 usec. // Command translates to "OCR3A = pulse1_usec *2"



        // We put a delay in here so we aren't trying to update the OCR

        // registers too frequently.



        WaitForTimer0Rollover(); // This Rollover occurs every 10 msec (100 Hz), so we are stuck with that sample rate if we use this function for the delay.



        if (j==-10)

        {  LED_TOGGLE( RED );  } //Just for fun, toggle Red LED at each recycle of the buffer.



        }  // end of "for j<numpts"


 

   }  // end "while (1)" loop



    return 0;

} // main



//***************************************************************************

/**

*   I2C Interrupt service routine

*/



SIGNAL(SIG_2WIRE_SERIAL)

{

    if ( !I2C_SlaveBootHandler() )

    {

        LogError( "Unrecognized status: 0x%x\n", TW_STATUS );

    }



    // Now that we've finished dealing with the interrupt, set the TWINT flag

    // which will stop the clock stretching and clear the interrupt source



    TWCR |= ( 1 << TWINT );



} // SIG_2WIRE_SERIAL




// Peter's code to signal Port.E2

//Tell the board to produce a pulse when Timer 2 overflows

ISR( TIMER2_OVF_vect )  //This sets the "Interrupt Service Routine" that happens when Timer2 Overflows

{

        PinPulse_Issue( GumInt );   //The routine is "PinPulse," which rapidly puts the pin high and then low.
        TCNT2 = TCNT2RESET; // Reset the TCNT2 Register to a non-zero value to fine-tune the frequency. This value can be between 0 and 255. The Frequency achieved will depend on the Prescaler as well. For prescaler = 256 and TCNT2 reset value = 130, we should interrupt at exactly 500 Hz. It works pretty well, though 500hz appears to be too fast for 8 channels even in fast mode of i2c.

                                //GumInt is a string that will be prepended to a bunch of variable names to make the functions happen

}

// //Peter's





//***************************************************************************

/**

*   Callback called to process incoming i2c commands.

*/



int ProcessCommand( I2C_Data_t *packet )

{

    int     rc;

    uint8_t cmd = packet->m_data[ 0 ];



    switch ( cmd )

    {

        case I2C_IO_GET_INFO:

        {

            I2C_IO_Info_t   *info = (I2C_IO_Info_t *)&packet->m_data[ 1 ];



            IO_LOG0( "GetInfo\n" );



            info->version       = I2C_IO_API_VERSION;

            info->minVersion    = I2C_IO_API_MIN_VERSION;

            info->svnRevision   = SVN_REVISION;



            packet->m_data[ 0 ] = sizeof( *info );



            return sizeof( *info ) + 1; // + 1 for len

        }



        case I2C_IO_GET_GPIO:

        {

            I2C_IO_Get_GPIO_t *req = (I2C_IO_Get_GPIO_t *)&packet->m_data[ 2 ];  // +1 for cmd, +1 for len

            uint8_t         portNum = req->portNum;



            if ( portNum > NUM_PORTS )

            {

                portNum = 0;

            }



            packet->m_data[ 0 ] = 1;

            packet->m_data[ 1 ] = *(gPIN[ portNum ]);



            IO_LOG2( "GetGPIO Port %c: 0x%02x\n", portNum + 'A', packet->m_data[ 1 ]);

            return 2;

        }



        case I2C_IO_SET_GPIO:

        {

            I2C_IO_Set_GPIO_t *req = (I2C_IO_Set_GPIO_t *)&packet->m_data[ 2 ];  // +1 for cmd, +1 for len

            uint8_t     portNum = req->portNum;

            uint8_t     pinMask = req->pinMask;

            uint8_t     pinVal  = req->pinVal;



            if ( portNum > NUM_PORTS )

            {

                portNum = 0;

            }



            IO_LOG3( "SetGPIO Port %c: Mask:0x%02x Val:0x%02x\n", portNum + 'A', pinMask, pinVal );



            *(gPORT[ portNum ]) &= ~pinMask;

            *(gPORT[ portNum ]) |= ( pinVal & pinMask );



            return 0;

        }



        case I2C_IO_GET_GPIO_DIR:

        {

            I2C_IO_Get_GPIO_t *req = (I2C_IO_Get_GPIO_t *)&packet->m_data[ 2 ];  // +1 for cmd, +1 for len

            uint8_t     portNum = req->portNum;



            if ( portNum > NUM_PORTS )

            {

                portNum = 0;

            }



            packet->m_data[ 0 ] = 1;

            packet->m_data[ 1 ] = *(gDDR[ portNum ]);



            IO_LOG2( "GetGPIODir Port %c: 0x%02x\n", portNum + 'A', packet->m_data[ 1 ]);

            return 2;

        }



        case I2C_IO_SET_GPIO_DIR:

        {

            I2C_IO_Set_GPIO_t *req = (I2C_IO_Set_GPIO_t *)&packet->m_data[ 2 ];  // +1 for cmd, +1 for len

            uint8_t     portNum = req->portNum;

            uint8_t     pinMask = req->pinMask;

            uint8_t     pinVal  = req->pinVal;



            if ( portNum > NUM_PORTS )

            {

                portNum = 0;

            }



            IO_LOG3( "SetGPIODir Port %c: Mask:0x%02x Val:0x%02x\n", portNum + 'A', pinMask, pinVal );



            *(gDDR[ portNum ]) &= ~pinMask;

            *(gDDR[ portNum ]) |= ( pinVal & pinMask );



            return 0;

        }



        case I2C_IO_GET_ADC:

        {

            I2C_IO_Get_ADC_t    *req = (I2C_IO_Get_ADC_t *)&packet->m_data[ 2 ];    // +1 for cmd, +1 for len

            uint8_t              mux = req->mux;



            // Set ADMUX but don't mess with REFS0 & REFS1



            ADMUX = ( ADMUX & (( 1 << REFS1 ) | ( 1 << REFS0 ))) | mux;



            // Start the conversion

            ADCSR = ADCSR | ( 1 << ADSC );



            // Wait for it to complete

            while ( ADCSR & ( 1 << ADSC ));



            packet->m_data[ 0 ] = 2;

            packet->m_data[ 1 ] = ADCL;

            packet->m_data[ 2 ] = ADCH;



            IO_LOG3( "GetADC mux:%d read 0x%02x%02x\n", mux, packet->m_data[ 2 ], packet->m_data[ 1 ]);



            return 3;

        }



        case I2C_IO_READ_REG_8:

        {

            I2C_IO_ReadReg8_t  *req = (I2C_IO_ReadReg8_t *)&packet->m_data[ 2 ];    // +1 for cmd, +1 for len

            volatile uint8_t   *regPtr = (volatile uint8_t *)(int)(req->reg);



            packet->m_data[ 0 ] = 1;

            packet->m_data[ 1 ] = *regPtr;



            IO_LOG2( "ReadReg8 reg:0x%02x read 0x%02x\n", (uint8_t)(int)regPtr, packet->m_data[ 1 ]);



            return 2;

        }



        case I2C_IO_READ_REG_16:

        {

            I2C_IO_ReadReg16_t *req = (I2C_IO_ReadReg16_t *)&packet->m_data[ 2 ];    // +1 for cmd, +1 for len

            volatile uint16_t  *regPtr = (volatile uint16_t *)(int)(req->reg);

            uint16_t            regVal = *regPtr;



            packet->m_data[ 0 ] = 2;

            packet->m_data[ 1 ] = (uint8_t)(  regVal        & 0xFF );

            packet->m_data[ 2 ] = (uint8_t)(( regVal >> 8 ) & 0xFF );



            IO_LOG3( "ReadReg16 reg:0x%02x read 0x%02x%02x\n", (uint8_t)(int)regPtr, packet->m_data[ 2 ], packet->m_data[ 1 ]);



            return 3;

        }



        case I2C_IO_WRITE_REG_8:

        {

            I2C_IO_WriteReg8_t  *req = (I2C_IO_WriteReg8_t *)&packet->m_data[ 2 ];    // +1 for cmd, +1 for len

            volatile uint8_t   *regPtr = (volatile uint8_t *)(int)(req->reg);



            *regPtr = req->val;



            IO_LOG2( "WriteReg8 reg:0x%02x wrote 0x%02x\n", (uint8_t)(int)regPtr, req->val);



            return 0;

        }



        case I2C_IO_WRITE_REG_16:

        {

            I2C_IO_WriteReg16_t *req = (I2C_IO_WriteReg16_t *)&packet->m_data[ 2 ];    // +1 for cmd, +1 for len

            volatile uint8_t   *regPtr = (volatile uint8_t *)(int)(req->reg);

            uint8_t             valH = (( req->val >> 8 ) & 0xFF );

            uint8_t             valL = (  req->val        & 0xFF );



            // For writing 16 bit registers, we need to write the high byte first



            regPtr[ 1 ] = valH;

            regPtr[ 0 ] = valL;



            IO_LOG3( "WriteReg16 reg:0x%02x wrote 0x%02x%02x\n", (uint8_t)(int)regPtr, valH, valL );



            return 0;

        }



        // Wisit's, multiple channels ADC data retrieving

        case I2C_IO_GET_ADCs:

        {

            I2C_IO_Get_ADC_t    *req = (I2C_IO_Get_ADC_t *)&packet->m_data[ 2 ];    // +1 for cmd, +1 for len

            uint8_t              mux = req->mux;



            // Set ADMUX but don't mess with REFS0 & REFS1



                uint8_t iMux;

                packet->m_data[ 0 ] = 2*mux;

                for (iMux = 0; iMux < mux; iMux++)

                {

                        ADMUX = ( ADMUX & (( 1 << REFS1 ) | ( 1 << REFS0 ))) | iMux;

               

                        // Start the conversion

                        ADCSR = ADCSR | ( 1 << ADSC );

               

                        // Wait for it to complete

                        while ( ADCSR & ( 1 << ADSC ));

               

                        //packet->m_data[ 0 ] = 2;

                        packet->m_data[ 2*iMux+1 ] = ADCL;

                        packet->m_data[ 2*iMux+2 ] = ADCH;

                }

            //IO_LOG3( "GetADC mux:%d read 0x%02x%02x\n", mux, packet->m_data[ 2 ], packet->m_data[ 1 ]);



            //return 3;

                return 2*mux+1;

        }



    }



    // It wasn't one of our commands, see if it's a bootloader command.



    if (( rc = I2C_SlaveBootProcessCommand( packet )) < 0 )

    {

        LogError( "Unrecognized command: 0x%02x\n", cmd );

    }



    return rc;



} // ProcessCommand



Re: Verdex + Robostix - Combining I2C with a Controller?

by Dave Hylands :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Peter,

On Wed, Oct 28, 2009 at 9:09 AM, p.g.adamczyk <p.g.adamczyk@...> wrote:
>
> Hi, List,
>
> Using a Verdex XM4BT and a Robostix, I have long had the i2c-io code (by
> Dave Hylands) working, with some modifications for time-regular data logging
> to the gumstix (~100 hz).

...snip...

> // Peter's code to signal Port.E2
>
> //Tell the board to produce a pulse when Timer 2 overflows
>
> ISR( TIMER2_OVF_vect )  //This sets the "Interrupt Service Routine" that
> happens when Timer2 Overflows
>
> {
>
>        PinPulse_Issue( GumInt );       //The routine is "PinPulse," which rapidly puts
> the pin high and then low.
>        TCNT2 = TCNT2RESET;                     // Reset the TCNT2 Register to a non-zero value to
> fine-tune the frequency. This value can be between 0 and 255. The Frequency
> achieved will depend on the Prescaler as well. For prescaler = 256 and TCNT2
> reset value = 130, we should interrupt at exactly 500 Hz. It works pretty
> well, though 500hz appears to be too fast for 8 channels even in fast mode
> of i2c.
>
>                                //GumInt is a string that will be prepended to a bunch of variable names
> to make the functions happen
>
> }

So, I see that there is a call to PinPulse_Issue from inside an ISR handler.

Note that interrupts are disabled while processing an interrupt
handler, and as a general rule ISR handlers shouldn't contain any
significant delays. If the code is just setting the pin high and then
low with perhaps a few instructions between, then you should be fine.
Otherwise, if the delay is significant (like anything over tens of
microseconds), then this could be messing with the i2c interrupts. At
100 kHz, the i2c interrupts occur roughly once every 100 microseconds
(during a transfer).

Try disabling portions of your code to see if that makes the i2c stuff
start working again.

--
Dave Hylands
Shuswap, BC, Canada
http://www.DaveHylands.com/

------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
gumstix-users mailing list
gumstix-users@...
https://lists.sourceforge.net/lists/listinfo/gumstix-users

Re: Verdex + Robostix - Combining I2C with a Controller?

by p.g.adamczyk :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


Thanks, Dave,

Alas, I have already disabled lots of stuff, and I have begun wondering whether it might be some sort of conflict in the definitions somewhere in the header files (?).

The PinPulse ISR is as simple as you suggest, and should be no problem: pin_hi, nop, pin_low, return
I know that does not cause problems on its own, because it works in my "enhanced" i2c-io program (with multiple ADCs in one return).

I have disabled many sets of things. Here are the symptoms:

    Disable Timer2 (and thus prevent any PinPulse interrupt): manual i2c-io calls return the same errors

    Disable PWM outputs, and all the background definitions for them in the early part of the file: automatic (@100Hz) and manual calls to i2c-io functions all fail (same errors)

    Disable a2d_10 calls in the controller code: same errors
        *note that I have not commented out the header a2d.h - I will try this later

    Disable array storage and update in the controller code: same errors

*  Disable everything in my controller code, as well as the Timer2 interrupts and PWM outputs (Which should have returned the code to the same state as the original working "enhanced" i2c-io): same errors!

Writing this, I feel like there may be an finger pointing at some conflict between the headers (??) needed/used for Simple-Servo and i2c-io. Perhaps the "a2d.h" file, which I realize I did not comment out during my tests. I will try commenting out the "a2d.h" header file and the analog sampling later, and see what happens.

Are there any other definition conflicts or register conflicts you can think of between these two pieces of code?

Thanks very much,
-Peter





Dave Hylands wrote:
Hi Peter,

On Wed, Oct 28, 2009 at 9:09 AM, p.g.adamczyk <p.g.adamczyk@gmail.com> wrote:
>
> Hi, List,
>
> Using a Verdex XM4BT and a Robostix, I have long had the i2c-io code (by
> Dave Hylands) working, with some modifications for time-regular data logging
> to the gumstix (~100 hz).

...snip...

> // Peter's code to signal Port.E2
>
> //Tell the board to produce a pulse when Timer 2 overflows
>
> ISR( TIMER2_OVF_vect )  //This sets the "Interrupt Service Routine" that
> happens when Timer2 Overflows
>
> {
>
>        PinPulse_Issue( GumInt );       //The routine is "PinPulse," which rapidly puts
> the pin high and then low.
>        TCNT2 = TCNT2RESET;                     // Reset the TCNT2 Register to a non-zero value to
> fine-tune the frequency. This value can be between 0 and 255. The Frequency
> achieved will depend on the Prescaler as well. For prescaler = 256 and TCNT2
> reset value = 130, we should interrupt at exactly 500 Hz. It works pretty
> well, though 500hz appears to be too fast for 8 channels even in fast mode
> of i2c.
>
>                                //GumInt is a string that will be prepended to a bunch of variable names
> to make the functions happen
>
> }

So, I see that there is a call to PinPulse_Issue from inside an ISR handler.

Note that interrupts are disabled while processing an interrupt
handler, and as a general rule ISR handlers shouldn't contain any
significant delays. If the code is just setting the pin high and then
low with perhaps a few instructions between, then you should be fine.
Otherwise, if the delay is significant (like anything over tens of
microseconds), then this could be messing with the i2c interrupts. At
100 kHz, the i2c interrupts occur roughly once every 100 microseconds
(during a transfer).

Try disabling portions of your code to see if that makes the i2c stuff
start working again.

--
Dave Hylands
Shuswap, BC, Canada
http://www.DaveHylands.com/

------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
gumstix-users mailing list
gumstix-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/gumstix-users

Re: Verdex + Robostix - Combining I2C with a Controller?

by Dave Hylands :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Peter,

> Writing this, I feel like there may be an finger pointing at some conflict
> between the headers (??) needed/used for Simple-Servo and i2c-io. Perhaps
> the "a2d.h" file, which I realize I did not comment out during my tests. I
> will try commenting out the "a2d.h" header file and the analog sampling
> later, and see what happens.

There shouldn't be any conflicts.

> Are there any other definition conflicts or register conflicts you can think
> of between these two pieces of code?

Perhaps you should try taking another approach.

Start over with the original i2c-io.c and make sure that works. It's
possible that it's a toolchain issue. Perhaps the i2c-Bootloader needs
to be built using the same version of toolchain as i2c-io or something
like that.

Then incrementally add stuff to see when it breaks.

--
Dave Hylands
Shuswap, BC, Canada
http://www.DaveHylands.com/

------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
gumstix-users mailing list
gumstix-users@...
https://lists.sourceforge.net/lists/listinfo/gumstix-users

Re: Verdex + Robostix - Combining I2C with a Controller?

by p.g.adamczyk :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Thanks, Dave.

I went through another painstaking process of elimination as suggested, and ultimately the problem is fixed. Naturally it turned out to be something silly, not anything that should have required help.

It turns out that I simply had the wrong versions of "Config.h" and "Hardware.h" in the project folder. This project needs the "i2c-io" versions, not the "Simple-Servo" versions. That's it :-\

Sorry for the help request, but thank you for giving your advice.

-Peter


Dave Hylands wrote:
Hi Peter,

> Writing this, I feel like there may be an finger pointing at some conflict
> between the headers (??) needed/used for Simple-Servo and i2c-io. Perhaps
> the "a2d.h" file, which I realize I did not comment out during my tests. I
> will try commenting out the "a2d.h" header file and the analog sampling
> later, and see what happens.

There shouldn't be any conflicts.

> Are there any other definition conflicts or register conflicts you can think
> of between these two pieces of code?

Perhaps you should try taking another approach.

Start over with the original i2c-io.c and make sure that works. It's
possible that it's a toolchain issue. Perhaps the i2c-Bootloader needs
to be built using the same version of toolchain as i2c-io or something
like that.

Then incrementally add stuff to see when it breaks.

--
Dave Hylands
Shuswap, BC, Canada
http://www.DaveHylands.com/