Giter Club home page Giter Club logo

stm32g0xx-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.17
      • 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.

stm32g0xx-hal's People

Contributors

adinack avatar agalakhov avatar almusil avatar altesschaf avatar andresv avatar burrbull avatar calebissharp avatar danc86 avatar davidlattimore avatar dimpolo avatar dotcypress avatar fayalalebrun avatar hannes-hochreiner avatar ijager avatar jacobbarssbailey avatar justinlatimer avatar keadwen avatar lkolbly avatar mattico avatar mettz avatar mgottschlag avatar mogenson avatar oldsheep68 avatar rblaze avatar richardeoin avatar sjoerdsimons avatar smeenka avatar timhoeppner avatar wassasin avatar yatekii 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  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  avatar  avatar

stm32g0xx-hal's Issues

Add G0B1 Variant

Hey everyone,

I'm starting a project based on the g0b1 variant (as it's the chip in the series with native USB support (along with the C1) and also a Nucleo board and as such, I think it would make sense to start here in the expansion of this HAL to other chips in the G0 PAC.

I started giving it a go, but this patch seems non-trivial. Apparently, the SVD for the B1 is quite different from the previous chips:

stm32-rs/stm32-rs#548
stm32-rs/stm32-rs#785
stm32-rs/stm32-rs#789

As such, more than just feature-gating various sections of code is needed to describe the discrepancies. For example, I'm working on fixing the USARTs right now, but several assumptions are incorrect:

  1. There are now up to 6 USARTs and 2 LPUARTs. This means in certain cases LPUART -> LPUART1
  2. There is the addition of SPI3 and I2C3
  3. Both of these require access to Port E and Alternative Function 8-15

All of these require additions to the DMAMUX. I've done all of this, but I need help with register naming discrepancies. For example, CR1 is no longer a field on the USARTs as the CR1 register layout is different whether or not the FIFO is enabled. One of the SVD patches defaults that register to the disabled case, but then how would we use the FIFO? The same is true for the ISR register in the USART. I'm sure there are other things I still need to run into, but that was the first blocker.

So, we can write code that has to save some state about the FIFIO configuration and then select the correct register, but that will be quite a bit of complexity to something that might simply be an SVD patch.

Any advice on how to proceed on this would be appreciated. Technically for my project, I need the ADC, DAC, GPIO, and USB UART, which I could hack together - but I would prefer to help get this variant off the ground.

Thanks!

timer interrupt fires immediately after being enabled

If I configure a timer peripheral with a long duration, like this:

    let mut timer = p.TIM15.timer(&mut rcc);
    timer.start(4_000.ms());
    timer.listen();

the associated interrupt fires immediately and then again every 4 seconds.

I want to use the timer to implement a watchdog-style behaviour where I reset the timer whenever a good event happens, and thus if the interrupt fires it's bad. For that usage pattern I need the interrupt handler not to fire until the actual timer has elapsed, not immediately.

Spelling error `dma_circualr_mode()`

pub trait DmaMode<ADC> {
    /// Error type returned by ADC methods
    type Error;
    fn dma_enable(&mut self, enable: bool);
    fn dma_circualr_mode(&mut self, enable: bool);   // <=======
}

Here DmaMode contains the method dma_circualr_mode(). Please correct it to dma_circular_mode(). The name error doesn't inspire confidence it will in fact work.

As seen on https://github.com/stm32-rs/stm32g0xx-hal/blob/e6145ef83c639e736556fb4775f349aef7100ad6/src/analog/adc.rs#L374C16-L374C16

i2c infinite loop when building with optimizations

When I build with optimizations (1 or 2) enabled

[profile.dev]
opt-level = 1

Then i2c read operations can get into an infinite loop in the busy_wait macro.
Bus speed = =100khz.

// Wait until address was sent
busy_wait!(self.i2c, busy);

Here the intention is to wait until the peripheral is not busy anymore and then break out of the loop.

} else if isr.$flag().bit_is_set() {
    break;
}

However, the busy flag is 1 if busy and will be cleared when not busy anymore. So the check should actually check for bit_is_cleared().

But I guess that's not true for all $flags that can be passed in.

Because optimization is on, the code is faster, the bit is already cleared so it ends up in an infinite loop.

Help, examples of measuring input signals

I'm very sorry to use this method to ask questions here, but I have tried my best to search for information (I can't find relevant cases online)

I am not familiar with the API. Can you give me an example if you are familiar with it?

For example:

How to read the rotational speed of a 4 pin fan FG signal

Build fails with --features stm32g081

cargo build --example blinky --features stm32g081

error: symbol `DEVICE_PERIPHERALS` is already defined
    --> /Users/andres/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32g0-0.10.0/src/stm32g081/mod.rs:1160:1
     |
1160 | static mut DEVICE_PERIPHERALS: bool = false;
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

error: could not compile `stm32g0`.

To learn more, run the command again with --verbose.

Feature: add RTIC monotonic impl

It is convenient if monotonic for RTIC is available in HAL. Otherwise users have to do it manually and relay on buggy versions that they might find from github.

Recently @burrbull has added nice impls for F1 and F4.
G0 monotonic can be based on those.

UnlockedFlash::write memory safety

The function UnlockedFlash::write (and write_native) let you write to arbitrary memory locations, bypassing Rust's ownership checks, but are currently not marked as unsafe.

I recently made some changes to some code that was using this function and accidentally ended up passing an address that was effectively a pointer to the stack rather than a pointer to flash. Needles to say, this didn't end well.

I feel like these functions as they are, should be marked as unsafe, since they rely on the caller to check that the address to be written is (a) part of flash and (b) not part of the program currently being executed.

A safe alternative API would be to accept an &mut [u8] for the part of flash that is to be written.

Thoughts?

Next release

I2C is now fixed and examples can be built for all targets. Also docs.rs doc generation should now work.
I think we are ready for the 0.0.8release.

Fix DMA channel count for STM32G071xx and STM32G081xx

According to RM0444 Reference manual:

There is one instance of DMA, with 7 channels on STM32G071xx and STM32G081xx devices and 5 on STM32G031xx and STM32G041xx.

Currently only 5 channels are defined:
https://github.com/stm32-rs/stm32g0xx-hal/blob/master/src/dma.rs#L242-L250

dma! {
    DMA: (dmaen, dma1rst, {
        Channel1: ( ccr1, cndtr1, cpar1, cmar1, cgif0 ),
        Channel2: ( ccr2, cndtr2, cpar2, cmar2, cgif4 ),
        Channel3: ( ccr3, cndtr3, cpar3, cmar3, cgif8 ),
        Channel4: ( ccr4, cndtr4, cpar4, cmar4, cgif12 ),
        Channel5: ( ccr5, cndtr5, cpar5, cmar5, cgif16 ),
    }),
}

Incorrect calculation for frequencies PLLQ and PLLP

    let p = stm32::Peripherals::take().expect("cannot take peripherals");
    let pll_config = hal::rcc::PllConfig { m: 1, n: 9, r: 3, q: Some(3), p: Some(3), ..hal::rcc::PllConfig::default() };
    let mut rcc = p.RCC.constrain().freeze(hal::rcc::Config::pll().pll_cfg(pll_config));

    defmt::info!("pll_clk.r={}", rcc.clocks.pll_clk.r.0);
    if let Some(clk) = rcc.clocks.pll_clk.q {
        defmt::info!("pll_clk.q={}", clk.0);
    }
    if let Some(clk) = rcc.clocks.pll_clk.p {
        defmt::info!("pll_clk.p={}", clk.0);
    }

Running the above code, I expect to see r, q and p all reporting 48Mhz, since all have a divisor of 3. Instead, I get:

pll_clk.r=48000000
pll_clk.q=5333333
pll_clk.p=5333333

In the following screenshot from STM32CubeMX, it shows PLLQ and PLLP taking their output from PLLN.

stm32g-pll

If I apply the following patch to the HAL crate, then I get the expected value of 48Mhz for all three clocks.

diff --git a/src/rcc/mod.rs b/src/rcc/mod.rs
index d503a23..9d4f440 100644
--- a/src/rcc/mod.rs
+++ b/src/rcc/mod.rs
@@ -235,7 +235,7 @@ impl Rcc {
                 self.rb
                     .pllsyscfgr
                     .write(move |w| unsafe { w.pllq().bits(div - 1) });
-                let req = freq / div as u32;
+                let req = pll_freq / div as u32;
                 Some(req.hz())
             }
             _ => None,
@@ -246,7 +246,7 @@ impl Rcc {
                 self.rb
                     .pllsyscfgr
                     .write(move |w| unsafe { w.pllp().bits(div - 1) });
-                let req = freq / div as u32;
+                let req = pll_freq / div as u32;
                 Some(req.hz())
             }
             _ => None,

Additional maintainer

I have big plans with this crate as I am using G0 in production.
Basically my plan is to port drivers from stm32l0xx-hal after we have tackled DMAMUX: #12.
Also CI must be setup. There are lot of stm32 HALs that are using it, we can do the same.

So I would like to become a co-maintainer of this crate. Let me know what do you think.

IWDG prescaler calculation

I have issue with independent watchdog...I can't set it to 16secs I tracked the start function and observed the frequency value used is 16khz and not 32khz as in the manual maybe the calculation of cycles use the half but I don't get it !? I will investigate more...

Blinky does not build

cargo build --example blinky --features stm32g031

error: no rules expected the token `}`
   --> src/dmamux.rs:209:5
    |
154 | macro_rules! dma_mux {
    | -------------------- when calling this macro
...
209 |     },
    |     ^ no rules expected this token in macro call

error[E0412]: cannot find type `Channels` in this scope
   --> src/dmamux.rs:214:21
    |
214 |     type Channels = Channels;
    |                     ^^^^^^^^
    |
help: try
    |
214 |     type Channels = Self::Channels;
    |                     ^^^^^^^^^^^^^^
help: consider importing this struct
    |
1   | use crate::dma::Channels;
    |

error[E0422]: cannot find struct, variant or union type `Channels` in this scope

@ijager looks like recent dmamux modifications have broken it.

It works fine with cargo build --example blinky --features stm32g071

Invalid clock configuration for apb_clk, apb_tim_clk and core_clk

G'day

I've identified an inconsistency in the RCC configuration.
According to page 166/1390 RM0444 Rev 5, the apb_clk is not driven by sys_freq, but ahb_freq.

In the further review of the RCC configuration freeze, I've noticed 3 separate inconsistencies with the RM0444 and STM32CubeMX Clock Configuration section:

  1. apb_clk input is sys_freq (code reference), when it should be ahb_clk.
  2. apb_tim_clk is always set as /2 (code reference), when it should be:
    • x1 when apb_psc is x1
    • x2 when apb_psc is x2 or greater
  3. core_clk is ahb_freq / 8 (code reference), when it should be either /1 or /8 (while /8 is default).

Image reference from STM32CubeMX for STM32G071GBU6
STM32G071GBUx

Thanks,
Jakub

feature stm32g07x should be split up

Currently we have the following features

stm32g07x = ["stm32g0/stm32g07x"]
stm32g030 = ["stm32g0/stm32g030"]
stm32g031 = ["stm32g0/stm32g031"]
stm32g041 = ["stm32g0/stm32g041"]
stm32g081 = ["stm32g0/stm32g081"]

However there are many distinctions between stm32g070 and stm32g071, so I think we should add separate features for both.

Also we might end up doing the following all over:

#[cfg(not(any(
    feature = "stm32g070",
    feature = "stm32g030"
)))]
// Datasheet DS12991 Rev 3 3.14.1
const TS_CAL2: *mut u16 = 0x1FFF_75CA as *mut u16;

So maybe we need to have a feature for value line / non-value line?

i2c-nonblocking: how to use?

What is the state of non-blocking i2c, can it be used? I tried
cargo add stm32g0xx-hal --no-default-features --features stm32g071cb,rt,i2c-nonblocking
but compilation fails with could not find blocking in i2c in prelude.rs.

Unexpected result from CRC digest

According to the CRC example from the SD Specifications (Part 1 Physical Layer Specification Simplified Specification V7.10) the following result is expected:

Polynomial: 0x09 (size: 7-bit)
Seed: 0
Data: 0x40 0x00 0x00 0x00 0x00
Hash: 0b1001010

Observed Result:

let mut u8array: [u8; 5] = [0x40, 0, 0, 0, 0];
let u8sum = crc.digest(&u8array[..]);

u8sum: 0b1101101

Digesting the data as u16 and u32 yielded the expected results.

let mut u16array: [u16; 3] = [0x40, 0, 0];
let u16sum = crc.digest(&u16array[..]);
crc.reset();
let mut u32array: [u32; 2] = [0x40, 0];
let u32sum = crc.digest(&u32array[..]);

u16sum: 0b1001010
u32sum: 0b1001010

Next release

Hi @dotcypress, Thanks for your work on this crate. It got me up te speed quickly with the stm32g070.

I have been writing crate examples based on this library. However it turns out I cannot publish that crate because it depends (dev-dependencies) on an unpublished version of this crate.

So I guess my question is when you're planning to do a next release (0.7)? And whether you need any help to reach that target.

You probably know this, but when doing a release, it would be nice to also git tag it so that there will be a neat release overview on github as well, like this

ADC VREFINT calibration values

I needed to perform a supply-relative ADC measurement using the internal reference voltage. To do that you need to use the VREFINT calibration value, which is the adc value measured at 3V during production.

VREFINT calibration value is a 16 bit value at 0x1FFF_75AA (datasheet 3.13.2). I couldn't find it in the pac.
For now I solved it like this in my application, but I think this should be part of the hal crate.

/// Returns a pointer to VREFINT_CAL, the VREFINT calibration value
#[inline(always)]
const fn vrefint_ptr() -> *const u16 {
    // DS12766 3.13.2
    0x1FFF_75AA as *const _
}

fn adc_abs_voltage(vref_val: u32, adc_val: u32) -> (u32,u32) {

    // safe because read only memory area
    let vref_cal: u32 = unsafe {
       ptr::read_volatile(vrefint_ptr())  as u32
    };

    // RM0454 14.9 Calculating the actual VDDA voltage using the internal reference voltage
    // V_DDA = 3 V x VREFINT_CAL / VREFINT_DATA
    let vdda_mv = 3000u32 * vref_cal / vref_val;

    // RM0454 14.9 Converting a supply-relative ADC measurement to an absolute voltage value
    //                   Vdda
    // VCHANNELx = --------------- × ADC_DATAx
    //                FULL_SCALE
    let adc_mv = (vdda_mv * adc_val / 4095u32); // TODO: full scale depends on config

    (vdda_mv, adc_mv)
}


let vref_val: u16 = adc.read(&mut vref).expect("adc read failed");
let adc_val: u16 = adc.read(&mut adc_pin).expect("adc read failed");
let (vdda_mv, adc_mv) = adc_abs_voltage(vref_val as u32, adc_val as u32);

Do you guys have opinions on how to implement this in de hal adc driver?

unable to build examples (exit status: 101)

Hello, did a fresh git clone install on a new Ubuntu install. when I try to run, I get
( error: failed to run custom build command for stm32g0 v0.13.0)

So I tried several things, but I finally settled on issue with this git as I tried others and the build works. You can see here, I did a new git clone, then a cargo test and it fails the same way a build fails.

I was running the build as follows:
jemo@jemo-MBP:~/development/git/stm32g0xx-hal$ cargo build --release --example blinky
Here is the output of what I mentioned above:

jemo@jemo-MBP:~/development/git$ git clone https://github.com/stm32-rs/stm32g0xx-hal.git
Cloning into 'stm32g0xx-hal'...
remote: Enumerating objects: 1769, done.
remote: Counting objects: 100% (575/575), done.
remote: Compressing objects: 100% (256/256), done.
remote: Total 1769 (delta 363), reused 484 (delta 315), pack-reused 1194
Receiving objects: 100% (1769/1769), 398.33 KiB | 3.04 MiB/s, done.
Resolving deltas: 100% (1223/1223), done.
jemo@jemo-MBP:~/development/git$ cd stm32g0xx-hal/
jemo@jemo-MBP:~/development/git/stm32g0xx-hal$ cargo test
    Updating crates.io index
   Compiling nb v1.0.0
   Compiling cortex-m v0.7.4
   Compiling semver-parser v0.7.0
   Compiling void v1.0.2
   Compiling proc-macro2 v1.0.36
   Compiling unicode-xid v0.2.2
   Compiling version_check v0.9.4
   Compiling syn v1.0.90
   Compiling vcell v0.1.3
   Compiling autocfg v1.1.0
   Compiling bitfield v0.13.2
   Compiling proc-macro2 v0.4.30
   Compiling unicode-xid v0.1.0
   Compiling cortex-m-rt v0.6.15
   Compiling critical-section v0.2.6
   Compiling bare-metal v1.0.0
   Compiling bytemuck v1.9.1
   Compiling atomic-polyfill v0.1.7
   Compiling syn v0.15.44
   Compiling hashbrown v0.11.2
   Compiling cfg-if v1.0.0
   Compiling byteorder v1.4.3
   Compiling num-derive v0.2.5
   Compiling r0 v0.2.2
   Compiling heapless v0.7.10
   Compiling cortex-m-semihosting v0.3.7
   Compiling stm32g0 v0.13.0
   Compiling stable_deref_trait v1.2.0
   Compiling rtic-core v1.0.0
   Compiling rtic-monotonic v1.0.0
   Compiling embedded-graphics v0.5.2
   Compiling panic-halt v0.2.0
   Compiling nb v0.1.3
   Compiling semver v0.9.0
   Compiling volatile-register v0.2.1
   Compiling proc-macro-error-attr v1.0.4
   Compiling proc-macro-error v1.0.4
   Compiling cortex-m-rtic v1.0.0
   Compiling rgb v0.8.32
   Compiling indexmap v1.8.1
   Compiling num-traits v0.2.14
   Compiling hash32 v0.2.1
   Compiling embedded-hal v0.2.7
   Compiling rustc_version v0.2.3
error: failed to run custom build command for `stm32g0 v0.13.0`

Caused by:
  process didn't exit successfully: `/home/jemo/development/git/stm32g0xx-hal/target/debug/build/stm32g0-0175a714f014c3f4/build-script-build` (exit status: 101)
  --- stdout
  cargo:rustc-link-search=/home/jemo/development/git/stm32g0xx-hal/target/thumbv6m-none-eabi/debug/build/stm32g0-9342c4cb479b36c9/out

  --- stderr
  thread 'main' panicked at 'No device features selected', /home/jemo/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32g0-0.13.0/build.rs:20: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
jemo@jemo-MBP:~/development/git/stm32g0xx-hal$ 

Configuring I2C pins causes them to be temporarily pulled low

Currently SDAPin and SCLPin are only implemented for pins in mode Output. Configuring the pins as open-drain prior to them being reconfigured for their alternate function results in the pins momentarily being pulled low (see scope trace below). I've found that this can confuse other devices on the bus. In my application, I'm currently working around this by using core::mem::transmute to construct a pin that thinks it's configured as open-drain, when it is in fact still in its default state. This seems to work well, but is pretty ugly.

Would you be open to implementing SDAPin and SCLPin for the pins in their default state? If so, I'm happy to send a pull request. Would you prefer that I implement for both DefaultMode and Output or just DefaultMode? Removing the implementations for Output would be a breaking change.

DS1Z_QuickPrint7

[dependencies.stm32g0xx-hal] produces error during cargo build "uplicate key: `stm32g0xx-hal`"

Hello,

I get the following error while trying to build after just adding entries to Cargo.toml. Here is the excerpt from that file:

[dependencies.stm32g0xx-hal]
version = "0.1.3"
features = ["rt", "stm32g030"]

[dependencies]
embedded-hal = "0.2.7"
bit_field = "~0.10"
bme280-multibus = "0.2.1"
stm32g0xx-hal = "0.1.3"

Here is the outcome changing the order by placing the [dependencies.stm32g0xx-hal] before/after [dependencies]

Caused by:
  duplicate key: `stm32g0xx-hal` for key `dependencies` at line 11 column 1
jemo@jemoLINUX:~/development/git/nuecleo-bme280$ cargo build
error: failed to parse manifest at `/home/jemo/development/git/nuecleo-bme280/Cargo.toml`

Caused by:
  could not parse input as TOML

Caused by:
  duplicate key: `stm32g0xx-hal` for key `dependencies` at line 14 column 1
jemo@jemoLINUX:~/development/git/nuecleo-bme280$ 

GPIO - alternate function + open drain

Hi.

I would like to use GPIO pin as timer output, but in open drain configuration instead of push-pull. I've found method setup(&self) in trait TimerPin<TIM>, but it accepts only pin in default Analog mode. Does HAL allow to configure timer pin as open drain?

Allow output value to be set before configuring pin as an output

Somewhat related to #87 (but more general)....

Sometimes you have a pin that has an external pull-up and you'd like to configure the pin as an output (generally an open-drain output) without momentarily pulling the pin low. I'd like it if we could have an API that allowed this. Possibilities that come to mind:

  1. Implement OutputPin for Analog. Downside would be that users might call set_low/high and expect an immediate effect.
  2. Implement some other method on pins that does the same thing as set_low/high, but makes the intent clearer. e.g. preset_low / preset_high.
  3. Add an argument to into_open_drain to specify the initial state. But this would be a breaking change.
  4. Add a new API for creating an OpenDrain output that allowed specifying the initial value and make into_open_drain just be a shortcut for this.

Thoughts?

SO8 package - is it supported?

It's not an issue but just a question: I'm thinking about getting the STM32G031J6 Discovery at some point, it's the one with the "8-legged" MCU. From the datasheet I understood that you can assign one of multiple GPIOs to the pins, e.g. PA8/PA11/PB1 to pin 5. Is that supported in the crate?

PWM: Off-by-one when computing ARR

    let p = stm32::Peripherals::take().expect("cannot take peripherals");
    let pll_config = PllConfig { m: 1, n: 9, r: 3, ..PllConfig::default() };
    let mut rcc = p.RCC.constrain().freeze(hal::rcc::Config::pll().pll_cfg(pll_config));
    let gpiob = p.GPIOB.split(&mut rcc);

    let pwm = p.TIM3.pwm(12.mhz(), &mut rcc);
    let mut pwm_ch1 = pwm.bind_pin(gpiob.pb0.set_speed(Speed::VeryHigh));
    let max = pwm_ch1.get_max_duty();
    pwm_ch1.set_duty((max + 1) / 2);
    pwm_ch1.enable();

If I run the above code on an STM32G031, I expect the output signal on PB0 to be 12Mhz. The system clock and the input to TIM3 is 16Mhz / 1 * 9 / 3 = 48Mhz, which is exactly 6 times the desired 12Mhz output. However, instead, I get 9.6Mhz. i.e. 48 / 5 instead of 48 / 4.

Signal when running the above code:

DS1Z_QuickPrint11

If I change pwm.rs to subtract 1 when computing arr, as follows:

diff --git a/src/timer/pwm.rs b/src/timer/pwm.rs
index c5decd2..d845e5f 100644
--- a/src/timer/pwm.rs
+++ b/src/timer/pwm.rs
@@ -56,7 +56,7 @@ macro_rules! pwm {
                 rcc.rb.$apbXrstr.modify(|_, w| w.$timXrst().clear_bit());
                 let ratio = rcc.clocks.apb_tim_clk / freq.into();
                 let psc = (ratio - 1) / 0xffff;
-                let arr = ratio / (psc + 1);
+                let arr = ratio / (psc + 1) - 1;
                 tim.psc.write(|w| unsafe { w.psc().bits(psc as u16) });
                 tim.arr.write(|w| unsafe { w.$arr().bits(arr as u16) });
                 $(

... then I get the expected 12Mhz signal:

DS1Z_QuickPrint10

I tried to find something definitive in the STM32 documentation, but couldn't. I did however find a fairly thorough write up of STM32 timers that shows the timer clock frequency being divided by ARR + 1 not simply by ARR.

I'm happy to send a PR if you'd like.

Feature: ADC over DMA support

Currently only single sample mode is supported by HAL.

G0 is very similar to L0 and it supports ADC over DMA.

However firstly we need to implement DMAMUX: #12 and then L0 code can be ported here.

I2C slave loses data on repeated start condition

I am currently using the nonblocking I2C slave implementation. I noticed that whenever a repeated start condition was present, I lost data from everything but the last operation.

I believe the reason is because I2cResult::Data is only given by I2c::check_isr_flags when the stop condition interrupt is generated. The problem being that the stop condition interrupt is not generated on a repeated start condition.

Perhaps the solution is to also return I2cResult::Data from the address interrupt if no stop condition happened since the last address was received. The challenge is that I2c::check_isr_flags would then need to return two structs in that call, one for the data and one for the address.

It would be good to hear from those who have more insight into the current implementation.

USART: Support half-duplex mode

The STM32G0x0 USART peripherals support a 1-wire half-duplex mode. From the reference manual:

26.5.15 USART single-wire Half-duplex communication

Single-wire Half-duplex mode is selected by setting the HDSEL bit in the USART_CR3 register. In this mode, the following bits must be kept cleared:

  • LINEN and CLKEN bits in the USART_CR2 register,
  • SCEN and IREN bits in the USART_CR3 register.
    The USART can be configured to follow a Single-wire Half-duplex protocol where the TX and RX lines are internally connected. The selection between half- and Full-duplex communication is made with a control bit HDSEL in USART_CR3.
    As soon as HDSEL is written to ‘1’:
  • The TX and RX lines are internally connected.
  • The RX pin is no longer used.
  • The TX pin is always released when no data is transmitted. Thus, it acts as a standard I/O in idle or in reception. It means that the I/O must be configured so that TX is configured as alternate function open-drain with an external pull-up.
    Apart from this, the communication protocol is similar to normal USART mode. Any conflict on the line must be managed by software (for instance by using a centralized arbiter). In particular, the transmission is never blocked by hardware and continues as soon as data are written in the data register while the TE bit is set.

The only other rust implementation I've been able to find is from the stm32l4xx-hal crate, but it looks like that is using a different style of configuration, so it wouldn't be a straight port.

I'd be happy to try and contribute this, but I'll need a couple of pointers (still pretty new to embedded rust).

Feature: fully erasable pins

GPIO in this project supports partially erased pin assignments, where the pin number is erased, allowing a group of related input or output pins to be collected in an array under a single type.

let generic_pa_pin_1 = gpioa.pa1.into_push_pull().downgrade(); // PAx<Output>

However it doesn't seem possible to remove the port number as well. For the general use case of wanting to create an array of pins, using only pins from a single port seems rather confining.

I've noticed that stm32f1xx-hal supports both partially and fully erased pin (erasing the pin number and the port respectively), by adding both Partially Erased and Fully Erased Pin types, with Partially Erased pins downgradable to Fully Erased pins:

let generic_pa_pin = gpioa.pa0.into_push_pull().downgrade(); // PAx<Output>
let generic_pin = generic_pa_pin.downgrade(); // PXx<Output>

To my (admittedly naive) eye it seems like this approach could be ported to this project without introducing any breaking changes, allowing for significantly more flexibility in managing IO pins.

If this sounds like a reasonable approach, I'd be happy to put together a pull request, but I wanted to make sure it would be a welcome and reasonable change before putting in the work.

Version 0.1.0

@dotcypress we have got bunch of good PRs lately, lets publish a new version to crates.io.
I think we could name it 0.1.0. Minor version number bump looks more solid than just using bugfix.

Lets also tag upcoming crates.io versions here. Then it is good to see what 0.1.0 contains and what is changed after that.

Feature: DMAMUX support

G0 is different from other STM32 MCUs because this uses a thing called DMAMUX. Well actually H7, L4+ and WB series are also using it but currently it is not implemented in their Rust HALs. So we can be the first ones to tackle this problem.

If this is done it allows to port a lot of DMA based drivers from stm32l0xx-hal which are relatively mature.

27.05.2020: Recently rust embedded wg suggested that this is way to go with DMA: https://github.com/ra-kete/dma-poc.
And an example how it is used: stm32-rs/stm32f3xx-hal#86

I2C doesn't send STOP if write_read is called immediately after any other transfer

If I call i2c.write_read twice in a row, then I don't see a STOP on the I2C bus in between the two transactions. The same happens if a read or a write is followed by a write_read.

I don't observe this behavior if I do just reads or writes.

Presumably what's special about write_read is that it clears the autoend bit in CR2, which must affect the auto-end still in progress for the previous transfer.

I'd like to propose that read, write and write_read should all wait until STOP is sent before returning. This does reduce parallelism slightly, however if someone wants to maximise parallelism, they'd probably want to use an interrupt or DMA based implementation. I've also run into other issues with this unintended parallelism. Specifically, I sent some data over I2C, then reset the system. Took me a while to realize that the data hadn't actually been fully sent out over the I2C bus when write returned.

I'll send a PR with the proposed change.

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.