mbed library sources. Supersedes mbed-src.

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

Revision:
188:bcfe06ba3d64
Child:
189:f392fc9709a3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/targets/TARGET_Cypress/TARGET_PSOC6/psoc6_utils.c	Thu Nov 08 11:46:34 2018 +0000
@@ -0,0 +1,456 @@
+/*
+ * mbed Microcontroller Library
+ * Copyright (c) 2017-2018 Future Electronics
+ *
+ * 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 "psoc6_utils.h"
+
+#if defined(__MBED__)
+
+#include "mbed_critical.h"
+#include "mbed_error.h"
+
+#else
+
+/** Adaptation layer to native Cypress environment */
+/* Notice, that since we use critical section here only for operations
+ * that do not involve function calls, we can get away with using
+ * a global static variable for interrupt status saving.
+ */
+
+#include "syslib/cy_syslib.h"
+
+#define error(arg)  CY_ASSERT(0)
+#define MBED_ASSERT CY_ASSERT
+
+#define core_util_critical_section_enter() \
+    uint32_t _last_irq_status_ = Cy_SysLib_EnterCriticalSection()
+
+#define core_util_critical_section_exit() \
+     Cy_SysLib_ExitCriticalSection(_last_irq_status_)
+
+#endif /* defined(__MBED__) */
+
+
+#define CY_NUM_PSOC6_PORTS      14
+#define CY_NUM_DIVIDER_TYPES    4
+#define NUM_SCB                 8
+#define NUM_TCPWM               32
+
+
+#if defined(TARGET_MCU_PSOC6_M0) || PSOC6_DYNSRM_DISABLE || !defined(__MBED__)
+
+/****************************************************************************/
+/*                   Dynamic Shared Resource Manager                        */
+/****************************************************************************/
+/*
+ * This part of the code is responsible for management of the hardware
+ * resource shared between both CPUs of the PSoC 6.
+ * It supports allocation, freeing and conflict detection, so that never
+ * both CPUs try to use a single resource.
+ * It also detects conflicts arising from allocation of hardware devices
+ * for different modes of operation and when user tries to assign multiple
+ * functions to the same chip pin.
+ * It supports two modes of operation:
+ * 1. DYNAMIC (default mode)
+ *    Resource manager is run on M0 core and M4 core asks it to allocate
+ *    or free resources using RPC over IPC mechanism.
+ *    M0 core communicates with manager via local function calls.
+ * 2. STATIC (enabled with PSOC6_DYNSRM_DISABLE compilation flag)
+ *    In this mode resources are split statically between both cores.
+ *    Targets using this mode should add psoc6_static_srm.h file to
+ *    each core folder with declarations of resources assigned to it.
+ *    See example file for details.
+ */
+
+
+#if PSOC6_DYNSRM_DISABLE
+
+#define SRM_INIT_RESOURCE(_type_, _res_, _field_, ...)                   \
+do {                                                            \
+    struct _init_s_ {                                           \
+        uint8_t idx;                                            \
+        _type_ val;                                             \
+    } init[] = {{0, 0}, __VA_ARGS__};                           \
+    uint32_t i;                                                 \
+    for (i = 1; i < sizeof(init)/sizeof(struct _init_s_); ++i)  \
+        _res_[init[i].idx]_field_ = init[i].val;                \
+} while(0)
+
+#if defined(TARGET_MCU_PSOC6_M0)
+/*
+ * On M0 we start with all resources assigned to M4 and then clear reservations
+ * for those assigned to it (M0).
+ */
+#define SRM_PORT(port, pins)               {(port), (uint8_t)~(pins)}
+#define SRM_DIVIDER(type, dividers)        {(type), (uint16_t)~(dividers)}
+#define SRM_SCB(num)                       {(num), (0)}
+#define SRM_TCPWM(num)                     {(num), (0)}
+
+#define DEFAULT_PORT_RES        0xff
+#define DEFAULT_DIVIDER_RES     0xffff
+#define DEFAULT_SCM_RES         1
+#define DEFAULT_TCPWM_RES       1
+
+#else // defined(TARGET_MCU_PSOC6_M0)
+
+#define SRM_PORT(port, pins)               {(port), (pins)}
+#define SRM_DIVIDER(type, dividers)        {(type), (dividers)}
+#define SRM_SCB(num)                       {(num), (1)}
+#define SRM_TCPWM(num)                     {(num), (1)}
+
+#define DEFAULT_PORT_RES        0
+#define DEFAULT_DIVIDER_RES     0
+#define DEFAULT_DIVIDER8_RES    0
+#define DEFAULT_SCM_RES         0
+#define DEFAULT_TCPWM_RES       0
+#endif // defined(TARGET_MCU_PSOC6_M0)
+
+#include "psoc6_static_srm.h"
+
+#else // PSOC6_DYNSRM_DISABLE
+
+#define DEFAULT_PORT_RES        0
+#define DEFAULT_DIVIDER_RES     0
+#define DEFAULT_DIVIDER8_RES    0x3         // dividers 0 & 1 are reserved for us_ticker
+#define DEFAULT_SCM_RES         0
+#define DEFAULT_TCPWM_RES       0x3         // 32b counters 0 & 1 are reserved for us_ticker
+
+#endif // PSOC6_DYNSRM_DISABLE
+
+static uint8_t port_reservations[CY_NUM_PSOC6_PORTS] = {DEFAULT_PORT_RES};
+
+typedef struct {
+    const uint32_t  max_index;
+    uint32_t        current_index;
+    uint32_t        reservations;
+} divider_alloc_t;
+
+static divider_alloc_t divider_allocations[CY_NUM_DIVIDER_TYPES] = {
+    { PERI_DIV_8_NR - 1,    2,  DEFAULT_DIVIDER8_RES },   // CY_SYSCLK_DIV_8_BIT
+    { PERI_DIV_16_NR - 1,   0,  DEFAULT_DIVIDER_RES },    // CY_SYSCLK_DIV_16_BIT
+    { PERI_DIV_16_5_NR - 1, 0,  DEFAULT_DIVIDER_RES },    // CY_SYSCLK_DIV_16_5_BIT
+    { PERI_DIV_24_5_NR - 1, 0,  DEFAULT_DIVIDER_RES }     // CY_SYSCLK_DIV_24_5_BIT
+};
+
+static uint8_t scb_reservations[NUM_SCB] = {DEFAULT_SCM_RES};
+
+static uint8_t tcpwm_reservations[NUM_TCPWM] = {DEFAULT_TCPWM_RES};
+
+
+int cy_reserve_io_pin(PinName pin_name)
+{
+    uint32_t port = CY_PORT(pin_name);
+    uint32_t pin = CY_PIN(pin_name);
+    int result = (-1);
+
+    if ((port < CY_NUM_PSOC6_PORTS) && (pin <= 7)) {
+        core_util_critical_section_enter();
+        if (!(port_reservations[port] & (1 << pin))) {
+            port_reservations[port] |= (1 << pin);
+            result = 0;
+        }
+        core_util_critical_section_exit();
+    } else {
+        error("Trying to reserve non existing port/pin!");
+    }
+    return result;
+}
+
+
+void cy_free_io_pin(PinName pin_name)
+{
+    uint32_t port = CY_PORT(pin_name);
+    uint32_t pin = CY_PIN(pin_name);
+    int result = (-1);
+
+    if ((port < CY_NUM_PSOC6_PORTS) && (pin <= 7)) {
+        core_util_critical_section_enter();
+        if (port_reservations[port] & (1 << pin)) {
+            port_reservations[port] &= ~(1 << pin);
+            result = 0;
+        }
+        core_util_critical_section_exit();
+    }
+
+    if (result) {
+        error("Trying to free wrong port/pin.");
+    }
+}
+
+
+uint32_t cy_clk_reserve_divider(cy_en_divider_types_t div_type, uint32_t div_num)
+{
+    uint32_t        divider = CY_INVALID_DIVIDER;
+    divider_alloc_t *p_alloc = &divider_allocations[div_type];
+
+    MBED_ASSERT(div_type < CY_NUM_DIVIDER_TYPES);
+    MBED_ASSERT(div_num <= p_alloc->max_index);
+
+    core_util_critical_section_enter();
+
+    if ((p_alloc->reservations & (1 << div_num)) == 0) {
+        p_alloc->reservations |= (1 << div_num);
+        divider = div_num;
+        p_alloc->current_index = ++div_num;
+        if (p_alloc->current_index > p_alloc->max_index) {
+            p_alloc->current_index = 0;
+        }
+    }
+
+    core_util_critical_section_exit();
+
+    return divider;
+}
+
+
+void cy_clk_free_divider(cy_en_divider_types_t div_type, uint32_t div_num)
+{
+    int result = (-1);
+    divider_alloc_t *p_alloc = &divider_allocations[div_type];
+
+    MBED_ASSERT(div_type < CY_NUM_DIVIDER_TYPES);
+    MBED_ASSERT(div_num <= p_alloc->max_index);
+
+    core_util_critical_section_enter();
+
+    if ((p_alloc->reservations & (1 << div_num)) != 0) {
+        p_alloc->reservations &= ~(1 << div_num);
+        result = 0;
+    }
+
+    core_util_critical_section_exit();
+
+    if (result) {
+        error("Trying to release wrong clock divider.");
+    }
+}
+
+
+uint32_t cy_clk_allocate_divider(cy_en_divider_types_t div_type)
+{
+    uint32_t        divider = CY_INVALID_DIVIDER;
+    divider_alloc_t *p_alloc = &divider_allocations[div_type];
+
+    MBED_ASSERT(div_type < CY_NUM_DIVIDER_TYPES);
+
+    core_util_critical_section_enter();
+
+    MBED_ASSERT(p_alloc->current_index < p_alloc->max_index);
+
+
+    for ( uint32_t first_index = p_alloc->current_index;
+            CY_INVALID_DIVIDER == (divider = cy_clk_reserve_divider(div_type, p_alloc->current_index));
+            ++p_alloc->current_index) {
+        if (p_alloc->current_index > p_alloc->max_index) {
+            p_alloc->current_index = 0;
+        }
+        if (p_alloc->current_index == first_index) {
+            break;
+        }
+    }
+
+    core_util_critical_section_exit();
+
+    return divider;
+}
+
+
+int cy_reserve_scb(uint32_t scb_num)
+{
+    int result = (-1);
+
+    if (scb_num < NUM_SCB) {
+        core_util_critical_section_enter();
+        if (scb_reservations[scb_num] == 0) {
+            scb_reservations[scb_num] = 1;
+        }
+        core_util_critical_section_exit();
+    }
+    return result;
+}
+
+
+void cy_free_scb(uint32_t scb_num)
+{
+    int result = (-1);
+
+    if (scb_num < NUM_SCB) {
+        core_util_critical_section_enter();
+        if (scb_reservations[scb_num] == 1) {
+            scb_reservations[scb_num] = 0;
+        }
+        core_util_critical_section_exit();
+    }
+    if (result) {
+        error("Trying to release wrong SCB.");
+    }
+}
+
+
+int cy_reserve_tcpwm(uint32_t tcpwm_num)
+{
+    int result = (-1);
+
+    if (tcpwm_num < NUM_TCPWM) {
+        core_util_critical_section_enter();
+        if (tcpwm_reservations[tcpwm_num] == 0) {
+            tcpwm_reservations[tcpwm_num] = 1;
+            result = 0;
+        }
+        core_util_critical_section_exit();
+    }
+    return result;
+}
+
+
+void cy_free_tcpwm(uint32_t tcpwm_num)
+{
+    int result = (-1);
+
+    if (tcpwm_num < NUM_TCPWM) {
+        core_util_critical_section_enter();
+        if (tcpwm_reservations[tcpwm_num] == 1) {
+            tcpwm_reservations[tcpwm_num] = 0;
+            result = 0;
+        }
+        core_util_critical_section_exit();
+    }
+    if (result) {
+        error("Trying to release wrong TCPWM.");
+    }
+}
+
+
+/*
+ * NVIC channel dynamic allocation (multiplexing) is used only on M0.
+ * On M4 IRQs are statically pre-assigned to NVIC channels.
+ */
+
+#if defined(TARGET_MCU_PSOC6_M0)
+
+#define NUM_NVIC_CHANNELS       ((uint32_t)(NvicMux31_IRQn - NvicMux0_IRQn) + 1)
+
+static uint32_t irq_channels[NUM_NVIC_CHANNELS] = {0};
+
+
+IRQn_Type cy_m0_nvic_allocate_channel(uint32_t channel_id)
+{
+    IRQn_Type alloc = (IRQn_Type)(-1);
+    uint32_t chn;
+    MBED_ASSERT(channel_id);
+
+    core_util_critical_section_enter();
+    for (chn = 0; chn < NUM_NVIC_CHANNELS; ++chn) {
+        if (irq_channels[chn] == 0) {
+            irq_channels[chn] = channel_id;
+            alloc = NvicMux0_IRQn + chn;
+            break;
+            irq_channels[chn] = channel_id;
+
+        }
+    }
+    core_util_critical_section_exit();
+    return alloc;
+}
+
+IRQn_Type cy_m0_nvic_reserve_channel(IRQn_Type channel, uint32_t channel_id)
+{
+    uint32_t chn = channel - NvicMux0_IRQn;
+
+    MBED_ASSERT(chn < NUM_NVIC_CHANNELS);
+    MBED_ASSERT(channel_id);
+
+    core_util_critical_section_enter();
+    if (irq_channels[chn]) {
+        channel =  (IRQn_Type)(-1);
+    } else {
+        irq_channels[chn] = channel_id;
+    }
+    core_util_critical_section_exit();
+    return channel;
+}
+
+void cy_m0_nvic_release_channel(IRQn_Type channel, uint32_t channel_id)
+{
+    uint32_t chn = channel - NvicMux0_IRQn;
+
+    MBED_ASSERT(chn < NUM_NVIC_CHANNELS);
+    MBED_ASSERT(channel_id);
+
+    core_util_critical_section_enter();
+    if (irq_channels[chn] == channel_id) {
+        irq_channels[chn] = 0;
+    } else {
+        error("NVIC channel cross-check failed on release.");
+    }
+    core_util_critical_section_exit();
+}
+
+#define CY_BLE_SFLASH_DIE_X_MASK                   (0x3Fu)
+#define CY_BLE_SFLASH_DIE_X_BITS                   (6u)
+#define CY_BLE_SFLASH_DIE_Y_MASK                   (0x3Fu)
+#define CY_BLE_SFLASH_DIE_Y_BITS                   (6u)
+#define CY_BLE_SFLASH_DIE_XY_BITS                  (CY_BLE_SFLASH_DIE_X_BITS + CY_BLE_SFLASH_DIE_Y_BITS)
+#define CY_BLE_SFLASH_DIE_WAFER_MASK               (0x1Fu)
+#define CY_BLE_SFLASH_DIE_WAFER_BITS               (5u)
+#define CY_BLE_SFLASH_DIE_XYWAFER_BITS             (CY_BLE_SFLASH_DIE_XY_BITS + CY_BLE_SFLASH_DIE_WAFER_BITS)
+#define CY_BLE_SFLASH_DIE_LOT_MASK                 (0x7Fu)
+#define CY_BLE_SFLASH_DIE_LOT_BITS                 (7u)
+
+static uint8_t cy_ble_deviceAddress[6] = {0x19u, 0x00u, 0x00u, 0x50u, 0xA0u, 0x00u};
+
+void cy_get_bd_mac_address(uint8_t *buffer)
+{
+    uint32_t bdAddrLoc;
+    bdAddrLoc = ((uint32_t)SFLASH->DIE_X & (uint32_t)CY_BLE_SFLASH_DIE_X_MASK) |
+                ((uint32_t)(((uint32_t)SFLASH->DIE_Y) & ((uint32_t)CY_BLE_SFLASH_DIE_Y_MASK)) <<
+                 CY_BLE_SFLASH_DIE_X_BITS) |
+                ((uint32_t)(((uint32_t)SFLASH->DIE_WAFER) & ((uint32_t)CY_BLE_SFLASH_DIE_WAFER_MASK)) <<
+                 CY_BLE_SFLASH_DIE_XY_BITS) |
+                ((uint32_t)(((uint32_t)SFLASH->DIE_LOT[0]) & ((uint32_t)CY_BLE_SFLASH_DIE_LOT_MASK)) <<
+                 CY_BLE_SFLASH_DIE_XYWAFER_BITS);
+
+    cy_ble_deviceAddress[0] = (uint8_t)bdAddrLoc;
+    cy_ble_deviceAddress[1] = (uint8_t)(bdAddrLoc >> 8u);
+    cy_ble_deviceAddress[2] = (uint8_t)(bdAddrLoc >> 16u);
+
+    for (int i = 0; i < 6; ++i) {
+        buffer[i] = cy_ble_deviceAddress[i];
+    }
+}
+
+#endif // defined(TARGET_MCU_PSOC6_M0)
+
+#endif // defined(TARGET_MCU_PSOC6_M0) || PSOC6_DSRM_DISABLE || !defined(__MBED__)
+
+void cy_srm_initialize(void)
+{
+#if PSOC6_DYNSRM_DISABLE
+#ifdef M0_ASSIGNED_PORTS
+    SRM_INIT_RESOURCE(uint8_t, port_reservations,, M0_ASSIGNED_PORTS);
+#endif
+#ifdef M0_ASSIGNED_DIVIDERS
+    SRM_INIT_RESOURCE(uint32_t, divider_allocations, .reservations, M0_ASSIGNED_DIVIDERS);
+#endif
+#ifdef M0_ASSIGNED_SCBS
+    SRM_INIT_RESOURCE(uint8_t, scb_reservations,, M0_ASSIGNED_SCBS);
+#endif
+#ifdef M0_ASSIGNED_TCPWMS
+    SRM_INIT_RESOURCE(uint8_t, tcpwm_reservations,,  M0_ASSIGNED_TCPWMS);
+#endif
+#endif // PSOC6_DYNSRM_DISABLE
+}
+