File Coverage

blib/lib/Device/Chip/AVR_HVSP.pm
Criterion Covered Total %
statement 310 344 90.1
branch 27 48 56.2
condition 8 21 38.1
subroutine 41 51 80.3
pod 21 23 91.3
total 407 487 83.5


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, 2014-2023 -- leonerd@leonerd.org.uk
5              
6 3     3   513962 use v5.26;
  3         25  
7 3     3   14 use warnings;
  3         5  
  3         112  
8 3     3   538 use Object::Pad 0.800;
  3         9122  
  3         139  
9              
10             package Device::Chip::AVR_HVSP 0.07;
11             class Device::Chip::AVR_HVSP
12 1     1   492 :isa(Device::Chip);
  1         13904  
  1         37  
13              
14 3     3   711 use Carp;
  3         6  
  3         155  
15              
16 3     3   15 use Future::AsyncAwait;
  3         6  
  3         13  
17              
18 3     3   1375 use Object::Pad::ClassAttr::Struct 0.05;
  3         2766  
  3         13  
19              
20 3     3   148 use constant PROTOCOL => "GPIO";
  3         6  
  3         1847  
21              
22             =head1 NAME
23              
24             C - high-voltage serial programming for F chips
25              
26             =head1 DESCRIPTION
27              
28             This L subclass allows interaction with an F
29             microcontroller of the F family in high-voltage serial programming
30             (HVSP) mode. It is particularly useful for configuring fuses or working with a
31             chip with the C fuse programmed, because in such cases a regular ISP
32             programmer cannot be used.
33              
34             =head2 CONNECTIONS
35              
36             To use this module you will need to make connections to the pins of the
37             F chip:
38              
39             ATtiny | tiny84 | tiny85
40             -------+--------+-------
41             SDO | 9 | 7
42             SII | 8 | 6
43             SDI | 7 | 5
44             SCI | 2 | 2
45             RESET | 4 | 1
46             Vcc | 1 | 8
47             GND | 14 | 4
48              
49             This module recognises the following kinds of adapter and automatically
50             assigns default pin connections for likely configurations:
51              
52             Bus Pirate | Sparkfun | Seeed |:| ATtiny
53             | cable | cable |:|
54             -----------+----------+----------+-+-------
55             MISO | brown | black |:| SDO
56             CS | red | white |:| SII
57             MOSI | orange | grey |:| SDI
58             CLK | yellow | purple |:| SCI
59             AUX | green | blue |:| HV control
60             +5V | grey | orange |:| Vcc
61             GND | black | brown |:| GND
62              
63             Z<>
64              
65             FTDI |:| ATtiny
66             -----+-+-------
67             D0 |:| SCI
68             D1 |:| SDI
69             D2 |:| SDO
70             D3 |:| SII
71             D4 |:| HV control
72              
73             For other kinds of adapter, use the named parameters to the L method
74             to tell the chip driver which F pin is connected to what GPIO line.
75              
76             The C line from the adapter will need to be able to control a +12V
77             supply to the C pin of the F chip. It should be active-high,
78             and can be achieved by a two-stage NPN-then-PNP transistor arrangement.
79              
80             Additionally, the C pin and the C to C pins of 14-pin devices
81             will need a pull-down to ground of around 100Ohm to 1kOhm.
82              
83             =cut
84              
85             =head1 MOUNT PARAMETERS
86              
87             =head2 sdi, sii, sci, sdo
88              
89             The names of GPIO lines on the adapter that are connected to the HVSP signal
90             pins of the F chip.
91              
92             =head2 hv
93              
94             The name of the GPIO line on the adapter that is connected to the 12V power
95             supply control.
96              
97             =head1 METHODS
98              
99             The following methods documented in an C expression return L
100             instances.
101              
102             =cut
103              
104             my %DEFAULT_PINS = (
105             'Device::Chip::Adapter::BusPirate' => {
106             sdi => "MOSI",
107             sii => "CS",
108             sci => "CLK",
109             sdo => "MISO",
110             hv => "AUX",
111             },
112              
113             'Device::Chip::Adapter::FTDI' => {
114             sdi => "D1",
115             sii => "D3",
116             sci => "D0",
117             sdo => "D2",
118             hv => "D4",
119             },
120              
121             # For unit testing this is convenient
122             'Test::Device::Chip::Adapter' => {
123             map { $_ => $_ } qw( sdi sii sci sdo hv )
124             },
125             );
126              
127             field %_pins;
128              
129 2         4 async method mount ( $adapter, %params )
  2         4  
  2         5  
  2         3  
130 2         6 {
131 2 50       10 if( my $pins = $DEFAULT_PINS{ref $adapter} ) {
132 2         26 %params = ( %$pins, %params );
133             }
134              
135 2         8 foreach my $pin (qw( sdi sii sci sdo hv )) {
136 10 50       22 defined $params{$pin} or croak "Require a pin assignment for '$pin'" ;
137              
138 10         14 $_pins{$pin} = $params{$pin};
139             }
140              
141 2         18 await $self->SUPER::mount( $adapter, %params );
142              
143             await $self->protocol->write_gpios( {
144             $_pins{sdi} => 0,
145             $_pins{sii} => 0,
146 2         1173 $_pins{sci} => 0,
147             });
148              
149             # Set input
150 2         16537 await $self->protocol->tris_gpios( [ $_pins{sdo} ] );
151 2     2 1 410 }
152              
153             =head2 start
154              
155             await $chip->start;
156              
157             Powers up the device, reads and checks the signature, ensuring it is a
158             recognised chip.
159              
160             This method leaves the chip powered up with +5V on Vcc and +12V on RESET. Use
161             the C, C or C methods to turn these off if it is
162             not required again immediately.
163              
164             =cut
165              
166             class Device::Chip::AVR_HVSP::_PartInfo :Struct(readonly)
167             {
168 15     15   22 field $signature;
  15         48  
169 2     2   5 field $flash_words;
  2         8  
170 66     66   274 field $flash_pagesize;
  66         261  
171 2     2   6 field $eeprom_words;
  2         10  
172 2     2   4 field $eeprom_pagesize;
  2         9  
173 1     1   2 field $has_efuse;
  1         6  
174             }
175 51     51 0 120 sub PartInfo { Device::Chip::AVR_HVSP::_PartInfo->new_values( @_ ) }
176              
177             class Device::Chip::AVR_HVSP::_MemoryInfo :Struct(readonly)
178             {
179 0     0   0 field $wordsize;
  0         0  
180 0     0   0 field $pagesize;
  0         0  
181 0     0   0 field $words;
  0         0  
182 0     0   0 field $can_write;
  0         0  
183             }
184 8     8 0 27 sub MemoryInfo { Device::Chip::AVR_HVSP::_MemoryInfo->new_values( @_ ) }
185              
186             my %PARTS;
187             {
188 1     1 1 62 local $_;
189             while( ) {
190             my ( $name, $data ) = m/^(\S+)\s*=\s*(.*?)\s*$/ or next;
191             $PARTS{$name} = PartInfo( split /\s+/, $data );
192             }
193             }
194              
195 1         5 field $_partname :reader;
196             field $_partinfo;
197             field @_memories;
198              
199 1         3 async method start ()
  1         2  
200 1         4 {
201 1         4 await $self->all_power(1);
202              
203 1         1301 my $sig = uc unpack "H*", await $self->read_signature;
204              
205 1         65 my $partinfo;
206             my $part;
207             ( $partinfo = $PARTS{$_} )->signature eq $sig and $part = $_, last
208 1   66     13 for keys %PARTS;
209              
210 1 50       5 defined $part or die "Unrecognised signature $sig\n";
211              
212 1         2 $_partname = $part;
213 1         2 $_partinfo = $partinfo;
214              
215 1 50       5 @_memories = (
216             # ws ps nw wr
217             signature => MemoryInfo( 8, 3, 3, 0 ),
218             calibration => MemoryInfo( 8, 1, 1, 0 ),
219             lock => MemoryInfo( 8, 1, 1, 1 ),
220             lfuse => MemoryInfo( 8, 1, 1, 1 ),
221             hfuse => MemoryInfo( 8, 1, 1, 1 ),
222             ( $partinfo->has_efuse ?
223             ( efuse => MemoryInfo( 8, 1, 1, 1 ) ) :
224             () ),
225             flash => MemoryInfo( 16, $partinfo->flash_pagesize, $partinfo->flash_words, 1 ),
226             eeprom => MemoryInfo( 8, $partinfo->eeprom_pagesize, $partinfo->eeprom_words, 1 ),
227             );
228              
229 1         5 return $self;
230 1     1 1 4690 }
231              
232             =head2 stop
233              
234             await $chip->stop;
235              
236             Shut down power to the device.
237              
238             =cut
239              
240 0         0 async method stop ()
  0         0  
241 0         0 {
242 0         0 await $self->all_power(0);
243 0     0 1 0 }
244              
245             =head2 power
246              
247             await $chip->power( $on );
248              
249             Controls +5V to the Vcc pin of the F chip.
250              
251             =cut
252              
253 1         2 async method power ( $on )
  1         2  
  1         2  
254 1         3 {
255 1         4 await $self->protocol->power( $on );
256 1     1 1 2 }
257              
258             =head2 hv_power
259              
260             await $chip->hv_power( $on );
261              
262             Controls +12V to the RESET pin of the F chip.
263              
264             =cut
265              
266 1         2 async method hv_power ( $on )
  1         2  
  1         2  
267 1         3 {
268 1         3 await $self->protocol->write_gpios( { $_pins{hv} => $on } );
269 1     1 1 3 }
270              
271             =head2 all_power
272              
273             await $chip->all_power( $on );
274              
275             Controls both +5V and +12V supplies at once. The +12V supply is turned on last
276             but off first, ensuring the correct HVSP-RESET sequence is applied to the
277             chip.
278              
279             =cut
280              
281 1         3 async method all_power ( $on )
  1         2  
  1         2  
282 1         2 {
283             # Allow power to settle before turning on +12V on AUX
284             # Normal serial line overheads should allow enough time here
285              
286 1 50       3 if( $on ) {
287 1         5 await $self->power(1);
288 1         104 await $self->hv_power(1);
289             }
290             else {
291 0         0 await $self->hv_power(0);
292 0         0 await $self->power(0);
293             }
294 1     1 1 2 }
295              
296             =head2 $name = $chip->partname
297              
298             Returns the name of the chip whose signature was detected by the C
299             method.
300              
301             =cut
302              
303             # :reader
304              
305             =head2 $memory = $avr->memory_info( $name )
306              
307             Returns a memory info structure giving details about the named memory for the
308             attached part. The following memory names are recognised:
309              
310             signature calibration lock lfuse hfuse efuse flash eeprom
311              
312             (Note that the F has no C memory).
313              
314             The structure will respond to the following methods:
315              
316             =over 4
317              
318             =item * wordsize
319              
320             Returns number of bits per word. This will be 8 for the byte-oriented
321             memories, but 16 for the main program flash.
322              
323             =item * pagesize
324              
325             Returns the number of words per page; the smallest amount that can be
326             written in one go.
327              
328             =item * words
329              
330             Returns the total number of words that are available.
331              
332             =item * can_write
333              
334             Returns true if the memory type can be written (in general; this does not take
335             into account the lock bits that might futher restrict a particular chip).
336              
337             =back
338              
339             =cut
340              
341 0         0 method memory_info ( $name )
  0         0  
  0         0  
342 0     0 1 0 {
343             $_memories[$_*2] eq $name and return $_memories[$_*2 + 1]
344 0   0     0 for 0 .. $#_memories/2;
345              
346 0         0 die "$_partname does not have a $name memory";
347             }
348              
349             =head2 %memories = $avr->memory_infos
350              
351             Returns a key/value list of all the known device memories.
352              
353             =cut
354              
355 0         0 method memory_infos ()
  0         0  
356 0     0 1 0 {
357 0         0 return @_memories;
358             }
359              
360             =head2 $fuseinfo = $avr->fuseinfo
361              
362             Returns a L instance containing information
363             on the fuses in the attached device type.
364              
365             =cut
366              
367 0         0 method fuseinfo ()
  0         0  
368 0     0 1 0 {
369 0         0 require Device::Chip::AVR_HVSP::FuseInfo;
370 0         0 return Device::Chip::AVR_HVSP::FuseInfo->for_part( $self->partname );
371             }
372              
373 1         2 async method _transfer ( $sdi, $sii )
  1         2  
  1         1  
  1         2  
374 1         4 {
375 1         3 my $SCI = $_pins{sci};
376 1         3 my $SDI = $_pins{sdi};
377 1         2 my $SII = $_pins{sii};
378 1         2 my $SDO = $_pins{sdo};
379              
380 1         2 my $sdo = 0;
381 1         3 my $proto = $self->protocol;
382              
383             # A "byte" transfer consists of 11 clock transitions; idle low. Each bit is
384             # clocked in from SDO on the falling edge of clocks 0 to 7, but clocked out
385             # of SDI and SII on clocks 1 to 8.
386             # We'll therefore toggle the clock 11 times; on each of the first 8 clocks
387             # we raise it, then simultaneously lower it, writing out the next out bits
388             # and reading in the input.
389             # Serial transfer is MSB first in both directions
390             #
391             # We cheat massively here and rely on pipeline ordering of the actual
392             # ->write calls, by writing all 22 of the underlying bit transitions to the
393             # underlying device, then waiting on all 11 reads to come back.
394              
395 1         7 my @f;
396 1         4 foreach my $i ( 0 .. 10 ) {
397 11 100       16974 my $mask = $i < 8 ? (1 << 7-$i) : 0;
398              
399 11         163 push @f, $proto->write_gpios( { $SCI => 1 } );
400              
401 11 100       11338 if( !$mask ) {
402 3         11 push @f, $proto->write_gpios( { $SCI => 0 } );
403 3         3074 next;
404             }
405              
406             # TODO: this used to be
407             # $mode->writeread
408             # on the BusPirate version
409 8         10 push @f,
410             $proto->write_gpios( {
411             $SDI => ( $sdi & $mask ),
412             $SII => ( $sii & $mask ),
413             $SCI => 0
414             } ),
415              
416 8     8   1770 $proto->read_gpios( [ $SDO ] )->on_done( sub ( $v ) {
  8         8  
417 8 100       21 $sdo |= $mask if $v->{$SDO};
418 8         42 });
419             }
420              
421 1         12 await Future->needs_all( @f );
422              
423 1         362 return $sdo;
424 1     1   6716 }
425              
426 99         176 async method _await_SDO_high ()
  99         228  
427 99         603 {
428 99         261 my $SDO = $_pins{sdo};
429              
430 99         517 my $proto = $self->protocol;
431              
432 99         646 my $count = 50;
433 99         187 while(1) {
434 99 50       387 $count-- or die "Timeout waiting for device to ACK";
435              
436 99 50       507 last if ( await $proto->read_gpios( [ $SDO ] ) )->{$SDO};
437             }
438 99     99   339 }
439              
440             # The AVR datasheet on HVSP does not name any of these operations, only
441             # giving them bit patterns. We'll use the names invented by RikusW. See also
442             # https://sites.google.com/site/megau2s/
443              
444             use constant {
445             # SII values
446 3         906 HVSP_CMD => 0x4C, # Command
447             HVSP_LLA => 0x0C, # Load Lo Address
448             HVSP_LHA => 0x1C, # Load Hi Address
449             HVSP_LLD => 0x2C, # Load Lo Data
450             HVSP_LHD => 0x3C, # Load Hi Data
451             HVSP_WLB => 0x64, # Write Lo Byte = WRL = WFU0
452             HVSP_WHB => 0x74, # Write Hi Byte = WRH = WFU1
453             HVSP_WFU2 => 0x66, # Write Extended Fuse
454             HVSP_RLB => 0x68, # Read Lo Byte
455             HVSP_RHB => 0x78, # Read Hi Byte
456             HVSP_RSIG => 0x68, # Read Signature
457             HVSP_RFU0 => 0x68, # Read Low Fuse
458             HVSP_RFU1 => 0x7A, # Read High Fuse
459             HVSP_RFU2 => 0x6A, # Read Extended Fuse
460             HVSP_REEP => 0x68, # Read EEPROM
461             HVSP_ROSC => 0x78, # Read Oscillator calibration
462             HVSP_RLCK => 0x78, # Read Lock
463             HVSP_PLH => 0x7D, # Page Latch Hi
464             HVSP_PLL => 0x6D, # Page Latch Lo
465             HVSP_ORM => 0x0C, # OR mask for SII to pulse actual read/write operation
466              
467             # HVSP_CMD Commands
468             CMD_CE => 0x80, # Chip Erase
469             CMD_WFUSE => 0x40, # Write Fuse
470             CMD_WLOCK => 0x20, # Write Lock
471             CMD_WFLASH => 0x10, # Write FLASH
472             CMD_WEEP => 0x11, # Write EEPROM
473             CMD_RSIG => 0x08, # Read Signature
474             CMD_RFUSE => 0x04, # Read Fuse
475             CMD_RFLASH => 0x02, # Read FLASH
476             CMD_REEP => 0x03, # Read EEPROM
477             CMD_ROSC => 0x08, # Read Oscillator calibration
478             CMD_RLOCK => 0x04, # Read Lock
479 3     3   9989 };
  3         6  
480             # Some synonyms not found in the AVR ctrlstack software
481             use constant {
482 3         5031 HVSP_WLCK => HVSP_WLB, # Write Lock
483             HVSP_WFU0 => HVSP_WLB, # Write Low Fuse
484             HVSP_WFU1 => HVSP_WHB, # Write High Fuse
485 3     3   19 };
  3         5  
486              
487             =head2 chip_erase
488              
489             await $avr->chip_erase;
490              
491             Performs an entire chip erase. This will clear the flash and EEPROM memories,
492             before resetting the lock bits. It does not affect the fuses.
493              
494             =cut
495              
496 1         2 async method chip_erase ()
  1         2  
497 1         4 {
498 1         3 await $self->_transfer( CMD_CE, HVSP_CMD );
499              
500 1         503 await $self->_transfer( 0, HVSP_WLB );
501 1         461 await $self->_transfer( 0, HVSP_WLB|HVSP_ORM );
502              
503 1         457 await $self->_await_SDO_high;
504 1     1 1 5751 }
505              
506             =head2 read_signature
507              
508             $bytes = await $avr->read_signature;
509              
510             Reads the three device signature bytes and returns them in as a single binary
511             string.
512              
513             =cut
514              
515 2         4 async method read_signature ()
  2         2  
516 2         8 {
517 2         8 await $self->_transfer( CMD_RSIG, HVSP_CMD );
518              
519 2         1042 my @sig;
520 2         7 foreach my $byte ( 0 .. 2 ) {
521 6         1873 await $self->_transfer( $byte, HVSP_LLA );
522 6         2838 await $self->_transfer( 0, HVSP_RSIG );
523 6         2760 push @sig, await $self->_transfer( 0, HVSP_RSIG|HVSP_ORM );
524             }
525              
526 2         1017 return pack "C*", @sig;
527 2     2 1 4632 }
528              
529             =head2 read_calibration
530              
531             $byte = await $avr->read_calibration;
532              
533             Reads the calibration byte.
534              
535             =cut
536              
537 1         2 async method read_calibration ()
  1         2  
538 1         5 {
539 1         3 await $self->_transfer( CMD_ROSC, HVSP_CMD );
540              
541 1         473 await $self->_transfer( 0, HVSP_LLA );
542 1         459 await $self->_transfer( 0, HVSP_ROSC );
543 1         457 my $val = await $self->_transfer( 0, HVSP_ROSC|HVSP_ORM );
544              
545 1         460 return chr $val;
546 1     1 1 3991 }
547              
548             =head2 read_lock
549              
550             $byte = await $avr->read_lock;
551              
552             Reads the lock byte.
553              
554             =cut
555              
556 1         2 async method read_lock ()
  1         3  
557 1         4 {
558 1         3 await $self->_transfer( CMD_RLOCK, HVSP_CMD );
559              
560 1         478 await $self->_transfer( 0, HVSP_RLCK );
561 1         458 my $val = await $self->_transfer( 0, HVSP_RLCK|HVSP_ORM );
562              
563 1         457 return chr( $val & 3 );
564 1     1 1 3699 }
565              
566             =head2 write_lock
567              
568             await $avr->write_lock( $byte );
569              
570             Writes the lock byte.
571              
572             =cut
573              
574 1         2 async method write_lock ( $byte )
  1         3  
  1         18  
575 1         38 {
576 1         6 await $self->_transfer( CMD_WLOCK, HVSP_CMD );
577              
578 1         492 await $self->_transfer( ( ord $byte ) & 3, HVSP_LLD );
579 1         525 await $self->_transfer( 0, HVSP_WLCK );
580 1         459 await $self->_transfer( 0, HVSP_WLCK|HVSP_ORM );
581              
582 1         456 await $self->_await_SDO_high;
583 1     1 1 3837 }
584              
585             =head2 read_fuse_byte
586              
587             $int = await $avr->read_fuse_byte( $fuse );
588              
589             Reads one of the fuse bytes C, C, C, returning an
590             integer.
591              
592             =cut
593              
594             my %SII_FOR_FUSE_READ = (
595             lfuse => HVSP_RFU0,
596             hfuse => HVSP_RFU1,
597             efuse => HVSP_RFU2,
598             );
599              
600 1         1 async method read_fuse_byte ( $fuse )
  1         2  
  1         2  
601 1         5 {
602 1 50       8 my $sii = $SII_FOR_FUSE_READ{$fuse} or croak "Unrecognised fuse type '$fuse'";
603              
604 1 50 33     5 $fuse eq "efuse" and !$_partinfo->has_efuse and
605             croak "This part does not have an 'efuse'";
606              
607 1         10 await $self->_transfer( CMD_RFUSE, HVSP_CMD );
608              
609 1         479 await $self->_transfer( 0, $sii );
610 1         459 return await $self->_transfer( 0, $sii|HVSP_ORM );
611 1     1 1 4813 }
612              
613             =head2 write_fuse_byte
614              
615             await $avr->write_fuse_byte( $fuse, $byte );
616              
617             Writes one of the fuse bytes C, C, C from an integer.
618              
619             =cut
620              
621             my %SII_FOR_FUSE_WRITE = (
622             lfuse => HVSP_WFU0,
623             hfuse => HVSP_WFU1,
624             efuse => HVSP_WFU2,
625             );
626              
627 1         3 async method write_fuse_byte ( $fuse, $byte )
  1         1  
  1         2  
  1         2  
628 1         3 {
629 1 50       4 my $sii = $SII_FOR_FUSE_WRITE{$fuse} or croak "Unrecognised fuse type '$fuse'";
630              
631 1 50 33     5 $fuse eq "efuse" and !$_partinfo->has_efuse and
632             croak "This part does not have an 'efuse'";
633              
634 1         3 await $self->_transfer( CMD_WFUSE, HVSP_CMD );
635              
636 1         483 await $self->_transfer( $byte, HVSP_LLD );
637 1         487 await $self->_transfer( 0, $sii );
638 1         460 await $self->_transfer( 0, $sii|HVSP_ORM );
639              
640 1         456 await $self->_await_SDO_high;
641 1     1 1 4280 }
642              
643             =head2 read_lfuse
644              
645             =head2 read_hfuse
646              
647             =head2 read_efuse
648              
649             $byte = await $avr->read_lfuse;
650              
651             $byte = await $avr->read_hfuse;
652              
653             $byte = await $avr->read_efuse;
654              
655             Convenient shortcuts to reading the low, high and extended fuses directly,
656             returning a byte.
657              
658             =head2 write_lfuse
659              
660             =head2 write_hfuse
661              
662             =head2 write_efuse
663              
664             await $avr->write_lfuse( $byte );
665              
666             await $avr->write_hfuse( $byte );
667              
668             await $avr->write_efuse( $byte );
669              
670             Convenient shortcuts for writing the low, high and extended fuses directly,
671             from a byte.
672              
673             =cut
674              
675 1         4 foreach my $fuse (qw( lfuse hfuse efuse )) {
676 3     3   21 no strict 'refs';
  3         6  
  3         7923  
677 0     0   0 *{"read_$fuse"} = async sub {
678 0         0 return chr await $_[0]->read_fuse_byte( $fuse );
679             };
680 0     0   0 *{"write_$fuse"} = async sub {
681 0         0 await $_[0]->write_fuse_byte( $fuse, ord $_[1] );
682             };
683             }
684              
685             =head2 read_flash
686              
687             $bytes = await $avr->read_flash( %args );
688              
689             Reads a range of the flash memory and returns it as a binary string.
690              
691             Takes the following optional arguments:
692              
693             =over 4
694              
695             =item start => INT
696              
697             =item stop => INT
698              
699             Address range to read. If omitted, reads the entire memory.
700              
701             =item bytes => INT
702              
703             Alternative to C; gives the nubmer of bytes (i.e. not words of flash)
704             to read.
705              
706             =back
707              
708             =cut
709              
710 1         2 async method read_flash ( %opts )
  1         2  
711 1         4 {
712 1 50       7 my $partinfo = $_partinfo or croak "Cannot ->read_flash of an unrecognised part";
713              
714 1   50     4 my $start = $opts{start} // 0;
715             my $stop = $opts{stop} //
716 1 50 33     10 $opts{bytes} ? $start + ( $opts{bytes}/2 ) : $partinfo->flash_words;
717              
718 1         2 my $bytes = "";
719              
720 1         3 await $self->_transfer( CMD_RFLASH, HVSP_CMD );
721 1         483 my $cur_ahi = -1;
722              
723 1         5 foreach my $addr ( $start .. $stop - 1 ) {
724 1         2 my $alo = $addr & 0xff;
725 1         2 my $ahi = $addr >> 8;
726              
727 1         3 await $self->_transfer( $alo, HVSP_LLA );
728              
729 1 50       465 await $self->_transfer( $cur_ahi = $ahi, HVSP_LHA ) if $cur_ahi != $ahi;
730              
731 1         460 await $self->_transfer( 0, HVSP_RLB );
732 1         459 $bytes .= chr await $self->_transfer( 0, HVSP_RLB|HVSP_ORM );
733              
734 1         472 await $self->_transfer( 0, HVSP_RHB );
735 1         493 $bytes .= chr await $self->_transfer( 0, HVSP_RHB|HVSP_ORM );
736             }
737              
738 1         463 return $bytes;
739 1     1 1 525 }
740              
741             =head2 write_flash
742              
743             await $avr->write_flash( $bytes );
744              
745             Writes the flash memory from the binary string.
746              
747             =cut
748              
749 1         2 async method write_flash ( $bytes )
  1         3  
  1         2  
750 1         8 {
751 1 50       4 my $partinfo = $_partinfo or croak "Cannot ->write_flash of an unrecognised part";
752 1         6 my $nbytes_page = $partinfo->flash_pagesize * 2; # words are 2 bytes
753              
754 1 50       5 croak "Cannot write - too large" if length $bytes > $partinfo->flash_words * 2;
755              
756 1         5 await $self->_transfer( CMD_WFLASH, HVSP_CMD );
757              
758 1         937 my @chunks = $bytes =~ m/(.{1,$nbytes_page})/gs;
759 1         5 my $addr = 0;
760              
761 1         3 foreach my $chunk ( @chunks ) {
762 64         101112 my $thisaddr = $addr;
763 64         324 $addr += $partinfo->flash_pagesize;
764              
765 64         284 await $self->_write_flash_page( $chunk, $thisaddr );
766             }
767              
768 1         1661 await $self->_transfer( 0, HVSP_CMD );
769 1     1 1 43594 }
770              
771 64         158 async method _write_flash_page ( $bytes, $baseaddr )
  64         104  
  64         125  
  64         88  
772 64         156 {
773 64         260 foreach my $idx ( 0 .. length($bytes)/2 - 1 ) {
774 1024         350242 my $addr = $baseaddr + $idx;
775 1024         2192 my $byte_lo = substr $bytes, $idx*2, 1;
776 1024         1624 my $byte_hi = substr $bytes, $idx*2 + 1, 1;
777              
778             # Datasheet disagrees with the byte value written in the final
779             # instruction. Datasheet says 6C even though the OR mask would yield
780             # the value 6E. It turns out emperically that either value works fine
781             # so for neatness of following other code patterns, we use 6E here.
782              
783 1024         2702 await $self->_transfer( $addr & 0xff, HVSP_LLA );
784 1024         376134 await $self->_transfer( ord $byte_lo, HVSP_LLD );
785 1024         371262 await $self->_transfer( 0, HVSP_PLL );
786 1024         372957 await $self->_transfer( 0, HVSP_PLL|HVSP_ORM );
787 1024         369518 await $self->_transfer( ord $byte_hi, HVSP_LHD );
788 1024         371877 await $self->_transfer( 0, HVSP_PLH );
789 1024         370220 await $self->_transfer( 0, HVSP_PLH|HVSP_ORM );
790             }
791              
792 64         24064 await $self->_transfer( $baseaddr >> 8, HVSP_LHA );
793 64         22921 await $self->_transfer( 0, HVSP_WLB );
794 64         22760 await $self->_transfer( 0, HVSP_WLB|HVSP_ORM );
795 64         23001 await $self->_await_SDO_high;
796 64     64   140 }
797              
798             =head2 read_eeprom
799              
800             $bytes = await $avr->read_eeprom( %args );
801              
802             Reads a range of the EEPROM memory and returns it as a binary string.
803              
804             Takes the following optional arguments:
805              
806             =over 4
807              
808             =item start => INT
809              
810             =item stop => INT
811              
812             Address range to read. If omitted, reads the entire memory.
813              
814             =item bytes => INT
815              
816             Alternative to C; gives the nubmer of bytes to read.
817              
818             =back
819              
820             =cut
821              
822 1         2 async method read_eeprom ( %opts )
  1         5  
  1         2  
823 1         9 {
824 1 50       12 my $partinfo = $_partinfo or croak "Cannot ->read_eeprom of an unrecognised part";
825              
826 1   50     4 my $start = $opts{start} // 0;
827             my $stop = $opts{stop} //
828 1 50 33     26 $opts{bytes} ? $start + $opts{bytes} : $partinfo->eeprom_words;
829              
830 1         4 my $bytes = "";
831              
832 1         5 await $self->_transfer( CMD_REEP, HVSP_CMD );
833              
834 1         513 my $cur_ahi = -1;
835              
836 1         5 foreach my $addr ( $start .. $stop - 1 ) {
837 1         2 my $alo = $addr & 0xff;
838 1         2 my $ahi = $addr >> 8;
839              
840 1         4 await $self->_transfer( $alo, HVSP_LLA );
841              
842 1 50       383 await $self->_transfer( $cur_ahi = $ahi, HVSP_LHA ) if $cur_ahi != $ahi;
843              
844 1         370 await $self->_transfer( 0, HVSP_REEP );
845 1         366 $bytes .= chr await $self->_transfer( 0, HVSP_REEP|HVSP_ORM );
846             }
847              
848 1         371 return $bytes;
849 1     1 1 29004 }
850              
851             =head2 write_eeprom
852              
853             await $avr->write_eeprom( $bytes );
854              
855             Writes the EEPROM memory from the binary string.
856              
857             =cut
858              
859 1         2 async method write_eeprom ( $bytes )
  1         2  
  1         3  
860 1         4 {
861 1 50       4 my $partinfo = $_partinfo or croak "Cannot ->write_eeprom of an unrecognised part";
862              
863 1 50       6 croak "Cannot write - too large" if length $bytes > $partinfo->eeprom_words;
864              
865 1         5 my $nwords_page = $partinfo->eeprom_pagesize;
866              
867 1         4 await $self->_transfer( CMD_WEEP, HVSP_CMD );
868              
869 1         435 my @chunks = $bytes =~ m/(.{1,$nwords_page})/gs;
870 1         3 my $addr = 0;
871              
872 1         3 foreach my $chunk ( @chunks ) {
873 32         41703 my $thisaddr = $addr;
874 32         62 $addr += $nwords_page;
875              
876 32         84 await $self->_write_eeprom_page( $chunk, $thisaddr )
877             }
878              
879 1         1376 await $self->_transfer( 0, HVSP_CMD );
880 1     1 1 8157 }
881              
882 32         48 async method _write_eeprom_page ( $bytes, $baseaddr )
  32         54  
  32         51  
  32         40  
883 32         95 {
884 32         87 foreach my $idx ( 0 .. length($bytes) - 1 ) {
885 128         34579 my $addr = $baseaddr + $idx;
886 128         260 my $byte = substr $bytes, $idx, 1;
887              
888             # Datasheet disagrees with the byte value written in the final
889             # instruction. Datasheet says 6C even though the OR mask would yield
890             # the value 6E. It turns out emperically that either value works fine
891             # so for neatness of following other code patterns, we use 6E here.
892              
893 128         353 await $self->_transfer( $addr & 0xff, HVSP_LLA );
894 128         49470 await $self->_transfer( $addr >> 8, HVSP_LHA );
895 128         46337 await $self->_transfer( ord $byte, HVSP_LLD );
896 128         47144 await $self->_transfer( 0, HVSP_PLL );
897 128         46333 await $self->_transfer( 0, HVSP_PLL|HVSP_ORM );
898             }
899              
900 32         11394 await $self->_transfer( 0, HVSP_WLB );
901 32         11441 await $self->_transfer( 0, HVSP_WLB|HVSP_ORM );
902 32         11445 await $self->_await_SDO_high;
903 32     32   55 }
904              
905             =head1 SEE ALSO
906              
907             =over 4
908              
909             =item *
910              
911             L -
912             High voltage serial programming for AVR chips with the Bus Pirate.
913              
914             =back
915              
916             =head1 AUTHOR
917              
918             Paul Evans
919              
920             =cut
921              
922             0x55AA;
923              
924             __DATA__