Hello Nordic Support,
I am developing a bare-metal, non-secure firmware for nRF9160 using nrf_modem from SDK nrfxlib v2.9.0, without Zephyr or RTOS.
I followed the porting guide here:
https://docs.nordicsemi.com/bundle/ncs-latest/page/nrfxlib/nrf_modem/doc/ug_nrf_modem_porting_os.html
However, calling nrf_modem_init() consistently fails with:
Modem init failed: -22
which maps to -EINVAL.
/*********************************************************************
* SEGGER Microcontroller GmbH *
* The Embedded Experts *
**********************************************************************
-------------------------- END-OF-HEADER -----------------------------
File : main_ns.c
Purpose : Generic application start
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <nrfx.h>
#include <nrf_gpio.h>
#include <nrf_errno.h>
#include <nrf.h>
#include <pins_def.h>
#include <nrfx_ipc.h>
#include <nrf_modem.h>
#include <nrf_modem_os.h>
#include "NSCFunctions.h"
#define SHMEM_TX_SIZE ( 0x3000 ) // 12 KB
#define SHMEM_RX_SIZE ( 0x3000 )
#define SHMEM_TRACE_SIZE ( 0x3000 )
#define SHMEM_SIZE (NRF_MODEM_CELLULAR_SHMEM_CTRL_SIZE + SHMEM_TX_SIZE + SHMEM_RX_SIZE + SHMEM_TRACE_SIZE)
// Create one contiguous memory space for the buffers required by the modem driver
typedef struct {
uint8_t nrf_modem_ctrl[NRF_MODEM_CELLULAR_SHMEM_CTRL_SIZE];
uint8_t nrf_modem_tx[SHMEM_TX_SIZE];
uint8_t nrf_modem_rx[SHMEM_RX_SIZE];
uint8_t nrf_modem_trace[SHMEM_TRACE_SIZE];
} nrf_modem_bufs_t;
static nrf_modem_bufs_t modem_shm __attribute__(( section(".modem_shm"), aligned(4)));
const struct nrf_modem_shmem_cfg modem_shmem_cfg = {
.ctrl = {
.base = (uint32_t)&modem_shm.nrf_modem_ctrl,
.size = NRF_MODEM_CELLULAR_SHMEM_CTRL_SIZE,
},
.tx = {
.base = (uint32_t)&modem_shm.nrf_modem_tx,
.size = SHMEM_TX_SIZE,
},
.rx = {
.base = (uint32_t)&modem_shm.nrf_modem_rx,
.size = SHMEM_RX_SIZE,
},
.trace = {
.base = (uint32_t)&modem_shm.nrf_modem_trace,
.size = SHMEM_TRACE_SIZE,
}
};
//***********************************
// modem_fault_handler
//***********************************
void modem_fault_handler(struct nrf_modem_fault_info *info)
{
printf("MODEM FAULT! PC=0x%08X Reason=%u\n", info->program_counter, info->reason);
}
void nrf_modem_os_init(void)
{
/* Initialize the glue layer and required peripherals. */
}
void nrf_modem_os_shutdown(void)
{
/* Deinitialize the glue layer.
When shutdown is called, all pending calls to nrf_modem_os_timedwait
shall exit and return -NRF_ESHUTDOWN. */
}
void *nrf_modem_os_shm_tx_alloc(size_t bytes)
{
/* Allocate a buffer on the TX area of shared memory. */
}
void nrf_modem_os_shm_tx_free(void *mem)
{
/* Free a shared memory buffer in the TX area. */
}
void *nrf_modem_os_alloc(size_t bytes)
{
/* Allocate a buffer on the library heap. */
}
void nrf_modem_os_free(void *mem)
{
/* Free a memory buffer in the library heap. */
}
void nrf_modem_os_busywait(int32_t usec)
{
/* Busy wait for a given number of microseconds. */
}
int32_t nrf_modem_os_timedwait(uint32_t context, int32_t *timeout)
{
if (!nrf_modem_is_initialized())
{
return -NRF_ESHUTDOWN;
}
/* Put a thread to sleep for a specific time or until an event occurs.
Wait for the timeout.
All waiting threads shall be woken by nrf_modem_event_notify.
A blind return value of zero will cause a blocking wait. */
if (!nrf_modem_is_initialized())
{
return -NRF_ESHUTDOWN;
}
return 0;
}
void nrf_modem_os_event_notify(uint32_t context)
{
// Notify the application that an event has occurred.
// This shall wake all threads sleeping in nrf_modem_os_timedwait.
}
void nrf_modem_os_errno_set(int errno_val)
{
/* Set OS errno. */
}
bool nrf_modem_os_is_in_isr(void)
{
// Check if executing in interrupt context.
return false;
}
int nrf_modem_os_sem_init(void **sem, unsigned int initial_count, unsigned int limit)
{
/* If multithreaded access to modem functionalities is needed, the function must allocate
* and initialize a semaphore and return its address through the `sem` parameter. If the
* address of an already allocated semaphore is provided as an input, the allocation part is
* skipped and the semaphore is only reinitialized.
*/
return 0;
}
void nrf_modem_os_sem_give(void *sem)
{
/* Give a semaphore. */
}
int nrf_modem_os_sem_take(void *sem, int timeout)
{
/* Try to take a semaphore with the given timeout. */
return 0;
}
unsigned int nrf_modem_os_sem_count_get(void *sem)
{
/* Get a semaphore's count. */
return 0;
}
int nrf_modem_os_mutex_init(void **mutex)
{
/* If multithreaded access to modem functionalities is needed, the function must allocate
* and initialize a reentrant mutex and return its address through the `mutex` parameter.
* If the address of an already allocated mutex is provided as an input, the allocation part
* is skipped and the mutex is only reinitialized.
* Mutexes are not required if multithreaded access to modem functionalities is not needed.
* In this case, the function must blindly return ``0``.
*/
return 0;
}
/*
void nrf_modem_os_mutex_unlock(void *sem)
{
// Unlock a mutex.
}
*/
int nrf_modem_os_mutex_lock(void *sem, int timeout)
{
/* Try to lock a reentrant mutex with the given timeout. */
return 0;
}
void nrf_modem_os_log(int level, const char *fmt, ...)
{
/* Generic logging procedure. */
// va_list ap;
// va_start(ap, fmt);
// vprintf(fmt, ap);
// printf("\n");
// va_end(ap);
}
void nrf_modem_os_logdump(int level, const char *str, const void *data, size_t len)
{
/* Log hex representation of object. */
}
// Configure non-secure peripherals.
void nrf_spu_periph_set(uint16_t id, uint32_t flags);
void nrf_spu_periph_clear(uint16_t id, uint32_t flags);
void nrf_spu_gpio_set(uint16_t id);
void nrf_spu_gpio_clear(uint16_t id);
// Non-secure callable function
extern uint32_t pxNSCFunctionHandler( uint32_t value );
//***********************************
// Print modem SHMEM CFG
//***********************************
void print_modem_shmem_cfg(void)
{
printf("======== Modem SHMEM Config ========\n");
printf("CTRL : base = 0x%08X, size = %u bytes\n",
(unsigned int)(uintptr_t)modem_shmem_cfg.ctrl.base,
(unsigned int)modem_shmem_cfg.ctrl.size);
printf("TX : base = 0x%08X, size = %u bytes\n",
(unsigned int)(uintptr_t)modem_shmem_cfg.tx.base,
(unsigned int)modem_shmem_cfg.tx.size);
printf("RX : base = 0x%08X, size = %u bytes\n",
(unsigned int)(uintptr_t)modem_shmem_cfg.rx.base,
(unsigned int)modem_shmem_cfg.rx.size);
printf("TRACE : base = 0x%08X, size = %u bytes\n",
(unsigned int)(uintptr_t)modem_shmem_cfg.trace.base,
(unsigned int)modem_shmem_cfg.trace.size);
printf("====================================\n");
}
//*********************************************************************
// main()
//*********************************************************************
int main(void)
{
int i, j, k = 0;
printf("Hello World!\n");
printf(nrf_modem_build_version());
printf("\n");
print_modem_shmem_cfg();
struct nrf_modem_init_params init_params = {
.shmem = modem_shmem_cfg,
.ipc_irq_prio = 0, // 0 ... 7
.fault_handler = modem_fault_handler,
.dfu_handler = NULL, // optional
};
int err = nrf_modem_init(&init_params);
if (err < 0)
{
printf("Modem init failed: %d\n", err);
}
nrf_gpio_cfg_output(2);
nrf_gpio_pin_set(2);
nrf_gpio_cfg_output(3);
nrf_gpio_pin_set(3);
nrf_gpio_cfg_output(4);
nrf_gpio_pin_set(4);
nrf_gpio_cfg_output(5);
nrf_gpio_pin_set(5);
printf("NSC function 1 call result: %d\n", entry1(2));
printf("NSC function 2 call result: %d\n", entry2(2));
j = 0;
do
{
for (i = 0; i < 10000; i++)
{
printf("Hello World %d!\n", i);;
}
nrf_gpio_pin_toggle( j + 2 );
j = ( j + 1 ) % 4;
} while (1);
}
/*************************** End of file ****************************/
Given that:
-
SHMEM areas are correctly aligned
-
Memory is below 0x20020000
-
Sizes are valid (4K + 3×12K = 40K)
-
Fault handler is defined correctly
-
nrf_modem_os_*stubs are implemented
I cannot identify why nrf_modem_init() returns -EINVAL. Could you help confirm whether this is a modem validation bug, a missing requirement, or a configuration issue?
Best regards,
Neculai