Embedded system Fun Blog
























































Find out all the best information, libraries and circuit about the latest Embedded systems.
Showing posts with label class. Show all posts
Showing posts with label class. Show all posts

Sunday, 8 January 2012

MBED: Super High Speed AnalogIn Class

.from: http://mbed.org/users/shintamainjp/libraries/HighSpeedAnalogIn/lm3z05

XxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXx HighSpeedAnalogIn.cpp XxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXx

#include "HighSpeedAnalogIn.h"

HighSpeedAnalogIn *HighSpeedAnalogIn::instance;
int HighSpeedAnalogIn::refcnt = 0;

HighSpeedAnalogIn::HighSpeedAnalogIn(PinName pin0, PinName pin1, PinName pin2, PinName pin3, PinName pin4, PinName pin5) {

    refcnt++;
    if (refcnt > 1) {
        error("Please do not use over an object.");
    }

    static const int sample_rate = 200000;
    static const int cclk_div = 1;

    int adc_clk_freq = CLKS_PER_SAMPLE * sample_rate;
    int m = (LPC_SC->PLL0CFG & 0xFFFF) + 1;
    int n = (LPC_SC->PLL0CFG >> 16) + 1;
    int cclkdiv = LPC_SC->CCLKCFG + 1;
    int Fcco = (2 * m * XTAL_FREQ) / n;
    int cclk = Fcco / cclkdiv;

    LPC_SC->PCONP |= (1 << 12);
    LPC_SC->PCLKSEL0 &= ~(0x3 << 24);
    switch (cclk_div) {
        case 1:
            LPC_SC->PCLKSEL0 |= 0x1 << 24;
            break;
        case 2:
            LPC_SC->PCLKSEL0 |= 0x2 << 24;
            break;
        case 4:
            LPC_SC->PCLKSEL0 |= 0x0 << 24;
            break;
        case 8:
            LPC_SC->PCLKSEL0 |= 0x3 << 24;
            break;
        default:
            fprintf(stderr, "Warning: ADC CCLK clock divider must be 1, 2, 4 or 8. %u supplied.\n", cclk_div);
            fprintf(stderr, "Defaulting to 1.\n");
            LPC_SC->PCLKSEL0 |= 0x1 << 24;
            break;
    }
    int pclk = cclk / cclk_div;
    int clock_div = pclk / adc_clk_freq;

    if (clock_div > 0xFF) {
        fprintf(stderr, "Warning: Clock division is %u which is above 255 limit. Re-Setting at limit.\n", clock_div);
        clock_div = 0xFF;
    }
    if (clock_div == 0) {
        fprintf(stderr, "Warning: Clock division is 0. Re-Setting to 1.\n");
        clock_div = 1;
    }

    int _adc_clk_freq = pclk / clock_div;
    if (_adc_clk_freq > MAX_ADC_CLOCK) {
        fprintf(stderr, "Warning: Actual ADC sample rate of %u which is above %u limit\n", _adc_clk_freq / CLKS_PER_SAMPLE, MAX_ADC_CLOCK / CLKS_PER_SAMPLE);
        int max_div = 1;
        while ((pclk / max_div) > MAX_ADC_CLOCK) {
            max_div++;
        }
        fprintf(stderr, "Maximum recommended sample rate is %u\n", (pclk / max_div) / CLKS_PER_SAMPLE);
    }

    LPC_ADC->ADCR = ((clock_div - 1) << 8) | (1 << 21);
    LPC_ADC->ADCR &= ~0xFF;

    for (int i = 0; i < 8; i++) {
        _adc_data[i] = 0;
    }

    // Attach IRQ
    instance = this;
    NVIC_SetVector(ADC_IRQn, (uint32_t)&static_adcisr);

    // Disable global interrupt
    LPC_ADC->ADINTEN &= ~0x100;

    // Clock frequency.
    printf("Clock frequency:%d\n", _adc_clk_freq);

    // Actual sampling rate.
    printf("Actual sampling rate:%d\n", _adc_clk_freq / CLKS_PER_SAMPLE);
   
    int tmp = LPC_ADC->ADCR & ~(0x0F << 24);
    tmp |= ((0x0 & 7) << 24) | ((0x0 & 1) << 27);
    LPC_ADC->ADCR = tmp;
    LPC_ADC->ADCR |= (1 << 16);

    if (pin0 != NC) setup(pin0, 1);
    if (pin1 != NC) setup(pin1, 1);
    if (pin2 != NC) setup(pin2, 1);
    if (pin3 != NC) setup(pin3, 1);
    if (pin4 != NC) setup(pin4, 1);
    if (pin5 != NC) setup(pin5, 1);

    interrupt_state(pin0, 1);
}

HighSpeedAnalogIn::~HighSpeedAnalogIn() {
}

void HighSpeedAnalogIn::static_adcisr(void) {
    instance->adcisr();
}

void HighSpeedAnalogIn::adcisr(void) {
    uint32_t stat = LPC_ADC->ADSTAT;
    // Scan channels for over-run or done and update array
    if (stat & 0x0101) _adc_data[0] = LPC_ADC->ADDR0;
    if (stat & 0x0202) _adc_data[1] = LPC_ADC->ADDR1;
    if (stat & 0x0404) _adc_data[2] = LPC_ADC->ADDR2;
    if (stat & 0x0808) _adc_data[3] = LPC_ADC->ADDR3;
    if (stat & 0x1010) _adc_data[4] = LPC_ADC->ADDR4;
    if (stat & 0x2020) _adc_data[5] = LPC_ADC->ADDR5;
    if (stat & 0x4040) _adc_data[6] = LPC_ADC->ADDR6;
    if (stat & 0x8080) _adc_data[7] = LPC_ADC->ADDR7;
}

int HighSpeedAnalogIn::get_channel(PinName pin) {
    int ch;
    switch (pin) {
        case p15:// =p0.23 of LPC1768
            ch = 0;
            break;
        case p16:// =p0.24 of LPC1768
            ch = 1;
            break;
        case p17:// =p0.25 of LPC1768
            ch = 2;
            break;
        case p18:// =p0.26 of LPC1768
            ch = 3;
            break;
        case p19:// =p1.30 of LPC1768
            ch = 4;
            break;
        case p20:// =p1.31 of LPC1768
            ch = 5;
            break;
        default:
            ch = 0;
            break;
    }
    return ch;
}

uint32_t HighSpeedAnalogIn::get_data(PinName pin) {
    // If in burst mode and at least one interrupt enabled then
    // take all values from _adc_data
    if (LPC_ADC->ADINTEN & 0x3F) {
        return (_adc_data[get_channel(pin)]);
    } else {
        // Return current register value or last value from interrupt
        switch (pin) {
            case p15:// =p0.23 of LPC1768
                return ((LPC_ADC->ADINTEN & 0x01) ? _adc_data[0] : LPC_ADC->ADDR0);
            case p16:// =p0.24 of LPC1768
                return ((LPC_ADC->ADINTEN & 0x02) ? _adc_data[1] : LPC_ADC->ADDR1);
            case p17:// =p0.25 of LPC1768
                return ((LPC_ADC->ADINTEN & 0x04) ? _adc_data[2] : LPC_ADC->ADDR2);
            case p18:// =p0.26 of LPC1768:
                return ((LPC_ADC->ADINTEN & 0x08) ? _adc_data[3] : LPC_ADC->ADDR3);
            case p19:// =p1.30 of LPC1768
                return ((LPC_ADC->ADINTEN & 0x10) ? _adc_data[4] : LPC_ADC->ADDR4);
            case p20:// =p1.31 of LPC1768
                return ((LPC_ADC->ADINTEN & 0x20) ? _adc_data[5] : LPC_ADC->ADDR5);
            default:
                return 0;
        }
    }
}

// Enable or disable an HighSpeedAnalogIn pin
void HighSpeedAnalogIn::setup(PinName pin, int state) {
    int ch = get_channel(pin);
    if ((state & 1) == 1) {
        switch (pin) {
            case p15:// =p0.23 of LPC1768
                LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 14);
                LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 14;
                LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 14);
                LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 14;
                break;
            case p16:// =p0.24 of LPC1768
                LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 16);
                LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 16;
                LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 16);
                LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 16;
                break;
            case p17:// =p0.25 of LPC1768
                LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 18);
                LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 18;
                LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 18);
                LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 18;
                break;
            case p18:// =p0.26 of LPC1768:
                LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 20);
                LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 20;
                LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 20);
                LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 20;
                break;
            case p19:// =p1.30 of LPC1768
                LPC_PINCON->PINSEL3 &= ~((unsigned int)0x3 << 28);
                LPC_PINCON->PINSEL3 |= (unsigned int)0x3 << 28;
                LPC_PINCON->PINMODE3 &= ~((unsigned int)0x3 << 28);
                LPC_PINCON->PINMODE3 |= (unsigned int)0x2 << 28;
                break;
            case p20:// =p1.31 of LPC1768
                LPC_PINCON->PINSEL3 &= ~((unsigned int)0x3 << 30);
                LPC_PINCON->PINSEL3 |= (unsigned int)0x3 << 30;
                LPC_PINCON->PINMODE3 &= ~((unsigned int)0x3 << 30);
                LPC_PINCON->PINMODE3 |= (unsigned int)0x2 << 30;
                break;
            default:
                error("Invalid pin.");
                break;
        }
        // Select channel
        LPC_ADC->ADCR |= (1 << ch);
    } else {
        switch (pin) {
            case p15://=p0.23 of LPC1768
                LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 14);
                LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 14);
                break;
            case p16://=p0.24 of LPC1768
                LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 16);
                LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 16);
                break;
            case p17://=p0.25 of LPC1768
                LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 18);
                LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 18);
                break;
            case p18://=p0.26 of LPC1768:
                LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 20);
                LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 20);
                break;
            case p19://=p1.30 of LPC1768
                LPC_PINCON->PINSEL3 &= ~((unsigned int)0x3 << 28);
                LPC_PINCON->PINMODE3 &= ~((unsigned int)0x3 << 28);
                break;
            case p20://=p1.31 of LPC1768
                LPC_PINCON->PINSEL3 &= ~((unsigned int)0x3 << 30);
                LPC_PINCON->PINMODE3 &= ~((unsigned int)0x3 << 30);
                break;
            default:
                error("Invalid pin.");
                break;
        }
        LPC_ADC->ADCR &= ~(1 << ch);
    }
}

void HighSpeedAnalogIn::interrupt_state(PinName pin, int state) {
    int ch = get_channel(pin);
    if (state == 1) {
        LPC_ADC->ADINTEN &= ~0x100;
        LPC_ADC->ADINTEN |= 1 << ch;
        /* Enable the HighSpeedAnalogIn Interrupt */
        NVIC_EnableIRQ(ADC_IRQn);
    } else {
        LPC_ADC->ADINTEN &= ~(1 << ch);
        //Disable interrrupt if no active pins left
        if ((LPC_ADC->ADINTEN & 0xFF) == 0)
            NVIC_DisableIRQ(ADC_IRQn);
    }
}

float HighSpeedAnalogIn::read(PinName pin) {
    /*
     * Reset DONE and OVERRUN.
     *
     * bit 31 : DONE
     * bit 30 : OVERRUN
     */
    _adc_data[get_channel(pin)] &= ~(((uint32_t)0x01 << 31) | ((uint32_t)0x01 << 30));
    return (float)((get_data(pin) >> 4) & 0xFFF) / (float)0xFFF;
}

unsigned short HighSpeedAnalogIn::read_u16(PinName pin) {
    /*
     * Reset DONE and OVERRUN.
     *
     * bit 31 : DONE
     * bit 30 : OVERRUN
     */
    _adc_data[get_channel(pin)] &= ~(((uint32_t)0x01 << 31) | ((uint32_t)0x01 << 30));
    return ((get_data(pin) >> 4) & 0xFFF);
}

XxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXx HighSpeedAnalogIn.h XxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXx

#ifndef HIGH_SPEED_ANALOG_IN_H
#define HIGH_SPEED_ANALOG_IN_H

#include "mbed.h"

class HighSpeedAnalogIn {
public:

    HighSpeedAnalogIn(PinName pin0, PinName pin1 = NC, PinName pin2 = NC, PinName pin3 = NC, PinName pin4 = NC, PinName pin5 = NC);
    ~HighSpeedAnalogIn();
    float read(PinName pin);
    unsigned short read_u16(PinName pin);

private:

    HighSpeedAnalogIn();
    uint32_t _adc_data[8];

    static const int XTAL_FREQ = 12000000;
    static const int MAX_ADC_CLOCK = 13000000;
    static const int CLKS_PER_SAMPLE = 64;
   
    static HighSpeedAnalogIn *instance;
    static int refcnt;

    static void static_adcisr(void);

    int get_channel(PinName pin);
    uint32_t get_data(PinName pin);
    void adcisr(void);
    void setup(PinName pin, int state);
    void interrupt_state(PinName pin, int state);
};

#endif
XxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXx EOF XxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXx