/stm32-fmc

Hardware Abstraction Layer for STM32 Memory Controllers (FMC/FSMC)

Primary LanguageRustApache License 2.0Apache-2.0

stm32-fmc

docs.rs Crates.io

Hardware Abstraction Layer for STM32 Memory Controllers (FMC/FSMC)

Currently only SDRAM functions are implemented.

This crate is a work in progress! Contributions very welcome

Implementing

(If your HAL already implements FMC, you can skip this)

See the docs

Usage

SDRAM

The FMC peripheral supports up to 2 external SDRAM devices. This crate currently only supports 1, although it may be on either bank 1 or 2.

External memories are defined by SdramChip implementations. There are several examples in the devices folder, or you can make your own.

To pass pins to a constructor, create a tuple with the following ordering:

let pins = (
    // A0-A12
    pa0, ...
    // BA0-BA1
    // D0-D31
    // NBL0 - NBL3
    // SDCKE
    // SDCLK
    // SDNCAS
    // SDNE
    // SDRAS
    // SDNWE
);

You can leave out address/data pins not used by your memory.

Constructing

If you are using a HAL, see the HAL documentation.

Otherwise you can implement FmcPeripheral yourself then use Sdram::new / Sdram::new_unchecked directly.

Initialising

Once you have an Sdram instance, you can:

  • Initialise it by calling init. This returns a raw pointer
  • Convert the raw pointer to a sized slice using from_raw_parts_mut
let ram = unsafe {
    // Initialise controller and SDRAM
    let ram_ptr: *mut u32 = sdram.init(&mut delay);

    // 32 MByte = 256Mbit SDRAM = 8M u32 words
    slice::from_raw_parts_mut(ram_ptr, 8 * 1024 * 1024)
};

NAND Flash

The FMC peripheral supports once external parallel NAND flash device.

External memories are defined by NandChip implementations. There are examples in the devices folder, or you can make your own.

To pass pins to a constructor, create a tuple with the following ordering:

let pins = (
    // A17/ALE
    // A16/CLE
    pa0, ...
    // D0-D7
    // NCE/#CE
    // NOE/#RE
    // NWE/#WE
    // NWAIT/R/#B
);

Constructing

If you are using a HAL, see the HAL documentation.

Otherwise you can implement FmcPeripheral yourself then use Nand::new / Nand::new_unchecked directly.

Initialising

Once you have an Nand instance you should initialise it by calling init. This returns a NandDevice instance.

let mut nand_device = nand.init(&mut delay);

// Read device identifier
let id = nand_device.read_id();

NOR Flash/PSRAM

TODO

Troubleshooting

The library automatically does some trace-level logging either via log or via defmt. To enable such logging, enable either the log or defmt feature in your Cargo.toml.

For debugging the SDRAM register contents, the library provides additional feature trace-register-values, which when enabled causes the init function to log the register contents to the trace level. This is useful for example when you want to compare the register values between stm32-fmc and CubeMX code. Note that one of the logging features (log/defmt) must be enabled for this to work.

Implementing a new device

If you end up depending on a fork or a newer version of this crate than the HAL crate for your device, you can override the version pulled in by the external crate using a [patch] section in your Cargo.toml, as described in the Cargo Book.

Releasing

  • Update Cargo.toml
  • Update CHANGELOG.md
git commit -am 'v0.2.0'
git push --set-upstream origin v0.2.0

Create a PR and check CI passes

git push --set-upstream origin v0.2.0:master
git tag -a 'v0.2.0' -m 'v0.2.0'
git push origin refs/tags/v0.2.0
cargo publish

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.