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

using the spim driver

Hi, the peripheral/spi example calls for nrf_drv_spi.h, which is located in the legacy directory in SDK 15. I found this post in the devzone:

So far we have kept the SPI interface for backwards compatibility (so you can easily port code from the nRF51/nRF52832 that uses it), but it might be removed in future products, so I would recommend using the SPIM instead. The SPIM interface is also more efficient since all the data transfer is handled by the DMA controller.

Since I'm starting a new project I want to use the SPIM driver, I am however unsure how to achieve that. The registers in nrf52832 datasheet clearly indicate that there is SPIM. However nrfx_spim is only available for pca10056 as an example.

Can someone explain how to use the new (non-legacy) SPIM driver with the nrf52832 DK? I want to simply connect it to a sensor slave.

Parents Reply Children
  • I'm confused now, since the nrfx_spim example is definitly only for 52840. I made it work for 52832 by copying the main.c to the spi example, and modifying some parts (mainly removing the extended feature stuff). Now I only need to use nrfx_spim.h and not the legacy nrf_drv_spi.h.

    I made connection to my sensor and can read and write registers now. However I encountered a strange behaviour that I could not grasp for more than one day now, maybe you have an idea:

    static uint8_t       m_rx_buf[4] = {0};               /**< RX buffer. */
    static const uint8_t m_rx_length = sizeof(m_rx_buf);  /**< Read length. */

    Reading e.g. the whoami register works fine with the RX buffer at a length of 4 (see above code). Setting it to 3 or 5 however will result in the rx buffer being empty. I tried many values, and found out that setting the array length to 10 will work again, 16 also, but in between all will return nothing. 17-23 will work, 23 not, but 24 again, 25 not.

    I'm out of ideas, since the ONLY thing I modify is the length of the rx buffer, it should not affect the data read at all, let alone the sensor itself (data send to sensor is always the same).

    edit: the code for transfer remained mostly the same, I only adjust m_tx_buf before (always size 2).

    m_tx_buf[0] = 0x80+0x41; //read data
    m_tx_buf[1] = 0xFF;
    
    memset(m_rx_buf, 0, m_rx_length); 
    spi_xfer_done = false; 
    APP_ERROR_CHECK(nrfx_spim_xfer(&spi, &xfer_desc, 0)); 
    while (!spi_xfer_done) __WFE();
    NRF_LOG_HEXDUMP_INFO(m_rx_buf, strlen((const char *)m_rx_buf));
    NRF_LOG_FLUSH();

  • That is indeed wierd...

    What is your Over Read Character?

    Do you have a scope of the bus? 

  • I tried 0xFF and 0x00 as ORC, without any impact.

    Bus is 4-wire SPI in mode 3, initialized as follows. I'm quite sure this is correct, since i get valid data from whoami register, not so if I change e.g. spi mode (tried everything). 

        nrfx_spim_config_t spi_config = NRFX_SPIM_DEFAULT_CONFIG;
        spi_config.frequency      = NRF_SPIM_FREQ_1M;
        spi_config.ss_pin         = 29;
        spi_config.miso_pin       = 28;
        spi_config.mosi_pin       = 4;
        spi_config.sck_pin        = 3;
        spi_config.mode           = NRF_SPIM_MODE_3;
        spi_config.orc            = 0xFF;
        spi_config.bit_order= NRF_SPIM_BIT_ORDER_MSB_FIRST;
        spi_config.ss_active_high = false;

    Two points I'm unsure about, since direct config isn't possible, but it was explicitly mentioned in the datasheet of the sensor:

    1. SCK is "active low", same as SS, but for SCK there is no setting to specify that. Is this taken care of automatically?

    2. Latching and transitioning data is recommended to be done alternating between leading and trailing edge. Is this also taken care of?

    But to be honest, since I can write and read data I assume the setup is correct. I tried all SPI modes and changed other settings, but all resulted in failure while this current one works. Since the only thing that changes is the read buffer, the reason must lay within the nRF52832, which is why I'm posting here and not in the sensor's manufacturers forum.

    1. From nrf_spim_mode_t; SCK active low, sample on trailing edge of clock.
    2. I've never read anything about alternating between leading and trailing edge. What is the general idea and why is that recommended? 

    I need the datasheet for the sensor, and a scope of the bus when using 3 and 4 byte RX buffers?

  • Figured it out now thanks to your question for the scope. I have none here at my current position, but use UART with the LOG_INFO functions for debugging. The event handler from the SPIM example was not fundamentally changed (here in original):

    void spim_event_handler(nrfx_spim_evt_t const * p_event,
                           void *                  p_context)
    {
        spi_xfer_done = true;
        NRF_LOG_INFO("Transfer completed.");
        if (m_rx_buf[0] != 0)
        {
            NRF_LOG_INFO(" Received:");
            NRF_LOG_HEXDUMP_INFO(m_rx_buf, strlen((const char *)m_rx_buf));
        }
    }
    
    /**
     * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
     * 
     * All rights reserved.
     * 
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     * 
     * 1. Redistributions of source code must retain the above copyright notice, this
     *    list of conditions and the following disclaimer.
     * 
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     * 
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     * 
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     * 
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     * 
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     * 
     */

    With this, however, there were two problems:

    1. I first read the if condition as "if(buffer_empty)", however it only adresses the first byte. If that is empty, it will report nothing recieved, even if there is data coming afterwards.

    2. As you see above, I also placed the logging function outside the handler (and the if), but NRF_LOG_HEXDUMP_INFO(m_rx_buf, strlen((const char *)m_rx_buf)) will ALSO report nothing - independently -  if alone the first byte is empty, which is very unintuitive if you have a look at its arguments. In order to get "scope-like" data I wrote an alternative logging function:

    NRF_LOG_INFO("\"0x%X\", \"0x%X\", \"0x%X\", \"0x%X\" and \"0x%X\" from slave.", m_rx_buf[0], m_rx_buf[1], m_rx_buf[2], m_rx_buf[3], m_rx_buf[4]);

    See the results for yourself:

    <info> app: Sent "0xF5" and "0xFF" to slave. Got:
    <info> app: "0x0", "0x98" and "0x0" from slave.  //rx_buf[3]
    
    <info> app: Sent "0xF5" and "0xFF" to slave. Got:
    <info> app: "0xFF", "0x98", "0x0" and "0xEB" from slave.  //rx_buf[4]
    
    <info> app: Sent "0xF5" and "0xFF" to slave. Got:
    <info> app: "0x0", "0x98", "0x0", "0xEB" and "0x46" from slave.  //rx_buf[5]

    It seems data always arrived, but the first byte changed dependent on how large the rx_buf is. Why this happens I still do not know, but its irrelevant anyway, just need to check for the second byte and thats always there as we know now.

    You might consider changing the hexdump function to really dump all the hex values even if the first byte is 0, to avoid future confusion. But thats only a suggestion, my matter is settled now.

    Thank you greatly for your suggestions and support!

Related