/** \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 -m -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 /** @}*/