diff --git a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/device_cfg.h b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/device_cfg.h index b18568b0d3..de66a69adb 100644 --- a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/device_cfg.h +++ b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/device_cfg.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 ARM Limited + * Copyright (c) 2018 Arm Limited * * Licensed under the Apache License Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,8 +27,54 @@ */ /* CMSDK Timers */ -#define ARM_CMSDK_TIMER0 #define ARM_CMSDK_TIMER1 +#define ARM_CMSDK_DUALTIMER + +/* Timer Peripherals are driven by APB System Core Clocks, + * defined in system_CMSDK_CM3DS.c + */ +#define TIMERS_INPUT_CLOCK_FREQ_HZ 25000000U + +/* mbed usec high-resolution ticker configuration */ +#define USEC_TIMER_DEV CMSDK_TIMER1_DEV + +#define usec_interval_irq_handler TIMER1_IRQHandler +#define USEC_INTERVAL_IRQ TIMER1_IRQn + +/* The us ticker uses CMSDK Timer1, that does not have HW prescaler. + * The reported shift define is necessary for the software emulated + * prescaler behavior, so the ticker works as if it was ticking on a + * virtually slower frequency. The value 5 sets up the ticker to work + * properly in the specified frequency interval. + */ +#define USEC_TIMER_BIT_WIDTH 32U +#define USEC_REPORTED_SHIFT 5U +#define USEC_REPORTED_FREQ_HZ (TIMERS_INPUT_CLOCK_FREQ_HZ >> \ + USEC_REPORTED_SHIFT) +#define USEC_REPORTED_BITS (USEC_TIMER_BIT_WIDTH - USEC_REPORTED_SHIFT) + +/* mbed low power ticker configuration */ +#define LP_TIMER_DEV CMSDK_DUALTIMER_DEV + +#define lp_interval_irq_handler DUALTIMER_IRQHandler +#define LP_INTERVAL_IRQ DUALTIMER_IRQn + +/* The lp ticker a CMSDK Dual Timer that is capable of prescaling + * its input clock frequency by 256 at most. Having 25MHz as input + * frequency requires an additional slowing factor in order for the ticker + * to operate in the specified frequency interval, thus the effective + * prescaler value is going to be the sum of the HW and the virtual + * prescaler values. + */ +#define LP_TIMER_BIT_WIDTH 32U +#define LP_TIMER_HW_PRESCALER 8U +#define LP_REPORTED_SHIFT 1U +#define LP_REPORTED_FREQ_HZ (TIMERS_INPUT_CLOCK_FREQ_HZ >> \ + (LP_TIMER_HW_PRESCALER+LP_REPORTED_SHIFT)) +#define LP_REPORTED_BITS (LP_TIMER_BIT_WIDTH - LP_REPORTED_SHIFT) + +/* RTC PL031 */ +#define RTC_PL031 /* ARM GPIO */ #define ARM_GPIO0 @@ -51,7 +97,7 @@ #define ARM_SPI4 /* ARM UART */ -#define DEFAULT_UART_BAUDRATE 9600 +#define DEFAULT_UART_BAUDRATE 9600U #define ARM_UART0 #define ARM_UART1 #define ARM_UART2 diff --git a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/drivers/dualtimer_cmsdk_drv.c b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/drivers/dualtimer_cmsdk_drv.c new file mode 100644 index 0000000000..b3c2ea2cc4 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/drivers/dualtimer_cmsdk_drv.c @@ -0,0 +1,590 @@ +/* + * Copyright (c) 2016-2018 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. + */ + +/** +* \file dualtimer_cmsdk_drv.c +* \brief Generic driver for CMSDK Dualtimers. +*/ + +#include "dualtimer_cmsdk_drv.h" + +/** Dualtimer state definition */ +#define DUALTIMER_CMSDK_INITIALIZED (1u) + +/** Dual timer control register bit indexes */ +#define CTRL_REG_ONE_SHOT_INDEX (0u) +#define CTRL_REG_SIZE_INDEX (1u) +#define CTRL_REG_PRESCALE_INDEX (3u) +#define CTRL_REG_IRQ_EN_INDEX (5u) +#define CTRL_REG_MODE_INDEX (6u) +#define CTRL_REG_TIMER_EN_INDEX (7u) + +/** Dual timer interrupt registers bit indexes */ +#define XRIS_REG_RAW_IRQ_INDEX (0u) +#define XMIS_REG_MASKED_IRQ_INDEX (0u) +#define XINTCLR_REG_CLEAR_IRQ_INDEX (0u) + +/** Misc definition */ +#define TWO_BITS_WIDTH (2u) + +/** Bit handling macros */ +#define ATOMIC_SET_BIT(WORD, BIT_INDEX) (WORD = (1u << BIT_INDEX)) +#define ATOMIC_CLR_BIT(WORD, BIT_INDEX) (WORD = ~(1u << BIT_INDEX)) +#define SET_BIT(WORD, BIT_INDEX) (WORD |= (1u << BIT_INDEX)) +#define CLR_BIT(WORD, BIT_INDEX) (WORD &= ~(1u << BIT_INDEX)) +#define GET_BIT(WORD, BIT_INDEX) (bool)((WORD & (1u << BIT_INDEX))) + +/** Generate a flexible width left shifted bit-mask */ +#define BIT_MASK(BIT_INDEX, WIDTH)\ + (((1u << (WIDTH)) - 1u) << (BIT_INDEX - WIDTH + 1u)) + +/** Set N number of bits defined by width at index position in a register */ +#define SET_NBITS(WORD, BIT_INDEX, WIDTH, DATA)\ + (WORD |= (DATA << (BIT_INDEX - WIDTH + 1u))\ + & BIT_MASK(BIT_INDEX, WIDTH)) + +/** Get N number of bits defined by width at index position in a register */ +#define GET_NBITS(WORD, BIT_INDEX, WIDTH)\ + ((WORD & BIT_MASK(BIT_INDEX, WIDTH))\ + >> (BIT_INDEX - WIDTH + 1u)) + +/** Map the registers for dualtimer device */ +#define DUALTIMER_REG_MAP(DEVICE)\ + ((struct dualtimer_cmsdk_reg_map_t*)((DEVICE)->cfg->base)) + +/** DualTimer register map structure */ +struct dualtimer_cmsdk_reg_map_t { + volatile uint32_t timer1load; /** Offset: 0x000 (R/W) Timer 1 Load */ + volatile uint32_t timer1value; /** Offset: 0x004 (R/ ) Timer 1 Counter + * Current Value */ + volatile uint32_t timer1ctrl; /** Offset: 0x008 (R/W) Timer 1 Control */ + volatile uint32_t timer1intclr; /** Offset: 0x00C ( /W) Timer 1 Interrupt + * Clear */ + volatile uint32_t timer1ris; /** Offset: 0x010 (R/ ) Timer 1 Raw + * Interrupt Status */ + volatile uint32_t timer1mis; /** Offset: 0x014 (R/ ) Timer 1 Masked + * Interrupt Status */ + volatile uint32_t timer1bgload; /** Offset: 0x018 (R/W) Background Load + * Register */ + volatile uint32_t reserved0; + volatile uint32_t timer2load; /** Offset: 0x020 (R/W) Timer 2 Load */ + volatile uint32_t timer2value; /** Offset: 0x024 (R/ ) Timer 2 Counter + * Current Value */ + volatile uint32_t timer2ctrl; /** Offset: 0x028 (R/W) Timer 2 Control */ + volatile uint32_t timer2intclr; /** Offset: 0x02C ( /W) Timer 2 Interrupt + * Clear */ + volatile uint32_t timer2ris; /** Offset: 0x030 (R/ ) Timer 2 Raw + * Interrupt Status */ + volatile uint32_t timer2mis; /** Offset: 0x034 (R/ ) Timer 2 Masked + * Interrupt Status */ + volatile uint32_t timer2bgload; /** Offset: 0x038 (R/W) Background Load + * Register */ + volatile uint32_t reserved1[945]; + volatile uint32_t itcr; /** Offset: 0xF00 (R/W) Integration Test + * Control Register */ + volatile uint32_t itop; /** Offset: 0xF04 ( /W) Integration Test + * Output Set + * Register */ +}; + +static void dualtimer_cmsdk_defaults(const struct dualtimer_cmsdk_dev_t* dev) +{ + dualtimer_cmsdk_disable_both_timers(dev); + dualtimer_cmsdk_clear_interrupt_timer1(dev); + dualtimer_cmsdk_clear_interrupt_timer2(dev); + dualtimer_cmsdk_set_oneshot_count_both_timers(dev, + DUALTIMER_CMSDK_WRAPPING); + dualtimer_cmsdk_set_size_both_timers(dev, DUALTIMER_CMSDK_SIZE_16BIT); + dualtimer_cmsdk_set_prescale_both_timers(dev, + DUALTIMER_CMSDK_CLOCK_DIV1); + dualtimer_cmsdk_enable_interrupt_both_timers(dev); + dualtimer_cmsdk_set_mode_both_timers(dev, DUALTIMER_CMSDK_FREE_RUNNING); + dualtimer_cmsdk_set_reload_both_timers(dev, + DUALTIMER_CMSDK_DEF_16BIT_RELOAD); +} +/** Init */ +void dualtimer_cmsdk_init(const struct dualtimer_cmsdk_dev_t* dev) +{ + if (DUALTIMER_CMSDK_INITIALIZED != dev->data->is_initialized) { + dualtimer_cmsdk_defaults(dev); + dev->data->is_initialized = 1; + } +} + +bool dualtimer_cmsdk_is_initialized(const struct dualtimer_cmsdk_dev_t* dev) +{ + return(bool)dev->data->is_initialized; +} + +void dualtimer_cmsdk_free(const struct dualtimer_cmsdk_dev_t* dev) +{ + dualtimer_cmsdk_disable_both_timers(dev); + dev->data->is_initialized = 0; +} + +/** Enable - Disable */ +void dualtimer_cmsdk_enable_timer1(const struct dualtimer_cmsdk_dev_t* dev) +{ + SET_BIT(DUALTIMER_REG_MAP(dev)->timer1ctrl, CTRL_REG_TIMER_EN_INDEX); +} + +void dualtimer_cmsdk_enable_timer2(const struct dualtimer_cmsdk_dev_t* dev) +{ + SET_BIT(DUALTIMER_REG_MAP(dev)->timer2ctrl, CTRL_REG_TIMER_EN_INDEX); +} + +void dualtimer_cmsdk_enable_both_timers(const struct dualtimer_cmsdk_dev_t* dev) +{ + dualtimer_cmsdk_enable_timer1(dev); + dualtimer_cmsdk_enable_timer2(dev); +} + +void dualtimer_cmsdk_disable_timer1(const struct dualtimer_cmsdk_dev_t* dev) +{ + CLR_BIT(DUALTIMER_REG_MAP(dev)->timer1ctrl, CTRL_REG_TIMER_EN_INDEX); +} + +void dualtimer_cmsdk_disable_timer2(const struct dualtimer_cmsdk_dev_t* dev) +{ + CLR_BIT(DUALTIMER_REG_MAP(dev)->timer2ctrl, CTRL_REG_TIMER_EN_INDEX); +} + +void dualtimer_cmsdk_disable_both_timers( + const struct dualtimer_cmsdk_dev_t* dev) +{ + dualtimer_cmsdk_disable_timer1(dev); + dualtimer_cmsdk_disable_timer2(dev); +} + +/** Interrupts */ +void dualtimer_cmsdk_enable_interrupt_timer1( + const struct dualtimer_cmsdk_dev_t* dev) +{ + SET_BIT(DUALTIMER_REG_MAP(dev)->timer1ctrl, CTRL_REG_IRQ_EN_INDEX); +} + +void dualtimer_cmsdk_enable_interrupt_timer2( + const struct dualtimer_cmsdk_dev_t* dev) +{ + SET_BIT(DUALTIMER_REG_MAP(dev)->timer2ctrl, CTRL_REG_IRQ_EN_INDEX); +} + +void dualtimer_cmsdk_enable_interrupt_both_timers( + const struct dualtimer_cmsdk_dev_t* dev) +{ + dualtimer_cmsdk_enable_interrupt_timer1(dev); + dualtimer_cmsdk_enable_interrupt_timer2(dev); +} + +void dualtimer_cmsdk_disable_interrupt_timer1( + const struct dualtimer_cmsdk_dev_t* dev) +{ + CLR_BIT(DUALTIMER_REG_MAP(dev)->timer1ctrl, CTRL_REG_IRQ_EN_INDEX); +} + +void dualtimer_cmsdk_disable_interrupt_timer2( + const struct dualtimer_cmsdk_dev_t* dev) +{ + CLR_BIT(DUALTIMER_REG_MAP(dev)->timer2ctrl, CTRL_REG_IRQ_EN_INDEX); +} + + void dualtimer_cmsdk_disable_interrupt_both_timers( + const struct dualtimer_cmsdk_dev_t* dev) +{ + dualtimer_cmsdk_disable_interrupt_timer1(dev); + dualtimer_cmsdk_disable_interrupt_timer2(dev); +} + +void dualtimer_cmsdk_clear_interrupt_timer1( + const struct dualtimer_cmsdk_dev_t* dev) +{ + ATOMIC_SET_BIT(DUALTIMER_REG_MAP(dev)->timer1intclr, + XINTCLR_REG_CLEAR_IRQ_INDEX); +} + +void dualtimer_cmsdk_clear_interrupt_timer2( + const struct dualtimer_cmsdk_dev_t* dev) +{ + ATOMIC_SET_BIT(DUALTIMER_REG_MAP(dev)->timer2intclr, + XINTCLR_REG_CLEAR_IRQ_INDEX); +} + +/** One Shot */ +void dualtimer_cmsdk_set_oneshot_count_timer1( + const struct dualtimer_cmsdk_dev_t* dev, + enum dualtimer_cmsdk_oneshot_t mode) +{ + if (DUALTIMER_CMSDK_ONE_SHOT == mode) { + SET_BIT(DUALTIMER_REG_MAP(dev)->timer1ctrl, CTRL_REG_ONE_SHOT_INDEX); + } else { + CLR_BIT(DUALTIMER_REG_MAP(dev)->timer1ctrl, CTRL_REG_ONE_SHOT_INDEX); + } +} + +void dualtimer_cmsdk_set_oneshot_count_timer2( + const struct dualtimer_cmsdk_dev_t* dev, + enum dualtimer_cmsdk_oneshot_t mode) +{ + if (DUALTIMER_CMSDK_ONE_SHOT == mode) { + SET_BIT(DUALTIMER_REG_MAP(dev)->timer2ctrl, CTRL_REG_ONE_SHOT_INDEX); + } else { + CLR_BIT(DUALTIMER_REG_MAP(dev)->timer2ctrl, CTRL_REG_ONE_SHOT_INDEX); + } +} + +void dualtimer_cmsdk_set_oneshot_count_both_timers( + const struct dualtimer_cmsdk_dev_t* dev, + enum dualtimer_cmsdk_oneshot_t mode) +{ + dualtimer_cmsdk_set_oneshot_count_timer1(dev, mode); + dualtimer_cmsdk_set_oneshot_count_timer2(dev, mode); +} + +/** Timer Size */ +void dualtimer_cmsdk_set_size_timer1(const struct dualtimer_cmsdk_dev_t* dev, + enum dualtimer_cmsdk_size_t bit_size) +{ + if (DUALTIMER_CMSDK_SIZE_32BIT == bit_size) { + SET_BIT(DUALTIMER_REG_MAP(dev)->timer1ctrl, CTRL_REG_SIZE_INDEX); + } else { + CLR_BIT(DUALTIMER_REG_MAP(dev)->timer1ctrl, CTRL_REG_SIZE_INDEX); + } +} +void dualtimer_cmsdk_set_size_timer2(const struct dualtimer_cmsdk_dev_t* dev, + enum dualtimer_cmsdk_size_t bit_size) +{ + if (DUALTIMER_CMSDK_SIZE_32BIT == bit_size) { + SET_BIT(DUALTIMER_REG_MAP(dev)->timer2ctrl, CTRL_REG_SIZE_INDEX); + } else { + CLR_BIT(DUALTIMER_REG_MAP(dev)->timer2ctrl, CTRL_REG_SIZE_INDEX); + } +} + +void dualtimer_cmsdk_set_size_both_timers( + const struct dualtimer_cmsdk_dev_t* dev, + enum dualtimer_cmsdk_size_t bit_size) +{ + dualtimer_cmsdk_set_size_timer1(dev, bit_size); + dualtimer_cmsdk_set_size_timer2(dev, bit_size); +} + +enum dualtimer_cmsdk_size_t dualtimer_cmsdk_get_size_timer1( + const struct dualtimer_cmsdk_dev_t* dev) +{ + if(GET_BIT(DUALTIMER_REG_MAP(dev)->timer1ctrl, CTRL_REG_SIZE_INDEX)) { + return DUALTIMER_CMSDK_SIZE_32BIT; + } + return DUALTIMER_CMSDK_SIZE_16BIT; +} + +enum dualtimer_cmsdk_size_t dualtimer_cmsdk_get_size_timer2( + const struct dualtimer_cmsdk_dev_t* dev) +{ + if(GET_BIT(DUALTIMER_REG_MAP(dev)->timer2ctrl, CTRL_REG_SIZE_INDEX)) { + return DUALTIMER_CMSDK_SIZE_32BIT; + } + return DUALTIMER_CMSDK_SIZE_16BIT; +} + +/** Timer Prescale */ +void dualtimer_cmsdk_set_prescale_timer1( + const struct dualtimer_cmsdk_dev_t* dev, + enum dualtimer_cmsdk_prescale_t prescale) +{ + SET_NBITS(DUALTIMER_REG_MAP(dev)->timer1ctrl, CTRL_REG_PRESCALE_INDEX, + TWO_BITS_WIDTH, prescale); +} + +void dualtimer_cmsdk_set_prescale_timer2( + const struct dualtimer_cmsdk_dev_t* dev, + enum dualtimer_cmsdk_prescale_t prescale) +{ + SET_NBITS(DUALTIMER_REG_MAP(dev)->timer2ctrl, CTRL_REG_PRESCALE_INDEX, + TWO_BITS_WIDTH, prescale); +} +void dualtimer_cmsdk_set_prescale_both_timers( + const struct dualtimer_cmsdk_dev_t* dev, + enum dualtimer_cmsdk_prescale_t prescale) +{ + dualtimer_cmsdk_set_prescale_timer1(dev, prescale); + dualtimer_cmsdk_set_prescale_timer2(dev, prescale); +} + +enum dualtimer_cmsdk_prescale_t dualtimer_cmsdk_get_prescale_timer1( + const struct dualtimer_cmsdk_dev_t* dev) +{ + return (enum dualtimer_cmsdk_prescale_t)\ + GET_NBITS(DUALTIMER_REG_MAP(dev)->timer1ctrl, CTRL_REG_PRESCALE_INDEX, + TWO_BITS_WIDTH); +} + +enum dualtimer_cmsdk_prescale_t dualtimer_cmsdk_get_prescale_timer2( + const struct dualtimer_cmsdk_dev_t* dev) +{ + return (enum dualtimer_cmsdk_prescale_t)\ + GET_NBITS(DUALTIMER_REG_MAP(dev)->timer2ctrl, CTRL_REG_PRESCALE_INDEX, + TWO_BITS_WIDTH); +} + +/** Timer Mode */ +void dualtimer_cmsdk_set_mode_timer1(const struct dualtimer_cmsdk_dev_t* dev, + enum dualtimer_cmsdk_mode_t mode) +{ + if (DUALTIMER_CMSDK_PERIODIC == mode) { + SET_BIT(DUALTIMER_REG_MAP(dev)->timer1ctrl, CTRL_REG_MODE_INDEX); + } else { + CLR_BIT(DUALTIMER_REG_MAP(dev)->timer1ctrl, CTRL_REG_MODE_INDEX); + } +} + +void dualtimer_cmsdk_set_mode_timer2(const struct dualtimer_cmsdk_dev_t* dev, + enum dualtimer_cmsdk_mode_t mode) +{ + if (DUALTIMER_CMSDK_PERIODIC == mode) { + SET_BIT(DUALTIMER_REG_MAP(dev)->timer2ctrl, CTRL_REG_MODE_INDEX); + } else { + CLR_BIT(DUALTIMER_REG_MAP(dev)->timer2ctrl, CTRL_REG_MODE_INDEX); + } +} + +void dualtimer_cmsdk_set_mode_both_timers( + const struct dualtimer_cmsdk_dev_t* dev, + enum dualtimer_cmsdk_mode_t mode) +{ + dualtimer_cmsdk_set_mode_timer1(dev, mode); + dualtimer_cmsdk_set_mode_timer2(dev, mode); +} + +enum dualtimer_cmsdk_mode_t dualtimer_cmsdk_get_mode_timer1( + const struct dualtimer_cmsdk_dev_t* dev) +{ + return (enum dualtimer_cmsdk_mode_t)\ + GET_BIT(DUALTIMER_REG_MAP(dev)->timer1ctrl, CTRL_REG_MODE_INDEX); +} + +enum dualtimer_cmsdk_mode_t dualtimer_cmsdk_get_mode_timer2( + const struct dualtimer_cmsdk_dev_t* dev) +{ + return (enum dualtimer_cmsdk_mode_t)\ + GET_BIT(DUALTIMER_REG_MAP(dev)->timer2ctrl, CTRL_REG_MODE_INDEX); +} + +/** Reload-Background reload */ +enum dualtimer_cmsdk_error_t dualtimer_cmsdk_set_reload_timer1( + const struct dualtimer_cmsdk_dev_t* dev, + uint32_t reload) +{ + const uint32_t rel_size = dualtimer_cmsdk_get_size_timer1(dev); + if (DUALTIMER_CMSDK_SIZE_16BIT == rel_size && UINT16_MAX <= reload) { + return DUALTIMER_CMSDK_ERR_OVERFLOW; + } + DUALTIMER_REG_MAP(dev)->timer1load = reload; + return DUALTIMER_CMSDK_ERR_NONE; +} + +enum dualtimer_cmsdk_error_t dualtimer_cmsdk_set_reload_timer2( + const struct dualtimer_cmsdk_dev_t* dev, + uint32_t reload) +{ + const uint32_t rel_size = dualtimer_cmsdk_get_size_timer2(dev); + if (DUALTIMER_CMSDK_SIZE_16BIT == rel_size && UINT16_MAX <= reload) { + return DUALTIMER_CMSDK_ERR_OVERFLOW; + } + DUALTIMER_REG_MAP(dev)->timer2load = reload; + return DUALTIMER_CMSDK_ERR_NONE; +} + +enum dualtimer_cmsdk_error_t dualtimer_cmsdk_set_reload_both_timers( + const struct dualtimer_cmsdk_dev_t* dev, + uint32_t reload) +{ + uint32_t ret = 0; + ret +=(uint32_t)dualtimer_cmsdk_set_reload_timer2(dev, reload); + ret +=(uint32_t)dualtimer_cmsdk_set_reload_timer2(dev, reload); + if (ret) { + return DUALTIMER_CMSDK_ERR_OVERFLOW; + } + return DUALTIMER_CMSDK_ERR_NONE; +} + +uint32_t dualtimer_cmsdk_get_reload_timer1( + const struct dualtimer_cmsdk_dev_t* dev) +{ + return DUALTIMER_REG_MAP(dev)->timer1load; +} + +uint32_t dualtimer_cmsdk_get_reload_timer2( + const struct dualtimer_cmsdk_dev_t* dev) +{ + return DUALTIMER_REG_MAP(dev)->timer2load; +} + +enum dualtimer_cmsdk_error_t dualtimer_cmsdk_set_bgreload_timer1( + const struct dualtimer_cmsdk_dev_t* dev, + uint32_t reload) +{ + const uint32_t rel_size = dualtimer_cmsdk_get_size_timer1(dev); + if (DUALTIMER_CMSDK_SIZE_16BIT == rel_size && UINT16_MAX <= reload) { + return DUALTIMER_CMSDK_ERR_OVERFLOW; + } + DUALTIMER_REG_MAP(dev)->timer1bgload = reload; + return DUALTIMER_CMSDK_ERR_NONE; +} + +enum dualtimer_cmsdk_error_t dualtimer_cmsdk_set_bgreload_timer2( + const struct dualtimer_cmsdk_dev_t* dev, + uint32_t reload) +{ + const uint32_t rel_size = dualtimer_cmsdk_get_size_timer2(dev); + if (DUALTIMER_CMSDK_SIZE_16BIT == rel_size && UINT16_MAX <= reload) { + return DUALTIMER_CMSDK_ERR_OVERFLOW; + } + DUALTIMER_REG_MAP(dev)->timer2bgload = reload; + return DUALTIMER_CMSDK_ERR_NONE; +} + +enum dualtimer_cmsdk_error_t dualtimer_cmsdk_set_bgreload_both_timers( + const struct dualtimer_cmsdk_dev_t* dev, + uint32_t reload) +{ + uint32_t ret = 0; + ret +=(uint32_t)dualtimer_cmsdk_set_bgreload_timer1(dev, reload); + ret +=(uint32_t)dualtimer_cmsdk_set_bgreload_timer2(dev, reload); + if (ret) { + return DUALTIMER_CMSDK_ERR_OVERFLOW; + } + return DUALTIMER_CMSDK_ERR_NONE; +} + +uint32_t dualtimer_cmsdk_get_bgreload_timer1( + const struct dualtimer_cmsdk_dev_t* dev) +{ + return DUALTIMER_REG_MAP(dev)->timer1bgload; +} + +uint32_t dualtimer_cmsdk_get_bgreload_timer2( + const struct dualtimer_cmsdk_dev_t* dev) +{ + return DUALTIMER_REG_MAP(dev)->timer2bgload; +} + +/** Current timer value */ +uint32_t dualtimer_cmsdk_get_current_timer1( + const struct dualtimer_cmsdk_dev_t* dev) +{ + return DUALTIMER_REG_MAP(dev)->timer1value; +} + +uint32_t dualtimer_cmsdk_get_current_timer2( + const struct dualtimer_cmsdk_dev_t* dev) +{ + return DUALTIMER_REG_MAP(dev)->timer2value; +} + +/** Status check methods */ +bool dualtimer_cmsdk_is_enabled_timer1( + const struct dualtimer_cmsdk_dev_t* dev) +{ + return (bool)GET_BIT(DUALTIMER_REG_MAP(dev)->timer1ctrl, + CTRL_REG_TIMER_EN_INDEX); +} + +bool dualtimer_cmsdk_is_enabled_timer2( + const struct dualtimer_cmsdk_dev_t* dev) +{ + return (bool)GET_BIT(DUALTIMER_REG_MAP(dev)->timer2ctrl, + CTRL_REG_TIMER_EN_INDEX); +} + +bool dualtimer_cmsdk_is_interrupt_enabled_timer1( + const struct dualtimer_cmsdk_dev_t* dev) +{ + return (bool)GET_BIT(DUALTIMER_REG_MAP(dev)->timer1ctrl, + CTRL_REG_IRQ_EN_INDEX); +} + +bool dualtimer_cmsdk_is_interrupt_enabled_timer2( + const struct dualtimer_cmsdk_dev_t* dev) +{ + return (bool)GET_BIT(DUALTIMER_REG_MAP(dev)->timer2ctrl, + CTRL_REG_IRQ_EN_INDEX); +} + +bool dualtimer_cmsdk_is_interrupt_active_timer1( + const struct dualtimer_cmsdk_dev_t* dev) +{ + return (bool)GET_BIT(DUALTIMER_REG_MAP(dev)->timer1mis, + XMIS_REG_MASKED_IRQ_INDEX); +} + +bool dualtimer_cmsdk_is_interrupt_active_timer2( + const struct dualtimer_cmsdk_dev_t* dev) +{ + return (bool)GET_BIT(DUALTIMER_REG_MAP(dev)->timer2mis, + XMIS_REG_MASKED_IRQ_INDEX); +} + +bool dualtimer_cmsdk_is_raw_interrupt_active_timer1( + const struct dualtimer_cmsdk_dev_t* dev) +{ + return (bool)GET_BIT(DUALTIMER_REG_MAP(dev)->timer1ris, + XRIS_REG_RAW_IRQ_INDEX); +} + +bool dualtimer_cmsdk_is_raw_interrupt_active_timer2( + const struct dualtimer_cmsdk_dev_t* dev) +{ + return (bool)GET_BIT(DUALTIMER_REG_MAP(dev)->timer2ris, + XRIS_REG_RAW_IRQ_INDEX); +} + +uint32_t dualtimer_cmsdk_get_elapsed_value_timer1( + const struct dualtimer_cmsdk_dev_t* dev) +{ + struct dualtimer_cmsdk_reg_map_t* register_map = + (struct dualtimer_cmsdk_reg_map_t*)dev->cfg->base; + return register_map->timer1load - register_map->timer1value; +} + +uint32_t dualtimer_cmsdk_get_elapsed_value_timer2( + const struct dualtimer_cmsdk_dev_t* dev) +{ + struct dualtimer_cmsdk_reg_map_t* register_map = + (struct dualtimer_cmsdk_reg_map_t*)dev->cfg->base; + return register_map->timer2load - register_map->timer2value; +} + +void dualtimer_cmsdk_reset_timer1(const struct dualtimer_cmsdk_dev_t* dev) +{ + struct dualtimer_cmsdk_reg_map_t* register_map = + (struct dualtimer_cmsdk_reg_map_t*)dev->cfg->base; + register_map->timer1value = register_map->timer1load; +} + +void dualtimer_cmsdk_reset_timer2(const struct dualtimer_cmsdk_dev_t* dev) +{ + struct dualtimer_cmsdk_reg_map_t* register_map = + (struct dualtimer_cmsdk_reg_map_t*)dev->cfg->base; + register_map->timer2value = register_map->timer2load; +} + +void dualtimer_cmsdk_reset_both_timers(const struct dualtimer_cmsdk_dev_t* dev) +{ + struct dualtimer_cmsdk_reg_map_t* register_map = + (struct dualtimer_cmsdk_reg_map_t*)dev->cfg->base; + register_map->timer1value = register_map->timer1load; + register_map->timer2value = register_map->timer2load; +} \ No newline at end of file diff --git a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/drivers/dualtimer_cmsdk_drv.h b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/drivers/dualtimer_cmsdk_drv.h new file mode 100644 index 0000000000..50a8e1bf75 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/drivers/dualtimer_cmsdk_drv.h @@ -0,0 +1,888 @@ +/* + * Copyright (c) 2016-2018 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. + */ + +/** + * \file dualtimer_cmsdk_drv.h + * \brief Generic driver for ARM CMSDK Dualtimers. + */ + +#ifndef __DUALTIMER_CMSDK_DRV_H__ +#define __DUALTIMER_CMSDK_DRV_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Dualtimer default reload value */ +#define DUALTIMER_CMSDK_DEF_32BIT_RELOAD UINT32_MAX +#define DUALTIMER_CMSDK_DEF_16BIT_RELOAD UINT16_MAX + +/* Dualtimer device configuration structure */ +struct dualtimer_cmsdk_dev_cfg_t { + const uint32_t base; /*!< Dualtimer base address */ +}; + +/* Dualtimer device data structure */ +struct dualtimer_cmsdk_dev_data_t { + uint32_t is_initialized; /*!< Indicates if the timer is initialized */ +}; + +/* Dualtimer device structure */ +struct dualtimer_cmsdk_dev_t { + const struct dualtimer_cmsdk_dev_cfg_t* const cfg; /*!< Dualtimer + configuration */ + struct dualtimer_cmsdk_dev_data_t* const data; /*!< Dualtimer data */ +}; + +/* Dualtimer enumeration types */ +enum dualtimer_cmsdk_error_t { + DUALTIMER_CMSDK_ERR_NONE = 0u, /*!< No error */ + DUALTIMER_CMSDK_ERR_NOT_INIT, /*!< Error dualtimer is not initialized */ + DUALTIMER_CMSDK_ERR_NOT_ENABLE, /*!< Error timer is not enabled */ + DUALTIMER_CMSDK_ERR_OVERFLOW +}; + +enum dualtimer_cmsdk_size_t { + DUALTIMER_CMSDK_SIZE_16BIT = 0u, /*!< Timer is set as 16 Bit */ + DUALTIMER_CMSDK_SIZE_32BIT = 1u /*!< Timer is set as 32 Bit */ +}; + +enum dualtimer_cmsdk_prescale_t { + DUALTIMER_CMSDK_CLOCK_DIV1 = 0u, /*!< Timer pre-scale is clock/1 */ + DUALTIMER_CMSDK_CLOCK_DIV16 = 1u, /*!< Timer pre-scale is clock/16 */ + DUALTIMER_CMSDK_CLOCK_DIV256 = 2u, /*!< Timer pre-scale is clock/256 */ +}; + +enum dualtimer_cmsdk_oneshot_t { + DUALTIMER_CMSDK_WRAPPING = 0u, /*!< Timer wraps around */ + DUALTIMER_CMSDK_ONE_SHOT = 1u /*!< Timer will halt when reaching 0 */ +}; + +enum dualtimer_cmsdk_mode_t { + DUALTIMER_CMSDK_FREE_RUNNING = 0u, /*!< Timer counts from UINT32_MAX */ + DUALTIMER_CMSDK_PERIODIC = 1u /*!< Timer counts from load value */ +}; + +/** + * \brief Initializes a dualtimer hardware. + * + * \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t + * + * \note This function doesn't check if dev is NULL. + * \note Init should be called prior to any other process. + */ +void dualtimer_cmsdk_init(const struct dualtimer_cmsdk_dev_t* dev); + +/** + * \brief Frees up a dualtimer hardware, so it could be reinitalized. + * + * \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t + * + * \note This function doesn't check if dev is NULL. + * \note Init should be called prior to any other process. + */ +void dualtimer_cmsdk_free(const struct dualtimer_cmsdk_dev_t* dev); + +/** + * \brief Enables single timer 1 included in dualtimer hardware. + * + * \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t + * + * \note This function doesn't check if dev is NULL. + * \note This function doesn't check if dualtimer has been initialized. + */ + void dualtimer_cmsdk_enable_timer1(const struct dualtimer_cmsdk_dev_t* dev); + + /** + * \brief Enables single timer 2 included in dualtimer hardware. + * + * \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t + * + * \note This function doesn't check if dev is NULL. + * \note This function doesn't check if dualtimer has been initialized. + */ + void dualtimer_cmsdk_enable_timer2(const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Enables both timer 1&2 included in dualtimer hardware. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +void dualtimer_cmsdk_enable_both_timers( + const struct dualtimer_cmsdk_dev_t* dev); + + +/** +* \brief Disables timer 1 included in dualtimer hardware. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +void dualtimer_cmsdk_disable_timer1( + const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Disables timer 2 included in dualtimer hardware. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +void dualtimer_cmsdk_disable_timer2(const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Disables both timers 1&2 included in dualtimer hardware. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +void dualtimer_cmsdk_disable_both_timers( + const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Sets one shot count for timer 1 included in dualtimer hardware. +* +* When timer reaches zero if one-shot is set it will wait there until user +* does one of the following: +* - Write a new value to load register. +* - Clear one shot setting the timers to WRAPPING mode. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* \param[in] mode enum dualtimer_cmsdk_oneshot_t WRAPPING/ONE_SHOT +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +void dualtimer_cmsdk_set_oneshot_count_timer1( + const struct dualtimer_cmsdk_dev_t* dev, + enum dualtimer_cmsdk_oneshot_t mode); + +/** +* \brief Sets one shot count for timer 2 included in dualtimer hardware. +* +* When timer reaches zero if one-shot is set it will wait there until user +* does one of the following: +* - Write a new value to load register. +* - Clear one shot setting the timers to WRAPPING mode. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* \param[in] mode enum dualtimer_cmsdk_oneshot_t WRAPING/ONE_SHOT +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +void dualtimer_cmsdk_set_oneshot_count_timer2( + const struct dualtimer_cmsdk_dev_t* dev, + enum dualtimer_cmsdk_oneshot_t mode); + +/** +* \brief Sets one shot count for timers 1&2 included in dualtimer hardware. +* +* When timer reaches zero if one-shot is set it will wait there until user +* does one of the following: +* - Write a new value to load register. +* - Clear one shot setting the timers to WRAPPING mode. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* \param[in] mode enum dualtimer_cmsdk_oneshot_t WRAPING/ONE_SHOT +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +void dualtimer_cmsdk_set_oneshot_count_both_timers( + const struct dualtimer_cmsdk_dev_t* dev, + enum dualtimer_cmsdk_oneshot_t mode); + +/** +* \brief Sets the size of timer 1 included in dualtimer hardware. +* +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* \param[in] bit_size enum dualtimer_cmsdk_oneshot_t SIZE_16BIT/SIZE_32BIT +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +void dualtimer_cmsdk_set_size_timer1( + const struct dualtimer_cmsdk_dev_t* dev, + enum dualtimer_cmsdk_size_t bit_size); + +/** +* \brief Sets the size of timer 2 included in dualtimer hardware. +* +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* \param[in] bit_size enum dualtimer_cmsdk_oneshot_t SIZE_16BIT/SIZE_32BIT +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +void dualtimer_cmsdk_set_size_timer2( + const struct dualtimer_cmsdk_dev_t* dev, + enum dualtimer_cmsdk_size_t bit_size); + +/** +* \brief Sets the size of timers 1&2 included in dualtimer hardware. +* +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* \param[in] bit_size enum dualtimer_cmsdk_oneshot_t SIZE_16BIT/SIZE_32BIT +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +void dualtimer_cmsdk_set_size_both_timers( + const struct dualtimer_cmsdk_dev_t* dev, + enum dualtimer_cmsdk_size_t bit_size); + +/** +* \brief Gets the size of timer 1 included in dualtimer hardware. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \return enum dualtimer_cmsdk_oneshot_t SIZE_16BIT/SIZE_32BIT +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +enum dualtimer_cmsdk_size_t dualtimer_cmsdk_get_size_timer1( + const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Gets the size of timer 2 included in dualtimer hardware. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \return enum dualtimer_cmsdk_oneshot_t SIZE_16BIT/SIZE_32BIT +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +enum dualtimer_cmsdk_size_t dualtimer_cmsdk_get_size_timer2( + const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Sets the clock divider for timer 1 included in dualtimer hardware. +* +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* \param[in] enum dualtimer_cmsdk_prescale_t prescale CLOCK_DIV1/16/256 +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +void dualtimer_cmsdk_set_prescale_timer1( + const struct dualtimer_cmsdk_dev_t* dev, + enum dualtimer_cmsdk_prescale_t prescale); + +/** +* \brief Sets the clock divider for timer 2 included in dualtimer hardware. +* +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* \param[in] enum dualtimer_cmsdk_prescale_t prescale CLOCK_DIV1/16/256 +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +void dualtimer_cmsdk_set_prescale_timer2( + const struct dualtimer_cmsdk_dev_t* dev, + enum dualtimer_cmsdk_prescale_t prescale); + +/** +* \brief Sets the clock divider for timers 1&2 included in dualtimer hardware. +* +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* \param[in] enum dualtimer_cmsdk_prescale_t prescale CLOCK_DIV1/16/256 +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +void dualtimer_cmsdk_set_prescale_both_timers( + const struct dualtimer_cmsdk_dev_t* dev, + enum dualtimer_cmsdk_prescale_t prescale); + +/** +* \brief Gets the current set prescale value for timer 1. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \return enum dualtimer_cmsdk_prescale_t prescale CLOCK_DIV1/16/256 +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +enum dualtimer_cmsdk_prescale_t dualtimer_cmsdk_get_prescale_timer1( + const struct dualtimer_cmsdk_dev_t* dev); + + +/** +* \brief Gets the current set prescale value for timer 2. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \return enum dualtimer_cmsdk_prescale_t prescale CLOCK_DIV1/16/256 +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +enum dualtimer_cmsdk_prescale_t dualtimer_cmsdk_get_prescale_timer2( + const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Sets the run mode for timer1 1 included in dualtimer hardware. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* \param[in] enum dualtimer_cmsdk_mode_t mode FREE_RUNNING/PERIODIC +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +void dualtimer_cmsdk_set_mode_timer1(const struct dualtimer_cmsdk_dev_t* dev, + enum dualtimer_cmsdk_mode_t mode); + +/** +* \brief Sets the run mode for timer 2 included in dualtimer hardware. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* \param[in] enum dualtimer_cmsdk_mode_t mode FREE_RUNNING/PERIODIC +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +void dualtimer_cmsdk_set_mode_timer2(const struct dualtimer_cmsdk_dev_t* dev, + enum dualtimer_cmsdk_mode_t mode); + +/** +* \brief Sets the run mode for timers 1&2 included in dualtimer hardware. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* \param[in] enum dualtimer_cmsdk_mode_t mode FREE_RUNNING/PERIODIC +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +void dualtimer_cmsdk_set_mode_both_timers( + const struct dualtimer_cmsdk_dev_t* dev, + enum dualtimer_cmsdk_mode_t mode); + +/** +* \brief Gets the run mode for timer 1 included in dualtimer hardware. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \return enum dualtimer_cmsdk_mode_t mode FREE_RUNNING/PERIODIC +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +enum dualtimer_cmsdk_mode_t dualtimer_cmsdk_get_mode_timer1( + const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Gets the run mode for timer 2 included in dualtimer hardware. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \return enum dualtimer_cmsdk_mode_t mode FREE_RUNNING/PERIODIC +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +enum dualtimer_cmsdk_mode_t dualtimer_cmsdk_get_mode_timer2( + const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Enables the interrupt for timer 1 included in dualtimer hardware. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +* \note This function only enables the hardware irq, use NVIC for handler setup. +*/ +void dualtimer_cmsdk_enable_interrupt_timer1( + const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Enables the interrupt for timer 2 included in dualtimer hardware. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +* \note This function only enables the hardware irq, use NVIC for handler setup. +*/ +void dualtimer_cmsdk_enable_interrupt_timer2( + const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Enables the interrupt for timer 1&2 included in dualtimer hardware. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +* \note This function only enables the hardware irq, use NVIC for handler setup. +*/ +void dualtimer_cmsdk_enable_interrupt_both_timers( + const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Disables the interrupt for timer 1 included in dualtimer hardware. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +void dualtimer_cmsdk_disable_interrupt_timer1( + const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Disables the interrupt for timer 2 included in dualtimer hardware. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +void dualtimer_cmsdk_disable_interrupt_timer2( + const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Disables the interrupt for timers 1&2 included in dualtimer hardware. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +void dualtimer_cmsdk_disable_interrupt_both_timers( + const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Clears the interrupt for timer 1 included in dualtimer hardware. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +void dualtimer_cmsdk_clear_interrupt_timer1( + const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Clears the interrupt for timer 2 included in dualtimer hardware. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +void dualtimer_cmsdk_clear_interrupt_timer2( + const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Set the reload value for timer 1 included in dualtimer hardware. +* +* Writing to the reload register while timer is active will reset the +* current value register to the reload value +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* \param[in] reload uint32_t value that the timer counts down from +* +* \return dualtimer_cmsdk_error_t NONE/ERR_OVERFLOW +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +* \note This function will detect if users sets a uint32_t value to 16Bit timer +*/ +enum dualtimer_cmsdk_error_t dualtimer_cmsdk_set_reload_timer1( + const struct dualtimer_cmsdk_dev_t* dev, + uint32_t reload); + +/** +* \brief Set the reload value for timer 2 included in dualtimer hardware. +* +* Writing to the reload register while timer is active will reset the +* current value register to the reload value +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* \param[in] reload uint32_t value that the timer counts down from +* +* \return dualtimer_cmsdk_error_t NONE/ERR_OVERFLOW +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +* \note This function will detect if users sets a uint32_t value to 16Bit timer +*/ +enum dualtimer_cmsdk_error_t dualtimer_cmsdk_set_reload_timer2( + const struct dualtimer_cmsdk_dev_t* dev, + uint32_t reload); + +/** +* \brief Set the reload value for timers 1&2 included in dualtimer hardware. +* +* Writing to the reload register while timer is active will reset the +* current value register to the reload value +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* \param[in] reload uint32_t value that the timer counts down from +* +* \return dualtimer_cmsdk_error_t NONE/ERR_OVERFLOW +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +* \note This function will detect if users sets a uint32_t value to 16Bit timer +*/ +enum dualtimer_cmsdk_error_t dualtimer_cmsdk_set_reload_both_timers( + const struct dualtimer_cmsdk_dev_t* dev, + uint32_t reload); + +/** +* \brief Gets the reload value for timer 1 included in dualtimer hardware. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \return uint32_t Reload value of timer 1 +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +uint32_t dualtimer_cmsdk_get_reload_timer1( + const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Gets the reload value for timer 2 included in dualtimer hardware. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \return uint32_t Reload value of timer 2 +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +uint32_t dualtimer_cmsdk_get_reload_timer2( + const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Set the background-reload value for timer 1 of dualtimer hw. +* +* Unlike normal reload, writing to this register will not affect current +* value of timer, and the change become effective after the timer counts to zero +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* \param[in] reload uint32_t value that the timer counts down from +* +* \return dualtimer_cmsdk_error_t NONE/ERR_OVERFLOW +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +* \note This function will detect if users sets a uint32_t value to 16Bit timer +*/ +enum dualtimer_cmsdk_error_t dualtimer_cmsdk_set_bgreload_timer1( + const struct dualtimer_cmsdk_dev_t* dev, + uint32_t reload); + +/** +* \brief Set the background-reload value for timers 2 of dualtimer hw. +* +* Unlike normal reload, writing to this register will not affect current +* value of timer, and the change become effective after the timer counts to zero +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* \param[in] reload uint32_t value that the timer counts down from +* +* \return dualtimer_cmsdk_error_t NONE/ERR_OVERFLOW +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +* \note This function will detect if users sets a uint32_t value to 16Bit timer +*/ +enum dualtimer_cmsdk_error_t dualtimer_cmsdk_set_bgreload_timer2( + const struct dualtimer_cmsdk_dev_t* dev, + uint32_t reload); + +/** +* \brief Set the background-reload value for timers 1&2 of dualtimer hw. +* +* Unlike normal reload, writing to this register will not affect current +* value of timer, and the change become effective after the timer counts to zero +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* \param[in] reload uint32_t value that the timer counts down from +* +* \return dualtimer_cmsdk_error_t NONE/ERR_OVERFLOW +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +* \note This function will detect if users sets a uint32_t value to 16Bit timer +*/ +enum dualtimer_cmsdk_error_t dualtimer_cmsdk_set_bgreload_both_timers( + const struct dualtimer_cmsdk_dev_t* dev, + uint32_t reload); + +/** +* \brief Gets the background-reload value for timer 1 of dualtimer hw. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \return uint32_t Reload value of timer 1 +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +uint32_t dualtimer_cmsdk_get_bgreload_timer1( + const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Gets the background-reload value for timer 2 of dualtimer hw. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \return uint32_t Reload value of timer 2 +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +uint32_t dualtimer_cmsdk_get_bgreload_timer2( + const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Gets the current value for timer 1 included in dualtimer hardware. +* +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \return uint32_t Copy of current value of timer. +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +uint32_t dualtimer_cmsdk_get_current_timer1( + const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Gets the current value for timer 2 included in dualtimer hardware. +* +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \return uint32_t Copy of current value of timer. +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +uint32_t dualtimer_cmsdk_get_current_timer2( + const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Checks if timer 1 included in dualtimer hardware, is enabled. +* +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \return bool true if timer 1 is enabled. +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +bool dualtimer_cmsdk_is_enabled_timer1(const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Checks if timer 2 included in dualtimer hardware, is enabled. +* +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \return bool true if timer 2 is enabled. +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +bool dualtimer_cmsdk_is_enabled_timer2(const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Checks if timer 1 included in dualtimer hardware, has the irq enabled. +* +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \return bool true if timer 1 irq is enabled. +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +bool dualtimer_cmsdk_is_interrupt_enabled_timer1( + const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Checks if timer 2 included in dualtimer hardware, has the irq enabled. +* +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \return bool true if timer 2 irq is enabled. +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +bool dualtimer_cmsdk_is_interrupt_enabled_timer2( + const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Checks the masked interrupt status of timer 1 included in dualtimer hw. +* +* This function is checking against the masked interrupt register which is the +* output of timerx enabled AND timerX raw interrupt. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \return bool true if timer 1's masked irq is active +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +bool dualtimer_cmsdk_is_interrupt_active_timer1( + const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Checks the masked interrupt status of timer 1 included in dualtimer hw. +* +* This function is checking against the masked interrupt register which is the +* output of timerx enabled AND timerX raw interrupt. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \return bool true if timer 2's masked irq is active +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +bool dualtimer_cmsdk_is_interrupt_active_timer2( + const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Checks the raw interrupt status of timer 1 included in dualtimer hw. +* +* This function is checking for the raw interrupt produced when timer reaches 0 +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \return bool true if timer 1's masked irq is active +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +bool dualtimer_cmsdk_is_raw_interrupt_active_timer1( + const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Checks the raw interrupt status of timer 1 included in dualtimer hw. +* +* This function is checking for the raw interrupt produced when timer reaches 0 +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \return bool true if timer 2's masked irq is active +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +bool dualtimer_cmsdk_is_raw_interrupt_active_timer2( + const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Checks if dualtimer hardware has been initialized. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \return bool true if dualtimer has been initialized. +* +* \note This function doesn't check if dev is NULL. +*/ +bool dualtimer_cmsdk_is_initialized(const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Reads the number of ticks elapsed in the current cycle of timer 1. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \return Get elapsed number of ticks since last reload was set. +* Elapsed = (Reload value - Current value) +*/ +uint32_t dualtimer_cmsdk_get_elapsed_value_timer1( + const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Reads the number of ticks elapsed in the current cycle of timer 2. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \return Get elapsed number of ticks since last reload was set. +* Elapsed = (Reload value - Current value) +*/ +uint32_t dualtimer_cmsdk_get_elapsed_value_timer2( + const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Resets the timer 1 count value to the reload value. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +void dualtimer_cmsdk_reset_timer1(const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Resets the timer 2 count value to the reload value. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +void dualtimer_cmsdk_reset_timer2(const struct dualtimer_cmsdk_dev_t* dev); + +/** +* \brief Resets both timers' count values to their reload values. +* +* \param[in] dev Dualtimer device structure \ref dualtimer_cmsdk_dev_t +* +* \note This function doesn't check if dev is NULL. +* \note This function doesn't check if dualtimer has been initialized. +*/ +void dualtimer_cmsdk_reset_both_timers(const struct dualtimer_cmsdk_dev_t* dev); + + +#ifdef __cplusplus +} +#endif +#endif /* __DUALTIMER_CMSDK_DRV_H__ */ diff --git a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/drivers/rtc_pl031_drv.c b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/drivers/rtc_pl031_drv.c new file mode 100644 index 0000000000..dc53cec8cf --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/drivers/rtc_pl031_drv.c @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2018 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. + */ + +/** + * \file rtc_pl031_drv.c + * \brief Implementation of the PL031 Real Time Clock (RTC) native driver. + * + * \note PL031 device specific definitions based on + * real_time_clock_pl031_r1p3_technical_reference_manual.pdf + * which is available from http://infocenter.arm.com. + */ + +#include +#include "rtc_pl031_drv.h" + +/** + * \brief Structure to access the memory mapped registers of the PL031. + */ +struct rtc_pl031_dev_reg_map_t { + volatile uint32_t rtcdr; /*!< Data Register */ + volatile uint32_t rtcmr; /*!< Match Register */ + volatile uint32_t rtclr; /*!< Load Register */ + volatile uint32_t rtccr; /*!< Control Register */ + volatile uint32_t rtcimsc; + /*!< Interrupt Mask Set or Clear Register */ + volatile uint32_t rtcris; /*!< Raw Interrupt Status Register */ + volatile uint32_t rtcmis; /*!< Masked Interrupt Status Register */ + volatile uint32_t rtcicr; /*!< Interrupt Clear Register */ + volatile uint32_t reserved[1008]; /*!< Reserved from Offset 0x20-0xFDC */ + volatile uint32_t rtcperiphid0; /*!< Peripheral ID0 Register */ + volatile uint32_t rtcperiphid1; /*!< Peripheral ID1 Register */ + volatile uint32_t rtcperiphid2; /*!< Peripheral ID2 Register */ + volatile uint32_t rtcperiphid3; /*!< Peripheral ID3 Register */ + volatile uint32_t rtcpcellid0; /*!< Primary Cell ID0 Register */ + volatile uint32_t rtcpcellid1; /*!< Primary Cell ID1 Register */ + volatile uint32_t rtcpcellid2; /*!< Primary Cell ID2 Register */ + volatile uint32_t rtcpcellid3; /*!< Primary Cell ID3 Register */ +}; + +/* RTC Control Register */ +#define RTC_PL031_RTCCR_ENABLE_POS 0x0U +#define RTC_PL031_RTCCR_ENABLE_MSK (0x1U << RTC_PL031_RTCCR_ENABLE_POS) + +/* RTC Interrupt Mask Set or Clear Register */ +#define RTC_PL031_RTCIMSC_SET_CLEAR_POS 0x0U +#define RTC_PL031_RTCIMSC_SET_CLEAR_MSK (0x1U << \ + RTC_PL031_RTCIMSC_SET_CLEAR_POS) + +/* RTC RAW Interrupt Status Register */ +#define RTC_PL031_RTCRIS_STATUS_POS 0x0U +#define RTC_PL031_RTCRIS_STATUS_MSK (0x1U << RTC_PL031_RTCRIS_STATUS_POS) + +/* RTC Masked Interrupt Status Register */ +#define RTC_PL031_RTCMIS_STATUS_POS 0x0U +#define RTC_PL031_RTCMIS_STATUS_MSK (0x1U << RTC_PL031_RTCMIS_STATUS_POS) + +/* RTC Interrupt Clear Register */ +#define RTC_PL031_RTCICR_CLEAR_POS 0x0U +#define RTC_PL031_RTCICR_CLEAR_MSK (0x1U << RTC_PL031_RTCICR_CLEAR_POS) + +bool rtc_pl031_init(struct rtc_pl031_dev_t* dev) +{ + struct rtc_pl031_dev_reg_map_t* p_rtc; + + if (dev == NULL) { + return false; + } + + p_rtc = (struct rtc_pl031_dev_reg_map_t*) dev->cfg->base; + p_rtc->rtcmr = 0U; + p_rtc->rtcicr = RTC_PL031_RTCICR_CLEAR_MSK; + return true; +} + +bool rtc_pl031_dev_enable(struct rtc_pl031_dev_t* dev) +{ + struct rtc_pl031_dev_reg_map_t* p_rtc; + + if (dev == NULL) { + return false; + } + + p_rtc = (struct rtc_pl031_dev_reg_map_t*) dev->cfg->base; + p_rtc->rtccr = RTC_PL031_RTCCR_ENABLE_MSK; + return true; +} + +bool rtc_pl031_dev_disable(struct rtc_pl031_dev_t* dev) +{ + struct rtc_pl031_dev_reg_map_t* p_rtc; + + if (dev == NULL) { + return false; + } + + p_rtc = (struct rtc_pl031_dev_reg_map_t*) dev->cfg->base; + p_rtc->rtccr = 0U; + return true; +} + +bool rtc_pl031_read_current_time(struct rtc_pl031_dev_t* dev, uint32_t *seconds) +{ + struct rtc_pl031_dev_reg_map_t* p_rtc; + + if (dev == NULL || seconds == NULL) { + return false; + } + + p_rtc = (struct rtc_pl031_dev_reg_map_t*) dev->cfg->base; + *seconds = (uint32_t)p_rtc->rtcdr; + return true; +} + +bool rtc_pl031_write_current_time(struct rtc_pl031_dev_t* dev, uint32_t seconds) +{ + struct rtc_pl031_dev_reg_map_t* p_rtc; + + if (dev == NULL) { + return false; + } + + p_rtc = (struct rtc_pl031_dev_reg_map_t*) dev->cfg->base; + p_rtc->rtclr = (uint32_t)seconds; + return true; +} + +bool rtc_pl031_enable_interrupt(struct rtc_pl031_dev_t* dev) +{ + struct rtc_pl031_dev_reg_map_t* p_rtc; + + if (dev == NULL) { + return false; + } + + p_rtc = (struct rtc_pl031_dev_reg_map_t*) dev->cfg->base; + p_rtc->rtcimsc = 0U; + return true; +} + +bool rtc_pl031_disable_interrupt(struct rtc_pl031_dev_t* dev) +{ + struct rtc_pl031_dev_reg_map_t* p_rtc; + + if (dev == NULL) { + return false; + } + + p_rtc = (struct rtc_pl031_dev_reg_map_t*) dev->cfg->base; + p_rtc->rtcimsc = RTC_PL031_RTCIMSC_SET_CLEAR_MSK; + return true; +} + +bool rtc_pl031_is_interrupt_masked(struct rtc_pl031_dev_t* dev) +{ + struct rtc_pl031_dev_reg_map_t* p_rtc = + (struct rtc_pl031_dev_reg_map_t*) dev->cfg->base; + + if (p_rtc->rtcimsc & RTC_PL031_RTCIMSC_SET_CLEAR_MSK){ + return true; + } else { + return false; + } +} + +bool rtc_pl031_is_raw_interrupt_pending(struct rtc_pl031_dev_t* dev) +{ + struct rtc_pl031_dev_reg_map_t* p_rtc = + (struct rtc_pl031_dev_reg_map_t*) dev->cfg->base; + + if (p_rtc->rtcris & RTC_PL031_RTCRIS_STATUS_MSK) { + return true; + } else { + return false; + } +} + +bool rtc_pl031_is_masked_interrupt_pending(struct rtc_pl031_dev_t* dev) +{ + struct rtc_pl031_dev_reg_map_t* p_rtc = + (struct rtc_pl031_dev_reg_map_t*) dev->cfg->base; + + if (p_rtc->rtcmis & RTC_PL031_RTCMIS_STATUS_MSK) { + return true; + } else { + return false; + } +} + +bool rtc_pl031_write_match_value(struct rtc_pl031_dev_t* dev, uint32_t seconds) +{ + struct rtc_pl031_dev_reg_map_t* p_rtc; + + if (dev == NULL) { + return false; + } + + p_rtc = (struct rtc_pl031_dev_reg_map_t*) dev->cfg->base; + p_rtc->rtcmr = (uint32_t)seconds; + return true; +} + +bool rtc_pl031_clear_interrupt(struct rtc_pl031_dev_t* dev) +{ + struct rtc_pl031_dev_reg_map_t* p_rtc; + + if (dev == NULL) { + return false; + } + + p_rtc = (struct rtc_pl031_dev_reg_map_t*) dev->cfg->base; + p_rtc->rtcicr = RTC_PL031_RTCICR_CLEAR_MSK; + return true; +} diff --git a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/drivers/rtc_pl031_drv.h b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/drivers/rtc_pl031_drv.h new file mode 100644 index 0000000000..c99f37036d --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/drivers/rtc_pl031_drv.h @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2018 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. + */ + +/** + * \file rtc_pl031_drv.h + * \brief Declarations for the PL031 Real Time Clock (RTC) native driver. + */ + +#ifndef __RTC_PL031_DRV_H__ +#define __RTC_PL031_DRV_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief RTC PL031 device configuration structure. + */ +struct rtc_pl031_dev_cfg_t { + const uintptr_t base; /*!< RTC PL031 base address */ +}; + +/** + * \brief RTC PL031 device structure. + */ +struct rtc_pl031_dev_t { + const struct rtc_pl031_dev_cfg_t* const cfg; + /*!< RTC driver configuration */ +}; + +/** + * \brief Initializes the RTC PL031 device. + * + * \param[in] dev RTC device structure \ref rtc_pl031_dev_t. + * + * \return Return true indicates that the function executed successfully, + * otherwise an error occurred. + */ +bool rtc_pl031_init(struct rtc_pl031_dev_t* dev); + +/** + * \brief Enables RTC PL031 device. + * + * \param[in] dev RTC device structure \ref rtc_pl031_dev_t. + * + * \return Return true indicates that the function executed successfully, + * otherwise an error occurred. + */ +bool rtc_pl031_dev_enable(struct rtc_pl031_dev_t* dev); + +/** + * \brief Disables RTC PL031 device. + * + * \param[in] dev RTC device structure \ref rtc_pl031_dev_t. + * + * \return Return true indicates that the function executed successfully, + * otherwise an error occurred. + */ +bool rtc_pl031_dev_disable(struct rtc_pl031_dev_t* dev); + +/** + * \brief Reads current time from RTC PL031 device. + * + * \param[in] dev RTC device structure \ref rtc_pl031_dev_t. + * \param[out] seconds Current time in seconds. + * + * \return Return true indicates that the function executed successfully, + * otherwise an error occurred. + */ +bool rtc_pl031_read_current_time(struct rtc_pl031_dev_t* dev, + uint32_t *seconds); + +/** + * \brief Writes current time to RTC PL031 device. + * + * \param[in] dev RTC device structure \ref rtc_pl031_dev_t. + * \param[in] seconds Current time to be set in seconds. + * + * \return Return true indicates that the function executed successfully, + * otherwise an error occurred. + */ +bool rtc_pl031_write_current_time(struct rtc_pl031_dev_t* dev, + uint32_t seconds); + +/** + * \brief Clears interrupt mask of RTC PL031. + * + * \param[in] dev RTC device structure \ref rtc_pl031_dev_t. + * + * \return Return true indicates that the function executed successfully, + * otherwise an error occurred. + */ +bool rtc_pl031_enable_interrupt(struct rtc_pl031_dev_t* dev); + +/** + * \brief Sets interrupt mask of RTC PL031. + * + * \param[in] dev RTC device structure \ref rtc_pl031_dev_t. + * + * \return Return true indicates that the function executed successfully, + * otherwise an error occurred. + */ +bool rtc_pl031_disable_interrupt(struct rtc_pl031_dev_t* dev); + +/** + * \brief Check if RTC PL031 interrupt is masked. + * + * \param[in] dev RTC device structure \ref rtc_pl031_dev_t. + * + * \return Return true indicates that RTC PL031 interrupt is masked. + * + * \note This function does not check if dev is NULL. + */ +bool rtc_pl031_is_interrupt_masked(struct rtc_pl031_dev_t* dev); + +/** + * \brief Gets raw interrupt pending status of RTC PL031. + * + * \param[in] dev RTC device structure \ref rtc_pl031_dev_t. + * + * \return Return true indicates that RTC PL031 raw interrupt + * status is pending. + * + * \note This function does not check if dev is NULL. + */ +bool rtc_pl031_is_raw_interrupt_pending(struct rtc_pl031_dev_t* dev); + +/** + * \brief Gets masked interrupt pending status of RTC PL031. + * + * \param[in] dev RTC device structure \ref rtc_pl031_dev_t. + * + * \return Return true indicates that RTC PL031 masked interrupt + * status is pending. + * + * \note This function does not check if dev is NULL. + */ +bool rtc_pl031_is_masked_interrupt_pending(struct rtc_pl031_dev_t* dev); + +/** + * \brief Writes match value to RTC PL031 device. + * + * \param[in] dev RTC device structure \ref rtc_pl031_dev_t. + * \param[in] seconds Match value to be set in seconds. + * + * \return Return true indicates that the function executed successfully, + * otherwise an error occurred. + */ +bool rtc_pl031_write_match_value(struct rtc_pl031_dev_t* dev, uint32_t seconds); + +/** + * \brief Clear interrupt status bit of RTC PL031. + * + * \param[in] dev RTC device structure \ref rtc_pl031_dev_t. + * + * \return Return true indicates that the function executed successfully, + * otherwise an error occurred. + */ +bool rtc_pl031_clear_interrupt(struct rtc_pl031_dev_t* dev); + +#ifdef __cplusplus +} +#endif +#endif /* __RTC_PL031_DRV_H__ */ diff --git a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/platform_devices.c b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/platform_devices.c index ccfab4b4ac..2fbf8921ff 100644 --- a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/platform_devices.c +++ b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/platform_devices.c @@ -37,6 +37,23 @@ struct timer_cmsdk_dev_t CMSDK_TIMER1_DEV = {&(CMSDK_TIMER1_DEV_CFG), &(CMSDK_TIMER1_DEV_DATA)}; #endif +/* ARM CMSDK Dual Timer driver structure */ +#ifdef ARM_CMSDK_DUALTIMER +static const struct dualtimer_cmsdk_dev_cfg_t CMSDK_DUALTIMER_DEV_CFG = { + .base = CMSDK_DUALTIMER_BASE}; +static struct dualtimer_cmsdk_dev_data_t CMSDK_DUALTIMER_DEV_DATA = { + .is_initialized = 0}; +struct dualtimer_cmsdk_dev_t CMSDK_DUALTIMER_DEV = {&(CMSDK_DUALTIMER_DEV_CFG), + &(CMSDK_DUALTIMER_DEV_DATA)}; +#endif + +/* PL031 Real-Time Clock structure */ +#ifdef RTC_PL031 +static const struct rtc_pl031_dev_cfg_t RTC_PL031_DEV_CFG = { + .base = CMSDK_RTC_BASE}; +struct rtc_pl031_dev_t RTC_PL031_DEV = {&(RTC_PL031_DEV_CFG)}; +#endif + /* ARM GPIO driver structures */ #ifdef ARM_GPIO0 static const struct arm_gpio_dev_cfg_t ARM_GPIO0_DEV_CFG = { diff --git a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/platform_devices.h b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/platform_devices.h index 14fdc45bc2..6e03e3d494 100644 --- a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/platform_devices.h +++ b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/platform_devices.h @@ -20,84 +20,107 @@ /* ======= Configures the peripheral set ======= */ #include "device_cfg.h" -/* ======= Includes generic driver headers ======= */ -#include "timer_cmsdk_drv.h" -#include "arm_gpio_drv.h" -#include "arm_mps2_io_drv.h" -#include "spi_pl022_drv.h" -#include "arm_uart_drv.h" -#include "smsc9220_eth_drv.h" - /* ======= Defines peripheral configuration structures ======= */ /* ARM CMSDK Timer driver structures */ #ifdef ARM_CMSDK_TIMER0 +#include "timer_cmsdk_drv.h" extern struct timer_cmsdk_dev_t CMSDK_TIMER0_DEV; #endif #ifdef ARM_CMSDK_TIMER1 +#include "timer_cmsdk_drv.h" extern struct timer_cmsdk_dev_t CMSDK_TIMER1_DEV; #endif +/* ARM CMSDK Dual Timer driver structure */ +#ifdef ARM_CMSDK_DUALTIMER +#include "dualtimer_cmsdk_drv.h" +extern struct dualtimer_cmsdk_dev_t CMSDK_DUALTIMER_DEV; +#endif + +/* RTC PL031 */ +#ifdef RTC_PL031 +#include "rtc_pl031_drv.h" +extern struct rtc_pl031_dev_t RTC_PL031_DEV; +#endif + /* ARM GPIO driver structures */ #ifdef ARM_GPIO0 +#include "arm_gpio_drv.h" extern struct arm_gpio_dev_t ARM_GPIO0_DEV; #endif #ifdef ARM_GPIO1 +#include "arm_gpio_drv.h" extern struct arm_gpio_dev_t ARM_GPIO1_DEV; #endif #ifdef ARM_GPIO2 +#include "arm_gpio_drv.h" extern struct arm_gpio_dev_t ARM_GPIO2_DEV; #endif #ifdef ARM_GPIO3 +#include "arm_gpio_drv.h" extern struct arm_gpio_dev_t ARM_GPIO3_DEV; #endif /* ARM MPS2 IO FPGAIO driver structures */ #ifdef ARM_MPS2_IO_FPGAIO +#include "arm_mps2_io_drv.h" extern struct arm_mps2_io_dev_t ARM_MPS2_IO_FPGAIO_DEV; #endif /* ARM MPS2 IO SCC driver structures */ #ifdef ARM_MPS2_IO_SCC +#include "arm_mps2_io_drv.h" extern struct arm_mps2_io_dev_t ARM_MPS2_IO_SCC_DEV; #endif /* ARM SPI driver structures */ #ifdef ARM_SPI0 +#include "spi_pl022_drv.h" extern struct spi_pl022_dev_t SPI0_PL022_DEV; #endif #ifdef ARM_SPI1 +#include "spi_pl022_drv.h" extern struct spi_pl022_dev_t SPI1_PL022_DEV; #endif #ifdef ARM_SPI2 +#include "spi_pl022_drv.h" extern struct spi_pl022_dev_t SPI2_PL022_DEV; #endif #ifdef ARM_SPI3 +#include "spi_pl022_drv.h" extern struct spi_pl022_dev_t SPI3_PL022_DEV; #endif #ifdef ARM_SPI4 +#include "spi_pl022_drv.h" extern struct spi_pl022_dev_t SPI4_PL022_DEV; #endif /* ARM UART driver structures */ #ifdef ARM_UART0 +#include "arm_uart_drv.h" extern struct arm_uart_dev_t ARM_UART0_DEV; #endif #ifdef ARM_UART1 +#include "arm_uart_drv.h" extern struct arm_uart_dev_t ARM_UART1_DEV; #endif #ifdef ARM_UART2 +#include "arm_uart_drv.h" extern struct arm_uart_dev_t ARM_UART2_DEV; #endif #ifdef ARM_UART3 +#include "arm_uart_drv.h" extern struct arm_uart_dev_t ARM_UART3_DEV; #endif #ifdef ARM_UART4 +#include "arm_uart_drv.h" extern struct arm_uart_dev_t ARM_UART4_DEV; #endif #ifdef SMSC9220_ETH +#include "smsc9220_eth_drv.h" extern struct smsc9220_eth_dev_t SMSC9220_ETH_DEV; #endif diff --git a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/lp_ticker.c b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/lp_ticker.c index 6b272a00b8..258b7fe4b2 100644 --- a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/lp_ticker.c +++ b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/lp_ticker.c @@ -1,5 +1,5 @@ /* mbed Microcontroller Library - * Copyright (c) 2018 ARM Limited + * Copyright (c) 2017-2018 Arm Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,108 +14,95 @@ * limitations under the License. */ - /** - * Low-power elapsed time measure and interval timer in micro-secundum, - * servicing \ref lp_ticker_api.h, using CMSDK Timer1 \ref CMSDK_TIMER1_DEV. - */ +/** + * Supports the Low Power Ticker for mbed by implementing \ref lp_ticker_api.h, + * using both timers in a CMSDK Dual Timer \ref dualtimer_cmsdk_dev_t. + */ -#include - -#include "cmsdk_ticker.h" +#include "dualtimer_cmsdk_drv.h" #include "lp_ticker_api.h" #include "platform_devices.h" -#if DEVICE_LPTICKER -/** - * \brief Calculate clocks to us - * - * \param[in] tick Number of clock ticks - * - * \return Number of usec, relative to the timer frequency, - * that a given ammount of ticks equates to. +static uint32_t last_read = 0; + +/* Initializes both timers in the Dualtimer: + * -Timer1 as the free running timer + * -Timer2 as the interval timer + * Both timers are set: + * -32 bit size + * -256 Clk divisor + * -Maximum reload value */ - static uint32_t convert_tick_to_us(uint32_t tick) - { - return (tick / (SystemCoreClock / SEC_TO_USEC_MULTIPLIER)); - } - -/** - * \brief Calculate us to clock ticks - * - * \param[in] us Time to convert to clock ticks - * - * \return Number of clock ticks relative to the timer frequency, - * that a given period of usec equates to. - */ - static uint32_t convert_us_to_tick(uint32_t us) - { - return (us * (SystemCoreClock / SEC_TO_USEC_MULTIPLIER)); - } - -static const struct tick_cfg_t cfg = -{ - .timer_driver = &CMSDK_TIMER1_DEV, - .irq_n = TIMER1_IRQn, - .interval_callback = &lp_ticker_irq_handler, - .convert_tick_to_time = &convert_tick_to_us, - .convert_time_to_tick = &convert_us_to_tick -}; - -static struct tick_data_t data = -{ - .is_initialized = false, - .cumulated_time = 0, - .max_interval_time = 0, - .reload_time = 0, - .interval_callback_enabled = false, - .previous_cumulated_time = 0, - .previous_elapsed = 0 -}; - -static struct tick_drv_data_t timer_data = -{ - .cfg = &cfg, - .data = &data -}; - void lp_ticker_init(void) { - cmsdk_ticker_init(&timer_data); -} - -uint32_t lp_ticker_read() -{ - return cmsdk_ticker_read(&timer_data); -} - -void lp_ticker_set_interrupt(timestamp_t timestamp) -{ - cmsdk_ticker_set_interrupt(&timer_data, timestamp); -} - -void lp_ticker_disable_interrupt(void) -{ - cmsdk_ticker_disable_interrupt(&timer_data); -} - -void lp_ticker_clear_interrupt(void) -{ - cmsdk_ticker_clear_interrupt(&timer_data); -} - -void lp_ticker_fire_interrupt(void) -{ - cmsdk_ticker_fire_interrupt(&timer_data); + dualtimer_cmsdk_init(&LP_TIMER_DEV); + dualtimer_cmsdk_set_size_both_timers(&LP_TIMER_DEV, + DUALTIMER_CMSDK_SIZE_32BIT); + dualtimer_cmsdk_set_prescale_both_timers(&LP_TIMER_DEV, + DUALTIMER_CMSDK_CLOCK_DIV256); + dualtimer_cmsdk_disable_both_timers(&LP_TIMER_DEV); + dualtimer_cmsdk_set_reload_both_timers(&LP_TIMER_DEV, + TIMER_CMSDK_MAX_RELOAD); + dualtimer_cmsdk_reset_both_timers(&LP_TIMER_DEV); + NVIC_EnableIRQ(LP_INTERVAL_IRQ); + dualtimer_cmsdk_enable_both_timers(&LP_TIMER_DEV); } void lp_ticker_free(void) { - + dualtimer_cmsdk_free(&LP_TIMER_DEV); } -void TIMER1_IRQHandler(void) +uint32_t lp_ticker_read() { - cmsdk_ticker_irq_handler(&timer_data); + uint32_t tick = dualtimer_cmsdk_get_elapsed_value_timer1(&LP_TIMER_DEV); + last_read = tick >> LP_REPORTED_SHIFT; + return last_read; } +void lp_ticker_set_interrupt(timestamp_t timestamp) +{ + uint32_t reload = (timestamp - last_read) << LP_REPORTED_SHIFT; + dualtimer_cmsdk_disable_timer2(&LP_TIMER_DEV); + dualtimer_cmsdk_set_reload_timer2(&LP_TIMER_DEV, reload); + dualtimer_cmsdk_reset_timer2(&LP_TIMER_DEV); + dualtimer_cmsdk_enable_interrupt_timer2(&LP_TIMER_DEV); + dualtimer_cmsdk_enable_timer2(&LP_TIMER_DEV); +} + +void lp_ticker_disable_interrupt(void) +{ + dualtimer_cmsdk_disable_interrupt_timer2(&LP_TIMER_DEV); +} + +void lp_ticker_clear_interrupt(void) +{ + dualtimer_cmsdk_clear_interrupt_timer2(&LP_TIMER_DEV); +} + +void lp_ticker_fire_interrupt(void) +{ + NVIC_SetPendingIRQ(LP_INTERVAL_IRQ); +} + +const ticker_info_t* lp_ticker_get_info() +{ + static const ticker_info_t info = { + LP_REPORTED_FREQ_HZ, + LP_REPORTED_BITS + }; + return &info; +} + +#ifndef lp_interval_irq_handler +#error "lp_interval_irq_handler should be defined, check device_cfg.h!" #endif +/* According to mbed's specification, the free running timer shouldn't fire + * interrupt, since the upper layer polls that and handles the overflow, + * by cumulating the read values. + */ +void lp_interval_irq_handler(void) +{ + lp_ticker_disable_interrupt(); + lp_ticker_irq_handler(); +} diff --git a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/rtc_api.c b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/rtc_api.c index 2de348666a..d79aad572d 100644 --- a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/rtc_api.c +++ b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/rtc_api.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 ARM Limited + * Copyright (c) 2018 Arm Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,8 +15,10 @@ */ #include "rtc_api.h" -#include "device.h" -#include "cmsis.h" +#include "platform_devices.h" +#include "rtc_pl031_drv.h" + +static uint32_t is_enabled = 0; /** * \defgroup hal_rtc RTC hal functions @@ -31,7 +33,9 @@ */ void rtc_init(void) { - CMSDK_RTC->RTCCR |= (1 << CMSDK_RTC_ENABLE_Pos); + rtc_pl031_init(&RTC_PL031_DEV); + rtc_pl031_dev_enable(&RTC_PL031_DEV); + is_enabled = 1; } /** @@ -41,7 +45,7 @@ void rtc_init(void) */ void rtc_free(void) { - /* Not supported */ + is_enabled = 0; } /** @@ -51,17 +55,24 @@ void rtc_free(void) */ int rtc_isenabled(void) { - return (CMSDK_RTC->RTCCR & CMSDK_RTC_ENABLE_Msk); + return is_enabled; } /** * \brief Get the current time from the RTC peripheral * + * Sysclock and RTC clock may not be in sync which can cause reading + * out metastable values. It's usually prevented by adding a loop, + * however PL031 has a syncronisation block to prevent this, therefore + * no additional loop needed. + * * \return The current time in seconds */ time_t rtc_read(void) { - return (time_t)CMSDK_RTC->RTCDR; + uint32_t val; + rtc_pl031_read_current_time(&RTC_PL031_DEV, &val); + return (time_t)val; } /** @@ -72,7 +83,7 @@ time_t rtc_read(void) void rtc_write(time_t t) { - CMSDK_RTC->RTCLR = (uint32_t)t; + rtc_pl031_write_current_time(&RTC_PL031_DEV, (uint32_t)t); } /**@}*/ diff --git a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/sleep_api.c b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/sleep_api.c new file mode 100644 index 0000000000..8b06e8d437 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/sleep_api.c @@ -0,0 +1,50 @@ + +/** \addtogroup hal */ +/** @{*/ +/* mbed Microcontroller Library + * Copyright (c) 2018 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. + */ + +#include "platform_devices.h" +#include "sleep_api.h" +#include "timer_cmsdk_drv.h" + +#if DEVICE_SLEEP + +void hal_sleep(void) +{ + __WFI(); +} + +/* Since there is no power management implemented in CM3DS, Deep Sleep could be + * supported only by additional software components, registering and managing + * the currently configured IPs. This would also mean a huge implementation + * overhead, that is not intended to be added. Therefore, Deep Sleep is almost + * identical to Sleep, representing a "Waiting For Interrupt" state, and + * disabling the Microsec ticker in addition */ +void hal_deepsleep(void) +{ +#if DEVICE_USTICKER + timer_cmsdk_disable(&USEC_TIMER_DEV); +#endif + __WFI(); +#if DEVICE_USTICKER + timer_cmsdk_enable(&USEC_TIMER_DEV); +#endif +} + +#endif + +/**@}*/ diff --git a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/us_ticker.c b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/us_ticker.c index db472ff56d..aa04a6244b 100644 --- a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/us_ticker.c +++ b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/us_ticker.c @@ -15,124 +15,104 @@ */ /** - * Elapsed time measure and interval timer in micro-secundum, - * servicing \ref us_ticker_api.h, using CMSDK Timer0 \ref CMSDK_TIMER0_DEV. + * Supports the High-resolution Ticker for mbed by implementing + * \ref us_ticker_api.h, using a CMSDK Timer \ref timer_cmsdk_dev_t. */ -#include "cmsdk_ticker.h" #include "us_ticker_api.h" #include "platform_devices.h" +#include "timer_cmsdk_drv.h" -/* - * The CMSDK Ticker counts on 32 bits. +static uint64_t total_ticks = 0; +/* Stores the last reload value, or the last tick value read when a read API + * call occurs from the upper layer, needed to keep total_ticks + * accumulated properly. */ -#define CMSDK_TICKER_COUNTER_BITS 32U +static uint32_t previous_ticks = 0; +static uint32_t last_read = 0; -/** - * \brief Pass-through function to make the US ticker HAL only work in the tick - * domain. This function is needed by the CMSDK Ticker layer. - * - * \param[in] tick Number of clock ticks - * - * \return The number of ticks given. - */ -static uint32_t convert_tick_to_us(uint32_t tick) +static void restart_timer(uint32_t new_reload) { - /* Work only in the tick domain. */ - return tick; + timer_cmsdk_disable(&USEC_TIMER_DEV); + timer_cmsdk_set_reload_value(&USEC_TIMER_DEV, + new_reload); + timer_cmsdk_reset(&USEC_TIMER_DEV); + timer_cmsdk_clear_interrupt(&USEC_TIMER_DEV); + timer_cmsdk_enable_interrupt(&USEC_TIMER_DEV); + timer_cmsdk_enable(&USEC_TIMER_DEV); } -/** - * \brief Pass-through function to make the US ticker HAL only work in the tick - * domain. This function is needed by the CMSDK Ticker layer. - * - * \param[in] us Number of us - * - * \return The number of us given. - */ -static uint32_t convert_us_to_tick(uint32_t us) -{ - /* Work only in the tick domain. */ - return us; -} - -static const struct tick_cfg_t cfg = -{ - .timer_driver = &CMSDK_TIMER0_DEV, - .irq_n = TIMER0_IRQn, - .interval_callback = &us_ticker_irq_handler, - .convert_tick_to_time = &convert_tick_to_us, - .convert_time_to_tick = &convert_us_to_tick -}; - -static struct tick_data_t data = -{ - .is_initialized = false, - .cumulated_time = 0, - .max_interval_time = 0, - .reload_time = 0, - .interval_callback_enabled = false, - .previous_cumulated_time = 0, - .previous_elapsed = 0 -}; - -static struct tick_drv_data_t timer_data = -{ - .cfg = &cfg, - .data = &data -}; - void us_ticker_init(void) { - cmsdk_ticker_init(&timer_data); -} - -uint32_t us_ticker_read() -{ - return cmsdk_ticker_read(&timer_data); -} - -void us_ticker_set_interrupt(timestamp_t timestamp) -{ - cmsdk_ticker_set_interrupt(&timer_data, timestamp); -} - -void us_ticker_disable_interrupt(void) -{ - cmsdk_ticker_disable_interrupt(&timer_data); -} - -void us_ticker_clear_interrupt(void) -{ - cmsdk_ticker_clear_interrupt(&timer_data); -} - -void us_ticker_fire_interrupt(void) -{ - cmsdk_ticker_fire_interrupt(&timer_data); + timer_cmsdk_init(&USEC_TIMER_DEV); + previous_ticks = TIMER_CMSDK_MAX_RELOAD; + NVIC_EnableIRQ(USEC_INTERVAL_IRQ); + restart_timer(previous_ticks); } void us_ticker_free(void) { - + timer_cmsdk_disable(&USEC_TIMER_DEV); } -void TIMER0_IRQHandler(void) +uint32_t us_ticker_read(void) { - cmsdk_ticker_irq_handler(&timer_data); + if (timer_cmsdk_is_interrupt_active(&USEC_TIMER_DEV)) { + total_ticks += previous_ticks; + previous_ticks = TIMER_CMSDK_MAX_RELOAD; + restart_timer(previous_ticks); + } else { + uint32_t tick = timer_cmsdk_get_current_value(&USEC_TIMER_DEV); + + if (tick < previous_ticks) { + uint32_t delta = previous_ticks - tick; + total_ticks += delta; + previous_ticks = tick; + } + } + last_read = (uint32_t)(total_ticks >> USEC_REPORTED_SHIFT); + return last_read; } -const ticker_info_t* us_ticker_get_info(void) +/* To ensure that timestamp is always bigger than the current time, it should + * be calculated by using the us_ticker_read() method. + */ +void us_ticker_set_interrupt(timestamp_t timestamp) { - static ticker_info_t us_ticker_info = { - .bits = CMSDK_TICKER_COUNTER_BITS + uint32_t reload = (timestamp - last_read) << USEC_REPORTED_SHIFT; + previous_ticks = reload; + restart_timer(previous_ticks); +} + +void us_ticker_disable_interrupt(void) +{ + timer_cmsdk_disable_interrupt(&USEC_TIMER_DEV); +} + +void us_ticker_clear_interrupt(void) +{ + timer_cmsdk_clear_interrupt(&USEC_TIMER_DEV); +} + +void us_ticker_fire_interrupt(void) +{ + NVIC_SetPendingIRQ(USEC_INTERVAL_IRQ); +} + +const ticker_info_t* us_ticker_get_info() +{ + static const ticker_info_t info = { + USEC_REPORTED_FREQ_HZ, + USEC_REPORTED_BITS }; - - /* - * SystemCoreClock is not a constant so it cannot be used to initialize the - * ticker_info_t structure. - */ - us_ticker_info.frequency = SystemCoreClock; - - return &us_ticker_info; + return &info; +} + +#ifndef usec_interval_irq_handler +#error "usec_interval_irq_handler should be defined, check device_cfg.h!"vector! +#endif +void usec_interval_irq_handler(void) +{ + us_ticker_read(); + us_ticker_irq_handler(); } diff --git a/targets/targets.json b/targets/targets.json index 0d1c151c29..10fcd483f6 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -4648,12 +4648,16 @@ "FLASH", "I2C", "INTERRUPTIN", + "LPTICKER", "PORTIN", "PORTINOUT", "PORTOUT", + "RTC", "SERIAL", + "SLEEP", "SPI", - "TRNG" + "TRNG", + "USTICKER" ], "release_versions": ["2", "5"], "copy_method": "mps2",