Part Number: TM4C123GH6PM
Tool/software: TI-RTOS
My application's target is getting measurement data from an IC via SPI, filtering it and sending it over CAN to another MCU. The code ist just running fine until, after 248-252 measurments including communication via SPI, loader_exit() is called. The number of measurement isn't treated specially in any way by the application.
The only task using the SPI-bus is the measure task, which is a while loop with a semaphore_pend which gets posted by a the HWI of a clock function every 10ms. The TI-RTOS SPI API "SPI.h" is used.
I tried to hunt down the problem in several ways, but the clues point in several directions:
- (1) Using larger periods for the measure task doesn't solve the problem and according to timestamps the measre task needs less than 10ms.
- (2) The number of measurments it takes until the exit is dependant on the Timer (Timer 0-5) chosen for the clock module, but alwas the same for the same timer and always about 250, but always smaller than 255 (no indication for overflow of any uint8_t).
- (3) The number of measurements is independent from the period of the measuring task, increasing it's period increases the time until the exit linearly. E.g. Setting the period to 100ms makes the time period till the exit 10 times higher, than when setting it to 10ms.
- (4) When measuring while the IC isn't connected physically to the TM4C as SPI-slave, the measurements don't add to the number of measurements until the exit. This means that the application runs stable for many minutes, trying to do thousands of measurements (but getting nothing via SPI of course), but only after connecting the IC again it takes 248-252 measurements till the exit.
- (5) When stepping through the code the exit seems to occur during a call to the TI_RTOS Task_sleep() function. Until the exit about 3000 calls to this function are made (again slightly dependant on the timer chosen for the clock module).
- (6) When letting the application just run, the exit occurs always after the same number of measurements. When stopping just before the exit should occur and single-stepping through every line of code the exit doesn't occur. To make it occur, it is needed that several line of code with calls to the Task_sleep() function are executed in one run before halting the MCU again.
- (7) In ROV no overflow of the task- SWI- or HWI-stack or the heap occurs
- (8) In ROV after 209-212 measurements (again slightly dependant on the timer chosen for the clock module) the error "Caught exception in view init code: "C:/ti/tirex-content/xdc tools_3_32_00_06_core/packages/xdc/rov/StructureDecoder.xs", line 518: java.lang.Exception: Target memory read failed at address: 0x94a994a8, length: 24th Is read is at an INVALID address according to the application's section map. The application is likely either uninitialized or corrupt." occurs in the context of the HWI module and stays till the exit. Again, as in (6), single-stepping through the code doesn't make the error occur.
Most clues seem to indicate a timing problem, but clue (4) seems to indicate a SPI problem. Is there any counter in the clock module or in the "SPI.h" which could have an overflow?
I tried the following withought any effect:
(a) Changing the clock module settings ( period, interrupt/don't interrupt every period)
(b) Switching from RTOS SPI functions to non-RTOS SPI-functions (using SSIPutDataNonBlocking()..)
(c) Using other boards
(d) using other XDCTools versions
(e) disabling other tasks
Following software versions are used:
CCS: 7.1.0.0016, TI-RTOS for TivaC: 2.16.0.08, TIVA C series arm CPUs: 2.1.1.15071, Compiler: v16.9.2.LTS, XDCTools: 3.32.0.06_core, OS: Windows 10 Home
Here the *.cfg, and the *.c for the measure task and the SPI connection, just in case they help you understanding the problem:
#include <_Task_measure.h>
//Measure every 10ms
void clock0_function(){
Semaphore_post(semaphore_measure);
//GPIO_toggle(Board_LED0); //JUST4FUN
}
uint8_t delayTaskMeasure;
void task_measure(void){ //-Measure Cell Voltages
//HIGH PRIO
Semaphore_pend(semaphore_booted, BIOS_WAIT_FOREVER);
putTimestamp("_task1_");
while(1){
Semaphore_pend(semaphore_measure, BIOS_WAIT_FOREVER);
measureCounter++;
if(measureCounter==209){
int i=0;
}
if(delayTaskMeasure==true){
//TaskDelayMilliseconds(2000*total_ic);
delayTaskMeasure=false;
}
putTimestamp("startmea");
if(USE_RANDOM_MEASUREMENTS){
measureRandom();
}
else{
if(doBalancing && didFirstMedian && sample==0){
stopBalancing();
}
measure();
putTimestamp("donemea");
//TaskDelayMilliseconds(10);
}
sendMinMaxStatus();
if(sample==SAMPLE_COUNT/2 && !USE_RANDOM_MEASUREMENTS){
//ltcChangeConfig();
}
if(doBalancing && didFirstMedian && sample==0 && !USE_RANDOM_MEASUREMENTS){
balance();
}
sample++;
if( sample >= SAMPLE_COUNT ){
prepareFiltering();
//send semaphore to Task2
Semaphore_post(semaphore_median);
sample = 0;
}
//putTimestamp("stopmea");
}
}
void task_median(void){
/*
*
* THIS CODE is used for Testing the Eeprom Storage with Can
//TODO only for debug
//AMSsendDataES910();
uint8_t TestData[8];
int i;
for(i = 0; i <= 7; i++){
TestData[i] = 17*i+14 ;
}
saveDatafromES910(&TestData);
*/
//LOW PRIO
while(1){
Semaphore_pend(semaphore_median, BIOS_WAIT_FOREVER);
filterMeasurements();
sendFilteredMeasurements();
if(didFirstMedian==false
&& battery_status.max_cell_temperature<maxAllowedTemp
&& battery_status.min_cell_voltage>minAllowedVoltage
&& battery_status.max_cell_voltage<maxAllowedVoltage){
Semaphore_post(semaphore_didSelftest);
didFirstMedian=true;
}
if(csc[0].median_temperature[0]<100){
delayTaskMeasure=true;
}
}
}
/*
* Peripherals_SPI_Transfer.c
*
* Created on: 07.04.2017
* Author: MalteEbner
*/
#include "Peripherals_SPI_Transfer.h"
SPI_Handle spi;
uint8_t peripheralNum;
SPI_Params spiParams;
uint8_t defaultTxBuffer[64];
inline void init_SPI_Transactions(){
SPI_Params_init(&spiParams);
spiParams.dataSize = 8; /* dataSize can range from 4 to 8 bits */
spiParams.transferMode = SPI_MODE_BLOCKING;
spiParams.transferCallbackFxn = NULL;
spiParams.bitRate=1000000;
spiParams.mode= SPI_MASTER;
peripheralNum = Board_SPI1;/* Such as SPI1 */
spi = SPI_open(peripheralNum, &spiParams);
if (spi == NULL) {
/* Error opening SPI */
errorHandling(0);
}
uint8_t i;
for(i=0; i<sizeof(defaultTxBuffer); i++){
defaultTxBuffer[i]=0xFF;
}
}
void init_SPI(){
/* SSI3 */
/*
* NOTE: TI-RTOS examples configure pins PD0 & PD1 for SSI3 or I2C3. Thus,
* a conflict occurs when the I2C & SPI drivers are used simultaneously in
* an application. Modify the pin mux settings in this file and resolve the
* conflict before running your the application.
*/
SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI3);
GPIOPinConfigure(GPIO_PD0_SSI3CLK);
//GPIOPinConfigure(GPIO_PD1_SSI3FSS);
GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE, GPIO_PIN_1);
GPIOPinConfigure(GPIO_PD2_SSI3RX);
GPIOPinConfigure(GPIO_PD3_SSI3TX);
GPIOPinTypeSSI(GPIO_PORTD_BASE, GPIO_PIN_0 |
GPIO_PIN_2 | GPIO_PIN_3);
EK_TM4C123GXL_initDMA();
SPI_init();
init_SPI_Transactions();
}
inline int8_t SPI_WriteRead(uint8_t tx_data[], uint8_t tx_length, uint8_t *rx_data, uint8_t rx_length){
static SPI_Transaction spiTransaction;
static uint8_t transferOK;
//Discard everything which can be received
//SPI_Write(64,NULL);
GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_1,0x00);
//Only send, do not handle receive
spiTransaction.count = tx_length;
spiTransaction.txBuf = tx_data;
spiTransaction.rxBuf = NULL;
transferOK = SPI_transfer(spi, &spiTransaction);
if (!transferOK) {
// Error in SPI transfer or transfer is already in progress
errorHandling(0);
}
/*
//Discard everything which can be received
uint8_t tmpRxBuf=1;
int readCounter=0:
while(tmpRxBuf!=0){
spiTransaction.count = 1;
spiTransaction.txBuf = NULL;
spiTransaction.rxBuf = tmpRxBuf;
transferOK = SPI_transfer(spi, &spiTransaction);
if (!transferOK) {
// Error in SPI transfer or transfer is already in progress
errorHandling(0);
}
readCounter++
}
*/
//Only send 0xFF and receive
spiTransaction.count = rx_length;
spiTransaction.txBuf = defaultTxBuffer;
spiTransaction.rxBuf = rx_data;
transferOK = SPI_transfer(spi, &spiTransaction);
GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_1,0xFF);
if (!transferOK) {
// Error in SPI transfer or transfer is already in progress
errorHandling(0);
}
return transferOK;
}
inline int8_t SPI_Write(uint8_t length, uint8_t* transmitBuffer){
static SPI_Transaction spiTransaction;
static uint8_t transferOK;
spiTransaction.count = length;
GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_1,0x00);
//Only send, discard everything received
spiTransaction.txBuf = transmitBuffer;
spiTransaction.rxBuf = NULL;
transferOK = SPI_transfer(spi, &spiTransaction);
GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_1,0xFF);
if (!transferOK) {
/* Error in SPI transfer or transfer is already in progress */
errorHandling(0);
}
return transferOK;
}
Unfortunately I have no ideas how to solve to the problem left as the clues and context is very confusing.
It would be very great if you had any idea in which direction to debug and hunt down the problem next.