Commit f545cdb9 authored by Anders Wallin's avatar Anders Wallin

first commit of dds-sw

parent 5b48ecc8
......@@ -10,4 +10,8 @@ Licensed under CERN-OHL-S v2 or later, see https://ohwr.org/cernohl
- /mixerboard
- /ddsboard
- /ocxo_board
- PICDIV (see https://github.com/aewallin/PICDIV_Board_v3)
- PICDIV (see https://github.com/aewallin/PICDIV_Board_v3)
- /mkr_ioboard (connects Arduino SPI signals to ddsboard)
- Firmware
- /dds_sw Firmware for control of ddsboard with Arduino MKR ZERO
/*
* Arduino code for microstepper-project DDS-board
* AW2021-09, see https://ohwr.org/project/microstepper
*
*/
#ifndef __AD9912_H__
#define __AD9912_H__
namespace AD9912 {
// AD9912 register addresses
// https://www.analog.com/media/en/technical-documentation/data-sheets/AD9912.pdf
// see Table 12 on page 31/40.
const int ser_conf = 0x0000;
const int PART_ID1 = 0x0002; // should read 0x02 = 02 decimal
const int PART_ID = 0x0003; // should read 0x19 = 25 decimal
const int SERIAL_OPTS_0 = 0x0004;
const int SERIAL_OPTS_1 = 0x0005;
const int PD_ENA = 0x0010; // address of Power-Down register
const int8_t PD_HSTL = 0b10000000; // power down HSTL driver
const int8_t CMOS_ENA = 0b01000000; // enable CMOS driver
const int8_t OUT_DBL = 0b00100000; // output doubler enable (see also register 0x0200)
const int8_t PLL_PD = 0b00010000; // power down SYSCLK PLL
const int8_t PD_FULL = 0b00000010; // full powerdown
const int8_t DIG_PD = 0b00000001; // digital powerdown;
const int RESET = 0x0012;
// system clock
const int PLL_N = 0x0020;
const int PLL_PARAMETERS = 0x0022;
const int8_t VCO_AUTORANGE = 0b10000000; // enables autorange, bit2 is set automatically
const int8_t REF_2X = 0b00001000; // 2x mode for input clock
const int8_t VCO_RANGE = 0b00000100; // 0=low, 1=high
const int8_t CPUMP_MSB = 0b00000010; // charge pump current, 00=250, 01=375, 10=0ff, 11=125 uA
const int8_t CPUMP_LSB = 0b00000001; // default is 00, i.e. 250uA
// frequency tuning word
const int FTW0 = 0x01A6;
const int FTW1 = 0x01A7;
const int FTW2 = 0x01A8;
const int FTW3 = 0x01A9;
const int FTW4 = 0x01AA;
const int FTW5 = 0x01AB;
// phase
const int phase_low = 0x01AC;
const int phase_high = 0x01AD;
// doubler/output drivers
const int hstl_driver = 0x0200;
const int cmos_driver = 0x0201;
const int READ = 0x8000;
const int WRITE = 0x0000;
const int BYTES_ONE = 0x0000;
const int BYTES_TWO = 0x2000;
const int BYTES_THREE = 0x4000;
const int BYTES_STREAM = 0x6000;
// new 2014-03-06, for 1GHz
const int F660[18][14] = {
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x99, 0x99, 0x99, 0x99, 0x99, 0x19 }, // 100 MHz
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x8f, 0xc2, 0xf5, 0x28, 0x5c, 0x8f, 0x02 }, // 10 MHz
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xa7, 0xc6, 0x4b, 0x37, 0x89, 0x41, 0x00 }, // 1 MHz
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xcb, 0x10, 0xc7, 0xba, 0xb8, 0x8d, 0x06, 0x00 }, // 100 kHz
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x47, 0x1b, 0x47, 0xac, 0xc5, 0xa7, 0x00, 0x00 }, // 10 kHz
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x8d, 0xed, 0xb5, 0xa0, 0xf7, 0xc6, 0x10, 0x00, 0x00 }, // 1 kHz
{ 0x00, 0x00, 0x00, 0x00, 0x80, 0xf4, 0xca, 0xab, 0x29, 0x7f, 0xad, 0x01, 0x00, 0x00 }, // 100 Hz
{ 0x00, 0x00, 0x00, 0x00, 0x74, 0x18, 0x61, 0xc4, 0x1d, 0xf3, 0x2a, 0x00, 0x00, 0x00 }, // 10 Hz
{ 0x00, 0x00, 0x00, 0x40, 0xa5, 0xb5, 0x09, 0xfa, 0x82, 0x4b, 0x04, 0x00, 0x00, 0x00 }, // 1 Hz
{ 0x00, 0x00, 0x00, 0xec, 0xf6, 0x5e, 0x67, 0x7f, 0xf3, 0x6d, 0x00, 0x00, 0x00, 0x00 }, // 100 mHz
{ 0x00, 0x00, 0x00, 0x4b, 0xb2, 0xbc, 0xf0, 0xbf, 0xfe, 0x0a, 0x00, 0x00, 0x00, 0x00 }, // 10 mHz
{ 0x00, 0x00, 0x10, 0xa1, 0xde, 0x12, 0x98, 0x79, 0x19, 0x01, 0x00, 0x00, 0x00, 0x00 }, // 1 mHz
{ 0x00, 0x00, 0x82, 0x76, 0x49, 0x68, 0xc2, 0x25, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 100 uHz
{ 0x00, 0x80, 0x73, 0x25, 0xd4, 0x70, 0x93, 0xd0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 10 uHz
{ 0x00, 0x54, 0x58, 0x9d, 0x7b, 0xbe, 0x0e, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 1 uHz
{ 0x00, 0x6f, 0x22, 0xf6, 0xa5, 0xac, 0x34, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 100 nHz
{ 0xb8, 0xa4, 0x36, 0x32, 0xaa, 0x77, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 10 nHz
{ 0xac, 0x43, 0xd2, 0xd1, 0x5d, 0x72, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } // 1 nHz
};
const int FTW660[6][18] = {
{ 2 , 5 , 5 , 3 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 4 , 9 , 4 , 9 , 0 , 9 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 3 , 4 , 6 , 0 , 3 , 8 , 2 , 3 , 2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 5 , 7 , 7 , 4 , 4 , 6 , 4 , 0 , 6 , 9 , 5 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 0 , 0 , 5 , 2 , 6 , 0 , 9 , 8 , 7 , 8 , 5 , 2 , 5 , 1 , 0 , 0 , 0 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 5 , 2 , 6 , 0 , 9 , 3 , 0 , 0 } };
// test of FTW vs. output frequency, 2021-09-16
// { 0xc6, 0x4b, 0x37, 0x89, 0x41, 0x00} -> close to 1 MHz?
/* old, for 660MHz
const int F660[18][14] = {
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, 0x26, 0x9b, 0x6c, 0xb2, 0xc9, 0x26 }, // 100 MHz
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe1, 0x83, 0x0f, 0x3e, 0xf8, 0xe0, 0x03 }, // 10 MHz
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x63, 0xc0, 0x34, 0x06, 0x4c, 0x63, 0x00 }, // 1 MHz
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0x09, 0xe0, 0x9e, 0x00, 0xee, 0x09, 0x00 }, // 100 kHz
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x64, 0x67, 0x16, 0x43, 0x33, 0xfe, 0x00, 0x00 }, // 10 kHz
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0xbd, 0x70, 0xb5, 0x86, 0x6b, 0x19, 0x00, 0x00 }, // 1 kHz
{ 0x00, 0x00, 0x00, 0x00, 0x80, 0x53, 0x79, 0xbe, 0xab, 0xc0, 0x8a, 0x02, 0x00, 0x00 }, // 100 Hz
{ 0x00, 0x00, 0x00, 0x00, 0xc0, 0xee, 0xd8, 0x5f, 0x44, 0x13, 0x41, 0x00, 0x00, 0x00 }, // 10 Hz
{ 0x00, 0x00, 0x00, 0xc0, 0xac, 0xe4, 0xc8, 0x3c, 0xed, 0x81, 0x06, 0x00, 0x00, 0x00 }, // 1 Hz
{ 0x00, 0x00, 0x00, 0x48, 0x11, 0x4a, 0x47, 0xb9, 0x97, 0xa6, 0x00, 0x00, 0x00, 0x00 }, // 100 mHz
{ 0x00, 0x00, 0x00, 0xed, 0x34, 0x54, 0xba, 0xc5, 0xa8, 0x10, 0x00, 0x00, 0x00, 0x00 }, // 10 mHz
{ 0x00, 0x00, 0x90, 0xe4, 0x9e, 0x3b, 0x2c, 0x7a, 0xaa, 0x01, 0x00, 0x00, 0x00, 0x00 }, // 1 mHz
{ 0x00, 0x00, 0x42, 0x7d, 0x29, 0x39, 0xd1, 0xa5, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 100 uHz
{ 0x00, 0x00, 0xed, 0xf2, 0x50, 0x1f, 0xc8, 0x43, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 10 uHz
{ 0x00, 0x14, 0x7e, 0x4b, 0xbb, 0x9c, 0x2d, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 1 uHz
{ 0x00, 0xcf, 0xbf, 0xba, 0x12, 0xf6, 0xea, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 100 nHz
{ 0xb0, 0x94, 0x79, 0xdf, 0x01, 0x7f, 0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 10 nHz
{ 0x79, 0x28, 0x8c, 0xc9, 0x19, 0xf3, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } // 1 nHz
};
const int FTW660[6][18] = {
{ 5 , 4 , 3 , 2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 7 , 6 , 2 , 0 , 0 , 6 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 5 , 2 , 2 , 8 , 6 , 6 , 3 , 5 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 2 , 5 , 5 , 5 , 6 , 0 , 9 , 3 , 3 , 9 , 3 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 0 , 5 , 2 , 1 , 8 , 7 , 0 , 0 , 8 , 0 , 7 , 0 , 0 , 1 , 0 , 0 , 0 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 5 , 2 , 1 , 8 , 7 , 5 , 2 , 0 , 0 } };
*/
// frequency tuning
/* old table
const int F660[15][6] = {
{ 0x27, 0x9b, 0x6c, 0xb2, 0xc9, 0x26 }, // 100 MHz
{ 0x84, 0x0f, 0x3e, 0xf8, 0xe0, 0x03 }, // 10 MHz
{ 0xc1, 0x34, 0x06, 0x4c, 0x63, 0x00 }, // 1 MHz
{ 0xe1, 0x9e, 0x00, 0xee, 0x09, 0x00 }, // 100 kHz
{ 0x17, 0x43, 0x33, 0xfe, 0x00, 0x00 }, // 10 kHz
{ 0xb6, 0x86, 0x6b, 0x19, 0x00, 0x00 }, // 1 kHz
{ 0xac, 0xc0, 0x8a, 0x02, 0x00, 0x00 }, // 100 Hz
{ 0x45, 0x13, 0x41, 0x00, 0x00, 0x00 }, // 10 Hz
{ 0xee, 0x81, 0x06, 0x00, 0x00, 0x00 }, // 1 Hz
{ 0x98, 0xa6, 0x00, 0x00, 0x00, 0x00 }, // 100 mHz
{ 0xa9, 0x10, 0x00, 0x00, 0x00, 0x00 }, // 10 mHz
{ 0xab, 0x01, 0x00, 0x00, 0x00, 0x00 }, // 1 mHz
{ 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 100 uHz
{ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 10 uHz
{ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 } // 1 uHz
};
const unsigned int FTW660[6][15] = {
{ 2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 0 , 0 , 6 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 8 , 6 , 6 , 3 , 5 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 5 , 6 , 0 , 9 , 3 , 3 , 9 , 3 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 1 , 8 , 7 , 0 , 0 , 8 , 0 , 7 , 0 , 0 , 1 , 0 , 0 , 0 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 , 5 , 2 , 1 , 8 , 7 , 5 , 2 , 0 , 0 } };
*/
} // end namespace
#endif
/*
* Arduino code for microstepper-project DDS-board
* AW2021-09, see https://ohwr.org/project/microstepper
*
*/
#ifndef __ADF4350_H__
#define __ADF4350_H__
namespace ADF4350 {
// ADF4350 register addresses
// https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4350.pdf
// Control Bits. Determines destination register
// Datasheet page 14/34
const int R0 = 0b000; // Resister 0 (R0), 1-reserved, 16-bit integer N, 12-bit fractional (FRAC), 3 control bits
const int R1 = 0b001; // Register 1 (R1), 4-reserved, 1-prescaler, 12-phase, 12-modulus (MOD), 3-control
const int R2 = 0b010; // Register 2 (R2), DB31:DB23 reserved, DB22 feedback select, DB22:DB20 Divider select
const int R3 = 0b011; // Resister 3 (R3)
const int R4 = 0b100; // Register 4 (R4)
const int R5 = 0b101; // Register 5 (R5)
//Register 0
// 10MHz ref in 1GHz out operation preset
// Send directly to PLL in descending order (R5 -> R0)
// old settings from 2014
//const int32_t preset1_R0 = 0x00C80000;
//const int32_t preset1_R1 = 0x08008009;
//const int32_t preset1_R2 = 0x00004E42;
//const int32_t preset1_R3 = 0x000004B3;
//const int32_t preset1_R4 = 0x00A5003C;
//const int32_t preset1_R5 = 0x00058005;
// new settings, using ADF435x Software, 2021
// Both output-A and output-B enabled, 10MHz ref, A and B both 1 GHz.
// register-values from Evaluation Software Rev 4.5.0
// https://www.analog.com/en/design-center/evaluation-hardware-and-software/evaluation-boards-kits/EVAL-ADF4350.html
const int32_t preset1_R0 = 0x01900000;
const int32_t preset1_R1 = 0x08008011;
const int32_t preset1_R2 = 0x14020E42;
const int32_t preset1_R3 = 0x000004B3;
const int32_t preset1_R4 = 0x0020A1FC;
const int32_t preset1_R5 = 0x00580005;
// 100MHz ref in 1GHz out operation preset
// Send directly to PLL in descending order (R5 -> R0)
const int32_t preset2_R0 = 0x00500000;
const int32_t preset2_R1 = 0x08008009;
const int32_t preset2_R2 = 0x01008E42;
const int32_t preset2_R3 = 0x000004B3;
const int32_t preset2_R4 = 0x00AC803C;
const int32_t preset2_R5 = 0x00058005;
} // end namespace
#endif
/*
* Arduino code for microstepper-project DDS-board
* AW2021-09, see https://ohwr.org/project/microstepper
*
* Copyright (C) 2021 Anders E.E. Wallin
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*
*
* Written for the following hardware:
* - Arduino MKR ZERO
* - Ethernet Shield for MKR ZERO
* - IO-board for SPI-signals to devices:
* -- ADF4350 PLL+VCO
* -- AD9912 DDS (2pcs A and B)
*
*/
#include "Arduino.h"
#include "ddslib.h"
#include "plllib.h"
#include "printf_wrapper.h"
// SPI pin definitions
// using MKR ZERO with IO-board
const int SPI_SDIO = 1; // D1
const int SPI_SCLK = 0; // D0
const int SPI_CSB_DDSA = 2; //D2
const int SPI_CSB_DDSB = 3; //D3
const int SPI_CSB_PLL = 4; //D4
// DDS-objects
AD9912::DDS ddsA(SPI_SDIO, SPI_CSB_DDSA, SPI_SCLK);
AD9912::DDS ddsB(SPI_SDIO, SPI_CSB_DDSB, SPI_SCLK);
// PLL-object
ADF4350::PLL pll(SPI_SDIO, SPI_CSB_PLL, SPI_SCLK);
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
delay(1000);
Serial.print("initializing.\n");
pll.preset1(); // 10MHz input, 1 GHz DDS clock
delay(1000);
delay(200);
delay(100);
ddsA.reset();
delay(100);
ddsB.reset();
delay(100);
int A_id = ddsA.read_id();
delay(20);
Serial.print(A_id);
Serial.print("\n");
int B_id = ddsB.read_id();
Serial.print(B_id);
Serial.print("\n");
delay(20);
ddsA.set_pd( AD9912::PD_HSTL | AD9912::PLL_PD); // no PLL!
delay(20);
ddsA.set_PLL_parameters(AD9912::VCO_AUTORANGE); // not required?
delay(20);
ddsA.update_registers();
delay(20);
ddsB.set_pd( AD9912::PD_HSTL | AD9912::PLL_PD); // no PLL!
delay(20);
ddsB.set_PLL_parameters(AD9912::VCO_AUTORANGE); // not required?
delay(20);
ddsB.update_registers();
delay(20);
serial_printf( "DDS A PLL_N = %d \n", ddsA.get_PLL_N() );
serial_printf( "DDS B PLL_N = %d \n", ddsB.get_PLL_N() );
int8_t f[6] = { (int8_t)0xc6, (int8_t)0x4b, (int8_t)0x37, (int8_t)0x89, (int8_t)0x41, (int8_t)0x00};
int8_t fB[6] = { (int8_t)0xc6, (int8_t)0x4b, (int8_t)0x37, (int8_t)0x89, (int8_t)0x41, (int8_t)0x00};
serial_printf("f = 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", f[5],f[4],f[3],f[2],f[1],f[0] );
// 6-element array
ddsA.set_frequency(f);
delay(20);
ddsB.set_frequency(f);
delay(20);
int8_t fr[6];
ddsA.get_frequency(fr);
delay(20);
serial_printf("fr = 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", fr[5],fr[4],fr[3],fr[2],fr[1],fr[0] );
ddsB.get_frequency(fr);
delay(20);
serial_printf("fr = 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", fr[5],fr[4],fr[3],fr[2],fr[1],fr[0] );
Serial.print("ready.\n");
}
void loop() {
// put your main code here, to run repeatedly:
}
/*
* Arduino code for microstepper-project DDS-board
* AW2021-09, see https://ohwr.org/project/microstepper
*
*/
#ifndef __DDSLIB_H__
#define __DDSLIB_H__
#include "Arduino.h"
#include "spibitbang.h"
#include "ad9912.h"
namespace AD9912 {
class DDS {
/*
experimental DDS control
AW 2014-01-02
*/
public:
DDS( int8_t SDIO, int8_t CSB, int8_t SCLK) {
spi = new SPIBitBang(SDIO, CSB, SCLK);
};
~DDS() {
delete spi;
}
// read the part ID
// should return 0x1902 = 6402 (decimal)
int8_t read_id() {
int instr = instruction( READ, BYTES_TWO, PART_ID);
int8_t id;
spi->write16read8(instr, id);
return id;
}
void reset() {
int instr = instruction( WRITE, BYTES_ONE, RESET);
spi->write24( instr, 255 );
}
void update_registers() {
int instr = instruction( WRITE, BYTES_ONE, SERIAL_OPTS_1);
spi->write24( instr, 255 );
}
void register_read_mode(int8_t mode) {
int instr = instruction( WRITE, BYTES_ONE, SERIAL_OPTS_0);
spi->write24( instr, mode );
}
// fixed divide-by-2 and 2-offset:
// set to zero, corresponds to N=4;
void set_PLL_N(int8_t n) {
int instr = instruction( WRITE, BYTES_ONE, PLL_N);
spi->write24( instr, n );
}
int8_t get_PLL_N() {
int instr = instruction( READ, BYTES_ONE, PLL_N);
int8_t n;
spi->write16read8( instr, n );
return n;
}
void set_PLL_parameters(int8_t par) {
int instr = instruction( WRITE, BYTES_ONE, PLL_PARAMETERS);
spi->write24( instr, par );
}
void set_pd(int8_t mode) {
int instr = instruction( WRITE, BYTES_ONE, PD_ENA);
spi->write24( instr, mode );
}
void set_frequency(int8_t* f) {
ftw[0]=f[0];
ftw[1]=f[1];
ftw[2]=f[2];
ftw[3]=f[3];
ftw[4]=f[4];
ftw[5]=f[5];
write_frequency();
}
void write_frequency() {
int instr = instruction( WRITE, BYTES_STREAM, FTW5);
spi->write16write48(instr, ftw);
//delay(1);
update_registers();
}
// read frequency tuning word
// initial state is set by S1-S4 pins on the AD9912
// s1 s2 s3 s4 ftw[5] ftw[4] Fout, assuming 1GHz sysclock
// 1 1 1 1 27 d0 155.51758 MHz
// 0 1 1 1 1f 75 122.87903
// 1 0 1 1 17 97 92.14783
// 0 0 1 1 13 e8 77.75879
// 1 1 0 1 0f ba 61.43188
// 0 1 0 1 0d 45 51.83411
// 1 0 0 1 09 f4 38.87939
// 1 0 0 0 00 00 0
int read_frequency() {
int instr = instruction( READ, BYTES_STREAM, FTW5);
spi->write16read48(instr, ftw);
}
void get_frequency(int8_t* f) {
read_frequency();
f[0]=ftw[0];
f[1]=ftw[1];
f[2]=ftw[2];
f[3]=ftw[3];
f[4]=ftw[4];
f[5]=ftw[5];
}
int instruction(int readwrite, int bytes, int address) {
return readwrite | bytes | address;
}
private:
SPIBitBang* spi;
int8_t ftw[6];
};
} // end namespace
#endif
/*
* Arduino code for microstepper-project DDS-board
* AW2021-09, see https://ohwr.org/project/microstepper
*
*/
#ifndef __PLLLIB_H__
#define __PLLLIB_H__
#include "Arduino.h"
#include "spibitbang.h"
#include "adf4350.h"
//#include "encoderlib.h"
//#include "FiniteStateMachine.h"
namespace ADF4350 {
class PLL {
/*
experimental PLL control
TT 2014-3-10
*/
public:
PLL( int8_t DATA, int8_t LE, int8_t CLK) {
spi = new SPIBitBang(DATA, LE, CLK);
//encoder = enc;
//iter = 0;
//numb = 2;
};
~PLL() {
delete spi;
}
// 10MHz ref in 1GHz out operation preset
void preset1(){
spi->write32_int32( ADF4350::preset1_R5 );
spi->write32_int32( ADF4350::preset1_R4 );
spi->write32_int32( ADF4350::preset1_R3 );
spi->write32_int32( ADF4350::preset1_R2 );
spi->write32_int32( ADF4350::preset1_R1 );
spi->write32_int32( ADF4350::preset1_R0 );
active = 1;
}
// 100MHz ref in 1GHz out operation preset
void preset2(){
spi->write32_int32( ADF4350::preset2_R5 );
spi->write32_int32( ADF4350::preset2_R4 );
spi->write32_int32( ADF4350::preset2_R3 );
spi->write32_int32( ADF4350::preset2_R2 );
spi->write32_int32( ADF4350::preset2_R1 );
spi->write32_int32( ADF4350::preset2_R0 );
active = 2;
}
private:
SPIBitBang* spi;
//Encoder* encoder;
//FSM* fsm;
//State* menu;
//int iter; // this is used to determine the state action
//unsigned int numb; // zero based number of state actions
unsigned int active; // number of the active preset
};
} // end namespace
#endif
/*
* Arduino code for microstepper-project DDS-board
* AW2021-09, see https://ohwr.org/project/microstepper
*
*/
#ifndef __PRINTF_WRAPPER_H__
#define __PRINTF_WRAPPER_H__
#include <stdarg.h>
// printf to Arduino serial terminal
void serial_printf(char *fmt, ... ){
char tmp[128]; // resulting string limited to 128 chars
va_list args;
va_start (args, fmt );
vsnprintf(tmp, 128, fmt, args);
va_end (args);
Serial.print(tmp);
}
#endif // __PRINTF_WRAPPER_H__
/*
* Arduino code for microstepper-project DDS-board
* AW2021-09, see https://ohwr.org/project/microstepper
*
*/
#ifndef __SPIBITBANG_H__
#define __SPIBITBANG_H__
#include "Arduino.h"
class SPIBitBang {
/*
experimental bit-banged SPI
AW 2014
native SPI api is at http://arduino.cc/en/Reference/SPI
pinSDIO is a combined MOSI/MISO data pin
pinCSB is the chip select pin
pinSCLK is the serial clock pin
*/
public:
SPIBitBang( int8_t pinSDIO, int8_t pinCSB, int8_t pinSCLK) : SDIO (pinSDIO), CSB(pinCSB), SCLK (pinSCLK) {
pinMode(SDIO, OUTPUT);
pinMode(CSB, OUTPUT);
digitalWrite( CSB, HIGH); // deactivate
pinMode(SCLK, OUTPUT);
digitalWrite( SCLK, LOW);
};
// write one byte
void write8(int8_t data) {
digitalWrite( SCLK, LOW); // ensure clock pin LOW when we start
digitalWrite( CSB, LOW);
shiftOut( SDIO, SCLK, MSBFIRST, data);
digitalWrite( CSB, HIGH);
};
// write two bytes
void write16(int data) {
digitalWrite( SCLK, LOW); // ensure clock pin LOW when we start
digitalWrite( CSB, LOW);
shiftOut( SDIO, SCLK, MSBFIRST, (data >> 8)); // high byte
shiftOut( SDIO, SCLK, MSBFIRST, data); // low byte
digitalWrite( CSB, HIGH);
};
// write three bytes:
// two-byte instruction
// one-byte data
void write24(int instruction, int8_t data) {
digitalWrite( SCLK, LOW); // ensure clock pin LOW when we start
digitalWrite( CSB, LOW);
shiftOut( SDIO, SCLK, MSBFIRST, (instruction >> 8)); // high byte
shiftOut( SDIO, SCLK, MSBFIRST, instruction); // low byte
shiftOut( SDIO, SCLK, MSBFIRST, data);
digitalWrite( CSB, HIGH);
};
// write four bytes
void write32(int data1, int data2) {
digitalWrite( SCLK, LOW); // ensure clock pin LOW when we start
digitalWrite( CSB, LOW);
shiftOut( SDIO, SCLK, MSBFIRST, (data1 >> 8)); // high byte
shiftOut( SDIO, SCLK, MSBFIRST, data1); // low byte
shiftOut( SDIO, SCLK, MSBFIRST, (data2 >> 8)); // high byte
shiftOut( SDIO, SCLK, MSBFIRST, data2); // low byte
digitalWrite( CSB, HIGH);
};
void write32_int32(int32_t data) {
digitalWrite( SCLK, LOW); // ensure clock pin LOW when we start
digitalWrite( CSB, LOW);
shiftOut( SDIO, SCLK, MSBFIRST, (data >> 24)); // high byte
shiftOut( SDIO, SCLK, MSBFIRST, (data >> 16)); // low byte
shiftOut( SDIO, SCLK, MSBFIRST, (data >> 8)); // high byte
shiftOut( SDIO, SCLK, MSBFIRST, (data)); // low byte
digitalWrite( CSB, HIGH);
};
/*
int read16() {
digitalWrite( SCLK, LOW); // ensure clock pin LOW when we start
digitalWrite( CSB, LOW);
pinMode(SDIO, INPUT);
int8_t msb = shiftIn( SDIO, SCLK, MSBFIRST);
int8_t lsb = shiftIn( SDIO, SCLK, MSBFIRST);
pinMode(SDIO, OUTPUT);
digitalWrite( CSB, HIGH);
return word(msb,lsb);
};*/
// write two bytes
// then read one byte
// the two-byte write is called "instruction", because it tells the AD9912 what to do
void write16read16(int instruction, int &data) {
digitalWrite( SCLK, LOW); // ensure clock pin LOW when we start
digitalWrite( CSB, LOW);
shiftOut( SDIO, SCLK, MSBFIRST, (instruction >> 8)); // high byte
shiftOut( SDIO, SCLK, MSBFIRST, instruction); // low byte
pinMode(SDIO, INPUT);
int8_t msb = shiftIn( SDIO, SCLK, MSBFIRST);
int8_t lsb = shiftIn( SDIO, SCLK, MSBFIRST);
digitalWrite( CSB, HIGH);
pinMode(SDIO, OUTPUT);
data = word(msb,lsb);
};
void write16read8(int instruction, int8_t &data) {
digitalWrite( SCLK, LOW); // ensure clock pin LOW when we start
digitalWrite( CSB, LOW);
shiftOut( SDIO, SCLK, MSBFIRST, (instruction >> 8)); // high byte
shiftOut( SDIO, SCLK, MSBFIRST, instruction); // low byte
pinMode(SDIO, INPUT);
int8_t msb = shiftIn( SDIO, SCLK, MSBFIRST);
digitalWrite( CSB, HIGH);
pinMode(SDIO, OUTPUT);
data = msb;
};
// used for reading the 6-byte FTW of the AD9912 DDS
// writes results to *data, supplied by the user, which must have space for the 6 bytes.
void write16read48(int instruction, int8_t* data) {
digitalWrite( SCLK, LOW); // ensure clock pin LOW when we start
digitalWrite( CSB, LOW);
shiftOut( SDIO, SCLK, MSBFIRST, (instruction >> 8)); // high byte
shiftOut( SDIO, SCLK, MSBFIRST, instruction); // low byte
pinMode(SDIO, INPUT);
data[5] = shiftIn( SDIO, SCLK, MSBFIRST);
data[4] = shiftIn( SDIO, SCLK, MSBFIRST);
data[3] = shiftIn( SDIO, SCLK, MSBFIRST);
data[2] = shiftIn( SDIO, SCLK, MSBFIRST);
data[1] = shiftIn( SDIO, SCLK, MSBFIRST);
data[0] = shiftIn( SDIO, SCLK, MSBFIRST);
digitalWrite( CSB, HIGH);
pinMode(SDIO, OUTPUT);
};
// this is used for setting the FTW (frequency tuning word) on the AD9912 DDS
// the FTW is 48 bits, or 6 bytes. We assume the *data pointer contains these bytes
// there is no error checking, so bad things will happen if *data is not the right type
void write16write48(int instruction, int8_t* data) {
digitalWrite( SCLK, LOW); // ensure clock pin LOW when we start
digitalWrite( CSB, LOW);
shiftOut( SDIO, SCLK, MSBFIRST, (instruction >> 8)); // high byte
shiftOut( SDIO, SCLK, MSBFIRST, instruction); // low byte
shiftOut( SDIO, SCLK, MSBFIRST, data[5] );
shiftOut( SDIO, SCLK, MSBFIRST, data[4] );
shiftOut( SDIO, SCLK, MSBFIRST, data[3] );
shiftOut( SDIO, SCLK, MSBFIRST, data[2] );
shiftOut( SDIO, SCLK, MSBFIRST, data[1] );
shiftOut( SDIO, SCLK, MSBFIRST, data[0] );
digitalWrite( CSB, HIGH);
};
private:
int8_t SDIO; // serial data in/out pin. OUTPUT or INPUT
int8_t CSB; // chip-select pink. OUTPUT
int8_t SCLK; // serial clock pin. OUTPUT
};
#endif
update=ke 23. joulukuuta 2020 11.17.04
update=to 16. syyskuuta 2021 13.17.56
version=1
last_client=kicad
[cvpcb]
......
......@@ -42,30 +42,30 @@ F1 = ftw_dds(400e6-4*IF) # DDS1
F2 = ftw_dds(400e6)-205 # DDS2
print 40*"-"
print "uStep output fractional frequency y"
print "FTW2 = %d (constant)" % F2
print "FTW1\t\tdFTW1\ty"
print( 40*"-" )
print( "uStep output fractional frequency y" )
print( "FTW2 = %d (constant)" % F2 )
print( "FTW1\t\tdFTW1\ty" )
ys =[]
for delta in [-5,-4,-3,-2,-1,0,1,2,3,4,5]:
delta=2*delta
F1x = F1+delta
y1 = y_out(F1x,F2)
ys.append(y1)
print "%d\t%d\t%.3g" % ( F1x, delta, y1)
print "y change due to 2 steps in FTW1: %.2g" % (min(numpy.diff(ys)))
print 40*"-"
print "uStep output fractional frequency y"
print "FTW1 = %d (constant)" % F1
print "FTW2\t\tdFTW2\ty"
print( "%d\t%d\t%.3g" % ( F1x, delta, y1) )
print( "y change due to 2 steps in FTW1: %.2g" % (min(numpy.diff(ys))) )
print( 40*"-" )
print( "uStep output fractional frequency y" )
print( "FTW1 = %d (constant)" % F1 )
print( "FTW2\t\tdFTW2\ty" )
ys =[]
for delta in [-5,-4,-3,-2,-1,0,1,2,3,4,5]:
delta=2*delta
F2x = F2+delta
y1 = y_out(F1,F2x)
ys.append(y1)
print "%d\t%d\t%.3g" % ( F2x, delta, y1)
print( "%d\t%d\t%.3g" % ( F2x, delta, y1) )
print "y change due to 2 steps in FTW2: %.2g" % (min(numpy.diff(ys)))
print 40*"-"
print( "y change due to 2 steps in FTW2: %.2g" % (min(numpy.diff(ys))) )
print( 40*"-" )
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