Shop OBEX P1 Docs P2 Docs Learn Events
SPI & MCP3208 in C — Parallax Forums

SPI & MCP3208 in C

amossamamossam Posts: 35
edited 2014-09-23 03:29 in Propeller 1
Me again... :smile: and in advance, my apologies if I'm asking stupid question!

i have MCP3208, and following GadgetGangster tutorial, i'm able to read values using SPIN and MCP3208 object.

Since I don't know SPIN, or PASM, I'm trying to do SPI communication in C/C++.
With _no_ success! :blank:

How I understand MCP3208 specs pdf, this is how communication should work:

CS OUT and HIGH
DIN_DOUT out and HIGH
CLK OUT and HIGH

and now setup (send 1 0 0 0 - single ended CH0):

DIN_DOUT high AND CLK low
pause for 50 micro seconds (with usleep(50))

DIN_DOUT low AND CLK high
pause for 50 micro seconds

DIN_DOUT low AND CLK low
pause for 50 micro seconds

DIN_DOUT low AND CLK high
pause for 50 micro seconds

this should be end of setup, and after CLK low - pause - CLK high, now goes reading:

repeat 12 times (for 12 bits result)
CLK not CLK
read from DIN_DOUT (i'm reading pin state with "(INA & mask) ? 1 : 0" and tried "(INA & mask) != 0" it that correct?? )
pause for 50 micro seconds

But, all I'm getting from DIN_DOUT is 0!
What am I doing wrong?
Code example for this would be awesome! :cool: becasue I can find any code regarding SPI communication in plain C/C++...

thx for any assistance!
«1

Comments

  • jazzedjazzed Posts: 11,803
    edited 2012-08-16 23:49
    I don't have a code example for this. So many things happening at once around here ....

    I'm pretty sure you need to set SPI_CS low for the device through most of your sequence. The times it should go high is at the beginning before you send the start, single/diff mode, and D2,1,0 bits. SPI_CS should be low before the start bit as well as at the end of the transaction. Page 20 of the .pdf specification has a great picture showing the signals.

    Show your code if you can. That's been the best way to get a little help around here for years. Use the code markup if possible to make a box.

    Hope this helps.
    --Steve
  • amossamamossam Posts: 35
    edited 2012-08-17 00:06
    -- deleted, double post...
  • amossamamossam Posts: 35
    edited 2012-08-17 00:14
    jazzed wrote: »
    I don't have a code example for this. So many things happening at once around here ....

    I'm pretty sure you need to set SPI_CS low for the device through most of your sequence. The times it should go high is at the beginning before you send the start, single/diff mode, and D2,1,0 bits. SPI_CS should be low before the start bit as well as at the end of the transaction. Page 20 of the .pdf specification has a great picture showing the signals.

    Show your code if you can. That's been the best way to get a little help around here for years. Use the code markup if possible to make a box.

    Hope this helps.
    --Steve

    hey!

    you are correct about SPI_CS. i put it HIGH and then LOW and then start sending data.

    I didn't posted any code, because it was too crude, i tried to use (translate) arduino code, but no help...
    Here is current version, that still doesn't work! :blank:

    helper functions
    int Pin::get()
    {
        DIRA &= ~m_mask;
        //return (INA & m_mask) != 0;
        return (INA & m_mask) ? 1 : 0;
    
    }
    
    void Pin::high()
    {
        OUTA |= m_mask;
        DIRA |= m_mask;
    }
    
    void Pin::low()
    {
        OUTA &= ~m_mask;
        DIRA |= m_mask;
    }
    
    inline void Pin::input()
    {
        DIRA &= ~m_mask;
    }
    
    inline void Pin::output()
    {
        DIRA |= m_mask;
    }
    
    

    main code:
    char ReadADC(int channel)
    {
       int i;
       int AdcResult;  
     
       CS.low();      // Active chip select
       usleep(1);    // Delay about 1 uS
       CLK.low();     // make clock low first
       usleep(2);
       channel = channel? 0xE0 : 0xC0;
       usleep(2);
       //--- write command 3 bit ----------
       DINOUT.output();
       for(i=0; i< 3;i++) {
          DINOUT.set((channel & 0x80) != 0);
          channel<<=1;
          CLK.high();
          usleep(2);        // delay about 2 uS
          CLK.low();
          usleep(2);        // delay about 2 uS
       }
    
       //--- read ADC result 12 bit --------
       DINOUT.input();
       AdcResult=0;
       for(i=0;i<12;i++) {
          CLK.high();
          usleep(2);        // delay about 2 uS
          CLK.low();
          usleep(2);        // delay about 2 uS
          AdcResult<<=1;
          AdcResult=AdcResult | (DINOUT.get() & 0x01);
          printf("%i\n", (DINOUT.get() & 0x01));
          CLK.high();
          usleep(2);        // delay about 2 uS
          CLK.low();
          usleep(2);        // delay about 2 uS
       }
       CS.high();
    }
    
    int main (int argc, char* argv[])
    {
        sleep(5);
        printf("Ch 0 : %i\n\r",ReadADC(0));
    
        return 0;
    }
    

    thx
  • jazzedjazzed Posts: 11,803
    edited 2012-08-17 00:26
    I meant CS should "go low", that is, start high then go low - your code only shows CS low (but It may be high already). I assume you've set the direction bits for you pins?

    Also don't you need 6 clocks before data starts coming? I see only 3. (JL below represents clock going high then low).
    CSHI, CSLO, START JL, SINGLE JL, D2 JL, D1 JL, D0 JL, EXTRA JL, RXNULL JL, RXBIT11 JL, RXBIT10 JL, ... RXBIT0 JL, CSHI

    amossam wrote: »
    Hey

    You are correct about CS, it should be low. I put it high, then low, and then start sending data.
    I didn't posted any code, because it was too crude! :blank:

    Folks around here don't mind crude code.
  • amossamamossam Posts: 35
    edited 2012-08-17 00:42
    jazzed wrote: »
    I meant CS should "go low", that is, start high then go low - your code only shows CS low (but It may be high already). I assume you've set the direction bits for you pins?

    Also don't you need 6 clocks before data starts coming? I see only 3. (JL below represents clock going high then low).
    CSHI, CSLO, START JL, SINGLE JL, D2 JL, D1 JL, D0 JL, EXTRA JL, RXNULL JL, RXBIT11 JL, RXBIT10 JL, ... RXBIT0 JL, CSHI

    Ok, will try when I get home, currently on work, and will report back...
    jazzed wrote: »
    Folks around here don't mind crude code.
    Goot to know that! :cool:

    P.S. it there, somewhere, minimal propeller usb stick? i mean, just FTDI and Propeller chip, maybe 2-3 LEDs, USB connector and that's it! No pins, not anything! So, something small size, that can be plugged into USB like small data stick and stay there? So that when you are not at home, and have time, continue working on propeller, and it doesn't take too much space!
  • photomankcphotomankc Posts: 943
    edited 2012-08-17 06:38
    amossam wrote: »
    P.S. it there, somewhere, minimal propeller usb stick? i mean, just FTDI and Propeller chip, maybe 2-3 LEDs, USB connector and that's it! No pins, not anything! So, something small size, that can be plugged into USB like small data stick and stay there? So that when you are not at home, and have time, continue working on propeller, and it doesn't take too much space!

    I know I saw someone that made such a thing or darn close to it. Closest I have used to that is a Quickstart. It's nice because it has touch buttons and 8 LEDs for easy feedback. Not sure if you already have that. Very easy to play with to as it powers from USB, but it sure is not a 'stick'.
  • amossamamossam Posts: 35
    edited 2012-08-17 07:00
    photomankc wrote: »
    I know I saw someone that made such a thing or darn close to it. Closest I have used to that is a Quickstart. It's nice because it has touch buttons and 8 LEDs for easy feedback. Not sure if you already have that. Very easy to play with to as it powers from USB, but it sure is not a 'stick'.

    Yea, I have QuickStart, and it is small, but it's not easy portable! :-D
    Maybe create some casing from plexy, but it's still too bulky to carry around! :cool:
    Well, I'll probably have to just wait for winter, and little more free time, and see what can be done about that....

    edit: Something like PropStick, but dualsided (so it could be shorter), without pin headers and with USB connector for direct plugging to pc!
  • Dave HeinDave Hein Posts: 6,347
    edited 2012-08-17 07:47
    You can use spinsim to test out code that doesn't need I/O. It does support serial I/O to the console through P31/P30. I believe it is distributed with PropGCC, or you can download it from the spinsim thread.
  • amossamamossam Posts: 35
    edited 2012-08-17 09:04
    ok, it seems that i succeed! :cool:
    int ReadADC(int channel)
    {
       int i;
       int AdcResult;
       int setup;
    
       DINOUT.output();
       CS.low();      // Active chip select
       usleep(2);    // Delay about 1 uS
    
       CLK.high();
       usleep(2);
       CLK.low();     // make clock low first
       DINOUT.high();
       usleep(2);
       DINOUT.low();
    
       CLK.high();
       usleep(2);
       CLK.low();     // make clock low first
    //   usleep(2);
    
       //--- write command 3 bit ----------
       setup = 0x80; // : 0xC0; // 1000000  ??
       for(i=0; i< 3;i++) { //i < 3 or i < 4
          DINOUT.set((setup & 0x80) != 0); // is MSB != 0
          setup<<=1;  // shift left
          usleep(2);        // delay about 2 uS
          CLK.high();
          usleep(2);        // delay about 2 uS
          CLK.low();
       }
    
       //Sample time?
       CLK.high();
       usleep(2);        // delay about 2 uS
       CLK.low();
       usleep(2);        // delay about 2 uS
    
       CLK.high();
       usleep(2);        // delay about 2 uS
       CLK.low();
       usleep(2);        // delay about 2 uS
    
       CLK.high();
       usleep(2);        // delay about 2 uS
       CLK.low();
       usleep(2);        // delay about 2 uS
    
       //--- read ADC result 12 bit --------
       DINOUT.input();
       AdcResult=0;
       int k;
       for(i=0;i<12;i++) {
          CLK.high();
          usleep(2);        // delay about 2 uS
          CLK.low();
          usleep(2);        // delay about 2 uS
          AdcResult<<=1;
          k = DINOUT.get() & 0x01;
          AdcResult=AdcResult | k;
          CLK.high();
          usleep(2);        // delay about 2 uS
          CLK.low();
          usleep(2);        // delay about 2 uS
       }
       CS.high();
       return(AdcResult);
    }
    
    int main (int argc, char* argv[])
    {
        sleep(5);
        CS.high();
        DINOUT.output();
    
        while (1)
        {
            int i, k;
            k = 0;
            for (i=1;i<500;i++)
                k = k + ReadADC(0);
            k = k/500;
            printf("Ch 0 : %i\n", k);
            sleep(1);
        }
        return 0;
    }
    
    

    But, values i got back are almost the same like in tutorial mentioned before, but my results oscillates much more!! i got around 2030 +- ~10, and SPIN code get 2080 +- ~2, with exactly same hardware setup!

    any hints?

    thx

    @Dave Hein: isn't spinsim for SPIN and PASM simulator?
  • jazzedjazzed Posts: 11,803
    edited 2012-08-17 10:39
    amossam wrote: »
    ok, it seems that i succeed! :cool:

    But, values i got back are almost the same like in tutorial mentioned before, but my results oscillates much more!! i got around 2030 +- ~10, and SPIN code get 2080 +- ~2, with exactly same hardware setup!

    any hints?

    thx

    @Dave Hein: isn't spinsim for SPIN and PASM simulator?

    Good job!

    I was going to mention this before, but wanted to see what happened with your new code ....

    It is possible that usleep() is causing some issues in your oscillations. While usleep() is necessary for pthread code (typically code that starts more than one thread per COG), it actually adds uncertainty. When not using pthread code, one can use waitcnt(). The waitcnt() function timing is deterministic where usleep() is not. So what to do? Replace usleep(microseconds) with delay(microseconds) as defined below.
    void delay(int us)
    {
        waitcnt(us*(CLKFREQ/1000000)+CNT);
    }
    


    Dave's spinsim supports SPIN and PASM.

    There have been a few USB-stick designs floating around. I have PCBs for one, but it is very difficult to assemble. @peward has a USB-stick called PropKey that looks good. Not sure what the status of it is though. http://forums.parallax.com/showthread.php?139043-PropKey-USB-keychain-Prop-board-(was-...toy...)
  • PublisonPublison Posts: 12,366
    edited 2012-08-17 10:47
    amossam wrote: »

    P.S. it there, somewhere, minimal propeller usb stick? i mean, just FTDI and Propeller chip, maybe 2-3 LEDs, USB connector and that's it! No pins, not anything! So, something small size, that can be plugged into USB like small data stick and stay there? So that when you are not at home, and have time, continue working on propeller, and it doesn't take too much space!

    Minimal footprint, but no LED's:

    http://www.parallax.com/Store/Microcontrollers/PropellerChips/tabid/142/ProductID/411/List/0/Default.aspx?SortField=ProductName,ProductName


    o
    r 16 pin I/O:

    http://www.parallax.com/StoreSearchResults/tabid/768/List/0/SortField/4/ProductID/448/Default.aspx?txtSearch=Spin+Stamp


  • jazzedjazzed Posts: 11,803
    edited 2012-08-17 10:54
    Oops. My delay() suggestion is not great because the function fails under about 8us. For the time being I suggest using the delay() suggestion with 10us or more just for simplicity. You could replace the delay() function with a macro if you like, but code would be bigger. There is another method that will be faster for normal C programs, but requires more code rework.

    // macro version of delay(us) function that works to about 6us
    #define delay(us) waitcnt((us)*(CLKFREQ/1000000)+CNT)
  • amossamamossam Posts: 35
    edited 2012-08-17 13:06
    jazzed wrote: »
    Good job!

    I was going to mention this before, but wanted to see what happened with your new code ....

    It is possible that usleep() is causing some issues in your oscillations. While usleep() is necessary for pthread code (typically code that starts more than one thread per COG), it actually adds uncertainty. When not using pthread code, one can use waitcnt(). The waitcnt() function timing is deterministic where usleep() is not. So what to do? Replace usleep(microseconds) with delay(microseconds) as defined below.
    void delay(int us)
    {
        waitcnt(us*(CLKFREQ/1000000)+CNT);
    }
    
    OK, tried that, and values oscillate similarly... I think i can manage this oscillation, as it's about 0.4% of total range...
    jazzed wrote: »
    There have been a few USB-stick designs floating around. I have PCBs for one, but it is very difficult to assemble. @peward has a USB-stick called PropKey that looks good. Not sure what the status of it is though. http://forums.parallax.com/showthread.php?139043-PropKey-USB-keychain-Prop-board-(was-...toy...)

    that's exactly what I had in mind! :-D have to check status of that sticks! :cool:
    jazzed wrote: »
    Oops. My delay() suggestion is not great because the function fails under about 8us. For the time being I suggest using the delay() suggestion with 10us or more just for simplicity. You could replace the delay() function with a macro if you like, but code would be bigger. There is another method that will be faster for normal C programs, but requires more code rework.

    // macro version of delay(us) function that works to about 6us
    #define delay(us) waitcnt((us)*(CLKFREQ/1000000)+CNT)
    well, 10us is OK, since I have 16(?) delays in function, that sums up to 160 us or 0.16ms and that is below 1.2ms frame that ADC gives for reading data...

    and off to check the code, something is not ok in there...
  • amossamamossam Posts: 35
    edited 2012-08-18 11:28
    ok, thx to jazzed, oscillations are now within +-2, and if I stay on CH0, everything is ok....

    but, something I'm doing wrong in setup part....
    when I set 0b1000 for setup, that should be chanel0 single-ended.. and if I set setup to 0b1001 that should be chanel1...
    but for some reason, 0b1000 select correct channel, but 0b1001 selects chanel4, and CH4 is 0b1100 by the specs sheet!? :blank:
    void delay(int us)
    {
        waitcnt(us*(CLKFREQ/1000000)+CNT);
    }
    
    void pulseCLK(int d)
    {
       CLK.high();
       delay(d);
       CLK.low();
    }
    
    int ReadADC(int channel)
    {
       int i;
       int AdcResult;
       int setup;
    
       DINOUT.output();
       CS.low();      // Active chip select
       delay(10);    // Delay about 1 uS
    
       pulseCLK(10);
       DINOUT.high(); //data goes on failing edge
       delay(10);    // Delay about 1 uS
    
       //--- write command 4 bit ----------
       setup = 0b1000 //setup data;
    
       for(i=0; i < 4;i++) 
       {
          pulseCLK(10);
          DINOUT.set( ((setup & 0b1000) == 0b1000) ? 1 : 0  ); // is MSB = 1
          setup <<= 1;  // shift left
          delay(10);
       }
    
       //Sample time?
       pulseCLK(10);
       delay(10);    // Delay about 1 uS
    
       pulseCLK(10);
       delay(10);    // Delay about 1 uS
    
       //--- read ADC result 12 bit --------
       DINOUT.input();
       AdcResult=0;
       int k;
       for(i=0;i<12;i++) {
          pulseCLK(10);
          AdcResult<<=1;
          k = DINOUT.get() & 0x01;
          AdcResult=AdcResult | k;
          delay(10);        // delay about 2 uS
       }
    
       CS.high();
       return(AdcResult);
    }
    

    any help?

    thx
  • amossamamossam Posts: 35
    edited 2012-08-18 13:10
    ok, disregard last post!! :D

    i finally got it working, on all 8 channels!!!!!!

    i'll clean up code, and upload it here in case someone needs it or finds it usefull! ;)
  • jazzedjazzed Posts: 11,803
    edited 2012-08-18 14:02
    amossam wrote: »
    ok, disregard last post!! :D

    i finally got it working, on all 8 channels!!!!!!

    i'll clean up code, and upload it here in case someone needs it or finds it usefull! ;)

    Great. Congrats.
  • amossamamossam Posts: 35
    edited 2012-08-18 16:08
    OK, here is "my" driver for MCP3208/3204 written in pure C.
    It took some time, nerves, and loot of googling and poking around the net...
    thx goes to jazzed, who helped a lot!

    So, it's all in a .h file, ready to be included and used.

    There are two main functions:
    int readADC(int channel, int dinout, int clk, int cs);
    int readADCAverage(int channel, int dinout, int clk, int cs, int samples);
    

    First one will read single value from ADC and return it,
    while second one will read specified number of values and return average...

    Any feedback is welcome, especially for optimizing code!

    P.S. @jazzed: What another method of delay had you had in mind? With current code, it can take only(?) around 1750 samples per second, with delay of 10 usec, and I saw code for this ADC that used delays down to 2 us!
  • jazzedjazzed Posts: 11,803
    edited 2012-08-21 09:49
    amossam wrote: »
    P.S. @jazzed: What another method of delay had you had in mind? With current code, it can take only(?) around 1750 samples per second, with delay of 10 usec, and I saw code for this ADC that used delays down to 2 us!

    The waitcnt2(count,wait) macro can allow very fine delay control.
    /**
     * @file delaydemo.c
     *
     * This program demonstrates creating 2 microsecond or more delays
     * with one statement between delays. The minimum delay is dictated
     * by how long it takes to execute instructions between delays. The
     * use of fcache (FastCache) also determines how small the delays can
     * be - this demo allows fcache to be disabled, but it can be enabled.
     *
     * It should be noted that if the time it takes for code to execute
     * is greater than wait, the code will appear to freeze for about
     * one minute with an 80MHz clock.
     */
    #include <propeller.h>
    
    
    /**
     * delaydemo function
     * HUBTEXT forces function to be in HUB RAM even with XMM modes.
     * Not designed for COG mode.
     *
     * The basis of this delay demo is the propeller.h waitcnt2 macro
     * which translates to __builtin_waitcnt(count, wait).
     *
     *   #define waitcnt2(a, b) __builtin_propeller_waitcnt((a),(b))
     *
     *   Wait until system counter reaches A value.
     *   waitcnt2 Parameters:
     *      a Target value
     *      b Adjust value
     *
     * Demo runs in an infinite loop to allow scope measurement.
     */
    HUBTEXT void delaydemo(void)
    {
        unsigned int count;
        unsigned int wait;
        unsigned int pin;
        // set pin to output
        pin = 1 << 15;
        DIRA |= pin;
        
        // 2us waits for 80MHz clock assuming no fcache.
        // If the code is small enough to fit in the fcache area
        // wait as small as 500ns is possible (at 80MHz).
        wait = CLKFREQ/500000;
        for(;;) {
            // initial delay just for reasonable scope triggering
            count = wait*50+CNT;
            OUTA &= ~pin;
            count = waitcnt2(count, wait);
            // now count contains the target count for the next waitcnt2 call.
            OUTA ^= pin;
            count = waitcnt2(count, wait);
            OUTA ^= pin;
            count = waitcnt2(count, wait);
            OUTA ^= pin;
            count = waitcnt2(count, wait);
            OUTA ^= pin;
            count = waitcnt2(count, wait);
            OUTA ^= pin;
            count = waitcnt2(count, wait);
            OUTA ^= pin;
            count = waitcnt2(count, wait);
            OUTA ^= pin;
            count = waitcnt2(count, wait);
            OUTA ^= pin;
            count = waitcnt2(count, wait);
            OUTA ^= pin;
            count = waitcnt2(count, wait);
            OUTA ^= pin;
            count = waitcnt2(count, wait);
            OUTA ^= pin;
            count = waitcnt2(count, wait);
            OUTA ^= pin;
            count = waitcnt2(count, wait);
            OUTA ^= pin;
            count = waitcnt2(count, wait);
        }
    }
    
    
    /**
     * Main program function.
     */
    void main(void)
    {
        delaydemo();
    }
    
  • amossamamossam Posts: 35
    edited 2012-09-01 07:36
    hey! me again! :innocent:

    thx jazzed for suggestion, but I wasn't been able to change code to work with waitcnt2....

    but, I have read al little about counters, and tried to use them...
    I succeeded, and now I can read few (4-5) times more samples (guessing) per second then with original code using waitcnt! :D
    (If I understand specs correctly, this chip can do a 50 ksps ("50 ksps max.sampling rate atVDD=2.7V") and that is 50 000 samples per second?
    and I guestimate that I'm reading at about 5000-6000 times per second)

    But, if I increase frequency of pulses generated by counter, I'm unable to read data, in fact I get garbage data.
    In what way code can be optimized more?

    thx

    P.S. this is more an exercise then something I need (at least for now)! so, if someone sees that I'm doing wrong something or there is better way, feel free to drop a comment!
    thx again


    Here is code, it's using functions from mcp3208.h
    int readADCCounter(int channel, int dinout, int clk, int cs)
    {
        int i;
        int AdcResult;
        int setup;
    
        //Setting up pins
        // In case pin was already been low, we put it high
        // so we can initiate communication after setting up pins
        pinOutput(cs);
        pinHigh(cs);
    
        pinOutput(dinout);
        pinLow(dinout);
    
        pinOutput(clk);
        int reg = (0b00100 << 26) + clk;
        CTRA = reg;
        FRQA = 8388608; //2^23
        pinLow(clk);
    
        pinLow(cs);      // Active chip select by setting pin low
        waitpeq((1 << clk), (1 << clk)); //high
        waitpne((1 << clk), (1 << clk)); //low
        // Sending configuration to device
        setup = channel | 0b11000;
        for(i=0; i < 5;i++)
        {
            // wait for low state
            waitpne((1 << clk), (1 << clk)); //low
    
            pinWrite(dinout, ((setup & 0b10000) == 0b10000));
            setup <<= 1;  // shift left
        }
    
        //wait 3? clocks
        waitpne((1 << clk), (1 << clk)); //low
        waitpeq((1 << clk), (1 << clk)); //high
        waitpne((1 << clk), (1 << clk)); //low
        waitpeq((1 << clk), (1 << clk)); //high
        waitpne((1 << clk), (1 << clk)); //low
        waitpeq((1 << clk), (1 << clk)); //high
    
        AdcResult=0;
    
        // read ADC result 12 bit
        for(i=0;i<12;i++) {
            waitpne((1 << clk), (1 << clk)); //low
    
            AdcResult=(AdcResult << 1) | (pinRead(dinout) & 0x01);
        }
        pinHigh(cs);
        CTRA = 0; //disable counter
        return(AdcResult);
    }
    
    int readADCAverage(int channel, int dinout, int clk, int cs, int samples)
    {
        int i, k = 0;
    
        for (i=0;i<samples;i++)
            k = k + readADCCounter(channel, dinout, clk, cs);
        return k/samples;
    }
    

    P.S.
    I was unable to figure out what freq is this!?!?
        int reg = (0b00100 << 26) + clk;
        CTRA = reg;
        FRQA = 8388608; //2^23
    
  • TinkersALotTinkersALot Posts: 535
    edited 2013-06-25 20:45
    Keeps coming back "zero"
    int main()                                    // main function
    {
      int buttonVoltage;
    
      do
      {
      pause(1000); 
    
    //(int channel, int dinout, int clk, int cs)
    
      buttonVoltage = readADCAverageEx(0, 26, 25, 27, 5 );
                                   // Wait 1 s for host
      printf("button = %d\n", buttonVoltage);                         // Display a message
      }while(1);
    }
    

    when running on a Prop ASC+ . Schematic for this board is here: http://mghdesigns.com/wiki/_media/asc:pasc-f.pdf

    with one of these stacked on top:

    http://www.hobbyking.com/hobbyking/store/__25087__Arduino_LCD_Keypad_Shield.html?gclid=CI3ciKXY_rcCFU_ZQgodGwwA8Q

    Am I misinterpreting something here?
  • ericpineericpine Posts: 31
    edited 2014-04-02 18:40
    Compiling in LMM model got this going.

    Please observe the 3.3k resistor described in the .h file (between Dout and Din pins).

    Gotta love that extra pin freed up in this function!

    I downloaded the mcp3208.h file on this thread (POST #18) and tucked it in ~ c:/program files/simple IDE/ prop gcc/ prop elf / include

    I ran this sample code fine in Simple IDE with Prop Activity Board in LMM model:


    #include "simpletools.h"
    #include "mcp3208.h" // COMPILE IN LMM MODE !!!

    serial *text;
    int value;
    int adc;

    int main()
    {


    while(1)
    {
    text = serial_open(31,30,1,115200);
    putStr("Enter a decimal:"); //terminal com input verify
    dscan(text, "%d", &value);
    pause(100);
    dprint(text,"You entered %d\n",value); //terminal com output verify
    pause(500);
    adc=readADCAverage(7,2,1,0,3); // read from Channel 7, data pin 2, clock pin 1, chip select pin 0, average 3 samples
    dprint(text,"ADC reads: %d out of 4096 bits\n",adc); // display a proportion of bits to the ref voltage you are running
    pause(1000);

    }
    }
  • jazzedjazzed Posts: 11,803
    edited 2014-04-02 20:40
    Interesting.

    Can I make a suggestion?

    Instead of using serial *text and all that entails, just use the default debug statements.

    I.E. instead of this:
    dprint(text,"You entered %d\n",value); //terminal com output verify

    Do this:
    print("You entered %d\n",value);

    Same goes for any of the functions that use the text pointer. You can also get rid of text = serial_open(...).

    There is a Simple Library update coming that has a smaller version of print also. The iprint function is the same as print but with no floating point support. Additionally there are "digits" versions of putDec, putBin, putHex, etc... aptly named putDecDigits, putBinDigits, putHexDigits.


    Cheers.
    --Steve
    ericpine wrote: »
    Compiling in LMM model got this going.

    Please observe the 3.3k resistor described in the .h file (between Dout and Din pins).

    Gotta love that extra pin freed up in this function!

    I downloaded the mcp3208.h file on this thread (POST #18) and tucked it in ~ c:/program files/simple IDE/ prop gcc/ prop elf / include

    I ran this sample code fine in Simple IDE with Prop Activity Board in LMM model:


    #include "simpletools.h"
    #include "mcp3208.h" // COMPILE IN LMM MODE !!!

    serial *text;
    int value;
    int adc;

    int main()
    {


    while(1)
    {
    text = serial_open(31,30,1,115200);
    putStr("Enter a decimal:"); //terminal com input verify
    dscan(text, "%d", &value);
    pause(100);
    dprint(text,"You entered %d\n",value); //terminal com output verify
    pause(500);
    adc=readADCAverage(7,2,1,0,3); // read from Channel 7, data pin 2, clock pin 1, chip select pin 0, average 3 samples
    dprint(text,"ADC reads: %d out of 4096 bits\n",adc); // display a proportion of bits to the ref voltage you are running
    pause(1000);

    }
    }
  • ericpineericpine Posts: 31
    edited 2014-04-03 23:46
    Jazzed,

    FYI, You are awesome.

    At this point,the attached code example is adapted from "my universal" starting point for general Propeller C I/O.

    It is quick and easy to copy and paste LCD and other devices in from this little file.

    I am new to the Propeller (and C) and I certainly struggle a bit. Thanks for the tips!

    Anywho, my next task is to interface the TI "TLC5628C" 8ch, 8 bit, DAC. I think this source code will help me a lot in that project.


    Don't forget the 7 bit RS232 ! -E-
  • DavidZemonDavidZemon Posts: 2,973
    edited 2014-04-07 07:32
    Eric,

    Have you seen PropWare or libpropeller? I skimmed your thread and didn't see any warning flags that would keep you from using one of them. The one requirement is that both libpropeller's MCP3208 and PropWare's MCP3000 classes require an independent cog for SPI communication. If you do not have a cog to spare, they won't help you. The good news is, PropWare's SPI cog can be used for other SPI peripherals as well (libpropeller's is locked to the MCP3208).

    Here is the doc page for PropWare::MCP3000 (ignore the class doc at the top that says only 3004/3008. I forgot to update that after adding support for the 320x and 330x).

    Doc page for libpropeller::MCP3208
    (Do note: libpropeller is not my product. It was written by forum member SRLM and he was gracious enough to allow me to package it along with PropWare. Original source is here)

    If you download a binary distribution of PropWare v2.0-beta1, it comes bundled with libpropeller and Simple so you can continue using your Simple functions and choose whichever API (PropWare or libpropeller) suits your comfort zone better. If you want to build from source, just run the "propwareImporter.py" script in the util directory and then "make" in the PropWare root directory.
    http://david.zemon.name/downloads/PropWare_Binaries/PropWare_v2.0-beta1.zip

    If you have questions, please let me know. PropWare is in active development and I am always looking for feedback.

    I have a TLC series DAC sitting around. I think 12-bit? Not sure. If you'd like, I can add support for that as well. I haven't looked at the TLC5628C, but I'll bet the protocols are similar enough that I can add support for both in a single class, just like the MCP3000 series.
  • ericpineericpine Posts: 31
    edited 2014-04-15 18:32
    SwimDude0614, The TLC5628C DAC works easily with shiftin/out. I'll post my code in another thread.

    I am most interested in interfacing older RS232 equipment with the propeller, namely 7 bits is my main problem. Jazzed said he will look at the serial libs, but I know he is very busy and I could be about the only one that is interested in 7E2 RS232 com.

    Any thoughts on that using Propware? At this point, I have cogs galore, so that is a non-issue. Thanks!
  • DavidZemonDavidZemon Posts: 2,973
    edited 2014-04-15 19:01
    Oh that's interesting... I've never bit-banged RS232 before - but it shouldn't be much more complicated than SPI. How fast do you need it to go and how soon do you need it done? C would be faster development time (than assembly) of course, but laughably slow performance. I could give this a go though.
  • ersmithersmith Posts: 6,053
    edited 2014-04-16 05:26
    Oh that's interesting... I've never bit-banged RS232 before - but it shouldn't be much more complicated than SPI. How fast do you need it to go and how soon do you need it done? C would be faster development time (than assembly) of course, but laughably slow performance. I could give this a go though.

    I don't think C performance should be bad -- the propgcc SimpleSerial routines are written in C, and I've looked at the assembly output and it's fairly reasonable. They are only half duplex, of course, but if I remember correctly Heater did a version of FullDuplexSerial in C.

    Eric
  • ericpineericpine Posts: 31
    edited 2014-04-16 18:34
  • pmrobertpmrobert Posts: 673
    edited 2014-07-01 15:10
    ersmith wrote: »
    I don't think C performance should be bad -- the propgcc SimpleSerial routines are written in C, and I've looked at the assembly output and it's fairly reasonable. They are only half duplex, of course, but if I remember correctly Heater did a version of FullDuplexSerial in C.

    Eric
    A data point.... I'm using fdserial at 350K baud all day long on an engine controller project. It takes a cog but fast and reliable comms are essential for my use and it has been 100% reliable during 48 hour testing.
  • DavidZemonDavidZemon Posts: 2,973
    edited 2014-07-01 18:35
    pmrobert wrote: »
    A data point.... I'm using fdserial at 350K baud all day long on an engine controller project. It takes a cog but fast and reliable comms are essential for my use and it has been 100% reliable during 48 hour testing.

    You're absolutely right. Performance turned out to be a non-issue. Mine is only somewhat full-duplex though. I've currently implemented a solution that uses dedicated I/O lines but only a single cog - so that means you can only send or receive - not both simultaneously. And there is no buffer, so the send and receive calls are infinitely blocking. I've started jotting down some notes during speed tests and putting my findings here:
    http://david.zemon.name/professional/PropWare/docs/html/classPropWare_1_1UART.html#details

    -
    -edit--
    I shouldn't say "you can only send or receive". There's no reason you couldn't start two HalfDuplex cogs and use one for sends and the other for receives. Perhaps this is even a better way to do it?
Sign In or Register to comment.