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.

PROBLEM I2C Tiva DK-129X (Master) and TLV320AIC3107 audio DAC (Slave)

Other Parts Discussed in Thread: TLV320AIC3107

Hi everybody, I new here and I need your experience and assistance. I'm in a new project (Audio control by TM4C129XNCZA) and I'm having many troubles with I2C module. In the first instance I want to write and read data from a register of TLV320AIC3107 for initing device. I base on code driver of TI (dac.c). But it always loop for waiting byte transfer.

    //
    // Wait until the current byte has been transferred.
    //
    while(I2CMasterIntStatus(DAC_I2C_MASTER_BASE, false))
    {
        I2CMasterIntClear(DAC_I2C_MASTER_BASE);
    }
KIT I am using DK-129x for TM4C and TLV320AIC3107EVM kit for TLV320AIC3107. And I use i2c 1 to control.

Link for DK-129x : www.ti.com/.../spmu360.pdf

Link for TLV320AIC3107EVM :  www.ti.com/.../slau261.pdf

And here is my code.

#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_ints.h"
#include "inc/hw_ssi.h"
#include "driverlib/ssi.h"
#include "driverlib/debug.h"
#include "driverlib/gpio.h"
#include "driverlib/i2c.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/systick.h"
#include "driverlib/sysctl.h"
#include "driverlib/udma.h"
#include "driverlib/interrupt.h"
#include "driverlib/timer.h"
#include "dac.h"

//*****************************************************************************
//
//! \addtogroup dac_api
//! @{
//
//*****************************************************************************

//*****************************************************************************
//
// The I2C and reset pins that are used by this application.
//
//*****************************************************************************
#define DAC_I2C_PERIPH                  (SYSCTL_PERIPH_I2C1)
#define DAC_I2C_GPIO_PERIPH             (SYSCTL_PERIPH_GPIOG)
#define DAC_I2CSCL_GPIO                 (GPIO_PG0_I2C1SCL)
#define DAC_I2CSDA_GPIO                 (GPIO_PG1_I2C1SDA)
#define DAC_I2C_BASE                    (GPIO_PORTG_BASE)
#define DAC_I2CSDA_PIN                  (GPIO_PIN_1)
#define DAC_I2CSCL_PIN                  (GPIO_PIN_0)
#define DAC_I2C_MASTER_BASE             (I2C1_BASE)

#define DAC_RESET_GPIO_PERIPH           (SYSCTL_PERIPH_GPIOE)
#define DAC_RESET_GPIO_PORT             (GPIO_PORTE_BASE)
#define DAC_RESET_PIN                   (GPIO_PIN_4)

//*****************************************************************************
//
// The current volume of the DAC.
//
//*****************************************************************************
unsigned long g_ucHPVolume;
extern uint32_t g_ui32SysClock;
//****************************************************************************

//*****************************************************************************
#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_ints.h"
#include "inc/hw_ssi.h"
#include "driverlib/ssi.h"
#include "driverlib/debug.h"
#include "driverlib/gpio.h"
#include "driverlib/i2c.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/systick.h"
#include "driverlib/sysctl.h"
#include "driverlib/udma.h"
#include "driverlib/interrupt.h"
#include "driverlib/timer.h"
#include "dac.h"

//*****************************************************************************
//
//! \addtogroup dac_api
//! @{
//
//*****************************************************************************

//*****************************************************************************
//
// The I2C and reset pins that are used by this application.
//
//*****************************************************************************
#define DAC_I2C_PERIPH                  (SYSCTL_PERIPH_I2C1)
#define DAC_I2C_GPIO_PERIPH             (SYSCTL_PERIPH_GPIOG)
#define DAC_I2CSCL_GPIO                 (GPIO_PG0_I2C1SCL)
#define DAC_I2CSDA_GPIO                 (GPIO_PG1_I2C1SDA)
#define DAC_I2C_BASE                    (GPIO_PORTG_BASE)
#define DAC_I2CSDA_PIN                  (GPIO_PIN_1)
#define DAC_I2CSCL_PIN                  (GPIO_PIN_0)
#define DAC_I2C_MASTER_BASE             (I2C1_BASE)

#define DAC_RESET_GPIO_PERIPH           (SYSCTL_PERIPH_GPIOE)
#define DAC_RESET_GPIO_PORT             (GPIO_PORTE_BASE)
#define DAC_RESET_PIN                   (GPIO_PIN_4)

//*****************************************************************************
//
// The current volume of the DAC.
//
//*****************************************************************************
unsigned long g_ucHPVolume;
extern uint32_t g_ui32SysClock;
//*****************************************************************************
//
//! Writes a register in the TLV320AIC3107 DAC.
//!
//! \param ucRegister is the offset to the register to write.
//! \param ulData is the data to be written to the DAC register.
//!
//!  This function will write the register passed in ucAddr with the value
//!  passed in to ulData.  The data in ulData is actually 9 bits and the
//!  value in ucAddr is interpreted as 7 bits.
//!
//! \return True on success or false on error.
//
//*****************************************************************************
bool
DACWriteRegister(unsigned char ucRegister, unsigned long ulData)
{
    IntMasterDisable();

    //
    // Set the slave address.
    //
    I2CMasterSlaveAddrSet(DAC_I2C_MASTER_BASE, TI_TLV320AIC3107_ADDR,
                          false);

    //
    // Write the first byte to the controller (register)
    //
    I2CMasterDataPut(DAC_I2C_MASTER_BASE, ucRegister);

    //
    // Continue the transfer.
    //
    I2CMasterControl(DAC_I2C_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_START);

    //
    // Wait until the current byte has been transferred.
    //
    while(I2CMasterIntStatus(DAC_I2C_MASTER_BASE, false) == 0)
    {
    }

    if(I2CMasterErr(DAC_I2C_MASTER_BASE) != I2C_MASTER_ERR_NONE)
    {
        I2CMasterIntClear(DAC_I2C_MASTER_BASE);
        return(false);
    }

    //
    // Wait until the current byte has been transferred.
    //
    while(I2CMasterIntStatus(DAC_I2C_MASTER_BASE, false))
    {
        I2CMasterIntClear(DAC_I2C_MASTER_BASE);
    }
//while(I2CMasterBusy(DAC_I2C_MASTER_BASE))
//{}
    //
    // Write the data byte to the controller.
    //
    I2CMasterDataPut(DAC_I2C_MASTER_BASE, ulData);

    //
    // End the transfer.
    //
    I2CMasterControl(DAC_I2C_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);

    //
    // Wait until the current byte has been transferred.
    //
    while(I2CMasterIntStatus(DAC_I2C_MASTER_BASE, false) == 0)
    {
    }

    if(I2CMasterErr(DAC_I2C_MASTER_BASE) != I2C_MASTER_ERR_NONE)
    {
        return(false);
    }

    while(I2CMasterIntStatus(DAC_I2C_MASTER_BASE, false))
    {
        I2CMasterIntClear(DAC_I2C_MASTER_BASE);
    }

    IntMasterEnable();

    return(true);
}

//*****************************************************************************
//
// Reads a register in the TLV320AIC3107 DAC.
//
// \param ucRegister is the offset to the register to write.
// \param pucData is a pointer to the returned data.
//
//  \return \b true on success or \b false on error.
//
//*****************************************************************************
static bool
DACReadRegister(unsigned char ucRegister, unsigned char *pucData)
{
    //
    // Set the slave address and "WRITE"
    //
    I2CMasterSlaveAddrSet(DAC_I2C_MASTER_BASE, TI_TLV320AIC3107_ADDR,
                              false);

    //
    // Write the first byte to the controller (register)
    //
    I2CMasterDataPut(DAC_I2C_MASTER_BASE, ucRegister);

    //
    // Continue the transfer.
    //
    I2CMasterControl(DAC_I2C_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_START);

    //
    // Wait until the current byte has been transferred.
    //
    while(I2CMasterIntStatus(DAC_I2C_MASTER_BASE, false) == 0)
    {
    }

    if(I2CMasterErr(DAC_I2C_MASTER_BASE) != I2C_MASTER_ERR_NONE)
    {
        I2CMasterIntClear(DAC_I2C_MASTER_BASE);
        return(false);
    }

    //
    // Wait until the current byte has been transferred.
    //
    while(I2CMasterIntStatus(DAC_I2C_MASTER_BASE, false))
    {
        I2CMasterIntClear(DAC_I2C_MASTER_BASE);
    }

    //
    // Set the slave address and "READ"/true.
    //
    I2CMasterSlaveAddrSet(DAC_I2C_MASTER_BASE, TI_TLV320AIC3107_ADDR, true);

    //
    // Read Data Byte.
    //
    I2CMasterControl(DAC_I2C_MASTER_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);

    //
    // Wait until the current byte has been transferred.
    //
    while(I2CMasterIntStatus(DAC_I2C_MASTER_BASE, false) == 0)
    {
    }

    if(I2CMasterErr(DAC_I2C_MASTER_BASE) != I2C_MASTER_ERR_NONE)
    {
        I2CMasterIntClear(DAC_I2C_MASTER_BASE);
        return(false);
    }

    //
    // Wait until the current byte has been transferred.
    //
    while(I2CMasterIntStatus(DAC_I2C_MASTER_BASE, false))
    {
        I2CMasterIntClear(DAC_I2C_MASTER_BASE);
    }

    //
    // Read the value received.
    //
    *pucData  = I2CMasterDataGet(DAC_I2C_MASTER_BASE);

    return(true);
}

//*****************************************************************************
//
//! Initializes the TLV320AIC3107 DAC.
//!
//! This function initializes the I2C interface and the TLV320AIC3107 DAC. It
//! must be called prior to any other API in the DAC module.
//!
//! \return Returns \b true on success or \b false on failure.
//
//*****************************************************************************
bool
DACInit(void)
{
    bool bRetcode;
    unsigned char ucTest;
    uint8_t ucread;

    //
    // Enable the GPIO port containing the I2C pins and set the SDA pin as a
    // GPIO input for now and engage a weak pull-down.  If the daughter board
    // is present, the pull-up on the board should easily overwhelm
    // the pull-down and we should read the line state as high.
    //
    SysCtlPeripheralReset(DAC_I2C_PERIPH);
    SysCtlPeripheralEnable(DAC_I2C_PERIPH); 

    //
    // Enable the I2C peripheral.
    //
    SysCtlPeripheralReset(DAC_I2C_GPIO_PERIPH);
    SysCtlPeripheralEnable(DAC_I2C_GPIO_PERIPH);

    //
    // Delay a while to ensure that we read a stable value from the SDA
    // GPIO pin.  If we read too quickly, the result is unpredictable.
    // This delay is around 2mS.
    //
    SysCtlDelay(g_ui32SysClock / (3 * 500));

    //
    // Configure the pin mux.
    //
    GPIOPinConfigure(DAC_I2CSCL_GPIO);
    GPIOPinConfigure(DAC_I2CSDA_GPIO);

    //
    // Configure the I2C SCL and SDA pins for I2C operation.
    //
    GPIOPinTypeI2C(DAC_I2C_BASE, DAC_I2CSDA_PIN);
    GPIOPinTypeI2CSCL(DAC_I2C_BASE, DAC_I2CSCL_PIN);    

    //
    // Initialize the I2C master.
    //
    I2CMasterInitExpClk(DAC_I2C_MASTER_BASE, g_ui32SysClock, false);
     SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C1);

    //
    // Enable the I2C peripheral.
    //
    //SysCtlPeripheralEnable(DAC_RESET_GPIO_PERIPH);

    //
    // Configure the PD0 as a GPIO output.
    //
    GPIOPinTypeGPIOOutput(DAC_RESET_GPIO_PORT, DAC_RESET_PIN);

    //
    // Reset the DAC
    //
    GPIOPinWrite(DAC_RESET_GPIO_PORT , DAC_RESET_PIN, 0);
    GPIOPinWrite(DAC_RESET_GPIO_PORT , DAC_RESET_PIN, DAC_RESET_PIN);

    //
    // Reset the DAC.  Check the return code on this call since we use it to
    // indicate whether or not the DAC is present.  If the register write
    // fails, we assume the I2S daughter board and DAC are not present and
    // return false.
    //
    bRetcode = DACWriteRegister(TI_SOFTWARE_RESET_R, 0x80);
    if(!bRetcode)
    {
        return(bRetcode);
    }

    //
    // Codec Data Path Register
    // ----------------------
    // Fsref = 44.1kHz.
    // Left DAC datapath plays left channel input data.
    // Right DAC datapath plays right channel input data.
    // ----------------------
    // D[7:0] = 1000 1010
    //
    DACWriteRegister(7, 0x8A);

    //
    // Audio Serial Data Interface Control Register A
    // ----------------------
    // BCLK is an output (master mode)
    // WCLK is an output (master mode)
    // BCLK/WCLK will continue to be transmitted when running in master mode.
    // ----------------------
    // D[7:0] = 1101 0000
    //
    DACWriteRegister(8, 0xD0);
    DACReadRegister(8, &ucread);

    //
    // Audio Serial Data Interface Control Register B
    // ----------------------
    // Serial data bus uses I2S mode.
    // Audio data word length = 16-bits.
    // ----------------------
    // D[7:0] = 0000 0000
    //        
    DACWriteRegister(9, 0x00);

    //
    // PLL Programming Register A
    // ----------------------
    // PLL Disabled (Enable Later)
    // Q = 2
    // P = 2
    // ----------------------
    // D[7:0] = 0001 0010
    //    
    DACWriteRegister(3, 0x12);

    //
    // PLL Programming Register B
    // ----------------------
    // J = 7
    // ----------------------
    // D[7:0] = 0001 1100
    //    
    DACWriteRegister(4, 0x1C);

    //
    // PLL Programming Register C
    // ----------------------
    // D most significant bits
    // ----------------------
    // D[7:0] = 0010 0011
    //    
    DACWriteRegister(5, 0x23);

    //
    // PLL Programming Register D
    // ----------------------
    // D least significant bits
    // ----------------------
    // D[7:0] = 0011 0100
    //    
    DACWriteRegister(6, 0x34);

    //
    // PLL Programming Register A
    // ----------------------
    // PLL is enabled.
    // Q = 2.
    // P = 2.
    // ----------------------
    // D[7:0] = 1001 0010 
    //   
    DACWriteRegister(3, 0x92);

    //
    // Headset/Button Press Detection Register A
    // ----------------------
    // Headset detection enabled.
    // ----------------------
    // D[7:0] = 1000 0000
    //   
    DACWriteRegister(13, 0x80);

    //
    // Headset/Button Press Detection Register B
    // ----------------------
    // Configure to stereo fully-differential output
    // ----------------------
    // D[7:0] = 0100 0000
    //   
    DACWriteRegister(14, 0x40);

    //
    // DAC Output Switching Control Register
    // ----------------------
    // Left DAC output selects DAC_L1 path
    // Right DAC output selects DAC_R1 path
    // Left and right DAC channels have independent volume controls.
    // ----------------------
    // D[7:0] = 0000 0000
    //   
    DACWriteRegister(41, 0x00);

    //
    // Left DAC Digital Volume Control Register
    // ----------------------
    // The left DAC is not muted.
    // Gain = 0.0dB.
    // ----------------------
    // D[7:0] = 0000 0000
    //   
    DACWriteRegister(43, 0x00);

    //
    // Right DAC Digital Volume Control Register
    // ----------------------
    // The right DAC channel is not muted.
    // Gain = 0.0dB.
    // ----------------------
    // D[7:0] = 0000 0000 
    //   
    DACWriteRegister(44, 0x00);

    //
    // Codec Sample Rate Select Register
    // ----------------------
    // DAC Fs = Fsref/4.
    // ----------------------
    // D[7:0] = 0000 0110
    //   
    DACWriteRegister(2, 0x06);

    //
    // DAC_L1 to HPLOUT Volume Control Register
    // ----------------------
    // DAC_L1 is routed to HPLOUT.
    // ----------------------
    // D[7:0] = 1000 0000
    //   
    DACWriteRegister(47, 0x80);

    //
    // DAC_R1 to HPROUT Volume Control Register
    // ----------------------
    // DAC_R1 is routed to HPROUT.
    // ----------------------
    // D[7:0] = 1000 0000
    //   
    DACWriteRegister(64, 0x80);

    //
    // DAC Power and Output Driver Control Register
    // ----------------------
    // Left DAC is powered up.
    // Right DAC is powered up.
    // ----------------------
    // D[7:0] = 1100 0000
    //     
    DACWriteRegister(37, 0xC0);

    //
    // Using L2/R2 bypasses the analog volume controls & mixing  networks. This
    // output provides the highest quality DAC playback performance with 
    // reduced power dissipation. Note: This can only be utilized if the DAC
    // output does not need to route to multiple output drivers simultaneously,
    // and if mixing of the DAC output with other analog signals is not needed. 
    // If mixing isdesired, L1/R2 would be utilized. However, for our
    // differential headpones/speakers, this will suffice.
    //
    // DAC Output Switching Control Register
    // ----------------------
    // Left DAC output selects DAC_L2 path to left high power output drivers.
    // Right DAC output selects DAC_R2 path to right high power output drivers.
    // ----------------------
    // D[7:0] = 1010 0000
    //   
    DACWriteRegister(41, 0xA0);

    //
    // Output Driver Pop Reduction Register
    // ----------------------
    // Driver power-on time = 400mS.
    // Driver ramp-up step time = 0mS.
    // ----------------------
    // D[7:0] = 1000 0000
    //   
    DACWriteRegister(42, 0x80);

    //
    // HPROUT Output Level Control Register
    // ----------------------
    // Output level control = 0dB.
    // HPROUT is not muted.
    // HPROUT is weakly driven to a common-mode when powered down.
    // HPROUT is fully powered up.
    // ----------------------
    // D[7:0] = 0000 1101
    //         
    DACWriteRegister(65, 0x0D);

    //
    // HPLOUT Output Level Control Reigster
    // ----------------------
    // Output level control = 0dB.
    // HPLOUT is not muted.
    // HPLOUT is weakly driven to a common-mode when powered down.
    // HPLOUT is fully powered up. 
    // ----------------------
    // D[7:0] = 0000 1101
    //    
    DACWriteRegister(51, 0x0D);

    //
    // Left DAC Digital Volume Control Register
    // ----------------------
    // Gain = -30dB.
    // ----------------------
    // D[7:0] = 0010 1100
    //    
    DACWriteRegister(43, pucVolumeTable[50 / 10 - 1]);

    //
    // Right DAC Digital Volume Control Register
    // ----------------------
    // Gain = -30dB.
    // ----------------------
    // D[7:0] = 0011 1100
    //   
    DACWriteRegister(44, pucVolumeTable[3]);

    //
    // Codec Datapath Setup Register
    // ----------------------
    // Fsref = 44.1kHz.
    // DAC dual rate mode is enabled.
    // LEFT DAC datapath plays left channel input data.
    // RIGHT DAC datapath plays right channel input data.
    // ----------------------
    // D[7:0] = 1010 1010
    //   
    DACWriteRegister(7, 0xAA);

    //
    // Codec Sample Rate Select Register
    // ----------------------
    // DAC Fs = Fsref/2
    // ----------------------
    // D[7:0] = 0000 0010
    //   
    DACWriteRegister(2, 0x02);

    //
    //Read Module Power Status Register
    //
    bRetcode = DACReadRegister(TI_MODULE_PWR_STAT_R, &ucTest);
    if(!bRetcode)
    {
        return(bRetcode);
    }

    return(true);
}

  • May I note yours as a comprehensive & well thought post? Especially for one new here - well done.

    You describe TM4C129 - yet much of this "I2C" code appears LX4F and TM4C123 based! Vendor's Amit has noted the need for a "double check (back-to-back)" method to insure that the I2C is "non-busy." I did not note that w/in your code. (possibly missed)

    If not answered quickly your search of the forum under TM4C129 I2C should prove useful...