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 slave receiver and DMA (USCI30)

Hi there!

It is well known that MSP430F552x, MSP430F551x have a problem with I2C(USCI30). It was described in SLAZ054J–July 2009–Revised June 2010.

So, I could not implement a workaround. One of the ways is using the DMA. I chose this one. It  works excellent in degug mode,  but in normal mode (without debug) is absolutely defective.

Are there anybody who made it ? Please, show the code! :)

  • There is my testing code:

    #include <stdint.h>
    #include <msp430.h>
    #include <HAL_PMM.h>
    #include <HAL_UCS.h>

    #include <board.h>


    #define I2C_byte_number 3 // Amount of I2C bytes

    #define XT1_PORT_SEL P5SEL
    #define XT1_ENABLE (BIT4 + BIT5)

    #define DMADT5 (0x4000) // DMA Repeated single transfer
    #define DMADSTINCR (0x0C00) // Destination address is incremented
    #define DMASRCINCR (0x0100) // Source address is unchanged.

    #define I2C_FLAG_SET (FLAGS | BIT0) // Set bit I2C, command has been received
    #define I2C_FLAG_CLEAR (FLAGS & ~BIT0) // Clear bit I2C, command has been performed
    #define I2C_FLAG_BRANCH (FLAGS & BIT0) // Use in branch

    /***************************************************************************//**
    * Status Flags and general variables

    ******************************************************************************/

    //Status flags of device
    volatile unsigned short FLAGS = 0;

    /***************************************************************************//**
    * I2C variables

    ******************************************************************************/ //
    // I2C command //
    unsigned long TWIcmd = 0; //
    // Buffer for I2C command, it uses by DMA //
    unsigned char I2C_array[I2C_byte_number] = {0}; //
    // Pointer on I2C_array(destination address DMA) //
    unsigned char *ptr_I2C_array; //


    void main(void)
    {
    // Stop WDT
    WDTCTL = WDTPW + WDTHOLD;
    // Basic GPIO initialization

    // Setup XT2
    XT2_PORT_SEL |= XT2_ENABLE;

    // My configuration
    P4DIR |= BIT3; // Set P1.1 to output direction LED_Power_on
    P6DIR |= BIT2; // Set P1.2 to output direction Synch


    // Set Vcore to accomodate for max. allowed system speed
     SetVCore(1);

    UCSCTL6 &= ~XT2OFF; // Enable XT2 10MHz
    UCSCTL3 |= SELREF_2; // FLLref = REFO
    // Since LFXT1 is not used,
    // sourcing FLL with LFXT1 can cause
    // XT1OFFG flag to set
    UCSCTL4 |= SELA_2; // ACLK=REFO,SMCLK=DCO,MCLK=DCO


    // Loop until XT1,XT2 & DCO stabilizes - in this case loop until XT2 settles
    do
    {
    UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + DCOFFG);
    // Clear XT2,XT1,DCO fault flags
    SFRIFG1 &= ~OFIFG; // Clear fault flags
    }while (SFRIFG1&OFIFG); // Test oscillator fault flag

    UCSCTL6 &= ~XT2DRIVE0; // Decrease XT2 Drive according to
    // expected frequency
    UCSCTL4 |= SELS_5 + SELM_5 + SELA_5; // SMCLK=MCLK=XT2

    ptr_I2C_array = I2C_array;
    /*****************************************************************************
    I2C USC
    ******************************************************************************/
    UCB1CTL1 |= UCSWRST; // Enable SW reset
    UCB1CTL1 |= UCSSEL1; // SMCLK as clock of I2c
    UCB1CTL0 = UCMODE_3 + UCSYNC; // I2C Slave, synchronous mode
    UCB1I2COA &= ~UCGCEN; // Do not respond to a general call
    UCB1I2COA |= 0x8; // Own Address is 0x0A for REGENT, 0x08 for others
    P4SEL |= 0x06; // Assign I2C pins to USCI_B1
    UCB1CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
    UCB1IE |= UCTXIE + UCSTPIE + UCNACKIE;


    /*****************************************************************************
    DMA cnannel 0 for I2C slave receiver
    ******************************************************************************/

    DMACTL0 = 0x16; // UCB1RXIFG trigger;
    DMA0CTL |= DMADT5 + DMADSTINCR + DMASRCINCR + DMADSTBYTE + DMASRCBYTE + DMAEN + DMAIE;
    DMACTL4 = DMARMWDIS; // Read-modify-write disable
    DMA0SA = (unsigned short)&UCB1RXBUF;
    DMA0DA = (unsigned short)ptr_I2C_array;
    DMA0SZ = I2C_byte_number;
    DMA0CTL |= DMAREQ;

    __bis_SR_register(GIE); 

    while (1)
    {
    /*============================== Check I2C =================================*/
    if(I2C_FLAG_BRANCH)
    {
    FLAGS = I2C_FLAG_CLEAR;
    TWIcmd = 0; // Clear int value of command I2C
    }
    }
    }

    /***************************************************************************//**
    * @brief Handles I2C interrupts.
    *
    * Receive and send data to\from master
    * @param TXData is the intedger(4 bytes) value of I2C command.
    * Significant part is low three bytes.
    ******************************************************************************/
    // USCI_B1 State ISR
    #pragma vector = USCI_B1_VECTOR
    __interrupt void USCI_B1_ISR(void)
    {

    __disable_interrupt(); // Disable all interrupt
    switch(__even_in_range(UCB1IV,12))
    {

    case 0: break; // Vector 0: No interrupts
    case 2: break;
    case 4: // Vector 4: NACKIFG
    UCB1IFG &= ~UCSTPIFG; // Clear stop condition int flag
    UCB1IFG &= ~UCTXIFG; // Clear start condition int flag
    break;
    case 6: // Vector 6: STTIFG
    UCB1IFG &= ~UCSTTIFG;
    UCB1IFG &= ~UCTXIFG;
    break;
    case 8: // Vector 8: STPIFG
    UCB1IFG &= ~UCSTPIFG; // Clear stop condition int flag
    UCB1IFG &= ~UCTXIFG; // Clear start condition int flag
    break;

    /*------------------------------------------------------------------------------
    * RECEIVING
    ------------------------------------------------------------------------------*/
    //******************************************************************************
    case 10: // Vector 10: RXIFG
    //******************************************************************************

    break;
    /*------------------------------------------------------------------------------
    *
    * TRANSMITTING
    *
    ------------------------------------------------------------------------------*/
    //******************************************************************************
    case 12: // Vector 12: TXIFG
    //******************************************************************************
    UCB1TXBUF = 0xAB;

    break;
    default: break;
    }
    __enable_interrupt(); // Enable interrupts

    }
    //End of I2C interrupt


    /***************************************************************************//**
    * @brief Handles DMA interrupts.
    *
    * DMA interrupt occurs every 3 bytes after receiving command
    * from I2C master
    ******************************************************************************/


    #pragma vector=DMA_VECTOR
    __interrupt void DMA_ISR(void)
    {
    switch(__even_in_range(DMAIV,16))
    {
    case 0: break;
    case 2: // DMA0IFG = DMA Channel 0
    for(unsigned char a = 0; a < I2C_byte_number; a++)
    {TWIcmd = (TWIcmd << 8) + I2C_array[a];}

    FLAGS = I2C_FLAG_SET; // Set bit I2C command has been received
    break;
    case 4: break; // DMA1IFG = DMA Channel 1
    case 6: break; // DMA2IFG = DMA Channel 2
    case 8: break; // DMA3IFG = DMA Channel 3
    case 10: break; // DMA4IFG = DMA Channel 4
    case 12: break; // DMA5IFG = DMA Channel 5
    case 14: break; // DMA6IFG = DMA Channel 6
    case 16: break; // DMA7IFG = DMA Channel 7
    default: break;
    }
    }

**Attention** This is a public forum