|
|
View previous topic :: View next topic |
Author |
Message |
Blob
Joined: 02 Jan 2006 Posts: 75 Location: Neeroeteren, Limburg, Belgium
|
ccp1 & 2 |
Posted: Tue Feb 14, 2012 7:08 am |
|
|
Hello all,
I am using both ccp1 and ccp2 in compare mode.
I am also sharing Timer3 for ccp1&2
they receive the same ccp value => CCP_1 = CCP_2
However their output is not the same at all (checked with scope)
Code: |
output_high(pin1);
output_high(pin2);
set_timer3(0);
CCP_1 = time;
CCP_2 = time; //same as CCP_1
setup_ccp1(CCP_USE_TIMER3 | CCP_COMPARE_CLR_ON_MATCH);
setup_ccp2(CCP_USE_TIMER3 | CCP_COMPARE_CLR_ON_MATCH); |
The datasheet of the pic18f2620 states: Quote: | Either module can be configured for the Special Event Trigger to reset the time base.
Automatic A/D conversions on CCP2 trigger event can be done. Conflicts may occur if
both modules are using the same time base. |
Does this apply to my application or only when using automatic A/D?
Thanks in advance,
Blob |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Tue Feb 14, 2012 7:31 am |
|
|
First tell us 'what chip'. Though the modules are pretty universal, there are small differences between chips.
Generally though, all the special event triggers clear the counter, so will interfere between the modules. For example (from the 18F2620/4620 data sheet, section 15.3.4) -
"For either CCP module, the Special Event Trigger resets the timer register pair for whichever timer resource is currently assigned as the module’s time base. This allows the CCPRx registers to serve as a programmable period register for either timer.
The Special Event Trigger for CCP2 can also start an A/D conversion. In order to do this, the A/D converter must already be enabled".
So your code will reset the counter when it triggers.
You really need to switch one CCP to use the other timer (normally timer1), to avoid this.
Best Wishes |
|
|
Blob
Joined: 02 Jan 2006 Posts: 75 Location: Neeroeteren, Limburg, Belgium
|
|
Posted: Tue Feb 14, 2012 8:05 am |
|
|
Hello,
indeed that is what the manual says for my 18f2620 I/SO
but it also states in 15.1.1
Quote: | The assignment of a particular timer to a module is
determined by the Timer-to-CCP enable bits in the
T3CON register (Register 14-1). Both modules may be
active at any given time and may share the same timer
resource if they are configured to operate in the same
mode (Capture/Compare or PWM) at the same time. |
Is there a way to disable the special event trigger?
Thanks,
Blob |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Tue Feb 14, 2012 8:17 am |
|
|
Generate a software interrupt on match, and reset the pin inside this. Will have the latency of the interrupt handler, but then the modules won't interfere with each other.
Best Wishes |
|
|
Blob
Joined: 02 Jan 2006 Posts: 75 Location: Neeroeteren, Limburg, Belgium
|
|
Posted: Tue Mar 13, 2012 7:31 am |
|
|
Hello,
I tried to generate a software interrupt as Ttelmah suggested.
I have timer 1 for CCP_1
and timer 3 for CCP_2
Both are in compare mode.
The idea is to open 2 valves for a short time based on the position of a rotating wheel.
The wheel has 12 teeth to determine the position.
At a given position vs rpm the valves must open.
CCP_1 will always start at the same position (6)
the pin will be driven high at position 6 and CCP_1 will generate an interrupt to drive it low.
CCP_2 will not have a fix starting point, it will have a floating start and a floating end point.
At a position CCP_2 will generate an interrupt to drive the pin high.
At another position CCP_2 will generate an interrupt to drive the pin low.
This works well with interrupt mode and with special event triggers.
But when the start of CCP2 comes before the interrupt of CCP1 the output of CCP1 changes.
I tried with interrupt mode and special event triggers, both give the same result...
Somehow CCP2 will distort CCP1.
Does someone have an idea?
Thanks |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
Blob
Joined: 02 Jan 2006 Posts: 75 Location: Neeroeteren, Limburg, Belgium
|
|
Posted: Wed Mar 14, 2012 2:57 am |
|
|
hello,
here it is
I am using 4.038
Code: |
#include <18F2620.h>
#device ADC=8
#include <stdlib.h>
#fuses H4 //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#fuses NOWDT //No Watch Dog Timer
#fuses PUT //Power Up Timer
#fuses BORV28 //Brownout reset at 2.8V
#fuses NOIESO //Internal External Switch Over mode disabled
#fuses NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#fuses NOWRTD //Data EEPROM write protected => ook interne schrijfopdrachten blokkeren**
#fuses WRTC //configuration registers write protected **
#fuses WRTB //Boot block write protected **
#fuses NOEBTR //No Memory protected from table reads **
#fuses NOSTVREN //Stack full/underflow will not cause reset
#fuses NODEBUG //No Debug mode for ICD
#fuses PROTECT //Code protected from reads
#fuses EBTRB //Boot block protected from table reads
#fuses CPB //Boot Block Code Protected
#fuses CPD //Data EEPROM Code Protected
#fuses NOWRT //No Program Memory Write Protected
#org 9984, 30080 {} //32767
#use fast_io(A)
#use fast_io(B)
#use fast_io(C)
#use delay (clock=40M)
#use rs232 (baud=115200, xmit=PIN_C6, rcv=PIN_C7)
#pragma BIT INT0IF = getenv("BIT:INT0IF") //interrupt flag bit INT EXT 0
#pragma BIT INT1IF = getenv("BIT:INT1IF") //interrupt flag bit INT EXT 1
#pragma BIT TM0IF = getenv("BIT:TMR0IF") //interrupt flag bit INT TIMER 0
#pragma BIT TM2IF = getenv("BIT:TMR2IF") //interrupt flag bit INT TIMER 2
#pragma BIT TM3IF = getenv("BIT:TMR3IF") //interrupt flag bit INT TIMER 3
////////////////////
////* variables *////
/////////////////////
int16 wait_1 = 8000;
int16 wait_2 = 100;
int16 wait_3 = 2000;
int pos = 0;
int start_pos = 0;
//////////////////////
////* DIGITAL OUT *////
///////////////////////
#define CCP_pin_1 PIN_C2 // CCP 1 pin
#define CCP_pin_2 PIN_C1 // CCP 2 pin
///////////////////////////////
////* calculation function *////
////////////////////////////////
#separate
void calculate_ccp2()
{
setup_timer_1(T1_INTERNAL|T1_DIV_BY_4); //set timer_1 fast
set_timer1(0); //set timer 1 to 0
start_pos ++; //increment start_pos
if (start_pos > 8) //reset start_pos
start_pos = 0;
CCP_2 = wait_2; //load CCP_2
setup_ccp2(CCP_COMPARE_CLR_ON_MATCH); //set_pin high and clear after ccp2
}
////////////////
////*********////
////* Main *////
////*********////
#separate
void main(void)
{
set_tris_a(47); //Port A direction
set_tris_b(15); //Port B direction
set_tris_c(129); //Port C direction
setup_timer_0(RTCC_INTERNAL | RTCC_DIV_4); //set timer0 speed
setup_timer_1(T1_INTERNAL | T1_DIV_BY_4); //set timer1 speed
setup_timer_3(T3_INTERNAL | T3_DIV_BY_4); //set timer2 speed
disable_interrupts(INT_RTCC); //no timer 0 interrupt
disable_interrupts(int_timer1); //no timer 1 interrupt
disable_interrupts(int_timer0); //no timer 3 interrupt
disable_interrupts(global); //global interrupt enabled
set_timer0(0); //set timer0 to 0
set_timer1(0); //set timer1 to 0
set_timer3(0); //set timer3 to 0
//simulation of the project:
//rotating disk, at certain positions ccp1/2 has to start - stop
//each rotation ccp gets a different value
//each while loop stands for 1 rotation position increments each loop
while(1)
{
pos ++;
if(pos == 1)
{
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8); //set timer1 slow timer to calculate RPM
set_timer1(0); //set timer 1 to 0
if(start_pos == pos) //if this is the start position
{
CCP_2 = get_timer1() + wait_2; //load CCP_2 value
setup_ccp2(CCP_COMPARE_SET_ON_MATCH); //setup CCP
}
}
else if(pos == 2)
{
if(start_pos == pos) //if this is the start position
{
CCP_2 = get_timer1() + wait_2; //load CCP_2 value
setup_ccp2(CCP_COMPARE_SET_ON_MATCH); //setup CCP
}
}
else if(pos == 3)
{
if(start_pos == pos) //if this is the start position
{
CCP_2 = get_timer1() + wait_2; //load CCP_2 value
setup_ccp2(CCP_COMPARE_SET_ON_MATCH); //setup CCP
}
}
else if(pos == 4)
{
if(start_pos == pos) //if this is the start position
{
CCP_2 = get_timer1() + wait_2; //load CCP_2 value
setup_ccp2(CCP_COMPARE_SET_ON_MATCH); //setup CCP
}
}
else if(pos == 5)
{
if(start_pos == pos) //if this is the start position
{
CCP_2 = get_timer1() + wait_2; //load CCP_2 value
setup_ccp2(CCP_COMPARE_SET_ON_MATCH); //setup CCP
}
}
else if(pos == 6)
{
set_timer3(0); //reset timer 3
CCP_1 = wait_1; //load time to CCP_1
setup_ccp1(CCP_USE_TIMER3 | CCP_COMPARE_CLR_ON_MATCH); //setup CCP1
if(start_pos == pos) //if this is the start position
{
CCP_2 = get_timer1() + wait_2; //load CCP_2 value
setup_ccp2(CCP_COMPARE_SET_ON_MATCH); //setup CCP
}
}
else if(pos == 7)
{
if(start_pos == pos) //if this is the start position
{
CCP_2 = get_timer1() + wait_2; //load CCP_2 value
setup_ccp2(CCP_COMPARE_SET_ON_MATCH); //setup CCP
}
}
else if(pos == 8)
{
if(start_pos == pos) //if this is the start position
{
CCP_2 = get_timer1() + wait_2; //load CCP_2 value
setup_ccp2(CCP_COMPARE_SET_ON_MATCH); //setup CCP
}
}
else if(pos > 8)
{
get_timer1(); //get slow timer for rpm
calculate_ccp2(); //go to function
pos = 0; //reset pos
}
delay_ms(1);
}
} |
If you compile you will see that CCP 1 output is not correct.
if all CCP_2 related code is in comment, CCP1 works ok
Thanks in advance,
Blob |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Mar 14, 2012 12:28 pm |
|
|
I copied and pasted your code into an MPLAB project. I installed vs. 4.038
and ran it on an 18F2620. I see the following waveform on CCP1 (pin C2):
Code: |
---- --- ----------
| | | |
--------- ---------
|
The scope's frequency counter says its 24.588 Hz.
The two negative pulses appear to be about 8ms long. The center
positive pulse is about 1 ms long.
I don't see it jumping around. It appears stable to me. |
|
|
Blob
Joined: 02 Jan 2006 Posts: 75 Location: Neeroeteren, Limburg, Belgium
|
|
Posted: Thu Mar 15, 2012 4:01 am |
|
|
hello PCM programmer,
in fact that is the same faulty signal I am getting.
I changed the values of the wait_x constants
Code: | int16 wait_1 = 5000; //40MHz timer/4 => 2ms
int16 wait_2 = 250; //0.1ms
int16 wait_3 = 2500; //1ms |
I am only using timer1 and 3 here
timer 1 runs at /8
timer 3 runs at /4
so they will not get an overflow below 26 ms
Both timers will be reset each rotation
1 rotation takes only 9 ms => no overflow possible
I expect CCP_1 to be like this:
Code: |
-- -- -- -- -- -- -- -- -- --
-------- -------- -------- -------- -------- -------- -------- -------- -------- -------- --------
|
with the changed values you will clearly see the error:
Code: |
CCP_1
-- -- -- -- -- -- -------- -------- -- --
-------- -------- -------- -------- -------- -------- -------- -- -- -------- --------
-- - --------- -------- ------- ------ ----- ---- --- -- -
--------- - -- --- ---- ----- ------ ------- -------- --------- -----
CCP_2
|
You can clearly see when CCP_2 drives the pin high while CCP_1 is on the run to drive his pin low, the output is messed up.
I have my scope at 10ms, trigger on CCP1
Best regards,
Blob |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Thu Mar 15, 2012 4:51 am |
|
|
I've not attempted to follow the logic of what you want to do, but have cut and pasted into a system showing how I'd use the CCP events.
See if this gives something less 'unexpected':
Code: |
#include <18F2620.h>
#device adc=16
#FUSES NOWDT, WDT128, H4, NOFCMEN, NOIESO, PUT, BROWNOUT_NOSL, BORV42, NOPBADEN, NOLPT1OSC, NOMCLR, NOLVP, NOXINST
#use delay(clock=40000000)
#bit CCP1IF=getenv("BIT:CCP1IF")
#bit CCP2IF=getenv("BIT:CCP2IF")
int16 wait_1 = 5000; //40MHz timer/4 => 2ms
int16 wait_2 = 250; //0.1ms
int16 wait_3 = 2500; //1ms
int pos = 0;
int start_pos = 0;
#int_global
void int_handler(void) {
if (CCP1IF) {
output_toggle(PIN_C2);
CCP1IF=0;
}
if (CCP2IF) {
output_toggle(PIN_C1);
CCP2IF=0;
}
}
//Since the function only affects the status bit, which is saved by the RETFIE
//no further register saving is needed
void calculate_ccp2(void) {
setup_timer_1(T1_INTERNAL|T1_DIV_BY_4); //set timer_1 fast
set_timer1(0); //set timer 1 to 0
start_pos ++; //increment start_pos
if (start_pos > 8) //reset start_pos
start_pos = 0;
CCP_2 = wait_2; //load CCP_2
}
void main(void) {
setup_timer_3(T3_INTERNAL|T3_DIV_BY_4);
setup_ccp1(CCP_COMPARE_INT);
setup_ccp2(CCP_COMPARE_INT);
output_low(PIN_C1);
output_low(PIN_C2);
CCP_1=0xFFFF;
CCP_2=0xFFFF;
CCP1IF=0;
CCP2IF=0; //Ensure CCP waits for timings to be setup
enable_interrupts(INT_CCP1);
enable_interrupts(INT_CCP2);
enable_interrupts(GLOBAL);
do {
pos ++;
if(pos == 1)
{
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8); //set timer1 slow timer to calculate RPM
set_timer1(0); //set timer 1 to 0
if(start_pos == pos) //if this is the start position
{
CCP_2 = get_timer1() + wait_2; //load CCP_2 value
}
}
else if(pos == 2)
{
if(start_pos == pos) //if this is the start position
{
CCP_2 = get_timer1() + wait_2; //load CCP_2 value
}
}
else if(pos == 3)
{
if(start_pos == pos) //if this is the start position
{
CCP_2 = get_timer1() + wait_2; //load CCP_2 value
}
}
else if(pos == 4)
{
if(start_pos == pos) //if this is the start position
{
CCP_2 = get_timer1() + wait_2; //load CCP_2 value
}
}
else if(pos == 5)
{
if(start_pos == pos) //if this is the start position
{
CCP_2 = get_timer1() + wait_2; //load CCP_2 value
}
}
else if(pos == 6)
{
set_timer3(0); //reset timer 3
CCP_1 = wait_1; //load time to CCP_1
if(start_pos == pos) //if this is the start position
{
CCP_2 = get_timer1() + wait_2; //load CCP_2 value
}
}
else if(pos == 7)
{
if(start_pos == pos) //if this is the start position
{
CCP_2 = get_timer1() + wait_2; //load CCP_2 value
}
}
else if(pos == 8)
{
if(start_pos == pos) //if this is the start position
{
CCP_2 = get_timer1() + wait_2; //load CCP_2 value
}
}
else if(pos > 8)
{
get_timer1(); //get slow timer for rpm
calculate_ccp2(); //go to function
pos = 0; //reset pos
}
delay_ms(1);
} while (TRUE);
}
|
Best Wishes |
|
|
Blob
Joined: 02 Jan 2006 Posts: 75 Location: Neeroeteren, Limburg, Belgium
|
|
Posted: Thu Mar 15, 2012 9:16 am |
|
|
Hello Ttelmah,
I was playing with the code you suggested, and I managed to narrow the error to 1 line (I think it is caused by the same error)
I changed your code a bit
Code: | #include <18F2620.h>
#device ADC=8
#include <stdlib.h>
#fuses H4 //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#fuses NOWDT //No Watch Dog Timer
#fuses PUT //Power Up Timer
#fuses BORV28 //Brownout reset at 2.8V
#fuses NOIESO //Internal External Switch Over mode disabled
#fuses NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#fuses NOWRTD //Data EEPROM write protected => ook interne schrijfopdrachten blokkeren**
#fuses WRTC //configuration registers write protected **
#fuses WRTB //Boot block write protected **
#fuses NOEBTR //No Memory protected from table reads **
#fuses NOSTVREN //Stack full/underflow will not cause reset
#fuses NODEBUG //No Debug mode for ICD
#fuses PROTECT //Code protected from reads
#fuses EBTRB //Boot block protected from table reads
#fuses CPB //Boot Block Code Protected
#fuses CPD //Data EEPROM Code Protected
#fuses NOWRT //No Program Memory Write Protected
#org 9984, 30080 {} //32767
#use fast_io(A)
#use fast_io(B)
#use fast_io(C)
#use delay (clock=40M)
#use rs232 (baud=115200, xmit=PIN_C6, rcv=PIN_C7)
#bit CCP1IF=getenv("BIT:CCP1IF")
#bit CCP2IF=getenv("BIT:CCP2IF")
int pos = 0;
int start_pos = 0;
#int_global
void int_handler(void) {
if (CCP1IF) {
output_low(PIN_C2);
CCP1IF=0;
}
}
//Since the function only affects the status bit, which is saved by the RETFIE
//no further register saving is needed
void main(void) {
set_tris_a(47); //Port A direction
set_tris_b(15); //Port B direction
set_tris_c(129); //Port C direction
setup_timer_3(T3_INTERNAL|T3_DIV_BY_4);
setup_ccp1(CCP_USE_TIMER3 | CCP_COMPARE_INT);
setup_ccp2(CCP_COMPARE_INT); //toggle this line in comment to see the difference!
//in comment output is 4 ms
//uncommented output is 3 ms
output_low(PIN_C1);
output_low(PIN_C2);
CCP_1=0xFFFF;
CCP_2=0xFFFF;
CCP1IF=0;
CCP2IF=0; //Ensure CCP waits for timings to be setup
enable_interrupts(INT_CCP1);
disable_interrupts(INT_CCP2);
enable_interrupts(GLOBAL);
do {
pos ++;
if(pos == 1)
{
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8); //set timer1 slow timer to calculate RPM
set_timer1(0); //set timer 1 to 0
}
else if(pos == 2)
{
}
else if(pos == 3)
{
}
else if(pos == 4)
{
}
else if(pos == 5)
{
}
else if(pos == 6)
{
output_high(PIN_C2);
set_timer3(0); //reset timer 3
CCP_1 = 10000; //load time to CCP_1
//10000 = 4 ms
}
else if(pos == 7)
{
}
else if(pos == 8)
{
}
else if(pos > 8)
{
get_timer1(); //get slow timer for rpm
setup_timer_1(T1_INTERNAL|T1_DIV_BY_4); //set timer_1 fast
set_timer1(0); //set timer 1 to 0
start_pos ++; //increment start_pos
if (start_pos > 8) //reset start_pos
start_pos = 0;
pos = 0; //reset pos
}
delay_ms(1);
} while (TRUE);
}
|
At pos == 6, I drive pin c2 high
CCP1 will drive it low after 10000 instructions, this equals 4ms (40MHz timer /4)
In this program CCP_2 is not used, the interrupt is disabled.
no time is loaded in CCP_2 (only at boot there is)
when setup_ccp2(CCP_COMPARE_INT); is NOT used, the code behaves as expected,
PIN_C2 is 5ms low and 4 ms high
when setup_ccp2(CCP_COMPARE_INT); IS used, the code behaves faulty:
PIN_C2 is 6ms low 3 ms high
CCP_1 and 2 do not share their timer,
CCP_1 uses timer 3
CCP_2 uses timer 1
CCP_2 interrupt is disabled
timer 1 is reset each rotation, it will never get an overflow => it will never reach 0xFFFF (initial value of CCP_2 )
To be continued... |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Thu Mar 15, 2012 9:45 am |
|
|
Seriously, can you try with a different chip?. Perhaps an old 18F252?.
Reason is that depending on your silicon revision, the 2620, has an enormous number of errata for the CCP/ECCP modules. The timer should not reset where you are describing, and doesn't for me.
Best Wishes |
|
|
Blob
Joined: 02 Jan 2006 Posts: 75 Location: Neeroeteren, Limburg, Belgium
|
|
Posted: Fri Mar 16, 2012 4:00 am |
|
|
I didnt find a 252, so I tried with a 2520
I get a similar result,
I used the same code,
only my Xtal now is 20 MHz
so I changed the dividers of the timers to get the same timings
one should expect to get an output of pin_c2:
4ms high, 5ms low
but again I get:
3ms high, 6ms low
exactly the same as with the 2620...
further info:
the device IDs of the 2620 are:
Quote: | dev ID 1 = 87
dev ID 2 = 0c |
I will have a go with an older compiler |
|
|
Blob
Joined: 02 Jan 2006 Posts: 75 Location: Neeroeteren, Limburg, Belgium
|
|
Posted: Fri Mar 16, 2012 4:51 am |
|
|
I have version 4.093 installed on an other pc.
Apparently in this version "use timer 3" is obsolete?
Code: | //#define CCP_USE_TIMER3 0x100 OBSOLETE, SEE TIMER-3 |
What should I see in TIMER-3?
There is no difference in the 2620.h files in timer3 both say:
Quote: | ////////////////////////////////////////////////////////////////// Timer 3
// Timer 3 Functions: SETUP_TIMER_3, GET_TIMER3, SET_TIMER3
// Constants used for SETUP_TIMER_3() are:
// (or (via |) together constants from each group)
#define T3_DISABLED 0
#define T3_INTERNAL 0x85
#define T3_EXTERNAL 0x87
#define T3_EXTERNAL_SYNC 0x83
#define T3_DIV_BY_1 0
#define T3_DIV_BY_2 0x10
#define T3_DIV_BY_4 0x20
#define T3_DIV_BY_8 0x30 |
isn't this supported anymore? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Fri Mar 16, 2012 8:58 am |
|
|
2520, is the same family as the 2620, and has the same errata. 252, was the older 'ancestor' model.
On the timer, look just a couple of lines below the obsolete line:
"#define T3_CCP1_TO_2"
"#define T3_CCP2"
These are "or'ed" in, just like the old CCP_USE_TIMER3, but allow you to select timer 3 for just CCP2, or for both CCP's.
Best Wishes |
|
|
|
|
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
|