esp8266 analogue input


The esp8266 contains a 10bit ADC. There are apparently various issues, including instability when transmitting over Wifi, and the lack of a voltage reference. However it is usable. The analogue input is labeled “tout” on the pinout below:


Unfortunately this isn’t broken out on the cheapest esp8266 boards (the esp1) but it’s possible to get access to it with some wirewrap wire and careful soldering (see image above).

The ADC input can then be read using some relatively simple C code as shown below. This code was adapted from an old version of the SDK (it doesn’t seem to be present in the current version).

I’ve also attached a complete working example that uses the function below: adc_test.tar

uint16 ICACHE_FLASH_ATTR adc_read(void) {
  uint8 i;
  uint16 sar_dout, tout, sardata[8];


  // disable interrupts?
  SET_PERI_REG_MASK(0x60000D5C, 0x200000);
  while (GET_PERI_REG_BITS(0x60000D50, 26, 24) > 0); //wait r_state == 0
  sar_dout = 0;
  CLEAR_PERI_REG_MASK(0x60000D50, 0x02); //force_en=0
  SET_PERI_REG_MASK(0x60000D50, 0x02); //force_en=1

  while (GET_PERI_REG_BITS(0x60000D50, 26, 24) > 0); //wait r_state == 0

  // Could this be averaging 8 readings? If anyone has any info please comment.
  for (i = 0; i < 8; i++) {
    sar_dout += sardata[i];
  tout = (sar_dout + 8) >> 4; //tout is 10 bits fraction

  // I assume this code re-enables interrupts
  while (GET_PERI_REG_BITS(0x60000D50, 26, 24) > 0); //wait r_state == 0
  CLEAR_PERI_REG_MASK(0x60000D5C, 0x200000);
  SET_PERI_REG_MASK(0x60000D60, 0x1); //force_en=1
  CLEAR_PERI_REG_MASK(0x60000D60, 0x1); //force_en=1
  return tout; //tout is 10 bits fraction

UPDATE: There’s also a system_adc_read function in the library symbols, I’ve not used it but it could be worth looking at.

This is a continuation of my notes on the esp8266 microcontroller, you can find a complete list of my esp8266 posts here