Shop OBEX P1 Docs P2 Docs Learn Events
MCP3208.spin — Parallax Forums

MCP3208.spin

mynet43mynet43 Posts: 644
edited 2007-05-10 16:26 in Propeller 1
I'm using the MCP3208.spin routine provided with the Propeller Tool.

There's one line of code that I don't understand. Here's a snippet of my code:

CON
dpin = 13
cpin = 14
spin = 15
mode = $FF

OBJ
adc : "MCP3208"

PUB start | chan
adc.start(dpin, cpin, spin, mode)

repeat chan from 0 to 7
adc.in(chan)
adc.average(chan, 10)
etc, etc

Here's my question: the MCP3208 object has a global variable called 'count'.

When you call adc.start, it calls the routine adc.startx, which initializes count to zero.

When you call the entry adc.average it consists of the following code:

PUB average(channel, n) : sample | c
c := count
repeat n
repeat while c == count
sample += ins.word[noparse][[/noparse]channel]
c++
sample /= n

I understand everything except the line: repeat while c == count, which has nothing indented below it.
It looks as if count is initialized to zero, c is set equal to count and
the "repeat while c == count" should be the same as "repeat while TRUE",
which would loop forever. I know there is a c++ below but it shouldn't get
to this one if it's stuck in the loop.

I know I'm probably missing something because the code apparently works.

Help me understand why that line is there.

Thanks for your help.

Jim

Comments

  • mirrormirror Posts: 322
    edited 2007-05-08 23:07
    count is updated by the assembly routine every time a sample is completed. So the line:
    repeat while c == count
    basically says - wait while the assembly language has not yet updated the sample.

    The reason for doing this is that if the check was not there, then a sampled value could end up being used multiple times in the averaging process.
  • mynet43mynet43 Posts: 644
    edited 2007-05-08 23:27
    Thanks, that makes complete sense.

    I understand the assembly code for this routine but I haven't quite figured out how the 'counter' variable in assembly gets passed back to the 'count' variable in the spin code.

    I'll keep looking.

    Thanks again.
  • mirrormirror Posts: 322
    edited 2007-05-09 03:23
    The sequence:
    skip                    add     t1,#2                   'advance sample pointer
                            add     command,#$01            'advance command
                            djnz    t3,#cloop               'more channels?
                            wrlong  counter,t1              'channels done, update counter
                            add     counter,#1
                            jmp     #main_loop              'perform conversions again
    
    

    is where it happen.
    Initially t1 points to ins[noparse][[/noparse]0]
    Every time around the loop (djnz t3,#cloop)·t1 gets incrmented by 2, so will point in turn to
    ins[noparse][[/noparse]1/2], ins[noparse][[/noparse]1], ins[noparse][[/noparse]1 1/2], ins[noparse][[/noparse]2], ins[noparse][[/noparse]2 1/2], ins[noparse][[/noparse]3], ins[noparse][[/noparse]3 1/2].
    Once it exists the loop, t1 will be pointing to count.
    At that point the value of counter is written to the address pointed to by t1 - which is count in the spin code. And·counter is incremented·for next time.

    Then the assembly code goes and does it all again.

    ·
  • mynet43mynet43 Posts: 644
    edited 2007-05-09 14:19
    Thanks, that's a big help!

    I'm still learning the Propeller Assembly language, I'm almost there...

    What fooled me here was that I assumed that the 'wrlong' command used the same syntax as most of the other instructions, i.e. right to left. Bad assumption! As soon as I saw that, everything fell into place.

    Thanks again.

    Jim

    P.S. I think the people that write these routines should take credit for them by putting their name in the remarks at the top. This is a pretty amazing piece of code.
  • mynet43mynet43 Posts: 644
    edited 2007-05-10 16:01
    Another question...

    I'm having trouble understanding how a particular call to an assembly language routine works.

    In the "startx" routine of MCP3208.spin there's a statement that says:

    return cog := cognew(@entry, @ins) + 1

    To me this says start a new assembly language cog with entry point @entry and parameter list at @ins. This all seems fine.

    Below, there's the routine called "in", which returns the adc value to the caller:

    PUB in(channel) : sample
    '' Read the current sample from an ADC channel (0..7)
    return ins.word[noparse][[/noparse]channel]

    What I don't understand is that the last line looks like it is calling the routine "ins", which is the parameter list and not the entry point for the assembly code.

    The manual doesn't seem to cover this. Can someone please explain?

    Thanks for your help!
  • mynet43mynet43 Posts: 644
    edited 2007-05-10 16:03
    Forget it, I just figured it out! It's not calling a routine, it's returning a value that's sitting there...
  • mynet43mynet43 Posts: 644
    edited 2007-05-10 16:26
    One more time...

    I've been agonizing over this routine (MCP3208.spin), trying to really understand it.

    In the process I've been running timing tests by counting clock cycles to see how long it takes to get a sample and an average sample.

    As a result, I think I discovered a bug in the program.
    The sample average routine works great.

    However, if you call the individual sample routine multiple times, you expect to get multiple readings from the chip.

    This isn't what happens. Instead of returning a new sample value, it returns whatever is sitting in the last sample buffer.

    This means if you call it 10 times you may well get the same old value each time, without it ever being updated.

    The "in" routine is currently:

    PUB in(channel) : sample
    '' Read the current sample from an ADC channel (0..7)
    return ins.word[noparse][[/noparse]channel]


    Here's what I think it should be, to force an adc read whenever it's called:

    PUB in(channel) : sample | c
    c := count
    repeat while c == count ' wait for new adc sample
    '' Read the current sample from an ADC channel (0..7)
    return ins.word[noparse][[/noparse]channel]

    When I made this change and tested it, the timing was very close to that of the average routine for the same number of samples.

    Would someone please take a look at this and let me know what you think?

    Thanks for your help.

    Jim
Sign In or Register to comment.