Hi,
I've been working with the nRF5x SDK for many years and happily implemented low level drivers on register level, sometimes also using the nrf_drv drivers, running FreeRTOS and using a simple makefile build system.
Now I need to port one project to the nRF5340, which means moving on to the nRF Connect SDK, and life has become hell. I don't mind using Zephyr for IPC and Bluetooth related topics, but I need full control over my device drivers as they sometimes implement critical features with hard real-time constraints. There are also scenarios where I need to connect different drivers via the PPI and handle low latency interrupts.
Developing software with Visual Studio Code and the Nordic plugin is really exhausting. Even though the plugin should have installed the necessary addons, VS Code asks me each time I start it if I want to install the plugins that should be already there (like Git and C++). Also, errors pop up and disappear all the time. And VS Code suddelny switches to other projects and/or build targets without any notice. But well, the most critical part is that I cannot get my device drivers running properly anymore.
One example: I started a new project based on zephyr/samples/basic/threads, using the nRF5340DK as a build target. There, I wanted to get the UARTE2 device running. But it is really difficult, I had problems using the nrfx_uarte driver as it didn't find UARTE2 even though I tried to enable it in proj.conf ("CONFIG_NRFX_UARTE2=y" did not work). I have lost a whole week already, and so I decided to go down to register level and implement my own UARTE driver (as I will need to add special low latency handling later anyway). But I still can't get the UARTE interface running on low level.
I have two particular question and hope somebody can help:
1. How can I get full access to the hardware devices while Zephyr is running on the background? Just including <nrf.h> or <nrf5340_application.h> does not help. To get the definitions for the UARTE2 device, I have to include <nrfx_uarte.h>. One more issue is that the UARTE device does not seem to work as expected, which brings me to my second question:
2. If I execute the following initialization code which should start receiving UART data, the TASKS_STARTRX task does not trigger an EVENTS_RXSTARTED event as expected. The device registers are initialized correctly as I can see in the VS Code plugin during debugging, but the event is not set. I observe similiar behavior when I try to transmit data instead of receiving (set the TXD buffer and size, trigger TASKS_STARTTX and wit for EVENTS_TXSTARTED which never appears. What could be the reason for this?
NRF_UARTE2->ENABLE = 0; while (NRF_UARTE2->ENABLE != 0); NRF_UARTE2->PSEL.RXD = UART_RX_PIN; NRF_UARTE2->PSEL.TXD = UART_TX_PIN; NRF_UARTE2->PSEL.RTS = -1; NRF_UARTE2->PSEL.CTS = -1; NRF_UARTE2->CONFIG = 0; NRF_UARTE2->BAUDRATE = NRF_UARTE_BAUDRATE_115200; NRF_UARTE2->SHORTS = NRF_UARTE_SHORT_ENDRX_STARTRX; NRF_UARTE2->TXD.PTR = 0; NRF_UARTE2->TXD.MAXCNT = 0; NRF_UARTE2->RXD.PTR = (uint32_t)(m_rx_buffer); NRF_UARTE2->RXD.MAXCNT = 5; NRF_UARTE2->INTENCLR = 0xFFFFFFFF; NRF_UARTE2->ENABLE = 1; while (!NRF_UARTE2->ENABLE); NRF_UARTE2->EVENTS_RXSTARTED = 0; NRF_UARTE2->TASKS_STARTRX = 1; while (!NRF_UARTE2->EVENTS_RXSTARTED); // never returns!
It doesn't matter whether I run this code in one of the sample's Zephyr threads, or it I add a main() function to the sample and run the initialization there. (I found out that I can just add a main() function and do some initialization stuff there, the threads will be started automatically once the main() function returns.)
Please help me to gain control over the silicon once more