Learning to use FIELD

When Chip added field to Spin2 I got an earful from people using my jm_fullduplexserial.spin2 object because I was using field as a local variable. After that got sorted I never paid attention to what field was about. @"Stephen Moraco" told me it was pretty neat, but until I asked Chip about it a few weeks ago at the Parallax day I didn't actually give it a try.
For those like me who ignored it, here's the skinny: field lets us create and n-bit array within a block of RAM. For example, S.BUS packets arrive 25 bytes at a time, and bytes 1-22 represent a packed array of sixteen 11-bit values. I struggled at first because I couldn't get my 25-byte array to translate properly. Then I read the details in the docs and found this comment.
Given the 11-bit size of S.BUS values I was forced to copy my byte array into an array of longs. Then it all worked. Here's the original method with a stacked loop for unpacking the values
pub decode_sbus(p_sbus, p_chans) | ch, work, bc, flags ' ~107us @ 200MHz '' Convert S.BUS array (of bytes) to channel values (words) '' -- p_sbus is [byte] pointer to S.BUS data '' -- p_chans is [word] pointer to channel values if (byte[p_sbus][0] <> $0F) ' check header return if (byte[p_sbus][24] <> $00) ' check footer return p_sbus += 1 ' point to data byte #1 longfill(@ch, 0, 3) ' clear locals repeat while (ch <= 15) ' Ch 1-16 decoding repeat while (bc < 11) ' collect enough bits for channel work |= (byte[p_sbus++] << bc) ' get byte, position, add to work bc += 8 ' bump bit count word[p_chans][ch++] := work & $07FF ' extract and save channel work >>= 11 ' remove channel, re-align lsb bc -= 11 ' fix bit count flags := byte[p_sbus] ' flags byte follows channels word[p_chans][16] := (flags & %0001) ? $07FF : 0 ' convert ch17 bit word[p_chans][17] := (flags & %0010) ? $07FF : 0 ' convert ch18 bit
And here's the update using field which runs about twice as fast as the original.
pub decode_sbus_v2(p_sbus, p_chans) | sb[6], pf, ch, flags ' ~49us @ 200MHz '' Convert S.BUS array (of bytes) to channel values (words) '' -- p_sbus is [byte] pointer to S.BUS data '' -- p_chans is [word] pointer to channel values if (byte[p_sbus][0] <> $0F) ' check header return if (byte[p_sbus][24] <> $00) ' check footer return bytemove(@sb, p_sbus+1, 22) ' leave out header, flags, footer pf := ^@sb.[10..0] ' set base field pointer repeat ch from 0 to 15 ' Ch 1-16 decoding word[p_chans][ch] := field[pf][ch] flags := byte[p_sbus][23] word[p_chans][16] := (flags & %0001) ? $07FF : 0 ' convert ch17 bit word[p_chans][17] := (flags & %0010) ? $07FF : 0 ' convert ch18 bit
As you can see, the second version is a bit tidier and runs faster.
With P2 smart pins I could write a cogless version of my S.BUS interface and will do that later that would be fine for projects that don't have a screaming fast process loop. Having started with the BASIC Stamp 1 I am very stingy about resources, so I've come up with cogless drivers where I have more time in my process loop than I have cogs that I can spare.
Comments
nice insights, thanks for sharing.
Field looks powerful, but the documentation is pretty spartan....
Maybe someone can use AI one day to make better documentation?
Don't fully understand it. Can see how it can work within a single long/word/byte.
But appears @JonnyMac is able to span many bytes somehow...
Don't think this is documented?
I tried variation of the example in docs and it doesn't work. No idea why not...
I think the problem has to do with debug; you're pointing to a word (k2) but telling it to print as 32 bits. Internally, the upper 32 bits will be set to 0.
I poked around the debug docs and found a mechanism that will show you what you wanted to see -- and it proves the field feature is working.
Interesting... Was wondering if it work with bits offset from LSB, seems it does:
CON _clkfreq = 10_000_000