Class similar to AnalogIn that uses burst mode to run continious background conversions so when the input is read, the last value can immediatly be returned. This slightly modified version allows NC pins.

Dependents:   Pinscape_Controller

Fork of FastAnalogIn by Erik -

FastAnalogIn_KLXX_K20D50M.cpp

Committer:
mjr
Date:
2015-12-19
Revision:
11:234c5cd2b8de
Parent:
9:31184aa1449c

File content as of revision 11:234c5cd2b8de:

#if defined(TARGET_KLXX) || defined(TARGET_K20D50M)

#include "FastAnalogIn.h"
#include "clk_freqs.h"

#define MAX_FADC            6000000
#define CHANNELS_A_SHIFT    5

#ifdef TARGET_K20D50M
static const PinMap PinMap_ADC[] = {
    {PTC2, ADC0_SE4b, 0},
    {PTD1, ADC0_SE5b, 0},
    {PTD5, ADC0_SE6b, 0},
    {PTD6, ADC0_SE7b, 0},
    {PTB0, ADC0_SE8,  0},
    {PTB1, ADC0_SE9,  0},
    {PTB2, ADC0_SE12, 0},
    {PTB3, ADC0_SE13, 0},
    {PTC0, ADC0_SE14, 0},
    {PTC1, ADC0_SE15, 0},
    {NC,   NC,        0}
};
#endif

FastAnalogIn::FastAnalogIn(PinName pin, bool enabled)
{
    if (pin == NC)
        return;
    
    ADCnumber = (ADCName)pinmap_peripheral(pin, PinMap_ADC);
    if (ADCnumber == (ADCName)NC) {
        error("ADC pin mapping failed");
    }

    SIM->SCGC6 |= SIM_SCGC6_ADC0_MASK;

    uint32_t port = (uint32_t)pin >> PORT_SHIFT;
    SIM->SCGC5 |= 1 << (SIM_SCGC5_PORTA_SHIFT + port);

    uint32_t cfg2_muxsel = ADC_CFG2_MUXSEL_MASK;
    if (ADCnumber & (1 << CHANNELS_A_SHIFT)) {
        cfg2_muxsel = 0;
    }
    
    // bus clk
    uint32_t PCLK = bus_frequency();
    uint32_t clkdiv;
    for (clkdiv = 0; clkdiv < 4; clkdiv++) {
        if ((PCLK >> clkdiv) <= MAX_FADC)
            break;
    }
    if (clkdiv == 4)                    //Set max div
        clkdiv = 0x7;

    ADC0->SC1[1] = ADC_SC1_ADCH(ADCnumber & ~(1 << CHANNELS_A_SHIFT));

    ADC0->CFG1 = ADC_CFG1_ADIV(clkdiv & 0x3)    // Clock Divide Select: (Input Clock)/8
               | ADC_CFG1_MODE(3)               // (16)bits Resolution
               | ADC_CFG1_ADICLK(clkdiv >> 2);  // Input Clock: (Bus Clock)/2

    ADC0->CFG2 = cfg2_muxsel            // ADxxb or ADxxa channels
               | ADC_CFG2_ADACKEN_MASK  // Asynchronous Clock Output Enable
               | ADC_CFG2_ADHSC_MASK;   // High-Speed Configuration

    ADC0->SC2 = ADC_SC2_REFSEL(0);      // Default Voltage Reference

    pinmap_pinout(pin, PinMap_ADC);

    //Enable channel
    running = false;
    enable(enabled);
}

void FastAnalogIn::enable(bool enabled)
{
    //If currently not running
    if (!running) {
        if (enabled) {
            //Enable the ADC channel
            ADC0->SC3 |= ADC_SC3_ADCO_MASK;       // Enable continuous conversion
            ADC0->SC1[0] = ADC_SC1_ADCH(ADCnumber & ~(1 << CHANNELS_A_SHIFT));  //Start conversion
            running = true;
        } else
            disable();
    }
}
 
void FastAnalogIn::disable( void )
{
    //If currently running
    if (running) {
        ADC0->SC3 &= ~ADC_SC3_ADCO_MASK;      // Disable continuous conversion
    }
    running = false;
}

uint16_t FastAnalogIn::read_u16()
{
    if (!running)
    {
        // start conversion
        ADC0->SC1[0] = ADC_SC1_ADCH(ADCnumber & ~(1 << CHANNELS_A_SHIFT));
        // Wait Conversion Complete
        while ((ADC0->SC1[0] & ADC_SC1_COCO_MASK) != ADC_SC1_COCO_MASK);
    }
    if(running && ((ADC0->SC1[0]&ADC_SC1_ADCH_MASK) != (ADC_SC1_ADCH(ADCnumber & ~(1 << CHANNELS_A_SHIFT)))))
    {
        running = false;
        enable();
        while ((ADC0->SC1[0] & ADC_SC1_COCO_MASK) != ADC_SC1_COCO_MASK);
    }
    // Return value
    return (uint16_t)ADC0->R[0];
}

#endif //defined TARGET_KLXX