Robostix i2c slave

From GumstixDocsWiki

Jump to: navigation, search

The page tries to explain how to use the i2c-slave.c file or i2c-slave-boot.c file on the robostix. The i2c-io sample program provides a working example of how to use the i2c-slave-boot.c file.

Contents

Delcare globals

If you're using i2c-slave.c, then you'll need to declare a global variable which is used to contain various bits of state information. All of the information contained in this variable should be considered private and there should be no reason to use or manipulate this by the calling program.

If you're using i2c-slave-boot.c, then it declares a global variable for you.

I2C_Globals_t gI2cGlobals;

Install the interrupt handler

The i2c slave code is entirely interrupt driven, and it relies on the main application to provide the interrupt handler. The interrupt handler would typically look something like this:

//***************************************************************************
/**
* 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

If you're using i2c-slave.c, then replace I2C_SlaveBootHandler() with I2C_SlaveHandler( &gI2cGlobals )

Initializing

The i2c slave code needs to be initialized. If you're using i2c-slave.c, then you need to allocate space for globals and pass in the address of this memory, along with the address to use on the i2c bus.

If you're using i2c-slave-boot.c, then it allocates storage for the globals for you, and uses the same i2c address that the boot loader is configured to use.

The final parameter, in either case, is a pointer to a function which will be called to process i2c commands.

The ProcessCmd function must have the following prototype:

int ProcessCommand( I2C_Data_t *packet );

The I2C_Data_t structure looks like this:

typedef struct
{
    #if CFG_I2C_USE_CRC
    uint8_t m_crc;
    #endif

    // For reads, m_len is the number of bytes actually read (doesn't include
    // the CRC - if present). If a block transfer was performed which has a 
    // length byte, this lenght will include the length byte.

    uint8_t m_len;

    // Note: Under SMBus, a block write can consist of a command, a length,
    // 32 bytes of payload, and a CRC.
    //
    // A read response can consist of a length, 32 bytes of data, and a CRC.

    uint8_t m_data[ I2C_MAX_DATA_LEN + 2]; // +1 for the command, +1 for length

} I2C_Data_t;

The packet parameter will contain the i2c data which was received, and is also where any response will be placed. packet->m_data[0] will contain the command (or register number). The remainder of the packet will depend on the particular type of transfer being performed.

The SMBus specification desribes the following protocols:

Protocol i2c-api.c fn Description
Quick command   In this case, the only data sent is the R/W bit. Since the linux i2c stack uses this for scanning the i2c bus, this variant isn't supported
Send Byte   A single byte of data is sent, and no response is expected.
Receive Byte   No data is sent and a single byte response is expected.
Write Byte I2cWriteByte A single byte command is sent followed by a single byte of data. No response is expected.
Read Byte I2cReadByte A single byte command is sent, and a single byte response is expected
Write Word   A single byte command is sent followed by a word (two bytes) of data. No response is expected.
Read Word   A single byte command is sent, and a word (two byte) response is expected.
Process Call   A single byte command along with a word of data is sent, and one word response is expected.
Write Block I2cWriteBlock A single byte command code, followed by a 1 byte length, followed by variable data is sent. No response is expected.
Read Block I2cReadBlock A single byte command is sent, and a single byte length followed by variable data is sent in response.
Process Block I2cProcessBlock A single byte command, followed by a 1 byte length and variable data is sent, and a 1 byte length followed by variable data is expected in response.

The CRC handling is taken care of automatically.

If you're using i2c-slave-boot.c and you would like to support the bootloader commands, if you don't recognize the command which is received, then you can call I2C_SlaveBootProcessCommand to see if the bootloader recognizes the command.

The ProcessCommand function should fill in the packet with the data to be sent as a response. The return from the ProcessCommand function should be the number of bytes to send as the response.

Note: So far, only the protocols with functions listed in the i2c-api.c fn column have been tested.

On the gumstix side of things

The i2c-api.c file contains wrapper functions for implementing the various protocols. The I2cTransfer function is the core code.

Personal tools