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.

TMS320F28388D: Can't Trigger SPIRX interrupt from within the Timer1 ISR

Part Number: TMS320F28388D


Tool/software:

Hi everyone,

My PCB board integrates an SPI ADC MAX11337 chip. My goal is to transmit 10 bytes to the SPI ADC chip via SPIB every 1ms, with each byte triggered by a seperate CS pulse. That's why DMA or FIFO mode aren't suitable as they don't handle the CS pulsing automatically. 

The process begins with sending the first byte in the Timer1 ISR. Subsequent bytes are transmitted one at a time in the SPI RX interrupt until all 10 bytes are sent (in 10 SPI interrupts). After that, the SPI RX interrupt is disabled.

The issue I am currently facing is the SPIRX interrupt doesn't trigger after sending the first SPI byte from within the Timer1 ISR. However, if the SPI write is performed from a non-ISR routine, e.g main loop, the SPIRX interrupt works as expected

Here's my code:

Initialization

CPU timer 1 interrupts every 1ms

void timer1_1ms_init(){
	CPUTimer_setEmulationMode(timer1_1ms_BASE, CPUTIMER_EMULATIONMODE_STOPAFTERNEXTDECREMENT);
	CPUTimer_setPreScaler(timer1_1ms_BASE, 200U);
	CPUTimer_setPeriod(timer1_1ms_BASE, 1000U);
	CPUTimer_enableInterrupt(timer1_1ms_BASE);
	CPUTimer_stopTimer(timer1_1ms_BASE);

	CPUTimer_reloadTimerCounter(timer1_1ms_BASE);
	CPUTimer_startTimer(timer1_1ms_BASE);
}

SPIB: non-FIFO. Interrupts on SPI_INT_RX_DATA_TX_EMPTY

void spi_adc_init(){
	SPI_disableModule(spi_adc_BASE);
	SPI_setConfig(spi_adc_BASE, DEVICE_LSPCLK_FREQ, SPI_PROT_POL1PHA0,
				  SPI_MODE_CONTROLLER, spi_adc_BITRATE, spi_adc_DATAWIDTH);
	SPI_setPTESignalPolarity(spi_adc_BASE, SPI_PTE_ACTIVE_LOW);
	SPI_disableFIFO(spi_adc_BASE);
	SPI_disableLoopback(spi_adc_BASE);
	SPI_setEmulationMode(spi_adc_BASE, SPI_EMULATION_STOP_MIDWAY);
	SPI_enableModule(spi_adc_BASE);
}

void INTERRUPT_init(){
	
	// Interrupt Settings for INT_timer1_1ms
	// ISR need to be defined for the registered interrupts
	Interrupt_register(INT_timer1_1ms, &timer1_1ms_ISR);
	Interrupt_enable(INT_timer1_1ms);
}

1. On Timer 1 interrupt, write the first byte to SPI in max11337_start()

 

__interrupt void timer1_1ms_ISR(void)
{
    if(max11337_ready()){
        max11337_start();
    }
}

2. This writes the first SPI byte to MAX11337.

void max11337_start(void)
{
     // Prime first word to start transfer
     txIndex = 1;
     rxIndex = 0;

     // Enable SPI RX interrupt
     SPI_clearInterruptStatus(SPIB_BASE, SPI_INT_RX_DATA_TX_EMPTY);
     SPI_enableInterrupt(SPIB_BASE, SPI_INT_RX_DATA_TX_EMPTY);

     // Enable CPU interrupt group
     Interrupt_enable(INT_SPIB_RX);

     // Set CS low
     GPIO_writePin(SPI_ADC_CS, 0);
     // Write the first byte
     SPI_writeDataNonBlocking(SPIB_BASE, spiTxBuffer[0]);
}

3. The SPIRX interrupt handler

__interrupt void spi_rx()
{
    // 1. Toggle CS high
    GPIO_writePin(SPI_ADC_CS, 0);
      
    // 2. Read the received word
    spiRxBuffer[rxIndex++] = SPI_readDataNonBlocking(SPIB_BASE);

    // 3. Clear interrupt flags
    SPI_clearInterruptStatus(SPIB_BASE, SPI_INT_RX_DATA_TX_EMPTY);

    // 4. Send next word if available
    if (txIndex < 10)
    {
        // Toggle CS low
        GPIO_writePin(SPI_ADC_CS, 0);
        SPI_writeDataNonBlocking(SPIB_BASE, spiTxBuffer[txIndex++]);
    }
    else
    {
        // All data sent and received, disable RX interrupt
        SPI_disableInterrupt(SPIB_BASE, SPI_INT_RX_DATA_TX_EMPTY);
    }

    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP6);  // SPIB = Group 6
}

Can someone point me what's wrong with my code?

  • My background primarily involves working with Microchip PIC products, where I've never encountered any issues with interrupts. This is my first prototype using a TI C2000 MCU, and I'm currently facing an interrupt-related problem. I’d greatly appreciate it if anyone could help identify the root cause, as I need a quick resolution.

  • Hello,

    Looking through your code, what I believe is happening here is that your SPI interrupt is trying to fire while you're still handling the timer ISR, and the C28x device does not have HW interrupt nesting. The simplest workaround is to set a flag in your timer ISR which blocks the write in the main loop.

    As an aside, I notice that you're never setting CS to 1 in the code you've provided.

    Regards,
    Jason Osborn

  • Hello Jason,

    Thanks for your response I really appreciate it. Please check my comments below:

    1. CS is set to 1 during hardware initialization. It is not shown here. 

    2. I prefer not to set a flag in the timer ISR and check it from the main loop as the timing would not be deterministic. Our system is real-time and precise timing is critical.

    3. I understand that interrupt nesting is not enabled by default in C2000. What i don't understand is why the SPIRX interrupt doesn't fire AFTER the program exits the Timer ISR. My understanding is when entering the Timer ISR, the INTM is automatically set to 1, and then cleared to 0 upon exiting. The SPIRX Interrupt flag should set when one word has been transmitted/received (regardless of the INTM state), and once the INTM is cleared after exiting the timer ISR, the CPU should proceed to service the SPIRX interrupt, but this doesn't happen. I have spent many hours trying to understand what might be preventing this behaviour, and I am hoping someone can provide some insight. 

  • BUMP. Anyone can help to solve this puzzle? 

  • Apologies for the delay in response, I had jury duty.

    Looking over your code again, I have a few notes and questions:

    First, timer1_1ms_ISR() and max11337_start() do not have an ack function. Make sure that the timer peripheral being used here is CPUTIMER1 or CPUTIMER2. CPUTIMER0 goes through the PIE like other peripherals and requires an ack. However, since TIMER0 is not in the same group as the SPI, this specifically is unlikely to be the cause of the problem.

    Second, you never show the interrupt_register() function for the SPI Rx, but because there are cases where things work, I'm going to assume that this is done and simply not shown similar to setting CS.

    As for the actual question you're asking, I'm looking into that as well. This doesn't fit the cases I expected it to, apologies. Do you have debug access to the chip? Ideally, the CCS Registers view of the SPI status register in the failed example would be useful to see here.

    Regards,
    Jason Osborn

  • Hi Jason.

    No worries about the delay. I appreciate your support in this matter. 

    Timer1_1ms_ISR() and max11337_start have no ACK function. I can confirm that the CPUTimer1 is being used, so ACK is not required.

    The interrupt register function for the SPIRX is shown below:

    void max11337_initialize()
    {
    
        // start with echo test.
        if( max11337_verifyEcho() == true){
            // initialize its registers.
            max11337_setupRegisters();
    
            // Register RX ISR
            Interrupt_register(INT_SPIB_RX, &spi_rx);
            ready = true;
        }
    }

    Please note that CPU1 will initially configure the MAX11337 registers using spi_write_read_16bit in a non-interrupt (blocking) mode. Once the setup is complete, it will register the SPIRX interrupt callback function and set the ready flag to 1. From that point onwards, all SPI write/read operations will be handled using interrupt-driven mode.

    static uint16_t spi_write_read_16bit(uint16_t txData)
    {
        uint16_t rxData = 0;
    
        GPIO_writePin(SPI_ADC_CS,0);
    
        // Wait until the TX buffer is ready (TXFFST = 0 means TX FIFO is empty)
        //while((HWREGH(SPIB_BASE + SPI_O_STS) & SPI_STS_BUFFULL_FLAG));
    
        // Write data to TX register
        SPI_writeDataBlockingNonFIFO(SPIB_BASE, txData);
    
        // Wait until RX buffer has received data (RXFFST != 0)
        //while((HWREGH(SPIB_BASE + SPI_O_FFRX) & SPI_FFRX_RXFFST_M) == 0);
    
        // Read and return received 16-bit word
        rxData = SPI_readDataBlockingNonFIFO(SPIB_BASE);
    
        GPIO_writePin(SPI_ADC_CS,1);
        return rxData;
    }

    Yes, I have debug access to the chip. Please let me know which registers you need to look at, and where to set the breakpoints. I will set it up accordingly and provide my screenshot.

    Regards,

    WeeHau

  • I'm very sorry for the delay in response again, I'll make absolutely certain it does not happen again.

    First, I have a suspicion I'd like to test. Can you change the CPU timer being used to TIMER2, and add the necessary ack function? Don't enable nesting, just let me know whether this by itself fixes the problem.

    If this doesn't work, in the fail state (i.e. max11337_start() already ran, but the SPI ISR did not trigger), please record the contents of the following registers:

    • Full contents of SPI register SPISTS (just record the hex value)
    • SPI Register bits SPICTL[SPIINTENA]
    • Full contents of PIE register PIEIFR6 (just hex value)
    • Variables txIndex, rxIndex, txData, rxData

    Regards,
    Jason Osborn

  • Thanks for the follow up. Sure, I will collect the information and update you soon.