feat: PS修改为演示验证版本

This commit is contained in:
2024-11-07 11:39:25 +08:00
parent 7dc4f160b6
commit 25c9dd91a3
92 changed files with 35864 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,28 @@
{
"project_name": "sjl_basic",
"version": "0.0.2",
"hw_design": "../system_top.xsa",
"hw_version": "sjl_basic-HW-0.0.2",
"apps": {
"sjl_basic_app": {
"sources": ["source/"],
"target_cpu": "ps7_cortexa9_0",
"os": "standalone",
"language": "C",
"mem_layout" : {
"heap_size": "0x80000",
"stack_size": "0x4000"
},
"build_config": {
"debug": {
"include-path": ["source/include"],
"libraries": ["m"]
},
"release": {
"include-path": ["source/include"],
"libraries": ["m"]
}
}
}
}
}
@@ -0,0 +1,296 @@
/*****************************************************************************/
/**
* Description: Global configurations.
*
* Date: 2021-04-28 13:19
* Last Editors: Fan Hao
* Last Edit Time: [2022-05-23 20:32]
*
* Revisions: Rev 0.0
* History:
* [2021-04-28]: Initial edition.
*
* Copyright(c) 2024 Beijing Institute of Technology.
* Lab of Communication and Networking
*
******************************************************************************/
#ifndef __APP_CONFIG_H_
#define __APP_CONFIG_H_
#include "xparameters.h"
#ifdef PLATFORM_ZYNQMP // Zynq MPSoC (Zynq UltraScale+)
#define HSJL_GE
#elif defined(PLATFORM_ZYNQ)
#define HSJL_NODE
#else
#error Unsupported hardware...
#endif
/******** Software Version ********/
#define _APP_VER 0x00010008
#define _APP_VER_MAIN ((_APP_VER & 0xFF000000) >> 24)
#define _APP_VER_MINOR ((_APP_VER & 0x00FF0000) >> 16)
#define _APP_VER_PATCH (_APP_VER & 0x0000FFFF)
/*********** Debug Info Level ************/
// #define _DEBUG_LEVEL 1
// 3 - print all debug info
// 2 - print warnings and errors
// 1 - print only errors
// other - print nothing
#define DATALINK_ENABLE_AUTORECONNECT
#define DATALINK_ENABLE_AUTOTIMESYNC
// #define DATALINK_ENABLE_BERTEST
/************ Hardware Configs ************/
#ifdef HSJL_GE // Zynq MPSoC (Zynq UltraScale+)
#define CPU_CLK_HZ XPAR_CPU_CORTEXA53_0_CPU_CLK_FREQ_HZ
#define FCLK_CLK0_HZ 100000000
#define APP_TIMER_CLK_HZ FCLK_CLK0_HZ
#else // Zynq-7000
#define CPU_CLK_HZ XPAR_CPU_CORTEXA9_0_CPU_CLK_FREQ_HZ
#define APP_TIMER_CLK_HZ (CPU_CLK_HZ / 2)
#define FCLK_CLK0_HZ 100000000
#endif
/********* Zynq Platform Configs **********/
// APP Timer (for logging)
#ifdef HSJL_GE // Zynq MPSoC (Zynq UltraScale+)
#define APPTIMER_DEVICE_ID XPAR_AXI_TIMER_DEVICE_ID
#define APPTIMER_INTR_ID XPAR_FABRIC_AXI_TIMER_INTERRUPT_INTR
#else
#define APPTIMER_DEVICE_ID XPAR_PS7_SCUTIMER_0_DEVICE_ID
#define APPTIMER_INTR_ID XPAR_SCUTIMER_INTR
#endif
// Physical Layer Configs
#define PHY_DEVICE_ID (0x01 | 0x00)
#define PHY_BASEADDR XPAR_PHYC_BASEADDR
#define PHY_BEAM_FORMING_ENABLE
// -- Antenna Bram Configs
#define PHY_ANTCONFIG_BRAM_DEVICE_ID XPAR_PHY_DATA_INTERFACE_ANT_CONFIG_BRAM_CTRL_DEVICE_ID
#define PHY_ANTINFO_BRAM_DEVICE_ID XPAR_PHY_DATA_INTERFACE_ANT_BEAM_BRAM_CTRL_DEVICE_ID
// -- Buffers
#define PHY_TXBUFF_BRAM_DEVICE_ID XPAR_PHY_DATA_INTERFACE_TX_FRAME_BRAM_CTRL_DEVICE_ID
#define PHY_RXBUFF_BRAM_DEVICE_ID XPAR_PHY_DATA_INTERFACE_RX_FRAME_BRAM_CTRL_DEVICE_ID
// -- Xadc
#define PHY_HW_SYSMON_DEVICE_ID XPAR_SYSTEM_MANAGEMENT_DEVICE_ID
// -- Interrupt id
#define PHY_INTR_ID XPAR_FABRIC_PHY_IRQ_INTR
#define PERIODIC_5MS_INTR_ID XPAR_FABRIC_PHY_5MS_DELAY_2MS_INTR
// Time Controller Configs
#define TIME_CONTROLLER_BASEADDR XPAR_TMC_BASEADDR
// System Bus Configs
#define SYSBUS_BASE_ADDR XPAR_SYSTEMBUS_BASEADDR
#define SYSBUS_TX_INTR_ID XPAR_FABRIC_SYSTEMBUS_TX_DONE_INTR
#define SYSBUS_RX_INTR_ID XPAR_FABRIC_SYSTEMBUS_RX_DONE_INTR
// INTC configis
#define INTC_DEVICE_ID XPAR_SCUGIC_0_DEVICE_ID
/********* Hardware Configurations **********/
#ifdef HSJL_GE // Zynq MPSoC (Zynq UltraScale+)
#define RFSOC
#define LMK04828
//#define LMX2594_ADC
//#define LMX2594_DAC
#define RFDC_DEVICE_ID XPAR_XRFDC_0_DEVICE_ID
#else
#define AD9361_REG
//#define AD9361_API
#define AD9528
//#define AD9653
//#define AD9694
#endif
// AD9361 Configuration
#define SPI_INTERFACE_SPI_ENGINE
#define HAVE_SPLIT_GAIN_TABLE 1 /* only set to 0 in case split_gain_table_mode_enable = 0*/
#define HAVE_TDD_SYNTH_TABLE 1 /* only set to 0 in case split_gain_table_mode_enable = 0*/
#define AD9361_DEVICE 1 /* set it 1 if AD9361 device is used, 0 otherwise */
#define AD9364_DEVICE 0 /* set it 1 if AD9364 device is used, 0 otherwise */
#define AD9363A_DEVICE 0 /* set it 1 if AD9363A device is used, 0 otherwise */
#define HAVE_VERBOSE_MESSAGES /* Recommended during development prints errors and warnings */
// #define HAVE_DEBUG_MESSAGES /* For Debug purposes only */
// AD9361 GPIO Configurations
#define AD9361_GPIO_DEVICE_ID 0
#define AD9361_GPIO_OFFSET 54
#define AD9361_GPIO_INPUT 0
#define AD9361_GPIO_OUTPUT 1
#define AD9361_GPIO_DISABLE 0
#define AD9361_GPIO_ENABLE 1
// -- AD9361-1 SPI Engine Configuration
#define AD9361_SPI_DEVICE_ID 0
#define AD9361_SPI_ENGINE_REF_CLK FCLK_CLK0_HZ
#define AD9361_SPI_ENGINE_MAX_SPEED 5000000
#define AD9361_SPI_ENGINE_BASEADDR XPAR_AXI_SPI_ENGINE_AXI_SPI_ENGINE_BASEADDR
#define AD9361_SPI_ENGINE_DATA_WIDTH 8
#define AD9361_SPI_ENGINE_CS_DELAY 3
#define AD9361_TIMEOUT_TH 2000
#define AD9361_1_SPI_CS 0x01
#define AD9361_2_SPI_CS 0x02
#define AD9361_2_TIMEOUT_TH 2000
// -- AD9361-1 GPIO
#define AD9361_1_TXNRX (AD9361_GPIO_OFFSET + 6)
#define AD9361_1_ENABLE (AD9361_GPIO_OFFSET + 7)
#define AD9361_1_EN_AGC (AD9361_GPIO_OFFSET + 8)
#define AD9361_1_RESET_B (AD9361_GPIO_OFFSET + 9)
#define AD9361_1_CTRL_OUT0 (AD9361_GPIO_OFFSET + 10)
#define AD9361_1_CTRL_OUT1 (AD9361_GPIO_OFFSET + 11)
#define AD9361_1_CTRL_OUT2 (AD9361_GPIO_OFFSET + 12)
#define AD9361_1_CTRL_OUT3 (AD9361_GPIO_OFFSET + 13)
#define AD9361_1_CTRL_OUT4 (AD9361_GPIO_OFFSET + 14)
#define AD9361_1_CTRL_OUT5 (AD9361_GPIO_OFFSET + 15)
#define AD9361_1_CTRL_OUT6 (AD9361_GPIO_OFFSET + 16)
#define AD9361_1_CTRL_OUT7 (AD9361_GPIO_OFFSET + 17)
#define AD9361_1_CTRL_IN0 (AD9361_GPIO_OFFSET + 18)
#define AD9361_1_CTRL_IN1 (AD9361_GPIO_OFFSET + 19)
#define AD9361_1_CTRL_IN2 (AD9361_GPIO_OFFSET + 20)
#define AD9361_1_CTRL_IN3 (AD9361_GPIO_OFFSET + 21)
// -- AD9361-2 GPIO
#define AD9361_2_TXNRX (AD9361_GPIO_OFFSET + 22)
#define AD9361_2_ENABLE (AD9361_GPIO_OFFSET + 23)
#define AD9361_2_EN_AGC (AD9361_GPIO_OFFSET + 24)
#define AD9361_2_RESET_B (AD9361_GPIO_OFFSET + 25)
#define AD9361_2_CTRL_OUT0 (AD9361_GPIO_OFFSET + 26)
#define AD9361_2_CTRL_OUT1 (AD9361_GPIO_OFFSET + 27)
#define AD9361_2_CTRL_OUT2 (AD9361_GPIO_OFFSET + 28)
#define AD9361_2_CTRL_OUT3 (AD9361_GPIO_OFFSET + 29)
#define AD9361_2_CTRL_OUT4 (AD9361_GPIO_OFFSET + 30)
#define AD9361_2_CTRL_OUT5 (AD9361_GPIO_OFFSET + 31)
#define AD9361_2_CTRL_OUT6 (AD9361_GPIO_OFFSET + 32)
#define AD9361_2_CTRL_OUT7 (AD9361_GPIO_OFFSET + 33)
#define AD9361_2_CTRL_IN0 (AD9361_GPIO_OFFSET + 34)
#define AD9361_2_CTRL_IN1 (AD9361_GPIO_OFFSET + 35)
#define AD9361_2_CTRL_IN2 (AD9361_GPIO_OFFSET + 36)
#define AD9361_2_CTRL_IN3 (AD9361_GPIO_OFFSET + 37)
// AD9361-Status Code
#define AD9361_SYNC (AD9361_GPIO_OFFSET + 38)
#define AD9361_RX_FIFO_RST (AD9361_GPIO_OFFSET + 39)
#define AD9361_1_CAL_START (AD9361_GPIO_OFFSET + 40)
#define AD9361_2_CAL_START (AD9361_GPIO_OFFSET + 41)
#define AD9361_RECAL (AD9361_GPIO_OFFSET + 42)
#define AD9361_TX_SWITCH (AD9361_GPIO_OFFSET + 43)
#define AD9361_1_CAL_DONE (AD9361_GPIO_OFFSET + 44)
#define AD9361_2_CAL_DONE (AD9361_GPIO_OFFSET + 45)
#define AD9361_CAL_RESULT (AD9361_GPIO_OFFSET + 46)
typedef enum
{
TX_FREQ_125,
TX_FREQ_126,
TX_FREQ_4125
} ad9361TxFreq;
// HMC7044 Configurations
#define HMC7044_GPIO_DEVICE_ID 0
#define HMC7044_GPIO_OFFSET 54
#define HMC7044_RESET (HMC7044_GPIO_OFFSET + 0)
#define HMC7044_SYNC (HMC7044_GPIO_OFFSET + 1)
#define HMC7044_GPIO_0 (HMC7044_GPIO_OFFSET + 2)
#define HMC7044_GPIO_1 (HMC7044_GPIO_OFFSET + 3)
#define HMC7044_GPIO_2 (HMC7044_GPIO_OFFSET + 4)
#define HMC7044_GPIO_3 (HMC7044_GPIO_OFFSET + 5)
// -- HMC7044 SPI Engine Configuration
#define HMC7044_SPI_DEVICE_ID 0
#define HMC7044_SPI_ENGINE_REF_CLK FCLK_CLK0_HZ
#define HMC7044_SPI_ENGINE_MAX_SPEED 5000000
#define HMC7044_SPI_ENGINE_BASEADDR XPAR_AXI_SPI_ENGINE_AXI_SPI_ENGINE_BASEADDR
#define HMC7044_SPI_ENGINE_DATA_WIDTH 8
#define HMC7044_SPI_ENGINE_CS_DELAY 3
#define HMC7044_SPI_CS_HMC7044 0x00
// AD9528 Configurations
#define AD9528_GPIO_DEVICE_ID 0
#define AD9528_GPIO_OFFSET 54
#define AD9528_RESETB (AD9528_GPIO_OFFSET+0)
#define AD9528_SYSREF_REQ (AD9528_GPIO_OFFSET+1)
#define AD9528_STATUS_0 (AD9528_GPIO_OFFSET+2)
#define AD9528_STATUS_1 (AD9528_GPIO_OFFSET+3)
// -- AD9528 SPI Engine Configuration
#define AD9528_SPI_DEVICE_ID 0
#define AD9528_SPI_ENGINE_REF_CLK FCLK_CLK0_HZ
#define AD9528_SPI_ENGINE_MAX_SPEED 5000000
#define AD9528_SPI_ENGINE_BASEADDR XPAR_AXI_SPI_ENGINE_AXI_SPI_ENGINE_BASEADDR
#define AD9528_SPI_ENGINE_DATA_WIDTH 8
#define AD9528_SPI_ENGINE_CS_DELAY 3
#define AD9528_SPI_CS 0x00
// LMK04828 Configurations
#define LMK04828_GPIO_DEVICE_ID 0
#define LMK04828_GPIO_OFFSET 54
// -- LMK04828 SPI Engine Configuration
#define LMK04828_SPI_DEVICE_ID 0
#define LMK04828_SPI_ENGINE_REF_CLK FCLK_CLK0_HZ
#define LMK04828_SPI_ENGINE_MAX_SPEED 5000000
#define LMK04828_SPI_ENGINE_BASEADDR XPAR_AXI_SPI_ENGINE_AXI_SPI_ENGINE_BASEADDR
#define LMK04828_SPI_ENGINE_DATA_WIDTH 8
#define LMK04828_SPI_ENGINE_CS_DELAY 3
#define LMK04828_SPI_CS 0x00
// LMX2594_ADC Configurations
#define LMX2594_ADC_GPIO_DEVICE_ID 0
#define LMX2594_ADC_GPIO_OFFSET 54
// -- LMX2594_ADC SPI Engine Configuration
#define LMX2594_ADC_SPI_DEVICE_ID 0
#define LMX2594_ADC_SPI_ENGINE_REF_CLK FCLK_CLK0_HZ
#define LMX2594_ADC_SPI_ENGINE_MAX_SPEED 5000000
#define LMX2594_ADC_SPI_ENGINE_BASEADDR XPAR_AXI_SPI_ENGINE_AXI_SPI_ENGINE_BASEADDR
#define LMX2594_ADC_SPI_ENGINE_DATA_WIDTH 8
#define LMX2594_ADC_SPI_ENGINE_CS_DELAY 3
#define LMX2594_ADC_SPI_CS 0x01
// LMX2594_DAC Configurations
#define LMX2594_DAC_GPIO_DEVICE_ID 0
#define LMX2594_DAC_GPIO_OFFSET 54
// -- LMX2594_DAC SPI Engine Configuration
#define LMX2594_DAC_SPI_DEVICE_ID 0
#define LMX2594_DAC_SPI_ENGINE_REF_CLK FCLK_CLK0_HZ
#define LMX2594_DAC_SPI_ENGINE_MAX_SPEED 5000000
#define LMX2594_DAC_SPI_ENGINE_BASEADDR XPAR_AXI_SPI_ENGINE_AXI_SPI_ENGINE_BASEADDR
#define LMX2594_DAC_SPI_ENGINE_DATA_WIDTH 8
#define LMX2594_DAC_SPI_ENGINE_CS_DELAY 3
#define LMX2594_DAC_SPI_CS 0x02
// AD9653 Configurations
#define AD9653_GPIO_DEVICE_ID 0
#define AD9653_GPIO_OFFSET 54
#define AD9653_POWR_DOWN (AD9653_GPIO_OFFSET+0)
// -- AD9653 SPI Engine Configuration
#define AD9653_SPI_DEVICE_ID 0
#define AD9653_SPI_ENGINE_REF_CLK FCLK_CLK0_HZ
#define AD9653_SPI_ENGINE_MAX_SPEED 5000000
#define AD9653_SPI_ENGINE_BASEADDR XPAR_AXI_SPI_ENGINE_AXI_SPI_ENGINE_BASEADDR
#define AD9653_SPI_ENGINE_DATA_WIDTH 8
#define AD9653_SPI_ENGINE_CS_DELAY 3
#define AD9653_SPI_CS 0x03
// AD9694 Configurations
#define AD9694_GPIO_DEVICE_ID 0
#define AD9694_GPIO_OFFSET 54
// -- AD9694 SPI Engine Configuration
#define AD9694_SPI_DEVICE_ID 0
#define AD9694_SPI_ENGINE_REF_CLK FCLK_CLK0_HZ
#define AD9694_SPI_ENGINE_MAX_SPEED 5000000
#define AD9694_SPI_ENGINE_BASEADDR XPAR_AXI_SPI_ENGINE_AXI_SPI_ENGINE_BASEADDR
#define AD9694_SPI_ENGINE_DATA_WIDTH 8
#define AD9694_SPI_ENGINE_CS_DELAY 3
#define AD9694_SPI_CS 0x03
// Configuration Check
#if defined(PHY_BEAM_SET_PRESET) && !defined(PHY_BEAM_FORMING_ENABLE)
#define PHY_BEAM_FORMING_ENABLE
#warning To impliment beam scan must enable beam forming...
#endif
#if defined(DATALINK_ENABLE_BERTEST)
#if !defined(DATALINK_ENABLE_AUTOTIMESYNC)
#warning To enbale bit error rate test, auto time-sync should be enabled...
#endif
#endif
#endif //__APP_CONFIG_H_
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,340 @@
#include "dev_profile.h"
#include "../config/app_config.h"
#include "../drivers/rf-transceiver/ad9361/ad9361_api.h"
#include "../drivers/axi_core/spi_engine/spi_engine.h"
#include "../drivers/platform/xilinx_gpio.h"
struct spi_engine_init_param spi_engine_param = {
.ref_clk_hz = AD9361_SPI_ENGINE_REF_CLK,
.type = SPI_ENGINE,
.spi_engine_baseaddr = AD9361_SPI_ENGINE_BASEADDR,
.cs_delay = AD9361_SPI_ENGINE_CS_DELAY,
.data_width = AD9361_SPI_ENGINE_DATA_WIDTH
};
struct xil_gpio_init_param xil_gpio_param = {
.type = GPIO_PS,
.device_id = AD9361_GPIO_DEVICE_ID
};
AD9361_InitParam ad9361_default_init_param = {
/* Device selection */
ID_AD9361, // dev_sel
/* Reference Clock */
48000000UL, //reference_clk_rate
/* Base Configuration */
1, //two_rx_two_tx_mode_enable *** adi,2rx-2tx-mode-enable
1, //one_rx_one_tx_mode_use_rx_num *** adi,1rx-1tx-mode-use-rx-num
1, //one_rx_one_tx_mode_use_tx_num *** adi,1rx-1tx-mode-use-tx-num
1, //frequency_division_duplex_mode_enable *** adi,frequency-division-duplex-mode-enable
0, //frequency_division_duplex_independent_mode_enable *** adi,frequency-division-duplex-independent-mode-enable
0, //tdd_use_dual_synth_mode_enable *** adi,tdd-use-dual-synth-mode-enable
0, //tdd_skip_vco_cal_enable *** adi,tdd-skip-vco-cal-enable
0, //tx_fastlock_delay_ns *** adi,tx-fastlock-delay-ns
0, //rx_fastlock_delay_ns *** adi,rx-fastlock-delay-ns
0, //rx_fastlock_pincontrol_enable *** adi,rx-fastlock-pincontrol-enable
0, //tx_fastlock_pincontrol_enable *** adi,tx-fastlock-pincontrol-enable
0, //external_rx_lo_enable *** adi,external-rx-lo-enable
0, //external_tx_lo_enable *** adi,external-tx-lo-enable
5, //dc_offset_tracking_update_event_mask *** adi,dc-offset-tracking-update-event-mask
6, //dc_offset_attenuation_high_range *** adi,dc-offset-attenuation-high-range
5, //dc_offset_attenuation_low_range *** adi,dc-offset-attenuation-low-range
0x28, //dc_offset_count_high_range *** adi,dc-offset-count-high-range
0x32, //dc_offset_count_low_range *** adi,dc-offset-count-low-range
0, //split_gain_table_mode_enable *** adi,split-gain-table-mode-enable
MAX_SYNTH_FREF, //trx_synthesizer_target_fref_overwrite_hz *** adi,trx-synthesizer-target-fref-overwrite-hz
0, // qec_tracking_slow_mode_enable *** adi,qec-tracking-slow-mode-enable
/* ENSM Control */
0, //ensm_enable_pin_pulse_mode_enable *** adi,ensm-enable-pin-pulse-mode-enable
0, //ensm_enable_txnrx_control_enable *** adi,ensm-enable-txnrx-control-enable
/* LO Control */
4125000000UL, //rx_synthesizer_frequency_hz *** adi,rx-synthesizer-frequency-hz
4126000000UL, //tx_synthesizer_frequency_hz *** adi,tx-synthesizer-frequency-hz
1, //tx_lo_powerdown_managed_enable *** adi,tx-lo-powerdown-managed-enable
/* Rate & BW Control */
{768000000, 192000000, 96000000, 48000000, 24000000, 24000000},// rx_path_clock_frequencies[6] *** adi,rx-path-clock-frequencies
{768000000, 192000000, 96000000, 48000000, 24000000, 24000000},// tx_path_clock_frequencies[6] *** adi,tx-path-clock-frequencies
18000000,//rf_rx_bandwidth_hz *** adi,rf-rx-bandwidth-hz
18000000,//rf_tx_bandwidth_hz *** adi,rf-tx-bandwidth-hz
/* RF Port Control */
0, //rx_rf_port_input_select *** adi,rx-rf-port-input-select
0, //tx_rf_port_input_select *** adi,tx-rf-port-input-select
/* TX Attenuation Control */
10000, //tx_attenuation_mdB *** adi,tx-attenuation-mdB
0, //update_tx_gain_in_alert_enable *** adi,update-tx-gain-in-alert-enable
/* Reference Clock Control */
0, //xo_disable_use_ext_refclk_enable *** adi,xo-disable-use-ext-refclk-enable
{8, 5920}, //dcxo_coarse_and_fine_tune[2] *** adi,dcxo-coarse-and-fine-tune
CLKOUT_DISABLE, //clk_output_mode_select *** adi,clk-output-mode-select
/* Gain Control */
2, //gc_rx1_mode *** adi,gc-rx1-mode
2, //gc_rx2_mode *** adi,gc-rx2-mode
58, //gc_adc_large_overload_thresh *** adi,gc-adc-large-overload-thresh
4, //gc_adc_ovr_sample_size *** adi,gc-adc-ovr-sample-size
47, //gc_adc_small_overload_thresh *** adi,gc-adc-small-overload-thresh
8192, //gc_dec_pow_measurement_duration *** adi,gc-dec-pow-measurement-duration
0, //gc_dig_gain_enable *** adi,gc-dig-gain-enable
800, //gc_lmt_overload_high_thresh *** adi,gc-lmt-overload-high-thresh
704, //gc_lmt_overload_low_thresh *** adi,gc-lmt-overload-low-thresh
24, //gc_low_power_thresh *** adi,gc-low-power-thresh
15, //gc_max_dig_gain *** adi,gc-max-dig-gain
0, //gc_use_rx_fir_out_for_dec_pwr_meas_enable *** adi,gc-use-rx-fir-out-for-dec-pwr-meas-enable
/* Gain MGC Control */
2, //mgc_dec_gain_step *** adi,mgc-dec-gain-step
2, //mgc_inc_gain_step *** adi,mgc-inc-gain-step
0, //mgc_rx1_ctrl_inp_enable *** adi,mgc-rx1-ctrl-inp-enable
0, //mgc_rx2_ctrl_inp_enable *** adi,mgc-rx2-ctrl-inp-enable
0, //mgc_split_table_ctrl_inp_gain_mode *** adi,mgc-split-table-ctrl-inp-gain-mode
/* Gain AGC Control */
10, //agc_adc_large_overload_exceed_counter *** adi,agc-adc-large-overload-exceed-counter
2, //agc_adc_large_overload_inc_steps *** adi,agc-adc-large-overload-inc-steps
0, //agc_adc_lmt_small_overload_prevent_gain_inc_enable *** adi,agc-adc-lmt-small-overload-prevent-gain-inc-enable
10, //agc_adc_small_overload_exceed_counter *** adi,agc-adc-small-overload-exceed-counter
4, //agc_dig_gain_step_size *** adi,agc-dig-gain-step-size
3, //agc_dig_saturation_exceed_counter *** adi,agc-dig-saturation-exceed-counter
1000, // agc_gain_update_interval_us *** adi,agc-gain-update-interval-us
0, //agc_immed_gain_change_if_large_adc_overload_enable *** adi,agc-immed-gain-change-if-large-adc-overload-enable
0, //agc_immed_gain_change_if_large_lmt_overload_enable *** adi,agc-immed-gain-change-if-large-lmt-overload-enable
10, //agc_inner_thresh_high *** adi,agc-inner-thresh-high
1, //agc_inner_thresh_high_dec_steps *** adi,agc-inner-thresh-high-dec-steps
12, //agc_inner_thresh_low *** adi,agc-inner-thresh-low
1, //agc_inner_thresh_low_inc_steps *** adi,agc-inner-thresh-low-inc-steps
10, //agc_lmt_overload_large_exceed_counter *** adi,agc-lmt-overload-large-exceed-counter
2, //agc_lmt_overload_large_inc_steps *** adi,agc-lmt-overload-large-inc-steps
10, //agc_lmt_overload_small_exceed_counter *** adi,agc-lmt-overload-small-exceed-counter
5, //agc_outer_thresh_high *** adi,agc-outer-thresh-high
2, //agc_outer_thresh_high_dec_steps *** adi,agc-outer-thresh-high-dec-steps
18, //agc_outer_thresh_low *** adi,agc-outer-thresh-low
2, //agc_outer_thresh_low_inc_steps *** adi,agc-outer-thresh-low-inc-steps
1, //agc_attack_delay_extra_margin_us; *** adi,agc-attack-delay-extra-margin-us
0, //agc_sync_for_gain_counter_enable *** adi,agc-sync-for-gain-counter-enable
/* Fast AGC */
64, //fagc_dec_pow_measuremnt_duration *** adi,fagc-dec-pow-measurement-duration
260, //fagc_state_wait_time_ns *** adi,fagc-state-wait-time-ns
/* Fast AGC - Low Power */
0, //fagc_allow_agc_gain_increase *** adi,fagc-allow-agc-gain-increase-enable
5, //fagc_lp_thresh_increment_time *** adi,fagc-lp-thresh-increment-time
1, //fagc_lp_thresh_increment_steps *** adi,fagc-lp-thresh-increment-steps
/* Fast AGC - Lock Level (Lock Level is set via slow AGC inner high threshold) */
1, //fagc_lock_level_lmt_gain_increase_en *** adi,fagc-lock-level-lmt-gain-increase-enable
5, //fagc_lock_level_gain_increase_upper_limit *** adi,fagc-lock-level-gain-increase-upper-limit
/* Fast AGC - Peak Detectors and Final Settling */
1, //fagc_lpf_final_settling_steps *** adi,fagc-lpf-final-settling-steps
1, //fagc_lmt_final_settling_steps *** adi,fagc-lmt-final-settling-steps
3, //fagc_final_overrange_count *** adi,fagc-final-overrange-count
/* Fast AGC - Final Power Test */
0, //fagc_gain_increase_after_gain_lock_en *** adi,fagc-gain-increase-after-gain-lock-enable
/* Fast AGC - Unlocking the Gain */
0, //fagc_gain_index_type_after_exit_rx_mode *** adi,fagc-gain-index-type-after-exit-rx-mode
1, //fagc_use_last_lock_level_for_set_gain_en *** adi,fagc-use-last-lock-level-for-set-gain-enable
1, //fagc_rst_gla_stronger_sig_thresh_exceeded_en *** adi,fagc-rst-gla-stronger-sig-thresh-exceeded-enable
5, //fagc_optimized_gain_offset *** adi,fagc-optimized-gain-offset
10, //fagc_rst_gla_stronger_sig_thresh_above_ll *** adi,fagc-rst-gla-stronger-sig-thresh-above-ll
1, //fagc_rst_gla_engergy_lost_sig_thresh_exceeded_en *** adi,fagc-rst-gla-engergy-lost-sig-thresh-exceeded-enable
1, //fagc_rst_gla_engergy_lost_goto_optim_gain_en *** adi,fagc-rst-gla-engergy-lost-goto-optim-gain-enable
10, //fagc_rst_gla_engergy_lost_sig_thresh_below_ll *** adi,fagc-rst-gla-engergy-lost-sig-thresh-below-ll
8, //fagc_energy_lost_stronger_sig_gain_lock_exit_cnt *** adi,fagc-energy-lost-stronger-sig-gain-lock-exit-cnt
1, //fagc_rst_gla_large_adc_overload_en *** adi,fagc-rst-gla-large-adc-overload-enable
1, //fagc_rst_gla_large_lmt_overload_en *** adi,fagc-rst-gla-large-lmt-overload-enable
0, //fagc_rst_gla_en_agc_pulled_high_en *** adi,fagc-rst-gla-en-agc-pulled-high-enable
0, //fagc_rst_gla_if_en_agc_pulled_high_mode *** adi,fagc-rst-gla-if-en-agc-pulled-high-mode
64, //fagc_power_measurement_duration_in_state5 *** adi,fagc-power-measurement-duration-in-state5
2, //fagc_large_overload_inc_steps *** adi,fagc-adc-large-overload-inc-steps
/* RSSI Control */
1, //rssi_delay *** adi,rssi-delay
1000, //rssi_duration *** adi,rssi-duration
3, //rssi_restart_mode *** adi,rssi-restart-mode
0, //rssi_unit_is_rx_samples_enable *** adi,rssi-unit-is-rx-samples-enable
1, //rssi_wait *** adi,rssi-wait
/* Aux ADC Control */
256, //aux_adc_decimation *** adi,aux-adc-decimation
48000000UL, //aux_adc_rate *** adi,aux-adc-rate
/* AuxDAC Control */
1, //aux_dac_manual_mode_enable *** adi,aux-dac-manual-mode-enable
0, //aux_dac1_default_value_mV *** adi,aux-dac1-default-value-mV
0, //aux_dac1_active_in_rx_enable *** adi,aux-dac1-active-in-rx-enable
0, //aux_dac1_active_in_tx_enable *** adi,aux-dac1-active-in-tx-enable
0, //aux_dac1_active_in_alert_enable *** adi,aux-dac1-active-in-alert-enable
0, //aux_dac1_rx_delay_us *** adi,aux-dac1-rx-delay-us
0, //aux_dac1_tx_delay_us *** adi,aux-dac1-tx-delay-us
0, //aux_dac2_default_value_mV *** adi,aux-dac2-default-value-mV
0, //aux_dac2_active_in_rx_enable *** adi,aux-dac2-active-in-rx-enable
0, //aux_dac2_active_in_tx_enable *** adi,aux-dac2-active-in-tx-enable
0, //aux_dac2_active_in_alert_enable *** adi,aux-dac2-active-in-alert-enable
0, //aux_dac2_rx_delay_us *** adi,aux-dac2-rx-delay-us
0, //aux_dac2_tx_delay_us *** adi,aux-dac2-tx-delay-us
/* Temperature Sensor Control */
256, //temp_sense_decimation *** adi,temp-sense-decimation
1000, //temp_sense_measurement_interval_ms *** adi,temp-sense-measurement-interval-ms
0xCE, //temp_sense_offset_signed *** adi,temp-sense-offset-signed
1, //temp_sense_periodic_measurement_enable *** adi,temp-sense-periodic-measurement-enable
/* Control Out Setup */
0xFF, //ctrl_outs_enable_mask *** adi,ctrl-outs-enable-mask
0, //ctrl_outs_index *** adi,ctrl-outs-index
/* External LNA Control */
0, //elna_settling_delay_ns *** adi,elna-settling-delay-ns
0, //elna_gain_mdB *** adi,elna-gain-mdB
0, //elna_bypass_loss_mdB *** adi,elna-bypass-loss-mdB
0, //elna_rx1_gpo0_control_enable *** adi,elna-rx1-gpo0-control-enable
0, //elna_rx2_gpo1_control_enable *** adi,elna-rx2-gpo1-control-enable
0, //elna_gaintable_all_index_enable *** adi,elna-gaintable-all-index-enable
/* Digital Interface Control */
0, //digital_interface_tune_skip_mode *** adi,digital-interface-tune-skip-mode
0, //digital_interface_tune_fir_disable *** adi,digital-interface-tune-fir-disable
1, //pp_tx_swap_enable *** adi,pp-tx-swap-enable
1, //pp_rx_swap_enable *** adi,pp-rx-swap-enable
0, //tx_channel_swap_enable *** adi,tx-channel-swap-enable
0, //rx_channel_swap_enable *** adi,rx-channel-swap-enable
1, //rx_frame_pulse_mode_enable *** adi,rx-frame-pulse-mode-enable
0, //two_t_two_r_timing_enable *** adi,2t2r-timing-enable
0, //invert_data_bus_enable *** adi,invert-data-bus-enable
0, //invert_data_clk_enable *** adi,invert-data-clk-enable
0, //fdd_alt_word_order_enable *** adi,fdd-alt-word-order-enable
0, //invert_rx_frame_enable *** adi,invert-rx-frame-enable
0, //fdd_rx_rate_2tx_enable *** adi,fdd-rx-rate-2tx-enable
0, //swap_ports_enable *** adi,swap-ports-enable
0, //single_data_rate_enable *** adi,single-data-rate-enable
1, //lvds_mode_enable *** adi,lvds-mode-enable
0, //half_duplex_mode_enable *** adi,half-duplex-mode-enable
0, //single_port_mode_enable *** adi,single-port-mode-enable
0, //full_port_enable *** adi,full-port-enable
0, //full_duplex_swap_bits_enable *** adi,full-duplex-swap-bits-enable
0, //delay_rx_data *** adi,delay-rx-data
0, //rx_data_clock_delay *** adi,rx-data-clock-delay
4, //rx_data_delay *** adi,rx-data-delay
7, //tx_fb_clock_delay *** adi,tx-fb-clock-delay
0, //tx_data_delay *** adi,tx-data-delay
150, //lvds_bias_mV *** adi,lvds-bias-mV
1, //lvds_rx_onchip_termination_enable *** adi,lvds-rx-onchip-termination-enable
0, //rx1rx2_phase_inversion_en *** adi,rx1-rx2-phase-inversion-enable
0xFF, //lvds_invert1_control *** adi,lvds-invert1-control
0x0F, //lvds_invert2_control *** adi,lvds-invert2-control
/* GPO Control */
0, //gpo_manual_mode_enable *** adi,gpo-manual-mode-enable
0, //gpo_manual_mode_enable_mask *** adi,gpo-manual-mode-enable-mask
0, //gpo0_inactive_state_high_enable *** adi,gpo0-inactive-state-high-enable
0, //gpo1_inactive_state_high_enable *** adi,gpo1-inactive-state-high-enable
0, //gpo2_inactive_state_high_enable *** adi,gpo2-inactive-state-high-enable
0, //gpo3_inactive_state_high_enable *** adi,gpo3-inactive-state-high-enable
0, //gpo0_slave_rx_enable *** adi,gpo0-slave-rx-enable
0, //gpo0_slave_tx_enable *** adi,gpo0-slave-tx-enable
0, //gpo1_slave_rx_enable *** adi,gpo1-slave-rx-enable
0, //gpo1_slave_tx_enable *** adi,gpo1-slave-tx-enable
0, //gpo2_slave_rx_enable *** adi,gpo2-slave-rx-enable
0, //gpo2_slave_tx_enable *** adi,gpo2-slave-tx-enable
0, //gpo3_slave_rx_enable *** adi,gpo3-slave-rx-enable
0, //gpo3_slave_tx_enable *** adi,gpo3-slave-tx-enable
0, //gpo0_rx_delay_us *** adi,gpo0-rx-delay-us
0, //gpo0_tx_delay_us *** adi,gpo0-tx-delay-us
0, //gpo1_rx_delay_us *** adi,gpo1-rx-delay-us
0, //gpo1_tx_delay_us *** adi,gpo1-tx-delay-us
0, //gpo2_rx_delay_us *** adi,gpo2-rx-delay-us
0, //gpo2_tx_delay_us *** adi,gpo2-tx-delay-us
0, //gpo3_rx_delay_us *** adi,gpo3-rx-delay-us
0, //gpo3_tx_delay_us *** adi,gpo3-tx-delay-us
/* Tx Monitor Control */
37000, //low_high_gain_threshold_mdB *** adi,txmon-low-high-thresh
0, //low_gain_dB *** adi,txmon-low-gain
24, //high_gain_dB *** adi,txmon-high-gain
0, //tx_mon_track_en *** adi,txmon-dc-tracking-enable
0, //one_shot_mode_en *** adi,txmon-one-shot-mode-enable
511, //tx_mon_delay *** adi,txmon-delay
8192, //tx_mon_duration *** adi,txmon-duration
2, //tx1_mon_front_end_gain *** adi,txmon-1-front-end-gain
2, //tx2_mon_front_end_gain *** adi,txmon-2-front-end-gain
48, //tx1_mon_lo_cm *** adi,txmon-1-lo-cm
48, //tx2_mon_lo_cm *** adi,txmon-2-lo-cm
/* GPIO definitions */
/* Reset_b */
{
.number = AD9361_1_RESET_B,
.platform_ops = &xil_gpio_ops,
.extra = &xil_gpio_param
}, //gpio_resetb *** reset-gpios
/* MCS Sync */
{
.number = -1,
.platform_ops = &xil_gpio_ops,
.extra = &xil_gpio_param
}, //gpio_sync *** sync-gpios
/* Cal-SW1 */
{
.number = -1,
.platform_ops = &xil_gpio_ops,
.extra = &xil_gpio_param
}, //gpio_cal_sw1 *** cal-sw1-gpios
/* Cal-SW2 */
{
.number = -1,
.platform_ops = &xil_gpio_ops,
.extra = &xil_gpio_param
}, //gpio_cal_sw2 *** cal-sw2-gpios
{
.device_id = AD9361_SPI_DEVICE_ID,
.mode = SPI_MODE_1,
.chip_select = AD9361_1_SPI_CS,
.platform_ops = &spi_eng_platform_ops,
.extra = &spi_engine_param
},
/* External LO clocks */
NULL, //(*ad9361_rfpll_ext_recalc_rate)()
NULL, //(*ad9361_rfpll_ext_round_rate)()
NULL, //(*ad9361_rfpll_ext_set_rate)()
};
AD9361_RXFIRConfig rx_fir_config = { // BPF PASSBAND 3/20 fs to 1/4 fs
3, // rx
0, // rx_gain
1, // rx_dec
{
-4, -6, -37, 35, 186, 86, -284, -315,
107, 219, -4, 271, 558, -307, -1182, -356,
658, 157, 207, 1648, 790, -2525, -2553, 748,
865, -476, 3737, 6560, -3583, -14731, -5278, 14819,
14819, -5278, -14731, -3583, 6560, 3737, -476, 865,
748, -2553, -2525, 790, 1648, 207, 157, 658,
-356, -1182, -307, 558, 271, -4, 219, 107,
-315, -284, 86, 186, 35, -37, -6, -4,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
}, // rx_coef[128]
64, // rx_coef_size
{0, 0, 0, 0, 0, 0}, //rx_path_clks[6]
0 // rx_bandwidth
};
AD9361_TXFIRConfig tx_fir_config = { // BPF PASSBAND 3/20 fs to 1/4 fs
3, // tx
-6, // tx_gain
1, // tx_int
{
-4, -6, -37, 35, 186, 86, -284, -315,
107, 219, -4, 271, 558, -307, -1182, -356,
658, 157, 207, 1648, 790, -2525, -2553, 748,
865, -476, 3737, 6560, -3583, -14731, -5278, 14819,
14819, -5278, -14731, -3583, 6560, 3737, -476, 865,
748, -2553, -2525, 790, 1648, 207, 157, 658,
-356, -1182, -307, 558, 271, -4, 219, 107,
-315, -284, 86, 186, 35, -37, -6, -4,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
}, // tx_coef[128]
64, // tx_coef_size
{0, 0, 0, 0, 0, 0}, // tx_path_clks[6]
0 // tx_bandwidth
};
@@ -0,0 +1,134 @@
#include "dev_profile.h"
#include "../config/app_config.h"
#include "../drivers/platform/xilinx_gpio.h"
#include "../drivers/axi_core/spi_engine/spi_engine.h"
#include "../drivers/frequency/ad9528/ad9528.h"
static struct spi_engine_init_param spi_engine_param = {
.ref_clk_hz = AD9528_SPI_ENGINE_REF_CLK,
.type = SPI_ENGINE,
.spi_engine_baseaddr = AD9528_SPI_ENGINE_BASEADDR,
.cs_delay = AD9528_SPI_ENGINE_CS_DELAY,
.data_width = AD9528_SPI_ENGINE_DATA_WIDTH
};
static struct xil_gpio_init_param xil_gpio_param = {
.type = GPIO_PS,
.device_id = AD9528_GPIO_DEVICE_ID
};
static struct spi_init_param ad9528_spi_init = {
.device_id = AD9528_SPI_DEVICE_ID,
.max_speed_hz = AD9528_SPI_ENGINE_MAX_SPEED,
.mode = SPI_MODE_0,
.chip_select = AD9528_SPI_CS,
.platform_ops = &spi_eng_platform_ops,
.extra = &spi_engine_param
};
static struct gpio_init_param ad9528_gpio_resetb_init = {
.number = AD9528_RESETB,
.platform_ops = &xil_gpio_ops,
.extra = &xil_gpio_param
};
static struct gpio_init_param ad9528_gpio_sysref_req_init = {
.number = AD9528_SYSREF_REQ,
.platform_ops = &xil_gpio_ops,
.extra = &xil_gpio_param
};
static ad9528pll1Settings_t clockPll1Settings = {
.refA_Frequency_Hz = 50000000,
.refA_Divider = 1,
.refA_bufferCtrl = SINGLE_ENDED,
.refB_Frequency_Hz = 0,
.refB_Divider = 1,
.refB_bufferCtrl = DISABLED,
.vcxo_Frequency_Hz = 50000000,
.vcxoBufferCtrl = SINGLE_ENDED,
.nDivider = 1
};
static ad9528pll2Settings_t clockPll2Settings = {
.rfDivider = 4,
.n2Divider = 20,
.totalNdiv = 80
};
/*******************************************************************
* Output Distribution Settings
* 9369CE02A uses the following clock outputs
* OUT 1: FPGA REFCLK
* OUT 3: FPGA SYSREF
* OUT 12: DUT SYSREF
* OUT 13: DUT REFCLK
*******************************************************************
*/
static ad9528outputSettings_t clockOutputSettings = {
.outPowerDown = 0xE001,
.outSource = {
AD9528_CHANNEL_DIV, AD9528_CHANNEL_DIV, AD9528_CHANNEL_DIV, AD9528_CHANNEL_DIV, AD9528_CHANNEL_DIV,
AD9528_CHANNEL_DIV, AD9528_CHANNEL_DIV, AD9528_CHANNEL_DIV, AD9528_CHANNEL_DIV, AD9528_CHANNEL_DIV,
AD9528_CHANNEL_DIV, AD9528_CHANNEL_DIV, AD9528_CHANNEL_DIV, AD9528_CHANNEL_DIV
},
.outBufferCtrl = {
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0
},
.outAnalogDelay = {
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0
},
.outDigitalDelay = {
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0
},
.outChannelDiv = {
5,25,25,5,5,
5,5,5,5,5,
5,5,10,5
},
.outFrequency_Hz = {
200e6, 40e6, 40e6, 200e6, 200e6,
200e6, 200e6, 200e6, 200e6, 200e6,
200e6, 200e6, 100e6, 200e6
}
};
static ad9528sysrefSettings_t clockSysrefSettings = {
.sysrefRequestMethod = PIN,
.sysrefSource = INTERNAL,
.sysrefPinEdgeMode = LEVEL_ACTIVE_HIGH,
.sysrefPinBufferMode = DISABLED,
.sysrefPatternMode = CONTINUOUS,
.sysrefNshotMode = FOUR_PULSES,
.sysrefDivide = 256
};
static ad9528spiSettings_t clockSpiSettings = {
.chipSelectIndex = AD9528_SPI_CS, //chip select Index, not used
.writeBitPolarity = 0, //Write bit polarity
.longInstructionWord = 1, //16bit instruction word
.MSBFirst = 1, //MSB first
.CPHA = 0, //Clock phase
.CPOL = 0, //Clock polarity
.enSpiStreaming = 0, //uint8_t enSpiStreaming;
.autoIncAddrUp = 1, //uint8_t autoIncAddrUp;
.fourWireMode = 1 //uint8_t fourWireMode;
};
ad9528Init_t ad9528_default_init_param = {
/* SPI */
.spi_init = &ad9528_spi_init,
.gpio_init_resetb = &ad9528_gpio_resetb_init,
.gpio_init_sysref_req = &ad9528_gpio_sysref_req_init,
.spiSettings = &clockSpiSettings,
.pll1Settings = &clockPll1Settings,
.pll2Settings = &clockPll2Settings,
.outputSettings = &clockOutputSettings,
.sysrefSettings = &clockSysrefSettings
};
@@ -0,0 +1,46 @@
#include "dev_profile.h"
#include "spi.h"
#include "../config/app_config.h"
#include "../drivers/adc/ad9653/ad9653.h"
#include "../drivers/axi_core/spi_engine/spi_engine.h"
#include "../drivers/platform/xilinx_gpio.h"
static struct spi_engine_init_param spi_engine_param = {
.ref_clk_hz = AD9653_SPI_ENGINE_REF_CLK,
.type = SPI_ENGINE,
.spi_engine_baseaddr = AD9653_SPI_ENGINE_BASEADDR,
.cs_delay = AD9653_SPI_ENGINE_CS_DELAY,
.data_width = AD9653_SPI_ENGINE_DATA_WIDTH
};
static struct xil_gpio_init_param xil_gpio_param = {
.type = GPIO_PS,
.device_id = AD9653_GPIO_DEVICE_ID
};
static struct spi_init_param ad9653_spi_init = {
.device_id = AD9653_SPI_DEVICE_ID,
.max_speed_hz = AD9653_SPI_ENGINE_MAX_SPEED,
.mode = SPI_MODE_4,
.chip_select = AD9653_SPI_CS,
.platform_ops = &spi_eng_platform_ops,
.extra = &spi_engine_param
};
static struct gpio_init_param ad9653_gpio_resetb_init = {
.number = AD9653_POWR_DOWN,
.platform_ops = &xil_gpio_ops,
.extra = &xil_gpio_param
};
struct ad9653_init_param ad9653_default_init_param = {
/* SPI */
.spi_init = &ad9653_spi_init,
.gpio_pdwn = &ad9653_gpio_resetb_init
};
const uint32_t ad9653_default_config_len = 36;
const struct ad9653_config ad9653_default_config[] = {
// configuration
};
@@ -0,0 +1,72 @@
#include "dev_profile.h"
#include "spi.h"
#include "../config/app_config.h"
#include "../drivers/adc/ad9694/ad9694.h"
#include "../drivers/axi_core/spi_engine/spi_engine.h"
#include "../drivers/platform/xilinx_gpio.h"
static struct spi_engine_init_param spi_engine_param = {
.ref_clk_hz = AD9694_SPI_ENGINE_REF_CLK,
.type = SPI_ENGINE,
.spi_engine_baseaddr = AD9694_SPI_ENGINE_BASEADDR,
.cs_delay = AD9694_SPI_ENGINE_CS_DELAY,
.data_width = AD9694_SPI_ENGINE_DATA_WIDTH
};
//static struct xil_gpio_init_param xil_gpio_param = {
// .type = GPIO_PS,
// .device_id = AD9694_GPIO_DEVICE_ID
//};
static struct spi_init_param ad9694_spi_init = {
.device_id = AD9694_SPI_DEVICE_ID,
.max_speed_hz = AD9694_SPI_ENGINE_MAX_SPEED,
.mode = SPI_MODE_4,
.chip_select = AD9694_SPI_CS,
.platform_ops = &spi_eng_platform_ops,
.extra = &spi_engine_param
};
struct ad9694_init_param ad9694_default_init_param = {
/* SPI */
.spi_init = &ad9694_spi_init
};
const uint32_t ad9694_default_config_len = 36;
const struct ad9694_config ad9694_default_config[] = {
// reset
{0x0000, 0x81},
{0x1228, 0x4F}, // JESD204B start-up circuit reset
{0x1228, 0x0F}, // JESD204B start-up normal operation
{0x1222, 0x04}, // PLL calibration
{0x1222, 0x00}, // PLL normal operation
{0x1262, 0x08}, // PLL loss of lock control - Clear loss of lock
{0x1262, 0x00}, // PLL loss of lock control - Normal operation
// system clock
{0x0108, 0x00}, // Clock divider = 1 -> device clock = 368.64MHz
{0x0201, 0x00}, // Chip decimation ration = 1 -> full sample rate
// channel configuration
{0x0009, 0x03}, // ADC Pair AB & CD receive all spi command
{0x0571, 0x15}, // JESD204B map JTX Link Control 1
{0x056E, 0x00}, // JESD204B map PLL control, lane rate 6.75~13.5Gbps, actual = 7.3728Gbps
{0x0570, 0x49}, // JESD204B map JTX quick config: L=2 M=2 F=2
{0x058B, 0x01}, // JESD204B map JTX SCR L config: scrambler disabled, L=2
{0x0590, 0x2F}, // JESD204B map JTX Subclass & NP config: subclass 1, N' = 16
{0x058D, 0x1F}, // JESD204B map JTX K config: K = 32
{0x058F, 0x2D}, // JESD204B map JTX N config: CS = 0, N = 14
{0x0571, 0x14}, // JESD204B map JTX Link Control 1
{0x05B0, 0x00}, // SERDOUTx0, SERDOUTx1 power on
{0x0120, 0x0A}, // SYSREF COntrol: continuous mode, captured on falling edge
// fast detect control
{0x0040, 0x00}, // FD_B/FD_D, FD_A/FD_C function as Fast Detect B/D, A/C output
{0x0245, 0x01}, // Fine fast detect enabled
{0x0247, 0xFE}, // Channel map fast detect upper threshold LSB
{0x0248, 0x1F}, // Channel map fast detect upper threshold MSB, -> 8190
{0x0249, 0xA4}, // Channel map fast detect lower threshold LSB
{0x024A, 0x1F}, // Channel map fast detect lower threshold MSB, -> 8100
{0x024B, 0x80}, // Channel map fast detect dwell time LSB
{0x024C, 0x00} // Channel map fast detect dwell time MSB, -> 128
};
@@ -0,0 +1,57 @@
#ifndef _DEV_PROFILE_H_
#define _DEV_PROFILE_H_
#include "irq.h"
#include "error.h"
#include "../drivers/frequency/hmc7044/hmc7044.h"
#include "../drivers/frequency/ad9528/ad9528.h"
#include "../drivers/frequency/lmk04828/lmk04828.h"
#include "../drivers/frequency/lmx2594/lmx2594.h"
#include "../drivers/rf-transceiver/ad9361_reg/ad9361_reg.h"
#include "../drivers/rf-transceiver/ad9361/ad9361_api.h"
#include "../drivers/adc/ad9694/ad9694.h"
#include "../drivers/adc/ad9653/ad9653.h"
#include "../config/app_config.h"
// device parameters
extern struct irq_init_param intc_init_param;
extern struct timer_init_param apptimer_init_param;
// HMC7044
extern struct hmc7044_init_param hmc7044_default_init_param;
// AD9528
extern ad9528Init_t ad9528_default_init_param;
// LMK04828
extern struct lmk04828_init_param lmk04828_default_init_param;
extern const struct lmk04828_config lmk04828_default_config[];
extern const uint32_t lmk04828_default_config_len;
// LMX2594
extern struct lmx2594_init_param lmx2594_adc_init_param;
extern struct lmx2594_init_param lmx2594_dac_init_param;
extern const struct lmx2594_config lmx2594_default_config[];
extern const uint32_t lmx2594_default_config_len;
// AD9361
extern AD9361_InitParam ad9361_default_init_param;
extern AD9361_RXFIRConfig rx_fir_config;
extern AD9361_TXFIRConfig tx_fir_config;
extern struct ad9361_reg_init_param ad9361_1_reg_default_init_param;
extern struct ad9361_reg_init_param ad9361_2_reg_default_init_param;
uint32_t ad9361_1_reg_config(struct ad9361_reg_dev *dev);
uint32_t ad9361_2_reg_config(struct ad9361_reg_dev *dev);
// AD9653
extern struct ad9653_init_param ad9653_default_init_param;
extern const struct ad9653_config ad9653_default_config[];
extern const uint32_t ad9653_default_config_len;
// AD9694
extern struct ad9694_init_param ad9694_default_init_param;
extern const struct ad9694_config ad9694_default_config[];
extern const uint32_t ad9694_default_config_len;
#endif /* SRC_DEV_PROFILE_H_ */
@@ -0,0 +1,132 @@
#include "dev_profile.h"
#include "../config/app_config.h"
#include "../drivers/platform/xilinx_gpio.h"
#include "../drivers/axi_core/spi_engine/spi_engine.h"
#include "../drivers/frequency/hmc7044/hmc7044.h"
static struct spi_engine_init_param spi_engine_param = {
.ref_clk_hz = HMC7044_SPI_ENGINE_REF_CLK,
.type = SPI_ENGINE,
.spi_engine_baseaddr = HMC7044_SPI_ENGINE_BASEADDR,
.cs_delay = HMC7044_SPI_ENGINE_CS_DELAY,
.data_width = HMC7044_SPI_ENGINE_DATA_WIDTH
};
//static struct xil_gpio_init_param xil_gpio_param = {
// .type = GPIO_PS,
// .device_id = AD9361_GPIO_DEVICE_ID
//};
// hmc7044 spi settings
static struct spi_init_param hmc7044_spi_init_param = {
.device_id = HMC7044_SPI_DEVICE_ID,
.max_speed_hz = HMC7044_SPI_ENGINE_MAX_SPEED,
.mode = SPI_MODE_4,
.chip_select = HMC7044_SPI_CS_HMC7044,
.platform_ops = &spi_eng_platform_ops,
.extra = &spi_engine_param
};
// hmc7044 channel specifications
struct hmc7044_chan_spec hmc7044_chan_spec[4] = {
/* AD9361_XTAL */
{
.disable = 0,
.num = 3,
.divider = 100,
.coarse_delay = 0,
.fine_delay = 0,
.high_performance_mode_dis = true,
.start_up_mode_dynamic_enable = false,
.dynamic_driver_enable = false,
.output_control0_rb4_enable = true,
.force_mute_enable = false,
.driver_mode = CML,
.driver_impedance = INTERNAL_100OHM_PER_PIN,
.out_mux_mode = CHANNEL_DIV
},
/* FPGA_DAC_LOGIC_CLK */
{
.disable = 0,
.num = 4,
.divider = 10,
.coarse_delay = 0,
.fine_delay = 0,
.high_performance_mode_dis = true,
.start_up_mode_dynamic_enable = false,
.dynamic_driver_enable = false,
.output_control0_rb4_enable = true,
.force_mute_enable = false,
.driver_mode = CML,
.driver_impedance = INTERNAL_100OHM_PER_PIN,
.out_mux_mode = CHANNEL_DIV
},
/* B_AD9361_XTAL */
{
.disable = 0,
.num = 12,
.divider = 100,
.coarse_delay = 0,
.fine_delay = 0,
.high_performance_mode_dis = false,
.start_up_mode_dynamic_enable = false,
.dynamic_driver_enable = false,
.output_control0_rb4_enable = true,
.force_mute_enable = false,
.driver_mode = CML,
.driver_impedance = INTERNAL_100OHM_PER_PIN,
.out_mux_mode = CHANNEL_DIV
},
/* AD9361_RX_EXT_LO */
{
.disable = 0,
.num = 13,
.divider = 10,
.coarse_delay = 0,
.fine_delay = 0,
.high_performance_mode_dis = false,
.start_up_mode_dynamic_enable = false,
.dynamic_driver_enable = false,
.output_control0_rb4_enable = true,
.force_mute_enable = false,
.driver_mode = CML,
.driver_impedance = INTERNAL_100OHM_PER_PIN,
.out_mux_mode = CHANNEL_DIV
},
};
// hmc7044 default configurations
struct hmc7044_init_param hmc7044_default_init_param = {
.spi_init = &hmc7044_spi_init_param,
.clkin_freq = {0, 100000000, 0, 0},
.vcxo_freq = 100000000,
.pll2_freq = 2500000000,
.pll1_loop_bw = 200,
.sysref_timer_div = 1536,
.in_buf_mode = {
BUFFER_DISABLE,
ENABLE_AC_COUPLE | ENABLE_INTERNAL_TERM | BUFFER_ENABLE,
BUFFER_DISABLE,
BUFFER_DISABLE,
ENABLE_AC_COUPLE | ENABLE_INTERNAL_TERM | BUFFER_ENABLE
},
.gpi_ctrl = {
GPI_DISABLE,
GPI_DISABLE,
CHIP_SLEEP_MODE,
PULSE_GEN_REQUSET
},
.gpo_ctrl = {
PLL1_LOCK_DETECT | GPO_CMOS_MODE,
PLL2_LOCK_DETECT | GPO_CMOS_MODE,
GPO_DISABLE,
GPO_DISABLE
},
.num_channels = 4,
.pll1_ref_prio_ctrl = 0xE4,
.sync_pin_mode = SYNC_MULTICHIP,
.high_performance_mode_clock_dist_en = false,
.pulse_gen_mode = PULSE_ONE,
.channels = hmc7044_chan_spec
};
@@ -0,0 +1,14 @@
#include "dev_profile.h"
#include "irq.h"
#include "../config/app_config.h"
#include "../drivers/platform/xilinx_irq.h"
struct xil_irq_init_param xil_intc_init_param = {
.type = IRQ_PS
};
struct irq_init_param intc_init_param = {
.irq_ctrl_id = INTC_DEVICE_ID,
.platform_ops = &xil_irq_ops,
.extra = &xil_intc_init_param
};
@@ -0,0 +1,182 @@
#include "dev_profile.h"
#include "spi.h"
#include "../config/app_config.h"
#include "../drivers/frequency/lmk04828/lmk04828.h"
#include "../drivers/axi_core/spi_engine/spi_engine.h"
#include "../drivers/platform/xilinx_gpio.h"
static struct spi_engine_init_param spi_engine_param = {
.ref_clk_hz = LMK04828_SPI_ENGINE_REF_CLK,
.type = SPI_ENGINE,
.spi_engine_baseaddr = LMK04828_SPI_ENGINE_BASEADDR,
.cs_delay = LMK04828_SPI_ENGINE_CS_DELAY,
.data_width = LMK04828_SPI_ENGINE_DATA_WIDTH
};
//static struct xil_gpio_init_param xil_gpio_param = {
// .type = GPIO_PS,
// .device_id = LMK04828_GPIO_DEVICE_ID
//};
static struct spi_init_param lmk04828_spi_init = {
.device_id = LMK04828_SPI_DEVICE_ID,
.max_speed_hz = LMK04828_SPI_ENGINE_MAX_SPEED,
.mode = SPI_MODE_0,
.chip_select = LMK04828_SPI_CS,
.platform_ops = &spi_eng_platform_ops,
.extra = &spi_engine_param
};
struct lmk04828_init_param lmk04828_default_init_param = {
/* SPI */
.spi_init = &lmk04828_spi_init
};
const uint32_t lmk04828_default_config_len = 137;
const struct lmk04828_config lmk04828_default_config[] = {
// 192MHz
{0x0000, 0x90}, // [7] reset; [4] 3-wire mode disabled
{0x0000, 0x10}, // [7] normal operation; [4] 3-wire mode disabled
{0x0002, 0x00}, // [0] normal operation
{0x0003, 0x06}, // [7-0] product device type, read only, default: 6
{0x0004, 0xD0}, // [7-0] msb of product identifier, read only, default: 208
{0x0005, 0x5B}, // [7-0] lsb of product identifier, read only, default: 91
{0x0006, 0x00}, // [7-0] ic version identifier, read only, default: 32
{0x000C, 0x51}, // [7-0] msb of vendor identifier, read only, default: 81
{0x000D, 0x04}, // [7-0] lsb of vendor identifier, read only, default: 4
// device clock 0
{0x0100, 0x10}, // [6] output drive level (ODL); [5] input drive level (IDL); [4-0] device clock (DCLK) output divider
{0x0101, 0x55}, // DCLK: [7-4] output digital delay (DDLY) high count; [3-0] DDLY low count
{0x0102, 0x55},
{0x0103, 0x01}, // DCLK: [7-3] analog delay (ADLY) value, 25 ps per lsb; [2] ADLY input mux; [1-0] DCLK input mux
{0x0104, 0x22}, // [6] DCLK half step value; [5] SDCLK output MUX; [4-1] SDCLK DDLY; [0] SYSREF half step value
{0x0105, 0x00}, // SYSREF: [4] ADLY enable; [3:0] ADLY value, 600 ps + 150 ps per lsb
{0x0106, 0xF0}, // [7] DCLK DDLY enable; [6] DCLK glitchless half step enable; [5] DCLK glitchless ADLY enable; [4] DCLK ADLY enable; [3]: clock group enable; [2-1] SYSREF disable mode; [0]: SYSREF disable
{0x0107, 0x11}, // [7] SDCLK output polarity; [6-4] SDCLK output format; [3] DCLK output polarity; [2:0] DCLK output format
// device clock 2
{0x0108, 0x10}, // [6] output drive level (ODL); [5] input drive level (IDL); [4-0] device clock (DCLK) output divider
{0x0109, 0x55}, // DCLK: [7-4] output digital delay (DDLY) high count; [3-0] DDLY low count
{0x010A, 0x55},
{0x010B, 0x00}, // DCLK: [7-3] analog delay (ADLY) value, 25 ps per lsb; [2] ADLY input mux; [1-0] DCLK input mux
{0x010C, 0x22}, // [6] DCLK half step value; [5] SDCLK output MUX; [4-1] SDCLK DDLY; [0] SYSREF half step value
{0x010D, 0x00}, // SYSREF: [4] ADLY enable; [3:0] ADLY value, 600 ps + 150 ps per lsb
{0x010E, 0xF0}, // [7] DCLK DDLY enable; [6] DCLK glitchless half step enable; [5] DCLK glitchless ADLY enable; [4] DCLK ADLY enable; [3]: clock group enable; [2-1] SYSREF disable mode; [0]: SYSREF disable
{0x010F, 0x10}, // [7] SDCLK output polarity; [6-4] SDCLK output format; [3] DCLK output polarity; [2:0] DCLK output format
// device clock 4
{0x0110, 0x10}, // [6] output drive level (ODL); [5] input drive level (IDL); [4-0] device clock (DCLK) output divider
{0x0111, 0x55}, // DCLK: [7-4] output digital delay (DDLY) high count; [3-0] DDLY low count
{0x0112, 0x55},
{0x0113, 0x00}, // DCLK: [7-3] analog delay (ADLY) value, 25 ps per lsb; [2] ADLY input mux; [1-0] DCLK input mux
{0x0114, 0x22}, // [6] DCLK half step value; [5] SDCLK output MUX; [4-1] SDCLK DDLY; [0] SYSREF half step value
{0x0115, 0x00}, // SYSREF: [4] ADLY enable; [3:0] ADLY value, 600 ps + 150 ps per lsb
{0x0116, 0xF0}, // [7] DCLK DDLY enable; [6] DCLK glitchless half step enable; [5] DCLK glitchless ADLY enable; [4] DCLK ADLY enable; [3]: clock group enable; [2-1] SYSREF disable mode; [0]: SYSREF disable
{0x0117, 0x11}, // [7] SDCLK output polarity; [6-4] SDCLK output format; [3] DCLK output polarity; [2:0] DCLK output format
// device clock 6
{0x0118, 0x10}, // [6] output drive level (ODL); [5] input drive level (IDL); [4-0] device clock (DCLK) output divider
{0x0119, 0x55}, // DCLK: [7-4] output digital delay (DDLY) high count; [3-0] DDLY low count
{0x011A, 0x55},
{0x011B, 0x00}, // DCLK: [7-3] analog delay (ADLY) value, 25 ps per lsb; [2] ADLY input mux; [1-0] DCLK input mux
{0x011C, 0x02}, // [6] DCLK half step value; [5] SDCLK output MUX; [4-1] SDCLK DDLY; [0] SYSREF half step value
{0x011D, 0x00}, // SYSREF: [4] ADLY enable; [3:0] ADLY value, 600 ps + 150 ps per lsb
{0x011E, 0xF0}, // [7] DCLK DDLY enable; [6] DCLK glitchless half step enable; [5] DCLK glitchless ADLY enable; [4] DCLK ADLY enable; [3]: clock group enable; [2-1] SYSREF disable mode; [0]: SYSREF disable
{0x011F, 0x55}, // [7] SDCLK output polarity; [6-4] SDCLK output format; [3] DCLK output polarity; [2:0] DCLK output format
// device clock 8
{0x0120, 0x10}, // [6] output drive level (ODL); [5] input drive level (IDL); [4-0] device clock (DCLK) output divider
{0x0121, 0x55}, // DCLK: [7-4] output digital delay (DDLY) high count; [3-0] DDLY low count
{0x0122, 0x55},
{0x0123, 0x00}, // DCLK: [7-3] analog delay (ADLY) value, 25 ps per lsb; [2] ADLY input mux; [1-0] DCLK input mux
{0x0124, 0x22}, // [6] DCLK half step value; [5] SDCLK output MUX; [4-1] SDCLK DDLY; [0] SYSREF half step value
{0x0125, 0x00}, // SYSREF: [4] ADLY enable; [3:0] ADLY value, 600 ps + 150 ps per lsb
{0x0126, 0xF0}, // [7] DCLK DDLY enable; [6] DCLK glitchless half step enable; [5] DCLK glitchless ADLY enable; [4] DCLK ADLY enable; [3]: clock group enable; [2-1] SYSREF disable mode; [0]: SYSREF disable
{0x0127, 0x55}, // [7] SDCLK output polarity; [6-4] SDCLK output format; [3] DCLK output polarity; [2:0] DCLK output format
// device clock 10
{0x0128, 0x10}, // [6] output drive level (ODL); [5] input drive level (IDL); [4-0] device clock (DCLK) output divider
{0x0129, 0x55}, // DCLK: [7-4] output digital delay (DDLY) high count; [3-0] DDLY low count
{0x012A, 0x55},
{0x012B, 0x00}, // DCLK: [7-3] analog delay (ADLY) value, 25 ps per lsb; [2] ADLY input mux; [1-0] DCLK input mux
{0x012C, 0x22}, // [6] DCLK half step value; [5] SDCLK output MUX; [4-1] SDCLK DDLY; [0] SYSREF half step value
{0x012D, 0x00}, // SYSREF: [4] ADLY enable; [3:0] ADLY value, 600 ps + 150 ps per lsb
{0x012E, 0xF0}, // [7] DCLK DDLY enable; [6] DCLK glitchless half step enable; [5] DCLK glitchless ADLY enable; [4] DCLK ADLY enable; [3]: clock group enable; [2-1] SYSREF disable mode; [0]: SYSREF disable
{0x012F, 0x51}, // [7] SDCLK output polarity; [6-4] SDCLK output format; [3] DCLK output polarity; [2:0] DCLK output format
// device clock 12
{0x0130, 0x10}, // [6] output drive level (ODL); [5] input drive level (IDL); [4-0] device clock (DCLK) output divider
{0x0131, 0x55}, // DCLK: [7-4] output digital delay (DDLY) high count; [3-0] DDLY low count
{0x0132, 0x55},
{0x0133, 0x00}, // DCLK: [7-3] analog delay (ADLY) value, 25 ps per lsb; [2] ADLY input mux; [1-0] DCLK input mux
{0x0134, 0x22}, // [6] DCLK half step value; [5] SDCLK output MUX; [4-1] SDCLK DDLY; [0] SYSREF half step value
{0x0135, 0x00}, // SYSREF: [4] ADLY enable; [3:0] ADLY value, 600 ps + 150 ps per lsb
{0x0136, 0xF0}, // [7] DCLK DDLY enable; [6] DCLK glitchless half step enable; [5] DCLK glitchless ADLY enable; [4] DCLK ADLY enable; [3]: clock group enable; [2-1] SYSREF disable mode; [0]: SYSREF disable
{0x0137, 0x55}, // [7] SDCLK output polarity; [6-4] SDCLK output format; [3] DCLK output polarity; [2:0] DCLK output format
// clock distribution source
{0x0138, 0x20}, // [6-5] VCO mux; [4] OSCout mux; [3:0] OSCout format
{0x0139, 0x03}, // [2] SYSREF output mux; [1-0] SYSREF source
{0x013A, 0x0C}, // [4-0] SYSREF divider [12:8]
{0x013B, 0x00}, // [7-0] SYSREF divider [7:0]
{0x013C, 0x00}, // [4-0] SYSREF DDLY [12:8]
{0x013D, 0x08}, // [7-0] SYSREF DDLY [7:0]
{0x013E, 0x03}, // [1-0] SYSREF pulse count
{0x013F, 0x00}, // [4] pll2 mux; [3] pll1 mux; [2-1] feedback mux; [0] feedback mux enable
{0x0140, 0x0B}, // power-down control: [7] pll1; [6] vco_ldo; [5] vco; [4] OSCin; [3] individual SYSREF; [2] SYSREF; [1] SYSREF DDLY; [0] SYSREF pluse generator
{0x0141, 0x00}, // dynamic DDLY control
{0x0142, 0x00}, // dynamic DDLY step control
{0x0143, 0x10},
{0x0144, 0xFF},
{0x0145, 0x7F},
{0x0146, 0x12},
{0x0147, 0x1A},
{0x0148, 0x03},
{0x0149, 0x05},
{0x014A, 0x1B},
{0x014B, 0x16},
{0x014C, 0x00},
{0x014D, 0x00},
{0x014E, 0xC0},
{0x014F, 0x7F},
{0x0150, 0x03},
{0x0151, 0x02},
{0x0152, 0x00},
{0x0153, 0x00},
{0x0154, 0x78},
{0x0155, 0x00},
{0x0156, 0x7D},
{0x0157, 0x00},
{0x0158, 0x96},
{0x0159, 0x06},
{0x015A, 0x00},
{0x015B, 0xD4},
{0x015C, 0x20},
{0x015D, 0x00},
{0x015E, 0x00},
{0x015F, 0x3B},
{0x0160, 0x00},
{0x0161, 0x02},
{0x0162, 0x44},
{0x0163, 0x00},
{0x0164, 0x00},
{0x0165, 0x0C},
{0x0171, 0xAA},
{0x0172, 0x02},
{0x017C, 0x15},
{0x017D, 0x33},
{0x0166, 0x00},
{0x0167, 0x00},
{0x0168, 0x19},
{0x0169, 0x59},
{0x016A, 0x20},
{0x016B, 0x00},
{0x016C, 0x00},
{0x016D, 0x00},
{0x016E, 0x1B},
{0x0173, 0x00},
{0x0182, 0x00},
{0x0183, 0x00},
{0x0184, 0x00},
{0x0185, 0x00},
{0x0188, 0x00},
{0x0189, 0x00},
{0x018A, 0x00},
{0x018B, 0x00},
{0x1FFD, 0x00},
{0x1FFE, 0x00},
{0x1FFF, 0x53}
};
@@ -0,0 +1,181 @@
#include "dev_profile.h"
#include "spi.h"
#include "../config/app_config.h"
#include "../drivers/frequency/lmx2594/lmx2594.h"
#include "../drivers/axi_core/spi_engine/spi_engine.h"
#include "../drivers/platform/xilinx_gpio.h"
static struct spi_engine_init_param spi_engine_param = {
.ref_clk_hz = AD9653_SPI_ENGINE_REF_CLK,
.type = SPI_ENGINE,
.spi_engine_baseaddr = AD9653_SPI_ENGINE_BASEADDR,
.cs_delay = AD9653_SPI_ENGINE_CS_DELAY,
.data_width = AD9653_SPI_ENGINE_DATA_WIDTH
};
//static struct xil_gpio_init_param xil_gpio_param = {
// .type = GPIO_PS,
// .device_id = AD9653_GPIO_DEVICE_ID
//};
static struct spi_init_param lmx2594_adc_spi_init = {
.device_id = LMX2594_ADC_SPI_DEVICE_ID,
.max_speed_hz = LMX2594_ADC_SPI_ENGINE_MAX_SPEED,
.mode = SPI_MODE_0,
.chip_select = LMX2594_ADC_SPI_CS,
.platform_ops = &spi_eng_platform_ops,
.extra = &spi_engine_param
};
static struct spi_init_param lmx2594_dac_spi_init = {
.device_id = LMX2594_DAC_SPI_DEVICE_ID,
.max_speed_hz = LMX2594_DAC_SPI_ENGINE_MAX_SPEED,
.mode = SPI_MODE_0,
.chip_select = LMX2594_DAC_SPI_CS,
.platform_ops = &spi_eng_platform_ops,
.extra = &spi_engine_param
};
struct lmx2594_init_param lmx2594_adc_init_param = {
/* SPI */
.spi_init = &lmx2594_adc_spi_init
};
struct lmx2594_init_param lmx2594_dac_init_param = {
/* SPI */
.spi_init = &lmx2594_dac_spi_init
};
const uint32_t lmx2594_default_config_len = 110;
const struct lmx2594_config lmx2594_default_config[] = {
// 0 ~ 78: General configuration
// 79 ~ 106: Ramping configuration
// 107 ~ 112: Readback registers
// Recommended Initial Power-Up Sequence
// For the most reliable programming, TI recommends this procedure::
// 1. Apply power to device.
// 2. Program RESET = 1 to reset registers.
// 3. Program RESET = 0 to remove reset.
// 4. Program registers as shown in the register map in REVERSE order from highest to lowest.
// 5. Wait 10 ms.
// 6. Program register R0 one additional time with FCAL_EN = 1 to ensure that the VCO calibration runs from a stable state.
// Reset
{ 0, 0x0002},
// Remove Reset
{ 0, 0x0000},
// Reverse order programming
{106, 0x0000},
{105, 0x0021},
{104, 0x0000},
{103, 0xD555},
{102, 0x3F97},
{101, 0x0011},
{100, 0x0000},
{ 99, 0x2AAB},
{ 98, 0x01A0},
{ 97, 0x0888},
{ 96, 0x0000},
{ 95, 0x0000}, // fixed
{ 94, 0x0000}, // fixed
{ 93, 0x0000}, // fixed
{ 92, 0x0000}, // fixed
{ 91, 0x0000}, // fixed
{ 90, 0x0000}, // fixed
{ 89, 0x0000}, // fixed
{ 88, 0x0000}, // fixed
{ 87, 0x0000}, // fixed
{ 86, 0x5879},
{ 85, 0xEC58},
{ 84, 0x0001},
{ 83, 0x54C9},
{ 82, 0x2961},
{ 81, 0x0000},
{ 80, 0x4000},
{ 79, 0x001F},
{ 78, 0x0003}, // [8:1] VCO_CAPCTRL_STRT
{ 77, 0x0000}, // fixed
{ 76, 0x000C}, // fixed
{ 75, 0x0800}, // [10:6] CHDIV
{ 74, 0x0000}, // [11:6] JESD_DAC4_CTRL; [5:0] JESD_DAC3_CTRL
{ 73, 0x003F}, // [11:6] JESD_DAC2_CTRL; [5:0] JESD_DAC1_CTRL
{ 72, 0x0001}, // [10:0] SYSREF_DIV
{ 71, 0x0081}, // [7:5] SYSREF_DIV_PRE; [4] SYSREF_PULSE; [3] SYSREF_EN; [2] SYSREF_REPEAT
{ 70, 0xC350}, // [15:0] MASH_RST_COUNT
{ 69, 0x0000}, // [15:0] MASH_RST_COUNT
{ 68, 0x03E8}, // fixed
{ 67, 0x0000}, // fixed
{ 66, 0x01F4}, // fixed
{ 65, 0x0000}, // fixed
{ 64, 0x1388}, // fixed
{ 63, 0x0000}, // fixed
{ 62, 0x0322}, // fixed
{ 61, 0x00A8}, // fixed
{ 60, 0x0000}, // [15:0] LD_DLY
{ 59, 0x0001}, // [0] LD_TYPE
{ 58, 0x9001}, // [15] INPIN_IGNORE; [14] INPIN_HYST; [13:12] INPIN_LVL; [11:9] INPIN_FMT
{ 57, 0x0020}, // fixed
{ 56, 0x0000}, // fixed
{ 55, 0x0000}, // fixed
{ 54, 0x0000}, // fixed
{ 53, 0x0000}, // fixed
{ 52, 0x0820}, // fixed
{ 51, 0x0080}, // fixed
{ 50, 0x0000}, // fixed
{ 49, 0x4180}, // fixed
{ 48, 0x0300}, // fixed
{ 47, 0x0300}, // fixed
{ 46, 0x07FC}, // [1:0] OUTB_MUX
{ 45, 0xC0DF}, // [12:11] OUTA_MUX; [10:9] OUT_ISET; [5:0] OUTB_PWR
{ 44, 0x1AA3}, // [13:8] OUTA_PWR; [7] OUTB_PD; [6] OUTA_PD; [5] MASH_RESET_N; [2:0] MASH_ORDER
{ 43, 0x0000}, // [15:0] PLL_NUM
{ 42, 0x0000}, // [15:0] PLL_NUM
{ 41, 0x0000}, // [15:0] MASH_SEE
{ 40, 0x0000}, // [15:0] MASH_SEE
{ 39, 0x03E8}, // [15:0] PLL_DEN
{ 38, 0x0000}, // [15:0] PLL_DEN
{ 37, 0x0304}, // [37] MASH_SEED_EN; [13:8] PFD_DLY_SEL
{ 36, 0x0028}, // [15:0] PLL_N
{ 35, 0x0004}, // fixed
{ 34, 0x0000}, // [2:0] PLL_N
{ 33, 0x1E21}, // fixed
{ 32, 0x0393}, // fixed
{ 31, 0x43EC}, // [14] SEG1_EN
{ 30, 0x318C}, // fixed
{ 29, 0x318C}, // fixed
{ 28, 0x0488}, // fixed
{ 27, 0x0002}, // fixed
{ 26, 0x0DB0}, // fixed
{ 25, 0x0C2B}, // fixed
{ 24, 0x071A}, // fixed
{ 23, 0x007C}, // fixed
{ 22, 0x0001}, // fixed
{ 21, 0x0401}, // fixed
{ 20, 0xE048}, // [13:11] VCO_SEL. [10] VCO_SEL_FORCE
{ 19, 0x27B7}, // [7:0] VCO_CAPCTRL
{ 18, 0x0064}, // fixed
{ 17, 0x012C}, // [8:0] VCO_DACISET_STRT
{ 16, 0x0080}, // [8:0] VCO_DACISET
{ 15, 0x064F}, // fixed
{ 14, 0x1E70}, // [6:4] CPG
{ 13, 0x4000}, // fixed
{ 12, 0x5001}, // [11:0] PLL_R_PR
{ 11, 0x0018}, // [11:4] PLL_R
{ 10, 0x10D8}, // [11:7] MULT
{ 9, 0x0604}, // [12] OSC_2X
{ 8, 0x2000}, // [14] VCO_DACISET_FORCE; [11] VCO_CAPCTRL_FORCE
{ 7, 0x40B2}, // [14] OUT_FORCE
{ 6, 0xC802}, // fixed
{ 5, 0x00C8}, // fixed
{ 4, 0x0C43}, // [15:8] ACAL_CMP_DLY
{ 3, 0x0642}, // fixed
{ 2, 0x0500}, // fixed
{ 1, 0x0809}, // [2:0] CAL_CLK_DIV
{ 0, 0x2598}, // [15] RAMP_EN; [14] VCO_PHASE_SYNC; [9] OUT_MUTE; [8:7] FCAL_HPFD_ADJ; [6:5] FCAL_LPFD_ADJ; [3] FCAL_EN; [2] MUXOUT_LD_SEL; [1] RESET; [0] POWERDOWN
// one more time
{ 0, 0x2598}
};
@@ -0,0 +1,21 @@
#include "dev_profile.h"
#include "timer.h"
#include "../config/app_config.h"
#include "../drivers/platform/xilinx_timer.h"
struct xil_timer_init_param xil_apptimer_init_param = {
.active_tmr = 0,
#ifdef __aarch64__
.type = TIMER_PL
#else
.type = TIMER_PS
#endif
};
struct timer_init_param apptimer_init_param = {
.id = APPTIMER_DEVICE_ID,
.freq_hz = APP_TIMER_CLK_HZ,
.ticks_count = (APP_TIMER_CLK_HZ/10), //update log every 100ms
.platform_ops = &xil_timer_ops,
.extra = &xil_apptimer_init_param
};
@@ -0,0 +1,129 @@
/***************************************************************************//**
* @file ad9653.c
* @brief Implementation of AD9653 Driver.
* @author DBogdan ([email protected])
********************************************************************************
* Copyright 2014-2016(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 Files **********************************/
/******************************************************************************/
#include "ad9653.h"
#include <stdlib.h>
#include <stdio.h>
#include "../../../include/error.h"
/***************************************************************************//**
* @brief ad9653_read
*******************************************************************************/
int32_t ad9653_read(struct ad9653_dev *dev,
uint16_t reg_addr,
uint8_t *reg_data)
{
uint8_t tx_buf[2];
uint8_t rx_buf[1];
int32_t ret;
tx_buf[0] = 0x80 | (reg_addr >> 8);
tx_buf[1] = reg_addr & 0xFF;
ret = spi_write_and_read_3wire(dev->spi_desc,
tx_buf, rx_buf, 2, 1);
*reg_data = rx_buf[0];
return ret;
}
/***************************************************************************//**
* @brief ad9653_write
*******************************************************************************/
int32_t ad9653_write(struct ad9653_dev *dev,
uint16_t reg_addr,
uint8_t reg_data)
{
uint8_t buf[3];
int32_t ret;
buf[0] = reg_addr >> 8;
buf[1] = reg_addr & 0xFF;
buf[2] = reg_data;
ret = spi_write_and_read_3wire(dev->spi_desc,
buf, NULL, 3, 0);
return ret;
}
/***************************************************************************//**
* @brief ad9653_init
*******************************************************************************/
int32_t ad9653_init(struct ad9653_dev **device,
const struct ad9653_init_param *init_param)
{
int ret = SUCCESS;
struct ad9653_dev *dev;
dev = (struct ad9653_dev *)malloc(sizeof(*dev));
if (!dev)
return FAILURE;
/* SPI */
ret = spi_init(&dev->spi_desc, init_param->spi_init);
*device = dev;
return ret;
}
/***************************************************************************//**
* @brief Free the resources allocated by ad9653_setup().
*
* @param dev - The device structure.
*
* @return SUCCESS in case of success, negative error code otherwise.
*******************************************************************************/
int32_t ad9653_remove(struct ad9653_dev *dev)
{
int32_t ret;
ret = spi_remove(dev->spi_desc);
free(dev);
return ret;
}
@@ -0,0 +1,233 @@
/***************************************************************************//**
* @file ad9653.h
* @brief Header file of AD9653 Driver.
* @author DBogdan ([email protected])
********************************************************************************
* Copyright 2014-2016(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
*******************************************************************************/
#ifndef AD9653_H_
#define AD9653_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdint.h>
#include "delay.h"
#include "spi.h"
/******************************************************************************/
/********************** Macros and Constants Definitions **********************/
/******************************************************************************/
#define AD9694_REG_GLOBAL_MAP_SPI_CONF_A 0x0000
#define AD9694_REG_GLOBAL_MAP_SPI_CONF_B 0x0001
#define AD9694_REG_CH_MAP_CHIP_CONF 0x0002
#define AD9694_REG_PAIR_MAP_CHIP_TYPE 0x0003
#define AD9694_REG_PAIR_MAP_CHIP_ID_LSB 0x0004
#define AD9694_REG_PAIR_MAP_CHIP_GRADE 0x0006
#define AD9694_REG_PAIR_MAP_DEV_INDEX 0x0008
#define AD9694_REG_GLOBAL_MAP_PAIR_INDEX 0x0009
#define AD9694_REG_PAIR_MAP_SCRATCH_PAD 0x000A
#define AD9694_REG_PAIR_MAP_SPI_REVISION 0x000B
#define AD9694_REG_PAIR_MAP_VENDOR_ID_LSB 0x000C
#define AD9694_REG_PAIR_MAP_VENDOR_ID_MSB 0x000D
#define AD9694_REG_CH_MAP_CHIP_PD_PIN 0x003F
#define AD9694_REG_PAIR_MAP_CHIP_PIN_CTRL_1 0x0040
#define AD9694_REG_PAIR_MAP_CLK_DIV_CTRL 0x0108
#define AD9694_REG_CH_MAP_CLK_DIV_PHASE 0x0109
#define AD9694_REG_PAIR_MAP_CLK_DIV_SYSREF_CTRL 0x010A
#define AD9694_REG_PAIR_MAP_CLK_DELAY_CTRL 0x0110
#define AD9694_REG_CH_MAP_CLK_SUPER_FINE_DELAY 0x0111
#define AD9694_REG_CH_MAP_CLK_FINE_DELAY 0x0112
#define AD9694_REG_CLK_DETN_CTRL 0x011A
#define AD9694_REG_PAIR_MAP_CLK_STAT 0x011B
#define AD9694_REG_CLK_DCS_CTRL_1 0x011C
#define AD9694_REG_CLK_DCS_CTRL_2 0x011E
#define AD9694_REG_CLK_DCS_CTRL_3 0x011F
#define AD9694_REG_PAIR_MAP_SYSREF_CTRL_1 0x0120
#define AD9694_REG_PAIR_MAP_SYSREF_CTRL_2 0x0121
#define AD9694_REG_PAIR_MAP_SYSREF_CTRL_4 0x0123
#define AD9694_REG_PAIR_MAP_SYSREF_STAT_1 0x0128
#define AD9694_REG_PAIR_MAP_SYSREF_STAT_2 0x0129
#define AD9694_REG_PAIR_MAP_SYSREF_STAT_3 0x012A
#define AD9694_REG_PAIR_MAP_CHIP_SYNC 0x01FF
#define AD9694_REG_PAIR_MAP_CHIP_MODE 0x0200
#define AD9694_REG_PAIR_MAP_CHIP_DEC_RATIO 0x0201
#define AD9694_REG_CH_MAP_CUSTOM_OFFSET 0x0228
#define AD9694_REG_CH_MAP_FD_CTRL 0x0245
#define AD9694_REG_CH_MAP_FD_UT_LSB 0x0247
#define AD9694_REG_CH_MAP_FD_UT_MSB 0x0248
#define AD9694_REG_CH_MAP_FD_LT_LSB 0x0249
#define AD9694_REG_CH_MAP_FD_LT_MSB 0x024A
#define AD9694_REG_CH_MAP_FD_DWELL_TIME_LSB 0x024B
#define AD9694_REG_CH_MAP_FD_DWELL_TIME_MSB 0x024C
#define AD9694_REG_PAIR_MAP_SIG_MON_SYNC_CTRL 0x026F
#define AD9694_REG_CH_MAP_SIG_MON_CTRL 0x0270
#define AD9694_REG_CH_MAP_SIG_MON_PERIOD_0 0x0271
#define AD9694_REG_CH_MAP_SIG_MON_PERIOD_1 0x0272
#define AD9694_REG_CH_MAP_SIG_MON_PERIOD_2 0x0273
#define AD9694_REG_CH_MAP_SIG_MON_STAT_CTRL 0x0274
#define AD9694_REG_CH_MAP_SIG_MON_STAT_0 0x0275
#define AD9694_REG_CH_MAP_SIG_MON_STAT_1 0x0276
#define AD9694_REG_CH_MAP_SIG_MON_STAT_2 0x0277
#define AD9694_REG_CH_MAP_SIG_MON_STAT_FRAME_CNT 0x0278
#define AD9694_REG_CH_MAP_SIG_MON_SERIAL_FRAMER_CTRL 0x0279
#define AD9694_REG_SPORT_OVER_JESD204B_INPUT_SEL 0x027A
#define AD9694_REG_PAIR_MAP_DDC_SYNC_CTRL 0x0300
#define AD9694_REG_PAIR_MAP_DDC_0_CTRL 0x0310
#define AD9694_REG_PAIR_MAP_DDC_0_INPUT_SEL 0x0311
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_INC_0 0x0314
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_INC_1 0x0315
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_INC_2 0x0316
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_INC_3 0x0317
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_INC_4 0x0318
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_INC_5 0x031A
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_OFFSET_0 0x031D
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_OFFSET_1 0x031E
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_OFFSET_2 0x031F
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_OFFSET_3 0x0320
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_OFFSET_4 0x0321
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_OFFSET_5 0x0322
#define AD9694_REG_PAIR_MAP_DDC_0_TEST_ENABLE 0x0327
#define AD9694_REG_PAIR_MAP_DDC_1_CTRL 0x0330
#define AD9694_REG_PAIR_MAP_DDC_1_INPUT_SEL 0x0331
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_INC_0 0x0334
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_INC_1 0x0335
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_INC_2 0x0336
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_INC_3 0x0337
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_INC_4 0x0338
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_INC_5 0x033A
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_OFFSET_0 0x033D
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_OFFSET_1 0x033E
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_OFFSET_2 0x033F
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_OFFSET_3 0x0340
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_OFFSET_4 0x0341
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_OFFSET_5 0x0342
#define AD9694_REG_PAIR_MAP_DDC_1_TEST_ENABLE 0x0347
#define AD9694_REG_CH_MAP_TEST_MODE_CTRL 0x0550
#define AD9694_REG_PAIR_MAP_USER_PATTERN_1_LSB 0x0551
#define AD9694_REG_PAIR_MAP_USER_PATTERN_1_MSB 0x0552
#define AD9694_REG_PAIR_MAP_USER_PATTERN_2_LSB 0x0553
#define AD9694_REG_PAIR_MAP_USER_PATTERN_2_MSB 0x0554
#define AD9694_REG_PAIR_MAP_USER_PATTERN_3_LSB 0x0555
#define AD9694_REG_PAIR_MAP_USER_PATTERN_3_MSB 0x0556
#define AD9694_REG_PAIR_MAP_USER_PATTERN_4_LSB 0x0557
#define AD9694_REG_PAIR_MAP_USER_PATTERN_4_MSB 0x0558
#define AD9694_REG_PAIR_MAP_OUTPUT_CTRL_MODE_0 0x0559
#define AD9694_REG_PAIR_MAP_OUTPUT_CTRL_MODE_1 0x055A
#define AD9694_REG_PAIR_MAP_OUTPUT_SAMPLE_MODE 0x0561
#define AD9694_REG_PAIR_MAP_OUTPUT_CH_SEL 0x0564
#define AD9694_REG_JESD204B_MAP_PLL_CTRL 0x056E
#define AD9694_REG_JESD204B_MAP_PLL_STAT 0x056F
#define AD9694_REG_JESD204B_MAP_JTX_QUICK_CONF 0x0570
#define AD9694_REG_JESD204B_MAP_JTX_LINK_CTRL_1 0x0571
#define AD9694_REG_JESD204B_MAP_JTX_LINK_CTRL_2 0x0572
#define AD9694_REG_JESD204B_MAP_JTX_LINK_CTRL_3 0x0573
#define AD9694_REG_JESD204B_MAP_JTX_LINK_CTRL_4 0x0574
#define AD9694_REG_JESD204B_MAP_JTX_LMFC_OFFSET 0x0578
#define AD9694_REG_JESD204B_MAP_JTX_DID_CONF 0x0580
#define AD9694_REG_JESD204B_MAP_JTX_BID_CONF 0x0581
#define AD9694_REG_JESD204B_MAP_JTX_LID_0_CONF 0x0583
#define AD9694_REG_JESD204B_MAP_JTX_LID_1_CONF 0x0585
#define AD9694_REG_JESD204B_MAP_JTX_SCR_L_CONF 0x058B
#define AD9694_REG_JESD204B_MAP_JTX_F_CONF 0x058C
#define AD9694_REG_JESD204B_MAP_JTX_K_CONF 0x058D
#define AD9694_REG_JESD204B_MAP_JTX_M_CONF 0x058E
#define AD9694_REG_JESD204B_MAP_JTX_CS_N_CONF 0x058F
#define AD9694_REG_JESD204B_MAP_JTX_SUBCLASS_CONF 0x0590
#define AD9694_REG_JESD204B_MAP_JTX_S_CONF 0x0591
#define AD9694_REG_JESD204B_MAP_JTX_HD_CF_CONF 0x0592
#define AD9694_REG_JESD204B_MAP_JTX_CHECKSUM_0_CONF 0x05A0
#define AD9694_REG_JESD204B_MAP_JTX_CHECKSUM_1_CONF 0x05A1
#define AD9694_REG_SERDOUTX0_SERDOUTX1_LANE_PD 0x05B0
#define AD9694_REG_JESD204B_MAP_JTX_LANE_ASSIGN_1 0x05B2
#define AD9694_REG_JESD204B_MAP_JTX_LANE_ASSIGN_2 0x05B3
#define AD9694_REG_JESD204B_MAP_SERD_ADJUST_0 0x05C0
#define AD9694_REG_JESD204B_MAP_SERD_ADJUST_1 0x05C1
#define AD9694_REG_JESD204B_SER_PE_SEL_LANE_0 0x05C4
#define AD9694_REG_JESD204B_SER_PE_SEL_LANE_1 0x05C6
#define AD9694_REG_LARGE_DITHER_CTRL 0x0922
#define AD9694_REG_PLL_CAL 0x1222
#define AD9694_REG_JESD204B_STARTUP_CIRCUIT_RST 0x1228
#define AD9694_REG_PLL_LOSS_OF_LOCK_CTRL 0x1262
#define AD9694_REG_DC_OFFSET_CAL_CTRL 0x0701
#define AD9694_REG_DC_OFFSET_CAL_CTRL_2 0x073B
#define AD9694_REG_PAIR_MAP_VREF_CTRL 0x18A6
#define AD9694_REG_EXT_VCM_BUF_CTRL_1 0x18E0
#define AD9694_REG_EXT_VCM_BUF_CTRL_2 0x18E1
#define AD9694_REG_EXT_VCM_BUF_CTRL_3 0x18E2
#define AD9694_REG_EXT_VCM_BUF_CTRL 0x18E3
#define AD9694_REG_TEMP_DIODE_EXPORT 0x18E6
#define AD9694_REG_CH_MAP_ANALOG_INPUT_CTRL 0x1908
#define AD9694_REG_CH_MAP_INPUT_FULLSCALE_RANGE 0x1910
#define AD9694_REG_CH_MAP_BUF_CTRL_1 0x1A4C
#define AD9694_REG_CH_MAP_BUF_CTRL_2 0x1A4D
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
struct ad9653_dev {
/* SPI */
struct spi_desc *spi_desc;
struct gpio_desc *gpio_desc_pdwn;
};
struct ad9653_init_param {
/* SPI */
struct spi_init_param *spi_init;
struct gpio_init_param *gpio_pdwn;
};
struct ad9653_config {
uint16_t addr;
uint8_t value;
};
/******************************************************************************/
/************************ Functions Declarations ******************************/
/******************************************************************************/
int32_t ad9653_read(struct ad9653_dev *dev,
uint16_t reg_addr,
uint8_t *reg_data);
int32_t ad9653_write(struct ad9653_dev *dev,
uint16_t reg_addr,
uint8_t reg_data);
int32_t ad9653_init(struct ad9653_dev **device,
const struct ad9653_init_param *init_param);
int32_t ad9653_remove(struct ad9653_dev *dev);
#endif
@@ -0,0 +1,128 @@
/***************************************************************************//**
* @file ad9694.c
* @brief Implementation of AD9680 Driver.
* @author DBogdan ([email protected])
********************************************************************************
* Copyright 2014-2016(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 Files **********************************/
/******************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include "ad9694.h"
#include "../../../include/error.h"
/***************************************************************************//**
* @brief ad9694_read
*******************************************************************************/
int32_t ad9694_read(struct ad9694_dev *dev,
uint16_t reg_addr,
uint8_t *reg_data)
{
uint8_t tx_buf[2];
uint8_t rx_buf[1];
int32_t ret;
tx_buf[0] = 0x80 | (reg_addr >> 8);
tx_buf[1] = reg_addr & 0xFF;
ret = spi_write_and_read_3wire(dev->spi_desc,
tx_buf, rx_buf, 2, 1);
*reg_data = rx_buf[0];
return ret;
}
/***************************************************************************//**
* @brief ad9694_write
*******************************************************************************/
int32_t ad9694_write(struct ad9694_dev *dev,
uint16_t reg_addr,
uint8_t reg_data)
{
uint8_t buf[3];
int32_t ret;
buf[0] = reg_addr >> 8;
buf[1] = reg_addr & 0xFF;
buf[2] = reg_data;
ret = spi_write_and_read_3wire(dev->spi_desc,
buf, NULL, 3, 0);
return ret;
}
/***************************************************************************//**
* @brief ad9694_init
*******************************************************************************/
int32_t ad9694_init(struct ad9694_dev **device,
const struct ad9694_init_param *init_param)
{
int ret = SUCCESS;
struct ad9694_dev *dev;
dev = (struct ad9694_dev *)malloc(sizeof(*dev));
if (!dev)
return FAILURE;
/* SPI */
ret = spi_init(&dev->spi_desc, init_param->spi_init);
*device = dev;
return ret;
}
/***************************************************************************//**
* @brief Free the resources allocated by ad9694_setup().
*
* @param dev - The device structure.
*
* @return SUCCESS in case of success, negative error code otherwise.
*******************************************************************************/
int32_t ad9694_remove(struct ad9694_dev *dev)
{
int32_t ret;
ret = spi_remove(dev->spi_desc);
free(dev);
return ret;
}
@@ -0,0 +1,231 @@
/***************************************************************************//**
* @file ad9694.h
* @brief Header file of AD9694 Driver.
* @author DBogdan ([email protected])
********************************************************************************
* Copyright 2014-2016(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
*******************************************************************************/
#ifndef AD9694_H_
#define AD9694_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdint.h>
#include "delay.h"
#include "spi.h"
/******************************************************************************/
/********************** Macros and Constants Definitions **********************/
/******************************************************************************/
#define AD9694_REG_GLOBAL_MAP_SPI_CONF_A 0x0000
#define AD9694_REG_GLOBAL_MAP_SPI_CONF_B 0x0001
#define AD9694_REG_CH_MAP_CHIP_CONF 0x0002
#define AD9694_REG_PAIR_MAP_CHIP_TYPE 0x0003
#define AD9694_REG_PAIR_MAP_CHIP_ID_LSB 0x0004
#define AD9694_REG_PAIR_MAP_CHIP_GRADE 0x0006
#define AD9694_REG_PAIR_MAP_DEV_INDEX 0x0008
#define AD9694_REG_GLOBAL_MAP_PAIR_INDEX 0x0009
#define AD9694_REG_PAIR_MAP_SCRATCH_PAD 0x000A
#define AD9694_REG_PAIR_MAP_SPI_REVISION 0x000B
#define AD9694_REG_PAIR_MAP_VENDOR_ID_LSB 0x000C
#define AD9694_REG_PAIR_MAP_VENDOR_ID_MSB 0x000D
#define AD9694_REG_CH_MAP_CHIP_PD_PIN 0x003F
#define AD9694_REG_PAIR_MAP_CHIP_PIN_CTRL_1 0x0040
#define AD9694_REG_PAIR_MAP_CLK_DIV_CTRL 0x0108
#define AD9694_REG_CH_MAP_CLK_DIV_PHASE 0x0109
#define AD9694_REG_PAIR_MAP_CLK_DIV_SYSREF_CTRL 0x010A
#define AD9694_REG_PAIR_MAP_CLK_DELAY_CTRL 0x0110
#define AD9694_REG_CH_MAP_CLK_SUPER_FINE_DELAY 0x0111
#define AD9694_REG_CH_MAP_CLK_FINE_DELAY 0x0112
#define AD9694_REG_CLK_DETN_CTRL 0x011A
#define AD9694_REG_PAIR_MAP_CLK_STAT 0x011B
#define AD9694_REG_CLK_DCS_CTRL_1 0x011C
#define AD9694_REG_CLK_DCS_CTRL_2 0x011E
#define AD9694_REG_CLK_DCS_CTRL_3 0x011F
#define AD9694_REG_PAIR_MAP_SYSREF_CTRL_1 0x0120
#define AD9694_REG_PAIR_MAP_SYSREF_CTRL_2 0x0121
#define AD9694_REG_PAIR_MAP_SYSREF_CTRL_4 0x0123
#define AD9694_REG_PAIR_MAP_SYSREF_STAT_1 0x0128
#define AD9694_REG_PAIR_MAP_SYSREF_STAT_2 0x0129
#define AD9694_REG_PAIR_MAP_SYSREF_STAT_3 0x012A
#define AD9694_REG_PAIR_MAP_CHIP_SYNC 0x01FF
#define AD9694_REG_PAIR_MAP_CHIP_MODE 0x0200
#define AD9694_REG_PAIR_MAP_CHIP_DEC_RATIO 0x0201
#define AD9694_REG_CH_MAP_CUSTOM_OFFSET 0x0228
#define AD9694_REG_CH_MAP_FD_CTRL 0x0245
#define AD9694_REG_CH_MAP_FD_UT_LSB 0x0247
#define AD9694_REG_CH_MAP_FD_UT_MSB 0x0248
#define AD9694_REG_CH_MAP_FD_LT_LSB 0x0249
#define AD9694_REG_CH_MAP_FD_LT_MSB 0x024A
#define AD9694_REG_CH_MAP_FD_DWELL_TIME_LSB 0x024B
#define AD9694_REG_CH_MAP_FD_DWELL_TIME_MSB 0x024C
#define AD9694_REG_PAIR_MAP_SIG_MON_SYNC_CTRL 0x026F
#define AD9694_REG_CH_MAP_SIG_MON_CTRL 0x0270
#define AD9694_REG_CH_MAP_SIG_MON_PERIOD_0 0x0271
#define AD9694_REG_CH_MAP_SIG_MON_PERIOD_1 0x0272
#define AD9694_REG_CH_MAP_SIG_MON_PERIOD_2 0x0273
#define AD9694_REG_CH_MAP_SIG_MON_STAT_CTRL 0x0274
#define AD9694_REG_CH_MAP_SIG_MON_STAT_0 0x0275
#define AD9694_REG_CH_MAP_SIG_MON_STAT_1 0x0276
#define AD9694_REG_CH_MAP_SIG_MON_STAT_2 0x0277
#define AD9694_REG_CH_MAP_SIG_MON_STAT_FRAME_CNT 0x0278
#define AD9694_REG_CH_MAP_SIG_MON_SERIAL_FRAMER_CTRL 0x0279
#define AD9694_REG_SPORT_OVER_JESD204B_INPUT_SEL 0x027A
#define AD9694_REG_PAIR_MAP_DDC_SYNC_CTRL 0x0300
#define AD9694_REG_PAIR_MAP_DDC_0_CTRL 0x0310
#define AD9694_REG_PAIR_MAP_DDC_0_INPUT_SEL 0x0311
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_INC_0 0x0314
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_INC_1 0x0315
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_INC_2 0x0316
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_INC_3 0x0317
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_INC_4 0x0318
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_INC_5 0x031A
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_OFFSET_0 0x031D
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_OFFSET_1 0x031E
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_OFFSET_2 0x031F
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_OFFSET_3 0x0320
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_OFFSET_4 0x0321
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_OFFSET_5 0x0322
#define AD9694_REG_PAIR_MAP_DDC_0_TEST_ENABLE 0x0327
#define AD9694_REG_PAIR_MAP_DDC_1_CTRL 0x0330
#define AD9694_REG_PAIR_MAP_DDC_1_INPUT_SEL 0x0331
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_INC_0 0x0334
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_INC_1 0x0335
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_INC_2 0x0336
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_INC_3 0x0337
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_INC_4 0x0338
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_INC_5 0x033A
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_OFFSET_0 0x033D
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_OFFSET_1 0x033E
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_OFFSET_2 0x033F
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_OFFSET_3 0x0340
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_OFFSET_4 0x0341
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_OFFSET_5 0x0342
#define AD9694_REG_PAIR_MAP_DDC_1_TEST_ENABLE 0x0347
#define AD9694_REG_CH_MAP_TEST_MODE_CTRL 0x0550
#define AD9694_REG_PAIR_MAP_USER_PATTERN_1_LSB 0x0551
#define AD9694_REG_PAIR_MAP_USER_PATTERN_1_MSB 0x0552
#define AD9694_REG_PAIR_MAP_USER_PATTERN_2_LSB 0x0553
#define AD9694_REG_PAIR_MAP_USER_PATTERN_2_MSB 0x0554
#define AD9694_REG_PAIR_MAP_USER_PATTERN_3_LSB 0x0555
#define AD9694_REG_PAIR_MAP_USER_PATTERN_3_MSB 0x0556
#define AD9694_REG_PAIR_MAP_USER_PATTERN_4_LSB 0x0557
#define AD9694_REG_PAIR_MAP_USER_PATTERN_4_MSB 0x0558
#define AD9694_REG_PAIR_MAP_OUTPUT_CTRL_MODE_0 0x0559
#define AD9694_REG_PAIR_MAP_OUTPUT_CTRL_MODE_1 0x055A
#define AD9694_REG_PAIR_MAP_OUTPUT_SAMPLE_MODE 0x0561
#define AD9694_REG_PAIR_MAP_OUTPUT_CH_SEL 0x0564
#define AD9694_REG_JESD204B_MAP_PLL_CTRL 0x056E
#define AD9694_REG_JESD204B_MAP_PLL_STAT 0x056F
#define AD9694_REG_JESD204B_MAP_JTX_QUICK_CONF 0x0570
#define AD9694_REG_JESD204B_MAP_JTX_LINK_CTRL_1 0x0571
#define AD9694_REG_JESD204B_MAP_JTX_LINK_CTRL_2 0x0572
#define AD9694_REG_JESD204B_MAP_JTX_LINK_CTRL_3 0x0573
#define AD9694_REG_JESD204B_MAP_JTX_LINK_CTRL_4 0x0574
#define AD9694_REG_JESD204B_MAP_JTX_LMFC_OFFSET 0x0578
#define AD9694_REG_JESD204B_MAP_JTX_DID_CONF 0x0580
#define AD9694_REG_JESD204B_MAP_JTX_BID_CONF 0x0581
#define AD9694_REG_JESD204B_MAP_JTX_LID_0_CONF 0x0583
#define AD9694_REG_JESD204B_MAP_JTX_LID_1_CONF 0x0585
#define AD9694_REG_JESD204B_MAP_JTX_SCR_L_CONF 0x058B
#define AD9694_REG_JESD204B_MAP_JTX_F_CONF 0x058C
#define AD9694_REG_JESD204B_MAP_JTX_K_CONF 0x058D
#define AD9694_REG_JESD204B_MAP_JTX_M_CONF 0x058E
#define AD9694_REG_JESD204B_MAP_JTX_CS_N_CONF 0x058F
#define AD9694_REG_JESD204B_MAP_JTX_SUBCLASS_CONF 0x0590
#define AD9694_REG_JESD204B_MAP_JTX_S_CONF 0x0591
#define AD9694_REG_JESD204B_MAP_JTX_HD_CF_CONF 0x0592
#define AD9694_REG_JESD204B_MAP_JTX_CHECKSUM_0_CONF 0x05A0
#define AD9694_REG_JESD204B_MAP_JTX_CHECKSUM_1_CONF 0x05A1
#define AD9694_REG_SERDOUTX0_SERDOUTX1_LANE_PD 0x05B0
#define AD9694_REG_JESD204B_MAP_JTX_LANE_ASSIGN_1 0x05B2
#define AD9694_REG_JESD204B_MAP_JTX_LANE_ASSIGN_2 0x05B3
#define AD9694_REG_JESD204B_MAP_SERD_ADJUST_0 0x05C0
#define AD9694_REG_JESD204B_MAP_SERD_ADJUST_1 0x05C1
#define AD9694_REG_JESD204B_SER_PE_SEL_LANE_0 0x05C4
#define AD9694_REG_JESD204B_SER_PE_SEL_LANE_1 0x05C6
#define AD9694_REG_LARGE_DITHER_CTRL 0x0922
#define AD9694_REG_PLL_CAL 0x1222
#define AD9694_REG_JESD204B_STARTUP_CIRCUIT_RST 0x1228
#define AD9694_REG_PLL_LOSS_OF_LOCK_CTRL 0x1262
#define AD9694_REG_DC_OFFSET_CAL_CTRL 0x0701
#define AD9694_REG_DC_OFFSET_CAL_CTRL_2 0x073B
#define AD9694_REG_PAIR_MAP_VREF_CTRL 0x18A6
#define AD9694_REG_EXT_VCM_BUF_CTRL_1 0x18E0
#define AD9694_REG_EXT_VCM_BUF_CTRL_2 0x18E1
#define AD9694_REG_EXT_VCM_BUF_CTRL_3 0x18E2
#define AD9694_REG_EXT_VCM_BUF_CTRL 0x18E3
#define AD9694_REG_TEMP_DIODE_EXPORT 0x18E6
#define AD9694_REG_CH_MAP_ANALOG_INPUT_CTRL 0x1908
#define AD9694_REG_CH_MAP_INPUT_FULLSCALE_RANGE 0x1910
#define AD9694_REG_CH_MAP_BUF_CTRL_1 0x1A4C
#define AD9694_REG_CH_MAP_BUF_CTRL_2 0x1A4D
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
struct ad9694_dev {
/* SPI */
struct spi_desc *spi_desc;
};
struct ad9694_init_param {
/* SPI */
struct spi_init_param *spi_init;
};
struct ad9694_config {
uint16_t addr;
uint8_t value;
};
/******************************************************************************/
/************************ Functions Declarations ******************************/
/******************************************************************************/
int32_t ad9694_read(struct ad9694_dev *dev,
uint16_t reg_addr,
uint8_t *reg_data);
int32_t ad9694_write(struct ad9694_dev *dev,
uint16_t reg_addr,
uint8_t reg_data);
int32_t ad9694_init(struct ad9694_dev **device,
const struct ad9694_init_param *init_param);
int32_t ad9694_remove(struct ad9694_dev *dev);
#endif
@@ -0,0 +1,241 @@
/***************************************************************************//**
* @file gpio.c
* @brief Implementation of the GPIO Interface
* @author Antoniu Miclaus ([email protected])
********************************************************************************
* Copyright 2020(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 <inttypes.h>
#include "gpio.h"
#include <stdlib.h>
#include "error.h"
/******************************************************************************/
/************************ Functions Definitions *******************************/
/******************************************************************************/
/**
* @brief Obtain the GPIO decriptor.
* @param desc - The GPIO descriptor.
* @param param - GPIO Initialization parameters.
* @return 0 in case of success, -1 otherwise.
*/
int32_t gpio_get(struct gpio_desc **desc,
const struct gpio_init_param *param)
{
int32_t ret;
if (!param || !param->platform_ops)
return -EINVAL;
if (!param->platform_ops->gpio_ops_get)
return -ENOSYS;
ret = param->platform_ops->gpio_ops_get(desc, param);
if (ret)
return ret;
(*desc)->platform_ops = param->platform_ops;
return 0;
}
/**
* @brief Get the value of an optional GPIO.
* @param desc - The GPIO descriptor.
* @param param - GPIO Initialization parameters.
* @return 0 in case of success, -1 otherwise.
*/
int32_t gpio_get_optional(struct gpio_desc **desc,
const struct gpio_init_param *param)
{
int32_t ret;
if (!param || (param->number == -1)) {
*desc = NULL;
return 0;
}
if (!param->platform_ops)
return -EINVAL;
if (!param->platform_ops->gpio_ops_get_optional)
return -ENOSYS;
ret = param->platform_ops->gpio_ops_get_optional(desc, param);
if (ret)
return ret;
(*desc)->platform_ops = param->platform_ops;
return 0;
}
/**
* @brief Free the resources allocated by gpio_get().
* @param desc - The GPIO descriptor.
* @return 0 in case of success, -1 otherwise.
*/
int32_t gpio_remove(struct gpio_desc *desc)
{
if (desc) {
if (!desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->gpio_ops_remove)
return -ENOSYS;
return desc->platform_ops->gpio_ops_remove(desc);
}
return 0;
}
/**
* @brief Enable the input direction of the specified GPIO.
* @param desc - The GPIO descriptor.
* @return 0 in case of success, -1 otherwise.
*/
int32_t gpio_direction_input(struct gpio_desc *desc)
{
if (desc) {
if (!desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->gpio_ops_direction_input)
return -ENOSYS;
return desc->platform_ops->gpio_ops_direction_input(desc);
}
return 0;
}
/**
* @brief Enable the output direction of the specified GPIO.
* @param desc - The GPIO descriptor.
* @param value - The value.
* Example: GPIO_HIGH
* GPIO_LOW
* @return 0 in case of success, -1 otherwise.
*/
int32_t gpio_direction_output(struct gpio_desc *desc,
uint8_t value)
{
if (desc) {
if (!desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->gpio_ops_direction_output)
return -ENOSYS;
return desc->platform_ops->
gpio_ops_direction_output(desc, value);
}
return 0;
}
/**
* @brief Get the direction of the specified GPIO.
* @param desc - The GPIO descriptor.
* @param direction - The direction.
* Example: GPIO_OUT
* GPIO_IN
* @return 0 in case of success, -1 otherwise.
*/
int32_t gpio_get_direction(struct gpio_desc *desc,
uint8_t *direction)
{
if (desc) {
if (!desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->gpio_ops_get_direction)
return -ENOSYS;
return desc->platform_ops->
gpio_ops_get_direction(desc, direction);
}
return 0;
}
/**
* @brief Set the value of the specified GPIO.
* @param desc - The GPIO descriptor.
* @param value - The value.
* Example: GPIO_HIGH
* GPIO_LOW
* @return 0 in case of success, -1 otherwise.
*/
int32_t gpio_set_value(struct gpio_desc *desc,
uint8_t value)
{
if (desc) {
if (!desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->gpio_ops_set_value)
return -ENOSYS;
return desc->platform_ops->gpio_ops_set_value(desc, value);
}
return 0;
}
/**
* @brief Get the value of the specified GPIO.
* @param desc - The GPIO descriptor.
* @param value - The value.
* Example: GPIO_HIGH
* GPIO_LOW
* @return 0 in case of success, -1 otherwise.
*/
int32_t gpio_get_value(struct gpio_desc *desc,
uint8_t *value)
{
if (desc) {
if (!desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->gpio_ops_set_value)
return -ENOSYS;
return desc->platform_ops->gpio_ops_get_value(desc, value);
}
return 0;
}
@@ -0,0 +1,135 @@
/***************************************************************************//**
* @file i2c.c
* @brief Implementation of the I2C Interface
* @author Antoniu Miclaus ([email protected])
********************************************************************************
* Copyright 2020(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 <inttypes.h>
#include "i2c.h"
#include <stdlib.h>
#include "error.h"
/**
* @brief Initialize the I2C communication peripheral.
* @param desc - The I2C descriptor.
* @param param - The structure that contains the I2C parameters.
* @return 0 in case of success, -1 otherwise.
*/
int32_t i2c_init(struct i2c_desc **desc,
const struct i2c_init_param *param)
{
int32_t ret;
if (!param || !param->platform_ops)
return -EINVAL;
if (!param->platform_ops->i2c_ops_init)
return -ENOSYS;
ret = param->platform_ops->i2c_ops_init(desc, param);
if (ret)
return ret;
(*desc)->platform_ops = param->platform_ops;
return 0;
}
/**
* @brief Free the resources allocated by i2c_init().
* @param desc - The I2C descriptor.
* @return 0 in case of success, -1 otherwise.
*/
int32_t i2c_remove(struct i2c_desc *desc)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->i2c_ops_remove)
return -ENOSYS;
return desc->platform_ops->i2c_ops_remove(desc);
}
/**
* @brief I2C Write data to slave device.
* @param desc - The I2C descriptor.
* @param data - The buffer with the transmitted/received data.
* @param bytes_number - Number of bytes to write.
* @param stop_bit - Stop conditional control.
* Example: 0 - A stop condition will not be generated.
* 1 - A stop condition will be generated.
* @return 0 in case of success, -1 otherwise.
*/
int32_t i2c_write(struct i2c_desc *desc,
uint8_t *data,
uint8_t bytes_number,
uint8_t stop_bit)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->i2c_ops_write)
return -ENOSYS;
return desc->platform_ops->i2c_ops_write(desc, data, bytes_number,
stop_bit);
}
/**
* @brief I2C Read data from slave device.
* @param desc - The i2c descriptor.
* @param data - The buffer with the transmitted/received data.
* @param bytes_number - Number of bytes to read.
* @param stop_bit - Stop conditional control.
* Example: 0 - A stop condition will not be generated.
* 1 - A stop condition will be generated.
* @return 0 in case of success, -1 otherwise.
*/
int32_t i2c_read(struct i2c_desc *desc,
uint8_t *data,
uint8_t bytes_number,
uint8_t stop_bit)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->i2c_ops_read)
return -ENOSYS;
return desc->platform_ops->i2c_ops_read(desc, data, bytes_number,
stop_bit);
}
@@ -0,0 +1,229 @@
/***************************************************************************//**
* @file irq.c
* @brief Implementation of the IRQ Interface
* @author Andrei Porumb ([email protected])
********************************************************************************
* Copyright 2021(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 <inttypes.h>
#include <stdlib.h>
#include "irq.h"
#include "error.h"
/**
* @brief Initialize the IRQ interrupts.
* @param desc - The IRQ descriptor.
* @param param - The structure that contains the IRQ parameters.
* @return 0 in case of success, -1 otherwise.
*/
int32_t irq_ctrl_init(struct irq_ctrl_desc **desc,
const struct irq_init_param *param)
{
int32_t ret;
if (!param || !param->platform_ops)
return -EINVAL;
if (!param->platform_ops->init)
return -ENOSYS;
ret = param->platform_ops->init(desc, param);
if (ret)
return ret;
(*desc)->platform_ops = param->platform_ops;
return 0;
}
/**
* @brief Free the resources allocated by irq_ctrl_init().
* @param desc - The SPI descriptor.
* @return 0 in case of success, -1 otherwise.
*/
int32_t irq_ctrl_remove(struct irq_ctrl_desc *desc)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->remove)
return -ENOSYS;
return desc->platform_ops->remove(desc);
}
/**
* @brief Register a callback to handle the irq events.
* @param desc - The IRQ controller descriptor.
* @param irq_id - Interrupt identifier.
* @param callback - Callback descriptor - platform specific type.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t irq_register_callback(struct irq_ctrl_desc *desc,
uint32_t irq_id,
struct callback_desc *callback)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->register_callback)
return -ENOSYS;
return desc->platform_ops->register_callback(desc, irq_id, callback);
}
/**
* @brief Unregisters a generic IRQ handling function.
* @param desc - The IRQ controller descriptor.
* @param irq_id - Interrupt identifier.
* @param callback - Callback descriptor - platform specific type.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t irq_unregister_callback(struct irq_ctrl_desc *desc,
uint32_t irq_id,
struct callback_desc *callback)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->unregister_callback)
return -ENOSYS;
return desc->platform_ops->unregister_callback(desc, irq_id, callback);
}
/**
* @brief Enable global interrupts.
* @return 0 in case of success, -1 otherwise.
*/
int32_t irq_global_enable(struct irq_ctrl_desc *desc)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->global_enable)
return -ENOSYS;
return desc->platform_ops->global_enable(desc);
}
/**
* @brief Disable global interrupts.
* @return 0 in case of success, -1 otherwise.
*/
int32_t irq_global_disable(struct irq_ctrl_desc *desc)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->global_disable)
return -ENOSYS;
return desc->platform_ops->global_disable(desc);
}
/**
* @brief Set interrupt trigger level.
* @param desc - The IRQ controller descriptor.
* @param irq_id - Interrupt identifier.
* @param trig - New trigger level for the interrupt.
* @return 0 in case of success, -1 otherwise.
*/
int32_t irq_trigger_level_set(struct irq_ctrl_desc *desc,
uint32_t irq_id,
enum irq_trig_level trig)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if(!desc->platform_ops->trigger_level_set)
return -ENOSYS;
return desc->platform_ops->trigger_level_set(desc, irq_id, trig);
}
/**
* @brief Enable specific interrupt.
* @param desc - The IRQ controller descriptor.
* @param irq_id - Interrupt identifier.
* @return 0 in case of success, -1 otherwise.
*/
int32_t irq_enable(struct irq_ctrl_desc *desc, uint32_t irq_id)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->enable)
return -ENOSYS;
return desc->platform_ops->enable(desc, irq_id);
}
/**
* @brief Disable specific interrupt.
* @param desc - The IRQ controller descriptor.
* @param irq_id - Interrupt identifier.
* @return 0 in case of success, -1 otherwise.
*/
int32_t irq_disable(struct irq_ctrl_desc *desc, uint32_t irq_id)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->disable)
return -ENOSYS;
return desc->platform_ops->disable(desc, irq_id);
}
/**
* @brief Set the priority for an interrupt.
* @param desc - The IRQ controller descriptor.
* @param irq_id - Interrupt identifier.
* @param priority_level - The priority level of the interrupt.
* @return 0 in case of success, negative errno error codes.
*/
int32_t irq_set_priority(struct irq_ctrl_desc *desc,
uint32_t irq_id,
uint32_t priority_level)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->set_priority)
return -ENOSYS;
return desc->platform_ops->set_priority(desc, irq_id, priority_level);
}
@@ -0,0 +1,161 @@
/***************************************************************************//**
* @file spi.c
* @brief Implementation of the SPI Interface
* @author Antoniu Miclaus ([email protected])
********************************************************************************
* Copyright 2020(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 <inttypes.h>
#include "spi.h"
#include <stdlib.h>
#include "error.h"
/**
* @brief Initialize the SPI communication peripheral.
* @param desc - The SPI descriptor.
* @param param - The structure that contains the SPI parameters.
* @return 0 in case of success, -1 otherwise.
*/
int32_t spi_init(struct spi_desc **desc,
const struct spi_init_param *param)
{
int32_t ret;
if (!param || !param->platform_ops)
return -EINVAL;
if (!param->platform_ops->init)
return -ENOSYS;
ret = param->platform_ops->init(desc, param);
if (ret)
return ret;
(*desc)->platform_ops = param->platform_ops;
(*desc)->parent = param->parent;
return 0;
}
/**
* @brief Free the resources allocated by spi_init().
* @param desc - The SPI descriptor.
* @return 0 in case of success, -1 otherwise.
*/
int32_t spi_remove(struct spi_desc *desc)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->remove)
return -ENOSYS;
return desc->platform_ops->remove(desc);
}
/**
* @brief Write and read data to/from SPI.
* @param desc - The SPI descriptor.
* @param data - The buffer with the transmitted/received data.
* @param bytes_number - Number of bytes to write/read.
* @return 0 in case of success, -1 otherwise.
*/
int32_t spi_write_and_read(struct spi_desc *desc,
uint8_t *data,
uint16_t bytes_number)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->write_and_read)
return -ENOSYS;
return desc->platform_ops->write_and_read(desc, data, bytes_number);
}
/**
* @brief Write and read data to/from SPI in 3 wire mode.
* @param desc - The SPI descriptor.
* @param write_data - The buffer with the transmitted data.
* @param read_data - The buffer with the received data.
* @param write_bytes_number - Number of bytes to write.
* @param read_bytes_number - Number of bytes to read.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t spi_write_and_read_3wire(struct spi_desc *desc,
uint8_t *write_data,
uint8_t *read_data,
uint16_t write_bytes_number,
uint16_t read_bytes_number)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->write_and_read_3wire)
return -ENOSYS;
return desc->platform_ops->write_and_read_3wire(desc, write_data, read_data,
write_bytes_number, read_bytes_number);
}
/**
* @brief Iterate over head list and send all spi messages
* @param desc - The SPI descriptor.
* @param msgs - Array of messages.
* @param len - Number of messages in the array.
* @return 0 in case of success, negativ error code otherwise.
*/
int32_t spi_transfer(struct spi_desc *desc,
struct spi_msg *msgs,
uint32_t len)
{
int32_t ret;
uint32_t i;
if (!desc || !desc->platform_ops)
return -EINVAL;
if (desc->platform_ops->transfer)
return desc->platform_ops->transfer(desc, msgs, len);
for (i = 0; i < len; i++) {
if (msgs[i].rx_buff != msgs[i].tx_buff || !msgs[i].tx_buff)
return -EINVAL;
ret = spi_write_and_read(desc, msgs[i].rx_buff,
msgs[i].bytes_number);
if (IS_ERR_VALUE(ret))
return ret;
}
return 0;
}
@@ -0,0 +1,211 @@
/***************************************************************************//**
* @file timer.c
* @brief Implementation of the timer Interface
* @author RBolboac ([email protected])
********************************************************************************
* Copyright 2022(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 Files **********************************/
/******************************************************************************/
#include "error.h"
#include "timer.h"
/******************************************************************************/
/************************ Functions Definitions *******************************/
/******************************************************************************/
/**
* @brief Initialize hardware timer and the handler structure associated with
* it.
* @param [out] desc - Pointer to the reference of the device handler.
* @param [in] param - Initialization structure.
* @return 0 in case of success, negative error code otherwise
*/
int32_t timer_init(struct timer_desc **desc,
struct timer_init_param *param)
{
int32_t ret;
if (!param || !param->platform_ops)
return -EINVAL;
if (!param->platform_ops->init)
return -ENOSYS;
ret = param->platform_ops->init(desc, param);
if (ret)
return ret;
(*desc)->platform_ops = param->platform_ops;
return 0;
}
/**
* @brief Free the memory allocated by timer_init().
* @param [in] desc - Pointer to the device handler.
* @return 0 in case of success, negative error code otherwise
*/
int32_t timer_remove(struct timer_desc *desc)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->remove)
return -ENOSYS;
return desc->platform_ops->remove(desc);
}
/**
* @brief Start a timer.
* @param [in] desc - Pointer to the device handler.
* @return 0 in case of success, negative error code otherwise
*/
int32_t timer_start(struct timer_desc *desc)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->start)
return -ENOSYS;
return desc->platform_ops->start(desc);
}
/**
* @brief Stop a timer from counting.
* @param [in] desc - Pointer to the device handler.
* @return 0 in case of success, negative error code otherwise
*/
int32_t timer_stop(struct timer_desc *desc)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->stop)
return -ENOSYS;
return desc->platform_ops->stop(desc);
}
/**
* @brief Get the value of the counter register for the timer.
* @param [in] desc - Pointer to the device handler.
* @param [out] counter - Pointer to the counter value.
* @return 0 in case of success, error code otherwise.
*/
int32_t timer_counter_get(struct timer_desc *desc,
uint32_t *counter)
{
if (!desc || !desc->platform_ops || !counter)
return -EINVAL;
if (!desc->platform_ops->counter_get)
return -ENOSYS;
return desc->platform_ops->counter_get(desc, counter);
}
/**
* @brief Set the timer counter register value.
* @param [in] desc - Pointer to the device handler.
* @param [in] new_val - The new value of the counter register.
* @return 0 in case of success, error code otherwise.
*/
int32_t timer_counter_set(struct timer_desc *desc, uint32_t new_val)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->counter_set)
return -ENOSYS;
return desc->platform_ops->counter_set(desc, new_val);
}
/**
* @brief Get the timer clock frequency.
* @param [in] desc - Pointer to the device handler.
* @param [out] freq_hz - The value in Hz of the timer clock.
* @return 0 in case of success, error code otherwise.
*/
int32_t timer_count_clk_get(struct timer_desc *desc,
uint32_t *freq_hz)
{
if (!desc || !desc->platform_ops || !freq_hz)
return -EINVAL;
if (!desc->platform_ops->count_clk_get)
return -ENOSYS;
return desc->platform_ops->count_clk_get(desc, freq_hz);
}
/**
* @brief Set the timer clock frequency.
* @param [in] desc - Pointer to the device handler.
* @param [in] freq_hz - The value in Hz of the new timer clock.
* @return 0 in case of success, error code otherwise.
*/
int32_t timer_count_clk_set(struct timer_desc *desc,
uint32_t freq_hz)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->count_clk_set)
return -ENOSYS;
return desc->platform_ops->count_clk_set(desc, freq_hz);
}
/**
* @brief Get the elapsed time in nsec for the timer.
* @param [in] desc - Pointer to the device handler.
* @param [in] elapsed_time - The elapsed time in nsec.
* @return 0 in case of success, error code otherwise.
*/
int32_t timer_get_elapsed_time_nsec(struct timer_desc *desc,
uint64_t *elapsed_time)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->get_elapsed_time_nsec)
return -ENOSYS;
return desc->platform_ops->get_elapsed_time_nsec(desc, elapsed_time);
}
@@ -0,0 +1,111 @@
/***************************************************************************//**
* @file trng.c
* @brief Implementation of the TRNG Interface
* @author Antoniu Miclaus ([email protected])
********************************************************************************
* Copyright 2023(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 Files **********************************/
/******************************************************************************/
#include <inttypes.h>
#include "trng.h"
#include <stdlib.h>
#include "error.h"
/******************************************************************************/
/************************ Functions Definitions *******************************/
/******************************************************************************/
/**
* @brief Initialize the TRNG.
* @param desc - The TRNG descriptor.
* @param param - The structure that contains the TRNG parameters.
* @return 0 in case of success, -1 otherwise.
*/
int trng_init(struct trng_desc **desc,
const struct trng_init_param *param)
{
int ret;
if (!param || !param->platform_ops)
return -EINVAL;
if (!param->platform_ops->init)
return -ENOSYS;
ret = param->platform_ops->init(desc, param);
if (ret)
return ret;
(*desc)->platform_ops = param->platform_ops;
return 0;
}
/**
* @brief Free the resources allocated by trng_init().
* @param desc - The TRNG descriptor.
* @return 0 in case of success, -1 otherwise.
*/
int trng_remove(struct trng_desc *desc)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->remove)
return -ENOSYS;
return desc->platform_ops->remove(desc);
}
/**
* @brief Fill buffer with rng data.
* @param desc - The TRNG descriptor.
* @param buff - Buffer to be filled
* @param len - Size of the buffer
* @return 0 in case of success, -1 otherwise.
*/
int trng_fill_buffer(struct trng_desc *desc, uint8_t *buff,
uint32_t len)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->fill_buffer)
return -ENOSYS;
return desc->platform_ops->fill_buffer(desc, buff, len);
}
@@ -0,0 +1,547 @@
/*******************************************************************************
* @file axi_dmac.c
* @brief Driver for the Analog Devices AXI-DMAC core.
* @author DBogdan ([email protected])
********************************************************************************
* Copyright 2018(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 Files **********************************/
/******************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include "axi_io.h"
#include "error.h"
#include "delay.h"
#include "axi_dmac.h"
/*******************************************************************************
* @brief ISR for dev to mem DMA transfer. It computes the next transfer params,
* if any, and sets the transfer structure fields accordingly.
*
* @param instance - the instance that triggered the ISR.
*
* @return None.
*******************************************************************************/
void axi_dmac_dev_to_mem_isr(void *instance)
{
struct axi_dmac *dmac = (struct axi_dmac *)instance;
uint32_t burst_size;
uint32_t reg_val;
/* Get interrupt sources and clear interrupts. */
axi_dmac_read(dmac, AXI_DMAC_REG_IRQ_PENDING, &reg_val);
axi_dmac_write(dmac, AXI_DMAC_REG_IRQ_PENDING, reg_val);
if (reg_val & AXI_DMAC_IRQ_SOT) {
if (dmac->remaining_size) {
/* See if remaining size is bigger than max transfer size and
* set burst size. */
if (dmac->remaining_size > dmac->max_length) {
burst_size = dmac->max_length;
} else {
burst_size = dmac->remaining_size - 1;
}
/* The current transfer was started; set up the new one. */
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_ADDRESS, dmac->next_dest_addr);
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_STRIDE, 0x0);
axi_dmac_write(dmac, AXI_DMAC_REG_X_LENGTH, burst_size);
axi_dmac_write(dmac, AXI_DMAC_REG_Y_LENGTH, 0x0);
/* Compute size of the next transfer. */
dmac->remaining_size = dmac->remaining_size - (burst_size + 1);
/* Address must advance with +1 since the DMAC writes X_LENGTH+1. */
dmac->next_dest_addr = dmac->next_dest_addr + (burst_size + 1);
/* Trigger the next transfer. */
axi_dmac_write(dmac, AXI_DMAC_REG_TRANSFER_SUBMIT, AXI_DMAC_TRANSFER_SUBMIT);
}
}
if (reg_val & AXI_DMAC_IRQ_EOT) {
if (!dmac->remaining_size) {
dmac->transfer.transfer_done = true;
dmac->next_dest_addr = 0;
}
}
}
/*******************************************************************************
* @brief ISR for mem DMA to dev transfer. It computes the next transfer params,
* if any, and sets the transfer structure fields accordingly.
*
* @param instance - the instance that triggered the ISR.
*
* @return None.
*******************************************************************************/
void axi_dmac_mem_to_dev_isr(void *instance)
{
struct axi_dmac *dmac = (struct axi_dmac *)instance;
uint32_t burst_size;
uint32_t reg_val;
/* Get interrupt sources and clear interrupts. */
axi_dmac_read(dmac, AXI_DMAC_REG_IRQ_PENDING, &reg_val);
axi_dmac_write(dmac, AXI_DMAC_REG_IRQ_PENDING, reg_val);
if (reg_val & AXI_DMAC_IRQ_SOT) {
if ((dmac->transfer.cyclic == CYCLIC) &&
(dmac->next_src_addr >= (dmac->init_addr + dmac->transfer.size - 1))) {
dmac->remaining_size = dmac->transfer.size;
dmac->next_src_addr = dmac->init_addr;
}
if (dmac->remaining_size) {
/** See if remaining size is bigger than max transfer size and
* set burst size. */
if (dmac->remaining_size > dmac->max_length) {
burst_size = dmac->max_length;
} else {
burst_size = dmac->remaining_size - 1;
}
/* The current transfer was started; set up the new one. */
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_ADDRESS, dmac->next_src_addr);
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_STRIDE, 0x0);
axi_dmac_write(dmac, AXI_DMAC_REG_X_LENGTH, burst_size);
axi_dmac_write(dmac, AXI_DMAC_REG_Y_LENGTH, 0x0);
/* Compute parameters for the next transfer. */
dmac->remaining_size = dmac->remaining_size - (burst_size + 1);
/* Address must advance with +1 since the DMAC writes X_LENGTH+1. */
dmac->next_src_addr = dmac->next_src_addr + (burst_size + 1);
/* Trigger the current transfer */
axi_dmac_write(dmac, AXI_DMAC_REG_TRANSFER_SUBMIT, AXI_DMAC_TRANSFER_SUBMIT);
}
}
if (reg_val & AXI_DMAC_IRQ_EOT) {
if ((!dmac->remaining_size) && (dmac->transfer.cyclic != CYCLIC)) {
dmac->transfer.transfer_done = true;
dmac->next_src_addr = 0;
}
}
}
/*******************************************************************************
* @brief ISR for mem DMA to mem DMA transfer. It computes the next transfer
* params, if any, and sets the transfer structure fields accordingly.
*
* @param instance - the instance that triggered the ISR.
*
* @return None.
*******************************************************************************/
void axi_dmac_mem_to_mem_isr(void *instance)
{
struct axi_dmac *dmac = (struct axi_dmac *)instance;
uint32_t burst_size;
uint32_t reg_val;
/* Get interrupt sources and clear interrupts. */
axi_dmac_read(dmac, AXI_DMAC_REG_IRQ_PENDING, &reg_val);
axi_dmac_write(dmac, AXI_DMAC_REG_IRQ_PENDING, reg_val);
if (reg_val & AXI_DMAC_IRQ_SOT) {
if (dmac->remaining_size) {
/** See if remaining size is bigger than max transfer size and
* set burst size. */
if (dmac->remaining_size > dmac->max_length) {
burst_size = dmac->max_length;
} else {
burst_size = dmac->remaining_size - 1;
}
/* The current transfer was started; set up the new one. */
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_ADDRESS, dmac->next_src_addr);
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_STRIDE, 0x0);
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_ADDRESS, dmac->next_dest_addr);
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_STRIDE, 0x0);
axi_dmac_write(dmac, AXI_DMAC_REG_X_LENGTH, burst_size);
axi_dmac_write(dmac, AXI_DMAC_REG_Y_LENGTH, 0x0);
/* Compute parameters for the next transfer. */
dmac->remaining_size = dmac->remaining_size - (burst_size + 1);
/* Address must advance with +1 since the DMAC writes X_LENGTH+1. */
dmac->next_src_addr = dmac->next_src_addr + (burst_size + 1);
dmac->next_dest_addr = dmac->next_dest_addr + (burst_size + 1);
/* If transfer finished advance src address so that transfer_done can be set*/
if (!dmac->remaining_size) {
dmac->next_src_addr = dmac->next_src_addr + (burst_size + 1);
}
/* Trigger the current transfer */
axi_dmac_write(dmac, AXI_DMAC_REG_TRANSFER_SUBMIT, AXI_DMAC_TRANSFER_SUBMIT);
}
}
if (reg_val & AXI_DMAC_IRQ_EOT) {
if (!dmac->remaining_size) {
if(dmac->next_src_addr > (dmac->init_addr + dmac->transfer.size)) {
dmac->transfer.transfer_done = true;
dmac->next_src_addr = 0;
dmac->next_dest_addr = 0;
}
}
}
}
/*******************************************************************************
* @brief Wrapper for AXI IO through UIO/devmem read function.
*
* @param dmac - DMAC istance containing UIO index (/dev/uioX)/base address.
* @param reg_addr - Address to read from.
* @param reg_data - Location where read data will be stored.
*
* @return 0 - success.
*******************************************************************************/
int32_t axi_dmac_read(struct axi_dmac *dmac,
uint32_t reg_addr,
uint32_t *reg_data)
{
axi_io_read(dmac->base, reg_addr, reg_data);
return 0;
}
/*******************************************************************************
* @brief Wrapper for AXI IO through UIO/devmem wrrite function.
*
* @param dmac - DMAC istance containing UIO index (/dev/uioX)/base address.
* @param reg_addr - Address to write to.
* @param reg_data - Data to be written.
*
* @return 0 - success.
*******************************************************************************/
int32_t axi_dmac_write(struct axi_dmac *dmac,
uint32_t reg_addr,
uint32_t reg_data)
{
axi_io_write(dmac->base, reg_addr, reg_data);
return 0;
}
/*******************************************************************************
* @brief Get transfer status (value of dmac->transfer.transfer_done flag).
*
* @note This function should not be used if DMA IRQ is not used.
*
* @param dmac - DMAC istance.
* @param rdy - Transfer status (0 - not ready, 1 - ready).
*
* @return 0 - success.
*******************************************************************************/
int32_t axi_dmac_is_transfer_ready(struct axi_dmac *dmac, bool *rdy)
{
*rdy = dmac->transfer.transfer_done;
return 0;
}
/*******************************************************************************
* @brief Get DMAC capabilities.
*
* @param dmac - DMAC istance.
*
* @return 0 for success, -1 in case of failure.
*******************************************************************************/
static int32_t axi_dmac_detect_caps(struct axi_dmac *dmac)
{
uint32_t reg_val, initial_reg_val = 0;
uint32_t src_mem_mapped = 0;
uint32_t dest_mem_mapped = 0;
dmac->max_length = -1;
dmac->direction = INVALID_DIR;
/* Check if HW cyclic possible */
axi_dmac_read(dmac, AXI_DMAC_REG_FLAGS, &initial_reg_val);
axi_dmac_write(dmac, AXI_DMAC_REG_FLAGS, DMA_CYCLIC);
axi_dmac_read(dmac, AXI_DMAC_REG_FLAGS, &reg_val);
if (reg_val == DMA_CYCLIC)
dmac->hw_cyclic = true;
/* Restore initial value for AXI_DMAC_REG_FLAGS register */
axi_dmac_write(dmac, AXI_DMAC_REG_FLAGS, initial_reg_val);
/* Get maximum burst size and set value. */
axi_dmac_write(dmac, AXI_DMAC_REG_X_LENGTH, dmac->max_length);
axi_dmac_read(dmac, AXI_DMAC_REG_X_LENGTH, &dmac->max_length);
/* Get transfer direction and set value. */
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_ADDRESS, 0xffffffff);
axi_dmac_read(dmac, AXI_DMAC_REG_DEST_ADDRESS, &dest_mem_mapped);
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_ADDRESS, 0xffffffff);
axi_dmac_read(dmac, AXI_DMAC_REG_SRC_ADDRESS, &src_mem_mapped);
if (dest_mem_mapped && !src_mem_mapped) {
dmac->direction = DMA_DEV_TO_MEM;
} else if (!dest_mem_mapped && src_mem_mapped) {
dmac->direction = DMA_MEM_TO_DEV;
} else if (dest_mem_mapped && src_mem_mapped) {
dmac->direction = DMA_MEM_TO_MEM;
} else {
printf("Destination and source memory-mapped interfaces not supported.\n");
return -1;
}
return 0;
}
/*******************************************************************************
* @brief Get transfer status (value of dmac->transfer.transfer_done flag).
*
* @param dmac_core - DMAC istance.
* @param init - Structure containing initializing data.
*
* @return 0 for success, -1 in case of failure.
*******************************************************************************/
int32_t axi_dmac_init(struct axi_dmac **dmac_core,
const struct axi_dmac_init *init)
{
struct axi_dmac *dmac;
dmac = (struct axi_dmac *)calloc(1, sizeof(*dmac));
if (!dmac)
return -1;
dmac->name = init->name;
dmac->base = init->base;
dmac->irq_option = init->irq_option;
*dmac_core = dmac;
int32_t status = axi_dmac_detect_caps(*dmac_core);
if (status < 0)
return -1;
return 0;
}
/*******************************************************************************
* @brief Remove the DMAC instance.
*
* @param dmac - DMAC istance.
*
* @return 0 for success, -1 in case of failure.
*******************************************************************************/
int32_t axi_dmac_remove(struct axi_dmac *dmac)
{
if (!dmac)
return -1;
free(dmac);
return 0;
}
/*******************************************************************************
* @brief Start a DMA transfer.
*
* @param dmac - DMAC istance.
* @param dma_transfer - Structure containing transfer details.
*
* @return 0 for success, -1 in case of failure.
*******************************************************************************/
int32_t axi_dmac_transfer_start(struct axi_dmac *dmac,
struct axi_dma_transfer *dma_transfer)
{
uint32_t reg_val, burst_size;
if (dma_transfer->size == 0)
return 0; /* Nothing to do. */
/* Set current transfer parameters. */
dmac->transfer.size = dma_transfer->size;
dmac->transfer.cyclic = dma_transfer->cyclic;
dmac->transfer.dest_addr = dma_transfer->dest_addr;
dmac->transfer.src_addr = dma_transfer->src_addr;
dmac->remaining_size = dma_transfer->size;
dmac->next_dest_addr = dma_transfer->dest_addr;
dmac->next_src_addr = dma_transfer->src_addr;
/* If HW cyclic transfer selected and not available, show error */
/* HW cyclic transfer available only for MEM to DEV transfers. */
if ((!dmac->hw_cyclic) && (dma_transfer->cyclic == CYCLIC)) {
printf("Transfer mode not supported!\n");
return -1;
}
/* Cyclic transfers not possible for DEV_TO_MEM and MEM_TO_MEM transmissions. */
if ((dmac->direction == DMA_DEV_TO_MEM)
|| (dmac->direction == DMA_MEM_TO_MEM)) {
if (dma_transfer->cyclic == CYCLIC) {
printf("Transfer mode not supported!\n");
return -1;
}
}
/* Cyclic transfers set to HW or SW depending on size for MEM to DEV. */
if ((dmac->direction == DMA_MEM_TO_DEV) && (dmac->transfer.cyclic == CYCLIC)) {
if ((dmac->remaining_size - 1) <= dmac->max_length) {
if (dmac->hw_cyclic) {
axi_dmac_read(dmac, AXI_DMAC_REG_FLAGS, &reg_val);
reg_val = reg_val | DMA_CYCLIC;
axi_dmac_write(dmac, AXI_DMAC_REG_FLAGS, reg_val);
}
} else {
axi_dmac_read(dmac, AXI_DMAC_REG_FLAGS, &reg_val);
reg_val = reg_val & ~DMA_CYCLIC;
axi_dmac_write(dmac, AXI_DMAC_REG_FLAGS, reg_val);
}
}
/* Enable DMA if not already enabled. */
axi_dmac_read(dmac, AXI_DMAC_REG_CTRL, &reg_val);
if (!(reg_val & AXI_DMAC_CTRL_ENABLE)) {
axi_dmac_write(dmac, AXI_DMAC_REG_CTRL, 0x0);
axi_dmac_write(dmac, AXI_DMAC_REG_CTRL, AXI_DMAC_CTRL_ENABLE);
axi_dmac_write(dmac, AXI_DMAC_REG_IRQ_MASK, 0x0);
}
axi_dmac_read(dmac, AXI_DMAC_REG_TRANSFER_SUBMIT, &reg_val);
/* If we don't have a start of transfer then start compute
* values and trigger next transfer. */
if (!(reg_val & AXI_DMAC_QUEUE_FULL)) {
switch (dmac->direction) {
case DMA_DEV_TO_MEM:
dmac->init_addr = dmac->next_dest_addr;
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_ADDRESS, dmac->next_dest_addr);
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_STRIDE, 0x0);
break;
case DMA_MEM_TO_DEV:
dmac->init_addr = dmac->next_src_addr;
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_ADDRESS, dmac->next_src_addr);
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_STRIDE, 0x0);
break;
case DMA_MEM_TO_MEM:
dmac->init_addr = dmac->next_src_addr;
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_ADDRESS, dmac->next_dest_addr);
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_STRIDE, 0x0);
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_ADDRESS, dmac->next_src_addr);
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_STRIDE, 0x0);
break;
default:
return -1; /* Other directions are not supported yet. */
}
/* Compute the burst size. */
if (dmac->remaining_size > dmac->max_length) {
burst_size = dmac->max_length;
} else {
burst_size = dmac->remaining_size - 1;
}
/* Compute next address (src or dest, or both, depending on type of transfer). */
switch (dmac->direction) {
case DMA_DEV_TO_MEM:
dmac->next_dest_addr = dmac->next_dest_addr + (burst_size + 1);
break;
case DMA_MEM_TO_DEV:
dmac->next_src_addr = dmac->next_src_addr + (burst_size + 1);
break;
case DMA_MEM_TO_MEM:
dmac->next_dest_addr = dmac->next_dest_addr + (burst_size + 1);
dmac->next_src_addr = dmac->next_src_addr + (burst_size + 1);
break;
default:
return -1;
}
/* Compute remaining size. */
dmac->remaining_size = dmac->remaining_size - (burst_size + 1);
/* Specify the length of the transfer and trigger transfer. */
axi_dmac_write(dmac, AXI_DMAC_REG_X_LENGTH, burst_size);
axi_dmac_write(dmac, AXI_DMAC_REG_Y_LENGTH, 0x0);
axi_dmac_write(dmac, AXI_DMAC_REG_TRANSFER_SUBMIT, AXI_DMAC_TRANSFER_SUBMIT);
} else {
return -1;
}
return 0;
}
/*******************************************************************************
* @brief Wait for DMA transfer to be completed.
*
* @param dmac - DMAC istance.
* @param timeout_ms - Number of ms to wait for completion of transfer.
*
* @return 0 for success, -1 in case trasnfer not completed in specified time.
*******************************************************************************/
int32_t axi_dmac_transfer_wait_completion(struct axi_dmac *dmac,
uint32_t timeout_ms)
{
uint32_t timeout = 0;
uint32_t reg_val = 0;
if (dmac->irq_option == IRQ_ENABLED) {
while (!dmac->transfer.transfer_done) {
timeout++;
mdelay(1);
if (timeout == timeout_ms) {
printf("Error transferring data using DMA.\n");
return -1;
}
}
} else if (dmac->irq_option == IRQ_DISABLED) {
axi_dmac_read(dmac, AXI_DMAC_REG_IRQ_PENDING, &reg_val);
while (reg_val != (AXI_DMAC_IRQ_SOT | AXI_DMAC_IRQ_EOT)) {
timeout++;
mdelay(1);
if (timeout == timeout_ms) {
printf("Error transferring data using DMA.\n");
return -1;
}
axi_dmac_read(dmac, AXI_DMAC_REG_IRQ_PENDING, &reg_val);
}
}
return 0;
}
/*******************************************************************************
* @brief Stop a DMA transfer.
*
* @param dmac - DMAC istance.
*
* @return None
*******************************************************************************/
void axi_dmac_transfer_stop(struct axi_dmac *dmac)
{
axi_dmac_write(dmac, AXI_DMAC_REG_CTRL, AXI_DMAC_CTRL_DISABLE);
}
@@ -0,0 +1,156 @@
/***************************************************************************//**
* @file axi_dmac.h
* @brief Driver for the Analog Devices AXI-DMAC core.
* @author DBogdan ([email protected])
********************************************************************************
* Copyright 2018(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
*******************************************************************************/
#ifndef AXI_DMAC_H_
#define AXI_DMAC_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdint.h>
#include "util.h"
/******************************************************************************/
/********************** Macros and Constants Definitions **********************/
/******************************************************************************/
#define AXI_DMAC_REG_IRQ_MASK 0x80
#define AXI_DMAC_REG_IRQ_PENDING 0x84
#define AXI_DMAC_IRQ_SOT BIT(0)
#define AXI_DMAC_IRQ_EOT BIT(1)
#define AXI_DMAC_REG_INTF_DESC 0x010
#define AXI_DMAC_DMA_TYPE_DEST GENMASK(5,4)
#define AXI_DMAC_DMA_TYPE_SRC GENMASK(13,12)
//Define macro for src and dest
#define AXI_DMAC_REG_CTRL 0x400
#define AXI_DMAC_CTRL_ENABLE BIT(0)
#define AXI_DMAC_CTRL_DISABLE 0u
#define AXI_DMAC_CTRL_PAUSE BIT(1)
#define AXI_DMAC_REG_TRANSFER_ID 0x404
#define AXI_DMAC_REG_TRANSFER_SUBMIT 0x408
#define AXI_DMAC_TRANSFER_SUBMIT BIT(0)
#define AXI_DMAC_QUEUE_FULL BIT(0)
#define AXI_DMAC_REG_FLAGS 0x40c
#define AXI_DMAC_REG_DEST_ADDRESS 0x410
#define AXI_DMAC_REG_SRC_ADDRESS 0x414
#define AXI_DMAC_REG_X_LENGTH 0x418
#define AXI_DMAC_REG_Y_LENGTH 0x41c
#define AXI_DMAC_REG_DEST_STRIDE 0x420
#define AXI_DMAC_REG_SRC_STRIDE 0x424
#define AXI_DMAC_REG_TRANSFER_DONE 0x428
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
enum use_irq {
IRQ_DISABLED = 0,
IRQ_ENABLED = 1
};
enum dma_direction {
INVALID_DIR = 0,
DMA_DEV_TO_MEM = 1,
DMA_MEM_TO_DEV = 2,
DMA_MEM_TO_MEM = 3
};
enum dma_flags {
DMA_CYCLIC = 1,
DMA_LAST = 2,
DMA_PARTIAL_REPORTING_EN = 4
};
// Could be transformed to a bool
enum cyclic_transfer {
NO = 0,
CYCLIC = 1
};
struct axi_dma_transfer {
uint32_t size;
volatile bool transfer_done;
enum cyclic_transfer cyclic;
uint32_t src_addr;
uint32_t dest_addr;
};
struct axi_dmac {
const char *name;
uint32_t base;
enum use_irq irq_option;
enum dma_direction direction;
bool hw_cyclic;
uint32_t max_length;
volatile struct axi_dma_transfer transfer;
//Current sub-transfer properties
uint32_t init_addr;
uint32_t remaining_size;
uint32_t next_src_addr;
uint32_t next_dest_addr;
};
struct axi_dmac_init {
const char *name;
uint32_t base;
enum use_irq irq_option;
};
/******************************************************************************/
/************************ Functions Declarations ******************************/
/******************************************************************************/
void axi_dmac_dev_to_mem_isr(void *instance);
void axi_dmac_mem_to_dev_isr(void *instance);
void axi_dmac_mem_to_mem_isr(void *instance);
void axi_dmac_write_isr(void *instance);
int32_t axi_dmac_read(struct axi_dmac *dmac, uint32_t reg_addr,
uint32_t *reg_data);
int32_t axi_dmac_write(struct axi_dmac *dmac, uint32_t reg_addr,
uint32_t reg_data);
int32_t axi_dmac_is_transfer_ready(struct axi_dmac *dmac, bool *rdy);
int32_t axi_dmac_init(struct axi_dmac **adc_core,
const struct axi_dmac_init *init);
int32_t axi_dmac_remove(struct axi_dmac *dmac);
int32_t axi_dmac_transfer_start(struct axi_dmac *dmac,
struct axi_dma_transfer *dma_transfer);
int32_t axi_dmac_transfer_wait_completion(struct axi_dmac *dmac,
uint32_t timeout_ms);
void axi_dmac_transfer_stop(struct axi_dmac *dmac);
#endif
@@ -0,0 +1,996 @@
/*******************************************************************************
* @file spi_engine.c
* @brief Core implementation of the SPI Engine Driver.
* @author Sergiu Cuciurean ([email protected])
********************************************************************************
* Copyright 2019(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 Files **********************************/
/******************************************************************************/
/* In debug mode the printf function used in displaying the messages is causing
significant delays */
//#define DEBUG_LEVEL 2
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sleep.h>
#include <inttypes.h>
#include "axi_io.h"
#include "error.h"
#include "spi_engine.h"
/**
* @brief Spi engine platform specific SPI platform ops structure
*/
const struct spi_platform_ops spi_eng_platform_ops = {
.init = &spi_engine_init,
.write_and_read = &spi_engine_write_and_read,
.write_and_read_3wire = &spi_engine_write_and_read_3wire,
.remove = &spi_engine_remove
};
/******************************************************************************/
/***************************** Static variables *******************************/
/******************************************************************************/
/**
* @brief Static variable used to sync transfers
*
*/
static uint8_t _sync_id = 0x01;
/******************************************************************************/
/************************** Functions Implementation **************************/
/******************************************************************************/
/**
* @brief Write SPI Engine's axi registers
*
* @param desc Decriptor containing SPI Engine's parameters
* @param reg_addr The address of the SPI Engine's axi register where the data
* will be written
* @param reg_data Data that will be written
* @return int32_t This function allways returns SUCCESS
*/
int32_t spi_engine_write(struct spi_engine_desc *desc,
uint32_t reg_addr,
uint32_t reg_data)
{
axi_io_write(desc->spi_engine_baseaddr, reg_addr, reg_data);
return SUCCESS;
}
/**
* @brief Read SPI Engine's axi registers
*
* @param desc Decriptor containing SPI Engine's parameters
* @param reg_addr The address of the SPI Engine's axi register from where the
* data where the data will be read
* @param reg_data Pointer where the read that will be stored
* @return int32_t This function allways returns SUCCESS
*/
int32_t spi_engine_read(struct spi_engine_desc *desc,
uint32_t reg_addr,
uint32_t *reg_data)
{
axi_io_read(desc->spi_engine_baseaddr, reg_addr, reg_data);
return SUCCESS;
}
/**
* @brief Set width of the transferred word over SPI
*
* @param desc Decriptor containing SPI interface parameters
* @param data_width The desired data width
* The supported values are:
* - 8
* - 16
* - 24
* - 32
*/
int32_t spi_engine_set_transfer_width(struct spi_desc *desc,
uint8_t data_width)
{
struct spi_engine_desc *desc_extra;
desc_extra = desc->extra;
if (data_width > desc_extra->max_data_width)
desc_extra->data_width = desc_extra->max_data_width;
else
desc_extra->data_width = data_width;
return SUCCESS;
}
/**
* @brief Set SPI engine clock frequency
*
* @param desc Decriptor containing SPI Engine's parameters
* @param speed_hz SPI engine transfer speed
*/
void spi_engine_set_speed(struct spi_desc *desc,
uint32_t speed_hz)
{
struct spi_engine_desc *desc_extra;
desc_extra = desc->extra;
desc_extra->clk_div = desc_extra->ref_clk_hz /
(2 * speed_hz) - 1;
}
/**
* @brief Set the number of words transferred in a single transaction
*
* @param desc Decriptor containing SPI Engine's parameters
* @param bytes_number The number of bytes to be converted
* @return uint8_t A number of words in which bytes_number can be grouped
*/
static uint8_t spi_get_words_number(struct spi_engine_desc *desc,
uint8_t bytes_number)
{
uint8_t xfer_word_len;
uint8_t words_number;
xfer_word_len = desc->data_width / 8;
words_number = bytes_number / xfer_word_len;
if ((bytes_number % xfer_word_len) != 0)
words_number++;
return words_number;
}
/**
* @brief Get the word length in bytes
*
* @param desc Decriptor containing SPI Engine's parameters
* @return uint8_t Number of bytes that fit in one word
*/
static uint8_t spi_get_word_length(struct spi_engine_desc *desc)
{
uint8_t word_length;
word_length = desc->data_width / 8;
return word_length;
}
/**
* @brief Compute the prescaler used to set the sleep period.
*
* @param desc Decriptor containing SPI interface parameters
* @param sleep_time_ns The amount of time where the transfer hangs
* @param sleep_div Clock prescaler
* @return int32_t This function allways returns SUCCESS
*/
static int32_t spi_get_sleep_div(struct spi_desc *desc,
uint32_t sleep_time_ns,
uint32_t *sleep_div)
{
struct spi_engine_desc *eng_desc;
eng_desc = desc->extra;
/*
* Engine Wiki:
*
* The frequency of the SCLK signal is derived from the
* module clock frequency using the following formula:
* f_sclk = f_clk / ((div + 1) * 2)
*/
*sleep_div = (desc->max_speed_hz / 1000000 * sleep_time_ns / 1000) /
((eng_desc->clk_div + 1) * 2) - 1;
return SUCCESS;
}
/**
* @brief Create a new commands queue used in a spi transfer
*
* @param fifo Command buffer, usually used in fifo mode
* @param cmd Command with which the buffer will be initiated
* @return int32_t Failure if the memory allocation failed
*/
static int32_t spi_engine_queue_new_cmd(struct spi_engine_cmd_queue **fifo,
uint32_t cmd)
{
struct spi_engine_cmd_queue *local_fifo;
local_fifo = (spi_engine_cmd_queue*)malloc(sizeof(*local_fifo));
if(!local_fifo)
return FAILURE;
local_fifo->cmd = cmd;
local_fifo->next = NULL;
*fifo = local_fifo;
return SUCCESS;
}
/**
* @brief Add a command at the end of an existing queue
*
* @param fifo Command buffer, usually used in fifo mode
* @param cmd Command to be added
*/
static void spi_engine_queue_add_cmd(struct spi_engine_cmd_queue **fifo,
uint32_t cmd)
{
struct spi_engine_cmd_queue *to_add = NULL;
struct spi_engine_cmd_queue *local_fifo;
local_fifo = *fifo;
while (local_fifo->next != NULL) {
// Get the last element
local_fifo = local_fifo->next;
}
// Create a new element
spi_engine_queue_new_cmd(&to_add, cmd);
// Add as the next element
local_fifo->next = to_add;
}
/**
* @brief Add a command at the beginning of an existing queue
*
* @param fifo Command buffer, usually used in fifo mode
* @param cmd Command to be added
*/
static void spi_engine_queue_append_cmd(struct spi_engine_cmd_queue **fifo,
uint32_t cmd)
{
struct spi_engine_cmd_queue *to_add = NULL;
// Create a new element
spi_engine_queue_new_cmd(&to_add, cmd);
// Interchange the addresses
to_add->next = *fifo;
*fifo = to_add;
}
/**
* @brief Get the command from the beginning of the queue
*
* @param fifo Command buffer, usually used in fifo mode
* @param cmd Value of the command that was extracted
* @return int32_t Return FAILURE if the queue is empty
*/
static int32_t spi_engine_queue_get_cmd(struct spi_engine_cmd_queue **fifo,
uint32_t *cmd)
{
struct spi_engine_cmd_queue *local_fifo;
if (!*fifo)
return FAILURE;
local_fifo = *fifo;
*cmd = local_fifo->cmd;
if ((*fifo)->next) {
*fifo = local_fifo->next;
free(local_fifo);
} else {
free(*fifo);
*fifo = NULL;
}
return SUCCESS;
}
/**
* @brief Free the memory allocated by a queue
*
* @param fifo The queue that needs it's memory freed
* @return int32_t This function always returns SUCCESS
*/
static int32_t spi_engine_queue_free(struct spi_engine_cmd_queue **fifo)
{
if(*fifo && (*fifo)->next)
spi_engine_queue_free(&(*fifo)->next);
if((*fifo) != NULL) {
free(*fifo);
*fifo = NULL;
}
return SUCCESS;
}
/**
* @brief Write the SPI engine's command fifo
*
* @param desc Decriptor containing SPI Engine's parameters
* @param cmd The command that will be written
* @return int32_t Returns FAILURE if the the axi transfer failed
*/
static int32_t spi_engine_write_cmd_reg(struct spi_engine_desc *desc,
uint32_t cmd)
{
int32_t ret;
/* Check if offload is enabled */
if(desc->offload_config & (OFFLOAD_TX_EN | OFFLOAD_RX_EN)) {
ret = spi_engine_write(desc,
SPI_ENGINE_REG_OFFLOAD_CMD_MEM(0),
cmd);
} else {
ret = spi_engine_write(desc,
SPI_ENGINE_REG_CMD_FIFO,
cmd);
}
return ret;
}
/**
* @brief Write a transfer command to the SPI engine's command fifo
*
* @param desc Decriptor containing SPI Engine's parameters
* @param read_write Read/Write operation flag
* @param bytes_number Number of bytes to transfer
* @return int32_t This function always returns SUCCESS
*/
static int32_t spi_engine_transfer(struct spi_engine_desc *desc,
uint8_t read_write,
uint8_t bytes_number)
{
uint8_t words_number;
words_number = spi_get_words_number(desc, bytes_number);
desc->offload_tx_len += words_number;
/*
* Engine Wiki:
*
* https://wiki.analog.com/resources/fpga/peripherals/spi_engine
*
* The words number is zero based
*/
spi_engine_write_cmd_reg(desc,
SPI_ENGINE_CMD_TRANSFER(read_write,
words_number - 1));
return SUCCESS;
}
/**
* @brief Change the state of the chip select port
*
* @param desc Decriptor containing SPI interface parameters
* @param assert Chip select state.
* The supported values are :
* -true (HIGH)
* -false (LOW)
*/
static void spi_engine_set_cs(struct spi_desc *desc,
bool assert)
{
uint8_t mask;
struct spi_engine_desc *eng_desc;
eng_desc = desc->extra;
mask = 0xFF;
/* Switch the state only of the selected chip select */
if (!assert)
mask ^= BIT(desc->chip_select);
spi_engine_write_cmd_reg(eng_desc,
SPI_ENGINE_CMD_ASSERT(eng_desc->cs_delay,
mask));
}
/**
* @brief Add a delay between the engine commands
*
* @param desc Decriptor containing SPI interface parameters
* @param sleep_time_ns Number of nanoseconds to sleep between commands
*/
static void spi_gen_sleep_ns(struct spi_desc *desc,
uint32_t sleep_time_ns)
{
uint32_t sleep_div;
struct spi_engine_desc *eng_desc;
eng_desc = desc->extra;
spi_get_sleep_div(desc, sleep_time_ns, &sleep_div);
spi_engine_write_cmd_reg(eng_desc, SPI_ENGINE_CMD_SLEEP(sleep_div));
}
/**
* @brief Spi engine command interpreter
*
* @param desc Decriptor containing SPI interface parameters
* @param cmd Command to send to the engine
* @return int32_t - SUCCESS if the command is transferred
* - FAILURE if the command format is invalid
*/
static int32_t spi_engine_write_cmd(struct spi_desc *desc,
uint32_t cmd)
{
uint8_t engine_command;
uint8_t parameter;
uint8_t modifier;
struct spi_engine_desc *desc_extra;
desc_extra = desc->extra;
engine_command = (cmd >> 12) & 0x0F;
modifier = (cmd >> 8) & 0x0F;
parameter = cmd & 0xFF;
switch(engine_command) {
case SPI_ENGINE_INST_TRANSFER:
spi_engine_transfer(desc_extra, modifier, parameter);
break;
case SPI_ENGINE_INST_ASSERT:
if(parameter == 0xFF) {
/* Set the CS HIGH */
spi_engine_set_cs(desc, true);
} else if(parameter == 0x00) {
/* Set the CS LOW */
spi_engine_set_cs(desc, false);
}
break;
/* The SYNC and SLEEP commands got the same value but different
modifier */
case SPI_ENGINE_INST_SYNC_SLEEP:
/* SYNC instruction */
if(modifier == 0x00) {
spi_engine_write_cmd_reg(desc_extra, cmd);
} else if(modifier == 0x01) {
spi_gen_sleep_ns(desc, parameter);
}
break;
case SPI_ENGINE_INST_CONFIG:
spi_engine_write_cmd_reg(desc_extra, cmd);
break;
default:
return FAILURE;
}
return SUCCESS;
}
/**
* @brief Prepare the command queue before sending it to the engine
*
* @param desc Decriptor containing SPI interface parameters
* @param msg Structure used to store the transfer messages
* @return int32_t This function always returns SUCCESS
*/
static int32_t spi_engine_compile_message(struct spi_desc *desc,
struct spi_engine_msg *msg)
{
struct spi_engine_desc *desc_extra;
desc_extra = desc->extra;
/* Configure the prescaler */
spi_engine_queue_append_cmd(&msg->cmds,
SPI_ENGINE_CMD_CONFIG(
SPI_ENGINE_CMD_REG_CLK_DIV,
desc_extra->clk_div));
/* Set the data transfer length */
spi_engine_queue_append_cmd(&msg->cmds,
SPI_ENGINE_CMD_CONFIG(
SPI_ENGINE_CMD_DATA_TRANSFER_LEN,
desc_extra->data_width));
/*
* Configure the spi mode :
* - 3 wire
* - CPOL
* - CPHA
*/
spi_engine_queue_append_cmd(&msg->cmds,
SPI_ENGINE_CMD_CONFIG(
SPI_ENGINE_CMD_REG_CONFIG,
desc->mode));
/* Add a sync command to signal that the transfer has finished */
spi_engine_queue_add_cmd(&msg->cmds, SPI_ENGINE_CMD_SYNC(_sync_id));
return SUCCESS;
}
/**
* @brief Initiate a spi transfer (Blocking)
*
* @param desc Decriptor containing SPI interface parameters
* @param msg Structure used to store the transfer messages
* @return int32_t - SUCCESS if the transfer finished
* - FAILURE if the memory allocation failed
*/
static int32_t spi_engine_transfer_message(struct spi_desc *desc,
struct spi_engine_msg *msg)
{
uint32_t i;
uint32_t data;
uint32_t sync_id;
bool offload_en;
struct spi_engine_desc *desc_extra;
desc_extra = desc->extra;
spi_engine_compile_message(desc, msg);
offload_en = (desc_extra->offload_config & OFFLOAD_TX_EN) |
(desc_extra->offload_config & OFFLOAD_RX_EN);
/* Write the command fifo buffer */
while(msg->cmds != NULL) {
spi_engine_queue_get_cmd(&msg->cmds, &data);
spi_engine_write_cmd(desc, data);
}
/* Write a number of tx_length WORDS on the SDO line */
if(offload_en) {
for(i = 0; i < desc_extra->offload_tx_len; i++)
spi_engine_write(desc_extra,
SPI_ENGINE_REG_OFFLOAD_SDO_MEM(0),
msg->tx_buf[i]);
} else {
if(msg->tx_buf != NULL){
for(i = 0; i < msg->tx_length; i++)
spi_engine_write(desc_extra,
SPI_ENGINE_REG_SDO_DATA_FIFO,
msg->tx_buf[i]);
}
do {
spi_engine_read(desc_extra,
SPI_ENGINE_REG_SYNC_ID,
&sync_id);
}
/* Wait for the end sync signal */
while(sync_id != _sync_id);
_sync_id++;
/* Read a number of rx_length WORDS from the SDI line and store
them */
for(i = 0; i < msg->rx_length; i++) {
spi_engine_read(desc_extra,
SPI_ENGINE_REG_SDI_DATA_FIFO,
&data);
/* Store the rx data if rx buffer valid, flush sdi_fifo if
rx buffer is invalid.*/
if(msg->rx_buf != NULL){
msg->rx_buf[i] = data;
}
}
}
return SUCCESS;
}
/**
* @brief Initialize the spi engine
*
* @param desc Decriptor containing SPI interface parameters
* @param param Structure containing the spi init parameters
* @return int32_t - SUCCESS if the transfer finished
* - FAILURE if the memory allocation failed
*/
int32_t spi_engine_init(struct spi_desc **desc,
const struct spi_init_param *param)
{
uint32_t data_width;
uint32_t spi_engine_version;
struct spi_engine_desc *eng_desc;
struct spi_engine_init_param *spi_engine_init;
if (!param) {
return FAILURE;
}
*desc = malloc(sizeof(**desc));
if(! *desc) {
free(*desc);
return FAILURE;
}
eng_desc = (struct spi_engine_desc*)malloc(sizeof(*eng_desc));
if (!eng_desc)
return FAILURE;
spi_engine_init = param->extra;
(*desc)->max_speed_hz = param->max_speed_hz;
(*desc)->chip_select = param->chip_select;
(*desc)->mode = param->mode;
(*desc)->extra = eng_desc;
eng_desc->offload_config = OFFLOAD_DISABLED;
eng_desc->spi_engine_baseaddr = spi_engine_init->spi_engine_baseaddr;
eng_desc->type = spi_engine_init->type;
eng_desc->cs_delay = spi_engine_init->cs_delay;
eng_desc->ref_clk_hz = spi_engine_init->ref_clk_hz;
eng_desc->clk_div = eng_desc->ref_clk_hz /
(2 * param->max_speed_hz) - 1;
/* Perform a reset */
spi_engine_write(eng_desc, SPI_ENGINE_REG_RESET, 0x01);
usleep(1000);
spi_engine_write(eng_desc, SPI_ENGINE_REG_RESET, 0x00);
/* Get current data width */
spi_engine_read(eng_desc, SPI_ENGINE_REG_DATA_WIDTH, &data_width);
eng_desc->max_data_width = data_width;
spi_engine_set_transfer_width(*desc, spi_engine_init->data_width);
/* Get spi engine version */
spi_engine_read(eng_desc, SPI_ENGINE_REG_VERSION, &spi_engine_version);
printf("Spi engine v%"PRIu32".%"PRIu32".%"PRIu32" successfully initialized.\n",
(spi_engine_version >> 16),
((spi_engine_version >> 8) & 0xFF),
(spi_engine_version & 0xFF));
return SUCCESS;
}
/**
* @brief Write/read on the spi interface in 4-wire mode (full-duplex)
*
* @param desc Decriptor containing SPI interface parameters
* @param data Pointer to data buffer
* @param bytes_number Number of bytes to transfer
* @return int32_t - SUCCESS if the transfer finished
* - FAILURE if the memory allocation or transfer failed
*/
int32_t spi_engine_write_and_read(struct spi_desc *desc,
uint8_t *data,
uint16_t bytes_number)
{
uint8_t word_len;
uint8_t words_number;
int32_t ret;
struct spi_engine_msg msg;
struct spi_engine_desc *desc_extra;
desc_extra = desc->extra;
/* If we want to access SPI interface and SPI engine offload module was
* activated, we need to disable it
* This is set in spi_engine_offload_init() */
desc_extra->offload_config = OFFLOAD_DISABLED;
/* This is set in spi_engine_offload_transfer() */
spi_engine_write(desc_extra, SPI_ENGINE_REG_OFFLOAD_CTRL(0), 0);
words_number = spi_get_words_number(desc_extra, bytes_number);
msg.cmds = (spi_engine_cmd_queue*)malloc(sizeof(*msg.cmds));
if (!msg.cmds)
return FAILURE;
msg.tx_buf =(uint32_t*)calloc(words_number, sizeof(msg.tx_buf[0]));
msg.rx_buf =(uint32_t*)calloc(words_number, sizeof(msg.rx_buf[0]));
msg.tx_length = words_number;
msg.rx_length = words_number;
/* Get the length of transferred word */
word_len = spi_get_word_length(desc_extra);
/* Make sure the CS is HIGH before starting a transaction */
msg.cmds->next = NULL;
msg.cmds->cmd = CS_HIGH;
// Assert select.
spi_engine_queue_add_cmd(&msg.cmds, CS_LOW);
// add read/write command
spi_engine_queue_add_cmd(&msg.cmds, WRITE_READ(bytes_number));
// Disable select.
spi_engine_queue_add_cmd(&msg.cmds, CS_HIGH);
/* Pack the bytes into engine WORDS */
for (int i = 0; i < bytes_number; i++)
msg.tx_buf[i / word_len] |= data[i] << (desc_extra->data_width-
(i % word_len + 1) * 8);
ret = spi_engine_transfer_message(desc, &msg);
for (int i = 0; i < bytes_number; i++)
data[i] = msg.rx_buf[(i) / word_len] >>
(desc_extra->data_width -
((i) % word_len + 1) * 8);
spi_engine_queue_free(&msg.cmds);
free(msg.tx_buf);
free(msg.rx_buf);
return ret;
}
/**
* @brief Write and read on the spi interface in 3-wire mode (half-duplex)
*
* @param desc Decriptor containing SPI interface parameters
* @param data Pointer to data buffer
* @param bytes_number Number of bytes to transfer
* @return int32_t - SUCCESS if the transfer finished
* - FAILURE if the memory allocation or transfer failed
*/
int32_t spi_engine_write_and_read_3wire(struct spi_desc *desc,
uint8_t *write_data,
uint8_t *read_data,
uint16_t write_bytes_number,
uint16_t read_bytes_number)
{
uint8_t word_len;
uint8_t wr_words_number;
uint8_t rd_words_number;
int32_t ret;
struct spi_engine_msg msg;
struct spi_engine_desc *desc_extra;
desc_extra = desc->extra;
/* If we want to access SPI interface and SPI engine offload module was
* activated, we need to disable it
* This is set in spi_engine_offload_init() */
desc_extra->offload_config = OFFLOAD_DISABLED;
/* This is set in spi_engine_offload_transfer() */
spi_engine_write(desc_extra, SPI_ENGINE_REG_OFFLOAD_CTRL(0), 0);
wr_words_number = spi_get_words_number(desc_extra, write_bytes_number);
rd_words_number = spi_get_words_number(desc_extra, read_bytes_number);
msg.cmds = (spi_engine_cmd_queue*)malloc(sizeof(*msg.cmds));
if (!msg.cmds)
return FAILURE;
msg.tx_buf =(wr_words_number>0)?(uint32_t*)calloc(wr_words_number, sizeof(msg.tx_buf[0])):NULL;
msg.rx_buf =(rd_words_number>0)?(uint32_t*)calloc(rd_words_number, sizeof(msg.rx_buf[0])):NULL;
msg.tx_length = wr_words_number;
msg.rx_length = rd_words_number;
/* Get the length of transferred word */
word_len = spi_get_word_length(desc_extra);
/* Make sure the CS is HIGH before starting a transaction */
msg.cmds->next = NULL;
msg.cmds->cmd = CS_HIGH;
// Assert select.
spi_engine_queue_add_cmd(&msg.cmds, CS_LOW);
// add read/write command
if(write_bytes_number > 0)
spi_engine_queue_add_cmd(&msg.cmds, WRITE(write_bytes_number));
if(read_bytes_number > 0)
spi_engine_queue_add_cmd(&msg.cmds, READ(read_bytes_number));
// Disable select.
spi_engine_queue_add_cmd(&msg.cmds, CS_HIGH);
/* Pack the bytes into engine WORDS */
for (int i = 0; i < write_bytes_number; i++)
msg.tx_buf[i / word_len] |= write_data[i] << (desc_extra->data_width-
(i % word_len + 1) * 8);
ret = spi_engine_transfer_message(desc, &msg);
for (int i = 0; i < read_bytes_number; i++)
read_data[i] = msg.rx_buf[(i) / word_len] >>
(desc_extra->data_width -
((i) % word_len + 1) * 8);
spi_engine_queue_free(&msg.cmds);
free(msg.tx_buf);
free(msg.rx_buf);
return ret;
}
/**
* @brief Initialize the SPI engine's offload module
*
* @param desc Decriptor containing SPI interface parameters
* @param param Structure containing the offload init parameters
* @return int32_t This function always returns SUCCESS
*/
int32_t spi_engine_offload_init(struct spi_desc *desc,
const struct spi_engine_offload_init_param *param)
{
struct spi_engine_desc *eng_desc;
struct axi_dmac_init dmac_init;
eng_desc = desc->extra;
eng_desc->offload_config = param->offload_config;
if(!(param->dma_flags)) {
eng_desc->cyclic = CYCLIC;
} else {
if((*(param->dma_flags)) & DMA_CYCLIC)
eng_desc->cyclic = CYCLIC;
else
eng_desc->cyclic = NO;
}
if(param->offload_config & OFFLOAD_TX_EN) {
dmac_init.name = "DAC DMAC";
dmac_init.base = param->tx_dma_baseaddr;
axi_dmac_init(&eng_desc->offload_tx_dma, &dmac_init);
if(!eng_desc->offload_tx_dma)
return FAILURE;
}
if(param->offload_config & OFFLOAD_RX_EN) {
dmac_init.name = "ADC DMAC";
dmac_init.base = param->rx_dma_baseaddr;
axi_dmac_init(&eng_desc->offload_rx_dma, &dmac_init);
if(!eng_desc->offload_rx_dma)
return FAILURE;
}
return SUCCESS;
}
/**
* @brief Initiate a SPI transfer in offload mode
*
* @param desc Decriptor containing SPI interface parameters
* @param msg Offload message that get's to be transferred
* @param no_samples Number of time the messages will be transferred
* @return int32_t This function always returns SUCCESS
*/
int32_t spi_engine_offload_transfer(struct spi_desc *desc,
struct spi_engine_offload_message msg,
uint32_t no_samples)
{
struct spi_engine_msg transfer;
struct spi_engine_desc *eng_desc;
uint32_t i;
uint8_t word_length;
eng_desc = desc->extra;
/* Check if offload is disabled */
if(!((eng_desc->offload_config & OFFLOAD_TX_EN) |
(eng_desc->offload_config & OFFLOAD_RX_EN)))
return FAILURE;
spi_engine_write(eng_desc, SPI_ENGINE_REG_OFFLOAD_RESET(0), 1);
spi_engine_write(eng_desc, SPI_ENGINE_REG_OFFLOAD_RESET(0), 0);
eng_desc->offload_tx_len = 0;
eng_desc->offload_rx_len = 0;
transfer.cmds = (spi_engine_cmd_queue*)malloc(sizeof(*transfer.cmds));
if (!transfer.cmds)
return -1;
transfer.tx_buf = msg.commands_data;
/* Load the commands into the message */
transfer.cmds->next = NULL;
transfer.cmds->cmd = msg.commands[0];
i = 1;
while(i < msg.no_commands) {
spi_engine_queue_add_cmd(&transfer.cmds, msg.commands[i++]);
}
spi_engine_transfer_message(desc, &transfer);
/* Start transfer */
spi_engine_write(eng_desc, SPI_ENGINE_REG_OFFLOAD_CTRL(0), 0x0001);
word_length = spi_get_word_length(eng_desc);
if(eng_desc->offload_config & OFFLOAD_TX_EN) {
struct axi_dma_transfer tx_transfer = {
// Number of bytes to write/read
.size = word_length * eng_desc->offload_tx_len * no_samples,
// Transfer done flag
.transfer_done = 0,
// Signal transfer mode
.cyclic = eng_desc->cyclic,
// Address of data source
.src_addr = (uintptr_t)msg.tx_addr,
// Address of data destination
.dest_addr = 0
};
axi_dmac_transfer_start(eng_desc->offload_tx_dma, &tx_transfer);
}
if(eng_desc->offload_config & OFFLOAD_RX_EN) {
struct axi_dma_transfer rx_transfer = {
// Number of bytes to write/read
.size = word_length * eng_desc->offload_tx_len * no_samples,
// Transfer done flag
.transfer_done = 0,
// Signal transfer mode
.cyclic = NO,
// Address of data source
.src_addr = 0,
// Address of data destination
.dest_addr = (uintptr_t)msg.rx_addr
};
axi_dmac_transfer_start(eng_desc->offload_rx_dma, &rx_transfer);
axi_dmac_transfer_wait_completion(eng_desc->offload_rx_dma, 500);
}
usleep(1000);
spi_engine_queue_free(&transfer.cmds);
return SUCCESS;
}
/**
* @brief Free the resources allocated by spi_init().
*
* @param desc Decriptor containing SPI interface parameters
* @return int32_t This function allways returns SUCCESS
*/
int32_t spi_engine_remove(struct spi_desc *desc)
{
struct spi_engine_desc *eng_desc;
eng_desc = desc->extra;
if(eng_desc->offload_config & OFFLOAD_TX_EN)
axi_dmac_remove(eng_desc->offload_tx_dma);
if(eng_desc->offload_config & OFFLOAD_RX_EN)
axi_dmac_remove(eng_desc->offload_rx_dma);
free(desc->extra);
free(desc);
return SUCCESS;
}
@@ -0,0 +1,229 @@
/*******************************************************************************
* @file spi_engine.h
* @brief Header file of SPI Engine core features.
* @author Sergiu Cuciurean ([email protected])
********************************************************************************
* Copyright 2019(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
*******************************************************************************/
#ifndef SPI_ENGINE_H
#define SPI_ENGINE_H
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdint.h>
#include "spi_engine_private.h"
#include "../axi_dmac/axi_dmac.h"
#include "../../platform/xilinx_spi.h"
/******************************************************************************/
/********************** Macros and Constants Definitions **********************/
/******************************************************************************/
#define OFFLOAD_DISABLED 0x00
#define OFFLOAD_TX_EN BIT(0)
#define OFFLOAD_RX_EN BIT(1)
#define OFFLOAD_TX_RX_EN OFFLOAD_TX_EN | OFFLOAD_RX_EN
#define SPI_ENGINE_MSG_QUEUE_END 0xFFFFFFFF
/* Spi engine commands */
#define WRITE(no_bytes) ((SPI_ENGINE_INST_TRANSFER << 12) |\
(SPI_ENGINE_INSTRUCTION_TRANSFER_W << 8) | no_bytes)
#define READ(no_bytes) ((SPI_ENGINE_INST_TRANSFER << 12) |\
(SPI_ENGINE_INSTRUCTION_TRANSFER_R << 8) | no_bytes)
#define WRITE_READ(no_bytes) ((SPI_ENGINE_INST_TRANSFER << 12) |\
(SPI_ENGINE_INSTRUCTION_TRANSFER_RW << 8) | no_bytes)
#define SLEEP(time) SPI_ENGINE_CMD_SLEEP(time & 0xF)
/* The delay and chip select parmeters are passed over the engine descriptor
and will be used inside the function call */
#define CS_HIGH SPI_ENGINE_CMD_ASSERT(0x01, 0xFF)
#define CS_LOW SPI_ENGINE_CMD_ASSERT(0x01, 0x00)
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
/**
* @struct spi_engine_init_param
* @brief Structure containing the init parameters needed by the SPI engine
*/
struct spi_engine_init_param {
/** SPI engine reference clock */
uint32_t ref_clk_hz;
/** Type of implementation */
enum xil_spi_type type;
/** Base address where the HDL core is situated */
uint32_t spi_engine_baseaddr;
/** Delay between the CS toggle and the start of SCLK */
uint32_t cs_delay;
/** Data with of one SPI transfer ( in bits ) */
uint8_t data_width;
};
/**
* @struct spi_engine_desc
* @brief Structure representing an SPI engine device
*/
struct spi_engine_desc {
/** SPI engine reference clock */
uint32_t ref_clk_hz;
/** Type of implementation */
enum xil_spi_type type;
/** Pointer to a DMAC used in transmission */
struct axi_dmac *offload_tx_dma;
/** Pointer to a DMAC used in reception */
struct axi_dmac *offload_rx_dma;
/** Transfer mode for Tx DMAC */
enum cyclic_transfer cyclic;
/** Offload's module transfer direction : TX, RX or both */
uint8_t offload_config;
/** Number of words that the module has to send */
uint8_t offload_tx_len;
/** Number of words that the module has to receive */
uint8_t offload_rx_len;
/** Base address where the HDL core is situated */
uint32_t spi_engine_baseaddr;
/** Base address where the RX DMAC core is situated */
uint32_t rx_dma_baseaddr;
/** Base address where the TX DMAC core is situated */
uint32_t tx_dma_baseaddr;
/** Delay between the CS toggle and the start of SCLK */
uint8_t cs_delay;
/** Clock divider used in transmission delays */
uint32_t clk_div;
/** Data with of one SPI transfer ( in bits ) */
uint8_t data_width;
/** The maximum data width supported by the engine */
uint8_t max_data_width;
};
/**
* @struct spi_engine_offload_init_param
* @brief Structure containing the init parameters needed by the offload module
*/
struct spi_engine_offload_init_param {
/** Base address where the RX DMAC core is situated */
uint32_t rx_dma_baseaddr;
/** Base address where the TX DMAC core is situated */
uint32_t tx_dma_baseaddr;
/** DMAC flags - if not initialized, the default value is DMA_CYCLIC */
uint32_t *dma_flags;
/** Offload's module transfer direction : TX, RX or both */
uint8_t offload_config;
};
/**
* @struct spi_engine_offload_message
* @brief Structure representing an offload message
*/
struct spi_engine_offload_message {
/** Pointer to the SPI engine commands buffer that will be sent.
* The available commands can be found at:
* https://wiki.analog.com/resources/fpga/peripherals/spi_engine/
*/
uint32_t *commands;
/** Length of the SPI engine commands buffer */
uint32_t no_commands;
/** Pointer of the data that will be sent over spi */
uint32_t *commands_data;
/** The address where the data that will be transmitted is situated */
uint32_t tx_addr;
/** The address where the data that will be received is situated */
uint32_t rx_addr;
};
/******************************************************************************/
/************************ Functions Declarations ******************************/
/******************************************************************************/
/**
* @brief Spi engine platform specific SPI platform ops structure
*/
extern const struct spi_platform_ops xil_spi_ops;
/* Write SPI Engine's axi registers */
int32_t spi_engine_write(struct spi_engine_desc *desc,
uint32_t reg_addr,
uint32_t reg_data);
/* Read SPI Engine's axi registers */
int32_t spi_engine_read(struct spi_engine_desc *desc,
uint32_t reg_addr,
uint32_t *reg_data);
/* Initialize the SPI engine device */
int32_t spi_engine_init(struct spi_desc **desc,
const struct spi_init_param *param);
/* Write and read data over SPI using the SPI engine */
int32_t spi_engine_write_and_read(struct spi_desc *desc,
uint8_t *data,
uint16_t bytes_number);
/* Write and read data over SPI using the SPI engine in 3-wire mode */
int32_t spi_engine_write_and_read_3wire(struct spi_desc *desc,
uint8_t *write_data,
uint8_t *read_data,
uint16_t write_bytes_number,
uint16_t read_bytes_number);
/* Free the resources used by the SPI engine device */
int32_t spi_engine_remove(struct spi_desc *desc);
/* Initialize the SPI engine offload module */
int32_t spi_engine_offload_init(struct spi_desc *desc,
const struct spi_engine_offload_init_param *param);
/* Write and read data over SPI using the offload module */
int32_t spi_engine_offload_transfer(struct spi_desc *desc,
struct spi_engine_offload_message msg,
uint32_t no_samples);
/* Set SPI transfer width */
int32_t spi_engine_set_transfer_width(struct spi_desc *desc,
uint8_t data_wdith);
/* Set SPI transfer speed */
void spi_engine_set_speed(struct spi_desc *desc,
uint32_t speed_hz);
#endif // SPI_ENGINE_H
@@ -0,0 +1,154 @@
/*******************************************************************************
* @file spi_engine_private.h
* @brief Private definitions of the SPI Engine
* @author Sergiu Cuciurean ([email protected])
********************************************************************************
* Copyright 2019(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
*******************************************************************************/
#ifndef SPI_ENGINE_PRIVATE_H
#define SPI_ENGINE_PRIVATE_H
#include <stdint.h>
#include <stdbool.h>
#include "spi.h"
#include "util.h"
/******************************************************************************/
/*************************** Spi Engine registers *****************************/
/******************************************************************************/
#define SPI_ENGINE_REG_VERSION 0x00
#define SPI_ENGINE_REG_DATA_WIDTH 0x0C
#define SPI_ENGINE_REG_RESET 0x40
#define SPI_ENGINE_REG_INT_ENABLE 0x80
#define SPI_ENGINE_REG_INT_PENDING 0x84
#define SPI_ENGINE_REG_INT_SOURCE 0x88
#define SPI_ENGINE_REG_SYNC_ID 0xC0
#define SPI_ENGINE_REG_CMD_FIFO_ROOM 0xD0
#define SPI_ENGINE_REG_SDO_FIFO_ROOM 0xD4
#define SPI_ENGINE_REG_SDI_FIFO_LEVEL 0xD8
#define SPI_ENGINE_REG_CMD_FIFO 0xE0
#define SPI_ENGINE_REG_SDO_DATA_FIFO 0xE4
#define SPI_ENGINE_REG_SDI_DATA_FIFO 0xE8
#define SPI_ENGINE_REG_SDI_DATA_FIFO_PEEK 0xEC
/******************************************************************************/
/************************ Spi Engine register parameters **********************/
/******************************************************************************/
#define SPI_ENGINE_INST_TRANSFER 0x00
#define SPI_ENGINE_INST_ASSERT 0x01
#define SPI_ENGINE_INST_CONFIG 0x02
#define SPI_ENGINE_INST_SYNC_SLEEP 0x03
#define SPI_ENGINE_INST_MISC 0x03
#define SPI_ENGINE_CMD_REG_CLK_DIV 0x00
#define SPI_ENGINE_CMD_REG_CONFIG 0x01
#define SPI_ENGINE_CMD_DATA_TRANSFER_LEN 0x02
#define SPI_ENGINE_MISC_SYNC 0x00
#define SPI_ENGINE_MISC_SLEEP 0x01
#define SPI_ENGINE_SYNC_TRANSFER_BEGIN BIT(1)
#define SPI_ENGINE_SYNC_TRANSFER_END BIT(2)
#define SPI_ENGINE_INT_CMD_ALMOST_EMPTY BIT(0)
#define SPI_ENGINE_INT_SDO_ALMOST_EMPTY BIT(1)
#define SPI_ENGINE_INT_SDI_ALMOST_FULL BIT(2)
#define SPI_ENGINE_INT_SYNC BIT(3)
#define SPI_ENGINE_OFFLOAD_CTRL_ENABLE BIT(0)
#define SPI_ENGINE_OFFLOAD_STATUS_ENABLED BIT(0)
#define SPI_ENGINE_CONFIG_CPHA BIT(0)
#define SPI_ENGINE_CONFIG_CPOL BIT(1)
#define SPI_ENGINE_CONFIG_3WIRE BIT(2)
#define SPI_ENGINE_VERSION_MAJOR(x) ((x >> 16) & 0xff)
#define SPI_ENGINE_VERSION_MINOR(x) ((x >> 8) & 0xff)
#define SPI_ENGINE_VERSION_PATCH(x) (x & 0xff)
/******************************************************************************/
/**************************** Spi Engine commands *****************************/
/******************************************************************************/
#define SPI_ENGINE_INSTRUCTION_TRANSFER_W 0x01
#define SPI_ENGINE_INSTRUCTION_TRANSFER_R 0x02
#define SPI_ENGINE_INSTRUCTION_TRANSFER_RW 0x03
#define SPI_ENGINE_REG_OFFLOAD_CTRL(x) (0x100 + (0x20 * x))
#define SPI_ENGINE_REG_OFFLOAD_STATUS(x) (0x104 + (0x20 * x))
#define SPI_ENGINE_REG_OFFLOAD_RESET(x) (0x108 + (0x20 * x))
#define SPI_ENGINE_REG_OFFLOAD_CMD_MEM(x) (0x110 + (0x20 * x))
#define SPI_ENGINE_REG_OFFLOAD_SDO_MEM(x) (0x114 + (0x20 * x))
#define SPI_ENGINE_CMD(inst, arg1, arg2) \
(((inst & 0x03) << 12) | \
((arg1 & 0x03) << 8) | arg2 )
#define SPI_ENGINE_CMD_TRANSFER(readwrite, n) \
SPI_ENGINE_CMD(SPI_ENGINE_INST_TRANSFER, \
(readwrite), (n))
#define SPI_ENGINE_CMD_ASSERT(delay, cs) \
SPI_ENGINE_CMD(SPI_ENGINE_INST_ASSERT, \
(delay), (cs))
#define SPI_ENGINE_CMD_CONFIG(reg, val) \
SPI_ENGINE_CMD(SPI_ENGINE_INST_CONFIG, \
(reg), (val))
#define SPI_ENGINE_CMD_SLEEP(delay) \
SPI_ENGINE_CMD(SPI_ENGINE_INST_MISC, \
SPI_ENGINE_MISC_SLEEP, \
(delay))
#define SPI_ENGINE_CMD_SYNC(id) \
SPI_ENGINE_CMD(SPI_ENGINE_INST_MISC, \
SPI_ENGINE_MISC_SYNC, \
(id))
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
typedef struct spi_engine_cmd_queue {
uint32_t cmd;
struct spi_engine_cmd_queue *next;
} spi_engine_cmd_queue;
typedef struct spi_engine_msg {
uint32_t *tx_buf;
uint32_t *rx_buf;
uint32_t tx_length;
uint32_t rx_length;
struct spi_engine_cmd_queue *cmds;
} spi_engine_msg;
#endif // SPI_ENGINE_PRIVATE_H
@@ -0,0 +1,783 @@
/**
* \file ad9528.c
* \brief Contains source code for configuring and initializing AD9528 clock device
*/
/**
* \page Disclaimer Legal Disclaimer
* Copyright 2015-2017 Analog Devices Inc.
* Released under the AD9371 API license.
*
*/
#include <stdlib.h>
#include <stdio.h>
#include "ad9528.h"
#include "../../../include/error.h"
static uint32_t _desired_time_to_elapse_ms = 0;
/**
* \brief Write data to a register
*/
int32_t AD9528_spiWriteByte(ad9528Device_t *device, uint16_t addr,
uint8_t data)
{
uint8_t buf[3];
int32_t status;
buf[0] = (addr >> 8) & 0x7F;
buf[1] = addr & 0xFF;
buf[2] = data;
status = spi_write_and_read_3wire(device->spi_desc,
buf, NULL, 3, 0);
return status;
}
/**
* \brief Read data from a register
*/
int32_t AD9528_spiReadByte(ad9528Device_t *device, uint16_t addr,
uint8_t *readdata)
{
uint8_t tx_buf[2];
uint8_t rx_buf[1];
int32_t status;
tx_buf[0] = 0x80 | addr >> 8;
tx_buf[1] = addr & 0xFF;
status = spi_write_and_read_3wire(device->spi_desc,
tx_buf, rx_buf, 2, 1);
*readdata = rx_buf[0];
return status;
}
/**
* \brief Modify a field of bits from a register
*/
int32_t AD9528_spiWriteField(ad9528Device_t *device,
uint16_t addr, uint8_t fieldVal, uint8_t mask, uint8_t startBit)
{
int32_t errVal;
uint8_t readVal;
errVal = AD9528_spiReadByte(device, addr, &readVal);
if (errVal < 0)
return errVal;
readVal = (readVal & ~mask) | ((fieldVal << startBit) & mask);
return AD9528_spiWriteByte(device, addr, readVal);
}
/**
* \brief Set the desired timeout value
*/
int32_t AD9528_setTimeout_ms(uint32_t timeOut_ms)
{
_desired_time_to_elapse_ms = timeOut_ms;
return SUCCESS;
}
/**
* \brief Verify if the desired time has elapsed
*/
int32_t AD9528_hasTimeoutExpired()
{
udelay(1000);
_desired_time_to_elapse_ms--;
if (_desired_time_to_elapse_ms > 0)
return SUCCESS;
return FAILURE;
}
/**
* \brief Performs a hard reset on the AD9528 DUT
*
* <B>Dependencies</B>
* - device->spiSettings->chipSelectIndex
*
* \param device is structure pointer to the AD9528 data structure containing settings
* \return Returns enum ADI_ERR, ADIERR_OK=pass, !ADIERR_OK=fail
*/
int32_t AD9528_resetDevice(ad9528Device_t *device)
{
gpio_direction_output(device->gpio_resetb, 0);
mdelay(100);
gpio_direction_output(device->gpio_resetb, 1);
mdelay(100);
AD9528_spiWriteByte(device, AD9528_ADDR_ADI_SPI_CONFIG_A, 0x81);
mdelay(100);
AD9528_spiWriteByte(device, AD9528_ADDR_ADI_SPI_CONFIG_A, 0x00);
mdelay(100);
return SUCCESS;
}
/**
* \brief Sets the AD9528 device SPI settings (3wire/4wire, MSBFirst, etc).
*
* This function will use the settings in the device->spiSettings structure
* to set SPI stream mode, address auto increment direction, MSBFirst/LSBfirst,
* and 3wire/4wire mode. The AD9528 device always uses SPI MODE 0 (CPHA=0, CPOL=0).
* This function will update your device->spiSettings to set CHPA=0 and CPOL=0 and
* longInstructionWord =1 to use a 16bit instruction word.
*
* <B>Dependencies</B>
* - writes device->spiSettings->CPHA = 0
* - writes device->spiSettings->CPOL = 0
* - writes device->spiSettings->longInstructionWord = 1
*
* - device->spiSettings->MSBFirst
* - device->spiSettings->enSpiStreaming
* - device->spiSettings->autoIncAddrUp
* - device->spiSettings->fourWireMode
*
* \param device is structure pointer to the AD9528 data structure containing settings
*
* \return Returns enum ADI_ERR, ADIERR_OK=pass, !ADIERR_OK=fail
*/
int32_t AD9528_setSpiSettings(ad9528Device_t *device)
{
uint8_t spiReg = 0;
device->spiSettings->CPHA = 0;
device->spiSettings->CPOL = 0;
device->spiSettings->longInstructionWord = 1;
if (device->spiSettings->MSBFirst == 0) {
spiReg |= 0x42; /* SPI bit is 1=LSB first */
}
if (device->spiSettings->autoIncAddrUp > 0) {
spiReg |= 0x24;
}
if (device->spiSettings->fourWireMode > 0) {
spiReg |= 0x18;
}
AD9528_spiWriteByte(device, AD9528_ADDR_ADI_SPI_CONFIG_A, spiReg);
if (device->spiSettings->enSpiStreaming > 0) {
/* Allow SPI streaming mode: SPI message ends when chip select deasserts */
AD9528_spiWriteByte(device, AD9528_ADDR_ADI_SPI_CONFIG_B, 0x00);
} else {
/* Force single instruction mode */
AD9528_spiWriteByte(device, AD9528_ADDR_ADI_SPI_CONFIG_B, 0x80);
}
return SUCCESS;
}
/**
* \brief Helper function for ADI transceiver eval boards to init the AD9528 data structure
*
* This function inits the AD9528 device data structure with defaults that
* are known to work with the ADI AD9369 and AD9371 evaluation boards. NOTE: This function will
* modify the contents of the AD9528 device data structure.
*
* <B>Dependencies</B>
* - spi->chipSelectIndex
* - spi
*
* \param device Pointer to the AD9528 device data structure to initialize
* \param vcxoFrequency_Hz The VCXO frequency that is connected to the AD9528
* \param refAFrequency_Hz The reference clock frequency being input into the AD9528 REFCLK A input
* \param outputDeviceClock_Hz Desired output clock frequency to the FPGA and transceiver device
*
* \return Returns enum ADI_ERR, 0=pass, >0 = fail
*/
int32_t AD9528_initDeviceDataStruct(ad9528Device_t *device,
uint32_t vcxoFrequency_Hz, uint32_t refAFrequency_Hz,
uint32_t outputDeviceClock_Hz)
{
// uint16_t chDiv;
// uint8_t i = 0;
//
// uint32_t pll1PfdFreq_Hz = 0;
// uint8_t pll1Ndiv = 0;
// uint8_t validPll1DivSetting = 0;
// uint8_t refAdiv = 1;
//
//
// uint8_t pll2RfDiv = 3; /* Valid values 3,4,5 */
// uint16_t pll2Ndiv = 1; /* Valid values 1-256 */
// uint32_t pll2InputFreq_Hz = 0;
// uint64_t pll2VcoFreq_Hz = 0;
// uint16_t pll2NdivStart = 0;
// uint8_t validPll2DivSetting = 0;
// uint64_t chDivU64 = 0;
//
// static const uint64_t PLL2_MIN_VCO_FREQ_HZ = 3450000000ULL;
// static const uint64_t PLL2_MAX_VCO_FREQ_HZ = 4025000000ULL;
// struct spi_init_param spi_param;
// int32_t status;
//
// status = gpio_get(&device->gpio_resetb, CLK_RESETB);
// status |= gpio_get(&device->gpio_sysref_req, ADRV_SYSREF_REQ);
//
// spi_param.id = 0;
// spi_param.mode = SPI_MODE_0;
// spi_param.chip_select = CLK_CS;
// status |= spi_init(&device->spi_desc, &spi_param);
//
// if (status != SUCCESS)
// return FAILURE;
/*******************************************************************
* PLL1 Settings
*******************************************************************
*/
/* find valid PLL1 Ndiv and REFA div */
// for (pll1Ndiv = 1; pll1Ndiv < 20; pll1Ndiv++) {
// pll1PfdFreq_Hz = vcxoFrequency_Hz / pll1Ndiv;
//
// if ((pll1PfdFreq_Hz <= 110000000) && (pll1PfdFreq_Hz >= 1000000) &&
// (pll1PfdFreq_Hz <= refAFrequency_Hz) &&
// (refAFrequency_Hz % pll1PfdFreq_Hz == 0)
// ) {
// validPll1DivSetting = 1;
// refAdiv = refAFrequency_Hz / pll1PfdFreq_Hz ;
// break;
// }
// }
//
// if (validPll1DivSetting == 0) {
// return FAILURE;
// }
// device->pll1Settings->nDivider =
// pll1Ndiv; //This init function always runs PLL1 at 30.72MHz Pfd rate
// device->pll1Settings->refA_bufferCtrl =
// DIFFERENTIAL; //DISABLED = 0, SINGLE_ENDED, NEG_SINGLE_ENDED, DIFFERENTIAL
// device->pll1Settings->refA_Divider = refAdiv;
// device->pll1Settings->refA_Frequency_Hz = refAFrequency_Hz;
// device->pll1Settings->refB_bufferCtrl =
// DISABLED; //DISABLED = 0, SINGLE_ENDED, NEG_SINGLE_ENDED, DIFFERENTIAL
// device->pll1Settings->refB_Divider = 1;
// device->pll1Settings->refB_Frequency_Hz = 0;
// device->pll1Settings->vcxoBufferCtrl =
// NEG_SINGLE_ENDED; //DISABLED = 0, SINGLE_ENDED, NEG_SINGLE_ENDED, DIFFERENTIAL
// device->pll1Settings->vcxo_Frequency_Hz = vcxoFrequency_Hz;
/*******************************************************************
* PLL2 Settings
*******************************************************************
*/
/*******************************************************************
* Output Distribution Settings
* 9369CE02A uses the following clock outputs
* OUT 1: FPGA REFCLK
* OUT 3: FPGA SYSREF
* OUT 12: DUT SYSREF
* OUT 13: DUT REFCLK
*******************************************************************
*/
/* PLL 2 input clock can be several different things. Currently hard coded by this init funciton to use
* PLL 1 output (VCXO Frequency) with no scaling
*/
// pll2InputFreq_Hz = device->pll1Settings->vcxo_Frequency_Hz;
// validPll2DivSetting = 0;
/* Sweep PLL2 Divider settings to find something that has a valid integer divide (3,4,5)*/
// for (pll2RfDiv = 3; pll2RfDiv <= 5; pll2RfDiv++) {
//
// pll2NdivStart = (PLL2_MIN_VCO_FREQ_HZ / pll2RfDiv / pll2InputFreq_Hz);
// /* find valid PLL2 Ndiv (1-256) */
// for (pll2Ndiv = pll2NdivStart; pll2Ndiv <= 256; pll2Ndiv++) {
// pll2VcoFreq_Hz = (pll2InputFreq_Hz * pll2RfDiv * pll2Ndiv);
//
// if (pll2VcoFreq_Hz < PLL2_MIN_VCO_FREQ_HZ) {
// /* Continue to next PLL2 N div */
// continue;
// } else if (pll2VcoFreq_Hz > PLL2_MAX_VCO_FREQ_HZ) {
// /* Break to next PLL2 RF div */
// break;
// }
//
// if (((pll2VcoFreq_Hz / pll2RfDiv) % outputDeviceClock_Hz) == 0) {
//
// device->pll2Settings->rfDivider = pll2RfDiv;
// device->pll2Settings->n2Divider = pll2Ndiv;
// device->pll2Settings->totalNdiv = pll2RfDiv * pll2Ndiv;
// chDivU64 = ((pll2VcoFreq_Hz / pll2RfDiv) / outputDeviceClock_Hz);
//
// if ((chDivU64 < 1) || (chDivU64 > 256)) {
// return FAILURE;
// } else {
// chDiv = (uint16_t)(chDivU64);
// }
//
// validPll2DivSetting = 1;
// break;
// }
// }
//
// if (validPll2DivSetting == 1) {
// break;
// }
// }
//
// if (validPll2DivSetting == 0) {
// return FAILURE;
// }
//
// device->outputSettings->outPowerDown = (uint16_t)(
// ~0x318A); //enable outputs 13,12,8,7,3 and 1
//
// for (i=0; i<14; i++) {
// device->outputSettings->outSource[i] =
// CHANNEL_DIV; //CHANNEL_DIV , PLL1_OUTPUT, SYSREF, INV_PLL1_OUTPUT
// device->outputSettings->outBufferCtrl[i] = LVDS; //LVDS, LVDS_BOOST, HSTL
// device->outputSettings->outChannelDiv[i] = chDiv;
// device->outputSettings->outFrequency_Hz[i] = outputDeviceClock_Hz;
// device->outputSettings->outAnalogDelay[i] = 0;
// device->outputSettings->outDigitalDelay[i] = 0;
// }
//
//
// device->outputSettings->outSource[3] = SYSREF;
// device->outputSettings->outSource[7] = SYSREF;
// device->outputSettings->outSource[12] = SYSREF;
//
//
// device->sysrefSettings->sysrefDivide =
// 512; //SYSREF frequency = VCXO / 2 / sysrefDivde
// device->sysrefSettings->sysrefNshotMode =
// ONE_PULSE; //ONE_PULSE=0, TWO_PULSES=2, FOUR_PULSES=3, SIX_PULSES=4, EIGHT_PULSES=5
// device->sysrefSettings->sysrefPatternMode =
// CONTINUOUS; //NSHOT=0, CONTINUOUS=1, PRBS=2, STOP=3
// device->sysrefSettings->sysrefPinBufferMode =
// DISABLED; //DISABLED = 0, SINGLE_ENDED, NEG_SINGLE_ENDED, DIFFERENTIAL
// device->sysrefSettings->sysrefPinEdgeMode =
// LEVEL_ACTIVE_HIGH; //LEVEL_ACTIVE_HIGH=0, LEVEL_ACTIVE_LOW=1, RISING_EDGE=2, FALLING_EDGE=3
// device->sysrefSettings->sysrefRequestMethod = PIN; //SPI=0,PIN=1
// device->sysrefSettings->sysrefSource =
// INTERNAL; //EXTERNAL=0, EXT_RESAMPLED=1, INTERNAL=2
return SUCCESS;
}
int32_t AD9528_init(ad9528Device_t **device, const ad9528Init_t *init_device)
{
int ret = SUCCESS;
ad9528Device_t *dev;
dev = (ad9528Device_t *)malloc(sizeof(*dev));
if (!dev)
return FAILURE;
/* SPI */
ret = spi_init(&dev->spi_desc, init_device->spi_init);
ret |= gpio_get(&dev->gpio_resetb, init_device->gpio_init_resetb);
ret |= gpio_get(&dev->gpio_sysref_req, init_device->gpio_init_sysref_req);
gpio_direction_output(dev->gpio_resetb, 0);
gpio_direction_output(dev->gpio_sysref_req, 0);
AD9528_resetDevice(dev);
dev->spiSettings = init_device->spiSettings;
dev->pll1Settings = init_device->pll1Settings;
dev->pll2Settings = init_device->pll2Settings;
dev->outputSettings = init_device->outputSettings;
dev->sysrefSettings = init_device->sysrefSettings;
*device = dev;
return ret;
}
/**
* \brief Initializes the AD9528 by writing all SPI registers
*
* Initializes the AD9528 for use with the AD9369 transceiver. Designed to work with
* a reference clock of 122.88MHz. Reference clock is expected to be 30.72MHz.
* The output clocks from the AD9528 can run at 122.88M, 153.6M, 184.32M, 245.76M, or 307.2M.
* Typical setup: REFA frequency = 30.72, VCXO = 122.88MHz
* SYNC(SYSREF) pulses output at rate of 120kHz
*
* <B>Dependencies</B>
* - All parameters in device structure
*
* \param device is structure pointer to AD9528 clock device structure
*
* \return Returns enum ADI_ERR, 0=pass, >0 = fail
*/
int32_t AD9528_config(ad9528Device_t
*device) //writes all registers to desired values, leaves clock outputs off, SYSREF output disabled.
{
uint8_t pll2_Adiv=0;
uint8_t pll2_Bdiv=0;
uint8_t reg108=0;
uint8_t reg109=0x4;
uint8_t i = 0;
uint8_t j = 0;
uint8_t reg508;
int32_t retval = SUCCESS;
retval = AD9528_setSpiSettings(device);
if (retval != SUCCESS) {
return retval;
}
/**********************************************************************
* Configure PLL1
**********************************************************************
*/
AD9528_spiWriteByte(device, AD9528_ADDR_REF_A_DIVIDER_LSB,
device->pll1Settings->refA_Divider & 0xFF); //REF A div[7:0]
AD9528_spiWriteByte(device, AD9528_ADDR_REF_A_DIVIDER_MSB,
(device->pll1Settings->refA_Divider >> 8) & 0x03); //REF A div[9:8]
AD9528_spiWriteByte(device, AD9528_ADDR_REF_B_DIVIDER_LSB,
device->pll1Settings->refB_Divider & 0xFF); //REF B div[7:0]
AD9528_spiWriteByte(device, AD9528_ADDR_REF_B_DIVIDER_MSB,
(device->pll1Settings->refB_Divider >> 8) & 0x03); //REF B div[9:8]
AD9528_spiWriteByte(device, AD9528_ADDR_PLL1_N_DIV_LSB,
device->pll1Settings->nDivider & 0xFF); //PLL1 N div[7:0]
AD9528_spiWriteByte(device, AD9528_ADDR_PLL1_N_DIV_MSB,
(device->pll1Settings->nDivider >> 8) & 0x03); //PLL1 N div[9:8]
AD9528_spiWriteByte(device, AD9528_ADDR_PLL1_CHARGEPUMP,
0x0A); //PLL1 Charge Pump control 1
AD9528_spiWriteByte(device, AD9528_ADDR_PLL1_CP_CTRL2,
0x03); //PLL1 Charge Pump control 2
switch (device->pll1Settings->refA_bufferCtrl) {
case DISABLED:
reg108 &= ~0x28;
reg109 &= ~0x01;
break; //clear all REFA enable bits
case SINGLE_ENDED:
reg108 |= 0x08;
reg109 &= ~0x01;
break; //Set REFA receiver enable, clear REFA SE negative input enable
case NEG_SINGLE_ENDED:
reg108 |= 0x08;
reg108 &= ~0x10;
reg109 |= 0x01;
break; //Disable REFA diff receiver, enable REFA receiver and use negative REFA input
case DIFFERENTIAL:
reg108 |= 0x28;
reg109 &= ~0x01;
break;
default:
reg108 |= 0x08;
reg109 &= ~0x01;
break; //default to single ended case
}
switch (device->pll1Settings->refB_bufferCtrl) {
case DISABLED:
reg108 &= ~0x50;
reg109 &= ~0x02;
break; //clear all REFB enable bits
case SINGLE_ENDED:
reg108 |= 0x10;
reg109 &= ~0x02;
break; //Set REFB receiver enable, clear REFB SE negative input enable
case NEG_SINGLE_ENDED:
reg108 |= 0x10;
reg108 &= ~0x40;
reg109 |= 0x02;
break; //Disable REFB diff receiver, enable REFB receiver and use negative REFB input
case DIFFERENTIAL:
reg108 |= 0x50;
reg109 &= ~0x02;
break;
default:
reg108 |= 0x10;
reg109 &= ~0x02;
break; //default to single ended case
}
switch (device->pll1Settings->vcxoBufferCtrl) {
case DISABLED:
reg108 &= ~0x03;
reg108 |= 0x04;
break; //power down VCXO input
case SINGLE_ENDED:
reg108 &= ~0x07;
break; //Clear VCXO receiver power down, defaults to Single ended mode
case NEG_SINGLE_ENDED:
reg108 &= ~0x07;
reg108 |= 0x02;
break; //Clear VCXO power down, enable Negative single ended mode[1]
case DIFFERENTIAL:
reg108 &= ~0x07;
reg108 |= 0x01;
break; //Clear VCXO power down, enable differential input buffer[0]
default:
reg108 &= ~0x07;
break; //default to positive single ended case
}
AD9528_spiWriteByte(device, AD9528_ADDR_INPUT_RECEIVERS1,
reg108); //Input receiver settings (single ended or differential clock inputs)
AD9528_spiWriteByte(device, AD9528_ADDR_INPUT_RECEIVERS2,
reg109); //Input receiver settings
AD9528_spiWriteByte(device, AD9528_ADDR_INPUT_RECEIVERS3,
0x0A); //Reference selection mode
AD9528_spiWriteByte(device, AD9528_ADDR_PLL1_FASTLOCK,
0x00); //Disable Fast lock
/**********************************************************************
* Configure PLL2
**********************************************************************
*/
pll2_Bdiv = device->pll2Settings->totalNdiv / 4;
pll2_Adiv = device->pll2Settings->totalNdiv % 4;
if (pll2_Adiv > 3) { //A div valid range (0 to 3)
return FAILURE;
}
if (pll2_Bdiv < 3 || pll2_Bdiv > 63) {
return FAILURE;
}
AD9528_spiWriteByte(device, AD9528_ADDR_PLL2_CHARGEPUMP,
0xE6); //PLL2 Charge Pump[7:0]
AD9528_spiWriteByte(device, AD9528_ADDR_PLL2_N_DIV,
((pll2_Adiv & 0x3) << 6) | (pll2_Bdiv & 0x3F)); //PLL2 A and B divider
AD9528_spiWriteByte(device, AD9528_ADDR_PLL2_CTRL, 0x03); //PLL2 control
AD9528_spiWriteByte(device, AD9528_ADDR_PLL2_VCO_CTRL, 0x01); //Manual VCO CAL
if (device->pll2Settings->rfDivider < 3
|| device->pll2Settings->rfDivider > 5) {
return FAILURE;
}
AD9528_spiWriteByte(device, AD9528_ADDR_PLL2_VCO_DIV,
device->pll2Settings->rfDivider); //VCO divider
AD9528_spiWriteByte(device, AD9528_ADDR_PLL2_LF_CTRL1,
0x3A); //PLL2 Loop filter [7:0]
AD9528_spiWriteByte(device, AD9528_ADDR_PLL2_LF_CTRL2,
0x00); //PLL2 Loop filter [8]
AD9528_spiWriteByte(device, AD9528_ADDR_PLL2_RDIV, 0x01); //R divider
AD9528_spiWriteByte(device, AD9528_ADDR_PLL2_REPLICA_CHDIV,
(device->pll2Settings->totalNdiv / device->pll2Settings->rfDivider)
-1 ); //Replica channel divider: Ndivider = rfDivider * R divider
AD9528_spiWriteByte(device, AD9528_ADDR_PLL2_REPLICA_DIV_PHASE,
0x00); //Replica Channel Divider phase
/**********************************************************************
* Configure Output Distribution
**********************************************************************
*/
for (i=0; i<14; i=i+1) {
AD9528_spiWriteByte(device, AD9528_ADDR_CH_OUT0_CTRL1 + j,
((device->outputSettings->outSource[i] & 0x7) << 5) |
(device->outputSettings->outAnalogDelay[i] & 0x1F));
AD9528_spiWriteByte(device, AD9528_ADDR_CH_OUT0_CTRL2 + j,
((device->outputSettings->outBufferCtrl[i] & 0x3) << 6) |
(device->outputSettings->outDigitalDelay[i] & 0x3F));
AD9528_spiWriteByte(device, AD9528_ADDR_CH_OUT0_CHDIV + j,
device->outputSettings->outChannelDiv[i]-1);
j = j+3;
}
AD9528_spiWriteByte(device, AD9528_ADDR_OUTPUT_SYNC, 0x00); //Sync outputs
AD9528_spiWriteByte(device, AD9528_ADDR_MASK_SYNC1, 0x00); //Mask SYNC[7:0]
AD9528_spiWriteByte(device, AD9528_ADDR_MASK_SYNC2, 0x00); //Mask SYNC[13:8]
AD9528_spiWriteByte(device, AD9528_ADDR_EN_OUTPUT_PATH_SEL1,
0x00); //Bypass SYSREF resample [6:0], bit0:Enable VCXO to feed output distrubution
AD9528_spiWriteByte(device, AD9528_ADDR_EN_OUTPUT_PATH_SEL2,
0x00); //Bypass SYSREF resample [13:7]
/**********************************************************************
* Configure SYSREF operation
**********************************************************************
*/
AD9528_spiWriteByte(device, AD9528_ADDR_SYSERF_DIV_LSB,
device->sysrefSettings->sysrefDivide & 0xFF); //SYSREF divider [7:0]
AD9528_spiWriteByte(device, AD9528_ADDR_SYSERF_DIV_MSB,
(device->sysrefSettings->sysrefDivide >> 8) & 0xFF); //SYSREF divider [7:0]
AD9528_spiWriteByte(device, AD9528_ADDR_SYSREF_CTRL3,
((device->sysrefSettings->sysrefRequestMethod & 0x1) << 7) |
((device->sysrefSettings->sysrefPinEdgeMode & 0x3) << 5) );
AD9528_spiWriteByte(device, AD9528_ADDR_SYSREF_CTRL4,
((device->sysrefSettings->sysrefSource & 0x03) << 6) |
((device->sysrefSettings->sysrefPatternMode & 0x3) << 4 ) |
((device->sysrefSettings->sysrefNshotMode & 0x7) << 1) );
if(device->sysrefSettings->sysrefPinBufferMode == DISABLED) {
AD9528_spiWriteByte(device, AD9528_ADDR_SYSREF_CTRL5,
0x04); //power down input buffer for external SYSREF
} else if(device->sysrefSettings->sysrefPinBufferMode == SINGLE_ENDED) {
AD9528_spiWriteByte(device, AD9528_ADDR_SYSREF_CTRL5,
0x00); //enable positive singled ended input
} else if(device->sysrefSettings->sysrefPinBufferMode == NEG_SINGLE_ENDED) {
AD9528_spiWriteByte(device, AD9528_ADDR_SYSREF_CTRL5,
0x02); //enable negative singled ended input
} else if(device->sysrefSettings->sysrefPinBufferMode == DIFFERENTIAL) {
AD9528_spiWriteByte(device, AD9528_ADDR_SYSREF_CTRL5,
0x01); //enable differential input buffer
} else {
AD9528_spiWriteByte(device, AD9528_ADDR_SYSREF_CTRL5,
0x04); //power down input buffer for external SYSREF
}
/**********************************************************************
* Power down control
**********************************************************************
*/
if (device->pll1Settings->bypassPll1 > 0) {
AD9528_spiWriteByte(device, AD9528_ADDR_POWERDOWN_CTRL,
0x14);// power up PLL2 and output distribution, power down PLL1
} else {
AD9528_spiWriteByte(device, AD9528_ADDR_POWERDOWN_CTRL,
0x10);// power up PLL1, PLL2 and output distribution
}
AD9528_spiWriteByte(device, AD9528_ADDR_CH_POWERDOWN1,
device->outputSettings->outPowerDown & 0xFF); //power down out[7:0]
AD9528_spiWriteByte(device, AD9528_ADDR_CH_POWERDOWN2,
((device->outputSettings->outPowerDown >> 8) & 0x3F)); //power down out[13:8]
AD9528_spiWriteByte(device, AD9528_ADDR_LDO_ENABLES1,
0xFF); //LDO enable per output channel [7:0]
AD9528_spiWriteByte(device, AD9528_ADDR_LDO_ENABLES2,
0xFF); //LDO enable per output channel [15:8]
AD9528_spiWriteByte(device, AD9528_ADDR_STATUS0_CTRL,
0x07); //STATUS 0 outputs REFA present
AD9528_spiWriteByte(device, AD9528_ADDR_STATUS1_CTRL,
0x01); //STATUS 1 outputs PLL1 and PLL2 locked
AD9528_spiWriteByte(device, AD9528_ADDR_STATUS_OE,
0x0C);// Make Status0 and Status1 outputs after reset.
AD9528_spiWriteByte(device, AD9528_ADDR_IO_UPDATE,
0x01); //IO update to make all these settings valid in the 9528
AD9528_setTimeout_ms(1000);
do {
AD9528_spiReadByte(device, AD9528_ADDR_STATUS_READBACK0, &reg508);
if(AD9528_hasTimeoutExpired() > 0) {
return FAILURE;
}
} while((reg508 & 0x26) != 0x26);
return SUCCESS;
}
/// Send a SPI message to request a SYSREF pulse or continuous SYSREF from the AD9528.
/*******************************************************************************//**
* Requests a SYSREF from the AD9528. It will use whatever settings for SYSREF
* that are current configured in the AD9528. This could be a single pulse,
* multiple pulses, or continuous pulses.
* <B>Dependencies</B>
* - device->spiSettings
* - device->sysrefSettings->sysrefPatternMode
*
* \param device is structure pointer to AD9528 clock device structure
* \param enableSYSREF If NSHOT SYSREF mode, this parameter is ignored. If PRBS/CONTINUOUS SYSREF mode, 1= enable SYSREF, 0= disable SYSREF.
*
* \return Returns enum ADI_ERR, 0=pass, >0 = fail
***********************************************************************************/
int32_t AD9528_requestSysref(ad9528Device_t *device, uint8_t enableSYSREF)
{
uint8_t _enableSYSREF=0;
if (device->sysrefSettings->sysrefPatternMode == NSHOT || enableSYSREF > 0) {
_enableSYSREF = 1;
} else {
_enableSYSREF = 0;
}
AD9528_spiWriteField(device, AD9528_ADDR_SYSREF_CTRL4, _enableSYSREF, 0x01,
0x00); //Set SPI SYSREF request bit
AD9528_spiWriteByte(device, AD9528_ADDR_IO_UPDATE,
0x01); //IO update to make all these settings valid in the 9528
return SUCCESS;
}
/// Allow changing the 9528 SYSREF frequency and pattern mode(CONTINUOUS, PRBS vs NSHOT mode)
/*******************************************************************************//**
* NOTE: this function will update the device structure with the parameter values passed
* into this function. The device->sysrefSettings->sysrefPatternMode, device->sysrefSettings->sysrefNshotMode,
* and device->sysrefSettings->sysrefDivide values will be updated in the device structure.
*
* <B>Dependencies</B>
* - device->spiSettings
*
* \param device is structure pointer to AD9528 clock device structure
* \param divideFromPll1Out Sets the SYSREF pulse frequency. SYSREF frequency = PLL1_VCXO frequency/divideFromPll1Out
* \param sysrefPatternMode Valid settings: NSHOT, CONTINUOUS, PRBS, STOP
* \param nShotPulses Valid settings: ONE_PULSE=0, TWO_PULSES=2, FOUR_PULSES=3, SIX_PULSES=4, EIGHT_PULSES=5
*
* \return Returns enum ADI_ERR, 0=pass, >0 = fail
***********************************************************************************/
int32_t AD9528_setupSYSREF(ad9528Device_t *device,
uint16_t divideFromPll1Out, sysrefPatternMode_t sysrefPatternMode,
sysrefNshotMode_t nShotPulses)
{
uint8_t reg403=0;
device->sysrefSettings->sysrefPatternMode = sysrefPatternMode;
device->sysrefSettings->sysrefNshotMode = nShotPulses;
device->sysrefSettings->sysrefDivide = divideFromPll1Out >>
1; //SYSREF frequency is (PLL1)VCXO frequency / 2 / device->sysrefSettings->sysrefDivide
AD9528_spiReadByte(device, AD9528_ADDR_SYSREF_CTRL4, &reg403);
reg403 = reg403 & ~0x01; //clear bit 0 to stop a continuous sysref if it is on.
AD9528_spiWriteByte(device, AD9528_ADDR_SYSREF_CTRL4, reg403);
reg403 = reg403 & ~0x3E; //clear bits for pattern mode and Nshot mode bitfields
reg403 = reg403 | ((sysrefPatternMode & 0x3) << 4) | ((nShotPulses & 0x7) << 1);
AD9528_spiWriteByte(device, AD9528_ADDR_SYSREF_CTRL4,
reg403); //update internal sysref pattern mode and Nshot mode (number of pulses)
//SYSREF request bit x403[0] is left 0. The next call to AD9528_requestSysref will start the SYSREF
AD9528_spiWriteByte(device, AD9528_ADDR_IO_UPDATE,
0x01); //IO update to make all these settings valid in the 9528
return SUCCESS;
}
int32_t AD9528_sysrefReq(ad9528Device_t *device,
ad9528SysrefReqMode_t mode)
{
if (mode == SYSREF_CONT_ON)
gpio_direction_output(device->gpio_sysref_req, 1);
else if (mode == SYSREF_CONT_OFF)
gpio_direction_output(device->gpio_sysref_req, 0);
else if (mode == SYSREF_PULSE) {
gpio_direction_output(device->gpio_sysref_req, 1);
mdelay(1);
gpio_direction_output(device->gpio_sysref_req, 0);
} else
return FAILURE;
return SUCCESS;
}
/**
* \brief Free the allocated resources
*/
int32_t AD9528_remove(ad9528Device_t *device)
{
int32_t status;
status = gpio_remove(device->gpio_resetb);
status |= gpio_remove(device->gpio_sysref_req);
status |= spi_remove(device->spi_desc);
return SUCCESS;
}
@@ -0,0 +1,245 @@
/**
* \file ad9528.h
* \brief Contains function declarations and ad9528Device_t structure typedef for ad9528.c
*/
/**
* \page Disclaimer Legal Disclaimer
* Copyright 2015-2017 Analog Devices Inc.
* Released under the AD9371 API license.
*
*/
#ifndef _AD9528_H_
#define _AD9528_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdint.h>
#include "delay.h"
#include "spi.h"
#include "gpio.h"
/******************************************************************************/
/********************** Macros and Constants Definitions **********************/
/******************************************************************************/
/* AD9528 SPI Address defines */
#define AD9528_ADDR_ADI_SPI_CONFIG_A 0x000
#define AD9528_ADDR_ADI_SPI_CONFIG_B 0x001
#define AD9528_ADDR_IO_UPDATE 0x00F
#define AD9528_ADDR_REF_A_DIVIDER_LSB 0x100
#define AD9528_ADDR_REF_A_DIVIDER_MSB 0x101
#define AD9528_ADDR_REF_B_DIVIDER_LSB 0x102
#define AD9528_ADDR_REF_B_DIVIDER_MSB 0x103
#define AD9528_ADDR_PLL1_N_DIV_LSB 0x104
#define AD9528_ADDR_PLL1_N_DIV_MSB 0x105
#define AD9528_ADDR_PLL1_CHARGEPUMP 0x106
#define AD9528_ADDR_PLL1_CP_CTRL2 0x107
#define AD9528_ADDR_INPUT_RECEIVERS1 0x108
#define AD9528_ADDR_INPUT_RECEIVERS2 0x109
#define AD9528_ADDR_INPUT_RECEIVERS3 0x10A
#define AD9528_ADDR_PLL1_FASTLOCK 0x10B
#define AD9528_ADDR_PLL2_CHARGEPUMP 0x200
#define AD9528_ADDR_PLL2_N_DIV 0x201
#define AD9528_ADDR_PLL2_CTRL 0x202
#define AD9528_ADDR_PLL2_VCO_CTRL 0x203
#define AD9528_ADDR_PLL2_VCO_DIV 0x204
#define AD9528_ADDR_PLL2_LF_CTRL1 0x205
#define AD9528_ADDR_PLL2_LF_CTRL2 0x206
#define AD9528_ADDR_PLL2_RDIV 0x207
#define AD9528_ADDR_PLL2_REPLICA_CHDIV 0x208
#define AD9528_ADDR_PLL2_REPLICA_DIV_PHASE 0x209
#define AD9528_ADDR_CH_OUT0_CTRL1 0x300
#define AD9528_ADDR_CH_OUT0_CTRL2 0x301
#define AD9528_ADDR_CH_OUT0_CHDIV 0x302
#define AD9528_ADDR_OUTPUT_SYNC 0x32A
#define AD9528_ADDR_MASK_SYNC1 0x32B
#define AD9528_ADDR_MASK_SYNC2 0x32C
#define AD9528_ADDR_EN_OUTPUT_PATH_SEL1 0x32D
#define AD9528_ADDR_EN_OUTPUT_PATH_SEL2 0x32E
#define AD9528_ADDR_SYSERF_DIV_LSB 0x400
#define AD9528_ADDR_SYSERF_DIV_MSB 0x401
#define AD9528_ADDR_SYSREF_CTRL3 0x402
#define AD9528_ADDR_SYSREF_CTRL4 0x403
#define AD9528_ADDR_SYSREF_CTRL5 0x404
#define AD9528_ADDR_POWERDOWN_CTRL 0x500
#define AD9528_ADDR_CH_POWERDOWN1 0x501
#define AD9528_ADDR_CH_POWERDOWN2 0x502
#define AD9528_ADDR_LDO_ENABLES1 0x503
#define AD9528_ADDR_LDO_ENABLES2 0x504
#define AD9528_ADDR_STATUS0_CTRL 0x505
#define AD9528_ADDR_STATUS1_CTRL 0x506
#define AD9528_ADDR_STATUS_OE 0x507
#define AD9528_ADDR_STATUS_READBACK0 0x508
#define AD9528_ADDR_STATUS_READBACK1 0x509
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
///Enum to select what source outputs from each AD9528 output channel
typedef enum {
AD9528_CHANNEL_DIV = 0, PLL1_OUTPUT = 1, //VCXO frequency
SYSREF = 2,
INV_PLL1_OUTPUT = 5 //VCXO inverted
} ad9528outSourceSel_t;
///Enum to select what output buffer standard is used for the clock outputs
typedef enum {
AD9528_LVDS = 0, AD9528_LVDS_BOOST = 1, AD9528_HSTL = 2
} ad9528outBufferControl_t;
///Enum to select the clock input buffer mode.
typedef enum {
DISABLED = 0, SINGLE_ENDED, NEG_SINGLE_ENDED, DIFFERENTIAL
} ad9528RefBuffer_t;
/// Structure to hold AD9528 PLL1 settings
typedef struct {
uint32_t refA_Frequency_Hz;
uint16_t refA_Divider;
ad9528RefBuffer_t refA_bufferCtrl;
uint32_t refB_Frequency_Hz;
uint16_t refB_Divider;
ad9528RefBuffer_t refB_bufferCtrl;
uint32_t vcxo_Frequency_Hz;
ad9528RefBuffer_t vcxoBufferCtrl;
uint16_t nDivider;
uint8_t bypassPll1;
} ad9528pll1Settings_t;
/// Structure to hold AD9528 PLL2 settings
typedef struct {
uint8_t rfDivider; //VCO divider: Valid range (3,4,5)
uint8_t n2Divider; //PLL2 N2 Divider
uint8_t totalNdiv; //NDiv = 4*Bdiv + Adiv //Bdiv valid range (3 to 63), Adiv valid range (0-3)
} ad9528pll2Settings_t;
/// Structure to hold AD9528 Output Clock settings
typedef struct {
uint16_t outPowerDown; //bit per output, if 1 power down that output.
ad9528outSourceSel_t
outSource[14]; //CHANNEL_DIV, PLL1_OUTPUT, SYSREF, INV_PLL1_OUTPUT
ad9528outBufferControl_t outBufferCtrl[14]; //LVDS, LVDS_BOOST, HSTL
uint8_t outAnalogDelay[14]; //5 bits
uint8_t outDigitalDelay[14]; //6 bits, 1/2 clock resolution @ channel div input frequency
uint8_t outChannelDiv[14]; //8 bit channel divider
uint32_t outFrequency_Hz[14]; //output clock frequency per clock output
} ad9528outputSettings_t;
///Enum to select the SYSREF output source
typedef enum {
EXTERNAL = 0, EXT_RESAMPLED = 1, INTERNAL = 2
} sysrefSourceSelection_t;
///Enum to choose the SYSREF pattern mode.
typedef enum {
NSHOT = 0, CONTINUOUS = 1, PRBS = 2, STOP = 3
} sysrefPatternMode_t;
///Enum to select the SYSREF input pin mode.
typedef enum {
LEVEL_ACTIVE_HIGH = 0, LEVEL_ACTIVE_LOW = 1, RISING_EDGE = 2, FALLING_EDGE = 3
} sysrefPinEdgeMode_t;
///Enum to select the SYSREF output # of pulses for NSHOT mode.
typedef enum {
ONE_PULSE = 0, TWO_PULSES = 2, FOUR_PULSES = 3, SIX_PULSES = 4, EIGHT_PULSES = 5
} sysrefNshotMode_t;
//Enum to select how a SYSREF is requested.
typedef enum {
SPI = 0, PIN = 1
} sysrefRequestMethod_t;
/// Structure to hold AD9528 SYSREF output settings
typedef struct {
sysrefRequestMethod_t sysrefRequestMethod;
sysrefSourceSelection_t sysrefSource;
sysrefPinEdgeMode_t sysrefPinEdgeMode;
ad9528RefBuffer_t sysrefPinBufferMode;
sysrefPatternMode_t sysrefPatternMode;
sysrefNshotMode_t sysrefNshotMode;
uint16_t sysrefDivide;
} ad9528sysrefSettings_t;
/// Structure to hold AD9528 SPI settings
typedef struct {
uint8_t chipSelectIndex; ///< valid 1~8
uint8_t writeBitPolarity; ///< the level of the write bit of a SPI write instruction word, value is inverted for SPI read operation
uint8_t longInstructionWord; ///< 1 = 16bit instruction word, 0 = 8bit instruction word
uint8_t MSBFirst; ///< 1 = MSBFirst, 0 = LSBFirst
uint8_t CPHA; ///< clock phase, sets which clock edge the data updates (valid 0 or 1)
uint8_t CPOL; ///< clock polarity 0 = clock starts low, 1 = clock starts high
uint8_t enSpiStreaming; ///< Not implemented. SW feature to improve SPI throughput.
uint8_t autoIncAddrUp; ///< Not implemented. For SPI Streaming, set address increment direction. 1= next addr = addr+1, 0:addr = addr-1
uint8_t fourWireMode; ///< 1: Use 4-wire SPI, 0: 3-wire SPI (SDIO pin is bidirectional). NOTE: ADI's FPGA platform always uses 4-wire mode.
uint32_t spiClkFreq_Hz; ///< SPI Clk frequency in Hz (default 25000000), platform will use next lowest frequency that it's baud rate generator can create */
} ad9528spiSettings_t;
/// Structure to hold AD9528 settings
typedef struct {
struct gpio_desc *gpio_resetb;
struct gpio_desc *gpio_sysref_req;
struct spi_desc *spi_desc;
ad9528spiSettings_t *spiSettings;
ad9528pll1Settings_t *pll1Settings;
ad9528pll2Settings_t *pll2Settings;
ad9528outputSettings_t *outputSettings;
ad9528sysrefSettings_t *sysrefSettings;
} ad9528Device_t;
typedef struct {
struct gpio_init_param *gpio_init_resetb;
struct gpio_init_param *gpio_init_sysref_req;
struct spi_init_param *spi_init;
ad9528spiSettings_t *spiSettings;
ad9528pll1Settings_t *pll1Settings;
ad9528pll2Settings_t *pll2Settings;
ad9528outputSettings_t *outputSettings;
ad9528sysrefSettings_t *sysrefSettings;
} ad9528Init_t;
typedef enum {
SYSREF_CONT_ON,
SYSREF_CONT_OFF,
SYSREF_PULSE,
} ad9528SysrefReqMode_t;
/******************************************************************************/
/************************ Functions Declarations ******************************/
/******************************************************************************/
//Helper function to setup the 9528 device data structure specifically for the ADI transceiver evaluation cards
int32_t AD9528_initDeviceDataStruct(ad9528Device_t *device,
uint32_t vcxoFrequency_Hz, uint32_t refAFrequency_Hz,
uint32_t outputDeviceClock_Hz);
int32_t AD9528_spiReadByte(ad9528Device_t *device, uint16_t addr,
uint8_t *readdata);
//AD9528 API functions
int32_t AD9528_hasTimeoutExpired();
int32_t AD9528_resetDevice(ad9528Device_t *device);
int32_t AD9528_init(ad9528Device_t **device, const ad9528Init_t *init_device);
int32_t AD9528_config(ad9528Device_t
*device); //writes all registers to desired values, leaves clock outputs off.
int32_t AD9528_setupSYSREF(ad9528Device_t *device,
uint16_t divideFromPll1Out, sysrefPatternMode_t sysrefPatternMode,
sysrefNshotMode_t nShotPulses);
int32_t AD9528_requestSysref(ad9528Device_t *device, uint8_t enableSYSREF);
int32_t AD9528_sysrefReq(ad9528Device_t *device,
ad9528SysrefReqMode_t mode);
int32_t AD9528_remove(ad9528Device_t *device);
#endif
@@ -0,0 +1,927 @@
/***************************************************************************//**
* @file hmc7044.c
* @brief Implementation of HMC7044, HMC7043 Driver.
* @author DBogdan ([email protected])
********************************************************************************
* Copyright 2018-2020(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 Files **********************************/
/******************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include "hmc7044.h"
#include "../../../include/error.h"
#include "../../../include/util.h"
/******************************************************************************/
/********************** Macros and Constants Definitions **********************/
/******************************************************************************/
#define HMC7044_WRITE (0 << 15)
#define HMC7044_READ (1 << 15)
#define HMC7044_CNT(x) (((x) - 1) << 13)
#define HMC7044_ADDR(x) ((x) & 0xFFF)
/* Global Control */
#define HMC7044_REG_SOFT_RESET 0x0000
#define HMC7044_SOFT_RESET BIT(0)
#define HMC7044_REG_REQ_MODE_0 0x0001
#define HMC7044_RESEED_REQ BIT(7)
#define HMC7044_HIGH_PERF_DISTRIB_PATH BIT(6)
#define HMC7044_HIGH_PERF_PLL_VCO BIT(5)
#define HMC7044_FORCE_HOLDOVER BIT(4)
#define HMC7044_MUTE_OUT_DIV BIT(3)
#define HMC7044_PULSE_GEN_REQ BIT(2)
#define HMC7044_RESTART_DIV_FSM BIT(1)
#define HMC7044_SLEEP_MODE BIT(0)
#define HMC7044_REG_REQ_MODE_1 0x0002
#define HMC7044_PLL2_AUTOTUNE_TRIG BIT(2)
#define HMC7044_SLIP_REQ BIT(1)
#define HMC7044_REG_EN_CTRL_0 0x0003
#define HMC7044_RF_RESEEDER_EN BIT(5)
#define HMC7044_VCO_SEL(x) (((x) & 0x3) << 3)
#define HMC7044_VCO_EXT 0
#define HMC7044_VCO_HIGH 1
#define HMC7044_VCO_LOW 2
#define HMC7044_SYSREF_TIMER_EN BIT(2)
#define HMC7044_PLL2_EN BIT(1)
#define HMC7044_PLL1_EN BIT(0)
#define HMC7044_REG_EN_CTRL_1 0x0004
#define HMC7044_SEVEN_PAIRS(x) ((x) & 0x7f)
#define HMC7044_REG_GLOB_MODE 0x0005
#define HMC7044_REF_PATH_EN(x) ((x) & 0xf)
#define HMC7044_RFSYNC_EN BIT(4)
#define HMC7044_VCOIN_MODE_EN BIT(5)
#define HMC7044_SYNC_PIN_MODE(x) (((x) & 0x3) << 6)
/* PLL1 */
#define HMC7044_REG_CLKIN0_BUF_CTRL 0x000A
#define HMC7044_REG_CLKIN1_BUF_CTRL 0x000B
#define HMC7044_REG_CLKIN2_BUF_CTRL 0x000C
#define HMC7044_REG_CLKIN3_BUF_CTRL 0x000D
#define HMC7044_REG_OSCIN_BUF_CTRL 0x000E
#define HMC7044_REG_PLL1_REF_PRIO_CTRL 0x0014
#define HMC7044_HIGH_Z_EN BIT(4)
#define HMC7044_LVPECL_EN BIT(3)
#define HMC7044_AC_COUPLING_EN BIT(2)
#define HMC7044_100_OHM_EN BIT(1)
#define HMC7044_BUF_EN BIT(0)
#define HMC7044_REG_CLKIN_PRESCALER(x) (0x001C + (x))
#define HMC7044_REG_OSCIN_PRESCALER 0x0020
#define HMC7044_REG_PLL1_R_LSB 0x0021
#define HMC7044_R1_LSB(x) ((x) & 0xff)
#define HMC7044_REG_PLL1_R_MSB 0x0022
#define HMC7044_R1_MSB(x) (((x) & 0xff00) >> 8)
#define HMC7044_REG_PLL1_N_LSB 0x0026
#define HMC7044_N1_LSB(x) ((x) & 0xff)
#define HMC7044_REG_PLL1_N_MSB 0x0027
#define HMC7044_N1_MSB(x) (((x) & 0xff00) >> 8)
#define HMC7044_REG_PLL1_LOCK_DETECT 0x0028
#define HMC7044_LOCK_DETECT_SLIP BIT(5)
#define HMC7044_LOCK_DETECT_TIMER(x) ((x) & 0x1f)
/* PLL2 */
#define HMC7044_REG_PLL2_FREQ_DOUBLER 0x0032
#define HMC7044_PLL2_FREQ_DOUBLER_DIS BIT(0)
#define HMC7044_REG_PLL2_R_LSB 0x0033
#define HMC7044_R2_LSB(x) ((x) & 0xff)
#define HMC7044_REG_PLL2_R_MSB 0x0034
#define HMC7044_R2_MSB(x) (((x) & 0xf00) >> 8)
#define HMC7044_REG_PLL2_N_LSB 0x0035
#define HMC7044_N2_LSB(x) ((x) & 0xff)
#define HMC7044_REG_PLL2_N_MSB 0x0036
#define HMC7044_N2_MSB(x) (((x) & 0xff00) >> 8)
#define HMC7044_REG_OSCOUT_PATH 0x0039
#define HMC7044_REG_OSCOUT_DRIVER_0 0x003A
#define HMC7044_REG_OSCOUT_DRIVER_1 0x003B
/* GPIO/SDATA Control */
#define HMC7044_REG_GPI_CTRL(x) (0x0046 + (x))
#define HMC7044_REG_GPI_SEL(x) ((x) & 0xf)
#define HMC7044_REG_GPO_CTRL(x) (0x0050 + (x))
#define HMC7044_GPO_SEL(x) (((x) & 0x3f) << 2)
#define HMC7044_GPO_MODE BIT(1)
#define HMC7044_GPO_EN BIT(0)
/* SYSREF/SYNC Control */
#define HMC7044_REG_PULSE_GEN 0x005A
#define HMC7044_PULSE_GEN_MODE(x) ((x) & 0x7)
#define HMC7044_REG_SYNC 0x005B
#define HMC7044_SYNC_RETIME BIT(2)
#define HMC7044_SYNC_THROUGH_PLL2 BIT(1)
#define HMC7044_SYNC_POLARITY BIT(0)
#define HMC7044_REG_SYSREF_TIMER_LSB 0x005C
#define HMC7044_SYSREF_TIMER_LSB(x) ((x) & 0xff)
#define HMC7044_REG_SYSREF_TIMER_MSB 0x005D
#define HMC7044_SYSREF_TIMER_MSB(x) (((x) & 0xf00) >> 8)
#define HMC7044_CLK_INPUT_CTRL 0x0064
#define HMC7044_LOW_FREQ_INPUT_MODE BIT(0)
#define HMC7044_DIV_2_INPUT_MODE BIT(1)
/* Status and Alarm readback */
#define HMC7044_REG_ALARM_READBACK 0x007D
#define HMC7044_REG_PLL1_STATUS 0x0082
#define HMC7044_PLL1_FSM_STATE(x) ((x) & 0x7)
#define HMC7044_PLL1_ACTIVE_CLKIN(x) (((x) >> 3) & 0x3)
#define HMC7044_PLL2_LOCK_DETECT(x) ((x) & 0x1)
#define HMC7044_SYSREF_SYNC_STAT(x) ((x) & 0x2)
#define HMC7044_CLK_OUT_PH_STATUS(x) ((x) & 0x4)
#define HMC7044_PLL1_PLL2_LOCK_STAT(x) ((x) & 0x8)
#define HMC7044_SYNC_REQ_STATUS(x) ((x) & 0x10)
/* Other Controls */
#define HMC7044_REG_CLK_OUT_DRV_LOW_PW 0x009F
#define HMC7044_REG_CLK_OUT_DRV_HIGH_PW 0x00A0
#define HMC7044_REG_PLL1_DELAY 0x00A5
#define HMC7044_REG_PLL1_HOLDOVER 0x00A8
#define HMC7044_REG_VTUNE_PRESET 0x00B0
/* Clock Distribution */
#define HMC7044_REG_CH_OUT_CRTL_0(ch) (0x00C8 + 0xA * (ch))
#define HMC7044_HI_PERF_MODE BIT(7)
#define HMC7044_SYNC_EN BIT(6)
#define HMC7044_CH_EN BIT(0)
#define HMC7044_START_UP_MODE_DYN_EN (BIT(3) | BIT(2))
#define HMC7044_REG_CH_OUT_CRTL_1(ch) (0x00C9 + 0xA * (ch))
#define HMC7044_DIV_LSB(x) ((x) & 0xFF)
#define HMC7044_REG_CH_OUT_CRTL_2(ch) (0x00CA + 0xA * (ch))
#define HMC7044_DIV_MSB(x) (((x) >> 8) & 0xFF)
#define HMC7044_REG_CH_OUT_CRTL_3(ch) (0x00CB + 0xA * (ch))
#define HMC7044_REG_CH_OUT_CRTL_4(ch) (0x00CC + 0xA * (ch))
#define HMC7044_REG_CH_OUT_CRTL_5(ch) (0x00CD + 0xA * (ch))
#define HMC7044_REG_CH_OUT_CRTL_6(ch) (0x00CE + 0xA * (ch))
#define HMC7044_REG_CH_OUT_CRTL_7(ch) (0x00CF + 0xA * (ch))
#define HMC7044_REG_CH_OUT_CRTL_8(ch) (0x00D0 + 0xA * (ch))
#define HMC7044_DRIVER_MODE(x) (((x) & 0x3) << 3)
#define HMC7044_DRIVER_Z_MODE(x) (((x) & 0x3) << 0)
#define HMC7044_DYN_DRIVER_EN BIT(5)
#define HMC7044_FORCE_MUTE_EN BIT(7)
#define HMC7044_NUM_CHAN 14
#define HMC7044_LOW_VCO_MIN 2150000
#define HMC7044_LOW_VCO_MAX 2880000
#define HMC7044_HIGH_VCO_MIN 2650000
#define HMC7044_HIGH_VCO_MAX 3200000
#define HMC7044_RECOMM_LCM_MIN 30000
#define HMC7044_RECOMM_LCM_MAX 70000
#define HMC7044_RECOMM_FPD1 10000
#define HMC7044_R1_MAX 65535
#define HMC7044_N1_MAX 65535
#define HMC7044_R2_MIN 1
#define HMC7044_R2_MAX 4095
#define HMC7044_N2_MIN 8
#define HMC7044_N2_MAX 65535
#define HMC7044_OUT_DIV_MIN 1
#define HMC7044_OUT_DIV_MAX 4094
/******************************************************************************/
/************************** Functions Implementation **************************/
/******************************************************************************/
/**
* SPI register write to device.
* @param dev - The device structure.
* @param reg - The register address.
* @param val - The register data.
* @return SUCCESS in case of success, negative error code otherwise.
*/
int32_t hmc7044_write(struct hmc7044_dev *dev,
uint16_t reg,
uint8_t val)
{
uint8_t buf[3];
uint16_t cmd;
cmd = HMC7044_WRITE | HMC7044_CNT(1) | HMC7044_ADDR(reg);
buf[0] = cmd >> 8;
buf[1] = cmd & 0xFF;
buf[2] = val;
return spi_write_and_read_3wire(dev->spi_desc, buf, NULL,
ARRAY_SIZE(buf), 0);
}
/**
* SPI register read from device.
* @param dev - The device structure.
* @param reg - The register address.
* @param val - The register data.
* @return SUCCESS in case of success, negative error code otherwise.
*/
int32_t hmc7044_read(struct hmc7044_dev *dev, uint16_t reg, uint8_t *val)
{
uint8_t wr_buf[2];
uint8_t rd_data[1];
uint16_t cmd;
int ret;
cmd = HMC7044_READ | HMC7044_CNT(1) | HMC7044_ADDR(reg);
wr_buf[0] = cmd >> 8;
wr_buf[1] = cmd & 0xFF;
ret = spi_write_and_read_3wire(dev->spi_desc, wr_buf, rd_data,
ARRAY_SIZE(wr_buf), ARRAY_SIZE(rd_data));
if (ret != SUCCESS)
return ret;
*val = rd_data[0];
return SUCCESS;
}
/**
* Calculate the output channel divider.
* @param rate - The desired rate.
* @param parent_rate - The parent rate.
* @return The output divider.
*/
uint32_t hmc7044_calc_out_div(uint32_t rate,
uint32_t parent_rate)
{
uint32_t div;
div = DIV_ROUND_CLOSEST(parent_rate, rate);
/* Supported odd divide ratios are 1, 3, and 5 */
if ((div != 1) && (div != 3) && (div != 5) && (div % 2))
div = DIV_ROUND_CLOSEST(parent_rate, rate * 2) * 2;
div = clamp_t(unsigned int,
div,
HMC7044_OUT_DIV_MIN,
HMC7044_OUT_DIV_MAX);
return div;
}
/**
* Recalculate rate corresponding to a channel.
* @param dev - The device structure.
* @param chan_num - Channel number.
* @param rate - Channel rate.
* @return SUCCESS in case of success, negative error code otherwise.
*/
int32_t hmc7044_clk_recalc_rate(struct hmc7044_dev *dev, uint32_t chan_num,
uint64_t *rate)
{
int i;
struct hmc7044_chan_spec *chan = NULL;
/* Find the reqested channel number */
for (i = 0; i < dev->num_channels; i++) {
if (dev->channels[i].num == chan_num) {
chan = &dev->channels[i];
break;
}
}
if (chan == NULL )
return FAILURE;
*rate = dev->pll2_freq / chan->divider;
return SUCCESS;
}
/**
* Calculate closest possible rate
* @param dev - The device structure
* @param rate - The desired rate.
* @param rounded_rate - The closest possible rate of desired rate.
* @return SUCCESS in case of success, negative error code otherwise.
*/
int32_t hmc7044_clk_round_rate(struct hmc7044_dev *dev, uint32_t rate,
uint64_t *rounded_rate)
{
uint32_t div = hmc7044_calc_out_div(rate, dev->pll2_freq);
*rounded_rate = DIV_ROUND_CLOSEST(dev->pll2_freq, div);
return SUCCESS;
}
/**
* Set channel rate.
* @param dev - The device structure.
* @param chan_num - Channel number.
* @param rate - Channel rate.
* @return SUCCESS in case of success, negative error code otherwise.
*/
int32_t hmc7044_clk_set_rate(struct hmc7044_dev *dev, uint32_t chan_num,
uint64_t rate)
{
uint32_t div;
int32_t ret;
int i;
struct hmc7044_chan_spec *chan = NULL;
/* Find the reqested channel number */
for (i = 0; i < dev->num_channels; i++) {
if (dev->channels[i].num == chan_num) {
chan = &dev->channels[i];
break;
}
}
if (chan == NULL )
return FAILURE;
div = hmc7044_calc_out_div(rate, dev->pll2_freq);
chan->divider = div;
ret = hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_1(chan->num),
HMC7044_DIV_LSB(div));
if(ret < 0)
return ret;
return hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_2(chan->num),
HMC7044_DIV_MSB(div));
}
/**
* Setup the device.
* @param dev - The device structure.
* @return SUCCESS in case of success, negative error code otherwise.
*/
static int32_t hmc7044_setup(struct hmc7044_dev *dev)
{
struct hmc7044_chan_spec *chan;
bool high_vco_en;
bool pll2_freq_doubler_en;
uint32_t vcxo_freq, pll2_freq;
uint32_t clkin_freq[4];
uint32_t lcm_freq;
uint32_t in_prescaler[5];
uint32_t pll1_lock_detect;
uint32_t n1, r1;
uint32_t pfd1_freq;
uint32_t vco_limit;
uint32_t n2[2], r2[2];
uint32_t i, ref_en = 0;
vcxo_freq = dev->vcxo_freq / 1000;
pll2_freq = dev->pll2_freq / 1000;
lcm_freq = vcxo_freq;
for (i = 0; i < ARRAY_SIZE(clkin_freq); i++) {
if (dev->clkin_freq_ccf[i])
clkin_freq[i] = dev->clkin_freq_ccf[i] / 1000;
else
clkin_freq[i] = dev->clkin_freq[i] / 1000;
if (clkin_freq[i]) {
lcm_freq = greatest_common_divisor(clkin_freq[i], lcm_freq);
ref_en |= BIT(i);
}
}
while (lcm_freq > HMC7044_RECOMM_LCM_MAX)
lcm_freq /= 2;
for (i = 0; i < ARRAY_SIZE(clkin_freq); i++) {
if (clkin_freq[i])
in_prescaler[i] = clkin_freq[i] / lcm_freq;
else
in_prescaler[i] = 1;
}
in_prescaler[4] = vcxo_freq / lcm_freq;
pll1_lock_detect = log_base_2((lcm_freq * 4000) / dev->pll1_loop_bw);
/* fVCXO / N1 = fLCM / R1 */
rational_best_approximation(vcxo_freq, lcm_freq,
HMC7044_N1_MAX, HMC7044_R1_MAX,
&n1, &r1);
pfd1_freq = vcxo_freq / n1;
while ((pfd1_freq > HMC7044_RECOMM_FPD1) &&
(n1 <= HMC7044_N1_MAX / 2) &&
(r1 <= HMC7044_R1_MAX / 2)) {
pfd1_freq /= 2;
n1 *= 2;
r1 *= 2;
}
dev->pll1_pfd = pfd1_freq;
if (pll2_freq < HMC7044_LOW_VCO_MIN ||
pll2_freq > HMC7044_HIGH_VCO_MAX)
return FAILURE;
vco_limit = (HMC7044_LOW_VCO_MAX + HMC7044_HIGH_VCO_MIN) / 2;
if (pll2_freq >= vco_limit)
high_vco_en = true;
else
high_vco_en = false;
/* fVCO / N2 = fVCXO * doubler / R2 */
pll2_freq_doubler_en = true;
rational_best_approximation(pll2_freq, vcxo_freq * 2,
HMC7044_N2_MAX, HMC7044_R2_MAX,
&n2[0], &r2[0]);
if (pll2_freq != vcxo_freq * n2[0] / r2[0]) {
rational_best_approximation(pll2_freq, vcxo_freq,
HMC7044_N2_MAX, HMC7044_R2_MAX,
&n2[1], &r2[1]);
if (abs((int)pll2_freq - (int)(vcxo_freq * 2 * n2[0] / r2[0])) >
abs((int)pll2_freq - (int)(vcxo_freq * n2[1] / r2[1]))) {
n2[0] = n2[1];
r2[0] = r2[1];
pll2_freq_doubler_en = false;
}
}
while ((n2[0] < HMC7044_N2_MIN) && (r2[0] <= HMC7044_R2_MAX / 2)) {
n2[0] *= 2;
r2[0] *= 2;
}
if (n2[0] < HMC7044_N2_MIN)
return -FAILURE;
/* Resets all registers to default values */
hmc7044_write(dev, HMC7044_REG_SOFT_RESET, HMC7044_SOFT_RESET);
mdelay(10);
hmc7044_write(dev, HMC7044_REG_SOFT_RESET, 0);
mdelay(10);
/* Disable all channels */
for (i = 0; i < HMC7044_NUM_CHAN; i++)
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_0(i), 0);
/* Load the configuration updates (provided by Analog Devices) */
hmc7044_write(dev, HMC7044_REG_CLK_OUT_DRV_LOW_PW, 0x4d);
hmc7044_write(dev, HMC7044_REG_CLK_OUT_DRV_HIGH_PW, 0xdf);
hmc7044_write(dev, HMC7044_REG_PLL1_DELAY, 0x06);
hmc7044_write(dev, HMC7044_REG_PLL1_HOLDOVER, 0x06);
hmc7044_write(dev, HMC7044_REG_VTUNE_PRESET, 0x04);
uint8_t rd_back;
hmc7044_read(dev, HMC7044_REG_CLK_OUT_DRV_LOW_PW, &rd_back);
hmc7044_read(dev, HMC7044_REG_CLK_OUT_DRV_HIGH_PW, &rd_back);
hmc7044_read(dev, HMC7044_REG_PLL1_DELAY, &rd_back);
hmc7044_read(dev, HMC7044_REG_PLL1_HOLDOVER, &rd_back);
hmc7044_read(dev, HMC7044_REG_VTUNE_PRESET, &rd_back);
hmc7044_write(dev, HMC7044_REG_GLOB_MODE,
HMC7044_SYNC_PIN_MODE(dev->sync_pin_mode) |
(dev->clkin0_rfsync_en ? HMC7044_RFSYNC_EN : 0) |
(dev->clkin1_vcoin_en ? HMC7044_VCOIN_MODE_EN : 0) |
HMC7044_REF_PATH_EN(ref_en));
/* Program PLL2 */
/* Select the VCO range */
hmc7044_write(dev, HMC7044_REG_EN_CTRL_0,
(dev->rf_reseeder_en ? HMC7044_RF_RESEEDER_EN : 0) |
HMC7044_VCO_SEL(high_vco_en ?
HMC7044_VCO_HIGH :
HMC7044_VCO_LOW) |
HMC7044_SYSREF_TIMER_EN | HMC7044_PLL2_EN |
HMC7044_PLL1_EN);
/* Program the dividers */
hmc7044_write(dev, HMC7044_REG_PLL2_R_LSB,
HMC7044_R2_LSB(r2[0]));
hmc7044_write(dev, HMC7044_REG_PLL2_R_MSB,
HMC7044_R2_MSB(r2[0]));
hmc7044_write(dev, HMC7044_REG_PLL2_N_LSB,
HMC7044_N2_LSB(n2[0]));
hmc7044_write(dev, HMC7044_REG_PLL2_N_MSB,
HMC7044_N2_MSB(n2[0]));
/* Program the reference doubler */
hmc7044_write(dev, HMC7044_REG_PLL2_FREQ_DOUBLER,
pll2_freq_doubler_en ? 0 : HMC7044_PLL2_FREQ_DOUBLER_DIS);
/* Program PLL1 */
/* Set the lock detect timer threshold */
hmc7044_write(dev, HMC7044_REG_PLL1_LOCK_DETECT,
HMC7044_LOCK_DETECT_TIMER(pll1_lock_detect));
/* Set the LCM */
for (i = 0; i < ARRAY_SIZE(clkin_freq); i++) {
hmc7044_write(dev, HMC7044_REG_CLKIN_PRESCALER(i),
in_prescaler[i]);
}
hmc7044_write(dev, HMC7044_REG_OSCIN_PRESCALER,
in_prescaler[4]);
/* Program the dividers */
hmc7044_write(dev, HMC7044_REG_PLL1_R_LSB,
HMC7044_R2_LSB(r1));
hmc7044_write(dev, HMC7044_REG_PLL1_R_MSB,
HMC7044_R2_MSB(r1));
hmc7044_write(dev, HMC7044_REG_PLL1_N_LSB,
HMC7044_N2_LSB(n1));
hmc7044_write(dev, HMC7044_REG_PLL1_N_MSB,
HMC7044_N2_MSB(n1));
hmc7044_write(dev, HMC7044_REG_PLL1_REF_PRIO_CTRL,
dev->pll1_ref_prio_ctrl);
/* Program the SYSREF timer */
/* Set the divide ratio */
hmc7044_write(dev, HMC7044_REG_SYSREF_TIMER_LSB,
HMC7044_SYSREF_TIMER_LSB(dev->sysref_timer_div));
hmc7044_write(dev, HMC7044_REG_SYSREF_TIMER_MSB,
HMC7044_SYSREF_TIMER_MSB(dev->sysref_timer_div));
/* Set the pulse generator mode configuration */
hmc7044_write(dev, HMC7044_REG_PULSE_GEN,
HMC7044_PULSE_GEN_MODE(dev->pulse_gen_mode));
/* Enable the input buffers */
hmc7044_write(dev, HMC7044_REG_CLKIN0_BUF_CTRL,
dev->in_buf_mode[0]);
hmc7044_write(dev, HMC7044_REG_CLKIN1_BUF_CTRL,
dev->in_buf_mode[1]);
hmc7044_write(dev, HMC7044_REG_CLKIN2_BUF_CTRL,
dev->in_buf_mode[2]);
hmc7044_write(dev, HMC7044_REG_CLKIN3_BUF_CTRL,
dev->in_buf_mode[3]);
hmc7044_write(dev, HMC7044_REG_OSCIN_BUF_CTRL,
dev->in_buf_mode[4]);
/* Set GPIOs */
for (i = 0; i < ARRAY_SIZE(dev->gpi_ctrl); i++) {
hmc7044_write(dev, HMC7044_REG_GPI_CTRL(i),
dev->gpi_ctrl[i]);
}
for (i = 0; i < ARRAY_SIZE(dev->gpo_ctrl); i++) {
hmc7044_write(dev, HMC7044_REG_GPO_CTRL(i),
dev->gpo_ctrl[i]);
}
mdelay(10);
/* Program the output channels */
for (i = 0; i < dev->num_channels; i++) {
chan = &dev->channels[i];
if (chan->num >= HMC7044_NUM_CHAN || chan->disable)
continue;
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_1(chan->num),
HMC7044_DIV_LSB(chan->divider));
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_2(chan->num),
HMC7044_DIV_MSB(chan->divider));
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_8(chan->num),
HMC7044_DRIVER_MODE(chan->driver_mode) |
HMC7044_DRIVER_Z_MODE(chan->driver_impedance) |
(chan->dynamic_driver_enable ?
HMC7044_DYN_DRIVER_EN : 0) |
(chan->force_mute_enable ?
HMC7044_FORCE_MUTE_EN : 0));
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_3(chan->num),
chan->fine_delay & 0x1F);
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_4(chan->num),
chan->coarse_delay & 0x1F);
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_7(chan->num),
chan->out_mux_mode & 0x3);
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_0(chan->num),
(chan->start_up_mode_dynamic_enable ?
HMC7044_START_UP_MODE_DYN_EN : 0) |
(chan->output_control0_rb4_enable ? BIT(4) : 0) |
(chan->high_performance_mode_dis ?
0 : HMC7044_HI_PERF_MODE) | HMC7044_SYNC_EN |
HMC7044_CH_EN);
}
mdelay(10);
/* Do a restart to reset the system and initiate calibration */
hmc7044_write(dev, HMC7044_REG_REQ_MODE_0,
HMC7044_RESTART_DIV_FSM);
mdelay(1);
hmc7044_write(dev, HMC7044_REG_REQ_MODE_0,
(dev->high_performance_mode_clock_dist_en ?
HMC7044_HIGH_PERF_DISTRIB_PATH : 0));
mdelay(1);
return SUCCESS;
}
/**
* Setup the device.
* @param dev - The device structure.
* @return SUCCESS in case of success, negative error code otherwise.
*/
static int32_t hmc7043_setup(struct hmc7044_dev *dev)
{
struct hmc7044_chan_spec *chan;
uint32_t i;
if (dev->clkin_freq_ccf[0])
dev->pll2_freq = dev->clkin_freq_ccf[0];
else
dev->pll2_freq = dev->clkin_freq[0];
if (!dev->pll2_freq) {
printf("%s: Failed to get valid parent rate\n", __func__);
return FAILURE;
}
/* Resets all registers to default values */
hmc7044_write(dev, HMC7044_REG_SOFT_RESET, HMC7044_SOFT_RESET);
mdelay(10);
hmc7044_write(dev, HMC7044_REG_SOFT_RESET, 0);
mdelay(10);
/* Load the configuration updates (provided by Analog Devices) */
hmc7044_write(dev, HMC7044_REG_CLK_OUT_DRV_LOW_PW, 0x4d);
hmc7044_write(dev, HMC7044_REG_CLK_OUT_DRV_HIGH_PW, 0xdf);
/* Disable all channels */
for (i = 0; i < HMC7044_NUM_CHAN; i++)
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_0(i), 0);
if (dev->pll2_freq < 1000000000U)
hmc7044_write(dev, HMC7044_CLK_INPUT_CTRL,
HMC7044_LOW_FREQ_INPUT_MODE);
hmc7044_write(dev, HMC7044_REG_EN_CTRL_0,
(dev->rf_reseeder_en ? HMC7044_RF_RESEEDER_EN : 0) |
HMC7044_SYSREF_TIMER_EN);
/* Program the SYSREF timer */
/* Set the divide ratio */
hmc7044_write(dev, HMC7044_REG_SYSREF_TIMER_LSB,
HMC7044_SYSREF_TIMER_LSB(dev->sysref_timer_div));
hmc7044_write(dev, HMC7044_REG_SYSREF_TIMER_MSB,
HMC7044_SYSREF_TIMER_MSB(dev->sysref_timer_div));
/* Set the pulse generator mode configuration */
hmc7044_write(dev, HMC7044_REG_PULSE_GEN,
HMC7044_PULSE_GEN_MODE(dev->pulse_gen_mode));
/* Enable the input buffers */
hmc7044_write(dev, HMC7044_REG_CLKIN0_BUF_CTRL,
dev->in_buf_mode[0]);
hmc7044_write(dev, HMC7044_REG_CLKIN1_BUF_CTRL,
dev->in_buf_mode[1]);
/* Set GPIOs */
hmc7044_write(dev, HMC7044_REG_GPI_CTRL(0),
dev->gpi_ctrl[0]);
hmc7044_write(dev, HMC7044_REG_GPO_CTRL(0),
dev->gpo_ctrl[0]);
/* Program the output channels */
for (i = 0; i < dev->num_channels; i++) {
chan = &dev->channels[i];
if (chan->num >= HMC7044_NUM_CHAN || chan->disable)
continue;
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_1(chan->num),
HMC7044_DIV_LSB(chan->divider));
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_2(chan->num),
HMC7044_DIV_MSB(chan->divider));
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_8(chan->num),
HMC7044_DRIVER_MODE(chan->driver_mode) |
HMC7044_DRIVER_Z_MODE(chan->driver_impedance) |
(chan->dynamic_driver_enable ?
HMC7044_DYN_DRIVER_EN : 0) |
(chan->force_mute_enable ?
HMC7044_FORCE_MUTE_EN : 0));
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_3(chan->num),
chan->fine_delay & 0x1F);
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_4(chan->num),
chan->coarse_delay & 0x1F);
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_7(chan->num),
chan->out_mux_mode & 0x3);
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_0(chan->num),
(chan->start_up_mode_dynamic_enable ?
HMC7044_START_UP_MODE_DYN_EN : 0) |
(chan->output_control0_rb4_enable ? BIT(4) : 0) |
(chan->high_performance_mode_dis ?
0 : HMC7044_HI_PERF_MODE) | HMC7044_SYNC_EN |
HMC7044_CH_EN);
}
mdelay(10);
/* Do a restart to reset the system and initiate calibration */
hmc7044_write(dev, HMC7044_REG_REQ_MODE_0,
HMC7044_RESTART_DIV_FSM);
mdelay(1);
hmc7044_write(dev, HMC7044_REG_REQ_MODE_0,
(dev->high_performance_mode_clock_dist_en ?
HMC7044_HIGH_PERF_DISTRIB_PATH : 0));
mdelay(1);
return SUCCESS;
}
/***************************************************************************//**
* @brief hmc7044_reg_init
*******************************************************************************/
int32_t hmc7044_reg_init(struct hmc7044_dev **device,
const struct hmc7044_init_param *init_param)
{
int ret = SUCCESS;
struct hmc7044_dev *dev;
dev = (struct hmc7044_dev *)malloc(sizeof(*dev));
if (!dev)
return FAILURE;
/* SPI */
ret = spi_init(&dev->spi_desc, init_param->spi_init);
*device = dev;
return ret;
}
/**
* Initialize the device.
* @param device - The device structure.
* @param init_param - The structure that contains the device initial
* parameters.
* @return SUCCESS in case of success, negative error code otherwise.
*/
int32_t hmc7044_init(struct hmc7044_dev **device,
const struct hmc7044_init_param *init_param)
{
struct hmc7044_dev *dev;
int32_t ret;
unsigned int i;
dev = (struct hmc7044_dev *)malloc(sizeof(*dev));
if (!dev)
return FAILURE;
ret = spi_init(&dev->spi_desc, init_param->spi_init);
if (ret < 0)
return ret;
dev->is_hmc7043 = init_param->is_hmc7043;
dev->clkin_freq[0] = init_param->clkin_freq[0];
dev->clkin_freq[1] = init_param->clkin_freq[1];
dev->clkin_freq[2] = init_param->clkin_freq[2];
dev->clkin_freq[3] = init_param->clkin_freq[3];
dev->clkin_freq_ccf[0] = init_param->clkin_freq_ccf[0];
dev->clkin_freq_ccf[1] = init_param->clkin_freq_ccf[1];
dev->clkin_freq_ccf[2] = init_param->clkin_freq_ccf[2];
dev->clkin_freq_ccf[3] = init_param->clkin_freq_ccf[3];
dev->vcxo_freq = init_param->vcxo_freq;
dev->pll1_pfd = init_param->pll1_pfd;
dev->pll2_freq = init_param->pll2_freq;
dev->pll1_loop_bw = init_param->pll1_loop_bw;
dev->sysref_timer_div = init_param->sysref_timer_div;
dev->pll1_ref_prio_ctrl = init_param->pll1_ref_prio_ctrl;
dev->clkin0_rfsync_en = init_param->clkin0_rfsync_en;
dev->clkin1_vcoin_en = init_param->clkin1_vcoin_en;
dev->high_performance_mode_clock_dist_en =
init_param->high_performance_mode_clock_dist_en;
dev->rf_reseeder_en = !init_param->rf_reseeder_disable;
dev->sync_pin_mode = init_param->sync_pin_mode;
dev->pulse_gen_mode = init_param->pulse_gen_mode;
dev->in_buf_mode[0] = init_param->in_buf_mode[0];
dev->in_buf_mode[1] = init_param->in_buf_mode[1];
dev->in_buf_mode[2] = init_param->in_buf_mode[2];
dev->in_buf_mode[3] = init_param->in_buf_mode[3];
dev->in_buf_mode[4] = init_param->in_buf_mode[4];
dev->gpi_ctrl[0] = init_param->gpi_ctrl[0];
dev->gpi_ctrl[1] = init_param->gpi_ctrl[1];
dev->gpi_ctrl[2] = init_param->gpi_ctrl[2];
dev->gpi_ctrl[3] = init_param->gpi_ctrl[3];
dev->gpo_ctrl[0] = init_param->gpo_ctrl[0];
dev->gpo_ctrl[1] = init_param->gpo_ctrl[1];
dev->gpo_ctrl[2] = init_param->gpo_ctrl[2];
dev->gpo_ctrl[3] = init_param->gpo_ctrl[3];
dev->num_channels = init_param->num_channels;
dev->channels = (struct hmc7044_chan_spec *)
malloc(sizeof(*dev->channels) * dev->num_channels);
for (i = 0; i < dev->num_channels; i++) {
dev->channels[i].num = init_param->channels[i].num;
dev->channels[i].disable = init_param->channels[i].disable;
dev->channels[i].divider = init_param->channels[i].divider;
dev->channels[i].driver_mode =
init_param->channels[i].driver_mode;
dev->channels[i].high_performance_mode_dis =
init_param->channels[i].high_performance_mode_dis;
dev->channels[i].start_up_mode_dynamic_enable =
init_param->channels[i].start_up_mode_dynamic_enable;
dev->channels[i].dynamic_driver_enable =
init_param->channels[i].dynamic_driver_enable;
dev->channels[i].output_control0_rb4_enable =
init_param->channels[i].output_control0_rb4_enable;
dev->channels[i].force_mute_enable =
init_param->channels[i].force_mute_enable;
dev->channels[i].driver_impedance =
init_param->channels[i].driver_impedance;
dev->channels[i].coarse_delay =
init_param->channels[i].coarse_delay;
dev->channels[i].fine_delay =
init_param->channels[i].fine_delay;
dev->channels[i].out_mux_mode =
init_param->channels[i].out_mux_mode;
}
*device = dev;
if (!dev->is_hmc7043)
return hmc7044_setup(dev);
else
return hmc7043_setup(dev);
}
/**
* Remove the device - release resources.
* @param device - The device structure.
* @return SUCCESS in case of success, negative error code otherwise.
*/
int32_t hmc7044_remove(struct hmc7044_dev *device)
{
int32_t ret;
ret = spi_remove(device->spi_desc);
free(device->channels);
free(device);
return ret;
}
@@ -0,0 +1,276 @@
/***************************************************************************//**
* @file hmc7044.h
* @brief Header file of HMC7044, HMC7043 Driver.
* @author DBogdan ([email protected])
********************************************************************************
* Copyright 2018-2020(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
*******************************************************************************/
#ifndef HMC7044_H_
#define HMC7044_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdbool.h>
#include <stdint.h>
#include "delay.h"
#include "spi.h"
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
// Enum to select SYNC pin configuration with respect to PLL2 (0x0005)
typedef enum
{
SYNC_DISABLED = 0,
SYNC_MULTICHIP = 1,
SYNC_PULSE_GEN = 2,
SYNC_ALARM = 3
} hmc7044SyncPinModeSelect_t;
// Enum to select input buffer mode (0x000A, 0x000B, 0x000C, 0x000D, 0x000E)
typedef enum
{
BUFFER_ENABLE = (1) << 0,
BUFFER_DISABLE = (0) << 0,
ENABLE_INTERNAL_TERM = (1) << 1,
ENABLE_AC_COUPLE = (1) << 2,
ENABLE_LVPECL = (1) << 3,
ENABLE_HIGH_Z = (1) << 4
} hmc7044InputBufferMode_t;
// Enum to select output driver mode (0x003A, 0x003B, 0x00D0, 0x00DA, 0x00E4,
// 0x00EE, 0x00F8, 0x0102, 0x010C, 0x0116, 0x0120, 0x012A, 0x0134, 0x013E,
// 0x0148, 0x0152)
typedef enum
{
CML = 0,
LVPECL = 1,
LVDS = 2,
CMOS = 3
} hmc7044DriverMode_t;
// Enum to select the GPIx functionality. (0x0046, 0x0047, 0x0048, 0x0049)
typedef enum
{
GPI_ENABLE = (1) << 0,
GPI_DISABLE = (0) << 0,
FORCE_PLL1_HOLDOVER = (0x01) << 1 | GPI_ENABLE,
SELECT_PLL1_REF_BIT1 = (0x02) << 1 | GPI_ENABLE,
SELECT_PLL1_REF_BIT2 = (0x03) << 1 | GPI_ENABLE,
CHIP_SLEEP_MODE = (0x04) << 1 | GPI_ENABLE,
MUTE_REQUSET = (0x05) << 1 | GPI_ENABLE,
SELECT_INTERNAL_VCO_TYPE = (0x06) << 1 | GPI_ENABLE,
SELECT_HI_PERF_MODE = (0x07) << 1 | GPI_ENABLE,
PULSE_GEN_REQUSET = (0x08) << 1 | GPI_ENABLE,
RESEED_REQUEST = (0x09) << 1 | GPI_ENABLE,
RESTART_REQUSET = (0x0A) << 1 | GPI_ENABLE,
FORCE_FANOUT_MODE = (0x0B) << 1 | GPI_ENABLE,
SLIP_REQUEST = (0x0D) << 1 | GPI_ENABLE,
} hmc7044GPIControl_t;
// Enum to select the GPOx functionality. (0x0050, 0x0051, 0x0052, 0x0053)
typedef enum
{
GPO_ENABLE = (1) << 0,
GPO_DISABLE = (0) << 0,
GPO_CMOS_MODE = (1) << 1,
GPO_OPEN_DRAIN_MODE = (0) << 1,
ALARM_SIGNAL = (0x00) << 3 | GPO_ENABLE,
SPI_SDATA = (0x01) << 3 | GPO_ENABLE,
CLKIN3_SIGNAL_LOSS = (0x02) << 3 | GPO_ENABLE,
CLKIN2_SIGNAL_LOSS = (0x03) << 3 | GPO_ENABLE,
CLKIN1_SIGNAL_LOSS = (0x04) << 3 | GPO_ENABLE,
CLKIN0_SIGNAL_LOSS = (0x05) << 3 | GPO_ENABLE,
PLL1_HOLDOVER_ENABLE = (0x06) << 3 | GPO_ENABLE,
PLL1_LOCK_DETECT = (0x07) << 3 | GPO_ENABLE,
PLL1_ACQUIRING_LOCK = (0x08) << 3 | GPO_ENABLE,
PLL1_NEAR_CLOCK_ACQ_STAT = (0x09) << 3 | GPO_ENABLE,
PLL2_LOCK_DETECT = (0x0A) << 3 | GPO_ENABLE,
PLL2_SYSREF_SYNC = (0x0B) << 3 | GPO_ENABLE,
CLOCK_OUTPUT_PHASE_STAT = (0x0C) << 3 | GPO_ENABLE,
PLL1_PLL2_LOCKED = (0x0D) << 3 | GPO_ENABLE,
SYNC_REQUSRT_STAT = (0x0E) << 3 | GPO_ENABLE,
PLL1_ACTIVE_CLKIN0 = (0x0F) << 3 | GPO_ENABLE,
PLL1_ACTIVE_CLKIN1 = (0x10) << 3 | GPO_ENABLE,
PLL1_HOLDOVER_IN_RANGE_STAT = (0x11) << 3 | GPO_ENABLE,
PLL1_HOLDOVER_IN_STAT = (0x12) << 3 | GPO_ENABLE,
PLL1_VCXO_STAT = (0x13) << 3 | GPO_ENABLE,
PLL1_ACTIVE_CLKINx_STAT = (0x14) << 3 | GPO_ENABLE,
PLL1_FSM_BIT0 = (0x15) << 3 | GPO_ENABLE,
PLL1_FSM_BIT1 = (0x16) << 3 | GPO_ENABLE,
PLL1_FSM_BIT2 = (0x17) << 3 | GPO_ENABLE,
PLL1_HOLDOVER_EXIT_PHASE_BIT0 = (0x18) << 3 | GPO_ENABLE,
PLL1_HOLDOVER_EXIT_PHASE_BIT1 = (0x19) << 3 | GPO_ENABLE,
CHANNEL_OUTPUT_FSM_BUSY = (0x1A) << 3 | GPO_ENABLE,
SYSREF_FSM_STAT_BIT0 = (0x1B) << 3 | GPO_ENABLE,
SYSREF_FSM_STAT_BIT1 = (0x1C) << 3 | GPO_ENABLE,
SYSREF_FSM_STAT_BIT2 = (0x1D) << 3 | GPO_ENABLE,
SYSREF_FSM_STAT_BIT3 = (0x1E) << 3 | GPO_ENABLE,
FORCE_LOGIC_1 = (0x1F) << 3 | GPO_ENABLE,
FORCE_LOGIC_0 = (0x20) << 3 | GPO_ENABLE,
PLL1_HOLDOVER_AVG_VALUE_BIT0 = (0x27) << 3 | GPO_ENABLE,
PLL1_HOLDOVER_AVG_VALUE_BIT1 = (0x28) << 3 | GPO_ENABLE,
PLL1_HOLDOVER_AVG_VALUE_BIT2 = (0x29) << 3 | GPO_ENABLE,
PLL1_HOLDOVER_AVG_VALUE_BIT3 = (0x2A) << 3 | GPO_ENABLE,
PLL1_HOLDOVER_CURR_VALUE_BIT0 = (0x2B) << 3 | GPO_ENABLE,
PLL1_HOLDOVER_CURR_VALUE_BIT1 = (0x2C) << 3 | GPO_ENABLE,
PLL1_HOLDOVER_CURR_VALUE_BIT2 = (0x2D) << 3 | GPO_ENABLE,
PLL1_HOLDOVER_CURR_VALUE_BIT3 = (0x2E) << 3 | GPO_ENABLE
} hmc7044GPOControl_t;
// Enum to select output channel (0x00CF, 0x00D9, 0x00E3, 0x00ED, 0x00F7,
// 0x0101, 0x010B, 0x0115, 0x011F, 0x0129, 0x0133, 0x013D, 0x0147, 0x0151
typedef enum
{
CHANNEL_DIV = 0,
ANALOG_DELAY = 1,
OTHER_CHANNEL = 2,
VCO_CLOCK = 3
} hmc7044OutputMuxSelect_t;
// Enum to select output driver impedance selection for CML mode (0x00D0,
// 0x00DA, 0x00E4, 0x00EE, 0x00F8, 0x0102, 0x010C, 0x0116, 0x0120, 0x012A,
// 0x0134, 0x013E, 0x0148, 0x0152)
typedef enum
{
INTERNAL_RES_DISABLE = 0,
INTERNAL_100OHM_PER_PIN = 1,
// INTERNAL_RES_RESERVED = 2,
INTERNAL_50OHM_PER_PIN = 3
} hmc7044DriverImpedance_t;
// Enum to select pulse generator mode (0x005A)
typedef enum
{
PULSE_LEVEL_SENSITIVE = 0,
PULSE_ONE = 1,
PULSE_TWO = 2,
PULSE_FOUR = 3,
PULSE_EIGHT = 4,
PULSE_SIXTEEN = 5,
// PULSE_SIXTEEN = 6,
PULSE_CONTINOUS = 7
} hmc7044SyncPulseGenControl_t;
struct hmc7044_chan_spec {
unsigned int num;
bool disable;
bool high_performance_mode_dis;
bool start_up_mode_dynamic_enable;
bool dynamic_driver_enable;
bool output_control0_rb4_enable;
bool force_mute_enable;
unsigned int divider;
unsigned int coarse_delay;
unsigned int fine_delay;
hmc7044DriverMode_t driver_mode;
hmc7044DriverImpedance_t driver_impedance;
hmc7044OutputMuxSelect_t out_mux_mode;
};
struct hmc7044_config {
uint16_t addr;
uint8_t value;
};
struct hmc7044_dev {
struct spi_desc *spi_desc;
bool is_hmc7043;
uint32_t clkin_freq[4];
uint32_t clkin_freq_ccf[4];
uint32_t vcxo_freq;
uint32_t pll1_pfd;
uint32_t pll2_freq;
uint32_t pll1_loop_bw;
uint32_t sysref_timer_div;
unsigned int pll1_ref_prio_ctrl;
bool clkin0_rfsync_en;
bool clkin1_vcoin_en;
bool high_performance_mode_clock_dist_en;
bool rf_reseeder_en;
hmc7044SyncPinModeSelect_t sync_pin_mode;
hmc7044SyncPulseGenControl_t pulse_gen_mode;
uint32_t in_buf_mode[5];
uint32_t gpi_ctrl[4];
uint32_t gpo_ctrl[4];
uint32_t num_channels;
struct hmc7044_chan_spec *channels;
};
struct hmc7044_init_param {
struct spi_init_param *spi_init;
bool is_hmc7043;
uint32_t clkin_freq[4];
uint32_t clkin_freq_ccf[4];
uint32_t vcxo_freq;
uint32_t pll1_pfd;
uint32_t pll2_freq;
uint32_t pll1_loop_bw;
uint32_t sysref_timer_div;
unsigned int pll1_ref_prio_ctrl;
bool clkin0_rfsync_en;
bool clkin1_vcoin_en;
bool high_performance_mode_clock_dist_en;
bool rf_reseeder_disable;
hmc7044SyncPinModeSelect_t sync_pin_mode;
hmc7044SyncPulseGenControl_t pulse_gen_mode;
uint32_t in_buf_mode[5];
uint32_t gpi_ctrl[4];
uint32_t gpo_ctrl[4];
uint32_t num_channels;
struct hmc7044_chan_spec *channels;
};
/******************************************************************************/
/************************ Functions Declarations ******************************/
/******************************************************************************/
/* Initialize the device. */
int32_t hmc7044_reg_init(struct hmc7044_dev **device,
const struct hmc7044_init_param *init_param);
int32_t hmc7044_init(struct hmc7044_dev **device,
const struct hmc7044_init_param *init_param);
/* Remove the device. */
int32_t hmc7044_remove(struct hmc7044_dev *device);
int32_t hmc7044_write(struct hmc7044_dev *dev,
uint16_t reg, uint8_t val);
int32_t hmc7044_read(struct hmc7044_dev *dev, uint16_t reg, uint8_t *val);
int32_t hmc7044_clk_recalc_rate(struct hmc7044_dev *dev, uint32_t chan_num,
uint64_t *rate);
int32_t hmc7044_clk_round_rate(struct hmc7044_dev *dev, uint32_t rate,
uint64_t *rounded_rate);
int32_t hmc7044_clk_set_rate(struct hmc7044_dev *dev, uint32_t chan_num,
uint64_t rate);
#endif // HMC7044_H_
@@ -0,0 +1,128 @@
/***************************************************************************//**
* @file lmk04828.c
* @brief Implementation of AD9680 Driver.
* @author DBogdan ([email protected])
********************************************************************************
* Copyright 2014-2016(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 Files **********************************/
/******************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include "lmk04828.h"
#include "../../../include/error.h"
/***************************************************************************//**
* @brief lmk04828_read
*******************************************************************************/
int32_t lmk04828_read(struct lmk04828_dev *dev,
uint16_t reg_addr,
uint8_t *reg_data)
{
uint8_t tx_buf[2];
uint8_t rx_buf[1];
int32_t ret;
tx_buf[0] = 0x80 | (reg_addr >> 8);
tx_buf[1] = reg_addr & 0xFF;
ret = spi_write_and_read_3wire(dev->spi_desc,
tx_buf, rx_buf, 2, 1);
*reg_data = rx_buf[0];
return ret;
}
/***************************************************************************//**
* @brief lmk04828_write
*******************************************************************************/
int32_t lmk04828_write(struct lmk04828_dev *dev,
uint16_t reg_addr,
uint8_t reg_data)
{
uint8_t buf[3];
int32_t ret;
buf[0] = reg_addr >> 8;
buf[1] = reg_addr & 0xFF;
buf[2] = reg_data;
ret = spi_write_and_read_3wire(dev->spi_desc,
buf, NULL, 3, 0);
return ret;
}
/***************************************************************************//**
* @brief lmk04828_init
*******************************************************************************/
int32_t lmk04828_init(struct lmk04828_dev **device,
const struct lmk04828_init_param *init_param)
{
int ret = SUCCESS;
struct lmk04828_dev *dev;
dev = (struct lmk04828_dev *)malloc(sizeof(*dev));
if (!dev)
return FAILURE;
/* SPI */
ret = spi_init(&dev->spi_desc, init_param->spi_init);
*device = dev;
return ret;
}
/***************************************************************************//**
* @brief Free the resources allocated by lmk04828_setup().
*
* @param dev - The device structure.
*
* @return SUCCESS in case of success, negative error code otherwise.
*******************************************************************************/
int32_t lmk04828_remove(struct lmk04828_dev *dev)
{
int32_t ret;
ret = spi_remove(dev->spi_desc);
free(dev);
return ret;
}
@@ -0,0 +1,90 @@
/***************************************************************************//**
* @file lmk04828.h
* @brief Header file of lmk04828 Driver.
* @author DBogdan ([email protected])
********************************************************************************
* Copyright 2014-2016(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
*******************************************************************************/
#ifndef LMK04828_H_
#define LMK04828_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdint.h>
#include "delay.h"
#include "spi.h"
#include "gpio.h"
/******************************************************************************/
/********************** Macros and Constants Definitions **********************/
/******************************************************************************/
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
struct lmk04828_dev {
/* SPI */
struct spi_desc *spi_desc;
};
struct lmk04828_init_param {
/* SPI */
struct spi_init_param *spi_init;
};
struct lmk04828_config {
uint16_t addr;
uint8_t value;
};
/******************************************************************************/
/************************ Functions Declarations ******************************/
/******************************************************************************/
int32_t lmk04828_read(struct lmk04828_dev *dev,
uint16_t reg_addr,
uint8_t *reg_data);
int32_t lmk04828_write(struct lmk04828_dev *dev,
uint16_t reg_addr,
uint8_t reg_data);
int32_t lmk04828_init(struct lmk04828_dev **device,
const struct lmk04828_init_param *init_param);
int32_t lmk04828_remove(struct lmk04828_dev *dev);
#endif
@@ -0,0 +1,129 @@
/***************************************************************************//**
* @file lmx2594.c
* @brief Implementation of AD9680 Driver.
* @author DBogdan ([email protected])
********************************************************************************
* Copyright 2014-2016(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 Files **********************************/
/******************************************************************************/
#include "../lmx2594/lmx2594.h"
#include <stdlib.h>
#include <stdio.h>
#include "../../../include/error.h"
/***************************************************************************//**
* @brief lmx2594_read
*******************************************************************************/
int32_t lmx2594_read(struct lmx2594_dev *dev,
uint8_t reg_addr,
uint16_t *reg_data)
{
uint8_t tx_buf[1];
uint8_t rx_buf[2];
int32_t ret;
tx_buf[0] = 0x80 | reg_addr;
ret = spi_write_and_read_3wire(dev->spi_desc,
tx_buf, rx_buf, 1, 2);
*reg_data = rx_buf[1];
*reg_data |= ((uint16_t)rx_buf[0]) << 8;
return ret;
}
/***************************************************************************//**
* @brief lmx2594_write
*******************************************************************************/
int32_t lmx2594_write(struct lmx2594_dev *dev,
uint8_t reg_addr,
uint16_t reg_data)
{
uint8_t buf[3];
int32_t ret;
buf[0] = reg_addr;
buf[1] = reg_data >> 8;
buf[2] = reg_data & 0xFF;
ret = spi_write_and_read_3wire(dev->spi_desc,
buf, NULL, 3, 0);
return ret;
}
/***************************************************************************//**
* @brief lmx2594_init
*******************************************************************************/
int32_t lmx2594_init(struct lmx2594_dev **device,
const struct lmx2594_init_param *init_param)
{
int ret = SUCCESS;
struct lmx2594_dev *dev;
dev = (struct lmx2594_dev *)malloc(sizeof(*dev));
if (!dev)
return FAILURE;
/* SPI */
ret = spi_init(&dev->spi_desc, init_param->spi_init);
*device = dev;
return ret;
}
/***************************************************************************//**
* @brief Free the resources allocated by lmx2594_setup().
*
* @param dev - The device structure.
*
* @return SUCCESS in case of success, negative error code otherwise.
*******************************************************************************/
int32_t lmx2594_remove(struct lmx2594_dev *dev)
{
int32_t ret;
ret = spi_remove(dev->spi_desc);
free(dev);
return ret;
}
@@ -0,0 +1,90 @@
/***************************************************************************//**
* @file lmx2594.h
* @brief Header file of lmx2594 Driver.
* @author DBogdan ([email protected])
********************************************************************************
* Copyright 2014-2016(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
*******************************************************************************/
#ifndef LMX2594_H_
#define LMX2594_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdint.h>
#include "delay.h"
#include "spi.h"
#include "gpio.h"
/******************************************************************************/
/********************** Macros and Constants Definitions **********************/
/******************************************************************************/
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
struct lmx2594_dev {
/* SPI */
struct spi_desc *spi_desc;
};
struct lmx2594_init_param {
/* SPI */
struct spi_init_param *spi_init;
};
struct lmx2594_config {
uint8_t addr;
uint16_t value;
};
/******************************************************************************/
/************************ Functions Declarations ******************************/
/******************************************************************************/
int32_t lmx2594_read(struct lmx2594_dev *dev,
uint8_t reg_addr,
uint16_t *reg_data);
int32_t lmx2594_write(struct lmx2594_dev *dev,
uint8_t reg_addr,
uint16_t reg_data);
int32_t lmx2594_init(struct lmx2594_dev **device,
const struct lmx2594_init_param *init_param);
int32_t lmx2594_remove(struct lmx2594_dev *dev);
#endif
@@ -0,0 +1,79 @@
/***************************************************************************//**
* @file xilinx/xilinx_axi_io.c
* @brief Implementation of Xilinx AXI IO.
* @author Antoniu Miclaus ([email protected])
********************************************************************************
* Copyright 2019(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 Files **********************************/
/******************************************************************************/
#include <xil_io.h>
#include "error.h"
#include "axi_io.h"
/******************************************************************************/
/************************ Functions Definitions *******************************/
/******************************************************************************/
/**
* @brief AXI IO Xilinx specific read function.
* @param base - Base address
* @param offset - Address offset
* @param data - variable where returned data is stored
* @return 0 in case of success, -1 otherwise.
*/
int32_t axi_io_read(uint32_t base, uint32_t offset, uint32_t *data)
{
*data = Xil_In32(base + offset);
return 0;
}
/**
* @brief AXI IO Xilinx specific write function.
* @param base - Base address
* @param offset - Address offset
* @param data - data to be written.
* @return 0 in case of success, -1 otherwise.
*/
int32_t axi_io_write(uint32_t base, uint32_t offset, uint32_t data)
{
Xil_Out32(base + offset, data);
return 0;
}
@@ -0,0 +1,100 @@
/***************************************************************************//**
* @file xilinx/xilinx_delay.c
* @brief Implementation of Xilinx Delay Functions.
* @author Antoniu Miclaus ([email protected])
********************************************************************************
* Copyright 2019(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 Files **********************************/
/******************************************************************************/
#include "delay.h"
#include <sleep.h>
#ifdef _XPARAMETERS_PS_H_
#include "util.h"
#include "xtime_l.h"
#endif
/******************************************************************************/
/************************ Functions Definitions *******************************/
/******************************************************************************/
/**
* @brief Generate microseconds delay.
* @param usecs - Delay in microseconds.
* @return None.
*/
void udelay(uint32_t usecs)
{
#ifdef _XPARAMETERS_PS_H_
usleep(usecs);
#else
usleep_MB(usecs);
#endif
}
/**
* @brief Generate miliseconds delay.
* @param msecs - Delay in miliseconds.
* @return None.
*/
void mdelay(uint32_t msecs)
{
#ifdef _XPARAMETERS_PS_H_
usleep(msecs * 1000);
#else
usleep_MB(msecs * 1000);
#endif
}
/**
* @brief Get current time.
* @return Current time structure from system start (seconds, microseconds).
*/
struct time get_time(void)
{
struct time t = {0, 0};
#ifdef _XPARAMETERS_PS_H_
unsigned long long Xtime_Global;
uint32_t rem;
XTime_GetTime(&Xtime_Global);
t.s = div_u64_rem(Xtime_Global, COUNTS_PER_SECOND, &rem);
t.us = div_u64((uint64_t)rem * 1000000, COUNTS_PER_SECOND);
#endif
return t;
}
@@ -0,0 +1,464 @@
/***************************************************************************//**
* @file xilinx/xilinx_gpio.c
* @brief Implementation of Xilinx GPIO Generic Driver.
* @author Antoniu Miclaus ([email protected])
********************************************************************************
* Copyright 2019(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 Files **********************************/
/******************************************************************************/
#include <stdlib.h>
#include <xparameters.h>
#ifdef XPAR_XGPIO_NUM_INSTANCES
#include <xgpio.h>
#endif
#ifdef XPAR_XGPIOPS_NUM_INSTANCES
#include <xgpiops.h>
#endif
#include "error.h"
#include "gpio.h"
#include "xilinx_gpio.h"
/******************************************************************************/
/************************ Functions Definitions *******************************/
/******************************************************************************/
/**
* @brief Prepare the GPIO decriptor.
* @param desc - The GPIO descriptor.
* @param param - The structure that contains the GPIO parameters.
* @return 0 in case of success, -1 otherwise.
*/
int32_t _gpio_init(struct gpio_desc *desc,
const struct gpio_init_param *param)
{
int32_t ret;
struct xil_gpio_desc *xdesc;
struct xil_gpio_init_param *xinit;
ret = -1;
xdesc = desc->extra;
xinit = param->extra;
xdesc->type = xinit->type;
desc->number = param->number;
switch (xinit->type) {
case GPIO_PL:
#ifdef XGPIO_H
xdesc->instance = (XGpio *)malloc(sizeof(XGpio));
if(!xdesc->instance)
goto pl_error;
xdesc->config = XGpio_LookupConfig(xinit->device_id);
if(xdesc->config == NULL)
goto pl_error;
ret = XGpio_CfgInitialize(xdesc->instance,
xdesc->config,
((XGpio_Config*)xdesc->config)
->BaseAddress);
if(ret < 0)
goto pl_error;
break;
pl_error:
free(xdesc->instance);
#endif
goto error;
case GPIO_PS:
#ifdef XGPIOPS_H
xdesc->instance = (XGpioPs *)malloc(sizeof(XGpioPs));
if(!xdesc->instance)
goto ps_error;
xdesc->config = XGpioPs_LookupConfig(xinit->device_id);
if(xdesc->config == NULL)
goto ps_error;
ret = XGpioPs_CfgInitialize(xdesc->instance,
xdesc->config,
((XGpioPs_Config*)xdesc->config)->BaseAddr);
if(ret < 0)
goto ps_error;
break;
ps_error:
free(xdesc->instance);
#endif
goto error;
error:
default:
return -1;
}
return 0;
}
/**
* @brief Obtain the GPIO decriptor.
* @param desc - The GPIO descriptor.
* @param param - GPIO initialization parameters
* @return 0 in case of success, -1 otherwise.
*/
int32_t xil_gpio_get(struct gpio_desc **desc,
const struct gpio_init_param *param)
{
struct gpio_desc *descriptor;
struct xil_gpio_desc *extra;
int32_t ret;
descriptor = (struct gpio_desc *)malloc(sizeof(*descriptor));
extra = (struct xil_gpio_desc*)malloc(sizeof(*extra));
if (!descriptor || !extra)
return -1;
descriptor->extra = extra;
ret = _gpio_init(descriptor, param);
if(ret != 0)
goto error;
*desc = descriptor;
return 0;
error:
free(extra);
free(descriptor);
return -1;
}
/**
* @brief Get the value of an optional GPIO.
* @param desc - The GPIO descriptor.
* @param param - GPIO Initialization parameters.
* @return 0 in case of success, -1 otherwise.
*/
int32_t xil_gpio_get_optional(struct gpio_desc **desc,
const struct gpio_init_param *param)
{
if(param == NULL) {
*desc = NULL;
return 0;
}
return xil_gpio_get(desc, param);
}
/**
* @brief Free the resources allocated by gpio_get().
* @param desc - The GPIO descriptor.
* @return 0 in case of success, -1 otherwise.
*/
int32_t xil_gpio_remove(struct gpio_desc *desc)
{
if (desc != NULL) {
free(((struct xil_gpio_desc *)(desc->extra))->instance);
free(desc->extra);
free(desc);
}
return 0;
}
/**
* @brief Enable the input direction of the specified GPIO.
* @param desc - The GPIO descriptor.
* @return 0 in case of success, -1 otherwise.
*/
int32_t xil_gpio_direction_input(struct gpio_desc *desc)
{
struct xil_gpio_desc *extra;
#ifdef XGPIO_H
uint8_t pin = desc->number;
uint32_t channel = 1;
uint32_t config = 0;
#endif
extra = desc->extra;
switch (extra->type) {
case GPIO_PL:
#ifdef XGPIO_H
/* We assume that pin 32 is the first pin from channel 2 */
if (pin >= 32) {
channel = 2;
pin -= 32;
}
config = XGpio_GetDataDirection((XGpio *)extra->instance,
channel);
config |= (1 << pin);
XGpio_SetDataDirection((XGpio *)extra->instance,
channel,
config);
#endif
break;
case GPIO_PS:
#ifdef XGPIOPS_H
XGpioPs_SetDirectionPin(extra->instance,
desc->number,
GPIO_IN);
#endif
break;
default:
return -1;
}
return 0;
}
/**
* @brief Enable the output direction of the specified GPIO.
* @param desc - The GPIO descriptor.
* @param value - The value.
* Example: GPIO_HIGH
* GPIO_LOW
* @return 0 in case of success, -1 otherwise.
*/
int32_t xil_gpio_direction_output(struct gpio_desc *desc,
uint8_t value)
{
struct xil_gpio_desc *extra;
#ifdef XGPIO_H
uint8_t pin = desc->number;
uint8_t channel;
uint32_t reg_val;
#endif
extra = desc->extra;
switch (extra->type) {
case GPIO_PL:
#ifdef XGPIO_H
if (pin >= 32) {
channel = 2;
pin -= 32;
} else
channel = 1;
reg_val = XGpio_GetDataDirection(extra->instance,
channel);
reg_val &= ~(1 << pin);
XGpio_SetDataDirection(extra->instance,
channel,
reg_val);
reg_val = XGpio_DiscreteRead(extra->instance,
channel);
if(value)
reg_val |= (1 << pin);
else
reg_val &= ~(1 << pin);
XGpio_DiscreteWrite(extra->instance,
channel,
reg_val);
#endif
break;
case GPIO_PS:
#ifdef XGPIOPS_H
XGpioPs_SetDirectionPin(extra->instance,
desc->number,
GPIO_OUT);
XGpioPs_SetOutputEnablePin(extra->instance,
desc->number,
GPIO_OUT);
XGpioPs_WritePin(extra->instance,
desc->number,
value);
#endif
break;
default:
return -1;
}
return 0;
}
/**
* @brief Get the direction of the specified GPIO.
* @param desc - The GPIO descriptor.
* @param direction - The direction.
* Example: GPIO_OUT
* GPIO_IN
* @return 0 in case of success, -1 otherwise.
*/
int32_t xil_gpio_get_direction(struct gpio_desc *desc,
uint8_t *direction)
{
if (!desc)
return -1;
struct xil_gpio_desc *extra;
uint8_t pin = desc->number;
#ifdef XGPIO_H
uint8_t channel;
#endif
extra = desc->extra;
switch (extra->type) {
case GPIO_PL:
#ifdef XGPIO_H
if (pin >= 32) {
channel = 2;
pin -= 32;
} else
channel = 1;
*direction = ((XGpio_GetDataDirection(extra->instance,
channel) >> pin) & 0x1) ^ 0x1;
#endif
break;
case GPIO_PS:
#ifdef XGPIOPS_H
*direction = XGpioPs_GetDirectionPin(extra->instance, pin);
#endif
break;
default:
return -1;
}
return 0;
}
/**
* @brief Set the value of the specified GPIO.
* @param desc - The GPIO descriptor.
* @param value - The value.
* Example: GPIO_HIGH
* GPIO_LOW
* @return 0 in case of success, -1 otherwise.
*/
int32_t xil_gpio_set_value(struct gpio_desc *desc,
uint8_t value)
{
struct xil_gpio_desc *extra;
#ifdef XGPIO_H
uint8_t pin = desc->number;
uint8_t channel;
uint32_t reg_val;
#endif
extra = desc->extra;
switch (extra->type) {
case GPIO_PL:
#ifdef XGPIO_H
if (pin >= 32) {
channel = 2;
pin -= 32;
} else
channel = 1;
reg_val = XGpio_DiscreteRead(extra->instance, channel);
if(value)
reg_val |= (1 << pin);
else
reg_val &= ~(1 << pin);
XGpio_DiscreteWrite(extra->instance, channel, reg_val);
#endif
break;
case GPIO_PS:
#ifdef XGPIOPS_H
XGpioPs_WritePin(extra->instance, desc->number, value);
#endif
break;
default:
return -1;
}
return 0;
}
/**
* @brief Get the value of the specified GPIO.
* @param desc - The GPIO descriptor.
* @param value - The value.
* Example: GPIO_HIGH
* GPIO_LOW
* @return 0 in case of success, -1 otherwise.
*/
int32_t xil_gpio_get_value(struct gpio_desc *desc,
uint8_t *value)
{
if (!desc)
return -1;
struct xil_gpio_desc *extra;
uint8_t pin = desc->number;
#ifdef XGPIO_H
uint8_t channel;
#endif
extra = desc->extra;
switch (extra->type) {
case GPIO_PL:
#ifdef XGPIO_H
if (pin >= 32) {
channel = 2;
pin -= 32;
} else
channel = 1;
*value = (XGpio_DiscreteRead(extra->instance, channel) >> pin) & 0x01;
#endif
break;
case GPIO_PS:
#ifdef XGPIOPS_H
*value = XGpioPs_ReadPin(extra->instance, pin);
#endif
break;
default:
return -1;
}
return 0;
}
/**
* @brief Xilinx platform specific GPIO platform ops structure
*/
const struct gpio_platform_ops xil_gpio_ops = {
.gpio_ops_get = &xil_gpio_get,
.gpio_ops_get_optional = &xil_gpio_get_optional,
.gpio_ops_remove = &xil_gpio_remove,
.gpio_ops_direction_input = &xil_gpio_direction_input,
.gpio_ops_direction_output = &xil_gpio_direction_output,
.gpio_ops_get_direction = &xil_gpio_get_direction,
.gpio_ops_set_value = &xil_gpio_set_value,
.gpio_ops_get_value = &xil_gpio_get_value,
};
@@ -0,0 +1,95 @@
/*******************************************************************************
* @file xilinx/xilinx_gpio.h
* @brief Header containing extra types used in the gpio driver
* @author scuciurean ([email protected])
********************************************************************************
* Copyright 2019(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
*******************************************************************************/
#ifndef XILINX_GPIO_H_
#define XILINX_GPIO_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdint.h>
#include <stdbool.h>
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
/**
* @enum xil_gpio_type
* @brief Xilinx platform architecture sections
*/
enum xil_gpio_type {
/** Programmable Logic */
GPIO_PL,
/** Processing System */
GPIO_PS
};
/**
* @struct xil_gpio_init_param
* @brief Structure holding the initialization parameters for Xilinx platform
* specific GPIO parameters.
*/
struct xil_gpio_init_param {
/** Xilinx architecture */
enum xil_gpio_type type;
/** Device ID */
uint32_t device_id;
};
/**
* @struct xil_gpio_desc
* @brief Xilinx platform specific GPIO descriptor
*/
struct xil_gpio_desc {
/** Xilinx architecture */
enum xil_gpio_type type;
/** Xilinx GPIO configuration */
void *config;
/** Xilinx GPIO Instance */
void *instance;
};
/**
* @brief Xilinx platform specific gpio platform ops structure
*/
extern const struct gpio_platform_ops xil_gpio_ops;
#endif
@@ -0,0 +1,360 @@
/***************************************************************************//**
* @file xilinx/xilinx_gpio_irq.c
* @brief Implementation of Xilinx GPIO IRQ Generic Driver.
* @author Porumb Andrei ([email protected])
********************************************************************************
* Copyright 2021(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 Files **********************************/
/******************************************************************************/
#include <stdlib.h>
#include "xparameters.h"
#include "error.h"
#include "xilinx_gpio_irq.h"
#include "util.h"
#include "list.h"
#include "irq.h"
/******************************************************************************/
/************************ Functions Definitions *******************************/
/******************************************************************************/
/**
* @brief Comparing function used by list.
* @param desc_a - Compared item
* @param desc_b - Reference item
* @return - 0 if items match
*/
static int32_t call_cmp(struct xil_callback_desc *desc_a,
struct xil_callback_desc *desc_b)
{
return desc_a->pin_nb - desc_b->pin_nb;
}
/**
* @brief Function called when GPIO IRQ occurs.
* @param param - GPIO IRQ desc's extra field
* @return - None.
*/
static void xil_gpio_irq_handler(struct xil_gpio_irq_desc *param)
{
int32_t status = 0;
int32_t pin_nb;
struct xil_callback_desc *callback_desc;
status = iterator_move_to_idx(param->it, 0);
while(!status) {
iterator_read(param->it, &callback_desc);
status = iterator_move(param->it, 1);
if(XGpioPs_IntrGetStatusPin(&param->my_Gpio, callback_desc->pin_nb))
callback_desc->triggered = true;
}
status = iterator_move_to_idx(param->it, 0);
while(!status) {
iterator_read(param->it, &callback_desc);
status = iterator_move(param->it, 1);
if(callback_desc->triggered == true) {
callback_desc->triggered = false;
XGpioPs_IntrDisablePin(&param->my_Gpio, callback_desc->pin_nb);
XGpioPs_IntrClearPin(&param->my_Gpio, callback_desc->pin_nb);
callback_desc->callback.legacy_callback(callback_desc->callback.ctx, 0U, NULL);
if(callback_desc->enabled)
XGpioPs_IntrEnablePin(&param->my_Gpio, callback_desc->pin_nb);
}
}
}
/**
* @brief Disable specific GPIO IRQ pin.
* @param desc - The GPIO IRQ controller descriptor.
* @param irq_id - Pin number.
* @return 0 in case of success, -1 otherwise.
*/
int32_t xil_gpio_irq_disable(struct irq_ctrl_desc *desc, uint32_t irq_id)
{
int32_t status;
struct xil_gpio_irq_desc *extra;
struct xil_callback_desc *callback_desc;
extra = desc->extra;
status = iterator_move_to_idx(extra->it, 0);
while(!status) {
iterator_read(extra->it, &callback_desc);
status = iterator_move(extra->it, 1);
if(callback_desc->pin_nb == irq_id) {
callback_desc->enabled = false;
break;
}
}
XGpioPs_IntrDisablePin(&extra->my_Gpio, irq_id);
return 0;
}
/**
* @brief Initialize the GPIO IRQ controller.
* @param desc - The GPIO IRQ controller descriptor.
* @param param - The GPIO IRQ controller initial parameters.
* irq_ctrl_id from irq_init_param is the interrupt id for the parent controller
* @return 0 in case of success, -1 otherwise.
*/
int32_t xil_gpio_irq_ctrl_init(struct irq_ctrl_desc **desc,
const struct irq_init_param *param)
{
int32_t i;
int32_t status;
struct irq_ctrl_desc *ldesc;
static XGpioPs_Config *GPIO_Config;
struct xil_gpio_irq_desc *xil_desc;
struct xil_gpio_irq_init_param *xil_ip;
struct callback_desc callback;
xil_desc = (struct xil_gpio_irq_desc *)calloc(1, sizeof(*xil_desc));
if(!xil_desc)
return -ENOMEM;
ldesc = (struct irq_ctrl_desc *)calloc(1, sizeof(*ldesc));
if(!ldesc) {
free(xil_desc);
return -ENOMEM;
}
xil_ip = param->extra;
GPIO_Config = XGpioPs_LookupConfig(xil_ip->gpio_device_id);
status = XGpioPs_CfgInitialize(&xil_desc->my_Gpio, GPIO_Config,
GPIO_Config->BaseAddr);
if(status)
goto error_desc;
ldesc->extra = xil_desc;
xil_desc->parent_desc = xil_ip->parent_desc;
status = list_init(&xil_desc->callback_list, LIST_DEFAULT,
call_cmp);
if(status)
goto error_list;
status = iterator_init(&xil_desc->it, xil_desc->callback_list, 0);
if(status) {
iterator_remove(xil_desc->it);
goto error_list;
}
ldesc->irq_ctrl_id = param->irq_ctrl_id;
status = irq_trigger_level_set(xil_desc->parent_desc, ldesc->irq_ctrl_id,
IRQ_EDGE_RISING);
if(status)
goto error_op;
status = irq_enable(xil_desc->parent_desc, ldesc->irq_ctrl_id);
if(status)
goto error_op;
callback.legacy_callback = &xil_gpio_irq_handler;
callback.ctx = ldesc->extra;
status = irq_register_callback(xil_desc->parent_desc, ldesc->irq_ctrl_id,
&callback);
if(status)
goto error_op;
*desc = ldesc;
return 0;
error_op:
iterator_remove(xil_desc->it);
error_list:
list_remove(xil_desc->callback_list);
error_desc:
free(xil_desc);
free(ldesc);
return status;
}
/**
* @brief Set GPIO interrupt trigger level.
* @param desc - The GPIO IRQ controller descriptor.
* @param irq_id - Pin number.
* @param trig - New trigger level for the GPIO interrupt.
* @return 0 in case of success, -1 otherwise.
*/
int32_t xil_gpio_irq_trigger_level_set(struct irq_ctrl_desc *desc,
uint32_t irq_id,
enum irq_trig_level trig)
{
static const int32_t trig_level[5] = {XGPIOPS_IRQ_TYPE_LEVEL_LOW,
XGPIOPS_IRQ_TYPE_LEVEL_HIGH,
XGPIOPS_IRQ_TYPE_EDGE_FALLING,
XGPIOPS_IRQ_TYPE_EDGE_RISING,
XGPIOPS_IRQ_TYPE_EDGE_BOTH
};
struct xil_gpio_irq_desc *extra;
extra = desc->extra;
XGpioPs_SetIntrTypePin(&extra->my_Gpio, irq_id, trig_level[trig]);
return 0;
}
/**
* @brief Register pin specific GPIO interrupt.
* @param desc - The GPIO IRQ controller descriptor.
* @param irq_id - Pin number.
* @param callback_desc - Callback.
* @return 0 in case of success, -1 otherwise.
*/
int32_t xil_gpio_irq_register_callback(struct irq_ctrl_desc *desc,
uint32_t irq_id,
struct callback_desc *callback_desc)
{
struct xil_callback_desc *dev_callback;
struct xil_gpio_irq_desc *extra;
dev_callback = (struct xil_callback_desc *)calloc(1,
sizeof(*dev_callback));
if(!dev_callback)
return -1;
dev_callback->pin_nb = irq_id;
dev_callback->callback.legacy_callback = callback_desc->legacy_callback;
dev_callback->callback.ctx = callback_desc->ctx;
dev_callback->triggered = false;
extra = desc->extra;
XGpioPs_SetDirectionPin(&extra->my_Gpio, irq_id, 0);
list_add_last(extra->callback_list, dev_callback);
return 0;
}
/**
* @brief Unregister pin specific GPIO interrupt.
* @param desc - The GPIO IRQ controller descriptor.
* @param irq_id - Pin number.
* @param cb - Callback descriptor.
* @return 0 in case of success, -1 otherwise.
*/
int32_t xil_gpio_irq_unregister_callback(struct irq_ctrl_desc *desc,
uint32_t irq_id, struct callback_desc *cb)
{
int32_t status;
struct xil_gpio_irq_desc *extra;
struct xil_callback_desc *dev_callback;
struct xil_callback_desc search_callback;
extra = desc->extra;
search_callback.pin_nb = irq_id;
status = list_get_find(extra->callback_list, &dev_callback,
&search_callback);
if(status)
return -ENXIO;
free(dev_callback);
return 0;
}
/**
* @brief Enable specific GPIO IRQ pin.
* @param desc - The GPIO IRQ controller descriptor.
* @param irq_id - Pin number.
* @return 0 in case of success, -1 otherwise.
*/
int32_t xil_gpio_irq_enable(struct irq_ctrl_desc *desc, uint32_t irq_id)
{
int32_t status;
struct xil_gpio_irq_desc *extra;
struct xil_callback_desc *callback_desc;
extra = desc->extra;
status = iterator_move_to_idx(extra->it, 0);
while(!status) {
iterator_read(extra->it, &callback_desc);
status = iterator_move(extra->it, 1);
if(callback_desc->pin_nb == irq_id) {
callback_desc->enabled = true;
XGpioPs_IntrClearPin(&extra->my_Gpio, irq_id);
break;
}
}
XGpioPs_IntrEnablePin(&extra->my_Gpio, irq_id);
return 0;
}
/**
* @brief Remove the GPIO IRQ controller.
* @param desc - The GPIO IRQ controller descriptor.
* @return 0 in case of success, -1 otherwise.
*/
int32_t xil_gpio_irq_ctrl_remove(struct irq_ctrl_desc *desc)
{
struct xil_gpio_irq_desc *extra;
struct xil_callback_desc *callback_desc;
if (!desc)
return -EINVAL;
extra = desc->extra;
while (0 == list_get_first(extra->callback_list, &callback_desc))
free(callback_desc);
iterator_remove(extra->it);
list_remove(extra->callback_list);
free(extra);
free(desc);
return 0;
}
/**
* @brief Xilinx platform specific GPIO IRQ platform ops structure
*/
const struct irq_platform_ops xil_gpio_irq_ops = {
.init = &xil_gpio_irq_ctrl_init,
.enable = &xil_gpio_irq_enable,
.disable = &xil_gpio_irq_disable,
.trigger_level_set = &xil_gpio_irq_trigger_level_set,
.register_callback = &xil_gpio_irq_register_callback,
.unregister_callback = xil_gpio_irq_unregister_callback,
.remove = &xil_gpio_irq_ctrl_remove
};
@@ -0,0 +1,92 @@
/***************************************************************************//**
* @file xilinx_gpio_irq.h
* @brief Implementation of Xilinx GPIO IRQ Generic Driver.
* @author Porumb Andrei ([email protected])
********************************************************************************
* Copyright 2021(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
*******************************************************************************/
#ifndef XILINX_GPIO_IRQ_H_
#define XILINX_GPIO_IRQ_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include "stdbool.h"
#include "list.h"
#include "xgpiops.h"
#include "irq.h"
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
/**
* @struct xil_callback_desc
* @brief Structure holding callback parameters for each pin
*/
struct xil_callback_desc {
int32_t pin_nb;
struct callback_desc callback;
bool triggered;
bool enabled;
};
/**
* @struct xil_gpio_irq_init_param
* @brief Structure holding the initialization parameters for Xilinx platform
* specific GPIO IRQ parameters.
*/
struct xil_gpio_irq_init_param {
struct irq_ctrl_desc *parent_desc;
int32_t gpio_device_id;
};
/**
* @struct xil_gpio_irq_desc
* @brief Xilinx platform specific GPIO IRQ descriptor
*/
struct xil_gpio_irq_desc {
struct irq_ctrl_desc *parent_desc;
XGpioPs my_Gpio;
struct list_desc *callback_list;
struct iterator *it;
};
/**
* @brief Xilinx specific GPIO IRQ platform ops structure
*/
extern const struct irq_platform_ops xil_gpio_irq_ops;
#endif
@@ -0,0 +1,514 @@
/***************************************************************************//**
* @file xilinx/xilinx_i2c.c
* @brief Implementation of Xilinx I2C Generic Driver.
* @author Antoniu Miclaus ([email protected])
********************************************************************************
* Copyright 2019(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 Files **********************************/
/******************************************************************************/
#include <stdlib.h>
#include <xparameters.h>
#ifdef XPAR_XIIC_NUM_INSTANCES
#include <xiic.h>
#endif
#ifdef XPAR_XIICPS_NUM_INSTANCES
#include <xiicps.h>
#endif
#include "error.h"
#include "i2c.h"
#include "xilinx_i2c.h"
#include "list.h"
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
static struct list_desc *pl_list = NULL;
static struct iterator *pl_it = NULL;
#ifdef XIICPS_H
static struct list_desc *ps_list = NULL;
static struct iterator *ps_it = NULL;
#endif /* XIICPS_H */
/**
* @struct inst_table_item
* @brief Table item for I2C cores already started.
*/
struct inst_table_item {
/** Instance the BSP driver uses for this core. */
void *instance;
/** Core ID in BSP. */
uint32_t device_id;
/** Number of ADI driver instances running on this core. */
uint32_t inst_no;
};
#ifdef XPAR_XIICPS_NUM_INSTANCES
/** Save the current state of the bitrate to not change it each time */
static uint32_t ps_last_bitrate = 0;
#endif
/**
* @brief Xilinx platform specific I2C platform ops structure
*/
const struct i2c_platform_ops xil_i2c_ops = {
.i2c_ops_init = &xil_i2c_init,
.i2c_ops_write = &xil_i2c_write,
.i2c_ops_read = &xil_i2c_read,
.i2c_ops_remove = &xil_i2c_remove
};
/******************************************************************************/
/************************ Functions Definitions *******************************/
/******************************************************************************/
/**
* @brief Compare two I2C cores by ID.
* @param el1 - First I2C core to compare.
* @param el2 - Second I2C core to compare.
* @return \ref 0 if the two cores have the same ID,
* \ref difference between the first and the second IDs otherwise.
*/
static int32_t xil_i2c_cmp(void *el1, void *el2)
{
struct inst_table_item *sel1 = el1, *sel2 = el2;
return (sel1->device_id - sel2->device_id);
}
/**
* @brief Configure slave address and bitrate if needed
* @param desc - Descriptor of the I2C device
* @return 0 in case of success, -1 otherwise.
*/
static int32_t xil_i2c_set_transmission_config(struct i2c_desc *desc)
{
struct xil_i2c_desc *xil_i2c_desc = desc->extra;
#ifdef XIICPS_H
int32_t ret;
#endif
switch (xil_i2c_desc->type) {
case IIC_PL:
#ifdef XIIC_H
break;
#endif
return -1;
case IIC_PS:
#ifdef XIICPS_H
if (desc->max_speed_hz != ps_last_bitrate) {
ret = XIicPs_SetSClk(xil_i2c_desc->instance, desc->max_speed_hz);
if (ret != XST_SUCCESS)
return -1;
ps_last_bitrate = desc->max_speed_hz;
}
break;
#endif
return -1;
default:
return -1;
}
return 0;
}
/**
* @brief Initialize the I2C communication peripheral.
* @param desc - The I2C descriptor.
* @param param - The structure that contains the I2C parameters.
* @return 0 in case of success, -1 otherwise.
*/
int32_t xil_i2c_init(struct i2c_desc **desc,
const struct i2c_init_param *param)
{
int32_t ret;
struct i2c_desc *idesc;
struct xil_i2c_desc *xdesc;
struct xil_i2c_init_param *xinit;
idesc = (struct i2c_desc *)malloc(sizeof(*idesc));
xdesc = (struct xil_i2c_desc *)malloc(sizeof(*xdesc));
if(!idesc || !xdesc)
goto error;
idesc->max_speed_hz = param->max_speed_hz;
idesc->slave_address = param->slave_address;
xinit = param->extra;
idesc->extra = xdesc;
xdesc->type = xinit->type;
xdesc->device_id = xinit->device_id;
switch (xinit->type) {
case IIC_PL:
#ifdef XIIC_H
; /** Intentional empty statement */
struct inst_table_item tab_check_pl;
struct inst_table_item *temp_el_pl;
if (!pl_list)
list_init(&pl_list, LIST_DEFAULT, xil_i2c_cmp);
if (!pl_it)
iterator_init(&pl_it, pl_list, true);
tab_check_pl.device_id = xdesc->device_id;
if (!IS_ERR_VALUE(list_read_find(pl_list, (void **)&temp_el_pl,
&tab_check_pl))) {
xdesc->instance = temp_el_pl->instance;
temp_el_pl->inst_no++;
break;
}
xdesc->instance = (XIic *)malloc(sizeof(XIic));
if(!xdesc->instance)
goto pl_error;
xdesc->config = XIic_LookupConfig(xinit->device_id);
if(xdesc->config == NULL)
goto pl_error;
ret = XIic_CfgInitialize(xdesc->instance,
xdesc->config,
((XIic_Config*)xdesc->config)
->BaseAddress);
if(ret != 0)
goto pl_error;
ret = XIic_Start(xdesc->instance);
if(ret != 0)
goto pl_error;
ret = XIic_SetAddress(xdesc->instance,
XII_ADDR_TO_SEND_TYPE,
param->slave_address);
if(ret != 0)
goto pl_error;
ret = XIic_SelfTest(xdesc->instance);
if(ret < 0)
goto pl_error;
ret = XIic_SetGpOutput(xdesc->instance, 1);
if(ret < 0)
goto pl_error;
temp_el_pl = (struct inst_table_item*)calloc(1, sizeof(*temp_el_pl));
temp_el_pl->device_id = xinit->device_id;
temp_el_pl->inst_no = 1;
temp_el_pl->instance = xdesc->instance;
pl_list->push(pl_list, temp_el_pl);
break;
pl_error:
free(xdesc->instance);
#endif
goto error;
case IIC_PS:
#ifdef XIICPS_H
; /** Intentional empty statement */
struct inst_table_item tab_check_ps;
struct inst_table_item *temp_el_ps;
if (!pl_list)
list_init(&ps_list, LIST_DEFAULT, xil_i2c_cmp);
if (!pl_it)
iterator_init(&ps_it, ps_list, true);
tab_check_ps.device_id = xdesc->device_id;
if (!IS_ERR_VALUE(list_read_find(ps_list,
(void **)&temp_el_ps,
&tab_check_ps))) {
xdesc->instance = temp_el_ps->instance;
temp_el_ps->inst_no++;
break;
}
xdesc->instance = (XIicPs *)malloc(sizeof(XIicPs));
if(!xdesc->instance)
goto ps_error;
xdesc->config = XIicPs_LookupConfig(xinit->device_id);
if(xdesc->config == NULL)
goto ps_error;
ret = XIicPs_CfgInitialize(xdesc->instance,
xdesc->config,
((XIicPs_Config*)xdesc->config)
->BaseAddress);
if(ret != 0)
goto ps_error;
XIicPs_SetSClk(xdesc->instance, param->max_speed_hz);
temp_el_ps = (struct inst_table_item*)calloc(1, sizeof(*temp_el_ps));
temp_el_ps->device_id = xinit->device_id;
temp_el_ps->inst_no = 1;
temp_el_ps->instance = xdesc->instance;
ps_list->push(ps_list, temp_el_ps);
break;
ps_error:
free(xdesc->instance);
#endif
goto error;
default:
goto error;
break;
}
*desc = idesc;
return 0;
error:
free(idesc);
free(xdesc);
return -1;
}
/**
* @brief Free the resources allocated by i2c_init().
* @param desc - The I2C descriptor.
* @return 0 in case of success, -1 otherwise.
*/
int32_t xil_i2c_remove(struct i2c_desc *desc)
{
struct xil_i2c_desc *xdesc;
int32_t ret;
xdesc = desc->extra;
switch (xdesc->type) {
case IIC_PL:
#ifdef XIIC_H
; /** Intentional empty statement */
struct inst_table_item tab_check_pl;
struct inst_table_item *temp_el_pl;
tab_check_pl.device_id = xdesc->device_id;
ret = iterator_find(pl_it, &tab_check_pl);
if (ret != 0)
goto error;
iterator_read(pl_it, (void **)&temp_el_pl);
temp_el_pl->inst_no--;
if (temp_el_pl->inst_no != 0)
break;
ret = XIic_Stop(((XIic *)xdesc->instance));
if(ret != 0)
goto error;
/** Remove list element */
iterator_get(pl_it, (void **)&temp_el_pl);
free(temp_el_pl);
break;
#endif
goto error;
case IIC_PS:
#ifdef XIICPS_H
; /** Intentional empty statement */
struct inst_table_item tab_check_ps;
struct inst_table_item *temp_el_ps;
tab_check_ps.device_id = xdesc->device_id;
ret = iterator_find(ps_it, &tab_check_ps);
if (ret != 0)
goto error;
iterator_read(ps_it, (void **)&temp_el_ps);
temp_el_ps->inst_no--;
if (temp_el_ps->inst_no != 0)
break;
/** Remove list element */
iterator_get(ps_it, (void **)&temp_el_ps);
free(temp_el_ps);
break;
#endif
/* Intended fallthrough */
error:
default:
return -1;
}
free(desc->extra);
free(desc);
return 0;
}
/**
* @brief Write data to a slave device.
* @param desc - The I2C descriptor.
* @param data - Buffer that stores the transmission data.
* @param bytes_number - Number of bytes to write.
* @param stop_bit - Stop condition control.
* Example: 0 - A stop condition will not be generated;
* 1 - A stop condition will be generated.
* @return 0 in case of success, -1 otherwise.
*/
int32_t xil_i2c_write(struct i2c_desc *desc,
uint8_t *data,
uint8_t bytes_number,
uint8_t stop_bit)
{
struct xil_i2c_desc *xdesc;
int32_t ret;
xdesc = desc->extra;
switch (xdesc->type) {
case IIC_PL:
#ifdef XIIC_H
ret = xil_i2c_set_transmission_config(desc);
if (ret != 0)
return -1;
XIic_Send(((XIic*)xdesc->instance)->BaseAddress,
desc->slave_address,
data,
bytes_number,
stop_bit ? XIIC_STOP : XIIC_REPEATED_START);
break;
#endif
goto error;
case IIC_PS:
#ifdef XIICPS_H
ret = xil_i2c_set_transmission_config(desc);
if (ret != 0)
return -1;
ret = XIicPs_SetOptions(xdesc->instance,
stop_bit ? 0 : XIICPS_REP_START_OPTION);
if(ret != 0)
goto error;
XIicPs_MasterSend(xdesc->instance,
data,
bytes_number,
desc->slave_address);
if(ret != 0)
goto error;
break;
#endif
/* Intended fallthrough */
error:
default:
return -1;
}
return 0;
}
/**
* @brief Read data from a slave device.
* @param desc - The I2C descriptor.
* @param data - Buffer that will store the received data.
* @param bytes_number - Number of bytes to read.
* @param stop_bit - Stop condition control.
* Example: 0 - A stop condition will not be generated;
* 1 - A stop condition will be generated.
* @return 0 in case of success, -1 otherwise.
*/
int32_t xil_i2c_read(struct i2c_desc *desc,
uint8_t *data,
uint8_t bytes_number,
uint8_t stop_bit)
{
struct xil_i2c_desc *xdesc;
int32_t ret;
xdesc = desc->extra;
switch (xdesc->type) {
case IIC_PL:
#ifdef XIIC_H
ret = xil_i2c_set_transmission_config(desc);
if (ret != 0)
return -1;
ret = XIic_Recv(((XIic*)xdesc->instance)->BaseAddress,
desc->slave_address,
data,
bytes_number,
stop_bit ? XIIC_STOP : XIIC_REPEATED_START);
if(ret != bytes_number)
goto error;
break;
#endif
goto error;
case IIC_PS:
#ifdef XIICPS_H
ret = xil_i2c_set_transmission_config(desc);
if (ret != 0)
return -1;
ret = XIicPs_SetOptions(xdesc->instance,
stop_bit ? 0 : XIICPS_REP_START_OPTION);
if(ret != 0)
goto error;
XIicPs_MasterRecv(xdesc->instance,
data,
bytes_number,
desc->slave_address);
if(ret != 0)
goto error;
break;
#endif
/* Intended fallthrough */
error:
default:
return -1;
break;
}
return 0;
}
@@ -0,0 +1,115 @@
/*******************************************************************************
* @file xilinx/xilinx_i2c.h
* @brief Header containing types used in the i2c driver.
* @author scuciurean ([email protected])
********************************************************************************
* Copyright 2019(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
*******************************************************************************/
#ifndef XILINX_I2C_H_
#define XILINX_I2C_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdint.h>
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
/**
* @enum xil_i2c_type
* @brief Xilinx platform architecture sections
*/
enum xil_i2c_type {
/** Programmable Logic */
IIC_PL,
/** Processing System */
IIC_PS
};
/**
* @struct xil_i2c_init
* @brief Structure holding the initialization parameters for Xilinx platform
* specific I2C parameters.
*/
struct xil_i2c_init_param {
/** Xilinx architecture */
enum xil_i2c_type type;
/** Device ID */
uint32_t device_id;
};
/**
* @struct xil_i2c_desc
* @brief Xilinx platform specific I2C descriptor
*/
struct xil_i2c_desc {
/** Xilinx architecture */
enum xil_i2c_type type;
/** Device ID */
uint32_t device_id;
/** Xilinx I2C configuration */
void *config;
/** Xilinx I2C Instance */
void *instance;
};
/**
* @brief Xilinx platform specific i2c platform ops structure
*/
extern const struct i2c_platform_ops xil_i2c_ops;
/******************************************************************************/
/************************ Functions Declarations ******************************/
/******************************************************************************/
/* Initialize the I2C communication peripheral. */
int32_t xil_i2c_init(struct i2c_desc **desc,
const struct i2c_init_param *param);
/* Free the resources allocated by i2c_init(). */
int32_t xil_i2c_remove(struct i2c_desc *desc);
/* I2C Write data */
int32_t xil_i2c_write(struct i2c_desc *desc, uint8_t *data,
uint8_t bytes_number, uint8_t stop_bit);
/* I2C Read data. */
int32_t xil_i2c_read(struct i2c_desc *desc, uint8_t *data,
uint8_t bytes_number, uint8_t stop_bit);
#endif // XILINX_I2C_H_
@@ -0,0 +1,433 @@
/***************************************************************************//**
* @file xilinx/xilinx_irq.c
* @brief Implementation of Xilinx IRQ Generic Driver.
* @author Cristian Pop ([email protected])
********************************************************************************
* Copyright 2019(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 Files **********************************/
/******************************************************************************/
#include <xparameters.h>
#include <stdlib.h>
#include "error.h"
#include "irq.h"
#include "xilinx_irq.h"
#ifdef XPAR_XSCUGIC_NUM_INSTANCES
#include <xscugic.h>
#endif
#ifdef XPAR_XINTC_NUM_INSTANCES
#include <xintc.h>
#endif
#ifdef XPAR_XTMRCTR_NUM_INSTANCES
#include <xtmrctr.h>
#endif
/******************************************************************************/
/************************ Functions Definitions *******************************/
/******************************************************************************/
/**
* @brief Initialize the IRQ interrupts.
* @param desc - The IRQ controller descriptor.
* @param param - The structure that contains the IRQ parameters.
* @return 0 in case of success, -1 otherwise.
*/
int32_t xil_irq_ctrl_init(struct irq_ctrl_desc **desc,
const struct irq_init_param *param)
{
int32_t status;
struct irq_ctrl_desc *descriptor;
struct xil_irq_desc *xil_dev;
#ifdef XSCUGIC_H
void *config;
#endif
descriptor = (struct irq_ctrl_desc *)calloc(1, sizeof *descriptor);
if(!descriptor)
return -1;
xil_dev = (struct xil_irq_desc *)calloc(1, sizeof *xil_dev);
if(!xil_dev) {
free(descriptor);
return -1;
}
Xil_ExceptionInit();
descriptor->irq_ctrl_id = param->irq_ctrl_id;
descriptor->extra = xil_dev;
xil_dev->type = ((struct xil_irq_init_param *)param->extra)->type;
switch(xil_dev->type) {
case IRQ_PS:
#ifdef XSCUGIC_H
xil_dev->instance = calloc(1, sizeof(XScuGic));
if(!xil_dev->instance)
goto error;
config = XScuGic_LookupConfig(descriptor->irq_ctrl_id);
if(!config)
goto ps_error;
status = XScuGic_CfgInitialize(xil_dev->instance, config,
((XScuGic_Config *)config)->CpuBaseAddress);
if (status != 0)
goto ps_error;
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler,
xil_dev->instance);
break;
ps_error:
free(xil_dev->instance);
#endif
goto error;
case IRQ_PL:
#ifdef XINTC_H
xil_dev->instance = calloc(1, sizeof(XIntc));
if(!xil_dev->instance)
goto error;
status = XIntc_Initialize(xil_dev->instance, descriptor->irq_ctrl_id);
if(status != 0)
goto pl_error;
status = XIntc_Start(xil_dev->instance, XIN_REAL_MODE);
if(status != 0)
goto pl_error;
break;
pl_error:
free(xil_dev->instance);
#endif
goto error;
default:
goto error;
break;
}
*desc = descriptor;
return 0;
error:
free(xil_dev);
free(descriptor);
return -1;
}
/**
* @brief Enable global interrupts.
* @return 0 in case of success, -1 otherwise.
*/
int32_t xil_irq_global_enable(struct irq_ctrl_desc *desc)
{
/* Enable interrupts */
Xil_ExceptionEnable();
return 0;
}
/**
* @brief Disable global interrupts.
* @return 0 in case of success, -1 otherwise.
*/
int32_t xil_irq_global_disable(struct irq_ctrl_desc *desc)
{
/* Disable interrupts */
Xil_ExceptionDisable();
return 0;
}
/**
* @brief Enable specific interrupt.
* @param desc - The IRQ controller descriptor.
* @param irq_id - Interrupt identifier.
* @return 0 in case of success, -1 otherwise.
*/
int32_t xil_irq_enable(struct irq_ctrl_desc *desc, uint32_t irq_id)
{
struct xil_irq_desc *xil_dev = desc->extra;
switch(xil_dev->type) {
case IRQ_PS:
#ifdef XSCUGIC_H
XScuGic_Enable(xil_dev->instance, irq_id);
#endif
break;
case IRQ_PL:
#ifdef XINTC_H
XIntc_Enable(xil_dev->instance, irq_id);
#endif
break;
default:
return -1;
}
return 0;
}
/**
* @brief Disable specific interrupt.
* @param desc - The IRQ controller descriptor.
* @param irq_id - Interrupt identifier.
* @return 0 in case of success, -1 otherwise.
*/
int32_t xil_irq_disable(struct irq_ctrl_desc *desc, uint32_t irq_id)
{
struct xil_irq_desc *xil_dev = desc->extra;
switch(xil_dev->type) {
case IRQ_PS:
#ifdef XSCUGIC_H
XScuGic_Disable(xil_dev->instance, irq_id);
#endif
break;
case IRQ_PL:
#ifdef XINTC_H
XIntc_Disable(xil_dev->instance, irq_id);
#endif
break;
default:
return -1;
}
return 0;
}
/**
* @brief Register a callback to handle the irq events.
* @param desc - The IRQ controller descriptor.
* @param irq_id - Interrupt identifier.
* @param callback_desc - Callback descriptor
* @return 0 in case of success, -1 otherwise.
*/
int32_t xil_irq_register_callback(struct irq_ctrl_desc *desc,
uint32_t irq_id,
struct callback_desc *callback_desc)
{
struct xil_irq_desc *xil_dev = desc->extra;
switch(xil_dev->type) {
case IRQ_PS:
#ifdef XSCUGIC_H
return XScuGic_Connect(xil_dev->instance, irq_id,
(Xil_InterruptHandler) callback_desc->callback,
callback_desc->ctx);
#endif
break;
case IRQ_PL:
#ifdef XINTC_H
if (irq_id == XPAR_AXI_INTC_AXI_TIMER_INTERRUPT_INTR) {
int32_t ret;
ret = XIntc_Connect(xil_dev->instance, irq_id,
XTmrCtr_InterruptHandler, callback_desc->legacy_config);
if (IS_ERR_VALUE(ret))
return -1;
XTmrCtr_SetHandler(callback_desc->legacy_config,
(XTmrCtr_Handler)callback_desc->callback,
callback_desc->ctx);
return 0;
}
return XIntc_Connect(xil_dev->instance, irq_id,
(XInterruptHandler) callback_desc->callback,
callback_desc->ctx);
#endif
break;
default:
break;
}
return -1;
}
/**
* @brief Set interrupt trigger level.
* @param desc - The IRQ controller descriptor.
* @param irq_id - Interrupt identifier.
* @param trig - New trigger level for the interrupt.
* @return 0 in case of success, -1 otherwise.
*/
int32_t xil_irq_trigger_level_set(struct irq_ctrl_desc *desc,
uint32_t irq_id,
enum irq_trig_level trig)
{
struct xil_irq_desc *xil_dev = desc->extra;
if(trig == IRQ_EDGE_BOTH)
return -EINVAL;
switch(xil_dev->type) {
case IRQ_PS:
#ifdef XSCUGIC_H
;
uint8_t priority, trigger;
XScuGic_GetPriorityTriggerType(xil_dev->instance, irq_id, &priority,
&trigger);
trigger = trig;
XScuGic_SetPriorityTriggerType(xil_dev->instance, irq_id, priority,
trigger);
return 0;
#endif
break;
case IRQ_PL:
#ifdef XINTC_H
/* Interrupt trigger determined in hardware. TODO: verify */
return 0;
#endif
break;
default:
break;
}
return -1;
}
/**
* @brief Set interrupt trigger level.
* @param desc - The IRQ controller descriptor.
* @param irq_id - Interrupt identifier.
* @param priority_level - New priority level for the interrupt.
* @return 0 in case of success, -1 otherwise.
*/
int32_t xil_irq_set_priority(struct irq_ctrl_desc *desc,
uint32_t irq_id,
uint32_t priority_level)
{
struct xil_irq_desc *xil_dev = desc->extra;
if(priority_level % 8 != 0)
return -EINVAL;
switch(xil_dev->type) {
case IRQ_PS:
#ifdef XSCUGIC_H
;
uint8_t priority, trigger;
XScuGic_GetPriorityTriggerType(xil_dev->instance, irq_id, &priority,
&trigger);
priority = priority_level;
XScuGic_SetPriorityTriggerType(xil_dev->instance, irq_id, priority,
trigger);
return 0;
#endif
break;
case IRQ_PL:
#ifdef XINTC_H
/* Interrupt priority level determined in hardware. TODO: verify */
return 0;
#endif
break;
default:
break;
}
return -1;
}
/**
* @brief Unregisters a generic IRQ handling function.
* @param desc - The IRQ controller descriptor.
* @param irq_id - Interrupt identifier.
* @param cb - Callback descriptor.
* @return 0 in case of success, -1 otherwise.
*/
int32_t xil_irq_unregister_callback(struct irq_ctrl_desc *desc,
uint32_t irq_id, struct callback_desc *cb)
{
struct xil_irq_desc *xil_dev = desc->extra;
switch(xil_dev->type) {
case IRQ_PS:
#ifdef XSCUGIC_H
XScuGic_Disconnect(xil_dev->instance, irq_id);
#endif
break;
case IRQ_PL:
#ifdef XINTC_H
XIntc_Disconnect(xil_dev->instance, irq_id);
#endif
break;
default:
return -1;
}
return 0;
}
/**
* @brief Free the resources allocated by irq_ctrl_init().
* @param desc - The IRQ control descriptor.
* @return 0 in case of success, -1 otherwise.
*/
int32_t xil_irq_ctrl_remove(struct irq_ctrl_desc *desc)
{
struct xil_irq_desc *xil_dev = desc->extra;
free(xil_dev->instance);
free(desc->extra);
free(desc);
return 0;
}
/**
* @brief Xilinx platform specific IRQ platform ops structure
*/
const struct irq_platform_ops xil_irq_ops = {
.init = &xil_irq_ctrl_init,
.register_callback = &xil_irq_register_callback,
.unregister_callback = &xil_irq_unregister_callback,
.global_enable = &xil_irq_global_enable,
.global_disable = &xil_irq_global_disable,
.trigger_level_set = &xil_irq_trigger_level_set,
.set_priority = &xil_irq_set_priority,
.enable = &xil_irq_enable,
.disable = &xil_irq_disable,
.remove = &xil_irq_ctrl_remove
};
@@ -0,0 +1,91 @@
/*******************************************************************************
* @file xilinx_irq.h
* @brief Header containing types used in the irq driver.
* @author Cristian Pop ([email protected])
********************************************************************************
* Copyright 2019(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
*******************************************************************************/
#ifndef XILINX_IRQ_H_
#define XILINX_IRQ_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdint.h>
#include "irq.h"
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
/**
* @enum xil_irq_type
* @brief Xilinx platform architecture sections
*/
enum xil_irq_type {
/** Programmable Logic */
IRQ_PL,
/** Processing System */
IRQ_PS
};
/**
* @struct xil_irq_init_param
* @brief Structure holding the initialization parameters for Xilinx platform
* specific IRQ parameters.
*/
struct xil_irq_init_param {
/** Xilinx architecture */
enum xil_irq_type type;
};
/**
* @struct xil_irq_desc
* @brief Xilinx platform specific IRQ descriptor
*/
struct xil_irq_desc {
/** Xilinx architecture */
enum xil_irq_type type;
/** Xilinx IRQ Instance */
void *instance;
};
/**
* @brief Xilinx specific IRQ platform ops structure
*/
extern const struct irq_platform_ops xil_irq_ops;
#endif
@@ -0,0 +1,462 @@
/***************************************************************************//**
* @file xilinx/xilinx_spi.c
* @brief Implementation of Xilinx SPI Generic Driver.
* @author Antoniu Miclaus ([email protected])
********************************************************************************
* Copyright 2019(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 Files **********************************/
/******************************************************************************/
#include <stdlib.h>
#include <xparameters.h>
#ifdef XPAR_XSPI_NUM_INSTANCES
#include <xspi.h>
#endif
#ifdef XPAR_XSPIPS_NUM_INSTANCES
#include <xspips.h>
#endif
#include "error.h"
#include "spi.h"
#include "xilinx_spi.h"
#if defined(PLATFORM_ZYNQ)
#define SPI_CLK_FREQ_HZ(dev) (XPAR_PS7_SPI_ ## dev ## _SPI_CLK_FREQ_HZ)
#define SPI_NUM_INSTANCES XPAR_XSPIPS_NUM_INSTANCES
#elif defined(PLATFORM_ZYNQMP)
#define SPI_CLK_FREQ_HZ(dev) (XPAR_PSU_SPI_ ## dev ## _SPI_CLK_FREQ_HZ)
#define SPI_NUM_INSTANCES XPAR_XSPIPS_NUM_INSTANCES
#else
#define SPI_NUM_INSTANCES 0
#endif
#warning SPI delays are not supported on the xilinx platform
/******************************************************************************/
/************************ Functions Definitions *******************************/
/******************************************************************************/
/**
* @brief Initialize the hardware SPI peripherial
*
* @param xdesc Platform specific SPI descriptor
* @param xinit Platform specific SPI init param
* @return int32_t -1 if the device couldn't be found or configured
*/
static int32_t spi_init_pl(struct spi_desc *desc,
const struct spi_init_param *param)
{
#ifdef XSPI_H
int32_t ret;
struct xil_spi_desc *xdesc;
struct xil_spi_init_param *xinit;
xdesc = (struct xil_spi_desc*)malloc(sizeof(struct xil_spi_desc));
if(!xdesc) {
free(xdesc);
return -1;
}
desc->extra = xdesc;
xinit = param->extra;
xdesc->type = xinit->type;
xdesc->flags = xinit->flags;
xdesc->instance = (XSpi*)calloc(1, sizeof(XSpi));
if(!xdesc->instance)
goto pl_error;
xdesc->config = XSpi_LookupConfig(param->device_id);
if(xdesc->config == NULL)
goto pl_error;
ret = XSpi_CfgInitialize(xdesc->instance,
xdesc->config,
((XSpi_Config*)xdesc->config)
->BaseAddress);
if(ret != 0)
goto pl_error;
ret = XSpi_Initialize(xdesc->instance, param->device_id);
if (ret != 0)
goto pl_error;
ret = XSpi_SetOptions(xdesc->instance,
XSP_MASTER_OPTION |
((desc->mode & SPI_CPOL) ?
XSP_CLK_ACTIVE_LOW_OPTION : 0) |
((desc->mode & SPI_CPHA) ?
XSP_CLK_PHASE_1_OPTION : 0));
if (ret != 0)
goto pl_error;
ret = XSpi_Start(xdesc->instance);
if (ret != 0)
goto pl_error;
XSpi_IntrGlobalDisable((XSpi *)(xdesc->instance));
return 0;
pl_error:
free(xdesc->instance);
free(xdesc);
#endif
return -1;
}
/**
* @brief Initialize the hardware SPI peripherial
*
* @param xdesc Platform specific SPI descriptor
* @param xinit Platform specific SPI init param
* @return int32_t -1 if the device couldn't be found or configured
*/
static int32_t spi_init_ps(struct spi_desc *desc,
const struct spi_init_param *param)
{
#ifdef XSPIPS_H
int32_t ret;
struct xil_spi_desc *xdesc;
struct xil_spi_init_param *xinit;
const uint32_t prescaler_default = XSPIPS_CLK_PRESCALE_64;
const uint32_t prescaler_min = XSPIPS_CLK_PRESCALE_4;
const uint32_t prescaler_max = XSPIPS_CLK_PRESCALE_256;
uint32_t prescaler = 0u;
uint32_t input_clock = 0u;
xdesc = (struct xil_spi_desc*)malloc(sizeof(struct xil_spi_desc));
if(!xdesc) {
free(xdesc);
return -1;
}
desc->extra = xdesc;
xinit = param->extra;
xdesc->type = xinit->type;
xdesc->flags = xinit->flags;
xdesc->instance = (XSpiPs*)malloc(sizeof(XSpiPs));
if(!xdesc->instance)
goto ps_error;
xdesc->config = XSpiPs_LookupConfig(param->device_id);
if(xdesc->config == NULL)
goto ps_error;
ret = XSpiPs_CfgInitialize(xdesc->instance,
xdesc->config,
((XSpiPs_Config*)xdesc->config)
->BaseAddress);
if(ret != 0)
goto ps_error;
switch (param->device_id) {
#if (SPI_NUM_INSTANCES >= 1)
case 0:
input_clock = SPI_CLK_FREQ_HZ(0);
break;
#endif
#if (SPI_NUM_INSTANCES >= 2)
case 1:
input_clock = SPI_CLK_FREQ_HZ(1);
break;
#endif
default:
goto ps_error;
};
if (desc->max_speed_hz != 0u) {
uint32_t div = input_clock / desc->max_speed_hz;
uint32_t rem = input_clock % desc->max_speed_hz;
uint32_t po2 = !(div & (div - 1)) && !rem;
// find the power of two just higher than div and
// store the exponent in prescaler
while(div) {
prescaler += 1;
div >>= 1u;
}
// this exponent - 1 is needed because of the way
// xilinx stores it into registers
if (prescaler)
prescaler -= 1;
// this exponent - 1 is needed when initial div was
// precisely a power of two
if (prescaler && po2)
prescaler -= 1;
if (prescaler < prescaler_min)
prescaler = prescaler_min;
if (prescaler > prescaler_max)
prescaler = prescaler_max;
} else
prescaler = prescaler_default;
ret = XSpiPs_SetClkPrescaler(xdesc->instance, prescaler);
if(ret != 0)
goto ps_error;
return 0;
ps_error:
free(xdesc->instance);
free(xdesc);
#endif
return -1;
}
/**
* @brief Initialize the SPI communication peripheral.
* @param desc - The SPI descriptor.
* @param param - The structure that contains the SPI parameters.
* @return 0 in case of success, -1 otherwise.
*/
int32_t xil_spi_init(struct spi_desc **desc,
const struct spi_init_param *param)
{
int32_t ret;
enum xil_spi_type *spi_type;
if (!param) {
return -1;
}
*desc = malloc(sizeof(**desc));
if(! *desc) {
free(*desc);
return -1;
}
spi_type = param->extra;
if(!spi_type)
goto init_error;
(*desc)->max_speed_hz = param->max_speed_hz;
(*desc)->mode = param->mode;
(*desc)->bit_order = param->bit_order;
(*desc)->chip_select = param->chip_select;
switch (*spi_type) {
case SPI_PL:
ret = spi_init_pl(*desc, param);
break;
case SPI_PS:
ret = spi_init_ps(*desc, param);
break;
default:
goto init_error;
break;
}
if (ret != 0) {
init_error:
free(*desc);
return -1;
}
return ret;
}
/**
* @brief Free the resources allocated by spi_init().
* @param desc - The SPI descriptor.
* @return 0 in case of success, -1 otherwise.
*/
int32_t xil_spi_remove(struct spi_desc *desc)
{
#ifdef XSPI_H
int32_t ret;
#endif
struct xil_spi_desc *xdesc = NULL;
enum xil_spi_type *spi_type;
spi_type = desc->extra;
if(!spi_type)
return -1;
switch (*spi_type ) {
case SPI_PL:
#ifdef XSPI_H
xdesc = desc->extra;
if(!xdesc)
return -1;
ret = XSpi_Stop((XSpi *)(xdesc->instance));
if(ret != 0)
goto error;
#endif
break;
case SPI_PS:
#ifdef XSPIPS_H
xdesc = desc->extra;
if(!xdesc)
return -1;
#endif
break;
/* Intended fallthrough */
#ifdef XSPI_H
error:
#endif
default:
return -1;
}
if(xdesc)
free(xdesc->instance);
free(desc->extra);
free(desc);
return 0;
}
/**
* @brief Write and read data to/from SPI.
* @param desc - The SPI descriptor.
* @param data - The buffer with the transmitted/received data.
* @param bytes_number - Number of bytes to write/read.
* @return 0 in case of success, -1 otherwise.
*/
int32_t xil_spi_write_and_read(struct spi_desc *desc,
uint8_t *data,
uint16_t bytes_number)
{
int32_t ret;
#ifdef XSPI_H
uint32_t ctrl_reg;
#endif
struct xil_spi_desc *xdesc;
enum xil_spi_type *spi_type;
ret = -1;
spi_type = desc->extra;
if(!spi_type)
return -1;
xdesc = desc->extra;
switch (*spi_type) {
case SPI_PL:
#ifdef XSPI_H
ret = XSpi_SetOptions(xdesc->instance,
XSP_MASTER_OPTION |
((desc->mode & SPI_CPOL) ?
XSP_CLK_ACTIVE_LOW_OPTION : 0) |
((desc->mode & SPI_CPHA) ?
XSP_CLK_PHASE_1_OPTION : 0));
if (ret != 0)
goto error;
ctrl_reg = XSpi_GetControlReg(((XSpi*)xdesc->instance));
if (desc->bit_order == SPI_BIT_ORDER_LSB_FIRST)
ctrl_reg |= XSP_CR_LSB_MSB_FIRST_MASK;
else
ctrl_reg &= ~ XSP_CR_LSB_MSB_FIRST_MASK;
XSpi_SetControlReg(((XSpi*)xdesc->instance), ctrl_reg);
ret = XSpi_SetSlaveSelect(xdesc->instance,
0x01 << desc->chip_select);
if (ret != 0)
goto error;
ret = XSpi_Transfer(xdesc->instance,
data,
data,
bytes_number);
if (ret != 0)
goto error;
#endif
break;
case SPI_PS:
#ifdef XSPIPS_H
ret = XSpiPs_SetOptions(xdesc->instance,
XSPIPS_MASTER_OPTION |
((xdesc->flags & SPI_CS_DECODE) ?
XSPIPS_DECODE_SSELECT_OPTION : 0) |
XSPIPS_FORCE_SSELECT_OPTION |
((desc->mode & SPI_CPOL) ?
XSPIPS_CLK_ACTIVE_LOW_OPTION : 0) |
((desc->mode & SPI_CPHA) ?
XSPIPS_CLK_PHASE_1_OPTION : 0));
if (ret != 0)
goto error;
ret = XSpiPs_SetSlaveSelect(xdesc->instance,
desc->chip_select);
if (ret != 0)
goto error;
ret = XSpiPs_PolledTransfer(xdesc->instance,
data,
data,
bytes_number);
if (ret != 0)
goto error;
ret = XSpiPs_SetSlaveSelect(xdesc->instance, SPI_DEASSERT_CURRENT_SS);
if (ret != 0)
goto error;
#endif
break;
error:
default:
return -1;
}
return ret;
}
/**
* @brief Xilinx platform specific SPI platform ops structure
*/
const struct spi_platform_ops xil_spi_ops = {
.init = &xil_spi_init,
.write_and_read = &xil_spi_write_and_read,
.remove = &xil_spi_remove
};
@@ -0,0 +1,115 @@
/*******************************************************************************
* @file xilinx/xilinx_spi.h
* @brief Header containing extra types used in the spi driver.
* @author scuciurean ([email protected])
********************************************************************************
* Copyright 2019(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
*******************************************************************************/
#ifndef XILINX_SPI_H_
#define XILINX_SPI_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdint.h>
#include "spi.h"
/******************************************************************************/
/********************** Macros and Constants Definitions **********************/
/******************************************************************************/
#define SPI_CS_DECODE 0x01
#define SPI_DEASSERT_CURRENT_SS 0x0F
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
/**
* @enum xil_spi_type
* @brief Xilinx platform architecture sections
*/
enum xil_spi_type {
/** Programmable Logic */
SPI_PL,
/** Processing System */
SPI_PS,
/** SPI Engine */
SPI_ENGINE
};
/**
* @struct xil_spi_init_param
* @brief Structure holding the initialization parameters for Xilinx platform
* specific SPI parameters when using xil_spi_ops.
*/
struct xil_spi_init_param {
/** Xilinx architecture */
enum xil_spi_type type;
/** SPI flags */
uint32_t flags;
};
/**
* @struct xil_spi_desc
* @brief Xilinx platform specific SPI descriptor
*/
struct xil_spi_desc {
/** Xilinx architecture */
enum xil_spi_type type;
/** SPI flags */
uint32_t flags;
/** SPI configuration */
void *config;
/** SPI instance */
void *instance;
};
/**
* @brief SPI engine platform ops structure
*/
extern const struct spi_platform_ops spi_eng_platform_ops;
/**
* @brief Xilinx specific SPI platform ops structure
*/
extern const struct spi_platform_ops xil_spi_ops;
/**
* @brief Xilinx SPI PS register functions. No extra param needed
*/
extern const struct spi_platform_ops xil_spi_pl_ops;
#endif // XILINX_SPI_H_
@@ -0,0 +1,533 @@
/*******************************************************************************
* @file xilinx/xilinx_spi_pl.c
* @brief Driver for spi pl device using registers
* @author Mihail Chindris ([email protected])
********************************************************************************
* Copyright 2021(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 <xparameters.h>
#ifdef XPAR_XSPI_NUM_INSTANCES
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <xspi.h>
#include <stdlib.h>
#include <stdbool.h>
#include "spi.h"
#include "error.h"
#include "delay.h"
#include "util.h"
#include "alloc.h"
/******************************************************************************/
/********************** Macros and Constants Definitions **********************/
/******************************************************************************/
#define XPS_TYPE_WRITE 0x1
#define XPS_TYPE_READ 0x2
#define XSP_DEFAULT_SR_VALUE 0x25
#define XSP_DUMMY_DATA 0xFF
/*
* Used to store current spi device configuration in order to not update it for
* each spi transaction if not needed.
*/
static struct spi_desc g_spi_desc[XPAR_XSPI_NUM_INSTANCES];
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
/* Xilinx PL spi specific data */
struct xspi_desc {
uint32_t base_addr;
uint32_t disable_slaves_mask;
uint32_t fifo_depth;
uint8_t cs_asserted;
};
/* Structure used to iterate over SPI messages */
struct msg_iter {
struct spi_msg *msgs;
uint32_t len;
uint32_t i;
uint32_t buff_i;
uint8_t is_wr;
};
/******************************************************************************/
/************************ Functions Definitions *******************************/
/******************************************************************************/
/* Read device register */
static inline uint32_t _read(struct xspi_desc *xdesc, uint32_t reg)
{
return Xil_In32(xdesc->base_addr + reg);
}
/* Write device register */
static inline void _write(struct xspi_desc *xdesc, uint32_t reg, uint32_t val)
{
Xil_Out32(xdesc->base_addr + reg, val);
}
/* Update device register. Only bits set to 1 in mask will be modified */
static inline void _wr_mask(struct xspi_desc *xdesc, uint32_t reg,
uint32_t val, uint32_t mask)
{
uint32_t tmp;
tmp = _read(xdesc, reg);
tmp &= ~mask;
tmp |= val & mask;
_write(xdesc, reg, tmp);
}
/* Update spi device configuration if needed */
static void _update_mode(struct spi_desc *desc)
{
uint32_t val;
uint32_t mask;
if (desc->mode == g_spi_desc[desc->device_id].mode &&
desc->bit_order == g_spi_desc[desc->device_id].bit_order)
return ;
/* Update mode */
val = desc->mode | SPI_CPOL ? XSP_CR_CLK_POLARITY_MASK : 0;
val |= desc->mode | SPI_CPHA ? XSP_CR_CLK_PHASE_MASK : 0;
mask = XSP_CR_CLK_POLARITY_MASK | XSP_CR_CLK_PHASE_MASK;
val |= desc->bit_order == SPI_BIT_ORDER_LSB_FIRST ?
XSP_CR_LSB_MSB_FIRST_MASK : 0;
mask |= XSP_CR_LSB_MSB_FIRST_MASK;
_wr_mask(desc->extra, XSP_CR_OFFSET, val, mask);
g_spi_desc[desc->device_id] = *desc;
}
/* Configure SPI PL device */
static int32_t _xil_spi_init_dev(struct xspi_desc *xdesc)
{
uint32_t val;
/* Software reset */
_write(xdesc, XSP_SRR_OFFSET, XSP_SRR_RESET_MASK);
mdelay(1);
/* Check if success reset */
val = _read(xdesc, XSP_SR_OFFSET);
if (val != XSP_DEFAULT_SR_VALUE)
return -ENODEV;
/* Disable interrupts. Drivers only works with pooled mode */
_write(xdesc, XSP_IIER_OFFSET, 0);
/* Deasert chip selects */
_write(xdesc, XSP_SSR_OFFSET, 0xFFFFFFFF);
/* Get fifo depth */
while (!(_read(xdesc, XSP_SR_OFFSET) & XSP_SR_TX_FULL_MASK))
_write(xdesc, XSP_DTR_OFFSET, XSP_DUMMY_DATA);
xdesc->fifo_depth = _read(xdesc, XSP_TFO_OFFSET) + 1;
/* Configure spi device */
val = XSP_CR_ENABLE_MASK |
XSP_CR_MANUAL_SS_MASK |
XSP_CR_TXFIFO_RESET_MASK |
XSP_CR_RXFIFO_RESET_MASK |
XSP_CR_MASTER_MODE_MASK |
XSP_CR_TRANS_INHIBIT_MASK;
_write(xdesc, XSP_CR_OFFSET, val);
return 0;
}
/* Initialize spi_desc structure and device */
static int32_t xil_spi_init_pl(struct spi_desc **desc,
const struct spi_init_param *param)
{
struct spi_desc *ldesc;
struct xspi_desc *xdesc;
int32_t err;
XSpi_Config *cfg;
if (!desc || !param || param->device_id >= XPAR_XSPI_NUM_INSTANCES)
return -EINVAL;
cfg = XSpi_LookupConfig(param->device_id);
if (!cfg)
return -EINVAL;
if (param->chip_select > cfg->NumSlaveBits)
return -EINVAL;
ldesc = (struct spi_desc *)calloc(1, sizeof(*ldesc));
if (!ldesc)
return -ENOMEM;
xdesc = (struct xspi_desc *)calloc(1, sizeof(*xdesc));
if (!xdesc) {
err = -ENOMEM;
goto error;
}
ldesc->bit_order = param->bit_order;
ldesc->chip_select = param->chip_select;
ldesc->mode = param->mode;
xdesc->base_addr = cfg->BaseAddress;
xdesc->disable_slaves_mask = (1 << cfg->NumSlaveBits) - 1;
xdesc->cs_asserted = 0;
err = _xil_spi_init_dev(xdesc);
if (IS_ERR_VALUE(err))
goto error;
ldesc->extra = xdesc;
*desc = ldesc;
return 0;
error:
free(xdesc);
free(ldesc);
return err;
}
/* Remove allocated resources */
static int32_t xil_spi_remove_pl(struct spi_desc *desc)
{
if (!desc)
return -EINVAL;
free(desc->extra);
free(desc);
return 0;
}
/*
* Fill fifo until fifo is full or no more data available.
* Return the number of written bytes.
*/
static uint32_t _wr_fifo(struct xspi_desc *xdesc, uint8_t *data,
uint32_t len)
{
uint32_t i;
uint32_t to_write;
uint32_t tx_available;
tx_available = xdesc->fifo_depth - _read(xdesc, XSP_TFO_OFFSET);
to_write = min(tx_available, len);
for (i = 0; i < to_write; ++i)
if (data)
_write(xdesc, XSP_DTR_OFFSET, data[i]);
else
_write(xdesc, XSP_DTR_OFFSET, XSP_DUMMY_DATA);
return to_write;
}
/*
* Read fifo until fifo is empty or no more buffer available to read into
* Returns the number of read bytes
*/
static uint32_t _rd_fifo(struct xspi_desc *xdesc, uint8_t *data,
uint32_t len)
{
uint32_t rx_available;
uint32_t to_read;
uint32_t tmp;
uint32_t i;
tmp = _read(xdesc, XSP_SR_OFFSET);
if (tmp & XSP_SR_RX_EMPTY_MASK)
return 0;
rx_available = _read(xdesc, XSP_RFO_OFFSET) + 1;
to_read = min(rx_available, len);
for (i = 0; i < to_read; ++i) {
tmp = _read(xdesc, XSP_DRR_OFFSET);
if (data)
data[i] = tmp;
}
return to_read;
}
/* If start is 0 stop transfer, else start it.
* CS will be asserted if needed. If different CS othere than the one needed
* is asserted. Deassert it and assert correct one */
static void _xil_spi_start_transfer(struct spi_desc *desc, uint8_t start)
{
struct xspi_desc *xdesc;
xdesc = desc->extra;
if (start) {
if (xdesc->cs_asserted) {
if (desc->chip_select ==
g_spi_desc[desc->device_id].chip_select)
return ;
else
/* Stop transfer to start again with new CS */
_xil_spi_start_transfer(desc, 0);
}
_write(xdesc, XSP_SSR_OFFSET, ~(1 << desc->chip_select));
_wr_mask(xdesc, XSP_CR_OFFSET, 0, XSP_CR_TRANS_INHIBIT_MASK);
} else {
_wr_mask(xdesc, XSP_CR_OFFSET, XSP_CR_TRANS_INHIBIT_MASK,
XSP_CR_TRANS_INHIBIT_MASK);
_write(xdesc, XSP_SSR_OFFSET, xdesc->disable_slaves_mask);
}
xdesc->cs_asserted = start;
}
/* SPI polled transfer */
static int32_t xil_spi_write_and_read_pl(struct spi_desc *desc,
uint8_t *data,
uint16_t bytes_number)
{
struct xspi_desc *xdesc;
uint32_t rx;
uint32_t tx;
if (!desc || !desc->extra)
return -EINVAL;
xdesc = desc->extra;
_update_mode(desc);
_xil_spi_start_transfer(desc, 1);
rx = 0;
tx = 0;
while (rx < bytes_number) {
if (tx < bytes_number)
tx += _wr_fifo(xdesc, data + tx, bytes_number - tx);
rx += _rd_fifo(xdesc, data + rx, bytes_number - rx);
}
_xil_spi_start_transfer(desc, 0);
return 0;
}
/* Get type of message. It can be READ, WRITE or both */
static uint32_t _get_msg_type(struct spi_msg *msg)
{
uint32_t type;
type = 0;
if (msg->tx_buff)
type |= XPS_TYPE_WRITE;
if (msg->rx_buff)
type |= XPS_TYPE_READ;
return type;
}
/* Get information based on current iterator position */
static void _get_data(struct msg_iter *it, uint8_t **buff, uint32_t *len,
uint32_t *type)
{
struct spi_msg *msg;
if (it->i == it->len) {
*len = 0;
return ;
}
msg = it->msgs + it->i;
if (it->is_wr)
*buff = msg->tx_buff;
else
*buff = msg->rx_buff;
if (*buff)
*buff += it->buff_i;
*len = msg->bytes_number - it->buff_i;
if (type)
*type = _get_msg_type(msg);
}
/*
* Increment iterator position with desired length.
* If the new position has a different message type, new_type will be set to 1
* If a CS change is needed, cs_change is set
*/
static void _increment_iter(struct msg_iter *it, uint32_t len,
uint8_t *cs_change, uint8_t *new_type)
{
struct spi_msg *msg;
uint32_t type;
uint32_t extra_len;
if (!len)
return ;
*cs_change = 0;
*new_type = 0;
msg = it->msgs + it->i;
if (it->buff_i + len > msg->bytes_number)
extra_len = it->buff_i + len - msg->bytes_number;
else
extra_len = 0;
len -= extra_len;
it->buff_i += len;
if (it->buff_i == msg->bytes_number) {
type = _get_msg_type(msg);
++it->i;
it->buff_i = 0;
if (cs_change && msg->cs_change)
*cs_change = 1;
if (new_type)
if (it->i == it->len ||
type != _get_msg_type(it->msgs + it->i))
*new_type = 1;
}
if (extra_len)
_increment_iter(it, extra_len, cs_change, new_type);
}
/*
* SPI polling transfer of multiple messages.
*/
static int32_t xil_spi_transfer_pl(struct spi_desc *desc,
struct spi_msg *msgs,
uint32_t len)
{
struct xspi_desc *xdesc;
uint8_t cs_change;
uint8_t new_type;
struct msg_iter rx = {.msgs = msgs, .len = len, .is_wr = 0};
struct msg_iter tx = {.msgs = msgs, .len = len, .is_wr = 1};
uint8_t *buff;
uint32_t bytes;
uint32_t type;
/* Bytes to increment rx when only a write transaction is executed */
uint32_t to_inc_rx;
/* Difference between rx and tx iterators in bytes */
uint32_t tx_advance;
/* Save bytes sent during a write loop */
uint32_t tx_sent;
/* Used to loop if need to empty the RX FIFO */
uint32_t loop;
if (!desc || !desc->extra)
return -EINVAL;
xdesc = desc->extra;
_update_mode(desc);
tx_advance = 0;
to_inc_rx = 0;
buff = NULL;
type = 0;
do {
_xil_spi_start_transfer(desc, 1);
tx_sent = 0;
/* Writing loop */
do {
_get_data(&tx, &buff, &bytes, &type);
if (type & XPS_TYPE_READ)
/*
* Do not write more bytes than fifo_depth if
* they haven't been read.
*/
bytes = min(bytes,
xdesc->fifo_depth - tx_advance);
bytes = _wr_fifo(xdesc, buff, bytes);
tx_sent += bytes;
_increment_iter(&tx, bytes, &cs_change, &new_type);
tx_advance += bytes;
} while (!cs_change && !new_type && bytes);
if (type & XPS_TYPE_READ) {
loop = 1;
/*
* Loop only when no more data to write otherwise read
* only available data.
*/
while (loop) {
if (!new_type)
loop = 0;
_get_data(&rx, &buff, &bytes, NULL);
bytes = _rd_fifo(xdesc, buff, bytes);
_increment_iter(&rx, bytes, &cs_change, &new_type);
tx_advance -= bytes;
if (loop && new_type)
break;
}
} else {
/* Clean RX FIFO if it was only a WRITE message */
to_inc_rx += tx_sent;
if (new_type) {
/* Wait for TX to be sent */
while (!(_read(xdesc, XSP_SR_OFFSET) &
XSP_SR_TX_EMPTY_MASK))
;
/* Reset fifo. Only write was performed */
_wr_mask(xdesc, XSP_CR_OFFSET,
XSP_CR_RXFIFO_RESET_MASK,
XSP_CR_RXFIFO_RESET_MASK);
_increment_iter(&rx, to_inc_rx, NULL, NULL);
tx_advance -= to_inc_rx;
to_inc_rx = 0;
}
}
if ((cs_change && rx.i != len) || (!cs_change && rx.i == len))
_xil_spi_start_transfer(desc, 0);
} while (rx.i < len);
return 0;
}
const struct spi_platform_ops xil_spi_pl_ops = {
.init = xil_spi_init_pl,
.remove = xil_spi_remove_pl,
.write_and_read = xil_spi_write_and_read_pl,
.transfer = xil_spi_transfer_pl
};
#endif // XPAR_XSPI_NUM_INSTANCES
@@ -0,0 +1,456 @@
/***************************************************************************//**
* @file xilinx/xilinx_timer.c
* @brief Timer and GIC control module source.
* @author Andrei Drimbarean (andrei.drimbarean@analog.com)
********************************************************************************
* Copyright 2020(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 Files **********************************/
/******************************************************************************/
#include <stdlib.h>
#include <xparameters.h>
#include "timer.h"
#include "xilinx_timer.h"
#include "error.h"
/******************************************************************************/
/********************** Macros and Constants Definitions **********************/
/******************************************************************************/
#if defined(_XPARAMETERS_PS_H_)
#define CORE_PRIVATE_TIMER_CLOCK (XPAR_CPU_CORTEXA9_CORE_CLOCK_FREQ_HZ / 2)
#endif
/******************************************************************************/
/************************ Functions Definitions *******************************/
/******************************************************************************/
/**
* @brief Set the current counter value of the timer.
* @param [in] desc - Pointer to the device handler.
* @param [in] new_val - New value for the timer counter.
* @return 0 in case of success, -1 otherwise
*/
int32_t xilinx_timer_counter_set(struct timer_desc *desc,
uint32_t new_val)
{
struct xil_timer_desc *xdesc;
if (!desc)
return -1;
xdesc = desc->extra;
switch (xdesc->type) {
case TIMER_PS:
#ifdef XSCUTIMER_H
XScuTimer_LoadTimer((XScuTimer *)xdesc->instance, new_val - 1);
break;
#endif
return -1;
case TIMER_PL:
#ifdef XTMRCTR_H
XTmrCtr_SetResetValue(xdesc->instance, xdesc->active_tmr, new_val);
XTmrCtr_Reset(xdesc->instance, xdesc->active_tmr);
break;
#endif
return -1;
default:
return -1;
}
return 0;
}
/**
* @brief Set the timer clock frequency.
* @param [in] desc - Pointer to the device handler.
* @param [in] freq_hz - New timer frequency in hertz.
* @return 0 in case of success, -1 otherwise
*/
int32_t xilinx_timer_count_clk_set(struct timer_desc *desc,
uint32_t freq_hz)
{
struct xil_timer_desc *xdesc;
if (!desc || !freq_hz)
return -1;
xdesc = desc->extra;
switch (xdesc->type) {
case TIMER_PS:
#ifdef XSCUTIMER_H
;
uint32_t prescaler = CORE_PRIVATE_TIMER_CLOCK / freq_hz;
if (prescaler == 0 || prescaler >= 256)
return -1;
XScuTimer_SetPrescaler(xdesc->instance, prescaler - 1);
desc->freq_hz = CORE_PRIVATE_TIMER_CLOCK / prescaler;
break;
#endif
return -1;
case TIMER_PL:
#ifdef XTMRCTR_H
(void *)xdesc;
/** Cannot be done. */
#endif
return -1;
default:
return -1;
}
return 0;
}
/**
* @brief Initialize hardware timer and the handler structure associated with
* it.
* @param [out] desc - Pointer to the reference of the device handler.
* @param [in] param - Initialization structure.
* @return 0 in case of success, -1 otherwise
*/
int32_t xilinx_timer_init(struct timer_desc **desc,
const struct timer_init_param *param)
{
int32_t ret;
struct timer_desc *dev;
struct xil_timer_desc *xdesc;
struct xil_timer_init_param *xinit;
if (!desc || !param)
return -1;
xinit = param->extra;
dev = (struct timer_desc *)calloc(1, sizeof(*dev));
if(!dev)
return -1;
xdesc = (struct xil_timer_desc *)calloc(1, sizeof(*xdesc));
if(!xdesc)
goto error_desc;
dev->id = param->id;
dev->freq_hz = param->freq_hz;
dev->ticks_count = param->ticks_count;
dev->extra = xdesc;
xdesc->active_tmr = xinit->active_tmr;
xdesc->type = xinit->type;
switch (xdesc->type) {
case TIMER_PS:
#ifdef XSCUTIMER_H
xdesc->config = XScuTimer_LookupConfig(dev->id);
xdesc->instance = calloc(1, sizeof(XScuTimer));
if (!xdesc->instance)
goto error_xdesc;
ret = XScuTimer_CfgInitialize(xdesc->instance, xdesc->config,
((XScuTimer_Config *)xdesc->config)->BaseAddr);
if (ret != XST_SUCCESS) {
free(xdesc->instance);
goto error_xdesc;
}
ret = xilinx_timer_count_clk_set(dev, param->freq_hz);
if (IS_ERR_VALUE(ret))
goto error_xdesc;
ret = xilinx_timer_counter_set(dev, dev->ticks_count);
if (IS_ERR_VALUE(ret))
goto error_xdesc;
XScuTimer_EnableAutoReload((XScuTimer *)xdesc->instance);
XScuTimer_EnableInterrupt((XScuTimer *)xdesc->instance);
break;
#endif
goto error_xdesc;
case TIMER_PL:
#ifdef XTMRCTR_H
xdesc->instance = (XTmrCtr *)calloc(1, sizeof(XTmrCtr));
if (!xdesc->instance)
return -1;
xdesc->config = XTmrCtr_LookupConfig(dev->id);
if (!xdesc->config) {
free(xdesc->instance);
goto error_desc;
}
XTmrCtr_CfgInitialize(xdesc->instance, xdesc->config,
((XTmrCtr_Config *)xdesc->config)->BaseAddress);
ret = XTmrCtr_InitHw(xdesc->instance);
if (ret != 0) {
free(xdesc->instance);
goto error_desc;
}
dev->freq_hz = ((XTmrCtr_Config *)xdesc->config)->SysClockFreqHz;
ret = XTmrCtr_SelfTest(xdesc->instance, dev->id);
if(ret != 0)
goto error_desc;
XTmrCtr_SetOptions(xdesc->instance, xdesc->active_tmr,
XTC_DOWN_COUNT_OPTION | XTC_INT_MODE_OPTION |
XTC_AUTO_RELOAD_OPTION);
XTmrCtr_SetResetValue(xdesc->instance, xdesc->active_tmr,
dev->ticks_count);
break;
#endif
goto error_xdesc;
default:
goto error_xdesc;
}
*desc = dev;
return 0;
error_xdesc:
free(xdesc);
error_desc:
free(dev);
return -1;
}
/**
* @brief Free the memory allocated by timer_setup().
* @param [in] desc - Pointer to the device handler.
* @return 0 in case of success, -1 otherwise
*/
int32_t xilinx_timer_remove(struct timer_desc *desc)
{
struct xil_timer_desc *xdesc;
if(!desc)
return -1;
xdesc = desc->extra;
switch (xdesc->type) {
case TIMER_PS:
#ifdef XSCUTIMER_H
XScuTimer_Stop(xdesc->instance);
free(xdesc->instance);
break;
#endif
return -1;
case TIMER_PL:
#ifdef XTMRCTR_H
XTmrCtr_Stop(xdesc->instance, xdesc->active_tmr);
break;
#endif
return -1;
default:
return -1;
}
free(xdesc);
free(desc);
return 0;
}
/**
* @brief Start a timer.
* @param [in] desc - Pointer to the device handler.
* @return 0 in case of success, -1 otherwise
*/
int32_t xilinx_timer_start(struct timer_desc *desc)
{
struct xil_timer_desc *xdesc;
if (!desc)
return -1;
xdesc = desc->extra;
switch (xdesc->type) {
case TIMER_PS:
#ifdef XSCUTIMER_H
XScuTimer_Start(xdesc->instance);
break;
#endif
return -1;
case TIMER_PL:
#ifdef XTMRCTR_H
XTmrCtr_Start(xdesc->instance, xdesc->active_tmr);
break;
#endif
return -1;
}
return 0;
}
/**
* @brief Stop a timer from counting.
* @param [in] desc - Pointer to the device handler.
* @return 0 in case of success, -1 otherwise
*/
int32_t xilinx_timer_stop(struct timer_desc *desc)
{
struct xil_timer_desc *xdesc;
if (!desc)
return -1;
xdesc = desc->extra;
switch (xdesc->type) {
case TIMER_PS:
#ifdef XSCUTIMER_H
XScuTimer_Stop(xdesc->instance);
break;
#endif
return -1;
case TIMER_PL:
#ifdef XTMRCTR_H
XTmrCtr_Stop(xdesc->instance, xdesc->active_tmr);
break;
#endif
return -1;
default:
return -1;
}
return 0;
}
/**
* @brief Get the current counter value of the timer.
* @param [in] desc - Pointer to the device handler.
* @param [out] counter - Pointer to the current counter value.
* @return 0 in case of success, -1 otherwise
*/
int32_t xilinx_timer_counter_get(struct timer_desc *desc,
uint32_t *counter)
{
struct xil_timer_desc *xdesc;
if (!desc || !counter)
return -1;
xdesc = desc->extra;
switch (xdesc->type) {
case TIMER_PS:
#ifdef XSCUTIMER_H
*counter = XScuTimer_GetCounterValue((XScuTimer *)xdesc->instance);
++(*counter);
break;
#endif
return -1;
case TIMER_PL:
#ifdef XTMRCTR_H
*counter = XTmrCtr_GetValue(xdesc->instance, xdesc->active_tmr);
break;
#endif
return -1;
default:
*counter = 0;
return -1;
}
return 0;
}
/**
* @brief Get the timer clock frequency.
* @param [in] desc - Pointer to the device handler.
* @param [out] freq_hz - Pointer to the returned frequency.
* @return 0 in case of success, -1 otherwise
*/
int32_t xilinx_timer_count_clk_get(struct timer_desc *desc,
uint32_t *freq_hz)
{
struct xil_timer_desc *xdesc;
if (!desc || !freq_hz)
return -1;
xdesc = desc->extra;
switch (xdesc->type) {
case TIMER_PS:
#ifdef XSCUTIMER_H
*freq_hz = desc->freq_hz;
break;
#endif
return -1;
case TIMER_PL:
#ifdef XTMRCTR_H
*freq_hz = ((XTmrCtr_Config *)xdesc->config)->SysClockFreqHz;
break;
#endif
return -1;
default:
*freq_hz = 0;
return -1;
}
return 0;
}
/**
* @brief Get the elapsed time in nsec for the timer.
* @param [in] desc - Pointer to the device handler.
* @param [in] elapsed_time - The elapsed time in nsec.
* @return -ENOSYS.
*/
int32_t xilinx_timer_get_elapsed_time_nsec(struct timer_desc *desc,
uint64_t *elapsed_time)
{
/* Function not implemented */
return -ENOSYS;
}
/**
* @brief Xilinx platform specific timer platform ops structure
*/
const struct timer_platform_ops xil_timer_ops = {
.init = &xilinx_timer_init,
.start = &xilinx_timer_start,
.stop = &xilinx_timer_stop,
.counter_get = &xilinx_timer_counter_get,
.counter_set = &xilinx_timer_counter_set,
.count_clk_get = &xilinx_timer_count_clk_get,
.count_clk_set = &xilinx_timer_count_clk_set,
.get_elapsed_time_nsec = &xilinx_timer_get_elapsed_time_nsec,
.remove = &xilinx_timer_remove
};
@@ -0,0 +1,101 @@
/***************************************************************************//**
* @file xilinx_timer.h
* @brief Timer control module header.
* @author Andrei Drimbarean (andrei.drimbarean@analog.com)
********************************************************************************
* Copyright 2020(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
*******************************************************************************/
#ifndef XILINX_TIMER_H_
#define XILINX_TIMER_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <xparameters.h>
#ifdef XPAR_XSCUTIMER_NUM_INSTANCES
#include <xscutimer.h>
#endif
#ifdef XPAR_XTMRCTR_NUM_INSTANCES
#include <xtmrctr.h>
#endif
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
/**
* @enum xil_timer_type
* @brief Xilinx platform architecture sections
*/
enum xil_timer_type {
/** Programmable Logic */
TIMER_PL,
/** Processing System */
TIMER_PS
};
/**
* @struct xil_timer_desc
* @brief Xilinx specific timer descriptor
*/
struct xil_timer_desc {
/** Pointer to the BSP driver handler */
void *instance;
/** Pointer to the BSP driver configuration handler */
void *config;
/** Timer used from the PL 3-timer core */
uint8_t active_tmr;
/** Platform selection parameter */
enum xil_timer_type type;
};
/**
* @struct xil_timer_init_param
* @brief Xilinx specific timer initialization structure
*/
struct xil_timer_init_param {
/** Timer used from the PL 3-timer core */
uint8_t active_tmr;
/** Platform selection parameter */
enum xil_timer_type type;
};
/**
* @brief Xilinx platform specific timer platform ops structure
*/
extern const struct timer_platform_ops xil_timer_ops;
#endif /* XILINX_TIMER_H_ */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,552 @@
/***************************************************************************//**
* @file ad9361_api.h
* @brief Header file of AD9361 API Driver.
* @author DBogdan (dragos.bogdan@analog.com)
********************************************************************************
* Copyright 2013(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
*******************************************************************************/
#ifndef AD9361_API_H_
#define AD9361_API_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include "ad9361_util.h"
#include "gpio.h"
#include "spi.h"
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
typedef struct {
/* Device selection */
enum dev_id dev_sel;
/* Reference Clock */
uint32_t reference_clk_rate;
/* Base Configuration */
uint8_t two_rx_two_tx_mode_enable; /* adi,2rx-2tx-mode-enable */
uint8_t one_rx_one_tx_mode_use_rx_num; /* adi,1rx-1tx-mode-use-rx-num */
uint8_t one_rx_one_tx_mode_use_tx_num; /* adi,1rx-1tx-mode-use-tx-num */
uint8_t frequency_division_duplex_mode_enable; /* adi,frequency-division-duplex-mode-enable */
uint8_t frequency_division_duplex_independent_mode_enable; /* adi,frequency-division-duplex-independent-mode-enable */
uint8_t tdd_use_dual_synth_mode_enable; /* adi,tdd-use-dual-synth-mode-enable */
uint8_t tdd_skip_vco_cal_enable; /* adi,tdd-skip-vco-cal-enable */
uint32_t tx_fastlock_delay_ns; /* adi,tx-fastlock-delay-ns */
uint32_t rx_fastlock_delay_ns; /* adi,rx-fastlock-delay-ns */
uint8_t rx_fastlock_pincontrol_enable; /* adi,rx-fastlock-pincontrol-enable */
uint8_t tx_fastlock_pincontrol_enable; /* adi,tx-fastlock-pincontrol-enable */
uint8_t external_rx_lo_enable; /* adi,external-rx-lo-enable */
uint8_t external_tx_lo_enable; /* adi,external-tx-lo-enable */
uint8_t dc_offset_tracking_update_event_mask; /* adi,dc-offset-tracking-update-event-mask */
uint8_t dc_offset_attenuation_high_range; /* adi,dc-offset-attenuation-high-range */
uint8_t dc_offset_attenuation_low_range; /* adi,dc-offset-attenuation-low-range */
uint8_t dc_offset_count_high_range; /* adi,dc-offset-count-high-range */
uint8_t dc_offset_count_low_range; /* adi,dc-offset-count-low-range */
uint8_t split_gain_table_mode_enable; /* adi,split-gain-table-mode-enable */
uint32_t trx_synthesizer_target_fref_overwrite_hz; /* adi,trx-synthesizer-target-fref-overwrite-hz */
uint8_t qec_tracking_slow_mode_enable; /* adi,qec-tracking-slow-mode-enable */
/* ENSM Control */
uint8_t ensm_enable_pin_pulse_mode_enable; /* adi,ensm-enable-pin-pulse-mode-enable */
uint8_t ensm_enable_txnrx_control_enable; /* adi,ensm-enable-txnrx-control-enable */
/* LO Control */
uint64_t rx_synthesizer_frequency_hz; /* adi,rx-synthesizer-frequency-hz */
uint64_t tx_synthesizer_frequency_hz; /* adi,tx-synthesizer-frequency-hz */
uint8_t tx_lo_powerdown_managed_enable; /* adi,tx-lo-powerdown-managed-enable */
/* Rate & BW Control */
uint32_t rx_path_clock_frequencies[6]; /* adi,rx-path-clock-frequencies */
uint32_t tx_path_clock_frequencies[6]; /* adi,tx-path-clock-frequencies */
uint32_t rf_rx_bandwidth_hz; /* adi,rf-rx-bandwidth-hz */
uint32_t rf_tx_bandwidth_hz; /* adi,rf-tx-bandwidth-hz */
/* RF Port Control */
uint32_t rx_rf_port_input_select; /* adi,rx-rf-port-input-select */
uint32_t tx_rf_port_input_select; /* adi,tx-rf-port-input-select */
/* TX Attenuation Control */
int32_t tx_attenuation_mdB; /* adi,tx-attenuation-mdB */
uint8_t update_tx_gain_in_alert_enable; /* adi,update-tx-gain-in-alert-enable */
/* Reference Clock Control */
uint8_t xo_disable_use_ext_refclk_enable; /* adi,xo-disable-use-ext-refclk-enable */
uint32_t dcxo_coarse_and_fine_tune[2]; /* adi,dcxo-coarse-and-fine-tune */
uint32_t clk_output_mode_select; /* adi,clk-output-mode-select */
/* Gain Control */
uint8_t gc_rx1_mode; /* adi,gc-rx1-mode */
uint8_t gc_rx2_mode; /* adi,gc-rx2-mode */
uint8_t gc_adc_large_overload_thresh; /* adi,gc-adc-large-overload-thresh */
uint8_t gc_adc_ovr_sample_size; /* adi,gc-adc-ovr-sample-size */
uint8_t gc_adc_small_overload_thresh; /* adi,gc-adc-small-overload-thresh */
uint16_t gc_dec_pow_measurement_duration; /* adi,gc-dec-pow-measurement-duration */
uint8_t gc_dig_gain_enable; /* adi,gc-dig-gain-enable */
uint16_t gc_lmt_overload_high_thresh; /* adi,gc-lmt-overload-high-thresh */
uint16_t gc_lmt_overload_low_thresh; /* adi,gc-lmt-overload-low-thresh */
uint8_t gc_low_power_thresh; /* adi,gc-low-power-thresh */
uint8_t gc_max_dig_gain; /* adi,gc-max-dig-gain */
uint8_t gc_use_rx_fir_out_for_dec_pwr_meas_enable; /* adi,gc-use-rx-fir-out-for-dec-pwr-meas-enable */
/* Gain MGC Control */
uint8_t mgc_dec_gain_step; /* adi,mgc-dec-gain-step */
uint8_t mgc_inc_gain_step; /* adi,mgc-inc-gain-step */
uint8_t mgc_rx1_ctrl_inp_enable; /* adi,mgc-rx1-ctrl-inp-enable */
uint8_t mgc_rx2_ctrl_inp_enable; /* adi,mgc-rx2-ctrl-inp-enable */
uint8_t mgc_split_table_ctrl_inp_gain_mode; /* adi,mgc-split-table-ctrl-inp-gain-mode */
/* Gain AGC Control */
uint8_t agc_adc_large_overload_exceed_counter; /* adi,agc-adc-large-overload-exceed-counter */
uint8_t agc_adc_large_overload_inc_steps; /* adi,agc-adc-large-overload-inc-steps - Name is misleading should be dec-steps*/
uint8_t agc_adc_lmt_small_overload_prevent_gain_inc_enable; /* adi,agc-adc-lmt-small-overload-prevent-gain-inc-enable */
uint8_t agc_adc_small_overload_exceed_counter; /* adi,agc-adc-small-overload-exceed-counter */
uint8_t agc_dig_gain_step_size; /* adi,agc-dig-gain-step-size */
uint8_t agc_dig_saturation_exceed_counter; /* adi,agc-dig-saturation-exceed-counter */
uint32_t agc_gain_update_interval_us; /* adi,agc-gain-update-interval-us */
uint8_t agc_immed_gain_change_if_large_adc_overload_enable; /* adi,agc-immed-gain-change-if-large-adc-overload-enable */
uint8_t agc_immed_gain_change_if_large_lmt_overload_enable; /* adi,agc-immed-gain-change-if-large-lmt-overload-enable */
uint8_t agc_inner_thresh_high; /* adi,agc-inner-thresh-high */
uint8_t agc_inner_thresh_high_dec_steps; /* adi,agc-inner-thresh-high-dec-steps */
uint8_t agc_inner_thresh_low; /* adi,agc-inner-thresh-low */
uint8_t agc_inner_thresh_low_inc_steps; /* adi,agc-inner-thresh-low-inc-steps */
uint8_t agc_lmt_overload_large_exceed_counter; /* adi,agc-lmt-overload-large-exceed-counter */
uint8_t agc_lmt_overload_large_inc_steps; /* adi,agc-lmt-overload-large-inc-steps */
uint8_t agc_lmt_overload_small_exceed_counter; /* adi,agc-lmt-overload-small-exceed-counter */
uint8_t agc_outer_thresh_high; /* adi,agc-outer-thresh-high */
uint8_t agc_outer_thresh_high_dec_steps; /* adi,agc-outer-thresh-high-dec-steps */
uint8_t agc_outer_thresh_low; /* adi,agc-outer-thresh-low */
uint8_t agc_outer_thresh_low_inc_steps; /* adi,agc-outer-thresh-low-inc-steps */
uint32_t agc_attack_delay_extra_margin_us; /* adi,agc-attack-delay-extra-margin-us */
uint8_t agc_sync_for_gain_counter_enable; /* adi,agc-sync-for-gain-counter-enable */
/* Fast AGC */
uint32_t fagc_dec_pow_measuremnt_duration; /* adi,fagc-dec-pow-measurement-duration */
uint32_t fagc_state_wait_time_ns; /* adi,fagc-state-wait-time-ns */
/* Fast AGC - Low Power */
uint8_t fagc_allow_agc_gain_increase; /* adi,fagc-allow-agc-gain-increase-enable */
uint32_t fagc_lp_thresh_increment_time; /* adi,fagc-lp-thresh-increment-time */
uint32_t fagc_lp_thresh_increment_steps; /* adi,fagc-lp-thresh-increment-steps */
/* Fast AGC - Lock Level (Lock Level is set via slow AGC inner high threshold) */
uint8_t fagc_lock_level_lmt_gain_increase_en; /* adi,fagc-lock-level-lmt-gain-increase-enable */
uint32_t fagc_lock_level_gain_increase_upper_limit; /* adi,fagc-lock-level-gain-increase-upper-limit */
/* Fast AGC - Peak Detectors and Final Settling */
uint32_t fagc_lpf_final_settling_steps; /* adi,fagc-lpf-final-settling-steps */
uint32_t fagc_lmt_final_settling_steps; /* adi,fagc-lmt-final-settling-steps */
uint32_t fagc_final_overrange_count; /* adi,fagc-final-overrange-count */
/* Fast AGC - Final Power Test */
uint8_t fagc_gain_increase_after_gain_lock_en; /* adi,fagc-gain-increase-after-gain-lock-enable */
/* Fast AGC - Unlocking the Gain */
uint32_t fagc_gain_index_type_after_exit_rx_mode; /* adi,fagc-gain-index-type-after-exit-rx-mode */
uint8_t fagc_use_last_lock_level_for_set_gain_en; /* adi,fagc-use-last-lock-level-for-set-gain-enable */
uint8_t fagc_rst_gla_stronger_sig_thresh_exceeded_en; /* adi,fagc-rst-gla-stronger-sig-thresh-exceeded-enable */
uint32_t fagc_optimized_gain_offset; /* adi,fagc-optimized-gain-offset */
uint32_t fagc_rst_gla_stronger_sig_thresh_above_ll; /* adi,fagc-rst-gla-stronger-sig-thresh-above-ll */
uint8_t fagc_rst_gla_engergy_lost_sig_thresh_exceeded_en; /* adi,fagc-rst-gla-engergy-lost-sig-thresh-exceeded-enable */
uint8_t fagc_rst_gla_engergy_lost_goto_optim_gain_en; /* adi,fagc-rst-gla-engergy-lost-goto-optim-gain-enable */
uint32_t fagc_rst_gla_engergy_lost_sig_thresh_below_ll; /* adi,fagc-rst-gla-engergy-lost-sig-thresh-below-ll */
uint32_t fagc_energy_lost_stronger_sig_gain_lock_exit_cnt; /* adi,fagc-energy-lost-stronger-sig-gain-lock-exit-cnt */
uint8_t fagc_rst_gla_large_adc_overload_en; /* adi,fagc-rst-gla-large-adc-overload-enable */
uint8_t fagc_rst_gla_large_lmt_overload_en; /* adi,fagc-rst-gla-large-lmt-overload-enable */
uint8_t fagc_rst_gla_en_agc_pulled_high_en; /* adi,fagc-rst-gla-en-agc-pulled-high-enable */
uint32_t fagc_rst_gla_if_en_agc_pulled_high_mode; /* adi,fagc-rst-gla-if-en-agc-pulled-high-mode */
uint32_t fagc_power_measurement_duration_in_state5; /* adi,fagc-power-measurement-duration-in-state5 */
uint32_t fagc_large_overload_inc_steps; /* adi,fagc-adc-large-overload-inc-steps - Name is misleading should be dec-steps */
/* RSSI Control */
uint32_t rssi_delay; /* adi,rssi-delay */
uint32_t rssi_duration; /* adi,rssi-duration */
uint8_t rssi_restart_mode; /* adi,rssi-restart-mode */
uint8_t rssi_unit_is_rx_samples_enable; /* adi,rssi-unit-is-rx-samples-enable */
uint32_t rssi_wait; /* adi,rssi-wait */
/* Aux ADC Control */
uint32_t aux_adc_decimation; /* adi,aux-adc-decimation */
uint32_t aux_adc_rate; /* adi,aux-adc-rate */
/* AuxDAC Control */
uint8_t aux_dac_manual_mode_enable; /* adi,aux-dac-manual-mode-enable */
uint32_t aux_dac1_default_value_mV; /* adi,aux-dac1-default-value-mV */
uint8_t aux_dac1_active_in_rx_enable; /* adi,aux-dac1-active-in-rx-enable */
uint8_t aux_dac1_active_in_tx_enable; /* adi,aux-dac1-active-in-tx-enable */
uint8_t aux_dac1_active_in_alert_enable; /* adi,aux-dac1-active-in-alert-enable */
uint32_t aux_dac1_rx_delay_us; /* adi,aux-dac1-rx-delay-us */
uint32_t aux_dac1_tx_delay_us; /* adi,aux-dac1-tx-delay-us */
uint32_t aux_dac2_default_value_mV; /* adi,aux-dac2-default-value-mV */
uint8_t aux_dac2_active_in_rx_enable; /* adi,aux-dac2-active-in-rx-enable */
uint8_t aux_dac2_active_in_tx_enable; /* adi,aux-dac2-active-in-tx-enable */
uint8_t aux_dac2_active_in_alert_enable; /* adi,aux-dac2-active-in-alert-enable */
uint32_t aux_dac2_rx_delay_us; /* adi,aux-dac2-rx-delay-us */
uint32_t aux_dac2_tx_delay_us; /* adi,aux-dac2-tx-delay-us */
/* Temperature Sensor Control */
uint32_t temp_sense_decimation; /* adi,temp-sense-decimation */
uint16_t temp_sense_measurement_interval_ms; /* adi,temp-sense-measurement-interval-ms */
int8_t temp_sense_offset_signed; /* adi,temp-sense-offset-signed */
uint8_t temp_sense_periodic_measurement_enable; /* adi,temp-sense-periodic-measurement-enable */
/* Control Out Setup */
uint8_t ctrl_outs_enable_mask; /* adi,ctrl-outs-enable-mask */
uint8_t ctrl_outs_index; /* adi,ctrl-outs-index */
/* External LNA Control */
uint32_t elna_settling_delay_ns; /* adi,elna-settling-delay-ns */
uint32_t elna_gain_mdB; /* adi,elna-gain-mdB */
uint32_t elna_bypass_loss_mdB; /* adi,elna-bypass-loss-mdB */
uint8_t elna_rx1_gpo0_control_enable; /* adi,elna-rx1-gpo0-control-enable */
uint8_t elna_rx2_gpo1_control_enable; /* adi,elna-rx2-gpo1-control-enable */
uint8_t elna_gaintable_all_index_enable; /* adi,elna-gaintable-all-index-enable */
/* Digital Interface Control */
uint8_t digital_interface_tune_skip_mode; /* adi,digital-interface-tune-skip-mode */
uint8_t digital_interface_tune_fir_disable; /* adi,digital-interface-tune-fir-disable */
uint8_t pp_tx_swap_enable; /* adi,pp-tx-swap-enable */
uint8_t pp_rx_swap_enable; /* adi,pp-rx-swap-enable */
uint8_t tx_channel_swap_enable; /* adi,tx-channel-swap-enable */
uint8_t rx_channel_swap_enable; /* adi,rx-channel-swap-enable */
uint8_t rx_frame_pulse_mode_enable; /* adi,rx-frame-pulse-mode-enable */
uint8_t two_t_two_r_timing_enable; /* adi,2t2r-timing-enable */
uint8_t invert_data_bus_enable; /* adi,invert-data-bus-enable */
uint8_t invert_data_clk_enable; /* adi,invert-data-clk-enable */
uint8_t fdd_alt_word_order_enable; /* adi,fdd-alt-word-order-enable */
uint8_t invert_rx_frame_enable; /* adi,invert-rx-frame-enable */
uint8_t fdd_rx_rate_2tx_enable; /* adi,fdd-rx-rate-2tx-enable */
uint8_t swap_ports_enable; /* adi,swap-ports-enable */
uint8_t single_data_rate_enable; /* adi,single-data-rate-enable */
uint8_t lvds_mode_enable; /* adi,lvds-mode-enable */
uint8_t half_duplex_mode_enable; /* adi,half-duplex-mode-enable */
uint8_t single_port_mode_enable; /* adi,single-port-mode-enable */
uint8_t full_port_enable; /* adi,full-port-enable */
uint8_t full_duplex_swap_bits_enable; /* adi,full-duplex-swap-bits-enable */
uint32_t delay_rx_data; /* adi,delay-rx-data */
uint32_t rx_data_clock_delay; /* adi,rx-data-clock-delay */
uint32_t rx_data_delay; /* adi,rx-data-delay */
uint32_t tx_fb_clock_delay; /* adi,tx-fb-clock-delay */
uint32_t tx_data_delay; /* adi,tx-data-delay */
uint32_t lvds_bias_mV; /* adi,lvds-bias-mV */
uint8_t lvds_rx_onchip_termination_enable; /* adi,lvds-rx-onchip-termination-enable */
uint8_t rx1rx2_phase_inversion_en; /* adi,rx1-rx2-phase-inversion-enable */
uint8_t lvds_invert1_control; /* adi,lvds-invert1-control */
uint8_t lvds_invert2_control; /* adi,lvds-invert2-control */
/* GPO Control */
uint8_t gpo_manual_mode_enable; /* adi,gpo-manual-mode-enable */
uint32_t gpo_manual_mode_enable_mask; /* adi,gpo-manual-mode-enable-mask */
uint8_t gpo0_inactive_state_high_enable; /* adi,gpo0-inactive-state-high-enable */
uint8_t gpo1_inactive_state_high_enable; /* adi,gpo1-inactive-state-high-enable */
uint8_t gpo2_inactive_state_high_enable; /* adi,gpo2-inactive-state-high-enable */
uint8_t gpo3_inactive_state_high_enable; /* adi,gpo3-inactive-state-high-enable */
uint8_t gpo0_slave_rx_enable; /* adi,gpo0-slave-rx-enable */
uint8_t gpo0_slave_tx_enable; /* adi,gpo0-slave-tx-enable */
uint8_t gpo1_slave_rx_enable; /* adi,gpo1-slave-rx-enable */
uint8_t gpo1_slave_tx_enable; /* adi,gpo1-slave-tx-enable */
uint8_t gpo2_slave_rx_enable; /* adi,gpo2-slave-rx-enable */
uint8_t gpo2_slave_tx_enable; /* adi,gpo2-slave-tx-enable */
uint8_t gpo3_slave_rx_enable; /* adi,gpo3-slave-rx-enable */
uint8_t gpo3_slave_tx_enable; /* adi,gpo3-slave-tx-enable */
uint8_t gpo0_rx_delay_us; /* adi,gpo0-rx-delay-us */
uint8_t gpo0_tx_delay_us; /* adi,gpo0-tx-delay-us */
uint8_t gpo1_rx_delay_us; /* adi,gpo1-rx-delay-us */
uint8_t gpo1_tx_delay_us; /* adi,gpo1-tx-delay-us */
uint8_t gpo2_rx_delay_us; /* adi,gpo2-rx-delay-us */
uint8_t gpo2_tx_delay_us; /* adi,gpo2-tx-delay-us */
uint8_t gpo3_rx_delay_us; /* adi,gpo3-rx-delay-us */
uint8_t gpo3_tx_delay_us; /* adi,gpo3-tx-delay-us */
/* Tx Monitor Control */
uint32_t low_high_gain_threshold_mdB; /* adi,txmon-low-high-thresh */
uint32_t low_gain_dB; /* adi,txmon-low-gain */
uint32_t high_gain_dB; /* adi,txmon-high-gain */
uint8_t tx_mon_track_en; /* adi,txmon-dc-tracking-enable */
uint8_t one_shot_mode_en; /* adi,txmon-one-shot-mode-enable */
uint32_t tx_mon_delay; /* adi,txmon-delay */
uint32_t tx_mon_duration; /* adi,txmon-duration */
uint32_t tx1_mon_front_end_gain; /* adi,txmon-1-front-end-gain */
uint32_t tx2_mon_front_end_gain; /* adi,txmon-2-front-end-gain */
uint32_t tx1_mon_lo_cm; /* adi,txmon-1-lo-cm */
uint32_t tx2_mon_lo_cm; /* adi,txmon-2-lo-cm */
/* GPIO definitions */
struct gpio_init_param gpio_resetb; /* reset-gpios */
/* MCS Sync */
struct gpio_init_param gpio_sync; /* sync-gpios */
struct gpio_init_param gpio_cal_sw1; /* cal-sw1-gpios */
struct gpio_init_param gpio_cal_sw2; /* cal-sw2-gpios */
struct spi_init_param spi_param;
/* External LO clocks */
uint32_t (*ad9361_rfpll_ext_recalc_rate)(struct refclk_scale *clk_priv);
int32_t (*ad9361_rfpll_ext_round_rate)(struct refclk_scale *clk_priv,
uint32_t rate);
int32_t (*ad9361_rfpll_ext_set_rate)(struct refclk_scale *clk_priv,
uint32_t rate);
} AD9361_InitParam;
typedef struct {
uint32_t rx; /* 1, 2, 3(both) */
int32_t rx_gain; /* -12, -6, 0, 6 */
uint32_t rx_dec; /* 1, 2, 4 */
int16_t rx_coef[128];
uint8_t rx_coef_size;
uint32_t rx_path_clks[6];
uint32_t rx_bandwidth;
} AD9361_RXFIRConfig;
typedef struct {
uint32_t tx; /* 1, 2, 3(both) */
int32_t tx_gain; /* -6, 0 */
uint32_t tx_int; /* 1, 2, 4 */
int16_t tx_coef[128];
uint8_t tx_coef_size;
uint32_t tx_path_clks[6];
uint32_t tx_bandwidth;
} AD9361_TXFIRConfig;
enum ad9361_ensm_mode {
ENSM_MODE_TX,
ENSM_MODE_RX,
ENSM_MODE_ALERT,
ENSM_MODE_FDD,
ENSM_MODE_WAIT,
ENSM_MODE_SLEEP,
ENSM_MODE_PINCTRL,
ENSM_MODE_PINCTRL_FDD_INDEP,
};
#define ENABLE 1
#define DISABLE 0
#define RX1 0
#define RX2 1
#define TX1 0
#define TX2 1
#define A_BALANCED 0
#define B_BALANCED 1
#define C_BALANCED 2
#define A_N 3
#define A_P 4
#define B_N 5
#define B_P 6
#define C_N 7
#define C_P 8
#define TX_MON1 9
#define TX_MON2 10
#define TX_MON1_2 11
#define TXA 0
#define TXB 1
#define MODE_1x1 1
#define MODE_2x2 2
#define HIGHEST_OSR 0
#define NOMINAL_OSR 1
#define INT_LO 0
#define EXT_LO 1
#define ON 0
#define OFF 1
/******************************************************************************/
/************************ Functions Declarations ******************************/
/******************************************************************************/
/* Initialize the AD9361 part. */
int32_t ad9361_init (struct ad9361_rf_phy **ad9361_phy,
AD9361_InitParam *init_param);
/* Free the allocated resources. */
int32_t ad9361_remove(struct ad9361_rf_phy *phy);
/* Set the Enable State Machine (ENSM) mode. */
int32_t ad9361_set_en_state_machine_mode (struct ad9361_rf_phy *phy,
uint32_t mode);
/* Get the Enable State Machine (ENSM) mode. */
int32_t ad9361_get_en_state_machine_mode (struct ad9361_rf_phy *phy,
uint32_t *mode);
/* Set the receive RF gain for the selected channel. */
int32_t ad9361_set_rx_rf_gain (struct ad9361_rf_phy *phy, uint8_t ch,
int32_t gain_db);
/* Get current receive RF gain for the selected channel. */
int32_t ad9361_get_rx_rf_gain (struct ad9361_rf_phy *phy, uint8_t ch,
int32_t *gain_db);
/* Set the RX RF bandwidth. */
int32_t ad9361_set_rx_rf_bandwidth (struct ad9361_rf_phy *phy,
uint32_t bandwidth_hz);
/* Get the RX RF bandwidth. */
int32_t ad9361_get_rx_rf_bandwidth (struct ad9361_rf_phy *phy,
uint32_t *bandwidth_hz);
/* Set the RX sampling frequency. */
int32_t ad9361_set_rx_sampling_freq (struct ad9361_rf_phy *phy,
uint32_t sampling_freq_hz);
/* Get current RX sampling frequency. */
int32_t ad9361_get_rx_sampling_freq (struct ad9361_rf_phy *phy,
uint32_t *sampling_freq_hz);
/* Set the RX LO frequency. */
int32_t ad9361_set_rx_lo_freq (struct ad9361_rf_phy *phy, uint64_t lo_freq_hz);
/* Get current RX LO frequency. */
int32_t ad9361_get_rx_lo_freq (struct ad9361_rf_phy *phy, uint64_t *lo_freq_hz);
/* Switch between internal and external LO. */
int32_t ad9361_set_rx_lo_int_ext(struct ad9361_rf_phy *phy, uint8_t int_ext);
/* Get the RSSI for the selected channel. */
int32_t ad9361_get_rx_rssi (struct ad9361_rf_phy *phy, uint8_t ch,
struct rf_rssi *rssi);
/* Set the gain control mode for the selected channel. */
int32_t ad9361_set_rx_gain_control_mode (struct ad9361_rf_phy *phy, uint8_t ch,
uint8_t gc_mode);
/* Get the gain control mode for the selected channel. */
int32_t ad9361_get_rx_gain_control_mode (struct ad9361_rf_phy *phy, uint8_t ch,
uint8_t *gc_mode);
/* Set the RX FIR filter configuration. */
int32_t ad9361_set_rx_fir_config (struct ad9361_rf_phy *phy,
AD9361_RXFIRConfig fir_cfg);
/* Get the RX FIR filter configuration. */
int32_t ad9361_get_rx_fir_config(struct ad9361_rf_phy *phy, uint8_t rx_ch,
AD9361_RXFIRConfig *fir_cfg);
/* Enable/disable the RX FIR filter. */
int32_t ad9361_set_rx_fir_en_dis (struct ad9361_rf_phy *phy, uint8_t en_dis);
/* Get the status of the RX FIR filter. */
int32_t ad9361_get_rx_fir_en_dis (struct ad9361_rf_phy *phy, uint8_t *en_dis);
/* Enable/disable the RX RFDC Tracking. */
int32_t ad9361_set_rx_rfdc_track_en_dis (struct ad9361_rf_phy *phy,
uint8_t en_dis);
/* Get the status of the RX RFDC Tracking. */
int32_t ad9361_get_rx_rfdc_track_en_dis (struct ad9361_rf_phy *phy,
uint8_t *en_dis);
/* Enable/disable the RX BasebandDC Tracking. */
int32_t ad9361_set_rx_bbdc_track_en_dis (struct ad9361_rf_phy *phy,
uint8_t en_dis);
/* Get the status of the RX BasebandDC Tracking. */
int32_t ad9361_get_rx_bbdc_track_en_dis (struct ad9361_rf_phy *phy,
uint8_t *en_dis);
/* Enable/disable the RX Quadrature Tracking. */
int32_t ad9361_set_rx_quad_track_en_dis (struct ad9361_rf_phy *phy,
uint8_t en_dis);
/* Get the status of the RX Quadrature Tracking. */
int32_t ad9361_get_rx_quad_track_en_dis (struct ad9361_rf_phy *phy,
uint8_t *en_dis);
/* Set the RX RF input port. */
int32_t ad9361_set_rx_rf_port_input (struct ad9361_rf_phy *phy, uint32_t mode);
/* Get the selected RX RF input port. */
int32_t ad9361_get_rx_rf_port_input (struct ad9361_rf_phy *phy, uint32_t *mode);
/* Store RX fastlock profile. */
int32_t ad9361_rx_fastlock_store(struct ad9361_rf_phy *phy, uint32_t profile);
/* Recall RX fastlock profile. */
int32_t ad9361_rx_fastlock_recall(struct ad9361_rf_phy *phy, uint32_t profile);
/* Load RX fastlock profile. */
int32_t ad9361_rx_fastlock_load(struct ad9361_rf_phy *phy, uint32_t profile,
uint8_t *values);
/* Save RX fastlock profile. */
int32_t ad9361_rx_fastlock_save(struct ad9361_rf_phy *phy, uint32_t profile,
uint8_t *values);
/* Power down the RX Local Oscillator. */
int32_t ad9361_rx_lo_powerdown(struct ad9361_rf_phy *phy, uint8_t option);
/* Get the RX Local Oscillator power status. */
int32_t ad9361_get_rx_lo_power(struct ad9361_rf_phy *phy, uint8_t *option);
/* Set the transmit attenuation for the selected channel. */
int32_t ad9361_set_tx_attenuation (struct ad9361_rf_phy *phy, uint8_t ch,
uint32_t attenuation_mdb);
/* Get current transmit attenuation for the selected channel. */
int32_t ad9361_get_tx_attenuation (struct ad9361_rf_phy *phy, uint8_t ch,
uint32_t *attenuation_mdb);
/* Set the TX RF bandwidth. */
int32_t ad9361_set_tx_rf_bandwidth (struct ad9361_rf_phy *phy,
uint32_t bandwidth_hz);
/* Get the TX RF bandwidth. */
int32_t ad9361_get_tx_rf_bandwidth (struct ad9361_rf_phy *phy,
uint32_t *bandwidth_hz);
/* Set the TX sampling frequency. */
int32_t ad9361_set_tx_sampling_freq (struct ad9361_rf_phy *phy,
uint32_t sampling_freq_hz);
/* Get current TX sampling frequency. */
int32_t ad9361_get_tx_sampling_freq (struct ad9361_rf_phy *phy,
uint32_t *sampling_freq_hz);
/* Set the TX LO frequency. */
int32_t ad9361_set_tx_lo_freq (struct ad9361_rf_phy *phy, uint64_t lo_freq_hz);
/* Get current TX LO frequency. */
int32_t ad9361_get_tx_lo_freq (struct ad9361_rf_phy *phy, uint64_t *lo_freq_hz);
/* Switch between internal and external LO. */
int32_t ad9361_set_tx_lo_int_ext(struct ad9361_rf_phy *phy, uint8_t int_ext);
/* Set the TX FIR filter configuration. */
int32_t ad9361_set_tx_fir_config (struct ad9361_rf_phy *phy,
AD9361_TXFIRConfig fir_cfg);
/* Get the TX FIR filter configuration. */
int32_t ad9361_get_tx_fir_config(struct ad9361_rf_phy *phy, uint8_t tx_ch,
AD9361_TXFIRConfig *fir_cfg);
/* Enable/disable the TX FIR filter. */
int32_t ad9361_set_tx_fir_en_dis (struct ad9361_rf_phy *phy, uint8_t en_dis);
/* Get the status of the TX FIR filter. */
int32_t ad9361_get_tx_fir_en_dis (struct ad9361_rf_phy *phy, uint8_t *en_dis);
/* Get the TX RSSI for the selected channel. */
int32_t ad9361_get_tx_rssi (struct ad9361_rf_phy *phy, uint8_t ch,
uint32_t *rssi_db_x_1000);
/* Set the TX RF output port. */
int32_t ad9361_set_tx_rf_port_output (struct ad9361_rf_phy *phy, uint32_t mode);
/* Get the selected TX RF output port. */
int32_t ad9361_get_tx_rf_port_output (struct ad9361_rf_phy *phy,
uint32_t *mode);
/* Enable/disable the auto calibration. */
int32_t ad9361_set_tx_auto_cal_en_dis (struct ad9361_rf_phy *phy,
uint8_t en_dis);
/* Get the status of the auto calibration flag. */
int32_t ad9361_get_tx_auto_cal_en_dis (struct ad9361_rf_phy *phy,
uint8_t *en_dis);
/* Store TX fastlock profile. */
int32_t ad9361_tx_fastlock_store(struct ad9361_rf_phy *phy, uint32_t profile);
/* Recall TX fastlock profile. */
int32_t ad9361_tx_fastlock_recall(struct ad9361_rf_phy *phy, uint32_t profile);
/* Load TX fastlock profile. */
int32_t ad9361_tx_fastlock_load(struct ad9361_rf_phy *phy, uint32_t profile,
uint8_t *values);
/* Save TX fastlock profile. */
int32_t ad9361_tx_fastlock_save(struct ad9361_rf_phy *phy, uint32_t profile,
uint8_t *values);
/* Power down the TX Local Oscillator. */
int32_t ad9361_tx_lo_powerdown(struct ad9361_rf_phy *phy, uint8_t option);
/* Get the TX Local Oscillator power status. */
int32_t ad9361_get_tx_lo_power(struct ad9361_rf_phy *phy, uint8_t *option);
/* Set the RX and TX path rates. */
int32_t ad9361_set_trx_path_clks(struct ad9361_rf_phy *phy,
uint32_t *rx_path_clks, uint32_t *tx_path_clks);
/* Get the RX and TX path rates. */
int32_t ad9361_get_trx_path_clks(struct ad9361_rf_phy *phy,
uint32_t *rx_path_clks, uint32_t *tx_path_clks);
/* Set the number of channels mode. */
int32_t ad9361_set_no_ch_mode(struct ad9361_rf_phy *phy, uint8_t no_ch_mode);
/* Do multi chip synchronization. */
int32_t ad9361_do_mcs(struct ad9361_rf_phy *phy_master,
struct ad9361_rf_phy *phy_slave);
/* Enable/disable the TRX FIR filters. */
int32_t ad9361_set_trx_fir_en_dis (struct ad9361_rf_phy *phy, uint8_t en_dis);
/* Set the OSR rate governor. */
int32_t ad9361_set_trx_rate_gov (struct ad9361_rf_phy *phy, uint32_t rate_gov);
/* Get the OSR rate governor. */
int32_t ad9361_get_trx_rate_gov (struct ad9361_rf_phy *phy, uint32_t *rate_gov);
/* Perform the selected calibration. */
int32_t ad9361_do_calib(struct ad9361_rf_phy *phy, uint32_t cal, int32_t arg);
/* Load and enable TRX FIR filters configurations. */
int32_t ad9361_trx_load_enable_fir(struct ad9361_rf_phy *phy,
AD9361_RXFIRConfig rx_fir_cfg,
AD9361_TXFIRConfig tx_fir_cfg);
/* Do DCXO coarse tuning. */
int32_t ad9361_do_dcxo_tune_coarse(struct ad9361_rf_phy *phy,
uint32_t coarse);
/* Do DCXO fine tuning. */
int32_t ad9361_do_dcxo_tune_fine(struct ad9361_rf_phy *phy,
uint32_t fine);
/* Get the temperature. */
int32_t ad9361_get_temperature(struct ad9361_rf_phy *phy,
int32_t *temp);
#endif
@@ -0,0 +1,86 @@
/***************************************************************************//**
* @file ad9361_conv.c
* @brief Implementation of AD9361 Conv Driver.
********************************************************************************
* Copyright 2014-2015(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 Files **********************************/
/******************************************************************************/
#include <inttypes.h>
#include <string.h>
#include "ad9361.h"
#include "ad9361_util.h"
#include "delay.h"
#include "../../../config/app_config.h"
/******************************************************************************/
/********************** Macros and Constants Definitions **********************/
/******************************************************************************/
/**
* HDL loopback enable/disable.
* @param phy The AD9361 state structure.
* @param enable Enable/disable option.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad9361_hdl_loopback(struct ad9361_rf_phy *phy, bool enable)
{
return -ENODEV;
}
/**
* Digital tune.
* @param phy The AD9361 state structure.
* @param max_freq Maximum frequency.
* @param flags Flags: BE_VERBOSE, BE_MOREVERBOSE, DO_IDELAY, DO_ODELAY.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad9361_dig_tune(struct ad9361_rf_phy *phy, uint32_t max_freq,
enum dig_tune_flags flags)
{
return 0;
}
/**
* Setup the AD9361 device.
* @param phy The AD9361 state structure.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad9361_post_setup(struct ad9361_rf_phy *phy)
{
return 0;
}
@@ -0,0 +1,335 @@
/***************************************************************************//**
* @file ad9361_util.c
* @brief AD9361 Implementation of Util Driver.
* @author DBogdan (dragos.bogdan@analog.com)
********************************************************************************
* Copyright 2013(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 Files **********************************/
/******************************************************************************/
#include <string.h>
#include "ad9361_util.h"
#include "../../../include/delay.h"
/******************************************************************************/
/*************************** Macros Definitions *******************************/
/******************************************************************************/
#define BITS_PER_LONG 32
/***************************************************************************//**
* @brief clk_prepare_enable
*******************************************************************************/
int32_t clk_prepare_enable(struct clk *clk)
{
if (clk) {
// Unused variable - fix compiler warning
}
return 0;
}
/***************************************************************************//**
* @brief clk_get_rate
*******************************************************************************/
uint32_t clk_get_rate(struct ad9361_rf_phy *phy,
struct refclk_scale *clk_priv)
{
uint32_t rate = 0;
uint32_t source;
source = clk_priv->source;
switch (source) {
case TX_REFCLK:
case RX_REFCLK:
case BB_REFCLK:
rate = ad9361_clk_factor_recalc_rate(clk_priv,
phy->clk_refin->rate);
break;
case TX_RFPLL_INT:
case RX_RFPLL_INT:
rate = ad9361_rfpll_int_recalc_rate(clk_priv,
phy->clks[clk_priv->parent_source]->rate);
break;
case RX_RFPLL_DUMMY:
case TX_RFPLL_DUMMY:
rate = ad9361_rfpll_dummy_recalc_rate(clk_priv);
break;
case TX_RFPLL:
case RX_RFPLL:
rate = ad9361_rfpll_recalc_rate(clk_priv);
break;
case BBPLL_CLK:
rate = ad9361_bbpll_recalc_rate(clk_priv,
phy->clks[clk_priv->parent_source]->rate);
break;
case ADC_CLK:
case R2_CLK:
case R1_CLK:
case CLKRF_CLK:
case RX_SAMPL_CLK:
case DAC_CLK:
case T2_CLK:
case T1_CLK:
case CLKTF_CLK:
case TX_SAMPL_CLK:
rate = ad9361_clk_factor_recalc_rate(clk_priv,
phy->clks[clk_priv->parent_source]->rate);
break;
default:
break;
}
return rate;
}
/***************************************************************************//**
* @brief clk_set_rate
*******************************************************************************/
int32_t clk_set_rate(struct ad9361_rf_phy *phy,
struct refclk_scale *clk_priv,
uint32_t rate)
{
uint32_t source;
int32_t i;
uint32_t round_rate;
source = clk_priv->source;
if(phy->clks[source]->rate != rate)
{
switch (source) {
case TX_REFCLK:
case RX_REFCLK:
case BB_REFCLK:
round_rate = ad9361_clk_factor_round_rate(clk_priv, rate,
&phy->clk_refin->rate);
ad9361_clk_factor_set_rate(clk_priv, round_rate,
phy->clk_refin->rate);
phy->clks[source]->rate = ad9361_clk_factor_recalc_rate(clk_priv,
phy->clk_refin->rate);
break;
case TX_RFPLL_INT:
case RX_RFPLL_INT:
round_rate = ad9361_rfpll_int_round_rate(clk_priv, rate,
&phy->clks[clk_priv->parent_source]->rate);
ad9361_rfpll_int_set_rate(clk_priv, round_rate,
phy->clks[clk_priv->parent_source]->rate);
phy->clks[source]->rate = ad9361_rfpll_int_recalc_rate(clk_priv,
phy->clks[clk_priv->parent_source]->rate);
break;
case RX_RFPLL_DUMMY:
case TX_RFPLL_DUMMY:
ad9361_rfpll_dummy_set_rate(clk_priv, rate);
break;
case TX_RFPLL:
case RX_RFPLL:
round_rate = ad9361_rfpll_round_rate(clk_priv, rate);
ad9361_rfpll_set_rate(clk_priv, round_rate);
phy->clks[source]->rate = ad9361_rfpll_recalc_rate(clk_priv);
break;
case BBPLL_CLK:
round_rate = ad9361_bbpll_round_rate(clk_priv, rate,
&phy->clks[clk_priv->parent_source]->rate);
ad9361_bbpll_set_rate(clk_priv, round_rate,
phy->clks[clk_priv->parent_source]->rate);
phy->clks[source]->rate = ad9361_bbpll_recalc_rate(clk_priv,
phy->clks[clk_priv->parent_source]->rate);
phy->bbpll_initialized = true;
break;
case ADC_CLK:
case R2_CLK:
case R1_CLK:
case CLKRF_CLK:
case RX_SAMPL_CLK:
case DAC_CLK:
case T2_CLK:
case T1_CLK:
case CLKTF_CLK:
case TX_SAMPL_CLK:
round_rate = ad9361_clk_factor_round_rate(clk_priv, rate,
&phy->clks[clk_priv->parent_source]->rate);
ad9361_clk_factor_set_rate(clk_priv, round_rate,
phy->clks[clk_priv->parent_source]->rate);
phy->clks[source]->rate = ad9361_clk_factor_recalc_rate(clk_priv,
phy->clks[clk_priv->parent_source]->rate);
break;
default:
break;
}
for(i = BB_REFCLK; i < BBPLL_CLK; i++)
{
phy->clks[i]->rate = ad9361_clk_factor_recalc_rate(phy->ref_clk_scale[i],
phy->clk_refin->rate);
}
phy->clks[BBPLL_CLK]->rate = ad9361_bbpll_recalc_rate(phy->ref_clk_scale[BBPLL_CLK],
phy->clks[phy->ref_clk_scale[BBPLL_CLK]->parent_source]->rate);
for(i = ADC_CLK; i < RX_RFPLL_INT; i++)
{
phy->clks[i]->rate = ad9361_clk_factor_recalc_rate(phy->ref_clk_scale[i],
phy->clks[phy->ref_clk_scale[i]->parent_source]->rate);
}
for(i = RX_RFPLL_INT; i < RX_RFPLL_DUMMY; i++)
{
phy->clks[i]->rate = ad9361_rfpll_int_recalc_rate(phy->ref_clk_scale[i],
phy->clks[phy->ref_clk_scale[i]->parent_source]->rate);
}
for(i = RX_RFPLL_DUMMY; i < RX_RFPLL; i++)
{
phy->clks[i]->rate = ad9361_rfpll_dummy_recalc_rate(phy->ref_clk_scale[i]);
}
for(i = RX_RFPLL; i < NUM_AD9361_CLKS; i++)
{
phy->clks[i]->rate = ad9361_rfpll_recalc_rate(phy->ref_clk_scale[i]);
}
} else {
if ((source == BBPLL_CLK) && !phy->bbpll_initialized) {
round_rate = ad9361_bbpll_round_rate(clk_priv, rate,
&phy->clks[clk_priv->parent_source]->rate);
ad9361_bbpll_set_rate(clk_priv, round_rate,
phy->clks[clk_priv->parent_source]->rate);
phy->clks[source]->rate = ad9361_bbpll_recalc_rate(clk_priv,
phy->clks[clk_priv->parent_source]->rate);
phy->bbpll_initialized = true;
}
}
return 0;
}
/***************************************************************************//**
* @brief int_sqrt
*******************************************************************************/
uint32_t int_sqrt(uint32_t x)
{
uint32_t b, m, y = 0;
if (x <= 1)
return x;
m = 1UL << (BITS_PER_LONG - 2);
while (m != 0) {
b = y + m;
y >>= 1;
if (x >= b) {
x -= b;
y += m;
}
m >>= 2;
}
return y;
}
/***************************************************************************//**
* @brief ilog2
*******************************************************************************/
int32_t ilog2(int32_t x)
{
int32_t A = !(!(x >> 16));
int32_t count = 0;
int32_t x_copy = x;
count = count + (A << 4);
x_copy = (((~A + 1) & (x >> 16)) + (~(~A + 1) & x));
A = !(!(x_copy >> 8));
count = count + (A << 3);
x_copy = (((~A + 1) & (x_copy >> 8)) + (~(~A + 1) & x_copy));
A = !(!(x_copy >> 4));
count = count + (A << 2);
x_copy = (((~A + 1) & (x_copy >> 4)) + (~(~A + 1) & x_copy));
A = !(!(x_copy >> 2));
count = count + (A << 1);
x_copy = (((~A + 1) & (x_copy >> 2)) + (~(~A + 1) & x_copy));
A = !(!(x_copy >> 1));
count = count + A;
return count;
}
/***************************************************************************//**
* @brief find_first_bit
*******************************************************************************/
uint32_t find_first_bit(uint32_t word)
{
int32_t num = 0;
if ((word & 0xffff) == 0) {
num += 16;
word >>= 16;
}
if ((word & 0xff) == 0) {
num += 8;
word >>= 8;
}
if ((word & 0xf) == 0) {
num += 4;
word >>= 4;
}
if ((word & 0x3) == 0) {
num += 2;
word >>= 2;
}
if ((word & 0x1) == 0)
num += 1;
return num;
}
/***************************************************************************//**
* @brief ERR_PTR
*******************************************************************************/
void * ERR_PTR(long error)
{
return (void *) error;
}
/***************************************************************************//**
* @brief zmalloc
*******************************************************************************/
void *zmalloc(size_t size)
{
void *ptr = malloc(size);
if (ptr)
memset(ptr, 0, size);
mdelay(1);
return ptr;
}
@@ -0,0 +1,120 @@
/***************************************************************************//**
* @file ad9361_util.h
* @brief AD9361 Header file of Util driver.
* @author DBogdan (dragos.bogdan@analog.com)
********************************************************************************
* Copyright 2013(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
*******************************************************************************/
#ifndef __AD9361_UTIL_H__
#define __AD9361_UTIL_H__
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "ad9361.h"
#include "common.h"
/******************************************************************************/
/********************** Macros and Constants Definitions **********************/
/******************************************************************************/
#define CLK_IGNORE_UNUSED BIT(3)
#define CLK_GET_RATE_NOCACHE BIT(6)
#if defined(HAVE_VERBOSE_MESSAGES)
#define dev_err(dev, format, ...) ({printf(format, ## __VA_ARGS__);printf("\n"); })
#define dev_warn(dev, format, ...) ({printf(format, ## __VA_ARGS__);printf("\n"); })
#if defined(HAVE_DEBUG_MESSAGES)
#define dev_dbg(dev, format, ...) ({printf(format, ## __VA_ARGS__);printf("\n"); })
#else
#define dev_dbg(dev, format, ...) ({ if (0) printf(format, ## __VA_ARGS__); })
#endif
#define printk(format, ...) printf(format, ## __VA_ARGS__)
#else
#define dev_err(dev, format, ...) ({ if (0) printf(format, ## __VA_ARGS__); })
#define dev_warn(dev, format, ...) ({ if (0) printf(format, ## __VA_ARGS__); })
#define dev_dbg(dev, format, ...) ({ if (0) printf(format, ## __VA_ARGS__); })
#define printk(format, ...) ({ if (0) printf(format, ## __VA_ARGS__); })
#endif
struct device {
};
struct spi_device {
struct device dev;
uint8_t id_no;
};
struct axiadc_state {
struct ad9361_rf_phy *phy;
uint32_t pcore_version;
};
struct axiadc_chip_info {
char *name;
int32_t num_channels;
};
struct axiadc_converter {
struct axiadc_chip_info *chip_info;
uint32_t scratch_reg[16];
};
#ifdef WIN32
#include "basetsd.h"
typedef SSIZE_T ssize_t;
#define strsep(s, ct) 0
#define snprintf(s, n, format, ...) 0
#define __func__ __FUNCTION__
#endif
/******************************************************************************/
/************************ Functions Declarations ******************************/
/******************************************************************************/
int32_t clk_prepare_enable(struct clk *clk);
uint32_t clk_get_rate(struct ad9361_rf_phy *phy,
struct refclk_scale *clk_priv);
int32_t clk_set_rate(struct ad9361_rf_phy *phy,
struct refclk_scale *clk_priv,
uint32_t rate);
uint32_t int_sqrt(uint32_t x);
int32_t ilog2(int32_t x);
uint32_t find_first_bit(uint32_t word);
void * ERR_PTR(long error);
void *zmalloc(size_t size);
#endif
@@ -0,0 +1,66 @@
/***************************************************************************//**
* @file common.h
* @brief Header file of Common Driver.
* @author DBogdan (dragos.bogdan@analog.com)
********************************************************************************
* Copyright 2013(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
*******************************************************************************/
#ifndef __AD9361_COMMON_H_
#define __AD9361_COMMON_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdint.h>
#include "../../../include/error.h"
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
#if defined (__STDC__) && (__STDC_VERSION__ >= 199901L)
#include <stdbool.h>
#else
typedef enum { false, true } bool;
#endif
struct clk {
const char *name;
uint32_t rate;
};
struct clk_hw {
struct clk *clk;
};
#endif // __AD9361_COMMON_H_
@@ -0,0 +1,151 @@
/***************************************************************************//**
* @file ad9361_reg.c
* @brief Implementation of AD9680 Driver.
* @author DBogdan (dragos.bogdan@analog.com)
********************************************************************************
* Copyright 2014-2016(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 Files **********************************/
/******************************************************************************/
#include "ad9361_reg.h"
#include <stdlib.h>
#include <stdio.h>
#include "../../../include/error.h"
/***************************************************************************//**
* @brief ad9361_reg_read
*******************************************************************************/
int32_t ad9361_reg_read(struct ad9361_reg_dev *dev,
uint16_t reg_addr,
uint8_t *reg_data)
{
uint8_t tx_buf[2];
uint8_t rx_buf[1];
int32_t ret;
tx_buf[0] = reg_addr >> 8;
tx_buf[1] = reg_addr & 0xFF;
ret = spi_write_and_read_3wire(dev->spi_desc,
tx_buf, rx_buf, 2, 1);
*reg_data = rx_buf[0];
return ret;
}
/***************************************************************************//**
* @brief ad9361_reg_write
*******************************************************************************/
int32_t ad9361_reg_write(struct ad9361_reg_dev *dev,
uint16_t reg_addr,
uint8_t reg_data)
{
uint8_t buf[3];
int32_t ret;
buf[0] = 0x80 | reg_addr >> 8;
buf[1] = reg_addr & 0xFF;
buf[2] = reg_data;
ret = spi_write_and_read_3wire(dev->spi_desc,
buf, NULL, 3, 0);
return ret;
}
/***************************************************************************//**
* @brief ad9361_reg_init
*******************************************************************************/
int32_t ad9361_reg_init(struct ad9361_reg_dev **device,
const struct ad9361_reg_init_param *init_param)
{
int ret = SUCCESS;
struct ad9361_reg_dev *dev;
dev = (struct ad9361_reg_dev *)malloc(sizeof(*dev));
if (!dev)
return FAILURE;
/* SPI */
ret = spi_init(&dev->spi_desc, init_param->spi_init);
ret |= gpio_get(&dev->gpio_desc_resetb, init_param->gpio_resetb);
gpio_direction_output(dev->gpio_desc_resetb, 0);
ad9361_reg_reset(dev);
*device = dev;
return ret;
}
/**
* AD9361 Device Reset
* @param phy The AD9361 state structure.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad9361_reg_reset(struct ad9361_reg_dev *dev)
{
if (dev->gpio_desc_resetb) {
gpio_set_value(dev->gpio_desc_resetb, 0);
mdelay(10);
gpio_set_value(dev->gpio_desc_resetb, 1);
mdelay(10);
return 0;
}
return 0;
}
/***************************************************************************//**
* @brief Free the resources allocated by ad9361_reg_setup().
*
* @param dev - The device structure.
*
* @return SUCCESS in case of success, negative error code otherwise.
*******************************************************************************/
int32_t ad9361_reg_remove(struct ad9361_reg_dev *dev)
{
int32_t ret;
ret = spi_remove(dev->spi_desc);
free(dev);
return ret;
}
@@ -0,0 +1,104 @@
/***************************************************************************//**
* @file ad9361_reg.h
* @brief Header file of ad9361_reg Driver.
* @author DBogdan (dragos.bogdan@analog.com)
********************************************************************************
* Copyright 2014-2016(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
*******************************************************************************/
#ifndef ad9361_reg_H_
#define ad9361_reg_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdint.h>
#include "delay.h"
#include "spi.h"
#include "gpio.h"
/******************************************************************************/
/********************** Macros and Constants Definitions **********************/
/******************************************************************************/
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
struct ad9361_reg_dev {
/* SPI */
struct spi_desc *spi_desc;
struct gpio_desc *gpio_desc_resetb;
};
struct ad9361_reg_init_param {
/* SPI */
struct spi_init_param *spi_init;
struct gpio_init_param *gpio_resetb;
};
enum Operation_Type{
AD9361_WRITE,
AD9361_READ,
AD9361_WAIT,
AD9361_WHEN
};
struct ad9361_reg_config {
int operation;
uint16_t val1;
uint16_t val2;
};
/******************************************************************************/
/************************ Functions Declarations ******************************/
/******************************************************************************/
int32_t ad9361_reg_read(struct ad9361_reg_dev *dev,
uint16_t reg_addr,
uint8_t *reg_data);
int32_t ad9361_reg_write(struct ad9361_reg_dev *dev,
uint16_t reg_addr,
uint8_t reg_data);
int32_t ad9361_reg_init(struct ad9361_reg_dev **device,
const struct ad9361_reg_init_param *init_param);
int32_t ad9361_reg_reset(struct ad9361_reg_dev *dev);
int32_t ad9361_reg_remove(struct ad9361_reg_dev *dev);
#endif
@@ -0,0 +1,740 @@
/*****************************************************************************/
/**
* Description: hwconfig.h
*
* Date: 2024-02-20 13:19
* Last Edit Time: [2024-02-20 13:19]
*
* Revisions: Rev 0.0
* History:
* [2023-05-07]: Initial edition.
*
* Copyright(c) 2024 Beijing Institute of Technology.
*
******************************************************************************/
/***************************** Include Files *********************************/
// Standard
#include <stdint.h>
#include <stdbool.h>
// Xilinx
#include "xgpiops.h"
#include "drivers/axi_core/spi_engine/spi_engine.h"
// App
#include "common.h"
#include "error.h"
#include "delay.h"
#include "system_monitor.h"
#include "hwconfig.h"
#include "config/app_config.h"
#include "dev_profile/dev_profile.h"
#ifdef RFSOC
#include "xrfdc.h"
#endif
/************************** Function Prototypes ******************************/
/*********************** Driver Instance Definitions **************************/
static struct hmc7044_dev *hmc7044_inst;
ad9528Device_t *ad9528_inst;
static struct lmk04828_dev *lmk04828_inst;
static struct lmx2594_dev *lmx2594_adc_inst;
static struct lmx2594_dev *lmx2594_dac_inst;
static struct ad9361_reg_dev *ad9361_1_reg_inst;
static struct ad9361_reg_dev *ad9361_2_reg_inst;
static struct ad9361_rf_phy *ad9361_phy;
static struct ad9653_dev *ad9653_inst;
static struct ad9694_dev *ad9694_inst;
XGpioPs Gpio;
#ifdef RFSOC
XRFdc RFdc;
#endif
/*****************************************************************************/
/**
* @brief Hardware_Init
*
* @param none.
*
* @return None.
*
******************************************************************************/
int32_t Hardware_Init(void)
{
int32_t Status;
// gpio initialization
XGpioPs_Config *ConfigPtr;
ConfigPtr = XGpioPs_LookupConfig(AD9361_GPIO_DEVICE_ID);
Status = XGpioPs_CfgInitialize(&Gpio, ConfigPtr, ConfigPtr->BaseAddr);
if (Status != SUCCESS)
{
return FAILURE;
}
#ifdef RFSOC
/**********************************************************/
/************* RF Data Converter Configuration ************/
/**********************************************************/
// rf data converter initialization
XRFdc_Config *RFdc_ConfigPtr;
RFdc_ConfigPtr = XRFdc_LookupConfig(RFDC_DEVICE_ID);
Status = XRFdc_CfgInitialize(&RFdc, RFdc_ConfigPtr);
if (Status != XST_SUCCESS)
{
return XST_FAILURE;
}
mdelay(100);
#endif
#ifdef HMC7044
/**********************************************************/
/****************** HMC7044 Configuration *****************/
/**********************************************************/
Status = hmc7044_init(&hmc7044_inst, &hmc7044_default_init_param);
if (Status != SUCCESS)
{
DBG_ERROR("HDWR: hmc7044_init() error: %" PRId32 "\n", Status);
return FAILURE;
}
#endif
#ifdef AD9528
/**********************************************************/
/****************** AD9528 Configuration ******************/
/**********************************************************/
Status = AD9528_init(&ad9528_inst, &ad9528_default_init_param);
if (Status != SUCCESS) {
DBG_ERROR("HDWR: AD9528_init() error: %" PRId32 "\n", Status);
return FAILURE;
}
Status = AD9528_config(ad9528_inst);
if (Status != SUCCESS) {
return FAILURE;
DBG_ERROR("HDWR: AD9528_config() error: %" PRId32 "\n", Status);
}
#endif
#ifdef LMK04828
/**********************************************************/
/***************** LMK04828 Configuration *****************/
/**********************************************************/
Status = lmk04828_init(&lmk04828_inst, &lmk04828_default_init_param);
for(int i = 0; i < lmk04828_default_config_len; i++)
{
Status = lmk04828_write(lmk04828_inst,
lmk04828_default_config[i].addr, lmk04828_default_config[i].value);
if (lmk04828_default_config[i].addr == 0x0000)
{
mdelay(500);
}
}
uint8_t Lmk04828Read;
// check pll1 lock status
Status = lmk04828_read(lmk04828_inst, 0x0182, &Lmk04828Read);
if ((Lmk04828Read & 0x02) == 0x02) {
DBG_INFO("HDWR: [LMK04828] PLL1 Locked.\r\n");
}
else {
DBG_ERROR("HDWR: [LMK04828] PLL1 NOT lock. It takes a while "
"for PLL1 to lock. Lock status is shown on LED.\r\n");
}
// check pll2 lock status
Status = lmk04828_read(lmk04828_inst, 0x0183, &Lmk04828Read);
if ((Lmk04828Read & 0x02) == 0x02) {
DBG_INFO("HDWR: [LMK04828] PLL2 Locked.\r\n");
}
else {
DBG_INFO("HDWR: [LMK04828] PLL2 NOT lock!\r\n");
}
#endif
#ifdef LMX2594_ADC
/**********************************************************/
/************* LMX2594 for ADC Configuration **************/
/**********************************************************/
Status = lmx2594_init(&lmx2594_adc_inst, &lmx2594_adc_init_param);
for(int i = 0; i < lmx2594_default_config_len; i++)
{
Status = lmx2594_write(lmx2594_adc_inst,
lmx2594_default_config[i].addr, lmx2594_default_config[i].value);
if (lmx2594_default_config[i].addr == 0)
{
mdelay(500);
}
}
uint16_t Lmx2594AdcRead;
// check vco lock status
Status = lmx2594_read(lmx2594_adc_inst, 110, &Lmx2594AdcRead);
if (((Lmx2594AdcRead >> 9) & 0x0003) == 0x0002) {
DBG_INFO("HDWR: [ADC LMX2594] Config Done.\r\n");
}
else {
DBG_INFO("HDWR: [ADC LMX2594] not lock!\r\n");
}
// set mux out to lock status
Status = lmx2594_write(lmx2594_adc_inst, 0x00, 0x259C);
DBG_INFO("HDWR: [ADC LMX2594] SPI readback disabled, "
"lock status is shown on LED.\r\n");
#endif
#ifdef LMX2594_DAC
/**********************************************************/
/************* LMX2594 for DAC Configuration **************/
/**********************************************************/
Status = lmx2594_init(&lmx2594_dac_inst, &lmx2594_dac_init_param);
for(int i = 0; i < lmx2594_default_config_len; i++)
{
Status = lmx2594_write(lmx2594_dac_inst,
lmx2594_default_config[i].addr, lmx2594_default_config[i].value);
if (lmx2594_default_config[i].addr == 0)
{
mdelay(500);
}
}
uint16_t Lmx2594DacRead;
// check vco lock status
Status = lmx2594_read(lmx2594_dac_inst, 110, &Lmx2594DacRead);
if (((Lmx2594DacRead >> 9) & 0x0003) == 0x0002) {
DBG_INFO("HDWR: [DAC LMX2594] Config Done.\r\n");
}
else {
DBG_INFO("HDWR: [DAC LMX2594] not lock!\r\n");
}
// set mux out to lock status
Status = lmx2594_write(lmx2594_dac_inst, 0x00, 0x259C);
DBG_INFO("HDWR: [DAC LMX2594] SPI readback disabled, "
"lock status is shown on LED.\r\n");
#endif
#if defined(AD9361_API) || defined(AD9361_REG)
/**********************************************************/
/***************** AD9361-1 Configuration *****************/
/**********************************************************/
XGpioPs_SetDirectionPin(&Gpio, AD9361_1_TXNRX, AD9361_GPIO_OUTPUT);
XGpioPs_SetDirectionPin(&Gpio, AD9361_1_ENABLE, AD9361_GPIO_OUTPUT);
XGpioPs_SetDirectionPin(&Gpio, AD9361_1_EN_AGC, AD9361_GPIO_OUTPUT);
XGpioPs_SetDirectionPin(&Gpio, AD9361_1_RESET_B, AD9361_GPIO_OUTPUT);
#ifdef AD9361_REG
ad9361_reg_init(&ad9361_1_reg_inst, &ad9361_1_reg_default_init_param);
XGpioPs_WritePin(&Gpio, AD9361_1_ENABLE, 0);
ad9361_1_reg_config(ad9361_1_reg_inst);
XGpioPs_WritePin(&Gpio, AD9361_1_ENABLE, 1);
#endif
#ifdef AD9361_API
Status = ad9361_init(&ad9361_phy, &ad9361_default_init_param);
if (Status != XST_SUCCESS){
DBG_ERROR("HDWR: ad9361_init() error: %" PRId32 "\n", Status);
return XST_FAILURE;
}
ad9361_set_tx_fir_config(ad9361_phy, tx_fir_config);
ad9361_set_rx_fir_config(ad9361_phy, rx_fir_config);
#endif
/**********************************************************/
/***************** AD9361-2 Configuration *****************/
/**********************************************************/
XGpioPs_SetDirectionPin(&Gpio, AD9361_2_TXNRX, AD9361_GPIO_OUTPUT);
XGpioPs_SetDirectionPin(&Gpio, AD9361_2_ENABLE, AD9361_GPIO_OUTPUT);
XGpioPs_SetDirectionPin(&Gpio, AD9361_2_EN_AGC, AD9361_GPIO_OUTPUT);
XGpioPs_SetDirectionPin(&Gpio, AD9361_2_RESET_B, AD9361_GPIO_OUTPUT);
ad9361_reg_init(&ad9361_2_reg_inst, &ad9361_2_reg_default_init_param);
XGpioPs_WritePin(&Gpio, AD9361_2_ENABLE, 0);
ad9361_2_reg_config(ad9361_2_reg_inst);
XGpioPs_WritePin(&Gpio, AD9361_2_ENABLE, 1);
// uint8_t rd_back;
// Status = ad9361_reg_read(ad9361_1_reg_inst, 0x0002, &rd_back);
// Status = ad9361_reg_read(ad9361_2_reg_inst, 0x0002, &rd_back);
// /**********************************************************/
// /******* AD9361 Baseband Multichip Synchronization ********/
// /**********************************************************/
// XGpioPs_SetDirectionPin(&Gpio, AD9361_SYNC, AD9361_GPIO_OUTPUT);
// XGpioPs_SetDirectionPin(&Gpio, AD9361_RX_FIFO_RST, AD9361_GPIO_OUTPUT);
//
// // SYNC BBPLL and DIGITAL SAMPLING CLOCKS
// ad9361_reg_write(ad9361_1_reg_inst, 0x0001, 0x0D); // MCS RF Enable; MCS BBPLL Enable; MCS BB Enable
// ad9361_reg_write(ad9361_2_reg_inst, 0x0001, 0x0D);
// ad9361_reg_write(ad9361_1_reg_inst, 0x0047, 0x80); // MCS refclk Scale Enable
// ad9361_reg_write(ad9361_2_reg_inst, 0x0047, 0x80);
// XGpioPs_WritePin(&Gpio, AD9361_SYNC, 0);
// mdelay(20);
// XGpioPs_WritePin(&Gpio, AD9361_SYNC, 1); // Input a rising-edge pulse to the SYNC_IN pin
// mdelay(500);
// XGpioPs_WritePin(&Gpio, AD9361_SYNC, 0);
// mdelay(2000);
// ad9361_reg_write(ad9361_1_reg_inst, 0x0001, 0x0B); // MCS RF Enable; MCS Digital CLK Enable ; MCS BB Enable
// ad9361_reg_write(ad9361_2_reg_inst, 0x0001, 0x0B);
// XGpioPs_WritePin(&Gpio, AD9361_SYNC, 1); // Input another rising-edge pulse to the SYNC_IN pin
// mdelay(500);
// XGpioPs_WritePin(&Gpio, AD9361_SYNC, 0);
// ad9361_reg_write(ad9361_1_reg_inst, 0x0001, 0x08); // clear MCS bits
// ad9361_reg_write(ad9361_2_reg_inst, 0x0001, 0x08);
//
// XGpioPs_WritePin(&Gpio, AD9361_RX_FIFO_RST, 0);
// mdelay(20);
// XGpioPs_WritePin(&Gpio, AD9361_RX_FIFO_RST, 1);
// mdelay(20);
// XGpioPs_WritePin(&Gpio, AD9361_RX_FIFO_RST, 0);
//
// /**********************************************************/
// /********* AD9361 Multichip Rx Phase Calibration **********/
// /**********************************************************/
// XGpioPs_SetDirectionPin(&Gpio, AD9361_TX_SWITCH, AD9361_GPIO_OUTPUT);
// XGpioPs_SetDirectionPin(&Gpio, AD9361_1_CAL_START, AD9361_GPIO_OUTPUT);
// XGpioPs_SetDirectionPin(&Gpio, AD9361_1_CAL_DONE, AD9361_GPIO_INPUT);
// XGpioPs_SetDirectionPin(&Gpio, AD9361_2_CAL_START, AD9361_GPIO_OUTPUT);
// XGpioPs_SetDirectionPin(&Gpio, AD9361_2_CAL_DONE, AD9361_GPIO_INPUT);
//
// // switch to lower frequency
// Status = Hardware_SwitchFreq(ad9361_1_reg_inst, TX_FREQ_126);
// XGpioPs_WritePin(&Gpio, AD9361_TX_SWITCH, 1);
// mdelay(20);
//
// // switch rx channel
// Status = ad9361_reg_write(ad9361_1_reg_inst, 0x0004, 0x30);
// Status = ad9361_reg_write(ad9361_2_reg_inst, 0x0004, 0x30);
//
// // enable dual ad9361 tx channels
// Status = ad9361_reg_write(ad9361_1_reg_inst, 0x0002, 0xE4); // Setup Tx Digital Filters/ Channels
//
// // switch ad9361 tx channel
// Status = ad9361_reg_write(ad9361_1_reg_inst, 0x0004, 0x70); // Select Rx input pin(A,B,C)/ Tx out pin (A,B)
// mdelay(20);
//
// // begin to calibrate the 1st ad9361
// XGpioPs_WritePin(&Gpio, AD9361_1_CAL_START, 0);
// XGpioPs_WritePin(&Gpio, AD9361_1_CAL_START, 1);
// mdelay(1);
// XGpioPs_WritePin(&Gpio, AD9361_1_CAL_START, 0);
//
// // read calibration status
// int32_t time_out_cnt = 0;
// do
// {
// mdelay(1); // Wait 1ms
// time_out_cnt++;
// } while (((XGpioPs_ReadPin(&Gpio, AD9361_1_CAL_DONE) == 0) && time_out_cnt <= AD9361_TIMEOUT_TH));
//
// if (time_out_cnt == AD9361_TIMEOUT_TH)
// {
// return FAILURE;
// }
//
// // begin to calibrate the 2nd ad9361
// XGpioPs_WritePin(&Gpio, AD9361_2_CAL_START, 1);
// mdelay(1);
// XGpioPs_WritePin(&Gpio, AD9361_2_CAL_START, 0);
//
// // read calibration status
// time_out_cnt = 0;
// do
// {
// mdelay(1); // Wait 1ms
// time_out_cnt++;
// } while (((XGpioPs_ReadPin(&Gpio, AD9361_2_CAL_DONE) == 0) && time_out_cnt <= AD9361_TIMEOUT_TH));
//
// if (time_out_cnt == AD9361_TIMEOUT_TH)
// {
// return FAILURE;
// }
//
// // enable single ad9361 tx channels
// Status = ad9361_reg_write(ad9361_1_reg_inst, 0x0002, 0xA4); // Setup Tx Digital Filters/ Channels
//
// // switch ad9361 tx & rx channel
// Status = ad9361_reg_write(ad9361_1_reg_inst, 0x0004, 0x03);
// Status = ad9361_reg_write(ad9361_2_reg_inst, 0x0004, 0x03);
//
// // switch to higher frequency
// Status = Hardware_SwitchFreq(ad9361_1_reg_inst, TX_FREQ_4125);
// XGpioPs_WritePin(&Gpio, AD9361_TX_SWITCH, 0);
//
Status = ad9361_reg_write(ad9361_1_reg_inst, 0x0109, 0x14); // Rx Gain
Status = ad9361_reg_write(ad9361_1_reg_inst, 0x010C, 0x14); // Rx Gain
Status = ad9361_reg_write(ad9361_2_reg_inst, 0x0109, 0x14); // Rx Gain
Status = ad9361_reg_write(ad9361_2_reg_inst, 0x010C, 0x14); // Rx Gain
#endif
#ifdef AD9653
Status = ad9653_init(&ad9653_inst, &ad9653_default_init_param);
for(int i = 0; i < ad9653_default_config_len; i++){
Status = ad9653_write(ad9653_inst, ad9653_default_config[i].addr,
ad9653_default_config[i].value);
if (ad9653_default_config[i].addr == 0x0000){
mdelay(500);
}
}
#endif
#ifdef AD9694
/**********************************************************/
/****************** AD9694 Configuration ******************/
/**********************************************************/
Status = ad9694_init(&ad9694_inst, &ad9694_default_init_param);
for(int i = 0; i < ad9694_default_config_len; i++){
Status = ad9694_write(ad9694_inst, ad9694_default_config[i].addr, ad9694_default_config[i].value);
if (ad9694_default_config[i].addr == 0x0000){
mdelay(500);
}
}
// uint8_t reg0008;
// uint8_t reg056F;
// uint8_t reg0571;
//
// ad9694_read(ad9694_inst,0x008,&reg0008);
// ad9694_read(ad9694_inst,0x56F,&reg056F);
// ad9694_read(ad9694_inst,0x571,&reg0571);
#endif
#ifdef RFSOC
/*
* DAC Mapping:
* Number Tile Block
* 1 (VOUT_00) 228 (XRFDC_TILE_ID0) DAC 0/DUC 0 (XRFDC_BLK_ID0)
* 2 (VOUT_02) 228 (XRFDC_TILE_ID0) DAC 1/DUC 2 (XRFDC_BLK_ID2)
* 3 (VOUT_10) 229 (XRFDC_TILE_ID1) DAC 1/DUC 0 (XRFDC_BLK_ID0)
* 4 (VOUT_12) 229 (XRFDC_TILE_ID1) DAC 1/DUC 2 (XRFDC_BLK_ID2)
* 5 (VOUT_20) 230 (XRFDC_TILE_ID2) DAC 0/DUC 0 (XRFDC_BLK_ID0)
* 6 (VOUT_22) 230 (XRFDC_TILE_ID2) DAC 1/DUC 2 (XRFDC_BLK_ID2)
* 7 (VOUT_30) 231 (XRFDC_TILE_ID3) DAC 0/DUC 0 (XRFDC_BLK_ID0)
* 8 (VOUT_32) 231 (XRFDC_TILE_ID3) DAC 1/DUC 2 (XRFDC_BLK_ID2)
*
*/
// get & set mixer settings
XRFdc_Mixer_Settings Mixer_Settings_DAC;
// 3th channel
Status = XRFdc_GetMixerSettings(&RFdc, XRFDC_DAC_TILE, XRFDC_TILE_ID1,
XRFDC_BLK_ID0, &Mixer_Settings_DAC);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
Mixer_Settings_DAC.Freq = 1500;
Status = XRFdc_SetMixerSettings(&RFdc, XRFDC_DAC_TILE, XRFDC_TILE_ID1,
XRFDC_BLK_ID0, &Mixer_Settings_DAC);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
mdelay(100);
Status = XRFdc_UpdateEvent(&RFdc, XRFDC_DAC_TILE, XRFDC_TILE_ID1,
XRFDC_BLK_ID0, XRFDC_EVENT_MIXER);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* ADC Mapping:
* Number Tile Block
* 1 (VIN0_01) 224 (XRFDC_TILE_ID0) ADC 0 (XRFDC_BLK_ID0)
* 2 (VIN0_12) 224 (XRFDC_TILE_ID0) ADC 1 (XRFDC_BLK_ID1)
* 3 (VIN1_01) 225 (XRFDC_TILE_ID1) ADC 0 (XRFDC_BLK_ID0)
* 4 (VIN1_23) 225 (XRFDC_TILE_ID1) ADC 1 (XRFDC_BLK_ID1)
* 5 (VIN2_01) 226 (XRFDC_TILE_ID2) ADC 0 (XRFDC_BLK_ID0)
* 6 (VIN2_23) 227 (XRFDC_TILE_ID2) ADC 1 (XRFDC_BLK_ID1)
* 7 (VIN3_01) 224 (XRFDC_TILE_ID0) ADC 0 (XRFDC_BLK_ID0)
* 8 (VIN3_23) 227 (XRFDC_TILE_ID3) ADC 1 (XRFDC_BLK_ID1)
*
*/
// get & set mixer settings
XRFdc_Mixer_Settings Mixer_Settings_ADC;
// 3rd channel
Status = XRFdc_GetMixerSettings(&RFdc, XRFDC_ADC_TILE, XRFDC_TILE_ID1,
XRFDC_BLK_ID0, &Mixer_Settings_ADC);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
Mixer_Settings_ADC.Freq = 1500;
Mixer_Settings_ADC.EventSource = XRFDC_EVNT_SRC_TILE;
Status = XRFdc_SetMixerSettings(&RFdc, XRFDC_ADC_TILE, XRFDC_TILE_ID1,
XRFDC_BLK_ID0, &Mixer_Settings_ADC);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
mdelay(100);
Status = XRFdc_UpdateEvent(&RFdc, XRFDC_ADC_TILE, XRFDC_TILE_ID1,
XRFDC_BLK_ID0, XRFDC_EVENT_MIXER);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
#endif
DBG_INFO("HDWR: Configuration Done.\n");
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Hardware_SwitchFreq
*
* @param devSysMonitor_UpdateHardwareStatus(newHwState);
* @param freq
*
* @return None.
*
******************************************************************************/
int32_t Hardware_SwitchFreq(struct ad9361_reg_dev *dev, ad9361TxFreq freq)
{
int32_t status = 0;
uint8_t value = 0;
int32_t time_out_cnt = 0;
switch (freq)
{
case TX_FREQ_125:
{
//************************************************************
// Setup Tx Frequency-Dependent Syntheisizer Registers
//************************************************************
status = ad9361_reg_write(dev, 0x027A, 0x4A); // Set VCO Output level[3:0]
status = ad9361_reg_write(dev, 0x0279, 0xC1); // Set Init ALC Value[3:0] and VCO Varactor[3:0]
status = ad9361_reg_write(dev, 0x0282, 0x0E); // Set VCO Bias Tcf[1:0] and VCO Bias Ref[2:0]
status = ad9361_reg_write(dev, 0x0278, 0x78); // Set VCO Cal Offset[3:0]
status = ad9361_reg_write(dev, 0x0285, 0x00); // Set VCO Cal Ref Tcf[2:0]
status = ad9361_reg_write(dev, 0x0291, 0x0B); // Set VCO Varactor Reference[3:0]
status = ad9361_reg_write(dev, 0x0290, 0x70); // Set VCO Varactor Ref Tcf[2:0] and VCO Varactor Offset[3:0]
status = ad9361_reg_write(dev, 0x027B, 0x94); // Set Synth Loop Filter charge pump current (Icp)
status = ad9361_reg_write(dev, 0x027E, 0xF4); // Set Synth Loop Filter C2 and C1
status = ad9361_reg_write(dev, 0x027F, 0xDF); // Set Synth Loop Filter R1 and C3
status = ad9361_reg_write(dev, 0x0280, 0x0A); // Set Synth Loop Filter R3
//************************************************************
// Write Tx Frequency Words
//************************************************************
status = ad9361_reg_write(dev, 0x0273, 0x00); // Write Tx Synth Fractional Freq Word[7:0]
status = ad9361_reg_write(dev, 0x0274, 0x00); // Write Tx Synth Fractional Freq Word[15:8]
status = ad9361_reg_write(dev, 0x0275, 0x00); // Write Tx Synth Fractional Freq Word[22:16]
status = ad9361_reg_write(dev, 0x0272, 0x00); // Write Tx Synth Integer Freq Word[10:8]
status = ad9361_reg_write(dev, 0x0271, 0xA0); // Write Tx Synth Integer Freq Word[7:0] (starts VCO cal)
status = ad9361_reg_write(dev, 0x0005, 0x57); // Set LO divider setting
//************************************************************
// Tx Quadrature Calibration Settings
//************************************************************
status = ad9361_reg_write(dev, 0x00A0, 0x75); // Set TxQuadcal NCO frequency
status = ad9361_reg_write(dev, 0x00A3, 0xC0); // Set TxQuadcal NCO frequency (Only update bits [7:6])
status = ad9361_reg_write(dev, 0x00A1, 0x7B); // Tx Quad Cal Configuration, Phase and Gain Cal Enable
status = ad9361_reg_write(dev, 0x00A9, 0xFF); // Set Tx Quad Cal Count
status = ad9361_reg_write(dev, 0x00A2, 0x7F); // Set Tx Quad Cal Kexp
status = ad9361_reg_write(dev, 0x00A5, 0x01); // Set Tx Quad Cal Magnitude Threshhold
status = ad9361_reg_write(dev, 0x00A6, 0x01); // Set Tx Quad Cal Magnitude Threshhold
status = ad9361_reg_write(dev, 0x00AA, 0x22); // Set Tx Quad Cal Gain Table index
status = ad9361_reg_write(dev, 0x00A4, 0xF0); // Set Tx Quad Cal Settle Count
status = ad9361_reg_write(dev, 0x00AE, 0x00); // Set Tx Quad Cal LPF Gain index incase Split table mode used
status = ad9361_reg_write(dev, 0x0169, 0xC0); // Disable Rx Quadrature Calibration before Running Tx Quadrature Calibration
status = ad9361_reg_write(dev, 0x0016, 0x10); // Start Tx Quad cal
break;
}
case TX_FREQ_126:
{
//************************************************************
// Setup Tx Frequency-Dependent Syntheisizer Registers
//************************************************************
status = ad9361_reg_write(dev, 0x027A, 0x4A); // Set VCO Output level[3:0]
status = ad9361_reg_write(dev, 0x0279, 0xC1); // Set Init ALC Value[3:0] and VCO Varactor[3:0]
status = ad9361_reg_write(dev, 0x0282, 0x0E); // Set VCO Bias Tcf[1:0] and VCO Bias Ref[2:0]
status = ad9361_reg_write(dev, 0x0278, 0x78); // Set VCO Cal Offset[3:0]
status = ad9361_reg_write(dev, 0x0285, 0x00); // Set VCO Cal Ref Tcf[2:0]
status = ad9361_reg_write(dev, 0x0291, 0x0B); // Set VCO Varactor Reference[3:0]
status = ad9361_reg_write(dev, 0x0290, 0x70); // Set VCO Varactor Ref Tcf[2:0] and VCO Varactor Offset[3:0]
status = ad9361_reg_write(dev, 0x027B, 0x93); // Set Synth Loop Filter charge pump current (Icp)
status = ad9361_reg_write(dev, 0x027E, 0xF4); // Set Synth Loop Filter C2 and C1
status = ad9361_reg_write(dev, 0x027F, 0xDF); // Set Synth Loop Filter R1 and C3
status = ad9361_reg_write(dev, 0x0280, 0x0A); // Set Synth Loop Filter R3
//************************************************************
// Write Tx Frequency Words
//************************************************************
status = ad9361_reg_write(dev, 0x0273, 0x06); // Write Tx Synth Fractional Freq Word[7:0]
status = ad9361_reg_write(dev, 0x0274, 0xD7); // Write Tx Synth Fractional Freq Word[15:8]
status = ad9361_reg_write(dev, 0x0275, 0x23); // Write Tx Synth Fractional Freq Word[22:16]
status = ad9361_reg_write(dev, 0x0272, 0x00); // Write Tx Synth Integer Freq Word[10:8]
status = ad9361_reg_write(dev, 0x0271, 0xA1); // Write Tx Synth Integer Freq Word[7:0] (starts VCO cal)
status = ad9361_reg_write(dev, 0x0005, 0x57); // Set LO divider setting
//************************************************************
// Tx Quadrature Calibration Settings
//************************************************************
status = ad9361_reg_write(dev, 0x00A0, 0x75); // Set TxQuadcal NCO frequency
status = ad9361_reg_write(dev, 0x00A3, 0xC0); // Set TxQuadcal NCO frequency (Only update bits [7:6])
status = ad9361_reg_write(dev, 0x00A1, 0x7B); // Tx Quad Cal Configuration, Phase and Gain Cal Enable
status = ad9361_reg_write(dev, 0x00A9, 0xFF); // Set Tx Quad Cal Count
status = ad9361_reg_write(dev, 0x00A2, 0x7F); // Set Tx Quad Cal Kexp
status = ad9361_reg_write(dev, 0x00A5, 0x01); // Set Tx Quad Cal Magnitude Threshhold
status = ad9361_reg_write(dev, 0x00A6, 0x01); // Set Tx Quad Cal Magnitude Threshhold
status = ad9361_reg_write(dev, 0x00AA, 0x22); // Set Tx Quad Cal Gain Table index
status = ad9361_reg_write(dev, 0x00A4, 0xF0); // Set Tx Quad Cal Settle Count
status = ad9361_reg_write(dev, 0x00AE, 0x00); // Set Tx Quad Cal LPF Gain index incase Split table mode used
status = ad9361_reg_write(dev, 0x0169, 0xC0); // Disable Rx Quadrature Calibration before Running Tx Quadrature Calibration
status = ad9361_reg_write(dev, 0x0016, 0x10); // Start Tx Quad cal
break;
}
case TX_FREQ_4125:
{
//************************************************************
// Setup Tx Frequency-Dependent Syntheisizer Registers
//************************************************************
status = ad9361_reg_write(dev, 0x027A, 0x4A); // Set VCO Output level[3:0]
status = ad9361_reg_write(dev, 0x0279, 0xC1); // Set Init ALC Value[3:0] and VCO Varactor[3:0]
status = ad9361_reg_write(dev, 0x0282, 0x0E); // Set VCO Bias Tcf[1:0] and VCO Bias Ref[2:0]
status = ad9361_reg_write(dev, 0x0278, 0x78); // Set VCO Cal Offset[3:0]
status = ad9361_reg_write(dev, 0x0285, 0x00); // Set VCO Cal Ref Tcf[2:0]
status = ad9361_reg_write(dev, 0x0291, 0x0B); // Set VCO Varactor Reference[3:0]
status = ad9361_reg_write(dev, 0x0290, 0x70); // Set VCO Varactor Ref Tcf[2:0] and VCO Varactor Offset[3:0]
status = ad9361_reg_write(dev, 0x027B, 0x93); // Set Synth Loop Filter charge pump current (Icp)
status = ad9361_reg_write(dev, 0x027E, 0xF4); // Set Synth Loop Filter C2 and C1
status = ad9361_reg_write(dev, 0x027F, 0xDF); // Set Synth Loop Filter R1 and C3
status = ad9361_reg_write(dev, 0x0280, 0x0A); // Set Synth Loop Filter R3
//************************************************************
// Write Rx Frequency Words
//************************************************************
status = ad9361_reg_write(dev, 0x0273, 0x00); // Write Tx Synth Fractional Freq Word[7:0]
status = ad9361_reg_write(dev, 0x0274, 0x00); // Write Tx Synth Fractional Freq Word[15:8]
status = ad9361_reg_write(dev, 0x0275, 0x00); // Write Tx Synth Fractional Freq Word[22:16]
status = ad9361_reg_write(dev, 0x0272, 0x00); // Write Tx Synth Integer Freq Word[10:8]
status = ad9361_reg_write(dev, 0x0271, 0xA5); // Write Tx Synth Integer Freq Word[7:0] (starts VCO cal)
status = ad9361_reg_write(dev, 0x0005, 0x07); // Set LO divider setting
//************************************************************
// Tx Quadrature Calibration Settings
//************************************************************
status = ad9361_reg_write(dev, 0x00A0, 0x75); // Set TxQuadcal NCO frequency
status = ad9361_reg_write(dev, 0x00A3, 0xC0); // Set TxQuadcal NCO frequency (Only update bits [7:6])
status = ad9361_reg_write(dev, 0x00A1, 0x7B); // Tx Quad Cal Configuration, Phase and Gain Cal Enable
status = ad9361_reg_write(dev, 0x00A9, 0xFF); // Set Tx Quad Cal Count
status = ad9361_reg_write(dev, 0x00A2, 0x7F); // Set Tx Quad Cal Kexp
status = ad9361_reg_write(dev, 0x00A5, 0x01); // Set Tx Quad Cal Magnitude Threshhold
status = ad9361_reg_write(dev, 0x00A6, 0x01); // Set Tx Quad Cal Magnitude Threshhold
status = ad9361_reg_write(dev, 0x00AA, 0x28); // Set Tx Quad Cal Gain Table index
status = ad9361_reg_write(dev, 0x00A4, 0xF0); // Set Tx Quad Cal Settle Count
status = ad9361_reg_write(dev, 0x00AE, 0x04); // Set Tx Quad Cal LPF Gain index incase Split table mode used
status = ad9361_reg_write(dev, 0x0169, 0xC0); // Disable Rx Quadrature Calibration before Running Tx Quadrature Calibration
status = ad9361_reg_write(dev, 0x0016, 0x10); // Start Tx Quad cal
break;
}
// Wait for cal to complete (Done when 0x016[4]==0)
time_out_cnt = 0;
do
{
status |= ad9361_reg_read(dev, 0x0016, &value);
mdelay(1); // Wait 1ms
time_out_cnt++;
} while ((value & 0x10) != 0x00 && time_out_cnt <= AD9361_TIMEOUT_TH);
}
return status;
}
// @ Get AD9361 - 1 temperature (Celsius Degree)
/**
* Read corresponding register to get AD9361 - 1 current temperature.
*/
int8_t Hardware_GetAD9361Temp_1(void)
{
int8_t scaleTemp;
double temp;
ad9361_reg_write(ad9361_1_reg_inst, 0x000B, -64);
ad9361_reg_write(ad9361_1_reg_inst, 0x001D, 0x01); // disable aux adc
ad9361_reg_read(ad9361_1_reg_inst, 0x000E, (uint8_t*)&scaleTemp);
ad9361_reg_write(ad9361_1_reg_inst, 0x001D, 0x00); // enable aux adc
temp = ((double)scaleTemp + 64)/1.16;
return ((temp > INT8_MAX) ? INT8_MAX : (int8_t)temp);
}
// @ Get AD9361 - 2 temperature (Celsius Degree)
/**
* Read corresponding register to get AD9361 - 2 current temperature.
*/
int8_t Hardware_GetAD9361Temp_2(void)
{
int8_t scaleTemp;
double temp;
ad9361_reg_write(ad9361_2_reg_inst, 0x000B, -64);
ad9361_reg_write(ad9361_2_reg_inst, 0x001D, 0x01); // disable aux adc
ad9361_reg_read(ad9361_2_reg_inst, 0x000E, (uint8_t*)&scaleTemp);
ad9361_reg_write(ad9361_2_reg_inst, 0x001D, 0x00); // enable aux adc
temp = ((double)scaleTemp + 64)/1.16;
return ((temp > INT8_MAX) ? INT8_MAX : (int8_t)temp);
}
// @ Determine AD9361 lock state
/**
* Read corresponding register to determine AD9361(both) lock state.
*/
uint8_t Hardware_GetAD9361LockStatus(void)
{
uint8_t ret = 0;
uint8_t regVal;
// bbpll
ad9361_reg_read(ad9361_1_reg_inst, 0x005E, &regVal); // [D7] is lock indicator
ret |= ((regVal & 0x80) == 0x80) ? CLK_AD0_BBPLL_LOCK : 0;
ad9361_reg_read(ad9361_2_reg_inst, 0x005E, &regVal); // [D7] is lock indicator
ret |= ((regVal & 0x80) == 0x80) ? CLK_AD1_BBPLL_LOCK : 0;
// rfpll
ad9361_reg_read(ad9361_1_reg_inst, 0x0287, &regVal); // [D1] is lock indicator
ret |= ((regVal & 0x02) == 0x02) ? CLK_AD0_RFPLL_LOCK : 0;
ad9361_reg_read(ad9361_2_reg_inst, 0x0287, &regVal); // [D1] is lock indicator
ret |= ((regVal & 0x02) == 0x02) ? CLK_AD1_RFPLL_LOCK : 0;
return ret;
}
// @ Determine HMC7044 lock state
/**
* Read corresponding register to determine clock lock state.
*/
uint8_t Hardware_GetHMC7044LockStatus(void)
{
uint8_t ret = 0;
uint8_t regVal;
// pll1
hmc7044_read(hmc7044_inst, 0x007C, &regVal); // [D5] is lock indicator
ret |= ((regVal & 0xE0) != 0x00) ? CLK_SP_PLL0_LOCK : 0;
// pll2
hmc7044_read(hmc7044_inst, 0x007D, &regVal); // [D0] is lock indicator
ret |= ((regVal & 0x01) == 0x01) ? CLK_SP_PLL1_LOCK : 0;
return ret;
}
@@ -0,0 +1,32 @@
/*****************************************************************************/
/**
* Description: hwconfig.h
*
* Date: 2024-02-20 13:19
* Last Edit Time: [2024-02-20 13:19]
*
* Revisions: Rev 0.0
* History:
* [2023-05-07]: Initial edition.
*
* Copyright(c) 2024 Beijing Institute of Technology.
*
******************************************************************************/
/***************************** Include Files *********************************/
// Standard
#include <stdint.h>
#include "config/app_config.h"
#include "drivers/rf-transceiver/ad9361_reg/ad9361_reg.h"
#include "drivers/rf-transceiver/ad9361/ad9361_api.h"
/************************** Function Prototypes ******************************/
int32_t Hardware_Init(void);
int32_t Hardware_SwitchFreq(struct ad9361_reg_dev *dev, ad9361TxFreq freq);
int8_t Hardware_GetAD9361Temp_1(void);
int8_t Hardware_GetAD9361Temp_2(void);
uint8_t Hardware_GetAD9361LockStatus(void);
uint8_t Hardware_GetHMC7044LockStatus(void);
@@ -0,0 +1,59 @@
/***************************************************************************//**
* @file axi_io.h
* @brief Header file of AXI IO.
* @author Antoniu Miclaus (antoniu.miclaus@analog.com)
********************************************************************************
* Copyright 2019(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
*******************************************************************************/
#ifndef _AXI_IO_H_
#define _AXI_IO_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdint.h>
/******************************************************************************/
/************************ Functions Declarations ******************************/
/******************************************************************************/
/* AXI IO Read data */
int32_t axi_io_read(uint32_t base, uint32_t offset, uint32_t *data);
/* AXI IO Write data */
int32_t axi_io_write(uint32_t base, uint32_t offset, uint32_t data);
#endif // _AXI_IO_H_
@@ -0,0 +1,100 @@
/*****************************************************************************/
/**
* @file circ_queue.h
* @author FanHao (hao_fan_bit_ee@163.com)
* @brief A simple circular FIFO bounded queue
* @version 0.1
* @date 2023-02-23
* @note Forked from https://github.com/chrismerck/rpa_queue.git
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
* Lab of Communication and Network
*
******************************************************************************/
/**
* @addtogroup Utility
* @{
*/
/**
* @defgroup CircularQueue
* @{
*/
#ifndef CIRC_QUEUE_H
#define CIRC_QUEUE_H
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
/**
* @struct CIRC_QUEUE
* @brief Circular queue Instance
*/
typedef struct
{
void **data;
volatile uint32_t nelts; ///< number of elements
uint32_t in; ///< next empty location
uint32_t out; ///< next filled location
uint32_t bounds; ///< max size of queue
} CIRC_QUEUE;
/**
* @brief create a FIFO queue
* @param queue The new queue
* @param queue_capacity maximum size of the queue
*/
bool CircQueueCreate(CIRC_QUEUE **queue, uint32_t queue_capacity);
/**
* @brief free queue memory -- call after destroy
*/
void CircQueueFree(CIRC_QUEUE *queue);
/**
* @brief Detects when the CIRC_QUEUE is full. This utility function is expected
* to be called from within critical sections, and is not threadsafe.
*/
bool isCircQueueFull(CIRC_QUEUE *queue);
/**
* @brief Detects when the CIRC_QUEUE is empty. This utility function is expected
* to be called from within critical sections, and is not threadsafe.
*/
bool isCircQueueEmpty(CIRC_QUEUE *queue);
/**
* @brief push/add an object to the queue, blocking if the queue is already full
*
* @param queue the queue
* @param data the data
* @return True on a successful push
* @return False push failed
*/
bool CircQueuePush(CIRC_QUEUE *queue, void *data);
/**
* @brief pop/get an object from the queue, blocking if the queue is already empty
*
* @param queue the queue
* @param data the data
* @return false pop failed
* @return true on a successful pop
*/
bool CircQueuePop(CIRC_QUEUE *queue, void **data);
/**
* @brief returns the size of the queue.
*
* @param queue the queue
* @return the size of the queue
*/
uint32_t CircQueueSize(CIRC_QUEUE *queue);
#endif /* CIRC_QUEUE_H */
/** @} CircularQueue*/
/** @} Utility*/
@@ -0,0 +1,138 @@
/*****************************************************************************/
/**
* @file clist.h
* @author FanHao (hao_fan_bit_ee@163.com)
* @brief A basic list data structure
* @version 0.1
* @date 2023-02-23
* @note Forked from https://github.com/clibs/list
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
* Lab of Communication and Network
*
******************************************************************************/
/**
* @addtogroup Utility
* @{
*/
/**
* @defgroup cList
* @{
*/
#ifndef __CLIST_H__
#define __CLIST_H__
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdlib.h>
#include <stdint.h>
/**
* @enum clist_direction_t
* @brief clist_t iterator direction.
*/
typedef enum
{
LIST_HEAD,
LIST_TAIL
} clist_direction_t;
/**
* @struct clist_node_t
* @brief clist_t node struct.
*/
typedef struct clist_node
{
struct clist_node *prev; ///< previous node
struct clist_node *next; ///< next node
void *val;
} clist_node_t;
/**
* @struct clist_t
* @brief clist_t struct.
*/
typedef struct
{
clist_node_t *head; ///< first node
clist_node_t *tail; ///< last node
uint32_t len; ///< list length
void (*free)(void *val); ///< node free function handle
int8_t (*compare)(void *a, void *b); ///< node compare function handle
} clist_t;
/**
* @struct clist_iterator_t
* @brief clist_t iterator struct.
*/
typedef struct
{
clist_node_t *next; ///< next element
clist_direction_t direction; ///< iter direction
} clist_iterator_t;
// Node prototypes.
clist_node_t *
clist_node_new(void *val);
// clist_t prototypes.
clist_t *
clist_new(void);
clist_node_t *
clist_rpush(clist_t *self, clist_node_t *node);
clist_node_t *
clist_lpush(clist_t *self, clist_node_t *node);
clist_node_t *
clist_find(clist_t *self, void *val);
clist_node_t *
clist_at(clist_t *self, int index);
clist_node_t *
clist_rpop(clist_t *self);
clist_node_t *
clist_lpop(clist_t *self);
void
clist_remove(clist_t *self, clist_node_t *node);
void
clist_clear(clist_t *self);
void
clist_destroy(clist_t *self);
// clist_t iterator prototypes.
clist_iterator_t *
clist_iterator_new(clist_t *list, clist_direction_t direction);
clist_iterator_t *
clist_iterator_new_from_node(clist_node_t *node, clist_direction_t direction);
clist_node_t *
clist_iterator_next(clist_iterator_t *self);
void
clist_iterator_destroy(clist_iterator_t *self);
#ifdef __cplusplus
}
#endif
#endif /* __CLIBS_LIST_H__ */
/** @} cList*/
/** @} Utility*/
@@ -0,0 +1,93 @@
/*****************************************************************************/
/**
* @file common.h
* @author FanHao (hao_fan_bit_ee@163.com)
* @brief Common macros
* @version 0.0
* @date 2022-07-16
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
* Lab of Communication and Network
*
******************************************************************************/
/**
* @defgroup COMMON_MACRO
* @{
*/
/***************************** Include Files *********************************/
#ifndef __COMMON_H_
#define __COMMON_H_
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include <inttypes.h>
#include <assert.h>
#include "util.h"
#include "error.h"
/************************** Constant Definitions *****************************/
/***************** Macros (Inline Functions) Definitions *********************/
#define __PRINT_BLOCK(block) \
do \
{ \
block \
} while (0)
#define ASSERT(exp) ((exp) ? (void)0 : AppAssert(__FILE__, __LINE__))
#define _nop_() __asm__("nop")
/* Stringify */
#define STR(x) #x
// #define _DEBUG_LEVEL 3
#if _DEBUG_LEVEL > 0
#define DBG_PRINT(...) printf(__VA_ARGS__)
#endif
#if _DEBUG_LEVEL >= 1
#define DBG_ERROR(...) __PRINT_BLOCK( \
printf("in "__FILE__ \
":%d [error]\t", \
__LINE__); \
printf(__VA_ARGS__);)
#endif
#if _DEBUG_LEVEL >= 2
#define DBG_WARNING(...) __PRINT_BLOCK( \
printf("[warning]\t"); \
printf(__VA_ARGS__);)
#endif
#if _DEBUG_LEVEL >= 3
#define DBG_INFO(...) __PRINT_BLOCK( \
printf("[Info]\t"); \
printf(__VA_ARGS__);)
#endif
#ifndef DBG_ERROR
#define DBG_ERROR(...) \
{ \
}
#endif
#ifndef DBG_WARNING
#define DBG_WARNING(...) \
{ \
}
#endif
#ifndef DBG_INFO
#define DBG_INFO(...) \
{ \
}
#endif
#ifndef DBG_PRINT
#define DBG_PRINT(...) \
{ \
}
#endif
/**************************** Type Definitions *******************************/
/************************** Variable Definitions *****************************/
/************************** Function Prototypes ******************************/
void AppAssert(const char *file, int line);
#endif /* __COMMON_H_ */
/** @} */
@@ -0,0 +1,70 @@
/***************************************************************************//**
* @file delay.h
* @brief Header file of Delay functions
* @author DBogdan (dragos.bogdan@analog.com)
********************************************************************************
* Copyright 2019(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
*******************************************************************************/
#ifndef _DELAY_H_
#define _DELAY_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdint.h>
/**
* @struct time
* @brief Structure holding time data (seconds, microseconds).
*/
struct time {
unsigned int s, us;
};
/******************************************************************************/
/************************ Functions Declarations ******************************/
/******************************************************************************/
/* Generate microseconds delay. */
void udelay(uint32_t usecs);
/* Generate miliseconds delay. */
void mdelay(uint32_t msecs);
/* Get current time */
struct time get_time(void);
#endif // _DELAY_H_
@@ -0,0 +1,56 @@
/*****************************************************************************/
/**
* @file common.h
* @author FanHao (hao_fan_bit_ee@163.com)
* @brief Common error numbers
* @version 0.0
* @date 2022-06-18
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
* Lab of Communication and Network
*
******************************************************************************/
/**
* @addtogroup COMMON_MACRO
* @{
*/
#ifndef SRC_ERROR_H_
#define SRC_ERROR_H_
#include <errno.h>
/******************************************************************************/
/********************** Macros and Constants Definitions **********************/
/******************************************************************************/
/**
* @name ERRORNO
* @{
*/
#ifdef SUCCESS
#undef SUCCESS
#endif
#define SUCCESS 0
#ifdef FAILURE
#undef FAILURE
#endif
#define FAILURE -1
#define EPARAM -2 /*!< Data crc check failed */
#define ECRC -3 /*!< Data crc check failed */
#define EDINVAL -4 /*!< Device is invalid (sleep or power off) */
#define EDCONF -5 /*!< Device configure error */
#define ETIMEOUT -6 /*!< Timeout error */
#define EIGNORE -7 /*!< Received an unsupported command, and ignore it */
#define EQUEUE -8 /*!< Queue overflow */
#define EUNEXP -9 /*!< Encounter an unexpected error */
#define IS_ERR_VALUE(x) ((x) != SUCCESS)
#endif // ERROR_H_
/** @} ERRORNO*/
/** @} COMMON_MACRO*/
@@ -0,0 +1,95 @@
#ifndef SRC_GLOBAL_TIMER_H_
#define SRC_GLOBAL_TIMER_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <inttypes.h>
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
/**
* @struct timer_init_param
* @brief Structure holding the parameters for timer initialization
*/
struct global_timer_init_param {
/** timer ID */
uintptr_t base_addr;
/** timer ID */
uint16_t id;
/** timer count frequency (Hz) */
uint32_t freq_hz;
/** counter start value */
uint64_t load_value;
};
/**
* @struct timer_desc
* @brief Structure holding timer descriptor
*/
struct global_timer_desc {
/** timer ID */
uintptr_t base_addr;
/** timer ID */
uint16_t id;
/** timer count frequency (Hz) */
uint32_t freq_hz;
/** counter start value */
uint64_t load_value;
};
/******************************************************************************/
/************************ Functions Declarations ******************************/
/******************************************************************************/
/* Initialize hardware timer and the handler structure associated with it. */
int32_t global_timer_init(struct global_timer_desc **desc,
struct global_timer_init_param *param);
/* Free the memory allocated by timer_setup(). */
int32_t global_timer_remove(struct global_timer_desc *desc);
/* Start a timer. */
int32_t global_timer_start(struct global_timer_desc *desc);
/* Stop a timer from counting. */
int32_t global_timer_stop(struct global_timer_desc *desc);
/* Get the value of the counter register for the timer. */
int32_t global_timer_counter_get(struct global_timer_desc *desc, uint64_t *counter);
/* Set the timer counter register value. */
int32_t global_timer_counter_set(struct global_timer_desc *desc, uint64_t new_val);
/* Get the timer clock frequency. */
int32_t global_timer_count_clk_get(struct global_timer_desc *desc, uint32_t *freq_hz);
/* Set the timer clock frequency. */
int32_t global_timer_count_clk_set(struct global_timer_desc *desc, uint32_t freq_hz);
/* Enable global timer interrupt. */
int32_t global_timer_irq_enable(struct global_timer_desc *desc);
/* Disable global timer interrupt. */
int32_t global_timer_irq_disable(struct global_timer_desc *desc);
/* Implement a acknowledgment global timer interrupt. */
int32_t global_timer_irq_ack(struct global_timer_desc *desc);
/* Set comparator register. */
int32_t global_timer_compara_set(struct global_timer_desc *desc, uint64_t com_val);
/* Set auto increment register . */
int32_t global_timer_auto_inc_set(struct global_timer_desc *desc, uint32_t inc_val);
/* Enable global timer auto increment mode. */
int32_t global_timer_auto_inc_enable(struct global_timer_desc *desc);
/* Disable global timer auto increment mode. */
int32_t global_timer_auto_inc_disable(struct global_timer_desc *desc);
#endif /* SRC_TIMER_H_ */
@@ -0,0 +1,188 @@
/***************************************************************************//**
* @file gpio.h
* @brief Header file of GPIO Interface
* @author DBogdan (dragos.bogdan@analog.com)
********************************************************************************
* Copyright 2019(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
*******************************************************************************/
#ifndef _GPIO_H_
#define _GPIO_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdint.h>
/******************************************************************************/
/********************** Macros and Constants Definitions **********************/
/******************************************************************************/
#define GPIO_OUT 0x01
#define GPIO_IN 0x00
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
/**
* @struct gpio_platform_ops
* @brief Structure holding gpio function pointers that point to the platform
* specific function
*/
struct gpio_platform_ops ;
/**
* @enum gpio_pull_up
* @brief Enum that holds the possible pull up/ pull down resistor configuration.
*/
enum gpio_pull_up {
PULL_NONE,
/** Strong pull up */
PULL_UP,
/** Strong pull down */
PULL_DOWN,
PULL_UP_WEAK,
PULL_DOWN_WEAK
};
/**
* @struct gpio_init_param
* @brief Structure holding the parameters for GPIO initialization.
*/
struct gpio_init_param {
/** Port number */
int32_t port;
/** GPIO number */
int32_t number;
/** Pull up/down resistor configuration */
enum gpio_pull_up pull;
/** GPIO platform specific functions */
const struct gpio_platform_ops *platform_ops;
/** GPIO extra parameters (device specific) */
void *extra;
};
/**
* @struct gpio_desc
* @brief Structure holding the GPIO descriptor.
*/
struct gpio_desc {
/** Port number */
int32_t port;
/** GPIO number */
int32_t number;
/** Pull up/down resistor configuration */
enum gpio_pull_up pull;
/** GPIO platform specific functions */
const struct gpio_platform_ops *platform_ops;
/** GPIO extra parameters (device specific) */
void *extra;
};
/**
* @enum gpio_values
* @brief Enum that holds the possible output states of a GPIO.
*/
enum gpio_values {
/** GPIO logic low */
GPIO_LOW,
/** GPIO logic high */
GPIO_HIGH,
/** GPIO high impedance */
GPIO_HIGH_Z
};
/**
* @struct gpio_platform_ops
* @brief Structure holding gpio function pointers that point to the platform
* specific function
*/
struct gpio_platform_ops {
/** gpio initialization function pointer */
int32_t (*gpio_ops_get)(struct gpio_desc **,
const struct gpio_init_param *);
/** gpio optional descriptor function pointer */
int32_t (*gpio_ops_get_optional)(struct gpio_desc **,
const struct gpio_init_param *);
/** gpio remove function pointer */
int32_t (*gpio_ops_remove)(struct gpio_desc *);
/** gpio direction input function pointer */
int32_t (*gpio_ops_direction_input)(struct gpio_desc *);
/** gpio direction output function pointer */
int32_t (*gpio_ops_direction_output)(struct gpio_desc *, uint8_t);
/** gpio get direction function pointer */
int32_t (*gpio_ops_get_direction)(struct gpio_desc *, uint8_t *);
/** gpio set value function pointer */
int32_t (*gpio_ops_set_value)(struct gpio_desc *, uint8_t);
/** gpio get value function pointer */
int32_t (*gpio_ops_get_value)(struct gpio_desc *, uint8_t *);
};
/******************************************************************************/
/************************ Functions Declarations ******************************/
/******************************************************************************/
/* Obtain the GPIO decriptor. */
int32_t gpio_get(struct gpio_desc **desc,
const struct gpio_init_param *param);
/* Obtain optional GPIO descriptor. */
int32_t gpio_get_optional(struct gpio_desc **desc,
const struct gpio_init_param *param);
/* Free the resources allocated by gpio_get(). */
int32_t gpio_remove(struct gpio_desc *desc);
/* Enable the input direction of the specified GPIO. */
int32_t gpio_direction_input(struct gpio_desc *desc);
/* Enable the output direction of the specified GPIO. */
int32_t gpio_direction_output(struct gpio_desc *desc,
uint8_t value);
/* Get the direction of the specified GPIO. */
int32_t gpio_get_direction(struct gpio_desc *desc,
uint8_t *direction);
/* Set the value of the specified GPIO. */
int32_t gpio_set_value(struct gpio_desc *desc,
uint8_t value);
/* Get the value of the specified GPIO. */
int32_t gpio_get_value(struct gpio_desc *desc,
uint8_t *value);
#endif // _GPIO_H_
@@ -0,0 +1,134 @@
/***************************************************************************//**
* @file i2c.h
* @brief Header file of I2C Interface
* @author DBogdan (dragos.bogdan@analog.com)
********************************************************************************
* Copyright 2019(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
*******************************************************************************/
#ifndef _I2C_H_
#define _I2C_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdint.h>
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
/**
* @struct i2c_platform_ops
* @brief Structure holding I2C function pointers that point to the platform
* specific function
*/
struct i2c_platform_ops ;
/**
* @struct i2c_init_param
* @brief Structure holding the parameters for I2C initialization.
*/
struct i2c_init_param {
/** Device ID */
uint32_t device_id;
/** I2C maximum transfer speed supported */
uint32_t max_speed_hz;
/** Slave address */
uint8_t slave_address;
/** I2C platform specific functions */
const struct i2c_platform_ops *platform_ops;
/** I2C extra parameters (device specific parameters) */
void *extra;
};
/**
* @struct i2c_desc
* @brief Structure holding I2C descriptor
*/
struct i2c_desc {
/** Device ID */
uint32_t device_id;
/** I2C maximum transfer speed supported */
uint32_t max_speed_hz;
/** Slave address */
uint8_t slave_address;
/** I2C platform specific functions */
const struct i2c_platform_ops *platform_ops;
/** I2C extra parameters (device specific parameters) */
void *extra;
};
/**
* @struct i2c_platform_ops
* @brief Structure holding i2c function pointers that point to the platform
* specific function
*/
struct i2c_platform_ops {
/** i2c initialization function pointer */
int32_t (*i2c_ops_init)(struct i2c_desc **,
const struct i2c_init_param *);
/** i2c write function pointer */
int32_t (*i2c_ops_write)(struct i2c_desc *, uint8_t *, uint8_t, uint8_t);
/** i2c write function pointer */
int32_t (*i2c_ops_read)(struct i2c_desc *, uint8_t *, uint8_t, uint8_t);
/** i2c remove function pointer */
int32_t (*i2c_ops_remove)(struct i2c_desc *);
};
/******************************************************************************/
/************************ Functions Declarations ******************************/
/******************************************************************************/
/* Initialize the I2C communication peripheral. */
int32_t i2c_init(struct i2c_desc **desc,
const struct i2c_init_param *param);
/* Free the resources allocated by i2c_init(). */
int32_t i2c_remove(struct i2c_desc *desc);
/* Write data to a slave device. */
int32_t i2c_write(struct i2c_desc *desc,
uint8_t *data,
uint8_t bytes_number,
uint8_t stop_bit);
/* Read data from a slave device. */
int32_t i2c_read(struct i2c_desc *desc,
uint8_t *data,
uint8_t bytes_number,
uint8_t stop_bit);
#endif // _I2C_H_
@@ -0,0 +1,235 @@
/***************************************************************************//**
* @file irq.h
* @brief Header file of IRQ interface.
* @author Cristian Pop (cristian.pop@analog.com)
********************************************************************************
* Copyright 2019(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
*******************************************************************************/
#ifndef _IRQ_H_
#define _IRQ_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdint.h>
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
/**
* @enum irq_uart_event_e
* @brief Possible events for uart interrupt
* @todo replace this with enum irq_event
*/
enum irq_uart_event_e {
/** Write operation finalized */
IRQ_WRITE_DONE,
/** Read operation finalized */
IRQ_READ_DONE,
/** An error occurred */
IRQ_ERROR
};
enum irq_event {
EVT_GPIO,
EVT_UART_TX_COMPLETE,
EVT_UART_RX_COMPLETE,
EVT_UART_ERROR,
EVT_RTC,
EVT_XINT,
EVT_TIM_ELAPSED
};
enum irq_trig_level {
IRQ_LEVEL_LOW,
IRQ_LEVEL_HIGH,
IRQ_EDGE_FALLING,
IRQ_EDGE_RISING,
IRQ_EDGE_BOTH
};
enum irq_peripheral {
GPIO_IRQ,
UART_IRQ,
RTC_IRQ,
TIM_IRQ
};
/**
* @struct irq_platform_ops
* @brief Structure holding IRQ function pointers that point to the platform
* specific function
*/
struct irq_platform_ops ;
/**
* @struct irq_init_param
* @brief Structure holding the initial parameters for Interrupt Request.
*/
struct irq_init_param {
/** Interrupt request controller ID. */
uint32_t irq_ctrl_id;
/** Platform specific IRQ platform ops structure. */
const struct irq_platform_ops *platform_ops;
/**
* This is intended to store irq controller specific configurations,
* it should not be a reference to any peripheral descriptor.
*/
void *extra;
};
/**
* @struct irq_desc
* @brief Structure for Interrupt Request descriptor.
*/
struct irq_ctrl_desc {
/** Interrupt request controller ID. */
uint32_t irq_ctrl_id;
/** Platform specific IRQ platform ops structure. */
const struct irq_platform_ops *platform_ops;
/**
* This is intended to store irq controller specific configurations,
* it should not be a reference to any peripheral descriptor.
*/
void *extra;
};
/**
* @struct callback_desc
* @brief Structure describing a callback to be registered
* @todo: remove this, use struct irq_callback instead.
*/
struct callback_desc {
/** Callback to be called when the event an event occurs. */
void (*callback)(void *context);
/**
* Callback to be called when the event an event occurs
* @param ctx - Same as \ref callback_desc.ctx
* @param event - Event that generated the callback
* @param extra - Platform specific data
*/
void (*legacy_callback)(void *ctx, uint32_t event,
void *extra); /* TODO: remove this. */
/** Parameter to be passed when the callback is called */
void *ctx;
/** Platform specific configuration for a callback */
void *legacy_config; /* TODO: remove this. */
/** Platform specific event that triggers the calling of the callback. */
enum irq_event event;
/** Interrupt source peripheral specifier. */
enum irq_peripheral peripheral;
/** This will be used to store HAL specific descriptors */
void *handle;
};
/**
* @struct irq_platform_ops
* @brief Structure holding IRQ function pointers that point to the platform
* specific function
*/
struct irq_platform_ops {
/** Initialize a interrupt controller peripheral. */
int32_t (*init)(struct irq_ctrl_desc **desc,
const struct irq_init_param *param);
/** Register a legacy_callback to handle the irq events */
int32_t (*register_callback)(struct irq_ctrl_desc *desc, uint32_t irq_id,
struct callback_desc *callback);
/** Unregisters a generic IRQ handling function */
int32_t (*unregister_callback)(struct irq_ctrl_desc *desc,
uint32_t irq_id,
struct callback_desc *callback);
/** Global interrupt enable */
int32_t (*global_enable)(struct irq_ctrl_desc *desc);
/** Global interrupt disable */
int32_t (*global_disable)(struct irq_ctrl_desc *desc);
/** Set interrupt trigger level. */
int32_t (*trigger_level_set)(struct irq_ctrl_desc *desc, uint32_t irq_id,
enum irq_trig_level trig);
/** Enable specific interrupt */
int32_t (*enable)(struct irq_ctrl_desc *desc, uint32_t irq_id);
/** Disable specific interrupt */
int32_t (*disable)(struct irq_ctrl_desc *desc, uint32_t irq_id);
/** Set the priority level for a specific interrupt */
int32_t (*set_priority)(struct irq_ctrl_desc *desc, uint32_t irq_id,
uint32_t priority_level);
/** IRQ remove function pointer */
int32_t (*remove)(struct irq_ctrl_desc *desc);
};
/******************************************************************************/
/************************ Functions Declarations ******************************/
/******************************************************************************/
/* Initialize a interrupt controller peripheral. */
int32_t irq_ctrl_init(struct irq_ctrl_desc **desc,
const struct irq_init_param *param);
/* Free the resources allocated by irq_ctrl_init(). */
int32_t irq_ctrl_remove(struct irq_ctrl_desc *desc);
/* Register a callback to handle the irq events */
int32_t irq_register_callback(struct irq_ctrl_desc *desc,
uint32_t irq_id,
struct callback_desc *callback_desc);
/* Unregisters a generic IRQ handling function */
int32_t irq_unregister_callback(struct irq_ctrl_desc *desc,
uint32_t irq_id,
struct callback_desc *callback_desc);
/* Global interrupt enable */
int32_t irq_global_enable(struct irq_ctrl_desc *desc);
/* Global interrupt disable */
int32_t irq_global_disable(struct irq_ctrl_desc *desc);
/* Set interrupt trigger level. */
int32_t irq_trigger_level_set(struct irq_ctrl_desc *desc,
uint32_t irq_id,
enum irq_trig_level trig);
/* Enable specific interrupt */
int32_t irq_enable(struct irq_ctrl_desc *desc, uint32_t irq_id);
/* Disable specific interrupt */
int32_t irq_disable(struct irq_ctrl_desc *desc, uint32_t irq_id);
/** Set the priority level for a specific interrupt */
int32_t irq_set_priority(struct irq_ctrl_desc *desc,
uint32_t irq_id,
uint32_t priority_level);
#endif // _IRQ_H_
@@ -0,0 +1,327 @@
/***************************************************************************//**
* @file list.h
* @brief List library header
* @author Mihail Chindris (mihail.chindris@analog.com)
********************************************************************************
* @copyright
* Copyright 2020(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
********************************************************************************
*
* @section list_details Library description
* This library handles double linked lists and it expose inseart,
* read, get and delete functions. \n
* It also can be accesed using it member functions which wrapp function for
* usual list types.\n
* @subsection example Sample code
* @code{.c}
* // -- Use a generic list
* struct list_desc *list1;
* struct iterator *it;
* uint32_t a;
* // Create list list1
* list_init(&list1, LIST_DEFAULT, NULL);
* // Add items to the list
* list_add_last(list1, 1);
* list_add_last(list1, 2);
* list_add_last(list1, 3);
* // Here the list will be: 1 -> 2 - > 3
*
* list_read_last(list1, &a);
* printf("Last: %d\n", a);
* // 3 will be printed
* // Create an iterator on the end of the list
* iterator_init(&it, list1, 0);
* // Move the iterator backword with one position
* iterator_move(it, -1);
* // Read the data at the current position
* iterator_read(it, &a);
* printf("Current: %d\n", a);
* // 2 will be printed
* iterator_remove(it);
* list_remove(list1);
*
* // -- Use a popular list
* struct list_desc *stack;
* // Create a FIFO list
* list_init(&stack, LIST_STACK, NULL);
* // Put elements in the list
* stack->push(stack, 1);
* stack->push(stack, 2);
* stack->push(stack, 3);
* // Read from the stack
* stack->pop(stack, &a);
* printf("Last: %d\n", a);
* // 3 will be printed
* list_remove(stack);
* @endcode
*******************************************************************************/
#ifndef _LIST_H_
#define _LIST_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdint.h>
#include <stdbool.h>
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
/**
* @struct list_desc
* @brief Structure storing the list and function wrapper for usual list types
*
* With this structure the funtionalities of usual list types
* ( \ref adapter_type ) can be accesed with the functions referenced in this
* structure.
* For example:
* @code{.c}
* my_queue->push(my_queue, my_data);
* @endcode
*/
struct list_desc;
/**
* @struct list_iterator
* @brief Structure used to iterate through the list using Iterator functions.
*/
struct iterator;
/**
* @brief Prototype of the compare function.
*
* The function used to compare the elements of the liste when doing
* operations on an ordered list.
* @param data1 - First element to be compared
* @param data2 - Second element to be compared
* @return
* - -1 - If data1 < data2
* - 0 - If data1 == data2
* - 1 - If data1 > data2
*/
typedef int32_t (*f_cmp)(void *data1, void *data2);
/**
* @name Generic functions
* Each function interacting with the list have one of the following formats.\n
* Aditionaly they may have one more parametere for specific functionalities.\n
* In the Iterator functions, the list reference is replaced by the iterator's
* one.
* @{
*/
/**
* @brief Add an element in the list.
*
* The element of the list is created and the data field is stored in it.
* @param list_desc - Reference to the list. Created by \ref list_init.
* @param data - Data to store in a list element
* @return
* - 0 : On success
* - -1 : Otherwise
*/
typedef int32_t (*f_add)(struct list_desc *list_desc, void *data);
/**
* @brief Edit an element in the list. The content is replaced by new_data.
* @param list_desc - Reference to the list. Created by \ref list_init.
* @param new_data - New data to replace the old one
* @return
* - 0 : On success
* - -1 : Otherwise
*/
typedef int32_t (*f_edit)(struct list_desc *list_desc, void *new_data);
/**
* @brief Read an element from the list.
* @param list_desc - Reference to the list. Created by \ref list_init.
* @param result - If not null, result is filled with:
* @param data - Content of the list element, NULL if some error occur.
* @return \n
* - 0 : On success
* - -1 : Otherwise
* @note If the content of an element can be 0 then the result must be checked
* to see if the functions has succeded
*/
typedef int32_t (*f_read)(struct list_desc *list_desc, void **data);
/**
* @brief Read and remove an element from the list.
* @param list_desc - Reference to the list. Created by \ref list_init.
* @param result - If not null, result is filled with:
* @param data - Content of the list element, NULL if some error occur.
* @return
* - 0 : On success
* - -1 : Otherwise
*/
typedef int32_t (*f_get)(struct list_desc *list_desc, void **data);
/** @} */
/**
* @enum adapter_type
* @brief Selects functionalities for functions in \ref list_desc
*/
enum adapter_type {
/** Default type is LIST_STACK */
LIST_DEFAULT,
/**
* Functions for a FIFO list (First-in first-out). Elements are inserted
* in one end and extracted from the other end.
* - \e Push: Insert element
* - \e Pop: Get next element (Read and remove)
* - \e Top_next: Read next element
* - \e Back: Read first element
* - \e Swap: Edit the content of the next element
*/
LIST_QUEUE,
/**
* Functions for a LIFO list (Last-in first-out). Elements are inserted
* and extracted only from the same end.
* - \e Push: Insert element
* - \e Pop: Get top element (Read and remove)
* - \e Top_next: Read top element
* - \e Back: Read bottom element
* - \e Swap: Edit the content of the top element
*/
LIST_STACK,
/**
* Functions for ordered list. The order of element is determinated
* usinge the \ref f_cmp.
* - \e Push: Insert element
* - \e Pop: Get lowest element (Read and remove)
* - \e Top_next: Read lowest element
* - \e Back: Read the biggest element
* - \e Swap: Edit the lowest element
*/
LIST_PRIORITY_LIST
};
struct list_desc {
/** Refer to \ref adapter_type */
f_add push;
/** Refer to \ref adapter_type */
f_get pop;
/** Refer to \ref adapter_type */
f_read top_next;
/** Refer to \ref adapter_type */
f_read back;
/** Refer to \ref adapter_type */
f_edit swap;
/** Structure storing the list internal parameters */
void *priv_desc;
};
/******************************************************************************/
/************************ Functions Declarations ******************************/
/******************************************************************************/
int32_t list_init(struct list_desc **list_desc,
enum adapter_type type,
f_cmp comparator);
int32_t list_remove(struct list_desc *list_desc);
int32_t list_get_size(struct list_desc *list_desc,
uint32_t *out_size);
/**
* @name Iterator functions
* An iterator is used to iterate through the list. For a list, any number of
* iterators can be created. All must be removed before removing a list.
* @{
*/
int32_t iterator_init(struct iterator **iter,
struct list_desc *list_desc,
bool start);
int32_t iterator_remove(struct iterator *iter);
int32_t iterator_move(struct iterator *iter, int32_t steps);
int32_t iterator_move_to_idx(struct iterator *iter, int32_t idx);
int32_t iterator_find(struct iterator *iter, void *cmp_data);
int32_t iterator_insert(struct iterator *iter, void *data,
bool after);
int32_t iterator_edit(struct iterator *iter, void *new_data);
int32_t iterator_read(struct iterator *iter, void **data);
int32_t iterator_get(struct iterator *iter, void **data);
/** @}*/
/**
* @name Operations on the ends of the list
* These functions will operate on the first or last element of the list
* @{
*/
int32_t list_add_first(struct list_desc *list_desc, void *data);
int32_t list_edit_first(struct list_desc *list_desc,
void *new_data);
int32_t list_read_first(struct list_desc *list_desc, void **data);
int32_t list_get_first(struct list_desc *list_desc, void **data);
int32_t list_add_last(struct list_desc *list_desc, void *data);
int32_t list_edit_last(struct list_desc *list_desc, void *new_data);
int32_t list_read_last(struct list_desc *list_desc, void **data);
int32_t list_get_last(struct list_desc *list_desc, void **data);
/** @}*/
/**
* @name Operations by index
* These functions use an index to identify the element in the list.
* @{
*/
int32_t list_add_idx(struct list_desc *list_desc, void *data,
uint32_t idx);
int32_t list_edit_idx(struct list_desc *list_desc, void *new_data,
uint32_t idx);
int32_t list_read_idx(struct list_desc *list_desc, void **data,
uint32_t idx);
int32_t list_get_idx(struct list_desc *list_desc, void **data,
uint32_t idx);
/** @}*/
/**
* @name Operations by comparation
* These functions use the specified \ref f_cmp at \ref list_init to identify
* the element this will operate on.
* @{
*/
int32_t list_add_find(struct list_desc *list_desc, void *data);
int32_t list_edit_find(struct list_desc *list_desc, void *new_data,
void *cmp_data);
int32_t list_read_find(struct list_desc *list_desc, void **data,
void *cmp_data);
int32_t list_get_find(struct list_desc *list_desc, void **data,
void *cmp_data);
/** @}*/
#endif // _LIST_H_
@@ -0,0 +1,209 @@
/***************************************************************************//**
* @file spi.h
* @brief Header file of SPI Interface
* @author DBogdan (dragos.bogdan@analog.com)
********************************************************************************
* Copyright 2019(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
*******************************************************************************/
#ifndef _SPI_H_
#define _SPI_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdint.h>
/******************************************************************************/
/********************** Macros and Constants Definitions **********************/
/******************************************************************************/
#define SPI_CPHA 0x01
#define SPI_CPOL 0x02
#define SPI_3WIRE 0x04
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
/**
* @enum spi_mode
* @brief SPI configuration for clock phase and polarity.
*/
enum spi_mode {
/** Data on rising, shift out on falling */
SPI_MODE_0 = (0 | 0),
/** Data on falling, shift out on rising */
SPI_MODE_1 = (0 | SPI_CPHA),
/** Data on rising, shift out on falling */
SPI_MODE_2 = (SPI_CPOL | 0),
/** Data on falling, shift out on rising */
SPI_MODE_3 = (SPI_CPOL | SPI_CPHA),
/** Data on rising, shift out on falling */
SPI_MODE_4 = SPI_3WIRE
};
/**
* @enum spi_bit_order
* @brief SPI configuration for bit order (MSB/LSB).
*/
enum spi_bit_order {
/** Most-significant bit (MSB) first */
SPI_BIT_ORDER_MSB_FIRST = 0,
/** Least-significant bit (LSB) first */
SPI_BIT_ORDER_LSB_FIRST = 1,
};
/**
* @struct spi_msg_list
* @brief List item describing a SPI transfer
*/
struct spi_msg {
/** Buffer with data to send. If NULL, 0x00 will be sent */
uint8_t *tx_buff;
/** Buffer where to store data. If NULL, incoming data won't be saved */
uint8_t *rx_buff;
/** Length of buffers. Must have equal size. */
uint32_t bytes_number;
/** If set, CS will be deasserted after the transfer */
uint8_t cs_change;
/**
* Minimum delay (in us) between the CS de-assert event of the current message
* and the assert of the next one.
*/
uint32_t cs_change_delay;
/** Delay (in us) between the CS assert and the first SCLK edge. */
uint32_t cs_delay_first;
/** Delay (in us) between the last SCLK edge and the CS deassert */
uint32_t cs_delay_last;
};
/**
* @struct spi_platform_ops
* @brief Structure holding SPI function pointers that point to the platform
* specific function
*/
struct spi_platform_ops ;
/**
* @struct spi_init_param
* @brief Structure holding the parameters for SPI initialization
*/
struct spi_init_param {
/** Device ID */
uint32_t device_id;
/** maximum transfer speed */
uint32_t max_speed_hz;
/** SPI chip select */
uint8_t chip_select;
/** SPI mode */
enum spi_mode mode;
/** SPI bit order */
enum spi_bit_order bit_order;
const struct spi_platform_ops *platform_ops;
/** SPI extra parameters (device specific) */
void *extra;
/** Parent of the device */
struct spi_desc *parent;
};
/**
* @struct spi_desc
* @brief Structure holding SPI descriptor.
*/
struct spi_desc {
/** Device ID */
uint32_t device_id;
/** maximum transfer speed */
uint32_t max_speed_hz;
/** SPI chip select */
uint8_t chip_select;
/** SPI mode */
enum spi_mode mode;
/** SPI bit order */
enum spi_bit_order bit_order;
const struct spi_platform_ops *platform_ops;
/** SPI extra parameters (device specific) */
void *extra;
/** Parent of the device */
struct spi_desc *parent;
};
/**
* @struct spi_platform_ops
* @brief Structure holding SPI function pointers that point to the platform
* specific function
*/
struct spi_platform_ops {
/** SPI initialization function pointer */
int32_t (*init)(struct spi_desc **, const struct spi_init_param *);
/** SPI write/read function pointer */
int32_t (*write_and_read)(struct spi_desc *, uint8_t *, uint16_t);
/** SPI write function pointer */
int32_t (*write_and_read_3wire)(struct spi_desc *, uint8_t *,uint8_t *,uint16_t, uint16_t);
/** Iterate over the spi_msg array and send all messages at once */
int32_t (*transfer)(struct spi_desc *, struct spi_msg *, uint32_t);
/** SPI remove function pointer */
int32_t (*remove)(struct spi_desc *);
};
/******************************************************************************/
/************************ Functions Declarations ******************************/
/******************************************************************************/
/* Initialize the SPI communication peripheral. */
int32_t spi_init(struct spi_desc **desc,
const struct spi_init_param *param);
/* Free the resources allocated by spi_init(). */
int32_t spi_remove(struct spi_desc *desc);
/* Write and read data to/from SPI. */
int32_t spi_write_and_read(struct spi_desc *desc,
uint8_t *data,
uint16_t bytes_number);
int32_t spi_write_and_read_3wire(struct spi_desc *desc,
uint8_t *write_data,
uint8_t *read_data,
uint16_t write_bytes_number,
uint16_t read_bytes_number);
/* Iterate over the spi_msg array and send all messages at once */
int32_t spi_transfer(struct spi_desc *desc,
struct spi_msg *msgs,
uint32_t len);
#endif // _SPI_H_
@@ -0,0 +1,159 @@
/***************************************************************************//**
* @file timer.h
* @brief Timer control module header.
* @author Andrei Drimbarean (andrei.drimbarean@analog.com)
********************************************************************************
* Copyright 2019(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
*******************************************************************************/
#ifndef _SRC_TIMER_H_
#define _SRC_TIMER_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdint.h>
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
/**
* @struct timer_desc
* @brief Structure holding timer descriptor
*/
struct timer_desc {
/** timer ID */
uint16_t id;
/** timer count frequency (Hz) */
uint32_t freq_hz;
/** the number of ticks the timer counts until it resets */
uint32_t ticks_count;
/** Timer platform operations */
const struct timer_platform_ops *platform_ops;
/** timer extra parameters (device specific) */
void *extra;
};
/**
* @struct timer_platform_ops
* @brief Structure holding timer function pointers that point to the platform
* specific function
*/
struct timer_platform_ops ;
/**
* @struct timer_init_param
* @brief Structure holding the parameters for timer initialization
*/
struct timer_init_param {
/** timer ID */
uint16_t id;
/** timer count frequency (Hz) */
uint32_t freq_hz;
/** the number of ticks the timer counts until it resets */
uint32_t ticks_count;
/** Timer platform operations */
const struct timer_platform_ops *platform_ops;
/** timer extra parameters (device specific) */
void *extra;
};
/**
* @struct timer_platform_ops
* @brief Structure holding timer function pointers that point to the platform
* specific function
*/
struct timer_platform_ops {
/** timer initialization function pointer */
int32_t (*init)(struct timer_desc **,
const struct timer_init_param *);
/** timer start function pointer */
int32_t (*start)(struct timer_desc *);
/** timer stop function pointer */
int32_t (*stop)(struct timer_desc *);
/** timer get counter function pointer */
int32_t (*counter_get)(struct timer_desc *, uint32_t *counter);
/** timer set counter function pointer */
int32_t (*counter_set)(struct timer_desc *, uint32_t new_val);
/** timer get clock frequency function pointer */
int32_t (*count_clk_get)(struct timer_desc *, uint32_t *freq_hz);
/** timer set clock frequency function pointer */
int32_t (*count_clk_set)(struct timer_desc *, uint32_t freq_hz);
/** timer get elapsed time in nsec */
int32_t (*get_elapsed_time_nsec)(struct timer_desc *,
uint64_t *elapsed_time);
/** timer remove function pointer */
int32_t (*remove)(struct timer_desc *);
};
/******************************************************************************/
/************************ Functions Declarations ******************************/
/******************************************************************************/
/* Initialize hardware timer and the handler structure associated with it. */
int32_t timer_init(struct timer_desc **desc,
struct timer_init_param *param);
/* Free the memory allocated by timer_setup(). */
int32_t timer_remove(struct timer_desc *desc);
/* Start a timer. */
int32_t timer_start(struct timer_desc *desc);
/* Stop a timer from counting. */
int32_t timer_stop(struct timer_desc *desc);
/* Get the value of the counter register for the timer. */
int32_t timer_counter_get(struct timer_desc *desc,
uint32_t *counter);
/* Set the timer counter register value. */
int32_t timer_counter_set(struct timer_desc *desc,
uint32_t new_val);
/* Get the timer clock frequency. */
int32_t timer_count_clk_get(struct timer_desc *desc,
uint32_t *freq_hz);
/* Set the timer clock frequency. */
int32_t timer_count_clk_set(struct timer_desc *desc,
uint32_t freq_hz);
/* Get the elapsed time in nsec for the timer. */
int32_t timer_get_elapsed_time_nsec(struct timer_desc *desc,
uint64_t *elapsed_time);
#endif // _SRC_TIMER_H_
@@ -0,0 +1,115 @@
/***************************************************************************//**
* @file trng.h
* @brief Header file of true random number generator
* @author Mihail Chindris (mihail.chindris@analog.com)
********************************************************************************
* @copyright
* Copyright 2020(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
*******************************************************************************/
#ifndef _TRNG_H_
#define _TRNG_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdint.h>
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
/**
* @struct trng_platform_ops
* @brief Structure holding TRNG function pointers that point to the platform
* specific function
*/
struct trng_platform_ops;
/**
* @struct trng_desc
* @brief TRNG Descriptor
*/
struct trng_desc {
/** Platform ops */
const struct trng_platform_ops *platform_ops;
/** Platform specific parameters */
void *extra;
};
/**
* @struct trng_init_param
* @brief Init parameter for TRNG
*/
struct trng_init_param {
/** Device id */
uint32_t dev_id;
/** Platform specific parameter */
void *extra;
/** Platform ops */
const struct trng_platform_ops *platform_ops;
};
/**
* @struct trng_platform_ops
* @brief Structure holding TRNG function pointers that point to the platform
* specific function
*/
struct trng_platform_ops {
/** TRNG initialization function pointer */
int (*init)(struct trng_desc **,
const struct trng_init_param *);
/** Fill buffer with random numbers */
int (*fill_buffer)(struct trng_desc *, uint8_t *, uint32_t);
/** TRNG remove function pointer */
int (*remove)(struct trng_desc *);
};
/******************************************************************************/
/************************ Functions Declarations ******************************/
/******************************************************************************/
/* Initialize descriptor */
int trng_init(struct trng_desc **desc,
const struct trng_init_param *param);
/* Free resources allocated in descriptor */
int trng_remove(struct trng_desc *desc);
/* Fill buffer with random numbers */
int trng_fill_buffer(struct trng_desc *desc, uint8_t *buff,
uint32_t len);
#endif // _TRNG_H_
@@ -0,0 +1,185 @@
/*****************************************************************************/
/**
* @file util.h
* @author FanHao (hao_fan_bit_ee@163.com)
* @brief Utility functions header file
* @version 0.0
* @date 2023-05-06
*
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
* Lab of Communication and Network
*
******************************************************************************/
/**
* @defgroup Utility
* @{
*/
#ifndef __UTIL_H_
#define __UTIL_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
/******************************************************************************/
/********************** Macros and Constants Definitions **********************/
/******************************************************************************/
// #define __CRC_LSB
#define __BITSWAP_TABLE
#define __CRC_LSB
#define CRC16_INIT 0x0000
#define CRC8_INIT 0x00
#define BIT(x) (1 << (x))
#define ARRAY_SIZE(x) \
(sizeof(x) / sizeof((x)[0]))
#define DIV_ROUND_UP(x, y) \
(((x) + (y)-1) / (y))
#define DIV_ROUND_CLOSEST(x, y) \
(((x) + (y) / 2) / (y))
#define DIV_ROUND_CLOSEST_ULL(x, y) \
DIV_ROUND_CLOSEST(x, y)
#define min(x, y) \
(((x) < (y)) ? (x) : (y))
#define min_t(type, x, y) \
(type) min((type)(x), (type)(y))
#define max(x, y) \
(((x) > (y)) ? (x) : (y))
#define max_t(type, x, y) \
(type) max((type)(x), (type)(y))
#define clamp(val, min_val, max_val) \
(max(min((val), (max_val)), (min_val)))
#define clamp_t(type, val, min_val, max_val) \
(type) clamp((type)(val), (type)(min_val), (type)(max_val))
#define swap(x, y) \
{ \
typeof(x) _tmp_ = (x); \
(x) = (y); \
(y) = _tmp_; \
}
#define round_up(x, y) \
(((x) + (y)-1) / (y))
#ifdef __aarch64__
#define NORMALIZE_SIZE(x) \
(((x) + sizeof(uint64_t) - 1) & 0xFFFFFFFFFFFFFFF8)
#else
#define NORMALIZE_SIZE(x) \
(((x) + sizeof(uint32_t) - 1) & 0xFFFFFFFC)
#endif
#define BITS_PER_LONG 32
#define GENMASK(h, l) ({ \
uint32_t t = (uint32_t)(~0UL); \
t = t << (BITS_PER_LONG - (h - l + 1)); \
t = t >> (BITS_PER_LONG - (h + 1)); \
t; \
})
#define bswap_constant_32(x) \
((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
(((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))
#define bswap_constant_16(x) ((((x) & (uint16_t)0xff00) >> 8) | \
(((x) & (uint16_t)0x00ff) << 8))
#define bit_swap_constant_8(x) \
((((x) & 0x80) >> 7) | \
(((x) & 0x40) >> 5) | \
(((x) & 0x20) >> 3) | \
(((x) & 0x10) >> 1) | \
(((x) & 0x08) << 1) | \
(((x) & 0x04) << 3) | \
(((x) & 0x02) << 5) | \
(((x) & 0x01) << 7))
#define U16_MAX ((uint16_t)~0U)
#define S16_MAX ((int16_t)(U16_MAX >> 1))
#define DIV_U64(x, y) (x / y)
#define UNUSED_PARAM(x) ((void)x)
#define shift_right(x, s) ((x) < 0 ? -(-(x) >> (s)) : (x) >> (s))
/******************************************************************************/
/************************ Functions Declarations ******************************/
/******************************************************************************/
void IO_Out32(uintptr_t addr, uint32_t value);
uint32_t IO_In32(uintptr_t addr);
/* flip a byte left to right*/
uint8_t byte_bit_swap(uint8_t byte);
/* flip a 32bit word left to right */
uint32_t word_bit_swap(uint32_t word);
/* Returns the number of 1-bits in digit. */
uint32_t count_ones(uint32_t word);
/* convert a fixed number to a double. */
double fix2double(int32_t val, uint8_t frac_bits);
/* Find first set bit in word. */
uint32_t find_first_set_bit(uint32_t word);
/* Find last set bit in word. */
uint32_t find_last_set_bit(uint32_t word);
/* Locate the closest element in an array. */
uint32_t find_closest(int32_t val,
const int32_t *array,
uint32_t size);
/* Shift the value and apply the specified mask. */
uint32_t field_prep(uint32_t mask, uint32_t val);
/* Get a field specified by a mask from a word. */
uint32_t field_get(uint32_t mask, uint32_t word);
/* Log base 2 of the given number. */
int32_t log_base_2(uint32_t x);
/* Find greatest common divisor of the given two numbers. */
uint32_t greatest_common_divisor(uint32_t a,
uint32_t b);
/* Calculate best rational approximation for a given fraction. */
void rational_best_approximation(uint32_t given_numerator,
uint32_t given_denominator,
uint32_t max_numerator,
uint32_t max_denominator,
uint32_t *best_numerator,
uint32_t *best_denominator);
/* Calculate the number of set bits. */
uint32_t hweight8(uint32_t word);
/* Calculate the quotient and the remainder of an integer division. */
uint64_t do_div(uint64_t *n,
uint64_t base);
/* Unsigned 64bit divide with 64bit divisor and remainder */
uint64_t div64_u64_rem(uint64_t dividend, uint64_t divisor,
uint64_t *remainder);
/* Unsigned 64bit divide with 32bit divisor with remainder */
uint64_t div_u64_rem(uint64_t dividend, uint32_t divisor, uint32_t *remainder);
int64_t div_s64_rem(int64_t dividend, int32_t divisor, int32_t *remainder);
/* Unsigned 64bit divide with 32bit divisor */
uint64_t div_u64(uint64_t dividend, uint32_t divisor);
int64_t div_s64(int64_t dividend, int32_t divisor);
/* Converts from string to int32_t */
int32_t str_to_int32(const char *str);
/* Converts from string to uint32_t */
uint32_t srt_to_uint32(const char *str);
int crc16_gen(uint8_t *buffPtr, uint32_t dataLen, uint16_t poly, uint16_t *crcVal);
bool crc16_check(uint8_t *buffPtr, uint32_t dataLen, uint32_t crcOffset, uint16_t poly);
int crc8_gen(uint8_t *buffPtr, uint32_t dataLen, uint16_t poly, uint8_t *crcVal);
bool crc8_check(uint8_t *buffPtr, uint32_t dataLen, uint32_t crcOffset, uint16_t poly);
#endif // __UTIL_H_
/** @} */
@@ -0,0 +1,557 @@
/*****************************************************************************/
/**
* Description: main.c
*
* Date: 2023-05-07 13:19
* Last Edit Time: [2023-05-07 20:32]
*
* Revisions: Rev 0.0
* History:
* [2023-05-07]: Initial edition.
*
* Copyright(c) 2024 Beijing Institute of Technology.
*
******************************************************************************/
/***************************** Include Files *********************************/
// Standard
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
// Xilinx
#include "xscugic.h"
#include "drivers/platform/xilinx_irq.h"
#include "drivers/platform/xilinx_timer.h"
// App
#include "common.h"
#include "error.h"
#include "timer.h"
#include "hwconfig.h"
#include "system_monitor.h"
#include "config/app_config.h"
#include "dev_profile/dev_profile.h"
//#include "systembus/systembus.h"
//#include "networking/phy_layer/phy_layer.h"
//#include "networking/link_layer/link_layer.h"
#ifdef HSJL_GE
#include <metal/log.h>
#endif
///************************** Function Prototypes ******************************/
//int32_t SetupInterruptSystem(struct irq_ctrl_desc *descPtr);
//void Phy_IntrHandler(void *context);
//void PeriodicPull_Handler(void *callBackRef);
//void AppTimer_IntrHandler(void *context);
//void Systembus_RxIntrHandler(void *context);
//void Systembus_TxIntrHandler(void *context);
//
///************************** Constant Definitions *****************************/
//struct callback_desc phy_callback_desc = {
// .callback = Phy_IntrHandler,
// .ctx = NULL
//};
//
//struct callback_desc periodicpull_callback_desc = {
// .callback = PeriodicPull_Handler,
// .ctx = NULL
//};
//
//
//struct callback_desc sysbus_rx_callback_desc = {
// .callback = Systembus_RxIntrHandler,
// .ctx = NULL
//};
//
//struct callback_desc sysbus_tx_callback_desc = {
// .callback = Systembus_TxIntrHandler,
// .ctx = NULL
//};
//
//struct callback_desc apptimer_callback_desc = {
// .callback = AppTimer_IntrHandler,
// .ctx = NULL
//};
//
//L2_CONFIG linkConfig = {
// .myType = L2_NODE_HEAD,
// .clustId = 1,
// .myId = 1,
// .headId = 1,
// .netScale = 3,
// .phyInstPtr = NULL, // physical layer reference
// .tmcInstPtr = NULL
//};
//
//// L2_CONFIG linkConfig = {
//// .myType = L2_NODE_MEMBER,
//// .clustId = 1,
//// .myId = 2,
//// .headId = 1,
//// .netScale = 2,
//// .phyInstPtr = NULL, // physical layer reference
//// .tmcInstPtr = NULL
//// };
//
//static PHY_CONFIG phyConfig = {
// .devId = PHY_DEVICE_ID,
// .baseAddr = PHY_BASEADDR,
// .antBramId = PHY_ANTCONFIG_BRAM_DEVICE_ID,
// .antInfoBramId = PHY_ANTINFO_BRAM_DEVICE_ID,
// .txBramId = PHY_TXBUFF_BRAM_DEVICE_ID,
// .rxBramId = PHY_RXBUFF_BRAM_DEVICE_ID,
// .hwSysmonId = PHY_HW_SYSMON_DEVICE_ID,
// .get_clk_state = NULL,
// .get_ad_lock_state = NULL,
// .get_ad0_temp = NULL,
// .get_ad1_temp = NULL
//};
//
//TMC_CONFIG tmcConfig = {
// .baseAddr = TIME_CONTROLLER_BASEADDR,
// .reset = 10
//};
//
//static SYSBUS_CONFIG sysbusConfig = {
// .baseAddr = SYSBUS_BASE_ADDR,
// .txQueueMax = 16,
// .rxQueueMax = 16
//};
///*********************** Driver Instance Definitions **************************/
//static struct irq_ctrl_desc *intcDescPtr; // General interrupt controller descriptor
//static struct timer_desc *logTmPtr;
//static SYSBUS *sysbusDescPtr;
//static PHY_INST *phyInstPtr;
//static TMC_INST *tmcInstPtr = NULL;
//L2_INST *linkInstPtr;
//
//#ifdef HSJL_GE
//void MetalLogHandler(enum metal_log_level level, const char *format, ...)
//{
// char msg[1024];
// va_list args;
// static const char * const level_strs[] = {
// "metal: emergency: ",
// "metal: alert: ",
// "metal: critical: ",
// "metal: error: ",
// "metal: warning: ",
// "metal: notice: ",
// "metal: info: ",
// "metal: debug: ",
// };
//
// va_start(args, format);
// vsnprintf(msg, sizeof(msg), format, args);
// va_end(args);
//
// if (level <= METAL_LOG_EMERGENCY || level > METAL_LOG_DEBUG)
// level = METAL_LOG_EMERGENCY;
//
// printf("%s%s", level_strs[level], msg);
//}
//#endif
//
///****************************************************************************/
///**
// * This function is responsible for initializing the SCUGIC instance, looking
// * for the device configuration based on the unique device ID, initializing a
// * SCUGIC instance, and initialize the interrupt at IRQ_F2P[0:0]
// *
// * @param intcDesc A pointer to INTC descriptor
// *
// * @return SUCCESS if initialize successful.
// * FAILURE if initialization failed.
// *
// *****************************************************************************/
//int32_t SetupInterruptSystem(struct irq_ctrl_desc *descPtr)
//{
// int32_t Status;
// struct xil_irq_desc *xil_dev;
//
// Status = irq_ctrl_init(&descPtr, &intc_init_param);
// if (Status != SUCCESS)
// {
// DBG_ERROR("Intc Init FAILED, ErrorCode: %" PRId32 ".\n", Status);
// return Status;
// }
//
// xil_dev = (struct xil_irq_desc *)(descPtr->extra);
//
// // Clear any pending interrupt flags
// uint32_t intrState = XScuGic_CPUReadReg((XScuGic *)(xil_dev->instance), XSCUGIC_INT_ACK_OFFSET);
// XScuGic_CPUWriteReg((XScuGic *)(xil_dev->instance), XSCUGIC_EOI_OFFSET, intrState);
//
// /* Initialize physical layer interrupt. */
// Status = irq_trigger_level_set(descPtr, PHY_INTR_ID, IRQ_EDGE_RISING);
// if (Status != SUCCESS)
// {
// DBG_ERROR("PHY_INTR trigger level set FAILED, ErrorCode: %" PRId32 ".\n", Status);
// return Status;
// }
// // Set highest interrupt priority
// Status = irq_set_priority(descPtr, PHY_INTR_ID, 0x08);
// if (Status != SUCCESS)
// {
// DBG_ERROR("PHY_INTR priority level set FAILED, ErrorCode: %" PRId32 ".\n", Status);
// return Status;
// }
// // Connect the interrupt service routine isr1 to the interrupt controller
// Status = irq_register_callback(descPtr, PHY_INTR_ID, &phy_callback_desc);
// if (Status != SUCCESS)
// {
// DBG_ERROR("PHY_INTR register callback FAILED, ErrorCode: %" PRId32 ".\n", Status);
// return Status;
// }
//
// /* Initialize linklayer layer interrupt. */
// Status = irq_trigger_level_set(descPtr, PERIODIC_5MS_INTR_ID, IRQ_EDGE_RISING);
// if (Status != SUCCESS)
// {
// DBG_ERROR("PERIODIC_5MS_INTR_ID trigger level set FAILED, ErrorCode: %" PRId32 ".\n", Status);
// return Status;
// }
// // Set highest interrupt priority
// Status = irq_set_priority(descPtr, PERIODIC_5MS_INTR_ID, 0x00);
// if (Status != SUCCESS)
// {
// DBG_ERROR("PERIODIC_5MS_INTR_ID priority level set FAILED, ErrorCode: %" PRId32 ".\n", Status);
// return Status;
// }
// // Connect the interrupt service routine isr1 to the interrupt controller
// Status = irq_register_callback(descPtr, PERIODIC_5MS_INTR_ID, &periodicpull_callback_desc);
// if (Status != SUCCESS)
// {
// DBG_ERROR("PHY_INTR register callback FAILED, ErrorCode: %" PRId32 ".\n", Status);
// return Status;
// }
//
// /* Initialize system bus interrupt. */
// Status = irq_trigger_level_set(descPtr, SYSBUS_TX_INTR_ID, IRQ_EDGE_RISING);
// if (Status != SUCCESS)
// {
// DBG_ERROR("PHY_INTR trigger level set FAILED, ErrorCode: %" PRId32 ".\n", Status);
// return Status;
// }
// // Set interrupt priority
// Status = irq_set_priority(descPtr, SYSBUS_TX_INTR_ID, 0x10);
// if (Status != SUCCESS)
// {
// DBG_ERROR("PHY_INTR priority level set FAILED, ErrorCode: %" PRId32 ".\n", Status);
// return Status;
// }
//
// // Connect the interrupt service routine isr1 to the interrupt controller
// Status = irq_register_callback(descPtr, SYSBUS_TX_INTR_ID, &sysbus_tx_callback_desc);
// if (Status != SUCCESS)
// {
// DBG_ERROR("PHY_INTR register callback FAILED, ErrorCode: %" PRId32 ".\n", Status);
// return Status;
// }
// Status = irq_trigger_level_set(descPtr, SYSBUS_RX_INTR_ID, IRQ_EDGE_RISING);
// if (Status != SUCCESS)
// {
// DBG_ERROR("PHY_INTR trigger level set FAILED, ErrorCode: %" PRId32 ".\n", Status);
// return Status;
// }
// // Set interrupt priority
// Status = irq_set_priority(descPtr, SYSBUS_RX_INTR_ID, 0x18);
// if (Status != SUCCESS)
// {
// DBG_ERROR("PHY_INTR priority level set FAILED, ErrorCode: %" PRId32 ".\n", Status);
// return Status;
// }
//
// // Connect the interrupt service routine isr1 to the interrupt controller
// Status = irq_register_callback(descPtr, SYSBUS_RX_INTR_ID, &sysbus_rx_callback_desc);
// if (Status != SUCCESS)
// {
// DBG_ERROR("PHY_INTR register callback FAILED, ErrorCode: %" PRId32 ".\n", Status);
// return Status;
// }
//
// /* Initialize Scu timer interrupt. */
// // Connect the interrupt service routine isr1 to the interrupt controller
// Status = irq_register_callback(descPtr, APPTIMER_INTR_ID, &apptimer_callback_desc);
// if (Status != SUCCESS)
// {
// DBG_ERROR("PHY_INTR register callback FAILED, ErrorCode: %" PRId32 ".\n", Status);
// return Status;
// }
//
// // Enable interrupts
// irq_enable(descPtr, PHY_INTR_ID);
// irq_enable(descPtr, PERIODIC_5MS_INTR_ID);
// irq_enable(descPtr, SYSBUS_RX_INTR_ID);
// irq_enable(descPtr, SYSBUS_TX_INTR_ID);
// irq_enable(descPtr, APPTIMER_INTR_ID);
//
// // Enable Exceptions
// Status = irq_global_enable(descPtr);
// if (Status != SUCCESS)
// {
// DBG_ERROR("IRQ global enable FAILED, ErrorCode: %" PRId32 ".\n", Status);
// return Status;
// }
// return SUCCESS;
//} // SetupInterruptSystem
//
///****************************************************************************/
///**
// * This function is a interrupt service routine for IRQ_F2P[1:1], IRQ_F2P[1:1]
// * tells CPU that the data in OCM is ready!
// *
// * @param context
// *
// * @return None.
// *
// *****************************************************************************/
//void Phy_IntrHandler(void *context)
//{
// Phy_UpdateState(phyInstPtr);
//} // PhyIntr_Handler
//
//
///****************************************************************************/
///**
// * Handler of periodic 5ms interrupt
// *
// * @param callBackRef is the linklayer instance pointer.
// *
// * @return None.
// *
// *****************************************************************************/
//void PeriodicPull_Handler(void *callBackRef)
//{
// int32_t Status;
// Status = Linklayer_Proc(linkInstPtr);
// if (Status != SUCCESS)
// {
// DBG_ERROR("Link layer runs failed, with error code: %" PRId32 "\n", Status);
// _nop_();
// }
//} // PeriodicPull_Handler
//
///*****************************************************************************/
///**
// * @brief Handler of System Bus RX done interrupt.
// *
// * @param context
// *
// * @return None.
// *
// ******************************************************************************/
//void Systembus_RxIntrHandler(void *context)
//{
// int32_t Status;
// Status = SystemBus_RxIntrHandler(sysbusDescPtr);
// if (Status != SUCCESS)
// {
// DBG_ERROR("SystemBus_RxIntrHandler exit with error code %" PRId32 ",\n", Status);
// }
//}
//
///*****************************************************************************/
///**
// * @brief Handler of System Bus TX done interrupt.
// *
// * @param context
// *
// * @return None.
// *
// ******************************************************************************/
//void Systembus_TxIntrHandler(void *context)
//{
// int32_t Status;
// Status = SystemBus_TxIntrHandler(sysbusDescPtr);
// if (Status != SUCCESS)
// {
// DBG_ERROR("SystemBus_TxIntrHandler exit with error code %" PRId32 ",\n", Status);
// }
//}
//
///*****************************************************************************/
///**
// * @brief Handler of AppTimer interrupt.
// *
// * @param context
// *
// * @return None.
// *
// ******************************************************************************/
//void AppTimer_IntrHandler(void *context)
//{
// struct xil_timer_desc *xdesc;
// xdesc = (struct xil_timer_desc *)(logTmPtr->extra);
//#ifdef XPAR_XSCUTIMER_NUM_INSTANCES
// if (XScuTimer_IsExpired((XScuTimer *)xdesc->instance))
// {
// // Refresh log
// Phy_RefreshHwSate(phyInstPtr);
// if (TimeCtrl_GetIntCnt(tmcInstPtr) - phyInstPtr->lastLogTime >= PHY_LOG_EXPIRE)
// {
// Phy_UpdateLogging(phyInstPtr);
// }
//
// XScuTimer_ClearInterruptStatus((XScuTimer *)xdesc->instance);
// }
//#elif defined(XPAR_XTMRCTR_NUM_INSTANCES)
// if (XTmrCtr_IsExpired((XTmrCtr *)xdesc->instance, 0))
// {
// // Refresh log
// Phy_RefreshHwSate(phyInstPtr);
// if (TimeCtrl_GetIntCnt(tmcInstPtr) - phyInstPtr->lastLogTime >= PHY_LOG_EXPIRE)
// {
// Phy_UpdateLogging(phyInstPtr);
// }
//
// XTmrCtr_WriteReg(((XTmrCtr *)xdesc->instance)->BaseAddress, 0,
// XTC_TCSR_OFFSET, XTC_CSR_INT_OCCURED_MASK);
// }
//#else
//#error No timer implementation!
//#endif
// else
// {
// DBG_WARNING("UNEXPECTED CALL of AppTimer_IntrHandler\n");
// }
//}
/*****************************************************************************/
/**
* @brief Main function, initialize all the device needed, initialize
* interrupt system, halt in while(1) wait for event interrupt.
*
* @param none.
*
* @return
*
******************************************************************************/
int main(void)
{
#ifdef HSJL_GE
metal_set_log_handler(MetalLogHandler);
metal_set_log_level(METAL_LOG_DEBUG);
#endif
int32_t Status;
DBG_PRINT("Application Version: %2d.%2d.%4d.\n", _APP_VER_MAIN, _APP_VER_MINOR, _APP_VER_PATCH);
/* System Monitor Initialize */
Status = SysMonitor_Init();
if (Status == SUCCESS)
{
DBG_PRINT("System monitor Init SUCCESS! \n");
}
else
{
DBG_PRINT("System monitor Init FAILED! \n");
return Status;
}
/* Hardware Initialize */
Status = Hardware_Init();
if (Status == SUCCESS)
{
DBG_PRINT("Hardware Init SUCCESS! \n");
}
else
{
DBG_PRINT("Hardware Init FAILED! \n");
return Status;
}
// /* Time controller Initialize */
// Status = TimeCtrl_Init(&tmcInstPtr, &tmcConfig);
// if (Status == SUCCESS)
// {
// DBG_PRINT("TmcCtrl Init SUCCESS! \n");
// }
// else
// {
// DBG_PRINT("TmcCtrl Init FAILED! \n");
// return Status;
// }
//
// /* Physical Layer Initialize */
// Status = Phy_Init(&phyInstPtr, &phyConfig);
// if (Status == SUCCESS)
// {
// DBG_PRINT("Physical layer Init SUCCESS! \n");
// }
// else
// {
// DBG_PRINT("Physical layer FAILED! \n");
// return Status;
// }
//
// /* Link Layer Initialize */
// linkConfig.phyInstPtr = phyInstPtr;
// linkConfig.tmcInstPtr = tmcInstPtr;
// Status = Linklayer_Init(&linkInstPtr, &linkConfig);
// if (Status == SUCCESS)
// {
// DBG_PRINT("LinkLayer Init SUCCESS! \n");
// }
// else
// {
// DBG_PRINT("Linklayer Init FAILED! \n");
// return Status;
// }
//
// /* System Bus Initialize */
// Status = SystemBus_Init(&sysbusDescPtr, &sysbusConfig);
// if (Status != SUCCESS)
// {
// DBG_ERROR("Systembus init FAILED, with error code: %" PRId32 "\n", Status);
// return Status;
// }
//
// /* System Monitor log timer Initialize */
// Status = timer_init(&logTmPtr, &apptimer_init_param);
// if (Status != SUCCESS)
// {
// DBG_ERROR("APP Timer init FAILED, with error code: %" PRId32 "\n", Status);
// return Status;
// }
//
// /* interrupts Initialize */
// Status = SetupInterruptSystem(intcDescPtr);
// if (Status == SUCCESS)
// {
// DBG_INFO("Interrupt system setup SUCCESS!\n");
// }
// else
// {
// DBG_ERROR("Interrupt system setup FAILED, ErrorCode: %" PRId32 ".\n", Status);
// return Status;
// }
//
// // Start System Monitor logging.
// timer_start(logTmPtr);
//
// DBG_PRINT("Physical started...\n");
// Phy_Start(phyInstPtr);
//
while (true)
{
// // System bus handler
// if (SystemBus_IsReqPending(sysbusDescPtr))
// {
// Status = SystemBus_HandleCmd(sysbusDescPtr);
// if (Status != SUCCESS)
// {
// DBG_ERROR("SystemBus_HandleCmd exit with ErrorCode: %" PRId32 ".\n", Status);
// }
// }
// if (SystemBus_IsRsqPending(sysbusDescPtr) && (!SystemBus_IsTxBusy(sysbusDescPtr)))
// {
// Status = SystemBus_MakeResp(sysbusDescPtr);
// if (Status != SUCCESS)
// {
// DBG_ERROR("SystemBus_HandleCmd exit with ErrorCode: %" PRId32 ".\n", Status);
// }
// }
}
} // main
@@ -0,0 +1,402 @@
/**
* @addtogroup SystemMonitor
* @{
*/
/***************************** Include Files *********************************/
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include "common.h"
#include "system_monitor.h"
/************************** Constant Definitions *****************************/
/**
* @name SystemMonitor_Private_Constants
* @{
*/
#define BUFF_A 0x00
#define BUFF_B 0x01
#define BUFF_NONE 0xFF
#define SYSINFO_PACK_LEN 54 // bytes
#define PAYLOAD_PACK_LEN 46 // bytes
#define SLOTLOG_PACK_LEN 88 // bytes
#define PRTCLLOG_PACK_ELN 24 // bytes
#define HWSTATE_PACK_ELN 12 // bytes
/** @} SystemMonitor_Private_Constants*/
/************************** Data Type Definitions ****************************/
/**
* @struct PINGPONG
* @brief PingPing Control
*/
typedef struct
{
uint8_t latest; ///< latest available index
uint8_t rBusy; ///< current read busy index
uint8_t wBusy; ///< current write busy index
} PINGPONG;
/**
* @struct SYSMONITOR
* @brief System Monitor struct holds all the system log info
*/
typedef struct
{
PINGPONG recvCtrl;
PAYLOAD recv[2];
PINGPONG sendCtrl;
PAYLOAD send[2];
PINGPONG sysInfoCtrl;
SYSINFO sysInfo[2];
PINGPONG linkLogCtrl;
LINKLOG linkLog[2];
PINGPONG phyLogCtrl;
PHYLOG phyLog[2];
PINGPONG hwStateCtrl;
HWSTATE hwState[2];
} SYSMONITOR;
/************************** Function Prototypes ******************************/
static uint8_t GetWritable(PINGPONG ctrllor);
static uint8_t GetReadable(PINGPONG ctrllor);
/************************** Variable Definitions *****************************/
static SYSMONITOR *sysMonitorInst;
/*********************** Function Implementations ***************************/
inline static uint8_t GetWritable(PINGPONG ctrllor)
{
// Allow only one write.
ASSERT(ctrllor.wBusy == BUFF_NONE);
if (ctrllor.rBusy == BUFF_NONE)
return ((ctrllor.latest == BUFF_B) ? BUFF_A : BUFF_B);
else
return ((ctrllor.rBusy == BUFF_B) ? BUFF_A : BUFF_B);
}
inline static uint8_t GetReadable(PINGPONG ctrllor)
{
if (ctrllor.wBusy == BUFF_NONE || ctrllor.wBusy != ctrllor.latest)
return ((ctrllor.latest == BUFF_NONE) ? BUFF_A : BUFF_B);
else
return ((ctrllor.wBusy == BUFF_B) ? BUFF_A : BUFF_B);
}
/**
* @brief Initialize System monitor
*
* @return SUCCESS
*/
int32_t SysMonitor_Init(void)
{
sysMonitorInst = calloc(1, sizeof(SYSMONITOR));
if (sysMonitorInst == NULL)
{
return ENOMEM;
}
memset(&(sysMonitorInst->recvCtrl), BUFF_NONE, sizeof(PINGPONG));
memset(&(sysMonitorInst->sendCtrl), BUFF_NONE, sizeof(PINGPONG));
memset(&(sysMonitorInst->sysInfoCtrl), BUFF_NONE, sizeof(PINGPONG));
memset(&(sysMonitorInst->linkLogCtrl), BUFF_NONE, sizeof(PINGPONG));
memset(&(sysMonitorInst->phyLogCtrl), BUFF_NONE, sizeof(PINGPONG));
memset(&(sysMonitorInst->hwStateCtrl), BUFF_NONE, sizeof(PINGPONG));
sysMonitorInst->recv[0].dataId = DATA_ID_NONE;
sysMonitorInst->recv[1].dataId = DATA_ID_NONE;
sysMonitorInst->send[0].dataId = DATA_ID_NONE;
sysMonitorInst->send[1].dataId = DATA_ID_NONE;
return SUCCESS;
}
/**
* @brief Destroy system monitor release all allocated memory
*/
void SysMonitor_Destroy(void)
{
free(sysMonitorInst);
}
/**
* @name SystemInfo_API
* @{
*/
/**
* @brief Update system info.
*
* @param info
*/
void SysMonitor_UpdateSysinfo(const SYSINFO *info)
{
uint8_t buffIndx;
buffIndx = GetWritable(sysMonitorInst->sysInfoCtrl);
sysMonitorInst->sysInfoCtrl.wBusy = buffIndx;
memcpy(&(sysMonitorInst->sysInfo[buffIndx]), info, sizeof(SYSINFO));
sysMonitorInst->sysInfoCtrl.latest = buffIndx;
sysMonitorInst->sysInfoCtrl.wBusy = BUFF_NONE;
}
/**
* @brief Get system info.
*
* @param info
*/
void SysMonitor_GetSysinfo(SYSINFO *info)
{
ASSERT(sysMonitorInst != NULL);
uint8_t buffIndx, buffIndex_old;
buffIndex_old = sysMonitorInst->sysInfoCtrl.rBusy;
if (buffIndex_old != BUFF_NONE)
buffIndx = buffIndex_old; // Keep it busy
else
buffIndx = GetReadable(sysMonitorInst->sysInfoCtrl);
sysMonitorInst->sysInfoCtrl.rBusy = buffIndx;
memcpy(info, &(sysMonitorInst->sysInfo[buffIndx]), sizeof(SYSINFO));
sysMonitorInst->sysInfoCtrl.rBusy = buffIndex_old;
}
/** @} SystemInfo_API*/
/**
* @name ServicePayload_API
* @{
*/
/**
* @brief Update send payload by
*
* @param buff
* @param len
*/
void SysMonitor_UpdateSendPayload(const uint8_t *buff, size_t len)
{
ASSERT(sysMonitorInst != NULL);
if (len > PAYLOAD_LEN_MAX)
{
return;
}
uint8_t buffIndx;
buffIndx = GetWritable(sysMonitorInst->sendCtrl);
sysMonitorInst->sendCtrl.wBusy = buffIndx;
memcpy(sysMonitorInst->send[buffIndx].data, buff, len);
sysMonitorInst->send[buffIndx].dataId++;
sysMonitorInst->sendCtrl.latest = buffIndx;
sysMonitorInst->sendCtrl.wBusy = BUFF_NONE;
}
/**
* @brief Get the latest send payload.
*
* @param buff
* @param id
* @param len
*/
void SysMonitor_GetSendPayload(uint8_t *buff, uint32_t *id, size_t len)
{
ASSERT(sysMonitorInst != NULL);
ASSERT(buff != NULL);
ASSERT(id != NULL);
if (len > PAYLOAD_LEN_MAX)
{
return;
}
uint8_t buffIndx, buffIndex_old;
buffIndex_old = sysMonitorInst->sendCtrl.rBusy;
if (buffIndex_old != BUFF_NONE)
buffIndx = buffIndex_old; // Keep it busy
else
buffIndx = GetReadable(sysMonitorInst->sendCtrl);
sysMonitorInst->sendCtrl.rBusy = buffIndx;
if (sysMonitorInst->send[buffIndx].dataId != DATA_ID_NONE)
{
memcpy(buff, sysMonitorInst->send[buffIndx].data, len);
}
*id = sysMonitorInst->send[buffIndx].dataId;
sysMonitorInst->sendCtrl.rBusy = buffIndex_old;
}
/**
* @brief Update receive payload.
*
* @param buff
* @param id
* @param len
*/
void SysMonitor_UpdateRecvPayload(const uint8_t *buff, uint32_t id, size_t len)
{
ASSERT(sysMonitorInst != NULL);
ASSERT(buff != NULL);
if (id == DATA_ID_NONE || len > PAYLOAD_LEN_MAX)
{
return;
}
uint8_t buffIndx;
buffIndx = GetWritable(sysMonitorInst->recvCtrl);
sysMonitorInst->recvCtrl.wBusy = buffIndx;
memcpy(sysMonitorInst->recv[buffIndx].data, buff, len);
sysMonitorInst->recv[buffIndx].dataId = id;
sysMonitorInst->recvCtrl.latest = buffIndx;
sysMonitorInst->recvCtrl.wBusy = BUFF_NONE;
}
/**
* @brief Get the latest receive payload.
*
* @param buff
* @param id
* @param len
*/
void SysMonitor_GetRecvPayload(uint8_t *buff, uint32_t *id, size_t len)
{
ASSERT(sysMonitorInst != NULL);
ASSERT(buff != NULL);
ASSERT(id != NULL);
if (len > PAYLOAD_LEN_MAX)
{
return;
}
uint8_t buffIndx, buffIndex_old;
buffIndex_old = sysMonitorInst->recvCtrl.rBusy;
if (buffIndex_old != BUFF_NONE)
buffIndx = buffIndex_old; // Keep it busy
else
buffIndx = GetReadable(sysMonitorInst->recvCtrl);
sysMonitorInst->recvCtrl.rBusy = buffIndx;
if (sysMonitorInst->recv[buffIndx].dataId != DATA_ID_NONE)
{
memcpy(buff, sysMonitorInst->recv[buffIndx].data, len);
}
*id = sysMonitorInst->recv[buffIndx].dataId;
sysMonitorInst->recvCtrl.rBusy = buffIndex_old;
}
/** @} ServicePayload_API*/
/**
* @name Linklayer_Log_API
* @{
*/
/**
* @brief Update link layer log
*
* @param log
*/
void SysMonitor_UpdateLinklayerLog(const LINKLOG *log)
{
ASSERT(sysMonitorInst != NULL);
ASSERT(log != NULL);
uint8_t buffIndx;
buffIndx = GetWritable(sysMonitorInst->linkLogCtrl);
sysMonitorInst->linkLogCtrl.wBusy = buffIndx;
memcpy(&(sysMonitorInst->linkLog[buffIndx]), log, sizeof(LINKLOG));
sysMonitorInst->linkLogCtrl.latest = buffIndx;
sysMonitorInst->linkLogCtrl.wBusy = BUFF_NONE;
}
/**
* @brief Get the latest link layer log
*
* @param log
*/
void SysMonitor_GetLinklayerLog(LINKLOG *log)
{
ASSERT(sysMonitorInst != NULL);
ASSERT(log != NULL);
uint8_t buffIndx, buffIndex_old;
buffIndex_old = sysMonitorInst->linkLogCtrl.rBusy;
if (buffIndex_old != BUFF_NONE)
buffIndx = buffIndex_old; // Keep it busy
else
buffIndx = GetReadable(sysMonitorInst->linkLogCtrl);
sysMonitorInst->linkLogCtrl.rBusy = buffIndx;
memcpy(log, &(sysMonitorInst->linkLog[buffIndx]), sizeof(LINKLOG));
sysMonitorInst->linkLogCtrl.rBusy = buffIndex_old;
}
/** @} Linklayer_Log_API*/
/**
* @name PhysicalLayer_Log_API
* @{
*/
/**
* @brief Update physical layer log
*
* @param log
*/
void SysMonitor_UpdatePhysicalLayerLog(const PHYLOG *log)
{
ASSERT(sysMonitorInst != NULL);
ASSERT(log != NULL);
uint8_t buffIndx;
buffIndx = GetWritable(sysMonitorInst->phyLogCtrl);
sysMonitorInst->phyLogCtrl.wBusy = buffIndx;
memcpy(&(sysMonitorInst->phyLog[buffIndx]), log, sizeof(PHYLOG));
sysMonitorInst->phyLogCtrl.latest = buffIndx;
sysMonitorInst->phyLogCtrl.wBusy = BUFF_NONE;
}
/**
* @brief Get the latest physical layer log
*
* @param log
*/
void SysMonitor_GetPhysicalLayerLog(PHYLOG *log)
{
ASSERT(sysMonitorInst != NULL);
ASSERT(log != NULL);
uint8_t buffIndx, buffIndex_old;
buffIndex_old = sysMonitorInst->phyLogCtrl.rBusy;
if (buffIndex_old != BUFF_NONE)
buffIndx = buffIndex_old; // Keep it busy
else
buffIndx = GetReadable(sysMonitorInst->phyLogCtrl);
sysMonitorInst->phyLogCtrl.rBusy = buffIndx;
memcpy(log, &(sysMonitorInst->phyLog[buffIndx]), sizeof(PHYLOG));
sysMonitorInst->phyLogCtrl.rBusy = buffIndex_old;
}
/** @} */
/**
* @name HardwareState_Log_API
* @{
*/
/**
* @brief Log hardware running status.
*
* @param state
*/
void SysMonitor_UpdateHardwareStatus(const HWSTATE *state)
{
ASSERT(sysMonitorInst != NULL);
ASSERT(state != NULL);
uint8_t buffIndx;
buffIndx = GetWritable(sysMonitorInst->hwStateCtrl);
sysMonitorInst->hwStateCtrl.wBusy = buffIndx;
memcpy(&(sysMonitorInst->hwState[buffIndx]), state, sizeof(HWSTATE));
sysMonitorInst->hwStateCtrl.latest = buffIndx;
sysMonitorInst->hwStateCtrl.wBusy = BUFF_NONE;
}
/**
* @brief Get the latest hardware running status.
*
* @param state
*/
void SysMonitor_GetHardwareStatus(HWSTATE *state)
{
ASSERT(sysMonitorInst != NULL);
ASSERT(state != NULL);
uint8_t buffIndx, buffIndex_old;
buffIndex_old = sysMonitorInst->hwStateCtrl.rBusy;
if (buffIndex_old != BUFF_NONE)
buffIndx = buffIndex_old; // Keep it busy
else
buffIndx = GetReadable(sysMonitorInst->hwStateCtrl);
sysMonitorInst->hwStateCtrl.rBusy = buffIndx;
memcpy(state, &(sysMonitorInst->hwState[buffIndx]), sizeof(HWSTATE));
sysMonitorInst->hwStateCtrl.rBusy = buffIndex_old;
}
/** @} HardwareState_Log_API */
/** @} SystemMonitor*/
@@ -0,0 +1,241 @@
/**
* @defgroup SystemMonitor
* @{
*/
#ifndef __SYSTEM_MONITOR_H_
#define __SYSTEM_MONITOR_H_
/***************************** Include Files *********************************/
#include <stdint.h>
#include <stdbool.h>
#include "util.h"
/************************* Constant Definitions ******************************/
/**
* @name SystemMonitor_Constants
* @{
*/
#define PAYLOAD_LEN_MAX 256
#define PAYLOAD_LEN_FLJ_RX 168
#define PAYLOAD_LEN_FLJ_TX 66
#define PAYLOAD_LEN_LJ_RX 66
#define PAYLOAD_LEN_LJ_TX 168
#define DATA_ID_NONE UINT32_MAX
#define DATA_ID_TEST 0x02030203
#define VOLTAGE_LSB 0.01 // volt
#define VOLTAGE_MAX 2.55 // volt
#define VOLT_PS_STD 1.0
#define VOLT_PSAUX_STD 1.8
#define VOLT_DDR_STD 1.5
#define VOLT_PL_STD 1.0
#define VOLT_PLAUX_STD 1.8
#define VOLT_BRAM_STD 1.0
#define VOLT_PS_OK BIT(0)
#define VOLT_PSAUX_OK BIT(1)
#define VOLT_DDR_OK BIT(2)
#define VOLT_PL_OK BIT(3)
#define VOLT_PLAUX_OK BIT(4)
#define VOLT_BRAM_OK BIT(5)
#define VOLT_ANT_PROC_OK BIT(0)
#define VOLT_ANT_RF_OK BIT(2)
#define VOLT_ANT_NIL_OK BIT(4)
#define ANT_STATE_OK BIT(6)
// Xilinx Recommended
// #define IS_PS_VALID(x) (x <= 1.05 && x >= 0.95)
// #define IS_PSAUX_VALID(x) (x <= 1.89 && x >= 1.71)
// #define IS_DDR_VALID(x) (x <= 1.89 && x >= 1.14)
// #define IS_PL_VALID(x) (x <= 1.03 && x >= 0.97)
// #define IS_PLAUX_VALID(x) (x <= 1.89 && x >= 1.71)
// #define IS_BRAM_VALID(x) (x <= 1.03 && x >= 0.97)
#define IS_PS_VALID(x) (x <= 1.1 && x >= 0.9)
#define IS_PSAUX_VALID(x) (x <= 2.0 && x >= 1.6)
#define IS_DDR_VALID(x) (x <= 1.7 && x >= 1.3)
#define IS_PL_VALID(x) (x <= 1.1 && x >= 0.9)
#define IS_PLAUX_VALID(x) (x <= 2.0 && x >= 1.6)
#define IS_BRAM_VALID(x) (x <= 1.1 && x >= 0.9)
#define CLK_SP_PLL0_LOCK BIT(0)
#define CLK_SP_PLL1_LOCK BIT(2)
#define CLK_AD0_BBPLL_LOCK BIT(0)
#define CLK_AD0_RFPLL_LOCK BIT(2)
#define CLK_AD1_BBPLL_LOCK BIT(4)
#define CLK_AD1_RFPLL_LOCK BIT(6)
#define CLK_ANT_BBPLL_LOCK BIT(0)
#define CLK_ANT_RFPLL0_LOCK BIT(2)
#define CLK_ANT_RFPLL1_LOCK BIT(4)
#define TEMPERATURE_LSB 1.0 // Celsius degree
#define TEMPERATURE_MAX 127.0 // Celsius degree
#define TEMPERATURE_MIN -128.0 // Celsius degree
/** @} SystemMonitor_Constants */
/************************* Data Type Definitions ****************************/
/**
* @struct SYSINFO
* @brief System Infomation log
*/
typedef struct __attribute__((packed))
{
uint32_t psBDS; ///< -- unit: ms, 0~604799999
uint16_t pBDS; ///< -- unit: week, 0~0~8191
uint32_t psGPS; ///< -- unit: ms, 0~604799999
uint16_t pGPS; ///< -- unit: week, 0~0~8191
uint8_t tmInd; ///< Time validation indicator \n
// -- [0] GPS\n
// -- [1] reserve.\n
// -- [2] UTC\n
// -- [3] BDS\n
float tmFly; ///< Time of flying uint: s
uint8_t stFly; ///< Status of flying \n
// [7:6] departure status 11 - departed/00 - not departed \n
// [5:4] ready status 11 - ready/00 - not ready \n
// [3:2] attitude status 11 - attitude ok/00 - attitude not ok \n
// [1:0] attitude adjust status 11 - adjusted/00 - not adjusted
float posX; ///< coord X Position in launch coordinate system
float posY; ///< coord Y Position in launch coordinate system
float posZ; ///< coord Z Position in launch coordinate system
float vX; ///< Speed X in launch coordinate system
float vY; ///< Speed Y in launch coordinate system
float vZ; ///< Speed Z in launch coordinate system
float pitch; ///< Pitch Attitude in launch inertia coordinate system
float yaw; ///< Yaw Attitude in launch inertia coordinate system
float roll; ///< Roll Attitude in launch inertia coordinate system
} SYSINFO;
/**
* @struct SYSBUSLOG
* @brief System Info holds the system bus log
*/
typedef struct __attribute__((packed))
{
// SystemBus log
uint8_t lastConfig[2]; ///< Last valid config \n
// byte 0: 0x11 FLJ, 0x00 LJ \n
// byte 1: 0x66 Full Power, 0x88 Low Power
uint32_t pollCnt; ///< number of poll commands
uint32_t svcCnt; ///< number of service commands
uint32_t remoteCnt; ///< number of remote check commands
} SYSBUSLOG;
/**
* @struct LINKLOG
* @brief Linklayer Log struct holds the Linklayer log
*/
typedef struct __attribute__((packed))
{
// Network log
uint32_t tuNum; ///< current time unite number
uint8_t slotNum; ///< current slot number
uint8_t nodeType; ///< current node type
uint8_t cxnStatus; ///< current connection status
uint8_t linkStage; ///< current linklayer working stage
uint32_t recxnCnt; ///< reconnect trial count
uint8_t beamNo; ///< current working beam number
uint8_t beamWidth; ///< current working beam width
uint16_t beamAz; ///< current working beam angle Az
uint16_t beamEl; ///< current working beam angle Ez
uint16_t advTxCnt; ///< adv frame send count
uint16_t advRecvCnt; ///< adv frame received count
uint16_t advCorrectCnt; ///< adv frame received correctly count
uint32_t cfmTxCnt; ///< cfm frame send count
uint32_t cfmRecvCnt; ///< cfm frame received count
uint32_t cfmCorrectCnt; ///< adv frame received correctly count
uint32_t svcTxCnt; ///< svc frame send count
uint32_t svcRecvCnt; ///< svc frame received count
uint32_t svcCorrectCnt; ///< svc frame received correctly count
int32_t timeDev; ///< last time deviation result
uint32_t sendId; ///< last send data id
uint32_t recvId; ///< last received data id
uint8_t reserve[4]; ///< reserved data
} LINKLOG;
/**
* @struct PHYLOG
* @brief Physical Layer Log struct holds the Linklayer log
*/
typedef struct __attribute__((packed))
{
uint32_t acqCnt; ///< aquisition count
uint32_t fsyncCnt; ///< frame sync count
uint32_t decodeCnt; ///< decode count
uint32_t crcCnt; ///< crc valid count
double doppler; ///< last doppler estimation result
uint64_t recvStamp; ///< last frame arrival time
double acqPAPR; ///< last acquisition peak-average ration
uint8_t acqPhase; ///< last acquisition phase estimation
uint8_t acqFreqCh; ///< last acquisition frequency deviation estimation
double fsyncPAPR; ///< last frame sync peak-average ration
uint8_t fsyncFreqCh; ///< last frame sync frequency estimation
uint16_t deintlvAmpEst; ///< de-interleave amplitude estimation
uint8_t antMode; ///< current antenna working mode
uint8_t reserve[3]; ///< reserved data
} PHYLOG;
/**
* @struct HWSTATE
* @brief Hardware Status Log struct holds all hardware status
*/
typedef struct __attribute__((packed))
{
bool isSpOk; ///< signal processor state
bool isAntOk; ///< antenna state
// -- Signal processor status
uint8_t spFpgaVolt; ///< Signal processor voltage state indicator
uint8_t spClkState; ///< Signal processor clock state indicator
uint8_t spAdLockState; ///< Signal processor adc lock state indicator
uint8_t spAdTemp_0; ///< Signal processor adc0 temperature
uint8_t spAdTemp_1; ///< Signal processor adc1 temperature
uint8_t spFpgaTemp; ///< Signal processor FPGA temperature
// -- Antenna status
uint8_t antVolt; ///< Antenna voltage state indicator
uint8_t antTemp; ///< Antenna rf temperature
uint8_t antPll; ///< Antenna rf lock state indicator
uint8_t antMgc0; ///< Antenna rf mgc0~1 indicator
uint8_t antMgc1; ///< Antenna rf mgc2~3 indicator
uint8_t phyId;
uint8_t reserve[1];
} HWSTATE;
/**
* @struct PAYLOAD
* @brief Payload struct holds the service payload
*/
typedef struct
{
uint32_t dataId;
uint8_t data[PAYLOAD_LEN_MAX];
} PAYLOAD;
/************************** Function Prototypes ******************************/
int32_t SysMonitor_Init(void);
void SysMonitor_Destroy(void);
void SysMonitor_UpdateSysinfo(const SYSINFO *info);
void SysMonitor_GetSysinfo(SYSINFO *info);
void SysMonitor_UpdateSendPayload(const uint8_t *buff, size_t len);
void SysMonitor_UpdateRecvPayload(const uint8_t *buff, uint32_t id, size_t len);
void SysMonitor_GetSendPayload(uint8_t *buff, uint32_t *id, size_t len);
void SysMonitor_GetRecvPayload(uint8_t *buff, uint32_t *id, size_t len);
void SysMonitor_UpdateLinklayerLog(const LINKLOG *log);
void SysMonitor_UpdatePhysicalLayerLog(const PHYLOG *log);
void SysMonitor_UpdateHardwareStatus(const HWSTATE *state);
void SysMonitor_GetLinklayerLog(LINKLOG *log);
void SysMonitor_GetPhysicalLayerLog(PHYLOG *log);
void SysMonitor_GetHardwareStatus(HWSTATE *state);
#endif //__SYSTEM_MONITOR_H_
/** @} */
@@ -0,0 +1,134 @@
/*****************************************************************************/
/**
* @file circ_queue.c
* @author FanHao (hao_fan_bit_ee@163.com)
* @brief A simple circular FIFO bounded queue
* @version 0.1
* @date 2023-02-23
* @note Forked from https://github.com/chrismerck/rpa_queue.git
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
* Lab of Communication and Network
*
******************************************************************************/
/**
* @addtogroup Utility
* @{
*/
/**
* @addtogroup CircularQueue
* @{
*/
#include "circ_queue.h"
#include "common.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
inline bool isCircQueueFull(CIRC_QUEUE *queue)
{
ASSERT(queue != NULL);
return ((queue)->nelts == (queue)->bounds);
}
inline bool isCircQueueEmpty(CIRC_QUEUE *queue)
{
ASSERT(queue != NULL);
return ((queue)->nelts == 0);
}
void CircQueueFree(CIRC_QUEUE *queue)
{
ASSERT(queue != NULL);
if (queue->data)
free(queue->data);
free(queue);
}
/**
* @brief Initialize the CIRC_QUEUE.
*/
bool CircQueueCreate(CIRC_QUEUE **q, uint32_t queueCapacity)
{
ASSERT(q != NULL);
CIRC_QUEUE *queue;
queue = malloc(sizeof(CIRC_QUEUE));
if (!queue)
{
return false;
}
*q = queue;
memset(queue, 0, sizeof(CIRC_QUEUE));
/* Set all the data in the queue to NULL */
queue->data = malloc(queueCapacity * sizeof(void *));
if (queue->data == NULL)
{
goto error;
}
queue->bounds = queueCapacity;
queue->nelts = 0;
queue->in = 0;
queue->out = 0;
return true;
error:
free(queue);
return false;
}
/**
* @brief Push new data onto the queue.
*/
bool CircQueuePush(CIRC_QUEUE *queue, void *data)
{
ASSERT(queue != NULL);
if (isCircQueueFull(queue))
{
return false;
}
queue->data[queue->in] = data;
queue->in++;
if (queue->in >= queue->bounds)
{
queue->in -= queue->bounds;
}
queue->nelts++;
return true;
}
/**
* @brief Return current number of element in queue.
*/
inline uint32_t CircQueueSize(CIRC_QUEUE *queue)
{
return queue->nelts;
}
/**
* @brief Retrieves the next item from the queue.
*/
bool CircQueuePop(CIRC_QUEUE *queue, void **data)
{
ASSERT(queue != NULL);
if (isCircQueueEmpty(queue))
{
return false;
}
*data = queue->data[queue->out];
queue->nelts--;
queue->out++;
if (queue->out >= queue->bounds)
{
queue->out -= queue->bounds;
}
return true;
}
/** @} CircularQueue*/
/** @} Utility*/
@@ -0,0 +1,353 @@
/*****************************************************************************/
/**
* @file clist.c
* @author FanHao (hao_fan_bit_ee@163.com)
* @brief A basic list data structure
* @version 0.1
* @date 2023-02-23
* @note Forked from https://github.com/clibs/list
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
* Lab of Communication and Network
*
******************************************************************************/
/**
* @addtogroup Utility
* @{
*/
/**
* @addtogroup cList
* @{
*/
#ifndef LIST_MALLOC
#define LIST_MALLOC malloc
#endif
#ifndef LIST_FREE
#define LIST_FREE free
#endif
#include <stdint.h>
#include "clist.h"
/**
* @brief a new clist_node_t. NULL on failure.
*/
clist_node_t *
clist_node_new(void *val)
{
clist_node_t *self;
if (!(self = LIST_MALLOC(sizeof(clist_node_t))))
return NULL;
self->prev = NULL;
self->next = NULL;
self->val = val;
return self;
}
/**
* @brief Allocate a new clist_t. NULL on failure.
*/
clist_t *
clist_new(void)
{
clist_t *self;
if (!(self = LIST_MALLOC(sizeof(clist_t))))
return NULL;
self->head = NULL;
self->tail = NULL;
self->free = NULL;
self->compare = NULL;
self->len = 0;
return self;
}
/**
* @brief Remove all the node in list.
* @param self: Pointer to the list
*/
void clist_clear(clist_t *self)
{
clist_node_t *next;
clist_node_t *curr = self->head;
while (curr != NULL)
{
next = curr->next;
if (self->free)
self->free(curr->val);
LIST_FREE(curr);
curr = next;
}
self->len = 0;
self->head = NULL;
}
/**
* @brief Free the list.
* @param self: Pointer to the list
*/
void clist_destroy(clist_t *self)
{
clist_clear(self);
LIST_FREE(self);
}
/**
* @brief Append the given node to the list and return the node, NULL on failure.
* @param self: Pointer to the list for popping node
* @param node: the node to push
*/
clist_node_t *
clist_rpush(clist_t *self, clist_node_t *node)
{
if (!node)
return NULL;
if (self->len)
{
node->prev = self->tail;
node->next = NULL;
self->tail->next = node;
self->tail = node;
}
else
{
self->head = self->tail = node;
node->prev = node->next = NULL;
}
++self->len;
return node;
}
/**
* @brief Return / detach the last node in the list, or NULL.
* @param self: Pointer to the list for popping node
*/
clist_node_t *
clist_rpop(clist_t *self)
{
if (!self->len)
return NULL;
clist_node_t *node = self->tail;
if (--self->len)
{
(self->tail = node->prev)->next = NULL;
}
else
{
self->tail = self->head = NULL;
}
node->next = node->prev = NULL;
return node;
}
/**
* @brief Return / detach the first node in the list, or NULL.
* @param self: Pointer to the list for popping node
*/
clist_node_t *
clist_lpop(clist_t *self)
{
if (!self->len)
return NULL;
clist_node_t *node = self->head;
if (--self->len)
{
(self->head = node->next)->prev = NULL;
}
else
{
self->head = self->tail = NULL;
}
node->next = node->prev = NULL;
return node;
}
/**
* @brief Prepend the given node to the list and return the node, NULL on failure.
* @param self: Pointer to the list for pushing node
* @param node: the node to push
*/
clist_node_t *
clist_lpush(clist_t *self, clist_node_t *node)
{
if (!node)
return NULL;
if (self->len)
{
node->next = self->head;
node->prev = NULL;
self->head->prev = node;
self->head = node;
}
else
{
self->head = self->tail = node;
node->prev = node->next = NULL;
}
++self->len;
return node;
}
/**
* @brief Return the node associated to val or NULL.
* @param self: Pointer to the list for finding given value
* @param val: Value to find
*/
clist_node_t *
clist_find(clist_t *self, void *val)
{
clist_iterator_t *it = clist_iterator_new(self, LIST_HEAD);
clist_node_t *node;
while ((node = clist_iterator_next(it)))
{
if (self->compare)
{
if (self->compare(val, node->val) == 0)
{
clist_iterator_destroy(it);
return node;
}
}
else
{
if (val == node->val)
{
clist_iterator_destroy(it);
return node;
}
}
}
clist_iterator_destroy(it);
return NULL;
}
/**
* @brief Return the node at the given index or NULL.
* @param self: Pointer to the list for finding given index
* @param index: the index of node in the list
*/
clist_node_t *
clist_at(clist_t *self, int index)
{
clist_direction_t direction = LIST_HEAD;
if (index < 0)
{
direction = LIST_TAIL;
index = ~index;
}
if ((unsigned)index < self->len)
{
clist_iterator_t *it = clist_iterator_new(self, direction);
clist_node_t *node = clist_iterator_next(it);
while (index--)
node = clist_iterator_next(it);
clist_iterator_destroy(it);
return node;
}
return NULL;
}
/**
* @brief Remove the given node from the list, freeing it and it's value.
* @param self: Pointer to the list to delete a node
* @param node: Pointer the node to be deleted
*/
void clist_remove(clist_t *self, clist_node_t *node)
{
node->prev
? (node->prev->next = node->next)
: (self->head = node->next);
node->next
? (node->next->prev = node->prev)
: (self->tail = node->prev);
if (self->free)
self->free(node->val);
LIST_FREE(node);
--self->len;
}
/**
* @brief Allocate a new clist_iterator_t. NULL on failure.\n
* Accepts a direction, which may be LIST_HEAD or LIST_TAIL.
*/
clist_iterator_t *
clist_iterator_new(clist_t *list, clist_direction_t direction)
{
clist_node_t *node = direction == LIST_HEAD
? list->head
: list->tail;
return clist_iterator_new_from_node(node, direction);
}
/**
* @brief Allocate a new clist_iterator_t with the given start
* node. NULL on failure.
*/
clist_iterator_t *
clist_iterator_new_from_node(clist_node_t *node, clist_direction_t direction)
{
clist_iterator_t *self;
if (!(self = LIST_MALLOC(sizeof(clist_iterator_t))))
return NULL;
self->next = node;
self->direction = direction;
return self;
}
/**
* @brief Return the next clist_node_t or NULL when no more
* nodes remain in the list.
*/
clist_node_t *
clist_iterator_next(clist_iterator_t *self)
{
clist_node_t *curr = self->next;
if (curr)
{
self->next = self->direction == LIST_HEAD
? curr->next
: curr->prev;
}
return curr;
}
/**
* @brief Free the list iterator.
*/
void clist_iterator_destroy(clist_iterator_t *self)
{
LIST_FREE(self);
self = NULL;
}
/** @} cList*/
/** @} Utility*/
@@ -0,0 +1,51 @@
/*****************************************************************************/
/**
* Description: Common functions
*
* Date: 2021-11-16 00:08
* LastEditors: Fan Hao
* LastEditTime: 2022-07-16 17:13
* Revisions: Rev 0.1
* History:
* [2022-07-16]: New branch for Dijian.
* [2021-11-16]: Initial version.
*
* Copyright(c) 2024 Beijing Institute of Technology.
* Lab of Communication and Networking
*
******************************************************************************/
/**
* @addtogroup COMMON_MACRO
* @{
*/
/***************************** Include Files *********************************/
#include "common.h"
#include "error.h"
#include "util.h"
/************************** Constant Definitions *****************************/
/***************** Macros (Inline Functions) Definitions *********************/
/**************************** Type Definitions *******************************/
/************************** Variable Definitions *****************************/
/*****************************************************************************/
/**
* @brief Throw an assert.
*
* @param file indicate the filename of the assertion
* @param line indicate which line the assertion occurs
*
* @return NONE.
*
******************************************************************************/
void AppAssert(const char *file, int line)
{
DBG_PRINT("in %s:%d [assert] .\n", file, line);
while (1)
;
}
/** @} */
@@ -0,0 +1,444 @@
/*****************************************************************************/
/**
* Description: CRC implementation file
*
* Author: Hao Fan
* Date: 2021-11-16 00:50
* LastEditors: Hao Fan
* LastEditTime: 2022-07-17 20:53
* Revisions: Rev 0.0
* History:
* [2022-07-17]: Add CRC16_0x8005 CRC8_0x31.
* [2022-01-06]: Initial verion (Basic CRC-16).
*
* Copyright(c) 2024 Beijing Institute of Technology.
* Lab of Communication and Networking
*
******************************************************************************/
/**
* @addtogroup Utility
* @{
*/
#include "util.h"
#include "error.h"
#ifdef __CRC_LSB
// CRC-16-CCITT G(X)=X16+X12+X5+1
// Reversed
static const uint16_t crc16_1021_lsb_lut[256] =
{
0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
};
// CRC-16-MAXIM G(X)=X16+X15+X2+1
const uint16_t crc16_8005_lsb_lut[256] =
{
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
};
// CRC-8-MAXIM G(X)=X8+X5+X4+1
const uint8_t crc8_31_lsb_lut[256] =
{
0x00, 0x5E, 0xBC, 0xE2, 0x61, 0x3F, 0xDD, 0x83,
0xC2, 0x9C, 0x7E, 0x20, 0xA3, 0xFD, 0x1F, 0x41,
0x9D, 0xC3, 0x21, 0x7F, 0xFC, 0xA2, 0x40, 0x1E,
0x5F, 0x01, 0xE3, 0xBD, 0x3E, 0x60, 0x82, 0xDC,
0x23, 0x7D, 0x9F, 0xC1, 0x42, 0x1C, 0xFE, 0xA0,
0xE1, 0xBF, 0x5D, 0x03, 0x80, 0xDE, 0x3C, 0x62,
0xBE, 0xE0, 0x02, 0x5C, 0xDF, 0x81, 0x63, 0x3D,
0x7C, 0x22, 0xC0, 0x9E, 0x1D, 0x43, 0xA1, 0xFF,
0x46, 0x18, 0xFA, 0xA4, 0x27, 0x79, 0x9B, 0xC5,
0x84, 0xDA, 0x38, 0x66, 0xE5, 0xBB, 0x59, 0x07,
0xDB, 0x85, 0x67, 0x39, 0xBA, 0xE4, 0x06, 0x58,
0x19, 0x47, 0xA5, 0xFB, 0x78, 0x26, 0xC4, 0x9A,
0x65, 0x3B, 0xD9, 0x87, 0x04, 0x5A, 0xB8, 0xE6,
0xA7, 0xF9, 0x1B, 0x45, 0xC6, 0x98, 0x7A, 0x24,
0xF8, 0xA6, 0x44, 0x1A, 0x99, 0xC7, 0x25, 0x7B,
0x3A, 0x64, 0x86, 0xD8, 0x5B, 0x05, 0xE7, 0xB9,
0x8C, 0xD2, 0x30, 0x6E, 0xED, 0xB3, 0x51, 0x0F,
0x4E, 0x10, 0xF2, 0xAC, 0x2F, 0x71, 0x93, 0xCD,
0x11, 0x4F, 0xAD, 0xF3, 0x70, 0x2E, 0xCC, 0x92,
0xD3, 0x8D, 0x6F, 0x31, 0xB2, 0xEC, 0x0E, 0x50,
0xAF, 0xF1, 0x13, 0x4D, 0xCE, 0x90, 0x72, 0x2C,
0x6D, 0x33, 0xD1, 0x8F, 0x0C, 0x52, 0xB0, 0xEE,
0x32, 0x6C, 0x8E, 0xD0, 0x53, 0x0D, 0xEF, 0xB1,
0xF0, 0xAE, 0x4C, 0x12, 0x91, 0xCF, 0x2D, 0x73,
0xCA, 0x94, 0x76, 0x28, 0xAB, 0xF5, 0x17, 0x49,
0x08, 0x56, 0xB4, 0xEA, 0x69, 0x37, 0xD5, 0x8B,
0x57, 0x09, 0xEB, 0xB5, 0x36, 0x68, 0x8A, 0xD4,
0x95, 0xCB, 0x29, 0x77, 0xF4, 0xAA, 0x48, 0x16,
0xE9, 0xB7, 0x55, 0x0B, 0x88, 0xD6, 0x34, 0x6A,
0x2B, 0x75, 0x97, 0xC9, 0x4A, 0x14, 0xF6, 0xA8,
0x74, 0x2A, 0xC8, 0x96, 0x15, 0x4B, 0xA9, 0xF7,
0xB6, 0xE8, 0x0A, 0x54, 0xD7, 0x89, 0x6B, 0x35
};
#else
// CRC-16-CCITT G(X)=X16+X12+X5+1
static const uint16_t crc16_1021_msb_lut[256] =
{
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
};
// CRC-16-MAXIM G(X)=X16+X15+X2+1
const uint16_t crc16_8005_msb_lut[256] =
{
0x0000, 0x8005, 0x800F, 0x000A, 0x801B, 0x001E, 0x0014, 0x8011,
0x8033, 0x0036, 0x003C, 0x8039, 0x0028, 0x802D, 0x8027, 0x0022,
0x8063, 0x0066, 0x006C, 0x8069, 0x0078, 0x807D, 0x8077, 0x0072,
0x0050, 0x8055, 0x805F, 0x005A, 0x804B, 0x004E, 0x0044, 0x8041,
0x80C3, 0x00C6, 0x00CC, 0x80C9, 0x00D8, 0x80DD, 0x80D7, 0x00D2,
0x00F0, 0x80F5, 0x80FF, 0x00FA, 0x80EB, 0x00EE, 0x00E4, 0x80E1,
0x00A0, 0x80A5, 0x80AF, 0x00AA, 0x80BB, 0x00BE, 0x00B4, 0x80B1,
0x8093, 0x0096, 0x009C, 0x8099, 0x0088, 0x808D, 0x8087, 0x0082,
0x8183, 0x0186, 0x018C, 0x8189, 0x0198, 0x819D, 0x8197, 0x0192,
0x01B0, 0x81B5, 0x81BF, 0x01BA, 0x81AB, 0x01AE, 0x01A4, 0x81A1,
0x01E0, 0x81E5, 0x81EF, 0x01EA, 0x81FB, 0x01FE, 0x01F4, 0x81F1,
0x81D3, 0x01D6, 0x01DC, 0x81D9, 0x01C8, 0x81CD, 0x81C7, 0x01C2,
0x0140, 0x8145, 0x814F, 0x014A, 0x815B, 0x015E, 0x0154, 0x8151,
0x8173, 0x0176, 0x017C, 0x8179, 0x0168, 0x816D, 0x8167, 0x0162,
0x8123, 0x0126, 0x012C, 0x8129, 0x0138, 0x813D, 0x8137, 0x0132,
0x0110, 0x8115, 0x811F, 0x011A, 0x810B, 0x010E, 0x0104, 0x8101,
0x8303, 0x0306, 0x030C, 0x8309, 0x0318, 0x831D, 0x8317, 0x0312,
0x0330, 0x8335, 0x833F, 0x033A, 0x832B, 0x032E, 0x0324, 0x8321,
0x0360, 0x8365, 0x836F, 0x036A, 0x837B, 0x037E, 0x0374, 0x8371,
0x8353, 0x0356, 0x035C, 0x8359, 0x0348, 0x834D, 0x8347, 0x0342,
0x03C0, 0x83C5, 0x83CF, 0x03CA, 0x83DB, 0x03DE, 0x03D4, 0x83D1,
0x83F3, 0x03F6, 0x03FC, 0x83F9, 0x03E8, 0x83ED, 0x83E7, 0x03E2,
0x83A3, 0x03A6, 0x03AC, 0x83A9, 0x03B8, 0x83BD, 0x83B7, 0x03B2,
0x0390, 0x8395, 0x839F, 0x039A, 0x838B, 0x038E, 0x0384, 0x8381,
0x0280, 0x8285, 0x828F, 0x028A, 0x829B, 0x029E, 0x0294, 0x8291,
0x82B3, 0x02B6, 0x02BC, 0x82B9, 0x02A8, 0x82AD, 0x82A7, 0x02A2,
0x82E3, 0x02E6, 0x02EC, 0x82E9, 0x02F8, 0x82FD, 0x82F7, 0x02F2,
0x02D0, 0x82D5, 0x82DF, 0x02DA, 0x82CB, 0x02CE, 0x02C4, 0x82C1,
0x8243, 0x0246, 0x024C, 0x8249, 0x0258, 0x825D, 0x8257, 0x0252,
0x0270, 0x8275, 0x827F, 0x027A, 0x826B, 0x026E, 0x0264, 0x8261,
0x0220, 0x8225, 0x822F, 0x022A, 0x823B, 0x023E, 0x0234, 0x8231,
0x8213, 0x0216, 0x021C, 0x8219, 0x0208, 0x820D, 0x8207, 0x0202
};
// CRC-8-MAXIM G(X)=X8+X5+X4+1
const uint8_t crc8_31_msb_lut[256] =
{
0x00, 0x31, 0x62, 0x53, 0xC4, 0xF5, 0xA6, 0x97,
0xB9, 0x88, 0xDB, 0xEA, 0x7D, 0x4C, 0x1F, 0x2E,
0x43, 0x72, 0x21, 0x10, 0x87, 0xB6, 0xE5, 0xD4,
0xFA, 0xCB, 0x98, 0xA9, 0x3E, 0x0F, 0x5C, 0x6D,
0x86, 0xB7, 0xE4, 0xD5, 0x42, 0x73, 0x20, 0x11,
0x3F, 0x0E, 0x5D, 0x6C, 0xFB, 0xCA, 0x99, 0xA8,
0xC5, 0xF4, 0xA7, 0x96, 0x01, 0x30, 0x63, 0x52,
0x7C, 0x4D, 0x1E, 0x2F, 0xB8, 0x89, 0xDA, 0xEB,
0x3D, 0x0C, 0x5F, 0x6E, 0xF9, 0xC8, 0x9B, 0xAA,
0x84, 0xB5, 0xE6, 0xD7, 0x40, 0x71, 0x22, 0x13,
0x7E, 0x4F, 0x1C, 0x2D, 0xBA, 0x8B, 0xD8, 0xE9,
0xC7, 0xF6, 0xA5, 0x94, 0x03, 0x32, 0x61, 0x50,
0xBB, 0x8A, 0xD9, 0xE8, 0x7F, 0x4E, 0x1D, 0x2C,
0x02, 0x33, 0x60, 0x51, 0xC6, 0xF7, 0xA4, 0x95,
0xF8, 0xC9, 0x9A, 0xAB, 0x3C, 0x0D, 0x5E, 0x6F,
0x41, 0x70, 0x23, 0x12, 0x85, 0xB4, 0xE7, 0xD6,
0x7A, 0x4B, 0x18, 0x29, 0xBE, 0x8F, 0xDC, 0xED,
0xC3, 0xF2, 0xA1, 0x90, 0x07, 0x36, 0x65, 0x54,
0x39, 0x08, 0x5B, 0x6A, 0xFD, 0xCC, 0x9F, 0xAE,
0x80, 0xB1, 0xE2, 0xD3, 0x44, 0x75, 0x26, 0x17,
0xFC, 0xCD, 0x9E, 0xAF, 0x38, 0x09, 0x5A, 0x6B,
0x45, 0x74, 0x27, 0x16, 0x81, 0xB0, 0xE3, 0xD2,
0xBF, 0x8E, 0xDD, 0xEC, 0x7B, 0x4A, 0x19, 0x28,
0x06, 0x37, 0x64, 0x55, 0xC2, 0xF3, 0xA0, 0x91,
0x47, 0x76, 0x25, 0x14, 0x83, 0xB2, 0xE1, 0xD0,
0xFE, 0xCF, 0x9C, 0xAD, 0x3A, 0x0B, 0x58, 0x69,
0x04, 0x35, 0x66, 0x57, 0xC0, 0xF1, 0xA2, 0x93,
0xBD, 0x8C, 0xDF, 0xEE, 0x79, 0x48, 0x1B, 0x2A,
0xC1, 0xF0, 0xA3, 0x92, 0x05, 0x34, 0x67, 0x56,
0x78, 0x49, 0x1A, 0x2B, 0xBC, 0x8D, 0xDE, 0xEF,
0x82, 0xB3, 0xE0, 0xD1, 0x46, 0x77, 0x24, 0x15,
0x3B, 0x0A, 0x59, 0x68, 0xFF, 0xCE, 0x9D, 0xAC
};
#endif
/* CRC lookup table algorithm
#define CRC_BIT_NUM 8u/16u/32u/64u
#define BITS_IN_BYTE 8u
uint8_t dataBuff[ARRAY_SIZE] = { 0x32, 0x33, …};
uint8_t/uint16_t/uint32_t crc_val = 0x0;
// LSB
for(int i = 0; i < sizeof(dataBuff); i++)
{
crc_val = (crc_val >> BITS_IN_BYTE) ^ crc_lsb_lut[(uint8)(crc_val^dataBuff[i])];
}
// MSB
for(int i = 0; i < sizeof(dataBuff); i++)
{
crc_val = (crc_val << BITS_IN_BYTE) ^ crc_msb_lut[(uint8)((crc_val>>8)^dataBuff[i])];
}
*/
/*****************************************************************************/
/**
* @brief CRC8 generator
*
* @param buffPtr data buffer pointer.
* @param dataLen data length
* @param poly polynomials of crc
* @param crcVal a pointer to store generated crc value
*
* @return SUCCESS
* FAILURE
*
******************************************************************************/
int crc8_gen(uint8_t *buffPtr, uint32_t dataLen, uint16_t poly, uint8_t *crcVal)
{
uint8_t crc = CRC8_INIT;
const uint8_t *crc_lut = NULL;
switch (poly)
{
#ifdef __CRC_LSB
case 0x31:
crc_lut = crc8_31_lsb_lut;
break;
default:
return FAILURE;
#else
case 0x31:
crc_lut = crc8_31_msb_lut;
break;
default:
return FAILURE;
#endif
}
for (int i = 0; i < dataLen; i++)
{
crc = crc_lut[(uint8_t)(crc ^ buffPtr[i])];
}
*crcVal = crc;
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief CRC16 generator
*
* @param buffPtr data buffer pointer.
* @param dataLen data length
* @param poly polynomials of crc
* @param crcVal a pointer to store generated crc value
*
* @return SUCCESS
* FAILURE
*
******************************************************************************/
int crc16_gen(uint8_t *buffPtr, uint32_t dataLen, uint16_t poly, uint16_t *crcVal)
{
uint16_t crc = CRC16_INIT;
const uint16_t *crc_lut = NULL;
switch (poly)
{
#ifdef __CRC_LSB
case 0x8005:
crc_lut = crc16_8005_lsb_lut;
break;
case 0x1021:
crc_lut = crc16_1021_lsb_lut;
break;
default:
return FAILURE;
#else
case 0x8005:
crc_lut = crc16_8005_msb_lut;
break;
case 0x1021:
crc_lut = crc16_1021_msb_lut;
break;
default:
return FAILURE;
#endif
}
for (int i = 0; i < dataLen; i++)
{
#ifdef __CRC_LSB
crc = (crc >> 8) ^ crc_lut[(uint8_t)(crc ^ buffPtr[i])];
#else
crc = (crc << 8) ^ crc_lut[(uint8_t)((crc >> 8) ^ buffPtr[i])];
#endif
}
*crcVal = crc;
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief CRC8 compare cheker
*
* @param buffPtr data buffer pointer.
* @param dataLen data length
* @param crcOffset byte offset of crc stored position.
* @param poly polynomials of crc
*
* @return true
* false
*
******************************************************************************/
bool crc8_check(uint8_t *buffPtr, uint32_t dataLen, uint32_t crcOffset, uint16_t poly)
{
int Status = SUCCESS;
uint8_t crc_comp;
uint8_t crc;
if (dataLen == 0)
{
return false;
}
crc_comp = (uint8_t)(*(buffPtr + crcOffset));
Status = crc8_gen(buffPtr, dataLen, poly, &crc);
if (Status == SUCCESS)
{
if (crc == crc_comp)
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
/*****************************************************************************/
/**
* @brief CRC16 compare cheker
*
* @param buffPtr data buffer pointer.
* @param dataLen data length
* @param crcOffset byte offset of crc stored position.
* @param poly polynomials of crc
*
* @return true
* fasle
*
******************************************************************************/
bool crc16_check(uint8_t *buffPtr, uint32_t dataLen, uint32_t crcOffset, uint16_t poly)
{
int Status = SUCCESS;
uint16_t crc_comp;
uint16_t crc;
if (dataLen == 0)
{
return false;
}
crc_comp = (uint16_t)(*(buffPtr + crcOffset));
crc_comp |= (uint16_t)((*(buffPtr + crcOffset + 1)) << 8);
Status = crc16_gen(buffPtr, dataLen, poly, &crc);
if (Status == SUCCESS)
{
if (crc == crc_comp)
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
/** @}*/
@@ -0,0 +1,886 @@
/*******************************************************************************
* @file list.c
* @brief List library implementation
* @author Mihail Chindris (mihail.chindris@analog.com)
********************************************************************************
* Copyright 2020(c) Analog Devices, 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:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 Files **********************************/
/******************************************************************************/
#include "list.h"
#include "error.h"
#include <stdlib.h>
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
/**
* @struct list_elem
* @brief Format of each element of the list
*/
struct list_elem
{
/** User data */
void *data;
/** Reference to previous element */
struct list_elem *prev;
/** Reference to next element */
struct list_elem *next;
};
/**
* @struct list_iterator
* @brief Structure used to iterate through the list
*/
struct iterator
{
/** List reference */
struct _list_desc *list;
/** Current element reference */
struct list_elem *elem;
};
/**
* @struct _list_desc
* @brief List descriptor
*/
struct _list_desc
{
/** Reference to first element in the list */
struct list_elem *first;
/** Reference to last element in the list*/
struct list_elem *last;
/** Number of elements in the list */
uint32_t nb_elements;
/** Function used to compare elements */
f_cmp comparator;
/** Number of current active iterators */
uint32_t nb_iterators;
/** Internal list iterator */
struct iterator l_it;
};
/** @brief Default function used to compare element in the list ( \ref f_cmp) */
static int32_t default_comparator(void *data1, void *data2)
{
return (int32_t)((int32_t *)data1 - (int32_t *)data2);
}
/**
* @brief Creates a new list elements an configure its value
* @param data - To set list_elem.data
* @param prev - To set list_elem.prev
* @param next - To set list_elem.next
* @return Address of the new element or NULL if allocation fails.
*/
static inline struct list_elem *create_element(void *data,
struct list_elem *prev,
struct list_elem *next)
{
struct list_elem *elem;
elem = (struct list_elem *)calloc(1, sizeof(*elem));
if (!elem)
return NULL;
elem->data = data;
elem->prev = prev;
elem->next = next;
return (elem);
}
/**
* @brief Updates the necesary link on the list elements to add or remove one
* @param prev - Low element
* @param elem - Middle element
* @param next - High element
*/
static inline void update_links(struct list_elem *prev, struct list_elem *elem,
struct list_elem *next)
{
if (prev)
prev->next = elem ? elem : next;
if (elem)
{
elem->prev = prev;
elem->next = next;
}
if (next)
next->prev = elem ? elem : prev;
}
/**
* @brief Update according to modification the list descriptor
* @param list - List reference
* @param new_first - New first element
* @param new_last - New last element
*/
static inline void update_desc(struct _list_desc *list,
struct list_elem *new_first,
struct list_elem *new_last)
{
if (new_first == list->first)
{
list->last = new_last;
if (new_first == NULL || new_last == NULL)
list->first = new_last;
}
else
{ /* if (new_last == list->last) */
list->first = new_first;
if (new_last == NULL || new_first == NULL)
list->last = new_first;
}
}
/**
* @brief Set the adapter functions acording to the adapter type
* @param ad - Reference of the adapter
* @param type - Type of the adapter
*/
static inline void set_adapter(struct list_desc *ad, enum adapter_type type)
{
switch (type)
{
case LIST_PRIORITY_LIST:
ad->push = list_add_find;
ad->pop = list_get_first;
ad->top_next = list_read_first;
ad->back = list_read_last;
ad->swap = list_edit_first;
break;
case LIST_QUEUE:
ad->push = list_add_last;
ad->pop = list_get_first;
ad->top_next = list_read_first;
ad->back = list_read_last;
ad->swap = list_edit_first;
break;
case LIST_DEFAULT:
case LIST_STACK:
default:
ad->push = list_add_last;
ad->pop = list_get_last;
ad->top_next = list_read_last;
ad->back = list_read_first;
ad->swap = list_edit_last;
break;
}
}
/**
* @brief Create a new empty list
* @param list_desc - Where to store the reference of the new created list
* @param type - Type of adapter to use.
* @param comparator - Used to compare item when using an ordered list or when
* using the \em find functions.
* @return
* - \ref SUCCESS : On success
* - \ref FAILURE : Otherwise
*/
int32_t list_init(struct list_desc **list_desc, enum adapter_type type,
f_cmp comparator)
{
struct list_desc *l_desc;
struct _list_desc *list;
if (!list_desc)
return FAILURE;
l_desc = (struct list_desc *)calloc(1, sizeof(*l_desc));
if (!l_desc)
return FAILURE;
list = (struct _list_desc *)calloc(1, sizeof(*list));
if (!list)
{
free(l_desc);
return FAILURE;
}
*list_desc = l_desc;
l_desc->priv_desc = list;
list->comparator = comparator ? comparator : default_comparator;
/* Configure wrapper */
set_adapter(l_desc, type);
list->l_it.list = list;
return SUCCESS;
}
/**
* @brief Remove the created list.
*
* All its elements will be cleared and the data inside each will be lost. If
* not all iterators have been removed, the list will not be removed.
* @param list_desc - Reference to the list
* @return
* - \ref SUCCESS : On success
* - \ref FAILURE : Otherwise
*/
int32_t list_remove(struct list_desc *list_desc)
{
void *data;
struct _list_desc *list;
if (!list_desc)
return FAILURE;
list = list_desc->priv_desc;
if (list->nb_iterators != 0)
return FAILURE;
/* Remove all the elements */
while (SUCCESS == list_get_first(list_desc, &data))
;
free(list_desc->priv_desc);
free(list_desc);
return SUCCESS;
}
/**
* @brief Get the number of elements inside the list
* @param list_desc - List reference
* @param out_size - Where to store the number of elements
* @return
* - \ref SUCCESS : On success
* - \ref FAILURE : Otherwise
*/
int32_t list_get_size(struct list_desc *list_desc, uint32_t *out_size)
{
struct _list_desc *list;
if (!list_desc || !out_size)
return FAILURE;
list = list_desc->priv_desc;
*out_size = list->nb_elements;
return SUCCESS;
}
/** @brief Add element at the begining of the list. Refer to \ref f_add */
int32_t list_add_first(struct list_desc *list_desc, void *data)
{
struct list_elem *prev;
struct list_elem *next;
struct list_elem *elem;
struct _list_desc *list;
if (!list_desc)
return FAILURE;
list = list_desc->priv_desc;
prev = NULL;
next = list->first;
elem = create_element(data, prev, next);
if (!elem)
return FAILURE;
update_links(prev, elem, next);
update_desc(list, elem, list->last);
list->nb_elements++;
return SUCCESS;
}
/** @brief Add element at the end of the list. Refer to \ref f_add */
int32_t list_add_last(struct list_desc *list_desc, void *data)
{
struct list_elem *prev;
struct list_elem *next;
struct list_elem *elem;
struct _list_desc *list;
if (!list_desc)
return FAILURE;
list = list_desc->priv_desc;
prev = list->last;
next = NULL;
elem = create_element(data, prev, next);
if (!elem)
return FAILURE;
update_links(prev, elem, next);
update_desc(list, list->first, elem);
list->nb_elements++;
return SUCCESS;
}
/** @brief Add element at the specified idx. Refer to \ref f_add */
int32_t list_add_idx(struct list_desc *list_desc, void *data, uint32_t idx)
{
struct _list_desc *list;
if (!list_desc)
return FAILURE;
list = list_desc->priv_desc;
/* If there are no elements the creation of an iterator will fail */
if (list->nb_elements == 0 || idx == 0)
return list_add_first(list_desc, data);
if (list->nb_elements == idx)
return list_add_last(list_desc, data);
list->l_it.elem = list->first;
if (SUCCESS != iterator_move(&(list->l_it), idx))
return FAILURE;
return iterator_insert(&(list->l_it), data, 0);
}
/** @brief Add element in ascending order. Refer to \ref f_add */
int32_t list_add_find(struct list_desc *list_desc, void *data)
{
struct list_elem *elem;
struct _list_desc *list;
if (!list_desc)
return FAILURE;
list = list_desc->priv_desc;
/* Based on place iterator */
elem = list->first;
while (elem)
{
if (0 < list->comparator(elem->data, data))
break;
elem = elem->next;
}
if (elem == NULL)
{
list->l_it.elem = list->last;
return iterator_insert(&(list->l_it), data, 1);
}
else
{
list->l_it.elem = elem;
return iterator_insert(&(list->l_it), data, 0);
}
}
/** @brief Edit the first element of the list. Refer to \ref f_edit */
int32_t list_edit_first(struct list_desc *list_desc, void *new_data)
{
struct _list_desc *list;
if (!list_desc)
return FAILURE;
list = list_desc->priv_desc;
list->first->data = new_data;
return SUCCESS;
}
/** @brief Edit the last element of the list. Refer to \ref f_edit */
int32_t list_edit_last(struct list_desc *list_desc, void *new_data)
{
struct _list_desc *list;
if (!list_desc)
return FAILURE;
list = list_desc->priv_desc;
list->last->data = new_data;
return SUCCESS;
}
/** @brief Edit the element at the specified idx. Refer to \ref f_edit */
int32_t list_edit_idx(struct list_desc *list_desc, void *new_data, uint32_t idx)
{
struct _list_desc *list;
if (!list_desc)
return FAILURE;
list = list_desc->priv_desc;
list->l_it.elem = list->first;
if (SUCCESS != iterator_move(&(list->l_it), idx))
return FAILURE;
return iterator_edit(&(list->l_it), new_data);
}
/** @brief Edit the element which match with cmp_data. Refer to \ref f_edit */
int32_t list_edit_find(struct list_desc *list_desc, void *new_data,
void *cmp_data)
{
struct _list_desc *list;
if (!list_desc)
return FAILURE;
list = list_desc->priv_desc;
list->l_it.elem = list->first;
if (SUCCESS != iterator_find(&(list->l_it), cmp_data))
return FAILURE;
return iterator_edit(&(list->l_it), new_data);
}
/** @brief Read the first element of the list. Refer to \ref f_read */
int32_t list_read_first(struct list_desc *list_desc, void **data)
{
struct _list_desc *list;
if (!list_desc || !data)
return FAILURE;
*data = NULL;
list = list_desc->priv_desc;
if (!list->first)
return FAILURE;
*data = list->first->data;
return SUCCESS;
}
/** @brief Read the last element of the list. Refer to \ref f_read */
int32_t list_read_last(struct list_desc *list_desc, void **data)
{
struct _list_desc *list;
if (!list_desc || !data)
return FAILURE;
*data = NULL;
list = list_desc->priv_desc;
if (!list->last)
return FAILURE;
*data = list->last->data;
return SUCCESS;
}
/** @brief Read the element at the specified idx. Refer to \ref f_read */
int32_t list_read_idx(struct list_desc *list_desc, void **data, uint32_t idx)
{
struct _list_desc *list;
if (!list_desc || !data)
return FAILURE;
*data = NULL;
list = list_desc->priv_desc;
if (!list)
return FAILURE;
if (idx >= list->nb_elements)
return FAILURE;
list->l_it.elem = list->first;
if (SUCCESS != iterator_move(&(list->l_it), idx))
return FAILURE;
return iterator_read(&(list->l_it), data);
}
/** @brief Read the element which match with cmp_data. Refer to \ref f_read */
int32_t list_read_find(struct list_desc *list_desc, void **data,
void *cmp_data)
{
struct _list_desc *list;
if (!list_desc || !data)
return FAILURE;
*data = NULL;
list = list_desc->priv_desc;
if (!list)
return FAILURE;
list = list_desc->priv_desc;
list->l_it.elem = list->first;
if (SUCCESS != iterator_find(&(list->l_it), cmp_data))
return FAILURE;
return iterator_read(&(list->l_it), data);
}
/** @brief Read and delete the first element of the list. Refer to \ref f_get */
int32_t list_get_first(struct list_desc *list_desc, void **data)
{
struct list_elem *prev;
struct list_elem *next;
struct list_elem *elem;
struct _list_desc *list;
if (!list_desc || !data)
return FAILURE;
*data = NULL;
list = list_desc->priv_desc;
if (!list->nb_elements)
return FAILURE;
elem = list->first;
prev = elem->prev;
next = elem->next;
update_links(prev, NULL, next);
update_desc(list, next, list->last);
list->nb_elements--;
*data = elem->data;
free(elem);
return SUCCESS;
}
/** @brief Read and delete the last element of the list. Refer to \ref f_get */
int32_t list_get_last(struct list_desc *list_desc, void **data)
{
struct list_elem *prev;
struct list_elem *next;
struct list_elem *elem;
struct _list_desc *list;
if (!list_desc || !data)
return FAILURE;
*data = NULL;
list = list_desc->priv_desc;
if (!list->nb_elements)
return FAILURE;
elem = list->last;
prev = elem->prev;
next = elem->next;
update_links(prev, NULL, next);
update_desc(list, list->first, prev);
list->nb_elements--;
*data = elem->data;
free(elem);
return SUCCESS;
}
/** @brief Read and delete the element at idx. Refer to \ref f_get */
int32_t list_get_idx(struct list_desc *list_desc, void **data, uint32_t idx)
{
struct _list_desc *list;
if (!list_desc || !data)
return FAILURE;
*data = NULL;
list = list_desc->priv_desc;
list->l_it.elem = list->first;
if (SUCCESS != iterator_move(&(list->l_it), idx))
return FAILURE;
return iterator_get(&(list->l_it), data);
}
/**
* @brief Read and delete the element which match with cmp_data.
* Refer to \ref f_get
*/
int32_t list_get_find(struct list_desc *list_desc, void **data, void *cmp_data)
{
struct _list_desc *list;
if (!list_desc || !data)
return FAILURE;
*data = NULL;
list = list_desc->priv_desc;
list->l_it.elem = list->first;
if (SUCCESS != iterator_find(&(list->l_it), cmp_data))
return FAILURE;
return iterator_get(&(list->l_it), data);
}
/**
* @brief Create a new iterator
* @param iter - Where to store the reference for the new iterator
* @param list_desc - Reference of the list the iterator will be used for
* @param start - If it is true the iterator will be positioned at the first
* element of the list, else it will be positioned at the last.
* @return
* - \ref SUCCESS : On success
* - \ref FAILURE : Otherwise
*/
int32_t iterator_init(struct iterator **iter, struct list_desc *list_desc,
bool start)
{
struct iterator *it;
if (!list_desc)
return FAILURE;
it = (struct iterator *)calloc(1, sizeof(*it));
if (!it)
return FAILURE;
it->list = list_desc->priv_desc;
it->list->nb_iterators++;
it->elem = start ? it->list->first : it->list->last;
*iter = it;
return SUCCESS;
}
/**
* @brief Remove the created iterator
* @param iter - Reference of the iterator
* @return
* - \ref SUCCESS : On success
* - \ref FAILURE : Otherwise
*/
int32_t iterator_remove(struct iterator *iter)
{
struct iterator *it = iter;
if (!it)
return FAILURE;
it->list->nb_iterators--;
free(it);
return SUCCESS;
}
/**
* @brief Move the position of the iteration through the list.
*
* If the required position is outside the list, the call will fail and the
* iterator will keep its position.
* @param iter - Reference of the iterator
* @param steps - Number of positions to be move. If positive, it will be moved
* forward, otherwise backwords.
* @return
* - \ref SUCCESS : On success
* - \ref FAILURE : Otherwise
*/
int32_t iterator_move(struct iterator *iter, int32_t steps)
{
struct iterator *it = iter;
struct list_elem *elem;
int32_t dir = (steps < 0) ? -1 : 1;
if (!it)
return FAILURE;
steps = abs(steps);
elem = it->elem;
while (steps > 0 && elem)
{
elem = dir > 0 ? elem->next : elem->prev;
steps--;
}
if (!elem)
return FAILURE;
it->elem = elem;
return SUCCESS;
}
/**
* @brief Move the position of the iterator at the specified index of the list.
*
* @param iter - Reference of the iterator
* @param idx - Position in the list. If negative start counting backwords
* @return
* - \ref SUCCESS : On success
* - \ref FAILURE : Otherwise
*/
int32_t iterator_move_to_idx(struct iterator *iter, int32_t idx)
{
struct list_elem *elem;
int32_t dir = (idx < 0) ? -1 : 1;
if (!iter)
return FAILURE;
idx = abs(idx);
elem = dir > 0 ? iter->list->first : iter->list->last;
while (idx > 0 && elem)
{
elem = dir > 0 ? elem->next : elem->prev;
idx--;
}
if (!elem)
return FAILURE;
iter->elem = elem;
return SUCCESS;
}
/**
* @brief Place the iterator where cmp_data if found.
* @param iter - Reference to the iterator
* @param cmp_data - Data to be found
* @return
* - \ref SUCCESS : On success
* - \ref FAILURE : Otherwise
*/
int32_t iterator_find(struct iterator *iter, void *cmp_data)
{
struct iterator *it = iter;
struct list_elem *elem;
if (!it)
return FAILURE;
elem = it->list->first;
while (elem)
{
if (0 == it->list->comparator(elem->data, cmp_data))
{
it->elem = elem;
return SUCCESS;
}
elem = elem->next;
}
return FAILURE;
}
/**
* @brief Replace the data at the current position. Refer to \ref f_edit
*/
int32_t iterator_edit(struct iterator *iter, void *new_data)
{
struct iterator *it = iter;
if (!it)
return FAILURE;
it->elem->data = new_data;
return SUCCESS;
}
/**
* @brief Read and remove the data at the current position. Refer to \ref f_get.
*
* If the current item is the last one, the iterator will be moved to the
* previous one.
*/
int32_t iterator_get(struct iterator *iter, void **data)
{
struct iterator *it = iter;
struct list_elem *next;
if (!it || !it->elem || !data)
return FAILURE;
update_links(it->elem->prev, NULL, it->elem->next);
if (it->elem == it->list->first)
update_desc(it->list, it->elem->next, it->list->last);
else if (it->elem == it->list->last)
update_desc(it->list, it->list->first, it->elem->prev);
it->list->nb_elements--;
*data = it->elem->data;
if (it->elem == it->list->last)
next = it->elem->prev;
else
next = it->elem->next;
free(it->elem);
it->elem = next;
return SUCCESS;
}
/**
* @brief Read the data at the current position. Refer to \ref f_read
*/
int32_t iterator_read(struct iterator *iter, void **data)
{
struct iterator *it = iter;
if (!it || !it->elem || !data)
return FAILURE;
*data = it->elem->data;
return SUCCESS;
}
/**
* @brief Insert an item in the list. Refer to \ref f_add
* @param iter
* @param data
* @param after - If true, the item will be inserted after the current position.
* Otherwise it will be inserted before.
*/
int32_t iterator_insert(struct iterator *iter, void *data, bool after)
{
struct iterator *it = iter;
struct list_elem *elem;
struct list_desc list_desc;
if (!it)
return FAILURE;
list_desc.priv_desc = iter->list;
if (after && it->elem == it->list->last)
return list_add_last(&list_desc, data);
if (!after && it->elem == it->list->first)
return list_add_first(&list_desc, data);
if (after)
elem = create_element(data, it->elem, it->elem->next);
else
elem = create_element(data, it->elem->prev, it->elem);
if (!elem)
return FAILURE;
update_links(elem->prev, elem, elem->next);
it->list->nb_elements++;
return SUCCESS;
}
@@ -0,0 +1,231 @@
Generating CRC table for crc8-31-lsb
0x00, 0x5E, 0xBC, 0xE2, 0x61, 0x3F, 0xDD, 0x83,
0xC2, 0x9C, 0x7E, 0x20, 0xA3, 0xFD, 0x1F, 0x41,
0x9D, 0xC3, 0x21, 0x7F, 0xFC, 0xA2, 0x40, 0x1E,
0x5F, 0x01, 0xE3, 0xBD, 0x3E, 0x60, 0x82, 0xDC,
0x23, 0x7D, 0x9F, 0xC1, 0x42, 0x1C, 0xFE, 0xA0,
0xE1, 0xBF, 0x5D, 0x03, 0x80, 0xDE, 0x3C, 0x62,
0xBE, 0xE0, 0x02, 0x5C, 0xDF, 0x81, 0x63, 0x3D,
0x7C, 0x22, 0xC0, 0x9E, 0x1D, 0x43, 0xA1, 0xFF,
0x46, 0x18, 0xFA, 0xA4, 0x27, 0x79, 0x9B, 0xC5,
0x84, 0xDA, 0x38, 0x66, 0xE5, 0xBB, 0x59, 0x07,
0xDB, 0x85, 0x67, 0x39, 0xBA, 0xE4, 0x06, 0x58,
0x19, 0x47, 0xA5, 0xFB, 0x78, 0x26, 0xC4, 0x9A,
0x65, 0x3B, 0xD9, 0x87, 0x04, 0x5A, 0xB8, 0xE6,
0xA7, 0xF9, 0x1B, 0x45, 0xC6, 0x98, 0x7A, 0x24,
0xF8, 0xA6, 0x44, 0x1A, 0x99, 0xC7, 0x25, 0x7B,
0x3A, 0x64, 0x86, 0xD8, 0x5B, 0x05, 0xE7, 0xB9,
0x8C, 0xD2, 0x30, 0x6E, 0xED, 0xB3, 0x51, 0x0F,
0x4E, 0x10, 0xF2, 0xAC, 0x2F, 0x71, 0x93, 0xCD,
0x11, 0x4F, 0xAD, 0xF3, 0x70, 0x2E, 0xCC, 0x92,
0xD3, 0x8D, 0x6F, 0x31, 0xB2, 0xEC, 0x0E, 0x50,
0xAF, 0xF1, 0x13, 0x4D, 0xCE, 0x90, 0x72, 0x2C,
0x6D, 0x33, 0xD1, 0x8F, 0x0C, 0x52, 0xB0, 0xEE,
0x32, 0x6C, 0x8E, 0xD0, 0x53, 0x0D, 0xEF, 0xB1,
0xF0, 0xAE, 0x4C, 0x12, 0x91, 0xCF, 0x2D, 0x73,
0xCA, 0x94, 0x76, 0x28, 0xAB, 0xF5, 0x17, 0x49,
0x08, 0x56, 0xB4, 0xEA, 0x69, 0x37, 0xD5, 0x8B,
0x57, 0x09, 0xEB, 0xB5, 0x36, 0x68, 0x8A, 0xD4,
0x95, 0xCB, 0x29, 0x77, 0xF4, 0xAA, 0x48, 0x16,
0xE9, 0xB7, 0x55, 0x0B, 0x88, 0xD6, 0x34, 0x6A,
0x2B, 0x75, 0x97, 0xC9, 0x4A, 0x14, 0xF6, 0xA8,
0x74, 0x2A, 0xC8, 0x96, 0x15, 0x4B, 0xA9, 0xF7,
0xB6, 0xE8, 0x0A, 0x54, 0xD7, 0x89, 0x6B, 0x35,
Generating CRC table for crc8-31-msb
0x00, 0x31, 0x62, 0x53, 0xC4, 0xF5, 0xA6, 0x97,
0xB9, 0x88, 0xDB, 0xEA, 0x7D, 0x4C, 0x1F, 0x2E,
0x43, 0x72, 0x21, 0x10, 0x87, 0xB6, 0xE5, 0xD4,
0xFA, 0xCB, 0x98, 0xA9, 0x3E, 0x0F, 0x5C, 0x6D,
0x86, 0xB7, 0xE4, 0xD5, 0x42, 0x73, 0x20, 0x11,
0x3F, 0x0E, 0x5D, 0x6C, 0xFB, 0xCA, 0x99, 0xA8,
0xC5, 0xF4, 0xA7, 0x96, 0x01, 0x30, 0x63, 0x52,
0x7C, 0x4D, 0x1E, 0x2F, 0xB8, 0x89, 0xDA, 0xEB,
0x3D, 0x0C, 0x5F, 0x6E, 0xF9, 0xC8, 0x9B, 0xAA,
0x84, 0xB5, 0xE6, 0xD7, 0x40, 0x71, 0x22, 0x13,
0x7E, 0x4F, 0x1C, 0x2D, 0xBA, 0x8B, 0xD8, 0xE9,
0xC7, 0xF6, 0xA5, 0x94, 0x03, 0x32, 0x61, 0x50,
0xBB, 0x8A, 0xD9, 0xE8, 0x7F, 0x4E, 0x1D, 0x2C,
0x02, 0x33, 0x60, 0x51, 0xC6, 0xF7, 0xA4, 0x95,
0xF8, 0xC9, 0x9A, 0xAB, 0x3C, 0x0D, 0x5E, 0x6F,
0x41, 0x70, 0x23, 0x12, 0x85, 0xB4, 0xE7, 0xD6,
0x7A, 0x4B, 0x18, 0x29, 0xBE, 0x8F, 0xDC, 0xED,
0xC3, 0xF2, 0xA1, 0x90, 0x07, 0x36, 0x65, 0x54,
0x39, 0x08, 0x5B, 0x6A, 0xFD, 0xCC, 0x9F, 0xAE,
0x80, 0xB1, 0xE2, 0xD3, 0x44, 0x75, 0x26, 0x17,
0xFC, 0xCD, 0x9E, 0xAF, 0x38, 0x09, 0x5A, 0x6B,
0x45, 0x74, 0x27, 0x16, 0x81, 0xB0, 0xE3, 0xD2,
0xBF, 0x8E, 0xDD, 0xEC, 0x7B, 0x4A, 0x19, 0x28,
0x06, 0x37, 0x64, 0x55, 0xC2, 0xF3, 0xA0, 0x91,
0x47, 0x76, 0x25, 0x14, 0x83, 0xB2, 0xE1, 0xD0,
0xFE, 0xCF, 0x9C, 0xAD, 0x3A, 0x0B, 0x58, 0x69,
0x04, 0x35, 0x66, 0x57, 0xC0, 0xF1, 0xA2, 0x93,
0xBD, 0x8C, 0xDF, 0xEE, 0x79, 0x48, 0x1B, 0x2A,
0xC1, 0xF0, 0xA3, 0x92, 0x05, 0x34, 0x67, 0x56,
0x78, 0x49, 0x1A, 0x2B, 0xBC, 0x8D, 0xDE, 0xEF,
0x82, 0xB3, 0xE0, 0xD1, 0x46, 0x77, 0x24, 0x15,
0x3B, 0x0A, 0x59, 0x68, 0xFF, 0xCE, 0x9D, 0xAC,
Generating CRC table for crc16-8005-lsb
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040,
Generating CRC table for crc16-8005-msb
0x0000, 0x8005, 0x800F, 0x000A, 0x801B, 0x001E, 0x0014, 0x8011,
0x8033, 0x0036, 0x003C, 0x8039, 0x0028, 0x802D, 0x8027, 0x0022,
0x8063, 0x0066, 0x006C, 0x8069, 0x0078, 0x807D, 0x8077, 0x0072,
0x0050, 0x8055, 0x805F, 0x005A, 0x804B, 0x004E, 0x0044, 0x8041,
0x80C3, 0x00C6, 0x00CC, 0x80C9, 0x00D8, 0x80DD, 0x80D7, 0x00D2,
0x00F0, 0x80F5, 0x80FF, 0x00FA, 0x80EB, 0x00EE, 0x00E4, 0x80E1,
0x00A0, 0x80A5, 0x80AF, 0x00AA, 0x80BB, 0x00BE, 0x00B4, 0x80B1,
0x8093, 0x0096, 0x009C, 0x8099, 0x0088, 0x808D, 0x8087, 0x0082,
0x8183, 0x0186, 0x018C, 0x8189, 0x0198, 0x819D, 0x8197, 0x0192,
0x01B0, 0x81B5, 0x81BF, 0x01BA, 0x81AB, 0x01AE, 0x01A4, 0x81A1,
0x01E0, 0x81E5, 0x81EF, 0x01EA, 0x81FB, 0x01FE, 0x01F4, 0x81F1,
0x81D3, 0x01D6, 0x01DC, 0x81D9, 0x01C8, 0x81CD, 0x81C7, 0x01C2,
0x0140, 0x8145, 0x814F, 0x014A, 0x815B, 0x015E, 0x0154, 0x8151,
0x8173, 0x0176, 0x017C, 0x8179, 0x0168, 0x816D, 0x8167, 0x0162,
0x8123, 0x0126, 0x012C, 0x8129, 0x0138, 0x813D, 0x8137, 0x0132,
0x0110, 0x8115, 0x811F, 0x011A, 0x810B, 0x010E, 0x0104, 0x8101,
0x8303, 0x0306, 0x030C, 0x8309, 0x0318, 0x831D, 0x8317, 0x0312,
0x0330, 0x8335, 0x833F, 0x033A, 0x832B, 0x032E, 0x0324, 0x8321,
0x0360, 0x8365, 0x836F, 0x036A, 0x837B, 0x037E, 0x0374, 0x8371,
0x8353, 0x0356, 0x035C, 0x8359, 0x0348, 0x834D, 0x8347, 0x0342,
0x03C0, 0x83C5, 0x83CF, 0x03CA, 0x83DB, 0x03DE, 0x03D4, 0x83D1,
0x83F3, 0x03F6, 0x03FC, 0x83F9, 0x03E8, 0x83ED, 0x83E7, 0x03E2,
0x83A3, 0x03A6, 0x03AC, 0x83A9, 0x03B8, 0x83BD, 0x83B7, 0x03B2,
0x0390, 0x8395, 0x839F, 0x039A, 0x838B, 0x038E, 0x0384, 0x8381,
0x0280, 0x8285, 0x828F, 0x028A, 0x829B, 0x029E, 0x0294, 0x8291,
0x82B3, 0x02B6, 0x02BC, 0x82B9, 0x02A8, 0x82AD, 0x82A7, 0x02A2,
0x82E3, 0x02E6, 0x02EC, 0x82E9, 0x02F8, 0x82FD, 0x82F7, 0x02F2,
0x02D0, 0x82D5, 0x82DF, 0x02DA, 0x82CB, 0x02CE, 0x02C4, 0x82C1,
0x8243, 0x0246, 0x024C, 0x8249, 0x0258, 0x825D, 0x8257, 0x0252,
0x0270, 0x8275, 0x827F, 0x027A, 0x826B, 0x026E, 0x0264, 0x8261,
0x0220, 0x8225, 0x822F, 0x022A, 0x823B, 0x023E, 0x0234, 0x8231,
0x8213, 0x0216, 0x021C, 0x8219, 0x0208, 0x820D, 0x8207, 0x0202,
Generating CRC table for crc16-1021-lsb
0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78,
Generating CRC table for crc16-1021-msb
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0,
#define CRC_BIT_NUM 8u/16u/32u/64u
#define BITS_IN_BYTE 8u
uint8_t dataBuff[ARRAY_SIZE] = { 0x32, 0x33, ...;
uint8_t/uint16_t/uint32_t crc_val = 0x0;
// LSB
for(int i = 0; i < sizeof(dataBuff); i++)
{
crc_val = (crc_val >> BITS_IN_BYTE) ^ crc_lsb_lut[(uint8)(crc_val^dataBuff[i])];
}
// MSB
for(int i = 0; i < sizeof(dataBuff); i++)
{
crc_val = (crc_val << BITS_IN_BYTE) ^ crc_msb_lut[(uint8)((crc_val>>8)^dataBuff[i])];
}
@@ -0,0 +1,403 @@
/*****************************************************************************/
/**
* @file util.c
* @author FanHao (hao_fan_bit_ee@163.com)
* @brief Utility functions implementation file
* @version 0.0
* @date 2023-05-06
*
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
* Lab of Communication and Network
*
******************************************************************************/
/***************************** Include Files **********************************/
/**
* @addtogroup Utility
* @{
*/
#include <string.h>
#include <stdlib.h>
// #include <arm_acle.h>
#include "util.h"
#include "error.h"
/************************** Functions Implementation **************************/
#ifdef __BITSWAP_TABLE
static uint8_t byte_flipLR[256] =
{
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
};
#endif
/**
* @brief Write a 32bit word to specific memory address
*/
inline void IO_Out32(uintptr_t addr, uint32_t value)
{
volatile uint32_t *localAddr = (volatile uint32_t *)addr;
*localAddr = value;
}
/**
* @brief Read a 32bit word from specific memory address
*/
inline uint32_t IO_In32(uintptr_t addr)
{
return *(volatile uint32_t *)addr;
}
/**
* @brief Swap a byte word bit-wise
*/
uint8_t byte_bit_swap(uint8_t byte)
{
#ifdef __BITSWAP_TABLE
return byte_flipLR[byte];
#else
return bit_swap_constant_8(byte);
#endif
}
/**
* @brief Swap 32bit word bit-wise
*/
uint32_t word_bit_swap(uint32_t word)
{
#ifdef __BITSWAP_TABLE
uint32_t rv_word = (byte_flipLR[word & 0xff] << 24) |
(byte_flipLR[(word >> 8) & 0xff] << 16) |
(byte_flipLR[(word >> 16) & 0xff] << 8) |
(byte_flipLR[(word >> 24) & 0xff]);
return rv_word;
#else
word = (((word & 0xaaaaaaaa) >> 1) | ((word & 0x55555555) << 1));
word = (((word & 0xcccccccc) >> 2) | ((word & 0x33333333) << 2));
word = (((word & 0xf0f0f0f0) >> 4) | ((word & 0x0f0f0f0f) << 4));
word = (((word & 0xff00ff00) >> 8) | ((word & 0x00ff00ff) << 8));
return ((word >> 16) | (word << 16));
#endif
}
/**
* @brief Count ones in an 32bit word
*/
uint32_t count_ones(uint32_t word)
{
#ifdef __GNUC__
return __builtin_popcount(word);
#else
uint32_t one_count = 0;
while (word)
{
if (word & 0x00000001)
one_count++;
word >>= 1;
}
return one_count;
#endif
}
/**
* @brief Convert fix ;oint number to float number
*/
double fix2double(int32_t val, uint8_t frac_bits)
{
return (((double)val) / (BIT(frac_bits)));
}
/**
* @brief Find first set bit in word.
*/
uint32_t find_first_set_bit(uint32_t word)
{
#ifdef __GNUC__
if (word != 0)
{
return __builtin_ctz(word);
}
else
{
return 32;
}
#else
uint32_t first_set_bit = 0;
while (word)
{
if (word & 0x1)
return first_set_bit;
word >>= 1;
first_set_bit++;
}
return 32;
#endif
}
/**
* @brief Find last set bit in word.
*/
uint32_t find_last_set_bit(uint32_t word)
{
#ifdef __GNUC__
if (word != 0)
{
return (31 - __builtin_clz(word));
}
else
{
return 32;
}
#else
uint32_t bit = 0;
uint32_t last_set_bit = 32;
while (word)
{
if (word & 0x1)
last_set_bit = bit;
word >>= 1;
bit++;
}
return last_set_bit;
#endif
}
/**
* @brief Locate the closest element in an array.
*/
uint32_t find_closest(int32_t val,
const int32_t *array,
uint32_t size)
{
int32_t diff = abs(array[0] - val);
uint32_t ret = 0;
uint32_t i;
for (i = 1; i < size; i++)
{
if (abs(array[i] - val) < diff)
{
diff = abs(array[i] - val);
ret = i;
}
}
return ret;
}
/**
* @brief Shift the value and apply the specified mask.
*/
uint32_t field_prep(uint32_t mask, uint32_t val)
{
return (val << find_first_set_bit(mask)) & mask;
}
/**
* @brief Get a field specified by a mask from a word.
*/
uint32_t field_get(uint32_t mask, uint32_t word)
{
return (word & mask) >> find_first_set_bit(mask);
}
/**
* @brief Log base 2 of the given number.
*/
int32_t log_base_2(uint32_t x)
{
return find_last_set_bit(x);
}
/**
* @brief Find greatest common divisor of the given two numbers.
*/
uint32_t greatest_common_divisor(uint32_t a,
uint32_t b)
{
uint32_t div;
uint32_t common_div = 1;
if ((a == 0) || (b == 0))
return max(a, b);
for (div = 1; (div <= a) && (div <= b); div++)
if (!(a % div) && !(b % div))
common_div = div;
return common_div;
}
/**
* @brief Calculate best rational approximation for a given fraction.
*/
void rational_best_approximation(uint32_t given_numerator,
uint32_t given_denominator,
uint32_t max_numerator,
uint32_t max_denominator,
uint32_t *best_numerator,
uint32_t *best_denominator)
{
uint32_t gcd;
gcd = greatest_common_divisor(given_numerator, given_denominator);
*best_numerator = given_numerator / gcd;
*best_denominator = given_denominator / gcd;
if ((*best_numerator > max_numerator) ||
(*best_denominator > max_denominator))
{
*best_numerator = 0;
*best_denominator = 0;
}
}
/**
* @brief Calculate the number of set bits.
*/
uint32_t hweight8(uint32_t word)
{
uint32_t count = 0;
while (word)
{
if (word & 0x1)
count++;
word >>= 1;
}
return count;
}
/**
* @brief Calculate the quotient and the remainder of an integer division.
*/
uint64_t do_div(uint64_t *n,
uint64_t base)
{
uint64_t mod = 0;
mod = *n % base;
*n = *n / base;
return mod;
}
/**
* @brief Unsigned 64bit divide with 64bit divisor and remainder
*/
uint64_t div64_u64_rem(uint64_t dividend, uint64_t divisor, uint64_t *remainder)
{
*remainder = dividend % divisor;
return dividend / divisor;
}
/**
* @brief Unsigned 64bit divide with 32bit divisor with remainder
*/
uint64_t div_u64_rem(uint64_t dividend, uint32_t divisor, uint32_t *remainder)
{
*remainder = do_div(&dividend, divisor);
return dividend;
}
/**
* @brief Signed 64bit divide with 32bit divisor with remainder
*/
int64_t div_s64_rem(int64_t dividend, int32_t divisor, int32_t *remainder)
{
*remainder = dividend % divisor;
return dividend / divisor;
}
/**
* @brief Unsigned 64bit divide with 32bit divisor
*/
uint64_t div_u64(uint64_t dividend, uint32_t divisor)
{
uint32_t remainder;
return div_u64_rem(dividend, divisor, &remainder);
}
/**
* @brief Signed 64bit divide with 32bit divisor
*/
int64_t div_s64(int64_t dividend, int32_t divisor)
{
int32_t remainder;
return div_s64_rem(dividend, divisor, &remainder);
}
/**
* @brief Converts from string to int32_t
* @param *str
* @return int32_t
*/
int32_t str_to_int32(const char *str)
{
char *end;
int32_t value = strtol(str, &end, 0);
if (end == str)
return FAILURE;
else
return value;
}
/**
* @brief Converts from string to uint32_t
* @param *str
* @return uint32_t
*/
uint32_t srt_to_uint32(const char *str)
{
char *end;
uint32_t value = strtoul(str, &end, 0);
if (end == str)
return FAILURE;
else
return value;
}
/** @} */