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.

CCS/MSP432P401R: SPI+DMA conflicts with I2C Interrupts simultaneously

Part Number: MSP432P401R

Tool/software: Code Composer Studio

Hi,

i am using the MSp432 to read a sensor on I2C (EUSCI_B1_BASE) and on the same time read an other sensor on SPI (EUSCI_A1_BASE + DMA_CH2_EUSCIA1TX +  DMA_CH3_EUSCIA1RX).

The Sensor_SPI gives me an interrupt on GPIO, i activate the DMA_CH2_EUSCIA1TX and get the DMA_CH3_EUSCIA1RX interurpt that data is ready to be read.

This is working fine.

The SPI_I2C gives an interrupt on GPIO  and here i set a flag to read the data later. So on the I2C by reading the values if have to use EUSCIB1_IRQHandler to EUSCI_B_I2C_RECEIVE_INTERRUPT0 or EUSCI_B_I2C_TRANSMIT_INTERRUPT0. And here is the problem that it gets stock here:

I2C_masterSendMultiByteStopWithTimeout(EUSCI_B1_BASE,1000); or I2C_masterSendMultiByteStopWithTimeout(EUSCI_B1_BASE,1000);

if the Sensor_SPI  is running simultaneously.

If i dont use the DMA on SPI and just set a flag and read the value later it works but i miss some Sensor_SPI data. The DMA set up is the bestone because i dont loose any information but it conflicts with my I2C EUSCIB1_IRQHandler some how.

Any idea?

  • Michael,

       I do not believe that the issue is related to the DMA and/or SPI but a timing issue in the I2C.   Does the I2C follow the format of this example?  If interrupts are enabled the assumption is that the API was called because the TX interrupt was serviced.  

    Regards,

    Chris

  • Hi Chris,

    yes it is the same as in the example. Yes it was called but why does it hangs there?
    It only leaves once timout expires.
  • I am concerned about the logic of the API and I will look into this further.  So you are not using interrupts when calling the API?

    Thanks,

    Chris

    bool I2C_masterSendMultiByteStopWithTimeout(uint32_t moduleInstance,
            uint32_t timeout)
    {
        ASSERT(timeout > 0);
    
        //If interrupts are not used, poll for flags
        if (!BITBAND_PERI(EUSCI_B_CMSIS(moduleInstance)->IE, EUSCI_B_IE_TXIE0_OFS))
        {
            //Poll for transmit interrupt flag.
            while ((!BITBAND_PERI(EUSCI_B_CMSIS(moduleInstance)->IFG,
                    EUSCI_B_IFG_TXIFG0_OFS)) && --timeout)
                ;
    
            //Check if transfer timed out
            if (timeout == 0)
                return false;
        }
    
        //Send stop condition.
        BITBAND_PERI(EUSCI_B_CMSIS(moduleInstance)->CTLW0, EUSCI_B_CTLW0_TXSTP_OFS) =
                1;
    
        return 0x01;
    }

  • Hi Chris,

    i am using I2C Interrupt. Here is my code:

    bool readBurstI2C_1(uint8_t ui8Addr, uint8_t ui8Reg, uint8_t *Data, uint32_t ui32ByteCount)
    {
    	/* Todo: Put a delay */
    	/* Wait until ready */
        int counterGetOut=0;
        while (MAP_I2C_isBusBusy(EUSCI_B1_BASE))
        {
            counterGetOut++;
            if(counterGetOut>=10000)
                return false;
        }
    
    	/* Assign Data to local Pointer */
    	pData_1 = Data;
    
        /* Disable I2C module to make changes */
        MAP_I2C_disableModule(EUSCI_B1_BASE);
    
      	/* Setup the number of bytes to receive */
        i2cConfig1.autoSTOPGeneration = EUSCI_B_I2C_NO_AUTO_STOP;
        g_ui32ByteCount_1 = ui32ByteCount;
        burstMode_1 = true;
        MAP_I2C_initMaster(EUSCI_B1_BASE, (const eUSCI_I2C_MasterConfig *)&i2cConfig1);
    
    	/* Load device slave address */
    	MAP_I2C_setSlaveAddress(EUSCI_B1_BASE, ui8Addr);
    
        /* Enable I2C Module to start operations */
    	MAP_I2C_enableModule(EUSCI_B1_BASE);
    
      	/* Enable master STOP and NACK interrupts */
        MAP_I2C_enableInterrupt(EUSCI_B1_BASE, EUSCI_B_I2C_STOP_INTERRUPT +EUSCI_B_I2C_NAK_INTERRUPT);
    
        /* Set our local state to Busy */
        ui8Status_1 = eUSCI_BUSY_1;
    
      	/* Send start bit and register */
      	MAP_I2C_masterSendMultiByteStart(EUSCI_B1_BASE,ui8Reg);
    
      	/* Enable master interrupt for the remaining data */
        MAP_Interrupt_enableInterrupt(INT_EUSCIB1);
    
      	/* NOTE: If the number of bytes to receive = 1, then as target register is being shifted
      	 * out during the write phase, UCBxTBCNT will be counted and will trigger STOP bit prematurely
      	 * If count is > 1, wait for the next TXBUF empty interrupt (just after reg value has been
      	 * shifted out
      	 */
        counterGetOut=0;
    	while(ui8Status_1 == eUSCI_BUSY_1)
    	{
    		if(MAP_I2C_getInterruptStatus(EUSCI_B1_BASE, EUSCI_B_I2C_TRANSMIT_INTERRUPT0))
    		{
    			ui8Status_1 = eUSCI_IDLE_1;
    		}
            else
            {
                counterGetOut++;
                if(counterGetOut>=4800)
                    return false;
            }
    	}
    
    	ui8Status_1 = eUSCI_BUSY_1;
    
      	/* Turn off TX and generate RE-Start */
      	MAP_I2C_masterReceiveStart(EUSCI_B1_BASE);
      	/* Enable RX interrupt */
    
        MAP_I2C_enableInterrupt(EUSCI_B1_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0);
    	/* Wait for all data be received */
        counterGetOut=0;
    	while(ui8Status_1 == eUSCI_BUSY_1)
    	{
    		__no_operation();
            counterGetOut++;
            if(counterGetOut>=4800)
                return false;
    	}
    
    
    
    	/* Disable interrupts */
    	MAP_I2C_disableInterrupt(EUSCI_B1_BASE, EUSCI_B_I2C_STOP_INTERRUPT +EUSCI_B_I2C_NAK_INTERRUPT + EUSCI_B_I2C_RECEIVE_INTERRUPT0);
        MAP_Interrupt_disableInterrupt(INT_EUSCIB1);
    
    	if(ui8Status_1 == eUSCI_NACK_1)
    	{
    		return(false);
    	}
    	else
    	{
    		return(true);
    	}
    }

    And here is my Interrupt routine code for I2C:

    void EUSCIB1_IRQHandler(void)
    {
        uint_fast16_t status;
    
        status = MAP_I2C_getEnabledInterruptStatus(EUSCI_B1_BASE);
        MAP_I2C_clearInterruptFlag(EUSCI_B1_BASE, status);
    
        if (status & EUSCI_B_I2C_NAK_INTERRUPT)
        {
        	/* Generate STOP when slave NACKS */
    //        MAP_I2C_masterSendMultiByteStop(EUSCI_B1_BASE);
        	/* Clear any pending TX interrupts */
        	MAP_I2C_clearInterruptFlag(EUSCI_B1_BASE, EUSCI_B_I2C_TRANSMIT_INTERRUPT0);
            /* Set our local state to NACK received */
        	ui8Status_1 = eUSCI_NACK_1;
        }
    
        if (status & EUSCI_B_I2C_START_INTERRUPT)
        {
            /* Change our local state */
        	ui8Status_1 = eUSCI_START_1;
        }
        if (status & EUSCI_B_I2C_STOP_INTERRUPT)
        {
            /* Change our local state */
        	ui8Status_1 = eUSCI_STOP_1;
        }
        if (status & EUSCI_B_I2C_RECEIVE_INTERRUPT0)
        {
    
        	if (burstMode_1)
        	{
        		//ui8DummyRead_2= MAP_I2C_masterReceiveMultiByteNext(EUSCI_B1_BASE);
        		/* RX data */
        		*pData_1++ = MAP_I2C_masterReceiveMultiByteNext(EUSCI_B1_BASE);
    
        		g_ui32ByteCount_1--;
        		if (g_ui32ByteCount_1 == 1)
        		{
        			burstMode_1 = false;
        			/* Generate STOP */
        	        //MAP_I2C_masterSendMultiByteStop(EUSCI_B1_BASE);
        	        I2C_masterSendMultiByteStopWithTimeout(EUSCI_B1_BASE,1000);//1000
    
        		}
        	}
        	else
        	{
        		//*pData_1++ = EUSCI_B_CMSIS(EUSCI_B1_BASE)->RXBUF & 0x00FF;
        		//MAP_I2C_masterSendMultiByteStop(EUSCI_B1_BASE);
        	    I2C_masterSendMultiByteStopWithTimeout(EUSCI_B1_BASE,1000);//1000
        		*pData_1++ = UCB1RXBUF;
        	}
    
        }
    
        if (status & EUSCI_B_I2C_TRANSMIT_INTERRUPT0)
        {
        	ui8Status_1 = eUSCI_IDLE_1;//ui8Status_1 == eUSCI_IDLE_1;
        }
    }

    Any idea? Is there a way to do this on DMA or improve this? 

    Edit: The only way to make I2C work with SPI simultaneously, i really have to disable GPIO Interrupt from SPI once i use I2C and after enable it again

  • I do not have an idea. Thank you for the additional information about the gpio. Are the GPIO interrupts for the SPI and I2C on the same port? ie P1?

    Regards,
    Chris
  • Hi Chris,
    no for SPI is PORT2.5 and I2C PORT4.1
    I have to disable SPI GPIO interrupt once i start a I2C communication. Because I2C has interrupt to check Aknowledge, SPI interrupt and communication cannot happend on the same time.
    If i let I2C and SPI work together on same time, i have debug it and saw that I2C interrupt aknowlegde never gets fired for example.

    For now i manage to get it to work by disabling SPI GPIO interrupt so that I2C communications succeeds.
    But thanks for your help.

    Kind regrads,

    Michael

**Attention** This is a public forum