Longmove in spin — Parallax Forums

# Longmove in spin

Posts: 16
edited 2021-09-12 04:48

Anyone can explain me a little why the longmove(@cs, @cspin, 4) is used and how that relates to the pins that get assigned at the start.

I set my pins too 15, 12, 14, 13

isn't it easier to just write directly to a pin?

`
var

long cs ' chip select
long clk ' clock
long mosi ' master out slave it (to MCP3208)
long miso ' master in slave out (from MCP3208)

pub start(cspin, clkpin, mosipin, misopin)
stop

longmove(@cs, @cspin, 4) ' copy pins

outa[cs] := 1 ' output high (disable)
dira[cs] := 1

outa[clk] := 0 ' output low
dira[clk] := 1

`

• Posts: 240

@AndyProp said:
Anyone can explain me a little why the longmove(@cs, @cspin, 4) is used and how that relates to the pins that get assigned at the start.

I set my pins too 15, 12, 14, 13

isn't it easier to just write directly to a pin?

`
var

long cs ' chip select
long clk ' clock
long mosi ' master out slave it (to MCP3208)
long miso ' master in slave out (from MCP3208)

pub start(cspin, clkpin, mosipin, misopin)
stop

longmove(@cs, @cspin, 4) ' copy pins

outa[cs] := 1 ' output high (disable)
dira[cs] := 1

outa[clk] := 0 ' output low
dira[clk] := 1

`

The longmove is a more compact/efficient way to copy a set of long variables to another set of long variables.

longmove is given three parameters, the first parameter is the address pointer of the destination long variable(s), the second parameter is the address/pointer of the source variable(s), the third parameter is the number of longs to be copied.

Note: In order for this copy method/style to work, the source variables need to be consecutive in memory, likewise for the destination variables.

```cs := cspin
clk := clkpin
mosi := mosipin
miso := misopin
```

Your code snippet appears to be from one of the drivers for the MCP3208 ADC. I believe that driver includes the use of PASM code, which needs to have the four pin parameters passed to it. So the driver has the set of pin values copied to another set of longs to be passed to the PASM routine.

• Posts: 16

Yes, thanks a lot for replying, and yes you are correct about the MCP3208.

I am editing it to read from 3 consecutive 3208s in one pass.

All the best to you

• Posts: 7,706
edited 2021-09-12 19:39

I believe that driver includes the use of PASM code...

No, it's a simple Spin1 driver, but I do need to save the pins so they can be used by the readx() method (see attached).

I am editing it to read from 3 consecutive 3208s in one pass.

You could just use three copies of the driver with shared SCLK, MOSI, and MISO pins -- THE CS pins would be unique to each (six pins total for 3x chips). Then you could put a simple method like this in your application:

```pub read_all(p_buf) : idx | ch

'' -- p_buf is pointer to array of 24 longs

repeat ch from 0 to 7

repeat ch from 0 to 7

repeat ch from 0 to 7
```

This reads three consecutive devices in one pass without having to create an entirely new object. SPI bus pins, other than CS, are designed to be shared.

You could also create a macro method that treats your three 8-channel ADCs as one 24-channel ADC.

```pub read_ch(ch) : value

case ch
00..07 :

08..16 :

17..23 :

other  :
return 0
```

The point here is that a we should use methods to cover specialty cases when a generic object handles the heavy load.

• Posts: 16
edited 2021-09-13 13:06

Actually I like this idea, not sure exactly of the code requirement as I am not so familiar with spin. Basically just changing the chip select according to channel sets required. This would then be infinitely scalable.

```case ch
00..07 :
ChipSelect := chipselect1pin

08..16 :
ChipSelect := chipselect2pin

17..23 :
ChipSelect := chipselect3pin

other  :
return 0

mux := 24+ch

outa[ChipSelect] := 0     'set CS low
dira[DatatoChipPin] := 1   'set pin to putput
```

No clue why the case ch 0..7 etc.. ended up outside the code block, maybe Monday morning blues :-)

then continue with the usual readx code.
I also to make the code less complex set the mux with a simple addition 24 to the value of the channel

`mux := 24+ch`

Then the result can be stored in arrays by ch,

Jon, if the array is based on longs will those values be available to other cogs.
say for example

As I stay thinking, the registers are 32 bits wide I understand and and we only use 12 bits. Almost worth using a register to store two channel value in bits 0-17 and 18-31, of course that would also get messy with 3 ADC's. With 4 it would be neat but I wonder with the additional code if anything would be saved.

• Posts: 16
edited 2021-09-13 13:03
```case ch
00..07 :
ChipSelect := CS1Pin

08..16 :
ChipSelect := CS2Pin

17..23 :
ChipSelect := CS3Pin

other  :
return 0

mux := 24+ch

outa[ChipSelect] := 0     'set CS low
```
• Posts: 285
edited 2021-09-13 12:53

Andy,

For block code, use three backticks on a line by itself (before and after the code)

`code here`

(I added spaces in between the backticks just for illustrative purposes; there shouldn't be any spaces between them when you use them)

Cheers

EDIT: nevermind... it interprets it anyway. Imagine these are backticks:
'''
code
'''

• Posts: 7,706
edited 2021-09-13 14:42

I also to make the code less complex set the mux with a simple addition 24 to the value of the channel

Really? This is the output I get doing the proper mux calculation (2nd column) vs your "less complex" version (3rd column).

``` 0  11000  11000
1  11001  11001
2  11010  11010
3  11011  11011
4  11100  11100
5  11101  11101
6  11110  11110
7  11111  11111
8  11000  00000
9  11001  00001
10  11010  00010
11  11011  00011
12  11100  00100
13  11101  00101
14  11110  00110
15  11111  00111
16  11000  01000
17  11001  01001
18  11010  01010
19  11011  01011
20  11100  01100
21  11101  01101
22  11110  01110
23  11111  01111
```

This would then be infinitely scalable.

No, it isn't. If you next decide you want a 32-channel ADC object, you need a new object with another start() method parameter for the new CS pin. If you use the method I shared above, then it doesn't matter how many channels you have; you can scale that method as required and use pin constants from your application.

I think it's a waste of time creating a 24-channel version, but if you're going to do it, I suggest the read() method do something like this. Of course, you would have passed the individual chip select pins through the start() method.

```pub read(ch) : level | cs, mux

'' -- single-ended mode

if ((ch => 0) and (ch <= 23))                                 ' valid channel?
cs := lookupz(ch >> 3 : cs1, cs2, cs3)                      '  yes, get CS for device
else
return 0                                                    '  no, abort

mux := %1_0_000 | (SE << 3) | (ch & %111)                     ' SE mux bits

outa[cs] := 0                                                 ' activate adc

mux <<= constant(32-5)                                        ' prep for msb output
repeat 5                                                      ' send mux bits
outa[mosi] := mux <-= 1                                     ' output a bit
outa[clk] := 1                                              ' clock the bit
outa[clk] := 0

repeat 13                                                     ' null + 12 data bits
outa[clk] := 1                                              ' clock a bit
outa[clk] := 0
level := (level << 1) | ina[miso]                           ' input data bit

outa[cs] := 1                                                 ' de-activate adc

return (level & \$FFF)
```

Note that the proper calculation of mux truncates unused bits that your mux := 24 + ch does not. And, FWIW, even if you did this (which would work):

```  mux := 24 + (ch & %111)
```

...it's not as obvious to newcomers using your code what's going on. Code should always be easy to understand. The compiler sees 24 and %11000 as the same thing, but using binary notation and named constants will help new people when the look up the mux bits

• Posts: 16
edited 2021-09-13 16:47

@avsa242 said:
Andy,

For block code, use three backticks on a line by itself (before and after the code)

I tried that, but actually it does not always appear to work, maybe a firefox thing I get smiley faces instead.

It took

@JonnyMac said:

I also to make the code less complex set the mux with a simple addition 24 to the value of the channel

Really? This is the output I get doing the proper mux calculation (2nd column) vs your "less complex" version (3rd column).

``` 0  11000  11000
1  11001  11001
2  11010  11010
3  11011  11011
4  11100  11100
5  11101  11101
6  11110  11110
7  11111  11111
8  11000  00000
9  11001  00001
10  11010  00010
11  11011  00011
12  11100  00100
13  11101  00101
14  11110  00110
15  11111  00111
16  11000  01000
17  11001  01001
18  11010  01010
19  11011  01011
20  11100  01100
21  11101  01101
22  11110  01110
23  11111  01111
```

Thank you for the input.

In the end I will just have an object that loads the values from the ADC's into arrays, it is all I want to do with it.
Like GetADCValues, how I share the array values to other cogs I have no idea yet but will find how to do that too. This is what I was doing for a few minutes:

```Fader := 0
repeat cs from 1 to 3
repeat channel from 0 to 7
pst.Str(String(" CS="))
pst.Dec(CS)
pst.Str(String(" Channel="))
pst.Dec(channel)
pst.Str(String(" MUX="))
mux :=channel +24
pst.Bin(mux, 5)
' Read from DAC and store the result in the Fader array
pst.Char(pst#NL)

pst.Char(pst#NL)

```