From 945794617d1fb947db7f075adf599c2a1243fa61 Mon Sep 17 00:00:00 2001 From: LithDefaux Date: Tue, 16 Sep 2025 12:29:38 +0300 Subject: [PATCH 1/3] feat(spi): Implement working master SPI prototype for NXP PAC --- .../lpc55s69/src/bin/spi_master_nxp-pac.rs | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 examples/lpc55s69/src/bin/spi_master_nxp-pac.rs diff --git a/examples/lpc55s69/src/bin/spi_master_nxp-pac.rs b/examples/lpc55s69/src/bin/spi_master_nxp-pac.rs new file mode 100644 index 0000000000..3f02917655 --- /dev/null +++ b/examples/lpc55s69/src/bin/spi_master_nxp-pac.rs @@ -0,0 +1,130 @@ +// Location should be embassy/examples/lpc55s69/src/bin/spi_master_test.rs +#![no_std] +#![no_main] + +use cortex_m::asm::nop; +use defmt::*; +use embassy_executor::Spawner; +//use embassy_nxp::pac::*; +use {defmt_rtt as _, panic_halt as _}; +use nxp_pac::*; + +fn init() { + info!("Init"); + // SPI 7 at FLEXCOMM 7 Setup + // CLOCK ENABLING + SYSCON.ahbclkctrl0().modify(|w| { + w.set_iocon(true); + } ); + SYSCON.ahbclkctrl1().modify(|w| { + w.set_fc(7, true); + } ); + + // RST FLEXCOMM 7 + SYSCON.presetctrl1().modify(|w| { + w.set_fc_rst(7, syscon::vals::FcRst::ASSERTED); + }); + SYSCON.presetctrl1().modify(|w| { + w.set_fc_rst(7, syscon::vals::FcRst::RELEASED); + }); + + // CLK SEL + SYSCON.fcclksel(7).modify(|w| + w.set_sel(syscon::vals::FcclkselSel::ENUM_0X2) + ); + FLEXCOMM7.pselid().modify(|w|{ + w.set_persel(flexcomm::vals::Persel::SPI); + }); + + // IOCON Setup + IOCON.pio1(20).modify(|w|{ + w.set_func(iocon::vals::PioFunc::ALT1); + w.set_digimode(iocon::vals::PioDigimode::DIGITAL); + w.set_slew(iocon::vals::PioSlew::STANDARD); + w.set_mode(iocon::vals::PioMode::INACTIVE); + w.set_invert(false); + w.set_od(iocon::vals::PioOd::NORMAL); + }); + IOCON.pio0(20).modify(|w|{ + w.set_func(iocon::vals::PioFunc::ALT7); + w.set_digimode(iocon::vals::PioDigimode::DIGITAL); + w.set_slew(iocon::vals::PioSlew::STANDARD); + w.set_mode(iocon::vals::PioMode::INACTIVE); + w.set_invert(false); + w.set_od(iocon::vals::PioOd::NORMAL); + }); + IOCON.pio0(19).modify(|w|{ + w.set_func(iocon::vals::PioFunc::ALT7); + w.set_digimode(iocon::vals::PioDigimode::DIGITAL); + w.set_slew(iocon::vals::PioSlew::STANDARD); + w.set_mode(iocon::vals::PioMode::INACTIVE); + w.set_invert(false); + w.set_od(iocon::vals::PioOd::NORMAL); + }); + IOCON.pio0(21).modify(|w|{ + w.set_func(iocon::vals::PioFunc::ALT7); + w.set_digimode(iocon::vals::PioDigimode::DIGITAL); + w.set_slew(iocon::vals::PioSlew::STANDARD); + w.set_mode(iocon::vals::PioMode::INACTIVE); + w.set_invert(false); + w.set_od(iocon::vals::PioOd::NORMAL); + }); + + // INTERFACE CLK Setup + SYSCON.flexfrgctrl(7).modify(|w|{ + w.set_div(0xFF); + w.set_mult(0); + }); + SPI7.div().modify(|w|{ + w.set_divval(0); + }); + + //SPI MASTER CONFIG + SPI7.cfg().modify(|w|{ + w.set_enable(true); + w.set_master(spi::vals::Master::MASTER_MODE); + w.set_lsbf(spi::vals::Lsbf::STANDARD); + w.set_cpha(spi::vals::Cpha::CHANGE); + w.set_cpol(spi::vals::Cpol::LOW); + w.set_loop_(false); + w.set_spol1(spi::vals::Spol1::LOW); + }); + SPI7.fifocfg().modify(|w| { + w.set_dmatx(false); + w.set_dmarx(false); + w.set_enabletx(true); + w.set_enablerx(true); + //w.set_emptytx(true); + //w.set_emptyrx(true); + }); + SPI7.fifowr().write(|w|{ + w.set_rxignore(spi::vals::Rxignore::IGNORE); + }); + + loop { + SPI7.fifowr().write(|w|w.set_txssel1_n(spi::vals::Txssel1N::ASSERTED)); + for _ in 0..100_000 { + nop();} + SPI7.fifowr().write(|w|{ + w.set_txdata(0x04); + w.set_len(8); + }); + for _ in 0..100_000 { + nop();} + let fifostat = SPI7.fifostat().read(); + info!("Tx full? {}", !fifostat.txnotfull()); + info!("Tx level: {}", fifostat.txlvl()); + info!("Tx empty? {}", fifostat.txempty()); + SPI7.fifowr().write(|w|{ + w.set_eot(true); + w.set_txssel1_n(spi::vals::Txssel1N::NOT_ASSERTED); + }); + for _ in 0..100_000 { + nop();} + } +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + init(); +} \ No newline at end of file From 31d6a5bd9bf85edd51d3df000b2ae112345002b8 Mon Sep 17 00:00:00 2001 From: LithDefaux Date: Mon, 22 Sep 2025 13:24:17 +0300 Subject: [PATCH 2/3] feat(spi): improve inline documentation and fix build errors --- examples/lpc55s69/Cargo.toml | 1 + .../lpc55s69/src/bin/spi_master_nxp-pac.rs | 33 ++++++++++++------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/examples/lpc55s69/Cargo.toml b/examples/lpc55s69/Cargo.toml index 579748595e..d3a55a7661 100644 --- a/examples/lpc55s69/Cargo.toml +++ b/examples/lpc55s69/Cargo.toml @@ -8,6 +8,7 @@ publish = false [dependencies] embassy-nxp = { version = "0.1.0", path = "../../embassy-nxp", features = ["lpc55-core0", "rt", "defmt", "time-driver-rtc"] } +nxp-pac = { version = "0.1.0", git = "https://github.com/i509VCB/nxp-pac", rev = "b736e3038254d593024aaa1a5a7b1f95a5728538", features = ["metadata"]} embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] } embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "tick-hz-32_768"] } diff --git a/examples/lpc55s69/src/bin/spi_master_nxp-pac.rs b/examples/lpc55s69/src/bin/spi_master_nxp-pac.rs index 3f02917655..c34c85ffdc 100644 --- a/examples/lpc55s69/src/bin/spi_master_nxp-pac.rs +++ b/examples/lpc55s69/src/bin/spi_master_nxp-pac.rs @@ -1,18 +1,16 @@ -// Location should be embassy/examples/lpc55s69/src/bin/spi_master_test.rs #![no_std] #![no_main] use cortex_m::asm::nop; use defmt::*; use embassy_executor::Spawner; -//use embassy_nxp::pac::*; use {defmt_rtt as _, panic_halt as _}; use nxp_pac::*; fn init() { info!("Init"); - // SPI 7 at FLEXCOMM 7 Setup - // CLOCK ENABLING + // SPI 7 at FLEXCOMM 7 Setup (spi instance is the same as the flexcomm instance) + // Enable iocon and flexcomm SYSCON.ahbclkctrl0().modify(|w| { w.set_iocon(true); } ); @@ -20,7 +18,7 @@ fn init() { w.set_fc(7, true); } ); - // RST FLEXCOMM 7 + // Reset Flexcomm 7 SYSCON.presetctrl1().modify(|w| { w.set_fc_rst(7, syscon::vals::FcRst::ASSERTED); }); @@ -29,14 +27,18 @@ fn init() { }); // CLK SEL + // Select Main Clock (ENUM_0X2 is FRO 12Mhz) SYSCON.fcclksel(7).modify(|w| w.set_sel(syscon::vals::FcclkselSel::ENUM_0X2) ); + // Set flexcomm to SPI FLEXCOMM7.pselid().modify(|w|{ w.set_persel(flexcomm::vals::Persel::SPI); }); // IOCON Setup + // All pins are configured according to the standard settings in the SPI config documentation + // SSEL1 at func 1 iocon IOCON.pio1(20).modify(|w|{ w.set_func(iocon::vals::PioFunc::ALT1); w.set_digimode(iocon::vals::PioDigimode::DIGITAL); @@ -45,6 +47,7 @@ fn init() { w.set_invert(false); w.set_od(iocon::vals::PioOd::NORMAL); }); + // MOSI at func 7 iocon IOCON.pio0(20).modify(|w|{ w.set_func(iocon::vals::PioFunc::ALT7); w.set_digimode(iocon::vals::PioDigimode::DIGITAL); @@ -53,6 +56,7 @@ fn init() { w.set_invert(false); w.set_od(iocon::vals::PioOd::NORMAL); }); + // MISO at func 7 iocon IOCON.pio0(19).modify(|w|{ w.set_func(iocon::vals::PioFunc::ALT7); w.set_digimode(iocon::vals::PioDigimode::DIGITAL); @@ -61,6 +65,7 @@ fn init() { w.set_invert(false); w.set_od(iocon::vals::PioOd::NORMAL); }); + // SCKL at func 7 iocon IOCON.pio0(21).modify(|w|{ w.set_func(iocon::vals::PioFunc::ALT7); w.set_digimode(iocon::vals::PioDigimode::DIGITAL); @@ -70,16 +75,18 @@ fn init() { w.set_od(iocon::vals::PioOd::NORMAL); }); - // INTERFACE CLK Setup + // FlexcommFRG divider (div is 0xFF by default in the documentation meaning it can be divided by either 1 or 2) SYSCON.flexfrgctrl(7).modify(|w|{ w.set_div(0xFF); w.set_mult(0); }); + // SPI clock divider can go from 1 to 255 SPI7.div().modify(|w|{ w.set_divval(0); }); + // Final Clock is 12 MHz - //SPI MASTER CONFIG + // SPI Master config using ssel_1 SPI7.cfg().modify(|w|{ w.set_enable(true); w.set_master(spi::vals::Master::MASTER_MODE); @@ -89,6 +96,7 @@ fn init() { w.set_loop_(false); w.set_spol1(spi::vals::Spol1::LOW); }); + // FIFO Config disabling DMA and enabling TX and RX SPI7.fifocfg().modify(|w| { w.set_dmatx(false); w.set_dmarx(false); @@ -97,17 +105,18 @@ fn init() { //w.set_emptytx(true); //w.set_emptyrx(true); }); + // Disabling RX is recommended in the documentation if you are not expecting to receive data SPI7.fifowr().write(|w|{ w.set_rxignore(spi::vals::Rxignore::IGNORE); }); loop { - SPI7.fifowr().write(|w|w.set_txssel1_n(spi::vals::Txssel1N::ASSERTED)); + SPI7.fifowr().write(|w|w.set_txssel1_n(spi::vals::Txssel1N::ASSERTED)); // Assert the SSEL you are transferring data to for _ in 0..100_000 { nop();} SPI7.fifowr().write(|w|{ - w.set_txdata(0x04); - w.set_len(8); + w.set_txdata(0x04); // Data to be transfered + w.set_len(8); // !! IMPORTANT !! If length isn't specified data won't be shifted out }); for _ in 0..100_000 { nop();} @@ -116,8 +125,8 @@ fn init() { info!("Tx level: {}", fifostat.txlvl()); info!("Tx empty? {}", fifostat.txempty()); SPI7.fifowr().write(|w|{ - w.set_eot(true); - w.set_txssel1_n(spi::vals::Txssel1N::NOT_ASSERTED); + w.set_eot(true); // Mark end of transfer + w.set_txssel1_n(spi::vals::Txssel1N::NOT_ASSERTED); // Deassert our SSEL }); for _ in 0..100_000 { nop();} From 997f468c664a7ce9ff8eacd545777b09287782a9 Mon Sep 17 00:00:00 2001 From: LithDefaux Date: Mon, 22 Sep 2025 13:32:41 +0300 Subject: [PATCH 3/3] fixed formatting issues --- .../lpc55s69/src/bin/spi_master_nxp-pac.rs | 76 ++++++++++++------- 1 file changed, 47 insertions(+), 29 deletions(-) diff --git a/examples/lpc55s69/src/bin/spi_master_nxp-pac.rs b/examples/lpc55s69/src/bin/spi_master_nxp-pac.rs index c34c85ffdc..688f2dd547 100644 --- a/examples/lpc55s69/src/bin/spi_master_nxp-pac.rs +++ b/examples/lpc55s69/src/bin/spi_master_nxp-pac.rs @@ -4,19 +4,21 @@ use cortex_m::asm::nop; use defmt::*; use embassy_executor::Spawner; -use {defmt_rtt as _, panic_halt as _}; use nxp_pac::*; +use {defmt_rtt as _, panic_halt as _}; fn init() { info!("Init"); - // SPI 7 at FLEXCOMM 7 Setup (spi instance is the same as the flexcomm instance) + + // SPI 7 at FLEXCOMM 7 Setup + // Enable iocon and flexcomm SYSCON.ahbclkctrl0().modify(|w| { w.set_iocon(true); - } ); + }); SYSCON.ahbclkctrl1().modify(|w| { w.set_fc(7, true); - } ); + }); // Reset Flexcomm 7 SYSCON.presetctrl1().modify(|w| { @@ -28,18 +30,20 @@ fn init() { // CLK SEL // Select Main Clock (ENUM_0X2 is FRO 12Mhz) - SYSCON.fcclksel(7).modify(|w| - w.set_sel(syscon::vals::FcclkselSel::ENUM_0X2) - ); + SYSCON + .fcclksel(7) + .modify(|w| w.set_sel(syscon::vals::FcclkselSel::ENUM_0X2)); + // Set flexcomm to SPI - FLEXCOMM7.pselid().modify(|w|{ + FLEXCOMM7.pselid().modify(|w| { w.set_persel(flexcomm::vals::Persel::SPI); }); - + // IOCON Setup // All pins are configured according to the standard settings in the SPI config documentation + // SSEL1 at func 1 iocon - IOCON.pio1(20).modify(|w|{ + IOCON.pio1(20).modify(|w| { w.set_func(iocon::vals::PioFunc::ALT1); w.set_digimode(iocon::vals::PioDigimode::DIGITAL); w.set_slew(iocon::vals::PioSlew::STANDARD); @@ -47,8 +51,9 @@ fn init() { w.set_invert(false); w.set_od(iocon::vals::PioOd::NORMAL); }); + // MOSI at func 7 iocon - IOCON.pio0(20).modify(|w|{ + IOCON.pio0(20).modify(|w| { w.set_func(iocon::vals::PioFunc::ALT7); w.set_digimode(iocon::vals::PioDigimode::DIGITAL); w.set_slew(iocon::vals::PioSlew::STANDARD); @@ -56,8 +61,9 @@ fn init() { w.set_invert(false); w.set_od(iocon::vals::PioOd::NORMAL); }); + // MISO at func 7 iocon - IOCON.pio0(19).modify(|w|{ + IOCON.pio0(19).modify(|w| { w.set_func(iocon::vals::PioFunc::ALT7); w.set_digimode(iocon::vals::PioDigimode::DIGITAL); w.set_slew(iocon::vals::PioSlew::STANDARD); @@ -65,8 +71,9 @@ fn init() { w.set_invert(false); w.set_od(iocon::vals::PioOd::NORMAL); }); + // SCKL at func 7 iocon - IOCON.pio0(21).modify(|w|{ + IOCON.pio0(21).modify(|w| { w.set_func(iocon::vals::PioFunc::ALT7); w.set_digimode(iocon::vals::PioDigimode::DIGITAL); w.set_slew(iocon::vals::PioSlew::STANDARD); @@ -76,18 +83,19 @@ fn init() { }); // FlexcommFRG divider (div is 0xFF by default in the documentation meaning it can be divided by either 1 or 2) - SYSCON.flexfrgctrl(7).modify(|w|{ + SYSCON.flexfrgctrl(7).modify(|w| { w.set_div(0xFF); w.set_mult(0); }); + // SPI clock divider can go from 1 to 255 - SPI7.div().modify(|w|{ + SPI7.div().modify(|w| { w.set_divval(0); }); // Final Clock is 12 MHz // SPI Master config using ssel_1 - SPI7.cfg().modify(|w|{ + SPI7.cfg().modify(|w| { w.set_enable(true); w.set_master(spi::vals::Master::MASTER_MODE); w.set_lsbf(spi::vals::Lsbf::STANDARD); @@ -96,44 +104,54 @@ fn init() { w.set_loop_(false); w.set_spol1(spi::vals::Spol1::LOW); }); - // FIFO Config disabling DMA and enabling TX and RX SPI7.fifocfg().modify(|w| { w.set_dmatx(false); w.set_dmarx(false); w.set_enabletx(true); w.set_enablerx(true); - //w.set_emptytx(true); - //w.set_emptyrx(true); + // w.set_emptytx(true); + // w.set_emptyrx(true); }); + // Disabling RX is recommended in the documentation if you are not expecting to receive data - SPI7.fifowr().write(|w|{ + SPI7.fifowr().write(|w| { w.set_rxignore(spi::vals::Rxignore::IGNORE); }); loop { - SPI7.fifowr().write(|w|w.set_txssel1_n(spi::vals::Txssel1N::ASSERTED)); // Assert the SSEL you are transferring data to + // Assert the SSEL you are transferring data to + SPI7.fifowr().write(|w| w.set_txssel1_n(spi::vals::Txssel1N::ASSERTED)); + for _ in 0..100_000 { - nop();} - SPI7.fifowr().write(|w|{ - w.set_txdata(0x04); // Data to be transfered - w.set_len(8); // !! IMPORTANT !! If length isn't specified data won't be shifted out + nop(); + } + + SPI7.fifowr().write(|w| { + w.set_txdata(0x04); // Data to be transferred + w.set_len(8); // !! IMPORTANT !! If length isn't specified data won't be shifted out }); + for _ in 0..100_000 { - nop();} + nop(); + } + let fifostat = SPI7.fifostat().read(); info!("Tx full? {}", !fifostat.txnotfull()); info!("Tx level: {}", fifostat.txlvl()); info!("Tx empty? {}", fifostat.txempty()); - SPI7.fifowr().write(|w|{ + + SPI7.fifowr().write(|w| { w.set_eot(true); // Mark end of transfer w.set_txssel1_n(spi::vals::Txssel1N::NOT_ASSERTED); // Deassert our SSEL }); + for _ in 0..100_000 { - nop();} + nop(); + } } } #[embassy_executor::main] async fn main(_spawner: Spawner) { init(); -} \ No newline at end of file +}