News:

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

Main Menu

PIC16F887 - PWM1 - problem?

Started by kuhrig, Jun 29, 2022, 10:56 AM

Previous topic - Next topic

kuhrig

Hi Les,
since days I am trying to migrate a code from an 877 to an 887 because of IC shortage. Acc. to Microchip migration document there shouldn't be any PWM changes.
But I cannot get the PWM1 (CCP1) on RC2 to work. PWM2 works fine.
After days of trying any possibility I wrote some test code in mikroBasic Pro. And no problems. PWM1 signal on RC2 there.
I am using the latest version 4.0.1.9.
I am now assuming the compiler must have a problem.
Perhaps the compiler is not adressing the right register bank? Sorry, I am lost.
Thanks in advance.
Kai

top204

#1
The PIC16F887 microcontroller has not got a problem with the HPWM commands. I have just ran a test and everything is works as expected with both CCP peripherals.

I tested with the simple program listing below:
'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Tester for a PIC16F887 and the HPWM commands
' Written for the Positron8 compiler by Les Johnson
'
    Device = 16F887                             ' Tell the compiler what device is being compiled for
    Declare Xtal = 20                           ' Tell the compiler what speed the device will be operating at
'
' Setup the pins for the CCP peripherals used by the HPWM command.
' Required because the CCP2 pin can be changed with a config setting.
'   
    Declare CCP1_Pin = PORTC.2                  ' Set the Port.Pin used by the HPWM1 command
    Declare CCP2_Pin = PORTC.1                  ' Set the Port.Pin used by the HPWM2 command
   
'-------------------------------------------------------------------
Main:
    HPWM 1, 127, 2000                           ' Set CCP1 for 50 percent duty at 2000Hz
    HPWM 2, 127, 2000                           ' Set CCP2 for 50 percent duty at 2000Hz

If you do not set the pin to use for CCP2, the compiler will not create code for it, so nothing will be output from it. This is because the port and pin used for peripheral CCP2 can be altered with a config fuse setting on some devices, so the compiler needs to know what pin to use. The CCP1 peripheral has a fixed Port and Pin on this device, but it is always better to place the CCPx_Pin declares, so the compiler knows what to setup because it no longer relies on defaults, because of the huge differences in each PIC microcontroller device.

I may add a reminder message if the HPWM commands are used but the CCPx_Pin declares have not been issued in the program. Just to be on the safe side.

Below is a screenshot of the above program running in a simulator, and I also tested it on an actual device:

HPWM_16F887.jpg

kuhrig

Thanks Les.
I'm not using the HPWM commands. I have set the ports and registers manually. (see my file)
Like it worked fine before with the 877 and on the pwm2 on the 887.
Just the pwm1 does not work on the 887 set the same as on the 877 and acc. to datasheet.
And acc. to migration doc from 877 to 887 there is no different setting.

Unfortunately the HPWM does not help as I need a 10 bit resolution.
It needs more investigation why the PWM1 cannot be set on the 887. (please see my file)
Thanks.

John Lawton

#3
If PWM works okay using the Positron commands then the problem must be in your settings somewhere, however I can't spot the problem :)

top204

#4
The program listing you uploaded is working fine on the device in front of me. I did have to get rid of the OSCCON SFR loading because that is only for internal oscillators and not external types, as setup in the config fuses.

Please.... Do not jump to conclusions that the compiler is at fault when something does not work as expected. Always test to see why something that should be categorically working, is not, before blaming the compiler itself. The compiler is, by no means, 100 percent perfect, but on such an old device that has been around for about 17 years and was once very commonly used, I think the wrinkles have been ironed out on it (famous last words). Once testing has been performed and a user presents a piece of code that should definately work but does not, I will not hesitate to get into the compiler's source and see why, then post an update. :-) I am the type of person who will always admit when I am wrong, or that I "do not know", unlike a few people I have known in my working career.

Below is a demo program that shows another way of performing the task, and it works beautifully:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Demonstrate the use of the CCP1 and CCP2 peripherals acting as 10-bit PWM waveform generators on a standard 14-bit core device.
' Written for the Positron8 compiler by Les Johnson.
'
    Device = 16F887                             ' Tell the compiler what device is being compiled for
    Declare Xtal = 20                           ' Tell the compiler what speed the device will be operating at
'
' Create a variable for the demo
'
    Dim wDuty As Word                           ' Holds the 10-but duty cycle for the PWM waveform generators

'-------------------------------------------------------------------
' The main program starts here
' Alter the duty cycle of both CCP periphals
'
Main:
    Analogue12_Open()                           ' Open the CCP1 and CCP2 peripherals as 10-bit PWM

    For wDuty = 0 To 1023                       ' Create a duty cycle loop
        Analogue1_Write(wDuty)                  ' Alter the duty cycle of CCP1
        Analogue2_Write(-wDuty)                 ' Alter the duty cycle of CCP2 (inverse to CCP1 to it will shrink while CCP1 expands)
        DelayMS 10                              ' A small delay so the duty cycle changes can be seen to happen
    Next                                        ' Close the loop

'---------------------------------------------------------
' Configure CCP1 and CCP2 as PWM with a resolution of 10-bits (0 - 1023)
' Input     : None
' Output    : None
' Notes     : Turns on Timer2 with a Prescaler value of 1:1
'             Sets both PWM resolutions to 10-bits
'
Proc Analogue12_Open()
    T2CON = $04                         ' \
    PR2 = 255                           ' / Setup Timer2 for a 10-bit PWM resolution
    CCP1CON = $0C                       ' Set the CCP1 peripheral to operate as PWM
    CCP2CON = $0C                       ' Set the CCP2 peripheral to operate as PWM
    CCPR1L = 0                          ' Clear the duty cycle SFR for CCP1
    CCPR2L = 0                          ' Clear the duty cycle SFR for CCP2
    PinOutput PORTC.1                   ' Make the CCP2 pin an output
    PinOutput PORTC.2                   ' Make the CCP1 pin an output
EndProc

'---------------------------------------------------------
' Change the duty cycle of the CCP1 peripheral operating as PWM
' Input     : pDuty holds the 10-bit duty value (0 to 1023)
' Output    : None
' Notes     : None
'
Proc Analogue1_Write(pDuty As Word)
    Dim bTemp As Byte

    CCP1CON = CCP1CON & $CF             ' Clear the duty cycle low bits
    bTemp = pDuty << 4                  ' Move the duty cycle parameter's low bits into the correct position
    bTemp = bTemp & $30                 ' Mask all but the duty cycle low bits
    CCP1CON = CCP1CON | bTemp           ' Or the duty cycle low bits into the CCP1CON SFR
    CCPR1L = pDuty >> 2                 ' Load the CCP1L SFR with the high bits of the duty cycle value
EndProc

'---------------------------------------------------------
' Change the duty cycle of the CCP2 peripheral operating as PWM
' Input     : pDuty holds the 10-bit duty value (0 to 1023)
' Output    : None
' Notes     : None
'
Proc Analogue2_Write(pDuty As Word)
    Dim bTemp As Byte

    CCP2CON = CCP2CON & $CF             ' Clear the duty cycle low bits
    bTemp = pDuty << 4                  ' Move the duty cycle parameter's low bits into the correct position
    bTemp = bTemp & $30                 ' Mask all but the duty cycle low bits
    CCP2CON = CCP2CON | bTemp           ' Or the duty cycle low bits into the CCP2CON SFR
    CCPR2L = pDuty >> 2                 ' Load the CCP2L SFR with the high bits of the duty cycle value
EndProc

I have tried the above demo program on a real device and in the simulator, and it works well. It uses the compiler's default config fuses because it is operating with an external crystal, so the configs are not needed in the program's listing. The demo loop changes the duty cycles of both CCP peripherals in the opposite direction, so when one is expanding the other is contracting. Just to show they are not just copying each other. Below is the program listing running in the simulator:

Positron8_PWM_Demo.jpg

kuhrig

Les, Thank you for looking into it.

I'm sorry, but it must be the compiler. Took me hours to figure out, what causes it after you proved the PWM1 is working.

My code starts with a 'clear' command as all my code does.

Add a 'clear' command before Main: and you should see the PWM1 does NOT work. Not on my DEV board with a real micro, ext osc. (I don't have a simulator)

I used your first code with HPWM command and added a 'clear' command. PWM2 is working, PWM1 is not working. Removing the 'clear' command and both are working again.
The code with the 'clear' command works fine with a PIC16F877, but as soon as it's the 887, PWM1 is not working.

I have informed you about problems in the past and every time you confirmed these problems and revised your compiler. I was checking for days until I posted it. I don't want to waste your time.

top204

My apologies. You are absolutely correct kuhrig, the Clear command is the issue with standard 14-bit core devices, and I can now see why.

The Clear command's assembler code is not setting the IRP bit of the STATUS SFR, when it needs to clear the high RAM bank area, so it is clearing out SFRs instead in the lew RAm bank area! This is the only thing I changed with the 14-bit core devices, last year, so that it would not clear out variables that were given assignments when created, but I never noticed that one issue with the assembler code.

An update will be uploaded ASAP.





kuhrig

Thanks. I'm lucky I was correct and not wasting your time.
Just out of interest: Why was PWM2 working?

Kai

top204

QuoteWhy was PWM2 working?

Unknown... But because when the assembler code was supposed to clear the higher RAM banks (above address 255), it was actually clearing the lower RAM bank SFRs, so I do not know which SFRs caused the anomaly. Some bits within some SFRs are writable and some are readable only!

The standard 14-bit core devices only have 8-bit indirect operations, so to get address' above 255, the IRP bit has to be set in the STATUS register, so the FSR register can access RAM above 255! Thankfully, this was changed in the 18F devices and the enhanced 14-bit core devices, that both have linear operation when using indirect instructions. i.e. Registers: FSR0L\H, FSR1L\H, and also FSR2L\H for 18F devices.

I'm busy creating the anomalies correction update, so I will upload it to the forum ASAP.

top204

Here is a link to the anomalies correction update for the compilers:

Positron Corrections Update 4.0.2.0 - 1.1.0.9

My previous statement of "famous last words" was correct. LOL