diff --git a/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/TARGET_CC3220SF_LAUNCHXL/CC3220SF_LAUNCHXL.c b/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/TARGET_CC3220SF_LAUNCHXL/CC3220SF_LAUNCHXL.c index 47c9772384..6500d968eb 100755 --- a/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/TARGET_CC3220SF_LAUNCHXL/CC3220SF_LAUNCHXL.c +++ b/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/TARGET_CC3220SF_LAUNCHXL/CC3220SF_LAUNCHXL.c @@ -215,6 +215,70 @@ const SPI_Config SPI_config[CC3220SF_LAUNCHXL_SPICOUNT] = { const uint_least8_t SPI_count = CC3220SF_LAUNCHXL_SPICOUNT; +/* + * =============================== PWM =============================== + */ +#include +#include + +PWMTimerCC32XX_Object pwmTimerCC3220SObjects[CC3220SF_LAUNCHXL_PWMCOUNT]; + +const PWMTimerCC32XX_HWAttrsV2 pwmTimerCC3220SHWAttrs[CC3220SF_LAUNCHXL_PWMCOUNT] = { + { /* CC3220SF_LAUNCHXL_PWM6 */ + .pwmPin = PWMTimerCC32XX_PIN_01 + }, + { /* CC3220SF_LAUNCHXL_PWM7 */ + .pwmPin = PWMTimerCC32XX_PIN_02 + }, + { /* CC3220SF_LAUNCHXL_PWM0 */ + .pwmPin = PWMTimerCC32XX_PIN_17 + }, + { /* CC3220SF_LAUNCHXL_PWM3 */ + .pwmPin = PWMTimerCC32XX_PIN_19 + }, + { /* CC3220SF_LAUNCHXL_PWM2 */ + .pwmPin = PWMTimerCC32XX_PIN_21 + }, + { /* CC3220SF_LAUNCHXL_PWM5 */ + .pwmPin = PWMTimerCC32XX_PIN_64 + }, +}; + +const PWM_Config PWM_config[CC3220SF_LAUNCHXL_PWMCOUNT] = { + { + .fxnTablePtr = &PWMTimerCC32XX_fxnTable, + .object = &pwmTimerCC3220SObjects[CC3220SF_LAUNCHXL_PWM6], + .hwAttrs = &pwmTimerCC3220SHWAttrs[CC3220SF_LAUNCHXL_PWM6] + }, + { + .fxnTablePtr = &PWMTimerCC32XX_fxnTable, + .object = &pwmTimerCC3220SObjects[CC3220SF_LAUNCHXL_PWM7], + .hwAttrs = &pwmTimerCC3220SHWAttrs[CC3220SF_LAUNCHXL_PWM7] + }, + { + .fxnTablePtr = &PWMTimerCC32XX_fxnTable, + .object = &pwmTimerCC3220SObjects[CC3220SF_LAUNCHXL_PWM0], + .hwAttrs = &pwmTimerCC3220SHWAttrs[CC3220SF_LAUNCHXL_PWM0] + }, + { + .fxnTablePtr = &PWMTimerCC32XX_fxnTable, + .object = &pwmTimerCC3220SObjects[CC3220SF_LAUNCHXL_PWM3], + .hwAttrs = &pwmTimerCC3220SHWAttrs[CC3220SF_LAUNCHXL_PWM3] + }, + { + .fxnTablePtr = &PWMTimerCC32XX_fxnTable, + .object = &pwmTimerCC3220SObjects[CC3220SF_LAUNCHXL_PWM2], + .hwAttrs = &pwmTimerCC3220SHWAttrs[CC3220SF_LAUNCHXL_PWM2] + }, + { + .fxnTablePtr = &PWMTimerCC32XX_fxnTable, + .object = &pwmTimerCC3220SObjects[CC3220SF_LAUNCHXL_PWM5], + .hwAttrs = &pwmTimerCC3220SHWAttrs[CC3220SF_LAUNCHXL_PWM5] + } +}; + +const uint_least8_t PWM_count = CC3220SF_LAUNCHXL_PWMCOUNT; + /* * =============================== DMA =============================== */ diff --git a/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/TARGET_CC3220SF_LAUNCHXL/CC3220SF_LAUNCHXL.h b/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/TARGET_CC3220SF_LAUNCHXL/CC3220SF_LAUNCHXL.h index d33152ffc3..efd23d0bba 100755 --- a/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/TARGET_CC3220SF_LAUNCHXL/CC3220SF_LAUNCHXL.h +++ b/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/TARGET_CC3220SF_LAUNCHXL/CC3220SF_LAUNCHXL.h @@ -138,7 +138,10 @@ typedef enum CC3220SF_LAUNCHXL_I2SName { typedef enum CC3220SF_LAUNCHXL_PWMName { CC3220SF_LAUNCHXL_PWM6 = 0, CC3220SF_LAUNCHXL_PWM7, - + CC3220SF_LAUNCHXL_PWM0, + CC3220SF_LAUNCHXL_PWM3, + CC3220SF_LAUNCHXL_PWM2, + CC3220SF_LAUNCHXL_PWM5, CC3220SF_LAUNCHXL_PWMCOUNT } CC3220SF_LAUNCHXL_PWMName; diff --git a/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/device/CC3220SF_WiFiInterface.cpp b/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/device/CC3220SF_WiFiInterface.cpp index ac3703e48a..4515891ff6 100644 --- a/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/device/CC3220SF_WiFiInterface.cpp +++ b/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/device/CC3220SF_WiFiInterface.cpp @@ -588,7 +588,7 @@ void CC3220SFInterface::_socket_background_thread() } _mutex.unlock(); } - wait_ms(READ_THREAD_SLEEP_MS); + ThisThread::sleep_for(READ_THREAD_SLEEP_MS); } } diff --git a/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/device/cc3200_simplelink.cpp b/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/device/cc3200_simplelink.cpp index 7feee34601..683a37d422 100644 --- a/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/device/cc3200_simplelink.cpp +++ b/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/device/cc3200_simplelink.cpp @@ -378,7 +378,7 @@ int CC3200_SIMPLELINK::scan(WiFiAccessPoint *res, unsigned count) while(triggeredScanTrials < MAX_SCAN_ATTEMPTS) { /* We wait for one second for the NWP to complete the initiated scan and collect results */ - wait_ms(1000); + ThisThread::sleep_for(1000); /* Collect results form one-shot scans.*/ ret = sl_WlanGetNetworkList(0, entries_count, netEntries); @@ -663,7 +663,7 @@ nsapi_error_t CC3200_SIMPLELINK::connect_socket(uint32_t sd, const SocketAddress { if (status == SL_ERROR_BSD_EALREADY && 1 == nonBlocking) { - wait_ms(1); + ThisThread::sleep_for(1); continue; } else if (status < 0) @@ -711,7 +711,7 @@ int CC3200_SIMPLELINK::sendto_socket(uint32_t sd, const void * buf, uint32_t buf status = sl_SendTo(sd, buf, bufLen, 0, sa, addrSize); if (status == SL_ERROR_BSD_EAGAIN && 1 == SOCKET_IS_NON_BLOCKING) { - wait_ms(1); + ThisThread::sleep_for(1); continue; } else if (status < 0) @@ -733,7 +733,7 @@ int32_t CC3200_SIMPLELINK::send(int sd, const void *data, uint32_t size) status = sl_Send(sd, data, size, 0); if (status == SL_ERROR_BSD_EAGAIN && 1 == SOCKET_IS_NON_BLOCKING) { - wait_ms(1); + ThisThread::sleep_for(1); continue; } else if (status < 0) diff --git a/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/objects.h b/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/objects.h index 0f21947308..821bc03017 100644 --- a/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/objects.h +++ b/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/objects.h @@ -40,8 +40,8 @@ struct gpio_irq_s { uint32_t port; PinName pin; uint32_t ch; - unsigned long pin_mask; - unsigned long irq_offset; + unsigned long pin_mask; + unsigned long irq_offset; }; struct port_s { @@ -52,7 +52,9 @@ struct port_s { }; struct pwmout_s { - uint32_t pwmPin; + uint32_t period_us; + float duty_percent; + void * handle; PWMName pwm; }; diff --git a/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/pwmout_api.c b/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/pwmout_api.c index bf345c5fb1..348bd2fc0f 100644 --- a/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/pwmout_api.c +++ b/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/pwmout_api.c @@ -15,148 +15,89 @@ */ #include "mbed_assert.h" #include "pwmout_api.h" -#include "cmsis.h" #include "pinmap.h" #include "PeripheralPins.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include -static const uint32_t timerBaseAddresses[4] = { - CC3220SF_TIMERA0_BASE, - CC3220SF_TIMERA1_BASE, - CC3220SF_TIMERA2_BASE, - CC3220SF_TIMERA3_BASE, -}; - -static const uint32_t timerHalves[2] = { - TIMER_A, - TIMER_B, -}; - -/*static const uint32_t gpioBaseAddresses[4] = { - CC3220SF_GPIOA0_BASE, - CC3220SF_GPIOA1_BASE, - CC3220SF_GPIOA2_BASE, - CC3220SF_GPIOA3_BASE, -};*/ - -/*static const uint32_t gpioPinIndexes[8] = { - GPIO_PIN_0, - GPIO_PIN_1, - GPIO_PIN_2, - GPIO_PIN_3, - GPIO_PIN_4, - GPIO_PIN_5, - GPIO_PIN_6, - GPIO_PIN_7, -};*/ - -#define PinConfigTimerPort(config) (((config) >> 28) & 0xF) -#define PinConfigTimerHalf(config) (((config) >> 24) & 0xF) -#define PinConfigGPIOPort(config) (((config) >> 20) & 0xF) -#define PinConfigGPIOPinIndex(config) (((config) >> 16) & 0xF) -#define PinConfigPinMode(config) (((config) >> 8) & 0xF) -#define PinConfigPin(config) (((config) >> 0) & 0x3F) - -#define PWMTimerCC32XX_T0A (0x00 << 24) -#define PWMTimerCC32XX_T0B (0x01 << 24) -#define PWMTimerCC32XX_T1A (0x10 << 24) -#define PWMTimerCC32XX_T1B (0x11 << 24) -#define PWMTimerCC32XX_T2A (0x20 << 24) -#define PWMTimerCC32XX_T2B (0x21 << 24) -#define PWMTimerCC32XX_T3A (0x30 << 24) -#define PWMTimerCC32XX_T3B (0x31 << 24) - -#define PWMTimerCC32XX_GPIO9 (0x11 << 16) -#define PWMTimerCC32XX_GPIO10 (0x12 << 16) -#define PWMTimerCC32XX_GPIO11 (0x13 << 16) -#define PWMTimerCC32XX_GPIO24 (0x30 << 16) -#define PWMTimerCC32XX_GPIO25 (0x31 << 16) - -#define PWMTimerCC32XX_GPIONONE (0xFF << 16) - -#define PWMTimerCC32XX_PIN_01 (PWMTimerCC32XX_T3A | PWMTimerCC32XX_GPIO10 | 0x0300) -#define PWMTimerCC32XX_PIN_02 (PWMTimerCC32XX_T3B | PWMTimerCC32XX_GPIO11 | 0x0301) -#define PWMTimerCC32XX_PIN_17 (PWMTimerCC32XX_T0A | PWMTimerCC32XX_GPIO24 | 0x0510) -#define PWMTimerCC32XX_PIN_19 (PWMTimerCC32XX_T1B | PWMTimerCC32XX_GPIONONE | 0x0812) -#define PWMTimerCC32XX_PIN_21 (PWMTimerCC32XX_T1A | PWMTimerCC32XX_GPIO25 | 0x0914) -#define PWMTimerCC32XX_PIN_64 (PWMTimerCC32XX_T2B | PWMTimerCC32XX_GPIO9 | 0x033F) - -//static unsigned int pwm_clock_mhz; +extern const PWM_Config PWM_config[]; void pwmout_init(pwmout_t* obj, PinName pin) { + PWM_Params pwmParams; + int pwmIndex = CC3220SF_LAUNCHXL_PWMCOUNT; + + PWM_init(); + PWMName pwm = (PWMName)pinmap_peripheral(pin, PinMap_PWM); MBED_ASSERT(pwm != (PWMName)NC); + obj->pwm = pwm; switch(pin) { - case PIN_01: obj->pwmPin = PWMTimerCC32XX_PIN_01; break; - case PIN_02: obj->pwmPin = PWMTimerCC32XX_PIN_02; break; - case PIN_17: obj->pwmPin = PWMTimerCC32XX_PIN_17; break; - case PIN_19: obj->pwmPin = PWMTimerCC32XX_PIN_19; break; - case PIN_21: obj->pwmPin = PWMTimerCC32XX_PIN_21; break; - case PIN_64: obj->pwmPin = PWMTimerCC32XX_PIN_64; break; - default: break; + case PIN_01: + pwmIndex = CC3220SF_LAUNCHXL_PWM6; + break; + + case PIN_02: + pwmIndex = CC3220SF_LAUNCHXL_PWM7; + break; + + case PIN_17: + pwmIndex = CC3220SF_LAUNCHXL_PWM0; + break; + + case PIN_19: + pwmIndex = CC3220SF_LAUNCHXL_PWM3; + break; + + case PIN_21: + pwmIndex = CC3220SF_LAUNCHXL_PWM2; + break; + + case PIN_64: + pwmIndex = CC3220SF_LAUNCHXL_PWM5; + break; + + default: + while(1); } - uint32_t timerBaseAddr = timerBaseAddresses[PinConfigTimerPort(obj->pwmPin)]; - uint16_t halfTimer = timerHalves[PinConfigTimerHalf(obj->pwmPin)]; + obj->handle = (void *)&PWM_config[pwmIndex]; - MAP_TimerDisable(timerBaseAddr, halfTimer); + // Initialize the PWM parameters + PWM_Params_init(&pwmParams); - /* - * The CC32XX SDK TimerConfigure API halts both timers when it is - * used to configure a single half timer. The code below performs - * the register operations necessary to configure each half timer - * individually. - */ - /* Enable CCP to IO path */ - HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_GPT_TRIG_SEL) = 0xFF; + obj->duty_percent = PWM_DEFAULT_DUTY_PERCENT; + obj->period_us = PWM_DEFAULT_PERIOD_US; - /* Split the timer and configure it as a PWM */ - uint32_t timerConfigVal = ((halfTimer & (TIMER_CFG_A_PWM | TIMER_CFG_B_PWM)) | - TIMER_CFG_SPLIT_PAIR); - HWREG(timerBaseAddr + TIMER_O_CFG) |= (timerConfigVal >> 24); - if (halfTimer & TIMER_A) { - HWREG(timerBaseAddr + TIMER_O_TAMR) = timerConfigVal & 255; + if (PWM_open(pwmIndex, &pwmParams)) + { + PWM_start((PWM_Handle)obj->handle); } - else { - HWREG(timerBaseAddr + TIMER_O_TBMR) = (timerConfigVal >> 8) & 255; + else + { + while(1); } - - /* Set the peripheral output to active-high */ - MAP_TimerControlLevel(timerBaseAddr, halfTimer, true); - - uint16_t mode = PinConfigPinMode(obj->pwmPin); - - /* Start the timer & set pinmux to PWM mode */ - MAP_TimerEnable(timerBaseAddr, halfTimer); - MAP_PinTypeTimer((unsigned long)pin, (unsigned long)mode); } void pwmout_free(pwmout_t* obj) { - // [TODO] + PWM_stop((PWM_Handle)obj->handle); + PWM_close((PWM_Handle)obj->handle); } void pwmout_write(pwmout_t* obj, float value) { - + PWM_setDuty((PWM_Handle)obj->handle, value*100); + obj->duty_percent = value; } float pwmout_read(pwmout_t* obj) { - return 0; + return (obj->duty_percent); } void pwmout_period(pwmout_t* obj, float seconds) { - pwmout_period_us(obj, seconds * 1000000.0f); + pwmout_period_us(obj, seconds * 1000 * 1000); } void pwmout_period_ms(pwmout_t* obj, int ms) { @@ -165,7 +106,8 @@ void pwmout_period_ms(pwmout_t* obj, int ms) { // Set the PWM period, keeping the duty cycle the same. void pwmout_period_us(pwmout_t* obj, int us) { - + PWM_setPeriod((PWM_Handle)obj->handle, us); + obj->period_us = us; } void pwmout_pulsewidth(pwmout_t* obj, float seconds) { @@ -177,7 +119,11 @@ void pwmout_pulsewidth_ms(pwmout_t* obj, int ms) { } void pwmout_pulsewidth_us(pwmout_t* obj, int us) { - + if (obj->period_us) + { + float value = (float)us / (float)obj->period_us; + pwmout_write(obj, value); + } } const PinMap *pwmout_pinmap() diff --git a/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/ti/drivers/PWM.c b/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/ti/drivers/PWM.c new file mode 100644 index 0000000000..7332b51153 --- /dev/null +++ b/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/ti/drivers/PWM.c @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2015-2017, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * ======== PWM.c ======== + */ + +#include +#include +#include + +#include +#include + +extern const PWM_Config PWM_config[]; +extern const uint_least8_t PWM_count; + +/* Default PWM parameters structure */ +const PWM_Params PWM_defaultParams = { + .periodUnits = PWM_PERIOD_US, /* Period is defined in Hz */ + .periodValue = PWM_DEFAULT_PERIOD_US, /* 1US */ + .dutyUnits = PWM_DUTY_FRACTION, /* Duty is fraction of period */ + .dutyValue = PWM_DEFAULT_DUTY_PERCENT, /* 0% duty cycle */ + .idleLevel = PWM_IDLE_LOW, /* Low idle level */ + .custom = NULL /* No custom params */ +}; + +static bool isInitialized = false; + +/* + * ======== PWM_close ======== + */ +void PWM_close(PWM_Handle handle) +{ + handle->fxnTablePtr->closeFxn(handle); +} + +/* + * ======== PWM_control ======== + */ +int_fast16_t PWM_control(PWM_Handle handle, uint_fast16_t cmd, void *arg) +{ + return handle->fxnTablePtr->controlFxn(handle, cmd, arg); +} + +/* + * ======== PWM_init ======== + */ +void PWM_init(void) +{ + uint_least8_t i; + uint_fast32_t key; + + key = HwiP_disable(); + + if (!isInitialized) { + isInitialized = (bool) true; + + /* Call each driver's init function */ + for (i = 0; i < PWM_count; i++) { + PWM_config[i].fxnTablePtr->initFxn((PWM_Handle) &(PWM_config[i])); + } + } + + HwiP_restore(key); +} + +/* + * ======== PWM_open ======== + */ +PWM_Handle PWM_open(uint_least8_t index, PWM_Params *params) +{ + PWM_Handle handle = NULL; + + if (isInitialized && (index < PWM_count)) { + /* If params are NULL use defaults */ + if (params == NULL) { + params = (PWM_Params *) &PWM_defaultParams; + } + + /* Get handle for this driver instance */ + handle = (PWM_Handle) &(PWM_config[index]); + + handle = handle->fxnTablePtr->openFxn(handle, params); + } + + return (handle); +} + +/* + * ======== PWM_Params_init ======== + */ +void PWM_Params_init(PWM_Params *params) +{ + *params = PWM_defaultParams; +} + +/* + * ======== PWM_setDuty ======== + */ +int_fast16_t PWM_setDuty(PWM_Handle handle, uint32_t duty) +{ + return(handle->fxnTablePtr->setDutyFxn(handle, duty)); +} + +/* + * ======== PWM_setDuty ======== + */ +int_fast16_t PWM_setPeriod(PWM_Handle handle, uint32_t period) +{ + return(handle->fxnTablePtr->setPeriodFxn(handle, period)); +} + +/* + * ======== PWM_start ======== + */ +void PWM_start(PWM_Handle handle) +{ + handle->fxnTablePtr->startFxn(handle); +} + +/* + * ======== PWM_stop ======== + */ +void PWM_stop(PWM_Handle handle) +{ + handle->fxnTablePtr->stopFxn(handle); +} diff --git a/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/ti/drivers/PWM.h b/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/ti/drivers/PWM.h new file mode 100644 index 0000000000..091141747b --- /dev/null +++ b/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/ti/drivers/PWM.h @@ -0,0 +1,594 @@ +/* + * Copyright (c) 2015-2017, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/** ============================================================================ + * @file PWM.h + * @brief PWM driver interface + * + * To use the PWM driver, ensure that the correct driver library for your + * device is linked in and include this header file as follows: + * @code + * #include + * @endcode + * + * This module serves as the main interface for applications. Its purpose + * is to redirect the PWM APIs to specific driver implementations + * which are specified using a pointer to a #PWM_FxnTable. + * + * # Overview # + * The PWM driver in TI-RTOS facilitates the generation of Pulse Width + * Modulated signals via simple and portable APIs. PWM instances must be + * opened by calling PWM_open() while passing in a PWM index and a parameters + * data structure. + * + * The driver APIs serve as an interface to a typical TI-RTOS application. + * The specific peripheral implementations are responsible for creating all OS + * specific primitives to allow for thread-safe operation. + * + * When a PWM instance is opened, the period, duty cycle and idle level are + * configured and the PWM is stopped (waveforms not generated until PWM_start() + * is called). The maximum period and duty supported is device dependent; + * refer to the implementation specific documentation for values. + * + * PWM outputs are active-high, meaning the duty will control the duration of + * high output on the pin (at 0% duty, the output is always low, at 100% duty, + * the output is always high). + * + * # Usage # + * + * @code + * PWM_Handle pwm; + * PWM_Params pwmParams; + * + * // Initialize the PWM driver. + * PWM_init(); + * + * // Initialize the PWM parameters + * PWM_Params_init(&pwmParams); + * pwmParams.idleLevel = PWM_IDLE_LOW; // Output low when PWM is not running + * pwmParams.periodUnits = PWM_PERIOD_HZ; // Period is in Hz + * pwmParams.periodValue = 1e6; // 1MHz + * pwmParams.dutyUnits = PWM_DUTY_FRACTION; // Duty is in fractional percentage + * pwmParams.dutyValue = 0; // 0% initial duty cycle + * + * // Open the PWM instance + * pwm = PWM_open(Board_PWM0, &pwmParams); + * + * if (pwm == NULL) { + * // PWM_open() failed + * while (1); + * } + * + * PWM_start(pwm); // start PWM with 0% duty cycle + * + * PWM_setDuty(pwm, + * (PWM_DUTY_FRACTION_MAX / 2)); // set duty cycle to 50% + * @endcode + * + * Details for the example code above are described in the following + * subsections. + * + * ### PWM Driver Configuration # + * + * In order to use the PWM APIs, the application is required + * to provide device-specific PWM configuration in the Board.c file. + * The PWM driver interface defines a configuration data structure: + * + * @code + * typedef struct PWM_Config_ { + * PWM_FxnTable const *fxnTablePtr; + * void *object; + * void const *hwAttrs; + * } PWM_Config; + * @endcode + * + * The application must declare an array of PWM_Config elements, named + * PWM_config[]. Each element of PWM_config[] is populated with + * pointers to a device specific PWM driver implementation's function + * table, driver object, and hardware attributes. The hardware attributes + * define properties such as which pin will be driven, and which timer peripheral + * will be used. Each element in PWM_config[] corresponds to + * a PWM instance, and none of the elements should have NULL pointers. + * + * Additionally, the PWM driver interface defines a global integer variable + * 'PWM_count' which is initialized to the number of PWM instances the + * application has defined in the PWM_Config array. + * + * You will need to check the device-specific PWM driver implementation's + * header file for example configuration. Please also refer to the + * Board.c file of any of your examples to see the PWM configuration. + * + * ### Initializing the PWM Driver # + * + * PWM_init() must be called before any other PWM APIs. This function + * calls the device implementation's PWM initialization function, for each + * element of PWM_config[]. + * + * ### Opening the PWM Driver # + * + * Opening a PWM requires four steps: + * 1. Create and initialize a PWM_Params structure. + * 2. Fill in the desired parameters. + * 3. Call PWM_open(), passing the index of the PWM in the PWM_config + * structure, and the address of the PWM_Params structure. The + * PWM instance is specified by the index in the PWM_config structure. + * 4. Check that the PWM handle returned by PWM_open() is non-NULL, + * and save it. The handle will be used to read and write to the + * PWM you just opened. + * + * Only one PWM index can be used at a time; calling PWM_open() a second + * time with the same index previously passed to PWM_open() will result in + * an error. You can, though, re-use the index if the instance is closed + * via PWM_close(). + * In the example code, Board_PWM0 is passed to PWM_open(). This macro + * is defined in the example's Board.h file. + * + * ### Modes of Operation # + * + * A PWM instance can be configured to interpret the period as one of three + * units: + * - #PWM_PERIOD_US: The period is in microseconds. + * - #PWM_PERIOD_HZ: The period is in (reciprocal) Hertz. + * - #PWM_PERIOD_COUNTS: The period is in timer counts. + * + * A PWM instance can be configured to interpret the duty as one of three + * units: + * - #PWM_DUTY_US: The duty is in microseconds. + * - #PWM_DUTY_FRACTION: The duty is in a fractional part of the period + * where 0 is 0% and #PWM_DUTY_FRACTION_MAX is 100%. + * - #PWM_DUTY_COUNTS: The period is in timer counts and must be less than + * the period. + * + * The idle level parameter is used to set the output to high/low when the + * PWM is not running (stopped or not started). The idle level can be + * set to: + * - #PWM_IDLE_LOW + * - #PWM_IDLE_HIGH + * + * The default PWM configuration is to set a duty of 0% with a 1MHz frequency. + * The default period units are in PWM_PERIOD_HZ and the default duty units + * are in PWM_DUTY_FRACTION. Finally, the default output idle level is + * PWM_IDLE_LOW. It is the application's responsibility to set the duty for + * each PWM output used. + * + * ### Controlling the PWM Duty Cycle # + * + * Once the PWM instance has been opened and started, the primary API used + * by the application will be #PWM_setDuty() to control the duty cycle of a + * PWM pin: + * + * @code + * PWM_setDuty(pwm, PWM_DUTY_FRACTION_MAX / 2); // Set 50% duty cycle + * @endcode + * + * # Implementation # + * + * The PWM driver interface module is joined (at link time) to an + * array of PWM_Config data structures named *PWM_config*. + * PWM_config is implemented in the application with each entry being a + * PWM instance. Each entry in *PWM_config* contains a: + * - (PWM_FxnTable *) to a set of functions that implement a PWM peripheral + * - (void *) data object that is associated with the PWM_FxnTable + * - (void *) hardware attributes that are associated with the PWM_FxnTable + * + * The PWM APIs are redirected to the device specific implementations + * using the PWM_FxnTable pointer of the PWM_config entry. + * In order to use device specific functions of the PWM driver directly, + * link in the correct driver library for your device and include the + * device specific PWM driver header file (which in turn includes PWM.h). + * For example, for the MSP432 family of devices, you would include the + * following header file: + * @code + * #include + * @endcode + * + * ============================================================================ + */ + +#ifndef ti_drivers_PWM__include +#define ti_drivers_PWM__include + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define PWM_DEFAULT_PERIOD_US 1 +#define PWM_DEFAULT_DUTY_PERCENT 0 + +/*! + * @brief Maximum duty (100%) when configuring duty cycle as a fraction of + * period. + */ +#define PWM_DUTY_FRACTION_MAX ((uint32_t) 100) + +/*! + * Common PWM_control command code reservation offset. + * PWM driver implementations should offset command codes with PWM_CMD_RESERVED + * growing positively. + * + * Example implementation specific command codes: + * @code + * #define PWMXYZ_COMMAND0 (PWM_CMD_RESERVED + 0) + * #define PWMXYZ_COMMAND1 (PWM_CMD_RESERVED + 1) + * @endcode + */ +#define PWM_CMD_RESERVED (32) + +/*! + * Common PWM_control status code reservation offset. + * PWM driver implementations should offset status codes with + * PWM_STATUS_RESERVED growing negatively. + * + * Example implementation specific status codes: + * @code + * #define PWMXYZ_STATUS_ERROR0 (PWM_STATUS_RESERVED - 0) + * #define PWMXYZ_STATUS_ERROR1 (PWM_STATUS_RESERVED - 1) + * #define PWMXYZ_STATUS_ERROR2 (PWM_STATUS_RESERVED - 2) + * @endcode + */ +#define PWM_STATUS_RESERVED (-32) + +/*! + * @brief Success status code returned by: + * PWM_control(), PWM_setDuty(), PWM_setPeriod(). + * + * Functions return PWM_STATUS_SUCCESS if the call was executed + * successfully. + */ +#define PWM_STATUS_SUCCESS (0) + +/*! + * @brief Generic error status code returned by PWM_control(). + * + * PWM_control() returns PWM_STATUS_ERROR if the control code was not executed + * successfully. + */ +#define PWM_STATUS_ERROR (-1) + +/*! + * @brief An error status code returned by PWM_control() for undefined + * command codes. + * + * PWM_control() returns PWM_STATUS_UNDEFINEDCMD if the control code is not + * recognized by the driver implementation. + */ +#define PWM_STATUS_UNDEFINEDCMD (-2) + +/*! + * @brief An error status code returned by PWM_setPeriod(). + * + * PWM_setPeriod() returns PWM_STATUS_INVALID_PERIOD if the period argument is + * invalid for the current configuration. + */ +#define PWM_STATUS_INVALID_PERIOD (-3) + +/*! + * @brief An error status code returned by PWM_setDuty(). + * + * PWM_setDuty() returns PWM_STATUS_INVALID_DUTY if the duty cycle argument is + * invalid for the current configuration. + */ +#define PWM_STATUS_INVALID_DUTY (-4) + +/*! + * @brief PWM period unit definitions. Refer to device specific + * implementation if using PWM_PERIOD_COUNTS (raw PWM/Timer counts). + */ +typedef enum PWM_Period_Units_ { + PWM_PERIOD_US, /*!< Period in microseconds */ + PWM_PERIOD_HZ, /*!< Period in (reciprocal) Hertz + (for example 2MHz = 0.5us period) */ + PWM_PERIOD_COUNTS /*!< Period in timer counts */ +} PWM_Period_Units; + +/*! + * @brief PWM duty cycle unit definitions. Refer to device specific + * implementation if using PWM_DUTY_COUNTS (raw PWM/Timer counts). + */ +typedef enum PWM_Duty_Units_ { + PWM_DUTY_US, /*!< Duty cycle in microseconds */ + PWM_DUTY_FRACTION, /*!< Duty as a fractional part of PWM_DUTY_FRACTION_MAX */ + PWM_DUTY_COUNTS /*!< Duty in timer counts */ +} PWM_Duty_Units; + +/*! + * @brief Idle output level when PWM is not running (stopped / not started). + */ +typedef enum PWM_IdleLevel_ { + PWM_IDLE_LOW = 0, + PWM_IDLE_HIGH = 1, +} PWM_IdleLevel; + +/*! + * @brief PWM Parameters + * + * PWM Parameters are used to with the PWM_open() call. Default values for + * these parameters are set using PWM_Params_init(). + * + * @sa PWM_Params_init() + */ +typedef struct PWM_Params_ { + PWM_Period_Units periodUnits; /*!< Units in which the period is specified */ + uint32_t periodValue; /*!< PWM initial period */ + PWM_Duty_Units dutyUnits; /*!< Units in which the duty is specified */ + uint32_t dutyValue; /*!< PWM initial duty */ + PWM_IdleLevel idleLevel; /*!< Pin output when PWM is stopped. */ + void *custom; /*!< Custom argument used by driver + implementation */ +} PWM_Params; + +/*! + * @brief A handle that is returned from a PWM_open() call. + */ +typedef struct PWM_Config_ *PWM_Handle; + +/*! + * @brief A function pointer to a driver specific implementation of + * PWM_close(). + */ +typedef void (*PWM_CloseFxn) (PWM_Handle handle); + +/*! + * @brief A function pointer to a driver specific implementation of + * PWM_control(). + */ +typedef int_fast16_t (*PWM_ControlFxn) (PWM_Handle handle, uint_fast16_t cmd, + void *arg); +/*! + * @brief A function pointer to a driver specific implementation of + * PWM_init(). + */ +typedef void (*PWM_InitFxn) (PWM_Handle handle); + +/*! + * @brief A function pointer to a driver specific implementation of + * PWM_open(). + */ +typedef PWM_Handle (*PWM_OpenFxn) (PWM_Handle handle, PWM_Params *params); + +/*! + * @brief A function pointer to a driver specific implementation of + * PWM_setDuty(). + */ +typedef int_fast16_t (*PWM_SetDutyFxn) (PWM_Handle handle, + uint32_t duty); + +/*! + * @brief A function pointer to a driver specific implementation of + * PWM_setPeriod(). + */ +typedef int_fast16_t (*PWM_SetPeriodFxn) (PWM_Handle handle, + uint32_t period); + +/*! + * @brief A function pointer to a driver specific implementation of + * PWM_start(). + */ +typedef void (*PWM_StartFxn) (PWM_Handle handle); + +/*! + * @brief A function pointer to a driver specific implementation of + * PWM_stop(). + */ +typedef void (*PWM_StopFxn) (PWM_Handle handle); + +/*! + * @brief The definition of a PWM function table that contains the + * required set of functions to control a specific PWM driver + * implementation. + */ +typedef struct PWM_FxnTable_ { + /*! Function to close the specified instance */ + PWM_CloseFxn closeFxn; + /*! Function to driver implementation specific control function */ + PWM_ControlFxn controlFxn; + /*! Function to initialize the given data object */ + PWM_InitFxn initFxn; + /*! Function to open the specified instance */ + PWM_OpenFxn openFxn; + /*! Function to set the duty cycle for a specific instance */ + PWM_SetDutyFxn setDutyFxn; + /*! Function to set the period for a specific instance */ + PWM_SetPeriodFxn setPeriodFxn; + /*! Function to start the PWM output for a specific instance */ + PWM_StartFxn startFxn; + /*! Function to stop the PWM output for a specific instance */ + PWM_StopFxn stopFxn; +} PWM_FxnTable; + +/*! + * @brief PWM Global configuration. + * + * The PWM_Config structure contains a set of pointers used to characterize + * the PWM driver implementation. + * + */ +typedef struct PWM_Config_ { + /*! Pointer to a table of driver-specific implementations of PWM APIs */ + PWM_FxnTable const *fxnTablePtr; + /*! Pointer to a driver specific data object */ + void *object; + /*! Pointer to a driver specific hardware attributes structure */ + void const *hwAttrs; +} PWM_Config; + +/*! + * @brief Function to close a PWM instance specified by the PWM handle. + * + * @pre PWM_open() must have been called first. + * @pre PWM_stop() must have been called first if PWM was started. + * + * @param handle A PWM handle returned from PWM_open(). + * + * @sa PWM_open() + * @sa PWM_start() + * @sa PWM_stop() + */ +extern void PWM_close(PWM_Handle handle); + +/*! + * @brief Function performs implementation specific features on a given + * PWM_Handle. + * + * @pre PWM_open() must have been called first. + * + * @param handle A PWM handle returned from PWM_open(). + * + * @param cmd A command value defined by the driver specific + * implementation. + * + * @param arg A pointer to an optional R/W (read/write) argument that + * is accompanied with cmd. + * + * @return A PWM_Status describing an error or success state. Negative values + * indicate an error occurred. + * + * @sa PWM_open() + */ +extern int_fast16_t PWM_control(PWM_Handle handle, uint_fast16_t cmd, + void *arg); + +/*! + * @brief This function initializes the PWM module. + * + * @pre The PWM_config structure must exist and be persistent before this + * function can be called. This function must be called before any + * other PWM driver APIs. This function does not modify any peripheral + * registers & should only be called once. + */ +extern void PWM_init(void); + +/*! + * @brief This function opens a given PWM instance and sets the period, + * duty and idle level to those specified in the params argument. + * + * @param index Logical instance number for the PWM indexed into + * the PWM_config table. + * + * @param params Pointer to an parameter structure. If NULL default + * values are used. + * + * @return A PWM_Handle if successful or NULL on an error or if it has been + * opened already. If NULL is returned further PWM API calls will + * result in undefined behavior. + * + * @sa PWM_close() + */ +extern PWM_Handle PWM_open(uint_least8_t index, PWM_Params *params); + +/*! + * @brief Function to initialize the PWM_Params structure to default values. + * + * @param params A pointer to PWM_Params structure for initialization. + * + * Defaults values are: + * Period units: PWM_PERIOD_HZ + * Period: 1e6 (1MHz) + * Duty cycle units: PWM_DUTY_FRACTION + * Duty cycle: 0% + * Idle level: PWM_IDLE_LOW + */ +extern void PWM_Params_init(PWM_Params *params); + +/*! + * @brief Function to set the duty cycle of the specified PWM handle. PWM + * instances run in active high output mode; 0% is always low output, + * 100% is always high output. This API can be called while the PWM + * is running & duty must always be lower than or equal to the period. + * If an error occurs while calling the function the PWM duty cycle + * will remain unchanged. + * + * @pre PWM_open() must have been called first. + * + * @param handle A PWM handle returned from PWM_open(). + * + * @param duty Duty cycle in the units specified by the params used + * in PWM_open(). + * + * @return A PWM status describing an error or success. Negative values + * indicate an error. + * + * @sa PWM_open() + */ +extern int_fast16_t PWM_setDuty(PWM_Handle handle, uint32_t duty); + +/*! + * @brief Function to set the period of the specified PWM handle. This API + * can be called while the PWM is running & the period must always be + * larger than the duty cycle. + * If an error occurs while calling the function the PWM period + * will remain unchanged. + * + * @pre PWM_open() must have been called first. + * + * @param handle A PWM handle returned from PWM_open(). + * + * @param period Period in the units specified by the params used + * in PWM_open(). + * + * @return A PWM status describing an error or success state. Negative values + * indicate an error. + * + * @sa PWM_open() + */ +extern int_fast16_t PWM_setPeriod(PWM_Handle handle, uint32_t period); + +/*! + * @brief Function to start the specified PWM handle with current settings. + * + * @pre PWM_open() has to have been called first. + * + * @param handle A PWM handle returned from PWM_open(). + * + * @sa PWM_open() + * @sa PWM_stop() + */ +extern void PWM_start(PWM_Handle handle); + +/*! + * @brief Function to stop the specified PWM handle. Output will set to the + * idle level specified by params in PWM_open(). + * + * @pre PWM_open() has to have been called first. + * + * @param handle A PWM handle returned from PWM_open(). + * + * @sa PWM_open() + * @sa PWM_start() + */ +extern void PWM_stop(PWM_Handle handle); + +#ifdef __cplusplus +} +#endif +#endif /* ti_drivers_PWM__include */ diff --git a/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/ti/drivers/Timer.h b/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/ti/drivers/Timer.h new file mode 100644 index 0000000000..a35edae0f3 --- /dev/null +++ b/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/ti/drivers/Timer.h @@ -0,0 +1,549 @@ +/* + * Copyright (c) 2016-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*!***************************************************************************** + * @file Timer.h + * @brief Timer driver interface + * + * The timer header file should be included in an application as follows: + * @code + * #include + * @endcode + * + * # Overview # + * The timer driver serves as the main interface for a typical RTOS + * application. Its purpose is to redirect the timer APIs to device specific + * implementations which are specified using a pointer to a #Timer_FxnTable. + * The device specific implementations are responsible for creating all the + * RTOS specific primitives to allow for thead-safe operation. This driver + * does not have PWM or capture functionalities. These functionalities are + * addressed in both the capture and PWM driver. + * + * The timer driver also handles the general purpose timer resource allocation. + * For each driver that requires use of a general purpose timer, it calls + * Timer_open() to occupy the specified timer, and calls Timer_close() to + * release the occupied timer resource. + * + * # Usage # + * The following example code opens a timer in continuous callback mode. The + * period is set to 1000 Hz. + * + * @code + * Timer_Handle handle; + * Timer_Params params; + * + * Timer_Params_init(¶ms); + * params.periodUnits = Timer_PERIOD_HZ; + * params.period = 1000; + * params.timerMode = Timer_CONTINUOUS_CALLBACK; + * params.timerCallback = UserCallbackFunction; + * + * handle = Timer_open(Board_TIMER0, ¶ms); + * + * if (handle == NULL) { + * // Timer_open() failed + * while (1); + * } + * + * status = Timer_start(handle); + * + * if (status == Timer_STATUS_ERROR) { + * //Timer_start() failed + * while (1); + * } + * + * sleep(10000); + * + * Timer_stop(handle); + * @endcode + * + * ### Timer Driver Configuration # + * + * In order to use the timer APIs, the application is required to provide + * device specific timer configuration in the Board.c file. The timer driver + * interface defines a configuration data structure: + * + * @code + * typedef struct Timer_Config_ { + * Timer_FxnTable const *fxnTablePtr; + * void *object; + * void const *hwAttrs; + * } Timer_Config; + * @endcode + * + * The application must declare an array of Timer_Config elements, named + * Timer_config[]. Each element of Timer_config[] are populated with + * pointers to a device specific timer driver implementation's function + * table, driver object, and hardware attributes. The hardware attributes + * define properties such as the timer peripheral's base address, interrupt + * number and interrupt priority. Each element in Timer_config[] corresponds + * to a timer instance, and none of the elements should have NULL pointers. + * There is no correlation between the index and the peripheral designation + * (such as TIMER0 or TIMER1). For example, it is possible to use + * Timer_config[0] for TIMER1. + * + * You will need to check the device specific timer driver implementation's + * header file for example configuration. + * + * ### Initializing the Timer Driver # + * + * Timer_init() must be called before any other timer APIs. This function + * calls the device implementation's timer initialization function, for each + * element of Timer_config[]. + * + * ### Modes of Operation # + * + * The timer driver supports four modes of operation which may be specified in + * the Timer_Params. The device specific implementation may configure the timer + * peripheral as an up or down counter. In any case, Timer_getCount() will + * return a value characteristic of an up counter. + * + * #Timer_ONESHOT_CALLBACK is non-blocking. After Timer_start() is called, + * the calling thread will continue execution. When the timer interrupt + * is triggered, the specified callback function will be called. The timer + * will not generate another interrupt unless Timer_start() is called again. + * Calling Timer_stop() or Timer_close() after Timer_start() but, before the + * timer interrupt, will prevent the specified callback from ever being + * invoked. + * + * #Timer_ONESHOT_BLOCKING is a blocking call. A semaphore is used to block + * the calling thread's execution until the timer generates an interrupt. If + * Timer_stop() is called, the calling thread will become unblocked + * immediately. The behavior of the timer in this mode is similar to a sleep + * function. + * + * #Timer_CONTINUOUS_CALLBACK is non-blocking. After Timer_start() is called, + * the calling thread will continue execution. When the timer interrupt is + * treiggered, the specified callback function will be called. The timer is + * automatically restarted and will continue to periodically generate + * interrupts until Timer_stop() is called. + * + * #Timer_FREE_RUNNING is non-blocking. After Timer_start() is called, + * the calling thread will continue execution. The timer will not + * generate an interrupt in this mode. The timer hardware will run until + * Timer_stop() is called. + * + * # Implementation # + * + * The timer driver interface module is joined (at link time) to an + * array of Timer_Config data structures named *Timer_config*. + * Timer_config is implemented in the application with each entry being an + * instance of a timer peripheral. Each entry in *Timer_config* contains a: + * - (Timer_FxnTable *) to a set of functions that implement a timer peripheral + * - (void *) data object that is associated with the Timer_FxnTable + * - (void *) hardware attributes that are associated with the Timer_FxnTable + * + * The timer APIs are redirected to the device specific implementations + * using the Timer_FxnTable pointer of the Timer_config entry. + * In order to use device specific functions of the timer driver directly, + * link in the correct driver library for your device and include the + * device specific timer driver header file (which in turn includes Timer.h). + * For example, for the MSP432 family of devices, you would include the + * following header file: + * + * @code + * #include + * @endcode + * + * ============================================================================ + */ + +#ifndef ti_drivers_Timer__include +#define ti_drivers_Timer__include + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + +/*! + * Common Timer_control command code reservation offset. + * Timer driver implementations should offset command codes with Timer_CMD_RESERVED + * growing positively + * + * Example implementation specific command codes: + * @code + * #define TimerXYZ_CMD_COMMAND0 Timer_CMD_RESERVED + 0 + * #define TimerXYZ_CMD_COMMAND1 Timer_CMD_RESERVED + 1 + * @endcode + */ +#define Timer_CMD_RESERVED (32) + +/*! + * Common Timer_control status code reservation offset. + * Timer driver implementations should offset status codes with + * Timer_STATUS_RESERVED growing negatively. + * + * Example implementation specific status codes: + * @code + * #define TimerXYZ_STATUS_ERROR0 Timer_STATUS_RESERVED - 0 + * #define TimerXYZ_STATUS_ERROR1 Timer_STATUS_RESERVED - 1 + * @endcode + */ +#define Timer_STATUS_RESERVED (-32) + +/*! + * @brief Successful status code. + */ +#define Timer_STATUS_SUCCESS (0) + +/*! + * @brief Generic error status code. + */ +#define Timer_STATUS_ERROR (-1) + +/*! + * @brief An error status code returned by Timer_control() for undefined + * command codes. + * + * Timer_control() returns Timer_STATUS_UNDEFINEDCMD if the control code is not + * recognized by the driver implementation. + */ +#define Timer_STATUS_UNDEFINEDCMD (-2) + +/*! + * @brief A handle that is returned from a Timer_open() call. + */ +typedef struct Timer_Config_ *Timer_Handle; + +/*! + * @brief Timer mode settings + * + * This enum defines the timer modes that may be specified in #Timer_Params. + */ +typedef enum Timer_Mode_ { + Timer_ONESHOT_CALLBACK, /*!< User routine doesn't get blocked and + user-specified callback function is + invoked once the timer interrupt happens + for only one time */ + Timer_ONESHOT_BLOCKING, /*!< User routine gets blocked until timer + interrupt happens for only one time. */ + Timer_CONTINUOUS_CALLBACK, /*!< User routine doesn't get blocked and + user-specified callback function is + invoked with every timer interrupt. */ + Timer_FREE_RUNNING +} Timer_Mode; + +/*! + * @brief Timer period unit enum + * + * This enum defines the units that may be specified for the period + * in #Timer_Params. This unit has no effect with Timer_getCounts. + */ +typedef enum Timer_PeriodUnits_ { + Timer_PERIOD_US, /*!< Period specified in micro seconds. */ + Timer_PERIOD_HZ, /*!< Period specified in hertz; interrupts per + second. */ + Timer_PERIOD_COUNTS /*!< Period specified in ticks or counts. Varies + from board to board. */ +} Timer_PeriodUnits; + +/*! + * @brief Timer callback function + * + * User definable callback function prototype. The timer driver will call the + * defined function and pass in the timer driver's handle and the pointer to the + * user-specified the argument. + * + * @param handle Timer_Handle + */ +typedef void (*Timer_CallBackFxn)(Timer_Handle handle); + +/*! + * @brief Timer Parameters + * + * Timer parameters are used to with the Timer_open() call. Default values for + * these parameters are set using Timer_Params_init(). + * + */ +typedef struct Timer_Params_ { + /*! Mode to be used by the timer driver. */ + Timer_Mode timerMode; + + /*! Units used to specify the period. */ + Timer_PeriodUnits periodUnits; + + /*! Callback function called when timerMode is Timer_ONESHOT_CALLBACK or + Timer_CONTINUOUS_CALLBACK. */ + Timer_CallBackFxn timerCallback; + + /*! Period in units of periodUnits. */ + uint32_t period; +} Timer_Params; + +/*! + * @brief A function pointer to a driver specific implementation of + * Timer_control(). + */ +typedef int_fast16_t (*Timer_ControlFxn)(Timer_Handle handle, + uint_fast16_t cmd, void *arg); + +/*! + * @brief A function pointer to a driver specific implementation of + * Timer_close(). + */ +typedef void (*Timer_CloseFxn)(Timer_Handle handle); + +/*! + * @brief A function pointer to a driver specific implementation of + * Timer_getCount(). + */ +typedef uint32_t (*Timer_GetCountFxn)(Timer_Handle handle); + +/*! + * @brief A function pointer to a driver specific implementation of + * Timer_init(). + */ +typedef void (*Timer_InitFxn)(Timer_Handle handle); + +/*! + * @brief A function pointer to a driver specific implementation of + * Timer_open(). + */ +typedef Timer_Handle (*Timer_OpenFxn)(Timer_Handle handle, + Timer_Params *params); + +/*! + * @brief A function pointer to a driver specific implementation of + * Timer_start(). + */ +typedef int32_t (*Timer_StartFxn)(Timer_Handle handle); + +/*! + * @brief A function pointer to a driver specific implementation of + * Timer_stop(). + */ +typedef void (*Timer_StopFxn)(Timer_Handle handle); + +/*! + * @brief The definition of a timer function table that contains the + * required set of functions to control a specific timer driver + * implementation. + */ +typedef struct Timer_FxnTable_ { + /*! Function to close the specified peripheral. */ + Timer_CloseFxn closeFxn; + + /*! Function to implementation specific control function. */ + Timer_ControlFxn controlFxn; + + /*! Function to get the count of the specified peripheral. */ + Timer_GetCountFxn getCountFxn; + + /*! Function to initialize the given data object. */ + Timer_InitFxn initFxn; + + /*! Function to open the specified peripheral. */ + Timer_OpenFxn openFxn; + + /*! Function to start the specified peripheral. */ + Timer_StartFxn startFxn; + + /*! Function to stop the specified peripheral. */ + Timer_StopFxn stopFxn; +} Timer_FxnTable; + +/*! + * @brief Timer Global configuration + * + * The Timer_Config structure contains a set of pointers used to characterize + * the timer driver implementation. + * + * This structure needs to be defined before calling Timer_init() and it must + * not be changed thereafter. + * + * @sa Timer_init() + */ +typedef struct Timer_Config_ { + /*! Pointer to a table of driver-specific implementations of timer APIs. */ + Timer_FxnTable const *fxnTablePtr; + + /*! Pointer to a driver specific data object. */ + void *object; + + /*! Pointer to a driver specific hardware attributes structure. */ + void const *hwAttrs; +} Timer_Config; + +/*! + * @brief Function to close a timer. The corresponding timer to the + * Timer_Handle becomes an available timer resource. + * + * @pre Timer_open() has been called. + * + * @param handle A Timer_Handle returned from Timer_open(). + * + * @sa Timer_open() + */ +extern void Timer_close(Timer_Handle handle); + +/*! + * @brief Function performs device specific features on a given + * Timer_Handle. + * + * @pre Timer_open() has been called. + * + * @param handle A Timer_Handle returned from Timer_open(). + * + * @param cmd A command value defined by the driver specific + * implementation. + * + * @param arg A pointer to an optional R/W (read/write) argument that + * is accompanied with cmd. + * + * @return A Timer_Status describing an error or success state. Negative values + * indicate an error occurred. + * + * @sa Timer_open() + */ +extern int_fast16_t Timer_control(Timer_Handle handle, uint_fast16_t cmd, + void *arg); + +/*! + * @brief Function to get the current count of a timer. The value returned + * represents timer counts. The value returned is always + * characteristic of an up counter. This is true even if the timer + * peripheral is counting down. Some device specific implementations + * may employ a prescaler in addition to this timer count. + * + * @pre Timer_open() has been called. + * + * @param handle A Timer_Handle returned from Timer_open(). + * + * @sa Timer_open() + * + * @return The current count of the timer in timer ticks. + * + */ +extern uint32_t Timer_getCount(Timer_Handle handle); + + +/*! + * @brief Function to initialize a timer module. This function will go through + * all available hardware resources and mark them as "available". + * + * @pre The Timer_config structure must exist and be persistent before this + * function can be called. This function must also be called before + * any other timer driver APIs. + * + * @sa Timer_open() + */ +extern void Timer_init(void); + +/*! + * @brief Function to initialize a given timer peripheral specified by the + * index argument. The Timer_Params specifies which mode the timer + * will operate. The accuracy of the desired period is limited by the + * the clock. For example, a 100 MHz clock will have a tick resolution + * of 10 nanoseconds. This function takes care of timer resource + * allocation. If the particular timer is available to use, the timer + * driver owns it and returns a Timer_Handle. + * + * @pre Timer_init() has been called. + * + * @param index Logical peripheral number for the timer indexed into + * the Timer_config table. + * + * @param params Pointer to an parameter block, if NULL it will use + * default values. + * + * @return A Timer_Handle upon success or NULL. If the desired period results + * in overflow, or saturation, of the timer, NULL is returned. If the + * timer resource is already in use, NULL is returned. + * + * @sa Timer_init() + * @sa Timer_close() + */ +extern Timer_Handle Timer_open(uint_least8_t index, Timer_Params *params); + +/*! + * @brief Function to initialize the Timer_Params struct to its defaults. + * + * @param params A pointer to Timer_Params structure for + * initialization. + * + * Defaults values are: + * timerMode = Timer_ONESHOT_BLOCKING + * periodUnit = Timer_PERIOD_COUNTS + * timerCallback = NULL + * period = (uint16_t) ~0 + */ +extern void Timer_Params_init(Timer_Params *params); + +/*! + * @brief Function to start the timer. + * + * @pre Timer_open() has been called. + * + * @param handle A Timer_Handle returned from Timer_open(). + * + * @return Timer_STATUS_SUCCESS or Timer_STATUS_ERROR. + * + * @sa Timer_stop() + */ +extern int32_t Timer_start(Timer_Handle handle); + +/*! + * @brief Function to stop timer. If the timer is already stopped, this + * function has no effect. + * + * @pre Timer_open() has been called. + * + * @param handle A Timer_Handle returned from Timer_open(). + * + * @sa Timer_start() + */ +extern void Timer_stop(Timer_Handle handle); + +/* The following are included for backwards compatibility. These should not be + * used by the application. + */ +#define TIMER_CMD_RESERVED Timer_CMD_RESERVED +#define TIMER_STATUS_RESERVED Timer_STATUS_RESERVED +#define TIMER_STATUS_SUCCESS Timer_STATUS_SUCCESS +#define TIMER_STATUS_ERROR Timer_STATUS_ERROR +#define TIMER_STATUS_UNDEFINEDCMD Timer_STATUS_UNDEFINEDCMD +#define TIMER_ONESHOT_CB Timer_ONESHOT_CALLBACK +#define TIMER_ONESHOT_BLOCK Timer_ONESHOT_BLOCKING +#define TIMER_CONTINUOUS_CB Timer_CONTINUOUS_CALLBACK +#define TIMER_MODE_FREE_RUNNING Timer_FREE_RUNNING +#define TIMER_PERIOD_US Timer_PERIOD_US +#define TIMER_PERIOD_HZ Timer_PERIOD_HZ +#define TIMER_PERIOD_COUNTS Timer_PERIOD_COUNTS +#define Timer_Period_Units Timer_PeriodUnits + +#ifdef __cplusplus +} +#endif + +#endif /* ti_drivers_Timer__include */ diff --git a/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/ti/drivers/pwm/PWMTimerCC32XX.c b/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/ti/drivers/pwm/PWMTimerCC32XX.c new file mode 100644 index 0000000000..d70037d501 --- /dev/null +++ b/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/ti/drivers/pwm/PWMTimerCC32XX.c @@ -0,0 +1,728 @@ +/* + * Copyright (c) 2015-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * By default disable both asserts and log for this module. + * This must be done before DebugP.h is included. + */ +#ifndef DebugP_ASSERT_ENABLED +#define DebugP_ASSERT_ENABLED 0 +#endif +#ifndef DebugP_LOG_ENABLED +#define DebugP_LOG_ENABLED 0 +#endif + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PAD_CONFIG_BASE (OCP_SHARED_BASE + OCP_SHARED_O_GPIO_PAD_CONFIG_0) +#define PAD_RESET_STATE 0xC61 + +void PWMTimerCC32XX_close(PWM_Handle handle); +int_fast16_t PWMTimerCC32XX_control(PWM_Handle handle, uint_fast16_t cmd, + void *arg); +void PWMTimerCC32XX_init(PWM_Handle handle); +PWM_Handle PWMTimerCC32XX_open(PWM_Handle handle, PWM_Params *params); +int_fast16_t PWMTimerCC32XX_setDuty(PWM_Handle handle, uint32_t dutyValue); +int_fast16_t PWMTimerCC32XX_setPeriod(PWM_Handle handle, uint32_t periodValue); +void PWMTimerCC32XX_start(PWM_Handle handle); +void PWMTimerCC32XX_stop(PWM_Handle handle); + +/* PWM function table for PWMTimerCC32XX implementation */ +const PWM_FxnTable PWMTimerCC32XX_fxnTable = { + PWMTimerCC32XX_close, + PWMTimerCC32XX_control, + PWMTimerCC32XX_init, + PWMTimerCC32XX_open, + PWMTimerCC32XX_setDuty, + PWMTimerCC32XX_setPeriod, + PWMTimerCC32XX_start, + PWMTimerCC32XX_stop +}; + +/* + * Internal value to notify an error has occurred while calculating a duty + * or period. + */ +static const uint32_t PWM_INVALID_VALUE = (~0); + +/* + * GPT peripheral load & match registers are 16 bits wide. Max value which + * can be set is 65535. + */ +static const uint16_t PWM_MAX_MATCH_REG_VALUE = (~0); + +/* + * GPT peripherals have 24 bit resolution. The max period value which be + * set is 16777215. + */ +static const uint32_t PWM_MAX_PERIOD_COUNT = (0xFFFFFF); + +/* + * The following fields are used by CC32XX driverlib APIs and therefore + * must be populated by driverlib macro definitions. For CC32XX driverlib + * these definitions are found in: + * - inc/hw_memmap.h + * - driverlib/gpio.h + * - driverlib/pin.h + * - driverlib/timer.h + */ +static const uint32_t timerBaseAddresses[4] = { + TIMERA0_BASE, + TIMERA1_BASE, + TIMERA2_BASE, + TIMERA3_BASE, +}; + +static const uint32_t timerHalves[2] = { + TIMER_A, + TIMER_B, +}; + +static const uint32_t gpioBaseAddresses[4] = { + GPIOA0_BASE, + GPIOA1_BASE, + GPIOA2_BASE, + GPIOA3_BASE, +}; + +static const uint32_t gpioPinIndexes[8] = { + GPIO_PIN_0, + GPIO_PIN_1, + GPIO_PIN_2, + GPIO_PIN_3, + GPIO_PIN_4, + GPIO_PIN_5, + GPIO_PIN_6, + GPIO_PIN_7, +}; + +#define PinConfigTimerPort(config) (((config) >> 28) & 0xF) +#define PinConfigTimerHalf(config) (((config) >> 24) & 0xF) +#define PinConfigGPIOPort(config) (((config) >> 20) & 0xF) +#define PinConfigGPIOPinIndex(config) (((config) >> 16) & 0xF) +#define PinConfigPinMode(config) (((config) >> 8) & 0xF) +#define PinConfigPin(config) (((config) >> 0) & 0x3F) + +extern uint32_t SystemCoreClock; + +/* + * ======== getDutyCounts ======== + */ +static uint32_t getDutyCounts(PWM_Duty_Units dutyUnits, uint32_t dutyValue, + uint32_t periodCounts) +{ + uint32_t duty = 0; + ClockP_FreqHz freq; + + freq.hi = 0; + freq.lo = SystemCoreClock; + + //ClockP_getCpuFreq(&freq); + + switch (dutyUnits) { + case PWM_DUTY_COUNTS: + duty = dutyValue; + break; + + case PWM_DUTY_FRACTION: + duty = (((uint64_t) dutyValue) * ((uint64_t) periodCounts)) / + PWM_DUTY_FRACTION_MAX; + break; + + case PWM_DUTY_US: + duty = (dutyValue != 0) ? (dutyValue * (freq.lo/1000000)) - 1 : 0; + break; + + default: + /* Unsupported duty units return an invalid duty */ + duty = PWM_INVALID_VALUE; + } + + return (duty); +} + +/* + * ======== getPeriodCounts ======== + */ +static uint32_t getPeriodCounts(PWM_Period_Units periodUnits, + uint32_t periodValue) +{ + uint32_t period = 0; + ClockP_FreqHz freq; + + freq.hi = 0; + freq.lo = SystemCoreClock; + + //ClockP_getCpuFreq(&freq); + + switch (periodUnits) { + case PWM_PERIOD_COUNTS: + period = periodValue; + break; + + case PWM_PERIOD_HZ: + if (periodValue && periodValue <= freq.lo) { + period = (freq.lo / periodValue) - 1; + } + break; + + case PWM_PERIOD_US: + period = (periodValue * (freq.lo/1000000)) - 1; + break; + + default: + /* Unsupported period units return an invalid period */ + period = PWM_INVALID_VALUE; + } + + return (period); +} + +/* + * ======== getPowerMgrId ======== + */ +static uint_fast16_t getPowerMgrId(uint32_t baseAddr) +{ + switch (baseAddr) { + case GPIOA0_BASE: + return (PowerCC32XX_PERIPH_GPIOA0); + case GPIOA1_BASE: + return (PowerCC32XX_PERIPH_GPIOA1); + case GPIOA2_BASE: + return (PowerCC32XX_PERIPH_GPIOA2); + case GPIOA3_BASE: + return (PowerCC32XX_PERIPH_GPIOA3); + case GPIOA4_BASE: + return (PowerCC32XX_PERIPH_GPIOA4); + default: + /* Should never get here */ + return ((unsigned int) -1); + } +} + +/* + * ======== initHw ======== + */ +static int initHw(PWM_Handle handle, uint32_t period, uint32_t duty) +{ + uintptr_t key; + int32_t result; + uint32_t timerConfigVal; + PWMTimerCC32XX_HWAttrsV2 const *hwAttrs = handle->hwAttrs; + uint32_t timerBaseAddr; + uint16_t halfTimer; + + timerBaseAddr = timerBaseAddresses[PinConfigTimerPort(hwAttrs->pwmPin)]; + halfTimer = timerHalves[PinConfigTimerHalf(hwAttrs->pwmPin)]; + + key = HwiP_disable(); + + MAP_TimerDisable(timerBaseAddr, halfTimer); + + /* + * The CC32XX SDK TimerConfigure API halts both timers when it is + * used to configure a single half timer. The code below performs + * the register operations necessary to configure each half timer + * individually. + */ + /* Enable CCP to IO path */ + HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_GPT_TRIG_SEL) = 0xFF; + + /* Split the timer and configure it as a PWM */ + timerConfigVal = ((halfTimer & (TIMER_CFG_A_PWM | TIMER_CFG_B_PWM)) | + TIMER_CFG_SPLIT_PAIR); + HWREG(timerBaseAddr + TIMER_O_CFG) |= (timerConfigVal >> 24); + if (halfTimer & TIMER_A) { + HWREG(timerBaseAddr + TIMER_O_TAMR) = timerConfigVal & 255; + } + else { + HWREG(timerBaseAddr + TIMER_O_TBMR) = (timerConfigVal >> 8) & 255; + } + + /* Set the peripheral output to active-high */ + MAP_TimerControlLevel(timerBaseAddr, halfTimer, true); + + HwiP_restore(key); + + result = PWMTimerCC32XX_setPeriod(handle, period); + if (result != PWM_STATUS_SUCCESS) { + return (result); + } + + result = PWMTimerCC32XX_setDuty(handle, duty); + if (result != PWM_STATUS_SUCCESS) { + return (result); + } + + return (PWM_STATUS_SUCCESS); +} + +/* + * ======== postNotifyFxn ======== + * Called by Power module when waking up from LPDS. + */ +static int postNotifyFxn(unsigned int eventType, uintptr_t eventArg, + uintptr_t clientArg) +{ + PWM_Handle handle = (PWM_Handle) clientArg; + PWMTimerCC32XX_Object *object = handle->object; + + initHw(handle, object->period, object->duty); + + return (Power_NOTIFYDONE); +} + +/* + * ======== PWMTimerCC32XX_close ======== + * @pre Function assumes that the handle is not NULL + */ +void PWMTimerCC32XX_close(PWM_Handle handle) +{ + PWMTimerCC32XX_Object *object = handle->object; + PWMTimerCC32XX_HWAttrsV2 const *hwAttrs = handle->hwAttrs; + TimerCC32XX_SubTimer subTimer; + uint32_t timerBaseAddr; + uint32_t gpioBaseAddr; + uint32_t padRegister; + uintptr_t key; + + timerBaseAddr = timerBaseAddresses[PinConfigTimerPort(hwAttrs->pwmPin)]; + + subTimer = (TimerCC32XX_SubTimer) (TimerCC32XX_timer16A + + PinConfigTimerHalf(hwAttrs->pwmPin)); + + /* + * Some PWM pins may not have GPIO capability; in these cases gpioBaseAddr + * is set to 0 & the GPIO power dependencies are not released. + */ + gpioBaseAddr = (PinConfigGPIOPort(hwAttrs->pwmPin) == 0xF) ? + 0 : gpioBaseAddresses[PinConfigGPIOPort(hwAttrs->pwmPin)]; + + PWMTimerCC32XX_stop(handle); + + key = HwiP_disable(); + + TimerCC32XX_freeTimerResource(timerBaseAddr, subTimer); + + /* Remove GPIO power dependency if pin is GPIO capable */ + if (gpioBaseAddr) { + Power_releaseDependency(getPowerMgrId(gpioBaseAddr)); + } + + Power_unregisterNotify(&object->postNotify); + + padRegister = (PinToPadGet((hwAttrs->pwmPin) & 0x3f)<<2) + PAD_CONFIG_BASE; + HWREG(padRegister) = PAD_RESET_STATE; + + object->isOpen = false; + + HwiP_restore(key); + + DebugP_log1("PWM:(%p) is closed", (uintptr_t) handle); +} + +/* + * ======== PWMTimerCC32XX_control ======== + * @pre Function assumes that the handle is not NULL + */ +int_fast16_t PWMTimerCC32XX_control(PWM_Handle handle, uint_fast16_t cmd, + void *arg) +{ + /* No implementation yet */ + return (PWM_STATUS_UNDEFINEDCMD); +} + +/* + * ======== PWMTimerCC32XX_init ======== + * @pre Function assumes that the handle is not NULL + */ +void PWMTimerCC32XX_init(PWM_Handle handle) +{ +} + +/* + * ======== PWMTimerCC32XX_open ======== + * @pre Function assumes that the handle is not NULL + */ +PWM_Handle PWMTimerCC32XX_open(PWM_Handle handle, PWM_Params *params) +{ + uintptr_t key; + PWMTimerCC32XX_Object *object = handle->object; + PWMTimerCC32XX_HWAttrsV2 const *hwAttrs = handle->hwAttrs; + TimerCC32XX_SubTimer subTimer; + uint32_t timerBaseAddr; + uint32_t gpioBaseAddr; + uint16_t pin; + + timerBaseAddr = timerBaseAddresses[PinConfigTimerPort(hwAttrs->pwmPin)]; + pin = PinConfigPin(hwAttrs->pwmPin); + + subTimer = (TimerCC32XX_SubTimer) (TimerCC32XX_timer16A + + PinConfigTimerHalf(hwAttrs->pwmPin)); + + key = HwiP_disable(); + + if (object->isOpen) { + HwiP_restore(key); + + DebugP_log1("PWM:(%p) already opened.", (uintptr_t) handle); + + return (NULL); + } + + if (!TimerCC32XX_allocateTimerResource(timerBaseAddr, subTimer)) { + HwiP_restore(key); + + DebugP_log1("Timer: 0x%X unavailable.", timerBaseAddr); + + return (NULL); + } + + object->isOpen = true; + + HwiP_restore(key); + + /* + * Some PWM pins may not have GPIO capability; in these cases gpioBaseAddr + * is set to 0 & the GPIO power dependencies are not set. + */ + gpioBaseAddr = (PinConfigGPIOPort(hwAttrs->pwmPin) == 0xF) ? + 0 : gpioBaseAddresses[PinConfigGPIOPort(hwAttrs->pwmPin)]; + + /* Set GPIO power dependency if pin is GPIO capable */ + if (gpioBaseAddr) { + /* Check GPIO power resource Id */ + if (getPowerMgrId(gpioBaseAddr) == ((unsigned int) -1)) { + TimerCC32XX_freeTimerResource(timerBaseAddr, subTimer); + + object->isOpen = false; + + DebugP_log1("PWM:(%p) Failed to determine GPIO power resource ID.", + (uintptr_t) handle); + + return (NULL); + } + + /* Register power dependency for GPIO port */ + Power_setDependency(getPowerMgrId(gpioBaseAddr)); + } + + Power_registerNotify(&object->postNotify, PowerCC32XX_AWAKE_LPDS, + postNotifyFxn, (uintptr_t) handle); + + /* + * Set PWM duty to initial value (not 0) - required when inverting + * output polarity to generate a duty equal to 0 or period. See comments in + * PWMTimerCC32XX_setDuty for more information. + */ + object->duty = 0; + object->period = 0; + object->dutyUnits = params->dutyUnits; + object->idleLevel = params->idleLevel; + object->periodUnits = params->periodUnits; + object->pwmStarted = 0; + + /* Initialize the peripheral & set the period & duty */ + if (initHw(handle, params->periodValue, params->dutyValue) != + PWM_STATUS_SUCCESS) { + PWMTimerCC32XX_close(handle); + + DebugP_log1("PWM:(%p) Failed set initial PWM configuration.", + (uintptr_t) handle); + + return (NULL); + } + + /* Configure the Power_pinParkState based on idleLevel param */ + PowerCC32XX_setParkState((PowerCC32XX_Pin) pin, + (object->idleLevel == PWM_IDLE_HIGH)); + + /* Called to set the initial idleLevel */ + PWMTimerCC32XX_stop(handle); + + DebugP_log3("PWM:(%p) opened; period set to: %d; duty set to: %d", + (uintptr_t) handle, params->periodValue, params->dutyValue); + + return (handle); +} + +/* + * ======== PWMTimerCC32XX_setDuty ======== + * @pre Function assumes that handle is not NULL + */ +int_fast16_t PWMTimerCC32XX_setDuty(PWM_Handle handle, uint32_t dutyValue) +{ + uintptr_t key; + uint32_t duty; + uint32_t period; + PWMTimerCC32XX_Object *object = handle->object; + PWMTimerCC32XX_HWAttrsV2 const *hwAttrs = handle->hwAttrs; + uint32_t timerBaseAddr; + uint16_t halfTimer; + + timerBaseAddr = timerBaseAddresses[PinConfigTimerPort(hwAttrs->pwmPin)]; + halfTimer = timerHalves[PinConfigTimerHalf(hwAttrs->pwmPin)]; + + key = HwiP_disable(); + + period = object->period; + duty = getDutyCounts(object->dutyUnits, dutyValue, period); + + if (duty == PWM_INVALID_VALUE) { + HwiP_restore(key); + + DebugP_log1("PWM:(%p) duty units could not be determined.", + (uintptr_t) handle); + + return (PWM_STATUS_ERROR); + } + + if (duty > period) { + HwiP_restore(key); + + DebugP_log1("PWM:(%p) duty is out of range.", (uintptr_t) handle); + + return (PWM_STATUS_INVALID_DUTY); + } + + /* + * The timer peripheral cannot generate a duty equal to the period when + * the timer is counting down. In these cases the PWM duty is set to the + * period value (output remains low) and output polarity is inverted. + * Additionally, if the output is changed from the period the PWM output + * polarity must be inverted again. + * + * The code below uses the previous duty (object->duty) and the new duty to + * determine if the polarity should be inverted. + * For more details refer to the device specific datasheet and the following + * E2E post: + * http://e2e.ti.com/support/microcontrollers/tiva_arm/f/908/t/354826.aspx + */ + if (((duty == period) && (object->duty != period)) || + ((duty != period) && (object->duty == period))) { + HWREG(timerBaseAddr + TIMER_O_CTL) ^= + (halfTimer & (TIMER_CTL_TAPWML | TIMER_CTL_TBPWML)); + } + + /* + * Set & store the new duty. IMPORTANT: this must be saved after output + * inversion is determined and before the duty = 0 corner case. + */ + object->duty = duty; + + /* + * Special corner case, if duty is 0 we set it to the period without + * inverting output + */ + if (duty == 0) { + duty = period; + } + + MAP_TimerPrescaleMatchSet(timerBaseAddr, halfTimer, + duty / PWM_MAX_MATCH_REG_VALUE); + MAP_TimerMatchSet(timerBaseAddr, halfTimer, + duty % PWM_MAX_MATCH_REG_VALUE); + + HwiP_restore(key); + + DebugP_log2("PWM:(%p) duty set to: %d", (uintptr_t) handle, dutyValue); + + return (PWM_STATUS_SUCCESS); +} + +/* + * ======== PWMTimerCC32XX_setPeriod ======== + * @pre Function assumes that handle is not NULL + */ +int_fast16_t PWMTimerCC32XX_setPeriod(PWM_Handle handle, uint32_t periodValue) +{ + uintptr_t key; + uint32_t duty; + uint32_t period; + PWMTimerCC32XX_Object *object = handle->object; + PWMTimerCC32XX_HWAttrsV2 const *hwAttrs = handle->hwAttrs; + uint32_t timerBaseAddr; + uint16_t halfTimer; + + timerBaseAddr = timerBaseAddresses[PinConfigTimerPort(hwAttrs->pwmPin)]; + halfTimer = timerHalves[PinConfigTimerHalf(hwAttrs->pwmPin)]; + + key = HwiP_disable(); + + duty = object->duty; + period = getPeriodCounts(object->periodUnits, periodValue); + + if (period == PWM_INVALID_VALUE) { + HwiP_restore(key); + + DebugP_log1("PWM:(%p) period units could not be determined.", + (uintptr_t) handle); + + return (PWM_STATUS_ERROR); + } + + if ((period == 0) || (period <= duty) || (period > PWM_MAX_PERIOD_COUNT)) { + HwiP_restore(key); + + DebugP_log1("PWM:(%p) period is out of range.", (uintptr_t) handle); + + return (PWM_STATUS_INVALID_PERIOD); + } + + /* Set the new period */ + object->period = period; + MAP_TimerPrescaleSet(timerBaseAddr, halfTimer, + period / PWM_MAX_MATCH_REG_VALUE); + MAP_TimerLoadSet(timerBaseAddr, halfTimer, + period % PWM_MAX_MATCH_REG_VALUE); + + HwiP_restore(key); + + DebugP_log2("PWM:(%p) period set to: %d", (uintptr_t) handle, periodValue); + + return (PWM_STATUS_SUCCESS); +} + +/* + * ======== PWMTimerCC32XX_start ======== + * @pre Function assumes that handle is not NULL + */ +void PWMTimerCC32XX_start(PWM_Handle handle) +{ + uintptr_t key; + PWMTimerCC32XX_Object *object = handle->object; + PWMTimerCC32XX_HWAttrsV2 const *hwAttrs = handle->hwAttrs; + uint32_t timerBaseAddr; + uint16_t halfTimer; + uint16_t pin; + uint16_t mode; + + timerBaseAddr = timerBaseAddresses[PinConfigTimerPort(hwAttrs->pwmPin)]; + halfTimer = timerHalves[PinConfigTimerHalf(hwAttrs->pwmPin)]; + pin = PinConfigPin(hwAttrs->pwmPin); + mode = PinConfigPinMode(hwAttrs->pwmPin); + + key = HwiP_disable(); + + /* + * GP timer ticks only in Active mode. Cannot be used in HIB or LPDS. + * Set constraint to disallow LPDS. + */ + if (!(object->pwmStarted)) { + Power_setConstraint(PowerCC32XX_DISALLOW_LPDS); + object->pwmStarted = true; + } + + /* Start the timer & set pinmux to PWM mode */ + MAP_TimerEnable(timerBaseAddr, halfTimer); + + MAP_PinTypeTimer((unsigned long)pin, (unsigned long)mode); + + HwiP_restore(key); + + DebugP_log1("PWM:(%p) started.", (uintptr_t) handle); +} + +/* + * ======== PWMTimerCC32XX_stop ======== + * @pre Function assumes that handle is not NULL + */ +void PWMTimerCC32XX_stop(PWM_Handle handle) +{ + uintptr_t key; + uint8_t output; + PWMTimerCC32XX_Object *object = handle->object; + PWMTimerCC32XX_HWAttrsV2 const *hwAttrs = handle->hwAttrs; + uint32_t timerBaseAddr; + uint16_t halfTimer; + uint32_t gpioBaseAddr; + uint8_t gpioPinIndex; + uint16_t pin; + + timerBaseAddr = timerBaseAddresses[PinConfigTimerPort(hwAttrs->pwmPin)]; + halfTimer = timerHalves[PinConfigTimerHalf(hwAttrs->pwmPin)]; + pin = PinConfigPin(hwAttrs->pwmPin); + + /* + * Some PWM pins may not have GPIO capability; in these cases gpioBaseAddr + * is set to 0 & the GPIO power dependencies are not set. + */ + gpioBaseAddr = (PinConfigGPIOPort(hwAttrs->pwmPin) == 0xF) ? + 0 : gpioBaseAddresses[PinConfigGPIOPort(hwAttrs->pwmPin)]; + gpioPinIndex = (PinConfigGPIOPinIndex(hwAttrs->pwmPin) == 0xF) ? + 0 : gpioPinIndexes[PinConfigGPIOPinIndex(hwAttrs->pwmPin)]; + + key = HwiP_disable(); + + /* Remove the dependency to allow LPDS */ + if (object->pwmStarted) { + Power_releaseConstraint(PowerCC32XX_DISALLOW_LPDS); + object->pwmStarted = false; + } + + /* Set pin as GPIO with IdleLevel value & stop the timer */ + output = (object->idleLevel) ? gpioPinIndex : 0; + MAP_PinTypeGPIO((unsigned long)pin, PIN_MODE_0, false); + + /* Only configure the pin as GPIO if the pin is GPIO capable */ + if (gpioBaseAddr) { + MAP_GPIODirModeSet(gpioBaseAddr, gpioPinIndex, GPIO_DIR_MODE_OUT); + MAP_GPIOPinWrite(gpioBaseAddr, gpioPinIndex, output); + } + + /* Stop the Timer */ + MAP_TimerDisable(timerBaseAddr, halfTimer); + + HwiP_restore(key); + + DebugP_log1("PWM:(%p) stopped.", (uintptr_t) handle); +} diff --git a/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/ti/drivers/pwm/PWMTimerCC32XX.h b/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/ti/drivers/pwm/PWMTimerCC32XX.h new file mode 100644 index 0000000000..18601e5d16 --- /dev/null +++ b/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/ti/drivers/pwm/PWMTimerCC32XX.h @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2015-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*! ============================================================================ + * @file PWMTimerCC32XX.h + * + * @brief PWM driver implementation using CC32XX General Purpose Timers. + * + * The PWM header file should be included in an application as follows: + * @code + * #include + * #include + * @endcode + * + * Refer to @ref PWM.h for a complete description of the PWM + * driver APIs provided and examples of their use. + * + * ## Overview # + * This driver configures a CC32XX General Purpose Timer (GPT) in PWM mode. + * When in PWM mode, each GPT is divided into 2 PWM outputs. This driver + * manages each output as an independent PWM instance. The timer is + * automatically configured in count-down mode using the system clock as + * the source. + * + * The timers operate at the system clock frequency (80 MHz). So each timer + * tick is 12.5 ns. The period and duty registers are 16 bits wide; thus + * 8-bit prescalars are used to extend period and duty registers. The + * maximum value supported is 16777215 timer counts ((2^24) - 1) or + * 209715 microseconds. Updates to a PWM's period or duty will occur + * instantaneously (GPT peripherals do not have shadow registers). + * + * When stopped, the driver will configure the pin in GPIO mode & set the + * output to the PWM_IdleLevel specified in the params used during open. Users + * need be aware that while PIN 19 can be used for PWM it is not GPIO capable, + * so it cannot be set to the PWM_IdleLevel. Output voltage will be PWM output + * at the moment it is stopped. + * + * Finally, when this driver is opened, it automatically changes the + * PWM pin's parking configuration (used when entering low power modes) to + * correspond with the PWM_IDLE_LEVEL set in the PWM_params. However, this + * setting is not reverted once the driver is closed, it is the users + * responsibility to change the parking configuration if necessary. + * + * ### CC32xx PWM Driver Configuration # + * + * In order to use the PWM APIs, the application is required + * to define 4 configuration items in the application Board.c file: + * + * 1. An array of PWMTimerCC32XX_Object elements, which will be used by + * by the driver to maintain instance state. + * Below is an example PWMTimerCC32XX_Object array appropriate for the CC3220SF Launchpad + * board: + * @code + * #include + * #include + * + * PWMTimerCC32XX_Object pwmTimerCC3220SObjects[CC3220SF_LAUNCHXL_PWMCOUNT]; + * @endcode + * + * 2. An array of PWMTimerCC32XX_HWAttrsV2 elements that defines which + * pin will be used by the corresponding PWM instance + * (see @ref pwmPinIdentifiersCC32XX). + * Below is an example PWMTimerCC32XX_HWAttrsV2 array appropriate for the CC3220SF Launchpad + * board: + * @code + * const PWMTimerCC32XX_HWAttrsV2 pwmTimerCC3220SHWAttrs[CC3220SF_LAUNCHXL_PWMCOUNT] = { + * { + * .pwmPin = PWMTimerCC32XX_PIN_01 + * }, + * { + * .pwmPin = PWMTimerCC32XX_PIN_02 + * } + * }; + * @endcode + * + * 3. An array of @ref PWM_Config elements, one for each PWM instance. Each + * element of this array identifies the device-specific API function table, + * the device specific PWM object instance, and the device specific Hardware + * Attributes to be used for each PWM channel. + * Below is an example @ref PWM_Config array appropriate for the CC3220SF Launchpad + * board: + * @code + * const PWM_Config PWM_config[CC3220SF_LAUNCHXL_PWMCOUNT] = { + * { + * .fxnTablePtr = &PWMTimerCC32XX_fxnTable, + * .object = &pwmTimerCC3220SObjects[CC3220SF_LAUNCHXL_PWM6], + * .hwAttrs = &pwmTimerCC3220SHWAttrs[CC3220SF_LAUNCHXL_PWM6] + * }, + * { + * .fxnTablePtr = &PWMTimerCC32XX_fxnTable, + * .object = &pwmTimerCC3220SObjects[CC3220SF_LAUNCHXL_PWM7], + * .hwAttrs = &pwmTimerCC3220SHWAttrs[CC3220SF_LAUNCHXL_PWM7] + * } + * }; + * @endcode + * + * 4. A global variable, PWM_count, that informs the driver how many PWM + * instances are defined: + * @code + * const uint_least8_t PWM_count = CC3220SF_LAUNCHXL_PWMCOUNT; + * @endcode + * + * ### Power Management # + * The TI-RTOS power management framework will try to put the device into the most + * power efficient mode whenever possible. Please see the technical reference + * manual for further details on each power mode. + * + * The PWMTimerCC32XX driver explicitly sets a power constraint when the + * PWM is running to prevent LPDS. + * The following statements are valid: + * - After PWM_open(): Clocks are enabled to the timer resource and the + * configured pwmPin. The device is still allowed + * to enter LPDS. + * - After PWM_start(): LPDS is disabled when PWM is running. + * - After PWM_stop(): Conditions are equal as for after PWM_open + * - After PWM_close(): The underlying GPTimer is turned off, and the clocks + * to the timer and pin are disabled.. + * + * ============================================================================= + */ + +#ifndef ti_driver_pwm_PWMTimerCC32XX__include +#define ti_driver_pwm_PWMTimerCC32XX__include + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/*! \cond */ +/* + * PWMTimer port/pin defines for pin configuration. + * + * The timer id (0, 1, 2, or 3) is stored in bits 31 - 28 + * The timer half (0 = A, 1 = B) is stored in bits 27 - 24 + * The GPIO port (0, 1, 2, or 3) is stored in bits 23 - 20 + * The GPIO pin index within the port (0 - 7) is stored in bits 19 - 16 + * The pin mode is stored in bits 11 - 8 + * The pin number is stored in bits 7 - 0 + * + * + * 31 - 28 27 - 24 23 - 20 19 - 16 11 - 8 7 - 0 + * ----------------------------------------------------------------------- + * | Timer id | Timer half | GPIO port | GPIO pin index | pin mode | pin | + * ----------------------------------------------------------------------- + * + * The CC32XX has fixed GPIO assignments and pin modes for a given pin. + * A PWM pin mode for a given pin has a fixed timer/timer-half. + */ +#define PWMTimerCC32XX_T0A (0x00 << 24) +#define PWMTimerCC32XX_T0B (0x01 << 24) +#define PWMTimerCC32XX_T1A (0x10 << 24) +#define PWMTimerCC32XX_T1B (0x11 << 24) +#define PWMTimerCC32XX_T2A (0x20 << 24) +#define PWMTimerCC32XX_T2B (0x21 << 24) +#define PWMTimerCC32XX_T3A (0x30 << 24) +#define PWMTimerCC32XX_T3B (0x31 << 24) + +#define PWMTimerCC32XX_GPIO9 (0x11 << 16) +#define PWMTimerCC32XX_GPIO10 (0x12 << 16) +#define PWMTimerCC32XX_GPIO11 (0x13 << 16) +#define PWMTimerCC32XX_GPIO24 (0x30 << 16) +#define PWMTimerCC32XX_GPIO25 (0x31 << 16) + +#define PWMTimerCC32XX_GPIONONE (0xFF << 16) +/*! \endcond */ + +/*! + * \defgroup pwmPinIdentifiersCC32XX PWMTimerCC32XX_HWAttrs 'pwmPin' field options + * @{ + */ +/*! + * @name PIN 01, GPIO10, uses Timer3A for PWM. + * @{ + */ +#define PWMTimerCC32XX_PIN_01 (PWMTimerCC32XX_T3A | PWMTimerCC32XX_GPIO10 | 0x0300) /*!< @hideinitializer */ +/*! @} */ +/*! + * @name PIN 02, GPIO11, uses Timer3B for PWM. + * @{ + */ +#define PWMTimerCC32XX_PIN_02 (PWMTimerCC32XX_T3B | PWMTimerCC32XX_GPIO11 | 0x0301) /*!< @hideinitializer */ +/*! @} */ +/*! + * @name PIN 17, GPIO24, uses Timer0A for PWM. + * @{ + */ +#define PWMTimerCC32XX_PIN_17 (PWMTimerCC32XX_T0A | PWMTimerCC32XX_GPIO24 | 0x0510) /*!< @hideinitializer */ +/*! @} */ +/*! + * @name PIN 19, uses Timer1B for PWM. + * @{ + */ +#define PWMTimerCC32XX_PIN_19 (PWMTimerCC32XX_T1B | PWMTimerCC32XX_GPIONONE | 0x0812) /*!< @hideinitializer */ +/*! @} */ +/*! + * @name PIN 21, GPIO25, uses Timer1A for PWM. + * @{ + */ +#define PWMTimerCC32XX_PIN_21 (PWMTimerCC32XX_T1A | PWMTimerCC32XX_GPIO25 | 0x0914) /*!< @hideinitializer */ +/*! @} */ +/*! + * @name PIN 64, GPIO9, uses Timer2B for PWM. + * @{ + */ +#define PWMTimerCC32XX_PIN_64 (PWMTimerCC32XX_T2B | PWMTimerCC32XX_GPIO9 | 0x033F) /*!< @hideinitializer */ +/*! @} */ +/*! @} */ + +/** + * @addtogroup PWM_STATUS + * PWMTimerCC32XX_STATUS_* macros are command codes only defined in the + * PWMTimerCC32XX.h driver implementation and need to: + * @code + * #include + * @endcode + * @{ + */ + +/* Add PWMTimerCC32XX_STATUS_* macros here */ + +/** @}*/ + +/** + * @addtogroup PWM_CMD + * PWMTimerCC32XX_CMD_* macros are command codes only defined in the + * PWMTimerCC32XX.h driver implementation and need to: + * @code + * #include + * @endcode + * @{ + */ + +/* Add PWMTimerCC32XX_CMD_* macros here */ + +/** @}*/ + +/* PWM function table pointer */ +extern const PWM_FxnTable PWMTimerCC32XX_fxnTable; + +/*! + * @brief PWMTimerCC32XX Hardware attributes + * + * The 'pwmPin' field identifies which physical pin to use for a + * particular PWM channel as well as the corresponding Timer resource used + * to source the PWM signal. The encoded pin identifier macros for + * initializing the 'pwmPin' field must be selected from the + * @ref pwmPinIdentifiersCC32XX macros. + * + * A sample structure is shown below: + * @code + * const PWMTimerCC32XX_HWAttrsV2 pwmTimerCC32XXHWAttrs[] = { + * { + * .pwmPin = PWMTimerCC32XX_PIN_01, + * }, + * { + * .pwmPin = PWMTimerCC32XX_PIN_02, + * } + * }; + * @endcode + */ +typedef struct PWMTimerCC32XX_HWAttrsV2 { + uint32_t pwmPin; /*!< Pin to output PWM signal on + (see @ref pwmPinIdentifiersCC32XX) */ +} PWMTimerCC32XX_HWAttrsV2; + +/*! + * @brief PWMTimerCC32XX Object + * + * The application must not access any member variables of this structure! + */ +typedef struct PWMTimerCC32XX_Object { + Power_NotifyObj postNotify; + uint32_t duty; /* Current duty cycle in Duty_Unites */ + uint32_t period; /* Current period PERIOD_Units */ + PWM_Duty_Units dutyUnits; /* Current duty cycle unit */ + PWM_Period_Units periodUnits; /* Current period unit */ + PWM_IdleLevel idleLevel; /* PWM idle level when stopped / not started */ + bool pwmStarted; /* Used to gate Power_set/releaseConstraint() calls */ + bool isOpen; /* open flag used to check if PWM is opened */ +} PWMTimerCC32XX_Object; + +#ifdef __cplusplus +} +#endif + +#endif /* ti_driver_pwm_PWMTimerCC32XX__include */ diff --git a/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/ti/drivers/timer/TimerCC32XX.c b/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/ti/drivers/timer/TimerCC32XX.c new file mode 100644 index 0000000000..9abfbda61e --- /dev/null +++ b/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/ti/drivers/timer/TimerCC32XX.c @@ -0,0 +1,605 @@ +/* + * Copyright (c) 2017-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +/* + * This macro is used to determine a logical shift value for the + * timerState.bitMask. Each timer peripheral occupies two bits in + * timerState.bitMask. + * + * The timer peripherals' base addresses have an offset of 0x1000 starting at + * 0x40030000. That byte is masked using 0xF000 which can result in a value + * ranging from 0x0000 to 0x3000 for this particular hardware instance. This + * value is then shifted right by 12 into the LSB. Lastly, the value is + * multiplied by two because there are two bits in the timerState.bitMask for + * each timer. The value returned is used for the logical shift. + */ +#define timerMaskShift(baseAddress) ((((baseAddress) & 0XF000) >> 12) * 2) + +void TimerCC32XX_close(Timer_Handle handle); +int_fast16_t TimerCC32XX_control(Timer_Handle handle, + uint_fast16_t cmd, void *arg); +uint32_t TimerCC32XX_getCount(Timer_Handle handle); +void TimerCC32XX_init(Timer_Handle handle); +Timer_Handle TimerCC32XX_open(Timer_Handle handle, Timer_Params *params); +int32_t TimerCC32XX_start(Timer_Handle handle); +void TimerCC32XX_stop(Timer_Handle handle); + +/* Internal static Functions */ +static void initHw(Timer_Handle handle); +static void getPrescaler(Timer_Handle handle); +static uint32_t getPowerMgrId(uint32_t baseAddress); +static int postNotifyFxn(unsigned int eventType, uintptr_t eventArg, + uintptr_t clientArg); +static void TimerCC32XX_hwiIntFunction(uintptr_t arg); + +/* Function table for TimerCC32XX implementation */ +const Timer_FxnTable TimerCC32XX_fxnTable = { + .closeFxn = TimerCC32XX_close, + .openFxn = TimerCC32XX_open, + .startFxn = TimerCC32XX_start, + .stopFxn = TimerCC32XX_stop, + .initFxn = TimerCC32XX_init, + .getCountFxn = TimerCC32XX_getCount, + .controlFxn = TimerCC32XX_control +}; + +/* + * Internal Timer status structure + * + * bitMask: Each timer peripheral occupies two bits in the bitMask. The least + * significant bit represents the first half width timer, TimerCC32XX_timer16A + * and the most significant bit represents the second half width timer, + * TimerCC32XX_timer16B. If the full width timer, TimerCC32XX_timer32, is used, + * both bits are set to 1. + + * 31 - 8 7 - 6 5 - 4 3 - 2 1 - 0 + * ------------------------------------------------ + * | Reserved | Timer3 | Timer2 | Timer1 | Timer0 | + * ------------------------------------------------ + */ +static struct { + uint32_t bitMask; +} timerState; + +/* + * ======== initHw ======== + */ +static void initHw(Timer_Handle handle) +{ + TimerCC32XX_HWAttrs const *hwAttrs = handle->hwAttrs; + TimerCC32XX_Object const *object = handle->object; + + /* Ensure the timer is disabled */ + TimerDisable(hwAttrs->baseAddress, object->timer); + + if (object->timer == TIMER_A) { + + HWREG(hwAttrs->baseAddress + TIMER_O_TAMR) = TIMER_TAMR_TAMR_PERIOD; + } + else { + + HWREG(hwAttrs->baseAddress + TIMER_O_TBMR) = TIMER_TBMR_TBMR_PERIOD; + } + + if (hwAttrs->subTimer == TimerCC32XX_timer32) { + + HWREG(hwAttrs->baseAddress + TIMER_O_CFG) = TIMER_CFG_32_BIT_TIMER; + } + else { + + HWREG(hwAttrs->baseAddress + TIMER_O_CFG) = TIMER_CFG_16_BIT; + } + + /* Disable all interrupts */ + HWREG(hwAttrs->baseAddress + TIMER_O_IMR) = ~object->timer; + + /* Writing the PSR Register has no effect for full width 32-bit mode */ + TimerPrescaleSet(hwAttrs->baseAddress, object->timer, object->prescaler); + TimerLoadSet(hwAttrs->baseAddress, object->timer, object->period); + + /* This function controls the stall response for the timer. When true, + * the timer stops counting if the processor enters debug mode. The + * default setting for the hardware is false. + */ + TimerControlStall(hwAttrs->baseAddress, object->timer, true); +} + +/* + * ========= getPrescaler ========= + * This function calculates the prescaler and timer interval load register + * for a half timer. The handle is assumed to contain a object->period which + * represents the number of clock cycles in the desired period. The calling + * function, TimerCC32XX_open() checks for overflow before calling this function. + * Therefore, this function is guaranteed to never fail. + */ +static void getPrescaler(Timer_Handle handle) +{ + TimerCC32XX_Object *object = handle->object; + uint32_t bestDiff = ~0, bestPsr = 0, bestIload = 0; + uint32_t diff, intervalLoad, prescaler; + + /* Loop over the 8-bit prescaler */ + for (prescaler = 1; prescaler < 256; prescaler++) { + + /* Calculate timer interval load */ + intervalLoad = object->period / (prescaler + 1); + + /* Will this fit in 16-bits? */ + if (intervalLoad > (uint16_t) ~0) { + continue; + } + + /* How close is the intervalLoad to what we actually want? */ + diff = object->period - intervalLoad * (prescaler + 1); + + /* If it is closer to what we want */ + if (diff <= bestDiff) { + + /* If its a perfect match */ + if (diff == 0) { + object->period = intervalLoad; + object->prescaler = prescaler; + + return; + } + + /* Snapshot in case we don't find something better */ + bestDiff = diff; + bestPsr = prescaler; + bestIload = intervalLoad; + } + } + + /* Never found a perfect match, settle for the best */ + object->period = bestIload; + object->prescaler = bestPsr; +} + +/* + * ======== getPowerMgrId ======== + */ +static uint32_t getPowerMgrId(uint32_t baseAddress) +{ + switch (baseAddress) { + + case TIMERA0_BASE: + + return (PowerCC32XX_PERIPH_TIMERA0); + + case TIMERA1_BASE: + + return (PowerCC32XX_PERIPH_TIMERA1); + + case TIMERA2_BASE: + + return (PowerCC32XX_PERIPH_TIMERA2); + + case TIMERA3_BASE: + + return (PowerCC32XX_PERIPH_TIMERA3); + + default: + + return ((uint32_t) -1); + } +} + +/* + * ======== postNotifyFxn ======== + * This functions is called when a transition from LPDS mode is made. + * clientArg should be a handle of a previously opened Timer instance. + */ +static int postNotifyFxn(unsigned int eventType, uintptr_t eventArg, + uintptr_t clientArg) +{ + initHw((Timer_Handle) clientArg); + + return (Power_NOTIFYDONE); +} + +/* + * ======== TimerCC32XX_allocateTimerResource ======== + */ +bool TimerCC32XX_allocateTimerResource(uint32_t baseAddress, + TimerCC32XX_SubTimer subTimer) +{ + uintptr_t key; + uint32_t mask; + uint32_t powerMgrId; + bool status; + + powerMgrId = getPowerMgrId(baseAddress); + + if (powerMgrId == (uint32_t) -1) { + + return (false); + } + + mask = subTimer << timerMaskShift(baseAddress); + + key = HwiP_disable(); + + if (timerState.bitMask & mask) { + + status = false; + } + else { + + Power_setDependency(powerMgrId); + timerState.bitMask = timerState.bitMask | mask; + status = true; + } + + HwiP_restore(key); + + return (status); +} + +/* + * ======== TimerCC32XX_close ======== + */ +void TimerCC32XX_close(Timer_Handle handle) +{ + TimerCC32XX_Object *object = handle->object; + TimerCC32XX_HWAttrs const *hwAttrs = handle->hwAttrs; + + /* Stopping the Timer before closing it */ + TimerCC32XX_stop(handle); + + Power_unregisterNotify(&(object->notifyObj)); + + if (object->hwiHandle) { + + HwiP_clearInterrupt(hwAttrs->intNum); + HwiP_delete(object->hwiHandle); + object->hwiHandle = NULL; + } + + if (object->timerSem) { + + SemaphoreP_delete(object->timerSem); + object->timerSem = NULL; + } + + TimerCC32XX_freeTimerResource(hwAttrs->baseAddress, hwAttrs->subTimer); +} + +/* + * ======== TimerCC32XX_control ======== + */ +int_fast16_t TimerCC32XX_control(Timer_Handle handle, + uint_fast16_t cmd, void *arg) +{ + return (Timer_STATUS_UNDEFINEDCMD); +} + +/* + * ======== TimerCC32XX_freeTimerResource ======== + */ +void TimerCC32XX_freeTimerResource(uint32_t baseAddress, + TimerCC32XX_SubTimer subTimer) +{ + uintptr_t key; + uint32_t mask; + + mask = subTimer << timerMaskShift(baseAddress); + + key = HwiP_disable(); + + timerState.bitMask = (timerState.bitMask & ~mask); + + Power_releaseDependency(getPowerMgrId(baseAddress)); + + HwiP_restore(key); +} + +/* + * ======== TimerCC32XX_getCount ======== + */ +uint32_t TimerCC32XX_getCount(Timer_Handle handle) +{ + TimerCC32XX_HWAttrs const *hWAttrs = handle->hwAttrs; + TimerCC32XX_Object const *object = handle->object; + uint32_t count; + + if (object->timer == TIMER_A) { + count = HWREG(hWAttrs->baseAddress + TIMER_O_TAR); + } + else { + count = HWREG(hWAttrs->baseAddress + TIMER_O_TBR); + } + + /* Virtual up counter */ + count = object->period - count; + + return (count); +} + +/* + * ======== TimerCC32XX_hwiIntFunction ======== + */ +void TimerCC32XX_hwiIntFunction(uintptr_t arg) +{ + Timer_Handle handle = (Timer_Handle) arg; + TimerCC32XX_HWAttrs const *hwAttrs = handle->hwAttrs; + TimerCC32XX_Object const *object = handle->object; + uint32_t interruptMask; + + /* Only clear the interrupt for this->object->timer */ + interruptMask = object->timer & (TIMER_TIMA_TIMEOUT | TIMER_TIMB_TIMEOUT); + TimerIntClear(hwAttrs->baseAddress, interruptMask); + + /* Hwi is not created when using Timer_FREE_RUNNING */ + if (object->mode != Timer_CONTINUOUS_CALLBACK) { + TimerCC32XX_stop(handle); + } + + if (object-> mode != Timer_ONESHOT_BLOCKING) { + object->callBack(handle); + } +} + +/* + * ======== TimerCC32XX_init ======== + */ +void TimerCC32XX_init(Timer_Handle handle) +{ + return; +} + +/* + * ======== TimerCC32XX_open ======== + */ +Timer_Handle TimerCC32XX_open(Timer_Handle handle, Timer_Params *params) +{ + TimerCC32XX_Object *object = handle->object; + TimerCC32XX_HWAttrs const *hwAttrs = handle->hwAttrs; + SemaphoreP_Params semParams; + HwiP_Params hwiParams; + ClockP_FreqHz clockFreq; + + /* Check for valid parameters */ + if (((params->timerMode == Timer_ONESHOT_CALLBACK || + params->timerMode == Timer_CONTINUOUS_CALLBACK) && + params->timerCallback == NULL) || + params->period == 0) { + + return (NULL); + } + + if (!TimerCC32XX_allocateTimerResource(hwAttrs->baseAddress, + hwAttrs->subTimer)) { + + return (NULL); + } + + Power_registerNotify(&(object->notifyObj), PowerCC32XX_AWAKE_LPDS, + postNotifyFxn, (uintptr_t) handle); + + object->mode = params->timerMode; + object->isRunning = false; + object->callBack = params->timerCallback; + object->period = params->period; + object->prescaler = 0; + + if (hwAttrs->subTimer == TimerCC32XX_timer16B) { + + object->timer = TIMER_B; + } + else { + + object->timer = TIMER_A; + } + + if (object->mode != Timer_FREE_RUNNING) { + + HwiP_Params_init(&hwiParams); + hwiParams.arg = (uintptr_t) handle; + hwiParams.priority = hwAttrs->intPriority; + object->hwiHandle = HwiP_create(hwAttrs->intNum, + TimerCC32XX_hwiIntFunction, &hwiParams); + + if (object->hwiHandle == NULL) { + + TimerCC32XX_close(handle); + + return (NULL); + } + + } + + /* Creating the semaphore if mode is blocking */ + if (params->timerMode == Timer_ONESHOT_BLOCKING) { + + SemaphoreP_Params_init(&semParams); + semParams.mode = SemaphoreP_Mode_BINARY; + object->timerSem = SemaphoreP_create(0, &semParams); + + if (object->timerSem == NULL) { + + TimerCC32XX_close(handle); + + return (NULL); + } + } + + /* Formality; CC32XX System Clock fixed to 80.0 MHz */ + ClockP_getCpuFreq(&clockFreq); + + if (params->periodUnits == Timer_PERIOD_US) { + + /* Checks if the calculated period will fit in 32-bits */ + if (object->period >= ((uint32_t) ~0) / (clockFreq.lo / 1000000)) { + + TimerCC32XX_close(handle); + + return (NULL); + } + + object->period = object->period * (clockFreq.lo / 1000000); + } + else if (params->periodUnits == Timer_PERIOD_HZ) { + + /* If (object->period) > clockFreq */ + if ((object->period = clockFreq.lo / object->period) == 0) { + + TimerCC32XX_close(handle); + + return (NULL); + } + } + + /* If using a half timer */ + if (hwAttrs->subTimer != TimerCC32XX_timer32) { + + if (object->period > 0xFFFF) { + + /* 24-bit resolution for the half timer */ + if (object->period >= (1 << 24)) { + + TimerCC32XX_close(handle); + + return (NULL); + } + + getPrescaler(handle); + } + } + + initHw(handle); + + return (handle); +} + +/* + * ======== TimerCC32XX_start ======== + */ +int32_t TimerCC32XX_start(Timer_Handle handle) +{ + TimerCC32XX_HWAttrs const *hwAttrs = handle->hwAttrs; + TimerCC32XX_Object *object = handle->object; + uint32_t interruptMask; + uintptr_t key; + + interruptMask = object->timer & (TIMER_TIMB_TIMEOUT | TIMER_TIMA_TIMEOUT); + + key = HwiP_disable(); + + if (object->isRunning) { + + HwiP_restore(key); + + return (Timer_STATUS_ERROR); + } + + object->isRunning = true; + + if (object->hwiHandle) { + + TimerIntEnable(hwAttrs->baseAddress, interruptMask); + } + + Power_setConstraint(PowerCC32XX_DISALLOW_LPDS); + + /* Reload the timer */ + if (object->timer == TIMER_A) { + HWREG(hwAttrs->baseAddress + TIMER_O_TAMR) |= TIMER_TAMR_TAILD; + } + else { + HWREG(hwAttrs->baseAddress + TIMER_O_TBMR) |= TIMER_TBMR_TBILD; + } + + TimerEnable(hwAttrs->baseAddress, object->timer); + + HwiP_restore(key); + + if (object->mode == Timer_ONESHOT_BLOCKING) { + + /* Pend forever, ~0 */ + SemaphoreP_pend(object->timerSem, ~0); + } + + return (Timer_STATUS_SUCCESS); +} + +/* + * ======== TimerCC32XX_stop ======== + */ +void TimerCC32XX_stop(Timer_Handle handle) +{ + TimerCC32XX_HWAttrs const *hwAttrs = handle->hwAttrs; + TimerCC32XX_Object *object = handle->object; + uint32_t interruptMask; + uintptr_t key; + bool flag = false; + + interruptMask = object->timer & (TIMER_TIMB_TIMEOUT | TIMER_TIMA_TIMEOUT); + + key = HwiP_disable(); + + if (object->isRunning) { + + object->isRunning = false; + + /* Post the Semaphore when called from the Hwi */ + if (object->mode == Timer_ONESHOT_BLOCKING) { + flag = true; + } + + TimerDisable(hwAttrs->baseAddress, object->timer); + TimerIntDisable(hwAttrs->baseAddress, interruptMask); + Power_releaseConstraint(PowerCC32XX_DISALLOW_LPDS); + } + + HwiP_restore(key); + + if (flag) { + SemaphoreP_post(object->timerSem); + } +} diff --git a/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/ti/drivers/timer/TimerCC32XX.h b/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/ti/drivers/timer/TimerCC32XX.h new file mode 100644 index 0000000000..f8f3a0de91 --- /dev/null +++ b/targets/TARGET_TI/TARGET_CC32XX/TARGET_CC3220SF/ti/drivers/timer/TimerCC32XX.h @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2017-2018, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*!***************************************************************************** + * @file TimerCC32XX.h + * @brief Timer driver interface for CC32XX devices + * + * # Operation # + * This driver implements half and full width general purpose timers for the + * CC32XX device. For CC32XX devices, the system clock is 80 MHz and a 16-bit + * timer has an 8-bit prescaler. The desired period may not always be + * achieved due to hardware limitations, such as the aforementioned. The timer + * resolution is limited to 12.5ns due to the 80 MHz clock. A timer period no + * greater than 209,714us can be achieved when operating in 16-bit mode. + * Similarly, a period no greater than 53,687,090us can be achieved when + * operating in 32-bit mode. The same time constraints apply to the 16-bit + * timer when attempting to use a frequency less than 5 Hertz. For additional + * details, refer to the device's technical reference manual. + * + * The timer always operates in count down mode. When using a half width timer, + * an 8-bit prescaler will be implemented by the driver if necessary. If the + * timer is operating in Timer_FREE_RUNNING, the timer will count down from the + * specified period to 0 before restarting. + * + * When using a half width timer, Timer_getCount() will return the + * value of the counter in bits 15:0 and bits 23:16 will contain the + * current free-running value of the prescaler. Bits 31:24 are always 0. + * When using a full width timer, Timer_getCount() will return the + * the value of the 32-bit timer. + * + * #Timer_ONESHOT_CALLBACK is non-blocking. After Timer_start() is called, + * the calling thread will continue execution. When the timer interrupt + * is triggered, the specified callback function will be called. The timer + * will not generate another interrupt unless Timer_start() is called again. + * Calling Timer_stop() or Timer_close() after Timer_start() but, before the + * timer interrupt, will prevent the specified callback from ever being + * invoked. + * + * #Timer_ONESHOT_BLOCKING is a blocking call. A semaphore is used to block + * the calling thead's execution until the timer generates an interrupt. If + * Timer_stop() is called, the calling thread will become unblocked + * immediately. The behavior of the timer in this mode is similar to a sleep + * function. + * + * #Timer_CONTINUOUS_CALLBACK is non-blocking. After Timer_start() is called, + * the calling thread will continue execution. When the timer interrupt is + * treiggered, the specified callback function will be called. The timer is + * automatically restarted and will continue to periodically generate + * interrupts until Timer_stop() is called. + * + * #Timer_FREE_RUNNING is non-blocking. After Timer_start() is called, + * the calling thread will continue execution. The timer will not + * generate an interrupt in this mode. The timer will count down from the + * specified period until it reaches 0. The timer will automatically reload + * the period and start over. The timer will continue running until + * Timer_stop() is called. + * + * # Resource Allocation # + * Each general purpose timer block contains two timers, Timer A and Timer B, + * that can be configured to operate independently; or concatenated to operate + * as one 32-bit timer. This behavior is managed through a set of resource + * allocation APIs. For example, the TimerCC32XX_allocateTimerResource API + * will allocate a timer for exclusive use. Any attempt to allocate this + * resource in the future will result in a false value being returned from the + * allocation API. To free a timer resource, the TimerCC32XX_freeTimerResource + * is used. The application is not responsible for calling these allocation + * APIs directly. + * + * ============================================================================ + */ + +#ifndef ti_drivers_timer_TimerCC32XX__include +#define ti_drivers_timer_TimerCC32XX__include + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include + +#include +#include +#include +#include + +/*! + * @def TimerCC32XX_SubTimer + * + * @brief Sub-timers on the CC32XX + * + * The timer peripheral supports full width and half width timer operation. + * Use the definitions in this enumerated type to specify a full width timer + * (32-bit) or half width timer (16-bit) in the hardware attributes. There are + * two half width timers per single timer peripheral. A 16-bit timer on this + * device has an 8-bit prescaler. + */ +typedef enum TimerCC32XX_SubTimer_ { + TimerCC32XX_timer16A = 0x0001, /*!< Half width timer A */ + TimerCC32XX_timer16B = 0x0002, /*!< Half width timer B */ + TimerCC32XX_timer32 = 0x0003, /*!< Full width timer */ +} TimerCC32XX_SubTimer; + +extern const Timer_FxnTable TimerCC32XX_fxnTable; + +/*! + * @brief TimerCC32XX Hardware Attributes + * + * Timer hardware attributes that tell the TimerCC32XX driver specific hardware + * configurations and interrupt/priority settings. + * + * A sample structure is shown below: + * @code + * const TimerCC32XX_HWAttrs timerCC32XXHWAttrs[] = + * { + * { + * .baseAddress = TIMERA0_BASE, + * .subTimer = TimerCC32XX_timer32, + * .intNum = INT_TIMERA0A, + * .intPriority = ~0 + * }, + * { + * .baseAddress = TIMERA1_BASE, + * .subTimer = TimerCC32XX_timer16A, + * .intNum = INT_TIMERA1A, + * .intPriority = ~0 + * }, + * { + * .baseAddress = TIMERA1_BASE, + * .subTimer = TimerCC32XX_timer16B, + * .intNum = INT_TIMERA1B, + * .intPriority = ~0 + * } + * }; + * @endcode + */ +typedef struct TimerCC32XX_HWAttrs_ { + /*! The base address of the timer peripheral. */ + uint32_t baseAddress; + + /*! Specifies a full width timer or half-width timer. */ + TimerCC32XX_SubTimer subTimer; + + /*! The hardware interrupt number for the timer peripheral. */ + uint32_t intNum; + + /*! The interrupt priority. */ + uint32_t intPriority; +} TimerCC32XX_HWAttrs; + +/*! + * @brief TimerCC32XX_Object + * + * The application must not access any member variables of this structure! + */ +typedef struct TimerCC32XX_Object_ { + HwiP_Handle hwiHandle; + Power_NotifyObj notifyObj; + SemaphoreP_Handle timerSem; + Timer_CallBackFxn callBack; + Timer_Mode mode; + uint32_t timer; + uint32_t period; + uint32_t prescaler; + bool isRunning; +} TimerCC32XX_Object; + +/*! + * @brief Function to allocate a timer peripheral. + * + * This function is intended to be used by any driver which implements a + * timer hardware peripheral. Calling this function will enable power to the + * timer peripheral specified by the parameter, baseAddress. + * + * @param baseAddress The base address of a timer hardware peripheral. + * + * @param subTimer The TimerCC32XX_subTimer to be allocated. + * + * @return A bool returning true if the timer resource was successfully + * allocated. If the base address is not valid or if the resource is + * not available, false is returned. + * + * @sa TimerCC32XX_freeTimerResource() + */ +extern bool TimerCC32XX_allocateTimerResource(uint32_t baseAddress, + TimerCC32XX_SubTimer subTimer); + +/*! + * @brief Function to de-allocate a timer peripheral. + * + * This function is intended to be used by any driver which implements a + * timer hardware peripheral. Calling this function will disable power to the + * timer peripheral specified by the parameter, baseAddress, if and only if + * the timer peripheral is no longer in use. + * + * @pre A successful call to TimerCC32XX_allocateTimerResource() using the + * baseAddress and subTimer must have been made prior to calling this + * API. + * + * @param baseAddress The base address of a timer hardware peripheral. + * + * @param subTimer The TimerCC32XX_subTimer to be freed. + * + * @sa TimerCC32XX_allocateTimerResource() + */ +extern void TimerCC32XX_freeTimerResource(uint32_t baseAddress, + TimerCC32XX_SubTimer subTimer); + +#ifdef __cplusplus +} +#endif + +#endif /* ti_drivers_timer_TimerCC32XX__include */