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

Revision:
0:03e8a03052c9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/daq.cpp	Fri Aug 27 15:20:30 2010 +0000
@@ -0,0 +1,144 @@
+#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;
+}
\ No newline at end of file