How to Read the ESP32-C6's Built-In Temperature Sensor
Temperature is one of the most important considerations for firmware engineers. It affects how far a crystal oscillator drifts from its rated frequency, how reliably flash writes complete, and how quickly the chip ages. To aid developers, the ESP32-C6 DevKitC has a built-in temperature sensor that you can easily read with just four function calls. In this guide, you’ll learn how to read that sensor and configure your firmware to react when your board gets too hot.
Built-In Sensor Basics
According to the ESP32-C6 DevKitC’s documentation, the sensor is designed to measure the temperature of the onboard chip. Because the CPU, the 2.4 GHz radio, and the sensor all live inside the same chip, every Bluetooth Low Energy (BLE) advertisement and every Wi-Fi packet will heat up the chip and affect the sensor reading. Thus, the sensor reading will always be higher than the ambient temperature and will change as the device’s workload changes.
How is the chip temperature useful? Firmware developers often need the chip temperature to decide when to throttle the CPU clock, back off the radio, delay a flash write, or log a thermal event alongside a crash.
Note: If ambient temperature is more important to you and your use case, you need to add an external sensor to the ESP32-C6. The onboard sensor cannot measure ambient temperature.
Sensor Measurement Range
What is it?
The ESP32-C6’s onboard temperature sensor consists of two parts. One is an 8-bit analog-to-digital converter (ADC) that converts the temperature to data. The other is a digital-to-analog converter (DAC) that sets the sensor’s temperature range.
The sensor can be configured to five different ranges (see below) that cumulatively cover -40 to 125 °C. Each measurement range has its own associated error that applies to every temperature reading.
| range_min | range_max | Error |
|---|---|---|
| 50 °C | 125 °C | < 3 °C |
| 20 °C | 100 °C | < 2 °C |
| -10 °C | 80 °C | < 1 °C |
| -30 °C | 50 °C | < 2 °C |
| -40 °C | 20 °C | < 3 °C |
How is it set?
You configure the sensor’s measurement range in firmware, specifically with TEMPERATURE_SENSOR_CONFIG_DEFAULT(min, max). While you can technically call this function with any arguments, it will only work if both arguments fall in the same range. For example, passing 40 and 110 °C won’t work, but 60 and 110 °C will.
The best range for your device is one that has the least error and still includes:
- All possible environmental temperature(s) where you plan to deploy your device.
- A sizeable gap between the highest possible ambient temperature and the range’s upper limit to account for heat generated from the chip under heavy workloads
For most devices that will stay indoors or inside an enclosure, -10 to 80 °C works well.
Read the Sensor
Before you begin, make sure you have ESP-IDF v5.4 or later installed on your PC.
To access your ESP32-C6’s temperature sensor, you need to add the esp_driver_tsens component to your main/CMakeLists.txt. It should look like the following afterward:
idf_component_register(SRCS "main.c"
INCLUDE_DIRS ""
REQUIRES esp_driver_tsens)Use the following code in main.c to initialize the sensor and read its temperature data:
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/temperature_sensor.h"
#include "esp_log.h"
static const char *TAG = "tsens";
// Install once at startup and reuse the handle. Reading costs far less.
static temperature_sensor_handle_t temp_handle = NULL;
void app_main(void)
{
// -10 to 80 C is the most accurate of the five ranges.
temperature_sensor_config_t cfg = TEMPERATURE_SENSOR_CONFIG_DEFAULT(-10, 80);
ESP_ERROR_CHECK(temperature_sensor_install(&cfg, &temp_handle));
// Powers the sensor on. Until this call succeeds,
// temperature_sensor_get_celsius() returns ESP_ERR_INVALID_STATE.
ESP_ERROR_CHECK(temperature_sensor_enable(temp_handle));
for (;;) {
float chip_c;
ESP_ERROR_CHECK(temperature_sensor_get_celsius(temp_handle, &chip_c));
ESP_LOGI(TAG, "chip temperature: %.1f C", chip_c);
vTaskDelay(pdMS_TO_TICKS(1000));
}
}Build the firmware, flash your board, and open the serial terminal. You should see one temperature line per second, confirming the onboard sensor is working and that you configured the measurement range correctly.

Use the Sensor to Prevent Chip Overheating
Now that you can read your ESP32-C6’s temperature sensor, it’s time to learn how to use that data to keep your board from overheating. The example below forces your chip to overheat and cools it down when it does.
Start by adding the components esp_wifi esp_netif esp_event nvs_flash to your main/CMakeLists.txt. Then, add the code below to main.c. This application does a few things:
- Defines the overheating temperature as your upper limit
- Defines a task to artificially overheat your chip using the Wi-Fi radio
- Initializes the temperature sensor with a measurement range
- Starts the task to heat the chip
- Runs a loop every second that prints the chip temperature and checks if it has overheated. If it did, the code suspends the overheating task, allowing the chip to cool down naturally
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/temperature_sensor.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_netif.h"
#include "esp_wifi.h"
#include "nvs_flash.h"
static const char *TAG = "tsens";
// Set this a few degrees above your board's idle reading.
#define LIMIT_C 31.0f
// Install once at startup and reuse the handle. Reading costs far less.
static temperature_sensor_handle_t temp_handle = NULL;
static TaskHandle_t heat_handle = NULL;
// A raw 802.11 probe request, padded out with a vendor-specific element.
// Length drives air time, and air time is what makes the heat.
// Bytes past index 27 stay zero, which the vendor element accounts for.
#define FRAME_LEN 268
static uint8_t frame[FRAME_LEN] = {
0x40, 0x00, // frame control, probe request
0x00, 0x00, // duration
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // destination, broadcast
0x02, 0x00, 0x00, 0x00, 0x00, 0x01, // source, locally administered
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // BSSID, broadcast
0x00, 0x00, // sequence, driver overwrites it
0x00, 0x00, // SSID element, zero length
0xdd, 0xf0, // vendor element, 240 bytes follow
};
// Transmits back to back so the radio heats the chip on demand.
static void heat_task(void *arg)
{
for (;;) {
for (int i = 0; i < 50; i++) {
esp_wifi_80211_tx(WIFI_IF_AP, frame, sizeof(frame), true);
}
// One tick between bursts. The idle task needs CPU time to feed the
// watchdog, and a loop that never yields forces a reset.
vTaskDelay(1);
}
}
// Brings up a SoftAP at full transmit power. Nothing has to connect to it.
// The access point exists so the radio has an interface to transmit on.
static void wifi_start_ap(void)
{
esp_err_t err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
err = nvs_flash_init();
}
ESP_ERROR_CHECK(err);
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_create_default_wifi_ap();
wifi_init_config_t init_cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&init_cfg));
wifi_config_t ap_cfg = {
.ap = {
.ssid = "tsens-heater",
.ssid_len = 12,
.channel = 1,
.max_connection = 1,
.authmode = WIFI_AUTH_OPEN,
},
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &ap_cfg));
ESP_ERROR_CHECK(esp_wifi_start());
// 84 is the top of the range, in quarter-dBm steps, so 20 dBm.
// Set it after start, because the call needs the radio running.
ESP_ERROR_CHECK(esp_wifi_set_max_tx_power(84));
}
void app_main(void)
{
// -10 to 80 C is the most accurate of the five ranges.
temperature_sensor_config_t cfg = TEMPERATURE_SENSOR_CONFIG_DEFAULT(-10, 80);
ESP_ERROR_CHECK(temperature_sensor_install(&cfg, &temp_handle));
// Powers the sensor on. Until this call succeeds,
// temperature_sensor_get_celsius() returns ESP_ERR_INVALID_STATE.
ESP_ERROR_CHECK(temperature_sensor_enable(temp_handle));
wifi_start_ap();
xTaskCreate(heat_task, "heat", 4096, NULL, 1, &heat_handle);
for (;;) {
float chip_c;
ESP_ERROR_CHECK(temperature_sensor_get_celsius(temp_handle, &chip_c));
ESP_LOGI(TAG, "chip temperature: %.1f C", chip_c);
if (chip_c > LIMIT_C && heat_handle != NULL) {
vTaskSuspend(heat_handle); // stop transmitting
ESP_ERROR_CHECK(esp_wifi_stop()); // and shut the radio down
heat_handle = NULL;
ESP_LOGW(TAG, "over limit at %.1f C, radio stopped", chip_c);
}
// Modify this delay to make your firmware more or less responsive to
// chip temperatures
vTaskDelay(pdMS_TO_TICKS(1000));
}
}Build and flash this firmware, and open the serial terminal. After your board boots, you should see the chip temperature climb until it exceeds the overheating temperature limit (which is 31.0 °C in this example). Then, you should see the board suspend the task using its radio, allowing it to cool down quickly.

Next Steps
You now know how to read your ESP32-C6’s onboard temperature sensor and how to use it to keep your board from overheating.
The next step is to lower your device temperatures even more. You can do that by taking advantage of dynamic frequency scaling and sleep modes, both of which reduce the chip’s workload. Whenever you change your ESP32-C6’s workload, read the built-in temperature sensor to measure how much your chip temperature actually changed.
Ready to connect your devices anywhere on Earth? Get started with Hubble Network for free →