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

nRF52840 Dongle + s140 softdevice + SPI

I am working on a device driver for the W25Q128JV flash device. This is the first SPI device I've used with the nRF52840. I had some observations and questions about SPI programming on this mcu.

int w25q128_flash__read_device_id(w25q128_flash f, uint8_t *device_id)
{
    uint8_t buf[5] = {0};

    buf[0] = 0xAB;
    ret_code_t ret = nrf_drv_spi_transfer(f->spi, buf, 4, buf, 5);

    *device_id = buf[4];

    return ret;
}
This is functionally the same as this:
int w25q128_flash__read_device_id(w25q128_flash f, uint8_t *device_id)
{
    uint8_t wr_buf[4] = {0};
    uint8_t rd_buf[5] = {0};

    wr_buf[0] = 0xAB;
    ret_code_t ret = nrf_drv_spi_transfer(f->spi, wr_buf, 4, rd_buf, 5);

    *device_id = rd_buf[4];

    return ret;
}
The second example is more like the spi example provided in the sdk. In the command, the 0xAB is an instruction, but is then followed by 3 dummy bytes. The next byte is then the id, which reads as 0x17. 
 
It seems like moving forward, I could use the single buffer and then offset the data like in the first example. This seems cleaner than the second example. What is typical on the nrf52840? Is the data read offset the way it should work, or is there a possible setup issue somewhere? I've implemented several functions using this offset approach, and it works fine, but wanted some opinions of other folks who have used SPI on the nrf52 series...
Parents
  • I switched to use the nrfx_spim driver. I was able to remove the legacy spi driver as far as I can tell.

    I updated the xfer function to look like:

    static int local_spi_xfer(w25q128_flash f, uint8_t const *wr_buf, uint8_t wr_len, uint8_t *rd_buf, uint16_t rd_len)
    {
        uint8_t *rbuf = malloc(wr_len + rd_len);
        if (NULL == rbuf)
            return FLASH_MALLOC_ERR;

        nrfx_spim_xfer_desc_t const xfer_desc =
        {
            .p_tx_buffer = wr_buf,
            .tx_length   = wr_len,
            .p_rx_buffer = rbuf,
            .rx_length   = wr_len + rd_len,
        };

        ret_code_t ret = FLASH_SUCCESS;

        nrf_gpio_pin_clear(f->cs_pin);
        ret = nrfx_spim_xfer(f->spi, &xfer_desc, 0);
        nrf_gpio_pin_set(f->cs_pin);

        if (NULL != rd_buf)
            memcpy(rd_buf, rbuf + wr_len, rd_len);
        free(rbuf);

        return ret;
    }
    There still seems to be an issue for certain write length. I can write up to 251 bytes -- with the instruction code and address bytes, that brings the total write to 255, which seems to be the max. If I write 252 bytes, then the function call has no effect at all if I then read back what is written.
    Is there some setting in the sdk_config.h that controls this? In the setup, I've set the handler to NULL, so this is a blocking call.
Reply
  • I switched to use the nrfx_spim driver. I was able to remove the legacy spi driver as far as I can tell.

    I updated the xfer function to look like:

    static int local_spi_xfer(w25q128_flash f, uint8_t const *wr_buf, uint8_t wr_len, uint8_t *rd_buf, uint16_t rd_len)
    {
        uint8_t *rbuf = malloc(wr_len + rd_len);
        if (NULL == rbuf)
            return FLASH_MALLOC_ERR;

        nrfx_spim_xfer_desc_t const xfer_desc =
        {
            .p_tx_buffer = wr_buf,
            .tx_length   = wr_len,
            .p_rx_buffer = rbuf,
            .rx_length   = wr_len + rd_len,
        };

        ret_code_t ret = FLASH_SUCCESS;

        nrf_gpio_pin_clear(f->cs_pin);
        ret = nrfx_spim_xfer(f->spi, &xfer_desc, 0);
        nrf_gpio_pin_set(f->cs_pin);

        if (NULL != rd_buf)
            memcpy(rd_buf, rbuf + wr_len, rd_len);
        free(rbuf);

        return ret;
    }
    There still seems to be an issue for certain write length. I can write up to 251 bytes -- with the instruction code and address bytes, that brings the total write to 255, which seems to be the max. If I write 252 bytes, then the function call has no effect at all if I then read back what is written.
    Is there some setting in the sdk_config.h that controls this? In the setup, I've set the handler to NULL, so this is a blocking call.
Children
Related