Shop OBEX P1 Docs P2 Docs Learn Events
handling ADC MCP3208 with Propeller — Parallax Forums

handling ADC MCP3208 with Propeller

gio_romegio_rome Posts: 48
edited 2014-01-30 16:29 in Propeller 1
Hello,

I'm using the MCP3208_fast library and so far I've managed to measure the RMS Voltage with channel 0 of the ADC (read max & min over a 5 cicle period, use experimental constants to tranform the value into an effective RMS value verifiable w/ that one of a voltmeter). I'm now trying to make the machine measure currents (...).

Anyway I've found two methods to initialize the ADC.

adc.start(na,nb,nc,%1111_1111)
or
adc.start(na,nb,nc,%1111_1111)

The first three numbers are the pins, but the last parameter, according to http://www.gadgetgangster.com/tutorials/382
actually "turns on channel". %1111_1111 evidently turns on all 8 channels.

BUT

MCP3208_fast documentation says
last parameter "not used, included for compatability with older program "
AND
in another version of the code I'm rewriting (of the old one I'm not responsible) this is the way it is initialized, i.e. with the last parameter=0.

Then which one is true/what's the exact way of initializing the ADC?

Why all this? Because I need certainties :-) I'm so unsure of the tracks and pins that I want there to be solid ground on which to build a new paradigm.

Tnx all!

Giovanni

Comments

  • pmrobertpmrobert Posts: 675
    edited 2014-01-27 05:48
    Get yourself a copy of the datasheet for the device - http://ww1.microchip.com/downloads/en/DeviceDoc/21298e.pdf - , carefully read Sections 5 & 6 and correlate the library code and comments with the datasheet. I, too, had been unhappy with the fact that I could use the libraries but didn't totally comprehend the "how & why" of the transmitted bit stream. It all became clear after sitting down with the library code, the datasheet and experimenting with the config bits.

    -Mike
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-01-27 09:38
    I tried writing my own MCP3208 driver once but I had so much trouble with it I went back to using the "fast" version from the OBEX.

    The MCP3208 will only return a reading on a single channel at a time. Any of the 8 channels can be read from "In" or "Average" methods. You don't need to set the number of channels with start.

    The MCP3208 has trouble reading quickly from high impedance sources. I've had some trouble getting good readings from 10K pots used as a voltage divider.
  • r.daneelr.daneel Posts: 96
    edited 2014-01-27 10:49
    gio_rome wrote: »
    Then which one is true/what's the exact way of initializing the ADC?Giovanni

    I don't think the mode parameter in Chip's original code was used to initialize the ADC - the mode parameter indicated which channels to read. There is no initialization really - each command to the ADC is self-contained (see the Serial Communication section of the datasheet). As far as I can tell the start function in the fast code just sets up the pin assignments, then each channel is read using the in function. I wrote my own code in assembler which works just fine, but you have to get the timing right (read the datasheet).

    As Duane said, the 3208 samples each channel separately, so you need a separate command to the chip to read each channel.

    Does anybody know of a relatively inexpensive 4 or 8 channel ADC in DIP form (I can't see SMDs let alone solder them) that samples simultaneously? I want to sample 4 channels simultaneously, and my solution at the moment is to use 4xMCP3201s and tie their CS and CLK pins together - that way I get almost simultaneous sampling, but I'd prefer a single chip (one that I can see...).
  • JonnyMacJonnyMac Posts: 9,107
    edited 2014-01-27 11:52
    If you're using PASM, will the very slight channel-to-channel delay of the MCP3208 be an issue? I would suggest you write a custom object. I wrote an MCP3208 driver in PASM for a friend's project that continuously samples and averages the inputs, writing these to the hub. The mainline code reads these values as needed.

    PASM is very friendly, and there are times when an off-the-shelf object/library is just not enough.
  • r.daneelr.daneel Posts: 96
    edited 2014-01-27 12:02
    I am using PASM. My understanding from reading the 3208 datasheet is that the sample/hold capacitor is charged a few clock cycles after the 3208 receives the start bit (I think after the channel bits are received, so it know which channel to sample). Since each read for each subsequent channel requires a new instruction, and so a new start bit, that suggests to me that the sample for each new channel will be a new sample from the pin at the time of (or just after) the start bit. Sure, in PASM the loop can be fast, but we're still talking about a measurable delay. I'm trying to locate sound using TDOA and I think the delay might be an issue - though that's just an untested assumption. The caveat here too is that I'm a software person and I'm really just guessing at the functionality of the 3208. I figured if there was a multi-channel ADC out there that did simultaneous sampling that was cheap enough that'd solve my problem. If I can do it with the 3208 and a smarter algorithm I'd be delighted.
  • JonnyMacJonnyMac Posts: 9,107
    edited 2014-01-27 12:13
    Perhaps a simple sample/hold circuit could added. I've not used a lot of ADCs, but I don't remember any that would simultaneously sample all channels.

    [Edit] Proving once again that search engines are our friends, I found this:
    -- http://www.analog.com/en/analog-to-digital-converters/ad-converters/ad7606/products/product.html

    So, these beasts exist -- now it's down to finding one that works for your project and writing some code for it.
  • r.daneelr.daneel Posts: 96
    edited 2014-01-27 12:27
    The problem is finding one one in DIP format - they all seem to be 64-pin SMD things - I can't solder them (I've tried...). And they seem to be $30-40 each, which is a bit much to buy just as a test (although I guess it's not that much more than 8xMCP3201s).

    I'll keep looking.
  • kwinnkwinn Posts: 8,697
    edited 2014-01-27 16:31
    Take a look at this one from Linear. It's QFN 32 and only six channels so you might need two but it's cheaper than 8 MCp 3201's.

    http://www.digikey.com/product-detail/en/LTC1408IUH-12%23PBF/LTC1408IUH-12%23PBF-ND/1468456
  • MJHanaganMJHanagan Posts: 189
    edited 2014-01-29 16:17
    r.daneel wrote: »
    I don't think the mode parameter in Chip's original code was used to initialize the ADC - the mode parameter indicated which channels to read. There is no initialization really - each command to the ADC is self-contained (see the Serial Communication section of the datasheet). As far as I can tell the start function in the fast code just sets up the pin assignments, then each channel is read using the in function. I wrote my own code in assembler which works just fine, but you have to get the timing right (read the datasheet).

    As Duane said, the 3208 samples each channel separately, so you need a separate command to the chip to read each channel.

    Does anybody know of a relatively inexpensive 4 or 8 channel ADC in DIP form (I can't see SMDs let alone solder them) that samples simultaneously? I want to sample 4 channels simultaneously, and my solution at the moment is to use 4xMCP3201s and tie their CS and CLK pins together - that way I get almost simultaneous sampling, but I'd prefer a single chip (one that I can see...).

    The MCP320x chips are capable of measuring up to 100,000 Hz, so if you measure all 8 channels the effective rate is 12,500 Hz per channel. If you are writing the code in PASM you could also track the CNT value at the beginning of each measurement and therefore know the exact time offset between measurements and do a software correction.

    What is the delay/delta time that begins to cause problems?
  • MJHanaganMJHanagan Posts: 189
    edited 2014-01-29 19:35
    Sanity check: assuming this is an acoustic locating application the important parameter to keep in mind is the speed of sound which is about 340 m/sec. If you are measuring 4 channels on the MCP3204 then one should be able to easily achieve an effective measurement frequency of 20,000 Hz (on each channel). The time delay between channel n and channel n+1 would be as short as 10-11 µs which makes the measurement uncertainty on the order of 4 mm. The time delay between two measurements of the same channel at 20,000 Hz would be about 17 mm. PASM is pretty deterministic so the exact timing should be known and therefore software corrections could significantly reduce these errors further. By the way, what is the response time of your input detectors? Can they react quickly enough?

    A few more important details on the MCP320x ADCs if you are working at fast measurement rates:

    Sampling of the selected channel begins with on the rising edge of the 5th clock signal after the CS is set low (just after sending the last bit of the input channel number). Sampling continues until the falling edge of the 6th clock tick. The charging capacitor in the MCP320x chip is 20 pF with a nominal 1000 ohm resistor in series. Pay particular attention to the charging time required as described in the datasheet (specifically Figures 4-1 and 4-2). Be sure you are not current limiting the ability of the sampling capacitor to achieve a full charge if your clocking speed is maxed out (that leaves you with only 750 ns to fully charge the 20 pF sampling capacitor). I ran into this charging problem trying to sample the voltage downstream from a 20 kohm resistor.

    If you are writing your SPI communication code in PASM then you need to heed the clock speed requirements - i.e. the clock signal must remain high for 250 ns and low for 250 ns so the chip has time to properly respond (maximum clock speed is 2 MHz). Pay particular attention to the Timing Parameters outlined in the specification table on page 3 of the datasheet. Failure to adhere to these parameters might lead to inaccurate measurements.

    There is also a minimum clock speed of about 10,000 Hz which is described in Section 6.2 of the datasheet (any slower than this and the sampling capacitor leaks charge which then results in a low voltage measurement error).
  • edited 2014-01-29 20:28
    Could you use two or more separate ADCs and clock them from the same line? I'm doing that with two ADC0831s. The clock lines for each ADC are wired to the same pin. Same for the chip selects. The data lines are attached to separate pins. That way the data from the two separate chips gets clocked in simultaneously.

    Not sure how many chips you could parallel like that but I bet it's way more than two.

    Sandy
  • Beau SchwabeBeau Schwabe Posts: 6,566
    edited 2014-01-29 20:51
    Alexander (Sandy) Hapgood,

    Yes, the 3202,3204, and 3208's will let you do that. I did that very thing to read a resolver SIN/COS on a CNC machine using an MCP3204.

    gio_rome,

    I could probably find that code if you are interested. As I recall, programming for the MCP3204 and the 3208 is the same, the MCP3202 is a little different.
  • r.daneelr.daneel Posts: 96
    edited 2014-01-30 04:20
    Could you use two or more separate ADCs and clock them from the same line? I'm doing that with two ADC0831s. The clock lines for each ADC are wired to the same pin. Same for the chip selects. The data lines are attached to separate pins. That way the data from the two separate chips gets clocked in simultaneously.

    Not sure how many chips you could parallel like that but I bet it's way more than two.

    Sandy

    That's precisely what I'm doing, but I'm using 4 x MCP3201s. The coding is a little different because there's no command sent to the chip (no channel or mode select - they are a single differential channel), but it's basically the same as all the 320x ADCs. As long as I can pick the peak on each ADC I can calculate the time difference. It would just be easier (I think) and use fewer pins if I had an ADC that samples 4 (or more) inputs simultaneously. I know kwinn pointed one out (thanks), but I can hardly see those tiny QFN things, much less solder them.

    MJHanagan: All good advice, and I actually started down that track (using 4 channels on a 3208). My code is PASM and you are absolutely right that timing is really important. In the end though it was just cleaner code to use an extra few pins and 4 x 3201s (which I just happened to have around). This is just a proof of concept at the moment - if I get it working then I may see if I can find a DIP multi-channel simultaneous sample ADC (or find someone to solder the QFN version for me...).
  • frank freedmanfrank freedman Posts: 1,983
    edited 2014-01-30 11:00
    Depending on the sample rate you are trying to achieve, you may end up with one cog per 3201 ADC. If you try to use one cog for all, you could end up with a greater skew between samples as your sample rate gets higher just as with 320x multiple channels, just a bit less overhead as no set up bits needed as mentioned above. The MCP320x does not incorporate a sample and hold function either though I seem to remember seeing a TI or Analog Devices with that capability.

    I do have an object in OBEX that was done for the purpose of multiple parallel cogs/ADCs (and learning PASM) using one master control cog, one timing generator cog, and up to 6 ADC cogs/ADCs... have not had time to refine it for a while, but it should be able to also run additional prop chips with at least 7 cogs each paralleled and controlled by the first one. If only for more time to play and less for work.....

    Frank

    r.daneel wrote: »
    That's precisely what I'm doing, but I'm using 4 x MCP3201s. The coding is a little different because there's no command sent to the chip (no channel or mode select - they are a single differential channel), but it's basically the same as all the 320x ADCs. As long as I can pick the peak on each ADC I can calculate the time difference. It would just be easier (I think) and use fewer pins if I had an ADC that samples 4 (or more) inputs simultaneously. I know kwinn pointed one out (thanks), but I can hardly see those tiny QFN things, much less solder them.

    MJHanagan: All good advice, and I actually started down that track (using 4 channels on a 3208). My code is PASM and you are absolutely right that timing is really important. In the end though it was just cleaner code to use an extra few pins and 4 x 3201s (which I just happened to have around). This is just a proof of concept at the moment - if I get it working then I may see if I can find a DIP multi-channel simultaneous sample ADC (or find someone to solder the QFN version for me...).
  • r.daneelr.daneel Posts: 96
    edited 2014-01-30 14:00
    The MCP3201 datasheet states:

    "The MCP3201 A/D Converter employs a conventional SAR architecture. With this architecture, a sample is acquired on an internal sample/hold capacitor for 1.5 clock cycles starting on the first rising edge of the serial clock after CS has been pulled low. Following this sample time, the input switch of the converter opens and the device uses the collected charge on the internal sample and hold capacitor to produce a serial 12-bit digital output code."

    So my theory is that if I tie the CS and CLK pins of 4x3201s together they'll all acquire a sample at the same time because they're all clocked from the same source. All I need to do is make sure I get the bits out of all four ADCs before the charge dissipates - or am I being too simplistic?

    Here's a snippet from my code:
    sample                  org
    
                            mov     dira, #0                     ' ensure all pins are input pins initially
    
                            andn    outa, adCLKMask              ' preset AD CLK pin low - clock idles low
                            or      outa, adCSMask               ' preset AD CS pin high - not selected
    
                            or      dira, adCLKMask              ' make AD CLK pin output
                            or      dira, adCSMask               ' make AD CS pin output
    
                            ' start sampling - timing here is for MCP3201 ADC
                            
    :sampleLoop             ' start new sample
     
                            mov     bits, #13                    ' get 13 bits from AD converter - 1 null bit followed by 12 data bits
    
                            ' initiate conversation with ADC
                            
                            andn    outa, adCSMask               ' ADC CS pin low - ADC CLK should be low here
                            long 0,0,0                           ' Tsucs: 150ns (Tsucs minimum is 100ns)
                            or      outa, adCLKMask              ' ADC CLK pin high - start conversation with ADC
                            long 0,0,0,0,0,0,0,0                 ' Thi: 400ns (Thi minimum is 312ns)
                            andn    outa, adCLKMask              ' ADC CLK pin low - ADC starts analog sample here
                            long 0,0,0,0,0,0,0,0                 ' Tlo: 400ns (Tlo minimum is 312ns) 
                            or      outa, adCLKMask              ' ADC CLK pin high
                            long 0,0,0,0,0,0,0,0                 ' Thi: 400ns
    
                            ' ADC analog sample complete - now get digital conversion
                            
    :shiftIn                andn    outa, adCLKMask              ' pull ADC CLK pin low - clock bit out of ADC
                            long 0,0,0,0,0,0,0,0                 ' Tlo: 400ns
                            or      outa, adCLKMask              ' ADC CLK pin high - latch ADC output bit here 
    
                            test    adOUTMask_0, ina        wc   ' test AD Output pin, set C if high
                            rcl     v0, #1                       ' rotate C into value
    
                            test    adOUTMask_1, ina        wc   ' test AD Output pin, set C if high
                            rcl     v1, #1                       ' rotate C into value
    
                            test    adOUTMask_2, ina        wc   ' test AD Output pin, set C if high
                            rcl     v2, #1                       ' rotate C into value
    
                            test    adOUTMask_3, ina        wc   ' test AD Output pin, set C if high
                            rcl     v3, #1                       ' rotate C into value
    
                            ' previous 4 test+rcl instruction pairs account for 400ns = Thi
    
                            djnz    bits, #:shiftIn              ' keep sampling bits until all bits shifted in
    
                            ' sample done - terminate conversation with ADC                                                              
    
                            or      outa, adCSMask               ' ADC CS high - idle state
                            andn    outa, adCLKMask              ' ADC CLK pin low - idle state
    
                            ' Tcsh is 625ns - the following instructions cover it
    
                            and     v0, fff                      ' trim value to 12 bits
                            and     v1, fff                      ' trim value to 12 bits
                            and     v2, fff                      ' trim value to 12 bits
                            and     v3, fff                      ' trim value to 12 bits
     
                            ' << peak detection code here >>
                            
                            jmp     #:sampleLoop                 ' sample again
    

    Without the peak detection code I should get a sample rate of somewhere bewteen 65 and 70k samples per second. I could probably tweak it a bit and get closer to 312ns for the clock transitions instead of 400ns. The peak detection code (which I've left out for brevity) isn't that many instructions, so should reduce the sample rate to no less than 50k samples per second.

    Anything I'm missing?

    I should add that this code seems to work - I get numbers that look right and look consistent. I've put a scope on one of the mics I'm using, and the number I get out of the 3201 for that mic looks right. If my theory about the sample time for all four ADCs being the same is right then I think I'm good. I think.
  • r.daneelr.daneel Posts: 96
    edited 2014-01-30 14:27
    MJHanagan wrote: »
    The time delay between channel n and channel n+1 would be as short as 10-11 µs which makes the measurement uncertainty on the order of 4 mm.

    That's a very good point - I just re-read your post and that jumped out at me. So maybe a 3204 (or 3208 if I go with more than 4 mics) is actually viable. Thanks.
  • frank freedmanfrank freedman Posts: 1,983
    edited 2014-01-30 15:56
    Not sure what your tolerances for the time difference would be in your application since the mcp320x has only one internal sample line; That said, you have caused me to wander down another odd path. And discover another shiny object. very shiny.

    Consider most my parallel ADC object. Like probably (nearly) all of the others, it clocks one bit in at a time, shifts the bit and goes back for more. Now, What if I wanted to get the input from say 24 MCP3201s but rather than with multiple cogs as my object does, I have just now thought of a way to do the same thing with only one cog. Rather than using multiple cogs to acquire one value, let us say we need more than 6 single channels and use a minimal number of cogs. Clock the ADCs as before, one pin per ADC input. So far no changes. Now, lets set up a stack of 12 registers in cog memory space (yep, no free lunch here either, the trade off for this trick is to eat 12 registers of space plus some additional code). read the input of the acquisition cog and mask for the ADC data. Your code should be smart enough to ignore the first three clock times after CS. After the prep pulses are passed, then start taking the masked data bits and store them into the first register for bit2^12 and repeat until all 12 bits are clocked in. You would be left with an array of bits with the words turned sideways so to speak. The final part of the trick would be to rotate this array so that the ADC values are each in a data word of their own. Have not quite figured out how to do that fast yet. Have to think of. a way to that efficiently with out loosing to much sample speed. My parallel ADC object uses one cog per ADC channel. max six channels on the first prop chip; but no real delays. This method would go many ADC channels into one cog, but an amount of delay would be introduced to reformat the input data into individual channel data.......

    Oh , for only a couple more hours a day.......
  • r.daneelr.daneel Posts: 96
    edited 2014-01-30 16:22
    Not sure what your tolerances for the time difference would be in your application since the mcp320x has only one internal sample line

    I only need one internal sample line if I'm using 4x3201s. If I use a 3204 (or 3208) then, as MJHanagan pointed out, the time difference is very small. I'm using TDOA to locate direction to the sound, and my microphones are 160mm apart. The time difference between microphones is then about 400-500µs, so a delay of 10-11µs isn't so bad.
  • MJHanaganMJHanagan Posts: 189
    edited 2014-01-30 16:29
    Not sure what your tolerances for the time difference would be in your application since the mcp320x has only one internal sample line; That said, you have caused me to wander down another odd path. And discover another shiny object. very shiny.

    Consider most my parallel ADC object. Like probably (nearly) all of the others, it clocks one bit in at a time, shifts the bit and goes back for more. Now, What if I wanted to get the input from say 24 MCP3201s but rather than with multiple cogs as my object does, I have just now thought of a way to do the same thing with only one cog. Rather than using multiple cogs to acquire one value, let us say we need more than 6 single channels and use a minimal number of cogs. Clock the ADCs as before, one pin per ADC input. So far no changes. Now, lets set up a stack of 12 registers in cog memory space (yep, no free lunch here either, the trade off for this trick is to eat 12 registers of space plus some additional code). read the input of the acquisition cog and mask for the ADC data. Your code should be smart enough to ignore the first three clock times after CS. After the prep pulses are passed, then start taking the masked data bits and store them into the first register for bit2^12 and repeat until all 12 bits are clocked in. You would be left with an array of bits with the words turned sideways so to speak. The final part of the trick would be to rotate this array so that the ADC values are each in a data word of their own. Have not quite figured out how to do that fast yet. Have to think of. a way to that efficiently with out loosing to much sample speed. My parallel ADC object uses one cog per ADC channel. max six channels on the first prop chip; but no real delays. This method would go many ADC channels into one cog, but an amount of delay would be introduced to reformat the input data into individual channel data.......

    Oh , for only a couple more hours a day.......

    Usually in a situation like this you need to collect the data quickly then have lots of time to do the analysis once all the data is accounted for. If that is the case here then you could simply read all 8 data bits and save them as a single byte in an array in main RAM (a single byte write costs no more than 23 clock ticks, or about 1.15 µs at 80 MHz). Once the data has been collected each byte could be deconstructed and put in separate arrays for each channel.

    If you had two cogs you could have the second cog watch the common clock pin and read the all the output pins and parse the bits into the 4/8 results and after the 12th bit transfer the data up to main RAM in word sized arrays. Four WRWORD commands will no doubt cost you the good part of 4x23 clock cycles so about 4.6 µs. That leaves you with a similar amount of time to parse the measured bits before the next measurement is ready and time to read the new inputs. If you were doing all 8 channels then the WRWORD would consume 9.2 µs leaving very time to do the parsing. In that case you might need to slow the data collection speed down to something like 80,000 Hz (with the speed of sound at 340 m/s that makes the uncertainty in the distance measurement roughly 1 mm).
Sign In or Register to comment.