mbed library sources. Supersedes mbed-src.
Dependents: Nucleo_Hello_Encoder BLE_iBeaconScan AM1805_DEMO DISCO-F429ZI_ExportTemplate1 ... more
Diff: targets/TARGET_Cypress/TARGET_PSOC6/psoc6_utils.c
- 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 = ÷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); + + 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 +} +