Shop OBEX P1 Docs P2 Docs Learn Events
Multiple ADCs? — Parallax Forums

Multiple ADCs?

JemartinJemartin Posts: 9
edited 2011-07-12 11:53 in Propeller 1
Hey,

So, i am looking for some help trying to connect multiple adcs to the prop. I have 3 8ch 10bit adcs (i cant remember the exact chip number right now) connected to the prop. I have the CS, CLK, DIN pins from each adc connected together and then to pins on the prop. Each Dout has its own pin on the prop. I hope theres my crude picture of this at the bottom.

I figured this was the best way to connect them, using the fewest number of pins and allowing for the easiest scaling up and down of adcs. I didnt completely think through how the driver was going to work with the adc, though.

Ive been using brandon nimon's ADC_Input_Driver from the obex with one adc and its been working great. It doesnt, however, work with more than one the way I have the pins tied together.

I feel like it wouldnt be that hard to modify a driver like this to work for multiple adcs, it would just have to alternate which dout pin it reads from. The problem i have is that im not all that proficient with the ASM code yet and dont really understand whats goin on in the driver well enough to be able to modify it.

Im wondering if there is a driver for adcs which is written in all spin that i maybe be able to better modify myself, or if maybe someone could get me set down the correct path for modifying an existing driver to do what i need it to do? Or, perhaps Im completely wrong and it wont work this way at all, or im missing something and theres a different, perhaps simpler, way to use a current adc driver to do what i want?

Thank you

adcs.jpg
353 x 346 - 27K

Comments

  • Bobb FwedBobb Fwed Posts: 1,119
    edited 2011-07-11 13:17
    I wrote that driver, and I just recently started doing an identical setup to what you are trying to do.

    I don't think any driver will work with the wiring you show in the diagram.
    In my setup, all 6 data pins (in and out for all three MCP3008s) are tied together to one IO. All three clock pins go to one IO, and each ADC gets a separate IO for the CS pin (so a total of 5 IOs for 3 ADCs)..

    The driver can only run one ADC at a time, and when it does, the other two CS pins need to be held high.

    So here is my code to start the driver on ADC1:
    OUTA[ADC_CS2]~~
      OUTA[ADC_CS3]~~
                      
      DIRA[ADC_CS2]~~
      DIRA[ADC_CS3]~~
      ADC.start(ADC_Data, ADC_Data, ADC_Clk, ADC_CS1, 8, 8, 10, 1)
    


    Modifying the driver would be possible, but difficult, especially since there are only 10 or so free longs in that COG.
  • Bobb FwedBobb Fwed Posts: 1,119
    edited 2011-07-11 13:25
    There is, however, this driver: http://obex.parallax.com/objects/403/ which could be modified to work with the MCP3008 pretty easily. Assuming you don't need any of the fancier features of the ADC Input Driver.
  • JemartinJemartin Posts: 9
    edited 2011-07-11 14:25
    thank you.

    well i figured the driver could control the clk and cs pins together, but only read in a value from the adc that you want the value from. So, the getval would have like to inputs, chip and channel. maybe i just dont understand this problem well enough.

    i guess dont mind having to change around my pins to make this work and i dont really need any of the 'fancier' features, i just want to be able to get all the values from the adc's and dump them onto a sd card.

    Going by your first example, would i have to restart the driver everytime i wanted to read values froma different adc?

    I saw that object in the obex, but im running into the same problem of not understanding ASM well enough to be able to modify it.

    I guess I just need to focus more on learning ASM.
  • Bobb FwedBobb Fwed Posts: 1,119
    edited 2011-07-11 14:50
    Yes, you would have to restart the object every time you switched ADCs (in my driver).

    For that 24-channel object, I'm not sure if the pins can be tied together like I described, but I would think so. The reason they need to be the way I described is that if you have the CS pins tied together, so when you issue a command, you are sending information to all three ADC at the same time, thus you will get information back from them all at the same time. You could design an interesting and very fast driver around that idea, but that is not how any of the drivers are written.
    So, if only one CS is held low, and the others are high, the commands only get send to one ADC, and only received from one. Much less confusing.

    To modify the 24-channel object, I think all you have to do is change line 283 from "mov bits,#14" to "mov bits,#12".
    Just to separate hardware problems from software problems, I would first wire up all ADCs to separate IOs (total 9 IOs). Then try the software, once that is working, rewire it, so you only use 5 IOs.
  • AribaAriba Posts: 2,690
    edited 2011-07-11 20:32
    This is a Spin SPI-ADC code for the MCP3202:
    CON
      _clkmode  = xtal1 + pll16x
      _xinfreq  = 5_000_000
    
      'ADC Pins  <--- set your pins here
      MISO  = 4   'Prop in  - ADC Dout
      MOSI  = 5   'Prop out - ADC Din
      SCLK  = 3   'serial clock
      CSEL  = 6   'chip select
      
    OBJ
      term :  "TV_Text"
          
    PUB Testcode : v
      term.start(12)
      term.str(string("SPI ADC Test",13))
      SpiInit
      repeat
        v := getADC(0)
        term.dec(v)
        term.out(32)
        v := getADC(1)
        term.dec(v)
        term.out(13)
        waitcnt(clkfreq + cnt)
    
    PUB SpiInit
      dira[MOSI] := 1               'set output pins
      dira[SCLK] := 1
      dira[CSEL] := 1
      outa[CSEL] := 1               'CSel high
        
    PUB getADC(channel) : shift     'for MCP3202
      shift := channel<<2 + %11
      outa[CSEL] := 0
      repeat 4                     'write 4 mode bits
        outa[MOSI] := shift
        outa[SCLK] := 1
        shift >>= 1
        outa[SCLK] := 0
      repeat 13                    'read dummy + 12 bits
        outa[SCLK] := 1
        shift := shift<<1 + ina[MISO]
        outa[SCLK] := 0
      outa[CSEL] := 1
    

    If you use 3 MCP3208 then this (untested) getADC methode may work with your current circuit:
    PUB getADCs(channel,DinPin) : shift    'for 3 x MCP3208
      shift := (channel><3) + %11<<3
      outa[CSEL] := 0
      repeat 5                     'write 5 mode bits
        outa[MOSI] := shift
        outa[SCLK] := 1
        shift >>= 1
        outa[SCLK] := 0
      repeat 14                    'read dummy + 12 bits
        outa[SCLK] := 1
        shift := shift<<1 + ina[DinPin]
        outa[SCLK] := 0
      outa[CSEL] := 1
      shift &= $0FFF
    

    Andy
  • JemartinJemartin Posts: 9
    edited 2011-07-12 11:16
    ariba, this looks very like what i was thinking. I think that that code should get me pretty close to where I wanna be for now. thank you very much.
  • Bobb FwedBobb Fwed Posts: 1,119
    edited 2011-07-12 11:53
    Bobb Fwed wrote: »
    Yes, you would have to restart the object every time you switched ADCs (in my driver).
    An alternative (not that you'll probably use it .. but I'm glad I figured out a work around to my previous statement) for restarting cogs....but now you need 3 available cogs.

    This is the exact method I'm going to use on my project because I need the "fancier" stuff.
    CON
    
      STNDBY_WAIT = 5000 ' wait 5000 cycles between standby_disable checks in ADC
    
      ADC_CS1   = 3
      ADC_Data  = 4
      ADC_Clk   = 5
      ADC_CS2   = 6
      ADC_CS3   = 7
    
      {== ADC Channels ==}
      { =ADC1 Inputs= }
      G2_1_R   = (1 << 8) + 0
      G3_1_R   = (1 << 8) + 1
      G4_1_R   = (1 << 8) + 2
      G5_1_R   = (1 << 8) + 3
      G2_2_R   = (1 << 8) + 4
      G3_2_R   = (1 << 8) + 5
      G4_2_R   = (1 << 8) + 6
      G5_2_R   = (1 << 8) + 7
    
      { =ADC2 Inputs= }
      G2_1_V   = (2 << 8) + 0
      G3_1_V   = (2 << 8) + 1
      G4_1_V   = (2 << 8) + 2
      G5_1_V   = (2 << 8) + 3
      G2_2_V   = (2 << 8) + 4
      G3_2_V   = (2 << 8) + 5
      G4_2_V   = (2 << 8) + 6
      G5_2_V   = (2 << 8) + 7
    
      { =ADC3 Inputs= }
      Antenna  = (3 << 8) + 0
      G1_2_R   = (3 << 8) + 1
      G1_1_R   = (3 << 8) + 2
      G1_1_V   = (3 << 8) + 3
      G1_2_V   = (3 << 8) + 4
      IN_V_1   = (3 << 8) + 5
      IN_V_2   = (3 << 8) + 6
      DIGI_V   = (3 << 8) + 7
    
    OBJ
    
      ADC1   : "ADC_INPUT_DRIVER"                           ' for ADC values
      ADC2   : "ADC_INPUT_DRIVER"                           ' for ADC values
      ADC3   : "ADC_INPUT_DRIVER"                           ' for ADC values
    
    PUB Main
    
      ' Start each ADC, then put it into standby
      ADC1.start(ADC_Data, ADC_Data, ADC_Clk, ADC_CS1, 8, 8, 10, 1)
      ADC1.standby_enable(STNDBY_WAIT)
      ADC2.start(ADC_Data, ADC_Data, ADC_Clk, ADC_CS2, 8, 8, 10, 1)
      ADC2.standby_enable(STNDBY_WAIT)
      ADC3.start(ADC_Data, ADC_Data, ADC_Clk, ADC_CS3, 8, 8, 10, 1)
      ADC3.standby_enable(STNDBY_WAIT)
    
      REPEAT            ' just use the modifed chanels to get the info
        get_val(G2_1_R)
        get_val(G5_1_V)
        get_val(IN_V_1)
    
    PUB get_val (chan) : val | adc
    
      adc := chan >> 8
      chan &= $F
    
      CASE adc
        1:
          ADC1.standby_disable
          val := ADC1.getval(chan)
          ADC1.standby_enable(STNDBY_WAIT)
        2:
          ADC2.standby_disable
          val := ADC2.getval(chan)
          ADC2.standby_enable(STNDBY_WAIT)
        3:
          ADC3.standby_disable
          val := ADC3.getval(chan)
          ADC3.standby_enable(STNDBY_WAIT)
    
Sign In or Register to comment.