/****************************************************************************** * \attention * *

© COPYRIGHT 2020 STMicroelectronics

* * 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 st25r3916_aat.c * * \author * * \brief ST25R3916 Antenna Tuning * * The antenna tuning algorithm tries to find the optimal settings for * the AAT_A and AAT_B registers, which are connected to variable capacitors * to tune the antenna matching. * */ /* ****************************************************************************** * INCLUDES ****************************************************************************** */ #include "st25r3916_aat.h" #include "utils.h" #include "st_errno.h" #include "st25r3916.h" #include "st25r3916_com.h" #include "platform.h" #include "rfal_chip.h" /* ****************************************************************************** * GLOBAL DEFINES ****************************************************************************** */ #define ST25R3916_AAT_CAP_DELAY_MAX 10 /*!< Max Variable Capacitor settle delay */ /* ****************************************************************************** * GLOBAL MACROS ****************************************************************************** */ #define st25r3916AatLog(...) /* platformLog(__VA_ARGS__) */ /*!< Logging macro */ /* ****************************************************************************** * LOCAL FUNCTION PROTOTYPES ****************************************************************************** */ static ReturnCode aatHillClimb( const struct st25r3916AatTuneParams* tuningParams, struct st25r3916AatTuneResult* tuningStatus); static int32_t aatGreedyDescent( uint32_t* f_min, const struct st25r3916AatTuneParams* tuningParams, struct st25r3916AatTuneResult* tuningStatus, int32_t previousDir); static int32_t aatSteepestDescent( uint32_t* f_min, const struct st25r3916AatTuneParams* tuningParams, struct st25r3916AatTuneResult* tuningStatus, int32_t previousDir, int32_t previousDir2); static ReturnCode aatMeasure( uint8_t serCap, uint8_t parCap, uint8_t* amplitude, uint8_t* phase, uint16_t* measureCnt); static uint32_t aatCalcF(const struct st25r3916AatTuneParams* tuningParams, uint8_t amplitude, uint8_t phase); static ReturnCode aatStepDacVals( const struct st25r3916AatTuneParams* tuningParams, uint8_t* a, uint8_t* b, int32_t dir); /*******************************************************************************/ ReturnCode st25r3916AatTune( const struct st25r3916AatTuneParams* tuningParams, struct st25r3916AatTuneResult* tuningStatus) { ReturnCode err; const struct st25r3916AatTuneParams* tp = tuningParams; struct st25r3916AatTuneResult* ts = tuningStatus; struct st25r3916AatTuneParams defaultTuningParams = { .aat_a_min = 0, .aat_a_max = 255, .aat_a_start = 127, .aat_a_stepWidth = 32, .aat_b_min = 0, .aat_b_max = 255, .aat_b_start = 127, .aat_b_stepWidth = 32, .phaTarget = 128, .phaWeight = 2, .ampTarget = 196, .ampWeight = 1, .doDynamicSteps = true, .measureLimit = 50, }; struct st25r3916AatTuneResult defaultTuneResult; if((NULL != tp) && ((tp->aat_a_min > tp->aat_a_max) || (tp->aat_a_start < tp->aat_a_min) || (tp->aat_a_start > tp->aat_a_max) || (tp->aat_b_min > tp->aat_b_max) || (tp->aat_b_start < tp->aat_b_min) || (tp->aat_b_start > tp->aat_b_max))) { return ERR_PARAM; } if(NULL == tp) { /* Start from current caps with default params */ st25r3916ReadRegister(ST25R3916_REG_ANT_TUNE_A, &defaultTuningParams.aat_a_start); st25r3916ReadRegister(ST25R3916_REG_ANT_TUNE_B, &defaultTuningParams.aat_b_start); tp = &defaultTuningParams; } if(NULL == ts) { ts = &defaultTuneResult; } ts->measureCnt = 0; /* Clear current measure count */ err = aatHillClimb(tp, ts); return err; } /*******************************************************************************/ static ReturnCode aatHillClimb( const struct st25r3916AatTuneParams* tuningParams, struct st25r3916AatTuneResult* tuningStatus) { ReturnCode err = ERR_NONE; uint32_t f_min; int32_t direction, gdirection; uint8_t amp, phs; struct st25r3916AatTuneParams tp = *tuningParams; // local copy to obey const tuningStatus->aat_a = tuningParams->aat_a_start; tuningStatus->aat_b = tuningParams->aat_b_start; /* Get a proper start value */ aatMeasure(tuningStatus->aat_a, tuningStatus->aat_b, &, &phs, &tuningStatus->measureCnt); f_min = aatCalcF(&tp, amp, phs); direction = 0; st25r3916AatLog("%d %d: %d***\n", tuningStatus->aat_a, tuningStatus->aat_b, f_min); do { direction = 0; /* Initially and after reducing step sizes we don't have a previous direction */ do { /* With the greedy step below always executed aftwards the -direction does never need to be investigated */ direction = aatSteepestDescent(&f_min, &tp, tuningStatus, direction, -direction); if(tuningStatus->measureCnt > tp.measureLimit) { err = ERR_OVERRUN; break; } do { gdirection = aatGreedyDescent(&f_min, &tp, tuningStatus, direction); if(tuningStatus->measureCnt > tp.measureLimit) { err = ERR_OVERRUN; break; } } while(0 != gdirection); } while(0 != direction); tp.aat_a_stepWidth /= 2U; /* Reduce step sizes */ tp.aat_b_stepWidth /= 2U; } while(tp.doDynamicSteps && ((tp.aat_a_stepWidth > 0U) || (tp.aat_b_stepWidth > 0U))); return err; } /*******************************************************************************/ static int32_t aatSteepestDescent( uint32_t* f_min, const struct st25r3916AatTuneParams* tuningParams, struct st25r3916AatTuneResult* tuningStatus, int32_t previousDir, int32_t previousDir2) { int32_t i; uint8_t amp, phs; uint32_t f; int32_t bestdir = 0; /* Negative direction: decrease, Positive: increase. (-)1: aat_a, (-)2: aat_b */ for(i = -2; i <= 2; i++) { uint8_t a = tuningStatus->aat_a, b = tuningStatus->aat_b; if((0 == i) || (i == -previousDir) || (i == -previousDir2)) { /* Skip no direction and avoid going backwards */ continue; } if(0U != aatStepDacVals( tuningParams, &a, &b, i)) { /* If stepping did not change the value, omit this direction */ continue; } aatMeasure(a, b, &, &phs, &tuningStatus->measureCnt); f = aatCalcF(tuningParams, amp, phs); st25r3916AatLog("%d : %d %d: %d", i, a, b, f); if(f < *f_min) { /* Value is better than all previous ones */ st25r3916AatLog("*"); *f_min = f; bestdir = i; } st25r3916AatLog("\n"); } if(0 != bestdir) { /* Walk into the best direction */ aatStepDacVals(tuningParams, &tuningStatus->aat_a, &tuningStatus->aat_b, bestdir); } return bestdir; } /*******************************************************************************/ static int32_t aatGreedyDescent( uint32_t* f_min, const struct st25r3916AatTuneParams* tuningParams, struct st25r3916AatTuneResult* tuningStatus, int32_t previousDir) { uint8_t amp, phs; uint32_t f; uint8_t a = tuningStatus->aat_a, b = tuningStatus->aat_b; if(0U != aatStepDacVals( tuningParams, &a, &b, previousDir)) { /* If stepping did not change the value, omit this direction */ return 0; } aatMeasure(a, b, &, &phs, &tuningStatus->measureCnt); f = aatCalcF(tuningParams, amp, phs); st25r3916AatLog("g : %d %d: %d", a, b, f); if(f < *f_min) { /* Value is better than previous one */ st25r3916AatLog("*\n"); tuningStatus->aat_a = a; tuningStatus->aat_b = b; *f_min = f; return previousDir; } st25r3916AatLog("\n"); return 0; } /*******************************************************************************/ static uint32_t aatCalcF(const struct st25r3916AatTuneParams* tuningParams, uint8_t amplitude, uint8_t phase) { /* f(amp, pha) = (ampWeight * |amp - ampTarget|) + (phaWeight * |pha - phaTarget|) */ uint8_t ampTarget = tuningParams->ampTarget; uint8_t phaTarget = tuningParams->phaTarget; uint32_t ampWeight = tuningParams->ampWeight; uint32_t phaWeight = tuningParams->phaWeight; /* Temp variables to avoid MISRA R10.8 (cast on composite expression) */ uint8_t ad = ((amplitude > ampTarget) ? (amplitude - ampTarget) : (ampTarget - amplitude)); uint8_t pd = ((phase > phaTarget) ? (phase - phaTarget) : (phaTarget - phase)); uint32_t ampDelta = (uint32_t)ad; uint32_t phaDelta = (uint32_t)pd; return ((ampWeight * ampDelta) + (phaWeight * phaDelta)); } /*******************************************************************************/ static ReturnCode aatStepDacVals( const struct st25r3916AatTuneParams* tuningParams, uint8_t* a, uint8_t* b, int32_t dir) { int16_t aat_a = (int16_t)*a, aat_b = (int16_t)*b; switch(abs(dir)) { /* Advance by steps size in requested direction */ case 1: aat_a = (dir < 0) ? (aat_a - (int16_t)tuningParams->aat_a_stepWidth) : (aat_a + (int16_t)tuningParams->aat_a_stepWidth); if(aat_a < (int16_t)tuningParams->aat_a_min) { aat_a = (int16_t)tuningParams->aat_a_min; } if(aat_a > (int16_t)tuningParams->aat_a_max) { aat_a = (int16_t)tuningParams->aat_a_max; } if((int16_t)*a == aat_a) { return ERR_PARAM; } break; case 2: aat_b = (dir < 0) ? (aat_b - (int16_t)tuningParams->aat_b_stepWidth) : (aat_b + (int16_t)tuningParams->aat_b_stepWidth); if(aat_b < (int16_t)tuningParams->aat_b_min) { aat_b = (int16_t)tuningParams->aat_b_min; } if(aat_b > (int16_t)tuningParams->aat_b_max) { aat_b = (int16_t)tuningParams->aat_b_max; } if((int16_t)*b == aat_b) { return ERR_PARAM; } break; default: return ERR_REQUEST; } /* We only get here if actual values have changed. In all other cases an error is returned */ *a = (uint8_t)aat_a; *b = (uint8_t)aat_b; return ERR_NONE; } /*******************************************************************************/ static ReturnCode aatMeasure( uint8_t serCap, uint8_t parCap, uint8_t* amplitude, uint8_t* phase, uint16_t* measureCnt) { ReturnCode err; *amplitude = 0; *phase = 0; st25r3916WriteRegister(ST25R3916_REG_ANT_TUNE_A, serCap); st25r3916WriteRegister(ST25R3916_REG_ANT_TUNE_B, parCap); /* Wait till caps have settled.. */ platformDelay(ST25R3916_AAT_CAP_DELAY_MAX); /* Get amplitude and phase .. */ err = rfalChipMeasureAmplitude(amplitude); if(ERR_NONE == err) { err = rfalChipMeasurePhase(phase); } if(measureCnt != NULL) { (*measureCnt)++; } return err; }