Portenta add interface to cypress hal

pull/14663/head
Martino Facchin 2021-03-16 11:14:15 +01:00 committed by pennam
parent ef7ce6ba68
commit 4200d752b2
7 changed files with 2875 additions and 0 deletions

View File

@ -0,0 +1,228 @@
/***************************************************************************//**
* \file cy_result.h
*
* \brief
* Basic function result handling. Defines a simple type for conveying
* information about whether something succeeded or details about any issues
* that were detected.
*
********************************************************************************
* \copyright
* Copyright 2018-2020 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.
*******************************************************************************/
/**
* \addtogroup group_result Result Type
* \ingroup group_abstraction
* \{
* \anchor anchor_general_description
* \brief Defines a type and related utilities for function result handling.
*
* The @ref cy_rslt_t type is a structured bitfield which encodes information
* about result type, the originating module, and a code for the specific
* error (or warning etc). In order to extract these individual fields from
* a @ref cy_rslt_t value, the utility macros @ref CY_RSLT_GET_TYPE, @ref CY_RSLT_GET_MODULE,
* and @ref CY_RSLT_GET_CODE are provided. For example:
* \code
* cy_rslt_t result = cy_hal_do_operation(arg);
* // Will be CY_RSLT_TYPE_INFO, CY_RSLT_TYPE_WARNING, CY_RSLT_TYPE_ERROR, or CY_RSLT_TYPE_FATAL
* uint8_t type = CY_RSLT_GET_TYPE(result)
* // See the "Modules" section for possible values
* uint16_t module_id = CY_RSLT_GET_MODULE(result);
* // Specific error codes are defined by each module
* uint16_t error_code = CY_RSLT_GET_CODE(result);
* \endcode
*/
#if !defined(CY_RESULT_H)
#define CY_RESULT_H
#include <stdint.h>
#if defined(__cplusplus)
extern "C" {
#endif
/**
* @brief Provides the result of an operation as a structured bitfield.
*
* See the \ref anchor_general_description "General Description"
* for more details on structure and usage.
*/
typedef uint32_t cy_rslt_t;
/** @ref cy_rslt_t return value indicating success */
#define CY_RSLT_SUCCESS ((cy_rslt_t)0x00000000U)
/** \cond INTERNAL */
/** Mask for the bit at position "x" */
#define CY_BIT_MASK(x) ((1UL << (x)) - 1U)
/** Bit position of the result type */
#define CY_RSLT_TYPE_POSITION (16U)
/** Bit width of the result type */
#define CY_RSLT_TYPE_WIDTH (2U)
/** Bit position of the module identifier */
#define CY_RSLT_MODULE_POSITION (18U)
/** Bit width of the module identifier */
#define CY_RSLT_MODULE_WIDTH (14U)
/** Bit position of the result code */
#define CY_RSLT_CODE_POSITION (0U)
/** Bit width of the result code */
#define CY_RSLT_CODE_WIDTH (16U)
/** Mask for the result type */
#define CY_RSLT_TYPE_MASK CY_BIT_MASK(CY_RSLT_TYPE_WIDTH)
/** Mask for the module identifier */
#define CY_RSLT_MODULE_MASK CY_BIT_MASK(CY_RSLT_MODULE_WIDTH)
/** Mask for the result code */
#define CY_RSLT_CODE_MASK CY_BIT_MASK(CY_RSLT_CODE_WIDTH)
/** \endcond */
/**
* \{
* @name Fields
* Utility macros for constructing result values and extracting individual fields from existing results.
*/
/**
* @brief Get the value of the result type field
* @param x the @ref cy_rslt_t value from which to extract the result type
*/
#define CY_RSLT_GET_TYPE(x) (((x) >> CY_RSLT_TYPE_POSITION) & CY_RSLT_TYPE_MASK)
/**
* @brief Get the value of the module identifier field
* @param x the @ref cy_rslt_t value from which to extract the module id
*/
#define CY_RSLT_GET_MODULE(x) (((x) >> CY_RSLT_MODULE_POSITION) & CY_RSLT_MODULE_MASK)
/**
* @brief Get the value of the result code field
* @param x the @ref cy_rslt_t value from which to extract the result code
*/
#define CY_RSLT_GET_CODE(x) (((x) >> CY_RSLT_CODE_POSITION) & CY_RSLT_CODE_MASK)
/**
* @brief Create a new @ref cy_rslt_t value that encodes the specified type, module, and result code.
* @param type one of @ref CY_RSLT_TYPE_INFO, @ref CY_RSLT_TYPE_WARNING,
* @ref CY_RSLT_TYPE_ERROR, @ref CY_RSLT_TYPE_FATAL
* @param module Identifies the module where this result originated; see @ref anchor_modules "Modules".
* @param code a module-defined identifier to identify the specific situation that
* this result describes.
*/
#define CY_RSLT_CREATE(type, module, code) \
((((module) & CY_RSLT_MODULE_MASK) << CY_RSLT_MODULE_POSITION) | \
(((code) & CY_RSLT_CODE_MASK) << CY_RSLT_CODE_POSITION) | \
(((type) & CY_RSLT_TYPE_MASK) << CY_RSLT_TYPE_POSITION))
/** \} fields */
/**
* \{
* @name Result Types
* Defines codes to identify the type of result.
*/
/** @brief The result code is informational-only */
#define CY_RSLT_TYPE_INFO (0U)
/** @brief The result code is warning of a problem but will proceed */
#define CY_RSLT_TYPE_WARNING (1U)
/** @brief The result code is an error */
#define CY_RSLT_TYPE_ERROR (2U)
/** @brief The result code is a fatal error */
#define CY_RSLT_TYPE_FATAL (3U)
/** \} severity */
/**
* \{
* @name Modules
* @anchor anchor_modules
* Defines codes to identify the module from which an error originated.
* For some large libraries, a range of module codes is defined here;
* see the library documentation for values corresponding to individual modules.
* Valid range is 0x0000-0x4000.
*/
/**** DRIVER Module codes: 0x0000 - 0x00FF ****/
/** Base module identifier for peripheral driver library drivers (0x0000 - 0x007F) */
#define CY_RSLT_MODULE_DRIVERS_PDL_BASE (0x0000U)
/** Base module identifier for wireless host driver library modules (0x0080 - 0x00FF) */
#define CY_RSLT_MODULE_DRIVERS_WHD_BASE (0x0080U)
/** Deprecated. Use \ref CY_RSLT_MODULE_ABSTRACTION_HAL */
#define CY_RSLT_MODULE_ABSTRACTION_HAL_BASE (0x0100U)
/** Module identifier for the Hardware Abstraction Layer */
#define CY_RSLT_MODULE_ABSTRACTION_HAL (0x0100U)
/** Module identifier for board support package */
#define CY_RSLT_MODULE_ABSTRACTION_BSP (0x0180U)
/** Module identifier for file system abstraction */
#define CY_RSLT_MODULE_ABSTRACTION_FS (0x0181U)
/** Module identifier for resource abstraction */
#define CY_RSLT_MODULE_ABSTRACTION_RESOURCE (0x0182U)
/** Module identifier for rtos abstraction */
#define CY_RSLT_MODULE_ABSTRACTION_OS (0x0183U)
/** Base identifier for environment abstraction modules (0x0184 - 0x01FF) */
#define CY_RSLT_MODULE_ABSTRACTION_ENV (0x0184U)
/** Base module identifier for Board Libraries (0x01A0 - 0x01BF) */
#define CY_RSLT_MODULE_BOARD_LIB_BASE (0x01A0U)
/** Module identifier for the Retarget IO Board Library */
#define CY_RSLT_MODULE_BOARD_LIB_RETARGET_IO (0x1A0U)
/** Module identifier for the RGB LED Board Library */
#define CY_RSLT_MODULE_BOARD_LIB_RGB_LED (0x01A1U)
/** Module identifier for the Serial Flash Board Library */
#define CY_RSLT_MODULE_BOARD_LIB_SERIAL_FLASH (0x01A2U)
/** Module identifier for the WiFi Host Driver + Board Support Integration Library */
#define CY_RSLT_MODULE_BOARD_LIB_WHD_INTEGRATION (0x01A3U)
/** Base module identifier for Shield Board Libraries (0x01B8 - 0x01BF) */
#define CY_RSLT_MODULE_BOARD_SHIELD_BASE (0x01B8U)
/** Module identifier for Shield Board CY8CKIT-028-EPD */
#define CY_RSLT_MODULE_BOARD_SHIELD_028_EPD (0x01B8U)
/** Module identifier for Shield Board CY8CKIT-028-TFT */
#define CY_RSLT_MODULE_BOARD_SHIELD_028_TFT (0x01B9U)
/** Module identifier for Shield Board CY8CKIT-032 */
#define CY_RSLT_MODULE_BOARD_SHIELD_032 (0x01BAU)
/** Base module identifier for Board Hardware Libraries (0x01C0 - 0x01FF) */
#define CY_RSLT_MODULE_BOARD_HARDWARE_BASE (0x01C0U)
/** Module identifier for the BMI160 Motion Sensor Library */
#define CY_RSLT_MODULE_BOARD_HARDWARE_BMI160 (0x01C0U)
/** Module identifier for the E2271CS021 E-Ink Controller Library */
#define CY_RSLT_MODULE_BOARD_HARDWARE_E2271CS021 (0x01C1U)
/** Module identifier for the NTC GPIO Thermistor Library */
#define CY_RSLT_MODULE_BOARD_HARDWARE_THERMISTOR (0x01C2U)
/** Module identifier for the SSD1306 OLED Controller Library */
#define CY_RSLT_MODULE_BOARD_HARDWARE_SSD1306 (0x01C3U)
/** Module identifier for the ST7789V TFT Controller Library */
#define CY_RSLT_MODULE_BOARD_HARDWARE_ST7789V (0x01C4U)
/** Module identifier for the Light Sensor Library */
#define CY_RSLT_MODULE_BOARD_HARDWARE_LIGHT_SENSOR (0x01C5U)
/** Module identifier for the AK4954A Audio Codec Library */
#define CY_RSLT_MODULE_BOARD_HARDWARE_AK4954A (0x01C6U)
/** Base module identifier for Middleware Libraries (0x0200 - 0x02FF) */
#define CY_RSLT_MODULE_MIDDLEWARE_BASE (0x0200U)
/** \} modules */
#ifdef __cplusplus
}
#endif
#endif /* CY_RESULT_H */
/** \} group_result */

View File

@ -0,0 +1,711 @@
/***************************************************************************//**
* \file cyabs_rtos.h
*
* \brief
* Defines the Cypress RTOS Interface. Provides prototypes for functions that
* allow Cypress libraries to use RTOS resources such as threads, mutexes &
* timing functions in an abstract way. The APIs are implemented in the Port
* Layer RTOS interface which is specific to the RTOS in use.
*
********************************************************************************
* \copyright
* Copyright 2018-2020 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.
*******************************************************************************/
#ifndef INCLUDED_CY_RTOS_INTERFACE_H_
#define INCLUDED_CY_RTOS_INTERFACE_H_
#include "cyabs_rtos_impl.h"
#include "cy_result.h"
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
/**
* \defgroup group_abstraction_rtos_common Common
* General types and defines for working with the RTOS abstraction layer.
* \defgroup group_abstraction_rtos_mutex Mutex
* APIs for acquiring and working with Mutexes.
* \defgroup group_abstraction_rtos_queue Queue
* APIs for creating and working with Queues.
* \defgroup group_abstraction_rtos_semaphore Semaphore
* APIs for acquiring and working with Semaphores.
* \defgroup group_abstraction_rtos_threads Threads
* APIs for creating and working with Threads.
* \defgroup group_abstraction_rtos_time Time
* APIs for getting the current time and waiting.
* \defgroup group_abstraction_rtos_timer Timer
* APIs for creating and working with Timers.
*/
#ifdef __cplusplus
extern "C"
{
#endif
/*********************************************** CONSTANTS **********************************************/
/**
* \ingroup group_abstraction_rtos_common
* \{
*/
#if defined(DOXYGEN)
//#include "Template/cyabs_rtos_impl.h"
/** Return value indicating success */
#define CY_RSLT_SUCCESS ((cy_rslt_t)0x00000000U)
#endif
/** Used with RTOS calls that require a timeout. This implies the call will never timeout. */
#define CY_RTOS_NEVER_TIMEOUT ( (uint32_t)0xffffffffUL )
//
// Note on error strategy. If the error is a normal part of operation (timeouts, full queues, empty
// queues), the these errors are listed here and the abstraction layer implementation must map from the
// underlying errors to these. If the errors are special cases, the the error \ref CY_RTOS_GENERAL_ERROR
// will be returned and \ref cy_rtos_last_error() can be used to retrieve the RTOS specific error message.
//
/** Requested operation did not complete in the specified time */
#define CY_RTOS_TIMEOUT CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_OS, 0)
/** The RTOS could not allocate memory for the specified operation */
#define CY_RTOS_NO_MEMORY CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_OS, 1)
/** An error occured in the RTOS */
#define CY_RTOS_GENERAL_ERROR CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_OS, 2)
/** A bad argument was passed into the APIs */
#define CY_RTOS_BAD_PARAM CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_OS, 5)
/** A memory alignment issue was detected. Ensure memory provided is aligned per \ref CY_RTOS_ALIGNMENT_MASK */
#define CY_RTOS_ALIGNMENT_ERROR CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_OS, 6)
/** \} group_abstraction_rtos_common */
/**
* \ingroup group_abstraction_rtos_queue
* \{
*/
/** The Queue is already full and can't accept any more items at this time */
#define CY_RTOS_QUEUE_FULL CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_OS, 3)
/** The Queue is empty and has nothing to remove */
#define CY_RTOS_QUEUE_EMPTY CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_OS, 4)
/** \} group_abstraction_rtos_queue */
/*********************************************** TYPES **********************************************/
/**
* The state a thread can be in
*
* \ingroup group_abstraction_rtos_threads
*/
typedef enum cy_thread_state
{
CY_THREAD_STATE_INACTIVE, /**< thread has not started or was terminated but not yet joined */
CY_THREAD_STATE_READY, /**< thread can run, but is not currently */
CY_THREAD_STATE_RUNNING, /**< thread is currently running */
CY_THREAD_STATE_BLOCKED, /**< thread is blocked waiting for something */
CY_THREAD_STATE_TERMINATED, /**< thread has terminated but not freed */
CY_THREAD_STATE_UNKNOWN, /**< thread is in an unknown state */
} cy_thread_state_t;
/**
* The type of timer
*
* \ingroup group_abstraction_rtos_timer
*/
typedef enum cy_timer_trigger_type
{
CY_TIMER_TYPE_PERIODIC, /**< called periodically until stopped */
CY_TIMER_TYPE_ONCE, /**< called once only */
cy_timer_type_periodic = CY_TIMER_TYPE_PERIODIC, /**< \deprecated replaced by \ref CY_TIMER_TYPE_PERIODIC */
cy_timer_type_once = CY_TIMER_TYPE_ONCE, /**< \deprecated replaced by \ref CY_TIMER_TYPE_ONCE */
} cy_timer_trigger_type_t;
/**
* The type of a function that is the entry point for a thread
*
* @param[in] arg the argument passed from the thread create call to the entry function
*
* \ingroup group_abstraction_rtos_threads
*/
typedef void (*cy_thread_entry_fn_t)(cy_thread_arg_t arg);
/**
* The callback function to be called by a timer
*
* \ingroup group_abstraction_rtos_timer
*/
typedef void (*cy_timer_callback_t)(cy_timer_callback_arg_t arg);
/**
* Return the last error from the RTOS.
*
* The functions in the RTOS abstraction layer adhere to the Cypress return
* results calling convention. The underlying RTOS implementations will not but rather
* will have their own error code conventions. This function is provided as a service
* to the developer, mostly for debugging, and returns the underlying RTOS error code
* from the last RTOS abstraction layer that returned \ref CY_RTOS_GENERAL_ERROR.
*
* @return RTOS specific error code.
*
* \ingroup group_abstraction_rtos_common
*/
cy_rtos_error_t cy_rtos_last_error();
/*********************************************** Threads **********************************************/
/**
* \ingroup group_abstraction_rtos_threads
* \{
*/
/** Create a thread with specific thread argument.
*
* This function is called to startup a new thread. If the thread can exit, it must call
* \ref cy_rtos_exit_thread() just before doing so. All created threads that can terminate, either
* by themselves or forcefully by another thread MUST have \ref cy_rtos_join_thread() called on them
* by another thread in order to cleanup any resources that might have been allocated for them.
*
* @param[out] thread Pointer to a variable which will receive the new thread handle
* @param[in] entry_function Function pointer which points to the main function for the new thread
* @param[in] name String thread name used for a debugger
* @param[in] stack The buffer to use for the thread stack. This must be aligned to
* \ref CY_RTOS_ALIGNMENT_MASK with a size of at least \ref CY_RTOS_MIN_STACK_SIZE.
* If stack is null, cy_rtos_create_thread will allocate a stack from the heap.
* @param[in] stack_size The size of the thread stack in bytes
* @param[in] priority The priority of the thread. Values are operating system specific, but some
* common priority levels are defined:
* CY_THREAD_PRIORITY_LOW
* CY_THREAD_PRIORITY_NORMAL
* CY_THREAD_PRIORITY_HIGH
* @param[in] arg The argument to pass to the new thread
*
* @return The status of thread create request. [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_NO_MEMORY, \ref CY_RTOS_GENERAL_ERROR]
*/
cy_rslt_t cy_rtos_create_thread(cy_thread_t *thread, cy_thread_entry_fn_t entry_function,
const char *name, void *stack, uint32_t stack_size, cy_thread_priority_t priority, cy_thread_arg_t arg);
/** Exit the current thread.
*
* This function is called just before a thread exits. In some cases it is sufficient
* for a thread to just return to exit, but in other cases, the RTOS must be explicitly
* signaled. In cases where a return is sufficient, this should be a null funcition.
* where the RTOS must be signaled, this function should perform that In cases operation.
* In code using RTOS services, this function should be placed at any at any location
* where the main thread function will return, exiting the thread. Threads that can
* exit must still be joined (\ref cy_rtos_join_thread) to ensure their resources are
* fully cleaned up.
*
* @return The status of thread exit request. [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_GENERAL_ERROR]
*/
cy_rslt_t cy_rtos_exit_thread();
/** Terminates another thread.
*
* This function is called to terminate another thread and reap the resources claimed
* by the thread. This should be called both when forcibly terminating another thread
* as well as any time a thread can exit on its own. For some RTOS implementations
* this is not required as the thread resources are claimed as soon as it exits. In
* other cases, this must be called to reclaim resources. Threads that are terminated
* must still be joined (\ref cy_rtos_join_thread) to ensure their resources are fully
* cleaned up.
*
* @param[in] thread Handle of the thread to terminate
*
* @returns The status of the thread terminate. [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_GENERAL_ERROR]
*/
cy_rslt_t cy_rtos_terminate_thread(cy_thread_t *thread);
/** Waits for a thread to complete.
*
* This must be called on any thread that can complete to ensure that any resources that
* were allocated for it are cleaned up.
*
* @param[in] thread Handle of the thread to wait for
*
* @returns The status of thread join request. [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_GENERAL_ERROR]
*/
cy_rslt_t cy_rtos_join_thread(cy_thread_t *thread);
/** Checks if the thread is running
*
* This function is called to determine if a thread is actively running or not. For information on
* the thread state, use the \ref cy_rtos_get_thread_state() function.
*
* @param[in] thread Handle of the terminated thread to delete
* @param[out] running Returns true if the thread is running, otherwise false
*
* @returns The status of the thread running check. [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_GENERAL_ERROR]
*/
cy_rslt_t cy_rtos_is_thread_running(cy_thread_t *thread, bool *running);
/** Gets the state the thread is currently in
*
* This function is called to determine if a thread is running/blocked/inactive/ready etc.
*
* @param[in] thread Handle of the terminated thread to delete
* @param[out] state Returns the state the thread is currently in
*
* @returns The status of the thread state check. [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_GENERAL_ERROR]
*/
cy_rslt_t cy_rtos_get_thread_state(cy_thread_t *thread, cy_thread_state_t *state);
/** Get current thread handle
*
* Returns the unique thread handle of the current running thread.
*
* @param[out] thread Handle of the current running thread
*
* @returns The status of thread join request. [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_GENERAL_ERROR]
*/
cy_rslt_t cy_rtos_get_thread_handle(cy_thread_t *thread);
/** \} group_abstraction_rtos_threads */
/*********************************************** Mutexes **********************************************/
/**
* \ingroup group_abstraction_rtos_mutex
* \{
*/
/** Create a recursive mutex.
*
* Creates a binary mutex which can be used to synchronize between threads
* and between threads and ISRs. Created mutexes are recursive and support priority inheritance.
*
* This function has been replaced by \ref cy_rtos_init_mutex2 which allow for specifying
* whether or not the mutex supports recursion or not.
*
* @param[out] mutex Pointer to the mutex handle to be initialized
*
* @return The status of mutex creation request. [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_NO_MEMORY, \ref CY_RTOS_GENERAL_ERROR]
*/
#define cy_rtos_init_mutex(mutex) cy_rtos_init_mutex2(mutex, true)
/** Create a mutex which can support recursion or not.
*
* Creates a binary mutex which can be used to synchronize between threads and between threads and
* ISRs. Created mutexes can support priority inheritance if recursive.
*
* \note Not all RTOS implementations support non-recursive mutexes. In this case a recursive
* mutex will be created.
*
* @param[out] mutex Pointer to the mutex handle to be initialized
* @param[in] recursive Should the created mutex support recursion or not
*
* @return The status of mutex creation request. [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_NO_MEMORY, \ref CY_RTOS_GENERAL_ERROR]
*/
cy_rslt_t cy_rtos_init_mutex2(cy_mutex_t *mutex, bool recursive);
/** Get a mutex.
*
* If the mutex is available, it is acquired and this function returned.
* If the mutex is not available, the thread waits until the mutex is available
* or until the timeout occurs.
*
* @note This function must not be called from an interrupt context as it may block.
*
* @param[in] mutex Pointer to the mutex handle
* @param[in] timeout_ms Maximum number of milliseconds to wait while attempting to get
* the mutex. Use the \ref CY_RTOS_NEVER_TIMEOUT constant to wait forever.
* Must be zero if in_isr is true.
*
* @return The status of the get mutex. Returns timeout if mutex was not acquired
* before timeout_ms period. [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_TIMEOUT, \ref CY_RTOS_GENERAL_ERROR]
*/
cy_rslt_t cy_rtos_get_mutex(cy_mutex_t *mutex, cy_time_t timeout_ms);
/** Set a mutex.
*
* The mutex is released allowing any other threads waiting on the mutex to
* obtain the semaphore.
*
* @param[in] mutex Pointer to the mutex handle
*
* @return The status of the set mutex request. [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_GENERAL_ERROR]
*
*/
cy_rslt_t cy_rtos_set_mutex(cy_mutex_t *mutex);
/** Deletes a mutex.
*
* This function frees the resources associated with a sempahore.
*
* @param[in] mutex Pointer to the mutex handle
*
* @return The status to the delete request. [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_GENERAL_ERROR]
*/
cy_rslt_t cy_rtos_deinit_mutex(cy_mutex_t *mutex);
/** \} group_abstraction_rtos_mutex */
/*********************************************** Semaphores **********************************************/
/**
* \ingroup group_abstraction_rtos_semaphore
* \{
*/
/**
* Create a semaphore
*
* This is basically a counting semaphore.
*
* @param[in,out] semaphore Pointer to the semaphore handle to be initialized
* @param[in] maxcount The maximum count for this semaphore
* @param[in] initcount The initial count for this semaphore
*
* @return The status of the semaphore creation. [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_NO_MEMORY, \ref CY_RTOS_GENERAL_ERROR]
*/
cy_rslt_t cy_rtos_init_semaphore(cy_semaphore_t *semaphore, uint32_t maxcount, uint32_t initcount);
/**
* Get/Acquire a semaphore
*
* If the semaphore count is zero, waits until the semaphore count is greater than zero.
* Once the semaphore count is greater than zero, this function decrements
* the count and return. It may also return if the timeout is exceeded.
*
* @param[in] semaphore Pointer to the semaphore handle
* @param[in] timeout_ms Maximum number of milliseconds to wait while attempting to get
* the semaphore. Use the \ref CY_RTOS_NEVER_TIMEOUT constant to wait forever. Must
* be zero is in_isr is true
* @param[in] in_isr true if we are trying to get the semaphore from with an ISR
* @return The status of get semaphore operation [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_TIMEOUT, \ref CY_RTOS_NO_MEMORY, \ref CY_RTOS_GENERAL_ERROR]
*/
cy_rslt_t cy_rtos_get_semaphore(cy_semaphore_t *semaphore, cy_time_t timeout_ms, bool in_isr);
/**
* Set/Release a semaphore
*
* Increments the semaphore count, up to the maximum count for this semaphore.
*
* @param[in] semaphore Pointer to the semaphore handle
* @param[in] in_isr Value of true indicates calling from interrupt context
* Value of false indicates calling from normal thread context
* @return The status of set semaphore operation [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_NO_MEMORY, \ref CY_RTOS_GENERAL_ERROR]
*/
cy_rslt_t cy_rtos_set_semaphore(cy_semaphore_t *semaphore, bool in_isr);
/**
* Get the count of a semaphore.
*
* Gets the number of available tokens on the semaphore.
*
* @param[in] semaphore Pointer to the semaphore handle
* @param[out] count Pointer to the return count
* @return The status of get semaphore count operation [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_GENERAL_ERROR]
*/
cy_rslt_t cy_rtos_get_count_semaphore(cy_semaphore_t *semaphore, size_t *count);
/**
* Deletes a semaphore
*
* This function frees the resources associated with a semaphore.
*
* @param[in] semaphore Pointer to the semaphore handle
*
* @return The status of semaphore deletion [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_NO_MEMORY, \ref CY_RTOS_GENERAL_ERROR]
*/
cy_rslt_t cy_rtos_deinit_semaphore(cy_semaphore_t *semaphore);
/** \} group_abstraction_rtos_semaphore */
/*********************************************** Events **********************************************/
/**
* \ingroup group_abstraction_rtos_event
* \{
*/
/** Create an event.
*
* This is an event which can be used to signal a set of threads
* with a 32 bit data element.
*
* @param[in,out] event Pointer to the event handle to be initialized
*
* @return The status of the event initialization request.
* [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_NO_MEMORY, \ref CY_RTOS_GENERAL_ERROR]
*/
cy_rslt_t cy_rtos_init_event(cy_event_t *event);
/** Set the event flag bits.
*
* This is an event which can be used to signal a set of threads
* with a 32 bit data element. Any threads waiting on this event are released
*
* @param[in] event Pointer to the event handle
* @param[in] bits The value of the 32 bit flags
* @param[in] in_isr If true, this is called from an ISR, otherwise from a thread
*
* @return The status of the set request. [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_NO_MEMORY, \ref CY_RTOS_GENERAL_ERROR]
*/
cy_rslt_t cy_rtos_setbits_event(cy_event_t *event, uint32_t bits, bool in_isr) ;
/**
* Clear the event flag bits
*
* This function clears bits in the event.
*
* @param[in] event Pointer to the event handle
* @param[in] bits Any bits set in this value, will be cleared in the event.
* @param[in] in_isr if true, this is called from an ISR, otherwise from a thread
*
* @return The status of the clear flags request. [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_NO_MEMORY, \ref CY_RTOS_GENERAL_ERROR]
*/
cy_rslt_t cy_rtos_clearbits_event(cy_event_t *event, uint32_t bits, bool in_isr) ;
/** Get the event bits.
*
* Returns the current bits for the event.
*
* @param[in] event Pointer to the event handle
* @param[out] bits pointer to receive the value of the event flags
*
* @return The status of the get request. [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_NO_MEMORY, \ref CY_RTOS_GENERAL_ERROR]
*/
cy_rslt_t cy_rtos_getbits_event(cy_event_t *event, uint32_t *bits);
/** Wait for the event and return bits.
*
* Waits for the event to be set and then returns the bits associated
* with the event, or waits for the given timeout period.
* @note This function returns if any bit in the set is set.
*
* @param[in] event Pointer to the event handle
* @param[in,out] bits pointer to receive the value of the event flags
* @param[in] clear if true, clear any bits set that cause the wait to return
* if false, do not clear bits
* @param[in] all if true, all bits in the initial bits value must be set to return
* if false, any one bit in the initial bits value must be set to return
* @param[in] timeout The amount of time to wait in milliseconds
*
* @return The status of the wait for event request. [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_NO_MEMORY, \ref CY_RTOS_GENERAL_ERROR]
*/
cy_rslt_t cy_rtos_waitbits_event(cy_event_t *event, uint32_t *bits, bool clear, bool all, cy_time_t timeout);
/** Deinitialize a event.
*
* This function frees the resources associated with an event.
*
* @param[in] event Pointer to the event handle
*
* @return The status of the deletion request. [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_GENERAL_ERROR]
*/
cy_rslt_t cy_rtos_deinit_event(cy_event_t *event);
/** \} group_abstraction_rtos_event */
/*********************************************** Queues **********************************************/
/**
* \ingroup group_abstraction_rtos_queue
* \{
*/
/** Create a queue.
*
* This is a queue of data where entries are placed on the back of the queue
* and removed from the front of the queue.
*
* @param[out] queue Pointer to the queue handle
* @param[in] length The maximum length of the queue in items
* @param[in] itemsize The size of each item in the queue.
*
* @return The status of the creation request. [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_NO_MEMORY, \ref CY_RTOS_GENERAL_ERROR]
*/
cy_rslt_t cy_rtos_init_queue(cy_queue_t *queue, size_t length, size_t itemsize);
/** Put an item in a queue.
*
* This function puts an item in the queue. The item is copied
* into the queue using a memory copy and the data pointed to by item_ptr
* is no longer referenced once the call returns.
*
* @note If in_isr is true, timeout_ms must be zero.
*
* @param[in] queue Pointer to the queue handle
* @param[in] item_ptr Pointer to the item to place in the queue
* @param[in] timeout_ms The time to wait to place the item in the queue
* @param[in] in_isr If true this is being called from within and ISR
*
* @return The status of the creation request. [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_NO_MEMORY, \ref CY_RTOS_GENERAL_ERROR, \ref CY_RTOS_QUEUE_FULL]
*/
cy_rslt_t cy_rtos_put_queue(cy_queue_t *queue, const void *item_ptr, cy_time_t timeout_ms, bool in_isr);
/** Gets an item in a queue.
*
* This function gets an item from the queue. The item is copied
* out of the queue into the memory provide by item_ptr. This space must be
* large enough to hold a queue entry as defined when the queue was initialized.
*
* @note If in_isr is true, timeout_ms must be zero.
*
* @param[in] queue Pointer to the queue handle
* @param[in] item_ptr Pointer to the memory for the item from the queue
* @param[in] timeout_ms The time to wait to get an item from the queue
* @param[in] in_isr If true this is being called from within an ISR
*
* @return The status of the creation request. [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_NO_MEMORY, \ref CY_RTOS_GENERAL_ERROR, \ref CY_RTOS_QUEUE_EMPTY]
*/
cy_rslt_t cy_rtos_get_queue(cy_queue_t *queue, void *item_ptr, cy_time_t timeout_ms, bool in_isr);
/** Return the number of items in the queue.
*
* This function returns the number of items currently in the queue.
*
* @param[in] queue Pointer to the queue handle
* @param[out] num_waiting Pointer to the return count
*
* @return The status of the creation request. [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_GENERAL_ERROR]
*/
cy_rslt_t cy_rtos_count_queue(cy_queue_t *queue, size_t *num_waiting);
/** Return the amount of empty space in the queue.
*
* This function returns the amount of empty space in the
* queue. For instance, if the queue was created with 10 entries max and there
* are currently 2 entries in the queue, this will return 8.
*
* @param[in] queue Pointer to the queue handle
* @param[out] num_spaces Pointer to the return count.
*
* @return The status of the creation request. [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_GENERAL_ERROR]
*/
cy_rslt_t cy_rtos_space_queue(cy_queue_t *queue, size_t *num_spaces);
/** Reset the queue.
*
* This function sets the queue to empty.
*
* @param[in] queue pointer to the queue handle
*
* @return The status of the creation request. [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_GENERAL_ERROR]
*/
cy_rslt_t cy_rtos_reset_queue(cy_queue_t *queue);
/** Deinitialize the queue handle.
*
* This function de-initializes the queue and returns all
* resources used by the queue.
*
* @param[in] queue Pointer to the queue handle
*
* @return The status of the creation request. [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_GENERAL_ERROR]
*/
cy_rslt_t cy_rtos_deinit_queue(cy_queue_t *queue);
/** \} group_abstraction_rtos_queue */
/*********************************************** Timers **********************************************/
/**
* \ingroup group_abstraction_rtos_timer
* \{
*/
/** Create a new timer.
*
* This function initializes a timer object.
* @note The timer is not active until start is called.
* @note The callback may be (likely will be) called from a different thread.
*
* @param[out] timer Pointer to the timer handle to initialize
* @param[in] type Type of timer (periodic or once)
* @param[in] fun The function
* @param[in] arg Argument to pass along to the callback function
*
* @return The status of the creation request. [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_GENERAL_ERROR]
*/
cy_rslt_t cy_rtos_init_timer(cy_timer_t *timer, cy_timer_trigger_type_t type,
cy_timer_callback_t fun, cy_timer_callback_arg_t arg);
/** Start a timer.
*
* @param[in] timer Pointer to the timer handle
* @param[in] num_ms The number of milliseconds to wait before the timer fires
*
* @return The status of the creation request. [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_GENERAL_ERROR]
*/
cy_rslt_t cy_rtos_start_timer(cy_timer_t *timer, cy_time_t num_ms);
/** Stop a timer.
*
* @param[in] timer Pointer to the timer handle
*
* @return The status of the creation request. [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_GENERAL_ERROR]
*/
cy_rslt_t cy_rtos_stop_timer(cy_timer_t *timer);
/** Returns state of a timer.
*
* @param[in] timer Pointer to the timer handle
* @param[out] state Return value for state, true if running, false otherwise
*
* @return The status of the creation request. [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_GENERAL_ERROR]
*/
cy_rslt_t cy_rtos_is_running_timer(cy_timer_t *timer, bool *state);
/** Deinit the timer.
*
* This function deinitializes the timer and frees all consumed resources.
*
* @param[in] timer Pointer to the timer handle
*
* @return The status of the creation request. [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_GENERAL_ERROR]
*/
cy_rslt_t cy_rtos_deinit_timer(cy_timer_t *timer);
/** \} group_abstraction_rtos_timer */
/*********************************************** Time **********************************************/
/**
* \ingroup group_abstraction_rtos_time
* \{
*/
/** Gets time in milliseconds since RTOS start.
*
* @note Since this is only 32 bits, it will roll over every 49 days, 17 hours, 2 mins, 47.296 seconds
*
* @param[out] tval Pointer to the struct to populate with the RTOS time
*
* @returns Time in milliseconds since the RTOS started.
*/
cy_rslt_t cy_rtos_get_time(cy_time_t *tval);
/** Delay for a number of milliseconds.
*
* Processing of this function depends on the minimum sleep
* time resolution of the RTOS. The current thread should sleep for
* the longest period possible which is less than the delay required,
* then makes up the difference with a tight loop.
*
* @param[in] num_ms The number of milliseconds to delay for
*
* @return The status of the creation request. [\ref CY_RSLT_SUCCESS, \ref CY_RTOS_GENERAL_ERROR]
*/
cy_rslt_t cy_rtos_delay_milliseconds(cy_time_t num_ms);
/** \} group_abstraction_rtos_time */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* ifndef INCLUDED_CY_RTOS_INTERFACE_H_ */

View File

@ -0,0 +1,77 @@
/***************************************************************************//**
* \file cyabs_rtos_impl.h
*
* \brief
* Internal definitions for RTOS abstraction layer
*
********************************************************************************
* \copyright
* Copyright 2019-2020 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.
*/
#ifndef INCLUDED_CYABS_RTOS_IMPL_H_
#define INCLUDED_CYABS_RTOS_IMPL_H_
#include "cmsis_os2.h"
#include "rtx_os.h"
#ifdef __cplusplus
extern "C"
{
#endif
/******************************************************
* Constants
******************************************************/
#define CY_RTOS_MIN_STACK_SIZE 300 /** Minimum stack size in bytes */
#define CY_RTOS_ALIGNMENT 0x00000008UL /** Minimum alignment for RTOS objects */
#define CY_RTOS_ALIGNMENT_MASK 0x00000007UL /** Mask for checking the alignment of created RTOS objects */
/******************************************************
* Type Definitions
******************************************************/
/* RTOS thread priority */
typedef enum
{
CY_RTOS_PRIORITY_MIN = osPriorityNone,
CY_RTOS_PRIORITY_LOW = osPriorityLow,
CY_RTOS_PRIORITY_BELOWNORMAL = osPriorityBelowNormal,
CY_RTOS_PRIORITY_NORMAL = osPriorityNormal,
CY_RTOS_PRIORITY_ABOVENORMAL = osPriorityAboveNormal,
CY_RTOS_PRIORITY_HIGH = osPriorityHigh,
CY_RTOS_PRIORITY_REALTIME = osPriorityRealtime,
CY_RTOS_PRIORITY_MAX = osPriorityRealtime7
} cy_thread_priority_t ;
typedef osThreadId_t cy_thread_t; /** CMSIS definition of a thread handle */
typedef void * cy_thread_arg_t; /** Argument passed to the entry function of a thread */
typedef osMutexId_t cy_mutex_t; /** CMSIS definition of a mutex */
typedef osSemaphoreId_t cy_semaphore_t; /** CMSIS definition of a semaphore */
typedef osEventFlagsId_t cy_event_t; /** CMSIS definition of an event */
typedef osMessageQueueId_t cy_queue_t; /** CMSIS definition of a message queue */
typedef osTimerId_t cy_timer_t; /** CMSIS definition of a timer */
typedef void * cy_timer_callback_arg_t; /** Argument passed to the timer callback function */
typedef uint32_t cy_time_t; /** Time in milliseconds */
typedef osStatus_t cy_rtos_error_t; /** CMSIS definition of a error status */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* ifndef INCLUDED_CYABS_RTOS_IMPL_H_ */

View File

@ -0,0 +1,863 @@
/***************************************************************************//**
* \file cyabs_rtos.c
*
* \brief
* Implementation for CMSIS RTOS v2 abstraction
*
********************************************************************************
* \copyright
* Copyright 2018-2020 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 <cy_utils.h>
#include <cyabs_rtos.h>
#if defined(__cplusplus)
extern "C" {
#endif
/******************************************************
* Error Converter
******************************************************/
/* Last received error status */
static cy_rtos_error_t dbgErr;
cy_rtos_error_t cy_rtos_last_error() { return dbgErr; }
/* Converts internal error type to external error type */
static cy_rslt_t error_converter(cy_rtos_error_t internalError)
{
cy_rslt_t value;
switch (internalError)
{
case osOK:
value = CY_RSLT_SUCCESS;
break;
case osErrorTimeout:
value = CY_RTOS_TIMEOUT;
break;
case osErrorParameter:
value = CY_RTOS_BAD_PARAM;
break;
case osErrorNoMemory:
value = CY_RTOS_NO_MEMORY;
break;
case osError:
case osErrorResource:
case osErrorISR:
default:
value = CY_RTOS_GENERAL_ERROR;
break;
}
/* Update the last known error status */
dbgErr = internalError;
return value;
}
/******************************************************
* Threads
******************************************************/
cy_rslt_t cy_rtos_create_thread(cy_thread_t *thread, cy_thread_entry_fn_t entry_function,
const char *name, void *stack, uint32_t stack_size, cy_thread_priority_t priority, cy_thread_arg_t arg)
{
cy_rslt_t status = CY_RSLT_SUCCESS;
osThreadAttr_t attr;
if (thread == NULL || stack_size < CY_RTOS_MIN_STACK_SIZE)
status = CY_RTOS_BAD_PARAM;
else if (stack != NULL && (0 != (((uint32_t)stack) & CY_RTOS_ALIGNMENT_MASK)))
status = CY_RTOS_ALIGNMENT_ERROR;
else
{
attr.name = name;
attr.attr_bits = osThreadJoinable;
attr.cb_size = osRtxThreadCbSize;
attr.stack_size = stack_size;
attr.priority = (osPriority_t)priority;
attr.tz_module = 0;
attr.reserved = 0;
/* Allocate stack if NULL was passed */
if ((uint32_t *)stack == NULL)
{
/* Note: 1 malloc so that it can be freed with 1 call when terminating */
uint32_t cb_mem_pad = (~osRtxThreadCbSize + 1) & CY_RTOS_ALIGNMENT_MASK;
attr.cb_mem = malloc(osRtxThreadCbSize + cb_mem_pad + stack_size);
if (attr.cb_mem != NULL)
attr.stack_mem = (uint32_t *)((uint32_t)attr.cb_mem + osRtxThreadCbSize + cb_mem_pad);
}
else
{
attr.cb_mem = malloc(osRtxThreadCbSize);
attr.stack_mem = stack;
}
if (attr.cb_mem == NULL)
status = CY_RTOS_NO_MEMORY;
else
{
CY_ASSERT(((uint32_t)attr.cb_mem & CY_RTOS_ALIGNMENT_MASK) == 0UL);
CY_ASSERT(((uint32_t)attr.stack_mem & CY_RTOS_ALIGNMENT_MASK) == 0UL);
*thread = osThreadNew((osThreadFunc_t)entry_function, arg, &attr);
CY_ASSERT((*thread == attr.cb_mem) || (*thread == NULL));
status = (*thread == NULL) ? CY_RTOS_GENERAL_ERROR : CY_RSLT_SUCCESS;
}
}
return status;
}
cy_rslt_t cy_rtos_exit_thread()
{
/* This does not have a return statement because the osThreadExit() function
* does not return so the return statement would be unreachable and causes a
* warning for IAR compiler.
*/
osThreadExit();
}
cy_rslt_t cy_rtos_terminate_thread(cy_thread_t *thread)
{
cy_rslt_t status;
cy_rtos_error_t statusInternal;
if (thread == NULL)
status = CY_RTOS_BAD_PARAM;
else
{
statusInternal = osThreadTerminate(*thread);
status = error_converter(statusInternal);
}
return status;
}
cy_rslt_t cy_rtos_is_thread_running(cy_thread_t *thread, bool *running)
{
cy_rslt_t status = CY_RSLT_SUCCESS;
if ((thread == NULL) || (running == NULL))
status = CY_RTOS_BAD_PARAM;
else
{
*running = (osThreadGetState(*thread) == osThreadRunning) ? true : false;
}
return status;
}
cy_rslt_t cy_rtos_get_thread_state(cy_thread_t *thread, cy_thread_state_t *state)
{
cy_rslt_t status = CY_RSLT_SUCCESS;
if ((thread == NULL) || (state == NULL))
status = CY_RTOS_BAD_PARAM;
else
{
switch (osThreadGetState(*thread))
{
case osThreadInactive:
*state = CY_THREAD_STATE_INACTIVE;
break;
case osThreadReady:
*state = CY_THREAD_STATE_READY;
break;
case osThreadRunning:
*state = CY_THREAD_STATE_RUNNING;
break;
case osThreadBlocked:
*state = CY_THREAD_STATE_BLOCKED;
break;
case osThreadTerminated:
*state = CY_THREAD_STATE_TERMINATED;
break;
case osThreadError:
case osThreadReserved:
default:
*state = CY_THREAD_STATE_UNKNOWN;
break;
}
}
return status;
}
cy_rslt_t cy_rtos_join_thread(cy_thread_t *thread)
{
cy_rslt_t status;
cy_rtos_error_t statusInternal;
if (thread == NULL)
status = CY_RTOS_BAD_PARAM;
else
{
statusInternal = osThreadJoin(*thread);
status = error_converter(statusInternal);
if (status == CY_RSLT_SUCCESS)
{
free(*thread);
*thread = NULL;
}
}
return status;
}
cy_rslt_t cy_rtos_get_thread_handle(cy_thread_t *thread)
{
cy_rslt_t status = CY_RSLT_SUCCESS;
if (thread == NULL)
status = CY_RTOS_BAD_PARAM;
else
*thread = osThreadGetId();
return status;
}
/******************************************************
* Mutexes
******************************************************/
cy_rslt_t cy_rtos_init_mutex2(cy_mutex_t *mutex, bool recursive)
{
cy_rslt_t status;
osMutexAttr_t attr;
if (mutex == NULL)
status = CY_RTOS_BAD_PARAM;
else
{
attr.name = NULL;
attr.attr_bits = osMutexPrioInherit;
if (recursive)
{
attr.attr_bits |= osMutexRecursive;
}
attr.cb_mem = malloc(osRtxMutexCbSize);
attr.cb_size = osRtxMutexCbSize;
if (attr.cb_mem == NULL)
status = CY_RTOS_NO_MEMORY;
else
{
CY_ASSERT(((uint32_t)attr.cb_mem & CY_RTOS_ALIGNMENT_MASK) == 0UL);
*mutex = osMutexNew(&attr);
CY_ASSERT((*mutex == attr.cb_mem) || (*mutex == NULL));
status = (*mutex == NULL) ? CY_RTOS_GENERAL_ERROR : CY_RSLT_SUCCESS;
}
}
return status;
}
cy_rslt_t cy_rtos_get_mutex(cy_mutex_t *mutex, cy_time_t timeout_ms)
{
cy_rslt_t status;
cy_rtos_error_t statusInternal;
if (mutex == NULL)
status = CY_RTOS_BAD_PARAM;
else
{
statusInternal = osMutexAcquire(*mutex, timeout_ms);
status = error_converter(statusInternal);
}
return status;
}
cy_rslt_t cy_rtos_set_mutex(cy_mutex_t *mutex)
{
cy_rslt_t status;
cy_rtos_error_t statusInternal;
if (mutex == NULL)
status = CY_RTOS_BAD_PARAM;
else
{
statusInternal = osMutexRelease(*mutex);
status = error_converter(statusInternal);
}
return status;
}
cy_rslt_t cy_rtos_deinit_mutex(cy_mutex_t *mutex)
{
cy_rslt_t status;
cy_rtos_error_t statusInternal;
if (mutex == NULL)
status = CY_RTOS_BAD_PARAM;
else
{
statusInternal = osMutexDelete(*mutex);
status = error_converter(statusInternal);
if (status == CY_RSLT_SUCCESS)
{
free(*mutex);
*mutex = NULL;
}
}
return status;
}
/******************************************************
* Semaphores
******************************************************/
cy_rslt_t cy_rtos_init_semaphore(cy_semaphore_t *semaphore, uint32_t maxcount, uint32_t initcount)
{
cy_rslt_t status;
osSemaphoreAttr_t attr;
if (semaphore == NULL)
status = CY_RTOS_BAD_PARAM;
else
{
attr.name = NULL;
attr.attr_bits = 0U;
attr.cb_mem = malloc(osRtxSemaphoreCbSize);
attr.cb_size = osRtxSemaphoreCbSize;
if (attr.cb_mem == NULL)
status = CY_RTOS_NO_MEMORY;
else
{
CY_ASSERT(((uint32_t)attr.cb_mem & CY_RTOS_ALIGNMENT_MASK) == 0UL);
*semaphore = osSemaphoreNew(maxcount, initcount, &attr);
CY_ASSERT((*semaphore == attr.cb_mem) || (*semaphore == NULL));
status = (*semaphore == NULL) ? CY_RTOS_GENERAL_ERROR : CY_RSLT_SUCCESS;
}
}
return status;
}
cy_rslt_t cy_rtos_get_semaphore(cy_semaphore_t *semaphore, cy_time_t timeout_ms, bool in_isr)
{
cy_rslt_t status = CY_RSLT_SUCCESS;
cy_rtos_error_t statusInternal;
if (semaphore == NULL)
status = CY_RTOS_BAD_PARAM;
else
{
/* Not allowed to be called in ISR if timeout != 0 */
if ((!in_isr) || (in_isr && (timeout_ms == 0U)))
statusInternal = osSemaphoreAcquire(*semaphore, timeout_ms);
else
statusInternal = osErrorISR;
status = error_converter(statusInternal);
}
return status;
}
cy_rslt_t cy_rtos_set_semaphore(cy_semaphore_t *semaphore, bool in_isr)
{
cy_rslt_t status = CY_RSLT_SUCCESS;
cy_rtos_error_t statusInternal;
(void)in_isr; // Unused parameter in this implementation
if (semaphore == NULL)
status = CY_RTOS_BAD_PARAM;
else
{
statusInternal = osSemaphoreRelease(*semaphore);
status = error_converter(statusInternal);
}
return status;
}
cy_rslt_t cy_rtos_get_count_semaphore(cy_semaphore_t *semaphore, size_t *count)
{
cy_rslt_t status;
if (semaphore == NULL || count == NULL)
status = CY_RTOS_BAD_PARAM;
else
{
*count = osSemaphoreGetCount(*semaphore);
status = CY_RSLT_SUCCESS;
}
return status;
}
cy_rslt_t cy_rtos_deinit_semaphore(cy_semaphore_t *semaphore)
{
cy_rslt_t status;
cy_rtos_error_t statusInternal;
if (semaphore == NULL)
status = CY_RTOS_BAD_PARAM;
else
{
statusInternal = osSemaphoreDelete(*semaphore);
status = error_converter(statusInternal);
if (status == CY_RSLT_SUCCESS)
{
free(*semaphore);
*semaphore = NULL;
}
}
return status;
}
/******************************************************
* Events
******************************************************/
#define CY_RTOS_EVENT_ERRORFLAG 0x80000000UL
#define CY_RTOS_EVENT_FLAGS 0x7FFFFFFFUL
cy_rslt_t cy_rtos_init_event(cy_event_t *event)
{
cy_rslt_t status;
osEventFlagsAttr_t attr;
if (event == NULL)
status = CY_RTOS_BAD_PARAM;
else
{
attr.name = NULL;
attr.attr_bits = 0U;
attr.cb_mem = malloc(osRtxEventFlagsCbSize);
attr.cb_size = osRtxEventFlagsCbSize;
if (attr.cb_mem == NULL)
status = CY_RTOS_NO_MEMORY;
else
{
CY_ASSERT(((uint32_t)attr.cb_mem & CY_RTOS_ALIGNMENT_MASK) == 0UL);
*event = osEventFlagsNew(&attr);
CY_ASSERT((*event == attr.cb_mem) || (*event == NULL));
status = (*event == NULL) ? CY_RTOS_GENERAL_ERROR : CY_RSLT_SUCCESS;
}
}
return status;
}
cy_rslt_t cy_rtos_setbits_event(cy_event_t *event, uint32_t bits, bool in_isr)
{
cy_rslt_t status = CY_RSLT_SUCCESS;
cy_rtos_error_t statusInternal;
(void)in_isr; // Unused parameter in this implementation
if (event == NULL)
status = CY_RTOS_BAD_PARAM;
else
{
statusInternal = (osStatus_t)osEventFlagsSet(*event, bits);
if ((statusInternal & CY_RTOS_EVENT_ERRORFLAG) != 0UL)
status = error_converter(statusInternal);
}
return status;
}
cy_rslt_t cy_rtos_clearbits_event(cy_event_t *event, uint32_t bits, bool in_isr)
{
cy_rslt_t status = CY_RSLT_SUCCESS;
cy_rtos_error_t statusInternal;
(void)in_isr; // Unused parameter in this implementation
if (event == NULL)
status = CY_RTOS_BAD_PARAM;
else
{
statusInternal = (osStatus_t)osEventFlagsClear(*event, bits);
if ((statusInternal & CY_RTOS_EVENT_ERRORFLAG) != 0UL)
status = error_converter(statusInternal);
}
return status;
}
cy_rslt_t cy_rtos_getbits_event(cy_event_t *event, uint32_t *bits)
{
cy_rslt_t status = CY_RSLT_SUCCESS;
if ((event == NULL) || (bits == NULL))
status = CY_RTOS_BAD_PARAM;
else
*bits = osEventFlagsGet(*event);
return status;
}
cy_rslt_t cy_rtos_waitbits_event(cy_event_t *event, uint32_t *bits, bool clear, bool all, cy_time_t timeout)
{
cy_rslt_t status = CY_RSLT_SUCCESS;
cy_rtos_error_t statusInternal;
uint32_t flagOption;
if ((event == NULL) || (bits == NULL))
status = CY_RTOS_BAD_PARAM;
else
{
flagOption = (all) ? osFlagsWaitAll : osFlagsWaitAny;
if (!clear)
flagOption |= osFlagsNoClear;
statusInternal = (osStatus_t)osEventFlagsWait(*event, *bits, flagOption, timeout);
if ((statusInternal & CY_RTOS_EVENT_ERRORFLAG) == 0UL)
*bits = statusInternal;
else
status = error_converter(statusInternal);
}
return status;
}
cy_rslt_t cy_rtos_deinit_event(cy_event_t *event)
{
cy_rslt_t status;
cy_rtos_error_t statusInternal;
if (event == NULL)
status = CY_RTOS_BAD_PARAM;
else
{
statusInternal = osEventFlagsDelete(*event);
status = error_converter(statusInternal);
if (status == CY_RSLT_SUCCESS)
{
free(*event);
*event = NULL;
}
}
return status;
}
/******************************************************
* Queues
******************************************************/
cy_rslt_t cy_rtos_init_queue(cy_queue_t *queue, size_t length, size_t itemsize)
{
cy_rslt_t status;
osMessageQueueAttr_t attr;
if (queue == NULL)
status = CY_RTOS_BAD_PARAM;
else
{
attr.name = NULL;
attr.attr_bits = 0U;
attr.cb_size = osRtxMessageQueueCbSize;
uint32_t blockSize = ((itemsize + 3U) & ~3UL) + sizeof(osRtxMessage_t);
attr.mq_size = blockSize * length;
/* Note: 1 malloc for both so that they can be freed with 1 call */
uint32_t cb_mem_pad = (8 - (osRtxMessageQueueCbSize & 0x07)) & 0x07;
attr.cb_mem = malloc(osRtxMessageQueueCbSize + cb_mem_pad + attr.mq_size);
if (attr.cb_mem != NULL)
attr.mq_mem = (uint32_t *)((uint32_t)attr.cb_mem + osRtxMessageQueueCbSize + cb_mem_pad);
if (attr.cb_mem == NULL)
status = CY_RTOS_NO_MEMORY;
else
{
CY_ASSERT(((uint32_t)attr.cb_mem & CY_RTOS_ALIGNMENT_MASK) == 0UL);
CY_ASSERT(((uint32_t)attr.mq_mem & CY_RTOS_ALIGNMENT_MASK) == 0UL);
*queue = osMessageQueueNew(length, itemsize, &attr);
CY_ASSERT((*queue == attr.cb_mem) || (*queue == NULL));
status = (*queue == NULL) ? CY_RTOS_GENERAL_ERROR : CY_RSLT_SUCCESS;
}
}
return status;
}
cy_rslt_t cy_rtos_put_queue(cy_queue_t *queue, const void *item_ptr, cy_time_t timeout_ms, bool in_isr)
{
cy_rslt_t status;
cy_rtos_error_t statusInternal;
if ((queue == NULL) || (item_ptr == NULL))
status = CY_RTOS_BAD_PARAM;
else
{
/* Not allowed to be called in ISR if timeout != 0 */
if ((!in_isr) || (in_isr && (timeout_ms == 0U)))
statusInternal = osMessageQueuePut(*queue, (uint8_t *)item_ptr, 0u, timeout_ms);
else
statusInternal = osErrorISR;
status = error_converter(statusInternal);
}
return status;
}
cy_rslt_t cy_rtos_get_queue(cy_queue_t *queue, void *item_ptr, cy_time_t timeout_ms, bool in_isr)
{
cy_rslt_t status;
cy_rtos_error_t statusInternal;
if ((queue == NULL) || (item_ptr == NULL))
status = CY_RTOS_BAD_PARAM;
else
{
/* Not allowed to be called in ISR if timeout != 0 */
if ((!in_isr) || (in_isr && (timeout_ms == 0U)))
statusInternal = osMessageQueueGet(*queue, (uint8_t *)item_ptr, 0u, timeout_ms);
else
statusInternal = osErrorISR;
status = error_converter(statusInternal);
}
return status;
}
cy_rslt_t cy_rtos_count_queue(cy_queue_t *queue, size_t *num_waiting)
{
cy_rslt_t status = CY_RSLT_SUCCESS;
if ((queue == NULL) || (num_waiting == NULL))
status = CY_RTOS_BAD_PARAM;
else
*num_waiting = osMessageQueueGetCount(*queue);
return status;
}
cy_rslt_t cy_rtos_space_queue(cy_queue_t *queue, size_t *num_spaces)
{
cy_rslt_t status = CY_RSLT_SUCCESS;
if ((queue == NULL) || (num_spaces == NULL))
status = CY_RTOS_BAD_PARAM;
else
*num_spaces = osMessageQueueGetSpace(*queue);
return status;
}
cy_rslt_t cy_rtos_reset_queue(cy_queue_t *queue)
{
cy_rslt_t status;
cy_rtos_error_t statusInternal;
if (queue == NULL)
status = CY_RTOS_BAD_PARAM;
else
{
statusInternal = osMessageQueueReset(*queue);
status = error_converter(statusInternal);
}
return status;
}
cy_rslt_t cy_rtos_deinit_queue(cy_queue_t *queue)
{
cy_rslt_t status;
cy_rtos_error_t statusInternal;
if (queue == NULL)
status = CY_RTOS_BAD_PARAM;
else
{
statusInternal = osMessageQueueDelete(*queue);
status = error_converter(statusInternal);
if (status == CY_RSLT_SUCCESS)
{
free(*queue);
*queue = NULL;
}
}
return status;
}
/******************************************************
* Timers
******************************************************/
cy_rslt_t cy_rtos_init_timer(cy_timer_t *timer, cy_timer_trigger_type_t type,
cy_timer_callback_t fun, cy_timer_callback_arg_t arg)
{
cy_rslt_t status;
osTimerAttr_t attr;
if (timer == NULL)
status = CY_RTOS_BAD_PARAM;
else
{
attr.name = NULL;
attr.attr_bits = 0U;
attr.cb_mem = malloc(osRtxTimerCbSize);
attr.cb_size = osRtxTimerCbSize;
if (attr.cb_mem == NULL)
status = CY_RTOS_NO_MEMORY;
else
{
osTimerType_t osTriggerType = (CY_TIMER_TYPE_PERIODIC == type)
? osTimerPeriodic
: osTimerOnce;
CY_ASSERT(((uint32_t)attr.cb_mem & CY_RTOS_ALIGNMENT_MASK) == 0UL);
*timer = osTimerNew( (osTimerFunc_t)fun, osTriggerType, (void *)arg, &attr );
CY_ASSERT((*timer == attr.cb_mem) || (*timer == NULL));
status = (*timer == NULL) ? CY_RTOS_GENERAL_ERROR : CY_RSLT_SUCCESS;
}
}
return status;
}
cy_rslt_t cy_rtos_start_timer(cy_timer_t *timer, cy_time_t num_ms)
{
cy_rslt_t status;
cy_rtos_error_t statusInternal;
if (timer == NULL)
status = CY_RTOS_BAD_PARAM;
else
{
/* Get Number of ticks per second */
uint32_t tick_freq = osKernelGetTickFreq();
/* Convert ticks count to time in milliseconds */
if (tick_freq != 0)
{
uint32_t ticks = ((num_ms * tick_freq) / 1000);
statusInternal = osTimerStart(*timer, ticks);
status = error_converter(statusInternal);
}
else
status = CY_RTOS_GENERAL_ERROR;
}
return status;
}
cy_rslt_t cy_rtos_stop_timer(cy_timer_t *timer)
{
cy_rslt_t status;
cy_rtos_error_t statusInternal;
if (timer == NULL)
status = CY_RTOS_BAD_PARAM;
else
{
statusInternal = osTimerStop(*timer);
status = error_converter(statusInternal);
}
return status;
}
cy_rslt_t cy_rtos_is_running_timer(cy_timer_t *timer, bool *state)
{
cy_rslt_t status = CY_RSLT_SUCCESS;
if ((timer == NULL) || (state == NULL))
status = CY_RTOS_BAD_PARAM;
else
*state = osTimerIsRunning(*timer);
return status;
}
cy_rslt_t cy_rtos_deinit_timer(cy_timer_t *timer)
{
cy_rslt_t status;
cy_rtos_error_t statusInternal;
if (timer == NULL)
status = CY_RTOS_BAD_PARAM;
else
{
statusInternal = osTimerDelete(*timer);
status = error_converter(statusInternal);
if (status == CY_RSLT_SUCCESS)
{
free(*timer);
*timer = NULL;
}
}
return status;
}
/******************************************************
* Time
******************************************************/
cy_rslt_t cy_rtos_get_time(cy_time_t *tval)
{
cy_rslt_t status = CY_RSLT_SUCCESS;
uint32_t tick_freq;
if (tval == NULL)
status = CY_RTOS_BAD_PARAM;
else
{
/* Get Number of ticks per second */
tick_freq = osKernelGetTickFreq();
/* Convert ticks count to time in milliseconds */
if (tick_freq != 0)
*tval = (cy_time_t)((osKernelGetTickCount() * 1000LL) / tick_freq);
else
status = CY_RTOS_GENERAL_ERROR;
}
return status;
}
cy_rslt_t cy_rtos_delay_milliseconds(cy_time_t num_ms)
{
cy_rslt_t status;
cy_rtos_error_t statusInternal;
statusInternal = osDelay(num_ms);
status = error_converter(statusInternal);
return status;
}
#if defined(__cplusplus)
}
#endif

View File

@ -0,0 +1,247 @@
/***************************************************************************//**
* \file cyhal_gpio.h
*
* \brief
* Provides a high level interface for interacting with the GPIO on Cypress devices.
* This interface abstracts out the chip specific details. If any chip specific
* functionality is necessary, or performance is critical the low level functions
* can be used directly.
*
********************************************************************************
* \copyright
* Copyright 2018-2020 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.
*******************************************************************************/
/**
* \addtogroup group_hal_gpio GPIO (General Purpose Input Output)
* \ingroup group_hal
* \{
* High level interface for configuring and interacting with general purpose input/outputs (GPIO).
*
* The GPIO driver provides functions to configure and initialize GPIO, and to read and write data to the pin.
* The driver also supports interrupt generation on GPIO signals with rising, falling or both edges.
*
* \note The APIs in this driver need not be used if a GPIO is to be used as an input or output of peripherals like I2C or PWM.
* The respective peripheral's driver will utilize the GPIO interface to configure and initialize its GPIO pins.
*
* \section subsection_gpio_features Features
* * Configurable GPIO pin direction - \ref cyhal_gpio_direction_t
* * Configurable GPIO pin drive modes - \ref cyhal_gpio_drive_mode_t
* * Configurable analog and digital characteristics
* * Configurable edge-triggered interrupts and callback assignment on GPIO events - \ref cyhal_gpio_event_t
*
* \section subsection_gpio_quickstart Quick Start
* \ref cyhal_gpio_init can be used for a simple GPIO initialization by providing the pin number (<b>pin</b>), pin direction (<b>direction</b>),
* pin drive mode (<b>drive_mode</b>) and the initial value on the pin (<b>init_val</b>).
*
* \section subsection_gpio_sample_snippets Code Snippets
*
* \subsection subsection_gpio_snippet_1 Snippet 1: Reading value from GPIO
* The following snippet initializes GPIO pin \ref P0_0 as an input with high impedance digital drive mode and initial value = <b>false</b> (low). A value is read
* from the pin and stored to a uint8_t variable (<b>read_val</b>).
* \snippet gpio.c snippet_cyhal_gpio_read
* \subsection subsection_gpio_snippet_2 Snippet 2: Writing value to a GPIO
* The following snippet initializes GPIO pin \ref P0_0 as an output pin with strong drive mode and initial value = <b>false</b> (low).
* A value = <b>true</b> (high) is written to the output driver.
* \snippet gpio.c snippet_cyhal_gpio_write
* \subsection subsection_gpio_snippet_3 Snippet 3: Reconfiguring a GPIO
* The following snippet shows how to reconfigure a GPIO pin during run-time using the firmware. The GPIO pin \ref P0_0
* is first initialized as an output pin with strong drive mode. The pin is then reconfigured as an input with high impedance digital drive mode.
* \note \ref cyhal_gpio_configure only changes the <b>direction</b> and the <b>drive_mode</b>
* of the pin. Previously set pin value is retained.
*
* \snippet gpio.c snippet_cyhal_gpio_reconfigure
* \subsection subsection_gpio_snippet_4 Snippet 4: Interrupts on GPIO events
* GPIO events can be mapped to an interrupt and assigned to a callback function. The callback function needs to be first registered and
* then the event needs to be enabled.
** The following snippet initializes GPIO pin \ref P0_0 as an input pin. It registers a callback function and enables detection
* of a falling edge event to trigger the callback.
* \note If no argument needs to be passed to the callback function then a NULL can be passed during registering. <br>
*
* \snippet gpio.c snippet_cyhal_gpio_interrupt
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "cy_result.h"
#include "cyhal_hw_types.h"
#if defined(__cplusplus)
extern "C" {
#endif /* __cplusplus */
/*******************************************************************************
* Defines
*******************************************************************************/
/** Integer representation of no connect pin (required to exist in all BSPs) */
#define CYHAL_NC_PIN_VALUE (NC)
/*******************************************************************************
* Enumerations
*******************************************************************************/
/** Pin events */
typedef enum {
CYHAL_GPIO_IRQ_NONE = 0, /**< No interrupt */
CYHAL_GPIO_IRQ_RISE = 1 << 0, /**< Interrupt on rising edge */
CYHAL_GPIO_IRQ_FALL = 1 << 1, /**< Interrupt on falling edge */
CYHAL_GPIO_IRQ_BOTH = (CYHAL_GPIO_IRQ_RISE | CYHAL_GPIO_IRQ_FALL), /**< Interrupt on both rising and falling edges */
} cyhal_gpio_event_t;
/** Pin direction */
typedef enum {
CYHAL_GPIO_DIR_INPUT, /**< Input pin */
CYHAL_GPIO_DIR_OUTPUT, /**< Output pin */
CYHAL_GPIO_DIR_BIDIRECTIONAL, /**< Input and output pin */
} cyhal_gpio_direction_t;
/** Pin drive mode */
/** \note When the <b> drive_mode </b> of the <b> pin </b> is set to <b> CYHAL_GPIO_DRIVE_PULL_NONE </b>,
* it is set to <b> CYHAL_GPIO_DRIVE_STRONG </b> if the <b> direction </b>
* of the <b> pin </b> is <b> CYHAL_GPIO_DIR_OUTPUT </b> or <b> CYHAL_GPIO_DIR_BIDIRECTIONAL</b>.
* If not, the <b> drive_mode </b> of the <b> pin </b> is set to <b> CYHAL_GPIO_DRIVE_NONE</b>.
*/
typedef enum {
CYHAL_GPIO_DRIVE_NONE, /**< Digital Hi-Z. Input only. Input init value(s): 0 or 1 */
CYHAL_GPIO_DRIVE_ANALOG, /**< Analog Hi-Z. Use only for analog purpose */
CYHAL_GPIO_DRIVE_PULLUP, /**< Pull-up resistor. Input and output. Input init value(s): 1, output value(s): 0 */
CYHAL_GPIO_DRIVE_PULLDOWN, /**< Pull-down resistor. Input and output. Input init value(s): 0, output value(s): 1 */
CYHAL_GPIO_DRIVE_OPENDRAINDRIVESLOW, /**< Open-drain, Drives Low. Input and output. Input init value(s): 1, output value(s): 0 */
CYHAL_GPIO_DRIVE_OPENDRAINDRIVESHIGH, /**< Open-drain, Drives High. Input and output. Input init value(s): 0, output value(s): 1 */
CYHAL_GPIO_DRIVE_STRONG, /**< Strong output. Output only. Output init value(s): 0 or 1 */
CYHAL_GPIO_DRIVE_PULLUPDOWN, /**< Pull-up and pull-down resistors. Input and output. Input init value(s): 0 or 1, output value(s): 0 or 1 */
CYHAL_GPIO_DRIVE_PULL_NONE, /**< No Pull-up or pull-down resistors. Input and output. Input init value(s): 0 or 1, output value(s): 0 or 1 */
} cyhal_gpio_drive_mode_t;
/** GPIO callback function type */
typedef void (*cyhal_gpio_event_callback_t)(void *callback_arg, cyhal_gpio_event_t event);
/*******************************************************************************
* Functions
*******************************************************************************/
/** Initialize the GPIO pin <br>
* See \ref subsection_gpio_snippet_1.
*
* @param[in] pin The GPIO pin to initialize
* @param[in] direction The pin direction
* @param[in] drive_mode The pin drive mode
* @param[in] init_val Initial value on the pin
*
* @return The status of the init request
*
* Guidance for using gpio drive modes ( \ref cyhal_gpio_drive_mode_t for details).
* For default use drive modes:
* Input GPIO direction - \ref CYHAL_GPIO_DRIVE_NONE
* Output GPIO direction - \ref CYHAL_GPIO_DRIVE_STRONG
* Bidirectional GPIO - \ref CYHAL_GPIO_DRIVE_PULLUPDOWN
* \warning Don't use \ref CYHAL_GPIO_DRIVE_STRONG for input GPIO direction. It may cause an overcurrent issue.
*/
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);
/** Uninitialize the gpio peripheral and the cyhal_gpio_t object
*
* @param[in] pin Pin number
*/
void cyhal_gpio_free(cyhal_gpio_t pin);
/** Configure the GPIO pin <br>
* See \ref subsection_gpio_snippet_3.
*
* @param[in] pin The GPIO pin
* @param[in] direction The pin direction
* @param[in] drive_mode The pin drive mode
*
* @return The status of the configure request
*/
cy_rslt_t cyhal_gpio_configure(cyhal_gpio_t pin, cyhal_gpio_direction_t direction, cyhal_gpio_drive_mode_t drive_mode);
/** Set the output value for the pin. This only works for output & in_out pins. <br>
* See \ref subsection_gpio_snippet_2.
*
* @param[in] pin The GPIO object
* @param[in] value The value to be set (high = true, low = false)
*/
void cyhal_gpio_write(cyhal_gpio_t pin, bool value);
/** Read the input value. This only works for \ref CYHAL_GPIO_DIR_INPUT & \ref CYHAL_GPIO_DIR_BIDIRECTIONAL pins. <br>
* See \ref subsection_gpio_snippet_1.
*
* @param[in] pin The GPIO object
* @return The value of the IO (true = high, false = low)
*/
bool cyhal_gpio_read(cyhal_gpio_t pin);
/** Toggle the output value <br>
* See \ref subsection_gpio_snippet_4.
* @param[in] pin The GPIO object
*/
void cyhal_gpio_toggle(cyhal_gpio_t pin);
/** Register/clear a callback handler for pin events <br>
*
* This function will be called when one of the events enabled by \ref cyhal_gpio_enable_event occurs.
*
* See \ref subsection_gpio_snippet_4.
*
* @param[in] pin The pin number
* @param[in] callback The function to call when the specified event happens. Pass NULL to unregister the handler.
* @param[in] callback_arg Generic argument that will be provided to the callback when called, can be NULL
*/
void cyhal_gpio_register_callback(cyhal_gpio_t pin, cyhal_gpio_event_callback_t callback, void *callback_arg);
/** Enable or Disable the specified GPIO event <br>
*
* When an enabled event occurs, the function specified by \ref cyhal_gpio_register_callback will be called.
*
* See \ref subsection_gpio_snippet_4.
*
* @param[in] pin The GPIO object
* @param[in] event The GPIO event
* @param[in] intr_priority The priority for NVIC interrupt events
* @param[in] enable True to turn on interrupts, False to turn off
*/
void cyhal_gpio_enable_event(cyhal_gpio_t pin, cyhal_gpio_event_t event, uint8_t intr_priority, bool enable);
/*******************************************************************************
* Backward compatibility macro. The following code is DEPRECATED and must
* not be used in new projects
*******************************************************************************/
/** \cond INTERNAL */
#define cyhal_gpio_register_irq(pin, priority, handler, handler_arg) cyhal_gpio_register_callback(pin, handler, handler_arg)
#define cyhal_gpio_irq_enable(pin, event, enable) cyhal_gpio_enable_event(pin, event, CYHAL_ISR_PRIORITY_DEFAULT, enable)
typedef cyhal_gpio_event_t cyhal_gpio_irq_event_t;
/** \endcond */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#ifdef CYHAL_GPIO_IMPL_HEADER
#include CYHAL_GPIO_IMPL_HEADER
#endif /* CYHAL_GPIO_IMPL_HEADER */
/** \} group_hal_gpio */

View File

@ -0,0 +1,366 @@
/***************************************************************************//**
* \file cyhal_sdio.h
*
* \brief
* Provides a high level interface for interacting with the Cypress SDIO interface.
* This interface abstracts out the chip specific details. If any chip specific
* functionality is necessary, or performance is critical the low level functions
* can be used directly.
*
********************************************************************************
* \copyright
* Copyright 2018-2020 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.
*******************************************************************************/
/**
* \addtogroup group_hal_sdio SDIO (Secure Digital Input Output)
* \ingroup group_hal
* \{
* High level interface to the Secure Digital Input Output (SDIO).
*
* This driver allows commands to be sent over the SDIO bus; the supported commands
* can be found in \ref cyhal_sdio_command_t. Bulk data transfer is also supported
* via cyhal_sdio_bulk_transfer().
*
* The SDIO protocol is an extension of the SD
* interface for general I/O functions. Refer to the SD Specifications Part 1 SDIO
* Specifications Version 4.10 for more information on the SDIO protocol and specifications.
*
*
* \section subsection_sdio_features Features
* * Supports 4-bit interface
* * Supports Ultra High Speed (UHS-I) mode
* * Supports Default Speed (DS), High Speed (HS), SDR12, SDR25 and SDR50 speed modes
* * Supports SDIO card interrupts in both 1-bit and 4-bit modes
* * Supports Standard capacity (SDSC), High capacity (SDHC) and Extended capacity (SDXC) memory
*
* \section subsection_sdio_quickstart Quick Start
*
* \ref cyhal_sdio_init initializes the SDIO peripheral and passes a pointer to the SDIO block through the **obj** object of type \ref cyhal_sdio_t.
*
* \section subsection_sdio_code_snippets Code Snippets
*
* \subsection subsection_sdio_use_case_1 Snippet1: Simple SDIO Initialization example
* The following snippet shows how to initialize the SDIO interface with a pre-defined configuration
*
* \snippet sdio.c snippet_cyhal_sdio_simple_init
*
* \subsection subsection_sdio_use_case_2 Snippet2: Configure Interrupt
* The following snippet shows how to configure an interrupt and handle specific events. Refer \ref cyhal_sdio_event_t for different types of events.
*
* \snippet sdio.c snippet_cyhal_sdio_interrupt_callback
*
* \subsection subsection_sdio_use_case_3 Snippet3: Sending Commands
* The following snippet shows how to send a particular command. Some steps of the card initialization have been provided for reference. Refer \ref cyhal_sdio_command_t for different commands.
*
* \snippet sdio.c snippet_cyhal_sdio_send_command
*
* \subsection subsection_sdio_use_case_4 Snippet4: Bulk Data Transfer
* The following snippet shows how to start a bulk data transfer.
*
* \snippet sdio.c snippet_cyhal_sdio_bulk_transfer
*
* \subsection subsection_sdio_use_case_5 Snippet5: Async Data Transfer
*
* The following snippet shows how to start an async data transfer.
* \snippet sdio.c snippet_cyhal_sdio_async_transfer
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "cy_result.h"
#include "cyhal_hw_types.h"
#if defined(__cplusplus)
extern "C" {
#endif
/*******************************************************************************
* Defines
*******************************************************************************/
#define CYHAL_SDIO_RET_NO_ERRORS (0x00) /**< No error*/
#define CYHAL_SDIO_RET_NO_SP_ERRORS (0x01) /**< Non-specific error code*/
#define CYHAL_SDIO_RET_CMD_CRC_ERROR (0x02) /**< There was a CRC error on the Command/Response*/
#define CYHAL_SDIO_RET_CMD_IDX_ERROR (0x04) /**< The index for the command didn't match*/
#define CYHAL_SDIO_RET_CMD_EB_ERROR (0x08) /**< There was an end bit error on the command*/
#define CYHAL_SDIO_RET_DAT_CRC_ERROR (0x10) /**< There was a data CRC Error*/
#define CYHAL_SDIO_RET_CMD_TIMEOUT (0x20) /**< The command didn't finish before the timeout period was over*/
#define CYHAL_SDIO_RET_DAT_TIMEOUT (0x40) /**< The data didn't finish before the timeout period was over*/
#define CYHAL_SDIO_RET_RESP_FLAG_ERROR (0x80) /**< There was an error in the resposne flag for command 53*/
#define CYHAL_SDIO_CLOCK_ERROR (0x100) /**< Failed to initial clock for SDIO */
#define CYHAL_SDIO_BAD_ARGUMENT (0x200) /**< Bad argument passed for SDIO */
#define CYHAL_SDIO_SEMA_NOT_INITED (0x400) /**< Semaphore is not initiated */
#define CYHAL_SDIO_FUNC_NOT_SUPPORTED (0x800) /**< Function is not supported */
#define CYHAL_SDIO_CANCELED (0x1000) /**< Operation canceled */
#define CYHAL_SDIO_PM_PENDING_ERROR (0x2000) /**< Transfer cannot be initiated after power mode transition allowed.*/
/* HAL return value defines */
/** \addtogroup group_hal_results_sdio SDIO HAL Results
* SDIO specific return codes
* \ingroup group_hal_results
* \{ *//**
*/
/** Incorrect parameter value define */
#define CYHAL_SDIO_RSLT_ERR_BAD_PARAM \
(CYHAL_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_SDIO, CYHAL_SDIO_BAD_ARGUMENT))
/** Clock initialization error define */
#define CYHAL_SDIO_RSLT_ERR_CLOCK \
(CYHAL_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_SDIO, CYHAL_SDIO_CLOCK_ERROR))
/** Semaphore not initiated error define */
#define CYHAL_SDIO_RSLT_ERR_SEMA_NOT_INITED \
(CYHAL_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_SDIO, CYHAL_SDIO_SEMA_NOT_INITED))
/** Error define based on SDIO lower function return value */
#define CYHAL_SDIO_RSLT_ERR_FUNC_RET(retVal) \
(CYHAL_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_SDIO, ((uint16_t)retVal)))
/** Define to indicate canceled operation */
#define CYHAL_SDIO_RSLT_CANCELED \
(CYHAL_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_SDIO, CYHAL_SDIO_CANCELED))
/** Transfers are not allowed after the SDIO block has allowed power mode transition. */
#define CYHAL_SDIO_RSLT_ERR_PM_PENDING \
(CYHAL_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_SDIO, CYHAL_SDIO_PM_PENDING_ERROR))
/**
* \}
*/
/*******************************************************************************
* Enumerations
*******************************************************************************/
/** Commands that can be issued */
typedef enum
{
CYHAL_SDIO_CMD_GO_IDLE_STATE = 0, //!< Go to idle state
CYHAL_SDIO_CMD_SEND_RELATIVE_ADDR = 3, //!< Send a relative address
CYHAL_SDIO_CMD_IO_SEND_OP_COND = 5, //!< Send an OP IO
CYHAL_SDIO_CMD_SELECT_CARD = 7, //!< Send a card select
CYHAL_SDIO_CMD_GO_INACTIVE_STATE = 15, //!< Go to inactive state
CYHAL_SDIO_CMD_IO_RW_DIRECT = 52, //!< Perform a direct read/write
CYHAL_SDIO_CMD_IO_RW_EXTENDED = 53, //!< Perform an extended read/write
} cyhal_sdio_command_t;
/** Types of transfer that can be performed */
typedef enum
{
CYHAL_READ, //!< Read from the card
CYHAL_WRITE //!< Write to the card
} cyhal_transfer_t;
/** Types of events that could be asserted by SDIO */
typedef enum {
/* Interrupt-based thread events */
CYHAL_SDIO_CMD_COMPLETE = 0x00001, //!< Command Complete
CYHAL_SDIO_XFER_COMPLETE = 0x00002, //!< Host read/write transfer is complete
CYHAL_SDIO_BGAP_EVENT = 0x00004, //!< This bit is set when both read/write transaction is stopped
CYHAL_SDIO_DMA_INTERRUPT = 0x00008, //!< Host controller detects an SDMA Buffer Boundary during transfer
CYHAL_SDIO_BUF_WR_READY = 0x00010, //!< This bit is set if the Buffer Write Enable changes from 0 to 1
CYHAL_SDIO_BUF_RD_READY = 0x00020, //!< This bit is set if the Buffer Read Enable changes from 0 to 1
CYHAL_SDIO_CARD_INSERTION = 0x00040, //!< This bit is set if the Card Inserted in the Present State
CYHAL_SDIO_CARD_REMOVAL = 0x00080, //!< This bit is set if the Card Inserted in the Present State
CYHAL_SDIO_CARD_INTERRUPT = 0x00100, //!< The synchronized value of the DAT[1] interrupt input for SD mode
CYHAL_SDIO_INT_A = 0x00200, //!< Reserved: set to 0
CYHAL_SDIO_INT_B = 0x00400, //!< Reserved: set to 0
CYHAL_SDIO_INT_C = 0x00800, //!< Reserved: set to 0
CYHAL_SDIO_RE_TUNE_EVENT = 0x01000, //!< Reserved: set to 0
CYHAL_SDIO_FX_EVENT = 0x02000, //!< This status is set when R[14] of response register is set to 1
CYHAL_SDIO_CQE_EVENT = 0x04000, //!< This status is set if Command Queuing/Crypto event has occurred
CYHAL_SDIO_ERR_INTERRUPT = 0x08000, //!< If any of the bits in the Error Interrupt Status register are set
/* Non-interrupt-based thread events */
CYHAL_SDIO_GOING_DOWN = 0x10000, //!< The interface is going away (eg: powering down for some period of time)
CYHAL_SDIO_COMING_UP = 0x20000, //!< The interface is back up (eg: came back from a low power state)
CYHAL_SDIO_ALL_INTERRUPTS = 0x0E1FF, //!< Is used to enable/disable all interrupts events
} cyhal_sdio_event_t;
/*******************************************************************************
* Data Structures
*******************************************************************************/
/** @brief SDIO controller initial configuration */
typedef struct
{
uint32_t frequencyhal_hz; //!< Clock frequency, in hertz
uint16_t block_size; //!< Block size
} cyhal_sdio_cfg_t;
/** Callback for SDIO events */
typedef void (*cyhal_sdio_event_callback_t)(void *callback_arg, cyhal_sdio_event_t event);
/*******************************************************************************
* Data Structures
*******************************************************************************/
/** Initialize the SDIO peripheral
*
* @param[out] obj Pointer to an SDIO object.
* The caller must allocate the memory for this object but the init
* function will initialize its contents.
* @param[out] clk The pin connected to the clk signal
* @param[in] cmd The pin connected to the command signal
* @param[in] data0 The pin connected to the data0 signal
* @param[in] data1 The pin connected to the data1 signal
* @param[in] data2 The pin connected to the data2 signal
* @param[in] data3 The pin connected to the data3 signal
* @return The status of the init request
*
* Returns \ref CY_RSLT_SUCCESS on successful operation. Refer \ref subsection_sdio_use_case_1 for more information.
*/
cy_rslt_t cyhal_sdio_init(cyhal_sdio_t *obj, cyhal_gpio_t cmd, cyhal_gpio_t clk, cyhal_gpio_t data0, cyhal_gpio_t data1, cyhal_gpio_t data2, cyhal_gpio_t data3);
/** Release the SDIO block.
*
* @param[in,out] obj The SDIO object
*/
void cyhal_sdio_free(cyhal_sdio_t *obj);
/** Configure the SDIO block with required parameters. Refer \ref cyhal_sdio_cfg_t for more information.
*
* @param[in,out] obj The SDIO object
* @param[in] config The SDIO configuration to apply
* @return The status of the configure request.
*
* Returns \ref CY_RSLT_SUCCESS on successful operation.
*/
cy_rslt_t cyhal_sdio_configure(cyhal_sdio_t *obj, const cyhal_sdio_cfg_t *config);
/** Sends command to the SDIO device. See \ref cyhal_sdio_command_t for list of available commands.
*
* This will block until the command is completed.
*
* @param[in,out] obj The SDIO object
* @param[in] direction The direction of transfer (read/write)
* @param[in] command The command to send to the SDIO device
* @param[in] argument The argument to the command
* @param[out] response The response from the SDIO device
* @return The status of the command transfer.
*
* Returns \ref CY_RSLT_SUCCESS on successful operation. Refer \ref subsection_sdio_use_case_3 for more information.
*/
cy_rslt_t cyhal_sdio_send_cmd(const cyhal_sdio_t *obj, cyhal_transfer_t direction, cyhal_sdio_command_t command, uint32_t argument, uint32_t* response);
/** Performs a bulk data transfer. Sends \ref CYHAL_SDIO_CMD_IO_RW_EXTENDED command (CMD=53) which allows writing and reading of a large number of I/O registers with a single command.
*
* This will block until the transfer is completed.
*
* @param[in,out] obj The SDIO object
* @param[in] direction The direction of transfer (read/write)
* @param[in] argument The argument to the command
* @param[in] data The data to send to the SDIO device. A bulk transfer is done in block
* size (default: 64 bytes) chunks for better performance. Therefore,
* the size of the data buffer passed into this function must be at least
* `length` bytes and a multiple of the block size. For example, when
* requesting to read 100 bytes of data with a block size 64 bytes, the
* data buffer needs to be at least 128 bytes. The first 100 bytes of data
* in the buffer will be the requested data.
* @param[in] length The number of bytes to send
* @param[out] response The response from the SDIO device
* @return The status of the bulk transfer operation.
*
* Returns \ref CY_RSLT_SUCCESS on successful operation. Refer \ref subsection_sdio_use_case_4 for more information.
*/
cy_rslt_t cyhal_sdio_bulk_transfer(cyhal_sdio_t *obj, cyhal_transfer_t direction, uint32_t argument, const uint32_t* data, uint16_t length, uint32_t* response);
/** Performs a bulk asynchronous data transfer by issuing the \ref CYHAL_SDIO_CMD_IO_RW_EXTENDED command(CMD=53) to the SDIO block.
* After exiting this function the \ref CYHAL_SDIO_CMD_COMPLETE and \ref CYHAL_SDIO_XFER_COMPLETE events are not asserted.
*
* To complete the asynchronous transfer, call \ref cyhal_sdio_is_busy()
* until it returns false.
* The \ref CYHAL_SDIO_CMD_COMPLETE and \ref CYHAL_SDIO_XFER_COMPLETE events are enabled
* after the asynchronous transfer is complete and in the condition they were
* enabled in before the transfer operation started. Handle these events in the interrupt callback.
*
* When the transfer is complete, the \ref CYHAL_SDIO_XFER_COMPLETE event will be raised.
* See \ref cyhal_sdio_register_callback and \ref cyhal_sdio_enable_event.
*
* @param[in,out] obj The SDIO object
* @param[in] direction The direction of transfer (read/write)
* @param[in] argument The argument to the command
* @param[in] data The data to send to the SDIO device
* @param[in] length The number of bytes to send
* @return The status of the async tranfer operation.
*
* Returns \ref CY_RSLT_SUCCESS on successful operation. Refer \ref subsection_sdio_use_case_5 for more information.
*/
cy_rslt_t cyhal_sdio_transfer_async(cyhal_sdio_t *obj, cyhal_transfer_t direction, uint32_t argument, const uint32_t* data, uint16_t length);
/** Checks if the specified SDIO is in use
*
* @param[in] obj The SDIO peripheral to check
* @return true if SDIO is in use. false, otherwise.
*/
bool cyhal_sdio_is_busy(const cyhal_sdio_t *obj);
/** Abort an SDIO transfer
*
* @param[in] obj The SDIO peripheral to stop
* @return The status of the abort_async request.
*
* Returns \ref CY_RSLT_SUCCESS on successful operation.
*/
cy_rslt_t cyhal_sdio_abort_async(const cyhal_sdio_t *obj);
/** Register an SDIO event callback to be invoked when the event is triggered.
*
* This function will be called when one of the events enabled by \ref cyhal_sdio_enable_event occurs.
*
* @param[in] obj The SDIO object
* @param[in] callback The callback function which will be invoked when the event triggers
* @param[in] callback_arg Generic argument that will be provided to the callback when executed
*
* Refer \ref subsection_sdio_use_case_2 for more implementation.
*/
void cyhal_sdio_register_callback(cyhal_sdio_t *obj, cyhal_sdio_event_callback_t callback, void *callback_arg);
/** Enables callbacks to be triggered for specified SDIO events. Refer \ref cyhal_sdio_event_t for all events.
*
* @param[in] obj The SDIO object
* @param[in] event The SDIO event type
* @param[in] intr_priority The priority for NVIC interrupt events
* @param[in] enable Set to true to enable events, or false to disable them
*
* Refer \ref subsection_sdio_use_case_2 for more information.
*/
void cyhal_sdio_enable_event(cyhal_sdio_t *obj, cyhal_sdio_event_t event, uint8_t intr_priority, bool enable);
/*******************************************************************************
* Backward compatibility macro. The following code is DEPRECATED and must
* not be used in new projects
*******************************************************************************/
/** \cond INTERNAL */
#define cyhal_sdio_register_irq cyhal_sdio_register_callback
#define cyhal_sdio_irq_enable(obj, event, enable) cyhal_sdio_enable_event(obj, event, CYHAL_ISR_PRIORITY_DEFAULT, enable)
typedef cyhal_sdio_event_t cyhal_sdio_irq_event_t;
typedef cyhal_sdio_event_callback_t cyhal_sdio_irq_handler_t;
/** \endcond */
#if defined(__cplusplus)
}
#endif
#ifdef CYHAL_SDIO_IMPL_HEADER
#include CYHAL_SDIO_IMPL_HEADER
#endif /* CYHAL_SDIO_IMPL_HEADER */
/** \} group_hal_sdio */

View File

@ -0,0 +1,383 @@
/***************************************************************************//**
* \file cyhal_spi.h
*
* \brief
* Provides a high level interface for interacting with the Cypress SPI.
* This interface abstracts out the chip specific details. If any chip specific
* functionality is necessary, or performance is critical the low level functions
* can be used directly.
*
********************************************************************************
* \copyright
* Copyright 2018-2020 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.
*******************************************************************************/
/**
* \addtogroup group_hal_spi SPI (Serial Peripheral Interface)
* \ingroup group_hal
* \{
* High level interface for interacting with the Serial Peripheral Interface (SPI).
*
* The SPI protocol is a synchronous serial interface protocol. Devices operate
* in either master or slave mode. The master initiates the data transfer.
*
* Motorola SPI modes 0, 1, 2, and 3 are supported, with either MSB or LSB first.
* The operating mode and data frame size can be configured via \ref cyhal_spi_cfg_t.
*
* \section section_spi_features Features
* * Supports master and slave functionality.
* * Supports Motorola modes - 0, 1, 2 and 3 - \ref cyhal_spi_mode_t
* * MSb or LSb first shift direction - \ref cyhal_spi_mode_t
* * Master supports up to four slave select lines
* * Supports data frame size of 8 or 16 bits
* * Configurable interrupt and callback assignment on SPI events:
* Data transfer to FIFO complete, Transfer complete and Transmission error - \ref cyhal_spi_event_t
* * Supports changing baud rate of the transaction in run time.
* * Provides functions to send/receive a single byte or block of data.
*
* \section section_spi_quickstart Quick Start
*
* Initialise a SPI master or slave interface using \ref cyhal_spi_init() and provide the SPI pins (<b>mosi</b>, <b>miso</b>, <b>sclk</b>, <b>ssel</b>),
* number of bits per frame (<b>data_bits</b>) and SPI Motorola <b>mode</b>. The data rate can be set using \ref cyhal_spi_set_frequency(). <br>
* See \ref section_spi_snippets for code snippets to send or receive the data.
*
* \section section_spi_snippets Code snippets
*
* \subsection subsection_spi_snippet_1 Snippet 1: SPI Master - Single byte transfer operation (Read and Write)
* The following code snippet initializes an SPI Master interface using the \ref cyhal_spi_init(). The data rate of transfer is set using \ref cyhal_spi_set_frequency().
* The code snippet shows how to transfer a single byte of data using \ref cyhal_spi_send() and \ref cyhal_spi_recv().
* \snippet spi.c snippet_cyhal_spi_master_byte_operation
*
* \subsection subsection_spi_snippet_2 Snippet 2: SPI Slave - Single byte transfer operation (Read and Write)
* The following code snippet initializes an SPI Slave interface using the \ref cyhal_spi_init(). The data rate of transfer is set using \ref cyhal_spi_set_frequency.
* The code snippet shows how to transfer a single byte of data using \ref cyhal_spi_send() and \ref cyhal_spi_recv.
* \snippet spi.c snippet_cyhal_spi_slave_byte_operation
*
* \subsection subsection_spi_snippet_3 Snippet 3: SPI Block Data transfer
* The following snippet sends and receives an array of data in a single SPI transaction using \ref cyhal_spi_transfer(). The example
* uses SPI master to transmit 5 bytes of data and receive 5 bytes of data in a single transaction.
* \snippet spi.c snippet_cyhal_spi_block_data_transfer
*
* \subsection subsection_spi_snippet_4 Snippet 4: Interrupts on SPI events
* SPI interrupt events ( \ref cyhal_spi_event_t) can be mapped to an interrupt and assigned to a callback function.
* The callback function needs to be first registered and then the event needs to be enabled.
* The following snippet initialises a SPI master to perform a block transfer using \ref cyhal_spi_transfer_async(). This is a non-blocking function.
* A callback function is registered using \ref cyhal_spi_register_callback to notify whenever the SPI transfer is complete.
* \snippet spi.c snippet_cyhal_spi_interrupt_callback_events
* \section subsection_spi_moreinfor More Information
*
* * <a href="https://github.com/cypresssemiconductorco/mtb-example-psoc6-spi-master"><b>mtb-example-psoc6-spi-master</b></a>: This example project demonstrates
* use of SPI (HAL) resource in PSoC® 6 MCU in Master mode to write data to an SPI slave.
*
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "cy_result.h"
#include "cyhal_hw_types.h"
#if defined(__cplusplus)
extern "C" {
#endif
/** \addtogroup group_hal_results_spi SPI HAL Results
* SPI specific return codes
* \ingroup group_hal_results
* \{ *//**
*/
/** Bad argument */
#define CYHAL_SPI_RSLT_BAD_ARGUMENT \
(CYHAL_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_SPI, 0))
/** Failed to initialize SPI clock */
#define CYHAL_SPI_RSLT_CLOCK_ERROR \
(CYHAL_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_SPI, 1))
/** Failed to Transfer SPI data */
#define CYHAL_SPI_RSLT_TRANSFER_ERROR \
(CYHAL_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_SPI, 2))
/** Provided clock is not supported by SPI */
#define CYHAL_SPI_RSLT_CLOCK_NOT_SUPPORTED \
(CYHAL_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_SPI, 3))
/** Provided PIN configuration is not supported by SPI */
#define CYHAL_SPI_RSLT_PIN_CONFIG_NOT_SUPPORTED \
(CYHAL_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_SPI, 5))
/** Provided PIN configuration is not supported by SPI */
#define CYHAL_SPI_RSLT_INVALID_PIN_API_NOT_SUPPORTED \
(CYHAL_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_SPI, 6))
/** The requested resource type is invalid */
#define CYHAL_SPI_RSLT_ERR_INVALID_PIN \
(CYHAL_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_SPI, 7))
/** Cannot configure SSEL signal */
#define CYHAL_SPI_RSLT_ERR_CANNOT_CONFIG_SSEL \
(CYHAL_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_SPI, 8))
/** Cannot switch SSEL - device is busy or incorrect pin provided */
#define CYHAL_SPI_RSLT_ERR_CANNOT_SWITCH_SSEL \
(CYHAL_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_SPI, 9))
/**
* \}
*/
/** Compatibility define for cyhal_spi_set_frequency. */
#define cyhal_spi_frequency cyhal_spi_set_frequency
/** SPI interrupt triggers */
typedef enum {
/** All transfer data has been moved into data FIFO */
CYHAL_SPI_IRQ_DATA_IN_FIFO = 1 << 1,
/** Transfer complete. */
CYHAL_SPI_IRQ_DONE = 1 << 2,
/** An error occurred while transferring data */
CYHAL_SPI_IRQ_ERROR = 1 << 3,
} cyhal_spi_event_t;
/** SPI Slave Select polarity */
typedef enum {
/** SSEL signal is active low */
CYHAL_SPI_SSEL_ACTIVE_LOW = 0,
/** SSEL signal is active high */
CYHAL_SPI_SSEL_ACTIVE_HIGH = 1,
} cyhal_spi_ssel_polarity_t;
/** Handler for SPI interrupts */
typedef void (*cyhal_spi_event_callback_t)(void *callback_arg, cyhal_spi_event_t event);
/** Flag for SPI \ref cyhal_spi_mode_t values indicating that the LSB is sent first. */
#define CYHAL_SPI_MODE_FLAG_LSB (0x01u)
/** Flag for SPI \ref cyhal_spi_mode_t values indicating that the CPHA=1. */
#define CYHAL_SPI_MODE_FLAG_CPHA (0x02u)
/** Flag for SPI \ref cyhal_spi_mode_t values indicating that the CPOL=1. */
#define CYHAL_SPI_MODE_FLAG_CPOL (0x04u)
/** Creates a \ref cyhal_spi_mode_t value given the cpol, cpha, lsb values. */
#define CYHAL_SPI_MODE(cpol, cpha, lsb) (((cpol > 0) ? CYHAL_SPI_MODE_FLAG_CPOL : 0) | \
((cpha > 0) ? CYHAL_SPI_MODE_FLAG_CPHA : 0) | \
(( lsb > 0) ? CYHAL_SPI_MODE_FLAG_LSB : 0))
/** SPI operating modes */
typedef enum
{
/** Standard motorola SPI CPOL=0, CPHA=0 with MSB first operation */
CYHAL_SPI_MODE_00_MSB = CYHAL_SPI_MODE(0, 0, 0),
/** Standard motorola SPI CPOL=0, CPHA=0 with LSB first operation */
CYHAL_SPI_MODE_00_LSB = CYHAL_SPI_MODE(0, 0, 1),
/** Standard motorola SPI CPOL=0, CPHA=1 with MSB first operation */
CYHAL_SPI_MODE_01_MSB = CYHAL_SPI_MODE(0, 1, 0),
/** Standard motorola SPI CPOL=0, CPHA=1 with LSB first operation */
CYHAL_SPI_MODE_01_LSB = CYHAL_SPI_MODE(0, 1, 1),
/** Standard motorola SPI CPOL=1, CPHA=0 with MSB first operation */
CYHAL_SPI_MODE_10_MSB = CYHAL_SPI_MODE(1, 0, 0),
/** Standard motorola SPI CPOL=1, CPHA=0 with LSB first operation */
CYHAL_SPI_MODE_10_LSB = CYHAL_SPI_MODE(1, 0, 1),
/** Standard motorola SPI CPOL=1, CPHA=1 with MSB first operation */
CYHAL_SPI_MODE_11_MSB = CYHAL_SPI_MODE(1, 1, 0),
/** Standard motorola SPI CPOL=1, CPHA=1 with LSB first operation */
CYHAL_SPI_MODE_11_LSB = CYHAL_SPI_MODE(1, 1, 1),
} cyhal_spi_mode_t;
/** @brief Initial SPI configuration. */
typedef struct
{
cyhal_spi_mode_t mode; //!< The operating mode
uint8_t data_bits; //!< The number of bits per transfer
bool is_slave; //!< Whether the peripheral is operating as slave or master
} cyhal_spi_cfg_t;
/** Initialize the SPI peripheral
*
* Configures the pins used by SPI, sets a default format and frequency, and enables the peripheral
* @param[out] obj Pointer to a SPI object. The caller must allocate the memory
* for this object but the init function will initialize its contents.
* @param[in] mosi The pin to use for MOSI
* @note At least MOSI or MISO pin should be non-NC
* @param[in] miso The pin to use for MISO
* @note At least MOSI or MISO pin should be non-NC
* @param[in] sclk The pin to use for SCLK
* @note This pin cannot be NC
* @param[in] ssel The pin to use for SSEL
* @note Provided pin will be configured for \ref CYHAL_SPI_SSEL_ACTIVE_LOW polarity and set as active. This can be changed
* (as well as additional ssel pins can be added) by \ref cyhal_spi_slave_select_config and \ref cyhal_spi_select_active_ssel
* functions. This pin can be NC.
* @param[in] clk The clock to use can be shared, if not provided a new clock will be allocated
* @param[in] bits The number of bits per frame
* @note bits should be 8 or 16
* @param[in] mode The SPI mode (clock polarity, phase, and shift direction)
* @param[in] is_slave false for master mode or true for slave mode operation
* @return The status of the init request
*/
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);
/** Release a SPI object
*
* Return the peripheral, pins and clock owned by the SPI object to their reset state
* @param[in,out] obj The SPI object to deinitialize
*/
void cyhal_spi_free(cyhal_spi_t *obj);
/** Set the SPI baud rate
*
* Actual frequency may differ from the desired frequency due to available dividers and bus clock
* Configures the SPI peripheral's baud rate
* @param[in,out] obj The SPI object to configure
* @param[in] hz The baud rate in Hz
* @return The status of the set_frequency request
*/
cy_rslt_t cyhal_spi_set_frequency(cyhal_spi_t *obj, uint32_t hz);
/** Configures provided ssel pin to work as SPI slave select with specified polarity.
*
* Multiple pins can be configured as SPI slave select pins. Please refer to device datasheet for details. Switching
* between configured slave select pins is done by \ref cyhal_spi_select_active_ssel function.
* Unless modified with this function, the SSEL pin provided as part of \ref cyhal_spi_init is the default.
* @param[in] obj The SPI object to add slave select for
* @param[in] ssel Slave select pin to be added
* @param[in] polarity Polarity of slave select
* @return The status of ssel pin configuration
*/
cy_rslt_t cyhal_spi_slave_select_config(cyhal_spi_t *obj, cyhal_gpio_t ssel, cyhal_spi_ssel_polarity_t polarity);
/** Selects an active slave select line from one of available.
*
* This function is applicable for the master and slave.
* SSEL pin should be configured by \ref cyhal_spi_slave_select_config or \ref cyhal_spi_init functions prior
* to selecting it as active. The active slave select line will automatically be toggled as part of any transfer.
* @param[in] obj The SPI object for switching
* @param[in] ssel Slave select pin to be set as active
* @return CY_RSLT_SUCCESS if slave select was switched successfully, otherwise - CYHAL_SPI_RSLT_ERR_CANNOT_SWITCH_SSEL
*/
cy_rslt_t cyhal_spi_select_active_ssel(cyhal_spi_t *obj, cyhal_gpio_t ssel);
/** Synchronously get a received value out of the SPI receive buffer
*
* In Master mode - transmits fill-in value and read the data from RxFifo
* In Slave mode - Blocks until a value is available
*
* @param[in] obj The SPI peripheral to read
* @param[in] value The value received
* @return The status of the read request
* @note
* - In Master mode, MISO pin required to be non-NC for this API to operate
* - In Slave mode, MOSI pin required to be non-NC for this API to operate
*/
cy_rslt_t cyhal_spi_recv(cyhal_spi_t *obj, uint32_t* value);
/** Synchronously send a byte out
*
* In Master mode transmits value to slave and read/drop a value from the RxFifo.
* In Slave mode writes a value to TxFifo
*
* @param[in] obj The SPI peripheral to use for sending
* @param[in] value The value to send
* @return The status of the write request
* @note
* - In Master mode, MOSI pin required to be non-NC for this API to operate
* - In Slave mode, MISO pin required to be non-NC for this API to operate
*/
cy_rslt_t cyhal_spi_send(cyhal_spi_t *obj, uint32_t value);
/** Synchronously Write a block out and receive a value
*
* The total number of bytes sent and received will be the maximum of tx_length
* and rx_length. The bytes written will be padded (at the end) with the value
* given by write_fill.
*
* This function will block for the duration of the transfer. \ref cyhal_spi_transfer_async
* can be used for non-blocking transfers.
*
* @param[in] obj The SPI peripheral to use for sending
* @param[in] tx Pointer to the byte-array of data to write to the device
* @param[in,out] tx_length Number of bytes to write, updated with the number actually written
* @param[out] rx Pointer to the byte-array of data to read from the device
* @param[in,out] rx_length Number of bytes to read, updated with the number actually read
* @param[in] write_fill Default data transmitted while performing a read
* @return The status of the transfer request
* @note Both MOSI and MISO pins required to be non-NC for this API to operate
*/
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);
/** Start an asynchronous SPI transfer.
*
* This will transfer `rx_length` bytes into the buffer pointed to by `rx`, while simultaneously transfering
* `tx_length` bytes of data from the buffer pointed to by `tx`, both in the background.
* When the transfer is complete, the @ref CYHAL_SPI_IRQ_DONE event will be raised.
* See @ref cyhal_spi_register_callback and @ref cyhal_spi_enable_event.
* \note For blocking transfers cyhal_spi_transfer can be used.
*
* @param[in] obj The SPI object that holds the transfer information
* @param[in] tx The transmit buffer
* @param[in,out] tx_length The number of bytes to transmit
* @param[out] rx The receive buffer
* @param[in,out] rx_length The number of bytes to receive
* @return The status of the transfer_async request
* @note Both MOSI and MISO pins required to be non-NC for this API to operate
*/
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);
/** Checks if the specified SPI peripheral is in use
*
* @param[in] obj The SPI peripheral to check
* @return Indication of whether the SPI is still transmitting
*/
bool cyhal_spi_is_busy(cyhal_spi_t *obj);
/** Abort an SPI transfer
*
* @param[in] obj The SPI peripheral to stop
* @return The status of the abort_async request
*/
cy_rslt_t cyhal_spi_abort_async(cyhal_spi_t *obj);
/** Register a SPI callback handler
*
* This function will be called when one of the events enabled by \ref cyhal_spi_enable_event occurs.
*
* @param[in] obj The SPI object
* @param[in] callback The callback handler which will be invoked when the interrupt fires
* @param[in] callback_arg Generic argument that will be provided to the callback when called
*/
void cyhal_spi_register_callback(cyhal_spi_t *obj, cyhal_spi_event_callback_t callback, void *callback_arg);
/** Configure SPI interrupt. This function is used for word-approach
*
* When an enabled event occurs, the function specified by \ref cyhal_spi_register_callback will be called.
*
* @param[in] obj The SPI object
* @param[in] event The SPI event type
* @param[in] intr_priority The priority for NVIC interrupt events
* @param[in] enable True to turn on interrupts, False to turn off
*/
void cyhal_spi_enable_event(cyhal_spi_t *obj, cyhal_spi_event_t event, uint8_t intr_priority, bool enable);
/*******************************************************************************
* Backward compatibility macro. The following code is DEPRECATED and must
* not be used in new projects
*******************************************************************************/
/** \cond INTERNAL */
typedef cyhal_spi_event_t cyhal_spi_irq_event_t;
/** \endcond */
#if defined(__cplusplus)
}
#endif
#ifdef CYHAL_SPI_IMPL_HEADER
#include CYHAL_SPI_IMPL_HEADER
#endif /* CYHAL_SPI_IMPL_HEADER */
/** \} group_hal_spi */