mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #3837 from ARMmbed/release-candidate
Release candidate for mbed-os-5.3.6mbed-os-5.3 mbed_lib_rev137
commit
5faf4b26c5
|
@ -70,7 +70,7 @@ SIMPLE_POSTS_TEST(0)
|
|||
|
||||
|
||||
void time_func(Timer *t, int ms) {
|
||||
TEST_ASSERT_INT_WITHIN(2, ms, t->read_ms());
|
||||
TEST_ASSERT_INT_WITHIN(5, ms, t->read_ms());
|
||||
t->reset();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
#include "mbed_events.h"
|
||||
#include "mbed.h"
|
||||
#include "rtos.h"
|
||||
#include "greentea-client/test_env.h"
|
||||
#include "unity.h"
|
||||
#include "utest.h"
|
||||
#include <cstdlib>
|
||||
#include <cmath>
|
||||
|
||||
using namespace utest::v1;
|
||||
|
||||
|
||||
// Test delay
|
||||
#ifndef TEST_EVENTS_TIMING_TIME
|
||||
#define TEST_EVENTS_TIMING_TIME 20000
|
||||
#endif
|
||||
|
||||
#ifndef TEST_EVENTS_TIMING_MEAN
|
||||
#define TEST_EVENTS_TIMING_MEAN 25
|
||||
#endif
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846264338327950288
|
||||
#endif
|
||||
|
||||
// Random number generation to skew timing values
|
||||
float gauss(float mu, float sigma) {
|
||||
float x = (float)rand() / ((float)RAND_MAX+1);
|
||||
float y = (float)rand() / ((float)RAND_MAX+1);
|
||||
float x2pi = x*2.0*M_PI;
|
||||
float g2rad = sqrt(-2.0 * log(1.0-y));
|
||||
float z = cos(x2pi) * g2rad;
|
||||
return mu + z*sigma;
|
||||
}
|
||||
|
||||
float chisq(float sigma) {
|
||||
return pow(gauss(0, sqrt(sigma)), 2);
|
||||
}
|
||||
|
||||
|
||||
Timer timer;
|
||||
DigitalOut led(LED1);
|
||||
|
||||
equeue_sema_t sema;
|
||||
|
||||
// Timer timing test
|
||||
void timer_timing_test() {
|
||||
timer.reset();
|
||||
timer.start();
|
||||
int prev = timer.read_us();
|
||||
|
||||
while (prev < TEST_EVENTS_TIMING_TIME*1000) {
|
||||
int next = timer.read_us();
|
||||
if (next < prev) {
|
||||
printf("backwards drift %d -> %d (%08x -> %08x)\r\n",
|
||||
prev, next, prev, next);
|
||||
}
|
||||
TEST_ASSERT(next >= prev);
|
||||
prev = next;
|
||||
}
|
||||
}
|
||||
|
||||
// equeue tick timing test
|
||||
void tick_timing_test() {
|
||||
unsigned start = equeue_tick();
|
||||
int prev = 0;
|
||||
|
||||
while (prev < TEST_EVENTS_TIMING_TIME) {
|
||||
int next = equeue_tick() - start;
|
||||
if (next < prev) {
|
||||
printf("backwards drift %d -> %d (%08x -> %08x)\r\n",
|
||||
prev, next, prev, next);
|
||||
}
|
||||
TEST_ASSERT(next >= prev);
|
||||
prev = next;
|
||||
}
|
||||
}
|
||||
|
||||
// equeue semaphore timing test
|
||||
void semaphore_timing_test() {
|
||||
srand(0);
|
||||
timer.reset();
|
||||
timer.start();
|
||||
|
||||
int err = equeue_sema_create(&sema);
|
||||
TEST_ASSERT_EQUAL(0, err);
|
||||
|
||||
while (timer.read_ms() < TEST_EVENTS_TIMING_TIME) {
|
||||
int delay = chisq(TEST_EVENTS_TIMING_MEAN);
|
||||
|
||||
int start = timer.read_us();
|
||||
equeue_sema_wait(&sema, delay);
|
||||
int taken = timer.read_us() - start;
|
||||
|
||||
printf("delay %dms => error %dus\r\n", delay, abs(1000*delay - taken));
|
||||
TEST_ASSERT_INT_WITHIN(5000, taken, delay * 1000);
|
||||
|
||||
led = !led;
|
||||
}
|
||||
|
||||
equeue_sema_destroy(&sema);
|
||||
}
|
||||
|
||||
|
||||
// Test setup
|
||||
utest::v1::status_t test_setup(const size_t number_of_cases) {
|
||||
GREENTEA_SETUP((number_of_cases+1)*TEST_EVENTS_TIMING_TIME, "default_auto");
|
||||
return verbose_test_setup_handler(number_of_cases);
|
||||
}
|
||||
|
||||
const Case cases[] = {
|
||||
Case("Testing accuracy of timer", timer_timing_test),
|
||||
Case("Testing accuracy of equeue tick", tick_timing_test),
|
||||
Case("Testing accuracy of equeue semaphore", semaphore_timing_test),
|
||||
};
|
||||
|
||||
Specification specification(test_setup, cases);
|
||||
|
||||
int main() {
|
||||
return !Harness::run(specification);
|
||||
}
|
||||
|
|
@ -26,15 +26,15 @@
|
|||
|
||||
// Ticker operations
|
||||
static bool equeue_tick_inited = false;
|
||||
static unsigned equeue_minutes = 0;
|
||||
static volatile unsigned equeue_minutes = 0;
|
||||
static unsigned equeue_timer[
|
||||
(sizeof(Timer)+sizeof(unsigned)-1)/sizeof(unsigned)];
|
||||
static unsigned equeue_ticker[
|
||||
(sizeof(Ticker)+sizeof(unsigned)-1)/sizeof(unsigned)];
|
||||
|
||||
static void equeue_tick_update() {
|
||||
equeue_minutes += reinterpret_cast<Timer*>(equeue_timer)->read_ms();
|
||||
reinterpret_cast<Timer*>(equeue_timer)->reset();
|
||||
equeue_minutes += 1;
|
||||
}
|
||||
|
||||
static void equeue_tick_init() {
|
||||
|
@ -48,7 +48,7 @@ static void equeue_tick_init() {
|
|||
equeue_minutes = 0;
|
||||
reinterpret_cast<Timer*>(equeue_timer)->start();
|
||||
reinterpret_cast<Ticker*>(equeue_ticker)
|
||||
->attach_us(equeue_tick_update, (1 << 16)*1000);
|
||||
->attach_us(equeue_tick_update, 1000 << 16);
|
||||
|
||||
equeue_tick_inited = true;
|
||||
}
|
||||
|
@ -58,8 +58,15 @@ unsigned equeue_tick() {
|
|||
equeue_tick_init();
|
||||
}
|
||||
|
||||
unsigned equeue_ms = reinterpret_cast<Timer*>(equeue_timer)->read_ms();
|
||||
return (equeue_minutes << 16) + equeue_ms;
|
||||
unsigned minutes;
|
||||
unsigned ms;
|
||||
|
||||
do {
|
||||
minutes = equeue_minutes;
|
||||
ms = reinterpret_cast<Timer*>(equeue_timer)->read_ms();
|
||||
} while (minutes != equeue_minutes);
|
||||
|
||||
return minutes + ms;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -135,7 +135,7 @@ USBHAL::USBHAL(void) {
|
|||
/* bulk/int 64 bytes in FS */
|
||||
HAL_PCDEx_SetTxFiFo(&hpcd, 0, (MAX_PACKET_SIZE_EP0/4)+1);
|
||||
/* bulk/int bytes in FS */
|
||||
HAL_PCDEx_SetTxFiFo(&hpcd, 1, (MAX_PACKET_SIZE_EP1/4));
|
||||
HAL_PCDEx_SetTxFiFo(&hpcd, 1, (MAX_PACKET_SIZE_EP1/4)+1);
|
||||
HAL_PCDEx_SetTxFiFo(&hpcd, 2, (MAX_PACKET_SIZE_EP2/4));
|
||||
/* ISOchronous */
|
||||
HAL_PCDEx_SetTxFiFo(&hpcd, 3, (MAX_PACKET_SIZE_EP3/4));
|
||||
|
|
|
@ -131,7 +131,7 @@ USBHAL::USBHAL(void) {
|
|||
/* bulk/int 64 bytes in FS */
|
||||
HAL_PCDEx_SetTxFiFo(&hpcd, 0, (MAX_PACKET_SIZE_EP0/4)+1);
|
||||
/* bulk/int bytes in FS */
|
||||
HAL_PCDEx_SetTxFiFo(&hpcd, 1, (MAX_PACKET_SIZE_EP1/4));
|
||||
HAL_PCDEx_SetTxFiFo(&hpcd, 1, (MAX_PACKET_SIZE_EP1/4)+1);
|
||||
HAL_PCDEx_SetTxFiFo(&hpcd, 2, (MAX_PACKET_SIZE_EP2/4));
|
||||
/* ISOchronous */
|
||||
HAL_PCDEx_SetTxFiFo(&hpcd, 3, (MAX_PACKET_SIZE_EP3/4));
|
||||
|
|
|
@ -121,7 +121,7 @@ USBHAL::USBHAL(void) {
|
|||
/* bulk/int 64 bytes in FS */
|
||||
HAL_PCDEx_SetTxFiFo(&hpcd, 0, (MAX_PACKET_SIZE_EP0/4)+1);
|
||||
/* bulk/int bytes in FS */
|
||||
HAL_PCDEx_SetTxFiFo(&hpcd, 1, (MAX_PACKET_SIZE_EP1/4));
|
||||
HAL_PCDEx_SetTxFiFo(&hpcd, 1, (MAX_PACKET_SIZE_EP1/4)+1);
|
||||
HAL_PCDEx_SetTxFiFo(&hpcd, 2, (MAX_PACKET_SIZE_EP2/4));
|
||||
/* ISOchronous */
|
||||
HAL_PCDEx_SetTxFiFo(&hpcd, 3, (MAX_PACKET_SIZE_EP3/4));
|
||||
|
|
|
@ -27,6 +27,10 @@
|
|||
//#define __packed __attribute__ ((__packed__))
|
||||
//#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define __packed __attribute__ ((__packed__))
|
||||
#endif
|
||||
|
||||
class USBHAL {
|
||||
public:
|
||||
/* Configuration */
|
||||
|
|
4
mbed.h
4
mbed.h
|
@ -16,13 +16,13 @@
|
|||
#ifndef MBED_H
|
||||
#define MBED_H
|
||||
|
||||
#define MBED_LIBRARY_VERSION 136
|
||||
#define MBED_LIBRARY_VERSION 137
|
||||
|
||||
#if MBED_CONF_RTOS_PRESENT
|
||||
// RTOS present, this is valid only for mbed OS 5
|
||||
#define MBED_MAJOR_VERSION 5
|
||||
#define MBED_MINOR_VERSION 3
|
||||
#define MBED_PATCH_VERSION 5
|
||||
#define MBED_PATCH_VERSION 6
|
||||
|
||||
#else
|
||||
// mbed 2
|
||||
|
|
|
@ -65,7 +65,7 @@ void spi_format(spi_t *obj, int bits, int mode, int slave)
|
|||
spi_master_config_t master_config;
|
||||
spi_slave_config_t slave_config;
|
||||
|
||||
if ((bits != 8) || (bits != 16)) {
|
||||
if ((bits != 8) && (bits != 16)) {
|
||||
error("Only 8bits and 16bits SPI supported");
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ void spi_format(spi_t *obj, int bits, int mode, int slave)
|
|||
spi_master_config_t master_config;
|
||||
spi_slave_config_t slave_config;
|
||||
|
||||
if ((bits != 8) || (bits != 16)) {
|
||||
if ((bits != 8) && (bits != 16)) {
|
||||
error("Only 8bits and 16bits SPI supported");
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -117,9 +117,6 @@ struct pwmout_s {
|
|||
};
|
||||
|
||||
struct sleep_s {
|
||||
uint32_t start_us;
|
||||
uint32_t end_us;
|
||||
uint32_t period_us;
|
||||
int powerdown;
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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));
|
||||
|
@ -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) {
|
||||
|
@ -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));
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
||||
|
|
|
@ -118,9 +118,6 @@ struct pwmout_s {
|
|||
};
|
||||
|
||||
struct sleep_s {
|
||||
uint32_t start_us;
|
||||
uint32_t end_us;
|
||||
uint32_t period_us;
|
||||
int powerdown;
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
@ -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_PCLK, 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_PCLK, 0, TMR1_RST, TMR1_IRQn, (void *) tmr1_vec};
|
||||
|
||||
#define TMR_CMP_MIN 2
|
||||
|
@ -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));
|
||||
|
@ -99,10 +89,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));
|
||||
|
@ -140,26 +130,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) {
|
||||
|
@ -172,42 +160,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));
|
||||
|
@ -216,9 +172,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();
|
||||
|
@ -230,48 +185,21 @@ 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);
|
||||
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;
|
||||
|
||||
|
|
|
@ -24,6 +24,8 @@ extern "C" {
|
|||
#define NU_MAX(a,b) ((a)>(b)?(a):(b))
|
||||
#define NU_MIN(a,b) ((a)<(b)?(a):(b))
|
||||
#define NU_CLAMP(x, min, max) NU_MIN(NU_MAX((x), (min)), (max))
|
||||
#define NU_ALIGN_DOWN(X, ALIGN) ((X) & ~((ALIGN) - 1))
|
||||
#define NU_ALIGN_UP(X, ALIGN) (((X) + (ALIGN) - 1) & ~((ALIGN) - 1))
|
||||
|
||||
void nu_nop(uint32_t n);
|
||||
|
||||
|
|
|
@ -83,14 +83,18 @@
|
|||
#define I2C_APB_CLK_DIVIDER_VAL_MASK 0x1FE0
|
||||
|
||||
/* Error check */
|
||||
#define I2C_UFL_CHECK (d->membase->STATUS.WORD & 0x80)
|
||||
#define FIFO_OFL_CHECK (d->membase->STATUS.WORD & 0x10)
|
||||
#define I2C_BUS_ERR_CHECK (d->membase->STATUS.WORD & 0x04)
|
||||
#define RD_DATA_READY (d->membase->STATUS.WORD & 0x02)
|
||||
#define I2C_UFL_CHECK (obj->membase->STATUS.WORD & 0x80)
|
||||
#define I2C_FIFO_FULL (obj->membase->STATUS.WORD & 0x20)
|
||||
#define FIFO_OFL_CHECK (obj->membase->STATUS.WORD & 0x10)
|
||||
#define I2C_BUS_ERR_CHECK (obj->membase->STATUS.WORD & 0x04)
|
||||
#define RD_DATA_READY (obj->membase->STATUS.WORD & 0x02)
|
||||
#define I2C_FIFO_EMPTY (obj->membase->STATUS.WORD & 0x01)
|
||||
|
||||
#define I2C_API_STATUS_SUCCESS 0
|
||||
#define PAD_REG_ADRS_BYTE_SIZE 4
|
||||
|
||||
#define SEND_COMMAND(cmd) while(!I2C_FIFO_EMPTY); wait_us(1); obj->membase->CMD_REG = cmd;
|
||||
|
||||
/** Init I2C device.
|
||||
* @details
|
||||
* Sets the necessary registers. The baud rate is set default to 100K
|
||||
|
@ -154,4 +158,4 @@ extern int32_t fI2cReadB(i2c_t *d, char *buf, int len);
|
|||
*/
|
||||
extern int32_t fI2cWriteB(i2c_t *d, const char *buf, int len);
|
||||
|
||||
#endif /* I2C_H_ */
|
||||
#endif /* I2C_H_ */
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
#include "i2c.h"
|
||||
#include "i2c_api.h"
|
||||
#include "wait_api.h"
|
||||
|
||||
#define I2C_READ_WRITE_BIT_MASK 0xFE
|
||||
|
||||
|
@ -151,10 +152,10 @@ int i2c_byte_read(i2c_t *obj, int last) /* TODO return size can be uint8_t */
|
|||
}
|
||||
if(last) {
|
||||
/* ACK */
|
||||
obj->membase->CMD_REG = I2C_CMD_WDAT0;
|
||||
SEND_COMMAND(I2C_CMD_WDAT0);
|
||||
} else {
|
||||
/* No ACK */
|
||||
obj->membase->CMD_REG = I2C_CMD_WDAT1;
|
||||
SEND_COMMAND(I2C_CMD_WDAT1);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
@ -168,8 +169,6 @@ int i2c_byte_write(i2c_t *obj, int data)
|
|||
return Count;
|
||||
}
|
||||
|
||||
obj->membase->CMD_REG = I2C_CMD_VRFY_ACK; /* Verify ACK */
|
||||
|
||||
while(obj->membase->STATUS.WORD & I2C_STATUS_CMD_FIFO_OFL_BIT); /* Wait till command overflow ends */
|
||||
|
||||
if(obj->membase->STATUS.WORD & I2C_STATUS_BUS_ERR_BIT) {
|
||||
|
@ -181,4 +180,4 @@ int i2c_byte_write(i2c_t *obj, int data)
|
|||
}
|
||||
}
|
||||
|
||||
#endif /* DEVICE_I2C */
|
||||
#endif /* DEVICE_I2C */
|
|
@ -60,6 +60,7 @@
|
|||
*/
|
||||
#if DEVICE_I2C
|
||||
#include "i2c.h"
|
||||
#include "wait_api.h"
|
||||
|
||||
/* See i2c.h for details */
|
||||
void fI2cInit(i2c_t *obj,PinName sda,PinName scl)
|
||||
|
@ -135,7 +136,7 @@ void fI2cFrequency(i2c_t *obj, uint32_t hz)
|
|||
int32_t fI2cStart(i2c_t *obj)
|
||||
{
|
||||
/* Send start bit */
|
||||
obj->membase->CMD_REG = I2C_CMD_START;
|
||||
SEND_COMMAND(I2C_CMD_START);
|
||||
return I2C_API_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -143,7 +144,7 @@ int32_t fI2cStart(i2c_t *obj)
|
|||
int32_t fI2cStop(i2c_t *obj)
|
||||
{
|
||||
/* Send stop bit */
|
||||
obj->membase->CMD_REG = I2C_CMD_STOP;
|
||||
SEND_COMMAND(I2C_CMD_STOP);
|
||||
if (obj->membase->STATUS.WORD & (I2C_STATUS_CMD_FIFO_FULL_BIT |
|
||||
I2C_STATUS_CMD_FIFO_OFL_BIT |
|
||||
I2C_STATUS_BUS_ERR_BIT)) {
|
||||
|
@ -154,23 +155,26 @@ int32_t fI2cStop(i2c_t *obj)
|
|||
}
|
||||
|
||||
/* See i2c.h for details */
|
||||
int32_t fI2cReadB(i2c_t *d, char *buf, int len)
|
||||
int32_t fI2cReadB(i2c_t *obj, char *buf, int len)
|
||||
{
|
||||
int32_t read = 0;
|
||||
|
||||
while (read < len) {
|
||||
/* Send read command */
|
||||
d->membase->CMD_REG = I2C_CMD_RDAT8;
|
||||
SEND_COMMAND(I2C_CMD_RDAT8);
|
||||
while(!RD_DATA_READY) {
|
||||
if (I2C_BUS_ERR_CHECK) {
|
||||
/* Bus error occured */
|
||||
return I2C_ERROR_BUS_BUSY;
|
||||
}
|
||||
}
|
||||
buf[read++] = d->membase->RD_FIFO_REG; /**< Reading 'read FIFO register' will clear status register */
|
||||
buf[read++] = obj->membase->RD_FIFO_REG; /**< Reading 'read FIFO register' will clear status register */
|
||||
|
||||
if(!(read>=len)) { /* No ACK will be generated for the last read, upper level I2C protocol should generate */
|
||||
d->membase->CMD_REG=I2C_CMD_WDAT0; /* TODO based on requirement generate ACK or NACK Based on the requirement. */
|
||||
SEND_COMMAND(I2C_CMD_WDAT0); /* TODO based on requirement generate ACK or NACK Based on the requirement. */
|
||||
} else {
|
||||
/* No ack */
|
||||
SEND_COMMAND(I2C_CMD_WDAT1);
|
||||
}
|
||||
|
||||
/* check for FIFO underflow */
|
||||
|
@ -187,42 +191,49 @@ int32_t fI2cReadB(i2c_t *d, char *buf, int len)
|
|||
}
|
||||
|
||||
/* See i2c.h for details */
|
||||
int32_t fI2cWriteB(i2c_t *d, const char *buf, int len)
|
||||
int32_t fI2cWriteB(i2c_t *obj, const char *buf, int len)
|
||||
{
|
||||
int32_t write = 0;
|
||||
|
||||
while (write < len) {
|
||||
/* Send write command */
|
||||
d->membase->CMD_REG = I2C_CMD_WDAT8;
|
||||
SEND_COMMAND(I2C_CMD_WDAT8);
|
||||
|
||||
if(buf[write] == I2C_CMD_RDAT8) {
|
||||
/* SW work around to counter FSM issue. If the only command in the CMD FIFO is the WDAT8 command (data of 0x13)
|
||||
then as the command is read out (i.e. the FIFO goes empty), the WDAT8 command will be misinterpreted as a
|
||||
RDAT8 command by the data FSM; resulting in an I2C bus error (NACK instead of an ACK). */
|
||||
/* Send 0x13 bit wise */
|
||||
d->membase->CMD_REG = I2C_CMD_WDAT0;
|
||||
d->membase->CMD_REG = I2C_CMD_WDAT0;
|
||||
d->membase->CMD_REG = I2C_CMD_WDAT0;
|
||||
d->membase->CMD_REG = I2C_CMD_WDAT1;
|
||||
SEND_COMMAND(I2C_CMD_WDAT0);
|
||||
|
||||
d->membase->CMD_REG = I2C_CMD_WDAT0;
|
||||
d->membase->CMD_REG = I2C_CMD_WDAT0;
|
||||
d->membase->CMD_REG = I2C_CMD_WDAT1;
|
||||
d->membase->CMD_REG = I2C_CMD_WDAT1;
|
||||
SEND_COMMAND(I2C_CMD_WDAT0);
|
||||
|
||||
SEND_COMMAND(I2C_CMD_WDAT0);
|
||||
|
||||
SEND_COMMAND(I2C_CMD_WDAT1);
|
||||
|
||||
SEND_COMMAND(I2C_CMD_WDAT0);
|
||||
|
||||
SEND_COMMAND(I2C_CMD_WDAT0);
|
||||
|
||||
SEND_COMMAND(I2C_CMD_WDAT1);
|
||||
|
||||
SEND_COMMAND(I2C_CMD_WDAT1);
|
||||
} else {
|
||||
/* Send data */
|
||||
d->membase->CMD_REG = buf[write++];
|
||||
SEND_COMMAND(buf[write++]);
|
||||
}
|
||||
d->membase->CMD_REG = I2C_CMD_VRFY_ACK; /* TODO Verify ACK based on requirement, Do we need? */
|
||||
|
||||
while(FIFO_OFL_CHECK); /* Wait till command overflow ends */
|
||||
SEND_COMMAND(I2C_CMD_VRFY_ACK); /* TODO Verify ACK based on requirement, Do we need? */
|
||||
|
||||
if (I2C_BUS_ERR_CHECK) {
|
||||
/* Bus error */
|
||||
return I2C_ERROR_BUS_BUSY;
|
||||
}
|
||||
|
||||
while(FIFO_OFL_CHECK); /* Wait till command overflow ends */
|
||||
}
|
||||
|
||||
return write;
|
||||
}
|
||||
|
||||
#endif /* DEVICE_I2C */
|
||||
#endif /* DEVICE_I2C */
|
|
@ -37,7 +37,7 @@ static int us_ticker_inited = 0;
|
|||
|
||||
static void us_timer_init(void);
|
||||
|
||||
static uint32_t us_ticker_int_counter = 0;
|
||||
static uint32_t us_ticker_target = 0;
|
||||
static volatile uint32_t msb_counter = 0;
|
||||
|
||||
void us_ticker_init(void)
|
||||
|
@ -168,20 +168,25 @@ extern void us_ticker_isr(void)
|
|||
/* Clear IRQ flag */
|
||||
TIM1REG->CLEAR = 0;
|
||||
|
||||
/* If this is a longer timer it will take multiple full hw counter cycles */
|
||||
if (us_ticker_int_counter > 0) {
|
||||
ticker_set(0xFFFF);
|
||||
us_ticker_int_counter--;
|
||||
} else {
|
||||
int32_t delta = us_ticker_target - us_ticker_read();
|
||||
if (delta <= 0) {
|
||||
TIM1REG->CONTROL.BITS.ENABLE = False;
|
||||
us_ticker_irq_handler();
|
||||
} else {
|
||||
// Clamp at max value of timer
|
||||
if (delta > 0xFFFF) {
|
||||
delta = 0xFFFF;
|
||||
}
|
||||
|
||||
ticker_set(delta);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set timer 1 ticker interrupt */
|
||||
void us_ticker_set_interrupt(timestamp_t timestamp)
|
||||
{
|
||||
int32_t delta = (uint32_t)timestamp - us_ticker_read();
|
||||
us_ticker_target = (uint32_t)timestamp;
|
||||
int32_t delta = us_ticker_target - us_ticker_read();
|
||||
|
||||
if (delta <= 0) {
|
||||
/* This event was in the past */
|
||||
|
@ -195,10 +200,10 @@ void us_ticker_set_interrupt(timestamp_t timestamp)
|
|||
return;
|
||||
}
|
||||
|
||||
/* Calculate how much delta falls outside the 16-bit counter range. */
|
||||
/* You will have to perform a full timer overflow for each bit above */
|
||||
/* that range. */
|
||||
us_ticker_int_counter = (uint32_t)(delta >> 16);
|
||||
// Clamp at max value of timer
|
||||
if (delta > 0xFFFF) {
|
||||
delta = 0xFFFF;
|
||||
}
|
||||
|
||||
ticker_set(delta);
|
||||
}
|
||||
|
|
|
@ -166,7 +166,6 @@ int gpio_irq_init(gpio_irq_t *obj, PinName pin, gpio_irq_handler handler, uint32
|
|||
InterruptHandlerRegister((IRQn_Type)(nIRQn_h+obj->ch), (void (*)(uint32_t))irq_tbl[obj->ch]);
|
||||
INTCICR1 &= ~(0x3 << shift);
|
||||
GIC_SetPriority((IRQn_Type)(nIRQn_h+obj->ch), 5);
|
||||
GIC_EnableIRQ((IRQn_Type)(nIRQn_h+obj->ch));
|
||||
obj->int_enable = 1;
|
||||
__enable_irq();
|
||||
|
||||
|
|
|
@ -83,7 +83,9 @@
|
|||
|
||||
HAL_StatusTypeDef HAL_Init(void);
|
||||
|
||||
#define HSE_VALUE ((uint32_t)25000000) /*!< Default value of the External oscillator in Hz */
|
||||
#if !defined (HSE_VALUE)
|
||||
#define HSE_VALUE ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */
|
||||
#endif /* HSE_VALUE */
|
||||
|
||||
#if !defined (HSI_VALUE)
|
||||
#define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/
|
||||
|
|
|
@ -83,7 +83,9 @@
|
|||
|
||||
HAL_StatusTypeDef HAL_Init(void);
|
||||
|
||||
#define HSE_VALUE ((uint32_t)25000000) /*!< Default value of the External oscillator in Hz */
|
||||
#if !defined (HSE_VALUE)
|
||||
#define HSE_VALUE ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */
|
||||
#endif /* HSE_VALUE */
|
||||
|
||||
#if !defined (HSI_VALUE)
|
||||
#define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/
|
||||
|
|
|
@ -103,9 +103,12 @@
|
|||
* This value is used by the RCC HAL module to compute the system frequency
|
||||
* (when HSE is used as system clock source, directly or through the PLL).
|
||||
*/
|
||||
#if !defined (HSE_VALUE)
|
||||
#define HSE_VALUE 8000000U /*!< Value of the External oscillator in Hz */
|
||||
#endif /* HSE_VALUE */
|
||||
//#if !defined (HSE_VALUE)
|
||||
#if defined(TARGET_DISCO_F746NG) || defined(TARGET_DISCO_F769NI)
|
||||
#define HSE_VALUE 25000000U /*!< Value of the External oscillator in Hz */
|
||||
#else
|
||||
#define HSE_VALUE 8000000U /*!< Default value of the External oscillator in Hz */
|
||||
#endif
|
||||
|
||||
#if !defined (HSE_STARTUP_TIMEOUT)
|
||||
#define HSE_STARTUP_TIMEOUT 200U /*!< Time out for HSE start up, in ms */
|
||||
|
|
|
@ -1123,9 +1123,12 @@ HAL_StatusTypeDef HAL_RTCEx_SetWakeUpTimer_IT(RTC_HandleTypeDef *hrtc, uint32_t
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Disable the Wake-Up timer */
|
||||
__HAL_RTC_WAKEUPTIMER_DISABLE(hrtc);
|
||||
|
||||
/* Clear flag Wake-Up */
|
||||
__HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(hrtc, RTC_FLAG_WUTF);
|
||||
|
||||
tickstart = HAL_GetTick();
|
||||
|
||||
/* Wait till RTC WUTWF flag is set and if Time out is reached exit */
|
||||
|
|
|
@ -291,23 +291,28 @@ void spi_frequency(spi_t *obj, int hz) {
|
|||
struct spi_s *spiobj = SPI_S(obj);
|
||||
int spi_hz = 0;
|
||||
uint8_t prescaler_rank = 0;
|
||||
uint8_t last_index = (sizeof(baudrate_prescaler_table)/sizeof(baudrate_prescaler_table[0])) - 1;
|
||||
SPI_HandleTypeDef *handle = &(spiobj->handle);
|
||||
|
||||
/* Get the clock of the peripheral */
|
||||
spi_hz = spi_get_clock_freq(obj);
|
||||
/* Calculate the spi clock for prescaler_rank 0: SPI_BAUDRATEPRESCALER_2 */
|
||||
spi_hz = spi_get_clock_freq(obj) / 2;
|
||||
|
||||
/* Define pre-scaler in order to get highest available frequency below requested frequency */
|
||||
while ((spi_hz > hz) && (prescaler_rank < sizeof(baudrate_prescaler_table)/sizeof(baudrate_prescaler_table[0]))){
|
||||
while ((spi_hz > hz) && (prescaler_rank < last_index)) {
|
||||
spi_hz = spi_hz / 2;
|
||||
prescaler_rank++;
|
||||
}
|
||||
|
||||
if (prescaler_rank <= sizeof(baudrate_prescaler_table)/sizeof(baudrate_prescaler_table[0])) {
|
||||
handle->Init.BaudRatePrescaler = baudrate_prescaler_table[prescaler_rank-1];
|
||||
} else {
|
||||
error("Couldn't setup requested SPI frequency");
|
||||
/* Use the best fit pre-scaler */
|
||||
handle->Init.BaudRatePrescaler = baudrate_prescaler_table[prescaler_rank];
|
||||
|
||||
/* In case maximum pre-scaler still gives too high freq, raise an error */
|
||||
if (spi_hz > hz) {
|
||||
error("Couldn't set suitable spi freq: request:%d, lowest:%d\r\n", hz, spi_hz);
|
||||
}
|
||||
|
||||
DEBUG_PRINTF("spi_frequency, request:%d, select:%d\r\n", hz, spi_hz);
|
||||
|
||||
init_spi(obj);
|
||||
}
|
||||
|
||||
|
|
|
@ -167,5 +167,11 @@
|
|||
},
|
||||
"NCS36510":{
|
||||
"OGChipSelectEditMenu": "NCS36510\tONSemiconductor NCS36510"
|
||||
},
|
||||
"NUC472HI8AE": {
|
||||
"OGChipSelectEditMenu": "NUC400AE series\tNuvoton NUC400AE series (NUC442AE,NUC472AE)"
|
||||
},
|
||||
"M453VG6AE": {
|
||||
"OGChipSelectEditMenu": "M451AE series\tNuvoton M451AE series (M451AE,M452AE,M453AE,M451MAE)"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue