blob: 7968094816691565c2c3377f137199cc99d5a6e7 [file] [log] [blame]
Brian Silvermanf92396c2013-09-12 20:13:13 -07001#include "analog.h"
brians0ab60bb2013-01-31 02:21:51 +00002
Brian Silverman74acd622013-10-26 14:47:14 -07003#include "LPC17xx.h"
Brian Silvermandb85c9a2013-11-02 14:38:43 -07004#include "FreeRTOS.h"
Austin Schuh63d0e9b2013-03-27 04:43:14 +00005
Brian Silvermandb85c9a2013-11-02 14:38:43 -07006static int discarded_samples[4];
7
8static uint16_t raw_analog(int channel) {
9 uint32_t value;
10 switch (channel) {
11 case 0:
12 value = ADC->ADDR0;
13 break;
14 case 1:
15 value = ADC->ADDR1;
16 break;
17 case 2:
18 value = ADC->ADDR2;
19 break;
20 case 3:
21 value = ADC->ADDR3;
22 break;
23 }
24
25 return (value >> 4) & 0xFFF;
26}
27
28void TIMER1_IRQHandler(void) {
29 TIM1->IR = 1 << 0; // clear channel 0 match
30
31 static const int kBadSampleThreshold = 175;
32 static const int kMaxBadSamples = 4;
33
34 static const uint32_t kBitShift = 16;
35 static const uint32_t kA =
36 (1.0 - 0.8408964152537146 /*0.5^0.25*/) * (1 << kBitShift) + 0.5;
37 for (int i = 0; i < 4; ++i) {
38 uint16_t current = raw_analog(i);
39 uint16_t average = averaged_values[i];
40 if ((current - average) < -kBadSampleThreshold ||
41 (current - average) > kBadSampleThreshold) {
42 ++discarded_samples[i];
43 if (discarded_samples[i] >= kMaxBadSamples) {
44 discarded_samples[i] = 0;
45 averaged_values[i] = current;
46 }
47 } else {
48 discarded_samples[i] = 0;
49 averaged_values[i] =
50 ((uint32_t)current * kA +
51 (uint32_t)average * ((1 << kBitShift) - kA)) >> kBitShift;
52 }
53 }
54}
Brian Silverman3e9464f2013-11-01 15:36:08 -070055
Brian Silverman6ad00b82013-03-27 19:02:38 -070056void analog_init(void) {
Brian Silverman6ad00b82013-03-27 19:02:38 -070057 SC->PCONP |= PCONP_PCAD;
brians0ab60bb2013-01-31 02:21:51 +000058
Brian Silvermandb85c9a2013-11-02 14:38:43 -070059 // Enable AD0.0, AD0.1, AD0.2, and AD0.3 (0.23 - 0.26).
Brian Silverman1ba46c72013-10-31 16:05:57 -070060 PINCON->PINSEL1 &= ~(3 << 14 | 3 << 16 | 3 << 18 | 3 << 20);
Brian Silverman74acd622013-10-26 14:47:14 -070061 PINCON->PINSEL1 |= 1 << 14 | 1 << 16 | 1 << 18 | 1 << 20;
Brian Silvermandb85c9a2013-11-02 14:38:43 -070062 PINCON->PINMODE1 &= ~(3 << 14 | 3 << 16 | 3 << 18 | 3 << 20);
63 PINCON->PINMODE1 |= 2 << 14 | 2 << 16 | 2 << 18 | 2 << 20;
Brian Silverman3e9464f2013-11-01 15:36:08 -070064
Brian Silverman74acd622013-10-26 14:47:14 -070065 ADC->ADCR = (1 << 0 | 1 << 1 | 1 << 2 | 1 << 3) /* enable all 4 */ |
Brian Silvermandb85c9a2013-11-02 14:38:43 -070066 79 << 8 /* takes 208us to scan through all 4 */ |
Brian Silverman74acd622013-10-26 14:47:14 -070067 1 << 16 /* enable burst mode */ |
68 1 << 21 /* turn on ADC */;
brians0ab60bb2013-01-31 02:21:51 +000069
Brian Silvermandb85c9a2013-11-02 14:38:43 -070070 // Set up the timer for the low-pass filter.
71 SC->PCONP |= 1 << 2;
72 TIM1->PR = (configCPU_CLOCK_HZ / 2000) - 1;
73 TIM1->TC = 0; // don't match the first time around
74 TIM1->MR0 = 1; // match every time it wraps
75 TIM1->MCR = 1 << 0 | 1 << 1; // interrupt and reset on match channel 0
76 // Priority 4 is higher than any FreeRTOS-managed stuff (ie USB), but lower
77 // than encoders etc.
78 NVIC_SetPriority(TIMER1_IRQn, 4);
79 NVIC_EnableIRQ(TIMER1_IRQn);
80 TIM1->TCR = 1; // enable it
brians0ab60bb2013-01-31 02:21:51 +000081}