Merge branch 'feature/e-endstop' into merge-abc-with-homing
[clinton/Smoothieware.git] / src / libs / Adc.cpp
CommitLineData
7b49793d 1/*
3c132bd0
AW
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.
7b49793d 5 You should have received a copy of the GNU General Public License along with Smoothie. If not, see <http://www.gnu.org/licenses/>.
3c132bd0
AW
6*/
7
7af0714f 8#include "Adc.h"
3c132bd0 9#include "libs/nuts_bolts.h"
3c132bd0 10#include "libs/Kernel.h"
7af0714f 11#include "libs/Pin.h"
3c132bd0
AW
12#include "libs/ADC/adc.h"
13#include "libs/Pin.h"
232593a2 14#include "libs/Median.h"
3c132bd0 15
232593a2
JM
16#include <cstring>
17#include <algorithm>
7af0714f 18
3fa4cf37
JM
19#include "mbed.h"
20
93694d6b 21// This is an interface to the mbed.org ADC library you can find in libs/ADC/adc.h
d337942a 22// TODO : Having the same name is confusing, should change that
93694d6b 23
232593a2
JM
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;
c0c44ac0
JM
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);
232593a2 38 this->adc->append(sample_isr);
3c132bd0
AW
39}
40
232593a2
JM
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
93694d6b 55// Enables ADC on a given pin
232593a2
JM
56void Adc::enable_pin(Pin *pin)
57{
3c132bd0 58 PinName pin_name = this->_pin_to_pinname(pin);
232593a2
JM
59 int channel = adc->_pin_to_channel(pin_name);
60 memset(sample_buffers[channel], 0, sizeof(sample_buffers[0]));
61
3c132bd0 62 this->adc->burst(1);
232593a2
JM
63 this->adc->setup(pin_name, 1);
64 this->adc->interrupt_state(pin_name, 1);
3c132bd0
AW
65}
66
232593a2
JM
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];
3fa4cf37 86 // needs atomic access TODO maybe be able to use std::atomic here or some lockless mutex
232593a2
JM
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
c0c44ac0
JM
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
5ec4700e 99 static uint16_t ave_buf[num_channels][4] = { {0} };
c0c44ac0
JM
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;
5ec4700e 110 return roundf((ave_buf[channel][0]+ave_buf[channel][1]+ave_buf[channel][2]+ave_buf[channel][3])/4.0F);
c0c44ac0 111
232593a2
JM
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);
c0c44ac0 120
232593a2 121#endif
3c132bd0
AW
122}
123
93694d6b 124// Convert a smoothie Pin into a mBed Pin
232593a2
JM
125PinName Adc::_pin_to_pinname(Pin *pin)
126{
127 if( pin->port == LPC_GPIO0 && pin->pin == 23 ) {
3c132bd0 128 return p15;
232593a2 129 } else if( pin->port == LPC_GPIO0 && pin->pin == 24 ) {
3c132bd0 130 return p16;
232593a2 131 } else if( pin->port == LPC_GPIO0 && pin->pin == 25 ) {
3c132bd0 132 return p17;
232593a2 133 } else if( pin->port == LPC_GPIO0 && pin->pin == 26 ) {
3c132bd0 134 return p18;
232593a2 135 } else if( pin->port == LPC_GPIO1 && pin->pin == 30 ) {
3c132bd0 136 return p19;
232593a2 137 } else if( pin->port == LPC_GPIO1 && pin->pin == 31 ) {
3c132bd0 138 return p20;
232593a2 139 } else {
7b49793d 140 //TODO: Error
69735c09 141 return NC;
3c132bd0
AW
142 }
143}
144