This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Attempting SPIM3 reads with MOSI and MISO Tied Together

Hello,

We are currently using SDK v17.0.2 with NRF52840, driving a display with SPIM3. We are able to successfully communicate with our display and command it to render various things. Because it's a display, we have MOSI and MISO tied together as the same pin (the display does not utilize a MISO line).

I am currently attempting to read back the temperature from the display, but not getting a sensible read. With MOSI and MISO tied together, is there special pin driving logic that needs to be performed? 

Here is my code:

    // Set up logic
    #define EINK_XFER_BUF_LEN    ( 2048 ) // bytes
    #define EINK_COMMAND_LEN     ( 1 )    // bytes
    #define EINK_RECEIVE_BUF_LEN ( 1 )    // bytes
    #define TEST_DELAY_US        ( 150 )  // In microseconds
    static uint8_t m_tx_buf[EINK_XFER_BUF_LEN] __attribute__( (section( ".errata198_workaround" ) ) ) = { 0 };
    static uint8_t m_rx_buf[EINK_RECEIVE_BUF_LEN] __attribute__( (section( ".errata198_workaround" ) ) ) = { 0 };
    nrfx_spim_xfer_desc_t xfer_receive_desc = NRFX_SPIM_XFER_TRX( m_tx_buf, 1, m_rx_buf, 1 );
    
    
    // Send temperature read command
    m_tx_buf[0] = TSC; 
    einkCtx->commandSent = m_tx_buf[0];
    einkCtx->isCommand   = true;
    einkCtx->spiXferDone = false;
    // Signal to the EPD that this is a command
    memset(m_rx_buf, 0, EINK_RECEIVE_BUF_LEN);
    einkCtx->retCode = nrfx_spim_xfer_dcx( &spim_eink, &xfer_receive_desc, 0, 1 ); 
    nrf_delay_us( TEST_DELAY_US );    
    
    
    // Read back logic in callback function
    if ( xsferCtx->commandSent == READ_TEMP )
    {
        // Wait until the Display is no longer busy
        while ( !nrf_gpio_pin_read( E_INK_BUSY_PIN ) );

        if ( m_rx_buf[0] != 0 )
        {
           NRF_LOG_INFO(" TSC Received:");
           xsferCtx->epd_temperature = m_rx_buf[0];
           NRF_LOG_INFO("m_rx_buf[0] == 0x%X ", m_rx_buf[0]);
          
        }
    }

Parents
  • The SPI code you are using assumes 4-wire SPI, but to connect MOSI to MISO 3-wire SPI mode is required, which I don't think the driver you are using supports. Here is low-level code showing how it's done:

    static void Test3WireSPI(void)
    {
      NRF_GPIO->PIN_CNF[CSPIN]   = 0x301;  // output, high drive high and low H0H1
      NRF_GPIO->PIN_CNF[SCKPIN]  = 0x301;  // output, high drive high and low H0H1
      NRF_GPIO->PIN_CNF[MOSIPIN] = 1;      // output, standard drive S0S1
      NRF_GPIO->PIN_CNF[MISOPIN] = 0;      // input pin, input buffer connected, no pull, S0S1, sense disabled
      NRF_GPIO->OUTSET = 1 << CSPIN;       // deactivate by setting chip select high
      NRF_SPIM3->PSEL.SCK = SCKPIN;
      NRF_SPIM3->PSEL.MOSI = MOSIPIN;
      NRF_SPIM3->PSEL.MISO = 0xFFFFFFFFUL; // MISOPIN;
      NRF_SPIM3->CONFIG = 0;               // CPOL 0 -- clock polarity active high, CPHA 1 -- sample on trailing clock edge, send Msb first
      NRF_SPIM3->FREQUENCY = 0x80000000UL; // 8 Mbps
      NRF_SPIM3->ORC =0;                   // Unused Tx bytes, set all low
    
      // Configure registers for 3-wire mode
      NRF_SPIM3->PSEL.MOSI = MOSIPIN;
      NRF_SPIM3->PSEL.MISO = 0xFFFFFFFFUL; // MISOPIN;
      NRF_GPIO->PIN_CNF[MOSIPIN] = 1;      // output
    
      NRF_SPIM3->EVENTS_ENDTX = 0;
      //NRF_SPIM3->EVENTS_ENDRX = 0;
    
      // Disable all interrupts
      NRF_SPIM3->INTENCLR = 0xFFFFFFFFUL;
      // Enable selected interrupts
      NRF_SPIM3->INTENSET = 0x40;   // END
    
      // Set interrupt priority and enable interrupt
      NVIC_SetPriority(SPIM3_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQn, 6);
      NVIC_ClearPendingIRQ(SPIM3_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQn);
      NVIC_EnableIRQ(SPIM3_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQn);
    
      NRF_SPIM3->ENABLE = 7;               // enable SPI
      // Transfer registers to set 3-wire SPI mode on target
      NRF_SPIM3->TXD.PTR = (uint32_t)mACC_ControlRegisterRequiredSettings;
      NRF_SPIM3->TXD.MAXCNT = sizeof(mACC_ControlRegisterRequiredSettings);
      NRF_SPIM3->RXD.PTR = NULL;
      NRF_SPIM3->RXD.MAXCNT = 0;
    
      NRF_GPIO->OUTCLR = 1 << CSPIN;    // drive cs low to initiate spi comm
      NRF_SPIM3->TASKS_START = 1;
      while(!NRF_SPIM3->EVENTS_ENDTX);  // last byte transmitted
      NRF_SPIM3->TASKS_STOP = 1;
      NRF_GPIO->OUTSET = 1 << CSPIN;
    
      // Send 3-wire whoami command byte (1 byte only)
      // Connect output drive, connect 1-wire rx/tx output to MOSI
      NRF_SPIM3->PSEL.MISO = 0xFFFFFFFF; // MISOPIN;
      NRF_SPIM3->PSEL.MOSI = MOSIPIN;
      NRF_GPIO->PIN_CNF[MOSIPIN] = 1;    // output
      NRF_SPIM3->TXD.PTR = (uint32_t)spi3wTXBuf;
      NRF_SPIM3->TXD.MAXCNT = 1;
      NRF_SPIM3->RXD.PTR = NULL;
      NRF_SPIM3->RXD.MAXCNT = 0;
      NRF_SPIM3->EVENTS_ENDTX = 0;
      NRF_GPIO->OUTCLR = 1 << CSPIN;       // drive cs low to initiate spi comm
      NRF_SPIM3->TASKS_START = 1;
      while(!NRF_SPIM3->EVENTS_ENDTX);     // last byte transmitted
    
      // Manual says disable SPI before changing pins, but actually doesn't matter
      NRF_SPIM3->ENABLE = 0;               // disable SPI
      // Disconnect output drive, connect 1-wire rx/tx input to MISO
      NRF_SPIM3->PSEL.MOSI = 0xFFFFFFFFUL; // MOSIPIN;
      NRF_GPIO->PIN_CNF[MOSIPIN] = 0;      // input pin, input buffer connected, no pull, S0S1, sense disabled
      NRF_SPIM3->PSEL.MISO = MOSIPIN;      // MISOPIN;
      NRF_SPIM3->ENABLE = 7;               // enable SPI
      spi3wRXBuf[0] = 99; spi3wRXBuf[1] = 98;
      NRF_SPIM3->TXD.PTR = NULL;
      NRF_SPIM3->TXD.MAXCNT = 0;
      NRF_SPIM3->RXD.PTR = (uint32_t)spi3wRXBuf;
      NRF_SPIM3->RXD.MAXCNT = 1;
      NRF_SPIM3->EVENTS_ENDRX = 0;
      NRF_SPIM3->TASKS_START = 1;
      while(!NRF_SPIM3->EVENTS_ENDRX);    // last byte received
    
      NRF_SPIM3->TASKS_STOP = 1;
      while(!NRF_SPIM3->EVENTS_STOPPED);
      NRF_GPIO->OUTSET = 1 << CSPIN;
    }

    This link give more details 3-wire-spi-bi-directional-communication

Reply
  • The SPI code you are using assumes 4-wire SPI, but to connect MOSI to MISO 3-wire SPI mode is required, which I don't think the driver you are using supports. Here is low-level code showing how it's done:

    static void Test3WireSPI(void)
    {
      NRF_GPIO->PIN_CNF[CSPIN]   = 0x301;  // output, high drive high and low H0H1
      NRF_GPIO->PIN_CNF[SCKPIN]  = 0x301;  // output, high drive high and low H0H1
      NRF_GPIO->PIN_CNF[MOSIPIN] = 1;      // output, standard drive S0S1
      NRF_GPIO->PIN_CNF[MISOPIN] = 0;      // input pin, input buffer connected, no pull, S0S1, sense disabled
      NRF_GPIO->OUTSET = 1 << CSPIN;       // deactivate by setting chip select high
      NRF_SPIM3->PSEL.SCK = SCKPIN;
      NRF_SPIM3->PSEL.MOSI = MOSIPIN;
      NRF_SPIM3->PSEL.MISO = 0xFFFFFFFFUL; // MISOPIN;
      NRF_SPIM3->CONFIG = 0;               // CPOL 0 -- clock polarity active high, CPHA 1 -- sample on trailing clock edge, send Msb first
      NRF_SPIM3->FREQUENCY = 0x80000000UL; // 8 Mbps
      NRF_SPIM3->ORC =0;                   // Unused Tx bytes, set all low
    
      // Configure registers for 3-wire mode
      NRF_SPIM3->PSEL.MOSI = MOSIPIN;
      NRF_SPIM3->PSEL.MISO = 0xFFFFFFFFUL; // MISOPIN;
      NRF_GPIO->PIN_CNF[MOSIPIN] = 1;      // output
    
      NRF_SPIM3->EVENTS_ENDTX = 0;
      //NRF_SPIM3->EVENTS_ENDRX = 0;
    
      // Disable all interrupts
      NRF_SPIM3->INTENCLR = 0xFFFFFFFFUL;
      // Enable selected interrupts
      NRF_SPIM3->INTENSET = 0x40;   // END
    
      // Set interrupt priority and enable interrupt
      NVIC_SetPriority(SPIM3_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQn, 6);
      NVIC_ClearPendingIRQ(SPIM3_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQn);
      NVIC_EnableIRQ(SPIM3_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQn);
    
      NRF_SPIM3->ENABLE = 7;               // enable SPI
      // Transfer registers to set 3-wire SPI mode on target
      NRF_SPIM3->TXD.PTR = (uint32_t)mACC_ControlRegisterRequiredSettings;
      NRF_SPIM3->TXD.MAXCNT = sizeof(mACC_ControlRegisterRequiredSettings);
      NRF_SPIM3->RXD.PTR = NULL;
      NRF_SPIM3->RXD.MAXCNT = 0;
    
      NRF_GPIO->OUTCLR = 1 << CSPIN;    // drive cs low to initiate spi comm
      NRF_SPIM3->TASKS_START = 1;
      while(!NRF_SPIM3->EVENTS_ENDTX);  // last byte transmitted
      NRF_SPIM3->TASKS_STOP = 1;
      NRF_GPIO->OUTSET = 1 << CSPIN;
    
      // Send 3-wire whoami command byte (1 byte only)
      // Connect output drive, connect 1-wire rx/tx output to MOSI
      NRF_SPIM3->PSEL.MISO = 0xFFFFFFFF; // MISOPIN;
      NRF_SPIM3->PSEL.MOSI = MOSIPIN;
      NRF_GPIO->PIN_CNF[MOSIPIN] = 1;    // output
      NRF_SPIM3->TXD.PTR = (uint32_t)spi3wTXBuf;
      NRF_SPIM3->TXD.MAXCNT = 1;
      NRF_SPIM3->RXD.PTR = NULL;
      NRF_SPIM3->RXD.MAXCNT = 0;
      NRF_SPIM3->EVENTS_ENDTX = 0;
      NRF_GPIO->OUTCLR = 1 << CSPIN;       // drive cs low to initiate spi comm
      NRF_SPIM3->TASKS_START = 1;
      while(!NRF_SPIM3->EVENTS_ENDTX);     // last byte transmitted
    
      // Manual says disable SPI before changing pins, but actually doesn't matter
      NRF_SPIM3->ENABLE = 0;               // disable SPI
      // Disconnect output drive, connect 1-wire rx/tx input to MISO
      NRF_SPIM3->PSEL.MOSI = 0xFFFFFFFFUL; // MOSIPIN;
      NRF_GPIO->PIN_CNF[MOSIPIN] = 0;      // input pin, input buffer connected, no pull, S0S1, sense disabled
      NRF_SPIM3->PSEL.MISO = MOSIPIN;      // MISOPIN;
      NRF_SPIM3->ENABLE = 7;               // enable SPI
      spi3wRXBuf[0] = 99; spi3wRXBuf[1] = 98;
      NRF_SPIM3->TXD.PTR = NULL;
      NRF_SPIM3->TXD.MAXCNT = 0;
      NRF_SPIM3->RXD.PTR = (uint32_t)spi3wRXBuf;
      NRF_SPIM3->RXD.MAXCNT = 1;
      NRF_SPIM3->EVENTS_ENDRX = 0;
      NRF_SPIM3->TASKS_START = 1;
      while(!NRF_SPIM3->EVENTS_ENDRX);    // last byte received
    
      NRF_SPIM3->TASKS_STOP = 1;
      while(!NRF_SPIM3->EVENTS_STOPPED);
      NRF_GPIO->OUTSET = 1 << CSPIN;
    }

    This link give more details 3-wire-spi-bi-directional-communication

Children
No Data
Related