Uncorrect ADC iniziatization with I2S
-
- Posts: 19
- Joined: Mon Jun 03, 2019 3:46 pm
Re: Uncorrect ADC iniziatization with I2S
Hello klaetze,
Which IDF are you using? Before pointing to 2Msps, did you try with slower sampling rate?
Could you show me some of your code?
I don't call bootloader_random_disable() function because it is called by the fw start-up routine.
Gianluca.
Which IDF are you using? Before pointing to 2Msps, did you try with slower sampling rate?
Could you show me some of your code?
I don't call bootloader_random_disable() function because it is called by the fw start-up routine.
Gianluca.
Re: Uncorrect ADC iniziatization with I2S
Hi Gianluca,
thanks for your reply,
I tried several sampling rates from 3 kHz to 100 kHz but it didn't work for any of them.
I am using the esp-idf version 4.1.
Here is the code that I used. I reused quite a lot of Your code.
thanks for your reply,
I tried several sampling rates from 3 kHz to 100 kHz but it didn't work for any of them.
I am using the esp-idf version 4.1.
Here is the code that I used. I reused quite a lot of Your code.
Code: Select all
#define TAG "I2S"
#define SAMPLE_RATE 5000
#define I2S_UNIT (0)
#define DMA_BUF_COUNT 4
#define DMA_BUF_LEN 1024
#define ADC_UNIT 1
#define ADC_CHANNEL 0
#define NUM_SAMPLES 1024
xQueueHandle adc_i2s_event_queue;
uint8_t adc_i2s_event_queue_size = 1;
// ...
i2s_event_t adc_i2s_evt;
static void adc_i2s_init(void)
{
esp_err_t ret = ESP_OK;
i2s_config_t adc_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,
.communication_format = I2S_COMM_FORMAT_I2S_MSB,
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
.intr_alloc_flags = 0,
.dma_buf_count = DMA_BUF_COUNT,
.dma_buf_len = DMA_BUF_LEN,
.use_apll = 1,//false,
.tx_desc_auto_clear = true
};
static const i2s_pin_config_t pin_config = {
.bck_io_num = 32, // Sample f(Hz) (= sample f * 2) on this pin (optional).
.ws_io_num = 33, // Left/Right (= sample f) on this pin (optional).
.data_out_num = I2S_PIN_NO_CHANGE,
.data_in_num = I2S_PIN_NO_CHANGE
};
//install and start i2s driver
ret = i2s_driver_install(I2S_UNIT, &adc_i2s_config, adc_i2s_event_queue_size , &adc_i2s_event_queue);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "i2s_driver_install operation error = %i", ret);
}
// Output sample clock & left/right signals to measure with oscilloscope (optional).
i2s_set_pin(I2S_UNIT, &pin_config);
//init ADC pad
ret = i2s_set_adc_mode(ADC_UNIT, ADC_CHANNEL);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "i2s_set_adc_mode_custom operation error = %i", ret);
}
vTaskDelay(2000);
}
static void adc_i2s_enable(void)
{
esp_err_t ret = ESP_OK;
ESP_ERROR_CHECK(i2s_zero_dma_buffer(I2S_UNIT));
ret = i2s_adc_enable(I2S_UNIT);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "i2s_adc_enable_custom operation error = %i", ret);
}
}
static void adc_i2s_disable(void)
{
i2s_adc_disable(I2S_UNIT);
}
static void adc_i2s_restore_sampling(void)
{
adc_i2s_disable();
vTaskDelay(100);
adc_power_on();
adc_i2s_init();
adc_i2s_enable();
}
#define I2S_MAX_CHANNELS 1
// Convert DMA 16bit (Chan 4b + ADC 12b) => 12bit, and print them in the same order each time.
void i2s_print_adc_data(uint8_t* s_buff, uint32_t len)
{
uint16_t dac_value[] = // Max 8 ADC1 input channels/pins.
{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
int chan = 0;
printf( "\tChan[n] : ADC raw\t");
for (int i = 0; i < len; i += (I2S_MAX_CHANNELS * 2)) {
for (int j = 0; j < (I2S_MAX_CHANNELS * 2); j += 2) {
chan = s_buff[i + j + 1] >> 4; // Cannel nbr is in bit 7:4.
dac_value[chan] = (((s_buff[i + j + 1] & 0x0F) << 8) | s_buff[i + j + 0 ]);
}
for (int j = 0; j < 8; j ++) {
if(dac_value[j] != 0xFFFF)
printf( "\t[%d] : %04x", j, dac_value[j]);
}
}
printf("\n\n");
}
static void adc_task(void *pvParameter)
{
esp_err_t ret = ESP_OK;
i2s_event_t adc_i2s_evt;
size_t bytes_read;
uint8_t* adc_data_buf = (uint8_t*) calloc(NUM_SAMPLES, sizeof(char));
adc_i2s_init();
vTaskDelay(5000 / portTICK_PERIOD_MS);
adc_i2s_enable();
while ( 1 )
{
if(xQueueReceive(adc_i2s_event_queue, (void * )&adc_i2s_evt, (portTickType)portMAX_DELAY))
{
if(adc_i2s_evt.type == I2S_EVENT_RX_DONE)
{
//vTaskDelay(3000 / portTICK_PERIOD_MS);
ret = i2s_read(I2S_UNIT, (char*)adc_data_buf, NUM_SAMPLES, &bytes_read, portMAX_DELAY);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "i2s_read operation error = %i", ret);
}
if(((adc_data_buf[0]) == 0) && ((adc_data_buf[1]) == 0) && ((adc_data_buf[2]) == 0))
{
printf("adc_data_buf[0] = %d adc_data_buf[1] = %d adc_data_buf[2] = %d\n",adc_data_buf[0],adc_data_buf[1],adc_data_buf[2]);
// If the adc reads zero values, it means it hasn't been started correctly. Restart it again to fix this problem.
adc_i2s_restore_sampling();
}
else
{
printf("adc_data_buf[0] = %d adc_data_buf[1] = %d adc_data_buf[2] = %d\n",adc_data_buf[0],adc_data_buf[1],adc_data_buf[2]);
ESP_LOGW(TAG, "RESTARTING");
vTaskDelay(1000);
// Restart is done to reproduce this problem
esp_restart();
}
}
}
}
adc_i2s_disable(); // Unreachable
}
esp_err_t app_main()
{
esp_log_level_set("I2S", ESP_LOG_INFO);
xTaskCreate( adc_task, "example_i2s_adc_dac", 4096, NULL, 5, NULL);
while(1)
{
vTaskDelay(5000 / portTICK_PERIOD_MS);
}
return ESP_OK;
}
-
- Posts: 19
- Joined: Mon Jun 03, 2019 3:46 pm
Re: Uncorrect ADC iniziatization with I2S
hello klaetze,
Giving a quick view of your code I noticed some point.
In your configuration, you set ".bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,", so, when you make a calloc you will need:
And so, in your read:
because you are casting adc_data_buf as a (char*)
Also, try to print the raw value by:
before any calculation on it.
Let me know if you will have any progress.
Regards,
Gianluca.
Giving a quick view of your code I noticed some point.
In your configuration, you set ".bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,", so, when you make a calloc you will need:
Code: Select all
uint16_t* adc_data_buf = (uint16_t*) calloc(NUM_SAMPLES, sizeof(uint16_t));
Code: Select all
ret = i2s_read(I2S_UNIT, (char*)adc_data_buf, NUM_SAMPLES*2, &bytes_read, portMAX_DELAY);
Also, try to print the raw value by:
Code: Select all
for(int i = 0; i < NUM_SAMPLES; i++)
{
ets_printf("%d ", adc_data_buf[i]);
}
Let me know if you will have any progress.
Regards,
Gianluca.
Re: Uncorrect ADC iniziatization with I2S
Hi Gianluca,
You are right that doesn't make sense in my code. I changed it according to your suggestions.
The problem unfortunately remains the same.
You are right that doesn't make sense in my code. I changed it according to your suggestions.
The problem unfortunately remains the same.
-
- Posts: 19
- Joined: Mon Jun 03, 2019 3:46 pm
Re: Uncorrect ADC iniziatization with I2S
Hello klaetze,
try to put ".use_apll = false," and also, which kind of values are you supposed to read?
To do some test, you can try to set up a DAC output and bring it (by a wire for example) to che ADC pin and try to read it in order to have a specific value.
Regars,
Gianluca.
try to put ".use_apll = false," and also, which kind of values are you supposed to read?
To do some test, you can try to set up a DAC output and bring it (by a wire for example) to che ADC pin and try to read it in order to have a specific value.
Regars,
Gianluca.
Re: Uncorrect ADC iniziatization with I2S
I have already tried both .apll=true, and apll=false, without any difference.
As input I use a cosine wave with a frequency of about 400Hz for testing purposes. I have also used constant values of 2.0V, but the adc display remains zero.
As input I use a cosine wave with a frequency of about 400Hz for testing purposes. I have also used constant values of 2.0V, but the adc display remains zero.
Re: Uncorrect ADC iniziatization with I2S
With the following code (quite messy) I am able to get realistic adc readings up to a frequency of 10 ksps however as soon as i increase the sampling rate over 10 ksps the adc-readings are all zeros again.
Code: Select all
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "esp_log.h"
#include "driver/i2s.h"
#include "soc/syscon_reg.h"
#include "driver/adc.h"
#include "esp_wifi.h"
#include "esp_event_loop.h"
#include "nvs_flash.h"
#include "driver/dac.h"
#define TAG "adc_i2s"
xQueueHandle i2s_event_queue;
uint8_t adc_i2s_event_queue_size = 1;
i2s_event_t evt;
static EventGroupHandle_t wifi_event_group;
static esp_err_t event_handler(void *ctx, system_event_t *event)
{
switch(event->event_id) {
case SYSTEM_EVENT_STA_START:
esp_wifi_connect();
break;
case SYSTEM_EVENT_STA_GOT_IP:
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
break;
default:
break;
}
return ESP_OK;
}
#define COSINE
static void dac_task()
{
#ifdef COSINE
esp_err_t ret = ESP_OK;
dac_cw_config_t cosine = {
.en_ch = DAC_CHANNEL_1, // output on pin 25
.scale = 0x0,
.phase = 0x2,
.freq = 500,
.offset = 1
};
ret = dac_cw_generator_config(&cosine);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "dac config error = %i", ret);
}
else
{
printf("config succesful\n");
}
ret = dac_cw_generator_enable();
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "dac enable error = %i", ret);
}
else
{
printf("enable succesful\n");
}
dac_output_enable( DAC_CHANNEL_1);
#else
dac_output_enable(DAC_CHANNEL_1);
dac_output_voltage(DAC_CHANNEL_1, 150);
#endif
while(1)
{
vTaskDelay(1000/portTICK_PERIOD_MS);
}
//dac_output_enable(DAC_CHANNEL_1)
}
void adc_task()
{
// initialization
i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN,
.sample_rate = 100000,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.communication_format = I2S_COMM_FORMAT_I2S,//I2S_COMM_FORMAT_I2S_MSB,
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 2,
.dma_buf_len = 1024,
.use_apll = true,
};
static const i2s_pin_config_t pin_config = {
.bck_io_num = 32, // Sample f(Hz) (= sample f * 2) on this pin (optional).
.ws_io_num = 33, // Left/Right (= sample f) on this pin (optional).
.data_out_num = I2S_PIN_NO_CHANGE,
.data_in_num = I2S_PIN_NO_CHANGE
};
printf("after config struct\n");
i2s_driver_install(I2S_NUM_0, &i2s_config, adc_i2s_event_queue_size , &i2s_event_queue);
printf("driver installed\n");
// Output sample clock & left/right signals to measure with oscilloscope (optional).
i2s_set_pin(I2S_NUM_0, &pin_config);
//******************************************************//
ESP_ERROR_CHECK(i2s_set_adc_mode(ADC_UNIT_1, ADC1_CHANNEL_0));
ESP_ERROR_CHECK(i2s_adc_enable(I2S_NUM_0));
// workaround
vTaskDelay(10 / portTICK_PERIOD_MS);
// enable continuous adc sampling
SYSCON.saradc_ctrl2.meas_num_limit = 0;
// channel, attenation, bit width
SYSCON.saradc_sar1_patt_tab[0] = ((ADC1_CHANNEL_0 << 4) | (ADC_WIDTH_BIT_12 << 2) | ADC_ATTEN_DB_11) << 24;
//************************************************************************//
// After running WiFi on esp_wifi_set_mode(), the ADC-I2S scanning is stops.
// init_wifi();
//dac_task();
// Read DMA event queue as ADC scanning result
printf("test\n");
int i2s_read_len = 1024 * 2;
size_t bytes_read = 0;
uint16_t i2s_read_buff[1024];
printf("while\n");
while(1) {
printf("in while\n");
if (xQueueReceive(i2s_event_queue,(void *)&evt, (portTickType)portMAX_DELAY)) {
printf("first if\n");
if (evt.type==2) {
printf("second if\n");
i2s_read(I2S_NUM_0, (char*)i2s_read_buff, i2s_read_len, &bytes_read, portMAX_DELAY);
ESP_LOG_BUFFER_HEX("i2s_read_buff", i2s_read_buff, 16);
}
}
}
}
void app_main()
{
xTaskCreate(dac_task, "DAC_TASK", 4096, NULL, 5, NULL);
xTaskCreate(adc_task, "ADC TASK", 8192, NULL, 5, NULL);
while(1)
{
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
Re: Uncorrect ADC iniziatization with I2S
Hi Guys,
i had to update from esp-idf version 4.1 to 4.2. Now everything is working as it should.
For further questions check out this post: https://github.com/espressif/esp-idf/pull/1991
i had to update from esp-idf version 4.1 to 4.2. Now everything is working as it should.
For further questions check out this post: https://github.com/espressif/esp-idf/pull/1991
-
- Posts: 19
- Joined: Mon Jun 03, 2019 3:46 pm
Re: Uncorrect ADC iniziatization with I2S
Hello Klaetze,
Great!
I haven't answer you yet because I haven't any time to test your fw. I'm glad you solved your problem.
Did you reach 2Msps?
Regards,
Gianluca.
Great!
I haven't answer you yet because I haven't any time to test your fw. I'm glad you solved your problem.
Did you reach 2Msps?
Regards,
Gianluca.
Re: Uncorrect ADC iniziatization with I2S
Hi Gianluca,
i measured the Sampling frequency with an oscilloscope and its indeed 2 Msps.
I also made a measurement with a pwm signal of 120 kHz and a duty cycle of 90%. As you can see on the picture it is pretty much 2 Msps.
i measured the Sampling frequency with an oscilloscope and its indeed 2 Msps.
I also made a measurement with a pwm signal of 120 kHz and a duty cycle of 90%. As you can see on the picture it is pretty much 2 Msps.
- Attachments
-
- 2MSPS.jpg (21.94 KiB) Viewed 6754 times
Who is online
Users browsing this forum: Majestic-12 [Bot] and 59 guests