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.

system_flush() aborting in ISR and SWI

Other Parts Discussed in Thread: MSP430F5529

Whenever I use system_flush() in an ISR or SWI, the uC (MSP430F5529) goes to exit.c. Specifically, the uC goes to about():

/****************************************************************************/
/* ABORT - ABNORMAL PROGRAM TERMINATION.  CURRENTLY JUST HALTS EXECUTION.   */
/****************************************************************************/
void abort(void)
{
   /*-------------------------------------------------------------------*/
   /* SET C$$EXIT LABEL SO THE DEBUGGER KNOWS WHEN THE C++ PROGRAM HAS  */
   /* COMPLETED.  THIS CAN BE REMOVED IF THE DEBUGGER IS NOT USED.      */
   /*-------------------------------------------------------------------*/
   __asm("        .global C$$EXIT");
   __asm("C$$EXIT: nop");

   for (;;);   /* SPINS FOREVER */
}

I am not sure why this happens. The uC is connected to another device through SPI. The uC that flushes is the slave. The master send a byte of data very quickly, every 100 cycles at 8.2MHz. My first guess was that the flush() was being interrupted by a message. So I disable the SPI interrupt every time the flush() executed. This didn't stop the uC from aborting from the flush(). 

Here is my code:

/*
 *  ======== main.c ========
 */

#include <xdc/std.h>
#include <ti/sysbios/BIOS.h>
#include <xdc/cfg/global.h>
#include <xdc/runtime/System.h>
#include <xdc/runtime/Log.h>

#include <driverlib.h>

#define GPIO_ALL	GPIO_PIN0|GPIO_PIN1|GPIO_PIN2|GPIO_PIN3| \
					GPIO_PIN4|GPIO_PIN5|GPIO_PIN6|GPIO_PIN7

uint8_t returnValue = 0x00;
uint8_t transmitData = 0x00,
		receiveData = 0x00;

void init_GPIO(void);
int init_SPI(void);
void start_SPI(void);
void SPI_ISR(void);

//-----------------------------------------
// Globals
//-----------------------------------------
volatile int16_t i16ToggleCount = 0;

/*
 *  ======== main ========
 */
Int main()
{ 
	init_GPIO();
	init_SPI();
	
	System_printf("You are in!");
	System_flush();

    BIOS_start();    /* does not return */
    return(0);
}

void start_SPI(){
	char rx_char= {'0'};

	rx_char= USCI_A_SPI_receiveData(USCI_A0_BASE);

	if( rx_char == 0x50){
   		GPIO_toggleOutputOnPin(GPIO_PORT_P4,GPIO_PIN7);
   	} else{
   		GPIO_toggleOutputOnPin(GPIO_PORT_P1,GPIO_PIN0);
  	}

	System_putch(rx_char);

	if( rx_char == '!' ){
		System_putch(rx_char);

		USCI_A_SPI_disableInterrupt(USCI_A0_BASE, USCI_A_SPI_RECEIVE_INTERRUPT);
		// System_flush();
		// USCI_A_SPI_enableInterrupt(USCI_A0_BASE, USCI_A_SPI_RECEIVE_INTERRUPT);
	}

//	System_flush();
}

int init_SPI(){
	// Configure for SPI
	// P3.4 as MISO
	GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P3,GPIO_PIN4);
	// P3.3 as MOSI
	GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P3,GPIO_PIN3);
	// P2.7 as SCLK
	GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P2,GPIO_PIN7);
    // P6.6 Chip select
    GPIO_setAsInputPin(GPIO_PORT_P6,GPIO_PIN6);

    returnValue = USCI_A_SPI_initSlave( USCI_A0_BASE, USCI_A_SPI_MSB_FIRST, USCI_A_SPI_PHASE_DATA_CHANGED_ONFIRST_CAPTURED_ON_NEXT,
    		USCI_A_SPI_CLOCKPOLARITY_INACTIVITY_LOW );

    if(STATUS_FAIL == returnValue){
    	return 0;
    }

    // Enable SPI Module
    USCI_A_SPI_enable(USCI_A0_BASE);

    // Enable Receive Interrupt
    USCI_A_SPI_clearInterrupt(USCI_A0_BASE, USCI_A_SPI_RECEIVE_INTERRUPT); // Flag may be needed or not
    USCI_A_SPI_enableInterrupt(USCI_A0_BASE, USCI_A_SPI_RECEIVE_INTERRUPT);

    return 1;
}

void init_GPIO(void){
	// Disable the Watchdog Timer (important, as this is enabled by default)
	WDT_A_hold( WDT_A_BASE );

	// Set GPIO ports to low-level outputs
    GPIO_setAsOutputPin( GPIO_PORT_P1, GPIO_PIN0 );
    GPIO_setAsOutputPin( GPIO_PORT_P4, GPIO_PIN7 );
    GPIO_setOutputLowOnPin( GPIO_PORT_P1, GPIO_PIN0 );
    GPIO_setOutputLowOnPin( GPIO_PORT_P4, GPIO_PIN7 );
}

void SPI_ISR(void)
{
	Swi_post(SPISwi);
	USCI_A_SPI_clearInterrupt(USCI_A0_BASE, USCI_A_SPI_RECEIVE_INTERRUPT); // Flag may be needed or not
}

  • Another clue to why is the memory that system_printf() saves to after a system_flush().

  • Rodney Wong said:
    Whenever I use system_flush() in an ISR or SWI, the uC (MSP430F5529) goes to exit.c.

    I was looking at the documentation to try and determine if system_flush() is safe to be called from an ISR or SWI.

    The introduction to the module xdc.runtime.System states:

    This module is gated and other modules use its gate via the Gate.enterSystem and Gate.leaveSystem. The System gate must be enterable by any thread in a multi-threaded environments. For example, in many real-time multi-threaded environments some types of threads, such as Interrupt Service Routines (ISRs), are not allowed to call operations that block the caller. In such an environment, either the System gate must disable all interrupts or ISRs must never call a function in the xdc.runtime package.

    This suggests that system_flush is not safe to be called from an ISR or SWI - although I haven't (yet) investigated.

  • Usually, a flushing operation is a blocking operation. That means, the function will not return until the flush is complete. However, other threads and ISRs must not be blocked. In fact, the flush might even need other ISRs to be executed. So calling it from inside an ISR is always a bad idea, even if it were (technically) safe to be called from inside an ISR (that means, not leading to a deadlock or stack or system state corruption).
    In general, ISRs should never do any operation that could block. Including stream I/O. If a flush (or any stream I/O or possible blocking or lengthy operation) is necessary, it should be done in a thread outside the ISR.

**Attention** This is a public forum