Shop OBEX P1 Docs P2 Docs Learn Events
First SX Project! - ADC TO PC — Parallax Forums

First SX Project! - ADC TO PC

skynuggetskynugget Posts: 172
edited 2009-04-14 13:00 in General Discussion
A friend of mine needed a cheap device for datalogging sensors in a SharePoint database project. I've been sitting on a couple SX28's for a while, and this was a good project to get me acquainted with SX 2.0. When i jumped into the SX , after years of BS2 I was a bit overwhelmed, but with some help from ya'll at this forum, I was able to wrap my head around it all.


Special Thank to JonnyMac for helping with the Max1270, and Jon Williams for writing all the Serial Comm Routines.

Heres my SX2.0 code, if you can make it better please share with the rest of the class!
' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------

'     Reads the all channels from a MAX1270 ADC, then spits out a string to a 
'    PC via a MAX232 Driver.  
'    ie: *,CH1, CH2, CH3, CH4, CH4, CH5, CH6, CH7, CH8, <repeat>

' -------------------------------------------------------------------------
' Conditional Compilation Symbols
' -------------------------------------------------------------------------


' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

ID              "1270SPIT"

DEVICE          SX28, OSCxt2, TURBO, STACKX, OPTIONX, BOR42
FREQ            4_000_000
IRC_CAL            IRC_4MHZ


' -------------------------------------------------------------------------
' I/O Pins
' -------------------------------------------------------------------------

SClock        PIN     RA.0 OUTPUT                      ' shift clock
SIn            PIN     RA.1 INPUT                       ' shiftin data
Sout        PIN     RA.2 OUTPUT                     ' shiftout data
CS1270      PIN     RA.3 OUTPUT                      ' max1270 chip select

PCin        PIN        RB.0 INPUT
PCout        PIN        RB.1 OUTPUT


' -------------------------------------------------------------------------
' Constants
' -------------------------------------------------------------------------
 

' -------------------------------------------------------------------------
' Variables
' -------------------------------------------------------------------------

chan        VAR        Byte
chLevel        VAR        Word

tmpB1        VAR        Byte                            ' work vars
tmpB2        VAR        Byte
tmpB3        VAR        Byte
tmpB4        VAR        Byte
tmpW1        VAR        Word
tmpW2        VAR        Word

nStr        VAR     Byte (5) BANK                   ' for STR and HEXSTR

' -------------------------------------------------------------------------
' Subroutine / Function / Task Declarations
' -------------------------------------------------------------------------

DELAY_MS    SUB        1, 2                            ' shell for PAUSE
    
GET_ADC     FUNC    2, 1                              ' get value from ADC

TX_BYTE     SUB     1                               ' transmit a byte
TX_STR      SUB     2                               ' transmit a string
TX_DEC      SUB     1, 3                            ' tx value in DEC format

' =========================================================================
  PROGRAM Start
' =========================================================================

Start:
      PLP_B = %0000_0000
      PLP_C = %0000_0000

      CS1270 = 1                                        ' deselect ADC

                            
Main:
    tx_str "*, "                                    ' send marker char
    
    FOR chan = 0 TO 7
        chLevel = GET_ADC chan                        ' get adc
    
        tmpW1 = chLevel ** $3880
        chLevel = chLevel + tmpW1                    ' convert to milivolts

        tx_dec chlevel, 5                            ' send milivolts out  
        
        tx_str ", "                                    ' send deliminate char
           
        delay_ms 100                                ' delay makes serial better?

        WATCH chan, 8, udec                            ' use Debug --> Run
        WATCH chLevel, 16, udec
    
        BREAK
        
    NEXT
    
    GOTO Main


' -------------------------------------------------------------------------
' Subroutine / Function / Task Code
' -------------------------------------------------------------------------

' Use: DELAY_MS milliseconds
' -- shell for PAUSE

SUB DELAY_MS
      mSecs        VAR    __WPARAM12

      \ SB    __PARAMCNT.1
      \  CLR  mSecs_MSB

      PAUSE mSecs

ENDSUB

' -------------------------------------------------------------------------
' Use: TX_BYTE aByte

SUB TX_BYTE
  SEROUT PCOUT, T9600, __PARAM1
  ENDSUB

' -------------------------------------------------------------------------
' Use: TX_DEC value {, digits } 
' -- transmits "value" in DEC format
' -- "digits" MUST be specified with word values
' -- DEC3 or DEC5 format is used if "digits" not specified or invalid

SUB TX_DEC
  dValue        VAR     tmpW1
  dDigits       VAR     tmpB1
  dIdx          VAR     tmpB2
  dChar         VAR     __PARAM1

  IF __PARAMCNT = 1 THEN                        ' byte w/o digits
    dValue = __PARAM1
    dDigits = 3
  ELSEIF __PARAMCNT = 2 THEN                    ' byte w/digits
    dValue = __PARAM1
    dDigits = __PARAM2
  ELSE                                          ' word w/digits
    dValue = __WPARAM12
    dDigits = __PARAM3
  ENDIF

  IF dDigits = 0 THEN                           ' validate digits
    dDigits = 5
  ELSEIF dDigits > 5 THEN
    dDigits = 5
  ENDIF

  STR nStr, dValue                              ' to decimal string
  dIdx = 5 - dDigits                            ' point to first char

  DO WHILE dIdx < 5
    TX_BYTE nStr(dIdx)
    INC dIdx
  LOOP
ENDSUB
' -------------------------------------------------------------------------
' Use: TX_STR [noparse][[/noparse]String | Label]
' -- pass embedded string or DATA label

SUB TX_STR
  strAddr    VAR    tmpW1
  sChar        VAR    __PARAM1

  strAddr = __WPARAM12                            ' get offset/base

  DO
    READINC strAddr, sChar                      ' read a character
    IF sChar = 0 THEN EXIT                      ' if 0, string complete
    TX_BYTE sChar                               ' send the byte
  LOOP
ENDSUB
' -------------------------------------------------------------------------
' Use: aVar = GET_ADC
' -- reads MAX1270 and places value into 'aVar'

FUNC GET_ADC
    adcChan    VAR    tmpB1
      adcResult    VAR    tmpW1

      adcChan = __PARAM1                            ' capture channel
      adcChan = adcChan & %0000_0111                ' limit, 0 - 7
      READ Adc_Cfg + adcChan, adcChan                ' convert to config bits

      SClock = 0                                  ' get ready
      CS1270 = 0                                    ' select max1270
  
    SHIFTOUT SOut, SClock, MSBFIRST, adcChan    ' send config/channel     
      
    CS1270 = 1                                    ' done
      NOP
      CS1270 = 0
  
      SHIFTIN Sin, SClock, MSBPRE, adcResult\12    ' get raw adc data    

      CS1270 = 1                                  ' done
  
    RETURN adcResult                            ' store

ENDFUNC


' =========================================================================
' User Data
' =========================================================================
' 0 - +5 , channels 1-8 
Adc_Cfg:       
    DATA    %11110000, %11100000, %11010000, %11000000
    DATA    %10110000, %10100000, %10010000, %10000000 




Thanks Again Forum!

Comments

  • JonnyMacJonnyMac Posts: 9,213
    edited 2009-03-14 15:51
    JonnyMac (Jon McPhalen, www.jonmcphalen.com) is the actor who used to be known as Jon Williams the Applications Engineer at Parallax. Not quite a Superman/Clark Kent kind of thing, but we are in fact the same person! Glad you know that you we're about to get everything working for your friend.

    I've updated your program to 2.00.16 features and improved the TX_DEC routine (I needed it for myself this week).
  • skynuggetskynugget Posts: 172
    edited 2009-03-14 16:15
    ha! mysterious arn't ya? thanks for the update, and for all your NV columns, don't think id be where i am without them.
  • skynuggetskynugget Posts: 172
    edited 2009-03-14 18:12
    hey jon, after about an hour of running, the chip starts spitting out garbage. On reset it spits out a couple good strings then garbage. If i leave it sit for a bit, then reset it spits out good strings again for a good bit. I'm using a PDB, with a Parallax resonator and the built in max232. Do you think its a function of temperature?
  • JonnyMacJonnyMac Posts: 9,213
    edited 2009-03-14 18:29
    That seems very odd and if you can get it to work after shutting down it does seem to be temperature related -- I, too, use the PDB all the time and have not seen that. You may want to check the MAX1270 docs to see if there is any information related to access time.
  • skynuggetskynugget Posts: 172
    edited 2009-03-14 20:54
    welp it seems the culprit is my on board max232! time to get out the tweezers!
  • Mike CookMike Cook Posts: 829
    edited 2009-03-28 12:29

    Slight confusion here.........

    I built this project and I seem to be getting 1/2 the full scale output value when I run with a 20 MHz resonator & at 115200 Baud (ADC channel connected to +5VDC).

    Went back and installed a 4 MHz resonator and running at 9600 Baud and now I'm getting full scale output.

    What am I missing?

    Complied w/2.00.18, 2.00.19, & 2.00.20.·Same results with·ALL versions


    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Mike

    Post Edited (Mike Cook) : 4/11/2009 7:19:51 PM GMT
  • Mike CookMike Cook Posts: 829
    edited 2009-04-11 19:23
    Still at a loss of why I'm getting 1/2 the full scale output value when I run with a 20 MHz resonator & @115200 Baud.

    I'm using Jon's example as-is posted on 3-14-09.

    The problem seems to happen when I compile @ 20Mhz @ ANY baud rate.

    Compiled at 4Mhz, max baud rate of 57600 and I DO get full scale output.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Mike
  • JonnyMacJonnyMac Posts: 9,213
    edited 2009-04-11 19:49
    That's very peculiar, Mike. Have you tried with a 50MHz resonator? I realize this is grasping at straws but I don't understand why it would work at one speed and not another, especially with the SHIFTIN and SHIFTOUT functions running at standard speed.
  • Mike CookMike Cook Posts: 829
    edited 2009-04-11 20:01
    No I have not tried a 50MHz resonator, let me round one up, and try that.

    Sampling an in line resistor (current measurement) at 10mS, and at 4MHz @ 57600 I'm getting 105 samples per second. Good enough for right now but will need to add an interrupt to dial it in to 10 mS samples per second.

    Would like to get the baud rate up to 115200, most of out test equipment operates at this speed. Our programmers give me a funny look when I bring in a piece of “glue hardware” that operates at a different baud rate than that!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Mike
  • Mike CookMike Cook Posts: 829
    edited 2009-04-11 20:39
    Same results using a 50MHz resonator - Getting 1/2 scale output at ANY baud rate.

    Don’t have a resonator, to try, in between 4MHz to 20 MHz.

    Seems, to me, like SHIFTIN is dropping the last bit, over 4MHz, just an "un-educated Guess"!

    Project built on a Parallax PN: 45301 Proto Board.

    Attached the code, Incase I've done something 'Bone Headed'.



    Thanks

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Mike
  • JonnyMacJonnyMac Posts: 9,213
    edited 2009-04-11 21:06
    I use SHIFTIN in 50MHz projects all the time -- have a pan/tilt controller for a camera head sitting near me that uses the ADC0838 and I'm actually doubling the speed to the ADC (to help make-up for the interrupt). I'd be more suspicious of the ADC chip than the SX and SX/B.
  • Mike CookMike Cook Posts: 829
    edited 2009-04-11 21:14
    Tried two different MAX1270ACNG chips. One on a PDB, and the other on the SX28 Proto Board.

    I have two other MAX1270BCNG chips (got to love www.maxim-ic.com's sampling policy!)

    Will try them next to see of there is a difference.

    Thanks for the suggestions!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Mike
  • JonnyMacJonnyMac Posts: 9,213
    edited 2009-04-11 22:31
    Maybe there's some setup time issues with the chip -- you may want to check the timing specs very carefully vis-a-vis setting the clock pin and cs before attempting to read from you. You may need to insert a short delay at faster speeds.
  • Mike CookMike Cook Posts: 829
    edited 2009-04-11 22:43
    Will go through the data sheet.............again.

    Thanks for the help, hopefully I'm missing something simple.· Might port this to a Propeller to see if I get the same results.

    Your example as posted works quite well.

    I just need a faster & timed (10mS) output.

    Thanks Again,

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Mike

    Post Edited (Mike Cook) : 4/12/2009 10:37:04 AM GMT
  • Mike CookMike Cook Posts: 829
    edited 2009-04-14 12:30
    Jon,

    As usual you were correct! tongue.gif

    Probably not the correct way to fix my problem but changed the GET_ADC function from:

    ' -------------------------------------------------------------------------
    ' Use: aVar = GET_ADC
    ' -- reads MAX1270 and places value into 'aVar'
    FUNC GET_ADC
      adcChan       VAR     tmpB1
      adcResult     VAR     tmpW1
      adcChan = __PARAM1                            ' capture channel
      adcChan = adcChan & %0000_0111                ' limit, 0 - 7
      READ Adc_Cfg + adcChan, adcChan               ' convert to config bits
      SClock = 0                                    ' get ready
      CS1270 = 0                                    ' select max1270
      SHIFTOUT SOut, SClock, MSBFIRST, adcChan      ' send config/channel
      CS1270 = 1                                    ' done - de-select max1270
      NOP
      CS1270 = 0                                    ' select max1270
      SHIFTIN Sin, SClock, MSBPRE, adcResult\12     ' get raw adc data
      CS1270 = 1                                    ' done - de-select max1270
      RETURN adcResult                              ' store
      ENDFUNC
    
    

    To:

    ' -------------------------------------------------------------------------
    ' Use: aVar = GET_ADC
    ' -- reads MAX1270 and places value into 'aVar'
    FUNC GET_ADC
      adcChan       VAR     tmpB1
      adcResult     VAR     tmpW1
      adcChan = __PARAM1                            ' capture channel
      adcChan = adcChan & %0000_0111                ' limit, 0 - 7
      READ Adc_Cfg + adcChan, adcChan               ' convert to config bits
      SClock = 0                                    ' get ready
      CS1270 = 0                                    ' select max1270
      SHIFTOUT SOut, SClock, MSBFIRST, adcChan      ' send config/channel
      CS1270 = 1                                    ' done - de-select max1270
    
     
      [b]for idx = 0 to 11                       ' 11 was the smallest delay @ 20MHz
        NOP
      next[/b]
     
      CS1270 = 0                                    ' select max1270
      SHIFTIN Sin, SClock, MSBPRE, adcResult\12     ' get raw adc data
      CS1270 = 1                                    ' done - de-select max1270
      RETURN adcResult                              ' store
      ENDFUNC
    


    Now this works at 20 MHz @ 115200 baud, but I have to 'fiddle' with the delay loop for 50 MHz, to get the same results.

    Next task is to determine how long a NOP is at 20 MHz and put in the proper delay so the function will return the correct value at any MHz other than 4Mhz.

    Thanks for the 'bread crumbs' !

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Mike
  • ZootZoot Posts: 2,227
    edited 2009-04-14 12:45
    Mike, instead of

    for idx = 0 to 11 ' 11 was the smallest delay @ 20MHz
    NOP
    next


    Why not use something like


    PAUSEUS 10 ' may need to play with value


    Which basically does the same thing (a delay loop) but then you can adjust in microseconds and know that you'll get the same delay even if you move the code or use a different FREQ (i.e. the PAUSEUS will work the same even if you change the project to 50mhz or 8mhz, etc)

    P.S. -- NOP always takes 1 cycle -- so at 50mhz it takes 1/50th of a micro second, at 20 mhz, 1/20 of a micro second etc. In your loop, in fact, the instructions that comprise the for/next loop actually take most of the time cycles, not the NOP itself. Again PAUSEUS will give you consistent results (once you decide the correct the delay time) regardless of frequency or device.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    When the going gets weird, the weird turn pro. -- HST

    1uffakind.com/robots/povBitMapBuilder.php
    1uffakind.com/robots/resistorLadder.php


    Post Edited (Zoot) : 4/14/2009 12:51:10 PM GMT
  • Mike CookMike Cook Posts: 829
    edited 2009-04-14 12:51
    Zoot,

    Thanks for the reply!

    Yes that was my idea of determining how long a NOP is at 20MHz, by using PAUSEUS that will save me some reading and math calculations!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Mike
  • Mike CookMike Cook Posts: 829
    edited 2009-04-14 13:00
    Looks like:

    PAUSEUS 6

    was the answer! Now works properly from 4 to 50Mhz.

    Thanks to ALL for the help!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Mike
Sign In or Register to comment.