Discrete RGB colour sensor using a colour LED flashing at high speed and a monochrome LDR (light dependent resistor) for detecting the colour via ADC conversion. The library implements interrupt driven ADC conversion at high speed (370 RGB readings per second, 128 times oversampling per channelfor noise reduction). The detection can optionally run in background.

Dependents:   rgb_sensor_buffer discrete_rgb_color_sensor_example

Committer:
meriac
Date:
Fri Jun 27 11:36:15 2014 +0000
Revision:
3:50e1ac3c56db
Parent:
2:4545984e62b6
Child:
4:0ffadc2caaf6
Added callback support for asynchronous case

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 0:576e43bd193d 109 void RGB_Sensor::adc_irq(void)
meriac 0:576e43bd193d 110 {
meriac 0:576e43bd193d 111 uint32_t sample, status;
meriac 0:576e43bd193d 112
meriac 0:576e43bd193d 113 status = LPC_ADC->ADSTAT;
meriac 0:576e43bd193d 114 if(status & (1UL<<m_adc_channel))
meriac 0:576e43bd193d 115 {
meriac 0:576e43bd193d 116 /* always read sample to acknowledge IRQ */
meriac 0:576e43bd193d 117 sample = (((&LPC_ADC->ADDR0)[m_adc_channel])>>4) & 0xFFF;
meriac 0:576e43bd193d 118
meriac 0:576e43bd193d 119 if(!m_done)
meriac 0:576e43bd193d 120 {
meriac 0:576e43bd193d 121 m_adc_aggregation[m_rgb_channel] += sample;
meriac 0:576e43bd193d 122
meriac 0:576e43bd193d 123 m_adc_count++;
meriac 0:576e43bd193d 124 if(m_adc_count>=RGB_OVERSAMPLING)
meriac 0:576e43bd193d 125 {
meriac 0:576e43bd193d 126 m_adc_count=0;
meriac 0:576e43bd193d 127 m_rgb_channel++;
meriac 0:576e43bd193d 128
meriac 0:576e43bd193d 129 /* prepare LEDs for upcoming channel */
meriac 0:576e43bd193d 130 switch(m_rgb_channel)
meriac 0:576e43bd193d 131 {
meriac 0:576e43bd193d 132 case 1:
meriac 2:4545984e62b6 133 m_red = RGB_LED_ON;
meriac 0:576e43bd193d 134 break;
meriac 0:576e43bd193d 135
meriac 0:576e43bd193d 136 case 2:
meriac 2:4545984e62b6 137 m_red = !RGB_LED_ON;
meriac 2:4545984e62b6 138 m_green = RGB_LED_ON;
meriac 0:576e43bd193d 139 break;
meriac 0:576e43bd193d 140
meriac 0:576e43bd193d 141 case 3:
meriac 2:4545984e62b6 142 m_green = !RGB_LED_ON;
meriac 2:4545984e62b6 143 m_blue= RGB_LED_ON;
meriac 0:576e43bd193d 144 break;
meriac 0:576e43bd193d 145
meriac 0:576e43bd193d 146 default:
meriac 2:4545984e62b6 147 m_blue= !RGB_LED_ON;
meriac 3:50e1ac3c56db 148 if(!m_callback)
meriac 3:50e1ac3c56db 149 m_done = true;
meriac 3:50e1ac3c56db 150 else
meriac 3:50e1ac3c56db 151 {
meriac 3:50e1ac3c56db 152 TRGB rgb;
meriac 3:50e1ac3c56db 153 convert(rgb);
meriac 3:50e1ac3c56db 154 m_done = !m_callback(rgb);
meriac 3:50e1ac3c56db 155 m_rgb_channel = 0;
meriac 3:50e1ac3c56db 156 }
meriac 0:576e43bd193d 157 /* stop data aquisition */
meriac 3:50e1ac3c56db 158 if(m_done)
meriac 3:50e1ac3c56db 159 LPC_ADC->ADCR &= ~(1UL<<16);
meriac 0:576e43bd193d 160 }
meriac 0:576e43bd193d 161 }
meriac 0:576e43bd193d 162 }
meriac 0:576e43bd193d 163 }
meriac 0:576e43bd193d 164 LPC_ADC->ADSTAT = status;
meriac 0:576e43bd193d 165 }
meriac 0:576e43bd193d 166
meriac 3:50e1ac3c56db 167 bool RGB_Sensor::capture(TRGB_Callback callback)
meriac 0:576e43bd193d 168 {
meriac 0:576e43bd193d 169 /* ignore mis-configurations */
meriac 0:576e43bd193d 170 if(m_adc_channel==(ADCName)NC)
meriac 0:576e43bd193d 171 return false;
meriac 0:576e43bd193d 172
meriac 3:50e1ac3c56db 173 m_callback = callback;
meriac 0:576e43bd193d 174 m_done = false;
meriac 0:576e43bd193d 175 m_adc_count = m_rgb_channel = 0;
meriac 0:576e43bd193d 176 memset((void*)&m_adc_aggregation, 0, sizeof(m_adc_aggregation));
meriac 0:576e43bd193d 177 /* start ADC burst mode */
meriac 0:576e43bd193d 178 LPC_ADC->ADCR |= (1UL<<16);
meriac 0:576e43bd193d 179
meriac 0:576e43bd193d 180 return true;
meriac 0:576e43bd193d 181 }
meriac 0:576e43bd193d 182
meriac 0:576e43bd193d 183 bool RGB_Sensor::wait(void)
meriac 0:576e43bd193d 184 {
meriac 0:576e43bd193d 185 /* ignore mis-configurations */
meriac 0:576e43bd193d 186 if(m_adc_channel==(ADCName)NC)
meriac 0:576e43bd193d 187 return false;
meriac 0:576e43bd193d 188
meriac 0:576e43bd193d 189 while(!m_done)
meriac 0:576e43bd193d 190 __WFE();
meriac 0:576e43bd193d 191
meriac 0:576e43bd193d 192 return true;
meriac 0:576e43bd193d 193 }
meriac 0:576e43bd193d 194
meriac 3:50e1ac3c56db 195 void RGB_Sensor::convert(TRGB &rgb)
meriac 0:576e43bd193d 196 {
meriac 0:576e43bd193d 197 /* correct "DC" offset by subdstracting
meriac 0:576e43bd193d 198 * environment light
meriac 0:576e43bd193d 199 */
meriac 0:576e43bd193d 200 rgb.ch.red = m_adc_aggregation[1] - m_adc_aggregation[0];
meriac 0:576e43bd193d 201 rgb.ch.green = m_adc_aggregation[2] - m_adc_aggregation[0];
meriac 0:576e43bd193d 202 rgb.ch.blue = m_adc_aggregation[3] - m_adc_aggregation[0];
meriac 3:50e1ac3c56db 203 }
meriac 0:576e43bd193d 204
meriac 3:50e1ac3c56db 205 bool RGB_Sensor::capture(TRGB &rgb)
meriac 3:50e1ac3c56db 206 {
meriac 3:50e1ac3c56db 207 if(!(capture(NULL) && wait()))
meriac 3:50e1ac3c56db 208 return false;
meriac 3:50e1ac3c56db 209
meriac 3:50e1ac3c56db 210 convert(rgb);
meriac 0:576e43bd193d 211 return true;
meriac 0:576e43bd193d 212 }