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.

I2C with Stellaris Launchpad LM4F120H5QR

Hello,

Im tryng to get I2C protocol working on my stellaris launchpad. I found I2C example from StellarisWare software pakage and tried that. But it gets stuck in the while loop when waiting for answere back from slave:

//
// Wait until the slave has received and acknowledged the data.
//
while(!(I2CSlaveStatus(I2C0_SLAVE_BASE) & I2C_SCSR_RREQ))
{
}

Can anyone help me with this or provide a working example.

Heres the code:

 

//*****************************************************************************
//
// uart_echo.c - Example for reading data from and writing data to the UART in
// an interrupt driven fashion.
//
// Copyright (c) 2012 Texas Instruments Incorporated. All rights reserved.
// Software License Agreement
//
// Texas Instruments (TI) is supplying this software for use solely and
// exclusively on TI's microcontroller products. The software is owned by
// TI and/or its suppliers, and is protected under applicable copyright
// laws. You may not combine this software with "viral" open-source
// software in order to form a larger program.
//
// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
// DAMAGES, FOR ANY REASON WHATSOEVER.
//
// This is part of revision 9453 of the EK-LM4F120XL Firmware Package.
//
//*****************************************************************************

#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/debug.h"
#include "driverlib/fpu.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "inc/hw_i2c.h"
#include "driverlib/i2c.h"
#include "utils/uartstdio.h"

//*****************************************************************************
//
//! \addtogroup i2c_examples_list
//! <h1>I2C Master Loopback (i2c_master_slave_loopback)</h1>
//!
//! This example shows how to configure the I2C0 module for loopback mode.
//! This includes setting up the master and slave module. Loopback mode
//! internally connects the master and slave data and clock lines together.
//! The address of the slave module is set in order to read data from the
//! master. Then the data is checked to make sure the received data matches
//! the data that was transmitted. This example uses a polling method for
//! sending and receiving data.
//!
//! This example uses the following peripherals and I/O signals. You must
//! review these and change as needed for your own board:
//! - I2C0 peripheral
//! - GPIO Port B peripheral (for I2C0 pins)
//! - I2C0SCL - PB2
//! - I2C0SDA - PB3
//!
//! The following UART signals are configured only for displaying console
//! messages for this example. These are not required for operation of I2C.
//! - UART0 peripheral
//! - GPIO Port A peripheral (for UART0 pins)
//! - UART0RX - PA0
//! - UART0TX - PA1
//!
//! This example uses the following interrupt handlers. To use this example
//! in your own application you must add these interrupt handlers to your
//! vector table.
//! - None.
//!
//
//*****************************************************************************

//*****************************************************************************
//
// Number of I2C data packets to send.
//
//*****************************************************************************
#define NUM_I2C_DATA 3

//*****************************************************************************
//
// Set the address for slave module. This is a 7-bit address sent in the
// following format:
// [A6:A5:A4:A3:A2:A1:A0:RS]
//
// A zero in the "RS" position of the first byte means that the master
// transmits (sends) data to the selected slave, and a one in this position
// means that the master receives data from the slave.
//
//*****************************************************************************
#define SLAVE_ADDRESS 0x3C

//*****************************************************************************
//
// This function sets up UART0 to be used for a console to display information
// as the example is running.
//
//*****************************************************************************
void
InitConsole(void)
{
//
// Initialize the UART and configure it for 115,200, 8-N-1 operation.
//
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
GPIOPinConfigure(GPIO_PA0_U0RX);
GPIOPinConfigure(GPIO_PA1_U0TX);
ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
UARTStdioInit(0);
}

//*****************************************************************************
//
// Configure the I2C0 master and slave and connect them using loopback mode.
//
//*****************************************************************************
int
main(void)
{
unsigned long ulDataTx[NUM_I2C_DATA];
unsigned long ulDataRx[NUM_I2C_DATA];
unsigned long ulindex;

//
// Set the clocking to run directly from the external crystal/oscillator.
// TODO: The SYSCTL_XTAL_ value must be changed to match the value of the
// crystal on your board.
//
SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
SYSCTL_XTAL_16MHZ);

//
// The I2C0 peripheral must be enabled before use.
//
SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);

//
// For this example I2C0 is used with PortB[3:2]. The actual port and
// pins used may be different on your part, consult the data sheet for
// more information. GPIO port B needs to be enabled so these pins can
// be used.
// TODO: change this to whichever GPIO port you are using.
//
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);

//
// Configure the pin muxing for I2C0 functions on port B2 and B3.
// This step is not necessary if your part does not support pin muxing.
// TODO: change this to select the port/pin you are using.
//
GPIOPinConfigure(GPIO_PB2_I2C0SCL);
GPIOPinConfigure(GPIO_PB3_I2C0SDA);

//
// Select the I2C function for these pins. This function will also
// configure the GPIO pins pins for I2C operation, setting them to
// open-drain operation with weak pull-ups. Consult the data sheet
// to see which functions are allocated per pin.
// TODO: change this to select the port/pin you are using.
//
GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_2 | GPIO_PIN_3);

//
// Enable loopback mode. Loopback mode is a built in feature that is
// useful for debugging I2C operations. It internally connects the I2C
// master and slave terminals, which effectively let's you send data as
// a master and receive data as a slave.
// NOTE: For external I2C operation you will need to use external pullups
// that are stronger than the internal pullups. Refer to the datasheet for
// more information.
//
HWREG(I2C0_MASTER_BASE + I2C_O_MCR) |= 0x01;

//
// 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. For this example we will use a data rate of 100kbps.
//
I2CMasterInitExpClk(I2C0_MASTER_BASE, SysCtlClockGet(), false);

//
// Enable the I2C0 slave module. This module is enabled only for testing
// purposes. It does not need to be enabled for proper operation of the
// I2Cx master module.
//
I2CSlaveEnable(I2C0_SLAVE_BASE);

//
// Set the slave address to SLAVE_ADDRESS. In loopback mode, it's an
// arbitrary 7-bit number (set in a macro above) that is sent to the
// I2CMasterSlaveAddrSet function.
//
I2CSlaveInit(I2C0_SLAVE_BASE, SLAVE_ADDRESS);

//
// Tell the master module what address it will place on the bus when
// communicating with the slave. Set the address to SLAVE_ADDRESS
// (as set in the slave module). The receive parameter is set to false
// which indicates the I2C Master is initiating a writes to the slave. If
// true, that would indicate that the I2C Master is initiating reads from
// the slave.
//
I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, SLAVE_ADDRESS, false);

//
// Set up the serial console to use for displaying messages. This is
// just for this example program and is not needed for I2C operation.
//
InitConsole();

//
// Display the example setup on the console.
//
UARTprintf("I2C Loopback Example ->");
UARTprintf("\n Module = I2C0");
UARTprintf("\n Mode = Single Send/Receive");
UARTprintf("\n Rate = 100kbps\n\n");

//
// Initalize the data to send.
//
ulDataTx[0] = 'I';
ulDataTx[1] = '2';
ulDataTx[2] = 'C';

//
// Initalize the receive buffer.
//
for(ulindex = 0; ulindex < NUM_I2C_DATA; ulindex++)
{
ulDataRx[ulindex] = 0;
}

//
// Indicate the direction of the data.
//
UARTprintf("Tranferring from: Master -> Slave\n");

//
// Send 3 peices of I2C data from the master to the slave.
//
for(ulindex = 0; ulindex < NUM_I2C_DATA; ulindex++)
{
//
// Display the data that the I2C0 master is transferring.
//
UARTprintf(" Sending: '%c' . . . ", ulDataTx[ulindex]);

//
// Place the data to be sent in the data register
//
I2CMasterDataPut(I2C0_MASTER_BASE, ulDataTx[ulindex]);

//
// Initiate send of data from the master. Since the loopback
// mode is enabled, the master and slave units are connected
// allowing us to receive the same data that we sent out.
//
I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_SINGLE_SEND);

//
// Wait until the slave has received and acknowledged the data.
//
while(!(I2CSlaveStatus(I2C0_SLAVE_BASE) & I2C_SCSR_RREQ))
{
}

//
// Read the data from the slave.
//
ulDataRx[ulindex] = I2CSlaveDataGet(I2C0_SLAVE_BASE);

//
// Wait until master module is done transferring.
//
while(I2CMasterBusy(I2C0_MASTER_BASE))
{
}

//
// Display the data that the slave has received.
//
UARTprintf("Received: '%c'\n", ulDataRx[ulindex]);
}

//
// Reset receive buffer.
//
for(ulindex = 0; ulindex < NUM_I2C_DATA; ulindex++)
{
ulDataRx[ulindex] = 0;
}

//
// Indicate the direction of the data.
//
UARTprintf("\n\nTranferring from: Slave -> Master\n");

//
// Modifiy the data direction to true, so that seeing the address will
// indicate that the I2C Master is initiating a read from the slave.
//
I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, SLAVE_ADDRESS, true);

//
// Do a dummy receive to make sure you don't get junk on the first receive.
//
I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);

//
// Dummy acknowledge and wait for the receive request from the master.
// This is done to clear any flags that should not be set.
//
while(!(I2CSlaveStatus(I2C0_SLAVE_BASE) & I2C_SLAVE_ACT_TREQ))
{
}

for(ulindex = 0; ulindex < NUM_I2C_DATA; ulindex++)
{
//
// Display the data that I2C0 slave module is transferring.
//
UARTprintf(" Sending: '%c' . . . ", ulDataTx[ulindex]);

//
// Place the data to be sent in the data register
//
I2CSlaveDataPut(I2C0_SLAVE_BASE, ulDataTx[ulindex]);

//
// Tell the master to read data.
//
I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);

//
// Wait until the slave is done sending data.
//
while(!(I2CSlaveStatus(I2C0_SLAVE_BASE) & I2C_SLAVE_ACT_TREQ))
{
}

//
// Read the data from the master.
//
ulDataRx[ulindex] = I2CMasterDataGet(I2C0_MASTER_BASE);

//
// Display the data that the slave has received.
//
UARTprintf("Received: '%c'\n", ulDataRx[ulindex]);
}


//
// Tell the user that the test is done.
//
UARTprintf("\nDone.\n\n");

//
// Return no errors
//
return(0);
}

  • It helps to know exactly which processor and the source of the example...

    In the meantime. let's pretend it's a LaucnhPad -- download the PINMUX utility, choose the I2C ports, and generate the header code for using the ports. Note the code generated. Compare particularly the initialization code for the SCL line.

    You could also look for I2C posts by cb1 -- he pointed out the issue with the SCL code initially I think.

    The example code for the LaunchPad does work -- I have tested it. I also changed it so that wires had to be connected externally. That works too.

    It should take about ten minutes to spot the problems if they are what I think they are.

    Merry Christmas from Canada!

  • Hello,

    Sorry, forgot to mention the processor number in the post, but its in the title. Processor is LX4F120H5QRF. 
    This sample code is from  "C:\StellarisWare\examples\peripherals\i2c\master_slave_loopback.c" where "C:\StellarisWare\" is the default installation location for StellarisWare.

    EDIT: 

    I trie and generated the code with PinMUX Utility but it didnt change anything. Heres the code i got from MuxUtility:

    void
    i2c_setup(void)
    {
    //
    // Enable Peripheral Clocks
    //
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C1);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);

    //
    // Enable port PB2 for I2C0 I2C0SCL
    //
    MAP_GPIOPinConfigure(GPIO_PB2_I2C0SCL);
    MAP_GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);

    //
    // Enable port PB3 for I2C0 I2C0SDA
    //
    MAP_GPIOPinConfigure(GPIO_PB3_I2C0SDA);
    MAP_GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);

    //
    // Enable port PA7 for I2C1 I2C1SDA
    //
    MAP_GPIOPinConfigure(GPIO_PA7_I2C1SDA);
    MAP_GPIOPinTypeI2C(GPIO_PORTA_BASE, GPIO_PIN_7);

    //
    // Enable port PA6 for I2C1 I2C1SCL
    //
    MAP_GPIOPinConfigure(GPIO_PA6_I2C1SCL);
    MAP_GPIOPinTypeI2CSCL(GPIO_PORTA_BASE, GPIO_PIN_6);
    }

    EDIT 2:

    Found another strange thing, when running the code woth debugger it gets stuck in the while loop i posted in the first post but when running without debugging everything works. 

    Priit.

  • Hi Priit,

    don't try to single-step I2C communication during debugging! Use breakpoints instead!

    Rgds
    aBUGSworstnightmare 

  • Hei aBUGSworstnightmare,

    I didnt try to single-step, i just hit run after getting to main function and that was it, it got stuck in the while when waiting for flag what's set when slave receives message. When i closed debug session it run nicely through everything.

    Priit.