{"id":25932396,"url":"https://github.com/secfurry/inky-frame","last_synced_at":"2026-06-06T12:31:26.986Z","repository":{"id":279872574,"uuid":"940236348","full_name":"secfurry/inky-frame","owner":"secfurry","description":"Driver and protocol library for InkyFrame devices with peripheral support","archived":false,"fork":false,"pushed_at":"2026-02-12T01:01:39.000Z","size":227,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-05-24T19:05:27.356Z","etag":null,"topics":["eink","embedded","embedded-rust","fat32","inkyframe","pico","pinorami","rp2040","rp2040w","rust","rust-packages","sdcard"],"latest_commit_sha":null,"homepage":"https://docs.rs/inky-frame/latest/inky_frame/","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/secfurry.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-02-27T20:46:10.000Z","updated_at":"2026-02-12T01:01:43.000Z","dependencies_parsed_at":null,"dependency_job_id":"d8adeebe-c17e-43bb-b0b1-9a734dab3d3b","html_url":"https://github.com/secfurry/inky-frame","commit_stats":null,"previous_names":["secfurry/inky-frame"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/secfurry/inky-frame","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/secfurry%2Finky-frame","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/secfurry%2Finky-frame/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/secfurry%2Finky-frame/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/secfurry%2Finky-frame/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/secfurry","download_url":"https://codeload.github.com/secfurry/inky-frame/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/secfurry%2Finky-frame/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33983046,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-06T02:00:07.033Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["eink","embedded","embedded-rust","fat32","inkyframe","pico","pinorami","rp2040","rp2040w","rust","rust-packages","sdcard"],"created_at":"2025-03-04T00:37:21.331Z","updated_at":"2026-06-06T12:31:26.980Z","avatar_url":"https://github.com/secfurry.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Inky-Frame\n\nDrivers and Utilities for Pimoroni InkyFrame Devices\n\nRust library with helpers and API functions to design programs for InkyFrame\ndevices or take advantage of any of the supplied embedded device utilities.\n\n## InkyFrame Devices\n\n- [Inky Frame 4](https://shop.pimoroni.com/products/inky-frame-4?variant=40443825094739)\n- [Inky Frame 5.7](https://shop.pimoroni.com/products/inky-frame-5-7?variant=40048398958675)\n\nThe Inky Frame 7.3 version uses different methods to update the display and set\ncolor information and is not directly supported. _(I am open to pull requests to_\n_add support :3)_\n\n_While the 5.7 model is supported, I don't have one on-hand to test. Specifically,_\n_the Display buffer size; it might need to be adjusted._\n\n### Supported Devices\n\nSupport for devices matches the underlying [RPSP support library](https://github.com/secfurry/rpsp?tab=readme-ov-file#supported-devices).\nView the [RPSP README](https://github.com/secfurry/rpsp/blob/main/README.md) for more information.\n\n## Exposed Libraries\n\nWhile this library is written for InkyFrame devices, the helper utilities contained\nin this library can be used with any embedded device.\n\n- UC8159 eInk SPI Driver with 7-Color Dithering\n- SD Card SPI Driver\n- FAT Filesystem Driver (with long filename support!)\n- TGA Image Parser\n- PCF85063A RTC I2C Driver\n\n## Note\n\nYou'll need to make sure you have the `flip-link` linker installed before compiling.\nTo do this, use the command `cargo install flip-link` to install it.\n\n### Additional Cargo Configuration\n\nFor best results, create a `.cargo/config.toml` file in your project root directory\nand specify somthing like this:\n\n```toml\n[target.'cfg(all(target_arch = \"arm\", target_os = \"none\"))']\nrustflags  = [\n    \"-C\", \"linker=flip-link\",\n    \"-C\", \"link-arg=--nmagic\",\n    \"-C\", \"link-arg=-Tlink.x\",\n    \"-Z\", \"trap-unreachable=no\",\n    \"-C\", \"no-vectorize-loops\",\n]\n\n[build]\ntarget    = \"thumbv6m-none-eabi\"\n```\n\nRequires the `nightly` version of the compiler to use `\"-Z\", \"trap-unreachable=no\",`\nand can be removed, but will increase binary size slightly.\n\nExtra bonus points if you add:\n\n```toml\nrunner    = \"probe-rs run --chip RP2040\"\n```\n\nUnder the `rustflags` option. This allows you to flash the firmware on the device\ndirectly from `cargo run`. (Pico debug probe probe and `probe-rs` required. Can be\ninstalled using `cargo install probe-rs-tools`. Pico probe can be made from another\nPico! [see here](https://mcuoneclipse.com/2022/09/17/picoprobe-using-the-raspberry-pi-pico-as-debug-probe/)).\n\nLastly, these are the recommended profile settings for best program results. These\ngo inside the `Cargo.toml` file in the project root directory.\n\n```toml\n[profile.dev]\ndebug            = 2\nstrip            = false\nopt-level        = 3\nincremental      = false\ncodegen-units    = 1\noverflow-checks  = true\ndebug-assertions = true\n\n[profile.release]\nlto              = \"fat\"\npanic            = \"abort\"\ndebug            = false\nstrip            = true\nopt-level        = 3\nincremental      = false\ncodegen-units    = 1\noverflow-checks  = false\ndebug-assertions = false\n```\n\n## Usage\n\nTo use this library, just import `inky_frame::InkyBoard` and call `InkyBoard::get()`.\nOn the first call, the device and it's clocks will be initialized and setup fully.\n\nThe configuration is automatic and uses the ROSC as the system clock, disables\nthe XOSC and PLLs and allows for DORMANT sleep, for maximum power savings.\n\n_This is similar to the RPSP `Board::get()` setup and init behavior. The `InkyBoard`_\n_struct actually has `Deref` for the `Board` struct and can be used as a drop-in replacement._\n\nTo supply main, you must setup the `main` function with the `#[rpsp::entry]` macro,\nwhich will setup the locks and properly redirect execution to the selected function.\n\nBasic programs should look something like this:\n\n```rust\n#![no_std]\n#![no_main]\n\n#[rpsp::entry]\nfn main() -\u003e ! {\n    // do stuff here\n}\n```\n\nIf you're not using something like `defmt`, _(which is not included by default)_\nyou'll need a `panic_handler`. The example below is a pretty basic one that just\nloops the CPU:\n\n```rust\n#[panic_handler]\nfn panic(_p: \u0026core::panic::PanicInfo\u003c'_\u003e) -\u003e ! {\n    loop {}\n}\n```\n\nFor the below examples, the `panic_handler` is omitted, so if you want to use\nthese, you'll need to add it in order for it to compile.\n\n## Inky Examples\n\n### InkyBoard\n\nThe `InkyBoard` struct exposes many helper functions to use the default peripherals\non the board.\n\n```rust\nlet i = InkyBoard::get();\n\ni.sync_rtc_to_pcf(); // Same as the Python function \"pico_rtc_to_pcf\"\ni.sync_pcf_to_rtc(); // Same as the Python function \"pcf_to_pico_rtc\"\n\n// Same as the Python function \"sleep_for\"\n// THIS IS IN SECONDS!! Instead of minutes\n// Requires unsafe since it will poweroff the Pico\nunsafe { i.deep_sleep(60) };\n\n// Same as the Python function \"turn_off\"\n// Requires unsafe since it will poweroff the Pico\nunsafe { i.power_off() };\n\nlet w = i.wake_reason(); // Receives the reason the Pico was woken.\n\nw.wake_from_rtc(); // Same as the Python function \"woken_by_rtc\"\nw.wake_from_ext(); // Same as the Python function \"woken_by_ext_trigger\"\nw.wake_from_button(); // Same as the Python function \"woken_by_button\"\n\nlet pcf = i.pcf(); // Pointer to the PCF85063A RTC\n\npcf.set_byte(1).unwrap(); // Exposes the free 1-byte register of the PCF\nlet _ = pcf.get_byte().unwrap();\n\n// Pointer to the I2C bus\n// This is the bus the PCF is running on.\nlet i2c_bus = i.i2c_bus();\n\n// Pointer to the SPI bus\n// This is the bus the SDCard and Inky are running on.\n// The bus is not initialized until this is first called.\nlet spi_bus = i.spi_bus();\n\n// Create the SDCard and wrap it with the FAT filesystem driver\n// Will initialize the SPI bus.\n// This is not owned by the \"InkyBoard\" struct, so multiple calls to this will\n// attempt to recreate it.\nlet sd = i.sd_card();\n```\n\n### Buttons\n\n```rust\nuse inky_frame::{InkyBoard, buttons};\n\n#[rpsp::entry]\nfn main() -\u003e ! {\n    let p = InkyBoard::get();\n    let b = p.buttons(); // Pointer to Buttons, owned by 'p'.\n    // Button data must be manually refreshed by calling \"b.read()\".\n    // On the first read (done automatically), the pressed buttons will be\n    // the same as the Wake Reason.\n\n    // Is button 'A' pressed?\n    if b.button_a() {\n        // Do stuff..\n    }\n    // Is button 'B' pressed?\n    if b.button_b() {\n        // Do stuff..\n    }\n    // Is button 'C' pressed?\n    if b.button_c() {\n        // Do stuff..\n    }\n    // Is button 'E' pressed?\n    if b.button_d() {\n        // Do stuff..\n    }\n    // Is button 'E' pressed?\n    if b.button_e() {\n        // Do stuff..\n    }\n\n    // Returns an enum of what was pressed. This also covers external triggers\n    // like the RTC and External Trigger.\n    let button = b.pressed();\n\n    // Another way to read the button ShiftRegister\n    // Returns true if a Button or the External Trigger was the cause.\n    let b = b.read_pressed();\n\n    // Access a reference to the ShiftRegister\n    // The ShiftRegister can be cloned if ownership is needed.\n    let sr = b.shift_register();\n\n    // If you need ownership of the Buttons struct, you can call\n    let ob = buttons();\n    // Has the same functions as the Buttons reference.\n\n    // Need this at the end since it's a '!' function.\n    loop {}\n}\n```\n\n### Leds\n\n```rust\nuse inky_frame::{InkyBoard, leds};\n\n#[rpsp::entry]\nfn main() -\u003e ! {\n    let p = InkyBoard::get();\n    let l = p.leds(); // Pointer to Leds, owned by 'p'.\n\n    l.all_on(); // Turn all LEDs on.\n    l.all_off(); // Turn all LEDs off.\n\n    l.a.on(); // Set Button 'A' LED on.\n    l.b.on(); // Set Button 'B' LED on.\n    l.c.on(); // Set Button 'C' LED on.\n    l.d.on(); // Set Button 'D' LED on.\n    l.e.on(); // Set Button 'E' LED on.\n\n    l.network.on(); // Set the Network (Top Right) LED on.\n    l.activity.on(); // Set the Activity (Top Left) LED on.\n\n    // The LEDs are PWM LEDs, which means their brightness can be adjusted also.\n    l.all_brightness(50); // Set brightness of all LEDs to 50%.\n\n    l.a.brightness(25); // Set Button 'A' LED brightness to 25%.\n\n    // Similar to the Button struct, if you need ownership of the LEDs struct, you\n    // can call\n    let ol = leds();\n    // Has the same functions as the LEDs reference.\n\n    // Need this at the end since it's a '!' function.\n    loop {}\n}\n```\n\n### PCF RTC\n\n```rust\nuse inky_frame::InkyBoard;\n\nuse rpsp::clock::AlarmConfig;\nuse rpsp::time::{Month, Time, Weekday};\n\n#[rpsp::entry]\nfn main() -\u003e ! {\n    let p = InkyBoard::get();\n    let r = p.pcf(); // Pointer to the PCF RTC, owned by 'p'.\n\n    let now = r.now().unwrap(); // Read the PCF's current time.\n\n    // Create new Time struct.\n    let dt = Time::new(2025, Month::March, 1, 15, 30, 0, Weekday::Tuesday);\n\n    // Set the PCF's current time\n    r.set_time(dt).unwrap();\n\n    // Set the PCF RTC Alarm\n    r.set_alarm(AlarmConfig::new().hour(16).mins(0).secs(0)).unwrap();\n    r.set_alarm_interrupt(true).unwrap();\n\n    // Use the free PCF 1-byte register\n    // Set it\n    r.set_byte(190).unwrap();\n    // Retrive it\n    let _ = r.get_byte();\n\n    // Need this at the end since it's a '!' function.\n    loop {}\n}\n```\n\n### SD Card and FAT File System\n\n```rust\nuse inky_frame::fs::Storage;\nuse inky_frame::sd::Card;\nuse inky_frame::InkyBoard;\n\nuse rpsp::pin::PinID;\n\n#[rpsp::entry]\nfn main() -\u003e ! {\n    let p = InkyBoard::get();\n\n    // There's two ways to make the SD Card. We'll use the more complex way.\n    let mut sd = Storage::new(Card::new(\u0026p, PinID::Pin22, p.spi_bus()))\n    // let mut sd = p.sd_card(); // Easy way.\n\n    let mut r = sd.root().unwrap(); // Get the first Volume on the SD Card.\n\n    // Open the \"root\" directory (/)\n    let root = r.dir_root();\n\n    // List the entries in the root directory.\n    root.list().unwrap().iter(|x| {\n        // Called on each entry..\n        if x.is_file() {\n            debug!(\"Found file {}!\", x.name());\n            debug!(\"Size is {}b\", x.size());\n        } else {\n            debug!(\"Found directory {}!\", x.name());\n        }\n    });\n\n    // Open a file under the \"root\" directory\n    let mut my_file_1 = root.file(\"test_file1.txt\", false).unwrap();\n    my_file_1.close();\n\n\n    // Open a file recursively (like an OS)\n    let mut f = r.open(\"/my_dir1/my_dir2/my_filename.txt\").unwrap();\n\n    // Read some data from it\n    let mut buf = [0u8; 32];\n    let n = f.read(\u0026mut buf).unwrap();\n    debug!(\"Read {n} bytes: [:?]\", \u0026buf[0..n]);\n\n    // Create a new file\n    let mut my_file_2 = r.file_create(\"/my_dir3/testing_dir2/file.txt\").unwrap();\n    // This will create the directory structure if it does not exist.\n    // Write to the file\n    let _ = my_file_2.write(\"Hello There!\\n\".as_bytes()).unwrap();\n    // Flush out the data to the card.\n    my_file_2.close();\n\n    // Need this at the end since it's a '!' function.\n    loop {}\n}\n```\n\n### Inky and TGA Image Parsing\n\n```rust\nuse inky_frame::frame::tga::TgaParser;\nuse inky_frame::frame::{Color, Inky, InkyPins, InkyRotation, RGB};\nuse inky_frame::fs::Storage;\nuse inky_frame::sd::Card;\nuse inky_frame::InkyBoard;\n\n#[rpsp::entry]\nfn main() -\u003e ! {\n    let p = InkyBoard::get();\n\n    // We're gonna use the InkyFrame4 for this example.\n    // The signature of the \"Inky\" struct is\n    //   pub struct Inky\u003c'a, const B: usize, const W: u16, const H: u16\u003e {}\n    // Where:\n    // - B is the buffer size (InkyFrame4 is 128_000)\n    // - W is the screen width (InkyFrame4 is 640)\n    // - H is the screen height (InkyFrame4 is 400)\n    //\n    // The alias \"Inky4\" can be used for convienence. It's singature is:\n    //   pub type Inky4\u003c'a\u003e = Inky\u003c'a, 128_000, 640u16, 400u16\u003e\n    //\n    // 'InkyPins::inky_frame4()' describes the default SPI and Busy pin\n    // configuration. When using \"new\" the SPI details are ignored as we're\n    // not creating the SPI bus.\n    let mut dis = Inky4::new(\u0026p, p.spi_bus(), InkyPins::inky_frame4()).unwrap();\n\n    // Get the SD Card\n    let mut sd = p.sd_card();\n    let mut r = sd.root().unwrap(); // Get the first Volume on the SD Card.\n\n    dis.set_fill(Color::Green); // Fill the entire screen with Green.\n\n    // Fill a rectangle from 200,50 to 300,100 with Blue.\n    for x in 200..300 {\n        for y in 50..100 {\n            dis.set_pixel(x, y, Color::Blue);\n        }\n    }\n\n    // Fill a rectangle from 400,100 to 500,200 with \"#C783E8\".\n    // Dithering will be applied to the color to make it appear as close as\n    // possible to the real color.\n    for x in 400..500 {\n        for y in 100..200 {\n            dis.set_pixel_color(x, y, RGB::rgb(199, 131, 232));\n        }\n    }\n\n    // Update the display to show the changes.\n    // This function blocks until the refresh is done.\n    dis.update();\n\n    // The 'set_with' command will run function with itself as the function\n    // argument to prevent any mutable contention issues. This function can\n    // pass back any errors with \"?\".\n    //\n    // Also is good for limiting resource usage inside the closure.\n    dis.set_with(|x| {\n        let mut f = r.open(\"/my_image1.tga\").unwrap();\n        // Load the image into the TGA parser.\n        let img = TgaParser::new(\u0026mut f)?;\n        // Set the image at 50,50\n        x.set_image(50, 50, img)\n    }).unwrap();\n\n    // TGA supports transparency and any transparent pixels will be skipped to\n    // allow for transparent overlapping images to be loaded.\n    dis.set_with(|x| {\n        let mut f = r.open(\"/my_image2.tga\").unwrap();\n        // Load the image into the TGA parser and set the image at 0,0\n        x.set_image(0, 0, TgaParser::new(\u0026mut f)?)\n    }).unwrap();\n\n    // Update the display\n    dis.update();\n\n    // Need this at the end since it's a '!' function.\n    loop {}\n}\n```\n\n### Low Power Shutoff on Battery\n\nIf the JST connector is used, the Frame can power off the Pico and wake it\nup when a button is pressed or by the PCF RTC alarm, allowing for super low\npower usage.\n\n```rust\nuse inky_frame::InkyBoard;\n\n#[rpsp::entry]\nfn main() -\u003e ! {\n    let p = InkyBoard::get();\n\n    unsafe { p.deep_sleep(30) };\n    // This will set the PCF RTC alarm for 30 seconds from now and power off\n    // the Pico if the JST Battery connector is used. After 30 seconds, the\n    // Pico will boot back up (like a reboot).\n    //\n    // If not using the JST Battery connector, this will just wait 30 seconds\n    // instead, then return.\n\n    unsafe { p.power_off() };\n    // Directly power off the Pico.\n    //\n    // Code after this will not run unless the JST Battery connector is not being\n    // used.\n\n    debug!(\"Not on battery!\");\n\n    // Need this at the end since it's a '!' function.\n    loop {}\n}\n```\n\n## Standard Examples\n\nThese are taken [from here](https://github.com/secfurry/rpsp/blob/main/README.md),\nbut are modified to show the drop-in replacement of the `InkyBoard` struct.\n\n### GPIO\n\nControl Pin output:\n\n```rust\nuse inky_frame::InkyBoard;\n\nuse rpsp::pin::PinID;\n\n#[rpsp::entry]\nfn main() -\u003e ! {\n    let p = InkyBoard::get();\n    let my_pin = p.pin(PinID::Pin5);\n    // You could also do..\n    // let my_pin = Pin::get(\u0026p, PinID::Pin5);\n\n    // Set High\n    my_pin.high();\n\n    // Set Low\n    my_pin.low();\n\n    // Need this at the end since it's a '!' function.\n    loop {}\n}\n```\n\nRead Pin output:\n\n```rust\nuse inky_frame::InkyBoard;\n\nuse rpsp::pin::PinID;\n\n#[rpsp::entry]\nfn main() -\u003e ! {\n    let p = InkyBoard::get();\n    let my_pin = p.pin(PinID::Pin6).into_input();\n\n    // Set High\n    if my_pin.is_high() {\n        // Do stuff..\n    }\n\n    if my_pin.is_low() {\n        // Do other stuff..\n    }\n\n    // Need this at the end since it's a '!' function.\n    loop {}\n}\n```\n\n### UART\n\n```rust\nuse inky_frame::InkyBoard;\n\nuse rpsp::pin::PinID;\nuse rpsp::uart::{Uart, UartConfig, UartDev};\n\n#[rpsp::entry]\nfn main() -\u003e ! {\n    let p = InkyBoard::get();\n\n    // DEFAULT_BAUDRATE is 115,200\n    let mut u = Uart::new(\n        \u0026p,\n        UartConfig::DEFAULT_BAUDRATE,\n        UartConfig::new(), // Default is NoParity, 8 Bits, 1 Stop Bit.\n        UartDev::new(PinID::Pin0, PinID::Pin1).unwrap(),\n        // ^ This can error since not all Pinouts are a valid UART set.\n        // You can also use..\n        // (PinID::Pin0, PinID::Pin1).into()\n    ).unwrap();\n\n    let _ = u.write(\"HEY THERE\\n\".as_bytes()).unwrap();\n    // Returns the amount of bytes written.\n\n    let mut buf = [0u8; 32];\n    let n = u.read(\u0026mut buf).unwrap();\n    // Read up to 32 bytes.\n\n    // Echo it back.\n    let _ = u.write(\u0026buf[0:n]).unwrap();\n\n    // Cleanup\n    u.close();\n\n    // Need this at the end since it's a '!' function.\n    loop {}\n}\n```\n\n### Time  and Sleep\n\n```rust\nuse inky_frame::InkyBoard;\n\n#[rpsp::entry]\nfn main() -\u003e ! {\n    let p = InkyBoard::get();\n\n    for i in 0..25 {\n        p.sleep(5_000); // Wait 5 seconds.\n\n        // Get current RTC time.\n        let now = p.rtc().now().unwrap();\n\n        debug!(\"the time is now {now:?}\");\n    }\n\n    // Need this at the end since it's a '!' function.\n    loop {}\n}\n```\n\n### Watchdog\n\n```rust\nuse inky_frame::InkyBoard;\n\n#[rpsp::entry]\nfn main() -\u003e ! {\n    let p = InkyBoard::get();\n    let dog = p.watchdog();\n\n    dog.start(5_000); // Die if we don't feed the dog every 5 seconds.\n\n    for _ in 0..10 {\n        p.sleep(2_500); // ait 2.5 seconds.\n\n        dog.feed(); // Feed da dog.\n    }\n\n    p.sleep(10_000); // Device will restart during here.\n\n    // Need this at the end since it's a '!' function.\n    loop {}\n}\n```\n\n## Bugs\n\n__This should be fixed with the v0.3.0 update!__\n__Turns out some cheap vendors don't follow standard protocols, weeeeee!__\n\nSome SDCards don't support SPI mode or don't initialize properly. I'm not\n100% sure if it's a protocol issue or something else. These cards return\n`READY (0)` when asked to go into `IDLE (1)` mode. They'll work fine on PCs.\n\nThese SDCards work fine on some of my Ender 3 3D Printers, _which use Arduino's_\n_SDCard library_ and have the same initializing sequence. But other devices, like\nthe Flipper Zero, don't work with them either.\n\nYou'll know if it fails as it won't get past the initialization phase and basically\n\"freezes\" and does not respond with the \"D\" and \"E\" LEDs on. __This error type__\n__does not use the Activity or Network LEDs.__\n\nIf you have a SDCard that has issues also, please leave an [Issue](https://github.com/secfurry/inky-frame/issues/new?title=SDCard+Init+Critical)\nwith information on the SDCard and it's manufactor, size and class markings\n(eg: C with the number, U with the number, etc.) so I can test further.\n\nSDCards verified to __not__ work:\n\n- [These SDHC Class 10/U1 Cards](https://www.amazon.com/dp/B07XJVFVSJ)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsecfurry%2Finky-frame","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsecfurry%2Finky-frame","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsecfurry%2Finky-frame/lists"}