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 07:21:51 2014 +0000
Revision:
2:4545984e62b6
Parent:
0:576e43bd193d
Child:
3:50e1ac3c56db
Configurable LED on-state

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 0:576e43bd193d 148 m_done = true;
meriac 0:576e43bd193d 149 /* stop data aquisition */
meriac 0:576e43bd193d 150 LPC_ADC->ADCR &= ~(1UL<<16);
meriac 0:576e43bd193d 151 }
meriac 0:576e43bd193d 152 }
meriac 0:576e43bd193d 153 }
meriac 0:576e43bd193d 154 }
meriac 0:576e43bd193d 155 LPC_ADC->ADSTAT = status;
meriac 0:576e43bd193d 156 }
meriac 0:576e43bd193d 157
meriac 0:576e43bd193d 158 bool RGB_Sensor::capture(void)
meriac 0:576e43bd193d 159 {
meriac 0:576e43bd193d 160 /* ignore mis-configurations */
meriac 0:576e43bd193d 161 if(m_adc_channel==(ADCName)NC)
meriac 0:576e43bd193d 162 return false;
meriac 0:576e43bd193d 163
meriac 0:576e43bd193d 164 m_done = false;
meriac 0:576e43bd193d 165 m_adc_count = m_rgb_channel = 0;
meriac 0:576e43bd193d 166 memset((void*)&m_adc_aggregation, 0, sizeof(m_adc_aggregation));
meriac 0:576e43bd193d 167 /* start ADC burst mode */
meriac 0:576e43bd193d 168 LPC_ADC->ADCR |= (1UL<<16);
meriac 0:576e43bd193d 169
meriac 0:576e43bd193d 170 return true;
meriac 0:576e43bd193d 171 }
meriac 0:576e43bd193d 172
meriac 0:576e43bd193d 173 bool RGB_Sensor::wait(void)
meriac 0:576e43bd193d 174 {
meriac 0:576e43bd193d 175 /* ignore mis-configurations */
meriac 0:576e43bd193d 176 if(m_adc_channel==(ADCName)NC)
meriac 0:576e43bd193d 177 return false;
meriac 0:576e43bd193d 178
meriac 0:576e43bd193d 179 while(!m_done)
meriac 0:576e43bd193d 180 __WFE();
meriac 0:576e43bd193d 181
meriac 0:576e43bd193d 182 return true;
meriac 0:576e43bd193d 183 }
meriac 0:576e43bd193d 184
meriac 0:576e43bd193d 185 bool RGB_Sensor::capture(TRGB &rgb)
meriac 0:576e43bd193d 186 {
meriac 0:576e43bd193d 187 if(!(capture() && wait()))
meriac 0:576e43bd193d 188 return false;
meriac 0:576e43bd193d 189
meriac 0:576e43bd193d 190 /* correct "DC" offset by subdstracting
meriac 0:576e43bd193d 191 * environment light
meriac 0:576e43bd193d 192 */
meriac 0:576e43bd193d 193 rgb.ch.red = m_adc_aggregation[1] - m_adc_aggregation[0];
meriac 0:576e43bd193d 194 rgb.ch.green = m_adc_aggregation[2] - m_adc_aggregation[0];
meriac 0:576e43bd193d 195 rgb.ch.blue = m_adc_aggregation[3] - m_adc_aggregation[0];
meriac 0:576e43bd193d 196
meriac 0:576e43bd193d 197 return true;
meriac 0:576e43bd193d 198 }