L14-Click 1.0
STM32WLE5CC LoRaWAN Sensor Platform
Loading...
Searching...
No Matches
nfc_st25r3.c
Go to the documentation of this file.
1/*
2 * nfc_st25r3.c
3 *
4 * Created on: 27. 12. 2025
5 * Author: Milan
6 */
7
8#if KOKOT
9
10// ST25DV I2C Addresses
11#define NFC4_I2C_ADDR_USER (0x53 << 1) // User Memory/EEPROM
12#define NFC4_I2C_ADDR_SYSTEM (0x57 << 1) // System Configuration
13
14// Register Addresses
15#define REG_GPO_CTRL_DYN 0x2000
16#define REG_EH_CTRL_DYN 0x2001 /* Energy-harvesting / field-presence status */
17#define REG_MB_CTRL_DYN 0x200D //0x200D
18#define REG_MB_LEN_DYN 0x200E
19#define REG_MB_RAM_START 0x2008
20
21// EH_CTRL_DYN bit masks
22#define NFC4_EH_FIELD_ON 0x04 /* RF field is currently detected (FIELD_ON) */
23
24/* RF busy-wait limit: 20 × 5 ms = 100 ms maximum wait before giving up */
25#define NFC4_RF_BUSY_TIMEOUT 20U
26
27#include "i2c.h"
28#include "nfc_st25r3.h"
29#include <string.h>
30
31static int8_t _isNfc = 0; // indicator whether sensor is active
32
33int8_t nfc_st25r3_Is(I2C_HandleTypeDef *hi2c, int8_t tryInit)
34{
35 if (!_isNfc && tryInit)
36 nfc_st25r3_Init(hi2c);
37 return _isNfc;
38}
39
40static HAL_StatusTypeDef nfc_st25r3_PresentPassword(I2C_HandleTypeDef *hi2c)
41{
42 // Total 17 bytes: [0x09 (Validation Code)] + [8-byte PWD] + [8-byte PWD]
43 uint8_t pwd_payload[17];
44 pwd_payload[0] = 0x09;
45 memset(&pwd_payload[1], 0x00, 16); // Default 8x 00h, repeated twice
46
47 // MUST be written to 0x0900 in SYSTEM address space
48 return HAL_I2C_Mem_Write(hi2c, NFC4_I2C_ADDR_SYSTEM, 0x0900, 2, pwd_payload, 17, 200);
49}
50
51static HAL_StatusTypeDef nfc_st25r3_onOff(I2C_HandleTypeDef *hi2c, uint8_t onOff)
52{
53 HAL_StatusTypeDef status = HAL_ERROR;
54
55 if (_isNfc)
56 {
57 uint8_t reg_val, i; //, session_status = 0;
58
59 // Configure GPO for ALL events:
60 // 0x95 = GPO_EN(1), MsgReady(1), WriteEEPROM(1), FieldChange(1)
61 reg_val = onOff;//0x95;
62 for (i = 0; i < 5; i++)
63 {
64 status = HAL_I2C_Mem_Write(hi2c, NFC4_I2C_ADDR_USER, REG_GPO_CTRL_DYN, I2C_MEMADD_SIZE_16BIT, &reg_val, 1, 100);
65 if (status == HAL_OK)
66 break; // for
67 HAL_Delay(10);
68 }
69 _isNfc = (status == HAL_OK);
70 }
71 return status;
72}
73
74
75HAL_StatusTypeDef nfc_st25r3_On(I2C_HandleTypeDef *hi2c)
76{
77 // Configure GPO for ALL events:
78 // 0x95 = GPO_EN(1), MsgReady(1), WriteEEPROM(1), FieldChange(1)
79 return nfc_st25r3_onOff(hi2c, 0x95);
80}
81
82HAL_StatusTypeDef nfc_st25r3_Off(I2C_HandleTypeDef *hi2c)
83{
84 // Configure GPO for ALL events:
85 // 0x95 = GPO_EN(1), MsgReady(1), WriteEEPROM(1), FieldChange(1)
86 return nfc_st25r3_onOff(hi2c, 0x00);
87}
88
89HAL_StatusTypeDef nfc_st25r3_IsOn(I2C_HandleTypeDef *hi2c, uint8_t *onOff)
90{
91 HAL_StatusTypeDef status = HAL_ERROR;
92
93 if (_isNfc)
94 {
95 uint8_t reg_val = 0;
96 status = HAL_I2C_Mem_Read(hi2c, NFC4_I2C_ADDR_USER, REG_GPO_CTRL_DYN, I2C_MEMADD_SIZE_16BIT, &reg_val, 1, 100);
97 if (status == HAL_OK)
98 if (onOff != NULL)
99 *onOff = (reg_val & 0x80) != 0;
100 }
101 return status;
102}
103
104HAL_StatusTypeDef nfc_st25r3_Init(I2C_HandleTypeDef *hi2c)
105{
106 HAL_StatusTypeDef status;
107 uint8_t reg_val, i; //, session_status = 0;
108
109 do
110 {
111 // 1. Wait for device to be ready
112 if ((status = I2C_IsDeviceReadyMT(hi2c, NFC4_I2C_ADDR_USER, 10, 100)) != HAL_OK)
113 break;
114#if 0
115 // 2. Present Password to modify system registers
116 if ((status = nfc_st25r3_PresentPassword(hi2c)) != HAL_OK)
117 break;
118
119 // --- CRITICAL: Wait for the Session to stabilize ---
120 HAL_Delay(50);
121
122 // 3. Requires Password presentation first - this doesn't work
123
124 reg_val = 0x01;
125 if ((status = HAL_I2C_Mem_Write(hi2c, NFC4_I2C_ADDR_SYSTEM, 0x000D, 2, &reg_val, 1, 100)) != HAL_OK)
126 break;
127
128
129 /* coje toto ????? preco sa prepsuje - kokotina*/
130 // 4. Enable Mailbox (Dynamic RAM)
131 // We use a small loop because the RF field might cause a NACK
132 reg_val = 0x01;
133 for (i = 0; i < 5; i++)
134 {
135 status = HAL_I2C_Mem_Write(hi2c, NFC4_I2C_ADDR_USER, REG_MB_CTRL_DYN, I2C_MEMADD_SIZE_16BIT, &reg_val, 1, 100);
136 if (status == HAL_OK)
137 break; // for
138 HAL_Delay(10);
139 }
140 if (status != HAL_OK)
141 break;
142
143 // --- CRITICAL: Wait for the Session to stabilize ---
144 HAL_Delay(50);
145
146 // 5. FORCE CLEAR the status (The "Deadlock Breaker")
147 // This forces Bit 0 (Host Put) and Bit 1 (RF Put) to 0.
148 reg_val = 0x00;
149 if ((status = HAL_I2C_Mem_Write(hi2c, NFC4_I2C_ADDR_USER, REG_MB_CTRL_DYN, I2C_MEMADD_SIZE_16BIT, &reg_val, 1, 100)) != HAL_OK)
150 break;
151#endif
152 // --- MANDATORY DELAY ---
153 // The chip needs time to process the Mailbox Enable before changing GPO settings
154 HAL_Delay(20);
155 _isNfc = 1;
156 nfc_st25r3_Off(hi2c);
157 } while (0);
158 return status;
159}
160
161HAL_StatusTypeDef nfc_st25r3_ReadEEPROM(I2C_HandleTypeDef *hi2c, uint16_t addr, uint8_t *pData, uint16_t len)
162{
163 return (_isNfc) ? HAL_I2C_Mem_Read(hi2c, NFC4_I2C_ADDR_USER, addr, I2C_MEMADD_SIZE_16BIT, pData, len, 500) : HAL_ERROR;
164}
165
166int8_t nfc_st25r3_IsRFBusy(I2C_HandleTypeDef *hi2c)
167{
168 uint8_t reg_val = 0;
169
170 if (!_isNfc)
171 return 0;
172
173 /* Read EH_CTRL_DYN; if the I2C read fails assume the field is not active */
174 if (HAL_I2C_Mem_Read(hi2c, NFC4_I2C_ADDR_USER, REG_EH_CTRL_DYN,
175 I2C_MEMADD_SIZE_16BIT, &reg_val, 1, 50) != HAL_OK)
176 return 0;
177
178 /* FIELD_ON (bit 2) is set while an RF field is present */
179 return (reg_val & NFC4_EH_FIELD_ON) ? 1 : 0;
180}
181
182HAL_StatusTypeDef nfc_st25r3_WriteEEPROM(I2C_HandleTypeDef *hi2c, uint16_t addr, uint8_t *pData, uint16_t len)
183{
184 HAL_StatusTypeDef status = HAL_ERROR;
185
186 if (_isNfc)
187 {
188 status = HAL_OK;
189
190 /* Wait for RF write to complete
191 uint8_t retry_count = 0;
192 while (nfc_st25r3_IsRFBusy(hi2c) && status == HAL_OK)
193 {
194 HAL_Delay(5);
195 if (++retry_count >= NFC4_RF_BUSY_TIMEOUT)
196 status = HAL_TIMEOUT;
197 } */
198 if (status == HAL_OK)
199 do
200 {
201 uint16_t i = 0;
202 while (i < len)
203 {
204 /* ST25DV page size is 4 bytes for write operations */
205 /* Clip chunk to: remaining bytes, max 4, and must not cross 4-byte page */
206 uint16_t page_offset = (addr + i) % 4; // offset within current 4-byte page
207 uint16_t max_in_page = 4 - page_offset; // bytes left in this page
208 uint16_t remaining = len - i;
209 uint16_t chunk = remaining < max_in_page ? remaining : max_in_page;
210
211 /* Poll for ACK — device NACKs during internal write cycle */
212 uint8_t retry = 0;
213 do
214 {
215 status = HAL_I2C_Mem_Write(hi2c, NFC4_I2C_ADDR_USER, addr + i, I2C_MEMADD_SIZE_16BIT, &pData[i], chunk, 100);
216 if (status == HAL_OK)
217 break;
218 HAL_Delay(2);
219 } while (++retry < 10);
220
221 if (status != HAL_OK)
222 break;
223 i += chunk;
224 HAL_Delay(6); // tW: ensure write cycle completes before next page
225 }
226 }while(0);
227 }
228 return status;
229}
230
231void nfc_st25r3_ResetEEPROM(I2C_HandleTypeDef *hi2c, uint16_t len)
232{
233 uint8_t zero = 0;
234
235 if (_isNfc)
236 for (uint16_t i = 0; i < len; i++)
237 {
238 nfc_st25r3_WriteEEPROM(hi2c, i, &zero, 1);
239 }
240}
241
242HAL_StatusTypeDef nfc_st25r3_ProcessMailBox(I2C_HandleTypeDef *hi2c)
243{
244 uint8_t mb_ctrl, mb_len;
245
246 if (_isNfc)
247 {
248 // Check if Mailbox has a message from RF (Phone)
249 HAL_I2C_Mem_Read(hi2c, NFC4_I2C_ADDR_USER, REG_MB_CTRL_DYN, I2C_MEMADD_SIZE_16BIT, &mb_ctrl, 1, 100);
250
251 if (mb_ctrl & 0x02)
252 { // RF Put Msg bit
253 HAL_I2C_Mem_Read(hi2c, NFC4_I2C_ADDR_USER, REG_MB_LEN_DYN, I2C_MEMADD_SIZE_16BIT, &mb_len, 1, 100);
254 uint8_t buffer[256];
255 uint16_t msg_len = mb_len + 1;
256
257 HAL_I2C_Mem_Read(hi2c, NFC4_I2C_ADDR_USER, REG_MB_RAM_START, I2C_MEMADD_SIZE_16BIT, buffer, msg_len, 200);
258 nfc_st25r3_OnMailboxData(buffer, msg_len);
259 return HAL_OK;
260 }
261 }
262 return HAL_ERROR;
263}
264
265HAL_StatusTypeDef nfc_st25r3_WriteMailBoxNDEF(I2C_HandleTypeDef *hi2c, char *text)
266{
267 if (!_isNfc)
268 return HAL_ERROR;
269
270 uint8_t payload[128];
271 uint8_t text_len = strlen(text);
272
273 // Simple NDEF Text Record Wrapper
274 payload[0] = 0xD1; // MB=1, ME=1, SR=1, Tnf=1 (NFC Forum Well-known type)
275 payload[1] = 0x01; // Type Length
276 payload[2] = text_len + 3; // Payload Length (3 bytes for status/lang + text)
277 payload[3] = 'T'; // Type: Text
278 payload[4] = 0x02; // Status: UTF-8, "en" length = 2
279 payload[5] = 'e'; // 'e'
280 payload[6] = 'n'; // 'n'
281 memcpy(&payload[7], text, text_len);
282
283 return HAL_I2C_Mem_Write(hi2c, NFC4_I2C_ADDR_USER, REG_MB_RAM_START, I2C_MEMADD_SIZE_16BIT, payload, text_len + 7, 200);
284}
285
286HAL_StatusTypeDef nfc_st25r3_SetRFMgmt(I2C_HandleTypeDef *hi2c, uint8_t enable)
287{
288 if (!_isNfc)
289 return HAL_ERROR;
290
291 nfc_st25r3_PresentPassword(hi2c);
292 uint8_t val = enable ? 0x00 : 0x01; // 0 = RF Enabled, 1 = RF Disabled
293 return HAL_I2C_Mem_Write(hi2c, NFC4_I2C_ADDR_SYSTEM, 0x0003, 2, &val, 1, 100);
294}
295
296#endif
This file contains all the function prototypes for the i2c.c file.
HAL_StatusTypeDef I2C_IsDeviceReadyMT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Trials, uint32_t Timeout)
Wrapper around HAL_I2C_IsDeviceReady() that recovers from a busy bus. If the HAL I2C bus is in a BUSY...
Definition i2c.c:158
void nfc_st25r3_OnMailboxData(uint8_t *data, uint16_t len)
Definition mymems.c:303
static int8_t _isNfc
void HAL_Delay(__IO uint32_t Delay)
Definition sys_app.c:369