Commit 03fefdbe authored by root's avatar root Committed by Tomasz Wlostowski

software: initial DDS PLL version, seems to lock to a 10 MHz reference

parent 1bd30289
OBJS = ad9516.o speclib/speclib.o filters.o
CFLAGS = -I../include -g -Imini_bone -Ispeclib -I.
all: $(OBJS)
gcc -o rf-test $(OBJS) -lm
clean:
rm -f $(OBJS) rf-test
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <sys/time.h>
#include <math.h>
#include "speclib.h"
#include "regs/dds_regs.h"
#include "filters.h"
void loader_low_level() {};
struct wr_rf_device {
void *card;
uint32_t base;
};
static inline void rf_writel(struct wr_rf_device *dev, uint32_t data, uint32_t addr)
{
spec_writel(dev->card, data, addr + dev->base);
}
static inline uint32_t rf_readl(struct wr_rf_device *dev, uint32_t addr)
{
return spec_readl (dev->card, addr + dev->base);
}
static void gpio_set(struct wr_rf_device *dev, uint32_t pin, int value)
{
uint32_t g = rf_readl(dev, DDS_REG_GPIOR);
if(value)
rf_writel(dev, g | pin, DDS_REG_GPIOR);
else
rf_writel(dev, g & ~pin, DDS_REG_GPIOR);
}
static int gpio_get(struct wr_rf_device *dev, uint32_t pin)
{
return rf_readl(dev, DDS_REG_GPIOR) & pin;
}
/* Returns the numer of microsecond timer ticks */
int64_t get_tics()
{
struct timezone tz= {0,0};
struct timeval tv;
gettimeofday(&tv, &tz);
return (int64_t)tv.tv_sec * 1000000LL + (int64_t) tv.tv_usec;
}
/* Microsecond-accurate delay */
void udelay(uint32_t usecs)
{
int64_t ts = get_tics();
while(get_tics() - ts < (int64_t)usecs);
}
static int extra_debug = 1;
void dbg(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
if(extra_debug)
vfprintf(stderr,fmt,ap);
va_end(ap);
}
void spi_txrx(struct wr_rf_device *dev, uint32_t cs_pin, int n_bits, uint32_t value, uint32_t *rval)
{
udelay(10);
gpio_set(dev, DDS_GPIOR_PLL_SCLK, 0);
udelay(10);
gpio_set(dev, cs_pin, 0);
udelay(10);
int i;
uint32_t rv = 0;
for(i = 0; i<n_bits; i++)
{
value <<= 1;
gpio_set(dev, DDS_GPIOR_PLL_SDIO, value & (1<<n_bits));
udelay(10);
gpio_set(dev, DDS_GPIOR_PLL_SCLK, 1);
udelay(10);
rv <<= 1;
rv |= gpio_get(dev, DDS_GPIOR_PLL_SDIO) ? 1 : 0;
udelay(10);
gpio_set(dev, DDS_GPIOR_PLL_SCLK, 0);
udelay(10);
}
gpio_set(dev, cs_pin, 1);
if(rval)
*rval = rv;
}
/* Reads a register from AD9516 */
static inline uint8_t ad951x_read_reg(struct wr_rf_device *dev, uint32_t cs_pin, uint16_t reg)
{
uint32_t rval;
spi_txrx(dev, cs_pin, 24, ((uint32_t)(reg & 0xfff) << 8) | (1<<23), &rval);
return rval & 0xff;
}
/* Writes an AD9516 register */
static inline void ad951x_write_reg(struct wr_rf_device *dev, uint32_t cs_pin, uint16_t reg, uint8_t val)
{
spi_txrx(dev, cs_pin, 24, ((uint32_t)(reg & 0xfff) << 8) | val, NULL);
// dbg("write %x val %x readback %x\n", reg, val, ad951x_read_reg(dev, cs_pin, reg));
}
static int ad9516_init(struct wr_rf_device *dev)
{
gpio_set(dev, DDS_GPIOR_PLL_SYS_RESET_N, 0);
udelay(1000);
gpio_set(dev, DDS_GPIOR_PLL_SYS_RESET_N, 1);
udelay(1000);
ad951x_write_reg(dev, DDS_GPIOR_PLL_SYS_CS_N, 0, 0x99);
ad951x_write_reg(dev, DDS_GPIOR_PLL_SYS_CS_N, 0x232, 1);
static struct {
int reg;
int val;
} regs [] = {
#include "regs/ad9516_init.h"
};
/* Check if the chip is present by reading its ID register */
dbg("AD9516 PLL ID Register = %x\n", ad951x_read_reg(dev, DDS_GPIOR_PLL_SYS_CS_N, 0x3));
/* Check if the chip is present by reading its ID register */
if(ad951x_read_reg(dev, DDS_GPIOR_PLL_SYS_CS_N, 0x3) != 0xc3)
{
dbg("%s: AD9516 PLL not responding.\n", __FUNCTION__);
return -1;
}
int i;
/* Load the regs */
for(i=0;regs[i].reg >=0 ;i++)
ad951x_write_reg (dev, DDS_GPIOR_PLL_SYS_CS_N, regs[i].reg, regs[i].val);
ad951x_write_reg(dev, DDS_GPIOR_PLL_SYS_CS_N, 0x232, 0);
ad951x_write_reg(dev, DDS_GPIOR_PLL_SYS_CS_N, 0x232, 1);
/* Wait until the PLL has locked */
uint64_t start_tics = get_tics();
uint64_t lock_timeout = 1000000ULL;
for(;;)
{
if(ad951x_read_reg(dev,DDS_GPIOR_PLL_SYS_CS_N, 0x1f) & 1)
break;
if(get_tics() - start_tics > lock_timeout)
{
dbg("%s: AD9516 PLL does not lock.\n", __FUNCTION__);
return -1;
}
udelay(100);
}
/* Synchronize the phase of all clock outputs (this is critical for the accuracy!) */
ad951x_write_reg(dev, DDS_GPIOR_PLL_SYS_CS_N, 0x230, 1);
ad951x_write_reg(dev, DDS_GPIOR_PLL_SYS_CS_N, 0x232, 1);
ad951x_write_reg(dev, DDS_GPIOR_PLL_SYS_CS_N, 0x230, 0);
ad951x_write_reg(dev, DDS_GPIOR_PLL_SYS_CS_N, 0x232, 1);
dbg("%s: AD9516 locked.\n", __FUNCTION__);
}
void reset_core(struct wr_rf_device *dev)
{
rf_writel(dev, DDS_RSTR_PLL_RST, DDS_REG_RSTR);
udelay(10);
rf_writel(dev, 0, DDS_REG_RSTR);
udelay(10);
rf_writel(dev, DDS_RSTR_SW_RST, DDS_REG_RSTR);
udelay(10);
rf_writel(dev, 0, DDS_REG_RSTR);
udelay(10000);
}
void set_center_freq(struct wr_rf_device *dev, double freq, double sample_rate)
{
uint64_t tune =(uint64_t) ( (double)(1ULL<<42) * (freq / sample_rate) * 8.0 );
dbg("Setting DDS center freq to: %.3f MHz (Fs = %.3f MHz), tune = 0x%llx\n", freq/1e6, sample_rate/1e6, tune);
rf_writel(dev, (tune >> 32) & 0xffffffffULL, DDS_REG_FREQ_HI);
rf_writel(dev, tune & 0xffffffffULL, DDS_REG_FREQ_LO);
// dbg("Freq_Lo 0x%x\n", rf_readl(dev, DDS_REG_FREQ_LO));
// dbg("Freq_Hi 0x%x\n", rf_readl(dev, DDS_REG_FREQ_HI));
}
void adf4002_write(struct wr_rf_device *dev, uint32_t value)
{
gpio_set(dev, DDS_GPIOR_ADF_CLK, 0);
udelay(10);
gpio_set(dev, DDS_GPIOR_ADF_LE, 0);
udelay(10);
int i;
for(i=0;i<24;i++)
{
value <<= 1;
gpio_set(dev, DDS_GPIOR_ADF_DATA, value & (1<<24) ? 1 : 0);
udelay(10);
gpio_set(dev, DDS_GPIOR_ADF_CLK, 1);
udelay(10);
gpio_set(dev, DDS_GPIOR_ADF_CLK, 0);
}
gpio_set(dev, DDS_GPIOR_ADF_LE, 1);
udelay(10);
}
void adf4002_configure(struct wr_rf_device *dev, int r_div, int n_div, int mon_output)
{
gpio_set(dev, DDS_GPIOR_ADF_CE, 1); /* enable the PD */
udelay(10);
adf4002_write(dev, 0 | (r_div << 2));
adf4002_write(dev, 1 | (n_div << 8));
adf4002_write(dev, 2 | (0<<7) | ( mon_output << 4)); /* R div -> muxout */
}
void ad9510_init(struct wr_rf_device *dev)
{
gpio_set(dev, DDS_GPIOR_PLL_VCXO_FUNCTION, 0); /* reset AD9510 */
udelay(10);
gpio_set(dev, DDS_GPIOR_PLL_VCXO_FUNCTION, 1); /* reset AD9510 */
udelay(1000);
ad951x_write_reg(dev, DDS_GPIOR_PLL_VCXO_CS_N, 0, 0x10);
}
int read_adc(struct wr_rf_device *dev, int *buffer, int size)
{
int n = size;
while(n--)
{
while(rf_readl(dev, DDS_REG_PD_FIFO_CSR) & DDS_PD_FIFO_CSR_EMPTY);
*buffer++ = rf_readl(dev, DDS_REG_PD_FIFO_R0) & 0xffff;
}
return n;
}
void write_tune(struct wr_rf_device *dev, int tune)
{
while(rf_readl(dev, DDS_REG_TUNE_FIFO_CSR) & DDS_TUNE_FIFO_CSR_FULL);
rf_writel(dev, tune, DDS_REG_TUNE_FIFO_R0);
}
void modulation_test(struct wr_rf_device *dev)
{
rf_writel(dev, 80, DDS_REG_GAIN); /* tuning gain = 0 dB */
double f_test = 1e3;
double f_samp = 125e6/1024.0;
int n;
for(;;)
{
double x = 32767.0 * cos(2.0*M_PI*(double)n * f_test / f_samp);
// printf("S %d\n", (int)x);
write_tune(dev, (int) x);
n++;
}
}
int main(int argc, char *argv[])
{
struct wr_rf_device dev;
dev.card = spec_open(-1, -1);
dev.base = 0x80000;
if(!dev.card)
{
dbg("SPEC open failed\n");
return -1;
}
dbg("SDB signature = 0x%x\n", spec_readl(dev.card, 0));
ad9516_init(&dev);
reset_core(&dev);
set_center_freq(&dev, 10e6, 500e6);
// rf_writel(&dev, DDS_RSTR_SW_RST, DDS_REG_RSTR);
// sleep(2);
// rf_writel(&dev, 0, DDS_REG_RSTR);
adf4002_configure(&dev, 2, 2, 4);
struct fir_filter *flt_comp = fir_load("fir_compensator.dat");
struct iir_1st *flt_loop = lowpass_init(0.03);
rf_writel(&dev, 6000, DDS_REG_GAIN); /* tuning gain = 0 dB */
//for(;;) write_tune(&dev, 15000);
// return 0;
/* for(;;)
{
int i;
dbg("up...\n");
for(i=0;i<1000000;i++)
write_tune(&dev, 30000);
dbg("down...\n");
for(i=0;i<1000000;i++)
write_tune(&dev, -30000);
}*/
int i;
int s;
for(i=0;i<10000;i++)
read_adc(&dev, &s , 1);
for(;;)
{
int s;
read_adc(&dev, &s , 1);
s-=32768;
// s*=-1;
s = lowpass_process(flt_loop, s);
s = fir_process(flt_comp, s);
s/=25;
// printf("%d\n", s);
if(s < -32000) s = -32000;
else if (s > 32000) s = 32000;
// s = 30000;
write_tune(&dev, s);
}
modulation_test(&dev);
spec_close(dev.card);
return 0;
}
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <getopt.h>
#include <errno.h>
#include "fdelay_lib.h"
#include "sveclib/sveclib.h"
#include "speclib/speclib.h"
#include "fdelay_lib.h"
void printk() {};
static void fd_svec_writel(void *priv, uint32_t data, uint32_t addr)
{
svec_writel(priv, data, addr);
}
static uint32_t fd_svec_readl(void *priv, uint32_t addr)
{
return svec_readl(priv, addr);
}
static void fd_spec_writel(void *priv, uint32_t data, uint32_t addr)
{
spec_writel(priv, data, addr);
}
static uint32_t fd_spec_readl(void *priv, uint32_t addr)
{
return spec_readl(priv, addr);
}
#if 0
#endif
#define VENDOR_CERN 0xce42
#define DEVICE_FD_CORE 0xf19ede1a
#define DEVICE_VUART 0xe2d13d04
static int probe_svec(fdelay_device_t *dev, const char *location)
{
uint32_t map_base;
int slot;
void *card;
uint32_t core_base;
printf("probe_svec: loc %s\n", location);
if (!strncmp(location, "svec:", 5)) {
sscanf(location+5, "%d,%x,%x", &slot, &map_base, &core_base);
} else
return -ENODEV;
card = svec_open(slot);
svec_set_map_base(card, map_base, 1);
if(!card)
{
fprintf(stderr,"SVEC probe failed.\n");
return -1;
}
dev->priv_io = card;
dev->writel = fd_svec_writel;
dev->readl = fd_svec_readl;
dev->base_addr = core_base;
dbg("svec: using slot %d, A32/D32 base: 0x%x, core base 0x%x\n", slot, map_base, core_base);
return 0;
}
//void loader_low_level() {};
static int probe_spec(fdelay_device_t *dev, const char *location)
{
uint32_t core_base;
int slot;
if (!strncmp(location, "spec:", 5)) {
sscanf(location+5, "%d,%x", &slot, &core_base);
} else
return -ENODEV;
dev->priv_io = spec_open(slot, -1);
if(!dev->priv_io)
{
fprintf(stderr,"Can't map the SPEC @ slot %d\n", slot);
return -1;
}
dev->writel = fd_spec_writel;
dev->readl = fd_spec_readl;
dev->base_addr = core_base;
dbg("spec: using slot %d, core base 0x%x\n", slot, core_base);
return 0;
}
int fdelay_probe(fdelay_device_t *dev, const char *location)
{
int ret;
ret = probe_svec(dev, location);
if(ret != -ENODEV)
return ret;
ret = probe_spec(dev, location);
if(ret != -ENODEV)
return ret;
}
fdelay_device_t *fdelay_create()
{
return (fdelay_device_t *) malloc(sizeof(fdelay_device_t));
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
struct fir_filter {
int n_taps;
int pos;
int *delay;
double *coefs;
};
struct iir_1st {
int x0;
double y0, alpha;
};
struct fir_filter * fir_load(const char *coeffs_fname)
{
FILE * f=fopen(coeffs_fname, "r");
double coeffs[1024];
if(!f)
return NULL;
int n = 0, i;
while((fscanf(f, "%lf", &coeffs[n]) == 1) && n < 1024) n++;
printf("Loaded FIR Filter %s: %d taps.\n", coeffs_fname, n);
struct fir_filter *flt = malloc(sizeof(struct fir_filter));
flt->delay = malloc(sizeof(int) * n);
flt->coefs = malloc(sizeof(double) * n);
memcpy(flt->coefs, coeffs, sizeof(double) * n);
flt->n_taps = n;
flt->pos = 0;
memset(flt->delay, 0, sizeof(int) * n);
fclose(f);
return flt;
}
int fir_process(struct fir_filter *flt, int x)
{
double acc = 0.0;
flt->delay[flt->pos] = x;
int i;
for(i = 0; i< flt->n_taps; i++)
{
int idx = flt->pos - flt->n_taps + 1 + i;
if(idx < 0)
idx += flt->n_taps;
else if (idx >= flt->n_taps)
idx -= flt->n_taps;
acc += flt->coefs[i] * (double)flt->delay[idx];
}
flt->pos++;
if(flt->pos == flt->n_taps)
flt->pos = 0;
return (int) acc;
}
struct iir_1st * lowpass_init(double alpha)
{
struct iir_1st *flt = malloc(sizeof(struct iir_1st));
flt->alpha = alpha;
flt->y0 = 0.0;
// flt->x0 = 0;
return flt;
}
int lowpass_process(struct iir_1st *flt, int x)
{
double y = flt->y0 + flt->alpha * ((double) x - flt->y0);
flt->y0 = y;
return (int) y;
}
#ifndef __FILTERS_H
#define __FILTERS_H
#include <math.h>
struct fir_filter {
int n_taps;
int pos;
int *delay;
double *coefs;
};
struct iir_1st {
int x0;
double y0, alpha;
};
struct fir_filter * fir_load(const char *coeffs_fname);
int fir_process(struct fir_filter *flt, int x);
struct iir_1st * lowpass_init(double alpha);
int lowpass_process(struct iir_1st *flt, int x);
#endif
-0.00038385 -0.0013273 -0.0015635 0.00091054 0.0047773 0.0039991 -0.0042284 -0.010424 -0.001365 0.016826 0.01661 -0.013276 -0.036778 -0.0081087 0.051718 0.054753 -0.038602 -0.12613 -0.049535 0.20453 0.43998 0.43998 0.20453 -0.049535 -0.12613 -0.038602 0.054753 0.051718 -0.0081087 -0.036778 -0.013276 0.01661 0.016826 -0.001365 -0.010424 -0.0042284 0.0039991 0.0047773 0.00091054 -0.0015635 -0.0013273 -0.00038385
\ No newline at end of file
#!/bin/bash
insmod /home/user/pts/test/fmcdelay1ns4cha/lib/spec/kernel/spec.ko
spec-fwloader /home/user/rf18.bin
#!/usr/bin/python
import sys
import re
expr = re.compile("^\"([0-9a-fA-F]{4})\"\,\"[0-1]{8}\"\,\"([0-9a-fA-F]{2})\"", re.DOTALL)
lines = open(sys.argv[1],"r").readlines()
for l in lines:
m = re.match(expr, l)
if(m):
print("{0x%s, 0x%s}," % (m.groups(1)[0], (m.groups(1)[1])))
print("{-1, -1}");
\ No newline at end of file
{0x0000, 0x99},
{0x0001, 0x00},
{0x0002, 0x10},
{0x0003, 0xC3},
{0x0004, 0x00},
{0x0010, 0x7C},
{0x0011, 0x05},
{0x0012, 0x00},
{0x0013, 0x0C},
{0x0014, 0x12},
{0x0015, 0x00},
{0x0016, 0x05},
{0x0017, 0x00},
{0x0018, 0x07},
{0x0019, 0x00},
{0x001A, 0x00},
{0x001B, 0x00},
{0x001C, 0x02},
{0x001D, 0x00},
{0x001E, 0x00},
{0x001F, 0x0E},
{0x00A0, 0x01},
{0x00A1, 0x00},
{0x00A2, 0x00},
{0x00A3, 0x01},
{0x00A4, 0x00},
{0x00A5, 0x00},
{0x00A6, 0x01},
{0x00A7, 0x00},
{0x00A8, 0x00},
{0x00A9, 0x01},
{0x00AA, 0x00},
{0x00AB, 0x00},
{0x00F0, 0x08},
{0x00F1, 0x0A},
{0x00F2, 0x0A},
{0x00F3, 0x0A},
{0x00F4, 0x0A},
{0x00F5, 0x0A},
{0x0140, 0x46},
{0x0141, 0x46},
{0x0142, 0x46},
{0x0143, 0x46},
{0x0190, 0x00},
{0x0191, 0x80},
{0x0192, 0x00},
{0x0193, 0xBB},
{0x0194, 0x00},
{0x0195, 0x00},
{0x0196, 0x00},
{0x0197, 0x00},
{0x0198, 0x00},
{0x0199, 0x11},
{0x019A, 0x00},
{0x019B, 0x11},
{0x019C, 0x20},
{0x019D, 0x00},
{0x019E, 0x11},
{0x019F, 0x00},
{0x01A0, 0x11},
{0x01A1, 0x20},
{0x01A2, 0x00},
{0x01A3, 0x00},
{0x01E0, 0x01},
{0x01E1, 0x02},
{0x0230, 0x00},
{0x0231, 0x00},
{0x0232, 0x00},
{-1, -1}
<
/*
Register definitions for slave core: DDS RF distribution WB Slave
* File : dds_regs.h
* Author : auto-generated by wbgen2 from dds_wb_slave.wb
* Created : Mon May 6 17:52:47 2013
* Standard : ANSI C
THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE dds_wb_slave.wb