![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
kgng97ccs
Joined: 02 Apr 2022 Posts: 97
|
Choice of timers for different frequencies in #use PWM |
Posted: Mon Jun 27, 2022 8:30 pm |
|
|
We are using the PIC18LF46K22, CCS PCWHD compiler v5.078, and MPLAB IDE v8.92.
We used the "#use PWM" directive for two different frequencies, monitored all the PWM pins with a logic analyzer, and observed an unexpected behavior.
For the following code, PWM1, PWM3, and PWM4 worked (the analyzer showed the correct signals), but PWM5 did not. Even when we swapped the positions of the PWM4 and PWM5 lines, it was still the PWM5 that did not work. Code: | …
#fuses CCP3E0
…
#use pwm(PWM1, timer=2, frequency=125kHz, duty=50, pwm_off, stream=PWM1_LF1)
#use pwm(PWM3, timer=2, frequency=125kHz, duty=50, pwm_off, stream=PWM3_LF2)
#use pwm(PWM4, timer=4, frequency=38kHz, duty=25, pwm_off, stream=PWM4_IR1)
#use pwm(PWM5, timer=4, frequency=38kHz, duty=25, pwm_off, stream=PWM5_IR2) |
However, when we swapped the timers, all the PWMs worked: Code: | …
#fuses CCP3E0
…
#use pwm(PWM1, timer=4, frequency=125kHz, duty=50, pwm_off, stream=PWM1_LF1)
#use pwm(PWM3, timer=4, frequency=125kHz, duty=50, pwm_off, stream=PWM3_LF2)
#use pwm(PWM4, timer=2, frequency=38kHz, duty=25, pwm_off, stream=PWM4_IR1)
#use pwm(PWM5, timer=2, frequency=38kHz, duty=25, pwm_off, stream=PWM5_IR2) |
Is there any explanation for this behavior?
It seems that assigning a lower timer number to a lower frequency works, but I could not find anything in the datasheet that would suggest we need to do this.
I will appreciate any comments or suggestions. Thank you. |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9174 Location: Greensville,Ontario
|
|
Posted: Tue Jun 28, 2022 5:59 am |
|
|
When you say 'it did not work', do you mean ZERO signal output ,or the wrong waveform ?
It shouldn't matter which timer (2,4, 6) you use, according to the datasheet they are identical.
two ideas.
1) the chip is 'defective', maybe an 'errata' for that batch of PICs ? Would have to look at Microchips website to see what 'errata' there are .
2) possible compiler 'bug' ? dump the listing, decode the assembler ,to see if maybe some bit of some register is not being properly set/reset
Since you should be able to use any of those 3 timers, maybe code and test if timer6 works or fails ?
Hopefully others will respond who have seen this before. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19369
|
|
Posted: Tue Jun 28, 2022 6:22 am |
|
|
This is a data sheet one. Surprising though that the compiler didn't
complain. If you look at CCP1, 2 & 3, these can select timer 1, 3 or 5
(register 14-3). However CCP4 & 5 can select timer 2, 4 or 6. (register
14-4). So the problem is actually with trying to select timer 2 for PWM1
and PWM3. The chip just cannot do this!... |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9174 Location: Greensville,Ontario
|
|
Posted: Tue Jun 28, 2022 7:36 am |
|
|
and yet he said those worked .....
or did I misread what he posted ?
... the older I get the easier I get confused..
![Confused](images/smiles/icon_confused.gif) |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19369
|
|
Posted: Tue Jun 28, 2022 9:43 am |
|
|
I think the compiler is "trying it's best", and probably swapping some of the
timer requests, but when he gets to the last line, because it has swapped
timers it then can't satisfy the timer 4 request on the last line.
When he does them with the timers swapped (which is then legal), it works.
It is not the order, but the timers being asked for that is causing the problem. |
|
![](templates/subSilver/images/spacer.gif) |
kgng97ccs
Joined: 02 Apr 2022 Posts: 97
|
|
Posted: Wed Jun 29, 2022 1:06 am |
|
|
Thank you, Jay and Ttelmah, for your comments.
Yes, “it did not work” means there was no signal at the PWM5 pin. Sorry I should have clarified that in my post. For the PWMs that worked (1, 3, and 4), the logic analyzer was able to capture the signals and display them on the computer screen. I tested all these PWMs several times.
I did find an errata document for the PIC18LF46K22 chip https://ww1.microchip.com/downloads/en/DeviceDoc/80000514J.pdf, but could not find anything related to PWM.
I have the impression from page 201 of the datasheet, under “REGISTER 14-3: CCPTMRS0” and “REGISTER 14-4: CCPTMRS1”, that CCP1 to CCP5 can use Timer 2, 4, or 6 in PWM modes (as Jay also highlighted), but Timer 1, 3, or 5 in Capture/Compare modes. So I assumed that I should be able to use timer2 for one frequency and timer4 for another frequency in the "#use PWM" directive.
I did further tests, including with timer6 (as Jay suggested), and observed the following:
All the PWMs worked with this code (timer2 for 125 kHz, timer6 for 38 kHz): Code: |
#fuses CCP3E0
…
#use pwm(PWM1, timer=2, frequency=125kHz, duty=50, pwm_off, stream=PWM1_LF1)
#use pwm(PWM3, timer=2, frequency=125kHz, duty=50, pwm_off, stream=PWM3_LF2)
#use pwm(PWM4, timer=6, frequency=38kHz, duty=25, pwm_off, stream=PWM4_IR1)
#use pwm(PWM5, timer=6, frequency=38kHz, duty=25, pwm_off, stream=PWM5_IR2) |
All the PWMs worked with this code (timer6 for 125 kHz, timer2 for 38 kHz): Code: | …
#fuses CCP3E0
…
#use pwm(PWM1, timer=6, frequency=125kHz, duty=50, pwm_off, stream=PWM1_LF1)
#use pwm(PWM3, timer=6, frequency=125kHz, duty=50, pwm_off, stream=PWM3_LF2)
#use pwm(PWM4, timer=2, frequency=38kHz, duty=25, pwm_off, stream=PWM4_IR1)
#use pwm(PWM5, timer=2, frequency=38kHz, duty=25, pwm_off, stream=PWM5_IR2) |
None of the PWMs worked with this code (timer4 for 125 kHz, timer6 for 38 kHz): Code: | …
#fuses CCP3E0
…
#use pwm(PWM1, timer=4, frequency=125kHz, duty=50, pwm_off, stream=PWM1_LF1)
#use pwm(PWM3, timer=4, frequency=125kHz, duty=50, pwm_off, stream=PWM3_LF2)
#use pwm(PWM4, timer=6, frequency=38kHz, duty=25, pwm_off, stream=PWM4_IR1)
#use pwm(PWM5, timer=6, frequency=38kHz, duty=25, pwm_off, stream=PWM5_IR2) |
None of the PWMs worked with this code (timer6 for 125 kHz, timer4 for 38 kHz): Code: | …
#fuses CCP3E0
…
#use pwm(PWM1, timer=6, frequency=125kHz, duty=50, pwm_off, stream=PWM1_LF1)
#use pwm(PWM3, timer=6, frequency=125kHz, duty=50, pwm_off, stream=PWM3_LF2)
#use pwm(PWM4, timer=4, frequency=38kHz, duty=25, pwm_off, stream=PWM4_IR1)
#use pwm(PWM5, timer=4, frequency=38kHz, duty=25, pwm_off, stream=PWM5_IR2) |
For all the tests, I checked the PWM timer selection control registers with the following code (I do not know how to analyze the lst file as I am not familiar with assembly language):
Code: | printf("CCPTMRS0 = %X\n", getenv("SFR:CCPTMRS0"));
printf("CCPTMRS1 = %X\n", getenv("SFR:CCPTMRS1")); |
All the PWM settings gave the same register values:
CCPTMRS0 = 0x49 (binary 0100 1001) — which suggests that PWM1 and PWM3 always use timer4 (PWM2 too).
CCPTMRS1 = 0x48 (binary 0100 1000) — which suggests that PWM4 always uses timer2, and PWM5 always uses timer6.
So, I tried the following code to correspond to these register values, and all the PWMs worked: Code: | …
#fuses CCP3E0
…
#use pwm(PWM1, timer=4, frequency=125kHz, duty=50, pwm_off, stream=PWM1_LF1)
#use pwm(PWM3, timer=4, frequency=125kHz, duty=50, pwm_off, stream=PWM3_LF2)
#use pwm(PWM4, timer=2, frequency=38kHz, duty=25, pwm_off, stream=PWM4_IR1)
#use pwm(PWM5, timer=6, frequency=38kHz, duty=25, pwm_off, stream=PWM5_IR2) |
So, it seems that there is some irregularity in the way the "#use PWM" directive operates.
The good thing is that at least I know which PWM settings work.
Correction:
The above printf statements for CCPTMRS0 and CCPTMRS1 are not correct. See my post dated July 2, 2022.
Last edited by kgng97ccs on Fri Jul 01, 2022 11:05 am; edited 2 times in total |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9174 Location: Greensville,Ontario
|
|
Posted: Wed Jun 29, 2022 5:43 am |
|
|
AND so do we !!!
Thanks for doing all the testing !!
I like your 'using PIC to display the registers' trick !
As a 'dinosuar', I just dump listing, write the register data on graph paper to decode the bits.
It sounds like there may be a 'bug' in the USE PWM(..). If so, send CCS the info, they can figure it out and update the compiler. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19369
|
|
Posted: Wed Jun 29, 2022 8:07 am |
|
|
I must admit, I never use #use PWM.
I want to know how many bits genuinely are available to me, and will select
the frequencies myself to ensure I get the resolution I need.
A thought though did occur to me, which ought to get rid of the oddities.
Consider not using #use for the second setup in the pairs.
So something like:
Code: |
#use pwm(PWM1, timer=2, frequency=125kHz, duty=50, pwm_off, stream=PWM1_LF1)
#use pwm(PWM4, timer=4, frequency=38kHz, duty=25, pwm_off, stream=PWM4_IR1)
void main()
{
setup_ccp2(CCP_PWM | CCP_USE_TIMER1_AND_TIMER2);
set_pwm2_duty(80L);
setup_ccp5(CCP_PWM | CCP_USE_TIMER3_AND_TIMER4);
set_pwm2_duty(256L);
|
This way the second PWM in the pair 'inherits' the timer settings already
made by the #use. |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jun 29, 2022 8:29 am |
|
|
The compiler reports those stats in the build window. This line:
Code: | #use pwm(PWM4, timer=4, frequency=38kHz, duty=25, pwm_off, stream=PWM4_IR1) |
shows this report:
Quote: | More info: PWM period: 26.38 us, Frequency: 37.915 kHz, Resolution: 10.00 bits
|
|
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19369
|
|
Posted: Wed Jun 29, 2022 10:13 am |
|
|
OK for nice values like this, but for the 125K one it says 7.32 bits. If 10 bits
is 0 to 1023, so the answer is (2^10)-1 as you would expect. However
the result for 7.32 bits would be 158, and if we assume a 20MHz clock
(which this suggests), 159, would be the right value.
So you end up having to check the calculation. Might as well do it yourself
the first time.... |
|
![](templates/subSilver/images/spacer.gif) |
kgng97ccs
Joined: 02 Apr 2022 Posts: 97
|
|
Posted: Fri Jul 01, 2022 10:33 am |
|
|
Thank you, Ttelmah and PCM Programmer, for your comments.
To set the record right for the sake of readers, I would like to make a correction to the above printf statements (thanks to Ttelmah; post dated July 1, 2022; https://www.ccsinfo.com/forum/viewtopic.php?t=59734&postdays=0&postorder=asc&start=30):
Original statements (which were wrong): Code: | printf("CCPTMRS0 = %X\n", getenv("SFR:CCPTMRS0"));
printf("CCPTMRS1 = %X\n", getenv("SFR:CCPTMRS1")); |
Corrected statements: Code: | printf("CCPTMRS0 = %X\n", *(getenv("SFR:CCPTMRS0")));
printf("CCPTMRS1 = %X\n", *(getenv("SFR:CCPTMRS1"))); |
With the corrected statements, some settings in the registers still do not match those in the “#use PWM” directive.
Just as an example, I will use this combination (for which PWM5 did not work): Code: | …
#fuses CCP3E0
…
#use pwm(PWM1, timer=2, frequency=125kHz, duty=50, pwm_off, stream=PWM1_LF1)
#use pwm(PWM3, timer=2, frequency=125kHz, duty=50, pwm_off, stream=PWM3_LF2)
#use pwm(PWM4, timer=4, frequency=38kHz, duty=25, pwm_off, stream=PWM4_IR1)
#use pwm(PWM5, timer=4, frequency=38kHz, duty=25, pwm_off, stream=PWM5_IR2) | Results:
CCPTMRS0 = 0x00 (binary 0000 0000), which suggests that both PWM1 and PWM3 use timer2 (same as in “#use PWM” timer settings), according to page 201 of datasheet.
CCPTMRS1 = 0x09 (binary 0000 1001), which suggests that PWM4 uses timer4 (same), but PWM5 uses timer6 (different). |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19369
|
|
Posted: Sun Jul 03, 2022 11:44 pm |
|
|
If you think about it, using #use PWM, with the same required output
frequency, and shared timer, is quite a complex thing to ask for. The #USE
is obviously having issues sharing the timer for any timer other than timer2.
I think really CCS need to offer a 'shared timer' setup for the #USE PWM.
So allow you to specify like:
Code: |
#use pwm(PWM1, timer=2, frequency=125kHz, duty=50, pwm_off, stream=PWM1_LF1)
#use pwm(PWM3, SHARED_TIMER=PWM1, duty=50, pwm_off, stream=PWM3_LF2)
#use pwm(PWM4, timer=4, frequency=38kHz, duty=25, pwm_off, stream=PWM4_IR1)
#use pwm(PWM5, SHARED_TIMER=PWM4, duty=25, pwm_off, stream=PWM5_IR2)
|
I'll email CCS, suggesting they look into a setup like this.
The point would be that the 'SHARED_TIMER' syntax, would imply that
both the timer, and frequency should match what is specified for the
other PWM, getting rid of the need for the compiler to 'spot' this sharing.
I'll suggest this to them. ![Smile](images/smiles/icon_smile.gif) |
|
![](templates/subSilver/images/spacer.gif) |
kgng97ccs
Joined: 02 Apr 2022 Posts: 97
|
|
Posted: Mon Jul 04, 2022 4:25 am |
|
|
Thank you, Ttelmah, for the suggestion. Yes, it will be good ask CCS to look into it.
Last week I e-mailed Technical Support at CCS, asking them to look into the issues discussed in this thread (I gave them the link).
Hopefully, CCS will come up with a resolution soon. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19369
|
|
Posted: Mon Jul 04, 2022 5:31 am |
|
|
The manual talks about sharing with Timer2 (which is the one you found
worked OK), but seems vague about sharing with another timer.
I think they need to add an explicit option for this....
Perhaps the syntax should be:
Code: |
#use pwm(PWM1, timer=2, frequency=125kHz, duty=50, pwm_off, stream=PWM1_LF1)
#use pwm(PWM3, SHARED_TIMER=2 duty=50, pwm_off, stream=PWM3_LF2)
#use pwm(PWM4, timer=4, frequency=38kHz, duty=25, pwm_off, stream=PWM4_IR1)
#use pwm(PWM5, SHARED_TIMER=4 duty=25, pwm_off, stream=PWM5_IR2) |
|
|
![](templates/subSilver/images/spacer.gif) |
kgng97ccs
Joined: 02 Apr 2022 Posts: 97
|
|
Posted: Thu Jul 07, 2022 1:13 am |
|
|
CCS has come back with a response (dated 2022-07-05), reproduced here with permission from CCS:
"The issue you're having is because of an error in the compiler when assigning the timers to use for the CCP4 and CCP5 peripherals for the PIC18FxxK22 device family. I have corrected the issue and the fix will be in the next compiler release we do. You can work around the problem in your version of the compiler by using timer 2 for CCP4 and CCP5 and putting their #use pwm() lines before the other #use pwm() lines, for example:
Code: | #use pwm(PWM4, timer=2, frequency=38kHz, duty=25, pwm_off, stream=PWM4_IR1)
#use pwm(PWM5, timer=2, frequency=38kHz, duty=25, pwm_off, stream=PWM5_IR2)
#use pwm(PWM1, timer=4, frequency=125kHz, duty=50, pwm_off, stream=PWM1_LF1)
#use pwm(PWM3, timer=4, frequency=125kHz, duty=50, pwm_off, stream=PWM3_LF2) | Unquote.
Actually, this combination is also one of the combinations that I tested earlier that worked.
In addition, it seems, from my testing, that the order of the "#use PWM" lines does not affect the results. That is, any order will work as long as timer2 is associated with 38 kHz and timer4 is associated with 125 kHz. The CCPTMTS0 (=0x41) and CCPTMTS1 (=0x00) registers gave the same values showing the correct timer assignments, and I was able to see the PWM signals at all four PWM pins.
I look forward to the updated compiler version. |
|
![](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
|