View previous topic :: View next topic |
Author |
Message |
epo
Joined: 03 Nov 2010 Posts: 2
|
set_pwm_duty()->Please explain some things |
Posted: Wed Nov 03, 2010 6:54 pm |
|
|
Hello!
I have a problem - I don't understand how does this function actually work in this compiler(4.104). I would imagine that it accepts long int values (10-bit max resolution). BUT searching the forum (to get my 16F690 running) for several times I have found answers form PCM Programmer that it only accepts 8-bit values (some mystical 8-bit mode and long int mode by adding L at the end of the parameter). I am referring for example to this thread.
So I looked at the assembler code (generated) and there it was... My misunderstanding. When the parameter (value of the duty cycle) is larger than 255 everything seems fine - the CCPR1L register is written and the CCP1CON bits 4&5 are written. BUT then when the parameter is smaller than 255 this value is put to CCPR1L as is - no shifting no nothing. I imagined that to get those low duty cycles I have to write the LSBs first not the MSBs (maybe I don't understand everything).
So what do I don't understand correctly (I am really only a student who does this for the very first time)? Please explain!
// At some point I even started to think that the parameter at the set_pwm_duty() is not the "duty*4*(PR2+1)" but only something that relates to the value in PR2. Is it?
Thank you!
Code: |
// I test this by dimming an LED
void main()
{
setup_timer_2(T2_DIV_BY_1, 199, 1); // sets the PWM freq to 10kHz (@8MHz internal osc)
//199 should be the PR2 value
my_setup_ccp1(CCP_PWM); // this function initializes PWM on F690 (found it on this forums - default built in function doesn't work)
Loop:
set_pwm1_duty(800); // Callculating in accordance with Microchip's datasheet this should be 100%
delay_ms(1000);
set_pwm1_duty(0); //0%
delay_ms(1000);
set_pwm1_duty(100); //12.5%
delay_ms(1000);
set_pwm1_duty(200); //25%
delay_ms(1000);
set_pwm1_duty(300); //37.5 //In the reality this makes the LED dimmer than @ 25% (???)
delay_ms(1000);
goto Loop;
} |
|
|
|
newguy
Joined: 24 Jun 2004 Posts: 1909
|
|
Posted: Wed Nov 03, 2010 9:08 pm |
|
|
This is one of the weird things about CCS that will make you pull your hair out....try :
Code: | set_pwm1_duty(300L); |
The "L" forces the compiler to treat the constant as a long (int16). As it is, coding
Code: | set_pwm1_duty(300); |
Is equivalent to:
Code: | set_pwm1_duty((int8)300); |
Unless you specify the L to force the compiler to treat the number as a long, it will essentially cast it to an int8, which can only hold values from 0-255. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19551
|
|
Posted: Thu Nov 04, 2010 3:08 am |
|
|
Not quite.
The 'point' is that the set_pwm_duty function, has two modes of operation. If it receives an int8, it only updates the 8bit register holding the upper 8bits of the PWM duty. If however it receives an int16, it rotates the value right by two bits, and updates the register, then transfers the original low two bits into the extra two bits stored in the CCPxCon register. This obviously requires more work, but gives 10bit operation.
Hence as newguy says, you need to explicitly 'pass' a 16bit value.
However his examples are then not quite right....
set_pwm1_duty(300);
_Will_ update the full 10bit value. Because the constant is >255, the compiler 'knows' it is an int16. So, 'no' it does _not_ behave as if this value is cast to an int8.
The problem comes when the value is <=255.
set_pwm1_duty(256);
Will put 64 into the duty cycle register, and 0 into the extra two bits into DCxB1 and DCxB0. 10bit mode.
But:
set_pwm1_duty(255);
Will put 255 into the duty cycle register, and not change DCxB0/B1, as the code 'switches' to using 8bit update mode, and will give 4* the value expected from working with the 10bit value.
So, 'right', except that the behaviour _only_ appears with values <256.
Normally, provided you update the value with a variable, there is no problem, and in fact the 'fast update' offered by using the 8bit values can be useful.
Best Wishes |
|
|
epo
Joined: 03 Nov 2010 Posts: 2
|
|
Posted: Thu Nov 04, 2010 4:32 am |
|
|
Thank you - I think I am starting to see a light at the end !
So do I understand correctly?:
My problem is that when I write set_pwm1_duty(200) compiler treats this as 8-bit value and doesn't bother updating LSBs in the CCP1CON register? So I should write set_pwm1_duty(200L) ??? To force it to accept this 200 as an int16 value? Will it work?
To be honest - I am just playing around to understand what actually happens inside. I find the manual very brief and I can't understand everything right away.
Still I don't understand why does setup_CCP1(PWM) doesn't work on the 16F690.
Thanks once again! |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1909
|
|
Posted: Thu Nov 04, 2010 7:15 am |
|
|
Ttelmah wrote: | Not quite. |
Thanks for the clarification. I got it bass ackwards! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19551
|
|
Posted: Thu Nov 04, 2010 9:15 am |
|
|
We can all do that (sometimes....)
Best Wishes |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19551
|
|
Posted: Thu Nov 04, 2010 9:21 am |
|
|
epo wrote: | Thank you - I think I am starting to see a light at the end !
So do I understand correctly?:
My problem is that when I write set_pwm1_duty(200) compiler treats this as 8-bit value and doesn't bother updating LSBs in the CCP1CON register? So I should write set_pwm1_duty(200L) ??? To force it to accept this 200 as an int16 value? Will it work?
To be honest - I am just playing around to understand what actually happens inside. I find the manual very brief and I can't understand everything right away.
Still I don't understand why does setup_CCP1(PWM) doesn't work on the 16F690.
Thanks once again! |
Yes, you need the 'L'.
On the 690, it depends on the compiler version. On reasonably 'new' compilers the standard function _does_ work OK. However this chip contains an 'ECCP', as opposed to just a 'CCP', and this needs to be 'turned down' to run as a CCP. On some compiler versions, this is not handled for you, and the peripheral only works if you use the more complex ECCP function....
The replacement function correctly handles the peripheral.
Best Wishes |
|
|
|