feat: 新增工程,由20241025技术支持包中的coms工程upgrade得到,发端修改为演示验证QPSK

This commit is contained in:
2024-11-03 00:11:51 +08:00
parent 27ff8f2354
commit decfa6f93e
261 changed files with 1226836 additions and 0 deletions
@@ -0,0 +1,35 @@
# keep compiled libs
!*.a
# Buid folder
build/
# Xilinx tools generated files
.metadata/
.settings/
.wsdata/
.Xil/
logs/
Packages/
*.log*
# System generated files
# -- macOS
.DS_Store
.AppleDouble
.LSOverride
._*
# -- Windows
Thumbs.db
ehthumbs.db
Desktop.ini
# -- Linux
*~
# IDEs and editors' files
*.idea
*.vscode
*.sublime-workspace
*.sublime-project
@@ -0,0 +1,8 @@
include ../../scripts/generic_variables.mk
PLATFORM := xilinx
CONFIG_FILE := $(PROJECT)/config.json
XILINX_VITIS_CLASSIC = y
SCRIPT_DIR = ../../scripts
include ../../scripts/generic.mk
@@ -0,0 +1,32 @@
@echo off
set "platform=xilinx"
set "pltform_ver=2024.1"
set "work_dir=%~dp0build"
set "config=%~dp0config.json"
set "tools_dir=%~dp0..\..\scripts\platform\%platform%"
REM Set up enviroment
call "%tools_dir%\setenv.bat" "%pltform_ver%"
if "%ERRORLEVEL%" neq "0" (
echo Error: Failed to installize enviroment.
pause >nul
exit /b 1
)
REM Build project
call "%tools_dir%\build.bat" "%config%" "%work_dir%"
if "%ERRORLEVEL%" neq "0" (
echo Error: Failed to build project.
pause >nul
exit /b 1
)
REM Lauch SDK
call "%tools_dir%\launch.bat" "%pltform_ver%" "%work_dir%"
if "%ERRORLEVEL%" neq "0" (
echo Error: Failed to launch SDK.
pause >nul
exit /b 1
)
exit /b 0
@@ -0,0 +1,60 @@
{
"project_name": "cx9261a_demo_cmos_20240829",
"version": "20240829",
"hw_design": "../CX9261A_ZC706.xsa",
"hw_version": "20241102",
"apps": {
"cx9261a_api_app": {
"sources": ["source_cx9261a_api_1_10_0/"],
"target_cpu": "ps7_cortexa9_0",
"os": "standalone",
"language": "C++",
"mem_layout" : {
"heap_size": "0x80000",
"stack_size": "0x4000"
}
},
"CX9261A_CPPV4": {
"sources": ["source_CX9261A_CPPV4/"],
"target_cpu": "ps7_cortexa9_0",
"os": "standalone",
"language": "C++",
"mem_layout" : {
"heap_size": "0x80000",
"stack_size": "0x4000"
}
},
"CX9261A_HOP": {
"sources": ["source_CX9261A_HOP/"],
"target_cpu": "ps7_cortexa9_0",
"os": "freertos10_xilinx",
"language": "C",
"mem_layout" : {
"heap_size": "0x80000",
"stack_size": "0x4000"
},
"bsp_lib": {
"lwip220": {
"version": "1.0",
"config": {
"api_mode": "SOCKET_API",
"pbuf_pool_size": 2048
}
},
"xilffs": {
"version": "5.2"
}
}
},
"ddr_test": {
"sources": ["source_ddr_test/"],
"target_cpu": "ps7_cortexa9_0",
"os": "standalone",
"language": "C++",
"mem_layout" : {
"heap_size": "0x80000",
"stack_size": "0x4000"
}
}
}
}
@@ -0,0 +1,546 @@
/**
* @file cx9261adriver.h
*/
#ifndef CX9261ADRIVER_CX9261ADRIVER_H
#define CX9261ADRIVER_CX9261ADRIVER_H
#define VERSION 1.10.0
#include "defs.h"
// 如果不需要输出日志内容,注释掉下面的宏定义
#define USE_LOGGING
#ifdef USE_LOGGING
# define LOGGING(x) logging(x);
#else
# define LOGGING(x)
#endif
namespace CX9261A {
#ifdef USE_LOGGING
/**
* @brief 输出日志的函数
* @param msg 要输出的内容
*/
void logging(const std::string& msg);
#endif
/**
* @brief 需要实现的函数,实现SPI写入寄存器功能
* @param address 要写入的寄存器地址
* @param value 要写入的寄存器值
*/
void writeSpi(int address, int value);
/**
* @brief 需要实现的函数,实现SPI读取寄存器功能
* @param address 要读取的寄存器地址
* @return 返回的寄存器值
*/
int readSpi(int address);
/**
* @brief 需要实现的函数,实现等待功能
* @param ms 等待时间,单位毫秒
*/
void pause(double ms);
/**
* @brief 需要实现的函数,实现配置FPGA对应寄存器功能
* @param pin 寄存器地址
* @param value 寄存器值
*/
void setPin(int pin, int value);
/**
* @brief 初始化芯片状态,写入与具体配置无关的寄存器值
*/
void initialChip();
/**
* @brief 初始化电源配置,如果只自定义配置部分模式下的电源管理,在自定义配置之前需要先调用此函数
*/
void initialPowerConfig(const CX9261AConfiguration& config);
/**
* @brief 初始化BBPLL相关寄存器,如果调用了initialChip,则无需单独调用此函数
*/
void initialBBPLL();
/**
* @brief 初始化PLL1相关寄存器,如果调用了initialChip,则无需单独调用此函数
*/
void initialPLL1();
/**
* @brief 初始化PLL2相关寄存器,如果调用了initialChip,则无需单独调用此函数
*/
void initialPLL2();
/**
* @brief 初始化PLL3相关寄存器,如果调用了initialChip,则无需单独调用此函数
*/
void initialPLL3();
/**
* @brief 初始化PLL4相关寄存器,如果调用了initialChip,则无需单独调用此函数
*/
void initialPLL4();
/**
* @brief 初始化PLL5相关寄存器,如果调用了initialChip,则无需单独调用此函数
*/
void initialPLL5();
/**
* @brief 配置受参考时钟频率影响的寄存器
* @param ref 参考时钟频率,单位MHz
*/
void configRef(double ref);
/**
* @brief 配置时钟相关寄存器,包括ADC和BBPLL
* @param config CX9261A参数结构体
*/
void configBBPLL(const CX9261AConfiguration& config);
/**
* @brief BBPLL AFC
* @return 是否锁定
*/
bool afcBBPll();
/**
* @brief 配置PLL1频率
* @param lo 目标频率
* @param clock 时钟结构体,使用其中的ref和refDoubler属性
*/
void configPll1(double lo, const Clock& clock);
/**
* @brief Pll1 AFC
* @return 是否锁定
*/
bool afcPll1();
/**
* @brief 配置PLL2频率
* @param lo 目标频率
* @param clock 时钟结构体,使用其中的ref和refDoubler属性
*/
void configPll2(double lo, const Clock& clock);
/**
* @brief Pll2 AFC
* @return 是否锁定
*/
bool afcPll2();
/**
* @brief 配置PLL3频率
* @param lo 目标频率
* @param clock 时钟结构体,使用其中的ref和refDoubler属性
*/
void configPll3(double lo, const Clock& clock);
/**
* @brief Pll3 AFC
* @return 是否锁定
*/
bool afcPll3();
/**
* @brief 配置PLL4频率
* @param lo 目标频率
* @param clock 时钟结构体,使用其中的ref和refDoubler属性
*/
void configPll4(double lo, const Clock& clock);
/**
* @brief Pll4 AFC
* @return 是否锁定
*/
bool afcPll4();
/**
* @brief 配置PLL5频率
* @param lo 目标频率
* @param clock 时钟结构体,使用其中的ref和refDoubler属性
*/
void configPll5(double lo, const Clock& clock);
/**
* @brief Pll5 AFC
* @return 是否锁定
*/
bool afcPll5();
/**
* @brief 配置AGC模式
* @param mode 模式0~13
*/
void configAGCMode(int mode);
/**
* @brief 配置AGC PDT
* @param pdt AGCPDT结构体
*/
void configAGCPDT(const AGCPDT& pdt);
/**
* @brief 配置AGC LMT
* @param lmt AGCLMT结构体
*/
void configAGCLMT(const AGCLMT& lmt);
/**
* @brief 配置AGC DIG
* @param dig AGCDIG结构体
*/
void configAGCDIG(const AGCDIG& dig);
/**
* @brief 配置AGC
* @param agc AGC结构体
*/
void configAGC(const AGC& agc);
/**
* @brief 配置片内处理器,仅在使用需要处理器辅助的校准方法时需要开启处理器
* @param on 开启/关闭
*/
void configRISCV(bool on);
/**
* @brief 配置温补
* @param mode 温补模式 DAC/Band
*/
void configTemperatureCompensation(TemperatureComp mode);
/**
* @brief ADC校准
* @param adc ADC速率
*/
void configADCCalib(double adc);
/**
* @brief Flash校准
*/
void configFlashCalib();
/**
* @brief QEC校准会改变部分寄存器配置,在进行校准之前需要保存这部分寄存器,校准后恢复
* @return 包含寄存器地址和值的map
*/
std::map<int, int> beforeQecState();
/**
* @brief 恢复QEC校准过程中改变的寄存器
* @param state beforeQecState函数返回的map
*/
void restoreQecState(const std::map<int, int>& state);
/**
* @brief 根据pll来源配置校准模式下的电源管理
* @param pllSource PllSource结构体
*/
void preparePowerForRxCalib(const PllSource& pllSource);
/**
* @brief 调整校准时Pll的配置
* @param config CX9261A配置结构体
* @param chan 要进行校准的通道
*/
void preparePllForRxCalib(const CX9261AConfiguration& config, RxChannel chan);
/**
* @brief 等待RxTST窄带校准结束,可重写
* @return 校准是否结束
*/
bool waitRxTSTFinished();
/**
* @brief RX时域统计校准
* @param chan 校准的RX通道
*/
void rxTSTCalib(RxChannel chan);
/**
* @brief RX延时线校准
* @param fs ADC采样率
* @param chan 校准的RX通道
*/
void rxDelayCalib(double fs, RxChannel chan);
/**
* @brief DC Tracking
* @param config CX9261A配置结构体
*/
void configDcCalib(const Calib& config);
void configDcCalibMethod(DCCalibMethod method);
void configDcTrackingLength(int length);
void configDcHighPassFactor(int factor);
/**
* @brief Rx校准
* @param config CX9261A配置结构体
* @param chan 要进行校准的通道
*/
void rxCalib(const CX9261AConfiguration& config, RxChannel chan);
/**
* @brief 选择校准方法
* @param calib 校准结构体
*/
void configCalibMethod(const Calib& calib);
/**
* @brief 读取当前Rx chan通道的校准值
* @param chan Rx通道
* @return 校准值结构体
*/
CalibPredis readRxCalibPredis(RxChannel chan);
/**
* @brief 储存校准值
* @param index 第index组校准值
* @param chan 接收通道
* @param pll 使用的PLL
*/
void saveRxCalibPredis(unsigned char index, RxChannel chan, LoSource pll);
/**
* @brief 加载保存的校准值
* @param index 第index组校准值
* @param chan 指定加载校准值的通道
* @param pll 使用的PLL
*/
void loadRxCalibPredis(unsigned char index, RxChannel chan, LoSource pll);
/**
* @brief Rx窄带多点校准
* @param config CX9261A配置结构体
* @param points 校准点
* @param chan 接收通道
*/
void configRxMultiPointsQec(const CX9261AConfiguration& config, const std::vector<double>& points, RxChannel chan);
/**
* @brief 根据pll来源配置校准模式下的电源管理
* @param pllSource PllSource结构体
*/
void preparePowerForTxCalib(const PllSource& pllSource);
/**
* @brief 调整校准时Pll的配置
* @param config CX9261A配置结构体
*/
void preparePllForTxCalib(const CX9261AConfiguration& config);
/**
* @brief TX二分法QEC校准
* @param f0 校准音频率
* @param fs adc频率
*/
void txBisectionQecCalib(double f0, double fs);
/**
* @brief TX时域统计法校准
* @param config CX9261A配置结构体
* @param chan 要校准的通道
*/
void txTSTCalib(const CX9261AConfiguration& config, TxChannel chan);
/**
* @brief TX二分法DC校准
* @param f0 校准音频率
* @param fs adc频率
*/
void txBisectionDcCalib(double f0, double fs);
/**
* @brief Tx多点校准
* @param config CX9261A配置结构体
* @param points 校准点
*/
void configTxMultiPointsQec(const CX9261AConfiguration& config, const std::vector<double>& points);
/**
* @brief Tx通道校准
* @param config CX9261A配置结构体
*/
void txCalib(const CX9261AConfiguration& config);
/**
* @brief 储存校准值
* @param index 第index组校准值
* @param chan 发射通道
* @param pll pll
*/
void saveTxCalibPredis(unsigned char index, TxChannel chan, LoSource pll);
/**
* @brief 加载保存的校准值
* @param index 第index组校准值
* @param chan 指定加载校准值的通道
* @param pll 指定加载校准值对应的PLL
*/
void loadTxCalibPredis(unsigned char index, TxChannel chan, LoSource pll);
/**
* @brief Qec校准顶层函数,内部根据配置选择使用对应方法进行校准
* @param config CX9261A配置结构体
*/
void configQecCalib(const CX9261AConfiguration& config);
/**
* @brief 配置TX NCO相关寄存器
* @param nco TX NCO配置结构体
* @param fs adc速率
*/
void configTxNco(const TxNCO& nco, double fs);
/**
* @brief 配置TX NCO BIST模式
* @param bist 开启/关闭BIST
*/
void configTxBIST(bool bist);
/**
* @brief 配置TX NCO频率
* @param freq 混频频率
* @param fs adc抽取后速率
*/
void configTxNcoFreq(double freq, double fs);
/**
* @brief 配置RX NCO相关寄存器
* @param nco RX NCO配置结构体
* @param fs adc速率
*/
void configRxNco(const RxNCO& nco, double fs);
/**
* @brief 配置Rx NCO模式
* @param mode NCO模式:Bypass/BIST/Up/Down
*/
void configRxNcoMode(NCOMode mode);
/**
* @brief 配置Rx NCO模式
* @param mode NCO模式:Master/Slaver
*/
void configRxNcoMS(NCOMode mode);
/**
* @brief 配置Rx NCO频率
* @param freq 混频频率
* @param fs adc速率
*/
void configRxNcoFreq(double freq, double fs);
/**
* @brief 配置接口相关寄存器
* @param interface Interface配置结构体
*/
void configInterface(const Interface& interface);
/**
* @brief 配置PLL来源
* @param pllSource PLlSource结构体
*/
void configPllSource(const PllSource& pllSource);
/**
* @brief 切换电源模式
* @param pm 电源模式
*/
void configPowerMode(PowerMode pm);
/**
* @brief 配置电源管理
* @param power 电源配置结构体
* @param pm 电源模式
*/
void configPowerPins(const Power& power, PowerMode pm);
/**
* @brief 配置参考倍频器
* @param doubler 倍频器开关
* @param ref 参考时钟频率,单位MHz
*/
void configRefDoubler(bool doubler, double ref);
/**
* @brief 初始化通道,调用initialChip函数会初始化RX1,RX2,RX3三个通道
* @param chan 通道 RX1/RX2/RX3
*/
void initialRxChannel(RxChannel chan);
/**
* @brief 配置Rx带宽
* @note 只改变Rx带宽会导致通道增益改变,建议使用configRxChannel函数进行带宽调整
* @param bandwidth 带宽,单位(MHz)
* @param chan 通道 Rx1/Rx2/Rx3
*/
void configRxBandwidth(double bandwidth, RxChannel chan);
/**
* @brief 配置Rx TIA
* @note 只改变TIA会导致通道带宽改变,建议使用configRxChannel函数进行TIA调整
* @param tia tia档位
* @param chan 通道 Rx1/Rx2/Rx3
*/
void configRxTIA(int tia, RxChannel chan);
/**
* @brief 配置Rx Mixer
* @param mixer mixer档位
*/
void configRxMixer(int mixer);
/**
* @brief 配置Rx通道,包含TIA,Mixer以及Bandwidth
* @param config RxConfig结构体
* @param chan Rx1/Rx2/Rx3
*/
void configRxChannel(const RxConfig& config, RxChannel chan);
/**
* @brief 配置Rx FIR滤波器抽取倍数
* @param fir 抽取倍数 0(Bypass)/1/2/3/4/8
*/
void configRxFIR(int fir);
/**
* @brief 配置Rx HBF1滤波器抽取倍数
* @param hbf 抽取倍数 0(Bypass)/2
*/
void configRxHBF1(int hbf);
/**
* @brief 配置Rx HBF2滤波器抽取倍数
* @param hbf 抽取倍数 0(Bypass)/2
*/
void configRxHBF2(int hbf);
/**
* @brief 配置Rx HBF3滤波器抽取倍数
* @param hbf 抽取倍数 0(Bypass)/2/3
*/
void configRxHBF3(int hbf);
/**
* @brief 配置Rx CIC滤波器
* @param cic 抽取倍数 0(Bypass)/20
*/
void configRxCIC(int cic);
/**
* @brief 配置Rx滤波器
* @param filters Filters结构体
*/
void configRxFilters(const Filters& filters);
/**
* @brief 配置Rx FIR滤波器系数
* @param coe 滤波器系数,长度为16的整倍数,最大128
*/
void configRxFIRCoe(const std::vector<double>& coe);
/**
* @brief 配置Tx带宽
* @param bandwidth 带宽,单位(MHz)
* @param chan 通道 TX1/TX2
*/
void configTxBandwidth(double bandwidth, TxChannel chan);
/**
* @brief 配置Tx Mixer
* @param mixer 混频器值
* @param chan TX1/TX2
*/
void configTxMixer(int mixer, TxChannel chan);
/**
* @brief 初始化Tx通道
* @param chan 通道 TX1/TX2
*/
void initialTxChannel(TxChannel chan);
/**
* @brief 根据Tx通道的本振频率,配置对应的参数
* @param lo 本振频率,单位(MHz)
* @param chan 通道(Tx1/Tx2)
*/
void configTxChannelFrequency(double lo, TxChannel chan);
/**
* @brief 配置Tx通道,Mixer以及Bandwidth
* @param config TxConfig结构体
* @param chan Tx1/Tx2
*/
void configTxChannel(const TxConfig& config, TxChannel chan);
/**
* @brief 配置Tx FIR滤波器插值倍数
* @param fir 插值倍数 0(Bypass)/1/2/3/4/8
*/
void configTxFIR(int fir);
/**
* @brief 配置Tx HBF1滤波器插值倍数
* @param hbf 插值倍数 0(Bypass)/2
*/
void configTxHBF1(int hbf);
/**
* @brief 配置Tx HBF2滤波器插值倍数
* @param hbf 插值倍数 0(Bypass)/2
*/
void configTxHBF2(int hbf);
/**
* @brief 配置Tx HBF3滤波器插值倍数
* @param hbf 插值倍数 0(Bypass)/2/3
*/
void configTxHBF3(int hbf);
/**
* @brief 配置Tx CIC滤波器
* @param cic 插值倍数 0(Bypass)/8/20/32/80
*/
void configTxCIC(int cic);
/**
* @brief 配置Tx滤波器
* @param filters Filters结构体
*/
void configTxFilters(const Filters& filters);
/**
* @brief 配置Tx FIR滤波器系数
* @param coe 滤波器系数,长度为16的整倍数,最大128
*/
void configTxFIRCoe(const std::vector<double>& coe);
/**
* @brief 读取当前Tx chan通道的校准值
* @param chan Tx通道
* @return 校准值结构体
*/
CalibPredis readTxCalibPredis(TxChannel chan);
/**
* @brief 此函数为Demo板配套配置函数,用于配置FPGA接口,用户开发自己的程序时应重写对应功能
* @param interface Interface结构体
*/
void configFPGA(const Interface& interface);
} // namespace CX9261A
#endif // CX9261ADRIVER_CX9261ADRIVER_H
@@ -0,0 +1,424 @@
/**
* @file defs.h
*/
#ifndef CX9261ADRIVER_DEFS_H
#define CX9261ADRIVER_DEFS_H
#include <bitset>
#include <map>
#include <vector>
#ifdef interface
# undef interface
#endif
namespace CX9261A {
/**
* @brief 芯片工作模式
*/
enum class WorkMode : std::uint8_t { Rx, Tx, FDD };
/**
* @brief 收发数据通道数量
* @note 此模式并不代表使用几个通道进行收发
*/
enum class TrMode : std::uint8_t { R1T1, R2T2 };
/**
* @brief 收发接口通道数量
*/
enum class PortMode : std::uint8_t { Single, Dual };
/**
* @brief 接口模式:
* CMOS CMOS接口模式,
* LVDS_S LVDS顺序模式,
* LVDS_E LVDS奇偶模式
*/
enum class IOMode : std::uint8_t { CMOS, LVDS_S, LVDS_E };
/**
* @brief 本振来源
*/
enum class LoSource : std::uint8_t {
Pll1 = 0b00001,
Pll2 = 0b00010,
Pll3 = 0b00100,
Pll4 = 0b01000,
Pll5 = 0b10000,
Off = 0
};
inline std::string toString(const LoSource source)
{
switch (source) {
case LoSource::Pll1:
return "Pll1";
case LoSource::Pll2:
return "Pll2";
case LoSource::Pll3:
return "Pll3";
case LoSource::Pll4:
return "Pll4";
case LoSource::Pll5:
return "Pll5";
default:
return "Off";
}
}
/**
* @brief 接收通道
*/
enum class RxChannel : std::uint8_t { Rx1 = 1, Rx2, Rx3 };
inline std::string toString(const RxChannel chan)
{
switch (chan) {
case RxChannel::Rx1:
return "Rx1";
case RxChannel::Rx2:
return "Rx2";
case RxChannel::Rx3:
return "Rx3";
default:
return "Unknown Channel";
}
}
/**
* @brief 发射通道
*/
enum class TxChannel : std::uint8_t { Tx1 = 1, Tx2 };
inline std::string toString(const TxChannel chan)
{
switch (chan) {
case TxChannel::Tx1:
return "Tx1";
case TxChannel::Tx2:
return "Tx2";
default:
return "Unknown Channel";
}
}
/**
* @brief 电源模式
*/
enum class PowerMode : std::uint8_t { Shutdown = 0, Sleep, Alert, Calib, Receive, Transmit, Duplex, Obs };
/**
* @brief NCO模式
*/
enum class NCOMode : std::uint8_t { Bypass = 0, Up, Down, BIST, Master, Slaver };
/**
* @brief 温补模式 DAC: DAC模式 Band: 跳子带模式
*/
enum class TemperatureComp : std::uint8_t { DAC = 0, Band };
/**
* @brief 校准方法 TST: 时域统计 Rx通道使用, Bisec: 二分法 Tx通道使用, MultiPoints: 多点校准
*/
enum class CalibMethod : std::uint8_t { TST = 0, Bisec, MultiPoints, Tracking };
/**
* @brief DC校准方法 Tracking: 跟踪校准 HighPass: 高通滤波器滤掉直流
*/
enum class DCCalibMethod : std::uint8_t { Tracking = 0, HighPass };
/**
* @brief AFC等待延时,单位ms
*/
constexpr double delay = 100;
/**
* @brief QEC等待延时,单位ms
*/
constexpr double qecDelay = 500;
/**
* @brief 接收通道本振来源映射表
*/
static const std::map<std::pair<LoSource, LoSource>, std::bitset<7>> rxSrcMap = {
{ { LoSource::Pll2, LoSource::Pll2 }, 0b0010000 }, { { LoSource::Pll1, LoSource::Pll1 }, 0b1101000 },
{ { LoSource::Pll2, LoSource::Pll1 }, 0b0100000 }, { { LoSource::Pll1, LoSource::Pll2 }, 0b1000000 },
{ { LoSource::Off, LoSource::Pll1 }, 0b0101010 }, { { LoSource::Off, LoSource::Pll2 }, 0b1010010 },
{ { LoSource::Pll1, LoSource::Off }, 0b1001001 }, { { LoSource::Pll2, LoSource::Off }, 0b0110001 },
{ { LoSource::Off, LoSource::Off }, 0b0011011 }
};
/**
* @brief 发射通道本振来源映射表
*/
static const std::map<std::pair<LoSource, LoSource>, std::bitset<11>> txSrcMap = {
{ { LoSource::Pll4, LoSource::Pll4 }, 16 }, { { LoSource::Pll3, LoSource::Pll3 }, 104 },
{ { LoSource::Pll4, LoSource::Pll3 }, 32 }, { { LoSource::Pll3, LoSource::Pll4 }, 64 },
{ { LoSource::Pll2, LoSource::Pll2 }, 1560 }, { { LoSource::Pll1, LoSource::Pll1 }, 1944 },
{ { LoSource::Pll2, LoSource::Pll1 }, 1688 }, { { LoSource::Pll1, LoSource::Pll2 }, 1816 },
{ { LoSource::Off, LoSource::Pll3 }, 42 }, { { LoSource::Off, LoSource::Pll4 }, 82 },
{ { LoSource::Off, LoSource::Pll2 }, 794 }, { { LoSource::Off, LoSource::Pll1 }, 666 },
{ { LoSource::Pll3, LoSource::Off }, 73 }, { { LoSource::Pll4, LoSource::Off }, 49 },
{ { LoSource::Pll2, LoSource::Off }, 1177 }, { { LoSource::Pll1, LoSource::Off }, 1305 },
{ { LoSource::Off, LoSource::Off }, 27 }, { { LoSource::Pll1, LoSource::Pll3 }, 1320 },
{ { LoSource::Pll1, LoSource::Pll4 }, 1360 }, { { LoSource::Pll2, LoSource::Pll3 }, 1064 },
{ { LoSource::Pll2, LoSource::Pll4 }, 1104 }, { { LoSource::Pll3, LoSource::Pll1 }, 712 },
{ { LoSource::Pll4, LoSource::Pll1 }, 688 }, { { LoSource::Pll3, LoSource::Pll2 }, 584 },
{ { LoSource::Pll4, LoSource::Pll2 }, 560 }
};
/**
* @brief 环路参数选择表
*/
static const std::vector<std::vector<std::vector<int>>> coreTable = {
{ { 0x0C, 0x30, 0x08 }, { 0x0B, 0x30, 0x09 }, { 0x0C, 0x30, 0x05 }, { 0x0D, 0x30, 0x08 } },
{ { 0x0C, 0x30, 0x0C }, { 0x0B, 0x30, 0x0E }, { 0x0C, 0x30, 0x08 }, { 0x0D, 0x30, 0x0B } },
{ { 0x0C, 0x20, 0x10 }, { 0x0B, 0x20, 0x10 }, { 0x0C, 0x20, 0x0A }, { 0x0D, 0x20, 0x0D } },
{ { 0x0C, 0x20, 0x11 }, { 0x0B, 0x20, 0x13 }, { 0x0C, 0x20, 0x0C }, { 0x0D, 0x20, 0x0F } },
{ { 0x0D, 0x30, 0x14 }, { 0x0D, 0x22, 0x14 }, { 0x0D, 0x20, 0x0D }, { 0x0D, 0x15, 0x0C } },
{ { 0x0E, 0x30, 0x18 }, { 0x0E, 0x25, 0x16 }, { 0x0E, 0x25, 0x0F }, { 0x0E, 0x18, 0x0F } },
{ { 0x0F, 0x38, 0x1A }, { 0x0F, 0x32, 0x1C }, { 0x0F, 0x18, 0x12 }, { 0x0F, 0x18, 0x12 } }
};
/**
* @brief AGC PDT模式的结构体
*/
struct AGCPDT
{
int pdtN;
int pdtM;
};
/**
* @brief AGC LMT模式的结构体
*/
struct AGCLMT
{
int count; /**< LMT统计次数阈值*/
int threshold1; /**< LMT阈值第一档*/
int threshold2; /**< LMT阈值第二档*/
int threshold3; /**< LMT阈值第三档*/
int threshold4; /**< LMT阈值第四档*/
};
/**
* @brief AGC DIG模式的结构体
*/
struct AGCDIG
{
int count; /**< DIG统计次数阈值*/
int threshold1; /**< DIG阈值第一档*/
int threshold2; /**< DIG阈值第二档*/
int threshold3; /**< DIG阈值第三档*/
int threshold4; /**< DIG阈值第四档*/
};
/**
* @brief AGC模式的结构体
*/
struct AGC
{
int mode; /**< AGC模式选择*/
AGCPDT pdt; /**< AGC PDT模式的结构体*/
AGCLMT lmt; /**< AGC LMT模式的结构体*/
AGCDIG dig; /**< AGC DIG模式的结构体*/
};
/**
* @brief 时钟相关参数结构体
*/
struct Clock
{
double ref; /**< 参考时钟频率,单位MHz*/
double adc; /**< ADC频率,单位MHz*/
int refDiv; /**< 参考时钟分频比*/
bool bbUseIntDiv; /**< 是否使用整数分频模式*/
bool refDoubler; /**< 是否使用参考时钟倍频器*/
};
/**
* @brief 校准相关参数结构体
*/
struct Calib
{
bool calibDC; /**< 是否开启DC Tracking*/
DCCalibMethod dcCalibMethod;
int dcTrackingLength; /**< DC Tracking长度*/
int dcHighPassFactor; /**< DC高通滤波系数,越大代表滤波器阶数越高,滤波范围越窄*/
std::uint8_t rx1CalibPll; /**< rx1校准的pll选择,Pll1 | Pll2*/
std::uint8_t rx2CalibPll; /**< rx2校准的pll选择,Pll1 | Pll2*/
std::uint8_t rx3CalibPll; /**< rx3校准的pll选择,Pll5*/
std::uint8_t tx1CalibPll; /**< tx1校准的pll选择,Pll1 | Pll2 | Pll3 | Pll4*/
std::uint8_t tx2CalibPll; /**< tx2校准的pll选择,Pll1 | Pll2 | Pll3 | Pll4*/
CalibMethod rxMethod;
CalibMethod txMethod;
double f0; /**< 校准音频率*/
std::vector<double> rxMultiPoints; /**< Rx多点校准的频率*/
std::vector<double> txMultiPoints; /**< Tx多点校准的频率*/
};
/**
* @brief 配置PLL来源相关参数结构体
*/
struct PllSource
{
bool rxUseExt; /**< 接收通道是否使用外本振*/
bool txUseExt; /**< 发射通道是否使用外本振*/
LoSource rx1Source; /**< Rx1通道本振来源*/
LoSource rx2Source; /**< Rx2通道本振来源*/
LoSource rx3Source; /**< Rx3通道本振来源*/
LoSource tx1Source; /**< Tx1通道本振来源*/
LoSource tx2Source; /**< Tx2通道本振来源*/
};
/**
* @brief 配置PLL频率相关参数结构体
*/
struct PllFreq
{
double pll1Freq; /**< PLL1本振时钟,单位MHz*/
double pll2Freq; /**< PLL2本振时钟,单位MHz*/
double pll3Freq; /**< PLL3本振时钟,单位MHz*/
double pll4Freq; /**< PLL4本振时钟,单位MHz*/
double pll5Freq; /**< PLL5本振时钟,单位MHz*/
double rxExtFreq; /**< 接收通道使用外本振时,外本振频率,单位MHz*/
double txExtFreq; /**< 发射通道使用外本振时,外本振频率,单位MHz*/
};
/**
* @brief 配置接口相关参数结构体
*/
struct Interface
{
WorkMode workMode; /**< 芯片工作模式*/
TrMode trMode; /**< 收发数据通道模式*/
PortMode portMode; /**< 收发接口通道模式*/
IOMode ioMode; /**< 接口电平模式*/
};
/**
* @brief 配置TX NCO相关参数结构体
*/
struct TxNCO
{
bool txUseBist; /**< 是否开启BIST模式*/
double txNCOFreq; /**< NCO频率*/
};
/**
* @brief 配置RX NCO相关参数结构体
*/
struct RxNCO
{
bool rxUseBist; /**< 是否开启BIST模式*/
bool rxNCOBypass; /**< 是否Bypass NCO*/
bool rxNCOUpward; /**< 开启上/下混频模式*/
bool rxNCOMaster; /**< 使用Master/Slaver模式*/
double rxNCOFreq; /**< NCO频率*/
};
/**
* @brief 配置接收通道相关参数结构体
*/
struct RxConfig
{
double bandwidth; /**< 接收通道1dB带宽,单位MHz*/
int tia; /**< 接收通道TIA增益配置,推荐配置6*/
int mixer; /**< 接收通道Mixer增益配置*/
};
/**
* @brief 配置发射通道相关参数结构体
*/
struct TxConfig
{
double bandwidth; /**< 发射通道1dB带宽,单位MHz*/
int mixer; /**< 发射通道Mixer增益配置*/
};
/**
* @brief 配置滤波器相关参数结构体,0代表bypass
*/
struct Filters
{
int fir; /**< FIR滤波器抽取/插值倍数*/
int hbf1; /**< HBF1滤波器抽取/插值倍数*/
int hbf2; /**< HBF2滤波器抽取/插值倍数*/
int hbf3; /**< HBF3滤波器抽取/插值倍数*/
int cic; /**< CIC滤波器抽取/插值倍数*/
};
/**
* @brief 配置电源模式结构体,1代表该模块上电
*/
struct Power
{
bool dig_tx2;
bool dig_tx1;
bool dig_rx3;
bool dig_rx2;
bool dig_rx1;
bool fref1_rx;
bool auxadc2;
bool auxadc1;
bool auxdac;
bool temp_sensor;
bool bgr;
bool exlo;
bool tx2;
bool tx1;
bool rx3;
bool rx2;
bool rx1;
bool pll5_ldo;
bool pll5;
bool pll4_ldo;
bool pll4;
bool pll3_ldo;
bool pll3;
bool pll2_ldo;
bool pll2;
bool pll1_ldo;
bool pll1;
bool bbpll;
};
/**
* @brief 配置电源模式管理,包含模式选择,接收模式,发射模式,FDD模式
*/
struct PowerManagement
{
PowerMode powerMode;
Power rxPower;
Power txPower;
Power fddPower;
};
/**
* @brief 储存窄带校准结果的结构体
*/
struct CalibPredis
{
int bHigh;
int bLow;
int cHigh;
int cLow;
int dciHigh;
int dciLow;
int dcqHigh;
int dcqLow;
};
/**
* @brief CX9261A结构体
*/
struct CX9261AConfiguration
{
TemperatureComp tempComp; /**< 温度补偿*/
AGC agc; /**< AGC结构体*/
Interface interface; /**< Interface结构体*/
Clock clock; /**< Clock结构体*/
PllSource pllSource; /**< PllSource结构体*/
Calib calib; /**< Calib结构体*/
PllFreq pllFreq; /**< PllFreq结构体*/
TxNCO txNco; /**< TxNCO结构体*/
RxNCO rxNco; /**< RxNCO结构体*/
RxConfig rx1Config; /**< RxConfig结构体*/
RxConfig rx2Config; /**< RxConfig结构体*/
RxConfig rx3Config; /**< RxConfig结构体*/
TxConfig tx1Config; /**< TxConfig结构体*/
TxConfig tx2Config; /**< TxConfig结构体*/
Filters rxFilters; /**< Filters结构体*/
Filters txFilters; /**< Filters结构体*/
PowerManagement powerManagement; /**< PowerManagement结构体*/
std::vector<double> rxFIRCoe; /**< Rx FIR滤波器系数*/
std::vector<double> txFIRCoe; /**< Tx FIR滤波器系数*/
};
} // namespace CX9261A
#endif // CX9261ADRIVER_DEFS_H
@@ -0,0 +1,106 @@
/*
* download_bin.c
*
* Created on: 2023年11月23日
* Author: cxlab
*/
#include "xilinx_io.h"
#include "sleep.h"
void download_bin(void){
int temp;
u8 rx_data;
u8 data[4];
u32 buf;
u8 addr[2];
int dpd_multicalib = 0;// 1:dpd,0:multicalib
if (dpd_multicalib) {
SpiPs_write_read1(0x079,0x00,&rx_data);//关闭CRC校验
SpiPs_write_read1(0x071,0x00,&rx_data);
SpiPs_write_read1(0x071,0x09,&rx_data);
for(int i=0;i<5507;i++){
addr[0]=(i>>8)&0xff;
addr[1]= i&0xff;
buf=rom_read((u8 *)&addr);
data[0]=buf>>24;
data[1]=(buf>>16)&0xff;
data[2]=(buf>>8)&0xff;
data[3]=buf&0xff;
for(int j=0;j<4;j++){
SpiPs_write_read1(0x070,data[j],&rx_data);
}
}
SpiPs_write_read1(0x071,0x1A,&rx_data);//开启CRC校验
SpiPs_write_read1(0x079,0x08,&rx_data);//开启CRC校验
usleep(1000);
SpiPs_write_read2(0x078,0x00,&rx_data);
temp=rx_data;
if (temp == 0x01) {
xil_printf("CRC successful");
}
else {
xil_printf("CRC unsuccessful");
}
SpiPs_write_read1(0x071,0x06,&rx_data);//处理器门控时钟使能
usleep(10000);
SpiPs_write_read2(0x0A7,0x00,&rx_data);//处理器运行成果标志
temp=rx_data;
if (temp == 0x11) {
xil_printf("core run successful");
}
else {
xil_printf("core run unsuccessful");
}
////////////////////dpd系数加载////////////////////
SpiPs_write_read1(0x302,0xDF,&rx_data);
SpiPs_write_read1(0x0A3,0x52,&rx_data);
usleep(200000);
SpiPs_write_read2(0x0A7,0x00,&rx_data);//dpd系数加载完成标志
temp=rx_data;
if (temp == 0x61) {
xil_printf("dpd index load bin successful");
}
else {
xil_printf("dpd index load bin unsuccessful");
}
}
else {
SpiPs_write_read1(0x071,0x00,&rx_data);
SpiPs_write_read1(0x071,0x29,&rx_data);
for(int i=0;i<15379;i++){
addr[0]=(i>>8)&0xff;
addr[1]= i&0xff;
buf=rom_read((u8 *)&addr);
data[0]=buf>>24;
data[1]=(buf>>16)&0xff;
data[2]=(buf>>8)&0xff;
data[3]=buf&0xff;
for(int j=0;j<4;j++){
SpiPs_write_read1(0x070,data[j],&rx_data);
}
}
SpiPs_write_read1(0x071,0x26,&rx_data);
SpiPs_write_read1(0x02E,0x03,&rx_data);
usleep(100000);
//验证是否下载成功
SpiPs_write_read2(0x0AB,0x00,&rx_data);
temp=rx_data;
if (temp == 0x08) {
xil_printf("multicalib load bin successful");
}
else {
xil_printf("multicalib load bin unsuccessful");
}
}
}
@@ -0,0 +1,94 @@
/*
* frqhop_config.c
*
* Created on: 2023年11月24日
* Author: cxlab
*/
#include "xilinx_io.h"
#include "sleep.h"
#include "time.h"
#include "xtime_l.h"
#include "math.h"
#include "cx9261adriver.h"
CX9261A::Clock* ref_clock;
void trx_ch_pll_config(u8 pll_index);
void frqhop_config(int hop_flag){
static XTime tCur;
XTime_GetTime(&tCur);
srand(tCur);
static double hop_freq ;
hop_freq = (rand()%(800-30))+30+(rand()%(101))/(double)100;//随机产生[30,800)double类型的数
// double hop_freq = 400.52;
static double hop_freq1 = 800.25;
static int pll_index=1;
static int unlock_pll1_cnt=0,unlock_pll2_cnt=0;
if(hop_freq == hop_freq1){
if(pll_index == 2){
pll_index = 4;
}
else if(pll_index == 1){
pll_index = 3;
}
}
if(hop_flag == 1){
if(pll_index == 1 || pll_index == 3)
{
//切换至pll2来源
trx_ch_pll_config(2);
//配置pll1参数
CX9261A::configPll1(hop_freq,*ref_clock);
while (!CX9261A::afcPll1()) {
unlock_pll1_cnt++;
}
pll_index = 2;
}
else if(pll_index == 2 || pll_index == 4)
{
//切换至pll1来源
trx_ch_pll_config(1);
//配置pll2参数
CX9261A::configPll2(hop_freq,*ref_clock);
while (!CX9261A::afcPll2()) {
unlock_pll2_cnt++;
}
pll_index = 1;
}
else if(pll_index == 3 )
{
//切换至pll2来源
trx_ch_pll_config(2);
pll_index = 2;
}
else if(pll_index == 4 ){
//切换至pll1来源
trx_ch_pll_config(1);
pll_index = 1;
}
}
hop_freq1 = hop_freq;
if(unlock_pll2_cnt!=0 || unlock_pll1_cnt !=0){
xil_printf("pll1 unlock num: %d; pll2 unlock num: %d;.\n", unlock_pll1_cnt, unlock_pll2_cnt);
}
}
void trx_ch_pll_config(u8 pll_index)
{
u8 rx_data;
u8 recv_buf[3]={0};
u32 trx_ch_pll_data;
if(pll_index==1){
trx_ch_pll_data = 0x00077DCF;
}else if(pll_index==2){
trx_ch_pll_data = 0x00077D0C;
}
recv_buf[0] =(trx_ch_pll_data>>16 & 0xff)|0x80 ;
recv_buf[1] = trx_ch_pll_data>>8 & 0xff;
recv_buf[2] = trx_ch_pll_data & 0xff;
SpiPs_write_read(recv_buf,&rx_data);
}
@@ -0,0 +1,196 @@
#include "cx9261adriver.h"
#include "defs.h"
#include "utils.h"
#include "xilinx_io.h"
int main() {
SpiPsInit(SPI_DEVICE_ID);
GpioInit(GPIO_DEVICE_ID);
/* cx9261a configuration */
peripheral_test();
download_bin();//多频点校准CX9261A处理器执行文件
AXIGpioInit();
XScuGicInit();
ConfigAXIGPIOIntr();
ExceptionInit();
/***********************配置参数定义*****************************/
// 芯片配置结构体
CX9261A::CX9261AConfiguration configuration;
// 电源管理 (与评估软件电源管理自定义电源里面勾选项相对应,先左再右,从上往下)
// 接收模式电源管理
configuration.powerManagement.rxPower = {0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0,
0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1};
// 发射模式电源管理
configuration.powerManagement.txPower = {1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1};
// FDD模式电源管理
configuration.powerManagement.fddPower = {1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1,
0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1};
// 电源模式 即初始化配置结束后的电源模式
configuration.powerManagement.powerMode = CX9261A::PowerMode::Transmit;
// 接口模式
configuration.interface.workMode = CX9261A::WorkMode::Tx;
configuration.interface.trMode = CX9261A::TrMode::R1T1;
configuration.interface.portMode = CX9261A::PortMode::Single;
configuration.interface.ioMode = CX9261A::IOMode::CMOS;
// 时钟相关 (与评估软件参考配置和基带配置相对应)
configuration.clock.ref = 100;
configuration.clock .adc = 50;
configuration.clock .refDiv = 1;
configuration.clock .bbUseIntDiv = false;
configuration.clock .refDoubler = false;
// 本振相关
using LoSource = CX9261A::LoSource;
// 本振来源
configuration.pllSource.rxUseExt = false;
configuration.pllSource.txUseExt = false;
configuration.pllSource.rx1Source = LoSource::Pll1;
configuration.pllSource.rx2Source = LoSource::Pll1;
configuration.pllSource.rx3Source = LoSource::Off;
configuration.pllSource.tx1Source = LoSource::Pll1;
configuration.pllSource.tx2Source = LoSource::Pll1;
// 本振频率 注意:使用的所有PLL,频率必须设为正数
configuration.pllFreq.pll1Freq = 800;
configuration.pllFreq.pll2Freq = 5800;
configuration.pllFreq.pll3Freq = 800;
configuration.pllFreq.pll4Freq = 900;
configuration.pllFreq.pll5Freq = 1000;
// Rx通道 注意:tia推荐配置为6 Mixer为三个通道共用同一个寄存器
configuration.rx1Config.bandwidth = 32;
configuration.rx1Config.tia = 6;
configuration.rx1Config.mixer = 31;
configuration.rx2Config.bandwidth = 32;
configuration.rx2Config.tia = 6;
configuration.rx2Config.mixer = 31;
configuration.rx3Config.bandwidth = 32;
configuration.rx3Config.tia = 6;
configuration.rx3Config.mixer = 31;
// Tx通道
configuration.tx1Config.bandwidth = 20;
configuration.tx1Config.mixer = 63;
configuration.tx2Config.bandwidth = 20;
configuration.tx2Config.mixer = 63;
// 接收滤波器
configuration.rxFilters.fir = 0;
configuration.rxFilters.hbf1 = 0;
configuration.rxFilters.hbf2 = 0;
configuration.rxFilters.hbf3 = 0;
configuration.rxFilters.cic = 0;
// 发射滤波器
configuration.txFilters.fir = 0;
configuration.txFilters.hbf1 = 2;
configuration.txFilters.hbf2 = 2;
configuration.txFilters.hbf3 = 0;
configuration.txFilters.cic = 0;
// Rx NCO
configuration.rxNco.rxUseBist = false;
configuration.rxNco.rxNCOBypass = true;
configuration.rxNco.rxNCOUpward = true;
configuration.rxNco.rxNCOMaster = true;
configuration.rxNco.rxNCOFreq = 0;
// Tx NCO
configuration.txNco.txUseBist = true;
configuration.txNco.txNCOFreq = 1;
// AGC 注意:mode = 0表示关闭AGC,此时其他的参数可以不配置
configuration.agc.mode = 0;
configuration.agc.pdt.pdtN = 0;
configuration.agc.pdt.pdtM = 2;
configuration.agc.lmt.count = 15;
configuration.agc.lmt.threshold1 = 2;
configuration.agc.lmt.threshold2 = 2;
configuration.agc.lmt.threshold3 = 2;
configuration.agc.lmt.threshold4 = 2;
configuration.agc.dig.count = 15;
configuration.agc.dig.threshold1 =-10;
configuration.agc.dig.threshold2 =-14;
configuration.agc.dig.threshold3 =-30;
configuration.agc.dig.threshold4 =-40;
// 校准
//跳频qec校准频点预设,最多256个频点。其中包含初始频点则加载初始频点校准值给三个通道
configuration.calib.calibDC = true;
configuration.calib.dcCalibMethod = CX9261A::DCCalibMethod::Tracking;
configuration.calib.dcTrackingLength = 16384;
configuration.calib.dcHighPassFactor = 8191;
configuration.calib.rx1CalibPll = int(LoSource::Pll1);
configuration.calib.rx2CalibPll = int(LoSource::Pll1);
configuration.calib.rx3CalibPll = false;
configuration.calib.tx1CalibPll = int(LoSource::Pll1);
configuration.calib.tx2CalibPll = int(LoSource::Pll1);
configuration.calib.rxMethod = CX9261A::CalibMethod::TST;
configuration.calib.rxMultiPoints = {2000, 5600, 5800, 6000};
configuration.calib.txMethod = CX9261A::CalibMethod::Bisec;
configuration.calib.txMultiPoints = {3500, 5600, 5800, 6000};
configuration.calib.f0 = 5;
// 配置温补模式为跳子带温补
configuration.tempComp = CX9261A::TemperatureComp::Band;
ref_clock = &configuration.clock;
/***********************配置参数执行*****************************/
// 开始配置芯片
CX9261A::initialChip(); // 最开始需要调用此函数
CX9261A::initialPowerConfig(configuration);
// 配置温补
configTemperatureCompensation(configuration.tempComp);
using PowerMode = CX9261A::PowerMode;
// 不需要自定义电源管理时,这部分代码可以省略
CX9261A::configPowerPins(configuration.powerManagement.rxPower, PowerMode::Receive);
CX9261A::configPowerPins(configuration.powerManagement.txPower, PowerMode::Transmit);
CX9261A::configPowerPins(configuration.powerManagement.fddPower, PowerMode::Duplex);
// 配置pll
CX9261A::configBBPLL(configuration);
CX9261A::configPllSource(configuration.pllSource);
CX9261A::configPll1(configuration.pllFreq.pll1Freq, configuration.clock);
CX9261A::configPll2(configuration.pllFreq.pll2Freq, configuration.clock);
// CX9261A::configPll3(configuration.pllFreq.pll3Freq, configuration.clock);
// CX9261A::configPll4(configuration.pllFreq.pll4Freq, configuration.clock);
// 配置Rx通道
CX9261A::configRxChannel(configuration.rx1Config, CX9261A::RxChannel::Rx1);
CX9261A::configRxChannel(configuration.rx2Config, CX9261A::RxChannel::Rx2);
CX9261A::configRxChannel(configuration.rx3Config, CX9261A::RxChannel::Rx3);
// 配置Tx通道
using TxChannel = CX9261A::TxChannel;
CX9261A::configTxChannelFrequency(configuration.pllFreq.pll1Freq, TxChannel::Tx1);
CX9261A::configTxChannelFrequency(configuration.pllFreq.pll1Freq, TxChannel::Tx2);
CX9261A::configTxChannel(configuration.tx1Config, TxChannel::Tx1);
CX9261A::configTxChannel(configuration.tx2Config, TxChannel::Tx2);
// 配置滤波器
CX9261A::configRxFilters(configuration.rxFilters);
CX9261A::configTxFilters(configuration.txFilters);
// 配置NCO
CX9261A::configRxNco(configuration.rxNco, configuration.clock.adc);
const int filters = std::max(configuration.rxFilters.fir, 1) * std::max(configuration.rxFilters.hbf3, 1) *
std::max(configuration.rxFilters.hbf2, 1) *
std::max(configuration.rxFilters.hbf1, 1) * std::max(configuration.rxFilters.cic, 1);
CX9261A::configTxNco(configuration.txNco, configuration.clock.adc / filters);
// 配置AGC
CX9261A::configAGC(configuration.agc);
// 切换到休眠模式
CX9261A::configPowerMode(PowerMode::Sleep);
CX9261A::pause(1000);
// 切换到校准模式
CX9261A::configPowerMode(PowerMode::Calib);
CX9261A::pause(100);
// 锁定BBPLL
while (!CX9261A::afcBBPll()) {
}
// 配置接口
CX9261A::configInterface(configuration.interface);
// 配置FPGA接口相关 此为示例,仅适用于Demo工程,用户应根据实际情况进行配置
CX9261A::configFPGA(configuration.interface);
// 配置校准
CX9261A::configDcCalib(configuration.calib);
CX9261A::configADCCalib(configuration.clock.adc);
CX9261A::configFlashCalib();
CX9261A::configQecCalib(configuration);
// CX9261A::loadRxCalibPredis(0, CX9261A::RxChannel::Rx1, LoSource::Pll1);
// CX9261A::loadRxCalibPredis(0, CX9261A::RxChannel::Rx2, LoSource::Pll2);
// 切换到工作模式
CX9261A::configPowerMode(configuration.powerManagement.powerMode);
// 锁定PLL 根据本振来源确定是否需要AFC
CX9261A::afcPll1();
return 0;
}
@@ -0,0 +1,99 @@
/**
* @file utils.h
*/
#ifndef CX9261ADRIVER_UTILS_H
#define CX9261ADRIVER_UTILS_H
#include <algorithm>
#include <bitset>
#include <cmath>
#include <string>
namespace CX9261A {
#if __cplusplus >= 201703L
template <typename T>
constexpr const T& clamp(const T& v, const T& lo, const T& hi) {
return std::clamp(v, lo, hi);
}
#else
template <typename T>
constexpr const T& clamp(const T& v, const T& lo, const T& hi) {
return std::max(std::min(hi, v), lo);
}
#endif
template <typename Float>
int round(Float f) {
return static_cast<int>(std::round(f));
}
template <typename Float>
long long round64(Float f) {
return static_cast<long long>(std::round(f));
}
template <typename Float>
int floor(Float f) {
return static_cast<int>(std::floor(f));
}
template <typename Float>
long long floor64(Float f) {
return static_cast<long long>(std::floor(f));
}
template <typename Float>
int ceil(Float f) {
return static_cast<int>(std::ceil(f));
}
template <typename Float>
long long ceil64(Float f) {
return static_cast<long long>(std::ceil(f));
}
/**
* @brief Register类,提供方便的位操作函数
*/
class Register {
public:
template <typename T = int>
constexpr Register(const T value = 0) {
// static_assert(std::is_integral_v<T>, "Register value must be integral!");
m_value = static_cast<unsigned long long>(value);
}
/**
* 以十进制返回寄存器值
*/
unsigned char value() const { return static_cast<unsigned char>(m_value.to_ulong()); }
/**
* 对寄存器值进行部分值的替换操作
* 例:replace(7, 4, 0b1111); 使寄存器的高四位为1
* @param start 起始位
* @param end 中止位
* @param after 要替换的值
*/
void replace(const unsigned int start, const unsigned int end, unsigned char after) {
for (auto i = end; i <= start; ++i) {
m_value[i] = (after >> (i - end)) & 0b1;
}
}
auto operator[](const size_t position) { return m_value[position]; }
template <typename Type>
operator Type() const {
// static_assert(std::is_integral_v<Type>, "Type must be an integral");
return static_cast<Type>(m_value.to_ulong());
}
private:
std::bitset<8> m_value{};
};
template <int N>
std::string frac2bin(const double frac) {
const long double num = frac * (pow(2.0, N));
std::string ret = std::bitset<N>(std::floor(num)).to_string();
return ret;
}
} // namespace CX9261A
#endif // CX9261ADRIVER_UTILS_H
@@ -0,0 +1,313 @@
/*
* xilinx_io.cc
*
* Created on: 2024年3月5日
* Author: cxlab
*/
#include "sleep.h"
#include "math.h"
#include "xilinx_io.h" /* SPI device driver */
#include "cx9261adriver.h"
#include "utils.h"
#include <stdio.h>
static XSpiPs SpiInstance;
XGpioPs Gpio; /* The driver instance for GPIO Device. */
XGpio axi_gpio_inst; //PL 端 AXI GPIO 驱动实例
XScuGic scugic_inst; //中断控制器 驱动实例
XScuGic_Config * scugic_cfg_ptr; //中断控制器 配置信息
int hop_flag,hop_intr_flag;
static int spi_select_value=0;
//跳频中断初始化
void AXIGpioInit(void){
XGpio_Initialize(&axi_gpio_inst, AXI_GPIO_ID);
//配置 PL AXI GPIO
XGpio_SetDataDirection(&axi_gpio_inst, 1, 1); //设置 AXI GPIO 通道 1 为输入
XGpio_InterruptEnable(&axi_gpio_inst, FRQHOP_MASK); //使能通道 1 中断
XGpio_InterruptGlobalEnable(&axi_gpio_inst); //使能 AXI GPIO 全局中断
}
void ConfigAXIGPIOIntr(void){
//设置中断优先级和触发类型(高电平触发)
XScuGic_SetPriorityTriggerType(&scugic_inst, GPIO_INT_ID, 0xA0, 0x3);
//关联中断 ID 和中断处理函数
XScuGic_Connect(&scugic_inst, GPIO_INT_ID, axi_gpio_handler, &axi_gpio_inst);
//使能 AXI GPIO 中断
XScuGic_Enable(&scugic_inst, GPIO_INT_ID);
}
void axi_gpio_handler(void *CallbackRef){
XGpio *GpioPtr = (XGpio *)CallbackRef;
GpioWritePin(hop,0x01);
XGpio_InterruptDisable(GpioPtr, FRQHOP_MASK); //关闭 AXI GPIO 中断使能
frqhop_config(hop_flag);
XGpio_InterruptClear(GpioPtr, FRQHOP_MASK); //清除中断
XGpio_InterruptEnable(GpioPtr, FRQHOP_MASK); //使能 AXI GPIO 中断
GpioWritePin(hop,0x00);
}
void ExceptionInit(void){
//设置并打开中断异常处理功能
Xil_ExceptionInit();
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, &scugic_inst);
Xil_ExceptionEnable();
}
void XScuGicInit(void){
scugic_cfg_ptr = XScuGic_LookupConfig(SCUGIC_ID);
XScuGic_CfgInitialize(&scugic_inst, scugic_cfg_ptr, scugic_cfg_ptr->CpuBaseAddress);
}
void frqhop_flag(int frqhop_flag){
u8 rx_data;
hop_flag = frqhop_flag;
GpioWritePin(hop,0x01);
SpiPs_write_read2(0x615,0x00,&rx_data);
GpioWritePin(hop,0x00);
}
//ps spi(emio)初始化
int SpiPsInit(u16 SpiDeviceId){
int Status;
XSpiPs_Config *SpiConfig;
/*
* Initialize the SPI driver so that it's ready to use
*/
SpiConfig = XSpiPs_LookupConfig(SpiDeviceId);
if (NULL == SpiConfig) {
return XST_FAILURE;
}
Status = XSpiPs_CfgInitialize((&SpiInstance), SpiConfig,
SpiConfig->BaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* Perform a self-test to check hardware build
*/
Status = XSpiPs_SelfTest((&SpiInstance));
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* The SPI device is a slave by default and the clock phase
* have to be set according to its master. In this example, CPOL is set
* to quiescent high and CPHA is set to 1.
*/
XSpiPs_SetOptions((&SpiInstance), (XSPIPS_CR_CPHA_MASK) |
XSPIPS_MASTER_OPTION |
XSPIPS_FORCE_SSELECT_OPTION);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
XSpiPs_SetClkPrescaler((&SpiInstance), XSPIPS_CLK_PRESCALE_8);
/*
* Set the Rx FIFO Threshold to the Max Data
*/
// XSpiPs_SetRXWatermark((&SpiInstance),MAX_DATA);
/*
* Enable the device.
*/
XSpiPs_Enable((&SpiInstance));
return XST_SUCCESS;
}
//gpio(emio)初始化
int GpioInit(u16 DeviceId)
{
int Status;
XGpioPs_Config *ConfigPtr;
/* Initialize the GPIO driver. */
ConfigPtr = XGpioPs_LookupConfig(DeviceId);
Status = XGpioPs_CfgInitialize(&Gpio, ConfigPtr,
ConfigPtr->BaseAddr);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
return XST_SUCCESS;
}
int GpioSetPinDir(u32 Pin,u32 Direction){
XGpioPs_SetDirectionPin((&Gpio),GPIO_EMIO_OFFSET + Pin,Direction);
return 0;
}
int GpioWritePin(u32 Pin,u32 data){
GpioSetPinDir(Pin,GPIO_DIR_OUTPUT);
XGpioPs_SetOutputEnablePin(&Gpio, GPIO_EMIO_OFFSET + Pin, 1);
XGpioPs_WritePin((&Gpio),GPIO_EMIO_OFFSET + Pin,data);
return 0;
}
int GpioReadPin(u32 Pin){
GpioSetPinDir(Pin,GPIO_DIR_INPUT);
return XGpioPs_ReadPin((&Gpio),GPIO_EMIO_OFFSET + Pin);
}
//外设测试及相关复位
int peripheral_test(void){
u8 spi_test;
u8 BRAM_test;
u8 DDR_test;
// CX9261A 复位
GpioWritePin(NRST,0x00);
GpioWritePin(NRST,0x01);
// CX9261A接口驱动 复位
GpioWritePin(rst,0x01);
GpioWritePin(rst,0x00);
// CX9261A接收数据fifo 复位
GpioWritePin(aresetn_0,0x00);
GpioWritePin(aresetn_0,0x01);
GpioWritePin(aresetn_1,0x00);
GpioWritePin(aresetn_1,0x01);
GpioWritePin(aresetn_2,0x00);
GpioWritePin(aresetn_2,0x01);
// CX3E04 复位
GpioWritePin(cx3e04_rstn,0x00);
GpioWritePin(cx3e04_rstn,0x01);
// CX9261A spi选择 0:ps spi(emio);1:axi pl spi
GpioWritePin(spi_select,spi_select_value&0xff);
// SPI TEST
u8 rx_data;
xil_printf("start spi test.\r\n");
u8 spi_wr_buff[3]={0x87,0x82,0x5A};
u8 spi_rd_buff[3]={0x07,0x82,0x00};
SpiPs_write_read(spi_wr_buff,&rx_data);
SpiPs_write_read(spi_rd_buff,&rx_data);
if(rx_data==spi_wr_buff[2])
{
xil_printf("spi test successful.\r\n");
spi_test = 1;
}else
{
xil_printf("spi test unsuccessful.\r\n");
spi_test = 0;
}
//BRAM TEST
xil_printf("start bram test.\r\n");
BRAM_test = 1;
for (u32 i=0;i<8192;i++){
Xil_Out32(XPAR_BRAM_0_BASEADDR + 4*i,i);
u32 bram0_data= Xil_In32(XPAR_BRAM_0_BASEADDR + 4*i);
Xil_Out32(XPAR_BRAM_1_BASEADDR + 4*i,i);
u32 bram1_data= Xil_In32(XPAR_BRAM_1_BASEADDR + 4*i);
if(i != bram0_data)
{
xil_printf("BRAM0 ERROR,ADDR %x DATA %d read back is %d.\r\n",XPAR_BRAM_0_BASEADDR + 4*i,i,bram0_data);
BRAM_test = 0;
}
if(i != bram1_data)
{
xil_printf("BRAM1 ERROR,ADDR %x DATA %d read back is %d.\r\n",XPAR_BRAM_1_BASEADDR + 4*i,i,bram1_data);
BRAM_test = 0;
}
}
//MIG TEST
xil_printf("start mig test.\r\n");
DDR_test = 1;
for (u32 i=0;i<2048;i++){
Xil_Out32(TX_BUFFER_BASE + 4*i,i);
u32 ddr_data= Xil_In32(TX_BUFFER_BASE + 4*i);
if(i != ddr_data)
{
xil_printf("MIG ERROR,ADDR %x DATA %d read back is %d.\r\n",TX_BUFFER_BASE + 4*i,i,ddr_data);
DDR_test = 0;
}
}
if((spi_test==1)&&(BRAM_test==1)&&(DDR_test==1))
{
xil_printf("peripheral test successful.\r\n");
return 1;
}else
{
xil_printf("peripheral test unsuccessful.\r\n");
return 0;
}
}
//axi总线结合pl spi模块实现cx9261a spi读写
int cx9261a_write(int addr , int value)
{
Xil_Out32(AXI4_LITE1_SPI_BASEADDR+addr*4,value);
return 1;
}
int cx9261a_read(int addr)
{
return Xil_In32(AXI4_LITE1_SPI_BASEADDR+addr*4);
}
//ps spi(emio)实现cx9261a spi读写
int SpiPs_write_read(u8 * data,u8 * rx_data){
int Status;
u8 rx_buffer[3];
if(spi_select_value == 0){
rx_buffer[0]= *data;
rx_buffer[1]= *(data+1);
rx_buffer[2]= *(data+2);
if(rx_buffer[0] >= 128){
cx9261a_write((rx_buffer[0]-128)*256+rx_buffer[1],rx_buffer[2]);
}else{
*rx_data=cx9261a_read(rx_buffer[0]*256+rx_buffer[1]);
}
}else{
XSpiPs_SetSlaveSelect((&SpiInstance),0x00);
Status = XSpiPs_PolledTransfer((&SpiInstance),data,rx_buffer,3);
*rx_data = rx_buffer[2];
}
return 0;
}
int SpiPs_write_read1(u16 addr,u8 data,u8 * rx_data){
u8 rx_data1;
u16 temp;
u8 rx_buffer[3];
temp= addr&0xff00;
rx_buffer[0]= temp/256+SPI_WRITE;
rx_buffer[1]= addr&0x00ff;
rx_buffer[2]= data;
if(spi_select_value == 0){
cx9261a_write(addr,data);
}else{
SpiPs_write_read((u8 *)&rx_buffer,&rx_data1);
*rx_data = rx_data1;
}
return 0;
}
int SpiPs_write_read2(u16 addr,u8 data,u8 * rx_data){
u8 rx_data1;
u16 temp;
u8 rx_buffer[3];
temp= addr&0xff00;
rx_buffer[0]= temp/256+SPI_READ;
rx_buffer[1]= addr&0x00ff;
rx_buffer[2]= data;
if(spi_select_value == 0){
*rx_data=cx9261a_read(addr);
}else{
SpiPs_write_read((u8 *)&rx_buffer,&rx_data1);
*rx_data = rx_data1;
}
return 0;
}
//axi读取pl rom
int rom_read(u8 * data)
{
int addr ;
addr = *(data + 0)*256+ *(data + 1);
return Xil_In32(BROM_BASEADDR+addr*4);
}
@@ -0,0 +1,99 @@
/*
* xilinx_io.h
*
* Created on: 2021年9月6日
* Author: cxlab
*/
#ifndef SRC_XILINX_IO_H_
#define SRC_XILINX_IO_H_
#endif /* SRC_XILINX_IO_H_ */
#include "xspips.h" /* SPI device driver */
#include "xgpiops.h"
#include "xgpio.h"
#include "xparameters.h"
#include "xscugic.h"
#include "xil_exception.h"
#include "defs.h"
extern CX9261A::Clock* ref_clock;
#define SPI_WRITE 0x80
#define SPI_READ 0x00
#define GPIO_DIR_INPUT 0x00
#define GPIO_DIR_OUTPUT 0x01
#define GPIO_EMIO_OFFSET 54
#define NRST 0
#define ENABLE_TRX1 1
#define ENABLE_TRX2 2
#define ENABLE_TRX3 3
#define TXNRX_TRX1 4
#define TXNRX_TRX2 5
#define TXNRX_RX3 6
#define aresetn_0 33
#define rst 34
#define tr_sel 35
#define tdd_fdd_sel 36
#define r1t1_r2t2_sel 37
#define sp_dp_sel 38
#define aresetn_1 39
#define aresetn_2 40
#define hop 41
#define cx3e04_rstn 42
#define spi_select 46
#define SPI_DEVICE_ID XPAR_XQSPIPS_0_DEVICE_ID
#define GPIO_DEVICE_ID XPAR_PS7_GPIO_0_DEVICE_ID
#define BROM_BASEADDR XPAR_M08_AXI_0_BASEADDR
#define AXI4_LITE0_SPI_BASEADDR XPAR_AXI4_LITE_SPI_0_BASEADDR
#define AXI4_LITE1_SPI_BASEADDR XPAR_AXI4_LITE_SPI_1_BASEADDR
#define TX_BUFFER_BASE XPAR_MIG_7SERIES_0_BASEADDR +0x2000
#define GPIO_INT_ID XPAR_FABRIC_GPIO_0_VEC_ID //PL 端 AXI GPIO 中断 ID
#define AXI_GPIO_ID XPAR_AXI_GPIO_0_DEVICE_ID //PL 端 AXI GPIO 器件 ID
#define SCUGIC_ID XPAR_SCUGIC_0_DEVICE_ID //中断控制器 ID
#define FRQHOP_MASK XGPIO_IR_CH1_MASK //通道 1 的位定义
void AXIGpioInit(void);
void ConfigAXIGPIOIntr(void);
void axi_gpio_handler(void *CallbackRef);
void XScuGicInit(void);
void ExceptionInit(void);
void frqhop_flag(int frqhop_flag);
int SpiPsInit(u16 SpiDeviceId);
int GpioInit(u16 DeviceId);
int GpioSetPinDir(u32 Pin,u32 Direction);
int GpioWritePin(u32 Pin,u32 data);
int GpioReadPin(u32 Pin);
int peripheral_test(void);
//cx3e04和cx9261a初始化配置及读写寄存器函数
//void cx3e04_config(void);
//int cx3e04_write(int addr , int value);
//int cx3e04_read(int addr);
int cx9261a_write(int addr , int value);
int cx9261a_read(int addr);
int SpiPs_write_read(u8 * data,u8 * rx_data);
int SpiPs_write_read1(u16 addr,u8 data,u8 * rx_data);
int SpiPs_write_read2(u16 addr,u8 data,u8 * rx_data);
//跳频
void frqhop_config(int hop_flag);
void trx_ch_pll_config(u8 pll_index);
//PL rom读取和cx9261a bin文件下载
int rom_read(u8 * data);
void download_bin(void);
@@ -0,0 +1,107 @@
/*
* download_bin.c
*
* Created on: 2023年11月23日
* Author: cxlab
*/
#include "xilinx_io.h"
#include "sleep.h"
void download_bin(void){
int temp;
u8 rx_data;
u8 data[4];
u32 buf;
u8 addr[2];
int dpd_multicalib = 0;// 1:dpd,0:multicalib
if (dpd_multicalib) {
SpiPs_write_read1(0x079,0x00,&rx_data);//关闭CRC校验
SpiPs_write_read1(0x071,0x00,&rx_data);
SpiPs_write_read1(0x071,0x09,&rx_data);
for(int i=0;i<5507;i++){
addr[0]=(i>>8)&0xff;
addr[1]= i&0xff;
buf=rom_read((u8 *)&addr);
data[0]=buf>>24;
data[1]=(buf>>16)&0xff;
data[2]=(buf>>8)&0xff;
data[3]=buf&0xff;
for(int j=0;j<4;j++){
SpiPs_write_read1(0x070,data[j],&rx_data);
}
}
SpiPs_write_read1(0x071,0x1A,&rx_data);//开启CRC校验
SpiPs_write_read1(0x079,0x08,&rx_data);//开启CRC校验
usleep(1000);
SpiPs_write_read2(0x078,0x00,&rx_data);
temp=rx_data;
if (temp == 0x01) {
xil_printf("CRC successful");
}
else {
xil_printf("CRC unsuccessful");
}
SpiPs_write_read1(0x071,0x06,&rx_data);//处理器门控时钟使能
usleep(10000);
SpiPs_write_read2(0x0A7,0x00,&rx_data);//处理器运行成果标志
temp=rx_data;
if (temp == 0x11) {
xil_printf("core run successful");
}
else {
xil_printf("core run unsuccessful");
}
////////////////////dpd系数加载////////////////////
SpiPs_write_read1(0x302,0xDF,&rx_data);
SpiPs_write_read1(0x0A3,0x52,&rx_data);
usleep(200000);
SpiPs_write_read2(0x0A7,0x00,&rx_data);//dpd系数加载完成标志
temp=rx_data;
if (temp == 0x61) {
xil_printf("dpd index load bin successful");
}
else {
xil_printf("dpd index load bin unsuccessful");
}
}
else {
SpiPs_write_read1(0x071,0x00,&rx_data);
SpiPs_write_read1(0x071,0x29,&rx_data);
for(int i=0;i<15379;i++){
addr[0]=(i>>8)&0xff;
addr[1]= i&0xff;
buf=rom_read((u8 *)&addr);
data[0]=buf>>24;
data[1]=(buf>>16)&0xff;
data[2]=(buf>>8)&0xff;
data[3]=buf&0xff;
for(int j=0;j<4;j++){
SpiPs_write_read1(0x070,data[j],&rx_data);
}
}
SpiPs_write_read1(0x071,0x26,&rx_data);
SpiPs_write_read1(0x02E,0x03,&rx_data);
usleep(100000);
//验证是否下载成功
SpiPs_write_read2(0x0AB,0x00,&rx_data);
temp=rx_data;
if (temp == 0x08) {
xil_printf("multicalib load bin successful");
}
else {
xil_printf("multicalib load bin unsuccessful");
}
SpiPs_write_read1(0x02E,0x00,&rx_data);
}
}
@@ -0,0 +1,436 @@
/*
* Copyright (C) 2016 - 2018 Xilinx, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
*/
#include <stdio.h>
#include <string.h>
#include "lwip/sockets.h"
#include "netif/xadapter.h"
#include "lwipopts.h"
#include "xil_printf.h"
#include "FreeRTOS.h"
#include "task.h"
#include "xilinx_io.h"
#define THREAD_STACKSIZE 1024
#define ACK 0x01
u16_t echo_port = 7;
//#define RECV_BUF_SIZE 65536*16*8
#define RECV_BUF_SIZE 1024
//char recv_buf[RECV_BUF_SIZE];
char recv_buf[1024];
char recv_buf_temp[3];
char trans_buf[8192*5];
struct spi_stack spistack;
u16 hop_cnt = 0;
void print_echo_app_header()
{
xil_printf("%20s %6d %s\r\n", "echo server",
echo_port,
"$ telnet <board_ip> 7");
}
enum {
CMD_VER = 0,
CMD_RST = 1,
CMD_SPI_WRI = 2 ,
CMD_SPI_READ = 3,
CMD_DATA_CAPTURE0 = 4,
CMD_WAVE_DOWNLOAD = 5,
CMD_PIN_SET = 6,
CMD_DATA_CAPTURE1 = 8,
CMD_DATA_CAPTURE2 = 9,
CMD_STACK_OUT = 10,
CMD_hopping = 11,
CMD_qecbin = 12,
CMD_cx9261a_config = 13,
CMD_cx3e04_config = 14,
CMD_cx3e04_SPI_WRI = 15 ,
CMD_cx3e04_SPI_READ = 16,
CMD_IMAGE_UPDATE = 22,
};
/* thread spawned for each connection */
void process_echo_request(void *p)
{
int sd = (int)p;
int status;
int n, nwrote,send_n,total_send;
u8 rx_data;
u32 capture_length;
u8 pin;
u8 pin_value;
char FPGA_SDK_IP[]="FPGA:2024829-SDK:202400829";
spistack.spi_write_num = 0;
while (1) {
/* read a max of RECV_BUF_SIZE bytes from socket */
if ((n = read(sd, recv_buf, 5)) < 0) {
xil_printf("%s: error reading from socket %d, closing socket\r\n", __FUNCTION__, sd);
break;
}
/* break if the recved message = "quit" */
if (!strncmp(recv_buf, "quit", 4))
break;
/* break if client closed connection */
if (n <= 0)
break;
else{/* excute cmd if recved message = "cmd"*/
n=0;
if (!strncmp(recv_buf, "cmd ", 4)){
// xil_printf("%d %d %d %d.\r\n", recv_buf[0],recv_buf[1],recv_buf[2],recv_buf[4]);
dbg_printf("Rece %d bytes.\r\n",n);
switch(recv_buf[4]){
case CMD_IMAGE_UPDATE:
{
u32 offset;
u32 image_size;
recv_buf[0] = ACK;
nwrote = write(sd, recv_buf, 1);
n = read(sd, recv_buf, RECV_BUF_SIZE);
offset = *(u32 *)recv_buf;
image_size = *(u32 *)(recv_buf + 4);
xil_printf("offset is 0x%x image_size is 0x%x.\n", offset, image_size);
void *image_ptr = (void *)0x30000000;
u32 LengthBytes;
write(sd, recv_buf, 1); // ask for image data
//// receive flash image to ddr
LengthBytes = 0;
while (LengthBytes < image_size)
{
n = read(sd, image_ptr + LengthBytes, RECV_BUF_SIZE);
// xil_printf("read %d bytes.\n",n);
LengthBytes = LengthBytes + n;
}
// image data sumcheck
// program image data into flash
//QspiStore( (u32) image_ptr, offset, image_size);
//xil_printf("flash program done.\n", n);
status = FfsSdWrite(image_ptr, image_size);
write(sd, recv_buf, 1); // send done
xil_printf("sd program done.\n", n);
n = 0;
break;
}
case CMD_VER:
dbg_printf("Version:FPGA_20240829;SDK_20240829;IP_192.168.1.99.\r\n");
n=26;
for(int i=0;i<26;i++){
recv_buf[i] = FPGA_SDK_IP[i];
}
break;
case CMD_RST:
dbg_printf("Rece cmd excute rst.\r\n");
DeviceRst();
break;
case CMD_STACK_OUT:
dbg_printf("Rece cmd STACK OUT.\r\n");
spi_stack_out(&spistack);
n=1;
recv_buf[0] = 0x55;
break;
case CMD_SPI_WRI:
read(sd, &recv_buf[5], 3);//´ÓsocketÖжÁ3¸ö×Ö·û·ÅÔÚrecv_buf[5:7]ÖÐ
dbg_printf("Rece cmd excute spi write.\r\n");
dbg_printf("ADDR 0x%x DATA 0x%x.\r\n",recv_buf[5]*256+recv_buf[6]-32768,recv_buf[7]);
// SpiPs_write_read((u8 *)&recv_buf[5],&rx_data);
status = spi_stack_in((u8 *)&recv_buf[5],&spistack);
if(status){//when memory is near full,start spi write
spi_stack_out(&spistack);
}
// n=1;
// recv_buf[0] = rx_data;
break;
case CMD_SPI_READ:
read(sd, &recv_buf[5], 3);
dbg_printf("Rece cmd excute spi read.\r\n");
dbg_printf("ADDR 0x%x DATA 0x%x.\r\n",recv_buf[5]*256+recv_buf[6],recv_buf[7]);
SpiPs_write_read((u8 *)&recv_buf[5],&rx_data);
n=1;
recv_buf[0] = rx_data;
break;
case CMD_DATA_CAPTURE0:
read(sd, &recv_buf[5], 4);
capture_length = *((u32 *) &recv_buf[5]);//num of sample
dbg_printf("Rece cmd excute %d sample data capture.\r\n",capture_length);
XAxiDmaCapture(xAxiDma0Get(),capture_length);
n = capture_length*8;
total_send = 0;
/* handle request */
while(n>0){
if(n>1024)
send_n = 1024;
else
send_n = n;
n= n-send_n;
memcpy(recv_buf,TX_BUFFER_BASE + total_send,send_n);
total_send = total_send + send_n;
if ((nwrote = write(sd, &recv_buf, send_n)) < 0) {
xil_printf("%s: ERROR responding to client echo request. received = %d, written = %d\r\n",__FUNCTION__, n, nwrote);
xil_printf("Closing socket %d\r\n", sd);
break;
}
else{
if(send_n!=nwrote){
xil_printf("%d Bytes Send %d.\r\n", send_n,nwrote);
}
}
}
dbg_printf("Send %d bytes.\r\n",n);
break;
case CMD_DATA_CAPTURE1:
read(sd, &recv_buf[5], 4);
capture_length = *((u32 *) &recv_buf[5]);//num of sample
dbg_printf("Rece cmd excute %d sample data capture.\r\n",capture_length);
XAxiDmaCapture(xAxiDma1Get(),capture_length);
n = capture_length*8;
total_send = 0;
/* handle request */
while(n>0){
if(n>1024)
send_n = 1024;
else
send_n = n;
n= n-send_n;
memcpy(recv_buf,TX_BUFFER_BASE + total_send,send_n);
total_send = total_send + send_n;
if ((nwrote = write(sd, &recv_buf, send_n)) < 0) {
xil_printf("%s: ERROR responding to client echo request. received = %d, written = %d\r\n",__FUNCTION__, n, nwrote);
xil_printf("Closing socket %d\r\n", sd);
break;
}
else{
if(send_n!=nwrote){
xil_printf("%d Bytes Send %d.\r\n", send_n,nwrote);
}
}
}
dbg_printf("Send %d bytes.\r\n",n);
break;
case CMD_DATA_CAPTURE2:
read(sd, &recv_buf[5], 4);
capture_length = *((u32 *) &recv_buf[5]);//num of sample
dbg_printf("Rece cmd excute %d sample data capture.\r\n",capture_length);
XAxiDmaCapture(xAxiDma2Get(),capture_length);
n = capture_length*8;
total_send = 0;
/* handle request */
while(n>0){
if(n>1024)
send_n = 1024;
else
send_n = n;
n= n-send_n;
memcpy(recv_buf,TX_BUFFER_BASE + total_send,send_n);
total_send = total_send + send_n;
if ((nwrote = write(sd, &recv_buf, send_n)) < 0) {
xil_printf("%s: ERROR responding to client echo request. received = %d, written = %d\r\n",__FUNCTION__, n, nwrote);
xil_printf("Closing socket %d\r\n", sd);
break;
}
else{
if(send_n!=nwrote){
xil_printf("%d Bytes Send %d.\r\n", send_n,nwrote);
}
}
}
dbg_printf("Send %d bytes.\r\n",n);
break;
case CMD_WAVE_DOWNLOAD:
dbg_printf("Rece cmd excute wave download.\r\n");
while(n<WAVE_LENGTH){
dbg_printf("Rece data num in recv_buf is %d.\r\n",n);
n =n + read(sd, &trans_buf[n], 512);//
}
dbg_printf("Rece data num in recv_buf is %d.\r\n",n);
DownloadWave((u8 *)&trans_buf[0]);
n=0;
break;
case CMD_PIN_SET:
read(sd, &recv_buf[5], 2);
pin = (u8) recv_buf[5];
pin_value = (u8) recv_buf[6];
dbg_printf("Rece cmd excute pin %d set %d.\r\n",pin,pin_value);
GpioWritePin(pin,pin_value&0x01);
break;
case CMD_hopping:
read(sd, &recv_buf[5], 4);
int hop_flag=recv_buf[5]&0x01;
frqhop_flag(hop_flag);
if(hop_flag==1){
xil_printf("hopping freqence start.\r\n");
}else{
xil_printf("hopping freqence end.\r\n");
}
break;
case CMD_qecbin:
download_bin();
break;
case CMD_cx9261a_config:
cx9261a_config();
break;
case CMD_cx3e04_config:
cx3e04_config();
break;
case CMD_cx3e04_SPI_WRI:
read(sd, &recv_buf[5], 3);
dbg_printf("Rece cmd excute cx3e04_spi write.\r\n");
dbg_printf("ADDR 0x%x DATA 0x%x.\r\n",recv_buf[5]*256+recv_buf[6]-32768,recv_buf[7]);
int addr = recv_buf[5]*256+recv_buf[6];
int value= recv_buf[7];
cx3e04_write(addr,value);
break;
case CMD_cx3e04_SPI_READ:
read(sd, &recv_buf[5], 2);
dbg_printf("Rece cmd excute cx3e04_spi read.\r\n");
dbg_printf("ADDR 0x%x.\r\n",recv_buf[5]*256+recv_buf[6]);
addr = recv_buf[5]*256+recv_buf[6];
n=1;
recv_buf[0] = cx3e04_read(addr);
break;
default :
xil_printf("cmd error 0x%x",recv_buf[4]);
break;
}
/*if(recv_buf[4] == 7){
read(sd, &recv_buf[5], 4);
capture_length = *((u32 *) &recv_buf[5]);//num of sample
dbg_printf("Rece cmd excute %d sample data capture.\r\n",capture_length);
XAxiDmaCapture2(capture_length);
// memcpy(recv_buf,TX_BUFFER_BASE,capture_length*8);
n = capture_length*8;
total_send = 0;
// handle request
while(n>0){
if(n>1024)
send_n = 1024;
else
send_n = n;
n= n-send_n;
total_send = total_send + send_n;
memcpy(recv_buf,TX_BUFFER_BASE + total_send,send_n);
if ((nwrote = write(sd, &recv_buf, send_n)) < 0) {
xil_printf("%s: ERROR responding to client echo request. received = %d, written = %d\r\n",
__FUNCTION__, n, nwrote);
xil_printf("Closing socket %d\r\n", sd);
break;
}
else{
if(send_n!=nwrote){
xil_printf("%d Bytes Send %d.\r\n", send_n,nwrote);
}
}
}
dbg_printf("Send %d bytes.\r\n",n);
}*/
}
}
/* handle request */
if ((nwrote = write(sd, recv_buf, n)) < 0) {
xil_printf("%s: ERROR responding to client echo request. received = %d, written = %d\r\n",
__FUNCTION__, n, nwrote);
xil_printf("Closing socket %d\r\n", sd);
break;
}
else{
if(n!=nwrote){
xil_printf("%d Bytes Send %d.\r\n", n,nwrote);
}
}
}
/* close connection */
close(sd);
vTaskDelete(NULL);
}
void echo_application_thread()
{
int sock, new_sd;
int size;
#if LWIP_IPV6==0
struct sockaddr_in address, remote;
memset(&address, 0, sizeof(address));
if ((sock = lwip_socket(AF_INET, SOCK_STREAM, 0)) < 0)
return;
address.sin_family = AF_INET;
address.sin_port = htons(echo_port);
address.sin_addr.s_addr = INADDR_ANY;
#else
struct sockaddr_in6 address, remote;
memset(&address, 0, sizeof(address));
address.sin6_len = sizeof(address);
address.sin6_family = AF_INET6;
address.sin6_port = htons(echo_port);
memset(&(address.sin6_addr), 0, sizeof(address.sin6_addr));
if ((sock = lwip_socket(AF_INET6, SOCK_STREAM, 0)) < 0)
return;
#endif
if (lwip_bind(sock, (struct sockaddr *)&address, sizeof (address)) < 0)
return;
lwip_listen(sock, 0);
size = sizeof(remote);
while (1) {
if ((new_sd = lwip_accept(sock, (struct sockaddr *)&remote, (socklen_t *)&size)) > 0) {
sys_thread_new("echos", process_echo_request,
(void*)new_sd,
THREAD_STACKSIZE,
DEFAULT_THREAD_PRIO);
}
}
}
@@ -0,0 +1,260 @@
/*
* frqhop_config.c
*
* Created on: 2023年11月24日
* Author: cxlab
*/
#include "xilinx_io.h"
#include "sleep.h"
#include "time.h"
#include "xtime_l.h"
#include "math.h"
#include <stdlib.h>
void frqhop_config(int hop_flag){
XTime tCur;
XTime_GetTime(&tCur);
srand(tCur);
// double hop_freq = (rand()%(800-30))+30+(rand()%(101))/(double)100;//随机产生[30,800)double类型的数
double hop_freq = 400.52;
double hop_freq1 = 800.25;
static int pll_index=1;
static int unlock_pll1_cnt=0,unlock_pll2_cnt=0;
if(hop_freq == hop_freq1){
if(pll_index == 2){
pll_index = 4;
}
else if(pll_index == 1){
pll_index = 3;
}
}
if(hop_flag == 1){
if(pll_index == 1)
{
//切换至pll2来源
trx_ch_pll_config(2);
//配置pll1参数
unlock_pll1_cnt=PLL_config(1,hop_freq)-1;
pll_index = 2;
}
else if(pll_index == 2){
//切换至pll1来源
trx_ch_pll_config(1);
//配置pll2参数
unlock_pll2_cnt=PLL_config(2,hop_freq1)-1;
pll_index = 1;
}
else if(pll_index == 3 )
{
//切换至pll2来源
trx_ch_pll_config(2);
pll_index = 2;
}
else if(pll_index == 4 ){
//切换至pll1来源
trx_ch_pll_config(1);
pll_index = 1;
}
}
hop_freq1 = hop_freq;
if(unlock_pll2_cnt!=0 || unlock_pll1_cnt !=0){
xil_printf("pll1 unlock num: %d; pll2 unlock num: %d;.\n", unlock_pll1_cnt, unlock_pll2_cnt);
}
}
u16 pll1_config_addr[] ={0x0620,0x061D,0x0B06,0x0B07,0x0B08,0x0B09,0x0B0A,0x061A,0x061B,0x061C,0x062A};
u16 pll2_config_addr[] ={0x0642,0x063F,0x0B14,0x0B15,0x0B16,0x0B17,0x0B18,0x063C,0x063D,0x063E,0x064C};
u16 pll3_config_addr[] ={0x0664,0x0661,0x0B22,0x0B23,0x0B24,0x0B25,0x0B26,0x065E,0x065F,0x0660,0x066E};
u16 pll4_config_addr[] ={0x0686,0x0683,0x0B30,0x0B31,0x0B32,0x0B33,0x0B34,0x0680,0x0681,0x0682,0x0690};
int PLL_config(u8 pll_index,double pll_frq)
{
int i = 0,afc_cnt=0;
u16 pll_config_addr[11];
u16 afc_addr,lock_addr;
double ref=100;
u8 pllreg_buf[11];
u8 recv_buf[3];
u8 rx_data,pll_div;
u16 div_addr;
switch(pll_index){
case 1:for (i = 0; i < 11; i++){pll_config_addr[i] = pll1_config_addr[i];} afc_addr=0x0617;lock_addr=0x0635;break;
case 2:for (i = 0; i < 11; i++){pll_config_addr[i] = pll2_config_addr[i];} afc_addr=0x0639;lock_addr=0x0657;break;
case 3:for (i = 0; i < 11; i++){pll_config_addr[i] = pll3_config_addr[i];} afc_addr=0x065B;lock_addr=0x0679;break;
case 4:for (i = 0; i < 11; i++){pll_config_addr[i] = pll4_config_addr[i];} afc_addr=0x067D;lock_addr=0x069B;break;
default :;
}
//caculate pll frequence word
pll_frq_caculation_new(ref,pll_frq,(u8 *)&pllreg_buf);
for (i = 0; i < 11; i++)
{
recv_buf[0] = (pll_config_addr[i]>>8 & 0xff)|0x80 ;
recv_buf[1] = pll_config_addr[i] & 0xff;
recv_buf[2] = pllreg_buf[i] & 0xff;
SpiPs_write_read((u8 *)&recv_buf[0],&rx_data);
}
//afc pll
pll_div = pllreg_buf[1];
div_addr = pll_config_addr[1];
recv_buf[0] = lock_addr>>8 & 0xff ;
recv_buf[1] = lock_addr & 0xff;
recv_buf[2] = 0x00;
rx_data = 0;
while(rx_data!=48){
PLL_afc(afc_addr,div_addr,pll_div);
SpiPs_write_read((u8 *)&recv_buf[0],&rx_data);
afc_cnt++;
}
return afc_cnt;
//xil_printf("afc lock count: %d.\r\n",afc_cnt);
}
void trx_ch_pll_config(u8 pll_index)
{
u8 rx_data;
u8 recv_buf[3]={0};
u32 trx_ch_pll_data;
if(pll_index==1){
trx_ch_pll_data = 0x00077DCF;
}else if(pll_index==2){
trx_ch_pll_data = 0x00077D0C;
}
recv_buf[0] =(trx_ch_pll_data>>16 & 0xff)|0x80 ;
recv_buf[1] = trx_ch_pll_data>>8 & 0xff;
recv_buf[2] = trx_ch_pll_data & 0xff;
SpiPs_write_read(recv_buf,&rx_data);
}
void PLL_afc(u16 afc_addr,u16 div_addr,u8 pll_div){
u8 recv_buf[3];
u8 rx_data;
if(pll_div>=48){
recv_buf[0] = (div_addr>>8 & 0xff)|0x80 ;
recv_buf[1] = div_addr & 0xff;
recv_buf[2] = pll_div & 0x2f;
SpiPs_write_read((u8 *)&recv_buf[0],&rx_data);
}
recv_buf[0] = (afc_addr>>8 & 0xff)|0x80 ;
recv_buf[1] = afc_addr & 0xff;
recv_buf[2] = 0x00;
SpiPs_write_read((u8 *)&recv_buf[0],&rx_data);
recv_buf[2] = 0x13;
SpiPs_write_read((u8 *)&recv_buf[0],&rx_data);
usleep(40);
if(pll_div>=48){
recv_buf[0] = (div_addr>>8 & 0xff)|0x80 ;
recv_buf[1] = div_addr & 0xff;
recv_buf[2] = pll_div & 0xff;
SpiPs_write_read((u8 *)&recv_buf[0],&rx_data);
}
}
int pll_frq_caculation_new(double ref,double pll_frq,u8 *reg_data){
u8 row,column;
double vco = pll_frq;
int div = 1;
while(vco < 6701){
vco = vco*2;
div = div*2;
}
char coreTable[7][4][3] = {{{0x0C,0x30,0x08},{0x0B,0x30,0x09},{0x0C,0x30,0x05},{0x0D,0x30,0x08}},
{{0x0C,0x30,0x0C},{0x0B,0x30,0x0E},{0x0C,0x30,0x08},{0x0D,0x30,0x0B}},
{{0x0C,0x20,0x10},{0x0B,0x20,0x10},{0x0C,0x20,0x0A},{0x0D,0x20,0x0D}},
{{0x0C,0x20,0x11},{0x0B,0x20,0x13},{0x0C,0x20,0x0C},{0x0D,0x20,0x0F}},
{{0x0D,0x30,0x14},{0x0D,0x22,0x14},{0x0D,0x20,0x0D},{0x0D,0x15,0x0C}},
{{0x0E,0x30,0x18},{0x0E,0x25,0x16},{0x0E,0x25,0x0F},{0x0E,0x18,0x0F}},
{{0x0F,0x38,0x1A},{0x0F,0x32,0x1C},{0x0F,0x18,0x12},{0x0F,0x18,0x12}}};
if (ref >= 28 && ref < 40){
row = 0;
}else if (ref >= 40 && ref < 60){
row = 1;
}else if (ref >= 60 && ref < 90){
row = 2;
}else if (ref >= 90 && ref < 110){
row = 3;
}else if (ref >= 110 && ref < 140){
row = 4;
}else if (ref >= 140 && ref < 180){
row = 5;
}else if (ref >= 180 && ref <= 240){
row = 6;
}
if (vco < 8400){
column = 0;
}else if (vco >= 8400 && vco < 10150){
column = 1;
}else if (vco >= 10150 && vco < 12000){
column = 2;
}else if (vco >= 12000 ){
column = 3;
}
char cp = coreTable[row][column][0];
char c1r3 = coreTable[row][column][1];
char r1 = coreTable[row][column][2];
char dither,nHigh,nLow,fHigh,fMiddle,fLow,outputDiv,core = 0x81;
if(vco > 10150){
core = core + 0x10;
}
if (div == 2){
outputDiv = 0+7;
}else if (div == 4){
outputDiv = 32+7;
}else{
outputDiv = 48 + divBin(div);
}
double nf = (int64_t)(round(vco / ref * 1e9)) / 1.0e9;
int n = nf;
double f = nf - n;
if(f > 1e-10){
dither = 11;
}else{
dither = 0;
}
if(n >= 256){
nHigh = 1;
}else{
nHigh = 0;
}
nLow = n & 0xff;
int f1 = f * pow(2,24);
fHigh = f1>>16 & 0xff;
fMiddle = f1>>8 & 0xff;
fLow = f1 & 0xff;
reg_data[0]=core;
reg_data[1]=outputDiv;
reg_data[2]=nHigh;
reg_data[3]=nLow;
reg_data[4]=fHigh;
reg_data[5]=fMiddle;
reg_data[6]=fLow;
reg_data[7]=cp;
reg_data[8]=c1r3;
reg_data[9]=r1;
reg_data[10]=dither;
return 0;
}
char divBin(u16 div){
switch(div){
case 8:return 7;break;
case 16:return 6;break;
case 32:return 5;break;
case 64:return 4;break;
case 128:return 3;break;
case 256:return 2;break;
default :return 2;
}
}
@@ -0,0 +1,115 @@
/*
* Copyright (C) 2016 - 2018 Xilinx, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
*/
#include <stdio.h>
#include "xparameters.h"
#if defined (__arm__) || defined(__aarch64__)
#include "xil_printf.h"
#endif
#ifdef XPS_BOARD_ZCU102
#ifdef XPAR_XIICPS_0_DEVICE_ID
#include "xiicps.h"
#define BUF_LEN 10U
#define IOEXPANDER1_ADDR 0x20U
#define IIC_SCLK_RATE_IOEXP 400000
#define CMD_CFG_0_REG 0x06U
#define CMD_OUTPUT_0_REG 0x02U
#define DATA_OUTPUT 0x0U
#define DATA_COMMON_CFG 0xE0U
#define DATA_GT_0000_CFG 0x00U
XIicPs I2c0InstancePtr;
int IicPhyReset(void)
{
u8 WriteBuffer[BUF_LEN] = {0};
XIicPs_Config *I2c0CfgPtr;
int Status = XST_SUCCESS;
/* Initialize the IIC0 driver so that it is ready to use */
I2c0CfgPtr = XIicPs_LookupConfig(XPAR_XIICPS_0_DEVICE_ID);
if (I2c0CfgPtr == NULL) {
Status = XST_FAILURE;
return Status;
}
Status = XIicPs_CfgInitialize(&I2c0InstancePtr, I2c0CfgPtr,
I2c0CfgPtr->BaseAddress);
if (Status != XST_SUCCESS) {
Status = XST_FAILURE;
return Status;
}
/* Set the IIC serial clock rate */
XIicPs_SetSClk(&I2c0InstancePtr, IIC_SCLK_RATE_IOEXP);
/* Configure I/O pins as Output */
WriteBuffer[0] = CMD_CFG_0_REG;
WriteBuffer[1] = DATA_OUTPUT;
Status = XIicPs_MasterSendPolled(&I2c0InstancePtr,
WriteBuffer, 2, IOEXPANDER1_ADDR);
if (Status != XST_SUCCESS) {
Status = XST_FAILURE;
return Status;
}
/* Wait until bus is idle to start another transfer */
while (XIicPs_BusIsBusy(&I2c0InstancePtr));
/*
* Deasserting I2C_MUX_RESETB
* And GEM3 Resetb
* Selecting lanes based on configuration
*/
WriteBuffer[0] = CMD_OUTPUT_0_REG;
/* gt0000 or no GT configuration */
WriteBuffer[1] = DATA_COMMON_CFG | DATA_GT_0000_CFG;
/* Send the Data */
Status = XIicPs_MasterSendPolled(&I2c0InstancePtr,
WriteBuffer, 2, IOEXPANDER1_ADDR);
if (Status != XST_SUCCESS) {
Status = XST_FAILURE;
return Status;
}
/* Wait until bus is idle */
while (XIicPs_BusIsBusy(&I2c0InstancePtr));
xil_printf("IIC PHY reset on ZCU102 successful \n\r");
}
#endif
#endif
@@ -0,0 +1,291 @@
/*******************************************************************/
/* */
/* This file is automatically generated by linker script generator.*/
/* */
/* Version: 2018.3 */
/* */
/* Copyright (c) 2010-2016 Xilinx, Inc. All rights reserved. */
/* */
/* Description : Cortex-A9 Linker Script */
/* */
/*******************************************************************/
_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x400;
_HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x400;
_ABORT_STACK_SIZE = DEFINED(_ABORT_STACK_SIZE) ? _ABORT_STACK_SIZE : 1024;
_SUPERVISOR_STACK_SIZE = DEFINED(_SUPERVISOR_STACK_SIZE) ? _SUPERVISOR_STACK_SIZE : 2048;
_IRQ_STACK_SIZE = DEFINED(_IRQ_STACK_SIZE) ? _IRQ_STACK_SIZE : 1024;
_FIQ_STACK_SIZE = DEFINED(_FIQ_STACK_SIZE) ? _FIQ_STACK_SIZE : 1024;
_UNDEF_STACK_SIZE = DEFINED(_UNDEF_STACK_SIZE) ? _UNDEF_STACK_SIZE : 1024;
/* Define Memories in the system */
MEMORY
{
axi_bram_ctrl_0_Mem0 : ORIGIN = 0x42000000, LENGTH = 0x8000
axi_bram_ctrl_1_Mem0 : ORIGIN = 0x43000000, LENGTH = 0x8000
mig_7series_0_memaddr : ORIGIN = 0x80000000, LENGTH = 0x40000000
ps7_ddr_0 : ORIGIN = 0x100000, LENGTH = 0x3FF00000
ps7_qspi_linear_0 : ORIGIN = 0xFC000000, LENGTH = 0x2000000
ps7_ram_0 : ORIGIN = 0x0, LENGTH = 0x30000
ps7_ram_1 : ORIGIN = 0xFFFF0000, LENGTH = 0xFE00
}
/* Specify the default entry point to the program */
ENTRY(_vector_table)
/* Define the sections, and where they are mapped in memory */
SECTIONS
{
.text : {
KEEP (*(.vectors))
*(.boot)
*(.text)
*(.text.*)
*(.gnu.linkonce.t.*)
*(.plt)
*(.gnu_warning)
*(.gcc_execpt_table)
*(.glue_7)
*(.glue_7t)
*(.vfp11_veneer)
*(.ARM.extab)
*(.gnu.linkonce.armextab.*)
} > ps7_ddr_0
.init : {
KEEP (*(.init))
} > ps7_ddr_0
.fini : {
KEEP (*(.fini))
} > ps7_ddr_0
.rodata : {
__rodata_start = .;
*(.rodata)
*(.rodata.*)
*(.gnu.linkonce.r.*)
__rodata_end = .;
} > ps7_ddr_0
.rodata1 : {
__rodata1_start = .;
*(.rodata1)
*(.rodata1.*)
__rodata1_end = .;
} > ps7_ddr_0
.sdata2 : {
__sdata2_start = .;
*(.sdata2)
*(.sdata2.*)
*(.gnu.linkonce.s2.*)
__sdata2_end = .;
} > ps7_ddr_0
.sbss2 : {
__sbss2_start = .;
*(.sbss2)
*(.sbss2.*)
*(.gnu.linkonce.sb2.*)
__sbss2_end = .;
} > ps7_ddr_0
.data : {
__data_start = .;
*(.data)
*(.data.*)
*(.gnu.linkonce.d.*)
*(.jcr)
*(.got)
*(.got.plt)
__data_end = .;
} > ps7_ddr_0
.data1 : {
__data1_start = .;
*(.data1)
*(.data1.*)
__data1_end = .;
} > ps7_ddr_0
.got : {
*(.got)
} > ps7_ddr_0
.ctors : {
__CTOR_LIST__ = .;
___CTORS_LIST___ = .;
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE(*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
__CTOR_END__ = .;
___CTORS_END___ = .;
} > ps7_ddr_0
.dtors : {
__DTOR_LIST__ = .;
___DTORS_LIST___ = .;
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE(*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
__DTOR_END__ = .;
___DTORS_END___ = .;
} > ps7_ddr_0
.fixup : {
__fixup_start = .;
*(.fixup)
__fixup_end = .;
} > ps7_ddr_0
.eh_frame : {
*(.eh_frame)
} > ps7_ddr_0
.eh_framehdr : {
__eh_framehdr_start = .;
*(.eh_framehdr)
__eh_framehdr_end = .;
} > ps7_ddr_0
.gcc_except_table : {
*(.gcc_except_table)
} > ps7_ddr_0
.mmu_tbl (ALIGN(16384)) : {
__mmu_tbl_start = .;
*(.mmu_tbl)
__mmu_tbl_end = .;
} > ps7_ddr_0
.ARM.exidx : {
__exidx_start = .;
*(.ARM.exidx*)
*(.gnu.linkonce.armexidix.*.*)
__exidx_end = .;
} > ps7_ddr_0
.preinit_array : {
__preinit_array_start = .;
KEEP (*(SORT(.preinit_array.*)))
KEEP (*(.preinit_array))
__preinit_array_end = .;
} > ps7_ddr_0
.init_array : {
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
} > ps7_ddr_0
.fini_array : {
__fini_array_start = .;
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array))
__fini_array_end = .;
} > ps7_ddr_0
.ARM.attributes : {
__ARM.attributes_start = .;
*(.ARM.attributes)
__ARM.attributes_end = .;
} > ps7_ddr_0
.sdata : {
__sdata_start = .;
*(.sdata)
*(.sdata.*)
*(.gnu.linkonce.s.*)
__sdata_end = .;
} > ps7_ddr_0
.sbss (NOLOAD) : {
__sbss_start = .;
*(.sbss)
*(.sbss.*)
*(.gnu.linkonce.sb.*)
__sbss_end = .;
} > ps7_ddr_0
.tdata : {
__tdata_start = .;
*(.tdata)
*(.tdata.*)
*(.gnu.linkonce.td.*)
__tdata_end = .;
} > ps7_ddr_0
.tbss : {
__tbss_start = .;
*(.tbss)
*(.tbss.*)
*(.gnu.linkonce.tb.*)
__tbss_end = .;
} > ps7_ddr_0
.bss (NOLOAD) : {
__bss_start = .;
*(.bss)
*(.bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
__bss_end = .;
} > ps7_ddr_0
_SDA_BASE_ = __sdata_start + ((__sbss_end - __sdata_start) / 2 );
_SDA2_BASE_ = __sdata2_start + ((__sbss2_end - __sdata2_start) / 2 );
/* Generate Stack and Heap definitions */
.heap (NOLOAD) : {
. = ALIGN(16);
_heap = .;
HeapBase = .;
_heap_start = .;
. += _HEAP_SIZE;
_heap_end = .;
HeapLimit = .;
} > ps7_ddr_0
.stack (NOLOAD) : {
. = ALIGN(16);
_stack_end = .;
. += _STACK_SIZE;
. = ALIGN(16);
_stack = .;
__stack = _stack;
. = ALIGN(16);
_irq_stack_end = .;
. += _IRQ_STACK_SIZE;
. = ALIGN(16);
__irq_stack = .;
_supervisor_stack_end = .;
. += _SUPERVISOR_STACK_SIZE;
. = ALIGN(16);
__supervisor_stack = .;
_abort_stack_end = .;
. += _ABORT_STACK_SIZE;
. = ALIGN(16);
__abort_stack = .;
_fiq_stack_end = .;
. += _FIQ_STACK_SIZE;
. = ALIGN(16);
__fiq_stack = .;
_undef_stack_end = .;
. += _UNDEF_STACK_SIZE;
. = ALIGN(16);
__undef_stack = .;
} > ps7_ddr_0
_end = .;
}
@@ -0,0 +1,298 @@
/*
* Copyright (C) 2016 - 2018 Xilinx, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
*/
#include <stdio.h>
#include "xparameters.h"
#include "netif/xadapter.h"
#include "platform_config.h"
#include "xil_printf.h"
#include "xilinx_io.h"
#include "FreeRTOS.h"
#include "queue.h"
#include "semphr.h"
#include "math.h"
#if LWIP_IPV6==1
#include "lwip/ip.h"
#else
#if LWIP_DHCP==1
#include "lwip/dhcp.h"
#endif
#endif
#ifdef XPS_BOARD_ZCU102
#ifdef XPAR_XIICPS_0_DEVICE_ID
int IicPhyReset(void);
#endif
#endif
int main_thread();
void print_echo_app_header();
void echo_application_thread(void *);
void lwip_init();
#if LWIP_IPV6==0
#if LWIP_DHCP==1
extern volatile int dhcp_timoutcntr;
err_t dhcp_start(struct netif *netif);
#endif
#endif
#define THREAD_STACKSIZE 1024
static struct netif server_netif;
struct netif *echo_netif;
#if LWIP_IPV6==1
void print_ip6(char *msg, ip_addr_t *ip)
{
print(msg);
xil_printf(" %x:%x:%x:%x:%x:%x:%x:%x\n\r",
IP6_ADDR_BLOCK1(&ip->u_addr.ip6),
IP6_ADDR_BLOCK2(&ip->u_addr.ip6),
IP6_ADDR_BLOCK3(&ip->u_addr.ip6),
IP6_ADDR_BLOCK4(&ip->u_addr.ip6),
IP6_ADDR_BLOCK5(&ip->u_addr.ip6),
IP6_ADDR_BLOCK6(&ip->u_addr.ip6),
IP6_ADDR_BLOCK7(&ip->u_addr.ip6),
IP6_ADDR_BLOCK8(&ip->u_addr.ip6));
}
#else
void
print_ip(char *msg, ip_addr_t *ip)
{
xil_printf(msg);
xil_printf("%d.%d.%d.%d\n\r", ip4_addr1(ip), ip4_addr2(ip),
ip4_addr3(ip), ip4_addr4(ip));
}
void
print_ip_settings(ip_addr_t *ip, ip_addr_t *mask, ip_addr_t *gw)
{
print_ip("Board IP: ", ip);
print_ip("Netmask : ", mask);
print_ip("Gateway : ", gw);
}
#endif
int main()
{
xil_printf("start \r\n");
sys_thread_new("main_thrd", (void(*)(void*))main_thread, 0,
THREAD_STACKSIZE,
DEFAULT_THREAD_PRIO);
vTaskStartScheduler();
while(1);
return 0;
}
void network_thread(void *p)
{
struct netif *netif;
/* the mac address of the board. this should be unique per board */
unsigned char mac_ethernet_address[] = { 0x00, 0x0a, 0x35, 0x00, 0x01, 0x02 };
#if LWIP_IPV6==0
ip_addr_t ipaddr, netmask, gw;
#if LWIP_DHCP==1
int mscnt = 0;
#endif
#endif
netif = &server_netif;
xil_printf("\r\n\r\n");
xil_printf("-----lwIP Socket Mode CX9261 TEST server Application Version 2022.05.31------\r\n");
#if LWIP_IPV6==0
#if LWIP_DHCP==0
/* initliaze IP addresses to be used */
IP4_ADDR(&ipaddr, 192, 168, 1, 99);
IP4_ADDR(&netmask, 255, 255, 255, 0);
IP4_ADDR(&gw, 192, 168, 1, 1);
#endif
/* print out IP settings of the board */
#if LWIP_DHCP==0
print_ip_settings(&ipaddr, &netmask, &gw);
/* print all application headers */
#endif
#if LWIP_DHCP==1
ipaddr.addr = 0;
gw.addr = 0;
netmask.addr = 0;
#endif
#endif
#if LWIP_IPV6==0
/* Add network interface to the netif_list, and set it as default */
if (!xemac_add(netif, &ipaddr, &netmask, &gw, mac_ethernet_address, PLATFORM_EMAC_BASEADDR)) {
xil_printf("Error adding N/W interface\r\n");
return;
}
#else
/* Add network interface to the netif_list, and set it as default */
if (!xemac_add(netif, NULL, NULL, NULL, mac_ethernet_address, PLATFORM_EMAC_BASEADDR)) {
xil_printf("Error adding N/W interface\r\n");
return;
}
netif->ip6_autoconfig_enabled = 1;
netif_create_ip6_linklocal_address(netif, 1);
netif_ip6_addr_set_state(netif, 0, IP6_ADDR_VALID);
print_ip6("\n\rBoard IPv6 address ", &netif->ip6_addr[0].u_addr.ip6);
#endif
netif_set_default(netif);
/* specify that the network if is up */
netif_set_up(netif);
/* start packet receive thread - required for lwIP operation */
sys_thread_new("xemacif_input_thread", (void(*)(void*))xemacif_input_thread, netif,
THREAD_STACKSIZE,
DEFAULT_THREAD_PRIO);
#if LWIP_IPV6==0
#if LWIP_DHCP==1
dhcp_start(netif);
while (1) {
vTaskDelay(DHCP_FINE_TIMER_MSECS / portTICK_RATE_MS);
dhcp_fine_tmr();
mscnt += DHCP_FINE_TIMER_MSECS;
if (mscnt >= DHCP_COARSE_TIMER_SECS*1000) {
dhcp_coarse_tmr();
mscnt = 0;
}
}
#else
xil_printf("\r\n");
xil_printf("%20s %6s %s\r\n", "Server", "Port", "Connect With..");
xil_printf("%20s %6s %s\r\n", "--------------------", "------", "--------------------");
print_echo_app_header();
xil_printf("\r\n");
sys_thread_new("echod", echo_application_thread, 0,
THREAD_STACKSIZE,
DEFAULT_THREAD_PRIO);
vTaskDelete(NULL);
#endif
#else
print_echo_app_header();
xil_printf("\r\n");
sys_thread_new("echod",echo_application_thread, 0,
THREAD_STACKSIZE,
DEFAULT_THREAD_PRIO);
vTaskDelete(NULL);
#endif
return;
}
int main_thread()
{
#if LWIP_DHCP==1
int mscnt = 0;
#endif
#ifdef XPS_BOARD_ZCU102
IicPhyReset();
#endif
/* initialize lwIP before calling sys_thread_new */
lwip_init();
SpiPsInit(SPI_DEVICE_ID);
GpioInit(GPIO_DEVICE_ID);
AXIGpioInit();
XScuGicInit();
ConfigAXIGPIOIntr();
ExceptionInit();
XAxiDma_Init(xAxiDma0Get(),AXI_DMA_DEVCIE_ID0);
XAxiDma_Init(xAxiDma1Get(),AXI_DMA_DEVCIE_ID1);
XAxiDma_Init(xAxiDma2Get(),AXI_DMA_DEVCIE_ID2);
PackerRst();
/* cx9261a configuration */
peripheral_test();
download_bin();
// frqhop_config(1);
/* any thread using lwIP should be created using sys_thread_new */
sys_thread_new("NW_THRD", network_thread, NULL,
THREAD_STACKSIZE,
DEFAULT_THREAD_PRIO);
#if LWIP_IPV6==0
#if LWIP_DHCP==1
while (1) {
vTaskDelay(DHCP_FINE_TIMER_MSECS / portTICK_RATE_MS);
if (server_netif.ip_addr.addr) {
xil_printf("DHCP request success\r\n");
print_ip_settings(&(server_netif.ip_addr), &(server_netif.netmask), &(server_netif.gw));
print_echo_app_header();
xil_printf("\r\n");
sys_thread_new("echod", echo_application_thread, 0,
THREAD_STACKSIZE,
DEFAULT_THREAD_PRIO);
break;
}
mscnt += DHCP_FINE_TIMER_MSECS;
if (mscnt >= 10000) {
xil_printf("ERROR: DHCP request timed out\r\n");
xil_printf("Configuring default IP of 192.168.1.100\r\n");
IP4_ADDR(&(server_netif.ip_addr), 192, 168, 1, 100);
IP4_ADDR(&(server_netif.netmask), 255, 255, 255, 0);
IP4_ADDR(&(server_netif.gw), 192, 168, 1, 1);
print_ip_settings(&(server_netif.ip_addr), &(server_netif.netmask), &(server_netif.gw));
/* print all application headers */
xil_printf("\r\n");
xil_printf("%20s %6s %s\r\n", "Server", "Port", "Connect With..");
xil_printf("%20s %6s %s\r\n", "--------------------", "------", "--------------------");
print_echo_app_header();
xil_printf("\r\n");
sys_thread_new("echod", echo_application_thread, 0,
THREAD_STACKSIZE,
DEFAULT_THREAD_PRIO);
break;
}
}
#endif
#endif
vTaskDelete(NULL);
return 0;
}
@@ -0,0 +1,10 @@
#ifndef __PLATFORM_CONFIG_H_
#define __PLATFORM_CONFIG_H_
#define PLATFORM_EMAC_BASEADDR XPAR_XEMACPS_0_BASEADDR
#define PLATFORM_ZYNQ
#endif
@@ -0,0 +1,178 @@
#include "sd.h"
/************************** Variable Definitions *****************************/
static FIL fil; /* File object */
static FATFS fatfs;
/*
* To test logical drive 0, FileName should be "0:/<File name>" or
* "<file_name>". For logical drive 1, FileName should be "1:/<file_name>"
*/
static char FileName[32] = "BOOT.bin";
static char *SD_File;
//#define BUFF_SIZE sizeof(image_data)
#define BUFF_SIZE 0x2000000
#ifdef __ICCARM__
#pragma data_alignment = 32
u8 DestinationAddress[10*1024];
#pragma data_alignment = 32
u8 SourceAddress[10*1024];
#else
//u8 DestinationAddress[10*1024] __attribute__ ((aligned(32)));
//u8 SourceAddress[10*1024] __attribute__ ((aligned(32)));
u8 DestinationAddress[BUFF_SIZE] __attribute__ ((aligned(32)));
u8 SourceAddress[BUFF_SIZE] __attribute__ ((aligned(32)));
#endif
#define TEST 7
/*****************************************************************************/
/**
*
* File system example using SD driver to write to and read from an SD card
* in polled mode. This example creates a new file on an
* SD card (which is previously formatted with FATFS), write data to the file
* and reads the same data back to verify.
*
* @param None
*
* @return XST_SUCCESS if successful, otherwise XST_FAILURE.
*
* @note None
*
******************************************************************************/
int FfsSdWrite(u8*image_data, u32 FileSize)
{
int error_flag = 0;
FRESULT Res;
UINT NumBytesRead;
UINT NumBytesWritten;
u32 BuffCnt;
BYTE work[FF_MAX_SS];
// u32 FileSize = (8*1024);
// u32 FileSize = sizeof(image_data);
/*
* To test logical drive 0, Path should be "0:/"
* For logical drive 1, Path should be "1:/"
*/
TCHAR *Path = "0:/";
u8 checksum = 0;
for(BuffCnt = 0; BuffCnt < FileSize; BuffCnt++){
// SourceAddress[BuffCnt] = TEST + BuffCnt;
SourceAddress[BuffCnt] = image_data[BuffCnt];
checksum = checksum + image_data[BuffCnt];
}
xil_printf("checksum is 0x%x.",checksum);
/*
* Register volume work area, initialize device
*/
Res = f_mount(&fatfs, Path, 0);
if (Res != FR_OK) {
return XST_FAILURE;
}
/*
* Path - Path to logical driver, 0 - FDISK format.
* 0 - Cluster size is automatically determined based on Vol size.
*/
Res = f_mkfs(Path, FM_FAT32, 0, work, sizeof work);
if (Res != FR_OK) {
return XST_FAILURE;
}
/*
* Open file with required permissions.
* Here - Creating new file with read/write permissions. .
* To open file with write permissions, file system should not
* be in Read Only mode.
*/
SD_File = (char *)FileName;
Res = f_open(&fil, SD_File, FA_CREATE_ALWAYS | FA_WRITE | FA_READ);
if (Res) {
return XST_FAILURE;
}
/*
* Pointer to beginning of file .
*/
Res = f_lseek(&fil, 0);
if (Res) {
return XST_FAILURE;
}
/*
* Write data to file.
*/
Res = f_write(&fil, (const void*)SourceAddress, FileSize,
&NumBytesWritten);
if (Res) {
return XST_FAILURE;
}
/*
* Close file.
*/
Res = f_close(&fil);
if (Res) {
return XST_FAILURE;
}
Res = f_open(&fil, SD_File, FA_READ);
if (Res) {
return XST_FAILURE;
}
/*
* Pointer to beginning of file .
*/
Res = f_lseek(&fil, 0);
if (Res) {
return XST_FAILURE;
}
/*
* Read data from file.
*/
Res = f_read(&fil, (void*)DestinationAddress, FileSize,
&NumBytesRead);
if (Res) {
return XST_FAILURE;
}
/*
* Data verification
*/
for(BuffCnt = 0; BuffCnt < FileSize; BuffCnt++){
if(SourceAddress[BuffCnt] != DestinationAddress[BuffCnt]){
// return XST_FAILURE;
error_flag = 1;
xil_printf('Data check error.');
}
}
/*
* Close file.
*/
Res = f_close(&fil);
if (Res) {
return XST_FAILURE;
}
if(error_flag){
return XST_FAILURE;
}
// Res = f_unmount(Path);
// if (Res) {
// return XST_FAILURE;
// }
//
// sleep(5);
return XST_SUCCESS;
}
@@ -0,0 +1,9 @@
/***************************** Include Files *********************************/
#include "xparameters.h" /* SDK generated parameters */
#include "xsdps.h" /* SD device driver */
#include "xil_printf.h"
#include "ff.h"
#include "xil_cache.h"
#include "xplatform_info.h"
/************************** Function Prototypes ******************************/
int FfsSdWrite(u8*image_data, u32 FileSize);
@@ -0,0 +1,139 @@
/*
* xilinx_io.h
*
* Created on: 2021年9月6日
* Author: cxlab
*/
#ifndef SRC_XILINX_IO_H_
#define SRC_XILINX_IO_H_
#endif /* SRC_XILINX_IO_H_ */
#include "xspips.h" /* SPI device driver */
#include "xgpiops.h"
#include "xgpio.h"
#include "xaxidma.h"
#include "xparameters.h"
#include "xscugic.h"
#include "xil_exception.h"
//#define DBGLOG
#define MAX_DATA 100
#define SPI_WRITE 0x80
#define SPI_READ 0x00
#define GPIO_DIR_INPUT 0x00
#define GPIO_DIR_OUTPUT 0x01
#define GPIO_EMIO_OFFSET 54
#define TX_EN 0x08
#define RX_EN 0x07
#define GPIO_1 0x06
#define GPIO_0 0x05
#define NRST 0
#define ENABLE_TRX1 1
#define ENABLE_TRX2 2
#define ENABLE_TRX3 3
#define TXNRX_TRX1 4
#define TXNRX_TRX2 5
#define TXNRX_RX3 6
#define aresetn_0 33
#define rst 34
#define tr_sel 35
#define tdd_fdd_sel 36
#define r1t1_r2t2_sel 37
#define sp_dp_sel 38
#define aresetn_1 39
#define aresetn_2 40
#define hop 41
#define cx3e04_rstn 42
#define spi_select 46
#define debug_mode 63
#define SPI_DEVICE_ID XPAR_XSPIPS_0_DEVICE_ID
#define GPIO_DEVICE_ID XPAR_PS7_GPIO_0_DEVICE_ID
#define AXI_DMA_DEVCIE_ID0 XPAR_AXI_DMA_0_DEVICE_ID
#define AXI_DMA_DEVCIE_ID1 XPAR_AXI_DMA_1_DEVICE_ID
#define AXI_DMA_DEVCIE_ID2 XPAR_AXI_DMA_2_DEVICE_ID
#define BROM_BASEADDR XPAR_M08_AXI_0_BASEADDR
#define AXI4_LITE0_SPI_BASEADDR XPAR_AXI4_LITE_SPI_0_BASEADDR
#define AXI4_LITE1_SPI_BASEADDR XPAR_AXI4_LITE_SPI_1_BASEADDR
#define BRAM_BASEADDR XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR
#define BRAM_BASEADDR_1 XPAR_AXI_BRAM_CTRL_1_S_AXI_BASEADDR
#define PACKER_BASEADDR0 XPAR_AXIS_ADC_DATA_PACKER_0_S00_AXI_BASEADDR
#define PACKER_BASEADDR1 XPAR_AXIS_ADC_DATA_PACKER_1_S00_AXI_BASEADDR
#define PACKER_BASEADDR2 XPAR_AXIS_ADC_DATA_PACKER_2_S00_AXI_BASEADDR
#define WAVELENGTH 8192
#define TX_BUFFER_BASE XPAR_MIG_7SERIES_0_BASEADDR +0x2000
#define WAVE_LENGTH 8192*4
#define GPIO_INT_ID XPAR_FABRIC_GPIO_0_VEC_ID //PL 端 AXI GPIO 中断 ID
#define AXI_GPIO_ID XPAR_AXI_GPIO_0_DEVICE_ID //PL 端 AXI GPIO 器件 ID
#define SCUGIC_ID XPAR_SCUGIC_0_DEVICE_ID //中断控制器 ID
#define FRQHOP_MASK XGPIO_IR_CH1_MASK //通道 1 的位定义
void AXIGpioInit(void);
void ConfigAXIGPIOIntr(void);
void axi_gpio_handler(void *CallbackRef);
void XScuGicInit(void);
void ExceptionInit(void);
void frqhop_flag(int frqhop_flag);
int SpiPsInit(u16 SpiDeviceId);
int GpioInit(u16 DeviceId);
int GpioSetPinDir(u32 Pin,u32 Direction);
int GpioWritePin(u32 Pin,u32 data);
int GpioReadPin(u32 Pin);
int peripheral_test(void);
int cx3e04_write(int addr , int value);
int cx3e04_read(int addr);
int cx9261a_write(int addr , int value);
int cx9261a_read(int addr);
int SpiPs_write_read(u8 * data,u8 * rx_data);
int SpiPs_write_read1(u16 addr,u8 data,u8 * rx_data);
int SpiPs_write_read2(u16 addr,u8 data,u8 * rx_data);
#define SPI_STACK_LENGTH 65536
struct spi_stack {
int spi_write_num;
u8 recv_buf[SPI_STACK_LENGTH*3];
};
int spi_stack_in(u8 * data,struct spi_stack * spistack);
void spi_stack_out(struct spi_stack * spistack);
void cx3e04_config(void);
void cx9261a_config(void);
void DeviceRst(void);
extern XAxiDma* xAxiDma0Get(void);
extern XAxiDma* xAxiDma1Get(void);
extern XAxiDma* xAxiDma2Get(void);
int XAxiDma_Init(XAxiDma* AxiDma,u16 DeviceId);
int XAxiDmaCapture(XAxiDma* AxiDma,u32 data_length);
int XAxiDmaCapture2(XAxiDma* AxiDma,u32 data_length);
int DownloadWave(u8 * data);
int SetPacketSize(XAxiDma* AxiDma,u32 length);
void dbg_printf( const char8 *ctrl1, ...);
void PackerRst(void);
int rom_read(u8 * data);
void download_bin(void);
//跳频
void frqhop_config(int hop_flag);
int PLL_config(u8 pll_index,double pll_frq);
void trx_ch_pll_config(u8 pll_index);
int pll_frq_caculation_new(double ref,double pll_frq,u8 *reg_data);
void PLL_afc(u16 afc_addr,u16 div_addr,u8 pll_div);
char divBin(u16 div);
@@ -0,0 +1,546 @@
/**
* @file cx9261adriver.h
*/
#ifndef CX9261ADRIVER_CX9261ADRIVER_H
#define CX9261ADRIVER_CX9261ADRIVER_H
#define VERSION 1.10.0
#include "defs.h"
// 如果不需要输出日志内容,注释掉下面的宏定义
#define USE_LOGGING
#ifdef USE_LOGGING
# define LOGGING(x) logging(x);
#else
# define LOGGING(x)
#endif
namespace CX9261A {
#ifdef USE_LOGGING
/**
* @brief 输出日志的函数
* @param msg 要输出的内容
*/
void logging(const std::string& msg);
#endif
/**
* @brief 需要实现的函数,实现SPI写入寄存器功能
* @param address 要写入的寄存器地址
* @param value 要写入的寄存器值
*/
void writeSpi(int address, int value);
/**
* @brief 需要实现的函数,实现SPI读取寄存器功能
* @param address 要读取的寄存器地址
* @return 返回的寄存器值
*/
int readSpi(int address);
/**
* @brief 需要实现的函数,实现等待功能
* @param ms 等待时间,单位毫秒
*/
void pause(double ms);
/**
* @brief 需要实现的函数,实现配置FPGA对应寄存器功能
* @param pin 寄存器地址
* @param value 寄存器值
*/
void setPin(int pin, int value);
/**
* @brief 初始化芯片状态,写入与具体配置无关的寄存器值
*/
void initialChip();
/**
* @brief 初始化电源配置,如果只自定义配置部分模式下的电源管理,在自定义配置之前需要先调用此函数
*/
void initialPowerConfig(const CX9261AConfiguration& config);
/**
* @brief 初始化BBPLL相关寄存器,如果调用了initialChip,则无需单独调用此函数
*/
void initialBBPLL();
/**
* @brief 初始化PLL1相关寄存器,如果调用了initialChip,则无需单独调用此函数
*/
void initialPLL1();
/**
* @brief 初始化PLL2相关寄存器,如果调用了initialChip,则无需单独调用此函数
*/
void initialPLL2();
/**
* @brief 初始化PLL3相关寄存器,如果调用了initialChip,则无需单独调用此函数
*/
void initialPLL3();
/**
* @brief 初始化PLL4相关寄存器,如果调用了initialChip,则无需单独调用此函数
*/
void initialPLL4();
/**
* @brief 初始化PLL5相关寄存器,如果调用了initialChip,则无需单独调用此函数
*/
void initialPLL5();
/**
* @brief 配置受参考时钟频率影响的寄存器
* @param ref 参考时钟频率,单位MHz
*/
void configRef(double ref);
/**
* @brief 配置时钟相关寄存器,包括ADC和BBPLL
* @param config CX9261A参数结构体
*/
void configBBPLL(const CX9261AConfiguration& config);
/**
* @brief BBPLL AFC
* @return 是否锁定
*/
bool afcBBPll();
/**
* @brief 配置PLL1频率
* @param lo 目标频率
* @param clock 时钟结构体,使用其中的ref和refDoubler属性
*/
void configPll1(double lo, const Clock& clock);
/**
* @brief Pll1 AFC
* @return 是否锁定
*/
bool afcPll1();
/**
* @brief 配置PLL2频率
* @param lo 目标频率
* @param clock 时钟结构体,使用其中的ref和refDoubler属性
*/
void configPll2(double lo, const Clock& clock);
/**
* @brief Pll2 AFC
* @return 是否锁定
*/
bool afcPll2();
/**
* @brief 配置PLL3频率
* @param lo 目标频率
* @param clock 时钟结构体,使用其中的ref和refDoubler属性
*/
void configPll3(double lo, const Clock& clock);
/**
* @brief Pll3 AFC
* @return 是否锁定
*/
bool afcPll3();
/**
* @brief 配置PLL4频率
* @param lo 目标频率
* @param clock 时钟结构体,使用其中的ref和refDoubler属性
*/
void configPll4(double lo, const Clock& clock);
/**
* @brief Pll4 AFC
* @return 是否锁定
*/
bool afcPll4();
/**
* @brief 配置PLL5频率
* @param lo 目标频率
* @param clock 时钟结构体,使用其中的ref和refDoubler属性
*/
void configPll5(double lo, const Clock& clock);
/**
* @brief Pll5 AFC
* @return 是否锁定
*/
bool afcPll5();
/**
* @brief 配置AGC模式
* @param mode 模式0~13
*/
void configAGCMode(int mode);
/**
* @brief 配置AGC PDT
* @param pdt AGCPDT结构体
*/
void configAGCPDT(const AGCPDT& pdt);
/**
* @brief 配置AGC LMT
* @param lmt AGCLMT结构体
*/
void configAGCLMT(const AGCLMT& lmt);
/**
* @brief 配置AGC DIG
* @param dig AGCDIG结构体
*/
void configAGCDIG(const AGCDIG& dig);
/**
* @brief 配置AGC
* @param agc AGC结构体
*/
void configAGC(const AGC& agc);
/**
* @brief 配置片内处理器,仅在使用需要处理器辅助的校准方法时需要开启处理器
* @param on 开启/关闭
*/
void configRISCV(bool on);
/**
* @brief 配置温补
* @param mode 温补模式 DAC/Band
*/
void configTemperatureCompensation(TemperatureComp mode);
/**
* @brief ADC校准
* @param adc ADC速率
*/
void configADCCalib(double adc);
/**
* @brief Flash校准
*/
void configFlashCalib();
/**
* @brief QEC校准会改变部分寄存器配置,在进行校准之前需要保存这部分寄存器,校准后恢复
* @return 包含寄存器地址和值的map
*/
std::map<int, int> beforeQecState();
/**
* @brief 恢复QEC校准过程中改变的寄存器
* @param state beforeQecState函数返回的map
*/
void restoreQecState(const std::map<int, int>& state);
/**
* @brief 根据pll来源配置校准模式下的电源管理
* @param pllSource PllSource结构体
*/
void preparePowerForRxCalib(const PllSource& pllSource);
/**
* @brief 调整校准时Pll的配置
* @param config CX9261A配置结构体
* @param chan 要进行校准的通道
*/
void preparePllForRxCalib(const CX9261AConfiguration& config, RxChannel chan);
/**
* @brief 等待RxTST窄带校准结束,可重写
* @return 校准是否结束
*/
bool waitRxTSTFinished();
/**
* @brief RX时域统计校准
* @param chan 校准的RX通道
*/
void rxTSTCalib(RxChannel chan);
/**
* @brief RX延时线校准
* @param fs ADC采样率
* @param chan 校准的RX通道
*/
void rxDelayCalib(double fs, RxChannel chan);
/**
* @brief DC Tracking
* @param config CX9261A配置结构体
*/
void configDcCalib(const Calib& config);
void configDcCalibMethod(DCCalibMethod method);
void configDcTrackingLength(int length);
void configDcHighPassFactor(int factor);
/**
* @brief Rx校准
* @param config CX9261A配置结构体
* @param chan 要进行校准的通道
*/
void rxCalib(const CX9261AConfiguration& config, RxChannel chan);
/**
* @brief 选择校准方法
* @param calib 校准结构体
*/
void configCalibMethod(const Calib& calib);
/**
* @brief 读取当前Rx chan通道的校准值
* @param chan Rx通道
* @return 校准值结构体
*/
CalibPredis readRxCalibPredis(RxChannel chan);
/**
* @brief 储存校准值
* @param index 第index组校准值
* @param chan 接收通道
* @param pll 使用的PLL
*/
void saveRxCalibPredis(unsigned char index, RxChannel chan, LoSource pll);
/**
* @brief 加载保存的校准值
* @param index 第index组校准值
* @param chan 指定加载校准值的通道
* @param pll 使用的PLL
*/
void loadRxCalibPredis(unsigned char index, RxChannel chan, LoSource pll);
/**
* @brief Rx窄带多点校准
* @param config CX9261A配置结构体
* @param points 校准点
* @param chan 接收通道
*/
void configRxMultiPointsQec(const CX9261AConfiguration& config, const std::vector<double>& points, RxChannel chan);
/**
* @brief 根据pll来源配置校准模式下的电源管理
* @param pllSource PllSource结构体
*/
void preparePowerForTxCalib(const PllSource& pllSource);
/**
* @brief 调整校准时Pll的配置
* @param config CX9261A配置结构体
*/
void preparePllForTxCalib(const CX9261AConfiguration& config);
/**
* @brief TX二分法QEC校准
* @param f0 校准音频率
* @param fs adc频率
*/
void txBisectionQecCalib(double f0, double fs);
/**
* @brief TX时域统计法校准
* @param config CX9261A配置结构体
* @param chan 要校准的通道
*/
void txTSTCalib(const CX9261AConfiguration& config, TxChannel chan);
/**
* @brief TX二分法DC校准
* @param f0 校准音频率
* @param fs adc频率
*/
void txBisectionDcCalib(double f0, double fs);
/**
* @brief Tx多点校准
* @param config CX9261A配置结构体
* @param points 校准点
*/
void configTxMultiPointsQec(const CX9261AConfiguration& config, const std::vector<double>& points);
/**
* @brief Tx通道校准
* @param config CX9261A配置结构体
*/
void txCalib(const CX9261AConfiguration& config);
/**
* @brief 储存校准值
* @param index 第index组校准值
* @param chan 发射通道
* @param pll pll
*/
void saveTxCalibPredis(unsigned char index, TxChannel chan, LoSource pll);
/**
* @brief 加载保存的校准值
* @param index 第index组校准值
* @param chan 指定加载校准值的通道
* @param pll 指定加载校准值对应的PLL
*/
void loadTxCalibPredis(unsigned char index, TxChannel chan, LoSource pll);
/**
* @brief Qec校准顶层函数,内部根据配置选择使用对应方法进行校准
* @param config CX9261A配置结构体
*/
void configQecCalib(const CX9261AConfiguration& config);
/**
* @brief 配置TX NCO相关寄存器
* @param nco TX NCO配置结构体
* @param fs adc速率
*/
void configTxNco(const TxNCO& nco, double fs);
/**
* @brief 配置TX NCO BIST模式
* @param bist 开启/关闭BIST
*/
void configTxBIST(bool bist);
/**
* @brief 配置TX NCO频率
* @param freq 混频频率
* @param fs adc抽取后速率
*/
void configTxNcoFreq(double freq, double fs);
/**
* @brief 配置RX NCO相关寄存器
* @param nco RX NCO配置结构体
* @param fs adc速率
*/
void configRxNco(const RxNCO& nco, double fs);
/**
* @brief 配置Rx NCO模式
* @param mode NCO模式:Bypass/BIST/Up/Down
*/
void configRxNcoMode(NCOMode mode);
/**
* @brief 配置Rx NCO模式
* @param mode NCO模式:Master/Slaver
*/
void configRxNcoMS(NCOMode mode);
/**
* @brief 配置Rx NCO频率
* @param freq 混频频率
* @param fs adc速率
*/
void configRxNcoFreq(double freq, double fs);
/**
* @brief 配置接口相关寄存器
* @param interface Interface配置结构体
*/
void configInterface(const Interface& interface);
/**
* @brief 配置PLL来源
* @param pllSource PLlSource结构体
*/
void configPllSource(const PllSource& pllSource);
/**
* @brief 切换电源模式
* @param pm 电源模式
*/
void configPowerMode(PowerMode pm);
/**
* @brief 配置电源管理
* @param power 电源配置结构体
* @param pm 电源模式
*/
void configPowerPins(const Power& power, PowerMode pm);
/**
* @brief 配置参考倍频器
* @param doubler 倍频器开关
* @param ref 参考时钟频率,单位MHz
*/
void configRefDoubler(bool doubler, double ref);
/**
* @brief 初始化通道,调用initialChip函数会初始化RX1,RX2,RX3三个通道
* @param chan 通道 RX1/RX2/RX3
*/
void initialRxChannel(RxChannel chan);
/**
* @brief 配置Rx带宽
* @note 只改变Rx带宽会导致通道增益改变,建议使用configRxChannel函数进行带宽调整
* @param bandwidth 带宽,单位(MHz)
* @param chan 通道 Rx1/Rx2/Rx3
*/
void configRxBandwidth(double bandwidth, RxChannel chan);
/**
* @brief 配置Rx TIA
* @note 只改变TIA会导致通道带宽改变,建议使用configRxChannel函数进行TIA调整
* @param tia tia档位
* @param chan 通道 Rx1/Rx2/Rx3
*/
void configRxTIA(int tia, RxChannel chan);
/**
* @brief 配置Rx Mixer
* @param mixer mixer档位
*/
void configRxMixer(int mixer);
/**
* @brief 配置Rx通道,包含TIA,Mixer以及Bandwidth
* @param config RxConfig结构体
* @param chan Rx1/Rx2/Rx3
*/
void configRxChannel(const RxConfig& config, RxChannel chan);
/**
* @brief 配置Rx FIR滤波器抽取倍数
* @param fir 抽取倍数 0(Bypass)/1/2/3/4/8
*/
void configRxFIR(int fir);
/**
* @brief 配置Rx HBF1滤波器抽取倍数
* @param hbf 抽取倍数 0(Bypass)/2
*/
void configRxHBF1(int hbf);
/**
* @brief 配置Rx HBF2滤波器抽取倍数
* @param hbf 抽取倍数 0(Bypass)/2
*/
void configRxHBF2(int hbf);
/**
* @brief 配置Rx HBF3滤波器抽取倍数
* @param hbf 抽取倍数 0(Bypass)/2/3
*/
void configRxHBF3(int hbf);
/**
* @brief 配置Rx CIC滤波器
* @param cic 抽取倍数 0(Bypass)/20
*/
void configRxCIC(int cic);
/**
* @brief 配置Rx滤波器
* @param filters Filters结构体
*/
void configRxFilters(const Filters& filters);
/**
* @brief 配置Rx FIR滤波器系数
* @param coe 滤波器系数,长度为16的整倍数,最大128
*/
void configRxFIRCoe(const std::vector<double>& coe);
/**
* @brief 配置Tx带宽
* @param bandwidth 带宽,单位(MHz)
* @param chan 通道 TX1/TX2
*/
void configTxBandwidth(double bandwidth, TxChannel chan);
/**
* @brief 配置Tx Mixer
* @param mixer 混频器值
* @param chan TX1/TX2
*/
void configTxMixer(int mixer, TxChannel chan);
/**
* @brief 初始化Tx通道
* @param chan 通道 TX1/TX2
*/
void initialTxChannel(TxChannel chan);
/**
* @brief 根据Tx通道的本振频率,配置对应的参数
* @param lo 本振频率,单位(MHz)
* @param chan 通道(Tx1/Tx2)
*/
void configTxChannelFrequency(double lo, TxChannel chan);
/**
* @brief 配置Tx通道,Mixer以及Bandwidth
* @param config TxConfig结构体
* @param chan Tx1/Tx2
*/
void configTxChannel(const TxConfig& config, TxChannel chan);
/**
* @brief 配置Tx FIR滤波器插值倍数
* @param fir 插值倍数 0(Bypass)/1/2/3/4/8
*/
void configTxFIR(int fir);
/**
* @brief 配置Tx HBF1滤波器插值倍数
* @param hbf 插值倍数 0(Bypass)/2
*/
void configTxHBF1(int hbf);
/**
* @brief 配置Tx HBF2滤波器插值倍数
* @param hbf 插值倍数 0(Bypass)/2
*/
void configTxHBF2(int hbf);
/**
* @brief 配置Tx HBF3滤波器插值倍数
* @param hbf 插值倍数 0(Bypass)/2/3
*/
void configTxHBF3(int hbf);
/**
* @brief 配置Tx CIC滤波器
* @param cic 插值倍数 0(Bypass)/8/20/32/80
*/
void configTxCIC(int cic);
/**
* @brief 配置Tx滤波器
* @param filters Filters结构体
*/
void configTxFilters(const Filters& filters);
/**
* @brief 配置Tx FIR滤波器系数
* @param coe 滤波器系数,长度为16的整倍数,最大128
*/
void configTxFIRCoe(const std::vector<double>& coe);
/**
* @brief 读取当前Tx chan通道的校准值
* @param chan Tx通道
* @return 校准值结构体
*/
CalibPredis readTxCalibPredis(TxChannel chan);
/**
* @brief 此函数为Demo板配套配置函数,用于配置FPGA接口,用户开发自己的程序时应重写对应功能
* @param interface Interface结构体
*/
void configFPGA(const Interface& interface);
} // namespace CX9261A
#endif // CX9261ADRIVER_CX9261ADRIVER_H
@@ -0,0 +1,424 @@
/**
* @file defs.h
*/
#ifndef CX9261ADRIVER_DEFS_H
#define CX9261ADRIVER_DEFS_H
#include <bitset>
#include <map>
#include <vector>
#ifdef interface
# undef interface
#endif
namespace CX9261A {
/**
* @brief 芯片工作模式
*/
enum class WorkMode : std::uint8_t { Rx, Tx, FDD };
/**
* @brief 收发数据通道数量
* @note 此模式并不代表使用几个通道进行收发
*/
enum class TrMode : std::uint8_t { R1T1, R2T2 };
/**
* @brief 收发接口通道数量
*/
enum class PortMode : std::uint8_t { Single, Dual };
/**
* @brief 接口模式:
* CMOS CMOS接口模式,
* LVDS_S LVDS顺序模式,
* LVDS_E LVDS奇偶模式
*/
enum class IOMode : std::uint8_t { CMOS, LVDS_S, LVDS_E };
/**
* @brief 本振来源
*/
enum class LoSource : std::uint8_t {
Pll1 = 0b00001,
Pll2 = 0b00010,
Pll3 = 0b00100,
Pll4 = 0b01000,
Pll5 = 0b10000,
Off = 0
};
inline std::string toString(const LoSource source)
{
switch (source) {
case LoSource::Pll1:
return "Pll1";
case LoSource::Pll2:
return "Pll2";
case LoSource::Pll3:
return "Pll3";
case LoSource::Pll4:
return "Pll4";
case LoSource::Pll5:
return "Pll5";
default:
return "Off";
}
}
/**
* @brief 接收通道
*/
enum class RxChannel : std::uint8_t { Rx1 = 1, Rx2, Rx3 };
inline std::string toString(const RxChannel chan)
{
switch (chan) {
case RxChannel::Rx1:
return "Rx1";
case RxChannel::Rx2:
return "Rx2";
case RxChannel::Rx3:
return "Rx3";
default:
return "Unknown Channel";
}
}
/**
* @brief 发射通道
*/
enum class TxChannel : std::uint8_t { Tx1 = 1, Tx2 };
inline std::string toString(const TxChannel chan)
{
switch (chan) {
case TxChannel::Tx1:
return "Tx1";
case TxChannel::Tx2:
return "Tx2";
default:
return "Unknown Channel";
}
}
/**
* @brief 电源模式
*/
enum class PowerMode : std::uint8_t { Shutdown = 0, Sleep, Alert, Calib, Receive, Transmit, Duplex, Obs };
/**
* @brief NCO模式
*/
enum class NCOMode : std::uint8_t { Bypass = 0, Up, Down, BIST, Master, Slaver };
/**
* @brief 温补模式 DAC: DAC模式 Band: 跳子带模式
*/
enum class TemperatureComp : std::uint8_t { DAC = 0, Band };
/**
* @brief 校准方法 TST: 时域统计 Rx通道使用, Bisec: 二分法 Tx通道使用, MultiPoints: 多点校准
*/
enum class CalibMethod : std::uint8_t { TST = 0, Bisec, MultiPoints, Tracking };
/**
* @brief DC校准方法 Tracking: 跟踪校准 HighPass: 高通滤波器滤掉直流
*/
enum class DCCalibMethod : std::uint8_t { Tracking = 0, HighPass };
/**
* @brief AFC等待延时,单位ms
*/
constexpr double delay = 100;
/**
* @brief QEC等待延时,单位ms
*/
constexpr double qecDelay = 500;
/**
* @brief 接收通道本振来源映射表
*/
static const std::map<std::pair<LoSource, LoSource>, std::bitset<7>> rxSrcMap = {
{ { LoSource::Pll2, LoSource::Pll2 }, 0b0010000 }, { { LoSource::Pll1, LoSource::Pll1 }, 0b1101000 },
{ { LoSource::Pll2, LoSource::Pll1 }, 0b0100000 }, { { LoSource::Pll1, LoSource::Pll2 }, 0b1000000 },
{ { LoSource::Off, LoSource::Pll1 }, 0b0101010 }, { { LoSource::Off, LoSource::Pll2 }, 0b1010010 },
{ { LoSource::Pll1, LoSource::Off }, 0b1001001 }, { { LoSource::Pll2, LoSource::Off }, 0b0110001 },
{ { LoSource::Off, LoSource::Off }, 0b0011011 }
};
/**
* @brief 发射通道本振来源映射表
*/
static const std::map<std::pair<LoSource, LoSource>, std::bitset<11>> txSrcMap = {
{ { LoSource::Pll4, LoSource::Pll4 }, 16 }, { { LoSource::Pll3, LoSource::Pll3 }, 104 },
{ { LoSource::Pll4, LoSource::Pll3 }, 32 }, { { LoSource::Pll3, LoSource::Pll4 }, 64 },
{ { LoSource::Pll2, LoSource::Pll2 }, 1560 }, { { LoSource::Pll1, LoSource::Pll1 }, 1944 },
{ { LoSource::Pll2, LoSource::Pll1 }, 1688 }, { { LoSource::Pll1, LoSource::Pll2 }, 1816 },
{ { LoSource::Off, LoSource::Pll3 }, 42 }, { { LoSource::Off, LoSource::Pll4 }, 82 },
{ { LoSource::Off, LoSource::Pll2 }, 794 }, { { LoSource::Off, LoSource::Pll1 }, 666 },
{ { LoSource::Pll3, LoSource::Off }, 73 }, { { LoSource::Pll4, LoSource::Off }, 49 },
{ { LoSource::Pll2, LoSource::Off }, 1177 }, { { LoSource::Pll1, LoSource::Off }, 1305 },
{ { LoSource::Off, LoSource::Off }, 27 }, { { LoSource::Pll1, LoSource::Pll3 }, 1320 },
{ { LoSource::Pll1, LoSource::Pll4 }, 1360 }, { { LoSource::Pll2, LoSource::Pll3 }, 1064 },
{ { LoSource::Pll2, LoSource::Pll4 }, 1104 }, { { LoSource::Pll3, LoSource::Pll1 }, 712 },
{ { LoSource::Pll4, LoSource::Pll1 }, 688 }, { { LoSource::Pll3, LoSource::Pll2 }, 584 },
{ { LoSource::Pll4, LoSource::Pll2 }, 560 }
};
/**
* @brief 环路参数选择表
*/
static const std::vector<std::vector<std::vector<int>>> coreTable = {
{ { 0x0C, 0x30, 0x08 }, { 0x0B, 0x30, 0x09 }, { 0x0C, 0x30, 0x05 }, { 0x0D, 0x30, 0x08 } },
{ { 0x0C, 0x30, 0x0C }, { 0x0B, 0x30, 0x0E }, { 0x0C, 0x30, 0x08 }, { 0x0D, 0x30, 0x0B } },
{ { 0x0C, 0x20, 0x10 }, { 0x0B, 0x20, 0x10 }, { 0x0C, 0x20, 0x0A }, { 0x0D, 0x20, 0x0D } },
{ { 0x0C, 0x20, 0x11 }, { 0x0B, 0x20, 0x13 }, { 0x0C, 0x20, 0x0C }, { 0x0D, 0x20, 0x0F } },
{ { 0x0D, 0x30, 0x14 }, { 0x0D, 0x22, 0x14 }, { 0x0D, 0x20, 0x0D }, { 0x0D, 0x15, 0x0C } },
{ { 0x0E, 0x30, 0x18 }, { 0x0E, 0x25, 0x16 }, { 0x0E, 0x25, 0x0F }, { 0x0E, 0x18, 0x0F } },
{ { 0x0F, 0x38, 0x1A }, { 0x0F, 0x32, 0x1C }, { 0x0F, 0x18, 0x12 }, { 0x0F, 0x18, 0x12 } }
};
/**
* @brief AGC PDT模式的结构体
*/
struct AGCPDT
{
int pdtN;
int pdtM;
};
/**
* @brief AGC LMT模式的结构体
*/
struct AGCLMT
{
int count; /**< LMT统计次数阈值*/
int threshold1; /**< LMT阈值第一档*/
int threshold2; /**< LMT阈值第二档*/
int threshold3; /**< LMT阈值第三档*/
int threshold4; /**< LMT阈值第四档*/
};
/**
* @brief AGC DIG模式的结构体
*/
struct AGCDIG
{
int count; /**< DIG统计次数阈值*/
int threshold1; /**< DIG阈值第一档*/
int threshold2; /**< DIG阈值第二档*/
int threshold3; /**< DIG阈值第三档*/
int threshold4; /**< DIG阈值第四档*/
};
/**
* @brief AGC模式的结构体
*/
struct AGC
{
int mode; /**< AGC模式选择*/
AGCPDT pdt; /**< AGC PDT模式的结构体*/
AGCLMT lmt; /**< AGC LMT模式的结构体*/
AGCDIG dig; /**< AGC DIG模式的结构体*/
};
/**
* @brief 时钟相关参数结构体
*/
struct Clock
{
double ref; /**< 参考时钟频率,单位MHz*/
double adc; /**< ADC频率,单位MHz*/
int refDiv; /**< 参考时钟分频比*/
bool bbUseIntDiv; /**< 是否使用整数分频模式*/
bool refDoubler; /**< 是否使用参考时钟倍频器*/
};
/**
* @brief 校准相关参数结构体
*/
struct Calib
{
bool calibDC; /**< 是否开启DC Tracking*/
DCCalibMethod dcCalibMethod;
int dcTrackingLength; /**< DC Tracking长度*/
int dcHighPassFactor; /**< DC高通滤波系数,越大代表滤波器阶数越高,滤波范围越窄*/
std::uint8_t rx1CalibPll; /**< rx1校准的pll选择,Pll1 | Pll2*/
std::uint8_t rx2CalibPll; /**< rx2校准的pll选择,Pll1 | Pll2*/
std::uint8_t rx3CalibPll; /**< rx3校准的pll选择,Pll5*/
std::uint8_t tx1CalibPll; /**< tx1校准的pll选择,Pll1 | Pll2 | Pll3 | Pll4*/
std::uint8_t tx2CalibPll; /**< tx2校准的pll选择,Pll1 | Pll2 | Pll3 | Pll4*/
CalibMethod rxMethod;
CalibMethod txMethod;
double f0; /**< 校准音频率*/
std::vector<double> rxMultiPoints; /**< Rx多点校准的频率*/
std::vector<double> txMultiPoints; /**< Tx多点校准的频率*/
};
/**
* @brief 配置PLL来源相关参数结构体
*/
struct PllSource
{
bool rxUseExt; /**< 接收通道是否使用外本振*/
bool txUseExt; /**< 发射通道是否使用外本振*/
LoSource rx1Source; /**< Rx1通道本振来源*/
LoSource rx2Source; /**< Rx2通道本振来源*/
LoSource rx3Source; /**< Rx3通道本振来源*/
LoSource tx1Source; /**< Tx1通道本振来源*/
LoSource tx2Source; /**< Tx2通道本振来源*/
};
/**
* @brief 配置PLL频率相关参数结构体
*/
struct PllFreq
{
double pll1Freq; /**< PLL1本振时钟,单位MHz*/
double pll2Freq; /**< PLL2本振时钟,单位MHz*/
double pll3Freq; /**< PLL3本振时钟,单位MHz*/
double pll4Freq; /**< PLL4本振时钟,单位MHz*/
double pll5Freq; /**< PLL5本振时钟,单位MHz*/
double rxExtFreq; /**< 接收通道使用外本振时,外本振频率,单位MHz*/
double txExtFreq; /**< 发射通道使用外本振时,外本振频率,单位MHz*/
};
/**
* @brief 配置接口相关参数结构体
*/
struct Interface
{
WorkMode workMode; /**< 芯片工作模式*/
TrMode trMode; /**< 收发数据通道模式*/
PortMode portMode; /**< 收发接口通道模式*/
IOMode ioMode; /**< 接口电平模式*/
};
/**
* @brief 配置TX NCO相关参数结构体
*/
struct TxNCO
{
bool txUseBist; /**< 是否开启BIST模式*/
double txNCOFreq; /**< NCO频率*/
};
/**
* @brief 配置RX NCO相关参数结构体
*/
struct RxNCO
{
bool rxUseBist; /**< 是否开启BIST模式*/
bool rxNCOBypass; /**< 是否Bypass NCO*/
bool rxNCOUpward; /**< 开启上/下混频模式*/
bool rxNCOMaster; /**< 使用Master/Slaver模式*/
double rxNCOFreq; /**< NCO频率*/
};
/**
* @brief 配置接收通道相关参数结构体
*/
struct RxConfig
{
double bandwidth; /**< 接收通道1dB带宽,单位MHz*/
int tia; /**< 接收通道TIA增益配置,推荐配置6*/
int mixer; /**< 接收通道Mixer增益配置*/
};
/**
* @brief 配置发射通道相关参数结构体
*/
struct TxConfig
{
double bandwidth; /**< 发射通道1dB带宽,单位MHz*/
int mixer; /**< 发射通道Mixer增益配置*/
};
/**
* @brief 配置滤波器相关参数结构体,0代表bypass
*/
struct Filters
{
int fir; /**< FIR滤波器抽取/插值倍数*/
int hbf1; /**< HBF1滤波器抽取/插值倍数*/
int hbf2; /**< HBF2滤波器抽取/插值倍数*/
int hbf3; /**< HBF3滤波器抽取/插值倍数*/
int cic; /**< CIC滤波器抽取/插值倍数*/
};
/**
* @brief 配置电源模式结构体,1代表该模块上电
*/
struct Power
{
bool dig_tx2;
bool dig_tx1;
bool dig_rx3;
bool dig_rx2;
bool dig_rx1;
bool fref1_rx;
bool auxadc2;
bool auxadc1;
bool auxdac;
bool temp_sensor;
bool bgr;
bool exlo;
bool tx2;
bool tx1;
bool rx3;
bool rx2;
bool rx1;
bool pll5_ldo;
bool pll5;
bool pll4_ldo;
bool pll4;
bool pll3_ldo;
bool pll3;
bool pll2_ldo;
bool pll2;
bool pll1_ldo;
bool pll1;
bool bbpll;
};
/**
* @brief 配置电源模式管理,包含模式选择,接收模式,发射模式,FDD模式
*/
struct PowerManagement
{
PowerMode powerMode;
Power rxPower;
Power txPower;
Power fddPower;
};
/**
* @brief 储存窄带校准结果的结构体
*/
struct CalibPredis
{
int bHigh;
int bLow;
int cHigh;
int cLow;
int dciHigh;
int dciLow;
int dcqHigh;
int dcqLow;
};
/**
* @brief CX9261A结构体
*/
struct CX9261AConfiguration
{
TemperatureComp tempComp; /**< 温度补偿*/
AGC agc; /**< AGC结构体*/
Interface interface; /**< Interface结构体*/
Clock clock; /**< Clock结构体*/
PllSource pllSource; /**< PllSource结构体*/
Calib calib; /**< Calib结构体*/
PllFreq pllFreq; /**< PllFreq结构体*/
TxNCO txNco; /**< TxNCO结构体*/
RxNCO rxNco; /**< RxNCO结构体*/
RxConfig rx1Config; /**< RxConfig结构体*/
RxConfig rx2Config; /**< RxConfig结构体*/
RxConfig rx3Config; /**< RxConfig结构体*/
TxConfig tx1Config; /**< TxConfig结构体*/
TxConfig tx2Config; /**< TxConfig结构体*/
Filters rxFilters; /**< Filters结构体*/
Filters txFilters; /**< Filters结构体*/
PowerManagement powerManagement; /**< PowerManagement结构体*/
std::vector<double> rxFIRCoe; /**< Rx FIR滤波器系数*/
std::vector<double> txFIRCoe; /**< Tx FIR滤波器系数*/
};
} // namespace CX9261A
#endif // CX9261ADRIVER_DEFS_H
@@ -0,0 +1,138 @@
#include "cx9261adriver.h"
#include "defs.h"
int main() {
// 芯片配置结构体
CX9261A::CX9261AConfiguration configuration;
// 电源管理
// 接收模式电源管理
configuration.powerManagement.rxPower = {0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0,
0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1};
// 发射模式电源管理
configuration.powerManagement.txPower = {1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1};
// FDD模式电源管理
configuration.powerManagement.fddPower = {1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1,
0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1};
// 电源模式 即配置结束后的电源模式
configuration.powerManagement.powerMode = CX9261A::PowerMode::Receive;
// 接口模式
configuration.interface = {.workMode = CX9261A::WorkMode::Rx,
.trMode = CX9261A::TrMode::R1T1,
.portMode = CX9261A::PortMode::Single,
.ioMode = CX9261A::IOMode::CMOS};
// 时钟相关
configuration.clock = {.ref = 125, .adc = 64, .refDiv = 2, .bbUseIntDiv = false, .refDoubler = false};
// 本振相关
using LoSource = CX9261A::LoSource;
// 本振来源
configuration.pllSource = {.rxUseExt = false,
.txUseExt = false,
.rx1Source = LoSource::Pll1,
.rx2Source = LoSource::Pll1,
.rx3Source = LoSource::Off,
.tx1Source = LoSource::Off,
.tx2Source = LoSource::Off};
// 本振频率 注意:使用的所有PLL,频率必须设为正数
configuration.pllFreq = {
.pll1Freq = 5800, .pll2Freq = 5800, .pll3Freq = 800, .pll4Freq = 900, .pll5Freq = 1000};
// Rx通道 注意:tia推荐配置为6 Mixer为三个通道共用同一个寄存器
configuration.rx1Config = {.bandwidth = 32, .tia = 6, .mixer = 31};
configuration.rx2Config = {.bandwidth = 32, .tia = 6, .mixer = 31};
configuration.rx3Config = {.bandwidth = 32, .tia = 6, .mixer = 31};
// Tx通道
configuration.tx1Config = {.bandwidth = 20, .mixer = 63};
configuration.tx2Config = {.bandwidth = 20, .mixer = 63};
// 接收滤波器
configuration.rxFilters = {.fir = 0, .hbf1 = 0, .hbf2 = 0, .hbf3 = 0, .cic = 0};
// 发射滤波器
configuration.txFilters = {.fir = 0, .hbf1 = 2, .hbf2 = 2, .hbf3 = 0, .cic = 0};
// Rx NCO
configuration.rxNco = {
.rxUseBist = false, .rxNCOBypass = true, .rxNCOUpward = true, .rxNCOMaster = true, .rxNCOFreq = 0};
// Tx NCO
configuration.txNco = {.txUseBist = false, .txNCOFreq = 0};
// AGC 注意:mode = 0表示关闭AGC,此时其他的参数可以不配置
configuration.calib = {
.calibDC = true,
.dcCalibMethod = CX9261A::DCCalibMethod::Tracking,
.dcTrackingLength = 16384,
.dcHighPassFactor = 8191,
.rx1CalibPll = int(LoSource::Pll1) | int(LoSource::Pll2),
.rx2CalibPll = int(LoSource::Pll1) | int(LoSource::Pll2),
.rx3CalibPll = int(LoSource::Pll5),
.tx1CalibPll = 0,
.tx2CalibPll = 0,
.rxMethod = CX9261A::CalibMethod::MultiPoints,
.txMethod = CX9261A::CalibMethod::Bisec,
.f0 = 4
};
configuration.agc = {.mode = 0};
// 校准
configuration.calib.rxMultiPoints = {2200, 2400, 2600, 2800, 3000, 3200, 3400, 3600, 3800, 4000, 4200,
4400, 4600, 4800, 5000, 5200, 5400, 5600, 5800, 6000};
// 配置温补模式为跳子带温补
configuration.tempComp = CX9261A::TemperatureComp::Band;
// 开始配置芯片
CX9261A::initialChip(); // 最开始需要调用此函数
CX9261A::initialPowerConfig(configuration);
// 配置温补
configTemperatureCompensation(configuration.tempComp);
using PowerMode = CX9261A::PowerMode;
// 不需要自定义电源管理时,这部分代码可以省略
CX9261A::configPowerPins(configuration.powerManagement.rxPower, PowerMode::Receive);
CX9261A::configPowerPins(configuration.powerManagement.txPower, PowerMode::Transmit);
CX9261A::configPowerPins(configuration.powerManagement.fddPower, PowerMode::Duplex);
// 配置pll
CX9261A::configBBPLL(configuration);
CX9261A::configPllSource(configuration.pllSource);
CX9261A::configPll1(configuration.pllFreq.pll1Freq, configuration.clock);
CX9261A::configPll2(configuration.pllFreq.pll2Freq, configuration.clock);
// 配置Rx通道
CX9261A::configRxChannel(configuration.rx1Config, CX9261A::RxChannel::Rx1);
CX9261A::configRxChannel(configuration.rx2Config, CX9261A::RxChannel::Rx2);
CX9261A::configRxChannel(configuration.rx3Config, CX9261A::RxChannel::Rx3);
// 配置Tx通道
using TxChannel = CX9261A::TxChannel;
CX9261A::configTxChannelFrequency(configuration.pllFreq.pll1Freq, TxChannel::Tx1);
CX9261A::configTxChannelFrequency(configuration.pllFreq.pll2Freq, TxChannel::Tx2);
CX9261A::configTxChannel(configuration.tx1Config, TxChannel::Tx1);
CX9261A::configTxChannel(configuration.tx2Config, TxChannel::Tx2);
// 配置滤波器
CX9261A::configRxFilters(configuration.rxFilters);
CX9261A::configTxFilters(configuration.txFilters);
// 配置NCO
CX9261A::configRxNco(configuration.rxNco, configuration.clock.adc);
const int filters = std::max(configuration.rxFilters.fir, 1) * std::max(configuration.rxFilters.hbf3, 1) *
std::max(configuration.rxFilters.hbf2, 1) *
std::max(configuration.rxFilters.hbf1, 1) * std::max(configuration.rxFilters.cic, 1);
CX9261A::configTxNco(configuration.txNco, configuration.clock.adc / filters);
// 配置AGC
CX9261A::configAGC(configuration.agc);
// 切换到休眠模式
CX9261A::configPowerMode(PowerMode::Sleep);
CX9261A::pause(1000);
// 切换到校准模式
CX9261A::configPowerMode(PowerMode::Calib);
CX9261A::pause(100);
// 锁定BBPLL
CX9261A::afcBBPll();
// 配置校准
CX9261A::configADCCalib(configuration.clock.adc);
CX9261A::configFlashCalib();
configDcCalib(configuration.calib);
configQecCalib(configuration);
CX9261A::loadRxCalibPredis(0, CX9261A::RxChannel::Rx1, LoSource::Pll1);
CX9261A::loadRxCalibPredis(0, CX9261A::RxChannel::Rx2, LoSource::Pll1);
// 配置接口
CX9261A::configInterface(configuration.interface);
// 配置FPGA接口相关 此为示例,仅适用于Demo工程,用户应根据实际情况进行配置
CX9261A::configFPGA(configuration.interface);
// 锁定PLL1
CX9261A::afcPll1();
// 锁定PLL2
CX9261A::afcPll2();
return 0;
}
@@ -0,0 +1,99 @@
/**
* @file utils.h
*/
#ifndef CX9261ADRIVER_UTILS_H
#define CX9261ADRIVER_UTILS_H
#include <algorithm>
#include <bitset>
#include <cmath>
#include <string>
namespace CX9261A {
#if __cplusplus >= 201703L
template <typename T>
constexpr const T& clamp(const T& v, const T& lo, const T& hi) {
return std::clamp(v, lo, hi);
}
#else
template <typename T>
constexpr const T& clamp(const T& v, const T& lo, const T& hi) {
return std::max(std::min(hi, v), lo);
}
#endif
template <typename Float>
int round(Float f) {
return static_cast<int>(std::round(f));
}
template <typename Float>
long long round64(Float f) {
return static_cast<long long>(std::round(f));
}
template <typename Float>
int floor(Float f) {
return static_cast<int>(std::floor(f));
}
template <typename Float>
long long floor64(Float f) {
return static_cast<long long>(std::floor(f));
}
template <typename Float>
int ceil(Float f) {
return static_cast<int>(std::ceil(f));
}
template <typename Float>
long long ceil64(Float f) {
return static_cast<long long>(std::ceil(f));
}
/**
* @brief Register类,提供方便的位操作函数
*/
class Register {
public:
template <typename T = int>
constexpr Register(const T value = 0) {
static_assert(std::is_integral_v<T>, "Register value must be integral!");
m_value = static_cast<unsigned long long>(value);
}
/**
* 以十进制返回寄存器值
*/
unsigned char value() const { return static_cast<unsigned char>(m_value.to_ulong()); }
/**
* 对寄存器值进行部分值的替换操作
* 例:replace(7, 4, 0b1111); 使寄存器的高四位为1
* @param start 起始位
* @param end 中止位
* @param after 要替换的值
*/
void replace(const unsigned int start, const unsigned int end, unsigned char after) {
for (auto i = end; i <= start; ++i) {
m_value[i] = (after >> (i - end)) & 0b1;
}
}
auto operator[](const size_t position) { return m_value[position]; }
template <typename Type>
operator Type() const {
static_assert(std::is_integral_v<Type>, "Type must be an integral");
return static_cast<Type>(m_value.to_ulong());
}
private:
std::bitset<8> m_value{};
};
template <int N>
std::string frac2bin(const double frac) {
const long double num = frac * (pow(2.0, N));
std::string ret = std::bitset<N>(std::floor(num)).to_string();
return ret;
}
} // namespace CX9261A
#endif // CX9261ADRIVER_UTILS_H
@@ -0,0 +1,47 @@
/******************************************************************************
*
* Copyright (C) 2008 - 2014 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
#ifndef __MEMORY_CONFIG_H_
#define __MEMORY_CONFIG_H_
struct memory_range_s {
char *name;
char *ip;
unsigned long base;
unsigned long size;
};
/* generated memory ranges defined in memory_ranges_g.c */
extern struct memory_range_s memory_ranges[];
extern int n_memory_ranges;
#endif
@@ -0,0 +1,38 @@
/* This file is automatically generated based on your hardware design. */
#include "memory_config.h"
struct memory_range_s memory_ranges[] = {
{
"axi_bram_ctrl_0_Mem0",
"axi_bram_ctrl_0",
0x42000000,
32768,
},
{
"axi_bram_ctrl_1_Mem0",
"axi_bram_ctrl_1",
0x43000000,
32768,
},
{
"mig_7series_0_memaddr",
"mig_7series_0",
0x80000000,
1073741824,
},
{
"ps7_ddr_0",
"ps7_ddr_0",
0x00100000,
1072693248,
},
/* ps7_ram_0 memory will not be tested since application resides in the same memory */
{
"ps7_ram_1",
"ps7_ram_1",
0xFFFF0000,
65024,
},
};
int n_memory_ranges = 5;
@@ -0,0 +1,108 @@
/******************************************************************************
*
* Copyright (C) 2009 - 2014 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
#include <stdio.h>
#include "xparameters.h"
#include "xil_types.h"
#include "xstatus.h"
#include "xil_testmem.h"
#include "platform.h"
#include "memory_config.h"
#include "xil_printf.h"
/*
* memory_test.c: Test memory ranges present in the Hardware Design.
*
* This application runs with D-Caches disabled. As a result cacheline requests
* will not be generated.
*
* For MicroBlaze/PowerPC, the BSP doesn't enable caches and this application
* enables only I-Caches. For ARM, the BSP enables caches by default, so this
* application disables D-Caches before running memory tests.
*/
void putnum(unsigned int num);
void test_memory_range(struct memory_range_s *range) {
XStatus status;
/* This application uses print statements instead of xil_printf/printf
* to reduce the text size.
*
* The default linker script generated for this application does not have
* heap memory allocated. This implies that this program cannot use any
* routines that allocate memory on heap (printf is one such function).
* If you'd like to add such functions, then please generate a linker script
* that does allocate sufficient heap memory.
*/
print("Testing memory region: "); print(range->name); print("\n\r");
print(" Memory Controller: "); print(range->ip); print("\n\r");
#ifdef __MICROBLAZE__
print(" Base Address: 0x"); putnum(range->base); print("\n\r");
print(" Size: 0x"); putnum(range->size); print (" bytes \n\r");
#else
xil_printf(" Base Address: 0x%lx \n\r",range->base);
xil_printf(" Size: 0x%lx bytes \n\r",range->size);
#endif
status = Xil_TestMem32((u32*)range->base, 1024, 0xAAAA5555, XIL_TESTMEM_ALLMEMTESTS);
print(" 32-bit test: "); print(status == XST_SUCCESS? "PASSED!":"FAILED!"); print("\n\r");
status = Xil_TestMem16((u16*)range->base, 2048, 0xAA55, XIL_TESTMEM_ALLMEMTESTS);
print(" 16-bit test: "); print(status == XST_SUCCESS? "PASSED!":"FAILED!"); print("\n\r");
status = Xil_TestMem8((u8*)range->base, 4096, 0xA5, XIL_TESTMEM_ALLMEMTESTS);
print(" 8-bit test: "); print(status == XST_SUCCESS? "PASSED!":"FAILED!"); print("\n\r");
}
int main()
{
int i;
init_platform();
print("--Starting Memory Test Application--\n\r");
print("NOTE: This application runs with D-Cache disabled.");
print("As a result, cacheline requests will not be generated\n\r");
for (i = 0; i < n_memory_ranges; i++) {
test_memory_range(&memory_ranges[i]);
}
print("--Memory Test Application Complete--\n\r");
cleanup_platform();
return 0;
}
@@ -0,0 +1,94 @@
/******************************************************************************
*
* Copyright (C) 2010 - 2014 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
#include "xparameters.h"
#include "xil_cache.h"
#include "platform_config.h"
#ifdef STDOUT_IS_16550
#include "xuartns550_l.h"
#endif
void
enable_caches()
{
#ifdef __PPC__
Xil_ICacheEnableRegion(XPAR_CACHEABLE_REGION_MASK);
// Do not enable caches for memory tests, this has pros and cons
// Pros - If caches are enabled, under certain configurations, there will be very few
// transactions to external memory
// Con - This might not generate a burst cacheline request
// Xil_DCacheEnableRegion(CACHEABLE_REGION_MASK);
#elif __MICROBLAZE__
#ifdef XPAR_MICROBLAZE_USE_ICACHE
Xil_ICacheEnable();
#endif
#ifdef XPAR_MICROBLAZE_USE_DCACHE
// See reason above for not enabling D Cache
// Xil_DCacheEnable();
#endif
#elif __arm__
// For ARM, BSP enables caches by default.
#endif
}
void
disable_caches()
{
Xil_DCacheDisable();
Xil_ICacheDisable();
}
void
init_platform()
{
enable_caches();
#ifdef __arm__
// For ARM, BSP enables caches by default. Disable them here.
// See reason above for disabling D Cache
Xil_DCacheDisable();
#endif
/* if we have a uart 16550, then that needs to be initialized */
#ifdef STDOUT_IS_16550
XUartNs550_SetBaud(STDOUT_BASEADDR, XPAR_XUARTNS550_CLOCK_HZ, 9600);
XUartNs550_SetLineControlReg(STDOUT_BASEADDR, XUN_LCR_8_DATA_BITS);
#endif
}
void
cleanup_platform()
{
disable_caches();
}
@@ -0,0 +1,41 @@
/******************************************************************************
*
* Copyright (C) 2008 - 2014 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
#ifndef __PLATFORM_H_
#define __PLATFORM_H_
#include "platform_config.h"
void init_platform();
void cleanup_platform();
#endif
@@ -0,0 +1,4 @@
#ifndef __PLATFORM_CONFIG_H_
#define __PLATFORM_CONFIG_H_
#endif