mbed-os/hal/sai_api.h

208 lines
8.1 KiB
C

/** \addtogroup hal */
/** @{*/
/* mbed Microcontroller Library
* Copyright (c) 2006-2018 ARM Limited
*
* 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 MBED_SAI_API_H
#define MBED_SAI_API_H
#include "device.h"
#if DEVICE_SAI
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
/**
* \defgroup hal_sai Serial audio interface hal functions
* Low level interface to the serial audio interface of a target.
*
* # Defined behaviours
* - `sai_init()` returns `SAI_RESULT_INVALID_PARAM` if at least one of the given parameters is
* undefined (NULL) ;
* - `sai_init()` returns `SAI_RESULT_ALREADY_INITIALIZED` if SAI is already initialized ;
* - `sai_init()` returns `SAI_RESULT_CONFIG_UNSUPPORTED` if the device can never support this
* configuration ;
* - `sai_init()` returns `SAI_RESULT_CONFIG_MISMATCH` if the device is not able to support this
* configuration at this point time because of other 'live' constraints (such as a shared
* format/clock configuration with a sibling) ;
* - `sai_free()` does nothing if passed a NULL pointer ;
* - `sai_free()` de-initialized & un-clock unused part of the device ;
* - a device/block can be reinitialized via `sai_init()` after being `sai_free()`d.
*
* if the device is a *receiver* :
* - `sai_transfer()` returns false if the `sai_t` object is NULL ;
* - `sai_transfer()` returns false if there's no sample in the FiFo ;
* - `sai_transfer()` if `psample` is NULL : it pops 1 sample from the FiFo and returns true ;
* - `sai_transfer()` if `psample` is not NULL : it pops 1 sample from the FiFo, stores it to the address
* pointed by `psample`, and returns true.
*
* if the device is a *transmitter* :
* - `sai_transfer()` returns false if the `sai_t` object is NULL ;
* - `sai_transfer()` returns false if the fifo is full and `*psample` could not be pushed ;
* - `sai_transfer()` if `psample` is NULL : it pushes one '0' sample to the FiFo and returns true ;
* - `sai_transfer()` if `psample` is not NULL : it pushes the pointed sample to the FiFo and returns true.
*
* # Undefined behaviours
* - Calling any function other than `sai_init()` before the initialization of the SAI ;
* - Calling any function other than `sai_init()` after calling `sai_free()`.
*
* # other requirements
* A target must also define these elements to allow tests to be run.
* - SAI_DEFAULT_SAMPLE_RATE :
* This is used by CI tests to validate that the device behaves as expected. As this parameter
* is higly device dependant, Partners need to set this value to an appropriate rate that can be
* supported by the target.
* - Pins for 2 SAI/I²S interface including MCLK, BCLK, WCLK and SD named respectively
* - SAI_A_MCLK, SAI_A_BCLK, SAI_A_WCLK and SAI_A_SD ;
* - SAI_B_MCLK, SAI_B_BCLK, SAI_B_WCLK and SAI_B_SD.
*
* @note
* A transceiver supporting async rx/tx should be considered as 2 different peripherals :
* - one read-only
* - one write-only
* The first allocated channel may or may not limit the second one's feature.
* eg:
* In a peripheral that supports async rx/tx but requires format to be the same,
* the first allocated instance will set the format and tie the second one to this format.
*
* @{
*/
/**
* \defgroup hal_sai_tests sai hal tests
* The sai HAL tests ensure driver conformance to defined behaviour.
*
* To run the SAI hal tests use the command:
*
* mbed test -t <toolchain> -m <target> -n tests-mbed_hal-sai*
*
*/
/** Defines frame format. */
typedef struct sai_format_s {
bool bclk_polarity; /**< true for Active high */
bool wclk_polarity; /**< true for Active high */
bool ws_delay; /**< true to toggle ws one bit earlier than the frame */
uint8_t ws_length; /**< ws assertion length from 1bclk to word length. */
uint8_t frame_length; /**< Frame length in word count [1; 32] */
uint32_t word_mask; /**< Mask on frame for used word (bitfield) */
uint8_t word_length; /**< Word length in bits [1; 32] */
uint8_t data_length; /**< Data length within the word. This must <= to word_length. */
bool lsb_first; /**< true to send lsb first */
bool aligned_left; /**< true to align Left */
uint8_t bit_shift; /**< sample bit shift distance from its alignment point. */
} sai_format_t;
/** Defines input mclk source */
typedef enum sai_clock_source_e {
SAI_CLOCK_SOURCE_INTERNAL,
SAI_CLOCK_SOURCE_EXTERNAL,
SAI_CLOCK_SOURCE_SIBLING
} sai_clock_source_t;
/** Init structure */
typedef struct sai_init_s {
PinName mclk; /**< master clock pin (opional, can be NC). */
PinName sd; /**< Data pin. */
PinName bclk; /**< Bit clock pin. */
PinName wclk; /**< Word clock pin. */
sai_clock_source_t mclk_source; /**< mclk input to this peripheral */
uint32_t input_mclk_frequency;
uint32_t output_mclk_frequency;
uint32_t sample_rate; /**< for example: 44100Hz */
bool is_receiver; /**< true if this is a receiver. */
sai_format_t format; /**< Describes the frame format. */
} sai_init_t;
/** Initialization return status.*/
typedef enum sai_result_e {
SAI_RESULT_OK, /**< Everything went well. */
SAI_RESULT_DEVICE_BUSY, /**< All endpoint for the requested type are busy. */
SAI_RESULT_CONFIG_UNSUPPORTED, /**< Some requested features are not supported by this platform. */
SAI_RESULT_CONFIG_MISMATCH, /**< Some requested features mismatch with the required config
(depends on underlying device state) */
SAI_RESULT_GENERIC_FAILURE, /**< In case of unknown error */
SAI_RESULT_ALREADY_INITIALIZED, /**< The block is already in use */
SAI_RESULT_INVALID_PARAM, /**< An input parameter is invalid/out of range */
} sai_result_t;
/** Delegated typedef @see target/ ** /object.h */
typedef struct sai_s sai_t;
/** SAI configuration for I2S Philips 16 bit data & word size */
extern const sai_format_t sai_mode_i2s16;
/** SAI configuration for I2S Philips 16bit data & 32bit word size */
extern const sai_format_t sai_mode_i2s16w32;
/** SAI configuration for I2S Philips 32 bit data & word size */
extern const sai_format_t sai_mode_i2s32;
/** SAI configuration for PCM 16 bit data & word size with long sync */
extern const sai_format_t sai_mode_pcm16l;
/** SAI configuration for PCM 16 bit data & word size with short sync */
extern const sai_format_t sai_mode_pcm16s;
/**
* Initialize `obj` based on `init` values.
* @param obj An SAI object to initialize.
* @param init An init structure filled with configuration parameters.
* @return initialization result.
*/
sai_result_t sai_init(sai_t *obj, sai_init_t *init);
/**
* Attempt to transmit or receive a sample depending of the mode of this instance.
* @param obj This SAI instance.
* @param psample Pointer to store or fetch a sample.
* @return true if the/a sample was transmitted/received.
*
* @note:
* if psample is NULL :
* - on reception : will read a sample from the fifo to the nether.
* - on transmission : will send a '0'.
*/
bool sai_transfer(sai_t *obj, uint32_t *psample);
/**
* Releases & de-initialize the referenced peripherals.
* @param obj This SAI instance.
*/
void sai_free(sai_t *obj);
/**
* Checks init parameter sanity.
* @param init A config to be sanity checked.
* @return True if the init is sane.
* @note This does not verify that the device actually supports this configuration.
*/
bool sai_check_sanity(sai_init_t *init);
/**@}*/
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // DEVICE_SAI
#endif // MBED_SAI_API_H
/** @}*/