- merge with original master from jorgen
- minimize RAM usage of all components - use both IRAM and DRAM in player component so we can buffer up to 1s on modules without SPI RAM - support fragemented pcm chunks so we can use all available RAM if there isn't a big enough block available but still enough HEAP - reinclude all components from jorgen's master branch - add custom i2s driver to get a precise timing of initial sync - change wrong usage of esp_timer for latency measurement of snapcast protocol - add player component
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,3 +1,3 @@
|
||||
build
|
||||
libopus
|
||||
components/lopus
|
||||
components/opus
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,3 +1,6 @@
|
||||
[submodule "components/opus/opus"]
|
||||
path = components/opus/opus
|
||||
url = https://github.com/xiph/opus
|
||||
[submodule "components/esp-dsp"]
|
||||
path = components/esp-dsp
|
||||
url = https://github.com/espressif/esp-dsp
|
||||
|
||||
168
README.md
168
README.md
@@ -1,100 +1,162 @@
|
||||
# Snapcast client for ESP32
|
||||
# Snapcast client for ESP32
|
||||
|
||||
### Synchronous Multiroom audio streaming client for [Snapcast](https://github.com/badaix/snapcast) ported to ESP32
|
||||
|
||||
## Feature list
|
||||
- Opus decoding currently supported
|
||||
- Wifi connection hardcoded in app
|
||||
- Auto connect to snapcast server on network
|
||||
- Buffers up to 150 ms on Wroom modules
|
||||
- Buffers more then enough on Wrover modules
|
||||
- Multiroom sync delay controlled from Snapcast server
|
||||
## Feature list
|
||||
- Opus and PCM decoding currently supported
|
||||
- Wifi setup from menuconfig
|
||||
- Auto connect to snapcast server on network
|
||||
- Buffers up to 150 ms on Wroom modules
|
||||
- Buffers more then enough on Wrover modules
|
||||
- Multiroom sync delay controlled from Snapcast server 400ms - 2000ms
|
||||
|
||||
## Description
|
||||
I have continued the work from @badaix and @bridadan towards a ESP32 Snapcast client. Currently it support basic features like multirum sync, network controlled volume and mute. For now it only support Opus 16bit/48Khz audio streams and the synchornization part is still being worked on.
|
||||
## Description
|
||||
I have continued the work from @badaix and @bridadan towards a ESP32 Snapcast
|
||||
client. Currently it support basic features like multirum sync, network
|
||||
controlled volume and mute. For now it only support Opus and PCM 16bit/48Khz
|
||||
audio streams and the synchornization part is still being worked on.
|
||||
|
||||
Please check out the task list and feel free to fill in.
|
||||
|
||||
I have used the Infineon MA12070P Multi level Class D combined coded/amp due to its superior power effecienty on a high supply rail. It allows battery power system with good playback time at normal listen level and stil have the power to start the party.
|
||||
I have used the Infineon MA12070P Multi level Class D combined coded/amp due to
|
||||
its superior power effecienty on a high supply rail. It allows battery power
|
||||
system with good playback time at normal listen level and still have the power
|
||||
to start the party.
|
||||
|
||||
### Codebase
|
||||
|
||||
The codebase is split into components and build on vanilla ESP-IDF. I stil have some refactoring on the todo list as the concept has started to settle and allow for new features can be added in a stuctured manner. In the code you will find parts that are only partly related features and still not on the task list.
|
||||
Components
|
||||
- MerusAudio : Low level communication interface MA12070P
|
||||
- opus : Opus audio coder/decoder full submodule
|
||||
- rtprx : Alternative RTP audio client UDP low latency also opus based
|
||||
- lightsnapcast : Port of @bridadan scapcast packages decode library
|
||||
- libbuffer : Generic buffer abstraction
|
||||
- esp-dsp : Port of ESP-DSP library - stripped version - submodule considered
|
||||
- dsp_processor : Audio Processor and I2S low level interface including sync buffer
|
||||
The codebase is split into components and build on vanilla ESP-IDF. I still
|
||||
have some refactoring on the todo list as the concept has started to settle and
|
||||
allow for new features can be added in a structured manner. In the code you
|
||||
will find parts that are only partly related features and still not on the task
|
||||
list.
|
||||
|
||||
### Hardware
|
||||
- ESP pinout MA12070P
|
||||
Components
|
||||
- MerusAudio : Low level communication interface MA12070P
|
||||
- opus : Opus audio coder/decoder full submodule
|
||||
- rtprx : Alternative RTP audio client UDP low latency also opus based
|
||||
- lightsnapcast : Port of @bridadan scapcast packages decode library
|
||||
- libbuffer : Generic buffer abstraction
|
||||
- esp-dsp : Submodule to the ESP-ADF done by David Douard
|
||||
- dsp_processor : Audio Processor and I2S low level interface including sync
|
||||
buffer
|
||||
|
||||
The snapclient functionanlity are implemented in a task included in main - but
|
||||
will be refactored to a component in near future.
|
||||
|
||||
Sync concept has been changed start 2021 on this implementation and differ a
|
||||
bit from the way original snap clints handle this.
|
||||
|
||||
The snapclient frontend handles communiction with the server and after
|
||||
successfully hello hand shake it dispatches packages from the server.
|
||||
|
||||
- CODEC_HEADER : Setup client audio codec (FLAC, OPUS, OGG or PCM) bitrate, n
|
||||
channels and bits pr sample
|
||||
- WIRE_CHUNK : Coded audio data
|
||||
- SERVER_SETTING : Channel volume, mute state, playback delay etc
|
||||
- TIME : Ping pong time keeping packages to keep track of time dif from server
|
||||
to client
|
||||
|
||||
Each wire_chunk of audio data comes with a timestamp and client has agreed play
|
||||
that sample playback-delay after the timestamp. One way to handle that is to
|
||||
pass on audio data to a buffer with a length that compensate for for
|
||||
playback-delay, network jitter and DAC to speaker.
|
||||
|
||||
In this implementation I have separated the sync task to a backend on the other
|
||||
end of a large ring buffer. Now the front end just need to pass on the audio
|
||||
data to the ring buffer with the server timestamp and chunk size. The backen
|
||||
read timestamps and waits until the audio chunk has the correct playback-delay
|
||||
to be written to the DAC amplifer speaker pipeline. When the backend pipeline
|
||||
is in sync, any offset get rolled in by micro tuning the APLL on the ESP. No
|
||||
sample manipulation needed.
|
||||
|
||||
|
||||
### Hardware
|
||||
- ESP pinout MA12070P
|
||||
------------------------------------------------------
|
||||
-> I2S_BCK Audio Clock 3.072 MHz
|
||||
-> I2S_WS Frame Word Select or L/R
|
||||
-> GND Ground
|
||||
-> I2S_DI Audio data 24bits LSB first
|
||||
-> I2S_BCK Audio Clock 3.072 MHz
|
||||
-> I2S_WS Frame Word Select or L/R
|
||||
-> GND Ground
|
||||
-> I2S_DI Audio data 24bits LSB first
|
||||
-> MCLK Master clk connect to I2S_BCK
|
||||
-> I2C_SCL I2C clock
|
||||
-> I2C_SDA I2C Data
|
||||
-> GND Ground
|
||||
-> NENABLE Amplifier Enable active low
|
||||
-> NENABLE Amplifier Enable active low
|
||||
-> NMUTE Amplifier Mute active low
|
||||
|
||||
|
||||
## Build
|
||||
|
||||
Clone this repo:
|
||||
|
||||
git clone https://github.com/jorgenkraghjakobsen/snapclint
|
||||
## Build
|
||||
|
||||
Update third party code:
|
||||
Clone this repo:
|
||||
|
||||
git clone https://github.com/jorgenkraghjakobsen/snapclint
|
||||
|
||||
Update third party code (opus and esp-dsp):
|
||||
|
||||
git submodule update --init
|
||||
|
||||
Configure to match your setup:
|
||||
Configure to match your setup
|
||||
- Wifi network name and password
|
||||
- Audio coded setup
|
||||
|
||||
idf.py menuconfig
|
||||
|
||||
Build, compile and flash:
|
||||
|
||||
idf.py build flash monitor
|
||||
idf.py build flash monitor
|
||||
|
||||
## Test
|
||||
Setup a snapcast server on your network
|
||||
## Test
|
||||
Setup a snapcast server on your network
|
||||
|
||||
On a linux box:
|
||||
On a linux box:
|
||||
|
||||
Clone snapcast build and start the server
|
||||
|
||||
./snapserver
|
||||
./snapserver
|
||||
|
||||
Pipe some audio to the snapcast server fifo
|
||||
Pipe some audio to the snapcast server fifo
|
||||
|
||||
mplayer http://ice1.somafm.com/secretagent-128-aac -ao pcm:file=/tmp/snapfifo -af format=s16LE -srate 48000
|
||||
|
||||
Test the server config on other knowen platform
|
||||
Test the server config on other knowen platform
|
||||
|
||||
./snapclient from the snapcast repo
|
||||
|
||||
Android : snapclient from the app play store
|
||||
Android : snapclient from the app play store
|
||||
|
||||
## Contribute
|
||||
|
||||
You are very welcome to help and provide [Pull
|
||||
Requests](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests)
|
||||
to the project.
|
||||
|
||||
We strongly suggest you activate [pre-commit](https://pre-commit.com) hooks in
|
||||
this git repository before starting to hack and make commits.
|
||||
|
||||
Assuming you have `pre-commit` installed on your machine (using `pip install
|
||||
pre-commit` or, on a debian-like system, `sudo apt install pre-commit`), type:
|
||||
|
||||
```
|
||||
:~/snapclient$ pre-commit install
|
||||
pre-commit installed at .git/hooks/pre-commit
|
||||
```
|
||||
|
||||
Then on every `git commit`, a few sanity/formatting checks will be performed.
|
||||
|
||||
|
||||
## Task list
|
||||
- [ok] Fix to alinge with above
|
||||
- [ok] Fix to alinge with above
|
||||
* kconfig
|
||||
* add codec description
|
||||
- [ ] Integrate ESP wifi provision
|
||||
* add codec description
|
||||
- [ ] Integrate ESP wifi provision
|
||||
- [ok] Find and connect to Avahi broadcasted Snapcast server name
|
||||
- [ ] Add a client command interface layer like volume/mute control
|
||||
- [ ] Build a ESP-ADF branch
|
||||
- [ ] Add a client command interface layer like volume/mute control
|
||||
- [ ] Build a ESP-ADF branch
|
||||
|
||||
## Minor task
|
||||
- [ ] Propergate mute/unute from server message to DSP backend mute control.
|
||||
- [ ] soft mute - play sample in buffer with decresing volume
|
||||
- [ok] hard mute - pass on zero at the DSP hackend
|
||||
- [ ] Startup: do not start parsing on samples to codec before sample ring buffer hits requested buffer size.
|
||||
## Minor task
|
||||
- [ ] Propergate mute/unute from server message to DSP backend mute control.
|
||||
- [ ] soft mute - play sample in buffer with decreasing volume
|
||||
- [ok] hard mute - pass on zero at the DSP hackend
|
||||
- [ ] Startup: do not start parsing on samples to codec before sample ring buffer hits requested buffer size.
|
||||
- [ok] Start from empty buffer
|
||||
|
||||
42
components/custom_board/CMakeLists.txt
Normal file
42
components/custom_board/CMakeLists.txt
Normal file
@@ -0,0 +1,42 @@
|
||||
# Edit following two lines to set component requirements (see docs)
|
||||
set(COMPONENT_REQUIRES)
|
||||
set(COMPONENT_PRIV_REQUIRES audio_hal esp_dispatcher esp_peripherals display_service)
|
||||
|
||||
if(CONFIG_AUDIO_BOARD_CUSTOM)
|
||||
message(STATUS "Current board name is " CONFIG_AUDIO_BOARD_CUSTOM)
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ./generic_board/include)
|
||||
set(COMPONENT_SRCS
|
||||
./generic_board/board.c
|
||||
./generic_board/board_pins_config.c
|
||||
)
|
||||
|
||||
if(CONFIG_DAC_PCM51XX)
|
||||
message(STATUS "Selected DAC is " CONFIG_DAC_PCM15XX)
|
||||
list(APPEND COMPONENT_ADD_INCLUDEDIRS ./pcm51xx/include)
|
||||
list(APPEND COMPONENT_SRCS ./pcm51xx/pcm51xx.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_DAC_MA120X0)
|
||||
message(STATUS "Selected DAC is " CONFIG_DAC_MA120X0)
|
||||
list(APPEND COMPONENT_ADD_INCLUDEDIRS ./ma120x0/include)
|
||||
list(APPEND COMPONENT_SRCS ./ma120x0/MerusAudio.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_DAC_MA120)
|
||||
message(STATUS "Selected DAC is " CONFIG_DAC_MA120)
|
||||
list(APPEND COMPONENT_ADD_INCLUDEDIRS ./ma120/include)
|
||||
list(APPEND COMPONENT_SRCS ./ma120/ma120.c)
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
register_component()
|
||||
|
||||
IF (IDF_VER MATCHES "v4.")
|
||||
idf_component_get_property(audio_board_lib audio_board COMPONENT_LIB)
|
||||
set_property(TARGET ${audio_board_lib} APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${COMPONENT_LIB})
|
||||
|
||||
ELSEIF (IDF_VER MATCHES "v3.")
|
||||
set_property(TARGET idf_component_audio_board APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:${COMPONENT_TARGET},INTERFACE_INCLUDE_DIRECTORIES>)
|
||||
|
||||
ENDIF (IDF_VER MATCHES "v4.")
|
||||
137
components/custom_board/Kconfig.projbuild
Normal file
137
components/custom_board/Kconfig.projbuild
Normal file
@@ -0,0 +1,137 @@
|
||||
menu "Custom Audio Board"
|
||||
depends on AUDIO_BOARD_CUSTOM
|
||||
|
||||
choice GENERIC_BOARD_DAC
|
||||
prompt "DAC chip"
|
||||
default DAC_MA120
|
||||
help
|
||||
Select a DAC connected to the generic ESP32 board
|
||||
|
||||
config DAC_PCM51XX
|
||||
bool "TI PCM51XX/TAS57XX based DAC"
|
||||
|
||||
config DAC_MA120
|
||||
bool "Infineon MA120 ClassD AMP"
|
||||
|
||||
config DAC_MA120X0
|
||||
bool "Infineon MA120X0 ClassD AMP"
|
||||
|
||||
|
||||
endchoice
|
||||
|
||||
menu "DAC I2C control interface"
|
||||
config DAC_I2C_SDA
|
||||
int "SDA pin"
|
||||
default 21
|
||||
help
|
||||
I2C SDA pin of the DAC control interface
|
||||
config DAC_I2C_SCL
|
||||
int "SCL pin"
|
||||
default 22
|
||||
help
|
||||
I2C SCL pin of the DAC control interface
|
||||
config DAC_I2C_ADDR
|
||||
hex "I2C address"
|
||||
default 0x20
|
||||
help
|
||||
I2C Address of the DAC control interface
|
||||
endmenu
|
||||
|
||||
menu "I2S master interface"
|
||||
config MASTER_I2S_BCK_PIN
|
||||
int "Master i2s bck"
|
||||
default 23
|
||||
help
|
||||
Master audio interface bit clock.
|
||||
|
||||
config MASTER_I2S_LRCK_PIN
|
||||
int "Master i2s lrck"
|
||||
default 13
|
||||
help
|
||||
Master audio interface left/right sync clock.
|
||||
|
||||
config MASTER_I2S_DATAOUT_PIN
|
||||
int "Master i2s data out"
|
||||
default 14
|
||||
help
|
||||
Master audio interface data out.
|
||||
endmenu
|
||||
|
||||
menu "I2S slave interface"
|
||||
|
||||
config SLAVE_I2S_BCK_PIN
|
||||
int "Slave i2s bck"
|
||||
default 26
|
||||
help
|
||||
Slave audio interface bit clock.
|
||||
|
||||
config SLAVE_I2S_LRCK_PIN
|
||||
int "Slave i2s lrck"
|
||||
default 12
|
||||
help
|
||||
Slave audio interface left/right sync clock.
|
||||
|
||||
config SLAVE_I2S_DATAOUT_PIN
|
||||
int "Slave i2s data out"
|
||||
default 5
|
||||
help
|
||||
Slave audio interface data out.
|
||||
endmenu
|
||||
|
||||
menu "Merus MA120x0 interface Configuration"
|
||||
depends on DAC_MA120X0
|
||||
|
||||
config MA120X0_NENABLE_PIN
|
||||
int "Master enable/disable for ma120x0"
|
||||
default 16
|
||||
help
|
||||
GPIO number to control enable/disable.
|
||||
|
||||
config MA120X0_NMUTE_PIN
|
||||
int "Master mute/unmute for ma120x0"
|
||||
default 2
|
||||
help
|
||||
GPIO number to controm mute/unmute.
|
||||
|
||||
config MERUS_NERR_PIN
|
||||
int "NERR monitor pin"
|
||||
default 21
|
||||
help
|
||||
GPIO number to monitor NERROR.
|
||||
|
||||
config MERUS_NCLIP_PIN
|
||||
int "Clip indication pin"
|
||||
default 22
|
||||
help
|
||||
GPIO number low if clip observed
|
||||
endmenu
|
||||
|
||||
menu "Merus MA120 interface Configuration"
|
||||
depends on DAC_MA120
|
||||
|
||||
config MA120_ENABLE_PIN
|
||||
int "Master enable/disable for ma120x0"
|
||||
default 16
|
||||
help
|
||||
GPIO number to control enable/disable.
|
||||
|
||||
config MA120_NMUTE_PIN
|
||||
int "Master mute/unmute for ma120x0"
|
||||
default 2
|
||||
help
|
||||
GPIO number to controm mute/unmute.
|
||||
|
||||
config MERUS_NERR_PIN
|
||||
int "NERR monitor pin"
|
||||
default 21
|
||||
help
|
||||
GPIO number to monitor NERROR.
|
||||
|
||||
config MERUS_NCLIP_PIN
|
||||
int "Clip indication pin"
|
||||
default 22
|
||||
help
|
||||
GPIO number low if clip observed
|
||||
endmenu
|
||||
|
||||
endmenu
|
||||
20
components/custom_board/component.mk
Normal file
20
components/custom_board/component.mk
Normal file
@@ -0,0 +1,20 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
||||
|
||||
ifdef CONFIG_AUDIO_BOARD_CUSTOM
|
||||
COMPONENT_ADD_INCLUDEDIRS += ./generic_board/include
|
||||
COMPONENT_SRCDIRS += ./generic_board
|
||||
|
||||
ifdef CONFIG_DAC_PCM51XX
|
||||
COMPONENT_ADD_INCLUDEDIRS += ./pcm51xx/include
|
||||
COMPONENT_SRCDIRS += ./pcm51xx
|
||||
endif
|
||||
|
||||
ifdef CONFIG_DAC_MA120X0
|
||||
COMPONENT_ADD_INCLUDEDIRS += ./ma120x0/include
|
||||
COMPONENT_SRCDIRS += ./ma120x0
|
||||
endif
|
||||
|
||||
endif
|
||||
112
components/custom_board/generic_board/board.c
Normal file
112
components/custom_board/generic_board/board.c
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
|
||||
* which case, it is free of charge, to any person obtaining a copy of this
|
||||
* software and associated documentation files (the "Software"), to deal in the
|
||||
* Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do
|
||||
* so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "board.h"
|
||||
|
||||
#include "audio_mem.h"
|
||||
#include "esp_log.h"
|
||||
#include "periph_adc_button.h"
|
||||
#include "periph_sdcard.h"
|
||||
|
||||
#if CONFIG_DAC_PCM51XX
|
||||
extern audio_hal_func_t AUDIO_CODEC_PCM51XX_DEFAULT_HANDLE;
|
||||
#define AUDIO_CODEC_DEFAULT_HANDLE AUDIO_CODEC_PCM51XX_DEFAULT_HANDLE
|
||||
#elif CONFIG_DAC_MA120X0
|
||||
extern audio_hal_func_t AUDIO_CODEC_MA120X0_DEFAULT_HANDLE;
|
||||
#define AUDIO_CODEC_DEFAULT_HANDLE AUDIO_CODEC_MA120X0_DEFAULT_HANDLE
|
||||
#elif CONFIG_DAC_MA120
|
||||
extern audio_hal_func_t AUDIO_CODEC_MA120_DEFAULT_HANDLE;
|
||||
#define AUDIO_CODEC_DEFAULT_HANDLE AUDIO_CODEC_MA120_DEFAULT_HANDLE
|
||||
#endif
|
||||
|
||||
static const char *TAG = "AUDIO_BOARD";
|
||||
|
||||
static audio_board_handle_t board_handle = 0;
|
||||
|
||||
audio_board_handle_t audio_board_init(void) {
|
||||
if (board_handle) {
|
||||
ESP_LOGW(TAG, "The board has already been initialized!");
|
||||
return board_handle;
|
||||
}
|
||||
board_handle =
|
||||
(audio_board_handle_t)audio_calloc(1, sizeof(struct audio_board_handle));
|
||||
AUDIO_MEM_CHECK(TAG, board_handle, return NULL);
|
||||
board_handle->audio_hal = audio_board_codec_init();
|
||||
ESP_LOGI(TAG,"board-handle done") ;
|
||||
return board_handle;
|
||||
}
|
||||
|
||||
audio_hal_handle_t audio_board_codec_init(void) {
|
||||
ESP_LOGI("HAL", "INIT" );
|
||||
audio_hal_codec_config_t audio_codec_cfg = AUDIO_CODEC_DEFAULT_CONFIG();
|
||||
|
||||
audio_hal_handle_t codec_hal =
|
||||
audio_hal_init(&audio_codec_cfg, &AUDIO_CODEC_DEFAULT_HANDLE);
|
||||
ESP_LOGI("HAL", "codec_hal done" );
|
||||
|
||||
AUDIO_NULL_CHECK(TAG, codec_hal, return NULL);
|
||||
return codec_hal;
|
||||
}
|
||||
|
||||
esp_err_t audio_board_key_init(esp_periph_set_handle_t set) {
|
||||
esp_err_t ret = ESP_OK;
|
||||
periph_adc_button_cfg_t adc_btn_cfg = PERIPH_ADC_BUTTON_DEFAULT_CONFIG();
|
||||
adc_arr_t adc_btn_tag = ADC_DEFAULT_ARR();
|
||||
adc_btn_tag.adc_ch = ADC1_CHANNEL_0; // GPIO36
|
||||
adc_btn_tag.total_steps = 4;
|
||||
int btn_array[5] = {200, 1355, 1820, 2280, 2930};
|
||||
adc_btn_tag.adc_level_step = btn_array;
|
||||
adc_btn_cfg.arr = &adc_btn_tag;
|
||||
adc_btn_cfg.arr_size = 1;
|
||||
esp_periph_handle_t adc_btn_handle = periph_adc_button_init(&adc_btn_cfg);
|
||||
AUDIO_NULL_CHECK(TAG, adc_btn_handle, return ESP_ERR_ADF_MEMORY_LACK);
|
||||
ret = esp_periph_start(set, adc_btn_handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t audio_board_sdcard_init(esp_periph_set_handle_t set,
|
||||
periph_sdcard_mode_t mode) {
|
||||
periph_sdcard_cfg_t sdcard_cfg = {
|
||||
.root = "/sdcard",
|
||||
.card_detect_pin = get_sdcard_intr_gpio(), // GPIO_NUM_34
|
||||
};
|
||||
esp_periph_handle_t sdcard_handle = periph_sdcard_init(&sdcard_cfg);
|
||||
esp_err_t ret = esp_periph_start(set, sdcard_handle);
|
||||
while (!periph_sdcard_is_mounted(sdcard_handle)) {
|
||||
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
audio_board_handle_t audio_board_get_handle(void) { return board_handle; }
|
||||
|
||||
esp_err_t audio_board_deinit(audio_board_handle_t audio_board) {
|
||||
esp_err_t ret = ESP_OK;
|
||||
ret |= audio_hal_deinit(audio_board->audio_hal);
|
||||
free(audio_board);
|
||||
board_handle = NULL;
|
||||
return ret;
|
||||
}
|
||||
126
components/custom_board/generic_board/board_pins_config.c
Normal file
126
components/custom_board/generic_board/board_pins_config.c
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
|
||||
* which case, it is free of charge, to any person obtaining a copy of this
|
||||
* software and associated documentation files (the "Software"), to deal in the
|
||||
* Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do
|
||||
* so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "audio_error.h"
|
||||
#include "audio_mem.h"
|
||||
#include "board.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
static const char *TAG = "GENERIC_BOARD";
|
||||
|
||||
esp_err_t get_i2c_pins(i2c_port_t port, i2c_config_t *i2c_config) {
|
||||
AUDIO_NULL_CHECK(TAG, i2c_config, return ESP_FAIL);
|
||||
if (port == I2C_NUM_0 || port == I2C_NUM_1) {
|
||||
i2c_config->sda_io_num = CONFIG_DAC_I2C_SDA;
|
||||
i2c_config->scl_io_num = CONFIG_DAC_I2C_SCL;
|
||||
} else {
|
||||
i2c_config->sda_io_num = -1;
|
||||
i2c_config->scl_io_num = -1;
|
||||
ESP_LOGE(TAG, "i2c port %d is not supported", port);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t get_i2s_pins(i2s_port_t port, i2s_pin_config_t *i2s_config) {
|
||||
AUDIO_NULL_CHECK(TAG, i2s_config, return ESP_FAIL);
|
||||
if (port == I2S_NUM_0) {
|
||||
i2s_config->bck_io_num = CONFIG_MASTER_I2S_BCK_PIN;
|
||||
i2s_config->ws_io_num = CONFIG_MASTER_I2S_LRCK_PIN;
|
||||
i2s_config->data_out_num = CONFIG_MASTER_I2S_DATAOUT_PIN;
|
||||
i2s_config->data_in_num = -1;
|
||||
} else if (port == I2S_NUM_1) {
|
||||
i2s_config->bck_io_num = CONFIG_SLAVE_I2S_BCK_PIN;
|
||||
i2s_config->ws_io_num = CONFIG_SLAVE_I2S_LRCK_PIN;
|
||||
i2s_config->data_out_num = CONFIG_SLAVE_I2S_DATAOUT_PIN;
|
||||
i2s_config->data_in_num = -1;
|
||||
} else {
|
||||
memset(i2s_config, -1, sizeof(i2s_pin_config_t));
|
||||
ESP_LOGE(TAG, "i2s port %d is not supported", port);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t i2s_mclk_gpio_select(i2s_port_t i2s_num, gpio_num_t gpio_num) {
|
||||
if (i2s_num >= I2S_NUM_MAX) {
|
||||
ESP_LOGE(TAG, "Does not support i2s number(%d)", i2s_num);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (gpio_num != GPIO_NUM_0 && gpio_num != GPIO_NUM_1 &&
|
||||
gpio_num != GPIO_NUM_3) {
|
||||
ESP_LOGE(TAG, "Only support GPIO0/GPIO1/GPIO3, gpio_num:%d", gpio_num);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
ESP_LOGI(TAG, "I2S%d, MCLK output by GPIO%d", i2s_num, gpio_num);
|
||||
if (i2s_num == I2S_NUM_0) {
|
||||
if (gpio_num == GPIO_NUM_0) {
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1);
|
||||
WRITE_PERI_REG(PIN_CTRL, 0xFFF0);
|
||||
} else if (gpio_num == GPIO_NUM_1) {
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_CLK_OUT3);
|
||||
WRITE_PERI_REG(PIN_CTRL, 0xF0F0);
|
||||
} else {
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_CLK_OUT2);
|
||||
WRITE_PERI_REG(PIN_CTRL, 0xFF00);
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t get_spi_pins(
|
||||
spi_bus_config_t *spi_config,
|
||||
spi_device_interface_config_t *spi_device_interface_config) {
|
||||
AUDIO_NULL_CHECK(TAG, spi_config, return ESP_FAIL);
|
||||
AUDIO_NULL_CHECK(TAG, spi_device_interface_config, return ESP_FAIL);
|
||||
|
||||
spi_config->mosi_io_num = -1;
|
||||
spi_config->miso_io_num = -1;
|
||||
spi_config->sclk_io_num = -1;
|
||||
spi_config->quadwp_io_num = -1;
|
||||
spi_config->quadhd_io_num = -1;
|
||||
|
||||
spi_device_interface_config->spics_io_num = -1;
|
||||
|
||||
ESP_LOGW(TAG, "SPI interface is not supported");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// sdcard
|
||||
|
||||
int8_t get_sdcard_intr_gpio(void) { return SDCARD_INTR_GPIO; }
|
||||
|
||||
int8_t get_sdcard_open_file_num_max(void) { return SDCARD_OPEN_FILE_NUM_MAX; }
|
||||
|
||||
int8_t get_input_volup_id(void) { return BUTTON_VOLUP_ID; }
|
||||
|
||||
int8_t get_input_voldown_id(void) { return BUTTON_VOLDOWN_ID; }
|
||||
|
||||
int8_t get_pa_enable_gpio(void) { return PA_ENABLE_GPIO; }
|
||||
115
components/custom_board/generic_board/include/board.h
Normal file
115
components/custom_board/generic_board/include/board.h
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
|
||||
* which case, it is free of charge, to any person obtaining a copy of this
|
||||
* software and associated documentation files (the "Software"), to deal in the
|
||||
* Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do
|
||||
* so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _AUDIO_BOARD_H_
|
||||
#define _AUDIO_BOARD_H_
|
||||
|
||||
#include "audio_hal.h"
|
||||
#include "board_def.h"
|
||||
#include "board_pins_config.h"
|
||||
#include "esp_peripherals.h"
|
||||
#include "periph_sdcard.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Audio board handle
|
||||
*/
|
||||
struct audio_board_handle {
|
||||
audio_hal_handle_t audio_hal; /*!< pa hardware abstract layer handle */
|
||||
audio_hal_handle_t adc_hal; /*!< adc hardware abstract layer handle */
|
||||
};
|
||||
|
||||
typedef struct audio_board_handle *audio_board_handle_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize audio board
|
||||
*
|
||||
* @return The audio board handle
|
||||
*/
|
||||
audio_board_handle_t audio_board_init(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize codec
|
||||
*
|
||||
* @return The audio hal handle
|
||||
*/
|
||||
audio_hal_handle_t audio_board_codec_init(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize adc
|
||||
*
|
||||
* @return The adc hal handle
|
||||
*/
|
||||
audio_hal_handle_t audio_board_adc_init(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize key peripheral
|
||||
*
|
||||
* @param set The handle of esp_periph_set_handle_t
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK, success
|
||||
* - Others, fail
|
||||
*/
|
||||
esp_err_t audio_board_key_init(esp_periph_set_handle_t set);
|
||||
|
||||
/**
|
||||
* @brief Initialize sdcard peripheral
|
||||
*
|
||||
* @param set The handle of esp_periph_set_handle_t
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK, success
|
||||
* - Others, fail
|
||||
*/
|
||||
esp_err_t audio_board_sdcard_init(esp_periph_set_handle_t set,
|
||||
periph_sdcard_mode_t mode);
|
||||
|
||||
/**
|
||||
* @brief Query audio_board_handle
|
||||
*
|
||||
* @return The audio board handle
|
||||
*/
|
||||
audio_board_handle_t audio_board_get_handle(void);
|
||||
|
||||
/**
|
||||
* @brief Uninitialize the audio board
|
||||
*
|
||||
* @param audio_board The handle of audio board
|
||||
*
|
||||
* @return 0 success,
|
||||
* others fail
|
||||
*/
|
||||
esp_err_t audio_board_deinit(audio_board_handle_t audio_board);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
82
components/custom_board/generic_board/include/board_def.h
Normal file
82
components/custom_board/generic_board/include/board_def.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
|
||||
* which case, it is free of charge, to any person obtaining a copy of this
|
||||
* software and associated documentation files (the "Software"), to deal in the
|
||||
* Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do
|
||||
* so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _AUDIO_BOARD_DEFINITION_H_
|
||||
#define _AUDIO_BOARD_DEFINITION_H_
|
||||
|
||||
#define BUTTON_VOLUP_ID 0
|
||||
#define BUTTON_VOLDOWN_ID 1
|
||||
#define BUTTON_MUTE_ID 2
|
||||
#define BUTTON_SET_ID 3
|
||||
|
||||
#define PA_ENABLE_GPIO GPIO_NUM_12
|
||||
#define ADC_DETECT_GPIO GPIO_NUM_36
|
||||
#define BATTERY_DETECT_GPIO GPIO_NUM_37
|
||||
|
||||
#define SDCARD_OPEN_FILE_NUM_MAX 5
|
||||
#define SDCARD_INTR_GPIO GPIO_NUM_34
|
||||
|
||||
#define AUDIO_CODEC_DEFAULT_CONFIG() \
|
||||
{ \
|
||||
.adc_input = AUDIO_HAL_ADC_INPUT_LINE1, \
|
||||
.dac_output = AUDIO_HAL_DAC_OUTPUT_ALL, \
|
||||
.codec_mode = AUDIO_HAL_CODEC_MODE_BOTH, \
|
||||
.i2s_iface = \
|
||||
{ \
|
||||
.mode = AUDIO_HAL_MODE_SLAVE, \
|
||||
.fmt = AUDIO_HAL_I2S_NORMAL, \
|
||||
.samples = AUDIO_HAL_48K_SAMPLES, \
|
||||
.bits = AUDIO_HAL_BIT_LENGTH_16BITS, \
|
||||
}, \
|
||||
};
|
||||
|
||||
#define INPUT_KEY_NUM 4
|
||||
|
||||
#define INPUT_KEY_DEFAULT_INFO() \
|
||||
{ \
|
||||
{ \
|
||||
.type = PERIPH_ID_ADC_BTN, \
|
||||
.user_id = INPUT_KEY_USER_ID_VOLUP, \
|
||||
.act_id = BUTTON_VOLUP_ID, \
|
||||
}, \
|
||||
{ \
|
||||
.type = PERIPH_ID_ADC_BTN, \
|
||||
.user_id = INPUT_KEY_USER_ID_VOLDOWN, \
|
||||
.act_id = BUTTON_VOLDOWN_ID, \
|
||||
}, \
|
||||
{ \
|
||||
.type = PERIPH_ID_ADC_BTN, \
|
||||
.user_id = INPUT_KEY_USER_ID_MUTE, \
|
||||
.act_id = BUTTON_MUTE_ID, \
|
||||
}, \
|
||||
{ \
|
||||
.type = PERIPH_ID_ADC_BTN, \
|
||||
.user_id = INPUT_KEY_USER_ID_SET, \
|
||||
.act_id = BUTTON_SET_ID, \
|
||||
}, \
|
||||
}
|
||||
|
||||
#endif
|
||||
31
components/custom_board/ma120/include/ma120.h
Normal file
31
components/custom_board/ma120/include/ma120.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#ifndef _MA120_H_
|
||||
#define _MA120_H_
|
||||
|
||||
#include "esp_system.h"
|
||||
#include "board.h"
|
||||
|
||||
esp_err_t ma120_init(audio_hal_codec_config_t *codec_cfg);
|
||||
esp_err_t ma120_deinit(void);
|
||||
esp_err_t ma120_set_volume(int vol);
|
||||
esp_err_t ma120_get_volume(int *value);
|
||||
esp_err_t ma120_set_mute(bool enable);
|
||||
esp_err_t ma120_get_mute(bool *enabled);
|
||||
esp_err_t ma120_ctrl(audio_hal_codec_mode_t, audio_hal_ctrl_t);
|
||||
esp_err_t ma120_config_iface(audio_hal_codec_mode_t , audio_hal_codec_i2s_iface_t *);
|
||||
|
||||
void setup_ma120(void);
|
||||
void ma120_read_error(uint8_t i2c_addr);
|
||||
void ma120_setup_audio(uint8_t i2c_addr);
|
||||
|
||||
void i2c_master_init(void);
|
||||
|
||||
esp_err_t ma_write_byte(uint8_t i2c_addr, uint8_t prot, uint16_t address,
|
||||
uint8_t value);
|
||||
esp_err_t ma_write(uint8_t i2c_addr, uint8_t prot, uint16_t address,
|
||||
uint8_t *wbuf, uint8_t n);
|
||||
|
||||
uint8_t ma_read_byte(uint8_t i2c_addr, uint8_t prot, uint16_t address);
|
||||
esp_err_t ma_read(uint8_t i2c_addr, uint8_t prot, uint16_t address,
|
||||
uint8_t *rbuf, uint8_t n);
|
||||
|
||||
#endif /* _MA120_H_ */
|
||||
1922
components/custom_board/ma120/include/ma120x0.h
Normal file
1922
components/custom_board/ma120/include/ma120x0.h
Normal file
File diff suppressed because it is too large
Load Diff
364
components/custom_board/ma120/ma120.c
Normal file
364
components/custom_board/ma120/ma120.c
Normal file
@@ -0,0 +1,364 @@
|
||||
//
|
||||
// MA120 ESP32 Driver
|
||||
//
|
||||
// Merus Audio - September 2018
|
||||
// Written by Joergen Kragh Jakobsen, jkj@myrun.dk
|
||||
//
|
||||
// Register interface thrugh I2C for MA120
|
||||
// Support a single amplifier/i2c address
|
||||
//
|
||||
//
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ma120.h"
|
||||
#include "board.h"
|
||||
#include "driver/i2c.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
|
||||
static const char *TAG = "MA120";
|
||||
|
||||
#define MA_ENABLE_IO CONFIG_MA120_ENABLE_PIN
|
||||
#define MA_NMUTE_IO CONFIG_MA120_NMUTE_PIN
|
||||
#define MA_NERR_IO CONFIG_MERUS_NERR_PIN
|
||||
#define MA_NCLIP_IO CONFIG_MERUS_NCLIP_PIN
|
||||
|
||||
static const char *I2C_TAG = "i2c";
|
||||
#define I2C_CHECK(a, str, ret) \
|
||||
if (!(a)) { \
|
||||
ESP_LOGE(I2C_TAG, "%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \
|
||||
return (ret); \
|
||||
}
|
||||
|
||||
#define I2C_MASTER_NUM I2C_NUM_0 /*!< I2C port number for master dev */
|
||||
#define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master do not need buffer */
|
||||
#define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master do not need buffer */
|
||||
#define I2C_MASTER_FREQ_HZ 100000 /*!< I2C master clock frequency */
|
||||
|
||||
#define MA120_ADDR \
|
||||
CONFIG_DAC_I2C_ADDR /*!< slave address for MA120 amplifier \
|
||||
*/
|
||||
|
||||
#define WRITE_BIT I2C_MASTER_WRITE /*!< I2C master write */
|
||||
#define READ_BIT I2C_MASTER_READ /*!< I2C master read */
|
||||
#define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/
|
||||
#define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */
|
||||
#define ACK_VAL 0x0 /*!< I2C ack value */
|
||||
#define NACK_VAL 0x1 /*!< I2C nack value */
|
||||
|
||||
audio_hal_func_t AUDIO_CODEC_MA120_DEFAULT_HANDLE = {
|
||||
.audio_codec_initialize = ma120_init,
|
||||
.audio_codec_deinitialize = ma120_deinit,
|
||||
.audio_codec_ctrl = ma120_ctrl,
|
||||
.audio_codec_config_iface = ma120_config_iface,
|
||||
.audio_codec_set_mute = ma120_set_mute,
|
||||
.audio_codec_set_volume = ma120_set_volume,
|
||||
.audio_codec_get_volume = ma120_get_volume,
|
||||
.audio_hal_lock = NULL,
|
||||
.handle = NULL,
|
||||
};
|
||||
|
||||
esp_err_t ma120_deinit(void) {
|
||||
// TODO
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ma120_ctrl(audio_hal_codec_mode_t mode, audio_hal_ctrl_t ctrl_state) {
|
||||
ESP_LOGI("MA120 Driver", "ctrl w. mode and ctrl_state");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ma120_config_iface(audio_hal_codec_mode_t mode,
|
||||
audio_hal_codec_i2s_iface_t *iface) {
|
||||
ESP_LOGI("MA120 Driver", "config_iface w. mode and interface");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ma120_set_volume(int vol) {
|
||||
esp_err_t ret = ESP_OK;
|
||||
uint8_t cmd[2];
|
||||
cmd[0] = 128 - vol;
|
||||
cmd[1] = cmd[0];
|
||||
ma_write(MA120_ADDR, 2, 0x0003, cmd, 2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t ma120_get_volume(int *vol) {
|
||||
esp_err_t ret = ESP_OK;
|
||||
uint8_t rxbuf;
|
||||
rxbuf = ma_read_byte(MA120_ADDR, 2, 3);
|
||||
*vol = 128 - rxbuf;
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t ma120_set_mute(bool enable) {
|
||||
esp_err_t ret = ESP_OK;
|
||||
uint8_t nmute;
|
||||
nmute = (enable) ? 0 : 1;
|
||||
gpio_set_level(MA_NMUTE_IO, nmute);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t ma120_get_mute(bool *enabled) {
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
*enabled = false; // TODO read from register
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t ma120_init(audio_hal_codec_config_t *codec_cfg) {
|
||||
esp_err_t ret = ESP_OK;
|
||||
setup_ma120();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void setup_ma120(void){
|
||||
gpio_config_t io_conf;
|
||||
|
||||
io_conf.intr_type = GPIO_PIN_INTR_DISABLE;
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.pin_bit_mask = (1ULL << MA_ENABLE_IO | 1ULL << MA_NMUTE_IO);
|
||||
io_conf.pull_down_en = 0;
|
||||
io_conf.pull_up_en = 0;
|
||||
|
||||
printf("setup output %d %d \n", MA_ENABLE_IO, MA_NMUTE_IO);
|
||||
gpio_config(&io_conf);
|
||||
|
||||
io_conf.intr_type = GPIO_PIN_INTR_DISABLE;
|
||||
io_conf.mode = GPIO_MODE_INPUT;
|
||||
io_conf.pin_bit_mask = (1ULL << MA_NCLIP_IO | 1ULL << MA_NERR_IO);
|
||||
io_conf.pull_down_en = 0;
|
||||
io_conf.pull_up_en = 0;
|
||||
printf("Setup input NCLIP:%d NERR:%d \n", MA_NCLIP_IO, MA_NERR_IO);
|
||||
gpio_config(&io_conf);
|
||||
|
||||
gpio_set_level(MA_NMUTE_IO, 0);
|
||||
gpio_set_level(MA_ENABLE_IO, 0);
|
||||
|
||||
|
||||
i2c_master_init();
|
||||
|
||||
gpio_set_level(MA_ENABLE_IO, 1);
|
||||
|
||||
uint8_t res = ma_write_byte(MA120_ADDR, 2, 0x060c, 0);
|
||||
res = ma_read_byte(MA120_ADDR, 2, 0x060c);
|
||||
printf("Hardware version: 0x%02x\n", res);
|
||||
|
||||
printf("Scan I2C bus: ");
|
||||
for (uint8_t addr = 0x20; addr <= 0x23; addr++) {
|
||||
res = ma_read_byte(addr, 2, 0);
|
||||
printf(" 0x%02x => GEN2 ,", addr);
|
||||
// printf("Scan i2c address 0x%02x read address 0 : 0x%02x \n", addr ,res);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
uint8_t rxbuf[32];
|
||||
uint8_t otp[1024];
|
||||
for (uint8_t i = 0; i < 16; i++) {
|
||||
ma_read(MA120_ADDR, 2, 0x8000 + i * 32, rxbuf, 32);
|
||||
// printf("%04x : ",0x8000+i*32 );
|
||||
for (uint8_t j = 0; j < 32; j++) {
|
||||
otp[i * 32 + j] = rxbuf[j];
|
||||
}
|
||||
}
|
||||
for (uint16_t i = 0; i < 16 * 32; i++) {
|
||||
if (i % 32 == 0) {
|
||||
printf("\n0x%04x : ", 0x8000 + i);
|
||||
}
|
||||
printf("%02x ", otp[i]);
|
||||
}
|
||||
|
||||
res = ma_read(MA120_ADDR, 2, 0x0000, rxbuf, 2);
|
||||
printf("\nAddress 0 : 0x%02x\n", rxbuf[0]);
|
||||
ma_write_byte(MA120_ADDR, 2, 0x0003, 0x50);
|
||||
ma_write_byte(MA120_ADDR, 2, 0x0004, 0x50);
|
||||
ma_write_byte(MA120_ADDR, 2, 0x0005, 0x02);
|
||||
// ma_write_byte(MA120_ADDR,2,0x0246,0x00) ; //
|
||||
ESP_LOGI(TAG, "ma120_setup done [ok]");
|
||||
}
|
||||
|
||||
#define CRED "\x1b[31m"
|
||||
#define CGRE "\x1b[32m"
|
||||
#define CYEL "\x1b[33m"
|
||||
#define CBLU "\x1b[34m"
|
||||
#define CMAG "\x1b[35m"
|
||||
#define CYAN "\x1b[36m"
|
||||
#define CWHI "\x1b[0m"
|
||||
const char *cherr_str[] = {"Clip_stuck", "DC", "VCF", "OCP_SEV", "OCP"};
|
||||
const char *syserr1_str[] = {" X ", " X ", "DSP3 ", " DSP2",
|
||||
" DSP1 ", "DSP0 ", "ERR", "PVT_low"};
|
||||
const char *syserr0_str[] = {"OTW", "OTE", "PV_uv", "PV_low",
|
||||
"OV_ov", " CLK ", "AUD", " TW "};
|
||||
|
||||
void ma120_read_error(uint8_t i2c_addr) { // 0x0118 error now ch0 [clip_stuck
|
||||
// dc vcf_err ocp_severe ocp]
|
||||
// 0x0119 error now ch1 [clip_stuck dc vcf_err ocp_severe ocp]
|
||||
// 0x011a error now system [ AE CE ... ]
|
||||
// 0x011b error now system [DSP3 DSP2 DSP1 DSP0 OC OE]
|
||||
// 0x011c error acc ch0 [clip_stuck dc vcf_err ocp_severe ocp]
|
||||
// 0x011d error acc ch1 [clip_stuck dc vcf_err ocp_severe ocp]
|
||||
// 0x011e error acc system [7..0]
|
||||
// 0x011f error acc system [13..8]
|
||||
uint8_t errbuf[10] = {0};
|
||||
|
||||
ma_read(i2c_addr, 2, 0x0118, errbuf, 8);
|
||||
|
||||
// Error flag now : RED
|
||||
// Error flag acc : WHITE
|
||||
// No flag set : GREEN
|
||||
for (int i = 0; i <= 7; i++) { // Error now
|
||||
printf(" %s%s ",
|
||||
((errbuf[3] & (1 << i)) == (1 << i)) ? CRED
|
||||
: ((errbuf[7] & (1 << i)) == (1 << i)) ? CWHI
|
||||
: CGRE,
|
||||
syserr1_str[i]);
|
||||
}
|
||||
printf(" [0x%02x 0x%02x]\n", errbuf[3], errbuf[7]);
|
||||
|
||||
for (int i = 0; i <= 7; i++) {
|
||||
printf(" %s%s ",
|
||||
((errbuf[2] & (1 << i)) == (1 << i)) ? CRED
|
||||
: ((errbuf[6] & (1 << i)) == (1 << i)) ? CWHI
|
||||
: CGRE,
|
||||
syserr0_str[i]);
|
||||
}
|
||||
printf(" [0x%02x 0x%02x]\n", errbuf[2], errbuf[6]);
|
||||
|
||||
// printf("0x011b : 0x%02x %s", rxbuf[2], l1 );
|
||||
// printf("\nError vectors :");
|
||||
// for (int i = 0; i<8; i++)
|
||||
//{ printf("%02x ", errbuf[i]);
|
||||
// }
|
||||
// printf("\n");
|
||||
}
|
||||
|
||||
static i2c_config_t i2c_cfg = {
|
||||
.mode = I2C_MODE_MASTER,
|
||||
.sda_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.scl_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.master.clk_speed = I2C_MASTER_FREQ_HZ,
|
||||
};
|
||||
|
||||
void i2c_master_init() {
|
||||
int i2c_master_port = I2C_MASTER_NUM;
|
||||
|
||||
get_i2c_pins(I2C_NUM_0, &i2c_cfg);
|
||||
|
||||
esp_err_t res = i2c_param_config(i2c_master_port, &i2c_cfg);
|
||||
printf("Driver param setup : %d\n", res);
|
||||
res = i2c_driver_install(i2c_master_port, i2c_cfg.mode,
|
||||
I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE,
|
||||
0);
|
||||
printf("Driver installed : %d\n", res);
|
||||
}
|
||||
|
||||
esp_err_t ma_write(uint8_t i2c_addr, uint8_t prot, uint16_t address,
|
||||
uint8_t *wbuf, uint8_t n) {
|
||||
bool ack = ACK_VAL;
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, i2c_addr << 1 | WRITE_BIT, ACK_CHECK_EN);
|
||||
if (prot == 2) {
|
||||
i2c_master_write_byte(cmd, (uint8_t)((address & 0xff00) >> 8), ACK_VAL);
|
||||
i2c_master_write_byte(cmd, (uint8_t)(address & 0x00ff), ACK_VAL);
|
||||
} else {
|
||||
i2c_master_write_byte(cmd, (uint8_t)address, ACK_VAL);
|
||||
}
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (i == n - 1) ack = NACK_VAL;
|
||||
i2c_master_write_byte(cmd, wbuf[i], ack);
|
||||
}
|
||||
i2c_master_stop(cmd);
|
||||
int ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if (ret == ESP_FAIL) {
|
||||
return ret;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ma_write_byte(uint8_t i2c_addr, uint8_t prot, uint16_t address,
|
||||
uint8_t value) {
|
||||
printf("%04x %02x\n", address, value);
|
||||
esp_err_t ret = 0;
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, (i2c_addr << 1) | WRITE_BIT, ACK_CHECK_EN);
|
||||
if (prot == 2) {
|
||||
i2c_master_write_byte(cmd, (uint8_t)((address & 0xff00) >> 8), ACK_VAL);
|
||||
i2c_master_write_byte(cmd, (uint8_t)(address & 0x00ff), ACK_VAL);
|
||||
} else {
|
||||
i2c_master_write_byte(cmd, (uint8_t)address, ACK_VAL);
|
||||
}
|
||||
i2c_master_write_byte(cmd, value, ACK_VAL);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if (ret == ESP_FAIL) {
|
||||
printf("ESP_I2C_WRITE ERROR : %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ma_read(uint8_t i2c_addr, uint8_t prot, uint16_t address,
|
||||
uint8_t *rbuf, uint8_t n) {
|
||||
esp_err_t ret;
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
if (cmd == NULL) {
|
||||
printf("ERROR handle null\n");
|
||||
}
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, (i2c_addr << 1) | WRITE_BIT, ACK_CHECK_EN);
|
||||
if (prot == 2) {
|
||||
i2c_master_write_byte(cmd, (uint8_t)((address & 0xff00) >> 8), ACK_VAL);
|
||||
i2c_master_write_byte(cmd, (uint8_t)(address & 0x00ff), ACK_VAL);
|
||||
} else {
|
||||
i2c_master_write_byte(cmd, (uint8_t)address, ACK_VAL);
|
||||
}
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, (i2c_addr << 1) | READ_BIT, ACK_CHECK_EN);
|
||||
// if (n == 1 )
|
||||
i2c_master_read(cmd, rbuf, n - 1, ACK_VAL);
|
||||
// for (uint8_t i = 0;i<n;i++)
|
||||
// { i2c_master_read_byte(cmd, rbuf++, ACK_VAL); }
|
||||
i2c_master_read_byte(cmd, rbuf + n - 1, NACK_VAL);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 100 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if (ret == ESP_FAIL) {
|
||||
printf("i2c Error read - readback\n");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t ma_read_byte(uint8_t i2c_addr, uint8_t prot, uint16_t address) {
|
||||
uint8_t value = 0;
|
||||
esp_err_t ret;
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd); // Send i2c start on bus
|
||||
i2c_master_write_byte(cmd, (i2c_addr << 1) | WRITE_BIT, ACK_CHECK_EN);
|
||||
if (prot == 2) {
|
||||
i2c_master_write_byte(cmd, (uint8_t)((address & 0xff00) >> 8), ACK_VAL);
|
||||
i2c_master_write_byte(cmd, (uint8_t)(address & 0x00ff), ACK_VAL);
|
||||
} else {
|
||||
i2c_master_write_byte(cmd, (uint8_t)address, ACK_VAL);
|
||||
}
|
||||
i2c_master_start(cmd); // Repeated start
|
||||
i2c_master_write_byte(cmd, (i2c_addr << 1) | READ_BIT, ACK_CHECK_EN);
|
||||
|
||||
i2c_master_read_byte(cmd, &value, NACK_VAL);
|
||||
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if (ret == ESP_FAIL) {
|
||||
printf("i2c Error read - readback\n");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
365
components/custom_board/ma120x0/MerusAudio.c
Normal file
365
components/custom_board/ma120x0/MerusAudio.c
Normal file
@@ -0,0 +1,365 @@
|
||||
//
|
||||
// MA120x0P ESP32 Driver
|
||||
//
|
||||
// Merus Audio - September 2018
|
||||
// Written by Joergen Kragh Jakobsen, jkj@myrun.dk
|
||||
//
|
||||
// Register interface thrugh I2C for MA12070P and MA12040P
|
||||
// Support a single amplifier/i2c address
|
||||
//
|
||||
//
|
||||
|
||||
#include "MerusAudio.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "driver/i2c.h"
|
||||
#include "esp_log.h"
|
||||
#include "ma120x0.h"
|
||||
//#include "ma120_rev1_all.h"
|
||||
|
||||
static const char *TAG = "MA120X0";
|
||||
|
||||
#define MA_NENABLE_IO CONFIG_MA120X0_NENABLE_PIN
|
||||
#define MA_ENABLE_IO CONFIG_MA120X0_ENABLE_PIN
|
||||
#define MA_NMUTE_IO CONFIG_MA120X0_NMUTE_PIN
|
||||
#define MA_NERR_IO CONFIG_MA120X0_NERR_PIN
|
||||
#define MA_NCLIP_IO CONFIG_MA120X0_NCLIP_PIN
|
||||
|
||||
static const char *I2C_TAG = "i2c";
|
||||
#define I2C_CHECK(a, str, ret) \
|
||||
if (!(a)) { \
|
||||
ESP_LOGE(I2C_TAG, "%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \
|
||||
return (ret); \
|
||||
}
|
||||
|
||||
#define I2C_MASTER_NUM I2C_NUM_0 /*!< I2C port number for master dev */
|
||||
#define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master do not need buffer */
|
||||
#define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master do not need buffer */
|
||||
#define I2C_MASTER_FREQ_HZ 100000 /*!< I2C master clock frequency */
|
||||
|
||||
#define MA120X0_ADDR \
|
||||
CONFIG_DAC_I2C_ADDR /*!< slave address for MA120X0 amplifier */
|
||||
|
||||
#define WRITE_BIT I2C_MASTER_WRITE /*!< I2C master write */
|
||||
#define READ_BIT I2C_MASTER_READ /*!< I2C master read */
|
||||
#define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/
|
||||
#define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */
|
||||
#define ACK_VAL 0x0 /*!< I2C ack value */
|
||||
#define NACK_VAL 0x1 /*!< I2C nack value */
|
||||
|
||||
static i2c_config_t i2c_cfg;
|
||||
|
||||
audio_hal_func_t AUDIO_CODEC_MA120X0_DEFAULT_HANDLE = {
|
||||
.audio_codec_initialize = ma120x0_init,
|
||||
.audio_codec_deinitialize = ma120x0_deinit,
|
||||
.audio_codec_ctrl = ma120x0_ctrl,
|
||||
.audio_codec_config_iface = ma120x0_config_iface,
|
||||
.audio_codec_set_mute = ma120x0_set_mute,
|
||||
.audio_codec_set_volume = ma120x0_set_volume,
|
||||
.audio_codec_get_volume = ma120x0_get_volume,
|
||||
.audio_hal_lock = NULL,
|
||||
.handle = NULL,
|
||||
};
|
||||
|
||||
esp_err_t ma120x0_deinit(void) {
|
||||
// TODO
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ma120x0_ctrl(audio_hal_codec_mode_t mode,
|
||||
audio_hal_ctrl_t ctrl_state) {
|
||||
// TODO
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ma120x0_config_iface(audio_hal_codec_mode_t mode,
|
||||
audio_hal_codec_i2s_iface_t *iface) {
|
||||
// TODO
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ma120x0_set_volume(int vol) {
|
||||
esp_err_t ret = ESP_OK;
|
||||
uint8_t cmd;
|
||||
cmd = 128 - vol;
|
||||
ma_write_byte(0x20, 1, 64, cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t ma120x0_get_volume(int *vol) {
|
||||
esp_err_t ret = ESP_OK;
|
||||
uint8_t rxbuf;
|
||||
rxbuf = ma_read_byte(0x20, 1, 64, rxbuf);
|
||||
*vol = 128 - rxbuf;
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t ma120x0_set_mute(bool enable) {
|
||||
esp_err_t ret = ESP_OK;
|
||||
uint8_t nmute = (enable) ? 0 : 1 gpio_set_level(MA_NMUTE_IO, nmute);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t ma120x0_get_mute(bool *enabled) {
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
*enabled = false; // TODO read from register
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t ma120x0_init(audio_hal_codec_config_t *codec_cfg) {
|
||||
esp_err_t ret = ESP_OK;
|
||||
gpio_config_t io_conf;
|
||||
|
||||
io_conf.intr_type = GPIO_PIN_INTR_DISABLE;
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.pin_bit_mask = (1ULL << MA_ENABLE_IO | 1ULL << MA_NMUTE_IO);
|
||||
io_conf.pull_down_en = 0;
|
||||
io_conf.pull_up_en = 0;
|
||||
|
||||
printf("setup output %d %d \n", MA_ENABLE_IO, MA_NMUTE_IO);
|
||||
gpio_config(&io_conf);
|
||||
|
||||
io_conf.intr_type = GPIO_PIN_INTR_DISABLE;
|
||||
io_conf.mode = GPIO_MODE_INPUT;
|
||||
io_conf.pin_bit_mask = (1ULL << MA_NCLIP_IO | 1ULL << MA_NERR_IO);
|
||||
io_conf.pull_down_en = 0;
|
||||
io_conf.pull_up_en = 0;
|
||||
printf("setup input %d %d \n", MA_NCLIP_IO, MA_NERR_IO);
|
||||
gpio_config(&io_conf);
|
||||
|
||||
gpio_set_level(MA_NMUTE_IO, 0);
|
||||
gpio_set_level(MA_ENABLE_IO, 0);
|
||||
// required?
|
||||
// gpio_set_drive_capability(I2C_MASTER_SCL_IO,2);
|
||||
// gpio_set_drive_capability(I2C_MASTER_SDA_IO,2);
|
||||
|
||||
i2c_master_init();
|
||||
|
||||
gpio_set_level(MA_ENABLE_IO, 1);
|
||||
|
||||
uint8_t res = ma_write_byte(0x20, 2, 1544, 0);
|
||||
res = ma_read_byte(0x20, 2, 1544);
|
||||
printf("Hardware version: 0x%02x\n", res);
|
||||
printf("Scan I2C bus: ");
|
||||
for (uint8_t addr = 0x20; addr <= 0x23; addr++) {
|
||||
res = ma_read_byte(addr, 2, 0);
|
||||
|
||||
printf(" 0x%02x => GEN2 ,", addr);
|
||||
// printf("Scan i2c address 0x%02x read address 0 : 0x%02x \n", addr ,res);
|
||||
}
|
||||
printf("\n");
|
||||
uint8_t rxbuf[32];
|
||||
uint8_t otp[1024];
|
||||
for (uint8_t i = 0; i < 16; i++) {
|
||||
ma_read(0x20, 2, 0x8000 + i * 32, rxbuf, 32);
|
||||
// printf("%04x : ",0x8000+i*32 );
|
||||
for (uint8_t j = 0; j < 32; j++) {
|
||||
otp[i * 32 + j] = rxbuf[j];
|
||||
}
|
||||
}
|
||||
for (uint16_t i = 0; i < 16 * 32; i++) {
|
||||
if (i % 32 == 0) {
|
||||
printf("\n0x%04x : ", 0x8000 + i);
|
||||
}
|
||||
printf("%02x ", otp[i]);
|
||||
}
|
||||
|
||||
res = ma_write_byte(0x20, 2, 0x060c, 0);
|
||||
res = ma_read(0x20, 2, 0x060c, rxbuf, 2);
|
||||
printf("\nHardware version: 0x%02x\n", rxbuf[0]);
|
||||
|
||||
res = ma_read(0x20, 2, 0x0000, rxbuf, 2);
|
||||
printf("\nAddress 0 : 0x%02x\n", rxbuf[0]);
|
||||
ma_write_byte(0x20, 2, 0x0003, 0x50);
|
||||
ma_write_byte(0x20, 2, 0x0004, 0x50);
|
||||
ma_write_byte(0x20, 2, 0x0005, 0x02);
|
||||
// ma_write_byte(0x20,2,0x0246,0x00) ; //
|
||||
printf("\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define CRED "\x1b[31m"
|
||||
#define CGRE "\x1b[32m"
|
||||
#define CYEL "\x1b[33m"
|
||||
#define CBLU "\x1b[34m"
|
||||
#define CMAG "\x1b[35m"
|
||||
#define CYAN "\x1b[36m"
|
||||
#define CWHI "\x1b[0m"
|
||||
const char *cherr_str[] = {"Clip_stuck", "DC", "VCF", "OCP_SEV", "OCP"};
|
||||
const char *syserr1_str[] = {" X ", " X ", "DSP3 ", " DSP2",
|
||||
" DSP1 ", "DSP0 ", "ERR", "PVT_low"};
|
||||
const char *syserr0_str[] = {"OTW", "OTE", "PV_uv", "PV_low",
|
||||
"OV_ov", " CLK ", "AUD", " TW "};
|
||||
// static uint8_t terr = 0;
|
||||
void ma120_read_error(uint8_t i2c_addr) { // 0x0118 error now ch0 [clip_stuck
|
||||
// dc vcf_err ocp_severe ocp]
|
||||
// 0x0119 error now ch1 [clip_stuck dc vcf_err ocp_severe ocp]
|
||||
// 0x011a error now system [ AE CE ... ]
|
||||
// 0x011b error now system [DSP3 DSP2 DSP1 DSP0 OC OE]
|
||||
// 0x011c error acc ch0 [clip_stuck dc vcf_err ocp_severe ocp]
|
||||
// 0x011d error acc ch1 [clip_stuck dc vcf_err ocp_severe ocp]
|
||||
// 0x011e error acc system [7..0]
|
||||
// 0x011f error acc system [13..8]
|
||||
uint8_t errbuf[10] = {0};
|
||||
|
||||
uint8_t res = ma_read(i2c_addr, 2, 0x0118, errbuf, 8);
|
||||
|
||||
// Error flag now : RED
|
||||
// Error flag acc : WHITE
|
||||
// No flag set : GREEN
|
||||
for (int i = 0; i <= 7; i++) { // Error now
|
||||
printf(" %s%s ",
|
||||
((errbuf[3] & (1 << i)) == (1 << i)) ? CRED
|
||||
: ((errbuf[7] & (1 << i)) == (1 << i)) ? CWHI
|
||||
: CGRE,
|
||||
syserr1_str[i]);
|
||||
}
|
||||
printf(" [0x%02x 0x%02x]\n", errbuf[3], errbuf[7]);
|
||||
|
||||
for (int i = 0; i <= 7; i++) {
|
||||
printf(" %s%s ",
|
||||
((errbuf[2] & (1 << i)) == (1 << i)) ? CRED
|
||||
: ((errbuf[6] & (1 << i)) == (1 << i)) ? CWHI
|
||||
: CGRE,
|
||||
syserr0_str[i]);
|
||||
}
|
||||
printf(" [0x%02x 0x%02x]\n", errbuf[2], errbuf[6]);
|
||||
|
||||
// printf("0x011b : 0x%02x %s", rxbuf[2], l1 );
|
||||
// printf("\nError vectors :");
|
||||
// for (int i = 0; i<8; i++)
|
||||
//{ printf("%02x ", errbuf[i]);
|
||||
// }
|
||||
// printf("\n");
|
||||
}
|
||||
|
||||
void i2c_master_init() {
|
||||
int i2c_master_port = I2C_MASTER_NUM;
|
||||
i2c_cfg = {
|
||||
.mode = I2C_MODE_MASTER,
|
||||
.sda_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.scl_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.master.clk_speed = I2C_MASTER_FREQ_HZ,
|
||||
};
|
||||
get_i2c_pins(I2C_NUM_0, &i2c_cfg);
|
||||
|
||||
esp_err_t res = i2c_param_config(i2c_master_port, &i2c_cfg);
|
||||
printf("Driver param setup : %d\n", res);
|
||||
res = i2c_driver_install(i2c_master_port, i2c_cfg.mode,
|
||||
I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE,
|
||||
0);
|
||||
printf("Driver installed : %d\n", res);
|
||||
}
|
||||
|
||||
esp_err_t ma_write(uint8_t i2c_addr, uint8_t prot, uint16_t address,
|
||||
uint8_t *wbuf, uint8_t n) {
|
||||
bool ack = ACK_VAL;
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, i2c_addr << 1 | WRITE_BIT, ACK_CHECK_EN);
|
||||
if (prot == 2) {
|
||||
i2c_master_write_byte(cmd, (uint8_t)((address & 0xff00) >> 8), ACK_VAL);
|
||||
i2c_master_write_byte(cmd, (uint8_t)(address & 0x00ff), ACK_VAL);
|
||||
} else {
|
||||
i2c_master_write_byte(cmd, (uint8_t)address, ACK_VAL);
|
||||
}
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (i == n - 1) ack = NACK_VAL;
|
||||
i2c_master_write_byte(cmd, wbuf[i], ack);
|
||||
}
|
||||
i2c_master_stop(cmd);
|
||||
int ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if (ret == ESP_FAIL) {
|
||||
return ret;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ma_write_byte(uint8_t i2c_addr, uint8_t prot, uint16_t address,
|
||||
uint8_t value) {
|
||||
printf("%04x %02x\n", address, value);
|
||||
esp_err_t ret = 0;
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, (i2c_addr << 1) | WRITE_BIT, ACK_CHECK_EN);
|
||||
if (prot == 2) {
|
||||
i2c_master_write_byte(cmd, (uint8_t)((address & 0xff00) >> 8), ACK_VAL);
|
||||
i2c_master_write_byte(cmd, (uint8_t)(address & 0x00ff), ACK_VAL);
|
||||
} else {
|
||||
i2c_master_write_byte(cmd, (uint8_t)address, ACK_VAL);
|
||||
}
|
||||
i2c_master_write_byte(cmd, value, ACK_VAL);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if (ret == ESP_FAIL) {
|
||||
printf("ESP_I2C_WRITE ERROR : %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ma_read(uint8_t i2c_addr, uint8_t prot, uint16_t address,
|
||||
uint8_t *rbuf, uint8_t n) {
|
||||
esp_err_t ret;
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
if (cmd == NULL) {
|
||||
printf("ERROR handle null\n");
|
||||
}
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, (i2c_addr << 1) | WRITE_BIT, ACK_CHECK_EN);
|
||||
if (prot == 2) {
|
||||
i2c_master_write_byte(cmd, (uint8_t)((address & 0xff00) >> 8), ACK_VAL);
|
||||
i2c_master_write_byte(cmd, (uint8_t)(address & 0x00ff), ACK_VAL);
|
||||
} else {
|
||||
i2c_master_write_byte(cmd, (uint8_t)address, ACK_VAL);
|
||||
}
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, (i2c_addr << 1) | READ_BIT, ACK_CHECK_EN);
|
||||
// if (n == 1 )
|
||||
i2c_master_read(cmd, rbuf, n - 1, ACK_VAL);
|
||||
// for (uint8_t i = 0;i<n;i++)
|
||||
// { i2c_master_read_byte(cmd, rbuf++, ACK_VAL); }
|
||||
i2c_master_read_byte(cmd, rbuf + n - 1, NACK_VAL);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 100 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if (ret == ESP_FAIL) {
|
||||
printf("i2c Error read - readback\n");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t ma_read_byte(uint8_t i2c_addr, uint8_t prot, uint16_t address) {
|
||||
uint8_t value = 0;
|
||||
esp_err_t ret;
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd); // Send i2c start on bus
|
||||
i2c_master_write_byte(cmd, (i2c_addr << 1) | WRITE_BIT, ACK_CHECK_EN);
|
||||
if (prot == 2) {
|
||||
i2c_master_write_byte(cmd, (uint8_t)((address & 0xff00) >> 8), ACK_VAL);
|
||||
i2c_master_write_byte(cmd, (uint8_t)(address & 0x00ff), ACK_VAL);
|
||||
} else {
|
||||
i2c_master_write_byte(cmd, (uint8_t)address, ACK_VAL);
|
||||
}
|
||||
i2c_master_start(cmd); // Repeated start
|
||||
i2c_master_write_byte(cmd, (i2c_addr << 1) | READ_BIT, ACK_CHECK_EN);
|
||||
|
||||
i2c_master_read_byte(cmd, &value, NACK_VAL);
|
||||
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if (ret == ESP_FAIL) {
|
||||
printf("i2c Error read - readback\n");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
20
components/custom_board/ma120x0/include/MerusAudio.h
Normal file
20
components/custom_board/ma120x0/include/MerusAudio.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef _MERUSAUDIO_H_
|
||||
#define _MERUSAUDIO_H_
|
||||
|
||||
void setup_ma120x0(void);
|
||||
void setup_ma120(void);
|
||||
void ma120_read_error(uint8_t i2c_addr);
|
||||
void ma120_setup_audio(uint8_t i2c_addr);
|
||||
|
||||
void i2c_master_init(void);
|
||||
|
||||
esp_err_t ma_write_byte(uint8_t i2c_addr, uint8_t prot, uint16_t address,
|
||||
uint8_t value);
|
||||
esp_err_t ma_write(uint8_t i2c_addr, uint8_t prot, uint16_t address,
|
||||
uint8_t *wbuf, uint8_t n);
|
||||
|
||||
uint8_t ma_read_byte(uint8_t i2c_addr, uint8_t prot, uint16_t address);
|
||||
esp_err_t ma_read(uint8_t i2c_addr, uint8_t prot, uint16_t address,
|
||||
uint8_t *rbuf, uint8_t n);
|
||||
|
||||
#endif /* _MERUSAUDIO_H_ */
|
||||
1922
components/custom_board/ma120x0/include/ma120x0.h
Normal file
1922
components/custom_board/ma120x0/include/ma120x0.h
Normal file
File diff suppressed because it is too large
Load Diff
145
components/custom_board/pcm51xx/include/pcm51xx.h
Normal file
145
components/custom_board/pcm51xx/include/pcm51xx.h
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
|
||||
* Copyright (c) 2021 David Douard <david.douard@sdfa3.org>
|
||||
*
|
||||
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
|
||||
* which case, it is free of charge, to any person obtaining a copy of this
|
||||
* software and associated documentation files (the "Software"), to deal in the
|
||||
* Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do
|
||||
* so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _PCM51XX_H_
|
||||
#define _PCM51XX_H_
|
||||
|
||||
#include "audio_hal.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define PCM51XX_REG_00 0x00
|
||||
#define PCM51XX_REG_02 0x02
|
||||
#define PCM51XX_REG_03 0x03
|
||||
#define PCM51XX_REG_24 0x24
|
||||
#define PCM51XX_REG_25 0x25
|
||||
#define PCM51XX_REG_26 0x26
|
||||
#define PCM51XX_REG_27 0x27
|
||||
#define PCM51XX_REG_28 0x28
|
||||
#define PCM51XX_REG_29 0x29
|
||||
#define PCM51XX_REG_2A 0x2a
|
||||
#define PCM51XX_REG_2B 0x2b
|
||||
#define PCM51XX_REG_35 0x35
|
||||
#define PCM51XX_REG_7E 0x7e
|
||||
#define PCM51XX_REG_7F 0x7f
|
||||
|
||||
#define PCM51XX_PAGE_00 0x00
|
||||
#define PCM51XX_PAGE_2A 0x2a
|
||||
|
||||
#define PCM51XX_BOOK_00 0x00
|
||||
#define PCM51XX_BOOK_8C 0x8c
|
||||
|
||||
#define PCM51XX_REG_VOL_L 0X3D
|
||||
#define PCM51XX_REG_VOL_R 0X3E
|
||||
#define PCM51XX_REG_MUTE 0X03
|
||||
|
||||
#define PCM51XX_DAMP_MODE_BTL 0x0
|
||||
#define PCM51XX_DAMP_MODE_PBTL 0x04
|
||||
|
||||
/**
|
||||
* @brief Initialize TAS5805 codec chip
|
||||
*
|
||||
* @param cfg configuration of TAS5805
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_FAIL
|
||||
*/
|
||||
esp_err_t pcm51xx_init(audio_hal_codec_config_t *codec_cfg);
|
||||
|
||||
/**
|
||||
* @brief Deinitialize TAS5805 codec chip
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_FAIL
|
||||
*/
|
||||
esp_err_t pcm51xx_deinit(void);
|
||||
|
||||
/**
|
||||
* @brief Set voice volume
|
||||
*
|
||||
* @param volume: voice volume (0~100)
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_FAIL
|
||||
*/
|
||||
esp_err_t pcm51xx_set_volume(int vol);
|
||||
|
||||
/**
|
||||
* @brief Get voice volume
|
||||
*
|
||||
* @param[out] *volume: voice volume (0~100)
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_FAIL
|
||||
*/
|
||||
esp_err_t pcm51xx_get_volume(int *value);
|
||||
|
||||
/**
|
||||
* @brief Set TAS5805 mute or not
|
||||
* Continuously call should have an interval time determined by
|
||||
* pcm51xx_set_mute_fade()
|
||||
*
|
||||
* @param enable enable(1) or disable(0)
|
||||
*
|
||||
* @return
|
||||
* - ESP_FAIL Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t pcm51xx_set_mute(bool enable);
|
||||
|
||||
/**
|
||||
* @brief Get TAS5805 mute status
|
||||
*
|
||||
* @return
|
||||
* - ESP_FAIL Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t pcm51xx_get_mute(bool *enabled);
|
||||
|
||||
/**
|
||||
* @brief Set DAMP mode
|
||||
*
|
||||
* @param value PCM51XX_DAMP_MODE_BTL or PCM51XX_DAMP_MODE_PBTL
|
||||
* @return
|
||||
* - ESP_FAIL Parameter error
|
||||
* - ESP_OK Success
|
||||
*
|
||||
*/
|
||||
esp_err_t pcm51xx_set_damp_mode(int value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
56
components/custom_board/pcm51xx/include/pcm51xx_reg_cfg.h
Normal file
56
components/custom_board/pcm51xx/include/pcm51xx_reg_cfg.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2021 David Douard <david.douard@sdfa3.org>
|
||||
*
|
||||
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
|
||||
* which case, it is free of charge, to any person obtaining a copy of this
|
||||
* software and associated documentation files (the "Software"), to deal in the
|
||||
* Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do
|
||||
* so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _PCM51XX_REG_CFG_
|
||||
#define _PCM51XX_REG_CFG_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uint8_t offset;
|
||||
uint8_t value;
|
||||
} pcm51xx_cfg_reg_t;
|
||||
|
||||
static const pcm51xx_cfg_reg_t pcm51xx_init_seq[] = {
|
||||
|
||||
// EXIT SHUTDOWN STATE
|
||||
{0x00, 0x00}, // SELECT PAGE 0
|
||||
{0x03, 0x00}, // UNMUTE
|
||||
{0x2a, 0x11}, // DAC DATA PATH L->ch1, R->ch2
|
||||
{0x02, 0x00}, // DISABLE STBY
|
||||
{0x0d, 0x10}, // BCK as SRC for PLL
|
||||
{0x25, 0x08}, // IGNORE MISSING MCLK
|
||||
{0x3d, 0x55}, // DIGITAL VOLUME L
|
||||
{0x3e, 0x55}, // DIGITAL VOLUME R
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
219
components/custom_board/pcm51xx/pcm51xx.c
Normal file
219
components/custom_board/pcm51xx/pcm51xx.c
Normal file
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
|
||||
* Copyright (c) 2021 David Douard <david.douard@sdfa3.org>
|
||||
*
|
||||
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
|
||||
* which case, it is free of charge, to any person obtaining a copy of this
|
||||
* software and associated documentation files (the "Software"), to deal in the
|
||||
* Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do
|
||||
* so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "pcm51xx.h"
|
||||
|
||||
#include "board.h"
|
||||
#include "esp_log.h"
|
||||
#include "i2c_bus.h"
|
||||
#include "pcm51xx_reg_cfg.h"
|
||||
|
||||
static const char *TAG = "PCM51XX";
|
||||
|
||||
#define PCM51XX_BASE_ADDR 0x98
|
||||
#define PCM51XX_RST_GPIO get_pa_enable_gpio()
|
||||
#define PCM51XX_VOLUME_MAX 255
|
||||
#define PCM51XX_VOLUME_MIN 0
|
||||
|
||||
#define PCM51XX_ASSERT(a, format, b, ...) \
|
||||
if ((a) != 0) { \
|
||||
ESP_LOGE(TAG, format, ##__VA_ARGS__); \
|
||||
return b; \
|
||||
}
|
||||
|
||||
esp_err_t pcm51xx_ctrl(audio_hal_codec_mode_t mode,
|
||||
audio_hal_ctrl_t ctrl_state);
|
||||
esp_err_t pcm51xx_config_iface(audio_hal_codec_mode_t mode,
|
||||
audio_hal_codec_i2s_iface_t *iface);
|
||||
static i2c_bus_handle_t i2c_handler;
|
||||
static int pcm51xx_addr;
|
||||
|
||||
/*
|
||||
* i2c default configuration
|
||||
*/
|
||||
static i2c_config_t i2c_cfg = {
|
||||
.mode = I2C_MODE_MASTER,
|
||||
.sda_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.scl_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.master.clk_speed = 100000,
|
||||
};
|
||||
|
||||
/*
|
||||
* Operate function
|
||||
*/
|
||||
audio_hal_func_t AUDIO_CODEC_PCM51XX_DEFAULT_HANDLE = {
|
||||
.audio_codec_initialize = pcm51xx_init,
|
||||
.audio_codec_deinitialize = pcm51xx_deinit,
|
||||
.audio_codec_ctrl = pcm51xx_ctrl,
|
||||
.audio_codec_config_iface = pcm51xx_config_iface,
|
||||
.audio_codec_set_mute = pcm51xx_set_mute,
|
||||
.audio_codec_set_volume = pcm51xx_set_volume,
|
||||
.audio_codec_get_volume = pcm51xx_get_volume,
|
||||
.audio_hal_lock = NULL,
|
||||
.handle = NULL,
|
||||
};
|
||||
|
||||
static esp_err_t pcm51xx_transmit_registers(const pcm51xx_cfg_reg_t *conf_buf,
|
||||
int size) {
|
||||
int i = 0;
|
||||
esp_err_t ret = ESP_OK;
|
||||
while (i < size) {
|
||||
ret = i2c_bus_write_bytes(i2c_handler, pcm51xx_addr,
|
||||
(unsigned char *)(&conf_buf[i].offset), 1,
|
||||
(unsigned char *)(&conf_buf[i].value), 1);
|
||||
i++;
|
||||
}
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Fail to load configuration to pcm51xx");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
ESP_LOGI(TAG, "%s: write %d reg done", __FUNCTION__, i);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t pcm51xx_init(audio_hal_codec_config_t *codec_cfg) {
|
||||
esp_err_t ret = ESP_OK;
|
||||
ESP_LOGI(TAG, "Power ON CODEC with GPIO %d", PCM51XX_RST_GPIO);
|
||||
// probably unnecessary...
|
||||
/*
|
||||
gpio_config_t io_conf;
|
||||
io_conf.pin_bit_mask = BIT64(PCM51XX_RST_GPIO);
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
gpio_config(&io_conf);
|
||||
gpio_set_level(PCM51XX_RST_GPIO, 0);
|
||||
vTaskDelay(20 / portTICK_RATE_MS);
|
||||
gpio_set_level(PCM51XX_RST_GPIO, 1);
|
||||
vTaskDelay(200 / portTICK_RATE_MS);
|
||||
*/
|
||||
|
||||
ret = get_i2c_pins(I2C_NUM_0, &i2c_cfg);
|
||||
i2c_handler = i2c_bus_create(I2C_NUM_0, &i2c_cfg);
|
||||
if (i2c_handler == NULL) {
|
||||
ESP_LOGW(TAG, "failed to create i2c bus handler\n");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
uint8_t data[] = {0, 0};
|
||||
for (int i = 0; i < 4; i++) {
|
||||
pcm51xx_addr = PCM51XX_BASE_ADDR + 2 * i;
|
||||
ESP_LOGI(TAG, "Looking for a pcm51xx chip at address 0x%x", pcm51xx_addr);
|
||||
ret = i2c_bus_write_data(i2c_handler, pcm51xx_addr, data, 0);
|
||||
if (ret == ESP_OK) {
|
||||
ESP_LOGI(TAG, "Found a pcm51xx chip at address 0x%x", pcm51xx_addr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PCM51XX_ASSERT(ret, "Fail to detect pcm51xx PA", ESP_FAIL);
|
||||
ret |= pcm51xx_transmit_registers(
|
||||
pcm51xx_init_seq, sizeof(pcm51xx_init_seq) / sizeof(pcm51xx_init_seq[0]));
|
||||
|
||||
PCM51XX_ASSERT(ret, "Fail to iniitialize pcm51xx PA", ESP_FAIL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t pcm51xx_set_volume(int vol) {
|
||||
// vol is given as 1/2dB step with
|
||||
// 255: -inf (mute)
|
||||
// 254: -103dB
|
||||
// 48: 0dB
|
||||
// 0 (max): +24dB
|
||||
|
||||
if (vol < PCM51XX_VOLUME_MIN) {
|
||||
vol = PCM51XX_VOLUME_MIN;
|
||||
}
|
||||
if (vol > PCM51XX_VOLUME_MAX) {
|
||||
vol = PCM51XX_VOLUME_MAX;
|
||||
}
|
||||
uint8_t cmd[2] = {0, 0};
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
cmd[1] = vol;
|
||||
|
||||
cmd[0] = PCM51XX_REG_VOL_L;
|
||||
ret = i2c_bus_write_bytes(i2c_handler, pcm51xx_addr, &cmd[0], 1, &cmd[1], 1);
|
||||
cmd[0] = PCM51XX_REG_VOL_R;
|
||||
ret |= i2c_bus_write_bytes(i2c_handler, pcm51xx_addr, &cmd[0], 1, &cmd[1], 1);
|
||||
ESP_LOGW(TAG, "Volume set to 0x%x", cmd[1]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t pcm51xx_get_volume(int *value) {
|
||||
/// FIXME: Got the digit volume is not right.
|
||||
uint8_t cmd[2] = {PCM51XX_REG_VOL_L, 0x00};
|
||||
esp_err_t ret =
|
||||
i2c_bus_read_bytes(i2c_handler, pcm51xx_addr, &cmd[0], 1, &cmd[1], 1);
|
||||
PCM51XX_ASSERT(ret, "Fail to get volume", ESP_FAIL);
|
||||
ESP_LOGI(TAG, "Volume is %d", cmd[1]);
|
||||
*value = cmd[1];
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t pcm51xx_set_mute(bool enable) {
|
||||
esp_err_t ret = ESP_OK;
|
||||
uint8_t cmd[2] = {PCM51XX_REG_MUTE, 0x00};
|
||||
ret |= i2c_bus_read_bytes(i2c_handler, pcm51xx_addr, &cmd[0], 1, &cmd[1], 1);
|
||||
|
||||
if (enable) {
|
||||
cmd[1] |= 0x11;
|
||||
} else {
|
||||
cmd[1] &= (~0x11);
|
||||
}
|
||||
ret |= i2c_bus_write_bytes(i2c_handler, pcm51xx_addr, &cmd[0], 1, &cmd[1], 1);
|
||||
|
||||
PCM51XX_ASSERT(ret, "Fail to set mute", ESP_FAIL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t pcm51xx_get_mute(bool *enabled) {
|
||||
esp_err_t ret = ESP_OK;
|
||||
uint8_t cmd[2] = {PCM51XX_REG_MUTE, 0x00};
|
||||
ret |= i2c_bus_read_bytes(i2c_handler, pcm51xx_addr, &cmd[0], 1, &cmd[1], 1);
|
||||
|
||||
PCM51XX_ASSERT(ret, "Fail to get mute", ESP_FAIL);
|
||||
*enabled = (bool)(cmd[1] & 0x11);
|
||||
ESP_LOGI(TAG, "Get mute value: %s", *enabled ? "muted" : "unmuted");
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t pcm51xx_deinit(void) {
|
||||
// TODO
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t pcm51xx_ctrl(audio_hal_codec_mode_t mode,
|
||||
audio_hal_ctrl_t ctrl_state) {
|
||||
// TODO
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t pcm51xx_config_iface(audio_hal_codec_mode_t mode,
|
||||
audio_hal_codec_i2s_iface_t *iface) {
|
||||
// TODO
|
||||
return ESP_OK;
|
||||
}
|
||||
2
components/custom_driver/CMakeLists.txt
Normal file
2
components/custom_driver/CMakeLists.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
idf_component_register( SRCS "i2s.c"
|
||||
INCLUDE_DIRS "include")
|
||||
2
components/custom_driver/component.mk
Normal file
2
components/custom_driver/component.mk
Normal file
@@ -0,0 +1,2 @@
|
||||
COMPONENT_SRCDIRS := .
|
||||
# CFLAGS +=
|
||||
1161
components/custom_driver/i2s.c
Normal file
1161
components/custom_driver/i2s.c
Normal file
File diff suppressed because it is too large
Load Diff
302
components/custom_driver/include/i2s.h
Normal file
302
components/custom_driver/include/i2s.h
Normal file
@@ -0,0 +1,302 @@
|
||||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_types.h"
|
||||
#include "esp_err.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "soc/i2s_periph.h"
|
||||
#include "soc/rtc_periph.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "hal/i2s_hal.h"
|
||||
#include "hal/i2s_types.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define I2S_PIN_NO_CHANGE (-1) /*!< Use in i2s_pin_config_t for pins which should not be changed */
|
||||
|
||||
typedef intr_handle_t i2s_isr_handle_t;
|
||||
|
||||
/**
|
||||
* @brief Set I2S pin number
|
||||
*
|
||||
* @note
|
||||
* The I2S peripheral output signals can be connected to multiple GPIO pads.
|
||||
* However, the I2S peripheral input signal can only be connected to one GPIO pad.
|
||||
*
|
||||
* @param i2s_num I2S_NUM_0 or I2S_NUM_1
|
||||
*
|
||||
* @param pin I2S Pin structure, or NULL to set 2-channel 8-bit internal DAC pin configuration (GPIO25 & GPIO26)
|
||||
*
|
||||
* Inside the pin configuration structure, set I2S_PIN_NO_CHANGE for any pin where
|
||||
* the current configuration should not be changed.
|
||||
*
|
||||
* @note if *pin is set as NULL, this function will initialize both of the built-in DAC channels by default.
|
||||
* if you don't want this to happen and you want to initialize only one of the DAC channels, you can call i2s_set_dac_mode instead.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_FAIL IO error
|
||||
*/
|
||||
esp_err_t i2s_custom_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin);
|
||||
|
||||
#if SOC_I2S_SUPPORTS_PDM
|
||||
/**
|
||||
* @brief Set PDM mode down-sample rate
|
||||
* In PDM RX mode, there would be 2 rounds of downsample process in hardware.
|
||||
* In the first downsample process, the sampling number can be 16 or 8.
|
||||
* In the second downsample process, the sampling number is fixed as 8.
|
||||
* So the clock frequency in PDM RX mode would be (fpcm * 64) or (fpcm * 128) accordingly.
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
* @param dsr i2s RX down sample rate for PDM mode.
|
||||
*
|
||||
* @note After calling this function, it would call i2s_set_clk inside to update the clock frequency.
|
||||
* Please call this function after I2S driver has been initialized.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NO_MEM Out of memory
|
||||
*/
|
||||
esp_err_t i2s_custom_set_pdm_rx_down_sample(i2s_port_t i2s_num, i2s_pdm_dsr_t dsr);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Set I2S dac mode, I2S built-in DAC is disabled by default
|
||||
*
|
||||
* @param dac_mode DAC mode configurations - see i2s_dac_mode_t
|
||||
*
|
||||
* @note Built-in DAC functions are only supported on I2S0 for current ESP32 chip.
|
||||
* If either of the built-in DAC channel are enabled, the other one can not
|
||||
* be used as RTC DAC function at the same time.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t i2s_custom_set_dac_mode(i2s_dac_mode_t dac_mode);
|
||||
|
||||
/**
|
||||
* @brief Install and start I2S driver.
|
||||
*
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
*
|
||||
* @param i2s_config I2S configurations - see i2s_config_t struct
|
||||
*
|
||||
* @param queue_size I2S event queue size/depth.
|
||||
*
|
||||
* @param i2s_queue I2S event queue handle, if set NULL, driver will not use an event queue.
|
||||
*
|
||||
* This function must be called before any I2S driver read/write operations.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NO_MEM Out of memory
|
||||
*/
|
||||
esp_err_t i2s_custom_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, int queue_size, void* i2s_queue);
|
||||
|
||||
/**
|
||||
* @brief Uninstall I2S driver.
|
||||
*
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t i2s_custom_driver_uninstall(i2s_port_t i2s_num);
|
||||
|
||||
/**
|
||||
* @brief Write data to I2S DMA transmit buffer.
|
||||
*
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
*
|
||||
* @param src Source address to write from
|
||||
*
|
||||
* @param size Size of data in bytes
|
||||
*
|
||||
* @param[out] bytes_written Number of bytes written, if timeout, the result will be less than the size passed in.
|
||||
*
|
||||
* @param ticks_to_wait TX buffer wait timeout in RTOS ticks. If this
|
||||
* many ticks pass without space becoming available in the DMA
|
||||
* transmit buffer, then the function will return (note that if the
|
||||
* data is written to the DMA buffer in pieces, the overall operation
|
||||
* may still take longer than this timeout.) Pass portMAX_DELAY for no
|
||||
* timeout.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t i2s_custom_write(i2s_port_t i2s_num, const void *src, size_t size, size_t *bytes_written, TickType_t ticks_to_wait);
|
||||
|
||||
/**
|
||||
* @brief Write data to I2S DMA transmit buffer while expanding the number of bits per sample. For example, expanding 16-bit PCM to 32-bit PCM.
|
||||
*
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
*
|
||||
* @param src Source address to write from
|
||||
*
|
||||
* @param size Size of data in bytes
|
||||
*
|
||||
* @param src_bits Source audio bit
|
||||
*
|
||||
* @param aim_bits Bit wanted, no more than 32, and must be greater than src_bits
|
||||
*
|
||||
* @param[out] bytes_written Number of bytes written, if timeout, the result will be less than the size passed in.
|
||||
*
|
||||
* @param ticks_to_wait TX buffer wait timeout in RTOS ticks. If this
|
||||
* many ticks pass without space becoming available in the DMA
|
||||
* transmit buffer, then the function will return (note that if the
|
||||
* data is written to the DMA buffer in pieces, the overall operation
|
||||
* may still take longer than this timeout.) Pass portMAX_DELAY for no
|
||||
* timeout.
|
||||
*
|
||||
* Format of the data in source buffer is determined by the I2S
|
||||
* configuration (see i2s_config_t).
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t i2s_custom_write_expand(i2s_port_t i2s_num, const void *src, size_t size, size_t src_bits, size_t aim_bits, size_t *bytes_written, TickType_t ticks_to_wait);
|
||||
|
||||
/**
|
||||
* @brief Read data from I2S DMA receive buffer
|
||||
*
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
*
|
||||
* @param dest Destination address to read into
|
||||
*
|
||||
* @param size Size of data in bytes
|
||||
*
|
||||
* @param[out] bytes_read Number of bytes read, if timeout, bytes read will be less than the size passed in.
|
||||
*
|
||||
* @param ticks_to_wait RX buffer wait timeout in RTOS ticks. If this many ticks pass without bytes becoming available in the DMA receive buffer, then the function will return (note that if data is read from the DMA buffer in pieces, the overall operation may still take longer than this timeout.) Pass portMAX_DELAY for no timeout.
|
||||
*
|
||||
* @note If the built-in ADC mode is enabled, we should call i2s_adc_enable and i2s_adc_disable around the whole reading process,
|
||||
* to prevent the data getting corrupted.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t i2s_custom_read(i2s_port_t i2s_num, void *dest, size_t size, size_t *bytes_read, TickType_t ticks_to_wait);
|
||||
|
||||
/**
|
||||
* @brief Set sample rate used for I2S RX and TX.
|
||||
*
|
||||
* The bit clock rate is determined by the sample rate and i2s_config_t configuration parameters (number of channels, bits_per_sample).
|
||||
*
|
||||
* `bit_clock = rate * (number of channels) * bits_per_sample`
|
||||
*
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
*
|
||||
* @param rate I2S sample rate (ex: 8000, 44100...)
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NO_MEM Out of memory
|
||||
*/
|
||||
esp_err_t i2s_custom_set_sample_rates(i2s_port_t i2s_num, uint32_t rate);
|
||||
|
||||
/**
|
||||
* @brief Stop I2S driver
|
||||
*
|
||||
* There is no need to call i2s_stop() before calling i2s_driver_uninstall().
|
||||
*
|
||||
* Disables I2S TX/RX, until i2s_start() is called.
|
||||
*
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t i2s_custom_stop(i2s_port_t i2s_num);
|
||||
|
||||
/**
|
||||
* @brief Start I2S driver
|
||||
*
|
||||
* It is not necessary to call this function after i2s_driver_install() (it is started automatically), however it is necessary to call it after i2s_stop().
|
||||
*
|
||||
*
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t i2s_custom_start(i2s_port_t i2s_num);
|
||||
|
||||
/**
|
||||
* @brief Zero the contents of the TX DMA buffer.
|
||||
*
|
||||
* Pushes zero-byte samples into the TX DMA buffer, until it is full.
|
||||
*
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t i2s_custom_zero_dma_buffer(i2s_port_t i2s_num);
|
||||
|
||||
/**
|
||||
* @brief send all dma buffers, so they are available to i2s_custom_write() immediatly
|
||||
*/
|
||||
esp_err_t i2s_custom_init_dma_tx_queues(i2s_port_t i2s_num, uint8_t *data, size_t size, size_t *written);
|
||||
|
||||
/**
|
||||
* @brief Set clock & bit width used for I2S RX and TX.
|
||||
*
|
||||
* Similar to i2s_set_sample_rates(), but also sets bit width.
|
||||
*
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
*
|
||||
* @param rate I2S sample rate (ex: 8000, 44100...)
|
||||
*
|
||||
* @param bits I2S bit width (I2S_BITS_PER_SAMPLE_16BIT, I2S_BITS_PER_SAMPLE_24BIT, I2S_BITS_PER_SAMPLE_32BIT)
|
||||
*
|
||||
* @param ch I2S channel, (I2S_CHANNEL_MONO, I2S_CHANNEL_STEREO)
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NO_MEM Out of memory
|
||||
*/
|
||||
esp_err_t i2s_custom_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t bits, i2s_channel_t ch);
|
||||
|
||||
/**
|
||||
* @brief get clock set on particular port number.
|
||||
*
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
*
|
||||
* @return
|
||||
* - actual clock set by i2s driver
|
||||
*/
|
||||
float i2s_custom_get_clk(i2s_port_t i2s_num);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
10
components/dsp_processor/CMakeLists.txt
Normal file
10
components/dsp_processor/CMakeLists.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
set(COMPONENT_REQUIRES)
|
||||
set(COMPONENT_PRIV_REQUIRES audio_board audio_sal audio_hal esp-dsp)
|
||||
|
||||
list(APPEND COMPONENT_ADD_INCLUDEDIRS ./include)
|
||||
set(COMPONENT_SRCS ./dsp_processor.c)
|
||||
register_component()
|
||||
|
||||
# IDF >=4
|
||||
idf_component_get_property(audio_board_lib audio_board COMPONENT_LIB)
|
||||
set_property(TARGET ${audio_board_lib} APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${COMPONENT_LIB})
|
||||
47
components/dsp_processor/Kconfig.projbuild
Normal file
47
components/dsp_processor/Kconfig.projbuild
Normal file
@@ -0,0 +1,47 @@
|
||||
# Config file for ESP32 DSP Processor
|
||||
|
||||
menu "ESP32 audio buffer and I2S pin config"
|
||||
config USE_PSRAM
|
||||
bool "Use PSRAM"
|
||||
default true
|
||||
depends on ESP32_SPIRAM_SUPPORT
|
||||
help
|
||||
Need wrover class modules with large SPRAM to have required buffers for Snapcast network delay
|
||||
|
||||
config USE_DSP_PROCESSOR
|
||||
bool "enable signal processing on audio data"
|
||||
default false
|
||||
help
|
||||
enable audio filtering before queueing it to player component
|
||||
|
||||
config BITS_PER_SAMPLE
|
||||
int "bits per sample output to i2s driver"
|
||||
default 16
|
||||
help
|
||||
Select number of bits per sample for codec configured and connected to esp32 i2s dma hw
|
||||
|
||||
config CHANNELS
|
||||
int "number of channels per sample output to i2s driver"
|
||||
default 2
|
||||
help
|
||||
Select number of channels per sample for codec configured and connected to esp32 i2s dma hw
|
||||
|
||||
config PCM_SAMPLE_RATE
|
||||
int "sample rate of audio pcm data"
|
||||
default 48000
|
||||
help
|
||||
sample rate of audio data, currently only 48kHz is heavily tested and used during development
|
||||
|
||||
config WIRE_CHUNK_DURATION_MS
|
||||
int "wire chunk duration [ms]"
|
||||
default 20
|
||||
help
|
||||
pcm data is encoded in chunks of x ms, this value has to match snapserver configuration
|
||||
|
||||
config USE_BIQUAD_ASM
|
||||
bool "Use uptimized asm version of Biquad_f32"
|
||||
default true
|
||||
help
|
||||
Asm version 2 x speed on ESP32 - not working on ESP32-S2
|
||||
|
||||
endmenu
|
||||
11
components/dsp_processor/component.mk
Normal file
11
components/dsp_processor/component.mk
Normal file
@@ -0,0 +1,11 @@
|
||||
#
|
||||
# Main Makefile. This is basically the same as a component makefile.
|
||||
#
|
||||
# This Makefile should, at the very least, just include $(SDK_PATH)/make/component_common.mk. By default,
|
||||
# this will take the sources in the src/ directory, compile them and link them into
|
||||
# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
|
||||
# please read the ESP-IDF documents if you need to do this.
|
||||
#
|
||||
|
||||
COMPONENT_ADD_INLUCDEDIRS += ./include
|
||||
COMPONENT_SRCDIRS += ./dsp_processor.c
|
||||
361
components/dsp_processor/dsp_processor.c
Normal file
361
components/dsp_processor/dsp_processor.c
Normal file
@@ -0,0 +1,361 @@
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#if CONFIG_USE_DSP_PROCESSOR
|
||||
#include "freertos/ringbuf.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include "driver/i2s.h"
|
||||
#include "dsps_biquad.h"
|
||||
#include "dsps_biquad_gen.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
//#include "websocket_if.h"
|
||||
#include "driver/dac.h"
|
||||
#include "driver/i2s.h"
|
||||
#include "dsp_processor.h"
|
||||
#include "hal/i2s_hal.h"
|
||||
//#include "adc1_i2s_private.h"
|
||||
#include "board_pins_config.h"
|
||||
|
||||
#ifdef CONFIG_USE_BIQUAD_ASM
|
||||
#define BIQUAD dsps_biquad_f32_ae32
|
||||
#else
|
||||
#define BIQUAD dsps_biquad_f32
|
||||
#endif
|
||||
|
||||
static const char *TAG = "dspProc";
|
||||
|
||||
static const uint8_t chunkDurationMs = CONFIG_WIRE_CHUNK_DURATION_MS;
|
||||
static const uint32_t sampleRate = CONFIG_PCM_SAMPLE_RATE;
|
||||
//static const uint8_t channels = CONFIG_CHANNELS;
|
||||
//static const uint8_t bitsPerSample = CONFIG_BITS_PER_SAMPLE;
|
||||
|
||||
// TODO: allocate these buffers dynamically from heap
|
||||
static float *sbuffer0 = NULL;//[1024];
|
||||
//static float sbuffer1[1024];
|
||||
//static float sbuffer2[1024];
|
||||
static float *sbufout0 = NULL;//[1024];
|
||||
//static float sbufout1[1024];
|
||||
//static float sbufout2[1024];
|
||||
static float *sbuftmp0 = NULL;//[1024];
|
||||
//static uint8_t dsp_audio[4 * 1024];
|
||||
//static uint8_t dsp_audio1[4 * 1024];
|
||||
|
||||
extern uint8_t muteCH[4];
|
||||
|
||||
ptype_t bq[8];
|
||||
|
||||
|
||||
int dsp_processor(char *audio, size_t chunk_size, dspFlows_t dspFlow) {
|
||||
double dynamic_vol = 1.0;
|
||||
int16_t len = chunk_size / 4;
|
||||
int16_t valint;
|
||||
uint16_t i;
|
||||
|
||||
// ESP_LOGI(TAG,
|
||||
// "got data %p, %d, %u", audio, chunk_size, dspFlow);
|
||||
|
||||
if ((sbuffer0 == NULL) || (sbufout0 == NULL) || (sbuftmp0 == NULL)) {
|
||||
ESP_LOGE(
|
||||
TAG,
|
||||
"No Memory allocated for dsp_processor %p %p %p", sbuffer0, sbufout0, sbuftmp0);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
for (uint16_t i = 0; i < len; i++) {
|
||||
sbuffer0[i] =
|
||||
dynamic_vol * 0.5 *
|
||||
((float)((int16_t)(audio[i * 4 + 1] << 8) + audio[i * 4 + 0])) / 32768;
|
||||
sbuffer1[i] =
|
||||
dynamic_vol * 0.5 *
|
||||
((float)((int16_t)(audio[i * 4 + 3] << 8) + audio[i * 4 + 2])) / 32768;
|
||||
sbuffer2[i] = ((sbuffer0[i] / 2) + (sbuffer1[i] / 2));
|
||||
}
|
||||
*/
|
||||
|
||||
switch (dspFlow) {
|
||||
case dspfStereo: {
|
||||
// for (i = 0; i < len; i++) {
|
||||
// audio[i * 4 + 0] = (muteCH[0] == 1) ? 0 : audio[i * 4 + 0];
|
||||
// audio[i * 4 + 1] = (muteCH[0] == 1) ? 0 : audio[i * 4 + 1];
|
||||
// audio[i * 4 + 2] = (muteCH[1] == 1) ? 0 : audio[i * 4 + 2];
|
||||
// audio[i * 4 + 3] = (muteCH[1] == 1) ? 0 : audio[i * 4 + 3];
|
||||
// }
|
||||
|
||||
// mute is done through audio_hal_set_mute()
|
||||
} break;
|
||||
|
||||
case dspfBassBoost: { // CH0 low shelf 6dB @ 400Hz
|
||||
// channel 0
|
||||
for (i = 0; i < len; i++) {
|
||||
sbuffer0[i] =
|
||||
dynamic_vol * 0.5 *
|
||||
((float)((int16_t)(audio[i * 4 + 1] << 8) + audio[i * 4 + 0])) / 32768;
|
||||
}
|
||||
BIQUAD(sbuffer0, sbufout0, len, bq[6].coeffs, bq[6].w);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
valint = (int16_t)(sbufout0[i] * 32768);
|
||||
|
||||
audio[i * 4 + 0] = (valint & 0x00ff);
|
||||
audio[i * 4 + 1] = ((valint & 0xff00) >> 8);
|
||||
}
|
||||
|
||||
// channel 1
|
||||
for (i = 0; i < len; i++) {
|
||||
sbuffer0[i] =
|
||||
dynamic_vol * 0.5 *
|
||||
((float)((int16_t)(audio[i * 4 + 3] << 8) + audio[i * 4 + 2])) / 32768;
|
||||
}
|
||||
BIQUAD(sbuffer0, sbufout0, len, bq[7].coeffs, bq[7].w);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
valint = (int16_t)(sbufout0[i] * 32768);
|
||||
audio[i * 4 + 2] = (valint & 0x00ff);
|
||||
audio[i * 4 + 3] = ((valint & 0xff00) >> 8);
|
||||
}
|
||||
|
||||
} break;
|
||||
|
||||
case dspfBiamp: {
|
||||
// Process audio ch0 LOW PASS FILTER
|
||||
for (i = 0; i < len; i++) {
|
||||
sbuffer0[i] =
|
||||
dynamic_vol * 0.5 *
|
||||
((float)((int16_t)(audio[i * 4 + 1] << 8) + audio[i * 4 + 0])) / 32768;
|
||||
}
|
||||
BIQUAD(sbuffer0, sbuftmp0, len, bq[0].coeffs, bq[0].w);
|
||||
BIQUAD(sbuftmp0, sbufout0, len, bq[1].coeffs, bq[1].w);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
valint = (int16_t)(sbufout0[i] * 32768);
|
||||
audio[i * 4 + 0] = (valint & 0x00ff);
|
||||
audio[i * 4 + 1] = ((valint & 0xff00) >> 8);
|
||||
}
|
||||
|
||||
// Process audio ch1 HIGH PASS FILTER
|
||||
for (i = 0; i < len; i++) {
|
||||
sbuffer0[i] =
|
||||
dynamic_vol * 0.5 *
|
||||
((float)((int16_t)(audio[i * 4 + 3] << 8) + audio[i * 4 + 2])) / 32768;
|
||||
}
|
||||
BIQUAD(sbuffer0, sbuftmp0, len, bq[2].coeffs, bq[2].w);
|
||||
BIQUAD(sbuftmp0, sbufout0, len, bq[3].coeffs, bq[3].w);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
valint = (int16_t)(sbufout0[i] * 32768);
|
||||
audio[i * 4 + 2] = (valint & 0x00ff);
|
||||
audio[i * 4 + 3] = ((valint & 0xff00) >> 8);
|
||||
}
|
||||
|
||||
} break;
|
||||
|
||||
case dspf2DOT1: { // Process audio L + R LOW PASS FILTER
|
||||
/*
|
||||
BIQUAD(sbuffer2, sbuftmp0, len, bq[0].coeffs, bq[0].w);
|
||||
BIQUAD(sbuftmp0, sbufout2, len, bq[1].coeffs, bq[1].w);
|
||||
|
||||
// Process audio L HIGH PASS FILTER
|
||||
BIQUAD(sbuffer0, sbuftmp0, len, bq[2].coeffs, bq[2].w);
|
||||
BIQUAD(sbuftmp0, sbufout0, len, bq[3].coeffs, bq[3].w);
|
||||
|
||||
// Process audio R HIGH PASS FILTER
|
||||
BIQUAD(sbuffer1, sbuftmp0, len, bq[4].coeffs, bq[4].w);
|
||||
BIQUAD(sbuftmp0, sbufout1, len, bq[5].coeffs, bq[5].w);
|
||||
|
||||
int16_t valint[5];
|
||||
for (uint16_t i = 0; i < len; i++) {
|
||||
valint[0] =
|
||||
(muteCH[0] == 1) ? (int16_t)0 : (int16_t)(sbufout0[i] * 32768);
|
||||
valint[1] =
|
||||
(muteCH[1] == 1) ? (int16_t)0 : (int16_t)(sbufout1[i] * 32768);
|
||||
valint[2] =
|
||||
(muteCH[2] == 1) ? (int16_t)0 : (int16_t)(sbufout2[i] * 32768);
|
||||
dsp_audio[i * 4 + 0] = (valint[2] & 0xff);
|
||||
dsp_audio[i * 4 + 1] = ((valint[2] & 0xff00) >> 8);
|
||||
dsp_audio[i * 4 + 2] = 0;
|
||||
dsp_audio[i * 4 + 3] = 0;
|
||||
|
||||
dsp_audio1[i * 4 + 0] = (valint[0] & 0xff);
|
||||
dsp_audio1[i * 4 + 1] = ((valint[0] & 0xff00) >> 8);
|
||||
dsp_audio1[i * 4 + 2] = (valint[1] & 0xff);
|
||||
dsp_audio1[i * 4 + 3] = ((valint[1] & 0xff00) >> 8);
|
||||
}
|
||||
|
||||
// TODO: this copy could be avoided if dsp_audio buffers are
|
||||
// allocated dynamically and pointers are exchanged after
|
||||
// audio was freed
|
||||
memcpy(audio, dsp_audio, chunk_size);
|
||||
|
||||
ESP_LOGW(TAG, "Don't know what to do with dsp_audio1");
|
||||
*/
|
||||
ESP_LOGW(TAG, "dspf2DOT1, not implemented yet, using stereo instead");
|
||||
} break;
|
||||
|
||||
case dspfFunkyHonda: { // Process audio L + R LOW PASS FILTER
|
||||
/*
|
||||
BIQUAD(sbuffer2, sbuftmp0, len, bq[0].coeffs, bq[0].w);
|
||||
BIQUAD(sbuftmp0, sbufout2, len, bq[1].coeffs, bq[1].w);
|
||||
|
||||
// Process audio L HIGH PASS FILTER
|
||||
BIQUAD(sbuffer0, sbuftmp0, len, bq[2].coeffs, bq[2].w);
|
||||
BIQUAD(sbuftmp0, sbufout0, len, bq[3].coeffs, bq[3].w);
|
||||
|
||||
// Process audio R HIGH PASS FILTER
|
||||
BIQUAD(sbuffer1, sbuftmp0, len, bq[4].coeffs, bq[4].w);
|
||||
BIQUAD(sbuftmp0, sbufout1, len, bq[5].coeffs, bq[5].w);
|
||||
|
||||
uint16_t scale = 16384; // 32768
|
||||
int16_t valint[5];
|
||||
for (uint16_t i = 0; i < len; i++) {
|
||||
valint[0] =
|
||||
(muteCH[0] == 1) ? (int16_t)0 : (int16_t)(sbufout0[i] * scale);
|
||||
valint[1] =
|
||||
(muteCH[1] == 1) ? (int16_t)0 : (int16_t)(sbufout1[i] * scale);
|
||||
valint[2] =
|
||||
(muteCH[2] == 1) ? (int16_t)0 : (int16_t)(sbufout2[i] * scale);
|
||||
valint[3] = valint[0] + valint[2];
|
||||
valint[4] = -valint[2];
|
||||
valint[5] = -valint[1] - valint[2];
|
||||
dsp_audio[i * 4 + 0] = (valint[3] & 0xff);
|
||||
dsp_audio[i * 4 + 1] = ((valint[3] & 0xff00) >> 8);
|
||||
dsp_audio[i * 4 + 2] = (valint[2] & 0xff);
|
||||
dsp_audio[i * 4 + 3] = ((valint[2] & 0xff00) >> 8);
|
||||
|
||||
dsp_audio1[i * 4 + 0] = (valint[4] & 0xff);
|
||||
dsp_audio1[i * 4 + 1] = ((valint[4] & 0xff00) >> 8);
|
||||
dsp_audio1[i * 4 + 2] = (valint[5] & 0xff);
|
||||
dsp_audio1[i * 4 + 3] = ((valint[5] & 0xff00) >> 8);
|
||||
}
|
||||
|
||||
// TODO: this copy could be avoided if dsp_audio buffers are
|
||||
// allocated dynamically and pointers are exchanged after
|
||||
// audio was freed
|
||||
memcpy(audio, dsp_audio, chunk_size);
|
||||
|
||||
ESP_LOGW(TAG, "Don't know what to do with dsp_audio1");
|
||||
*/
|
||||
ESP_LOGW(TAG, "dspfFunkyHonda, not implemented yet, using stereo instead");
|
||||
|
||||
} break;
|
||||
|
||||
default: { } break; }
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ESP32 DSP processor
|
||||
//======================================================
|
||||
// Each time a buffer of audio is passed to the DSP - samples are
|
||||
// processed according to a dynamic list of audio processing nodes.
|
||||
|
||||
// Each audio processor node consist of a data struct holding the
|
||||
// required weights and states for processing an automomous processing
|
||||
// function. The high level parameters is maintained in the structure
|
||||
// as well
|
||||
|
||||
// Release - Prove off concept
|
||||
// ----------------------------------------
|
||||
// Fixed 2x2 biquad flow Xover for biAmp systems
|
||||
// Interface for cross over frequency and level
|
||||
|
||||
void dsp_setup_flow(double freq, uint32_t samplerate) {
|
||||
float f = freq / samplerate / 2.0;
|
||||
uint16_t len = (sampleRate * chunkDurationMs / 1000);
|
||||
|
||||
bq[0] = (ptype_t){LPF, f, 0, 0.707, NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}};
|
||||
bq[1] = (ptype_t){LPF, f, 0, 0.707, NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}};
|
||||
bq[2] = (ptype_t){HPF, f, 0, 0.707, NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}};
|
||||
bq[3] = (ptype_t){HPF, f, 0, 0.707, NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}};
|
||||
bq[4] = (ptype_t){HPF, f, 0, 0.707, NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}};
|
||||
bq[5] = (ptype_t){HPF, f, 0, 0.707, NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}};
|
||||
bq[6] = (ptype_t){LOWSHELF, f, 6, 0.707, NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}};
|
||||
bq[7] = (ptype_t){LOWSHELF, f, 6, 0.707, NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}};
|
||||
|
||||
pnode_t *aflow = NULL;
|
||||
aflow = malloc(sizeof(pnode_t));
|
||||
if (aflow == NULL) {
|
||||
printf("Could not create node");
|
||||
}
|
||||
|
||||
for (uint8_t n = 0; n <= 7; n++) {
|
||||
switch (bq[n].filtertype) {
|
||||
case LOWSHELF:
|
||||
dsps_biquad_gen_lowShelf_f32(bq[n].coeffs, bq[n].freq, bq[n].gain,
|
||||
bq[n].q);
|
||||
break;
|
||||
case LPF:
|
||||
dsps_biquad_gen_lpf_f32(bq[n].coeffs, bq[n].freq, bq[n].q);
|
||||
break;
|
||||
case HPF:
|
||||
dsps_biquad_gen_hpf_f32(bq[n].coeffs, bq[n].freq, bq[n].q);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// for (uint8_t i = 0; i <= 4; i++) {
|
||||
// printf("%.6f ", bq[n].coeffs[i]);
|
||||
// }
|
||||
// printf("\n");
|
||||
}
|
||||
|
||||
|
||||
sbuffer0 = (float *)heap_caps_malloc(sizeof(float) * len, MALLOC_CAP_8BIT);
|
||||
sbufout0 = (float *)heap_caps_malloc(sizeof(float) * len, MALLOC_CAP_8BIT);
|
||||
sbuftmp0 = (float *)heap_caps_malloc(sizeof(float) * len, MALLOC_CAP_8BIT);
|
||||
if ((sbuffer0 == NULL) || (sbufout0 == NULL) || (sbuftmp0 == NULL)) {
|
||||
ESP_LOGE(
|
||||
TAG,
|
||||
"Failed to allocate initial memory for dsp_processor %p %p %p", sbuffer0, sbufout0, sbuftmp0);
|
||||
|
||||
if (sbuffer0) {
|
||||
free(sbuffer0);
|
||||
}
|
||||
if (sbufout0) {
|
||||
free(sbufout0);
|
||||
}
|
||||
if (sbuftmp0) {
|
||||
free(sbuftmp0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ESP_LOGI(
|
||||
TAG,
|
||||
"GOT memory for dsp_processor %p %p", sbuffer0, sbufout0);
|
||||
}
|
||||
}
|
||||
|
||||
void dsp_set_xoverfreq(uint8_t freqh, uint8_t freql, uint32_t samplerate) {
|
||||
float freq = freqh * 256 + freql;
|
||||
// printf("%f\n", freq);
|
||||
float f = freq / samplerate / 2.;
|
||||
for (int8_t n = 0; n <= 5; n++) {
|
||||
bq[n].freq = f;
|
||||
switch (bq[n].filtertype) {
|
||||
case LPF:
|
||||
// for (uint8_t i = 0; i <= 4; i++) {
|
||||
// printf("%.6f ", bq[n].coeffs[i]);
|
||||
// }
|
||||
// printf("\n");
|
||||
dsps_biquad_gen_lpf_f32(bq[n].coeffs, bq[n].freq, bq[n].q);
|
||||
// for (uint8_t i = 0; i <= 4; i++) {
|
||||
// printf("%.6f ", bq[n].coeffs[i]);
|
||||
// }
|
||||
// printf("%f \n", bq[n].freq);
|
||||
break;
|
||||
case HPF:
|
||||
dsps_biquad_gen_hpf_f32(bq[n].coeffs, bq[n].freq, bq[n].q);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
46
components/dsp_processor/include/dsp_processor.h
Normal file
46
components/dsp_processor/include/dsp_processor.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#ifndef _DSP_PROCESSOR_H_
|
||||
#define _DSP_PROCESSOR_H_
|
||||
|
||||
typedef enum dspFlows {
|
||||
dspfStereo,
|
||||
dspfBiamp,
|
||||
dspf2DOT1,
|
||||
dspfFunkyHonda,
|
||||
dspfBassBoost
|
||||
} dspFlows_t;
|
||||
|
||||
enum filtertypes {
|
||||
LPF,
|
||||
HPF,
|
||||
BPF,
|
||||
BPF0DB,
|
||||
NOTCH,
|
||||
ALLPASS360,
|
||||
ALLPASS180,
|
||||
PEAKINGEQ,
|
||||
LOWSHELF,
|
||||
HIGHSHELF
|
||||
};
|
||||
|
||||
// Process node
|
||||
typedef struct ptype {
|
||||
int filtertype;
|
||||
float freq;
|
||||
float gain;
|
||||
float q;
|
||||
float *in, *out;
|
||||
float coeffs[5];
|
||||
float w[2];
|
||||
} ptype_t;
|
||||
|
||||
// Process flow
|
||||
typedef struct pnode {
|
||||
ptype_t process;
|
||||
struct pnode *next;
|
||||
} pnode_t;
|
||||
|
||||
void dsp_setup_flow(double freq, uint32_t samplerate);
|
||||
int dsp_processor(char *audio, size_t chunk_size, dspFlows_t dspFlow);
|
||||
void dsp_set_xoverfreq(uint8_t, uint8_t, uint32_t);
|
||||
|
||||
#endif /* _DSP_PROCESSOR_H_ */
|
||||
54
components/esp-dsp/.gitignore
vendored
Normal file
54
components/esp-dsp/.gitignore
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
.config
|
||||
*.o
|
||||
*.pyc
|
||||
|
||||
# gtags
|
||||
GTAGS
|
||||
GRTAGS
|
||||
GPATH
|
||||
|
||||
# emacs
|
||||
.dir-locals.el
|
||||
|
||||
# emacs temp file suffixes
|
||||
*~
|
||||
.#*
|
||||
\#*#
|
||||
|
||||
# eclipse setting
|
||||
.settings
|
||||
|
||||
# MacOS directory files
|
||||
.DS_Store
|
||||
|
||||
# Example project files
|
||||
examples/**/sdkconfig
|
||||
examples/**/sdkconfig.old
|
||||
examples/**/build
|
||||
|
||||
# Test app files
|
||||
test_app/build
|
||||
test_app/sdkconfig
|
||||
test_app/sdkconfig.old
|
||||
|
||||
# Doc build artifacts
|
||||
docs/_build/
|
||||
docs/doxygen-warning-log.txt
|
||||
docs/sphinx-warning-log.txt
|
||||
docs/sphinx-warning-log-sanitized.txt
|
||||
docs/xml/
|
||||
docs/xml_in/
|
||||
docs/man/
|
||||
docs/doxygen_sqlite3.db
|
||||
|
||||
TEST_LOGS
|
||||
|
||||
|
||||
# gcov coverage reports
|
||||
*.gcda
|
||||
*.gcno
|
||||
coverage.info
|
||||
coverage_report/
|
||||
|
||||
# VS Code Settings
|
||||
.vscode/
|
||||
98
components/esp-dsp/.gitlab-ci.yml
Normal file
98
components/esp-dsp/.gitlab-ci.yml
Normal file
@@ -0,0 +1,98 @@
|
||||
stages:
|
||||
- build
|
||||
- deploy
|
||||
|
||||
image: $CI_DOCKER_REGISTRY/esp32-ci-env:latest
|
||||
|
||||
variables:
|
||||
# System environment
|
||||
|
||||
# Common parameters for the 'make' during CI tests
|
||||
MAKEFLAGS: "-j5 --no-keep-going"
|
||||
|
||||
# GitLab-CI environment
|
||||
GET_SOURCES_ATTEMPTS: "10"
|
||||
ARTIFACT_DOWNLOAD_ATTEMPTS: "10"
|
||||
GIT_SUBMODULE_STRATEGY: none
|
||||
|
||||
ESP_IDF_GIT: "https://gitlab-ci-token:${CI_JOB_TOKEN}@${GITLAB_HTTPS_SERVER}/espressif/esp-idf.git"
|
||||
|
||||
.setup_idf_tools: &setup_idf_tools |
|
||||
tools/idf_tools.py --non-interactive install && eval "$(tools/idf_tools.py --non-interactive export)" || exit 1
|
||||
|
||||
.add_gh_key_remote: &add_gh_key_remote |
|
||||
command -v ssh-agent >/dev/null || exit 1
|
||||
eval $(ssh-agent -s)
|
||||
printf '%s\n' "${GH_PUSH_KEY}" | tr -d '\r' | ssh-add - > /dev/null
|
||||
mkdir -p ~/.ssh && chmod 700 ~/.ssh
|
||||
[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config || ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts
|
||||
git remote remove github || true
|
||||
git remote add github ${GH_PUSH_REPO}
|
||||
|
||||
after_script:
|
||||
# Just for cleaning space, no other causes
|
||||
- git clean -ffdx
|
||||
|
||||
build:
|
||||
stage: build
|
||||
tags:
|
||||
- build
|
||||
script:
|
||||
# Get ESP-IDF
|
||||
- git clone ${ESP_IDF_GIT} esp-idf
|
||||
- pushd esp-idf
|
||||
# Non-recursive getting its submodules
|
||||
- git submodule update --init
|
||||
- export IDF_PATH=$PWD
|
||||
- *setup_idf_tools
|
||||
- popd
|
||||
|
||||
# Create a copy of the project in "esp-dsp" directory.
|
||||
# This is needed because CMake build system can not build a component
|
||||
# when ESP-IDF directory is inside the component.
|
||||
# After cloning, we will have two directories at the same level: "esp-idf" and "esp-dsp"
|
||||
- git clone $PWD esp-dsp
|
||||
- cd esp-dsp
|
||||
|
||||
# Build test app by both Makefiles and CMake ways
|
||||
- pushd test_app
|
||||
- make defconfig && make
|
||||
- rm -rf build
|
||||
- idf.py build
|
||||
- popd
|
||||
|
||||
# Build examples
|
||||
- ./build_examples.sh
|
||||
|
||||
build_docs:
|
||||
stage: build
|
||||
tags:
|
||||
- build_docs
|
||||
artifacts:
|
||||
when: always
|
||||
paths:
|
||||
- docs/doxygen-warning-log.txt
|
||||
- docs/sphinx-warning-log.txt
|
||||
- docs/_build/html
|
||||
expire_in: 1 day
|
||||
# No cleaning when the artifacts
|
||||
after_script: []
|
||||
script:
|
||||
- cd docs
|
||||
- make html
|
||||
- ./check_doc_warnings.sh
|
||||
|
||||
push_master_to_github:
|
||||
stage: deploy
|
||||
tags:
|
||||
- deploy
|
||||
only:
|
||||
- master
|
||||
- /^release\/v/
|
||||
- /^v\d+\.\d+(\.\d+)?($|-)/
|
||||
when: on_success
|
||||
script:
|
||||
# Just for a helper script
|
||||
- git clone --depth 1 ${ESP_IDF_GIT} esp-idf
|
||||
- *add_gh_key_remote
|
||||
- esp-idf/tools/ci/push_to_github.sh
|
||||
108
components/esp-dsp/CMakeLists.txt
Normal file
108
components/esp-dsp/CMakeLists.txt
Normal file
@@ -0,0 +1,108 @@
|
||||
set(COMPONENT_SRCS "modules/common/misc/dsps_pwroftwo.cpp"
|
||||
"modules/dotprod/float/dsps_dotprod_f32_ae32.S"
|
||||
"modules/dotprod/float/dsps_dotprod_f32_m_ae32.S"
|
||||
"modules/dotprod/float/dsps_dotprode_f32_ae32.S"
|
||||
"modules/dotprod/float/dsps_dotprode_f32_m_ae32.S"
|
||||
"modules/dotprod/float/dsps_dotprod_f32_ansi.c"
|
||||
"modules/dotprod/float/dsps_dotprode_f32_ansi.c"
|
||||
"modules/dotprod/fixed/dsps_dotprod_s16_ae32.S"
|
||||
"modules/dotprod/fixed/dsps_dotprod_s16_m_ae32.S"
|
||||
"modules/dotprod/fixed/dsps_dotprod_s16_ansi.c"
|
||||
"modules/matrix/float/dspm_mult_3x3x1_f32_ae32.S"
|
||||
"modules/matrix/float/dspm_mult_3x3x3_f32_ae32.S"
|
||||
"modules/matrix/float/dspm_mult_4x4x1_f32_ae32.S"
|
||||
"modules/matrix/float/dspm_mult_4x4x4_f32_ae32.S"
|
||||
"modules/matrix/float/dspm_mult_f32_ae32.S"
|
||||
"modules/matrix/float/dspm_mult_f32_ansi.c"
|
||||
"modules/matrix/fixed/dspm_mult_s16_ae32.S"
|
||||
"modules/matrix/fixed/dspm_mult_s16_m_ae32_vector.S"
|
||||
"modules/matrix/fixed/dspm_mult_s16_m_ae32.S"
|
||||
"modules/matrix/fixed/dspm_mult_s16_ansi.c"
|
||||
"modules/matrix/mat/mat.cpp"
|
||||
"modules/math/mulc/float/dsps_mulc_f32_ansi.c"
|
||||
"modules/math/addc/float/dsps_addc_f32_ansi.c"
|
||||
"modules/math/mulc/fixed/dsps_mulc_s16_ansi.c"
|
||||
"modules/math/mulc/fixed/dsps_mulc_s16_ae32.S"
|
||||
"modules/math/add/float/dsps_add_f32_ansi.c"
|
||||
"modules/math/add/fixed/dsps_add_s16_ansi.c"
|
||||
"modules/math/add/fixed/dsps_add_s16_ae32.S"
|
||||
"modules/math/sub/float/dsps_sub_f32_ansi.c"
|
||||
"modules/math/mul/float/dsps_mul_f32_ansi.c"
|
||||
"modules/math/mul/fixed/dsps_mul_s16_ansi.c"
|
||||
"modules/math/mulc/float/dsps_mulc_f32_ae32.S"
|
||||
"modules/math/addc/float/dsps_addc_f32_ae32.S"
|
||||
"modules/math/add/float/dsps_add_f32_ae32.S"
|
||||
"modules/math/sub/float/dsps_sub_f32_ae32.S"
|
||||
"modules/math/mul/float/dsps_mul_f32_ae32.S"
|
||||
"modules/math/sqrt/float/dsps_sqrt_f32_ansi.c"
|
||||
|
||||
"modules/fft/float/dsps_fft2r_fc32_ae32_.S"
|
||||
"modules/fft/float/dsps_fft2r_fc32_ansi.c"
|
||||
"modules/fft/float/dsps_fft2r_fc32_ae32.c"
|
||||
"modules/fft/float/dsps_fft4r_fc32_ansi.c"
|
||||
"modules/fft/float/dsps_fft4r_fc32_ae32.c"
|
||||
"modules/fft/float/dsps_fft2r_bitrev_tables_fc32.c"
|
||||
"modules/fft/float/dsps_fft4r_bitrev_tables_fc32.c"
|
||||
"modules/fft/fixed/dsps_fft2r_sc16_ae32.S"
|
||||
"modules/fft/fixed/dsps_fft2r_sc16_ansi.c"
|
||||
|
||||
"modules/dct/float/dsps_dct_f32.c"
|
||||
"modules/support/snr/float/dsps_snr_f32.cpp"
|
||||
"modules/support/sfdr/float/dsps_sfdr_f32.cpp"
|
||||
"modules/support/misc/dsps_d_gen.c"
|
||||
"modules/support/misc/dsps_h_gen.c"
|
||||
"modules/support/misc/dsps_tone_gen.c"
|
||||
"modules/support/view/dsps_view.cpp"
|
||||
"modules/windows/hann/float/dsps_wind_hann_f32.c"
|
||||
"modules/windows/blackman/float/dsps_wind_blackman_f32.c"
|
||||
"modules/windows/blackman_harris/float/dsps_wind_blackman_harris_f32.c"
|
||||
"modules/windows/blackman_nuttall/float/dsps_wind_blackman_nuttall_f32.c"
|
||||
"modules/windows/nuttall/float/dsps_wind_nuttall_f32.c"
|
||||
"modules/windows/flat_top/float/dsps_wind_flat_top_f32.c"
|
||||
"modules/conv/float/dsps_conv_f32_ansi.c"
|
||||
"modules/conv/float/dsps_conv_f32_ae32.S"
|
||||
"modules/conv/float/dsps_corr_f32_ansi.c"
|
||||
"modules/conv/float/dsps_corr_f32_ae32.S"
|
||||
"modules/conv/float/dsps_ccorr_f32_ansi.c"
|
||||
"modules/conv/float/dsps_ccorr_f32_ae32.S"
|
||||
"modules/iir/biquad/dsps_biquad_f32_ae32.S"
|
||||
"modules/iir/biquad/dsps_biquad_f32_ansi.c"
|
||||
"modules/iir/biquad/dsps_biquad_gen_f32.c"
|
||||
"modules/fir/float/dsps_fir_f32_ae32.S"
|
||||
"modules/fir/float/dsps_fird_f32_ae32.S"
|
||||
"modules/fir/float/dsps_fir_f32_ansi.c"
|
||||
"modules/fir/float/dsps_fir_init_f32.c"
|
||||
"modules/fir/float/dsps_fird_f32_ansi.c"
|
||||
"modules/fir/float/dsps_fird_init_f32.c")
|
||||
|
||||
set(COMPONENT_ADD_INCLUDEDIRS "modules/dotprod/include"
|
||||
"modules/support/include"
|
||||
"modules/windows/include"
|
||||
"modules/windows/hann/include"
|
||||
"modules/windows/blackman/include"
|
||||
"modules/windows/blackman_harris/include"
|
||||
"modules/windows/blackman_nuttall/include"
|
||||
"modules/windows/nuttall/include"
|
||||
"modules/windows/flat_top/include"
|
||||
"modules/iir/include"
|
||||
"modules/fir/include"
|
||||
"modules/math/include"
|
||||
"modules/math/add/include"
|
||||
"modules/math/sub/include"
|
||||
"modules/math/mul/include"
|
||||
"modules/math/addc/include"
|
||||
"modules/math/mulc/include"
|
||||
"modules/math/sqrt/include"
|
||||
"modules/matrix/include"
|
||||
"modules/fft/include"
|
||||
"modules/dct/include"
|
||||
"modules/conv/include"
|
||||
"modules/common/include")
|
||||
|
||||
set(COMPONENT_PRIV_INCLUDEDIRS "modules/dotprod/float"
|
||||
"modules/dotprod/fixed"
|
||||
"modules/common/private_include")
|
||||
|
||||
register_component()
|
||||
|
||||
#component_compile_options(-ffast-math -O2 -Wno-error=maybe-uninitialized)
|
||||
53
components/esp-dsp/Kconfig
Normal file
53
components/esp-dsp/Kconfig
Normal file
@@ -0,0 +1,53 @@
|
||||
menu "DSP Library"
|
||||
|
||||
|
||||
choice DSP_OPTIMIZATION
|
||||
bool "DSP Optimization for ESP32"
|
||||
default DSP_OPTIMIZED
|
||||
help
|
||||
An Ansi C version could be used for verification and debug purpose.
|
||||
|
||||
config DSP_ANSI
|
||||
bool "ANSI C"
|
||||
config DSP_OPTIMIZED
|
||||
bool "ESP32 Optimized"
|
||||
endchoice
|
||||
|
||||
config DSP_OPTIMIZATION
|
||||
int
|
||||
default 0 if DSP_ANSI
|
||||
default 1 if DSP_OPTIMIZED
|
||||
|
||||
choice DSP_MAX_FFT_SIZE
|
||||
bool "Maximum FFT length"
|
||||
default DSP_MAX_FFT_SIZE_4096
|
||||
help
|
||||
This is default FFT size for internal usage.
|
||||
|
||||
config DSP_MAX_FFT_SIZE_512
|
||||
bool "512"
|
||||
config DSP_MAX_FFT_SIZE_1024
|
||||
bool "1024"
|
||||
config DSP_MAX_FFT_SIZE_2048
|
||||
bool "2048"
|
||||
config DSP_MAX_FFT_SIZE_4096
|
||||
bool "4096"
|
||||
config DSP_MAX_FFT_SIZE_8192
|
||||
bool "8192"
|
||||
config DSP_MAX_FFT_SIZE_16384
|
||||
bool "16384"
|
||||
config DSP_MAX_FFT_SIZE_32768
|
||||
bool "32768"
|
||||
endchoice
|
||||
|
||||
config DSP_MAX_FFT_SIZE
|
||||
int
|
||||
default 512 if DSP_MAX_FFT_SIZE_512
|
||||
default 1024 if DSP_MAX_FFT_SIZE_1024
|
||||
default 2048 if DSP_MAX_FFT_SIZE_2048
|
||||
default 4096 if DSP_MAX_FFT_SIZE_4096
|
||||
default 8192 if DSP_MAX_FFT_SIZE_8192
|
||||
default 16384 if DSP_MAX_FFT_SIZE_16384
|
||||
default 32768 if DSP_MAX_FFT_SIZE_32768
|
||||
|
||||
endmenu
|
||||
202
components/esp-dsp/LICENSE
Normal file
202
components/esp-dsp/LICENSE
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
||||
71
components/esp-dsp/README.md
Normal file
71
components/esp-dsp/README.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# Espressif DSP Library
|
||||
|
||||
ESP-DSP is the official DSP library for the [ESP32](https://espressif.com/en/products/hardware/esp32/overview) chip.
|
||||
|
||||
## Overview
|
||||
|
||||
ESP-DSP is intended to be used as an [ESP-IDF](https://github.com/espressif/esp-idf) component. For the introduction to ESP-IDF, refer to the [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/).
|
||||
|
||||
The ESP-DSP library includes implementations of the following functions:
|
||||
- Matrix multiplication: [reference](https://docs.espressif.com/projects/esp-dsp/en/latest/esp-dsp-apis.html#matrix-operations-apis)
|
||||
- Dot product: [reference](https://docs.espressif.com/projects/esp-dsp/en/latest/esp-dsp-apis.html#dot-product), [example](https://github.com/espressif/esp-dsp/tree/master/examples/dotprod)
|
||||
- FFT: [reference](https://docs.espressif.com/projects/esp-dsp/en/latest/esp-dsp-apis.html#fft), [example](https://github.com/espressif/esp-dsp/tree/master/examples/fft)
|
||||
- IIR: [reference](https://docs.espressif.com/projects/esp-dsp/en/latest/esp-dsp-apis.html#iir), [example](https://github.com/espressif/esp-dsp/tree/master/examples/iir)
|
||||
- FIR: [reference](https://docs.espressif.com/projects/esp-dsp/en/latest/esp-dsp-apis.html#fir)
|
||||
- Vector math operations: [reference](https://docs.espressif.com/projects/esp-dsp/en/latest/esp-dsp-apis.html#math)
|
||||
|
||||
Many of the library functions are written in assembly and are optimized for the CPU configuration used in the ESP32. In addition to the optimized implementations, reference implementations written in ANSI C are provided.
|
||||
|
||||
Function implementations are provided for single precision floating point (32-bit float), and 16-bit signed integers.
|
||||
|
||||
## Documentation
|
||||
|
||||
- [ESP-DSP Overview](https://docs.espressif.com/projects/esp-dsp/en/latest/esp-dsp-library.html)
|
||||
- [ESP-DSP API Reference](https://docs.espressif.com/projects/esp-dsp/en/latest/esp-dsp-apis.html)
|
||||
- [ESP-DSP Benchmarks](https://docs.espressif.com/projects/esp-dsp/en/latest/esp-dsp-benchmarks.html)
|
||||
|
||||
Documentation found in the above links is automatically generated from the contents of this repository. If you find that some information is missing or incomplete, please report an issue.
|
||||
|
||||
## Installation and Usage
|
||||
|
||||
The ESP-DSP library is a component for the [ESP-IDF build system](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html). It also works with the [new CMake-based build system](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system-cmake.html).
|
||||
|
||||
### Trying out ESP-DSP examples
|
||||
|
||||
If you haven't created an ESP-IDF project yet, and wish to try the examples provided with ESP-DSP, you can clone ESP-DSP repository into any directory, and then run examples from there:
|
||||
|
||||
cd ~/esp
|
||||
git clone https://github.com/espressif/esp-dsp.git
|
||||
cd esp-dsp/examples/dotprod
|
||||
make -j4 flash monitor ESPPORT=PORT
|
||||
|
||||
or, if you are using CMake based build system,
|
||||
|
||||
idf.py -p PORT flash monitor
|
||||
|
||||
where `PORT` is the UART port name of your development board, such as `/dev/ttyUSB0` or `COM1`.
|
||||
|
||||
Note that you need to set up environment variables (`IDF_PATH`, `PATH`) before building the project. Refer to the [ESP-IDF Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) if you don't have the environment set up yet.
|
||||
|
||||
For the list of the examples, please see [README.md](examples/README.md) in the examples directory.
|
||||
|
||||
### Including ESP-DSP into your own project
|
||||
|
||||
To include ESP-DSP into your ESP-IDF project, clone ESP-DSP repository (or add it as a submodule) into the components directory of the project:
|
||||
|
||||
cd your-project-directory
|
||||
mkdir -p components
|
||||
cd components
|
||||
git clone https://github.com/espressif/esp-dsp.git
|
||||
|
||||
ESP-IDF build system also allows including components which are not located in the project components directory, using `EXTRA_COMPONENT_DIRS` project variable. Please refer to the [ESP-IDF build system documentation](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html) for details.
|
||||
|
||||
## Reporting Issues
|
||||
|
||||
If you have found an issue in ESP-DSP, or wish to submit an enhancement request, please use the [Issues](https://github.com/espressif/esp-dsp/issues) section on Github.
|
||||
|
||||
For general questions related to this library, please use the [esp32.com forum](https://esp32.com/).
|
||||
|
||||
## Copyrights and License
|
||||
|
||||
All original source code in this repository is Copyright (C) 2018-2019 Espressif Systems. This source code is licensed under the Apache License 2.0 as described in the file LICENSE.
|
||||
52
components/esp-dsp/build_examples.sh
Normal file
52
components/esp-dsp/build_examples.sh
Normal file
@@ -0,0 +1,52 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Build all examples from the examples directory.
|
||||
#
|
||||
# -----------------------------------------------------------------------------
|
||||
# Safety settings (see https://gist.github.com/ilg-ul/383869cbb01f61a51c4d).
|
||||
|
||||
if [[ ! -z ${DEBUG_SHELL} ]]
|
||||
then
|
||||
set -x # Activate the expand mode if DEBUG is anything but empty.
|
||||
fi
|
||||
|
||||
set -o errexit # Exit if command failed.
|
||||
set -o pipefail # Exit if pipe failed.
|
||||
set -o nounset # Exit if variable not set.
|
||||
|
||||
# Remove the initial space and instead use '\n'.
|
||||
IFS=$'\n\t'
|
||||
|
||||
STARS='***************************************************'
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
die() {
|
||||
echo "${1:-"Unknown Error"}" 1>&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
pushd examples
|
||||
|
||||
EXAMPLES=$(find . -maxdepth 1 -mindepth 1 -type d | cut -d '/' -f 2)
|
||||
|
||||
for NAME in ${EXAMPLES}
|
||||
do
|
||||
echo "$STARS"
|
||||
echo "Building example $NAME with Make"
|
||||
pushd $NAME
|
||||
# -j option will be set via MAKEFLAGS in .gitlab-ci.yml
|
||||
make defconfig && make || die "Make build for ${NAME} has failed"
|
||||
rm -rf build
|
||||
echo "$STARS"
|
||||
echo "Building example $NAME with CMake for Esp32"
|
||||
idf.py set-target esp32
|
||||
idf.py build || die "CMake build for ${NAME} has failed for Esp32"
|
||||
echo "Building example $NAME with CMake for Esp32-s2"
|
||||
idf.py clean
|
||||
idf.py set-target esp32s2
|
||||
idf.py build || die "CMake build for ${NAME} has failed for Esp32-s2"
|
||||
popd
|
||||
done
|
||||
|
||||
popd
|
||||
87
components/esp-dsp/component.mk
Normal file
87
components/esp-dsp/component.mk
Normal file
@@ -0,0 +1,87 @@
|
||||
COMPONENT_ADD_INCLUDEDIRS := modules/dotprod/include \
|
||||
modules/support/include \
|
||||
modules/windows/include \
|
||||
modules/windows/hann/include \
|
||||
modules/windows/blackman/include \
|
||||
modules/windows/blackman_harris/include \
|
||||
modules/windows/blackman_nuttall/include \
|
||||
modules/windows/nuttall/include \
|
||||
modules/windows/flat_top/include \
|
||||
modules/iir/include \
|
||||
modules/fir/include \
|
||||
modules/math/include \
|
||||
modules/math/add/include \
|
||||
modules/math/sub/include \
|
||||
modules/math/mul/include \
|
||||
modules/math/addc/include \
|
||||
modules/math/mulc/include \
|
||||
modules/math/sqrt/include \
|
||||
modules/matrix/include \
|
||||
modules/fft/include \
|
||||
modules/dct/include \
|
||||
modules/conv/include \
|
||||
modules/common/include
|
||||
|
||||
COMPONENT_SRCDIRS :=. \
|
||||
modules/common \
|
||||
modules/common/misc \
|
||||
modules/dotprod \
|
||||
modules/dotprod/float \
|
||||
modules/dotprod/fixed \
|
||||
modules/matrix \
|
||||
modules/matrix/float \
|
||||
modules/matrix/fixed \
|
||||
modules/matrix/mat \
|
||||
modules/math \
|
||||
modules/math/mulc \
|
||||
modules/math/mulc/float \
|
||||
modules/math/mulc/fixed \
|
||||
modules/math/addc \
|
||||
modules/math/addc/float \
|
||||
modules/math/add \
|
||||
modules/math/add/float \
|
||||
modules/math/add/fixed \
|
||||
modules/math/mul \
|
||||
modules/math/mul/float \
|
||||
modules/math/mul/fixed \
|
||||
modules/math/sub \
|
||||
modules/math/sub/float \
|
||||
modules/math/sqrt/float \
|
||||
modules/fft/float \
|
||||
modules/fft/fixed \
|
||||
modules/support \
|
||||
modules/support/snr/float \
|
||||
modules/support/sfdr/float \
|
||||
modules/support/misc \
|
||||
modules/support/view \
|
||||
modules/windows/hann \
|
||||
modules/windows/hann/float \
|
||||
modules/windows/hann/fixed \
|
||||
modules/windows/blackman \
|
||||
modules/windows/blackman/float \
|
||||
modules/windows/blackman/fixed \
|
||||
modules/windows/blackman_harris \
|
||||
modules/windows/blackman_harris/float \
|
||||
modules/windows/blackman_harris/fixed \
|
||||
modules/windows/blackman_nuttall \
|
||||
modules/windows/blackman_nuttall/float \
|
||||
modules/windows/blackman_nuttall/fixed \
|
||||
modules/windows/nuttall \
|
||||
modules/windows/nuttall/float \
|
||||
modules/windows/nuttall/fixed \
|
||||
modules/windows/flat_top \
|
||||
modules/windows/flat_top/float \
|
||||
modules/windows/flat_top/fixed \
|
||||
modules/conv \
|
||||
modules/conv/float \
|
||||
modules/dct \
|
||||
modules/dct/float \
|
||||
modules/iir \
|
||||
modules/iir/biquad \
|
||||
modules/fir \
|
||||
modules/fir/float
|
||||
|
||||
COMPONENT_PRIV_INCLUDEDIRS := modules/dotprod/float \
|
||||
modules/dotprod/fixed \
|
||||
modules/common/private_include
|
||||
|
||||
109
components/esp-dsp/docs/Doxyfile
Normal file
109
components/esp-dsp/docs/Doxyfile
Normal file
@@ -0,0 +1,109 @@
|
||||
# This is Doxygen configuration file
|
||||
#
|
||||
# Doxygen provides over 260 configuration statements
|
||||
# To make this file easier to follow,
|
||||
# it contains only statements that are non-default
|
||||
#
|
||||
# NOTE:
|
||||
# It is recommended not to change defaults unless specifically required
|
||||
# Test any changes how they affect generated documentation
|
||||
# Make sure that correct warnings are generated to flag issues with documented code
|
||||
#
|
||||
# For the complete list of configuration statements see:
|
||||
# https://www.stack.nl/~dimitri/doxygen/manual/config.html
|
||||
|
||||
|
||||
PROJECT_NAME = "Espressif DSP Library"
|
||||
|
||||
## The 'INPUT' statement below is used as input by script 'gen-df-input.py'
|
||||
## to automatically generate API reference list files heder_file.inc
|
||||
## These files are placed in '_inc' directory
|
||||
## and used to include in API reference documentation
|
||||
|
||||
INPUT = \
|
||||
##
|
||||
## Common - API Reference
|
||||
##
|
||||
../modules/common/include/dsp_common.h \
|
||||
## Dot Product - API Reference
|
||||
../modules/dotprod/include/dsps_dotprod.h \
|
||||
## FFT - API Reference
|
||||
../modules/fft/include/dsps_fft2r.h \
|
||||
## DCT - API Reference
|
||||
../modules/dct/include/dsps_dct.h \
|
||||
## FIR Filter - API Reference
|
||||
../modules/fir/include/dsps_fir.h \
|
||||
## IIR Filter - API Reference
|
||||
../modules/iir/include/dsps_biquad_gen.h \
|
||||
../modules/iir/include/dsps_biquad.h \
|
||||
## Math - API Reference
|
||||
../modules/math/mulc/include/dsps_mulc.h \
|
||||
../modules/math/addc/include/dsps_addc.h \
|
||||
../modules/math/add/include/dsps_add.h \
|
||||
../modules/math/sub/include/dsps_sub.h \
|
||||
../modules/math/mul/include/dsps_mul.h \
|
||||
## Matrix - API Reference
|
||||
../modules/matrix/include/dspm_mult.h \
|
||||
../modules/matrix/include/mat.h \
|
||||
## Convolution/Cprrelation - API Reference
|
||||
../modules/conv/include/dsps_conv.h \
|
||||
../modules/conv/include/dsps_corr.h \
|
||||
## Support - API Reference
|
||||
../modules/support/include/dsps_view.h \
|
||||
../modules/support/include/dsps_tone_gen.h \
|
||||
../modules/support/include/dsps_snr.h \
|
||||
../modules/support/include/dsps_sfdr.h \
|
||||
../modules/support/include/dsps_d_gen.h \
|
||||
../modules/support/include/dsps_h_gen.h \
|
||||
## Windows - API Reference
|
||||
../modules/windows/hann/include/dsps_wind_hann.h \
|
||||
../modules/windows/blackman/include/dsps_wind_blackman.h \
|
||||
../modules/windows/blackman_harris/include/dsps_wind_blackman_harris.h \
|
||||
../modules/windows/blackman_nuttall/include/dsps_wind_blackman_nuttall.h \
|
||||
../modules/windows/nuttall/include/dsps_wind_nuttall.h \
|
||||
../modules/windows/flat_top/include/dsps_wind_flat_top.h
|
||||
|
||||
|
||||
## Get warnings for functions that have no documentation for their parameters or return value
|
||||
##
|
||||
WARN_NO_PARAMDOC = YES
|
||||
|
||||
## Enable preprocessing and remove __attribute__(...) expressions from the INPUT files
|
||||
##
|
||||
ENABLE_PREPROCESSING = YES
|
||||
MACRO_EXPANSION = YES
|
||||
EXPAND_ONLY_PREDEF = YES
|
||||
PREDEFINED = \
|
||||
__attribute__(x)= \
|
||||
IRAM_ATTR= \
|
||||
configSUPPORT_DYNAMIC_ALLOCATION=1 \
|
||||
configSUPPORT_STATIC_ALLOCATION=1 \
|
||||
configQUEUE_REGISTRY_SIZE=1 \
|
||||
configUSE_RECURSIVE_MUTEXES=1 \
|
||||
configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS=1 \
|
||||
configNUM_THREAD_LOCAL_STORAGE_POINTERS=1 \
|
||||
configUSE_APPLICATION_TASK_TAG=1 \
|
||||
configTASKLIST_INCLUDE_COREID=1
|
||||
|
||||
## Do not complain about not having dot
|
||||
##
|
||||
HAVE_DOT = NO
|
||||
|
||||
## Generate XML that is required for Breathe
|
||||
##
|
||||
GENERATE_XML = YES
|
||||
XML_OUTPUT = xml
|
||||
|
||||
GENERATE_HTML = NO
|
||||
HAVE_DOT = NO
|
||||
GENERATE_LATEX = NO
|
||||
GENERATE_MAN = YES
|
||||
GENERATE_RTF = NO
|
||||
|
||||
## Skip distracting progress messages
|
||||
##
|
||||
QUIET = YES
|
||||
## Log warnings in a file for further review
|
||||
##
|
||||
WARN_LOGFILE = "doxygen-warning-log.txt"
|
||||
|
||||
2
components/esp-dsp/docs/Makefile
Normal file
2
components/esp-dsp/docs/Makefile
Normal file
@@ -0,0 +1,2 @@
|
||||
LANGUAGE=en
|
||||
include docs_common.mk
|
||||
46
components/esp-dsp/docs/check_doc_warnings.sh
Normal file
46
components/esp-dsp/docs/check_doc_warnings.sh
Normal file
@@ -0,0 +1,46 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Check for Documentation warnings:
|
||||
# doxygen-warning-log.txt should be an empty file
|
||||
# sphinx-warning-log.txt should only contain (fuzzy) matches to ../sphinx-known-warnings.txt
|
||||
RESULT=0
|
||||
STARS='***************************************************'
|
||||
|
||||
if [ -s doxygen-warning-log.txt ]; then
|
||||
echo "$STARS"
|
||||
echo "Build failed due to doxygen warnings:"
|
||||
cat doxygen-warning-log.txt
|
||||
echo "$STARS"
|
||||
RESULT=1
|
||||
fi
|
||||
|
||||
|
||||
SED=sed
|
||||
os_name=`uname -s`
|
||||
if [[ "${os_name}" == "Darwin" ]]; then
|
||||
SED=gsed
|
||||
fi
|
||||
|
||||
# Remove escape characters, file paths, line numbers from
|
||||
# the Sphinx warning log
|
||||
# (escape char removal from https://www.commandlinefu.com/commands/view/6141/remove-color-codes-special-characters-with-sed
|
||||
${SED} -r 's:\x1B\[[0-9;]*[mK]::g' sphinx-warning-log.txt | \
|
||||
${SED} -E "s~${IDF_PATH}~\${IDF_PATH}~" | \
|
||||
${SED} -E "s/:[0-9]+:/:line:/" > sphinx-warning-log-sanitized.txt
|
||||
|
||||
# diff sanitized warnings, ignoring lines which only appear in ../sphinx-known-warnings.txt
|
||||
|
||||
# format is to display only lines new or changed in second argument
|
||||
DIFF_FORMAT="--unchanged-line-format= --old-line-format= --new-line-format=%L"
|
||||
|
||||
SPHINX_WARNINGS=$(diff $DIFF_FORMAT sphinx-known-warnings.txt sphinx-warning-log-sanitized.txt)
|
||||
if ! [ -z "$SPHINX_WARNINGS" ]; then
|
||||
echo "$STARS"
|
||||
echo "Build failed due to new/different Sphinx warnings:"
|
||||
echo "$SPHINX_WARNINGS"
|
||||
echo "$STARS"
|
||||
RESULT=1
|
||||
echo "(Check files sphinx-known-warnings.txt and sphinx-warning-log.txt for full details.)"
|
||||
fi
|
||||
|
||||
exit $RESULT
|
||||
19
components/esp-dsp/docs/conf.py
Normal file
19
components/esp-dsp/docs/conf.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# English Language RTD & Sphinx config file
|
||||
#
|
||||
# Uses IDF_PATH/conf_common.py for most non-language-specific settings.
|
||||
|
||||
# Importing conf_common adds all the non-language-specific
|
||||
# parts to this conf module
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.abspath('.'))
|
||||
from conf_common import *
|
||||
|
||||
# General information about the project.
|
||||
project = u'Espressif DSP Library'
|
||||
copyright = u'2016 - 2018, Espressif Systems (Shanghai) PTE LTD'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
language = 'en'
|
||||
317
components/esp-dsp/docs/conf_common.py
Normal file
317
components/esp-dsp/docs/conf_common.py
Normal file
@@ -0,0 +1,317 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Common (non-language-specific) configuration for Read The Docs & Sphinx
|
||||
#
|
||||
# Based on a Read the Docs Template documentation build configuration file,
|
||||
# created by sphinx-quickstart on Tue Aug 26 14:19:49 2014.
|
||||
#
|
||||
# This file is imported from a language-specific conf.py (ie en/conf.py or
|
||||
# zh_CN/conf.py)
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
import sys, os
|
||||
import re
|
||||
import subprocess
|
||||
import shlex
|
||||
|
||||
# Note: If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute
|
||||
sys.path.insert(0, os.path.abspath('.'))
|
||||
from local_util import run_cmd_get_output, copy_if_modified
|
||||
|
||||
# build_docs on the CI server sometimes fails under Python3. This is a workaround:
|
||||
sys.setrecursionlimit(3500)
|
||||
|
||||
try:
|
||||
builddir = os.environ['BUILDDIR']
|
||||
except KeyError:
|
||||
builddir = '_build'
|
||||
|
||||
def call_with_python(cmd):
|
||||
# using sys.executable ensures that the scripts are called with the same Python interpreter
|
||||
if os.system('{} {}'.format(sys.executable, cmd)) != 0:
|
||||
raise RuntimeError('{} failed'.format(cmd))
|
||||
|
||||
# Call Doxygen to get XML files from the header files
|
||||
print("Calling Doxygen to generate latest XML files")
|
||||
if os.system("doxygen Doxyfile") != 0:
|
||||
raise RuntimeError('Doxygen call failed')
|
||||
|
||||
# Doxygen has generated XML files in 'xml' directory.
|
||||
# Copy them to 'xml_in', only touching the files which have changed.
|
||||
copy_if_modified('xml/', 'xml_in/')
|
||||
|
||||
# Generate 'api_name.inc' files using the XML files by Doxygen
|
||||
call_with_python('gen-dxd.py')
|
||||
|
||||
|
||||
# http://stackoverflow.com/questions/12772927/specifying-an-online-image-in-sphinx-restructuredtext-format
|
||||
#
|
||||
suppress_warnings = ['image.nonlocal_uri']
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = ['breathe', 'link-roles' ]
|
||||
|
||||
# Enabling this fixes cropping of blockdiag edge labels
|
||||
seqdiag_antialias = True
|
||||
|
||||
# Breathe extension variables
|
||||
|
||||
# Doxygen regenerates files in 'xml/' directory every time,
|
||||
# but we copy files to 'xml_in/' only when they change, to speed up
|
||||
# incremental builds.
|
||||
breathe_projects = { "esp32-idf": "xml_in/" }
|
||||
breathe_default_project = "esp32-idf"
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = ['.rst', '.md']
|
||||
|
||||
source_parsers = {
|
||||
'.md': 'recommonmark.parser.CommonMarkParser',
|
||||
}
|
||||
|
||||
# The encoding of source files.
|
||||
#source_encoding = 'utf-8-sig'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
|
||||
# Readthedocs largely ignores 'version' and 'release', and displays one of
|
||||
# 'latest', tag name, or branch name, depending on the build type.
|
||||
# Still, this is useful for non-RTD builds.
|
||||
# This is supposed to be "the short X.Y version", but it's the only version
|
||||
# visible when you open index.html.
|
||||
# Display full version to make things less confusing.
|
||||
version = run_cmd_get_output('git describe')
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
# If needed, nearest tag is returned by 'git describe --abbrev=0'.
|
||||
release = version
|
||||
print('Version: {0} Release: {1}'.format(version, release))
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
#today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
#today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
exclude_patterns = ['_build', 'issue_template.md']
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all
|
||||
# documents.
|
||||
#default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
#add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
#add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
#show_authors = False
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
#modindex_common_prefix = []
|
||||
|
||||
# If true, keep warnings as "system message" paragraphs in the built documents.
|
||||
#keep_warnings = False
|
||||
|
||||
|
||||
# -- Options for HTML output ----------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
#html_theme_path = []
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
#html_title = None
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
#html_logo = idf_path + "/docs/_static/espressif-logo.svg"
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
#html_favicon = None
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
#html_static_path = [idf_path + '/docs/_static']
|
||||
|
||||
# Add any extra paths that contain custom files (such as robots.txt or
|
||||
# .htaccess) here, relative to this directory. These files are copied
|
||||
# directly to the root of the documentation.
|
||||
#html_extra_path = []
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
#html_last_updated_fmt = '%b %d, %Y'
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
#html_sidebars = {}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
#html_domain_indices = True
|
||||
|
||||
# If false, no index is generated.
|
||||
#html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
#html_show_sourcelink = True
|
||||
|
||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||
#html_show_sphinx = True
|
||||
|
||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||
#html_show_copyright = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#html_use_opensearch = ''
|
||||
|
||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
#html_file_suffix = None
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'ReadtheDocsTemplatedoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output ---------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#'preamble': '',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
('index', 'ReadtheDocsTemplate.tex', u'Read the Docs Template Documentation',
|
||||
u'Read the Docs', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
#latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
#latex_use_parts = False
|
||||
|
||||
# If true, show page references after internal links.
|
||||
#latex_show_pagerefs = False
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#latex_show_urls = False
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#latex_domain_indices = True
|
||||
|
||||
|
||||
# -- Options for manual page output ---------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('index', 'readthedocstemplate', u'Read the Docs Template Documentation',
|
||||
[u'Read the Docs'], 1)
|
||||
]
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#man_show_urls = False
|
||||
|
||||
|
||||
# -- Options for Texinfo output -------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
('index', 'ReadtheDocsTemplate', u'Read the Docs Template Documentation',
|
||||
u'Read the Docs', 'ReadtheDocsTemplate', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#texinfo_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#texinfo_domain_indices = True
|
||||
|
||||
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
||||
#texinfo_show_urls = 'footnote'
|
||||
|
||||
# If true, do not generate a @detailmenu in the "Top" node's menu.
|
||||
#texinfo_no_detailmenu = False
|
||||
|
||||
# Override RTD CSS theme to introduce the theme corrections
|
||||
# https://github.com/rtfd/sphinx_rtd_theme/pull/432
|
||||
# def setup(app):
|
||||
# app.add_stylesheet('theme_overrides.css')
|
||||
# generate_version_specific_includes(app)
|
||||
214
components/esp-dsp/docs/docs_common.mk
Normal file
214
components/esp-dsp/docs/docs_common.mk
Normal file
@@ -0,0 +1,214 @@
|
||||
# "Common" Makefile for Sphinx documentation
|
||||
#
|
||||
# (included from en/Makefile & zh_CN/Makefile
|
||||
#
|
||||
# NOTE: This makefile runs with cwd=either en or zh_CN subfolder, so this
|
||||
# (docs/) directory is '..' relative to it.
|
||||
|
||||
# ************ IMPORTANT *****************
|
||||
#
|
||||
# ReadTheDocs DOES NOT USE THIS MAKEFILE,
|
||||
# so any behaviour additions must be
|
||||
# done via Sphinx Config not here
|
||||
#
|
||||
# ****************************************
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
# note: this is changed from sphinx-build so it depends on default python interpreter, not on /bin/sphinx-build
|
||||
# (which will be the most recently installed version of sphinx and may not match)
|
||||
SPHINXBUILD = python -m sphinx
|
||||
PAPER =
|
||||
BUILDDIR = _build
|
||||
|
||||
# Internal variables.
|
||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||
PAPEROPT_letter = -D latex_paper_size=letter
|
||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) -w sphinx-warning-log.txt .
|
||||
# the i18n builder cannot share the environment and doctrees with the others
|
||||
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
|
||||
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext dependencies version-specific-includes check_python_packages
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>\' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " dirhtml to make HTML files named index.html in directories"
|
||||
@echo " singlehtml to make a single large HTML file"
|
||||
@echo " pickle to make pickle files"
|
||||
@echo " json to make JSON files"
|
||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||
@echo " qthelp to make HTML files and a qthelp project"
|
||||
@echo " devhelp to make HTML files and a Devhelp project"
|
||||
@echo " epub to make an epub"
|
||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||
@echo " latexpdf to make LaTeX files and run them through pdflatex"
|
||||
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
|
||||
@echo " text to make text files"
|
||||
@echo " man to make manual pages"
|
||||
@echo " texinfo to make Texinfo files"
|
||||
@echo " info to make Texinfo files and run them through makeinfo"
|
||||
@echo " gettext to make PO message catalogs"
|
||||
@echo " changes to make an overview of all changed/added/deprecated items"
|
||||
@echo " xml to make Docutils-native XML files"
|
||||
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
|
||||
@echo " linkcheck to check all external links for integrity"
|
||||
@echo " doctest to run all doctests embedded in the documentation (if enabled) "
|
||||
|
||||
clean:
|
||||
rm -rf $(BUILDDIR)/*
|
||||
|
||||
check_python_packages:
|
||||
true
|
||||
|
||||
html: | check_python_packages
|
||||
@echo "Build the HTML pages are in $(BUILDDIR)/html."
|
||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
|
||||
dirhtml: | check_python_packages
|
||||
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
||||
|
||||
singlehtml: | check_python_packages
|
||||
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
||||
|
||||
pickle: | check_python_packages
|
||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
||||
@echo
|
||||
@echo "Build finished; now you can process the pickle files."
|
||||
|
||||
json: | check_python_packages
|
||||
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
||||
@echo
|
||||
@echo "Build finished; now you can process the JSON files."
|
||||
|
||||
htmlhelp: | check_python_packages
|
||||
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||
".hhp project file in $(BUILDDIR)/htmlhelp."
|
||||
|
||||
qthelp: | check_python_packages
|
||||
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
||||
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
|
||||
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/ReadtheDocsTemplate.qhcp"
|
||||
@echo "To view the help file:"
|
||||
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/ReadtheDocsTemplate.qhc"
|
||||
|
||||
devhelp: | check_python_packages
|
||||
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
|
||||
@echo
|
||||
@echo "Build finished."
|
||||
@echo "To view the help file:"
|
||||
@echo "# mkdir -p $$HOME/.local/share/devhelp/ReadtheDocsTemplate"
|
||||
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/ReadtheDocsTemplate"
|
||||
@echo "# devhelp"
|
||||
|
||||
epub: | check_python_packages
|
||||
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
|
||||
@echo
|
||||
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
|
||||
|
||||
latex: | check_python_packages
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo
|
||||
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
||||
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
||||
"(use \`make latexpdf' here to do that automatically)."
|
||||
|
||||
latexpdf: | check_python_packages
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through pdflatex..."
|
||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
latexpdfja: | check_python_packages
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through platex and dvipdfmx..."
|
||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
text: | check_python_packages
|
||||
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
|
||||
@echo
|
||||
@echo "Build finished. The text files are in $(BUILDDIR)/text."
|
||||
|
||||
man: | check_python_packages
|
||||
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
|
||||
@echo
|
||||
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
|
||||
|
||||
texinfo: | check_python_packages
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo
|
||||
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
|
||||
@echo "Run \`make' in that directory to run these through makeinfo" \
|
||||
"(use \`make info' here to do that automatically)."
|
||||
|
||||
info: | check_python_packages
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo "Running Texinfo files through makeinfo..."
|
||||
make -C $(BUILDDIR)/texinfo info
|
||||
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
|
||||
|
||||
gettext: | check_python_packages
|
||||
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
|
||||
@echo
|
||||
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
|
||||
|
||||
changes: | check_python_packages
|
||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||
@echo
|
||||
@echo "The overview file is in $(BUILDDIR)/changes."
|
||||
|
||||
linkcheck: | check_python_packages
|
||||
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
||||
@echo
|
||||
@echo "Link check complete; look for any errors in the above output " \
|
||||
"or in $(BUILDDIR)/linkcheck/output.txt."
|
||||
|
||||
gh-linkcheck: | check_python_packages
|
||||
@echo "Checking for hardcoded GitHub links"
|
||||
@if (find ../ -name '*.rst' | xargs grep \
|
||||
'https://github.com/espressif/esp-idf/tree\|https://github.com/espressif/esp-idf/blob\|https://github.com/espressif/esp-idf/raw'\
|
||||
); \
|
||||
then \
|
||||
echo "WARNINIG: Some .rst files contain hardcoded Github links."; \
|
||||
echo "Please check above output and replace links with one of the following:"; \
|
||||
echo "- :idf:\`dir\` - points to directory inside ESP-IDF"; \
|
||||
echo "- :idf_file:\`file\` - points to file inside ESP-IDF"; \
|
||||
echo "- :idf_raw:\`file\` - points to raw view of the file inside ESP-IDF"; \
|
||||
echo "- :component:\`dir\` - points to directory inside ESP-IDF components dir"; \
|
||||
echo "- :component_file:\`file\` - points to file inside ESP-IDF components dir"; \
|
||||
echo "- :component_raw:\`file\` - points to raw view of the file inside ESP-IDF"; \
|
||||
echo " components dir"; \
|
||||
echo "- :example:\`dir\` - points to directory inside ESP-IDF examples dir"; \
|
||||
echo "- :example_file:\`file\` - points to file inside ESP-IDF examples dir"; \
|
||||
echo "- :example_raw:\`file\` - points to raw view of the file inside ESP-IDF"; \
|
||||
echo " examples dir"; \
|
||||
echo "These link types will point to the correct GitHub version automatically"; \
|
||||
exit 1; \
|
||||
fi
|
||||
@echo "No hardcoded links found"
|
||||
|
||||
doctest: | check_python_packages
|
||||
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
||||
@echo "Testing of doctests in the sources finished, look at the " \
|
||||
"results in $(BUILDDIR)/doctest/output.txt."
|
||||
|
||||
xml: | check_python_packages
|
||||
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
|
||||
@echo
|
||||
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
|
||||
|
||||
pseudoxml: | check_python_packages
|
||||
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
|
||||
@echo
|
||||
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
|
||||
108
components/esp-dsp/docs/esp-dsp-apis.rst
Normal file
108
components/esp-dsp/docs/esp-dsp-apis.rst
Normal file
@@ -0,0 +1,108 @@
|
||||
Espressif DSP Library API Reference
|
||||
===================================
|
||||
|
||||
Header Files
|
||||
------------
|
||||
|
||||
To use the library, include ``esp_dsp.h`` header file into the source code.
|
||||
|
||||
* :repo_file:`modules/common/include/esp_dsp.h`
|
||||
|
||||
|
||||
Signal (1D) Processing APIs
|
||||
----------------------------
|
||||
|
||||
Signal processing APIs use ``dsps`` prefix. The following modules are available:
|
||||
|
||||
- Dot-product_ - Calculates dot-product of two vectors
|
||||
- FFT_ - Fast Fourier Transform functionality
|
||||
- DCT_ - Discrete Cosine Transform functionality
|
||||
- IIR_ - IIR filter functionality
|
||||
- FIR_ - FIR filter functionality
|
||||
- Math_ - Basic vector operations
|
||||
- Conv_ - Convolution/correlation functionality
|
||||
- Support_ - Support functions
|
||||
- `Window functions`_ - FFT window generation functions
|
||||
|
||||
Dot-product
|
||||
+++++++++++
|
||||
|
||||
.. include:: /_build/inc/dsps_dotprod.inc
|
||||
|
||||
FFT
|
||||
+++
|
||||
|
||||
.. include:: /_build/inc/dsps_fft2r.inc
|
||||
|
||||
DCT
|
||||
+++
|
||||
|
||||
.. include:: /_build/inc/dsps_dct.inc
|
||||
|
||||
FIR
|
||||
+++
|
||||
|
||||
.. include:: /_build/inc/dsps_fir.inc
|
||||
|
||||
IIR
|
||||
+++
|
||||
|
||||
.. include:: /_build/inc/dsps_biquad_gen.inc
|
||||
.. include:: /_build/inc/dsps_biquad.inc
|
||||
|
||||
Math
|
||||
++++
|
||||
|
||||
.. include:: /_build/inc/dsps_add.inc
|
||||
.. include:: /_build/inc/dsps_sub.inc
|
||||
.. include:: /_build/inc/dsps_mul.inc
|
||||
.. include:: /_build/inc/dsps_addc.inc
|
||||
.. include:: /_build/inc/dsps_mulc.inc
|
||||
|
||||
Conv
|
||||
++++
|
||||
|
||||
.. include:: /_build/inc/dsps_conv.inc
|
||||
.. include:: /_build/inc/dsps_corr.inc
|
||||
|
||||
Support
|
||||
+++++++
|
||||
|
||||
.. include:: /_build/inc/dsps_d_gen.inc
|
||||
.. include:: /_build/inc/dsps_h_gen.inc
|
||||
.. include:: /_build/inc/dsps_tone_gen.inc
|
||||
.. include:: /_build/inc/dsps_view.inc
|
||||
.. include:: /_build/inc/dsps_snr.inc
|
||||
.. include:: /_build/inc/dsps_sfdr.inc
|
||||
|
||||
Window Functions
|
||||
++++++++++++++++
|
||||
|
||||
.. include:: /_build/inc/dsps_wind_hann.inc
|
||||
|
||||
Matrix Operations APIs
|
||||
----------------------
|
||||
|
||||
Matrix operations APIs use ``dspm`` prefix. The following modules are available:
|
||||
|
||||
- Multiplication - basic matrix multiplication operations
|
||||
|
||||
Matrix Multiplication
|
||||
+++++++++++++++++++++
|
||||
|
||||
.. include:: /_build/inc/dspm_mult.inc
|
||||
|
||||
Matrix Operations
|
||||
+++++++++++++++++++++
|
||||
|
||||
.. include:: /_build/inc/mat.inc
|
||||
|
||||
Miscellaneous
|
||||
-------------
|
||||
|
||||
Various common functions used by other modules are included in this module.
|
||||
|
||||
Common APIs
|
||||
+++++++++++
|
||||
|
||||
.. include:: /_build/inc/dsp_common.inc
|
||||
66
components/esp-dsp/docs/esp-dsp-benchmarks.rst
Normal file
66
components/esp-dsp/docs/esp-dsp-benchmarks.rst
Normal file
@@ -0,0 +1,66 @@
|
||||
Espressif DSP Library Benchmarks
|
||||
================================
|
||||
|
||||
The table bellow contains benchmarks of functions provided by ESP-DSP library. The values are CPU cycle counts taken to execute each of the functions. Values in "ESP32" column are for the optimized (assembly) implementation, values in "ANSI C" column are for the non-optimized implementation.
|
||||
|
||||
+----------------------------------------------------------+----------+----------+
|
||||
| Function name and arguments | CPU cycles |
|
||||
+----------------------------------------------------------+----------+----------+
|
||||
| | ESP32 | ANSI C |
|
||||
+==========================================================+==========+==========+
|
||||
| | | |
|
||||
+----------------------------------------------------------+----------+----------+
|
||||
| **Dot Product** | | |
|
||||
+----------------------------------------------------------+----------+----------+
|
||||
| dsps_dotprod_f32 for N=256 points | 1057 | 2597 |
|
||||
+----------------------------------------------------------+----------+----------+
|
||||
| dsps_dotprode_f32 for N=256 points, with step 1 | 1318 | 2601 |
|
||||
+----------------------------------------------------------+----------+----------+
|
||||
| dsps_dotprod_s16 for N=256 points | 448 | 5185 |
|
||||
+----------------------------------------------------------+----------+----------+
|
||||
| | | |
|
||||
+----------------------------------------------------------+----------+----------+
|
||||
| **FIR Filters** | | |
|
||||
+----------------------------------------------------------+----------+----------+
|
||||
| dsps_fir_f32 1024 input samples and 256 coefficients | 1338418 | 3583556 |
|
||||
+----------------------------------------------------------+----------+----------+
|
||||
| dsps_fird_f32 1024 samples, 256 coeffs and decimation 4 | 37582 | 82535 |
|
||||
+----------------------------------------------------------+----------+----------+
|
||||
| | | |
|
||||
+----------------------------------------------------------+----------+----------+
|
||||
| **FFTs** | | |
|
||||
+----------------------------------------------------------+----------+----------+
|
||||
| dsps_fft2r_fc32 for 64 complex points | 5451 | 8187 |
|
||||
+----------------------------------------------------------+----------+----------+
|
||||
| dsps_fft2r_fc32 for 128 complex points | 12400 | 18756 |
|
||||
+----------------------------------------------------------+----------+----------+
|
||||
| dsps_fft2r_fc32 for 256 complex points | 27829 | 42381 |
|
||||
+----------------------------------------------------------+----------+----------+
|
||||
| dsps_fft2r_fc32 for 512 complex points | 61755 | 94616 |
|
||||
+----------------------------------------------------------+----------+----------+
|
||||
| dsps_fft2r_fc32 for 1024 complex points | 135745 | 209058 |
|
||||
+----------------------------------------------------------+----------+----------+
|
||||
| | | |
|
||||
+----------------------------------------------------------+----------+----------+
|
||||
| **IIR Filters** | | |
|
||||
+----------------------------------------------------------+----------+----------+
|
||||
| dsps_biquad_f32 - biquad filter for 1024 input samples | 17451 | 31778 |
|
||||
+----------------------------------------------------------+----------+----------+
|
||||
| | | |
|
||||
+----------------------------------------------------------+----------+----------+
|
||||
| **Matrix Multiplication** | | |
|
||||
+----------------------------------------------------------+----------+----------+
|
||||
| dspm_mult_f32 - C[16,16] = A[16,16]*B[16,16]; | 24669 | 59690 |
|
||||
+----------------------------------------------------------+----------+----------+
|
||||
| dspm_mult_s16 - C[16,16] = A[16,16]*B[16,16]; | 24964 | 114150 |
|
||||
+----------------------------------------------------------+----------+----------+
|
||||
| dspm_mult_3x3x1_f32 - C[3,1] = A[3,3]*B[3,1]; | 80 | 242 |
|
||||
+----------------------------------------------------------+----------+----------+
|
||||
| dspm_mult_3x3x3_f32 - C[3,3] = A[3,3]*B[3,3]; | 212 | 541 |
|
||||
+----------------------------------------------------------+----------+----------+
|
||||
| dspm_mult_4x4x1_f32 - C[4,1] = A[4,4]*B[4,1]; | 112 | 362 |
|
||||
+----------------------------------------------------------+----------+----------+
|
||||
| dspm_mult_4x4x4_f32 - C[4,4] = A[4,4]*B[4,4]; | 404 | 1130 |
|
||||
+----------------------------------------------------------+----------+----------+
|
||||
|
||||
The benchmark test could be reproduced by executing test cases found in :repo_file:`test/test_dsp.c`.
|
||||
78
components/esp-dsp/docs/esp-dsp-library.rst
Normal file
78
components/esp-dsp/docs/esp-dsp-library.rst
Normal file
@@ -0,0 +1,78 @@
|
||||
Espressif DSP Library
|
||||
=====================
|
||||
|
||||
Overview
|
||||
--------
|
||||
An Espressif DSP Library (esp-dsp) it's library of functions, modules and components that provides possibility
|
||||
to use Espressif's CPUs as DSPs in efficient way.
|
||||
|
||||
|
||||
Function Naming
|
||||
---------------
|
||||
Naming conventions for the Library functions are similar for all covered domains. You can distinguish signal processing functions by the dsps prefix, while image and video processing functions have dspi prefix,
|
||||
and functions that are specific for operations on small matrices have dspm prefix in their names. Function names in Library have the following general format:
|
||||
|
||||
dsp<data-domain>_<name>_<datatype1><datatype_ext>_<datatype2><datatype_ext>[_<descriptor>]<_impl>(<parameters>);
|
||||
|
||||
The elements of this format are explained in the sections that follow.
|
||||
|
||||
Data-Domain
|
||||
^^^^^^^^^^^
|
||||
|
||||
The data-domain is a single character that expresses the subset of functionality to which a given function belongs. The Library designed to supports the following data-domains:
|
||||
|
||||
- s - for signals (expected data type is a 1D signal)
|
||||
- i - for images and video (expected data type is a 2D image)
|
||||
- m - for matrices (expected data type is a matrix)
|
||||
- r - for realistic rendering functionality and 3D data processing (expected data type depends on supported rendering techniques)
|
||||
- q - for signals of fixed length
|
||||
|
||||
For example, function names that begin with dspi signify that respective functions are used for image or video processing.
|
||||
|
||||
Name
|
||||
^^^^
|
||||
|
||||
The name is an abbreviation for the core operation that the function really does, for example Add, Sqrt,
|
||||
followed in some cases by a function-specific modifier: = [_modifier]
|
||||
|
||||
This modifier, if present, denotes a slight modification or variation of the given function.
|
||||
|
||||
Data Types
|
||||
^^^^^^^^^^
|
||||
|
||||
The library supports two main data types – int16 for fixed point arithmetic and float for floating point arithmetic. The datatype described as:
|
||||
|
||||
Data type suffices:
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
- s - signed
|
||||
- u - unsigned
|
||||
- f - float
|
||||
|
||||
Data type extensions:
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
- c - complex
|
||||
|
||||
Data type Bits resolution:
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
- 16
|
||||
- 32
|
||||
|
||||
For example: dsps_mac_sc16 defines that mac operation with 1d array will be made with 16 bit signed complex data.
|
||||
|
||||
Implementation Type
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
Each function could be implemented different for different platform and could use different style and resources.
|
||||
That's why every implemented function will have name extension <_impl> that will define which kind of implementation it is.
|
||||
User can use universal function without extension.
|
||||
|
||||
Implementation extensions:
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
By default all functions could be used without extensions. The option that select optimized/ansi can be chosen in menuconfig.
|
||||
|
||||
Inside library the extensions means:
|
||||
- _ansi - a universal function where body of function implemented on ANSI C. This implementation not includes any hardware optimization
|
||||
- _ae32 - written on ESP32 assembler and optimized for ESP32
|
||||
- _platform - header file with definitions of available CPUs instructions for different functions
|
||||
- others- depends on amount of supported CPUs. This list will be extended in future
|
||||
|
||||
|
||||
318
components/esp-dsp/docs/gen-dxd.py
Normal file
318
components/esp-dsp/docs/gen-dxd.py
Normal file
@@ -0,0 +1,318 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# gen-dxd.py - Generate Doxygen Directives
|
||||
#
|
||||
# This code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
# Unless required by applicable law or agreed to in writing, this
|
||||
# software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
# CONDITIONS OF ANY KIND, either express or implied.
|
||||
#
|
||||
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
from builtins import range
|
||||
from io import open
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
|
||||
# Determime build directory
|
||||
builddir = '_build'
|
||||
if 'BUILDDIR' in os.environ:
|
||||
builddir = os.environ['BUILDDIR']
|
||||
|
||||
# Script configuration
|
||||
header_file_path_prefix = "../modules/"
|
||||
"""string: path prefix for header files.
|
||||
"""
|
||||
doxyfile_path = "./Doxyfile"
|
||||
"""string: path to a file containing header files to processs.
|
||||
"""
|
||||
xml_directory_path = "xml"
|
||||
"""string: path to directory with XML files by Doxygen.
|
||||
"""
|
||||
inc_directory_path = os.path.join(builddir, 'inc')
|
||||
"""string: path prefix for header files.
|
||||
"""
|
||||
all_kinds = [
|
||||
("function", "Functions"),
|
||||
("union", "Unions"),
|
||||
("struct", "Structures"),
|
||||
("define", "Macros"),
|
||||
("typedef", "Type Definitions"),
|
||||
("enum", "Enumerations")
|
||||
]
|
||||
"""list of items that will be generated for a single API file
|
||||
"""
|
||||
|
||||
|
||||
def get_doxyfile_input():
|
||||
"""Get contents of Doxyfile's INPUT statement.
|
||||
|
||||
Returns:
|
||||
Contents of Doxyfile's INPUT.
|
||||
|
||||
"""
|
||||
if not os.path.isfile(doxyfile_path):
|
||||
print("Doxyfile '%s' does not exist!" % doxyfile_path)
|
||||
sys.exit()
|
||||
|
||||
print("Getting Doxyfile's INPUT")
|
||||
|
||||
input_file = open(doxyfile_path, "r", encoding='utf-8')
|
||||
|
||||
line = input_file.readline()
|
||||
# read contents of Doxyfile until 'INPUT' statement
|
||||
while line:
|
||||
if line.find("INPUT") == 0:
|
||||
break
|
||||
line = input_file.readline()
|
||||
|
||||
doxyfile_INPUT = ""
|
||||
line = input_file.readline()
|
||||
# skip input_file contents until end of 'INPUT' statement
|
||||
while line:
|
||||
if line.isspace():
|
||||
# we have reached the end of 'INPUT' statement
|
||||
break
|
||||
# process only lines that are not comments
|
||||
if line.find("#") == -1:
|
||||
# extract header file path inside components folder
|
||||
m = re.search(header_file_path_prefix + "(.*\.h)", line)
|
||||
header_file_path = m.group(1)
|
||||
doxyfile_INPUT += "modules/" + header_file_path + "\n"
|
||||
# proceed reading next line
|
||||
line = input_file.readline()
|
||||
|
||||
input_file.close()
|
||||
return doxyfile_INPUT
|
||||
|
||||
|
||||
def get_api_name(header_file_path):
|
||||
"""Get name of API from header file path.
|
||||
|
||||
Args:
|
||||
header_file_path: path to the header file.
|
||||
|
||||
Returns:
|
||||
The name of API.
|
||||
|
||||
"""
|
||||
api_name = ""
|
||||
regex = r".*/(.*)\.h"
|
||||
m = re.search(regex, header_file_path)
|
||||
if m:
|
||||
api_name = m.group(1)
|
||||
|
||||
return api_name
|
||||
|
||||
|
||||
def get_rst_header(header_name):
|
||||
"""Get rst formatted code with a header.
|
||||
|
||||
Args:
|
||||
header_name: name of header.
|
||||
|
||||
Returns:
|
||||
Formatted rst code with the header.
|
||||
|
||||
"""
|
||||
|
||||
rst_output = ""
|
||||
rst_output += header_name + "\n"
|
||||
rst_output += "^" * len(header_name) + "\n"
|
||||
rst_output += "\n"
|
||||
|
||||
return rst_output
|
||||
|
||||
|
||||
def select_unions(innerclass_list):
|
||||
"""Select unions from innerclass list.
|
||||
|
||||
Args:
|
||||
innerclass_list: raw list with unions and structures
|
||||
extracted from Dogygen's xml file.
|
||||
|
||||
Returns:
|
||||
Doxygen directives with unions selected from the list.
|
||||
|
||||
"""
|
||||
|
||||
rst_output = ""
|
||||
for line in innerclass_list.splitlines():
|
||||
# union is denoted by "union" at the beginning of line
|
||||
if line.find("union") == 0:
|
||||
union_id, union_name = re.split(r"\t+", line)
|
||||
rst_output += ".. doxygenunion:: "
|
||||
rst_output += union_name
|
||||
rst_output += "\n"
|
||||
|
||||
return rst_output
|
||||
|
||||
|
||||
def select_structs(innerclass_list):
|
||||
"""Select structures from innerclass list.
|
||||
|
||||
Args:
|
||||
innerclass_list: raw list with unions and structures
|
||||
extracted from Dogygen's xml file.
|
||||
|
||||
Returns:
|
||||
Doxygen directives with structures selected from the list.
|
||||
Note: some structures are excluded as described on code below.
|
||||
|
||||
"""
|
||||
|
||||
rst_output = ""
|
||||
for line in innerclass_list.splitlines():
|
||||
# structure is denoted by "struct" at the beginning of line
|
||||
if line.find("struct") == 0:
|
||||
# skip structures that are part of union
|
||||
# they are documented by 'doxygenunion' directive
|
||||
if line.find("::") > 0:
|
||||
continue
|
||||
struct_id, struct_name = re.split(r"\t+", line)
|
||||
rst_output += ".. doxygenstruct:: "
|
||||
rst_output += struct_name
|
||||
rst_output += "\n"
|
||||
rst_output += " :members:\n"
|
||||
rst_output += "\n"
|
||||
|
||||
return rst_output
|
||||
|
||||
|
||||
def get_directives(tree, kind):
|
||||
"""Get directives for specific 'kind'.
|
||||
|
||||
Args:
|
||||
tree: the ElementTree 'tree' of XML by Doxygen
|
||||
kind: name of API "kind" to be generated
|
||||
|
||||
Returns:
|
||||
Doxygen directives for selected 'kind'.
|
||||
Note: the header with "kind" name is included.
|
||||
|
||||
"""
|
||||
|
||||
rst_output = ""
|
||||
if kind in ["union", "struct"]:
|
||||
innerclass_list = ""
|
||||
for elem in tree.iterfind('compounddef/innerclass'):
|
||||
innerclass_list += elem.attrib["refid"] + "\t" + elem.text + "\n"
|
||||
if kind == "union":
|
||||
rst_output += select_unions(innerclass_list)
|
||||
else:
|
||||
rst_output += select_structs(innerclass_list)
|
||||
else:
|
||||
for elem in tree.iterfind(
|
||||
'compounddef/sectiondef/memberdef[@kind="%s"]' % kind):
|
||||
name = elem.find('name')
|
||||
rst_output += ".. doxygen%s:: " % kind
|
||||
rst_output += name.text + "\n"
|
||||
if rst_output:
|
||||
all_kinds_dict = dict(all_kinds)
|
||||
rst_output = get_rst_header(all_kinds_dict[kind]) + rst_output + "\n"
|
||||
|
||||
return rst_output
|
||||
|
||||
|
||||
def generate_directives(header_file_path):
|
||||
"""Generate API reference with Doxygen directives for a header file.
|
||||
|
||||
Args:
|
||||
header_file_path: a path to the header file with API.
|
||||
|
||||
Returns:
|
||||
Doxygen directives for the header file.
|
||||
|
||||
"""
|
||||
|
||||
api_name = get_api_name(header_file_path)
|
||||
|
||||
# in XLT file name each "_" in the api name is expanded by Doxygen to "__"
|
||||
xlt_api_name = api_name.replace("_", "__")
|
||||
xml_file_path = "%s/%s_8h.xml" % (xml_directory_path, xlt_api_name)
|
||||
|
||||
rst_output = ""
|
||||
rst_output = ".. File automatically generated by 'gen-dxd.py'\n"
|
||||
rst_output += "\n"
|
||||
rst_output += get_rst_header("Header File")
|
||||
rst_output += "* :repo_file:`" + header_file_path + "`\n"
|
||||
rst_output += "\n"
|
||||
|
||||
try:
|
||||
import xml.etree.cElementTree as ET
|
||||
except ImportError:
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
tree = ET.ElementTree(file=xml_file_path)
|
||||
for i in range(len(all_kinds)):
|
||||
kind = all_kinds[i][0]
|
||||
rst_output += get_directives(tree, kind)
|
||||
|
||||
return rst_output
|
||||
|
||||
|
||||
def generate_api_inc_files():
|
||||
"""Generate header_file.inc files
|
||||
with API reference made of doxygen directives
|
||||
for each header file
|
||||
specified in the 'INPUT' statement of Doxyfile.
|
||||
|
||||
"""
|
||||
|
||||
if not os.path.isdir(xml_directory_path):
|
||||
print("Directory %s does not exist!" % xml_directory_path)
|
||||
sys.exit()
|
||||
|
||||
if not os.path.exists(inc_directory_path):
|
||||
os.makedirs(inc_directory_path)
|
||||
|
||||
list_to_generate = get_doxyfile_input()
|
||||
print("Generating 'api_name.inc' files with Doxygen directives")
|
||||
for header_file_path in list_to_generate.splitlines():
|
||||
api_name = get_api_name(header_file_path)
|
||||
inc_file_path = inc_directory_path + "/" + api_name + ".inc"
|
||||
rst_output = generate_directives(header_file_path)
|
||||
|
||||
previous_rst_output = ''
|
||||
if os.path.isfile(inc_file_path):
|
||||
with open(inc_file_path, "r", encoding='utf-8') as inc_file_old:
|
||||
previous_rst_output = inc_file_old.read()
|
||||
|
||||
if previous_rst_output != rst_output:
|
||||
with open(inc_file_path, "w", encoding='utf-8') as inc_file:
|
||||
inc_file.write(rst_output)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
"""The main script that generates
|
||||
Doxygen directives.
|
||||
|
||||
"""
|
||||
|
||||
# Process command line arguments, if any
|
||||
if len(sys.argv) > 1:
|
||||
if not os.path.isdir(xml_directory_path):
|
||||
print("Directory %s does not exist!" % xml_directory_path)
|
||||
sys.exit()
|
||||
header_file_path = sys.argv[1]
|
||||
api_name = get_api_name(header_file_path)
|
||||
if api_name:
|
||||
rst_output = generate_directives(header_file_path)
|
||||
print("Doxygen directives for '%s'" % header_file_path)
|
||||
print()
|
||||
print(rst_output)
|
||||
else:
|
||||
print("Options to execute 'gen-dxd.py' application:")
|
||||
print("1: $ python gen-dxd.py")
|
||||
print(" Generate API 'header_file.inc' files for headers defined in '%s'" % doxyfile_path)
|
||||
print("2: $ python gen-dxd.py header_file_path")
|
||||
print(" Print out Doxygen directives for a single header file")
|
||||
print(" example: $ python gen-dxd.py mdns/include/mdns.h")
|
||||
print(" NOTE: Run Doxygen first to get XML files for the header file")
|
||||
|
||||
sys.exit()
|
||||
|
||||
# No command line arguments given
|
||||
generate_api_inc_files()
|
||||
9
components/esp-dsp/docs/index.rst
Normal file
9
components/esp-dsp/docs/index.rst
Normal file
@@ -0,0 +1,9 @@
|
||||
ESP-DSP Library
|
||||
***************
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
Introduction <esp-dsp-library>
|
||||
Benchmarks <esp-dsp-benchmarks>
|
||||
API Reference <esp-dsp-apis>
|
||||
80
components/esp-dsp/docs/issue_template.md
Normal file
80
components/esp-dsp/docs/issue_template.md
Normal file
@@ -0,0 +1,80 @@
|
||||
----------------------------- Delete below -----------------------------
|
||||
|
||||
If your issue is a general question, starts similar to "How do I..", or is related to 3rd party development kits/libs, please discuss this on our community forum at esp32.com instead.
|
||||
|
||||
INSTRUCTIONS
|
||||
============
|
||||
|
||||
Before submitting a new issue, please follow the checklist and try to find the answer.
|
||||
|
||||
- [ ] I have read the documentation [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/) and the issue is not addressed there.
|
||||
- [ ] I have updated my IDF branch (master or release) to the latest version and checked that the issue is present there.
|
||||
- [ ] I have searched the issue tracker for a similar issue and not found a similar issue.
|
||||
|
||||
If the issue cannot be solved after the steps before, please follow these instructions so we can get the needed information to help you in a quick and effective fashion.
|
||||
|
||||
1. Fill in all the fields under **Environment** marked with [ ] by picking the correct option for you in each case and deleting the others.
|
||||
2. Describe your problem.
|
||||
3. Include [debug logs on the monitor](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/idf-monitor.html#automatically-decoding-addresses) or the [coredump](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/core_dump.html).
|
||||
4. Provide more items under **Other items if possible** can help us better locate your problem.
|
||||
5. Use markup (buttons above) and the Preview tab to check what the issue will look like.
|
||||
6. Delete these instructions from the above to the below marker lines before submitting this issue.
|
||||
|
||||
----------------------------- Delete above -----------------------------
|
||||
|
||||
## Environment
|
||||
|
||||
- Development Kit: [ESP32-Wrover-Kit|ESP32-DevKitC|ESP32-PICO-Kit|ESP32-LyraT|ESP32-LyraTD-MSC|none]
|
||||
- Kit version (for WroverKit/PicoKit/DevKitC): [v1|v2|v3|v4]
|
||||
- Module or chip used: [ESP32-WROOM-32|ESP32-WROOM-32D|ESP32-WROOM-32U|ESP32-WROVER|ESP32-WROVER-I|ESP32-WROVER-B|ESP32-WROVER-IB|ESP32-SOLO-1|ESP32-PICO-D4|ESP32]
|
||||
- IDF version (run ``git describe --tags`` to find it):
|
||||
// v3.2-dev-1148-g96cd3b75c
|
||||
- Build System: [Make|CMake]
|
||||
- Compiler version (run ``xtensa-esp32-elf-gcc --version`` to find it):
|
||||
// 1.22.0-80-g6c4433a
|
||||
- Operating System: [Windows|Linux|macOS]
|
||||
- Power Supply: [USB|external 5V|external 3.3V|Battery]
|
||||
|
||||
## Problem Description
|
||||
|
||||
//Detailed problem description goes here.
|
||||
|
||||
### Expected Behavior
|
||||
|
||||
### Actual Behavior
|
||||
|
||||
### Steps to repropduce
|
||||
|
||||
1. step1
|
||||
2. ...
|
||||
|
||||
// It helps if you attach a picture of your setup/wiring here.
|
||||
|
||||
|
||||
### Code to reproduce this issue
|
||||
|
||||
```cpp
|
||||
// the code should be wrapped in the ```cpp tag so that it will be displayed better.
|
||||
#include "esp_log.h"
|
||||
|
||||
void app_main()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
// If your code is longer than 30 lines, [GIST](https://gist.github.com) is preferred.
|
||||
|
||||
## Debug Logs
|
||||
|
||||
```
|
||||
Debug log goes here, should contain the backtrace, as well as the reset source if it is a crash.
|
||||
Please copy the plain text here for us to search the error log. Or attach the complete logs but leave the main part here if the log is *too* long.
|
||||
```
|
||||
|
||||
## Other items if possible
|
||||
|
||||
- [ ] sdkconfig file (attach the sdkconfig file from your project folder)
|
||||
- [ ] elf file in the ``build`` folder (**note this may contain all the code details and symbols of your project.**)
|
||||
- [ ] coredump (This provides stacks of tasks.)
|
||||
|
||||
46
components/esp-dsp/docs/link-roles.py
Normal file
46
components/esp-dsp/docs/link-roles.py
Normal file
@@ -0,0 +1,46 @@
|
||||
# based on http://protips.readthedocs.io/link-roles.html
|
||||
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
import re
|
||||
import os
|
||||
from docutils import nodes
|
||||
from local_util import run_cmd_get_output
|
||||
|
||||
|
||||
def get_github_rev():
|
||||
path = run_cmd_get_output('git rev-parse --short HEAD')
|
||||
tag = run_cmd_get_output('git describe --exact-match')
|
||||
print('Git commit ID: ', path)
|
||||
if len(tag):
|
||||
print('Git tag: ', tag)
|
||||
path = tag
|
||||
return path
|
||||
|
||||
|
||||
def setup(app):
|
||||
rev = get_github_rev()
|
||||
|
||||
# links to files or folders on the GitHub
|
||||
baseurl = 'https://github.com/espressif/esp-dsp'
|
||||
app.add_role('repo', autolink('{}/tree/{}/%s'.format(baseurl, rev)))
|
||||
app.add_role('repo_file', autolink('{}/blob/{}/%s'.format(baseurl, rev)))
|
||||
app.add_role('repo_raw', autolink('{}/raw/{}/%s'.format(baseurl, rev)))
|
||||
app.add_role('example', autolink('{}/tree/{}/examples/%s'.format(baseurl, rev)))
|
||||
app.add_role('example_file', autolink('{}/blob/{}/examples/%s'.format(baseurl, rev)))
|
||||
app.add_role('example_raw', autolink('{}/raw/{}/examples/%s'.format(baseurl, rev)))
|
||||
|
||||
|
||||
def autolink(pattern):
|
||||
def role(name, rawtext, text, lineno, inliner, options={}, content=[]):
|
||||
m = re.search('(.*)\s*<(.*)>', text) # noqa: W605 - regular expression
|
||||
if m:
|
||||
link_text = m.group(1)
|
||||
link = m.group(2)
|
||||
else:
|
||||
link_text = text
|
||||
link = text
|
||||
url = pattern % (link,)
|
||||
node = nodes.reference(rawtext, link_text, refuri=url, **options)
|
||||
return [node], []
|
||||
return role
|
||||
57
components/esp-dsp/docs/local_util.py
Normal file
57
components/esp-dsp/docs/local_util.py
Normal file
@@ -0,0 +1,57 @@
|
||||
# Utility functions used in conf.py
|
||||
#
|
||||
# Copyright 2017 Espressif Systems (Shanghai) PTE LTD
|
||||
#
|
||||
# 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.
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from io import open
|
||||
import os
|
||||
import shutil
|
||||
|
||||
|
||||
def run_cmd_get_output(cmd):
|
||||
return os.popen(cmd).read().strip()
|
||||
|
||||
|
||||
def files_equal(path_1, path_2):
|
||||
if not os.path.exists(path_1) or not os.path.exists(path_2):
|
||||
return False
|
||||
file_1_contents = ''
|
||||
with open(path_1, "r", encoding='utf-8') as f_1:
|
||||
file_1_contents = f_1.read()
|
||||
file_2_contents = ''
|
||||
with open(path_2, "r", encoding='utf-8') as f_2:
|
||||
file_2_contents = f_2.read()
|
||||
return file_1_contents == file_2_contents
|
||||
|
||||
|
||||
def copy_file_if_modified(src_file_path, dst_file_path):
|
||||
if not files_equal(src_file_path, dst_file_path):
|
||||
dst_dir_name = os.path.dirname(dst_file_path)
|
||||
if not os.path.isdir(dst_dir_name):
|
||||
os.makedirs(dst_dir_name)
|
||||
shutil.copy(src_file_path, dst_file_path)
|
||||
|
||||
|
||||
def copy_if_modified(src_path, dst_path):
|
||||
if os.path.isfile(src_path):
|
||||
copy_file_if_modified(src_path, dst_path)
|
||||
return
|
||||
|
||||
src_path_len = len(src_path)
|
||||
for root, dirs, files in os.walk(src_path):
|
||||
for src_file_name in files:
|
||||
src_file_path = os.path.join(root, src_file_name)
|
||||
dst_file_path = os.path.join(dst_path + root[src_path_len:], src_file_name)
|
||||
copy_file_if_modified(src_file_path, dst_file_path)
|
||||
8
components/esp-dsp/docs/requirements.txt
Normal file
8
components/esp-dsp/docs/requirements.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
# This is a list of python packages used to generate documentation. This file is used with pip:
|
||||
# pip install --user -r requirements.txt
|
||||
#
|
||||
future
|
||||
sphinx==1.6.5
|
||||
sphinx-rtd-theme
|
||||
breathe==4.7.3
|
||||
recommonmark
|
||||
0
components/esp-dsp/docs/sphinx-known-warnings.txt
Normal file
0
components/esp-dsp/docs/sphinx-known-warnings.txt
Normal file
18
components/esp-dsp/examples/README.md
Normal file
18
components/esp-dsp/examples/README.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# ESP-DSP Examples
|
||||
|
||||
This directory contains a range of examples for ESP-DSP library.
|
||||
|
||||
These examples are intended to demonstrate part of ESP-DSP functionality (e.g. initialization, execution) and to provide code that you can copy and adapt into your own projects.
|
||||
|
||||
See the [README.md](../README.md) file in the upper level directory for more information about ESP-DSP.
|
||||
|
||||
# Example Layout
|
||||
|
||||
The examples are grouped into subdirectories by category. Each category directory contains one or more example projects:
|
||||
|
||||
* [Dot Product Calculation](./dotprod/README.md) Example
|
||||
* [Basic Math Operations](./basic_math/README.md) Example
|
||||
* [FFT](./fft/README.md) Example
|
||||
* [Matrix](./matrix/README.md) example
|
||||
* [FFT Window](./fft_window/README.md) Example
|
||||
* [IIR Filter](./iir/README.md) Example
|
||||
9
components/esp-dsp/examples/basic_math/CMakeLists.txt
Normal file
9
components/esp-dsp/examples/basic_math/CMakeLists.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(EXTRA_COMPONENT_DIRS "../../")
|
||||
set(IDF_EXCLUDE_COMPONENTS test test_app)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(basic_math)
|
||||
16
components/esp-dsp/examples/basic_math/Makefile
Normal file
16
components/esp-dsp/examples/basic_math/Makefile
Normal file
@@ -0,0 +1,16 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := basic_math
|
||||
|
||||
# This line has to be included into the make file
|
||||
# to include components that are located somewhere
|
||||
# but not in "component" directory
|
||||
|
||||
EXTRA_COMPONENT_DIRS := $(realpath ../..)
|
||||
EXCLUDE_COMPONENTS := test
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
||||
83
components/esp-dsp/examples/basic_math/README.md
Normal file
83
components/esp-dsp/examples/basic_math/README.md
Normal file
@@ -0,0 +1,83 @@
|
||||
# Basic Math Example
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
This example demonstrates how to use basic math functions from esp-dsp library. Example does the following steps:
|
||||
|
||||
1. Initialize the library
|
||||
2. Initialize input signals with 1024 samples
|
||||
3. Apply window to input signal by standard C loop.
|
||||
4. Calculate FFT for 1024 complex samples and show the result
|
||||
5. Show results on the plots
|
||||
6. Apply window to input signal by basic math functions dsps_mul_f32 and dsps_mulc_f32.
|
||||
7. Calculate FFT for 1024 complex samples
|
||||
8. Show results on the plots
|
||||
|
||||
## How to use example
|
||||
|
||||
### Hardware required
|
||||
|
||||
This example does not require any special hardware, and can be run on any common development board.
|
||||
|
||||
### Configure the project
|
||||
|
||||
If using Make based build system, run `make menuconfig` and set serial port under Serial Flasher Options.
|
||||
If using CMake based build system, no configuration is required.
|
||||
Also, under Component Config ---> DSP Library ---> Optimization for ESP32, it's possible to select optimized or ansi implementation to compare.
|
||||
|
||||
### Build and flash
|
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
make -j4 flash monitor
|
||||
```
|
||||
|
||||
Or, for CMake based build system (replace PORT with serial port name):
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example output
|
||||
|
||||
Here is an typical example console output.
|
||||
|
||||
```bash
|
||||
I (132) main: *** Start Example. ***
|
||||
I (132) main: *** Multiply tone signal with Hann window by standard C loop. ***
|
||||
I (152) view: Data min[432] = -173.749878, Data max[205] = 23.849705
|
||||
________________________________________________________________
|
||||
0 | |
|
||||
1 | |
|
||||
2 | |
|
||||
3 || |
|
||||
4 | | |
|
||||
5 || | |
|
||||
6 ||| || |
|
||||
7 ||||| |||| |
|
||||
8||||||||||||||| |||||| |
|
||||
9 |||||||||||||||||||||||||
|
||||
0123456789012345678901234567890123456789012345678901234567890123
|
||||
I (162) view: Plot: Length=512, min=-120.000000, max=40.000000
|
||||
I (162) main: *** Multiply tone signal with Hann window by esp-dsp basic math functions. ***
|
||||
I (162) view: Data min[432] = -173.749878, Data max[205] = 23.849705
|
||||
________________________________________________________________
|
||||
0 | |
|
||||
1 | |
|
||||
2 | |
|
||||
3 || |
|
||||
4 | | |
|
||||
5 || | |
|
||||
6 ||| || |
|
||||
7 ||||| |||| |
|
||||
8||||||||||||||| |||||| |
|
||||
9 |||||||||||||||||||||||||
|
||||
0123456789012345678901234567890123456789012345678901234567890123
|
||||
I (172) view: Plot: Length=512, min=-120.000000, max=40.000000
|
||||
I (172) main: *** End Example. ***
|
||||
```
|
||||
@@ -0,0 +1,4 @@
|
||||
set(COMPONENT_SRCS "dsps_math_main.c")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS "")
|
||||
|
||||
register_component()
|
||||
8
components/esp-dsp/examples/basic_math/main/component.mk
Normal file
8
components/esp-dsp/examples/basic_math/main/component.mk
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# Main component makefile.
|
||||
#
|
||||
# This Makefile can be left empty. By default, it will take the sources in the
|
||||
# src/ directory, compile them and link them into lib(subdirectory_name).a
|
||||
# in the build directory. This behaviour is entirely configurable,
|
||||
# please read the ESP-IDF documents if you need to do this.
|
||||
#
|
||||
93
components/esp-dsp/examples/basic_math/main/dsps_math_main.c
Normal file
93
components/esp-dsp/examples/basic_math/main/dsps_math_main.c
Normal file
@@ -0,0 +1,93 @@
|
||||
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_system.h"
|
||||
#include "driver/spi_master.h"
|
||||
#include "soc/gpio_struct.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/uart.h"
|
||||
#include "soc/uart_struct.h"
|
||||
#include <math.h>
|
||||
|
||||
#include "esp_dsp.h"
|
||||
|
||||
static const char *TAG = "main";
|
||||
|
||||
// This example shows how to use FFT from esp-dsp library
|
||||
|
||||
#define N_SAMPLES 1024
|
||||
int N = N_SAMPLES;
|
||||
// Input test array
|
||||
float x1[N_SAMPLES];
|
||||
// Window coefficients
|
||||
float wind[N_SAMPLES];
|
||||
// working complex array
|
||||
float y_cf[N_SAMPLES*2];
|
||||
// Pointers to result arrays
|
||||
float* y1_cf = &y_cf[0];
|
||||
|
||||
static void process_and_show(float* data, int length)
|
||||
{
|
||||
dsps_fft2r_fc32(data, length);
|
||||
// Bit reverse
|
||||
dsps_bit_rev_fc32(data, length);
|
||||
// Convert one complex vector to two complex vectors
|
||||
dsps_cplx2reC_fc32(data, length);
|
||||
|
||||
for (int i = 0 ; i < length/2 ; i++) {
|
||||
data[i] = 10 * log10f((data[i * 2 + 0] * data[i * 2 + 0] + data[i * 2 + 1] * data[i * 2 + 1])/N);
|
||||
}
|
||||
|
||||
// Show power spectrum in 64x10 window from -100 to 0 dB from 0..N/4 samples
|
||||
dsps_view(data, length/2, 64, 10, -120, 40, '|');
|
||||
}
|
||||
|
||||
void app_main()
|
||||
{
|
||||
esp_err_t ret;
|
||||
ESP_LOGI(TAG, "*** Start Example. ***");
|
||||
ret = dsps_fft2r_init_fc32(NULL, CONFIG_DSP_MAX_FFT_SIZE);
|
||||
if (ret != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Not possible to initialize FFT. Error = %i", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
// Generate Hann window
|
||||
dsps_wind_hann_f32(wind, N);
|
||||
|
||||
ESP_LOGI(TAG, "*** Multiply tone signal with Hann window by standard C loop. ***");
|
||||
// Generate input signal
|
||||
dsps_tone_gen_f32(x1, N, 1., 0.2, 0);
|
||||
// Convert two input vectors to one complex vector
|
||||
for (int i=0 ; i< N ; i++)
|
||||
{
|
||||
y_cf[i*2 + 0] = x1[i]*wind[i];
|
||||
y_cf[i*2 + 1] = 0;
|
||||
}
|
||||
process_and_show(y_cf, N);
|
||||
|
||||
ESP_LOGI(TAG, "*** Multiply tone signal with Hann window by esp-dsp basic math functions. ***");
|
||||
// Convert two input vectors to one complex vector with basic functions
|
||||
dsps_mul_f32(x1, wind, y_cf, N, 1, 1, 2); // Multiply input array with window and store as real part
|
||||
dsps_mulc_f32(&y_cf[1], &y_cf[1], N, 0, 2, 2); // Clear imaginary part of the complex signal
|
||||
process_and_show(y_cf, N);
|
||||
ESP_LOGI(TAG, "*** End Example. ***");
|
||||
}
|
||||
9
components/esp-dsp/examples/dotprod/CMakeLists.txt
Normal file
9
components/esp-dsp/examples/dotprod/CMakeLists.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(EXTRA_COMPONENT_DIRS "../..")
|
||||
set(IDF_EXCLUDE_COMPONENTS test test_app)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(dotprod)
|
||||
16
components/esp-dsp/examples/dotprod/Makefile
Normal file
16
components/esp-dsp/examples/dotprod/Makefile
Normal file
@@ -0,0 +1,16 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := dotprod
|
||||
|
||||
# This line has to be included into the make file
|
||||
# to include components that are located somewhere
|
||||
# but not in "component" directory
|
||||
|
||||
EXTRA_COMPONENT_DIRS := $(realpath ../..)
|
||||
EXCLUDE_COMPONENTS := test
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
||||
50
components/esp-dsp/examples/dotprod/README.md
Normal file
50
components/esp-dsp/examples/dotprod/README.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# Dot Product Calculation Example
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
This example demonstrates how to use dotprod dsps_dotprod_f32 from esp-dsp library. Example does the following steps:
|
||||
|
||||
1. Initialize the input arrays
|
||||
2. Calculate dot product of two arrays
|
||||
3. Compare results and calculate execution time in cycles.
|
||||
|
||||
## How to use example
|
||||
|
||||
### Hardware required
|
||||
|
||||
This example does not require any special hardware, and can be run on any common development board.
|
||||
|
||||
### Configure the project
|
||||
|
||||
If using Make based build system, run `make menuconfig` and set serial port under Serial Flasher Options.
|
||||
If using CMake based build system, no configuration is required.
|
||||
Also, under Component Config/DSP Library/Optimization for ESP32, it's possible to select optimized or ansi implementation to compare.
|
||||
|
||||
### Build and flash
|
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
make -j4 flash monitor
|
||||
```
|
||||
|
||||
Or, for CMake based build system (replace PORT with serial port name):
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example output
|
||||
|
||||
Here is an typical example console output.
|
||||
|
||||
```
|
||||
I (55) main: Start Example.
|
||||
I (55) main: The sum of 101 elements from 0..100 = 5050.000000
|
||||
I (55) main: Operation for 101 samples took 1381 cycles
|
||||
I (65) main: End Example.
|
||||
```
|
||||
4
components/esp-dsp/examples/dotprod/main/CMakeLists.txt
Normal file
4
components/esp-dsp/examples/dotprod/main/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
set(COMPONENT_SRCS "dsps_dotproduct_main.c")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS "")
|
||||
|
||||
register_component()
|
||||
8
components/esp-dsp/examples/dotprod/main/component.mk
Normal file
8
components/esp-dsp/examples/dotprod/main/component.mk
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# Main component makefile.
|
||||
#
|
||||
# This Makefile can be left empty. By default, it will take the sources in the
|
||||
# src/ directory, compile them and link them into lib(subdirectory_name).a
|
||||
# in the build directory. This behaviour is entirely configurable,
|
||||
# please read the ESP-IDF documents if you need to do this.
|
||||
#
|
||||
@@ -0,0 +1,63 @@
|
||||
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_system.h"
|
||||
#include "driver/spi_master.h"
|
||||
#include "soc/gpio_struct.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/uart.h"
|
||||
#include "soc/uart_struct.h"
|
||||
|
||||
#include "esp_dsp.h"
|
||||
|
||||
static const char *TAG = "main";
|
||||
|
||||
// This example shows how to use dsps_dotprod_f32 and dsps_dotprode_f32 functions
|
||||
|
||||
#define N_SAMPLES 256
|
||||
int N = N_SAMPLES;
|
||||
float input1[N_SAMPLES];
|
||||
float input2[N_SAMPLES];
|
||||
|
||||
void app_main()
|
||||
{
|
||||
esp_err_t ret;
|
||||
ESP_LOGI(TAG, "Start Example.");
|
||||
|
||||
// The example will calculate n!
|
||||
//Initialize an input arrays
|
||||
for (int i=0 ; i< N ; i++)
|
||||
{
|
||||
input1[i] = 1;
|
||||
input2[i] = i;
|
||||
}
|
||||
float result1 = 0;
|
||||
unsigned int start_b = xthal_get_ccount();
|
||||
ret = dsps_dotprod_f32(input1, input2, &result1, 101);
|
||||
unsigned int end_b = xthal_get_ccount();
|
||||
if (ret != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Operation error = %i", ret);
|
||||
}
|
||||
ESP_LOGI(TAG, "The sum of 101 elements from 0..100 = %f", result1);
|
||||
ESP_LOGI(TAG, "Operation for 101 samples take %i cycles", end_b - start_b);
|
||||
|
||||
ESP_LOGI(TAG, "End Example.");
|
||||
}
|
||||
9
components/esp-dsp/examples/fft/CMakeLists.txt
Normal file
9
components/esp-dsp/examples/fft/CMakeLists.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(EXTRA_COMPONENT_DIRS "../../")
|
||||
set(IDF_EXCLUDE_COMPONENTS test test_app)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(fft2r)
|
||||
16
components/esp-dsp/examples/fft/Makefile
Normal file
16
components/esp-dsp/examples/fft/Makefile
Normal file
@@ -0,0 +1,16 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := fft2r
|
||||
|
||||
# This line has to be included into the make file
|
||||
# to include components that are located somewhere
|
||||
# but not in "component" directory
|
||||
|
||||
EXTRA_COMPONENT_DIRS := $(realpath ../..)
|
||||
EXCLUDE_COMPONENTS := test
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
||||
99
components/esp-dsp/examples/fft/README.md
Normal file
99
components/esp-dsp/examples/fft/README.md
Normal file
@@ -0,0 +1,99 @@
|
||||
# FFT Example
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
This example demonstrates how to use FFT functionality from esp-dsp library. Example does the following steps:
|
||||
|
||||
1. Initialize the library
|
||||
2. Initialize input signals with 1024 samples: one 0 dB, second with -20 dB
|
||||
3. Combine two signals as one complex input signal and apply window to input signals paar.
|
||||
4. Calculate FFT for 1024 complex samples
|
||||
5. Apply bit reverse operation for output complex vector
|
||||
6. Split one complex FFT output spectrum to two real signal spectrums
|
||||
7. Show results on the plots
|
||||
8. Show execution time of FFT
|
||||
|
||||
## How to use example
|
||||
|
||||
### Hardware required
|
||||
|
||||
This example does not require any special hardware, and can be run on any common development board.
|
||||
|
||||
### Configure the project
|
||||
|
||||
If using Make based build system, run `make menuconfig` and set serial port under Serial Flasher Options.
|
||||
If using CMake based build system, no configuration is required.
|
||||
Also, under Component Config/DSP Library/Optimization for ESP32, it's possible to select optimized or ansi implementation to compare.
|
||||
|
||||
### Build and flash
|
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
make -j4 flash monitor
|
||||
```
|
||||
|
||||
Or, for CMake based build system (replace PORT with serial port name):
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example output
|
||||
|
||||
Here is an typical example console output.
|
||||
|
||||
```
|
||||
I (59) main: Start Example.
|
||||
W (89) main: Signal x1
|
||||
I (89) view: Data min[495] = -162.760925, Data max[164] = 23.938747
|
||||
________________________________________________________________
|
||||
0 |
|
||||
1 | |
|
||||
2 | |
|
||||
3 | |
|
||||
4 | |
|
||||
5 | |
|
||||
6 | | |
|
||||
7 | | |
|
||||
8 || || |
|
||||
9|||||||||||||||||| ||||||||||||||||||||||||||||||||||||||||||
|
||||
0123456789012345678901234567890123456789012345678901234567890123
|
||||
I (159) view: Plot: Length=512, min=-60.000000, max=40.000000
|
||||
W (169) main: Signal x2
|
||||
I (169) view: Data min[502] = -164.545135, Data max[205] = 3.857752
|
||||
________________________________________________________________
|
||||
0 |
|
||||
1 |
|
||||
2 |
|
||||
3 | |
|
||||
4 | |
|
||||
5 | |
|
||||
6 | |
|
||||
7 || |
|
||||
8 | | |
|
||||
9|||||||||||||||||||||||| ||||||||||||||||||||||||||||||||||||||
|
||||
0123456789012345678901234567890123456789012345678901234567890123
|
||||
I (249) view: Plot: Length=512, min=-60.000000, max=40.000000
|
||||
W (249) main: Signals x1 and x2 on one plot
|
||||
I (259) view: Data min[505] = -159.215271, Data max[164] = 23.938747
|
||||
________________________________________________________________
|
||||
0 |
|
||||
1 | |
|
||||
2 | |
|
||||
3 | | |
|
||||
4 | | |
|
||||
5 | | |
|
||||
6 | | | |
|
||||
7 | | || |
|
||||
8 || || | | |
|
||||
9|||||||||||||||||| | ||||||||||||||||||||||||||||||||||||||
|
||||
0123456789012345678901234567890123456789012345678901234567890123
|
||||
I (339) view: Plot: Length=512, min=-60.000000, max=40.000000
|
||||
I (339) main: FFT for 1024 complex points take 140472 cycles
|
||||
I (349) main: End Example.
|
||||
```
|
||||
4
components/esp-dsp/examples/fft/main/CMakeLists.txt
Normal file
4
components/esp-dsp/examples/fft/main/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
set(COMPONENT_SRCS "dsps_fft_main.c")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS "")
|
||||
|
||||
register_component()
|
||||
8
components/esp-dsp/examples/fft/main/component.mk
Normal file
8
components/esp-dsp/examples/fft/main/component.mk
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# Main component makefile.
|
||||
#
|
||||
# This Makefile can be left empty. By default, it will take the sources in the
|
||||
# src/ directory, compile them and link them into lib(subdirectory_name).a
|
||||
# in the build directory. This behaviour is entirely configurable,
|
||||
# please read the ESP-IDF documents if you need to do this.
|
||||
#
|
||||
101
components/esp-dsp/examples/fft/main/dsps_fft_main.c
Normal file
101
components/esp-dsp/examples/fft/main/dsps_fft_main.c
Normal file
@@ -0,0 +1,101 @@
|
||||
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_system.h"
|
||||
#include "driver/spi_master.h"
|
||||
#include "soc/gpio_struct.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/uart.h"
|
||||
#include "soc/uart_struct.h"
|
||||
#include <math.h>
|
||||
|
||||
#include "esp_dsp.h"
|
||||
|
||||
static const char *TAG = "main";
|
||||
|
||||
// This example shows how to use FFT from esp-dsp library
|
||||
|
||||
#define N_SAMPLES 1024
|
||||
int N = N_SAMPLES;
|
||||
// Input test array
|
||||
float x1[N_SAMPLES];
|
||||
float x2[N_SAMPLES];
|
||||
// Window coefficients
|
||||
float wind[N_SAMPLES];
|
||||
// working complex array
|
||||
float y_cf[N_SAMPLES*2];
|
||||
// Pointers to result arrays
|
||||
float* y1_cf = &y_cf[0];
|
||||
float* y2_cf = &y_cf[N_SAMPLES];
|
||||
|
||||
// Sum of y1 and y2
|
||||
float sum_y[N_SAMPLES/2];
|
||||
|
||||
void app_main()
|
||||
{
|
||||
esp_err_t ret;
|
||||
ESP_LOGI(TAG, "Start Example.");
|
||||
ret = dsps_fft2r_init_fc32(NULL, CONFIG_DSP_MAX_FFT_SIZE);
|
||||
if (ret != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Not possible to initialize FFT. Error = %i", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
// Generate hann window
|
||||
dsps_wind_hann_f32(wind, N);
|
||||
// Generate input signal for x1 A=1 , F=0.1
|
||||
dsps_tone_gen_f32(x1, N, 1.0, 0.16, 0);
|
||||
// Generate input signal for x2 A=0.1,F=0.2
|
||||
dsps_tone_gen_f32(x2, N, 0.1, 0.2, 0);
|
||||
|
||||
// Convert two input vectors to one complex vector
|
||||
for (int i=0 ; i< N ; i++)
|
||||
{
|
||||
y_cf[i*2 + 0] = x1[i] * wind[i];
|
||||
y_cf[i*2 + 1] = x2[i] * wind[i];
|
||||
}
|
||||
// FFT
|
||||
unsigned int start_b = xthal_get_ccount();
|
||||
dsps_fft2r_fc32(y_cf, N);
|
||||
unsigned int end_b = xthal_get_ccount();
|
||||
// Bit reverse
|
||||
dsps_bit_rev_fc32(y_cf, N);
|
||||
// Convert one complex vector to two complex vectors
|
||||
dsps_cplx2reC_fc32(y_cf, N);
|
||||
|
||||
for (int i = 0 ; i < N/2 ; i++) {
|
||||
y1_cf[i] = 10 * log10f((y1_cf[i * 2 + 0] * y1_cf[i * 2 + 0] + y1_cf[i * 2 + 1] * y1_cf[i * 2 + 1])/N);
|
||||
y2_cf[i] = 10 * log10f((y2_cf[i * 2 + 0] * y2_cf[i * 2 + 0] + y2_cf[i * 2 + 1] * y2_cf[i * 2 + 1])/N);
|
||||
// Simple way to show two power spectrums as one plot
|
||||
sum_y[i] = fmax(y1_cf[i], y2_cf[i]);
|
||||
}
|
||||
|
||||
// Show power spectrum in 64x10 window from -100 to 0 dB from 0..N/4 samples
|
||||
ESP_LOGW(TAG, "Signal x1");
|
||||
dsps_view(y1_cf, N/2, 64, 10, -60, 40, '|');
|
||||
ESP_LOGW(TAG, "Signal x2");
|
||||
dsps_view(y2_cf, N/2, 64, 10, -60, 40, '|');
|
||||
ESP_LOGW(TAG, "Signals x1 and x2 on one plot");
|
||||
dsps_view(sum_y, N/2, 64, 10, -60, 40, '|');
|
||||
ESP_LOGI(TAG, "FFT for %i complex points take %i cycles", N, end_b - start_b);
|
||||
|
||||
ESP_LOGI(TAG, "End Example.");
|
||||
}
|
||||
9
components/esp-dsp/examples/fft4real/CMakeLists.txt
Normal file
9
components/esp-dsp/examples/fft4real/CMakeLists.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(EXTRA_COMPONENT_DIRS "../../")
|
||||
set(IDF_EXCLUDE_COMPONENTS test test_app)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(fft4real)
|
||||
16
components/esp-dsp/examples/fft4real/Makefile
Normal file
16
components/esp-dsp/examples/fft4real/Makefile
Normal file
@@ -0,0 +1,16 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := fft4real
|
||||
|
||||
# This line has to be included into the make file
|
||||
# to include components that are located somewhere
|
||||
# but not in "component" directory
|
||||
|
||||
EXTRA_COMPONENT_DIRS := $(realpath ../..)
|
||||
EXCLUDE_COMPONENTS := test
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
||||
99
components/esp-dsp/examples/fft4real/README.md
Normal file
99
components/esp-dsp/examples/fft4real/README.md
Normal file
@@ -0,0 +1,99 @@
|
||||
# FFT 4 Real Input Example
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
This example demonstrates how to use FFT functionality from esp-dsp library. Example does the following steps:
|
||||
|
||||
1. Initialize the library
|
||||
2. Initialize input signals with 1024 samples: one 0 dB, second with -20 dB
|
||||
4. Calculate FFT Radix-2 for 1024 complex samples
|
||||
4. Calculate FFT Radix-4 for 1024 complex samples
|
||||
5. Apply bit reverse operation for output complex vectors
|
||||
7. Show results on the plots
|
||||
8. Show execution time of FFTs
|
||||
|
||||
## How to use example
|
||||
|
||||
### Hardware required
|
||||
|
||||
This example does not require any special hardware, and can be run on any common development board.
|
||||
|
||||
### Configure the project
|
||||
|
||||
If using Make based build system, run `make menuconfig` and set serial port under Serial Flasher Options.
|
||||
If using CMake based build system, no configuration is required.
|
||||
Also, under Component Config/DSP Library/Optimization for ESP32, it's possible to select optimized or ansi implementation to compare.
|
||||
|
||||
### Build and flash
|
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
make -j4 flash monitor
|
||||
```
|
||||
|
||||
Or, for CMake based build system (replace PORT with serial port name):
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example output
|
||||
|
||||
Here is an typical example console output.
|
||||
|
||||
```
|
||||
I (344) main: Start Example.
|
||||
W (424) main: Signal x1
|
||||
I (424) view: Data min[673] = -103.113297, Data max[328] = 20.490950
|
||||
________________________________________________________________
|
||||
0 |
|
||||
1 | |
|
||||
2 | |
|
||||
3 | |
|
||||
4 | |
|
||||
5 | |
|
||||
6 | |
|
||||
7 | | |
|
||||
8 | | |
|
||||
9||||||||||||||||||| |||||||||||||||||||||||||||||||||||||||||||
|
||||
0123456789012345678901234567890123456789012345678901234567890123
|
||||
I (494) view: Plot: Length=1024, min=-60.000000, max=40.000000
|
||||
W (504) main: Signal x2
|
||||
I (504) view: Data min[582] = -103.113297, Data max[328] = 20.490950
|
||||
________________________________________________________________
|
||||
0 |
|
||||
1 | |
|
||||
2 | |
|
||||
3 | |
|
||||
4 | |
|
||||
5 | |
|
||||
6 | |
|
||||
7 | | |
|
||||
8 | | |
|
||||
9||||||||||||||||||| |||||||||||||||||||||||||||||||||||||||||||
|
||||
0123456789012345678901234567890123456789012345678901234567890123
|
||||
I (584) view: Plot: Length=1024, min=-60.000000, max=40.000000
|
||||
W (593) main: Difference between signals x1 and x2 on one plot
|
||||
I (594) view: Data min[0] = 0.000000, Data max[392] = 0.313019
|
||||
________________________________________________________________
|
||||
0 |
|
||||
1 |
|
||||
2 |
|
||||
3 |
|
||||
4 |
|
||||
5 |
|
||||
6 |
|
||||
7 |
|
||||
8----------------------------------------------------------------|
|
||||
9 |
|
||||
0123456789012345678901234567890123456789012345678901234567890123
|
||||
I (674) view: Plot: Length=1024, min=0.000000, max=40.000000
|
||||
I (674) main: FFT Radix 2 for 1024 complex points take 168652 cycles
|
||||
I (684) main: FFT Radix 4 for 1024 complex points take 104665 cycles
|
||||
I (694) main: End Example.
|
||||
```
|
||||
4
components/esp-dsp/examples/fft4real/main/CMakeLists.txt
Normal file
4
components/esp-dsp/examples/fft4real/main/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
set(COMPONENT_SRCS "dsps_fft4real_main.c")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS "")
|
||||
|
||||
register_component()
|
||||
8
components/esp-dsp/examples/fft4real/main/component.mk
Normal file
8
components/esp-dsp/examples/fft4real/main/component.mk
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# Main component makefile.
|
||||
#
|
||||
# This Makefile can be left empty. By default, it will take the sources in the
|
||||
# src/ directory, compile them and link them into lib(subdirectory_name).a
|
||||
# in the build directory. This behaviour is entirely configurable,
|
||||
# please read the ESP-IDF documents if you need to do this.
|
||||
#
|
||||
114
components/esp-dsp/examples/fft4real/main/dsps_fft4real_main.c
Normal file
114
components/esp-dsp/examples/fft4real/main/dsps_fft4real_main.c
Normal file
@@ -0,0 +1,114 @@
|
||||
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_system.h"
|
||||
#include "driver/spi_master.h"
|
||||
#include "soc/gpio_struct.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/uart.h"
|
||||
#include "soc/uart_struct.h"
|
||||
#include <math.h>
|
||||
|
||||
#include "esp_dsp.h"
|
||||
|
||||
static const char *TAG = "main";
|
||||
|
||||
// This example shows how to use FFT from esp-dsp library
|
||||
|
||||
#define N_SAMPLES 2048 // Amount of real input samples
|
||||
int N = N_SAMPLES;
|
||||
// Input test array
|
||||
float x1[N_SAMPLES];
|
||||
float x2[N_SAMPLES];
|
||||
// Window coefficients
|
||||
float wind[N_SAMPLES];
|
||||
// Pointers to result arrays
|
||||
float* y1_cf = &x1[0];
|
||||
float* y2_cf = &x2[0];
|
||||
|
||||
// diff of y1 and y2
|
||||
float diff_y[N_SAMPLES/2];
|
||||
|
||||
void app_main()
|
||||
{
|
||||
esp_err_t ret;
|
||||
ESP_LOGI(TAG, "Start Example.");
|
||||
ret = dsps_fft2r_init_fc32(NULL, N>>1);
|
||||
if (ret != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Not possible to initialize FFT2R. Error = %i", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = dsps_fft4r_init_fc32(NULL, N >> 1);
|
||||
if (ret != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Not possible to initialize FFT4R. Error = %i", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
// Generate hann window
|
||||
dsps_wind_hann_f32(wind, N);
|
||||
// Generate input signal for x1 A=1 , F=0.1
|
||||
dsps_tone_gen_f32(x1, N, 1.0, 0.16, 0);
|
||||
|
||||
// Convert two input vectors to one complex vector
|
||||
for (int i=0 ; i< N ; i++)
|
||||
{
|
||||
x1[i] = x1[i] * wind[i];
|
||||
x2[i] = x1[i];
|
||||
}
|
||||
// FFT Radix-2
|
||||
unsigned int start_r2 = xthal_get_ccount();
|
||||
dsps_fft2r_fc32(x1, N>>1);
|
||||
// Bit reverse
|
||||
dsps_bit_rev2r_fc32(x1, N>>1);
|
||||
// Convert one complex vector with length N/2 to one real spectrum vector with length N/2
|
||||
dsps_cplx2real_fc32(x1, N>>1);
|
||||
unsigned int end_r2 = xthal_get_ccount();
|
||||
|
||||
// FFT Radix-4
|
||||
unsigned int start_r4 = xthal_get_ccount();
|
||||
dsps_fft4r_fc32(x2, N>>1);
|
||||
// Bit reverse
|
||||
dsps_bit_rev4r_fc32(x2, N>>1);
|
||||
// Convert one complex vector with length N/2 to one real spectrum vector with length N/2
|
||||
dsps_cplx2real_fc32(x2, N>>1);
|
||||
unsigned int end_r4 = xthal_get_ccount();
|
||||
|
||||
for (int i = 0 ; i < N/2 ; i++) {
|
||||
x1[i] = 10 * log10f((x1[i * 2 + 0] * x1[i * 2 + 0] + x1[i * 2 + 1] * x1[i * 2 + 1] + 0.0000001)/N);
|
||||
x2[i] = 10 * log10f((x2[i * 2 + 0] * x2[i * 2 + 0] + x2[i * 2 + 1] * x2[i * 2 + 1] + 0.0000001)/N);
|
||||
// Simple way to show two power spectrums as one plot
|
||||
diff_y[i] = fabs(x1[i] - x2[i]);
|
||||
}
|
||||
|
||||
// Show power spectrum in 64x10 window from -100 to 0 dB from 0..N/4 samples
|
||||
ESP_LOGW(TAG, "Signal x1");
|
||||
dsps_view(x1, N/2, 64, 10, -60, 40, '|');
|
||||
ESP_LOGW(TAG, "Signal x2");
|
||||
dsps_view(x2, N/2, 64, 10, -60, 40, '|');
|
||||
ESP_LOGW(TAG, "Difference between signals x1 and x2 on one plot");
|
||||
dsps_view(diff_y, N/2, 64, 10, 0, 40, '-');
|
||||
ESP_LOGI(TAG, "FFT Radix 2 for %i complex points take %i cycles", N/2, end_r2 - start_r2);
|
||||
ESP_LOGI(TAG, "FFT Radix 4 for %i complex points take %i cycles", N/2, end_r4 - start_r4);
|
||||
|
||||
ESP_LOGI(TAG, "End Example.");
|
||||
}
|
||||
9
components/esp-dsp/examples/fft4real/main/linker.ld
Normal file
9
components/esp-dsp/examples/fft4real/main/linker.ld
Normal file
@@ -0,0 +1,9 @@
|
||||
[mapping:dsp]
|
||||
archive: libdsp.a
|
||||
entries:
|
||||
* (noflash)
|
||||
|
||||
[mapping:esp-dsp]
|
||||
archive: libesp-dsp.a
|
||||
entries:
|
||||
* (noflash)
|
||||
9
components/esp-dsp/examples/fft_window/CMakeLists.txt
Normal file
9
components/esp-dsp/examples/fft_window/CMakeLists.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(EXTRA_COMPONENT_DIRS "../../")
|
||||
set(IDF_EXCLUDE_COMPONENTS test test_app)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(fft_window)
|
||||
16
components/esp-dsp/examples/fft_window/Makefile
Normal file
16
components/esp-dsp/examples/fft_window/Makefile
Normal file
@@ -0,0 +1,16 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := fft_window
|
||||
|
||||
# This line has to be included into the make file
|
||||
# to include components that are located somewhere
|
||||
# but not in "component" directory
|
||||
|
||||
EXTRA_COMPONENT_DIRS := $(realpath ../..)
|
||||
EXCLUDE_COMPONENTS := test
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
||||
142
components/esp-dsp/examples/fft_window/README.md
Normal file
142
components/esp-dsp/examples/fft_window/README.md
Normal file
@@ -0,0 +1,142 @@
|
||||
# FFT Window Example
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
This example demonstrates how to use Window and FFT functionality from esp-dsp library. Example does the following steps:
|
||||
|
||||
1. Initialize the library
|
||||
2. Initialize input signals with 1024 samples
|
||||
3. Apply window to input signal.
|
||||
4. Calculate FFT for 1024 complex samples
|
||||
5. Apply bit reverse operation for output complex vector
|
||||
6. Split one complex FFT output spectrum to two real signal spectrums
|
||||
7. Show results on the plots
|
||||
|
||||
## How to use example
|
||||
|
||||
### Hardware required
|
||||
|
||||
This example does not require any special hardware, and can be run on any common development board.
|
||||
|
||||
### Configure the project
|
||||
|
||||
If using Make based build system, run `make menuconfig` and set serial port under Serial Flasher Options.
|
||||
If using CMake based build system, no configuration is required.
|
||||
Also, under Component Config/DSP Library/Optimization for ESP32, it's possible to select optimized or ansi implementation to compare.
|
||||
|
||||
### Build and flash
|
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
make -j4 flash monitor
|
||||
```
|
||||
|
||||
Or, for CMake based build system (replace PORT with serial port name):
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example output
|
||||
|
||||
Here is an typical example console output.
|
||||
|
||||
```
|
||||
I (128) main: Start Example.
|
||||
W (128) main: Hann Window
|
||||
I (128) view: Data min[256] = -inf, Data max[1] = 24.086628
|
||||
________________________________________________________________
|
||||
0| |
|
||||
1| |
|
||||
2| |
|
||||
3| |
|
||||
4| |
|
||||
5 | |
|
||||
6 | |
|
||||
7 ||||| |
|
||||
8 ||||||||||||||| |
|
||||
9 ||||||||||||||||||||||||||||||||||||||||||
|
||||
0123456789012345678901234567890123456789012345678901234567890123
|
||||
I (138) view: Plot: Length=512, min=-120.000000, max=40.000000
|
||||
W (138) main: Blackman Window
|
||||
I (148) view: Data min[355] = -165.295654, Data max[1] = 24.083012
|
||||
________________________________________________________________
|
||||
0| |
|
||||
1| |
|
||||
2| |
|
||||
3| |
|
||||
4| |
|
||||
5| |
|
||||
6 | |
|
||||
7 ||| |
|
||||
8 ||||||||| |
|
||||
9 |||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||
0123456789012345678901234567890123456789012345678901234567890123
|
||||
I (158) view: Plot: Length=512, min=-120.000000, max=40.000000
|
||||
W (158) main: Blackman-Harris Window
|
||||
I (168) view: Data min[128] = -inf, Data max[1] = 23.874702
|
||||
________________________________________________________________
|
||||
0| |
|
||||
1| |
|
||||
2| |
|
||||
3| |
|
||||
4| |
|
||||
5| |
|
||||
6| |
|
||||
7|| |
|
||||
8| |||| |
|
||||
9 |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||
0123456789012345678901234567890123456789012345678901234567890123
|
||||
I (178) view: Plot: Length=512, min=-120.000000, max=40.000000
|
||||
W (178) main: Blackman-Nuttall Window
|
||||
I (188) view: Data min[128] = -inf, Data max[1] = 23.890663
|
||||
________________________________________________________________
|
||||
0| |
|
||||
1| |
|
||||
2| |
|
||||
3| |
|
||||
4| |
|
||||
5| |
|
||||
6| |
|
||||
7 || |
|
||||
8 |||| | |
|
||||
9 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||
0123456789012345678901234567890123456789012345678901234567890123
|
||||
I (198) view: Plot: Length=512, min=-120.000000, max=40.000000
|
||||
W (198) main: Nuttall Window
|
||||
I (208) view: Data min[203] = -175.147400, Data max[1] = 23.858671
|
||||
________________________________________________________________
|
||||
0| |
|
||||
1| |
|
||||
2| |
|
||||
3| |
|
||||
4| |
|
||||
5| |
|
||||
6| |
|
||||
7|| |
|
||||
8 ||| |
|
||||
9 ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||
0123456789012345678901234567890123456789012345678901234567890123
|
||||
I (218) view: Plot: Length=512, min=-120.000000, max=40.000000
|
||||
W (218) main: Flat-Top Window
|
||||
I (228) view: Data min[256] = -inf, Data max[1] = 22.490753
|
||||
________________________________________________________________
|
||||
0| |
|
||||
1| |
|
||||
2| |
|
||||
3| |
|
||||
4| |
|
||||
5| |
|
||||
6| |
|
||||
7 || |
|
||||
8 ||||| |
|
||||
9 |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||
0123456789012345678901234567890123456789012345678901234567890123
|
||||
I (238) view: Plot: Length=512, min=-120.000000, max=40.000000
|
||||
I (238) main: End Example.
|
||||
```
|
||||
@@ -0,0 +1,4 @@
|
||||
set(COMPONENT_SRCS "dsps_window_main.c")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS "")
|
||||
|
||||
register_component()
|
||||
8
components/esp-dsp/examples/fft_window/main/component.mk
Normal file
8
components/esp-dsp/examples/fft_window/main/component.mk
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# Main component makefile.
|
||||
#
|
||||
# This Makefile can be left empty. By default, it will take the sources in the
|
||||
# src/ directory, compile them and link them into lib(subdirectory_name).a
|
||||
# in the build directory. This behaviour is entirely configurable,
|
||||
# please read the ESP-IDF documents if you need to do this.
|
||||
#
|
||||
141
components/esp-dsp/examples/fft_window/main/dsps_window_main.c
Normal file
141
components/esp-dsp/examples/fft_window/main/dsps_window_main.c
Normal file
@@ -0,0 +1,141 @@
|
||||
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_system.h"
|
||||
#include "driver/spi_master.h"
|
||||
#include "soc/gpio_struct.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/uart.h"
|
||||
#include "soc/uart_struct.h"
|
||||
#include <math.h>
|
||||
|
||||
#include "esp_dsp.h"
|
||||
|
||||
static const char *TAG = "main";
|
||||
|
||||
// This example shows how to use FFT from esp-dsp library
|
||||
|
||||
#define N_SAMPLES 1024
|
||||
int N = N_SAMPLES;
|
||||
// Input test array
|
||||
float x1[N_SAMPLES];
|
||||
// Window coefficients
|
||||
float wind[N_SAMPLES];
|
||||
// working complex array
|
||||
float y_cf[N_SAMPLES*2];
|
||||
// Pointers to result arrays
|
||||
float* y1_cf = &y_cf[0];
|
||||
|
||||
void process_and_show(float* data, int length)
|
||||
{
|
||||
dsps_fft2r_fc32(data, length);
|
||||
// Bit reverse
|
||||
dsps_bit_rev_fc32(data, length);
|
||||
// Convert one complex vector to two complex vectors
|
||||
dsps_cplx2reC_fc32(data, length);
|
||||
|
||||
for (int i = 0 ; i < length/2 ; i++) {
|
||||
data[i] = 10 * log10f((data[i * 2 + 0] * data[i * 2 + 0] + data[i * 2 + 1] * data[i * 2 + 1])/N);
|
||||
}
|
||||
|
||||
// Show power spectrum in 64x10 window from -100 to 0 dB from 0..N/4 samples
|
||||
dsps_view(data, length/2, 64, 10, -120, 40, '|');
|
||||
|
||||
}
|
||||
|
||||
void app_main()
|
||||
{
|
||||
esp_err_t ret;
|
||||
ESP_LOGI(TAG, "Start Example.");
|
||||
ret = dsps_fft2r_init_fc32(NULL, CONFIG_DSP_MAX_FFT_SIZE);
|
||||
if (ret != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Not possible to initialize FFT. Error = %i", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGW(TAG, "Hann Window");
|
||||
// Generate Hann window
|
||||
dsps_wind_hann_f32(wind, N);
|
||||
// Convert two input vectors to one complex vector
|
||||
for (int i=0 ; i< N ; i++)
|
||||
{
|
||||
y_cf[i*2 + 0] = wind[i];
|
||||
y_cf[i*2 + 1] = 0;
|
||||
}
|
||||
process_and_show(y_cf, N);
|
||||
|
||||
ESP_LOGW(TAG, "Blackman Window");
|
||||
// Generate Blackman window
|
||||
dsps_wind_blackman_f32(wind, N);
|
||||
// Convert two input vectors to one complex vector
|
||||
for (int i=0 ; i< N ; i++)
|
||||
{
|
||||
y_cf[i*2 + 0] = wind[i];
|
||||
y_cf[i*2 + 1] = 0;
|
||||
}
|
||||
process_and_show(y_cf, N);
|
||||
|
||||
ESP_LOGW(TAG, "Blackman-Harris Window");
|
||||
// Generate Blackman-Harris window
|
||||
dsps_wind_blackman_harris_f32(wind, N);
|
||||
// Convert two input vectors to one complex vector
|
||||
for (int i=0 ; i< N ; i++)
|
||||
{
|
||||
y_cf[i*2 + 0] = wind[i];
|
||||
y_cf[i*2 + 1] = 0;
|
||||
}
|
||||
process_and_show(y_cf, N);
|
||||
|
||||
ESP_LOGW(TAG, "Blackman-Nuttall Window");
|
||||
// Generate Blackman-Nuttall window
|
||||
dsps_wind_blackman_nuttall_f32(wind, N);
|
||||
// Convert two input vectors to one complex vector
|
||||
for (int i=0 ; i< N ; i++)
|
||||
{
|
||||
y_cf[i*2 + 0] = wind[i];
|
||||
y_cf[i*2 + 1] = 0;
|
||||
}
|
||||
process_and_show(y_cf, N);
|
||||
|
||||
ESP_LOGW(TAG, "Nuttall Window");
|
||||
// Generate Nuttall window
|
||||
dsps_wind_nuttall_f32(wind, N);
|
||||
// Convert two input vectors to one complex vector
|
||||
for (int i=0 ; i< N ; i++)
|
||||
{
|
||||
y_cf[i*2 + 0] = wind[i];
|
||||
y_cf[i*2 + 1] = 0;
|
||||
}
|
||||
process_and_show(y_cf, N);
|
||||
|
||||
ESP_LOGW(TAG, "Flat-Top Window");
|
||||
// Generate Flat-Top window
|
||||
dsps_wind_flat_top_f32(wind, N);
|
||||
// Convert two input vectors to one complex vector
|
||||
for (int i=0 ; i< N ; i++)
|
||||
{
|
||||
y_cf[i*2 + 0] = wind[i];
|
||||
y_cf[i*2 + 1] = 0;
|
||||
}
|
||||
process_and_show(y_cf, N);
|
||||
|
||||
ESP_LOGI(TAG, "End Example.");
|
||||
}
|
||||
9
components/esp-dsp/examples/iir/CMakeLists.txt
Normal file
9
components/esp-dsp/examples/iir/CMakeLists.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(EXTRA_COMPONENT_DIRS "../../")
|
||||
set(IDF_EXCLUDE_COMPONENTS test test_app)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(iir)
|
||||
16
components/esp-dsp/examples/iir/Makefile
Normal file
16
components/esp-dsp/examples/iir/Makefile
Normal file
@@ -0,0 +1,16 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := iir
|
||||
|
||||
# This line has to be included into the make file
|
||||
# to include components that are located somewhere
|
||||
# but not in "component" directory
|
||||
|
||||
EXTRA_COMPONENT_DIRS := $(realpath ../..)
|
||||
EXCLUDE_COMPONENTS := test
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
||||
115
components/esp-dsp/examples/iir/README.md
Normal file
115
components/esp-dsp/examples/iir/README.md
Normal file
@@ -0,0 +1,115 @@
|
||||
# IIR Filter Example
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
This example demonstrates how to use IIR filters functionality from esp-dsp library. Example does the following steps:
|
||||
|
||||
1. Initialize the library
|
||||
2. Initialize input signal
|
||||
3. Show LPF filter with Q factor 1
|
||||
* Calculate iir filter coefficients
|
||||
* Filter the input test signal (delta function)
|
||||
* Shows impulse response on the plot
|
||||
* Shows frequency response on the plot
|
||||
* Calculate execution performance
|
||||
4. The same for LPF filter with Q factor 10
|
||||
|
||||
## How to use example
|
||||
|
||||
### Hardware required
|
||||
|
||||
This example does not require any special hardware, and can be run on any common development board.
|
||||
|
||||
### Configure the project
|
||||
|
||||
If using Make based build system, run `make menuconfig` and set serial port under Serial Flasher Options.
|
||||
If using CMake based build system, no configuration is required.
|
||||
Also, under Component Config/DSP Library/Optimization for ESP32, it's possible to select optimized or ansi implementation to compare.
|
||||
|
||||
### Build and flash
|
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
make -j4 flash monitor
|
||||
```
|
||||
|
||||
Or, for CMake based build system (replace PORT with serial port name):
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example output
|
||||
|
||||
Here is an typical example console output.
|
||||
|
||||
```
|
||||
I (58) main: Start Example.
|
||||
I (58) main: Impulse response of IIR filter with F=0.100000, qFactor=1.000000
|
||||
I (68) view: Data min[8] = -0.060052, Data max[2] = 0.333517
|
||||
________________________________________________________________
|
||||
0 |
|
||||
1 |
|
||||
2 - |
|
||||
3- - |
|
||||
4 -------------------------------------------------------------|
|
||||
5 |
|
||||
6 |
|
||||
7 |
|
||||
8 |
|
||||
9 |
|
||||
0123456789012345678901234567890123456789012345678901234567890123
|
||||
I (138) view: Plot: Length=128, min=-1.000000, max=1.000000
|
||||
I (148) view: Data min[511] = -149.983795, Data max[0] = 0.000000
|
||||
________________________________________________________________
|
||||
0 |
|
||||
1 |
|
||||
2----------------- |
|
||||
3 ---------- |
|
||||
4 ------------- |
|
||||
5 ---------- |
|
||||
6 ------- |
|
||||
7 --- |
|
||||
8 -- |
|
||||
9 --|
|
||||
0123456789012345678901234567890123456789012345678901234567890123
|
||||
I (228) view: Plot: Length=512, min=-100.000000, max=0.000000
|
||||
I (228) main: IIR for 1024 samples take 20276 cycles
|
||||
I (238) main: Impulse response of IIR filter with F=0.100000, qFactor=10.000000
|
||||
I (248) view: Data min[7] = -0.453739, Data max[2] = 0.526114
|
||||
________________________________________________________________
|
||||
0 |
|
||||
1 |
|
||||
2 - - |
|
||||
3- - - - --- --- - - |
|
||||
4- - - - - ---- -------------------------------------|
|
||||
5 -- -- -- -- |
|
||||
6 |
|
||||
7 |
|
||||
8 |
|
||||
9 |
|
||||
0123456789012345678901234567890123456789012345678901234567890123
|
||||
I (318) view: Plot: Length=128, min=-1.000000, max=1.000000
|
||||
I (328) view: Data min[511] = -149.480377, Data max[0] = 0.000000
|
||||
________________________________________________________________
|
||||
0 -- |
|
||||
1 -- - |
|
||||
2---------- ----- |
|
||||
3 -------- |
|
||||
4 ------------ |
|
||||
5 ---------- |
|
||||
6 ------- |
|
||||
7 --- |
|
||||
8 -- |
|
||||
9 --|
|
||||
0123456789012345678901234567890123456789012345678901234567890123
|
||||
I (408) view: Plot: Length=512, min=-100.000000, max=0.000000
|
||||
I (408) main: IIR for 1024 samples take 17456 cycles
|
||||
I (418) main: End Example.
|
||||
|
||||
```
|
||||
4
components/esp-dsp/examples/iir/main/CMakeLists.txt
Normal file
4
components/esp-dsp/examples/iir/main/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
set(COMPONENT_SRCS "dsps_iir_main.c")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS "")
|
||||
|
||||
register_component()
|
||||
8
components/esp-dsp/examples/iir/main/component.mk
Normal file
8
components/esp-dsp/examples/iir/main/component.mk
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# Main component makefile.
|
||||
#
|
||||
# This Makefile can be left empty. By default, it will take the sources in the
|
||||
# src/ directory, compile them and link them into lib(subdirectory_name).a
|
||||
# in the build directory. This behaviour is entirely configurable,
|
||||
# please read the ESP-IDF documents if you need to do this.
|
||||
#
|
||||
112
components/esp-dsp/examples/iir/main/dsps_iir_main.c
Normal file
112
components/esp-dsp/examples/iir/main/dsps_iir_main.c
Normal file
@@ -0,0 +1,112 @@
|
||||
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_system.h"
|
||||
#include "driver/spi_master.h"
|
||||
#include "soc/gpio_struct.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/uart.h"
|
||||
#include "soc/uart_struct.h"
|
||||
#include <math.h>
|
||||
|
||||
#include "esp_dsp.h"
|
||||
|
||||
static const char *TAG = "main";
|
||||
|
||||
// This example shows how to use iir filters from esp-dsp library
|
||||
|
||||
#define N_SAMPLES 1024
|
||||
int N = N_SAMPLES;
|
||||
// Input test array
|
||||
float d[N_SAMPLES];
|
||||
// output array
|
||||
float y[N_SAMPLES];
|
||||
float y_cf[N_SAMPLES*2];
|
||||
|
||||
// Function shows result of IIR filter
|
||||
void ShowIIRfilter(float freq, float qFactor)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
float coeffs_lpf[5];
|
||||
float w_lpf[5] = {0,0};
|
||||
// Calculate iir filter coefficients
|
||||
ret = dsps_biquad_gen_lpf_f32(coeffs_lpf, freq, qFactor);
|
||||
if (ret != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Operation error = %i", ret);
|
||||
return;
|
||||
}
|
||||
// Process input signal
|
||||
unsigned int start_b = xthal_get_ccount();
|
||||
ret = dsps_biquad_f32(d, y, N, coeffs_lpf, w_lpf);
|
||||
unsigned int end_b = xthal_get_ccount();
|
||||
if (ret != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Operation error = %i", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
// Show result as a plot
|
||||
ESP_LOGI(TAG, "Impulse response of IIR filter with F=%f, qFactor=%f", freq, qFactor);
|
||||
dsps_view(y, 128, 64, 10, -1, 1, '-');
|
||||
|
||||
// Show result as frequency responce on the plot
|
||||
for (int i=0 ; i< N ; i++)
|
||||
{
|
||||
y_cf[i*2 + 0] = y[i];
|
||||
y_cf[i*2 + 1] = 0;
|
||||
}
|
||||
|
||||
// We making FFT transform
|
||||
dsps_fft2r_fc32_ansi(y_cf, N);
|
||||
// Bit reverse
|
||||
dsps_bit_rev_fc32_ansi(y_cf, N);
|
||||
// Calculating power of spectrum in dB
|
||||
for (int i = 0 ; i < N/2 ; i++) {
|
||||
y_cf[i] = 10 * log10f((y_cf[i * 2 + 0] * y_cf[i * 2 + 0] + y_cf[i * 2 + 1] * y_cf[i * 2 + 1])/N);
|
||||
}
|
||||
// Show power spectrum in 64x10 window from -100 to 0 dB from 0..N/2 samples
|
||||
dsps_view(y_cf, N/2, 64, 10, -100, 0, '-');
|
||||
ESP_LOGI(TAG, "IIR for %i samples take %i cycles", N, end_b - start_b);
|
||||
}
|
||||
|
||||
void app_main()
|
||||
{
|
||||
esp_err_t ret;
|
||||
ESP_LOGI(TAG, "Start Example.");
|
||||
// If user don't care about buffer allocation, the defalt
|
||||
// initialization could be used as shown here:
|
||||
ret = dsps_fft2r_init_fc32(NULL, CONFIG_DSP_MAX_FFT_SIZE);
|
||||
if (ret != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Not possible to initialize FFT. Error = %i", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize input signal
|
||||
// Generate d function as input signal
|
||||
dsps_d_gen_f32(d, N, 0);
|
||||
|
||||
// Show filter with Q factor 1
|
||||
ShowIIRfilter(0.1, 1);
|
||||
// Show filter with Q factor 10
|
||||
ShowIIRfilter(0.1, 10);
|
||||
|
||||
ESP_LOGI(TAG, "End Example.");
|
||||
}
|
||||
9
components/esp-dsp/examples/matrix/CMakeLists.txt
Normal file
9
components/esp-dsp/examples/matrix/CMakeLists.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(EXTRA_COMPONENT_DIRS "../../")
|
||||
set(IDF_EXCLUDE_COMPONENTS test test_app)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(matrix)
|
||||
16
components/esp-dsp/examples/matrix/Makefile
Normal file
16
components/esp-dsp/examples/matrix/Makefile
Normal file
@@ -0,0 +1,16 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := matrix
|
||||
|
||||
# This line has to be included into the make file
|
||||
# to include components that are located somewhere
|
||||
# but not in "component" directory
|
||||
|
||||
EXTRA_COMPONENT_DIRS := $(realpath ../..)
|
||||
EXCLUDE_COMPONENTS := test
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
||||
62
components/esp-dsp/examples/matrix/README.md
Normal file
62
components/esp-dsp/examples/matrix/README.md
Normal file
@@ -0,0 +1,62 @@
|
||||
# Matrix Operations Example
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
This example demonstrates how to use Mat class functionality from esp-dsp library. Example does the following steps:
|
||||
|
||||
1. Initialize a matrix A and matirx x
|
||||
2. Calculate matrix b: b = A*x
|
||||
3. Find roots x1_: A*x1_ = b, with different methods
|
||||
4. Print result
|
||||
|
||||
## How to use example
|
||||
|
||||
### Hardware required
|
||||
|
||||
This example does not require any special hardware, and can be run on any common development board.
|
||||
|
||||
### Configure the project
|
||||
|
||||
If using Make based build system, run `make menuconfig` and set serial port under Serial Flasher Options.
|
||||
If using CMake based build system, no configuration is required.
|
||||
Also, under Component Config/DSP Library/Optimization for ESP32, it's possible to select optimized or ansi implementation to compare.
|
||||
|
||||
### Build and flash
|
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
make -j4 flash monitor
|
||||
```
|
||||
|
||||
Or, for CMake based build system (replace PORT with serial port name):
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example output
|
||||
|
||||
Here is an typical example console output.
|
||||
|
||||
```
|
||||
I (215) main: Start Example.
|
||||
I (215) main: Original vector x:
|
||||
0
|
||||
1
|
||||
2
|
||||
I (215) main: Solve result:
|
||||
0
|
||||
1
|
||||
2
|
||||
I (215) main: Roots result:
|
||||
0
|
||||
1
|
||||
2
|
||||
I (215) main: End Example.
|
||||
|
||||
```
|
||||
4
components/esp-dsp/examples/matrix/main/CMakeLists.txt
Normal file
4
components/esp-dsp/examples/matrix/main/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
set(COMPONENT_SRCS "dspm_matrix_main.cpp")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS "")
|
||||
|
||||
register_component()
|
||||
8
components/esp-dsp/examples/matrix/main/component.mk
Normal file
8
components/esp-dsp/examples/matrix/main/component.mk
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# Main component makefile.
|
||||
#
|
||||
# This Makefile can be left empty. By default, it will take the sources in the
|
||||
# src/ directory, compile them and link them into lib(subdirectory_name).a
|
||||
# in the build directory. This behaviour is entirely configurable,
|
||||
# please read the ESP-IDF documents if you need to do this.
|
||||
#
|
||||
62
components/esp-dsp/examples/matrix/main/dspm_matrix_main.cpp
Normal file
62
components/esp-dsp/examples/matrix/main/dspm_matrix_main.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "dsp_platform.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "esp_dsp.h"
|
||||
|
||||
static const char *TAG = "main";
|
||||
|
||||
// This example shows how to use Mat class from esp-dsp library.
|
||||
//
|
||||
// First we create matix A and x, and then calculating matrix b as result
|
||||
// A*x = b
|
||||
// Then we can find x as roots of matrices X and b
|
||||
//
|
||||
extern "C" void app_main();
|
||||
|
||||
void app_main()
|
||||
{
|
||||
ESP_LOGI(TAG, "Start Example.");
|
||||
int M = 3;
|
||||
int N = 3;
|
||||
dspm::Mat A(M, N);
|
||||
dspm::Mat x(N, 1);
|
||||
for (int m = 0 ; m < M ; m++) {
|
||||
for (int n = 0 ; n < N ; n++) {
|
||||
A(m, n) = N * m + n;
|
||||
}
|
||||
x(m, 0) = m;
|
||||
}
|
||||
A(0, 0) = 10;
|
||||
A(0, 1) = 11;
|
||||
|
||||
dspm::Mat b = A * x;
|
||||
// Gaussian method
|
||||
dspm::Mat x1_ = dspm::Mat::solve(A, b);
|
||||
// Non Gaussian method
|
||||
dspm::Mat x2_ = dspm::Mat::roots(A, b);
|
||||
|
||||
ESP_LOGI(TAG, "Original vector x:");
|
||||
std::cout << x;
|
||||
ESP_LOGI(TAG, "Solve result:");
|
||||
std::cout << x1_;
|
||||
ESP_LOGI(TAG, "Roots result:");
|
||||
std::cout << x2_;
|
||||
ESP_LOGI(TAG, "End Example.");
|
||||
}
|
||||
53
components/esp-dsp/modules/common/include/dsp_common.h
Normal file
53
components/esp-dsp/modules/common/include/dsp_common.h
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// 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 _dsp_common_H_
|
||||
#define _dsp_common_H_
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "dsp_err.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief check power of two
|
||||
* The function check if the argument is power of 2.
|
||||
* The implementation use ANSI C and could be compiled and run on any platform
|
||||
*
|
||||
* @return
|
||||
* - true if x is power of two
|
||||
* - false if no
|
||||
*/
|
||||
bool dsp_is_power_of_two(int x);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Power of two
|
||||
* The function return power of 2 for values 2^N.
|
||||
* The implementation use ANSI C and could be compiled and run on any platform
|
||||
*
|
||||
* @return
|
||||
* - power of two
|
||||
*/
|
||||
int dsp_power_of_two(int x);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _dsp_common_H_
|
||||
23
components/esp-dsp/modules/common/include/dsp_err.h
Normal file
23
components/esp-dsp/modules/common/include/dsp_err.h
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// 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 _DSP_ERR_H_
|
||||
#define _DSP_ERR_H_
|
||||
|
||||
#include "stdint.h"
|
||||
#include "esp_err.h"
|
||||
#include "dsp_err_codes.h"
|
||||
|
||||
#endif // _DSP_ERR_H_
|
||||
27
components/esp-dsp/modules/common/include/dsp_err_codes.h
Normal file
27
components/esp-dsp/modules/common/include/dsp_err_codes.h
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// 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 _dsp_error_codes_H_
|
||||
#define _dsp_error_codes_H_
|
||||
|
||||
#define DSP_OK 0 // For internal use only. Please use ESP_OK instead
|
||||
#define ESP_ERR_DSP_BASE 0x70000
|
||||
#define ESP_ERR_DSP_INVALID_LENGTH (ESP_ERR_DSP_BASE + 1)
|
||||
#define ESP_ERR_DSP_INVALID_PARAM (ESP_ERR_DSP_BASE + 2)
|
||||
#define ESP_ERR_DSP_PARAM_OUTOFRANGE (ESP_ERR_DSP_BASE + 3)
|
||||
#define ESP_ERR_DSP_UNINITIALIZED (ESP_ERR_DSP_BASE + 4)
|
||||
#define ESP_ERR_DSP_REINITIALIZED (ESP_ERR_DSP_BASE + 5)
|
||||
|
||||
|
||||
#endif // _dsp_error_codes_H_
|
||||
25
components/esp-dsp/modules/common/include/dsp_platform.h
Normal file
25
components/esp-dsp/modules/common/include/dsp_platform.h
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// 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 dsp_platform_h_
|
||||
#define dsp_platform_h_
|
||||
#include "soc/cpu.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/portable.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
#endif // dsp_platform_h_
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user