Skip to content

CM3DS Maintenance Pull Request: Driver updates (4/4) #6170

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 12 additions & 11 deletions targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/PeripheralNames.h
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2017 ARM Limited
* Copyright (c) 2006-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.
Expand All @@ -23,11 +23,11 @@ extern "C" {
#endif

typedef enum {
UART_0 = (int)CMSDK_UART0_BASE, /* MCC UART */
UART_1 = (int)CMSDK_UART1_BASE, /* MPS2+ UART */
UART_2 = (int)CMSDK_UART2_BASE, /* Shield 0 UART */
UART_3 = (int)CMSDK_UART3_BASE, /* Shield 1 UART */
UART_4 = (int)CMSDK_UART4_BASE /* Shield BT UART */
UART_0 = 0, /* MCC UART */
UART_1, /* MPS2+ UART */
UART_2, /* Shield 0 UART */
UART_3, /* Shield 1 UART */
UART_4 /* Shield BT UART */
} UARTName;

typedef enum {
Expand All @@ -53,11 +53,12 @@ typedef enum {
} ADCName;

typedef enum {
SPI_0 = (int)MPS2_SSP0_BASE,
SPI_1 = (int)MPS2_SSP1_BASE,
SPI_2 = (int)MPS2_SSP2_BASE,
SPI_3 = (int)MPS2_SSP3_BASE,
SPI_4 = (int)MPS2_SSP4_BASE
SPI_0 = 0,
SPI_1,
SPI_2,
SPI_3,
SPI_4,
SPI_NC = (SPI_4 + 1)
} SPIName;

typedef enum {
Expand Down
2 changes: 1 addition & 1 deletion targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/PinNames.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2017 ARM Limited
* Copyright (c) 2006-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.
Expand Down
166 changes: 166 additions & 0 deletions targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/cmsdk_ticker.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/*
* 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 cmsdk_ticker.c
* Two abstracted functionalities for CMSDK APB Timers
* 1. Measure elapsed time
* 2. Timer interval interrupt
*
* Passed \ref tick_drv_data_t should be initialized by the caller
* for using these services accordingly.
* See details \ref tick_cfg_t and \ref tick_data_t.
*/

#include "cmsdk_ticker.h"

void cmsdk_ticker_init(const struct tick_drv_data_t* timer_data)
{
if (!timer_data->data->is_initialized) {
timer_cmsdk_init(timer_data->cfg->timer_driver);
timer_cmsdk_set_reload_value(timer_data->cfg->timer_driver,
TIMER_CMSDK_MAX_RELOAD);
timer_cmsdk_enable_interrupt(timer_data->cfg->timer_driver);
NVIC_EnableIRQ(timer_data->cfg->irq_n);

timer_data->data->max_interval_time =
timer_data->cfg->convert_tick_to_time(TIMER_CMSDK_MAX_RELOAD);
timer_data->data->reload_time = timer_data->data->max_interval_time;
timer_data->data->is_initialized = true;
timer_cmsdk_enable(timer_data->cfg->timer_driver);
}
}

uint32_t cmsdk_ticker_read(const struct tick_drv_data_t* timer_data)
{
uint32_t current_elapsed = 0;

if (!timer_data->data->is_initialized) {
cmsdk_ticker_init(timer_data);
}
current_elapsed = timer_cmsdk_get_elapsed_value(timer_data->cfg->timer_driver);
/*
* If for the same reload cycle (ie. cumulated_time is the same) the
* current elapsed time is lower than the previous one, it means that the
* timer has wrapped around without the system logging it. To ensure that
* we are always returning an increasing time in those condition, we return
* the time perviously read.
*/
if ((timer_data->data->previous_cumulated_time ==
timer_data->data->cumulated_time) &&
(current_elapsed < timer_data->data->previous_elapsed)) {
current_elapsed = timer_data->data->previous_elapsed;
}

timer_data->data->previous_elapsed = current_elapsed;
timer_data->data->previous_cumulated_time =
timer_data->data->cumulated_time;

return (timer_data->data->cumulated_time +
timer_data->cfg->convert_tick_to_time(current_elapsed));
}

void cmsdk_ticker_set_interrupt(const struct tick_drv_data_t* timer_data,
uint32_t timestamp)
{
uint32_t interval = 0;
uint32_t interval_reload_tick = 0;

/* Stop before read to avoid race condition with IRQ. */
timer_cmsdk_disable(timer_data->cfg->timer_driver);
uint32_t current_time = cmsdk_ticker_read(timer_data);

timer_data->data->interval_callback_enabled = true;

/*
* We always assume that the event is in the future, even if this
* substraction underflows it is still corect.
*/
interval = (timestamp - current_time);

if (interval >= timer_data->data->max_interval_time) {
/* Event will be in the future but the time is too big: set max */
interval_reload_tick = TIMER_CMSDK_MAX_RELOAD;
timer_data->data->reload_time = timer_data->data->max_interval_time;
} else {
/* Event will be in the future in a time that can be set */
interval_reload_tick =
timer_data->cfg->convert_time_to_tick(interval);
timer_data->data->reload_time = interval;
}

/* Store the current elapsed time, before reset the timer */
timer_data->data->cumulated_time = current_time;
/* Reset the timer with new reload value */
timer_cmsdk_set_reload_value(timer_data->cfg->timer_driver,
interval_reload_tick);
timer_cmsdk_reset(timer_data->cfg->timer_driver);

timer_cmsdk_enable(timer_data->cfg->timer_driver);
}

void cmsdk_ticker_disable_interrupt(const struct tick_drv_data_t* timer_data)
{
if (!timer_data->data->is_initialized) {
cmsdk_ticker_init(timer_data);
}

timer_data->data->interval_callback_enabled = false;

/* Stop before read to avoid race condition with IRQ. */
timer_cmsdk_disable(timer_data->cfg->timer_driver);
/* If interval interrupt is disabled, restore the default max interval,
* but save the current elapsed time before changing the timer. */
timer_data->data->cumulated_time = cmsdk_ticker_read(timer_data);
/* Reset the timer with default reload value */
timer_cmsdk_set_reload_value(timer_data->cfg->timer_driver,
TIMER_CMSDK_MAX_RELOAD);
timer_data->data->reload_time = timer_data->data->max_interval_time;

timer_cmsdk_reset(timer_data->cfg->timer_driver);
timer_cmsdk_enable(timer_data->cfg->timer_driver);
}

void cmsdk_ticker_clear_interrupt(const struct tick_drv_data_t* timer_data)
{
timer_cmsdk_clear_interrupt(timer_data->cfg->timer_driver);
}

void cmsdk_ticker_fire_interrupt(const struct tick_drv_data_t* timer_data)
{
NVIC_SetPendingIRQ(timer_data->cfg->irq_n);
}

void cmsdk_ticker_irq_handler(const struct tick_drv_data_t* timer_data)
{
uint32_t reload_val = 0;
/* If timer's internal interrupt status is not active, then not overflow,
* but explicit interrupt request was fired by cmsdk_ticker_fire_interrupt.
*/
if (timer_cmsdk_is_interrupt_active(timer_data->cfg->timer_driver)) {
/* 1. Calculate cumulated time by overflow */
timer_cmsdk_clear_interrupt(timer_data->cfg->timer_driver);
reload_val = timer_cmsdk_get_reload_value(timer_data->cfg->timer_driver);
timer_data->data->cumulated_time +=
timer_data->cfg->convert_tick_to_time(reload_val);
}

/* 2. Call mbed interval interrupt handler if it's required */
if (timer_data->data->interval_callback_enabled) {
cmsdk_ticker_disable_interrupt(timer_data);
timer_data->cfg->interval_callback();
}
}
150 changes: 150 additions & 0 deletions targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/cmsdk_ticker.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
/*
* 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 cmsdk_ticker.h
* CMSDK Ticker implements the functionalities of mbed tickers:
* 1. Elapsed time measurement
* 2. Interval interrupt request
*
* This ticker service is based on CMSDK APB Timers, abstracting
* the HAL logic, the timer driver and interrupt number.
* These parameters should be passed to the functions by
* an initialized \ref tick_drv_data_t pointer.
*/

#ifndef CMSDK_TICKER_H
#define CMSDK_TICKER_H

#include <stdbool.h>

#include "CMSDK_CM3DS.h"
#include "timer_cmsdk_drv.h"

#define SEC_TO_USEC_MULTIPLIER 1000000U

/**
* brief Encapsulating struct for config data \ref tick_cfg_t and
* the current status \ref tick_data_t.
*/
struct tick_drv_data_t {
const struct tick_cfg_t* const cfg;
struct tick_data_t* const data;
};

/**
* brief Configuration data of the CMSDK ticker
*/
struct tick_cfg_t {
/** Pointer to the used CMSDK Timer's device structure */
struct timer_cmsdk_dev_t* const timer_driver;
/** IRQ number of the used CMSDK Timer */
const IRQn_Type irq_n;
/** Interval callback of mbed*/
void (*const interval_callback)();
/** Function pointers to call for conversions of clock ticks and defined
* time unit.
* These conversions define the unit of the measured time.
*/
uint32_t (*const convert_tick_to_time)(uint32_t tick);
uint32_t (*const convert_time_to_tick)(uint32_t time);
};

/**
* brief Current state data of the CMSDK ticker
*/
struct tick_data_t {
/** True if initialized the ticker, false otherwise */
bool is_initialized;
/** Measured elapsed time in the defined unit by
* \ref convert_tick_to_time and \ref convert_time_to_tick */
uint32_t cumulated_time;
/** Max interval time possible to set, in the defined unit by
* \ref convert_tick_to_time and \ref convert_time_to_tick */
uint32_t max_interval_time;
/** Current reload time in the defined unit by
* \ref convert_tick_to_time and \ref convert_time_to_tick */
uint32_t reload_time;
/** Interval IRQ callback is requested */
bool interval_callback_enabled;
/** Previous cumulated time calculated for this ticker. Used in the
* cmsdk_ticker_read function to detect that the timer has wrapped. */
uint32_t previous_cumulated_time;
/** Previous elapsed value for this ticker. Used in the
* cmsdk_ticker_read function to detect that the timer has wrapped. */
uint32_t previous_elapsed;
};

/**
* \brief Init the CMSDK Ticker
*
* \param[in] timer_data Pointer to the used CMSDK Timer's device structure
*/
void cmsdk_ticker_init(const struct tick_drv_data_t* timer_data);

/**
* \brief Read elapsed time by CMSDK Ticker
*
* \param[in] timer_data Pointer to the used CMSDK Timer's device structure
*
* \return Elapsed time in the unit defined by \ref convert_tick_to_time
*/

uint32_t cmsdk_ticker_read(const struct tick_drv_data_t* timer_data);

/**
* \brief Request interval interrupt by time stamp \ref timestamp_t
*
* \param[in] timer_data Pointer to the used CMSDK Timer's device structure
* \param[in] timestamp Absolute time \ref timestamp_t value when the interval
* is requested. Unit of the timestamp is defined by
* \ref convert_tick_to_time and \ref convert_time_to_tick
*/
void cmsdk_ticker_set_interrupt(const struct tick_drv_data_t* timer_data,
uint32_t timestamp);

/**
* \brief Disable interval interrupt
*
* \param[in] timer_data Pointer to the used CMSDK Timer's device structure
*/
void cmsdk_ticker_disable_interrupt(const struct tick_drv_data_t* timer_data);

/**
* \brief Clear interval interrupt
*
* \param[in] timer_data Pointer to the used CMSDK Timer's device structure
*/
void cmsdk_ticker_clear_interrupt(const struct tick_drv_data_t* timer_data);

/**
* \brief Set pending interrupt that should be fired right away.
*
* \param[in] timer_data Pointer to the used CMSDK Timer's device structure
*/
void cmsdk_ticker_fire_interrupt(const struct tick_drv_data_t* timer_data);

/**
* \brief Interrupt handler of the given CMSDK Timer
*
* \warning This function may be called from multiple interrupt handlers,
* so extra care must be taken for re-entrancy!
*
* \param[in] timer_data Pointer to the used CMSDK Timer's device structure
*/
void cmsdk_ticker_irq_handler(const struct tick_drv_data_t* timer_data);
#endif
Loading