New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
adc i2s mode with multiple channel pattern (IDFGH-803) #1991
base: master
Are you sure you want to change the base?
Conversation
b3a56e3
to
ef2d34e
Compare
Andrew Dikarev seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account. You have signed the CLA already but the status is still pending? Let us recheck it. |
@phonec I've bumped into your work, as I'm trying to read all 8 channels of ADC1 simultaneously using I2S. What's the status of your pull request? The PR here redefines the API slightly, but before I take a closer look and patch this in, I was wondering if you had success in your own applications using this patch. Could you let me know ? |
@pimvanpelt, The status of this request is still active, I think that this is the required functionality and should be useful to many. I use it in an energy meter with detect current leak with two current and one voltage sensors, this patch allows me to solve this task with a high I2S sampling rate of 96KHz for all sensors. |
In this context the declaration of the adc_i2s_pattern[] inside the function should be 'static'.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
adc i2s mode with multiple channel pattern #1991
adc i2s mode with multiple channel pattern espressif#1991
Any updates when this can be merge to master? |
@phonec Can you post a multichannel initialisation example? I'm running into weird problems, like dropped samples. |
@szmodz, use only one I2S channel with the option I2S_CHANNEL_FMT_ONLY_RIGHT, try the initialization example
|
Tangentally related -- I have an ESP32 multichan (8 channels) I2S
implementation based on this work living here:
https://github.com/pimvanpelt/apc7920/blob/master/firmware/src/i2s.c
…On Tue, Mar 19, 2019 at 3:24 PM szmodz ***@***.***> wrote:
@phonec <https://github.com/phonec> Can you post a multichannel
initialisation example? I'm running into weird problems, like dropped
samples.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#1991 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AIcZPaziMHzH7BAZQIMyWmxOM_8_PEkpks5vYPMxgaJpZM4UKpsC>
.
--
Pim van Pelt <pim@ipng.nl>
PBVP1-RIPE - http://www.ipng.nl/
|
@phonec I'm using the same config with a different sample rate, buffer size and 4 channels instead of 2. It keeps losing 2 samples after exactly 254 correct samples. If I change ADC_MAX_MEAS_NUM_DEFAULT in rtc_module.c to 127, there are 2 lost samples after each 126 correct samples, so it seems this is related to the APB_SARADC_MAX_MEAS_NUM value (adc_set_measure_limit in rtc_module.c). Disabling the limit doesn't work. This is only easily noticeable when the pattern table size is greater than 2. With a pattern table length of 3, it goes insane. Any idea what's going on? The TRM is not exactly helpful here. BTW. the check in adc_i2s_mode_init and adc_set_i2s_data_len disallows a 16 entry pattern table. |
Setting ADC_MAX_MEAS_NUM_DEFAULT (rtc_module.c) to 2 seems to fix this. No idea why though. Using I2S_CHANNEL_FMT_ONLY_LEFT orders the samples correctly, starting from the first pattern table entry. |
That's not the whole story though. There are some weird interactions between the config options, ADC_MAX_MEAS_NUM_DEFAULT, the pattern table size and sample order. |
@szmodz this PR only adds the ability to configure multiple channels and does not solve possible future issues. Unfortunately, I can not reproduce this repeatedly. Maybe you have an example clearly demonstrating the loss of samples? |
@phonec not a complete example, but should be enough. Call testStart(). Should print:
Breaks in the repeating patterns can be seen. One would expect to see a repeating pattern equal in length to the pattern table length. pattern table lengths of 4 and 8 seem to work with ADC_MAX_MEAS_NUM_DEFAULT=2 I2S_CHANNEL_FMT_ONLY_LEFT / I2S_CHANNEL_FMT_ONLY_RIGHT seems to affect the order within the pattern only didn't check if the samples are actually regularly spaced. |
@phonec it's much worse with a pattern table length of 3 or 6. |
@szmodz Thanks for the example, really weird behavior with a loss in the sequence of samples. |
@szmodz, e.g: thanks !! |
Allow configuring ADC DMA via the i2s peripheral for multiple channels, instead of hard limiting it to a single channel. See-also: espressif#1991 Signed-off-by: Karl Palsson <karlp@tweak.net.au>
Sorry for this very late feedback. (I got so feed up with ESP32 for a while, even though I love it.) And as @szmodz says, use only One channel, regardless 1-8 inputs.
And the above of course uses other #define's for buffers and such but it's based on the examples/peripherals/i2s_adc_dac/main/app_main.c |
Add a new API for configuring ADC DMA via the i2s peripheral for multiple channels, but leave the existing API for a single channel in place. Inspired by: espressif#1991 Signed-off-by: Karl Palsson <karlp@tweak.net.au>
Hello, For initializing I2S I use the same code as @amedes.The problem is that the i2s_read function only writes zeros to the buffer if I use a sample rate higher than 10 ksps, for example '.sample_rate = 20000". Have any of you guys encountered a similar problem? @giPeteR could you tell me what you had to change to achieve a sample rate of 2Msps? |
@kletze this is the code for 2Msps.
But the ADC samples have much noise like this (captured 10kHz sine wave). |
Thanks @amedes for sharing your code. But when reading from the DMA buffer with the library function "i2s_read(I2S_NUM_0, (char*)i2s_read_buff, i2s_read_len, &bytes_read, portMAX_DELAY);" the function still returns all zeros. In my application, everything works as expected as long as my sample rate is less than 10 ksps. But as soon as I increase the sample rate to more than 10 ksps, the i2s_read function returns only zeros. Is there anything specific I need to consider when reading from the DMA buffer? |
@kletze here is my test code. I compiled the code using ESP-IDF v4.2.
|
Hi @amedes, I updated from esp-idf v4.1 to v4.2. Now the code is working as it should. Thank you very much for you patience. |
what is the status of this? I tried rebasing it but without luck, too many conflicts which I cannot resolve. |
This is my application h library
c library
|
Thank you a lot!
…_________________________________________
***@***.***
TRUCCO MATTIA
R&D
(HQ) Corso Orbassano, 416/10
10137 Torino – ITALY
Ph: +39 011 9027012
Fax: +39 011 9040782
Mail: ***@***.***<http://www.kgrse.it/>
Web: http://www.kgrse.it<http://www.kgrse.it/>
Web: http://www.caar-to.it<http://www.caar-to.it/>
Company of CAAR Group
***@***.***
C.A.A.R. GROUP:
Headquarter: Torino (Italy)
Subsidiaries: Bolzano (Italy) – Corato (Italy) - Belo Horizonte (Brazil) - Kragujevac (Serbia)
Da: hasan kara ***@***.***>
Inviato: giovedì 24 marzo 2022 13:37
A: espressif/esp-idf ***@***.***>
Cc: Mattia Trucco ***@***.***>; Comment ***@***.***>
Oggetto: Re: [espressif/esp-idf] adc i2s mode with multiple channel pattern (IDFGH-803) (#1991)
This is my application
h library
#pragma once
#include "driver/adc.h"
#include "stdint.h"
//\\\_\__\___\____\_____\______
//\\\ TYPEDEFS
//\\\_\__\___\____\_____\______
typedef struct
{
float x[2];
float y[2];
} lin_interp_ts;
///\\\-\---\----\------\-------\--------\----------\-----------\-------------
extern float lin_interp_calc(lin_interp_ts *li, float val);
extern float lin_interp_raw(float x0, float y0, float x1, float y1, float val);
///\\\-\---\----\------\-------\--------\----------\-----------\-------------
extern long adc_result[ADC1_CHANNEL_MAX];
extern void app_adc_start(void);
c library
/*
* ADC1 SCAN MODE CONVERSION
*/
//\\\_\__\___\____\_____\______
//\\\ INCLUDES
//\\\_\__\___\____\_____\______
#include "AnalogRead.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_event_loop.h"
#include "soc/syscon_periph.h"
#include "driver/i2s.h"
#include <driver/adc.h>
#include <driver/dac.h>
//\\\_\__\___\____\_____\______
//\\\ DEFINES
//\\\_\__\___\____\_____\______
#define SAMPLE_RATE (100000)
#define I2S_NUM (0)
#define filt_w 100
#define TEST_SGN_EN 1
#define TEST_SGN_ADC_CHAN ADC1_CHANNEL_4
#define TEST_SGN_DAC_CHAN DAC_CHANNEL_1
//\\\_\__\___\____\_____\______
//\\\ VARIABLES
//\\\_\__\___\____\_____\______
long adc_result[ADC1_CHANNEL_MAX];
static uint32_t adc_tot[ADC1_CHANNEL_MAX];
static uint32_t adc_head[ADC1_CHANNEL_MAX];
static int32_t adc_summ[filt_w][ADC1_CHANNEL_MAX];
static QueueHandle_t s_i2s_event_queue;
static uint16_t i2s_read_buff[filt_w * ADC1_CHANNEL_MAX ];
///\\\-\---\----\------\-------\--------\----------\-----------\-------------
static const int adc_x[] = {
0,
100,
200,
300,
400,
500,
600,
700,
800,
900,
1000,
1100,
1200,
1300,
1400,
1500,
1600,
1700,
1800,
1900,
2000,
2100,
2200,
2300,
2400,
2500,
2600,
2700,
2800,
2900,
3000,
3100,
3200,
3300,
3400,
3500,
3600,
3700,
3800,
3900,
4000,
4100,
};
static const int adc_y[] = {
129,
209,
289,
371,
453,
534,
610,
690,
773,
854,
932,
1009,
1089,
1167,
1246,
1327,
1404,
1483,
1563,
1644,
1723,
1800,
1883,
1962,
2044,
2127,
2203,
2282,
2362,
2438,
2514,
2590,
2666,
2742,
2818,
2894,
2970,
3046,
3122,
3198,
3274,
3350};
///\\\-\---\----\------\-------\--------\----------\-----------\-------------
float lin_interp_calc(lin_interp_ts *li, float val)
{
float ca = (li->y[1] - li->y[0]) / (li->x[1] - li->x[0]);
float cb = li->y[0] - li->x[0]* ca;
return (ca * val + cb);
}
float lin_interp_raw(float x0, float y0, float x1, float y1, float val)
{
lin_interp_ts li = { .x[0] = x0, .y[0] = y0, .x[1] = x1, .y[1] = y1 };
return lin_interp_calc(&li, val);
}
///\\\-\---\----\------\-------\--------\----------\-----------\-------------
int adc_raw2volt(int raw)
{
int ind = raw / 100;
int max = (sizeof(adc_x) / sizeof(int)) - 2;
if (ind > max)
{
ind = max;
}
int result = (int)lin_interp_raw(adc_x[ind], adc_y[ind], adc_x[ind + 1], adc_y[ind + 1], raw);
return result;
}
///\\\-\---\----\------\-------\--------\----------\-----------\-------------
size_t bytes_read = 0;
static void _adc_scanner(void *arg)
{
#if (TEST_SGN_EN)
dac_output_enable(TEST_SGN_DAC_CHAN);
#endif
vTaskDelay(10 / portTICK_PERIOD_MS);
i2s_adc_enable(I2S_NUM);
while (1)
{
int i2s_read_len = filt_w * ADC1_CHANNEL_MAX * 2 ;
system_event_t evt;
if (xQueueReceive(s_i2s_event_queue, &evt, portMAX_DELAY) != pdPASS)
{
ESP_LOGI("i2s", "No event to consume - consider reducing i2s_scanner frequency");
continue;
}
if (evt.event_id != 2)
{ // Event is not I2S_EVENT_RX_DONE
ESP_LOGI("i2s", "Event %d received, skipping", evt.event_id);
continue;
}
i2s_read(I2S_NUM, (char *)i2s_read_buff, i2s_read_len, &bytes_read, 0);
for (int i = 0; i < bytes_read / 2; i++)
{
uint8_t chan = (i2s_read_buff[i] >> 12) & 0x07;
uint16_t adc_value = i2s_read_buff[i] & 0xfff;
/*en eski deger cikarilir*/
adc_tot[chan] -= adc_summ[adc_head[chan]][chan];
adc_summ[adc_head[chan]][chan] = adc_value;
/*en yeni deger eklenir*/
adc_tot[chan] += adc_summ[adc_head[chan]][chan];
adc_head[chan]++;
if (adc_head[chan] >= filt_w)
adc_head[chan] = 0;
}
for (int i = 0; i < ADC1_CHANNEL_MAX; i++)
{
adc_result[i] = adc_raw2volt(adc_tot[i] / filt_w);
}
#if (TEST_SGN_EN)
dac_output_voltage(TEST_SGN_DAC_CHAN, adc_result[TEST_SGN_ADC_CHAN] * 256 / 3350);
#endif
}
}
void app_adc_start(void )
{
i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN,
.sample_rate = SAMPLE_RATE,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.dma_buf_count = 4,
.dma_buf_len = 128,
.use_apll = true,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1};
i2s_driver_install(I2S_NUM, &i2s_config, 2, &s_i2s_event_queue);
i2s_set_adc_mode(I2S_NUM, ADC1_CHANNEL_0);
// This 32 bit register has 4 bytes for the first set of channels to scan.
// Each byte consists of:
// [7:4] Channel
// [3:2] Bit Width; 3=12bit, 2=11bit, 1=10bit, 0=9bit
// [1:0] Attenuation; 3=11dB, 2=6dB, 1=2.5dB, 0=0dB
WRITE_PERI_REG(SYSCON_SARADC_SAR1_PATT_TAB1_REG, 0x3F2f1f0F);
WRITE_PERI_REG(SYSCON_SARADC_SAR1_PATT_TAB2_REG, 0x7F6F5F4F);
WRITE_PERI_REG(SYSCON_SARADC_SAR1_PATT_TAB3_REG, 0);
WRITE_PERI_REG(SYSCON_SARADC_SAR1_PATT_TAB4_REG, 0);
// Scan multiple channels.
SET_PERI_REG_BITS(SYSCON_SARADC_CTRL_REG, SYSCON_SARADC_SAR1_PATT_LEN, 0x7, SYSCON_SARADC_SAR1_PATT_LEN_S);
// The raw ADC data is written to DMA in inverted form. Invert back.
SET_PERI_REG_MASK(SYSCON_SARADC_CTRL2_REG, SYSCON_SARADC_SAR1_INV);
xTaskCreate(_adc_scanner, "adc_scanner", 1024 * 2, NULL, 100, NULL);
}
—
Reply to this email directly, view it on GitHub<#1991 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AW5YUU7DP3VSV5QXQUPVOO3VBROU7ANCNFSM4FBKTMBA>.
You are receiving this because you commented.Message ID: ***@***.******@***.***>>
|
this code help me a lot, thanks!!!!!!!!!!!!!!!! |
hello, i wonder why it need to XOR when output the data printf("%d\n", buf[i ^ 1] & 0x0fff);,is there anything i miss in the ESP-IDF programming guide? I would appreciate it if you could reply me. |
Please see Figure70 mode1 in TRM ver.4.6 p309. Figure 70: Modes of Writing Received Data into FIFO, ESP32 TRM (Version 4.6) p309 |
i already understand it, thanks a lot for your reply, wish you have a good day 👍 |
|
Hi all. |
Folks, I need to ask a very basic and stupid question: If the i2s configuration was made to capture two ADC signals with DMA such as channel 0 and channel 6, for instance, how to inform the buffers should be used for each channel ? Sorry for this question but every examples shows only the configutarion... I could not find any complete example that shows what to do next to finally get access to ADC values........ |
|
Hi, the channel# is part of recorded adc-value: bits <...> channel; bits<...> adc-value. So all values go into same buffer and you have to get from each value the channel#.
Am 2. August 2023 05:34:47 MESZ schrieb AntonioFromBrazil ***@***.***>:
…Folks, I need to ask a very basic and stupid question: If the i2s configuration was made to capture two ADC signals with DMA such as channel 0 and channel 6, for instance, how to inform the buffers should be used for each channel ? Sorry for this question but every examples shows only the configutarion... I could not find any complete example that shows what to do next to finally get access to ADC values........
--
Reply to this email directly or view it on GitHub:
#1991 (comment)
You are receiving this because you commented.
Message ID: ***@***.***>
|
channel 4 bits ; adc-value (resolution) 12 bits => 16 bit
so you read from buffer 2byte and get channel and adc-valur
Am 2. August 2023 11:19:16 MESZ schrieb Ulli ***@***.***>:
…Hi, the channel# is part of recorded adc-value: bits <...> channel; bits<...> adc-value. So all values go into same buffer and you have to get from each value the channel#.
Am 2. August 2023 05:34:47 MESZ schrieb AntonioFromBrazil ***@***.***>:
>Folks, I need to ask a very basic and stupid question: If the i2s configuration was made to capture two ADC signals with DMA such as channel 0 and channel 6, for instance, how to inform the buffers should be used for each channel ? Sorry for this question but every examples shows only the configutarion... I could not find any complete example that shows what to do next to finally get access to ADC values........
>
>--
>Reply to this email directly or view it on GitHub:
>#1991 (comment)
>You are receiving this because you commented.
>
>Message ID: ***@***.***>
|
possibly the channel bits there have also the adc-unit included: adc-unit (0 or 1) 2bits, channel (0...8) 2bits. check documentation, I'am not sure :-)
Am 2. August 2023 11:28:24 MESZ schrieb Ulli ***@***.***>:
…channel 4 bits ; adc-value (resolution) 12 bits => 16 bit
so you read from buffer 2byte and get channel and adc-valur
Am 2. August 2023 11:19:16 MESZ schrieb Ulli ***@***.***>:
>Hi, the channel# is part of recorded adc-value: bits <...> channel; bits<...> adc-value. So all values go into same buffer and you have to get from each value the channel#.
>
>Am 2. August 2023 05:34:47 MESZ schrieb AntonioFromBrazil ***@***.***>:
>>Folks, I need to ask a very basic and stupid question: If the i2s configuration was made to capture two ADC signals with DMA such as channel 0 and channel 6, for instance, how to inform the buffers should be used for each channel ? Sorry for this question but every examples shows only the configutarion... I could not find any complete example that shows what to do next to finally get access to ADC values........
>>
>>--
>>Reply to this email directly or view it on GitHub:
>>#1991 (comment)
>>You are receiving this because you commented.
>>
>>Message ID: ***@***.***>
|
a working example you find at:
https://www.sciencedirect.com/science/article/pii/S2468067222000013
-> chapter esp32 implementation
link to code within this article
Am 2. August 2023 11:37:39 MESZ schrieb Ulli ***@***.***>:
…possibly the channel bits there have also the adc-unit included: adc-unit (0 or 1) 2bits, channel (0...8) 2bits. check documentation, I'am not sure :-)
Am 2. August 2023 11:28:24 MESZ schrieb Ulli ***@***.***>:
>channel 4 bits ; adc-value (resolution) 12 bits => 16 bit
>
>so you read from buffer 2byte and get channel and adc-valur
>
>Am 2. August 2023 11:19:16 MESZ schrieb Ulli ***@***.***>:
>>Hi, the channel# is part of recorded adc-value: bits <...> channel; bits<...> adc-value. So all values go into same buffer and you have to get from each value the channel#.
>>
>>Am 2. August 2023 05:34:47 MESZ schrieb AntonioFromBrazil ***@***.***>:
>>>Folks, I need to ask a very basic and stupid question: If the i2s configuration was made to capture two ADC signals with DMA such as channel 0 and channel 6, for instance, how to inform the buffers should be used for each channel ? Sorry for this question but every examples shows only the configutarion... I could not find any complete example that shows what to do next to finally get access to ADC values........
>>>
>>>--
>>>Reply to this email directly or view it on GitHub:
>>>#1991 (comment)
>>>You are receiving this because you commented.
>>>
>>>Message ID: ***@***.***>
|
Thanks everyone for advice. I tryied to use a couple of examples but I did not succeded. I think my problem is much easier than the examples showned. What I want is just transform the code bellow to read two channels simultaneoulsly. As it is bellow it is working well for one channel only... Thanks again for any help.
|
So I will be forever grateful if someone would help me in this question. I am trying hard to underestand the i2s Espressif docs but sincerelly it is too much confuse and look like it is for professionals only. Unfortunatelly it is not my case :( |
On @phonec post dated from March,19,2023, about how to read two ADC channels with i2s/DMA (copied bellow), the code uses adc_i2s_pattern_t function that is NOT present in none of available IDF versions. Would you please tell me what version did you use to compile the code or where can I find the adc_i2s_pattern_t function ? Thanks
|
This allows you to simultaneously scan multiple ADC1 channels in accordance with the pattern table that defines the measurement rule for each channel. Added function
adc_set_mode_inv()
which enable inversion in this mode for DIG CTRL, unlikeadc_set_data_inv()
.