mirror of https://github.com/ARMmbed/mbed-os.git
457 lines
14 KiB
C
457 lines
14 KiB
C
/*
|
|
* 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
|
|
}
|
|
|