Форум программистов, компьютерный форум, киберфорум
Микроконтроллеры
Войти
Регистрация
Восстановить пароль
 
Рейтинг 5.00/7: Рейтинг темы: голосов - 7, средняя оценка - 5.00
-8 / 1 / 0
Регистрация: 02.01.2016
Сообщений: 69
1

Ввод/вывод звука по I2S, используя ESP32

03.06.2021, 19:53. Показов 1324. Ответов 19

Добрый день друзья!
Подскажите пожалуйста ответ на такую задачу.
Есть необходимость сделать следующее. Перечислю устройства последовательно, по мере прохождения звукового сигнала.
1. Всенаправленный MEMS-микрофон интерфейса I2S - INMP441 INMP441.
2. ESP32.
3. Плата DAC декодера интерфейса I2S - PCM5102A.

Далее. Звук с микрофона по шине I2S заворачиваем на ESP32 (благо есть такой интерфейс), обрабатываем как нам необходимо и также по шине I2S передаем на ЦАП PCM5102A.

Под обработкой, как нам необходимо, в идеале, следует понимать применение шифрования. Т.е. ESP32 предполагается использовать для шифрования и соответственно расшифровки. Но для начала шифрование вообще не будем затрагивать.

На данном этапе задача - это с микрофона ввести звук по шине I2S в ESP32 и вывести этот же звук по I2S на ЦАП.

Сразу честно скажу, что прям такого большого опыта с обработкой звука у меня нет. Были различные другие проекты с датчиками температуры, модулями Lora и т.д. Со звуком не работал и также с шиной I2S.

В интернете много различной информации, но вот как сделать одновременно - вводить и тут же выводить звук на/с ESP32 я не нашел... Если возможно, подскажите пожалуйста или направьте! Буду очень признателен. Если у кого был также опыт с шифрованием звука, то подскажите если можно (посоветуйте какую библиотеку или подобные проекты...).
СПАСИБО!
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
03.06.2021, 19:53
Ответы с готовыми решениями:

esp32 и i2s аудио
Всё подключил, работает. Но как только подношу палец близко - начинаются помехи (на видео они...

Ввод-вывод звука черезмикрофон/динамики - кто делал?
Дано: Windows(2000Prof), VS.NET 2003. Можно и обычный C++ от 5-ой студии ))) Народ - есть вопрос...

Ввод звука и его последующий вывод в записывающее устройство
На днях захотелось создать прогу, что-то на подобии эффекта рации. Программа по моей задумке должна...

Ввод и вывод структуры используя файлы
Помогите пожалуйста написать структуру используя файлы на С++. Очень срочно помогите пожалуйста...

19
1895 / 1213 / 121
Регистрация: 04.01.2010
Сообщений: 4,339
04.06.2021, 17:35 2
Цитата Сообщение от mike84 Посмотреть сообщение
Как сделать одновременно - вводить и тут же выводить звук на/с ESP32 я не нашел...
Для этого на ESP32 должно быть два I2S интерфейса. Иначе придется _пытаться_ колхозить его эквивалент, на таймерах и штатном SPI (опять же - если он доступен), скорее всего, при низком битрейте должно получиться.
Цитата Сообщение от mike84 Посмотреть сообщение
с микрофона ввести звук по шине I2S в ESP32 и вывести этот же звук по I2S на ЦАП.
тут как раз проблем нет - вешаете в режиме слейвов ЦАП и микрофон, и настраиваете клок шины на вашем МК. В итоге и МК и ЦАП будут получать одни и те же данные. ЦАП, при этом, скорее всего будет работать в одноканальном режиме, если его нельзя перевести в режим моно. Но...

вот можно ли передавать/принимать сигнал моно по I2S как по шине - я не знаю. Ничего, вроде бы не мешает. Но могут быть ньюансы. Например, может не хватить скорости МК, т.к. он постоянно будет должен переключать режим прием/передача для I2S, что не является его штатным режимом (по крайней мере я таким не пользовался). Для стерео данный трюк точно не подойдет.

Добавлено через 2 минуты
Цитата Сообщение от mike84 Посмотреть сообщение
шифрованием звука
вообще непонятно, что вы под этим понимаете. Шифрование в общем случае никак не относится к звуку, а относится к данным вообще. И сделать шифрование и дешифрование можно любыми имеющимися способами. Вопрос лишь в том, сможет ли линия передачи данных и динамический диапазон ЦАП "воспроизвести" и [принимающая сторона] "принять" такой сигнал. Обычно, весь этот процесс отталкивается от ограничений этой цепочки и линий связи, и совсем не от источника сигнала и цифровых интерфейсов.
0
-8 / 1 / 0
Регистрация: 02.01.2016
Сообщений: 69
05.06.2021, 14:35  [ТС] 3
Вот соорудил такой код в Arduini IDE.
Код
#include <driver/i2s.h>
const int sample_rate = 44100;
esp_err_t err1; esp_err_t err2;

uint16_t buf_len = 1024;
char *buf = (char*) calloc(buf_len, sizeof(char));
int bytes_written = 0;

void setup() {
  Serial.begin(115200);
  delay(100);
  Serial.println("  ");  Serial.println("Setup I2S ...");
  delay(1000);
  i2s_install();
  i2s_setpin();
  //i2s_start(I2S_NUM_1);
  //i2s_start(I2S_NUM_0);   
  delay(500);
}

void loop() {
   
   int bytes_read = 0;
   
   while(bytes_read == 0) {
      bytes_read = i2s_read_bytes(I2S_NUM_1, buf, buf_len, 0);
    }
   
   i2s_write_bytes(I2S_NUM_0, buf, bytes_read, portMAX_DELAY);

}
void i2s_install(){
    /* TX: I2S_NUM_0 */
  const i2s_config_t i2s_config_tx = {
    .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_TX),
    .sample_rate = sample_rate,
    .bits_per_sample = i2s_bits_per_sample_t(16),
    .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
    .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
    .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // default interrupt priority
    .dma_buf_count = 32,
    .dma_buf_len = 32 * 2,  // 2
     // .use_apll = false,
     // .tx_desc_auto_clear = false,  // I2S автоматически очищает дескриптор tx, если есть состояние недостаточного заполнения (помогает избежать шума в случае недоступности данных)
     // .fixed_mclk = 0 // I2S с использованием фиксированного выхода MCLK. Если use_apll = true и fixed_mclk> 0, то выходной сигнал часов для i2s фиксирован и равен значению fixed_mclk.
  };
  err1 = i2s_driver_install(I2S_NUM_0, &i2s_config_tx, 0, NULL);
  if (err1 != ESP_OK) {
  Serial.printf("Failed installing driver_1: %d\n", err1);
  while (true);
  }
       /* RX: I2S_NUM_1 */
  const i2s_config_t i2s_config_rx = {
    .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX),
    .sample_rate = sample_rate,
    .bits_per_sample = i2s_bits_per_sample_t(16), //32
    .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
    .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
    .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // default interrupt priority
    .dma_buf_count = 32,
    .dma_buf_len = 32 * 2,  //2
     // .use_apll = false,
     // .tx_desc_auto_clear = false,  // I2S автоматически очищает дескриптор tx, если есть состояние недостаточного заполнения (помогает избежать шума в случае недоступности данных)
     // .fixed_mclk = 0 // I2S с использованием фиксированного выхода MCLK. Если use_apll = true и fixed_mclk> 0, то выходной сигнал часов для i2s фиксирован и равен значению fixed_mclk.
  };
  err2 = i2s_driver_install(I2S_NUM_1, &i2s_config_rx, 0, NULL);
  if (err2 != ESP_OK) {
  Serial.printf("Failed installing driver_2: %d\n", err2);
  while (true);
  }
  Serial.println("I2S driver installed.");
}

void i2s_setpin(){
     /* TX: I2S_NUM_0 */
  const i2s_pin_config_t pin_config_tx = {
    .bck_io_num =   26,
    .ws_io_num =    25,
    .data_out_num = 22,
    .data_in_num =  I2S_PIN_NO_CHANGE  };
    
    err1 = i2s_set_pin(I2S_NUM_0, &pin_config_tx);
    if (err1 != ESP_OK) {
    Serial.printf("Failed setting pin_1: %d\n", err1);
    while (true);
    }
    /* RX: I2S_NUM_1 */
  const i2s_pin_config_t pin_config_rx = {
    .bck_io_num =   17,
    .ws_io_num =    27,
    .data_out_num = I2S_PIN_NO_CHANGE,
    .data_in_num =  33  };

    err2 = i2s_set_pin(I2S_NUM_1, &pin_config_rx);
    if (err2 != ESP_OK) {
    Serial.printf("Failed setting pin_2: %d\n", err2);
    while (true);
    }
  Serial.println("I2S pins installed.");
}
Но звук на выходе ЦАП искаженный по уровню (это я определил на слух). Если далеко говорить от микрофона, то более-менее, но тихо.
Посмотрите пожалуйста сам код, думаю что-то нужно подправить, но что конкретно пока не знаю.
0
-8 / 1 / 0
Регистрация: 02.01.2016
Сообщений: 69
07.06.2021, 13:42  [ТС] 4
Рабочий код такой. Свел все на один интерфейс I2S_NUM_0. Все работает отлично. А хрипело из-за того, что неправильно сделали обвязку TDA1543A. А когда подключил готовую плану на PCM5102A, то на выходе звук отличный.

Код
#include <driver/i2s.h>
const int sample_rate = 44100;
esp_err_t err;

uint16_t buf_len = 1024;
char *buf = (char*) calloc(buf_len, sizeof(char));
int bytes_written = 0;

void setup() {
  Serial.begin(115200);
  delay(100);
  Serial.println("  ");  Serial.println("Setup I2S ...");
  delay(1000);
  i2s_install();
  i2s_setpin();
  delay(500);
}

void loop() {
   int bytes_read = 0;
   while(bytes_read == 0) {
      bytes_read = i2s_read_bytes(I2S_NUM_0, buf, buf_len, 0);    
    }
   i2s_write_bytes(I2S_NUM_0, buf, bytes_read, portMAX_DELAY);  
}

void i2s_install(){
  const i2s_config_t i2s_config = {
    .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX),
    .sample_rate = sample_rate,
    .bits_per_sample = i2s_bits_per_sample_t(16),
    .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
    .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
    .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // default interrupt priority
    .dma_buf_count = 32,
    .dma_buf_len = 32 * 2,  
};
  err = i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
  if (err != ESP_OK) {
  Serial.printf("Failed installing driver_1: %d\n", err);
  while (true);
  }
  Serial.println("I2S driver installed.");
}

void i2s_setpin(){
     /* TX: I2S_NUM_0 */
  const i2s_pin_config_t pin_config = {
    .bck_io_num =   26,
    .ws_io_num =    25,
    .data_out_num = 22,
    .data_in_num =  33     
    };   
    
    err = i2s_set_pin(I2S_NUM_0, &pin_config);
    if (err != ESP_OK) {
    Serial.printf("Failed setting pin_1: %d\n", err);
    while (true);
    }
  Serial.println("I2S pins installed.");   Serial.println("  ");
}
Формат функции i2s_read_bytes:
Код
int i2s_read_bytes(i2s_port_t i2s_num, void *dest, size_t size, TickType_t ticks_to_wait) __attribute__ ((deprecated));

 * @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_start and i2s_adc_stop around the whole reading process, to prevent the data getting corrupted.
 * @return
 *     - ESP_OK               Success
 *     - ESP_ERR_INVALID_ARG  Parameter error
Формат функции i2s_write_bytes:
Код
int i2s_write_bytes(i2s_port_t i2s_num, const void *src, size_t size, TickType_t ticks_to_wait) __attribute__ ((deprecated));

 * @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
Если обратить внимание на код, то там есть buf. Я так понимаю, что в нем заложен сам звук, который вначале считывается, а потом передается на ЦАП. В каком формате этот buf?
Спрашиваю с той целью, чтобы между функциями i2s_read_bytes и i2s_write_bytes провести шифрование. Я так понимаю, что шифровать нужно именно значения buf.
0
-8 / 1 / 0
Регистрация: 02.01.2016
Сообщений: 69
09.06.2021, 12:39  [ТС] 5
Друзья, Привет!
В общем разобрался я и с шифрованием, но частично. Что я имею ввиду. Сам механизм шифрования готов и работает отлично. Единственное что ....
Вначале мы читаем звук с микрофона при помощи функции i2s_read_bytes в массив buf.
После чего шифруем этот массив, скажем получая buf1.
После отправляем массив buf1 на ЦАП при помощи функции i2s_write_bytes.

Так вот оказывается, что ничего не работает по следующе причине. Для того, чтобы функции шифрования обработать массив из 16 значений ей требуется 3 мс. Если взять буфер размером 32 или 64 значения, то соответственно необходимо время на шифрование 6 мс и 12 мс соответственно.

В динамике звук хрипит и шипит и вообще не похож на речь.
Вы скажите, так это же зашифрованный звук и есть!!! Ан нет....
Для проверки, между двумя функциями i2s_read_bytes и i2s_write_bytes я как и говорил вставил функцию шифрования, но через функцию i2s_write_bytes вывел первоначальный буфер buf. Получается что зашло, то и вышло, но с задержкой, равной работе функции шифрования.
Далее я пошел дальше. Просто удалил функцию шифрования и вместо нее вставил обычный delay. И стал играться с ним.

ИТОГ. Я не пойму почему так происходит? Ну да мы считали буфер buf, обработали шифрованием и получили buf1 либо просто вставили небольшую задержку, скажем 5-8 мс (delay(8)). После этого направили на ЦАП. Так вот на время обработки (задержки) и должна быть задержка между входом и выходом. Но почему именно хрипит и шипит??? Почему я не слышу свой же нормальный голос, но с небольшой задержкой?
0
1895 / 1213 / 121
Регистрация: 04.01.2010
Сообщений: 4,339
09.06.2021, 14:39 6
Цитата Сообщение от mike84 Посмотреть сообщение
После этого направили на ЦАП
нет, не направили. Я ж Вам писал выше - шина I2S это (почти) обычный SPI, в котором в момент работы не может быть несколько "отправителей" (что вы пытаетесь сделать). В данном случае, когда вы пытаетесь "отправлять" команды из ESP32 в момент передачи потока данных микрофоном, возникает коллизия. В худшем случае - могут выгореть выходные каскады пинов МК или микрофона, в лучшем - вы просто получите мусор на выходе. То есть это как раз то, о чем вы и говорите:
Цитата Сообщение от mike84 Посмотреть сообщение
хрипит и шипит
0
-8 / 1 / 0
Регистрация: 02.01.2016
Сообщений: 69
09.06.2021, 14:59  [ТС] 7
Цитата Сообщение от Voland_ Посмотреть сообщение
нет, не направили
В смысле не направили?
Вот код, который работает отлично! звук отличный на выходе ЦАП!

Эпизод 1.
Вначале мы читаем звук с микрофона по I2S при помощи функции i2s_read_bytes в массив buf.
После, отправляем по I2S массив buf на ЦАП при помощи функции i2s_write_bytes.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <driver/i2s.h>
const int sample_rate = 44100;
esp_err_t err;
 
uint16_t buf_len = 1024;
char *buf = (char*) calloc(buf_len, sizeof(char));
int bytes_written = 0;
 
void setup() {
  Serial.begin(115200);
  delay(100);
  Serial.println("  ");  Serial.println("Setup I2S ...");
  delay(1000);
  i2s_install();
  i2s_setpin();
  delay(500);
}
 
void loop() {
   int bytes_read = 0;
   while(bytes_read == 0) {
      bytes_read = i2s_read_bytes(I2S_NUM_0, buf, buf_len, 0);    
    }
   i2s_write_bytes(I2S_NUM_0, buf, bytes_read, portMAX_DELAY);  
}
 
void i2s_install(){
  const i2s_config_t i2s_config = {
    .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX),
    .sample_rate = sample_rate,
    .bits_per_sample = i2s_bits_per_sample_t(16),
    .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
    .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
    .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // default interrupt priority
    .dma_buf_count = 32,
    .dma_buf_len = 32 * 2,  
};
  err = i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
  if (err != ESP_OK) {
  Serial.printf("Failed installing driver_1: %d\n", err);
  while (true);
  }
  Serial.println("I2S driver installed.");
}
 
void i2s_setpin(){
     /* TX: I2S_NUM_0 */
  const i2s_pin_config_t pin_config = {
    .bck_io_num =   26,
    .ws_io_num =    25,
    .data_out_num = 22,
    .data_in_num =  33     
    };   
    
    err = i2s_set_pin(I2S_NUM_0, &pin_config);
    if (err != ESP_OK) {
    Serial.printf("Failed setting pin_1: %d\n", err);
    while (true);
    }
  Serial.println("I2S pins installed.");   Serial.println("  ");
}
Вы Voland_ это понимаете? что тут все работает отлично!

Эпизод 2.
Только теперь, если что-то вставить между функций i2s_read_bytes и i2s_write_bytes, что обрабатывается несколько миллисекунд (6-8 мс), то начинается хрипеть и шипеть, что абсолютно не похоже на голос.
Вопрос: Почему так происходит?
Ну да мы считали буфер buf, далее небольшая задержка скажем 5-8 мс. После этого направили на ЦАП. Почему я не слышу свой же нормальный голос, но с небольшой задержкой (5-8 мс)?

Voland_ - вы вначале прочитайте внимательно, просмотрите код, ну а потом уже ..... ля-ля....

Добавлено через 5 минут
Цитата Сообщение от Voland_ Посмотреть сообщение
не может быть несколько "отправителей" (что вы пытаетесь сделать)
поясните пожалуйста, если можете.
0
1895 / 1213 / 121
Регистрация: 04.01.2010
Сообщений: 4,339
09.06.2021, 15:05 8
Цитата Сообщение от mike84 Посмотреть сообщение
Вы Voland_ это понимаете? что тут все работает отлично!
я понимаю, что вы заблуждаетесь . ну, или я просто не вник в особенности вашей системы.
Цитата Сообщение от mike84 Посмотреть сообщение
вы вначале прочитайте внимательно, просмотрите код, ну а потом уже ..... ля-ля....
покажите диаграммы на ногах интерфейса I2S, поэкспериментируйте с шиной, и все (не сразу) станет ясно.
прочитайте внимательно спецификацию I2S, если мне не верите ).
PS: методом тыка, которые вы в данный момент пытаетесь использовать, не читая ни спецификации, ни даташитов, ни схем - вашу задачу не решишь.
0
-8 / 1 / 0
Регистрация: 02.01.2016
Сообщений: 69
09.06.2021, 16:16  [ТС] 9
Цитата Сообщение от Voland_ Посмотреть сообщение
я понимаю, что вы заблуждаетесь .
Вы утверждаете, что приведенный мной код не рабочий?

Вы можете конкретно подсказать, что нужно сделать, чтобы было правильно?

Вы можете ответить на этот вопрос?
Цитата Сообщение от mike84 Посмотреть сообщение
Только теперь, если что-то вставить между функций i2s_read_bytes и i2s_write_bytes, что обрабатывается несколько миллисекунд (6-8 мс), то начинается хрипеть и шипеть, что абсолютно не похоже на голос.
Вопрос: Почему так происходит?
Ну да мы считали буфер buf, далее небольшая задержка скажем 5-8 мс. После этого направили на ЦАП. Почему я не слышу свой же нормальный голос, но с небольшой задержкой (5-8 мс)?
0
2593 / 1869 / 406
Регистрация: 11.09.2009
Сообщений: 6,937
10.06.2021, 01:55 10
Цитата Сообщение от mike84 Посмотреть сообщение
Вы можете ответить на этот вопрос?
Поставьте в вашем коде задержку не 6-8 мс, а несколько секунд, и сразу всё поймёте сами.
Конвейер надо делать.
1
-8 / 1 / 0
Регистрация: 02.01.2016
Сообщений: 69
10.06.2021, 08:03  [ТС] 11
Цитата Сообщение от i8085 Посмотреть сообщение
Поставьте в вашем коде задержку не 6-8 мс, а несколько секунд, и сразу всё поймёте сами.
Конвейер надо делать.
Сегодня обязательно сделаю, но уже предвижу, что там будет полная ерунда... Если от 6-8 мс такое, то если 1-2 с, вообще будет ....
Пожалуйста растолкуйте, что за конвейер... Как его сделать, где посмотреть?
0
1895 / 1213 / 121
Регистрация: 04.01.2010
Сообщений: 4,339
10.06.2021, 09:26 12
Цитата Сообщение от mike84 Посмотреть сообщение
Вы можете ответить на этот вопрос?
я ответил уже на Ваш вопрос.
Цитата Сообщение от Voland_ Посмотреть сообщение
В данном случае, когда вы пытаетесь "отправлять" команды из ESP32 в момент передачи потока данных микрофоном, возникает коллизия.
По-прежнему остаюсь верен этому объяснению

Добавлено через 4 минуты
Цитата Сообщение от i8085 Посмотреть сообщение
Поставьте в вашем коде задержку не 6-8 мс, а несколько секунд
Вы напишите ТС, что он может получить, и что это из этого следует ).
0
-8 / 1 / 0
Регистрация: 02.01.2016
Сообщений: 69
10.06.2021, 09:46  [ТС] 13
Цитата Сообщение от Voland_ Посмотреть сообщение
я ответил уже на Ваш вопрос.
Цитата Сообщение от Voland_ Посмотреть сообщение
По-прежнему остаюсь верен этому объяснению
Voland_, в Ваших ответах нет никакой конкретики, Вы пишите, что это коллизия, что изучите I2S... но это общие слова... И так понятно, что что-то не работает... а вот почему конкретно?... Так обычно советуют люди, которые не совсем в этом разбираются... Например: я подвешиваю на нитку 5 килограмм... почему она все время рвется??? Ваш ответ: изучите всю Теоретическую механику и Детали машин и вы найдете ответ... Конкретный ответ: попробуйте использовать нитку потолще или канатик.

Вот i8085 посоветовал применить конвейер, это конкретное предложение, сейчас изучаю что это и как применить.
0
1895 / 1213 / 121
Регистрация: 04.01.2010
Сообщений: 4,339
10.06.2021, 10:03 14
mike84, такое ощущение, что Вы здесь занимаетесь не своим делом ). Я ж вам еще в первом своем посте написал что надо делать:
Цитата Сообщение от Voland_ Посмотреть сообщение
Для этого на ESP32 должно быть два I2S интерфейса. Иначе придется _пытаться_ колхозить его эквивалент, на таймерах и штатном SPI (опять же - если он доступен), скорее всего, при низком битрейте должно получиться.
Это ключевое, что вы должны были прочитать. И да, естественно, что этот подход так или иначе предполагает:
Цитата Сообщение от i8085 Посмотреть сообщение
Конвейер надо делать.
PS: читаете не внимательно.

Цитата Сообщение от mike84 Посмотреть сообщение
Конкретный ответ: попробуйте использовать нитку потолще или канатик.
ну, если вы не в теме, то вы не знаете что такое "нитка", "потолще" и "канатик". Вот так и происходит - вы пытаетесь вникнуть в тему, в которой ничего не понимаете. (не в обиду)
0
-8 / 1 / 0
Регистрация: 02.01.2016
Сообщений: 69
10.06.2021, 10:10  [ТС] 15
Цитата Сообщение от Voland_ Посмотреть сообщение
Это ключевое, что вы должны были прочитать. И да, естественно, что этот подход так или иначе предполагает:
По ходу Вы и тут не в курсе, что на ESP32 есть 2 интерфейса I2S, раз предлагаете там что-то колхозить...
Цитата Сообщение от Voland_ Посмотреть сообщение
PS: читаете не внимательно.
Это я прочитал сразу и сразу ответил, одновременно начав изучать. Про конвейер написали на Вы...
Цитата Сообщение от mike84 Посмотреть сообщение
Пожалуйста растолкуйте, что за конвейер... Как его сделать, где посмотреть?
Voland_, заканчивайте заполнять тему пустой информацией! Толку с того, что вы пишите... одни препирательства.
0
1895 / 1213 / 121
Регистрация: 04.01.2010
Сообщений: 4,339
10.06.2021, 11:31 16
Цитата Сообщение от mike84 Посмотреть сообщение
По ходу Вы и тут не в курсе, что на ESP32 есть 2 интерфейса I2S, раз предлагаете там что-то колхозить
да, не в курсе. А обязан? Если есть два I2S то все проще конечно.
Цитата Сообщение от mike84 Посмотреть сообщение
заканчивайте заполнять тему пустой информацией!
Вы задали вопрос, пытаюсь на него ответить. В чем проблема? Впредь буду знать, что вам помогать - сизифов труд. Всего хорошего!
0
2760 / 1271 / 166
Регистрация: 28.10.2011
Сообщений: 4,697
Записей в блоге: 6
11.06.2021, 12:36 17
Цитата Сообщение от mike84 Посмотреть сообщение
По ходу Вы и тут не в курсе, что на ESP32 есть 2 интерфейса I2S, раз предлагаете там что-то колхозить
Вы работаете только с одним.
Цитата Сообщение от mike84 Посмотреть сообщение
C
1
2
3
4
    while(bytes_read == 0) {
      bytes_read = i2s_read_bytes(I2S_NUM_0, buf, buf_len, 0);    
    }
   i2s_write_bytes(I2S_NUM_0, buf, bytes_read, portMAX_DELAY);
0
-8 / 1 / 0
Регистрация: 02.01.2016
Сообщений: 69
11.06.2021, 12:46  [ТС] 18
Цитата Сообщение от locm Посмотреть сообщение
Вы работаете только с одним.
Согласен. Вначале я развел на два, но потом свёл в один. Но когда было на два, я не пробовал с задержками между функциями i2s_read_bytes и i2s_write_bytes.
Сегодня вернусь назад и попробую.
Пока читаю, изучаю как организовать конвейер.

Добавлено через 5 минут
Свёл в один I2S потому, что хотел в последствии к ESP32 подсоединить по второму I2S модем.
0
2760 / 1271 / 166
Регистрация: 28.10.2011
Сообщений: 4,697
Записей в блоге: 6
11.06.2021, 13:27 19
Цитата Сообщение от mike84 Посмотреть сообщение
я не пробовал с задержками между функциями i2s_read_bytes и i2s_write_bytes.
Задержек быть не должно. Функции должны выполнятся одновременно чтобы поток был непрерывным. Обычно это достигается используя DMA с прерываниями по приему/передаче половины и всего массива.
1
-8 / 1 / 0
Регистрация: 02.01.2016
Сообщений: 69
11.06.2021, 17:07  [ТС] 20
Цитата Сообщение от locm Посмотреть сообщение
Задержек быть не должно. Функции должны выполнятся одновременно чтобы поток был непрерывным.
Я понимаю, что задержек не должно быть, но мне нужно работать с прочитанными данными, после чего отправить.
Т.е. звук с микрофона по I2S при помощи функции i2s_read_bytes считывается в массив buf.
После чего данный массив обрабатывается и отправляется функцией i2s_write_bytes также по I2S на ЦАП.
Обработка занимает время 10-15 мс для buf_len = 64. Для эксперимента я пробую, устанавливая delay(12).

Если установить delay(12) и buf_len = 1024, то все прекрасно. Если установить buf_len = 64, то все хрипит.

Но тут один момент. Чем больше в данном случае буфер (buf_len), тем дольше он будет обрабатываться и, соответственно, это уже будет не 10-15 мс.
Проведя измерения (при помощи millis), я получил, что 16 элементов буфера обрабатываются (библиотекой шифрования aes) в среднем 3 мс. Таким образом устанавливать большое значение buf_len не получается.

В этом коде я опять разделил на 2 интерфейса I2S, на I2S_NUM_0 и I2S_NUM_1. Результат тот же.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <driver/i2s.h>
const int sample_rate = 44100;
esp_err_t err1; 
esp_err_t err2;
 
uint16_t buf_len = 64;
char *buf = (char*) calloc(buf_len, sizeof(char));
int bytes_written = 0;
 
void setup() {
  Serial.begin(115200);
  delay(100);
  Serial.println("  ");  Serial.println("Setup I2S ...");
  delay(1000);
  i2s_install();
  i2s_setpin();
  delay(500);
}
 
void loop() {
   int bytes_read = 0;
   
   while(bytes_read == 0) {
      bytes_read = i2s_read_bytes(I2S_NUM_1, buf, buf_len, 0);
   }
 
   delay(12);
   
   i2s_write_bytes(I2S_NUM_0, buf, bytes_read, portMAX_DELAY);
}
 
void i2s_install(){
    /* TX: I2S_NUM_0 */
  const i2s_config_t i2s_config_tx = {
    .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_TX),
    .sample_rate = sample_rate,
    .bits_per_sample = i2s_bits_per_sample_t(16),
    .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
    .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
    .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // default interrupt priority
    .dma_buf_count = 32,
    .dma_buf_len = 32 * 2,  // 2
  };
  err1 = i2s_driver_install(I2S_NUM_0, &i2s_config_tx, 0, NULL);
  if (err1 != ESP_OK) {
  Serial.printf("Failed installing driver_1: %d\n", err1);
  while (true);
  }
       /* RX: I2S_NUM_1 */
  const i2s_config_t i2s_config_rx = {
    .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX),
    .sample_rate = sample_rate,
    .bits_per_sample = i2s_bits_per_sample_t(16), //32
    .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
    .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
    .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // default interrupt priority
    .dma_buf_count = 32,
    .dma_buf_len = 32 * 2,  //2
  };
  err2 = i2s_driver_install(I2S_NUM_1, &i2s_config_rx, 0, NULL);
  if (err2 != ESP_OK) {
  Serial.printf("Failed installing driver_2: %d\n", err2);
  while (true);
  }
  Serial.println("I2S driver installed.");
}
 
void i2s_setpin(){
     /* TX: I2S_NUM_0 */
  const i2s_pin_config_t pin_config_tx = {
    .bck_io_num =   26,
    .ws_io_num =    25,
    .data_out_num = 22,
    .data_in_num =  I2S_PIN_NO_CHANGE  };
    
    err1 = i2s_set_pin(I2S_NUM_0, &pin_config_tx);
    if (err1 != ESP_OK) {
    Serial.printf("Failed setting pin_1: %d\n", err1);
    while (true);
    }
    /* RX: I2S_NUM_1 */
  const i2s_pin_config_t pin_config_rx = {
    .bck_io_num =   17,
    .ws_io_num =    27,
    .data_out_num = I2S_PIN_NO_CHANGE,
    .data_in_num =  33  };
 
    err2 = i2s_set_pin(I2S_NUM_1, &pin_config_rx);
    if (err2 != ESP_OK) {
    Serial.printf("Failed setting pin_2: %d\n", err2);
    while (true);
    }
  Serial.println("I2S pins installed.");
}
Вот в этом у меня и загвоздка, что нужно обработать звук перед отправкой.

Добавлено через 3 часа 1 минуту
Нашел вот такой пример по созданию конвейера.
Тут поток звука грузится с интернета, декодируется и направляется далее по I2S.
Вижу, что тут много лишнего в плане логирования и вывода информации о самом процессе. Пока ухватить основное и как всё это работает не могу... Если кто может, подскажите, если этот пример мне подходит, то какие основные команды, функции чтобы решить мою задачу.
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
11.06.2021, 17:07

Расчет по формуле. Ввод и вывод, используя текстовые поля
Помогите пожалуста!Нужно сделать прогу которая рассчитывает значение по формуле : x=100/ n +y ,...

Ввод/вывод данных организовать, используя книгу Excel
Здравствуйте Ввод/вывод данных организовать, используя книгу Excel. Дан одномерный...

Ввод и вывод строк осуществлять, используя функции gets и puts
Задана строка, содержащая целые числа и слова, разделенные пробелами (одним или несколькими)....

Рассчитать значение функции, используя массив (файловый ввод/вывод)
Дается массив из след.элементов(44 штуки):...

Ввод - вывод в типизированый файл используя процедуры как исправить
Ввод - вывод в типизированый файл используя процедуры Во время выполнения показывает ошибку 103...

Подскажите как выполнить задачу используя блоковый ввод-вывод
Подскажите как это реализовать в коде ну или скиньте пожалуйста ссылки на информацию ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.