Skip to main content
RFlod.2
Associate III
April 24, 2026
Question

RFAL with ST25R3911B not working when porting from STM32L4 to STMG070

  • April 24, 2026
  • 8 replies
  • 248 views

I have been using RFAL succesfully with STM32L4. For a more price sensitive project I need to port the code to STMG070 and I cannot get RFID readings to work.

 

Measuring ampltiude gives same result on both codes:

st25r3911MeasureAmplitude(&c);
printf("Amplitude %d\n\r", c);

 

The following have been verified:

* Same RFID PCB is used for both processors (RFID PCB and processor PCB are connected by pin connector)

* Same RFID card is used

* Init of RFAL gives ID 13 on both codes

* GPIO interrups are generated

* Same LDO on both PCB

* Voltage to ST25R3911B is stable

* Both processors runs at same frequency 16 MHz

 

On STM32L4 the state change (during a succesful RFID read) of rfalNfcWorker goes like:

RFAL_NFC_STATE_IDLE

RFAL_NFC_STATE_POLL_TECHDETECT x 19

RFAL_NFC_STATE_POLL_COLAVOIDANCE x 29

RFAL_NFC_STATE_POLL_ACTIVATION x 2

But when running on STM32G070 

RFAL_NFC_STATE_IDLE

RFAL_NFC_STATE_POLL_TECHDETECT

RFAL_NFC_STATE_LISTEN_TECHDETECT until timeout

 

 

Anyone have any ideas what I should look into? Why is state change differently?

 

This is code on STM32L4 (which works):

#define platformSpiSelect() platformGpioClear(ST25R_SS_PORT, ST25R_SS_PIN)/*!< SPI SS\CS: Chip|Slave Select */
#define platformSpiDeselect() platformGpioSet(ST25R_SS_PORT, ST25R_SS_PIN) /*!< SPI SS\CS: Chip|Slave Deselect */
#define platformSpiTxRx( txBuf, rxBuf, len ) spiTxRx(txBuf, rxBuf, len) /*!< SPI transceive */


void SPI2_Init(void)
{
	LL_SPI_InitTypeDef SPI2_InitStruct;
	GPIO_InitTypeDef GPIO_InitStructure;
	__HAL_RCC_SPI2_FORCE_RESET();
	__HAL_RCC_SPI2_RELEASE_RESET();
	__HAL_RCC_SPI2_CLK_ENABLE();
	__HAL_RCC_GPIOB_CLK_ENABLE();

	GPIO_InitStructure.Pin = GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
	GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
	GPIO_InitStructure.Pull = GPIO_NOPULL;	//GPIO_PULLUP;
	GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
	GPIO_InitStructure.Alternate = GPIO_AF5_SPI2;

	HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);

	spi2Timeouts = 0;

	SPI2_InitStruct.TransferDirection = LL_SPI_FULL_DUPLEX;
	SPI2_InitStruct.Mode = LL_SPI_MODE_MASTER;
	SPI2_InitStruct.DataWidth = LL_SPI_DATAWIDTH_8BIT;
	SPI2_InitStruct.ClockPolarity = LL_SPI_POLARITY_LOW;
#ifdef RFID_STR25 //#elif RFID_PN5180
	SPI2_InitStruct.ClockPhase = LL_SPI_PHASE_2EDGE;
#else
	SPI2_InitStruct.ClockPhase = LL_SPI_PHASE_1EDGE;
#endif
	SPI2_InitStruct.NSS = LL_SPI_NSS_SOFT;
	SPI2_InitStruct.BitOrder = LL_SPI_MSB_FIRST;
	SPI2_InitStruct.CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE;
	SPI2_InitStruct.CRCPoly = 7U;

	SPI2_InitStruct.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV64;
	LL_SPI_Init(SPI2, &SPI2_InitStruct);

	// Check if the SPI is enabled
	if((SPI2->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE)
	{
	 // If disabled, I enable it
	 SET_BIT(SPI2->CR1, SPI_CR1_SPE);
	}

}


unsigned char SPI2_readWriteByte(unsigned char byte)
{
	volatile uint32_t wait = 0;
	//HW_UART_PutChar(LOG, '5');

	while (LL_SPI_IsActiveFlag_TXE(SPI2) == 0)
	{
		wait++;
		if(wait > MAX_WAIT)
		{
			printf("SPI2 timeout 1, %X\n\r", (int)SPI2->SR);
			spi2Timeouts++;
			SPI2_Init();
			return 0;
		}
	}
	/* Send byte through the SPI1 peripheral */
	LL_SPI_TransmitData8(SPI2, byte);
	/* Wait to receive a byte */
	wait = 0;
	SET_BIT(SPI2->CR2, SPI_RXFIFO_THRESHOLD);
	while(LL_SPI_IsActiveFlag_RXNE(SPI2) == 0)
	{
		wait++;
		if(wait > MAX_WAIT)
		{
			printf("SPI2 timeout 2, %X\n\r", (int)SPI2->SR);
			spi2Timeouts++;
			wait = LL_SPI_ReceiveData8(SPI1);
			SPI2_Init();
			return 0;
		}
	}
	/*if(LL_SPI_IsActiveFlag_RXNE(SPI1) == 0)
	{
		printf("SPI RX fel!\n\r");
		return 0;
	}*/
	spi2Timeouts = 0;
	/* Return the byte read from the SPI bus */
	return LL_SPI_ReceiveData8(SPI2);
}


#define SPI_TIMEOUT 1000
#define SPI_BUF_LEN 512


static uint8_t txBuf[SPI_BUF_LEN];
//static uint8_t rxBuf[SPI_BUF_LEN];

HAL_StatusTypeDef spiTxRx(const uint8_t *txData, uint8_t *rxData, uint16_t length)
{
	int i;
	uint8_t transmit;
	if(length > SPI_BUF_LEN)
	{
		return HAL_ERROR;
	}

	/* Initialize Tx data*/
	if(txData != NULL)
	{
		memcpy(txBuf, txData, length );
	}
	else
	{
		memset(txBuf, 0x00, length );
	}

	for(i = 0; i< length; i++)
	{
		transmit = txBuf[i];
		if(rxData != 0)
		{
			rxData[i] = SPI2_readWriteByte(transmit);
		}
		else
		{
			SPI2_readWriteByte(transmit);
		}
	}
	return HAL_OK;
}

 

This is code on STM32G070 (which doesn't work):

#define platformSpiSelect() platformGpioClear(ST25R_SS_PORT, ST25R_SS_PIN)/*!< SPI SS\CS: Chip|Slave Select */
#define platformSpiDeselect() platformGpioSet(ST25R_SS_PORT, ST25R_SS_PIN) /*!< SPI SS\CS: Chip|Slave Deselect */
#define platformSpiTxRx( txBuf, rxBuf, len ) spiTxRx(txBuf, rxBuf, len) /*!< SPI transceive */


void SPI1_Init(void)
{
	//SPI_InitTypeDef SPI_InitStructure;	GPIO_InitTypeDef GPIO_InitStruct;

	__HAL_RCC_SPI1_FORCE_RESET();
	__HAL_RCC_SPI1_RELEASE_RESET();
	__HAL_RCC_GPIOA_CLK_ENABLE();
	__HAL_RCC_SPI1_CLK_ENABLE();


	/**SPI1 GPIO Configuration
	PA5 ------> SPI1_SCK
	PA6 ------> SPI1_MISO
	PA7 ------> SPI1_MOSI
	*/

	GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
	GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
	GPIO_InitStruct.Alternate = GPIO_AF0_SPI1;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
	HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

	LL_SPI_InitTypeDef SPI_InitStruct = {0};

	SPI_InitStruct.TransferDirection = LL_SPI_FULL_DUPLEX;
	SPI_InitStruct.Mode = LL_SPI_MODE_MASTER;
	SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_8BIT;
	SPI_InitStruct.ClockPolarity = LL_SPI_POLARITY_LOW;
	SPI_InitStruct.ClockPhase = LL_SPI_PHASE_2EDGE;
	SPI_InitStruct.NSS = LL_SPI_NSS_SOFT;
	SPI_InitStruct.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV64;
	SPI_InitStruct.BitOrder = LL_SPI_MSB_FIRST;
	SPI_InitStruct.CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE;
	SPI_InitStruct.CRCPoly = 7U;
	LL_SPI_Init(SPI1, &SPI_InitStruct);

	/* Configure FIFO Threshold */
	/* Crucial for 8-bit data on G0: Set RX FIFO threshold to 1/4 (8-bit) */
	LL_SPI_SetRxFIFOThreshold(SPI1, LL_SPI_RX_FIFO_TH_QUARTER);

	/* Enable SPI */
	LL_SPI_Enable(SPI1);
}

unsigned char SPI1_readWriteByte(unsigned char byte)
{
	volatile uint32_t wait = 0;

	while (LL_SPI_IsActiveFlag_TXE(SPI1) == 0)
	{
		wait++;
		if(wait > MAX_WAIT)
		{
			printf("SPI timeout 1, %X\n\r", (int)SPI1->SR);
			SPI1_Init();
			return 0;
		}
	}
	/* Send byte through the SPI1 peripheral */
	LL_SPI_TransmitData8(SPI1, byte);
	/* Wait to receive a byte */
	wait = 0;
	SET_BIT(SPI1->CR2, SPI_RXFIFO_THRESHOLD);
	while(LL_SPI_IsActiveFlag_RXNE(SPI1) == 0)
	{
		wait++;
		if(wait > MAX_WAIT)
		{
			printf("SPI timeout 2, %X\n\r", (int)SPI1->SR);
			wait = LL_SPI_ReceiveData8(SPI1);
			SPI1_Init();
			return 0;
		}
	}
	/* Return the byte read from the SPI bus */
	return LL_SPI_ReceiveData8(SPI1);
}

 

8 replies

Brian TIDAL
Technical Moderator
April 24, 2026

Hi,

Could you enable ST25R_SELFTEST and ST25R_SELFTEST_TIMER and then check the return code of st25r3911Initialize?

Could you also check that the st25r3911Isr() function is properly called by the EXTIxx_IRQHandler?

Rgds

BT

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
RFlod.2
RFlod.2Author
Associate III
April 24, 2026

 

I defined ST25R_SELFTEST  and ST25R_SELFTEST_TIMER 

st25r3911Initialize returns RFAL_ERR_NONE 

 

As stated above, interupts are working.

Brian TIDAL
Technical Moderator
April 24, 2026

Hi,

 

Could you probe the RF field (just connect the tip of the scope probe to the GND of the probe to create a simple loop): do you see the 13.56MHz field being emitted? 

Could you connect a logic analyzer on SPI (CLK, MISO, MOSI, CS) and ST25R_IRQ pin and send us the raw log file?

Rgds

BT

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
RFlod.2
RFlod.2Author
Associate III
April 24, 2026

I am not sure I made correct but I tried this (sorry for bad web camera quality), and cannot see any change in signal of oscilloscope nor any sign of 13.56 MHz signal.

RFlod2_0-1777027104397.png

 

I will try to find and set up a logic analyzer

 

I also increased CPU frequency of STM32G070 from 16 to 64 MHz to minimize delays, no change in behaviour.

RFlod.2
RFlod.2Author
Associate III
April 24, 2026

Here is capture of SPI communcation.

RFlod2_0-1777034514168.png

 

First initiation of ST25R3911B  and then try to read RFID

RFlod.2
RFlod.2Author
Associate III
April 24, 2026

And SPI communication when reading amplitude which works good. Note that IRQ is set in both initiation and amplitude measurement but not when reading RFID card.

RFlod.2
RFlod.2Author
Associate III
April 24, 2026

Here are the same SPI sequences with STM32L4 where RFID reading works 

Brian TIDAL
Technical Moderator
April 24, 2026

Hi,

what is the priority setting of the various interrupts in STM32G0 and in STM32L4?

Rgds

BT

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
RFlod.2
RFlod.2Author
Associate III
April 24, 2026

STM32G070

	HAL_NVIC_SetPriority(TIM1_BRK_UP_TRG_COM_IRQn, 3, 0);
	HAL_NVIC_EnableIRQ(TIM1_BRK_UP_TRG_COM_IRQn);

	HAL_NVIC_SetPriority(TIM3_IRQn, 4, 0);
	HAL_NVIC_EnableIRQ(TIM3_IRQn);

	HAL_NVIC_SetPriority(EXTI4_15_IRQn, 5, 0);
	HAL_NVIC_EnableIRQ(EXTI4_15_IRQn);

 

STM32L4

 

	HAL_NVIC_SetPriority(TIM2_IRQn, 4, 0);
	HAL_NVIC_EnableIRQ(TIM2_IRQn);

	HAL_NVIC_SetPriority(TIM7_IRQn, 3, 0);
	HAL_NVIC_EnableIRQ(TIM7_IRQn);

	HAL_NVIC_SetPriority(RTC_WKUP_IRQn, 0x0, 0);
	HAL_NVIC_EnableIRQ(RTC_WKUP_IRQn);

	/* EXTI interrupt init*/
	HAL_NVIC_SetPriority(EXTI9_5_IRQn, 2, 0);
	HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
RFlod.2
RFlod.2Author
Associate III
April 24, 2026

I compared the init SPI commands and see that they do differ:

 

STM32G070:

RFlod2_0-1777043902064.png

STM32L4:

RFlod2_1-1777043913464.png

 

 

But I have no clue why....

 

 

 

 

Brian TIDAL
Technical Moderator
April 27, 2026

Hi,

make sure to configure the SPI decoder with CPHA=1 in Salae Logic:

BrianTIDAL_0-1777277932435.png

Rgds

BT

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
RFlod.2
RFlod.2Author
Associate III
April 27, 2026

Here is recorded data with  CPHA=1.

 

1) Init

2) Measure amplitude

3) Read RFID (which fails)

RFlod.2
RFlod.2Author
Associate III
April 24, 2026

Looking at the code and comparing with SPI commands I think STM32G070 looks more correct than STM32L4, which is confusing

ReturnCode st25r3911Initialize(void)
{
uint16_t vdd_mV;
ReturnCode ret;

/* Ensure a defined chip select state */
platformSpiDeselect();

/* Execute a Set Default on ST25R3911 */
st25r3911ExecuteCommand(ST25R3911_CMD_SET_DEFAULT);

/* Set Registers which are not affected by Set default command to default value */
st25r3911WriteRegister(ST25R3911_REG_OP_CONTROL, 0x00);
st25r3911WriteRegister(ST25R3911_REG_IO_CONF1, ST25R3911_REG_IO_CONF1_osc);
st25r3911WriteRegister(ST25R3911_REG_IO_CONF2, 0x00);


/* Enable pull downs on miso line */
st25r3911ModifyRegister(ST25R3911_REG_IO_CONF2, 0x00,
ST25R3911_REG_IO_CONF2_miso_pd1 |
ST25R3911_REG_IO_CONF2_miso_pd2);

 

Brian TIDAL
Technical Moderator
April 27, 2026

Hi,

my comment about the SPI decoder was related to the difference you have seen in the decoding between the STM32G0 and the STM32L4. With the proper CPHA=1 decoding, the init sequences are the same.

In your STM32G0 configuration, the output slew rate / drive capability of SPI IO is set to:

GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

whereas this is GPIO_SPEED_FREQ_ LOW in your STM32L4 configuration. I suggest aligning both configurations (GPIO_SPEED_FREQ_ LOW is probably enough but in case of doubt, check the signal integrity).

Also, could you set a breakpoint in rfalFieldOnAndStartGT and step in? What is the return code, what is the value of gRFAL.state and what is the value of st25r3911IsOscOn?

Could you as well check the stack size on the STM32G0 application?

Rgds

BT

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
RFlod.2
RFlod.2Author
Associate III
April 27, 2026

I have changed GPIO speed GPIO_SPEED_FREQ_ LOW.

Stack was 0x900.I changed to 0xBB8 (same as STM32L4 with same result)

The code does not reach rfalFieldOnAndStartGT

 

in  case RFAL_NFC_STATE_POLL_TECHDETECT:: 

rfalNfcPollTechDetection returns RFAL_ERR_NONE

 

It does enter any if cases in rfalNfcPollTechDetection 

Ulysses HERNIOSUS
Technical Moderator
April 27, 2026

Hi,

what are the values of gNfcDev.isFieldOn and gNfcDev.disc.techs2Find ???

Ulysses