cryptjar / avr-progmem-rs Goto Github PK
View Code? Open in Web Editor NEWProgmem utility for the AVR architecture
License: Apache License 2.0
Progmem utility for the AVR architecture
License: Apache License 2.0
Hey!
You should probably pin the version of avr-hal
in the dev-dependencies to a specific git revision. avr-hal
is still quite early in development and newer versions might break the example code so this way anyone downloading the project and trying to compile the example in the future will build against the same version of avr-hal
that you originally wrote it for:
[dev-dependencies.arduino-uno]
# It is not yet available via crates.io
git = "https://github.com/Rahix/avr-hal.git"
rev = "7337cd76cd96f2d27701b137396d94a06d3a501d"
(7337cd76cd96
is the latest commit on master, you should probably check whether that still works and use an older rev instead if it does not ...)
I'd like to store sprite animation frames in PROGMEM
, where each frame has the same size (represented as a [u8; 8]
) but the number of frames can vary between animations.
So I have something like
progmem! {
pub static progmem IDLE: [[u8; 8]; 1] = ....;
pub static progmem WALK: [[u8; 8]; 3] = ...;
The first issue is dereferencing these. I can use e.g. WALK.load_at(2)
to get a [u8; 8]
, but if I want to process it byte-wise, is there a way to avoid that 7-byte overhead and get just the one byte, something like e.g. WALK.load_wrapper_at(2).load_at(3)
?
The second issue is storing a reference to the currently playing animation. If they were all the same length, I could store a &'static ProgMem<[[u8;8];3>
in my state; however, since they are not, one of the wrappers has type ProgMem<[[u8;8];1>
while the other one is ProgMem<[[u8;8];3>
. I think what I'd need is something like a ProgMemArrayRef<[u8;8]>
that has a dynamic length accessible at runtime.
Here, the code loops over the bytes that a type may occupy and reads each:
Lines 170 to 177 in 8d00b35
As you note, this is morally equivalent to ptr::copy
, but implemented via bytewise reading. Unfortunately, the results are not well-defined for all T
. A type may have uninitialized bytes or initialization invariants, such as padding or niches.
#[derive(Clone, Copy, Default)]
struct HasPadding {
a: u16,
b: u8,
}
assert_eq!(4, mem::size_of::<HasPadding>()); // A padding byte exists
If it is valid to read a padding byte, this will incite no complaints, but we are not so lucky:
for i in 0..mem::size_of::<HasPadding>() {
unsafe {
let padded = padded.cast::<u8>().add(i);
let blender = blender.cast::<u8>().add(i);
// error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
blender.write(padded.read())
};
}
I put together a few examples of ways to provoke Miri's anger on the Playground while studying this. In particular, you can observe how making sure there is no padding byte by so much as adding a field in the right place quiets Miri's complaints. Unfortunately, Miri is not fully aware of AVR's memory semantics, so has no useful commentary there.
Obviously, as this function is unsafe, no change in the code is required, merely documenting this additional invariant. However, this has implications on the function's usage and how it is used in this crate and others, so you may want a solution. It may be correct to simply copy all the bytes in a type before any individual byte enters Rust (i.e. to copy each T
fully while in a single asm!
block). This is in the domain of "underdefined semantics that may be subject to change", but is unlikely to, as it is a consequence of Rust only understanding assembly in a "black box" manner, seeing only its defined interface and having no vocabulary for what goes on inside asm!
: "Whereof one cannot speak, thereof one must be silent".
All of the array sizes in the documentation examples seem to be fairly small: the element type is always bytes, and the size is never more than about 5. I think that an example of hash function round constants would be more compelling, such as the data found here:
Here, the program needs 64 u32s and loads (up to) 16 at a time.
Motivated via rust-lang/rust#109000.
I have spent the afternoon experimenting with how to put a string in progmem.
Using
#[cfg_attr(target_arch = "avr", link_section = ".progmem.data")]
static MESSAGE3: &str = "apple";
only puts the pointer and count of the slice in progmem. The actual characters still end up in RAM.
It is possible to use something like
#[cfg_attr(target_arch = "avr", link_section = ".progmem.data")]
static MESSAGE6: &[u8; 9] = b"dai kenja";
But if you try
#[cfg_attr(target_arch = "avr", link_section = ".progmem.data")]
static MESSAGE5: &[u8; 13] = b"dai 大賢者 kenja";
you get an error:
error: byte constant must be ASCII. Use a \xHH escape for a non-ASCII byte
The latest AVR template now uses channel = "nightly-2022-05-10"
. Unfortunately, that breaks any code that uses llvm_asm!
error: cannot find macro `llvm_asm` in this scope
--> /home/thoth/.cargo/registry/src/github.com-1ecc6299db9ec823/avr-progmem-0.2.0/src/raw.rs:84:4
|
84 | llvm_asm!(
| ^^^^^^^^
I think the avr-hal crates use feature flags enabled by build.rs
to support the new rust :
Rahix/avr-hal@5d75769
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.