Files
Beslan 0ef1717155
Some checks failed
Basic Checks / license-check (push) Has been cancelled
Basic Checks / include-check (push) Has been cancelled
Basic Checks / style-check (push) Has been cancelled
Basic Checks / docs-check (push) Has been cancelled
Basic Checks / python-tests (push) Has been cancelled
Basic Checks / pin-validation (push) Has been cancelled
Basic Checks / cmake-checks (push) Has been cancelled
Basic Checks / frozen-tools-check (push) Has been cancelled
Publish or Update docker image for head of branch / prepare-tags (push) Has been cancelled
Release or update docker image for a released mbed-os version / prepare-tags (push) Has been cancelled
Publish or Update docker image for head of branch / build-container (push) Has been cancelled
Publish or Update docker image for head of branch / test-container (linux/amd64) (push) Has been cancelled
Publish or Update docker image for head of branch / test-container (linux/arm64) (push) Has been cancelled
Publish or Update docker image for head of branch / deploy-container (push) Has been cancelled
Release or update docker image for a released mbed-os version / build-container (push) Has been cancelled
Release or update docker image for a released mbed-os version / test-container (linux/amd64) (push) Has been cancelled
Release or update docker image for a released mbed-os version / test-container (linux/arm64) (push) Has been cancelled
Release or update docker image for a released mbed-os version / deploy-container (push) Has been cancelled
Prune temporary docker images / prune-images (push) Has been cancelled
Mirror mbed-os-6.15.0
2026-07-10 18:42:39 +03:00

399 lines
15 KiB
C

/***************************************************************************//**
* \file cyhal_gpio.c
*
* Description:
* Provides a high level interface for interacting with the Cypress GPIO. This is
* a wrapper around the lower level PDL API.
*
********************************************************************************
* \copyright
* Copyright 2018-2021 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 "cyhal_gpio_impl.h"
#include "cyhal_interconnect.h"
#include "cyhal_system.h"
#include "cyhal_hwmgr.h"
#if defined(CY_IP_MXS40IOSS) || defined(CY_IP_M0S8IOSS)
#if defined(__cplusplus)
extern "C" {
#endif /* __cplusplus */
/*******************************************************************************
* Internal
*******************************************************************************/
#if defined(COMPONENT_CAT1A) || defined(COMPONENT_CAT1B)
#define _CYHAL_GPIO_DIRECTION_OUTPUT_MASK (0x07UL) /**< Mask to disable the input buffer */
#elif defined(COMPONENT_CAT2)
#define _CYHAL_GPIO_DIRECTION_OUTPUT_MASK (0x08UL) /**< Mask to disable the input buffer */
#endif
/* Callback array for GPIO interrupts */
static cyhal_gpio_event_callback_t _cyhal_gpio_callbacks[IOSS_GPIO_GPIO_PORT_NR][CY_GPIO_PINS_MAX];
static void *_cyhal_gpio_callback_args[IOSS_GPIO_GPIO_PORT_NR][CY_GPIO_PINS_MAX];
#if defined(CY_IP_MXS40IOSS)
static cyhal_source_t _cyhal_gpio_source_signals[sizeof(cyhal_pin_map_peri_tr_io_output)/sizeof(cyhal_resource_pin_mapping_t)] = { CYHAL_TRIGGER_CPUSS_ZERO };
#endif
#if defined(CY_DEVICE_PMG1S3)
/* PMG1-S3: Work-around as device does not support any GPIO port specific interrupts. */
#define ioss_interrupts_gpio_0_IRQn (ioss_interrupt_gpio_IRQn)
#endif
/*******************************************************************************
* Internal Interrupt Service Routine
*******************************************************************************/
static void _cyhal_gpio_irq_handler(void)
{
IRQn_Type irqn = _CYHAL_UTILS_GET_CURRENT_IRQN();
uint32_t port = (uint32_t)(irqn - ioss_interrupts_gpio_0_IRQn);
uint32_t intr_cause = 1 << port;
#if defined(COMPONENT_CAT2)
if (irqn == ioss_interrupt_gpio_IRQn)
{
intr_cause = Cy_GPIO_GetInterruptCause();
}
#endif
while(intr_cause != 0)
{
uint32_t curr_port = 31U - __CLZ(intr_cause);
GPIO_PRT_Type *portAddr = Cy_GPIO_PortToAddr(curr_port);
for (uint8_t cnt = 0u; cnt < CY_GPIO_PINS_MAX; cnt++)
{
/* Each supported architecture much have a way to check the interrupt status of a pin on a port. */
#if defined(COMPONENT_CAT1A) || defined(COMPONENT_CAT1B)
if (Cy_GPIO_GetInterruptStatusMasked(portAddr, cnt))
{
#elif defined(COMPONENT_CAT2)
if (Cy_GPIO_GetInterruptStatus(portAddr, cnt))
{
#else
#error "Unsupported architecture"
#endif
if (_cyhal_gpio_callbacks[curr_port][cnt] != NULL)
{
/* Call registered callbacks here */
cyhal_gpio_event_t event, edge = (cyhal_gpio_event_t)Cy_GPIO_GetInterruptEdge(portAddr, cnt);
switch (edge)
{
case CYHAL_GPIO_IRQ_RISE:
case CYHAL_GPIO_IRQ_FALL:
event = edge;
break;
default:
event = Cy_GPIO_Read(portAddr, cnt) != 0 ? CYHAL_GPIO_IRQ_RISE : CYHAL_GPIO_IRQ_FALL;
break;
}
(void)(_cyhal_gpio_callbacks[curr_port][cnt])(_cyhal_gpio_callback_args[curr_port][cnt], event);
}
Cy_GPIO_ClearInterrupt(portAddr, cnt);
}
}
intr_cause &= ~(1 << curr_port);
}
}
static uint32_t _cyhal_gpio_convert_drive_mode(cyhal_gpio_drive_mode_t drive_mode, cyhal_gpio_direction_t direction)
{
uint32_t drvMode;
switch (drive_mode)
{
/* For DRIVE_NONE and DRIVE_ANALOG: Return immediately so drvMode is
* not modified after switch statement based on direction as direction
* does not make sense for input only drive modes */
case CYHAL_GPIO_DRIVE_NONE:
drvMode = CY_GPIO_DM_HIGHZ;
return drvMode;
case CYHAL_GPIO_DRIVE_ANALOG:
drvMode = CY_GPIO_DM_ANALOG;
return drvMode;
case CYHAL_GPIO_DRIVE_PULLUP:
drvMode = CY_GPIO_DM_PULLUP;
break;
case CYHAL_GPIO_DRIVE_PULLDOWN:
drvMode = CY_GPIO_DM_PULLDOWN;
break;
case CYHAL_GPIO_DRIVE_OPENDRAINDRIVESLOW:
drvMode = CY_GPIO_DM_OD_DRIVESLOW;
break;
case CYHAL_GPIO_DRIVE_OPENDRAINDRIVESHIGH:
drvMode = CY_GPIO_DM_OD_DRIVESHIGH;
break;
case CYHAL_GPIO_DRIVE_STRONG:
drvMode = CY_GPIO_DM_STRONG;
break;
case CYHAL_GPIO_DRIVE_PULLUPDOWN:
drvMode = CY_GPIO_DM_PULLUP_DOWN;
break;
case CYHAL_GPIO_DRIVE_PULL_NONE:
if (direction == CYHAL_GPIO_DIR_OUTPUT || direction == CYHAL_GPIO_DIR_BIDIRECTIONAL)
{
drvMode = CY_GPIO_DM_STRONG;
}
else
{
drvMode = CY_GPIO_DM_HIGHZ;
}
break;
default:
CY_ASSERT(false);
drvMode = CY_GPIO_DM_HIGHZ;
}
if (direction == CYHAL_GPIO_DIR_OUTPUT)
{
#if defined(COMPONENT_CAT1A) || defined(COMPONENT_CAT1B)
drvMode &= _CYHAL_GPIO_DIRECTION_OUTPUT_MASK;
#elif defined(COMPONENT_CAT2)
drvMode |= _CYHAL_GPIO_DIRECTION_OUTPUT_MASK;
#endif
}
return drvMode;
}
/*******************************************************************************
* HAL Implementation
*******************************************************************************/
cy_rslt_t cyhal_gpio_init(cyhal_gpio_t pin, cyhal_gpio_direction_t direction, cyhal_gpio_drive_mode_t drive_mode, bool init_val)
{
/* Mbed creates GPIOs for pins that are dedicated to other peripherals in some cases. */
#ifndef __MBED__
cyhal_resource_inst_t pinRsc = _cyhal_utils_get_gpio_resource(pin);
cy_rslt_t status = cyhal_hwmgr_reserve(&pinRsc);
#else
cy_rslt_t status = CY_RSLT_SUCCESS;
#endif
if (status == CY_RSLT_SUCCESS)
{
uint32_t pdl_drive_mode = _cyhal_gpio_convert_drive_mode(drive_mode, direction);
Cy_GPIO_Pin_FastInit(CYHAL_GET_PORTADDR(pin), CYHAL_GET_PIN(pin), pdl_drive_mode, init_val, HSIOM_SEL_GPIO);
}
return status;
}
void cyhal_gpio_free(cyhal_gpio_t pin)
{
if (pin != CYHAL_NC_PIN_VALUE)
{
#if defined(COMPONENT_CAT1A) || defined(COMPONENT_CAT1B)
Cy_GPIO_SetInterruptMask(CYHAL_GET_PORTADDR(pin), CYHAL_GET_PIN(pin), 0);
#elif defined(COMPONENT_CAT2)
Cy_GPIO_SetInterruptEdge(CYHAL_GET_PORTADDR(pin), CYHAL_GET_PIN(pin), CY_GPIO_INTR_DISABLE);
#endif
_cyhal_gpio_callbacks[CYHAL_GET_PORT(pin)][CYHAL_GET_PIN(pin)] = NULL;
_cyhal_gpio_callback_args[CYHAL_GET_PORT(pin)][CYHAL_GET_PIN(pin)] = NULL;
(void)cyhal_gpio_disable_output(pin);
#if defined(CY_IP_MXS40IOSS)
for(uint8_t i = 0; i < (uint8_t)(sizeof(cyhal_pin_map_peri_tr_io_output)/sizeof(cyhal_resource_pin_mapping_t)); i++)
{
cyhal_resource_pin_mapping_t mapping = cyhal_pin_map_peri_tr_io_output[i];
if(mapping.pin == pin)
{
if (CYHAL_TRIGGER_CPUSS_ZERO != _cyhal_gpio_source_signals[i])
{
(void)cyhal_gpio_disconnect_digital(pin, _cyhal_gpio_source_signals[i]);
}
}
}
#endif
Cy_GPIO_Pin_FastInit(CYHAL_GET_PORTADDR(pin), CYHAL_GET_PIN(pin), CY_GPIO_DM_ANALOG, 0UL, HSIOM_SEL_GPIO);
/* Do not attempt to free the resource we don't reserve in mbed. */
#ifndef __MBED__
cyhal_resource_inst_t pinRsc = _cyhal_utils_get_gpio_resource(pin);
cyhal_hwmgr_free(&pinRsc);
#endif
}
}
cy_rslt_t cyhal_gpio_configure(cyhal_gpio_t pin, cyhal_gpio_direction_t direction, cyhal_gpio_drive_mode_t drive_mode)
{
uint32_t pdldrive_mode = _cyhal_gpio_convert_drive_mode(drive_mode, direction);
Cy_GPIO_SetDrivemode(CYHAL_GET_PORTADDR(pin), CYHAL_GET_PIN(pin), pdldrive_mode);
return CY_RSLT_SUCCESS;
}
void cyhal_gpio_register_callback(cyhal_gpio_t pin, cyhal_gpio_event_callback_t callback, void *callback_arg)
{
uint32_t savedIntrStatus = cyhal_system_critical_section_enter();
_cyhal_gpio_callbacks[CYHAL_GET_PORT(pin)][CYHAL_GET_PIN(pin)] = callback;
_cyhal_gpio_callback_args[CYHAL_GET_PORT(pin)][CYHAL_GET_PIN(pin)] = callback_arg;
cyhal_system_critical_section_exit(savedIntrStatus);
}
void cyhal_gpio_enable_event(cyhal_gpio_t pin, cyhal_gpio_event_t event, uint8_t intr_priority, bool enable)
{
Cy_GPIO_ClearInterrupt(CYHAL_GET_PORTADDR(pin), CYHAL_GET_PIN(pin));
#if defined(COMPONENT_CAT1A) || defined(COMPONENT_CAT1B)
Cy_GPIO_SetInterruptEdge(CYHAL_GET_PORTADDR(pin), CYHAL_GET_PIN(pin), (uint32_t)event);
Cy_GPIO_SetInterruptMask(CYHAL_GET_PORTADDR(pin), CYHAL_GET_PIN(pin), (uint32_t)enable);
IRQn_Type irqn = (IRQn_Type)(ioss_interrupts_gpio_0_IRQn + CYHAL_GET_PORT(pin));
#elif defined(COMPONENT_CAT2)
uint32_t intr_val = enable ? (uint32_t)event : CY_GPIO_INTR_DISABLE;
Cy_GPIO_SetInterruptEdge(CYHAL_GET_PORTADDR(pin), CYHAL_GET_PIN(pin), intr_val);
IRQn_Type irqn = (ioss_interrupts_gpio_0_IRQn + CYHAL_GET_PORT(pin) < ioss_interrupt_gpio_IRQn)
? (IRQn_Type)(ioss_interrupts_gpio_0_IRQn + CYHAL_GET_PORT(pin))
: (IRQn_Type)(ioss_interrupt_gpio_IRQn);
#endif
/* Only enable if it's not already enabled */
if (NVIC_GetEnableIRQ(irqn) == 0)
{
cy_stc_sysint_t irqCfg = {irqn, intr_priority};
Cy_SysInt_Init(&irqCfg, _cyhal_gpio_irq_handler);
NVIC_EnableIRQ(irqn);
}
else
{
NVIC_SetPriority(irqn, intr_priority);
}
}
#if defined(CY_IP_MXS40IOSS)
cy_rslt_t cyhal_gpio_connect_digital(cyhal_gpio_t pin, cyhal_source_t source, cyhal_signal_type_t type)
{
// Search through cyhal_pin_map_peri_tr_io_output to determine if a trigger
// can be routed to it. (Note: tr_io_output refers to trigger mux output,
// not peripheral output. A trigger mux output is routed to a peripheral
// input.)
for(uint8_t i = 0; i < (uint8_t)(sizeof(cyhal_pin_map_peri_tr_io_output)/sizeof(cyhal_resource_pin_mapping_t)); i++)
{
cyhal_resource_pin_mapping_t mapping = cyhal_pin_map_peri_tr_io_output[i];
if(mapping.pin == pin)
{
Cy_GPIO_SetHSIOM(CYHAL_GET_PORTADDR(pin), CYHAL_GET_PIN(pin), mapping.hsiom);
cyhal_dest_t dest = (cyhal_dest_t)(CYHAL_TRIGGER_PERI_TR_IO_OUTPUT0 + (uint32_t)(mapping.inst));
cy_rslt_t rslt = _cyhal_connect_signal(source, dest, type);
if (CY_RSLT_SUCCESS == rslt)
{
_cyhal_gpio_source_signals[i] = source;
}
return rslt;
}
}
return CYHAL_GPIO_RSLT_ERR_NO_INPUT_SIGNAL;
}
cy_rslt_t cyhal_gpio_enable_output(cyhal_gpio_t pin, cyhal_source_t *source)
{
// Search through cyhal_pin_map_peri_tr_io_input to determine if pin can be
// used to drive a trigger line. (Note: tr_io_input refers to trigger mux
// input, not peripheral input. A peripheral output is routed to a trigger
// mux input.)
for(uint8_t i = 0; i < (uint8_t)(sizeof(cyhal_pin_map_peri_tr_io_input)/sizeof(cyhal_resource_pin_mapping_t)); i++)
{
cyhal_resource_pin_mapping_t mapping = cyhal_pin_map_peri_tr_io_input[i];
if(mapping.pin == pin)
{
Cy_GPIO_SetHSIOM(CYHAL_GET_PORTADDR(pin), CYHAL_GET_PIN(pin), mapping.hsiom);
*source = (cyhal_source_t)(CYHAL_TRIGGER_PERI_TR_IO_INPUT0 + (uint32_t)(mapping.inst));
return CY_RSLT_SUCCESS;
}
}
return CYHAL_GPIO_RSLT_ERR_NO_OUTPUT_SIGNAL;
}
cy_rslt_t cyhal_gpio_disconnect_digital(cyhal_gpio_t pin, cyhal_source_t source)
{
for(uint8_t i = 0; i < (uint8_t)(sizeof(cyhal_pin_map_peri_tr_io_output)/sizeof(cyhal_resource_pin_mapping_t)); i++)
{
cyhal_resource_pin_mapping_t mapping = cyhal_pin_map_peri_tr_io_output[i];
if(mapping.pin == pin)
{
Cy_GPIO_SetHSIOM(CYHAL_GET_PORTADDR(pin), CYHAL_GET_PIN(pin), HSIOM_SEL_GPIO);
cyhal_dest_t dest = (cyhal_dest_t)(CYHAL_TRIGGER_PERI_TR_IO_OUTPUT0 + (uint32_t)(mapping.inst));
cy_rslt_t rslt = _cyhal_disconnect_signal(source, dest);
if (CY_RSLT_SUCCESS == rslt)
{
_cyhal_gpio_source_signals[i] = CYHAL_TRIGGER_CPUSS_ZERO;
}
return rslt;
}
}
return CYHAL_GPIO_RSLT_ERR_NO_INPUT_SIGNAL;
}
cy_rslt_t cyhal_gpio_disable_output(cyhal_gpio_t pin)
{
for(uint8_t i = 0; i < (uint8_t)(sizeof(cyhal_pin_map_peri_tr_io_input)/sizeof(cyhal_resource_pin_mapping_t)); i++)
{
cyhal_resource_pin_mapping_t mapping = cyhal_pin_map_peri_tr_io_input[i];
if(mapping.pin == pin)
{
Cy_GPIO_SetHSIOM(CYHAL_GET_PORTADDR(pin), CYHAL_GET_PIN(pin), HSIOM_SEL_GPIO);
return CY_RSLT_SUCCESS;
}
}
return CYHAL_GPIO_RSLT_ERR_NO_OUTPUT_SIGNAL;
}
#elif defined(CY_IP_M0S8IOSS)
// M0S8 devices do not have gpio triggers
cy_rslt_t cyhal_gpio_connect_digital(cyhal_gpio_t pin, cyhal_source_t source, cyhal_signal_type_t type)
{
CY_UNUSED_PARAMETER(pin);
CY_UNUSED_PARAMETER(source);
CY_UNUSED_PARAMETER(type);
return CYHAL_INTERCONNECT_RSLT_INVALID_CONNECTION;
}
cy_rslt_t cyhal_gpio_enable_output(cyhal_gpio_t pin, cyhal_source_t *source)
{
CY_UNUSED_PARAMETER(pin);
CY_UNUSED_PARAMETER(source);
return CYHAL_INTERCONNECT_RSLT_INVALID_CONNECTION;
}
cy_rslt_t cyhal_gpio_disconnect_digital(cyhal_gpio_t pin, cyhal_source_t source)
{
CY_UNUSED_PARAMETER(pin);
CY_UNUSED_PARAMETER(source);
return CYHAL_INTERCONNECT_RSLT_INVALID_CONNECTION;
}
cy_rslt_t cyhal_gpio_disable_output(cyhal_gpio_t pin)
{
CY_UNUSED_PARAMETER(pin);
return CYHAL_INTERCONNECT_RSLT_INVALID_CONNECTION;
}
#endif
#if defined(__cplusplus)
}
#endif /* __cplusplus */
#endif /* defined(CY_IP_MXS40IOSS) || defined(CY_IP_M0S8IOSS) */