Merge pull request #1375 from embassy-rs/stm32-sdmmc-refactor
stm32/sdmmc: refactor, simplify code, add HIL test
This commit is contained in:
		
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -39,7 +39,18 @@ async fn main(_spawner: Spawner) {
 | 
			
		||||
    // Should print 400kHz for initialization
 | 
			
		||||
    info!("Configured clock: {}", sdmmc.clock().0);
 | 
			
		||||
 | 
			
		||||
    unwrap!(sdmmc.init_card(mhz(48)).await);
 | 
			
		||||
    let mut err = None;
 | 
			
		||||
    loop {
 | 
			
		||||
        match sdmmc.init_card(mhz(24)).await {
 | 
			
		||||
            Ok(_) => break,
 | 
			
		||||
            Err(e) => {
 | 
			
		||||
                if err != Some(e) {
 | 
			
		||||
                    info!("waiting for card error, retrying: {:?}", e);
 | 
			
		||||
                    err = Some(e);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let card = unwrap!(sdmmc.card());
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
 | 
			
		||||
 | 
			
		||||
[features]
 | 
			
		||||
stm32f103c8 = ["embassy-stm32/stm32f103c8"]     # Blue Pill
 | 
			
		||||
stm32f429zi = ["embassy-stm32/stm32f429zi"]     # Nucleo
 | 
			
		||||
stm32f429zi = ["embassy-stm32/stm32f429zi", "sdmmc"]     # Nucleo
 | 
			
		||||
stm32g071rb = ["embassy-stm32/stm32g071rb"]     # Nucleo
 | 
			
		||||
stm32c031c6 = ["embassy-stm32/stm32c031c6"]     # Nucleo
 | 
			
		||||
stm32g491re = ["embassy-stm32/stm32g491re"]     # Nucleo
 | 
			
		||||
@@ -15,6 +15,8 @@ stm32wb55rg = ["embassy-stm32/stm32wb55rg"]     # Nucleo
 | 
			
		||||
stm32h563zi = ["embassy-stm32/stm32h563zi"]     # Nucleo
 | 
			
		||||
stm32u585ai = ["embassy-stm32/stm32u585ai"]     # IoT board
 | 
			
		||||
 | 
			
		||||
sdmmc = []
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
 | 
			
		||||
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
 | 
			
		||||
@@ -31,6 +33,45 @@ embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" }
 | 
			
		||||
embedded-hal-async = { version = "=0.2.0-alpha.1" }
 | 
			
		||||
panic-probe = { version = "0.3.0", features = ["print-defmt"] }
 | 
			
		||||
 | 
			
		||||
# BEGIN TESTS
 | 
			
		||||
# Generated by gen_test.py. DO NOT EDIT.
 | 
			
		||||
[[bin]]
 | 
			
		||||
name = "gpio"
 | 
			
		||||
path = "src/bin/gpio.rs"
 | 
			
		||||
required-features = []
 | 
			
		||||
 | 
			
		||||
[[bin]]
 | 
			
		||||
name = "sdmmc"
 | 
			
		||||
path = "src/bin/sdmmc.rs"
 | 
			
		||||
required-features = [ "sdmmc",]
 | 
			
		||||
 | 
			
		||||
[[bin]]
 | 
			
		||||
name = "spi"
 | 
			
		||||
path = "src/bin/spi.rs"
 | 
			
		||||
required-features = []
 | 
			
		||||
 | 
			
		||||
[[bin]]
 | 
			
		||||
name = "spi_dma"
 | 
			
		||||
path = "src/bin/spi_dma.rs"
 | 
			
		||||
required-features = []
 | 
			
		||||
 | 
			
		||||
[[bin]]
 | 
			
		||||
name = "timer"
 | 
			
		||||
path = "src/bin/timer.rs"
 | 
			
		||||
required-features = []
 | 
			
		||||
 | 
			
		||||
[[bin]]
 | 
			
		||||
name = "usart"
 | 
			
		||||
path = "src/bin/usart.rs"
 | 
			
		||||
required-features = []
 | 
			
		||||
 | 
			
		||||
[[bin]]
 | 
			
		||||
name = "usart_dma"
 | 
			
		||||
path = "src/bin/usart_dma.rs"
 | 
			
		||||
required-features = []
 | 
			
		||||
 | 
			
		||||
# END TESTS
 | 
			
		||||
 | 
			
		||||
[profile.dev]
 | 
			
		||||
debug = 2
 | 
			
		||||
debug-assertions = true
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										44
									
								
								tests/stm32/gen_test.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								tests/stm32/gen_test.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
			
		||||
import os
 | 
			
		||||
import toml
 | 
			
		||||
from glob import glob
 | 
			
		||||
 | 
			
		||||
abspath = os.path.abspath(__file__)
 | 
			
		||||
dname = os.path.dirname(abspath)
 | 
			
		||||
os.chdir(dname)
 | 
			
		||||
 | 
			
		||||
# ======= load test list
 | 
			
		||||
tests = {}
 | 
			
		||||
for f in sorted(glob('./src/bin/*.rs')):
 | 
			
		||||
    name = os.path.splitext(os.path.basename(f))[0]
 | 
			
		||||
    features = []
 | 
			
		||||
    with open(f, 'r') as f:
 | 
			
		||||
        for line in f:
 | 
			
		||||
            if line.startswith('// required-features:'):
 | 
			
		||||
                features = line.split(':', 2)[1].strip().split(',')
 | 
			
		||||
 | 
			
		||||
    tests[name] = features
 | 
			
		||||
 | 
			
		||||
# ========= Update Cargo.toml
 | 
			
		||||
 | 
			
		||||
things = {
 | 
			
		||||
    'bin': [
 | 
			
		||||
        {
 | 
			
		||||
            'name': f'{name}',
 | 
			
		||||
            'path': f'src/bin/{name}.rs',
 | 
			
		||||
            'required-features': features,
 | 
			
		||||
        }
 | 
			
		||||
        for name, features in tests.items()
 | 
			
		||||
    ]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SEPARATOR_START = '# BEGIN TESTS\n'
 | 
			
		||||
SEPARATOR_END = '# END TESTS\n'
 | 
			
		||||
HELP = '# Generated by gen_test.py. DO NOT EDIT.\n'
 | 
			
		||||
with open('Cargo.toml', 'r') as f:
 | 
			
		||||
    data = f.read()
 | 
			
		||||
before, data = data.split(SEPARATOR_START, maxsplit=1)
 | 
			
		||||
_, after = data.split(SEPARATOR_END, maxsplit=1)
 | 
			
		||||
data = before + SEPARATOR_START + HELP + \
 | 
			
		||||
    toml.dumps(things) + SEPARATOR_END + after
 | 
			
		||||
with open('Cargo.toml', 'w') as f:
 | 
			
		||||
    f.write(data)
 | 
			
		||||
							
								
								
									
										148
									
								
								tests/stm32/src/bin/sdmmc.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								tests/stm32/src/bin/sdmmc.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,148 @@
 | 
			
		||||
// required-features: sdmmc
 | 
			
		||||
#![no_std]
 | 
			
		||||
#![no_main]
 | 
			
		||||
#![feature(type_alias_impl_trait)]
 | 
			
		||||
 | 
			
		||||
use defmt::{assert_eq, *};
 | 
			
		||||
use embassy_executor::Spawner;
 | 
			
		||||
use embassy_stm32::sdmmc::{DataBlock, Sdmmc};
 | 
			
		||||
use embassy_stm32::time::mhz;
 | 
			
		||||
use embassy_stm32::{interrupt, Config};
 | 
			
		||||
use {defmt_rtt as _, panic_probe as _};
 | 
			
		||||
 | 
			
		||||
#[embassy_executor::main]
 | 
			
		||||
async fn main(_spawner: Spawner) {
 | 
			
		||||
    info!("Hello World!");
 | 
			
		||||
 | 
			
		||||
    let mut config = Config::default();
 | 
			
		||||
    config.rcc.sys_ck = Some(mhz(48));
 | 
			
		||||
    config.rcc.pll48 = true;
 | 
			
		||||
    let p = embassy_stm32::init(config);
 | 
			
		||||
 | 
			
		||||
    #[cfg(feature = "stm32f429zi")]
 | 
			
		||||
    let (mut sdmmc, mut irq, mut dma, mut clk, mut cmd, mut d0, mut d1, mut d2, mut d3) = (
 | 
			
		||||
        p.SDIO,
 | 
			
		||||
        interrupt::take!(SDIO),
 | 
			
		||||
        p.DMA2_CH3,
 | 
			
		||||
        p.PC12,
 | 
			
		||||
        p.PD2,
 | 
			
		||||
        p.PC8,
 | 
			
		||||
        p.PC9,
 | 
			
		||||
        p.PC10,
 | 
			
		||||
        p.PC11,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Arbitrary block index
 | 
			
		||||
    let block_idx = 16;
 | 
			
		||||
 | 
			
		||||
    let mut pattern1 = DataBlock([0u8; 512]);
 | 
			
		||||
    let mut pattern2 = DataBlock([0u8; 512]);
 | 
			
		||||
    for i in 0..512 {
 | 
			
		||||
        pattern1[i] = i as u8;
 | 
			
		||||
        pattern2[i] = !i as u8;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let mut block = DataBlock([0u8; 512]);
 | 
			
		||||
 | 
			
		||||
    // ======== Try 4bit. ==============
 | 
			
		||||
    info!("initializing in 4-bit mode...");
 | 
			
		||||
    let mut s = Sdmmc::new_4bit(
 | 
			
		||||
        &mut sdmmc,
 | 
			
		||||
        &mut irq,
 | 
			
		||||
        &mut dma,
 | 
			
		||||
        &mut clk,
 | 
			
		||||
        &mut cmd,
 | 
			
		||||
        &mut d0,
 | 
			
		||||
        &mut d1,
 | 
			
		||||
        &mut d2,
 | 
			
		||||
        &mut d3,
 | 
			
		||||
        Default::default(),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    let mut err = None;
 | 
			
		||||
    loop {
 | 
			
		||||
        match s.init_card(mhz(24)).await {
 | 
			
		||||
            Ok(_) => break,
 | 
			
		||||
            Err(e) => {
 | 
			
		||||
                if err != Some(e) {
 | 
			
		||||
                    info!("waiting for card: {:?}", e);
 | 
			
		||||
                    err = Some(e);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let card = unwrap!(s.card());
 | 
			
		||||
 | 
			
		||||
    info!("Card: {:#?}", Debug2Format(card));
 | 
			
		||||
    info!("Clock: {}", s.clock());
 | 
			
		||||
 | 
			
		||||
    info!("writing pattern1...");
 | 
			
		||||
    s.write_block(block_idx, &pattern1).await.unwrap();
 | 
			
		||||
 | 
			
		||||
    info!("reading...");
 | 
			
		||||
    s.read_block(block_idx, &mut block).await.unwrap();
 | 
			
		||||
    assert_eq!(block, pattern1);
 | 
			
		||||
 | 
			
		||||
    info!("writing pattern2...");
 | 
			
		||||
    s.write_block(block_idx, &pattern2).await.unwrap();
 | 
			
		||||
 | 
			
		||||
    info!("reading...");
 | 
			
		||||
    s.read_block(block_idx, &mut block).await.unwrap();
 | 
			
		||||
    assert_eq!(block, pattern2);
 | 
			
		||||
 | 
			
		||||
    drop(s);
 | 
			
		||||
 | 
			
		||||
    // ======== Try 1bit. ==============
 | 
			
		||||
    info!("initializing in 1-bit mode...");
 | 
			
		||||
    let mut s = Sdmmc::new_1bit(
 | 
			
		||||
        &mut sdmmc,
 | 
			
		||||
        &mut irq,
 | 
			
		||||
        &mut dma,
 | 
			
		||||
        &mut clk,
 | 
			
		||||
        &mut cmd,
 | 
			
		||||
        &mut d0,
 | 
			
		||||
        Default::default(),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    let mut err = None;
 | 
			
		||||
    loop {
 | 
			
		||||
        match s.init_card(mhz(24)).await {
 | 
			
		||||
            Ok(_) => break,
 | 
			
		||||
            Err(e) => {
 | 
			
		||||
                if err != Some(e) {
 | 
			
		||||
                    info!("waiting for card: {:?}", e);
 | 
			
		||||
                    err = Some(e);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let card = unwrap!(s.card());
 | 
			
		||||
 | 
			
		||||
    info!("Card: {:#?}", Debug2Format(card));
 | 
			
		||||
    info!("Clock: {}", s.clock());
 | 
			
		||||
 | 
			
		||||
    info!("reading pattern2 written in 4bit mode...");
 | 
			
		||||
    s.read_block(block_idx, &mut block).await.unwrap();
 | 
			
		||||
    assert_eq!(block, pattern2);
 | 
			
		||||
 | 
			
		||||
    info!("writing pattern1...");
 | 
			
		||||
    s.write_block(block_idx, &pattern1).await.unwrap();
 | 
			
		||||
 | 
			
		||||
    info!("reading...");
 | 
			
		||||
    s.read_block(block_idx, &mut block).await.unwrap();
 | 
			
		||||
    assert_eq!(block, pattern1);
 | 
			
		||||
 | 
			
		||||
    info!("writing pattern2...");
 | 
			
		||||
    s.write_block(block_idx, &pattern2).await.unwrap();
 | 
			
		||||
 | 
			
		||||
    info!("reading...");
 | 
			
		||||
    s.read_block(block_idx, &mut block).await.unwrap();
 | 
			
		||||
    assert_eq!(block, pattern2);
 | 
			
		||||
 | 
			
		||||
    drop(s);
 | 
			
		||||
 | 
			
		||||
    info!("Test OK");
 | 
			
		||||
    cortex_m::asm::bkpt();
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user