![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
Jim Hearne
Joined: 22 Dec 2003 Posts: 109 Location: West Sussex, UK
|
18f24K22. Timer1 causing spurious state changes on CCP2 or 3 |
Posted: Fri Sep 09, 2016 6:19 am |
|
|
Hi all,
Does anybody have any thoughts on this problem.
We have a product that uses the 18f24K22 PIC.
We have 2 pwm outputs generated by using the CCP2 and CCP3 modules in compare mode.
We noticed that very occasionally (on average 5 mins) there would be a big spike on the smoothed PWM output.
Eventually I've narrowed it down to the code below, this shows the problem with just CCP2 running.
For some reason I can't figure out, if timer1 is running (but not used) when I reset timer 3 in the CCP interrupt code the CCP2 output gets set or reset straight away and effectively misses a high or low pulse.
I set another output (LED_A) in the same code which I've also got on the scope.
This test code has the CCP running faster so the problem occurs every 30 seconds or so.
If I comment out the line that enables timer1 the problem does not occur.
But there should be no connection between timer1 and the CCP using Timer3 (also happens on CCP3 using timer5).
If I don't reset timer3 but instead add the period value to CCP2 the problem also doesn't occur. So I have a work around but why is it happening ?
Scope pictures are below, Blue (bottom) trace is the CCP2 output (on B3), the Yellow (top) trace is the LED_A output which is set in the interrupt code so I know the interrupt is being processed.
Compiler version 4.130
I've tried the test code on a pcb with just the processor and the problem still occurs.
Code: |
#include <18f24K22.h>
#device ADC=10
#device *=16
#fuses INTRC_IO, put, WDT512, nolvp, nocpd, PROTECT, NOMCLR, WRT, BROWNOUT, NODEBUG, BORV29, NOFCMEN, NOIESO,PLLEN, NOPBADEN, CCP2B3, CCP3B5
#use delay(clock=64000000,RESTART_WDT)
#use fast_io(a)
#use fast_io(b)
#use fast_io(c)
#use fast_io(e)
#byte port_a = 0x0f80
#byte port_b = 0x0f81
#byte port_c = 0x0f82
#byte port_e = 0x0f84
#bit led_a = port_a.6
#bit pwm_1 = port_b.3
#bit pwm_2 = port_b.5
int1 pwm_state=0;
#int_ccp2
void compare2_interrupt_handler(void)
{
if(pwm_state==0)
{
led_a=0;
set_timer3(0);
CCP_2=4096;
setup_ccp2(CCP_COMPARE_SET_ON_MATCH | CCP_USE_TIMER3_AND_TIMER4);
}
else
{
led_a=1;
set_timer3(0);
CCP_2=4096;
setup_ccp2(CCP_COMPARE_CLR_ON_MATCH | CCP_USE_TIMER3_AND_TIMER4);
}
pwm_state=!pwm_state;
}
void main()
{
setup_ccp2(ccp_off);
setup_ccp3(ccp_off);
setup_adc (adc_off);
setup_timer_0(T0_DIV_256 | T0_INTERNAL);
setup_adc_ports(no_analogs);
setup_timer_1 (T1_INTERNAL | T1_DIV_BY_2 ); // ****** Disable timer 1 and problem does not occur. ******
setup_timer_3 (T3_INTERNAL | T3_DIV_BY_2 );
setup_timer_5 (T5_INTERNAL | T5_DIV_BY_2 );
port_a = 0b00000000;
set_tris_a(0b00011111);
port_b= 0b00000000;
set_tris_b(0b10000000);
port_b_pullups(0);
port_c = 0b00000010;
set_tris_c(0b10000000);
set_tris_e(0b00001000);
CCP_2=4096;
set_timer3(0);
setup_ccp2(CCP_COMPARE_SET_ON_MATCH | CCP_USE_TIMER3_AND_TIMER4);
enable_interrupts(int_ccp2);
enable_interrupts(global);
while(1)
{
restart_wdt();
}
}
|
Scope pictures:
https://www.dropbox.com/s/g0f07sxr9ql10z9/scope1.jpg?dl=0
https://www.dropbox.com/s/8ak1ki6k43a73bg/scope2.jpg?dl=0
Many thanks,
Jim |
|
![](templates/subSilver/images/spacer.gif) |
newguy
Joined: 24 Jun 2004 Posts: 1903
|
|
Posted: Fri Sep 09, 2016 7:55 am |
|
|
Does the chip's errata say anything about PWM at all? You might have discovered a chip (silicon) problem. Might be best to open a support ticket with Microchip.
Quite some time ago I found that a documented errata of a dsPIC wasn't quite correct. Even though the errata clearly stated that the documented issue only happened under very specific conditions, it was actually occurring under a slightly broader range of conditions as well. I opened a support ticket with Microchip and they confirmed the issue within a few days' time. |
|
![](templates/subSilver/images/spacer.gif) |
Jim Hearne
Joined: 22 Dec 2003 Posts: 109 Location: West Sussex, UK
|
|
Posted: Fri Sep 09, 2016 8:04 am |
|
|
newguy wrote: | Does the chip's errata say anything about PWM at all? You might have discovered a chip (silicon) problem. Might be best to open a support ticket with Microchip.
Quite some time ago I found that a documented errata of a dsPIC wasn't quite correct. Even though the errata clearly stated that the documented issue only happened under very specific conditions, it was actually occurring under a slightly broader range of conditions as well. I opened a support ticket with Microchip and they confirmed the issue within a few days' time. |
Hi, yes,
I have checked the errata I could find for this chip and it didn't seem to have anything on it relating to the CCP module and the only thing relating to the timers was if they were in asynchronous mode.
http://ww1.microchip.com/downloads/en/DeviceDoc/80000512H.pdf
My feeling also is it may be a silicon problem but i'd like to be sure it's not a compiler or my code issue before I mention it to Microchip.
Many thanks,
Jim |
|
![](templates/subSilver/images/spacer.gif) |
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Fri Sep 09, 2016 8:24 am |
|
|
does this happen if you leave timer1 enabled and shut off the
watchdog code?
also
this does not compile as is
SO where do you define CCP_2 ??
and what is it's purpose ?
( i HOPE as an int16 )
and c'mon here .....
Code: |
#int_ccp2
void compare2_interrupt_handler(void)
{
led_a=pwm_state;
set_timer3(0);
CCP_2=4096;
setup_ccp2(CCP_COMPARE_SET_ON_MATCH | CCP_USE_TIMER3_AND_TIMER4); //THIS LOOKS SUSPECT <<
pwm_state=!pwm_state;
} |
LASTLY since all your timers are setup the same
BUT not synchronously - have you considered what happens when you start zeroing JUST timer3 later in your code?
there has to be more going on in this code than you are showing ( since it won't compile anyway) and sorry but i am more concerned with subtle programmer errata than this chip |
|
![](templates/subSilver/images/spacer.gif) |
Jim Hearne
Joined: 22 Dec 2003 Posts: 109 Location: West Sussex, UK
|
|
Posted: Fri Sep 09, 2016 8:51 am |
|
|
Hi, thank you for your reply.
asmboy wrote: | does this happen if you leave timer1 enabled and shut off the
watchdog code? |
Still the same problem.
Quote: |
this does not compile as is
SO where do you define CCP_2 ??
and what is it's purpose ?
( i HOPE as an int16 )
|
It compiles fine under PCH version 4.130
CCP_2 is the actual compare register for the CCP module.
CCP_2 is declared in the 18F24K22.H CCS header file as:
#word CCP_2 = getenv("SFR:CCPR2L")
Quote: |
setup_ccp2(CCP_COMPARE_SET_ON_MATCH | CCP_USE_TIMER3_AND_TIMER4); //THIS LOOKS SUSPECT <<
|
This is correct as far as I can see, the second half sets which timers the CCPx module uses.
It's in the 18f24K22.h file like this:
Code: | ////////////////////////////////////////////////////////////////// CCP
// CCP Functions: SETUP_CCPx, SET_PWMx_DUTY
// CCP Variables: CCP_x, CCP_x_LOW, CCP_x_HIGH
// Constants used for SETUP_CCPx() are:
#define CCP_OFF 0
#define CCP_CAPTURE_FE 4
#define CCP_CAPTURE_RE 5
#define CCP_CAPTURE_DIV_4 6
#define CCP_CAPTURE_DIV_16 7
#define CCP_COMPARE_SET_ON_MATCH 8
#define CCP_COMPARE_CLR_ON_MATCH 9
#define CCP_COMPARE_INT 0xA
#define CCP_COMPARE_INT_AND_TOGGLE 0x2
#define CCP_COMPARE_RESET_TIMER 0xB
#define CCP_PWM 0xC
#define CCP_PWM_PLUS_1 0x1c
#define CCP_PWM_PLUS_2 0x2c
#define CCP_PWM_PLUS_3 0x3c
//#define CCP_USE_TIMER3 0x100 OBSOLETE, SEE TIMER-3
#word CCP_1 = getenv("SFR:CCPR1L")
#byte CCP_1_LOW = getenv("SFR:CCPR1L")
#byte CCP_1_HIGH = getenv("SFR:CCPR1H")
// The following are used to select the Timer source for the CCP/ECCP
// The first timer is the timer used when in CAPTURE or COMPARE mode
// The second timer is the timer used when in PWM mode
#define CCP_USE_TIMER1_AND_TIMER2 0x0000
#define CCP_USE_TIMER3_AND_TIMER4 0x0100
#define CCP_USE_TIMER5_AND_TIMER6 0x0200
|
Quote: |
LASTLY since all your timers are setup the same
BUT not synchronously - have you considered what happens when you start zeroing JUST timer3 later in your code?
|
I have tried initialising the timers to different values, indeed, in the full project they are deliberately started at different values so the interrupts don't coincide.
Quote: |
there has to be more going on in this code than you are showing ( since it won't compile anyway) and sorry but i am more concerned with subtle programmer errata than this chip |
I think I have addressed all your program concerns.
Many thanks,
Jim |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Sep 09, 2016 10:13 am |
|
|
Quote: | setup_timer_1 (T1_INTERNAL | T1_DIV_BY_2 ); |
You have the Timer1 divisor set to /2. That could be the problem.
The PIC16(L)F1768/1769 errata lists a bug that sounds very similar
to your problem. I know it's a different PIC and the CCP mode in the
errata is different than yours. But sometimes Microchip hasn't found or
published all the silicon bugs that exist. I think they likely re-use silicon
modules across many PIC families. Or at least they use one module as
the basis to design a new one. Therefore bugs can be replicated across
PIC familes.
My suggestion is to try the Method 1 work-around below.
Quote: |
3. Module: ECCP
3.1 Compare Mode
The ECCP Compare Toggle modes
(CCPxCON<3:0> bits = 0010 or 0001) work
properly as long as the Timer1 prescaler value is
configured to 1:1. When the Timer1 prescaler
value is configured to any other value, the ECCP
Compare output yields unexpected results.
Work-arounds -
Method 1:
Only use the Compare Toggle mode when the
Timer1 prescaler value is set to 1:1.
Method 2:
Use CCP Compare mode with pulse output
(CCPxCON<3:0> bits = 1011) to clock a CLC
configured as a J-K flip-flop in Toggle mode. |
|
|
![](templates/subSilver/images/spacer.gif) |
Jim Hearne
Joined: 22 Dec 2003 Posts: 109 Location: West Sussex, UK
|
|
Posted: Mon Sep 12, 2016 5:31 am |
|
|
Hi PCM programmer,
Thank you for your suggestion.
I have tried setting both timer1 only to 1:1 and all 3 timers to 1:1
Unfortunately it has no effect on the problem.
Interestingly slowing timer1 down to 1:8 doesn't seem to make any difference to how often the problem occurs.
So it's just having timer1 enabled that is causing the problem, not it's actual frequency.
I'll send the details to Microchip and see what they have to say.
Many thanks,
Jim |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19368
|
|
Posted: Mon Sep 12, 2016 1:23 pm |
|
|
I'd suspect that during the change from sampling the rising edge to falling edge, the chip is momentarily selecting timer1 (it is the default). If this happens to meet the sampling criteria during this time, you will get a spurious trigger.
Now this is partially because this is a ECCP, which involves several registers being updated.
My suggestion would be to try the following. Read the data sheet and work out the minimum bits that need to change to just change the sampling edge.
Then once the CCP is started, to change the edge, don't use the CCS code, instead manually disable the CCP, and just change the bits that are needed, then re-enable it. If the behaviour changes, then you know you are in the right area..... |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19368
|
|
Posted: Tue Sep 13, 2016 1:09 am |
|
|
Looking at the data sheet, try:
Code: |
#byte CCP2CON=getenv("SFR:CCP2CON")
#bit CLR_ON2 = CCP2CON.0
#int_ccp2
void compare2_interrupt_handler(void)
{
if(CLR_ON2==FALSE)
{
led_a=0;
set_timer3(0);
CCP_2=4096;
CLR_ON2=TRUE; //clear on match
}
else
{
led_a=1;
set_timer3(0);
CCP_2=4096;
CLR_ON2=FALSE; //set on match
}
}
|
This also gets rid of the pwm_state variable (uses the bit in the CCP register, saying which edge to work on). |
|
![](templates/subSilver/images/spacer.gif) |
Jim Hearne
Joined: 22 Dec 2003 Posts: 109 Location: West Sussex, UK
|
|
Posted: Tue Sep 13, 2016 2:29 am |
|
|
Hi Ttelmah,
Thank you very much for doing that, after your previous message I was going to go through it when I got into work this morning, but you've beaten me to it.
The great news is that this does cure the problem.
I'll brush up on my PIC assembly code and try and figure out which bit of the CCS code for the setup_ccp2(CCP_COMPARE_SET_ON_MATCH | CCP_USE_TIMER3_AND_TIMER4); statement upsets things.
Many thanks for your help,
Jim
Ttelmah wrote: | Looking at the data sheet, try:
Code: |
#byte CCP2CON=getenv("SFR:CCP2CON")
#bit CLR_ON2 = CCP2CON.0
#int_ccp2
void compare2_interrupt_handler(void)
{
if(CLR_ON2==FALSE)
{
led_a=0;
set_timer3(0);
CCP_2=4096;
CLR_ON2=TRUE; //clear on match
}
else
{
led_a=1;
set_timer3(0);
CCP_2=4096;
CLR_ON2=FALSE; //set on match
}
}
|
This also gets rid of the pwm_state variable (uses the bit in the CCP register, saying which edge to work on). |
|
|
![](templates/subSilver/images/spacer.gif) |
Jim Hearne
Joined: 22 Dec 2003 Posts: 109 Location: West Sussex, UK
|
|
Posted: Tue Sep 13, 2016 4:11 am |
|
|
Hi All,
After working out what the CCS code for the Setup_ccp2 function was doing the problem becomes apparent, it is as Ttelmah suggested, the source for CCP2 is momentarily set to Timer1 before it is reset to timer3.
Assuming I have understood the assembly correctly, the last few instructions I wasn't familiar with, I think they are new for the PIC 18 chips.
Code: | .................... setup_ccp2(CCP_COMPARE_CLR_ON_MATCH | CCP_USE_TIMER3_AND_TIMER4);
00E6: BSF LATB.LATB3 // bit set LATB3
00E8: MOVLW 09 // W reg=0x09
00EA: MOVWF CCP2CON // CCP2CON = 0x09
00EC: CLRF PWM2CON // PWM2CON = 0x00
00EE: CLRF ECCP2AS // ECCP2AS = 0x00
00F0: MOVLW 01 // W reg = 0x01
00F2: MOVWF PSTR2CON // PSTR2CON = 0x01
00F4: MOVLW E7 // W reg = 0xE7
00F6: MOVLB F // BSR (bank select register) = 0x0F
00F8: ANDWF x49,F // AND W(0xE7) and F = AND W (0xE7 0b11100111) with SFR 0x49 CCPTMRS0 this selects timer 1 for CCP2 !!
00FA: MOVLW 08 // W reg = 0x08
00FC: IORWF x49,F // OR W and F = OR W (0x08 0b00001000) with SFR 0x49 CCPTMRS0 this selects timer 3 for CCP2
|
Would this be classed as a compiler bug ??
It would be better to read the CCPTMRS0 register, do the AND and OR operations and then store the result back in the register.
Rather than working directly on the register.
Can somebody with the latest version of the compiler try the original code and see if this function it still compiles to the same assembly code.
Maybe they have already fixed it, the last version I have is PCWH version 4.130
Many thanks for all the help,
Jim |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19368
|
|
Posted: Tue Sep 13, 2016 7:12 am |
|
|
It's a problematical one.
The supplied function, is doing a 'complete' setup on the registers. Lots of I/O control etc., and then the alternative timer setup as the last operation. They didn't contemplate anyone using the 'toggle' trick, and also wanting to use the alternative timers. Adding code to handle just changing the required bit, then means the routine would no longer be performing the full setup. Perhaps an option to just toggle the edge, as a separate routine, would be the nicest solution.
However this is easy to code yourself, and the the bit change route I've posted is even easier.
The actual design of the ECCP, makes it harder than it really needs to be, since there is not a single bit to disable the ECCP.... |
|
![](templates/subSilver/images/spacer.gif) |
Jim Hearne
Joined: 22 Dec 2003 Posts: 109 Location: West Sussex, UK
|
|
Posted: Tue Sep 13, 2016 7:59 am |
|
|
Hi Ttelmah,
Yes, maybe I am using the function in an unexpected way.
Though, from searching the net to try and find the problem, it doesn't seem uncommon to use the compare function in this way to generate pwm outputs.
Your method of just changing the one bit works perfectly, and means quite a bit less code in the interrupt routine, always good.
Many thanks,
Jim |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19368
|
|
Posted: Tue Sep 13, 2016 8:13 am |
|
|
Good.
Just updated.
I've posted to CCS, suggesting that it would be rather nice to add a new option to the setup_ccp function:
setup_ccp(CCP_CHANGE_TRIGGER_EDGE);
Which should just do this. Allowing the edge to be changed without having to set the other registers.
Hopefully they will consider this a worthwhile suggestion. |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|