|
|
View previous topic :: View next topic |
Author |
Message |
johnl
Joined: 30 Sep 2003 Posts: 120
|
PWM from the data sheet |
Posted: Tue Feb 23, 2016 1:25 pm |
|
|
I cannot get the proper duty cycle out. The period, as calculated by (PR+1)/Clock = 16384/32,000,000 = 512uS is correct on the scope. (I am trying to get 14 bits resolution at 2KHz.)
However, if I try any DC greater than 255, no output. At 255 it's about 8%.
Compiler v5.055
Code: |
#include <16f1765.h>
#define RAND_MAX 63
#include <stdlib.h>
#fuses INTRC_IO,NOWDT,PUT,MCLR,PROTECT,NOBROWNOUT, PLLEN,NODEBUG,NOLVP,
#use delay(clock = 32000000)
#byte PWM5PRH = 0xD96
#byte PWM5PRL = 0xD95
#byte PWM5DCH = 0xD94
#byte PWM5DCL = 0xD93
#byte PWM5CON = 0xD9B
#byte PWM5CLKCON = 0xD9E
#byte RC2PPS = 0xEA2
#byte PWM5PHL = 0xD91
#byte PWM5PHH = 0xD92
void main(void)
{
int X;
port_a_pullups(TRUE);
port_c_pullups(TRUE);
set_tris_c(0);
PWM5PRH = 0x3F;
PWM5PRL = 0xFF;
PWM5DCH = 0x1F; // 1FFF ----> 50% DC
PWM5DCL = 0xFF; // (doesn't work - low output)
PWM5CON = 0x80;
PWM5CLKCON = 0x0; // Fosc source
RC2PPS = 0x10; //PWM5 out on C2
PWM5PHL = 0x0;
PWM5PHH = 0x0;
while(1)
{
output_toggle(PIN_C3); //chip is alive. Instruction clock = 8 MHz
//verified on scope
delay_cycles(250); delay_cycles(250);
delay_cycles(250); delay_cycles(250);
}
}
|
|
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9243 Location: Greensville,Ontario
|
|
Posted: Tue Feb 23, 2016 3:22 pm |
|
|
Have to ask why not use the CCS functions for this ??
Jay |
|
|
johnl
Joined: 30 Sep 2003 Posts: 120
|
|
Posted: Tue Feb 23, 2016 3:29 pm |
|
|
temtronic wrote: | Have to ask why not use the CCS functions for this ??
Jay |
I have to say I couldn't get them to work. I intended my post to ask how to go from the working code from the registers to the CCS functions, but apparently I didn't get that far!
I did not see how to read the data sheet, read the include file, read the CCS manual and make the logical connections. For example, the include file only has a couple of parameter defines for the #use PWM directive. There was no answer there on how to set it up. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9243 Location: Greensville,Ontario
|
|
Posted: Tue Feb 23, 2016 4:06 pm |
|
|
When you have your program open, pressing F11 should open and display the CCS manual. Usually there's enough info to figure it out. There are a few examples in the 'example's folders, though I can't specifically say which one.
Jay |
|
|
johnl
Joined: 30 Sep 2003 Posts: 120
|
|
Posted: Tue Feb 23, 2016 4:23 pm |
|
|
I did give the manual a try. I think part of the problem is that there are 2 PWM modules on this chip: a 10 bit and a 16 bit. I'm trying to get the 16 bit to work. I believe it is a fairly new chip, so I didn't run across any good examples.
If I could find out what is wrong with my register approach, it might be easier to use the functions.
Thanks. |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Tue Feb 23, 2016 5:14 pm |
|
|
i am quite anxious about fuse "PLLEN,"
combined withh your use_delay at 32mhz -
does your .LST file show the right setup ?......
as to the 10 vs 16 bit PWM
10 bit pwm should be possible at up to 40khz or so
also be sure to CAST your values passed to the CCS set_pwm() function
as int16 or LONG else an 8 bit quantity may be all you CAN set in 10 bit space.
you need to READ and think about the 16F1765.h header file under
heading SETUP_PWM ()
i think it will get you farther along than the quasi assembler you attempt.
also consider that the part in question is very NEW and CCS support could be less than robust. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19540
|
|
Posted: Wed Feb 24, 2016 1:57 am |
|
|
Some general comments:
First, much easier and safer to write to 16bit registers, by using #word, and writing 16bit values, than trying to write to the bytes separately. Then use the getenv function to get the register addresses. They look right, but far too easy for one to be wrong. So:
#word PWM5PR=getenv("SFR:PWM5PRL")
gives you a 16bit register PWM5PR that can be written to with 16bit values.
The PPS register is much easier controlled just using #pin_select. Look at the top of the processor include file (33 lines down), and you will find a little table giving the pins that can be used, and the peripherals that can be fed to them.
#PIN_SELECT PWM5=PIN_C2
or whatever pin you want.
Then the key is that the higher PWM's do not use the standard PWM functions. They are not CCP based, and have different capabilities and values (including things like phase control), so have their own suite of functions to control them:
setup_pwm5(PWM_STANDARD | PWM_CLK_FOSC | PWM_CLK_DIV_BY_1);
To give a basic PWM without special abilities (except for the larger counter used).
set_pwm5_period() then sets the period register, and
set_pwm5_duty() the duty register.
As has been said before, you have to treat the processor include file, as 'part of the documentation'. It gives the pin select details, and also the syntax and values available for the pwm controls.
One other comment added. port_x_pullups(TRUE) is wrong.
There are two versions of this function, depending on the chip. Chips that only allow the pullups to be on/off, use TRUE/FALSE to enable them. Chips that have individual pullups require a mask value for the pullups.
As a further comment, always debug, with protection _off_. Only enable it once you have working code. With it enabled, the programmer has to perform a full erase of the chip (which uses an extra life on the EEPROM), every time you change anything.
Also you want NOPPS1WAY.
You code to write to the PPS register won't be working at all. To change the PPS, you have to perform an unlock sequence first. The compiler knows to do this.
Code: |
#include <stdlib.h>
#fuses INTRC_IO,NOWDT, PUT, MCLR, NOPROTECT,NOBROWNOUT, NODEBUG, NOLVP
#fuses NOPPS1WAY
#use delay(INTERNAL = 32000000)
#PIN_SELECT PWM5=PIN_C2 //select the PWM 5 pin
void main(void)
{
port_a_pullups(0xFF); //8 bit mask required
port_c_pullups(0xFF);
set_tris_c(0);
setup_pwm5(PWM_STANDARD | PWM_CLK_FOSC | PWM_CLK_DIV_BY_1);
set_pwm5_period(0x3FFF);
set_pwm5_duty(0x1FFF);
while(TRUE)
{
output_toggle(PIN_C3); //chip is alive. Instruction clock = 8 MHz
delay_us(125);
}
}
|
|
|
|
johnl
Joined: 30 Sep 2003 Posts: 120
|
|
Posted: Wed Feb 24, 2016 9:59 am |
|
|
Thank you, Ttelmah (and asmboy.)
As mentioned, my thinking was to work with the registers directly at first (to learn about the PWM module) and then use the CCS functions.
Actually there was something flaky about writing the duty cycle registers directly, as you pointed out in general for writing 16 bit values. When I used the duty cycle function, set_pwm5_duty(7000); everything worked.
However, I tried
#word PWM5DC = getenv("SFR:PWM5DCL")
then PWM5DC = 7000;
but that did not work.
Ttelmah, thank you for all your valuable comments, which I will go over.
One question:
Why doesn't the PLLEN fuse need to be set or is it better to use #delay like you did? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19540
|
|
Posted: Wed Feb 24, 2016 10:25 am |
|
|
Quite a few of the similar chips, don't allow the PLL fuse to enable the PLL, when in INTOSC mode. It has to be enabled in software after the code starts. This one does accept the fuse, so it doesn't matter. However using the INTOSC=xx form, the compiler knows which method has to be used, and automatically handles this if necessary... |
|
|
johnl
Joined: 30 Sep 2003 Posts: 120
|
|
Posted: Wed Feb 24, 2016 11:36 am |
|
|
Something is still flaky.
First time I compiled your code (after putting in the #include <16f1765.h> line), it worked perfectly.
However, now it doesn't. I still get the square wave out of C3, but the PWM output is solid low. Tried changing chips and also the PWM output pin.
Once in a while reprogramming it works, but not often. I'm new to MPLABX, so maybe I'm overlooking something. Any ideas?
Code: | //Source "B"
#include <16f1765.h>
#include <stdlib.h>
#fuses INTRC_IO,NOWDT, PUT, MCLR, NOPROTECT,NOBROWNOUT, NODEBUG, NOLVP
#fuses NOPPS1WAY
#use delay(INTERNAL = 32000000)
#PIN_SELECT PWM5=PIN_C2 //select the PWM 5 pin
void main(void)
{
port_a_pullups(0xFF); //8 bit mask required
port_c_pullups(0xFF);
set_tris_c(0);
setup_pwm5(PWM_STANDARD | PWM_CLK_FOSC | PWM_CLK_DIV_BY_1);
set_pwm5_period(0x3FFF);
set_pwm5_duty(0x1FFF);
while(TRUE)
{
output_toggle(PIN_C3); //chip is alive. Instruction clock = 8 MHz
delay_us(125);
}
} |
Last edited by johnl on Wed Feb 24, 2016 2:24 pm; edited 1 time in total |
|
|
johnl
Joined: 30 Sep 2003 Posts: 120
|
|
Posted: Wed Feb 24, 2016 1:15 pm |
|
|
I just restarted MPLABX, programmed a chip and the PWM worked as expected. Reprogrammed the same chip and PWM stopped outputting, though the toggling on pin C3 always works.
Switched to the following code which worked 5 times in a row on three different chips. Compiler bug?
Code: | //Source "A"
#include <16f1765.h>
#define RAND_MAX 63
#include <stdlib.h>
#fuses INTRC_IO,NOWDT,PUT,MCLR,NOPROTECT,NOBROWNOUT, PLLEN,NODEBUG,NOLVP,
#use delay(clock = 32000000)
#byte PWM5PRH = 0xD96
#byte PWM5PRL = 0xD95
#byte PWM5DCH = 0xD94
#byte PWM5DCL = 0xD93
#byte PWM5CON = 0xD9B
#byte PWM5CLKCON = 0xD9E
#byte RC2PPS = 0xEA2
#byte PWM5PHL = 0xD91
#byte PWM5PHH = 0xD92
#word PWM5DC = getenv("SFR:PWM5DCL")
////#use pwm(pwm5, output=PIN_C2, period=32000000,pwm_on)
///
void main(void)
{
int X;
port_a_pullups(0b11111);
port_c_pullups(0b11111);
set_tris_c(0);
setup_adc(ADC_OFF);
PWM5PRH = 0x3F;
PWM5PRL = 0xFF;
PWM5DCH = 0; //0x1F; // 1FFF ----> 50% DC
PWM5DCL = 0xFF;
PWM5CON = 0x80;
PWM5CLKCON = 0x0; // Fosc source
RC2PPS = 0x10; //PWM5 out on C2
PWM5PHL = 0x0;
PWM5PHH = 0x0;
set_pwm5_duty(7000);
//
while(1)
{
output_toggle(PIN_C3); //chip is alive. Instruction clock = 8 MHz
delay_cycles(250);
delay_cycles(250); delay_cycles(250); delay_cycles(250);
}
}
|
Last edited by johnl on Wed Feb 24, 2016 2:23 pm; edited 2 times in total |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9243 Location: Greensville,Ontario
|
|
Posted: Wed Feb 24, 2016 1:32 pm |
|
|
OK I don't use that PIC or MPLABX but
when you reprogram the PIC do you also recompile? If so, dump the listing.Recompiling the same code MUST give you the SAME listing. If it doesn't something is wrong.
Now if the listings are identical, maybe it's an MPLABX bug?
You should be able to read back the PIC hex code into MPLAB and compare with the original. They should be the same, if not MPLABX is altering it.
Maybe an environmental issue? How's the humidity, dry ?? static could be a problem. What programmer are you using ? That may have PSU issues ? 'erratic' or 'random' running problems are hard to debug. I see....
1) source code : if this never changes then compiled code shouldn't
2) compiled code : see 1
3) PIC : if PICs are all same batch, all should be the same
4) compiler :dump listing to see if code is correct
5) IDE MPLABX : might be setup wrong for that PIC
6) programmer : same as 5
7) operating setup : static, power, ???
maybe a few other 'things' to consider
Jay |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19540
|
|
Posted: Wed Feb 24, 2016 1:35 pm |
|
|
You can't have a period of 32MHz from the PWM.
Use a possible value.
Then your PPS code still won't actually be working. The PPS register has to be unlocked before you can write to it.
Remember MPLAB defaults to debug mode and this will override some settings.
More likely an MPLAB problem.... |
|
|
johnl
Joined: 30 Sep 2003 Posts: 120
|
|
Posted: Wed Feb 24, 2016 2:57 pm |
|
|
I just built and programmed 3 chips in a row using "Source A" above. All 3 chips ran as expected.
Then I did the same for 3 chips with 'Source B" above. Only 1 of the 3 worked.
I made sure MPLABX was not compiling for debug mode, however, I see both a .COF and .HEX files in the output folder, both with the same timestamp. I am not sure which file is getting programmed. MPLABX seems to have taken a lot of control away and has automated tasks more.
temtronic, what do you or others use for the programmer and environment? I am not fond of MPLABX at this point.
Ttelmah, The period is 3FFF which is 2^14-1. If I want 14 bit resolution, don't I need that? From the datasheet, the period is (PR+1)/CLK = 16384/32,000,000 = 512uS which is what I see on the scope. The duty cycle is the DC register/ (PR+1). So I need to be able to specify a 14 bit number in the numerator. I don't understand what you mean by 32MHz period. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19540
|
|
Posted: Wed Feb 24, 2016 3:36 pm |
|
|
You'd tried to use #use PWM. With a period of 32MHz... |
|
|
|
|
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
|