X-Git-Url: https://git.hcoop.net/clinton/Smoothieware.git/blobdiff_plain/507dd64d7adf3ef3fda6fe0472f1fcdc061f13e1..f7fd185d6004e6e3d2be1ba6f00d81c047f0fa18:/src/libs/Adc.cpp diff --git a/src/libs/Adc.cpp b/src/libs/Adc.cpp index 14d41087..c85d38c7 100644 --- a/src/libs/Adc.cpp +++ b/src/libs/Adc.cpp @@ -5,50 +5,138 @@ You should have received a copy of the GNU General Public License along with Smoothie. If not, see . */ -using namespace std; -#include +#include "Adc.h" #include "libs/nuts_bolts.h" -#include "libs/Module.h" #include "libs/Kernel.h" -#include "Adc.h" +#include "libs/Pin.h" #include "libs/ADC/adc.h" #include "libs/Pin.h" +#include "libs/Median.h" + +#include +#include + +#include "mbed.h" // This is an interface to the mbed.org ADC library you can find in libs/ADC/adc.h // TODO : Having the same name is confusing, should change that -Adc::Adc(){ - this->adc = new ADC(1000, 1); +Adc *Adc::instance; + +static void sample_isr(int chan, uint32_t value) +{ + Adc::instance->new_sample(chan, value); } +Adc::Adc() +{ + instance = this; + // ADC sample rate need to be fast enough to be able to read the enabled channels within the thermistor poll time + // even though ther maybe 32 samples we only need one new one within the polling time + const uint32_t sample_rate= 1000; // 1KHz sample rate + this->adc = new mbed::ADC(sample_rate, 8); + this->adc->append(sample_isr); +} + +/* +LPC176x ADC channels and pins + +Adc Channel Port Pin Pin Functions Associated PINSEL Register +AD0 P0.23 0-GPIO, 1-AD0[0], 2-I2SRX_CLK, 3-CAP3[0] 14,15 bits of PINSEL1 +AD1 P0.24 0-GPIO, 1-AD0[1], 2-I2SRX_WS, 3-CAP3[1] 16,17 bits of PINSEL1 +AD2 P0.25 0-GPIO, 1-AD0[2], 2-I2SRX_SDA, 3-TXD3 18,19 bits of PINSEL1 +AD3 P0.26 0-GPIO, 1-AD0[3], 2-AOUT, 3-RXD3 20,21 bits of PINSEL1 +AD4 P1.30 0-GPIO, 1-VBUS, 2- , 3-AD0[4] 28,29 bits of PINSEL3 +AD5 P1.31 0-GPIO, 1-SCK1, 2- , 3-AD0[5] 30,31 bits of PINSEL3 +AD6 P0.3 0-GPIO, 1-RXD0, 2-AD0[6], 3- 6,7 bits of PINSEL0 +AD7 P0.2 0-GPIO, 1-TXD0, 2-AD0[7], 3- 4,5 bits of PINSEL0 +*/ + // Enables ADC on a given pin -void Adc::enable_pin(Pin* pin){ +void Adc::enable_pin(Pin *pin) +{ PinName pin_name = this->_pin_to_pinname(pin); + int channel = adc->_pin_to_channel(pin_name); + memset(sample_buffers[channel], 0, sizeof(sample_buffers[0])); + this->adc->burst(1); - this->adc->setup(pin_name,1); - this->adc->interrupt_state(pin_name,1); + this->adc->setup(pin_name, 1); + this->adc->interrupt_state(pin_name, 1); +} + +// Keeps the last 8 values for each channel +// This is called in an ISR, so sample_buffers needs to be accessed atomically +void Adc::new_sample(int chan, uint32_t value) +{ + // Shuffle down and add new value to the end + if(chan < num_channels) { + memmove(&sample_buffers[chan][0], &sample_buffers[chan][1], sizeof(sample_buffers[0]) - sizeof(sample_buffers[0][0])); + sample_buffers[chan][num_samples - 1] = (value >> 4) & 0xFFF; // the 12 bit ADC reading + } } -// Read the last value ( burst mode ) on a given pin -unsigned int Adc::read(Pin* pin){ - return this->adc->read(this->_pin_to_pinname(pin)); +//#define USE_MEDIAN_FILTER +// Read the filtered value ( burst mode ) on a given pin +unsigned int Adc::read(Pin *pin) +{ + PinName p = this->_pin_to_pinname(pin); + int channel = adc->_pin_to_channel(p); + + uint16_t median_buffer[num_samples]; + // needs atomic access TODO maybe be able to use std::atomic here or some lockless mutex + __disable_irq(); + memcpy(median_buffer, sample_buffers[channel], sizeof(median_buffer)); + __enable_irq(); + +#ifdef USE_MEDIAN_FILTER + // returns the median value of the last 8 samples + return median_buffer[quick_median(median_buffer, num_samples)]; + +#elif defined(OVERSAMPLE) + // Oversample to get 2 extra bits of resolution + // weed out top and bottom worst values then oversample the rest + // put into a 4 element moving average and return the average of the last 4 oversampled readings + static uint16_t ave_buf[num_channels][4] = { {0} }; + std::sort(median_buffer, median_buffer + num_samples); + uint32_t sum = 0; + for (int i = num_samples / 4; i < (num_samples - (num_samples / 4)); ++i) { + sum += median_buffer[i]; + } + // this slows down the rate of change a little bit + ave_buf[channel][3]= ave_buf[channel][2]; + ave_buf[channel][2]= ave_buf[channel][1]; + ave_buf[channel][1]= ave_buf[channel][0]; + ave_buf[channel][0]= sum >> OVERSAMPLE; + return roundf((ave_buf[channel][0]+ave_buf[channel][1]+ave_buf[channel][2]+ave_buf[channel][3])/4.0F); + +#else + // sort the 8 readings and return the average of the middle 4 + std::sort(median_buffer, median_buffer + num_samples); + int sum = 0; + for (int i = num_samples / 4; i < (num_samples - (num_samples / 4)); ++i) { + sum += median_buffer[i]; + } + return sum / (num_samples / 2); + +#endif } // Convert a smoothie Pin into a mBed Pin -PinName Adc::_pin_to_pinname(Pin* pin){ - if( pin->port == LPC_GPIO0 && pin->pin == 23 ){ +PinName Adc::_pin_to_pinname(Pin *pin) +{ + if( pin->port == LPC_GPIO0 && pin->pin == 23 ) { return p15; - }else if( pin->port == LPC_GPIO0 && pin->pin == 24 ){ + } else if( pin->port == LPC_GPIO0 && pin->pin == 24 ) { return p16; - }else if( pin->port == LPC_GPIO0 && pin->pin == 25 ){ + } else if( pin->port == LPC_GPIO0 && pin->pin == 25 ) { return p17; - }else if( pin->port == LPC_GPIO0 && pin->pin == 26 ){ + } else if( pin->port == LPC_GPIO0 && pin->pin == 26 ) { return p18; - }else if( pin->port == LPC_GPIO1 && pin->pin == 30 ){ + } else if( pin->port == LPC_GPIO1 && pin->pin == 30 ) { return p19; - }else if( pin->port == LPC_GPIO1 && pin->pin == 31 ){ + } else if( pin->port == LPC_GPIO1 && pin->pin == 31 ) { return p20; - }else{ + } else { //TODO: Error return NC; }