X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=bertos%2Fdrv%2Fi2s.h;h=8758cb0080cb7e2a18e0340743495214603c1893;hb=e25abecb6a6ff52917d44d1331e5af831aeceb9c;hp=2623702c4e17fe165c804e20a694bc436b0464f0;hpb=6fc70471426c7427c1c4f1e8dffbed557ff90b44;p=bertos.git diff --git a/bertos/drv/i2s.h b/bertos/drv/i2s.h index 2623702c..8758cb00 100644 --- a/bertos/drv/i2s.h +++ b/bertos/drv/i2s.h @@ -26,92 +26,168 @@ * invalidate any other reasons why the executable file might be covered by * the GNU General Public License. * - * Copyright 2009 Develer S.r.l. (http://www.develer.com/) + * Copyright 2011 Develer S.r.l. (http://www.develer.com/) * * --> * - * \brief I2S driver functions. + * \defgroup i2s Generic I2S driver + * \ingroup drivers + * \{ + * \brief * - * This driver uses a double buffering technique to keep i2s bus busy. First fill in the two buffers - * using i2s_getBuffer(), then start audio playing with i2s_start(). Then call i2s_getFreeBuffer() - * until you have finished your samples. The reproduction will automatically stop if you don't - * call i2s_getFreeBuffer() frequently enough. + * Configuration file: cfg_i2s.h * - * Example: - * \code - * // fill in the buffers before start - * buf = i2s_getBuffer(I2S_FIRST_BUF); - * // ... - * buf = i2s_getBuffer(I2S_SECOND_BUF); - * // ... - * // here the driver will play only the first two buffers... - * i2s_start(); - * // ...call getFreeBuffer() to continue playing. - * while (!(buf = i2s_getFreeBuffer())) - * ; - * // now fill the buffer again - * \endcode - * - * \version $Id$ - * \author Luca Ottaviano + * \author Daniele Basile * * $WIZ$ module_name = "i2s" * $WIZ$ module_configuration = "bertos/cfg/cfg_i2s.h" - * $WIZ$ module_supports = "not atmega103 and not atmega168 and not atmega8" + * $WIZ$ module_supports = "not all" */ -#ifndef I2S_H -#define I2S_H -#include "cfg/cfg_i2s.h" +#ifndef DRV_I2S_H +#define DRV_I2S_H + +#warning __FILTER_NEXT_WARNING__ +#warning This API is ALPHA! we could change it.. #include +#include #include -#include -/** - * First buffer. - */ -#define I2S_FIRST_BUF 0 -/** - * Second buffer. - */ -#define I2S_SECOND_BUF 1 +#include -/** - * Initializes the module and sets current buffer to I2S_FIRST_BUF. - */ -void i2s_init(void); +#include CPU_HEADER(i2s) -/** - * Returns one of the two buffers or NULL if none is available. - * - * You can't call this function if you have already started the player. - * \param buf_num The number of the buffer, ie I2S_FIRST_BUF or I2S_SECOND_BUF. - * \return A pointer to the buffer if the buffer is available (not full), 0 on errors - */ -uint8_t *i2s_getBuffer(unsigned buf_num); +struct I2sContext; +struct I2s; -/** - * Returns a buffer that will be played after the current one. - * - * You should fill it faster than your reproduction time. You can't call this function - * if the player is not running - * \return The next buffer to be played, 0 if both are busy. - */ -uint8_t *i2s_getFreeBuffer(void); +typedef int (*i2s_write_t) (struct I2s *i2s, uint32_t sample); +typedef uint32_t (*i2s_read_t) (struct I2s *i2s); +typedef void (*i2s_dma_tx_buf_t) (struct I2s *i2s, void *buf, size_t len); +typedef void (*i2s_dma_rx_buf_t) (struct I2s *i2s, void *buf, size_t len); +typedef bool (*i2s_dma_tx_is_finished_t) (struct I2s *i2s); +typedef bool (*i2s_dma_rx_is_finished_t) (struct I2s *i2s); +typedef void (*i2s_dma_callback_t) (struct I2s *i2s, void *_buf, size_t len); +typedef void (*i2s_dma_start_streaming_t) (struct I2s *i2s, void *buf, size_t len, size_t slice_len); +typedef void (*i2s_dma_wait_t) (struct I2s *i2s); +typedef void (*i2s_dma_stop_t) (struct I2s *i2s); -/** - * Starts playing from I2S_FIRST_BUFFER. +typedef struct I2sContext +{ + i2s_write_t write; + i2s_dma_tx_buf_t tx_buf; + i2s_dma_tx_is_finished_t tx_isFinish; + i2s_dma_callback_t tx_callback; + i2s_dma_start_streaming_t tx_start; + i2s_dma_wait_t tx_wait; + i2s_dma_stop_t tx_stop; + size_t tx_slice_len; + + i2s_read_t read; + i2s_dma_rx_buf_t rx_buf; + i2s_dma_rx_is_finished_t rx_isFinish; + i2s_dma_callback_t rx_callback; + i2s_dma_start_streaming_t rx_start; + i2s_dma_wait_t rx_wait; + i2s_dma_stop_t rx_stop; + size_t rx_slice_len; + + DB(id_t _type); + +} I2sContext; + +typedef struct I2s +{ + I2sContext ctx; + struct I2sHardware *hw; +} I2s; + +INLINE int i2s_write(I2s *i2s, uint32_t sample) +{ + ASSERT(i2s->ctx.write); + return i2s->ctx.write(i2s, sample); +} + + +INLINE uint32_t i2s_read(I2s *i2s) +{ + ASSERT(i2s->ctx.read); + return i2s->ctx.read(i2s); +} + +/* + * Check if a dma transfer is finished. * - * You must have filled both buffers before calling this function. Does nothing if already playing. - * \return false on errors, true otherwise. + * Useful for kernel-less applications. */ -bool i2s_start(void); +INLINE bool i2s_dmaTxIsFinished(I2s *i2s) +{ + ASSERT(i2s->ctx.tx_isFinish); + return i2s->ctx.tx_isFinish(i2s); +} + +INLINE bool i2s_dmaRxIsFinished(I2s *i2s) +{ + ASSERT(i2s->ctx.rx_isFinish); + return i2s->ctx.rx_isFinish(i2s); +} + +INLINE void i2s_dmaTxBuffer(I2s *i2s, void *buf, size_t len) +{ + ASSERT(i2s->ctx.tx_buf); + i2s->ctx.tx_buf(i2s, buf, len); +} + +INLINE void i2s_dmaRxBuffer(I2s *i2s, void *buf, size_t len) +{ + ASSERT(i2s->ctx.rx_buf); + i2s->ctx.rx_buf(i2s, buf, len); +} + + +INLINE void i2s_dmaTxWait(I2s *i2s) +{ + ASSERT(i2s->ctx.tx_wait); + i2s->ctx.tx_wait(i2s); +} + + +INLINE void i2s_dmaStartTxStreaming(I2s *i2s, void *buf, size_t len, size_t slice_len, i2s_dma_callback_t callback) +{ + ASSERT(i2s->ctx.tx_start); + ASSERT(len % slice_len == 0); + ASSERT(callback); + + i2s->ctx.tx_callback = callback; + i2s->ctx.tx_slice_len = slice_len; + i2s->ctx.tx_start(i2s, buf, len, slice_len); +} + +INLINE void i2s_dmaTxStop(I2s *i2s) +{ + ASSERT(i2s->ctx.tx_stop); + i2s->ctx.tx_stop(i2s); +} -INLINE bool i2s_isPlaying(void) +INLINE void i2s_dmaStartRxStreaming(I2s *i2s, void *buf, size_t len, size_t slice_len, i2s_dma_callback_t callback) { - return !(SSC_SR & BV(SSC_TXEMPTY)); + ASSERT(i2s->ctx.rx_start); + ASSERT(len % slice_len == 0); + ASSERT(callback); + + i2s->ctx.rx_callback = callback; + i2s->ctx.rx_slice_len = slice_len; + i2s->ctx.rx_start(i2s, buf, len, slice_len); } -#endif /* I2S_H */ +INLINE void i2s_dmaRxStop(I2s *i2s) +{ + ASSERT(i2s->ctx.rx_stop); + i2s->ctx.rx_stop(i2s); +} + +void i2s_init(I2s *i2s, int channel); + +/** \} */ //defgroup i2s +#endif /* DRV_I2S_H */