On a Tiva (Texas Instruments Cortex M4F ARM) TM4C129XNCZAD I have a problem with I2C interface. I have enabled 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 I tried to send 1 byte using I2C_MASTER_CMD_SINGLE_SEND command. I spend a lot of time to make it working, but SCK line keeps Low logical level. I followed exactly TivaWare™ Peripheral Driver Library USER’S GUIDE, but the communication doesn't work. Has anybody some experience with it?
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 0x3C
void delay (void)
{
volatile uint32_t ui32Loop;
for(ui32Loop = 0; ui32Loop < 200000; ui32Loop++);
}
volatile uint32_t result;
int main (void)
{
SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
//
// Enable the GPIO port that is used for the on-board LED.
//
SYSCTL_RCGCGPIO_R = SYSCTL_RCGCGPIO_R3 | SYSCTL_RCGCGPIO_R9 | SYSCTL_RCGCGPIO_R1;
//
// Do a dummy read to insert a few cycles after enabling the peripheral.
//
result = SYSCTL_RCGCGPIO_R;
//
// Enable the GPIO pin for the LED (PD3). Set the direction as output, and
// enable the GPIO pin for digital function.
//
GPIO_PORTD_AHB_DIR_R = 0x8;
GPIO_PORTD_AHB_DEN_R = 0x8;
GPIO_PORTK_DEN_R = 0xC0; // Enable Port K for I2C module 4
GPIO_PORTB_AHB_DEN_R = 0xC0; // Enable Port B for I2C module 6
SYSCTL_RCGCI2C_R = (1 << 4) | (1 << 6); // Mode Clock Gating Control for I2C modules 4 and 6
GPIO_PORTK_AFSEL_R = 0xC0; // Alternate Function Select PK6, PK7
GPIO_PORTB_AHB_AFSEL_R = 0xC0; // Alternate Function Select PB6, PB7
GPIOPinConfigure(GPIO_PK6_I2C4SCL);
GPIOPinConfigure(GPIO_PK7_I2C4SDA);
GPIOPinConfigure(GPIO_PB6_I2C6SCL);
GPIOPinConfigure(GPIO_PB7_I2C6SDA);
GPIOPinTypeI2C(GPIO_PORTK_BASE, 7); // Configurtes SDA
GPIOPinTypeI2CSCL(GPIO_PORTK_BASE, 6); // Configurtes SCL
GPIOPinTypeI2C(GPIO_PORTB_BASE, 7); // Configurtes SDA
GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, 6); // Configurtes SCL
I2CMasterInitExpClk(I2C4_BASE, SysCtlClockGet(), false);
I2CSlaveEnable(I2C6_BASE);
I2CSlaveInit(I2C6_BASE, SLAVE_ADDRESS);
I2CMasterSlaveAddrSet(I2C4_BASE, SLAVE_ADDRESS, false);
//
// Loop forever.
//
while(1)
{
//
// Turn on the LED.
//
GPIO_PORTD_AHB_DATA_R |= 0x8;
I2CMasterDataPut(I2C4_BASE, 0x33);
I2CMasterControl(I2C4_BASE, I2C_MASTER_CMD_SINGLE_SEND);
//
// Wait until the slave has received and acknowledged the data.
//
while(!(I2CSlaveStatus(I2C6_BASE) & I2C_SLAVE_ACT_RREQ));
//
// Read the data from the slave.
//
result = I2CSlaveDataGet(I2C6_BASE);
//
// Wait until master module is done transferring.
//
while(I2CMasterBusy(I2C4_BASE));
//
// Delay for a bit.
//
delay ();
//
// Turn off the LED.
//
GPIO_PORTD_AHB_DATA_R &= ~(0x8);
//
// Delay for a bit.
//
delay ();
}
}
The problem has been resolved. There were issues:
GPIOPinTypeI2C()
2nd parameter as a bit field instead of a bit number. SysCtlClockSet()
is dedicated specially to TM4C123 devices. Instead use g_ui32SysClock = SysCtlClockFreqSet((SYSCTL_OSC_MAIN | SYSCTL_XTAL_25MHZ | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_320), 40000000);
SysCtlClockGet()
procedure. This is also dedicated to TM4C123 devices. Instead use I2CMasterInitExpClk(I2C4_BASE, g_ui32SysClock, false);
Here is the updated 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 0x3C
void delay (void)
{
volatile uint32_t ui32Loop;
for(ui32Loop = 0; ui32Loop < 200; ui32Loop++);
}
volatile uint32_t result;
uint32_t g_ui32SysClock;
int main(void)
{
g_ui32SysClock = SysCtlClockFreqSet((SYSCTL_OSC_MAIN | SYSCTL_XTAL_25MHZ | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_320), 40000000);
//
// Enable the GPIO port that is used for the on-board LED.
//
SYSCTL_RCGCGPIO_R = SYSCTL_RCGCGPIO_R3 | SYSCTL_RCGCGPIO_R9 | SYSCTL_RCGCGPIO_R1;
//
// Do a dummy read to insert a few cycles after enabling the peripheral.
//
result = SYSCTL_RCGCGPIO_R;
//
// Enable the GPIO pin for the LED (PD3). Set the direction as output, and
// enable the GPIO pin for digital function.
//
GPIO_PORTD_AHB_DIR_R = 0x8;
GPIO_PORTD_AHB_DEN_R = 0x8;
SYSCTL_RCGCI2C_R = (1 << 4) | (1 << 6); // Mode Clock Gating Control for I2C modules 4 and 6
GPIOPinConfigure(GPIO_PK6_I2C4SCL);
GPIOPinConfigure(GPIO_PK7_I2C4SDA);
GPIOPinConfigure(GPIO_PB6_I2C6SCL);
GPIOPinConfigure(GPIO_PB7_I2C6SDA);
GPIOPinTypeI2C(GPIO_PORTK_BASE, (1 << 7)); // Configures SDA
GPIOPinTypeI2CSCL(GPIO_PORTK_BASE, (1 << 6)); // Configures SCL
GPIOPinTypeI2C(GPIO_PORTB_BASE, (1 << 7)); // Configures SDA
GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, (1 << 6)); // Configures SCL
I2CMasterInitExpClk(I2C4_BASE, g_ui32SysClock, false);
I2CSlaveEnable(I2C6_BASE);
I2CSlaveInit(I2C6_BASE, SLAVE_ADDRESS);
I2CMasterSlaveAddrSet(I2C4_BASE, SLAVE_ADDRESS, false);
//
// Loop forever.
//
while(1)
{
//
// Turn on the LED.
//
GPIO_PORTD_AHB_DATA_R |= 0x8;
I2CMasterDataPut(I2C4_BASE, 0x33);
I2CMasterControl(I2C4_BASE, I2C_MASTER_CMD_SINGLE_SEND);
//
// Wait until the slave has received and acknowledged the data.
//
while(!(I2CSlaveStatus(I2C6_BASE) & I2C_SLAVE_ACT_RREQ));
//
// Read the data from the slave.
//
result = I2CSlaveDataGet(I2C6_BASE);
//
// Wait until master module is done transferring.
//
while(I2CMasterBusy(I2C4_BASE));
//
// Delay for a bit.
//
delay ();
//
// Turn off the LED.
//
GPIO_PORTD_AHB_DATA_R &= ~(0x8);
//
// Delay for a bit.
//
delay ();
}
}
I was able to get I2C working on TIVA Launchpad TM4C123GH6PM. I used the the Tivaware library. I created 3 functions, init 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 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));
}
Complete code for TIVA + I2C can be found here.
Reference
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With