tweaked detection to use photoresistor through an opamp

Dependents:   rgb_sensor_buffer

Fork of rgb_sensor by Milosch Meriac

Committer:
bridadan
Date:
Fri Mar 20 16:03:21 2015 +0000
Revision:
11:fea393d0d17a
Parent:
9:7bd80f4a965e
Tweaked sensor because photoresistor using inverted voltage (ran through an opamp)

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 9:7bd80f4a965e 148 sample = filter(sample);
meriac 9:7bd80f4a965e 149 if(m_adc_count>=RGB_SENSOR_IGNORE)
meriac 9:7bd80f4a965e 150 m_adc_aggregation[m_rgb_channel] += sample;
meriac 0:576e43bd193d 151
meriac 0:576e43bd193d 152 m_adc_count++;
meriac 9:7bd80f4a965e 153 if(m_adc_count>=(RGB_OVERSAMPLING+RGB_SENSOR_IGNORE))
meriac 0:576e43bd193d 154 {
meriac 0:576e43bd193d 155 m_adc_count=0;
meriac 0:576e43bd193d 156 m_rgb_channel++;
meriac 0:576e43bd193d 157
meriac 0:576e43bd193d 158 /* prepare LEDs for upcoming channel */
meriac 0:576e43bd193d 159 switch(m_rgb_channel)
meriac 0:576e43bd193d 160 {
meriac 0:576e43bd193d 161 case 1:
meriac 2:4545984e62b6 162 m_red = RGB_LED_ON;
meriac 0:576e43bd193d 163 break;
meriac 0:576e43bd193d 164
meriac 0:576e43bd193d 165 case 2:
meriac 2:4545984e62b6 166 m_red = !RGB_LED_ON;
meriac 2:4545984e62b6 167 m_green = RGB_LED_ON;
meriac 0:576e43bd193d 168 break;
meriac 0:576e43bd193d 169
meriac 0:576e43bd193d 170 case 3:
meriac 2:4545984e62b6 171 m_green = !RGB_LED_ON;
meriac 6:fc64a14a2f4a 172 m_blue = RGB_LED_ON;
meriac 0:576e43bd193d 173 break;
meriac 0:576e43bd193d 174
meriac 0:576e43bd193d 175 default:
meriac 6:fc64a14a2f4a 176 m_blue = !RGB_LED_ON;
meriac 6:fc64a14a2f4a 177 m_rgb_channel = 0;
meriac 6:fc64a14a2f4a 178
meriac 3:50e1ac3c56db 179 if(!m_callback)
meriac 3:50e1ac3c56db 180 m_done = true;
meriac 3:50e1ac3c56db 181 else
meriac 3:50e1ac3c56db 182 {
meriac 3:50e1ac3c56db 183 TRGB rgb;
meriac 3:50e1ac3c56db 184 convert(rgb);
meriac 3:50e1ac3c56db 185 m_done = !m_callback(rgb);
meriac 3:50e1ac3c56db 186 }
meriac 0:576e43bd193d 187 /* stop data aquisition */
meriac 3:50e1ac3c56db 188 if(m_done)
meriac 3:50e1ac3c56db 189 LPC_ADC->ADCR &= ~(1UL<<16);
meriac 4:0ffadc2caaf6 190 else
meriac 6:fc64a14a2f4a 191 {
meriac 6:fc64a14a2f4a 192 m_adc_filter_pos ^= 1;
meriac 4:0ffadc2caaf6 193 memset(&m_adc_aggregation, 0, sizeof(m_adc_aggregation));
meriac 6:fc64a14a2f4a 194 }
meriac 0:576e43bd193d 195 }
meriac 0:576e43bd193d 196 }
meriac 0:576e43bd193d 197 }
meriac 0:576e43bd193d 198 }
meriac 0:576e43bd193d 199 LPC_ADC->ADSTAT = status;
meriac 0:576e43bd193d 200 }
meriac 0:576e43bd193d 201
meriac 3:50e1ac3c56db 202 bool RGB_Sensor::capture(TRGB_Callback callback)
meriac 0:576e43bd193d 203 {
meriac 0:576e43bd193d 204 /* ignore mis-configurations */
meriac 0:576e43bd193d 205 if(m_adc_channel==(ADCName)NC)
meriac 0:576e43bd193d 206 return false;
meriac 0:576e43bd193d 207
meriac 3:50e1ac3c56db 208 m_callback = callback;
meriac 0:576e43bd193d 209 m_done = false;
meriac 6:fc64a14a2f4a 210 m_adc_filter_pos = m_adc_count = m_rgb_channel = 0;
meriac 0:576e43bd193d 211 memset((void*)&m_adc_aggregation, 0, sizeof(m_adc_aggregation));
meriac 5:1fed2b68e661 212 memset(&m_adc_filter, 0, sizeof(m_adc_filter));
meriac 5:1fed2b68e661 213
meriac 0:576e43bd193d 214 /* start ADC burst mode */
meriac 0:576e43bd193d 215 LPC_ADC->ADCR |= (1UL<<16);
meriac 0:576e43bd193d 216
meriac 0:576e43bd193d 217 return true;
meriac 0:576e43bd193d 218 }
meriac 0:576e43bd193d 219
meriac 0:576e43bd193d 220 bool RGB_Sensor::wait(void)
meriac 0:576e43bd193d 221 {
meriac 0:576e43bd193d 222 /* ignore mis-configurations */
meriac 0:576e43bd193d 223 if(m_adc_channel==(ADCName)NC)
meriac 0:576e43bd193d 224 return false;
meriac 0:576e43bd193d 225
meriac 0:576e43bd193d 226 while(!m_done)
meriac 0:576e43bd193d 227 __WFE();
bridadan 11:fea393d0d17a 228
meriac 0:576e43bd193d 229 return true;
meriac 0:576e43bd193d 230 }
meriac 0:576e43bd193d 231
meriac 3:50e1ac3c56db 232 void RGB_Sensor::convert(TRGB &rgb)
meriac 0:576e43bd193d 233 {
meriac 8:88acb970df76 234 int i, sample;
meriac 8:88acb970df76 235
meriac 0:576e43bd193d 236 /* correct "DC" offset by subdstracting
meriac 0:576e43bd193d 237 * environment light
meriac 0:576e43bd193d 238 */
meriac 8:88acb970df76 239 for(i=0; i<3; i++)
meriac 8:88acb970df76 240 {
bridadan 11:fea393d0d17a 241 // Invert this because ADC signal inverted (no pull up)
bridadan 11:fea393d0d17a 242 sample = m_adc_aggregation[i+1] - m_adc_aggregation[0];
meriac 8:88acb970df76 243 rgb.data[i] = (sample<0) ? 0 : sample;
meriac 8:88acb970df76 244 }
meriac 3:50e1ac3c56db 245 }
meriac 0:576e43bd193d 246
meriac 3:50e1ac3c56db 247 bool RGB_Sensor::capture(TRGB &rgb)
meriac 3:50e1ac3c56db 248 {
meriac 3:50e1ac3c56db 249 if(!(capture(NULL) && wait()))
meriac 3:50e1ac3c56db 250 return false;
meriac 3:50e1ac3c56db 251
meriac 3:50e1ac3c56db 252 convert(rgb);
meriac 0:576e43bd193d 253 return true;
meriac 0:576e43bd193d 254 }