aboutsummaryrefslogtreecommitdiffstats
path: root/firmware/fx3
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/fx3')
-rw-r--r--firmware/fx3/.gitignore3
-rw-r--r--firmware/fx3/README.md8
-rw-r--r--firmware/fx3/ad9361/include/ad9361_dispatch.h16
-rw-r--r--firmware/fx3/ad9361/include/ad9361_transaction.h90
-rw-r--r--firmware/fx3/ad9361/lib/ad9361_filter_taps.h47
-rw-r--r--firmware/fx3/ad9361/lib/ad9361_gain_tables.h95
-rw-r--r--firmware/fx3/ad9361/lib/ad9361_impl.c1918
-rw-r--r--firmware/fx3/ad9361/lib/ad9361_synth_lut.h135
-rw-r--r--firmware/fx3/b200/b200_ad9361.c57
-rw-r--r--firmware/fx3/b200/b200_main.c328
-rw-r--r--firmware/fx3/b200/b200_main.h9
-rw-r--r--firmware/fx3/b200/b200_vrq.h21
-rw-r--r--firmware/fx3/b200/makefile6
13 files changed, 9 insertions, 2724 deletions
diff --git a/firmware/fx3/.gitignore b/firmware/fx3/.gitignore
new file mode 100644
index 000000000..f2c372d44
--- /dev/null
+++ b/firmware/fx3/.gitignore
@@ -0,0 +1,3 @@
+common
+lpp_source
+u3p_firmware
diff --git a/firmware/fx3/README.md b/firmware/fx3/README.md
index e2e8a13d4..84a895059 100644
--- a/firmware/fx3/README.md
+++ b/firmware/fx3/README.md
@@ -9,16 +9,15 @@ show you how to build our firmware source
**A brief "Theory of Operations":**
The host sends commands to the FX3, our USB3 PHY, which has an on-board ARM
-which runs the FX3 firmware code (hex file). That code translates commands into
-SPI commands to/from the AD9361. The SPI lines run through the FPGA (bin or bit
-file), where they are level-translated, and then head to the AD9361. Note that
-the FPGA takes no action on these SPI lines. They are passive pass-throughs.
+which runs the FX3 firmware code (hex file). That code is responsible for
+managing the transport from the host to the FPGA by configuring IO and DMA.
## Setting up the Cypress SDK
In order to compile the USRP B200 and B210 firmware, you will need the FX3 SDK
distributed by the FX3 manufacturer, Cypress Semiconductor. You can download the
[FX3 SDK from here](http://www.cypress.com/?rID=57990).
+*Note*: You *must* use SDK version 1.2.3!
Once you have downloaded it, extract the ARM cross-compiler sub-directory from
the zip file and put it somewhere useful. The highest level directory you need
@@ -46,7 +45,6 @@ uhd.git/
|
--fx3/
|
- --ad9361/ # From UHD
--b200/ # From UHD
--common/ # From Cypress SDK
--gpif2_designer/ # From UHD
diff --git a/firmware/fx3/ad9361/include/ad9361_dispatch.h b/firmware/fx3/ad9361/include/ad9361_dispatch.h
deleted file mode 100644
index e89a4e0b0..000000000
--- a/firmware/fx3/ad9361/include/ad9361_dispatch.h
+++ /dev/null
@@ -1,16 +0,0 @@
-//
-// Copyright 2013-2014 Ettus Research LLC
-//
-
-#ifndef INCLUDED_AD9361_DISPATCH_H
-#define INCLUDED_AD9361_DISPATCH_H
-
-#include <ad9361_transaction.h>
-
-extern void ad9361_dispatch(const char* request, char* response);
-
-typedef void (*msgfn)(const char*, ...);
-
-extern void ad9361_set_msgfn(msgfn pfn);
-
-#endif /* INCLUDED_AD9361_DISPATCH_H */
diff --git a/firmware/fx3/ad9361/include/ad9361_transaction.h b/firmware/fx3/ad9361/include/ad9361_transaction.h
deleted file mode 100644
index 2349a5d3d..000000000
--- a/firmware/fx3/ad9361/include/ad9361_transaction.h
+++ /dev/null
@@ -1,90 +0,0 @@
-//
-// Copyright 2013-2014 Ettus Research LLC
-//
-
-#ifndef INCLUDED_AD9361_TRANSACTION_H
-#define INCLUDED_AD9361_TRANSACTION_H
-
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-//various constants
-#define AD9361_TRANSACTION_VERSION 0x4
-#define AD9361_DISPATCH_PACKET_SIZE 64
-
-//action types
-#define AD9361_ACTION_ECHO 0
-#define AD9361_ACTION_INIT 1
-#define AD9361_ACTION_SET_RX1_GAIN 2
-#define AD9361_ACTION_SET_TX1_GAIN 3
-#define AD9361_ACTION_SET_RX2_GAIN 4
-#define AD9361_ACTION_SET_TX2_GAIN 5
-#define AD9361_ACTION_SET_RX_FREQ 6
-#define AD9361_ACTION_SET_TX_FREQ 7
-#define AD9361_ACTION_SET_CODEC_LOOP 8
-#define AD9361_ACTION_SET_CLOCK_RATE 9
-#define AD9361_ACTION_SET_ACTIVE_CHAINS 10
-
-static inline void ad9361_double_pack(const double input, uint32_t output[2])
-{
- const uint32_t *p = (const uint32_t *)&input;
- output[0] = p[0];
- output[1] = p[1];
-}
-
-static inline double ad9361_double_unpack(const uint32_t input[2])
-{
- double output = 0.0;
- uint32_t *p = (uint32_t *)&output;
- p[0] = input[0];
- p[1] = input[1];
- return output;
-}
-
-typedef struct
-{
- //version is expected to be AD9361_TRANSACTION_VERSION
- //check otherwise for compatibility
- uint32_t version;
-
- //sequence number - increment every call for sanity
- uint32_t sequence;
-
- //action tells us what to do, see AD9361_ACTION_*
- uint32_t action;
-
- union
- {
- //enable mask for chains
- uint32_t enable_mask;
-
- //true to enable codec internal loopback
- uint32_t codec_loop;
-
- //freq holds request LO freq and result from tune
- uint32_t freq[2];
-
- //gain holds request gain and result from action
- uint32_t gain[2];
-
- //rate holds request clock rate and result from action
- uint32_t rate[2];
-
- } value;
-
- //error message comes back as a reply -
- //set to null string for no error \0
- char error_msg[];
-
-} ad9361_transaction_t;
-
-#define AD9361_TRANSACTION_MAX_ERROR_MSG (AD9361_DISPATCH_PACKET_SIZE - (sizeof(ad9361_transaction_t)-4)-1) // -4 for 'error_msg' alignment padding, -1 for terminating \0
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* INCLUDED_AD9361_TRANSACTION_H */
diff --git a/firmware/fx3/ad9361/lib/ad9361_filter_taps.h b/firmware/fx3/ad9361/lib/ad9361_filter_taps.h
deleted file mode 100644
index afbe27630..000000000
--- a/firmware/fx3/ad9361/lib/ad9361_filter_taps.h
+++ /dev/null
@@ -1,47 +0,0 @@
-//
-// Copyright 2013-2014 Ettus Research LLC
-//
-
-#ifndef INCLUDED_AD9361_FILTER_TAPS_HPP
-#define INCLUDED_AD9361_FILTER_TAPS_HPP
-
-/* A default 128-tap filter that can be used for generic circumstances. */
-static uint16_t default_128tap_coeffs[] = {
- 0x0001,0xfff1,0xffcf,0xffc0,0xffe8,0x0020,0x001a,0xffe3,
- 0xffe1,0x001f,0x0028,0xffdf,0xffcc,0x0024,0x0043,0xffdb,
- 0xffac,0x0026,0x0068,0xffdb,0xff80,0x0022,0x009a,0xffe2,
- 0xff47,0x0017,0x00db,0xfff3,0xfeff,0xffff,0x012b,0x0013,
- 0xfea5,0xffd7,0x0190,0x0046,0xfe35,0xff97,0x020e,0x0095,
- 0xfda7,0xff36,0x02ae,0x010d,0xfcf0,0xfea1,0x0383,0x01c6,
- 0xfbf3,0xfdb6,0x04b7,0x02f8,0xfa6d,0xfc1a,0x06be,0x0541,
- 0xf787,0xf898,0x0b60,0x0b6d,0xee88,0xea40,0x2786,0x7209
-};
-
-
-/* The below pair of filters is optimized for a 10MHz LTE application. */
-/*
-static uint16_t lte10mhz_rx_coeffs[] = {
- 0xffe2,0x0042,0x0024,0x0095,0x0056,0x004d,0xffcf,0xffb7,
- 0xffb1,0x0019,0x0059,0x006a,0x0004,0xff9d,0xff72,0xffd4,
- 0x0063,0x00b7,0x0062,0xffac,0xff21,0xff59,0x0032,0x0101,
- 0x00f8,0x0008,0xfeea,0xfeac,0xffa3,0x0117,0x01b5,0x00d0,
- 0xff05,0xfdea,0xfe9e,0x00ba,0x026f,0x0215,0xffb5,0xfd4a,
- 0xfd18,0xffa0,0x02de,0x03dc,0x0155,0xfd2a,0xfb0d,0xfd54,
- 0x0287,0x062f,0x048a,0xfe37,0xf862,0xf8c1,0x004d,0x0963,
- 0x0b88,0x02a4,0xf3e7,0xebdd,0xf5f8,0x1366,0x3830,0x518b
-};
-
-static uint16_t lte10mhz_tx_coeffs[] = {
- 0xfffb,0x0000,0x0004,0x0017,0x0024,0x0028,0x0013,0xfff3,
- 0xffdc,0xffe5,0x000b,0x0030,0x002e,0xfffe,0xffc4,0xffb8,
- 0xfff0,0x0045,0x0068,0x002b,0xffb6,0xff72,0xffad,0x0047,
- 0x00b8,0x0088,0xffc8,0xff1c,0xff33,0x001a,0x0110,0x0124,
- 0x0019,0xfec8,0xfe74,0xff9a,0x0156,0x0208,0x00d3,0xfe9b,
- 0xfd68,0xfe96,0x015d,0x033f,0x0236,0xfecd,0xfc00,0xfcb5,
- 0x00d7,0x04e5,0x04cc,0xffd5,0xf9fe,0xf8fb,0xfef2,0x078c,
- 0x0aae,0x036d,0xf5c0,0xed89,0xf685,0x12af,0x36a4,0x4faa
-};
-*/
-
-
-#endif // INCLUDED_AD9361_FILTER_TAPS_HPP
diff --git a/firmware/fx3/ad9361/lib/ad9361_gain_tables.h b/firmware/fx3/ad9361/lib/ad9361_gain_tables.h
deleted file mode 100644
index 58dcbeb65..000000000
--- a/firmware/fx3/ad9361/lib/ad9361_gain_tables.h
+++ /dev/null
@@ -1,95 +0,0 @@
-//
-// Copyright 2013-2014 Ettus Research LLC
-//
-
-#ifndef INCLUDED_AD9361_GAIN_TABLES_HPP
-#define INCLUDED_AD9361_GAIN_TABLES_HPP
-
-uint8_t gain_table_sub_1300mhz[77][5] = { {0,0x00,0x00,0x20,1},
- {1,0x00,0x00,0x00,0}, {2,0x00,0x00,0x00,0}, {3,0x00,0x01,0x00,0},
- {4,0x00,0x02,0x00,0}, {5,0x00,0x03,0x00,0}, {6,0x00,0x04,0x00,0},
- {7,0x00,0x05,0x00,0}, {8,0x01,0x03,0x20,1}, {9,0x01,0x04,0x00,0},
- {10,0x01,0x05,0x00,0}, {11,0x01,0x06,0x00,0}, {12,0x01,0x07,0x00,0},
- {13,0x01,0x08,0x00,0}, {14,0x01,0x09,0x00,0}, {15,0x01,0x0A,0x00,0},
- {16,0x01,0x0B,0x00,0}, {17,0x01,0x0C,0x00,0}, {18,0x01,0x0D,0x00,0},
- {19,0x01,0x0E,0x00,0}, {20,0x02,0x09,0x20,1}, {21,0x02,0x0A,0x00,0},
- {22,0x02,0x0B,0x00,0}, {23,0x02,0x0C,0x00,0}, {24,0x02,0x0D,0x00,0},
- {25,0x02,0x0E,0x00,0}, {26,0x02,0x0F,0x00,0}, {27,0x02,0x10,0x00,0},
- {28,0x02,0x2B,0x20,1}, {29,0x02,0x2C,0x00,0}, {30,0x04,0x27,0x20,1},
- {31,0x04,0x28,0x00,0}, {32,0x04,0x29,0x00,0}, {33,0x04,0x2A,0x00,0},
- {34,0x04,0x2B,0x00,1}, {35,0x24,0x21,0x20,0}, {36,0x24,0x22,0x00,1},
- {37,0x44,0x20,0x20,0}, {38,0x44,0x21,0x00,0}, {39,0x44,0x22,0x00,0},
- {40,0x44,0x23,0x00,0}, {41,0x44,0x24,0x00,0}, {42,0x44,0x25,0x00,0},
- {43,0x44,0x26,0x00,0}, {44,0x44,0x27,0x00,0}, {45,0x44,0x28,0x00,0},
- {46,0x44,0x29,0x00,0}, {47,0x44,0x2A,0x00,0}, {48,0x44,0x2B,0x00,0},
- {49,0x44,0x2C,0x00,0}, {50,0x44,0x2D,0x00,0}, {51,0x44,0x2E,0x00,0},
- {52,0x44,0x2F,0x00,0}, {53,0x44,0x30,0x00,0}, {54,0x44,0x31,0x00,0},
- {55,0x64,0x2E,0x20,1}, {56,0x64,0x2F,0x00,0}, {57,0x64,0x30,0x00,0},
- {58,0x64,0x31,0x00,0}, {59,0x64,0x32,0x00,0}, {60,0x64,0x33,0x00,0},
- {61,0x64,0x34,0x00,0}, {62,0x64,0x35,0x00,0}, {63,0x64,0x36,0x00,0},
- {64,0x64,0x37,0x00,0}, {65,0x64,0x38,0x00,0}, {66,0x65,0x38,0x20,1},
- {67,0x66,0x38,0x20,1}, {68,0x67,0x38,0x20,1}, {69,0x68,0x38,0x20,1},
- {70,0x69,0x38,0x20,1}, {71,0x6A,0x38,0x20,1}, {72,0x6B,0x38,0x20,1},
- {73,0x6C,0x38,0x20,1}, {74,0x6D,0x38,0x20,1}, {75,0x6E,0x38,0x20,1},
- {76,0x6F,0x38,0x20,1}};
-
-
-uint8_t gain_table_1300mhz_to_4000mhz[77][5] = { {0,0x00,0x00,0x20,1},
- {1,0x00,0x00,0x00,0}, {2,0x00,0x00,0x00,0}, {3,0x00,0x01,0x00,0},
- {4,0x00,0x02,0x00,0}, {5,0x00,0x03,0x00,0}, {6,0x00,0x04,0x00,0},
- {7,0x00,0x05,0x00,0}, {8,0x01,0x03,0x20,1}, {9,0x01,0x04,0x00,0},
- {10,0x01,0x05,0x00,0}, {11,0x01,0x06,0x00,0}, {12,0x01,0x07,0x00,0},
- {13,0x01,0x08,0x00,0}, {14,0x01,0x09,0x00,0}, {15,0x01,0x0A,0x00,0},
- {16,0x01,0x0B,0x00,0}, {17,0x01,0x0C,0x00,0}, {18,0x01,0x0D,0x00,0},
- {19,0x01,0x0E,0x00,0}, {20,0x02,0x09,0x20,1}, {21,0x02,0x0A,0x00,0},
- {22,0x02,0x0B,0x00,0}, {23,0x02,0x0C,0x00,0}, {24,0x02,0x0D,0x00,0},
- {25,0x02,0x0E,0x00,0}, {26,0x02,0x0F,0x00,0}, {27,0x02,0x10,0x00,0},
- {28,0x02,0x2B,0x20,1}, {29,0x02,0x2C,0x00,0}, {30,0x04,0x28,0x20,1},
- {31,0x04,0x29,0x00,0}, {32,0x04,0x2A,0x00,0}, {33,0x04,0x2B,0x00,0},
- {34,0x24,0x20,0x20,0}, {35,0x24,0x21,0x00,1}, {36,0x44,0x20,0x20,0},
- {37,0x44,0x21,0x00,1}, {38,0x44,0x22,0x00,0}, {39,0x44,0x23,0x00,0},
- {40,0x44,0x24,0x00,0}, {41,0x44,0x25,0x00,0}, {42,0x44,0x26,0x00,0},
- {43,0x44,0x27,0x00,0}, {44,0x44,0x28,0x00,0}, {45,0x44,0x29,0x00,0},
- {46,0x44,0x2A,0x00,0}, {47,0x44,0x2B,0x00,0}, {48,0x44,0x2C,0x00,0},
- {49,0x44,0x2D,0x00,0}, {50,0x44,0x2E,0x00,0}, {51,0x44,0x2F,0x00,0},
- {52,0x44,0x30,0x00,0}, {53,0x44,0x31,0x00,0}, {54,0x44,0x32,0x00,0},
- {55,0x64,0x2E,0x20,1}, {56,0x64,0x2F,0x00,0}, {57,0x64,0x30,0x00,0},
- {58,0x64,0x31,0x00,0}, {59,0x64,0x32,0x00,0}, {60,0x64,0x33,0x00,0},
- {61,0x64,0x34,0x00,0}, {62,0x64,0x35,0x00,0}, {63,0x64,0x36,0x00,0},
- {64,0x64,0x37,0x00,0}, {65,0x64,0x38,0x00,0}, {66,0x65,0x38,0x20,1},
- {67,0x66,0x38,0x20,1}, {68,0x67,0x38,0x20,1}, {69,0x68,0x38,0x20,1},
- {70,0x69,0x38,0x20,1}, {71,0x6A,0x38,0x20,1}, {72,0x6B,0x38,0x20,1},
- {73,0x6C,0x38,0x20,1}, {74,0x6D,0x38,0x20,1}, {75,0x6E,0x38,0x20,1},
- {76,0x6F,0x38,0x20,1}};
-
-
-uint8_t gain_table_4000mhz_to_6000mhz[77][5] = { {0,0x00,0x00,0x20,1},
- {1,0x00,0x00,0x00,0}, {2,0x00,0x00,0x00,0}, {3,0x00,0x00,0x00,0},
- {4,0x00,0x00,0x00,0}, {5,0x00,0x01,0x00,0}, {6,0x00,0x02,0x00,0},
- {7,0x00,0x03,0x00,0}, {8,0x01,0x01,0x20,1}, {9,0x01,0x02,0x00,0},
- {10,0x01,0x03,0x00,0}, {11,0x01,0x04,0x20,1}, {12,0x01,0x05,0x00,0},
- {13,0x01,0x06,0x00,0}, {14,0x01,0x07,0x00,0}, {15,0x01,0x08,0x00,0},
- {16,0x01,0x09,0x00,0}, {17,0x01,0x0A,0x00,0}, {18,0x01,0x0B,0x00,0},
- {19,0x01,0x0C,0x00,0}, {20,0x02,0x08,0x20,1}, {21,0x02,0x09,0x00,0},
- {22,0x02,0x0A,0x00,0}, {23,0x02,0x0B,0x20,1}, {24,0x02,0x0C,0x00,0},
- {25,0x02,0x0D,0x00,0}, {26,0x02,0x0E,0x00,0}, {27,0x02,0x0F,0x00,0},
- {28,0x02,0x2A,0x20,1}, {29,0x02,0x2B,0x00,0}, {30,0x04,0x27,0x20,1},
- {31,0x04,0x28,0x00,0}, {32,0x04,0x29,0x00,0}, {33,0x04,0x2A,0x00,0},
- {34,0x04,0x2B,0x00,0}, {35,0x04,0x2C,0x00,0}, {36,0x04,0x2D,0x00,0},
- {37,0x24,0x20,0x20,1}, {38,0x24,0x21,0x00,0}, {39,0x24,0x22,0x00,0},
- {40,0x44,0x20,0x20,1}, {41,0x44,0x21,0x00,0}, {42,0x44,0x22,0x00,0},
- {43,0x44,0x23,0x00,0}, {44,0x44,0x24,0x00,0}, {45,0x44,0x25,0x00,0},
- {46,0x44,0x26,0x00,0}, {47,0x44,0x27,0x00,0}, {48,0x44,0x28,0x00,0},
- {49,0x44,0x29,0x00,0}, {50,0x44,0x2A,0x00,0}, {51,0x44,0x2B,0x00,0},
- {52,0x44,0x2C,0x00,0}, {53,0x44,0x2D,0x00,0}, {54,0x44,0x2E,0x00,0},
- {55,0x64,0x2E,0x20,1}, {56,0x64,0x2F,0x00,0}, {57,0x64,0x30,0x00,0},
- {58,0x64,0x31,0x00,0}, {59,0x64,0x32,0x00,0}, {60,0x64,0x33,0x00,0},
- {61,0x64,0x34,0x00,0}, {62,0x64,0x35,0x00,0}, {63,0x64,0x36,0x00,0},
- {64,0x64,0x37,0x00,0}, {65,0x64,0x38,0x00,0}, {66,0x65,0x38,0x20,1},
- {67,0x66,0x38,0x20,1}, {68,0x67,0x38,0x20,1}, {69,0x68,0x38,0x20,1},
- {70,0x69,0x38,0x20,1}, {71,0x6A,0x38,0x20,1}, {72,0x6B,0x38,0x20,1},
- {73,0x6C,0x38,0x20,1}, {74,0x6D,0x38,0x20,1}, {75,0x6E,0x38,0x20,1},
- {76,0x6F,0x38,0x20,1}};
-
-
-#endif /* INCLUDED_AD9361_GAIN_TABLES_HPP */
diff --git a/firmware/fx3/ad9361/lib/ad9361_impl.c b/firmware/fx3/ad9361/lib/ad9361_impl.c
deleted file mode 100644
index 61512d2c8..000000000
--- a/firmware/fx3/ad9361/lib/ad9361_impl.c
+++ /dev/null
@@ -1,1918 +0,0 @@
-//
-// Copyright 2013-2014 Ettus Research LLC
-//
-
-/* This file implements b200 vendor requests handler
- * It handles ad9361 setup and configuration
- */
-
-#include <stdarg.h>
-#include <stdio.h>
-#include <math.h>
-
-#include <ad9361_transaction.h>
-#include "ad9361_filter_taps.h"
-#include "ad9361_gain_tables.h"
-#include "ad9361_synth_lut.h"
-#include "ad9361_dispatch.h"
-
-////////////////////////////////////////////////////////////
-
-static void fake_msg(const char* str, ...)
-{
-}
-
-static msgfn _msgfn = fake_msg;
-
-//extern void msg(const char* str, ...); External object must provide this symbol
-#define msg (_msgfn)
-
-void ad9361_set_msgfn(msgfn pfn)
-{
- _msgfn = pfn;
-}
-
-////////////////////////////////////////////////////////////
-#define AD9361_MAX_GAIN 89.75
-
-#define DOUBLE_PI 3.14159265359
-#define DOUBLE_LN_2 0.693147181
-
-#define RX_TYPE 0
-#define TX_TYPE 1
-
-#ifndef AD9361_CLOCKING_MODE
-#error define a AD9361_CLOCKING_MODE
-#endif
-
-#ifndef AD9361_RX_BAND_EDGE0
-#error define a AD9361_RX_BAND_EDGE0
-#endif
-
-#ifndef AD9361_RX_BAND_EDGE1
-#error define a AD9361_RX_BAND_EDGE1
-#endif
-
-#ifndef AD9361_TX_BAND_EDGE
-#error define a AD9361_TX_BAND_EDGE
-#endif
-
-////////////////////////////////////////////////////////////
-// the following macros evaluate to a compile time constant
-// macros By Tom Torfs - donated to the public domain
-
-/* turn a numeric literal into a hex constant
-(avoids problems with leading zeroes)
-8-bit constants max value 0x11111111, always fits in unsigned long
-*/
-#define HEX__(n) 0x##n##LU
-
-/* 8-bit conversion function */
-#define B8__(x) ((x&0x0000000FLU)?1:0) \
-+((x&0x000000F0LU)?2:0) \
-+((x&0x00000F00LU)?4:0) \
-+((x&0x0000F000LU)?8:0) \
-+((x&0x000F0000LU)?16:0) \
-+((x&0x00F00000LU)?32:0) \
-+((x&0x0F000000LU)?64:0) \
-+((x&0xF0000000LU)?128:0)
-
-/* *** user macros *** */
-
-/* for upto 8-bit binary constants */
-#define B8(d) ((unsigned char)B8__(HEX__(d)))
-
-////////////////////////////////////////////////////////////
-// shadow registers
-static uint8_t reg_vcodivs;
-static uint8_t reg_inputsel;
-static uint8_t reg_rxfilt;
-static uint8_t reg_txfilt;
-static uint8_t reg_bbpll;
-static uint8_t reg_bbftune_config;
-static uint8_t reg_bbftune_mode;
-
-////////////////////////////////////////////////////////////
-// other private data fields for VRQ handler
-static double _rx_freq, _tx_freq, _req_rx_freq, _req_tx_freq;
-static double _baseband_bw, _bbpll_freq, _adcclock_freq;
-static double _req_clock_rate, _req_coreclk;
-static uint16_t _rx_bbf_tunediv;
-static uint8_t _curr_gain_table;
-static uint32_t _rx1_gain, _rx2_gain, _tx1_gain, _tx2_gain;
-static int _tfir_factor;
-
-double set_gain(int which, int n, const double value);
-void set_active_chains(bool tx1, bool tx2, bool rx1, bool rx2);
-/***********************************************************************
- * Placeholders, unused, or test functions
- **********************************************************************/
-static char *tmp_req_buffer;
-
-void post_err_msg(const char* error)
-{
- msg("[AD9361 error] %s", error);
-
- if (!tmp_req_buffer)
- return;
-
- ad9361_transaction_t *request = (ad9361_transaction_t *)tmp_req_buffer;
- strncpy(request->error_msg, error, (AD9361_TRANSACTION_MAX_ERROR_MSG + 1)); // '+ 1' as length excludes terminating NUL
- request->error_msg[AD9361_TRANSACTION_MAX_ERROR_MSG] = '\0'; // If string was too long, NUL will not be copied, so force one just in case
-}
-
-void write_ad9361_reg(uint32_t reg, uint8_t val)
-{
- ad9361_transact_spi((reg << 8) | val | (1 << 23));
-}
-
-uint8_t read_ad9361_reg(uint32_t reg)
-{
- return ad9361_transact_spi((reg << 8)) & 0xff;
-}
-
-//shortcuts for double packer/unpacker function
-#define double_pack ad9361_double_pack
-#define double_unpack ad9361_double_unpack
-
-/* Make Catalina output its test tone. */
-void output_test_tone(void) {
- /* Output a 480 kHz tone at 800 MHz */
- write_ad9361_reg(0x3F4, 0x0B);
- write_ad9361_reg(0x3FC, 0xFF);
- write_ad9361_reg(0x3FD, 0xFF);
- write_ad9361_reg(0x3FE, 0x3F);
-}
-
-/* Turn on/off Catalina's TX port --> RX port loopback. */
-void data_port_loopback(const int on) {
- msg("[data_port_loopback] Enabled: %d", on);
- write_ad9361_reg(0x3F5, (on ? 0x01 : 0x00));
-}
-
-/* This is a simple comparison for very large double-precision floating
- * point numbers. It is used to prevent re-tunes for frequencies that are
- * the same but not 'exactly' because of data precision issues. */
-// TODO: see if we can avoid the need for this function
-int freq_is_nearly_equal(double a, double b) {
- return AD9361_MAX(a,b) - AD9361_MIN(a,b) < 1;
-}
-
-/***********************************************************************
- * Filter functions
- **********************************************************************/
-
-/* This function takes in the calculated maximum number of FIR taps, and
- * returns a number of taps that makes Catalina happy. */
-int get_num_taps(int max_num_taps) {
-
- int num_taps = 0;
- int num_taps_list[] = {16, 32, 48, 64, 80, 96, 112, 128};
- int i;
- for(i = 1; i < 8; i++) {
- if(max_num_taps >= num_taps_list[i]) {
- continue;
- } else {
- num_taps = num_taps_list[i - 1];
- break;
- }
- } if(num_taps == 0) { num_taps = 128; }
-
- return num_taps;
-}
-
-/* Program either the RX or TX FIR filter.
- *
- * The process is the same for both filters, but the function must be told
- * how many taps are in the filter, and given a vector of the taps
- * themselves. Note that the filters are symmetric, so value of 'num_taps'
- * should actually be twice the length of the tap vector. */
-void program_fir_filter(int which, int num_taps, \
- uint16_t *coeffs) {
-
- uint16_t base;
- if(which == RX_TYPE) {
- base = 0x0f0;
- write_ad9361_reg(base+6, 0x02); //filter gain
- } else {
- base = 0x060;
- }
-
- /* Write the filter configuration. */
- uint8_t reg_numtaps = (((num_taps / 16) - 1) & 0x07) << 5;
-
- /* Turn on the filter clock. */
- write_ad9361_reg(base+5, reg_numtaps | 0x1a);
- ad9361_msleep(1);
-
- int num_unique_coeffs = (num_taps / 2);
-
- /* The filters are symmetric, so iterate over the tap vector,
- * programming each index, and then iterate backwards, repeating the
- * process. */
- int addr;
- for(addr=0; addr < num_unique_coeffs; addr++) {
- write_ad9361_reg(base+0, addr);
- write_ad9361_reg(base+1, (coeffs[addr]) & 0xff);
- write_ad9361_reg(base+2, (coeffs[addr] >> 8) & 0xff);
- write_ad9361_reg(base+5, 0xfe);
- write_ad9361_reg(base+4, 0x00);
- write_ad9361_reg(base+4, 0x00);
- }
-
- for(addr=0; addr < num_unique_coeffs; addr++) {
- write_ad9361_reg(base+0, addr+num_unique_coeffs);
- write_ad9361_reg(base+1, (coeffs[num_unique_coeffs-1-addr]) & 0xff);
- write_ad9361_reg(base+2, (coeffs[num_unique_coeffs-1-addr] >> 8) & 0xff);
- write_ad9361_reg(base+5, 0xfe);
- write_ad9361_reg(base+4, 0x00);
- write_ad9361_reg(base+4, 0x00);
- }
-
- /* Disable the filter clock. */
- write_ad9361_reg(base+5, 0xf8);
-}
-
-/* Program the RX FIR Filter. */
-void setup_rx_fir(int total_num_taps) {
- int num_taps = total_num_taps / 2;
- uint16_t coeffs[num_taps];
- int i;
- for(i = 0; i < num_taps; i++) {
- coeffs[num_taps - 1 - i] = default_128tap_coeffs[63 - i];
- }
-
- program_fir_filter(RX_TYPE, total_num_taps, coeffs);
-}
-
-/* Program the TX FIR Filter. */
-void setup_tx_fir(int total_num_taps) {
- int num_taps = total_num_taps / 2;
- uint16_t coeffs[num_taps];
- int i;
- for(i = 0; i < num_taps; i++) {
- coeffs[num_taps - 1 - i] = default_128tap_coeffs[63 - i];
- }
-
- program_fir_filter(TX_TYPE, total_num_taps, coeffs);
-}
-
-/***********************************************************************
- * Calibration functions
- ***********************************************************************/
-
-/* Calibrate and lock the BBPLL.
- *
- * This function should be called anytime the BBPLL is tuned. */
-void calibrate_lock_bbpll() {
- write_ad9361_reg(0x03F, 0x05); // Start the BBPLL calibration
- write_ad9361_reg(0x03F, 0x01); // Clear the 'start' bit
-
- /* Increase BBPLL KV and phase margin. */
- write_ad9361_reg(0x04c, 0x86);
- write_ad9361_reg(0x04d, 0x01);
- write_ad9361_reg(0x04d, 0x05);
-
- /* Wait for BBPLL lock. */
- int count = 0;
- while(!(read_ad9361_reg(0x05e) & 0x80)) {
- if(count > 1000) {
- post_err_msg("BBPLL not locked");
- break;
- }
-
- count++;
- ad9361_msleep(2);
- }
-}
-
-/* Calibrate the synthesizer charge pumps.
- *
- * Technically, this calibration only needs to be done once, at device
- * initialization. */
-void calibrate_synth_charge_pumps() {
- /* If this function ever gets called, and the ENSM isn't already in the
- * ALERT state, then something has gone horribly wrong. */
- if((read_ad9361_reg(0x017) & 0x0F) != 5) {
- post_err_msg("Catalina not in ALERT during cal");
- }
-
- /* Calibrate the RX synthesizer charge pump. */
- int count = 0;
- write_ad9361_reg(0x23d, 0x04);
- while(!(read_ad9361_reg(0x244) & 0x80)) {
- if(count > 5) {
- post_err_msg("RX charge pump cal failure");
- break;
- }
-
- count++;
- ad9361_msleep(1);
- }
- write_ad9361_reg(0x23d, 0x00);
-
- /* Calibrate the TX synthesizer charge pump. */
- count = 0;
- write_ad9361_reg(0x27d, 0x04);
- while(!(read_ad9361_reg(0x284) & 0x80)) {
- if(count > 5) {
- post_err_msg("TX charge pump cal failure");
- break;
- }
-
- count++;
- ad9361_msleep(1);
- }
- write_ad9361_reg(0x27d, 0x00);
-}
-
-/* Calibrate the analog BB RX filter.
- *
- * Note that the filter calibration depends heavily on the baseband
- * bandwidth, so this must be re-done after any change to the RX sample
- * rate. */
-double calibrate_baseband_rx_analog_filter() {
- /* For filter tuning, baseband BW is half the complex BW, and must be
- * between 28e6 and 0.2e6. */
- double bbbw = _baseband_bw / 2.0;
- if(bbbw > 28e6) {
- bbbw = 28e6;
- } else if (bbbw < 0.20e6) {
- bbbw = 0.20e6;
- }
-
- double rxtune_clk = ((1.4 * bbbw * 2 *
- DOUBLE_PI) / DOUBLE_LN_2);
-
- _rx_bbf_tunediv = AD9361_MIN(511, AD9361_CEIL_INT(_bbpll_freq / rxtune_clk));
-
- reg_bbftune_config = (reg_bbftune_config & 0xFE) \
- | ((_rx_bbf_tunediv >> 8) & 0x0001);
-
- double bbbw_mhz = bbbw / 1e6;
-
- double temp = ((bbbw_mhz - AD9361_FLOOR_INT(bbbw_mhz)) * 1000) / 7.8125;
- uint8_t bbbw_khz = (uint8_t) AD9361_MIN(127, (AD9361_FLOOR_INT(temp + 0.5)));
-
- /* Set corner frequencies and dividers. */
- write_ad9361_reg(0x1fb, (uint8_t)(bbbw_mhz));
- write_ad9361_reg(0x1fc, bbbw_khz);
- write_ad9361_reg(0x1f8, (_rx_bbf_tunediv & 0x00FF));
- write_ad9361_reg(0x1f9, reg_bbftune_config);
-
- /* RX Mix Voltage settings - only change with apps engineer help. */
- write_ad9361_reg(0x1d5, 0x3f);
- write_ad9361_reg(0x1c0, 0x03);
-
- /* Enable RX1 & RX2 filter tuners. */
- write_ad9361_reg(0x1e2, 0x02);
- write_ad9361_reg(0x1e3, 0x02);
-
- /* Run the calibration! */
- int count = 0;
- write_ad9361_reg(0x016, 0x80);
- while(read_ad9361_reg(0x016) & 0x80) {
- if(count > 100) {
- post_err_msg("RX baseband filter cal FAILURE");
- break;
- }
-
- count++;
- ad9361_msleep(1);
- }
-
- /* Disable RX1 & RX2 filter tuners. */
- write_ad9361_reg(0x1e2, 0x03);
- write_ad9361_reg(0x1e3, 0x03);
-
- return bbbw;
-}
-
-/* Calibrate the analog BB TX filter.
- *
- * Note that the filter calibration depends heavily on the baseband
- * bandwidth, so this must be re-done after any change to the TX sample
- * rate. */
-double calibrate_baseband_tx_analog_filter() {
- /* For filter tuning, baseband BW is half the complex BW, and must be
- * between 28e6 and 0.2e6. */
- double bbbw = _baseband_bw / 2.0;
- if(bbbw > 20e6) {
- bbbw = 20e6;
- } else if (bbbw < 0.625e6) {
- bbbw = 0.625e6;
- }
-
- double txtune_clk = ((1.6 * bbbw * 2 *
- DOUBLE_PI) / DOUBLE_LN_2);
-
- uint16_t txbbfdiv = AD9361_MIN(511, (AD9361_CEIL_INT(_bbpll_freq / txtune_clk)));
-
- reg_bbftune_mode = (reg_bbftune_mode & 0xFE) \
- | ((txbbfdiv >> 8) & 0x0001);
-
- /* Program the divider values. */
- write_ad9361_reg(0x0d6, (txbbfdiv & 0x00FF));
- write_ad9361_reg(0x0d7, reg_bbftune_mode);
-
- /* Enable the filter tuner. */
- write_ad9361_reg(0x0ca, 0x22);
-
- /* Calibrate! */
- int count = 0;
- write_ad9361_reg(0x016, 0x40);
- while(read_ad9361_reg(0x016) & 0x40) {
- if(count > 100) {
- post_err_msg("TX baseband filter cal FAILURE");
- break;
- }
-
- count++;
- ad9361_msleep(1);
- }
-
- /* Disable the filter tuner. */
- write_ad9361_reg(0x0ca, 0x26);
-
- return bbbw;
-}
-
-/* Calibrate the secondary TX filter.
- *
- * This filter also depends on the TX sample rate, so if a rate change is
- * made, the previous calibration will no longer be valid. */
-void calibrate_secondary_tx_filter() {
- /* For filter tuning, baseband BW is half the complex BW, and must be
- * between 20e6 and 0.53e6. */
- double bbbw = _baseband_bw / 2.0;
- if(bbbw > 20e6) {
- bbbw = 20e6;
- } else if (bbbw < 0.53e6) {
- bbbw = 0.53e6;
- }
-
- double bbbw_mhz = bbbw / 1e6;
-
- /* Start with a resistor value of 100 Ohms. */
- int res = 100;
-
- /* Calculate target corner frequency. */
- double corner_freq = 5 * bbbw_mhz * 2 * DOUBLE_PI;
-
- /* Iterate through RC values to determine correct combination. */
- int cap = 0;
- int i;
- for(i = 0; i <= 3; i++) {
- cap = (AD9361_FLOOR_INT(0.5 + (( 1 / ((corner_freq * res) * 1e6)) * 1e12))) - 12;
-
- if(cap <= 63) {
- break;
- }
-
- res = res * 2;
- }
- if(cap > 63) {
- cap = 63;
- }
-
- uint8_t reg0d0, reg0d1, reg0d2;
-
- /* Translate baseband bandwidths to register settings. */
- if((bbbw_mhz * 2) <= 9) {
- reg0d0 = 0x59;
- } else if(((bbbw_mhz * 2) > 9) && ((bbbw_mhz * 2) <= 24)) {
- reg0d0 = 0x56;
- } else if((bbbw_mhz * 2) > 24) {
- reg0d0 = 0x57;
- } else {
- post_err_msg("Cal2ndTxFil: INVALID_CODE_PATH bad bbbw_mhz");
- reg0d0 = 0x00;
- }
-
- /* Translate resistor values to register settings. */
- if(res == 100) {
- reg0d1 = 0x0c;
- } else if(res == 200) {
- reg0d1 = 0x04;
- } else if(res == 400) {
- reg0d1 = 0x03;
- } else if(res == 800) {
- reg0d1 = 0x01;
- } else {
- reg0d1 = 0x0c;
- }
-
- reg0d2 = cap;
-
- /* Program the above-calculated values. Sweet. */
- write_ad9361_reg(0x0d2, reg0d2);
- write_ad9361_reg(0x0d1, reg0d1);
- write_ad9361_reg(0x0d0, reg0d0);
-}
-
-/* Calibrate the RX TIAs.
- *
- * Note that the values in the TIA register, after calibration, vary with
- * the RX gain settings. */
-void calibrate_rx_TIAs() {
-
- uint8_t reg1eb = read_ad9361_reg(0x1eb) & 0x3F;
- uint8_t reg1ec = read_ad9361_reg(0x1ec) & 0x7F;
- uint8_t reg1e6 = read_ad9361_reg(0x1e6) & 0x07;
- uint8_t reg1db = 0x00;
- uint8_t reg1dc = 0x00;
- uint8_t reg1dd = 0x00;
- uint8_t reg1de = 0x00;
- uint8_t reg1df = 0x00;
-
- /* For calibration, baseband BW is half the complex BW, and must be
- * between 28e6 and 0.2e6. */
- double bbbw = _baseband_bw / 2.0;
- if(bbbw > 20e6) {
- bbbw = 20e6;
- } else if (bbbw < 0.20e6) {
- bbbw = 0.20e6;
- }
- double ceil_bbbw_mhz = AD9361_CEIL_INT(bbbw / 1e6);
-
- /* Do some crazy resistor and capacitor math. */
- int Cbbf = (reg1eb * 160) + (reg1ec * 10) + 140;
- int R2346 = 18300 * (reg1e6 & 0x07);
- double CTIA_fF = (Cbbf * R2346 * 0.56) / 3500;
-
- /* Translate baseband BW to register settings. */
- if(ceil_bbbw_mhz <= 3) {
- reg1db = 0xe0;
- } else if((ceil_bbbw_mhz > 3) && (ceil_bbbw_mhz <= 10)) {
- reg1db = 0x60;
- } else if(ceil_bbbw_mhz > 10) {
- reg1db = 0x20;
- } else {
- post_err_msg("CalRxTias: INVALID_CODE_PATH bad bbbw_mhz");
- }
-
- if(CTIA_fF > 2920) {
- reg1dc = 0x40;
- reg1de = 0x40;
-
- uint8_t temp = (uint8_t) AD9361_MIN(127, (AD9361_FLOOR_INT(0.5 + ((CTIA_fF - 400.0) / 320.0))));
- reg1dd = temp;
- reg1df = temp;
- } else {
- uint8_t temp = (uint8_t) AD9361_FLOOR_INT(0.5 + ((CTIA_fF - 400.0) / 40.0)) + 0x40;
- reg1dc = temp;
- reg1de = temp;
- reg1dd = 0;
- reg1df = 0;
- }
-
- /* w00t. Settings calculated. Program them and roll out. */
- write_ad9361_reg(0x1db, reg1db);
- write_ad9361_reg(0x1dd, reg1dd);
- write_ad9361_reg(0x1df, reg1df);
- write_ad9361_reg(0x1dc, reg1dc);
- write_ad9361_reg(0x1de, reg1de);
-}
-
-/* Setup the Catalina ADC.
- *
- * There are 40 registers that control the ADC's operation, most of the
- * values of which must be derived mathematically, dependent on the current
- * setting of the BBPLL. Note that the order of calculation is critical, as
- * some of the 40 registers depend on the values in others. */
-void setup_adc() {
- double bbbw_mhz = (((_bbpll_freq / 1e6) / _rx_bbf_tunediv) * DOUBLE_LN_2) \
- / (1.4 * 2 * DOUBLE_PI);
-
- /* For calibration, baseband BW is half the complex BW, and must be
- * between 28e6 and 0.2e6. */
- if(bbbw_mhz > 28) {
- bbbw_mhz = 28;
- } else if (bbbw_mhz < 0.20) {
- bbbw_mhz = 0.20;
- }
-
- uint8_t rxbbf_c3_msb = read_ad9361_reg(0x1eb) & 0x3F;
- uint8_t rxbbf_c3_lsb = read_ad9361_reg(0x1ec) & 0x7F;
- uint8_t rxbbf_r2346 = read_ad9361_reg(0x1e6) & 0x07;
-
- double fsadc = _adcclock_freq / 1e6;
-
- /* Sort out the RC time constant for our baseband bandwidth... */
- double rc_timeconst = 0.0;
- if(bbbw_mhz < 18) {
- rc_timeconst = (1 / ((1.4 * 2 * DOUBLE_PI) \
- * (18300 * rxbbf_r2346)
- * ((160e-15 * rxbbf_c3_msb)
- + (10e-15 * rxbbf_c3_lsb) + 140e-15)
- * (bbbw_mhz * 1e6)));
- } else {
- rc_timeconst = (1 / ((1.4 * 2 * DOUBLE_PI) \
- * (18300 * rxbbf_r2346)
- * ((160e-15 * rxbbf_c3_msb)
- + (10e-15 * rxbbf_c3_lsb) + 140e-15)
- * (bbbw_mhz * 1e6) * (1 + (0.01 * (bbbw_mhz - 18)))));
- }
-
- double scale_res = ad9361_sqrt(1 / rc_timeconst);
- double scale_cap = ad9361_sqrt(1 / rc_timeconst);
-
- double scale_snr = (_adcclock_freq < 80e6) ? 1.0 : 1.584893192;
- double maxsnr = 640 / 160;
-
- /* Calculate the values for all 40 settings registers.
- *
- * DO NOT TOUCH THIS UNLESS YOU KNOW EXACTLY WHAT YOU ARE DOING. kthx.*/
- uint8_t data[40];
- data[0] = 0; data[1] = 0; data[2] = 0; data[3] = 0x24;
- data[4] = 0x24; data[5] = 0; data[6] = 0;
- data[7] = (uint8_t) AD9361_MIN(124, (AD9361_FLOOR_INT(-0.5
- + (80.0 * scale_snr * scale_res
- * AD9361_MIN(1.0, ad9361_sqrt(maxsnr * fsadc / 640.0))))));
- double data007 = data[7];
- data[8] = (uint8_t) AD9361_MIN(255, (AD9361_FLOOR_INT(0.5
- + ((20.0 * (640.0 / fsadc) * ((data007 / 80.0))
- / (scale_res * scale_cap))))));
- data[10] = (uint8_t) AD9361_MIN(127, (AD9361_FLOOR_INT(-0.5 + (77.0 * scale_res
- * AD9361_MIN(1.0, ad9361_sqrt(maxsnr * fsadc / 640.0))))));
- double data010 = data[10];
- data[9] = (uint8_t) AD9361_MIN(127, (AD9361_FLOOR_INT(0.8 * data010)));
- data[11] = (uint8_t) AD9361_MIN(255, (AD9361_FLOOR_INT(0.5
- + (20.0 * (640.0 / fsadc) * ((data010 / 77.0)
- / (scale_res * scale_cap))))));
- data[12] = (uint8_t) AD9361_MIN(127, (AD9361_FLOOR_INT(-0.5
- + (80.0 * scale_res * AD9361_MIN(1.0,
- ad9361_sqrt(maxsnr * fsadc / 640.0))))));
- double data012 = data[12];
- data[13] = (uint8_t) AD9361_MIN(255, (AD9361_FLOOR_INT(-1.5
- + (20.0 * (640.0 / fsadc) * ((data012 / 80.0)
- / (scale_res * scale_cap))))));
- data[14] = 21 * (uint8_t)(AD9361_FLOOR_INT(0.1 * 640.0 / fsadc));
- data[15] = (uint8_t) AD9361_MIN(127, (1.025 * data007));
- double data015 = data[15];
- data[16] = (uint8_t) AD9361_MIN(127, (AD9361_FLOOR_INT((data015
- * (0.98 + (0.02 * AD9361_MAX(1.0,
- (640.0 / fsadc) / maxsnr)))))));
- data[17] = data[15];
- data[18] = (uint8_t) AD9361_MIN(127, (0.975 * (data010)));
- double data018 = data[18];
- data[19] = (uint8_t) AD9361_MIN(127, (AD9361_FLOOR_INT((data018
- * (0.98 + (0.02 * AD9361_MAX(1.0,
- (640.0 / fsadc) / maxsnr)))))));
- data[20] = data[18];
- data[21] = (uint8_t) AD9361_MIN(127, (0.975 * data012));
- double data021 = data[21];
- data[22] = (uint8_t) AD9361_MIN(127, (AD9361_FLOOR_INT((data021
- * (0.98 + (0.02 * AD9361_MAX(1.0,
- (640.0 / fsadc) / maxsnr)))))));
- data[23] = data[21];
- data[24] = 0x2e;
- data[25] = (uint8_t)(AD9361_FLOOR_INT(128.0 + AD9361_MIN(63.0,
- 63.0 * (fsadc / 640.0))));
- data[26] = (uint8_t)(AD9361_FLOOR_INT(AD9361_MIN(63.0, 63.0 * (fsadc / 640.0)
- * (0.92 + (0.08 * (640.0 / fsadc))))));
- data[27] = (uint8_t)(AD9361_FLOOR_INT(AD9361_MIN(63.0,
- 32.0 * ad9361_sqrt(fsadc / 640.0))));
- data[28] = (uint8_t)(AD9361_FLOOR_INT(128.0 + AD9361_MIN(63.0,
- 63.0 * (fsadc / 640.0))));
- data[29] = (uint8_t)(AD9361_FLOOR_INT(AD9361_MIN(63.0,
- 63.0 * (fsadc / 640.0)
- * (0.92 + (0.08 * (640.0 / fsadc))))));
- data[30] = (uint8_t)(AD9361_FLOOR_INT(AD9361_MIN(63.0,
- 32.0 * ad9361_sqrt(fsadc / 640.0))));
- data[31] = (uint8_t)(AD9361_FLOOR_INT(128.0 + AD9361_MIN(63.0,
- 63.0 * (fsadc / 640.0))));
- data[32] = (uint8_t)(AD9361_FLOOR_INT(AD9361_MIN(63.0,
- 63.0 * (fsadc / 640.0) * (0.92
- + (0.08 * (640.0 / fsadc))))));
- data[33] = (uint8_t)(AD9361_FLOOR_INT(AD9361_MIN(63.0,
- 63.0 * ad9361_sqrt(fsadc / 640.0))));
- data[34] = (uint8_t) AD9361_MIN(127, (AD9361_FLOOR_INT(64.0
- * ad9361_sqrt(fsadc / 640.0))));
- data[35] = 0x40;
- data[36] = 0x40;
- data[37] = 0x2c;
- data[38] = 0x00;
- data[39] = 0x00;
-
- /* Program the registers! */
- int i;
- for(i=0; i<40; i++) {
- write_ad9361_reg(0x200+i, data[i]);
- }
-
-}
-
-/* Calibrate the baseband DC offset.
- *
- * Note that this function is called from within the TX quadrature
- * calibration function! */
-void calibrate_baseband_dc_offset() {
- write_ad9361_reg(0x193, 0x3f); // Calibration settings
- write_ad9361_reg(0x190, 0x0f); // Set tracking coefficient
- //write_ad9361_reg(0x190, /*0x0f*//*0xDF*/0x80*1 | 0x40*1 | (16+8/*+4*/)); // Set tracking coefficient: don't *4 counter, do decim /4, increased gain shift
- write_ad9361_reg(0x194, 0x01); // More calibration settings
-
- /* Start that calibration, baby. */
- int count = 0;
- write_ad9361_reg(0x016, 0x01);
- while(read_ad9361_reg(0x016) & 0x01) {
- if(count > 100) {
- post_err_msg("Baseband DC Offset Calibration Failure");
- break;
- }
-
- count++;
- ad9361_msleep(5);
- }
-}
-
-/* Calibrate the RF DC offset.
- *
- * Note that this function is called from within the TX quadrature
- * calibration function. */
-void calibrate_rf_dc_offset() {
- /* Some settings are frequency-dependent. */
- if(_rx_freq < 4e9) {
- write_ad9361_reg(0x186, 0x32); // RF DC Offset count
- write_ad9361_reg(0x187, 0x24);
- write_ad9361_reg(0x188, 0x05);
- } else {
- write_ad9361_reg(0x186, 0x28); // RF DC Offset count
- write_ad9361_reg(0x187, 0x34);
- write_ad9361_reg(0x188, 0x06);
- }
-
- write_ad9361_reg(0x185, 0x20); // RF DC Offset wait count
- write_ad9361_reg(0x18b, 0x83);
- write_ad9361_reg(0x189, 0x30);
-
- /* Run the calibration! */
- int count = 0;
- write_ad9361_reg(0x016, 0x02);
- while(read_ad9361_reg(0x016) & 0x02) {
- if(count > 100) {
- post_err_msg("RF DC Offset Calibration Failure");
- break;
- }
-
- count++;
- ad9361_msleep(50);
- }
-}
-
-/* Start the RX quadrature calibration.
- *
- * Note that we are using Catalina's 'tracking' feature for RX quadrature
- * calibration, so once it starts it continues to free-run during operation.
- * It should be re-run for large frequency changes. */
-void calibrate_rx_quadrature(void) {
- /* Configure RX Quadrature calibration settings. */
- write_ad9361_reg(0x168, 0x03); // Set tone level for cal
- write_ad9361_reg(0x16e, 0x25); // RX Gain index to use for cal
- write_ad9361_reg(0x16a, 0x75); // Set Kexp phase
- write_ad9361_reg(0x16b, 0x15); // Set Kexp amplitude
- write_ad9361_reg(0x169, 0xcf); // Continuous tracking mode
- write_ad9361_reg(0x18b, 0xad);
-}
-
-/* TX quadtrature calibration routine.
- *
- * The TX quadrature needs to be done twice, once for each TX chain, with
- * only one register change in between. Thus, this function enacts the
- * calibrations, and it is called from calibrate_tx_quadrature. */
-void tx_quadrature_cal_routine(void) {
-
- /* This is a weird process, but here is how it works:
- * 1) Read the calibrated NCO frequency bits out of 0A3.
- * 2) Write the two bits to the RX NCO freq part of 0A0.
- * 3) Re-read 0A3 to get bits [5:0] because maybe they changed?
- * 4) Update only the TX NCO freq bits in 0A3.
- * 5) Profit (I hope). */
- uint8_t reg0a3 = read_ad9361_reg(0x0a3);
- uint8_t nco_freq = (reg0a3 & 0xC0);
- write_ad9361_reg(0x0a0, 0x15 | (nco_freq >> 1));
- reg0a3 = read_ad9361_reg(0x0a3);
- write_ad9361_reg(0x0a3, (reg0a3 & 0x3F) | nco_freq);
-
- /* It is possible to reach a configuration that won't operate correctly,
- * where the two test tones used for quadrature calibration are outside
- * of the RX BBF, and therefore don't make it to the ADC. We will check
- * for that scenario here. */
- double max_cal_freq = (((_baseband_bw * _tfir_factor) * ((nco_freq >> 6) + 1)) / 32) * 2;
- double bbbw = _baseband_bw / 2.0; // bbbw represents the one-sided BW
- if(bbbw > 28e6) {
- bbbw = 28e6;
- } else if (bbbw < 0.20e6) {
- bbbw = 0.20e6;
- }
- if (max_cal_freq > bbbw )
- post_err_msg("max_cal_freq > bbbw");
-
- write_ad9361_reg(0x0a1, 0x7B); // Set tracking coefficient
- write_ad9361_reg(0x0a9, 0xff); // Cal count
- write_ad9361_reg(0x0a2, 0x7f); // Cal Kexp
- write_ad9361_reg(0x0a5, 0x01); // Cal magnitude threshold VVVV
- write_ad9361_reg(0x0a6, 0x01);
-
- /* The gain table index used for calibration must be adjusted for the
- * mid-table to get a TIA index = 1 and LPF index = 0. */
- if((_rx_freq >= 1300e6) && (_rx_freq < 4000e6)) {
- write_ad9361_reg(0x0aa, 0x22); // Cal gain table index
- } else {
- write_ad9361_reg(0x0aa, 0x25); // Cal gain table index
- }
-
- write_ad9361_reg(0x0a4, 0xf0); // Cal setting conut
- write_ad9361_reg(0x0ae, 0x00); // Cal LPF gain index (split mode)
-
- /* First, calibrate the baseband DC offset. */
- calibrate_baseband_dc_offset();
-
- /* Second, calibrate the RF DC offset. */
- calibrate_rf_dc_offset();
-
- /* Now, calibrate the TX quadrature! */
- int count = 0;
- write_ad9361_reg(0x016, 0x10);
- while(read_ad9361_reg(0x016) & 0x10) {
- if(count > 100) {
- post_err_msg("TX Quadrature Calibration Failure");
- break;
- }
-
- count++;
- ad9361_msleep(10);
- }
-}
-
-/* Run the TX quadrature calibration.
- *
- * Note that from within this function we are also triggering the baseband
- * and RF DC calibrations. */
-void calibrate_tx_quadrature(void) {
- /* Make sure we are, in fact, in the ALERT state. If not, something is
- * terribly wrong in the driver execution flow. */
- if((read_ad9361_reg(0x017) & 0x0F) != 5) {
- post_err_msg("TX Quad Cal started, but not in ALERT");
- }
-
- /* Turn off free-running and continuous calibrations. Note that this
- * will get turned back on at the end of the RX calibration routine. */
- write_ad9361_reg(0x169, 0xc0);
-
- /* This calibration must be done in a certain order, and for both TX_A
- * and TX_B, separately. Store the original setting so that we can
- * restore it later. */
- uint8_t orig_reg_inputsel = reg_inputsel;
-
- /***********************************************************************
- * TX1/2-A Calibration
- **********************************************************************/
- reg_inputsel = reg_inputsel & 0xBF;
- write_ad9361_reg(0x004, reg_inputsel);
-
- tx_quadrature_cal_routine();
-
- /***********************************************************************
- * TX1/2-B Calibration
- **********************************************************************/
- reg_inputsel = reg_inputsel | 0x40;
- write_ad9361_reg(0x004, reg_inputsel);
-
- tx_quadrature_cal_routine();
-
- /***********************************************************************
- * fin
- **********************************************************************/
- reg_inputsel = orig_reg_inputsel;
- write_ad9361_reg(0x004, orig_reg_inputsel);
-}
-
-
-/***********************************************************************
- * Other Misc Setup Functions
- ***********************************************************************/
-
-/* Program the mixer gain table.
- *
- * Note that this table is fixed for all frequency settings. */
-void program_mixer_gm_subtable() {
- uint8_t gain[] = {0x78, 0x74, 0x70, 0x6C, 0x68, 0x64, 0x60, 0x5C, 0x58,
- 0x54, 0x50, 0x4C, 0x48, 0x30, 0x18, 0x00};
- uint8_t gm[] = {0x00, 0x0D, 0x15, 0x1B, 0x21, 0x25, 0x29, 0x2C, 0x2F,
- 0x31, 0x33, 0x34, 0x35, 0x3A, 0x3D, 0x3E};
-
- /* Start the clock. */
- write_ad9361_reg(0x13f, 0x02);
-
- /* Program the GM Sub-table. */
- int i;
- for(i = 15; i >= 0; i--) {
- write_ad9361_reg(0x138, i);
- write_ad9361_reg(0x139, gain[(15 - i)]);
- write_ad9361_reg(0x13A, 0x00);
- write_ad9361_reg(0x13B, gm[(15 - i)]);
- write_ad9361_reg(0x13F, 0x06);
- write_ad9361_reg(0x13C, 0x00);
- write_ad9361_reg(0x13C, 0x00);
- }
-
- /* Clear write bit and stop clock. */
- write_ad9361_reg(0x13f, 0x02);
- write_ad9361_reg(0x13C, 0x00);
- write_ad9361_reg(0x13C, 0x00);
- write_ad9361_reg(0x13f, 0x00);
-}
-
-/* Program the gain table.
- *
- * There are three different gain tables for different frequency ranges! */
-void program_gain_table() {
-
- /* Figure out which gain table we should be using for our current
- * frequency band. */
- uint8_t (*gain_table)[5] = NULL;
- uint8_t new_gain_table;
- if(_rx_freq < 1300e6) {
- gain_table = gain_table_sub_1300mhz;
- new_gain_table = 1;
- } else if(_rx_freq < 4e9) {
- gain_table = gain_table_1300mhz_to_4000mhz;
- new_gain_table = 2;
- } else if(_rx_freq <= 6e9) {
- gain_table = gain_table_4000mhz_to_6000mhz;
- new_gain_table = 3;
- } else {
- post_err_msg("Wrong _rx_freq value");
- new_gain_table = 1;
- }
-
- /* Only re-program the gain table if there has been a band change. */
- if(_curr_gain_table == new_gain_table) {
- return;
- } else {
- _curr_gain_table = new_gain_table;
- }
-
- /* Okay, we have to program a new gain table. Sucks, brah. Start the
- * gain table clock. */
- write_ad9361_reg(0x137, 0x1A);
-
- /* IT'S PROGRAMMING TIME. */
- uint8_t index = 0;
- for(; index < 77; index++) {
- write_ad9361_reg(0x130, index);
- write_ad9361_reg(0x131, gain_table[index][1]);
- write_ad9361_reg(0x132, gain_table[index][2]);
- write_ad9361_reg(0x133, gain_table[index][3]);
- write_ad9361_reg(0x137, 0x1E);
- write_ad9361_reg(0x134, 0x00);
- write_ad9361_reg(0x134, 0x00);
- }
-
- /* Everything above the 77th index is zero. */
- for(; index < 91; index++) {
- write_ad9361_reg(0x130, index);
- write_ad9361_reg(0x131, 0x00);
- write_ad9361_reg(0x132, 0x00);
- write_ad9361_reg(0x133, 0x00);
- write_ad9361_reg(0x137, 0x1E);
- write_ad9361_reg(0x134, 0x00);
- write_ad9361_reg(0x134, 0x00);
- }
-
- /* Clear the write bit and stop the gain clock. */
- write_ad9361_reg(0x137, 0x1A);
- write_ad9361_reg(0x134, 0x00);
- write_ad9361_reg(0x134, 0x00);
- write_ad9361_reg(0x137, 0x00);
-}
-
-/* Setup gain control registers.
- *
- * This really only needs to be done once, at initialization. */
-void setup_gain_control() {
- write_ad9361_reg(0x0FA, 0xE0); // Gain Control Mode Select
- write_ad9361_reg(0x0FB, 0x08); // Table, Digital Gain, Man Gain Ctrl
- write_ad9361_reg(0x0FC, 0x23); // Incr Step Size, ADC Overrange Size
- write_ad9361_reg(0x0FD, 0x4C); // Max Full/LMT Gain Table Index
- write_ad9361_reg(0x0FE, 0x44); // Decr Step Size, Peak Overload Time
- write_ad9361_reg(0x100, 0x6F); // Max Digital Gain
- write_ad9361_reg(0x104, 0x2F); // ADC Small Overload Threshold
- write_ad9361_reg(0x105, 0x3A); // ADC Large Overload Threshold
- write_ad9361_reg(0x107, 0x31); // Large LMT Overload Threshold
- write_ad9361_reg(0x108, 0x39); // Small LMT Overload Threshold
- write_ad9361_reg(0x109, 0x23); // Rx1 Full/LMT Gain Index
- write_ad9361_reg(0x10A, 0x58); // Rx1 LPF Gain Index
- write_ad9361_reg(0x10B, 0x00); // Rx1 Digital Gain Index
- write_ad9361_reg(0x10C, 0x23); // Rx2 Full/LMT Gain Index
- write_ad9361_reg(0x10D, 0x18); // Rx2 LPF Gain Index
- write_ad9361_reg(0x10E, 0x00); // Rx2 Digital Gain Index
- write_ad9361_reg(0x114, 0x30); // Low Power Threshold
- write_ad9361_reg(0x11A, 0x27); // Initial LMT Gain Limit
- write_ad9361_reg(0x081, 0x00); // Tx Symbol Gain Control
-}
-
-/* Setup the RX or TX synthesizers.
- *
- * This setup depends on a fixed look-up table, which is stored in an
- * included header file. The table is indexed based on the passed VCO rate.
- */
-void setup_synth(int which, double vcorate) {
- /* The vcorates in the vco_index array represent lower boundaries for
- * rates. Once we find a match, we use that index to look-up the rest of
- * the register values in the LUT. */
- int vcoindex = 0;
- int i;
- for(i = 0; i < 53; i++) {
- vcoindex = i;
- if(vcorate > vco_index[i]) {
- break;
- }
- }
-
- if (vcoindex > 53)
- post_err_msg("vcoindex > 53");
-
- /* Parse the values out of the LUT based on our calculated index... */
- uint8_t vco_output_level = synth_cal_lut[vcoindex][0];
- uint8_t vco_varactor = synth_cal_lut[vcoindex][1];
- uint8_t vco_bias_ref = synth_cal_lut[vcoindex][2];
- uint8_t vco_bias_tcf = synth_cal_lut[vcoindex][3];
- uint8_t vco_cal_offset = synth_cal_lut[vcoindex][4];
- uint8_t vco_varactor_ref = synth_cal_lut[vcoindex][5];
- uint8_t charge_pump_curr = synth_cal_lut[vcoindex][6];
- uint8_t loop_filter_c2 = synth_cal_lut[vcoindex][7];
- uint8_t loop_filter_c1 = synth_cal_lut[vcoindex][8];
- uint8_t loop_filter_r1 = synth_cal_lut[vcoindex][9];
- uint8_t loop_filter_c3 = synth_cal_lut[vcoindex][10];
- uint8_t loop_filter_r3 = synth_cal_lut[vcoindex][11];
-
- /* ... annnd program! */
- if(which == RX_TYPE) {
- write_ad9361_reg(0x23a, 0x40 | vco_output_level);
- write_ad9361_reg(0x239, 0xC0 | vco_varactor);
- write_ad9361_reg(0x242, vco_bias_ref | (vco_bias_tcf << 3));
- write_ad9361_reg(0x238, (vco_cal_offset << 3));
- write_ad9361_reg(0x245, 0x00);
- write_ad9361_reg(0x251, vco_varactor_ref);
- write_ad9361_reg(0x250, 0x70);
- write_ad9361_reg(0x23b, 0x80 | charge_pump_curr);
- write_ad9361_reg(0x23e, loop_filter_c1 | (loop_filter_c2 << 4));
- write_ad9361_reg(0x23f, loop_filter_c3 | (loop_filter_r1 << 4));
- write_ad9361_reg(0x240, loop_filter_r3);
- } else if(which == TX_TYPE) {
- write_ad9361_reg(0x27a, 0x40 | vco_output_level);
- write_ad9361_reg(0x279, 0xC0 | vco_varactor);
- write_ad9361_reg(0x282, vco_bias_ref | (vco_bias_tcf << 3));
- write_ad9361_reg(0x278, (vco_cal_offset << 3));
- write_ad9361_reg(0x285, 0x00);
- write_ad9361_reg(0x291, vco_varactor_ref);
- write_ad9361_reg(0x290, 0x70);
- write_ad9361_reg(0x27b, 0x80 | charge_pump_curr);
- write_ad9361_reg(0x27e, loop_filter_c1 | (loop_filter_c2 << 4));
- write_ad9361_reg(0x27f, loop_filter_c3 | (loop_filter_r1 << 4));
- write_ad9361_reg(0x280, loop_filter_r3);
- } else {
- post_err_msg("[setup_synth] INVALID_CODE_PATH");
- }
-}
-
-
-/* Tune the baseband VCO.
- *
- * This clock signal is what gets fed to the ADCs and DACs. This function is
- * not exported outside of this file, and is invoked based on the rate
- * fed to the public set_clock_rate function. */
-double tune_bbvco(const double rate) {
- msg("[tune_bbvco] rate=%.10f", rate);
-
- /* Let's not re-tune to the same frequency over and over... */
- if(freq_is_nearly_equal(rate, _req_coreclk)) {
- return _adcclock_freq;
- }
-
- _req_coreclk = rate;
-
- const double fref = 40e6;
- const int modulus = 2088960;
- const double vcomax = 1430e6;
- const double vcomin = 672e6;
- double vcorate;
- int vcodiv;
-
- /* Iterate over VCO dividers until appropriate divider is found. */
- int i = 1;
- for(; i <= 6; i++) {
- vcodiv = 1 << i;
- vcorate = rate * vcodiv;
-
- if(vcorate >= vcomin && vcorate <= vcomax) break;
- }
- if(i == 7)
- post_err_msg("[tune_bbvco] wrong vcorate");
-
- msg("[tune_bbvco] vcodiv=%d vcorate=%.10f", vcodiv, vcorate);
-
- /* Fo = Fref * (Nint + Nfrac / mod) */
- int nint = vcorate / fref;
- msg("[tune_bbvco] (nint)=%.10f", (vcorate / fref));
- int nfrac = lround(((vcorate / fref) - (double)nint) * (double)modulus);
- msg("[tune_bbvco] (nfrac)=%.10f", (((vcorate / fref) - (double)nint) * (double)modulus));
- msg("[tune_bbvco] nint=%d nfrac=%d", nint, nfrac);
- double actual_vcorate = fref * ((double)nint + ((double)nfrac / (double)modulus));
-
- /* Scale CP current according to VCO rate */
- const double icp_baseline = 150e-6;
- const double freq_baseline = 1280e6;
- double icp = icp_baseline * (actual_vcorate / freq_baseline);
- int icp_reg = (icp / 25e-6) - 1;
-
- write_ad9361_reg(0x045, 0x00); // REFCLK / 1 to BBPLL
- write_ad9361_reg(0x046, icp_reg & 0x3F); // CP current
- write_ad9361_reg(0x048, 0xe8); // BBPLL loop filters
- write_ad9361_reg(0x049, 0x5b); // BBPLL loop filters
- write_ad9361_reg(0x04a, 0x35); // BBPLL loop filters
-
- write_ad9361_reg(0x04b, 0xe0);
- write_ad9361_reg(0x04e, 0x10); // Max accuracy
-
- write_ad9361_reg(0x043, nfrac & 0xFF); // Nfrac[7:0]
- write_ad9361_reg(0x042, (nfrac >> 8) & 0xFF); // Nfrac[15:8]
- write_ad9361_reg(0x041, (nfrac >> 16) & 0xFF); // Nfrac[23:16]
- write_ad9361_reg(0x044, nint); // Nint
-
- calibrate_lock_bbpll();
-
- reg_bbpll = (reg_bbpll & 0xF8) | i;
-
- _bbpll_freq = actual_vcorate;
- _adcclock_freq = (actual_vcorate / vcodiv);
-
- return _adcclock_freq;
-}
-
-/* This function re-programs all of the gains in the system.
- *
- * Because the gain values match to different gain indices based on the
- * current operating band, this function can be called to update all gain
- * settings to the appropriate index after a re-tune. */
-void program_gains() {
- set_gain(RX_TYPE,1, _rx1_gain);
- set_gain(RX_TYPE,2, _rx2_gain);
- set_gain(TX_TYPE,1, _tx1_gain);
- set_gain(TX_TYPE,2, _tx2_gain);
-}
-
-/* This is the internal tune function, not available for a host call.
- *
- * Calculate the VCO settings for the requested frquency, and then either
- * tune the RX or TX VCO. */
-double tune_helper(int which, const double value) {
-
- /* The RFPLL runs from 6 GHz - 12 GHz */
- const double fref = 80e6;
- const int modulus = 8388593;
- const double vcomax = 12e9;
- const double vcomin = 6e9;
- double vcorate;
- int vcodiv;
-
- /* Iterate over VCO dividers until appropriate divider is found. */
- int i;
- for(i = 0; i <= 6; i++) {
- vcodiv = 2 << i;
- vcorate = value * vcodiv;
- if(vcorate >= vcomin && vcorate <= vcomax) break;
- }
- if(i == 7)
- post_err_msg("RFVCO can't find valid VCO rate!");
-
- int nint = vcorate / fref;
- int nfrac = ((vcorate / fref) - nint) * modulus;
-
- double actual_vcorate = fref * (nint + (double)(nfrac)/modulus);
- double actual_lo = actual_vcorate / vcodiv;
-
- // UHD_VAR(actual_lo); // TODO:
-
- if(which == RX_TYPE) {
-
- _req_rx_freq = value;
-
- /* Set band-specific settings. */
- if(value < AD9361_RX_BAND_EDGE0) {
- reg_inputsel = (reg_inputsel & 0xC0) | 0x30;
- } else if((value >= AD9361_RX_BAND_EDGE0) && (value < AD9361_RX_BAND_EDGE1)) {
- reg_inputsel = (reg_inputsel & 0xC0) | 0x0C;
- } else if((value >= AD9361_RX_BAND_EDGE1) && (value <= 6e9)) {
- reg_inputsel = (reg_inputsel & 0xC0) | 0x03;
- } else {
- post_err_msg("[tune_helper] INVALID_CODE_PATH");
- }
-
- write_ad9361_reg(0x004, reg_inputsel);
-
- /* Store vcodiv setting. */
- reg_vcodivs = (reg_vcodivs & 0xF0) | (i & 0x0F);
-
- /* Setup the synthesizer. */
- setup_synth(RX_TYPE, actual_vcorate);
-
- /* Tune!!!! */
- write_ad9361_reg(0x233, nfrac & 0xFF);
- write_ad9361_reg(0x234, (nfrac >> 8) & 0xFF);
- write_ad9361_reg(0x235, (nfrac >> 16) & 0xFF);
- write_ad9361_reg(0x232, (nint >> 8) & 0xFF);
- write_ad9361_reg(0x231, nint & 0xFF);
- write_ad9361_reg(0x005, reg_vcodivs);
-
- /* Lock the PLL! */
- ad9361_msleep(2);
- if((read_ad9361_reg(0x247) & 0x02) == 0) {
- post_err_msg("RX PLL NOT LOCKED");
- }
-
- _rx_freq = actual_lo;
-
- return actual_lo;
-
- } else {
-
- _req_tx_freq = value;
-
- /* Set band-specific settings. */
- if(value < AD9361_TX_BAND_EDGE) {
- reg_inputsel = reg_inputsel | 0x40;
- } else if((value >= AD9361_TX_BAND_EDGE) && (value <= 6e9)) {
- reg_inputsel = reg_inputsel & 0xBF;
- } else {
- post_err_msg("[tune_helper] INVALID_CODE_PATH");
- }
-
- write_ad9361_reg(0x004, reg_inputsel);
-
- /* Store vcodiv setting. */
- reg_vcodivs = (reg_vcodivs & 0x0F) | ((i & 0x0F) << 4);
-
- /* Setup the synthesizer. */
- setup_synth(TX_TYPE, actual_vcorate);
-
- /* Tune it, homey. */
- write_ad9361_reg(0x273, nfrac & 0xFF);
- write_ad9361_reg(0x274, (nfrac >> 8) & 0xFF);
- write_ad9361_reg(0x275, (nfrac >> 16) & 0xFF);
- write_ad9361_reg(0x272, (nint >> 8) & 0xFF);
- write_ad9361_reg(0x271, nint & 0xFF);
- write_ad9361_reg(0x005, reg_vcodivs);
-
- /* Lock the PLL! */
- ad9361_msleep(2);
- if((read_ad9361_reg(0x287) & 0x02) == 0) {
- post_err_msg("TX PLL NOT LOCKED");
- }
-
- _tx_freq = actual_lo;
-
- return actual_lo;
- }
-}
-
-/* Configure the various clock / sample rates in the RX and TX chains.
- *
- * Functionally, this function configures Catalina's RX and TX rates. For
- * a requested TX & RX rate, it sets the interpolation & decimation filters,
- * and tunes the VCO that feeds the ADCs and DACs.
- */
-double setup_rates(const double rate) {
-
- /* If we make it into this function, then we are tuning to a new rate.
- * Store the new rate. */
- _req_clock_rate = rate;
-
- /* Set the decimation and interpolation values in the RX and TX chains.
- * This also switches filters in / out. Note that all transmitters and
- * receivers have to be turned on for the calibration portion of
- * bring-up, and then they will be switched out to reflect the actual
- * user-requested antenna selections. */
- int divfactor = 0;
- _tfir_factor = 0;
- if(rate < 0.33e6) {
- // RX1 + RX2 enabled, 3, 2, 2, 4
- reg_rxfilt = B8( 11101111 ) ;
-
- // TX1 + TX2 enabled, 3, 2, 2, 4
- reg_txfilt = B8( 11101111 ) ;
-
- divfactor = 48;
- _tfir_factor = 2;
- } else if(rate < 0.66e6) {
- // RX1 + RX2 enabled, 2, 2, 2, 4
- reg_rxfilt = B8( 11011111 ) ;
-
- // TX1 + TX2 enabled, 2, 2, 2, 4
- reg_txfilt = B8( 11011111 ) ;
-
- divfactor = 32;
- _tfir_factor = 2;
- } else if(rate <= 20e6) {
- // RX1 + RX2 enabled, 2, 2, 2, 2
- reg_rxfilt = B8( 11011110 ) ;
-
- // TX1 + TX2 enabled, 2, 2, 2, 2
- reg_txfilt = B8( 11011110 ) ;
-
- divfactor = 16;
- _tfir_factor = 2;
- } else if((rate > 20e6) && (rate < 23e6)) {
- // RX1 + RX2 enabled, 3, 2, 2, 2
- reg_rxfilt = B8( 11101110 ) ;
-
- // TX1 + TX2 enabled, 3, 1, 2, 2
- reg_txfilt = B8( 11100110 ) ;
-
- divfactor = 24;
- _tfir_factor = 2;
- } else if((rate >= 23e6) && (rate < 41e6)) {
- // RX1 + RX2 enabled, 2, 2, 2, 2
- reg_rxfilt = B8( 11011110 ) ;
-
- // TX1 + TX2 enabled, 1, 2, 2, 2
- reg_txfilt = B8( 11001110 ) ;
-
- divfactor = 16;
- _tfir_factor = 2;
- } else if((rate >= 41e6) && (rate <= 56e6)) {
- // RX1 + RX2 enabled, 3, 1, 2, 2
- reg_rxfilt = B8( 11100110 ) ;
-
- // TX1 + TX2 enabled, 3, 1, 1, 2
- reg_txfilt = B8( 11100010 ) ;
-
- divfactor = 12;
- _tfir_factor = 2;
- } else if((rate > 56e6) && (rate <= 61.44e6)) {
- // RX1 + RX2 enabled, 3, 1, 1, 2
- reg_rxfilt = B8( 11100010 ) ;
-
- // TX1 + TX2 enabled, 3, 1, 1, 1
- reg_txfilt = B8( 11100001 ) ;
-
- divfactor = 6;
- _tfir_factor = 1;
- } else {
- // should never get in here
- post_err_msg("[setup_rates] INVALID_CODE_PATH");
- }
-
- msg("[setup_rates] divfactor=%d", divfactor);
-
- /* Tune the BBPLL to get the ADC and DAC clocks. */
- const double adcclk = tune_bbvco(rate * divfactor);
- double dacclk = adcclk;
-
- /* The DAC clock must be <= 336e6, and is either the ADC clock or 1/2 the
- * ADC clock.*/
- if(adcclk > 336e6) {
- /* Make the DAC clock = ADC/2, and bypass the TXFIR. */
- reg_bbpll = reg_bbpll | 0x08;
- dacclk = adcclk / 2.0;
- } else {
- reg_bbpll = reg_bbpll & 0xF7;
- }
-
- /* Set the dividers / interpolators in Catalina. */
- write_ad9361_reg(0x002, reg_txfilt);
- write_ad9361_reg(0x003, reg_rxfilt);
- write_ad9361_reg(0x004, reg_inputsel);
- write_ad9361_reg(0x00A, reg_bbpll);
-
- msg("[setup_rates] adcclk=%f", adcclk);
- _baseband_bw = (adcclk / divfactor);
-
- /* Setup the RX and TX FIR filters. Scale the number of taps based on
- * the clock speed. */
- const int max_tx_taps = 16 * AD9361_MIN((int)((dacclk / rate) + 0.5), \
- AD9361_MIN(4 * (1 << _tfir_factor), 8));
- const int max_rx_taps = AD9361_MIN((16 * (int)(adcclk / rate)), 128);
-
- const int num_tx_taps = get_num_taps(max_tx_taps);
- const int num_rx_taps = get_num_taps(max_rx_taps);
-
- setup_tx_fir(num_tx_taps);
- setup_rx_fir(num_rx_taps);
-
- return _baseband_bw;
-}
-
-/***********************************************************************
- * Publicly exported functions to host calls
- **********************************************************************/
-void init_ad9361(void) {
-
- /* Initialize shadow registers. */
- reg_vcodivs = 0x00;
- reg_inputsel = 0x30;
- reg_rxfilt = 0x00;
- reg_txfilt = 0x00;
- reg_bbpll = 0x02;
- reg_bbftune_config = 0x1e;
- reg_bbftune_mode = 0x1e;
-
- /* Initialize private VRQ fields. */
- _rx_freq = 0.0;
- _tx_freq = 0.0;
- _req_rx_freq = 0.0;
- _req_tx_freq = 0.0;
- _baseband_bw = 0.0;
- _req_clock_rate = 0.0;
- _req_coreclk = 0.0;
- _bbpll_freq = 0.0;
- _adcclock_freq = 0.0;
- _rx_bbf_tunediv = 0;
- _curr_gain_table = 0;
- _rx1_gain = 0;
- _rx2_gain = 0;
- _tx1_gain = 0;
- _tx2_gain = 0;
-
- /* Reset the device. */
- write_ad9361_reg(0x000,0x01);
- write_ad9361_reg(0x000,0x00);
- ad9361_msleep(20);
-
- /* There is not a WAT big enough for this. */
- write_ad9361_reg(0x3df, 0x01);
-
- write_ad9361_reg(0x2a6, 0x0e); // Enable master bias
- write_ad9361_reg(0x2a8, 0x0e); // Set bandgap trim
-
- /* Set RFPLL ref clock scale to REFCLK * 2 */
- write_ad9361_reg(0x2ab, 0x07);
- write_ad9361_reg(0x2ac, 0xff);
-
- /* Enable clocks. */
- if (AD9361_CLOCKING_MODE == 0)
- {
- write_ad9361_reg(0x009, 0x17);
- }
- if (AD9361_CLOCKING_MODE == 1)
- {
- write_ad9361_reg(0x009, 0x07);
- write_ad9361_reg(0x292, 0x08);
- write_ad9361_reg(0x293, 0x80);
- write_ad9361_reg(0x294, 0x00);
- write_ad9361_reg(0x295, 0x14);
- }
- ad9361_msleep(20);
-
- /* Tune the BBPLL, write TX and RX FIRS. */
- setup_rates(50e6);
-
- /* Setup data ports (FDD dual port DDR CMOS):
- * FDD dual port DDR CMOS no swap.
- * Force TX on one port, RX on the other. */
- write_ad9361_reg(0x010, 0xc8);
- write_ad9361_reg(0x011, 0x00);
- write_ad9361_reg(0x012, 0x02);
-
- /* Data delay for TX and RX data clocks */
- write_ad9361_reg(0x006, 0x0F);
- write_ad9361_reg(0x007, 0x0F);
-
- /* Setup AuxDAC */
- write_ad9361_reg(0x018, 0x00); // AuxDAC1 Word[9:2]
- write_ad9361_reg(0x019, 0x00); // AuxDAC2 Word[9:2]
- write_ad9361_reg(0x01A, 0x00); // AuxDAC1 Config and Word[1:0]
- write_ad9361_reg(0x01B, 0x00); // AuxDAC2 Config and Word[1:0]
- write_ad9361_reg(0x023, 0xFF); // AuxDAC Manaul/Auto Control
- write_ad9361_reg(0x026, 0x00); // AuxDAC Manual Select Bit/GPO Manual Select
- write_ad9361_reg(0x030, 0x00); // AuxDAC1 Rx Delay
- write_ad9361_reg(0x031, 0x00); // AuxDAC1 Tx Delay
- write_ad9361_reg(0x032, 0x00); // AuxDAC2 Rx Delay
- write_ad9361_reg(0x033, 0x00); // AuxDAC2 Tx Delay
-
- /* Setup AuxADC */
- write_ad9361_reg(0x00B, 0x00); // Temp Sensor Setup (Offset)
- write_ad9361_reg(0x00C, 0x00); // Temp Sensor Setup (Temp Window)
- write_ad9361_reg(0x00D, 0x03); // Temp Sensor Setup (Periodic Measure)
- write_ad9361_reg(0x00F, 0x04); // Temp Sensor Setup (Decimation)
- write_ad9361_reg(0x01C, 0x10); // AuxADC Setup (Clock Div)
- write_ad9361_reg(0x01D, 0x01); // AuxADC Setup (Decimation/Enable)
-
- /* Setup control outputs. */
- write_ad9361_reg(0x035, 0x07);
- write_ad9361_reg(0x036, 0xFF);
-
- /* Setup GPO */
- write_ad9361_reg(0x03a, 0x27); //set delay register
- write_ad9361_reg(0x020, 0x00); // GPO Auto Enable Setup in RX and TX
- write_ad9361_reg(0x027, 0x03); // GPO Manual and GPO auto value in ALERT
- write_ad9361_reg(0x028, 0x00); // GPO_0 RX Delay
- write_ad9361_reg(0x029, 0x00); // GPO_1 RX Delay
- write_ad9361_reg(0x02A, 0x00); // GPO_2 RX Delay
- write_ad9361_reg(0x02B, 0x00); // GPO_3 RX Delay
- write_ad9361_reg(0x02C, 0x00); // GPO_0 TX Delay
- write_ad9361_reg(0x02D, 0x00); // GPO_1 TX Delay
- write_ad9361_reg(0x02E, 0x00); // GPO_2 TX Delay
- write_ad9361_reg(0x02F, 0x00); // GPO_3 TX Delay
-
- write_ad9361_reg(0x261, 0x00); // RX LO power
- write_ad9361_reg(0x2a1, 0x00); // TX LO power
- write_ad9361_reg(0x248, 0x0b); // en RX VCO LDO
- write_ad9361_reg(0x288, 0x0b); // en TX VCO LDO
- write_ad9361_reg(0x246, 0x02); // pd RX cal Tcf
- write_ad9361_reg(0x286, 0x02); // pd TX cal Tcf
- write_ad9361_reg(0x249, 0x8e); // rx vco cal length
- write_ad9361_reg(0x289, 0x8e); // rx vco cal length
- write_ad9361_reg(0x23b, 0x80); // set RX MSB?, FIXME 0x89 magic cp
- write_ad9361_reg(0x27b, 0x80); // "" TX //FIXME 0x88 see above
- write_ad9361_reg(0x243, 0x0d); // set rx prescaler bias
- write_ad9361_reg(0x283, 0x0d); // "" TX
-
- write_ad9361_reg(0x23d, 0x00); // Clear half VCO cal clock setting
- write_ad9361_reg(0x27d, 0x00); // Clear half VCO cal clock setting
-
- /* The order of the following process is EXTREMELY important. If the
- * below functions are modified at all, device initialization and
- * calibration might be broken in the process! */
-
- write_ad9361_reg(0x015, 0x04); // dual synth mode, synth en ctrl en
- write_ad9361_reg(0x014, 0x05); // use SPI for TXNRX ctrl, to ALERT, TX on
- write_ad9361_reg(0x013, 0x01); // enable ENSM
- ad9361_msleep(1);
-
- calibrate_synth_charge_pumps();
-
- tune_helper(RX_TYPE, 800e6);
- tune_helper(TX_TYPE, 850e6);
-
- program_mixer_gm_subtable();
- program_gain_table();
- setup_gain_control();
-
- calibrate_baseband_rx_analog_filter();
- calibrate_baseband_tx_analog_filter();
- calibrate_rx_TIAs();
- calibrate_secondary_tx_filter();
-
- setup_adc();
-
- calibrate_tx_quadrature();
- calibrate_rx_quadrature();
-
- write_ad9361_reg(0x012, 0x02); // cals done, set PPORT config
- write_ad9361_reg(0x013, 0x01); // Set ENSM FDD bit
- write_ad9361_reg(0x015, 0x04); // dual synth mode, synth en ctrl en
-
- /* Default TX attentuation to 10dB on both TX1 and TX2 */
- write_ad9361_reg(0x073, 0x00);
- write_ad9361_reg(0x074, 0x00);
- write_ad9361_reg(0x075, 0x00);
- write_ad9361_reg(0x076, 0x00);
-
- /* Setup RSSI Measurements */
- write_ad9361_reg(0x150, 0x0E); // RSSI Measurement Duration 0, 1
- write_ad9361_reg(0x151, 0x00); // RSSI Measurement Duration 2, 3
- write_ad9361_reg(0x152, 0xFF); // RSSI Weighted Multiplier 0
- write_ad9361_reg(0x153, 0x00); // RSSI Weighted Multiplier 1
- write_ad9361_reg(0x154, 0x00); // RSSI Weighted Multiplier 2
- write_ad9361_reg(0x155, 0x00); // RSSI Weighted Multiplier 3
- write_ad9361_reg(0x156, 0x00); // RSSI Delay
- write_ad9361_reg(0x157, 0x00); // RSSI Wait
- write_ad9361_reg(0x158, 0x0D); // RSSI Mode Select
- write_ad9361_reg(0x15C, 0x67); // Power Measurement Duration
-
- /* Turn on the default RX & TX chains. */
- set_active_chains(true, false, false, false);
-
- /* Set TXers & RXers on (only works in FDD mode) */
- write_ad9361_reg(0x014, 0x21);
-}
-
-
-/* This function sets the RX / TX rate between Catalina and the FPGA, and
- * thus determines the interpolation / decimation required in the FPGA to
- * achieve the user's requested rate.
- *
- * This is the only clock setting function that is exposed to the outside. */
-double set_clock_rate(const double req_rate) {
- if(req_rate > 61.44e6) {
- post_err_msg("Requested master clock rate outside range");
- }
-
- msg("[set_clock_rate] req_rate=%.10f", req_rate);
-
- /* UHD has a habit of requesting the same rate like four times when it
- * starts up. This prevents that, and any bugs in user code that request
- * the same rate over and over. */
- if(freq_is_nearly_equal(req_rate, _req_clock_rate)) {
- return _baseband_bw;
- }
-
- /* We must be in the SLEEP / WAIT state to do this. If we aren't already
- * there, transition the ENSM to State 0. */
- uint8_t current_state = read_ad9361_reg(0x017) & 0x0F;
- switch(current_state) {
- case 0x05:
- /* We are in the ALERT state. */
- write_ad9361_reg(0x014, 0x21);
- ad9361_msleep(5);
- write_ad9361_reg(0x014, 0x00);
- break;
-
- case 0x0A:
- /* We are in the FDD state. */
- write_ad9361_reg(0x014, 0x00);
- break;
-
- default:
- post_err_msg("[set_clock_rate:1] AD9361 in unknown state");
- break;
- };
-
- /* Store the current chain / antenna selections so that we can restore
- * them at the end of this routine; all chains will be enabled from
- * within setup_rates for calibration purposes. */
- uint8_t orig_tx_chains = reg_txfilt & 0xC0;
- uint8_t orig_rx_chains = reg_rxfilt & 0xC0;
-
- /* Call into the clock configuration / settings function. This is where
- * all the hard work gets done. */
- double rate = setup_rates(req_rate);
-
- msg("[set_clock_rate] rate=%.10f", rate);
-
- /* Transition to the ALERT state and calibrate everything. */
- write_ad9361_reg(0x015, 0x04); //dual synth mode, synth en ctrl en
- write_ad9361_reg(0x014, 0x05); //use SPI for TXNRX ctrl, to ALERT, TX on
- write_ad9361_reg(0x013, 0x01); //enable ENSM
- ad9361_msleep(1);
-
- calibrate_synth_charge_pumps();
-
- tune_helper(RX_TYPE, _rx_freq);
- tune_helper(TX_TYPE, _tx_freq);
-
- program_mixer_gm_subtable();
- program_gain_table();
- setup_gain_control();
- program_gains();
-
- calibrate_baseband_rx_analog_filter();
- calibrate_baseband_tx_analog_filter();
- calibrate_rx_TIAs();
- calibrate_secondary_tx_filter();
-
- setup_adc();
-
- calibrate_tx_quadrature();
- calibrate_rx_quadrature();
-
- write_ad9361_reg(0x012, 0x02); // cals done, set PPORT config
- write_ad9361_reg(0x013, 0x01); // Set ENSM FDD bit
- write_ad9361_reg(0x015, 0x04); // dual synth mode, synth en ctrl en
-
- /* End the function in the same state as the entry state. */
- switch(current_state) {
- case 0x05:
- /* We are already in ALERT. */
- break;
-
- case 0x0A:
- /* Transition back to FDD, and restore the original antenna
- * / chain selections. */
- reg_txfilt = (reg_txfilt & 0x3F) | orig_tx_chains;
- reg_rxfilt = (reg_rxfilt & 0x3F) | orig_rx_chains;
-
- write_ad9361_reg(0x002, reg_txfilt);
- write_ad9361_reg(0x003, reg_rxfilt);
- write_ad9361_reg(0x014, 0x21);
- break;
-
- default:
- post_err_msg("[set_clock_rate:2] AD9361 in unknown state");
- break;
- };
-
- return rate;
-}
-
-
-/* Set which of the four TX / RX chains provided by Catalina are active.
- *
- * Catalina provides two sets of chains, Side A and Side B. Each side
- * provides one TX antenna, and one RX antenna. The B200 maintains the USRP
- * standard of providing one antenna connection that is both TX & RX, and
- * one that is RX-only - for each chain. Thus, the possible antenna and
- * chain selections are:
- *
- * B200 Antenna Catalina Side Catalina Chain
- * -------------------------------------------------------------------
- * TX / RX1 Side A TX1 (when switched to TX)
- * TX / RX1 Side A RX1 (when switched to RX)
- * RX1 Side A RX1
- *
- * TX / RX2 Side B TX2 (when switched to TX)
- * TX / RX2 Side B RX2 (when switched to RX)
- * RX2 Side B RX2
- */
-void set_active_chains(bool tx1, bool tx2, bool rx1, bool rx2) {
- /* Clear out the current active chain settings. */
- reg_txfilt = reg_txfilt & 0x3F;
- reg_rxfilt = reg_rxfilt & 0x3F;
-
- /* Turn on the different chains based on the passed parameters. */
- if(tx1) { reg_txfilt = reg_txfilt | 0x40; }
- if(tx2) { reg_txfilt = reg_txfilt | 0x80; }
- if(rx1) { reg_rxfilt = reg_rxfilt | 0x40; }
- if(rx2) { reg_rxfilt = reg_rxfilt | 0x80; }
-
- /* Turn on / off the chains. */
- write_ad9361_reg(0x002, reg_txfilt);
- write_ad9361_reg(0x003, reg_rxfilt);
-}
-
-/* Tune the RX or TX frequency.
- *
- * This is the publicly-accessible tune function. It makes sure the tune
- * isn't a redundant request, and if not, passes it on to the class's
- * internal tune function.
- *
- * After tuning, it runs any appropriate calibrations. */
-double tune(int which, const double value) {
-
- if(which == RX_TYPE) {
- if(freq_is_nearly_equal(value, _req_rx_freq)) {
- return _rx_freq;
- }
-
- } else if(which == TX_TYPE) {
- if(freq_is_nearly_equal(value, _req_tx_freq)) {
- return _tx_freq;
- }
-
- } else {
- post_err_msg("[tune] INVALID_CODE_PATH");
- }
-
- /* If we aren't already in the ALERT state, we will need to return to
- * the FDD state after tuning. */
- int not_in_alert = 0;
- if((read_ad9361_reg(0x017) & 0x0F) != 5) {
- /* Force the device into the ALERT state. */
- not_in_alert = 1;
- write_ad9361_reg(0x014, 0x01);
- }
-
- /* Tune the RF VCO! */
- double tune_freq = tune_helper(which, value);
-
- /* Run any necessary calibrations / setups */
- if(which == RX_TYPE) {
- program_gain_table();
- }
-
- /* Update the gain settings. */
- program_gains();
-
- /* Run the calibration algorithms. */
- calibrate_tx_quadrature();
- calibrate_rx_quadrature();
-
- /* If we were in the FDD state, return it now. */
- if(not_in_alert) {
- write_ad9361_reg(0x014, 0x21);
- }
-
- return tune_freq;
-}
-
-/* Set the gain of RX1, RX2, TX1, or TX2.
- *
- * Note that the 'value' passed to this function is the actual gain value,
- * _not_ the gain index. This is the opposite of the eval software's GUI!
- * Also note that the RX chains are done in terms of gain, and the TX chains
- * are done in terms of attenuation. */
-double set_gain(int which, int n, const double value) {
-
- if(which == RX_TYPE) {
- /* Indexing the gain tables requires an offset from the requested
- * amount of total gain in dB:
- * < 1300MHz: dB + 5
- * >= 1300MHz and < 4000MHz: dB + 3
- * >= 4000MHz and <= 6000MHz: dB + 14
- */
- int gain_offset = 0;
- if(_rx_freq < 1300e6) {
- gain_offset = 5;
- } else if(_rx_freq < 4000e6) {
- gain_offset = 3;
- } else {
- gain_offset = 14;
- }
-
- int gain_index = value + gain_offset;
-
- /* Clip the gain values to the proper min/max gain values. */
- if(gain_index > 76) gain_index = 76;
- if(gain_index < 0) gain_index = 0;
-
- if(n == 1) {
- _rx1_gain = value;
- write_ad9361_reg(0x109, gain_index);
- } else {
- _rx2_gain = value;
- write_ad9361_reg(0x10c, gain_index);
- }
-
- return gain_index - gain_offset;
- } else {
- /* Setting the below bits causes a change in the TX attenuation word
- * to immediately take effect. */
- write_ad9361_reg(0x077, 0x40);
- write_ad9361_reg(0x07c, 0x40);
-
- /* Each gain step is -0.25dB. Calculate the attenuation necessary
- * for the requested gain, convert it into gain steps, then write
- * the attenuation word. Max gain (so zero attenuation) is 89.75. */
- double atten = AD9361_MAX_GAIN - value;
- int attenreg = atten * 4;
- if(n == 1) {
- _tx1_gain = value;
- write_ad9361_reg(0x073, attenreg & 0xFF);
- write_ad9361_reg(0x074, (attenreg >> 8) & 0x01);
- } else {
- _tx2_gain = value;
- write_ad9361_reg(0x075, attenreg & 0xFF);
- write_ad9361_reg(0x076, (attenreg >> 8) & 0x01);
- }
- return AD9361_MAX_GAIN - ((double)(attenreg)/ 4);
- }
-}
-
-/* This function is responsible to dispatch the vendor request call
- * to the proper handler
- */
-void ad9361_dispatch(const char* vrb, char* vrb_out) {
- memcpy(vrb_out, vrb, AD9361_DISPATCH_PACKET_SIZE); // Copy request to response memory
- tmp_req_buffer = vrb_out; // Set this to enable 'post_err_msg'
-
- //////////////////////////////////////////////
-
- double ret_val = 0.0;
- int mask = 0;
-
- const ad9361_transaction_t *request = (const ad9361_transaction_t *)vrb;
- ad9361_transaction_t *response = (ad9361_transaction_t *)vrb_out;
- response->error_msg[0] = '\0'; // Ensure error is cleared
-
- //msg("[ad9361_dispatch] action=%d", request->action);
-
- switch (request->action) {
- case AD9361_ACTION_ECHO:
- break; // nothing to do
- case AD9361_ACTION_INIT:
- init_ad9361();
- break;
- case AD9361_ACTION_SET_RX1_GAIN:
- ret_val = set_gain(RX_TYPE,1,double_unpack(request->value.gain));
- double_pack(ret_val, response->value.gain);
- break;
- case AD9361_ACTION_SET_TX1_GAIN:
- ret_val = set_gain(TX_TYPE,1,double_unpack(request->value.gain));
- double_pack(ret_val, response->value.gain);
- break;
- case AD9361_ACTION_SET_RX2_GAIN:
- ret_val = set_gain(RX_TYPE,2,double_unpack(request->value.gain));
- double_pack(ret_val, response->value.gain);
- break;
- case AD9361_ACTION_SET_TX2_GAIN:
- ret_val = set_gain(TX_TYPE,2,double_unpack(request->value.gain));
- double_pack(ret_val, response->value.gain);
- break;
- case AD9361_ACTION_SET_RX_FREQ:
- ret_val = tune(RX_TYPE, double_unpack(request->value.freq));
- double_pack(ret_val, response->value.freq);
- break;
- case AD9361_ACTION_SET_TX_FREQ:
- ret_val = tune(TX_TYPE, double_unpack(request->value.freq));
- double_pack(ret_val, response->value.freq);
- break;
- case AD9361_ACTION_SET_CODEC_LOOP:
- data_port_loopback(request->value.codec_loop != 0);
- break;
- case AD9361_ACTION_SET_CLOCK_RATE:
- ret_val = set_clock_rate(double_unpack(request->value.rate));
- double_pack(ret_val, response->value.rate);
- break;
- case AD9361_ACTION_SET_ACTIVE_CHAINS:
- mask = request->value.enable_mask;
- set_active_chains(mask & 1, mask & 2, mask & 4, mask & 8);
- break;
- default:
- post_err_msg("[ad9361_dispatch] NOT IMPLEMENTED");
- break;
- }
-}
diff --git a/firmware/fx3/ad9361/lib/ad9361_synth_lut.h b/firmware/fx3/ad9361/lib/ad9361_synth_lut.h
deleted file mode 100644
index 79214526d..000000000
--- a/firmware/fx3/ad9361/lib/ad9361_synth_lut.h
+++ /dev/null
@@ -1,135 +0,0 @@
-//
-// Copyright 2013-2014 Ettus Research LLC
-//
-
-#ifndef INCLUDED_AD9361_SYNTH_LUT_HPP
-#define INCLUDED_AD9361_SYNTH_LUT_HPP
-
-
-double vco_index[53] = {12605000000, 12245000000, 11906000000, 11588000000,
- 11288000000, 11007000000, 10742000000, 10492000000,
- 10258000000, 10036000000, 9827800000, 9631100000,
- 9445300000, 9269800000, 9103600000, 8946300000,
- 8797000000, 8655300000, 8520600000, 8392300000,
- 8269900000, 8153100000, 8041400000, 7934400000,
- 7831800000, 7733200000, 7638400000, 7547100000,
- 7459000000, 7374000000, 7291900000, 7212400000,
- 7135500000, 7061000000, 6988700000, 6918600000,
- 6850600000, 6784600000, 6720500000, 6658200000,
- 6597800000, 6539200000, 6482300000, 6427000000,
- 6373400000, 6321400000, 6270900000, 6222000000,
- 6174500000, 6128400000, 6083600000, 6040100000,
- 5997700000};
-
-int synth_cal_lut[53][12] = { {10, 0, 4, 0, 15, 8, 8, 13, 4, 13, 15, 9},
- {10, 0, 4, 0, 15, 8, 9, 13, 4, 13, 15, 9},
- {10, 0, 4, 0, 15, 8, 10, 13, 4, 13, 15, 9},
- {10, 0, 4, 0, 15, 8, 11, 13, 4, 13, 15, 9},
- {10, 0, 4, 0, 15, 8, 11, 13, 4, 13, 15, 9},
- {10, 0, 4, 0, 14, 8, 12, 13, 4, 13, 15, 9},
- {10, 0, 4, 0, 14, 8, 13, 13, 4, 13, 15, 9},
- {10, 0, 5, 1, 14, 9, 13, 13, 4, 13, 15, 9},
- {10, 0, 5, 1, 14, 9, 14, 13, 4, 13, 15, 9},
- {10, 0, 5, 1, 14, 9, 15, 13, 4, 13, 15, 9},
- {10, 0, 5, 1, 14, 9, 15, 13, 4, 13, 15, 9},
- {10, 0, 5, 1, 13, 9, 16, 13, 4, 13, 15, 9},
- {10, 0, 5, 1, 13, 9, 17, 13, 4, 13, 15, 9},
- {10, 0, 5, 1, 13, 9, 18, 13, 4, 13, 15, 9},
- {10, 0, 5, 1, 13, 9, 18, 13, 4, 13, 15, 9},
- {10, 0, 5, 1, 13, 9, 19, 13, 4, 13, 15, 9},
- {10, 1, 6, 1, 15, 11, 14, 13, 4, 13, 15, 9},
- {10, 1, 6, 1, 15, 11, 14, 13, 4, 13, 15, 9},
- {10, 1, 6, 1, 15, 11, 15, 13, 4, 13, 15, 9},
- {10, 1, 6, 1, 15, 11, 15, 13, 4, 13, 15, 9},
- {10, 1, 6, 1, 15, 11, 16, 13, 4, 13, 15, 9},
- {10, 1, 6, 1, 15, 11, 16, 13, 4, 13, 15, 9},
- {10, 1, 6, 1, 15, 11, 17, 13, 4, 13, 15, 9},
- {10, 1, 6, 1, 15, 11, 17, 13, 4, 13, 15, 9},
- {10, 1, 6, 1, 15, 11, 18, 13, 4, 13, 15, 9},
- {10, 1, 6, 1, 15, 11, 18, 13, 4, 13, 15, 9},
- {10, 1, 6, 1, 15, 11, 19, 13, 4, 13, 15, 9},
- {10, 1, 6, 1, 15, 11, 19, 13, 4, 13, 15, 9},
- {10, 1, 6, 1, 15, 11, 20, 13, 4, 13, 15, 9},
- {10, 1, 7, 2, 15, 12, 20, 13, 4, 13, 15, 9},
- {10, 1, 7, 2, 15, 12, 21, 13, 4, 13, 15, 9},
- {10, 1, 7, 2, 15, 12, 21, 13, 4, 13, 15, 9},
- {10, 1, 7, 2, 15, 14, 22, 13, 4, 13, 15, 9},
- {10, 1, 7, 2, 15, 14, 22, 13, 4, 13, 15, 9},
- {10, 1, 7, 2, 15, 14, 23, 13, 4, 13, 15, 9},
- {10, 1, 7, 2, 15, 14, 23, 13, 4, 13, 15, 9},
- {10, 1, 7, 2, 15, 14, 24, 13, 4, 13, 15, 9},
- {10, 1, 7, 2, 15, 14, 24, 13, 4, 13, 15, 9},
- {10, 1, 7, 2, 15, 14, 25, 13, 4, 13, 15, 9},
- {10, 1, 7, 2, 15, 14, 25, 13, 4, 13, 15, 9},
- {10, 1, 7, 2, 15, 14, 26, 13, 4, 13, 15, 9},
- {10, 1, 7, 2, 15, 14, 26, 13, 4, 13, 15, 9},
- {10, 1, 7, 2, 15, 14, 27, 13, 4, 13, 15, 9},
- {10, 1, 7, 2, 15, 14, 27, 13, 4, 13, 15, 9},
- {10, 3, 7, 3, 15, 12, 18, 13, 4, 13, 15, 9},
- {10, 3, 7, 3, 15, 12, 18, 13, 4, 13, 15, 9},
- {10, 3, 7, 3, 15, 12, 18, 13, 4, 13, 15, 9},
- {10, 3, 7, 3, 15, 12, 19, 13, 4, 13, 15, 9},
- {10, 3, 7, 3, 15, 12, 19, 13, 4, 13, 15, 9},
- {10, 3, 7, 3, 15, 12, 19, 13, 4, 13, 15, 9},
- {10, 3, 7, 3, 15, 12, 19, 13, 4, 13, 15, 9},
- {10, 3, 7, 3, 15, 12, 20, 13, 4, 13, 15, 9},
- {10, 3, 7, 3, 15, 12, 20, 13, 4, 13, 15, 9}};
-
-
-#if 0 /* This is the table for a 40MHz RFPLL Reference */
-int synth_cal_lut[53][12] = { {10, 0, 4, 0, 15, 8, 8, 12, 3, 14, 15, 11},
- {10, 0, 4, 0, 15, 8, 9, 12, 3, 14, 15, 11},
- {10, 0, 4, 0, 15, 8, 9, 12, 3, 14, 15, 11},
- {10, 0, 4, 0, 15, 8, 10, 12, 3, 14, 15, 11},
- {10, 0, 4, 0, 15, 8, 11, 12, 3, 14, 15, 11},
- {10, 0, 4, 0, 15, 8, 11, 12, 3, 14, 15, 11},
- {10, 0, 4, 0, 14, 8, 12, 12, 3, 14, 15, 11},
- {10, 0, 5, 1, 14, 9, 13, 12, 3, 14, 15, 11},
- {10, 0, 5, 1, 14, 9, 13, 12, 3, 14, 15, 11},
- {10, 0, 5, 1, 14, 9, 14, 12, 3, 14, 15, 11},
- {10, 0, 5, 1, 14, 9, 15, 12, 3, 14, 15, 11},
- {10, 0, 5, 1, 14, 9, 15, 12, 3, 14, 15, 11},
- {10, 0, 5, 1, 14, 9, 16, 12, 3, 14, 15, 11},
- {10, 0, 5, 1, 14, 9, 17, 12, 3, 14, 15, 11},
- {10, 0, 5, 1, 14, 9, 17, 12, 3, 14, 15, 11},
- {10, 0, 5, 1, 14, 9, 18, 12, 3, 14, 15, 11},
- {10, 1, 6, 1, 15, 11, 13, 12, 3, 14, 15, 11},
- {10, 1, 6, 1, 15, 11, 14, 12, 3, 14, 15, 11},
- {10, 1, 6, 1, 15, 11, 14, 12, 3, 14, 15, 11},
- {10, 1, 6, 1, 15, 11, 15, 12, 3, 14, 15, 11},
- {10, 1, 6, 1, 15, 11, 15, 12, 3, 14, 15, 11},
- {10, 1, 6, 1, 15, 11, 16, 12, 3, 14, 15, 11},
- {10, 1, 6, 1, 15, 11, 16, 12, 3, 14, 15, 11},
- {10, 1, 6, 1, 15, 11, 17, 12, 3, 14, 15, 11},
- {10, 1, 6, 1, 15, 11, 17, 12, 3, 14, 15, 11},
- {10, 1, 6, 1, 15, 11, 17, 12, 3, 14, 15, 11},
- {10, 1, 6, 1, 15, 11, 18, 12, 3, 14, 15, 11},
- {10, 1, 6, 1, 15, 11, 18, 12, 3, 14, 15, 11},
- {10, 1, 6, 1, 15, 11, 19, 12, 3, 14, 15, 11},
- {10, 1, 7, 2, 15, 12, 19, 12, 3, 14, 15, 11},
- {10, 1, 7, 2, 15, 12, 20, 12, 3, 14, 15, 11},
- {10, 1, 7, 2, 15, 12, 20, 12, 3, 14, 15, 11},
- {10, 1, 7, 2, 15, 14, 21, 12, 3, 14, 15, 11},
- {10, 1, 7, 2, 15, 14, 21, 12, 3, 14, 15, 11},
- {10, 1, 7, 2, 15, 14, 22, 12, 3, 14, 15, 11},
- {10, 1, 7, 2, 15, 14, 22, 12, 3, 14, 15, 11},
- {10, 1, 7, 2, 15, 14, 23, 12, 3, 14, 15, 11},
- {10, 1, 7, 2, 15, 14, 23, 12, 3, 14, 15, 11},
- {10, 1, 7, 2, 15, 14, 24, 12, 3, 14, 15, 11},
- {10, 1, 7, 2, 15, 14, 24, 12, 3, 14, 15, 11},
- {10, 1, 7, 2, 15, 14, 25, 12, 3, 14, 15, 11},
- {10, 1, 7, 2, 15, 14, 25, 12, 3, 14, 15, 11},
- {10, 1, 7, 2, 15, 14, 26, 12, 3, 14, 15, 11},
- {10, 1, 7, 2, 15, 14, 26, 12, 3, 14, 15, 11},
- {10, 3, 7, 3, 15, 12, 17, 12, 3, 14, 15, 11},
- {10, 3, 7, 3, 15, 12, 17, 12, 3, 14, 15, 11},
- {10, 3, 7, 3, 15, 12, 17, 12, 3, 14, 15, 11},
- {10, 3, 7, 3, 15, 12, 18, 12, 3, 14, 15, 11},
- {10, 3, 7, 3, 15, 12, 18, 12, 3, 14, 15, 11},
- {10, 3, 7, 3, 15, 12, 18, 12, 3, 14, 15, 11},
- {10, 3, 7, 3, 15, 12, 18, 12, 3, 14, 15, 11},
- {10, 3, 7, 3, 15, 12, 19, 12, 3, 14, 15, 11},
- {10, 3, 7, 3, 15, 12, 19, 12, 3, 14, 15, 11} };
-#endif
-
-#endif /* INCLUDED_AD9361_SYNTH_LUT_HPP */
diff --git a/firmware/fx3/b200/b200_ad9361.c b/firmware/fx3/b200/b200_ad9361.c
deleted file mode 100644
index ebb0dda70..000000000
--- a/firmware/fx3/b200/b200_ad9361.c
+++ /dev/null
@@ -1,57 +0,0 @@
-//
-// Copyright 2013-2014 Ettus Research LLC
-//
-
-#include "cyu3error.h"
-#include "cyu3i2c.h"
-#include "cyu3spi.h"
-#include "cyu3os.h"
-#include "cyu3pib.h"
-#include "cyu3system.h"
-#include "cyu3usb.h"
-#include "cyu3utils.h"
-#include "pib_regs.h"
-#include "b200_vrq.h"
-#include <stdint.h>
-
-#define true CyTrue
-#define false CyFalse
-
-typedef CyBool_t bool;
-
-/* Fast sqrt() - precision can be improved by increasing
- * the number of iterations
- */
-float ad9361_sqrt(const float number)
-{
- uint32_t i;
- float x2, y;
-
- x2 = number * 0.5F;
- y = number;
- i = *(uint32_t *) &y;
- i = 0x5f3759df - ( i >> 1 );
- y = *(float *) &i;
- y = y * (1.5F - (x2 * y * y));
-
- return number * y;
-}
-
-void ad9361_msleep(const unsigned millis)
-{
- CyU3PThreadSleep(millis);
-}
-
-#define AD9361_MIN(a, b) CY_U3P_MIN(a, b)
-#define AD9361_MAX(a, b) CY_U3P_MAX(a, b)
-
-#define AD9361_CEIL_INT(a) ((int)(a+1))
-#define AD9361_FLOOR_INT(a) ((int)(a))
-
-#define AD9361_CLOCKING_MODE 0
-
-#define AD9361_RX_BAND_EDGE0 2.2e9
-#define AD9361_RX_BAND_EDGE1 4e9
-#define AD9361_TX_BAND_EDGE 2.5e9
-
-#include "../ad9361/lib/ad9361_impl.c"
diff --git a/firmware/fx3/b200/b200_main.c b/firmware/fx3/b200/b200_main.c
index 38af9ed4e..077ee251b 100644
--- a/firmware/fx3/b200/b200_main.c
+++ b/firmware/fx3/b200/b200_main.c
@@ -12,7 +12,6 @@
#include "b200_main.h"
#include "b200_gpifconfig.h"
-#include "b200_vrq.h"
#include "b200_i2c.h"
#include "cyu3dma.h"
@@ -28,9 +27,6 @@
#include "cyfxversion.h"
#include "pib_regs.h"
-#include <ad9361_transaction.h>
-#include <ad9361_dispatch.h>
-
#define STATIC_SAVER static // Save stack space for variables in a non-re-entrant function (e.g. USB setup callback)
/*
@@ -40,7 +36,6 @@
//#define HAS_HEAP // This requires memory to be set aside for the heap (e.g. required for printing floating-point numbers). You can apply the accompanying patch ('fx3_mem_map.patch') to fx3.ld & cyfxtx.c to create one.
//#define ENABLE_MSG // This will cause the compiled code to exceed the default text memory area (SYS_MEM). You can apply the accompanying patch ('fx3_mem_map.patch') to fx3.ld & cyfxtx.c to resize the memory map so it will fit.
-//#define ENABLE_AD9361_LOGGING // When enabling this, you *must* enable the heap with HAS_HEAP (and apply the accompanying memory map patch 'fx3_mem_map.patch') otherwise the FW will crash when printing a floating-point number (as there is no heap for _sbrk by default)
//#define ENABLE_MANUAL_DMA_XFER
//#define ENABLE_MANUAL_DMA_XFER_FROM_HOST
//#define ENABLE_MANUAL_DMA_XFER_TO_HOST
@@ -69,13 +64,6 @@
#ifdef ENABLE_MSG
#pragma message "msg enabled"
-
-#ifdef ENABLE_AD9361_LOGGING
-#pragma message " AD9361 logging enabled"
-#else
-#pragma message " AD9361 logging disabled"
-#endif // ENABLE_AD9361_LOGGING
-
#else
#pragma message "msg disabled"
#endif // ENABLE_MSG
@@ -156,21 +144,15 @@ static CyU3PThread thread_fpga_config;
#ifdef ENABLE_RE_ENUM_THREAD
static CyU3PThread thread_re_enum;
#endif // ENABLE_RE_ENUM_THREAD
-static CyU3PThread thread_ad9361;
static CyBool_t g_app_running = CyFalse;
static uint8_t g_fx3_state = STATE_UNDEFINED;
-//#define AD9361_DISPATCH_PACKET_SIZE 64 // Must fit into smallest VREQ
#define USB2_VREQ_BUF_SIZE 64
#define USB3_VREQ_BUF_SIZE 512
#define MIN_VREQ_BUF_SIZE USB2_VREQ_BUF_SIZE
#define MAX_VREQ_BUF_SIZE USB3_VREQ_BUF_SIZE
-#if AD9361_DISPATCH_PACKET_SIZE > MIN_VREQ_BUF_SIZE
-#error "AD9361_DISPATCH_PACKET_SIZE must be less than MIN_VREQ_BUF_SIZE"
-#endif
-
static uint16_t g_vendor_req_buff_size = MIN_VREQ_BUF_SIZE;
static uint8_t g_vendor_req_buffer[MAX_VREQ_BUF_SIZE] __attribute__ ((aligned (32)));
static uint16_t g_vendor_req_read_count = 0;
@@ -180,8 +162,6 @@ static uint8_t fw_hash[4] __attribute__ ((aligned (32)));
static uint8_t compat_num[2];
static uint32_t g_fpga_programming_write_count = 0;
-static char g_ad9361_response[AD9361_DISPATCH_PACKET_SIZE];
-
#define COUNTER_MAGIC 0x10024001
#define LOG_BUFFER_SIZE /*MAX_VREQ_BUF_SIZE*/1024 // [Max vreq @ USB3 (64 @ USB2)] Can be larger
static char log_buffer[LOG_BUFFER_SIZE];
@@ -685,214 +665,6 @@ void gpio_interrupt_callback(uint8_t gpio_id) {
}
-// The following two functions are intended to replace write_spi_to_ad9361
-// and read_spi_from_ad9361 after the code porting is complete
-/*! Perform a register write to the ad9361 chip.
- * A pointer to the register address followed by data will be provided as
- * parameter
- */
-static void write_ad9361_reg(uint16_t reg, uint8_t val) {
-
- CyBool_t gpio_value;
- uint8_t write_buff[3];
- MAKE_AD9361_WRITE(write_buff, reg, val)
-
- // Number of bytes we are writing.
- uint8_t num_bytes = 3; //register address = 2 bytes, data = 1 byte
-
- CyU3PGpioSetValue(GPIO_FX3_CE, 0);
-
- // Clock the data out to AD9361 over SPI.
- int8_t bit_count, byte_count;
- for(byte_count = 0; byte_count < num_bytes; byte_count++) {
-
- uint8_t miso = 0x00;
- uint8_t data = write_buff[byte_count];
-
- for(bit_count = 7; bit_count >= 0; bit_count--) {
- CyU3PGpioSetValue(GPIO_FX3_SCLK, 1);
- CyU3PGpioSetValue(GPIO_FX3_MOSI, ((data >> bit_count) & 0x01));
- CyU3PGpioSetValue(GPIO_FX3_SCLK, 0);
-
- CyU3PGpioGetValue(GPIO_FX3_MISO, &gpio_value);
- if(gpio_value) {
- miso |= (1 << bit_count);
- }
- }
- // FIXME: Determine what to do with miso value;
- }
-
- CyU3PGpioSetValue(GPIO_FX3_MOSI, 0);
- CyU3PGpioSetValue(GPIO_FX3_CE, 1);
-}
-
-/*! Perform a register read from to the ad9361 chip.
- * A pointer to register address will be provided as parameter
- * The function returns the value read from the register
- */
-static uint8_t read_ad9361_reg(uint16_t reg) {
-
- CyBool_t gpio_value;
- uint8_t write_buff[2];
- MAKE_AD9361_READ(write_buff, reg)
-
- // Each 9361 register read returns 1 byte
-
- CyU3PGpioSetValue(GPIO_FX3_CE, 0);
-
- // Write the two register address bytes.
- int8_t bit_count, byte_count;
- for(byte_count = 0; byte_count < 2; byte_count++) {
-
- uint8_t miso = 0x00;
- uint8_t data = write_buff[byte_count];
-
- for(bit_count = 7; bit_count >= 0; bit_count--) {
- CyU3PGpioSetValue(GPIO_FX3_SCLK, 1);
- CyU3PGpioSetValue(GPIO_FX3_MOSI, ((data >> bit_count) & 0x01));
- CyU3PGpioSetValue(GPIO_FX3_SCLK, 0);
-
- CyU3PGpioGetValue(GPIO_FX3_MISO, &gpio_value);
- if(gpio_value) {
- miso |= (1 << bit_count);
- }
- }
- // FIXME: Determine what to do with miso value;
- }
-
- CyU3PGpioSetValue(GPIO_FX3_MOSI, 0);
-
- // Read the response data from the chip.
- uint8_t data = 0x00;
-
- for(bit_count = 7; bit_count >= 0; bit_count--) {
- CyU3PGpioSetValue(GPIO_FX3_SCLK, 1);
-
- CyU3PGpioGetValue(GPIO_FX3_MISO, &gpio_value);
- if(gpio_value) {
- data |= (1 << bit_count);
- }
-
- CyU3PGpioSetValue(GPIO_FX3_SCLK, 0);
- }
- CyU3PGpioSetValue(GPIO_FX3_CE, 1);
- return data;
-}
-
-/*! Perform a register write to the ad9361 chip.
- *
- * This function will take data received over EP0, as a vendor request, and
- * perform a SPI write to ad9361. This requires that the FPGA be passing these
- * SPI lines through to the ad9361 chip. */
-void write_spi_to_ad9361(void) {
-
- CyBool_t gpio_value;
-
- /* Pull out the number of bytes we are writing. */
- uint8_t num_bytes = ((g_vendor_req_buffer[0] & 0x70) >> 4) + 1;
-
- CyU3PGpioSetValue(GPIO_FX3_CE, 0);
-
- /* Clock the data out to AD9361 over SPI. */
- int8_t bit_count, byte_count;
- for(byte_count = 0; byte_count < (num_bytes + 2); byte_count++) {
-
- uint8_t miso = 0x00;
- uint8_t data = g_vendor_req_buffer[byte_count];
-
- for(bit_count = 7; bit_count >= 0; bit_count--) {
- CyU3PGpioSetValue(GPIO_FX3_SCLK, 1);
- CyU3PGpioSetValue(GPIO_FX3_MOSI, ((data >> bit_count) & 0x01));
- CyU3PGpioSetValue(GPIO_FX3_SCLK, 0);
-
- CyU3PGpioGetValue(GPIO_FX3_MISO, &gpio_value);
- if(gpio_value) {
- miso |= (1 << bit_count);
- }
- }
-
- g_vendor_req_buffer[byte_count] = miso;
- }
-
- CyU3PGpioSetValue(GPIO_FX3_MOSI, 0);
- CyU3PGpioSetValue(GPIO_FX3_CE, 1);
-}
-
-
-/*! Perform a register read from the ad9361 chip.
- *
- * This function will write a command to the ad9361 chip, performing a register
- * read, and store the returned data in the vendor request buffer. This data can
- * then be retrieved with another vendor request from the host.
- *
- * This requires that the FPGA be passing these SPI lines through to the
- * ad9361 chip. */
-void read_spi_from_ad9361(void) {
-
- CyBool_t gpio_value;
-
- /* Pull out the number of bytes we are reading. */
- uint8_t num_bytes = ((g_vendor_req_buffer[0] & 0x70) >> 4) + 1;
-
- CyU3PGpioSetValue(GPIO_FX3_CE, 0);
-
- /* Write the two instruction bytes. */
- int8_t bit_count, byte_count;
- for(byte_count = 0; byte_count < 2; byte_count++) {
-
- uint8_t miso = 0x00;
- uint8_t data = g_vendor_req_buffer[byte_count];
-
- for(bit_count = 7; bit_count >= 0; bit_count--) {
- CyU3PGpioSetValue(GPIO_FX3_SCLK, 1);
- CyU3PGpioSetValue(GPIO_FX3_MOSI, ((data >> bit_count) & 0x01));
- CyU3PGpioSetValue(GPIO_FX3_SCLK, 0);
-
- CyU3PGpioGetValue(GPIO_FX3_MISO, &gpio_value);
- if(gpio_value) {
- miso |= (1 << bit_count);
- }
- }
-
- g_vendor_req_buffer[byte_count] = miso;
- }
-
- CyU3PGpioSetValue(GPIO_FX3_MOSI, 0);
-
- /* Read the response data from the chip. */
- for(byte_count = 0; byte_count < num_bytes; byte_count++) {
-
- uint8_t data = 0x00;
-
- for(bit_count = 7; bit_count >= 0; bit_count--) {
- CyU3PGpioSetValue(GPIO_FX3_SCLK, 1);
-
- CyU3PGpioGetValue(GPIO_FX3_MISO, &gpio_value);
- if(gpio_value) {
- data |= (1 << bit_count);
- }
-
- CyU3PGpioSetValue(GPIO_FX3_SCLK, 0);
- }
-
- g_vendor_req_buffer[byte_count + 2] = data;
- }
-
- CyU3PGpioSetValue(GPIO_FX3_CE, 1);
-}
-
-
-uint32_t ad9361_transact_spi(const uint32_t bits) {
- // FIXME: Could make this more sane
- if ((bits >> 23) & 0x1)
- {
- write_ad9361_reg(bits >> 8, bits & 0xff);
- return 0;
- }
- return read_ad9361_reg(bits >> 8);
-}
-
-
/*! Stops the application, and destroys transport data structures.
*
* This function is essentially a destructor for all transport configurations.
@@ -1891,22 +1663,6 @@ CyBool_t usb_setup_callback(uint32_t data0, uint32_t data1) {
break;
}
- case B200_VREQ_SPI_WRITE_AD9361: {
- CyU3PUsbGetEP0Data(g_vendor_req_buff_size, g_vendor_req_buffer, \
- &read_count);
-
- write_spi_to_ad9361(); // FIXME: Should have g_vendor_req_buffer & read_count passed in as args
- break;
- }
-
- case B200_VREQ_SPI_READ_AD9361: {
- CyU3PUsbGetEP0Data(g_vendor_req_buff_size, g_vendor_req_buffer, \
- &read_count);
-
- read_spi_from_ad9361(); // FIXME: Should have g_vendor_req_buffer & read_count passed in as args
- break;
- }
-
case B200_VREQ_LOOP_CODE: {
CyU3PUsbSendEP0Data(g_vendor_req_buff_size, g_vendor_req_buffer);
break;
@@ -2152,55 +1908,6 @@ CyBool_t usb_setup_callback(uint32_t data0, uint32_t data1) {
break;
}
- case B200_VREQ_AD9361_CTRL_READ: {
- CyU3PUsbSendEP0Data(g_vendor_req_buff_size, g_vendor_req_buffer);
- /*
- * This is where vrb gets sent back to the host
- */
- break;
- }
-
- case B200_VREQ_AD9361_CTRL_WRITE: {
- CyU3PUsbGetEP0Data(g_vendor_req_buff_size, g_vendor_req_buffer, &read_count);
- CyU3PEventSet(&g_event_usb_config, EVENT_AD9361_XACT_INIT, CYU3P_EVENT_OR);
-
- uint32_t event_flag;
- CyU3PEventGet(&g_event_usb_config, EVENT_AD9361_XACT_DONE, CYU3P_EVENT_AND_CLEAR, &event_flag, CYU3P_WAIT_FOREVER);
-
- memcpy(g_vendor_req_buffer, g_ad9361_response, AD9361_DISPATCH_PACKET_SIZE);
- break;
- }
-
- case B200_VREQ_AD9361_LOOPBACK: {
- CyU3PUsbGetEP0Data(g_vendor_req_buff_size, g_vendor_req_buffer, &read_count);
-
- if (read_count > 0) {
- ad9361_transaction_t xact;
- memset(&xact, 0x00, sizeof(xact));
-
- xact.version = AD9361_TRANSACTION_VERSION;
- xact.action = AD9361_ACTION_SET_CODEC_LOOP;
- xact.sequence = 0;
- xact.value.codec_loop = g_vendor_req_buffer[0];
-
- memcpy(g_vendor_req_buffer, &xact, sizeof(xact));
-
- CyU3PEventSet(&g_event_usb_config, EVENT_AD9361_XACT_INIT, CYU3P_EVENT_OR);
-
- uint32_t event_flag;
- CyU3PEventGet(&g_event_usb_config, EVENT_AD9361_XACT_DONE, CYU3P_EVENT_AND_CLEAR, &event_flag, CYU3P_WAIT_FOREVER);
-
- memcpy(g_vendor_req_buffer, g_ad9361_response, AD9361_DISPATCH_PACKET_SIZE);
-
- if (xact.value.codec_loop)
- msg("Codec loopback ON");
- else
- msg("Codec loopback OFF");
- }
-
- break;
- }
-
default:
msg("! Unknown VREQ %02X", (uint32_t)bRequest);
handled = CyFalse;
@@ -2684,23 +2391,6 @@ void thread_main_app_entry(uint32_t input) {
}
}
-
-void thread_ad9361_entry(uint32_t input) {
- uint32_t event_flag;
-
- //msg("thread_ad9361_entry");
-
- while (1) {
- if (CyU3PEventGet(&g_event_usb_config, \
- EVENT_AD9361_XACT_INIT, CYU3P_EVENT_AND_CLEAR, \
- &event_flag, CYU3P_WAIT_FOREVER) == CY_U3P_SUCCESS) {
- ad9361_dispatch((const char*)g_vendor_req_buffer, g_ad9361_response);
-
- CyU3PEventSet(&g_event_usb_config, EVENT_AD9361_XACT_DONE, CYU3P_EVENT_OR);
- }
- }
-}
-
static uint16_t g_poll_last_phy_error_count = 0, g_poll_last_link_error_count = 0;
static uint32_t g_poll_last_phy_error_status = 0;
@@ -2966,7 +2656,7 @@ void thread_fpga_sb_poll_entry(uint32_t input) {
* If thread creation fails, lock the system and force a power reset.
*/
void CyFxApplicationDefine(void) {
- void *app_thread_ptr, *fpga_thread_ptr, *ad9361_thread_ptr;
+ void *app_thread_ptr, *fpga_thread_ptr;
#ifdef ENABLE_RE_ENUM_THREAD
void *re_enum_thread_ptr;
#endif // ENABLE_RE_ENUM_THREAD
@@ -2975,9 +2665,6 @@ void CyFxApplicationDefine(void) {
#endif // ENABLE_FPGA_SB
g_counters.magic = COUNTER_MAGIC;
-#ifdef ENABLE_AD9361_LOGGING
- ad9361_set_msgfn(msg);
-#endif // ENABLE_AD9361_LOGGING
memset(&g_config, 0xFF, sizeof(g_config)); // Initialise to -1
CyU3PMutexCreate(&g_log_lock, CYU3P_NO_INHERIT);
@@ -3032,7 +2719,6 @@ void CyFxApplicationDefine(void) {
#ifdef ENABLE_RE_ENUM_THREAD
re_enum_thread_ptr = CyU3PMemAlloc(APP_THREAD_STACK_SIZE);
#endif // ENABLE_RE_ENUM_THREAD
- ad9361_thread_ptr = CyU3PMemAlloc(APP_THREAD_STACK_SIZE);
#ifdef ENABLE_FPGA_SB
fpga_sb_poll_thread_ptr = CyU3PMemAlloc(APP_THREAD_STACK_SIZE);
#endif // ENABLE_FPGA_SB
@@ -3077,18 +2763,6 @@ void CyFxApplicationDefine(void) {
CYU3P_NO_TIME_SLICE,
CYU3P_AUTO_START);
#endif // ENABLE_RE_ENUM_THREAD
- /* Create thread to handle AD9361 transactions */
- if (ad9361_thread_ptr != NULL)
- CyU3PThreadCreate(&thread_ad9361,
- "500:B200 AD9361",
- thread_ad9361_entry,
- 0,
- ad9361_thread_ptr,
- APP_THREAD_STACK_SIZE,
- THREAD_PRIORITY,
- THREAD_PRIORITY,
- CYU3P_NO_TIME_SLICE,
- CYU3P_AUTO_START);
#ifdef ENABLE_FPGA_SB
/* Create thread to handling Settings Bus logging/transactions */
if (fpga_sb_poll_thread_ptr != NULL)
diff --git a/firmware/fx3/b200/b200_main.h b/firmware/fx3/b200/b200_main.h
index 7971c1625..2c6f178ec 100644
--- a/firmware/fx3/b200/b200_main.h
+++ b/firmware/fx3/b200/b200_main.h
@@ -10,7 +10,7 @@
#include "cyu3types.h"
#include "cyu3usbconst.h"
-#define FX3_COMPAT_MAJOR (uint8_t)(4)
+#define FX3_COMPAT_MAJOR (uint8_t)(7)
#define FX3_COMPAT_MINOR (uint8_t)(0)
/* GPIO Pins */
@@ -67,16 +67,11 @@
#define B200_VREQ_WRITE_SB (uint8_t)(0x29)
#define B200_VREQ_SET_SB_BAUD_DIV (uint8_t)(0x30)
#define B200_VREQ_FLUSH_DATA_EPS (uint8_t)(0x31)
-#define B200_VREQ_SPI_WRITE_AD9361 (uint8_t)(0x32)
-#define B200_VREQ_SPI_READ_AD9361 (uint8_t)(0x42)
#define B200_VREQ_FPGA_CONFIG (uint8_t)(0x55)
#define B200_VREQ_TOGGLE_FPGA_RESET (uint8_t)(0x62)
#define B200_VREQ_TOGGLE_GPIF_RESET (uint8_t)(0x72)
#define B200_VREQ_GET_USB_SPEED (uint8_t)(0x80)
#define B200_VREQ_GET_STATUS (uint8_t)(0x83)
-#define B200_VREQ_AD9361_CTRL_WRITE (uint8_t)(0x90)
-#define B200_VREQ_AD9361_CTRL_READ (uint8_t)(0x91)
-#define B200_VREQ_AD9361_LOOPBACK (uint8_t)(0x92)
#define B200_VREQ_RESET_DEVICE (uint8_t)(0x99)
#define B200_VREQ_EEPROM_WRITE (uint8_t)(0xBA)
#define B200_VREQ_EEPROM_READ (uint8_t)(0xBB)
@@ -86,8 +81,6 @@
#define EVENT_GPIO_INITB_RISE (1 << 3)
#define EVENT_FPGA_CONFIG (1 << 4)
#define EVENT_RE_ENUM (1 << 5)
-#define EVENT_AD9361_XACT_INIT (1 << 6)
-#define EVENT_AD9361_XACT_DONE (1 << 7)
/* FX3 States */
diff --git a/firmware/fx3/b200/b200_vrq.h b/firmware/fx3/b200/b200_vrq.h
deleted file mode 100644
index d1f79f0ad..000000000
--- a/firmware/fx3/b200/b200_vrq.h
+++ /dev/null
@@ -1,21 +0,0 @@
-//
-// Copyright 2013-2014 Ettus Research LLC
-//
-
-/* This file defines b200 vendor requests handlers, version 1
- */
-#ifndef B200_VRQ_H
-#define B200_VRQ_H
-
-uint32_t ad9361_transact_spi(const uint32_t bits);
-
-// note: for a write instruction bit 7 from byte 0 is set to 1
-#define MAKE_AD9361_WRITE(dest, reg, val) {dest[0] = 0x80 | ((reg >> 8) & 0x3F); \
- dest[1] = reg & 0xFF; \
- dest[2] = val;}
-#define MAKE_AD9361_READ(dest, reg) {dest[0] = (reg >> 8) & 0x3F; \
- dest[1] = reg & 0xFF;}
-
-#endif //B200_VRQ_H
-
-
diff --git a/firmware/fx3/b200/makefile b/firmware/fx3/b200/makefile
index d693db076..22eb1bbcc 100644
--- a/firmware/fx3/b200/makefile
+++ b/firmware/fx3/b200/makefile
@@ -19,13 +19,9 @@ MODULE = b200_main
SOURCE += $(MODULE).c
SOURCE += b200_usb_descriptors.c
-SOURCE += b200_ad9361.c
SOURCE += b200_i2c.c
-INCLUDES = b200_main.h b200_vrq.h b200_gpifconfig.h b200_i2c.h
-INCLUDES += ../ad9361/include/ad9361_transaction.h
-
-INCFLAGS = -I ../ad9361/include
+INCLUDES = b200_main.h b200_gpifconfig.h b200_i2c.h
LDLIBS += \
"$$ARMGCC_INSTALL_PATH"/arm-none-eabi/lib/libm.a