330 lines
12 KiB
C
Executable File
330 lines
12 KiB
C
Executable File
/******************************************************************************
|
|
* \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 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;
|
|
}
|