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

softdevice controller use

Hi,

I'm trying to make the softdevice controller work on NuttX RTOS. I followed the SDK example code to reproduce initialization. All calls are returning 0 (no error). However, once I send the first HCI command (a controller RESET) I don't receive SWI interrupt which would lead to signaling for available HCI EVT. If I call sdc_hci_evt_get() on my own, it returns 0 (indicating available EVT), so I think the SWI signaling is not working. I'm also not receiving any other interrupts configured (for RTC, TIMER, RADIO, etc). If I monitor peripheral registers after initialization calls, I also don't see any registers related to peripheral interrupt change. I also verified that if I manually pend the chosen SWI line I get to the appropriate ISR. I'm not sure if I should be doing something else besides these initialization calls (do I need to enable events for each peripheral?). The relevant code is as follows:

int nrf52_sdc_initialize(void)
{
  int ret;
  int32_t required_memory;
  sdc_cfg_t cfg;

  /* Initialize device data */

  memset(&g_sdc_dev, 0, sizeof(g_sdc_dev));
  nxsem_init(&g_sdc_dev.exclsem, 0, 1);

  /* Register interrupt handler for normal-priority events */

  irq_attach(NRF52_IRQ_SWI5_EGU5, swi_isr, NULL);
  irq_attach(NRF52_IRQ_POWER_CLOCK, power_clock_isr, NULL);
  irq_attach(NRF52_IRQ_RNG, rng_isr, NULL);

  up_enable_irq(NRF52_IRQ_SWI5_EGU5);
  up_enable_irq(NRF52_IRQ_POWER_CLOCK);
  up_enable_irq(NRF52_IRQ_RNG);

  up_prioritize_irq(NRF52_IRQ_SWI5_EGU5, NVIC_SYSH_PRIORITY_DEFAULT);
  up_prioritize_irq(NRF52_IRQ_POWER_CLOCK, NVIC_SYSH_PRIORITY_DEFAULT);
  up_prioritize_irq(NRF52_IRQ_RNG, NVIC_SYSH_PRIORITY_DEFAULT);

  // TODO: RNG handler should be called with normal priority but without
  // added processing, is it OK to use NuttX forwarding then?
  // Otherwise, is it OK to do as below but use normal priority?

  /* TODO: how do WFI again after high priority interrupt wakes MCU up? */

  /* Register high-priority interrupts for specific peripherals */

  arm_ramvec_attach(NRF52_IRQ_RTC0, rtc0_handler);
  arm_ramvec_attach(NRF52_IRQ_TIMER0, timer0_handler);
  arm_ramvec_attach(NRF52_IRQ_RADIO, radio_handler);

  up_prioritize_irq(NRF52_IRQ_RTC0, MPSL_HIGH_IRQ_PRIORITY);
  up_prioritize_irq(NRF52_IRQ_TIMER0, MPSL_HIGH_IRQ_PRIORITY);
  up_prioritize_irq(NRF52_IRQ_RADIO, MPSL_HIGH_IRQ_PRIORITY);

  up_enable_irq(NRF52_IRQ_RTC0);
  up_enable_irq(NRF52_IRQ_TIMER0);
  up_enable_irq(NRF52_IRQ_RADIO);

  /* Initialize MPSL */

  ret = mpsl_init(&g_clock_config, SWI5_EGU5_IRQn, &mpsl_assert_handler);

  if (ret < 0)
    {
      wlerr("mpsl init failed: %d\n", ret);
      return ret;
    }

  /* Initialize SDC */

  ret = sdc_init(&sdc_fault_handler);

  if (ret < 0)
    {
      wlerr("mpsl init failed: %d\n", ret);
      return ret;
    }

  cfg.master_count.count = SDC_MASTER_COUNT;
  ret = sdc_cfg_set(SDC_DEFAULT_RESOURCE_CFG_TAG,
                    SDC_CFG_TYPE_MASTER_COUNT, &cfg);

  if (ret < 0)
    {
      wlerr("Failed to set master role count: %d\n", ret);
      return ret;
    }

  cfg.slave_count.count = CONFIG_NRF52_SDC_SLAVE_COUNT;
  ret = sdc_cfg_set(SDC_DEFAULT_RESOURCE_CFG_TAG,
                    SDC_CFG_TYPE_SLAVE_COUNT, &cfg);

  if (ret < 0)
    {
      wlerr("Failed to set slave role count: %d\n", ret);
      return ret;
    }

  cfg.buffer_cfg.rx_packet_size = SDC_DEFAULT_RX_PACKET_SIZE;
  cfg.buffer_cfg.tx_packet_size = SDC_DEFAULT_TX_PACKET_SIZE;
  cfg.buffer_cfg.rx_packet_count = SDC_DEFAULT_RX_PACKET_COUNT;
  cfg.buffer_cfg.tx_packet_count = SDC_DEFAULT_TX_PACKET_COUNT;

  required_memory =
      sdc_cfg_set(SDC_DEFAULT_RESOURCE_CFG_TAG,
                  SDC_CFG_TYPE_BUFFER_CFG, &cfg);

  if (required_memory < 0)
    {
      wlerr("Failed to set packet size/count: %ld\n", required_memory);
      return ret;
    }

  ASSERT(required_memory <= sizeof(g_sdc_dev.mempool));

  /* Turn on specific features */

#ifdef CONFIG_NRF52_SDC_ADVERTISING
  ret = sdc_support_adv();

  if (ret < 0)
    {
      wlerr("Could not enable advertising feature: %d\n", ret);
      return ret;
    }
#endif

#ifdef CONFIG_NRF52_SDC_SCANNING
  ret = sdc_support_scan();

  if (ret < 0)
    {
      wlerr("Could not enable scanning feature: %d\n", ret);
      return ret;
    }
#endif

#ifdef CONFIG_NRF52_SDC_CONNECTION
  ret = sdc_support_master();

  if (ret < 0)
    {
      wlerr("Could not enable master feature: %d\n", ret);
      return ret;
    }
#endif

#if CONFIG_NRF52_SDC_SLAVE_COUNT > 0
  ret = sdc_support_slave();

  if (ret < 0)
    {
      wlerr("Could not enable slave feature: %d\n", ret);
      return ret;
    }
#endif

  ret = sdc_enable(sdc_hci_signal, g_sdc_dev.mempool);

  if (ret < 0)
    {
      wlerr("SoftDevice controller enable failed: %d\n", ret);
      return ret;
    }

  /* Register network device */

  ret = bt_netdev_register(&g_bt_driver);

  return ret;
}

Thank you,

Matias

  • Actually I see that the example code mostly does the same: it triggers event handling right after sending, by posting the same semaphore that is posted when the signal is received from MPSL:

    static int cmd_handle(struct net_buf *cmd)
    {
            BT_DBG("");
    
            int errcode = MULTITHREADING_LOCK_ACQUIRE();
    
            if (!errcode) {
                    errcode = hci_internal_cmd_put(cmd->data);
                    MULTITHREADING_LOCK_RELEASE();
            }
            if (errcode) {
                    return errcode;
            }
    
            k_sem_give(&sem_recv);
    
            return 0;
    }

    and

    void host_signal(void)
    {
            /* Wake up the RX event/data thread */
            k_sem_give(&sem_recv);
    }

    It would be good if you could clarify as to why this is needed. In other words, what kind of events will trigger the signal and which will not. Also, I think that this should be better documented as it is not evident from the documentation.

Related