![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
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.
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; }