avr_boot/
lib.rs

1//! # Avr Boot
2//!
3//! This crate contains functions to write to the program memory of AVR MCUs, using the `spm` instruction.
4//!
5//! It could be considered a reimagining of the macros in boot.h from avr-libc, but in Rust, plus some artisanal, hand-crafted asm.
6//! If you're looking to create a bootloader, this crate should be useful.
7//!
8//! It is hal independent, and optimised for code size.
9//!
10//! Regular and extended (>64k) addressing modes are supported.
11//!
12//! ## Getting started
13//! Add the module to your Cargo.toml:
14//! ```toml
15//! [dependencies]
16//! avr-boot = "0.1.0"
17//! ```
18//!
19//! Pick from the high level API:
20//! ```rust
21//! use avr_boot::PageBuffer;
22//!
23//! let address: u16 = 0x1000;
24//! let data = [0xffff; PageBuffer::LENGTH];
25//! let buff = PageBuffer::new(address);
26//! buff.copy_from(&data);
27//! buff.store();
28//! ```
29//!
30//! Or the low level one:
31//! ```rust
32//! use avr_boot::{spm, SPM_PAGESIZE_WORDS, Address};
33//!
34//! let page_address: u16 = 0x1000;
35//! for w in 0..SPM_PAGESIZE_WORDS {
36//!     spm::fill_page((page_address + (w * 2) as u16), 0x1234);
37//! }
38//! spm::erase_page(page_address);
39//! spm::write_page(page_address);
40//! spm::rww_enable();
41//! ```
42//!
43//! Check out the [examples module](https://github.com/orukusaki/avr-boot/tree/main/avr-boot-examples/src/bin) for more usage examples
44
45#![no_std]
46#![feature(asm_experimental_arch)]
47#![feature(asm_const)]
48#![feature(asm_sym)]
49
50mod address;
51mod buffer;
52
53use core::ops::Deref;
54use const_env__value::value_from_env;
55pub mod spm;
56pub use address::Address;
57pub use buffer::PageBuffer;
58
59/// Total size of the SPM page buffer, for the current MCU target
60pub const SPM_PAGESIZE_BYTES: usize = value_from_env!("AVR_BOOT_SPM_PAGESIZE": usize);
61
62/// Total length in 16 byte words of the SPM page buffer, for the current MCU target
63pub const SPM_PAGESIZE_WORDS: usize = SPM_PAGESIZE_BYTES / 2;
64
65#[cfg(any(extended_addressing))]
66#[doc(hidden)]
67pub const RAMPZ: *mut u8 = value_from_env!("AVR_RAMPZ": u8) as *mut u8;
68#[cfg(target_arch = "avr")]
69const SPMCSR: *mut u8 = value_from_env!("AVR_BOOT_SPMCSR": u8) as *mut u8;
70#[cfg(target_arch = "avr")]
71const PAGE_ERASE: u8 = value_from_env!("AVR_BOOT_PAGE_ERASE": u8);
72#[cfg(target_arch = "avr")]
73const PAGE_WRITE: u8 = value_from_env!("AVR_BOOT_PAGE_WRITE": u8);
74#[cfg(target_arch = "avr")]
75const PAGE_FILL: u8 = value_from_env!("AVR_BOOT_PAGE_FILL": u8);
76#[cfg(target_arch = "avr")]
77const LOCK_BITS_SET: u8 = value_from_env!("AVR_BOOT_LOCK_BITS_SET": u8);
78#[cfg(rww_enable)]
79const RWW_ENABLE: u8 = value_from_env!("AVR_BOOT_RWW_ENABLE": u8);
80
81/// NewType, an array of memory the same size as the page buffer
82pub struct DataPage(pub [u16; SPM_PAGESIZE_WORDS]);
83
84impl<'a> From<&'a [u16; SPM_PAGESIZE_WORDS]> for &'a DataPage {
85    fn from(data: &'a [u16; SPM_PAGESIZE_WORDS]) -> &'a DataPage {
86        unsafe { core::mem::transmute(data) }
87    }
88}
89
90impl<'a> From<&'a [u8; SPM_PAGESIZE_BYTES]> for &'a DataPage {
91    fn from(data: &'a [u8; SPM_PAGESIZE_BYTES]) -> &'a DataPage {
92        unsafe { core::mem::transmute(data) }
93    }
94}
95
96impl From<[u16; SPM_PAGESIZE_WORDS]> for DataPage {
97    fn from(data: [u16; SPM_PAGESIZE_WORDS]) -> DataPage {
98        unsafe { core::mem::transmute(data) }
99    }
100}
101
102impl From<[u8; SPM_PAGESIZE_BYTES]> for DataPage {
103    fn from(data: [u8; SPM_PAGESIZE_BYTES]) -> DataPage {
104        unsafe { core::mem::transmute(data) }
105    }
106}
107
108impl Deref for DataPage {
109    type Target = [u16; SPM_PAGESIZE_WORDS];
110    fn deref(&self) -> &Self::Target {
111        &self.0
112    }
113}