Fast AnalogIn module which asks for a single non blocking reading and causes and interrupt when done.

NbAnalogIn.cpp

Committer:
dontknowhow
Date:
2017-04-03
Revision:
2:336af413f75c
Parent:
1:2666729acca1
Child:
3:d4f99bc10643

File content as of revision 2:336af413f75c:

#include "NbAnalogIn.h"

static inline int pos_inc(int i) {
    
    if (i < ADC_BUF_SIZE - 1) {
        i++;
    } else {
        i = 0;
    }    
    return i;  
}

static const PinMap PinMap_ADC[] = {
    P0_23, ADC0_0, 1,
    P0_24, ADC0_1, 1,
    P0_25, ADC0_2, 1,
    P0_26, ADC0_3, 1,
    P1_30, ADC0_4, 3,
    P1_31, ADC0_5, 3,
    P0_2,  ADC0_7, 2,
    P0_3,  ADC0_6, 2,
    NC,    NC,     0
};

//set the static handlers array to 0
NbAnalogIn* NbAnalogIn::handlers[ADC_CHANNELS] = {0}; 
volatile bool NbAnalogIn::converting = false; 

NbAnalogIn::NbAnalogIn( PinName pin, void (*irqfunc)() ) {
    
    NVIC_EnableIRQ(ADC_IRQn);
    NVIC_SetVector(ADC_IRQn, (uint32_t)irq);
    
    cirq = irqfunc;
    
    channel = (ADCName)pinmap_peripheral(pin, PinMap_ADC);
    if (channel == (uint32_t)NC)
        error("ADC pin mapping failed");
    
    
    write_pos = 0;      // next position to be written to
    read_pos = 0;       // next position to be read from
    
    handlers[channel] = this;    // put a pointer to this object into the handlers array
    
    LPC_SC->PCONP |= (1 << 12); // turn power for ADC on
    
    
    // set peripheral clock registers to provide clock for ADC (bits 24 & 25)
    // set to 00 for PCLK = CCLK
    LPC_SC->PCLKSEL0 &= ~(0x3 << 24); // clear bits
    LPC_SC->PCLKSEL0 |= (0x1 << 24);  // set bits
        
    
    //Map pins
    pinmap_pinout(pin, PinMap_ADC);
    
    /* set the A/D control register */
    
    // select clkdiv = 7, enable, don't start yet
    LPC_ADC->ADCR  |= (7 << 8)          // set CLKDIV=7 (the fastest)
                    | (1 << 21)         // Power On
                    | (0 << 24) ;       // Don't Start yet
                    
    LPC_ADC->ADINTEN |= (1 << 8);
}


int NbAnalogIn::readBl() {
    
    /* disable interrupt */
    NVIC_EnableIRQ(ADC_IRQn);
    
    LPC_ADC->ADCR   &= ~( 0xff );  // disable all other channels
    LPC_ADC->ADCR   |= (1 << channel)
                    |  (1 << 24) ; // start conversion
                    
    
    while((LPC_ADC->ADSTAT & (1 << channel)) == 0);
    
    int adc_result = (int)( (LPC_ADC->ADGDR >> 4) & 0xFFF );
    
    NVIC_EnableIRQ(ADC_IRQn);
    return adc_result;
}

void NbAnalogIn::triggerConv( bool wait) {
    
    if(wait) {
        while(converting);
    }
    
    converting = true;
    LPC_ADC->ADCR   &= ~( 0xff );  // disable all other channels
    LPC_ADC->ADCR   |= (1 << channel)
                    |  (1 << 24) ; // start conversion
                    
 
}

// static interrupt handler
void NbAnalogIn::irq() {
    
    
    int adc_result = (int)((LPC_ADC->ADGDR >> 4) & 0xFFF);
    uint8_t adc_channel = (uint8_t)((LPC_ADC->ADGDR >> 24) & 0x7);
    
    converting = false;
    
    /** for debug 
    static int count = 0;    
    adc_result = count++;    
    printf("NbAnalogIn::irq(): channel %d, result %d \n",adc_channel, adc_result);
    */
    
    // call the right channel's handler
    handlers[adc_channel]->handler(adc_result);
    
}

void NbAnalogIn::handler( int adc_result ) {
    
    
    buffer[write_pos] = adc_result;
    
    //printf("NbAnalogIn::handler(c%d): %d written into pos %d \n", channel,adc_result, write_pos);
    write_pos = pos_inc( write_pos );
    
    // loop around
    if( write_pos == read_pos ) {
        read_pos = pos_inc( read_pos ); // keep read position ahead of write position
        //printf("NbAnalogIn::handler(c%d): LOOP AROUND!!! incremented r \n", channel);
    }
    //printf("NbAnalogIn::handler(c%d): w=%d, r=%d \n", channel, write_pos, read_pos);

        // call custom irq handler if set
    if (cirq)
        cirq();    
}

bool NbAnalogIn::readable() {
    return  write_pos != read_pos;
}

int NbAnalogIn::read() {
    
    while(write_pos == read_pos);
    
    int result = buffer[read_pos];
    
    //printf("NbAnalogIn::readNb(c%d): read %d from pos %d\n", channel, buffer[read_pos], read_pos );
    
    read_pos = pos_inc( read_pos ); // increment reading position
    
    return result;
}