Simple Analog -- Could Use Some Help

JonnyMacJonnyMac Posts: 6,596
edited 2020-03-23 - 23:51:35 in Propeller 2
I have this constant:
con
'          %AAAA_BBBB_FFF_PPP_PPP_PPPPPPP_TT_MMMMM_0
  ANALOG = %0000_0000_000_100_011_0000000_00_11000_0
...and this little snippet of code using a 10K pot with between 3.3v and ground, with the wiper attached to pin 40.
  pinstart(40, ANALOG, %00_1011, 0)
  
  repeat
    waitms(100)
    level := rdpin(40)
    term.fstr1(string("POT = %d\r"), level)
It works, but instead of 0..4095 I am getting 705..3389.

Comments

  • JonnyMacJonnyMac Posts: 6,596
    edited 2020-03-24 - 00:39:49
    After seeing this in another thread:
    Your measurement loop should periodically run the calibrate step on every ADC pin.
    ...I'm guessing this is what we need to do:
    con
    '           %AAAA_BBBB_FFF_PPP_PPP_PPPPPPP_TT_MMMMM_0
      AIN_GND = %0000_0000_000_100_000_0000000_00_11000_0
      AIN_VIO = %0000_0000_000_100_001_0000000_00_11000_0
      AIN_PIN = %0000_0000_000_100_011_0000000_00_11000_0
    
    
    pub main() | lo, hi, level
    
      setup()
    
      pinstart(40, AIN_GND, %00_1100, 0)
      waitms(100)
      lo := rdpin(40)
     
      pinstart(40, AIN_VIO, %00_1100, 0)
      waitms(100)
      hi := rdpin(40)  
      
      pinstart(40, AIN_PIN, %00_1100, 0)
      
      repeat
        waitms(100)
        level := map(rdpin(40), lo, hi, 0, 4095)
        term.fstr1(string("POT = %d\r"), level)
        
      
    pub map(value, inmin, inmax, outmin, outmax) : result
    
    '' Maps value in range inmin..inmax to new value in range outmin..outmax
    
      value := (value - inmin) * (outmax - outmin) / (inmax - inmin) + outmin  
      
      return outmin #> value <# outmax
    
  • pmrobertpmrobert Posts: 598
    edited 2020-03-24 - 01:04:31
    Disregard please/
  • Be aware the ADC can measure below gnd and above 3V3.

  • I think we're doing the same thing -- I'm using the RevB ES and the mode bits have changed.
  • pmrobert wrote: »
    You apparently need to get the GND and VIO calibration values before scaling and calculating an accurate result. Here's some very sloppy C code that worked on 2 consecutive pins on my RevA P2-ES.

    /* ADC Functions */
    
    #define adc_read_mode 0b0000_0000_000_100011_0000000_00_01111_0
    #define adc_gndcal_mode 0b0000_0000_000_100000_0000000_00_01111_0
    #define adc_viocal_mode 0b0000_0000_000_100001_0000000_00_01111_0
    
    int adcgndcal[2];
    int adcviocal[2];
    int adc_cycles = 600;
    
    /* Returns voltage in microvolts from one channel */
    int adc_acq(pin) {
        int val;
        int start_cnt;
        int acqdelay = adc_cycles*2;
        {
            /* Read the pin value */
            val = adc_read(pin);
            /* Return uv */
            //fds.printfss("Pin %d Val %d\n\r",pin,val);
            return(val - adcgndcal[pin]) * 3300000 / (adcviocal[pin] - adcgndcal[pin]);
        }
    
    }
    
    int adc_read(pin) {
        //fds.printfss("Reading Pin %d\n\r",pin);
        int val;
        int mode;
        int time;
        int acqdelay = adc_cycles*2;
        int loccycles = adc_cycles;
        adc_calibrate();
        mode = adc_read_mode;
        __asm{
            wrpin mode,pin
            wxpin loccycles,pin
            dirh pin
            getct   time
            addct1  time, acqdelay
            waitct1
            rdpin val,pin
        };
        //fds.printfss("Reading Pin %d Val %d\n\r",pin,val);
        return(val);
    }
    
    void adc_calibrate()
    {
        int val;
        int mode;
        int time;
        int acqdelay = adc_cycles*2;
        int loccycles = adc_cycles;
        int pin;
        for(pin=0; pin<2; pin++)
        {
            mode = adc_gndcal_mode;
            __asm{
                wrpin mode,pin
                wxpin loccycles,pin
                dirh pin
                getct   time
                addct1  time, acqdelay
                waitct1
                rdpin val,pin
            };
            adcgndcal[pin] = val;
            mode = adc_viocal_mode;
            __asm{
                wrpin mode,pin
                wxpin loccycles,pin
                dirh pin
                getct   time
                addct1  time, acqdelay
                waitct1
                rdpin val,pin
            };
            adcviocal[pin] = val;
        }
    }
    

  • What OzPropDev said is the key, the ADC has a party trick that lets it measure beyond the rails

    when we take a 16 bit ADC sample (0..65535),
    "0" corresponds to around -0.7v DC
    "10~12000" corresponds to 0v GND
    "53~55000" corresponds to 3v3
    "65535" corresponds to around 4v

    You're working on 12 bits, so divide the above values by 16, gives you around 700 to 3400 that you are seeing
Sign In or Register to comment.