File Coverage

blib/lib/Device/BusPirate/Chip/AVR_HVSP.pm
Criterion Covered Total %
statement 33 239 13.8
branch 0 40 0.0
condition 0 24 0.0
subroutine 11 82 13.4
pod 13 17 76.4
total 57 402 14.1


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 -- leonerd@leonerd.org.uk
5              
6             package Device::BusPirate::Chip::AVR_HVSP;
7              
8 1     1   592 use strict;
  1         1  
  1         32  
9 1     1   3 use warnings;
  1         2  
  1         32  
10 1     1   10 use base qw( Device::BusPirate::Chip );
  1         1  
  1         504  
11              
12             our $VERSION = '0.02';
13              
14 1     1   412 use Carp;
  1         1  
  1         59  
15              
16 1     1   486 use Future::Utils qw( repeat );
  1         1723  
  1         69  
17 1     1   448 use Struct::Dumb qw( readonly_struct );
  1         782  
  1         5  
18              
19 1     1   49 use constant CHIP => "AVR_HVSP";
  1         1  
  1         52  
20 1     1   4 use constant MODE => "BB";
  1         1  
  1         963  
21              
22             readonly_struct PartInfo => [qw( signature flash_words flash_pagesize eeprom_words eeprom_pagesize has_efuse )];
23             readonly_struct MemoryInfo => [qw( wordsize pagesize words can_write )];
24              
25             =head1 NAME
26              
27             C - high-voltage serial programming for F chips
28              
29             =head1 DESCRIPTION
30              
31             This L subclass allows interaction with an F
32             microcontroller of the F family in high-voltage serial programming
33             (HVSP) mode. It is particularly useful for configuring fuses or working with a
34             chip with the C fuse programmed, because in such cases a regular ISP
35             programmer cannot be used.
36              
37             =head2 CONNECTIONS
38              
39             To use this module, make the following connections between the F
40             (with colours of common cable types), and the F chip (with example pin
41             numbers for some common devices):
42              
43             Bus Pirate | Sparkfun | Seeed |:| ATtiny | tiny84 | tiny85
44             -----------+----------+----------+-+--------+--------+-------
45             MISO | brown | black |:| SDO | 9 | 7
46             CS | red | white |:| SII | 8 | 6
47             MOSI | orange | grey |:| SDI | 7 | 5
48             CLK | yellow | purple |:| SCI | 2 | 2
49             AUX | green | blue |:| +12V supply - see below
50             | | |:| RESET | 4 | 1
51             +5V | grey | orange |:| Vcc | 1 | 8
52             GND | black | brown |:| GND | 14 | 4
53              
54             The C line from the F will need to be able to control a +12V
55             supply to the C pin of the F chip. It should be active-high,
56             and can be achieved by a two-stage NPN-then-PNP transistor arrangement.
57              
58             Additionally, the C pin and the C to C pins of 14-pin devices
59             will need a pull-down to ground of around 100Ohm to 1kOhm.
60              
61             =cut
62              
63             =head1 METHODS
64              
65             The following methods documented with a trailing call to C<< ->get >> return
66             L instances.
67              
68             =cut
69              
70             # TODO: This needs to be migrated to Device::BusPirate itself
71             sub _enter_mutex
72             {
73 0     0     my $self = shift;
74 0           my ( $code ) = @_;
75              
76 0   0       my $oldmtx = $self->{mutex} // $self->pirate->_new_future->done( $self );
77 0           $self->{mutex} = my $newmtx = $self->pirate->_new_future;
78              
79             $oldmtx->then( $code )
80             ->then_with_f( sub {
81 0     0     my $f = shift;
82 0           $newmtx->done( $self );
83 0           $f
84 0           });
85             }
86              
87             my $SDI = "mosi";
88             my $SII = "cs";
89             my $SCI = "clk";
90             my $SDO = "miso";
91              
92             sub mount
93             {
94 0     0 1   my $self = shift;
95 0           my ( $mode ) = @_;
96              
97             $self->SUPER::mount( $mode )
98             ->then( sub {
99 0     0     $mode->configure(
100             open_drain => 0,
101             );
102             })
103             ->then( sub {
104 0     0     $mode->write(
105             $SDI => 0,
106             $SII => 0,
107             $SCI => 0,
108             );
109             })
110             ->then( sub {
111             # Set input
112 0     0     $mode->read_miso;
113 0           });
114             }
115              
116             =head2 $chip->start->get
117              
118             Powers up the device, reads and checks the signature, ensuring it is a
119             recognised chip.
120              
121             =cut
122              
123             my %PARTS = (
124             # Sig Flash sz Eeprom sz EF
125             ATtiny24 => PartInfo( "1E910B", 1024, 16, 128, 4, 1 ),
126             ATtiny44 => PartInfo( "1E9207", 2048, 16, 256, 4, 1 ),
127             ATtiny84 => PartInfo( "1E930C", 4096, 32, 512, 4, 1 ),
128              
129             ATtiny13 => PartInfo( "1E9007", 512, 16, 64, 4, 0 ),
130             ATtiny25 => PartInfo( "1E9108", 1024, 16, 128, 4, 1 ),
131             ATtiny45 => PartInfo( "1E9206", 2048, 32, 256, 4, 1 ),
132             ATtiny85 => PartInfo( "1E930B", 4096, 32, 512, 4, 1 ),
133             );
134              
135             sub start
136             {
137 0     0 1   my $self = shift;
138              
139             # Allow power to settle before turning on +12V on AUX
140             # Normal serial line overheads should allow enough time here
141              
142             $self->power(1)->then( sub {
143 0     0     $self->aux(1)
144             })->then( sub {
145 0     0     $self->read_signature;
146             })->then( sub {
147 0     0     my ( $sig ) = @_;
148 0           $sig = uc unpack "H*", $sig;
149              
150 0           my $partinfo;
151             my $part;
152             ( $partinfo = $PARTS{$_} )->signature eq $sig and $part = $_, last
153 0   0       for keys %PARTS;
154              
155 0 0         defined $part or return Future->fail( "Unrecognised signature $sig" );
156              
157 0           $self->{part} = $part;
158 0           $self->{partinfo} = $partinfo;
159              
160             # ARRAYref so we keep this nice order
161 0 0         $self->{memories} = [
162             # ws ps nw wr
163             signature => MemoryInfo( 8, 3, 3, 0 ),
164             calibration => MemoryInfo( 8, 1, 1, 0 ),
165             lock => MemoryInfo( 8, 1, 1, 1 ),
166             lfuse => MemoryInfo( 8, 1, 1, 1 ),
167             hfuse => MemoryInfo( 8, 1, 1, 1 ),
168             ( $partinfo->has_efuse ?
169             ( efuse => MemoryInfo( 8, 1, 1, 1 ) ) :
170             () ),
171             flash => MemoryInfo( 16, $partinfo->flash_pagesize, $partinfo->flash_words, 1 ),
172             eeprom => MemoryInfo( 8, $partinfo->eeprom_pagesize, $partinfo->eeprom_words, 1 ),
173             ];
174              
175 0           return Future->done( $self );
176 0           });
177             }
178              
179             =head2 $chip->stop->get
180              
181             Shut down power to the device.
182              
183             =cut
184              
185             sub stop
186             {
187 0     0 1   my $self = shift;
188              
189 0           Future->needs_all(
190             $self->power(0),
191             $self->aux(0),
192             );
193             }
194              
195             =head2 $name = $chip->partname
196              
197             Returns the name of the chip whose signature was detected by the C
198             method.
199              
200             =cut
201              
202             sub partname
203             {
204 0     0 1   my $self = shift;
205 0           return $self->{part};
206             }
207              
208             =head2 $memory = $avr->memory_info( $name )
209              
210             Returns a memory info structure giving details about the named memory for the
211             attached part. The following memory names are recognised:
212              
213             signature calibration lock lfuse hfuse efuse flash eeprom
214              
215             (Note that the F has no C memory).
216              
217             The structure will respond to the following methods:
218              
219             =over 4
220              
221             =item * wordsize
222              
223             Returns number of bits per word. This will be 8 for the byte-oriented
224             memories, but 16 for the main program flash.
225              
226             =item * pagesize
227              
228             Returns the number of words per page; the smallest amount that can be
229             written in one go.
230              
231             =item * words
232              
233             Returns the total number of words that are available.
234              
235             =item * can_write
236              
237             Returns true if the memory type can be written (in general; this does not take
238             into account the lock bits that might futher restrict a particular chip).
239              
240             =back
241              
242             =cut
243              
244             sub memory_info
245             {
246 0     0 1   my $self = shift;
247 0           my ( $name ) = @_;
248              
249 0           my $memories = $self->{memories};
250             $memories->[$_*2] eq $name and return $memories->[$_*2 + 1]
251 0   0       for 0 .. $#$memories/2;
252              
253 0           die "$self->{part} does not have a $name memory";
254             }
255              
256             =head2 %memories = $avr->memory_infos
257              
258             Returns a key/value list of all the known device memories.
259              
260             =cut
261              
262             sub memory_infos
263             {
264 0     0 1   my $self = shift;
265 0           return @{ $self->{memories} };
  0            
266             }
267              
268             sub _transfer
269             {
270 0     0     my $self = shift;
271              
272 0           my ( $sdi, $sii ) = @_;
273              
274 0           my $sdo = 0;
275 0           my $mode = $self->mode;
276              
277             # A "byte" transfer consists of 11 clock transitions; idle low. Each bit is
278             # clocked in from SDO on the falling edge of clocks 0 to 7, but clocked out
279             # of SDI and SII on clocks 1 to 8.
280             # We'll therefore toggle the clock 11 times; on each of the first 8 clocks
281             # we raise it, then simultaneously lower it, writing out the next out bits
282             # and reading in the input.
283             # Serial transfer is MSB first in both directions
284             #
285             # We cheat massively here and rely on pipeline ordering of the actual
286             # ->write calls, by writing all 22 of the underlying bytes to the Bus
287             # Pirate serial port, then waiting on all 22 bytes to come back.
288              
289 0 0         Future->needs_all( map {
290             my $mask = $_ < 8 ? (1 << 7-$_) : 0;
291              
292             Future->needs_all(
293             $mode->write( $SCI => 1 ),
294              
295             $mode->writeread(
296             $SDI => ( $sdi & $mask ),
297             $SII => ( $sii & $mask ),
298             $SCI => 0
299             )->on_done( sub {
300 0 0   0     $sdo |= $mask if shift->{$SDO};
301             })
302 0           )
303             } 0 .. 10 )
304 0     0     ->then( sub { Future->done( $sdo ) } );
  0            
305             }
306              
307             sub _await_SDO_high
308             {
309 0     0     my $self = shift;
310              
311 0           my $mode = $self->mode;
312              
313 0           my $count = 50;
314             repeat {
315 0 0   0     $count-- or return Future->fail( "Timeout waiting for device to ACK" );
316              
317 0           $mode->${\"read_$SDO"}
  0            
318 0 0   0     } until => sub { $_[0]->failure or $_[0]->get };
  0            
319             }
320              
321             # The AVR datasheet on HVSP does not name any of these operations, only
322             # giving them bit patterns. We'll use the names invented by RikusW. See also
323             # https://sites.google.com/site/megau2s/
324              
325             use constant {
326             # SII values
327 1         628 HVSP_CMD => 0x4C, # Command
328             HVSP_LLA => 0x0C, # Load Lo Address
329             HVSP_LHA => 0x1C, # Load Hi Address
330             HVSP_LLB => 0x2C, # Load Lo Byte
331             HVSP_LHB => 0x3C, # Load Hi Byte
332             HVSP_WLB => 0x64, # Write Lo Byte = WRL = WFU0
333             HVSP_WHB => 0x74, # Write Hi Byte = WRH = WFU1
334             HVSP_WFU2 => 0x66, # Write Extended Fuse
335             HVSP_RLB => 0x68, # Read Lo Byte
336             HVSP_RHB => 0x78, # Read Hi Byte
337             HVSP_RSIG => 0x68, # Read Signature
338             HVSP_RFU0 => 0x68, # Read Low Fuse
339             HVSP_RFU1 => 0x7A, # Read High Fuse
340             HVSP_RFU2 => 0x6A, # Read Extended Fuse
341             HVSP_REEP => 0x68, # Read EEPROM
342             HVSP_ROSC => 0x78, # Read Oscillator calibration
343             HVSP_RLCK => 0x78, # Read Lock
344             HVSP_PLH => 0x7D, # Program (?) Hi
345             HVSP_PLL => 0x6D, # Program (?) Lo
346             HVSP_ORM => 0x0C, # OR mask for SII to pulse actual read/write operation
347              
348             # HVSP_CMD Commands
349             CMD_CE => 0x80, # Chip Erase
350             CMD_WFUSE => 0x40, # Write Fuse
351             CMD_WLOCK => 0x20, # Write Lock
352             CMD_WFLASH => 0x10, # Write FLASH
353             CMD_WEEP => 0x11, # Write EEPROM
354             CMD_RSIG => 0x08, # Read Signature
355             CMD_RFUSE => 0x04, # Read Fuse
356             CMD_RFLASH => 0x02, # Read FLASH
357             CMD_REEP => 0x03, # Read EEPROM
358             CMD_ROSC => 0x08, # Read Oscillator calibration
359             CMD_RLOCK => 0x04, # Read Lock
360 1     1   5 };
  1         2  
361             # Some synonyms not found in the AVR ctrlstack software
362             use constant {
363 1         1112 HVSP_WLCK => HVSP_WLB, # Write Lock
364             HVSP_WFU0 => HVSP_WLB, # Write Low Fuse
365             HVSP_WFU1 => HVSP_WHB, # Write High Fuse
366 1     1   5 };
  1         1  
367              
368             =head2 $avr->chip_erase->get
369              
370             Performs an entire chip erase. This will clear the flash and EEPROM memories,
371             before resetting the lock bits. It does not affect the fuses.
372              
373             =cut
374              
375             sub chip_erase
376             {
377 0     0 0   my $self = shift;
378              
379             $self->_transfer( CMD_CE, HVSP_CMD )
380 0     0     ->then( sub { $self->_transfer( 0, HVSP_WLB ) })
381 0     0     ->then( sub { $self->_transfer( 0, HVSP_WLB|HVSP_ORM ) })
382 0     0     ->then( sub { $self->_await_SDO_high });
  0            
383             }
384              
385             =head2 $bytes = $avr->read_signature->get
386              
387             Reads the three device signature bytes and returns them in as a single binary
388             string.
389              
390             =cut
391              
392             sub read_signature
393             {
394 0     0 0   my $self = shift;
395              
396             $self->_transfer( CMD_RSIG, HVSP_CMD )->then( sub {
397 0     0     my @sig;
398             repeat {
399 0           my $byte = shift;
400             $self->_transfer( $byte, HVSP_LLA )
401 0           ->then( sub { $self->_transfer( 0, HVSP_RSIG ) } )
402 0           ->then( sub { $self->_transfer( 0, HVSP_RSIG|HVSP_ORM ) } )
403 0           ->on_done( sub { $sig[$byte] = shift; } );
  0            
404             } foreach => [ 0 .. 2 ],
405 0           otherwise => sub { Future->done( pack "C*", @sig ) };
  0            
406             })
407 0           }
408              
409             =head2 $byte = $avr->read_calibration->get
410              
411             Reads the calibration byte.
412              
413             =cut
414              
415             sub read_calibration
416             {
417 0     0 0   my $self = shift;
418              
419             $self->_transfer( CMD_ROSC, HVSP_CMD )
420 0     0     ->then( sub { $self->_transfer( 0, HVSP_LLA ) } )
421 0     0     ->then( sub { $self->_transfer( 0, HVSP_ROSC ) } )
422 0     0     ->then( sub { $self->_transfer( 0, HVSP_ROSC|HVSP_ORM ) } )
423             ->then( sub {
424 0     0     Future->done( chr $_[0] )
425 0           });
426             }
427              
428             =head2 $byte = $avr->read_lock->get
429              
430             Reads the lock byte.
431              
432             =cut
433              
434             sub read_lock
435             {
436 0     0 0   my $self = shift;
437              
438             $self->_transfer( CMD_RLOCK, HVSP_CMD )
439 0     0     ->then( sub { $self->_transfer( 0, HVSP_RLCK ) } )
440 0     0     ->then( sub { $self->_transfer( 0, HVSP_RLCK|HVSP_ORM ) } )
441             ->then( sub {
442 0     0     my ( $byte ) = @_;
443 0           Future->done( chr( $byte & 3 ) );
444 0           });
445             }
446              
447             =head2 $avr->write_lock( $byte )->get
448              
449             Writes the lock byte.
450              
451             =cut
452              
453             sub write_lock
454             {
455 0     0 1   my $self = shift;
456 0           my ( $byte ) = @_;
457              
458             $self->_transfer( CMD_WLOCK, HVSP_CMD )
459 0     0     ->then( sub { $self->_transfer( ( ord $byte ) & 3, HVSP_LLB ) })
460 0     0     ->then( sub { $self->_transfer( 0, HVSP_WLCK ) })
461 0     0     ->then( sub { $self->_transfer( 0, HVSP_WLCK|HVSP_ORM ) })
462 0     0     ->then( sub { $self->_await_SDO_high });
  0            
463             }
464              
465             =head2 $int = $avr->read_fuse_byte( $fuse )->get
466              
467             Reads one of the fuse bytes C, C, C, returning an
468             integer.
469              
470             =cut
471              
472             my %SII_FOR_FUSE_READ = (
473             lfuse => HVSP_RFU0,
474             hfuse => HVSP_RFU1,
475             efuse => HVSP_RFU2,
476             );
477              
478             sub read_fuse_byte
479             {
480 0     0 1   my $self = shift;
481 0           my ( $fuse ) = @_;
482              
483 0 0         my $sii = $SII_FOR_FUSE_READ{$fuse} or croak "Unrecognised fuse type '$fuse'";
484              
485 0 0 0       $fuse eq "efuse" and !$self->{partinfo}->has_efuse and
486             croak "This part does not have an 'efuse'";
487              
488             $self->_transfer( CMD_RFUSE, HVSP_CMD )
489 0     0     ->then( sub { $self->_transfer( 0, $sii ) } )
490 0     0     ->then( sub { $self->_transfer( 0, $sii|HVSP_ORM ) } )
491 0           }
492              
493             =head2 $avr->write_fuse_byte( $fuse, $byte )->get
494              
495             Writes one of the fuse bytes C, C, C from an integer.
496              
497             =cut
498              
499             my %SII_FOR_FUSE_WRITE = (
500             lfuse => HVSP_WFU0,
501             hfuse => HVSP_WFU1,
502             efuse => HVSP_WFU2,
503             );
504              
505             sub write_fuse_byte
506             {
507 0     0 1   my $self = shift;
508 0           my ( $fuse, $byte ) = @_;
509              
510 0 0         my $sii = $SII_FOR_FUSE_WRITE{$fuse} or croak "Unrecognised fuse type '$fuse'";
511              
512 0 0 0       $fuse eq "efuse" and !$self->{part}->has_efuse and
513             croak "This part does not have an 'efuse'";
514              
515             $self->_transfer( CMD_WFUSE, HVSP_CMD )
516 0     0     ->then( sub { $self->_transfer( $byte, HVSP_LLB ) })
517 0     0     ->then( sub { $self->_transfer( 0, $sii ) })
518 0     0     ->then( sub { $self->_transfer( 0, $sii|HVSP_ORM ) })
519 0     0     ->then( sub { $self->_await_SDO_high });
  0            
520             }
521              
522             =head2 $byte = $avr->read_lfuse->get
523              
524             =head2 $byte = $avr->read_hfuse->get
525              
526             =head2 $byte = $avr->read_efuse->get
527              
528             Convenient shortcuts to reading the low, high and extended fuses directly,
529             returning a byte.
530              
531             =head2 $avr->write_lfuse( $byte )->get
532              
533             =head2 $avr->write_hfuse( $byte )->get
534              
535             =head2 $avr->write_efuse( $byte )->get
536              
537             Convenient shortcuts for writing the low, high and extended fuses directly,
538             from a byte.
539              
540             =cut
541              
542             foreach my $fuse (qw( lfuse hfuse efuse )) {
543 1     1   5 no strict 'refs';
  1         1  
  1         1682  
544             *{"read_$fuse"} = sub {
545             shift->read_fuse_byte( $fuse )
546 0     0     ->then( sub { Future->done( chr $_[0] ) });
  0            
547             };
548             *{"write_$fuse"} = sub {
549 0     0     $_[0]->write_fuse_byte( $fuse, ord $_[1] );
550             };
551             }
552              
553             =head2 $bytes = $avr->read_flash( %args )->get
554              
555             Reads a range of the flash memory and returns it as a binary string.
556              
557             Takes the following optional arguments:
558              
559             =over 4
560              
561             =item start => INT
562              
563             =item stop => INT
564              
565             Address range to read. If omitted, reads the entire memory.
566              
567             =item bytes => INT
568              
569             Alternative to C; gives the nubmer of bytes (i.e. not words of flash)
570             to read.
571              
572             =back
573              
574             =cut
575              
576             sub read_flash
577             {
578 0     0 1   my $self = shift;
579 0           my %opts = @_;
580              
581 0 0         my $partinfo = $self->{partinfo} or croak "Cannot ->read_flash of an unrecognised part";
582              
583 0   0       my $start = $opts{start} // 0;
584 0 0 0       my $stop = $opts{stop} //
585             $opts{bytes} ? $start + ( $opts{bytes}/2 ) : $partinfo->flash_words;
586              
587 0           my $bytes = "";
588              
589             $self->_transfer( CMD_RFLASH, HVSP_CMD )->then( sub {
590 0     0     my $cur_ahi = -1;
591              
592             repeat {
593 0           my ( $addr ) = @_;
594 0           my $alo = $addr & 0xff;
595 0           my $ahi = $addr >> 8;
596              
597             $self->_transfer( $alo, HVSP_LLA )
598 0 0         ->then( sub { $cur_ahi == $ahi ? Future->done
599             : $self->_transfer( $cur_ahi = $ahi, HVSP_LHA ) })
600 0           ->then( sub { $self->_transfer( 0, HVSP_RLB ) })
601 0           ->then( sub { $self->_transfer( 0, HVSP_RLB|HVSP_ORM ) })
602 0           ->then( sub { $bytes .= chr $_[0];
603 0           $self->_transfer( 0, HVSP_RHB ) })
604 0           ->then( sub { $self->_transfer( 0, HVSP_RHB|HVSP_ORM ) })
605 0           ->then( sub { $bytes .= chr $_[0];
606 0           Future->done; });
  0            
607             } foreach => [ $start .. $stop - 1 ],
608 0           otherwise => sub { Future->done( $bytes ) };
  0            
609 0           });
610             }
611              
612             =head2 $avr->write_flash( $bytes )->get
613              
614             Writes the flash memory from the binary string.
615              
616             =cut
617              
618             sub write_flash
619             {
620 0     0 1   my $self = shift;
621 0           my ( $bytes ) = @_;
622              
623 0 0         my $partinfo = $self->{partinfo} or croak "Cannot ->write_flash of an unrecognised part";
624 0           my $nbytes_page = $partinfo->flash_pagesize * 2; # words are 2 bytes
625              
626 0 0         croak "Cannot write - too large" if length $bytes > $partinfo->flash_words * 2;
627              
628             $self->_transfer( CMD_WFLASH, HVSP_CMD )->then( sub {
629 0     0     my @chunks = $bytes =~ m/(.{1,$nbytes_page})/gs;
630 0           my $addr = 0;
631              
632             repeat {
633 0           my $thisaddr = $addr;
634 0           $addr += $partinfo->flash_pagesize;
635              
636 0           $self->_write_flash_page( $_[0], $thisaddr )
637 0           } foreach => \@chunks;
638             })
639 0     0     ->then( sub { $self->_transfer( 0, HVSP_CMD ) });
  0            
640             }
641              
642             sub _write_flash_page
643             {
644 0     0     my $self = shift;
645 0           my ( $bytes, $baseaddr ) = @_;
646              
647             (
648             repeat {
649 0     0     my $addr = $baseaddr + $_[0];
650 0           my $byte_lo = substr $bytes, $_[0]*2, 1;
651 0           my $byte_hi = substr $bytes, $_[0]*2 + 1, 1;
652              
653             # Datasheet disagrees with the byte value written in the final
654             # instruction. Datasheet says 6C even though the OR mask would yield
655             # the value 6E. It turns out emperically that either value works fine
656             # so for neatness of following other code patterns, we use 6E here.
657              
658             $self->_transfer( $addr & 0xff, HVSP_LLA )
659 0           ->then( sub { $self->_transfer( ord $byte_lo, HVSP_LLB ) })
660 0           ->then( sub { $self->_transfer( 0, HVSP_PLL ) })
661 0           ->then( sub { $self->_transfer( 0, HVSP_PLL|HVSP_ORM ) })
662 0           ->then( sub { $self->_transfer( ord $byte_hi, HVSP_LHB ) })
663 0           ->then( sub { $self->_transfer( 0, HVSP_PLH ) })
664 0           ->then( sub { $self->_transfer( 0, HVSP_PLH|HVSP_ORM ) })
665 0           } foreach => [ 0 .. length($bytes)/2 - 1 ]
666             )
667 0     0     ->then( sub { $self->_transfer( $baseaddr >> 8, HVSP_LHA ) })
668 0     0     ->then( sub { $self->_transfer( 0, HVSP_WLB ) })
669 0     0     ->then( sub { $self->_transfer( 0, HVSP_WLB|HVSP_ORM ) })
670 0     0     ->then( sub { $self->_await_SDO_high });
  0            
671             }
672              
673             =head2 $bytes = $avr->read_eeprom( %args )->get
674              
675             Reads a range of the EEPROM memory and returns it as a binary string.
676              
677             Takes the following optional arguments:
678              
679             =over 4
680              
681             =item start => INT
682              
683             =item stop => INT
684              
685             Address range to read. If omitted, reads the entire memory.
686              
687             =item bytes => INT
688              
689             Alternative to C; gives the nubmer of bytes to read.
690              
691             =back
692              
693             =cut
694              
695             sub read_eeprom
696             {
697 0     0 1   my $self = shift;
698 0           my %opts = @_;
699              
700 0 0         my $partinfo = $self->{partinfo} or croak "Cannot ->read_eeprom of an unrecognised part";
701              
702 0   0       my $start = $opts{start} // 0;
703 0 0 0       my $stop = $opts{stop} //
704             $opts{bytes} ? $start + $opts{bytes} : $partinfo->eeprom_words;
705              
706 0           my $bytes = "";
707              
708             $self->_transfer( CMD_REEP, HVSP_CMD )->then( sub {
709 0     0     my $cur_ahi = -1;
710              
711             repeat {
712 0           my ( $addr ) = @_;
713 0           my $alo = $addr & 0xff;
714 0           my $ahi = $addr >> 8;
715              
716             $self->_transfer( $alo, HVSP_LLA )
717 0 0         ->then( sub { $cur_ahi == $ahi ? Future->done
718             : $self->_transfer( $cur_ahi = $ahi, HVSP_LHA ) } )
719 0           ->then( sub { $self->_transfer( 0, HVSP_REEP ) } )
720 0           ->then( sub { $self->_transfer( 0, HVSP_REEP|HVSP_ORM ) } )
721 0           ->then( sub { $bytes .= chr $_[0];
722 0           Future->done; });
  0            
723             } foreach => [ $start .. $stop - 1 ],
724 0           otherwise => sub { Future->done( $bytes ) };
  0            
725 0           });
726             }
727              
728             =head2 $avr->write_eeprom( $bytes )->get
729              
730             Writes the EEPROM memory from the binary string.
731              
732             =cut
733              
734             sub write_eeprom
735             {
736 0     0 1   my $self = shift;
737 0           my ( $bytes ) = @_;
738              
739 0 0         my $partinfo = $self->{partinfo} or croak "Cannot ->write_eeprom of an unrecognised part";
740              
741 0 0         croak "Cannot write - too large" if length $bytes > $partinfo->eeprom_words;
742              
743 0           my $nwords_page = $partinfo->eeprom_pagesize;
744              
745             $self->_transfer( CMD_WEEP, HVSP_CMD )->then( sub {
746 0     0     my @chunks = $bytes =~ m/(.{1,$nwords_page})/gs;
747 0           my $addr = 0;
748              
749             repeat {
750 0           my $thisaddr = $addr;
751 0           $addr += $nwords_page;
752              
753 0           $self->_write_eeprom_page( $_[0], $thisaddr )
754 0           } foreach => \@chunks;
755             })
756 0     0     ->then( sub { $self->_transfer( 0, HVSP_CMD ) });
  0            
757             }
758              
759             sub _write_eeprom_page
760             {
761 0     0     my $self = shift;
762 0           my ( $bytes, $baseaddr ) = @_;
763              
764             (
765             repeat {
766 0     0     my $addr = $baseaddr + $_[0];
767 0           my $byte = substr $bytes, $_[0], 1;
768              
769             # Datasheet disagrees with the byte value written in the final
770             # instruction. Datasheet says 6C even though the OR mask would yield
771             # the value 6E. It turns out emperically that either value works fine
772             # so for neatness of following other code patterns, we use 6E here.
773              
774             $self->_transfer( $addr & 0xff, HVSP_LLA )
775 0           ->then( sub { $self->_transfer( $addr >> 8, HVSP_LHA ) })
776 0           ->then( sub { $self->_transfer( ord $byte, HVSP_LLB ) })
777 0           ->then( sub { $self->_transfer( 0, HVSP_PLL ) })
778 0           ->then( sub { $self->_transfer( 0, HVSP_PLL|HVSP_ORM ) })
779 0           } foreach => [ 0 .. length($bytes) - 1 ]
780             )
781 0     0     ->then( sub { $self->_transfer( 0, HVSP_WLB ) })
782 0     0     ->then( sub { $self->_transfer( 0, HVSP_WLB|HVSP_ORM ) })
783 0     0     ->then( sub { $self->_await_SDO_high });
  0            
784             }
785              
786             =head1 SEE ALSO
787              
788             =over 4
789              
790             =item *
791              
792             L -
793             High voltage serial programming for AVR chips with the Bus Pirate.
794              
795             =back
796              
797             =head1 AUTHOR
798              
799             Paul Evans
800              
801             =cut
802              
803             0x55AA;