CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

Suspicious int32 bug

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Jul 21, 2006 1:42 am     Reply with quote

Quote:
sometimes, after an interrupt, the ADC oversampling accumulator are corrupted.


If you modify an int16 or int32 global variable inside an interrupt service
routine (isr) and then you read it outside of the isr, you must turn off
interrupts while you're reading the variable. That's because to read
a 32-bit variable, the PIC must execute 8 instructions. It can't read
it in just one instruction. If an interrupt occurs between any of those
8 instructions, the int32 value will be changed. Then when control
returns to the main() code, and the remaining bytes to be read may
be different than they were before the interrupt. Your program will
appear to have a corrupted variable.

Here is the .LST file code which shows the 8 instructions required to read
the global int32 variable:
Code:

0000            00390 .... temp = isr_value;
0055 082C       00391 MOVF   2C,W
0056 00B0       00392 MOVWF  30
0057 082B       00393 MOVF   2B,W
0058 00AF       00394 MOVWF  2F
0059 082A       00395 MOVF   2A,W
005A 00AE       00396 MOVWF  2E
005B 0829       00397 MOVF   29,W
005C 00AD       00398 MOVWF  2D


To fix the problem, add the lines shown in bold below:
Quote:

#include <16F877.h>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)

int32 isr_value;

#int_timer0
void timer0_isr(void)
{

isr_value++;

}

//======================
void main()
{
int32 temp;

while(1)
{
disable_interrupts(GLOBAL);
temp = isr_value;
enable_interrupts(GLOBAL);
}

}
Murph



Joined: 20 Jul 2006
Posts: 4

View user's profile Send private message

PostPosted: Fri Jul 21, 2006 3:25 am     Reply with quote

Thank you for so fast reply.

In a old version of code I disabled the interrupt during the accumulator exchanging values but the error still happened

In a successive version, where the oversampling was entirely made out of the isr routine, again the problem happened

Now, I discard the oversampling result if a interrupt occurred and all appear right, but this is not the right manner


Murph
Murph



Joined: 20 Jul 2006
Posts: 4

View user's profile Send private message

PostPosted: Mon Jul 24, 2006 8:48 am     Reply with quote

Hallo PCM programmer,
I prepared some lines of code generating the bug.

After the initialization, the main() function repeatedly call AdcOversampling() that increases and checks the variable acc_sample. There is yet the interrupt routine that stops the execution and makes only a delay.
If you run this code and send a sequence of interrupt you will find the AdcOversampling() end to work because the value of acc_sample exceeds the maximum possible value.

Where is the problem?

Thanks for your aid
Murph

Code:
#include <16F819>

#fuses XT, NOWDT, PUT, NOBROWNOUT, NOLVP, NOWRT, NOCPD, NOPROTECT
#use delay(clock = 4000000)

// Special Function Registers
#byte STATUS_REG = 0x03
#byte OPTION_REG = 0x81
#byte INTCON_REG = 0x0B

// Flag interrupt
#bit  INT_EXT_FLAG = INTCON_REG.1

// Definizioni IO
#byte PORT_A = 0x05
#byte PORT_B = 0x06
#byte TRIS_A = 0x85
#byte TRIS_B = 0x86
#bit  SYSTEM_LED = PORT_B.4
#bit  PIN_DEBUG  = PORT_B.5

void SystemInit(void);
void AdcOversampling(void);
void Rs232IsrRx(void);
void main(void);


// ****************************************************************************
void SystemInit(void)
{
   TRIS_A = 0b11100001;
   PORT_A = 0b00000000;

   TRIS_B = 0b00000011;
   PORT_B = 0b00000000;

   // RB0 = External Interrupt on Falling Edge
   ext_int_edge(H_TO_L);
   enable_interrupts(INT_EXT);
   
   // Usa IO veloci
   #use fast_io(A)
   #use fast_io(B)

   // Abilita interrupt
   enable_interrupts(GLOBAL);
}


// ****************************************************************************
void AdcOversampling(void)
{
   unsigned int16 num_sample;
   unsigned int32 acc_sample;

   acc_sample = 0;
   
   for (num_sample = 1; num_sample < 16384; num_sample++)
   {
       acc_sample = acc_sample + 0x1FF;

      if (acc_sample > 10000000)
      {
         for(;;)
         {
            SYSTEM_LED = ~SYSTEM_LED;
            delay_ms(50);     
         }
      }
   }
}


// ****************************************************************************
#INT_EXT
void Rs232IsrRx(void)
{
   // Disabilita interrupt
   disable_interrupts(GLOBAL);
   INT_EXT_FLAG = FALSE;

   PIN_DEBUG = TRUE;
   delay_ms(10);
   PIN_DEBUG = FALSE;

   enable_interrupts(GLOBAL);
}


// ****************************************************************************
void main(void)
{
   SystemInit();
   
   for (;;)
   {
      // Acquisisce campione con oversampling
      AdcOversampling();

      // Lampeggio LED sistema
      SYSTEM_LED = ~SYSTEM_LED;
   }
}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Jul 24, 2006 12:10 pm     Reply with quote

Remove the lines shown in bold below. They are not necessary, and
the last one can cause the program to crash. Never do this.
Quote:

#INT_EXT
void Rs232IsrRx(void)
{
// Disabilita interrupt
disable_interrupts(GLOBAL);
INT_EXT_FLAG = FALSE;

PIN_DEBUG = TRUE;
delay_ms(10);
PIN_DEBUG = FALSE;

enable_interrupts(GLOBAL);
}


This thread explains why the enable_interrupts(GLOBAL) line can cause
the program to crash:
http://www.ccsinfo.com/forum/viewtopic.php?t=26117
Murph



Joined: 20 Jul 2006
Posts: 4

View user's profile Send private message

PostPosted: Tue Jul 25, 2006 6:26 am     Reply with quote

Magic PCM Programmer,
now the code works.

This is my first work with PIC micro and I do the mistake to believe, cause the simple structure of the device, that the programmer must to say to uP everything what to do.

Thank you
Murph
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Tue Jul 25, 2006 6:49 am     Reply with quote

Just one more note on your code
Code:
   INT_EXT_FLAG = FALSE;

You are aware that by default the compiler will clear the interrupt flag at the end of the interrupt routine also? Maybe not a problem in your application but at least double work.
You can add the NOCLEAR directive to the #int_ext line to prevent the compiler from clearing the interrupt, or remove your line from the program for easier reading.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group