feat: 新增NCO PS工程
This commit is contained in:
@@ -0,0 +1,293 @@
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* 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"
|
||||
|
||||
/******** 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 PLATFORM_ZYNQMP // 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 PLATFORM_ZYNQMP // 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 0 // XPAR_PHYC_BASEADDR
|
||||
#define PHY_BEAM_FORMING_ENABLE
|
||||
// -- Antenna Bram Configs
|
||||
#define PHY_ANTCONFIG_BRAM_DEVICE_ID 0 // XPAR_PHY_DATA_INTERFACE_ANT_CONFIG_BRAM_CTRL_DEVICE_ID
|
||||
#define PHY_ANTINFO_BRAM_DEVICE_ID 0 // XPAR_PHY_DATA_INTERFACE_ANT_BEAM_BRAM_CTRL_DEVICE_ID
|
||||
// -- Buffers
|
||||
#define PHY_TXBUFF_BRAM_DEVICE_ID 0 // XPAR_PHY_DATA_INTERFACE_TX_FRAME_BRAM_CTRL_DEVICE_ID
|
||||
#define PHY_RXBUFF_BRAM_DEVICE_ID 0 // 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 0 // XPAR_FABRIC_PHY_IRQ_INTR
|
||||
#define PERIODIC_5MS_INTR_ID 0 // XPAR_FABRIC_PHY_5MS_DELAY_2MS_INTR
|
||||
|
||||
// Time Controller Configs
|
||||
#define TIME_CONTROLLER_BASEADDR 0 // XPAR_TMC_BASEADDR
|
||||
|
||||
// System Bus Configs
|
||||
#define SYSBUS_BASE_ADDR 0 // XPAR_SYSTEMBUS_BASEADDR
|
||||
#define SYSBUS_TX_INTR_ID 0 // XPAR_FABRIC_SYSTEMBUS_TX_DONE_INTR
|
||||
#define SYSBUS_RX_INTR_ID 0 // XPAR_FABRIC_SYSTEMBUS_RX_DONE_INTR
|
||||
|
||||
// INTC configis
|
||||
#define INTC_DEVICE_ID XPAR_SCUGIC_0_DEVICE_ID
|
||||
|
||||
// hop bram
|
||||
#define HOP_DEVICE_ID XPAR_AXI_BRAM_CTRL_HOP_DEVICE_ID
|
||||
|
||||
/********* Hardware Configurations **********/
|
||||
#ifdef PLATFORM_ZYNQMP // Zynq MPSoC (Zynq UltraScale+)
|
||||
#define RFDC_DEVICE_ID XPAR_XRFDC_0_DEVICE_ID
|
||||
#define RFSOC
|
||||
#endif
|
||||
|
||||
#define LMK04828
|
||||
#define LMX2594_ADC
|
||||
#define LMX2594_DAC
|
||||
#define AD9528
|
||||
|
||||
#define AD9361_REG
|
||||
#define AD9361_API
|
||||
|
||||
#define AD9653
|
||||
#define AD9694
|
||||
|
||||
// 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[] = {
|
||||
// 200MHz
|
||||
{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, 0x03}, // [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, 0x02}, // [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, 0xF9}, // [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, 0x55}, // [7] SDCLK output polarity; [6-4] SDCLK output format; [3] DCLK output polarity; [2:0] DCLK output format
|
||||
// device clock 2
|
||||
{0x0108, 0x0C}, // [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, 0x50}, // [7] SDCLK output polarity; [6-4] SDCLK output format; [3] DCLK output polarity; [2:0] DCLK output format
|
||||
// device clock 4
|
||||
{0x0110, 0x08}, // [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, 0x02}, // [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, 0xF9}, // [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, 0x00}, // [7] SDCLK output polarity; [6-4] SDCLK output format; [3] DCLK output polarity; [2:0] DCLK output format
|
||||
// device clock 6
|
||||
{0x0118, 0x0C}, // [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, 0xF1}, // [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, 0x0C}, // [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, 0xF1}, // [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, 0x00}, // [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, 0x02}, // [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, 0x50}, // [7] SDCLK output polarity; [6-4] SDCLK output format; [3] DCLK output polarity; [2:0] DCLK output format
|
||||
// device clock 12
|
||||
{0x0130, 0x0C}, // [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, 0xF1}, // [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, 0x00}, // [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, 0x1A},
|
||||
{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, 0x0A},
|
||||
{0x0157, 0x00},
|
||||
{0x0158, 0x96},
|
||||
{0x0159, 0x00},
|
||||
{0x015A, 0x60},
|
||||
{0x015B, 0xD4},
|
||||
{0x015C, 0x20},
|
||||
{0x015D, 0x00},
|
||||
{0x015E, 0x00},
|
||||
{0x015F, 0x3B},
|
||||
{0x0160, 0x00},
|
||||
{0x0161, 0x40},
|
||||
{0x0162, 0x44},
|
||||
{0x0163, 0x00},
|
||||
{0x0164, 0x00},
|
||||
{0x0165, 0x0C},
|
||||
{0x0171, 0xAA},
|
||||
{0x0172, 0x02},
|
||||
{0x017C, 0x15},
|
||||
{0x017D, 0x33},
|
||||
{0x0166, 0x00},
|
||||
{0x0167, 0x02},
|
||||
{0x0168, 0x71},
|
||||
{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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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
|
||||
+996
@@ -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;
|
||||
}
|
||||
+229
@@ -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
|
||||
+154
@@ -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, ®508);
|
||||
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, ®403);
|
||||
|
||||
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(¶m->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(¶m->my_Gpio, callback_desc->pin_nb);
|
||||
XGpioPs_IntrClearPin(¶m->my_Gpio, callback_desc->pin_nb);
|
||||
callback_desc->callback.legacy_callback(callback_desc->callback.ctx, 0U, NULL);
|
||||
if(callback_desc->enabled)
|
||||
XGpioPs_IntrEnablePin(¶m->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 ([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 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 ([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.
|
||||
*******************************************************************************/
|
||||
|
||||
#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_ */
|
||||
+7475
File diff suppressed because it is too large
Load Diff
+3568
File diff suppressed because it is too large
Load Diff
+2157
File diff suppressed because it is too large
Load Diff
+552
@@ -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
|
||||
+86
@@ -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;
|
||||
}
|
||||
+335
@@ -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;
|
||||
}
|
||||
+120
@@ -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_
|
||||
+151
@@ -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;
|
||||
}
|
||||
+104
@@ -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
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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 PLATFORM_ZYNQMP
|
||||
#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 PLATFORM_ZYNQMP
|
||||
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 PLATFORM_ZYNQMP
|
||||
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,189 @@
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @file framing.h
|
||||
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||
* @brief DF Linklayer framing functions.
|
||||
* @version 0.0
|
||||
* @date 2023-05-06
|
||||
*
|
||||
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||
* Lab of Communication and Network
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @addtogroup LinkLayer
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup LinkLayer_Framing
|
||||
* @{
|
||||
*/
|
||||
/***************************** Include Files *********************************/
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "error.h"
|
||||
#include "common.h"
|
||||
#include "msg_def.h"
|
||||
#include "link_layer.h"
|
||||
|
||||
/************************** Constant Definitions *****************************/
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Insert a data chunk to a bit array.
|
||||
*
|
||||
* @param frame pointer to target bit array.
|
||||
* @param offset offset of insert start position.
|
||||
* @param bytes number of insert bytes
|
||||
* @param chunk pointer to data chunk
|
||||
*
|
||||
* @return NONE
|
||||
*
|
||||
******************************************************************************/
|
||||
void L2_FrameInsertChunk(uint8_t *frame, size_t offset, size_t bytes, const void *chunk)
|
||||
{
|
||||
ASSERT(frame != NULL);
|
||||
ASSERT(chunk != NULL);
|
||||
memcpy(frame + offset, chunk, bytes);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Get a data chunk to a frame buff.
|
||||
*
|
||||
* @param frame pointer to target bit array.
|
||||
* @param offset offset of data chunk start position.
|
||||
* @param bytes number of data bytes
|
||||
* @param chunk pointer to data chunk
|
||||
*
|
||||
* @return NONE
|
||||
*
|
||||
******************************************************************************/
|
||||
void L2_FrameGetChunk(uint8_t *frame, size_t offset, size_t bytes, void *chunk)
|
||||
{
|
||||
ASSERT(frame != NULL);
|
||||
ASSERT(chunk != NULL);
|
||||
memcpy(chunk, frame + offset, bytes);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Generate crc of specified data.
|
||||
*
|
||||
* @param dataBuff pointer to data buffer.
|
||||
* @param dataLen length of specified data.
|
||||
* @param crcType type of crc
|
||||
* @param crc a pointer to 32 bit crc container.
|
||||
*
|
||||
* @return FAILURE crc type not support.
|
||||
* SUCCESS
|
||||
*
|
||||
******************************************************************************/
|
||||
static int32_t L2_CrcGen(uint8_t *dataBuff, uint32_t dataLen, L2_CRC_TYPE crcType, uint32_t *crc)
|
||||
{
|
||||
ASSERT(dataBuff != NULL);
|
||||
int32_t Status;
|
||||
switch (crcType)
|
||||
{
|
||||
case L2_CRC16_1021:
|
||||
Status = crc16_gen(dataBuff, dataLen, 0x1021, (uint16_t *)crc);
|
||||
break;
|
||||
case L2_CRC16_8005:
|
||||
Status = crc16_gen(dataBuff, dataLen, 0x8005, (uint16_t *)crc);
|
||||
break;
|
||||
case L2_CRC8_31:
|
||||
Status = crc8_gen(dataBuff, dataLen, 0x31, (uint8_t *)crc);
|
||||
break;
|
||||
default:
|
||||
Status = EPARAM;
|
||||
break;
|
||||
}
|
||||
return Status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Append a crc of specified data, to a specified position.
|
||||
*
|
||||
* @param dataBuff pointer to data buffer.
|
||||
* @param dataLen length of specified data.
|
||||
* @param crcPos position of crc insert position
|
||||
* @param crcType type of crc
|
||||
*
|
||||
* @return FAILURE crc type not support.
|
||||
* SUCCESS
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t L2_CrcAppend(uint8_t *dataBuff, uint32_t dataLen, uint32_t crcPos, L2_CRC_TYPE crcType)
|
||||
{
|
||||
ASSERT(dataBuff != NULL);
|
||||
int32_t Status;
|
||||
uint32_t crcVal;
|
||||
uint8_t *crcPtr;
|
||||
crcPtr = dataBuff + crcPos;
|
||||
Status = L2_CrcGen(dataBuff, dataLen, crcType, &crcVal);
|
||||
if (Status != SUCCESS)
|
||||
{
|
||||
return Status;
|
||||
}
|
||||
switch (crcType)
|
||||
{
|
||||
case L2_CRC16_1021:
|
||||
*(crcPtr + 1) = (uint8_t)(crcVal >> 8);
|
||||
*crcPtr = (uint8_t)(crcVal);
|
||||
break;
|
||||
case L2_CRC16_8005:
|
||||
*(crcPtr + 1) = (uint8_t)(crcVal >> 8);
|
||||
*crcPtr = (uint8_t)(crcVal);
|
||||
break;
|
||||
case L2_CRC8_31:
|
||||
*crcPtr = (uint8_t)crcVal;
|
||||
break;
|
||||
default:
|
||||
Status = EPARAM;
|
||||
break;
|
||||
}
|
||||
return Status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Check data validation by crc.
|
||||
*
|
||||
* @param dataBuff pointer to data buffer.
|
||||
* @param dataLen length of specified data.
|
||||
* @param crcType type of crc
|
||||
*
|
||||
* @return FAILURE crc type not support.
|
||||
* SUCCESS
|
||||
*
|
||||
******************************************************************************/
|
||||
bool L2_CrcCheck(uint8_t *dataBuff, uint32_t dataLen, L2_CRC_TYPE crcType)
|
||||
{
|
||||
ASSERT(dataBuff != NULL);
|
||||
int32_t Status;
|
||||
uint32_t crcVal;
|
||||
crcVal = 0;
|
||||
Status = L2_CrcGen(dataBuff, dataLen, crcType, &crcVal);
|
||||
if (Status == SUCCESS)
|
||||
{
|
||||
if (crcVal == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** @} LinkLayer_Framing*/
|
||||
|
||||
/** @} LinkLayer*/
|
||||
@@ -0,0 +1,237 @@
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @file coord.c
|
||||
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||
* @version 0.0
|
||||
* @date 2023-05-06
|
||||
*
|
||||
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||
* Lab of Communication and Network
|
||||
*
|
||||
******************************************************************************/
|
||||
/**
|
||||
* @addtogroup LinkLayer
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup LinkLayerGeometry
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup LinkLayerGeometry_Coord
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include "coord.h"
|
||||
|
||||
const COORD COORD_NIL = {NAN, NAN, NAN};
|
||||
const COORD COORD_ZERO = {0.0, 0.0, 0.0};
|
||||
const COORD COORD_ONE = {1.0, 1.0, 1.0};
|
||||
const COORD COORD_X_AXIS = {1.0, 0.0, 0.0};
|
||||
const COORD COORD_Y_AXIS = {0.0, 1.0, 0.0};
|
||||
const COORD COORD_Z_AXIS = {0.0, 0.0, 1.0};
|
||||
|
||||
/** @brief Subtracts two coordinate vectors. */
|
||||
COORD Coord_Sub(COORD a, COORD b)
|
||||
{
|
||||
COORD ret;
|
||||
ret.x = a.x - b.x;
|
||||
ret.y = a.y - b.y;
|
||||
ret.z = a.z - b.z;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @brief Adds two coordinate vectors. */
|
||||
COORD Coord_Add(COORD a, COORD b)
|
||||
{
|
||||
COORD ret;
|
||||
ret.x = a.x + b.x;
|
||||
ret.y = a.y + b.y;
|
||||
ret.z = a.z + b.z;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @brief Multiplies a coordinate vector by a real number. */
|
||||
void Coord_ScalarMult(COORD *a, double t)
|
||||
{
|
||||
a->x *= t;
|
||||
a->y *= t;
|
||||
a->z *= t;
|
||||
}
|
||||
|
||||
/** @brief Multiplies a coordinate vector by a real number. */
|
||||
COORD Coord_GetScalarMult(COORD a, double t)
|
||||
{
|
||||
COORD ret;
|
||||
ret.x = a.x * t;
|
||||
ret.y = a.y * t;
|
||||
ret.z = a.z * t;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @brief Divides a coordinate vector by a real number. */
|
||||
void Coord_ScalarDiv(COORD *a, double t)
|
||||
{
|
||||
a->x /= t;
|
||||
a->y /= t;
|
||||
a->z /= t;
|
||||
}
|
||||
|
||||
/** @brief Divides a coordinate vector by a real number. */
|
||||
COORD Coord_GetScalarDiv(COORD a, double t)
|
||||
{
|
||||
COORD ret;
|
||||
ret.x = a.x / t;
|
||||
ret.y = a.y / t;
|
||||
ret.z = a.z / t;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @brief Dot product. */
|
||||
inline double Coord_Dot(COORD a, COORD b)
|
||||
{
|
||||
return (a.x * b.x + a.y * b.y + a.z * b.z);
|
||||
}
|
||||
|
||||
/** @brief Cross product. */
|
||||
COORD Coord_Cross(COORD a, COORD b)
|
||||
{
|
||||
COORD ret;
|
||||
ret.x = a.y * b.z - a.z * b.y;
|
||||
ret.y = a.z * b.x - a.x * b.z;
|
||||
ret.z = a.x * b.y - a.y * b.x;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @brief Multiplies two coordinate vector in elementwise. */
|
||||
COORD Coord_ElementwiseMult(COORD a, COORD b)
|
||||
{
|
||||
COORD ret;
|
||||
ret.x = a.x * b.x;
|
||||
ret.y = a.y * b.y;
|
||||
ret.z = a.z * b.z;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @brief Divides two coordinate vector in elementwise. */
|
||||
COORD Coord_ElementwiseDiv(COORD a, COORD b)
|
||||
{
|
||||
COORD ret;
|
||||
ret.x = a.x / b.x;
|
||||
ret.y = a.y / b.y;
|
||||
ret.z = a.z / b.z;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @brief Calculate a coordinate vector length^2 (omits calling square root). */
|
||||
double Coord_SquareLength(COORD a)
|
||||
{
|
||||
return (a.x * a.x + a.y * a.y + a.z * a.z);
|
||||
}
|
||||
|
||||
/** @brief Calculate a coordinate vector length. */
|
||||
double Coord_Length(COORD a)
|
||||
{
|
||||
return sqrt(Coord_SquareLength(a));
|
||||
}
|
||||
|
||||
/** @brief Calculate two coordinates' distance. */
|
||||
double Coord_Distance(COORD a, COORD b)
|
||||
{
|
||||
return Coord_Length(Coord_Sub(a, b));
|
||||
}
|
||||
|
||||
/** @brief Normalize coordinate vector. */
|
||||
void Coord_Normalize(COORD *a)
|
||||
{
|
||||
Coord_ScalarDiv(a, Coord_Length(*a));
|
||||
}
|
||||
|
||||
/** @brief Normalize coordinate vector. */
|
||||
COORD Coord_GetNormalized(COORD a)
|
||||
{
|
||||
Coord_Normalize(&a);
|
||||
return a;
|
||||
}
|
||||
|
||||
/** @brief Returns the angle between the two vectors. */
|
||||
double Coord_Angle(COORD a, COORD b)
|
||||
{
|
||||
Coord_Normalize(&a);
|
||||
Coord_Normalize(&b);
|
||||
return acos(Coord_Dot(a, b));
|
||||
}
|
||||
|
||||
// Additional Coordinates convert
|
||||
// TODO: Confirm correctness
|
||||
/** @brief Convert coordinate from Launch coordinate system to ECEF. */
|
||||
COORD Coord_Launch2Ecef(COORD o, COORD p, double A, double B, double lambda)
|
||||
{
|
||||
COORD ret;
|
||||
double sinA, cosA, sinB, cosB, sinL, cosL;
|
||||
double S11, S12, S13, S21, S22, S23, S31, S32, S33;
|
||||
sinA = sin(A);
|
||||
cosA = cos(A);
|
||||
sinB = sin(B);
|
||||
cosB = cos(B);
|
||||
sinL = sin(lambda);
|
||||
cosL = cos(lambda);
|
||||
|
||||
S11 = -sinA * sinL - cosA * sinB * cosL;
|
||||
S12 = cosB * cosL;
|
||||
S13 = -cosA * sinL + sinA * sinB * cosL;
|
||||
|
||||
S21 = sinA * cosL - cosA * sinB * sinL;
|
||||
S22 = cosB * sinL;
|
||||
S23 = cosA * cosL + sinA * sinB * sinL;
|
||||
|
||||
S31 = cosA * cosB;
|
||||
S32 = sinB;
|
||||
S33 = -sinA * cosB;
|
||||
|
||||
ret.x = p.x * (S11 + S21 + S31) + o.x;
|
||||
ret.y = p.y * (S12 + S22 + S32) + o.y;
|
||||
ret.z = p.z * (S13 + S23 + S33) + o.z;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @brief Convert coordinate from launch coordinate system to Inertia coordinate system. */
|
||||
COORD Coord_Launch2Inertia(COORD o, COORD p, double A, double B, double we, double t)
|
||||
{
|
||||
COORD ret;
|
||||
double OmgX, OmgY, OmgZ, sinwet, coswet;
|
||||
double M11, M12, M13, M21, M22, M23, M31, M32, M33;
|
||||
OmgX = cos(A) * cos(B);
|
||||
OmgY = sin(B);
|
||||
OmgZ = -sin(A) * cos(B);
|
||||
sinwet = sin(we * t);
|
||||
coswet = cos(we * t);
|
||||
|
||||
M11 = 1 - (1 - OmgX * OmgX) * (1 - coswet);
|
||||
M12 = OmgX * OmgY * (1 - coswet) + OmgZ * sinwet;
|
||||
M13 = OmgX * OmgZ * (1 - coswet) - OmgY * sinwet;
|
||||
|
||||
M21 = OmgY * OmgX * (1 - coswet) - OmgZ * sinwet;
|
||||
M22 = 1 - (1 - OmgY * OmgY) * (1 - coswet);
|
||||
M23 = OmgY * OmgZ * (1 - coswet) + OmgX * sinwet;
|
||||
|
||||
M31 = OmgZ * OmgX * (1 - coswet) + OmgY * sinwet;
|
||||
M32 = OmgZ * OmgY * (1 - coswet) - OmgX * sinwet;
|
||||
M33 = 1 - (1 - OmgZ * OmgZ) * (1 - coswet);
|
||||
|
||||
ret.x = p.x * (M11 + M21 + M31) + o.x;
|
||||
ret.y = p.y * (M12 + M22 + M32) + o.y;
|
||||
ret.z = p.z * (M13 + M23 + M33) + o.z;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @} LinkLayerGeometry_Coord */
|
||||
|
||||
/** @} LinkLayerGeometry */
|
||||
|
||||
/** @} LinkLayer */
|
||||
@@ -0,0 +1,102 @@
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @file coord.h
|
||||
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||
* @version 0.0
|
||||
* @date 2023-05-06
|
||||
*
|
||||
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||
* Lab of Communication and Network
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef _COORD_H
|
||||
#define _COORD_H
|
||||
/**
|
||||
* @addtogroup LinkLayer
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup LinkLayerGeometry
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup LinkLayerGeometry_Coord
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @struct COORD
|
||||
* @brief Structure for storing 3D coordinates.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
} COORD;
|
||||
|
||||
extern const COORD COORD_NIL;
|
||||
extern const COORD COORD_ZERO;
|
||||
extern const COORD COORD_ONE;
|
||||
extern const COORD COORD_X_AXIS;
|
||||
extern const COORD COORD_Y_AXIS;
|
||||
extern const COORD COORD_Z_AXIS;
|
||||
|
||||
/** @brief Subtracts two coordinate vectors. */
|
||||
COORD Coord_Sub(COORD a, COORD b);
|
||||
|
||||
/** @brief Adds two coordinate vectors. */
|
||||
COORD Coord_Add(COORD a, COORD b);
|
||||
|
||||
/** @brief Multiplies a coordinate vector by a real number. */
|
||||
void Coord_ScalarMult(COORD *a, double t);
|
||||
|
||||
/** @brief Multiplies a coordinate vector by a real number. */
|
||||
COORD Coord_GetScalarMult(COORD a, double t);
|
||||
|
||||
/** @brief Divides a coordinate vector by a real number. */
|
||||
void Coord_ScalarDiv(COORD *a, double t);
|
||||
|
||||
/** @brief Divides a coordinate vector by a real number. */
|
||||
COORD Coord_GetScalarDiv(COORD a, double t);
|
||||
|
||||
/** @brief Dot product. */
|
||||
double Coord_Dot(COORD a, COORD b);
|
||||
|
||||
/** @brief Cross product. */
|
||||
COORD Coord_Cross(COORD a, COORD b);
|
||||
|
||||
/** @brief Multiplies two coordinate vector in elementwise. */
|
||||
COORD Coord_ElementwiseMult(COORD a, COORD b);
|
||||
|
||||
/** @brief Divides two coordinate vector in elementwise. */
|
||||
COORD Coord_ElementwiseDiv(COORD a, COORD b);
|
||||
|
||||
/** @brief Calculate a coordinate vector length^2 (omits calling square root). */
|
||||
double Coord_SquareLength(COORD a);
|
||||
|
||||
/** @brief Calculate a coordinate vector length. */
|
||||
double Coord_Length(COORD a);
|
||||
|
||||
/** @brief Calculate two coordinates' distance. */
|
||||
double Coord_Distance(COORD a, COORD b);
|
||||
|
||||
/** @brief Normalize coordinate vector. */
|
||||
void Coord_Normalize(COORD *a);
|
||||
|
||||
/** @brief Normalize coordinate vector. */
|
||||
COORD Coord_GetNormalized(COORD a);
|
||||
|
||||
/** @brief Returns the angle between the two vectors. */
|
||||
double Coord_Angle(COORD a, COORD b);
|
||||
|
||||
#endif
|
||||
|
||||
/** @} LinkLayerGeometry_Coord */
|
||||
|
||||
/** @} LinkLayerGeometry */
|
||||
|
||||
/** @} LinkLayer */
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @file eulerangles.c
|
||||
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||
* @version 0.0
|
||||
* @date 2023-05-06
|
||||
*
|
||||
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||
* Lab of Communication and Network
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @addtogroup LinkLayer
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup LinkLayerGeometry
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup LinkLayerGeometry_EulerAngles
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include "eulerangles.h"
|
||||
|
||||
const EULERANGLES EULERANGLES_NIL = {NAN, NAN, NAN};
|
||||
const EULERANGLES EULERANGLES_ZERO = {0.0, 0.0, 0.0};
|
||||
|
||||
/** @brief Add two EulerAngles. */
|
||||
EULERANGLES EulerAngles_Add(EULERANGLES e1, EULERANGLES e2)
|
||||
{
|
||||
EULERANGLES ret;
|
||||
ret.alpha = e1.alpha + e2.alpha;
|
||||
ret.beta = e1.beta + e2.beta;
|
||||
ret.gamma = e1.gamma + e2.gamma;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @brief Subtracts two EulerAngles. */
|
||||
EULERANGLES EulerAngles_Sub(EULERANGLES e1, EULERANGLES e2)
|
||||
{
|
||||
EULERANGLES ret;
|
||||
ret.alpha = e1.alpha - e2.alpha;
|
||||
ret.beta = e1.beta - e2.beta;
|
||||
ret.gamma = e1.gamma - e2.gamma;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @brief Multiplies EulerAngles by a real number. */
|
||||
void EulerAngles_ScalarMult(EULERANGLES *e, double f)
|
||||
{
|
||||
e->alpha *= f;
|
||||
e->beta *= f;
|
||||
e->gamma *= f;
|
||||
}
|
||||
|
||||
/** @brief Multiplies EulerAngles by a real number. */
|
||||
EULERANGLES EulerAngles_GetScalarMult(EULERANGLES e, double f)
|
||||
{
|
||||
EulerAngles_ScalarMult(&e, f);
|
||||
return e;
|
||||
}
|
||||
|
||||
/** @brief Normalize EulerAngles. */
|
||||
void EulerAngles_Normalize(EULERANGLES *e)
|
||||
{
|
||||
e->alpha = fmod(e->alpha, 2 * EUL_PI);
|
||||
e->beta = fmod(e->beta, 2 * EUL_PI);
|
||||
e->gamma = fmod(e->gamma, 2 * EUL_PI);
|
||||
}
|
||||
|
||||
/** @brief Normalize EulerAngles. */
|
||||
EULERANGLES EulerAngles_GetNormalize(EULERANGLES e)
|
||||
{
|
||||
EulerAngles_Normalize(&e);
|
||||
return e;
|
||||
}
|
||||
|
||||
/** @} LinkLayerGeometry_EulerAngles */
|
||||
|
||||
/** @} LinkLayerGeometry */
|
||||
|
||||
/** @} LinkLayer */
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @file eulerangles.h
|
||||
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||
* @version 0.0
|
||||
* @date 2023-05-06
|
||||
*
|
||||
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||
* Lab of Communication and Network
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @addtogroup LinkLayer
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup LinkLayerGeometry
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup LinkLayerGeometry_EulerAngles
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef __EULERANGLES_H
|
||||
#define __EULERANGLES_H
|
||||
|
||||
#define EUL_PI 3.14159265358979323846
|
||||
|
||||
#define DEG2RAD(d) ((EUL_PI / 180.0) * d)
|
||||
#define RAD2DEG(r) ((180.0 / EUL_PI) * r)
|
||||
|
||||
/**
|
||||
* Orientations are represented by 3D double precision Tait-Bryan (Euler) tuples
|
||||
* called EulerAngles. The angles are in Z, Y', X" order that is often called
|
||||
* intrinsic rotations, they are measured in radians. The default (unrotated)
|
||||
* orientation is along the X axis. Conceptually, the Z axis rotation is heading,
|
||||
* the Y' axis rotation is descending (negative elevation), the X" axis rotation is bank.
|
||||
* For example, positive rotation along the Z axis rotates X into Y (turns left), positive
|
||||
* rotation along the Y axis rotates Z into X (leans forward), positive rotation
|
||||
* along the X axis rotates Y into Z (leans right).
|
||||
*/
|
||||
|
||||
/**
|
||||
* @struct EULERANGLES
|
||||
* @brief Structure for standard quaternion
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
double alpha; // unit rad
|
||||
double beta; // unit rad
|
||||
double gamma; // unit rad
|
||||
} EULERANGLES;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
EULERANGLES_NONE = 0,
|
||||
EULERANGLES_ZYX = 1,
|
||||
EULERANGLES_ZYZ = 2,
|
||||
EULERANGLES_XYZ = 3,
|
||||
} EULERANGLES_TYPE;
|
||||
|
||||
extern const EULERANGLES EULERANGLES_ZERO;
|
||||
extern const EULERANGLES EULERANGLES_NIL;
|
||||
|
||||
/** @brief Add two EulerAngles. */
|
||||
EULERANGLES EulerAngles_Add(EULERANGLES e1, EULERANGLES e2);
|
||||
|
||||
/** @brief Subtracts two EulerAngles. */
|
||||
EULERANGLES EulerAngles_Sub(EULERANGLES e1, EULERANGLES e2);
|
||||
|
||||
/** @brief Multiplies EulerAngles by a real number. */
|
||||
void EulerAngles_ScalarMult(EULERANGLES *e, double f);
|
||||
|
||||
/** @brief Multiplies EulerAngles by a real number. */
|
||||
EULERANGLES EulerAngles_GetScalarMult(EULERANGLES e, double f);
|
||||
|
||||
/** @brief Normalize EulerAngles. */
|
||||
void EulerAngles_Normalize(EULERANGLES *e);
|
||||
|
||||
/** @brief Normalize EulerAngles. */
|
||||
EULERANGLES EulerAngles_GetNormalize(EULERANGLES e);
|
||||
|
||||
#endif
|
||||
|
||||
/** @} LinkLayerGeometry_EulerAngles */
|
||||
|
||||
/** @} LinkLayerGeometry */
|
||||
|
||||
/** @} LinkLayer */
|
||||
+480
@@ -0,0 +1,480 @@
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @file quaternion.c
|
||||
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||
* @version 0.0
|
||||
* @date 2023-05-06
|
||||
*
|
||||
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||
* Lab of Communication and Network
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @addtogroup LinkLayer
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup LinkLayerGeometry
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup LinkLayerGeometry_Quaternion
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "coord.h"
|
||||
#include "eulerangles.h"
|
||||
#include "quaternion.h"
|
||||
|
||||
typedef union
|
||||
{
|
||||
float value;
|
||||
uint32_t raw;
|
||||
} SOFT_FLOAT;
|
||||
|
||||
typedef union
|
||||
{
|
||||
double value;
|
||||
uint64_t raw;
|
||||
} SOFT_DOUBLE;
|
||||
|
||||
const SOFT_FLOAT EPS_FLOAT = {.raw = 0x34000000};
|
||||
const SOFT_DOUBLE EPS_DOUBLE = {.raw = 0x3CB0000000000000};
|
||||
|
||||
const QUATERNION QUATERNION_IDENTITY = {1.0, 0.0, 0.0, 0.0};
|
||||
const QUATERNION QUATERNION_NIL = {NAN, NAN, NAN, NAN};
|
||||
|
||||
/** @brief Subtracts two quaternions. */
|
||||
QUATERNION Quaternion_Sub(QUATERNION q1, QUATERNION q2)
|
||||
{
|
||||
QUATERNION ret;
|
||||
ret.s = q1.s - q2.s;
|
||||
ret.i = q1.i - q2.i;
|
||||
ret.j = q1.j - q2.j;
|
||||
ret.k = q1.k - q2.k;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @brief Adds two quaternions. */
|
||||
QUATERNION Quaternion_Add(QUATERNION q1, QUATERNION q2)
|
||||
{
|
||||
QUATERNION ret;
|
||||
ret.s = q1.s + q2.s;
|
||||
ret.i = q1.i + q2.i;
|
||||
ret.j = q1.j + q2.j;
|
||||
ret.k = q1.k + q2.k;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @brief Multiplies a quaternion by a real number. */
|
||||
void Quaternion_ScalarMult(QUATERNION *q, double t)
|
||||
{
|
||||
q->s *= t;
|
||||
q->i *= t;
|
||||
q->j *= t;
|
||||
q->k *= t;
|
||||
}
|
||||
|
||||
/** @brief Multiplies a quaternion by a real number. */
|
||||
QUATERNION Quaternion_GetScalarMult(QUATERNION a, double t)
|
||||
{
|
||||
Quaternion_ScalarMult(&a, t);
|
||||
return a;
|
||||
}
|
||||
|
||||
/** @brief Divides a quaternion by a real number. */
|
||||
void Quaternion_ScalarDiv(QUATERNION *q, double t)
|
||||
{
|
||||
q->s /= t;
|
||||
q->i /= t;
|
||||
q->j /= t;
|
||||
q->k /= t;
|
||||
}
|
||||
|
||||
/** @brief Divides a quaternion by a real number. */
|
||||
QUATERNION Quaternion_GetScalarDiv(QUATERNION q, double t)
|
||||
{
|
||||
Quaternion_ScalarDiv(&q, t);
|
||||
return q;
|
||||
}
|
||||
|
||||
/** @brief Multiplies two quaternions. */
|
||||
QUATERNION Quaternion_Mult(QUATERNION q1, QUATERNION q2)
|
||||
{
|
||||
QUATERNION ret;
|
||||
ret.s = q1.s * q2.s - (q1.i * q2.i + q1.j * q2.j + q1.k * q2.k);
|
||||
ret.i = q1.j * q2.k - q1.k * q2.j + q1.s * q2.i + q1.i * q2.s;
|
||||
ret.j = q1.k * q2.i - q1.i * q2.k + q1.s * q2.j + q1.j * q2.s;
|
||||
ret.k = q1.i * q2.j - q1.j * q2.i + q1.s * q2.k + q1.k * q2.s;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @brief Divides two quaternions. */
|
||||
QUATERNION Quaternion_Div(QUATERNION q1, QUATERNION q2)
|
||||
{
|
||||
Quaternion_Inverse(&q2);
|
||||
return Quaternion_Mult(q1, q2);
|
||||
}
|
||||
|
||||
/** @brief Dot product. */
|
||||
inline double Quaternion_Dot(QUATERNION q1, QUATERNION q2)
|
||||
{
|
||||
return (q1.s * q2.s + q1.i * q2.i + q1.j * q2.j + q1.k * q2.k);
|
||||
}
|
||||
|
||||
/** @brief Calculate a quaternion length^2 (omits calling square root). */
|
||||
inline double Quaternion_SquareLength(QUATERNION q)
|
||||
{
|
||||
return (q.s * q.s + q.i * q.i + q.j * q.j + q.k * q.k);
|
||||
}
|
||||
|
||||
/** @brief Calculate a quaternion length. */
|
||||
inline double Quaternion_Length(QUATERNION q)
|
||||
{
|
||||
return sqrt(Quaternion_SquareLength(q));
|
||||
}
|
||||
|
||||
/** @brief Normalize quaternion. */
|
||||
void Quaternion_Normalize(QUATERNION *q)
|
||||
{
|
||||
Quaternion_ScalarDiv(q, Quaternion_Length(*q));
|
||||
}
|
||||
|
||||
/** @brief Normalize quaternion. */
|
||||
QUATERNION Quaternion_GetNormalized(QUATERNION q)
|
||||
{
|
||||
Quaternion_Normalize(&q);
|
||||
return q;
|
||||
}
|
||||
|
||||
/** @brief Conjugated quaternion. */
|
||||
void Quaternion_Conjugated(QUATERNION *q)
|
||||
{
|
||||
q->i = -q->i;
|
||||
q->j = -q->j;
|
||||
q->k = -q->k;
|
||||
}
|
||||
|
||||
/** @brief Conjugated quaternion. */
|
||||
QUATERNION Quaternion_GetConjugated(QUATERNION q)
|
||||
{
|
||||
Quaternion_Conjugated(&q);
|
||||
return q;
|
||||
}
|
||||
|
||||
/** @brief Inverse quaternion. */
|
||||
void Quaternion_Inverse(QUATERNION *q)
|
||||
{
|
||||
Quaternion_Conjugated(q);
|
||||
Quaternion_ScalarDiv(q, Quaternion_SquareLength(*q));
|
||||
}
|
||||
|
||||
/** @brief Inverse quaternion. */
|
||||
QUATERNION Quaternion_GeInverse(QUATERNION q)
|
||||
{
|
||||
Quaternion_Inverse(&q);
|
||||
return q;
|
||||
}
|
||||
|
||||
inline double Quaternion_GetRotationAngle(QUATERNION q)
|
||||
{
|
||||
return (acos(q.s) * 2);
|
||||
}
|
||||
|
||||
/** @brief Get axis of quaternion. */
|
||||
COORD Quaternion_GetRotationAxis(QUATERNION q)
|
||||
{
|
||||
double sin_theta_inv;
|
||||
COORD ret;
|
||||
sin_theta_inv = 1.0 / sin(acos(q.s));
|
||||
ret.x = q.i * sin_theta_inv;
|
||||
ret.y = q.j * sin_theta_inv;
|
||||
ret.z = q.k * sin_theta_inv;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @brief Get the axis and rotate angle of a unit Quaternion */
|
||||
void Quaternion_GetRotationAxisAndAngle(QUATERNION q, COORD *axis, double *angle)
|
||||
{
|
||||
double sin_theta_inv;
|
||||
*angle = acos(q.s);
|
||||
|
||||
// pre-compute to save time
|
||||
sin_theta_inv = 1.0 / sin(*angle);
|
||||
|
||||
// now the vector
|
||||
axis->x = q.i * sin_theta_inv;
|
||||
axis->y = q.j * sin_theta_inv;
|
||||
axis->z = q.k * sin_theta_inv;
|
||||
*angle = (*angle) * 2;
|
||||
}
|
||||
|
||||
/** @brief Decompose the rotation on to 2 parts. */
|
||||
void Quaternion_GetSwingAndTwist(QUATERNION q, COORD axis, QUATERNION *swing, QUATERNION *twist)
|
||||
{
|
||||
double p;
|
||||
COORD v;
|
||||
v.x = q.i;
|
||||
v.y = q.j;
|
||||
v.z = q.k;
|
||||
// return projection v1 on to v2 (parallel component)
|
||||
p = Coord_Dot(v, axis);
|
||||
v = Coord_GetScalarMult(axis, p);
|
||||
twist->s = q.s;
|
||||
twist->i = v.x;
|
||||
twist->j = v.y;
|
||||
twist->k = v.z;
|
||||
Quaternion_Normalize(twist);
|
||||
*swing = Quaternion_Mult(q, Quaternion_GetConjugated(*twist));
|
||||
}
|
||||
|
||||
/** @brief rotates v by this quaternion (quaternion must be unit) */
|
||||
COORD Quaternion_Rotate(QUATERNION q, COORD v)
|
||||
{
|
||||
QUATERNION temp;
|
||||
COORD ret;
|
||||
temp.s = 0;
|
||||
temp.i = v.x;
|
||||
temp.j = v.y;
|
||||
temp.k = v.z;
|
||||
temp = Quaternion_Mult(q, temp);
|
||||
Quaternion_Conjugated(&q);
|
||||
temp = Quaternion_Mult(temp, q);
|
||||
ret.x = temp.i;
|
||||
ret.y = temp.j;
|
||||
ret.z = temp.k;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @brief returns the euler angles from a rotation Quaternion */
|
||||
EULERANGLES Quaternion_ToEulerAngles(QUATERNION q, EULERANGLES_TYPE type)
|
||||
{
|
||||
EULERANGLES ret;
|
||||
switch (type)
|
||||
{
|
||||
case EULERANGLES_ZYX:
|
||||
{
|
||||
/* Covert form matlab 2023a */
|
||||
// Cap all inputs to asin to 1, since values >1 produce complex
|
||||
// results
|
||||
// Since the quaternion is of unit length, this should never happen,
|
||||
// but some code generation configuration seem to hit this edge case
|
||||
// under some circumstances.
|
||||
|
||||
double asinValue;
|
||||
bool mask1, mask2;
|
||||
|
||||
asinValue = -2.0 * (q.i * q.k - q.s * q.j);
|
||||
mask1 = asinValue >= 1.0 - 10 * EPS_DOUBLE.value;
|
||||
mask2 = asinValue <= -1.0 + 10 * EPS_DOUBLE.value;
|
||||
if (mask1)
|
||||
asinValue = 1;
|
||||
if (mask2)
|
||||
asinValue = -1;
|
||||
|
||||
if (mask1 || mask2)
|
||||
{
|
||||
ret.alpha = (asinValue > 0) ? (-2.0 * atan2(q.i, q.s)) : (2.0 * atan2(q.i, q.s));
|
||||
ret.gamma = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.alpha = atan2(2.0 * (q.i * q.j + q.s * q.k), q.s * q.s + q.i * q.i - q.j * q.j - q.k * q.k);
|
||||
ret.gamma = atan2(2.0 * (q.j * q.k + q.s * q.i), q.s * q.s - q.i * q.i - q.j * q.j + q.k * q.k);
|
||||
}
|
||||
ret.beta = asin(asinValue);
|
||||
break;
|
||||
}
|
||||
|
||||
case EULERANGLES_ZYZ:
|
||||
{
|
||||
// TODO;
|
||||
ret = EULERANGLES_NIL;
|
||||
break;
|
||||
}
|
||||
|
||||
case EULERANGLES_XYZ:
|
||||
{
|
||||
/* Covert form matlab 2023a */
|
||||
// Prevent singularities as done in ZYX case
|
||||
// Alternative to rotm2eul(quat2rotm(q), 'XYZ') with fewer
|
||||
// operations
|
||||
// sin(y) = R13 = 2 * (qx*qz + qy*qw)
|
||||
// tan(x) = sin(x) / cos(x) = -R23 / R33
|
||||
// = -2 * (qy*qz - qx*qw) / (1 - 2*(qx^2 + qy^2))
|
||||
// = -2 * (qy*qz - qx*qw) / (qw^2 - qx^2 - qy^2 + qz^2)
|
||||
// tan(z) = sin(z) / cos(z) = -R12 / R11
|
||||
// = -2 * (qx*qy - qz*qw) / (1 - 2*(qy^2 + qz^2))
|
||||
// = -2 * (qy*qz - qx*qw) / (qw^2 + qx^2 - qy^2 - qz^2)
|
||||
|
||||
double asinValue;
|
||||
bool mask1, mask2;
|
||||
|
||||
asinValue = 2.0 * (q.i * q.k + q.s * q.j);
|
||||
mask1 = asinValue >= 1.0 - 10 * EPS_DOUBLE.value;
|
||||
mask2 = asinValue <= -1.0 + 10 * EPS_DOUBLE.value;
|
||||
if (mask1)
|
||||
asinValue = 1;
|
||||
if (mask2)
|
||||
asinValue = -1;
|
||||
if (mask1 || mask2)
|
||||
{
|
||||
ret.alpha = 0;
|
||||
ret.gamma = (asinValue > 0) ? (2.0 * atan2(q.i, q.s)) : (-2.0 * atan2(q.i, q.s));
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.alpha = atan2(-2.0 * (q.j * q.k - q.s * q.i), q.s * q.s - q.i * q.i - q.j * q.j + q.k * q.k);
|
||||
ret.gamma = atan2(-2.0 * (q.i * q.j - q.s * q.k), q.s * q.s + q.i * q.i - q.j * q.j - q.k * q.k);
|
||||
}
|
||||
ret.beta = asin(asinValue);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ret = EULERANGLES_NIL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @brief returns the rotation Quaternion from a euler angles */
|
||||
QUATERNION Quaternion_FromeEulerAngles(EULERANGLES e, EULERANGLES_TYPE type)
|
||||
{
|
||||
QUATERNION ret;
|
||||
double cosx, sinx, cosy, siny, cosz, sinz;
|
||||
cosx = cos(e.alpha * 0.5);
|
||||
sinx = sin(e.alpha * 0.5);
|
||||
cosy = cos(e.beta * 0.5);
|
||||
siny = sin(e.beta * 0.5);
|
||||
cosz = cos(e.gamma * 0.5);
|
||||
sinz = sin(e.gamma * 0.5);
|
||||
switch (type)
|
||||
{
|
||||
case EULERANGLES_ZYX:
|
||||
ret.s = cosx * cosy * cosz + sinx * siny * sinz;
|
||||
ret.i = cosx * cosy * sinz - sinx * siny * cosz;
|
||||
ret.j = cosx * siny * cosz + sinx * cosy * sinz;
|
||||
ret.k = sinx * cosy * cosz - cosx * siny * sinz;
|
||||
break;
|
||||
case EULERANGLES_ZYZ:
|
||||
ret.s = cosx * cosy * cosz - sinx * cosy * sinz;
|
||||
ret.i = cosx * siny * sinz - sinx * siny * cosz;
|
||||
ret.j = cosx * siny * cosz + sinx * siny * sinz;
|
||||
ret.k = sinx * cosy * cosz + cosx * cosy * sinz;
|
||||
break;
|
||||
case EULERANGLES_XYZ:
|
||||
ret.s = cosx * cosy * cosz - sinx * siny * sinz;
|
||||
ret.i = sinx * cosy * cosz + cosx * siny * sinz;
|
||||
ret.j = -sinx * cosy * sinz + cosx * siny * cosz;
|
||||
ret.k = cosx * cosy * sinz + sinx * siny * cosz;
|
||||
break;
|
||||
default:
|
||||
ret = QUATERNION_NIL;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @brief adapted from https://svn.code.sf.net/p/irrlicht/code/trunk/include/quaternion.h */
|
||||
QUATERNION Quaternion_RotationFromTo(COORD from, COORD to)
|
||||
{
|
||||
// Based on Stan Melax's article in Game Programming Gems
|
||||
COORD axis;
|
||||
QUATERNION ret;
|
||||
double c, s;
|
||||
Coord_Normalize(&from);
|
||||
Coord_Normalize(&to);
|
||||
|
||||
c = Coord_Dot(from, to);
|
||||
|
||||
if (c >= 1.0)
|
||||
{ // If dot == 1, vectors are the same
|
||||
return QUATERNION_IDENTITY; // identity
|
||||
}
|
||||
else if (c <= -1.0)
|
||||
{ // exactly opposite
|
||||
axis = Coord_Cross(COORD_X_AXIS, from);
|
||||
|
||||
if (Coord_Length(axis) == 0)
|
||||
axis = Coord_Cross(COORD_Y_AXIS, from);
|
||||
|
||||
// same as fromAxisAngle(axis, PI).normalize();
|
||||
ret.s = 0;
|
||||
ret.i = axis.x;
|
||||
ret.j = axis.y;
|
||||
ret.k = axis.z;
|
||||
Quaternion_Normalize(&ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
s = sqrt((1 + c) * 2);
|
||||
axis = Coord_Cross(from, to);
|
||||
Coord_ScalarDiv(&axis, s);
|
||||
ret.s = s * 0.5;
|
||||
ret.i = axis.x;
|
||||
ret.j = axis.y;
|
||||
ret.k = axis.z;
|
||||
Quaternion_Normalize(&ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @brief linear quaternion interpolation */
|
||||
QUATERNION Quaternion_Lerp(QUATERNION q1, QUATERNION q2, double t)
|
||||
{
|
||||
QUATERNION ret;
|
||||
Quaternion_ScalarMult(&q1, 1 - t);
|
||||
Quaternion_ScalarMult(&q1, t);
|
||||
ret = Quaternion_Add(q1, q2);
|
||||
Quaternion_Normalize(&ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @brief spherical linear interpolation */
|
||||
QUATERNION Quaternion_Slerp(QUATERNION q1, QUATERNION q2, double t)
|
||||
{
|
||||
double dot;
|
||||
QUATERNION q3, ret;
|
||||
dot = Quaternion_Dot(q1, q2);
|
||||
/* dot = cos(theta)
|
||||
if (dot < 0), q1 and q2 are more than 90 degrees apart,
|
||||
so we can invert one to reduce spinning */
|
||||
if (dot < 0)
|
||||
{
|
||||
dot = -dot;
|
||||
q3.s = -q2.s;
|
||||
q3.i = -q2.i;
|
||||
q3.j = -q2.j;
|
||||
q3.k = -q2.k;
|
||||
}
|
||||
else
|
||||
{
|
||||
q3 = q2;
|
||||
}
|
||||
|
||||
if (dot < 0.95)
|
||||
{
|
||||
double angle = acos(dot);
|
||||
Quaternion_ScalarMult(&q1, sin(angle * (1 - t)));
|
||||
Quaternion_ScalarMult(&q3, sin(angle * t));
|
||||
ret = Quaternion_Add(q1, q3);
|
||||
Quaternion_ScalarDiv(&ret, sin(angle));
|
||||
return ret;
|
||||
}
|
||||
// if the angle is small, use linear interpolation
|
||||
else
|
||||
{
|
||||
return Quaternion_Lerp(q1, q3, t);
|
||||
}
|
||||
}
|
||||
|
||||
/** @} LinkLayerGeometry_Quaternion */
|
||||
|
||||
/** @} LinkLayerGeometry */
|
||||
|
||||
/** @} LinkLayer */
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @file quaternion.h
|
||||
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||
* @version 0.0
|
||||
* @date 2023-05-06
|
||||
*
|
||||
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||
* Lab of Communication and Network
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @addtogroup LinkLayer
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup LinkLayerGeometry
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup LinkLayerGeometry_Quaternion
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef __QUATERNION_H
|
||||
#define __QUATERNION_H
|
||||
|
||||
#include "coord.h"
|
||||
#include "eulerangles.h"
|
||||
|
||||
/**
|
||||
* @struct QUATERNION
|
||||
* @brief Structure for standard quaternion
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
double s;
|
||||
double i;
|
||||
double j;
|
||||
double k;
|
||||
} QUATERNION;
|
||||
|
||||
extern const QUATERNION QUATERNION_IDENTITY;
|
||||
extern const QUATERNION QUATERNION_NIL;
|
||||
|
||||
/** @brief Subtracts two quaternions. */
|
||||
QUATERNION Quaternion_Sub(QUATERNION q1, QUATERNION q2);
|
||||
|
||||
/** @brief Adds two quaternions. */
|
||||
QUATERNION Quaternion_Add(QUATERNION q1, QUATERNION q2);
|
||||
|
||||
/** @brief Multiplies a quaternion by a real number. */
|
||||
void Quaternion_ScalarMult(QUATERNION *q, double t);
|
||||
|
||||
/** @brief Multiplies a quaternion by a real number. */
|
||||
QUATERNION Quaternion_GetScalarMult(QUATERNION a, double t);
|
||||
|
||||
/** @brief Divides a quaternion by a real number. */
|
||||
void Quaternion_ScalarDiv(QUATERNION *q, double t);
|
||||
|
||||
/** @brief Divides a quaternion by a real number. */
|
||||
QUATERNION Quaternion_GetScalarDiv(QUATERNION a, double t);
|
||||
|
||||
/** @brief Multiplies two quaternions. */
|
||||
QUATERNION Quaternion_Mult(QUATERNION q1, QUATERNION q2);
|
||||
|
||||
/** @brief Divides two quaternions. */
|
||||
QUATERNION Quaternion_Div(QUATERNION q1, QUATERNION q2);
|
||||
|
||||
/** @brief Dot product. */
|
||||
double Quaternion_Dot(QUATERNION q1, QUATERNION q2);
|
||||
|
||||
/** @brief Calculate a quaternion length^2 (omits calling square root). */
|
||||
double Quaternion_SquareLength(QUATERNION q);
|
||||
|
||||
/** @brief Calculate a quaternion length. */
|
||||
double Quaternion_Length(QUATERNION q);
|
||||
|
||||
/** @brief Normalize quaternion. */
|
||||
void Quaternion_Normalize(QUATERNION *q);
|
||||
|
||||
/** @brief Normalize quaternion. */
|
||||
QUATERNION Quaternion_GetNormalized(QUATERNION q);
|
||||
|
||||
/** @brief Conjugated quaternion. */
|
||||
void Quaternion_Conjugated(QUATERNION *q);
|
||||
|
||||
/** @brief Conjugated quaternion. */
|
||||
QUATERNION Quaternion_GetConjugated(QUATERNION q);
|
||||
|
||||
/** @brief Inverse quaternion. */
|
||||
void Quaternion_Inverse(QUATERNION *q);
|
||||
|
||||
/** @brief Inverse quaternion. */
|
||||
QUATERNION Quaternion_GeInverse(QUATERNION q);
|
||||
|
||||
/** @brief Get rotate angle of quaternion. */
|
||||
double Quaternion_GetRotationAngle(QUATERNION q);
|
||||
|
||||
/** @brief Get axis of quaternion. */
|
||||
COORD Quaternion_GetRotationAxis(QUATERNION q);
|
||||
|
||||
/** @brief Get the axis and rotate angle of a unit Quaternion */
|
||||
void Quaternion_GetRotationAxisAndAngle(QUATERNION q, COORD *axis, double *angle);
|
||||
|
||||
/** @brief Decompose the rotation on to 2 parts.
|
||||
1. Twist - rotation around the "direction" vector
|
||||
2. Swing - rotation around axis that is perpendicular to "direction" vector
|
||||
The rotation can be composed back by rotation = swing * twist
|
||||
|
||||
has singularity in case of swing_rotation close to 180 degrees rotation.
|
||||
if the input quaternion is of non-unit length, the outputs are non-unit as well
|
||||
otherwise, outputs are both unit
|
||||
*/
|
||||
void Quaternion_GetSwingAndTwist(QUATERNION q, COORD axis, QUATERNION *swing, QUATERNION *twist);
|
||||
|
||||
/** @brief rotates v by this quaternion (quaternion must be unit) */
|
||||
COORD Quaternion_Rotate(QUATERNION q, COORD v);
|
||||
|
||||
/** @brief returns the euler angles from a rotation Quaternion */
|
||||
EULERANGLES Quaternion_ToEulerAngles(QUATERNION q, EULERANGLES_TYPE type);
|
||||
|
||||
/** @brief returns the rotation Quaternion from a euler angles */
|
||||
QUATERNION Quaternion_FromeEulerAngles(EULERANGLES e, EULERANGLES_TYPE type);
|
||||
|
||||
/** @brief adapted from https://svn.code.sf.net/p/irrlicht/code/trunk/include/quaternion.h */
|
||||
QUATERNION Quaternion_RotationFromTo(COORD from, COORD to);
|
||||
|
||||
/** @brief linear quaternion interpolation */
|
||||
QUATERNION Quaternion_Lerp(QUATERNION q1, QUATERNION q2, double t);
|
||||
|
||||
/** @brief spherical linear interpolation */
|
||||
QUATERNION Quaternion_Slerp(QUATERNION q1, QUATERNION q2, double t);
|
||||
|
||||
#endif
|
||||
|
||||
/** @} LinkLayerGeometry_Quaternion */
|
||||
|
||||
/** @} LinkLayerGeometry */
|
||||
|
||||
/** @} LinkLayer */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,221 @@
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @file link_layer.h
|
||||
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||
* @brief DF Linklayer header file.
|
||||
* @version 0.1
|
||||
* @date 2023-05-06
|
||||
*
|
||||
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||
* Lab of Communication and Network
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @defgroup LinkLayer
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef __LINK_LAYER_H_
|
||||
#define __LINK_LAYER_H_
|
||||
|
||||
/***************************** Include Files *********************************/
|
||||
#include <stdint.h>
|
||||
#include "link_layer_types.h"
|
||||
#include "schdevent.h"
|
||||
#include "node_list.h"
|
||||
#include "circ_queue.h"
|
||||
#include "../phy_layer/phy_layer.h"
|
||||
#include "../../system_monitor.h"
|
||||
/************************** Constant Definitions *****************************/
|
||||
/***************** Macros (Inline Functions) Definitions *********************/
|
||||
#define AssertL2Event(instPtr, event) Linklayer_EventHandler(instPtr, event)
|
||||
/**************************** Type Definitions *******************************/
|
||||
|
||||
/**
|
||||
* @struct L2_CONFIG
|
||||
* @brief A struct holds all linklayer initialization parameters
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
L2_NODE_TYPE myType; ///< node type
|
||||
uint8_t clustId; ///< node cluster id
|
||||
uint8_t myId; ///< node id
|
||||
uint8_t headId; ///< head node id
|
||||
uint8_t netScale; ///< net scale
|
||||
PHY_INST *phyInstPtr; ///< pointer to system physical layer instance
|
||||
TMC_INST *tmcInstPtr; ///< pointer to system timer controller layer instance
|
||||
} L2_CONFIG;
|
||||
|
||||
/**
|
||||
* @struct L2_LOG
|
||||
* @brief A struct holds linklayer operating log
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t frameRx; ///< total rx frame count
|
||||
uint32_t frameTx; ///< total tx frame count
|
||||
uint32_t frameRecv; ///< total received frame count
|
||||
uint32_t frameCorrect; ///< total correctly received frame count
|
||||
|
||||
uint32_t advRxCnt; ///< advertise rx frame count
|
||||
uint32_t advTxCnt; ///< advertise tx frame count
|
||||
uint32_t advRecvCnt; ///< advertise received frame count
|
||||
uint32_t advCorrectCnt; ///< advertise correctly received frame count
|
||||
|
||||
uint32_t cfmRxCnt; ///< confirm rx frame count
|
||||
uint32_t cfmTxCnt; ///< confirm tx frame count
|
||||
uint32_t cfmRecvCnt; ///< confirm received frame count
|
||||
uint32_t cfmCorrectCnt; ///< confirm correctly received frame count
|
||||
|
||||
uint32_t svcRxCnt; ///< service rx frame count
|
||||
uint32_t svcTxCnt; ///< service tx frame count
|
||||
uint32_t svcRecvCnt; ///< service received frame count
|
||||
uint32_t svcCorrectCnt; ///< service correctly received frame count
|
||||
|
||||
int64_t timeDev; ///< last time deviation estimation result
|
||||
uint8_t lastBeamWidth; ///< last beam width
|
||||
uint32_t reconnectCnt; ///< reconnect trial count
|
||||
|
||||
PAYLOAD rxLog;
|
||||
PAYLOAD txLog;
|
||||
} L2_LOG;
|
||||
|
||||
/**
|
||||
* @struct L2_INST
|
||||
* @brief A linklayer instance
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
L2_CONFIG config; ///< linklayer configuration parameters
|
||||
L2_NODE_INFO myInfo; ///< current node info
|
||||
NODE_LIST *nodeList; ///< discovered node list
|
||||
L2_SCHD_POOL *schdEventPool; ///< event schedule pool
|
||||
uint32_t netStartTime; ///< network start time
|
||||
bool isEnable; ///< indicates if the node is connected to the network
|
||||
bool dataAvail; ///< indicates if there is a valid received frame data in rx buffer
|
||||
bool cxn2Net; ///< indicates if the node is connected to the network
|
||||
L2_RCD frameNum; ///< stores the last current and next frame number.
|
||||
L2_RCD slotNum; ///< stores the last current and next slot number.
|
||||
L2_RCD frame; ///< stores the last current and next link layer frame type.
|
||||
L2_RCD tor; ///< stores the last current and next link layer tx/rx state.
|
||||
L2_NODE_STATE mainState; ///< the main state of link layer state
|
||||
L2_NODE_STATE nextState; ///< next state of link layer state, which will be applied to mainState every second.
|
||||
L2_RTNE_CONFIG rtneConfig; ///< current routine table configuration and status.
|
||||
L2_SCAN_FSM *scanFSM; ///< FSM of scan net (link set up)
|
||||
L2_SVC_FSM *serviceFSM; ///< FSM of service net (data service)
|
||||
uint8_t *sendPktData; ///< send data buffer
|
||||
uint8_t *recvPktData; ///< received data buffer
|
||||
L2_LOG log; ///< Linklayer operating log
|
||||
// for system log
|
||||
SYSINFO sysInfo; ///< system info
|
||||
LINKLOG linkLog; ///< linklayer log for system monitor
|
||||
} L2_INST;
|
||||
|
||||
/************************** Variable Definitions *****************************/
|
||||
extern L2_RTNE_TABLE_ENTRY *initTable[L2_INIT_RTNE_PERIOD];
|
||||
extern L2_RTNE_TABLE_ENTRY *normalTable[L2_NORMAL_RTNE_PERIOD];
|
||||
/************************** Function Prototypes ******************************/
|
||||
/**
|
||||
* @defgroup LinkLayer_Main
|
||||
* @{
|
||||
*/
|
||||
int32_t Linklayer_Init(L2_INST **instPtr, const L2_CONFIG *config);
|
||||
int32_t Linklayer_Reconfig(L2_INST *instPtr, const L2_CONFIG *config);
|
||||
void Linklayer_Destroy(L2_INST *instPtr);
|
||||
int32_t Linklayer_Start(L2_INST *instPtr);
|
||||
int32_t Linklayer_Halt(L2_INST *instPtr);
|
||||
int32_t Linklayer_Proc(L2_INST *instPtr);
|
||||
int32_t Linklayer_EventHandler(L2_INST *instPtr, const L2_EVENT *l2Event);
|
||||
int32_t Linklayer_PktHandler(L2_INST *instPtr, L2_FRAME_TYPE frameType);
|
||||
int32_t L2_SteerBeam2Node(L2_INST *instPtr, uint8_t nodeId);
|
||||
int32_t L2_SetupNextSlot(L2_INST *instPtr, L2_TOR_TYPE txrxMode, L2_FRAME_TYPE frameType);
|
||||
/** @} LinkLayer_Main*/
|
||||
|
||||
/**
|
||||
* @defgroup LinkLayer_Framing
|
||||
* @{
|
||||
*/
|
||||
void L2_FrameInsertChunk(uint8_t *frame, size_t offset, size_t bytes, const void *chunk);
|
||||
void L2_FrameGetChunk(uint8_t *frame, size_t offset, size_t bytes, void *chunk);
|
||||
int32_t L2_CrcAppend(uint8_t *dataBuff, uint32_t dataLen, uint32_t crcPos, L2_CRC_TYPE crcType);
|
||||
bool L2_CrcCheck(uint8_t *dataBuff, uint32_t dataLen, L2_CRC_TYPE crcType);
|
||||
/** @} LinkLayer_Framing*/
|
||||
|
||||
/**
|
||||
* @defgroup LinkLayer_Scheduler
|
||||
* @{
|
||||
*/
|
||||
void L2_EventPoolHandler(L2_INST *instPtr);
|
||||
int32_t L2_ScheduleEventAt(L2_INST *instPtr, L2_SCHD_EVENT *schdEvent, uint32_t frameNo, uint32_t slotNo);
|
||||
int32_t L2_ScheduleEventAfter(L2_INST *instPtr, L2_SCHD_EVENT *schdEvent, uint32_t numSlots);
|
||||
int32_t L2_RescheduleEventAt(L2_INST *instPtr, L2_SCHD_EVENT *schdEvent, uint32_t frameNo, uint32_t slotNo);
|
||||
int32_t L2_RescheduleEventAfter(L2_INST *instPtr, L2_SCHD_EVENT *schdEvent, uint32_t numSlots);
|
||||
/** @} LinkLayer_Scheduler*/
|
||||
|
||||
/**
|
||||
* @defgroup LinkLayer_Scan
|
||||
* @{
|
||||
*/
|
||||
int32_t L2_Scan_Init(L2_SCAN_FSM **scanFSMPtr);
|
||||
void L2_Scan_RefreashScanTable(L2_INST *instPtr);
|
||||
void L2_Scan_Reset(L2_SCAN_FSM *scanFSMPtr);
|
||||
void L2_Scan_Destroy(L2_SCAN_FSM *scanFSMPtr);
|
||||
int32_t L2_Scan_Proc(L2_INST *instPtr);
|
||||
int32_t L2_Scan_PktHandler(L2_INST *instPtr, uint8_t *msg);
|
||||
int32_t L2_Scan_Routine(L2_INST *instPtr, const L2_RTNE_TABLE_ENTRY *schedEntry);
|
||||
/** @} LinkLayer_Scan*/
|
||||
|
||||
/**
|
||||
* @defgroup LinkLayer_Service
|
||||
* @{
|
||||
*/
|
||||
int32_t L2_Service_Init(L2_SVC_FSM **svcFSMPtr);
|
||||
void L2_Service_Reset(L2_SVC_FSM *svcFSMPtr);
|
||||
void L2_Service_Destroy(L2_SVC_FSM *svcFSMPtr);
|
||||
int32_t L2_Service_PktHandler(L2_INST *instPtr, uint8_t *msg);
|
||||
int32_t L2_Service_Proc(L2_INST *instPtr);
|
||||
int32_t L2_Service_Routine(L2_INST *instPtr, const L2_RTNE_TABLE_ENTRY *schedEntry);
|
||||
/** @} LinkLayer_Service*/
|
||||
|
||||
/**
|
||||
* @defgroup LinkLayer_TimeSync
|
||||
* @{
|
||||
*/
|
||||
int32_t L2_GetTimeDeviation(L2_INST *instPtr, uint32_t frameNum, uint32_t slotNum, bool relative, int64_t *timeDev);
|
||||
void L2_TimeAdjust(L2_INST *instPtr, const int64_t *timeDev);
|
||||
/** @} LinkLayer_TimeSync*/
|
||||
|
||||
/**
|
||||
* @defgroup LinkLayer_Utility
|
||||
* @{
|
||||
*/
|
||||
uint8_t L2_GetNodeId(L2_INST *instPtr);
|
||||
uint8_t L2_GetClusterId(L2_INST *instPtr);
|
||||
uint8_t L2_GetHeadId(L2_INST *instPtr);
|
||||
uint8_t L2_GetNetScale(L2_INST *instPtr);
|
||||
L2_NODE_TYPE L2_GetNodeType(L2_INST *instPtr);
|
||||
L2_NODE_STATE L2_GetMainState(L2_INST *instPtr);
|
||||
bool L2_isStarted(L2_INST *instPtr);
|
||||
bool L2_isDataAvail(L2_INST *instPtr);
|
||||
bool L2_isCxn2Net(L2_INST *instPtr);
|
||||
uint32_t L2_GetFrameLen(L2_FRAME_TYPE l2FrameType);
|
||||
uint32_t L2_GetLastFrameNum(L2_INST *instPtr);
|
||||
uint32_t L2_GetLastSlotNum(L2_INST *instPtr);
|
||||
L2_FRAME_TYPE L2_GetLastFrameType(L2_INST *instPtr);
|
||||
L2_TOR_TYPE L2_GetLastTor(L2_INST *instPtr);
|
||||
uint32_t L2_GetCurrentFrameNum(L2_INST *instPtr);
|
||||
uint32_t L2_GetCurrentSlotNum(L2_INST *instPtr);
|
||||
L2_FRAME_TYPE L2_GetCurrentFrameType(L2_INST *instPtr);
|
||||
L2_TOR_TYPE L2_GetCurrentTor(L2_INST *instPtr);
|
||||
uint32_t L2_GetNextFrameNum(L2_INST *instPtr);
|
||||
uint32_t L2_GetNextSlotNum(L2_INST *instPtr);
|
||||
L2_FRAME_TYPE L2_GetNextFrameType(L2_INST *instPtr);
|
||||
L2_TOR_TYPE L2_GetNextTor(L2_INST *instPtr);
|
||||
L2_FRAME_TYPE L2_GetLastOptFrameType(L2_INST *instPtr);
|
||||
L1_FRAME_TYPE L2_L2frame2L1frame(L2_FRAME_TYPE l2Frame);
|
||||
/** @} LinkLayer_Utility*/
|
||||
|
||||
#endif /* __LINK_LAYER_H_ */
|
||||
|
||||
/** @} LinkLayer*/
|
||||
+262
@@ -0,0 +1,262 @@
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @file link_layer_types.h
|
||||
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||
* @brief DF Linklayer types definition.
|
||||
* @version 0.1
|
||||
* @date 2023-05-06
|
||||
*
|
||||
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||
* Lab of Communication and Network
|
||||
*
|
||||
******************************************************************************/
|
||||
/**
|
||||
* @defgroup LinkLayer
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef __LINK_LAYER_DEF_H_
|
||||
#define __LINK_LAYER_DEF_H_
|
||||
|
||||
/***************************** Include Files *********************************/
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "geometry/coord.h"
|
||||
#include "geometry/quaternion.h"
|
||||
#include "../phy_layer/phy_layer.h"
|
||||
#ifndef EMULATION
|
||||
#include "../config/app_config.h"
|
||||
#endif
|
||||
/************************** Constant Definitions *****************************/
|
||||
/**
|
||||
* @name Linklayer_Common_Constants
|
||||
* @{
|
||||
*/
|
||||
// Common node ID definition
|
||||
#define L2_BROADCAST_ID 0xFF
|
||||
#define L2_NONE_ID 0
|
||||
|
||||
// Routine configure
|
||||
#define L2_INIT_RTNE_PERIOD 1
|
||||
#define L2_NORMAL_RTNE_PERIOD 1
|
||||
|
||||
// Common slot number definition
|
||||
#define L2_SLOTNO_NONE 0
|
||||
#define L2_FRAMENO_NONE 0
|
||||
|
||||
// Common number of slots definition
|
||||
#define L2_SLOTS_PER_FRAME 100
|
||||
#define L2_SLOTS_PER_SUBFRAME 20
|
||||
|
||||
#define L2_NUM_SLOTS_NONE UINT32_MAX
|
||||
#define L2_NUM_SLOTS_100MS 20
|
||||
#define L2_NUM_SLOTS_20MS 4
|
||||
#define L2_NUM_SLOTS_10MS 2
|
||||
#define L2_NUM_SLOTS_5MS 1
|
||||
#define L2_NUM_SLOTS_SKIP 0
|
||||
/** @} Linklayer_Common_Constants*/
|
||||
|
||||
/**************************** Type Definitions *******************************/
|
||||
|
||||
/**
|
||||
* @struct L2_RCD
|
||||
* @brief Linklayer recode buffer
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t last;
|
||||
uint32_t curr;
|
||||
uint32_t next;
|
||||
} L2_RCD;
|
||||
|
||||
/**
|
||||
* @enum L2_TOR_TYPE
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
L2_TOR_SUSPEND = 0,
|
||||
L2_TOR_TX = 1,
|
||||
L2_TOR_RX = 2
|
||||
} L2_TOR_TYPE;
|
||||
|
||||
/**
|
||||
* @enum L2_NODE_TYPE
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
L2_NODE_NONE = 0,
|
||||
L2_NODE_HEAD = 1,
|
||||
L2_NODE_MEMBER = 2,
|
||||
L2_NODE_BACKUP = 3
|
||||
} L2_NODE_TYPE;
|
||||
|
||||
/**
|
||||
* @enum L2_NODE_STATE
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
L2_NONE_STATE = 0,
|
||||
L2_INIT_STATE = 1,
|
||||
L2_NORMAL_STATE = 2,
|
||||
L2_INTRA_SEEK_STATE = 3,
|
||||
L2_INTER_SEEK_STATE = 4,
|
||||
L2_SEEK_STATE = 5
|
||||
} L2_NODE_STATE;
|
||||
|
||||
/**
|
||||
* @struct L2_NODE_INFO
|
||||
* @brief Node information struct contains the detail node info which needed by the link layer.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t nodeId; ///< node ID
|
||||
uint8_t clustId; ///< node cluster ID
|
||||
uint8_t headId; ///< cluster head ID
|
||||
L2_NODE_TYPE nodeType; ///< node type
|
||||
uint8_t beamNo; ///< beam number to this node
|
||||
COORD pos; ///< node position
|
||||
COORD speed; ///< node speed
|
||||
QUATERNION attitude; ///< node attitude
|
||||
} L2_NODE_INFO;
|
||||
|
||||
/**
|
||||
* @enum L2_EVENT_TYPE
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
L2_EV_NONE = 0,
|
||||
L2_EV_SCAN_PROC_DONE = 1,
|
||||
L2_EV_NET_ADV_UPDATE = 2,
|
||||
L2_EV_NET_SETUP_DONE = 3,
|
||||
L2_EV_TIME_SYNC = 4,
|
||||
L2_EV_LOST_CXN = 5,
|
||||
L2_EV_LOST_NODE = 6,
|
||||
L2_EV_SET_FRAME_NUM = 7,
|
||||
L2_EV_SET_SLOT_NUM = 8,
|
||||
L2_EV_MAIN_STATE_UPDATE = 9,
|
||||
L2_ROUTINE_FINISH = 10,
|
||||
L2_ROUTINE_UPDATE = 11
|
||||
} L2_EVENT_TYPE;
|
||||
|
||||
/**
|
||||
* @struct L2_EVENT
|
||||
* @brief Linklayer event instance
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
L2_EVENT_TYPE event; ///< event type
|
||||
void *msg; ///< event message
|
||||
} L2_EVENT;
|
||||
|
||||
/**
|
||||
* @enum L2_SLOT_TYPE
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
L2_SLOT_NONE = 0,
|
||||
L2_SLOT_IDLE = 1,
|
||||
L2_SLOT_SCAN = 2,
|
||||
L2_SLOT_ADVERTISE = 3,
|
||||
L2_SLOT_CONFIRM = 4,
|
||||
L2_SLOT_SERVICE = 5,
|
||||
} L2_SLOT_TYPE;
|
||||
|
||||
/**
|
||||
* @enum L2_FRAME_TYPE
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
L2_NONE_FRAME = 0,
|
||||
L2_SCAN_FRAME = 1,
|
||||
L2_ADV_FRAME = 2,
|
||||
L2_CFM_FRAME = 3,
|
||||
L2_SVC_FRAME = 4
|
||||
} L2_FRAME_TYPE;
|
||||
|
||||
/**
|
||||
* @enum L2_CRC_TYPE
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
L2_CRC_NONE = 0,
|
||||
L2_CRC16_1021 = 1,
|
||||
L2_CRC16_8005 = 2,
|
||||
L2_CRC8_31 = 3
|
||||
} L2_CRC_TYPE;
|
||||
|
||||
/**
|
||||
* @struct L2_RTNE_TABLE_ENTRY
|
||||
* @brief Linklayer routine table entry
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
L2_SLOT_TYPE slotType : 8; ///< slot type
|
||||
uint8_t slotSeq; ///< slot sequence number
|
||||
uint8_t src; ///< source node ID
|
||||
uint8_t dst; ///< destination node ID
|
||||
} L2_RTNE_TABLE_ENTRY;
|
||||
|
||||
/**
|
||||
* @enum SCAN_STAGE
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
L2_SCAN_NONE_STAGE = 0,
|
||||
L2_SCAN_INIT_STAGE = 1,
|
||||
L2_SCAN_ADV_STAGE = 2,
|
||||
L2_SCAN_CFM_STAGE = 3
|
||||
} SCAN_STAGE;
|
||||
|
||||
/**
|
||||
* @struct L2_SCAN_FSM
|
||||
* @brief Linklayer scan process FSM instance
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
bool isLocked; ///< indicates if init acq done(beam locked).
|
||||
bool isAdvRecvd; ///< indicates if advertisement frame done(beam locked).
|
||||
bool isAckPending; ///< indicates if confirm message acked
|
||||
uint8_t scanCnt; ///< scan count
|
||||
uint8_t advTimeout; ///< adv receive try count
|
||||
uint8_t cfmTimeout; ///< cmf receive try count
|
||||
SCAN_STAGE scanStage; ///< scan stage \n
|
||||
/// only for member node
|
||||
uint8_t beamNo; ///< locked beam number
|
||||
uint8_t tableNo; ///< scan table index
|
||||
} L2_SCAN_FSM;
|
||||
|
||||
/**
|
||||
* @struct L2_SVC_FSM
|
||||
* @brief Linklayer service process FSM
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t txCnt; ///< tx frame count
|
||||
uint32_t rxCnt; ///< rx frame count
|
||||
uint32_t rxdCnt; ///< received frame count
|
||||
#ifdef DATALINK_ENABLE_BERTEST
|
||||
uint32_t bitTotal; ///< received bits count
|
||||
uint32_t bitError; ///< error bits count
|
||||
double lossRate; ///< packet loss rate
|
||||
double errorRate; ///< bit error rate
|
||||
#endif
|
||||
} L2_SVC_FSM;
|
||||
|
||||
/**
|
||||
* @struct L2_RTNE_CONFIG
|
||||
* @brief Linklayer routine table configuration
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
L2_RTNE_TABLE_ENTRY **rtneTable; ///< routine table
|
||||
uint32_t rtnePrd; ///< period of routine table
|
||||
L2_RTNE_TABLE_ENTRY *last; ///< last routine entry
|
||||
L2_RTNE_TABLE_ENTRY *curr; ///< curent routine entry
|
||||
L2_RTNE_TABLE_ENTRY *next; ///< next routine entry
|
||||
} L2_RTNE_CONFIG;
|
||||
|
||||
/************************** Variable Definitions *****************************/
|
||||
|
||||
#endif /* __LINK_LAYER_DEF_H_ */
|
||||
|
||||
/** @} LinkLayer*/
|
||||
@@ -0,0 +1,130 @@
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @file msg_def.c
|
||||
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||
* @brief DF Linklayer message definition constants.
|
||||
* @version 0.0
|
||||
* @date 2023-05-06
|
||||
*
|
||||
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||
* Lab of Communication and Network
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @addtogroup LinkLayer
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @name LinkLayer_MSG_Constants
|
||||
* @{
|
||||
*/
|
||||
#ifndef __L2_MSG_DEF_H_
|
||||
#define __L2_MSG_DEF_H_
|
||||
|
||||
#define L2_PACK_LEN_MAX 512 // bytes
|
||||
|
||||
#define L2_ADV_PACK_LEN 28 // bytes
|
||||
#define L2_CMF_PACK_LEN 268 // bytes
|
||||
#define L2_SVC_PACK_LEN 268 // bytes
|
||||
|
||||
// Common structure:
|
||||
// [bytes] [name]
|
||||
// 4 fame number
|
||||
// 1 slot number
|
||||
// 1 source id
|
||||
// 1 destination id
|
||||
// 1 message type
|
||||
#define L2_MSG_FRAME_NUM 0
|
||||
#define L2_MSG_FRAME_NUM_LEN 4
|
||||
#define L2_MSG_SLOT_NUM 4
|
||||
#define L2_MSG_SLOT_NUM_LEN 1
|
||||
#define L2_MSG_SRC_ID 5
|
||||
#define L2_MSG_SRC_ID_LEN 1
|
||||
#define L2_MSG_DST_ID 6
|
||||
#define L2_MSG_DST_ID_LEN 1
|
||||
#define L2_MSG_TYPE 7
|
||||
#define L2_MSG_TYPE_LEN 1
|
||||
#define L2_MSG_PAYLOAD 8
|
||||
|
||||
// advertisement payload structure:
|
||||
// [bytes] [name]
|
||||
// 4 position x
|
||||
// 4 position y
|
||||
// 4 position z
|
||||
// 4 net start time
|
||||
// 2 crc
|
||||
#define L2_MSG_ADV_SRC_POSX 8
|
||||
#define L2_MSG_ADV_SRC_POSX_LEN 4
|
||||
#define L2_MSG_ADV_SRC_POSY 12
|
||||
#define L2_MSG_ADV_SRC_POSY_LEN 4
|
||||
#define L2_MSG_ADV_SRC_POSZ 16
|
||||
#define L2_MSG_ADV_SRC_POSZ_LEN 4
|
||||
#define L2_MSG_ADV_SRC_NETSTART_TIME 20
|
||||
#define L2_MSG_ADV_SRC_NETSTART_TIME_LEN 4
|
||||
#define L2_MSG_ADV_SVC_CRC 26
|
||||
#define L2_MSG_ADV_SVC_CRC_LEN 2
|
||||
|
||||
// confirm payload structure:
|
||||
// [bytes] [name]
|
||||
// 4 position x
|
||||
// 4 position y
|
||||
// 4 position z
|
||||
// 4 speed x
|
||||
// 4 speed y
|
||||
// 4 speed z
|
||||
// 2 crc
|
||||
#define L2_MSG_CFM_SRC_POSX 8
|
||||
#define L2_MSG_CFM_SRC_POSX_LEN 4
|
||||
#define L2_MSG_CFM_SRC_POSY 12
|
||||
#define L2_MSG_CFM_SRC_POSY_LEN 4
|
||||
#define L2_MSG_CFM_SRC_POSZ 16
|
||||
#define L2_MSG_CFM_SRC_POSZ_LEN 4
|
||||
#define L2_MSG_CFM_SRC_SPEEDX 20
|
||||
#define L2_MSG_CFM_SRC_SPEEDX_LEN 4
|
||||
#define L2_MSG_CFM_SRC_SPEEDY 24
|
||||
#define L2_MSG_CFM_SRC_SPEEDY_LEN 4
|
||||
#define L2_MSG_CFM_SRC_SPEEDZ 28
|
||||
#define L2_MSG_CFM_SRC_SPEEDZ_LEN 4
|
||||
#define L2_MSG_CFM_PAYLOAD_ID 32
|
||||
#define L2_MSG_CFM_PAYLOAD_ID_LEN 4
|
||||
#define L2_MSG_CFM_PAYLOAD 36
|
||||
#define L2_MSG_CFM_PAYLOAD_LEN 230
|
||||
#define L2_MSG_CFM_CRC 266
|
||||
#define L2_MSG_CFM_CRC_LEN 2
|
||||
|
||||
// service payload structure:
|
||||
// [bytes] [name]
|
||||
// 4 position x
|
||||
// 4 position y
|
||||
// 4 position z
|
||||
// 4 speed x
|
||||
// 4 speed y
|
||||
// 4 speed z
|
||||
// 234 payload
|
||||
// 2 crc
|
||||
#define L2_MSG_SVC_SRC_POSX 8
|
||||
#define L2_MSG_SVC_SRC_POSX_LEN 4
|
||||
#define L2_MSG_SVC_SRC_POSY 12
|
||||
#define L2_MSG_SVC_SRC_POSY_LEN 4
|
||||
#define L2_MSG_SVC_SRC_POSZ 16
|
||||
#define L2_MSG_SVC_SRC_POSZ_LEN 4
|
||||
#define L2_MSG_SVC_SRC_SPEEDX 20
|
||||
#define L2_MSG_SVC_SRC_SPEEDX_LEN 4
|
||||
#define L2_MSG_SVC_SRC_SPEEDY 24
|
||||
#define L2_MSG_SVC_SRC_SPEEDY_LEN 4
|
||||
#define L2_MSG_SVC_SRC_SPEEDZ 28
|
||||
#define L2_MSG_SVC_SRC_SPEEDZ_LEN 4
|
||||
#define L2_MSG_SVC_PAYLOAD_ID 32
|
||||
#define L2_MSG_SVC_PAYLOAD_ID_LEN 4
|
||||
#define L2_MSG_SVC_PAYLOAD 36
|
||||
#define L2_MSG_SVC_PAYLOAD_LEN 230
|
||||
#define L2_MSG_SVC_CRC 266
|
||||
#define L2_MSG_SVC_CRC_LEN 2
|
||||
|
||||
#endif //__L2_MSG_DEF_H_
|
||||
|
||||
/** @} LinkLayer_MSG_Constants*/
|
||||
|
||||
/** @} LinkLayer*/
|
||||
@@ -0,0 +1,561 @@
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @file node_list.c
|
||||
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||
* @brief DF Linklayer node list implementation file
|
||||
* @version 0.0
|
||||
* @date 2023-05-06
|
||||
*
|
||||
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||
* Lab of Communication and Network
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @addtogroup LinkLayer
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup LinkLayer_NodeList
|
||||
* @{
|
||||
*/
|
||||
/***************************** Include Files *********************************/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "link_layer_types.h"
|
||||
#include "node_list.h"
|
||||
#include "clist.h"
|
||||
#include "common.h"
|
||||
#include "error.h"
|
||||
|
||||
/***************** Macros (Inline Functions) Definitions *********************/
|
||||
/**
|
||||
* @brief Get the node list length
|
||||
* @param list pointer to node list
|
||||
*/
|
||||
inline uint32_t L2_GetNodeListLen(NODE_LIST *list)
|
||||
{
|
||||
ASSERT(list != NULL);
|
||||
return list->len;
|
||||
}
|
||||
/**************************** Type Definitions *******************************/
|
||||
|
||||
/************************** Variable Definitions *****************************/
|
||||
static NODE_ENTRY util_entry;
|
||||
/************************** Function Prototypes ******************************/
|
||||
/**
|
||||
* @brief helper function to free node entry.
|
||||
*/
|
||||
static void entry_free(void *val)
|
||||
{
|
||||
free(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief helper function to match node entries by nodeIds
|
||||
*/
|
||||
static int8_t entry_compare(void *a, void *b)
|
||||
{
|
||||
ASSERT(a != NULL);
|
||||
ASSERT(b != NULL);
|
||||
register uint8_t idA, idB;
|
||||
idA = ((NODE_ENTRY *)a)->nodeInfo.nodeId;
|
||||
idB = ((NODE_ENTRY *)b)->nodeInfo.nodeId;
|
||||
if (idA == idB)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (idA < idB)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Initialize node list
|
||||
*
|
||||
* @param list
|
||||
*
|
||||
* @return SUCCESS
|
||||
* ENOMEM - not enough memory.
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t L2_NodeList_Init(NODE_LIST **list)
|
||||
{
|
||||
(*list) = clist_new();
|
||||
if (*list == NULL)
|
||||
{
|
||||
return ENOMEM;
|
||||
}
|
||||
(*list)->free = entry_free;
|
||||
(*list)->compare = entry_compare;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Clear all nodes in the node list, free allocated memory.
|
||||
*
|
||||
* @param list
|
||||
* @return NONE
|
||||
*
|
||||
******************************************************************************/
|
||||
void L2_NodeList_Clear(NODE_LIST *list)
|
||||
{
|
||||
ASSERT(list != NULL);
|
||||
clist_clear(list);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Completely destroy node list.
|
||||
*
|
||||
* @param list
|
||||
*
|
||||
* @return NONE
|
||||
*
|
||||
******************************************************************************/
|
||||
void L2_NodeList_Destroy(NODE_LIST *list)
|
||||
{
|
||||
clist_destroy(list);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Get node entry from node list base on node id.
|
||||
*
|
||||
* @param list
|
||||
* @param nodeId
|
||||
*
|
||||
* @return Node entry \n
|
||||
* NULL if node dose not exist.
|
||||
*
|
||||
******************************************************************************/
|
||||
NODE_ENTRY *L2_GetNodeById(NODE_LIST *list, uint8_t nodeId)
|
||||
{
|
||||
ASSERT(list != NULL);
|
||||
if (nodeId == L2_BROADCAST_ID || nodeId == L2_NONE_ID)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
util_entry.nodeInfo.nodeId = nodeId;
|
||||
clist_node_t *node = clist_find(list, &util_entry);
|
||||
if (node == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ((NODE_ENTRY *)node->val);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Append a new node entry to the node list
|
||||
*
|
||||
* @param list
|
||||
* @param nodeId
|
||||
* @param nodeType
|
||||
*
|
||||
* @return SUCCESS Node was added successfully.\n
|
||||
* Other Error occurred.(Node already exist, memory alloc error ect.)
|
||||
*
|
||||
******************************************************************************/
|
||||
NODE_ENTRY *L2_AppendNode(NODE_LIST *list, uint8_t nodeId, L2_NODE_TYPE nodeType)
|
||||
{
|
||||
ASSERT(list != NULL);
|
||||
if (L2_isNodeInList(list, nodeId))
|
||||
{
|
||||
DBG_WARNING("Node [%" PRIu8 "] already exist.\n", nodeId);
|
||||
return NULL;
|
||||
}
|
||||
DBG_INFO("Link layer appending node [%" PRIu8 "] to node list.\n", nodeId);
|
||||
NODE_ENTRY *nodeEntry = (NODE_ENTRY *)malloc(sizeof(NODE_ENTRY));
|
||||
if (nodeEntry == NULL)
|
||||
{
|
||||
DBG_ERROR("Failed to allocated memory for nodeEntry.\n");
|
||||
return NULL;
|
||||
}
|
||||
clist_node_t *node = clist_node_new(nodeEntry);
|
||||
if (node == NULL)
|
||||
{
|
||||
DBG_ERROR("Failed to allocated memory for list node.\n");
|
||||
free(nodeEntry);
|
||||
return NULL;
|
||||
}
|
||||
nodeEntry->nodeInfo.nodeId = nodeId;
|
||||
nodeEntry->nodeInfo.nodeType = (uint8_t)nodeType;
|
||||
nodeEntry->nodeInfo.pos.x = 0;
|
||||
nodeEntry->nodeInfo.pos.y = 0;
|
||||
nodeEntry->nodeInfo.pos.z = 0;
|
||||
nodeEntry->nodeInfo.speed.x = 0;
|
||||
nodeEntry->nodeInfo.speed.y = 0;
|
||||
nodeEntry->nodeInfo.speed.z = 0;
|
||||
nodeEntry->nodeInfo.beamNo = 0;
|
||||
nodeEntry->ttlCnt = 0;
|
||||
clist_rpush(list, node);
|
||||
return nodeEntry;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Delete a node in list based on node id.
|
||||
*
|
||||
* @param list
|
||||
* @param nodeId
|
||||
*
|
||||
* @return SUCCESS Node has been successfully deleted.\n
|
||||
* Other Node not exist.
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t L2_DeleteNodeById(NODE_LIST *list, uint8_t nodeId)
|
||||
{
|
||||
ASSERT(list != NULL);
|
||||
util_entry.nodeInfo.nodeId = nodeId;
|
||||
clist_node_t *node = clist_find(list, &util_entry);
|
||||
if (node == NULL)
|
||||
{
|
||||
DBG_WARNING("Node [%" PRIu8 "] in not in node list, skip deleting process.\n", nodeId);
|
||||
return SUCCESS;
|
||||
}
|
||||
DBG_INFO("Deleting node [%" PRIu8 "].\n", nodeId);
|
||||
clist_remove(list, node);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Check whether the node is already in the node list.
|
||||
*
|
||||
* @param list
|
||||
* @param nodeId
|
||||
*
|
||||
* @return true node in the list\n
|
||||
* false node not in the list
|
||||
*
|
||||
******************************************************************************/
|
||||
bool L2_isNodeInList(NODE_LIST *list, uint8_t nodeId)
|
||||
{
|
||||
ASSERT(list != NULL);
|
||||
return (L2_GetNodeById(list, nodeId) != NULL);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Get the distance between me and the node.
|
||||
*
|
||||
* @param list
|
||||
* @param nodeId
|
||||
* @param dst A pointer to store distance.
|
||||
*
|
||||
* @return SUCCESS distance has been successfully store in dst\n
|
||||
* FAILURE Node dose not exit.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
int32_t L2_GetDistance(NODE_LIST *list, COORD myCoord, uint8_t nodeId, double *dst)
|
||||
{
|
||||
ASSERT(list != NULL);
|
||||
NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId);
|
||||
if (nodeEntry == NULL)
|
||||
{
|
||||
return FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
*dst = Coord_Distance(myCoord, nodeEntry->nodeInfo.pos);
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Update node positions information.
|
||||
*
|
||||
* @param list
|
||||
* @param nodeId
|
||||
* @param newPos A structure stores the corresponding node position info.
|
||||
*
|
||||
* @return SUCCESS update successfully.\n
|
||||
* FAILURE node not exist.
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t L2_UpdateNodePos(NODE_LIST *list, uint8_t nodeId, const COORD *newPos)
|
||||
{
|
||||
ASSERT(list != NULL);
|
||||
NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId);
|
||||
if (nodeEntry == NULL)
|
||||
{
|
||||
return FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(&(nodeEntry->nodeInfo.pos), newPos, sizeof(COORD));
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Get node positions information.
|
||||
*
|
||||
* @param list
|
||||
* @param nodeId
|
||||
* @param newPos A structure stores the corresponding node position info.
|
||||
*
|
||||
* @return SUCCESS update successfully.\n
|
||||
* FAILURE node not exist.
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t L2_GetNodePos(NODE_LIST *list, uint8_t nodeId, COORD *pos)
|
||||
{
|
||||
ASSERT(list != NULL);
|
||||
NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId);
|
||||
if (nodeEntry == NULL)
|
||||
{
|
||||
return FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(pos, &(nodeEntry->nodeInfo.pos), sizeof(COORD));
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Update node speed information.
|
||||
*
|
||||
* @param list
|
||||
* @param nodeId
|
||||
* @param newSpeed A structure stores the corresponding node speed info.
|
||||
*
|
||||
* @return SUCCESS update successfully.\n
|
||||
* FAILURE node not exist.
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t L2_UpdateNodeSpeed(NODE_LIST *list, uint8_t nodeId, const COORD *newSpeed)
|
||||
{
|
||||
ASSERT(list != NULL);
|
||||
NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId);
|
||||
if (nodeEntry == NULL)
|
||||
{
|
||||
return FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(&(nodeEntry->nodeInfo.speed), newSpeed, sizeof(COORD));
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Get node speed information.
|
||||
*
|
||||
* @param list
|
||||
* @param nodeId
|
||||
* @param newSpeed A structure stores the corresponding node speed info.
|
||||
*
|
||||
* @return SUCCESS update successfully.\n
|
||||
* FAILURE node not exist.
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t L2_GetNodeSpeed(NODE_LIST *list, uint8_t nodeId, COORD *speed)
|
||||
{
|
||||
ASSERT(list != NULL);
|
||||
NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId);
|
||||
if (nodeEntry == NULL)
|
||||
{
|
||||
return FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(speed, &(nodeEntry->nodeInfo.speed), sizeof(COORD));
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Update node ACK status.
|
||||
*
|
||||
* @param list
|
||||
* @param nodeId
|
||||
* @param devi
|
||||
*
|
||||
* @return SUCCESS update successfully.\n
|
||||
* FAILURE Node not exist.
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t L2_UpdateNodeTimeDeviation(NODE_LIST *list, uint8_t nodeId, int32_t devi)
|
||||
{
|
||||
ASSERT(list != NULL);
|
||||
NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId);
|
||||
if (nodeEntry == NULL)
|
||||
{
|
||||
return FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
nodeEntry->timeDevi = devi;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Increase TTL of specified node in the list.
|
||||
*
|
||||
* @param list
|
||||
* @param inc cnt of slot to add
|
||||
* @param nodeId
|
||||
*
|
||||
* @return NONE
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t L2_IncNodeTTL(NODE_LIST *list, uint8_t nodeId, uint32_t inc)
|
||||
{
|
||||
ASSERT(list != NULL);
|
||||
NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId);
|
||||
if (nodeEntry == NULL)
|
||||
{
|
||||
return FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
nodeEntry->ttlCnt += inc;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Reset node TTL based on node id.
|
||||
*
|
||||
* @param list
|
||||
* @param nodeId
|
||||
*
|
||||
* @return SUCCESS TTL has been successfully cleared.\n
|
||||
* FAILURE Node not exist.
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t L2_RstNodeTTL(NODE_LIST *list, uint8_t nodeId)
|
||||
{
|
||||
ASSERT(list != NULL);
|
||||
NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId);
|
||||
if (nodeEntry == NULL)
|
||||
{
|
||||
return FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
nodeEntry->ttlCnt = 0;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Get TTL of specified node in the list.
|
||||
*
|
||||
* @param list
|
||||
* @param nodeId
|
||||
* @param ttl
|
||||
*
|
||||
* @return NONE
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t L2_GetNodeTTL(NODE_LIST *list, uint8_t nodeId, uint32_t *ttl)
|
||||
{
|
||||
ASSERT(list != NULL);
|
||||
NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId);
|
||||
if (nodeEntry == NULL)
|
||||
{
|
||||
return FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
*ttl = nodeEntry->ttlCnt;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Implements a edit operations to each node.
|
||||
*
|
||||
* @param list
|
||||
* @param param
|
||||
* @param operation A pointer to a function handled "NODE_ENTRY*" as input
|
||||
* which defines the operations need to be apply.
|
||||
*
|
||||
* @return SUCCESS Operations has been applied successfully to all nodes.\n
|
||||
* Other Error occurred.
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t L2_IterEditNode(NODE_LIST *list, const void *param, int32_t (*operation)(NODE_ENTRY *, const void *))
|
||||
{
|
||||
ASSERT(list != NULL);
|
||||
int32_t Status;
|
||||
clist_node_t *node;
|
||||
clist_iterator_t *iter = clist_iterator_new(list, LIST_HEAD);
|
||||
if (iter == NULL)
|
||||
{
|
||||
DBG_ERROR("Failed to initialize list iteration process.\n");
|
||||
return ENOMEM;
|
||||
}
|
||||
while ((node = clist_iterator_next(iter)))
|
||||
{
|
||||
Status = operation((NODE_ENTRY *)node->val, param);
|
||||
if (Status != SUCCESS)
|
||||
{
|
||||
DBG_ERROR("Error occurred when iteratively edit node entry.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
clist_iterator_destroy(iter);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Filter all node, delete all the node not satisfied the condition.
|
||||
*
|
||||
* @param list
|
||||
* @param condition A pointer to a function handled "NODE_ENTRY*" as input
|
||||
* which defines the condition need to be verify.
|
||||
*
|
||||
* @return SUCCESS
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t L2_IterDeleteNode(NODE_LIST *list, bool (*condition)(NODE_ENTRY *))
|
||||
{
|
||||
ASSERT(list != NULL);
|
||||
clist_node_t *node;
|
||||
clist_iterator_t *iter = clist_iterator_new(list, LIST_HEAD);
|
||||
if (iter == NULL)
|
||||
{
|
||||
DBG_ERROR("Failed to initialize list iteration process.\n");
|
||||
return ENOMEM;
|
||||
}
|
||||
while ((node = clist_iterator_next(iter)))
|
||||
{
|
||||
if (condition((NODE_ENTRY *)node->val) == false)
|
||||
{
|
||||
clist_remove(list, node);
|
||||
}
|
||||
}
|
||||
clist_iterator_destroy(iter);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/** @} LinkLayer_NodeList*/
|
||||
|
||||
/** @} LinkLayer*/
|
||||
@@ -0,0 +1,79 @@
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @file node_list.h
|
||||
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||
* @brief DF Linklayer node list header file
|
||||
* @version 0.0
|
||||
* @date 2023-05-06
|
||||
*
|
||||
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||
* Lab of Communication and Network
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @addtogroup LinkLayer
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup LinkLayer_NodeList
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
||||
/***************************** Include Files *********************************/
|
||||
#ifndef NODE_LIST_H_
|
||||
#define NODE_LIST_H_
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
#include "link_layer_types.h"
|
||||
#include "geometry/coord.h"
|
||||
#include "util.h"
|
||||
#include "clist.h"
|
||||
|
||||
/************************** Constant Definitions *****************************/
|
||||
/***************** Macros (Inline Functions) Definitions *********************/
|
||||
/**************************** Type Definitions *******************************/
|
||||
/**
|
||||
* @struct NODE_ENTRY
|
||||
* @brief Linklayer discovered node list node entry
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
L2_NODE_INFO nodeInfo;
|
||||
uint32_t ttlCnt;
|
||||
int32_t timeDevi;
|
||||
} NODE_ENTRY;
|
||||
|
||||
typedef clist_t NODE_LIST;
|
||||
|
||||
/************************** Variable Definitions *****************************/
|
||||
|
||||
/************************** Function Prototypes ******************************/
|
||||
int32_t L2_NodeList_Init(NODE_LIST **list);
|
||||
void L2_NodeList_Clear(NODE_LIST *list);
|
||||
void L2_NodeList_Destroy(NODE_LIST *list);
|
||||
uint32_t L2_GetNodeListLen(NODE_LIST *list);
|
||||
NODE_ENTRY *L2_GetNodeById(NODE_LIST *list, uint8_t nodeId);
|
||||
NODE_ENTRY *L2_AppendNode(NODE_LIST *list, uint8_t nodeId, L2_NODE_TYPE nodeType);
|
||||
int32_t L2_DeleteNodeById(NODE_LIST *list, uint8_t nodeId);
|
||||
int32_t L2_UpdateNodePos(NODE_LIST *list, uint8_t nodeId, const COORD *newPos);
|
||||
bool L2_isNodeInList(NODE_LIST *list, uint8_t nodeId);
|
||||
int32_t L2_GetNodePos(NODE_LIST *list, uint8_t nodeId, COORD *newPos);
|
||||
int32_t L2_UpdateNodeSpeed(NODE_LIST *list, uint8_t nodeId, const COORD *newSpeed);
|
||||
int32_t L2_GetNodeSpeed(NODE_LIST *list, uint8_t nodeId, COORD *speed);
|
||||
int32_t L2_UpdateNodeTimeDeviation(NODE_LIST *list, uint8_t nodeId, int32_t devi);
|
||||
int32_t L2_GetDistance(NODE_LIST *list, COORD myCoord, uint8_t nodeId, double *dst);
|
||||
int32_t L2_RstNodeTTL(NODE_LIST *list, uint8_t nodeId);
|
||||
int32_t L2_IncNodeTTL(NODE_LIST *list, uint8_t nodeId, uint32_t inc);
|
||||
int32_t L2_GetNodeTTL(NODE_LIST *list, uint8_t nodeId, uint32_t *ttl);
|
||||
int32_t L2_IterEditNode(NODE_LIST *list, const void *param, int32_t (*operation)(NODE_ENTRY *, const void *));
|
||||
int32_t L2_IterDeleteNode(NODE_LIST *list, bool (*condition)(NODE_ENTRY *));
|
||||
|
||||
#endif /* NODE_LIST_H_ */
|
||||
|
||||
/** @} LinkLayer_NodeList*/
|
||||
/** @} LinkLayer*/
|
||||
@@ -0,0 +1,263 @@
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @file routine_table.c
|
||||
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||
* @brief DF Linklayer node list implementation file
|
||||
* @version 0.0
|
||||
* @date 2023-05-06
|
||||
*
|
||||
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||
* Lab of Communication and Network
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @addtogroup LinkLayer
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @name RoutineTable
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "link_layer.h"
|
||||
#include "link_layer_types.h"
|
||||
|
||||
L2_RTNE_TABLE_ENTRY intraScanSubT[L2_SLOTS_PER_FRAME] = {
|
||||
// SubFrame 0
|
||||
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||
|
||||
// SubFrame 1
|
||||
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||
|
||||
// SubFrame 2
|
||||
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||
{L2_SLOT_ADVERTISE, 0x00, 0x01, 0xFF},
|
||||
{L2_SLOT_ADVERTISE, 0x01, 0x01, 0xFF},
|
||||
{L2_SLOT_ADVERTISE, 0x02, 0x01, 0xFF},
|
||||
{L2_SLOT_ADVERTISE, 0x03, 0x01, 0xFF},
|
||||
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||
|
||||
// SubFrame 3
|
||||
{L2_SLOT_CONFIRM, 0x00, 0x01, 0xFF},
|
||||
{L2_SLOT_CONFIRM, 0x01, 0x01, 0xFF},
|
||||
{L2_SLOT_CONFIRM, 0x02, 0x01, 0xFF},
|
||||
{L2_SLOT_CONFIRM, 0x03, 0x01, 0xFF},
|
||||
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||
{L2_SLOT_CONFIRM, 0x00, 0x01, 0xFF},
|
||||
{L2_SLOT_CONFIRM, 0x01, 0x01, 0xFF},
|
||||
{L2_SLOT_CONFIRM, 0x02, 0x01, 0xFF},
|
||||
{L2_SLOT_CONFIRM, 0x03, 0x01, 0xFF},
|
||||
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||
{L2_SLOT_CONFIRM, 0x00, 0x02, 0x01},
|
||||
{L2_SLOT_CONFIRM, 0x01, 0x02, 0x01},
|
||||
{L2_SLOT_CONFIRM, 0x02, 0x02, 0x01},
|
||||
{L2_SLOT_CONFIRM, 0x03, 0x02, 0x01},
|
||||
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||
{L2_SLOT_CONFIRM, 0x00, 0x03, 0x01},
|
||||
{L2_SLOT_CONFIRM, 0x01, 0x03, 0x01},
|
||||
{L2_SLOT_CONFIRM, 0x02, 0x03, 0x01},
|
||||
{L2_SLOT_CONFIRM, 0x03, 0x03, 0x01},
|
||||
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||
|
||||
// SubFrame 4
|
||||
{L2_SLOT_CONFIRM, 0x00, 0x02, 0x01},
|
||||
{L2_SLOT_CONFIRM, 0x01, 0x02, 0x01},
|
||||
{L2_SLOT_CONFIRM, 0x02, 0x02, 0x01},
|
||||
{L2_SLOT_CONFIRM, 0x03, 0x02, 0x01},
|
||||
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||
{L2_SLOT_CONFIRM, 0x00, 0x03, 0x01},
|
||||
{L2_SLOT_CONFIRM, 0x01, 0x03, 0x01},
|
||||
{L2_SLOT_CONFIRM, 0x02, 0x03, 0x01},
|
||||
{L2_SLOT_CONFIRM, 0x03, 0x03, 0x01},
|
||||
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||
{L2_SLOT_CONFIRM, 0x00, 0x02, 0x01},
|
||||
{L2_SLOT_CONFIRM, 0x01, 0x02, 0x01},
|
||||
{L2_SLOT_CONFIRM, 0x02, 0x02, 0x01},
|
||||
{L2_SLOT_CONFIRM, 0x03, 0x02, 0x01},
|
||||
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||
{L2_SLOT_CONFIRM, 0x00, 0x03, 0x01},
|
||||
{L2_SLOT_CONFIRM, 0x01, 0x03, 0x01},
|
||||
{L2_SLOT_CONFIRM, 0x02, 0x03, 0x01},
|
||||
{L2_SLOT_CONFIRM, 0x03, 0x03, 0x01},
|
||||
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||
};
|
||||
|
||||
L2_RTNE_TABLE_ENTRY normalSub[L2_SLOTS_PER_FRAME] = {
|
||||
// SubFrame 0
|
||||
{L2_SLOT_SERVICE, 0x00, 0x01, 0x02},
|
||||
{L2_SLOT_SERVICE, 0x01, 0x01, 0x02},
|
||||
{L2_SLOT_SERVICE, 0x02, 0x01, 0x02},
|
||||
{L2_SLOT_SERVICE, 0x03, 0x01, 0x02},
|
||||
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||
{L2_SLOT_SERVICE, 0x00, 0x02, 0x01},
|
||||
{L2_SLOT_SERVICE, 0x01, 0x02, 0x01},
|
||||
{L2_SLOT_SERVICE, 0x02, 0x02, 0x01},
|
||||
{L2_SLOT_SERVICE, 0x03, 0x02, 0x01},
|
||||
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||
{L2_SLOT_SERVICE, 0x00, 0x01, 0x03},
|
||||
{L2_SLOT_SERVICE, 0x01, 0x01, 0x03},
|
||||
{L2_SLOT_SERVICE, 0x02, 0x01, 0x03},
|
||||
{L2_SLOT_SERVICE, 0x03, 0x01, 0x03},
|
||||
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||
{L2_SLOT_SERVICE, 0x00, 0x03, 0x01},
|
||||
{L2_SLOT_SERVICE, 0x01, 0x03, 0x01},
|
||||
{L2_SLOT_SERVICE, 0x02, 0x03, 0x01},
|
||||
{L2_SLOT_SERVICE, 0x03, 0x03, 0x01},
|
||||
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||
|
||||
// SubFrame 1
|
||||
{L2_SLOT_SERVICE, 0x00, 0x01, 0x02},
|
||||
{L2_SLOT_SERVICE, 0x01, 0x01, 0x02},
|
||||
{L2_SLOT_SERVICE, 0x02, 0x01, 0x02},
|
||||
{L2_SLOT_SERVICE, 0x03, 0x01, 0x02},
|
||||
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||
{L2_SLOT_SERVICE, 0x00, 0x02, 0x01},
|
||||
{L2_SLOT_SERVICE, 0x01, 0x02, 0x01},
|
||||
{L2_SLOT_SERVICE, 0x02, 0x02, 0x01},
|
||||
{L2_SLOT_SERVICE, 0x03, 0x02, 0x01},
|
||||
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||
{L2_SLOT_SERVICE, 0x00, 0x01, 0x03},
|
||||
{L2_SLOT_SERVICE, 0x01, 0x01, 0x03},
|
||||
{L2_SLOT_SERVICE, 0x02, 0x01, 0x03},
|
||||
{L2_SLOT_SERVICE, 0x03, 0x01, 0x03},
|
||||
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||
{L2_SLOT_SERVICE, 0x00, 0x03, 0x01},
|
||||
{L2_SLOT_SERVICE, 0x01, 0x03, 0x01},
|
||||
{L2_SLOT_SERVICE, 0x02, 0x03, 0x01},
|
||||
{L2_SLOT_SERVICE, 0x03, 0x03, 0x01},
|
||||
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||
|
||||
// SubFrame 2
|
||||
{L2_SLOT_SERVICE, 0x00, 0x01, 0x02},
|
||||
{L2_SLOT_SERVICE, 0x01, 0x01, 0x02},
|
||||
{L2_SLOT_SERVICE, 0x02, 0x01, 0x02},
|
||||
{L2_SLOT_SERVICE, 0x03, 0x01, 0x02},
|
||||
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||
{L2_SLOT_SERVICE, 0x00, 0x02, 0x01},
|
||||
{L2_SLOT_SERVICE, 0x01, 0x02, 0x01},
|
||||
{L2_SLOT_SERVICE, 0x02, 0x02, 0x01},
|
||||
{L2_SLOT_SERVICE, 0x03, 0x02, 0x01},
|
||||
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||
{L2_SLOT_SERVICE, 0x00, 0x01, 0x03},
|
||||
{L2_SLOT_SERVICE, 0x01, 0x01, 0x03},
|
||||
{L2_SLOT_SERVICE, 0x02, 0x01, 0x03},
|
||||
{L2_SLOT_SERVICE, 0x03, 0x01, 0x03},
|
||||
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||
{L2_SLOT_SERVICE, 0x00, 0x03, 0x01},
|
||||
{L2_SLOT_SERVICE, 0x01, 0x03, 0x01},
|
||||
{L2_SLOT_SERVICE, 0x02, 0x03, 0x01},
|
||||
{L2_SLOT_SERVICE, 0x03, 0x03, 0x01},
|
||||
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||
|
||||
// SubFrame 3
|
||||
{L2_SLOT_SERVICE, 0x00, 0x01, 0x02},
|
||||
{L2_SLOT_SERVICE, 0x01, 0x01, 0x02},
|
||||
{L2_SLOT_SERVICE, 0x02, 0x01, 0x02},
|
||||
{L2_SLOT_SERVICE, 0x03, 0x01, 0x02},
|
||||
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||
{L2_SLOT_SERVICE, 0x00, 0x02, 0x01},
|
||||
{L2_SLOT_SERVICE, 0x01, 0x02, 0x01},
|
||||
{L2_SLOT_SERVICE, 0x02, 0x02, 0x01},
|
||||
{L2_SLOT_SERVICE, 0x03, 0x02, 0x01},
|
||||
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||
{L2_SLOT_SERVICE, 0x00, 0x01, 0x03},
|
||||
{L2_SLOT_SERVICE, 0x01, 0x01, 0x03},
|
||||
{L2_SLOT_SERVICE, 0x02, 0x01, 0x03},
|
||||
{L2_SLOT_SERVICE, 0x03, 0x01, 0x03},
|
||||
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||
{L2_SLOT_SERVICE, 0x00, 0x03, 0x01},
|
||||
{L2_SLOT_SERVICE, 0x01, 0x03, 0x01},
|
||||
{L2_SLOT_SERVICE, 0x02, 0x03, 0x01},
|
||||
{L2_SLOT_SERVICE, 0x03, 0x03, 0x01},
|
||||
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||
|
||||
// SubFrame 4
|
||||
{L2_SLOT_SERVICE, 0x00, 0x01, 0x02},
|
||||
{L2_SLOT_SERVICE, 0x01, 0x01, 0x02},
|
||||
{L2_SLOT_SERVICE, 0x02, 0x01, 0x02},
|
||||
{L2_SLOT_SERVICE, 0x03, 0x01, 0x02},
|
||||
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||
{L2_SLOT_SERVICE, 0x00, 0x02, 0x01},
|
||||
{L2_SLOT_SERVICE, 0x01, 0x02, 0x01},
|
||||
{L2_SLOT_SERVICE, 0x02, 0x02, 0x01},
|
||||
{L2_SLOT_SERVICE, 0x03, 0x02, 0x01},
|
||||
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||
{L2_SLOT_SERVICE, 0x00, 0x01, 0x03},
|
||||
{L2_SLOT_SERVICE, 0x01, 0x01, 0x03},
|
||||
{L2_SLOT_SERVICE, 0x02, 0x01, 0x03},
|
||||
{L2_SLOT_SERVICE, 0x03, 0x01, 0x03},
|
||||
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||
{L2_SLOT_SERVICE, 0x00, 0x03, 0x01},
|
||||
{L2_SLOT_SERVICE, 0x01, 0x03, 0x01},
|
||||
{L2_SLOT_SERVICE, 0x02, 0x03, 0x01},
|
||||
{L2_SLOT_SERVICE, 0x03, 0x03, 0x01},
|
||||
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||
};
|
||||
|
||||
L2_RTNE_TABLE_ENTRY *initTable[L2_INIT_RTNE_PERIOD] =
|
||||
{
|
||||
intraScanSubT
|
||||
};
|
||||
|
||||
L2_RTNE_TABLE_ENTRY *normalTable[L2_NORMAL_RTNE_PERIOD] =
|
||||
{
|
||||
normalSub
|
||||
};
|
||||
|
||||
/** @} RoutineTable*/
|
||||
/** @} LinkLayer*/
|
||||
@@ -0,0 +1,929 @@
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @file scan.c
|
||||
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||
* @brief DF Linklayer scan implementation file.
|
||||
* @version 0.1
|
||||
* @date 2023-05-06
|
||||
*
|
||||
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||
* Lab of Communication and Network
|
||||
*
|
||||
******************************************************************************/
|
||||
/**
|
||||
* @addtogroup LinkLayer
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup LinkLayer_Scan
|
||||
* @{
|
||||
*/
|
||||
|
||||
/***************************** Include Files *********************************/
|
||||
#include <string.h>
|
||||
#include "link_layer.h"
|
||||
#include "link_layer_types.h"
|
||||
#include "msg_def.h"
|
||||
#include "node_list.h"
|
||||
#include "error.h"
|
||||
#include "common.h"
|
||||
#include "../phy_layer/phy_layer.h"
|
||||
|
||||
/************************** Constant Definitions *****************************/
|
||||
#define ADV_LISTEN_TIMEOUT 40
|
||||
#define CFM_LISTEN_TIMEOUT 5
|
||||
#define ADV_FRAME_SLOTS 4
|
||||
#define CFM_FRAME_SLOTS 5
|
||||
/***************** Macros (In-line Functions) Definitions *********************/
|
||||
|
||||
/**************************** Type Definitions *******************************/
|
||||
|
||||
/************************** Variable Definitions *****************************/
|
||||
// Pair by regex
|
||||
// Regex: ((\{\.oaxis = [0-9]+[ ,]+\.raxis = [0-9]+[ ]*\}, ){2})
|
||||
PHY_ANT_ANGLE antNrrwPattern_0[L1_NUM_ANT_NRRW_PATTERN] =
|
||||
{
|
||||
{.oaxis = 0 , .raxis = 0 },
|
||||
{.oaxis = 139, .raxis = 2225},
|
||||
{.oaxis = 152, .raxis = 850 },
|
||||
{.oaxis = 138, .raxis = 3155},
|
||||
{.oaxis = 159, .raxis = 1680},
|
||||
{.oaxis = 168, .raxis = 285 },
|
||||
{.oaxis = 195, .raxis = 2630},
|
||||
{.oaxis = 211, .raxis = 1204},
|
||||
{.oaxis = 225, .raxis = 3429},
|
||||
{.oaxis = 249, .raxis = 2022},
|
||||
{.oaxis = 272, .raxis = 629 },
|
||||
{.oaxis = 265, .raxis = 2934},
|
||||
{.oaxis = 277, .raxis = 1499},
|
||||
{.oaxis = 289, .raxis = 124 },
|
||||
{.oaxis = 300, .raxis = 2349},
|
||||
{.oaxis = 311, .raxis = 959 },
|
||||
{.oaxis = 321, .raxis = 3199},
|
||||
{.oaxis = 331, .raxis = 1824},
|
||||
{.oaxis = 341, .raxis = 389 },
|
||||
{.oaxis = 351, .raxis = 2674},
|
||||
{.oaxis = 360, .raxis = 1268},
|
||||
{.oaxis = 364, .raxis = 3483},
|
||||
{.oaxis = 378, .raxis = 2118},
|
||||
{.oaxis = 387, .raxis = 733 },
|
||||
{.oaxis = 416, .raxis = 3028},
|
||||
{.oaxis = 404, .raxis = 1623},
|
||||
{.oaxis = 433, .raxis = 248 },
|
||||
{.oaxis = 421, .raxis = 2473},
|
||||
{.oaxis = 429, .raxis = 1098},
|
||||
{.oaxis = 437, .raxis = 3303},
|
||||
{.oaxis = 445, .raxis = 1948},
|
||||
{.oaxis = 443, .raxis = 543 },
|
||||
{.oaxis = 450, .raxis = 2828},
|
||||
{.oaxis = 448, .raxis = 1422},
|
||||
{.oaxis = 455, .raxis = 47 },
|
||||
{.oaxis = 453, .raxis = 2272},
|
||||
{.oaxis = 450, .raxis = 897 }
|
||||
};
|
||||
|
||||
PHY_ANT_ANGLE antNrrwPattern_1[L1_NUM_ANT_NRRW_PATTERN] =
|
||||
{
|
||||
{.oaxis = 0 , .raxis = 0 },
|
||||
{.oaxis = 139, .raxis = 1155},
|
||||
{.oaxis = 152, .raxis = 3380},
|
||||
{.oaxis = 138, .raxis = 2085},
|
||||
{.oaxis = 159, .raxis = 610 },
|
||||
{.oaxis = 168, .raxis = 2815},
|
||||
{.oaxis = 195, .raxis = 1560},
|
||||
{.oaxis = 211, .raxis = 134 },
|
||||
{.oaxis = 225, .raxis = 2359},
|
||||
{.oaxis = 249, .raxis = 952 },
|
||||
{.oaxis = 272, .raxis = 3159},
|
||||
{.oaxis = 265, .raxis = 1864},
|
||||
{.oaxis = 277, .raxis = 429 },
|
||||
{.oaxis = 289, .raxis = 2654},
|
||||
{.oaxis = 300, .raxis = 1279},
|
||||
{.oaxis = 311, .raxis = 3489},
|
||||
{.oaxis = 321, .raxis = 2129},
|
||||
{.oaxis = 331, .raxis = 754 },
|
||||
{.oaxis = 341, .raxis = 2919},
|
||||
{.oaxis = 351, .raxis = 1604},
|
||||
{.oaxis = 360, .raxis = 198 },
|
||||
{.oaxis = 364, .raxis = 2413},
|
||||
{.oaxis = 378, .raxis = 1048},
|
||||
{.oaxis = 387, .raxis = 3263},
|
||||
{.oaxis = 416, .raxis = 1958},
|
||||
{.oaxis = 404, .raxis = 553 },
|
||||
{.oaxis = 433, .raxis = 2778},
|
||||
{.oaxis = 421, .raxis = 1403},
|
||||
{.oaxis = 429, .raxis = 28 },
|
||||
{.oaxis = 437, .raxis = 2233},
|
||||
{.oaxis = 445, .raxis = 878 },
|
||||
{.oaxis = 443, .raxis = 3073},
|
||||
{.oaxis = 450, .raxis = 1758},
|
||||
{.oaxis = 448, .raxis = 352 },
|
||||
{.oaxis = 455, .raxis = 2577},
|
||||
{.oaxis = 453, .raxis = 1202},
|
||||
{.oaxis = 450, .raxis = 3427},
|
||||
};
|
||||
/************************** Function Prototypes ******************************/
|
||||
static void LockStateUpdate(L2_SCAN_FSM *scanFsmPtr, bool state);
|
||||
static void AdvRecvStateUpdate(L2_SCAN_FSM *scanFsmPtr, bool state);
|
||||
static void StageUpdate(L2_SCAN_FSM *scanFsmPtr, SCAN_STAGE newStage);
|
||||
static void PendCfmAck(L2_SCAN_FSM *scanFsmPtr);
|
||||
|
||||
static int32_t Scan_InitScanHandler(L2_INST *instPtr);
|
||||
static int32_t Scan_AdvHandler(L2_INST *instPtr);
|
||||
static int32_t Scan_CfmHandler(L2_INST *instPtr);
|
||||
|
||||
static int32_t ScanMsg_Packing(L2_INST *instPtr, L2_FRAME_TYPE type, uint8_t dstId);
|
||||
|
||||
/**
|
||||
* @brief Update Init-Scan lock state.
|
||||
*/
|
||||
static inline void LockStateUpdate(L2_SCAN_FSM *scanFsmPtr, bool state)
|
||||
{
|
||||
ASSERT(scanFsmPtr != NULL);
|
||||
DBG_INFO("Update BeamLockState from [%" PRId8 "] to [%" PRId8 "].\n",
|
||||
scanFsmPtr->isLocked, state);
|
||||
scanFsmPtr->isLocked = state;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Update Base-info Advertisement state.
|
||||
*/
|
||||
static void AdvRecvStateUpdate(L2_SCAN_FSM *scanFsmPtr, bool state)
|
||||
{
|
||||
ASSERT(scanFsmPtr != NULL);
|
||||
DBG_INFO("Update AdvRecvState from [%" PRId8 "] to [%" PRId8 "].\n",
|
||||
scanFsmPtr->isAdvRecvd, state);
|
||||
scanFsmPtr->isAdvRecvd = state;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Update 2-Way Acquisition ack state.
|
||||
*/
|
||||
static void PendCfmAck(L2_SCAN_FSM *scanFsmPtr)
|
||||
{
|
||||
ASSERT(scanFsmPtr != NULL);
|
||||
DBG_INFO("Pending Cfm-Ack...\n");
|
||||
scanFsmPtr->isAckPending = true;
|
||||
return;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Update current Scan-Net stage
|
||||
*
|
||||
* @param scanFsmPtr A pointer to scan net fsm.
|
||||
* newStage New state.
|
||||
*
|
||||
* @return NONE.
|
||||
*
|
||||
******************************************************************************/
|
||||
static void StageUpdate(L2_SCAN_FSM *scanFsmPtr, SCAN_STAGE newStage)
|
||||
{
|
||||
ASSERT(newStage >= L2_SCAN_NONE_STAGE && newStage <= L2_SCAN_CFM_STAGE);
|
||||
DBG_INFO("ScanNet current stage: %" PRIu8 " -> ScanNet new stage: %" PRIu8 " \n",
|
||||
scanFsmPtr->scanStage, newStage);
|
||||
scanFsmPtr->scanStage = newStage;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Member node scan net InitScan stage handler.
|
||||
*
|
||||
* @param instPtr A pointer to l2 instance
|
||||
*
|
||||
* @return used slot (5ms slot).
|
||||
*
|
||||
******************************************************************************/
|
||||
static int32_t Scan_InitScanHandler(L2_INST *instPtr)
|
||||
{
|
||||
ASSERT(instPtr != NULL);
|
||||
PHY_INST *phyRef = instPtr->config.phyInstPtr;
|
||||
L2_SCAN_FSM *scanFsmPtr = instPtr->scanFSM;
|
||||
DBG_INFO("** Net-Setup - InitScan Procedure (Attempts: %" PRIu8 ")**\n", scanFsmPtr->scanCnt);
|
||||
|
||||
if (scanFsmPtr->scanCnt == 0)
|
||||
{
|
||||
// Update scan beam table
|
||||
L2_Scan_RefreashScanTable(instPtr);
|
||||
}
|
||||
else if (Phy_IsFrameDetected(phyRef))
|
||||
{
|
||||
// last scan beam number
|
||||
scanFsmPtr->beamNo = Phy_LastScanBeamNo(phyRef);
|
||||
// Update scan beam table
|
||||
L2_Scan_RefreashScanTable(instPtr);
|
||||
}
|
||||
|
||||
if (scanFsmPtr->isLocked == true)
|
||||
{
|
||||
scanFsmPtr->beamNo = Phy_LastScanBeamNo(phyRef);
|
||||
Phy_SetBeamNo(phyRef, scanFsmPtr->beamNo, PHY_ANT_BEAM_16);
|
||||
L2_SetupNextSlot(instPtr, L2_TOR_RX, L2_ADV_FRAME);
|
||||
StageUpdate(scanFsmPtr, L2_SCAN_ADV_STAGE);
|
||||
instPtr->log.lastBeamWidth = PHY_ANT_BEAM_16;
|
||||
} /* Otherwise remain L2_SCAN_INIT_STAGE */
|
||||
else
|
||||
{
|
||||
/* Antenna steering (reserved, automatically accomplished by physical layer) */
|
||||
Phy_SetBeamNo(phyRef, scanFsmPtr->beamNo, PHY_ANT_BEAM_16);
|
||||
L2_SetupNextSlot(instPtr, L2_TOR_RX, L2_SCAN_FRAME);
|
||||
scanFsmPtr->scanCnt++;
|
||||
instPtr->log.lastBeamWidth = PHY_ANT_BEAM_16;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Member node scan net BmAdvt stage handler.
|
||||
*
|
||||
* @param scanFsmPtr A pointer to scan net fsm.
|
||||
* mainState A pointer to main node state.
|
||||
*
|
||||
* @return used slot (5ms slot).
|
||||
*
|
||||
******************************************************************************/
|
||||
static int32_t Scan_AdvHandler(L2_INST *instPtr)
|
||||
{
|
||||
ASSERT(instPtr != NULL);
|
||||
L2_SCAN_FSM *scanFsmPtr = instPtr->scanFSM;
|
||||
PHY_INST *phyRef = instPtr->config.phyInstPtr;
|
||||
TMC_INST *tmcRef = instPtr->config.tmcInstPtr;
|
||||
DBG_INFO("** Net-Setup - Advertisement Procedure (Timeout: %" PRIu8 ") **\n", scanFsmPtr->advTimeout);
|
||||
|
||||
// if received a valid bm frame.
|
||||
if (scanFsmPtr->isAdvRecvd == true)
|
||||
{
|
||||
// last scan beam number
|
||||
scanFsmPtr->beamNo = Phy_LastScanBeamNo(phyRef);
|
||||
// reset listen counter.
|
||||
scanFsmPtr->advTimeout = 0;
|
||||
|
||||
// Update scan stage
|
||||
StageUpdate(scanFsmPtr, L2_SCAN_CFM_STAGE);
|
||||
|
||||
// start a confirm frame reception if in the target slot
|
||||
if ((TimeCtrl_GetIntCnt(tmcRef) + 1) % CFM_FRAME_SLOTS == 0)
|
||||
{
|
||||
// using pull mode to receive confirm frame
|
||||
// since first time sync procedure is accomplished in ADV stage.
|
||||
Phy_SetBeamWidth(phyRef, PHY_ANT_BEAM_16);
|
||||
Phy_SetBeamNo(phyRef, scanFsmPtr->beamNo, PHY_ANT_BEAM_16);
|
||||
Phy_SetMode(phyRef, PHY_MODE_PULL);
|
||||
L2_SetupNextSlot(instPtr, L2_TOR_RX, L2_CFM_FRAME);
|
||||
scanFsmPtr->cfmTimeout++; // increase counter.
|
||||
instPtr->log.lastBeamWidth = PHY_ANT_BEAM_16;
|
||||
}
|
||||
// otherwise skip...
|
||||
return SUCCESS;
|
||||
}
|
||||
// no valid bm frame was received.
|
||||
else
|
||||
{
|
||||
/* if time out reached, go back to init scan stage. */
|
||||
if (scanFsmPtr->advTimeout > ADV_LISTEN_TIMEOUT)
|
||||
{
|
||||
/* Antenna steering (reserved, automatically accomplished by physical layer) */
|
||||
Phy_SetBeamNo(phyRef, scanFsmPtr->beamNo, PHY_ANT_BEAM_16);
|
||||
L2_SetupNextSlot(instPtr, L2_TOR_RX, L2_SCAN_FRAME);
|
||||
DBG_WARNING("Adv timeout, restart net scan from L2_SCAN_INIT_STAGE.\n");
|
||||
L2_Scan_Reset(scanFsmPtr);
|
||||
instPtr->log.lastBeamWidth = PHY_ANT_BEAM_16;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Antenna steering (reserved, automatically accomplished by physical layer) */
|
||||
Phy_SetBeamNo(phyRef, scanFsmPtr->beamNo, PHY_ANT_BEAM_16);
|
||||
L2_SetupNextSlot(instPtr, L2_TOR_RX, L2_ADV_FRAME);
|
||||
scanFsmPtr->advTimeout++;
|
||||
instPtr->log.lastBeamWidth = PHY_ANT_BEAM_16;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Scan net 2Way-Acq stage handler.
|
||||
*
|
||||
* @param instPtr a pointer to linklayer layer instance
|
||||
*
|
||||
* @return used slot (5ms slot).
|
||||
*
|
||||
******************************************************************************/
|
||||
static int32_t Scan_CfmHandler(L2_INST *instPtr)
|
||||
{
|
||||
ASSERT(instPtr != NULL);
|
||||
L2_SCAN_FSM *scanFsmPtr = instPtr->scanFSM;
|
||||
PHY_INST *phyRef = instPtr->config.phyInstPtr;
|
||||
DBG_INFO("** Net-Setup - Confirm Procedure (Timeout: %" PRIu8 ") **\n", scanFsmPtr->cfmTimeout);
|
||||
|
||||
// 2 way acq failed, back to init stage.
|
||||
if (scanFsmPtr->cfmTimeout >= CFM_LISTEN_TIMEOUT)
|
||||
{
|
||||
DBG_WARNING("Cmf timeout, restart net scan from L2_SCAN_INIT_STAGE.\n");
|
||||
L2_Scan_Reset(scanFsmPtr);
|
||||
return SUCCESS;
|
||||
}
|
||||
if (L2_GetNextSlotNum(instPtr) % CFM_FRAME_SLOTS == 0)
|
||||
{
|
||||
// using pull mode to receive confirm frame
|
||||
// since first time sync procedure is accomplished in ADV stage.
|
||||
Phy_SetBeamWidth(phyRef, PHY_ANT_BEAM_16);
|
||||
Phy_SetBeamNo(phyRef, scanFsmPtr->beamNo, PHY_ANT_BEAM_16);
|
||||
Phy_SetMode(phyRef, PHY_MODE_PULL);
|
||||
L2_SetupNextSlot(instPtr, L2_TOR_RX, L2_CFM_FRAME);
|
||||
scanFsmPtr->cfmTimeout++; // increase counter.
|
||||
instPtr->log.lastBeamWidth = PHY_ANT_BEAM_16;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Packing Scan message to a bit array.
|
||||
*
|
||||
* @param bitarr pointer to bit array buffer.
|
||||
* @param msgType message type.
|
||||
*
|
||||
* @return EPARAM
|
||||
* SUCCESS
|
||||
*
|
||||
******************************************************************************/
|
||||
static int32_t ScanMsg_Packing(L2_INST *instPtr, L2_FRAME_TYPE type, uint8_t dstId)
|
||||
{
|
||||
ASSERT(instPtr != NULL);
|
||||
int32_t Status;
|
||||
uint32_t dataChunk;
|
||||
uint8_t *buff = instPtr->sendPktData;
|
||||
if (type < L2_ADV_FRAME || type > L2_CFM_FRAME)
|
||||
{
|
||||
DBG_ERROR("Unexpected frame type: %" PRId8 ".\n", type);
|
||||
return EPARAM;
|
||||
}
|
||||
|
||||
// Common section of link layer package
|
||||
dataChunk = L2_GetNextFrameNum(instPtr);
|
||||
L2_FrameInsertChunk(buff, L2_MSG_FRAME_NUM, L2_MSG_FRAME_NUM_LEN, &dataChunk);
|
||||
dataChunk = L2_GetNextSlotNum(instPtr);
|
||||
L2_FrameInsertChunk(buff, L2_MSG_SLOT_NUM, L2_MSG_SLOT_NUM_LEN, &dataChunk);
|
||||
dataChunk = L2_GetNodeId(instPtr);
|
||||
L2_FrameInsertChunk(buff, L2_MSG_SRC_ID, L2_MSG_SRC_ID_LEN, &dataChunk);
|
||||
dataChunk = dstId;
|
||||
L2_FrameInsertChunk(buff, L2_MSG_DST_ID, L2_MSG_DST_ID_LEN, &dataChunk);
|
||||
switch (type)
|
||||
{
|
||||
case L2_ADV_FRAME:
|
||||
{
|
||||
dataChunk = L2_ADV_FRAME;
|
||||
L2_FrameInsertChunk(buff, L2_MSG_TYPE, L2_MSG_TYPE_LEN, &dataChunk);
|
||||
|
||||
SysMonitor_GetSysinfo(&(instPtr->sysInfo));
|
||||
// insert position and speed info
|
||||
L2_FrameInsertChunk(buff, L2_MSG_ADV_SRC_POSX, L2_MSG_ADV_SRC_POSX_LEN, &(instPtr->sysInfo.posX));
|
||||
L2_FrameInsertChunk(buff, L2_MSG_ADV_SRC_POSY, L2_MSG_ADV_SRC_POSY_LEN, &(instPtr->sysInfo.posY));
|
||||
L2_FrameInsertChunk(buff, L2_MSG_ADV_SRC_POSZ, L2_MSG_ADV_SRC_POSZ_LEN, &(instPtr->sysInfo.posZ));
|
||||
|
||||
// Insert net start time
|
||||
L2_FrameInsertChunk(buff, L2_MSG_ADV_SRC_NETSTART_TIME, L2_MSG_ADV_SRC_NETSTART_TIME_LEN, &(instPtr->netStartTime));
|
||||
|
||||
// Append CRC
|
||||
Status = L2_CrcAppend(buff, L2_ADV_PACK_LEN - L2_MSG_ADV_SVC_CRC_LEN, L2_MSG_ADV_SVC_CRC, L2_CRC16_1021);
|
||||
if (Status != SUCCESS)
|
||||
{
|
||||
DBG_ERROR("Fail to append CRC, error code: %" PRId32 ".\n", Status);
|
||||
return Status;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case L2_CFM_FRAME:
|
||||
{
|
||||
dataChunk = L2_CFM_FRAME;
|
||||
L2_FrameInsertChunk(buff, L2_MSG_TYPE, L2_MSG_TYPE_LEN, &dataChunk);
|
||||
|
||||
SysMonitor_GetSysinfo(&(instPtr->sysInfo));
|
||||
// insert position and speed info
|
||||
L2_FrameInsertChunk(buff, L2_MSG_CFM_SRC_POSX, L2_MSG_CFM_SRC_POSX_LEN, &(instPtr->sysInfo.posX));
|
||||
L2_FrameInsertChunk(buff, L2_MSG_CFM_SRC_POSY, L2_MSG_CFM_SRC_POSY_LEN, &(instPtr->sysInfo.posY));
|
||||
L2_FrameInsertChunk(buff, L2_MSG_CFM_SRC_POSZ, L2_MSG_CFM_SRC_POSZ_LEN, &(instPtr->sysInfo.posZ));
|
||||
L2_FrameInsertChunk(buff, L2_MSG_CFM_SRC_SPEEDX, L2_MSG_CFM_SRC_SPEEDX_LEN, &(instPtr->sysInfo.vX));
|
||||
L2_FrameInsertChunk(buff, L2_MSG_CFM_SRC_SPEEDY, L2_MSG_CFM_SRC_SPEEDY_LEN, &(instPtr->sysInfo.vY));
|
||||
L2_FrameInsertChunk(buff, L2_MSG_CFM_SRC_SPEEDZ, L2_MSG_CFM_SRC_SPEEDZ_LEN, &(instPtr->sysInfo.vZ));
|
||||
|
||||
// Packing extra payload
|
||||
uint32_t dataId;
|
||||
if (L2_GetNodeType(instPtr) == L2_NODE_HEAD)
|
||||
{
|
||||
SysMonitor_GetSendPayload(buff + L2_MSG_CFM_PAYLOAD, &dataId, PAYLOAD_LEN_FLJ_TX);
|
||||
}
|
||||
else
|
||||
{
|
||||
SysMonitor_GetSendPayload(buff + L2_MSG_CFM_PAYLOAD, &dataId, PAYLOAD_LEN_LJ_TX);
|
||||
}
|
||||
|
||||
L2_FrameInsertChunk(buff, L2_MSG_CFM_PAYLOAD_ID, L2_MSG_CFM_PAYLOAD_ID_LEN, &dataId);
|
||||
if (dataId == DATA_ID_NONE)
|
||||
{
|
||||
memset(buff + L2_MSG_CFM_PAYLOAD, 0xAA, L2_MSG_CFM_PAYLOAD_LEN);
|
||||
}
|
||||
|
||||
// Append CRC
|
||||
Status = L2_CrcAppend(buff, L2_CMF_PACK_LEN - L2_MSG_CFM_CRC_LEN, L2_MSG_CFM_CRC, L2_CRC16_1021);
|
||||
if (Status != SUCCESS)
|
||||
{
|
||||
DBG_ERROR("Fail to append CRC, error code: %" PRId32 ".\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
// Logging...
|
||||
memcpy(instPtr->log.txLog.data, buff, L2_CMF_PACK_LEN);
|
||||
instPtr->log.txLog.dataId = dataId;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
DBG_ERROR("Unexpected frame type: %" PRId8 ".\n", type);
|
||||
return EPARAM;
|
||||
}
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Scan net packet handler.
|
||||
*
|
||||
* @param instPtr a pointer to linklayer layer instance
|
||||
* @param msg A pointer to frame data buffer.
|
||||
*
|
||||
* @return
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t L2_Scan_PktHandler(L2_INST *instPtr, uint8_t *msg)
|
||||
{
|
||||
ASSERT(instPtr != NULL);
|
||||
ASSERT(msg != NULL);
|
||||
int32_t Status;
|
||||
uint8_t srcId = L2_NONE_ID;
|
||||
uint8_t dstId = L2_NONE_ID;
|
||||
L2_FRAME_TYPE frameType = L2_NONE_FRAME;
|
||||
L2_SCAN_FSM *scanFsmPtr = instPtr->scanFSM;
|
||||
L2_FrameGetChunk(msg, L2_MSG_TYPE, L2_MSG_TYPE_LEN, &frameType);
|
||||
L2_FrameGetChunk(msg, L2_MSG_SRC_ID, L2_MSG_SRC_ID_LEN, &srcId);
|
||||
L2_FrameGetChunk(msg, L2_MSG_DST_ID, L2_MSG_DST_ID_LEN, &dstId);
|
||||
if(dstId != L2_GetNodeId(instPtr) && L2_GetNodeType(instPtr) == L2_NODE_HEAD)
|
||||
{
|
||||
DBG_WARNING("Drop frame not addressed to me (%u)", nodeId);
|
||||
return SUCCESS;
|
||||
}
|
||||
else if(dstId != L2_GetNodeId(instPtr) && dstId == L2_NONE_ID)
|
||||
{
|
||||
DBG_WARNING("Drop frame not addressed to me (%u)", nodeId);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
switch (frameType)
|
||||
{
|
||||
case L2_SCAN_FRAME:
|
||||
case L2_ADV_FRAME:
|
||||
{
|
||||
if (L2_GetLastOptFrameType(instPtr) == L2_SCAN_FRAME)
|
||||
{
|
||||
LockStateUpdate(scanFsmPtr, true);
|
||||
StageUpdate(scanFsmPtr, L2_SCAN_ADV_STAGE);
|
||||
}
|
||||
if (L2_GetNodeType(instPtr) == L2_NODE_HEAD)
|
||||
{
|
||||
DBG_ERROR("Unexpected call from head node, only member Node can handle L2_SCAN_FRAME and L2_ADV_FRAME.\n");
|
||||
Status = EUNEXP;
|
||||
break;
|
||||
}
|
||||
|
||||
NODE_ENTRY *node;
|
||||
node = L2_GetNodeById(instPtr->nodeList, srcId);
|
||||
if (node == NULL)
|
||||
{
|
||||
node = L2_AppendNode(instPtr->nodeList, srcId, L2_NODE_MEMBER);
|
||||
if (node == NULL)
|
||||
{
|
||||
DBG_ERROR("Failed to append new node [id: %" PRId8 "]", srcId);
|
||||
Status = ENOMEM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Update node info.
|
||||
float nodePos;
|
||||
L2_FrameGetChunk(msg, L2_MSG_ADV_SRC_POSX, L2_MSG_ADV_SRC_POSX_LEN, &nodePos);
|
||||
node->nodeInfo.pos.x = (double)nodePos;
|
||||
L2_FrameGetChunk(msg, L2_MSG_ADV_SRC_POSY, L2_MSG_ADV_SRC_POSY_LEN, &nodePos);
|
||||
node->nodeInfo.pos.y = (double)nodePos;
|
||||
L2_FrameGetChunk(msg, L2_MSG_ADV_SRC_POSZ, L2_MSG_ADV_SRC_POSZ_LEN, &nodePos);
|
||||
node->nodeInfo.pos.z = (double)nodePos;
|
||||
node->nodeInfo.beamNo = Phy_LastScanBeamNo(instPtr->config.phyInstPtr);
|
||||
|
||||
// Reset node ttl
|
||||
node->ttlCnt = 0;
|
||||
|
||||
uint32_t netstartTime;
|
||||
// Update net start time.
|
||||
L2_FrameGetChunk(msg, L2_MSG_ADV_SRC_NETSTART_TIME, L2_MSG_ADV_SRC_NETSTART_TIME_LEN, &netstartTime);
|
||||
L2_EVENT netSetupDoneEvent = {
|
||||
.event = L2_EV_NET_ADV_UPDATE,
|
||||
.msg = &netstartTime};
|
||||
AssertL2Event(instPtr, &netSetupDoneEvent);
|
||||
|
||||
// Calculate time deviation
|
||||
uint32_t frameNum, slotNum = 0;
|
||||
L2_FrameGetChunk(msg, L2_MSG_FRAME_NUM, L2_MSG_FRAME_NUM_LEN, &frameNum);
|
||||
L2_FrameGetChunk(msg, L2_MSG_SLOT_NUM, L2_MSG_SLOT_NUM_LEN, &slotNum);
|
||||
Status = L2_GetTimeDeviation(instPtr, frameNum, slotNum, true, &(instPtr->log.timeDev));
|
||||
if (Status != SUCCESS)
|
||||
{
|
||||
DBG_ERROR("Failed to compute time deviation.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
// Time sync.
|
||||
L2_TimeAdjust(instPtr, &(instPtr->log.timeDev));
|
||||
|
||||
// trigger flag
|
||||
AdvRecvStateUpdate(scanFsmPtr, true);
|
||||
Status = SUCCESS;
|
||||
break;
|
||||
}
|
||||
case L2_CFM_FRAME:
|
||||
{
|
||||
NODE_ENTRY *node;
|
||||
node = L2_GetNodeById(instPtr->nodeList, srcId);
|
||||
if (node == NULL)
|
||||
{
|
||||
node = L2_AppendNode(instPtr->nodeList, srcId, L2_NODE_MEMBER);
|
||||
if (node == NULL)
|
||||
{
|
||||
DBG_ERROR("Failed to append new node [id: %" PRId8 "]", srcId);
|
||||
Status = ENOMEM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Update node info.
|
||||
float nodePos;
|
||||
L2_FrameGetChunk(msg, L2_MSG_CFM_SRC_POSX, L2_MSG_CFM_SRC_POSX_LEN, &nodePos);
|
||||
node->nodeInfo.pos.x = (double)nodePos;
|
||||
L2_FrameGetChunk(msg, L2_MSG_CFM_SRC_POSY, L2_MSG_CFM_SRC_POSY_LEN, &nodePos);
|
||||
node->nodeInfo.pos.y = (double)nodePos;
|
||||
L2_FrameGetChunk(msg, L2_MSG_CFM_SRC_POSZ, L2_MSG_CFM_SRC_POSZ_LEN, &nodePos);
|
||||
node->nodeInfo.pos.z = (double)nodePos;
|
||||
float nodeSpeed;
|
||||
L2_FrameGetChunk(msg, L2_MSG_CFM_SRC_SPEEDX, L2_MSG_CFM_SRC_SPEEDX_LEN, &nodeSpeed);
|
||||
node->nodeInfo.speed.x = (double)nodePos;
|
||||
L2_FrameGetChunk(msg, L2_MSG_CFM_SRC_SPEEDY, L2_MSG_CFM_SRC_SPEEDY_LEN, &nodeSpeed);
|
||||
node->nodeInfo.speed.y = (double)nodePos;
|
||||
L2_FrameGetChunk(msg, L2_MSG_CFM_SRC_SPEEDZ, L2_MSG_CFM_SRC_SPEEDZ_LEN, &nodeSpeed);
|
||||
node->nodeInfo.speed.z = (double)nodePos;
|
||||
|
||||
// Reset node ttl
|
||||
node->ttlCnt = 0;
|
||||
|
||||
// Calculate time deviation
|
||||
uint32_t frameNum, slotNum = 0;
|
||||
L2_FrameGetChunk(msg, L2_MSG_FRAME_NUM, L2_MSG_FRAME_NUM_LEN, &frameNum);
|
||||
L2_FrameGetChunk(msg, L2_MSG_SLOT_NUM, L2_MSG_SLOT_NUM_LEN, &slotNum);
|
||||
Status = L2_GetTimeDeviation(instPtr, frameNum, slotNum, true, &(instPtr->log.timeDev));
|
||||
if (Status != SUCCESS)
|
||||
{
|
||||
DBG_ERROR("Failed to compute time deviation.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (L2_GetNodeType(instPtr) != L2_NODE_HEAD)
|
||||
{
|
||||
// check if net setup finished.
|
||||
if (L2_isCxn2Net(instPtr) == false)
|
||||
{
|
||||
// Assert Net-Setup Done.
|
||||
L2_EVENT l2Event;
|
||||
l2Event.event = L2_EV_NET_SETUP_DONE;
|
||||
l2Event.msg = NULL;
|
||||
AssertL2Event(instPtr, &l2Event);
|
||||
|
||||
// Assert update routine event...
|
||||
L2_RTNE_CONFIG newRtneConfig = {0};
|
||||
L2_EVENT rtneUpEvent =
|
||||
{
|
||||
.event = L2_ROUTINE_UPDATE,
|
||||
.msg = &newRtneConfig
|
||||
};
|
||||
newRtneConfig.rtneTable = initTable;
|
||||
newRtneConfig.rtnePrd = ARRAY_SIZE(initTable);
|
||||
AssertL2Event(instPtr, &rtneUpEvent);
|
||||
}
|
||||
PendCfmAck(instPtr->scanFSM);
|
||||
// Time sync.
|
||||
L2_TimeAdjust(instPtr, &(instPtr->log.timeDev));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (L2_GetMainState(instPtr) == L2_INIT_STATE
|
||||
&& L2_GetNodeListLen(instPtr->nodeList) >= instPtr->config.netScale - 1)
|
||||
{
|
||||
// Assert Net-Setup Done.
|
||||
L2_EVENT l2Event;
|
||||
L2_NODE_STATE newState = L2_NORMAL_STATE;
|
||||
l2Event.event = L2_EV_MAIN_STATE_UPDATE;
|
||||
l2Event.msg = &newState;
|
||||
AssertL2Event(instPtr, &l2Event);
|
||||
}
|
||||
}
|
||||
|
||||
// Get data payload
|
||||
uint32_t dataId;
|
||||
L2_FrameGetChunk(msg, L2_MSG_CFM_PAYLOAD_ID, L2_MSG_CFM_PAYLOAD_ID_LEN, &dataId);
|
||||
|
||||
if (L2_GetNodeType(instPtr) == L2_NODE_HEAD)
|
||||
{
|
||||
SysMonitor_UpdateRecvPayload(msg + L2_MSG_CFM_PAYLOAD, dataId, PAYLOAD_LEN_FLJ_RX);
|
||||
}
|
||||
else
|
||||
{
|
||||
SysMonitor_UpdateRecvPayload(msg + L2_MSG_CFM_PAYLOAD, dataId, PAYLOAD_LEN_LJ_RX);
|
||||
}
|
||||
|
||||
// Logging...
|
||||
memcpy(instPtr->log.rxLog.data, msg, L2_CMF_PACK_LEN);
|
||||
instPtr->log.rxLog.dataId = dataId;
|
||||
|
||||
Status = SUCCESS;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
DBG_ERROR("Unsupported frame type: %" PRId8 ".\n", frameType);
|
||||
Status = EUNEXP;
|
||||
break;
|
||||
}
|
||||
return Status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Initialize scan FSM.
|
||||
*
|
||||
* @param instPtr
|
||||
*
|
||||
* @return
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t L2_Scan_Init(L2_SCAN_FSM **scanFSMPtr)
|
||||
{
|
||||
ASSERT(scanFSMPtr != NULL);
|
||||
*scanFSMPtr = (L2_SCAN_FSM *)malloc(sizeof(L2_SCAN_FSM));
|
||||
if (*scanFSMPtr == NULL)
|
||||
{
|
||||
DBG_ERROR("Failed to allocate memory for scanFsmPtr.\n");
|
||||
return ENOMEM;
|
||||
}
|
||||
L2_Scan_Reset(*scanFSMPtr);
|
||||
(*scanFSMPtr)->beamNo = 0;
|
||||
(*scanFSMPtr)->tableNo = 0;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Reset ScanNet FSM
|
||||
*
|
||||
* @param scanFsmPtr a pointer to scan net finite state machine
|
||||
*
|
||||
* @return NONE
|
||||
*
|
||||
******************************************************************************/
|
||||
void L2_Scan_Reset(L2_SCAN_FSM *scanFSMPtr)
|
||||
{
|
||||
ASSERT(scanFSMPtr != NULL);
|
||||
scanFSMPtr->isLocked = false;
|
||||
scanFSMPtr->isAdvRecvd = false;
|
||||
scanFSMPtr->isAckPending = false;
|
||||
scanFSMPtr->scanCnt = 0;
|
||||
scanFSMPtr->advTimeout = 0;
|
||||
scanFSMPtr->cfmTimeout = 0;
|
||||
scanFSMPtr->scanStage = L2_SCAN_NONE_STAGE;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Destroy ScanNet FSM, free memory
|
||||
*
|
||||
* @param scanFsmPtr a pointer to scan net finite state machine
|
||||
*
|
||||
* @return NONE
|
||||
*
|
||||
******************************************************************************/
|
||||
void L2_Scan_Destroy(L2_SCAN_FSM *scanFSMPtr)
|
||||
{
|
||||
free(scanFSMPtr);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Refresh scan beam table.
|
||||
*
|
||||
* @param instPtr a pointer to linklayer layer instance
|
||||
*
|
||||
* @return NONE
|
||||
*
|
||||
******************************************************************************/
|
||||
void L2_Scan_RefreashScanTable(L2_INST *instPtr)
|
||||
{
|
||||
ASSERT(instPtr != NULL);
|
||||
L2_SCAN_FSM *scanFsmPtr = instPtr->scanFSM;
|
||||
PHY_INST *phyRef = instPtr->config.phyInstPtr;
|
||||
if (scanFsmPtr->tableNo == 0)
|
||||
{
|
||||
Phy_SetBeamTable(phyRef, antNrrwPattern_0, scanFsmPtr->beamNo);
|
||||
scanFsmPtr->tableNo = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Phy_SetBeamTable(phyRef, antNrrwPattern_1, scanFsmPtr->beamNo);
|
||||
scanFsmPtr->tableNo = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Execute a member node scan net procedure.
|
||||
*
|
||||
* @param instPtr a pointer to linklayer layer instance
|
||||
*
|
||||
* @return used slot (5ms slot).
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t L2_Scan_Proc(L2_INST *instPtr)
|
||||
{
|
||||
L2_SCAN_FSM *scanFSM = instPtr->scanFSM;
|
||||
if (L2_GetNodeType(instPtr) == L2_NODE_HEAD)
|
||||
{
|
||||
DBG_ERROR("Only member node needs to execute L2_Scan_Proc. \n");
|
||||
return FAILURE;
|
||||
}
|
||||
int32_t Status;
|
||||
DBG_INFO("-------- ScanNet Process --------\n");
|
||||
switch (scanFSM->scanStage)
|
||||
{
|
||||
case L2_SCAN_NONE_STAGE:
|
||||
/* Start Scan. */
|
||||
StageUpdate(scanFSM, L2_SCAN_INIT_STAGE);
|
||||
Status = Scan_InitScanHandler(instPtr);
|
||||
break;
|
||||
case L2_SCAN_INIT_STAGE:
|
||||
Status = Scan_InitScanHandler(instPtr);
|
||||
break;
|
||||
case L2_SCAN_ADV_STAGE:
|
||||
Status = Scan_AdvHandler(instPtr);
|
||||
break;
|
||||
case L2_SCAN_CFM_STAGE:
|
||||
Status = Scan_CfmHandler(instPtr);
|
||||
break;
|
||||
default:
|
||||
DBG_ERROR("Unexpected scan net stage: %" PRId8 ".\n", scanFSM->scanStage);
|
||||
Status = FAILURE;
|
||||
break;
|
||||
}
|
||||
return Status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Execute a scan net Routine procedure.
|
||||
*
|
||||
* @param rtneEntry Routine configuration
|
||||
*
|
||||
* @return used slot (5ms slot).
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t L2_Scan_Routine(L2_INST *instPtr, const L2_RTNE_TABLE_ENTRY *rtneEntry)
|
||||
{
|
||||
ASSERT(instPtr != NULL);
|
||||
L2_TOR_TYPE torState;
|
||||
int32_t Status;
|
||||
const NODE_ENTRY *commNode;
|
||||
PHY_INST *phyRef = instPtr->config.phyInstPtr;
|
||||
DBG_INFO("-------- Scan Routine --------\n");
|
||||
|
||||
if (rtneEntry->slotSeq != 0)
|
||||
{
|
||||
return SUCCESS; // skip
|
||||
}
|
||||
|
||||
if (L2_GetNodeType(instPtr) != L2_NODE_HEAD)
|
||||
{
|
||||
if (rtneEntry->dst == L2_GetNodeId(instPtr) || rtneEntry->dst == L2_BROADCAST_ID)
|
||||
{
|
||||
torState = L2_TOR_RX;
|
||||
commNode = L2_GetNodeById(instPtr->nodeList, rtneEntry->src);
|
||||
}
|
||||
else if (rtneEntry->src == L2_GetNodeId(instPtr) || rtneEntry->src == L2_BROADCAST_ID)
|
||||
{
|
||||
torState = L2_TOR_TX;
|
||||
commNode = L2_GetNodeById(instPtr->nodeList, rtneEntry->dst);
|
||||
}
|
||||
else
|
||||
{
|
||||
torState = L2_TOR_SUSPEND;
|
||||
}
|
||||
|
||||
// Setup antenna beam
|
||||
Phy_SetBeamWidth(phyRef, PHY_ANT_BEAM_16);
|
||||
instPtr->log.lastBeamWidth = PHY_ANT_BEAM_16;
|
||||
if (commNode != NULL)
|
||||
{
|
||||
Phy_SetBeamNo(phyRef, commNode->nodeInfo.beamNo, PHY_ANT_BEAM_16);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rtneEntry->dst == L2_GetNodeId(instPtr))
|
||||
{
|
||||
torState = L2_TOR_RX;
|
||||
}
|
||||
else if (rtneEntry->src == L2_GetNodeId(instPtr))
|
||||
{
|
||||
torState = L2_TOR_TX;
|
||||
}
|
||||
else
|
||||
{
|
||||
torState = L2_TOR_SUSPEND;
|
||||
}
|
||||
// Setup antenna beam
|
||||
Phy_SetBeamWidth(phyRef, PHY_ANT_BEAM_120);
|
||||
instPtr->log.lastBeamWidth = PHY_ANT_BEAM_120;
|
||||
}
|
||||
|
||||
switch (rtneEntry->slotType)
|
||||
{
|
||||
case L2_SLOT_SCAN:
|
||||
if (L2_GetNodeType(instPtr) != L2_NODE_HEAD && torState == L2_TOR_TX)
|
||||
{
|
||||
DBG_ERROR("Only head node can send init-scan Frame.\n");
|
||||
Status = FAILURE;
|
||||
goto routine_err;
|
||||
}
|
||||
L2_SetupNextSlot(instPtr, torState, L2_SCAN_FRAME);
|
||||
break;
|
||||
|
||||
case L2_SLOT_ADVERTISE:
|
||||
if (torState == L2_TOR_TX)
|
||||
{
|
||||
if (L2_GetNodeType(instPtr) != L2_NODE_HEAD)
|
||||
{
|
||||
DBG_ERROR("Only head node can send ADV Frame.\n");
|
||||
Status = FAILURE;
|
||||
goto routine_err;
|
||||
}
|
||||
memset(instPtr->sendPktData, 0xAA, L2_PACK_LEN_MAX);
|
||||
if (ScanMsg_Packing(instPtr, L2_ADV_FRAME, rtneEntry->dst) != SUCCESS)
|
||||
{
|
||||
Status = FAILURE;
|
||||
goto routine_err;
|
||||
}
|
||||
}
|
||||
/* Antenna setting (reserved.) */
|
||||
L2_SetupNextSlot(instPtr, torState, L2_ADV_FRAME);
|
||||
break;
|
||||
|
||||
case L2_SLOT_CONFIRM:
|
||||
if (torState == L2_TOR_TX)
|
||||
{
|
||||
if (L2_GetNodeType(instPtr) != L2_NODE_HEAD)
|
||||
{
|
||||
if (instPtr->scanFSM->isAckPending == false)
|
||||
{
|
||||
DBG_INFO("Member node has no pending CFM-Ack frame.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
memset(instPtr->sendPktData, 0xAA, L2_PACK_LEN_MAX);
|
||||
if (ScanMsg_Packing(instPtr, L2_CFM_FRAME, rtneEntry->dst) != SUCCESS)
|
||||
{
|
||||
Status = FAILURE;
|
||||
goto routine_err;
|
||||
}
|
||||
}
|
||||
/* Antenna setting (reserved.) */
|
||||
L2_SetupNextSlot(instPtr, torState, L2_CFM_FRAME);
|
||||
break;
|
||||
default:
|
||||
DBG_ERROR("Cannot start a routine for slot type [%" PRId8 "] properly.\n", rtneEntry->slotType);
|
||||
Status = FAILURE;
|
||||
goto routine_err;
|
||||
}
|
||||
return SUCCESS;
|
||||
routine_err:
|
||||
return Status;
|
||||
}
|
||||
|
||||
/** @} LinkLayer_Scan*/
|
||||
/** @} LinkLayer*/
|
||||
@@ -0,0 +1,438 @@
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @file schdevent.c
|
||||
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||
* @brief DF Linklayer Event scheduling implementation file.
|
||||
* @version 0.1
|
||||
* @date 2023-05-06
|
||||
*
|
||||
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||
* Lab of Communication and Network
|
||||
*
|
||||
******************************************************************************/
|
||||
/**
|
||||
* @addtogroup LinkLayer
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup LinkLayer_Scheduler
|
||||
* @{
|
||||
*/
|
||||
/***************************** Include Files *********************************/
|
||||
#include <stdlib.h>
|
||||
#include "schdevent.h"
|
||||
#include "link_layer.h"
|
||||
#include "link_layer_types.h"
|
||||
#include "error.h"
|
||||
#include "clist.h"
|
||||
/***************** Macros (Inline Functions) Definitions *********************/
|
||||
/**************************** Type Definitions *******************************/
|
||||
/************************** Variable Definitions *****************************/
|
||||
static L2_SCHD_EVENT util_schdevent;
|
||||
/************************** Function Prototypes ******************************/
|
||||
/**
|
||||
* @brief helper function to free schedule events.
|
||||
*/
|
||||
static void schdevent_free(void *val)
|
||||
{
|
||||
if (val == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
free(((L2_SCHD_EVENT *)val)->l2Event.msg);
|
||||
free(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief helper function to match events by ids.
|
||||
*/
|
||||
static int8_t schdevent_compare(void *a, void *b)
|
||||
{
|
||||
ASSERT(a == NULL);
|
||||
ASSERT(b != NULL);
|
||||
register uint32_t idA, idB;
|
||||
idA = ((L2_SCHD_EVENT *)a)->eventId;
|
||||
idB = ((L2_SCHD_EVENT *)b)->eventId;
|
||||
if (idA == idB)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (idA < idB)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Creat a schedule event pool.
|
||||
*
|
||||
* @param schdPool a pointer to schedule pool instance.
|
||||
*
|
||||
* @return SUCCESS
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t L2_CreateSchedEventPool(L2_SCHD_POOL **schdPool)
|
||||
{
|
||||
(*schdPool) = malloc(sizeof(L2_SCHD_POOL));
|
||||
if (*schdPool == NULL)
|
||||
{
|
||||
DBG_ERROR("Failed to allocated memory for schdPool.\n");
|
||||
return ENOMEM;
|
||||
}
|
||||
(*schdPool)->schdList = clist_new();
|
||||
if ((*schdPool)->schdList == NULL)
|
||||
{
|
||||
DBG_ERROR("Failed to allocated memory for schdPool->schdList.\n");
|
||||
free(*schdPool);
|
||||
return ENOMEM;
|
||||
}
|
||||
(*schdPool)->schdList->free = schdevent_free;
|
||||
(*schdPool)->schdList->compare = schdevent_compare;
|
||||
(*schdPool)->envCnt = 0;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Clear schedule event pool, delete all events in pool and
|
||||
* free allocated memory.
|
||||
*
|
||||
* @param schdPool a pointer to schedule pool instance.
|
||||
*
|
||||
* @return SUCCESS
|
||||
*
|
||||
******************************************************************************/
|
||||
void L2_ClearSchedEventPool(L2_SCHD_POOL *schdPool)
|
||||
{
|
||||
ASSERT(schdPool != NULL);
|
||||
clist_clear(schdPool->schdList);
|
||||
schdPool->envCnt = 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Completely destroy schedule event pool.
|
||||
*
|
||||
* @param schdPool a pointer to schedule pool instance.
|
||||
*
|
||||
* @return SUCCESS
|
||||
*
|
||||
******************************************************************************/
|
||||
void L2_DestroySchedEventPool(L2_SCHD_POOL *schdPool)
|
||||
{
|
||||
if (schdPool == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
clist_destroy(schdPool->schdList);
|
||||
free(schdPool);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Creat a new schedule event, register event in schedule event pool.
|
||||
*
|
||||
* @param schdPool a pointer to schedule pool instance.
|
||||
* @param event event type of the new schedule event.
|
||||
* @param isVolatile event type of the new schedule event.
|
||||
*
|
||||
* @return NULL error occurred
|
||||
* Pointer to schedule event.
|
||||
*
|
||||
******************************************************************************/
|
||||
L2_SCHD_EVENT *L2_CreatNewSchdEvent(L2_SCHD_POOL *schdPool, L2_EVENT_TYPE event, bool isVolatile)
|
||||
{
|
||||
ASSERT(schdPool != NULL);
|
||||
if (event < L2_EV_SCAN_PROC_DONE || event > L2_ROUTINE_UPDATE)
|
||||
{
|
||||
DBG_ERROR("Unknown event type: %" PRId8 ".\n", event);
|
||||
return NULL;
|
||||
}
|
||||
L2_SCHD_EVENT *schdEvent = (L2_SCHD_EVENT *)malloc(sizeof(L2_SCHD_EVENT));
|
||||
if (schdEvent == NULL)
|
||||
{
|
||||
DBG_ERROR("Failed to allocate schedule event.\n");
|
||||
return NULL;
|
||||
}
|
||||
clist_node_t *node = clist_node_new(schdEvent);
|
||||
if (node == NULL)
|
||||
{
|
||||
DBG_ERROR("Failed to allocate schedule event list node.\n");
|
||||
free(schdEvent);
|
||||
return NULL;
|
||||
}
|
||||
schdEvent->eventId = schdPool->envCnt++;
|
||||
schdEvent->occurCnt = 0;
|
||||
schdEvent->l2Event.event = event;
|
||||
schdEvent->l2Event.msg = NULL;
|
||||
schdEvent->isSchd = false;
|
||||
schdEvent->isVolatile = isVolatile;
|
||||
schdEvent->schdSlot = L2_SLOTNO_NONE;
|
||||
schdEvent->schdFrame = L2_FRAMENO_NONE;
|
||||
clist_rpush(schdPool->schdList, node);
|
||||
return schdEvent;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Get a schedule event by its id.
|
||||
*
|
||||
* @param schdPool a pointer to schedule pool instance.
|
||||
* @param id ID of the event
|
||||
*
|
||||
* @return NULL
|
||||
* Pointer to the schedule event.
|
||||
*
|
||||
******************************************************************************/
|
||||
L2_SCHD_EVENT *L2_GetEventById(L2_SCHD_POOL *schdPool, uint32_t id)
|
||||
{
|
||||
ASSERT(schdPool != NULL);
|
||||
util_schdevent.eventId = id;
|
||||
clist_node_t *node = clist_find(schdPool->schdList, &util_schdevent);
|
||||
if (node != NULL)
|
||||
{
|
||||
DBG_WARNING("Event with id=%" PRIu32 ", dose not exist.\n", id);
|
||||
return NULL;
|
||||
}
|
||||
return ((L2_SCHD_EVENT *)node->val);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Delete a schedule event, remove the event from event pool,
|
||||
* release memory.
|
||||
*
|
||||
* @param schdPool a pointer to schedule pool instance.
|
||||
* @param id ID of the event
|
||||
*
|
||||
* @return SUCCESS
|
||||
* error code
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t L2_DeleteSchdEventById(L2_SCHD_POOL *schdPool, uint32_t id)
|
||||
{
|
||||
ASSERT(schdPool != NULL);
|
||||
util_schdevent.eventId = id;
|
||||
clist_node_t *node = clist_find(schdPool->schdList, &util_schdevent);
|
||||
if (node != NULL)
|
||||
{
|
||||
DBG_ERROR("Event with id=%" PRIu32 ", dose not exist.\n", id);
|
||||
return EIGNORE;
|
||||
}
|
||||
clist_remove(schdPool->schdList, node);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Schedule a event at a specific time(indexed by frame and slot number)
|
||||
*
|
||||
* @param instPtr a pointer to linklayer instance
|
||||
* @param schdEvent pointer to the schedule event.
|
||||
* @param frameNum schedule frame number
|
||||
* @param slotNum schedule slot number
|
||||
*
|
||||
* @return FAILURE, event has already been scheduled/schedule time not allowed.
|
||||
* SUCCESS
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t L2_ScheduleEventAt(L2_INST *instPtr, L2_SCHD_EVENT *schdEvent, uint32_t frameNum, uint32_t slotNum)
|
||||
{
|
||||
ASSERT(schdEvent != NULL);
|
||||
if (L2_isEventScheduled(schdEvent) == true)
|
||||
{
|
||||
DBG_ERROR("Event %" PRIu32 " has already been scheduled.\n", schdEvent->eventId);
|
||||
return FAILURE;
|
||||
}
|
||||
if (frameNum <= L2_GetCurrentFrameNum(instPtr) && slotNum < L2_GetCurrentSlotNum(instPtr))
|
||||
{
|
||||
DBG_ERROR("Cannot schedule event %" PRIu32 " to the past(current: [%" PRIu32 "-%" PRIu32 "], schedule: [%" PRIu32 "-%" PRIu32 "]).\n",
|
||||
schdEvent->eventId, L2_GetCurrentFrameNum(instPtr), L2_GetCurrentSlotNum(instPtr), frameNum, slotNum);
|
||||
return FAILURE;
|
||||
}
|
||||
DBG_INFO("Schedule event (type:%" PRIu8 ") [%" PRIu32 "] at %" PRIu32 "-%" PRIu32 ".\n",
|
||||
schdEvent->l2Event.event, schdEvent->eventId,
|
||||
frameNum, slotNum);
|
||||
schdEvent->isSchd = true;
|
||||
schdEvent->schdFrame = frameNum;
|
||||
schdEvent->schdSlot = slotNum;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Schedule a event after a specific time period.
|
||||
*
|
||||
* @param instPtr a pointer to linklayer instance
|
||||
* @param schdEvent pointer to the schedule event.
|
||||
* @param numSlots how many slot later the event should be scheduled
|
||||
*
|
||||
* @return FAILURE, event has already been scheduled/schedule time not allowed.
|
||||
* SUCCESS
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t L2_ScheduleEventAfter(L2_INST *instPtr, L2_SCHD_EVENT *schdEvent, uint32_t numSlots)
|
||||
{
|
||||
ASSERT(schdEvent != NULL);
|
||||
if (L2_isEventScheduled(schdEvent) == true)
|
||||
{
|
||||
DBG_ERROR("Event %" PRIu32 " has already been scheduled.\n", schdEvent->eventId);
|
||||
return FAILURE;
|
||||
}
|
||||
uint32_t frameNum = L2_GetCurrentFrameNum(instPtr) + (numSlots / L2_SLOTS_PER_FRAME);
|
||||
uint32_t slotNum = L2_GetCurrentSlotNum(instPtr) + (numSlots % L2_SLOTS_PER_FRAME);
|
||||
return L2_ScheduleEventAt(instPtr, schdEvent, frameNum, slotNum);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Reschedule a event at a specific time(indexed by frame and slot number)
|
||||
*
|
||||
* @param instPtr a pointer to linklayer instance
|
||||
* @param schdEvent pointer to the schedule event.
|
||||
* @param frameNum schedule frame number
|
||||
* @param slotNum schedule slot number
|
||||
*
|
||||
* @return FAILURE, event has already been scheduled/schedule time not allowed.
|
||||
* SUCCESS
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t L2_RescheduleEventAt(L2_INST *instPtr, L2_SCHD_EVENT *schdEvent, uint32_t frameNum, uint32_t slotNum)
|
||||
{
|
||||
ASSERT(schdEvent != NULL);
|
||||
if (schdEvent->isSchd == false)
|
||||
{
|
||||
DBG_WARNING("Event %" PRIu32 " has not been scheduled yet.\n", schdEvent->eventId);
|
||||
}
|
||||
schdEvent->isSchd = false;
|
||||
return L2_ScheduleEventAt(instPtr, schdEvent, frameNum, slotNum);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Reschedule a event after a specific time period.
|
||||
*
|
||||
* @param instPtr a pointer to linklayer instance
|
||||
* @param schdEvent pointer to the schedule event.
|
||||
* @param numSlots how many slot later the event should be scheduled
|
||||
*
|
||||
* @return FAILURE, event has already been scheduled/schedule time not allowed.
|
||||
* SUCCESS
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t L2_RescheduleEventAfter(L2_INST *instPtr, L2_SCHD_EVENT *schdEvent, uint32_t numSlots)
|
||||
{
|
||||
ASSERT(schdEvent != NULL);
|
||||
if (schdEvent->isSchd == false)
|
||||
{
|
||||
DBG_WARNING("Event %" PRIu32 " has not been scheduled yet.\n", schdEvent->eventId);
|
||||
}
|
||||
return L2_ScheduleEventAfter(instPtr, schdEvent, numSlots);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Check and excute schedule event in event pool illiterate.
|
||||
*
|
||||
* @param instPtr a pointer to linklayer instance
|
||||
*
|
||||
* @return NONE.
|
||||
*
|
||||
******************************************************************************/
|
||||
void L2_EventPoolHandler(L2_INST *instPtr)
|
||||
{
|
||||
ASSERT(instPtr != NULL);
|
||||
clist_node_t *node;
|
||||
L2_SCHD_EVENT *event;
|
||||
L2_SCHD_POOL *pool = instPtr->schdEventPool;
|
||||
clist_iterator_t *iter = clist_iterator_new(pool->schdList, LIST_HEAD);
|
||||
if (iter == NULL)
|
||||
{
|
||||
DBG_ERROR("Failed to initialize schedule event pool iteration.\n");
|
||||
return;
|
||||
}
|
||||
while ((node = clist_iterator_next(iter)))
|
||||
{
|
||||
event = (L2_SCHD_EVENT *)node->val;
|
||||
if (L2_isEventScheduled(event))
|
||||
{
|
||||
if (event->schdFrame == L2_GetCurrentFrameNum(instPtr) && event->schdSlot == L2_GetCurrentSlotNum(instPtr))
|
||||
{
|
||||
DBG_INFO("Asserting scheduled event [%" PRIu32 "].\n", event->eventId);
|
||||
AssertL2Event(instPtr, &(event->l2Event));
|
||||
if (event->isVolatile == true)
|
||||
{
|
||||
DBG_INFO("Deleting scheduled event [%" PRIu32 "], since it is volatile.\n", event->eventId);
|
||||
clist_remove(pool->schdList, node);
|
||||
}
|
||||
else
|
||||
{
|
||||
event->occurCnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
clist_iterator_destroy(iter);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Append extra message content to specific schedule event.
|
||||
*
|
||||
* @param schdEvent pointer to the schedule event.
|
||||
* msg pointer to the append content.
|
||||
*
|
||||
* @return SUCCESS.
|
||||
* error code.
|
||||
*
|
||||
******************************************************************************/
|
||||
inline void L2_SchdEventAppendMsg(L2_SCHD_EVENT *schdEvent, void *msg)
|
||||
{
|
||||
ASSERT(schdEvent != NULL);
|
||||
schdEvent->l2Event.msg = msg;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Cancel a scheduled event.
|
||||
*
|
||||
* @param schdEvent pointer to the schedule event.
|
||||
*
|
||||
* @return SUCCESS.
|
||||
*
|
||||
******************************************************************************/
|
||||
inline int32_t L2_CancelEvent(L2_SCHD_EVENT *schdEvent)
|
||||
{
|
||||
ASSERT(schdEvent != NULL);
|
||||
if (schdEvent->isSchd == false)
|
||||
{
|
||||
DBG_WARNING("Event %" PRIu32 " has not been scheduled yet.\n", schdEvent->eventId);
|
||||
}
|
||||
schdEvent->isSchd = false;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Check if the event was scheduled.
|
||||
*
|
||||
* @param schdEvent pointer to the schedule event.
|
||||
*
|
||||
* @return true.
|
||||
* false.
|
||||
*
|
||||
******************************************************************************/
|
||||
inline bool L2_isEventScheduled(const L2_SCHD_EVENT *schdEvent)
|
||||
{
|
||||
ASSERT(schdEvent != NULL);
|
||||
return schdEvent->isSchd;
|
||||
}
|
||||
|
||||
/** @} LinkLayer_Scheduler*/
|
||||
/** @} LinkLayer*/
|
||||
@@ -0,0 +1,76 @@
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @file schdevent.c
|
||||
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||
* @brief DF Linklayer Event scheduling header file.
|
||||
* @version 0.1
|
||||
* @date 2023-05-06
|
||||
*
|
||||
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||
* Lab of Communication and Network
|
||||
*
|
||||
******************************************************************************/
|
||||
/**
|
||||
* @addtogroup LinkLayer
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup LinkLayer_Scheduler
|
||||
* @{
|
||||
*/
|
||||
#ifndef SCHDEVENT_H_
|
||||
#define SCHDEVENT_H_
|
||||
|
||||
#define SCHDEVENT_ID_NONE UINT32_MAX
|
||||
/***************************** Include Files *********************************/
|
||||
#include <stdlib.h>
|
||||
#include "link_layer_types.h"
|
||||
#include "error.h"
|
||||
#include "clist.h"
|
||||
/***************** Macros (Inline Functions) Definitions *********************/
|
||||
/**************************** Type Definitions *******************************/
|
||||
/**
|
||||
* @struct L2_SCHD_EVENT
|
||||
* @brief Linklayer scheduled event descriptor
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
bool isSchd;
|
||||
bool isVolatile;
|
||||
L2_EVENT l2Event;
|
||||
uint32_t eventId;
|
||||
uint32_t occurCnt;
|
||||
uint32_t schdFrame;
|
||||
uint32_t schdSlot;
|
||||
} L2_SCHD_EVENT;
|
||||
|
||||
/**
|
||||
* @struct L2_SCHD_POOL
|
||||
* @brief Linklayer schedule event pool instance
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
clist_t *schdList;
|
||||
uint32_t envCnt;
|
||||
} L2_SCHD_POOL;
|
||||
|
||||
/************************** Variable Definitions *****************************/
|
||||
/************************** Function Prototypes ******************************/
|
||||
// Scheduling Event
|
||||
int32_t L2_CreateSchedEventPool(L2_SCHD_POOL **schdPool);
|
||||
void L2_ClearSchedEventPool(L2_SCHD_POOL *schdPool);
|
||||
void L2_DestroySchedEventPool(L2_SCHD_POOL *schdPool);
|
||||
|
||||
L2_SCHD_EVENT *L2_CreatNewSchdEvent(L2_SCHD_POOL *schdPool, L2_EVENT_TYPE event, bool isVolatile);
|
||||
L2_SCHD_EVENT *L2_GetEventById(L2_SCHD_POOL *schdPool, uint32_t id);
|
||||
int32_t L2_DeleteSchdEventById(L2_SCHD_POOL *schdPool, uint32_t id);
|
||||
|
||||
void L2_SchdEventAppendMsg(L2_SCHD_EVENT *schdEvent, void *msg);
|
||||
bool L2_isEventScheduled(const L2_SCHD_EVENT *schdEvent);
|
||||
int32_t L2_CancelEvent(L2_SCHD_EVENT *schdEvent);
|
||||
|
||||
#endif // SCHDEVENT_H_
|
||||
|
||||
/** @} LinkLayer_Scheduler*/
|
||||
/** @} LinkLayer*/
|
||||
@@ -0,0 +1,440 @@
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @file service.c
|
||||
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||
* @brief DF Linklayer service implementation file.
|
||||
* @version 0.0
|
||||
* @date 2023-05-06
|
||||
*
|
||||
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||
* Lab of Communication and Network
|
||||
*
|
||||
******************************************************************************/
|
||||
/**
|
||||
* @addtogroup LinkLayer
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup LinkLayer_Service
|
||||
* @{
|
||||
*/
|
||||
/***************************** Include Files *********************************/
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include "link_layer.h"
|
||||
#include "link_layer_types.h"
|
||||
#include "msg_def.h"
|
||||
#include "error.h"
|
||||
#include "common.h"
|
||||
#include "circ_queue.h"
|
||||
#ifndef EMULATION
|
||||
#include "../config/app_config.h"
|
||||
#endif
|
||||
/************************** Constant Definitions *****************************/
|
||||
/***************** Macros (Inline Functions) Definitions *********************/
|
||||
/**************************** Type Definitions *******************************/
|
||||
/************************** Function Prototypes ******************************/
|
||||
static int32_t Service_Packing(L2_INST *instPtr, L2_FRAME_TYPE type, uint8_t dstId);
|
||||
/************************** Variable Definitions *****************************/
|
||||
|
||||
static uint8_t testData[L2_PACK_LEN_MAX] =
|
||||
{
|
||||
0x39, 0x85, 0x02, 0xF0, 0xC7, 0x6A, 0xE8, 0xB4, 0xE7, 0xAB, 0xC9, 0xDC, 0x0B, 0x41, 0x42, 0xE0,
|
||||
0xED, 0x21, 0x07, 0x62, 0x4E, 0x80, 0xA0, 0xE1, 0xAC, 0x77, 0x9B, 0x1F, 0x48, 0x0B, 0x58, 0xB9,
|
||||
0x45, 0xA5, 0x24, 0xEF, 0xF3, 0x71, 0x2E, 0x84, 0x6C, 0x22, 0xB3, 0x05, 0xEB, 0x75, 0xF2, 0x0B,
|
||||
0x45, 0x73, 0x01, 0xA8, 0x1E, 0x00, 0x21, 0x3E, 0x03, 0x86, 0x55, 0x59, 0x98, 0x5C, 0x61, 0xA2,
|
||||
0xE8, 0x20, 0x0E, 0x7A, 0xD5, 0x72, 0xAF, 0xF4, 0xBC, 0xB3, 0x6F, 0xFE, 0xB3, 0x78, 0x6A, 0x59,
|
||||
0x73, 0xBD, 0x97, 0xBE, 0x44, 0xA4, 0x9B, 0x71, 0x11, 0x45, 0x37, 0xFE, 0xB3, 0x71, 0xEF, 0x1E,
|
||||
0x3A, 0x2B, 0x58, 0x07, 0xF6, 0x01, 0x1C, 0x73, 0x28, 0x11, 0xA8, 0x15, 0xA2, 0x58, 0x32, 0x2E,
|
||||
0x7D, 0x35, 0x9C, 0xE4, 0x98, 0x7F, 0x9C, 0x81, 0x32, 0xAA, 0xC4, 0x87, 0x16, 0x26, 0x23, 0x95,
|
||||
0x57, 0xC9, 0xD4, 0x34, 0xCE, 0x63, 0x78, 0x7E, 0xD4, 0x3C, 0x16, 0x1D, 0x80, 0xC0, 0x55, 0xBF,
|
||||
0xB5, 0xD6, 0x0C, 0xA5, 0xB9, 0x0A, 0x14, 0x5B, 0x4D, 0x52, 0xF2, 0xA9, 0x7A, 0x08, 0x67, 0x8E,
|
||||
0xEB, 0x67, 0x34, 0x7F, 0x7A, 0x35, 0xAF, 0xD9, 0x07, 0x52, 0x30, 0x38, 0x70, 0xC9, 0x41, 0xF8,
|
||||
0x36, 0x61, 0x32, 0x72, 0xA4, 0x7A, 0xEA, 0x21, 0xB4, 0xBF, 0xAA, 0xCF, 0x93, 0x4F, 0xE1, 0x5C,
|
||||
0xA0, 0xFB, 0xD0, 0x2B, 0xA3, 0x82, 0x2E, 0x69, 0x7D, 0xB7, 0x76, 0x88, 0xF7, 0x5C, 0xF3, 0x82,
|
||||
0xC6, 0x6D, 0x49, 0x92, 0x64, 0x88, 0x9A, 0x43, 0xEE, 0xE9, 0x93, 0xC3, 0x70, 0x50, 0x22, 0xF1,
|
||||
0xD3, 0x2B, 0xCF, 0xA9, 0xE5, 0x69, 0x22, 0xF9, 0xBF, 0x78, 0x9A, 0xA4, 0x5A, 0x3D, 0x2E, 0x2A,
|
||||
0x23, 0xE3, 0x51, 0x8F, 0x1A, 0xC1, 0xAF, 0x47, 0x9C, 0x14, 0xCE, 0xB9, 0xCD, 0xD0, 0x02, 0xB7,
|
||||
0xB8, 0x81, 0xCC, 0x44, 0xE7, 0xA2, 0x6F, 0x32, 0x8C, 0x78, 0x79, 0x10, 0xF3, 0xE1, 0xB0, 0x7C,
|
||||
0xAB, 0x40, 0xDB, 0xF9, 0x99, 0xE7, 0x27, 0x30, 0x53, 0x67, 0x00, 0xE8, 0x33, 0x6D, 0xFC, 0x4D,
|
||||
0xDC, 0xB0, 0xFC, 0x3D, 0xEF, 0x8D, 0x43, 0xAF, 0x7E, 0x41, 0x69, 0xDA, 0xFD, 0xDF, 0x2F, 0xF8,
|
||||
0xEC, 0xFB, 0x6A, 0x65, 0xE7, 0xEC, 0xC7, 0x53, 0x1B, 0x14, 0xDF, 0xBD, 0x0C, 0x54, 0x57, 0xD2,
|
||||
0x56, 0x15, 0xF4, 0x34, 0xE2, 0xFB, 0x12, 0xA0, 0xA2, 0xDE, 0x82, 0xF5, 0x04, 0x81, 0x9B, 0x08,
|
||||
0xB6, 0x8C, 0x7B, 0xE0, 0xAA, 0xDF, 0xC9, 0x92, 0x9D, 0x5F, 0x2D, 0xF7, 0x4A, 0x0B, 0xFF, 0xA5,
|
||||
0xAA, 0xDC, 0xD6, 0x3F, 0x56, 0xB2, 0x6A, 0x3C, 0x6F, 0xAA, 0xAC, 0x84, 0xAC, 0x3F, 0x3D, 0x05,
|
||||
0x96, 0x12, 0x44, 0x39, 0x1C, 0xD1, 0xFA, 0xBE, 0x6B, 0x1A, 0xCD, 0x31, 0x29, 0x41, 0x31, 0xA3,
|
||||
0xA8, 0x0D, 0x87, 0xEB, 0x96, 0x21, 0x39, 0xD6, 0x3B, 0x11, 0x50, 0xB5, 0xFE, 0x44, 0x0E, 0x74,
|
||||
0x31, 0x12, 0xA1, 0x66, 0x49, 0xFD, 0x2D, 0x75, 0x72, 0xF9, 0xC8, 0xD9, 0x6C, 0xC9, 0x11, 0x74,
|
||||
0x2E, 0xEB, 0x20, 0x33, 0x3D, 0x2C, 0x5E, 0xEA, 0x39, 0x31, 0x88, 0xC7, 0xD1, 0x93, 0x95, 0xD8,
|
||||
0x9E, 0x87, 0x93, 0xBC, 0x09, 0x17, 0xC9, 0xA2, 0x59, 0x18, 0x51, 0x8F, 0xBF, 0x55, 0x45, 0x81,
|
||||
0x8D, 0xFD, 0xAF, 0xB2, 0x21, 0xB7, 0xD8, 0xA8, 0x00, 0x2E, 0x70, 0x73, 0x2F, 0x74, 0xBC, 0x61,
|
||||
0x0A, 0x8E, 0xE3, 0x0A, 0x92, 0x82, 0xD2, 0x82, 0xBA, 0xE4, 0x3E, 0x8E, 0xBB, 0xC7, 0xA2, 0x8F,
|
||||
0x68, 0xE1, 0x29, 0x34, 0x7C, 0xB4, 0x22, 0xCF, 0x36, 0x8F, 0x9D, 0x63, 0x9D, 0x04, 0x8F, 0x4A,
|
||||
0xFB, 0x84, 0xBB, 0x6B, 0x97, 0x2C, 0x15, 0xC9, 0x37, 0x4F, 0x40, 0xD7, 0x47, 0x50, 0x39, 0x97
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Packing Service message
|
||||
*
|
||||
* @param instPtr pointer to linklayer instance
|
||||
* type message type.
|
||||
* dstId destination node address.
|
||||
*
|
||||
* @return EPARAM
|
||||
* SUCCESS
|
||||
*
|
||||
******************************************************************************/
|
||||
static int32_t Service_Packing(L2_INST *instPtr, L2_FRAME_TYPE type, uint8_t dstId)
|
||||
{
|
||||
#ifndef DATALINK_ENABLE_BERTEST
|
||||
ASSERT(instPtr != NULL);
|
||||
int32_t Status;
|
||||
uint32_t dataChunk;
|
||||
uint8_t *buff = instPtr->sendPktData;
|
||||
|
||||
// Common section of link layer package
|
||||
dataChunk = L2_GetNextFrameNum(instPtr);
|
||||
L2_FrameInsertChunk(buff, L2_MSG_FRAME_NUM, L2_MSG_FRAME_NUM_LEN, &dataChunk);
|
||||
dataChunk = L2_GetNextSlotNum(instPtr);
|
||||
L2_FrameInsertChunk(buff, L2_MSG_SLOT_NUM, L2_MSG_SLOT_NUM_LEN, &dataChunk);
|
||||
dataChunk = L2_GetNodeId(instPtr);
|
||||
L2_FrameInsertChunk(buff, L2_MSG_SRC_ID, L2_MSG_SRC_ID_LEN, &dataChunk);
|
||||
dataChunk = dstId;
|
||||
L2_FrameInsertChunk(buff, L2_MSG_DST_ID, L2_MSG_DST_ID_LEN, &dataChunk);
|
||||
switch (type)
|
||||
{
|
||||
case L2_SVC_FRAME:
|
||||
{
|
||||
dataChunk = L2_SVC_FRAME;
|
||||
L2_FrameInsertChunk(buff, L2_MSG_TYPE, L2_MSG_TYPE_LEN, &dataChunk);
|
||||
|
||||
SysMonitor_GetSysinfo(&(instPtr->sysInfo));
|
||||
// insert position and speed info
|
||||
L2_FrameInsertChunk(buff, L2_MSG_SVC_SRC_POSX, L2_MSG_SVC_SRC_POSX_LEN, &(instPtr->sysInfo.posX));
|
||||
L2_FrameInsertChunk(buff, L2_MSG_SVC_SRC_POSY, L2_MSG_SVC_SRC_POSY_LEN, &(instPtr->sysInfo.posY));
|
||||
L2_FrameInsertChunk(buff, L2_MSG_SVC_SRC_POSZ, L2_MSG_SVC_SRC_POSZ_LEN, &(instPtr->sysInfo.posZ));
|
||||
L2_FrameInsertChunk(buff, L2_MSG_SVC_SRC_SPEEDX, L2_MSG_SVC_SRC_SPEEDX_LEN, &(instPtr->sysInfo.vX));
|
||||
L2_FrameInsertChunk(buff, L2_MSG_SVC_SRC_SPEEDY, L2_MSG_SVC_SRC_SPEEDY_LEN, &(instPtr->sysInfo.vY));
|
||||
L2_FrameInsertChunk(buff, L2_MSG_SVC_SRC_SPEEDZ, L2_MSG_SVC_SRC_SPEEDZ_LEN, &(instPtr->sysInfo.vZ));
|
||||
|
||||
uint32_t dataId;
|
||||
if (L2_GetNodeType(instPtr) == L2_NODE_HEAD)
|
||||
{
|
||||
SysMonitor_GetSendPayload(buff + L2_MSG_SVC_PAYLOAD, &dataId, PAYLOAD_LEN_FLJ_TX);
|
||||
}
|
||||
else
|
||||
{
|
||||
SysMonitor_GetSendPayload(buff + L2_MSG_SVC_PAYLOAD, &dataId, PAYLOAD_LEN_LJ_TX);
|
||||
}
|
||||
|
||||
L2_FrameInsertChunk(buff, L2_MSG_SVC_PAYLOAD_ID, L2_MSG_SVC_PAYLOAD_ID_LEN, &dataId);
|
||||
if (dataId == DATA_ID_NONE)
|
||||
{
|
||||
L2_FrameInsertChunk(buff, L2_MSG_SVC_PAYLOAD, L2_MSG_SVC_PAYLOAD_LEN, testData);
|
||||
}
|
||||
|
||||
Status = L2_CrcAppend(buff, L2_SVC_PACK_LEN - L2_MSG_SVC_CRC_LEN, L2_MSG_SVC_CRC, L2_CRC16_1021);
|
||||
if (Status != SUCCESS)
|
||||
{
|
||||
DBG_ERROR("Fail to append CRC...\n");
|
||||
return Status;
|
||||
}
|
||||
|
||||
memcpy(instPtr->log.txLog.data, buff, L2_SVC_PACK_LEN);
|
||||
instPtr->log.txLog.dataId = dataId;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
DBG_ERROR("Unexpected frame type: %" PRIu8 ".\n", type);
|
||||
return EPARAM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return SUCCESS;
|
||||
#else
|
||||
DBG_ERROR("Unexpected call of Service_Packing in BER test mode.\n");
|
||||
return EUNEXP;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Handle service received packet. Send data up to MPC
|
||||
*
|
||||
* @param msg A point32_ter the the message frame.
|
||||
*
|
||||
* @return SUCCESS message has been successfully handled.
|
||||
* other error occurred.
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t L2_Service_PktHandler(L2_INST *instPtr, uint8_t *msg)
|
||||
{
|
||||
ASSERT(instPtr != NULL);
|
||||
ASSERT(msg != NULL);
|
||||
int32_t Status;
|
||||
#ifndef DATALINK_ENABLE_BERTEST
|
||||
uint8_t srcId = L2_NONE_ID;
|
||||
uint8_t dstId = L2_NONE_ID;
|
||||
L2_FRAME_TYPE frameType = L2_NONE_FRAME;
|
||||
L2_FrameGetChunk(msg, L2_MSG_SRC_ID, L2_MSG_SRC_ID_LEN, &srcId);
|
||||
L2_FrameGetChunk(msg, L2_MSG_DST_ID, L2_MSG_DST_ID_LEN, &dstId);
|
||||
if(dstId != L2_GetNodeId(instPtr)) {
|
||||
DBG_WARNING("Drop frame not addressed to me (%u->%u)", srcId, dstId);
|
||||
return SUCCESS;
|
||||
}
|
||||
L2_FrameGetChunk(msg, L2_MSG_TYPE, L2_MSG_TYPE_LEN, &frameType);
|
||||
switch (frameType)
|
||||
{
|
||||
case L2_SVC_FRAME:
|
||||
{
|
||||
NODE_ENTRY *node;
|
||||
node = L2_GetNodeById(instPtr->nodeList, srcId);
|
||||
if (node == NULL)
|
||||
{
|
||||
DBG_WARNING("Unrecognized node (%u).", srcId);
|
||||
Status = FAILURE;
|
||||
break;
|
||||
}
|
||||
|
||||
// Update node info.
|
||||
float nodePos;
|
||||
L2_FrameGetChunk(msg, L2_MSG_SVC_SRC_POSX, L2_MSG_SVC_SRC_POSX_LEN, &nodePos);
|
||||
node->nodeInfo.pos.x = (double)nodePos;
|
||||
L2_FrameGetChunk(msg, L2_MSG_SVC_SRC_POSY, L2_MSG_SVC_SRC_POSY_LEN, &nodePos);
|
||||
node->nodeInfo.pos.y = (double)nodePos;
|
||||
L2_FrameGetChunk(msg, L2_MSG_SVC_SRC_POSZ, L2_MSG_SVC_SRC_POSZ_LEN, &nodePos);
|
||||
node->nodeInfo.pos.z = (double)nodePos;
|
||||
float nodeSpeed;
|
||||
L2_FrameGetChunk(msg, L2_MSG_SVC_SRC_SPEEDX, L2_MSG_SVC_SRC_SPEEDX_LEN, &nodeSpeed);
|
||||
node->nodeInfo.speed.x = (double)nodePos;
|
||||
L2_FrameGetChunk(msg, L2_MSG_SVC_SRC_SPEEDY, L2_MSG_SVC_SRC_SPEEDY_LEN, &nodeSpeed);
|
||||
node->nodeInfo.speed.y = (double)nodePos;
|
||||
L2_FrameGetChunk(msg, L2_MSG_SVC_SRC_SPEEDZ, L2_MSG_SVC_SRC_SPEEDZ_LEN, &nodeSpeed);
|
||||
node->nodeInfo.speed.z = (double)nodePos;
|
||||
|
||||
// Reset node ttl
|
||||
node->ttlCnt = 0;
|
||||
|
||||
// Calculate time deviation
|
||||
uint32_t frameNum, slotNum = 0;
|
||||
L2_FrameGetChunk(msg, L2_MSG_FRAME_NUM, L2_MSG_FRAME_NUM_LEN, &frameNum);
|
||||
L2_FrameGetChunk(msg, L2_MSG_SLOT_NUM, L2_MSG_SLOT_NUM_LEN, &slotNum);
|
||||
Status = L2_GetTimeDeviation(instPtr, frameNum, slotNum, true, &(instPtr->log.timeDev));
|
||||
if (Status != SUCCESS)
|
||||
{
|
||||
DBG_ERROR("Failed to compute time deviation.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t dataId;
|
||||
L2_FrameGetChunk(msg, L2_MSG_SVC_PAYLOAD_ID, L2_MSG_SVC_PAYLOAD_ID_LEN, &dataId);
|
||||
|
||||
if (L2_GetNodeType(instPtr) == L2_NODE_HEAD)
|
||||
{
|
||||
SysMonitor_UpdateRecvPayload(msg + L2_MSG_SVC_PAYLOAD, dataId, PAYLOAD_LEN_FLJ_RX);
|
||||
}
|
||||
else
|
||||
{
|
||||
SysMonitor_UpdateRecvPayload(msg + L2_MSG_SVC_PAYLOAD, dataId, PAYLOAD_LEN_LJ_RX);
|
||||
}
|
||||
|
||||
// Logging
|
||||
memcpy(instPtr->log.rxLog.data, msg, L2_SVC_PACK_LEN);
|
||||
instPtr->log.rxLog.dataId = dataId;
|
||||
instPtr->serviceFSM->rxdCnt++;
|
||||
|
||||
#ifdef DATALINK_ENABLE_AUTOTIMESYNC
|
||||
// Implement a auto time sync.
|
||||
if (L2_GetNodeType(instPtr) != L2_NODE_HEAD)
|
||||
{
|
||||
// Time sync.
|
||||
L2_TimeAdjust(instPtr, &(instPtr->log.timeDev));
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
default:
|
||||
DBG_ERROR("Unsupported frame type: %" PRIu8 ".\n", frameType);
|
||||
break;
|
||||
}
|
||||
return Status;
|
||||
#else
|
||||
uint32_t errorBits = 0;
|
||||
for (int i = 0; i < L2_SVC_PACK_LEN; i++)
|
||||
{
|
||||
errorBits += count_ones(msg[i] ^ testData[i]);
|
||||
}
|
||||
|
||||
instPtr->serviceFSM->bitError += errorBits;
|
||||
instPtr->serviceFSM->bitTotal += L2_SVC_PACK_LEN * 8;
|
||||
|
||||
// Calculate time deviation
|
||||
uint32_t frameNum, slotNum = 0;
|
||||
L2_FrameGetChunk(msg, L2_MSG_FRAME_NUM, L2_MSG_FRAME_NUM_LEN, &frameNum);
|
||||
L2_FrameGetChunk(msg, L2_MSG_SLOT_NUM, L2_MSG_SLOT_NUM_LEN, &slotNum);
|
||||
Status = L2_GetTimeDeviation(instPtr, frameNum, slotNum, true, &(instPtr->log.timeDev));
|
||||
if (Status != SUCCESS)
|
||||
{
|
||||
DBG_ERROR("Failed to compute time deviation.\n")
|
||||
return Status;
|
||||
}
|
||||
// Implement a auto time sync.
|
||||
if (L2_GetNodeType(instPtr) != L2_NODE_HEAD)
|
||||
{
|
||||
// Time sync.
|
||||
L2_TimeAdjust(instPtr, &(instPtr->log.timeDev));
|
||||
}
|
||||
return SUCCESS;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Initialize service net FSM
|
||||
*
|
||||
* @param serviceFSM A pointer to service FSM instance.
|
||||
*
|
||||
* @return SUCCESS Initialize successfully.
|
||||
* Other Initialize failed.
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t L2_Service_Init(L2_SVC_FSM **svcFSMPtr)
|
||||
{
|
||||
ASSERT(svcFSMPtr != NULL);
|
||||
*svcFSMPtr = (L2_SVC_FSM *)malloc(sizeof(L2_SVC_FSM));
|
||||
if (*svcFSMPtr == NULL)
|
||||
{
|
||||
return ENOMEM;
|
||||
}
|
||||
L2_Service_Reset(*svcFSMPtr);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Reset ServiceNet FSM
|
||||
*
|
||||
* @param scanFsmPtr a pointer to service net finite state machine
|
||||
*
|
||||
* @return NONE
|
||||
*
|
||||
******************************************************************************/
|
||||
void L2_Service_Reset(L2_SVC_FSM *svcFSMPtr)
|
||||
{
|
||||
ASSERT(svcFSMPtr != NULL);
|
||||
svcFSMPtr->txCnt = 0;
|
||||
svcFSMPtr->rxCnt = 0;
|
||||
svcFSMPtr->rxdCnt = 0;
|
||||
#ifdef DATALINK_ENABLE_BERTEST
|
||||
svcFSMPtr->bitTotal = 0;
|
||||
svcFSMPtr->bitError = 0;
|
||||
svcFSMPtr->lossRate = 0;
|
||||
svcFSMPtr->errorRate = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Destroy ServiceNet FSM, free memory
|
||||
*
|
||||
* @param scanFsmPtr a pointer to service net finite state machine
|
||||
*
|
||||
* @return NONE
|
||||
*
|
||||
******************************************************************************/
|
||||
void L2_Service_Destroy(L2_SVC_FSM *serviceFSM)
|
||||
{
|
||||
free(serviceFSM);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Service FSM Routine.
|
||||
*
|
||||
* @param instPtr
|
||||
* @param schedEntry
|
||||
*
|
||||
* @return Slot has been used.
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t L2_Service_Routine(L2_INST *instPtr, const L2_RTNE_TABLE_ENTRY *rtneEntry)
|
||||
{
|
||||
ASSERT(instPtr != NULL);
|
||||
DBG_INFO("-------- ServiceNet Routine --------\n");
|
||||
|
||||
if (rtneEntry->slotSeq != 0)
|
||||
{
|
||||
return SUCCESS; // skip
|
||||
}
|
||||
|
||||
PHY_INST *phyRef = instPtr->config.phyInstPtr;
|
||||
L2_SVC_FSM *svcFSMPtr = instPtr->serviceFSM;
|
||||
L2_TOR_TYPE torState;
|
||||
const NODE_ENTRY *commNode;
|
||||
if (rtneEntry->src == L2_GetNodeId(instPtr))
|
||||
{
|
||||
torState = L2_TOR_TX;
|
||||
commNode = L2_GetNodeById(instPtr->nodeList, rtneEntry->dst);
|
||||
}
|
||||
else if (rtneEntry->dst == L2_GetNodeId(instPtr))
|
||||
{
|
||||
torState = L2_TOR_RX;
|
||||
commNode = L2_GetNodeById(instPtr->nodeList, rtneEntry->src);
|
||||
}
|
||||
else
|
||||
{
|
||||
torState = L2_TOR_SUSPEND;
|
||||
}
|
||||
|
||||
// Setup antenna beam
|
||||
if (L2_GetNodeType(instPtr) != L2_NODE_HEAD && commNode != NULL)
|
||||
{
|
||||
Phy_SetBeamWidth(phyRef, PHY_ANT_BEAM_16);
|
||||
Phy_SetBeamNo(phyRef, commNode->nodeInfo.beamNo, PHY_ANT_BEAM_16);
|
||||
instPtr->log.lastBeamWidth = PHY_ANT_BEAM_16;
|
||||
}
|
||||
else
|
||||
{
|
||||
Phy_SetBeamWidth(phyRef, PHY_ANT_BEAM_120);
|
||||
instPtr->log.lastBeamWidth = PHY_ANT_BEAM_120;
|
||||
}
|
||||
|
||||
switch (rtneEntry->slotType)
|
||||
{
|
||||
case L2_SLOT_SERVICE:
|
||||
if (torState == L2_TOR_TX)
|
||||
{
|
||||
svcFSMPtr->txCnt++;
|
||||
#ifndef DATALINK_ENABLE_BERTEST
|
||||
// Packing service data
|
||||
Service_Packing(instPtr, L2_SVC_FRAME, rtneEntry->dst);
|
||||
#else
|
||||
memcpy(instPtr->sendPktData, testData, L2_SVC_PACK_LEN);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
svcFSMPtr->rxCnt++;
|
||||
}
|
||||
L2_SetupNextSlot(instPtr, torState, L2_SVC_FRAME);
|
||||
break;
|
||||
default:
|
||||
DBG_ERROR("UNKNOWN slot type [%" PRIu8 "].\n", rtneEntry->slotType);
|
||||
return FAILURE;
|
||||
}
|
||||
#ifdef DATALINK_ENABLE_BERTEST
|
||||
uint32_t pktLoss;
|
||||
pktLoss = svcFSMPtr->rxCnt - svcFSMPtr->rxdCnt;
|
||||
svcFSMPtr->lossRate = (svcFSMPtr->rxCnt == 0) ? 0 : (double)pktLoss / (double)svcFSMPtr->rxCnt;
|
||||
svcFSMPtr->errorRate = (svcFSMPtr->bitTotal == 0) ? 0 : (double)svcFSMPtr->bitError / (double)svcFSMPtr->bitTotal;
|
||||
DBG_PRINT("Packet Loss Rate -- Total: %lu, Loss: %lu.\n", instPtr->log.svcRxCnt, pktLoss);
|
||||
DBG_PRINT("Bit Error Rate -- Total:%lu, Error:%lu.\n", svcFSMPtr->bitTotal, svcFSMPtr->bitError);
|
||||
#endif
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/** @} LinkLayer_Service*/
|
||||
/** @} LinkLayer*/
|
||||
@@ -0,0 +1,105 @@
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @file time_sync.c
|
||||
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||
* @brief DF Linklayer time sync implementation file.
|
||||
* @version 0.0
|
||||
* @date 2023-05-06
|
||||
*
|
||||
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||
* Lab of Communication and Network
|
||||
*
|
||||
******************************************************************************/
|
||||
/**
|
||||
* @addtogroup LinkLayer
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup LinkLayer_TimeSync
|
||||
* @{
|
||||
*/
|
||||
/***************************** Include Files *********************************/
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "link_layer.h"
|
||||
#include "../phy_layer/phy_layer.h"
|
||||
#include "error.h"
|
||||
#include "common.h"
|
||||
|
||||
/************************** Constant Definitions *****************************/
|
||||
/***************** Macros (Inline Functions) Definitions *********************/
|
||||
/**************************** Type Definitions *******************************/
|
||||
/************************** Variable Definitions *****************************/
|
||||
/************************** Function Prototypes ******************************/
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Get time deviation to the specified frame and slot number.
|
||||
*
|
||||
* @param instPtr a pointer to linklayer layer instance
|
||||
* @param frameNum
|
||||
* @param slotNum
|
||||
* @param relative
|
||||
* @param timeDev
|
||||
*
|
||||
* @return SUCCESS
|
||||
* EIGNORE there is no received frame
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t L2_GetTimeDeviation(L2_INST *instPtr, uint32_t frameNum, uint32_t slotNum, bool relative, int64_t *timeDev)
|
||||
{
|
||||
ASSERT(instPtr != NULL);
|
||||
ASSERT(timeDev != NULL);
|
||||
L1_FRAME_TYPE lastRecvdFrame;
|
||||
PHY_INST *phyRef = instPtr->config.phyInstPtr;
|
||||
lastRecvdFrame = Phy_GetLastRecvFrameType(phyRef);
|
||||
if (lastRecvdFrame == L1_NONE_FRAME)
|
||||
{
|
||||
DBG_ERROR("Invalid TimeAlign operation, no frame was received.");
|
||||
return EIGNORE;
|
||||
}
|
||||
|
||||
DBG_INFO("Starting TimeAlign operation...\n");
|
||||
// read nextSendTime from physical layer
|
||||
uint64_t currTime, expectTime;
|
||||
TIME_WORD timeStamp;
|
||||
expectTime = ((uint64_t)(frameNum * L2_SLOTS_PER_FRAME + slotNum)) * TIME_FRAC_MAX;
|
||||
expectTime += Phy_GetTimeComp(lastRecvdFrame);
|
||||
|
||||
if (relative)
|
||||
{
|
||||
expectTime += (uint64_t)instPtr->netStartTime * L2_SLOTS_PER_FRAME * TIME_FRAC_MAX;
|
||||
}
|
||||
|
||||
Phy_GetLastReceivedFrameSyncTimeStamp(phyRef, &timeStamp);
|
||||
currTime = (uint64_t)timeStamp.frac_part;
|
||||
currTime += ((uint64_t)timeStamp.int_part) * TIME_FRAC_MAX;
|
||||
|
||||
*timeDev = (int64_t)(expectTime - currTime);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Implement time adjustment by applying time deviation.
|
||||
*
|
||||
* @param instPtr a pointer to linklayer layer instance
|
||||
* @param timeDev
|
||||
*
|
||||
* @return NONE
|
||||
*
|
||||
******************************************************************************/
|
||||
void L2_TimeAdjust(L2_INST *instPtr, const int64_t *timeDev)
|
||||
{
|
||||
ASSERT(instPtr != NULL);
|
||||
ASSERT(timeDev != NULL);
|
||||
TIME_WORD slotTimerAdjmet;
|
||||
slotTimerAdjmet.int_part = (uint32_t)(*timeDev / TIME_FRAC_MAX);
|
||||
slotTimerAdjmet.frac_part = (uint32_t)(*timeDev % TIME_FRAC_MAX);
|
||||
TimeCtrl_TimeAdjust(instPtr->config.tmcInstPtr, &slotTimerAdjmet, TM_ADJ_ADD);
|
||||
}
|
||||
|
||||
/** @} LinkLayer_TimeSync*/
|
||||
|
||||
/** @} LinkLayer*/
|
||||
@@ -0,0 +1,428 @@
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @file phy_antenna.h
|
||||
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||
* @brief Physical layer control antenna configuration functions.
|
||||
* @version 0.0
|
||||
* @date 2023-04-24
|
||||
*
|
||||
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||
* Lab of Communication and Network
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @addtogroup PhysicalLayer
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup PhysicalLayer_AntennaControl
|
||||
* @{
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
#include "error.h"
|
||||
#include "phy_layer.h"
|
||||
|
||||
/**
|
||||
* @name PhysicalLayer_AntennaConfig_Constants
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define ANT_PI 3.14159265358979323846
|
||||
|
||||
#define ANT_COINFO_HEAD 0xAA
|
||||
#define ANT_COINFO_TAIL 0xCC
|
||||
|
||||
#define CTRL_WORD_DEFAULT 0x00
|
||||
|
||||
#define ANT_MODE_BEAM_MASK 0xF0
|
||||
#define ANT_BEAM_NARROR 0x00 // 8
|
||||
#define ANT_BEAM_SUBNARROR_0 0x10 // 25
|
||||
#define ANT_BEAM_SUBNARROR_1 0x20 // 60
|
||||
#define ANT_BEAM_WIDE 0x30 // 120
|
||||
|
||||
#define ANT_MODE_POWER_MASK 0x0F
|
||||
#define ANT_POWER_FULL 0x00
|
||||
#define ANT_POWER_LOW 0x04
|
||||
#define ANT_POWER_STANDBY 0x0F
|
||||
#define ATN_MODE_SILENT (ANT_BEAM_SUBNARROR_0 | ANT_POWER_STANDBY)
|
||||
#define ATN_MODE_LOWPOWER (ANT_BEAM_SUBNARROR_0 | ANT_POWER_LOW)
|
||||
#define ATN_MODE_FULLPOWER (ANT_BEAM_SUBNARROR_0 | ANT_POWER_FULL)
|
||||
#define ATN_MODE_DEFAULT ATN_MODE_SILENT
|
||||
|
||||
#define DEFAULT_CENTRTAL_FREQ 0x06D7 // 26.25GHz
|
||||
|
||||
#define RXTXMODE_RX 0x00
|
||||
#define RXTXMODE_TX 0x01
|
||||
|
||||
#define RXTXMODE_DEFAULT 0x00
|
||||
|
||||
#define CALIBRMODE_NORMAL 0x00
|
||||
#define CALIBRMODE_SINGLE_TR_CAL 0x01
|
||||
|
||||
#define RF_CTRL_DEFAULT 0x00
|
||||
|
||||
// Pair by regex
|
||||
// Regex: (([0-9]+, ){8})
|
||||
const uint16_t freqTable[L1_FRAME_MAX_HOPS] =
|
||||
{
|
||||
1084, 1097, 1110, 1123, 1136, 1149, 1162, 1175,
|
||||
1188, 1201, 1214, 1227, 1240, 1253, 1266, 1279,
|
||||
1292, 1305, 1318, 1331, 1344, 1357, 1370, 1383,
|
||||
1396, 1409, 1422, 1435, 1448, 1461, 1474, 1487,
|
||||
1500, 1513, 1526, 1539, 1552, 1565, 1578, 1591,
|
||||
1604, 1617, 1630, 1643, 1656, 1669, 1682, 1695,
|
||||
1708, 1721, 1734, 1747, 1760, 1773, 1786, 1799,
|
||||
1812, 1825, 1838, 1851, 1864, 1877, 1890, 1903,
|
||||
1916, 1929, 1942, 1955, 1968, 1981, 1994, 2007,
|
||||
2020, 2033, 2046, 2059, 2072, 2085, 2098, 2111,
|
||||
2124
|
||||
};
|
||||
|
||||
const uint16_t antCalTable[L1_FRAME_MAX_HOPS][L1_ANT_NUM_CH] =
|
||||
//Antenna-JG01
|
||||
{
|
||||
{ 0, 406, -10530, -8223}, { 0, 697, -9933, -7988},
|
||||
{ 0, 296, -10497, -8272}, { 0, 515, -10264, -8093},
|
||||
{ 0, 689, -10212, -8064}, { 0, 40, -10960, -8572},
|
||||
{ 0, 722, -10878, -8518}, { 0, 59, -10987, -8962},
|
||||
{ 0, 56, -11264, -8770}, { 0, -464, -11341, -9159},
|
||||
{ 0, 19, -10924, -8887}, { 0, -669, -10927, -8679},
|
||||
{ 0, -701, -11154, -8712}, { 0, -255, -10739, -8009},
|
||||
{ 0, -192, -10509, -8242}, { 0, -1057, -11183, -9007},
|
||||
{ 0, -57, -10606, -8350}, { 0, -719, -10949, -8880},
|
||||
{ 0, -760, -11084, -8660}, { 0, -457, -10735, -8833},
|
||||
{ 0, -188, -10623, -9119}, { 0, -628, -12609, -10119},
|
||||
{ 0, -434, -12714, -10225}, { 0, -727, -13074, -10685},
|
||||
{ 0, -12, -12408, -10190}, { 0, 33, -12790, -10624},
|
||||
{ 0, 93, -13235, -10819}, { 0, -363, -13301, -11183},
|
||||
{ 0, -514, -13955, -11557}, { 0, -458, -13878, -11722},
|
||||
{ 0, 93, -13086, -11726}, { 0, -663, -13597, -11868},
|
||||
{ 0, 174, -12814, -11295}, { 0, 121, -12278, -11150},
|
||||
{ 0, 425, -11255, -10363}, { 0, 430, -11645, -10189},
|
||||
{ 0, 277, -11844, -9499}, { 0, -132, -12241, -9420},
|
||||
{ 0, 448, -11934, -9612}, { 0, 200, -11778, -9582},
|
||||
{ 0, -40, -12069, -9336}, { 0, 1692, -11315, -9085},
|
||||
{ 0, -1753, -11445, -9482}, { 0, -2520, -12620, -10068},
|
||||
{ 0, -1976, -12674, -10218}, { 0, -1984, -12525, -10354},
|
||||
{ 0, -2272, -13476, -10932}, { 0, -2123, -13918, -11095},
|
||||
{ 0, -2883, -14447, -11659}, { 0, -2826, -13946, -11563},
|
||||
{ 0, -2697, -13680, -11328}, { 0, -3068, -13393, -11614},
|
||||
{ 0, -2935, -13074, -11882}, { 0, -3017, -13038, -11163},
|
||||
{ 0, -2490, -12379, -11288}, { 0, -2463, -12286, -10726},
|
||||
{ 0, -2686, -12167, -10673}, { 0, -2428, -12077, -10555},
|
||||
{ 0, -2282, -12564, -10388}, { 0, -2017, -12303, -10844},
|
||||
{ 0, -2329, -12637, -11250}, { 0, -2703, -13362, -11807},
|
||||
{ 0, -1820, -12605, -11733}, { 0, 596, -10833, -9852},
|
||||
{ 0, 9, -11140, -9776}, { 0, 41, -11168, -9478},
|
||||
{ 0, -261, -11368, -9752}, { 0, 226, -11282, -9879},
|
||||
{ 0, -68, -11454, -10148}, { 0, -314, -12278, -10716},
|
||||
{ 0, -66, -11998, -10762}, { 0, -58, -11469, -10664},
|
||||
{ 0, 319, -10759, -10212}, { 0, 122, -11041, -9901},
|
||||
{ 0, -269, -11085, -10008}, { 0, 637, -10569, -9674},
|
||||
{ 0, 1185, -10632, -9521}, { 0, 902, -11053, -9681},
|
||||
{ 0, 560, -11408, -9588}, { 0, 1162, -11079, -9371},
|
||||
{ 0, 1780, -10547, -9133},
|
||||
};
|
||||
|
||||
const uint8_t hopPattern_2KBPS_20MS[L1_FRAME_2KBPS_20MS_HOPS] =
|
||||
{
|
||||
0
|
||||
};
|
||||
|
||||
const uint8_t hopPattern_2KBPS_100MS[L1_FRAME_2KBPS_100MS_HOPS] =
|
||||
{
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23,
|
||||
24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39,
|
||||
40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55,
|
||||
56, 57, 58, 59, 60, 61, 62, 63,
|
||||
64, 65, 66, 67, 68, 69, 70, 71,
|
||||
72, 73, 74, 75, 76, 77, 78, 79,
|
||||
80
|
||||
};
|
||||
|
||||
const uint8_t hopPattern_10KBPS_10MS[L1_FRAME_10KBPS_10MS_HOPS] =
|
||||
{
|
||||
80
|
||||
};
|
||||
|
||||
const uint8_t hopPattern_10KBPS_20MS[L1_FRAME_10KBPS_20MS_HOPS] =
|
||||
{
|
||||
80, 1, 2, 3, 4, 5, 6, 7,
|
||||
8, 9, 10
|
||||
};
|
||||
|
||||
const uint8_t hopPattern_40KBPS_10MS[L1_FRAME_40KBPS_10MS_HOPS] =
|
||||
{
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
8,
|
||||
};
|
||||
|
||||
const uint8_t hopPattern_40KBPS_20MS[L1_FRAME_40KBPS_20MS_HOPS] =
|
||||
{
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18
|
||||
};
|
||||
|
||||
const uint8_t hopPattern_200KBPS_5MS[L1_FRAME_200KBPS_5MS_HOPS] =
|
||||
{
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19
|
||||
};
|
||||
|
||||
const uint8_t hopPattern_1M2BPS_5MS[L1_FRAME_1M2BPS_5MS_HOPS] =
|
||||
{
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19
|
||||
};
|
||||
|
||||
/** @} PhysicalLayer_AntennaConfig_Constants*/
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Initialize antenna configurations (load preset values)
|
||||
*
|
||||
* @param antConfig pointer to antenna configure
|
||||
*
|
||||
* @return None.
|
||||
*
|
||||
******************************************************************************/
|
||||
void Phy_AntConfigInit(PHY_ANT_CONFIG *antConfig)
|
||||
{
|
||||
ASSERT(antConfig != NULL);
|
||||
|
||||
antConfig->ctrlWord = CTRL_WORD_DEFAULT;
|
||||
antConfig->antMode = ATN_MODE_DEFAULT;
|
||||
|
||||
// FIXME: Dummy default value.
|
||||
// off axis angle setting
|
||||
antConfig->oaxis[0] = 0;
|
||||
antConfig->oaxis[1] = 0;
|
||||
// round axis angle setting
|
||||
antConfig->raxis[0] = 0;
|
||||
antConfig->raxis[1] = 0;
|
||||
// ***********************
|
||||
|
||||
antConfig->antFreq[0] = (uint8_t)(DEFAULT_CENTRTAL_FREQ);
|
||||
antConfig->antFreq[1] = (uint8_t)(DEFAULT_CENTRTAL_FREQ >> 8);
|
||||
|
||||
// FIXME: Dummy default value.
|
||||
// trSelect
|
||||
antConfig->trSlect = 0;
|
||||
// Antenna attenuation setting
|
||||
antConfig->antAtt = 0;
|
||||
// phase setting
|
||||
antConfig->phase = 0;
|
||||
// ***********************
|
||||
|
||||
antConfig->rxtxMode = RXTXMODE_DEFAULT;
|
||||
antConfig->calibrMode = CALIBRMODE_NORMAL;
|
||||
antConfig->antReserved = 0x00;
|
||||
|
||||
// FIXME: Dummy default value.
|
||||
// RF mode control
|
||||
antConfig->rfCtrl = RF_CTRL_DEFAULT;
|
||||
// RF frequency
|
||||
antConfig->rfFreq[0] = (uint8_t)(DEFAULT_CENTRTAL_FREQ);
|
||||
antConfig->rfFreq[1] = (uint8_t)(DEFAULT_CENTRTAL_FREQ >> 8);
|
||||
// RF MGC control
|
||||
antConfig->rfTxMgc = 0;
|
||||
// RF channel 1&2 calibration mgc
|
||||
antConfig->rf12CalMgc = 0;
|
||||
// RF channel 2&3 calibration mgc
|
||||
antConfig->rf34CalMgc = 0;
|
||||
// Receive channel 1-4 MGC
|
||||
antConfig->rcvMgc = 0;
|
||||
antConfig->rfReserved0 = 0x00;
|
||||
antConfig->rfReserved1 = 0x00;
|
||||
// ***********************
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Update antenna power mode setting
|
||||
*
|
||||
* @param instPtr pointer to physical layer instance
|
||||
* @param mode new antenna mode
|
||||
*
|
||||
* @return None.
|
||||
*
|
||||
******************************************************************************/
|
||||
void Phy_AntConfigMode(PHY_INST *instPtr, PHY_ANT_MODE mode)
|
||||
{
|
||||
ASSERT(instPtr != NULL);
|
||||
uint8_t config = instPtr->antConfig.antMode & ANT_MODE_BEAM_MASK;
|
||||
switch (mode)
|
||||
{
|
||||
case PHY_ANT_MODE_STANDBY:
|
||||
config |= ANT_POWER_STANDBY;
|
||||
break;
|
||||
case PHY_ANT_MODE_POWER_LOW:
|
||||
config |= ANT_POWER_LOW;
|
||||
break;
|
||||
case PHY_ANT_MODE_POWER_FULL:
|
||||
config |= ANT_POWER_FULL;
|
||||
break;
|
||||
default:
|
||||
DBG_ERROR("Unknown antenna mode: %" PRIu8 ", remain previous mode.\n", mode);
|
||||
return;
|
||||
}
|
||||
instPtr->phyLog.antMode = mode;
|
||||
instPtr->antConfig.antMode = config;
|
||||
// Sync logs to system monitor
|
||||
SysMonitor_UpdatePhysicalLayerLog(&(instPtr->phyLog));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Update antenna beam table
|
||||
*
|
||||
* @param instPtr pointer to physical layer instance
|
||||
* @param table new beam table
|
||||
* @param offset table offset
|
||||
*
|
||||
* @return None
|
||||
*
|
||||
******************************************************************************/
|
||||
void Phy_SetBeamTable(PHY_INST *instPtr, PHY_ANT_ANGLE *table, uint32_t offset)
|
||||
{
|
||||
ASSERT(instPtr != NULL);
|
||||
ASSERT(table != NULL);
|
||||
for (int i = 0; i < L1_NUM_ANT_NRRW_PATTERN; i++)
|
||||
{
|
||||
instPtr->antNrrwPattern[i] = table[(i + offset) % L1_NUM_ANT_NRRW_PATTERN];
|
||||
}
|
||||
memcpy((uint32_t *)instPtr->antInfoAddr, instPtr->antNrrwPattern,
|
||||
NORMALIZE_SIZE(L1_NUM_ANT_NRRW_PATTERN * sizeof(PHY_ANT_ANGLE)));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Update antenna point direction using predefined beam table
|
||||
*
|
||||
* @param instPtr pointer to physical layer instance
|
||||
* @param beamNo new beam index
|
||||
*
|
||||
* @return SUCCESS.
|
||||
* FAILURE beamNo exceeds the table size
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t Phy_SetBeamNo(PHY_INST *instPtr, int32_t beamNo, PHY_ANT_BEAM_WIDTH beamWidth)
|
||||
{
|
||||
ASSERT(instPtr != NULL);
|
||||
|
||||
if (beamWidth == PHY_ANT_BEAM_16)
|
||||
{
|
||||
if (beamNo >= L1_NUM_ANT_NRRW_PATTERN)
|
||||
{
|
||||
return FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
instPtr->beamNo.next = beamNo;
|
||||
instPtr->antConfig.oaxis[0] = (uint8_t)(instPtr->antNrrwPattern[beamNo].oaxis >> 8);
|
||||
instPtr->antConfig.oaxis[1] = (uint8_t)(instPtr->antNrrwPattern[beamNo].oaxis);
|
||||
instPtr->antConfig.raxis[0] = (uint8_t)(instPtr->antNrrwPattern[beamNo].raxis >> 8);
|
||||
instPtr->antConfig.raxis[1] = (uint8_t)(instPtr->antNrrwPattern[beamNo].raxis);
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Beam number assign not support.
|
||||
// Assign default angle (0,0)
|
||||
instPtr->beamNo.next = 0;
|
||||
instPtr->antConfig.oaxis[0] = 0;
|
||||
instPtr->antConfig.oaxis[1] = 0;
|
||||
instPtr->antConfig.raxis[0] = 0;
|
||||
instPtr->antConfig.raxis[1] = 0;
|
||||
DBG_WARNING("Using default beam number...\n");
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Update antenna beam width setting
|
||||
*
|
||||
* @param instPtr pointer to physical layer instance
|
||||
* @param beamWidth new beam width
|
||||
*
|
||||
* @return SUCCESS.
|
||||
* EPARAM
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t Phy_SetBeamWidth(PHY_INST *instPtr, PHY_ANT_BEAM_WIDTH beamWidth)
|
||||
{
|
||||
ASSERT(instPtr != NULL);
|
||||
uint8_t beamConfig = instPtr->antConfig.antMode & (~ANT_MODE_BEAM_MASK);
|
||||
switch (beamWidth)
|
||||
{
|
||||
case PHY_ANT_BEAM_120:
|
||||
beamConfig |= ANT_BEAM_WIDE;
|
||||
break;
|
||||
case PHY_ANT_BEAM_60:
|
||||
beamConfig |= ANT_BEAM_SUBNARROR_1;
|
||||
break;
|
||||
case PHY_ANT_BEAM_25:
|
||||
beamConfig |= ANT_BEAM_SUBNARROR_0;
|
||||
break;
|
||||
case PHY_ANT_BEAM_16:
|
||||
beamConfig |= ANT_BEAM_NARROR;
|
||||
break;
|
||||
default:
|
||||
DBG_ERROR("Beam width code: 0x%08X is illegal.\n\r", beamWidth);
|
||||
return EPARAM;
|
||||
}
|
||||
instPtr->antConfig.antMode = beamConfig;
|
||||
instPtr->beamWd.next = beamWidth;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Set antenna to a specific direction
|
||||
*
|
||||
* @param instPtr pointer to physical layer instance
|
||||
* @param offAx elevation angle
|
||||
* @param rndAx azimuth angle
|
||||
*
|
||||
* @return SUCCESS.
|
||||
* EPARAM - the direction is exceeds predefined range
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t Phy_SetBeamAngle(PHY_INST *instPtr, double offAx, double rndAx)
|
||||
{
|
||||
ASSERT(instPtr != NULL);
|
||||
uint16_t offAxDeg = 0;
|
||||
uint16_t rndAxDeg = 0;
|
||||
offAxDeg = (offAx >= 0) ? (((int32_t)(offAx * 180 / ANT_PI)) % 360) : (((int32_t)(offAx * 180 / ANT_PI)) % 360 + 360);
|
||||
rndAxDeg = (rndAx >= 0) ? (((int32_t)(rndAx * 180 / ANT_PI)) % 360) : (((int32_t)(rndAx * 180 / ANT_PI)) % 360 + 360);
|
||||
if (offAxDeg > 60)
|
||||
{
|
||||
DBG_ERROR("Angle out of range, off axis angle: %" PRIu16 " (should be 0~60), round axis angle: %" PRIu16 " (should be 0~360).\n",
|
||||
offAxDeg, rndAxDeg);
|
||||
return EPARAM;
|
||||
}
|
||||
offAxDeg = offAxDeg * 10;
|
||||
rndAxDeg = rndAxDeg * 10;
|
||||
instPtr->antConfig.oaxis[0] = (uint8_t)(offAxDeg >> 8);
|
||||
instPtr->antConfig.oaxis[1] = (uint8_t)offAxDeg;
|
||||
instPtr->antConfig.raxis[0] = (uint8_t)(rndAxDeg >> 8);
|
||||
instPtr->antConfig.raxis[1] = (uint8_t)rndAxDeg;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/** @} PhysicalLayer_AntennaControl*/
|
||||
|
||||
/** @} PhysicalLayer*/
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user