poke and @bptrinc

Pic8581

New Member
Hi

I would like to do a few ADC conversions, poke the values into memory and then use them for averaging.
Unfortunately the @bptinc is not doing what I expect (It does auto increment, but where does the value go?).

What am I doing wrong?

Thanks for any pointer...




b40=0
let bptr = 40
let @bptr = 40 ;at this time bptr is pointing to b40 and the value of 40 is loaded correctly

;do
;readadc A.0, b0 ; read value into b0
;poke @bptrinc, b0 ; for future use -> this was supposed to fill a buffer region
;loop while....

; Test code for "poke @bptrinc "
poke @bptrinc, 55 ; at this time b40 is populated with 55 correctly
poke @bptrinc, 65 ; b41 is supposed to by filled with 65 but I can't find what is happening here anymore, since I do not
; get any errors I assume that another register is written, but which one?
poke @bptrinc, 75 ; b42 ... same
poke @bptrinc, 85
 

Goeytex

Senior Member
You are using poke & @bptrinc incorrectly. @bptrinc is the value stored in the location with post increment. bptr is the location. So when you poke @bptrinc you are poking location 55, which is the last B location in an X2 Picaxe so the pointer overflows to location 0. bptr / @bptr cannot be used above location 55.
You need to tell us what Picaxe you are using so we don't have to guess. I will assume a 28X2. See the code below for some examples

Code:
[color=Blue]symbol [/color][color=Black]ram_loc [/color][color=DarkCyan]= [/color][color=Purple]b0[/color]

[color=Blue]let [/color][color=Purple]b40[/color][color=DarkCyan]=[/color][color=Navy]0[/color]
[color=Blue]let [/color][color=Purple]bptr [/color][color=DarkCyan]= [/color][color=Navy]40[/color]
[color=Blue]let [/color][color=Purple]@bptr [/color][color=DarkCyan]= [/color][color=Navy]255 [/color]

[color=Green]; Test code for "poke @bptrinc "[/color]
[color=Blue]let [/color][color=Purple]@bptrinc [/color][color=DarkCyan]= [/color][color=Navy]55 [/color][color=Green]; at this time b40 is populated with 55 correctly[/color]
[color=Blue]let [/color][color=Purple]@bptrinc [/color][color=DarkCyan]= [/color][color=Navy]65 [/color][color=Green]; b41 is supposed to by filled with 65 [/color]
[color=Blue]let [/color][color=Purple]@bptrinc [/color][color=DarkCyan]= [/color][color=Navy]75 [/color][color=Green]; b42[/color]
[color=Blue]let [/color][color=Purple]@bptrinc [/color][color=DarkCyan]= [/color][color=Navy]85 [/color][color=Green]; b43 


'//////   or using poke  //////[/color]

[color=Blue]let [/color][color=Black]ram_loc [/color][color=DarkCyan]= [/color][color=Navy]40[/color]
[color=Blue]poke [/color][color=Black]ram_loc, [/color][color=Navy]95  [/color][color=Black]: [/color][color=Blue]inc [/color][color=Black]ram_loc[/color]
[color=Blue]poke [/color][color=Black]ram_loc, [/color][color=Navy]100 [/color][color=Black]: [/color][color=Blue]inc [/color][color=Black]ram_loc[/color]
[color=Blue]poke [/color][color=Black]ram_loc, [/color][color=Navy]105 [/color][color=Black]: [/color][color=Blue]inc [/color][color=Black]ram_loc[/color]
[color=Blue]poke [/color][color=Black]ram_loc, [/color][color=Navy]110 [/color][color=Black]: [/color][color=Blue]inc [/color][color=Black]ram_loc[/color]
[color=Blue]poke [/color][color=Black]ram_loc, [/color][color=Navy]115 

  [/color][color=Green]'// or //
  
  [/color][color=Blue]for [/color][color=Purple]bptr [/color][color=DarkCyan]= [/color][color=Navy]40 [/color][color=Blue]to [/color][color=Navy]49     [/color][color=Green]'use b40 to b49 for buffering ADC
      [/color][color=Blue]readadc a.0[/color][color=Black], [/color][color=Purple]@bptr
       [/color][color=Blue]pause [/color][color=Navy]100
  [/color][color=Blue]next 
  
      [/color][color=Green]'//  or //
   
  [/color][color=Purple]bptr [/color][color=DarkCyan]= [/color][color=Navy]20 [/color][color=Green]' set the pointer to B20   
  [/color][color=Blue]do 
     readadc a.0[/color][color=Black],[/color][color=Purple]@bptrinc
     [/color][color=Blue]pause [/color][color=Navy]100
  [/color][color=Blue]loop while [/color][color=Purple]bptr [/color][color=DarkCyan]< [/color][color=Navy]30[/color]
There are other, more common ways to to average ADC readings. Here's one
Code:
[color=Blue]symbol [/color][color=Purple]ADC_VAL [/color][color=DarkCyan]= [/color][color=Purple]b0 [/color]
[color=Blue]symbol [/color][color=Purple]cntr  [/color][color=DarkCyan]= [/color][color=Purple]b1[/color]
[color=Blue]symbol [/color][color=Purple]SUM  [/color][color=DarkCyan]= [/color][color=Purple]W1  

sum [/color][color=DarkCyan]= [/color][color=Navy]0 [/color]

[color=Blue]do
    for [/color][color=Purple]cntr [/color][color=DarkCyan]= [/color][color=Navy]1 [/color][color=Blue]to [/color][color=Navy]16 
        [/color][color=Blue]readadc a.0[/color][color=Black], [/color][color=Purple]adc_val
        sum [/color][color=DarkCyan]= [/color][color=Purple]sum [/color][color=DarkCyan]+ [/color][color=Purple]adc_val
    [/color][color=Blue]next 
    [/color][color=Purple]adc_val [/color][color=DarkCyan]= [/color][color=Purple]sum [/color][color=DarkCyan]/ [/color][color=Navy]16 
    [/color][color=Blue]sertxd ([/color][color=Red]"Average ADC value is "[/color][color=Black],#[/color][color=Purple]adc_val[/color][color=Black],[/color][color=Blue]cr[/color][color=Black],[/color][color=Blue]lf)
    [/color][color=Purple]sum [/color][color=DarkCyan]= [/color][color=Navy]0 [/color]
[color=Blue]pause [/color][color=Navy]1000[/color]
[color=Blue]loop [/color]
 
Last edited:

lbenson

Senior Member
>pointer overflows to location 0. bptr / @bptr cannot be used above location 55.

bptr doesn't overflow (and cycle back to 0 (as a pointer--the value of bptr can still be above 511/255)) until the top of ram is reached--511 on M2 devices (the 512th byte of ram, of which the first 28 are also registers b0-b27), and 255 on the X2 devices (see Manual 2 for variations in storage variable sizes).

If the value of bptr on an M2 device is 27, then @bptrinc = 40 results in the value of 40 being placed in ram at byte 27 (b27), and bptr now (after the increment), pointing to RAM byte 28, past the registers but still accessible with peek/poke and @bptr.

Note that the increment in bptrinc is of the pointer, not of the value being pointed to.

You would not customarily use poke and @bptr in the same statement (though you can), since that is double indirection--is what you want simply @bptrinc=75 or do you actually want to poke into the location indicated by the value which bptr is pointing to and next poke into the value indicated by the following bptr location?
 
Last edited:

Goeytex

Senior Member
bptr doesn't overflow (and cycle back to 0) until the top of ram is reached--511 on M2 devices (the 512th byte of ram, of which the first 28 are also registers b0-b27), and 255 on the X2 devices.
It overflows to 0 after 55 in both the PE5 and PE6 and Simulators. This is why a value of 85 is placed in location 0.

Run the OP's Code and have a look.

Actually is is not overflowing. Poke @bptriinc, 55 is writing to location 0 since location 41 is a value of 0. It was simply coincidental that the value was 55 which happens to be the same number of system B variables.
 
Last edited:

hippy

Technical Support
Staff member
I have not analysed what the OP's code is doing but there should not be a wrapround for bPtr after 55. As lbenson notes it should wrapround at the end of RAM, after 127, 255, or 511 depending on PICAXE. This works as expected when simulated -

Code:
bPtr = 55
Poke @bPtrInc, 0
SerTxd( "bPtr=", #bPtr, CR, LF )
Do:Loop
I also suspect it's a double-indirection which is causing the appearance of wrapround, data being written to RAM location 0 (b0), even though 'bPtr' points elsewhere. Again, as lbenson notes, double-indirection is unusual and can cause confusing or unexpected results.
 

AllyCat

Senior Member
Hi,

I suspect that the OP didn't intend to use double indirection. So note that poke bptr,variable and @bptr = variable each do exactly the same thing (which is probably what was wanted). However, the @ can be only associated with bptr (i.e. not with b1, etc.) but it (the variable) has the advantage that it can be included within an expression (e.g. @bptr = @bptr * 2) whilst peek and poke must use separate statement lines.

Also, IMHO it would be better to use separate inc bptr statements (rather that @bptrinc) until the concept of indirection is fully understood. For example @bptr = @bptrinc mignt not do what you expect. ;)

Cheers, Alan.
 

Pic8581

New Member
Bonus questions

Hi
here is a general related question that I have not found an answer for yet.
Now that I have my data in b40 to b50 let's say. I want to sort it.

The manual talks about arrays but not how to access them.



Other languages allow to access an array with array[n] for instance

Something like


symbol i = b0

For i = 40 to 50

do something with b

next i
 

marks

Senior Member
Hi Pic8581 ,
I think others have covered it but heres another example
best to keep your data in an orderly fashion

FOR bptr = 40 TO 50
SERTXD(@bptr)
NEXT
 

AllyCat

Senior Member
Hi,

Yes that's what the bptr is intended for. But in some cases you might use LOOKUP or LOOKDOWN.

If you need more than one array then you need to manage that yourself. For example:

Symbol BeginI = 40
Symbol EndI = 50
Symbol BeginJ = 51 ... etc..

For bptr = BeginI to EndI
; do something with @bptr
Next bptr

Cheers, Alan.
 

lbenson

Senior Member
And to further complicate array handling on the picaxe, if you want to move data from one array to another, you have to use bptr for both arrays, meaning that you have to access an item with @bptrinc, save the bptr value, put the pointer to the destination array in bptr, move the retrieved value into the new array with @bptrinc, save the destination bptr, and repeat.

It's a little easier if you have one array in ram and another in the scratchpad, since you can then use @ptrinc = @bptrinc.

I've said it before, but I'd lobby for another bptr at least so that you can easily move arrays in ram--especially useful with the 512 bytes of ram in the M2 devices, and perhaps subsequent picaxes will have even more.
 

Pic8581

New Member
I found a solution -> workaround, still would like if there is something better to sort an array:


bptr = 40 ' set the array pointer to B40

do
readadc a.0,@bptrinc
pause 100
loop while bptr < 43 ' three values captured


symbol i = b15
symbol k = b16
symbol swapped = b17

do

For i = 40 to 41
k=i+1
peek i , b10
peek k, b11


let swapped = 0

if b11 < b10 then
poke i , b11
poke k , b10
swapped=1 ;value was sapped -> sort possibly not finished yet

end if

next i
loop while swapped = 1



BTW: Is there a way to watch a symbol instaed a Ram location: "k" instead of b10 (and having to remember that b10 is k) ?
 

hippy

Technical Support
Staff member
Here's how I would sort an array, data in RAM 40 to 50. Simple bubble sort using PE6 ...

Code:
#Macro GetTwoValues( idx, bx, by )
  bPtr = idx
  bx = @bPtrInc
  by = @bPtrInc
#EndMacro

#Macro PutTwoValues( idx, bx, by )
  bPtr = idx
  @bPtrInc = bx
  @bPtrInc = by
#EndMacro

; Create random numbers
For bPtr = 40 To 50
  Random w0
  @bPtr = b0
Next

; Print the numbers
For bPtr = 40 To 50
  SerTxd( #@bPtr, " " )
Next
SerTxd( CR, LF)

; Sort numbers
Do
  b3 = 0
  For b0 = 40 To 49
    GetTwoValues( b0, b1, b2 )
    If b1 > b2 Then
      PutTwoValues( b0, b2, b1 )
      b3 = 1
    End If
  Next
Loop Until b3 = 0	

; Print the numbers
For bPtr = 40 To 50
  SerTxd( #@bPtr, " " )
Next
SerTxd( CR, LF)
 

AllyCat

Senior Member
Hi,

Hmm, that code does rather highlight a "weakness" in the PE6 "random number" generator. ;)

In principle, the following code (which passes syntax checking) should be a "neat" way to exchange bytes in a list. But sadly, PE5 and PE6 both in simulation mode or when programming a "real" PICaxe all give different results and none of them "correct", or at least as might be expected (or hoped for). :(

Code:
if @bptrinc > @bptr then
   swap @bptrdec,@bptrinc
endif
So, using @bptr{inc/dec} within peek and poke instructions is perhaps the tidiest way to move bytes around in an array.

Cheers, Alan.
 

hippy

Technical Support
Staff member
In principle, the following code (which passes syntax checking) should be a "neat" way to exchange bytes in a list. But sadly, PE5 and PE6 both in simulation mode or when programming a "real" PICaxe all give different results and none of them "correct", or at least as might be expected (or hoped for). :(
The problem there is not seeing things as they are under the hood. For example, "Swap x,y" can be implemented in a number of ways, one of them being -

tempx = x
tempy = y
y = tempx
x = tempy

Replace 'x' and/or 'y' with any @...inc or @...dec variables and one can see there may be double increments or decrements and what actually gets done depends on the exact operations and order of things done under the hood.

In most cases the order of execution is obvious or doesn't matter but in a few cases when using @...inc or @...dec it isn't.
 

Technical

Technical Support
Staff member
We wouldn't recommend using @ in pseudo commands such as swap as unexpected behaviour will result.

For instance
swap b0,b1

is processed internally as


let temp = b1
let b1 = b0
let b0 = temp

and hence explains why your code does not work as you would expect.
 

AllyCat

Senior Member
Hi,

Thanks hippy and Technical, I must admit that I was (and am) being a Devil's Advocate. ;)

However, isn't the idea of a high level language that it's supposed to "shield" the user from what's happening "under the hood" (rhetorical question)? But, I do now see that the manual doesn't actually define whether the "Post Increment" occurs after the read/write, the operation, the complete instruction, or what?

Also, I do wonder if/how the typical user is even aware of the "pseudo" commands (I don't believe that their existence is even documented in the manuals, let alone which they are). I was quite surprised to discover that SWAP and PWMDUTY are pseudo commands (in quite a "big" way), but CALIBADC is not.

Cheers, Alan.
 

Technical

Technical Support
Staff member
"shield" the user from what's happening "under the hood" (rhetorical question)?.
Indeed, swap just got accidentally missed and we'll add a warning to the compiler.

Try something like this and you'll see the expected error msg:

inc @bptrinc
 

Pic8581

New Member
marks, I am not sure how this applies.

srnet, my question is how I can access RAM locations though an index.
Like "add 1 to all Ram locations between b1 and b20"

for i = 1 to 20

inc b

next i
 

lbenson

Senior Member
add 1 to all Ram locations between b1 and b20
Code:
for bptr = 1 to 20
  inc @bptr
next bptr
Note that if you put your code in a post within the tags [ code] and [ /code] (without the spaces), any indentation in your code will be retained.
 
Top