diff options
Diffstat (limited to 'firmware/drivers/adc.c')
-rw-r--r-- | firmware/drivers/adc.c | 67 |
1 files changed, 32 insertions, 35 deletions
diff --git a/firmware/drivers/adc.c b/firmware/drivers/adc.c index a75f788417..4a99a49753 100644 --- a/firmware/drivers/adc.c +++ b/firmware/drivers/adc.c | |||
@@ -286,60 +286,57 @@ void adc_init(void) | |||
286 | #elif CONFIG_CPU == PP5020 || (CONFIG_CPU == PP5002) | 286 | #elif CONFIG_CPU == PP5020 || (CONFIG_CPU == PP5002) |
287 | 287 | ||
288 | struct adc_struct { | 288 | struct adc_struct { |
289 | long last_read; | 289 | long timeout; |
290 | unsigned short (*conversion)(unsigned short data); | 290 | void (*conversion)(unsigned short *data); |
291 | short channelnum; | 291 | short channelnum; |
292 | unsigned short data; | 292 | unsigned short data; |
293 | }; | 293 | }; |
294 | 294 | ||
295 | static struct adc_struct adcdata[NUM_ADC_CHANNELS] IDATA_ATTR; | 295 | static struct adc_struct adcdata[NUM_ADC_CHANNELS] IDATA_ATTR; |
296 | 296 | ||
297 | /* This takes 10 bit ADC data from the subtractor circuit and scales it to | 297 | static unsigned short _adc_read(struct adc_struct *adc) |
298 | * a 13 bit value corresponding to 0-5.4v, the resulting range is 13FB-17FA, | ||
299 | * representing 3.1-5.4v */ | ||
300 | static unsigned short ten_bit_subtractor(unsigned short data) { | ||
301 | return (data<<2)+0x4FB; | ||
302 | } | ||
303 | |||
304 | static unsigned short _adc_scan(struct adc_struct *adc) | ||
305 | { | 298 | { |
306 | unsigned short data; | 299 | if (adc->timeout < current_tick) { |
307 | 300 | unsigned char data[2]; | |
308 | /* ADCC1, 8 bit, start */ | 301 | unsigned short value; |
309 | pcf50605_write(0x2f, 0x80 | (adc->channelnum << 1) | 0x1); | 302 | /* 5x per 2 seconds */ |
310 | data = pcf50605_read(0x30); /* ADCS1 */ | 303 | adc->timeout = current_tick + (HZ * 2 / 5); |
311 | 304 | ||
312 | if (adc->conversion) { | 305 | /* ADCC1, 10 bit, start */ |
313 | data = adc->conversion(data); | 306 | pcf50605_write(0x2f, (adc->channelnum << 1) | 0x1); |
307 | pcf50605_read_multiple(0x30, data, 2); /* ADCS1, ADCS2 */ | ||
308 | value = data[0]; | ||
309 | value <<= 2; | ||
310 | value |= data[1] & 0x3; | ||
311 | |||
312 | if (adc->conversion) { | ||
313 | adc->conversion(&value); | ||
314 | } | ||
315 | adc->data = value; | ||
316 | return value; | ||
317 | } else { | ||
318 | return adc->data; | ||
314 | } | 319 | } |
315 | adc->data = data; | ||
316 | return data; | ||
317 | } | 320 | } |
318 | 321 | ||
319 | /* Force an ADC scan _now_ */ | 322 | /* Force an ADC scan _now_ */ |
320 | unsigned short adc_scan(int channel) { | 323 | unsigned short adc_scan(int channel) { |
321 | return _adc_scan(&adcdata[channel]); | 324 | struct adc_struct *adc = &adcdata[channel]; |
325 | adc->timeout = 0; | ||
326 | return _adc_read(adc); | ||
322 | } | 327 | } |
323 | 328 | ||
324 | /* Retrieve the ADC value, only does a scan once per second or less */ | 329 | /* Retrieve the ADC value, only does a scan periodically */ |
325 | unsigned short adc_read(int channel) | 330 | unsigned short adc_read(int channel) { |
326 | { | 331 | return _adc_read(&adcdata[channel]); |
327 | struct adc_struct *adc = &adcdata[channel]; | ||
328 | if (adc->last_read + HZ < current_tick) { | ||
329 | adc->last_read = current_tick; | ||
330 | return _adc_scan(adc); | ||
331 | } else { | ||
332 | return adc->data; | ||
333 | } | ||
334 | } | 332 | } |
335 | 333 | ||
336 | void adc_init(void) | 334 | void adc_init(void) |
337 | { | 335 | { |
338 | struct adc_struct *adc_battery = &adcdata[ADC_BATTERY]; | 336 | struct adc_struct *adc_battery = &adcdata[ADC_BATTERY]; |
339 | adc_battery->channelnum = 0x3; /* ADCVIN1, subtractor */ | 337 | adc_battery->channelnum = 0x2; /* ADCVIN1, resistive divider */ |
340 | adc_battery->conversion = ten_bit_subtractor; | 338 | adc_battery->timeout = 0; |
341 | adc_battery->last_read = current_tick; | 339 | _adc_read(adc_battery); |
342 | _adc_scan(adc_battery); | ||
343 | } | 340 | } |
344 | 341 | ||
345 | #elif CONFIG_CPU == PNX0101 | 342 | #elif CONFIG_CPU == PNX0101 |