The Godfather talking
You can run, but you can't hide.
Sonsivri
 
*
Welcome, Guest. Please login or register.
Did you miss your activation email?
April 19, 2024, 06:47:28 06:47


Login with username, password and session length


Pages: [1]
Print
Author Topic: PIC16F Timer1 single pulse mode worthless?  (Read 6793 times)
0 Members and 1 Guest are viewing this topic.
fantomex
Newbie
*
Offline Offline

Posts: 14

Thank You
-Given: 12
-Receive: 0


« on: February 26, 2015, 10:32:57 10:32 »

I'm trying to sample a signal with a PIC16F. Every bit starts on the falling edge of the signal. A 0 bit will cause the signal to go high again after 1us, and if the signal goes high after 3us the transmitted bit was a 1. Thus, the time the signal remains low determines whether it's a 0 or 1. Seems like a good task for 'single pulse mode' with a timer. Unfortunately, I couldn't get it to work, so I started simplifying things. First I just want to toggle a port whenever a new bit begins:

Code:
while (1) {
while (PORTAbits.RA4); // wait for falling edge
SCOPE_TEAL = !SCOPE_TEAL; // bit transmission just begun
while (!PORTAbits.RA4); // wait for it to end
}

As expected, this is produced on the scope:


Now let's try with the timer 1 single pulse mode method:
Code:
APFCONbits.T1GSEL = 0b00; // T1G function is on RA4
T1GCONbits.TMR1GE = 1; // Timer1 counting is controlled by the Timer1 gate function
T1GCONbits.T1GPOL = 0; // Timer1 gate is active-low (Timer1 counts when gate is low)
T1GCONbits.T1GSPM = 1; // Timer1 Gate Single-Pulse mode is enabled and is controlling Timer1 gate
T1GCONbits.T1GTM = 0; // Timer1 Gate Toggle mode is disabled and toggle flip-flop is cleared
T1CONbits.nT1SYNC = 0; // Synchronize asynchronous clock input with system clock (FOSC)
T1GCONbits.T1GSS = 0b00; // Timer1 Gate Pin (RA4 due to APFCON)
T1CONbits.TMR1CS = 0b00; // Clock source 01=FOSC, 00=FOSC/4
T1CONbits.T1CKPS = 0b00; // 1:1 Prescale value
T1CONbits.TMR1ON = 1; // timer 1 enabled

From my understanding, you set the 'GO' bit of the config register. Timer 1 then waits for its gate function to go low. When that happens it starts counting. Then when the gate function goes high again, the GO bit is cleared and TMR1 contains the number of cycles the signal was low. Seems perfect.
I would expect this code to produce the same image on the scope:
Code:
T1GCONbits.T1GGO_nDONE = 1; // go
while (!T1GCONbits.T1GGO_nDONE) {
// just went high after a low, implies next bit ready
SCOPE_TEAL = !SCOPE_TEAL;
T1GCONbits.T1GGO_nDONE = 1;
}

Unfortunately, this method seems to skip bits all the time. A still of the scope may look like this (but the skipped bits vary all the time):



Does this mean that the timer 1 single pulse mode cannot be used for my purpose? Any explanation for why it seems to skip bits? I hope I made a mistake here, because I really prefer the hardware to do the counting over wasting precious instruction cycles to do it.
Logged
UncleBog
Active Member
***
Offline Offline

Posts: 131

Thank You
-Given: 165
-Receive: 170


« Reply #1 on: February 26, 2015, 01:28:36 13:28 »

is your FOSC a sufficiently high frequency to be able to sample the incoming signal properly ?

Also you're synchronising the incoming signal to FOSC - a good thing, but the synchronised signal will be variably delayed from the incoming signal.
Logged
fantomex
Newbie
*
Offline Offline

Posts: 14

Thank You
-Given: 12
-Receive: 0


« Reply #2 on: February 26, 2015, 02:12:28 14:12 »

FOSC is internal 16MHz, with 3x PLL, so I have 12 instructions per µs. I think that should be enough, but can't hurt to try with 20MHz xtal.
Good tip on thinking twice about the synchronization. I've toyed around with synchronizing the clock (nT1SYNC) but it didn't seem to make much of a difference on the output. I'll study what exactly it means in more detail first.
Logged
Ichan
Hero Member
*****
Offline Offline

Posts: 833

Thank You
-Given: 312
-Receive: 392



WWW
« Reply #3 on: February 27, 2015, 07:13:02 19:13 »

Thus, the time the signal remains low determines whether it's a 0 or 1.

Sorry i did not read the post in very detail, but the sentence above bring me a quick thought that i may do it by measuring "the time the signal remains low" by using the timer in capture mode.

-ichan
Logged

There is Gray, not only Black or White.
fantomex
Newbie
*
Offline Offline

Posts: 14

Thank You
-Given: 12
-Receive: 0


« Reply #4 on: February 27, 2015, 08:28:26 20:28 »

I'm guessing that what you mean by "capture" mode is exactly the "single pulse" mode that I'm having trouble with Grin
Logged
flo0319
Junior Member
**
Offline Offline

Posts: 81

Thank You
-Given: 7
-Receive: 17


« Reply #5 on: February 28, 2015, 03:42:23 15:42 »

Code:
T1GCONbits.T1GGO_nDONE = 1; // go
while (!T1GCONbits.T1GGO_nDONE) {
// just went high after a low, implies next bit ready
SCOPE_TEAL = !SCOPE_TEAL;
T1GCONbits.T1GGO_nDONE = 1;
}

after is going out from while your code is doing something else and is executed again the sequence where you enable "again" GO ( T1GCONbits.T1GGO_nDONE = 1;) If in between GO from while and go before while was a valid LOW pulse , your toggle will miss it. Also another problem is when you set GO and the gate is already in the active low state, in this case you need to wait the next pulse to get GO = 0; You can see this on your osci : the 3th yellow puls (active low) start very fast after your toggel, I suppose that your GO is set when the Gate line is low which means that you will wait for the next puls.

I can see some picks on your signal, try to filter the line using a small capacitor or a pull-up/down resistor, they can trigger your gate. Maybe you need just a decoupling capacitor in between Vcc and GND on PIC

change your code with this:
 
Code:
while(1)
{
//...
T1GCONbits.T1GGO_nDONE = 1; // go
while (T1GCONbits.T1GGO_nDONE) {asm("nop");};
// read timer1 counter to see how many clocks
// reset timer1 counter
SCOPE_TEAL = !SCOPE_TEAL;
//...
}

... I will use the interrupt routine for detecting pulses

Logged
fantomex
Newbie
*
Offline Offline

Posts: 14

Thank You
-Given: 12
-Receive: 0


« Reply #6 on: March 01, 2015, 01:51:37 13:51 »

That while loop is actually contained within a while (1) {} construct, so there's nothing else running to get those scope pictures.
With my FOSC there shouldn't be any pulses in between loop cycles.
Quote
Also another problem is when you set GO and the gate is already in the active low state, in this case you need to wait the next pulse to get GO = 0;
I believe/hope this is incorrect. Single pulse mode should wait for the next falling edge, then start counting until the next rising edge.
Logged
flo0319
Junior Member
**
Offline Offline

Posts: 81

Thank You
-Given: 7
-Receive: 17


« Reply #7 on: March 01, 2015, 07:32:03 19:32 »

Is exactly what I try to tell you if you set GO after the falling edge (an active low pulse is already there ) the counting will stop after next pulse (a falling and a rising edge peer )

next code need to do exactly what you expect
Code:
T1GCONbits.T1GGO_nDONE = 1; // go
while(1)
{
while (T1GCONbits.T1GGO_nDONE) {asm("nop");};
SCOPE_TEAL = !SCOPE_TEAL;
T1GCONbits.T1GGO_nDONE = 1; // go
}
Logged
Signal
Active Member
***
Offline Offline

Posts: 197

Thank You
-Given: 111
-Receive: 81



« Reply #8 on: March 02, 2015, 07:26:51 19:26 »

I'm trying to sample a signal <...> Seems like a good task for 'single pulse mode' with a timer.
No, It does not seem so. Even if finally you reach a "working" state.

At first, a word "sample" is not so bad. The base for it - if you sample a signal at one moment a probability that you sample a noise is much less than that you get a correct value.

Contrary the "single pulse mode" ensures that even single disturbance _during_ bit interval certainly affects the result. Thinking that way one can suppose that using timer in gate mode without single pulse feature could be much more reliable - forgetting short interferences during measured period. But still you need to do something with synchronizing edges to prevent false start. Or instead to use gate mode to reliably detect MARK.

Note 1: Your draft code do not contain comparing of T1 values with threshold (and/or resetting T1, T1IF, ...) to make a decision for received bit. Composing received byte and bit counter are also missing. How many clock ticks do you estimate for these tasks. Are you still in time with your sampling?

Note 2: Did you see that two lines of your code:
   while (PORTAbits.RA4); // wait for falling edge
   SCOPE_TEAL = !SCOPE_TEAL; // bit transmission just begun
result in 1 us delay between input falling edge and generated output edge. Wrapping "SCOPE_TEAL = !SCOPE_TEAL;" inside two loops with inversion in condition increases this number to 2 us (second graph). That is too much for timings of your signal. Your optimistic calculation about 12 instructions per us means nothing if you can not control actual performance of your code.
Try to do the same but coding it in ASM or check disassembler listings.

If you are not going to share cpu with different tasks during the recepion, then (considering not big oversampling numbers) the hardcoded (better in ASM) receiver based on periodic sampling without usage of any smart modules is not a bad idea.

I'm guessing that what you mean by "capture" mode is exactly the "single pulse" mode that I'm having trouble with Grin
I think Ichan said about CCP module in capture mode.

« Last Edit: March 02, 2015, 07:54:11 19:54 by Signal » Logged

Give a right name to a right game and play it right
fantomex
Newbie
*
Offline Offline

Posts: 14

Thank You
-Given: 12
-Receive: 0


« Reply #9 on: March 08, 2015, 01:59:18 13:59 »

Thanks signal, all of that actually makes a lot of sense. There's a considerable difference between measuring the duration of a low signal and sampling at a known, stable, moment.
I've optimized my 'bookkeeping' in asm to a point where it fits within the required timeframe, but it still doesn't feel robust yet.

So, tossing the idea of using single pulse mode aside, would it be a reasonable idea to start sampling on a interrupt-on-change of the port when it first goes low?
I'm not using any other interrupts as there is no other time-critical functionality in use. Are there any objects to 'occupying' the interrupt routine for a prolonged time, even if you are certain no other interrupts will be missed by doing so?
Logged
Signal
Active Member
***
Offline Offline

Posts: 197

Thank You
-Given: 111
-Receive: 81



« Reply #10 on: March 09, 2015, 06:36:39 18:36 »

... would it be a reasonable idea to start sampling on a interrupt-on-change of the port when it first goes low?
1. Why not? There should be reasons for IOC to exist. This one is such a reason.
2. Why polling could be more reliable than IOC? Just because there is a risk that external noise will hang your CPU in continuous handling of incoming interrupts. In real life it rarely is a problem, but should be considered and/or controlled.

I'm not using any other interrupts as there is no other time-critical functionality in use. Are there any objects to 'occupying' the interrupt routine for a prolonged time, even if you are certain no other interrupts will be missed by doing so?
It is only a useful convention to spend a minimum time in ISR to leave more resources for other tasks and not to block them as much as possible for better CPU sharing. It's up to you how to arrange your program - it could even never return from ISR once it got there.

In your case we talk about 4 us *9 = 36 us for reception of one byte (as I understand). Quite short to make problems. If you can accept a blocking subroutine then you can accept an ISR that does the same.

Think of ISR as about usual subroutine. Differences are:
1) caller is not a CPU instruction (other subroutine) but an event
2) ISR can not be interrupted by other events (or by event with less priority)
3) You or CPU should store and restore context (some SFR values)
4) ISR does not receive argument as functions do.
5) ISR can not return any result (values) directly - only through shared memory. You can not see this difference using ASM.
During interrupt a uC is not in a special mode of any kind except treatment of GIE flag at entering and leaving ISR.

The truth is - I do not know what is the best solution for your task. There are many factors in shade.
For example, bit-synchronization usually is used when clocks are not stable enough (tolerance?) and/or transmission of bits could be delayed (prolongation of high-level portions is allowed). What is the source and what noise is expected. etc. In case of clean signal a single sample at 1.5 us time-out started at falling edge could be enough for bit reception.

A bit reception could be based on UART or SPI. The former can detect falling edge as a start bit automatically. The latter can be used to sample a signal continuously (am not sure can SPI master of your uC work without delay between byte reception or not). In both cases you will examine a received byte as a set of samples instead of reading input pin at each oversampling moments. You can read 25.1.2.2 "Receiving Data" in 41391C.pdf "PIC16F/LF1826/27 Data Sheet" for receiver data recovery algorithm used in UART module. It will be useful in case of manual sampling too. I am very curious what will be your solution.
« Last Edit: March 10, 2015, 04:38:36 04:38 by Signal » Logged

Give a right name to a right game and play it right
johnny27
Inactive

Offline Offline

Posts: 1

Thank You
-Given: 0
-Receive: 0


« Reply #11 on: January 13, 2016, 09:16:12 21:16 »

Hi, i am new here so i am not sure if this is of any help, but i will mention it anyhow.
Using 2 separate CCP's or Enhanced CCP's maybe of use for you, its helpful for capturing the on times of high going pulses (rising edge) and low going pulse period (on the falling edge of the pulse)
But even if you dont need to measure the period of the rising edge pulse period, you could use a CCP in compare mode, not to actually use a timer value to CCPx period compare but just to simply trigger an interrupt to flag occurrence of pulse being high. You could use this rising edge interrupt to direct you program flow to process the previous captured value of the falling edge pulse, so that processing of the captured low period is only done during the pulse high period so that the program ensures that your main code executes just as the falling edge pulse has ended.
Logged
Pages: [1]
Print
Jump to:  


DISCLAIMER
WE DONT HOST ANY ILLEGAL FILES ON THE SERVER
USE CONTACT US TO REPORT ILLEGAL FILES
ADMINISTRATORS CANNOT BE HELD RESPONSIBLE FOR USERS POSTS AND LINKS

... Copyright © 2003-2999 Sonsivri.to ...
Powered by SMF 1.1.18 | SMF © 2006-2009, Simple Machines LLC | HarzeM Dilber MC