FEM: nrf21540 SoC 5340, ESB-Receiver mode not working

Good Day,

We build a custom board with nrf5340 & nrf21540,

NetCore DTS (below) , NetApp DTS has the gpio_fwd in place , all looks good in .config generated.
Net-core UART0 disabled in favor for SPI0. GPIO-TX/RX/PDN + MODE & ANTSEL correct wired.

The ESB sender/receiver code is tested w/o the FEM on two nrf5340DK boards, so I'm sure there is ESB signals.
The config for nmp1300 is OK, the 21540 and 5340 have 3v3 volt. I/O is 3v3.

mpsl_fem_enable() is called before the esb_start_rx()

Because the UART is disabled in the NetCore, I use JLINKRTTViewer for the logs in the netcore.
SDK version below:

*** Booting nRF Connect SDK v2.7.99-cs2-d73b286ff6d9 ***
*** Using Zephyr OS v3.6.99-3d01dcc251bf ***
[00:00:00.002,105] <inf> esb_prx: Enhanced ShockBurst Receiver NetCore
[00:00:00.002,441] <dbg> esb_prx: clocks_start: HF clock started
[00:00:00.002,746] <dbg> esb_prx: esb_fem_init: Fem require receiver setup
[00:00:00.002,746] <dbg> esb_prx: esb_fem_init: Fem require sender setup
[00:00:00.002,838] <inf> esb_prx: ESB initialized
[00:00:00.002,929] <inf> esb_prx: IPC bound complete
[00:00:00.002,929] <inf> esb_prx: Setting up for packet receiption

CONFIG_DT_HAS_NORDIC_NRF21540_FEM_ENABLED=y
CONFIG_DT_HAS_NORDIC_NRF21540_FEM_SPI_ENABLED=y
..
CONFIG_MPSL_FEM_ONLY=y
CONFIG_MPSL_FEM_ANY_SUPPORT=y
CONFIG_MPSL_FEM_NRF21540_GPIO_SUPPORT=y
CONFIG_MPSL_FEM_NRF21540_GPIO_SPI_SUPPORT=y
CONFIG_MPSL_FEM_NCS_SUPPORTED_FEM_USED=y
CONFIG_MPSL_FEM_API_AVAILABLE=y
CONFIG_MPSL_FEM=y
# CONFIG_MPSL_FEM_NRF21540_GPIO is not set
CONFIG_MPSL_FEM_NRF21540_GPIO_SPI=y
CONFIG_MPSL_FEM_NRF21540_TX_GAIN_DB=10
CONFIG_MPSL_FEM_NRF21540_TX_GAIN_DB_POUTA=20
CONFIG_MPSL_FEM_NRF21540_TX_GAIN_DB_POUTB=10
CONFIG_MPSL_FEM_NRF21540_RX_GAIN_DB=13
CONFIG_MPSL_FEM_NRF21540_RUNTIME_PA_GAIN_CONTROL=y
CONFIG_MPSL_FEM_POWER_MODEL=y
CONFIG_MPSL_FEM_POWER_MODEL_NRF21540_USE_BUILTIN=y
CONFIG_MPSL_FEM_BUILTIN_POWER_MODEL_UPDATE_PERIOD=2000
CONFIG_MPSL_FEM_DEVICE_CONFIG_254=y
CONFIG_MPSL_FEM_INIT_PRIORITY=50
# CONFIG_MPSL_FEM_LOG_LEVEL_OFF is not set
# CONFIG_MPSL_FEM_LOG_LEVEL_ERR is not set
# CONFIG_MPSL_FEM_LOG_LEVEL_WRN is not set
# CONFIG_MPSL_FEM_LOG_LEVEL_INF is not set
CONFIG_MPSL_FEM_LOG_LEVEL_DBG=y
# CONFIG_MPSL_FEM_LOG_LEVEL_DEFAULT is not set
CONFIG_MPSL_FEM_LOG_LEVEL=4
..
CONFIG_FEM_AL_LIB=y
CONFIG_FEM=y
CONFIG_NRF21540_FEM=y
..
CONFIG_ESB=y
CONFIG_ESB_MAX_PAYLOAD_LENGTH=32
CONFIG_ESB_TX_FIFO_SIZE=8
CONFIG_ESB_RX_FIFO_SIZE=8
CONFIG_ESB_PIPE_COUNT=8
CONFIG_ESB_RADIO_IRQ_PRIORITY=1
CONFIG_ESB_EVENT_IRQ_PRIORITY=2
..
CONFIG_ESB_SYS_TIMER2=y
CONFIG_ESB_SYS_TIMER_INSTANCE=2

And here is the problem I discovered when I measure the GPIO lines and CSN after start the ESB-receiver:

I measure the pins at nrf21540 after esb_start_rx()
RX = 3v
TX = 0v
PDN = 3v
CSN = 3v  <--- that should be 0V?

CSN  described in the Product specs 4446_194 v1.0 / 2020-08-20 Page 12 , needs driven LOW explicit mentioned

but later version of the Product Spec 4446_194 v1.2 / 2022-01-28 CSN is a non't care (striped out) and not mentioned any more.

So documentation is a bit uncertain, and this change isn't mentioned in the document history.

I add for test in my main() a loop toggle receiver on (5s) off (5s) to check the CSN signal for each state:

bool rxon=false;
   for (;;) {
       if (rxon) {
         esb_stop_rx();
       }
       else {
         esb_start_rx();
       }
       rxon = !rxon;
       LOG_DBG("RX is %s", rxon?"on":"off" );
       k_sleep(K_MSEC(5000));
   }

RTT-Viewer:
[00:00:55.004,821] <dbg> esb_prx: main: RX is off      ----> and the CSN pin is 0V
[00:01:00.004,974] <dbg> esb_prx: main: RX is on     -----> and the CSN pin is 3V

This is the result.

Please have a look into it.

With kind regards
Chris

Parents
  • Hi,

    A missing part might, that the nrf21540 must have a UICR programming cycle, even without a EFUSE burn?  That is not explicit mentioned anywhere.

    Setup the chip below.

    But still have no success yet receiving.

    #define NRF21_NODE  DT_ALIAS(femspi)
    #define SPI_OP      (SPI_WORD_SET(8) | SPI_TRANSFER_MSB)
    static struct spi_dt_spec nrf21spi = SPI_DT_SPEC_GET(NRF21_NODE, SPI_OP, 0);
    static const struct gpio_dt_spec pdn = GPIO_DT_SPEC_GET(FEM_NODE, pdn_gpios);

    #define CONFREG0 0x00
    #define CONFREG1 0x01
    #define CONFREG2 0x02
    #define CONFREG3 0x03
    #define PARTNUMBER 0x14
    #define HW_REVISION 0x15
    #define HW_ID0 0x16
    #define HW_ID1 0x17
    uint8_t baseaddr = 0x00;
    uint8_t registers[8] = {CONFREG0, CONFREG1, CONFREG2, CONFREG3, PARTNUMBER, HW_REVISION, HW_ID0, HW_ID1};

    static void uicr_setup()
    {
       int ret;
       uint8_t recv_buffer[2];
       uint8_t send_buffer[2];
       uint8_t writeop = 0x03 << 6;

       struct spi_buf tx_spi_buf       = {.buf = (void *)&send_buffer, .len = 2};
       struct spi_buf_set tx_spi_buf_set   = {.buffers = &tx_spi_buf, .count = 1};
       struct spi_buf rx_spi_bufs      = {.buf = (void *)&recv_buffer, .len = 2};
       struct spi_buf_set rx_spi_buf_set   = {.buffers = &rx_spi_bufs, .count = 1};

       int devready = spi_is_ready_dt(&nrf21spi);
       if (!devready) {
           LOG_ERR("Error: SPI device is not ready, err: %d", devready);
           return;
       }

       if (pdn.port) {
           gpio_pin_configure_dt(&pdn, GPIO_OUTPUT_INACTIVE);
           gpio_pin_set_dt(&pdn, 1);
           k_busy_wait(200);
       }
       else {
         LOG_ERR("No PDN Gpio");
         return;
       }

       send_buffer[0] = registers[1] | writeop;
       send_buffer[1] = 0x04; // enable uicr
       memset(&recv_buffer, 0, ARRAY_SIZE(recv_buffer));
       ret = spi_transceive_dt(&nrf21spi, &tx_spi_buf_set, &rx_spi_buf_set);
       if (ret<0) {

         LOG_ERR("Failed to enable UICR");
       }

       send_buffer[0] = registers[1] | writeop;
       send_buffer[1] = 0xf0;  // enter mode
       memset(&recv_buffer, 0, ARRAY_SIZE(recv_buffer));
       ret = spi_transceive_dt(&nrf21spi, &tx_spi_buf_set, &rx_spi_buf_set);
       if (ret<0) {
         LOG_ERR("Failed to enter UICR");
       }

       send_buffer[0] = registers[3] | writeop;
       send_buffer[1] = 0x1f;  // Set UICR max (31) + POUTB_PROD mode
       memset(&recv_buffer, 0, ARRAY_SIZE(recv_buffer));
       ret = spi_transceive_dt(&nrf21spi, &tx_spi_buf_set, &rx_spi_buf_set);
       if (ret<0) {
         LOG_ERR("Failed UICR CONFREG3");
       }

       send_buffer[0] = registers[2] | writeop;
       send_buffer[1] = 0x1f;  // Set UICR max (31) + POUTA_PROD mode + EFUSE IDLE
       memset(&recv_buffer, 0, ARRAY_SIZE(recv_buffer));
       ret = spi_transceive_dt(&nrf21spi, &tx_spi_buf_set, &rx_spi_buf_set);
       if (ret<0) {
         LOG_ERR("Failed UICR CONFREG3");
       }

       send_buffer[0] = registers[1] | writeop;
       send_buffer[1] = 0x00;  // exit mode
       memset(&recv_buffer, 0, ARRAY_SIZE(recv_buffer));
       ret = spi_transceive_dt(&nrf21spi, &tx_spi_buf_set, &rx_spi_buf_set);
       if (ret<0) {
         LOG_ERR("Failed to enter UICR");
       }
       gpio_pin_set_dt(&pdn, 0);
       k_busy_wait(5000);
    }

Reply
  • Hi,

    A missing part might, that the nrf21540 must have a UICR programming cycle, even without a EFUSE burn?  That is not explicit mentioned anywhere.

    Setup the chip below.

    But still have no success yet receiving.

    #define NRF21_NODE  DT_ALIAS(femspi)
    #define SPI_OP      (SPI_WORD_SET(8) | SPI_TRANSFER_MSB)
    static struct spi_dt_spec nrf21spi = SPI_DT_SPEC_GET(NRF21_NODE, SPI_OP, 0);
    static const struct gpio_dt_spec pdn = GPIO_DT_SPEC_GET(FEM_NODE, pdn_gpios);

    #define CONFREG0 0x00
    #define CONFREG1 0x01
    #define CONFREG2 0x02
    #define CONFREG3 0x03
    #define PARTNUMBER 0x14
    #define HW_REVISION 0x15
    #define HW_ID0 0x16
    #define HW_ID1 0x17
    uint8_t baseaddr = 0x00;
    uint8_t registers[8] = {CONFREG0, CONFREG1, CONFREG2, CONFREG3, PARTNUMBER, HW_REVISION, HW_ID0, HW_ID1};

    static void uicr_setup()
    {
       int ret;
       uint8_t recv_buffer[2];
       uint8_t send_buffer[2];
       uint8_t writeop = 0x03 << 6;

       struct spi_buf tx_spi_buf       = {.buf = (void *)&send_buffer, .len = 2};
       struct spi_buf_set tx_spi_buf_set   = {.buffers = &tx_spi_buf, .count = 1};
       struct spi_buf rx_spi_bufs      = {.buf = (void *)&recv_buffer, .len = 2};
       struct spi_buf_set rx_spi_buf_set   = {.buffers = &rx_spi_bufs, .count = 1};

       int devready = spi_is_ready_dt(&nrf21spi);
       if (!devready) {
           LOG_ERR("Error: SPI device is not ready, err: %d", devready);
           return;
       }

       if (pdn.port) {
           gpio_pin_configure_dt(&pdn, GPIO_OUTPUT_INACTIVE);
           gpio_pin_set_dt(&pdn, 1);
           k_busy_wait(200);
       }
       else {
         LOG_ERR("No PDN Gpio");
         return;
       }

       send_buffer[0] = registers[1] | writeop;
       send_buffer[1] = 0x04; // enable uicr
       memset(&recv_buffer, 0, ARRAY_SIZE(recv_buffer));
       ret = spi_transceive_dt(&nrf21spi, &tx_spi_buf_set, &rx_spi_buf_set);
       if (ret<0) {

         LOG_ERR("Failed to enable UICR");
       }

       send_buffer[0] = registers[1] | writeop;
       send_buffer[1] = 0xf0;  // enter mode
       memset(&recv_buffer, 0, ARRAY_SIZE(recv_buffer));
       ret = spi_transceive_dt(&nrf21spi, &tx_spi_buf_set, &rx_spi_buf_set);
       if (ret<0) {
         LOG_ERR("Failed to enter UICR");
       }

       send_buffer[0] = registers[3] | writeop;
       send_buffer[1] = 0x1f;  // Set UICR max (31) + POUTB_PROD mode
       memset(&recv_buffer, 0, ARRAY_SIZE(recv_buffer));
       ret = spi_transceive_dt(&nrf21spi, &tx_spi_buf_set, &rx_spi_buf_set);
       if (ret<0) {
         LOG_ERR("Failed UICR CONFREG3");
       }

       send_buffer[0] = registers[2] | writeop;
       send_buffer[1] = 0x1f;  // Set UICR max (31) + POUTA_PROD mode + EFUSE IDLE
       memset(&recv_buffer, 0, ARRAY_SIZE(recv_buffer));
       ret = spi_transceive_dt(&nrf21spi, &tx_spi_buf_set, &rx_spi_buf_set);
       if (ret<0) {
         LOG_ERR("Failed UICR CONFREG3");
       }

       send_buffer[0] = registers[1] | writeop;
       send_buffer[1] = 0x00;  // exit mode
       memset(&recv_buffer, 0, ARRAY_SIZE(recv_buffer));
       ret = spi_transceive_dt(&nrf21spi, &tx_spi_buf_set, &rx_spi_buf_set);
       if (ret<0) {
         LOG_ERR("Failed to enter UICR");
       }
       gpio_pin_set_dt(&pdn, 0);
       k_busy_wait(5000);
    }

Children
No Data
Related