remove SPI class from libs/spi as everything now uses mbed::spi
[clinton/Smoothieware.git] / src / libs / Adc.cpp
... / ...
CommitLineData
1/*
2 This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl).
3 Smoothie is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
4 Smoothie is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
5 You should have received a copy of the GNU General Public License along with Smoothie. If not, see <http://www.gnu.org/licenses/>.
6*/
7
8#include "Adc.h"
9#include "libs/nuts_bolts.h"
10#include "libs/Kernel.h"
11#include "libs/Pin.h"
12#include "libs/ADC/adc.h"
13#include "libs/Pin.h"
14#include "libs/Median.h"
15
16#include <cstring>
17#include <algorithm>
18
19#include "mbed.h"
20
21// This is an interface to the mbed.org ADC library you can find in libs/ADC/adc.h
22// TODO : Having the same name is confusing, should change that
23
24Adc *Adc::instance;
25
26static void sample_isr(int chan, uint32_t value)
27{
28 Adc::instance->new_sample(chan, value);
29}
30
31Adc::Adc()
32{
33 instance = this;
34 // ADC sample rate need to be fast enough to be able to read the enabled channels within the thermistor poll time
35 // even though ther maybe 32 samples we only need one new one within the polling time
36 const uint32_t sample_rate= 1000; // 1KHz sample rate
37 this->adc = new mbed::ADC(sample_rate, 8);
38 this->adc->append(sample_isr);
39}
40
41/*
42LPC176x ADC channels and pins
43
44Adc Channel Port Pin Pin Functions Associated PINSEL Register
45AD0 P0.23 0-GPIO, 1-AD0[0], 2-I2SRX_CLK, 3-CAP3[0] 14,15 bits of PINSEL1
46AD1 P0.24 0-GPIO, 1-AD0[1], 2-I2SRX_WS, 3-CAP3[1] 16,17 bits of PINSEL1
47AD2 P0.25 0-GPIO, 1-AD0[2], 2-I2SRX_SDA, 3-TXD3 18,19 bits of PINSEL1
48AD3 P0.26 0-GPIO, 1-AD0[3], 2-AOUT, 3-RXD3 20,21 bits of PINSEL1
49AD4 P1.30 0-GPIO, 1-VBUS, 2- , 3-AD0[4] 28,29 bits of PINSEL3
50AD5 P1.31 0-GPIO, 1-SCK1, 2- , 3-AD0[5] 30,31 bits of PINSEL3
51AD6 P0.3 0-GPIO, 1-RXD0, 2-AD0[6], 3- 6,7 bits of PINSEL0
52AD7 P0.2 0-GPIO, 1-TXD0, 2-AD0[7], 3- 4,5 bits of PINSEL0
53*/
54
55// Enables ADC on a given pin
56void Adc::enable_pin(Pin *pin)
57{
58 PinName pin_name = this->_pin_to_pinname(pin);
59 int channel = adc->_pin_to_channel(pin_name);
60 memset(sample_buffers[channel], 0, sizeof(sample_buffers[0]));
61
62 this->adc->burst(1);
63 this->adc->setup(pin_name, 1);
64 this->adc->interrupt_state(pin_name, 1);
65}
66
67// Keeps the last 8 values for each channel
68// This is called in an ISR, so sample_buffers needs to be accessed atomically
69void Adc::new_sample(int chan, uint32_t value)
70{
71 // Shuffle down and add new value to the end
72 if(chan < num_channels) {
73 memmove(&sample_buffers[chan][0], &sample_buffers[chan][1], sizeof(sample_buffers[0]) - sizeof(sample_buffers[0][0]));
74 sample_buffers[chan][num_samples - 1] = (value >> 4) & 0xFFF; // the 12 bit ADC reading
75 }
76}
77
78//#define USE_MEDIAN_FILTER
79// Read the filtered value ( burst mode ) on a given pin
80unsigned int Adc::read(Pin *pin)
81{
82 PinName p = this->_pin_to_pinname(pin);
83 int channel = adc->_pin_to_channel(p);
84
85 uint16_t median_buffer[num_samples];
86 // needs atomic access TODO maybe be able to use std::atomic here or some lockless mutex
87 __disable_irq();
88 memcpy(median_buffer, sample_buffers[channel], sizeof(median_buffer));
89 __enable_irq();
90
91#ifdef USE_MEDIAN_FILTER
92 // returns the median value of the last 8 samples
93 return median_buffer[quick_median(median_buffer, num_samples)];
94
95#elif defined(OVERSAMPLE)
96 // Oversample to get 2 extra bits of resolution
97 // weed out top and bottom worst values then oversample the rest
98 // put into a 4 element moving average and return the average of the last 4 oversampled readings
99 static uint16_t ave_buf[num_channels][4] = { {0} };
100 std::sort(median_buffer, median_buffer + num_samples);
101 uint32_t sum = 0;
102 for (int i = num_samples / 4; i < (num_samples - (num_samples / 4)); ++i) {
103 sum += median_buffer[i];
104 }
105 // this slows down the rate of change a little bit
106 ave_buf[channel][3]= ave_buf[channel][2];
107 ave_buf[channel][2]= ave_buf[channel][1];
108 ave_buf[channel][1]= ave_buf[channel][0];
109 ave_buf[channel][0]= sum >> OVERSAMPLE;
110 return roundf((ave_buf[channel][0]+ave_buf[channel][1]+ave_buf[channel][2]+ave_buf[channel][3])/4.0F);
111
112#else
113 // sort the 8 readings and return the average of the middle 4
114 std::sort(median_buffer, median_buffer + num_samples);
115 int sum = 0;
116 for (int i = num_samples / 4; i < (num_samples - (num_samples / 4)); ++i) {
117 sum += median_buffer[i];
118 }
119 return sum / (num_samples / 2);
120
121#endif
122}
123
124// Convert a smoothie Pin into a mBed Pin
125PinName Adc::_pin_to_pinname(Pin *pin)
126{
127 if( pin->port == LPC_GPIO0 && pin->pin == 23 ) {
128 return p15;
129 } else if( pin->port == LPC_GPIO0 && pin->pin == 24 ) {
130 return p16;
131 } else if( pin->port == LPC_GPIO0 && pin->pin == 25 ) {
132 return p17;
133 } else if( pin->port == LPC_GPIO0 && pin->pin == 26 ) {
134 return p18;
135 } else if( pin->port == LPC_GPIO1 && pin->pin == 30 ) {
136 return p19;
137 } else if( pin->port == LPC_GPIO1 && pin->pin == 31 ) {
138 return p20;
139 } else {
140 //TODO: Error
141 return NC;
142 }
143}
144