Shop OBEX P1 Docs P2 Docs Learn Events
Propeller Chip and DataloggerSPI — Parallax Forums

Propeller Chip and DataloggerSPI

-GRIMM--GRIMM- Posts: 56
edited 2011-03-02 10:48 in Propeller 1
For a quick background, I know my way around with the BS2, but needed something with more speed for this current projects, so I decided to go with the Propeller chip. The spin language is new to me, so this might be easy for you guys.

I am using the propeller chip to read a value from a few sensors (already got that part working).

The problem arises when I try to use dataloggerSPI with the parallax memory stick datalogger. I have no problem writing a string to the USB drive, but the value I need to write is a number (a byte).

The program I have checks for the directory, deletes it if present and recreates it (from the test code), opens it, writes a file header to it, then goes in to the data loop.

The data loop reads the sensor (coming from an ADC0831 so I believe it may be binary in form), opens the file, writes the value, closes the file.

When i open the file all I see is a bunch of random characters.

Can anyone show me how to write a byte value using dataloggerSPI, or possibly convert it to numerical and save it with CR's between each value?

The code i am using right now is:

logger.openFileForWrite(string("Data.txt"),0)
logger.writeToFile(byte[lm34temp], 8 ,0)
logger.closeFile(string("Data.txt"))

i've tried writeToFile(@lm34temp, 4,0), as well as a few others.


Thanks

-Steven

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2011-02-28 11:40
    The trick is to take the decimal output routine from something and modify it to produce a string. This is from FullDuplexSerial:
    PUB dec(value, address) | i
    
    '' Print a decimal number.  There's no checking whether the resulting string will fit.
    '' If the string buffer is at least 12 bytes long, there should be no problem.
    '' This routine returns the address of the terminating zero byte to make it easy to add on to the end of the string.
    
      if value < 0
        -value
        byte[address++] := "-"
    
      i := 1_000_000_000
    
      repeat 10
        if value => i
          byte[address++] := value / i + "0"
          value //= i
          result~~
        elseif result or i == 1
          byte[address++] := "0"
        i /= 10
      byte[address]~  ' mark end of string
      return address
    

    To use this, you'd do:
    VAR byte buffer[12]
    '...
    dec(byte[lm34temp],@buffer)
    logger.writeToFile(@buffer,strsize(@buffer),0)
    
  • -GRIMM--GRIMM- Posts: 56
    edited 2011-02-28 18:20
    Thank you!

    Finally recording correct, legible data!

    What a relief. Any insight on writing a carriage return after each value? right now they are all in a line.

    I have tried multiple things, none of these worked;


    VAR
    · word CRLF

    CRLF = $0A0D
    logger.writeToFile(@CRLF,2,0)


    logger.writeToFile(10,1,0)
    logger.writeToFile(13,1,0)


    logger.writeToFile(string(" \r\n").....)

    etc.

    thanks!
  • -GRIMM--GRIMM- Posts: 56
    edited 2011-02-28 18:34
    Experiencing a minor problem with that code.

    I have a program to test the output, and am getting '21' as my value.

    When i save this to the USB drive it saved all the numbers as '8'

    Any idea why it might do this?

    Thanks

    This is the code im using right now, after creating the folder and file...
    logger.openFileForWrite(string("Data.txt"),0)
    
    repeat 100
      
      !outa[17]
    
        waitcnt(2_000_000+cnt)
        dira[21] :=0     'set pin 21 as input
        lm34temp :=0     'starts the lm34temp variable as 0
        temp:=ina[21]    'sets the value of temp to the value of pin 21 (one or zero)
        dira[20]~~       'sets pin as output
        outa[20]~~       'sets pin 20 high  
        outa[20]~        'sets pin 20 low    'takes chip select low activating the adc       'the ADC0831
    
        repeat 8  
          dira[19]~~     'sets pin as output
          outa[19]:=1    'sets clock (pin 19) high      
          outa[19]:=0    'sets clock (pin 19)low  'takes the adc clk low 
            if ina[21]==1  
               temp:=1
            else
             temp:=0        
          lm34temp:=lm34temp*2
          lm34temp:=lm34temp+temp
    
        dec(byte[lm34temp],@buffer2)
      
      'logger.openFileForWrite(string("Data.txt"),0)
      logger.writeToFile(@buffer2,strsize(@buffer),0)
    
    
    logger.closeFile(string("Data.txt"))
    
    I have the
    PUB dec(value, address) | i

    routine at the bottom of the program
  • kuronekokuroneko Posts: 3,623
    edited 2011-02-28 18:42
    logger.writeToFile(@buffer2,strsize(@buffer),0)
    
    Shouldn't that read strsize(@buffer2)? There may be other issues though.
  • Mike GreenMike Green Posts: 23,101
    edited 2011-02-28 18:43
    Why do you have @buffer2 ? Shouldn't it be @buffer ? Or maybe the other way around?

    To write a carriage return / line feed (needed for Windows), do: logger.writeToFile(string(13,10), 2, 0)

    If you want just a carriage return (like for MacOS), leave out the ", 10" and change the ", 2" to ", 1"
  • -GRIMM--GRIMM- Posts: 56
    edited 2011-02-28 19:05
    Yes kuroneko, it should be buffer2. I thought that would solve the problem as well but it didnt.

    Thank you! finally have a carriage return.

    I tested the sensor, current output is 65.

    I run the program and this is what is saved to the flash drive.

    Datalog Test
    33
    33
    33
    33
    33
    33
    33
    33
    33
    33
    33
    33
    33
    33
    33
    ... etc


    any ideas?

    thanks

    -Steven
  • kuronekokuroneko Posts: 3,623
    edited 2011-02-28 19:26
        repeat 8  
          dira[19]~~     'sets pin as output
          outa[19]:=1    'sets clock (pin 19) high      
          outa[19]:=0    'sets clock (pin 19)low  'takes the adc clk low 
            if ina[21]==1  
               temp:=1
            else
             temp:=0        
          [COLOR="red"]lm34temp:=lm34temp*2
          lm34temp:=lm34temp+temp[/COLOR]
    
        dec([COLOR="blue"]byte[lm34temp][/COLOR],@buffer2)
    
    You assemble the byte value in lm34temp and then use this as an address??? The dec() function takes a value/buffer pair so you should get away with dec(lm34temp, @buffer2).
    lm34temp := lm34temp*2 + ina[21]
    
    Will be sufficient :) But you should get it working first.
  • -GRIMM--GRIMM- Posts: 56
    edited 2011-02-28 19:37
    That's it!

    Took out the byte[] and now it saves the temperature value the test program is outputting.

    Thank you!

    Just to verify, the dec() can record any number of digits?

    Now all i have to do is find a way to record the time value. Can anyone point me in the right direction?

    Thank you all
  • kuronekokuroneko Posts: 3,623
    edited 2011-02-28 19:41
    -GRIMM- wrote: »
    Just to verify, the dec() can record any number of digits?
    The input value is a long, as it's decimal conversion you get a maximum of 10 digits a sign and the string terminator -> 12 byte buffer.

    You can obviously append to the buffer provided you make it bigger and pass the correct address to subsequent conversion calls.
  • -GRIMM--GRIMM- Posts: 56
    edited 2011-02-28 19:55
    That will be plenty. I only need a range of 0-1000.

    Any hints on outputting time steps?

    Thank you!

    -Steven
  • kuronekokuroneko Posts: 3,623
    edited 2011-02-28 20:04
    -GRIMM- wrote: »
    Any hints on outputting time steps?
    Where do you get your time from and what format is it? IIRC the common objects let you extract hours/minutes/seconds etc so I'd suggest extracting them and send them out as e.g. H:M:S. Or if it's just (increasing) numbers then just print/save them.
  • -GRIMM--GRIMM- Posts: 56
    edited 2011-02-28 20:41
    right now i'm just logging 'temp, cnt'

    and since _xinfreq = 6_250_000 i an just taking the change between current and last and dividing by 6,250,000
  • kuronekokuroneko Posts: 3,623
    edited 2011-02-28 20:47
    Just call dec() with cnt as the first parameter. Note that you may end up with negative values. You could also incorporate the Simple_Numbers object which gives you several conversion options (available in the PropellerTool library).
  • -GRIMM--GRIMM- Posts: 56
    edited 2011-02-28 21:01
    Im currently calling

    dec(cnt,@buffer3)

    the cnt im getting back is about 8,500,000 (coordinating to about 1.3 seconds) different than the one before it. But i can see the LED blinking about 10 times per second.
  • kuronekokuroneko Posts: 3,623
    edited 2011-02-28 21:06
    -GRIMM- wrote: »
    But i can see the LED blinking about 10 times per second.
    That sounds like a complaint. Should it be slower? What makes it blink (some code would be useful)?
  • -GRIMM--GRIMM- Posts: 56
    edited 2011-02-28 21:58
    Sorry, no not a complaint.

    I have it change the state of a pin connected to the LED every time it finishes the loop.

    on/off = 2 data points.

    What frequency does cnt operate at?

    thanks
  • kuronekokuroneko Posts: 3,623
    edited 2011-02-28 22:01
    It increments with clkfreq. So for you - provided you use PLL16X - that's 100MHz.
  • -GRIMM--GRIMM- Posts: 56
    edited 2011-03-01 08:25
    i'm using:

    _clkmode = xtal1 + pll16x

    is that still 100MHz?

    Thanks, everything is coming together!
  • Mike GreenMike Green Posts: 23,101
    edited 2011-03-01 08:36
    PLL16X gives a 16 times multiplication of your crystal frequency. Similarly, PLL8X gives an 8 times multiplication. Most Propeller boards use a 5MHz crystal. With PLL16X, that would give an 80MHz system clock frequency which is the maximum system clock frequency for full industrial temperature range. Some boards use a 6.25MHz crystal for 100MHz. The Propeller datasheet shows the maximum clock frequency vs. temperature and supply voltage and also shows clock frequency vs. power consumption. Note that the higher clock frequencies require additional care in PCB design, particularly bypassing and routing of leads.
  • -GRIMM--GRIMM- Posts: 56
    edited 2011-03-01 08:41
    Interesting.

    Where can I read up on the PCB care?

    Thanks

    -Steven
  • Mike GreenMike Green Posts: 23,101
    edited 2011-03-01 10:39
    It's scattered through various forum threads. There are several forum members who have made Prop boards designed to run at 100MHz or 104MHz and they've discussed some of their design choices. Most important is keeping supply leads short and direct. You need bypass capacitors as close as possible to the the Prop power leads. You have to use all the power pins on the Prop package (or you'll get other problems as well). The Demo Board, Propeller Backpack, and Cluso99's RamBlade are all examples of good design. The RamBlade normally comes with a 6.5MHz crystal and runs at 104MHz.
  • -GRIMM--GRIMM- Posts: 56
    edited 2011-03-01 21:56
    Learned alot of interesting things looking that up, thanks.

    I have yet another question though:

    With your help, I got the previous code working for an ADC0831 and LM34 temp sensor.

    But when i take the code from the LISY300 gyro test program (used it to make sure the circuit is working, checks out) the values from the gyroscope all save as a 0 or 8191.

    Everything up to this point in the code works:
    repeat 100                       
    
      Measure
      dec(ADC,@buffer2)  
      logger.writeToFile(@buffer2,strsize(@buffer2),0)
      logger.writeToFile(string(", "),2,0)                                               
      dec(cnt,@buffer3)
      logger.writeToFile(@buffer3,strsize(@buffer3),0)
      logger.writeToFile(string(13,10), 2, 0)
    
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    
    PUB Measure                                             ' Clock data in for 13 bits.  (First three are zero, next ten are data)
    
      result~                                                ' Clear result
      outa[nCS]~                                             ' nCS = low
    
      repeat 13                                             ' repeat 13 times
        outa[SCLK]~                                         ' clk low
        outa[SCLK]~~                                        ' clk high
        ADC := result := result << 1 | ina[DOUT]            ' Save value in ADC variable
    
      outa[nCS]~~                                            ' cCS = high
          
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    
    PUB dec(value, address) | i
    
      if value < 0
        -value
        byte[address++] := "-"
    
      i := 1_000_000_000
    
      repeat 10
        if value => i
          byte[address++] := value / i + "0"
          value //= i
          result~~
        elseif result or i == 1
          byte[address++] := "0"
        i /= 10
      byte[address]~  ' mark end of string
      return address
    
    

    But this is where it goes bad.

    Data saved looks like this:

    0, -876833898
    0, -862191530
    0, -847551098
    8191, -832909450
    8191, -817573610
    0, -802933178
    0, -788292554
    0, -773128138





    Thanks again!

    -Steven
  • Mike GreenMike Green Posts: 23,101
    edited 2011-03-01 22:31
    8191 is not a valid output for the LISY300. The highest number you should get is 1023. Did you make nCS and SCLK both outputs? Did you initialize nCS and SCLK both to high?
  • -GRIMM--GRIMM- Posts: 56
    edited 2011-03-02 10:48
    CON 
    
      DOUT   = 16                      
      SCLK   = 18
      nCS    = 17
    
    


    There is the problem. Forgot to add:

    dira[SCLK..nCS]~~

    to the code!

    thank you again! Looks like everything is in business now. Time for field testing!

    Thanks

    -Steven
Sign In or Register to comment.