|
|
View previous topic :: View next topic |
Author |
Message |
Oleg_S
Joined: 08 May 2012 Posts: 6
|
pic18f pwm initialization |
Posted: Tue May 08, 2012 3:11 pm |
|
|
hi,
first of all I want to say thank you for this community. I've learned much from your posts.
And now is my project: I am going to build 3 phase pwm sinewave generator for step-up transformer. I have 3 outputs from the microcontroller wich will drive mosfet half-bridge each (trough a driver). Primary windings of the transformer will be connected (star) so 3 half-bridges should be enough (i hope).
I use pic18f47j13 (just because i have it on a prototype board and because it has enough ECCP modules). But I struggle to do initial settings in C. I expected it would be easier in C but I suspect CCS have done everything to confuse a user - the variables and settings in *.h file difficult to understand end there is no explanation for that. I can't reference some CCS terms of the *.h file to the Microchip Datasheet:
Code: |
CCP_PWM_PLUS_1
CCP_PWM_PLUS_2
CCP_PWM_PLUS_3
CCP_PWM_H_H
CCP_PWM_H_L
CCP_PWM_L_H
CCP_PWM_L_L
CCP Variables: CCP_x, CCP_x_LOW, CCP_x_HIGH
|
What are they? And how do you know that?
I would appreciate any help with understanding CCS terms and PWM settings. I'd like to set the period of PWM to 16kHz or higher. This is my code. Do I have to set timers here?
Code: |
#include <18F47J13.h>
#device adc=12 // right/left 16/12 justified
#FUSES ADC10 // ADC is 10/12-bits
#FUSES NOWDT // No Watch Dog Timer
#FUSES WDT128 // Watch Dog Timer uses 1:128 Postscale
#FUSES STVREN // Stack full/underflow will not cause reset
#FUSES NOXINST // Extended set extension and Indexed Addressing mode disabled (Legacy mode)
#FUSES INTRC_IO //Internal RC Osc, no CLKOUT
#FUSES SOSC_DIG // Digital mode, I/O port functionality of RC0 and RC1
#FUSES NOCLOCKOUT
#FUSES NOFCMEN // Fail-safe clock monitor disabled
#FUSES NOIESO // Internal External Switch Over mode disabled
#FUSES RTCOSC_INT // RTCC uses Internal 31KHz Oscillator as reference source
#FUSES NODSBOR // BOR disabled in Deep Sleep
#FUSES NODSWDT // Deep Sleep Watchdog Timer disabled
#FUSES NOWPFP // Write/Erase Protect Page
#use delay(int=8000000)
#CASE // case sensitive compiler
#PIN_SELECT RX2 = PIN_A0 // remap rx2 to pin
#PIN_SELECT TX2 = PIN_A1 // remap tx2 to pin
#use rs232(uart2, baud=38400, parity=N, xmit=PIN_A1, rcv=PIN_A0, bits=8)
#USE FAST_IO(A) // let user decide when set and clear tris_x
#USE FAST_IO(B) // let user decide when set and clear tris_x
#USE FAST_IO(D) // let user decide when set and clear tris_x
#USE FAST_IO(E) // let user decide when set and clear tris_x
#define phase_a PIN_C1
#define phase_b PIN_C6
#define phase_c PIN_C7
void main() {
//setup_oscillator(OSC_32MHZ|OSC_INTRC|OSC_PLL_ON);
set_tris_a(0b00001001); // pin A3= Vbat, A1=TX, A0=RX
set_tris_b(0b00000000);
set_tris_d(0b00000000);
set_tris_e(0b00000000);
setup_ccp8(CCP_PWM|CCP_USE_TIMER1_AND_TIMER6);
setup_ccp9(CCP_PWM|CCP_USE_TIMER1_AND_TIMER4);
setup_ccp10(CCP_PWM|CCP_USE_TIMER1_AND_TIMER2);
setup_timer_2(mode, period, postscale);
setup_timer_4(mode, period, postscale);
setup_timer_6(mode, period, postscale);
do
{
}
while(1);
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue May 08, 2012 5:28 pm |
|
|
What's your compiler version ?
The version is given at the top of the .LST file, which will be in your
project directory after you compile a file with no errors. Example of
version numbers:
http://www.ccsinfo.com/devices.php?page=versioninfo |
|
|
Oleg_S
Joined: 08 May 2012 Posts: 6
|
|
Posted: Tue May 08, 2012 11:49 pm |
|
|
Hi, it's v4.120. Thank you. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed May 09, 2012 1:46 pm |
|
|
Quote: |
CCP_PWM_PLUS_1
CCP_PWM_PLUS_2
CCP_PWM_PLUS_3
|
This thread has an explanation of those parameters:
http://www.ccsinfo.com/forum/viewtopic.php?t=22119
Quote: |
CCP_PWM_H_H
CCP_PWM_H_L
CCP_PWM_L_H
CCP_PWM_L_L
|
You left off the #define statement values for those constants. They are
0xc, 0xd, 0xe, 0xf. These numbers correspond exactly to the CCPxM
bits in the lower 4 bit positions of the CCPxCON register. These 4 bits
control the polarity of the PWM output signals.
Look in at the following Register explanation in the 18F47J13 data sheet.
Look in this section of the data sheet:
Quote: |
REGISTER 19-1: CCPxCON: ECCP1/2/3 CONTROL (1, ACCESS FBAh; 2, FB4h; 3, BANKED F15h)
bit 3-0 CCPxM<3:0>: ECCPx Mode Select bits:
1100 = PWM mode; PxA and PxC active-high; PxB and PxD active-high
1101 = PWM mode; PxA and PxC active-high; PxB and PxD active-low
1110 = PWM mode; PxA and PxC active-low; PxB and PxD active-high
1111 = PWM mode; PxA and PxC active-low; PxB and PxD active-low |
Code: | CCP Variables: CCP_x, CCP_x_LOW, CCP_x_HIGH
|
Those variables allow you to have direct access to the CCP registers
in your program. For example, if you are doing a tachometer program,
you would read the contents of the CCP register after you got a CCP
interrupt. When you have two sequential interrupts, you can then
subtract the two values and find the difference. Then you can calculate
the time between the two CCP events and calculate the frequency, and
then convert that to RPM or speed, or whatever your application requires.
Your compiler version has some bugs in the PWM code that will prevent
it from working in some modes. I don't have any more time to work on
it today. Maybe in a few days. |
|
|
Oleg_S
Joined: 08 May 2012 Posts: 6
|
|
Posted: Wed May 09, 2012 3:27 pm |
|
|
Thank you. It's more clear now. But where is it described? I've tried searching ccs help file with no luck.
I've worked all day on this and managed to make it working with some changes. Closer look at datasheet helped to understand that there are 10pwm modules - first three are ECCP and rest are CCP. Output pins of ECCP are remapable and CCP - fixed hardware. So my working code now:
Code: |
#include <18F47J13.h>
#device adc=12 // right/left 16/12 justified
#FUSES ADC10 // ADC is 10/12-bits
#FUSES NOWDT //No Watch Dog Timer
#FUSES WDT128 //Watch Dog Timer uses 1:128 Postscale
#FUSES STVREN //Stack full/underflow will cause reset
#FUSES NOXINST //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
#FUSES INTRC_PLL_IO //Internal RC Osc with 4X PLL, no CLK1OUT
#FUSES SOSC_HIGH // High power SOSC circuit
#FUSES RTCOSC_INT //RTCC uses Internal 31KHz Oscillator as reference source
#FUSES NOCLOCKOUT
#FUSES NOFCMEN //Fail-safe clock monitor disabled
#FUSES NOIESO //Internal External Switch Over mode disabled
#FUSES NODSBOR //B2OR disabled in Deep Sleep
#FUSES NODSWDT //Deep Sleep Watchdog Timer disabled
#FUSES NOIOL1WAY
#use delay(internal=8M) // sets oscillator speed (31kHz to 8MHz)
#CASE // case sensetive compiler
#PIN_SELECT RX2 = PIN_A0 // remap rx2 to pin
#PIN_SELECT TX2 = PIN_A1 // remap tx2 to pin
#use rs232(uart2, baud=38400, parity=N, xmit=PIN_A1, rcv=PIN_A0, bits=8)
#PIN_SELECT P1A = PIN_B0 // remap ECCP1
#PIN_SELECT P2A = PIN_B1 // remap ECCP2
#PIN_SELECT P3A = PIN_B2 // remap ECCP3
#USE FAST_IO(A) // let user decide when set and clear tris_x
#USE FAST_IO(B) // let user decide when set and clear tris_x
#USE FAST_IO(D) // let user decide when set and clear tris_x
#USE FAST_IO(E) // let user decide when set and clear tris_x
#define phase_a PIN_B0
#define phase_b PIN_B1
#define phase_c PIN_B2
void main() {
#use delay(clock=32M)
setup_oscillator(OSC_32MHZ|OSC_PLL_ON);
set_tris_a(0b00001001); // pin A3= Vbat, A1=TX, A0=RX
set_tris_b(0b00000000);
set_tris_d(0b00000000);
set_tris_e(0b00000000);
// setup pwm period
setup_timer_2(T2_DIV_BY_1, 255, 1); // 512us overflow
// setup pwms
setup_ccp1(CCP_PWM);
setup_ccp2(CCP_PWM);
setup_ccp3(CCP_PWM);
// set duty
set_pwm1_duty(0L);
set_pwm2_duty(0L);
set_pwm3_duty(0L);
long Duty = 0;
// setup_ccp1(CCP_OFF);
// setup_ccp2(CCP_OFF);
// setup_ccp3(CCP_OFF);
do
{
if (++Duty > 1023)
{
Duty = 0;
}
set_pwm1_duty(Duty);
set_pwm2_duty(Duty);
set_pwm3_duty(Duty);
output_toggle(PIN_B3);
delay_ms(10);
}
while(1);
}
|
|
|
|
Oleg_S
Joined: 08 May 2012 Posts: 6
|
|
Posted: Wed May 09, 2012 3:47 pm |
|
|
Another question - now all my 3 channels have the same period which is set by Timer2 Prescaler and Period Register PR2. Duty of each PWM is hold in CCPRxH & CCPRxL.
What datasheet says about that PWMs can be based on TMR2, TMR4, TMR6, TMR8?
Do they also used like Timer2 to set period? I would be able to set different periods to all channels? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed May 09, 2012 3:55 pm |
|
|
Quote: | But where is it described?
|
In many cases it's not described. You just have to look at the PIC data
sheet and the .h file for the PIC and make an inference or a judgement,
similar to how I did it for CCP_PWM_H_H, etc., in a post above.
Quote: |
I would be able to set different periods to all channels.
|
Look in the PIC data sheet. Look in the "PWM mode" column for CCP4,
CCP5, CCP6, and CCP7:
Quote: |
TABLE 18-2: TIMER ASSIGNMENTS FOR CCP MODULES 4, 5, 6 AND 7 |
It looks possible to assign a different timer to each CCP. So you can
probably have a different PWM frequency for each one. |
|
|
Oleg_S
Joined: 08 May 2012 Posts: 6
|
|
Posted: Wed May 09, 2012 4:05 pm |
|
|
And last one for today - I had problems with setting oscillator speed by #use delay(). I've tried different ways and either hardware speed was wrong but delay_ms() correct or vice versa.
I use internal oscillator pic18f47j13 which is 8Mhz. Then 4xPLL can be used to rise speed to 32Mhz. And I can't do it correctly. My PWM period is ok but delay function wrong or both wrong.
I've tried Code: | #use delay (clock=32M, internal=8M) | as described in help file but it didn't work. Then I used Code: | #use delay(internal=8M) | following Code: | setup_oscillator(OSC_32MHZ|OSC_PLL_ON) | where hardware timing was right but delay function wrong.
How do you do it?
And I also didn't manage to set 40Mhz oscillator using PLL. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed May 09, 2012 4:14 pm |
|
|
I don't have an 18F47J13 to test. Maybe by Monday I will have one. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Thu May 10, 2012 1:50 am |
|
|
Oleg_S wrote: | And last one for today - I had problems with setting oscillator speed by #use delay(). I've tried different ways and either hardware speed was wrong but delay_ms() correct or vice versa.
I use internal oscillator pic18f47j13 which is 8Mhz. Then 4xPLL can be used to rise speed to 32Mhz. And I can't do it correctly. My PWM period is ok but delay function wrong or both wrong.
I've tried Code: | #use delay (clock=32M, internal=8M) | as described in help file but it didn't work. Then I used Code: | #use delay(internal=8M) | following Code: | setup_oscillator(OSC_32MHZ|OSC_PLL_ON) | where hardware timing was right but delay function wrong.
How do you do it?
And I also didn't manage to set 40Mhz oscillator using PLL. |
I'd do this:
Code: |
#use delay (clock=32M)
//Sets the timing used by delays etc...
setup_oscillator(OSC_32MHZ|OSC_PLL_ON)
//Ensures the internal oscillator is used and set to 32MHz.
|
You do realise 40MHz can only be done with either an external 10MHz crystal, or an external 40MHz clock input?.
Best Wishes |
|
|
Oleg_S
Joined: 08 May 2012 Posts: 6
|
|
Posted: Thu May 10, 2012 4:49 pm |
|
|
Thanks. 32MHz working both hardware and software delay.
Quote: |
You do realise 40MHz can only be done with either an external 10MHz crystal, or an external 40MHz clock input?.
|
As far as I understood my chip has 2 PLL - first gives 16-32Mhz from internal oscillator and second gives 48MHz from 4Mhz. I just don't know that trick which turns on second PLL. There is someone else on the forum with the same chip and the same problem.
So, my working software so far:
Code: |
#include <18F47J13.h>
#device adc=12 // right/left 16/12 justified
#FUSES ADC10 // ADC is 10/12-bits
#FUSES NOWDT //No Watch Dog Timer
#FUSES WDT128 //Watch Dog Timer uses 1:128 Postscale
#FUSES NOSTVREN //Stack full/underflow will not cause reset
#FUSES NOXINST //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
#FUSES PLLEN //4X HW PLL enabled
#FUSES INTRC_PLL_IO //Internal RC Osc with 4X PLL, no CLKOUT
#FUSES NOCLOCKOUT
#FUSES SOSC_DIG //Digital mode, I/O port functionality of RC0 and RC1
#FUSES NOFCMEN //Fail-safe clock monitor disabled
#FUSES NOIESO //Internal External Switch Over mode disabled
#FUSES NODSBOR //BOR disabled in Deep Sleep
#FUSES NODSWDT //Deep Sleep Watchdog Timer disabled
#FUSES NOIOL1WAY //Allows multiple reconfigurations of peripheral pins
#use delay(clock=32M)
#CASE // case sensetive compiler
#PIN_SELECT RX2 = PIN_A0 // remap rx2 to pin
#PIN_SELECT TX2 = PIN_A1 // remap tx2 to pin
#use rs232(uart2, baud=38400, parity=N, xmit=PIN_A1, rcv=PIN_A0, bits=8)
#PIN_SELECT P1A = PIN_B0 // remap ECCP1
#PIN_SELECT P2A = PIN_B1 // remap ECCP2
#PIN_SELECT P3A = PIN_B2 // remap ECCP3
#USE FAST_IO(A) // let user decide when set and clear tris_x
#USE FAST_IO(B) // let user decide when set and clear tris_x
#USE FAST_IO(D) // let user decide when set and clear tris_x
#USE FAST_IO(E) // let user decide when set and clear tris_x
#define phase_a PIN_B0
#define phase_b PIN_B1
#define phase_c PIN_B2
long Duty[] = {0, 21, 43, 64, 86, 107, 128, 149, 171, 192, 213, 234, 254, 275, 296, 316, 336, 367, 377, 396,
416, 436, 455, 474, 493, 512, 530, 548, 566, 584, 601, 619, 635, 652, 668, 685, 700, 716, 731,
746, 760, 774, 788, 802, 815, 828, 840, 852, 864, 875, 886, 896, 907, 916, 926, 935, 943, 951,
959, 966, 973, 979, 985, 991, 996, 1001, 1005, 1009, 1012, 1015, 1017, 1019, 1021, 1022, 1023,
1023, 1023, 1022, 1021, 1019, 1017, 1015, 1012, 1009, 1005, 1001, 996, 991, 985, 979, 973, 966,
959, 951, 943, 935, 926, 916, 907, 896, 886, 875, 864, 852, 840, 828, 815, 802, 788, 774, 760,
746, 731, 716, 700, 685, 668, 652, 635, 619, 601, 584, 566, 548, 530, 511, 493, 474, 455, 436,
416, 396, 377, 357, 336, 316, 296, 275, 254, 234, 213, 192, 171, 149, 128, 107, 86, 64, 43, 21, 0};
char phase_a_index=0, phase_b_index=50, phase_c_index=100; // phase shifts
#int_TIMER1
void TIMER1_isr(void)
{
set_timer1(64528); // ~66us overflow
// increment & check index
if (++phase_a_index > 150)
{
phase_a_index = 0;
output_toggle(PIN_B3);
}
if (++phase_b_index > 150)
{
phase_b_index = 0;
}
if (++phase_c_index > 150)
{
phase_c_index = 0;
}
// set duty
set_pwm1_duty(Duty[phase_a_index]);
set_pwm2_duty(Duty[phase_b_index]);
set_pwm3_duty(Duty[phase_c_index]);
}
void main() {
setup_oscillator(OSC_32MHZ|OSC_PLL_ON);
set_tris_a(0b00001001); // pin A3= Vbat, A1=TX, A0=RX
set_tris_b(0b00000000);
set_tris_d(0b00000000);
set_tris_e(0b00000000);
// setup pwm period
setup_timer_2(T2_DIV_BY_4, 255, 1); //
// setup pwms
setup_ccp1(CCP_PWM);
setup_ccp2(CCP_PWM);
setup_ccp3(CCP_PWM);
// set duty
set_pwm1_duty(0);
set_pwm2_duty(0);
set_pwm3_duty(0);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_1); // 125ns increment
set_timer1(64528); //
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
do
{
}
while(1);
}
|
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon May 14, 2012 3:44 pm |
|
|
I made it work at 48MHz with the internal oscillator. It requires the
following 4 fuse settings to enable the PLL in the correct mode.
This program was tested with your compiler vs. 4.120 and it works.
I bought an 18F27J13 to test it. That PIC is in the same family as your
18F47J13.
Code: |
#include <18F27J13.h>
#fuses INTRC_PLL_IO, PLL96MHZ, PLL2, PLLEN, NOWDT, SOSC_DIG
#use delay(clock=48M)
//=================================
void main()
{
// Blink LED at 1 Hz.
while(1)
{
output_toggle(PIN_B0);
delay_ms(500);
}
} |
|
|
|
|
|
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
|