imxrt-hal 0.5.14

Hardware abstraction layer for NXP i.MX RT microcontrollers.
Documentation
//! Demonstrates a SPI device with blocking I/O.
//!
//! Connect SDI to SDO. The example uses the LPSPI interrupt to
//! schedule transfers, and to receive data. You can observe the
//! I/O with a scope / logic analyzer. The SPI CLK runs at 1MHz.
//!
//! Keep an eye on the defmt log to see if tests fail.

#![no_std]
#![no_main]

#[rtic::app(device = board, peripherals = false)]
mod app {

    use imxrt_hal as hal;

    const PIT_DELAY_MS: u32 = board::PIT_FREQUENCY / 1_000 * 250;

    #[local]
    struct Local {
        spi: board::Spi,
        pit: hal::pit::Pit<2>,
    }

    #[shared]
    struct Shared {}

    #[init]
    fn init(_: init::Context) -> (Shared, Local) {
        let (
            board::Common {
                pit: (_, _, pit, _),
                ..
            },
            board::Specifics { spi, .. },
        ) = board::new();
        (Shared {}, Local { spi, pit })
    }

    #[idle(local = [spi, pit])]
    fn idle(cx: idle::Context) -> ! {
        let idle::LocalResources { spi, pit, .. } = cx.local;
        pit.set_load_timer_value(PIT_DELAY_MS);

        let mut delay = move || {
            pit.enable();
            while !pit.is_elapsed() {}
            pit.clear_elapsed();
            pit.disable();
        };

        loop {
            for _ in 0..3 {
                delay();
            }

            // For studying the effects of bit order and word size.
            //
            // If you have a logic analyzer that can change its word
            // size and bit order, use this sequence to evaluate how
            // the driver packs your transfer elements.
            {
                use eh02::blocking::spi::Write;
                use hal::lpspi::BitOrder::{self, *};

                const BIT_ORDERS: [BitOrder; 2] = [Msb, Lsb];

                const U32_WORDS: [u32; 2] = [0xDEADBEEFu32, 0xAD1CAC1D];
                for bit_order in BIT_ORDERS {
                    spi.set_bit_order(bit_order);
                    spi.write(&U32_WORDS).unwrap();
                }

                const U8_WORDS: [u8; 7] = [0xDEu8, 0xAD, 0xBE, 0xEF, 0x12, 0x34, 0x56];
                for bit_order in BIT_ORDERS {
                    spi.set_bit_order(bit_order);
                    spi.write(&U8_WORDS).unwrap();
                }

                const U16_WORDS: [u16; 3] = [0xDEADu16, 0xBEEF, 0x1234];
                for bit_order in BIT_ORDERS {
                    spi.set_bit_order(bit_order);
                    spi.write(&U16_WORDS).unwrap();
                }

                delay();
            }

            // Change me to explore bit order behavors in the
            // remaining write / loopback transfer tests.
            spi.set_bit_order(hal::lpspi::BitOrder::Msb);

            // Make sure concatenated elements look correct on the wire.
            // Make sure we can read those elements.
            {
                use eh02::blocking::spi::Transfer;
                use hal::lpspi::BitOrder;

                macro_rules! transfer_test {
                    ($arr:expr, $bit_order:expr) => {
                        let bit_order_name = match $bit_order {
                            BitOrder::Msb => "MSB",
                            BitOrder::Lsb => "LSB",
                        };

                        spi.set_bit_order($bit_order);
                        let mut buffer = $arr;
                        spi.transfer(&mut buffer).unwrap();
                        defmt::assert_eq!(buffer, $arr, "Bit Order {}", bit_order_name);
                    };
                }

                transfer_test!([1u8, 2, 3], BitOrder::Msb);
                transfer_test!([1u8, 2, 3], BitOrder::Lsb);

                transfer_test!([1u8, 2, 3, 4], BitOrder::Msb);
                transfer_test!([1u8, 2, 3, 4], BitOrder::Lsb);

                transfer_test!([1u8, 2, 3, 4, 5], BitOrder::Msb);
                transfer_test!([1u8, 2, 3, 4, 5], BitOrder::Lsb);

                transfer_test!([1u8, 2, 3, 4, 5, 6], BitOrder::Msb);
                transfer_test!([1u8, 2, 3, 4, 5, 6], BitOrder::Lsb);

                transfer_test!([1u8, 2, 3, 4, 5, 6, 7], BitOrder::Msb);
                transfer_test!([1u8, 2, 3, 4, 5, 6, 7], BitOrder::Lsb);

                transfer_test!([0x0102u16, 0x0304, 0x0506], BitOrder::Msb);
                transfer_test!([0x0102u16, 0x0304, 0x0506], BitOrder::Lsb);

                transfer_test!([0x0102u16, 0x0304, 0x0506, 0x0708], BitOrder::Msb);
                transfer_test!([0x0102u16, 0x0304, 0x0506, 0x0708], BitOrder::Lsb);

                transfer_test!([0x0102u16, 0x0304, 0x0506, 0x0708, 0x090A], BitOrder::Msb);
                transfer_test!([0x0102u16, 0x0304, 0x0506, 0x0708, 0x090A], BitOrder::Lsb);

                transfer_test!([0x01020304u32, 0x05060708, 0x090A0B0C], BitOrder::Msb);
                transfer_test!([0x01020304u32, 0x05060708, 0x090A0B0C], BitOrder::Lsb);

                spi.set_bit_order(BitOrder::Msb);
                delay();
            }

            {
                use eh02::blocking::spi::{Transfer, Write};

                // Change me to test different Elem sizes, buffer sizes,
                // bit patterns.
                type Elem = u8;
                const SENTINEL: Elem = 0x0F;
                const BUFFER: [Elem; 13] = [SENTINEL; 13];

                // Simple loopback transfer. Easy to find with your
                // scope.
                let mut buffer = BUFFER;
                spi.transfer(&mut buffer).unwrap();
                if buffer != BUFFER {
                    defmt::error!("Simple transfer buffer mismatch!");
                }

                delay();

                // Adjacent loopback transfer. Look for the big
                // burst of data on your scope.
                let mut buffer = BUFFER;
                let mut error = false;
                for idx in 0u32..16 {
                    buffer.fill(SENTINEL.rotate_right(idx));
                    let expected = buffer;
                    spi.transfer(&mut buffer).unwrap();
                    error |= buffer != expected;
                }
                if error {
                    defmt::error!("At least one of the bursted transfers didn't match!");
                }

                delay();

                // Simple write.
                let buffer = BUFFER;
                spi.write(&buffer).unwrap();

                delay();

                // Pipelined writes. Look for the burst of data
                // on your scope. Internally, the writes will flush,
                // so the delay between transfers should be about
                // the same as they are for the transfers.
                let mut buffer = BUFFER;
                for idx in 0..16 {
                    buffer.fill(SENTINEL.rotate_right(idx));
                    spi.write(&buffer).unwrap();
                }

                delay();
            }
        }
    }
}