-
Hi, this is my demo code for measuring the temperature in °C from a NTC 10K B3450 sensor: Wiring:
Code: package main
import (
"fmt"
"machine"
"math"
"time"
)
func main() {
time.Sleep(time.Millisecond * 1000)
fmt.Println("Starting...")
var adc machine.ADC = machine.ADC{Pin: machine.GPIO28}
machine.InitADC()
adc.Configure(machine.ADCConfig{})
const (
r25 = 10000.0
beta = 3450.0
rHigh = 10000.0
)
for {
adcValue := float64(adc.Get())
println(adcValue)
// Thermistor to GND
//r := rHigh / (65535.0/adcValue - 1.0)
// Thermistor to VCC
r := rHigh * (65535.0/adcValue - 1.0)
lnr := math.Log(r / r25)
tsC := -274.15 + 1.0 / (1.0 / 298.15 + lnr / beta)
fmt.Printf("%5.1f °C\n", tsC)
time.Sleep(2 * time.Second)
}
} This works for a RP2040 (Pico) but with a RP2350 (Pico2) the temperature reading has a ~ 17K offset. Is there a difference between RP2350 and RP2040 when it comes to ADC measurements? Here are the outputs of Pico$ tinygo flash -target=pico -monitor read_temp.go
Connected to /dev/cu.usbmodem111101. Press Ctrl-C to exit.
Starting...
+3.168000e+004
22.3 °C
+3.153600e+004
22.0 °C
+3.142400e+004
21.9 °C
+3.132800e+004
21.7 °C
+3.128000e+004
21.6 °C
+3.116800e+004
21.4 °C Pico2$ tinygo flash -target=pico2 -monitor read_temp.go
Connected to /dev/cu.usbmodem2101. Press Ctrl-C to exit.
Starting...
+3.966400e+004
35.7 °C
+4.000000e+004
36.3 °C
+3.956800e+004
35.5 °C
+3.977600e+004
35.9 °C
+3.984000e+004
36.0 °C Edit: I also checked ADC_VRef voltage on each board, both are a 3.28V |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 4 replies
-
I don't see any difference in the datasheets, and the TinyGo implementation is the same for the two chips. I'd try with a known voltage (say, the reference voltage) and see whether the raw ADC readings still differ. |
Beta Was this translation helpful? Give feedback.
-
Ok I did some more debugging, I wrote (with some help of Claude) a Program in C. That works on RP2040 and RP2350, I then ported it to GO: C#include <stdio.h>
#include <math.h>
#include "pico/stdlib.h"
#include "hardware/adc.h"
// Thermistor parameters
#define B_VALUE 3450.0 // B-value of the NTC thermistor
#define NOMINAL_RESISTANCE 10000.0 // Resistance at 25°C (10k ohm)
#define NOMINAL_TEMP 25.0 // Temperature for nominal resistance (25°C)
// Hardware parameters
#define THERMISTOR_ADC_CHANNEL 2 // GPIO28 is ADC channel 2
#define SERIES_RESISTOR 10000.0 // 10k ohm series resistor
#define ADC_RESOLUTION 4096.0 // 12-bit ADC (2^12)
#define VREF 3.3 // Reference voltage
// Function to convert ADC reading to resistance
float adc_to_resistance(uint16_t adc_value) {
// Convert ADC value to voltage
float voltage = (adc_value / ADC_RESOLUTION) * VREF;
// Calculate thermistor resistance using voltage divider
// In your wiring: VREF -> THERMISTOR -> GPIO28 -> 10k_RESISTOR -> GND
// Vout = Vref * (R_series / (R_thermistor + R_series))
// Solving for R_thermistor:
// R_thermistor = R_series * (Vref - Vout) / Vout
float resistance = SERIES_RESISTOR * (VREF - voltage) / voltage;
return resistance;
}
// Function to convert resistance to temperature using B-parameter equation
float resistance_to_temperature(float resistance) {
// B-parameter equation:
// 1/T = 1/T0 + (1/B) * ln(R/R0)
// Where:
// T = temperature in Kelvin
// T0 = nominal temperature in Kelvin (25°C = 298.15K)
// R = measured resistance
// R0 = nominal resistance at T0
// B = B-value of the thermistor
float temp_kelvin = 1.0 / ((1.0 / (NOMINAL_TEMP + 273.15)) +
(1.0 / B_VALUE) * log(resistance / NOMINAL_RESISTANCE));
// Convert from Kelvin to Celsius
float temp_celsius = temp_kelvin - 273.15;
return temp_celsius;
}
int main() {
// Initialize stdio for USB output
stdio_init_all();
// Initialize ADC
adc_init();
// Enable ADC input on GPIO28 (ADC channel 2)
adc_gpio_init(28);
// Wait for USB connection (optional, remove if not needed)
sleep_ms(2000);
printf("Thermistor Temperature Monitor\n");
printf("==============================\n");
while (1) {
// Select ADC channel 2 (GPIO28)
adc_select_input(THERMISTOR_ADC_CHANNEL);
// Read ADC value
uint16_t adc_value = adc_read();
// Convert ADC reading to resistance
float resistance = adc_to_resistance(adc_value);
// Convert resistance to temperature
float temp_celsius = resistance_to_temperature(resistance);
// Debug: show what voltage this represents
float voltage = (adc_value / ADC_RESOLUTION) * VREF;
printf("Debug - ADC: %d, Voltage: %.3fV\n", adc_value, voltage);
// Display ADC value and temperature
printf("ADC: %4d, %5.1f °C\n", adc_value, temp_celsius);
// Wait 2 seconds before next reading
sleep_ms(2000);
}
return 0;
} Pico RP2040
Pico RP2040
Voltages and ADC Values are in the same range for both boards. GOSame program in tinygo: package main
import (
"fmt"
"machine"
"math"
"time"
)
const (
// Thermistor parameters
B_VALUE = 3450.0 // B-value of the NTC thermistor
NOMINAL_RESISTANCE = 10000.0 // Resistance at 25°C (10k ohm)
NOMINAL_TEMP = 25.0 // Temperature for nominal resistance (25°C)
// Hardware parameters
SERIES_RESISTOR = 10000.0 // 10k ohm series resistor
ADC_RESOLUTION = 65536.0 // TinyGo returns 16-bit values (2^16)
VREF = 3.3 // Reference voltage
)
// Function to convert ADC reading to resistance
func adcToResistance(adcValue uint16) float64 {
// Convert ADC value to voltage
voltage := (float64(adcValue) / ADC_RESOLUTION) * VREF
// Calculate thermistor resistance using voltage divider
// In your wiring: VREF -> THERMISTOR -> GPIO28 -> 10k_RESISTOR -> GND
// R_thermistor = R_series * (Vref - Vout) / Vout
resistance := SERIES_RESISTOR * (VREF - voltage) / voltage
return resistance
}
// Function to convert resistance to temperature using B-parameter equation
func resistanceToTemperature(resistance float64) float64 {
// B-parameter equation:
// 1/T = 1/T0 + (1/B) * ln(R/R0)
// Where T is in Kelvin, T0 = 298.15K (25°C)
tempKelvin := 1.0 / ((1.0 / (NOMINAL_TEMP + 273.15)) +
(1.0/B_VALUE)*math.Log(resistance/NOMINAL_RESISTANCE))
// Convert from Kelvin to Celsius
tempCelsius := tempKelvin - 273.15
return tempCelsius
}
func main() {
// Wait for initialization
time.Sleep(time.Second * 2)
fmt.Println("Thermistor Temperature Monitor")
fmt.Println("==============================")
// Initialize ADC
machine.InitADC()
// Configure ADC on GPIO28
adc := machine.ADC{Pin: machine.GPIO28}
adc.Configure(machine.ADCConfig{})
for {
// Read ADC value
adcValue := adc.Get()
// Debug: show what voltage this represents
voltage := (float64(adcValue) / ADC_RESOLUTION) * VREF
fmt.Printf("Debug - ADC: %d, Voltage: %.3fV\n", adcValue, voltage)
// Convert ADC reading to resistance
resistance := adcToResistance(adcValue)
// Convert resistance to temperature
tempCelsius := resistanceToTemperature(resistance)
// Display ADC value and temperature
fmt.Printf("ADC: %4d, %5.1f °C\n", adcValue, tempCelsius)
// Wait 2 seconds before next reading
time.Sleep(2 * time.Second)
}
} Pico2 RP2350
Pico RP2040
The voltages and ADC values are different, between the boards. So something is definitely different between pico & pico2 tinygo implementations. |
Beta Was this translation helpful? Give feedback.
-
I glanced at the Pico SDK, and it doesn't seem to differentiate between rp2350 and rp2040 either. I did find #4938, but that's an unlikely cause. I also found #4939, which is more juicy. |
Beta Was this translation helpful? Give feedback.
I glanced at the Pico SDK, and it doesn't seem to differentiate between rp2350 and rp2040 either.
I did find #4938, but that's an unlikely cause.
I also found #4939, which is more juicy.