• AVR Freaks

Newbie: controlling duty cycle of PWM set up with MCC

Page: << < ..678910.. > >> Showing page 10 of 14
Author
SGK
Senior Member
  • Total Posts : 158
  • Reward points : 0
  • Joined: 2018/05/14 13:55:08
  • Location: 0
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/07/04 15:30:47 (permalink)
0
FWIW I tried to implement the 'tiny' printf linked to in post 173.  I received compiler errors wherever const was used in printf.c. For example:
 
      const char digit = (char)(value % base);
 
printf.c:690: error: (188) constant expression required
 
Oh well. I was thinking, while larger, such a printf version would have more general use and save a lot of 'specific' coding.  I will look again at Paul's 'trick'.
 
On the float/integer point, it's not having only integer precision as to temperatures that bothers me but rather I have a working algorithm for setting PWM/duty cycle values, 9 'buckets' from the 50% DC limit to Over_Temp less 10C, which I am somewhat reluctant to revisit. That requires float. Maybe I should just look at it again. The code seems to do everything I require at this stage with 97% memory usage.  However, the PCB is more flexible and could allow for an I2C breakout board, for communication to a keypad and LCD display, and control over 2 more switches (which could totally replace the Sestos B3S-2R-24 timer the project currently uses).  Doing any of this would require more efficient memory use. 
 
 
 
 
qɥb
Monolothic Member
  • Total Posts : 3332
  • Reward points : 0
  • Joined: 2017/09/09 05:07:30
  • Location: Jupiter
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/07/04 15:51:34 (permalink)
0
The printf implementation in XC8 is pretty good.
It goes to a lot of effort to only include support for formats that you actually use. Don't use floating point, and it won't include that part.
Floating point is the lazy man's way of doing the job. Almost any embedded application can be done more efficiently with integers when properly analysed.

This forum is mis-configured so it only works correctly if you access it via https protocol.
The Microchip website links to it using http protocol. Will they ever catch on?
PicForum "it just works"
SGK
Senior Member
  • Total Posts : 158
  • Reward points : 0
  • Joined: 2018/05/14 13:55:08
  • Location: 0
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/07/04 16:15:15 (permalink)
0
Ok.  I will try to avoid being lazy. :) So I understand how computation in C works... In the following example
 
a = b + c/d + e/f

 
where each of b, c, d, e and f are integers, is the computation done with 'full' precision and the result truncated to an integer returned as 'a' or is c/d and e/f computed only to integer precision and added to b? (I understand that I can multiply all right-side terms by 10 and then divide 'a' by 10 for better precision but before doing so I'm wondering if I 'need' to.)
qɥb
Monolothic Member
  • Total Posts : 3332
  • Reward points : 0
  • Joined: 2017/09/09 05:07:30
  • Location: Jupiter
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/07/04 16:48:04 (permalink)
0
If all the variables are integers, then ALL the calculations are done using integer arithmetic.
C does not use extra precision for the progressive calculations.
 

This forum is mis-configured so it only works correctly if you access it via https protocol.
The Microchip website links to it using http protocol. Will they ever catch on?
PicForum "it just works"
PStechPaul
Super Member
  • Total Posts : 2558
  • Reward points : 0
  • Joined: 2006/06/27 16:11:32
  • Location: Cockeysville, MD, USA
  • Status: online
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/07/04 20:05:54 (permalink)
+1 (1)
The only function where you "need" to use float appears to be:
//Calculate temp at an NTC in degrees Celsius
float readNTC(adc_channel_t channel)
{
    int ADC_value = ADC_GetConversion(channel);
    float rNTC   =   NTC_Balance_Resistor * ((Max_ADC / ADC_value)-1);
    float Temp    =   ((NTC_Beta * Room_TempK) / (NTC_Beta + (Room_TempK * log(rNTC / Res_Room_Temp)))) - 273.15;
    return Temp;
}

You might be able to implement the log() function by means of a look-up table with interpolation. If you do not really need to accommodate different thermistors with unique NTC_Beta and Res_Room_Temp entered by the user, you could use a LUT for Temp. And, simplest of all, you could use a LUT to get PWM value directly from rNTC by pre-calculating the values. Since you have only 9 "buckets", or discrete PWM values for a range of temperatures, you could just use an "if..else if" structure, or maybe a switch statement, to do this.
if( rNTC > 10000 )
  CCPR_Val = 9; // Temperature less than room temperature, 50% duty cycle
else if (rNTC > 6946)
  CCPR_Val = 11; // 60% duty cycle at 35C
else if (rNTC > 4936)
  CCPR_Val = 13; // 70% duty cycle at 45C
else if (rNTC > 3582)
  CCPR_Val = 15; // 80% duty cycle at 55C
Duty_Cycle = (CCPR_Val+1)*5;

You could have the rNTC values as an array, for each 5 degrees, which would look like:
int rNTC[] = {10000, 8309, 6946, 5840, 4936, 4195, 3582, 3073, 2649, 2293};


 
SGK
Senior Member
  • Total Posts : 158
  • Reward points : 0
  • Joined: 2018/05/14 13:55:08
  • Location: 0
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/07/05 07:07:04 (permalink)
+1 (1)
I think I have found enough middle ground for now. First, changing the algorithm for duty cycle and CCPR was actually a little easier in integer: no need to determine if round() had rounded up or down (and no use of round() saved some space as well).
 

 
int Temp_Increment = (Over_Temp - 10 - DC50_Limit)*100/9.0;
int Adj_Temp = (Fan_Temp - DC50_Limit)*100/Temp_Increment;
CCPR_Val = Adj_Temp + 10;
Duty_Cycle = (CCPR_Val + 1) * 5;

 
Secondly - and hopefully I haven't screwed this up - I left the calculation of temp the same (i.e. done in float) but returned the answer as an integer.
 

 
//Calculate temp at an NTC in degrees Celsius
int readNTC(adc_channel_t channel)
{
uint16_t ADC_value = ADC_GetConversion(channel);
float rNTC = NTC_Balance_Resistor * (Max_ADC / ADC_value - 1);
float Temp = NTC_Beta * Room_TempK / (NTC_Beta + (Room_TempK * log(rNTC / Res_Room_Temp))) - 273.15;
return Temp;
}

 
If I round Temp before returning it as an integer for better accuracy increases use of the math library and costs 4% memory consumption.
 
With that, temperatures everywhere else are treated in integer format:
 

 
int Temp_NTC1=25;
int Temp_NTC2=25;
int Temp_NTC3=25;
int Temp_NTC4=25;
char Keyboard_Input;
int Fan1_DC;
int Fan2_DC;

int readNTC(adc_channel_t channel); //Declare functions
int Set_Duty_Cycle(int Fan_Num, int Fan_Temp);
void Send_String(const char *x);
void Send_Welcome(void);
void Send_Programming_String(void);
void Send_Temps_DC(int Temp1, int Temp2, int Temp3, int Temp4, int DC1, int DC2);
void Program_Constants(void);

Send_Welcome(); //Send welcome to RS232 connected PC

while (1) //MAIN LOOP
{

Temp_NTC1=readNTC(NTC1); //Read temperatures
Temp_NTC2=readNTC(NTC2);
Temp_NTC3=readNTC(NTC3);
Temp_NTC4=readNTC(NTC4);

int High_Temp_Fan1=0; //Calculate max temp of NTC pairs
if (Temp_NTC1>=Temp_NTC2){
High_Temp_Fan1=Temp_NTC1;}
else
High_Temp_Fan1=Temp_NTC2;

int High_Temp_Fan2=0;
if (Temp_NTC3>=Temp_NTC4){
High_Temp_Fan2=Temp_NTC3;}
else
High_Temp_Fan2=Temp_NTC4;

Fan1_DC = Set_Duty_Cycle(1,High_Temp_Fan1); //Set duty cycle CCPR values and return duty cycles
Fan2_DC = Set_Duty_Cycle(2,High_Temp_Fan2);

 
most importantly in the Send_Temps_DC printf functions.
 

 
void Send_Temps_DC(int Temp1, int Temp2, int Temp3, int Temp4, int DC1, int DC2)
{
Send_String("Temperatures in degrees Celsius\n");
printf("NTC1 %d\n", Temp1);
printf("NTC2 %d\n", Temp2);
printf("NTC3 %d\n", Temp3);
printf("NTC4 %d\n\n", Temp4);
Send_String("Duty cycles in per cent.\n");
printf("Fan 1 %d\n", DC1);
printf("Fan 2 %d\n\n\n\n", DC2);
}

 
That drops my program memory consumption to 54%.  If I haven't screwed it up that's a lot smarter with no loss of flexibility and only very modest loss of 'accuracy'.
post edited by SGK - 2018/07/05 07:11:05
SGK
Senior Member
  • Total Posts : 158
  • Reward points : 0
  • Joined: 2018/05/14 13:55:08
  • Location: 0
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/07/25 16:33:41 (permalink)
0
Hey guys. I'm testing my board and noticed I only get 2.8V peak (logic high) on pin 17 CCP3 versus an expected circa 5V. Pin 8 CCP4 operates as expected with respect the logic high voltage.  Any ideas why this might be the case?
 
Also, my 'scope is showing a duty cycle of 45% (logic high) rather than 50%. In my code the CCPR values are initialised at 9 which MPLAB MCC shows is a duty cycle of 50%. (PWM resolution of 4 bits.) My code is reporting a Duty Cycle of 50% meaning the CCPR value is 9.  Both scope and MCC can't be right....
 
('Scope agrees with the 25kHz PWM frequency.)
 
I'd post scope pics but it seems I can only link images via a URL here and not upload them to the forum's server. (Dropbox removed their functionality to share images with anyone via URL and I haven't had a need to replace it until now.)
 

//Set CCPR value for duty cycle and return Duty Cycle
int Set_Duty_Cycle(int Fan_Num, int Fan_Temp)
{
int CCPR_Val = 9;
int Duty_Cycle = 50;
if (Fan_Temp > DC50_Limit){
if (Fan_Temp >= (Over_Temp - 10)) {
CCPR_Val = 19;
Duty_Cycle = 100;
}
else {
int Temp_Increment = (Over_Temp - 10 - DC50_Limit)*100/9.0;
int Adj_Temp = (Fan_Temp - DC50_Limit)*100/Temp_Increment;
CCPR_Val = Adj_Temp + 10;
Duty_Cycle = (CCPR_Val + 1) * 5;
}
}
switch (Fan_Num){
case '1': PWM4_LoadDutyValue(CCPR_Val);
break;
case '2': PWM3_LoadDutyValue(CCPR_Val);
break;
}

return (Duty_Cycle);
}

mbrowning
USNA79
  • Total Posts : 1674
  • Reward points : 0
  • Joined: 2005/03/16 14:32:56
  • Location: Melbourne, FL
  • Status: online
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/07/25 17:13:59 (permalink)
+1 (1)
only get 2.8V peak (logic high) on pin 17

clearly shorted to another signal, or very strong pull-down
 
9/19 = 47.4% duty cycle - close to 45%. 10/19 = 52.6%.
Or maybe 100% is really 20, so 9/20=45.0%
SGK
Senior Member
  • Total Posts : 158
  • Reward points : 0
  • Joined: 2018/05/14 13:55:08
  • Location: 0
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/07/25 18:18:43 (permalink)
0
Yes a 27k pull down resistor is measuring 98R.  Clearly I fried it somehow. 
 
In MCC Easy Setup you enter a duty cycle % and it derives the CCPR value. I see that 47% yields a CCPR of 8 while 48% yields 9.  0% => 0 and 98% and above yields 19. So I still don't see how a CCPR value of 9 generates a measured 44.8%. Either way it seems the result returned in MCC Easy Setup is wrong. I'd like to know the correct possible values for CCPR (confirm 0-19?) and the duty cycles each relates to.
qɥb
Monolothic Member
  • Total Posts : 3332
  • Reward points : 0
  • Joined: 2017/09/09 05:07:30
  • Location: Jupiter
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/07/25 18:21:10 (permalink)
0
What is the PR value?
You can't derive duty cycle from CCPR alone, it depends upon PR as well.
 

This forum is mis-configured so it only works correctly if you access it via https protocol.
The Microchip website links to it using http protocol. Will they ever catch on?
PicForum "it just works"
SGK
Senior Member
  • Total Posts : 158
  • Reward points : 0
  • Joined: 2018/05/14 13:55:08
  • Location: 0
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/07/25 18:51:02 (permalink)
0
??
 
Timer settings:
post scaler 1:1
prescaler 1:16 => 40uS 25kHz
 
Clock is INTOSC 8MHz
qɥb
Monolothic Member
  • Total Posts : 3332
  • Reward points : 0
  • Joined: 2017/09/09 05:07:30
  • Location: Jupiter
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/07/25 19:12:40 (permalink)
0
If the timing is coming from Timer#2, then the name of the "PR" register is "PR2".
The timer period is
Fosc/4/Prescale/Postscale/(PR2+1)
so
PR2 = (Fosc/Prescale/Postscale/25khz)-1
= (8MHz/16/1/25kHz)-1
= 19
That means there are 20 timer counts in each period (0 to 19)
Duty cycle = CCPR/period = 9/20 = 0.45 = 45% which is what your scope reports.
I think the "(CCPR_Val + 1) * 5" formula is wrong, the "+1" should not be in there.
 
Edit: Formula correction
Fosc/4/Prescale/(PR2+1)
so
PR2 = (Fosc/4/Prescale/25khz)-1
= (8MHz/4/16/25kHz)-1
= 4
 
post edited by qɥb - 2018/07/26 13:16:08

This forum is mis-configured so it only works correctly if you access it via https protocol.
The Microchip website links to it using http protocol. Will they ever catch on?
PicForum "it just works"
SGK
Senior Member
  • Total Posts : 158
  • Reward points : 0
  • Joined: 2018/05/14 13:55:08
  • Location: 0
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/07/25 19:29:08 (permalink)
0
Thanks. The +1 was required to align the CCPR value and duty cycle figures reported in MCC CCP3 (and CCP4) Easy Setup under "Duty Cycle". CCPR is initialised there by entering a duty cycle figure in %. I wanted to initialise at 50% duty cycle and hence CCPR was set to 9 by MCC.  Clearly this is a bug in MCC.
 
This is my first attempt at using PWM to drive a fan.  One other thing surprised me. The current draw from my bench PSU with a fan connected to my board and (presumably) operating at 45% duty cycle (I can only measure the voltage at the gate of the MOSFET driver) was 0.27A. When I connected the fan directly to the 12V bench PSU the current draw was 0.3A. The board with no fans connected barely registers on the ammeter, perhaps 10mA. I was expecting a far greater differential in fan current draw from 100% duty vs 45% duty, perhaps not double but closer thereto. I'm wondering why I was wrong in my expectation.
qɥb
Monolothic Member
  • Total Posts : 3332
  • Reward points : 0
  • Joined: 2017/09/09 05:07:30
  • Location: Jupiter
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/07/25 19:36:24 (permalink)
0
Have you posted a schematic of your circuit?
I suspect your power transistor is taking a fair while to turn off.

This forum is mis-configured so it only works correctly if you access it via https protocol.
The Microchip website links to it using http protocol. Will they ever catch on?
PicForum "it just works"
SGK
Senior Member
  • Total Posts : 158
  • Reward points : 0
  • Joined: 2018/05/14 13:55:08
  • Location: 0
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/07/25 19:58:00 (permalink)
0
I'm away from my computer at the moment but the MOSFET is a VN3205N8-G. Turn off delay and fall time combined are about 50nS if I recall correctly and the device is meant to have low input capacitance.  Circuit (for this part) is simply relevant PIC pin connected to gate of VN3205 and 27k ohms to ground (possibly unnecessary). 12V to fan, drain of FET connected to fan return and source connected to GND.  I need to poke around a bit more tomorrow. 
PStechPaul
Super Member
  • Total Posts : 2558
  • Reward points : 0
  • Joined: 2006/06/27 16:11:32
  • Location: Cockeysville, MD, USA
  • Status: online
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/07/25 20:02:31 (permalink)
0
The formula for PWM period is [PR+1]*4*tOsc*PS. So for PR=19 and PS=16 and 8 MHz, that comes to:
 
20*4*125*16 = 160 uSec => 6.67 kHz. I think the PS may be 4, to get your 25 kHz.
 
The duty cycle is (4*CCPRxL+CCPxCON<5:4>) / 4*(PR+1). So for PR=19 and CCPRval=9:
 
duty cycle = 36 / 80 = 0.45
 
This assumes that CCPxCON<5:4> is zero and CCPRval => CCPRxL. They are initialized to zero on startup.

 
qɥb
Monolothic Member
  • Total Posts : 3332
  • Reward points : 0
  • Joined: 2017/09/09 05:07:30
  • Location: Jupiter
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/07/25 20:27:08 (permalink)
0
PStechPaul
The formula for PWM period is [PR+1]*4*tOsc*PS. So for PR=19 and PS=16 and 8 MHz, that comes to:
 
20*4*125*16 = 160 uSec => 6.67 kHz. I think the PS may be 4, to get your 25 kHz.

Agreed.
I got that first, then remembered about the two extra bits available to PWM, then applied the x4 factor in the wrong spot.
So yes, PR2=4, for 5 clock cycles.
The PWM uses two bits from the prescaler to allow compare values from 0 to 19

This forum is mis-configured so it only works correctly if you access it via https protocol.
The Microchip website links to it using http protocol. Will they ever catch on?
PicForum "it just works"
SGK
Senior Member
  • Total Posts : 158
  • Reward points : 0
  • Joined: 2018/05/14 13:55:08
  • Location: 0
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/07/26 09:36:19 (permalink)
0
I'm struggling... and feeling rather stupid as a result. 
 
I'm trying to relate your formulae and shorthand variable references to what I see in MCC and here:
 
http://umassamherstm5.org/tech-tutorials/pic32-tutorials/pic32mx220-tutorials/pwm
 
When I setup MCC I chose a clock of INTOSC and 8Mhz in the System Module (Easy Setup). I need to use TM2 and selected 1:1 Postscaler and 1:16 Prescaler there. Also, I chose a Timer Period of 40uS to get a frequency of 25kHz. In CCP3 I merely set the mode to PWM, make sure the timer is Timer 2 and set a duty cycle for the PWM.  CCPR3 value is then calculated by MCC (erroneously it appears). I don't set PR anywhere but I can observe that the uppermost value for CCPR3 is 19 (by setting duty cycle to 100%). 
 
Where does the your factor *4 come from?
 
The reference above has: PWM period = (PR+1) x TPB x PS = 20 x 125 x 16 = 40uS or 25kHz 
 
If I look at the register values in the Timer2 setup I see PR2 = 0x4. 
 
I presume PWM requires first to relate how many (8MHz) clock cycles are in a PWM period to get to the desired frequency (rather than 8MHz) and how many of those 8Mhz cycles should be on versus off. While I don't understand exactly what the prescaler is doing I can make the leap of faith that if I want 25kHz, a period of 40uS, I need 320 8Mhz cycles divided by the impact of a 16:1 prescaler = 20.  So I would have thought PWM could generate an "on-state" ranging from none through to all 20 of those 16x scaled 8MHz cycles being on (duty cycle being just the ratio of 'on' to total periods). If CCPRx is how we set the number of (scaled) clock cycles that are 'on' is there not 21 possible values: 0 to 20? 
 
 
*********
 
I probed the drain of the Microchip Supertex VN3025N8-G and it is showing the correct on/off switching (45% duty cycle, 25kHz).  So I'm not sure why there isn't as distinct a difference in current draw as I was expecting.  The 120mm fan certainly blasts along (and the build will have two going next to each other - one blowing into a radiator and the other driving air into the enclosure more generally). I think I might alter the program so that the fans are just on at 25C and below (say, 5% DC so I at least know they're working) and have them step up from there as temps rise. 
SGK
Senior Member
  • Total Posts : 158
  • Reward points : 0
  • Joined: 2018/05/14 13:55:08
  • Location: 0
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/07/26 10:17:37 (permalink)
0
Register CCPxCON has a value of 0x1C when CCP Mode is set to PWM. [CCP3M = PWM and DC3B = 0x1]
 
If CCPR is initialised at 9 (by setting duty cycle to 50%) CCPRxL is set to 0x2. 
 
post edited by SGK - 2018/07/26 10:20:22
PStechPaul
Super Member
  • Total Posts : 2558
  • Reward points : 0
  • Joined: 2006/06/27 16:11:32
  • Location: Cockeysville, MD, USA
  • Status: online
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/07/26 12:19:47 (permalink)
+1 (1)
The example in the reference you supplied is for a PIC32 device, which uses the system clock for PWM. PIC16 devices use the instruction clock which is fOsc/4.
 
You may want to make sure you have a commutating diode across the fan to reduce inductive spikes at turn-off. Also make sure the fans are meant to have speed controlled by PWM. If they are BLDC they may have an internal speed regulator. Also, feeding them with unfiltered PWM may cause the circuitry to respond to the peak voltage. Maybe try a capacitor across the fans, although that will cause high current spikes when the PWM voltage is applied to the capacitor.
 
[edit] I thought you might be using just CCPRxL and ignoring the CCPxCON LSB bits to make things easier. If you don't need fine precision for PWM, that will work quite well. But it seems you are setting the full CCPR (2*4+1), for 50%, although it really should be set to 10 for 50% duty cycle.
post edited by PStechPaul - 2018/07/26 12:38:30

 
Page: << < ..678910.. > >> Showing page 10 of 14
Jump to:
© 2020 APG vNext Commercial Version 4.5