-
16 bit PWM using CCP1
I am trying to do 16 bit PWM as per Tip#10 16 bit Resolution PWM page 40 (3-10) Microchip Tips 'n Tricks
Basically when TM1 value equals the CCP1 (PWM duty) setting the CCP1 interrupt sets PORTC.2 low (works OK).
When the free running TM1 interrupts it is supposed to set PORTC.2 high (doesn't).
As a test CCP1 can be configured to toggle (this works OK as see in ISIS) but if configured
to set low for PWM the pin cannot be set high again even though CCP1 int is cleared.
The following code tries to set pin high in TM1 interrupt.
Norm
Code:
'FL PIC18F4520
; @ __CONFIG _CONFIG1H, _OSC_XT_1H
@ __CONFIG _CONFIG1H, _OSC_HSPLL_1H
@ __CONFIG _CONFIG2L, _BOREN_ON_2L
@ __CONFIG _CONFIG2H, _WDT_ON_2H
@ __CONFIG _CONFIG3H, _MCLRE_ON_3H & _PBADEN_OFF_3H
@ __CONFIG _CONFIG4L, _LVP_OFF_4L & _XINST_OFF_4L
DEFINE OSC 40
Clear
sSEROUT_PIN VAR PORTA.2
sBAUD CON 16416 '16416 = 19200 BAUD
wsave VAR BYTE bankA system ' Saves W
ssave VAR BYTE bankA system ' Saves STATUS
yTEMP VAR Byte
wDUTY VAR Word
wDUTY = 32768 '32768 = 50% DUTY PWM
'********************
'16 BIT CCP1 PWM
Input PORTC.2 ' Disable the HPWM output while things are being setup
RCON.7 = 0 ' 0 DISABLES PRIORITY LEVELS ON INTERRUPTS (16F COMPATABILITY)
T1CON = %10110000 ' Turn off Timer1 with a Prescaler value of 1:8
PIE1 = %00000101 ' enable CCP1, TMR1 overflow interrupt
INTCON = %11000000 ' enable global and peripheral interrupts
Output PORTC.2 ' Set PORTC.2 (CCP1) to output
' CCP1CON = %00000010 'TOGGLE PORTC.2 ON MATCH TM1 WITH DUTY ********** OK ************
CCP1CON = %00001001 'LOW PORTC.2 ON MATCH TM1 WITH DUTY ?????????? NOT OK ???????????????
T3CON = %00000000
' CCPR1L = wDUTY.LOWBYTE
CCPR1H = wDUTY.HighByte
CCPR1L = wDUTY.LowByte
DEFINE INTHAND myint
Goto START 'Jump over the subroutines
'**** ASSEMBLY INTURRUPT ROUTINE ****
Asm
myint ;KEEP LEFT
; Save the state of critical registers
movwf wsave ; Save W
swapf STATUS, W ; Swap STATUS To W (swap avoids changing STATUS)
clrf STATUS ; Clear STATUS
movwf ssave ; Save swapped STATUS
EndAsm
' yTEMP = yTEMP +1
' SerOut2 sSEROUT_PIN,sBAUD,["INT ",DEC yTEMP,13]
PIR1.2 = 0 ' CLEAR THE CCP1 INT FLAG
High PORTC.2 '???????????????? DOES NOT SET HIGH ?????????????????
Asm
bcf PIR1, 0 ; Clear interrupt flag
swapf ssave, W ; Retrieve the swapped STATUS value (swap To avoid changing STATUS)
movwf STATUS ; Restore it To STATUS
swapf wsave, F ; Swap the stored W value
swapf wsave, W ; Restore it To W (swap To avoid changing STATUS)
retfie ; Return from interrupt
EndAsm
'**** END ASSEMBLY INTURRUPT ROUTINE ****
'***********************************************
'***********************************************
START:
PAUSE 800
SerOut2 sSEROUT_PIN,sBAUD,["START",13]
T1CON.0 = 1 'TMR1 ON
MAIN:
yTEMP = yTEMP +1
SerOut2 sSEROUT_PIN,sBAUD,["LOOP ",Dec yTEMP,13]
PAUSE 500
Goto MAIN
End
-
Hi Norm,
To set the pin High, simply clear the CCP1CON register, then load it<sub>(Bruce)</sub> with the compare mode again %00001001 (9).
And, only do it on a Timer1 interrupt. The CCP changes the pin low on its own, so you don't need to enable the CCP interrupt.
A few other things are either not needed or can be done differently.
Have a go at this ...
Code:
'FL PIC18F4520
; @ __CONFIG _CONFIG1H, _OSC_XT_1H
@ __CONFIG _CONFIG1H, _OSC_HSPLL_1H
@ __CONFIG _CONFIG2L, _BOREN_ON_2L
@ __CONFIG _CONFIG2H, _WDT_ON_2H
@ __CONFIG _CONFIG3H, _MCLRE_ON_3H & _PBADEN_OFF_3H
@ __CONFIG _CONFIG4L, _LVP_OFF_4L & _XINST_OFF_4L
DEFINE OSC 40
DEFINE INTHAND myint
Clear
sSEROUT_PIN VAR PORTA.2
sBAUD CON 16416 '16416 = 19200 BAUD
yTEMP VAR Byte
wDUTY VAR WORD EXT ' map wDuty to CCPR1L:H as a word
@wDUTY = CCPR1L
'***********************************************
START:
ADCON1 = $0F ' disable analog functions
CMCON = 7 ' disable comparators
'********************
'16 BIT CCP1 PWM
T1CON = %00110000 ' Turn off Timer1 with a Prescaler value of 1:8
PIE1 = %00000001 ' enable TMR1 overflow interrupt
INTCON = %11000000 ' enable global and peripheral interrupts
CCP1CON = %00001001 ' LOW PORTC.2 ON MATCH TM1 WITH DUTY
OUTPUT PORTC.2 ' Set PORTC.2 (CCP1) to output, starts High
wDUTY = 32768 ' 32768 = 50% DUTY PWM
T1CON.0 = 1 ' TMR1 ON
PAUSE 800
SerOut2 sSEROUT_PIN,sBAUD,["START",13]
'***********************************************
MAIN:
yTEMP = yTEMP +1
SerOut2 sSEROUT_PIN,sBAUD,["LOOP ",Dec yTEMP,13]
PAUSE 500
Goto MAIN
'**** ASSEMBLY INTERRUPT ROUTINE ****
Asm
myint
movlw 9 ; %00001001 compare mode, low on match
clrf CCP1CON ; clrf added per Bruce's suggestion
movwf CCP1CON ; Set Pin to default state (High)
bcf PIR1,0 ; Clear Timer Int Flag
retfie FAST ; Return from interrupt with shadow regs
EndAsm
'**** END ASSEMBLY INTURRUPT ROUTINE ****
End
P.S. Using both CCP's with this method would make a great 2 channel hardware driven servo driver.
Dutycycles between 2500-5000 would give pulses between 1-2ms at ~40hz.
-
2-CH Hardware Servo Driver
And since you made me think of it ... :)
Here's a 2 channel Hardware Servo Driver, that uses Timer1 and both CCP modules in Compare mode.
With an 18F.
Servo outputs are the CCP? pins.
Pulses will be continuous at ~40hz, regardless of MainLoop activity.
Cheers ...
Code:
'***************************************************************************
'* Name : 2CH_Servo.pbp
'* Author : Darrel Taylor
'* Date : 12/13/2009
'* Notes : 18F's only
'***************************************************************************
@ __CONFIG _CONFIG1H, _OSC_HSPLL_1H
@ __CONFIG _CONFIG2L, _BOREN_OFF_2L
@ __CONFIG _CONFIG2H, _WDT_OFF_2H
@ __CONFIG _CONFIG4L, _LVP_OFF_4L & _XINST_OFF_4L
CLEAR
DEFINE OSC 40
DEFINE INTHAND myint
;----[User Selections]------------------------------------------------------
MoveSpeed CON 3 ' movement speed smaller = faster
PosRange CON 900 ' position is 0-900, 0.0-90.0 degrees
' 450 is Center
CCP1pin VAR PORTC.2 ' Specify the pin that CCP1 uses
CCP2pin VAR PORTC.1 ' Specify the pin that CCP2 uses
;----[Variables and Aliases]------------------------------------------------
Servo1 VAR WORD ' Position for Servo1
Servo2 VAR WORD ' Position for Servo2
DutyHold1 VAR WORD BANK0 SYSTEM ' holds next dutycycle, synch with PWM
DutyHold2 VAR WORD BANK0 SYSTEM '
TempW VAR WORD ' temporary variable
POS VAR WORD ' loop counter variable
TMR1IE VAR PIE1.0 ' Timer1 Interrupt Enable
TMR1IF VAR PIR1.0 ' Timer1 Interrupt Flag
TMR1ON VAR T1CON.0 ' Timer1 ON bit
GIE VAR INTCON.7 ' Global Interrupt Enable
PEIE VAR INTCON.6 ' Peripheral Interrupt Enable
;----[Initialization]-------------------------------------------------------
Init:
T1CON = %00100000 ' Timer1 off, Prescaler 1:4 (40mhz)
' 1:2 (20mhz), 1:1 (10mhz)
TMR1IE = 1 ' Enable TMR1 overflow interrupt
TMR1IF = 0 ' Clear TMR1 interrupt flag
PEIE = 1 ' Enable peripheral interrupts
GIE = 1 ' Enable global interrupts
CCP1CON = 9 ' Low on match TMR1 with DUTY1
CCP2CON = 9 ' Low on match TMR1 with DUTY2
OUTPUT CCP1pin ' Set CCP1 pin to output, starts High
OUTPUT CCP2pin ' Set CCP1 pin to output, starts High
Servo1 = PosRange/2 ' Start at Center Position
Servo2 = PosRange/2
GOSUB SetServos
TMR1ON = 1 ' turn ON TMR1
PAUSE 2000 ' allow time for servo to Home
;----[Main Program Loop]----------------------------------------------------
Main:
FOR POS = 0 TO PosRange ' move both from one end to the other
Servo1 = POS
GOSUB SetServo1 ' Set servo1's position
Servo2 = POS
GOSUB SetServo2 ' Set servo2's position
PAUSE MoveSpeed ' movement speed
NEXT POS
FOR POS = PosRange TO 0 STEP -1 ' move servo1 back to home
Servo1 = POS
GOSUB SetServo1
PAUSE MoveSpeed
NEXT POS
FOR POS = PosRange TO 0 STEP -1 ' move servo2 back to home
Servo2 = POS
GOSUB SetServo2
PAUSE MoveSpeed
NEXT POS
PAUSE 1000
Goto Main ' rinse and repeat
;----[Convert Position in degrees to dutycycle]-----------------------------
SetServos: ' Set both Servo's dutycycles
GOSUB SetServo1
SetServo2: ' scale Posistion to 2500 Dutycycle
TempW = Servo2 * 2500
TempW = DIV32 PosRange + 2500
GIE = 0 ' no ints during variable update
DutyHold2 = TempW
GIE = 1
RETURN
SetServo1:
TempW = Servo1 * 2500
TempW = DIV32 PosRange + 2500
GIE = 0
DutyHold1 = TempW
GIE = 1
RETURN
;----[Dual Servo Driver - Interrupt Service]--------------------------------
Asm
myint
movlw 9 ; %00001001 compare mode, low on match
clrf CCP1CON ; clrf added per Bruce's suggestion
movwf CCP1CON ; Set Pins to default state (High)
clrf CCP2CON ; clrf added per Bruce's suggestion
movwf CCP2CON
movf DutyHold1+1,W ; update current position's dutycycle
movwf CCPR1H ; for both servos
movf DutyHold1,W
movwf CCPR1L
movf DutyHold2+1,W
movwf CCPR2H
movf DutyHold2,W
movwf CCPR2L
bcf PIR1,0 ; Clear Timer Int Flag
retfie FAST ; Return from interrupt with shadow regs
EndAsm
-
Hi Darrel,
Pretty cool stuff. Have you tested this on other 18F parts? I don't have a 4520 to test
with, but I couldn't get this to work without clearing CCP1CON before moving 9 to it on
a 452 or 4431.
Had to do this;
Code:
ASM
MyInt
clrf CCP1CON ; 18F452 & 18F4431 require this before it changes CCP1 output
movlw 9
movwf CCP1CON
bcf PIR1,TMR1IF ; clear TMR1 int flag
retfie FAST ; use RETFIE FAST to restore WREG, STATUS & BSR
ENDASM
On an 18F452 or 18F4431, the above works fine, but only if I clear CCP1CON first.
This works on a 452 & 4431 with CCP1 & TMR1 ints enabled on any output pin;
Code:
ASM
MyInt
btfss PIR1,TMR1IF ; TMR1 interrupt?
bra CCP ; no - service CCP interrupt
bcf PIR1,TMR1IF ; yes - clear TMR1 int flag
bsf LATB,0 ; set RB0 on TMR1 interrupt
retfie FAST ; return
CCP
bcf PIR1,CCP1IF ; clear CCP1 int flag
bcf LATB,0 ; clear RB0 on compare interrupt
retfie FAST ; use RETFIE FAST to restore WREG, STATUS & BSR
ENDASM
I was just wondering if this might be a fluke with the 4520 part - since none of the other
18F parts I've tested will toggle CCP1 with just the movlw 9, movwf CCP1CON?
-
Hmmm, very interesting.
I had not tried it on any other chips, and with the 4520 you definitely don't have to clear it first.
But I just tried an 18F452, and you are absolutely correct.
It doesn't work unless you clear the CCPCON register first.
Very interesting indeed,
Thanks Bruce.
<br>
-
Thanks. I was just curious. I had fought with this one before on a servo driver, and just
couldn't get it to work without both ints enabled, or clearing CCP1CON first.
I'm thinking it may be due to the huge number of problems Mchip had (see erratas') on
ECCP & CCP with this one?
-
Quote:
Originally Posted by
Bruce
I'm thinking it may be due to the huge number of problems Mchip had (see erratas') on ECCP & CCP with this one?
No doubt!
BTW, I like the any Output Pin variation too. http://www.picbasic.co.uk/forum/images/icons/icon14.gif
<br>
-
Works good!
Thanks Darrel
Would it be correct to say the maximum PWM frequency for a 40 MHz PIC is 152 Hz?
To slow for music.
Know of any > 10 bit PWM PIC's?
Norm
-
Yup, that's what mister-e's calculator says with 40mhz, 1:1, and 16-bit. 152 hz.
The PIC18F2331/2431/4331/4431 series has a bunch of 14-bit PWM modules. But they are completely different from the CCP module.
Bruce has done a few examples, but I don't think any of them were for music. :eek:
best regards,
-
PIC18F2331/2431/4331/4431:
FOSC 40 MHz
MIPS 10
PWM Resolution 14 bits
PWM Frequency 2.4 kHz
14 bit to slow for CD quality music.
10 bit sounds good though.
A dsPIC would be ideal.
On my first post my code included saving the state of the critical registers.
Would this be required in a longer program?
Norm
-
Maybe you'd be better off with an R2R network as a Digital to Analog Converter.
Something like what Steven Wright did here (Not PBP).
SDMMCWavPlayer
http://www.sfcompiler.co.uk/wiki/pmw...SDMMCWavPlayer
And no, you won't need to save STATUS, WREG and BSR, unless you start using Low Priority interrupts.
The Shadow registers automatically save and restore them in hardware for High priority ints on 18F's.
<br>
-
R2 ladder done here PIC iPod wav player
Now would like to port to PBP a basic PWM low pin count low part count wave player.
The code is 8,069 program bytes possibly less if optimized.
Are their < 28 pin 18F PICs supported by compiler 2.50C?
Norm
-
Quote:
Originally Posted by
Darrel Taylor
.... Pulses will be continuous at ~40hz ....
How do you get ~40-Hz?
<added>
Oops! Sorry! I see it. Timer 1 rollover every 26.2144 msecs (38.14697265625 Hz)... I need another cup o' coffee (grin)...
-
Re: 16 bit PWM using CCP1
Hi Everyone,
Talat from Istanbul here. Please help wıth my PWM problem.
My code is runnıng BUT I get only 1 or 2 output pulses from port B3 on startup then no output after that.
What am ı doıng wrong?
Thanks ın advance fo you help.
Talat
'************************************************* ***************
'* Name : *
'* Author : [select VIEW...EDITOR OPTIONS] *
'* Notice : Copyright (c) 2011 [select VIEW...EDITOR OPTIONS] *
'* : All Rights Reserved *
'* Date : 09.08.2014 *
'* Version : 1.0 *
'* Notes : 16F1827 *
'* : *
'************************************************* ***************
' DEVİCE 16F1827
ASM
__config _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF
__config _CONFIG2, _PLLEN_ON & _LVP_OFF & _LVP_OFF & _STVREN_OFF; & _VCAPEN_OFF
ENDASM
CLEAR
DEFINE OSC 32
OSCCON=%01110000 '32
DEFINE INTHAND PWM_INT
PWM_VAL VAR WORD BANK0 SYSTEM
VALUE VAR WORD
INIT:
APFCON0 = 0 'SET PORTB.3 TO CCP1
T1CON = %00100000 'Prescaler 1:4
PIE1.0 = 1 'TMR1IE TMR1 Interrupt Enable
PIR1.0 = 0 'TMR1IF TMR1 Interrupt Flag
INTCON.7 = 1 'GIE Global Interrupt Enable
INTCON.6 = 1 'PEIE Peripheral Interrupt Enable
CCP1CON = 9 'compare mode
OUTPUT PORTB.3 'CCP PIN
T1CON.0 = 1 'TMR1ON SET TMR1
PAUSE 1000
VALUE=1000
MLOOP:
VALUE=VALUE+1
PWM_VAL = VALUE
Goto MLOOP
Asm
PWM_INT
movlw 9 ; compare mode
clrf CCP1CON ; clear reg
movwf CCP1CON ; Set reg
movf PWM_VAL+1,W ; hb
movwf CCPR1H ; put
movf PWM_VAL,W ; lb
movwf CCPR1L ; put
bsf INTCON,7 ;GIE = 1
bsf INTCON,6 ;PEIE = 1 Enable peripheral interrupts
bsf PIE1,0 ; TMR1IE= 1 Enable TMR1
bcf PIR1,0 ; TMR1IF = 0 Clear Timer1 Int Flag
RETFIE ; Return from Interrupt
EndAsm
END
-
Re: 16 bit PWM using CCP1
Hi Darrel & Everyone,
Talat from Istanbul here. Please help with my PWM problem.
My code is running(?) BUT I get only 1 or 2 output pulses from port B3 on startup then no output after that.
What am I doıng wrong?
Thanks in advance fo you help.
Talat
'************************************************* ***************
'* Name : *
'* Author : [select VIEW...EDITOR OPTIONS] *
'* Notice : Copyright (c) 2011 [select VIEW...EDITOR OPTIONS] *
'* : All Rights Reserved *
'* Date : 09.08.2014 *
'* Version : 1.0 *
'* Notes : 16F1827 *
'* : *
'************************************************* ***************
' DEVİCE 16F1827
ASM
__config _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF
__config _CONFIG2, _PLLEN_ON & _LVP_OFF & _LVP_OFF & _STVREN_OFF; & _VCAPEN_OFF
ENDASM
CLEAR
DEFINE OSC 32
OSCCON=%01110000 '32
DEFINE INTHAND PWM_INT
PWM_VAL VAR WORD BANK0 SYSTEM
VALUE VAR WORD
INIT:
APFCON0 = 0 'SET PORTB.3 TO CCP1
T1CON = %00100000 'Prescaler 1:4
PIE1.0 = 1 'TMR1IE TMR1 Interrupt Enable
PIR1.0 = 0 'TMR1IF TMR1 Interrupt Flag
INTCON.7 = 1 'GIE Global Interrupt Enable
INTCON.6 = 1 'PEIE Peripheral Interrupt Enable
CCP1CON = 9 'compare mode
OUTPUT PORTB.3 'CCP PIN
T1CON.0 = 1 'TMR1ON SET TMR1
PAUSE 1000
VALUE=1000
MLOOP:
VALUE=VALUE+1
PWM_VAL = VALUE
Goto MLOOP
Asm
PWM_INT
movlw 9 ; compare mode
clrf CCP1CON ; clear reg
movwf CCP1CON ; Set reg
movf PWM_VAL+1,W ; hb
movwf CCPR1H ; put
movf PWM_VAL,W ; lb
movwf CCPR1L ; put
bsf INTCON,7 ;GIE = 1
bsf INTCON,6 ;PEIE = 1 Enable peripheral interrupts
bsf PIE1,0 ; TMR1IE= 1 Enable TMR1
bcf PIR1,0 ; TMR1IF = 0 Clear Timer1 Int Flag
RETFIE ; Return from Interrupt
EndAsm
END
-
Re: 16 bit PWM using CCP1
Hi, Talatsahim
First have a look to how PBP shares its variables with asm ...
Alain
-
Re: 16 bit PWM using CCP1
Quote:
Originally Posted by
Acetronics2
Hi, Talatsahim
First have a look to how PBP shares its variables with asm ...
Alain
_WhatsThat ?
-
Re: 16 bit PWM using CCP1
For starters, There is NO 16 bit compare register for PWM use. The upper byte is shared with a few other bits of config. There is ONLY 10 bit's available for PWM use in hardware. Read the data sheet for the processor you are using.
-
Re: 16 bit PWM using CCP1
Hi, Acetronics2
This is part of code. Variable sharing, what is wrong?
Thanx
-
Re: 16 bit PWM using CCP1
Thanx Dave,
I use 10 bit hardware PWM. But I need more resulation. I such a little trick :)
Talat
-
Re: 16 bit PWM using CCP1
What Acetronics2 is trying to say is, when accessing PBP variables inside of an ASM routine you need to prefix an underscore before the variable name such as "movf _PWM_VAL,W ; lb"
As far as getting more resolution from the PIC processor, Your out of luck. You can always build your own digital pwm circuit with hardware if you are so inclined.
-
Re: 16 bit PWM using CCP1
Hi Dave,
This is just copy-paste error..
What's interesting is that, these codes do not work to as 8-bit (10 bit too)
Thanx
-
Re: 16 bit PWM using CCP1
Hi,
Quote:
As far as getting more resolution from the PIC processor, Your out of luck.
So, Microchip themselves and previous posters in the this thread (Darrel, Bruce, Norm) are wrong then, what am I missing?
When using the CCP module in PWM mode it's limited to 10bits resolution. But if you use it in compare mode, the way that the application note describes you can get 16bit resolution but:
1) You won't be able to get 100% dutycycle
2) The maximum output frequency will be limited to ~122Hz @32MHz.
3) You'll get some CPU load from the interrupt processing.
4) You need to deal with assembly code in the ISR (or deal with more "CPU load" if using DT-Ints)
/Henrik.
-
Re: 16 bit PWM using CCP1
Quote:
Originally Posted by
Dave
What Acetronics2 is trying to say is, when accessing PBP variables inside of an ASM routine you need to prefix an underscore before the variable name such as "movf _PWM_VAL,W ; lb"
As far as getting more resolution from the PIC processor, Your out of luck. You can always build your own digital pwm circuit with hardware if you are so inclined.
But Darrel did not do this in his code, prefix with "_". Also as Talat has said he is following Darel's example for "16 bit PWM using CCP1" which obviously worked for Darrel, Bruce and Norm.
So Talat 16 bit PWM is possible. I have read the whole thread and the datasheets for the 18F452 and the chip you are using 16F1827.
The first possible issue Darell said his code was for 18F's only in post 3 does anyone know why not 16F's? The 16F has CCPx compare mode.
With regard to the 16F1827 I think CCP4 has the required features needed and CCP1 does not but I need more time to re-read the datasheet but in the meantime it would be helpful if some one could confirm which CCPx should be used.
-
Re: 16 bit PWM using CCP1
in dt's code the var is declared in a asm routine and as EXT in pbp
Quote:
wDUTY VAR WORD EXT ' map wDuty to CCPR1L:H as a word
@wDUTY = CCPR1L
if you declare a var in pbp and wish to refer to it in asm it must be prefixed with an underscore as others have stated
-
Re: 16 bit PWM using CCP1
Quote:
Originally Posted by
richard
in dt's code the var is declared in a asm routine and as EXT in pbp
if you declare a var in pbp and wish to refer to it in asm it must be prefixed with an underscore as others have stated
That is from post #1 but in #3 which Talat is using
Code:
DutyHold1 VAR WORD BANK0 SYSTEM ' holds next dutycycle, synch with PWM
DutyHold2 VAR WORD BANK0 SYSTEM '
is the way they are declared and again "_" is not used.
-
Re: 16 bit PWM using CCP1
Found the answer in the manual of all places!
Quote:
Modifiers can be used to specify certain attributes of the variable when created:
address A numeric address may be used as a modifier. This instructs PBP where to locate the variable in RAM.
BANKx Instructs PBP to locate the variable in a specific bank of RAM.
SYSTEM The default behavior of PBP is to append a prefix underscore character when creating the variable in Assembly Language. The SYSTEM modifier inhibits this behavior so that the variable name will be identical in PBP code and Assembly code.
Does anyone read the manual, me included obviously?
-
Re: 16 bit PWM using CCP1
-
Re: 16 bit PWM using CCP1
Quote:
Originally Posted by
EarlyBird2
The first possible issue Darell said his code was for 18F's only in post 3 does anyone know why not 16F's? The 16F has CCPx compare mode.
With regard to the 16F1827 I think CCP4 has the required features needed and CCP1 does not but I need more time to re-read the datasheet but in the meantime it would be helpful if some one could confirm which CCPx should be used.
Having dealt with the "_", wild goose chase, which had nothing to do with the problem any ideas?
-
Re: 16 bit PWM using CCP1
I'm trying to get this idea to fly on a 16f1825
the code when converted to C works fine (I get a nice pwm waveform at 60.85 hz)
but it won't fly with pbp3 yet
Code:
/*
* File: newmain.c
* Author: richard
*
* Created on 23 August 2014, 7:25 PM
*/
#include <xc.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
// CONFIG1
#pragma config FOSC = INTOSC // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = ON // Power-up Timer Enable (PWRT enabled)
#pragma config MCLRE = ON // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = ON // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = OFF // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = OFF // Internal/External Switchover (Internal/External Switchover mode is disabled)
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is disabled)
// CONFIG2
#pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = ON // PLL Enable (4x PLL enabled)
#pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LVP = OFF // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)
typedef unsigned char byte;
#define bit_time 100 // 9600 ok @8mhz
#define serout_pin PORTAbits.RA0
#define _XTAL_FREQ 32000000
void send_serial( char data);
void ser_str(char *buff);
byte prnb[20];
uint16_t duty;
void main(void) {
OSCCON=0X70;
ANSELA=0;
ANSELC=0;
TRISA = 0b001110;
TRISC=0b11111001;
PORTA=255;
__delay_ms(2000);
T1CON = 0b00000000 ;
PIE1 = 0b00000001;
INTCON = 0b11000000;
CCP4CON = 0b00001001;
duty = 32768 ;
CCPR4H=duty>>8;
CCPR4L=duty;
T1CONbits.TMR1ON=1;
strcpy(prnb,"ready");
ser_str(prnb);
INTCON=0xc0;
while(1){
strcpy(prnb," loop ");
ser_str(prnb);
sprintf(prnb,"%4x",duty) ;
duty+=200;
ser_str(prnb);
CCPR4H=duty>>8;
CCPR4L=duty;
__delay_ms(2000);
}
return;
}
void interrupt ISR (void) {
CCP4CON=0;
CCP4CON=9;
PIR1bits.TMR1IF=0;
PORTCbits.RC2=!PORTCbits.RC2; // just to check interrupt
}
void send_serial( char data){ // bit_time 200us 4800 baud ,100 us 9600 ,400us 2400 (NOT INVERTED)
uint8_t i;
i=8; // 8 data bits to send
// di();
serout_pin = 0; // make start bit
__delay_us(bit_time);
while(i) // send 8 serial bits, LSB first
{
if(data&1) serout_pin = 1; // invert and send data bit
else serout_pin = 0;
data >>=1 ;//(data >> 1); // rotate right to get next bit
i--;
__delay_us(bit_time); // wait for baud
}
serout_pin = 1; // make stop bit
// ei();
__delay_us(bit_time);
}
void ser_str(char *buff){
char k = strlen(buff);
for (int j=0;j< k;j++){
send_serial(buff[j]);
}
}
-
Re: 16 bit PWM using CCP1
A pbp version
Code:
'****************************************************************
'* Name : PWM16.BAS *
'* Author : RICHARD *
'* Notice : Copyright (c) 2014 [select VIEW...EDITOR OPTIONS] *
'* : All Rights Reserved *
'* Date : 8/23/2014 *
'* Version : 1.0 *
'* Notes : *
'* : *
'****************************************************************
#CONFIG
__config _CONFIG1, _FOSC_INTOSC & _CP_OFF & _WDTE_ON & _PWRTE_ON & _MCLRE_ON & _CLKOUTEN_OFF
__config _CONFIG2, _PLLEN_ON & _LVP_OFF
#ENDCONFIG
include "dt_ints-14.bas"
asm
INT_LIST macro
INT_HANDLER TMR1_INT, _Tm1, asm,yes
endm
INT_CREATE
ENDASM
DEFINE OSC 32
sSEROUT_PIN VAR PORTA.0
sBAUD CON 84 '16416 = 19200 BAUD
yTEMP VAR Byte
wDUTY VAR WORD
'***********************************************
START:
' disable analog functions
OSCCON=$70
ANSELA=0
ANSELC=0
'********************
'16 BIT CCP1 PWM
T1CON = 0 ' Turn off Timer1 with a Prescaler value of 1:8
PIE1 = %00000001 ' enable TMR1 overflow interrupt
INTCON = %11000000 ' enable global and peripheral interrupts
' LOW PORTC.2 ON MATCH TM1 WITH DUTY
ccp4con=0
wDUTY = 32768 ' 32768 = 50% DUTY PWM
T1CON.0 = 1 ' TMR1 ON
CCPR4H=$80;
CCPR4L=0;
PAUSE 800
SerOut2 sSEROUT_PIN,sBAUD,["START",13]
trisc = %11111001
'***********************************************
CCP4CON = %00001001
MAIN:
yTEMP = yTEMP +1
SerOut2 sSEROUT_PIN,sBAUD,["LOOP ",Dec yTEMP,13]
PAUSE 500
Goto MAIN
'**** ASSEMBLY INTERRUPT ROUTINE ****
Tm1:
Asm
bsf PORTC ,2
CHK?RP CCP4CON
clrf CCP4CON
movlw 9
movwf CCP4CON
banksel 0
bcf PORTC ,2
EndAsm
'**** END ASSEMBLY INTURRUPT ROUTINE ****
@ INT_RETURN
End
-
Re: 16 bit PWM using CCP1
Quote:
Originally Posted by
richard
A pbp version
Code:
'****************************************************************
'* Name : PWM16.BAS *
'* Author : RICHARD *
'* Notice : Copyright (c) 2014 [select VIEW...EDITOR OPTIONS] *
'* : All Rights Reserved *
'* Date : 8/23/2014 *
'* Version : 1.0 *
'* Notes : *
'* : *
'****************************************************************
#CONFIG
__config _CONFIG1, _FOSC_INTOSC & _CP_OFF & _WDTE_ON & _PWRTE_ON & _MCLRE_ON & _CLKOUTEN_OFF
__config _CONFIG2, _PLLEN_ON & _LVP_OFF
#ENDCONFIG
include "dt_ints-14.bas"
asm
INT_LIST macro
INT_HANDLER TMR1_INT, _Tm1, asm,yes
endm
INT_CREATE
ENDASM
DEFINE OSC 32
sSEROUT_PIN VAR PORTA.0
sBAUD CON 84 '16416 = 19200 BAUD
yTEMP VAR Byte
wDUTY VAR WORD
'***********************************************
START:
' disable analog functions
OSCCON=$70
ANSELA=0
ANSELC=0
'********************
'16 BIT CCP1 PWM
T1CON = 0 ' Turn off Timer1 with a Prescaler value of 1:8
PIE1 = %00000001 ' enable TMR1 overflow interrupt
INTCON = %11000000 ' enable global and peripheral interrupts
' LOW PORTC.2 ON MATCH TM1 WITH DUTY
ccp4con=0
wDUTY = 32768 ' 32768 = 50% DUTY PWM
T1CON.0 = 1 ' TMR1 ON
CCPR4H=$80;
CCPR4L=0;
PAUSE 800
SerOut2 sSEROUT_PIN,sBAUD,["START",13]
trisc = %11111001
'***********************************************
CCP4CON = %00001001
MAIN:
yTEMP = yTEMP +1
SerOut2 sSEROUT_PIN,sBAUD,["LOOP ",Dec yTEMP,13]
PAUSE 500
Goto MAIN
'**** ASSEMBLY INTERRUPT ROUTINE ****
Tm1:
Asm
bsf PORTC ,2
CHK?RP CCP4CON
clrf CCP4CON
movlw 9
movwf CCP4CON
banksel 0
bcf PORTC ,2
EndAsm
'**** END ASSEMBLY INTURRUPT ROUTINE ****
@ INT_RETURN
End
Impressive Richard!
What was the difference CCP4?
-
Re: 16 bit PWM using CCP1
no any ccp will work I tested it on 2,3 and 4 , the issue was the Bank selection a pic18 doesn't need it a pic16 will die without it
-
Re: 16 bit PWM using CCP1
Code:
'************************************************* ***************
'* Name : *
'* Author : [select VIEW...EDITOR OPTIONS] *
'* Notice : Copyright (c) 2011 [select VIEW...EDITOR OPTIONS] *
'* : All Rights Reserved *
'* Date : 09.08.2014 *
'* Version : 1.0 *
'* Notes : 16F1827 *
'* : *
'************************************************* ***************
' DEVİCE 16F1827
ASM
__config _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF
__config _CONFIG2, _PLLEN_ON & _LVP_OFF & _LVP_OFF & _STVREN_OFF; & _VCAPEN_OFF
ENDASM
CLEAR
DEFINE OSC 32
OSCCON=%01110000 '32
DEFINE INTHAND PWM_INT
PWM_VAL VAR WORD BANK0 SYSTEM
VALUE VAR WORD
INIT:
APFCON0 = 0 'SET PORTB.3 TO CCP1
T1CON = %00100000 'Prescaler 1:4
PIE1.0 = 1 'TMR1IE TMR1 Interrupt Enable
PIR1.0 = 0 'TMR1IF TMR1 Interrupt Flag
INTCON.7 = 1 'GIE Global Interrupt Enable
INTCON.6 = 1 'PEIE Peripheral Interrupt Enable
CCP1CON = 9 'compare mode
OUTPUT PORTB.3 'CCP PIN
T1CON.0 = 1 'TMR1ON SET TMR1
PAUSE 1000
VALUE=1000
MLOOP:
VALUE=VALUE+1
PWM_VAL = VALUE
Goto MLOOP
Asm
PWM_INT
movlw 9 ; compare mode
clrf CCP1CON ; clear reg
movwf CCP1CON ; Set reg
movf PWM_VAL+1,W ; hb
movwf CCPR1H ; put
movf PWM_VAL,W ; lb
movwf CCPR1L ; put
bsf INTCON,7 ;GIE = 1
bsf INTCON,6 ;PEIE = 1 Enable peripheral interrupts
bsf PIE1,0 ; TMR1IE= 1 Enable TMR1
bcf PIR1,0 ; TMR1IF = 0 Clear Timer1 Int Flag
RETFIE ; Return from Interrupt
EndAsm
END
Now we know that what you want to do is possible, thanks to Richard. Can anyone work out what is wrong with Talat's code?
-
Re: 16 bit PWM using CCP1
I didn't pickup what ver of pbp talat was using , and I'm not sure if the chk?rp macro exists in early versions
but try
Code:
Asm
PWM_INT
CHK?RP CCP1CON
movlw 9 ; compare mode
clrf CCP1CON ; clear reg
movwf CCP1CON ; Set reg
CHK?RP PWM_VAL
movf PWM_VAL+1,W ; hb
CHK?RP CCPRIL
movwf CCPR1H ; put
CHK?RP PWM_VAL
movf PWM_VAL,W ; lb
CHK?RP CCPRIL
movwf CCPR1L ; put
banksel 0
bsf INTCON,7 ;GIE = 1
bsf INTCON,6 ;PEIE = 1 Enable peripheral interrupts
bsf PIE1,0 ; TMR1IE= 1 Enable TMR1
bcf PIR1,0 ; TMR1IF = 0 Clear Timer1 Int Flag
RETFIE ; Return from Interrupt
EndAsm
if that fails try
banksel CCP1CON OR WHATERVER SFR
OR
read data sheet and find what bank each sfr is in
with all that bank switching the effort may be pointless
-
Re: 16 bit PWM using CCP1
a warning to anybody trying to use this idea , its not fool proof and apart from the limitations as described by henrik its a bit risky too.
Quote:
if you try to set the pwm duty below the number of timer ticks taken up during the interrupt latency the pwm pin will be driven high and may cause unexpected results
my tests indicate a minimum pwm duty of 30
caveat emptor
-
Re: 16 bit PWM using CCP1
post 35 is wrong pie1 is not in bank0 either
Code:
Asm
PWM_INT
CHK?RP CCP1CON
movlw 9 ; compare mode
clrf CCP1CON ; clear reg
movwf CCP1CON ; Set reg
CHK?RP PWM_VAL
movf PWM_VAL+1,W ; hb
CHK?RP CCPRIL
movwf CCPR1H ; put
CHK?RP PWM_VAL
movf PWM_VAL,W ; lb
CHK?RP CCPRIL
movwf CCPR1L ; put
banksel 0
bsf INTCON,7 ;GIE = 1
bsf INTCON,6 ;PEIE = 1 Enable peripheral interrupts
CHK?RP PIE1
bsf PIE1,0 ; TMR1IE= 1 Enable TMR1
BANKSEL 0
bcf PIR1,0 ; TMR1IF = 0 Clear Timer1 Int Flag
RETFIE ; Return from Interrupt
EndAsm
it just gets worse
-
Re: 16 bit PWM using CCP1
Richard and EarlyBird,
Thank you very much for your generosity and support.
I'm using version 3.0.1.4.
:)
Talat
-
Re: 16 bit PWM using CCP1
Talat
I do not understand why you included the lines in red in you ISR
Code:
'************************************************* ***************
'* Name : *
'* Author : [select VIEW...EDITOR OPTIONS] *
'* Notice : Copyright (c) 2011 [select VIEW...EDITOR OPTIONS] *
'* : All Rights Reserved *
'* Date : 09.08.2014 *
'* Version : 1.0 *
'* Notes : 16F1827 *
'* : *
'************************************************* ***************
' DEVİCE 16F1827
ASM
__config _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF
__config _CONFIG2, _PLLEN_ON & _LVP_OFF & _LVP_OFF & _STVREN_OFF; & _VCAPEN_OFF
ENDASM
CLEAR
DEFINE OSC 32
OSCCON=%01110000 '32
DEFINE INTHAND PWM_INT
PWM_VAL VAR WORD BANK0 SYSTEM
VALUE VAR WORD
INIT:
APFCON0 = 0 'SET PORTB.3 TO CCP1
T1CON = %00100000 'Prescaler 1:4
PIE1.0 = 1 'TMR1IE TMR1 Interrupt Enable
PIR1.0 = 0 'TMR1IF TMR1 Interrupt Flag
INTCON.7 = 1 'GIE Global Interrupt Enable
INTCON.6 = 1 'PEIE Peripheral Interrupt Enable
CCP1CON = 9 'compare mode
OUTPUT PORTB.3 'CCP PIN
T1CON.0 = 1 'TMR1ON SET TMR1
PAUSE 1000
VALUE=1000
MLOOP:
VALUE=VALUE+1
PWM_VAL = VALUE
Goto MLOOP
Asm
PWM_INT
movlw 9 ; compare mode
clrf CCP1CON ; clear reg
movwf CCP1CON ; Set reg
movf PWM_VAL+1,W ; hb
movwf CCPR1H ; put
movf PWM_VAL,W ; lb
movwf CCPR1L ; put
bsf INTCON,7 ;GIE = 1
bsf INTCON,6 ;PEIE = 1 Enable peripheral interrupts
bsf PIE1,0 ; TMR1IE= 1 Enable TMR1
bcf PIR1,0 ; TMR1IF = 0 Clear Timer1 Int Flag
RETFIE ; Return from Interrupt
EndAsm
END
As I do not have a 16F1827 I can not do any testing. But after some thought I used an 18F452 to test your code and it did not work. I then compared data sheets for the 16F1827 and 18F452 and finding no reason for the lines in red I commented them out reprogramed the 18F452 and it ran. But I had to add a pause 10 in the main loop so my voltmeter could display the readings.
Here is my version
Code:
'************************************************* ***************
'* Name : *
'* Author : [select VIEW...EDITOR OPTIONS] *
'* Notice : Copyright (c) 2011 [select VIEW...EDITOR OPTIONS] *
'* : All Rights Reserved *
'* Date : 09.08.2014 *
'* Version : 1.0 *
'* Notes : 16F1827 *
'* : *
'************************************************* ***************
' DEVİCE 16F1827
ASM
__config _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF
__config _CONFIG2, _PLLEN_ON & _LVP_OFF & _LVP_OFF & _STVREN_OFF; & _VCAPEN_OFF
ENDASM
CLEAR
DEFINE OSC 32
OSCCON=%01110000 '32
DEFINE INTHAND PWM_INT
PWM_VAL VAR WORD BANK0 SYSTEM
INIT:
APFCON0 = 0 'SET PORTB.3 TO CCP1
T1CON = %00100000 'Prescaler 1:4
PIE1.0 = 1 'TMR1IE TMR1 Interrupt Enable
PIR1.0 = 0 'TMR1IF TMR1 Interrupt Flag
INTCON.7 = 1 'GIE Global Interrupt Enable
INTCON.6 = 1 'PEIE Peripheral Interrupt Enable
CCP1CON = 9 'compare mode
OUTPUT PORTB.3 'CCP PIN
T1CON.0 = 1 'TMR1ON SET TMR1
PAUSE 1000
MLOOP:
PWM_VAL = PWM_VAL+1
PAUSE 10
Goto MLOOP
Asm
PWM_INT
movlw 9 ; compare mode
clrf CCP1CON ; clear reg
movwf CCP1CON ; Set reg
movf PWM_VAL+1,W ; hb
movwf CCPR1H ; put
movf PWM_VAL,W ; lb
movwf CCPR1L ; put
bcf PIR1,0 ; TMR1IF = 0 Clear Timer1 Int Flag
RETFIE ; Return from Interrupt
EndAsm
END
I am very interested to know if my version works on the 16F1827 that you have.
-
Re: 16 bit PWM using CCP1
your version cannot work since CCP1CON and CCPR1H are not in bank 0
and yes the code you marked red serves no purpose in the given example