-
Notifications
You must be signed in to change notification settings - Fork 1
/
ad9910.c
188 lines (159 loc) · 5.41 KB
/
ad9910.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/*
* Copyright (C) 2014 Bjoern Biesenbach <bjoern at bjoern-b.de>
* 2014 homerj00 <homerj00 at web.de>
*
* 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 2 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, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <avr/io.h>
#include <util/delay.h>
#include "settings.h"
#include "ad9910.h"
#define DDS_REGISTER_CFR1 0x00
#define DDS_REGISTER_CFR1_LENGTH 4
#define DDS_REGISTER_CFR2 0x01
#define DDS_REGISTER_CFR2_LENGTH 4
#define DDS_REGISTER_CFR3 0x02
#define DDS_REGISTER_CFR3_LENGTH 4
#define DDS_REGISTER_FTW 0x07
#define DDS_REGISTER_FTW_LENGTH 4
#define DDS_REGISTER_SINGLE_TONE0 0x0E
#define DDS_REGISTER_SINGLE_TONE_LENGTH 8
#define PLL_ENABLE (1<<8)
#define PFD_RESET (1<<10)
#define REFCLK_IN_DIV_RESET_B (1<<14)
#define REFCLK_IN_DIV_BYPASS (1<<15)
#define PLL_N(X) ((uint32_t)X<<1)
#define PLL_ICP(X) ((uint32_t)X<<19)
#define PLL_VCO_SEL(X) ((uint32_t)X<<24)
#define PLL_DRV0(X) ((uint32_t)X<<28)
#define DAC_POWER_DOWN 6
#define DDS_POWER_DOWN 7
#define DDS_CS_SET() DDS_PORT0 |= (1<<DDS_CS);
#define DDS_CS_CLR() DDS_PORT0 &= ~(1<<DDS_CS);
#define DDS_DO_IOUPDATE() DDS_PORT0 |= (1<<DDS_IO_UPDATE); DDS_PORT0 &= ~(1<<DDS_IO_UPDATE);
//#define FREQUENCY_FACTOR 2235 // divide by 10000
#define FREQUENCY_FACTOR 4.474705
static uint8_t *uint64_to_uint8_array(uint64_t value)
{
uint8_t i;
static uint8_t values[8];
for (i = 0; i < 8; i++) {
values[8 - i - 1] = (value >> ((8 - i - 1) * 8)) & 0xFF;
}
return values;
}
static uint8_t *uint32_to_uint8_array(uint32_t value)
{
uint8_t i;
static uint8_t values[4];
for (i = 0; i < 4; i++) {
values[4 - i - 1] = (value >> ((4 - i - 1) * 8)) & 0xFF;
}
return values;
}
static void dds_cmd(uint8_t address, uint8_t read_access, uint8_t * values,
uint8_t size)
{
uint8_t i;
uint32_t temp;
DDS_CS_CLR(); // Start transfer
_delay_us(1);
SPDR = (address & 0x1F) | (read_access << 7);
while (!(SPSR & (1 << SPIF))); // wait until transmission finished
for (i = 0; i < size; i++) {
// Start with upper byte (MSB first)
temp = values[size - i - 1];
SPDR = temp & 0xFF;
while (!(SPSR & (1 << SPIF))); // wait until transmission finished
}
DDS_CS_SET(); // End of transfer
_delay_us(1);
}
static void dds_cmd_32(uint8_t address, uint8_t read_access,
uint32_t value, uint8_t size)
{
uint8_t *values;
if (size > 4)
return;
values = uint32_to_uint8_array(value);
dds_cmd(address, read_access, values, size);
}
static void dds_cmd_64(uint8_t address, uint8_t read_access,
uint64_t value, uint8_t size)
{
uint8_t *values;
if (size > 8)
return;
values = uint64_to_uint8_array(value);
dds_cmd(address, read_access, values, size);
}
void dds_power(uint8_t on)
{
if(!on){ // off
PORTA &= ~(1 << OUTPUT_LED);
dds_cmd_32(DDS_REGISTER_CFR1, 0, (uint32_t)(1 << DDS_POWER_DOWN),
DDS_REGISTER_CFR1_LENGTH);
}else{ // on
PORTA |= (1 << OUTPUT_LED);
dds_cmd_32(DDS_REGISTER_CFR1, 0, (uint32_t)(0 << DDS_POWER_DOWN),
DDS_REGISTER_CFR1_LENGTH);
}
DDS_DO_IOUPDATE();
}
void ad9910_init()
{
DDRB |=
(1 << DDS_CS) | (1 << DDS_SCK) | (1 << DDS_MOSI) |
(1 <<DDS_MASTER_RESET)| (1 << DDS_IO_UPDATE) | (1 << DDS_IO_RESET);
// RESET
PORTB |= (1 << DDS_CS) | (1 << DDS_IO_RESET) | (1 << DDS_MASTER_RESET);
_delay_ms(1);
PORTB &= ~((1 << DDS_IO_RESET) | (1 << DDS_MASTER_RESET));
DDRE |=
(1 << DDS_OSK) | (1 << DDS_DRCTL) | (1 << DDS_PROFILE0) |
(1 <<DDS_PROFILE1)| (1 << DDS_PROFILE2);
PORTE |= (1 << DDS_OSK);
PORTE &= ~(1 << DDS_DRCTL);
DDRG = (1 << PGA0) | (1 << PGA1) | (1 << PGA2) | (1 << PGA3);
PORTG = (0 << PGA0) | (1 << PGA1) | (0 << PGA2) | (1 << PGA3);
// LED
DDRA = (1 << OUTPUT_LED);
//SPI
SPCR |=
(1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0) | (0 << CPOL);
//SPSR |= (1<<SPI2X);
dds_cmd_32(DDS_REGISTER_CFR3, 0,
PLL_N(40) | PLL_ENABLE | REFCLK_IN_DIV_RESET_B | PLL_DRV0(1)
| PLL_VCO_SEL(5) | PLL_ICP(3), DDS_REGISTER_CFR3_LENGTH);
DDS_DO_IOUPDATE();
dds_power(0);
}
void dds_set_single_tone_frequency(uint16_t amplitude, uint32_t frequency)
{
uint64_t val;
uint16_t phase = 0;
val =
((uint64_t) amplitude & 0x3FFF) << 48 | (uint64_t) phase << 32 |
(uint32_t) (((double) frequency * FREQUENCY_FACTOR));
dds_cmd_64(DDS_REGISTER_SINGLE_TONE0, 0, val,
DDS_REGISTER_SINGLE_TONE_LENGTH);
DDS_DO_IOUPDATE();
}
void pga_set_gain(uint8_t gain)
{
gain = (gain & 0x03) | ((gain & 0x8) >> 1) | ((gain & 0x04) << 1);
PORTG = gain & (1 << PGA0 | 1 << PGA1 | 1 << PGA2 | 1 << PGA3);
}