File Coverage

blib/lib/Device/Chip/AD9833.pm
Criterion Covered Total %
statement 73 92 79.3
branch 5 16 31.2
condition n/a
subroutine 16 18 88.8
pod 7 8 87.5
total 101 134 75.3


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4             # (C) Paul Evans, 2020-2023 -- leonerd@leonerd.org.uk
5              
6 3     3   632307 use v5.26;
  3         31  
7 3     3   17 use warnings;
  3         5  
  3         100  
8 3     3   654 use Object::Pad 0.800;
  3         11116  
  3         170  
9              
10             package Device::Chip::AD9833 0.05;
11             class Device::Chip::AD9833
12 1     1   618 :isa(Device::Chip);
  1         16969  
  1         44  
13              
14 3     3   820 use Carp;
  3         7  
  3         212  
15 3     3   1535 use Data::Bitfield 0.02 qw( bitfield boolfield );
  3         6845  
  3         241  
16              
17 3     3   23 use Future::AsyncAwait 0.38; # aync method
  3         42  
  3         16  
18              
19 3     3   212 use constant PROTOCOL => "SPI";
  3         6  
  3         253  
20              
21             use constant {
22 3         6532 REG_CONFIG => 0x0000,
23             REG_FREQ0 => 0x4000,
24             REG_FREQ1 => 0x8000,
25             REG_PHASE0 => 0xC000,
26             REG_PHASE1 => 0xE000,
27 3     3   23 };
  3         7  
28              
29             =head1 NAME
30              
31             C - chip driver for F
32              
33             =head1 SYNOPSIS
34              
35             use Device::Chip::AD9833;
36             use Future::AsyncAwait;
37              
38             my $chip = Device::Chip::AD9833->new;
39             await $chip->mount( Device::Chip::Adapter::...->new );
40              
41             await $chip->init;
42              
43             my $freq = 440; # in Hz
44             await $chip->write_FREQ0( ( $freq << 28 ) / 25E6 ); # presuming 25MHz reference
45              
46             =head1 DESCRIPTION
47              
48             This L subclass provides specific communication to an
49             F F attached to a computer via an SPI adapter.
50              
51             The reader is presumed to be familiar with the general operation of this chip;
52             the documentation here will not attempt to explain or define chip-specific
53             concepts or features, only the use of this module to access them.
54              
55             =cut
56              
57             sub SPI_options
58             {
59 2     2 0 949 return ( mode => 2 );
60             }
61              
62             field $_config = 0;
63              
64 7         11 async method _write ( $word )
  7         14  
  7         11  
65 7         18 {
66 7         35 await $self->protocol->write( pack "S>", $word )
67 7     7   397 }
68              
69             =head1 METHODS
70              
71             The following methods documented in an C expression return L
72             instances.
73              
74             =cut
75              
76             =head2 init
77              
78             await $chip->init;
79              
80             Resets the chip to a working configuration, including setting the C bit
81             appropriately for the way this module writes the frequency registers.
82              
83             This method must be called before setting the frequency using L
84             or L.
85              
86             =cut
87              
88 1         2 async method init ()
  1         1  
89 1         4 {
90 1         7 await $self->_write( REG_CONFIG | 0x2100 ); # RESET, B28=1
91 1         9838 await $self->_write( REG_CONFIG | 0x2000 ); # unreset, B28=1
92 1     1 1 376 }
93              
94             bitfield { format => "integer" }, CONFIG =>
95             B28 => boolfield( 13 ),
96             HLB => boolfield( 12 ),
97             FSELECT => boolfield( 11 ),
98             PSELECT => boolfield( 10 ),
99             SLEEP1 => boolfield( 7 ),
100             SLEEP12 => boolfield( 6 ),
101             OPBITEN => boolfield( 5 ),
102             DIV2 => boolfield( 3 ),
103             MODE => boolfield( 1 );
104              
105             =head2 read_config
106              
107             $config = await $chip->read_config;
108              
109             Returns a C reference containing the current chip configuration. Note
110             that since the chip does not support querying the configuration, this is just
111             an in-memory copy maintained by the object instance, updated by calls to
112             L.
113              
114             The hash will contain the following named fields, all booleans.
115              
116             B28
117             HLB
118             FSELECT
119             PSELECT
120             SLEEP1
121             SLEEP12
122             OPBITEN
123             DIV2
124             MODE
125              
126             In addition, a new value C will be created combining the current
127             settings of C, C and C to explain the waveform generated
128              
129             wave => "sine" | "triangle" | "square" | "square/2"
130              
131             =cut
132              
133 1         3 async method read_config ()
  1         2  
134 1         3 {
135 1         4 my %config = unpack_CONFIG( $_config );
136              
137 1         144 my $wave;
138 1 50       6 if( $config{OPBITEN} ) {
    50          
139 0 0       0 $wave = $config{DIV2} ? "square" : "square/2";
140             }
141             elsif( $config{MODE} ) {
142 0         0 $wave = "triangle";
143             }
144             else {
145 1         3 $wave = "sine";
146             }
147 1         2 $config{wave} = $wave;
148              
149 1         17 return \%config;
150 1     1 1 224 }
151              
152             =head2 change_config
153              
154             await $chip->change_config( %changes );
155              
156             Writes updates to the chip configuration. Takes named arguments of the same
157             form as returned by L, including the synthesized C
158             setting.
159              
160             =cut
161              
162 2         5 async method change_config ( %changes )
  2         5  
  2         4  
163 2         7 {
164 2 100       11 if( defined( my $wave = delete $changes{wave} ) ) {{
165 1 50       6 $changes{OPBITEN} = 1, $changes{MODE} = 0, $changes{DIV2} = 1, last if $wave eq "square";
  1         7  
166 0 0       0 $changes{OPBITEN} = 1, $changes{MODE} = 0, $changes{DIV2} = 0, last if $wave eq "square/2";
167 0 0       0 $changes{OPBITEN} = 0, $changes{MODE} = 1, last if $wave eq "triangle";
168 0 0       0 $changes{OPBITEN} = 0, $changes{MODE} = 0, last if $wave eq "sine";
169 0         0 croak "Unrecognised value for 'wave' configuration - $wave";
170             }}
171              
172 2         10 my %config = ( unpack_CONFIG( $_config ), %changes );
173              
174 2         227 $config{B28} = 1;
175              
176 2         11 await $self->_write( REG_CONFIG | ( $_config = pack_CONFIG( %config ) ) );
177 2     2 1 19152 }
178              
179             =head2 write_FREQ0
180              
181             =head2 write_FREQ1
182              
183             await $chip->write_FREQ0( $freq );
184             await $chip->write_FREQ1( $freq );
185              
186             Writes the C or C frequency control register. C<$freq> should
187             be a 28bit integer value.
188              
189             =cut
190              
191 1         2 async method write_FREQ0 ( $freq )
  1         2  
  1         1  
192 1         5 {
193 1         4 await $self->_write( REG_FREQ0 | ( $freq & 0x3FFF ) );
194 1         1479 await $self->_write( REG_FREQ0 | ( $freq >> 14 ) );
195 1     1 1 6249 }
196              
197 0         0 async method write_FREQ1 ( $freq )
  0         0  
  0         0  
198 0         0 {
199 0         0 await $self->_write( REG_FREQ1 | ( $freq & 0x3FFF ) );
200 0         0 await $self->_write( REG_FREQ1 | ( $freq >> 14 ) );
201 0     0 1 0 }
202              
203             =head2 write_PHASE0
204              
205             =head2 write_PHASE1
206              
207             await $chip->write_PHASE0( $phase );
208             await $chip->write_PHASE1( $phase );
209              
210             Writes the C or C phase control register. C<$phase> should
211             be a 12bit integer value.
212              
213             =cut
214              
215 1         4 async method write_PHASE0 ( $phase )
  1         2  
  1         3  
216 1         4 {
217 1         4 await $self->_write( REG_PHASE0 | $phase );
218 1     1 1 5246 }
219              
220 0           async method write_PHASE1 ( $phase )
  0            
  0            
221 0           {
222 0           await $self->_write( REG_PHASE1 | $phase );
223 0     0 1   }
224              
225             =head1 AUTHOR
226              
227             Paul Evans
228              
229             =cut
230              
231             0x55AA;