DW3xxx_XR6.0C_24Feb2022 dw_drivers requirements

Hi, I’m trying to port the DW3xxx_XR6.0C_24Feb2022 release to Zephyr. It seems the library needs a symbol dw_drivers to be defined, can you explain how this is supposed to be set up?

Hi br1,

you’re right, __dw_drivers_start and __dw_drivers_end must be defined properly in your linker and then you can call the probe function in order to use the right driver .

SECTION_PROLOGUE(.dw_drivers,)
{
. = ALIGN(4);
dw_drivers_load_start = .;
dw_drivers_start = .;
__dw_drivers_start = dw_drivers_start;
KEEP((.dw_drivers .dw_drivers.))
. = ALIGN(4);
} GROUP_LINK_IN(ROMABLE_REGION)

dw_drivers_end = dw_drivers_start + SIZEOF(.dw_drivers);
dw_drivers_size = SIZEOF(.dw_drivers);
__dw_drivers_end = dw_drivers_end;
dw_drivers_load_end = dw_drivers_end;

Celine

Hi, thank you for the answer. This script needed some fixup to be working with Nordic Connect SDK and it seems it is not sufficient. Please check out our current WIP at

Especially, this seems to be necessary:

It’s a bit strange for a library to require a custom linker script. Could you help us to make it work on Zephyr/Nordic Connect SDK?

Hi, I don’t work with a Nordic Microcontroller or cmake but have you tried to link the whole archive with the linker flags “-Wl,–whole-archive -ldwt_uwb_driver-m4-hfp-6.0.7 -Wl,–no-whole-archive”?

1 Like

Hi @br1 ,

If you’ve modified your linker, I don’t think you need the following code, but I didn’t see the dwt_probe function in you code, you have to call this function after your dw3000_init() in order to select properly the driver.

//TEST
#if 0
struct dwt_driver_s __dw_drivers_start[3] attribute((section(".dw_drivers")));
struct dwt_driver_s *__dw_drivers_end attribute((section(".dw_drivers")));
#endif
extern struct dwt_driver_s *dw3000_driver;
extern struct dwt_driver_s *dw3700_driver;
extern struct dwt_driver_s *dw3720_driver;

//TEST

#if 1
/* Access library symbols (perhaps removed by optimizing compiler?) */
uint32_t fee = &dw3000_driver;
printk(“foo 0x%x\n”, fee);
uint32_t fie = &dw3700_driver;
printk(“foo 0x%x\n”, fie);
uint32_t foe = &dw3720_driver;
printk(“foo 0x%x\n”, foe);
#else
memcpy(&__dw_drivers_start[0], &dw3000_driver, sizeof(struct dwt_driver_s));
memcpy(&__dw_drivers_start[1], &dw3700_driver, sizeof(struct dwt_driver_s));
memcpy(&__dw_drivers_start[2], &dw3720_driver, sizeof(struct dwt_driver_s));
__dw_drivers_end = &__dw_drivers_start[0] + 3;
#endif

Celine

Hello @Celine,

You are correct. The above code is not needed when using the custom linker script:

SECTION_PROLOGUE(.dw_drivers,,)
{
. = ALIGN(4);
dw_drivers_load_start = .;
dw_drivers_start = .;
__dw_drivers_start = dw_drivers_start;
KEEP(*(.dw_drivers .dw_drivers.))
. = ALIGN(4);
} GROUP_LINK_IN(ROMABLE_REGION)

dw_drivers_end = dw_drivers_start + SIZEOF(.dw_drivers);
dw_drivers_size = SIZEOF(.dw_drivers);
__dw_drivers_end = dw_drivers_end;
dw_drivers_load_end = dw_drivers_end;

together with the linker flags suggested by @tobias
The code existed before the custom linker script requirement was known
BTW, is it possible to expose a library API so the custom linker script is not required?

The dwt_probe() call is made in an application example after dw3000_init().

Another issue is a crash on ex_02g_simple_rx_sts_sdc example if -O2, … are used (default is -O0). The crash occurs in standard DW3xxx_XR6.0C_24Feb2022 release
under nRF52 SDK (it is not a Zephyr issue). It may possibly be caused by write to stack
argument in library function using wrong length (e.g. writing *int instead of *short).

Carl

Hi Carl,

is it possible to expose a library API so the custom linker script is not required?
No, for the moment we don’t want to expose API, so the linker modification is required

Celine

Don’t you think there would be another solution which does not modify the API but would get rid of the custom linker script?

May I add here that the whole-archive linker flag forces us to load the whole library to flash, also functions we might not use, and which would otherwise get optimized out, for example the 24KB big dwt_ioctl() function. That wastes a lot of space in a memory constrained environment (like nRF52 chips).

Also, what’s the use of the probe function? To go thru the array of drivers (dw3000_driver, dw3700_driver and dw3720_driver) and select one that matches the HW DEVID, right? That could be done easily internally in the library without imposing special linker requirements! Or even easier, it would be totally acceptable for the library user to specify the chip present in an initialization (or probe) function.

Honestly, this is the worst library I was ever forced to link to.

Especially since you chose to make this a closed source library, you’d have to provide a certain product quality and think more about your users and design a proper API without needlessly imposing restrictions.

Hi @br1 ,

Which optimization option are you using? With -O3 you should be able to remove unused functions

Sorry for your disappointment, I take your point and will pass it on to the team . This mechanism is also done to allow the switch between shielded chips for example

Celine

What would be even better would be if the drivers were open source like they used to be and the user manual for the chip actually included everything you need to know in order to use it.

Right now the only reason I’m looking at the DW3000 is because I’m already using the DW1000.

As far as I understand the -03 optimization flag applies to the compiler, not the linker. --whole-archive forces the linker to link the whole archive, not optimizing out unused symbols. There may be reasons to do that, but I do not think that this is necessary in this case and that its bad library design. Of course having an open source library like it was in Decawaves times would be the best option.