View previous topic :: View next topic |
Author |
Message |
aumc
Joined: 20 Nov 2019 Posts: 4
|
Capture 32 bit roll over |
Posted: Wed Nov 20, 2019 7:53 am |
|
|
The roll over of a 32 bit timer doesn't occur.
This is my configuration:
PIC24FJ64GB004
PCWHD Compiler 5.053
Capture 1 (16 bit) and 2 (16 bit) in cascade (32 bit)
External pulse signal to capture on pin RB7
Part of main.c:
Code: | unsigned int32 TimerValue, TimerValue1, TimerValue2;
float32 TimerClock, TimerFlow, TimerFrequency;
//******************************* INTERRUPTS ***********************************
#int_ic1 // Interrupt "Capture" for flowmeter.
void ic1_interrupt() // Captures the rising edge of CCP1 pin.
{
TimerValue1 = TimerValue2;
TimerValue2 = get_capture32(1, FALSE); // Argument WAIT = TRUE, this reads the last value. Previous values are deleted. If WAIT is true the get_capture waits and returns the next found capture, this isn't working with interrupts due to the wait. If WAIT is false the last capture is returned.
TimerValue = TimerValue2 - TimerValue1;
TimerClock = (float)(getenv("CLOCK"));
TimerFrequency = (float)(getenv("CLOCK")/2) / TimerValue; // CLOCK = 32 MHz. Frequency MCU = 32 MHz / 2 = 16 MHz
TimerFlow = 0.06 * TimerFrequency; // Some calculation to convert frequency to flow.
clear_interrupt(INT_IC1);
}
void main()
{
setup_timer1(TMR_INTERNAL | TMR_DIV_BY_8, 8000); // 4 mSec 250 Hz | Fcy / 8 / 800 = (32Mc / 2) / 8 / 8000 = 250Hz -> This interrupt doesn't have anything to do with my capture.
setup_timer2(TMR_DISABLED);
setup_timer3(TMR_DISABLED);
setup_timer4(TMR_DISABLED);
setup_timer5(TMR_DISABLED);
// The next two lines are used for a 32 bit capture mode. Two capture units cascaded.
setup_capture(2, CAPTURE_RE | INTERRUPT_EVERY_CAPTURE | CAPTURE_SYSTEM_CLOCK | CAPTURE_TRIG_SYNC_IC2); // Most significant 16 bits.
setup_capture(1, CAPTURE_RE | INTERRUPT_EVERY_CAPTURE | CAPTURE_SYSTEM_CLOCK | CAPTURE_TRIG_SYNC_IC2 | COMPARE_32_BIT); // Least significant 16 bits.
} |
Part of main.h
Code: | #pin_select IC1=PIN_B7
#pin_select IC2=PIN_B7 |
The measurement is working properly except the IC2 hangs at the value where IC2TMR is 0xFFFF = 1111 1111 1111 1111b. This means the roll over of IC2TMR doesn't occur. IC1TMR is working fine in cascade mode and as a separate 16 bit capture.
The interrupt "#int_ic1" is still working during the hang (tested with an output pin).
After the hang the register values are:
Code: | IC1CON1: 0001 1100 0000 0011
IC1CON2: 0000 0001 0001 0101
IC1BUF: 0000 0000 0000 0000
IC1TMR: 0000 0000 0000 0000
IC2CON1: 0001 1100 0000 0011
IC2CON2: 0000 0001 0001 0101
IC2BUF: 1111 1111 1111 1111
IC2TMR: 1111 1111 1111 1111 |
Help would be appreciated. Thanks.
Last edited by aumc on Thu Nov 21, 2019 1:30 am; edited 1 time in total |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19545
|
|
Posted: Wed Nov 20, 2019 8:17 am |
|
|
The key here is a bad bit of documentation. Post your setup line for timer 2?.
It needs to set the 32bit value for the PR2 & PR3 registers, but the
documentation only refers to a 16bit value:
Code: |
Period is an optional 16 bit integer parameter that specifies the timer period. The default value is 0xFFFF.
|
In fact when using the combined timer in 32bit mode, the period value can
(must...) be a 32bit value.
So:
Code: |
setup_timer2(TMR_INTERNAL | TMR_DIV_BY_1 | TMR_32_BIT, 0xFFFFFFFF); //set to use 32bit and with period set.
|
If the period is not set the timer won't wrap.
The default is '0x0000FFFF', which then gives problems for 32bit....
If you check, with the 32bit value given, as shown, both PR2 & PR3 will be
set to 0xFFFF. If you only put a 16bit value in PR3 gets set to 0, and when it
wraps then jams at zero..... |
|
|
aumc
Joined: 20 Nov 2019 Posts: 4
|
|
Posted: Thu Nov 21, 2019 1:52 am |
|
|
I haven't used timer2. Added the timer configuration in the first post. Timer 1 is used for something else. What I understand from the documentation is that the capture unit have their own timer. See Microchip DS70000352D.
http://ww1.microchip.com/downloads/en/DeviceDoc/70000352D.pdf
One of the lines in the document is: "The Input Capture module contains a dedicated 16-bit, synchronous, up-counting timer used for the 32-bit Input Capture function.".
The Microchip document also doesn't mention using a 32-bit timer when Capture 1 and Capture 2 are used in 32-bit mode. I am using the Synchronous Cascaded Configuration.
I will try the suggestion with the timer. Reaction follows. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19545
|
|
Posted: Thu Nov 21, 2019 2:44 am |
|
|
OK. Using the system clock is OK. OR in COMPARE_TRIG_SYNC_SELF.
This is what specifies what resets the timer. It'll reset to zero when this
'source' goes to '1'. Using itself, when it reaches the end of the count it'll
reset, Currently you are not specifying a reset source.... |
|
|
aumc
Joined: 20 Nov 2019 Posts: 4
|
|
Posted: Fri Nov 22, 2019 6:47 am |
|
|
COMPARE_TRIG_SYNC_SELF has the value 0x001F0000. This corresponds to the bits <4:0> and seems to be an option for the register OCxCON2. OCxCON2 is a part of the output compare.
I assume you have to code:
Code: | setup_timer2(TMR_INTERNAL | TMR_DIV_BY_1 | TMR_32_BIT, 0xFFFFFFFF); //set to use 32bit and with period set. |
from the CCS manual. In the manual the function get_capture32( ) mentions that this is only available with devices with a 32-bit Input Capture module.
I also found this information:
https://microchipdeveloper.com/faq:1774
This is a dsPIC but it sounds like my problem.
My workaround for now is to reset the capture when it is 0xFFFF0000. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19545
|
|
Posted: Fri Nov 22, 2019 7:10 am |
|
|
Code: |
setup_capture(1, CAPTURE_RE | INTERRUPT_EVERY_CAPTURE | CAPTURE_SYSTEM_CLOCK | CAPTURE_TRIG_SYNC_IC2 | COMPARE_32_BIT | COMPARE_TRIG_SYNC_SELF );
|
It should make the internal counter reset when it overloads.
However I've always used an actual timer, so I can control when it resets. |
|
|
aumc
Joined: 20 Nov 2019 Posts: 4
|
|
Posted: Fri Nov 22, 2019 7:28 am |
|
|
Hmmm... Seems to be working now.
The next code of the first post: Code: | setup_capture(1, CAPTURE_RE | INTERRUPT_EVERY_CAPTURE | CAPTURE_SYSTEM_CLOCK | CAPTURE_TRIG_SYNC_IC2 | COMPARE_32_BIT); // Least significant 16 bits. | Is replaced with: Code: | setup_capture(1, CAPTURE_RE | INTERRUPT_EVERY_CAPTURE | CAPTURE_SYSTEM_CLOCK | CAPTURE_TRIG_SYNC_IC2 | COMPARE_32_BIT | COMPARE_TRIG_SYNC_SELF); // Least significant 16 bits. |
Adding the COMPARE_TRIG_SYNC_SELF changed:
IC1CON and IC2CON <3> -> ICBNE from 0 to 1
IC1CON and IC2CON <2:0> ICM <2:0> from 101 to 111
Looking in the list file:
IC2CON1 from 0x0115 to 0x011F
IC1CON1 from 0x0115 to 0x011F
bit 3 ICBNE: Input Capture x Buffer Empty Status bit (read-only)
1 = Input capture buffer is not empty, at least one more capture value can be read
0 = Input capture buffer is empty
bit 2-0 ICM<2:0>: Input Capture Mode Select bits(1)
111 = Interrupt mode: input capture functions as interrupt pin only when device is in Sleep or Idle mode
(rising edge detect only, all other control bits are not applicable)
110 = Unused (module disabled)
101 = Prescaler Capture mode: capture on every 16th rising edge
100 = Prescaler Capture mode: capture on every 4th rising edge
011 = Simple Capture mode: capture on every rising edge
010 = Simple Capture mode: capture on every falling edge
001 = Edge Detect Capture mode: capture on every edge (rising and falling); ICI<1:0 bits do not
control interrupt generation for this mode
000 = Input capture module turned off
I don't understand why ICM was 101 and why ICBNE (read only) changed to 1. Anyway... Happy me.
@Ttelmah: Thanks a lot. I almost was giving up... |
|
|
|