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 made some logical updates which make the code make more sense to me. This handles the offset issue I described previously.

    int w25q128_flash__read_jedec_id(w25q128_flash f, uint32_t *jedec_id)
    {
        if (NULL == f) return FLASH_NO_EXIST;

        uint8_t wr_buf[1] = {FLASH_REG_RD_JEDEC_ID};
        uint8_t rd_buf[3] = {0};

        ret_code_t ret = local_spi_xfer(f, wr_buf, 1, rd_buf, 3);

        *jedec_id = rd_buf[0] << 16 | rd_buf[1] << 8 | rd_buf[2];

        return ret;
    }


    int w25q128_flash__read_device_id(w25q128_flash f, uint8_t *device_id)
    {
        if (NULL == f) return FLASH_NO_EXIST;

        uint8_t wr_buf[4] = {FLASH_REG_RD_DEVICE_ID, 0x00, 0x00, 0x00};

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

        uint8_t rlen = wr_len + rd_len;

        ret_code_t ret = FLASH_SUCCESS;

        nrf_gpio_pin_clear(f->cs_pin);
        ret = nrf_drv_spi_transfer(f->spi, wr_buf, wr_len, rbuf, rlen);
        nrf_gpio_pin_set(f->cs_pin);

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

        return ret;
    }
    This brings up a question. There is a size limitation imposed by the call to nrf_drv_spi_transfer().
    __STATIC_INLINE
    ret_code_t nrf_drv_spi_transfer(nrf_drv_spi_t const * const p_instance,
                                    uint8_t const * p_tx_buffer,
                                    uint8_t         tx_buffer_length,
                                    uint8_t       * p_rx_buffer,
                                    uint8_t         rx_buffer_length);
    The actual struct internally uses a size_t which is certainly larger than 255 max length. The flash itself has the ability to write up to 256 bytes at once, before a cyclic page overwrite occurs. This sort of implies I need to write a full page in two chunks.
    If I were to call nrfx_spi_xfer() instead, I would be able to setup the nrfx_spi_xfer_desc_t data structure directly. I guess my question is the 256 bytes thing a hardware limitation or not? I only used the nrf_drv_spi_transfer() call since that's what the spi demo was using.

  • Here is a overview of the MAXCNT registers for peripherals on each 52 chip: https://infocenter.nordicsemi.com/topic/struct_nrf52/struct/nrf52.html?cp=4 

    Using nrfx_spi supports longer transfers but since it is legacy SPI  peripheral the CPU need to be updated the byte that is sendt\received for each byte. 

    nrfx_spim will allow you to use 16bit lengths, (65535 bytes) per transfer. 

    Regards,
    Jonathan

Reply Children
No Data
Related