View previous topic :: View next topic |
Author |
Message |
Diode
Joined: 27 Jul 2012 Posts: 35
|
DSPIC30F2020 PWM problem |
Posted: Mon Feb 03, 2014 12:39 pm |
|
|
// Programming skills: beginner
// Compiler: 4.105
Currently I'm trying to get pwm working on a 30F2020 which isn't as easy as I expected it to be. Below my test code:
Code: |
#include<30F2020.h>
#FUSES NOWDT //No Watch Dog Timer
#FUSES NOWRTB //Boot block not write protected
#FUSES NOCPB //No Boot Block code protection
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOWRT //Program memory not write protected
#FUSES FRC_PLL //Internal Fast RC oscillator with PLL
#FUSES NOCKSFSM //Clock Switching is disabled, fail Safe clock monitor is disabled
#FUSES FRANGE_HIGH //Frequency Range for FRC 14.55MHz
#FUSES NOOSCIO //OSC2 is clock output
#FUSES NOPR //Pimary oscillaotr disabled
#FUSES NOWINDIS //Watch Dog Timer in Window mode
#FUSES WPRES128 //Watch Dog Timer PreScalar 1:128
#FUSES WPOSTS16 //Watch Dog Timer PostScalar 1:32768
#FUSES PUT128 //Power On Reset Timer value 128ms
#FUSES NODEBUG //No Debug mode for ICD
#FUSES ICSP1 //ICD uses PGC1/PGD1 pins
#use delay(clock=58200000) // =14.55MHZ *4 (interne rc oscillator)
void main()
{
setup_compare(1,COMPARE_PWM | COMPARE_TIMER2 );
setup_timer2(TMR_INTERNAL | TMR_DIV_BY_8,0 );
setup_compare(2,COMPARE_PWM | COMPARE_TIMER3 );
setup_timer3(TMR_INTERNAL | TMR_DIV_BY_8,0 );
setup_spi( FALSE );
setup_wdt(WDT_ON);
while (true)
{
output_high(PIN_e4);
Delay_ms(10);
output_low(PIN_e4);
Delay_ms(10);
set_pwm_duty(1,231);
set_pwm_duty(2,231);
}
}
|
Pin E4 is for testing purposes and I see a square wave on this pin, indicating that the PIC is running.
I'm not sure on which pin the PWM signal should occur. In an example I found here for another controller pwm1 should be on OC1 but in my case it is constant 5V.
The goal is to get a phase shift controller so I want to be able to adjust the phase shift between the two pwm channels. Sadly there isn't much information in the manual/help file. |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Mon Feb 03, 2014 3:32 pm |
|
|
CCS assumes that you have CCS manual, microchip manual and appropriate header files to hand. You often need all three.
Microchip manual gives E0/1 for PWM1 outputs, E2/3 for PWM2.
You've not set a period for either timer.
Hope this helps.
Mike |
|
|
Diode
Joined: 27 Jul 2012 Posts: 35
|
|
Posted: Tue Feb 04, 2014 8:02 am |
|
|
Thanks for your comment Mike. You are totally right, I forgot to set a period for each timer, quite dumb
I now have set it to a frequency of about 28.5 kHz and I have a PWM signal at F6 and D0.
The E0 up to E3 are for the power PWM I believe.
Anyway, I now have two pwm signals. I tried to phase shift them by starting them a few microseconds after each other but that doesn't work. So the next problem is how to create a phase shift.
In the microchip manual I have read about a phase shift register which can be set . Perhaps I need to figure out how I can set registers with CCS.
I have looked in the compiler help and at a manual I found on Internet but the: setup_compare(1,COMPARE_PWM | COMPARE_TIMER2 ); command isn't described in both of them.
The header file is the 30f2020.h file I assume? I don't get much wiser reading that file neither. |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Tue Feb 04, 2014 8:33 am |
|
|
I don't use your PIC, so I'm guessing a little.
You're using two timers, for each PWM.
As I understand it the PWMs are driven by their timer.
The PWMs are, in effect, sync'd to the timers.
To phase shift the PWM's you could start one timer then the other after a delay.
The power PWM's (motor PWM's) are designed for a more controlled phase shift.
You could tweak the PWM phase by incrementing one timer's period, let it overflow once, then decrementing that timer's period back to its previous value.
Mike |
|
|
Diode
Joined: 27 Jul 2012 Posts: 35
|
|
Posted: Tue Feb 04, 2014 8:57 am |
|
|
Hi Mike,
I tried to set the one pwm duty after the other but setting the timer with a delay sounds quite logic. Will give it a try.
I just was reading the datasheet and came to the conclusion that the power-pwm have a phase shift function. So that is probably the correct way to go I guess.
Haven't used power pwm before so that is all new to me. But always eager to learn something new! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19539
|
|
Posted: Tue Feb 04, 2014 9:20 am |
|
|
The duty won't change the phase.
The duty only updates when the PWM next resets. This is done so that multiple PWM's will always update together. Mike's comment is spot on.
Basically reset one timer, wait for the time required for your phases, then reset the other.
Best Wishes |
|
|
Diode
Joined: 27 Jul 2012 Posts: 35
|
|
Posted: Tue Feb 04, 2014 10:08 am |
|
|
I have tried Mike his option to delay the timer and that works indeed. But as mentioned before, the power pwm should have a function for setting the phase. So I want to try that option too. But sadly the manual doens't describe anything about it. |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Tue Feb 04, 2014 10:52 am |
|
|
Quote: | The header file is the 30f2020.h file I assume? I don't get much wiser reading that file neither.
So I want to try that option too. But sadly the manual doens't describe anything about it. |
Sorry, meant to say this before. The .h file gives you all the allowed options etc. for the compiler with the correct syntax.
In general the options follow the microchip format, so you can usually work out what each one is supposed to do.
With very recent chips there may be bugs or CCS has not got round to it. Either way you will have to write directly to the registers.
Mike |
|
|
Diode
Joined: 27 Jul 2012 Posts: 35
|
|
Posted: Tue Feb 04, 2014 11:01 am |
|
|
Mike,
For example: _bif void set_pwm_duty(unsigned int8 module, unsigned int16 duty);
This is mentioned in the 30f2020.h file.
I can't find anything about phase so I may assume that there is no option to directly adjust the phase shift?
Is there an explanation around on how to set the registers directly?
According to the datasheet it is register PHASE but how to tell what phase I need? |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Tue Feb 04, 2014 11:11 am |
|
|
I don't have the PCD compiler.
In previous versions, writing directly to registers was done with either #bit or #byte.
Both are described in the CCS manual. I would expect there to be something similar for PCD.
Mike
EDIT
I've just had a quick look in the PCD reference manual. Both #bit and #byte are there.
Yesterday, I also had look at the power PWM module in the Microchip manual.
There's rather a large number of registers to get right. Could take some time. |
|
|
Diode
Joined: 27 Jul 2012 Posts: 35
|
|
Posted: Tue Feb 04, 2014 12:53 pm |
|
|
I appreciate your help, thanks for that!
I will read the manual and datasheet and see how things will go. Will get back here with the results within a few days. |
|
|
Diode
Joined: 27 Jul 2012 Posts: 35
|
|
Posted: Wed Feb 05, 2014 3:11 am |
|
|
I'm experimenting with writing registers but I'm not sure if I write the registers correctly.
On page 144 of the datasheet the power supply register map is given. I want to write into the PTCON register which has address 0400. Bit 15 enables the pwm module so I want to force this to "1".
I try this as shown in the code below: Code: |
#include<30F2020.h>
#FUSES NOWDT //No Watch Dog Timer
#FUSES NOWRTB //Boot block not write protected
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOWRT //Program memory not write protected
#FUSES FRC_PLL //Internal Fast RC oscillator with PLL
#FUSES NOCKSFSM //Clock Switching is disabled, fail Safe clock monitor is disabled
#FUSES FRANGE_HIGH //Frequency Range for FRC 14.55MHz
#FUSES NOOSCIO //OSC2 is clock output
#FUSES NOPR //Pimary oscillaotr disabled
#FUSES NOWINDIS //Watch Dog Timer in Window mode
#FUSES WPRES128 //Watch Dog Timer PreScalar 1:128
#FUSES WPOSTS16 //Watch Dog Timer PostScalar 1:32768
#FUSES PUT128 //Power On Reset Timer value 128ms
#FUSES NODEBUG //No Debug mode for ICD
#FUSES ICSP1 //ICD uses PGC1/PGD1 pins
#use delay(clock=58200000) // =14.55MHZ *4 (interne rc oscillator)
#byte PTCON = 0x0400 //Declare address of register PTCON
#byte PWMCON1 = 0x0408
#byte Phase1 = 0x0410
#byte Phase2 = 0x0424
void main()
{
setup_compare(1,COMPARE_PWM | COMPARE_TIMER2 );
setup_timer2(TMR_INTERNAL | TMR_DIV_BY_1,1024 );
setup_compare(2,COMPARE_PWM | COMPARE_TIMER3 );
setup_timer3(TMR_INTERNAL | TMR_DIV_BY_1,1024 );
setup_spi( FALSE );
setup_wdt(WDT_ON);
set_pwm_duty(1,0);
set_pwm_duty(2,0);
PTCON = 0x8000; //Enable PWM module
PWMCON1 = 0x100;
while (true)
{
set_pwm_duty(1,512);
delay_us(150);
set_pwm_duty(2,512);
Phase1 = 0x0800;
Phase2 = 0x0800;
}
} |
First I assign the address 0400 to the variable PTCON with:
#byte PTCON = 0x0400 //Declare address of register PTCON
Then I want to enable the PWM module by:
PTCON = 0x8000; //Enable PWM module
Is this the way to go?
Anyone which can point me in the right way? |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Wed Feb 05, 2014 4:12 am |
|
|
To control just one bit of a register its safer to use the #BIT option.
Writing to a complete register runs the risk of fouling up something else within that register.
In the case you're quoting just define PTEN as PTCON bit 15.
Then:-
PTEN = 1 ; // Enables
PTEN = 0 ; // Disables
The #BYTE is best for setting registers which count or hold compare values etc.
Say the MDC or PDCx, in the case where you are wanting to set all the bits at one time.
You can check on what is being written to registers with MPLABSIM.
Might be an idea to look at what the CCS compiler does with the registers when you set up the PWM.
Also Microchip does provide some sample code in the data sheet. That could be a useful guide as to which registers to set up.
Or you may find exactly what you want on Microchips website.
Best of luck.
Mike |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19539
|
|
Posted: Wed Feb 05, 2014 8:32 am |
|
|
The phase registers are 16bit registers, so should be set with #word, not #byte
Use getenv - safer.
#word PHASE1=getenv("SFR:PHASE1")
Then for PTEN:
#bit PTEN=getenv("BIT:PTEN")
No need to look up addresses etc...
You need to setup the PWM, to use multi-phase mode, or the phase registers will be ignored.
Best Wishes |
|
|
Diode
Joined: 27 Jul 2012 Posts: 35
|
|
Posted: Wed Feb 05, 2014 1:44 pm |
|
|
Many thanks to both of you!
I now have PWM1 working on a frequency of 26kHz and I'm able to change the PWM frequency during my program. So the begin is there.
The functions Ttelmah gave work quite easily once you know that they exist. I never knew that you could "call" the registers by name, I thought that you needed to write the actual address of the register.
It makes it all much clearer.
See if I can get PMW2 working as well and then I can try if the phase shift does work. I find it enough for today.
Thanks again and I will keep you posted about the progress. |
|
|
|