mbed library sources. Supersedes mbed-src.
Dependents: Nucleo_Hello_Encoder BLE_iBeaconScan AM1805_DEMO DISCO-F429ZI_ExportTemplate1 ... more
targets/TARGET_Cypress/TARGET_PSOC6/psoc6_utils.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 "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__) */ #include "cy_crypto_core_hw.h" #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_DIVIDER8_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, 0, 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 = ÷r_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 = ÷r_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 = ÷r_allocations[div_type]; MBED_ASSERT(div_type < CY_NUM_DIVIDER_TYPES); MBED_ASSERT(p_alloc->current_index < p_alloc->max_index); core_util_critical_section_enter(); // Try to reserve current divider divider = cy_clk_reserve_divider(div_type, p_alloc->current_index); if (CY_INVALID_DIVIDER == divider) { // Store current index uint32_t first_index = p_alloc->current_index; // Move index forward before start circular search ++p_alloc->current_index; if (p_alloc->current_index > p_alloc->max_index) { p_alloc->current_index = 0; } // Execute circular divider search for (; (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; result = 0; } 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; result = 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."); } } static uint8_t crypto_reservations[NUM_CRYPTO_HW] = { 0u }; static int cy_crypto_reserved_status(void) { return ((int)(crypto_reservations[CY_CRYPTO_TRNG_HW] | crypto_reservations[CY_CRYPTO_CRC_HW] | crypto_reservations[CY_CRYPTO_VU_HW] | crypto_reservations[CY_CRYPTO_COMMON_HW])); } int cy_reserve_crypto(cy_en_crypto_submodule_t module_num) { int result = (-1); if (module_num < NUM_CRYPTO_HW) { core_util_critical_section_enter(); if (cy_crypto_reserved_status() == 0) { /* Enable Crypto IP on demand */ Cy_Crypto_Core_Enable(CRYPTO); } if (module_num == CY_CRYPTO_COMMON_HW) { if (crypto_reservations[module_num] != 1) { crypto_reservations[module_num] = 1; result = 0; } } else { crypto_reservations[module_num] = 1; result = 0; } core_util_critical_section_exit(); } return result; } void cy_free_crypto(cy_en_crypto_submodule_t module_num) { int result = (-1); if (module_num < NUM_CRYPTO_HW) { core_util_critical_section_enter(); if (crypto_reservations[module_num] == 1) { crypto_reservations[module_num] = 0; if (cy_crypto_reserved_status() == 0) { /* Crypto hardware is still in enabled state; to disable: Cy_Crypto_Core_Disable(CRYPTO) */ } result = 0; } core_util_critical_section_exit(); } if (result) { error("Trying to release wrong CRYPTO hardware submodule."); } } /* * 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 defined(TARGET_MCU_PSOC6_M0) || PSOC6_DYNSRM_DISABLE || !defined(__MBED__) uint32_t i; for (i = 0; i < CY_NUM_PSOC6_PORTS; ++i) { port_reservations[i] = DEFAULT_PORT_RES; } for (i = 0; i < NUM_SCB; ++i) { scb_reservations[i] = DEFAULT_SCM_RES; } for (i = 0; i < NUM_TCPWM; ++i) { tcpwm_reservations[i] = DEFAULT_TCPWM_RES; } #if PSOC6_DYNSRM_DISABLE #ifdef CYCFG_ASSIGNED_PORTS SRM_INIT_RESOURCE(uint8_t, port_reservations,, CYCFG_ASSIGNED_PORTS); #endif #ifdef CYCFG_ASSIGNED_DIVIDERS SRM_INIT_RESOURCE(uint32_t, divider_allocations, .reservations, CYCFG_ASSIGNED_DIVIDERS); #endif #ifdef CYCFG_ASSIGNED_SCBS SRM_INIT_RESOURCE(uint8_t, scb_reservations,, CYCFG_ASSIGNED_SCBS); #endif #ifdef CYCFG_ASSIGNED_TCPWMS SRM_INIT_RESOURCE(uint8_t, tcpwm_reservations,, CYCFG_ASSIGNED_TCPWMS); #endif #endif // PSOC6_DYNSRM_DISABLE #endif // defined(TARGET_MCU_PSOC6_M0) || PSOC6_DSRM_DISABLE || !defined(__MBED__) }