|
|
View previous topic :: View next topic |
Author |
Message |
mellemhere
Joined: 14 Feb 2018 Posts: 4 Location: Brazil
|
CCP PWM Strange behavior - Brief failing |
Posted: Wed Feb 14, 2018 2:49 pm |
|
|
Hello all,
I am trying generate a PWM using CCP and change its frequency on the fly, going from 1.15KHz to 3.28kHz in 180ms.
I am using:
PIC: 16F887
Frequency: 4MHz (internal)
Compiler: CCS PCM C Compiler, Version 5.008
My problem is: My code is generating the PWM and going from 1.15KHz to 3.28kHz (50% duty) in 180ms as I wish to active, but it is also generating "holes", gaps, where nothing happens for some time.
This gaps goes from 3,7ms to 4,07ms, as shown by this image I could get from my oscilloscope:
I am doing this using the following code:
main.h
Code: |
#include <16F887.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES HS //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#FUSES NOPUT //No Power Up Timer
#FUSES NOMCLR //Master Clear pin used for I/O
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOCPD //No EE protection
#FUSES NOBROWNOUT //No brownout reset
#FUSES IESO //Internal External Switch Over mode enabled
#FUSES FCMEN //Fail-safe clock monitor enabled
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOWRT //Program memory not write protected
#FUSES BORV40 //Brownout reset at 4.0V
#FUSES RESERVED //Used to set the reserved FUSE bits
#use delay(clock=4000000)
|
main.c
Code: |
/*
Effect vars
*/
short STATE = 1;
int PR_VALUE = 33;
short CHANGED = 0;
int16 counter = 0;
#int_RDA
void RDA_isr(void)
{
//TO-DO
}
/*
Runs every 256us
*/
#int_RTCC
void RTCC_isr(void)
{
counter++;
}
/*
Performs a step every 20x256us = 5.12ms
Goes from 53 (1.15KHz) to 18 (3.28Khz)
*/
void EFFECT(){
if(counter >= 20){
CHANGED = 1;
if(STATE){
PR_VALUE++;
if(PR_VALUE >= 53) STATE = 0;
}else{
PR_VALUE--;
if(PR_VALUE <= 18) STATE = 1;
}
counter = 0;
}
if(CHANGED){
CHANGED = 0;
setup_timer_2(T2_DIV_BY_16, PR_VALUE, 1);
set_pwm1_duty(PR_VALUE/2);
set_pwm2_duty(PR_VALUE/2);
}
}
void main()
{
setup_comparator(NC_NC_NC_NC);
setup_adc_ports(NO_ANALOGS|VSS_VDD);
setup_adc(ADC_CLOCK_DIV_2);
setup_spi(SPI_SS_DISABLED);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_oscillator(OSC_4MHZ);
enable_interrupts(INT_RTCC);
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
setup_ccp1(CCP_PWM_L_H);
setup_ccp2(CCP_PWM_H_L);
while(1){
EFFECT();
}
}
|
Things I have done trying to fix this problem:
- Removed the counter and added a push button and for every push I incremented the PR value, I went from 18 1.15KHz to 3.28Khz without this "holes" appearing
- Attached an square wave frequency generator to the input where the push button was and noticed that the fasted I changed the PR more "holes" appeared
Any ideas how I am able to remove this weird errors? |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9229 Location: Greensville,Ontario
|
|
Posted: Wed Feb 14, 2018 3:12 pm |
|
|
OK, wild idea but.. change pr_value to an unsigned 16 bit and use 33L not 33.
The timer register is 16 bit so the upper byte might be anything. The 33L forces 33 to be 16 bits.not just 8 bits, so it'll properly set the register.
I'm not sure if this will work, but it has been seen in the past. A dump of the listing would show if the compiler is setting BOTH high and low bytes or just the low byte.
If nothing else it's easy to try and if it works, great if not, well...we've eliminated that possiblity.
Jay |
|
|
mellemhere
Joined: 14 Feb 2018 Posts: 4 Location: Brazil
|
|
Posted: Wed Feb 14, 2018 3:27 pm |
|
|
Hi Jay! Thanks for the reply
I have performed the changes you sugested, changed the pr_value to an unsigned int16 and added the L after the 33. As you can see this is my code right now:
Code: |
short STATE = 1;
unsigned int16 PR_VALUE = 33L;
short CHANGED = 0;
int16 counter = 0;
|
The rest of the code is unchanged.
Running this code I still have those "holes" and for some reason my duty cycle is not 50% anymore, but it doesn't matter much.
This is what I see now:
Sorry if it is a noob question, but how can I get the dump of the listing?
Thanks for replying!
*Edit: Changing unsigned int16 PR_VALUE = 33L; to unsigned int PR_VALUE = 33L; brought back the 50% duty but still have those "holes" |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9229 Location: Greensville,Ontario
|
|
Posted: Wed Feb 14, 2018 3:34 pm |
|
|
list is
project's filename.lst
so whatever you named the project or source with a dotLST after it.
If using MPLAB, you can see it by selecting 'view', then select 'disassembly listing'.
Jay |
|
|
mellemhere
Joined: 14 Feb 2018 Posts: 4 Location: Brazil
|
|
Posted: Wed Feb 14, 2018 3:36 pm |
|
|
This is my listing:
Code: |
CCS PCM C Compiler, Version 5.008, 5967 14-fev-18 19:28
Filename: main.lst
ROM used: 234 words (3%)
Largest free fragment is 2048
RAM used: 17 (5%) at main() level
18 (5%) worst case
Stack used: 2 locations (1 in main + 1 for interrupts)
Stack size: 8
*
0000: MOVLW 00
0001: MOVWF 0A
0002: GOTO 070
0003: NOP
0004: MOVWF 7F
0005: SWAPF 03,W
0006: CLRF 03
0007: MOVWF 21
0008: MOVF 0A,W
0009: MOVWF 20
000A: CLRF 0A
000B: MOVF 04,W
000C: MOVWF 22
000D: MOVF 77,W
000E: MOVWF 23
000F: MOVF 78,W
0010: MOVWF 24
0011: MOVF 79,W
0012: MOVWF 25
0013: MOVF 7A,W
0014: MOVWF 26
0015: BCF 03.7
0016: BCF 03.5
0017: BTFSS 0B.5
0018: GOTO 01B
0019: BTFSC 0B.2
001A: GOTO 032
001B: MOVLW 8C
001C: MOVWF 04
001D: BTFSS 00.5
001E: GOTO 021
001F: BTFSC 0C.5
0020: GOTO 035
0021: MOVF 22,W
0022: MOVWF 04
0023: MOVF 23,W
0024: MOVWF 77
0025: MOVF 24,W
0026: MOVWF 78
0027: MOVF 25,W
0028: MOVWF 79
0029: MOVF 26,W
002A: MOVWF 7A
002B: MOVF 20,W
002C: MOVWF 0A
002D: SWAPF 21,W
002E: MOVWF 03
002F: SWAPF 7F,F
0030: SWAPF 7F,W
0031: RETFIE
0032: BCF 0A.3
0033: BCF 0A.4
0034: GOTO 03C
0035: BCF 0A.3
0036: BCF 0A.4
0037: GOTO 038
.................... #include "main.h"
.................... #include <16F887.h>
.................... //////// Standard Header file for the PIC16F887 device ////////////////
.................... #device PIC16F887
....................
.................... #list
....................
.................... #device adc=8
....................
.................... #FUSES NOWDT //No Watch Dog Timer
.................... #FUSES HS //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
.................... #FUSES NOPUT //No Power Up Timer
.................... #FUSES NOMCLR //Master Clear pin used for I/O
.................... #FUSES NOPROTECT //Code not protected from reading
.................... #FUSES NOCPD //No EE protection
.................... #FUSES NOBROWNOUT //No brownout reset
.................... #FUSES IESO //Internal External Switch Over mode enabled
.................... #FUSES FCMEN //Fail-safe clock monitor enabled
.................... #FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
.................... #FUSES NODEBUG //No Debug mode for ICD
.................... #FUSES NOWRT //Program memory not write protected
.................... #FUSES BORV40 //Brownout reset at 4.0V
.................... #FUSES RESERVED //Used to set the reserved FUSE bits
....................
.................... #use delay(clock=4000000)
.................... #use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
....................
....................
....................
....................
....................
.................... /*
.................... Effect vars
.................... */
.................... short STATE = 1;
.................... unsigned int PR_VALUE = 33L;
.................... short CHANGED = 0;
.................... int16 counter = 0;
....................
.................... #int_RDA
.................... void RDA_isr(void)
.................... {
.................... //p_charRecived();
.................... }
....................
....................
.................... /*
.................... Runs every 256us
.................... */
0038: BCF 0C.5
0039: BCF 0A.3
003A: BCF 0A.4
003B: GOTO 021
.................... #int_RTCC
.................... void RTCC_isr(void)
.................... {
.................... counter++;
003C: INCF 29,F
003D: BTFSC 03.2
003E: INCF 2A,F
003F: BCF 0B.2
0040: BCF 0A.3
0041: BCF 0A.4
0042: GOTO 021
.................... }
....................
.................... /*
.................... Performs a step every 20x256us = 5.12ms
.................... Goes from 53 (1.15KHz) to 18 (3.28Khz)
.................... */
.................... void EFFECT(){
.................... if(counter >= 20){
0043: MOVF 2A,F
0044: BTFSS 03.2
0045: GOTO 04A
0046: MOVF 29,W
0047: SUBLW 13
0048: BTFSC 03.0
0049: GOTO 05A
.................... CHANGED = 1;
004A: BSF 27.1
.................... if(STATE){
004B: BTFSS 27.0
004C: GOTO 053
.................... PR_VALUE++;
004D: INCF 28,F
.................... if(PR_VALUE >= 53) STATE = 0;
004E: MOVF 28,W
004F: SUBLW 34
0050: BTFSS 03.0
0051: BCF 27.0
.................... }else{
0052: GOTO 058
.................... PR_VALUE--;
0053: DECF 28,F
.................... if(PR_VALUE <= 18) STATE = 1;
0054: MOVF 28,W
0055: SUBLW 12
0056: BTFSC 03.0
0057: BSF 27.0
.................... }
....................
.................... counter = 0;
0058: CLRF 2A
0059: CLRF 29
.................... }
....................
.................... if(CHANGED){
005A: BTFSS 27.1
005B: GOTO 06D
.................... CHANGED = 0;
005C: BCF 27.1
....................
.................... setup_timer_2(T2_DIV_BY_16, PR_VALUE, 1);
005D: MOVLW 00
005E: MOVWF 78
005F: IORLW 06
0060: MOVWF 12
0061: MOVF 28,W
0062: BSF 03.5
0063: MOVWF 12
.................... set_pwm1_duty(PR_VALUE/2);
0064: BCF 03.0
0065: BCF 03.5
0066: RRF 28,W
0067: MOVWF 2C
0068: MOVWF 15
.................... set_pwm2_duty(PR_VALUE/2);
0069: BCF 03.0
006A: RRF 28,W
006B: MOVWF 2C
006C: MOVWF 1B
.................... }
006D: BCF 0A.3
006E: BCF 0A.4
006F: GOTO 0E8 (RETURN)
.................... }
....................
....................
....................
....................
.................... void main()
0070: MOVF 03,W
0071: ANDLW 1F
0072: MOVWF 03
0073: BSF 03.5
0074: BSF 03.6
0075: BCF 07.3
0076: MOVLW 19
0077: BCF 03.6
0078: MOVWF 19
0079: MOVLW A6
007A: MOVWF 18
007B: MOVLW 90
007C: BCF 03.5
007D: MOVWF 18
007E: BSF 27.0
007F: MOVLW 21
0080: MOVWF 28
0081: BCF 27.1
0082: CLRF 2A
0083: CLRF 29
0084: MOVLW FF
0085: MOVWF 2B
0086: BSF 03.5
0087: BSF 03.6
0088: MOVF 09,W
0089: ANDLW C0
008A: MOVWF 09
008B: BCF 03.6
008C: BCF 1F.4
008D: BCF 1F.5
008E: MOVLW 00
008F: BSF 03.6
0090: MOVWF 08
0091: BCF 03.5
0092: CLRF 07
0093: CLRF 08
0094: CLRF 09
0095: BCF 03.7
.................... {
....................
.................... setup_comparator(NC_NC_NC_NC);
0096: CLRF 07
0097: CLRF 08
0098: CLRF 09
.................... setup_adc_ports(NO_ANALOGS|VSS_VDD);
0099: BSF 03.5
009A: MOVF 09,W
009B: ANDLW C0
009C: MOVWF 09
009D: BCF 03.6
009E: BCF 1F.4
009F: BCF 1F.5
00A0: MOVLW 00
00A1: BSF 03.6
00A2: MOVWF 08
.................... setup_adc(ADC_CLOCK_DIV_2);
00A3: BCF 03.5
00A4: BCF 03.6
00A5: BCF 1F.6
00A6: BCF 1F.7
00A7: BSF 03.5
00A8: BCF 1F.7
00A9: BCF 03.5
00AA: BSF 1F.0
.................... setup_spi(SPI_SS_DISABLED);
00AB: BCF 14.5
00AC: BCF 2B.5
00AD: MOVF 2B,W
00AE: BSF 03.5
00AF: MOVWF 07
00B0: BCF 03.5
00B1: BSF 2B.4
00B2: MOVF 2B,W
00B3: BSF 03.5
00B4: MOVWF 07
00B5: BCF 03.5
00B6: BCF 2B.3
00B7: MOVF 2B,W
00B8: BSF 03.5
00B9: MOVWF 07
00BA: MOVLW 01
00BB: BCF 03.5
00BC: MOVWF 14
00BD: MOVLW 00
00BE: BSF 03.5
00BF: MOVWF 14
....................
.................... setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
00C0: MOVF 01,W
00C1: ANDLW C7
00C2: IORLW 08
00C3: MOVWF 01
....................
.................... setup_timer_1(T1_DISABLED);
00C4: BCF 03.5
00C5: CLRF 10
....................
.................... setup_oscillator(OSC_4MHZ);
00C6: MOVLW 61
00C7: BSF 03.5
00C8: MOVWF 0F
00C9: MOVF 0F,W
....................
.................... enable_interrupts(INT_RTCC);
00CA: BCF 03.5
00CB: BSF 0B.5
....................
.................... enable_interrupts(INT_RDA);
00CC: BSF 03.5
00CD: BSF 0C.5
....................
.................... enable_interrupts(GLOBAL);
00CE: MOVLW C0
00CF: BCF 03.5
00D0: IORWF 0B,F
....................
.................... setup_ccp1(CCP_PWM_L_H);
00D1: BCF 2B.2
00D2: MOVF 2B,W
00D3: BSF 03.5
00D4: MOVWF 07
00D5: BCF 03.5
00D6: BCF 07.2
00D7: MOVLW 0E
00D8: MOVWF 17
00D9: BSF 03.5
00DA: CLRF 1B
00DB: CLRF 1C
00DC: MOVLW 01
00DD: MOVWF 1D
.................... setup_ccp2(CCP_PWM_H_L);
00DE: BCF 03.5
00DF: BCF 2B.1
00E0: MOVF 2B,W
00E1: BSF 03.5
00E2: MOVWF 07
00E3: BCF 03.5
00E4: BCF 07.1
00E5: MOVLW 0D
00E6: MOVWF 1D
....................
.................... while(1){
.................... EFFECT();
00E7: GOTO 043
00E8: GOTO 0E7
.................... }
.................... }
....................
00E9: SLEEP
Configuration Fuses:
Word 1: 2CD2 HS NOWDT NOPUT NOMCLR NOPROTECT NOCPD NOBROWNOUT IESO FCMEN NOLVP NODEBUG
Word 2: 3FFF BORV40 NOWRT |
|
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9229 Location: Greensville,Ontario
|
|
Posted: Wed Feb 14, 2018 7:21 pm |
|
|
OK, I was wrong...timer 2 for the 16F887 is ONLY 8 bits...for some reason I thought it was 16 bits...arrgh.. too many PICs ..
The listing does show an important detail though. The compiler you're using is 5.008. very very 'young'. Hopefully someone can test on their system, me, well, 'somehow' Windows just lost 24,000+ PIC files while I was out, so I have a huge nightmare to deal with once the sun comes up.
Jay |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Thu Feb 15, 2018 2:40 am |
|
|
I've input a modified version, with several comments 'inline'.
See if this improves on things.
Code: |
#include <16F887.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES HS //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#FUSES NOPUT //No Power Up Timer
#FUSES NOMCLR //Master Clear pin used for I/O
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOCPD //No EE protection
#FUSES NOBROWNOUT //No brownout reset
#FUSES IESO //Internal External Switch Over mode enabled
#FUSES FCMEN //Fail-safe clock monitor enabled
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOWRT //Program memory not write protected
#FUSES BORV40 //Brownout reset at 4.0V
#FUSES RESERVED //Used to set the reserved FUSE bits
#use delay(clock=4000000)
#define UP TRUE
#define DOWN FALSE
/*
Effect vars
*/
short State = UP; //start counting up
int8 Pr_Value = 33;
int8 counter = 0;
//As a general comment, it is a standard in C, to reserve ALLCAPITALS
//for #defines, and ENUM values. Helps to give an immediate 'hint' as to what
//a value actually 'is'. Have changed the variable names here to this form.
/*
Runs every 1024us
*/
#int_RTCC
void RTCC_isr(void)
{
counter++;
}
/*
Performs a step every 5*1024us = 5.12ms
Goes from 53 (1.15KHz) to 18 (3.28Khz)
*/
void Effect(void)
{
if(counter >= 5)
{
counter = 0;
if(State==UP)
{
Pr_Value++;
if(Pr_Value >= 53)
State = DOWN;
}
else
{
Pr_Value--;
if(Pr_Value <= 18)
State = UP;
}
//Here it has changed. Why test again?....
clear_interrupt(INT_TIMER2); //wait for Timer2 to update
while (!interrupt_active(INT_TIMER2))
;
//now reprogram the timer only in the moment after a cycle finishes
setup_timer_2(T2_DIV_BY_16, PR_VALUE, 1);
set_pwm1_duty(((int16)PR_VALUE)*2);
set_pwm2_duty(((int16)PR_VALUE)*2);
}
}
void main()
{
setup_oscillator(OSC_4MHZ);
setup_comparator(NC_NC_NC_NC);
setup_adc_ports(NO_ANALOGS|VSS_VDD);
setup_adc(ADC_CLOCK_DIV_8);
//DIV_2 is too fast. At 4MHz DIV_8 is needed
setup_spi(FALSE);
//correct command to disable SPI
setup_timer_0(RTCC_INTERNAL|T0_DIV_4);
//Slight problem here. DIV_1 means this interrupt will be triggering every 256
//instructions. *4 takes this to 1024. At 256 instructions, about 1/4 of your
//entire processor time will be used to just handle the counter....
setup_timer_1(T1_DISABLED);
enable_interrupts(INT_RTCC);
//enable_interrupts(INT_RDA); //Don't enable this till you have a handler
//That actually reads the character. Otherwise chip will be hung.
enable_interrupts(GLOBAL);
setup_ccp1(CCP_PWM_L_H);
setup_ccp2(CCP_PWM_H_L);
while(TRUE)
{
Effect();
}
}
|
The change affecting what you are seeing, is I now update the PWM, only immediately after the PWM timer resets. This avoids a problem if the timer has already _passed_ the PR2 value when you set it to a lower value.
So (for instance), imagine the timer is at 49, and you set PR2 to 49. The set takes effect on the next cycle, so PR2 is set to 49, and the timer is now at 50. At this point it'll count up to 255, reset, and then count up to 49, and so you get a 'long' cycle about 6* the value it ought to have.... |
|
|
mellemhere
Joined: 14 Feb 2018 Posts: 4 Location: Brazil
|
|
Posted: Thu Feb 15, 2018 7:27 am |
|
|
Hi! Thank you so much for the reply.
I ran your code and got no output. After a little bit of debugging I found out that the following two lines were the cause of this.
Code: |
//Here it has changed. Why test again?....
clear_interrupt(INT_TIMER2); //wait for Timer2 to update
while (!interrupt_active(INT_TIMER2));
|
If I have this two lines in the code nothing happens (no output), if I remove them I have an output but with those "holes". What could it be?
Another way I tried to sove this was by adding the following statement to my code:
Code: |
if(get_timer2() > PR_VALUE){
set_timer2(PR_VALUE);
}
|
Making my Effect function look like this:
Code: |
if(counter >= 5){
CHANGED = 1;
if(!state){
PR_VALUE++;
if(PR_VALUE >= 53) STATE = 1;
}else{
PR_VALUE--;
if(PR_VALUE <= 18) STATE = 0;
}
counter = 0;
}
if(CHANGED){
CHANGED = 0;
if(get_timer2() > PR_VALUE){
set_timer2(PR_VALUE);
}
setup_timer_2(T2_DIV_BY_16, PR_VALUE, 1);
set_pwm1_duty(PR_VALUE/2);
set_pwm2_duty(PR_VALUE/2);
}
|
It made the holes appear much less frequently, but I can still see some once or twice in the oscilloscope.
Thank you so much for the help! Hope we can find out why those two lines of your code are blocking the flow, because your code is much better than mine. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Thu Feb 15, 2018 9:30 am |
|
|
OK. That almost certainly means your compiler version has a fault in the handling of this bit. It is a very early version.
You can program round with:
Code: |
#byte PIR1 = 0xC //given the age I'm not trusting getenv
#bit TMR2IF = PIR1.1
//Then use
TMR2IF=FALSE;
while (TMR2IF==FALSE)
;
|
You are still adding the extra test for changed. Pointless. |
|
|
|
|
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
|