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

SPI initialization according to spec

I am initializing an SPI master to talk to ADXL362 accelerometer using NRF51-DK.

Datasheet page 19: www.analog.com/.../ADXL362.pdf

No matter what I do connected or disconnected, I always get 0xFF back. Makes no difference changing transfer speed, MSB or LSB, IRQ priority or anything. So I have some questions to clarify.

Code

void Spi_Initialize()
{
	spi_master_config_t spi_config = SPI_MASTER_INIT_DEFAULT;

#if defined(SPI_MASTER_0_ENABLE)
	spi_config.SPI_Pin_SCK = SPIM0_SCK_PIN;
	spi_config.SPI_Pin_MISO = SPIM0_MISO_PIN;
	spi_config.SPI_Pin_MOSI = SPIM0_MOSI_PIN;
	spi_config.SPI_Pin_SS = SPIM0_SS_PIN;
#elif defined(SPI_MASTER_1_ENABLE)
	spi_config.SPI_Pin_SCK = SPIM1_SCK_PIN;
	spi_config.SPI_Pin_MISO = SPIM1_MISO_PIN;
	spi_config.SPI_Pin_MOSI = SPIM1_MOSI_PIN;
	spi_config.SPI_Pin_SS = SPIM1_SS_PIN;
#endif /* SPI_MASTER_ENABLE */

	spi_config.SPI_CONFIG_ORDER = SPI_CONFIG_ORDER_LsbFirst; // :     SPI_CONFIG_ORDER_MsbFirst);	
	spi_config.SPI_CONFIG_CPOL = SPI_CONFIG_CPOL_ActiveHigh;
	spi_config.SPI_CONFIG_CPHA = SPI_CONFIG_CPHA_Leading;
	spi_config.SPI_Freq = SPI_FREQUENCY_FREQUENCY_M1;
	//spi_config.SPI_PriorityIRQ = APP_IRQ_PRIORITY_HIGH;

	uint32_t result = spi_master_open(SPI_MASTER_HW, &spi_config);
	APP_ERROR_CHECK(result);

	spi_master_evt_handler_reg(SPI_MASTER_HW, spi_master_event_handler);

	Adxl362_Setup();
}

I set SPI_MASTER_0_ENABLE in the makefile and make sure it is compiled with -DSPI_MASTER_0_ENABLE . Code runs fine, and no appearent hard faults while debugging, or sending the data through bluetooth.

  1. Datasheet says "The SPI timing scheme follows CPHA = CPOL = 0." spi_config.SPI_CONFIG_CPOL = SPI_CONFIG_CPOL_ActiveHigh; and spi_config.SPI_CONFIG_CPHA = SPI_CONFIG_CPHA_Leading; mean this? The actual #define values are 0, but high sounds like 1 to me? What is correct? isn't this "mode 0" ?

  2. When connecting "CS" from the ADXL362 to the NRF51-DK "SEL" Pin (24), does this mean that NRF51-DK will send CS 1 and 0 before and after each command automatically? In arduino etc you need to do this manually. Or does "SEL" on the NRF51-DK have another meaning? There's like 100 different words for "chip select" it seems like :)

  3. Pin 24 is also "LED 4". Does this mean that any CS output from ADXL362 will make it light up or the other way around? It is constantly lit. Should I disable this?

I am really stuck, and wonder if I have accidentally fried the ADXL362. Thanks!

UPDATE: I got a hold of a logic analyzer. Here is my output:

Logic Output

What's going on here. OK, there is some noise from the clock into MISO, but it is completely dead. Shouldn't the clock be sent when getting a reply?

Success = 0 = OK.

static uint16_t Adxl362_Read(unsigned reg)
{
	uint8_t buf[4];
	uint16_t rxcnt;

	buf[0] = ADXL34X_CMD_READ;
	buf[1] = reg;

	if (reg & REG_2B) {
		rxcnt = 2;
	}
	else {
		rxcnt = 1;
		buf[3] = 0;
	}

	uint32_t status = spi_master_send_recv(SPI_MASTER_HW, &buf[0], 2, &buf[2], rxcnt);

	APP_ERROR_CHECK(status);


	return (uint16_t)buf[2];
}

My current settings aside from pins are:

spi_config.SPI_CONFIG_ORDER = SPI_CONFIG_ORDER_LsbFirst;
spi_config.SPI_CONFIG_CPOL = SPI_CONFIG_CPOL_ActiveHigh;
spi_config.SPI_CONFIG_CPHA = SPI_CONFIG_CPHA_Leading;
spi_config.SPI_Freq = SPI_FREQUENCY_FREQUENCY_M1;

Any ideas?

Update 2:

3 bytes

Here's a screenshot of sending 3 bytes where the 3rd now is 0xFF. Which seems delayed a lot. I read that the SPI buffer is only 2 bytes, but is 30 µs too much of a separation? Also it seems to be dead with both LSB first and MSB first even when sending the dummy 1 byte.

I am using a ble uart sample with advertising etc with one ADC on another pin, can the IRQs and timers interfere with the SPI?

Here are the timings. Does NRF adhere to these timings? Timings

  • RESPONSE TO RESPONSE TO EDIT 2 :)

    I made it work with this dummy byte! I had to remove the Saleae Logic from the circuit since it introduced noise and it didn't work reliably.

    So let me get this straight. The RX and TX buffers passed in must be in the same size. Is it sensible to have one big buffer of 10 bytes as opposed to 2 buffers with 5 bytes each?

    The command is 2 bytes + dummy byte = 3 bytes.

    The response can either be a byte or an uint = 1-2 = 2 at most. = 4 bytes total.

    So then I have a buffer with 8 bytes, where the offset 4 is passed to the RX. I then read 4+2 = 6th index to get the response which is 1 or 2 bytes.

    static uint8_t _buf[8];
    

    ...

    _buf[0] = ADXL34X_CMD_READ;
    _buf[1] = reg;
    _buf[2] = SPI_DEFAULT_TX_BYTE;
    
    if (reg & REG_2B) {
    	rxcnt = 2;
    	_buf[3] = SPI_DEFAULT_TX_BYTE;
    }
    else {
    	rxcnt = 1;
    }
    uint32_t status = spi_master_send_recv(SPI_MASTER_HW, &_buf[0], 2 + rxcnt, &_buf[4], 2 + rxcnt);
    

    ...

    return _buf[6]; // add conversion for 16 bit values
    
  • Glad it finally works :) No, they don't need to be the same size. If the SPI executes a transfer with a rx_buffer larger than the tx_buffer it will shift out dummy bytes until the rx_buffer is full. If the tx_buffer is larger than the rx_buffer the redundant received bytes will be discarded. E.g. if your tx_buffer is 10 bytes and the rx_buffer is 3 then the first three incoming bytes will be put in the rx_buffer and the last 7 will be discarded.

    Regarding one large vs two small buffers I don't know really. Personally I think it would be easier to read and use the code with two arrays. But it is really up to you.

  • Thanks for all your help! I actually had to use all the standard settings, and use MSB configuration. In practice the buffers have to be the same size or rx > tx if I want to get anything from the dummy bytes I suppose. I am glad I finally sorted out SPI with your API.

    The ADXL362 is VERY sensitive to noise so I have to do some analog design to give it a nicer and more noise free transmission line.

    So a reminder: CPOL = 0 = SPI_CONFIG_CPOL_ActiveHigh

    CPHA = 0 = SPI_CONFIG_CPHA_Leading

    This = MODE 0

  • Happy to help. Is it the ADXL362 itself or a combination of the sensor and the PCB that makes it is sensitive? Just curious. I use a Saleae logic analyzer myself and has never had a problem with it.

  • It is the ADXL362 itself I think. I searched on various forums etc, and they had to be careful about cable lengths and add filtering caps to ground etc.

    A Rigol 1054Z is on the way so I can see how that behaves in comparison :)

Related