Device-AVR-UPDI

 view release on metacpan or  search on metacpan

lib/Device/AVR/UPDI.pm  view on Meta::CPAN


=head2 read_asi_sys_status

   $status = await $updi->read_asi_sys_status;

Reads the C<ASI_SYS_STATUS> register.

=cut

async method read_asi_sys_status ()
{
   return await $self->ldcs( REG_ASI_SYS_STATUS );
}

=head2 read_sib

   $sib = await $updi->read_sib;

Reads the System Information Block.

This is returned in a HASH reference, containing four keys:

   {
      family       => "tinyAVR",
      nvm_version  => "P:0",
      ocd_version  => "D:0",
      dbg_osc_freq => 3,
   }

=cut

async method read_sib ()
{
   my $bytes = await
      $self->_op_writeread( SYNC . pack( "C", OP_KEY_READSIB ), 16 );
   printf STDERR ">> READSIB -> %v02X\n", $bytes if DEBUG;

   my ( $family, $nvm, $ocd, $dbgosc ) = unpack "A7 x A3 A3 x A1", $bytes;
   return {
      family       => $family,
      nvm_version  => $nvm,
      ocd_version  => $ocd,
      dbg_osc_freq => $dbgosc,
   };
}

=head2 read_signature

   $signature = await $updi->read_signature;

Reads the three signature bytes from the Signature Row of the device. This is
returned as a plain byte string of length 3.

=cut

async method read_signature ()
{
   # The ATtiny814 datasheet says
   #   All Atmel microcontrollers have a three-byte signature code which
   #   identifies the device. This code can be read in both serial and parallel
   #   mode, also when the device is locked. The three bytes reside in a
   #   separate address space.
   # So far no attempt at reading signature over UPDI from a locked device has
   # been successful. :(

   return await $self->ld( $_partinfo->baseaddr_sigrow, 3 );
}

=head2 request_reset

   await $updi->request_reset( $reset );

Sets or clears the system reset request. Typically used to issue a system
reset by momentarilly toggling the request on and off again:

   await $updi->request_reset( 1 );
   await $updi->request_reset( 0 );

=cut

async method request_reset ( $reset )
{
   await $self->stcs( REG_ASI_RESET_REQ, $reset ? ASI_RESET_REQ_SIGNATURE : 0 );
}

=head2 erase_chip

   await $updi->erase_chip;

Requests a full chip erase, waiting until the erase is complete.

After this, the chip will be unlocked.

Takes an optional named argument:

=over 4

=item no_reset => BOOL

If true, does not issue a system reset request after loading the key. This
allows you to load multiple keys at once before sending the reset, which
may be required e.g. to recover from a bad C<SYSCFG0> fuse setting.

   await $updi->erase_chip( no_reset => 1 );
   await $updi->enable_nvmprog;

=back

=cut

async method erase_chip ( :$no_reset = 0 )
{
   await $self->key( KEY_CHIPERASE );

   die "Failed to set CHIPERASE key\n" unless ASI_KEY_CHIPERASE & await $self->ldcs( REG_ASI_KEY_STATUS );

   return if $no_reset;

   await $self->request_reset( 1 );
   await $self->request_reset( 0 );

   my $timeout = 50;
   while( --$timeout ) {
      last if not ASI_SYS_STATUS_LOCKSTATUS & await $self->ldcs( REG_ASI_SYS_STATUS );

      await Future::IO->sleep( 0.05 );
   }
   die "Failed to unlock chip\n" if !$timeout;
}

=head2 enable_nvmprog

   await $updi->enable_nvmprog;

Requests the chip to enter NVM programming mode.

=cut

async method enable_nvmprog ()
{
   await $self->key( KEY_NVMPROG );

   die "Failed to set NVMPROG key\n" unless ASI_KEY_NVMPROG & await $self->ldcs( REG_ASI_KEY_STATUS );

   await $self->request_reset( 1 );
   await $self->request_reset( 0 );

   my $timeout = 50;
   while( --$timeout ) {
      last if ASI_SYS_STATUS_NVMPROG & await $self->ldcs( REG_ASI_SYS_STATUS );

      await Future::IO->sleep( 0.05 );



( run in 0.503 second using v1.01-cache-2.11-cpan-0bb4e1dffa6 )