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

SPI configuration for nrf52832

I've configured the SPI with DMA module as in the code below.

I've loaded the tx buffer with sample data and start the transaction; however, I'm not reading anything either on the MOSI pin or the MISO pin. The SCK pin also stays low. The tx and rx end events do go from 0 to 1 correctly.

Any ideas what I'm doing wrong?

Thanksspi code.rtf

  • #define CSPIN 11  //spi chip select
    #define SCKPIN 12  //spi clock
    #define MOSIPIN 13  //spi mosi
    #define MISOPIN 14  //spi miso
    
    int main()
    {
      NRF_GPIO->PIN_CNF[CSPIN] = 1;  //output
      NRF_GPIO->PIN_CNF[SCKPIN] = 1;  //output
      NRF_GPIO->PIN_CNF[MOSIPIN] = 1;  //output
      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 = MISOPIN;
      NRF_SPIM0->CONFIG = 0b010;  //CPOL 0 -- clock polarity active high, CPHA 1 -- sample on trailing clock edge, send Msb first
      NRF_SPIM0->FREQUENCY = 0x20000000;  //2 Mbps
      uint8_t spiTXBuf[2];  //2 byte tx buffer
      uint8_t spiRXBuf[2];  //2 byte rx buffer
      spiTXBuf[0] = 0b10101010;  //example byte
      spiTXBuf[1] = 0b10101010;  //example byte
      NRF_SPIM0->TXD.PTR = (uint32_t)((uint8_t *)spiTXBuf);
      NRF_SPIM0->TXD.MAXCNT = 2;
      NRF_SPIM0->RXD.PTR = (uint32_t)((uint8_t *)spiRXBuf);
      NRF_SPIM0->RXD.MAXCNT = 2;
      NRF_SPIM0->ENABLE = 7;  //enabled
      NRF_SPIM0->EVENTS_ENDTX = 0;
      NRF_SPIM0->EVENTS_ENDRX = 0;
      NRF_GPIO->OUTCLR |= 1 << CSPIN;  //drive cs low to initiate spi comm
      for(uint8_t i = 0; i < 21; i++) __asm__("nop\n\t");  //low for 21 machine instructions
      NRF_SPIM0->TASKS_START = 1;
      while(!NRF_SPIM0->EVENTS_ENDTX);  //last byte transmitted
      while(!NRF_SPIM0->EVENTS_ENDRX);  //last byte received
      NRF_SPIM0->TASKS_STOP = 1;
      NRF_GPIO->OUTSET |= 1 << CSPIN;
      while(1);
    }

    Sorry. Here's the program

  • Not the answer you are looking for, but a useful tip nonetheless. There are three separate but related issues to doing this:

    NRF_GPIO->OUTSET |= 1 << CSPIN;

    This statement reads the current port status on 32 physical pins, then sets any of those pins high that was read high plus the CSPIN which you actually wanted to be set high. So what? Mostly no problem, but:

    1) if a pin was previously set high but was artificially being held below the threshold voltage by an outside influence that pin would now be unexpectedly driven low

    2) if another pin had a capacitive load such that the rising edge took longer than the time between when it was set high and and when CSPIN was subsequently set high, that pin would be unexpectedly set low

    3) race hazard can occur (very rare perhaps) if two adjacent instructions operate on two different pins on the same port

    You can avoid all of these (and potential weeks of debugging) by instead doing this:

    NRF_GPIO->OUTSET = 1 << CSPIN;

  • Thanks. I think I had "NRF_GPIO->OUTSET = 1 << CSPIN;" at one point but changed it because I didn't want to change all the other pins to low, which, I now see, it wouldn't do. I'll change these lines as you suggest.

    Nonetheless, as you say, this doesn't address my problem.

  • I see in the spim code with a cortex-M4 Nordic do an implicit event read-back after the set to 0 (#if __CORTEX_M == 0x04):

      NRF_SPIM0->EVENTS_ENDTX;
      NRF_SPIM0->EVENTS_ENDRX;

  • Ha ha! I had to smile at this one .. my answer I posted earlier below I think really is the issue, but we didn't look far enough :-) so GPIO->OUTSET does exactly what I said it does, as you concurred, but of course so does GPIO->OUTCLR .. any pins which are high are erroneously driven low because of this:

      NRF_GPIO->OUTCLR |= 1 << CSPIN;  //drive cs low to initiate spi comm

    Change to this and your code works fine:

      NRF_GPIO->OUTCLR = 1 << CSPIN;  //drive cs low to initiate spi comm

    This can be an interview question ..

Related