diff --git a/targets/TARGET_NORDIC/TARGET_NRF5x/trng_api.c b/targets/TARGET_NORDIC/TARGET_NRF5x/trng_api.c index 829dac51847..aa00d60749b 100644 --- a/targets/TARGET_NORDIC/TARGET_NRF5x/trng_api.c +++ b/targets/TARGET_NORDIC/TARGET_NRF5x/trng_api.c @@ -37,21 +37,45 @@ */ #if defined(DEVICE_TRNG) -#include "trng_api.h" + +#include "hal/trng_api.h" +#include "hal/critical_section_api.h" + #include "nrf_drv_rng.h" +/* Keep track of instantiated FlashIAP objects. */ +static int nordic_trng_counter = 0; + void trng_init(trng_t *obj) { (void) obj; - (void)nrf_drv_rng_init(NULL); + /* Increment global counter inside critical section. */ + hal_critical_section_enter(); + nordic_trng_counter++; + int counter = nordic_trng_counter; + hal_critical_section_exit(); + + /* Initialize TRNG on first object only. */ + if (counter == 1) { + nrf_drv_rng_init(NULL); + } } void trng_free(trng_t *obj) { (void) obj; - nrf_drv_rng_uninit(); + /* Decrement global counter inside critical section. */ + hal_critical_section_enter(); + nordic_trng_counter--; + int counter = nordic_trng_counter; + hal_critical_section_exit(); + + /* Deinitialize TRNG when all objects have been freed. */ + if (counter == 0) { + nrf_drv_rng_uninit(); + } } /* Get random data from NRF5x TRNG peripheral. @@ -61,30 +85,35 @@ void trng_free(trng_t *obj) */ int trng_get_bytes(trng_t *obj, uint8_t *output, size_t length, size_t *output_length) { - uint8_t bytes_available; - (void) obj; + /* Query how many bytes are available. */ + uint8_t bytes_available; nrf_drv_rng_bytes_available(&bytes_available); + /* If no bytes are cached, block until at least 1 byte is available. */ if (bytes_available == 0) { nrf_drv_rng_block_rand(output, 1); *output_length = 1; } else { + /* Get up to the requested number of bytes. */ if (bytes_available > length) { bytes_available = length; } - if (nrf_drv_rng_rand(output, bytes_available) != NRF_SUCCESS) { - *output_length = 0; - return -1; - } else { + ret_code_t result = nrf_drv_rng_rand(output, bytes_available); + + /* Set output length with available bytes. */ + if (result == NRF_SUCCESS) { *output_length = bytes_available; + } else { + *output_length = 0; } } - return 0; + /* Set return value based on how many bytes was read. */ + return (*output_length == 0) ? -1 : 0; } #endif diff --git a/targets/targets.json b/targets/targets.json index c365f51257a..a1630b0b8ab 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -3442,6 +3442,7 @@ "device_has": [ "ITM", "FLASH", + "TRNG", "STCLK_OFF_DURING_SLEEP" ], "extra_labels": [ @@ -3475,7 +3476,7 @@ "supported_form_factors": ["ARDUINO"], "inherits": ["MCU_NRF52832"], "macros_add": ["BOARD_PCA10040", "NRF52_PAN_12", "NRF52_PAN_15", "NRF52_PAN_58", "NRF52_PAN_55", "NRF52_PAN_54", "NRF52_PAN_31", "NRF52_PAN_30", "NRF52_PAN_51", "NRF52_PAN_36", "NRF52_PAN_53", "S132", "CONFIG_GPIO_AS_PINRESET", "BLE_STACK_SUPPORT_REQD", "SWI_DISABLE0", "NRF52_PAN_20", "NRF52_PAN_64", "NRF52_PAN_62", "NRF52_PAN_63"], - "device_has_add": ["ANALOGIN", "I2C", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPI_ASYNCH", "SPISLAVE", "TRNG"], + "device_has_add": ["ANALOGIN", "I2C", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPI_ASYNCH", "SPISLAVE"], "release_versions": ["5"], "device_name": "nRF52832_xxAA" }, @@ -3549,6 +3550,7 @@ "device_has": [ "ITM", "FLASH", + "TRNG", "STCLK_OFF_DURING_SLEEP" ], "extra_labels": [ @@ -3582,7 +3584,7 @@ "supported_form_factors": ["ARDUINO"], "inherits": ["MCU_NRF52840"], "macros_add": ["BOARD_PCA10056", "CONFIG_GPIO_AS_PINRESET", "SWI_DISABLE0", "NRF52_ERRATA_20"], - "device_has_add": ["ANALOGIN", "I2C", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "TRNG"], + "device_has_add": ["ANALOGIN", "I2C", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE"], "release_versions": ["5"], "device_name": "nRF52840_xxAA", "bootloader_supported": true