Skip to content

Commit

Permalink
EXPERIMENTAL: Use calibration data for TX power (PA Bias)
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrej committed Oct 3, 2024
1 parent 5e37901 commit 4c8def8
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 93 deletions.
60 changes: 60 additions & 0 deletions openrtx/include/calibration/calibInfo_A36Plus.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/***************************************************************************
* Copyright (C) 2020 - 2023 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN *
* Frederik Saraci IU2NRO *
* Silvano Seva IU2KWO *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, see <http://www.gnu.org/licenses/> *
***************************************************************************/

#ifndef CALIBINFO_A36PLUS_H
#define CALIBINFO_A36PLUS_H

#include <datatypes.h>
#include <stdint.h>

/**
* Data types defining the structure of calibration data stored in external
* flash memory of A36plus devices.
*/

/**
* \brief Calibration data for A36plus.
*/
typedef struct
{
// To be determined
}
A36plusCalib_t;

typedef struct PowerCalibration {
uint8_t power_below_130mhz;
uint8_t power_455_470mhz;
uint8_t power_420_455mhz;
uint8_t power_300_420mhz;
uint8_t power_200_300mhz;
uint8_t power_166_200mhz;
uint8_t power_145_166mhz;
uint8_t power_130_145mhz;
uint8_t unused[56]; // Remaining unused bytes in the 64-byte block
} PowerCalibration;

typedef struct PowerCalibrationTables {
PowerCalibration high;
PowerCalibration med;
PowerCalibration low;
} PowerCalibrationTables;

#endif /* CALIBINFO_A36PLUS_H */

93 changes: 16 additions & 77 deletions platform/drivers/NVM/nvmem_A36Plus.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#include <wchar.h>
#include <interfaces/delays.h>
#include <interfaces/nvmem.h>
#include <calibInfo_GDx.h>
#include <calibInfo_A36Plus.h>
#include <utils.h>
#include "AT24Cx.h"
#include "W25Qx.h"
Expand Down Expand Up @@ -52,25 +52,10 @@ typedef struct
}
__attribute__((packed)) dataBlock_t;

//TODO: change these to real addresses when I figure out the
// cal data location and format
static const uint32_t UHF_CAL_BASE = 0x8F000;
static const uint32_t VHF_CAL_BASE = 0x8F070;
static const uint32_t CAL_BASE = 0xF000;

static const uint32_t baseAddress = 0x000A1000; // 0x000A1000;

/**
* \internal Utility function for loading band-specific calibration data into
* the corresponding data structure.
*
* @param baseAddr: start address of the data block;
* @param cal: pointer to calibration data structure to be filled.
*/
static void _loadBandCalData(uint32_t baseAddr, bandCalData_t *cal)
{
return;
}

// A function that dumps a portion of external flash to UART
#if 0
void nvm_dumpFlash()
Expand All @@ -80,14 +65,16 @@ void nvm_dumpFlash()

uint8_t buf[16];
// there's no printf, so use sprintf to write to a buffer and then write the buffer to UART
char str[16];
for(uint32_t i = 0xA1000; i < 0xA1100; i += 16)
char str[64];
for(uint32_t i = 0; i < 0x4000; i += 16)
{
W25Qx_readData(i, buf, 16);
printf("\r\nx%08X ", i);
sprintf(str, "\r\nx%08X ", i);
usart0_IRQwrite(str);
for(uint8_t j = 0; j < 16; j++)
{
printf("%02X", buf[j]);
sprintf(str, "%02X", buf[j]);
usart0_IRQwrite(str);
}
}

Expand Down Expand Up @@ -115,75 +102,27 @@ const struct nvmDescriptor *nvm_getDesc(const size_t index)

void nvm_readCalibData(void *buf)
{
return; // for now
W25Qx_wakeup();
delayUs(5);

PowerCalibrationTables *calib = ((PowerCalibrationTables *) buf);

gdxCalibration_t *calib = ((gdxCalibration_t *) buf);

_loadBandCalData(VHF_CAL_BASE, &(calib->data[0])); /* Load VHF band calibration data */
_loadBandCalData(UHF_CAL_BASE, &(calib->data[1])); /* Load UHF band calibration data */
// Load calibration data
uint32_t addr = CAL_BASE;
W25Qx_readData(addr, &calib->high, sizeof(PowerCalibration));
addr += sizeof(PowerCalibration);
W25Qx_readData(addr, &calib->med, sizeof(PowerCalibration));
addr += sizeof(PowerCalibration);
W25Qx_readData(addr, &calib->low, sizeof(PowerCalibration));

// W25Qx_sleep();

/*
* Finally, load calibration points. These are common among all the GDx
* devices.
* VHF calibration head and tail are not equally spaced as the other points,
* so we manually override the values.
*/
for(uint8_t i = 0; i < 16; i++)
{
uint8_t ii = i/2;
calib->uhfCalPoints[ii] = 405000000 + (5000000 * ii);
calib->uhfPwrCalPoints[i] = 400000000 + (5000000 * i);
}

for(uint8_t i = 0; i < 8; i++)
{
calib->vhfCalPoints[i] = 135000000 + (5000000 * i);
}

calib->vhfCalPoints[0] = 136000000;
calib->vhfCalPoints[7] = 172000000;
}

void nvm_readHwInfo(hwInfo_t *info)
{
/* Not sure yet. */
(void) info;
}
/*
int nvm_readVfoChannelData(channel_t *channel)
{
// Read the channel data from the external flash
W25Qx_readData(0x000A1000, channel, sizeof(channel_t));
return 0;
}
int nvm_readSettings(settings_t *settings)
{
// Read the settings from the external flash
W25Qx_readData(0x000A1000 + sizeof(channel_t), settings, sizeof(settings_t));
return 0;
}
int nvm_writeSettings(const settings_t *settings)
{
// Write the settings to the external flash
W25Qx_writeData(0x000A1000 + sizeof(channel_t), settings, sizeof(settings_t));
return 0;
}
int nvm_writeSettingsAndVfo(const settings_t *settings, const channel_t *vfo)
{
// Write the settings and VFO data to the external flash
W25Qx_writeData(0x000A1000, vfo, sizeof(channel_t));
W25Qx_writeData(0x000A1000 + sizeof(channel_t), settings, sizeof(settings_t));
return 0;
}
*/

int nvm_readVfoChannelData(channel_t *channel)
{
Expand Down
57 changes: 47 additions & 10 deletions platform/drivers/baseband/bk4819.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,13 @@ SOFTWARE.
*/

#include "bk4819.h"
#include <calibInfo_A36Plus.h>
#include <lib/printf/printf.h>

#include "interfaces/delays.h"

extern PowerCalibrationTables *calData;

static void spi_write_byte(uint8_t data)
{
BK4819_SCK_LOW;
Expand Down Expand Up @@ -208,29 +212,62 @@ void bk4819_rtx_off(void){
WriteRegister(BK4819_REG_30, 0x00); // reset
}

// set BK4819 power
void bk4819_setTxPower(uint32_t power)
// Consolidated function to get the calibration value based on frequency
uint8_t getPaBiasCalValue(uint32_t freq, PowerCalibration calTable) {
if (freq < 130000000) {
return calTable.power_below_130mhz;
} else if (freq >= 455000000 && freq <= 470000000) {
return calTable.power_455_470mhz;
} else if (freq >= 420000000 && freq < 455000000) {
return calTable.power_420_455mhz;
} else if (freq >= 300000000 && freq < 420000000) {
return calTable.power_300_420mhz;
} else if (freq >= 200000000 && freq < 300000000) {
return calTable.power_200_300mhz;
} else if (freq >= 166000000 && freq < 200000000) {
return calTable.power_166_200mhz;
} else if (freq >= 145000000 && freq < 166000000) {
return calTable.power_145_166mhz;
} else if (freq >= 130000000 && freq < 145000000) {
return calTable.power_130_145mhz;
}
// Default case, should not happen if freq is within valid range
return calTable.power_below_130mhz;
}

void bk4819_setTxPower(uint32_t power, uint32_t freq, PowerCalibrationTables calData)
{
// Power setting is done by setting the PA bias voltage
// in REG_36<15:8> and the gain tuning values in <5:0>.
// I'm eyeballing what 1W, 5W and 10W should be,
// but I'm not at all sure if the values are correct.
uint16_t reg = 0;
uint8_t PaBias = 0;
uint8_t PaGainValues = 0;

// NOTE: PaGainValues taken straight from disassembly.

// Determine the PaGainValues based on power
switch (power)
{
case 1000:
reg = 0x40A6;
PaGainValues = 0xD7;
// Retrieve the top byte from calData based on power and frequency
PaBias = getPaBiasCalValue(freq, calData.low);
break;
case 5000:
reg = 0x9FAD;
PaGainValues = 0xD7;
PaBias = getPaBiasCalValue(freq, calData.med);
break;
case 10000:
reg = 0xFFBF;
PaGainValues = 0xFF;
PaBias = getPaBiasCalValue(freq, calData.high);
break;
default:
reg = 0x2092;
PaGainValues = 0x13;
PaBias = getPaBiasCalValue(freq, calData.low);
break;
}

// Combine the top byte with the least significant byte
reg = (PaBias << 8) | PaGainValues;

WriteRegister(BK4819_REG_36, reg);
}

Expand Down
14 changes: 12 additions & 2 deletions platform/drivers/baseband/bk4819.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "gpio.h"
#include "peripherals/gpio.h"
#include <calibInfo_A36Plus.h>
// Written by Jamiexu
#ifdef __cplusplus
extern "C" {
Expand Down Expand Up @@ -242,9 +243,18 @@ void bk4819_set_freq(uint32_t frq);
/**
* @brief Set TX power
*
* @param power
* @param power TX power in mW
* @param freq Frequency
* @param calData Calibration data
*/
void bk4819_setTxPower(uint32_t power);
void bk4819_setTxPower(uint32_t power, uint32_t freq, PowerCalibrationTables calData);

/**
* @brief Get band from frequency
*
* @return uint32_t
*/
uint8_t getBandFromFreq(uint32_t freq);

/**
* @brief Turn on RX
Expand Down
11 changes: 7 additions & 4 deletions platform/drivers/baseband/radio_A36Plus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
* along with this program; if not, see <http://www.gnu.org/licenses/> *
***************************************************************************/

#include <calibInfo_A36Plus.h>
#include <interfaces/nvmem.h>
#include <drivers/USART0.h>
#include <gd32f3x0.h>
#include <hwconfig.h>
Expand All @@ -37,9 +39,7 @@
static const rtxStatus_t*
config; // Pointer to data structure with radio configuration

// static gdxCalibration_t calData; // Calibration data
// static Band currRxBand = BND_NONE; // Current band for RX
// static Band currTxBand = BND_NONE; // Current band for TX
static PowerCalibrationTables calData; // Power (PA bias) calibration data
// static uint16_t apcVoltage = 0; // APC voltage for TX output power control

static enum opstatus radioStatus; // Current operating status
Expand Down Expand Up @@ -75,6 +75,9 @@ void radio_init(const rtxStatus_t* rtxState)
config = rtxState;
radioStatus = OFF;

// Load calibration data
nvm_readCalibData(&calData);

/*
* Configure RTX GPIOs
*/
Expand Down Expand Up @@ -222,7 +225,7 @@ void radio_updateConfiguration()
0x5f, 0x5e, 0x20, 0x08
);
// Set BK4819 PA Gain tuning according to TX power (config->txPower)
bk4819_setTxPower(config->txPower);
bk4819_setTxPower(config->txPower, config->txFrequency, calData);
bk4819_set_freq(config->rxFrequency / 10);
// Disable corresponding filter
// If frequency is VHF, toggle GPIO C15
Expand Down

0 comments on commit 4c8def8

Please sign in to comment.