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 CCS Technical Support

PIC12F1822: PWM int-flag problem on mask level 9

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



Joined: 29 Aug 2008
Posts: 7

View user's profile Send private message

PIC12F1822: PWM int-flag problem on mask level 9
PostPosted: Fri May 23, 2014 3:43 pm     Reply with quote

Hi,

I am using PIC12F1822 to generate a sine wave via pwm.
The code was written and tested on silicium mask level 8.

But now I got mask level 9 and the code does not work anymore.
After some testing I found out that the pwm int-flag may cause
the problem.

This is my code:
Code:

   while(1)
   {
      // check PWM int-flag
      if( (PIR1 & 0x02) == 0x02 )
      {
         // set new pwm value
         set_pwm1_duty( sine[ sine_ptr ] );
   
         // read next pwm value from table
         if( sine_ptr < 49 ) sine_ptr++;

         if( sine_ptr >= 49 )
         {
            if( input( EN_PIN ) )
            sine_ptr = 0;
            poti = read_adc( );
            poti >>=5;
         }
         
         // clear PWM int-flag
         PIR1 &= 0xfd;
   
         for( c=0; c<poti; c++ );
      }
   }


This is the init code:
Code:

void HW_Init ()
{
   // Set internal oscillator to 16 MHz
   setup_oscillator(OSC_16MHZ|OSC_INTRC);

   // Set Timer 2 clock to internal osc, no prescaler, used for PWM timing
   setup_timer_2(T2_DIV_BY_1, 99, 1);   // 40 KHz

   // enable CCP1 for PWM mode
   setup_ccp1( CCP_PWM );

   setup_comparator(NC_NC_NC_NC);                 

   // Setup Ports for ADC operation
   setup_adc_ports(sAN3|VSS_VDD);
   setup_adc(ADC_CLOCK_INTERNAL);

   // Set ADC-Channel for next conversion
   set_adc_channel(3);
}

The program does not pass the first if statement.
In Mask level 8 it does. Very strange.

The program is used to generate a sine wave with
variable (voltage controlled) frequency for engine
warning signals for zeppelin pilots.

Next week are FAA tests so this problem is very urgent.

If anyone has an idea, please help!

Best wishes,
Chris
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri May 23, 2014 4:25 pm     Reply with quote

I assume you're talking about Microchip silicon Rev. A9 for the 12F1822.
Where did you buy the PICs ? A reputable supplier ?

1. Post a complete test program. I don't mean post your whole
proprietary program, but I mean post the #include, all #device
statements, #fuses, #use delay, all necessary variable declarations,
main(), etc., so that we can compile and test the problem.
If you're changing the default behavior of the compiler in any way,
such as changing the #opt level, be sure to tell us.
Test the program before you post it, to confirm that you still get
a failure.

2. Post your CCS compiler version. It's given at the top of the .LST file
after a successful compilation. It's a 4 digit number in this format: x.xxx
Example: http://www.ccsinfo.com/devices.php?page=versioninfo

3. What's the Vdd voltage for your PIC during testing ?
What power supply are you using ? Have you checked it with a scope
for a constant, low noise DC voltage ?

4. Are you using a 12F1822, or is it the "LF" version ? Look at the
markings on the PIC package.

5. What package are you using ? DIP, SOIC, or DFN ?

6. Did you follow all standard design practice rules, such as putting
a 100 nF ceramic SMD capacitor to ground, very close to the PIC's Vdd pin ?

7. Describe the test conditions. Does the A/D voltage come from a
trimpot that you turn with your hand ? What is the voltage range
that you are sending to the AN3 pin with the trimpot during the test ?
Does the problem occur at any particular A/D input voltage ?
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Fri May 23, 2014 6:58 pm     Reply with quote

is
SINE[] an int8 or int16 ??

adc, is it in 8 bit or 10 bit output mode ?
poti 16 bit or 8 ?

what is the purpose of var c ??
defining CCP1IF by a #bit directive would be
another way to do the detect and clear thing you coded ...

I do heartily agree with PCMP that too much is still concealed to
have a strong opinion about what is wrong...

what i do suspect is that the later silicon is less broken than what you worked with at first from Microchip

Very Happy Very Happy Very Happy
Ttelmah



Joined: 11 Mar 2010
Posts: 19513

View user's profile Send private message

PostPosted: Sat May 24, 2014 12:43 am     Reply with quote

As a general comment though, use the #BIT ability to access the flag.

Code:

#BIT PWMFLAG=PIR1.1

//then the if becomes

if (PWMFLAG)

//and the reset becomes
PWMFLAG=FALSE;


Fiddling around with mask bits and bytes, is silly, since the processor has bit test and set functions, and using the #bit command, the compiler will access these. Smaller, faster, less likely to have problems.

Too much 'missing' (as PCM programmer says), to know what is wrong. There is not any visible erratum that would cause this. However look carefully at the errata for the older chip as well - could a compiler fix for one of these give problems with the newer chip?.
chrhartz



Joined: 29 Aug 2008
Posts: 7

View user's profile Send private message

PostPosted: Sat May 24, 2014 5:21 am     Reply with quote

@Ttelmah

finally I found the problem. It was the bit setting of the PIR1 register.
I do not really understand the reason. Can anyone explain this?

Why is
if( (PIR1 & 0x02) == 0x02 )

not the same like
if( PWMFLAG ) ?

And I do not understand why the code works with silicon rev. 8
and not with rev. 9. I have both revisions here and can change the
chips easily. With the bit set and test code it runs on both revisions!

If anyone needs a simple tone generator with sine output,
frequency adjustable in 64 steps from 160 to 1.6 KHz and enable,
this is the code: Smile

Code:
/***********************************************************************/
// Compiler Directives

#device adc=10                     // 10 Bit ADC result

#FUSES NOWDT            // No Watch Dog Timer
#FUSES INTRC_IO         // Internal RC Oscillator with I/O on OSC-Pins
#FUSES BROWNOUT         // Enable Brownout


/***********************************************************************/
// defines

// Input Pins
#define EN_PIN            pin_A5      // (1 = active, Sine enable)

// Internal register definitions
#byte PIR1 = 0x11
#bit PWMFLAG = PIR1.1

/***********************************************************************/
// global vars
unsigned int8 sine_ptr;

/***********************************************************************/
// constants

byte sine[50] =  {52,57,62,66,70,74,77,80,82,84,85,86,86,
                  86,85,83,81,78,75,72,69,65,61,56,52,
                  48,44,39,35,31,28,25,22,19,17,15,14,14,
                  14,15,16,18,20,23,26,30,34,38,43,48};

/***********************************************************************/
// Main Program

void main()
{
   int16 c;
   int16 poti = 0;

   // Set internal oscillator to 16 MHz
   setup_oscillator(OSC_8MHZ|OSC_NORMAL|OSC_PLL_ON);

   // Set Timer 2 clock to internal osc, no prescaler
   setup_timer_2(T2_DIV_BY_1, 99, 1);   // 40 KHz

   // enable CCP1 for PWM mode
   setup_ccp1( CCP_PWM );

   setup_comparator(NC_NC_NC_NC);                 

   // Setup Ports for ADC operation
   setup_adc_ports(sAN3|VSS_VDD);
   setup_adc(ADC_CLOCK_INTERNAL);

   // Set ADC-Channel for next conversion
   set_adc_channel(3);
 
   // table pointer to first value
   sine_ptr = 0;

//------------------------------------------------------------------

   while(1)
   {
      // check PWM int-flag
      if( PWMFLAG )
      {
         // set new pwm value
         set_pwm1_duty( sine[ sine_ptr ] );
   
         // read next pwm value from table
         if( sine_ptr < 49 ) sine_ptr++;

         if( sine_ptr >= 49 )
         {
            if( input( EN_PIN ) )
            sine_ptr = 0;
            poti = read_adc( );
            poti >>=5;
         }
         
         // clear PWM int-flag
         PWMFLAG = FALSE;
   
         for( c=0; c<poti; c++ );
      }
   }
}
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Sat May 24, 2014 8:23 am     Reply with quote

Glad it worked out for you.
do you use any low pass analog filtering on the "sine wave"?
8-bit PWM generated "sine" waves have a really significant
even order harmonic content that can be very troublesome in
many applications. 2nd harmonic of only -10db or so for what you
generate this way.

for really excellent, high purity ( 10 bits worth) sine generation
(unfiltered harmonics at -45 db or so ) you might consider
the analog devices Ad9833 and similar DDS chips instead.

as a bonus it makes really linear tri-waves too
( for fans of ODD order harmonics )

just my 2 cents Very Happy Very Happy Very Happy
gpsmikey



Joined: 16 Nov 2010
Posts: 588
Location: Kirkland, WA

View user's profile Send private message

PostPosted: Sat May 24, 2014 8:55 am     Reply with quote

Quote:
Why is
if( (PIR1 & 0x02) == 0x02 )

not the same like
if( PWMFLAG ) ?


The only thing I can suggest is to look at the lst file for both forms and see if you see anything obvious. It certainly looks reasonable to me, however, processors don't always see things the same way I do Evil or Very Mad

mikey
_________________
mikey
-- you can't have too many gadgets or too much disk space !
old engineering saying: 1+1 = 3 for sufficiently large values of 1 or small values of 3
Ttelmah



Joined: 11 Mar 2010
Posts: 19513

View user's profile Send private message

PostPosted: Sun May 25, 2014 1:47 am     Reply with quote

It's going to be very different code.

Testing the bit as I show uses a single machine instruction. It'll use either a BTFSC, or a BTFSS instruction to just test the one bit and jump.

The original code, has to load the whole byte from the register, then perform an '&' on this with the constant 2, then take the result, and test if this is equal to 2 (another subtraction). Probably four or five instructions. So using the bit is always going to be quicker, and smaller code. On clearing the bit again using the #bit form, will just use the BCF instruction, while the load and mask form again takes several instructions. However the original form should work.
On a couple of other chips in the PIC12 family there is an erratum concerning byte operations on the PIR register. It's not listed as a problem for this chip, but it sounds as if revision 9, may have added this problem....
If I remember correctly, it was if a bit set in the same instruction as you read it, it could sometimes fail to set. This would give exactly the problem seen here...

Leave everything else unchanged.

Compile with the original code, and save this small part of the assembler. Verify it doesn't work.
Then re-compile with the #bit form, and verify this does work. Again save the assembler section.
Then send the two sections to Microchip, with the simple explanation that the former works with the Rev8 chip, and not with the Rev9 chip....

Best Wishes
chrhartz



Joined: 29 Aug 2008
Posts: 7

View user's profile Send private message

PostPosted: Sun May 25, 2014 3:26 pm     Reply with quote

@Ttelmah

Thank you for the explanation. I didnĀ“t know that the #bit directive
uses bit set, test and clear instead of byte operations. I will use this
in the future.

@asmboy
I have found this website from Roman Black:
http://www.romanblack.com/onesec/Sine1kHz.htm

There is a very good description about signal quality and improvements.

I am using his sine table and idea to check the pwm int bit. I have
added the enable signal and start/stop at null point of the sine wave.

Best wishes,
Chris
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