 389ff92cc1
			
		
	
	
		389ff92cc1
		
			
		
	
	
	
	
		
			
			* Makefile, Scripts: new linter * About: remove ID from IC * Firmware: remove double define for DIVC/DIVR * Scripts: check folder names too. Docker: replace syntax check with make lint. * Reformat Sources and Migrate to new file naming convention * Docker: symlink clang-format-12 to clang-format * Add coding style guide
		
			
				
	
	
		
			793 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			793 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
 | |
| /******************************************************************************
 | |
|   * \attention
 | |
|   *
 | |
|   * <h2><center>© COPYRIGHT 2020 STMicroelectronics</center></h2>
 | |
|   *
 | |
|   * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
 | |
|   * You may not use this file except in compliance with the License.
 | |
|   * You may obtain a copy of the License at:
 | |
|   *
 | |
|   *        www.st.com/myliberty
 | |
|   *
 | |
|   * Unless required by applicable law or agreed to in writing, software 
 | |
|   * distributed under the License is distributed on an "AS IS" BASIS, 
 | |
|   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
 | |
|   * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
 | |
|   * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
 | |
|   * See the License for the specific language governing permissions and
 | |
|   * limitations under the License.
 | |
|   *
 | |
| ******************************************************************************/
 | |
| 
 | |
| /*
 | |
|  *      PROJECT:   ST25R3916 firmware
 | |
|  *      Revision: 
 | |
|  *      LANGUAGE:  ISO C99
 | |
|  */
 | |
| 
 | |
| /*! \file
 | |
|  *
 | |
|  *  \author Gustavo Patricio
 | |
|  *
 | |
|  *  \brief ST25R3916 high level interface
 | |
|  *
 | |
|  */
 | |
| 
 | |
| /*
 | |
| ******************************************************************************
 | |
| * INCLUDES
 | |
| ******************************************************************************
 | |
| */
 | |
| 
 | |
| #include "st25r3916.h"
 | |
| #include "st25r3916_com.h"
 | |
| #include "st25r3916_led.h"
 | |
| #include "st25r3916_irq.h"
 | |
| #include "utils.h"
 | |
| 
 | |
| /*
 | |
| ******************************************************************************
 | |
| * LOCAL DEFINES
 | |
| ******************************************************************************
 | |
| */
 | |
| 
 | |
| #define ST25R3916_SUPPLY_THRESHOLD \
 | |
|     3600U /*!< Power supply measure threshold between 3.3V or 5V                   */
 | |
| #define ST25R3916_NRT_MAX \
 | |
|     0xFFFFU /*!< Max Register value of NRT                                           */
 | |
| 
 | |
| #define ST25R3916_TOUT_MEASURE_VDD \
 | |
|     100U /*!< Max duration time of Measure Power Supply command  Datasheet: 25us  */
 | |
| #define ST25R3916_TOUT_MEASURE_AMPLITUDE \
 | |
|     10U /*!< Max duration time of Measure Amplitude command     Datasheet: 25us  */
 | |
| #define ST25R3916_TOUT_MEASURE_PHASE \
 | |
|     10U /*!< Max duration time of Measure Phase command         Datasheet: 25us  */
 | |
| #define ST25R3916_TOUT_MEASURE_CAPACITANCE \
 | |
|     10U /*!< Max duration time of Measure Capacitance command   Datasheet: 25us  */
 | |
| #define ST25R3916_TOUT_CALIBRATE_CAP_SENSOR \
 | |
|     4U /*!< Max duration Calibrate Capacitive Sensor command   Datasheet: 3ms   */
 | |
| #define ST25R3916_TOUT_ADJUST_REGULATORS \
 | |
|     6U /*!< Max duration time of Adjust Regulators command     Datasheet: 5ms   */
 | |
| #define ST25R3916_TOUT_CA \
 | |
|     10U /*!< Max duration time of Collision Avoidance command                    */
 | |
| 
 | |
| #define ST25R3916_TEST_REG_PATTERN \
 | |
|     0x33U /*!< Register Read Write test pattern used during selftest               */
 | |
| #define ST25R3916_TEST_WU_TOUT \
 | |
|     12U /*!< Timeout used on WU timer during self test                           */
 | |
| #define ST25R3916_TEST_TMR_TOUT \
 | |
|     20U /*!< Timeout used during self test                                       */
 | |
| #define ST25R3916_TEST_TMR_TOUT_DELTA \
 | |
|     2U /*!< Timeout used during self test                                       */
 | |
| #define ST25R3916_TEST_TMR_TOUT_8FC \
 | |
|     (ST25R3916_TEST_TMR_TOUT * 16950U) /*!< Timeout in 8/fc                          */
 | |
| 
 | |
| /*
 | |
| ******************************************************************************
 | |
| * LOCAL CONSTANTS
 | |
| ******************************************************************************
 | |
| */
 | |
| 
 | |
| /*
 | |
| ******************************************************************************
 | |
| * LOCAL VARIABLES
 | |
| ******************************************************************************
 | |
| */
 | |
| 
 | |
| static uint32_t gST25R3916NRT_64fcs;
 | |
| 
 | |
| /*
 | |
| ******************************************************************************
 | |
| * LOCAL FUNCTION PROTOTYPES
 | |
| ******************************************************************************
 | |
| */
 | |
| 
 | |
| /*
 | |
|  ******************************************************************************
 | |
|  * LOCAL FUNCTION
 | |
|  ******************************************************************************
 | |
|  */
 | |
| 
 | |
| ReturnCode st25r3916ExecuteCommandAndGetResult(
 | |
|     uint8_t cmd,
 | |
|     uint8_t resReg,
 | |
|     uint8_t tout,
 | |
|     uint8_t* result) {
 | |
|     /* Clear and enable Direct Command interrupt */
 | |
|     st25r3916GetInterrupt(ST25R3916_IRQ_MASK_DCT);
 | |
|     st25r3916EnableInterrupts(ST25R3916_IRQ_MASK_DCT);
 | |
| 
 | |
|     st25r3916ExecuteCommand(cmd);
 | |
| 
 | |
|     st25r3916WaitForInterruptsTimed(ST25R3916_IRQ_MASK_DCT, tout);
 | |
|     st25r3916DisableInterrupts(ST25R3916_IRQ_MASK_DCT);
 | |
| 
 | |
|     /* After execution read out the result if the pointer is not NULL */
 | |
|     if(result != NULL) {
 | |
|         st25r3916ReadRegister(resReg, result);
 | |
|     }
 | |
| 
 | |
|     return ERR_NONE;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ******************************************************************************
 | |
| * GLOBAL FUNCTIONS
 | |
| ******************************************************************************
 | |
| */
 | |
| 
 | |
| ReturnCode st25r3916Initialize(void) {
 | |
|     uint16_t vdd_mV;
 | |
|     ReturnCode ret;
 | |
| 
 | |
|     /* Set default state on the ST25R3916 */
 | |
|     st25r3916ExecuteCommand(ST25R3916_CMD_SET_DEFAULT);
 | |
| 
 | |
| #ifndef RFAL_USE_I2C
 | |
|     /* Increase MISO driving level as SPI can go up to 10MHz */
 | |
|     st25r3916WriteRegister(ST25R3916_REG_IO_CONF2, ST25R3916_REG_IO_CONF2_io_drv_lvl);
 | |
| #endif /* RFAL_USE_I2C */
 | |
| 
 | |
|     if(!st25r3916CheckChipID(NULL)) {
 | |
|         platformErrorHandle();
 | |
|         return ERR_HW_MISMATCH;
 | |
|     }
 | |
| 
 | |
|     st25r3916InitInterrupts();
 | |
|     st25r3916ledInit();
 | |
| 
 | |
|     gST25R3916NRT_64fcs = 0;
 | |
| 
 | |
| #ifndef RFAL_USE_I2C
 | |
|     /* Enable pull downs on MISO line */
 | |
|     st25r3916SetRegisterBits(
 | |
|         ST25R3916_REG_IO_CONF2,
 | |
|         (ST25R3916_REG_IO_CONF2_miso_pd1 | ST25R3916_REG_IO_CONF2_miso_pd2));
 | |
| #endif /* RFAL_USE_I2C */
 | |
| 
 | |
|     /* Disable internal overheat protection */
 | |
|     st25r3916ChangeTestRegisterBits(0x04, 0x10, 0x10);
 | |
| 
 | |
| #ifdef ST25R_SELFTEST
 | |
|     /******************************************************************************
 | |
|      * Check communication interface: 
 | |
|      *  - write a pattern in a register
 | |
|      *  - reads back the register value
 | |
|      *  - return ERR_IO in case the read value is different
 | |
|      */
 | |
|     st25r3916WriteRegister(ST25R3916_REG_BIT_RATE, ST25R3916_TEST_REG_PATTERN);
 | |
|     if(!st25r3916CheckReg(
 | |
|            ST25R3916_REG_BIT_RATE,
 | |
|            (ST25R3916_REG_BIT_RATE_rxrate_mask | ST25R3916_REG_BIT_RATE_txrate_mask),
 | |
|            ST25R3916_TEST_REG_PATTERN)) {
 | |
|         platformErrorHandle();
 | |
|         return ERR_IO;
 | |
|     }
 | |
| 
 | |
|     /* Restore default value */
 | |
|     st25r3916WriteRegister(ST25R3916_REG_BIT_RATE, 0x00);
 | |
| 
 | |
|     /*
 | |
|      * Check IRQ Handling:
 | |
|      *  - use the Wake-up timer to trigger an IRQ
 | |
|      *  - wait the Wake-up timer interrupt
 | |
|      *  - return ERR_TIMEOUT when the Wake-up timer interrupt is not received
 | |
|      */
 | |
|     st25r3916WriteRegister(
 | |
|         ST25R3916_REG_WUP_TIMER_CONTROL,
 | |
|         ST25R3916_REG_WUP_TIMER_CONTROL_wur | ST25R3916_REG_WUP_TIMER_CONTROL_wto);
 | |
|     st25r3916EnableInterrupts(ST25R3916_IRQ_MASK_WT);
 | |
|     st25r3916ExecuteCommand(ST25R3916_CMD_START_WUP_TIMER);
 | |
|     if(st25r3916WaitForInterruptsTimed(ST25R3916_IRQ_MASK_WT, ST25R3916_TEST_WU_TOUT) == 0U) {
 | |
|         platformErrorHandle();
 | |
|         return ERR_TIMEOUT;
 | |
|     }
 | |
|     st25r3916DisableInterrupts(ST25R3916_IRQ_MASK_WT);
 | |
|     st25r3916WriteRegister(ST25R3916_REG_WUP_TIMER_CONTROL, 0U);
 | |
|     /*******************************************************************************/
 | |
| #endif /* ST25R_SELFTEST */
 | |
| 
 | |
|     /* Enable Oscillator and wait until it gets stable */
 | |
|     ret = st25r3916OscOn();
 | |
|     if(ret != ERR_NONE) {
 | |
|         platformErrorHandle();
 | |
|         return ret;
 | |
|     }
 | |
| 
 | |
|     /* Measure VDD and set sup3V bit according to Power supplied  */
 | |
|     vdd_mV = st25r3916MeasureVoltage(ST25R3916_REG_REGULATOR_CONTROL_mpsv_vdd);
 | |
|     st25r3916ChangeRegisterBits(
 | |
|         ST25R3916_REG_IO_CONF2,
 | |
|         ST25R3916_REG_IO_CONF2_sup3V,
 | |
|         ((vdd_mV < ST25R3916_SUPPLY_THRESHOLD) ? ST25R3916_REG_IO_CONF2_sup3V_3V :
 | |
|                                                  ST25R3916_REG_IO_CONF2_sup3V_5V));
 | |
| 
 | |
|     /* Make sure Transmitter and Receiver are disabled */
 | |
|     st25r3916TxRxOff();
 | |
| 
 | |
| #ifdef ST25R_SELFTEST_TIMER
 | |
|     /******************************************************************************
 | |
|      * Check SW timer operation :
 | |
|      *  - use the General Purpose timer to measure an amount of time
 | |
|      *  - test whether an interrupt is seen when less time was given
 | |
|      *  - test whether an interrupt is seen when sufficient time was given
 | |
|      */
 | |
| 
 | |
|     st25r3916EnableInterrupts(ST25R3916_IRQ_MASK_GPE);
 | |
|     st25r3916SetStartGPTimer(
 | |
|         (uint16_t)ST25R3916_TEST_TMR_TOUT_8FC, ST25R3916_REG_TIMER_EMV_CONTROL_gptc_no_trigger);
 | |
|     if(st25r3916WaitForInterruptsTimed(
 | |
|            ST25R3916_IRQ_MASK_GPE, (ST25R3916_TEST_TMR_TOUT - ST25R3916_TEST_TMR_TOUT_DELTA)) !=
 | |
|        0U) {
 | |
|         platformErrorHandle();
 | |
|         return ERR_SYSTEM;
 | |
|     }
 | |
| 
 | |
|     /* Stop all activities to stop the GP timer */
 | |
|     st25r3916ExecuteCommand(ST25R3916_CMD_STOP);
 | |
|     st25r3916ClearAndEnableInterrupts(ST25R3916_IRQ_MASK_GPE);
 | |
|     st25r3916SetStartGPTimer(
 | |
|         (uint16_t)ST25R3916_TEST_TMR_TOUT_8FC, ST25R3916_REG_TIMER_EMV_CONTROL_gptc_no_trigger);
 | |
|     if(st25r3916WaitForInterruptsTimed(
 | |
|            ST25R3916_IRQ_MASK_GPE, (ST25R3916_TEST_TMR_TOUT + ST25R3916_TEST_TMR_TOUT_DELTA)) ==
 | |
|        0U) {
 | |
|         platformErrorHandle();
 | |
|         return ERR_SYSTEM;
 | |
|     }
 | |
| 
 | |
|     /* Stop all activities to stop the GP timer */
 | |
|     st25r3916ExecuteCommand(ST25R3916_CMD_STOP);
 | |
|     /*******************************************************************************/
 | |
| #endif /* ST25R_SELFTEST_TIMER */
 | |
| 
 | |
|     /* After reset all interrupts are enabled, so disable them at first */
 | |
|     st25r3916DisableInterrupts(ST25R3916_IRQ_MASK_ALL);
 | |
| 
 | |
|     /* And clear them, just to be sure */
 | |
|     st25r3916ClearInterrupts();
 | |
| 
 | |
|     return ERR_NONE;
 | |
| }
 | |
| 
 | |
| /*******************************************************************************/
 | |
| void st25r3916Deinitialize(void) {
 | |
|     st25r3916DisableInterrupts(ST25R3916_IRQ_MASK_ALL);
 | |
| 
 | |
|     /* Disabe Tx and Rx, Keep OSC On */
 | |
|     st25r3916TxRxOff();
 | |
| 
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*******************************************************************************/
 | |
| ReturnCode st25r3916OscOn(void) {
 | |
|     /* Check if oscillator is already turned on and stable                                                */
 | |
|     /* Use ST25R3916_REG_OP_CONTROL_en instead of ST25R3916_REG_AUX_DISPLAY_osc_ok to be on the safe side */
 | |
|     if(!st25r3916CheckReg(
 | |
|            ST25R3916_REG_OP_CONTROL, ST25R3916_REG_OP_CONTROL_en, ST25R3916_REG_OP_CONTROL_en)) {
 | |
|         /* Clear any eventual previous oscillator IRQ */
 | |
|         st25r3916GetInterrupt(ST25R3916_IRQ_MASK_OSC);
 | |
| 
 | |
|         /* Enable oscillator frequency stable interrupt */
 | |
|         st25r3916EnableInterrupts(ST25R3916_IRQ_MASK_OSC);
 | |
| 
 | |
|         /* Enable oscillator and regulator output */
 | |
|         st25r3916SetRegisterBits(ST25R3916_REG_OP_CONTROL, ST25R3916_REG_OP_CONTROL_en);
 | |
| 
 | |
|         /* Wait for the oscillator interrupt */
 | |
|         st25r3916WaitForInterruptsTimed(ST25R3916_IRQ_MASK_OSC, ST25R3916_TOUT_OSC_STABLE);
 | |
|         st25r3916DisableInterrupts(ST25R3916_IRQ_MASK_OSC);
 | |
|     }
 | |
| 
 | |
|     if(!st25r3916CheckReg(
 | |
|            ST25R3916_REG_AUX_DISPLAY,
 | |
|            ST25R3916_REG_AUX_DISPLAY_osc_ok,
 | |
|            ST25R3916_REG_AUX_DISPLAY_osc_ok)) {
 | |
|         return ERR_SYSTEM;
 | |
|     }
 | |
| 
 | |
|     return ERR_NONE;
 | |
| }
 | |
| 
 | |
| /*******************************************************************************/
 | |
| uint8_t st25r3916MeasurePowerSupply(uint8_t mpsv) {
 | |
|     uint8_t result;
 | |
| 
 | |
|     /* Set the source of direct command: Measure Power Supply Voltage */
 | |
|     st25r3916ChangeRegisterBits(
 | |
|         ST25R3916_REG_REGULATOR_CONTROL, ST25R3916_REG_REGULATOR_CONTROL_mpsv_mask, mpsv);
 | |
| 
 | |
|     /* Execute command: Measure Power Supply Voltage */
 | |
|     st25r3916ExecuteCommandAndGetResult(
 | |
|         ST25R3916_CMD_MEASURE_VDD, ST25R3916_REG_AD_RESULT, ST25R3916_TOUT_MEASURE_VDD, &result);
 | |
| 
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| /*******************************************************************************/
 | |
| uint16_t st25r3916MeasureVoltage(uint8_t mpsv) {
 | |
|     uint8_t result;
 | |
|     uint16_t mV;
 | |
| 
 | |
|     result = st25r3916MeasurePowerSupply(mpsv);
 | |
| 
 | |
|     /* Convert cmd output into mV (each step represents 23.4 mV )*/
 | |
|     mV = ((uint16_t)result) * 23U;
 | |
|     mV += (((((uint16_t)result) * 4U) + 5U) / 10U);
 | |
| 
 | |
|     return mV;
 | |
| }
 | |
| 
 | |
| /*******************************************************************************/
 | |
| ReturnCode st25r3916AdjustRegulators(uint16_t* result_mV) {
 | |
|     uint8_t result;
 | |
| 
 | |
|     /* Reset logic and set regulated voltages to be defined by result of Adjust Regulators command */
 | |
|     st25r3916SetRegisterBits(
 | |
|         ST25R3916_REG_REGULATOR_CONTROL, ST25R3916_REG_REGULATOR_CONTROL_reg_s);
 | |
|     st25r3916ClrRegisterBits(
 | |
|         ST25R3916_REG_REGULATOR_CONTROL, ST25R3916_REG_REGULATOR_CONTROL_reg_s);
 | |
| 
 | |
|     /* Execute Adjust regulators cmd and retrieve result */
 | |
|     st25r3916ExecuteCommandAndGetResult(
 | |
|         ST25R3916_CMD_ADJUST_REGULATORS,
 | |
|         ST25R3916_REG_REGULATOR_RESULT,
 | |
|         ST25R3916_TOUT_ADJUST_REGULATORS,
 | |
|         &result);
 | |
| 
 | |
|     /* Calculate result in mV */
 | |
|     result >>= ST25R3916_REG_REGULATOR_RESULT_reg_shift;
 | |
| 
 | |
|     if(result_mV != NULL) {
 | |
|         if(st25r3916CheckReg(
 | |
|                ST25R3916_REG_IO_CONF2,
 | |
|                ST25R3916_REG_IO_CONF2_sup3V,
 | |
|                ST25R3916_REG_IO_CONF2_sup3V)) {
 | |
|             result = MIN(
 | |
|                 result,
 | |
|                 (uint8_t)(result - 5U)); /* In 3.3V mode [0,4] are not used                       */
 | |
|             *result_mV = 2400U; /* Minimum regulated voltage 2.4V in case of 3.3V supply */
 | |
|         } else {
 | |
|             *result_mV = 3600U; /* Minimum regulated voltage 3.6V in case of 5V supply   */
 | |
|         }
 | |
| 
 | |
|         *result_mV +=
 | |
|             (uint16_t)result * 100U; /* 100mV steps in both 3.3V and 5V supply                */
 | |
|     }
 | |
|     return ERR_NONE;
 | |
| }
 | |
| 
 | |
| /*******************************************************************************/
 | |
| ReturnCode st25r3916MeasureAmplitude(uint8_t* result) {
 | |
|     return st25r3916ExecuteCommandAndGetResult(
 | |
|         ST25R3916_CMD_MEASURE_AMPLITUDE,
 | |
|         ST25R3916_REG_AD_RESULT,
 | |
|         ST25R3916_TOUT_MEASURE_AMPLITUDE,
 | |
|         result);
 | |
| }
 | |
| 
 | |
| /*******************************************************************************/
 | |
| ReturnCode st25r3916MeasurePhase(uint8_t* result) {
 | |
|     return st25r3916ExecuteCommandAndGetResult(
 | |
|         ST25R3916_CMD_MEASURE_PHASE, ST25R3916_REG_AD_RESULT, ST25R3916_TOUT_MEASURE_PHASE, result);
 | |
| }
 | |
| 
 | |
| /*******************************************************************************/
 | |
| ReturnCode st25r3916MeasureCapacitance(uint8_t* result) {
 | |
|     return st25r3916ExecuteCommandAndGetResult(
 | |
|         ST25R3916_CMD_MEASURE_CAPACITANCE,
 | |
|         ST25R3916_REG_AD_RESULT,
 | |
|         ST25R3916_TOUT_MEASURE_CAPACITANCE,
 | |
|         result);
 | |
| }
 | |
| 
 | |
| /*******************************************************************************/
 | |
| ReturnCode st25r3916CalibrateCapacitiveSensor(uint8_t* result) {
 | |
|     ReturnCode ret;
 | |
|     uint8_t res;
 | |
| 
 | |
|     /* Clear Manual calibration values to enable automatic calibration mode */
 | |
|     st25r3916ClrRegisterBits(
 | |
|         ST25R3916_REG_CAP_SENSOR_CONTROL, ST25R3916_REG_CAP_SENSOR_CONTROL_cs_mcal_mask);
 | |
| 
 | |
|     /* Execute automatic calibration */
 | |
|     ret = st25r3916ExecuteCommandAndGetResult(
 | |
|         ST25R3916_CMD_CALIBRATE_C_SENSOR,
 | |
|         ST25R3916_REG_CAP_SENSOR_RESULT,
 | |
|         ST25R3916_TOUT_CALIBRATE_CAP_SENSOR,
 | |
|         &res);
 | |
| 
 | |
|     /* Check wether the calibration was successull */
 | |
|     if(((res & ST25R3916_REG_CAP_SENSOR_RESULT_cs_cal_end) !=
 | |
|         ST25R3916_REG_CAP_SENSOR_RESULT_cs_cal_end) ||
 | |
|        ((res & ST25R3916_REG_CAP_SENSOR_RESULT_cs_cal_err) ==
 | |
|         ST25R3916_REG_CAP_SENSOR_RESULT_cs_cal_err) ||
 | |
|        (ret != ERR_NONE)) {
 | |
|         return ERR_IO;
 | |
|     }
 | |
| 
 | |
|     if(result != NULL) {
 | |
|         (*result) = (uint8_t)(res >> ST25R3916_REG_CAP_SENSOR_RESULT_cs_cal_shift);
 | |
|     }
 | |
| 
 | |
|     return ERR_NONE;
 | |
| }
 | |
| 
 | |
| /*******************************************************************************/
 | |
| ReturnCode st25r3916SetBitrate(uint8_t txrate, uint8_t rxrate) {
 | |
|     uint8_t reg;
 | |
| 
 | |
|     st25r3916ReadRegister(ST25R3916_REG_BIT_RATE, ®);
 | |
|     if(rxrate != ST25R3916_BR_DO_NOT_SET) {
 | |
|         if(rxrate > ST25R3916_BR_848) {
 | |
|             return ERR_PARAM;
 | |
|         }
 | |
| 
 | |
|         reg = (uint8_t)(reg & ~ST25R3916_REG_BIT_RATE_rxrate_mask); /* MISRA 10.3 */
 | |
|         reg |= rxrate << ST25R3916_REG_BIT_RATE_rxrate_shift;
 | |
|     }
 | |
|     if(txrate != ST25R3916_BR_DO_NOT_SET) {
 | |
|         if(txrate > ST25R3916_BR_6780) {
 | |
|             return ERR_PARAM;
 | |
|         }
 | |
| 
 | |
|         reg = (uint8_t)(reg & ~ST25R3916_REG_BIT_RATE_txrate_mask); /* MISRA 10.3 */
 | |
|         reg |= txrate << ST25R3916_REG_BIT_RATE_txrate_shift;
 | |
|     }
 | |
|     return st25r3916WriteRegister(ST25R3916_REG_BIT_RATE, reg);
 | |
| }
 | |
| 
 | |
| /*******************************************************************************/
 | |
| ReturnCode st25r3916PerformCollisionAvoidance(
 | |
|     uint8_t FieldONCmd,
 | |
|     uint8_t pdThreshold,
 | |
|     uint8_t caThreshold,
 | |
|     uint8_t nTRFW) {
 | |
|     uint8_t treMask;
 | |
|     uint32_t irqs;
 | |
|     ReturnCode err;
 | |
| 
 | |
|     if((FieldONCmd != ST25R3916_CMD_INITIAL_RF_COLLISION) &&
 | |
|        (FieldONCmd != ST25R3916_CMD_RESPONSE_RF_COLLISION_N)) {
 | |
|         return ERR_PARAM;
 | |
|     }
 | |
| 
 | |
|     err = ERR_INTERNAL;
 | |
| 
 | |
|     /* Check if new thresholds are to be applied */
 | |
|     if((pdThreshold != ST25R3916_THRESHOLD_DO_NOT_SET) ||
 | |
|        (caThreshold != ST25R3916_THRESHOLD_DO_NOT_SET)) {
 | |
|         treMask = 0;
 | |
| 
 | |
|         if(pdThreshold != ST25R3916_THRESHOLD_DO_NOT_SET) {
 | |
|             treMask |= ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_mask;
 | |
|         }
 | |
| 
 | |
|         if(caThreshold != ST25R3916_THRESHOLD_DO_NOT_SET) {
 | |
|             treMask |= ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_mask;
 | |
|         }
 | |
| 
 | |
|         /* Set Detection Threshold and|or Collision Avoidance Threshold */
 | |
|         st25r3916ChangeRegisterBits(
 | |
|             ST25R3916_REG_FIELD_THRESHOLD_ACTV,
 | |
|             treMask,
 | |
|             (pdThreshold & ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_mask) |
 | |
|                 (caThreshold & ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_mask));
 | |
|     }
 | |
| 
 | |
|     /* Set n x TRFW */
 | |
|     st25r3916ChangeRegisterBits(ST25R3916_REG_AUX, ST25R3916_REG_AUX_nfc_n_mask, nTRFW);
 | |
| 
 | |
|     /*******************************************************************************/
 | |
|     /* Enable and clear CA specific interrupts and execute command */
 | |
|     st25r3916GetInterrupt(
 | |
|         (ST25R3916_IRQ_MASK_CAC | ST25R3916_IRQ_MASK_CAT | ST25R3916_IRQ_MASK_APON));
 | |
|     st25r3916EnableInterrupts(
 | |
|         (ST25R3916_IRQ_MASK_CAC | ST25R3916_IRQ_MASK_CAT | ST25R3916_IRQ_MASK_APON));
 | |
| 
 | |
|     st25r3916ExecuteCommand(FieldONCmd);
 | |
| 
 | |
|     /*******************************************************************************/
 | |
|     /* Wait for initial APON interrupt, indicating anticollision avoidance done and ST25R3916's 
 | |
|      * field is now on, or a CAC indicating a collision */
 | |
|     irqs = st25r3916WaitForInterruptsTimed(
 | |
|         (ST25R3916_IRQ_MASK_CAC | ST25R3916_IRQ_MASK_APON), ST25R3916_TOUT_CA);
 | |
| 
 | |
|     if((ST25R3916_IRQ_MASK_CAC & irqs) != 0U) /* Collision occurred */
 | |
|     {
 | |
|         err = ERR_RF_COLLISION;
 | |
|     } else if((ST25R3916_IRQ_MASK_APON & irqs) != 0U) {
 | |
|         /* After APON wait for CAT interrupt, indication field was switched on minimum guard time has been fulfilled */
 | |
|         irqs = st25r3916WaitForInterruptsTimed((ST25R3916_IRQ_MASK_CAT), ST25R3916_TOUT_CA);
 | |
| 
 | |
|         if((ST25R3916_IRQ_MASK_CAT & irqs) != 0U) /* No Collision detected, Field On */
 | |
|         {
 | |
|             err = ERR_NONE;
 | |
|         }
 | |
|     } else {
 | |
|         /* MISRA 15.7 - Empty else */
 | |
|     }
 | |
| 
 | |
|     /* Clear any previous External Field events and disable CA specific interrupts */
 | |
|     st25r3916GetInterrupt((ST25R3916_IRQ_MASK_EOF | ST25R3916_IRQ_MASK_EON));
 | |
|     st25r3916DisableInterrupts(
 | |
|         (ST25R3916_IRQ_MASK_CAC | ST25R3916_IRQ_MASK_CAT | ST25R3916_IRQ_MASK_APON));
 | |
| 
 | |
|     return err;
 | |
| }
 | |
| 
 | |
| /*******************************************************************************/
 | |
| void st25r3916SetNumTxBits(uint16_t nBits) {
 | |
|     st25r3916WriteRegister(ST25R3916_REG_NUM_TX_BYTES2, (uint8_t)((nBits >> 0) & 0xFFU));
 | |
|     st25r3916WriteRegister(ST25R3916_REG_NUM_TX_BYTES1, (uint8_t)((nBits >> 8) & 0xFFU));
 | |
| }
 | |
| 
 | |
| /*******************************************************************************/
 | |
| uint16_t st25r3916GetNumFIFOBytes(void) {
 | |
|     uint8_t reg;
 | |
|     uint16_t result;
 | |
| 
 | |
|     st25r3916ReadRegister(ST25R3916_REG_FIFO_STATUS2, ®);
 | |
|     reg =
 | |
|         ((reg & ST25R3916_REG_FIFO_STATUS2_fifo_b_mask) >>
 | |
|          ST25R3916_REG_FIFO_STATUS2_fifo_b_shift);
 | |
|     result = ((uint16_t)reg << 8);
 | |
| 
 | |
|     st25r3916ReadRegister(ST25R3916_REG_FIFO_STATUS1, ®);
 | |
|     result |= (((uint16_t)reg) & 0x00FFU);
 | |
| 
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| /*******************************************************************************/
 | |
| uint8_t st25r3916GetNumFIFOLastBits(void) {
 | |
|     uint8_t reg;
 | |
| 
 | |
|     st25r3916ReadRegister(ST25R3916_REG_FIFO_STATUS2, ®);
 | |
| 
 | |
|     return (
 | |
|         (reg & ST25R3916_REG_FIFO_STATUS2_fifo_lb_mask) >>
 | |
|         ST25R3916_REG_FIFO_STATUS2_fifo_lb_shift);
 | |
| }
 | |
| 
 | |
| /*******************************************************************************/
 | |
| uint32_t st25r3916GetNoResponseTime(void) {
 | |
|     return gST25R3916NRT_64fcs;
 | |
| }
 | |
| 
 | |
| /*******************************************************************************/
 | |
| ReturnCode st25r3916SetNoResponseTime(uint32_t nrt_64fcs) {
 | |
|     ReturnCode err;
 | |
|     uint8_t nrt_step;
 | |
|     uint32_t tmpNRT;
 | |
| 
 | |
|     tmpNRT = nrt_64fcs; /* MISRA 17.8 */
 | |
|     err = ERR_NONE;
 | |
| 
 | |
|     gST25R3916NRT_64fcs = tmpNRT; /* Store given NRT value in 64/fc into local var       */
 | |
|     nrt_step =
 | |
|         ST25R3916_REG_TIMER_EMV_CONTROL_nrt_step_64fc; /* Set default NRT in steps of 64/fc                   */
 | |
| 
 | |
|     if(tmpNRT > ST25R3916_NRT_MAX) /* Check if the given NRT value fits using 64/fc steps */
 | |
|     {
 | |
|         nrt_step =
 | |
|             ST25R3916_REG_TIMER_EMV_CONTROL_nrt_step_4096_fc; /* If not, change NRT set to 4096/fc                   */
 | |
|         tmpNRT = ((tmpNRT + 63U) / 64U); /* Calculate number of steps in 4096/fc                */
 | |
| 
 | |
|         if(tmpNRT > ST25R3916_NRT_MAX) /* Check if the NRT value fits using 64/fc steps       */
 | |
|         {
 | |
|             tmpNRT = ST25R3916_NRT_MAX; /* Assign the maximum possible                         */
 | |
|             err = ERR_PARAM; /* Signal parameter error                              */
 | |
|         }
 | |
|         gST25R3916NRT_64fcs = (64U * tmpNRT);
 | |
|     }
 | |
| 
 | |
|     /* Set the ST25R3916 NRT step units and the value */
 | |
|     st25r3916ChangeRegisterBits(
 | |
|         ST25R3916_REG_TIMER_EMV_CONTROL, ST25R3916_REG_TIMER_EMV_CONTROL_nrt_step, nrt_step);
 | |
|     st25r3916WriteRegister(ST25R3916_REG_NO_RESPONSE_TIMER1, (uint8_t)(tmpNRT >> 8U));
 | |
|     st25r3916WriteRegister(ST25R3916_REG_NO_RESPONSE_TIMER2, (uint8_t)(tmpNRT & 0xFFU));
 | |
| 
 | |
|     return err;
 | |
| }
 | |
| 
 | |
| /*******************************************************************************/
 | |
| ReturnCode st25r3916SetStartNoResponseTimer(uint32_t nrt_64fcs) {
 | |
|     ReturnCode err;
 | |
| 
 | |
|     err = st25r3916SetNoResponseTime(nrt_64fcs);
 | |
|     if(err == ERR_NONE) {
 | |
|         st25r3916ExecuteCommand(ST25R3916_CMD_START_NO_RESPONSE_TIMER);
 | |
|     }
 | |
| 
 | |
|     return err;
 | |
| }
 | |
| 
 | |
| /*******************************************************************************/
 | |
| void st25r3916SetGPTime(uint16_t gpt_8fcs) {
 | |
|     st25r3916WriteRegister(ST25R3916_REG_GPT1, (uint8_t)(gpt_8fcs >> 8));
 | |
|     st25r3916WriteRegister(ST25R3916_REG_GPT2, (uint8_t)(gpt_8fcs & 0xFFU));
 | |
| }
 | |
| 
 | |
| /*******************************************************************************/
 | |
| ReturnCode st25r3916SetStartGPTimer(uint16_t gpt_8fcs, uint8_t trigger_source) {
 | |
|     st25r3916SetGPTime(gpt_8fcs);
 | |
|     st25r3916ChangeRegisterBits(
 | |
|         ST25R3916_REG_TIMER_EMV_CONTROL,
 | |
|         ST25R3916_REG_TIMER_EMV_CONTROL_gptc_mask,
 | |
|         trigger_source);
 | |
| 
 | |
|     /* If there's no trigger source, start GPT immediately */
 | |
|     if(trigger_source == ST25R3916_REG_TIMER_EMV_CONTROL_gptc_no_trigger) {
 | |
|         st25r3916ExecuteCommand(ST25R3916_CMD_START_GP_TIMER);
 | |
|     }
 | |
| 
 | |
|     return ERR_NONE;
 | |
| }
 | |
| 
 | |
| /*******************************************************************************/
 | |
| bool st25r3916CheckChipID(uint8_t* rev) {
 | |
|     uint8_t ID;
 | |
| 
 | |
|     ID = 0;
 | |
|     st25r3916ReadRegister(ST25R3916_REG_IC_IDENTITY, &ID);
 | |
| 
 | |
|     /* Check if IC Identity Register contains ST25R3916's IC type code */
 | |
|     if((ID & ST25R3916_REG_IC_IDENTITY_ic_type_mask) !=
 | |
|        ST25R3916_REG_IC_IDENTITY_ic_type_st25r3916) {
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     if(rev != NULL) {
 | |
|         *rev = (ID & ST25R3916_REG_IC_IDENTITY_ic_rev_mask);
 | |
|     }
 | |
| 
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| /*******************************************************************************/
 | |
| ReturnCode st25r3916GetRegsDump(t_st25r3916Regs* regDump) {
 | |
|     uint8_t regIt;
 | |
| 
 | |
|     if(regDump == NULL) {
 | |
|         return ERR_PARAM;
 | |
|     }
 | |
| 
 | |
|     /* Dump Registers on space A */
 | |
|     for(regIt = ST25R3916_REG_IO_CONF1; regIt <= ST25R3916_REG_IC_IDENTITY; regIt++) {
 | |
|         st25r3916ReadRegister(regIt, ®Dump->RsA[regIt]);
 | |
|     }
 | |
| 
 | |
|     regIt = 0;
 | |
| 
 | |
|     /* Read non-consecutive Registers on space B */
 | |
|     st25r3916ReadRegister(ST25R3916_REG_EMD_SUP_CONF, ®Dump->RsB[regIt++]);
 | |
|     st25r3916ReadRegister(ST25R3916_REG_SUBC_START_TIME, ®Dump->RsB[regIt++]);
 | |
|     st25r3916ReadRegister(ST25R3916_REG_P2P_RX_CONF, ®Dump->RsB[regIt++]);
 | |
|     st25r3916ReadRegister(ST25R3916_REG_CORR_CONF1, ®Dump->RsB[regIt++]);
 | |
|     st25r3916ReadRegister(ST25R3916_REG_CORR_CONF2, ®Dump->RsB[regIt++]);
 | |
|     st25r3916ReadRegister(ST25R3916_REG_SQUELCH_TIMER, ®Dump->RsB[regIt++]);
 | |
|     st25r3916ReadRegister(ST25R3916_REG_FIELD_ON_GT, ®Dump->RsB[regIt++]);
 | |
|     st25r3916ReadRegister(ST25R3916_REG_AUX_MOD, ®Dump->RsB[regIt++]);
 | |
|     st25r3916ReadRegister(ST25R3916_REG_TX_DRIVER_TIMING, ®Dump->RsB[regIt++]);
 | |
|     st25r3916ReadRegister(ST25R3916_REG_RES_AM_MOD, ®Dump->RsB[regIt++]);
 | |
|     st25r3916ReadRegister(ST25R3916_REG_TX_DRIVER_STATUS, ®Dump->RsB[regIt++]);
 | |
|     st25r3916ReadRegister(ST25R3916_REG_REGULATOR_RESULT, ®Dump->RsB[regIt++]);
 | |
|     st25r3916ReadRegister(ST25R3916_REG_OVERSHOOT_CONF1, ®Dump->RsB[regIt++]);
 | |
|     st25r3916ReadRegister(ST25R3916_REG_OVERSHOOT_CONF2, ®Dump->RsB[regIt++]);
 | |
|     st25r3916ReadRegister(ST25R3916_REG_UNDERSHOOT_CONF1, ®Dump->RsB[regIt++]);
 | |
|     st25r3916ReadRegister(ST25R3916_REG_UNDERSHOOT_CONF2, ®Dump->RsB[regIt++]);
 | |
| 
 | |
|     return ERR_NONE;
 | |
| }
 | |
| 
 | |
| /*******************************************************************************/
 | |
| bool st25r3916IsCmdValid(uint8_t cmd) {
 | |
|     if(!((cmd >= ST25R3916_CMD_SET_DEFAULT) && (cmd <= ST25R3916_CMD_RESPONSE_RF_COLLISION_N)) &&
 | |
|        !((cmd >= ST25R3916_CMD_GOTO_SENSE) && (cmd <= ST25R3916_CMD_GOTO_SLEEP)) &&
 | |
|        !((cmd >= ST25R3916_CMD_MASK_RECEIVE_DATA) && (cmd <= ST25R3916_CMD_MEASURE_AMPLITUDE)) &&
 | |
|        !((cmd >= ST25R3916_CMD_RESET_RXGAIN) && (cmd <= ST25R3916_CMD_ADJUST_REGULATORS)) &&
 | |
|        !((cmd >= ST25R3916_CMD_CALIBRATE_DRIVER_TIMING) &&
 | |
|          (cmd <= ST25R3916_CMD_START_PPON2_TIMER)) &&
 | |
|        (cmd != ST25R3916_CMD_SPACE_B_ACCESS) && (cmd != ST25R3916_CMD_STOP_NRT)) {
 | |
|         return false;
 | |
|     }
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| /*******************************************************************************/
 | |
| ReturnCode st25r3916StreamConfigure(const struct st25r3916StreamConfig* config) {
 | |
|     uint8_t smd;
 | |
|     uint8_t mode;
 | |
| 
 | |
|     smd = 0;
 | |
| 
 | |
|     if(config->useBPSK != 0U) {
 | |
|         mode = ST25R3916_REG_MODE_om_bpsk_stream;
 | |
|         if((config->din < 2U) || (config->din > 4U)) /* not in fc/4 .. fc/16 */
 | |
|         {
 | |
|             return ERR_PARAM;
 | |
|         }
 | |
|         smd |= ((4U - config->din) << ST25R3916_REG_STREAM_MODE_scf_shift);
 | |
|     } else {
 | |
|         mode = ST25R3916_REG_MODE_om_subcarrier_stream;
 | |
|         if((config->din < 3U) || (config->din > 6U)) /* not in fc/8 .. fc/64 */
 | |
|         {
 | |
|             return ERR_PARAM;
 | |
|         }
 | |
|         smd |= ((6U - config->din) << ST25R3916_REG_STREAM_MODE_scf_shift);
 | |
|         if(config->report_period_length == 0U) {
 | |
|             return ERR_PARAM;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if((config->dout < 1U) || (config->dout > 7U)) /* not in fc/2 .. fc/128 */
 | |
|     {
 | |
|         return ERR_PARAM;
 | |
|     }
 | |
|     smd |= (7U - config->dout) << ST25R3916_REG_STREAM_MODE_stx_shift;
 | |
| 
 | |
|     if(config->report_period_length > 3U) {
 | |
|         return ERR_PARAM;
 | |
|     }
 | |
|     smd |= (config->report_period_length << ST25R3916_REG_STREAM_MODE_scp_shift);
 | |
| 
 | |
|     st25r3916WriteRegister(ST25R3916_REG_STREAM_MODE, smd);
 | |
|     st25r3916ChangeRegisterBits(ST25R3916_REG_MODE, ST25R3916_REG_MODE_om_mask, mode);
 | |
| 
 | |
|     return ERR_NONE;
 | |
| }
 | |
| 
 | |
| /*******************************************************************************/
 | |
| ReturnCode st25r3916GetRSSI(uint16_t* amRssi, uint16_t* pmRssi) {
 | |
|     /*******************************************************************************/
 | |
|     /* MISRA 8.9 An object should be defined at block scope if its identifier only appears in a single function */
 | |
|     /*< ST25R3916  RSSI Display Reg values:      0   1   2   3   4   5   6    7    8   9    a     b    c    d  e  f */
 | |
|     static const uint16_t st25r3916Rssi2mV[] = {
 | |
|         0, 20, 27, 37, 52, 72, 99, 136, 190, 262, 357, 500, 686, 950, 1150, 1150};
 | |
| 
 | |
|     /* ST25R3916 2/3 stage gain reduction [dB]          0    0    0    0    0    3    6    9   12   15   18  na na na na na */
 | |
|     static const uint16_t st25r3916Gain2Percent[] = {
 | |
|         100, 100, 100, 100, 100, 141, 200, 281, 398, 562, 794, 1, 1, 1, 1, 1};
 | |
|     /*******************************************************************************/
 | |
| 
 | |
|     uint8_t rssi;
 | |
|     uint8_t gainRed;
 | |
| 
 | |
|     st25r3916ReadRegister(ST25R3916_REG_RSSI_RESULT, &rssi);
 | |
|     st25r3916ReadRegister(ST25R3916_REG_GAIN_RED_STATE, &gainRed);
 | |
| 
 | |
|     if(amRssi != NULL) {
 | |
|         *amRssi =
 | |
|             (uint16_t)(((uint32_t)st25r3916Rssi2mV[(rssi >> ST25R3916_REG_RSSI_RESULT_rssi_am_shift)] * (uint32_t)st25r3916Gain2Percent[(gainRed >> ST25R3916_REG_GAIN_RED_STATE_gs_am_shift)]) / 100U);
 | |
|     }
 | |
| 
 | |
|     if(pmRssi != NULL) {
 | |
|         *pmRssi =
 | |
|             (uint16_t)(((uint32_t)st25r3916Rssi2mV[(rssi & ST25R3916_REG_RSSI_RESULT_rssi_pm_mask)] * (uint32_t)st25r3916Gain2Percent[(gainRed & ST25R3916_REG_GAIN_RED_STATE_gs_pm_mask)]) / 100U);
 | |
|     }
 | |
| 
 | |
|     return ERR_NONE;
 | |
| }
 |