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

set_pwm_duty()->Please explain some things

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



Joined: 03 Nov 2010
Posts: 2

View user's profile Send private message

set_pwm_duty()->Please explain some things
PostPosted: Wed Nov 03, 2010 6:54 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Nov 03, 2010 9:08 pm     Reply with quote

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. Rolling Eyes
Ttelmah



Joined: 11 Mar 2010
Posts: 19545

View user's profile Send private message

PostPosted: Thu Nov 04, 2010 3:08 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Nov 04, 2010 4:32 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Nov 04, 2010 7:15 am     Reply with quote

Ttelmah wrote:
Not quite.


Thanks for the clarification. I got it bass ackwards! Laughing
Ttelmah



Joined: 11 Mar 2010
Posts: 19545

View user's profile Send private message

PostPosted: Thu Nov 04, 2010 9:15 am     Reply with quote

We can all do that (sometimes....) Very Happy

Best Wishes
Ttelmah



Joined: 11 Mar 2010
Posts: 19545

View user's profile Send private message

PostPosted: Thu Nov 04, 2010 9:21 am     Reply with quote

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
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