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
964 lines
33 KiB
C
964 lines
33 KiB
C
/***************************************************************************//**
|
||
* \file cyhal_spi.c
|
||
*
|
||
* \brief
|
||
* Provides a high level interface for interacting with the Cypress SPI. 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 <stdlib.h>
|
||
#include <string.h>
|
||
#include "cyhal_spi.h"
|
||
#include "cyhal_scb_common.h"
|
||
#include "cyhal_gpio.h"
|
||
#include "cyhal_system_impl.h"
|
||
#include "cyhal_hwmgr.h"
|
||
#include "cyhal_system.h"
|
||
#include "cyhal_syspm.h"
|
||
#include "cyhal_clock.h"
|
||
|
||
#if defined(CY_IP_MXSCB) || defined(CY_IP_M0S8SCB)
|
||
|
||
#if defined(__cplusplus)
|
||
extern "C"
|
||
{
|
||
#endif
|
||
|
||
#define _CYHAL_SPI_DEFAULT_SPEED 100000
|
||
|
||
#define _CYHAL_SPI_OVERSAMPLE_MIN 4
|
||
#define _CYHAL_SPI_OVERSAMPLE_MAX 16
|
||
#define _CYHAL_SPI_SSEL_NUM 4
|
||
|
||
#define _CYHAL_SPI_PENDING_NONE 0
|
||
#define _CYHAL_SPI_PENDING_RX 1
|
||
#define _CYHAL_SPI_PENDING_TX 2
|
||
#define _CYHAL_SPI_PENDING_TX_RX 3
|
||
|
||
#define _CYHAL_SPI_SSEL_ACTIVATE true
|
||
#define _CYHAL_SPI_SSEL_DEACTIVATE false
|
||
|
||
/* Default SPI configuration */
|
||
static const cy_stc_scb_spi_config_t _cyhal_spi_default_config =
|
||
{
|
||
.spiMode = CY_SCB_SPI_MASTER,
|
||
.subMode = CY_SCB_SPI_MOTOROLA,
|
||
.sclkMode = CY_SCB_SPI_CPHA0_CPOL0,
|
||
.oversample = _CYHAL_SPI_OVERSAMPLE_MIN,
|
||
.rxDataWidth = 8,
|
||
.txDataWidth = 8,
|
||
.enableMsbFirst = true,
|
||
.enableFreeRunSclk = false,
|
||
.enableInputFilter = false,
|
||
.enableMisoLateSample = true,
|
||
.enableTransferSeperation = false,
|
||
.enableWakeFromSleep = false,
|
||
.ssPolarity = CY_SCB_SPI_ACTIVE_LOW,
|
||
.rxFifoTriggerLevel = 0,
|
||
.rxFifoIntEnableMask = 0,
|
||
.txFifoTriggerLevel = 0,
|
||
.txFifoIntEnableMask = 0,
|
||
.masterSlaveIntEnableMask = 0
|
||
};
|
||
|
||
static void _cyhal_ssel_switch_state(cyhal_spi_t *obj, uint8_t ssel_idx, bool ssel_activate);
|
||
|
||
static cy_rslt_t _cyhal_spi_int_frequency(cyhal_spi_t *obj, uint32_t hz, uint8_t *over_sample_val)
|
||
{
|
||
CY_ASSERT(NULL != obj);
|
||
cy_rslt_t result = CY_RSLT_SUCCESS;
|
||
uint8_t oversample_value;
|
||
uint32_t divider_value;
|
||
uint32_t last_diff = 0xFFFFFFFFU;
|
||
uint8_t last_ovrsmpl_val = 0;
|
||
uint32_t last_dvdr_val = 0;
|
||
uint32_t oversampled_freq = 0;
|
||
uint32_t divided_freq = 0;
|
||
uint32_t diff = 0;
|
||
|
||
Cy_SysClk_PeriphDisableDivider((cy_en_divider_types_t)obj->clock.block, obj->clock.channel);
|
||
|
||
#if defined(COMPONENT_CAT1A) || defined(COMPONENT_CAT1B)
|
||
uint32_t peri_freq = Cy_SysClk_ClkPeriGetFrequency();
|
||
#elif defined(COMPONENT_CAT2)
|
||
uint32_t peri_freq = Cy_SysClk_ClkSysGetFrequency();
|
||
#endif
|
||
if (!obj->is_slave)
|
||
{
|
||
for (oversample_value = _CYHAL_SPI_OVERSAMPLE_MIN; oversample_value <= _CYHAL_SPI_OVERSAMPLE_MAX; oversample_value++)
|
||
{
|
||
oversampled_freq = hz * oversample_value;
|
||
if ((hz * oversample_value > peri_freq) && (_CYHAL_SPI_OVERSAMPLE_MIN == oversample_value))
|
||
{
|
||
return CYHAL_SPI_RSLT_CLOCK_ERROR;
|
||
}
|
||
else if (hz * oversample_value > peri_freq)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
divider_value = _cyhal_utils_divider_value(hz * oversample_value, 0);
|
||
divided_freq = peri_freq /divider_value;
|
||
diff = (oversampled_freq > divided_freq)
|
||
? oversampled_freq - divided_freq
|
||
: divided_freq - oversampled_freq;
|
||
|
||
if (diff < last_diff)
|
||
{
|
||
last_diff = diff;
|
||
last_ovrsmpl_val = oversample_value;
|
||
last_dvdr_val = divider_value;
|
||
if (0 == diff)
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
*over_sample_val = last_ovrsmpl_val;
|
||
}
|
||
else
|
||
{
|
||
/* Slave requires such frequency: required_frequency = N / ((0.5 * desired_period) – 20 nsec - tDSI,
|
||
* N is 3 when "Enable Input Glitch Filter" is false and 4 when true.
|
||
* tDSI Is external master delay which is assumed to be 16.66 nsec */
|
||
|
||
/* Divided by 2 desired period to avoid dividing in required_frequency formula */
|
||
float desired_period_us_divided = 5e5f * (1 / (float)hz);
|
||
uint32_t required_frequency = (uint32_t)(3e6f / (desired_period_us_divided - 36.66f / 1e3f));
|
||
|
||
if (required_frequency > peri_freq)
|
||
{
|
||
return CYHAL_SPI_RSLT_CLOCK_ERROR;
|
||
}
|
||
|
||
/* Use maximum available clock for slave to make it able to work with any master environment */
|
||
last_dvdr_val = 1;
|
||
}
|
||
|
||
result = Cy_SysClk_PeriphSetDivider((cy_en_divider_types_t)obj->clock.block, obj->clock.channel, last_dvdr_val - 1);
|
||
|
||
if (CY_RSLT_SUCCESS == result)
|
||
{
|
||
Cy_SysClk_PeriphEnableDivider((cy_en_divider_types_t)obj->clock.block, obj->clock.channel);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
static inline cyhal_spi_event_t _cyhal_spi_convert_interrupt_cause(uint32_t pdl_cause)
|
||
{
|
||
static const uint32_t status_map[] =
|
||
{
|
||
(uint32_t)CYHAL_SPI_IRQ_ERROR, // Default error if unknown value is set
|
||
(uint32_t)CYHAL_SPI_IRQ_DATA_IN_FIFO, // CY_SCB_SPI_TRANSFER_IN_FIFO_EVENT
|
||
(uint32_t)CYHAL_SPI_IRQ_DONE, // CY_SCB_SPI_TRANSFER_CMPLT_EVENT
|
||
(uint32_t)CYHAL_SPI_IRQ_ERROR, // CY_SCB_SPI_TRANSFER_ERR_EVENT
|
||
};
|
||
return (cyhal_spi_event_t)_cyhal_utils_convert_flags(status_map, sizeof(status_map) / sizeof(uint32_t), pdl_cause);
|
||
}
|
||
|
||
static void _cyhal_spi_irq_handler(void)
|
||
{
|
||
cyhal_spi_t *obj = (cyhal_spi_t*) _cyhal_scb_get_irq_obj();
|
||
if (NULL == obj)
|
||
{
|
||
return;
|
||
}
|
||
|
||
Cy_SCB_SPI_Interrupt(obj->base, &(obj->context));
|
||
|
||
if (!obj->is_async)
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (0 == (Cy_SCB_SPI_GetTransferStatus(obj->base, &obj->context) & CY_SCB_SPI_TRANSFER_ACTIVE))
|
||
{
|
||
if (obj->tx_buffer)
|
||
{
|
||
/* Start TX Transfer */
|
||
obj->pending = _CYHAL_SPI_PENDING_TX;
|
||
const uint8_t *buf = obj->tx_buffer;
|
||
obj->tx_buffer = NULL;
|
||
|
||
Cy_SCB_SPI_Transfer(obj->base, (uint8_t *)buf, NULL, obj->tx_buffer_size, &obj->context);
|
||
}
|
||
else if (obj->rx_buffer)
|
||
{
|
||
/* Start RX Transfer */
|
||
obj->pending = _CYHAL_SPI_PENDING_RX;
|
||
uint8_t *rx_buf = obj->rx_buffer;
|
||
uint8_t *tx_buf;
|
||
size_t trx_size = obj->rx_buffer_size;
|
||
|
||
if (obj->rx_buffer_size > 1)
|
||
{
|
||
/* In this case we don't have a transmit buffer; we only have a receive buffer. While the PDL
|
||
* is fine with passing NULL for transmit, we don't get to control what data it is sending in
|
||
* that case, which we allowed the user to set. To honor the user's request, we reuse the rx
|
||
* buffer as the tx buffer too. We set all bytes beyond the one we will start filling in with
|
||
* the user provided 'write_fill'. This means the tx buffer is 1 element smaller than the rx
|
||
* buffer. As a result, we must therefore transfer 1 less element then we really want to in
|
||
* this transfer. When this transfer is complete, it will call into this again to receive the
|
||
* final element.
|
||
*/
|
||
trx_size -= 1; // Transfer everything left except for the last byte
|
||
|
||
uint8_t **rx_buffer_p = (uint8_t **) &obj->rx_buffer;
|
||
|
||
tx_buf = *rx_buffer_p + 1; // Start at second byte to avoid trying to transmit and receive the same byte
|
||
memset(tx_buf, obj->write_fill, trx_size);
|
||
|
||
*rx_buffer_p += trx_size; // Move to 1 byte before end
|
||
obj->rx_buffer_size = 1; // Transfer the last byte on the next interrupt
|
||
}
|
||
else
|
||
{
|
||
tx_buf = &obj->write_fill;
|
||
|
||
obj->rx_buffer = NULL;
|
||
}
|
||
|
||
Cy_SCB_SPI_Transfer(obj->base, tx_buf, rx_buf, trx_size, &obj->context);
|
||
}
|
||
else
|
||
{
|
||
/* Finish Async Transfer */
|
||
obj->pending = _CYHAL_SPI_PENDING_NONE;
|
||
obj->is_async = false;
|
||
_cyhal_ssel_switch_state(obj, obj->active_ssel, _CYHAL_SPI_SSEL_DEACTIVATE);
|
||
}
|
||
}
|
||
}
|
||
|
||
static void _cyhal_spi_cb_wrapper(uint32_t event)
|
||
{
|
||
cyhal_spi_t *obj = (cyhal_spi_t*) _cyhal_scb_get_irq_obj();
|
||
cyhal_spi_irq_event_t anded_events = (cyhal_spi_irq_event_t) (obj->irq_cause & (uint32_t) _cyhal_spi_convert_interrupt_cause(event));
|
||
|
||
// Don't call the callback until the final transfer has put everything in the FIFO/completed
|
||
if ((anded_events & (CYHAL_SPI_IRQ_DATA_IN_FIFO | CYHAL_SPI_IRQ_DONE)) && !(obj->rx_buffer == NULL && obj->tx_buffer == NULL))
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (anded_events)
|
||
{
|
||
cyhal_spi_event_callback_t callback = (cyhal_spi_event_callback_t) obj->callback_data.callback;
|
||
callback(obj->callback_data.callback_arg, anded_events);
|
||
}
|
||
}
|
||
|
||
static cy_en_scb_spi_sclk_mode_t _cyhal_convert_mode_sclk(cyhal_spi_mode_t mode)
|
||
{
|
||
uint8_t sclk_mode = (mode & (CYHAL_SPI_MODE_FLAG_CPOL | CYHAL_SPI_MODE_FLAG_CPHA));
|
||
|
||
switch (sclk_mode)
|
||
{
|
||
case CYHAL_SPI_MODE_FLAG_CPOL | CYHAL_SPI_MODE_FLAG_CPHA:
|
||
return (CY_SCB_SPI_CPHA1_CPOL1);
|
||
case CYHAL_SPI_MODE_FLAG_CPOL:
|
||
return (CY_SCB_SPI_CPHA0_CPOL1);
|
||
case CYHAL_SPI_MODE_FLAG_CPHA:
|
||
return (CY_SCB_SPI_CPHA1_CPOL0);
|
||
default:
|
||
return (CY_SCB_SPI_CPHA0_CPOL0);
|
||
}
|
||
}
|
||
|
||
static inline bool _is_cyhal_mode_msb(cyhal_spi_mode_t mode)
|
||
{
|
||
return ((mode & CYHAL_SPI_MODE_FLAG_LSB) != CYHAL_SPI_MODE_FLAG_LSB);
|
||
}
|
||
|
||
static bool _cyhal_spi_pm_callback_instance(void *obj_ptr, cyhal_syspm_callback_state_t state, cy_en_syspm_callback_mode_t pdl_mode)
|
||
{
|
||
cyhal_spi_t *obj = (cyhal_spi_t *)obj_ptr;
|
||
bool allow = true;
|
||
cy_stc_syspm_callback_params_t spi_callback_params = {
|
||
.base = (void *) (obj->base),
|
||
.context = (void *) &(obj->context)
|
||
};
|
||
|
||
if (CYHAL_SYSPM_CB_CPU_DEEPSLEEP == state)
|
||
allow = (CY_SYSPM_SUCCESS == Cy_SCB_SPI_DeepSleepCallback(&spi_callback_params, pdl_mode));
|
||
#if defined(COMPONENT_CAT1A) || defined(COMPONENT_CAT1B)
|
||
else if (CYHAL_SYSPM_CB_SYSTEM_HIBERNATE == state)
|
||
allow = (CY_SYSPM_SUCCESS == Cy_SCB_SPI_HibernateCallback(&spi_callback_params, pdl_mode));
|
||
#endif
|
||
|
||
return allow;
|
||
}
|
||
|
||
static cy_rslt_t _cyhal_spi_get_ssel_map_idx(cyhal_spi_t *obj, cyhal_gpio_t ssel,
|
||
const cyhal_resource_pin_mapping_t **ssel_map, uint8_t *idx)
|
||
{
|
||
#ifdef CY_IP_M0S8SCB
|
||
/* SSEL0 is only available for Slave on M0S8SCB */
|
||
static const cyhal_resource_pin_mapping_t *ssel_s_pin_maps[] = { cyhal_pin_map_scb_spi_s_select0 };
|
||
static const size_t ssel_s_pin_maps_sizes_bytes[] = { sizeof(cyhal_pin_map_scb_spi_s_select0) };
|
||
#else
|
||
static const cyhal_resource_pin_mapping_t *ssel_s_pin_maps[] = {
|
||
cyhal_pin_map_scb_spi_s_select0, cyhal_pin_map_scb_spi_s_select1,
|
||
cyhal_pin_map_scb_spi_s_select2, cyhal_pin_map_scb_spi_s_select3 };
|
||
static const size_t ssel_s_pin_maps_sizes_bytes[] = {
|
||
sizeof(cyhal_pin_map_scb_spi_s_select0), sizeof(cyhal_pin_map_scb_spi_s_select1),
|
||
sizeof(cyhal_pin_map_scb_spi_s_select2), sizeof(cyhal_pin_map_scb_spi_s_select3) };
|
||
#endif /* M0S8 version of SCB or other */
|
||
for (uint8_t i = 0; i < sizeof(ssel_s_pin_maps) / sizeof(ssel_s_pin_maps[0]); i++)
|
||
{
|
||
*ssel_map = _cyhal_scb_find_map(ssel, ssel_s_pin_maps[i],
|
||
ssel_s_pin_maps_sizes_bytes[i] / sizeof(cyhal_resource_pin_mapping_t), &(obj->resource));
|
||
if (NULL != *ssel_map)
|
||
{
|
||
*idx = i;
|
||
return CY_RSLT_SUCCESS;
|
||
}
|
||
}
|
||
return CYHAL_SPI_RSLT_ERR_CANNOT_CONFIG_SSEL;
|
||
}
|
||
|
||
cy_rslt_t cyhal_spi_init(cyhal_spi_t *obj, cyhal_gpio_t mosi, cyhal_gpio_t miso, cyhal_gpio_t sclk, cyhal_gpio_t ssel,
|
||
const cyhal_clock_t *clk, uint8_t bits, cyhal_spi_mode_t mode, bool is_slave)
|
||
{
|
||
CY_ASSERT(NULL != obj);
|
||
memset(obj, 0, sizeof(cyhal_spi_t));
|
||
|
||
cy_rslt_t result = CY_RSLT_SUCCESS;
|
||
uint8_t ovr_sample_val = _CYHAL_SPI_OVERSAMPLE_MIN;
|
||
obj->pending = _CYHAL_SPI_PENDING_NONE;
|
||
|
||
// Explicitly marked not allocated resources as invalid to prevent freeing them.
|
||
obj->resource.type = CYHAL_RSC_INVALID;
|
||
obj->pin_miso = NC;
|
||
obj->pin_mosi = NC;
|
||
obj->pin_sclk = NC;
|
||
|
||
for (uint8_t i = 0; i < _CYHAL_SPI_SSEL_NUM; i++)
|
||
{
|
||
obj->pin_ssel[i] = NC;
|
||
obj->ssel_pol[i] = CY_SCB_SPI_ACTIVE_LOW;
|
||
}
|
||
|
||
obj->write_fill = (uint8_t) CY_SCB_SPI_DEFAULT_TX;
|
||
obj->active_ssel = 0;
|
||
|
||
/* Validate pins configuration. Mandatory pins:*/
|
||
/* Master mode: MOSI pin used, MISO unused: SCLK, SSEL are optional */
|
||
/* Master mode: MISO pin used, MOSI unused: SCLK is mandatory, MOSI, SSEL are optional */
|
||
/* Slave mode: MOSI or MISO are used: SCLK and SSEL are mandatory */
|
||
|
||
/* Slave */
|
||
if (is_slave)
|
||
{
|
||
if ((NC == sclk) || (NC == ssel) || ((NC == mosi) && (NC == miso)))
|
||
{
|
||
return CYHAL_SPI_RSLT_PIN_CONFIG_NOT_SUPPORTED;
|
||
}
|
||
}
|
||
/* Master */
|
||
else
|
||
{
|
||
if ((NC != miso && NC == sclk) || (NC == mosi && NC == miso))
|
||
{
|
||
return CYHAL_SPI_RSLT_PIN_CONFIG_NOT_SUPPORTED;
|
||
}
|
||
}
|
||
|
||
obj->is_slave = is_slave;
|
||
|
||
/* Get pin configurations */
|
||
const cyhal_resource_pin_mapping_t *mosi_map = NULL;
|
||
const cyhal_resource_pin_mapping_t *miso_map = NULL;
|
||
const cyhal_resource_pin_mapping_t *sclk_map = NULL;
|
||
const cyhal_resource_pin_mapping_t *ssel_map = NULL;
|
||
uint8_t active_ssel = 0;
|
||
if (is_slave)
|
||
{
|
||
mosi_map = _CYHAL_SCB_FIND_MAP(mosi, cyhal_pin_map_scb_spi_s_mosi);
|
||
miso_map = _CYHAL_SCB_FIND_MAP(miso, cyhal_pin_map_scb_spi_s_miso);
|
||
sclk_map = _CYHAL_SCB_FIND_MAP(sclk, cyhal_pin_map_scb_spi_s_clk);
|
||
result = _cyhal_spi_get_ssel_map_idx(obj, ssel, &ssel_map, &active_ssel);
|
||
}
|
||
else
|
||
{
|
||
mosi_map = _CYHAL_SCB_FIND_MAP(mosi, cyhal_pin_map_scb_spi_m_mosi);
|
||
miso_map = _CYHAL_SCB_FIND_MAP(miso, cyhal_pin_map_scb_spi_m_miso);
|
||
sclk_map = _CYHAL_SCB_FIND_MAP(sclk, cyhal_pin_map_scb_spi_m_clk);
|
||
/* No need to find maps for ssel pins, as GPIO used */
|
||
}
|
||
|
||
const cyhal_resource_inst_t *spi_inst = (NC != mosi)
|
||
? (mosi_map != NULL ? mosi_map->inst : NULL)
|
||
: (miso_map != NULL ? miso_map->inst : NULL);
|
||
|
||
/* Validate pins mapping */
|
||
if (NULL == spi_inst ||
|
||
((NC != mosi) && ((NULL == mosi_map) || !_cyhal_utils_resources_equal(spi_inst, mosi_map->inst))) ||
|
||
((NC != miso) && ((NULL == miso_map) || !_cyhal_utils_resources_equal(spi_inst, miso_map->inst))) ||
|
||
((NC != sclk) && ((NULL == sclk_map) || !_cyhal_utils_resources_equal(spi_inst, sclk_map->inst))) ||
|
||
((is_slave) && ((NC != ssel) && ((NULL == ssel_map) || !_cyhal_utils_resources_equal(spi_inst, ssel_map->inst)))))
|
||
{
|
||
return CYHAL_SPI_RSLT_ERR_INVALID_PIN;
|
||
}
|
||
|
||
if (CY_RSLT_SUCCESS != (result = cyhal_hwmgr_reserve(spi_inst)))
|
||
{
|
||
return result;
|
||
}
|
||
|
||
obj->resource = *spi_inst;
|
||
obj->base = _CYHAL_SCB_BASE_ADDRESSES[obj->resource.block_num];
|
||
|
||
// reserve the MOSI pin
|
||
if ((result == CY_RSLT_SUCCESS) && (NC != mosi))
|
||
{
|
||
result = _cyhal_utils_reserve_and_connect(mosi, mosi_map);
|
||
if (result == CY_RSLT_SUCCESS)
|
||
{
|
||
obj->pin_mosi = mosi;
|
||
}
|
||
}
|
||
|
||
// reserve the MISO pin
|
||
if ((result == CY_RSLT_SUCCESS) && (NC != miso))
|
||
{
|
||
result = _cyhal_utils_reserve_and_connect(miso, miso_map);
|
||
if (result == CY_RSLT_SUCCESS)
|
||
{
|
||
obj->pin_miso = miso;
|
||
}
|
||
}
|
||
|
||
// reserve the SCLK pin
|
||
if (result == CY_RSLT_SUCCESS && (NC != sclk))
|
||
{
|
||
result = _cyhal_utils_reserve_and_connect(sclk, sclk_map);
|
||
if (result == CY_RSLT_SUCCESS)
|
||
{
|
||
obj->pin_sclk = sclk;
|
||
}
|
||
}
|
||
|
||
// reserve and configure the SSEL pin
|
||
if ((result == CY_RSLT_SUCCESS) && (NC != ssel))
|
||
{
|
||
result = cyhal_spi_slave_select_config(obj, ssel, CYHAL_SPI_SSEL_ACTIVE_LOW);
|
||
}
|
||
|
||
if (result == CY_RSLT_SUCCESS)
|
||
{
|
||
if (clk == NULL)
|
||
{
|
||
result = cyhal_clock_allocate(&(obj->clock), CYHAL_CLOCK_BLOCK_PERIPHERAL_16BIT);
|
||
obj->alloc_clock = true;
|
||
}
|
||
else
|
||
{
|
||
|
||
obj->clock = *clk;
|
||
obj->alloc_clock = false;
|
||
_cyhal_utils_update_clock_format(&(obj->clock));
|
||
|
||
/* Per CDT 315848 and 002-20730 Rev. *E:
|
||
* For SPI, an integer clock divider must be used for both master and slave. */
|
||
if ((obj->clock.block == CYHAL_CLOCK_BLOCK_PERIPHERAL_16_5BIT) || (obj->clock.block == CYHAL_CLOCK_BLOCK_PERIPHERAL_24_5BIT))
|
||
{
|
||
result = CYHAL_SPI_RSLT_CLOCK_NOT_SUPPORTED;
|
||
}
|
||
}
|
||
}
|
||
if (result == CY_RSLT_SUCCESS)
|
||
{
|
||
result = (cy_rslt_t)Cy_SysClk_PeriphAssignDivider(
|
||
_cyhal_scb_get_clock_index(obj->resource.block_num),
|
||
(cy_en_divider_types_t)obj->clock.block, obj->clock.channel);
|
||
|
||
if (result == CY_RSLT_SUCCESS)
|
||
{
|
||
result = _cyhal_spi_int_frequency(obj, _CYHAL_SPI_DEFAULT_SPEED, &ovr_sample_val);
|
||
}
|
||
}
|
||
|
||
if (result == CY_RSLT_SUCCESS)
|
||
{
|
||
_cyhal_scb_update_instance_data(obj->resource.block_num, (void*)obj, &_cyhal_spi_pm_callback_instance);
|
||
cy_stc_scb_spi_config_t config_structure = _cyhal_spi_default_config;
|
||
config_structure.spiMode = is_slave == 0
|
||
? CY_SCB_SPI_MASTER
|
||
: CY_SCB_SPI_SLAVE;
|
||
obj->msb_first = _is_cyhal_mode_msb(mode);
|
||
config_structure.enableMsbFirst = obj->msb_first;
|
||
obj->clk_mode = _cyhal_convert_mode_sclk(mode);
|
||
config_structure.sclkMode = obj->clk_mode;
|
||
config_structure.rxDataWidth = bits;
|
||
config_structure.txDataWidth = bits;
|
||
config_structure.oversample = ovr_sample_val;
|
||
obj->data_bits = bits;
|
||
obj->mode = (uint8_t) mode;
|
||
obj->oversample_value = ovr_sample_val;
|
||
Cy_SCB_SPI_Init(obj->base, &config_structure, &(obj->context));
|
||
|
||
/* Activating specified by user ssel after init */
|
||
if (NC != ssel)
|
||
{
|
||
result = cyhal_spi_select_active_ssel(obj, ssel);
|
||
}
|
||
|
||
obj->callback_data.callback = NULL;
|
||
obj->callback_data.callback_arg = NULL;
|
||
obj->irq_cause = 0;
|
||
|
||
cy_stc_sysint_t irqCfg = { _CYHAL_SCB_IRQ_N[obj->resource.block_num], CYHAL_ISR_PRIORITY_DEFAULT };
|
||
Cy_SysInt_Init(&irqCfg, _cyhal_spi_irq_handler);
|
||
NVIC_EnableIRQ(_CYHAL_SCB_IRQ_N[obj->resource.block_num]);
|
||
|
||
Cy_SCB_SPI_Enable(obj->base);
|
||
}
|
||
else
|
||
{
|
||
cyhal_spi_free(obj);
|
||
}
|
||
return result;
|
||
}
|
||
|
||
void cyhal_spi_free(cyhal_spi_t *obj)
|
||
{
|
||
if (NULL != obj->base)
|
||
{
|
||
_cyhal_scb_update_instance_data(obj->resource.block_num, NULL, NULL);
|
||
Cy_SCB_SPI_Disable(obj->base, NULL);
|
||
Cy_SCB_SPI_DeInit(obj->base);
|
||
obj->base = NULL;
|
||
}
|
||
|
||
if (obj->resource.type != CYHAL_RSC_INVALID)
|
||
{
|
||
IRQn_Type irqn = _CYHAL_SCB_IRQ_N[obj->resource.block_num];
|
||
NVIC_DisableIRQ(irqn);
|
||
|
||
cyhal_hwmgr_free(&(obj->resource));
|
||
obj->resource.type = CYHAL_RSC_INVALID;
|
||
}
|
||
|
||
_cyhal_utils_release_if_used(&(obj->pin_miso));
|
||
_cyhal_utils_release_if_used(&(obj->pin_mosi));
|
||
_cyhal_utils_release_if_used(&(obj->pin_sclk));
|
||
for (uint8_t i = 0; i < _CYHAL_SPI_SSEL_NUM; i++)
|
||
{
|
||
_cyhal_utils_release_if_used(&(obj->pin_ssel[i]));
|
||
}
|
||
|
||
if (obj->alloc_clock)
|
||
{
|
||
cyhal_clock_free(&(obj->clock));
|
||
obj->alloc_clock = false;
|
||
}
|
||
}
|
||
|
||
static void _cyhal_ssel_switch_state(cyhal_spi_t *obj, uint8_t ssel_idx, bool ssel_activate)
|
||
{
|
||
if ((!obj->is_slave) && (CYHAL_NC_PIN_VALUE != obj->pin_ssel[ssel_idx]))
|
||
{
|
||
/* Situations described:
|
||
* ssel_activate = true (need to set SSEL into active state)
|
||
* CY_SCB_SPI_ACTIVE_LOW - writing 0 to ssel pin
|
||
* CY_SCB_SPI_ACTIVE_HIGH - writing 1 to ssel pin
|
||
* ssel_activate = false (need to set SSEL into inactive state)
|
||
* CY_SCB_SPI_ACTIVE_LOW - writing 1 to ssel pin
|
||
* CY_SCB_SPI_ACTIVE_HIGH - writing 0 to ssel pin */
|
||
bool ssel_state = (CY_SCB_SPI_ACTIVE_LOW == obj->ssel_pol[ssel_idx]) ? !ssel_activate : ssel_activate;
|
||
cyhal_gpio_write(obj->pin_ssel[ssel_idx], ssel_state);
|
||
}
|
||
}
|
||
|
||
cy_rslt_t cyhal_spi_set_frequency(cyhal_spi_t *obj, uint32_t hz)
|
||
{
|
||
cy_rslt_t result = CY_RSLT_SUCCESS;
|
||
uint8_t ovr_sample_val;
|
||
|
||
if (NULL == obj)
|
||
{
|
||
return CYHAL_SPI_RSLT_BAD_ARGUMENT;
|
||
}
|
||
|
||
Cy_SCB_SPI_Disable(obj->base, &obj->context);
|
||
result = _cyhal_spi_int_frequency(obj, hz, &ovr_sample_val);
|
||
|
||
/* No need to reconfigure slave since oversample value, that was changed in _cyhal_spi_int_frequency, in slave is ignored */
|
||
if ((CY_RSLT_SUCCESS == result) && !obj->is_slave && (obj->oversample_value != ovr_sample_val))
|
||
{
|
||
cy_stc_scb_spi_config_t config_structure = _cyhal_spi_default_config;
|
||
Cy_SCB_SPI_DeInit(obj->base);
|
||
config_structure.spiMode = obj->is_slave == false
|
||
? CY_SCB_SPI_MASTER
|
||
: CY_SCB_SPI_SLAVE;
|
||
config_structure.enableMsbFirst = obj->msb_first;
|
||
config_structure.sclkMode = obj->clk_mode;
|
||
config_structure.rxDataWidth = obj->data_bits;
|
||
config_structure.txDataWidth = obj->data_bits;
|
||
config_structure.oversample = ovr_sample_val;
|
||
obj->oversample_value = ovr_sample_val;
|
||
Cy_SCB_SPI_Init(obj->base, &config_structure, &(obj->context));
|
||
}
|
||
|
||
Cy_SCB_SPI_Enable(obj->base);
|
||
|
||
return result;
|
||
}
|
||
|
||
cy_rslt_t cyhal_spi_select_active_ssel(cyhal_spi_t *obj, cyhal_gpio_t ssel)
|
||
{
|
||
CY_ASSERT(NULL != obj);
|
||
CY_ASSERT(NULL != obj->base);
|
||
if ((NC != ssel) && (_CYHAL_SPI_PENDING_NONE == obj->pending))
|
||
{
|
||
for (uint8_t i = 0; i < _CYHAL_SPI_SSEL_NUM; i++)
|
||
{
|
||
if(obj->pin_ssel[i] == ssel)
|
||
{
|
||
Cy_SCB_SPI_SetActiveSlaveSelect(obj->base, (cy_en_scb_spi_slave_select_t)i);
|
||
obj->active_ssel = i;
|
||
return CY_RSLT_SUCCESS;
|
||
}
|
||
}
|
||
}
|
||
return CYHAL_SPI_RSLT_ERR_CANNOT_SWITCH_SSEL;
|
||
}
|
||
|
||
static inline cy_en_scb_spi_polarity_t _cyhal_spi_pol_from_hal_to_pdl(cyhal_spi_ssel_polarity_t hal_polarity)
|
||
{
|
||
return (hal_polarity == CYHAL_SPI_SSEL_ACTIVE_HIGH) ? CY_SCB_SPI_ACTIVE_HIGH : CY_SCB_SPI_ACTIVE_LOW;
|
||
}
|
||
|
||
cy_rslt_t cyhal_spi_slave_select_config(cyhal_spi_t *obj, cyhal_gpio_t ssel, cyhal_spi_ssel_polarity_t polarity)
|
||
{
|
||
CY_ASSERT(NULL != obj);
|
||
cy_rslt_t result = CYHAL_SPI_RSLT_ERR_CANNOT_CONFIG_SSEL;
|
||
uint8_t found_idx = 0;
|
||
bool configuring_existing = false;
|
||
if ((NC != ssel) && (_CYHAL_SPI_PENDING_NONE == obj->pending))
|
||
{
|
||
for (uint8_t i = 0; i < _CYHAL_SPI_SSEL_NUM; i++)
|
||
{
|
||
if ((configuring_existing = (ssel == obj->pin_ssel[i])))
|
||
{
|
||
result = CY_RSLT_SUCCESS;
|
||
found_idx = i;
|
||
break;
|
||
}
|
||
if (!obj->is_slave)
|
||
{
|
||
/* Looking for first available ssel slot */
|
||
if ((NC == obj->pin_ssel[i]))
|
||
{
|
||
result = cyhal_gpio_init(ssel, CYHAL_GPIO_DIR_OUTPUT, CYHAL_GPIO_DRIVE_STRONG,
|
||
(polarity == CYHAL_SPI_SSEL_ACTIVE_LOW) ? true : false);
|
||
found_idx = i;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
if (!configuring_existing && (obj->is_slave))
|
||
{
|
||
const cyhal_resource_pin_mapping_t *ssel_map = NULL;
|
||
if (CY_RSLT_SUCCESS == _cyhal_spi_get_ssel_map_idx(obj, ssel, &ssel_map, &found_idx))
|
||
{
|
||
/* Either mosi or miso should present. Will take one of them as instance SCB instance index source */
|
||
const cyhal_resource_pin_mapping_t *data_pin_map = (NC != obj->pin_mosi) ?
|
||
_CYHAL_SCB_FIND_MAP_BLOCK(obj->pin_mosi, cyhal_pin_map_scb_spi_s_mosi, &(obj->resource)) :
|
||
_CYHAL_SCB_FIND_MAP_BLOCK(obj->pin_miso, cyhal_pin_map_scb_spi_s_miso, &(obj->resource));
|
||
|
||
if ((NULL != ssel_map) && (NC == obj->pin_ssel[found_idx]) &&
|
||
_cyhal_utils_resources_equal(data_pin_map->inst, ssel_map->inst))
|
||
{
|
||
result = _cyhal_utils_reserve_and_connect(ssel, ssel_map);
|
||
}
|
||
}
|
||
}
|
||
if (CY_RSLT_SUCCESS == result)
|
||
{
|
||
if (!configuring_existing)
|
||
obj->pin_ssel[found_idx] = ssel;
|
||
obj->ssel_pol[found_idx] = _cyhal_spi_pol_from_hal_to_pdl(polarity);
|
||
|
||
/* Immediatelly apply updated slave select polarity */
|
||
Cy_SCB_SPI_SetActiveSlaveSelectPolarity(obj->base, (cy_en_scb_spi_slave_select_t)found_idx, obj->ssel_pol[found_idx]);
|
||
if (!obj->is_slave)
|
||
_cyhal_ssel_switch_state(obj, found_idx, _CYHAL_SPI_SSEL_DEACTIVATE);
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
cy_rslt_t cyhal_spi_recv(cyhal_spi_t *obj, uint32_t *value)
|
||
{
|
||
if (NULL == obj)
|
||
return CYHAL_SPI_RSLT_BAD_ARGUMENT;
|
||
|
||
if (_cyhal_scb_pm_transition_pending())
|
||
return CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
|
||
|
||
uint32_t read_value = CY_SCB_SPI_RX_NO_DATA;
|
||
const uint32_t fill_in = 0x0000ffffUL; /* PDL Fill in value */
|
||
uint32_t count = 0;
|
||
|
||
if ((obj->is_slave) && (CYHAL_NC_PIN_VALUE == obj->pin_mosi))
|
||
{
|
||
return CYHAL_SPI_RSLT_INVALID_PIN_API_NOT_SUPPORTED;
|
||
}
|
||
|
||
if ((!obj->is_slave) && (CYHAL_NC_PIN_VALUE == obj->pin_miso))
|
||
{
|
||
return CYHAL_SPI_RSLT_INVALID_PIN_API_NOT_SUPPORTED;
|
||
}
|
||
|
||
if (!obj->is_slave)
|
||
{
|
||
_cyhal_ssel_switch_state(obj, obj->active_ssel, _CYHAL_SPI_SSEL_ACTIVATE);
|
||
|
||
/* Clear FIFOs */
|
||
Cy_SCB_SPI_ClearTxFifo(obj->base);
|
||
Cy_SCB_SPI_ClearRxFifo(obj->base);
|
||
|
||
while (count == 0)
|
||
{
|
||
count = Cy_SCB_SPI_Write(obj->base, fill_in);
|
||
}
|
||
|
||
while (Cy_SCB_SPI_IsTxComplete(obj->base) == false) { }
|
||
while (Cy_SCB_SPI_GetNumInRxFifo(obj->base) == 0) { } /* Wait for RX FIFO not empty */
|
||
_cyhal_ssel_switch_state(obj, obj->active_ssel, _CYHAL_SPI_SSEL_DEACTIVATE);
|
||
}
|
||
|
||
while (read_value == CY_SCB_SPI_RX_NO_DATA)
|
||
{
|
||
read_value = Cy_SCB_SPI_Read(obj->base);
|
||
}
|
||
*value = read_value;
|
||
return CY_RSLT_SUCCESS;
|
||
}
|
||
|
||
cy_rslt_t cyhal_spi_send(cyhal_spi_t *obj, uint32_t value)
|
||
{
|
||
if (NULL == obj)
|
||
return CYHAL_SPI_RSLT_BAD_ARGUMENT;
|
||
|
||
if (_cyhal_scb_pm_transition_pending())
|
||
return CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
|
||
|
||
uint32_t count = 0;
|
||
cy_rslt_t result = CY_RSLT_SUCCESS;
|
||
|
||
if ((obj->is_slave) && (CYHAL_NC_PIN_VALUE == obj->pin_miso))
|
||
{
|
||
return CYHAL_SPI_RSLT_INVALID_PIN_API_NOT_SUPPORTED;
|
||
}
|
||
|
||
if ((!obj->is_slave) && (CYHAL_NC_PIN_VALUE == obj->pin_mosi))
|
||
{
|
||
return CYHAL_SPI_RSLT_INVALID_PIN_API_NOT_SUPPORTED;
|
||
}
|
||
|
||
if (!obj->is_slave)
|
||
{
|
||
_cyhal_ssel_switch_state(obj, obj->active_ssel, _CYHAL_SPI_SSEL_ACTIVATE);
|
||
|
||
/* Clear FIFOs */
|
||
Cy_SCB_SPI_ClearTxFifo(obj->base);
|
||
Cy_SCB_SPI_ClearRxFifo(obj->base);
|
||
}
|
||
|
||
while (count == 0)
|
||
{
|
||
count = Cy_SCB_SPI_Write(obj->base, value);
|
||
}
|
||
|
||
if (!obj->is_slave)
|
||
{
|
||
while (Cy_SCB_SPI_IsTxComplete(obj->base) == false) { }
|
||
while (Cy_SCB_SPI_GetNumInRxFifo(obj->base) == 0) { } /* Wait for RX FIFO not empty */
|
||
_cyhal_ssel_switch_state(obj, obj->active_ssel, _CYHAL_SPI_SSEL_DEACTIVATE);
|
||
(void)Cy_SCB_SPI_Read(obj->base);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
cy_rslt_t cyhal_spi_transfer(cyhal_spi_t *obj, const uint8_t *tx, size_t tx_length, uint8_t *rx, size_t rx_length, uint8_t write_fill)
|
||
{
|
||
if (NULL == obj)
|
||
return CYHAL_SPI_RSLT_BAD_ARGUMENT;
|
||
|
||
if (_cyhal_scb_pm_transition_pending())
|
||
return CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
|
||
|
||
obj->write_fill = write_fill;
|
||
cy_rslt_t rslt = cyhal_spi_transfer_async(obj, tx, tx_length, rx, rx_length);
|
||
if (rslt == CY_RSLT_SUCCESS)
|
||
{
|
||
while (obj->pending != _CYHAL_SPI_PENDING_NONE) { } /* Wait for async transfer to complete */
|
||
}
|
||
obj->write_fill = (uint8_t) CY_SCB_SPI_DEFAULT_TX;
|
||
return rslt;
|
||
}
|
||
|
||
cy_rslt_t cyhal_spi_transfer_async(cyhal_spi_t *obj, const uint8_t *tx, size_t tx_length, uint8_t *rx, size_t rx_length)
|
||
{
|
||
if (NULL == obj)
|
||
return CYHAL_SPI_RSLT_BAD_ARGUMENT;
|
||
|
||
if (_cyhal_scb_pm_transition_pending())
|
||
return CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
|
||
|
||
cy_en_scb_spi_status_t spi_status;
|
||
|
||
if ((CYHAL_NC_PIN_VALUE == obj->pin_mosi) || (CYHAL_NC_PIN_VALUE == obj->pin_miso))
|
||
{
|
||
return CYHAL_SPI_RSLT_INVALID_PIN_API_NOT_SUPPORTED;
|
||
}
|
||
|
||
_cyhal_ssel_switch_state(obj, obj->active_ssel, _CYHAL_SPI_SSEL_ACTIVATE);
|
||
obj->is_async = true;
|
||
|
||
/* Setup transfer */
|
||
if (tx_length > rx_length)
|
||
{
|
||
if (rx_length > 0)
|
||
{
|
||
/* I) write + read, II) write only */
|
||
obj->pending = _CYHAL_SPI_PENDING_TX_RX;
|
||
obj->rx_buffer = NULL;
|
||
|
||
obj->tx_buffer = tx + (obj->data_bits <= 8 ? rx_length : (rx_length * 2));
|
||
obj->tx_buffer_size = tx_length - rx_length;
|
||
|
||
tx_length = rx_length; // Use tx_length to store entire transfer length
|
||
}
|
||
else
|
||
{
|
||
/* I) write only */
|
||
obj->pending = _CYHAL_SPI_PENDING_TX;
|
||
obj->rx_buffer = NULL;
|
||
obj->tx_buffer = NULL;
|
||
|
||
rx = NULL;
|
||
}
|
||
}
|
||
else if (rx_length > tx_length)
|
||
{
|
||
if (tx_length > 0)
|
||
{
|
||
/* I) write + read, II) read only */
|
||
obj->pending = _CYHAL_SPI_PENDING_TX_RX;
|
||
obj->tx_buffer = NULL;
|
||
|
||
obj->rx_buffer = rx + (obj->data_bits <= 8 ? tx_length : (tx_length * 2));
|
||
obj->rx_buffer_size = rx_length - tx_length;
|
||
}
|
||
else
|
||
{
|
||
/* I) read only. */
|
||
obj->pending = _CYHAL_SPI_PENDING_RX;
|
||
obj->tx_buffer = NULL;
|
||
|
||
obj->rx_buffer = rx_length > 1 ? rx + 1 : NULL;
|
||
obj->rx_buffer_size = rx_length - 1;
|
||
tx = &obj->write_fill;
|
||
tx_length = 1;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* RX and TX of the same size: I) write + read. */
|
||
obj->pending = _CYHAL_SPI_PENDING_TX_RX;
|
||
obj->rx_buffer = NULL;
|
||
obj->tx_buffer = NULL;
|
||
}
|
||
spi_status = Cy_SCB_SPI_Transfer(obj->base, (void *)tx, rx, tx_length, &obj->context);
|
||
return spi_status == CY_SCB_SPI_SUCCESS
|
||
? CY_RSLT_SUCCESS
|
||
: CYHAL_SPI_RSLT_TRANSFER_ERROR;
|
||
}
|
||
|
||
bool cyhal_spi_is_busy(cyhal_spi_t *obj)
|
||
{
|
||
return Cy_SCB_SPI_IsBusBusy(obj->base) || (_CYHAL_SPI_PENDING_NONE != obj->pending);
|
||
}
|
||
|
||
cy_rslt_t cyhal_spi_abort_async(cyhal_spi_t *obj)
|
||
{
|
||
if (NULL == obj)
|
||
{
|
||
return CYHAL_SPI_RSLT_BAD_ARGUMENT;
|
||
}
|
||
|
||
Cy_SCB_SPI_AbortTransfer(obj->base, &(obj->context));
|
||
obj->pending = _CYHAL_SPI_PENDING_NONE;
|
||
return CY_RSLT_SUCCESS;
|
||
}
|
||
|
||
void cyhal_spi_register_callback(cyhal_spi_t *obj, cyhal_spi_event_callback_t callback, void *callback_arg)
|
||
{
|
||
uint32_t savedIntrStatus = cyhal_system_critical_section_enter();
|
||
obj->callback_data.callback = (cy_israddress) callback;
|
||
obj->callback_data.callback_arg = callback_arg;
|
||
cyhal_system_critical_section_exit(savedIntrStatus);
|
||
Cy_SCB_SPI_RegisterCallback(obj->base, _cyhal_spi_cb_wrapper, &(obj->context));
|
||
|
||
obj->irq_cause = 0;
|
||
}
|
||
|
||
void cyhal_spi_enable_event(cyhal_spi_t *obj, cyhal_spi_event_t event, uint8_t intr_priority, bool enable)
|
||
{
|
||
if (enable)
|
||
{
|
||
obj->irq_cause |= event;
|
||
}
|
||
else
|
||
{
|
||
obj->irq_cause &= ~event;
|
||
}
|
||
|
||
IRQn_Type irqn = _CYHAL_SCB_IRQ_N[obj->resource.block_num];
|
||
NVIC_SetPriority(irqn, intr_priority);
|
||
}
|
||
|
||
cy_rslt_t cyhal_spi_set_fifo_level(cyhal_spi_t *obj, cyhal_spi_fifo_type_t type, uint16_t level)
|
||
{
|
||
return _cyhal_scb_set_fifo_level(obj->base, (cyhal_scb_fifo_type_t)type, level);
|
||
}
|
||
|
||
cy_rslt_t cyhal_spi_enable_output(cyhal_spi_t *obj, cyhal_spi_output_t output, cyhal_source_t *source)
|
||
{
|
||
return _cyhal_scb_enable_output(obj->base, obj->resource, (cyhal_scb_output_t)output, source);
|
||
}
|
||
|
||
cy_rslt_t cyhal_spi_disable_output(cyhal_spi_t *obj, cyhal_spi_output_t output)
|
||
{
|
||
return _cyhal_scb_disable_output(obj->base, obj->resource, (cyhal_scb_output_t)output);
|
||
}
|
||
|
||
#if defined(__cplusplus)
|
||
}
|
||
#endif
|
||
|
||
#endif /* CY_IP_MXSCB */
|