cancel
Showing results for 
Search instead for 
Did you mean: 

How to minimize flash usage

LHabe.1
Associate II

Hello all, my company has decided to use the STM32L03 series for a simple ISO ​14443-3 tag reader, and we underestimated how much memory the full rfal takes up. Can anyone help me find an easier way to cut down the provided polling demo into 16k flash or less? I can scrap all other tag types except the T2T /nfc-a, and I only need read functionality. I am slowly working through and trimming the fat, but if there's a smarter way to limit program memory I'd be very thankful.

1 ACCEPTED SOLUTION

Accepted Solutions
Brian TIDAL
ST Employee

Hi Luke,

Can you share more information about your setup:

  • Do you use the ST25R3916 or the ST25R3911B reader?
  • What is your compiler?
  • which STM32L0 do you use?

The RFAL code is scalable through the platform.h file. To remove useless features in your application, you just need to change the "RFAL FEATURES CONFIGURATION" in the platform.h. For example, if your application only needs to support NFC-A/T2T tags, the following features configuration can be used.

/*
*****************************************************
* RFAL FEATURES CONFIGURATION
*****************************************************
*/
 
#define RFAL_FEATURE_LISTEN_MODE               false 
#define RFAL_FEATURE_WAKEUP_MODE               false 
#define RFAL_FEATURE_LOWPOWER_MODE             false 
#define RFAL_FEATURE_NFCA                      true  
#define RFAL_FEATURE_NFCB                      false 
#define RFAL_FEATURE_NFCF                      false 
#define RFAL_FEATURE_NFCV                      false 
#define RFAL_FEATURE_T1T                       false 
#define RFAL_FEATURE_T2T                       true  
#define RFAL_FEATURE_T4T                       false 
#define RFAL_FEATURE_ST25TB                    false 
#define RFAL_FEATURE_ST25xV                    false 
#define RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG     false 
#define RFAL_FEATURE_DPO                       false 
#define RFAL_FEATURE_ISO_DEP                   false 
#define RFAL_FEATURE_ISO_DEP_POLL              false 
#define RFAL_FEATURE_ISO_DEP_LISTEN            false 
#define RFAL_FEATURE_NFC_DEP                   false

Then, you can remove the USE_LOGGER define (printf on the serial console) and remove the UART.

Also, make sure to use the proper level of optimization in the compiler options (Optimize for size). See https://www.keil.com/appnotes/files/apnt202.pdf if using Keil µVision.

demo_polling.c file can also be modified to get rid of demoP2P, demoAPDU, demoNfcv, demoNfcf and demoCE and reduce the size of demo_polling.o.

You should then be close to the 16k flask size limit.

Once those suggestions are applied, feel free to share the map file of your application if you are still exceeding the 16k.

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.

View solution in original post

8 REPLIES 8
Brian TIDAL
ST Employee

Hi Luke,

Can you share more information about your setup:

  • Do you use the ST25R3916 or the ST25R3911B reader?
  • What is your compiler?
  • which STM32L0 do you use?

The RFAL code is scalable through the platform.h file. To remove useless features in your application, you just need to change the "RFAL FEATURES CONFIGURATION" in the platform.h. For example, if your application only needs to support NFC-A/T2T tags, the following features configuration can be used.

/*
*****************************************************
* RFAL FEATURES CONFIGURATION
*****************************************************
*/
 
#define RFAL_FEATURE_LISTEN_MODE               false 
#define RFAL_FEATURE_WAKEUP_MODE               false 
#define RFAL_FEATURE_LOWPOWER_MODE             false 
#define RFAL_FEATURE_NFCA                      true  
#define RFAL_FEATURE_NFCB                      false 
#define RFAL_FEATURE_NFCF                      false 
#define RFAL_FEATURE_NFCV                      false 
#define RFAL_FEATURE_T1T                       false 
#define RFAL_FEATURE_T2T                       true  
#define RFAL_FEATURE_T4T                       false 
#define RFAL_FEATURE_ST25TB                    false 
#define RFAL_FEATURE_ST25xV                    false 
#define RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG     false 
#define RFAL_FEATURE_DPO                       false 
#define RFAL_FEATURE_ISO_DEP                   false 
#define RFAL_FEATURE_ISO_DEP_POLL              false 
#define RFAL_FEATURE_ISO_DEP_LISTEN            false 
#define RFAL_FEATURE_NFC_DEP                   false

Then, you can remove the USE_LOGGER define (printf on the serial console) and remove the UART.

Also, make sure to use the proper level of optimization in the compiler options (Optimize for size). See https://www.keil.com/appnotes/files/apnt202.pdf if using Keil µVision.

demo_polling.c file can also be modified to get rid of demoP2P, demoAPDU, demoNfcv, demoNfcf and demoCE and reduce the size of demo_polling.o.

You should then be close to the 16k flask size limit.

Once those suggestions are applied, feel free to share the map file of your application if you are still exceeding the 16k.

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.

Thank you for the reply. We are using the ST25R3911B driven by the STM32L031G6U7 (32k), and compiling through the standard CubeIDE gcc compiler. I have tried ripping out all the non required architecture out manually, and was able to get down to 16k, but wasn't getting tag interrupts (after the initialization ones) so I probably removed something important.

I'll try a new build and only setup the platform as you suggest, and yes I still need to modify polling heavily.

I​ll send my mapping once I get that set up. Thanks

Brian TIDAL
ST Employee

Hi Luke,

regarding the interrupt issue:

  • make sure the ST25R311B IRQ pin is properly connected to a STM32L031 GPIO
  • make sure this GPIO is configured as GPIO_EXTIx External Interrupt mode with rising edge trigger detection, no pull up no pull down
  • make sure the EXTI Line x interrupt is enabled
  • make sure that st25r3911Isr(); is called in EXTIx_y_IRQHandler in stm32l0xx_it.c

See stm32l0xx_it.c in STM32CubeExpansion_NFC5_V2.0.0\Projects\STM32L053R8-Nucleo\Applications\PollingTagDetect\Src from X-CUBE-NFC5 package for an example of interrupt configuration on STM32L053.

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.

I was able to get it down to 37k with your suggested filtering and LDO optimization. Seems the lion share of this is in the nfcworker related functions and not the initialization. I still have the logger active as I will be using that anyway (and it only takes up about 2k). Below is the memory mapping down to 100B files:

FLASH		0x08000000				32 KB
.text		0x080000c0		0x080000c0		36.88 KB
HAL_RCC_OscConfig		0x08003720		0x08003720		1.74 KB
rfal_rfst25r3911.o		0x0800801c		0x0800801c		1.41 KB
UART_SetConfig		0x08004cd4		0x08004cd4		1.19 KB
rfalNfcaPollerSingleCollisionResolution		0x0800656c		0x0800656c		1.17 KB
demoCycle		0x080007d0		0x080007d0		1.03 KB
rfalSetBitRate		0x08007138		0x08007138		900 B
HAL_SPI_TransmitReceive		0x080045be		0x080045be		886 B
HAL_ADC_Init		0x080028b4		0x080028b4		744 B
HAL_GPIO_Init		0x080030f0		0x080030f0		732 B
rfal_rfst25r3911.o		0x08007d48		0x08007d48		724 B
HAL_RCC_ClockConfig		0x08003e18		0x08003e18		656 B
HAL_RCCEx_PeriphCLKConfig		0x08004260		0x08004260		588 B
rfalNfcaPollerFullCollisionResolution		0x08006a1c		0x08006a1c		576 B
rfalSetMode		0x08006ef8		0x08006ef8		576 B
rfal_nfc.o		0x08006180		0x08006180		568 B
rfalISO14443ATransceiveShortFrame		0x08008680		0x08008680		564 B
_printf_i		0x08008fd4		0x08008fd4		548 B
rfalISO14443ATransceiveAnticollisionFrame		0x080088b4		0x080088b4		544 B
rfalStartTransceive		0x08007680		0x08007680		516 B
_svfiprintf_r		0x08008cf4		0x08008cf4		512 B
_svfprintf_r		0x08008cf4		0x08008cf4		512 B
rfalNfcWorker		0x08005af8		0x08005af8		508 B
rfalNfcDiscover		0x08005810		0x08005810		440 B
rfalSetAnalogConfig		0x08005540		0x08005540		424 B
__udivmoddi4		0x080002d4		0x080002d4		408 B
UART_WaitOnFlagUntilTimeout		0x08005390		0x08005390		392 B
UART_AdvFeatureConfig		0x08005198		0x08005198		360 B
rfal_nfc.o		0x0800601c		0x0800601c		356 B
HAL_DMA_IRQHandler		0x08002f94		0x08002f94		348 B
rfal_nfc.o		0x08005ec0		0x08005ec0		348 B
HAL_UART_Transmit		0x08004b84		0x08004b84		336 B
HAL_RCC_GetSysClockFreq		0x080040a8		0x080040a8		332 B
rfal_rfst25r3911.o		0x08007c04		0x08007c04		324 B
rfalNfcaPollerSelect		0x08006c5c		0x08006c5c		320 B
MX_GPIO_Init		0x08000fa4		0x08000fa4		300 B
HAL_I2C_Init		0x080034c4		0x080034c4		300 B
st25r3911PerformCollisionAvoidance		0x08001e2c		0x08001e2c		294 B
rfalNfcDataExchangeStart		0x08005cf4		0x08005cf4		292 B
MX_ADC_Init		0x080004c0		0x080004c0		288 B
demo.o		0x08000dec		0x08000dec		284 B
stm32l0xx_hal_spi.o		0x08004934		0x08004934		284 B
rfal_rfst25r3911.o		0x08007abc		0x08007abc		284 B
HAL_SPI_Init		0x080044ac		0x080044ac		274 B
hex2Str		0x08001300		0x08001300		272 B
__aeabi_uidiv		0x0800012c		0x0800012c		268 B
__udivsi3		0x0800012c		0x0800012c		268 B
HAL_ADC_ConfigChannel		0x08002b9c		0x08002b9c		268 B
demo.o		0x08000cf0		0x08000cf0		252 B
HAL_DMA_Init		0x08002ea4		0x08002ea4		240 B
SystemClock_Config		0x080014c0		0x080014c0		236 B
rfal_analogConfig.o		0x080056e8		0x080056e8		236 B
_printf_common		0x08008ef4		0x08008ef4		222 B
stm32l0xx_hal_cortex.o		0x08002d1c		0x08002d1c		220 B
HAL_ADC_MspInit		0x080005e0		0x080005e0		216 B
HAL_I2C_MspInit		0x08001150		0x08001150		208 B
rfalFieldOnAndStartGT		0x08007588		0x08007588		204 B
__ssputs_r		0x08008c30		0x08008c30		196 B
_malloc_r		0x080092c8		0x080092c8		188 B
st25r3911AdjustRegulators		0x08001a64		0x08001a64		184 B
HAL_SPI_MspInit		0x08001628		0x08001628		180 B
rfalInitialize		0x08006dd4		0x08006dd4		180 B
main		0x08001410		0x08001410		176 B
HAL_UART_Init		0x08004adc		0x08004adc		168 B
rfalNfcDataExchangeGetStatus		0x08005e18		0x08005e18		168 B
st25r3911SetBitrate		0x08001b38		0x08001b38		166 B
demoIni		0x0800072c		0x0800072c		164 B
st25r3911ModifyInterrupts		0x080025a4		0x080025a4		160 B
st25r3911SetNoResponseTime_64fcs		0x08001d94		0x08001d94		152 B
HAL_I2CEx_ConfigAnalogFilter		0x080035f0		0x080035f0		152 B
HAL_I2CEx_ConfigDigitalFilter		0x08003688		0x08003688		152 B
_free_r		0x08009234		0x08009234		148 B
UART_CheckIdleState		0x08005300		0x08005300		144 B
stm32l0xx_hal_spi.o		0x08004a50		0x08004a50		140 B
demo.o		0x08000c00		0x08000c00		136 B
HAL_UART_MspInit		0x080018b8		0x080018b8		136 B
rfalTransceiveBlockingTx		0x080078cc		0x080078cc		130 B
rfalTransceiveBlockingTxRx		0x080079ba		0x080079ba		130 B
MX_I2C1_Init		0x080010d0		0x080010d0		128 B
st25r3911.o		0x08001f7c		0x08001f7c		120 B
st25r3911ChangeTestRegisterBits		0x08002384		0x08002384		118 B
demo.o		0x080006b8		0x080006b8		116 B
spiTxRx		0x080016dc		0x080016dc		116 B
MX_SPI1_Init		0x080015b8		0x080015b8		112 B
st25r3911ReadMultipleRegisters		0x0800209a		0x0800209a		112 B
st25r3911ModifyRegister		0x08002314		0x08002314		112 B
st25r3911WaitForInterruptsTimed		0x08002644		0x08002644		112 B
rfalNfcaPollerCheckPresence		0x080064a8		0x080064a8		112 B
rfalCalibrate		0x08006e88		0x08006e88		112 B
st25r3911ExecuteCommand		0x080024ba		0x080024ba		110 B
_sbrk		0x080017e0		0x080017e0		108 B
st25r3911ReadTestRegister		0x0800210a		0x0800210a		106 B
demo.o		0x08000c88		0x08000c88		104 B
st25r3911Initialize		0x080019fc		0x080019fc		104 B
st25r3911MeasureVoltage		0x08001c12		0x08001c12		104 B
HAL_InitTick		0x080027cc		0x080027cc		104 B
st25r3911WriteRegister		0x080021ce		0x080021ce		102 B
logUsartTx		0x0800123c		0x0800123c		100 B

IRQ is set up correctly, i was getting the original interrupts that get sent out during initialization, just not when in discovery mode (can't sense tags). Could be a hardware problem but i doubt it. I can activate the IRQ by applying a voltage directly.

Brian TIDAL
ST Employee

Hi,

ST25R3911B sends interrupts during initialization. For example when oscillator frequency is stable, I_osc is raised (see st25r3911OscOn()).

Can you share more details about your HW setup: do you use a custom board or a X-NUCLEO-NFC05A1 plugged onto a NUCLEO-L031K6?

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.

It's a custom board, but the schematic and layout of the RFID portion are almost identical to the X-NUCLEO-NFC05A1 expander (just without the capacitive sensor). It's worth noting that the initialization and rf calibration all pass, and i'm able to communicate with the R3911 fine. The current draw does seem low though if it is truly searching for passive tags. I would assume 100mA or so and it is in discovery mode at 16mA. I did order dev kits of the hardware to verify it's FW and not HW, but they will take a while.

LHabe.1
Associate II

Thank you for your continued support Brian. I had my compiler on Optimize Most (-O3) instead of for size (-Os). With that I was able to drop down to 27.7kB which is enough for testing the RFID at least. I'm sure I can scrounge around for the other 5k i'll need to add my other code back in.

Thanks!