I Miss The P1 Counters / P2 SIRCS Decoding
JonnyMac
Posts: 9,510
As I'm porting more of my P1 objects to the P2, I'm now noticing how frequently I employed the cog counters. For example, in my P1 SIRCS decoder, I used CTRA in Neg Detect mode to measure a pulse, and CTRB in Pos Detect mode to time the idle spaces between pulses (and detect the end of the stream).
Am I missing something with smart pins, or am I going to have to do grunt timing like this (test code that works)?
Am I missing something with smart pins, or am I going to have to do grunt timing like this (test code that works)?
pub pulse_in(pin) : result | t0
'' Returns duration of low-going pulse
'' -- value returned in system ticks
'' -- blocks until pulse arrives
org
fltl pin ' make pin an input
.wait getct t0 ' get system timer (start of pulse)
testp pin wc ' check pin state
if_c jmp #.wait ' if still high, back to .wait
.measure getct result ' get system timer (end of pulse)
testp pin wc ' check pin state
if_nc jmp #.measure ' if still low, back to .measure
subs result, t0
end

Comments
For those who have been around P2ASM a while, would you please review and comment? Thanks.
pub sircs_in(pin) : ircode, irbits | starttix, bit1tix, tfall, trise, tdelta starttix := 2400 * US_001 * 9 / 10 ' 90% of 2.4ms bit1tix := starttix >> 1 ' 1 bit is 50% of start bit org fltl pin get_start getct tfall ' mark start of pulse testp pin wc if_c jmp #get_start ' wait for 1->0 transition wait_start getct trise ' mark end of pulse testp pin wc if_nc jmp #wait_start ' wait for 0->1 transition check_start mov tdelta, trise ' calculate pulse width subs tdelta, tfall cmps tdelta, starttix wcz ' validate against start pulse width if_b jmp #wait_start mov ircode, #0 ' clear results mov irbits, #0 get_bits getct tdelta ' wait for start of data bit (1->0) testp pin wc if_nc mov tfall, tdelta ' detected, mark time & continue if_nc jmp #wait_bit subs tdelta, trise ' time-out (end of data bits)? cmps tdelta, bit1tix wcz if_a jmp #done jmp #get_bits wait_bit getct trise ' wait for end of data bit (0->1) testp pin wc if_c jmp #check_bit jmp #wait_bit check_bit mov tdelta, trise subs tdelta, tfall cmps tdelta, bit1tix wcz shl ircode, #1 ' make space for bit if_a or ircode, #1 ' write new bit add irbits, #1 ' update count jmp #get_bits done rev ircode ' correct lsbs mov tdelta, #32 sub tdelta, irbits shr ircode, tdelta endYou can configure a neighbor smartpin to monitor another neighbor. Up to 3 pins away. So for example, you can configure pin 6 to do the neg detect mode, and then configure pin 7 to do pos detect but set it to look at pin 6 for input to the detect.
The pin itself can still be used for digital IO.
With respect, I'll believe that when I see it presented in practical, real-world code.
This code works:
pub pulse0_in(pin) : result | t0 org fltl pin wait_1_0 getct t0 testp pin wc ' wait for 1->0 if_c jmp #wait_1_0 wait_0_1 getct result testp pin wc ' wait for 0->1 if_nc jmp #wait_0_1 subs result, t0 ' calculate duration of low endWhile this "smart pin" version returns gibberish.pub sp_pulse0_in(pin) : result org fltl pin wrpin ##P_STATE_TICKS, pin wxpin #0, pin wypin #0, pin drvl pin wait_1_0 testp pin wc ' wait for 1->0 if_c jmp #wait_1_0 wait_0_1 testp pin wc ' wait for 0->1 if_nc jmp #wait_0_1 rdpin result, pin ' read duration of low endIt's frustrating that after all of these years of development there is so little documentation, and even more so that the documentation that exists has few practical examples.Yes, the P2 docs are cryptic...
I think there are other HW supported paths (but firm examples are sparse)
a) WAITSE1 Wait for the selectable-event-1 event flag
%001_PPPPPP = INA/INB bit of pin %PPPPPP rises
%010_PPPPPP = INA/INB bit of pin %PPPPPP falls
%011_PPPPPP = INA/INB bit of pin %PPPPPP changes
b) I think the Smart Pins can also capture & clear on either edge - maybe this mode ? %10000 = Time A-input states, and you would check the pin level to see what was just captured.
For very slow edges, that would allow a single pin to be used.
Understatement of the year!
Other times there has been ambiguity in the choice of words and even Chip doesn't remember the definitive meaning reading it back. He does occasionally rewrite a section of the docs.
More recently, Searth and Jon are quietly fleshing some bits out.
I haven't tried your code but the one extra line below should fix it:
wait_1_0 testp pin wc ' wait for 1->0 if_c jmp #wait_1_0 rdpin result, pin ' read duration of high nop wait_0_1 testp pin wc ' wait for 0->1 if_nc jmp #wait_0_1 rdpin result, pin ' read duration of lowEDIT: On second thoughts, TESTP sees stale data when immediately after RDPIN, it'll also need a NOP as well ... edit ...
You can't read the pin state directly when in smart mode. So the wait for 1 -> 0 and 0 -> 1 do not work. A high at the pin indicates that a state change occured, the C flag can show what state it was. So something like that should work:
wait_1_0 testp pin wc ' wait for state change if_nc jmp #wait_1_0 rdpin resultH, pin wc ' read duration of high if_nc jmp #wait_1_0 ' was it a high state? wait_0_1 testp pin wc ' wait for state chance if_nc jmp #wait_0_1 rdpin resultL, pin ' read duration of lowAndyEdit: For the frequencies which IR uses it's not necessary to use PASM, Spin2 would do it also, I think
I am pleased you’re giving p2asm a go. The P1 assembler instructions are the best I have seen on any micro and I’ve seen/used a lot. They are simple and regular and therefore easy to remember.
Of the 32, you’ll mostly use less than half of them.
On P2, start with the simple regular P1 equivalent instructions first, and you will pick it up in no time. Then you can move to the more exotic P2 instructions as you have need for them. It will fall in to place more easily that way.
Just remember, when you don’t need speed, spin is great, but when the chips are down, use pasm. Generally tho, I recommend spin and pasm to use separate cogs (cores) even tho P2 can mix them in one cog.
My first thought is that you can use mode %10001 (Time A-input high states), configured to look at an inverted signal (since yours is actually a low signal). To read the data, use the selectable event mechanism (which I just consolidated to make a little more clear) to detect the completion of the counting, followed by RDPIN/RQPIN to read the count value. Something like:
wrpin pin_mode, pin ' set pin mode dirh pin ' enable smart pin or pin, #%001_000000 setse1 pin ' set selectable event (INx rises) waitse1 ' wait for event (finished counting) rdpin result, pin ' read count pin_mode long %0001010000000_00_10001_0 ' A input, inverted, mode %10001Looking at your longer code snippet, you could instead use mode %10000 (Time A-input states) which will give you both high and low durations (with C indicating high or low state). The code would look something like this, I think:
pub sircs_cfg(pin): org wrpin ##%0001000000000_00_10000_0, pin ' configure smart pin: input, time A-input states dirl pin or pin, #%001_000000 ' IN[pin] rises setse1 pin end pub sircs_in(pin) : ircode, irbits | starttix, bit1tix, tdelta starttix := 2400 * US_001 * 9 / 10 ' 90% of 2.4ms bit1tix := starttix >> 1 ' 1 bit is 50% of start bit org dirh pin ' enable smart pin get_start waitse1 ' wait for initial transition if_c waitse1 ' signal had been high, wait for next low period rdpin tdelta, pin ' read the low duration cmps tdelta, starttix wcz ' validate against start pulse width if_b jmp #get_start ' not valid, start again mov ircode, #0 ' clear results mov irbits, #0 get_bits getct tdelta addct1 tdelta, bit1tix ' set up timeout period chk_timeout pollct1 wz ' check for timeout if_z jmp #done ' timeout reached, done pollse1 wz ' check for measurement if_nz jmp #chk_timeout ' not yet, loop waitse1 ' prior SE was for high state, now wait for low state rdpin tdelta, pin ' read the low duration cmps tdelta, bit1tix wcz shl ircode, #1 ' make space for bit if_a or ircode, #1 ' write new bit add irbits, #1 ' update count jmp #get_bits done dirl pin ' disable smart pin rev ircode ' correct lsbs mov tdelta, #32 sub tdelta, irbits shr ircode, tdelta end(mind you, this code is entirely untested, so caveat emptor and all that.)
The code that I said works was tested by pointing a Sony remote at an IR sensor and comparing the value returned with what I expected (~2.4ms) and what I could see on my 'scope.
I know that I'll eventually get it (P2ASM), I'm just in the frustrating part of the learning curve.
Sorry. I definitely wasn't questioning your SIRCS knowledge. It was new to me, so I looked it up and noticed the non-inverted signal. Maybe a better question would have been: am I looking at the right spec? Regardless, the only reason I mentioned is was because the smart pin configuration could be updated to invert the inverted signal so that your code matched the actual signal specification.
This is a source I use for IR protocol information (SIRCS and others)
-- https://www.sbprojects.net/knowledge/ir/sirc.php
From a broader view, what I want to learn to do with smart pins is measure a pulse, like the old BS2 PULSIN command (that can be used to receive SIRCS if one is careful). I'm sure it's possible -- I just haven't had my "Aha!" moment with it.
For grins, I've attached my P1 SIRCS receive object so you can see where I'm coming from.
Take a look at the second block of code in my post above. In that block, I am using a smart pin mode (%10000) that measures the length of each transition. That's primarily because of your timeout test. If not for that, I could have used the measure high mode (%10001) instead (with the input inverted, in your case).
In a sense, %10000 is PULSIN if you toggle the state parameter each "call", while %10001 is like PULSIN where the state parameter is determined by a bit in the WRPIN d-field.
Yes, tho polling has a coarse granularity, that hardware methods avoid. In your example, that granularity is totally 'don't care' but users may have other tasks where this matters more ?
You can improve your 3 line granularity down to 2 lines, which is then 4 sysclks.
Some hardware (event or Smart Pin cell timers) would allow that to come down to 1 sysclk.