News:

PROTON pic BASIC Compilers for PIC, PIC24, dsPIC33

Main Menu

Storing 1,2,3 or 4 byte variables in a byte array

Started by kcsl, Apr 30, 2025, 04:47 PM

Previous topic - Next topic

kcsl

I'm looking for a way to store 1, 2, 3 or 4 byte variables on a byte by byte basis into a byte array.
I wrote something quick and dirty that worked, but thought it was horrible so started looking for a better way.

The smallest version I can come up with is this:

Proc WriteEEPROMBytes(pwAddress As Word, pnBytes As Byte, pdwValue As Dword)
    Dim rnLoop As Byte
   
    For rnLoop = 0 To pnBytes - 1
        gnEEPROM[ pwAddress ] = pdwValue & $FF   
        Inc pwAddress
        pdwValue = pdwValue >> 8
    Next rnLoop
EndProc
I think it would work, but it does an extra bitshift that's not needed at the end.
Also it just feels messy.

I can't just do this:
gnEEPROM[ pwAddress ] = pdwValue.byte0
gnEEPROM[ pwAddress+1 ] = pdwValue.byte1
gnEEPROM[ pwAddress+2 ] = pdwValue.byte2
gnEEPROM[ pwAddress+3 ] = pdwValue.byte3

as it would always write to four elements in the array irrespective of the variable size, and I'm also not sure what would be in the higher bytes of pdwValue when a smaller size variable is passed anyway.

Anybody got a suggestion ?

Regards,
Joe
There's no room for optimism in software or hardware engineering.

trastikata

#1
1. Create the 4-bytes array as heap
2. Alias a dummy dword variable to the first item in the array
3. Use the dummy variable to write in the array
4. Or you can write to parts of the dummy variable

Device = 18F14K50
Declare Xtal = 4

Dim baMyArray[4] As Byte Heap
Dim dwDummy As Dword At baMyArray#0
Dim wTemp As Word

Main:
    dwDummy = 0xFAFBFCFD
    dwDummy.Byte0 = 0xAB
    dwDummy.Word0 = 0xABCD
   
    wTemp = 0xBCDE
    dwDummy.Word0 = wTemp
    End

trastikata

Still the fastest and the cleanest way, in my opinion, is to set array element to variable bytes when needed instead of passing parameters ...  This takes only one Assembler mnemonic per byte and still happens anyway:

Dim baMyArray[4] As Byte Heap
Dim dwDummy As Dword At baMyArray#0
Dim wTemp As Word

Main:
    dwDummy = 0xFAFBFCFD
    dwDummy.Byte0 = 0xAB
    dwDummy.Word0 = 0xABCD
   
    wTemp = 0xBCDE
    dwDummy.Word0 = wTemp
   
    baMyArray#0 = wTemp.Byte0
    baMyArray#1 = wTemp.Byte1
    End

keytapper

I suppose that it's possible to store and retrieve the data as they're sized, except for strings.
Declare Hserout_baud = 9600
Dim MyWord As Dword = 3944005050
Dim StoredWord As Dword
Dim epos as Byte = 48

Ewrite[epos] MyWord
StoredWord = Eread[epos]

Hserout [StoredWord]

This is a sketch, I'm not correctly remember the keyword.
Ignorance comes with a cost

top204

You could try the C way, using pointers, but it is certainly not the fastest way, or the smallest. However, the compiler does a very good job at craating the assembler code for it. But that type of thing does not seem to matter that much in the world of C or C++. :-)

    Dim MyByteArray[4] As Byte Heap

'----------------------------------------------------------------------------
' The main program starts here
'
Main:
    Clear MyByteArray
    EE_WriteBytes(MyByteArray, 3, $FE123456)
    HRsoutLn IHex2 MyByteArray#3, ",", IHex2 MyByteArray#2, ",", IHex2 MyByteArray#1, ",", IHex2 MyByteArray#0

'----------------------------------------------------------------------------
' Load a byte array's elements with seperated bytes of a 32-bit integer variable passed to it
' Input     : pArrayAddr holds the address of the byte array to write too
'           : pAmount holds how many elements to write (1 to 4)
'           : pValue holds the value to split and write to the array
' Output    : The array passed to the "pArrayAddr" parameter, will contain the seperated bytes
' Notes     : None
'
Proc EE_WriteBytes(ByRef pArrayAddr As Word, pAmount As Byte, pValue As Dword)
    If pAmount = 0 Then ExitProc
    If pAmount > 4 Then ExitProc
    Repeat
        Ptr8(pArrayAddr++) = pValue     ' Load an element of the array passed in pArrayAddr, with Byte00 of pValue
        pValue = pValue >> 8            ' Shift the 32-bit value right to move to its next byte
        Dec pAmount                     ' \ Loop until pAmount is 0
    Until STATUSbits_Z = 1              ' /
EndProc

On the serial terminal, it will display:

$00,$12,$34,$56

Because it has been told to seperate the first 3 bytes from the value: $FE123456.

The assembler code created by the compiler for the EE_WriteBytes procedure is:

F1_000068 equ $ ; in [TEST_18F25K20.BAS] Proc EE_WriteBytes(ByRef pArrayAddr As Word, pAmount As byte, pValue As Dword)
EE_WriteBytes
F1_000069 equ $ ; in [TEST_18F25K20.BAS] if pAmount = 0 Then ExitProc
    movf EE_WriteBytespAmount,F,0
    bnz _lbl__5
    return 0
_lbl__5
F1_000070 equ $ ; in [TEST_18F25K20.BAS] if pAmount > 4 Then ExitProc
    movlw 5
    subwf EE_WriteBytespAmount,W,0
    bnc _lbl__7
    return 0
_lbl__7
F1_000071 equ $ ; in [TEST_18F25K20.BAS] Repeat
_lbl__8
F1_000072 equ $ ; in [TEST_18F25K20.BAS] Ptr8(pArrayAddr++) = pValue
    movff EE_WriteBytespArrayAddrH,FSR0LH
    movff EE_WriteBytespArrayAddr,FSR0L
    movff EE_WriteBytespValue,POSTINC0
    infsnz EE_WriteBytespArrayAddr,F,0
    incf EE_WriteBytespArrayAddrH,F,0
F1_000073 equ $ ; in [TEST_18F25K20.BAS] pValue = pValue >> 8
    movff EE_WriteBytespValueH,EE_WriteBytespValue
    movff EE_WriteBytespValueHH,EE_WriteBytespValueH
    movff EE_WriteBytespValueHHH,EE_WriteBytespValueHH
    clrf EE_WriteBytespValueHHH,0
F1_000074 equ $ ; in [TEST_18F25K20.BAS] Dec pAmount
    decf EE_WriteBytespAmount,F,0
_lbl__10
F1_000075 equ $ ; in [TEST_18F25K20.BAS] Until STATUS.2 = 1
    bnz _lbl__8
_lbl__9
F1_000076 equ $ ; in [TEST_18F25K20.BAS] EndProc
    return 0 ; EndProc

Which is not too bad at all. Even if I do say so myself... :-)

But, as Dyanko stated, aliasing and re-addressing can be the fastest way, as long as it is always the same byte array holding the results.