Commit f2323010 authored by Tristan Gingold's avatar Tristan Gingold

software: change API to support smooth phase changes.

parent 08d1bc0b
......@@ -3,8 +3,8 @@ VMEBRIDGE=/acc/local/L867/drv/vmebus/1.0.1
PREFIX=/usr/local
CC=gcc
CFLAGS=-g -O -Wall --std=c99 -I$(VMEBRIDGE)/include/vmebus -I../include
LDFLAGS=$(VMEBRIDGE)/lib/libvmebus.a -lrt
CFLAGS=-g -O -Wall --std=gnu99 -I$(VMEBRIDGE)/include/vmebus -I../include
LDFLAGS=$(VMEBRIDGE)/lib/libvmebus.a -lrt -lm
OBJS_LIB=init.o board.o oc_spi16.o ad9910_init.o dac_timing.o
OBJS_HOST=host.o
......
......@@ -130,7 +130,8 @@ libwr2rf_dds_init(struct libwr2rf_dev *dev, unsigned io_update)
}
int
libwr2rf_dds_freq_init(struct libwr2rf_dev *dev, uint64_t freq, unsigned io_update)
libwr2rf_dds_freq_init(struct libwr2rf_dev *dev,
uint64_t freq, unsigned io_update)
{
int res;
......
......@@ -2,6 +2,8 @@
#include <assert.h>
#include <stdio.h>
#include <string.h>
#define _USE_MATH_DEFINES
#include <math.h>
#include "libwr2rf/board.h"
#include "libwr2rf/api.h"
#include "regs.h"
......@@ -196,27 +198,149 @@ void libwr2rf_dac_write(struct libwr2rf_dev *dev, unsigned ch, unsigned reg, uin
NULL);
}
int libwr2rf_dac_iqsetpoint(struct libwr2rf_dev *dev, unsigned ch, unsigned igain, unsigned qgain)
#define DAC_IQGAIN_MAX 0x7fff
#define DAC_IQGAIN_MIN 0x8000
/* Convert to short.
The dynamic is asymetric. */
static int dac_convert(float gain)
{
if (gain >= 0.0)
return gain * DAC_IQGAIN_MAX;
else
return gain * DAC_IQGAIN_MIN;
}
static int dac_check_range(int gain)
{
if (gain > DAC_IQGAIN_MAX
|| gain < -DAC_IQGAIN_MIN)
return 0;
return 1;
}
int libwr2rf_dac_set_phase_amp(struct libwr2rf_dev *dev, unsigned ch,
float amplitude, float phase, unsigned verbose)
{
unsigned igain_addr = 0;
unsigned qgain_addr = 0;
if (!(amplitude >= 0.0 && amplitude <= 1.0))
return -1;
if (!(phase >= 0.0 && phase <= 360.0))
return -1;
float phase_rad = phase * M_PI / 180.0;
float igainf = amplitude * cosf (phase_rad);
float qgainf = amplitude * sinf (phase_rad);
int igain = dac_convert(igainf);
int qgain = dac_convert(qgainf);
if (!dac_check_range(igain) || !dac_check_range(qgain))
return -1;
switch (ch) {
if (verbose)
fprintf(stderr,
"DAC IQ %u: ampl=%3.1f, phase=%3.1f, igain=%04x qgain=%04x\n",
ch, amplitude, phase,
(unsigned short)igain, (unsigned short)qgain);
unsigned igain_addr;
unsigned qgain_addr;
unsigned phase_addr;
unsigned updat_addr;
switch (ch) {
case 1:
igain_addr = WR2RF_VME_REGS_CTRL + WR2RF_CTRL_REGS_RF1_IQDAC_IGAIN;
qgain_addr = WR2RF_VME_REGS_CTRL + WR2RF_CTRL_REGS_RF1_IQDAC_QGAIN;
phase_addr = WR2RF_VME_REGS_CTRL + WR2RF_CTRL_REGS_RF1_IQDAC_PHASE;
updat_addr = WR2RF_VME_REGS_CTRL + WR2RF_CTRL_REGS_RF1_IQDAC_PHASE_UPDATE;
break;
case 2:
igain_addr = WR2RF_VME_REGS_CTRL + WR2RF_CTRL_REGS_RF2_IQDAC_IGAIN;
qgain_addr = WR2RF_VME_REGS_CTRL + WR2RF_CTRL_REGS_RF2_IQDAC_QGAIN;
phase_addr = WR2RF_VME_REGS_CTRL + WR2RF_CTRL_REGS_RF2_IQDAC_PHASE;
updat_addr = WR2RF_VME_REGS_CTRL + WR2RF_CTRL_REGS_RF2_IQDAC_PHASE_UPDATE;
break;
default:
return LIBWR2RF_ERROR_BAD_ID;
}
libwr2rf_write16(dev, igain_addr, igain);
libwr2rf_write16(dev, qgain_addr, qgain);
return 0;
libwr2rf_write16(dev, igain_addr, igain);
libwr2rf_write16(dev, qgain_addr, qgain);
libwr2rf_write16(dev, phase_addr, (short)phase);
libwr2rf_write16(dev, updat_addr,
WR2RF_CTRL_REGS_RF1_IQDAC_PHASE_UPDATE_VALID);
return 0;
}
int libwr2rf_dac_reset_phase_amp(struct libwr2rf_dev *dev, unsigned ch,
float amplitude, float phase)
{
return libwr2rf_dac_set_phase_amp(dev, ch, amplitude, phase, 0);
}
int libwr2rf_dac_phase_amp_ext(struct libwr2rf_dev *dev, unsigned ch,
float amplitude, float phase, unsigned verbose)
{
const int phase_step = 15;
int iphase;
unsigned phase_addr;
int last_phase;
int res;
/* According to fmod:
the returned value has the same sign as x and a magnitude
less than the magnitude of y. */
phase = fmodf(phase, 360.0);
if (phase < 0.0)
phase += 360.0;
/* IPHASE is in 0 .. 360. */
iphase = (int)phase;
/* Current phase. */
switch (ch) {
case 1:
phase_addr = WR2RF_VME_REGS_CTRL + WR2RF_CTRL_REGS_RF1_IQDAC_PHASE;
break;
case 2:
phase_addr = WR2RF_VME_REGS_CTRL + WR2RF_CTRL_REGS_RF2_IQDAC_PHASE;
break;
default:
return LIBWR2RF_ERROR_BAD_ID;
}
last_phase = libwr2rf_read16(dev, phase_addr);
while (1) {
int dph = iphase - last_phase;
if ((dph >= 0 && dph < phase_step)
|| (dph < 0 && dph > -phase_step)
|| (dph >= 0 && dph >= 360 - phase_step)
|| (dph <= 0 && dph <= -360 + phase_step)) {
/* Smooth enough, apply directly. */
return libwr2rf_dac_set_phase_amp(dev, ch, amplitude, phase, verbose);
}
if ((dph >= 0 && dph <= 180) || (dph < 0 && dph < -180))
last_phase += phase_step;
else
last_phase -= phase_step;
res = libwr2rf_dac_set_phase_amp(dev, ch, amplitude, last_phase, verbose);
if (res != 0)
return res;
/* A delay is implicit through the slow VME access (about 300ns per
access). */
}
}
int libwr2rf_dac_phase_amp(struct libwr2rf_dev *dev, unsigned ch,
float amplitude, float phase)
{
return libwr2rf_dac_phase_amp_ext(dev, ch, amplitude, phase, 0);
}
unsigned libwr2rf_read_fwversion(struct libwr2rf_dev *dev)
......
......@@ -239,8 +239,8 @@ libwr2rf_api_init (struct libwr2rf_dev *dev)
libwr2rf_iodelay_init(dev);
/* Command dac-iqsetpoint */
libwr2rf_dac_iqsetpoint(dev, 1, 0x4000, 0);
libwr2rf_dac_iqsetpoint(dev, 2, 0x4000, 0);
libwr2rf_dac_reset_phase_amp(dev, 1, 0.5, 0.0);
libwr2rf_dac_reset_phase_amp(dev, 2, 0.5, 0.0);
/* Commands:
dds-init (TODO: io_update)
......
......@@ -64,8 +64,16 @@ int libwr2rf_check_link_time(struct libwr2rf_dev *dev);
/* Read the mac address (6 bytes). Can be used as unique id. */
int libwr2rf_get_mac(struct libwr2rf_dev *dev, unsigned char *mac);
/* DAC IQ set points. */
int libwr2rf_dac_iqsetpoint(struct libwr2rf_dev *dev, unsigned ch, unsigned igain, unsigned qgain);
/* Set DAC amplitude and phase. Amplitude must be between 0.0 and 1.0,
phase must be between -360.0 and 360.0
Do a smooth transition in case of phase jump. */
int libwr2rf_dac_phase_amp(struct libwr2rf_dev *dev, unsigned ch,
float amplitude, float phase);
/* Like the previous function but apply immediately. Can only be used
when the trigger units are not enabled. */
int libwr2rf_dac_reset_phase_amp(struct libwr2rf_dev *dev, unsigned ch,
float amplitude, float phase);
/* Mask (or not mask) NCO resets. */
int libwr2rf_nco_reset(struct libwr2rf_dev *dev, unsigned ch, unsigned en);
......
......@@ -25,6 +25,9 @@ void libwr2rf_dds_write(struct libwr2rf_dev *dev, unsigned reg,
uint64_t value, unsigned nbits);
uint64_t libwr2rf_dds_read(struct libwr2rf_dev *dev, unsigned reg, unsigned nbits);
int libwr2rf_dds_freq_init(struct libwr2rf_dev *dev,
uint64_t freq, unsigned io_update);
/* Trigger ioupdate. */
void libwr2rf_dds_ioupdate(struct libwr2rf_dev *dev);
......@@ -42,6 +45,10 @@ int libwr2rf_dac_port_timing(struct libwr2rf_dev *dev, unsigned ch);
int libwr2rf_dac_validate_timing(struct libwr2rf_dev *dev, unsigned ch);
void libwr2rf_dac_set_timing_delay(struct libwr2rf_dev *dev, unsigned ch, unsigned v);
/* Adjust phase and amplitude of DAC CH. */
int libwr2rf_dac_phase_amp_ext(struct libwr2rf_dev *dev, unsigned ch,
float amplitude, float phase, unsigned verbose);
/* Raw 32bit IOs through the wb16 to wb32 bridge. */
uint32_t libwr2rf_16x32_read32(struct libwr2rf_dev *dev, unsigned off);
void libwr2rf_16x32_write32(struct libwr2rf_dev *dev, unsigned off,
......
......@@ -8,6 +8,7 @@
#include <termios.h>
#include <errno.h>
#include <ctype.h>
#include <math.h>
#include <arpa/inet.h>
#include "libwr2rf/io.h"
#include "libwr2rf/host.h"
......@@ -1779,6 +1780,8 @@ static void
dac_iqsetpoint (struct libwr2rf_dev *dev, int argc, char **argv)
{
int ch;
unsigned igain_addr;
unsigned qgain_addr;
if (argc != 2 && argc != 4) {
printf ("usage: %s 1|2 [i_setpoint q_setpoint]\n", argv[0]);
......@@ -1786,37 +1789,88 @@ dac_iqsetpoint (struct libwr2rf_dev *dev, int argc, char **argv)
}
ch = parse_dac_channel(argv[1]);
if (ch < 0)
if (ch < 1 || ch > 2)
return;
if (argc == 4) {
unsigned igain = 0;
unsigned qgain = 0;
unsigned update_addr;
unsigned igain;
unsigned qgain;
if (ch == DAC1_CS) {
igain_addr = WR2RF_VME_REGS_CTRL + WR2RF_CTRL_REGS_RF1_IQDAC_IGAIN_ARM;
qgain_addr = WR2RF_VME_REGS_CTRL + WR2RF_CTRL_REGS_RF1_IQDAC_QGAIN_ARM;
update_addr = WR2RF_VME_REGS_CTRL + WR2RF_CTRL_REGS_RF1_IQDAC_PHASE_UPDATE;
} else {
igain_addr = WR2RF_VME_REGS_CTRL + WR2RF_CTRL_REGS_RF2_IQDAC_IGAIN_ARM;
qgain_addr = WR2RF_VME_REGS_CTRL + WR2RF_CTRL_REGS_RF2_IQDAC_QGAIN_ARM;
update_addr = WR2RF_VME_REGS_CTRL + WR2RF_CTRL_REGS_RF2_IQDAC_PHASE_UPDATE;
}
igain = strtoul(argv[2], NULL, 0);
qgain = strtoul(argv[3], NULL, 0);
if (libwr2rf_dac_iqsetpoint(dev, ch, igain, qgain) != 0) {
printf("error\n");
return;
}
libwr2rf_write16(dev, igain_addr, igain);
libwr2rf_write16(dev, qgain_addr, qgain);
libwr2rf_write16(dev, update_addr, WR2RF_CTRL_REGS_RF2_IQDAC_PHASE_UPDATE_VALID);
printf("Setting RF Channel %d i_setpoint=%04x q_setpoint=%04x\n", ch, igain, qgain);
} else {
unsigned igain_addr = 0;
unsigned qgain_addr = 0;
unsigned igain;
unsigned qgain;
unsigned phase;
unsigned phase_addr;
if (ch == DAC1_CS) {
igain_addr = WR2RF_VME_REGS_CTRL + WR2RF_CTRL_REGS_RF1_IQDAC_IGAIN;
qgain_addr = WR2RF_VME_REGS_CTRL + WR2RF_CTRL_REGS_RF1_IQDAC_QGAIN;
phase_addr = WR2RF_VME_REGS_CTRL + WR2RF_CTRL_REGS_RF1_IQDAC_PHASE;
} else {
igain_addr = WR2RF_VME_REGS_CTRL + WR2RF_CTRL_REGS_RF2_IQDAC_IGAIN;
qgain_addr = WR2RF_VME_REGS_CTRL + WR2RF_CTRL_REGS_RF2_IQDAC_QGAIN;
phase_addr = WR2RF_VME_REGS_CTRL + WR2RF_CTRL_REGS_RF2_IQDAC_PHASE;
}
igain = libwr2rf_read16(dev, igain_addr);
qgain = libwr2rf_read16(dev, qgain_addr);
printf("RF Channel %d i_setpoint=%04x q_setpoint=%04x\n", ch, igain, qgain);
phase = libwr2rf_read16(dev, phase_addr);
printf("RF Channel %d i_setpoint=%04x q_setpoint=%04x, phase=%u\n", ch, igain, qgain, phase);
float igainf = (short)igain;
float qgainf = (short)qgain;
float rad = atan2f (igainf, qgainf);
float amp = hypotf(igainf, qgainf);
printf ("Real phase=%3.1f gain=%04x\n",
rad * 180.0 / M_PI, (unsigned short)amp);
}
}
static void
dac_iq_phase (struct libwr2rf_dev *dev, int argc, char **argv)
{
int ch;
float phase;
float amp;
int err;
if (argc != 3 && argc != 4) {
printf ("usage: %s 1|2 phase [amp]\n", argv[0]);
return;
}
ch = parse_dac_channel(argv[1]);
if (ch < 1 || ch > 2)
return;
phase = strtof(argv[2], NULL);
if (argc > 3)
amp = strtof(argv[3], NULL);
else
amp = 0.5;
err = libwr2rf_dac_phase_amp_ext(dev, ch, amp, phase, 1);
if (err != 0)
printf("error while setting phase+amp\n");
}
static void
......@@ -4111,6 +4165,7 @@ static struct cmds cmds[] =
{ "dds-freq", dds_freq, "control the DDS output frequency - useful for standalone DDS rf signal output"},
{ "dac-xdds", dac_xdds, "control the xilinx DDS for testing the IQdac"},
{ "dac-iqsetpoint", dac_iqsetpoint, "configures the amplitude and phase for the IQdacs"},
{ "dac-iq-phase", dac_iq_phase, "change phase and amplitude of IQdacs"},
{ "dac-iqctrl", dac_iqctrl, "Selects the IQdata lines between RFNCO+IQMod or debug DDS"},
{ "dac-tman", dac_tman, "Forces the dac timing"},
{ "dac-power", dac_power, "Set dac power-down register"},
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment