diff --git a/include/ad9915.h b/include/ad9915.h new file mode 100644 index 0000000..4363f6e --- /dev/null +++ b/include/ad9915.h @@ -0,0 +1,49 @@ +/* +dds initialisation et SPI +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* memory management */ +#include +#include "spi.h" +#include +#include +#include + + +static const char CFRAddress[] = {0x00,0x01,0x02,0x03}; + +static const char CFR1Start[] ={0x00, 0x01, 0x00, 0x0a}; +//static const char CFR1Start[] ={0x00, 0x01, 0x01, 0x08}; //with osk enable +static const char CFR2Start[] ={0x00, 0x80, 0x09, 0x00}; //0x80 enable prof mode +static const char CFR3Start[] = {0x00, 0x00, 0x19, 0x1C}; +static const char CFR4Start[] = {0x00, 0x05, 0x21, 0x20}; + +static const char USR0Address = 0x1B; +static const char FTW0Address = 0x0b; //profile 0 ftw +static const char PA0Address = 0x0c; //profile 0 + +static const char DACCalEnable[] = {0x01, 0x05, 0x21, 0x20}; //Command to enable the DAC Cal, should be 0x01XXXXXX, where X is the last 6 digits of CFR4Start + + +void Send_Reset(int f_dds); +void Send_IO_Update (int f_dds); //Send the update to set the control registers +void write_register (int fd, unsigned char addr, unsigned char d3, unsigned char d2, unsigned char d1, unsigned char d0); +void Initialize_DDS (int fd, int f_dds); +void Calibrate_DAC(int fd, int f_dds); +void basic_setup(int fd, int f_dds, uint16_t ampWord, uint16_t phaseWord); +void modulus_setup(int fd, int f_dds); +void setFreqMM(int fd, int f_dds, unsigned int ftw, unsigned int A, unsigned int B); +void setAmpPhaseWord(int fd, int f_dds,unsigned int phaseAmpWord); +int openAndSetDdsFreq( char * device, char * gpio_update, double f_clk, double f_out, uint16_t ampWord, uint16_t phaseWord); +int receiveParameterFromPythonServer(char * device, double f_clk, double f_out); +int setDdsFreqFull ( int fd, int f_dds, double f_clk, double f_out, uint16_t ampWord, uint16_t phaseWord); + diff --git a/include/ddsFreq.h b/include/ddsFreq.h new file mode 100644 index 0000000..0ff0f55 --- /dev/null +++ b/include/ddsFreq.h @@ -0,0 +1,15 @@ +#include +#include +#include +#include + +struct frac +{ + long double numerator; + long double denominator; +}; + +long double pgcd ( long double m , long double n); + +int ddsFreq(int fd, int f_dds); +int setddsFreq(int fd, int f_dds, long double f0, long double fs); diff --git a/include/spi.h b/include/spi.h new file mode 100644 index 0000000..15b8716 --- /dev/null +++ b/include/spi.h @@ -0,0 +1,13 @@ +#ifndef SPI_H +#define SPI_H + +int configureSpi(char *device); +uint16_t transfer(int fd, uint16_t valeur, int truc); +uint8_t spi_put(int fd, uint8_t valeur); +uint8_t spi_put_multiple(int fd, uint8_t *tx, uint16_t tx_size, + uint8_t *rx, uint16_t rx_size); +void setMode(int fd, uint8_t mode); +uint8_t tr2(int fd, uint8_t val); +uint8_t tr3(int fd, uint8_t *val, uint8_t *rx, uint8_t size); +int configureSpiFromFd (int fd); +#endif /*SPI_H */ diff --git a/src/ad9915.c b/src/ad9915.c new file mode 100644 index 0000000..9e90697 --- /dev/null +++ b/src/ad9915.c @@ -0,0 +1,164 @@ +/* + SPI : initialisation du dds et communication SPI + */ +#include"ad9915.h" +#include "spi.h" +#include "ddsFreq.h" + +#define debug +//fonction reset +void Send_Reset(int f_dds) +{ + char reset='2'; + write(f_dds,&reset,sizeof(reset)); //reset + sleep(0.1); +} + +//fonction ioupdate +void Send_IO_Update(int f_dds) +{ + char update='1'; + write(f_dds,&update,sizeof(update)); //reset + sleep(0.1); +} + +//fonction write register +void write_register (int fd, unsigned char addr, unsigned char d3, unsigned char d2, unsigned char d1, unsigned char d0) +{ + unsigned char tx[5]={0}; + tx[0]=addr; + tx[1]=d3; + tx[2]=d2; + tx[3]=d1; + tx[4]=d0; + //spi_put_multiple envoie le vecteur dans cet ordre + //[tx0]-[tx1]-[tx2] -> adresse->bit poids Fort->bit poids faible + spi_put_multiple(fd,tx,5,NULL,0); +} + +//initialisation du dds +void Initialize_DDS (int fd, int f_dds) +{ + Send_Reset(f_dds); + write_register(fd,CFRAddress[0],CFR1Start[0], CFR1Start[1], CFR1Start[2], CFR1Start[3]); + Send_IO_Update (f_dds); //Send the update to set the control registers + write_register(fd,CFRAddress[1], CFR2Start[0], CFR2Start[1], CFR2Start[2], CFR2Start[3]); + Send_IO_Update (f_dds); + write_register(fd,CFRAddress[2], CFR3Start[0], CFR3Start[1], CFR3Start[2], CFR3Start[3]); + Send_IO_Update (f_dds); + write_register(fd,CFRAddress[3], CFR4Start[0], CFR4Start[1], CFR4Start[2], CFR4Start[3]); + Send_IO_Update (f_dds); + write_register(fd,USR0Address, 0xA2, 0x00, 0x08, 0x00); + Send_IO_Update (f_dds); +} + +//calibration du dac +void Calibrate_DAC (int fd, int f_dds) +{ + write_register(fd,CFRAddress[3], DACCalEnable[0], DACCalEnable[1], DACCalEnable[2], DACCalEnable[3]); + Send_IO_Update (f_dds); + write_register(fd,CFRAddress[3], CFR4Start[0], CFR4Start[1], CFR4Start[2], CFR4Start[3]); + Send_IO_Update (f_dds); +} + +void modulus_setup(int fd, int f_dds) +{ + write_register(fd,0x00,0x00, 0x01, 0x01, 0x08); //OSK enable + Send_IO_Update (f_dds); + write_register(fd,0x01,0x00, 0x89, 0x09, 0x00); //enable program modulus and digital ramp + Send_IO_Update (f_dds); +} + +void basic_setup(int fd, int f_dds,uint16_t ampWord, uint16_t phaseWord) +{ + write_register(fd,0x00,0x00, 0x01, 0x01, 0x08); //OSK enable + Send_IO_Update (f_dds); + write_register(fd,0x01,0x00, 0x89, 0x09, 0x00); //enable program modulus and digital ramp + Send_IO_Update (f_dds); + write_register(fd,0x04,0x19, 0x99, 0x99, 0x99); //ftw + Send_IO_Update (f_dds); + write_register(fd,0x05,0xC0, 0x00, 0x00, 0x00); //A + Send_IO_Update (f_dds); + write_register(fd,0x06,0x00, 0x00, 0x00, 0x05); //B + Send_IO_Update (f_dds); + //write_register(fd,0x0c, 0x0F, 0xFF, 0x00, 0x00); // amp (12b) ph(16) + write_register(fd,0x0c, (uint8_t)((ampWord>>8) & 0x0F), (uint8_t)(ampWord & 0xFF), (uint8_t)((phaseWord>>8) & 0xFF), (uint8_t)(phaseWord & 0xFF)); // amp (12b) ph(16) + Send_IO_Update (f_dds); +} + +void setFreqMM(int fd, int f_dds, unsigned int ftw, unsigned int A, unsigned int B) +{ + //uint16_t phaseWord = 0x7400; + //uint16_t ampWord = (uint16_t)strtol(argv[4],NULL,0) & 0x0FFF ; //masque en 2 + //uint16_t ampWord = 0x00000FFF; + //uint32_t phaseAmpWord = phaseWord | ampWord<<16; + + //write_register(fd,0x00,0x00, 0x01, 0x01, 0x08); //OSK enable + //Send_IO_Update(f_dds); + //write_register(fd,0x01,0x00, 0x89, 0x09, 0x00); //enable program modulus and digital ramp + //Send_IO_Update(f_dds); + write_register(fd,0x04,ftw>>24&0xFF, ftw>>16&0xFF, ftw>>8&0xFF, ftw&0xFF); //ftw + Send_IO_Update(f_dds); + write_register(fd,0x05,A>>24&0xFF,A>>16&0xFF, A>>8&0xFF, A&0xFF); //A + Send_IO_Update(f_dds); + write_register(fd,0x06,B>>24&0xFF,B>>16&0xFF, B>>8&0xFF, B&0xFF); //B + Send_IO_Update(f_dds); + // write_register(fd,0x0c, phaseAmpWord>>24&0xFF, phaseAmpWord>>16&0xFF,phaseAmpWord>>8&0xFF,phaseAmpWord&0xFF); // amp (12b) ph(16) + //Send_IO_Update(f_dds); +} + +void setAmpPhaseWord(int fd, int f_dds,unsigned int phaseAmpWord) +{ + write_register(fd,0x0c, phaseAmpWord>>24&0xFF, phaseAmpWord>>16&0xFF,phaseAmpWord>>8&0xFF,phaseAmpWord&0xFF); // amp (12b) ph(16) + Send_IO_Update(f_dds); +} + + +int openAndSetDdsFreq( char * device, char * gpio_update, double f_clk, double f_out, uint16_t ampWord, uint16_t phaseWord) +{ + #ifdef debug + printf("device=%s\tgpio_update=%s\tf_clk=%e\tf_out=%e\tampWord=%d\tphaseWord=%d\n\n",device,gpio_update,f_clk,f_out,ampWord,phaseWord); + #else + printf("device=%s\tgpio_update=%s\tf_clk=%e\tf_out=%e\tampWord=%d\tphaseWord=%d\n\n",device,gpio_update,f_clk,f_out,ampWord,phaseWord); + int fd=configureSpi(device); //ex #define FILENAME2 "/dev/spidev0.0" + printf("fd(funct)=%d\n",fd); + setMode(fd,SPI_MODE_0); + if (fd <= 0){ + printf("ERREUR : ouverture périphérique SPI %s\n",device); + return EXIT_FAILURE; + } + int f_dds=open(gpio_update,O_RDWR); //ex #define UPDATE2 "/sys/dds/gpio24/updateOn" + printf("f_dds(funct)=%d\n",f_dds); + if (f_dds <= 0){ + printf("ERREUR : ouverture ");printf(gpio_update);printf("\n"); + printf("Chargez le module ddsIOupdateX\n"); + return EXIT_FAILURE; + } + setddsFreq(fd,f_dds,f_out,f_clk); + //debug + phaseWord = 0x0000; + ampWord=0x0FFF; + uint32_t phaseAmpWord = phaseWord | ampWord<<16; + setAmpPhaseWord(fd, f_dds, phaseAmpWord); + #endif + return EXIT_SUCCESS; +} + +int setDdsFreqFull ( int fd, int f_dds, double f_clk, double f_out, uint16_t ampWord, uint16_t phaseWord) +{ + setddsFreq(fd,f_dds,f_out,f_clk); + #ifdef debug + phaseWord = 0x0000; + ampWord=0x0FFF; + #endif + uint32_t phaseAmpWord = phaseWord | ampWord<<16; + setAmpPhaseWord(fd, f_dds, phaseAmpWord); + + return EXIT_SUCCESS; +} + +int receiveParameterFromPythonServer(char * device, double f_clk, double f_out){ + + printf("receiveParameterFromPythonServer::device=%s\tf_clk=%e\tf_out=%e\n",device,f_clk,f_out); + return 0; +} diff --git a/src/ddsFreq.c b/src/ddsFreq.c new file mode 100644 index 0000000..14fa684 --- /dev/null +++ b/src/ddsFreq.c @@ -0,0 +1,139 @@ +#include +#include +#include +#include +#include "ddsFreq.h" +#include "ad9915.h" + +//#define debug +long double pgcd ( long double m , long double n) +{ + if (fmod(m,n) ==0) + return n; + return pgcd(n,fmod(m,n)); +} + +int setddsFreq(int fd, int f_dds, long double f0, long double fs) +{ + + #ifdef debug + printf("f0=%Le\tfs=%Le\n",f0,fs); + #endif + + if (fs<0 || f0<0) return EXIT_FAILURE; + + struct frac f1; + + f1.numerator = f0; + f1.denominator = fs; + + long double d1 = pgcd (f1.numerator , f1.denominator ); + //printf(" d1 = %24.16Lf\n",d1); + + long double M = f0 / d1 ; + long double N = fs / d1 ; + //printf(" M = f0 / d1 = %24.16Lf\n",M); + //printf(" N = fs / d1 = %24.16Lf\n",N); + + + long double ftw = M * scalbn(1.0,32); + ftw /= N; + //printf("ftw = %24.16Lf\n",ftw); + + + //printf("X=floor(ftw) = %24.16Lf\n",(long double)floor(ftw)); + + long double Y = M * scalbn(1.0,32); + Y -= N * floor(ftw); + //printf("Y=M*2**32-X*N = %24.16Lf\n",Y); + + long double d2 = pgcd (Y,N); + //printf(" d2 = %24.16Lf\n",d2); + + long double A = Y / d2; + long double B = N / d2; + //printf("A = Y/d2 = %24.16Lf\n",A); + //printf("B = N/d2 = %24.16Lf\n",B); + + //printf("f0 = (M/N) * fclk= %24.32Lf\n",fs*M/N); + //printf("f0 = (X+A/B)2**32= %24.32Lf\n",fs*(floor(ftw)+A/B)/scalbn(1.0,32)); + +#ifdef debug +printf("\n so finally the programmed registers are :\n" + "ftw= 0x%08x A= 0x%08x B= 0x%08x\n" + "",(unsigned int)ftw,(unsigned int)A,(unsigned int)B); +printf("uint ftw = %d\n",(unsigned int)ftw); + +printf("\n 0x%08x 0x%08x 0x%08x \n\n",(unsigned int)ftw,(unsigned int)A,(unsigned int)B); +//setFreqMM(fd,f_dds,(unsigned int)ftw, (unsigned int)A, (unsigned int)B); +#endif +setFreqMM(fd,f_dds,(unsigned int)ftw, 2*(unsigned int)B, 2*(unsigned int)A); //??why *2?? + return EXIT_SUCCESS; +} +int ddsFreq(int fd, int f_dds) +{ + //checkSize(); + long double f0,fs; + //printf("long = %lu\n",sizeof (long)); + //printf("float = %lu\n",sizeof (float)); + //printf("double = %lu\n",sizeof (double)); + //printf("long double = %lu\n",sizeof (long double)); + + printf("\nDesired output Frequency (MHz) : "); + scanf("%Lf",&f0); + printf("DDS frequency Clock (MHz) : "); + scanf("%Lf",&fs); + + //long double f0=atof(argv[1]); //desired output freq + //long double fs=atof(argv[2]); //dds_clk + //int toto = (int)strtol(argv[3],NULL,0); + //printf("toto=%d\t%x\n",toto,toto); + + if (fs<0 || f0<0) return EXIT_FAILURE; + + struct frac f1; + + f1.numerator = f0; + f1.denominator = fs; + + long double d1 = pgcd (f1.numerator , f1.denominator ); + printf(" d1 = %24.16Lf\n",d1); + + long double M = f0 / d1 ; + long double N = fs / d1 ; + printf(" M = f0 / d1 = %24.16Lf\n",M); + printf(" N = fs / d1 = %24.16Lf\n",N); + + + long double ftw = M * scalbn(1.0,32); + ftw /= N; + printf("ftw = %24.16Lf\n",ftw); + + + printf("X=floor(ftw) = %24.16Lf\n",(long double)floor(ftw)); + + long double Y = M * scalbn(1.0,32); + Y -= N * floor(ftw); + printf("Y=M*2**32-X*N = %24.16Lf\n",Y); + + long double d2 = pgcd (Y,N); + printf(" d2 = %24.16Lf\n",d2); + + long double A = Y / d2; + long double B = N / d2; + printf("A = Y/d2 = %24.16Lf\n",A); + printf("B = N/d2 = %24.16Lf\n",B); + + printf("f0 = (M/N) * fclk= %24.32Lf\n",fs*M/N); + printf("f0 = (X+A/B)2**32= %24.32Lf\n",fs*(floor(ftw)+A/B)/scalbn(1.0,32)); + +printf("\n so finally the programmed registers are :\n" + "ftw= 0x%08x A= 0x%08x B= 0x%08x\n" + "",(unsigned int)ftw,(unsigned int)A,(unsigned int)B); +//printf("uint ftw = %d\n",(unsigned int)ftw); + +printf("\n 0x%08x 0x%08x 0x%08x \n\n",(unsigned int)ftw,(unsigned int)A,(unsigned int)B); +//setFreqMM(fd,f_dds,(unsigned int)ftw, (unsigned int)A, (unsigned int)B); +setFreqMM(fd,f_dds,(unsigned int)ftw, 2*(unsigned int)B, 2*(unsigned int)A); + return EXIT_SUCCESS; +} diff --git a/src/spi.c b/src/spi.c new file mode 100644 index 0000000..8b08aea --- /dev/null +++ b/src/spi.c @@ -0,0 +1,161 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* memory management */ +#include +#include "spi.h" +#include + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +#undef DEBUG +//#define DEBUG +static uint8_t bits = 8; +//static uint32_t speed = 15000000; // 9600; +//static uint32_t speed = 20000000; // 9600; +static uint32_t speed = 10000000; +//static uint32_t speed = 100000; // 9600; +//static uint16_t delay; +static void +pabort (const char *s) +{ + perror (s); + abort (); +} + +uint8_t +spi_put_multiple (int fd, uint8_t * tx, uint16_t tx_size, + uint8_t * rx, uint16_t rx_size) +{ + int ret; + int nb = 2; + if (rx_size == 0 || tx_size == 0) + nb = 1; + struct spi_ioc_transfer xfer[nb]; + nb = 0; + memset (xfer, 0, sizeof (xfer)); + if (tx_size > 0) + { + xfer[nb].tx_buf = (unsigned long) tx; + xfer[nb].len = tx_size; + nb++; + } + if (rx_size > 0) + { + xfer[nb].rx_buf = (unsigned long) rx; + xfer[nb].len = rx_size; + nb++; + } + ret = ioctl (fd, SPI_IOC_MESSAGE (nb), xfer); + return ret; +} + +uint8_t +tr3 (int fd, uint8_t * val, uint8_t * rx, uint8_t size) +{ + int ret; + + struct spi_ioc_transfer xfer[2]; + memset (xfer, 0, sizeof (xfer)); + + xfer[0].tx_buf = (unsigned long) val; + xfer[0].len = size; + xfer[1].rx_buf = (unsigned long) rx; + xfer[1].len = size; + + ret = ioctl (fd, SPI_IOC_MESSAGE (2), xfer); + if (ret < 1) + { + pabort ("can't send spi message"); + } + return ret; +} + +void +setMode (int fd, uint8_t mode) +{ + if (ioctl (fd, SPI_IOC_WR_MODE, &mode) < 0) + pabort ("can't set mode"); + if (ioctl (fd, SPI_IOC_RD_MODE, &mode) < 0) + pabort ("can't get mode"); +} + +uint8_t +spi_put (int fd, uint8_t valeur) +{ + int ret; + uint8_t rx_buf[1], tx_buf[1]; + tx_buf[0] = valeur; + struct spi_ioc_transfer xfer[2]; + memset (xfer, 0, sizeof (xfer)); + + xfer[0].tx_buf = (unsigned long) tx_buf; + xfer[0].rx_buf = (unsigned long) rx_buf; + xfer[0].len = 1; + ret = ioctl (fd, SPI_IOC_MESSAGE (1), xfer); + if (ret < 1) + { + pabort ("can't send spi message"); + } + return rx_buf[0]; +} + +int +configureSpi (char *device) +{ + printf("device(configureSpi)=%s\n",device); + int fd = open (device, O_RDWR); + if (fd < 0) + pabort ("can't open device"); + + setMode (fd, 0); + /* bits per word */ + if (ioctl (fd, SPI_IOC_WR_BITS_PER_WORD, &bits) == -1) + pabort ("can't set bits per word"); + if (ioctl (fd, SPI_IOC_RD_BITS_PER_WORD, &bits) == -1) + pabort ("can't get bits per word"); + + /* max speed hz */ + if (ioctl (fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) == -1) + pabort ("can't set max speed hz"); + + if (ioctl (fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) == -1) + pabort ("can't get max speed hz"); +//#ifdef DEBUG + //printf("spi mode: %d\n", mode); + //printf ("bits per word: %d\r\n", bits); + //printf ("max speed: %lu Hz (%lu kHz)\r\n", +// (unsigned long) speed, ((unsigned long) speed) / 1000); +//#endif /* DEBUG */ + return fd; +} + +int configureSpiFromFd (int fd) +{ + setMode (fd, 0); + /* bits per word */ + if (ioctl (fd, SPI_IOC_WR_BITS_PER_WORD, &bits) == -1) + pabort ("can't set bits per word"); + if (ioctl (fd, SPI_IOC_RD_BITS_PER_WORD, &bits) == -1) + pabort ("can't get bits per word"); + + /* max speed hz */ + if (ioctl (fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) == -1) + pabort ("can't set max speed hz"); + + if (ioctl (fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) == -1) + pabort ("can't get max speed hz"); +#ifdef DEBUG +//printf("spi mode: %d\n", mode); +printf ("bits per word: %d\r\n", bits); +printf ("max speed: %lu Hz (%lu kHz)\r\n", + (unsigned long) speed, ((unsigned long) speed) / 1000); +#endif /* DEBUG */ + return EXIT_SUCCESS; +}