DIY IoTaWatt-style board: MCP3208 always reads ~2k / ~4k, CTs have no effect (ESP8266 + MCP3208 test sketch inside)

Hi all,
A friend and I are building a DIY energy-monitor board based on the IoTaWatt design: ESP8266 (NodeMCU 1.0 / ESP-12E) + MCP3208 + multiple CT inputs on 3.5 mm jacks. Before flashing the IoTaWatt firmware, we are trying to sanity-check the hardware by polling the MCP3208 directly over SPI.

However, the ADC readings look wrong and do not react to the CTs in the way we expect.

Hardware setup

• ESP8266 NodeMCU 1.0

• MCP3208 wired according to the IoTaWatt-style schematic:

• VDD = 3.3 V

• VREF = 3.3 V (bias network around 1.65 V for CT inputs)

• CH0–CH7 connected via burden resistors and jacks for CTs

• SPI pins (ESP8266):

• MOSI = D7 (GPIO13)

• MISO = D6 (GPIO12)

• SCLK = D5 (GPIO14)

• CS for MCP3208 = D4 (GPIO2)

• 9 VAC reference transformer plugged into the AC adapter and wired in as the voltage reference (tested both with and without this connected).

The module powers on fine and SPI communication works in the sense that I get stable digital values back.

Observed behaviour

With the test sketch below, printing raw values for channels 0–6 every 300 ms:

1. Early tests:

• CH1 sat around 2045–2048 and did not change whether a CT was plugged in or not.

• CH3 appeared “dead” (no meaningful variation).

• CH7 initially looked “reasonable” with values around 2040–2050, but when a CT was plugged in, it sometimes jumped to max code (4095) or gave large swings (roughly 500–1548).

2. After soldering more jacks (6 total):

• The script prints continuous data for all 7 channels, but:

• Channels C1 and C2 stay in the ~2k range regardless of CT connection.

• Channels C3–C7 stay in the ~4k range regardless of CT connection.

• In another run, I saw “all garbage” – all channels changing but not in any way that correlated with plugging a CT in or out.

3. I repeated the same tests with the 9 VAC adapter plugged in and the voltage reference connected. The raw MCP3208 outputs look essentially the same: still stuck around ~2k and ~4k on the same channels, with no clear correlation to CT connectivity or load.

We also tried swapping the series resistor on the “dead” channel (CH3) with the one from CH1 to rule out a single bad resistor, but behaviour did not improve.

Test sketch

#include <SPI.h>

// MCP3208 Chip Select pin on ESP8266.

// CS0 = D4 → GPIO 2.

#define MCP_CS 2 // GPIO2 as the CS pin for MCP3208

// Read one channel from MCP3208

// MCP3208 protocol (12-bit, single-ended):

// - Send 5-bit control: Start(1), SGL/DIFF(1), D2, D1, D0

// - MCP responds with 12 data bits (0–4095)

uint16_t readMCP3208(uint8_t channel) {

// Build command byte:

// 1 1 c2 c1 c0 0 0 0

// ‘11’ = Start + single-ended mode

uint8_t command = 0b11000000 | (channel << 2);

digitalWrite(MCP_CS, LOW); // Begin SPI frame

SPI.transfer(command); // Send start + channel select

uint16_t result = (SPI.transfer(0x00) & 0x0F) << 8; // High nibble of result

result |= SPI.transfer(0x00); // Low byte of result

digitalWrite(MCP_CS, HIGH); // End SPI frame

return result; // 0–4095 (12-bit)

}

void setup() {

Serial.begin(115200);

// ESP8266 SPI pins are FIXED:

// MOSI = D7(GPIO13), MISO = D6(GPIO12), SCLK = D5(GPIO14)

SPI.begin(); // No pin arguments required for ESP8266

pinMode(MCP_CS, OUTPUT);

digitalWrite(MCP_CS, HIGH); // CS should idle HIGH

Serial.println(“MCP3208 7-Port Scanner Ready”);

Serial.println(“Channels 0–6 will be printed continuously.\n”);

}

void loop() {

Serial.print("Ports: ");

for (int ch = 0; ch < 7; ch++) {

uint16_t value = readMCP3208(ch);

Serial.print(value);

if (ch < 6) Serial.print(" ");

}

Serial.println();

delay(300);

}

Questions:

1. Is my SPI command sequence for MCP3208 actually correct?

The MCP3208 datasheet shows a start bit, SGL/DIFF bit, and three channel-select bits (D2–D0), followed by a null bit and then 12 data bits, typically implemented as a 3-byte transaction (config bits then 12-bit read). Here I am sending a single “command” byte 0b11000000 | (channel << 2) and then immediately clocking out two bytes of result, which is closer to many MCP3008 examples. Could this alone explain the constant ~2048 / ~4095 readings?

2. Given the IoTaWatt-style front end (CT + burden + mid-supply bias into MCP3208 with 9 VAC reference), what should I expect to see with no current vs. a load?

My understanding is that with no current I should see values close to mid-scale (~2048) with some noise, and with a load I should see an AC waveform around that mid-point. Instead, most channels are effectively locked at either ~2k or ~4k regardless of CT connection or the presence of the 9 VAC reference.

3. Does the pattern “C1 & C2 stuck near 2k, C3–C7 stuck near 4k” ring any bells for people who have built DIY IoTaWatt clones or worked with MCP3208 front-ends?

I am trying to determine whether this is more likely:

• a wiring issue (e.g., VREF or bias network not correct),

• an SPI framing / control-word error,

• or a damaged MCP3208 / passive network on some channels.

Any pointers on whether the SPI command is wrong, or on systematic checks to debug the ADC readings on this kind of board, would be very helpful.