This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

LAUNCHXL-F28379D: Modify the i2c-ex2-eeprom example for simple single sensor i2c communication

Part Number: LAUNCHXL-F28379D


Hey there,

I'm new to this so please if you can, explain rather more than less. :)

I need to set up an connection to a sensor for range measurement via I2C. I already wrote the function for initialisation and range measurement, just a bunch of simple register read and write executions. Now I  want to modify this example to fit my purpose:

/ FILE:   i2c_ex2_eeprom.c

//
// Included Files
//
#include "driverlib.h"
#include "device.h"

//
// Defines
//
#define SLAVE_ADDRESS               0x50 //my new adress is 0x29
#define EEPROM_HIGH_ADDR            0x00 // for initialisation i have arround 30 high and low addrs with
#define EEPROM_LOW_ADDR             0x30 // values to write in arrays saved for use in the structs
#define NUM_BYTES                   8 //just 1 in my case
#define MAX_BUFFER_SIZE             14      // Max is currently 14 because of
                                            // 2 address bytes and the 16-byte
                                            // FIFO

//
// I2C message states for I2CMsg struct
//
#define MSG_STATUS_INACTIVE         0x0000 // Message not in use, do not send
#define MSG_STATUS_SEND_WITHSTOP    0x0010 // Send message with stop bit
#define MSG_STATUS_WRITE_BUSY       0x0011 // Message sent, wait for stop
#define MSG_STATUS_SEND_NOSTOP      0x0020 // Send message without stop bit
#define MSG_STATUS_SEND_NOSTOP_BUSY 0x0021 // Message sent, wait for ARDY
#define MSG_STATUS_RESTART          0x0022 // Ready to become master-receiver
#define MSG_STATUS_READ_BUSY        0x0023 // Wait for stop before reading data

//
// Error messages for read and write functions
//
#define ERROR_BUS_BUSY              0x1000
#define ERROR_STOP_NOT_READY        0x5555
#define SUCCESS                     0x0000

//
// Typedefs
//
struct I2CMsg
{
    uint16_t msgStatus;                  // Word stating what state msg is in.
                                         // See MSG_STATUS_* defines above.
    uint16_t slaveAddr;                  // Slave address tied to the message.
    uint16_t numBytes;                   // Number of valid bytes in message.
    uint16_t memoryHighAddr;             // EEPROM address of data associated
                                         // with message (high byte).
    uint16_t memoryLowAddr;              // EEPROM address of data associated
                                         // with message (low byte).
    uint16_t msgBuffer[MAX_BUFFER_SIZE]; // Array holding message data.
};

//
// Globals
//
struct I2CMsg i2cMsgOut = {MSG_STATUS_SEND_WITHSTOP,
                           SLAVE_ADDRESS,
                           NUM_BYTES,
                           EEPROM_HIGH_ADDR, /later i will define new structs for every communication
                           EEPROM_LOW_ADDR,
                           0x01,                // Message bytes
                           0x23,
                           0x45,
                           0x67,
                           0x89,
                           0xAB,
                           0xCD,
                           0xEF};
struct I2CMsg i2cMsgIn  = {MSG_STATUS_SEND_NOSTOP,
                           SLAVE_ADDRESS,
                           NUM_BYTES,
                           EEPROM_HIGH_ADDR, ///later i will define new structs for every communication
                           EEPROM_LOW_ADDR};

struct I2CMsg *currentMsgPtr;                   // Used in interrupt

uint16_t passCount = 0; //no need for my purpose
uint16_t failCount = 0;

//
// Function Prototypes
//
void initI2C(void);
uint16_t readData(struct I2CMsg *msg);
uint16_t writeData(struct I2CMsg *msg);

void fail(void); // no need for my purpose
void pass(void);

__interrupt void i2cAISR(void);

//
// Main
//
void main(void)
{
    uint16_t error;
    uint16_t i;

    //
    // Initialize device clock and peripherals
    //
    Device_init();

    //
    // Disable pin locks and enable internal pullups.
    //
    Device_initGPIO();

    //
    // Initialize GPIOs 32 and 33 for use as SDA A and SCL A respectively
    //
    GPIO_setPinConfig(GPIO_32_SDAA);
    GPIO_setPadConfig(32, GPIO_PIN_TYPE_PULLUP);
    GPIO_setQualificationMode(32, GPIO_QUAL_ASYNC);

    GPIO_setPinConfig(GPIO_33_SCLA);
    GPIO_setPadConfig(33, GPIO_PIN_TYPE_PULLUP);
    GPIO_setQualificationMode(33, GPIO_QUAL_ASYNC);

    //
    // Initialize PIE and clear PIE registers. Disable CPU interrupts.
    //
    Interrupt_initModule();

    //
    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    //
    Interrupt_initVectorTable();

    //
    // Interrupts that are used in this example are re-mapped to ISR functions
    // found within this file.
    //
    Interrupt_register(INT_I2CA, &i2cAISR); //I think here the interrupts are set onto the i2cAISR function for interrupt handle

    //
    // Set I2C use, initializing it for FIFO mode
    //
    initI2C();

    //
    // Clear incoming message buffer
    //
    for (i = 0; i < MAX_BUFFER_SIZE; i++)
    {
        i2cMsgIn.msgBuffer[i] = 0x0000;
    }

    //
    // Set message pointer used in interrupt to point to outgoing message
    //
    currentMsgPtr = &i2cMsgOut;

    //
    // Enable interrupts required for this example
    //
    Interrupt_enable(INT_I2CA);

    //
    // Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
    //
    EINT;
    ERTM;

    //
    // Loop indefinitely
    //
    while(1)
    {
        //
        // **** Write data to EEPROM section ****
        //
        // Check the outgoing message to see if it should be sent. In this
        // example it is initialized to send with a stop bit.
        //
        if(i2cMsgOut.msgStatus == MSG_STATUS_SEND_WITHSTOP)
        {
            //
            // Send the data to the EEPROM
            //
            error = writeData(&i2cMsgOut);

            //
            // If communication is correctly initiated, set msg status to busy
            // and update currentMsgPtr for the interrupt service routine.
            // Otherwise, do nothing and try again next loop. Once message is
            // initiated, the I2C interrupts will handle the rest. See the
            // function i2cAISR().
            //
            if(error == SUCCESS)
            {
                currentMsgPtr = &i2cMsgOut;
                i2cMsgOut.msgStatus = MSG_STATUS_WRITE_BUSY;
            }
        }

        //
        // **** Read data from EEPROM section ****
        //
        // Check outgoing message status. Bypass read section if status is
        // not inactive.
        //
        if (i2cMsgOut.msgStatus == MSG_STATUS_INACTIVE)
        {
            //
            // Check incoming message status
            //
            if(i2cMsgIn.msgStatus == MSG_STATUS_SEND_NOSTOP)
            {
                //
                // Send EEPROM address setup
                //
                while(readData(&i2cMsgIn) != SUCCESS)
                {
                    //
                    // Maybe setup an attempt counter to break an infinite
                    // while loop. The EEPROM will send back a NACK while it is
                    // performing a write operation. Even though the write
                    // is complete at this point, the EEPROM could still be
                    // busy programming the data. Therefore, multiple
                    // attempts are necessary.
                    //
                }

                //
                // Update current message pointer and message status
                //
                currentMsgPtr = &i2cMsgIn;
                i2cMsgIn.msgStatus = MSG_STATUS_SEND_NOSTOP_BUSY;
           }

            //
            // Once message has progressed past setting up the internal address
            // of the EEPROM, send a restart to read the data bytes from the
            // EEPROM. Complete the communique with a stop bit. msgStatus is
            // updated in the interrupt service routine.
            //
            else if(i2cMsgIn.msgStatus == MSG_STATUS_RESTART)
            {
                //
                // Read data portion
                //
                while(readData(&i2cMsgIn) != SUCCESS)
                {
                    //
                    // Maybe setup an attempt counter to break an infinite
                    // while loop.
                    //
                }

                //
                // Update current message pointer and message status
                //
                currentMsgPtr = &i2cMsgIn;
                i2cMsgIn.msgStatus = MSG_STATUS_READ_BUSY;
            }
        }
    }
}

//
// initI2C - Function to configure I2C A in FIFO mode.
//
void
initI2C()
{
    //
    // Must put I2C into reset before configuring it
    //
    I2C_disableModule(I2CA_BASE);

    //
    // I2C configuration. Use a 400kHz I2CCLK with a 33% duty cycle.
    //
    I2C_initMaster(I2CA_BASE, DEVICE_SYSCLK_FREQ, 400000, I2C_DUTYCYCLE_33);
    I2C_setBitCount(I2CA_BASE, I2C_BITCOUNT_8);
    I2C_setSlaveAddress(I2CA_BASE, SLAVE_ADDRESS);
    I2C_setEmulationMode(I2CA_BASE, I2C_EMULATION_FREE_RUN);

    //
    // Enable stop condition and register-access-ready interrupts
    //
    I2C_enableInterrupt(I2CA_BASE, I2C_INT_STOP_CONDITION |
                        I2C_INT_REG_ACCESS_RDY);

    //
    // FIFO configuration
    //
    I2C_enableFIFO(I2CA_BASE);
    I2C_clearInterruptStatus(I2CA_BASE, I2C_INT_RXFF | I2C_INT_TXFF);

    //
    // Configuration complete. Enable the module.
    //
    I2C_enableModule(I2CA_BASE);
}

//
// writeData - Function to send the data that is to be written to the EEPROM
//
uint16_t
writeData(struct I2CMsg *msg)
{
    uint16_t i;

    //
    // Wait until the STP bit is cleared from any previous master
    // communication. Clearing of this bit by the module is delayed until after
    // the SCD bit is set. If this bit is not checked prior to initiating a new
    // message, the I2C could get confused.
    //
    if(I2C_getStopConditionStatus(I2CA_BASE))
    {
        return(ERROR_STOP_NOT_READY);
    }

    //
    // Setup slave address
    //
    I2C_setSlaveAddress(I2CA_BASE, SLAVE_ADDRESS);

    //
    // Check if bus busy
    //
    if(I2C_isBusBusy(I2CA_BASE))
    {
        return(ERROR_BUS_BUSY);
    }

    //
    // Setup number of bytes to send msgBuffer and address
    //
    I2C_setDataCount(I2CA_BASE, (msg->numBytes + 2));

    //
    // Setup data to send
    //
    I2C_putData(I2CA_BASE, msg->memoryHighAddr);
    I2C_putData(I2CA_BASE, msg->memoryLowAddr);

    for (i = 0; i < msg->numBytes; i++) // only 1 byte for my purpose
    {
        I2C_putData(I2CA_BASE, msg->msgBuffer[i]);
    }

    //
    // Send start as master transmitter
    //
    I2C_setConfig(I2CA_BASE, I2C_MASTER_SEND_MODE);
    I2C_sendStartCondition(I2CA_BASE);
    I2C_sendStopCondition(I2CA_BASE);

    return(SUCCESS);
}

//
// readData - Function to prepare for the data that is to be read from the EEPROM
//
uint16_t
readData(struct I2CMsg *msg)
{
    //
    // Wait until the STP bit is cleared from any previous master
    // communication. Clearing of this bit by the module is delayed until after
    // the SCD bit is set. If this bit is not checked prior to initiating a new
    // message, the I2C could get confused.
    //
    if(I2C_getStopConditionStatus(I2CA_BASE))
    {
        return(ERROR_STOP_NOT_READY);
    }

    //
    // Setup slave address
    //
    I2C_setSlaveAddress(I2CA_BASE, SLAVE_ADDRESS);

    //
    // If we are in the the address setup phase, send the address without a
    // stop condition.
    //
    if(msg->msgStatus == MSG_STATUS_SEND_NOSTOP)
    {
        //
        // Check if bus busy
        //
        if(I2C_isBusBusy(I2CA_BASE))
        {
            return(ERROR_BUS_BUSY);
        }

        //
        // Send data to setup EEPROM address
        //
        I2C_setDataCount(I2CA_BASE, 2);
        I2C_putData(I2CA_BASE, msg->memoryHighAddr);
        I2C_putData(I2CA_BASE, msg->memoryLowAddr);
        I2C_setConfig(I2CA_BASE, I2C_MASTER_SEND_MODE);
        I2C_sendStartCondition(I2CA_BASE);
    }
    else if(msg->msgStatus == MSG_STATUS_RESTART)
    {
        //
        // Address setup phase has completed. Now setup how many bytes expected
        // and send restart as master-receiver.
        //
        I2C_setDataCount(I2CA_BASE, (msg->numBytes));
        I2C_setConfig(I2CA_BASE, I2C_MASTER_RECEIVE_MODE);
        I2C_sendStartCondition(I2CA_BASE);
        I2C_sendStopCondition(I2CA_BASE);
    }

    return(SUCCESS);
}

//
// i2cAISR - I2C A ISR (non-FIFO)
//
__interrupt void
i2cAISR(void)
{
    I2C_InterruptSource intSource;
    uint16_t i;

    //
    // Read interrupt source
    //
    intSource = I2C_getInterruptSource(I2CA_BASE);

    //
    // Interrupt source = stop condition detected
    //
    if(intSource == I2C_INTSRC_STOP_CONDITION)
    {
        //
        // If completed message was writing data, reset msg to inactive state
        //
        if(currentMsgPtr->msgStatus == MSG_STATUS_WRITE_BUSY)
        {
            currentMsgPtr->msgStatus = MSG_STATUS_INACTIVE;
        }
        else
        {
            //
            // If a message receives a NACK during the address setup portion of
            // the EEPROM read, the code further below included in the register
            // access ready interrupt source code will generate a stop
            // condition. After the stop condition is received (here), set the
            // message status to try again. User may want to limit the number
            // of retries before generating an error.
            //
            if(currentMsgPtr->msgStatus == MSG_STATUS_SEND_NOSTOP_BUSY)
            {
                currentMsgPtr->msgStatus = MSG_STATUS_SEND_NOSTOP;
            }
            //
            // If completed message was reading EEPROM data, reset message to
            // inactive state and read data from FIFO.
            //
            else if(currentMsgPtr->msgStatus == MSG_STATUS_READ_BUSY)
            {
                currentMsgPtr->msgStatus = MSG_STATUS_INACTIVE;
                for(i=0; i < NUM_BYTES; i++)
                {
                    currentMsgPtr->msgBuffer[i] = I2C_getData(I2CA_BASE);
                }

                //
                // Check received data // not needed for my purpose
                //
                for(i=0; i < NUM_BYTES; i++)
                {
                    if(i2cMsgIn.msgBuffer[i] == i2cMsgOut.msgBuffer[i])
                    {
                        passCount++;
                    }
                    else
                    {
                        failCount++;
                    }
                }

                if(passCount == NUM_BYTES)
                {
                    pass();
                }
                else
                {
                    fail();
                }
            }
        }
    }
    //
    // Interrupt source = Register Access Ready
    //
    // This interrupt is used to determine when the EEPROM address setup
    // portion of the read data communication is complete. Since no stop bit
    // is commanded, this flag tells us when the message has been sent
    // instead of the SCD flag.
    //
    else if(intSource == I2C_INTSRC_REG_ACCESS_RDY)
    {
        //
        // If a NACK is received, clear the NACK bit and command a stop.
        // Otherwise, move on to the read data portion of the communication.
        //
        if((I2C_getStatus(I2CA_BASE) & I2C_STS_NO_ACK) != 0)
        {
            I2C_sendStopCondition(I2CA_BASE);
            I2C_clearStatus(I2CA_BASE, I2C_STS_NO_ACK);
        }
        else if(currentMsgPtr->msgStatus == MSG_STATUS_SEND_NOSTOP_BUSY)
        {
            currentMsgPtr->msgStatus = MSG_STATUS_RESTART;
        }
    }
    else
    {
        //
        // Generate some error from invalid interrupt source
        //
        asm("   ESTOP0");
    }

    //
    // Issue ACK to enable future group 8 interrupts
    //
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP8);
}

//
// pass - Function to be called if data written matches data read // no purpose
//
void
pass(void)
{
    asm("   ESTOP0");
    for(;;);
}

//
// fail - Function to be called if data written does NOT match data read
//
void fail(void)
{
    asm("   ESTOP0");
    for(;;);
}

//
// End of Filet/later i will define new structs for every communication
//

I marked everything red, what i already modified. My question is now, if I wirte my own main loop, say I would use parts of it for simple read and write purpose, can I do so? With all the interrupts and states already declared? I would like to modify as little as possible. Or do I need to modify the interrupt function? I dont quite get, when which i2c interrupt occurs, therefore cant completely understand the code.

For later use I want to write a function when the gpio interrupt of the sensor is set. So I would like to set an interrupt on one of the pins that pulls the pin high if a new measurement is ready and than read the register out. Any tips on that?

  • Hi Alexander,

    The I2C eeprom example code you're working off of is written to be used with a CAT24WC256 eeprom memory device, or similar I2C eeprom that expects the same protocol. By default the example will write data to the designated eeprom memory address (high/low address bytes) and then read back the written data. The SW is mostly interrupt driven and includes a state machine, which can make it hard to follow.

    Alexander Laub said:
    For later use I want to write a function when the gpio interrupt of the sensor is set. So I would like to set an interrupt on one of the pins that pulls the pin high if a new measurement is ready and than read the register out. Any tips on that?

    If the above is ultimately your goal, I think it would be simpler to write new software using the I2C DriverLib functions (within i2c.h) than try to leverage the example's state machine. The pin used for this interrupt will be an input or output of the c2000 device? What is the sequence for configuring and reading a measurement from your sensor device?

    Best,

    Kevin

  • //
    // Included Files
    //
    #include "driverlib.h"
    #include "device.h"
    #include "stdio.h"
    
    //
    // Defines
    //
    #define SLAVE_ADDRESS               0x29
    //#define EEPROM_HIGH_ADDR            0x00
    //#define EEPROM_LOW_ADDR             0x30
    #define NUM_BYTES                   1
    #define MAX_BUFFER_SIZE             14      // Max is currently 14 because of
                                                // 2 address bytes and the 16-byte 
                                                // FIFO
    //
    // Needed Functions For Range Continuous Mode
    //
    #define SYSRANGE_INTERMEASUREMENT_PERIOD        0x01B
    #define SYSTEM_MODE_GPIO1                       0x011
    #define SYSTEM_INTERRUPT_CONFIG_GPIO            0x014
    #define SYSRANGE_START                          0x018
    #define RESULT_RANGE_RAW                        0x064
    #define SYSTEM_INTERRUPT_CLEAR                  0x015
    
    typedef uint16_t VL6180xDev_t;
    VL6180xDev_t dev = SLAVE_ADDRESS;
    uint16_t n = 0;
    
    //
    // I2C message states for I2CMsg Struct
    //
    #define MSG_STATUS_INACTIVE         0x0000 // Message not in use, do not send
    #define MSG_STATUS_SEND_WITHSTOP    0x0010 // Send message with stop bit
    #define MSG_STATUS_WRITE_BUSY       0x0011 // Message sent, wait for stop
    #define MSG_STATUS_SEND_NOSTOP      0x0020 // Send message without stop bit
    #define MSG_STATUS_SEND_NOSTOP_BUSY 0x0021 // Message sent, wait for ARDY
    #define MSG_STATUS_RESTART          0x0022 // Ready to become master-receiver
    #define MSG_STATUS_READ_BUSY        0x0023 // Wait for stop before reading data
    
    //
    // Error messages for read and write functions
    //
    #define ERROR_BUS_BUSY              0x1000
    #define ERROR_STOP_NOT_READY        0x5555
    #define SUCCESS                     0x0000
    
    
    //
    // Typedefs
    //
    struct I2CMsg 
    {
        uint16_t msgStatus;                  // Word stating what state msg is in.
                                             // See MSG_STATUS_* defines above.
        uint16_t slaveAddr;                  // Slave address tied to the message.
        uint16_t numBytes;                   // Number of valid bytes in message.
        uint16_t memoryHighAddr[30];          // EEPROM address of data associated
                                             // with message (high byte).
        uint16_t memoryLowAddr[30];           // EEPROM address of data associated
                                             // with message (low byte).
        uint16_t msgBuffer[30];               // Array holding message data.
    };
    
    //
    // Globals
    //
    /*struct I2CMsg i2cMsgOut = {MSG_STATUS_SEND_WITHSTOP,
                               SLAVE_ADDRESS,
                               NUM_BYTES,
                               ArrayMemoryHighAddr[n],
                               ArrayMemoryLowAddr[n],
                               ArrayAddrValue[n]};
    
    struct I2CMsg i2cMsgIn  = {MSG_STATUS_SEND_NOSTOP,
                               SLAVE_ADDRESS,
                               NUM_BYTES,
                               ArrayMemoryHighAddr[n],
                               ArrayMemoryLowAddr[n]};
    */
    struct I2CMsg *currentMsgPtr;                   // Used in interrupt
    
    //
    // Function Prototypes
    //
    void initI2C(void);
    void initVL6180X(void);
    uint16_t readData(struct I2CMsg *msg);
    uint16_t writeData(struct I2CMsg *msg);
    int VL6180x_Init(VL6180xDev_t dev);
    int VL6180x_RangeSetInterMeasPeriod(VL6180xDev_t dev, uint32_t InterMeasTime_msec);
    int VL6180x_SetupGPIO1(VL6180xDev_t dev, uint16_t GPIOIntOn, uint16_t ActiveHigh);
    int VL6180x_RangeConfigInterrupt(VL6180xDev_t dev, uint16_t LevelLow, uint16_t LevelHigh, uint16_t OutOfWindow, uint16_t NewSample);
    int VL6180x_RangeStartContinuousMode(VL6180xDev_t dev, uint16_t ContMode, uint16_t StartMode);
    int VL6180x_RangeGetMeasurement(VL6180xDev_t dev, int32_t *pRange_mm);
    int VL6180x_ClearAllInterrupt(VL6180xDev_t dev, uint16_t ClearRange, uint16_t ClearALS, uint16_t ClearError);
    
    __interrupt void i2cAISR(void);
    
    //
    // Main
    //
    void main(void)
    {
        //uint16_t i;
    
        //
        // Initialize device clock and peripherals
        //
        Device_init();
    
        //
        // Disable pin locks and enable internal pullups.
        //
        Device_initGPIO();
    
        //
        // Initialize GPIOs 32 and 33 for use as SDA A and SCL A respectively
        //
        GPIO_setPinConfig(GPIO_104_SDAA);
        GPIO_setPadConfig(104, GPIO_PIN_TYPE_PULLUP);
        GPIO_setQualificationMode(104, GPIO_QUAL_ASYNC);
    
        GPIO_setPinConfig(GPIO_105_SCLA);
        GPIO_setPadConfig(105, GPIO_PIN_TYPE_PULLUP);
        GPIO_setQualificationMode(105, GPIO_QUAL_ASYNC);
    
        //
        // Initialize PIE and clear PIE registers. Disable CPU interrupts.
        //
        Interrupt_initModule();
    
        //
        // Initialize the PIE vector table with pointers to the shell Interrupt
        // Service Routines (ISR).
        //
        Interrupt_initVectorTable();
    
        //
        // Interrupts that are used in this example are re-mapped to ISR functions
        // found within this file.
        //
        Interrupt_register(INT_I2CA, &i2cAISR);
    
        //
        // Set I2C use, initializing it for FIFO mode
        //
        initI2C();
    
        //
        // Clear incoming message buffer
        //
        /*for (i = 0; i < MAX_BUFFER_SIZE; i++)
        {
            i2cMsgIn.msgBuffer[i] = 0x0000;
        }
    */
        //
        // Set message pointer used in interrupt to point to outgoing message
        //
        //currentMsgPtr = &i2cMsgOut;
    
        //
        // Enable interrupts required for this example
        //
        Interrupt_enable(INT_I2CA);
    
        //
        // Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
        //
        EINT;
        ERTM;
    
    
        int status = VL6180x_Init(dev);
        DEVICE_DELAY_US(1000);
        status = VL6180x_RangeSetInterMeasPeriod(dev, 1000);
        DEVICE_DELAY_US(1000);
        status = VL6180x_SetupGPIO1(dev, 1, 1);
        DEVICE_DELAY_US(1000);
        status = VL6180x_RangeConfigInterrupt(dev, 0, 0, 0, 1);
        DEVICE_DELAY_US(1000);
        status = VL6180x_RangeStartContinuousMode(dev, 1, 1);
        DEVICE_DELAY_US(1000);
        int32_t RANGE = 0;
        while(true) {
        status = VL6180x_RangeGetMeasurement(dev, &RANGE);
        DEVICE_DELAY_US(1000000);
        //fprintf("%c\n", &RANGE);
        status = VL6180x_ClearAllInterrupt(dev, 1, 0, 1);
        }
    }
    //
    // initI2C - Function to configure I2C A in FIFO mode.
    //
    void
    initI2C()
    {
        //
        // Must put I2C into reset before configuring it
        //
        I2C_disableModule(I2CA_BASE);
    
        //
        // I2C configuration. Use a 400kHz I2CCLK with a 33% duty cycle.
        //
        I2C_initMaster(I2CA_BASE, DEVICE_SYSCLK_FREQ, 400000, I2C_DUTYCYCLE_33);
        I2C_setBitCount(I2CA_BASE, I2C_BITCOUNT_8);
        I2C_setSlaveAddress(I2CA_BASE, SLAVE_ADDRESS);
        I2C_setEmulationMode(I2CA_BASE, I2C_EMULATION_FREE_RUN);
    
        //
        // Enable stop condition and register-access-ready interrupts
        //
        I2C_enableInterrupt(I2CA_BASE, I2C_INT_STOP_CONDITION |
                            I2C_INT_REG_ACCESS_RDY);
    
        //
        // FIFO configuration
        //
        I2C_enableFIFO(I2CA_BASE);
        I2C_clearInterruptStatus(I2CA_BASE, I2C_INT_RXFF | I2C_INT_TXFF);
    
        //
        // Configuration complete. Enable the module.
        //
        I2C_enableModule(I2CA_BASE);
    }
    
    //
    // writeData Mask
    //
    uint16_t
    I2CwriteData(struct I2CMsg *msg) {
        uint16_t error;
        if(msg->msgStatus == MSG_STATUS_SEND_WITHSTOP) {
            error = writeData(msg);
    
            if(error == SUCCESS) {
                currentMsgPtr = msg;
                msg->msgStatus = MSG_STATUS_WRITE_BUSY;
    
                return 0;
            }
        }
        else {
            return 1;
        }
        return 0;
    }
    
    //
    // writeData - Function to send the data that is to be written to the EEPROM
    //
    uint16_t
    writeData(struct I2CMsg *msg)
    {
        //uint16_t i;
    
        //
        // Wait until the STP bit is cleared from any previous master
        // communication. Clearing of this bit by the module is delayed until after
        // the SCD bit is set. If this bit is not checked prior to initiating a new
        // message, the I2C could get confused.
        //
        if(I2C_getStopConditionStatus(I2CA_BASE))
        {
            return(ERROR_STOP_NOT_READY);
        }
    
        //
        // Setup slave address
        //
        I2C_setSlaveAddress(I2CA_BASE, SLAVE_ADDRESS);
    
        //
        // Check if bus busy
        //
        if(I2C_isBusBusy(I2CA_BASE))
        {
            return(ERROR_BUS_BUSY);
        }
    
        //
        // Setup number of bytes to send msgBuffer and address
        //
        I2C_setDataCount(I2CA_BASE, (msg->numBytes + 2));
    
        //
        // Setup data to send
        //
        I2C_putData(I2CA_BASE, msg->memoryHighAddr[n]);
        I2C_putData(I2CA_BASE, msg->memoryLowAddr[n]);
    
        //for (i = 0; i < msg->numBytes; i++)
        //{
            I2C_putData(I2CA_BASE, msg->msgBuffer[n]);
        //}
    
        //
        // Send start as master transmitter
        //
        I2C_setConfig(I2CA_BASE, I2C_MASTER_SEND_MODE);
        I2C_sendStartCondition(I2CA_BASE);
        I2C_sendStopCondition(I2CA_BASE);
    
        return(SUCCESS);
    }
    
    //
    // readData Mask
    //
    uint16_t
    I2CreadData(struct I2CMsg *msg)
    {
        while(true) {
            if(msg->msgStatus == MSG_STATUS_SEND_NOSTOP) {
                while(readData(msg) != SUCCESS) {
    
                }
                currentMsgPtr = msg;
                msg->msgStatus = MSG_STATUS_SEND_NOSTOP_BUSY;
            }
    
    
            else if(msg->msgStatus == MSG_STATUS_RESTART) {
                while(readData(msg) != SUCCESS) {
    
                }
                currentMsgPtr = msg;
                msg->msgStatus = MSG_STATUS_READ_BUSY;
                break;
            }
        }
        return 0;
    }
    
    //
    // readData - Function to prepare for the data that is to be read from the EEPROM
    //
    uint16_t
    readData(struct I2CMsg *msg)
    {
        //
        // Wait until the STP bit is cleared from any previous master
        // communication. Clearing of this bit by the module is delayed until after
        // the SCD bit is set. If this bit is not checked prior to initiating a new
        // message, the I2C could get confused.
        //
        if(I2C_getStopConditionStatus(I2CA_BASE))
        {
            return(ERROR_STOP_NOT_READY);
        }
    
        //
        // Setup slave address
        //
        I2C_setSlaveAddress(I2CA_BASE, SLAVE_ADDRESS);
    
        //
        // If we are in the the address setup phase, send the address without a
        // stop condition.
        //
        if(msg->msgStatus == MSG_STATUS_SEND_NOSTOP)
        {
            //
            // Check if bus busy
            //
            if(I2C_isBusBusy(I2CA_BASE))
            {
                return(ERROR_BUS_BUSY);
            }
    
            //
            // Send data to setup EEPROM address
            //
            I2C_setDataCount(I2CA_BASE, 2);
            I2C_putData(I2CA_BASE, msg->memoryHighAddr[0]);
            I2C_putData(I2CA_BASE, msg->memoryLowAddr[0]);
            I2C_setConfig(I2CA_BASE, I2C_MASTER_SEND_MODE);
            I2C_sendStartCondition(I2CA_BASE);
        }
        else if(msg->msgStatus == MSG_STATUS_RESTART)
        {
            //
            // Address setup phase has completed. Now setup how many bytes expected
            // and send restart as master-receiver.
            //
            I2C_setDataCount(I2CA_BASE, (msg->numBytes));
            I2C_setConfig(I2CA_BASE, I2C_MASTER_RECEIVE_MODE);
            I2C_sendStartCondition(I2CA_BASE);
            I2C_sendStopCondition(I2CA_BASE);
        }
    
        return(SUCCESS);
    }
    
    //
    // i2cAISR - I2C A ISR (non-FIFO)
    //
    __interrupt void
    i2cAISR(void)
    {
        I2C_InterruptSource intSource;
        uint16_t i;
    
        //
        // Read interrupt source
        //
        intSource = I2C_getInterruptSource(I2CA_BASE);
    
        //
        // Interrupt source = stop condition detected
        //
        if(intSource == I2C_INTSRC_STOP_CONDITION)
        {
            //
            // If completed message was writing data, reset msg to inactive state
            //
            if(currentMsgPtr->msgStatus == MSG_STATUS_WRITE_BUSY)
            {
                currentMsgPtr->msgStatus = MSG_STATUS_INACTIVE;
            }
            else
            {
                //
                // If a message receives a NACK during the address setup portion of
                // the EEPROM read, the code further below included in the register
                // access ready interrupt source code will generate a stop
                // condition. After the stop condition is received (here), set the
                // message status to try again. User may want to limit the number
                // of retries before generating an error.
                //
                if(currentMsgPtr->msgStatus == MSG_STATUS_SEND_NOSTOP_BUSY)
                {
                    currentMsgPtr->msgStatus = MSG_STATUS_SEND_NOSTOP;
                }
                //
                // If completed message was reading EEPROM data, reset message to
                // inactive state and read data from FIFO.
                //
                else if(currentMsgPtr->msgStatus == MSG_STATUS_READ_BUSY)
                {
                    currentMsgPtr->msgStatus = MSG_STATUS_INACTIVE;
                    for(i=0; i < NUM_BYTES; i++)
                    {
                        currentMsgPtr->msgBuffer[i] = I2C_getData(I2CA_BASE);
                    }
    
                }
            }
        }
        //
        // Interrupt source = Register Access Ready
        //
        // This interrupt is used to determine when the EEPROM address setup
        // portion of the read data communication is complete. Since no stop bit
        // is commanded, this flag tells us when the message has been sent
        // instead of the SCD flag.
        //
        else if(intSource == I2C_INTSRC_REG_ACCESS_RDY)
        {
            //
            // If a NACK is received, clear the NACK bit and command a stop.
            // Otherwise, move on to the read data portion of the communication.
            //
            if((I2C_getStatus(I2CA_BASE) & I2C_STS_NO_ACK) != 0)
            {
                I2C_sendStopCondition(I2CA_BASE);
                I2C_clearStatus(I2CA_BASE, I2C_STS_NO_ACK);
            }
            else if(currentMsgPtr->msgStatus == MSG_STATUS_SEND_NOSTOP_BUSY)
            {
                currentMsgPtr->msgStatus = MSG_STATUS_RESTART;
            }
        }
        else
        {
            //
            // Generate some error from invalid interrupt source
            //
            asm("   ESTOP0");
        }
    
        //
        // Issue ACK to enable future group 8 interrupts
        //
        Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP8);
    }
    
    //
    // VL6180X Register Initialisation
    //
    int VL6180x_Init(VL6180xDev_t dev){
    
        uint16_t ArrayMemoryHighAddr[30]    = { 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00 };
        uint16_t ArrayMemoryLowAddr[30]     = { 0x07, 0x08, 0x96, 0x97, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xF5, 0xD9, 0xDB, 0xDC, 0xDD, 0x9F, 0xA3, 0xB7, 0xBB, 0xB2, 0xCA, 0x98, 0xB0, 0xAD, 0xFF, 0x00, 0x99, 0xA6, 0xAC, 0xA7, 0x30 };
        uint16_t ArrayAddrValue[30]         = { 0x01, 0x01, 0x00, 0xFD, 0x00, 0x04, 0x02, 0x01, 0x03, 0x02, 0x05, 0xCE, 0x03, 0xF8, 0x00, 0x3C, 0x00, 0x3C, 0x09, 0x09, 0x01, 0x17, 0x00, 0x05, 0x05, 0x05, 0x1B, 0x3E, 0x1F, 0x00 };
        uint16_t n = 0;
        int status = 0;
    
        struct I2CMsg I2CMsgInit = {MSG_STATUS_SEND_WITHSTOP,
                                   SLAVE_ADDRESS,
                                   NUM_BYTES};
        for (n = 0; n < 30; n++) {
            I2CMsgInit.memoryHighAddr[n] = ArrayMemoryHighAddr[n];
            I2CMsgInit.memoryLowAddr[n] = ArrayMemoryLowAddr[n];
            I2CMsgInit.msgBuffer[n] = ArrayAddrValue[n];
        } for (n = 0; n < 30; n++) { I2CMsgInit.msgStatus = MSG_STATUS_SEND_WITHSTOP; status = I2CwriteData(&I2CMsgInit); DEVICE_DELAY_US(1000); } if (status) { fprintf(stderr, "Initialisation write fail \n"); } return status; } // // VL6180X Inter Measurement Period Time Set // int VL6180x_RangeSetInterMeasPeriod(VL6180xDev_t dev, uint32_t InterMeasTime_msec) { uint16_t SetTime = 0; int status = 0; if (InterMeasTime_msec <= 2550 && InterMeasTime_msec >= 10) { SetTime = (uint16_t)(InterMeasTime_msec / 10); struct I2CMsg I2CMsgOut = {MSG_STATUS_SEND_WITHSTOP, SLAVE_ADDRESS, NUM_BYTES, {0x00}, {SYSRANGE_INTERMEASUREMENT_PERIOD}, SetTime}; status = I2CwriteData(&I2CMsgOut); //status = I2CWrite(dev, SYSRANGE_INTERMEASUREMENT_PERIOD, SetTime); if (status) { fprintf(stderr, "SYSRANGE_INTERMEASUREMENT_PERIOD write fail"); } } else { fprintf(stderr, "InterMeasTime_msec out of range"); status = 1; } return status; } // // VL6180X GPIO1 Interrupt Set // int VL6180x_SetupGPIO1(VL6180xDev_t dev, uint16_t GPIOIntOn, uint16_t ActiveHigh) { uint16_t value = 0; int status = 0; if ((GPIOIntOn <= 0x01) && (ActiveHigh <= 0x01)) { value = ActiveHigh << 5; value |= GPIOIntOn << 4; struct I2CMsg I2CMsgOut = {MSG_STATUS_SEND_WITHSTOP, SLAVE_ADDRESS, NUM_BYTES, {0x00}, {SYSTEM_MODE_GPIO1}, value}; status = I2CwriteData(&I2CMsgOut); //status = I2CWrite(dev, SYSTEM_MODE_GPIO1, value); if (status) { fprintf(stderr, "SYSTEM_MODE_GPIO1 write fail"); } } else { fprintf(stderr, "GPIOIntOn or ActiveHigh out of range"); status = 1; } return status; } // // VL6180X Range Interrupt Configuration // int VL6180x_RangeConfigInterrupt(VL6180xDev_t dev, uint16_t LevelLow, uint16_t LevelHigh, uint16_t OutOfWindow, uint16_t NewSample) { uint16_t value = 0; int status = 0; if ((LevelLow <= 0x01) && (LevelHigh <= 0x01) && (OutOfWindow <= 0x01) && (NewSample <= 0x01)) { value = LevelLow; value |= LevelHigh << 1; if (OutOfWindow == 0x01){ value |= 0x03; } value |= NewSample << 2; struct I2CMsg I2CMsgOut = {MSG_STATUS_SEND_WITHSTOP, SLAVE_ADDRESS, NUM_BYTES, {0x00}, {SYSTEM_INTERRUPT_CONFIG_GPIO}, value}; status = I2CwriteData(&I2CMsgOut); //status = I2CWrite(dev, SYSTEM_INTERRUPT_CONFIG_GPIO, value); if (status) { fprintf(stderr, "SYSTEM_INTERRUPT_CONFIG_GPIO write fail"); } } else { fprintf(stderr, "ConfigGpioInt out of range"); status = 1; } return status; } // // VL6180X Range Continuous Mode Set // int VL6180x_RangeStartContinuousMode(VL6180xDev_t dev, uint16_t ContMode, uint16_t StartMode) { uint16_t value = 0; int status = 0; /* FIXME we are not checking device is ready via @a VL6180x_RangeWaitDeviceReady * so if called back to back real fast we are not checking * if previous mode "set" got absorbed => bit 0 must be 0 so that it work */ if ((ContMode <= 0x01) && (StartMode <= 0x01)) { value = ContMode << 1; struct I2CMsg I2CMsgOut = {MSG_STATUS_SEND_WITHSTOP, SLAVE_ADDRESS, NUM_BYTES, {0x00}, {SYSRANGE_START}, value}; status = I2CwriteData(&I2CMsgOut); //status = I2CWrite(dev, SYSRANGE_START, value); DEVICE_DELAY_US(100); value |= StartMode; I2CMsgOut.msgBuffer[0] = value; I2CMsgOut.msgStatus = MSG_STATUS_SEND_WITHSTOP; status = I2CwriteData(&I2CMsgOut); //status = I2CWrite(dev, SYSRANGE_START, value); if (status) { fprintf(stderr, "SYSRANGE_START write fail"); } } else { fprintf(stderr, "Mode or StartMode out of range"); status = 1; } return status; } // // VL6180X Range Get Measurement // int VL6180x_RangeGetMeasurement(VL6180xDev_t dev, int32_t *pRange_mm) { int status = 0; int16_t RawRange = 0; struct I2CMsg I2CMsgIn = {MSG_STATUS_SEND_NOSTOP, SLAVE_ADDRESS, NUM_BYTES, {0x00}, {RESULT_RANGE_RAW}, RawRange}; status = I2CreadData(&I2CMsgIn); //status = I2CRead(dev, RESULT_RANGE_RAW, &RawRange); if (status) { fprintf(stderr, "RESULT_RANGE_RAW read fail"); } else { *pRange_mm = (int32_t)I2CMsgIn.msgBuffer[0]; } return status; } // // VL6180X Clear Interrupt Configuration // int VL6180x_ClearAllInterrupt(VL6180xDev_t dev, uint16_t ClearRange, uint16_t ClearALS, uint16_t ClearError) { uint16_t value = 0; int status = 0; if ((ClearRange <= 1) && (ClearALS <= 1) && (ClearError <= 1)) { value = ClearError << 2; value |= ClearALS << 1; value |= ClearRange; struct I2CMsg I2CMsgOut = {MSG_STATUS_SEND_WITHSTOP, SLAVE_ADDRESS, NUM_BYTES, {0x00}, {SYSTEM_INTERRUPT_CLEAR}, value}; status = I2CwriteData(&I2CMsgOut); //status = I2CWrite(dev, SYSTEM_INTERRUPT_CLEAR, value); if (status) { fprintf(stderr, "SYSTEM_INTERRUPT_CLEAR write fail"); } } else { fprintf(stderr, "ClearRange or ClearALS or ClearError out of range"); status = 1; } return status; }

  • I know what you mean but the sensor I am using seems to use the same protocol with 2 bytes per adress and so on. The sensor is the VL6180x, a time of flight distance sensor. Below I inserted my current code, which is running but does not read out the current distance, which is currently my goal.
    I will try to explain my changes. The sensor is in standy when powered on. Then it need a sequence of register writes for initialisation.
    VL6180x_Init writes 30 registers for initialisation.
    VL6180x_RangeSetInterMeasPeriod writes 1 register to setup period between range measurements.
    VL6180x_SetupGPIO1 sets the interrupt pin up, which will be high when a new measurement is ready, BUT CURRENTLY NOT USED, LATER
    VL6180x_RangeConfigInterrrupt writes 1 register to set up, why the interrupt on gpio1 should be set, here when new measurement is ready, BUT CURRENTLY NOT USED, LATER
    VL6180x_RangeStartContinousMode writes 1 register to set up continous ranging mode
    VL6180x_RangeMeasurement should read one register and set it on a variable I want to read out, variable RANGE in my main(void)
    VL6180x_ClearAllInterrupt writes 1 register to clear interrupts

    I still used the msg struct, so i dont have to modify the code to much, just if you are wondering.
    The VL6180xDev_t type is just a integer with the slave adress in single sensor use.
    I use pin 104 and 105 for the datapin and clockpin.
    The I2Cwrite/readdata are just mask functions to use the VL6180x functions without modifying the original write/readData, with the STATUS variables used so interrupts can wrok properly.

    So everything is working, code is running and no errors, the only thing is that the VL6180x_RangeMeasurement doesn't give me a range measurement. Does somebody see why? I followed every step with brakpoints and its just not putting a vlaue in my .msgbuffer[0] so far.

  • I know what you mean but the sensor I am using seems to use the same protocol with 2 bytes per adress and so on. The sensor is the VL6180x, a time of flight distance sensor. Below I inserted my current code, which is running but does not read out the current distance, which is currently my goal.I will try to explain my changes. The sensor is in standy when powered on.

    Then it need a sequence of register writes for initialisation.

    VL6180x_Init writes 30 registers for initialisation.

    VL6180x_RangeSetInterMeasPeriod writes 1 register to setup period between range measurements.

    VL6180x_SetupGPIO1 sets the interrupt pin up, which will be high when a new measurement is ready, BUT CURRENTLY NOT USED, LATER

    VL6180x_RangeConfigInterrrupt writes 1 register to set up, why the interrupt on gpio1 should be set, here when new measurement is ready, BUT CURRENTLY NOT USED, LATER

    VL6180x_RangeStartContinousMode writes 1 register to set up continous ranging mode

    VL6180x_RangeMeasurement should read one register and set it on a variable I want to read out, variable RANGE in my main(void)

    VL6180x_ClearAllInterrupt writes 1 register to clear interrupts

    I still used the msg struct, so i dont have to modify the code to much, just if you are wondering.

    The VL6180xDev_t type is just a integer with the slave adress in single sensor use.

    I use pin 104 and 105 for the datapin and clockpin.

    The I2Cwrite/readdata are just mask functions to use the VL6180x functions without modifying the original write/readData, with the STATUS variables used so interrupts can wrok properly.

    So everything is working, code is running and no errors, the only thing is that the VL6180x_RangeMeasurement doesn't give me a range measurement.

    Does somebody see why?

    I followed every step with breakpoints and its just not putting a value in my .msgbuffer[0] so far.

     



  • Hi Alexander,

    Using an I2C logic analyzer usually makes it a lot simpler to debug things like this. Do you have access to one you can use by chance?

    Can you post the segment of your code you're having issues with? It's difficult to review otherwise.

    Best,

    Kevin