abstract: this application note describes the proper use of interrupt output functionality in the max9635 ambient light sensor for lcd backlight management in portable devices like smartphones and tablets. the interrupt functionality allows adjustment of light threshold values for multiple illumination zones without the need to poll the light sensor repeatedly. when used properly, this function allows the system to remain in a low-power sleep mode or to dedicate other resources for other user-defined tasks. the interrupt functionality significantly improves energy efficiency, system performance, and the user's experience in different lighting conditions. this article also gives an example of i²c c pseudocode for programming the interrupt.
introductionthe max9635 ambient light sensor uses advanced techniques to detect the brightness of ambient light. this device is useful in multiple applications including, but not limited to, display lcd backlight adjustment in portable and home electronics and room lighting. the max9635's extremely low operating power (just 0.65µa) and its 1.8v operating voltage (designed to facilitate easy interaction with a microcontroller i/o ports) make it attractive for use in a number of sensor and security applications. the backlight adjustment and low operating power extend battery life and increase the energy efficiency of the lighting application.
one of the max9635's most valuable features is a highly versatile interrupt output pin. this pin allows the system to stay in a low-power sleep state or dedicate resources for other user-valued tasks.
this application note explains how to code this interrupt output functionality to ensure optimal system performance. some example c-style pseudocode is given.
register presetsthe table below shows the register map of the max9635, together with power-on reset (por) states.
register
bit
register address
power-on reset state
r/w
7
6
5
4
3
2
1
0
status
interrupt status
—
—
—
—
—
—
—
ints
0x00
0x00
r
interrupt enable
—
—
—
—
—
—
—
inte
0x01
0x00
r/w
configuration
configuration
cont
manual
—
—
cdr
tim[2:0]
0x02
0x03
r/w
lux reading
lux high byte
e3
e2
e1
e0
m7
m6
m5
m4
0x03
0x00
r
lux low byte
—
—
—
—
m3
m2
m1
m0
0x04
0x00
r
threshold set
upper threshold high byte
ue3
ue2
ue1
ue0
um7
um6
um5
um4
0x05
0xff
r/w
lower threshold high byte
le3
le2
le1
le0
lm7
lm6
lm5
lm4
0x06
0x00
r/w
threshold timer
t7
t6
t5
t4
t3
t2
t1
t0
0x07
0xff
r/w
the preset registers are configuration, interrupt enable, and threshold timer.
power-up settings for the configuration register (address 0x02), cont=0 and manual=0, are sufficient for most user applications. these settings tell the max9635 to automatically scale its sensitivity up and down based on the appropriate ambient light level.
to enable interrupt functionality, the master, i.e., the microcontroller, first writes a 1 to the interrupt enable register (address 0x01).
the master then writes a suitable delay to the threshold timer register (address 0x07). normally, this setting does not change. there are two principal reasons for writing this threshold delay. first, writing a nonzero value to this register prevents nuisance trips due to fleeting or momentary changes in light conditions. a fleeting light change could occur when a shadow passes over the light sensor after a user gesture or movement of the device. second, an intentional delay in the response of display brightness allows time for a defined user-interface algorithm. an example of this would be a mobile application like an ipad™ device. in this example one would not want the display brightness to fluctuate rapidly when passing through a dark corridor like a subway punctuated by periodic lights.
threshold register settingsduring normal operation the user repeatedly programs the upper threshold register (address 0x05) and lower threshold register (address 0x06). an interrupt is triggered (ints bit in register 0x00 is set to 1 and the active-low int hardware pin is pulled low) when the ambient light level exceeds the window levels defined by these registers. this interrupt will last longer than the delay defined by the threshold timer register (address 0x07).
to program the threshold register settings, the master first reads the lux counts from the data registers, lux high byte (address 0x03) and lux low byte (address 0x04), to find the current operating zone. the master then sets appropriate upper threshold register and lower threshold register counts.
example algorithm for backlight controlthe human eye perceives brightness logarithmically, in much the same way as the human ear perceives loudness. as a result, backlight strength is typically programmed so that it also responds in a logarithmic fashion to ambient light levels. therefore, there are finer steps in low-light levels, while the backlight strength does not change as much in bright ambient conditions. the host processor would, ideally, also implement additional advanced image-processing algorithms such as contrast and color adjustment based on this ambient light-level information.
a typical algorithm for brightness control could have five threshold levels for control. quite often the type of interface glass and size of physical opening can reduce the light that the light sensor sees down to as little as 5% to 10% of external ambient light. this scaling should be taken into account when setting the threshold levels.
the following table is one example of backlight strength and upper and lower thresholds. to convert the threshold lux to threshold counts, simply divide the target lux setting by 0.045.
illumination zone
external lux (typ)
backlight strength (%)
external lux, lower threshold (typ)
external lux, upper threshold (typ)
lower threshold (10% glass)
upper threshold (10% glass)
dark
4
25
10
1
dim
20
45
50
5
home
100
65
200
20
office
400
85
1000
100
sunlight
> 2000
100
maximum
maximum
changing backlight strength with external lighting conditions.
implementing an interruptthe following figure shows a typical example of a flowchart implemented by the master microcontroller.
algorithm threshold levels and ambient measurement: counts vs. luxit is more straightforward to implement the algorithm in terms of counts rather than lux values. doing so bypasses the need to use any floating-point math and allows simple fixed-point microcontroller code.
ambient light count
2^(exponent) × mantissa
exponent = 8xe3 + 4xe2 + 2xe1 + e0
mantissa = 128xm7 + 64xm6 + 32xm5 + 16xm4 + 8xm3 + 4xm2 + 2xm1 + m0
upper threshold count
2^(exponent) × mantissa
exponent = 8xe3 + 4xe2 + 2xe1 + e0
mantissa = 128xm7 + 64xm6 + 32xm5 + 16xm4 + 15
lower threshold count
2^(exponent) × mantissa
exponent = 8xe3 + 4xe2 + 2xe1 + e0
mantissa = 128xm7 + 64xm6 + 32xm5 + 16xm4
using the desired thresholds from the table above, one can calculate threshold register bytes for use as limits in the pseudocode for each illumination zone. these thresholds are simply compared to ambient light count calculated from the equation above.
zone
lower threshold, 10% glass (lux)
upper threshold, 10% glass (lux)
desired lower threshold counts
desired upper threshold counts
lower threshold register byte
upper threshold register byte
actual lower threshold counts
actual upper threshold counts
actual lower threshold (lux)
actual upper threshold (lux)
dark
1
0
22
0000
0000
0000
0001
0
31
1.395
dim
5
22
111
0000
0001
0000
0110
16
111
4.995
home
20
111
556
0000
0110
0010
1001
96
636
28.62
office
100
556
2222
0010
1001
0100
1000
576
2288
102.96
sunlight
maximum
2222
4177920
0100
1000
1110
1111
2048
4177920
188006
it should be noted that if the operating light level is quite close to the border of a defined illumination zone, backlight levels can fluctuate more frequently and cause discomfort to a user. for this reason, a small overlap zone has been defined between the upper threshold of one illumination zone and the lower threshold of the next higher illumination zone. this provides a natural hysteresis to act as a shield against small light fluctuations. these overlaps can be expanded further if desired.
the algorithm described here is only a general guideline for one possible implementation of backlight brightness control. those skilled in the art of backlight control have developed many different algorithms to deliver a sophisticated and transparent feel to the end user.
sample c pseudocode implementation// begin definition of slave device address
#define max9635_wr_addr 0x96
#define max9635_rd_addr 0x97
// begin definition of slave register addresses for max9635
#define int_status 0x00
#define int_enable 0x01
#define config_reg 0x02
#define high_byte 0x03
#define low_byte 0x04
#define thresh_high 0x05
#define thresh_low 0x06
#define thresh_timer 0x07
// end definition of slave addresses for max9635
// define some lookup tables for the upper and lower thresholds as well as the
// brightness. all tables values are taken from text of application notes
#define num_regions 5
uint8 upperthresholds[num_regions] = {0x01, 0x06, 0x29, 0x48, 0xef};
uint8 lowerthresholds[num_regions] = {0x00, 0x01, 0x06, 0x29, 0x48};
uint8 backlightbrightness[num_regions] = {0x40, 0x73, 0xa6, 0xd9, 0xff};
/**
function: setpwmdutycycle
arguments: uint8 dc - desired duty cycle
returns: none
description: sets the duty cycle of a 8-bit pwm, assuming that in this
architecture, 0x00 = 0% duty cycle 0x7f = 50% and 0xff = 100%
**/
extern void setpwmdutycycle(uint8 dc);
extern void setupmicro(void);
extern void idle(void);
/**
function: i2c_writebyte
arguments: uint8 slaveaddr - address of the slave device
uint8 regaddr - destination register in slave device
uint8 data - data to write to the register
returns: ack bit
description: performs necessary functions to send one byte of data to a
specified register in a specific device on the i²c bus
**/
extern uint8 i2c_writebyte(uint8 slaveaddr, uint8 regaddr, uint8 data);
/**
function: i2c_readbyte
arguments: uint8 slaveaddr - address of the slave device
uint8 regaddr - destination register in slave device
uint8 *data - pointer data to read from the register
returns: ack bit
description: performs necessary functions to get one byte of data from a
specified register in a specific device on the i²c bus
**/
extern uint8 i2c_readbyte(uint8 slaveaddr, uint8 regaddr, uint8* data);
/**
function: findnewthresholdsandbrightness
arguments: uint8 luxcounts - light counts high byte
uint8 *highthresh - pointer to memory storing upper threshold byte
uint8 *lowthresh - pointer to memory storing lower threshold byte
returns: none
description: based on what the lux reading was (in counts), this routine
determines the current operating illumination zone. the zones
are defined by upper and lower bounds in a lookup table. after
knowing the operating zone, this function may set new interrupt
thresholds and a backlight brightness. since the interrupt only
fires when the lux reading is outside the defined region, these
threshold and brightness settings are not overwritten with the
same data repeatedly.
**/
void findnewthresholdsandbrightness(uint8 luxcounts, uint8 *highthresh,
uint8 *lowthresh);
void main() {
uint8 *highthresholdbyte; // upper and lower threshold bytes
uint8 *lowthresholdbyte;
uint8 *timerbyte;
uint8 max9635interrupt = 0; // status of max9635 interrupt register
uint8 luxcounts; // computed as shown below
setupmicro(); // some subroutine which initializes this cpu
*highbyte = 0;
*lowbyte = 0;
*highthresholdbyte = 0xef; // upper threshold counts
// initially = por setting (maximum possible = 0xef)
*lowthresholdbyte = 0x00; // lower threshold counts
// initially por setting (minimum possible = 0x00)
*timerbyte = 0x14; // initial timer delay for thresholds:
// 0x14 * 100ms = 2 seconds
// initialize max9635 threshold and timer registers
i2c_writebyte(max9635_wr_addr, thresh_high, *highthresholdbyte);
i2c_writebyte(max9635_wr_addr, thresh_low, *lowthresholdbyte);
i2c_writebyte(max9635_wr_addr, thresh_timer, *timerbyte);
i2c_writebyte(max9635_wr_addr, int_enable, 0x01);// enable sensor interrupts
while(1) {
// do other tasks until an interrupt fires
// assume that this function waits for the status of a gpio-type pin to
// change states
while (! gpio_statuschanged() ) {
// some idling subroutine, shown with polling a port for
// simplicity - but alternate interrupt-based routines are more
// efficient
idle();
} // loop until an interrupt occurs
// ok... an interrupt fired! was it from the max9635?
i2c_readbyte(max9635_rd_addr, int_status, max9635interrupt);
/**
place code to check other devices here, if desired
**/
if (max9635interrupt) {
// get the current lux reading from the max9635
i2c_readbyte(max9635_rd_addr, high_byte, luxcounts);
findnewthresholdsandbrightness(luxcounts, highthresholdbyte,
lowthresholdbyte);
// write to the threshold and timer registers with new data
i2c_writebyte(max9635_wr_addr, thresh_high, *highthresholdbyte);
i2c_writebyte(max9635_wr_addr, thresh_low, *lowthresholdbyte);
max9635interrupt = 0; // interrupt serviced, clear the bits
} // only executes if the max9635's interrupt fired
// perform other tasks which are only done after change of a gpio pin
} // loop forever
} // main routine
void findnewthresholdsandbrightness(uint8 luxcounts, uint8 *highthresh, uint8 *lowthresh) {
uint8 i;
for (i=0; i = lowerthresholds[i]) && (luxcounts <= upperthresholds[i])){
*highthresh = upperthresholds[i];
*lowthresh = lowerthresholds[i];
// pwm duty cycle sets the brightness of the backlight
setpwmdutycycle(backlightbrightness[i]);
return; // found the region -- no point in continuing the loop
} // found the right region
} // check where the lux reading lies in terms of threshold regions
} // findnewthresholdsandbrightness
研华提供从端到云物联网完整解决方案
雷达感知是什么? 你不知道的雷达应用
DVI信号线简介及应用
华为路由Q2体验 高效Wi-Fi扩展方案适用场景广泛
2021年,数据中心将加速部署新兴技术
Interface code implementation
测土配方仪器的原理是什么
专利之争 LED封装龙头亿光接连获胜
昂科技术软件更新支持烧录Belling16位串行可擦除可编程只读存储器BL24C16A-PA
对于电动汽车电池的耐用性看看特斯拉是怎么做的
基于Linux的智能家居管理方案
HTC U旗舰新机靠谱渲染图首曝:设计神似U Ultra
物联网和人工智能这对组合的应用盘点
软件测试的代码划分:黑盒白盒灰盒的区别
TE就收购Deutsch举行独家谈判
软通动力:抢抓智能座舱新机遇 聚焦汽车智能化发展新路径
电动化市场“阵痛”与产业链应对方案
固体钽电容和非固体钽电容区别
欧洲航天局正在选择空中客车建造SMILE卫星
电池电量计:以精度制胜