mbed library sources. Supersedes mbed-src.

Dependents:   Nucleo_Hello_Encoder BLE_iBeaconScan AM1805_DEMO DISCO-F429ZI_ExportTemplate1 ... more

targets/TARGET_Cypress/TARGET_PSOC6/analogout_api.c

Committer:
AnnaBridge
Date:
2019-02-20
Revision:
189:f392fc9709a3
Parent:
188:bcfe06ba3d64

File content as of revision 189:f392fc9709a3:

/*
 * mbed Microcontroller Library
 * Copyright (c) 2017-2018 Future Electronics
 * Copyright (c) 2018-2019 Cypress Semiconductor Corporation
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "device.h"
#include "analogout_api.h"
#include "cy_ctdac.h"
#include "psoc6_utils.h"
#include "mbed_assert.h"
#include "mbed_error.h"
#include "pinmap.h"
#include "PeripheralPins.h"
#include "platform/mbed_error.h"

#if DEVICE_ANALOGOUT

#define CTDAC_NUM_BITS          12
const uint16_t CTDAC_MAX_VALUE = (uint16_t)((1UL << CTDAC_NUM_BITS) - 1);

const uint32_t CTDAC_BASE_CLOCK_HZ = 500000;    // 500 kHz or less

#define CTDAC_DEGLITCH_CYCLES   35



/** Global CTDAC configuration data.
 */
static cy_stc_ctdac_config_t ctdac_config = {
    .refSource          = CY_CTDAC_REFSOURCE_VDDA,          /**< Reference source: Vdda or externally through Opamp1 of CTB */
    .formatMode         = CY_CTDAC_FORMAT_UNSIGNED,         /**< Format of DAC value: signed or unsigned */
    .updateMode         = CY_CTDAC_UPDATE_BUFFERED_WRITE,   /**< Update mode: direct or buffered writes or hardware, edge or level */
    .deglitchMode       = CY_CTDAC_DEGLITCHMODE_UNBUFFERED, /**< Deglitch mode: disabled, buffered, unbuffered, or both */
    .outputMode         = CY_CTDAC_OUTPUT_VALUE,            /**< Output mode: enabled (value or value + 1), high-z, Vssa, or Vdda */
    .outputBuffer       = CY_CTDAC_OUTPUT_UNBUFFERED,       /**< Output path: Buffered through Opamp0 of CTB or connected directly to Pin 6 */
    .deepSleep          = CY_CTDAC_DEEPSLEEP_DISABLE,       /**< Enable or disable the CTDAC during Deep Sleep */
    .deglitchCycles     = CTDAC_DEGLITCH_CYCLES,            /**< Number of deglitch cycles from 0 to 63 */
    .value              = 0,        /**< Current DAC value */
    .nextValue          = 0,        /**< Next DAC value for double buffering */
    .enableInterrupt    = false,    /**< If true, enable interrupt when next value register is transferred to value register */
    .configClock        = false,    /**< Configure or ignore clock information */
};


static bool ctdac_initialized = 0;

static void ctdac_init(dac_t *obj)
{
    if (!ctdac_initialized) {
        uint32_t dac_clock_divider = CY_INVALID_DIVIDER;

        ctdac_initialized = true;
        // Allocate and setup clock.
        dac_clock_divider = cy_clk_allocate_divider(CY_SYSCLK_DIV_8_BIT);
        if (dac_clock_divider == CY_INVALID_DIVIDER) {
            error("CTDAC clock divider allocation failed.");
        }
        Cy_SysClk_PeriphSetDivider(CY_SYSCLK_DIV_8_BIT,
                                   dac_clock_divider,
                                   ((cy_PeriClkFreqHz + CTDAC_BASE_CLOCK_HZ / 2) / CTDAC_BASE_CLOCK_HZ) - 1);
        Cy_SysClk_PeriphEnableDivider(CY_SYSCLK_DIV_8_BIT, dac_clock_divider);
        Cy_SysClk_PeriphAssignDivider(obj->clock, CY_SYSCLK_DIV_8_BIT, dac_clock_divider);

        Cy_CTDAC_Init(obj->base, &ctdac_config);
        Cy_CTDAC_Enable(obj->base);
    }
}


void analogout_init(dac_t *obj, PinName pin)
{
    uint32_t    dac = 0;
    uint32_t    dac_function = 0;

    MBED_ASSERT(obj);
    MBED_ASSERT(pin != (PinName)NC);

    dac = pinmap_peripheral(pin, PinMap_DAC);
    if (dac != (uint32_t)NC) {

        if ((0 != cy_reserve_io_pin(pin)) && !ctdac_initialized) {
            error("ANALOG OUT pin reservation conflict.");
        }

        /* Initialize object */
        obj->base = (CTDAC_Type *)CY_PERIPHERAL_BASE(dac);
        obj->pin = pin;

        /* Configure CTDAC hardware */
        dac_function = pinmap_function(pin, PinMap_DAC);
        obj->clock = CY_PIN_CLOCK(dac_function);
        pin_function(pin, dac_function);

        if (AOUT != pin) {
            const PinName directOutput = AOUT;

            /* Connect AOUT to the AMUXA bus to drive output */
            Cy_GPIO_SetHSIOM(Cy_GPIO_PortToAddr(CY_PORT(directOutput)), CY_PIN(directOutput), HSIOM_SEL_AMUXA);
        }

        ctdac_init(obj);

    } else {
        error("ANALOG OUT pinout mismatch.");
    }
}

void analogout_free(dac_t *obj)
{
    /* MBED AnalogIn driver does not call this function in destructor */
}

void analogout_write(dac_t *obj, float value)
{
    uint32_t val = 0;

    if (value > 1.0) {
        val = CTDAC_MAX_VALUE;
    } else if (value > 0.0) {
        val = value * CTDAC_MAX_VALUE;
    }
    Cy_CTDAC_SetValueBuffered(obj->base, val);
}

void analogout_write_u16(dac_t *obj, uint16_t value)
{
    uint32_t val = 0;

    val = (value >> (16 - CTDAC_NUM_BITS)); // Convert from 16-bit range.

    Cy_CTDAC_SetValueBuffered(obj->base, val);
}

float analogout_read(dac_t *obj)
{
    return (float)analogout_read_u16(obj) / 0xffff;
}

uint16_t analogout_read_u16(dac_t *obj)
{
    uint16_t value = (obj->base->CTDAC_VAL_NXT >> CTDAC_CTDAC_VAL_NXT_VALUE_Pos) & CTDAC_CTDAC_VAL_NXT_VALUE_Msk;

    value <<= (16 - CTDAC_NUM_BITS); // Convert to 16-bit range.

    return value;
}

#endif // DEVICE_ANALOGIN