Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: rgb_sensor_buffer discrete_rgb_color_sensor_example
rgb_sensor.cpp
- Committer:
- meriac
- Date:
- 2014-06-27
- Revision:
- 4:0ffadc2caaf6
- Parent:
- 3:50e1ac3c56db
- Child:
- 5:1fed2b68e661
File content as of revision 4:0ffadc2caaf6:
/* Discrete RGB color sensor
*
* - uses single-channel light-dependent resistor (via ADC)
* and a RGB LED.
* - compensates background light
*
* Copyright (c) 2014 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <mbed.h>
#include <pinmap.h>
#include "rgb_sensor.h"
static const PinMap RGB_Sensor__PinMap_ADC[] = {
{P0_23, ADC0_0, 1},
{P0_24, ADC0_1, 1},
{P0_25, ADC0_2, 1},
{P0_26, ADC0_3, 1},
{P1_30, ADC0_4, 3},
{P1_31, ADC0_5, 3},
{P0_2, ADC0_7, 2},
{P0_3, ADC0_6, 2},
{NC, NC, 0}
};
DigitalOut g_dbg(LED1);
/* initialize globally */
RGB_Sensor* RGB_Sensor::m_global = NULL;
RGB_Sensor::RGB_Sensor(PinName red, PinName green, PinName blue, PinName adc)
:m_red(red), m_green(green), m_blue(blue)
{
uint32_t clkdiv;
m_done=true;
/* allow only one instance */
if(m_global)
{
m_adc_channel = (ADCName)NC;
return;
}
/* disable LED's */
m_red = !RGB_LED_ON;
m_green = !RGB_LED_ON;
m_blue = !RGB_LED_ON;
// enable ADC power
LPC_SC->PCONP |= (1<<12);
// set ADC clock to PCLK
LPC_SC->PCLKSEL0 = (LPC_SC->PCLKSEL0 & ~(0x3UL<<24)) | (0x1UL<<24);
// determine mapping
m_adc_channel = (ADCName)pinmap_peripheral(adc, RGB_Sensor__PinMap_ADC);
if (m_adc_channel == (ADCName)NC)
return;
// initialize ADC
clkdiv = ((SystemCoreClock+RGB_MAX_ADC_CLK-1)/RGB_MAX_ADC_CLK)-1;
LPC_ADC->ADCR = (1UL<<m_adc_channel) | (clkdiv<<8) | (1UL<<21);
// set up ADC IRQ
NVIC_SetVector(ADC_IRQn, (uint32_t)&__adc_irq);
LPC_ADC->ADINTEN = (1UL<<m_adc_channel);
NVIC_EnableIRQ(ADC_IRQn);
// propagate pin setting
pinmap_pinout(adc, RGB_Sensor__PinMap_ADC);
// remember this instance
m_global = this;
}
RGB_Sensor::~RGB_Sensor(void)
{
/* only deal with fully initialized objects */
if(m_adc_channel == (ADCName)NC)
return;
/* wait for completion */
wait();
/* reset global reference */
m_global = NULL;
/* turn off ADC */
LPC_ADC->ADINTEN = 0;
LPC_ADC->ADCR = 0;
LPC_SC->PCONP &= ~(1UL<<12);
}
void RGB_Sensor::__adc_irq(void)
{
if(m_global)
m_global->adc_irq();
}
void RGB_Sensor::adc_irq(void)
{
uint32_t sample, status;
status = LPC_ADC->ADSTAT;
if(status & (1UL<<m_adc_channel))
{
/* always read sample to acknowledge IRQ */
sample = (((&LPC_ADC->ADDR0)[m_adc_channel])>>4) & 0xFFF;
if(!m_done)
{
m_adc_aggregation[m_rgb_channel] += sample;
m_adc_count++;
if(m_adc_count>=RGB_OVERSAMPLING)
{
m_adc_count=0;
m_rgb_channel++;
/* prepare LEDs for upcoming channel */
switch(m_rgb_channel)
{
case 1:
m_red = RGB_LED_ON;
break;
case 2:
m_red = !RGB_LED_ON;
m_green = RGB_LED_ON;
break;
case 3:
m_green = !RGB_LED_ON;
m_blue= RGB_LED_ON;
break;
default:
m_blue= !RGB_LED_ON;
if(!m_callback)
m_done = true;
else
{
TRGB rgb;
convert(rgb);
m_done = !m_callback(rgb);
m_rgb_channel = 0;
}
/* stop data aquisition */
if(m_done)
LPC_ADC->ADCR &= ~(1UL<<16);
else
memset(&m_adc_aggregation, 0, sizeof(m_adc_aggregation));
}
}
}
}
LPC_ADC->ADSTAT = status;
}
bool RGB_Sensor::capture(TRGB_Callback callback)
{
/* ignore mis-configurations */
if(m_adc_channel==(ADCName)NC)
return false;
m_callback = callback;
m_done = false;
m_adc_count = m_rgb_channel = 0;
memset((void*)&m_adc_aggregation, 0, sizeof(m_adc_aggregation));
/* start ADC burst mode */
LPC_ADC->ADCR |= (1UL<<16);
return true;
}
bool RGB_Sensor::wait(void)
{
/* ignore mis-configurations */
if(m_adc_channel==(ADCName)NC)
return false;
while(!m_done)
__WFE();
return true;
}
void RGB_Sensor::convert(TRGB &rgb)
{
/* correct "DC" offset by subdstracting
* environment light
*/
rgb.ch.red = m_adc_aggregation[1] - m_adc_aggregation[0];
rgb.ch.green = m_adc_aggregation[2] - m_adc_aggregation[0];
rgb.ch.blue = m_adc_aggregation[3] - m_adc_aggregation[0];
}
bool RGB_Sensor::capture(TRGB &rgb)
{
if(!(capture(NULL) && wait()))
return false;
convert(rgb);
return true;
}