4 changes: 4 additions & 0 deletions features/filesystem/littlefs/littlefs/tests/test_paths.sh
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ tests/test.py << TEST
lfs_stat(&lfs, "/", &info) => 0;
info.type => LFS_TYPE_DIR;
strcmp(info.name, "/") => 0;
lfs_mkdir(&lfs, "/") => LFS_ERR_EXIST;
lfs_file_open(&lfs, &file[0], "/", LFS_O_WRONLY | LFS_O_CREAT)
=> LFS_ERR_ISDIR;
lfs_unmount(&lfs) => 0;
TEST

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,12 @@ USBHAL::USBHAL(void) {
__HAL_RCC_USB_OTG_HS_ULPI_CLK_ENABLE();
__HAL_RCC_USB_OTG_HS_CLK_ENABLE();

#elif defined(TARGET_STEVAL_3DP001V1)
__HAL_RCC_GPIOB_CLK_ENABLE();
pin_function(PA_11, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF10_OTG_FS)); // DM
pin_function(PA_12, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF10_OTG_FS)); // DP
__HAL_RCC_USB_OTG_FS_CLK_ENABLE();

#else
#error "USB pins are not configured !"
#endif
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#if defined(TARGET_NUCLEO_F207ZG) || \
defined(TARGET_NUCLEO_F401RE) || \
defined(TARGET_STEVAL_3DP001V1) || \
defined(TARGET_NUCLEO_F411RE) || \
defined(TARGET_NUCLEO_F412ZG) || \
defined(TARGET_NUCLEO_F413ZH) || \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,11 @@ USBHALHost::USBHALHost()
pin_function(PA_10, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_PULLUP, GPIO_AF10_OTG_FS)); // ID
pin_function(PC_11, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF10_OTG_FS)); // VBUS

#elif defined(TARGET_STEVAL_3DP001V1)
__HAL_RCC_GPIOA_CLK_ENABLE();
pin_function(PA_11, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF10_OTG_FS)); // DM
pin_function(PA_12, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF10_OTG_FS)); // DP

#else
#error "USB pins are not configured !"
#endif
Expand Down
4 changes: 2 additions & 2 deletions mbed.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@
#ifndef MBED_H
#define MBED_H

#define MBED_LIBRARY_VERSION 160
#define MBED_LIBRARY_VERSION 161

#if MBED_CONF_RTOS_PRESENT
// RTOS present, this is valid only for mbed OS 5
#define MBED_MAJOR_VERSION 5
#define MBED_MINOR_VERSION 7
#define MBED_PATCH_VERSION 6
#define MBED_PATCH_VERSION 7

#else
// mbed 2
Expand Down
3 changes: 2 additions & 1 deletion platform/mbed_retarget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -740,12 +740,13 @@ extern "C" uint32_t __HeapLimit;
extern "C" int errno;

// Dynamic memory allocation related syscall.
#if defined(TARGET_NUVOTON)
#if (defined(TARGET_NUVOTON) || defined(TWO_RAM_REGIONS))

// Overwrite _sbrk() to support two region model (heap and stack are two distinct regions).
// __wrap__sbrk() is implemented in:
// TARGET_NUMAKER_PFM_NUC472 targets/TARGET_NUVOTON/TARGET_NUC472/TARGET_NUMAKER_PFM_NUC472/TOOLCHAIN_GCC_ARM/nuc472_retarget.c
// TARGET_NUMAKER_PFM_M453 targets/TARGET_NUVOTON/TARGET_M451/TARGET_NUMAKER_PFM_M453/TOOLCHAIN_GCC_ARM/m451_retarget.c
// TARGET_STM32L4 targets/TARGET_STM/TARGET_STM32L4/TARGET_STM32L4/l4_retarget.c
extern "C" void *__wrap__sbrk(int incr);
extern "C" caddr_t _sbrk(int incr) {
return (caddr_t) __wrap__sbrk(incr);
Expand Down
6 changes: 3 additions & 3 deletions platform/mbed_sleep.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
#ifndef MBED_SLEEP_H
#define MBED_SLEEP_H

#include "sleep_api.h"
#include "hal/sleep_api.h"
#include "mbed_toolchain.h"
#include <stdbool.h>

Expand Down Expand Up @@ -128,7 +128,7 @@ void sleep_manager_sleep_auto(void);
* Flash re-programming and the USB serial port will remain active, but the mbed program will no longer be
* able to access the LocalFileSystem
*/
__INLINE static void sleep(void)
static inline void sleep(void)
{
#if !(defined(FEATURE_UVISOR) && defined(TARGET_UVISOR_SUPPORTED))
#if DEVICE_SLEEP
Expand Down Expand Up @@ -158,7 +158,7 @@ __INLINE static void sleep(void)
*/

MBED_DEPRECATED_SINCE("mbed-os-5.6", "One entry point for an application, use sleep()")
__INLINE static void deepsleep(void)
static inline void deepsleep(void)
{
#if !(defined(FEATURE_UVISOR) && defined(TARGET_UVISOR_SUPPORTED))
#if DEVICE_SLEEP
Expand Down
3 changes: 2 additions & 1 deletion rtos/TARGET_CORTEX/mbed_rtx_handlers.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ __NO_RETURN uint32_t osRtxErrorNotify (uint32_t code, void *object_id)
switch (code) {
case osRtxErrorStackUnderflow:
// Stack underflow detected for thread (thread_id=object_id)
error("CMSIS-RTOS error: Stack underflow (status: 0x%X, task ID: 0x%X, task name: %s)\n\r",
// Note: "overflow" is printed instead of "underflow" due to end user familiarity with overflow errors
error("CMSIS-RTOS error: Stack overflow (status: 0x%X, task ID: 0x%X, task name: %s)\n\r",
code, object_id, osThreadGetName(object_id));
break;
case osRtxErrorISRQueueOverflow:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
.file "irq_armv8mml.S"
.syntax unified

+#ifndef __DOMAIN_NS
#ifndef __DOMAIN_NS
.equ __DOMAIN_NS, 0
#endif

Expand Down
2 changes: 1 addition & 1 deletion targets/TARGET_ARM_SSG/TARGET_BEETLE/us_ticker.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ void us_ticker_set_interrupt(timestamp_t timestamp) {

void us_ticker_fire_interrupt(void)
{
uint32_t us_ticker_irqn1 = Timer_GetIRQn(TIMER1);
uint32_t us_ticker_irqn1 = Timer_GetIRQn(TIMER0);
NVIC_SetPendingIRQ((IRQn_Type)us_ticker_irqn1);
}

Expand Down
3 changes: 3 additions & 0 deletions targets/TARGET_Freescale/TARGET_KLXX/us_ticker.c
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,9 @@ void us_ticker_set_interrupt(timestamp_t timestamp) {

void us_ticker_fire_interrupt(void)
{
us_ticker_int_counter = 0;
us_ticker_int_remainder = 0;

#if defined(TARGET_KL43Z)
NVIC_SetPendingIRQ(LPTMR0_IRQn);
#else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,14 @@ void us_ticker_clear_interrupt(void)

void us_ticker_set_interrupt(timestamp_t timestamp)
{
uint32_t delta = timestamp - us_ticker_read();
uint32_t now_us, delta_us;

now_us = us_ticker_read();
delta_us = timestamp >= now_us ? timestamp - now_us : (uint32_t)((uint64_t)timestamp + 0xFFFFFFFF - now_us);

PIT_StopTimer(PIT, kPIT_Chnl_3);
PIT_StopTimer(PIT, kPIT_Chnl_2);
PIT_SetTimerPeriod(PIT, kPIT_Chnl_3, (uint32_t)delta);
PIT_SetTimerPeriod(PIT, kPIT_Chnl_3, (uint32_t)delta_us);
PIT_EnableInterrupts(PIT, kPIT_Chnl_3, kPIT_TimerInterruptEnable);
PIT_StartTimer(PIT, kPIT_Chnl_3);
PIT_StartTimer(PIT, kPIT_Chnl_2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,14 @@ void us_ticker_clear_interrupt(void)

void us_ticker_set_interrupt(timestamp_t timestamp)
{
uint32_t delta = timestamp - us_ticker_read();
uint32_t now_us, delta_us;

now_us = us_ticker_read();
delta_us = timestamp >= now_us ? timestamp - now_us : (uint32_t)((uint64_t)timestamp + 0xFFFFFFFF - now_us);

PIT_StopTimer(PIT, kPIT_Chnl_3);
PIT_StopTimer(PIT, kPIT_Chnl_2);
PIT_SetTimerPeriod(PIT, kPIT_Chnl_3, (uint32_t)delta);
PIT_SetTimerPeriod(PIT, kPIT_Chnl_3, (uint32_t)delta_us);
PIT_EnableInterrupts(PIT, kPIT_Chnl_3, kPIT_TimerInterruptEnable);
PIT_StartTimer(PIT, kPIT_Chnl_3);
PIT_StartTimer(PIT, kPIT_Chnl_2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,13 @@ void us_ticker_clear_interrupt(void)

void us_ticker_set_interrupt(timestamp_t timestamp)
{
uint32_t delta = timestamp - us_ticker_read();
uint32_t now_us, delta_us;

now_us = us_ticker_read();
delta_us = timestamp >= now_us ? timestamp - now_us : (uint32_t)((uint64_t)timestamp + 0xFFFFFFFF - now_us);

LPTMR_StopTimer(LPTMR0);
LPTMR_SetTimerPeriod(LPTMR0, (uint32_t)delta);
LPTMR_SetTimerPeriod(LPTMR0, (uint32_t)delta_us);
LPTMR_EnableInterrupts(LPTMR0, kLPTMR_TimerInterruptEnable);
LPTMR_StartTimer(LPTMR0);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,13 @@ void us_ticker_clear_interrupt(void)

void us_ticker_set_interrupt(timestamp_t timestamp)
{
uint32_t delta = timestamp - us_ticker_read();
uint32_t now_us, delta_us;

now_us = us_ticker_read();
delta_us = timestamp >= now_us ? timestamp - now_us : (uint32_t)((uint64_t)timestamp + 0xFFFFFFFF - now_us);

LPTMR_StopTimer(LPTMR0);
LPTMR_SetTimerPeriod(LPTMR0, (uint32_t)delta);
LPTMR_SetTimerPeriod(LPTMR0, (uint32_t)delta_us);
LPTMR_EnableInterrupts(LPTMR0, kLPTMR_TimerInterruptEnable);
LPTMR_StartTimer(LPTMR0);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,14 @@ void us_ticker_clear_interrupt(void)

void us_ticker_set_interrupt(timestamp_t timestamp)
{
uint32_t delta = timestamp - us_ticker_read();
uint32_t now_us, delta_us;

now_us = us_ticker_read();
delta_us = timestamp >= now_us ? timestamp - now_us : (uint32_t)((uint64_t)timestamp + 0xFFFFFFFF - now_us);

PIT_StopTimer(PIT, kPIT_Chnl_3);
PIT_StopTimer(PIT, kPIT_Chnl_2);
PIT_SetTimerPeriod(PIT, kPIT_Chnl_3, (uint32_t)delta);
PIT_SetTimerPeriod(PIT, kPIT_Chnl_3, (uint32_t)delta_us);
PIT_EnableInterrupts(PIT, kPIT_Chnl_3, kPIT_TimerInterruptEnable);
PIT_StartTimer(PIT, kPIT_Chnl_3);
PIT_StartTimer(PIT, kPIT_Chnl_2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,14 @@ void us_ticker_clear_interrupt(void)

void us_ticker_set_interrupt(timestamp_t timestamp)
{
uint32_t delta = timestamp - us_ticker_read();
uint32_t now_us, delta_us;

now_us = us_ticker_read();
delta_us = timestamp >= now_us ? timestamp - now_us : (uint32_t)((uint64_t)timestamp + 0xFFFFFFFF - now_us);

PIT_StopTimer(PIT, kPIT_Chnl_3);
PIT_StopTimer(PIT, kPIT_Chnl_2);
PIT_SetTimerPeriod(PIT, kPIT_Chnl_3, (uint32_t)delta);
PIT_SetTimerPeriod(PIT, kPIT_Chnl_3, (uint32_t)delta_us);
PIT_EnableInterrupts(PIT, kPIT_Chnl_3, kPIT_TimerInterruptEnable);
PIT_StartTimer(PIT, kPIT_Chnl_3);
PIT_StartTimer(PIT, kPIT_Chnl_2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ static void lptmr_isr(void)
us_ticker_irq_handler();
}

void us_ticker_init(void)
void us_ticker_init(void)
{
if (us_ticker_inited) {
return;
Expand Down Expand Up @@ -69,7 +69,7 @@ void us_ticker_init(void)
}


uint32_t us_ticker_read()
uint32_t us_ticker_read()
{
if (!us_ticker_inited) {
us_ticker_init();
Expand All @@ -78,21 +78,25 @@ uint32_t us_ticker_read()
return ~(PIT_GetCurrentTimerCount(PIT, kPIT_Chnl_1));
}

void us_ticker_disable_interrupt(void)
void us_ticker_disable_interrupt(void)
{
LPTMR_DisableInterrupts(LPTMR0, kLPTMR_TimerInterruptEnable);
}

void us_ticker_clear_interrupt(void)
void us_ticker_clear_interrupt(void)
{
LPTMR_ClearStatusFlags(LPTMR0, kLPTMR_TimerCompareFlag);
}

void us_ticker_set_interrupt(timestamp_t timestamp)
void us_ticker_set_interrupt(timestamp_t timestamp)
{
uint32_t delta = timestamp - us_ticker_read();
uint32_t now_us, delta_us;

now_us = us_ticker_read();
delta_us = timestamp >= now_us ? timestamp - now_us : (uint32_t)((uint64_t)timestamp + 0xFFFFFFFF - now_us);

LPTMR_StopTimer(LPTMR0);
LPTMR_SetTimerPeriod(LPTMR0, (uint32_t)delta);
LPTMR_SetTimerPeriod(LPTMR0, (uint32_t)delta_us);
LPTMR_EnableInterrupts(LPTMR0, kLPTMR_TimerInterruptEnable);
LPTMR_StartTimer(LPTMR0);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,14 @@ void us_ticker_clear_interrupt(void)

void us_ticker_set_interrupt(timestamp_t timestamp)
{
uint32_t delta = timestamp - us_ticker_read();
uint32_t now_us, delta_us;

now_us = us_ticker_read();
delta_us = timestamp >= now_us ? timestamp - now_us : (uint32_t)((uint64_t)timestamp + 0xFFFFFFFF - now_us);

PIT_StopTimer(PIT, kPIT_Chnl_3);
PIT_StopTimer(PIT, kPIT_Chnl_2);
PIT_SetTimerPeriod(PIT, kPIT_Chnl_3, (uint32_t)delta);
PIT_SetTimerPeriod(PIT, kPIT_Chnl_3, (uint32_t)delta_us);
PIT_EnableInterrupts(PIT, kPIT_Chnl_3, kPIT_TimerInterruptEnable);
PIT_StartTimer(PIT, kPIT_Chnl_3);
PIT_StartTimer(PIT, kPIT_Chnl_2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,14 @@ void us_ticker_clear_interrupt(void)

void us_ticker_set_interrupt(timestamp_t timestamp)
{
uint32_t delta = timestamp - us_ticker_read();
uint32_t now_us, delta_us;

now_us = us_ticker_read();
delta_us = timestamp >= now_us ? timestamp - now_us : (uint32_t)((uint64_t)timestamp + 0xFFFFFFFF - now_us);

PIT_StopTimer(PIT, kPIT_Chnl_3);
PIT_StopTimer(PIT, kPIT_Chnl_2);
PIT_SetTimerPeriod(PIT, kPIT_Chnl_3, (uint32_t)delta);
PIT_SetTimerPeriod(PIT, kPIT_Chnl_3, (uint32_t)delta_us);
PIT_EnableInterrupts(PIT, kPIT_Chnl_3, kPIT_TimerInterruptEnable);
PIT_StartTimer(PIT, kPIT_Chnl_3);
PIT_StartTimer(PIT, kPIT_Chnl_2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ void us_ticker_set_interrupt(timestamp_t timestamp)
now_us = us_ticker_read();
delta_us = timestamp >= now_us ? timestamp - now_us : (uint32_t)((uint64_t)timestamp + 0xFFFFFFFF - now_us);

uint32_t delta = timestamp - us_ticker_read();
PIT_StopTimer(PIT, kPIT_Chnl_3);
PIT_StopTimer(PIT, kPIT_Chnl_2);
PIT_SetTimerPeriod(PIT, kPIT_Chnl_3, (uint32_t)delta_us);
Expand Down
4 changes: 3 additions & 1 deletion targets/TARGET_Maxim/TARGET_MAX32600/us_ticker.c
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,9 @@ void us_ticker_set_interrupt(timestamp_t timestamp)

void us_ticker_fire_interrupt(void)
{
NVIC_SetPendingIRQ(US_TIMER_IRQn);
US_TIMER->ctrl &= ~MXC_F_TMR_CTRL_ENABLE0; // disable timer
US_TIMER->term_cnt32 = 1;
US_TIMER->ctrl |= MXC_F_TMR_CTRL_ENABLE0; // enable timer
}

//******************************************************************************
Expand Down
4 changes: 3 additions & 1 deletion targets/TARGET_Maxim/TARGET_MAX32610/us_ticker.c
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,9 @@ void us_ticker_set_interrupt(timestamp_t timestamp)

void us_ticker_fire_interrupt(void)
{
NVIC_SetPendingIRQ(US_TIMER_IRQn);
US_TIMER->ctrl &= ~MXC_F_TMR_CTRL_ENABLE0; // disable timer
US_TIMER->term_cnt32 = 1;
US_TIMER->ctrl |= MXC_F_TMR_CTRL_ENABLE0; // enable timer
}

//******************************************************************************
Expand Down
4 changes: 3 additions & 1 deletion targets/TARGET_Maxim/TARGET_MAX32620/us_ticker.c
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,9 @@ void us_ticker_set_interrupt(timestamp_t timestamp)

void us_ticker_fire_interrupt(void)
{
NVIC_SetPendingIRQ(US_TIMER_IRQn);
US_TIMER->ctrl &= ~MXC_F_TMR_CTRL_ENABLE0; // disable timer
US_TIMER->term_cnt32 = 1;
US_TIMER->ctrl |= MXC_F_TMR_CTRL_ENABLE0; // enable timer
}

//******************************************************************************
Expand Down
4 changes: 4 additions & 0 deletions targets/TARGET_Maxim/TARGET_MAX32625/PeripheralPins.c
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,10 @@ const PinMap PinMap_ADC[] = {
{ AIN_3, ADC, ADC_CH_3 },
{ AIN_4, ADC, ADC_CH_0_DIV_5 },
{ AIN_5, ADC, ADC_CH_1_DIV_5 },
{ AIN_6, ADC, ADC_CH_VDDB_DIV_4 },
{ AIN_7, ADC, ADC_CH_VDD18 },
{ AIN_8, ADC, ADC_CH_VDD12 },
{ AIN_9, ADC, ADC_CH_VRTC_DIV_2 },
{ NC, NC, 0 }
};

Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ typedef enum {
P4_0 = (4 << PORT_SHIFT), P4_1, P4_2, P4_3, P4_4, P4_5, P4_6, P4_7,

// Analog input pins
AIN_0 = (0xA << PORT_SHIFT), AIN_1, AIN_2, AIN_3, AIN_4, AIN_5,
AIN_0 = (0xA << PORT_SHIFT), AIN_1, AIN_2, AIN_3, AIN_4, AIN_5, AIN_6, AIN_7, AIN_8, AIN_9,

LED_GREEN = P3_1,
LED_RED = P3_0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ typedef enum {
P4_0 = (4 << PORT_SHIFT), P4_1, P4_2, P4_3, P4_4, P4_5, P4_6, P4_7,

// Analog input pins
AIN_0 = (0xA << PORT_SHIFT), AIN_1, AIN_2, AIN_3, AIN_4, AIN_5,
AIN_0 = (0xA << PORT_SHIFT), AIN_1, AIN_2, AIN_3, AIN_4, AIN_5, AIN_6, AIN_7, AIN_8, AIN_9,

// LEDs
LED1 = P2_4,
Expand Down
4 changes: 2 additions & 2 deletions targets/TARGET_Maxim/TARGET_MAX32625/analogin_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ float analogin_read(analogin_t *obj)
float result;

// Start conversion with no input scaling and no input buffer bypass
ADC_StartConvert(obj->channel, 0, 0);
ADC_StartConvert(obj->channel, 1, 0);

if (ADC_GetData(&tmp) == E_OVERFLOW) {
result = FLOAT_FULL_SCALE;
Expand All @@ -83,7 +83,7 @@ uint16_t analogin_read_u16(analogin_t *obj)
uint16_t result;

// Start conversion with no input scaling and no input buffer bypass
ADC_StartConvert(obj->channel, 0, 0);
ADC_StartConvert(obj->channel, 1, 0);

if (ADC_GetData(&tmp) == E_OVERFLOW) {
result = INT_FULL_SCALE;
Expand Down
6 changes: 0 additions & 6 deletions targets/TARGET_Maxim/TARGET_MAX32625/i2c_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ int i2c_stop(i2c_t *obj)
//******************************************************************************
int i2c_read(i2c_t *obj, int address, char *data, int length, int stop)
{
MBED_ASSERT(stop != 0);
return I2CM_Read(obj->i2c, address >> 1, NULL, 0, (uint8_t *)data, length);
}

Expand Down Expand Up @@ -147,11 +146,6 @@ int i2c_byte_read(i2c_t *obj, int last)
if (I2CM_WriteTxFifo(i2cm, fifo, MXC_S_I2CM_TRANS_TAG_RXDATA_NACK) != E_NO_ERROR) {
goto byte_write_err;
}

// Send the stop condition
if (I2CM_WriteTxFifo(i2cm, fifo, MXC_S_I2CM_TRANS_TAG_STOP) != E_NO_ERROR) {
goto byte_write_err;
}
} else {
if (I2CM_WriteTxFifo(i2cm, fifo, MXC_S_I2CM_TRANS_TAG_RXDATA_COUNT) != E_NO_ERROR) {
goto byte_write_err;
Expand Down
32 changes: 22 additions & 10 deletions targets/TARGET_Maxim/TARGET_MAX32625/serial_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@
MXC_F_UART_INTFL_RX_FIFO_OVERFLOW)

// Variables for managing the stdio UART
int stdio_uart_inited;
serial_t stdio_uart;
int stdio_uart_inited = 0;
serial_t stdio_uart = {0};

// Variables for interrupt driven
static uart_irq_handler irq_handler;
Expand All @@ -75,12 +75,6 @@ void serial_init(serial_t *obj, PinName tx, PinName rx)
obj->index = MXC_UART_GET_IDX(obj->uart);
obj->fifo = (mxc_uart_fifo_regs_t*)MXC_UART_GET_BASE_FIFO(obj->index);

// Manage stdio UART
if (uart == STDIO_UART) {
stdio_uart_inited = 1;
memcpy(&stdio_uart, obj, sizeof(serial_t));
}

// Record the pins requested
obj->tx = tx;
obj->rx = rx;
Expand Down Expand Up @@ -111,6 +105,12 @@ void serial_init(serial_t *obj, PinName tx, PinName rx)
obj->cfg.size = UART_DATA_SIZE_8_BITS;
obj->cfg.parity = UART_PARITY_DISABLE;

// Manage stdio UART
if (uart == STDIO_UART) {
stdio_uart_inited = 1;
stdio_uart = *obj;
}

int retval = UART_Init(obj->uart, &obj->cfg, &obj->sys_cfg);
MBED_ASSERT(retval == E_NO_ERROR);
}
Expand Down Expand Up @@ -181,7 +181,16 @@ void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_b
void uart_handler(serial_t *obj)
{
if (obj && obj->id) {
irq_handler(obj->id, RxIrq);
// Check for errors or RX Threshold
if (obj->uart->intfl & (MXC_F_UART_INTFL_RX_FIFO_NOT_EMPTY | UART_ERRORS)) {
irq_handler(obj->id, RxIrq);
obj->uart->intfl = (MXC_F_UART_INTFL_RX_FIFO_NOT_EMPTY | UART_ERRORS);
}
// Check for TX Threshold
if (obj->uart->intfl & MXC_F_UART_INTFL_TX_FIFO_AE) {
irq_handler(obj->id, TxIrq);
obj->uart->intfl = MXC_F_UART_INTFL_TX_FIFO_AE;
}
}
}

Expand All @@ -199,6 +208,9 @@ void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id)
//******************************************************************************
void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable)
{
MBED_ASSERT(obj->index < MXC_CFG_UART_INSTANCES);
objs[obj->index] = obj;

switch (obj->index) {
case 0:
NVIC_SetVector(UART0_IRQn, (uint32_t)uart0_handler);
Expand Down Expand Up @@ -250,7 +262,7 @@ void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable)
//******************************************************************************
int serial_getc(serial_t *obj)
{
int c = 0;
int c = -1;

if (obj->rx != NC) {
// Wait for data to be available
Expand Down
60 changes: 49 additions & 11 deletions targets/TARGET_Maxim/TARGET_MAX32625/spi_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,19 +167,58 @@ int spi_master_write(spi_t *obj, int value)
return *req.rx_data;
}

int spi_master_block_write(spi_t *obj, const char *tx_buffer, int tx_length,
char *rx_buffer, int rx_length, char write_fill) {
int total = (tx_length > rx_length) ? tx_length : rx_length;

for (int i = 0; i < total; i++) {
char out = (i < tx_length) ? tx_buffer[i] : write_fill;
char in = spi_master_write(obj, out);
if (i < rx_length) {
rx_buffer[i] = in;
//******************************************************************************
int spi_master_block_write(spi_t *obj, const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length, char write_fill)
{
spim_req_t req;

if (!(tx_length | rx_length) ||
(tx_length < 0) ||
(rx_length < 0)) {
return 0;
}

req.width = SPIM_WIDTH_1;
req.ssel = 0;
req.deass = 1;
req.callback = NULL;

core_util_critical_section_enter();
if (tx_length == rx_length) {
req.tx_data = (uint8_t *)tx_buffer;
req.rx_data = (uint8_t *)rx_buffer;
req.len = tx_length;
SPIM_Trans(obj->spi, &req);
} else if (tx_length < rx_length) {
req.tx_data = (tx_length > 0) ? (uint8_t *)tx_buffer : NULL;
req.rx_data = (uint8_t *)rx_buffer;
req.len = (tx_length > 0) ? tx_length : rx_length;
SPIM_Trans(obj->spi, &req);

if (tx_length) {
req.tx_data = NULL;
req.rx_data = (uint8_t *)(rx_buffer + tx_length);
req.len = rx_length - tx_length;
SPIM_Trans(obj->spi, &req);
}
} else {
req.tx_data = (uint8_t *)tx_buffer;
req.rx_data = (rx_length > 0) ? (uint8_t *)rx_buffer : NULL;
req.len = (rx_length > 0) ? rx_length : tx_length;
SPIM_Trans(obj->spi, &req);

if (rx_length) {
req.tx_data = (uint8_t *)(tx_buffer + rx_length);
req.rx_data = NULL;
req.len = tx_length - rx_length;
SPIM_Trans(obj->spi, &req);
}
}
core_util_critical_section_exit();

while (SPIM_Busy(obj->spi));

return total;
return tx_length > rx_length ? tx_length : rx_length;
}

//******************************************************************************
Expand All @@ -193,4 +232,3 @@ uint8_t spi_get_module(spi_t *obj)
{
return obj->index;
}

30 changes: 25 additions & 5 deletions targets/TARGET_Maxim/TARGET_MAX32625/us_ticker.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,11 @@

#include <stddef.h>
#include "mbed_error.h"
#include "mbed_critical.h"
#include "us_ticker_api.h"
#include "PeripheralNames.h"
#include "tmr.h"
#include "assert.h"

#define US_TIMER MXC_TMR0
#define US_TIMER_IRQn TMR0_0_IRQn
Expand All @@ -49,7 +51,7 @@ static volatile uint64_t event_cnt; // Holds the value of the next event
#define MAX_TICK_VAL ((uint64_t)0xFFFFFFFF * ticks_per_us)

//******************************************************************************
static inline void inc_current_cnt(uint32_t inc)
static inline void inc_current_cnt_no_crit(uint32_t inc)
{
// Overflow the ticker when the us ticker overflows
current_cnt += inc;
Expand All @@ -58,6 +60,14 @@ static inline void inc_current_cnt(uint32_t inc)
}
}

//******************************************************************************
static inline void inc_current_cnt(uint32_t inc)
{
core_util_critical_section_enter();
inc_current_cnt_no_crit(inc);
core_util_critical_section_exit();
}

//******************************************************************************
static inline int event_passed(uint64_t current, uint64_t event)
{
Expand Down Expand Up @@ -89,11 +99,12 @@ static void tmr_handler(void)
{
uint32_t cmp = TMR32_GetCompare(US_TIMER);
TMR32_SetCompare(US_TIMER, 0xFFFFFFFF); // reset to max value to prevent further interrupts
if (TMR32_GetFlag(US_TIMER)) {
inc_current_cnt_no_crit(cmp);
}
TMR32_ClearFlag(US_TIMER);
NVIC_ClearPendingIRQ(US_TIMER_IRQn);

inc_current_cnt(cmp);

if (event_passed(current_cnt + TMR32_GetCount(US_TIMER), event_cnt)) {
// the timestamp has expired
event_cnt = 0xFFFFFFFFFFFFFFFFULL; // reset to max value
Expand Down Expand Up @@ -162,6 +173,7 @@ uint32_t us_ticker_read(void)
uint64_t current_cnt1, current_cnt2;
uint32_t cmp, cnt;
uint32_t flag1, flag2;
static uint32_t last = 0;

if (!us_ticker_inited) {
us_ticker_init();
Expand All @@ -179,12 +191,19 @@ uint32_t us_ticker_read(void)

// Account for an unserviced interrupt
if (flag1) {
// Clear peripheral interrupt flag; leaving NVIC pending set
TMR32_ClearFlag(US_TIMER);
// Advance global count
inc_current_cnt(cmp + cnt);

current_cnt1 += cmp;
}

current_cnt1 += cnt;

return (current_cnt1 / ticks_per_us);
assert(last <= (current_cnt1 / ticks_per_us));
last = (current_cnt1 / ticks_per_us);
return last;
}

//******************************************************************************
Expand Down Expand Up @@ -228,9 +247,10 @@ void us_ticker_set_interrupt(timestamp_t timestamp)
TMR32_Start(US_TIMER);
}

//******************************************************************************
void us_ticker_fire_interrupt(void)
{
NVIC_SetPendingIRQ(US_TIMER_IRQn);
TMR32_SetCompare(US_TIMER, 1);
}

//******************************************************************************
Expand Down
2 changes: 1 addition & 1 deletion targets/TARGET_Maxim/TARGET_MAX32630/us_ticker.c
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ void us_ticker_set_interrupt(timestamp_t timestamp)

void us_ticker_fire_interrupt(void)
{
NVIC_SetPendingIRQ(US_TIMER_IRQn);
TMR32_SetCompare(US_TIMER, 1);
}

//******************************************************************************
Expand Down
14 changes: 14 additions & 0 deletions targets/TARGET_NORDIC/TARGET_MCU_NRF51822/us_ticker.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "PeripheralNames.h"
#include "nrf_delay.h"
#include "mbed_toolchain.h"
#include "mbed_critical.h"

/*
* Note: The micro-second timer API on the nRF51 platform is implemented using
Expand Down Expand Up @@ -52,6 +53,8 @@
#define RTC_UNITS_TO_MICROSECONDS(RTC_UNITS) (((RTC_UNITS) * (uint64_t)1000000) / RTC_CLOCK_FREQ)
#define MICROSECONDS_TO_RTC_UNITS(MICROS) ((((uint64_t)(MICROS) * RTC_CLOCK_FREQ) + 999999) / 1000000)

#define US_TICKER_SW_IRQ_MASK 0x1

static bool us_ticker_inited = false;
static volatile uint32_t overflowCount; /**< The number of times the 24-bit RTC counter has overflowed. */
static volatile bool us_ticker_callbackPending = false;
Expand All @@ -62,6 +65,9 @@ static bool os_tick_started = false; /**< flag indicating i
*/
static uint32_t previous_tick_cc_value = 0;

// us ticker fire interrupt flag for IRQ handler
volatile uint8_t m_common_sw_irq_flag = 0;

/*
RTX provide the following definitions which are used by the tick code:
* os_trv: The number (minus 1) of clock cycle between two tick.
Expand Down Expand Up @@ -181,6 +187,11 @@ static inline uint32_t rtc1_getCounter(void)
*/
void us_ticker_handler(void)
{
if (m_common_sw_irq_flag & US_TICKER_SW_IRQ_MASK) {
m_common_sw_irq_flag &= ~US_TICKER_SW_IRQ_MASK;
us_ticker_irq_handler();
}

if (NRF_RTC1->EVENTS_OVRFLW) {
overflowCount++;
NRF_RTC1->EVENTS_OVRFLW = 0;
Expand Down Expand Up @@ -287,7 +298,10 @@ void us_ticker_set_interrupt(timestamp_t timestamp)

void us_ticker_fire_interrupt(void)
{
core_util_critical_section_enter();
m_common_sw_irq_flag |= US_TICKER_SW_IRQ_MASK;
NVIC_SetPendingIRQ(RTC1_IRQn);
core_util_critical_section_exit();
}

void us_ticker_disable_interrupt(void)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
/*
* Copyright (c) 2013 Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, must reproduce
* the above copyright notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/

#ifndef MBED_PINNAMES_H
#define MBED_PINNAMES_H

#include "cmsis.h"

#ifdef __cplusplus
extern "C" {
#endif

typedef enum {
PIN_INPUT,
PIN_OUTPUT
} PinDirection;

#define PORT_SHIFT 3

typedef enum {
p0 = 0,
p1 = 1,
p2 = 2,
p3 = 3,
p4 = 4,
p5 = 5,
p6 = 6,
p7 = 7,
p8 = 8,
p9 = 9,
p10 = 10,
p11 = 11,
p12 = 12,
p13 = 13,
p14 = 14,
p15 = 15,
p16 = 16,
p17 = 17,
p18 = 18,
p19 = 19,
p20 = 20,
p21 = 21,
p22 = 22,
p23 = 23,
p24 = 24,
p25 = 25,
p26 = 26,
p27 = 27,
p28 = 28,
p29 = 29,
p30 = 30,

P0_0 = p0,
P0_1 = p1,
P0_2 = p2,
P0_3 = p3,
P0_4 = p4,
P0_5 = p5,
P0_6 = p6,
P0_7 = p7,

P0_8 = p8,
P0_9 = p9,
P0_10 = p10,
P0_11 = p11,
P0_12 = p12,
P0_13 = p13,
P0_14 = p14,
P0_15 = p15,

P0_16 = p16,
P0_17 = p17,
P0_18 = p18,
P0_19 = p19,
P0_20 = p20,
P0_21 = p21,
P0_22 = p22,
P0_23 = p23,

P0_24 = p24,
P0_25 = p25,
P0_26 = p26,
P0_27 = p27,
P0_28 = p28,
P0_29 = p29,
P0_30 = p30,
/*
┏━━━━━━━━━━┓
UART┬── TX D0 ╶┨ 1 ╒╕ 16 ┠╴ VCC
└── RX D1 ╶┨ 2 ╘╛ 15 ┠╴ D8 SCL ─┬I²C
D2 ╶┨ 3 14 ┠╴ D7 SDA ─┘
SPI┬ MOSI D3 ╶┨ 4 13 ┠╴ A0
│ MISO D4 ╶┨ 5 ┌──┐12 ┠╴ A1
│ SEL D5 ╶┨ 6 └──┘11 ┠╴ D9 AREF
└─ CLK D4 ╶┨ 7 10 ┠╴ A2
GND ╶┨ 8 :: 9 ┠╴ A3
┗━━━━━━━━━━┛
*/

OSHCHIP_PIN_1 = p20,
OSHCHIP_PIN_2 = p18,
OSHCHIP_PIN_3 = p16,
OSHCHIP_PIN_4 = p15,
OSHCHIP_PIN_5 = p12,
OSHCHIP_PIN_6 = p11,
OSHCHIP_PIN_7 = p9,
OSHCHIP_PIN_9 = p1,
OSHCHIP_PIN_10 = p2,
OSHCHIP_PIN_11 = p0,
OSHCHIP_PIN_12 = p27,
OSHCHIP_PIN_13 = p26,
OSHCHIP_PIN_14 = p24,
OSHCHIP_PIN_15 = p21,

LED1 = p8,
LED2 = p5,
LED3 = p3,

LED_RED = LED1,
LED_GREEN = LED2,
LED_BLUE = LED3,

RX_PIN_NUMBER = OSHCHIP_PIN_2,
TX_PIN_NUMBER = OSHCHIP_PIN_1,
CTS_PIN_NUMBER = (int)0xFFFFFFFF, //no connection
RTS_PIN_NUMBER = (int)0xFFFFFFFF, //no connection

// mBed interface Pins
USBTX = TX_PIN_NUMBER,
USBRX = RX_PIN_NUMBER,

SPI_PSELMOSI0 = OSHCHIP_PIN_4,
SPI_PSELMISO0 = OSHCHIP_PIN_5,
SPI_PSELSS0 = OSHCHIP_PIN_6,
SPI_PSELSCK0 = OSHCHIP_PIN_7,

SPI_PSELMOSI1 = OSHCHIP_PIN_4,
SPI_PSELMISO1 = OSHCHIP_PIN_5,
SPI_PSELSS1 = OSHCHIP_PIN_6,
SPI_PSELSCK1 = OSHCHIP_PIN_7,

SPIS_PSELMOSI = OSHCHIP_PIN_4,
SPIS_PSELMISO = OSHCHIP_PIN_5,
SPIS_PSELSS = OSHCHIP_PIN_6,
SPIS_PSELSCK = OSHCHIP_PIN_7,

I2C_SDA0 = OSHCHIP_PIN_14,
I2C_SCL0 = OSHCHIP_PIN_15,

D0 = OSHCHIP_PIN_1,
D1 = OSHCHIP_PIN_2,
D2 = OSHCHIP_PIN_3,
D3 = OSHCHIP_PIN_4,
D4 = OSHCHIP_PIN_5,
D5 = OSHCHIP_PIN_6,
D6 = OSHCHIP_PIN_7,
D7 = OSHCHIP_PIN_15,
D8 = OSHCHIP_PIN_14,
D9 = OSHCHIP_PIN_11,

A0 = OSHCHIP_PIN_13,
A1 = OSHCHIP_PIN_12,
A2 = OSHCHIP_PIN_10,
A3 = OSHCHIP_PIN_9,

// Not connected
NC = (int)0xFFFFFFFF
} PinName;

typedef enum {
PullNone = 0,
PullDown = 1,
PullUp = 3,
PullDefault = PullUp
} PinMode;

#ifdef __cplusplus
}
#endif

#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// The 'features' section in 'target.json' is now used to create the device's hardware preprocessor switches.
// Check the 'features' section of the target description in 'targets.json' for more details.
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_DEVICE_H
#define MBED_DEVICE_H

#include "objects.h"

#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
/* mbed Microcontroller Library
* Copyright (c) 2013 Nordic Semiconductor
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_PINNAMES_H
#define MBED_PINNAMES_H

#include "cmsis.h"

#ifdef __cplusplus
extern "C" {
#endif

typedef enum {
PIN_INPUT,
PIN_OUTPUT
} PinDirection;

#define PORT_SHIFT 3

typedef enum {
p0 = 0,
p1 = 1,
p2 = 2,
p3 = 3,
p4 = 4,
p5 = 5,
p6 = 6,
p7 = 7,
p8 = 8,
p9 = 9,
p10 = 10,
p11 = 11,
p12 = 12,
p13 = 13,
p14 = 14,
p15 = 15,
p16 = 16,
p17 = 17,
p18 = 18,
p19 = 19,
p20 = 20,
p21 = 21,
p22 = 22,
p23 = 23,
p24 = 24,
p25 = 25,
p26 = 26,
p27 = 27,
p28 = 28,
p29 = 29,
p30 = 30,
p31 = 31,


P0_0 = p0,
P0_1 = p1,
P0_2 = p2,
P0_3 = p3,
P0_4 = p4,
P0_5 = p5,
P0_6 = p6,
P0_7 = p7,

P0_8 = p8,
P0_9 = p9,
P0_10 = p10,
P0_11 = p11,
P0_12 = p12,
P0_13 = p13,
P0_14 = p14,
P0_15 = p15,

P0_16 = p16,
P0_17 = p17,
P0_18 = p18,
P0_19 = p19,
P0_20 = p20,
P0_21 = p21,
P0_22 = p22,
P0_23 = p23,

P0_24 = p24,
P0_25 = p25,
P0_26 = p26,
P0_27 = p27,
P0_28 = p28,
P0_29 = p29,
P0_30 = p30,
P0_31 = p31,

// Module pins. Refer datasheet for pin numbers.
SIO_1 = P0_1,
SIO_2 = P0_2,
SIO_3 = P0_3,
SIO_4 = P0_4,
SIO_5 = P0_5,
SIO_6 = P0_6,
SIO_7 = P0_7,
SIO_8 = P0_8,
SIO_9 = P0_9, //NFC1
SIO_10 = P0_10, //NFC2
SIO_11 = P0_11,
SIO_12 = P0_12,
SIO_13 = P0_13,
SIO_14 = P0_14,
SIO_15 = P0_15,
SIO_16 = P0_16,
SIO_17 = P0_17,
SIO_18 = P0_18,
SIO_19 = P0_19,
SIO_20 = P0_20,

SIO_22 = P0_22,
SIO_23 = P0_23,
SIO_24 = P0_24,
SIO_25 = P0_25,
SIO_26 = P0_26,
SIO_27 = P0_27,
SIO_28 = P0_28,
SIO_29 = P0_29,
SIO_30 = P0_30,
SIO_31 = P0_31,
SIO_0 = P0_0,

// Not connected
NC = (int)0xFFFFFFFF,

//Mbed MTB pin defines.
P_1 = NC,
P_2 = SIO_24, //MISO
P_3 = SIO_23, //MOSI
P_4 = SIO_22,
// P_5 = SWDIO,
// P_6 = SWDCLK,
// P_7 = NRST,
P_8 = SIO_20,
P_9 = SIO_18,
P_10 = SIO_16,
P_11 = SIO_14,
P_12 = SIO_12,
P_13 = SIO_11,
P_14 = SIO_10,
P_15 = SIO_9,
P_16 = NC,
P_17 = SIO_8,
P_18 = SIO_7,
P_19 = SIO_6,
P_20 = SIO_5,
P_21 = SIO_4,
P_22 = SIO_3,
P_23 = SIO_2,
P_24 = SIO_1,
P_25 = SIO_0,
P_26 = NC,
P_27 = NC,
P_28 = SIO_13,
P_29 = SIO_15,
P_30 = SIO_17,
P_31 = SIO_19,
P_32 = SIO_31,
P_33 = SIO_30,
P_34 = SIO_29,
P_35 = SIO_28,
P_36 = SIO_27,
P_37 = SIO_26,
P_38 = SIO_25,
P_39 = NC,

//LEDs
LED1 = SIO_28,
LED2 = SIO_29,
LED3 = SIO_30,
LED_RED = LED1,
LED_GREEN = LED2,
LED_BLUE = LED3,

GP0 = SIO_11,
//Standardized button name
BUTTON1 = GP0,

//Nordic SDK pin names
RX_PIN_NUMBER = SIO_8,
TX_PIN_NUMBER = SIO_6,
CTS_PIN_NUMBER = SIO_7,
RTS_PIN_NUMBER = SIO_5,

// mBed interface Pins
USBTX = TX_PIN_NUMBER,
USBRX = RX_PIN_NUMBER,

SPI_MOSI = SIO_23,
SPI_MISO = SIO_24,
SPI_SS0 = SIO_17, //CS for LCD on MTB
SPI_SS1 = SIO_10, //CS for SD card on MTB
SPI_SCK1 = SIO_25,
SPI_SCK2 = SIO_31,

//Default SPI
SPI_SCK = SPI_SCK1,
SPI_CS = SPI_SS1,

I2C_SDA = SIO_26,
I2C_SCL = SIO_27,

//MTB aliases
GP1 = SIO_13,
AIN0 = SIO_2,
AIN1 = SIO_3,
AIN2 = SIO_4,
GP2 = SIO_10,
GP3 = SIO_9,
GP4 = SIO_22,
GP5 = SIO_19, //A0 for LCD on MTB
GP6 = SIO_18, //RESET for LCD on MTB
GP7 = SIO_17,
GP8 = SIO_15,

} PinName;

typedef enum {
PullNone = 0,
PullDown = 1,
PullUp = 3,
PullDefault = PullUp
} PinMode;

#ifdef __cplusplus
}
#endif

#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// The 'features' section in 'target.json' is now used to create the device's hardware preprocessor switches.
// Check the 'features' section of the target description in 'targets.json' for more details.
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_DEVICE_H
#define MBED_DEVICE_H

#include "objects.h"

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@
#define NRF_MAXIMUM_LATENCY_US 2000

/* RNG */
#define RNG_ENABLED 0
#define RNG_ENABLED 1

#if (RNG_ENABLED == 1)
#define RNG_CONFIG_ERROR_CORRECTION true
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,281 @@
/*
* Copyright (c) 2014 Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, must reproduce
* the above copyright notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/

/**
* @file
* @brief RNG HAL API.
*/

#ifndef NRF_RNG_H__
#define NRF_RNG_H__
/**
* @defgroup nrf_rng_hal RNG HAL
* @{
* @ingroup nrf_rng
* @brief Hardware access layer for managing the random number generator (RNG).
*/

#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include "nrf.h"

#ifdef __cplusplus
extern "C" {
#endif

#define NRF_RNG_TASK_SET (1UL)
#define NRF_RNG_EVENT_CLEAR (0UL)
/**
* @enum nrf_rng_task_t
* @brief RNG tasks.
*/
typedef enum /*lint -save -e30 -esym(628,__INTADDR__) */
{
NRF_RNG_TASK_START = offsetof(NRF_RNG_Type, TASKS_START), /**< Start the random number generator. */
NRF_RNG_TASK_STOP = offsetof(NRF_RNG_Type, TASKS_STOP) /**< Stop the random number generator. */
} nrf_rng_task_t; /*lint -restore */

/**
* @enum nrf_rng_event_t
* @brief RNG events.
*/
typedef enum /*lint -save -e30 -esym(628,__INTADDR__) */
{
NRF_RNG_EVENT_VALRDY = offsetof(NRF_RNG_Type, EVENTS_VALRDY) /**< New random number generated event. */
} nrf_rng_event_t; /*lint -restore */

/**
* @enum nrf_rng_int_mask_t
* @brief RNG interrupts.
*/
typedef enum
{
NRF_RNG_INT_VALRDY_MASK = RNG_INTENSET_VALRDY_Msk /**< Mask for enabling or disabling an interrupt on VALRDY event. */
} nrf_rng_int_mask_t;

/**
* @enum nrf_rng_short_mask_t
* @brief Types of RNG shortcuts.
*/
typedef enum
{
NRF_RNG_SHORT_VALRDY_STOP_MASK = RNG_SHORTS_VALRDY_STOP_Msk /**< Mask for setting shortcut between EVENT_VALRDY and TASK_STOP. */
} nrf_rng_short_mask_t;

/**
* @brief Function for enabling interrupts.
*
* @param[in] rng_int_mask Mask of interrupts.
*/
__STATIC_INLINE void nrf_rng_int_enable(uint32_t rng_int_mask);

/**
* @brief Function for disabling interrupts.
*
* @param[in] rng_int_mask Mask of interrupts.
*/
__STATIC_INLINE void nrf_rng_int_disable(uint32_t rng_int_mask);

/**
* @brief Function for getting the state of a specific interrupt.
*
* @param[in] rng_int_mask Interrupt.
*
* @retval true If the interrupt is not enabled.
* @retval false If the interrupt is enabled.
*/
__STATIC_INLINE bool nrf_rng_int_get(nrf_rng_int_mask_t rng_int_mask);

/**
* @brief Function for getting the address of a specific task.
*
* This function can be used by the PPI module.
*
* @param[in] rng_task Task.
*/
__STATIC_INLINE uint32_t * nrf_rng_task_address_get(nrf_rng_task_t rng_task);

/**
* @brief Function for setting a specific task.
*
* @param[in] rng_task Task.
*/
__STATIC_INLINE void nrf_rng_task_trigger(nrf_rng_task_t rng_task);

/**
* @brief Function for getting address of a specific event.
*
* This function can be used by the PPI module.
*
* @param[in] rng_event Event.
*/
__STATIC_INLINE uint32_t * nrf_rng_event_address_get(nrf_rng_event_t rng_event);

/**
* @brief Function for clearing a specific event.
*
* @param[in] rng_event Event.
*/
__STATIC_INLINE void nrf_rng_event_clear(nrf_rng_event_t rng_event);

/**
* @brief Function for getting the state of a specific event.
*
* @param[in] rng_event Event.
*
* @retval true If the event is not set.
* @retval false If the event is set.
*/
__STATIC_INLINE bool nrf_rng_event_get(nrf_rng_event_t rng_event);

/**
* @brief Function for setting shortcuts.
*
* @param[in] rng_short_mask Mask of shortcuts.
*
*/
__STATIC_INLINE void nrf_rng_shorts_enable(uint32_t rng_short_mask);

/**
* @brief Function for clearing shortcuts.
*
* @param[in] rng_short_mask Mask of shortcuts.
*
*/
__STATIC_INLINE void nrf_rng_shorts_disable(uint32_t rng_short_mask);

/**
* @brief Function for getting the previously generated random value.
*
* @return Previously generated random value.
*/
__STATIC_INLINE uint8_t nrf_rng_random_value_get(void);

/**
* @brief Function for enabling digital error correction.
*/
__STATIC_INLINE void nrf_rng_error_correction_enable(void);

/**
* @brief Function for disabling digital error correction.
*/
__STATIC_INLINE void nrf_rng_error_correction_disable(void);

/**
*@}
**/

#ifndef SUPPRESS_INLINE_IMPLEMENTATION

__STATIC_INLINE void nrf_rng_int_enable(uint32_t rng_int_mask)
{
NRF_RNG->INTENSET = rng_int_mask;
}

__STATIC_INLINE void nrf_rng_int_disable(uint32_t rng_int_mask)
{
NRF_RNG->INTENCLR = rng_int_mask;
}

__STATIC_INLINE bool nrf_rng_int_get(nrf_rng_int_mask_t rng_int_mask)
{
return (bool)(NRF_RNG->INTENCLR & rng_int_mask);
}

__STATIC_INLINE uint32_t * nrf_rng_task_address_get(nrf_rng_task_t rng_task)
{
return (uint32_t *)((uint8_t *)NRF_RNG + rng_task);
}

__STATIC_INLINE void nrf_rng_task_trigger(nrf_rng_task_t rng_task)
{
*((volatile uint32_t *)((uint8_t *)NRF_RNG + rng_task)) = NRF_RNG_TASK_SET;
}

__STATIC_INLINE uint32_t * nrf_rng_event_address_get(nrf_rng_event_t rng_event)
{
return (uint32_t *)((uint8_t *)NRF_RNG + rng_event);
}

__STATIC_INLINE void nrf_rng_event_clear(nrf_rng_event_t rng_event)
{
*((volatile uint32_t *)((uint8_t *)NRF_RNG + rng_event)) = NRF_RNG_EVENT_CLEAR;
#if __CORTEX_M == 0x04
volatile uint32_t dummy = *((volatile uint32_t *)((uint8_t *)NRF_RNG + rng_event));
(void)dummy;
#endif
}

__STATIC_INLINE bool nrf_rng_event_get(nrf_rng_event_t rng_event)
{
return (bool) * ((volatile uint32_t *)((uint8_t *)NRF_RNG + rng_event));
}

__STATIC_INLINE void nrf_rng_shorts_enable(uint32_t rng_short_mask)
{
NRF_RNG->SHORTS |= rng_short_mask;
}

__STATIC_INLINE void nrf_rng_shorts_disable(uint32_t rng_short_mask)
{
NRF_RNG->SHORTS &= ~rng_short_mask;
}

__STATIC_INLINE uint8_t nrf_rng_random_value_get(void)
{
return (uint8_t)(NRF_RNG->VALUE & RNG_VALUE_VALUE_Msk);
}

__STATIC_INLINE void nrf_rng_error_correction_enable(void)
{
NRF_RNG->CONFIG |= RNG_CONFIG_DERCEN_Msk;
}

__STATIC_INLINE void nrf_rng_error_correction_disable(void)
{
NRF_RNG->CONFIG &= ~RNG_CONFIG_DERCEN_Msk;
}

#endif

#ifdef __cplusplus
}
#endif

#endif /* NRF_RNG_H__ */
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
/* Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved.
*
* The information contained herein is property of Nordic Semiconductor ASA.
* Terms and conditions of usage are described in detail in NORDIC
* SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
*
* Licensees are granted free, non-transferable use of the information. NO
* WARRANTY of ANY KIND is provided. This heading must NOT be removed from
* the file.
*
*/

#include <stdint.h>
#include <stddef.h>

#include "nrf_drv_rng.h"
#include "nrf_assert.h"
#include "nrf_drv_common.h"
#include "nordic_common.h"
#include "nrf_error.h"
#include "nrf_assert.h"
#ifdef SOFTDEVICE_PRESENT
#include "nrf_sdm.h"
#include "nrf_soc.h"
#else
#include "app_fifo.h"
#include "app_util_platform.h"

static __INLINE uint32_t fifo_length(app_fifo_t * p_fifo)
{
uint32_t tmp = p_fifo->read_pos;
return p_fifo->write_pos - tmp;
}

#define FIFO_LENGTH(fifo) fifo_length(&(fifo)) /**< Macro for calculating the FIFO length. */

#endif // SOFTDEVICE_PRESENT
typedef struct
{
nrf_drv_state_t state;
#ifndef SOFTDEVICE_PRESENT
app_fifo_t rand_pool;
uint8_t buffer[RNG_CONFIG_POOL_SIZE];
#endif // SOFTDEVICE_PRESENT
} nrf_drv_rng_cb_t;

static nrf_drv_rng_cb_t m_rng_cb;
#ifndef SOFTDEVICE_PRESENT
static const nrf_drv_rng_config_t m_default_config = NRF_DRV_RNG_DEFAULT_CONFIG;
static void rng_start(void)
{
if (FIFO_LENGTH(m_rng_cb.rand_pool) <= m_rng_cb.rand_pool.buf_size_mask)
{
nrf_rng_event_clear(NRF_RNG_EVENT_VALRDY);
nrf_rng_int_enable(NRF_RNG_INT_VALRDY_MASK);
nrf_rng_task_trigger(NRF_RNG_TASK_START);
}
}


static void rng_stop(void)
{
nrf_rng_int_disable(NRF_RNG_INT_VALRDY_MASK);
nrf_rng_task_trigger(NRF_RNG_TASK_STOP);
}


#endif // SOFTDEVICE_PRESENT


ret_code_t nrf_drv_rng_init(nrf_drv_rng_config_t const * p_config)
{
uint32_t result;

if (m_rng_cb.state == NRF_DRV_STATE_UNINITIALIZED)
{
#ifndef SOFTDEVICE_PRESENT

result = app_fifo_init(&m_rng_cb.rand_pool, m_rng_cb.buffer, RNG_CONFIG_POOL_SIZE);

if (p_config == NULL)
{
p_config = &m_default_config;
}

if (result == NRF_SUCCESS)
{
if (p_config->error_correction)
{
nrf_rng_error_correction_enable();
}

nrf_drv_common_irq_enable(RNG_IRQn, p_config->interrupt_priority);

nrf_rng_shorts_disable(NRF_RNG_SHORT_VALRDY_STOP_MASK);

rng_start();
m_rng_cb.state = NRF_DRV_STATE_INITIALIZED;
}
#else
UNUSED_VARIABLE(p_config);
uint8_t softdevice_is_enabled;
result = sd_softdevice_is_enabled(&softdevice_is_enabled);

if (softdevice_is_enabled)
{
m_rng_cb.state = NRF_DRV_STATE_INITIALIZED;
}
else
{
result = NRF_ERROR_SOFTDEVICE_NOT_ENABLED;
}
#endif // SOFTDEVICE_PRESENT
}
else
{
result = NRF_ERROR_INVALID_STATE;
}
return result;
}


void nrf_drv_rng_uninit(void)
{
ASSERT(m_rng_cb.state == NRF_DRV_STATE_INITIALIZED);

m_rng_cb.state = NRF_DRV_STATE_UNINITIALIZED;
#ifndef SOFTDEVICE_PRESENT
rng_stop();
nrf_drv_common_irq_disable(RNG_IRQn);
#endif // SOFTDEVICE_PRESENT
}

ret_code_t nrf_drv_rng_bytes_available(uint8_t * p_bytes_available)
{
ret_code_t result;
ASSERT(m_rng_cb.state == NRF_DRV_STATE_INITIALIZED);

#ifndef SOFTDEVICE_PRESENT

result = NRF_SUCCESS;
*p_bytes_available = FIFO_LENGTH(m_rng_cb.rand_pool);

#else

result = sd_rand_application_bytes_available_get(p_bytes_available);

#endif // SOFTDEVICE_PRESENT

return result;
}

ret_code_t nrf_drv_rng_pool_capacity(uint8_t * p_pool_capacity)
{
ret_code_t result;
ASSERT(m_rng_cb.state == NRF_DRV_STATE_INITIALIZED);

#ifndef SOFTDEVICE_PRESENT

result = NRF_SUCCESS;
*p_pool_capacity = RNG_CONFIG_POOL_SIZE;

#else

result = sd_rand_application_pool_capacity_get(p_pool_capacity);

#endif // SOFTDEVICE_PRESENT
return result;
}

ret_code_t nrf_drv_rng_rand(uint8_t * p_buff, uint8_t length)
{
ret_code_t result;

ASSERT(m_rng_cb.state == NRF_DRV_STATE_INITIALIZED);

#ifndef SOFTDEVICE_PRESENT
if (FIFO_LENGTH(m_rng_cb.rand_pool) >= length)
{
result = NRF_SUCCESS;

for (uint32_t i = 0; (i < length) && (result == NRF_SUCCESS); i++)
{
result = app_fifo_get(&(m_rng_cb.rand_pool), &p_buff[i]);
}
rng_start();
}
else
{
result = NRF_ERROR_NO_MEM;
}
#else

result = sd_rand_application_vector_get(p_buff, length);

#endif // SOFTDEVICE_PRESENT


return result;
}

ret_code_t nrf_drv_rng_block_rand(uint8_t * p_buff, uint32_t length)
{
uint32_t count = 0, poolsz = 0;
ret_code_t result;
ASSERT(m_rng_cb.state == NRF_DRV_STATE_INITIALIZED);

result = nrf_drv_rng_pool_capacity((uint8_t *) &poolsz);
if(result != NRF_SUCCESS)
{
return result;
}

while(length)
{
uint32_t len = length >= poolsz ? poolsz : length;
while((result = nrf_drv_rng_rand(&p_buff[count], len)) != NRF_SUCCESS)
{
#ifndef SOFTDEVICE_PRESENT
ASSERT(result == NRF_ERROR_NO_MEM);
#else
ASSERT(result == NRF_ERROR_SOC_RAND_NOT_ENOUGH_VALUES);
#endif
}

length -= len;
count += len;
}

return result;
}


#ifndef SOFTDEVICE_PRESENT
void RNG_IRQHandler(void)
{
if (nrf_rng_event_get(NRF_RNG_EVENT_VALRDY) &&
nrf_rng_int_get(NRF_RNG_INT_VALRDY_MASK))
{
nrf_rng_event_clear(NRF_RNG_EVENT_VALRDY);
uint32_t nrf_error = app_fifo_put(&m_rng_cb.rand_pool, nrf_rng_random_value_get());

if ((FIFO_LENGTH(m_rng_cb.rand_pool) > m_rng_cb.rand_pool.buf_size_mask) || (nrf_error == NRF_ERROR_NO_MEM))
{
rng_stop();
}
}
}

#endif // SOFTDEVICE_PRESENT
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/* Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved.
*
* The information contained herein is property of Nordic Semiconductor ASA.
* Terms and conditions of usage are described in detail in NORDIC
* SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
*
* Licensees are granted free, non-transferable use of the information. NO
* WARRANTY of ANY KIND is provided. This heading must NOT be removed from
* the file.
*
*/

#ifndef NRF_DRV_RNG_H__
#define NRF_DRV_RNG_H__

#include <stdbool.h>
#include <stdint.h>

#include "nrf_rng.h"
#include "sdk_errors.h"
#include "nrf_drv_config.h"

/**
* @addtogroup nrf_rng RNG HAL and driver
* @ingroup nrf_drivers
* @brief Random number generator (RNG) APIs.
* @details The RNG HAL provides basic APIs for accessing the registers of the random number generator.
* The RNG driver provides APIs on a higher level.
*
* @defgroup nrf_drv_rng RNG driver
* @{
* @ingroup nrf_rng
* @brief Driver for managing the random number generator (RNG).
*/

/**@brief Struct for RNG configuration. */
typedef struct
{
bool error_correction; /**< Error correction flag. */
uint8_t interrupt_priority; /**< interrupt priority */
} nrf_drv_rng_config_t;

/**@brief RNG default configuration. */
#define NRF_DRV_RNG_DEFAULT_CONFIG \
{ \
.error_correction = RNG_CONFIG_ERROR_CORRECTION, \
.interrupt_priority = RNG_CONFIG_IRQ_PRIORITY, \
}

/**
* @brief Function for initializing the nrf_drv_rng module.
*
* @param[in] p_config Initial configuration. Default configuration used if NULL.
*
* @retval NRF_SUCCESS Driver was successfully initialized.
* @retval NRF_ERROR_INVALID_STATE Driver was already initialized.
* @retval NRF_ERROR_INVALID_LENGTH Pool size have to be a power of 2.
* @retval NRF_ERROR_SOFTDEVICE_NOT_ENABLED SoftDevice is present, but not enabled.
*/
ret_code_t nrf_drv_rng_init(nrf_drv_rng_config_t const * p_config);

/**
* @brief Function for uninitializing the nrf_drv_rng module.
*/
void nrf_drv_rng_uninit(void);

/**
* @brief Function for getting the number of currently available random bytes.
*
* @param[out] p_bytes_available The number of bytes currently available in the pool.
*
* @retval NRF_SUCCESS If the number of available random bytes was written to p_bytes_available.
*/
ret_code_t nrf_drv_rng_bytes_available(uint8_t * p_bytes_available);

/**
* @brief Function for querying the capacity of the application random pool.
*
* @param[out] p_pool_capacity The capacity of the pool.
*
* @retval NRF_SUCCESS If the capacity of the pool was written to p_pool_capacity.
*/
ret_code_t nrf_drv_rng_pool_capacity(uint8_t * p_pool_capacity);

/**
* @brief Function for getting the vector of random numbers.
*
* @param[out] p_buff Pointer to uint8_t buffer for storing the bytes.
* @param[in] length Number of bytes to take from the pool and place in p_buff.
*
* @retval NRF_SUCCESS If the requested bytes were written to p_buff.
* @retval NRF_ERROR_NO_MEM If no bytes were written to the buffer
* because there were not enough bytes available in p_buff.
* @retval NRF_ERROR_SOC_RAND_NOT_ENOUGH_VALUES If no bytes were written to the buffer
* because there were not enough bytes available in the pool.
*/
ret_code_t nrf_drv_rng_rand(uint8_t * p_buff, uint8_t length);

/**
* @brief Blocking function for getting an arbitrary array of random numbers.
*
* @note This function may execute for a substantial amount of time depending on the length of the buffer
* required and on the state of the current internal pool of random numbers.
*
* @param[out] p_buff Pointer to uint8_t buffer for storing the bytes.
* @param[in] length Number of bytes place in p_buff.
*
* @retval NRF_SUCCESS If the requested bytes were written to p_buff.
*/
ret_code_t nrf_drv_rng_block_rand(uint8_t * p_buff, uint32_t length);

/**
*@}
**/
#endif // NRF_DRV_RNG_H__
4 changes: 4 additions & 0 deletions targets/TARGET_NORDIC/TARGET_NRF5/common_rtc.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
#define OS_TICK_CC_CHANNEL 1
#define LP_TICKER_CC_CHANNEL 2

#define US_TICKER_SW_IRQ_MASK 0x1
#define LP_TICKER_SW_IRQ_MASK 0x2

#define COMMON_RTC_EVENT_COMPARE(channel) \
CONCAT_2(NRF_RTC_EVENT_COMPARE_, channel)
#define COMMON_RTC_INT_COMPARE_MASK(channel) \
Expand All @@ -47,6 +50,7 @@

extern bool m_common_rtc_enabled;
extern uint32_t volatile m_common_rtc_overflows;
extern uint8_t volatile m_common_sw_irq_flag;

void common_rtc_init(void);
uint32_t common_rtc_32bit_ticks_get(void);
Expand Down
9 changes: 5 additions & 4 deletions targets/TARGET_NORDIC/TARGET_NRF5/lp_ticker.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#if DEVICE_LOWPOWERTIMER

#include "common_rtc.h"
#include "mbed_critical.h"

void lp_ticker_init(void)
{
Expand All @@ -37,10 +38,10 @@ void lp_ticker_set_interrupt(timestamp_t timestamp)

void lp_ticker_fire_interrupt(void)
{
uint32_t closest_safe_compare = common_rtc_32bit_ticks_get() + 2;

nrf_rtc_cc_set(COMMON_RTC_INSTANCE, LP_TICKER_CC_CHANNEL, RTC_WRAP(closest_safe_compare));
nrf_rtc_event_enable(COMMON_RTC_INSTANCE, LP_TICKER_INT_MASK);
core_util_critical_section_enter();
m_common_sw_irq_flag |= LP_TICKER_SW_IRQ_MASK;
NVIC_SetPendingIRQ(RTC1_IRQn);
core_util_critical_section_exit();
}

void lp_ticker_disable_interrupt(void)
Expand Down
134 changes: 113 additions & 21 deletions targets/TARGET_NORDIC/TARGET_NRF5/trng_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,54 +37,146 @@
*/

#if defined(DEVICE_TRNG)
#include "trng_api.h"

#include "hal/trng_api.h"
#include "hal/lp_ticker_api.h"

#include "nrf_drv_rng.h"

#define DEFAULT_TIMEOUT_US (1000*1000)

/* Macro for testing if the SoftDevice is active, regardless of whether the
* application is build with the SoftDevice or not.
*/
#if defined(SOFTDEVICE_PRESENT)
#include "nrf_sdm.h"
static uint8_t wrapper(void) {
uint8_t softdevice_is_enabled;
ret_code_t result = sd_softdevice_is_enabled(&softdevice_is_enabled);
return ((result == NRF_SUCCESS) && (softdevice_is_enabled == 1));
}
#define NRF_HAL_SD_IS_ENABLED() wrapper()
#else
#define NRF_HAL_SD_IS_ENABLED() 0
#endif

/** Initialize the TRNG peripheral
*
* @param obj The TRNG object
*/
void trng_init(trng_t *obj)
{
(void) obj;

(void)nrf_drv_rng_init(NULL);
/* Initialize low power ticker. Used for timeouts. */
static bool first_init = true;

if (first_init) {
first_init = false;
lp_ticker_init();
}
}

/** Deinitialize the TRNG peripheral
*
* @param obj The TRNG object
*/
void trng_free(trng_t *obj)
{
(void) obj;

nrf_drv_rng_uninit();
}

/* Get random data from NRF5x TRNG peripheral.
/** Get random data from TRNG peripheral
*
* This implementation returns num of random bytes in range <1, length>.
* For parameters description see trng_api.h file.
* @param obj The TRNG object
* @param output The pointer to an output array
* @param length The size of output data, to avoid buffer overwrite
* @param output_length The length of generated data
* @return 0 success, -1 fail
*/
int trng_get_bytes(trng_t *obj, uint8_t *output, size_t length, size_t *output_length)
{
uint8_t bytes_available;

(void) obj;

nrf_drv_rng_bytes_available(&bytes_available);
/* Use SDK RNG driver if SoftDevice is enabled. */
if (NRF_HAL_SD_IS_ENABLED()) {

if (bytes_available == 0) {
nrf_drv_rng_block_rand(output, 1);
*output_length = 1;
} else {
/* Initialize driver once. */
static bool nordic_driver_init = true;

if (bytes_available > length) {
bytes_available = length;
if (nordic_driver_init) {
nordic_driver_init = false;
nrf_drv_rng_init(NULL);
}

if (nrf_drv_rng_rand(output, bytes_available) != NRF_SUCCESS) {
*output_length = 0;
return -1;
/* 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 {
*output_length = bytes_available;

/* Get up to the requested number of bytes. */
if (bytes_available > length) {
bytes_available = length;
}

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;
}
}
} else {

/* Initialize low-level registers once. */
static bool nordic_register_init = true;

if (nordic_register_init) {
nordic_register_init = false;

/* Enable RNG */
nrf_rng_error_correction_enable();
nrf_rng_task_trigger(NRF_RNG_TASK_START);
}

/* Copy out one byte at a time. */
size_t index = 0;
for ( ; index < length; index++) {

/* Setup stop watch for timeout. */
uint32_t start_us = lp_ticker_read();
uint32_t now_us = start_us;

/* Block until timeout or random numer is ready. */
while (((now_us - start_us) < DEFAULT_TIMEOUT_US) &&
!nrf_rng_event_get(NRF_RNG_EVENT_VALRDY)) {
now_us = lp_ticker_read();
}

/* Abort if timeout was reached. */
if ((now_us - start_us) >= DEFAULT_TIMEOUT_US) {
break;
} else {

/* Read random byte and clear event in preparation for the next byte. */
nrf_rng_event_clear(NRF_RNG_EVENT_VALRDY);
output[index] = nrf_rng_random_value_get();
}
}

/* Set output length with available bytes. */
*output_length = index;
}

return 0;
/* Set return value based on how many bytes was read. */
return (*output_length == 0) ? -1 : 0;
}

#endif
18 changes: 13 additions & 5 deletions targets/TARGET_NORDIC/TARGET_NRF5/us_ticker.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@
bool m_common_rtc_enabled = false;
uint32_t volatile m_common_rtc_overflows = 0;

// lp/us ticker fire interrupt flag for IRQ handler
volatile uint8_t m_common_sw_irq_flag = 0;

__STATIC_INLINE void rtc_ovf_event_check(void)
{
if (nrf_rtc_event_pending(COMMON_RTC_INSTANCE, NRF_RTC_EVENT_OVERFLOW)) {
Expand All @@ -74,11 +77,15 @@ void COMMON_RTC_IRQ_HANDLER(void)

rtc_ovf_event_check();

if (nrf_rtc_event_pending(COMMON_RTC_INSTANCE, US_TICKER_EVENT)) {
if ((m_common_sw_irq_flag & US_TICKER_SW_IRQ_MASK) || nrf_rtc_event_pending(COMMON_RTC_INSTANCE, US_TICKER_EVENT)) {
us_ticker_irq_handler();
}

#if DEVICE_LOWPOWERTIMER
if (m_common_sw_irq_flag & LP_TICKER_SW_IRQ_MASK) {
m_common_sw_irq_flag &= ~LP_TICKER_SW_IRQ_MASK;
lp_ticker_irq_handler();
}
if (nrf_rtc_event_pending(COMMON_RTC_INSTANCE, LP_TICKER_EVENT)) {

lp_ticker_irq_handler();
Expand Down Expand Up @@ -273,10 +280,10 @@ void us_ticker_set_interrupt(timestamp_t timestamp)

void us_ticker_fire_interrupt(void)
{
uint32_t closest_safe_compare = common_rtc_32bit_ticks_get() + 2;

nrf_rtc_cc_set(COMMON_RTC_INSTANCE, US_TICKER_CC_CHANNEL, RTC_WRAP(closest_safe_compare));
nrf_rtc_event_enable(COMMON_RTC_INSTANCE, US_TICKER_INT_MASK);
core_util_critical_section_enter();
m_common_sw_irq_flag |= US_TICKER_SW_IRQ_MASK;
NVIC_SetPendingIRQ(RTC1_IRQn);
core_util_critical_section_exit();
}

void us_ticker_disable_interrupt(void)
Expand All @@ -286,6 +293,7 @@ void us_ticker_disable_interrupt(void)

void us_ticker_clear_interrupt(void)
{
m_common_sw_irq_flag &= ~US_TICKER_SW_IRQ_MASK;
nrf_rtc_event_clear(COMMON_RTC_INSTANCE, US_TICKER_EVENT);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,13 +104,18 @@ typedef enum {
D13 = PC_5,
D14 = PE_5,
D15 = PE_4,

I2C_SCL = D15,
I2C_SDA = D14,

// FIXME: other board-specific naming
// NOTE: board-specific naming
// UART naming
USBTX = PA_8,
USBRX = PA_9,
STDIO_UART_TX = USBTX,
STDIO_UART_RX = USBRX,
SERIAL_TX = USBTX,
SERIAL_RX = USBRX,
// LED naming
LED1 = PD_2,
LED2 = PD_3,
Expand Down
201 changes: 52 additions & 149 deletions targets/TARGET_NUVOTON/TARGET_M451/lp_ticker.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,14 @@
/* Timer max counter */
#define NU_TMR_MAXCNT ((1 << NU_TMR_MAXCNT_BITSIZE) - 1)

static void tmr2_vec(void);
static void tmr3_vec(void);
/* Configure scheduled alarm */
static void arm_alarm(uint32_t cd_clk);

static int ticker_inited = 0;
static uint32_t ticker_last_read_clk = 0;
static void tmr1_vec(void);

/* NOTE: To wake the system from power down mode, timer clock source must be ether LXT or LIRC. */
/* NOTE: TIMER_2 for normal counting and TIMER_3 for scheduled alarm */
static const struct nu_modinit_s timer2_modinit = {TIMER_2, TMR2_MODULE, CLK_CLKSEL1_TMR2SEL_LXT, 0, TMR2_RST, TMR2_IRQn, (void *) tmr2_vec};
static const struct nu_modinit_s timer3_modinit = {TIMER_3, TMR3_MODULE, CLK_CLKSEL1_TMR3SEL_LXT, 0, TMR3_RST, TMR3_IRQn, (void *) tmr3_vec};
static const struct nu_modinit_s timer1_modinit = {TIMER_1, TMR1_MODULE, CLK_CLKSEL1_TMR1SEL_LXT, 0, TMR1_RST, TMR1_IRQn, (void *) tmr1_vec};

#define TIMER_MODINIT timer1_modinit

static int ticker_inited = 0;

#define TMR_CMP_MIN 2
#define TMR_CMP_MAX 0xFFFFFFu
Expand All @@ -58,43 +54,37 @@ void lp_ticker_init(void)
}
ticker_inited = 1;

ticker_last_read_clk = 0;

// Reset module
SYS_ResetModule(timer2_modinit.rsetidx);
SYS_ResetModule(timer3_modinit.rsetidx);
SYS_ResetModule(TIMER_MODINIT.rsetidx);

// Select IP clock source
CLK_SetModuleClock(timer2_modinit.clkidx, timer2_modinit.clksrc, timer2_modinit.clkdiv);
CLK_SetModuleClock(timer3_modinit.clkidx, timer3_modinit.clksrc, timer3_modinit.clkdiv);
CLK_SetModuleClock(TIMER_MODINIT.clkidx, TIMER_MODINIT.clksrc, TIMER_MODINIT.clkdiv);

// Enable IP clock
CLK_EnableModuleClock(timer2_modinit.clkidx);
CLK_EnableModuleClock(timer3_modinit.clkidx);
CLK_EnableModuleClock(TIMER_MODINIT.clkidx);

// Configure clock
uint32_t clk_timer2 = TIMER_GetModuleClock((TIMER_T *) NU_MODBASE(timer2_modinit.modname));
uint32_t prescale_timer2 = clk_timer2 / NU_TMRCLK_PER_SEC - 1;
MBED_ASSERT((prescale_timer2 != (uint32_t) -1) && prescale_timer2 <= 127);
MBED_ASSERT((clk_timer2 % NU_TMRCLK_PER_SEC) == 0);
uint32_t cmp_timer2 = TMR_CMP_MAX;
MBED_ASSERT(cmp_timer2 >= TMR_CMP_MIN && cmp_timer2 <= TMR_CMP_MAX);
uint32_t clk_timer = TIMER_GetModuleClock((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
uint32_t prescale_timer = clk_timer / NU_TMRCLK_PER_SEC - 1;
MBED_ASSERT((prescale_timer != (uint32_t) -1) && prescale_timer <= 127);
MBED_ASSERT((clk_timer % NU_TMRCLK_PER_SEC) == 0);
uint32_t cmp_timer = TMR_CMP_MAX;
MBED_ASSERT(cmp_timer >= TMR_CMP_MIN && cmp_timer <= TMR_CMP_MAX);
// Continuous mode
// NOTE: TIMER_CTL_CNTDATEN_Msk exists in NUC472, but not in M451. In M451, TIMER_CNT is updated continuously by default.
((TIMER_T *) NU_MODBASE(timer2_modinit.modname))->CTL = TIMER_PERIODIC_MODE | prescale_timer2/* | TIMER_CTL_CNTDATEN_Msk*/;
((TIMER_T *) NU_MODBASE(timer2_modinit.modname))->CMP = cmp_timer2;
((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname))->CTL = TIMER_CONTINUOUS_MODE | prescale_timer/* | TIMER_CTL_CNTDATEN_Msk*/;
((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname))->CMP = cmp_timer;

// Set vector
NVIC_SetVector(timer2_modinit.irq_n, (uint32_t) timer2_modinit.var);
NVIC_SetVector(timer3_modinit.irq_n, (uint32_t) timer3_modinit.var);
NVIC_SetVector(TIMER_MODINIT.irq_n, (uint32_t) TIMER_MODINIT.var);

NVIC_EnableIRQ(timer2_modinit.irq_n);
NVIC_EnableIRQ(timer3_modinit.irq_n);
NVIC_EnableIRQ(TIMER_MODINIT.irq_n);

TIMER_EnableInt((TIMER_T *) NU_MODBASE(timer2_modinit.modname));
TIMER_EnableWakeup((TIMER_T *) NU_MODBASE(timer2_modinit.modname));
TIMER_EnableInt((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
TIMER_EnableWakeup((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
/* NOTE: When engine is clocked by low power clock source (LXT/LIRC), we need to wait for 3 engine clocks. */
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
TIMER_Start((TIMER_T *) NU_MODBASE(timer2_modinit.modname));
TIMER_Start((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
}

timestamp_t lp_ticker_read()
Expand All @@ -103,145 +93,49 @@ timestamp_t lp_ticker_read()
lp_ticker_init();
}

TIMER_T * timer2_base = (TIMER_T *) NU_MODBASE(timer2_modinit.modname);
TIMER_T * timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname);

ticker_last_read_clk = TIMER_GetCounter(timer2_base);
return (ticker_last_read_clk / NU_TMRCLK_PER_TICK);
return (TIMER_GetCounter(timer_base) / NU_TMRCLK_PER_TICK);
}

void lp_ticker_set_interrupt(timestamp_t timestamp)
{
TIMER_Stop((TIMER_T *) NU_MODBASE(timer3_modinit.modname));

/* We need to get alarm interval from alarm timestamp `timestamp` to configure H/W timer.
*
* Because both `timestamp` and xx_ticker_read() would wrap around, we have difficulties in distinguishing
* long future event and past event. To distinguish them, we need `tick_last_read` against which
* `timestamp` is calculated out. In timeline, we would always have below after fixing wrap-around:
* (1) tick_last_read <= present_clk
* (2) tick_last_read <= alarm_ts_clk
*
*
* 1. Future event case:
*
* tick_last_read present_clk alarm_ts_clk
* | | |
* --------------------------------------------------------
* |-alarm_intvl1_clk-|
* |-------------------alarm_intvl2_clk-------------------|
*
* 2. Past event case:
*
* tick_last_read alarm_ts_clk present_clk
* | | |
* --------------------------------------------------------
* |-------------------alarm_intvl1_clk-------------------|
* |-alarm_intvl2_clk-|
/* In continuous mode, counter will be reset to zero with the following sequence:
* 1. Stop counting
* 2. Configure new CMP value
* 3. Restart counting
*
* Unfortunately, `tick_last_read` is not passed along the xx_ticker_set_interrupt() call. To solve it, we
* assume that `tick_last_read` tick is exactly the one returned by the last xx_ticker_read() call before
* xx_ticker_set_interrupt() is invoked. With this assumption, we can hold it via `xx_ticker_last_read_clk`
* in xx_ticker_read().
* This behavior is not what we want. To fix it, we could configure new CMP value
* without stopping counting first.
*/

/* ticker_last_read_clk will update in lp_ticker_read(). Keep it beforehand. */
uint32_t last_read_clk = ticker_last_read_clk;
uint32_t present_clk = lp_ticker_read() * NU_TMRCLK_PER_TICK;
uint32_t alarm_ts_clk = timestamp * NU_TMRCLK_PER_TICK;
uint32_t alarm_intvl1_clk, alarm_intvl2_clk;

/* alarm_intvl1_clk = present_clk - last_read_clk
*
* NOTE: Don't miss the `=` sign here. Otherwise, we would get the wrong result.
*/
if (present_clk >= last_read_clk) {
alarm_intvl1_clk = present_clk - last_read_clk;
} else {
alarm_intvl1_clk = (uint32_t) (((uint64_t) NU_TMR_MAXCNT) + 1 + present_clk - last_read_clk);
}
TIMER_T * timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname);

/* alarm_intvl2_clk = alarm_ts_clk - last_read_clk
*
* NOTE: Don't miss the `=` sign here. Otherwise, we would get the wrong result.
*/
if (alarm_ts_clk >= last_read_clk) {
alarm_intvl2_clk = alarm_ts_clk - last_read_clk;
} else {
alarm_intvl2_clk = (uint32_t) (((uint64_t) NU_TMR_MAXCNT) + 1 + alarm_ts_clk - last_read_clk);
}
/* NOTE: Because H/W timer requests min compare value, our implementation would have alarm delay of
* (TMR_CMP_MIN - interval_clk) clocks when interval_clk is between [1, TMR_CMP_MIN). */
uint32_t cmp_timer = timestamp * NU_TMRCLK_PER_TICK;
cmp_timer = NU_CLAMP(cmp_timer, TMR_CMP_MIN, TMR_CMP_MAX);
timer_base->CMP = cmp_timer;

/* Distinguish (long) future event and past event
*
* NOTE: No '=' sign here. Alarm should go off immediately in equal case.
*/
if (alarm_intvl2_clk > alarm_intvl1_clk) {
/* Schedule for future event */
arm_alarm(alarm_intvl2_clk - alarm_intvl1_clk);
} else {
/* Go off immediately for past event, including equal case */
lp_ticker_fire_interrupt();
}
/* NOTE: When engine is clocked by low power clock source (LXT/LIRC), we need to wait for 3 engine clocks. */
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
TIMER_Start(timer_base);
}

void lp_ticker_disable_interrupt(void)
{
TIMER_DisableInt((TIMER_T *) NU_MODBASE(timer3_modinit.modname));
TIMER_DisableInt((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
}

void lp_ticker_clear_interrupt(void)
{
TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(timer3_modinit.modname));
TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
}

void lp_ticker_fire_interrupt(void)
{
// NOTE: This event was in the past. Set the interrupt as pending, but don't process it here.
// This prevents a recursive loop under heavy load which can lead to a stack overflow.
NVIC_SetPendingIRQ(timer3_modinit.irq_n);
}

static void tmr2_vec(void)
{
TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(timer2_modinit.modname));
TIMER_ClearWakeupFlag((TIMER_T *) NU_MODBASE(timer2_modinit.modname));
}

static void tmr3_vec(void)
{
TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(timer3_modinit.modname));
TIMER_ClearWakeupFlag((TIMER_T *) NU_MODBASE(timer3_modinit.modname));

// NOTE: lp_ticker_set_interrupt() may get called in lp_ticker_irq_handler();
lp_ticker_irq_handler();

}

static void arm_alarm(uint32_t cd_clk)
{
TIMER_T * timer3_base = (TIMER_T *) NU_MODBASE(timer3_modinit.modname);

// Reset 8-bit PSC counter, 24-bit up counter value and CNTEN bit
timer3_base->CTL |= TIMER_CTL_RSTCNT_Msk;
// One-shot mode, Clock = 1 KHz
uint32_t clk_timer3 = TIMER_GetModuleClock((TIMER_T *) NU_MODBASE(timer3_modinit.modname));
uint32_t prescale_timer3 = clk_timer3 / NU_TMRCLK_PER_SEC - 1;
MBED_ASSERT((prescale_timer3 != (uint32_t) -1) && prescale_timer3 <= 127);
MBED_ASSERT((clk_timer3 % NU_TMRCLK_PER_SEC) == 0);
// NOTE: TIMER_CTL_CNTDATEN_Msk exists in NUC472, but not in M451. In M451, TIMER_CNT is updated continuously by default.
timer3_base->CTL &= ~(TIMER_CTL_OPMODE_Msk | TIMER_CTL_PSC_Msk/* | TIMER_CTL_CNTDATEN_Msk*/);
timer3_base->CTL |= TIMER_ONESHOT_MODE | prescale_timer3/* | TIMER_CTL_CNTDATEN_Msk*/;

/* NOTE: Because H/W timer requests min compare value, our implementation would have alarm delay of
* (TMR_CMP_MIN - interval_clk) clocks when interval_clk is between [1, TMR_CMP_MIN). */
uint32_t cmp_timer3 = cd_clk;
cmp_timer3 = NU_CLAMP(cmp_timer3, TMR_CMP_MIN, TMR_CMP_MAX);
timer3_base->CMP = cmp_timer3;

TIMER_EnableInt(timer3_base);
TIMER_EnableWakeup((TIMER_T *) NU_MODBASE(timer3_modinit.modname));
/* NOTE: When engine is clocked by low power clock source (LXT/LIRC), we need to wait for 3 engine clocks. */
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
TIMER_Start(timer3_base);
NVIC_SetPendingIRQ(TIMER_MODINIT.irq_n);
}

const ticker_info_t* lp_ticker_get_info()
Expand All @@ -253,4 +147,13 @@ const ticker_info_t* lp_ticker_get_info()
return &info;
}

static void tmr1_vec(void)
{
TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
TIMER_ClearWakeupFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));

// NOTE: lp_ticker_set_interrupt() may get called in lp_ticker_irq_handler();
lp_ticker_irq_handler();
}

#endif
186 changes: 45 additions & 141 deletions targets/TARGET_NUVOTON/TARGET_M451/us_ticker.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,12 @@
#define NU_TMR_MAXCNT ((1 << NU_TMR_MAXCNT_BITSIZE) - 1)

static void tmr0_vec(void);
static void tmr1_vec(void);
/* Configure scheduled alarm */
static void arm_alarm(uint32_t cd_clk);

static int ticker_inited = 0;
static uint32_t ticker_last_read_clk = 0;
static const struct nu_modinit_s timer0_modinit = {TIMER_0, TMR0_MODULE, CLK_CLKSEL1_TMR0SEL_PCLK0, 0, TMR0_RST, TMR0_IRQn, (void *) tmr0_vec};

#define TIMER_MODINIT timer0_modinit

/* NOTE: TIMER_0 for normal counting and TIMER_1 for scheduled alarm. */
static const struct nu_modinit_s timer0hires_modinit = {TIMER_0, TMR0_MODULE, CLK_CLKSEL1_TMR0SEL_PCLK0, 0, TMR0_RST, TMR0_IRQn, (void *) tmr0_vec};
static const struct nu_modinit_s timer1hires_modinit = {TIMER_1, TMR1_MODULE, CLK_CLKSEL1_TMR1SEL_PCLK0, 0, TMR1_RST, TMR1_IRQn, (void *) tmr1_vec};
static int ticker_inited = 0;

#define TMR_CMP_MIN 2
#define TMR_CMP_MAX 0xFFFFFFu
Expand All @@ -53,38 +49,32 @@ void us_ticker_init(void)
}
ticker_inited = 1;

ticker_last_read_clk = 0;

// Reset IP
SYS_ResetModule(timer0hires_modinit.rsetidx);
SYS_ResetModule(timer1hires_modinit.rsetidx);
SYS_ResetModule(TIMER_MODINIT.rsetidx);

// Select IP clock source
CLK_SetModuleClock(timer0hires_modinit.clkidx, timer0hires_modinit.clksrc, timer0hires_modinit.clkdiv);
CLK_SetModuleClock(timer1hires_modinit.clkidx, timer1hires_modinit.clksrc, timer1hires_modinit.clkdiv);
CLK_SetModuleClock(TIMER_MODINIT.clkidx, TIMER_MODINIT.clksrc, TIMER_MODINIT.clkdiv);

// Enable IP clock
CLK_EnableModuleClock(timer0hires_modinit.clkidx);
CLK_EnableModuleClock(timer1hires_modinit.clkidx);
CLK_EnableModuleClock(TIMER_MODINIT.clkidx);

// Timer for normal counter
uint32_t clk_timer0 = TIMER_GetModuleClock((TIMER_T *) NU_MODBASE(timer0hires_modinit.modname));
uint32_t prescale_timer0 = clk_timer0 / NU_TMRCLK_PER_SEC - 1;
MBED_ASSERT((prescale_timer0 != (uint32_t) -1) && prescale_timer0 <= 127);
MBED_ASSERT((clk_timer0 % NU_TMRCLK_PER_SEC) == 0);
uint32_t cmp_timer0 = TMR_CMP_MAX;
MBED_ASSERT(cmp_timer0 >= TMR_CMP_MIN && cmp_timer0 <= TMR_CMP_MAX);
uint32_t clk_timer = TIMER_GetModuleClock((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
uint32_t prescale_timer = clk_timer / NU_TMRCLK_PER_SEC - 1;
MBED_ASSERT((prescale_timer != (uint32_t) -1) && prescale_timer <= 127);
MBED_ASSERT((clk_timer % NU_TMRCLK_PER_SEC) == 0);
uint32_t cmp_timer = TMR_CMP_MAX;
MBED_ASSERT(cmp_timer >= TMR_CMP_MIN && cmp_timer <= TMR_CMP_MAX);
// NOTE: TIMER_CTL_CNTDATEN_Msk exists in NUC472, but not in M451. In M451, TIMER_CNT is updated continuously by default.
((TIMER_T *) NU_MODBASE(timer0hires_modinit.modname))->CTL = TIMER_PERIODIC_MODE | prescale_timer0/* | TIMER_CTL_CNTDATEN_Msk*/;
((TIMER_T *) NU_MODBASE(timer0hires_modinit.modname))->CMP = cmp_timer0;
((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname))->CTL = TIMER_CONTINUOUS_MODE | prescale_timer/* | TIMER_CTL_CNTDATEN_Msk*/;
((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname))->CMP = cmp_timer;

NVIC_SetVector(timer0hires_modinit.irq_n, (uint32_t) timer0hires_modinit.var);
NVIC_SetVector(timer1hires_modinit.irq_n, (uint32_t) timer1hires_modinit.var);
NVIC_SetVector(TIMER_MODINIT.irq_n, (uint32_t) TIMER_MODINIT.var);

NVIC_EnableIRQ(timer0hires_modinit.irq_n);
NVIC_EnableIRQ(timer1hires_modinit.irq_n);
NVIC_EnableIRQ(TIMER_MODINIT.irq_n);

TIMER_EnableInt((TIMER_T *) NU_MODBASE(timer0hires_modinit.modname));
TIMER_Start((TIMER_T *) NU_MODBASE(timer0hires_modinit.modname));
TIMER_EnableInt((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
TIMER_Start((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
}

uint32_t us_ticker_read()
Expand All @@ -93,139 +83,45 @@ uint32_t us_ticker_read()
us_ticker_init();
}

TIMER_T * timer0_base = (TIMER_T *) NU_MODBASE(timer0hires_modinit.modname);
TIMER_T * timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname);

ticker_last_read_clk = TIMER_GetCounter(timer0_base);
return (ticker_last_read_clk / NU_TMRCLK_PER_TICK);
return (TIMER_GetCounter(timer_base) / NU_TMRCLK_PER_TICK);
}

void us_ticker_set_interrupt(timestamp_t timestamp)
{
TIMER_Stop((TIMER_T *) NU_MODBASE(timer1hires_modinit.modname));

/* We need to get alarm interval from alarm timestamp `timestamp` to configure H/W timer.
*
* Because both `timestamp` and xx_ticker_read() would wrap around, we have difficulties in distinguishing
* long future event and past event. To distinguish them, we need `tick_last_read` against which
* `timestamp` is calculated out. In timeline, we would always have below after fixing wrap-around:
* (1) tick_last_read <= present_clk
* (2) tick_last_read <= alarm_ts_clk
*
*
* 1. Future event case:
*
* tick_last_read present_clk alarm_ts_clk
* | | |
* --------------------------------------------------------
* |-alarm_intvl1_clk-|
* |-------------------alarm_intvl2_clk-------------------|
*
* 2. Past event case:
*
* tick_last_read alarm_ts_clk present_clk
* | | |
* --------------------------------------------------------
* |-------------------alarm_intvl1_clk-------------------|
* |-alarm_intvl2_clk-|
*
* Unfortunately, `tick_last_read` is not passed along the xx_ticker_set_interrupt() call. To solve it, we
* assume that `tick_last_read` tick is exactly the one returned by the last xx_ticker_read() call before
* xx_ticker_set_interrupt() is invoked. With this assumption, we can hold it via `xx_ticker_last_read_clk`
* in xx_ticker_read().
*/

/* ticker_last_read_clk will update in us_ticker_read(). Keep it beforehand. */
uint32_t last_read_clk = ticker_last_read_clk;
uint32_t present_clk = us_ticker_read() * NU_TMRCLK_PER_TICK;
uint32_t alarm_ts_clk = timestamp * NU_TMRCLK_PER_TICK;
uint32_t alarm_intvl1_clk, alarm_intvl2_clk;

/* alarm_intvl1_clk = present_clk - last_read_clk
/* In continuous mode, counter will be reset to zero with the following sequence:
* 1. Stop counting
* 2. Configure new CMP value
* 3. Restart counting
*
* NOTE: Don't miss the `=` sign here. Otherwise, we would get the wrong result.
*/
if (present_clk >= last_read_clk) {
alarm_intvl1_clk = present_clk - last_read_clk;
} else {
alarm_intvl1_clk = (uint32_t) (((uint64_t) NU_TMR_MAXCNT) + 1 + present_clk - last_read_clk);
}

/* alarm_intvl2_clk = alarm_ts_clk - last_read_clk
*
* NOTE: Don't miss the `=` sign here. Otherwise, we would get the wrong result.
* This behavior is not what we want. To fix it, we could configure new CMP value
* without stopping counting first.
*/
if (alarm_ts_clk >= last_read_clk) {
alarm_intvl2_clk = alarm_ts_clk - last_read_clk;
} else {
alarm_intvl2_clk = (uint32_t) (((uint64_t) NU_TMR_MAXCNT) + 1 + alarm_ts_clk - last_read_clk);
}
TIMER_T * timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname);

/* Distinguish (long) future event and past event
*
* NOTE: No '=' sign here. Alarm should go off immediately in equal case.
*/
if (alarm_intvl2_clk > alarm_intvl1_clk) {
/* Schedule for future event */
arm_alarm(alarm_intvl2_clk - alarm_intvl1_clk);
} else {
/* Go off immediately for past event, including equal case */
us_ticker_fire_interrupt();
}
/* NOTE: Because H/W timer requests min compare value, our implementation would have alarm delay of
* (TMR_CMP_MIN - interval_clk) clocks when interval_clk is between [1, TMR_CMP_MIN). */
uint32_t cmp_timer = timestamp * NU_TMRCLK_PER_TICK;
cmp_timer = NU_CLAMP(cmp_timer, TMR_CMP_MIN, TMR_CMP_MAX);
timer_base->CMP = cmp_timer;
}

void us_ticker_disable_interrupt(void)
{
TIMER_DisableInt((TIMER_T *) NU_MODBASE(timer1hires_modinit.modname));
TIMER_DisableInt((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
}

void us_ticker_clear_interrupt(void)
{
TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(timer1hires_modinit.modname));
TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
}

void us_ticker_fire_interrupt(void)
{
// NOTE: This event was in the past. Set the interrupt as pending, but don't process it here.
// This prevents a recursive loop under heavy load which can lead to a stack overflow.
NVIC_SetPendingIRQ(timer1hires_modinit.irq_n);
}

static void tmr0_vec(void)
{
TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(timer0hires_modinit.modname));
}

static void tmr1_vec(void)
{
TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(timer1hires_modinit.modname));

// NOTE: us_ticker_set_interrupt() may get called in us_ticker_irq_handler();
us_ticker_irq_handler();
}

static void arm_alarm(uint32_t cd_clk)
{
TIMER_T * timer1_base = (TIMER_T *) NU_MODBASE(timer1hires_modinit.modname);

// Reset 8-bit PSC counter, 24-bit up counter value and CNTEN bit
timer1_base->CTL |= TIMER_CTL_RSTCNT_Msk;
// One-shot mode, Clock = 1 MHz
uint32_t clk_timer1 = TIMER_GetModuleClock((TIMER_T *) NU_MODBASE(timer1hires_modinit.modname));
uint32_t prescale_timer1 = clk_timer1 / NU_TMRCLK_PER_SEC - 1;
MBED_ASSERT((prescale_timer1 != (uint32_t) -1) && prescale_timer1 <= 127);
MBED_ASSERT((clk_timer1 % NU_TMRCLK_PER_SEC) == 0);
// NOTE: TIMER_CTL_CNTDATEN_Msk exists in NUC472, but not in M451. In M451, TIMER_CNT is updated continuously by default.
timer1_base->CTL &= ~(TIMER_CTL_OPMODE_Msk | TIMER_CTL_PSC_Msk/* | TIMER_CTL_CNTDATEN_Msk*/);
timer1_base->CTL |= TIMER_ONESHOT_MODE | prescale_timer1/* | TIMER_CTL_CNTDATEN_Msk*/;

/* NOTE: Because H/W timer requests min compare value, our implementation would have alarm delay of
* (TMR_CMP_MIN - interval_clk) clocks when interval_clk is between [1, TMR_CMP_MIN). */
uint32_t cmp_timer1 = cd_clk;
cmp_timer1 = NU_CLAMP(cmp_timer1, TMR_CMP_MIN, TMR_CMP_MAX);
timer1_base->CMP = cmp_timer1;

TIMER_EnableInt(timer1_base);
TIMER_Start(timer1_base);
NVIC_SetPendingIRQ(TIMER_MODINIT.irq_n);
}

const ticker_info_t* us_ticker_get_info()
Expand All @@ -236,3 +132,11 @@ const ticker_info_t* us_ticker_get_info()
};
return &info;
}

static void tmr0_vec(void)
{
TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));

// NOTE: us_ticker_set_interrupt() may get called in us_ticker_irq_handler();
us_ticker_irq_handler();
}
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,17 @@ typedef enum {
D14 = PG_3,
D15 = PG_2,

I2C_SCL = D15,
I2C_SDA = D14,

// Note: board-specific
// UART naming
USBTX = PD_3,
USBRX = PD_2,
STDIO_UART_TX = USBTX,
STDIO_UART_RX = USBRX,
SERIAL_TX = USBTX,
SERIAL_RX = USBRX,
// LED naming
LED_RED = PH_0,
LED_YELLOW = PH_1,
Expand Down
204 changes: 52 additions & 152 deletions targets/TARGET_NUVOTON/TARGET_M480/lp_ticker.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,14 @@
/* Timer max counter */
#define NU_TMR_MAXCNT ((1 << NU_TMR_MAXCNT_BITSIZE) - 1)

static void tmr2_vec(void);
static void tmr3_vec(void);
/* Configure scheduled alarm */
static void arm_alarm(uint32_t cd_clk);

static int ticker_inited = 0;
static uint32_t ticker_last_read_clk = 0;
static void tmr1_vec(void);

/* NOTE: To wake the system from power down mode, timer clock source must be ether LXT or LIRC. */
/* NOTE: TIMER_2 for normal counting and TIMER_3 for scheduled alarm */
static const struct nu_modinit_s timer2_modinit = {TIMER_2, TMR2_MODULE, CLK_CLKSEL1_TMR2SEL_LXT, 0, TMR2_RST, TMR2_IRQn, (void *) tmr2_vec};
static const struct nu_modinit_s timer3_modinit = {TIMER_3, TMR3_MODULE, CLK_CLKSEL1_TMR3SEL_LXT, 0, TMR3_RST, TMR3_IRQn, (void *) tmr3_vec};
static const struct nu_modinit_s timer1_modinit = {TIMER_1, TMR1_MODULE, CLK_CLKSEL1_TMR1SEL_LXT, 0, TMR1_RST, TMR1_IRQn, (void *) tmr1_vec};

#define TIMER_MODINIT timer1_modinit

static int ticker_inited = 0;

#define TMR_CMP_MIN 2
#define TMR_CMP_MAX 0xFFFFFFu
Expand All @@ -58,43 +54,37 @@ void lp_ticker_init(void)
}
ticker_inited = 1;

ticker_last_read_clk = 0;

// Reset module
SYS_ResetModule(timer2_modinit.rsetidx);
SYS_ResetModule(timer3_modinit.rsetidx);
SYS_ResetModule(TIMER_MODINIT.rsetidx);

// Select IP clock source
CLK_SetModuleClock(timer2_modinit.clkidx, timer2_modinit.clksrc, timer2_modinit.clkdiv);
CLK_SetModuleClock(timer3_modinit.clkidx, timer3_modinit.clksrc, timer3_modinit.clkdiv);
CLK_SetModuleClock(TIMER_MODINIT.clkidx, TIMER_MODINIT.clksrc, TIMER_MODINIT.clkdiv);

// Enable IP clock
CLK_EnableModuleClock(timer2_modinit.clkidx);
CLK_EnableModuleClock(timer3_modinit.clkidx);
CLK_EnableModuleClock(TIMER_MODINIT.clkidx);

// Configure clock
uint32_t clk_timer2 = TIMER_GetModuleClock((TIMER_T *) NU_MODBASE(timer2_modinit.modname));
uint32_t prescale_timer2 = clk_timer2 / NU_TMRCLK_PER_SEC - 1;
MBED_ASSERT((prescale_timer2 != (uint32_t) -1) && prescale_timer2 <= 127);
MBED_ASSERT((clk_timer2 % NU_TMRCLK_PER_SEC) == 0);
uint32_t cmp_timer2 = TMR_CMP_MAX;
MBED_ASSERT(cmp_timer2 >= TMR_CMP_MIN && cmp_timer2 <= TMR_CMP_MAX);
uint32_t clk_timer = TIMER_GetModuleClock((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
uint32_t prescale_timer = clk_timer / NU_TMRCLK_PER_SEC - 1;
MBED_ASSERT((prescale_timer != (uint32_t) -1) && prescale_timer <= 127);
MBED_ASSERT((clk_timer % NU_TMRCLK_PER_SEC) == 0);
uint32_t cmp_timer = TMR_CMP_MAX;
MBED_ASSERT(cmp_timer >= TMR_CMP_MIN && cmp_timer <= TMR_CMP_MAX);
// Continuous mode
// NOTE: TIMER_CTL_CNTDATEN_Msk exists in NUC472, but not in M451/M480. In M451/M480, TIMER_CNT is updated continuously by default.
((TIMER_T *) NU_MODBASE(timer2_modinit.modname))->CTL = TIMER_PERIODIC_MODE | prescale_timer2/* | TIMER_CTL_CNTDATEN_Msk*/;
((TIMER_T *) NU_MODBASE(timer2_modinit.modname))->CMP = cmp_timer2;
((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname))->CTL = TIMER_CONTINUOUS_MODE | prescale_timer/* | TIMER_CTL_CNTDATEN_Msk*/;
((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname))->CMP = cmp_timer;

// Set vector
NVIC_SetVector(timer2_modinit.irq_n, (uint32_t) timer2_modinit.var);
NVIC_SetVector(timer3_modinit.irq_n, (uint32_t) timer3_modinit.var);
NVIC_SetVector(TIMER_MODINIT.irq_n, (uint32_t) TIMER_MODINIT.var);

NVIC_EnableIRQ(timer2_modinit.irq_n);
NVIC_EnableIRQ(timer3_modinit.irq_n);
NVIC_EnableIRQ(TIMER_MODINIT.irq_n);

TIMER_EnableInt((TIMER_T *) NU_MODBASE(timer2_modinit.modname));
TIMER_EnableWakeup((TIMER_T *) NU_MODBASE(timer2_modinit.modname));
TIMER_EnableInt((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
TIMER_EnableWakeup((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
/* NOTE: When engine is clocked by low power clock source (LXT/LIRC), we need to wait for 3 engine clocks. */
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
TIMER_Start((TIMER_T *) NU_MODBASE(timer2_modinit.modname));
TIMER_Start((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
}

timestamp_t lp_ticker_read()
Expand All @@ -103,148 +93,49 @@ timestamp_t lp_ticker_read()
lp_ticker_init();
}

TIMER_T * timer2_base = (TIMER_T *) NU_MODBASE(timer2_modinit.modname);
TIMER_T * timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname);

ticker_last_read_clk = TIMER_GetCounter(timer2_base);
return (ticker_last_read_clk / NU_TMRCLK_PER_TICK);
return (TIMER_GetCounter(timer_base) / NU_TMRCLK_PER_TICK);
}

void lp_ticker_set_interrupt(timestamp_t timestamp)
{
TIMER_Stop((TIMER_T *) NU_MODBASE(timer3_modinit.modname));

/* We need to get alarm interval from alarm timestamp `timestamp` to configure H/W timer.
*
* Because both `timestamp` and xx_ticker_read() would wrap around, we have difficulties in distinguishing
* long future event and past event. To distinguish them, we need `tick_last_read` against which
* `timestamp` is calculated out. In timeline, we would always have below after fixing wrap-around:
* (1) tick_last_read <= present_clk
* (2) tick_last_read <= alarm_ts_clk
*
*
* 1. Future event case:
*
* tick_last_read present_clk alarm_ts_clk
* | | |
* --------------------------------------------------------
* |-alarm_intvl1_clk-|
* |-------------------alarm_intvl2_clk-------------------|
*
* 2. Past event case:
*
* tick_last_read alarm_ts_clk present_clk
* | | |
* --------------------------------------------------------
* |-------------------alarm_intvl1_clk-------------------|
* |-alarm_intvl2_clk-|
/* In continuous mode, counter will be reset to zero with the following sequence:
* 1. Stop counting
* 2. Configure new CMP value
* 3. Restart counting
*
* Unfortunately, `tick_last_read` is not passed along the xx_ticker_set_interrupt() call. To solve it, we
* assume that `tick_last_read` tick is exactly the one returned by the last xx_ticker_read() call before
* xx_ticker_set_interrupt() is invoked. With this assumption, we can hold it via `xx_ticker_last_read_clk`
* in xx_ticker_read().
* This behavior is not what we want. To fix it, we could configure new CMP value
* without stopping counting first.
*/

/* ticker_last_read_clk will update in lp_ticker_read(). Keep it beforehand. */
uint32_t last_read_clk = ticker_last_read_clk;
uint32_t present_clk = lp_ticker_read() * NU_TMRCLK_PER_TICK;
uint32_t alarm_ts_clk = timestamp * NU_TMRCLK_PER_TICK;
uint32_t alarm_intvl1_clk, alarm_intvl2_clk;

/* alarm_intvl1_clk = present_clk - last_read_clk
*
* NOTE: Don't miss the `=` sign here. Otherwise, we would get the wrong result.
*/
if (present_clk >= last_read_clk) {
alarm_intvl1_clk = present_clk - last_read_clk;
} else {
alarm_intvl1_clk = (uint32_t) (((uint64_t) NU_TMR_MAXCNT) + 1 + present_clk - last_read_clk);
}
TIMER_T * timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname);

/* alarm_intvl2_clk = alarm_ts_clk - last_read_clk
*
* NOTE: Don't miss the `=` sign here. Otherwise, we would get the wrong result.
*/
if (alarm_ts_clk >= last_read_clk) {
alarm_intvl2_clk = alarm_ts_clk - last_read_clk;
} else {
alarm_intvl2_clk = (uint32_t) (((uint64_t) NU_TMR_MAXCNT) + 1 + alarm_ts_clk - last_read_clk);
}
/* NOTE: Because H/W timer requests min compare value, our implementation would have alarm delay of
* (TMR_CMP_MIN - interval_clk) clocks when interval_clk is between [1, TMR_CMP_MIN). */
uint32_t cmp_timer = timestamp * NU_TMRCLK_PER_TICK;
cmp_timer = NU_CLAMP(cmp_timer, TMR_CMP_MIN, TMR_CMP_MAX);
timer_base->CMP = cmp_timer;

/* Distinguish (long) future event and past event
*
* NOTE: No '=' sign here. Alarm should go off immediately in equal case.
*/
if (alarm_intvl2_clk > alarm_intvl1_clk) {
/* Schedule for future event */
arm_alarm(alarm_intvl2_clk - alarm_intvl1_clk);
} else {
/* Go off immediately for past event, including equal case */
lp_ticker_fire_interrupt();
}
/* NOTE: When engine is clocked by low power clock source (LXT/LIRC), we need to wait for 3 engine clocks. */
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
TIMER_Start(timer_base);
}

void lp_ticker_disable_interrupt(void)
{
TIMER_DisableInt((TIMER_T *) NU_MODBASE(timer3_modinit.modname));
TIMER_DisableInt((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
}

void lp_ticker_clear_interrupt(void)
{
TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(timer3_modinit.modname));
TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
}

void lp_ticker_fire_interrupt(void)
{
// NOTE: This event was in the past. Set the interrupt as pending, but don't process it here.
// This prevents a recursive loop under heavy load which can lead to a stack overflow.
NVIC_SetPendingIRQ(timer3_modinit.irq_n);
}

static void tmr2_vec(void)
{
TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(timer2_modinit.modname));
TIMER_ClearWakeupFlag((TIMER_T *) NU_MODBASE(timer2_modinit.modname));
}

static void tmr3_vec(void)
{
TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(timer3_modinit.modname));
TIMER_ClearWakeupFlag((TIMER_T *) NU_MODBASE(timer3_modinit.modname));

// NOTE: lp_ticker_set_interrupt() may get called in lp_ticker_irq_handler();
lp_ticker_irq_handler();

}

static void arm_alarm(uint32_t cd_clk)
{
TIMER_T * timer3_base = (TIMER_T *) NU_MODBASE(timer3_modinit.modname);

// Reset 8-bit PSC counter, 24-bit up counter value and CNTEN bit
// NUC472/M451: See TIMER_CTL_RSTCNT_Msk
// M480
timer3_base->CNT = 0;
while (timer3_base->CNT & TIMER_CNT_RSTACT_Msk);
// One-shot mode, Clock = 1 KHz
uint32_t clk_timer3 = TIMER_GetModuleClock((TIMER_T *) NU_MODBASE(timer3_modinit.modname));
uint32_t prescale_timer3 = clk_timer3 / NU_TMRCLK_PER_SEC - 1;
MBED_ASSERT((prescale_timer3 != (uint32_t) -1) && prescale_timer3 <= 127);
MBED_ASSERT((clk_timer3 % NU_TMRCLK_PER_SEC) == 0);
// NOTE: TIMER_CTL_CNTDATEN_Msk exists in NUC472, but not in M451/M480. In M451/M480, TIMER_CNT is updated continuously by default.
timer3_base->CTL &= ~(TIMER_CTL_OPMODE_Msk | TIMER_CTL_PSC_Msk/* | TIMER_CTL_CNTDATEN_Msk*/);
timer3_base->CTL |= TIMER_ONESHOT_MODE | prescale_timer3/* | TIMER_CTL_CNTDATEN_Msk*/;

/* NOTE: Because H/W timer requests min compare value, our implementation would have alarm delay of
* (TMR_CMP_MIN - interval_clk) clocks when interval_clk is between [1, TMR_CMP_MIN). */
uint32_t cmp_timer3 = cd_clk;
cmp_timer3 = NU_CLAMP(cmp_timer3, TMR_CMP_MIN, TMR_CMP_MAX);
timer3_base->CMP = cmp_timer3;

TIMER_EnableInt(timer3_base);
TIMER_EnableWakeup((TIMER_T *) NU_MODBASE(timer3_modinit.modname));
/* NOTE: When engine is clocked by low power clock source (LXT/LIRC), we need to wait for 3 engine clocks. */
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
TIMER_Start(timer3_base);
NVIC_SetPendingIRQ(TIMER_MODINIT.irq_n);
}

const ticker_info_t* lp_ticker_get_info()
Expand All @@ -256,4 +147,13 @@ const ticker_info_t* lp_ticker_get_info()
return &info;
}

static void tmr1_vec(void)
{
TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
TIMER_ClearWakeupFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));

// NOTE: lp_ticker_set_interrupt() may get called in lp_ticker_irq_handler();
lp_ticker_irq_handler();
}

#endif
Loading