Skip to content

Instantly share code, notes, and snippets.

@flaminggoat
Created March 3, 2023 21:23
Show Gist options
  • Save flaminggoat/6106ef29de5df367fb907cf05c363c17 to your computer and use it in GitHub Desktop.
Save flaminggoat/6106ef29de5df367fb907cf05c363c17 to your computer and use it in GitHub Desktop.
ESP32 SD card access from Rust using esp_idf_sys
use std::io::{BufWriter, Write};
use std::ptr::{null, null_mut};
use std::time::Instant;
use esp_idf_sys as _; // If using the `binstart` feature of `esp-idf-sys`, always keep this module imported
use esp_idf_sys::c_types::{c_int, c_void};
use std::fs::{self, File};
fn main() {
// It is necessary to call this function once. Otherwise some patches to the runtime
// implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
esp_idf_sys::link_patches();
const SDMMC_HOST_FLAG_1BIT: u32 = 1 << 0; // host supports 1-line SD and MMC protocol
const SDMMC_HOST_FLAG_4BIT: u32 = 1 << 1; // host supports 4-line SD and MMC protocol
const SDMMC_HOST_FLAG_8BIT: u32 = 1 << 2; // host supports 8-line MMC protocol
const SDMMC_HOST_FLAG_SPI: u32 = 1 << 3; // host supports SPI protocol
const SDMMC_HOST_FLAG_DDR: u32 = 1 << 4; // host supports DDR mode for SD/MMC
const SDMMC_HOST_FLAG_DEINIT_ARG: u32 = 1 << 5; // host `deinit` function called with the slot argument
const SDMMC_FREQ_DEFAULT: c_int = 20000; // SD/MMC Default speed (limited by clock divider)
const SDMMC_FREQ_HIGHSPEED: c_int = 40000; // SD High speed (limited by clock divider)
const SDMMC_FREQ_PROBING: c_int = 400; // SD/MMC probing speed
const SDMMC_FREQ_52M: c_int = 52000; // MMC 52MHz speed
const SDMMC_FREQ_26M: c_int = 26000; // MMC 26MHz speed
let host = esp_idf_sys::sdmmc_host_t {
flags: SDMMC_HOST_FLAG_4BIT | SDMMC_HOST_FLAG_1BIT,
slot: 1,
max_freq_khz: SDMMC_FREQ_HIGHSPEED,
io_voltage: 3.3,
init: Some(esp_idf_sys::sdmmc_host_init),
set_bus_width: Some(esp_idf_sys::sdmmc_host_set_bus_width),
get_bus_width: Some(esp_idf_sys::sdmmc_host_get_slot_width),
set_bus_ddr_mode: Some(esp_idf_sys::sdmmc_host_set_bus_ddr_mode),
set_card_clk: Some(esp_idf_sys::sdmmc_host_set_card_clk),
do_transaction: Some(esp_idf_sys::sdmmc_host_do_transaction),
io_int_enable: Some(esp_idf_sys::sdmmc_host_io_int_enable),
io_int_wait: Some(esp_idf_sys::sdmmc_host_io_int_wait),
command_timeout_ms: 0,
__bindgen_anon_1: esp_idf_sys::sdmmc_host_t__bindgen_ty_1 {
deinit: Some(esp_idf_sys::sdmmc_host_deinit),
},
};
const SDMMC_SLOT_NO_CD: esp_idf_sys::gpio_num_t = esp_idf_sys::gpio_num_t_GPIO_NUM_NC; // indicates that card detect line is not used
const SDMMC_SLOT_NO_WP: esp_idf_sys::gpio_num_t = esp_idf_sys::gpio_num_t_GPIO_NUM_NC; // indicates that write protect line is not used
const SDMMC_SLOT_WIDTH_DEFAULT: u8 = 0; // use the maximum possible width for the slot
let mut slot = esp_idf_sys::sdmmc_slot_config_t {
__bindgen_anon_1: esp_idf_sys::sdmmc_slot_config_t__bindgen_ty_1 {
gpio_cd: SDMMC_SLOT_NO_CD,
},
__bindgen_anon_2: esp_idf_sys::sdmmc_slot_config_t__bindgen_ty_2 {
gpio_wp: SDMMC_SLOT_NO_WP,
},
width: 1, // esp cam should support 4 but not working for some reason
flags: 0,
};
let slot_ptr: *const esp_idf_sys::sdmmc_slot_config_t = &slot;
let mount_config = esp_idf_sys::esp_vfs_fat_sdmmc_mount_config_t {
format_if_mount_failed: true,
max_files: 5,
allocation_unit_size: 16 * 1024,
};
let mut card: *mut esp_idf_sys::sdmmc_card_t = null_mut();
let card_ptr: *mut *mut esp_idf_sys::sdmmc_card_t = &mut card;
const MOUNT_POINT: &[u8] = b"/sdcard\0";
println!("Initialising SD{}", host.slot);
let card_mount_result = unsafe {
esp_idf_sys::esp_vfs_fat_sdmmc_mount(
MOUNT_POINT.as_ptr() as *const i8,
&host,
slot_ptr as *const c_void,
&mount_config,
card_ptr,
)
};
println!("SD init result {}", card_mount_result);
if card_mount_result != 0 {
return;
}
let paths = fs::read_dir("/sdcard").unwrap();
for path in paths {
println!("Name: {}", path.unwrap().path().display())
}
let mut file = BufWriter::new(File::create("/sdcard/test.bin").unwrap());
let buf_size = 1024;
let buf_count = 100;
let buf = vec![0xaa_u8; buf_size];
let start_write = Instant::now();
for _ in 0..buf_count {
file.write_all(&buf).unwrap();
}
println!(
"Wrote {} bytes. {}KiB/s",
(buf_size * buf_count),
((buf_size * buf_count * 1000) / start_write.elapsed().as_millis() as usize) / 1024
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment