007 - mCTC Debugging and Trouble Shooting


Some general question regarding the product are covered in the Frequently Asked Questions section: https://portgmbh.atlassian.net/wiki/spaces/IRJ45SOM/pages/131629572 . In this document methods for debugging and checking proper functionality of the communication between application and communication module shall be shown.



Following table shows the basic structure of the SPI frame.







0 .. 3

4 byte

MCTC SPI header

4 .. 76

73 byte

cyclic data (data mapper)

77 .. 126

50 byte

RPC data


1 byte


The block MCTC SPI Header contains the following elements:

/**< SPI cyclic data header */ typedef struct { uint16_t crc_le16; /**< checksum */ uint8_t seq; /**< sequence number */ uint8_t lenData; /**< data length */ } GOAL_MI_MCTC_SPI_CYCLIC_T;

The field crc_le16 contains a checksum ( Fletcher-16, Wikipedia ) with a starting value of 0x0007.

The field seq contains a sequence counter which increases with each updated frame.

The field lenData contains the length of valid data after the MCTC header (e.g. 124).

Is the application controller receiving valid frames?

If incoming frames from the communication module can be checked by content, following hints should determine wether valid frames are received:

  • The first 2 bytes (crc) contains a value != 0

  • The 3rd byte changes with each frame (cyclic counter)

  • The 4th byte (length) has a value != 0

Programmatically, valid frames are detected by checking the CRC field in the header.

For uGOAL this is determined within the SAPI module:

/****************************************************************************/ /** Basic cyclic communication function * * This function initiates SPI transfer and dispatches received data to * upper layers data callback and RPC handling. * */ void sapi_loop( void ) { /* update frame header */ sapi_pdUpdateHeader(sendData, GOAL_MI_MCTC_LEN - sizeof(GOAL_MI_MCTC_SPI_CYCLIC_T)); /* transfer data via SPI */ plat_spiTransfer((const char *) &sendData[0], (char *) receiveData, BUF_LENGTH); /* control LED if Connection valid or Wink active */ if (true == sapi_pdCheckHeader(receiveData, GOAL_MI_MCTC_LEN - sizeof(GOAL_MI_MCTC_SPI_CYCLIC_T))) { /* inform application */ som_dataCb(&receiveData[0], &sendData[0]); /* trigger RPC */ goal_miMctcDmCbRead(); } }

If line 22 within the function api_loop is executed, valid frames from the communication module are received.

For GOAL based applications this can be determined in the function goal_miMctcSpiProcessTask within the goal_mi_mctc_spi.c module:

do { /* check frame CRC */ res = goal_miMctcCrc(&pBufSpi[sizeof(GOAL_MI_MCTC_SPI_CYCLIC_T)], pHdr->lenData, GOAL_le16toh_p(&pHdr->crc_le16)); if (GOAL_RES_ERR(res)) { break; } /* check sequence counter */ if (pMiMctcSpi->seqCyclicRem != pHdr->seq) { /* inform MI MCTC that connection is running */ goal_miMctcMonitorRx(pMiMctc, GOAL_TRUE); /* re-arm watchdog */ pMiMctcSpi->tsTout = tsNow + pMiMctc->cfgToutValue; /* update seen sequence */ pMiMctcSpi->seqCyclicRem = pHdr->seq; } if (pHdr->lenData) { /* process MI DM incoming data */ goal_miDmReadSync(pMiMctcSpi->pMiDmRead, &pBufSpi[sizeof(GOAL_MI_MCTC_SPI_CYCLIC_T)]); } } while (0);

If the checks shown in the code are performed successfully a valid frame was received.

Manually this could be checked by evaluating the crc from the SPI frame and calculating the expected value over the given data with the given length from the header. The header itself is skipped from crc calculation.

Is the communication module receiving the frames from the application controller?

The communication module will provide valid mCTC frames even if the application controller does not. Thus it is not that easy to determine, if the frames sent by the application controller are evaluated by the communication module.

A good measurement whether the communication module receives the frames from the application controller is the capability to perform the RPC synchronisation. This is executed initially with beginning of the communication.

The RPC synchronisation follows a state machine with the following states:








Initial state

Entered initially or in error case


Initial request state

Entered after INIT state


Initial acknowledge state

Entered after SYNC REQ state


Initial sync request was acknowledged

Entered if SYNC request was acknowledged, the peer module received our request!


Setup state after Sync

Entered when SYNC was successful


Normal operating state

Entered after SYNC is done

So if the state GOAL_MI_MCTC_RPC_STATE_SYNC_ACK_REMOTE is entered, the communication module received the frames sent by the application controller.

Following code shows the state machine in exceprts:


By default both the basic SPI communication and the RPC communication are monitored and in case of loss of communication or a missing response an error is detected and propagated. This will stop the system from working any further. This can be disabled for debugging purpose. However this should never be done in a productive system, since this will mask potential communication problems.


For uGOAL application, the following defines need to be set in goal_config.h:

or using the make system, using the command in a project directory, like ugoal/projects/ugoal/02_profinet/gcc:

and building the project:

To switch the Debugging Mode off, use ‘make debug’ too


For GOAL based application, following code needs to be called before any other functions. So best place the following calls in appl_init():


This will disable both the RPC timeout and the SPI communication timeout. If the application controller is halted for an arbitrary time, operation can be resumed without any error.