| Details | Message |
|---|
Read-Only Author Marco Loi Posted 22-Jul-2008 11:08 GMT Toolset C166 |  ILLOPA exception on C167CR-LM Marco Loi Hello, I developed an emmbedded application for a C167CR-LM. In this application I've some very big data structures stored in internal RAM (IDATA) and some dynamic list managed using malloc and free. For dynamic allocation I define the pool:
unsigned char far equivalence_pool[0x4000];
init_mempool (equivalence_pool, sizeof (equivalence_pool));
In my application there is a IRQ routine on a Timer T6 with a period of 0.5 ms. In some situations the ILLOPA exception is trapped an the application crashes. It generally happens when many digital input (linked to port P2 pins) are active together. I tried to increase the user stack with no effect. Adding 2 calls to printf in the IRQ routine, ILLOPA is not generated. Have you some suggestions for help me how to investigate this problem? Testing with Mon166 the trap routines are not available, and using Simulator is too complex cause the hardware and input sequences to generate. Thanks, Marco |
|
Read-Only Author Tamir Michael Posted 22-Jul-2008 11:42 GMT Toolset C166 |  RE: ILLOPA exception on C167CR-LM Tamir Michael I you sure you are not exceeding the size of IDATA? |
|
Read-Only Author Marco Loi Posted 22-Jul-2008 11:49 GMT Toolset C166 |  RE: ILLOPA exception on C167CR-LM Marco Loi Yes, because I know the dimension of my memory and then because building the application the Compiler would generate a warning message on exceeding the size of IDATA. But thi Warning is not present. Thanks. |
|
Read-Only Author Tamir Michael Posted 22-Jul-2008 11:51 GMT Toolset C166 |  RE: ILLOPA exception on C167CR-LM Tamir Michael Please show the ISR's code. |
|
Read-Only Author Tamir Michael Posted 22-Jul-2008 11:50 GMT Toolset C166 |  RE: ILLOPA exception on C167CR-LM Tamir Michael could it be that your T6 ISR corrupts something critical for the main loop or another ISR? |
|
Read-Only Author Marco Loi Posted 22-Jul-2008 11:56 GMT Toolset C166 |  RE: ILLOPA exception on C167CR-LM Marco Loi The routine is too long to print it here. Therefore it's good because it was part of an old application, ant its the main function in my application. Thanks to all. |
|
Read-Only Author Tamir Michael Posted 22-Jul-2008 11:59 GMT Toolset C166 |  RE: ILLOPA exception on C167CR-LM Tamir Michael Therefore it's good because it was part of an old application, ant its the main function in my application. no no no Marco, the fact that is used to work means nothing - maybe there is a hidden bug in it you never encountered? you must post more details to allow further analysis. |
|
Read-Only Author Marco Loi Posted 22-Jul-2008 12:11 GMT Toolset C166 |  RE: ILLOPA exception on C167CR-LM 1/4 Marco Loi Here the 1/4 part of the code:
void Timer6Interrupt(void) interrupt 0x26 using Timer6Bank
{
UINT i;
UBYTE countEnc, gapEnc, cnt;
UINT checkRB;
bit errRB;
long comptime;
UINT metaldata;
UBYTE ErrScan = 0; // ** MTL ** eventuale errore di scansione matrice
UBYTE ErrReset = 0;// ** MTL ** eventuale errore di reset buffer
UBYTE ErrEqu = 0; // ** MTL ** eventuale errore di normalizzazione equivalenze
UBYTE ErrLab = 0; // ** MTL ** eventuale errore di normalizzazione etichette
UBYTE ErrCat = 0; // ** MTL ** eventuale errore di catalogazione etichette
UBYTE ErrDel = 0; // ** MTL ** eventuale errore di eliminazione equivalenze
// ** NEW ** Calcolo Tempo di Idle
StopT1Read = T1;
comptime = (long)StopT1Read - (long)StartT1Idle;
if ((comptime) < 0)
IdleTicks = PERF_TIMER + comptime;
else
IdleTicks = comptime;
// ** NEW ** Ci interessa il minimo Tempo di Idle perche' verra'
// trasmesso il suo valore percentuale insieme allo stato
// Tale valore viene resettato per le prime 5 ricezioni del
// comando STS (transitorio) dopodiche entrera' a regime
if (IdleTicks < MinIdleTicks)
MinIdleTicks = IdleTicks;
// ** NEW ** Calcolo Tempo di Cycle
comptime = (long)StopT1Read - (long)StartT1Cycle;
if ((comptime) < 0)
CycleTicks = PERF_TIMER + comptime;
else
CycleTicks = comptime;
StartT1Cycle = StopT1Read;
errRB = 0;
// ================== GESTIONE RICERCA METALLI =======================
if (MetalDetection.Enable) {
// ************************* CONTATORI *******************************
// Sezione 1 - Ritardi e abilitazioni
if (MetalDetection.Encoder == 0xFF) {
// Ritardi e campionamenti a tempo
for (i = 0; i < MTL_BUFNUM; i++) {
// Contatore trigger di attivazione
if (MetalCounter[i].StartCount != NO_COUNT) {
MetalCounter[i].StartCount--;
if (MetalCounter[i].StartCount <= 0) {
// printf("\nFine StartCount T su buffer %d\n",i);
MetalCounter[i].ReadEnable = 1;
MetalCounter[i].Active = 1;
MetalCounter[i].Broken = 0;
MetalCounter[i].StartCount = NO_COUNT;
ErrReset = ResetBuf(i); // Resetto il buffer i
}
}
// Contatore trigger di disattivazione
if (MetalCounter[i].StopCount != NO_COUNT) {
MetalCounter[i].StopCount--;
if (MetalCounter[i].StopCount <= 0) {
// printf("\nFine StopCount T su buffer %d\n",i);
MetalCounter[i].EndDoc = MetalDetection.SensorsDelay;
MetalCounter[i].StopCount = NO_COUNT;
}
}
// Contatore timer di campionamento
if (MetalCounter[i].Timer != NO_COUNT) {
MetalCounter[i].Timer--;
if (MetalCounter[i].Timer <= 0) {
// printf("\nFine Timer T su buffer %d\n",i);
MetalCounter[i].ReadEnable = 1;
MetalCounter[i].Timer = NO_COUNT;
}
}
// Contatore bit di dato valido
if (MetalCounter[i].CountValid != NO_COUNT) {
MetalCounter[i].CountValid--;
if (MetalCounter[i].CountValid <= 0) {
// printf("\nFine CountValid T su buffer %d\n",i);
MetalCounter[i].Valid = 0;
MetalCounter[i].CountValid = NO_COUNT;
// Abilitazione invio report LENTO1
MetalDetection.SendRepEnable = 1;
}
}
} // for (i = 0; i < MTL_BUFNUM; i++) - Tempo
}//to be continued
|
|
Read-Only Author Marco Loi Posted 22-Jul-2008 12:17 GMT Toolset C166 |  RE: ILLOPA exception on C167CR-LM 2/4 Marco Loi Here the 2/4 part of the code:
...
// Ritardi e campionamenti a spazio
countEnc = ENCPORT[0];
for (i = 0; i < MTL_BUFNUM; i++) {
// Contatore trigger di attivazione
if (MetalCounter[i].StartCount != NO_COUNT) {
gapEnc = abs(countEnc - MetalCounter[i].EncPrev);
if (gapEnc > MAX_GAP) { // l'encoder e' passato per lo zero
// Calcolo il decremento interpretando la direzione di
// conteggio dell'encoder
MetalCounter[i].StartCount -= (countEnc > MAX_GAP) ?
(0xFF - countEnc + MetalCounter[i].EncPrev) :
(0xFF + countEnc - MetalCounter[i].EncPrev);
}
else
MetalCounter[i].StartCount -= gapEnc;
if (MetalCounter[i].StartCount <= 0) {
// printf("\nFine StartCount su buffer %d\n",i);
MetalCounter[i].ReadEnable = 1;
MetalCounter[i].Active = 1;
MetalCounter[i].Broken = 0;
MetalCounter[i].StartCount = NO_COUNT;
ErrReset = ResetBuf(i); // Resetto il buffer i
}
}
// Contatore trigger di disattivazione
if (MetalCounter[i].StopCount != NO_COUNT) {
gapEnc = abs(countEnc - MetalCounter[i].EncPrev);
if (gapEnc > MAX_GAP) { // l'encoder e' passato per lo zero
// Calcolo il decremento interpretando la direzione di
// conteggio dell'encoder
MetalCounter[i].StopCount -= (countEnc > MAX_GAP) ?
(0xFF - countEnc + MetalCounter[i].EncPrev) :
(0xFF + countEnc - MetalCounter[i].EncPrev);
}
else
MetalCounter[i].StopCount -= gapEnc;
if (MetalCounter[i].StopCount <= 0) {
// printf("\nFine StopCount su buffer %d\n",i);
MetalCounter[i].EndDoc = MetalDetection.SensorsDelay;
MetalCounter[i].StopCount = NO_COUNT;
}
}
// Contatore timer di campionamento
if (MetalCounter[i].Timer != NO_COUNT) {
gapEnc = abs(countEnc - MetalCounter[i].EncPrev);
if (gapEnc > MAX_GAP) { // l'encoder e' passato per lo zero
// Calcolo il decremento interpretando la direzione di
// conteggio dell'encoder
MetalCounter[i].Timer -= (countEnc > MAX_GAP) ?
(0xFF - countEnc + MetalCounter[i].EncPrev) :
(0xFF + countEnc - MetalCounter[i].EncPrev);
}
else
MetalCounter[i].Timer -= gapEnc;
if (MetalCounter[i].Timer <= 0) {
// printf("\nFine Timer su buffer %d\n",i);
MetalCounter[i].ReadEnable = 1;
MetalCounter[i].Timer = NO_COUNT;
}
}
// Contatore bit di dato valido
if (MetalCounter[i].CountValid != NO_COUNT) {
gapEnc = abs(countEnc - MetalCounter[i].EncPrev);
if (gapEnc > MAX_GAP) { // l'encoder e' passato per lo zero
// Calcolo il decremento interpretando la direzione di
// conteggio dell'encoder
MetalCounter[i].CountValid -= (countEnc > MAX_GAP) ?
(0xFF - countEnc + MetalCounter[i].EncPrev) :
(0xFF + countEnc - MetalCounter[i].EncPrev);
}
else
MetalCounter[i].CountValid -= gapEnc;
if (MetalCounter[i].CountValid <= 0) {
// printf("\nFine CountValid su buffer %d\n",i);
MetalCounter[i].Valid = 0;
MetalCounter[i].CountValid = NO_COUNT;
// Abilitazione invio report LENTO1
MetalDetection.SendRepEnable = 1;
}
}
// La lettura attuale diventa lettura precedente
// per il prossimo interrupt da Timer6
MetalCounter[i].EncPrev = countEnc;
} // for (i = 0; i < MTL_BUFNUM; i++) - Spazio
} // Fine Sezione 1 - Ritardi e abilitazioni
//to be continued
|
|
Read-Only Author Marco Loi Posted 22-Jul-2008 12:23 GMT Toolset C166 |  RE: ILLOPA exception on C167CR-LM 3/4 Marco Loi Here the 3/4 part of the code:
// ************************* LETTURA SENSORI *************************
// le nuove versioni (VerHw = 1) hanno gli ingressi attivi alti
metaldata = (Hw) ? (~P2 & MaskInSpeed) : (P2 & MaskInSpeed);
// Shift per isolare solo i sensori (0 e 1 vanno all'encoder,
// 2-10 vanno ai sensori, 11 va' al trigger)
metaldata = metaldata >> (NInputSpeed - 9 - 1);
metaldata &= 0x01FF;
// Interpretazione ingressi tramite polarity
metaldata ^= MetalDetection.SensorsPolarity;
// ***************** SCANSIONI RICERCA METALLI **********************
// Sezione 2 - Scansione documento e matrice
for (i = 0; i < MTL_BUFNUM; i++)
{
if (MetalCounter[i].ReadEnable)
{
if (MetalCounter[i].EndDoc == NO_ENDDOC)
{
// Salvo sulla matrice di scansione la prima barriera di sensori
ScanMatrix[i][0][ScanDoc[i].TotCol] = metaldata & 0x0001;
ScanMatrix[i][2][ScanDoc[i].TotCol] = (metaldata >> 2) & 0x0001;
ScanMatrix[i][4][ScanDoc[i].TotCol] = (metaldata >> 4) & 0x0001;
ScanMatrix[i][6][ScanDoc[i].TotCol] = (metaldata >> 6) & 0x0001;
ScanMatrix[i][8][ScanDoc[i].TotCol] = (metaldata >> 8) & 0x0001;
if (ScanDoc[i].TotCol >= MetalDetection.SensorsDelay)
{
// if (ScanDoc[i].TotCol == MetalDetection.SensorsDelay)
// printf("\nStart lettura seconda barriera su buffer %d\n",i);
// Salvo sulla matrice di scansione la seconda barriera di sensori
ScanMatrix[i][1][ScanDoc[i].TotCol - MetalDetection.SensorsDelay] =
(metaldata >> 1) & 0x0001;
ScanMatrix[i][3][ScanDoc[i].TotCol - MetalDetection.SensorsDelay] =
(metaldata >> 3) & 0x0001;
ScanMatrix[i][5][ScanDoc[i].TotCol - MetalDetection.SensorsDelay] =
(metaldata >> 5) & 0x0001;
ScanMatrix[i][7][ScanDoc[i].TotCol - MetalDetection.SensorsDelay] =
(metaldata >> 7) & 0x0001;
// Analizzo la colonna appena completata per identificare le regioni
ErrScan = ScansioneMatrice(i, ScanDoc[i].TotCol - MetalDetection.SensorsDelay);
}
if (++ScanDoc[i].TotCol == MTL_SCAN_COLS)
{
// Ho superato la dimensione massima del buffer: chiudo la scansione
// documento abilitando la lettura solo della seconda barriera
// printf("\nRaggiunto limite su buffer %d\n",i);
MetalCounter[i].EndDoc = MetalDetection.SensorsDelay;
MetalCounter[i].Broken = 1;
MetalCounter[i].StopCount = NO_COUNT;
}
// Inizializzo il contatore per la prossima scansione
MetalCounter[i].Timer = MetalDetection.Timing;
}
else // if (MetalCounter[i].EndDoc == NO_ENDDOC)
{
// Siamo a fine documento: completo la lettura salvando sulla
// matrice di scansione solo la seconda barriera di sensori
ScanMatrix[i][1][ScanDoc[i].TotCol - MetalDetection.SensorsDelay] =
(metaldata >> 1) & 0x0001;
ScanMatrix[i][3][ScanDoc[i].TotCol - MetalDetection.SensorsDelay] =
(metaldata >> 3) & 0x0001;
ScanMatrix[i][5][ScanDoc[i].TotCol - MetalDetection.SensorsDelay] =
(metaldata >> 5) & 0x0001;
ScanMatrix[i][7][ScanDoc[i].TotCol - MetalDetection.SensorsDelay] =
(metaldata >> 7) & 0x0001;
// Analizzo la colonna appena completata per identificare le regioni
ErrScan = ScansioneMatrice(i, ScanDoc[i].TotCol - MetalDetection.SensorsDelay);
// Decremento il contatore di fine documento
MetalCounter[i].EndDoc--;
if (MetalCounter[i].EndDoc)
{
//to be continued
|
|
Read-Only Author Marco Loi Posted 22-Jul-2008 12:28 GMT Toolset C166 |  RE: ILLOPA exception on C167CR-LM 4/5 Marco Loi Here the 4/5 part of the code:
// Continuo la chiusura lettura documento
ScanDoc[i].TotCol++;
// Inizializzo il contatore per la prossima scansione
MetalCounter[i].Timer = MetalDetection.Timing;
}
else
{
// printf("\nFine scansione su buffer %d\n",i);
// La scansione del documento e' terminata
MetalDetection.LastRead = i;
ScanDoc[i].TotCol -= (MetalDetection.SensorsDelay - 1);
MetalCounter[i].Active = 0;
MetalCounter[i].EndDoc = NO_ENDDOC;
MetalCounter[i].Timer = NO_COUNT;
MetalCounter[i].EquEnable = 1;
MetalDetection.BufAvailable = 1;
// Viene aggiornato lo stato della scheda secondo lo
// stato della memoria di allocazione dinamica, ma non
// viene generato un report dello stato slave, pertanto
// il nuovo stato verra' trasmesso al primo invio
// programmato
if (ErrMemory)
{
Stato |= ERROR_MTL;
}
else
{
Stato &= ~ERROR_MTL;
}
}
} // if (MetalCounter[i].EndDoc == NO_ENDDOC)
// Disabilito la lettura sensori
MetalCounter[i].ReadEnable = 0;
} //if (MetalCounter[i].ReadEnable)
} // for (i = 0; i < MTL_BUFNUM; i++)
// **************** ELABORAZIONI RICERCA METALLI *********************
for (i = 0; i < MTL_BUFNUM; i++)
{
// Sezione 3 - Normalizzazione equivalenze
if (MetalCounter[i].EquEnable)
{
MetalCounter[i].EquEnable = 0;
ErrEqu = NormalizzaEquivalenze(i);
MetalCounter[i].LabEnable = 1;
// printf("\nNormalizzazione equivalenze eseguita su buffer %d\n",i);
} //if (MetalCounter[i].EquEnable)
// Sezione 4 - Normalizzazione etichette
if (MetalCounter[i].LabEnable)
{
MetalCounter[i].LabEnable = 0;
ErrLab = NormalizzaEtichette(i);
MetalCounter[i].CatEnable = 1;
// printf("\nNormalizzazione etichette eseguita su buffer %d\n",i);
} //if (MetalCounter[i].LabEnable)
// Sezione 5 - Catalogazione etichette
if (MetalCounter[i].CatEnable)
{
MetalCounter[i].CatEnable = 0;
ErrCat = CatalogaEtichette(i);
MetalDetection.LastComplete = i;
ErrDel = EliminaEquivalenze(i);
printf("\n TotCol per buffer %d = %d\n",i, ScanDoc[i].TotCol);
/* printf(" SamplesCount per buffer %d = %d\n",i, ScanDoc[i].SamplesCount);
printf(" RegionsCount per buffer %d = %d\n",i, ScanDoc[i].RegionsCount);
printf(" NumRegions per buffer %d = %d\n",i, ScanDoc[i].NumRegions);
printf(" LargerRegionSamples per buffer %d = %d\n",i, ScanDoc[i].LargerRegionSamples);
printf(" HigherRegionHeight per buffer %d = %d\n",i, ScanDoc[i].HigherRegionHeight);
printf(" HigherRegionLength per buffer %d = %d\n",i, ScanDoc[i].HigherRegionLength);
printf(" LongerRegionHeight per buffer %d = %d\n",i, ScanDoc[i].LongerRegionHeight);
printf(" LongerRegionLength per buffer %d = %d\n\n\n",i, ScanDoc[i].LongerRegionLength);
*/
// Set del bit di dato valido
MetalCounter[i].Valid = 1;
MetalCounter[i].CountValid = MetalDetection.DlyValid;
// Abilitazione invio report LENTO1
MetalDetection.SendRepEnable = 1;
// Se la gestione e' a spazio leggo lo stato dell'encoder
if (MetalDetection.Encoder != 0xFF)
MetalCounter[i].EncPrev = ENCPORT[0];
} //if (MetalCounter[i].CatEnable)
} // for (i = 0; i < MTL_BUFNUM; i++)
} // if (MetalDetection.Enable)
// =============== GESTIONE RICERCA METALLI: FINE ====================
countEnc = ENCPORT[0];
//to be continued
|
|
Read-Only Author Marco Loi Posted 22-Jul-2008 12:31 GMT Toolset C166 |  Finishing RE: ILLOPA exception on C167CR-LM 5/5 Marco Loi Here the 5/5 part of the code:
// ================== GESTIONE RILETTURA USCITE ======================
if (NOutputSpeed) {
if (!RB_Cnt) {
// controllo della rilettura di tutte le uscite
checkRB = ((~Output) ^ P5) & MaskOutSpeed;
for (i=0; i<NOutputSpeed; i++) {
if (EnableRB[i] && (checkRB & (1<<i))) {
CountErrRB++;
errRB =1;
}
}
RB_Cnt = NO_COUNT;
}
if (RB_Cnt != NO_COUNT)
RB_Cnt--;
}
// ===================== GESTIONE RITARDI ===========================
if (NDly) {
// gestione canali ritardati
for (i=0; i<NDly; i++) {
// se nel ciclo precedente è cambiato lo stato dell'uscita viene
// controllato se si è verificato un errore di rilettura (se abilitata)
if(EnableRB[Dly[i].Output] && (!Dly[i].Status)) {
if(((~Output) ^ P5) & (0x0001 << Dly[i].Output)) {
CountErrRB++;
errRB = 1;
}
Dly[i].Status = NO_COUNT;
}
if (Dly[i].Status != NO_COUNT)
Dly[i].Status--;
if (Dly[i].Encoder == 0xFF) {
// -------------- Ritardi a tempo -------------------------------
if (Dly[i].CountDlyOn != NO_COUNT) {
Dly[i].CountDlyOn--;
if (Dly[i].CountDlyOn < 0) {
Output |= (0x0001 << Dly[i].Output);
Dly[i].Status = RB_DELAY;
Dly[i].CountDlyOn = NO_COUNT;
}
}
if (Dly[i].CountDlyOff != NO_COUNT) {
Dly[i].CountDlyOff--;
if (Dly[i].CountDlyOff < 0) {
Output &= ~(0x0001 << Dly[i].Output);
Dly[i].Status = RB_DELAY;
Dly[i].CountDlyOff = NO_COUNT;
}
}
}
else {
// -------------- Ritardi a spazio (encoder) ----------------------
if (Dly[i].CountDlyOn != NO_COUNT) {
cnt = abs(countEnc - countON[i]);
if (cnt > MAX_GAP)
Dly[i].CountDlyOn -= (countEnc > MAX_GAP) ? (0xFF - countEnc + countON[i]):
(0xFF + countEnc - countON[i]);
else Dly[i].CountDlyOn -= cnt;
// Dly[i].CountDlyOn -= abs(countEnc - countON[i]);
countON[i] = countEnc;
if (Dly[i].CountDlyOn <= 0) {
Output |= (0x0001 << Dly[i].Output) ;
Dly[i].Status = RB_DELAY;
Dly[i].CountDlyOn = NO_COUNT;
}
}
if (Dly[i].CountDlyOff != NO_COUNT) {
cnt = abs(countEnc - countOFF[i]);
if (cnt > MAX_GAP)
Dly[i].CountDlyOff -= (countEnc > MAX_GAP) ? (0xFF - countEnc + countOFF[i]):
(0xFF + countEnc - countOFF[i]);
else Dly[i].CountDlyOff -= cnt;
// Dly[i].CountDlyOff -= abs(countEnc - countOFF[i]);
countOFF[i] = countEnc;
if (Dly[i].CountDlyOff <= 0) {
Output &= ~(0x0001 << Dly[i].Output);
Dly[i].Status = RB_DELAY;
Dly[i].CountDlyOff = NO_COUNT;
}
}
}
}
// attuazione dei canali di uscita
SetOut(Output);
}
// trasmissione su CAN della condizione di errore sul PDO di stato
// se si è verificato almeno un errore di rilettura
if (errRB && (!(Stato & ERROR_RB))) {
T8R = 1;
Stato |= ERROR_RB;
CAN_MSGOBJ[STATO].msg_ctl = CPUUPD_SET;
CAN_MSGOBJ[STATO].msg_cfg = MSG_CFG(1, CANDIR_TRANSMIT, 0);
CAN_MSGOBJ[STATO].msg[0] = Stato;
CAN_MSGOBJ[STATO].msg_ctl = CPUUPD_CLR & TXRQ_SET;
}
StartT1Idle = T1;
}
|
|
Read-Only Author Per Westermark Posted 22-Jul-2008 12:22 GMT Toolset C166 |  RE: ILLOPA exception on C167CR-LM 1/4 Per Westermark That ISR is very seriously broken. It is many, many, many times too large and tries to do things a 0.5ms ISR should not try to do. Do split your code into ISR to collect events and a main loop that process the events. Your ISR shouldn't be larger than what you can view at the same time without selecting a microscopic font. How have you made sure that for any sequence of input stimuli, your ISR manages to do all work in 0.5ms? If y ou can't guarantee that - why even bother to have the code in the ISR if it isn't critical enough that it _must_ be done within 0.5ms? |
|
Read-Only Author Marco Loi Posted 22-Jul-2008 12:38 GMT Toolset C166 |  RE: ILLOPA exception on C167CR-LM 1/4 Marco Loi This ISR rotine is a quarter of another one in another application for the same boards in the same plant, and it runs always good ... |
|
Read-Only Author Per Westermark Posted 22-Jul-2008 13:04 GMT Toolset C166 |  RE: ILLOPA exception on C167CR-LM 1/4 Per Westermark There are stunt drivers that can drive their cars on two wheels - that doesn't mean that it is good to drive a car with two wheels in the air... |
|
Read-Only Author Tamir Michael Posted 22-Jul-2008 13:06 GMT Toolset C166 |  Redesign Tamir Michael your ISR is miles long. it contains wasteful references to array elements, multiple loops... try what Per suggested: move the whole block outside of interrupt context - put it in a function and call it from your main loop. what happens then? again: the fact that code works means nothing beyond that it does not fail on that hardware, under certain circumstance |
|
Read-Only Author Marco Loi Posted 22-Jul-2008 13:21 GMT Toolset C166 |  RE: Redesign Marco Loi I cannot modify the structure of this program. It's not my property. I had received this code with this function by the company customer and I removed some unuseful pieces and add a new part. I cannot split this routine. |
|
Read-Only Author Mike Kleshov Posted 22-Jul-2008 13:45 GMT Toolset C166 |  RE: Redesign Mike Kleshov Hi Marco, Back to your original question: what causes the Illegal Operation trap? You should add a trap handler to collect some debugging information (address of the offending opcode, contents of some CPU registers etc.) Soon you'll be able to map the offending opcode to the exact line of source code. Regards, - mike |
|
Read-Only Author Mike Kleshov Posted 22-Jul-2008 13:55 GMT Toolset C166 |  RE: Redesign Mike Kleshov Small correction. Just looked it up: ILLOPA is 'Illegal Word Operand Access.' It happens when a word access is attempted at an odd address. Look out for unaligned pointers. The method I suggested should allow you to pinpoint the exact line of source code and the offending unaligned pointer. |
|
Read-Only Author Marco Loi Posted 22-Jul-2008 13:58 GMT Toolset C166 |  RE: Redesign Marco Loi Thanks Mike, so at this moment I've a trap function that, in case of ILLOPA event, print a string "ILLOPA trap!" on serial link. I can add here a complete printf whith more informations. Now I try to understand what are the registers or pointers of interest about my problem. Thank you very much. Marco |
|
Read-Only Author Mike Kleshov Posted 22-Jul-2008 14:03 GMT Toolset C166 |  RE: Redesign Mike Kleshov See the MCU manual. The C167 CPU will push PSW, CSP and IP onto the system stack. Print them. CSP and IP will point to the offending instruction. Using a disassembler, you'll be able to map the instruction to the source code. |
|
Read-Only Author Marco Loi Posted 22-Jul-2008 14:14 GMT Toolset C166 |  RE: Redesign Marco Loi More thanks. Marco |
|
Read-Only Author Marco Loi Posted 23-Jul-2008 14:24 GMT Toolset C166 |  RE: Redesign Marco Loi Hello Mike, I looked to User Manual but is written that IP and CSP are not directly accessible, so how can I print IP and CSP? Thanks |
|
Read-Only Author Mike Kleshov Posted 23-Jul-2008 14:56 GMT Toolset C166 |  RE: Redesign Mike Kleshov I looked to User Manual but is written that IP and CSP are not directly accessible You mean this, right? The IP register is not mapped into the C167CS's address space, and thus it is not directly accessible by the programmer That's true, but why would you want to read IP in the trap handler? It will not do you any good. You don't need to read the actual registers. You need the contents of those registers at the time when the trap occured. And those are saved on the stack by the CPU (see manual, section on trap functions.) If I remember correctly, Keil's C166 compiler has an intrinsic function for popping words off the stack. _pop_(), maybe? Look it up. Here is what I would do:
void trap_handler(void)
{
uint16_t psw, csp, ip;
ip = _pop_();
csp = _pop_();
psw = _pop_();
... print psw, csp, ip ...
}
|
|
Read-Only Author Marco Loi Posted 23-Jul-2008 15:06 GMT Toolset C166 |  RE: Redesign Marco Loi You are correct. Summary: #include <intrins.h> int _pop_ (void); Description: The _pop_ function inserts a POP instruction into the program which pops the next word from the system stack. Return Value: The _pop_ function returns the 16-bit value poped from the system stack. Example:
#include <intrins.h>
void testpop (void) {
volatile unsigned temp;
_push_ (temp);
temp = _pop_ ();
}
|
|
Read-Only Author Tamir Michael Posted 23-Jul-2008 15:51 GMT Toolset C166 |  RE: Redesign Tamir Michael you may want to have a look at the Keil provided traps.c file, too. |
|
Read-Only Author Marco Loi Posted 23-Jul-2008 16:05 GMT Toolset C166 |  RE: Redesign Marco Loi Yes, Ok. I've in my project a custom version of traps.c. Using the calls to _pop_ function I will insert them in a function called by ILLOPA trap in my traps.c. Thanks. |
|
Read-Only Author Mike Kleshov Posted 23-Jul-2008 16:21 GMT Toolset C166 |  RE: Redesign Mike Kleshov Using the calls to _pop_ function I will insert them in a function called by ILLOPA trap in my traps.c Be careful, though. Each function call pushes more data onto the stack. You have to account for that when trying to extract the saved PSW, CSP, IP. The three simple pops will not do. |
|
Read-Only Author Marco Loi Posted 23-Jul-2008 16:26 GMT Toolset C166 |  RE: Redesign Marco Loi You are correct, it's a problem. I will try to find a solution. Thanks! |
|
Read-Only Author Per Westermark Posted 23-Jul-2008 16:28 GMT Toolset C166 |  RE: Redesign Per Westermark If a ILLOPA represents an 'Illegal Word Operand Access', then I recommend that you test your trap handler by intentionally doing an incorrect access, and verify that the data you get do point to the correct position in the code. You may loose a lot of time if your trap handler is buggy and prints the wrong address, and you then spend time trying to figure out why a completely different location contains a problem... |
|
Read-Only Author Marco Loi Posted 23-Jul-2008 16:38 GMT Toolset C166 |  RE: Redesign Marco Loi Ok, thanks. |
|
Read-Only Author Tamir Michael Posted 23-Jul-2008 20:03 GMT Toolset C166 |  RE: Redesign Tamir Michael one more important thing:
#pragma NOFRAME // gain full control over stack push/pop instructions of the interrupt handler
static void task_switch() interrupt 0x20
notice the #pragma. placed before a function, it will prevent the compiler from automatically generating code that saves your registers onto the stack thereby not polluting it. |
|
Read-Only Author Marco Loi Posted 24-Jul-2008 09:20 GMT Toolset C166 |  RE: Redesign Marco Loi Ok. I've updated my Class_B_trap function in the customised file traps.c with the red code below.
#pragma NOFRAME
void Class_B_trap (void) interrupt 0x0A {
volatile UINT reg_ip;
volatile UINT reg_csp;
volatile UINT reg_psw;
reg_ip = _pop_();
reg_csp = _pop_();
reg_psw = _pop_();
printf("IP: %X, CSP: %X, PSW: %X\n\n", reg_ip, reg_csp, reg_psw);
if (ILLBUS) puts("Accesso a bus esterno non valido");
if (ILLINA) puts("Accesso ad istruzione non valido");
if (ILLOPA) puts("Accesso ad operando non valido");
if (PRTFLT) puts("Istruzione di protezione non valida");
if (PRTFLT) puts("Codice istruzione non definita");
ERRF = 1;
while (1); /* end-less loop */
}
So the value of reg_ip combined with the reg_csp value will be the address of the instruction following the one which caused the trap. Is it correct? |
|
Read-Only Author Per Westermark Posted 24-Jul-2008 10:32 GMT Toolset C166 |  RE: Redesign Per Westermark Why do you declare your variables volatile? Are you expecting them to be changed by memory corruption or? The keyword volatile should be used for a global variable that may asynchronously changed by someone else, such as an interrupt handler or a a different thread. An auto variable should never be changed asynchronously unless you have a memory corruption somewhere, allowing an interrupt or thread to play with stack memory they do not own. By the way: Think about using an unified intentation strategy. Your code has three different indent levels and/or mixings of space and tab. That doesn't help readability. |
|
Read-Only Author Mike Kleshov Posted 24-Jul-2008 12:53 GMT Toolset C166 |  RE: Redesign Mike Kleshov Why do you declare your variables volatile? Oh please! Obviously, the guy is only interested in fixing this particular bug. He's got a fair share of advice on programming style already in this thread. Apparently, volatile comes from here: http://www.keil.com/support/man/docs/c166/c166__pop_.htm So blame Keil for this. I, too, cannot see why they would declare the variable volatile. Except, perhaps, 'just in case'... |
|
Read-Only Author Tamir Michael Posted 24-Jul-2008 13:07 GMT Toolset C166 |  RE: Redesign Tamir Michael Mike, I think Per's latest comment are very much appropriate. The OP (assuming he is not aware of the impact of volatile, of course) might have gotten the false impression that volatile is somehow required, and start using it regularly (thanks to a weird example by Keil, indeed). That will have a negative impact on the performance and size of his code. And who knows, if somebody ever proved him wrong, he would have given us a bad name :-) |
|
Read-Only Author Per Westermark Posted 24-Jul-2008 13:58 GMT Toolset C166 |  RE: Redesign Per Westermark I'm not blaming anyone. I just know that volatile is a often misunderstood keyword. A volatile too much hurts optimization a lot. A volatile too little can result in totally unexplainable errors. In a single-tasking PC program, it is possible to ignore this keyword, but in an embedded environment with interrupts and possibly RTOS tasks, it is important to realize the the meaning of it, and that includes both when to use it, and when not to use it. |
|
Read-Only Author Marco Loi Posted 24-Jul-2008 13:09 GMT Toolset C166 |  RE: Redesign Marco Loi Why do you declare your variables volatile? Are you expecting them to be changed by memory corruption or?
I copied it from the C166 User Manual.
By the way: Think about using an unified intentation strategy. Your code has three different indent levels and/or mixings of space and tab. That doesn't help readability.
I's a problem of copy and paste ...
Thanks. |
|
Read-Only Author Marco Loi Posted 29-Jul-2008 08:49 GMT Toolset C166 |  RE: Redesign Marco Loi Well, using the lower 8 bits of CSP and the 16 bits of IP I've an address. Looking at the Disassembly window it seems that it's not the address of the offending instruction, and it's not the instruction following the one which caused the trap, because looking at the conditions of my test, the routine containing these instructions cannot be called. Have you any suggestions? Thanks! |
|
Read-Only Author Per Westermark Posted 29-Jul-2008 09:57 GMT Toolset C166 |  RE: Redesign Per Westermark I'll repeat myself: "f a ILLOPA represents an 'Illegal Word Operand Access', then I recommend that you test your trap handler by intentionally doing an incorrect access, and verify that the data you get do point to the correct position in the code. You may loose a lot of time if your trap handler is buggy and prints the wrong address, and you then spend time trying to figure out why a completely different location contains a problem..." If you know exactly where you came from, it is easier to verify what data you have on the stack and what your trap handler produces. |
|
Read-Only Author Marco Loi Posted 29-Jul-2008 10:06 GMT Toolset C166 |  RE: Redesign Marco Loi I recommend that you test your trap handler by intentionally doing an incorrect access, and verify that the data you get do point to the correct position in the code. I'm not able to do this operation. Have you a possible example? Thanks! |
|
Read-Only Author Per Westermark Posted 29-Jul-2008 12:25 GMT Toolset C166 |  RE: Redesign Per Westermark What happens if you do the following: - Have an array of two int. - Let a byte pointer get the address of the first int. - Increment the byte pointer one step. - Typecast the byte pointer to an int pointer and try to read. This should perform a word access from an odd address. |
|
Read-Only Author Marco Loi Posted 29-Jul-2008 12:34 GMT Toolset C166 |  RE: Redesign Marco Loi Thanks! It's easiest than I had imagined |
|