tweaked detection to use photoresistor through an opamp

Dependents:   rgb_sensor_buffer

Fork of rgb_sensor by Milosch Meriac

Committer:
meriac
Date:
Sat Jun 28 16:02:24 2014 +0000
Revision:
6:fc64a14a2f4a
Parent:
5:1fed2b68e661
Child:
8:88acb970df76
Fixed filtering

Who changed what in which revision?

UserRevisionLine numberNew contents of line
meriac 0:576e43bd193d 1 /* Discrete RGB color sensor
meriac 0:576e43bd193d 2 *
meriac 0:576e43bd193d 3 * - uses single-channel light-dependent resistor (via ADC)
meriac 0:576e43bd193d 4 * and a RGB LED.
meriac 0:576e43bd193d 5 * - compensates background light
meriac 0:576e43bd193d 6 *
meriac 0:576e43bd193d 7 * Copyright (c) 2014 ARM Limited
meriac 0:576e43bd193d 8 *
meriac 0:576e43bd193d 9 * Licensed under the Apache License, Version 2.0 (the "License");
meriac 0:576e43bd193d 10 * you may not use this file except in compliance with the License.
meriac 0:576e43bd193d 11 * You may obtain a copy of the License at
meriac 0:576e43bd193d 12 *
meriac 0:576e43bd193d 13 * http://www.apache.org/licenses/LICENSE-2.0
meriac 0:576e43bd193d 14 *
meriac 0:576e43bd193d 15 * Unless required by applicable law or agreed to in writing, software
meriac 0:576e43bd193d 16 * distributed under the License is distributed on an "AS IS" BASIS,
meriac 0:576e43bd193d 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
meriac 0:576e43bd193d 18 * See the License for the specific language governing permissions and
meriac 0:576e43bd193d 19 * limitations under the License.
meriac 0:576e43bd193d 20 */
meriac 0:576e43bd193d 21
meriac 0:576e43bd193d 22 #include <mbed.h>
meriac 0:576e43bd193d 23 #include <pinmap.h>
meriac 0:576e43bd193d 24 #include "rgb_sensor.h"
meriac 0:576e43bd193d 25
meriac 0:576e43bd193d 26 static const PinMap RGB_Sensor__PinMap_ADC[] = {
meriac 0:576e43bd193d 27 {P0_23, ADC0_0, 1},
meriac 0:576e43bd193d 28 {P0_24, ADC0_1, 1},
meriac 0:576e43bd193d 29 {P0_25, ADC0_2, 1},
meriac 0:576e43bd193d 30 {P0_26, ADC0_3, 1},
meriac 0:576e43bd193d 31 {P1_30, ADC0_4, 3},
meriac 0:576e43bd193d 32 {P1_31, ADC0_5, 3},
meriac 0:576e43bd193d 33 {P0_2, ADC0_7, 2},
meriac 0:576e43bd193d 34 {P0_3, ADC0_6, 2},
meriac 0:576e43bd193d 35 {NC, NC, 0}
meriac 0:576e43bd193d 36 };
meriac 0:576e43bd193d 37
meriac 0:576e43bd193d 38 DigitalOut g_dbg(LED1);
meriac 0:576e43bd193d 39
meriac 0:576e43bd193d 40 /* initialize globally */
meriac 0:576e43bd193d 41 RGB_Sensor* RGB_Sensor::m_global = NULL;
meriac 0:576e43bd193d 42
meriac 0:576e43bd193d 43 RGB_Sensor::RGB_Sensor(PinName red, PinName green, PinName blue, PinName adc)
meriac 0:576e43bd193d 44 :m_red(red), m_green(green), m_blue(blue)
meriac 0:576e43bd193d 45 {
meriac 0:576e43bd193d 46 uint32_t clkdiv;
meriac 0:576e43bd193d 47
meriac 0:576e43bd193d 48 m_done=true;
meriac 0:576e43bd193d 49
meriac 0:576e43bd193d 50 /* allow only one instance */
meriac 0:576e43bd193d 51 if(m_global)
meriac 0:576e43bd193d 52 {
meriac 0:576e43bd193d 53 m_adc_channel = (ADCName)NC;
meriac 0:576e43bd193d 54 return;
meriac 0:576e43bd193d 55 }
meriac 0:576e43bd193d 56
meriac 0:576e43bd193d 57 /* disable LED's */
meriac 2:4545984e62b6 58 m_red = !RGB_LED_ON;
meriac 2:4545984e62b6 59 m_green = !RGB_LED_ON;
meriac 2:4545984e62b6 60 m_blue = !RGB_LED_ON;
meriac 0:576e43bd193d 61
meriac 0:576e43bd193d 62 // enable ADC power
meriac 0:576e43bd193d 63 LPC_SC->PCONP |= (1<<12);
meriac 0:576e43bd193d 64 // set ADC clock to PCLK
meriac 0:576e43bd193d 65 LPC_SC->PCLKSEL0 = (LPC_SC->PCLKSEL0 & ~(0x3UL<<24)) | (0x1UL<<24);
meriac 0:576e43bd193d 66
meriac 0:576e43bd193d 67 // determine mapping
meriac 0:576e43bd193d 68 m_adc_channel = (ADCName)pinmap_peripheral(adc, RGB_Sensor__PinMap_ADC);
meriac 0:576e43bd193d 69 if (m_adc_channel == (ADCName)NC)
meriac 0:576e43bd193d 70 return;
meriac 0:576e43bd193d 71
meriac 0:576e43bd193d 72 // initialize ADC
meriac 0:576e43bd193d 73 clkdiv = ((SystemCoreClock+RGB_MAX_ADC_CLK-1)/RGB_MAX_ADC_CLK)-1;
meriac 0:576e43bd193d 74 LPC_ADC->ADCR = (1UL<<m_adc_channel) | (clkdiv<<8) | (1UL<<21);
meriac 0:576e43bd193d 75
meriac 0:576e43bd193d 76 // set up ADC IRQ
meriac 0:576e43bd193d 77 NVIC_SetVector(ADC_IRQn, (uint32_t)&__adc_irq);
meriac 0:576e43bd193d 78 LPC_ADC->ADINTEN = (1UL<<m_adc_channel);
meriac 0:576e43bd193d 79 NVIC_EnableIRQ(ADC_IRQn);
meriac 0:576e43bd193d 80
meriac 0:576e43bd193d 81 // propagate pin setting
meriac 0:576e43bd193d 82 pinmap_pinout(adc, RGB_Sensor__PinMap_ADC);
meriac 0:576e43bd193d 83
meriac 0:576e43bd193d 84 // remember this instance
meriac 0:576e43bd193d 85 m_global = this;
meriac 0:576e43bd193d 86 }
meriac 0:576e43bd193d 87
meriac 0:576e43bd193d 88 RGB_Sensor::~RGB_Sensor(void)
meriac 0:576e43bd193d 89 {
meriac 0:576e43bd193d 90 /* only deal with fully initialized objects */
meriac 0:576e43bd193d 91 if(m_adc_channel == (ADCName)NC)
meriac 0:576e43bd193d 92 return;
meriac 0:576e43bd193d 93 /* wait for completion */
meriac 0:576e43bd193d 94 wait();
meriac 0:576e43bd193d 95 /* reset global reference */
meriac 0:576e43bd193d 96 m_global = NULL;
meriac 0:576e43bd193d 97 /* turn off ADC */
meriac 0:576e43bd193d 98 LPC_ADC->ADINTEN = 0;
meriac 0:576e43bd193d 99 LPC_ADC->ADCR = 0;
meriac 0:576e43bd193d 100 LPC_SC->PCONP &= ~(1UL<<12);
meriac 0:576e43bd193d 101 }
meriac 0:576e43bd193d 102
meriac 0:576e43bd193d 103 void RGB_Sensor::__adc_irq(void)
meriac 0:576e43bd193d 104 {
meriac 0:576e43bd193d 105 if(m_global)
meriac 0:576e43bd193d 106 m_global->adc_irq();
meriac 0:576e43bd193d 107 }
meriac 0:576e43bd193d 108
meriac 5:1fed2b68e661 109 int RGB_Sensor::filter(int sample)
meriac 5:1fed2b68e661 110 {
meriac 5:1fed2b68e661 111 int a,b,x,y,z;
meriac 6:fc64a14a2f4a 112
meriac 5:1fed2b68e661 113 /* get the two previous samples */
meriac 5:1fed2b68e661 114 a = m_adc_filter[m_rgb_channel][0];
meriac 5:1fed2b68e661 115 b = m_adc_filter[m_rgb_channel][1];
meriac 5:1fed2b68e661 116
meriac 5:1fed2b68e661 117 /* calculate node distances in triplet */
meriac 5:1fed2b68e661 118 x = abs(a-sample);
meriac 5:1fed2b68e661 119 y = abs(b-sample);
meriac 5:1fed2b68e661 120 z = abs(a-b);
meriac 5:1fed2b68e661 121
meriac 5:1fed2b68e661 122 /* remember current sample */
meriac 5:1fed2b68e661 123 m_adc_filter[m_rgb_channel][m_adc_filter_pos] = sample;
meriac 5:1fed2b68e661 124
meriac 5:1fed2b68e661 125 /* choose edge with shortest distance and
meriac 5:1fed2b68e661 126 * return average of the two edge nodes */
meriac 5:1fed2b68e661 127 if((x<=y) && (x<=z))
meriac 5:1fed2b68e661 128 return (a+sample)/2;
meriac 5:1fed2b68e661 129 if((y<=x) && (y<=z))
meriac 5:1fed2b68e661 130 return (b+sample)/2;
meriac 5:1fed2b68e661 131 return (a+b)/2;
meriac 5:1fed2b68e661 132 }
meriac 5:1fed2b68e661 133
meriac 0:576e43bd193d 134 void RGB_Sensor::adc_irq(void)
meriac 0:576e43bd193d 135 {
meriac 6:fc64a14a2f4a 136 int sample;
meriac 6:fc64a14a2f4a 137 uint32_t status;
meriac 0:576e43bd193d 138
meriac 0:576e43bd193d 139 status = LPC_ADC->ADSTAT;
meriac 0:576e43bd193d 140 if(status & (1UL<<m_adc_channel))
meriac 0:576e43bd193d 141 {
meriac 0:576e43bd193d 142 /* always read sample to acknowledge IRQ */
meriac 0:576e43bd193d 143 sample = (((&LPC_ADC->ADDR0)[m_adc_channel])>>4) & 0xFFF;
meriac 0:576e43bd193d 144
meriac 0:576e43bd193d 145 if(!m_done)
meriac 0:576e43bd193d 146 {
meriac 5:1fed2b68e661 147 /* filter value to remove ADC noise/conversion errors */
meriac 5:1fed2b68e661 148 m_adc_aggregation[m_rgb_channel] += filter(sample);
meriac 0:576e43bd193d 149
meriac 0:576e43bd193d 150 m_adc_count++;
meriac 0:576e43bd193d 151 if(m_adc_count>=RGB_OVERSAMPLING)
meriac 0:576e43bd193d 152 {
meriac 0:576e43bd193d 153 m_adc_count=0;
meriac 0:576e43bd193d 154 m_rgb_channel++;
meriac 0:576e43bd193d 155
meriac 0:576e43bd193d 156 /* prepare LEDs for upcoming channel */
meriac 0:576e43bd193d 157 switch(m_rgb_channel)
meriac 0:576e43bd193d 158 {
meriac 0:576e43bd193d 159 case 1:
meriac 2:4545984e62b6 160 m_red = RGB_LED_ON;
meriac 0:576e43bd193d 161 break;
meriac 0:576e43bd193d 162
meriac 0:576e43bd193d 163 case 2:
meriac 2:4545984e62b6 164 m_red = !RGB_LED_ON;
meriac 2:4545984e62b6 165 m_green = RGB_LED_ON;
meriac 0:576e43bd193d 166 break;
meriac 0:576e43bd193d 167
meriac 0:576e43bd193d 168 case 3:
meriac 2:4545984e62b6 169 m_green = !RGB_LED_ON;
meriac 6:fc64a14a2f4a 170 m_blue = RGB_LED_ON;
meriac 0:576e43bd193d 171 break;
meriac 0:576e43bd193d 172
meriac 0:576e43bd193d 173 default:
meriac 6:fc64a14a2f4a 174 m_blue = !RGB_LED_ON;
meriac 6:fc64a14a2f4a 175 m_rgb_channel = 0;
meriac 6:fc64a14a2f4a 176
meriac 3:50e1ac3c56db 177 if(!m_callback)
meriac 3:50e1ac3c56db 178 m_done = true;
meriac 3:50e1ac3c56db 179 else
meriac 3:50e1ac3c56db 180 {
meriac 3:50e1ac3c56db 181 TRGB rgb;
meriac 3:50e1ac3c56db 182 convert(rgb);
meriac 3:50e1ac3c56db 183 m_done = !m_callback(rgb);
meriac 3:50e1ac3c56db 184 }
meriac 0:576e43bd193d 185 /* stop data aquisition */
meriac 3:50e1ac3c56db 186 if(m_done)
meriac 3:50e1ac3c56db 187 LPC_ADC->ADCR &= ~(1UL<<16);
meriac 4:0ffadc2caaf6 188 else
meriac 6:fc64a14a2f4a 189 {
meriac 6:fc64a14a2f4a 190 m_adc_filter_pos ^= 1;
meriac 4:0ffadc2caaf6 191 memset(&m_adc_aggregation, 0, sizeof(m_adc_aggregation));
meriac 6:fc64a14a2f4a 192 }
meriac 0:576e43bd193d 193 }
meriac 0:576e43bd193d 194 }
meriac 0:576e43bd193d 195 }
meriac 0:576e43bd193d 196 }
meriac 0:576e43bd193d 197 LPC_ADC->ADSTAT = status;
meriac 0:576e43bd193d 198 }
meriac 0:576e43bd193d 199
meriac 3:50e1ac3c56db 200 bool RGB_Sensor::capture(TRGB_Callback callback)
meriac 0:576e43bd193d 201 {
meriac 0:576e43bd193d 202 /* ignore mis-configurations */
meriac 0:576e43bd193d 203 if(m_adc_channel==(ADCName)NC)
meriac 0:576e43bd193d 204 return false;
meriac 0:576e43bd193d 205
meriac 3:50e1ac3c56db 206 m_callback = callback;
meriac 0:576e43bd193d 207 m_done = false;
meriac 6:fc64a14a2f4a 208 m_adc_filter_pos = m_adc_count = m_rgb_channel = 0;
meriac 0:576e43bd193d 209 memset((void*)&m_adc_aggregation, 0, sizeof(m_adc_aggregation));
meriac 5:1fed2b68e661 210 memset(&m_adc_filter, 0, sizeof(m_adc_filter));
meriac 5:1fed2b68e661 211
meriac 0:576e43bd193d 212 /* start ADC burst mode */
meriac 0:576e43bd193d 213 LPC_ADC->ADCR |= (1UL<<16);
meriac 0:576e43bd193d 214
meriac 0:576e43bd193d 215 return true;
meriac 0:576e43bd193d 216 }
meriac 0:576e43bd193d 217
meriac 0:576e43bd193d 218 bool RGB_Sensor::wait(void)
meriac 0:576e43bd193d 219 {
meriac 0:576e43bd193d 220 /* ignore mis-configurations */
meriac 0:576e43bd193d 221 if(m_adc_channel==(ADCName)NC)
meriac 0:576e43bd193d 222 return false;
meriac 0:576e43bd193d 223
meriac 0:576e43bd193d 224 while(!m_done)
meriac 0:576e43bd193d 225 __WFE();
meriac 0:576e43bd193d 226
meriac 0:576e43bd193d 227 return true;
meriac 0:576e43bd193d 228 }
meriac 0:576e43bd193d 229
meriac 3:50e1ac3c56db 230 void RGB_Sensor::convert(TRGB &rgb)
meriac 0:576e43bd193d 231 {
meriac 0:576e43bd193d 232 /* correct "DC" offset by subdstracting
meriac 0:576e43bd193d 233 * environment light
meriac 0:576e43bd193d 234 */
meriac 0:576e43bd193d 235 rgb.ch.red = m_adc_aggregation[1] - m_adc_aggregation[0];
meriac 0:576e43bd193d 236 rgb.ch.green = m_adc_aggregation[2] - m_adc_aggregation[0];
meriac 0:576e43bd193d 237 rgb.ch.blue = m_adc_aggregation[3] - m_adc_aggregation[0];
meriac 3:50e1ac3c56db 238 }
meriac 0:576e43bd193d 239
meriac 3:50e1ac3c56db 240 bool RGB_Sensor::capture(TRGB &rgb)
meriac 3:50e1ac3c56db 241 {
meriac 3:50e1ac3c56db 242 if(!(capture(NULL) && wait()))
meriac 3:50e1ac3c56db 243 return false;
meriac 3:50e1ac3c56db 244
meriac 3:50e1ac3c56db 245 convert(rgb);
meriac 0:576e43bd193d 246 return true;
meriac 0:576e43bd193d 247 }