0
votes

On a Tiva (Texas Instruments Cortex M4F ARM) TM4C129XNCZAD I have another problem with I2C interface. I have employed both a master on I2C module 4 thru port K and a slave on I2C module 6 thru port B. I have interconnected both I2C modules. Using Texas Instruments driver library the master sends 3 bytes to the slave within "Master Send" mode as a request and then the master switches into "Master Receive" mode and the master receives 3 bytes from the slave. Till now everything looks to be OKay, but there is an issue. After the master receives data from the slave, in spite of the master sets a STOP bit within an I2C MCS register, the master module persists in the "Master Receive" mode and the I2C MCS register polling indicates the I2C bus is busy. Because of that there is impossible to set a new slave address and to enter to new cycle. Has anybody any idea how to fix this issue?

There is my code:

#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_i2c.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/gpio.h"
#include "driverlib/i2c.h"
#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
#include "inc/tm4c129xnczad.h"

#define SLAVE_ADDRESS 0x2C
#define NUM_I2C_DATA 3

#define RUN     1 
#define START   2
#define STOP    4
#define ACK     8
#define QCCMD   0x20
#define BURST   0x40

uint32_t  ui32Index;
uint32_t pui32DataRx[NUM_I2C_DATA];
uint32_t pui32DataTx[NUM_I2C_DATA];

int test(void)
{
    while(1)
    {
        for(ui32Index = 0; ui32Index < NUM_I2C_DATA; ui32Index++)
        {
                pui32DataRx[ui32Index] = 0;
                pui32DataTx[ui32Index] = 0;                 
        }
        while(I2CMasterBusBusy(I2C4_BASE));             
        I2CMasterSlaveAddrSet(I2C4_BASE, SLAVE_ADDRESS, false);         
/*-------------------------------------------------------------*/
        I2CMasterDataPut(I2C4_BASE, '1');
        I2CMasterControl(I2C4_BASE, START | RUN);   // I2C_MASTER_CMD_BURST_SEND_START);
        while(!(I2CSlaveStatus(I2C6_BASE) & I2C_SLAVE_ACT_RREQ)); // Wait until the slave has received and acknowledged the data.           
        pui32DataRx[0] = I2CSlaveDataGet(I2C6_BASE);  // Read the data from the slave.
        while(I2CMasterBusy(I2C4_BASE));            
/*-------------------------------------------------------------*/           
        I2CMasterDataPut(I2C4_BASE, '2');
        I2CMasterControl(I2C4_BASE, RUN);   // I2C_MASTER_CMD_BURST_SEND_CONT);
        while(!(I2CSlaveStatus(I2C6_BASE) & I2C_SLAVE_ACT_RREQ));           
        pui32DataRx[1] = I2CSlaveDataGet(I2C6_BASE);
        while(I2CMasterBusy(I2C4_BASE));                
/*-------------------------------------------------------------*/   
        I2CMasterDataPut(I2C4_BASE, '3');
        I2CMasterControl(I2C4_BASE, STOP | RUN);    //I2C_MASTER_CMD_BURST_SEND_FINISH);
        while(!(I2CSlaveStatus(I2C6_BASE) & I2C_SLAVE_ACT_RREQ));           
        pui32DataRx[2] = I2CSlaveDataGet(I2C6_BASE);
        while(I2CMasterBusy(I2C4_BASE));                            
/*-------------------------------------------------------------*/               
        I2CMasterSlaveAddrSet(I2C4_BASE, SLAVE_ADDRESS, true);
/*-------------------------------------------------------------*/                   
        I2CMasterControl(I2C4_BASE, RUN | START | ACK); // I2C_MASTER_CMD_BURST_RECEIVE_START);
        while(!(I2CSlaveStatus(I2C6_BASE) & I2C_SLAVE_ACT_TREQ));
        I2CSlaveDataPut(I2C6_BASE, 'A');
        while(I2CMasterBusy(I2C4_BASE));    
        pui32DataTx[0] = I2CMasterDataGet(I2C4_BASE);
/*-------------------------------------------------------------*/       
        I2CSlaveDataPut(I2C6_BASE, 'B');
        I2CMasterControl(I2C4_BASE, RUN | ACK);//I2C_MASTER_CMD_BURST_RECEIVE_CONT);
        while(!(I2CSlaveStatus(I2C6_BASE) & I2C_SLAVE_ACT_TREQ));
        while(I2CMasterBusy(I2C4_BASE));    
        pui32DataTx[1] = I2CMasterDataGet(I2C4_BASE);
/*-------------------------------------------------------------*/
        I2CSlaveDataPut(I2C6_BASE, 'C');
        I2CMasterControl(I2C4_BASE, RUN | ACK); // I2C_MASTER_CMD_BURST_RECEIVE_CONT);
// Missing an ACK causing I2CSlaveStatus stays clear.               
        while(!(I2CSlaveStatus(I2C6_BASE) & I2C_SLAVE_ACT_TREQ));
        while(I2CMasterBusy(I2C4_BASE));    
        pui32DataTx[2] = I2CMasterDataGet(I2C4_BASE);
/*
When the I2C module operates in Master receiver mode, the ACK bit is normally
set, causing the I2C bus controller to transmit an acknowledge automatically after each byte. This
bit must be cleared when the I2C bus controller requires no further data to be transmitted from the
slave transmitter.

b. In Master Receive mode, a STOP condition should be generated only after a Data Negative Acknowledge executed by
the master or an Address Negative Acknowledge executed by the slave.
*/
        I2CMasterControl(I2C4_BASE, STOP);  // I2C_MASTER_CMD_BURST_SEND_STOP);
        while(I2CMasterBusy(I2C4_BASE));
    }
}
2

2 Answers

0
votes

@MarcoPolo

I look at your code and it hard for me to follow the flow. But I was able to get I2C working on TIVA Launchpad TM4C123GH6PM. I used the the Tivaware library. I created 3 functions, init, read and write. Here are the functions.

Initialization

void initI2C0(void)
{
   SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);

   //reset I2C module
   SysCtlPeripheralReset(SYSCTL_PERIPH_I2C0);

   //enable GPIO peripheral that contains I2C
   SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);

   // Configure the pin muxing for I2C0 functions on port B2 and B3.
   GPIOPinConfigure(GPIO_PB2_I2C0SCL);
   GPIOPinConfigure(GPIO_PB3_I2C0SDA);

   // Select the I2C function for these pins.
   GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);
   GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);

   // Enable and initialize the I2C0 master module.  Use the system clock for
   // the I2C0 module.  The last parameter sets the I2C data transfer rate.
   // If false the data rate is set to 100kbps and if true the data rate will
   // be set to 400kbps.
   I2CMasterInitExpClk(I2C0_BASE, SysCtlClockGet(), false);

   //clear I2C FIFOs
   HWREG(I2C0_BASE + I2C_O_FIFOCTL) = 80008000;
}

I2C Read Function

uint8_t readI2C0(uint16_t device_address, uint16_t device_register)
{
   //specify that we want to communicate to device address with an intended write to bus
   I2CMasterSlaveAddrSet(I2C0_BASE, device_address, false);

   //the register to be read
   I2CMasterDataPut(I2C0_BASE, device_register);

   //send control byte and register address byte to slave device
   I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_SEND);

   //wait for MCU to complete send transaction
   while(I2CMasterBusy(I2C0_BASE));

   //read from the specified slave device
   I2CMasterSlaveAddrSet(I2C0_BASE, device_address, true);

   //send control byte and read from the register from the MCU
   I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);

   //wait while checking for MCU to complete the transaction
   while(I2CMasterBusy(I2C0_BASE));

   //Get the data from the MCU register and return to caller
   return( I2CMasterDataGet(I2C0_BASE));
 }

I2C Write Function

void writeI2C0(uint16_t device_address, uint16_t device_register, uint8_t device_data)
{
   //specify that we want to communicate to device address with an intended write to bus
   I2CMasterSlaveAddrSet(I2C0_BASE, device_address, false);

   //register to be read
   I2CMasterDataPut(I2C0_BASE, device_register);

   //send control byte and register address byte to slave device
   I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);

   //wait for MCU to finish transaction
   while(I2CMasterBusy(I2C0_BASE));

   I2CMasterSlaveAddrSet(I2C0_BASE, device_address, true);

   //specify data to be written to the above mentioned device_register
   I2CMasterDataPut(I2C0_BASE, device_data);

   //wait while checking for MCU to complete the transaction
   I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH);

   //wait for MCU & device to complete transaction
   while(I2CMasterBusy(I2C0_BASE));
}

I will post the complete code online to help understand the application.

Update: Complete code for TIVA + I2C can be found here.

Reference

0
votes

FYI...I2CMasterSlaveAddrSet(I2C2_BASE, SLAVE_ADDR, false); is when you want to write and I2CMasterSlaveAddrSet(I2C2_BASE, SLAVE_ADDR, true);is when you want to read from I2C bus.