nrf52840 3 wire spi using sdk

Is it possible to use SDK of nrf52840 to configure a 3wire SPI?

I saw in some posts that i can not use directly the MISO pin and not assing it in the sdk's nrf function, but is the best way to proceed?

  • By SDK hopefully you mean nRF52 SDK, but in any case here's a guide using bare-metal programming which you can use to alter other examples. Tested with LIS2DH12 which starts as 4-wire SPI but can be set to 3-wire SPI. (This code assumes the SPI slave is always 3-wire so the 4-wire to 3-wire slave command is not shown). Sequence is send a 1-byte command, no rx, reverse the pin then send a dummy command and receive whatever number of rx bytes are required, in this example a single byte "I am .." response but can be longer

    #define CSPIN    11  // spi chip select
    #define SCKPIN   12  // spi clock
    #define MOSIPIN  13  // spi mosi
    //#define MISOPIN  14  // spi miso - not used in 3-wire mode
    
    #define LIS2DH12_WHO_AM_I  0x0F // Read as 0x33
    
    uint8_t spi3wTXBuf[] = {0x80|LIS2DH12_WHO_AM_I, 0xFF};
    uint8_t spi3wRXBuf[sizeof(spi3wTXBuf)] = {0,0};
    static const uint8_t m3wRxTxBufLength = sizeof(spi3wTXBuf);
    
    volatile uint32_t mSpiInterruptCounter = 0UL;
    
    void notSPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler(void)
    {
      if (NRF_SPIM0->EVENTS_END) NRF_SPIM0->EVENTS_END = 0;
      mSpiInterruptCounter++;
    }
    
    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_SPIM0->PSEL.SCK = SCKPIN;
      NRF_SPIM0->PSEL.MOSI = MOSIPIN;
      NRF_SPIM0->PSEL.MISO = 0xFFFFFFFFUL; // MISOPIN;
      NRF_SPIM0->CONFIG = 0;               // CPOL 0 -- clock polarity active high, CPHA 1 -- sample on trailing clock edge, send Msb first
      NRF_SPIM0->FREQUENCY = 0x80000000UL; // 8 Mbps
      NRF_SPIM0->ORC =0;                   // Unused Tx bytes, set all low
    
      // Configure registers for 3-wire mode
      NRF_SPIM0->PSEL.MOSI = MOSIPIN;
      NRF_SPIM0->PSEL.MISO = 0xFFFFFFFFUL; // MISOPIN;
      NRF_GPIO->PIN_CNF[MOSIPIN] = 1;       // output
      NRF_SPIM0->EVENTS_ENDTX = 0;
      //NRF_SPIM0->EVENTS_ENDRX = 0;
      // Disable all interrupts
      NRF_SPIM0->INTENCLR = 0xFFFFFFFFUL;
      // Enable selected interrupts
      NRF_SPIM0->INTENSET = 0x40;   // END
      // Set interrupt priority and enable interrupt
      NVIC_SetPriority(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQn, 6);
      NVIC_ClearPendingIRQ(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQn);
      NVIC_EnableIRQ(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQn);
      NRF_SPIM0->ENABLE = 7;               // enable SPI
      // Transfer registers to set 3-wire SPI mode on target
      // - not required if slave only has or is already in 3-wire mode
    
      // Send 3-wire whoami command byte (1 byte only)
      // Connect output drive, connect 1-wire rx/tx output to MOSI
      NRF_SPIM0->PSEL.MISO = 0xFFFFFFFF; // MISOPIN;
      NRF_SPIM0->PSEL.MOSI = MOSIPIN;
      NRF_GPIO->PIN_CNF[MOSIPIN] = 1;    // output
      NRF_SPIM0->TXD.PTR = (uint32_t)spi3wTXBuf;
      NRF_SPIM0->TXD.MAXCNT = 1;
      NRF_SPIM0->RXD.PTR = NULL;
      NRF_SPIM0->RXD.MAXCNT = 0;
      NRF_SPIM0->EVENTS_ENDTX = 0;
      NRF_GPIO->OUTCLR = 1 << CSPIN;       // drive cs low to initiate spi comm
      NRF_SPIM0->TASKS_START = 1;
      while(!NRF_SPIM0->EVENTS_ENDTX);     // last byte transmitted
    
      // Manual says disable SPI before changing pins, but actually doesn't matter
      NRF_SPIM0->ENABLE = 0;               // disable SPI
      // Disconnect output drive, connect 1-wire rx/tx input to MISO
      NRF_SPIM0->PSEL.MOSI = 0xFFFFFFFFUL; // MOSIPIN;
      NRF_GPIO->PIN_CNF[MOSIPIN] = 0;      // input pin, input buffer connected, no pull, S0S1, sense disabled
      NRF_SPIM0->PSEL.MISO = MOSIPIN;      // MISOPIN;
      NRF_SPIM0->ENABLE = 7;               // enable SPI
      spi3wRXBuf[0] = 99; spi3wRXBuf[1] = 98;
      NRF_SPIM0->TXD.PTR = NULL;
      NRF_SPIM0->TXD.MAXCNT = 0;
      NRF_SPIM0->RXD.PTR = (uint32_t)spi3wRXBuf;
      NRF_SPIM0->RXD.MAXCNT = 1;
      NRF_SPIM0->EVENTS_ENDRX = 0;
      NRF_SPIM0->TASKS_START = 1;
      while(!NRF_SPIM0->EVENTS_ENDRX);    // last byte received
    
      NRF_SPIM0->TASKS_STOP = 1;
      while(!NRF_SPIM0->EVENTS_STOPPED);
      NRF_GPIO->OUTSET = 1 << CSPIN;
      while(1);
    }

    Bunch of other links via this post: nrf52840-3-wire-spi-implementation

  • Hi

    I agree with Hugh, there is no reason you shouldn't be able to set either the MISO or the MOSI pin to unassigned (0xFFFFFFFF) in order to run the SPI interface in 3-wire mode.

    Best regards
    Torbjørn

Related