The rx examples generally have this initialisation sequence:
- Set SPI rate.
- Power on/reset IC.
dwt_probe()
- Poll
dwt_checkidlerc()
dwt_initialise()
See for example, simple_rx_nlos.c
or rx_diagnostics.c
.
In my experience (stm32) this reliably segfaults due to a read from a NULL pointer. And this seems entirely reasonable, since dwt_checkidlerc()
calls this chain:
dwt_checkidlerc()
in deca_compat.c
ioctl(DWT_CHECKIDLERC)
in dw3000_device.c
ull_checkidlerc()
dwt_read16bitoffsetreg()
dwt_readfromdevice()
dwt_xfer3xxx(DW3000_SPI_RD_BIT)
And there, inside the DW3000_SPI_RD_BIT
case, is this line:
if ((LOCAL_DATA(dw)->spicrc == DWT_SPI_CRC_MODE_WRRD) ...
LOCAL_DATA(dw)
expands to dw->priv
and priv
is set to NULL in dwt_probe()
when static_dw
is assigned to dw
. So this bombs out reliably.
The first thing dwt_initialise()
does is malloc()
this field, so calling it before dwt_checkidlerc()
resolves the issue.
This seems pretty fundamental so I’m surprised I can find no discussion or explanation. Is my version of the API hosed? Am I using it wrong? Or is everyone quietly doing this as well?
Hello,
The most recent version of the driver is 08.02.02. If you have downloaded the most recent QM33 SDK 1.0.0, then you are using the latest software.
I reviewed the code in this SDK and it is similar to what you describe, dwt_checkidlerc is called before dwt_initialise().
dwt_initialise should be called only once the device has properly booted, and reach idle_rc stage.
The error is likely to be linked to an error in the STM32 porting, and incorrect allocation. I will raise it to the internal teams
1 Like
Looks like the same story in 08.02.02. For example, the application entry point in rx_diagnostics.c
follows the probe-check-initialise ordering:
dwt_probe((struct dwt_probe_s *)&dw3000_probe_interf);
while (!dwt_checkidlerc()) /* Need to make sure DW IC is in IDLE_RC before proceeding */ { };
if (dwt_initialise(DWT_DW_INIT) == DWT_ERROR)
dw3000_probe_interf
is defined in both the nRF52840 and STM_Nucleo projects in deca_probe_interface.c
as:
const struct dwt_probe_s dw3000_probe_interf =
{
.dw = NULL,
.spi = (void*)&dw3000_spi_fct,
.wakeup_device_with_io = wakeup_device_with_io,
.driver_list = (struct dwt_driver_s **)tmp_ptr,
.dw_driver_num = 2,
};
That NULL dw
gets set to &static_dw
in dwt_probe()
, as defined in deca_compat.c
. static_dw
is initialised to all zeros, and dwt_probe()
only assigns a few fields - priv
is not one of them.
So I can’t see how dw->priv
can be anything other than NULL by the time dwt_checkidlerc()
runs. I’m obviously missing something fundamental here, so I’m looking forward to your findings!