Giter VIP home page Giter VIP logo

stm32g4xx-hal's Introduction

STM32 Peripheral Access Crates

CI crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io Matrix

This repository provides Rust device support crates for all STM32 microcontrollers, providing a safe API to that device's peripherals using svd2rust and a community-built collection of patches to the basic SVD files. There is one crate per device family, and each supported device is a feature-gated module in that crate. These crates are commonly known as peripheral access crates or "PACs".

To view the generated code that makes up each crate, visit the stm32-rs-nightlies repository, which is automatically rebuilt on every commit to stm32-rs master. The stm32-rs repository contains the patches to the underlying SVD files and the tooling to generate the crates.

While these crates are widely used, not every register of every device will have been tested on hardware, and so errors or omissions may remain. We can't make any guarantee of correctness. Please report any bugs you find!

You can see current coverage status for each chip here. Coverage means that individual fields are documented with possible values, but even devices with low coverage should have every register and field available in the API. That page also allows you to drill down into each field on each register on each peripheral.

Using Device Crates In Your Own Project

In your own project's Cargo.toml:

[dependencies.stm32f4]
version = "0.15.1"
features = ["stm32f405", "rt"]

The rt feature is optional but helpful. See svd2rust for details.

Then, in your code:

use stm32f4::stm32f405;

let mut peripherals = stm32f405::Peripherals::take().unwrap();

Refer to svd2rust documentation for further usage.

Replace stm32f4 and stm32f405 with your own device; see the individual crate READMEs for the complete list of supported devices. All current STM32 devices should be supported to some level.

Using Latest "Nightly" Builds

Whenever the master branch of this repository is updated, all device crates are built and deployed to the stm32-rs-nightlies repository. You can use this in your Cargo.toml:

[dependencies.stm32f4]
git = "https://github.com/stm32-rs/stm32-rs-nightlies"
features = ["stm32f405", "rt"]

The nightlies should always build and be as stable as the latest release, but contain the latest patches and updates.

Generating Device Crates / Building Locally

  • Install svd2rust, svdtools, and form:
    • On x86-64 Linux, run make install to download pre-built binaries at the current version used by stm32-rs
    • Otherwise, build using cargo (double check versions against scripts/tool_install.sh):
      • cargo install form --version 0.12.1
      • cargo install svdtools --version 0.3.18
      • cargo install svd2rust --version 0.33.4
  • Install rustfmt: rustup component add rustfmt
  • Generate patched SVD files: make patch (you probably want -j for all make invocations)
    • Alternatively you could install cargo-make runner and then use it instead of make. Works on MS Windows natively:
      • cargo install cargo-make
      • cargo make patch
  • Generate svd2rust device crates: make svd2rust
  • Optional: Format device crates: make form

Motivation and Objectives

This project serves two purposes:

  • Create a source of high-quality STM32 SVD files, with manufacturer errors and inconsistencies fixed. These files could be used with svd2rust or other tools, or in other projects. They should hopefully be useful in their own right.
  • Create and publish svd2rust-generated crates covering all STM32s, using the SVD files.

When this project began, many individual crates existed for specific STM32 devices, typically maintained separately with hand-edited updates to the SVD files. This project hopes to reduce that duplication of effort and centralise the community's STM32 device support in one place.

Helping

This project is still young and there's a lot to do!

  • More peripheral patches need to be written, most of all. See what we've got in peripherals/ and grab a reference manual!
  • Also everything needs testing, and you can't so easily automate finding bugs in the SVD files...

Supported Device Families

crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io

Please see the individual crate READMEs for the full list of devices each crate supports. All SVDs released by ST for STM32 devices are covered, so probably your device is supported to some extent!

Devices that are nearly identical, like the STM32F405/F415, are supported by ST under a single SVD file STM32F405, so if you can't find your exact device check if its sibling is supported instead. The crate READMEs make this clear.

Many peripherals are not yet patched to provide the type-safe friendly-name interface (enumerated values); please consider helping out with this!

Check out the full list of supported devices here.

Adding New Devices

  • Update SVD zips in svd/vendor to include new SVDs.
  • Run make extract to extract the new zip files.
  • Add new YAML file in devices/ with the new SVD path and include any required SVD patches for this device, such as renaming or merging fields.
  • Add the new devices to stm32_part_table.yaml.
  • Add the new devices to scripts/makecrates.py.
  • You can run scripts/matchperipherals.py script to find out what existing peripherals could be cleanly applied to this new SVD. If they look sensible, you can include them in your device YAML. This requires a Python environment with the pyyaml and svdtools dependencies. Example command: python scripts/matchperipherals.py peripherals/rcc devices/stm32h562.yaml
  • Re-run scripts/makecrates.py devices/ to update the crates with the new devices.
  • Run make to rebuild, which will make a patched SVD and then run svd2rust on it to generate the final library.

If adding a new STM32 family (not just a new device to an existing family), complete these steps as well:

  • Add the new devices to the CRATES field in Makefile.
  • Update this Readme to include the new devices.
  • Add the devices to workflows/ci.yaml and workflows/nightlies.yaml.

Updating Existing Devices/Peripherals

  • Using Linux, run make extract at least once to pull the SVDs out.
  • Edit the device or peripheral YAML (see below for format).
  • Using Linux, run make to rebuild all the crates using svd patch and svd2rust.
  • Test your new stuff compiles: cd stm32f4; cargo build --features stm32f405

If you've added a new peripheral, consider using the matchperipherals.py script to see which devices it would cleanly apply to.

To generate a new peripheral file from scratch, consider using periphtemplate.py, which creates an empty peripheral file based on a single SVD file, with registers and fields ready to be populated. For single bit wide fields with names ending in 'E' or 'D' it additionally generates sample "Enabled"/"Disabled" entries to save time.

Device and Peripheral YAML Format

Please see the svdtools documentation for full details of the patch file format.

Style Guide

  • Enumerated values should be named in the past tense ("enabled", "masked", etc).
  • Descriptions should start with capital letters but do not end with a period

Releasing

Notes for maintainers:

  1. Create PR preparing for new release:
    • Update CHANGELOG.md with changes since last release and new contributors
    • Update README.md to bump version number in example snippet
    • Update scripts/makecrates.py to update version number for generated PACs
  2. Merge PR once CI passes, pull master locally.
  3. make clean
  4. make -j16 form
  5. for f in stm32f0 stm32f1 stm32f2 stm32f3 stm32f4 stm32f7 stm32h7 stm32l0 stm32l1 stm32l4 stm32l5 stm32g0 stm32g4 stm32mp1 stm32wl stm32wb; cd $f; pwd; cargo publish --allow-dirty --no-default-features; cd ..; end
  6. git tag -a vX.X.X -m vX.X.X
  7. git push vX.X.X

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.

stm32g4xx-hal's People

Contributors

amcelroy avatar dotcypress avatar dtjones190 avatar geens avatar jbtheou avatar kevswims avatar konradb3 avatar liamkinne avatar luctius avatar mgottschlag avatar nandobongers avatar no111u3 avatar pawelchcki avatar rmsc avatar stabler avatar timblakely avatar usbalbin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

stm32g4xx-hal's Issues

Create a crate release

As far as I can tell, this crate is at 0.0.0 which is 4 years old (and contains pretty much nothing). It seems to have enough functionality to warrant a 0.1.0 release?

enable to read data from the counting timer

We can't read data after starting the timer.
let mut tim3=Timer::new(dp.TIM3, &rcc.clocks).start_count_down(25.hz()); tim3.read(); // I should be able to call a function to read the value

Follow instructions did not work

I try to implement by using
cargo generate --git https://github.com/stm32-rs/stm32g4xx-hal

Then when I did cargo build I got this error
Compiling typenum v1.11.2
Compiling proc-macro2 v1.0.6
Compiling semver-parser v0.7.0
Compiling unicode-xid v0.2.0
Compiling rand_core v0.4.2
Compiling syn v1.0.8
Compiling cortex-m v0.6.2
Compiling cortex-m-rt v0.6.10
Compiling stm32g4 v0.9.0
Compiling semver v0.9.0
Compiling rand_core v0.3.1
Compiling rand v0.5.6
error: failed to run custom build command for stm32g4 v0.9.0

Caused by:
process didn't exit successfully: C:\Users\KNC\workspace_rust\stm32-g4\target\debug\build\stm32g4-e59bfc4da205d66f\build-script-build (exit code: 101)
--- stdout
cargo:rustc-link-search=C:\Users\KNC\workspace_rust\stm32-g4\target\thumbv7em-none-eabihf\debug\build\stm32g4-d469d43ef2d76064\out

--- stderr
thread 'main' panicked at 'No device features selected', C:\Users\KNC.cargo\registry\src\github.com-1ecc6299db9ec823\stm32g4-0.9.0\build.rs:22:18
note: run with RUST_BACKTRACE=1 environment variable to display a backtrace

warning: build failed, waiting for other jobs to finish...
error: build failed

Please let me know if there is a way to fix it.

Thank you.

`.defmt` section found, but no version symbol

I get this when trying to run the examples

$ cargo run --example blinky --features stm32g474 -- --chip STM32G474RBTx
Compiling stm32g4xx-hal v0.0.1
    Finished dev [unoptimized + debuginfo] target(s) in 0.21s
     Running `probe-run --connect-under-reset target/thumbv7em-none-eabihf/debug/examples/blinky --chip STM32G474RBTx`
(HOST) INFO  flashing program (9 pages / 9.00 KiB)
(HOST) INFO  success!
Error: `.defmt` section found, but no version symbol - check your linker configuration

Adding the line use defmt_rtt as _; in the blinky example makes the error go away, however there is no sign of the logging output. There is no difference when replacing info!() with error!().


Adding use defmt_rtt as _; to the example/hello (which uses cortex_m_semihosting::hprintln to print) gives

Compiling stm32g4xx-hal v0.0.1 (stm32g4xx-hal)
    Finished dev [unoptimized + debuginfo] target(s) in 0.19s
     Running `probe-run --connect-under-reset target/thumbv7em-none-eabihf/debug/examples/hello --chip STM32G474RBTx`
(HOST) INFO  flashing program (13 pages / 13.00 KiB)
(HOST) INFO  success!
────────────────────────────────────────────────────────────────────────────────
────────────────────────────────────────────────────────────────────────────────
stack backtrace:
   0: __c_m_sh_syscall
(HOST) WARN  call stack was corrupted; unwinding could not be completed
(HOST) ERROR error occurred during backtrace creation: debug information for address 0x80017d4 is missing. Likely fixes:
        1. compile the Rust code with `debug = 1` or higher. This is configured in the `profile.{release,bench}` sections of Cargo.toml (`profile.{dev,test}` default to `debug = 2`)
        2. use a recent version of the `cortex-m` crates (e.g. cortex-m 0.6.3 or newer). Check versions in Cargo.lock
        3. if linking to C code, compile the C code with the `-g` flag

Caused by:
    Do not have unwind info for the given address.
               the backtrace may be incomplete.
(HOST) INFO  device halted without error

To verify, I have tested https://github.com/knurling-rs/app-template which works as expected.

Am I doing something wrong or is this a bug?

stm32g4xx-hal version: 0.0.1
device: Nucleo-G474RE (STM32G474RE)

Example blinky: --release has extreme effect

I first thought that the simple blinky does not work right. But actually, it does - it's just that one loop iteration takes roughly a minute to run. When compiling with --release, it is roughly a second. But even then, the duty cycle is not 50%, more like 33% on.
Is this due to the poor man's delay function? If so, I think there should be a note about that somewhere.

Flash memory read / write issues?

Howdy,

I was wondering if anyone has had any luck with the flash memory module for reading and writing? I am using the Nucleo-G474RE and am trying to write some data to flash memory using RTIC 1.x as the "RTOS". The main issue seems to be when calling the FlashWriter::write function that core::ptr::write_volatile doesn't write, and when the subsequent core::ptr::read_volatile is called, the results don't match and the function returns with Err(Error::VerifyError);

There isn't a working flash example, so here is a summary of my attempt that hopefully can be added to the examples when things are up and running. The PLL config is being used to bump the clock speed up to 128MHz and get the ADC running at a 1MHz (not included in the test). Removing this code and checking clock domains will be the next step.

The example project should compile and run using the Segger J-Link tools using VS Code (tested on my Macbook Pro M2).

HRTIM

Would there be any interest in support for the HRTIM peripheral? The peripheral is useful for things like generating PWM waveforms for powersupplies and similar. It is available in the stm32g474 and stm32g484, and some processors from stm32f3xx and stm32h7xx. I have not found a rust implementation for it yet, so as far as I know this would probably be the first?

If this is something that would be accepted as a PR, do you have any suggestions for how to think when creating an API for it?

From what I understand(correct me if I am wrong) looking at the stm32g474 and stm32g484. We have 6 timers, each timer has two outputs which may be routed to pins. So far it looks just as any other pwm timer, however the waveform for each output is defined by up to 32 event sources. Some of those are the ouput's own timer's compare registers(4) and the period wrap around(1), other than that there are lots of other sources like a selection of other timers compare registers, master timer etc. Safe to say, there is not simply one single set_duty that controls the waveform. Then there are dead time and, faults etc.

With that said perhaps it would be wise to start small with some sort of MVP. What would you think about something like splitting this in to three main types:

  • HrTimer - this is where we control the period, and overall timer modes and settings
  • CompareRegister - I guess this could implement the PwmPin trait even if it might not necessarily be the "duty" that is controlled with set_duty in all cases
  • Output - This is what owns an output pin, may be used for setting what events to listen to in order to form the wave form.
    I would imagine something roughly like this
//        .               .
//        .  30%          .
//         ----           .                 ----
//out1    |    |          .                |    |                
//        |    |          .                |    |                
// --------    ----------------------------    --------------------
//        .                ----           .                ----
//out2    .               |    |                          |    |
//        .               |    |                          |    |
// ------------------------    ----------------------------    ----

type Prescaler = Pscl4; // Prescaler of 4
let (timer, cr1, _cr2, _cr3, _cr4, (out1, out2)) = dp.HRTIM_TIMA.pwm_hrtim::<Prescaler>((pin_a, pin_b), rcc)
    .period(0xFFFF)
    .mode(Mode::PushPull) // Set push pull mode, out1 and out2 are 
                          // alternated every period with one being
                          // inactive and the other getting to output its wave form
                          // as normal
    .finalize();

out1.rst_event(EventSource::Cr1); // Set low on compare match with cr1
out2.rst_event(EventSource::Cr1);

out1.set_event(EventSource::Period); // Set high at new period
out2.set_event(EventSource::Period);
                    // ^
                    // |
                    //  *---- Perhaps multiple EventSources could be Or:ed together?

cr1.set_duty(timer.get_period() / 3);
timer.set_period(foo);

adc-one-shot example does not work in release mode

Replacing opt-level = 0 with opt-level = 0 or opt-level = "s" causes adc conversion to get stuck at wait_for_conversion_sequence. As far as I can see the same thing happens when running in release mode(without changing any settings).

rustc 1.70.0 (90c541806 2023-05-31)
Device: nucleo-G474RE with stm32g474ret

Cargo.toml

 [profile.dev]
-opt-level = 0
+opt-level = "s"

 codegen-units = 1
 debug = true
 incremental = false
 lto = false

 [profile.release]
 debug = false
 codegen-units = 1
 incremental = false
 lto = true

Log

$ DEFMT_LOG=info cargo run --example adc-one-shot --features stm32g474,log-rtt,defmt -- --chip STM32G474RETx
   Compiling defmt-macros v0.3.5
   Compiling defmt v0.3.4
   Compiling defmt-rtt v0.4.0
   Compiling stm32g4xx-hal v0.0.1 (/home/decahe/stm32g4xx-hal)
   Compiling panic-probe v0.3.1
    Finished dev [optimized + debuginfo] target(s) in 29.07s
     Running `probe-run --connect-under-reset target/thumbv7em-none-eabihf/debug/examples/adc-one-shot --chip STM32G474RETx`
(HOST) INFO  flashing program (14 pages / 14.00 KiB)
(HOST) INFO  success!
────────────────────────────────────────────────────────────────────────────────
INFO  start
└─ adc_one_shot::__cortex_m_rt_main @ examples/adc-one-shot.rs:24
INFO  rcc
└─ adc_one_shot::__cortex_m_rt_main @ examples/adc-one-shot.rs:29
INFO  Setup Adc1
└─ adc_one_shot::__cortex_m_rt_main @ examples/adc-one-shot.rs:34
INFO  Setup Gpio
└─ adc_one_shot::__cortex_m_rt_main @ examples/adc-one-shot.rs:40
INFO  Enter Loop
└─ adc_one_shot::__cortex_m_rt_main @ examples/adc-one-shot.rs:45
INFO  Convert
└─ adc_one_shot::__cortex_m_rt_main @ examples/adc-one-shot.rs:48
^C────────────────────────────────────────────────────────────────────────────────
stack backtrace:
   0: stm32g4xx_hal::adc::DynamicAdc<stm32g4::stm32g474::ADC1>::wait_for_conversion_sequence
        at src/adc.rs:1594:27
   1: core::ptr::read_volatile
        at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/ptr/mod.rs:1553:9
   2: vcell::VolatileCell<T>::get
        at /home/decahe/.cargo/registry/src/index.crates.io-6f17d22bba15001f/vcell-0.1.3/src/lib.rs:33:18
   3: stm32g4::generic::Reg<REG>::read
        at /home/decahe/.cargo/registry/src/index.crates.io-6f17d22bba15001f/stm32g4-0.15.1/src/generic.rs:73:19
   4: stm32g4xx_hal::adc::DynamicAdc<stm32g4::stm32g474::ADC1>::current_sample
        at src/adc.rs:1608:21
   5: stm32g4xx_hal::adc::DynamicAdc<stm32g4::stm32g474::ADC1>::convert
        at src/adc.rs:1576:34
   6: stm32g4xx_hal::adc::Adc<stm32g4::stm32g474::ADC1,stm32g4xx_hal::adc::Disabled>::convert
        at src/adc.rs:1996:21
   7: adc_one_shot::__cortex_m_rt_main
        at examples/adc-one-shot.rs:49:22
   8: main
        at examples/adc-one-shot.rs:20:1
   9: Reset
(HOST) INFO  device halted by user

CAN FIlter Configuration

Hello,

I have written some code to try and modify the fdcan0 filters without success.
My code to configure the can is as follows :

let can1 = {

       let rx = gpioa.pa11.into_alternate().set_speed(Speed::VeryHigh);
       let tx = gpioa.pa12.into_alternate().set_speed(Speed::VeryHigh);

       let can = FdCan::new(dp.FDCAN1, tx, rx, &rcc);

       let mut can = can.into_config_mode();
       can.set_protocol_exception_handling(false);

       can.set_nominal_bit_timing(btr);

       //Create new Standard Filter
       let filtre = StandardFilter {
           filter: FilterType::BitMask {
               filter: 0x004,
               mask: 0x7FF
           },
           action: Action::StoreInFifo0,
       };

       can.set_standard_filter(
           StandardFilterSlot::_0,
           filtre,
       );

       //Set fdcan to reject all frames that do not match the filter
       can.set_global_filter(GlobalFilter::reject_all());

       hprintln!("-- Current Config: {:#?}", can.get_config());

       can.into_normal()
   };

The code builds without issues or warnings but when I try to print the messages received by the can using the can-echo.rs example I receive everything. The messages I am supposed to get and those that I don't. Also the receiver header does not have the right ID. Sending messages using a Raspberry Pi with different ID, the STM always sends back an ID equal to 0.
Furthermore, using GDB I have looked at the register configuration values at the address 0x4000A480 where the FDCAN_RXGFC (Global FIlter COnfiguration) register is located and the register has the reset value. No configuration has been applied.

Am I doing something wrong ? I some kind of configuration wrong ? I am using a testbench where I used to test the bus CAN using STM32F103 without any problems so it is not a hardware problem. The logic analyzer also reads the correct Standard ID so the problem is also not on the message sent by the Raspberry Pi.

Race condition in gpio

I hope I am wrong, but I think there might be a race condition in the gpio's into_{x} methods.

gpio.pupdr.modify(|r, w| {

Notice how we perform a read-modify-write sequence without anything preventing the same thing being done to another pin in the same port.

As far as I can see, I believe we would need either a critical section or exclusive access to some sort of token to guarantee exclusive access. A critical section would cause a slight bit of overhead but would otherwise be non-breaking API-wise, I think.

Timer driven Events

There aren't any way to setup run ADC from any timer or other event.
Also there aren't any functions to create chain of timers.

@usbalbin if you have some future PR's or any ideas, code snippets, welcome to the discussion.

Flash - Bad LengthTooLong check

    /// Retrieve a slice of data from `FLASH_START + offset`
    pub fn read(&self, offset: u32, length: usize) -> Result<&[u8]> {
        self.valid_address(offset)?;

        if offset + length as u32 > self.flash_sz.kbytes() {
            return Err(Error::LengthTooLong);
        }

I do not believe that check takes dual bank flash into account (RM)

From what I can tell from the table in the RM, the address offset 0x0004_0000 (Page 0 on Bank 2) should be valid for all devices supporting dual bank and having it enabled no matter 128, 256 or 512kB. However trying to read from that on an 256kB device gives Err(Error::LengthTooLong)

#![no_main]
#![no_std]

use cortex_m_rt::entry;
use hal::prelude::*;
use hal::stm32;
use stm32g4xx_hal as hal;
use hal::flash::FlashSize;
use hal::flash::FlashExt;
extern crate cortex_m_rt as rt;

#[macro_use]
mod utils;

use utils::logger::println;

#[entry]
fn main() -> ! {
    utils::logger::init();

    let dp = stm32::Peripherals::take().expect("cannot take peripherals");

    let mut flash = dp.FLASH.constrain();
    let is_dual_bank = flash.is_dual_bank();

    println!("Is dual bank: {}", is_dual_bank);

    let flash_writer = flash.writer::<2048>(FlashSize::Sz256K);

    let bytes = flash_writer.read(0x0000_0000, 4).unwrap();
    println!("Bank 1 first 4 bytes: {:?}", bytes);

    if is_dual_bank {
        let bytes = flash_writer.read(0x0004_0000, 4).unwrap(); // BOOM <-- Error::LengthTooLong 
        println!("Bank 2 first 4 bytes: {:?}", bytes);
    }

    loop {
        cortex_m::asm::nop()
    }
}

uart-dma example with changing data length

The uart-dma example does not show how to send data with different length using dma.

Is this not supported by this crate or is it even a hardware limitation?

example:

[...]

let data_to_send = [
    &b"Hello"[..], // These are to be sent one at a time to simulate sending messages of different sizes
    &b"I"[..],
    &b"am Bob the Bot"[..],
];


// Setup DMA for USART2 TX with dma channel 1.
let mut transfer =
    streams
        .0
        .into_memory_to_peripheral_transfer(tx.enable_dma(), &mut tx_buffer[..], config);

transfer.start(|_tx| {});
loop {
    while !transfer.get_transfer_complete_flag() {}

    delay_syst.delay(1000.millis());
    led.toggle().unwrap();
    transfer.restart(|_tx| {}); // <---------- Do something here to either change buffer to data_to_send[i],
                                // , or copy to tx_buffer (assuming it is large enough) and tell `transfer` the new data length
}

GPIO alternate function not configurable

It's not possible to configure the alternate function registers of the GPIO pins. This is needed for implementing peripherals like I2C and others.

The STM32F3 series has the same register interface for GPIO. I'll try and port their implementation and code generator . I'm making this issue for tracking and discussion.

RFC: Automatic clock configuration

The HAL currently expects the user to manually select a suitable clock configuration. Usually, this is done using, for example, STM32CubeMX.

I would argue that this is not what most users want - they do not want to download a comparably large additional software package and click through its interface whenever their clock requirements change. I would argue that it should be possible to specify the required frequencies somewhere in the project and have some tool automatically generate the required clock configuration.

Other HALs (stm32f4xx-hal, for example) implement a more comfortable interface which calculates the PLL configurations at runtime. This approach is suboptimal as it increases code size and startup time - clock configuration calculation should ideally be done at compile time.

I just hacked a library together (mgottschlag/stm32g4xx-clkcfg) together which basically performs an exhaustive search over all possible clock configurations, selecting the best according to the requirements specified by the user. The library then generates a code fragment that can be included via include!().

What do you think of this approach? Should something like that be integrated into the HAL or at least referenced by the README?

Currently, the library has its own copy of stm32g4xx-hals config structs and will therefore break whenever those are changed, so some refactoring is necessary to make the approach more robust.

Usage Example

use std::io::stdout;

use embedded_time::rate::*;
use stm32g4xx_clkcfg::{ClockRequirements, Frequencies};

fn main() {
    println!("Configuration for the highest possible sysclk with a 48MHz USB clock from a 24 MHz crystal:");
    let req = ClockRequirements::new()
        .hse(24_000_000.Hz())
        .sysclk(170_000_000.Hz())
        .usb_rng_clk(true);
    match req.resolve(false) {
        Ok((cfg, freqs)) => {
            cfg.write_code(&mut stdout()).unwrap();
	    // _freqs holds the frequencies generated by the configuration.
        }
        Err(e) => {
            println!("Error: {:?}", e);
        }
    }
}

ADC configuration register constraints

Hi,

I've been running into some issues configuring the ADC in a non-standard configuration (I'm using injected channels, I realize that isn't currently supported by the library, but I'm trying to use the library as much as possible and I hope to contribute a PR in the near future).

I find that in certain cases the ADC will hang in the calibration step. I believe I've tracked it down to section 21.4.10 of the reference manual (screenshot below), which states that writes to CFGR, SMPRx, TRy, SQRy, JDRy, OFRy, OFCHRy and IER registers are only allowed when the ADC is enabled but not started (and there's no hardware protection against this, and it can result in undefined ADC behavior).

In other words, most of the configuration accessors implemented on impl Adc<stm32::$adc_type, Disabled> should instead be implemented on impl Adc<stm32::$adc_type, Configured> (set_resolution, set_align, set_external_trigger, set_continuous, etc.).

In my case I see different behavior on 0.0.1 compared to head of main, with main being more sensitive to the register access sequencing.

Does this sound plausible? I was surprised by this section of the reference manual, but it seems to fix the issue in my case.

image

more delay methods

The delay function seems to be lacking some methods. It would be nice if this example worked for the commented out lines.

Click to expand
#![deny(warnings)]
#![deny(unsafe_code)]
#![no_main]
#![no_std]

#[cfg(debug_assertions)]
use panic_semihosting as _;

#[cfg(not(debug_assertions))]
use panic_halt as _;

use stm32g4xx_hal::{
   delay::DelayFromCountDownTimer,
   prelude::*,
   rcc::Config,
   stm32::Peripherals,
   timer::Timer,
};

use cortex_m_rt::entry;

#[entry]
fn main() -> ! {
    let dp = Peripherals::take().expect("cannot take peripherals");
    let cp = cortex_m::Peripherals::take().expect("cannot take core peripherals");
    let mut rcc = dp.RCC.freeze(Config::hsi());

    let gpioa = dp.GPIOA.split(&mut rcc);
    let mut led = gpioa.pa5.into_push_pull_output();

    let mut delay_syst = cp.SYST.delay(&rcc.clocks);

    let timer2 = Timer::new(dp.TIM2, &rcc.clocks);
    let mut delay_tim2 = DelayFromCountDownTimer::new(timer2.start_count_down(100.ms()));

    loop {
        led.toggle().unwrap();
        delay_syst.delay(1000.ms());
        delay_syst.delay_ms(1000);
        delay_syst.delay_ms(1000_u32); 
        //delay_syst.delay_ms(1000_u16);   //expected `u32`, found `u16`
        //delay_syst.delay_ms(100_u8);    //expected `u32`, found `u8`

        led.toggle().unwrap();
        //delay_tim2.delay(1000.ms());    //method not found 
        //delay_tim2.delay_ms(1000);      //trait `DelayMs<i32>` is not implemented
        delay_tim2.delay_ms(1000_u32);
        delay_tim2.delay_ms(1000_u16);
        delay_tim2.delay_ms(100_u8);
    }
}

Also, module stm32 should be called pac. Several hals are doing this by making pac an alias for stm32.

I am attempting several examples on stm32g4xx_hal that I have compiling on other hals. Differences with delay are causing the most problems at the moment . (See https://github.com/pdgilbert/rust-integration-testing/actions.)

ADC calibration should be done after setting the clock mode

Hi,

I noticed on my board nucleo-G474-RE when connecting an ADC to ground with RC filter, that the readings were off by 50mV. I noticed that calibrating the ADC before setting the clock config (which the enable function of the HAL also does) results in wrong calibration value (almost max register value). Which resulted in 50 bits offset being applied to my readings. The ADC doesn't work correctly when the clock is higher than the maximum (60MHz), so before the clock mode settings are set the clock might be AHB clock. Calibration should be done before ADEN=1 but after setting the clock mode in the common ADC registers.

Easy fix might be to swap around calibrate_all() and apply_config() calls to calibrate after setting clocks (And other config options, but before enabling the ADC).

What would be reqired to get this to a working state?

I'm interested in getting USB up and running on these micros, so I got myself a STM32G474 Nucleo and a STM32G431 Nucleo board. Was trying to get the blinky example to work but it won't compile.

I was wondering how much work was required to get this to a working state and if someone could possibly point me in the right direction.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.