This code is to collect data from the ADCs in burst mode, decimate the data, encapsulate it in a simple UDP-like packet and then transmit it over the serial port.

Dependencies:   mbed

daq.cpp

Committer:
jimurai
Date:
2010-08-27
Revision:
0:03e8a03052c9

File content as of revision 0:03e8a03052c9:

#include "mbed.h"
#include "daq.h"

/**
 *  A class to implement BURST mode sampling of multiple ADCs
 */

ADC_BURST *ADC_BURST::instance;

/**
 * Constructor for BURST mode.
 * ADCs in use are on mbed pins 15-17 and 19
 * These equate to ADCs
 */

ADC_BURST::ADC_BURST () {
    // Make this instance available for pointing to privately
    instance = this;
    // Power up the ADC
    LPC_SC->PCONP |= (1 << 12);
    // Set up the pins
    //  DIP15:17 = ADC0:2
    LPC_PINCON->PINSEL1 &=     ~((uint32_t)0x3F << 14);
    LPC_PINCON->PINSEL1 |=      ((uint32_t)0x15 << 14);
    //  DIP19 = ADC4
    LPC_PINCON->PINSEL3 |=      ((uint32_t)0x3 << 28);
    //  Tri-state, no-pull
    LPC_PINCON->PINMODE1 &=    ~((uint32_t)0x3F << 14);
    LPC_PINCON->PINMODE1 |=     ((uint32_t)0x2A << 14);
    LPC_PINCON->PINMODE3 &=    ~((uint32_t)0x3 << 28);
    LPC_PINCON->PINMODE3 |=     ((uint32_t)0x2 << 28);
    // Set the clock divider to 256 (96e6/4/24 = 1e6) [LPC_SC->PCLKSEL0:PCLK_ADC = x20 by default]
    LPC_ADC->ADCR = (255 << 8);
    // Select the ADC channel
    LPC_ADC->ADCR &= ~0xFF;
    LPC_ADC->ADCR |= 0x17;      // ADC0:2,4 - DIP15:17,19
    // Attach a function to the interrupt vector table
    NVIC_SetVector(ADC_IRQn, (uint32_t)&_burst_isr);
    NVIC_EnableIRQ(ADC_IRQn);
    // Enable interrupts
    LPC_ADC->ADINTEN = 0x17;    // Interrupt on channels 0:2,4
    attached_ = false;
}

/**
 * Attach a function to the interrupt service routine
 *
 * @param inptr Function pointer passed from main code.
 */

void ADC_BURST::attach (FuncPtr inptr) {
    isr_pointer_ = inptr;
    // Power up the ADC circuitry
    LPC_ADC->ADCR |= (1 << 21);
    // Enable BURST mode to start continuous conversions
    LPC_ADC->ADCR |= (1 << 16);
    attached_ = true;
}

void ADC_BURST::burst_isr () {
    // CanNOT read from global ADC interrupt register - otherwise interrupt is NOT CLEARED
    if ((LPC_ADC->ADSTAT & 0xFF00) != 0)
        // Overflow!
        error("ADSTAT: %x\n", LPC_ADC->ADSTAT);

    uint32_t chan = (LPC_ADC->ADGDR >> 24) & 0xF;
    switch (chan) {
        case 0:
            data[0] = (LPC_ADC->ADDR0 & 0x0000FFF0);
            break;
        case 1:
            data[1] = (LPC_ADC->ADDR1 & 0x0000FFF0);
            break;
        case 2:
            data[2] = (LPC_ADC->ADDR2 & 0x0000FFF0);
            break;
        case 4:
            data[3] = (LPC_ADC->ADDR4 & 0x0000FFF0);
            if (attached_) (*isr_pointer_)();
            break;
        default:
            error("Random channel interrupt: %d!\n",chan);
    }
}

void ADC_BURST::_burst_isr() {
    instance->burst_isr();
}

ADC_BURST::~ADC_BURST () {
    // Kill ADC
    LPC_ADC->ADINTEN = 0;
    LPC_SC->PCONP &= ~(1 << 12);
}

/**
 *  Decimator class to implement simple low-pass filtering on uC
 */

/**
 * Decimator constructor.
 * Constructor to zero circular decimation buffer and pointers.
 * As init state is zero accumulator is safe from underflow on subtraction.
 */
Decimator::Decimator (uint8_t order) {
    decimation_pointer_ = 0;                       // Initialise the buffer pointer
    decimation_order_ = (order > 5) ? 5: order;    // Limit the order to 5
    decimation_length_ = 1 << decimation_order_;
    // Clear the buffer
    for (uint8_t i=0; i<decimation_length_; i++) {
        decimation_buffer_[i] = 0;
    }
    accumulator_ = 0;
}

/**
 *  Data input function
 *  Write a new value into the decimator.
 *  Input is unsigned 16bits, max decimation length is 32 (5bits)
 *  so 32 bit accumulator is safe from overflow
 */
void Decimator::write (uint16_t in_sample) {
    // Remove oldest sample from accumulator
    accumulator_ -= decimation_buffer_[decimation_pointer_];
    // Write in the newest sample
    decimation_buffer_[decimation_pointer_] = in_sample;
    accumulator_ += in_sample;
    // Increment the pointer
    decimation_pointer_++;
    if (decimation_pointer_ >= decimation_length_)
        decimation_pointer_ = 0;
}

/**
 * Data output function
 * Read the decimated signal
 */
uint16_t Decimator::read() {
    // Just return the accumulator. Don't bother with any down scaling
    uint32_t output = accumulator_ >> decimation_order_;
    if ((accumulator_ & (decimation_length_>>1)) != 0)
        output++;
    return (uint16_t)output;
}