Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SCK hiccups when using blocking::spi::Write::write rendering Mosi data corrupted #441

Open
BryceBeagle opened this issue Sep 10, 2022 · 1 comment

Comments

@BryceBeagle
Copy link

BryceBeagle commented Sep 10, 2022

If I try to .write more than a certain number of bytes[1] (exactly) in a single call/packet, the SCK signal stops working properly, hiccuping at regular intervals and preventing the data from getting sent. A couple other users on the Embedded Rust matrix server reported having similar issues and it was requested that I open an issue for this.

I am using an stm32f103 bluepill. I have tried with both the v0.9.0 release of the HAL and the head of master (f063d5b at time of writing).

[1]: With opt-level = 2 this is >13 bytes; with opt-level = 3 this is >28 bytes. These numbers are exact and deterministic


13 bytes of 0b10101010 at opt-level = 2:
Screenshot from 2022-09-08 21-51-58

14 bytes of 0b10101010 at opt-level = 2:
Screenshot from 2022-09-08 21-53-07


Reproducible snippet:

#![deny(unsafe_code)]
#![no_main]
#![no_std]

use cortex_m_rt::entry;
use embedded_hal::spi::MODE_0;
use nb::block;
use panic_rtt_target as _;
use rtt_target::{rprintln, rtt_init_print};
use stm32f1xx_hal::{pac, prelude::*, timer::Timer};
use stm32f1xx_hal::spi::{NoMiso, NoSck, Spi};

#[entry]
fn main() -> ! {
    rtt_init_print!();

    let cp = cortex_m::Peripherals::take().unwrap();
    let dp = pac::Peripherals::take().unwrap();

    let mut flash = dp.FLASH.constrain();
    let rcc = dp.RCC.constrain();

    let clocks = rcc.cfgr
        .use_hse(8.MHz())
        .sysclk(48.MHz())
        .hclk(12.MHz())
        .pclk1(6.MHz())
        .freeze(&mut flash.acr);

    let mut gpiob = dp.GPIOB.split();
    let mosi = gpiob.pb15.into_alternate_push_pull(&mut gpiob.crh);
    let sck = gpiob.pb13.into_alternate_push_pull(&mut gpiob.crh);
    let mut spi = Spi::spi2(
        dp.SPI2,
        (sck, NoMiso, mosi),
        MODE_0,
        3.MHz(),
        clocks,
    );

    let mut timer = Timer::syst(cp.SYST, &clocks).counter_hz();
    timer.start(60.Hz()).unwrap();

    loop {
        spi.write(&[
            // 13 bytes
            0b10101010, 0b10101010, 0b10101010, 0b10101010,
            0b10101010, 0b10101010, 0b10101010, 0b10101010,
            0b10101010, 0b10101010, 0b10101010, 0b10101010,
            0b10101010,

            // One extra (uncommenting this breaks things with opt-level = 2)
            // 0b10101010,
        ]).unwrap();
        block!(timer.wait()).unwrap();
    }
@hawav
Copy link

hawav commented Mar 3, 2023

I've encountered the same issue while driving WS2812B using SPI. No matter what I did, I couldn't get the lights to work properly.
After using an oscilloscope, I found that spi.write will cause SCK stops for a period of time after each byte is sent.
I was able to work around the issue by using DMA transfers instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants