esp-rs / esp-idf-hal

embedded-hal implementation for Rust on ESP32 and ESP-IDF
https://docs.esp-rs.org/esp-idf-hal/
Apache License 2.0
458 stars 171 forks source link

Spi has some problems. or clk needs to pull up resistors、or other...(esp32c2 rust-std) #401

Closed xiaguangbo closed 6 months ago

xiaguangbo commented 6 months ago

I use spi connect max31865 do pt100 temperature measurement,the clk needs to pull up resistors,or touch clk with hand,or hang clk on the oscilloscope probe...must select a, Otherwise, it's not normal.. Spi tm1638(A digital display and key scanning), write is ok, read key is all zero.

hard spi read use this api:

self.spi.transaction(&mut [Operation::Write(&[0x01]), Operation::Read(&mut rbuf)]).unwrap();

Using gpio to simulate spi is normal. Maybe it's SPI's GPIO setup problem.

I connected MOSI to MISO, because they wouldn't work at the same time, and tm1638 uses "half3wire". There seems to be a problem with using half3wire provided by the library, will reportspi_master: check_trans_valid(793): SPI half duplex mode is not supported when both MOSI and MISO phases are enabled.

simulate spi half3wire : Use external pullup resistors

struct Tm1638<'a, Clk, Dio, Cs>
where
    Clk: Peripheral<P = Clk> + OutputPin,
    Dio: Peripheral<P = Dio> + InputPin + OutputPin,
    Cs: Peripheral<P = Cs> + OutputPin,
{
    clk: PinDriver<'a, Clk, Output>,
    dio: PinDriver<'a, Dio, InputOutput>,
    cs: PinDriver<'a, Cs, Output>,
}

impl<'a, Clk, Dio, Cs> Tm1638<'a, Clk, Dio, Cs>
where
    Clk: Peripheral<P = Clk> + OutputPin,
    Dio: Peripheral<P = Dio> + InputPin + OutputPin,
    Cs: Peripheral<P = Cs> + OutputPin,
{
    pub fn new(clk: Clk, dio: Dio, cs: Cs) -> Self {
        let mut clk = PinDriver::output(clk).unwrap();
        let mut dio = PinDriver::input_output_od(dio).unwrap();
        let mut cs = PinDriver::output(cs).unwrap();

        clk.set_high().unwrap();
        cs.set_high().unwrap();

        Self { clk, dio, cs }
    }
...

Hard spi: common

    let peripherals = Peripherals::take().unwrap();

    let spi = SpiDriver::new::<SPI2>(
        peripherals.spi2,
        peripherals.pins.gpio2,
        peripherals.pins.gpio3,
        Some(peripherals.pins.gpio4),
        &SpiDriverConfig::new(),
    )
    .unwrap();

    // distributed among different threads.
    let spi_1 = Arc::new(spi);
    let spi_2 = spi_1.clone();
pub struct Tm1638<'a, Spi>
where
    Spi: Borrow<SpiDriver<'a>> + 'a,
{
    spi: SpiDeviceDriver<'a, Spi>,
}

impl<'a, Spi> Tm1638<'a, Spi>
where
    Spi: Borrow<SpiDriver<'a>> + 'a,
{
    pub fn new<Cs>(spi: Spi, cs: Cs) -> Self
    where
        Cs: Peripheral<P = Cs> + OutputPin,
    {
        let config = config::Config::default()
            .data_mode(config::MODE_3)
            .bit_order(config::BitOrder::LsbFirst);

        let spi = SpiDeviceDriver::new(spi, Some(cs), &config).unwrap();

        Self { spi }
    }
...
pub struct Max31865<'a, Spi>
where
    Spi: Borrow<SpiDriver<'a>> + 'a,
{
    spi: SpiDeviceDriver<'a, Spi>,
    delay: Delay,
}

impl<'a, Spi> Max31865<'a, Spi>
where
    Spi: Borrow<SpiDriver<'a>> + 'a,
{
    pub fn new<Cs>(spi: Spi, cs: Cs) -> Self
    where
        Cs: Peripheral<P = Cs> + OutputPin,
    {
        let config = config::Config::default().data_mode(config::MODE_3);

        let spi = SpiDeviceDriver::new(spi, Some(cs), &config).unwrap();

        Self {
            spi,
            delay: Delay::new_default(),
        }
    }
xiaguangbo commented 6 months ago

This macro only has esp32 and esp32s2, other models do not support half-duplex?

.embuild/espressif/esp-idf/v5.1.3/components/driver/spi/gpspi/spi_master.c L790:

#if !SOC_SPI_HD_BOTH_INOUT_SUPPORTED
    //On these chips, HW doesn't support using both TX and RX phases when in halfduplex mode
    SPI_CHECK(!is_half_duplex || !tx_enabled || !rx_enabled, "SPI half duplex mode is not supported when both MOSI and MISO phases are enabled.", ESP_ERR_INVALID_ARG);
    SPI_CHECK(!is_half_duplex || !trans_desc->length || !trans_desc->rxlength, "SPI half duplex mode is not supported when both MOSI and MISO phases are enabled.", ESP_ERR_INVALID_ARG);
#endif
xiaguangbo commented 6 months ago
let peripherals = Peripherals::take().unwrap();

    let spi = SpiDriver::new::<SPI2>(
        peripherals.spi2,
        peripherals.pins.gpio2,
        peripherals.pins.gpio3,
        Option::<AnyIOPin>::None,
        &SpiDriverConfig::new(),
    )
    .unwrap();

    let spi_1 = Arc::new(spi);
    let spi_2 = spi_1.clone();
std::thread::Builder::new()
        .stack_size(8 * 1024)
        .spawn(move || {
            let mut temperature = temperature::TemperatureMax31865::new(
                spi_1.as_ref(),
                peripherals.pins.gpio5,
                tx_temp_ctrl,
                tx_temp_modbus,
                tx_temp_ui,
            );

            temperature.work();
        })
        .unwrap();

std::thread::Builder::new()
        .stack_size(8 * 1024)
        .spawn(move || {
            let mut ui = ui::UiTm1638::new(
                spi_2.as_ref(),
                peripherals.pins.gpio7,
                rx_temp_ui,
                tx_get_temp_keep_ui,
                rx_temp_keep_ui,
                tx_set_temp_keep_ui,
                tx_get_slave_addr_ui,
                rx_slave_addr_ui,
                tx_set_slave_addr_ui,
            );

            ui.work();
        })
        .unwrap();
use std::borrow::Borrow;

pub struct TemperatureMax31865<'a, Spi>
where
    Spi: Borrow<SpiDriver<'a>> + 'a,
{
    max31865: Max31865<'a, Spi>,
    tx_temp_ctrl: mpsc::SyncSender<f32>,
    tx_temp_modbus: mpsc::SyncSender<f32>,
    tx_temp_ui: mpsc::SyncSender<f32>,
}

impl<'a, Spi> TemperatureMax31865<'a, Spi>
where
    Spi: Borrow<SpiDriver<'a>> + 'a,
{
    pub fn new<Cs>(
        spi: Spi,
        cs: Cs,
        tx_temp_ctrl: mpsc::SyncSender<f32>,
        tx_temp_modbus: mpsc::SyncSender<f32>,
        tx_temp_ui: mpsc::SyncSender<f32>,
    ) -> Self
    where
        Cs: Peripheral<P = Cs> + OutputPin,
    {
        Self {
            max31865: Max31865::new(spi, cs),
            tx_temp_ctrl,
            tx_temp_modbus,
            tx_temp_ui,
        }
    }
...

pub struct Max31865<'a, Spi>
where
    Spi: Borrow<SpiDriver<'a>> + 'a,
{
    spi: SpiDeviceDriver<'a, Spi>,
    delay: Delay,
}

impl<'a, Spi> Max31865<'a, Spi>
where
    Spi: Borrow<SpiDriver<'a>> + 'a,
{
    pub fn new<Cs>(spi: Spi, cs: Cs) -> Self
    where
        Cs: Peripheral<P = Cs> + OutputPin,
    {
        let config = config::Config::default()
              .data_mode(config::MODE_3)
              .duplex(config::Duplex::Half3Wire);

        let spi = SpiDeviceDriver::new(spi, Some(cs), &config).unwrap();

        Self {
            spi,
            delay: Delay::new_default(),
        }
    }
...
use std::borrow::Borrow;

pub struct UiTm1638<'a, Spi>
where
    Spi: Borrow<SpiDriver<'a>> + 'a,
{
    tm1638: Tm1638<'a, Spi>,
    key: Key,
    rx_temp: mpsc::Receiver<f32>,
    tx_get_temp_keep: mpsc::SyncSender<bool>,
    rx_temp_keep: mpsc::Receiver<i16>,
    tx_set_temp_keep: mpsc::SyncSender<i16>,
    tx_get_slave_addr: mpsc::SyncSender<bool>,
    rx_slave_addr: mpsc::Receiver<u8>,
    tx_set_slave_addr: mpsc::SyncSender<u8>,
}

impl<'a, Spi> UiTm1638<'a, Spi>
where
    Spi: Borrow<SpiDriver<'a>> + 'a,
{
    pub fn new<Cs>(
        spi: Spi,
        cs: Cs,
        rx_temp: mpsc::Receiver<f32>,
        tx_get_temp_keep: mpsc::SyncSender<bool>,
        rx_temp_keep: mpsc::Receiver<i16>,
        tx_set_temp_keep: mpsc::SyncSender<i16>,
        tx_get_slave_addr: mpsc::SyncSender<bool>,
        rx_slave_addr: mpsc::Receiver<u8>,
        tx_set_slave_addr: mpsc::SyncSender<u8>,
    ) -> Self
    where
        Cs: Peripheral<P = Cs> + OutputPin,
    {
        Self {
            tm1638: Tm1638::new(spi, cs),
            key: Key::new(),
            rx_temp,
            tx_get_temp_keep,
            rx_temp_keep,
            tx_set_temp_keep,
            tx_get_slave_addr,
            rx_slave_addr,
            tx_set_slave_addr,
        }
    }
...

pub struct Tm1638<'a, Spi>
where
    Spi: Borrow<SpiDriver<'a>> + 'a,
{
    spi: SpiDeviceDriver<'a, Spi>,
}

impl<'a, Spi> Tm1638<'a, Spi>
where
    Spi: Borrow<SpiDriver<'a>> + 'a,
{
    pub fn new<Cs>(spi: Spi, cs: Cs) -> Self
    where
        Cs: Peripheral<P = Cs> + OutputPin,
    {
        let config = config::Config::default()
            .data_mode(config::MODE_3)
            .bit_order(config::BitOrder::LsbFirst)
            .duplex(config::Duplex::Half3Wire);

        let spi = SpiDeviceDriver::new(spi, Some(cs), &config).unwrap();

        Self { spi }
    }
...
xiaguangbo commented 6 months ago

solution: https://github.com/espressif/esp-idf/issues/13554