News:

Let's find out together what makes a PIC Tick!

Main Menu

PIC18F25K22 10-bit PWM?

Started by Bernard, Jul 10, 2024, 12:41 PM

Previous topic - Next topic

Bernard

Having previously successfully used 10-bit HPWM on CCP1 (PortC.2) and CCP2 (PortC.1) using Amicus with PIC18F25K22, I am hoping that it will be possible switch to the Positron compilers which I have recently purchased. There does not seem to be a built-in 10-bit HPWM command however. Is there a way to achieve this?

top204

#1
In order to operate the CCP peripherals as PWM at a fixed maximum resolution, they must share the same frequency and Timer2, that operates them, must be set for a specific rate.

The code below sets the CCP1 and CCP2 peripherals to operate as PWM and sets their resolution to the maximum on a PIC18F25K22 device, which is 10-bits:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Create some procedures to operate CCP1 and CCP2 peripherals as PWM at their maximum resolution (10-bits)
' Written for the Positron8 compiler by Les Johnson.
'
    Device = 18F25K22                           ' Tell the compiler what device to compile for
    Declare Xtal = 64                           ' Tell the compiler what frequency the device is operating at (in MHz)
'
' Setup USART1
'
    Declare Hserial1_Baud = 9600                ' Setup the Baud rate of USART1
    Declare HRSOut1_Pin = PORTC.6               ' Setup the pin used for USART1 TX
    Declare HRSIn1_Pin = PORTC.7                ' Setup the pin used for USART1 RX
'
' Tell the compiler what pins are used for PWM on this device
'
    Declare CCP1_Pin = PORTC.2
    Declare CCP2_Pin = PORTC.1
    'Declare CCP3_Pin = PORTB.5
    'Declare CCP4_Pin = PORTB.0
'
' Create any global variables for the demo here
'
    Dim wDuty1 As Word                          ' Holds the duty cycle for the PWM1 peripheral
    Dim wDuty2 As Word                          ' Holds the duty cycle for the PWM2 peripheral

'------------------------------------------------------------------------------
' The main program starts here
' Alter the duty cycles for PWM1 and PWM2
'
Main:
    Analog12_Open()                             ' Open the CCP1 and CCP2 peripherals to operate as PWM with maximum resolution

    For wDuty1 = 0 To 1023                      ' Create a duty cycle loop
        wDuty2 = 1023 - wDuty1                  ' Make the duty cycle for PWM2, the inverse of the duty cycle for PWM1
        Analog1_Write(wDuty1)                   ' Write the duty cycle to the PWM1 peripheral
        Analog2_Write(wDuty2)                   ' Write the duty cycle to the PWM2 peripheral
        DelayMs 10                              ' A small delay between changes, so they can be seen changing on an oscilloscope
    Next

'------------------------------------------------------------------------------
' Configure CCP1 as PWM with a resolution of 10-bits (0 - 1023)
' Notes     : None
' Output    : None
' Notes     : Uses the pin setup by: Declare CCP1_Pin
'
Proc Analog1_Open()
    T2CON = %00000100                           ' Turn on Timer2 with a Prescaler value of 1:1
    PR2 = 255                                   ' Set PWM resolution to maximum
    CCPR1L = 0                                  ' Reset the CCPR1L register
    CCP1CON = %00001100                         ' Turn on PWM Module 1 by setting bits 2 and 3 of CCP1CON
    PinOutput __CCP1_PORT_PIN                   ' Enable the PWM1 output pin
EndProc

'------------------------------------------------------------------------------
' Configure CCP2 as PWM with a resolution of 10-bits (0 - 1023)
' Notes     : None
' Output    : None
' Notes     : Uses the pin setup by: Declare CCP2_Pin
'
Proc Analog2_Open()
    T2CON = %00000100                           ' Turn on Timer2 with a Prescaler value of 1:1
    PR2 = 255                                   ' Set PWM resolution to maximum
    CCPR2L = 0                                  ' Reset the CCPR2L register
    CCP2CON = %00001100                         ' Turn on PWM Module 2 by setting bits 2 and 3 of CCP2CON
    PinOutput __CCP2_PORT_PIN                   ' Enable the PWM2 output pin
EndProc

'------------------------------------------------------------------------------
' Configure CCP1 and CCP2 as PWM with a resolution of 10-bits (0 - 1023)
' Notes     : None
' Output    : None
' Notes     : Uses the pins setup by: Declare CCP1_Pin and Declare CCP2_Pin
'
Proc Analog12_Open()
    T2CON = %00000100                           ' Turn on Timer2 with a Prescaler value of 1:1
    PR2 = 255                                   ' Set PWM resolution to maximum
    CCP1CON = %00001100                         ' Turn on PWM Module 1 by setting bits 2 and 3 of CCP1CON
    CCP2CON = %00001100                         ' Turn on PWM Module 2 by setting bits 2 and 3 of CCP2CON
    CCPR1L = 0                                  ' \
    CCPR2L = 0                                  ' / Reset the CCPR1L and CCPR2L registers
    PinOutput __CCP1_PORT_PIN                   ' \
    PinOutput __CCP2_PORT_PIN                   ' / Enable the PWM1 and PWM2 output pins
EndProc

'------------------------------------------------------------------------------
' Set the duty of the 10-bit CCP1 peripheral operating as 10-bit PWM
' Input     : pDutyCycle holds the 10-bit duty cycle for CCP1 (0 to 1023)
' Output    : None
' Notes     : None
'
Proc Analog1_Write(pDutyCycle As Word)
    CCP1CON = CCP1CON & %11001111
    WREG = pDutyCycle << 4
    WREG = WREG & %00110000
    CCP1CON = CCP1CON | WREG
    CCPR1L = pDutyCycle >> 2
EndProc

'------------------------------------------------------------------------------
' Set the duty of the 10-bit CCP2 peripheral operating as 10-bit PWM
' Input     : pDutyCycle holds the 10-bit duty cycle for CCP2 (0 to 1023)
' Output    : None
' Notes     : None
'
Proc Analog2_Write(pDutyCycle As Word)
    CCP2CON = CCP2CON & %11001111
    WREG = pDutyCycle << 4
    WREG = WREG & %00110000
    CCP2CON = CCP2CON | WREG
    CCPR2L = pDutyCycle >> 2
EndProc

'------------------------------------------------------------------------------
' Turn off CCP1 acting as PWM by clearing CCP1CON
' Input     : None
' Output    : None
' Notes     : Also disables the PWM1 output pin
'           : Uses the pin setup by: Declare CCP1_Pin
'
Proc Analog1_Close()
    CCP1CON = 0
    PinInput __CCP1_PORT_PIN
EndProc

'------------------------------------------------------------------------------
' Turn off CCP2 acting as PWM by clearing CCP2CON
' Input     : None
' Output    : None
' Notes     : Also disables the PWM2 output pin
'           : Uses the pin setup by: Declare CCP2_Pin
'
Proc Analog2_Close()
    CCP2CON = 0
    PinInput __CCP2_PORT_PIN
EndProc

'------------------------------------------------------------------------------
' Turn off CCP1 and CCP2 acting as PWM
' Input     : None
' Output    : None
' Notes     : Also disables the PWM1 and PWM2 output pin
'           : Uses the pins setup by: Declare CCP1_Pin and Declare CCP2_Pin
'
Proc Analog12_Close()
    CCP1CON = 0
    CCP2CON = 0
    PinInput __CCP1_PORT_PIN
    PinInput __CCP2_PORT_PIN
EndProc

'------------------------------------------------------------------------------
' Setup the config fuses for a PIC18F25K22 device to operate with an external crystal with the 4xPLL enabled
'
Config_Start
    FOSC = HSHP           ' HS oscillator (high power > 16 MHz)
    PLLCFG = On           ' Oscillator multiplied by 4
    PRICLKEN = On         ' Primary clock enabled
    FCMEN = Off           ' Fail-Safe Clock Monitor disabled
    IESO = Off            ' Internal/External Oscillator Switchover mode disabled
    PWRTEN = On           ' Power up timer enabled
    BOREN = SBORDIS       ' Brown-out Reset enabled in hardware only (SBOREN is disabled)
    BORV = 190            ' Brown Out Reset Voltage set to 1.90 V nominal
    WDTEN = Off           ' Watch dog timer is always disabled. SWDTEN has no effect.
    WDTPS = 128           ' Watchdog Timer Postscale 1:128
    CCP2MX = PORTC1       ' CCP2 input/output is multiplexed with RC1
    PBADEN = Off          ' PORTB<5:0> pins are configured as digital I/O on Reset
    CCP3MX = PORTB5       ' P3A/CCP3 input/output is multiplexed with RB5
    HFOFST = On           ' HFINTOSC output and ready status are not delayed by the oscillator stable status
    T3CMX = PORTC0        ' Timer3 Clock Input (T3CKI) is on RC0
    P2BMX = PORTB5        ' ECCP2 B (P2B) is on RB5
    MCLRE = EXTMCLR       ' MCLR pin enabled, RE3 input pin disabled
    STVREN = Off          ' Stack full/underflow will not cause Reset
    LVP = Off             ' Single-Supply ICSP disabled
    XINST = Off           ' Instruction set extension and Indexed Addressing mode disabled (Legacy mode)
    Debug = Off           ' Disabled
    Cp0 = Off             ' Block 0 (000800-001FFF) not code-protected
    CP1 = Off             ' Block 1 (002000-003FFF) not code-protected
    CP2 = Off             ' Block 2 (004000-005FFF) not code-protected
    CP3 = Off             ' Block 3 (006000-007FFF) not code-protected
    CPB = Off             ' Boot block (000000-0007FF) not code-protected
    CPD = Off             ' Data EEPROM not code-protected
    WRT0 = Off            ' Block 0 (000800-001FFF) not write-protected
    WRT1 = Off            ' Block 1 (002000-003FFF) not write-protected
    WRT2 = Off            ' Block 2 (004000-005FFF) not write-protected
    WRT3 = Off            ' Block 3 (006000-007FFF) not write-protected
    WRTC = Off            ' Configuration registers (300000-3000FF) not write-protected
    WRTB = Off            ' Boot Block (000000-0007FF) not write-protected
    WRTD = Off            ' Data EEPROM not write-protected
    EBTR0 = Off           ' Block 0 (000800-001FFF) not protected from table reads executed in other blocks
    EBTR1 = Off           ' Block 1 (002000-003FFF) not protected from table reads executed in other blocks
    EBTR2 = Off           ' Block 2 (004000-005FFF) not protected from table reads executed in other blocks
    EBTR3 = Off           ' Block 3 (006000-007FFF) not protected from table reads executed in other blocks
    EBTRB = Off           ' Boot Block (000000-0007FF) not protected from table reads executed in other blocks
Config_End

With the microcontroller operating at 64MHz, the frequency of the PWM waveform is 62.5KHz.

Bernard

Thank you for your quick reply. I will try your code tomorrow and report back.

Bernard

The demo code worked perfectly. However a problem occurs if instead of Analog12_Open() you use Analog1_Open and Analog2_Open separately. In the procedure Analog2_Open, the line CCP1CON = %00001100 should read CCP2CON = %00001100.

top204

#4
Now corrected.

That's what happens when code is written too fast, and too late in the day. :-)