micro:bit Internal Analog Reference

IMG_0541(1)For the last few days I have been playing with the micro:bits builtin capability to measure analog voltages on P0, P1 & P2 (you can set up some of the other IO lines as analog inputs but this is a bit of an involved process and best avoided if possible).

** WARNING **  – YOU MUST ENSURE THAT ANY VOLTAGE APPLIED TO THE MICRO:BIT DOES NOT EXCEED THE SUPPLY RAIL [TYPICALLY 3V] DOING SO WILL RESULT IN DAMAGE TO YOUR MICRO:BIT

 

 

By default the analog converter in the micro:bit is referenced to the micro:bit supply rail and is configured for 10 bit operation. Hence the following code;

from microbit import *
a = pin0.read_analog()
print(a)
display.scroll(str(a))

will return 1023 if you connect the 3V & P0 pads together, irrespective of battery condition of if you power via the micro USB connector. For many applications this is fine and using the micro:bits 3V supply as the source voltage for any analog experiments is the best way to minimize risk of damage the the micro:bit.

However if you want to measure a voltage not derived from the micro:bits supply things can become a bit more problematic. It’s fine if you can power the micro:bit from a constant source – for instance a phone mains power adapter, but not so good if you are running from a battery. This because as the ADC (analog to digit converter) reference voltage will drop as the battery discharges resulting in a change to the count value returned. For instance assuming a new set of batteries provides 3V, a 1.5V source on P0 would return 512, but if the battery voltage drops to 2.5V the reading would change to 614 counts. To get around this the ADC in the micro:bit can be configured to reference an internal fixed 1.2V voltage reference. This means the count value will not vary with a changing supply voltage.IMG_0547(1)

In it’s basic setup this would mean a voltage of 1.2V on P0 would give a result of 1023. However 0-1.2V is quite a small range so the ADC circuit includes a configurable ‘pre-scaler’ to help us. Configuring this to 3:1 we get full scale ADC range of 0-3.6V. It is important to note however that the rule of keeping the maximum voltage applied to a micor:bit input pin at or below the supply rail still applies. 

The following code will setup the ADC to use the internal reference on P0 together with a 3:1 pre-scaler.

Code to demo using the micro:bit internal ADC reference 
# based on material and help from Carlos Pereira Atencio https://gist.github.com/microbit-carlos/
# David Saul 2017. Released to the public domain.

from microbit import *

NRF_ADC_BASE = 0x40007000
NRF_ADC_CONFIG = NRF_ADC_BASE + 0x504

# functions used to modify ADC setup
@micropython.asm_thumb
def reg_read(r0):
 ldr(r0, [r0, 0])

@micropython.asm_thumb
def reg_bit_clear(r0, r1):
 ldr(r2, [r0, 0])
 bic(r2, r1)
 str(r2, [r0, 0])
 
 
# change ADC config for pin0

# mbed configured: 10bit, input 1/3, ref 1/3 vdd, enable ADC in AIN4-P0.03-pin0
pin0.read_analog() 
#Set ref voltage to internal ref 1.2V (band gap), set bits 5-6 to 0x00
reg_bit_clear(NRF_ADC_CONFIG, 0x60)
print("ADC config should be 0x100A: {:#010x}".format(reg_read(NRF_ADC_CONFIG)))

#variable definition
vt = 0 # raw / scaled analog value
vf = "0000" # measured voltage as a formatted string 
cal = 352 # calibration variable
# cal is calculated as (Vin / raw count)*10000
while True
 vt = pin0.read_analog()
 print ('raw count = ',vt)
 
 # the following lines of code scale the measured value and derive a
 # string (vf) that equates to it - there are simpler ways to do this
 # but this method avoids the use of floating variables which are very
 # inefficient on cards like the micro:bit
 
 vt = int((vt * cal)/1000) 
 vs = str(vt)
 if vt > 1000:
  vf = vs[0:2]+'.'+vs[2:3] 
 elif vt > 100 :
  vf = vs[0:1]+'.'+vs[1:3]
 elif vt > 10 :
  vf = '0.'+vs
 elif vt > 1 :
  vf = '0.0'+vs
 else :
  vf = '0.000' 
 
 vf = vf+"V"
 print ('Scaled', vf)
 display.scroll(vf)
 
 sleep(2000)

 

link to code on GitHub

The ‘keep to the rail voltage’ is a generally safe but slight simplification of the ADC operating rules. If you are looking to work with source voltages not limited to the micro:bit supply rail there are specific rules you need to be aware of to avoid damaging your micro:bit. A number of discussion threads have been written on these [ probably because it’s not very understandable in the NORDIC chip datasheet ] one example which is ‘relatively’ clear is https://devzone.nordicsemi.com/question/102/what-voltage-range-can-be-measured-with-the-adc/

 

 

 

Advertisements