{"record":{"id":"9ab5d5eaa0cc73ad","repo":"embassy-rs/embassy","slug":"qspi-data-is-empty-so-the-data-width-should-be-no","errorCode":null,"errorMessage":"QSPI data is empty, so the data width should be NONE","messagePattern":"QSPI data is empty, so the data width should be NONE","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"embassy-stm32/src/qspi/mod.rs","lineNumber":387,"sourceCode":"        match (transaction.address, transaction.awidth) {\n            (Some(_), QspiWidth::NONE) => panic!(\"QSPI address can't be sent with an address width of NONE\"),\n            (Some(address), _) => {\n                // u32::bit_width was only stabilized in 1.97\n                let address_bit_width = u32::BITS - address.leading_zeros();\n                if address_bit_width > transaction.address_size.bit_width() as u32 {\n                    panic!(\"QSPI address too large to be represented with the given address size\");\n                }\n            }\n            (None, QspiWidth::NONE) => {}\n            (None, _) => panic!(\"QSPI address is not set, so the address width should be NONE\"),\n        }\n\n        match (data_len, transaction.dwidth) {\n            (Some(0), _) => panic!(\"QSPI data must be at least one byte\"),\n            (Some(_), QspiWidth::NONE) => panic!(\"QSPI data can't be sent with a data width of NONE\"),\n            (Some(_), _) => {}\n            (None, QspiWidth::NONE) => {}\n            (None, _) => panic!(\"QSPI data is empty, so the data width should be NONE\"),\n        }\n\n        T::REGS.fcr().modify(|v| {\n            v.set_csmf(true);\n            v.set_ctcf(true);\n            v.set_ctef(true);\n            v.set_ctof(true);\n        });\n\n        while T::REGS.sr().read().busy() {}\n\n        if let Some(len) = data_len {\n            T::REGS.dlr().write(|v| v.set_dl(len as u32 - 1));\n        }\n\n        T::REGS.ccr().write(|v| {\n            v.set_fmode(fmode.into());\n            v.set_imode(transaction.iwidth.into());","sourceCodeStart":369,"sourceCodeEnd":405,"githubUrl":"https://github.com/embassy-rs/embassy/blob/463a07b963419a1bfe61d5d597c44acb810afb8b/embassy-stm32/src/qspi/mod.rs#L369-L405","documentation":"In setup_transaction, embassy-stm32's QSPI driver requires that when no data bytes are transferred (data_len is None), the transaction's data width (dwidth) must be QspiWidth::NONE. If you pass no data but a non-NONE width, the driver panics because the hardware config would be inconsistent. It is a fail-fast invariant check on the command/transaction configuration.","triggerScenarios":"Calling blocking_read, blocking_write, setup_auto_poll, or setup_command with a QspiCommand whose data phase is omitted (no buffer/length) while transaction.dwidth is set to something other than QspiWidth::NONE. Related panics in the same match: Some(0) length, or Some(len) with QspiWidth::NONE, also panic.","commonSituations":"Copying a command struct from an example that sent data but stripping out the buffer without resetting dwidth; building commands dynamically where the data field is Option and the width is hardcoded; mixing up the alternate/instruction width with the data width.","solutions":["Set dwidth: QspiWidth::NONE on the command whenever no data bytes are transferred.","If data should be sent, provide a non-empty buffer/length (Some(len), len >= 1) matching the dwidth.","Validate at construction: ensure (data_len.is_some() == (dwidth != QspiWidth::NONE)) before calling the blocking APIs."],"exampleFix":"// before\nlet mut cmd = QspiCommand::new(instruction, QspiWidth::SING);\ncmd.data_width = QspiWidth::QUAD; // data_len is None -> panic\nqspi.blocking_command(cmd);\n// after\nlet mut cmd = QspiCommand::new(instruction, QspiWidth::SING);\ncmd.data_width = QspiWidth::NONE; // no data phase\nqspi.blocking_command(cmd);","handlingStrategy":"validation","validationCode":"assert_eq!(\n    cmd.args.data.is_some(),\n    cmd.data_width != QspiWidth::NONE,\n    \"QSPI: data phase presence must match data width\"\n);\nassert!(cmd.args.data.as_ref().map_or(true, |d| !d.is_empty()), \"QSPI: data must be at least one byte\");","typeGuard":"fn has_consistent_data_phase(cmd: &QspiCommand) -> bool {\n    match (cmd.args.data.as_ref().map(|d| d.len()), cmd.data_width) {\n        (Some(0), _) | (Some(_), QspiWidth::NONE) => false,\n        (None, QspiWidth::NONE) | (Some(_), _) => true,\n        (None, _) => false,\n    }\n}","tryCatchPattern":null,"preventionTips":["Always set data_width to NONE when building commands without a data buffer.","Never hardcode data_width independently of the data buffer; derive one from the other.","Add a unit test that enumerates your command set and checks the (data_len, dwidth) consistency matrix."],"tags":["rust","embedded","qspi","panic","invalid-configuration"],"backgroundTag":"invalid-config-value","analyzedSha":"463a07b963419a1bfe61d5d597c44acb810afb8b","analyzedAt":"2026-09-10T13:38:26.660Z","contentChangedAt":"2026-09-10T13:38:26.660Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}