PDA

View Full Version : 2 bytes to word array variable - fastest way



MikeWinston
- 8th June 2011, 00:20
Hello All,
I would like an "expert check" on this one....
I need to put 2 ADC bytes into a word variable thats part of an array.

This is what I have:
adcData var word[16]
adcData[index] = (ADRESH << 8) + ADRESL

Is there a better way (faster) ?

thanks,
Mike

P.S.
I am modernizing an old dehumidifier whose humidity sensor (tape strip) has
gone the way of the dodo. I figure get an electronic humidity sensor and I
would have another excuse for a PIC project.

cncmachineguy
- 8th June 2011, 00:37
Have you tested that? it seems like it will shift ADRESH 8 times, then assign it to the word. DOing it like that would be better I think like this:


adcdata[index] = ADRESH
adcdata[index] = adcdata[index]<<8
adcdata[index] = adcdata[index]+ADRESL

Not sure about that either.

I think you can do this:


adcdata.highbyte[index] = ADRESH
adcdata.lowbyte[index] = ADRESL

I am not certain on this, so my reply is as much a question as an answer. Hmmm, that sounds a little deep :)

OK, this I am certain about:


tempword var word

tempword.highbyte = ADRESH
tempword.lowbyte = ADRESL
adcdata[index] = tempword

MikeWinston
- 8th June 2011, 02:14
I have tested the code with VB.Net, and it works, but I haven't tested on the PIC yet.

I actually tried this code first but it did not compile:
adcData.highbyte[index] = ADRESH
adcData.lowbyte[index] = ADRESL
I guess you can't use the .lowbyte/.highbyte syntax on arrays.

Using the temp variable is probably the norm but I figure there might be some trick to doing
the same thing all nice and clean on one line.

cncmachineguy
- 8th June 2011, 02:19
In your VB test, Was ADRESH a byte or a word?

MikeWinston
- 8th June 2011, 12:55
Thanks Bert. I see what your getting at. ADRESH was a word.
I just tried ADRESH as a byte and had an overflow. oops, I missed that one.
I guess I'll use the temp variable way.

There is another way I used before:
adcData[index] = (ADRESH * 256) + ADRESL
But I would put money on this way is slower than the temp variable way.

HenrikOlsson
- 8th June 2011, 13:31
Hi,
Have you tried:

adcData.lowbyte[index] = ADRESL
adcData.lowbyte[index+1] = ADRESH
Take a look at Melanies writeup (http://www.picbasic.co.uk/forum/showthread.php?t=544&highlight=indexing+bits), specifically section 5, for further details.

/Henrik.

cncmachineguy
- 8th June 2011, 14:26
Thanks for clearing that up Henrik. I knew there was a way, and I knew my guess was not correct. While I feel like the highbyte/lowbyte should work, I realize it does not. I feel like this is a shortcoming of PBP, adcdata.lowbyte[index+1] feels like it should be the lowbyte of the next word. Anyone agree or do I not have my mind wrapped around this just yet?

It seems a little un-intuitive, but who cares, thats how it works. :)

HenrikOlsson
- 8th June 2011, 17:56
Actually I may have messed that up myself, based on this post I'm not sure it'll do what the OP wanted - to be honest.

I agree it's a abit unituitive and I'll admit I haven't sat down and looked into what's really happening - until now. Before I go on I'll point out that I suck at ASM so if this is completely wrong then I applogise before hand and hope that whoever knows/understands better will correct me.

When you declare an array of words PBP 'calculates' the start adress of that array in memory (where in the RAM memory the first byte in the array is located). If, somewhere in your program, you use the LOWBYTE,HIGHBYTE "modifiers" it also calculates where the lowbyte and highbyte of the first word in the array is. Glancing at the .lst file it might look something like this:


'00038 _myArray EQU RAM_START + 01Dh
'00043 _myArray??LOWBYTE EQU _myArray
'00044 _myArray??HIGHBYTE EQU _myArray + 001h
So all it really knows (and need to know) is where myArray starts. The .LOWBYTE of myArray is at the very same adress as the array starts and .HIGHBYTE is at the next adress. Makes sense.

Now, let's say we do something like this:

myArray VAR WORD[3]
myByte VAR BYTE

myVar = myArray[0]
myVar = myArray[1]

What's going on here then? We're actually trying to stuff a WORD from the array into our BYTE-sized variable. The code generated looks like this:

movff _myArray, _myVAR
movff _myArray + 00002h, _myVAR
First it takes the byte at the start adress of the array (which is the low byte of word 0, right) and puts that in our BYTE-variable. Then it takes start-adress of the array, adds 2 to that adress and grabs the byte at that location. This is the third byte in our WORD-array so it's grabbing the low byte of word 1. This is pretty straight forward and intuitive - it simply truncates the word from the array into our byte variable.

Now,

myVar = myArray.LowByte
myVar = myArray.HighByte
The above PBP code compiles:

movff _myArray??LOWBYTE, _myVAR
movff _myArray??HIGHBYTE, _myVAR
As we saw above myArray??LOWBYTE is the very same adress as the start of the array so this IS the low byte of the first word. myArray??HIGHBYTE is at the start adress of the array + 1 so we'll get the high byte of the first word. Still OK, what we wanted, and probably what we expected.

Now lets start indexing into the array.


myVar = myArray.LowByte[0]
myVar = myArray.HighByte[0]
This code compiles to:

movff ((_myArray??LOWBYTE) + (000h)), _myVAR
movff ((_myArray??HIGHBYTE) + (000h)), _myVAR
As you can see this takes the adress of the lowbyte of the first word in the array, adds nothing (zero) to it, gets the byte at that adress and puts it in our byte variable. Then it takes the address of the highbyte of the first word in the array, adds nothing to that and gets the byte at that adress. This is still fine, what we wanted (perhaps) and what we might expect. But now it starts to get interesting.



myVar = myArray.LowByte[1]
myVar = myArray.HighByte[1]
From this we might, intuitively, expect to get the low and high byte of the second word the array but the above code compiles to:

movff ((_myArray??LOWBYTE) + (001h)), _myVAR
movff ((_myArray??HIGHBYTE) + (001h)), _myVAR
So, what's going on here... It takes the adress of the 'lowbyte' (the very first byte in our array, low byte of word 0), adds one to that address and gets the byte at that adress. What we're getting is actually the second byte in the array which is the high byte of the first word (word 0). Then it takes the adress of 'highbyte', adds one to that and gets the byte at that adress which is now the third byte in the array or the low byte of the second word (word 1). Not what one might expect but when you know what goes on under the hood it kind of makes sense.

And, to illustrate it one more time:

MyVar = myArray.Lowbyte[2]
myVar = myArray.HighByte[2]
Intuitively we'd expect to get the low and high byte of the third word but we now know that ain't what's happening because we're telling it to index an array of words byte by byte. We tell it to get the byte at the adress of myArray.Lowbyte+2. myArray.Lowbyte is the very first byte in the array, add two to that and we'll end up the adress of the third byte in the array which is the low byte of word 1 - not word 2 as we intutively might think. And, obviously the same thing happends with myArray.HighByte[2] - it gets 4th byte in the array which is the high byte if word 1.

What we need to do when working with word-arrays on a byte-by-byte-basis is to index, or step, thru them in steps of 2. Like....

accData VAR WORD[16]
Index VAR BYTE

For Index = 0 to 16 STEP 2
accData[Index] = ADRESL 'Low byte (bytes 0, 2, 4, 6...)
accData[Index+1] = ADRESH 'High byte (bytes 1, 3, 5, 7...)
NEXT


So, again, I'm not sure my earlier advice is actually going to work. It might work if the word indexed is first but it kind of screws up as we've seen above.

/Henrik.

MikeWinston
- 8th June 2011, 18:26
Hi Henrik,
I understand your explanation and thank you. But in your last bit of code
doesn't it need the ".lowbyte" part?


For Index = 0 to 16 STEP 2
accData.lowbyte[Index] = ADRESL 'Low byte (bytes 0, 2, 4, 6...)
accData.lowbyte[Index+1] = ADRESH 'High byte (bytes 1, 3, 5, 7...)
NEXT



This is more intuitive though at the cost of a word variable


for index = 0 to 16
tempword.highbyte = ADRESH
tempword.lowbyte = ADRESL
adcdata[index] = tempword
next


Mike -

HenrikOlsson
- 8th June 2011, 18:39
Yes, you're quite right, otherwise it'll be as in the first example where the indexing is actually word based and we'll get the low byte of all the words instead of the low and high byte. Thanks for pointing that out!

/Henrik.

I wish I could edit my post and correct that but the 10 second window for doing that has passed.... :-(

cncmachineguy
- 8th June 2011, 19:18
Again thank you Henrik. Yes knowing what goes on under the hood does make it make sense, But I stand by my statement that this is a shortcomming of PBP. I would almost go so far to call this a work around for word array indexing on a byte level. I think I will add a wish list thread for this. PBP should certainly be able to distinguish the intention. It would be even more intuitive to address it this way:


adcdata[index].lowbyte
adcdata[index].highbyte


But knowing is half the battle, again thanks for the very clear explanation.

HenrikOlsson
- 8th June 2011, 20:52
I fully agree, it might be somewhat logical when one understands it but it's certanly not intuitive, your format would be much cleaner for its typical purpose. I'm sure though that there are some clever tricks that can be done (which I'm not clever enough to figure out) with the way it currently is.

/Henrik.

scrwld
- 8th June 2011, 21:55
hello, i use this and work:

read I,b1.HIGHBYTE ' read byte type var from EEprom
read I+1,b1.LOWBYTE 'read byte type var from EEprom
TEmpDs18(L) = B1 'word array

MikeWinston
- 8th June 2011, 23:46
Well it turns out the more intuitive way is also a little faster. That is if I
have done this correctly.

I used [view] [program memory] in MPLab and counted the number of
instructions between the start and end labels.

This code was 18 lines:


StartTest:
adcData.lowbyte[Index] = ADRESL
adcData.lowbyte[Index+1] = ADRESH
EndTest:



This code was 16 lines:


StartTest:
tempWord.highbyte = ADRESH
tempWord.lowbyte = ADRESL
adcdata[index] = tempword
EndTest:



So as long as I can afford the extra word variable, I will be using the
temp variable way...... unless someone else reveals a clever trick.

thanks all for your replies,
Mike -

mister_e
- 9th June 2011, 00:08
If ADRESH & ADRESL are consecutive SFR... then you could use



@ADRESULT = ADRESL
ADRESULT VAR WORD EXT

MyArray VAR WORD [8]

Start:
MyArray[0] = ADRESULT


But I doubt ADRESL/ADRESH are consecutive in many PIC.

MikeWinston
- 9th June 2011, 00:45
mister_e,
Thats a good trick. One to remember. And it only produces 9 lines of
instruction. But your right, the PIC I'm using (16F684), ADRESH/L are not
next to each other.

Actually, ACCON0 is after ADRESH. That would give you an interesting result.

thanks,
Mike -