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

pic18f pwm initialization

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



Joined: 08 May 2012
Posts: 6

View user's profile Send private message

pic18f pwm initialization
PostPosted: Tue May 08, 2012 3:11 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Tue May 08, 2012 5:28 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Tue May 08, 2012 11:49 pm     Reply with quote

Hi, it's v4.120. Thank you.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed May 09, 2012 1:46 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Wed May 09, 2012 3:27 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Wed May 09, 2012 3:47 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Wed May 09, 2012 3:55 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Wed May 09, 2012 4:05 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Wed May 09, 2012 4:14 pm     Reply with quote

I don't have an 18F47J13 to test. Maybe by Monday I will have one.
Ttelmah



Joined: 11 Mar 2010
Posts: 19538

View user's profile Send private message

PostPosted: Thu May 10, 2012 1:50 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu May 10, 2012 4:49 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Mon May 14, 2012 3:44 pm     Reply with quote

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);
  }

}
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