Skip to content

[NUC472/M453] Export IAR project and other bugfixes #3590

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 13, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,6 @@ struct pwmout_s {
};

struct sleep_s {
uint32_t start_us;
uint32_t end_us;
uint32_t period_us;
int powerdown;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@

#include "M451Series.h"
#include <errno.h>
#include "nu_miscutil.h"

extern uint32_t __mbed_sbrk_start;
extern uint32_t __mbed_krbs_start;

#define NU_HEAP_ALIGN 32

/**
* The default implementation of _sbrk() (in common/retarget.cpp) for GCC_ARM requires one-region model (heap and stack share one region), which doesn't
* fit two-region model (heap and stack are two distinct regions), for example, NUMAKER-PFM-NUC472 locates heap on external SRAM. Define __wrap__sbrk() to
Expand All @@ -23,8 +26,8 @@ extern uint32_t __mbed_krbs_start;
void *__wrap__sbrk(int incr)
{
static uint32_t heap_ind = (uint32_t) &__mbed_sbrk_start;
uint32_t heap_ind_old = heap_ind;
uint32_t heap_ind_new = (heap_ind_old + incr + 7) & ~7;
uint32_t heap_ind_old = NU_ALIGN_UP(heap_ind, NU_HEAP_ALIGN);
uint32_t heap_ind_new = NU_ALIGN_UP(heap_ind_old + incr, NU_HEAP_ALIGN);

if (heap_ind_new > &__mbed_krbs_start) {
errno = ENOMEM;
Expand Down
23 changes: 3 additions & 20 deletions targets/TARGET_NUVOTON/TARGET_M451/sleep.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@
#include "objects.h"
#include "PeripheralPins.h"

void us_ticker_prepare_sleep(struct sleep_s *obj);
void us_ticker_wakeup_from_sleep(struct sleep_s *obj);
static void mbed_enter_sleep(struct sleep_s *obj);
static void mbed_exit_sleep(struct sleep_s *obj);

Expand Down Expand Up @@ -57,8 +55,7 @@ void deepsleep(void)
mbed_exit_sleep(&sleep_obj);
}


void mbed_enter_sleep(struct sleep_s *obj)
static void mbed_enter_sleep(struct sleep_s *obj)
{
// Check if serial allows entering power-down mode
if (obj->powerdown) {
Expand All @@ -77,16 +74,7 @@ void mbed_enter_sleep(struct sleep_s *obj)
obj->powerdown = pwmout_allow_powerdown();
}
// TODO: Check if other peripherals allow entering power-down mode

obj->start_us = lp_ticker_read();
// Let us_ticker prepare for power-down or reject it.
us_ticker_prepare_sleep(obj);

// NOTE(STALE): To pass mbed-drivers test, timer requires to be fine-grained, so its implementation needs HIRC rather than LIRC/LXT as its clock source.
// But as CLK_PowerDown()/CLK_Idle() is called, HIRC will be disabled and timer cannot keep counting and alarm. To overcome the dilemma,
// just make CPU halt and compromise power saving.
// NOTE: As CLK_PowerDown()/CLK_Idle() is called, HIRC/HXT will be disabled in normal mode, but not in ICE mode. This may cause confusion in development.


if (obj->powerdown) { // Power-down mode (HIRC/HXT disabled, LIRC/LXT enabled)
SYS_UnlockReg();
CLK_PowerDown();
Expand All @@ -101,14 +89,9 @@ void mbed_enter_sleep(struct sleep_s *obj)
__NOP();
__NOP();
__NOP();

obj->end_us = lp_ticker_read();
obj->period_us = (obj->end_us > obj->start_us) ? (obj->end_us - obj->start_us) : (uint32_t) ((uint64_t) obj->end_us + 0xFFFFFFFFu - obj->start_us);
// Let us_ticker recover from power-down.
us_ticker_wakeup_from_sleep(obj);
}

void mbed_exit_sleep(struct sleep_s *obj)
static void mbed_exit_sleep(struct sleep_s *obj)
{
// TODO: TO BE CONTINUED

Expand Down
108 changes: 18 additions & 90 deletions targets/TARGET_NUVOTON/TARGET_M451/us_ticker.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,29 +27,22 @@

#define TMR0HIRES_CLK_PER_SEC (1000 * 1000)
#define TMR1HIRES_CLK_PER_SEC (1000 * 1000)
#define TMR1LORES_CLK_PER_SEC (__LIRC)

#define US_PER_TMR0HIRES_CLK (US_PER_SEC / TMR0HIRES_CLK_PER_SEC)
#define US_PER_TMR1HIRES_CLK (US_PER_SEC / TMR1HIRES_CLK_PER_SEC)
#define US_PER_TMR1LORES_CLK (US_PER_SEC / TMR1LORES_CLK_PER_SEC)

#define US_PER_TMR0HIRES_INT (1000 * 1000 * 10)
#define TMR0HIRES_CLK_PER_TMR0HIRES_INT ((uint32_t) ((uint64_t) US_PER_TMR0HIRES_INT * TMR0HIRES_CLK_PER_SEC / US_PER_SEC))


// Determine to use lo-res/hi-res timer according to CD period
#define US_TMR_SEP_CD 1000

static void tmr0_vec(void);
static void tmr1_vec(void);
static void us_ticker_arm_cd(void);

static int us_ticker_inited = 0;
static volatile uint32_t counter_major = 0;
static volatile uint32_t pd_comp_us = 0; // Power-down compenstaion for normal counter
static volatile uint32_t cd_major_minor_us = 0;
static volatile uint32_t cd_minor_us = 0;
static volatile int cd_hires_tmr_armed = 0; // Flag of armed or not of hi-res timer for CD counter

// NOTE: PCLK is set up in mbed_sdk_init(), invocation of which must be before C++ global object constructor. See init_api.c for details.
// NOTE: Choose clock source of timer:
Expand All @@ -58,7 +51,6 @@ static volatile int cd_hires_tmr_armed = 0; // Flag of armed or not of hi-res ti
// 3. PCLK(HXT): Less accurate but can pass mbed-drivers test.
// NOTE: TIMER_0 for normal counter, TIMER_1 for countdown.
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 timer1lores_modinit = {TIMER_1, TMR1_MODULE, CLK_CLKSEL1_TMR1SEL_LIRC, 0, TMR1_RST, TMR1_IRQn, (void *) tmr1_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};

#define TMR_CMP_MIN 2
Expand All @@ -71,22 +63,20 @@ void us_ticker_init(void)
}

counter_major = 0;
pd_comp_us = 0;
cd_major_minor_us = 0;
cd_minor_us = 0;
cd_hires_tmr_armed = 0;
us_ticker_inited = 1;

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

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

// Timer for normal counter
uint32_t clk_timer0 = TIMER_GetModuleClock((TIMER_T *) NU_MODBASE(timer0hires_modinit.modname));
Expand All @@ -100,10 +90,10 @@ void us_ticker_init(void)
((TIMER_T *) NU_MODBASE(timer0hires_modinit.modname))->CMP = cmp_timer0;

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

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

TIMER_EnableInt((TIMER_T *) NU_MODBASE(timer0hires_modinit.modname));
TIMER_Start((TIMER_T *) NU_MODBASE(timer0hires_modinit.modname));
Expand Down Expand Up @@ -141,26 +131,24 @@ uint32_t us_ticker_read()
}
while (minor_us == 0 || minor_us == US_PER_TMR0HIRES_INT);

// Add power-down compensation
return (major_minor_us + pd_comp_us) / US_PER_TICK;
return (major_minor_us / US_PER_TICK);
}
while (0);
}

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

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

void us_ticker_set_interrupt(timestamp_t timestamp)
{
TIMER_Stop((TIMER_T *) NU_MODBASE(timer1lores_modinit.modname));
cd_hires_tmr_armed = 0;
TIMER_Stop((TIMER_T *) NU_MODBASE(timer1hires_modinit.modname));

int delta = (int) (timestamp - us_ticker_read());
if (delta > 0) {
Expand All @@ -173,42 +161,10 @@ void us_ticker_set_interrupt(timestamp_t timestamp)
* This event was in the past. Set the interrupt as pending, but don't process it here.
* This prevents a recurive loop under heavy load which can lead to a stack overflow.
*/
NVIC_SetPendingIRQ(timer1lores_modinit.irq_n);
NVIC_SetPendingIRQ(timer1hires_modinit.irq_n);
}
}

void us_ticker_prepare_sleep(struct sleep_s *obj)
{
// Reject power-down if hi-res timer (HIRC/HXT) is now armed for CD counter.
if (obj->powerdown) {
obj->powerdown = ! cd_hires_tmr_armed;
}

core_util_critical_section_enter();

if (obj->powerdown) {
// NOTE: On entering power-down mode, HIRC/HXT will be disabled in normal mode, but not in ICE mode. This may cause confusion in development.
// To not be inconsistent due to above, always disable clock source of normal counter, and then re-enable it and make compensation on wakeup from power-down.
CLK_DisableModuleClock(timer0hires_modinit.clkidx);
}

core_util_critical_section_exit();
}

void us_ticker_wakeup_from_sleep(struct sleep_s *obj)
{
core_util_critical_section_enter();

if (obj->powerdown) {
// Calculate power-down compensation
pd_comp_us += obj->period_us;

CLK_EnableModuleClock(timer0hires_modinit.clkidx);
}

core_util_critical_section_exit();
}

static void tmr0_vec(void)
{
TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(timer0hires_modinit.modname));
Expand All @@ -217,9 +173,8 @@ static void tmr0_vec(void)

static void tmr1_vec(void)
{
TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(timer1lores_modinit.modname));
TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(timer1hires_modinit.modname));
cd_major_minor_us = (cd_major_minor_us > cd_minor_us) ? (cd_major_minor_us - cd_minor_us) : 0;
cd_hires_tmr_armed = 0;
if (cd_major_minor_us == 0) {
// NOTE: us_ticker_set_interrupt() may get called in us_ticker_irq_handler();
us_ticker_irq_handler();
Expand All @@ -231,49 +186,22 @@ static void tmr1_vec(void)

static void us_ticker_arm_cd(void)
{
TIMER_T * timer1_base = (TIMER_T *) NU_MODBASE(timer1lores_modinit.modname);
uint32_t tmr1_clk_per_sec;
uint32_t us_per_tmr1_clk;

/**
* Reserve US_TMR_SEP_CD-plus alarm period for hi-res timer
* 1. period >= US_TMR_SEP_CD * 2. Divide into two rounds:
* US_TMR_SEP_CD * n (lo-res timer)
* US_TMR_SEP_CD + period % US_TMR_SEP_CD (hi-res timer)
* 2. period < US_TMR_SEP_CD * 2. Just one round:
* period (hi-res timer)
*/
if (cd_major_minor_us >= US_TMR_SEP_CD * 2) {
cd_minor_us = cd_major_minor_us - cd_major_minor_us % US_TMR_SEP_CD - US_TMR_SEP_CD;

CLK_SetModuleClock(timer1lores_modinit.clkidx, timer1lores_modinit.clksrc, timer1lores_modinit.clkdiv);
tmr1_clk_per_sec = TMR1LORES_CLK_PER_SEC;
us_per_tmr1_clk = US_PER_TMR1LORES_CLK;

cd_hires_tmr_armed = 0;
}
else {
cd_minor_us = cd_major_minor_us;

CLK_SetModuleClock(timer1hires_modinit.clkidx, timer1hires_modinit.clksrc, timer1hires_modinit.clkdiv);
tmr1_clk_per_sec = TMR1HIRES_CLK_PER_SEC;
us_per_tmr1_clk = US_PER_TMR1HIRES_CLK;

cd_hires_tmr_armed = 1;
}
TIMER_T * timer1_base = (TIMER_T *) NU_MODBASE(timer1hires_modinit.modname);

cd_minor_us = cd_major_minor_us;

// 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(timer1lores_modinit.modname));
uint32_t prescale_timer1 = clk_timer1 / tmr1_clk_per_sec - 1;
uint32_t clk_timer1 = TIMER_GetModuleClock((TIMER_T *) NU_MODBASE(timer1hires_modinit.modname));
uint32_t prescale_timer1 = clk_timer1 / TMR1HIRES_CLK_PER_SEC - 1;
MBED_ASSERT((prescale_timer1 != (uint32_t) -1) && prescale_timer1 <= 127);
MBED_ASSERT((clk_timer1 % tmr1_clk_per_sec) == 0);
MBED_ASSERT((clk_timer1 % TMR1HIRES_CLK_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*/;

uint32_t cmp_timer1 = cd_minor_us / us_per_tmr1_clk;
uint32_t cmp_timer1 = cd_minor_us / US_PER_TMR1HIRES_CLK;
cmp_timer1 = NU_CLAMP(cmp_timer1, TMR_CMP_MIN, TMR_CMP_MAX);
timer1_base->CMP = cmp_timer1;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,6 @@ struct pwmout_s {
};

struct sleep_s {
uint32_t start_us;
uint32_t end_us;
uint32_t period_us;
int powerdown;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@

#include "NUC472_442.h"
#include <errno.h>
#include "nu_miscutil.h"

extern uint32_t __mbed_sbrk_start;
extern uint32_t __mbed_krbs_start;

#define NU_HEAP_ALIGN 32

/**
* The default implementation of _sbrk() (in common/retarget.cpp) for GCC_ARM requires one-region model (heap and stack share one region), which doesn't
* fit two-region model (heap and stack are two distinct regions), for example, NUMAKER-PFM-NUC472 locates heap on external SRAM. Define __wrap__sbrk() to
Expand All @@ -23,8 +26,8 @@ extern uint32_t __mbed_krbs_start;
void *__wrap__sbrk(int incr)
{
static uint32_t heap_ind = (uint32_t) &__mbed_sbrk_start;
uint32_t heap_ind_old = heap_ind;
uint32_t heap_ind_new = (heap_ind_old + incr + 7) & ~7;
uint32_t heap_ind_old = NU_ALIGN_UP(heap_ind, NU_HEAP_ALIGN);
uint32_t heap_ind_new = NU_ALIGN_UP(heap_ind_old + incr, NU_HEAP_ALIGN);

if (heap_ind_new > &__mbed_krbs_start) {
errno = ENOMEM;
Expand Down
16 changes: 0 additions & 16 deletions targets/TARGET_NUVOTON/TARGET_NUC472/sleep.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@
#include "objects.h"
#include "PeripheralPins.h"

void us_ticker_prepare_sleep(struct sleep_s *obj);
void us_ticker_wakeup_from_sleep(struct sleep_s *obj);
static void mbed_enter_sleep(struct sleep_s *obj);
static void mbed_exit_sleep(struct sleep_s *obj);

Expand Down Expand Up @@ -77,15 +75,6 @@ static void mbed_enter_sleep(struct sleep_s *obj)
}
// TODO: Check if other peripherals allow entering power-down mode

obj->start_us = lp_ticker_read();
// Let us_ticker prepare for power-down or reject it.
us_ticker_prepare_sleep(obj);

// NOTE(STALE): To pass mbed-drivers test, timer requires to be fine-grained, so its implementation needs HIRC rather than LIRC/LXT as its clock source.
// But as CLK_PowerDown()/CLK_Idle() is called, HIRC will be disabled and timer cannot keep counting and alarm. To overcome the dilemma,
// just make CPU halt and compromise power saving.
// NOTE: As CLK_PowerDown()/CLK_Idle() is called, HIRC/HXT will be disabled in normal mode, but not in ICE mode. This may cause confusion in development.

if (obj->powerdown) { // Power-down mode (HIRC/HXT disabled, LIRC/LXT enabled)
SYS_UnlockReg();
CLK_PowerDown();
Expand All @@ -103,11 +92,6 @@ static void mbed_enter_sleep(struct sleep_s *obj)
__NOP();
__NOP();
__NOP();

obj->end_us = lp_ticker_read();
obj->period_us = (obj->end_us > obj->start_us) ? (obj->end_us - obj->start_us) : (uint32_t) ((uint64_t) obj->end_us + 0xFFFFFFFFu - obj->start_us);
// Let us_ticker recover from power-down.
us_ticker_wakeup_from_sleep(obj);
}

static void mbed_exit_sleep(struct sleep_s *obj)
Expand Down
Loading