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?

Parents
  • 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

Reply
  • 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

Children
No Data
Related