mirror of
				https://github.com/esp8266/Arduino.git
				synced 2025-11-03 14:33:37 +03:00 
			
		
		
		
	Add I2S class support (#7874)
Fixes #427 Adds a basic I2S class based off of the Arduino-SAMD core. The raw i2s_xxx functions are still a better way to use I2S due to their flexibility, but this will allow basic Arduino sketches to work.
This commit is contained in:
		
				
					committed by
					
						
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							9fc5afd5fd
						
					
				
				
					commit
					e99df4fe1a
				
			@@ -24,7 +24,7 @@
 | 
			
		||||
#include "osapi.h"
 | 
			
		||||
#include "ets_sys.h"
 | 
			
		||||
#include "i2s_reg.h"
 | 
			
		||||
#include "i2s.h"
 | 
			
		||||
#include "core_esp8266_i2s.h"
 | 
			
		||||
 | 
			
		||||
extern "C" {
 | 
			
		||||
 | 
			
		||||
@@ -194,11 +194,11 @@ static void ICACHE_RAM_ATTR i2s_slc_isr(void) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void i2s_set_callback(void (*callback) (void)) {
 | 
			
		||||
  tx->callback = callback;
 | 
			
		||||
  if (tx) tx->callback = callback;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void i2s_rx_set_callback(void (*callback) (void)) {
 | 
			
		||||
  rx->callback = callback;
 | 
			
		||||
  if (rx) rx->callback = callback;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _alloc_channel(i2s_state_t *ch) {
 | 
			
		||||
@@ -343,7 +343,7 @@ bool i2s_write_lr(int16_t left, int16_t right){
 | 
			
		||||
 | 
			
		||||
// writes a buffer of frames into the DMA memory, returns the amount of frames written
 | 
			
		||||
// A frame is just a int16_t for mono, for stereo a frame is two int16_t, one for each channel.
 | 
			
		||||
static uint16_t _i2s_write_buffer(int16_t *frames, uint16_t frame_count, bool mono, bool nb) {
 | 
			
		||||
static uint16_t _i2s_write_buffer(const int16_t *frames, uint16_t frame_count, bool mono, bool nb) {
 | 
			
		||||
    uint16_t frames_written=0;
 | 
			
		||||
 | 
			
		||||
    while(frame_count>0) {
 | 
			
		||||
@@ -401,13 +401,13 @@ static uint16_t _i2s_write_buffer(int16_t *frames, uint16_t frame_count, bool mo
 | 
			
		||||
    return frames_written;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint16_t i2s_write_buffer_mono_nb(int16_t *frames, uint16_t frame_count) { return _i2s_write_buffer(frames, frame_count, true, true); }
 | 
			
		||||
uint16_t i2s_write_buffer_mono_nb(const int16_t *frames, uint16_t frame_count) { return _i2s_write_buffer(frames, frame_count, true, true); }
 | 
			
		||||
 | 
			
		||||
uint16_t i2s_write_buffer_mono(int16_t *frames, uint16_t frame_count) { return _i2s_write_buffer(frames, frame_count, true, false); }
 | 
			
		||||
uint16_t i2s_write_buffer_mono(const int16_t *frames, uint16_t frame_count) { return _i2s_write_buffer(frames, frame_count, true, false); }
 | 
			
		||||
 | 
			
		||||
uint16_t i2s_write_buffer_nb(int16_t *frames, uint16_t frame_count) { return _i2s_write_buffer(frames, frame_count, false, true); }
 | 
			
		||||
uint16_t i2s_write_buffer_nb(const int16_t *frames, uint16_t frame_count) { return _i2s_write_buffer(frames, frame_count, false, true); }
 | 
			
		||||
 | 
			
		||||
uint16_t i2s_write_buffer(int16_t *frames, uint16_t frame_count) { return _i2s_write_buffer(frames, frame_count, false, false); }
 | 
			
		||||
uint16_t i2s_write_buffer(const int16_t *frames, uint16_t frame_count) { return _i2s_write_buffer(frames, frame_count, false, false); }
 | 
			
		||||
 | 
			
		||||
bool i2s_read_sample(int16_t *left, int16_t *right, bool blocking) {
 | 
			
		||||
  if (!rx) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										81
									
								
								cores/esp8266/core_esp8266_i2s.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								cores/esp8266/core_esp8266_i2s.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,81 @@
 | 
			
		||||
/* 
 | 
			
		||||
  i2s.h - Software I2S library for esp8266
 | 
			
		||||
 | 
			
		||||
  Copyright (c) 2015 Hristo Gochkov. All rights reserved.
 | 
			
		||||
  This file is part of the esp8266 core for Arduino environment.
 | 
			
		||||
 
 | 
			
		||||
  This library is free software; you can redistribute it and/or
 | 
			
		||||
  modify it under the terms of the GNU Lesser General Public
 | 
			
		||||
  License as published by the Free Software Foundation; either
 | 
			
		||||
  version 2.1 of the License, or (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
  This library is distributed in the hope that it will be useful,
 | 
			
		||||
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
  Lesser General Public License for more details.
 | 
			
		||||
 | 
			
		||||
  You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
  License along with this library; if not, write to the Free Software
 | 
			
		||||
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 | 
			
		||||
*/
 | 
			
		||||
#ifndef I2S_h
 | 
			
		||||
#define I2S_h
 | 
			
		||||
 | 
			
		||||
#define I2S_HAS_BEGIN_RXTX_DRIVE_CLOCKS 1
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
How does this work? Basically, to get sound, you need to:
 | 
			
		||||
- Connect an I2S codec to the I2S pins on the ESP.
 | 
			
		||||
- Start up a thread that's going to do the sound output
 | 
			
		||||
- Call i2s_set_bits() if you want to enable 24-bit mode
 | 
			
		||||
- Call i2s_begin()
 | 
			
		||||
- Call i2s_set_rate() with the sample rate you want.
 | 
			
		||||
- Generate sound and call i2s_write_sample() with 32-bit samples.
 | 
			
		||||
The 32bit samples basically are 2 16-bit signed values (the analog values for
 | 
			
		||||
the left and right channel) concatenated as (Rout<<16)+Lout
 | 
			
		||||
 | 
			
		||||
i2s_write_sample will block when you're sending data too quickly, so you can just
 | 
			
		||||
generate and push data as fast as you can and i2s_write_sample will regulate the
 | 
			
		||||
speed.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
bool i2s_set_bits(int bits); // Set bits per sample, only 16 or 24 supported.  Call before begin.
 | 
			
		||||
// Note that in 24 bit mode each sample must be left-aligned (i.e. 0x00000000 .. 0xffffff00) as the
 | 
			
		||||
// hardware shifts starting at bit 31, not bit 23.
 | 
			
		||||
 | 
			
		||||
void i2s_begin(); // Enable TX only, for compatibility
 | 
			
		||||
bool i2s_rxtx_begin(bool enableRx, bool enableTx); // Allow TX and/or RX, returns false on OOM error
 | 
			
		||||
bool i2s_rxtxdrive_begin(bool enableRx, bool enableTx, bool driveRxClocks, bool driveTxClocks);
 | 
			
		||||
void i2s_end();
 | 
			
		||||
void i2s_set_rate(uint32_t rate);//Sample Rate in Hz (ex 44100, 48000)
 | 
			
		||||
void i2s_set_dividers(uint8_t div1, uint8_t div2);//Direct control over output rate
 | 
			
		||||
float i2s_get_real_rate();//The actual Sample Rate on output
 | 
			
		||||
bool i2s_write_sample(uint32_t sample);//32bit sample with channels being upper and lower 16 bits (blocking when DMA is full)
 | 
			
		||||
bool i2s_write_sample_nb(uint32_t sample);//same as above but does not block when DMA is full and returns false instead
 | 
			
		||||
bool i2s_write_lr(int16_t left, int16_t right);//combines both channels and calls i2s_write_sample with the result
 | 
			
		||||
bool i2s_read_sample(int16_t *left, int16_t *right, bool blocking); // RX data returned in both 16-bit outputs.
 | 
			
		||||
bool i2s_is_full();//returns true if DMA is full and can not take more bytes (overflow)
 | 
			
		||||
bool i2s_is_empty();//returns true if DMA is empty (underflow)
 | 
			
		||||
bool i2s_rx_is_full();
 | 
			
		||||
bool i2s_rx_is_empty();
 | 
			
		||||
uint16_t i2s_available();// returns the number of samples than can be written before blocking
 | 
			
		||||
uint16_t i2s_rx_available();// returns the number of samples than can be written before blocking
 | 
			
		||||
void i2s_set_callback(void (*callback) (void));
 | 
			
		||||
void i2s_rx_set_callback(void (*callback) (void));
 | 
			
		||||
 | 
			
		||||
// writes a buffer of frames into the DMA memory, returns the amount of frames written
 | 
			
		||||
// A frame is just a int16_t for mono, for stereo a frame is two int16_t, one for each channel.
 | 
			
		||||
uint16_t i2s_write_buffer_mono(const int16_t *frames, uint16_t frame_count);
 | 
			
		||||
uint16_t i2s_write_buffer_mono_nb(const int16_t *frames, uint16_t frame_count);
 | 
			
		||||
uint16_t i2s_write_buffer(const int16_t *frames, uint16_t frame_count);
 | 
			
		||||
uint16_t i2s_write_buffer_nb(const int16_t *frames, uint16_t frame_count);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -1,81 +1,12 @@
 | 
			
		||||
/* 
 | 
			
		||||
  i2s.h - Software I2S library for esp8266
 | 
			
		||||
// This include file is a hack to ensure backward compatibility with
 | 
			
		||||
// pre 3.0.0 versions of the core.  There was a *lowercase* "i2s.h"
 | 
			
		||||
// header which was in this directory, now renamed to "core_esp82i66s.h"
 | 
			
		||||
// But, the I2S class has a header, "I2S.h" in uppercase.  On Linux
 | 
			
		||||
// the two names are different, but on Windows it's case-insensitive
 | 
			
		||||
// so the names conflict.
 | 
			
		||||
//
 | 
			
		||||
// Avoid the issue by preserving the old i2s.h file and have it redirect
 | 
			
		||||
// to I2S.h which will give the ESP8266-specific functions as well as
 | 
			
		||||
// the generic I2S class.
 | 
			
		||||
 | 
			
		||||
  Copyright (c) 2015 Hristo Gochkov. All rights reserved.
 | 
			
		||||
  This file is part of the esp8266 core for Arduino environment.
 | 
			
		||||
 
 | 
			
		||||
  This library is free software; you can redistribute it and/or
 | 
			
		||||
  modify it under the terms of the GNU Lesser General Public
 | 
			
		||||
  License as published by the Free Software Foundation; either
 | 
			
		||||
  version 2.1 of the License, or (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
  This library is distributed in the hope that it will be useful,
 | 
			
		||||
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
  Lesser General Public License for more details.
 | 
			
		||||
 | 
			
		||||
  You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
  License along with this library; if not, write to the Free Software
 | 
			
		||||
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 | 
			
		||||
*/
 | 
			
		||||
#ifndef I2S_h
 | 
			
		||||
#define I2S_h
 | 
			
		||||
 | 
			
		||||
#define I2S_HAS_BEGIN_RXTX_DRIVE_CLOCKS 1
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
How does this work? Basically, to get sound, you need to:
 | 
			
		||||
- Connect an I2S codec to the I2S pins on the ESP.
 | 
			
		||||
- Start up a thread that's going to do the sound output
 | 
			
		||||
- Call i2s_set_bits() if you want to enable 24-bit mode
 | 
			
		||||
- Call i2s_begin()
 | 
			
		||||
- Call i2s_set_rate() with the sample rate you want.
 | 
			
		||||
- Generate sound and call i2s_write_sample() with 32-bit samples.
 | 
			
		||||
The 32bit samples basically are 2 16-bit signed values (the analog values for
 | 
			
		||||
the left and right channel) concatenated as (Rout<<16)+Lout
 | 
			
		||||
 | 
			
		||||
i2s_write_sample will block when you're sending data too quickly, so you can just
 | 
			
		||||
generate and push data as fast as you can and i2s_write_sample will regulate the
 | 
			
		||||
speed.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
bool i2s_set_bits(int bits); // Set bits per sample, only 16 or 24 supported.  Call before begin.
 | 
			
		||||
// Note that in 24 bit mode each sample must be left-aligned (i.e. 0x00000000 .. 0xffffff00) as the
 | 
			
		||||
// hardware shifts starting at bit 31, not bit 23.
 | 
			
		||||
 | 
			
		||||
void i2s_begin(); // Enable TX only, for compatibility
 | 
			
		||||
bool i2s_rxtx_begin(bool enableRx, bool enableTx); // Allow TX and/or RX, returns false on OOM error
 | 
			
		||||
bool i2s_rxtxdrive_begin(bool enableRx, bool enableTx, bool driveRxClocks, bool driveTxClocks);
 | 
			
		||||
void i2s_end();
 | 
			
		||||
void i2s_set_rate(uint32_t rate);//Sample Rate in Hz (ex 44100, 48000)
 | 
			
		||||
void i2s_set_dividers(uint8_t div1, uint8_t div2);//Direct control over output rate
 | 
			
		||||
float i2s_get_real_rate();//The actual Sample Rate on output
 | 
			
		||||
bool i2s_write_sample(uint32_t sample);//32bit sample with channels being upper and lower 16 bits (blocking when DMA is full)
 | 
			
		||||
bool i2s_write_sample_nb(uint32_t sample);//same as above but does not block when DMA is full and returns false instead
 | 
			
		||||
bool i2s_write_lr(int16_t left, int16_t right);//combines both channels and calls i2s_write_sample with the result
 | 
			
		||||
bool i2s_read_sample(int16_t *left, int16_t *right, bool blocking); // RX data returned in both 16-bit outputs.
 | 
			
		||||
bool i2s_is_full();//returns true if DMA is full and can not take more bytes (overflow)
 | 
			
		||||
bool i2s_is_empty();//returns true if DMA is empty (underflow)
 | 
			
		||||
bool i2s_rx_is_full();
 | 
			
		||||
bool i2s_rx_is_empty();
 | 
			
		||||
uint16_t i2s_available();// returns the number of samples than can be written before blocking
 | 
			
		||||
uint16_t i2s_rx_available();// returns the number of samples than can be written before blocking
 | 
			
		||||
void i2s_set_callback(void (*callback) (void));
 | 
			
		||||
void i2s_rx_set_callback(void (*callback) (void));
 | 
			
		||||
 | 
			
		||||
// writes a buffer of frames into the DMA memory, returns the amount of frames written
 | 
			
		||||
// A frame is just a int16_t for mono, for stereo a frame is two int16_t, one for each channel.
 | 
			
		||||
uint16_t i2s_write_buffer_mono(int16_t *frames, uint16_t frame_count);
 | 
			
		||||
uint16_t i2s_write_buffer_mono_nb(int16_t *frames, uint16_t frame_count);
 | 
			
		||||
uint16_t i2s_write_buffer(int16_t *frames, uint16_t frame_count);
 | 
			
		||||
uint16_t i2s_write_buffer_nb(int16_t *frames, uint16_t frame_count); 
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
#include "../../libraries/I2S/src/I2S.h"
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user