2026-01-12 6:16 AM
Hello, everyone!
My project consists of creating a sensor system that works with NFC. It will be a TAG with the st25dv04k chip, which will power a set of chips through Energy Harvesting. The reader system consists of the ST25R300, chosen for its transmission power. Currently, for the first steps, I am using the development cores: NFC04A1 and NFC12A1. And the RFAL middleware with STM32CubeIDE.
My first steps were to use the library's polling example to do an initial anchoring test between the tag and reader, which worked well. My current goal is to expand the polling example to work better with Energy Harvesting, and thus achieve higher voltage measurements to consolidate the idea of powering chips with it.
I made an improvised measurement on the EH pin of the x-core while it was running the polling example on the NFC12A1 x-core, to get an idea, and I reached 10 mV on the EH pin.
What can I do to increase this to perhaps 1V, for example? Would it be possible to reach 3V in EH?
From what I've seen, it's possible to adjust the transmission power of the ST25R300, but how can I do this in RFAL and STM32CubeIDE?
Solved! Go to Solution.
2026-01-22 3:34 AM
Hello,
Are you enabling the EH from the static register (EEPROM)?
I think the ST25DV_EH_Enable_Static function is wrong. It looks like to me that it is setting bit 0 (EH)_EN) of static register EH_MODE to 1 to enable EH. If you look at the datasheet table 40, it must be set to 0 to enable EH. Actually, it is a bit of a trap as this bit is reversed compared to the EH_EN bit in the EH_CTRL_dyn register.
Best regards.
2026-01-12 8:26 AM
Hello,
You should already get more than 10mV on EH with the standard ST25R300 setting (I'm expecting some Volts not mili-Volts). So, I guess there is something wrong to fix before trying to tune the reader.
How and where do you measure EH?
How did you enable EH in the ST25DV04K? (it is disabled by default)
Best regards.
2026-01-21 5:32 AM
Hello! Thank you for your reply.
Yes, I activated EH. I am not using RFAL in the TAG system because I have a very large space limitation in the MCU. But my current configuration saves the active EH status from the ST25DV EEPROM.
/* ===============================================================================
2. Energy Harvesting (EH) Implementation
Usa o registro dinâmico EH_CTRL_Dyn (Volátil).
=============================================================================== */
int32_t ST25DV_EH_Enable_Dyn(st25dv_io_t *io) {
uint8_t reg_val;
int32_t status = io->i2c_read(ST25DV_ADDR_USER_DYN, ST25DV_REG_EH_CTRL_DYN, ®_val, 1);
if (status != 0) return status;
reg_val |= ST25DV_EH_EN_MASK; // Set bit 0
return io->i2c_write(ST25DV_ADDR_USER_DYN, ST25DV_REG_EH_CTRL_DYN, ®_val, 1);
}
int32_t ST25DV_EH_Disable_Dyn(st25dv_io_t *io) {
uint8_t reg_val;
int32_t status = io->i2c_read(ST25DV_ADDR_USER_DYN, ST25DV_REG_EH_CTRL_DYN, ®_val, 1);
if (status != 0) return status;
reg_val &= ~ST25DV_EH_EN_MASK; // Clear bit 0
return io->i2c_write(ST25DV_ADDR_USER_DYN, ST25DV_REG_EH_CTRL_DYN, ®_val, 1);
}
bool ST25DV_Field_On(st25dv_io_t *io) {
uint8_t reg_val;
io->i2c_read(ST25DV_ADDR_USER_DYN, ST25DV_REG_EH_CTRL_DYN, ®_val, 1);
return (reg_val & ST25DV_FIELD_ON_MASK) ? true : false;
}
/* ===============================================================================
Energy Harvesting - Configuração ESTÁTICA (EEPROM - Persistente)
Adicione estas funções ao seu st25dv_driver.c
=============================================================================== */
// Habilita Energy Harvesting de forma permanente (grava na EEPROM)
// Esta configuração persiste mesmo sem alimentação do MCU
int32_t ST25DV_EH_Enable_Static(st25dv_io_t *io) {
uint8_t reg_val;
// 1. Ler o valor atual do registro EH_MODE (0x0002) na área de sistema
int32_t status = io->i2c_read(ST25DV_ADDR_SYSCFG, ST25DV_REG_EH_MODE, ®_val, 1);
if (status != 0) return status;
// 2. Setar bit 0 (EH_EN) para habilitar permanentemente
reg_val |= ST25DV_EH_EN_MASK; // bit 0 = 1
// 3. Escrever de volta no registro (EEPROM)
status = io->i2c_write(ST25DV_ADDR_SYSCFG, ST25DV_REG_EH_MODE, ®_val, 1);
if (status != 0) return status;
// 4. Aguardar tempo de gravação na EEPROM (típico: 5ms, máx: 10ms)
io->delay_ms(10);
return 0;
}
// Desabilita Energy Harvesting de forma permanente (grava na EEPROM)
int32_t ST25DV_EH_Disable_Static(st25dv_io_t *io) {
uint8_t reg_val;
// 1. Ler o valor atual do registro EH_MODE (0x0002)
int32_t status = io->i2c_read(ST25DV_ADDR_SYSCFG, ST25DV_REG_EH_MODE, ®_val, 1);
if (status != 0) return status;
// 2. Limpar bit 0 (EH_EN) para desabilitar permanentemente
reg_val &= ~ST25DV_EH_EN_MASK; // bit 0 = 0
// 3. Escrever de volta no registro (EEPROM)
status = io->i2c_write(ST25DV_ADDR_SYSCFG, ST25DV_REG_EH_MODE, ®_val, 1);
if (status != 0) return status;
// 4. Aguardar tempo de gravação na EEPROM
io->delay_ms(10);
return 0;
}
// Lê a configuração permanente do Energy Harvesting (EEPROM)
// Retorna: 0 = Desabilitado, 1 = Habilitado
int32_t ST25DV_EH_ReadConfig_Static(st25dv_io_t *io, uint8_t *eh_enabled) {
uint8_t reg_val;
// Ler o registro EH_MODE (0x0002) na área de sistema
int32_t status = io->i2c_read(ST25DV_ADDR_SYSCFG, ST25DV_REG_EH_MODE, ®_val, 1);
if (status != 0) return status;
// Verificar bit 0
*eh_enabled = (reg_val & ST25DV_EH_EN_MASK) ? 1 : 0;
return 0;
}ST25Driver h:
/*
* st25dv_driver.h
*
* Created on: 14 de jan. de 2026
* Author: Matheus Markies
*/
#ifndef ST25DV_DRIVER_H
#define ST25DV_DRIVER_H
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
/* Endereços I2C (7-bit) baseados em E1=0, E0=0. Ajuste conforme seu hardware */
#define ST25DV_ADDR_USER_DYN 0x53 // E2=0
#define ST25DV_ADDR_SYSCFG 0x57 // E2=1
#define ST25DV_REG_IC_REF 0x0017
/* --- Mapeamento de Registros (System Configuration E2=1) --- */
#define ST25DV_REG_EH_MODE 0x0002 // [cite: 4259]
#define ST25DV_REG_MB_MODE 0x000D // [cite: 4259]
#define ST25DV_REG_MB_WDG 0x000E // [cite: 4259]
/* --- Mapeamento de Registros (Dynamic E2=0) --- */
#define ST25DV_REG_EH_CTRL_DYN 0x2002 // [cite: 4293]
#define ST25DV_REG_MB_CTRL_DYN 0x2006 // [cite: 4293]
#define ST25DV_REG_MB_LEN_DYN 0x2007 // [cite: 4293]
#define ST25DV_REG_MB_BUFFER 0x2008 // Início do buffer de 256 bytes [cite: 4311]
/* --- Máscaras de Bits --- */
// EH_CTRL_Dyn
#define ST25DV_EH_EN_MASK 0x01
#define ST25DV_EH_ON_MASK 0x02
#define ST25DV_FIELD_ON_MASK 0x04
#define ST25DV_VCC_ON_MASK 0x08
// MB_MODE [cite: 4361]
#define ST25DV_MB_MODE_RW 0x01
// MB_CTRL_Dyn [cite: 4377]
#define ST25DV_MB_EN_MASK 0x01
#define ST25DV_MB_HOST_PUT_MSG 0x02 // I2C colocou mensagem
#define ST25DV_MB_RF_PUT_MSG 0x04 // RF colocou mensagem
/* --- Estrutura do Driver (Abstração de Hardware) --- */
typedef struct {
// Ponteiros para funções de plataforma (I2C Read/Write, GPIO Write, Delay)
// addr: Endereço I2C do dispositivo (7-bit)
// reg: Endereço do registro (16-bit)
int32_t (*i2c_write)(uint8_t addr, uint16_t reg, uint8_t *data, uint16_t len);
int32_t (*i2c_read)(uint8_t addr, uint16_t reg, uint8_t *data, uint16_t len);
void (*set_lpd_pin)(uint8_t state); // 1 = High, 0 = Low
void (*delay_ms)(uint32_t ms);
} st25dv_io_t;
/* --- Protótipos das Funções --- */
// Inicialização
int32_t ST25DV_Init(st25dv_io_t *io);
int32_t ST25DV_ReadID(st25dv_io_t *io, uint8_t *id);
// 1. Low Power Mode
void ST25DV_LPD_Enable(st25dv_io_t *io); // Entra em baixo consumo
void ST25DV_LPD_Disable(st25dv_io_t *io); // Sai do baixo consumo (boot)
// 2. Energy Harvesting (Dinâmico)
int32_t ST25DV_EH_Enable_Dyn(st25dv_io_t *io);
int32_t ST25DV_EH_Disable_Dyn(st25dv_io_t *io);
int32_t ST25DV_EH_Enable_Static(st25dv_io_t *io);
int32_t ST25DV_EH_Disable_Static(st25dv_io_t *io);
int32_t ST25DV_EH_ReadConfig_Static(st25dv_io_t *io, uint8_t *eh_enabled);
bool ST25DV_EH_IsActive(st25dv_io_t *io);
bool ST25DV_Field_On(st25dv_io_t *io);
// 3. Mailbox (Fast Transfer Mode)
int32_t ST25DV_MB_Init(st25dv_io_t *io); // Habilita MB_MODE (Static)
int32_t ST25DV_MB_WriteMessage(st25dv_io_t *io, uint8_t *pData, uint8_t len);
int32_t ST25DV_MB_ReadMessage(st25dv_io_t *io, uint8_t *pData, uint8_t *pLen);
bool ST25DV_MB_HasMessageFromRF(st25dv_io_t *io);
int32_t ST25DV_MB_Enable_Static(st25dv_io_t *io);
int32_t ST25DV_MB_Disable_Static(st25dv_io_t *io);
int32_t ST25DV_MB_ReadConfig_Static(st25dv_io_t *io, uint8_t *mb_enabled);
int32_t ST25DV_MB_Enable_Dyn(st25dv_io_t *io);
int32_t ST25DV_MB_Init_Smart(st25dv_io_t *io);
int32_t ST25DV_I2C_PresentPassword(st25dv_io_t *io);
bool ST25DV_I2C_IsSessionOpen(st25dv_io_t *io);
#endif // ST25DV_DRIVER_H These codes are running on my own board and not on the X-NUCLEO-NFC04A1, as I wanted to test my entire system with Harvesting. The reader continues to be the X-NUCLEO-NFC12A1.
I realize that I have a big problem with my tag antenna, since it only works when it is touching the reader antenna. One of the problems I identified in the antenna is that its inductance does not match what was expected in the ST25DV. To correct this, I will add a 220pF capacitor in parallel (between AC1 and AC0).
2026-01-22 3:34 AM
Hello,
Are you enabling the EH from the static register (EEPROM)?
I think the ST25DV_EH_Enable_Static function is wrong. It looks like to me that it is setting bit 0 (EH)_EN) of static register EH_MODE to 1 to enable EH. If you look at the datasheet table 40, it must be set to 0 to enable EH. Actually, it is a bit of a trap as this bit is reversed compared to the EH_EN bit in the EH_CTRL_dyn register.
Best regards.
2026-01-22 5:40 AM
Thank you! I ended up overlooking that part. In addition, using an example such as polling in Reader made my field variable, which caused instability in reading. Now I have a value of 3.6V using X-Nucleos, and in the next steps I will implement it in my custom tag.