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 ...@@ -3,8 +3,8 @@ VMEBRIDGE=/acc/local/L867/drv/vmebus/1.0.1
PREFIX=/usr/local PREFIX=/usr/local
CC=gcc CC=gcc
CFLAGS=-g -O -Wall --std=c99 -I$(VMEBRIDGE)/include/vmebus -I../include CFLAGS=-g -O -Wall --std=gnu99 -I$(VMEBRIDGE)/include/vmebus -I../include
LDFLAGS=$(VMEBRIDGE)/lib/libvmebus.a -lrt LDFLAGS=$(VMEBRIDGE)/lib/libvmebus.a -lrt -lm
OBJS_LIB=init.o board.o oc_spi16.o ad9910_init.o dac_timing.o OBJS_LIB=init.o board.o oc_spi16.o ad9910_init.o dac_timing.o
OBJS_HOST=host.o OBJS_HOST=host.o
......
...@@ -130,7 +130,8 @@ libwr2rf_dds_init(struct libwr2rf_dev *dev, unsigned io_update) ...@@ -130,7 +130,8 @@ libwr2rf_dds_init(struct libwr2rf_dev *dev, unsigned io_update)
} }
int 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; int res;
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
#include <assert.h> #include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#define _USE_MATH_DEFINES
#include <math.h>
#include "libwr2rf/board.h" #include "libwr2rf/board.h"
#include "libwr2rf/api.h" #include "libwr2rf/api.h"
#include "regs.h" #include "regs.h"
...@@ -196,27 +198,149 @@ void libwr2rf_dac_write(struct libwr2rf_dev *dev, unsigned ch, unsigned reg, uin ...@@ -196,27 +198,149 @@ void libwr2rf_dac_write(struct libwr2rf_dev *dev, unsigned ch, unsigned reg, uin
NULL); 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; if (!(amplitude >= 0.0 && amplitude <= 1.0))
unsigned qgain_addr = 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: case 1:
igain_addr = WR2RF_VME_REGS_CTRL + WR2RF_CTRL_REGS_RF1_IQDAC_IGAIN; igain_addr = WR2RF_VME_REGS_CTRL + WR2RF_CTRL_REGS_RF1_IQDAC_IGAIN;
qgain_addr = WR2RF_VME_REGS_CTRL + WR2RF_CTRL_REGS_RF1_IQDAC_QGAIN; 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; break;
case 2: case 2:
igain_addr = WR2RF_VME_REGS_CTRL + WR2RF_CTRL_REGS_RF2_IQDAC_IGAIN; igain_addr = WR2RF_VME_REGS_CTRL + WR2RF_CTRL_REGS_RF2_IQDAC_IGAIN;
qgain_addr = WR2RF_VME_REGS_CTRL + WR2RF_CTRL_REGS_RF2_IQDAC_QGAIN; 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; break;
default: default:
return LIBWR2RF_ERROR_BAD_ID; return LIBWR2RF_ERROR_BAD_ID;
} }
libwr2rf_write16(dev, igain_addr, igain); libwr2rf_write16(dev, igain_addr, igain);
libwr2rf_write16(dev, qgain_addr, qgain); libwr2rf_write16(dev, qgain_addr, qgain);
return 0; 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) unsigned libwr2rf_read_fwversion(struct libwr2rf_dev *dev)
......
...@@ -239,8 +239,8 @@ libwr2rf_api_init (struct libwr2rf_dev *dev) ...@@ -239,8 +239,8 @@ libwr2rf_api_init (struct libwr2rf_dev *dev)
libwr2rf_iodelay_init(dev); libwr2rf_iodelay_init(dev);
/* Command dac-iqsetpoint */ /* Command dac-iqsetpoint */
libwr2rf_dac_iqsetpoint(dev, 1, 0x4000, 0); libwr2rf_dac_reset_phase_amp(dev, 1, 0.5, 0.0);
libwr2rf_dac_iqsetpoint(dev, 2, 0x4000, 0); libwr2rf_dac_reset_phase_amp(dev, 2, 0.5, 0.0);
/* Commands: /* Commands:
dds-init (TODO: io_update) dds-init (TODO: io_update)
......
...@@ -64,8 +64,16 @@ int libwr2rf_check_link_time(struct libwr2rf_dev *dev); ...@@ -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. */ /* Read the mac address (6 bytes). Can be used as unique id. */
int libwr2rf_get_mac(struct libwr2rf_dev *dev, unsigned char *mac); int libwr2rf_get_mac(struct libwr2rf_dev *dev, unsigned char *mac);
/* DAC IQ set points. */ /* Set DAC amplitude and phase. Amplitude must be between 0.0 and 1.0,
int libwr2rf_dac_iqsetpoint(struct libwr2rf_dev *dev, unsigned ch, unsigned igain, unsigned qgain); 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. */ /* Mask (or not mask) NCO resets. */
int libwr2rf_nco_reset(struct libwr2rf_dev *dev, unsigned ch, unsigned en); 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, ...@@ -25,6 +25,9 @@ void libwr2rf_dds_write(struct libwr2rf_dev *dev, unsigned reg,
uint64_t value, unsigned nbits); uint64_t value, unsigned nbits);
uint64_t libwr2rf_dds_read(struct libwr2rf_dev *dev, unsigned reg, 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. */ /* Trigger ioupdate. */
void libwr2rf_dds_ioupdate(struct libwr2rf_dev *dev); void libwr2rf_dds_ioupdate(struct libwr2rf_dev *dev);
...@@ -42,6 +45,10 @@ int libwr2rf_dac_port_timing(struct libwr2rf_dev *dev, unsigned ch); ...@@ -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); 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); 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. */ /* Raw 32bit IOs through the wb16 to wb32 bridge. */
uint32_t libwr2rf_16x32_read32(struct libwr2rf_dev *dev, unsigned off); uint32_t libwr2rf_16x32_read32(struct libwr2rf_dev *dev, unsigned off);
void libwr2rf_16x32_write32(struct libwr2rf_dev *dev, unsigned off, void libwr2rf_16x32_write32(struct libwr2rf_dev *dev, unsigned off,
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <termios.h> #include <termios.h>
#include <errno.h> #include <errno.h>
#include <ctype.h> #include <ctype.h>
#include <math.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include "libwr2rf/io.h" #include "libwr2rf/io.h"
#include "libwr2rf/host.h" #include "libwr2rf/host.h"
...@@ -1779,6 +1780,8 @@ static void ...@@ -1779,6 +1780,8 @@ static void
dac_iqsetpoint (struct libwr2rf_dev *dev, int argc, char **argv) dac_iqsetpoint (struct libwr2rf_dev *dev, int argc, char **argv)
{ {
int ch; int ch;
unsigned igain_addr;
unsigned qgain_addr;
if (argc != 2 && argc != 4) { if (argc != 2 && argc != 4) {
printf ("usage: %s 1|2 [i_setpoint q_setpoint]\n", argv[0]); 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) ...@@ -1786,37 +1789,88 @@ dac_iqsetpoint (struct libwr2rf_dev *dev, int argc, char **argv)
} }
ch = parse_dac_channel(argv[1]); ch = parse_dac_channel(argv[1]);
if (ch < 0) if (ch < 1 || ch > 2)
return; return;
if (argc == 4) { if (argc == 4) {
unsigned igain = 0; unsigned update_addr;
unsigned qgain = 0; 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); igain = strtoul(argv[2], NULL, 0);
qgain = strtoul(argv[3], NULL, 0); qgain = strtoul(argv[3], NULL, 0);
if (libwr2rf_dac_iqsetpoint(dev, ch, igain, qgain) != 0) { libwr2rf_write16(dev, igain_addr, igain);
printf("error\n"); libwr2rf_write16(dev, qgain_addr, qgain);
return; 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); printf("Setting RF Channel %d i_setpoint=%04x q_setpoint=%04x\n", ch, igain, qgain);
} else { } else {
unsigned igain_addr = 0;
unsigned qgain_addr = 0;
unsigned igain; unsigned igain;
unsigned qgain; unsigned qgain;
unsigned phase;
unsigned phase_addr;
if (ch == DAC1_CS) { if (ch == DAC1_CS) {
igain_addr = WR2RF_VME_REGS_CTRL + WR2RF_CTRL_REGS_RF1_IQDAC_IGAIN; igain_addr = WR2RF_VME_REGS_CTRL + WR2RF_CTRL_REGS_RF1_IQDAC_IGAIN;
qgain_addr = WR2RF_VME_REGS_CTRL + WR2RF_CTRL_REGS_RF1_IQDAC_QGAIN; 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 { } else {
igain_addr = WR2RF_VME_REGS_CTRL + WR2RF_CTRL_REGS_RF2_IQDAC_IGAIN; igain_addr = WR2RF_VME_REGS_CTRL + WR2RF_CTRL_REGS_RF2_IQDAC_IGAIN;
qgain_addr = WR2RF_VME_REGS_CTRL + WR2RF_CTRL_REGS_RF2_IQDAC_QGAIN; 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); igain = libwr2rf_read16(dev, igain_addr);
qgain = libwr2rf_read16(dev, qgain_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 static void
...@@ -4111,6 +4165,7 @@ static struct cmds cmds[] = ...@@ -4111,6 +4165,7 @@ static struct cmds cmds[] =
{ "dds-freq", dds_freq, "control the DDS output frequency - useful for standalone DDS rf signal output"}, { "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-xdds", dac_xdds, "control the xilinx DDS for testing the IQdac"},
{ "dac-iqsetpoint", dac_iqsetpoint, "configures the amplitude and phase for the IQdacs"}, { "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-iqctrl", dac_iqctrl, "Selects the IQdata lines between RFNCO+IQMod or debug DDS"},
{ "dac-tman", dac_tman, "Forces the dac timing"}, { "dac-tman", dac_tman, "Forces the dac timing"},
{ "dac-power", dac_power, "Set dac power-down register"}, { "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