Checking nrf21540-DK registers using SPI3

I am attempting to do a simple read from the FEM on the nrf21540-DK board. I should be able to use the zephyr driver with spi3 (or fem_spi) to do a simple read/write from the fem chip correct?

I seem to be able to get the device - 

const struct device *spi_dev = DEVICE_DT_GET(DT_NODELABEL(spi3))

but the gpio don't seem to show up (the following is just done for validation):

struct gpio_dt_spec spim_cs_gpio =SPI_CS_GPIOS_DT_SPEC_GET(DT_NODELABEL(spi3))
    if(!device_is_ready(spim_cs_gpio.port)){
        printk("SPI master chip select device not ready!\n");
    }


The above will always report the cs_gpio is not ready.


There is no other FEM libraries used at this point (that I am aware of )
The project file is essentially
CONFIG_GPIO=y

CONFIG_SPI=y
CONFIG_SPI_ASYNC=y

Any quick ideas what I am doing wrong ?

This code in its sort of simplest form is the following.

	static uint8_t tx_buffer[2];
	static uint8_t rx_buffer[2];

static struct spi_config spi_cfg = {
	.operation = SPI_WORD_SET(8) | SPI_TRANSFER_MSB ,
	.frequency = 4000000,
	.slave = 0,
	.cs = {.gpio = MY_SPI_MASTER_CS_DT_SPEC, .delay = 0},
};

	const struct spi_buf tx_buf = {
		.buf = tx_buffer,
		.len = sizeof(tx_buffer)
	};
	const struct spi_buf_set tx = {
		.buffers = &tx_buf,
		.count = 1
	};

	struct spi_buf rx_buf = {
		.buf = rx_buffer,
		.len = sizeof(rx_buffer),
	};
	const struct spi_buf_set rx = {
		.buffers = &rx_buf,
		.count = 1
	};

	// Reset signal
	k_poll_signal_reset(&spi_done_sig);
	
	// Start transaction
	int error = spi_transceive_signal(spi_dev, &spi_cfg, &tx, &rx, &spi_done_sig);
	if(error != 0){
		printk("SPI transceive error: %i\n", error);
		return error;
	}

	// Wait for the done signal to be raised and log the rx buffer
	int spi_signaled, spi_result;
	do{
		k_poll_signal_check(&spi_done_sig, &spi_signaled, &spi_result);
	} while(spi_signaled == 0);

Parents
  • Hello,

    This repository is a bit outdated.

    I will attach an application that sets up basic SPIM functionality, so perhaps you can test this. Look at how it gets the devicetree from main.c.

    There is no overlay for the nRF21540 DK, but you can copy the content from the nrf52840dk_nrf52840.overlay.

    Note that if you want to set the nRF21540 in programming state, you need to set the PDN pin high. Please see:

    https://docs.nordicsemi.com/bundle/ps_nrf21540/page/chapters/device_control/doc/operating_state.html

    To be sure, you should also make sure that the TX_EN and RX_EN are low, so that it doesn't enter TX or RX mode. 

    hello_world_spim.zip

    Best regards,

    Edvin

  • Yup, added in a few items to point to the FEM on the nrf21540dk/nrf52840 target, enabled the power pin and it appears to work. The HW_REVISION doesn't match the pdf I have. I received 0x30 and expected a 0x03.

    *** Booting nRF Connect SDK v2.7.0-5cb85570ca43 ***
    *** Using Zephyr OS v3.6.99-100befc70c74 ***
    [00:00:00.365,356] <inf> app: Hello World! nrf21540dk/nrf52840
    [00:00:00.365,356] <inf> app: spi_is_ready_dt() returned 0x1
    [00:00:01.365,661] <inf> app: spi_tranceive_dt() returned 0
    [00:00:01.365,692] <inf> app: data returned 80 0c
    [00:00:02.365,905] <inf> app: spi_tranceive_dt() returned 0
    [00:00:02.365,936] <inf> app: data returned 80 30
    [00:00:03.366,180] <inf> app: spi_tranceive_dt() returned 0
    [00:00:03.366,210] <inf> app: data returned 80 02
    [00:00:04.366,455] <inf> app: spi_tranceive_dt() returned 0
    [00:00:04.366,485] <inf> app: data returned 80 1c


    Just for clarity the code (enclosed) is reading registers 0x14,0x15,0x16, and 0x17 from the FEM.

    /*
     * Copyright (c) 2012-2014 Wind River Systems, Inc.
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    #include <stdio.h>
    #include <errno.h>
    #include <zephyr/kernel.h>
    #include <zephyr/device.h>
    #include <zephyr/devicetree.h>
    #include <zephyr/sys/byteorder.h>
    #include <zephyr/sys/printk.h>
    #include <zephyr/logging/log.h>
    #include <zephyr/drivers/gpio.h>
    #include <zephyr/drivers/spi.h>
    #include <nrfx_gpiote.h>
    
    
    #include <zephyr/irq.h>
    
    #define LOG_MODULE_NAME app
    LOG_MODULE_REGISTER(LOG_MODULE_NAME);
    
    #define SPIOP       SPI_WORD_SET(8) | SPI_TRANSFER_MSB
    
    struct spi_dt_spec spispec = SPI_DT_SPEC_GET(DT_NODELABEL(nrf_radio_fem_spi), SPIOP, 0);
    
    #define NRF_FEM_GPIO ((NRF_GPIO_Type *)DT_REG_ADDR(DT_GPIO_CTLR(DT_PHANDLE(DT_NODELABEL(radio), fem), pdn_gpios)))
    #define NRF_GPIO_PDN_PIN    DT_GPIO_PIN(DT_PHANDLE(DT_NODELABEL(radio), fem), pdn_gpios)
    
    
    void test_spi(void)
    {
        int err;
    
        err = spi_is_ready_dt(&spispec);
        LOG_INF("spi_is_ready_dt() returned 0x%0x", err);
    
        NRF_FEM_GPIO->DIRSET = BIT(NRF_GPIO_PDN_PIN);
        NRF_FEM_GPIO->OUTSET = BIT(NRF_GPIO_PDN_PIN); // power on the nrf21540
    
        uint8_t tx_buffer[2] = {0xff, 0xff};
        tx_buffer[0] = 0x80 | 0x14; // read = register 14
    
        uint8_t data[100];
        uint16_t size = sizeof(data);
        struct spi_buf tx_spi_buf		= {.buf = (void *)&tx_buffer, .len = sizeof(tx_buffer)};
        struct spi_buf_set tx_spi_buf_set 	= {.buffers = &tx_spi_buf, .count = 1};
        struct spi_buf rx_spi_bufs 		= {.buf = data, .len = size};
        struct spi_buf_set rx_spi_buf_set	= {.buffers = &rx_spi_bufs, .count = 1};
    
        k_sleep(K_MSEC(1000));
    
        tx_buffer[0] = 0x80 | 0x14; // read = register 14
        err = spi_transceive_dt(&spispec, &tx_spi_buf_set, &rx_spi_buf_set);
        LOG_INF("spi_tranceive_dt() returned %d", err);
        LOG_INF("data returned %02x %02x", data[0],data[1] );
    
        k_sleep(K_MSEC(1000));
    
        tx_buffer[0] = 0x80 | 0x15; 
        err = spi_transceive_dt(&spispec, &tx_spi_buf_set, &rx_spi_buf_set);
        LOG_INF("spi_tranceive_dt() returned %d", err);
        LOG_INF("data returned %02x %02x", data[0],data[1] );
    
        k_sleep(K_MSEC(1000));
    
        tx_buffer[0] = 0x80 | 0x16; 
        err = spi_transceive_dt(&spispec, &tx_spi_buf_set, &rx_spi_buf_set);
        LOG_INF("spi_tranceive_dt() returned %d", err);
        LOG_INF("data returned %02x %02x", data[0],data[1] );
    
        k_sleep(K_MSEC(1000));
    
        tx_buffer[0] = 0x80 | 0x17; 
        err = spi_transceive_dt(&spispec, &tx_spi_buf_set, &rx_spi_buf_set);
        LOG_INF("spi_tranceive_dt() returned %d", err);
        LOG_INF("data returned %02x %02x", data[0],data[1] );
    
        while (true) {
            err = spi_transceive_dt(&spispec, &tx_spi_buf_set, &rx_spi_buf_set);
            if (err) {
                LOG_ERR("Transceive failed %d", err);
            }
            k_sleep(K_MSEC(1000));
        }
    }
    
    int main(void)
    {
    	LOG_INF("Hello World! %s", CONFIG_BOARD_TARGET);
        
        test_spi();
    	return 0;
    }
    

Reply
  • Yup, added in a few items to point to the FEM on the nrf21540dk/nrf52840 target, enabled the power pin and it appears to work. The HW_REVISION doesn't match the pdf I have. I received 0x30 and expected a 0x03.

    *** Booting nRF Connect SDK v2.7.0-5cb85570ca43 ***
    *** Using Zephyr OS v3.6.99-100befc70c74 ***
    [00:00:00.365,356] <inf> app: Hello World! nrf21540dk/nrf52840
    [00:00:00.365,356] <inf> app: spi_is_ready_dt() returned 0x1
    [00:00:01.365,661] <inf> app: spi_tranceive_dt() returned 0
    [00:00:01.365,692] <inf> app: data returned 80 0c
    [00:00:02.365,905] <inf> app: spi_tranceive_dt() returned 0
    [00:00:02.365,936] <inf> app: data returned 80 30
    [00:00:03.366,180] <inf> app: spi_tranceive_dt() returned 0
    [00:00:03.366,210] <inf> app: data returned 80 02
    [00:00:04.366,455] <inf> app: spi_tranceive_dt() returned 0
    [00:00:04.366,485] <inf> app: data returned 80 1c


    Just for clarity the code (enclosed) is reading registers 0x14,0x15,0x16, and 0x17 from the FEM.

    /*
     * Copyright (c) 2012-2014 Wind River Systems, Inc.
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    #include <stdio.h>
    #include <errno.h>
    #include <zephyr/kernel.h>
    #include <zephyr/device.h>
    #include <zephyr/devicetree.h>
    #include <zephyr/sys/byteorder.h>
    #include <zephyr/sys/printk.h>
    #include <zephyr/logging/log.h>
    #include <zephyr/drivers/gpio.h>
    #include <zephyr/drivers/spi.h>
    #include <nrfx_gpiote.h>
    
    
    #include <zephyr/irq.h>
    
    #define LOG_MODULE_NAME app
    LOG_MODULE_REGISTER(LOG_MODULE_NAME);
    
    #define SPIOP       SPI_WORD_SET(8) | SPI_TRANSFER_MSB
    
    struct spi_dt_spec spispec = SPI_DT_SPEC_GET(DT_NODELABEL(nrf_radio_fem_spi), SPIOP, 0);
    
    #define NRF_FEM_GPIO ((NRF_GPIO_Type *)DT_REG_ADDR(DT_GPIO_CTLR(DT_PHANDLE(DT_NODELABEL(radio), fem), pdn_gpios)))
    #define NRF_GPIO_PDN_PIN    DT_GPIO_PIN(DT_PHANDLE(DT_NODELABEL(radio), fem), pdn_gpios)
    
    
    void test_spi(void)
    {
        int err;
    
        err = spi_is_ready_dt(&spispec);
        LOG_INF("spi_is_ready_dt() returned 0x%0x", err);
    
        NRF_FEM_GPIO->DIRSET = BIT(NRF_GPIO_PDN_PIN);
        NRF_FEM_GPIO->OUTSET = BIT(NRF_GPIO_PDN_PIN); // power on the nrf21540
    
        uint8_t tx_buffer[2] = {0xff, 0xff};
        tx_buffer[0] = 0x80 | 0x14; // read = register 14
    
        uint8_t data[100];
        uint16_t size = sizeof(data);
        struct spi_buf tx_spi_buf		= {.buf = (void *)&tx_buffer, .len = sizeof(tx_buffer)};
        struct spi_buf_set tx_spi_buf_set 	= {.buffers = &tx_spi_buf, .count = 1};
        struct spi_buf rx_spi_bufs 		= {.buf = data, .len = size};
        struct spi_buf_set rx_spi_buf_set	= {.buffers = &rx_spi_bufs, .count = 1};
    
        k_sleep(K_MSEC(1000));
    
        tx_buffer[0] = 0x80 | 0x14; // read = register 14
        err = spi_transceive_dt(&spispec, &tx_spi_buf_set, &rx_spi_buf_set);
        LOG_INF("spi_tranceive_dt() returned %d", err);
        LOG_INF("data returned %02x %02x", data[0],data[1] );
    
        k_sleep(K_MSEC(1000));
    
        tx_buffer[0] = 0x80 | 0x15; 
        err = spi_transceive_dt(&spispec, &tx_spi_buf_set, &rx_spi_buf_set);
        LOG_INF("spi_tranceive_dt() returned %d", err);
        LOG_INF("data returned %02x %02x", data[0],data[1] );
    
        k_sleep(K_MSEC(1000));
    
        tx_buffer[0] = 0x80 | 0x16; 
        err = spi_transceive_dt(&spispec, &tx_spi_buf_set, &rx_spi_buf_set);
        LOG_INF("spi_tranceive_dt() returned %d", err);
        LOG_INF("data returned %02x %02x", data[0],data[1] );
    
        k_sleep(K_MSEC(1000));
    
        tx_buffer[0] = 0x80 | 0x17; 
        err = spi_transceive_dt(&spispec, &tx_spi_buf_set, &rx_spi_buf_set);
        LOG_INF("spi_tranceive_dt() returned %d", err);
        LOG_INF("data returned %02x %02x", data[0],data[1] );
    
        while (true) {
            err = spi_transceive_dt(&spispec, &tx_spi_buf_set, &rx_spi_buf_set);
            if (err) {
                LOG_ERR("Transceive failed %d", err);
            }
            k_sleep(K_MSEC(1000));
        }
    }
    
    int main(void)
    {
    	LOG_INF("Hello World! %s", CONFIG_BOARD_TARGET);
        
        test_spi();
    	return 0;
    }
    

Children
No Data
Related