Hi daniel_m
The problem is when we attemped to create the buffer with “iio_device_create_buffer” after we enabled the channels we need (we enabled the ones we need and disable the rest). We got a NULL pointer in iio_buf and errno:22, which means “Invalid argument” (based on what we have found on the internet). The initialization of the ADC (enabling channels, creating the buffer, etc) is done in the ADC_init() function. The “iio_buffer_refill()” function is executed later within a while(true) once the buffer have been created. This code works if we only enabled one channel. But if we enable more than one, it throws that same error.
We also tried to skip the return when the iio_buf is NULL, and try to execute the “iio_buffer_refill()” function anyway with a NULL argument, and it fails.
This code below is the one we got error.
//defines
#define ANALOG_IN0 0
#define ANALOG_IN1 1
#define ANALOG_IN_NOTUSED1 2
#define ANALOG_IN_NOTUSED2 3
#define ANALOG_IN_NOTUSED3 4
#define ANALOG_IN_NOTUSED4 5
#define ANALOG_IN_NOTUSED5 6
#define ANALOG_IN_NOTUSED6 7
#define ANALOG_IN2 8
#define ANALOG_IN3 9
#define ANALOG_IN_NOTUSED7 10
//global variables
struct iio_context* ctx;
struct iio_device* dev;
struct iio_buffer* iio_buf;
struct iio_channel *chn0;
struct iio_channel *chn1;
struct iio_channel *chn2;
struct iio_channel *chn3;
struct iio_channel *chn_NOTUSED1;
struct iio_channel *chn_NOTUSED2;
struct iio_channel *chn_NOTUSED3;
struct iio_channel *chn_NOTUSED4;
struct iio_channel *chn_NOTUSED5;
struct iio_channel *chn_NOTUSED6;
struct iio_channel *chn_NOTUSED7;
bool ADC_init(void)
{
ssize_t ret;
struct iio_device *iio_sysfs_trigger;
struct iio_device *trigger0;
const struct iio_device *current_trigger;
ctx = iio_create_local_context();
dev = iio_context_get_device(ctx, DEVICE_LOCAL);
//pregunto si ya esta seteado el current_trigger en el device "dev"
ret = iio_device_get_trigger(dev, ¤t_trigger);
if (ret < 0) {
char buf_test[256];
iio_strerror(-(int) ret, buf_test, sizeof(buf_test));
printf("Error al obtener el current trigger : %s\n", buf_test);
}
//si no tiene seteado ningun trigger
if (!current_trigger)
{
// obtengo puntero al sysfs_trigger
iio_sysfs_trigger = iio_context_find_device(ctx, "iio_sysfs_trigger");
if (!iio_sysfs_trigger) {
printf("Trigger %s not found\n", "iio_sysfs_trigger");
goto free_ctx_dev;
}
//echo 0 > /sys/bus/iio/devices/iio_sysfs_trigger/add_trigger
// averiguo si ya existe el trigger0
trigger0 = iio_context_find_device(ctx, "trigger0");
if (!trigger0) {
printf("El trigger0 no existía.\n");
// intento crearlo
ret = iio_device_attr_write_bool(iio_sysfs_trigger, "add_trigger", false);
if (ret < 0) {
printf("No se pudo escribir el atributo add_trigger en iio_sysfs_trigger\n");
}
goto free_ctx_dev;
}
//cat /sys/bus/iio/devices/trigger0/name > /sys/bus/iio/devices/iio:device0/trigger/current_trigger
ret = iio_device_set_trigger(dev, trigger0);
if (ret < 0) {
printf("No se pudo setear el trigger\n");
goto free_ctx_dev;
}
}
// inicializamos los punteros a los canales
chn0 = iio_device_get_channel(dev, ANALOG_IN0);
chn1 = iio_device_get_channel(dev, ANALOG_IN1);
chn2 = iio_device_get_channel(dev, ANALOG_IN2);
chn3 = iio_device_get_channel(dev, ANALOG_IN3);
chn_NOTUSED1 = iio_device_get_channel(dev, ANALOG_IN_NOTUSED1);
chn_NOTUSED2 = iio_device_get_channel(dev, ANALOG_IN_NOTUSED2);
chn_NOTUSED3 = iio_device_get_channel(dev, ANALOG_IN_NOTUSED3);
chn_NOTUSED4 = iio_device_get_channel(dev, ANALOG_IN_NOTUSED4);
chn_NOTUSED5 = iio_device_get_channel(dev, ANALOG_IN_NOTUSED5);
chn_NOTUSED6 = iio_device_get_channel(dev, ANALOG_IN_NOTUSED6);
chn_NOTUSED7 = iio_device_get_channel(dev, ANALOG_IN_NOTUSED7);
// deshabilitar todos los canales, se habilitarán de a uno para accederlos.
iio_channel_enable(chn0);
iio_channel_enable(chn1);
iio_channel_enable(chn2);
iio_channel_enable(chn3);
iio_channel_disable(chn_NOTUSED1);
iio_channel_disable(chn_NOTUSED2);
iio_channel_disable(chn_NOTUSED3);
iio_channel_disable(chn_NOTUSED4);
iio_channel_disable(chn_NOTUSED5);
iio_channel_disable(chn_NOTUSED6);
iio_channel_disable(chn_NOTUSED7);
iio_buf = iio_device_create_buffer(dev, 16, false);
if (!iio_buf) {
char buf_test[256];
iio_strerror(-(int)errno, buf_test, sizeof(buf_test));
printf("Create buffer failed : %s\n", buf_test);
goto free_ctx_dev;
}
return true;
// liberar contexto y device
free_ctx_dev:
iio_context_destroy(ctx);
ctx = NULL;
dev = NULL;
return false;
}
bool ADC_read(void)
{
struct iio_channel *chn;
timeval_t tiempo;
ssize_t nbytes_rx;
char *p_dat, *p_end;
ptrdiff_t p_inc;
// tomo el tiempo
gettimeofday(&tiempo, NULL);
//canales Refill
nbytes_rx = iio_buffer_refill(iio_buf);
if (nbytes_rx < 0) {
printf("Error refilling buf %d\n", (int) nbytes_rx);
}
// READ: Get pointers to RX buf and read IQ from RX buf port 0
p_inc = iio_buffer_step(iio_buf);
p_end = iio_buffer_end(iio_buf);
for (p_dat = (char*) iio_buffer_first(iio_buf, chn); p_dat < p_end;
p_dat += p_inc) {
printf("%02x, %02x, %02x, %02x,", ((int16_t*) p_dat)[0], ((int16_t*) p_dat)[1], ((int16_t*) p_dat)[2], ((int16_t*) p_dat)[3]);
}
printf("\n");
return true;
}
int main(int argc, char **argv)
{
// inicialización de conversor
ADC_init();
while (true)
{
ADC_read();
} //cierro while infinito
} /* main() */
After trying different approaches, we came up to this solution. In the main, we initialized the ADC and then in a while(true) in the same main, we call ADC_leer_canal(ch) for each channel of interest. In that function, we enable the channel passed as argument, then if the buffer was previously created, we delete it, and then create a new one, then read the samples and finally disable the channel. After that, we call the same function but with next channel and so on. This is the only approach we managed to get it working. This approach is far from what we would like it to be. Keep in mind that we need the samples of the four channels to be in the same buffer in order to acquire them simultaneously.
I attached the code below:
//defines
#define ANALOG_IN0 0
#define ANALOG_IN1 1
#define ANALOG_IN_NOTUSED1 2
#define ANALOG_IN_NOTUSED2 3
#define ANALOG_IN_NOTUSED3 4
#define ANALOG_IN_NOTUSED4 5
#define ANALOG_IN_NOTUSED5 6
#define ANALOG_IN_NOTUSED6 7
#define ANALOG_IN2 8
#define ANALOG_IN3 9
#define ANALOG_IN_NOTUSED7 10
//global variables
struct iio_context* ctx;
struct iio_device* dev;
struct iio_buffer* iio_buf;
struct iio_channel *chn0;
struct iio_channel *chn1;
struct iio_channel *chn2;
struct iio_channel *chn3;
struct iio_channel *chn_NOTUSED1;
struct iio_channel *chn_NOTUSED2;
struct iio_channel *chn_NOTUSED3;
struct iio_channel *chn_NOTUSED4;
struct iio_channel *chn_NOTUSED5;
struct iio_channel *chn_NOTUSED6;
struct iio_channel *chn_NOTUSED7;
bool ADC_init(void)
{
ssize_t ret;
struct iio_device *iio_sysfs_trigger;
struct iio_device *trigger0;
const struct iio_device *current_trigger;
ctx = iio_create_local_context();
dev = iio_context_get_device(ctx, DEVICE_LOCAL);
//pregunto si ya esta seteado el current_trigger en el device "dev"
ret = iio_device_get_trigger(dev, ¤t_trigger);
if (ret < 0) {
char buf_test[256];
iio_strerror(-(int) ret, buf_test, sizeof(buf_test));
printf("Error al obtener el current trigger : %s\n", buf_test);
}
//si no tiene seteado ningun trigger
if (!current_trigger)
{
// obtengo puntero al sysfs_trigger
iio_sysfs_trigger = iio_context_find_device(ctx, "iio_sysfs_trigger");
if (!iio_sysfs_trigger) {
printf("Trigger %s not found\n", "iio_sysfs_trigger");
goto free_ctx_dev;
}
//echo 0 > /sys/bus/iio/devices/iio_sysfs_trigger/add_trigger
// averiguo si ya existe el trigger0
trigger0 = iio_context_find_device(ctx, "trigger0");
if (!trigger0) {
printf("El trigger0 no existía.\n");
// intento crearlo
ret = iio_device_attr_write_bool(iio_sysfs_trigger, "add_trigger", false);
if (ret < 0) {
printf("No se pudo escribir el atributo add_trigger en iio_sysfs_trigger\n");
}
goto free_ctx_dev;
}
//cat /sys/bus/iio/devices/trigger0/name > /sys/bus/iio/devices/iio:device0/trigger/current_trigger
ret = iio_device_set_trigger(dev, trigger0);
if (ret < 0) {
printf("No se pudo setear el trigger\n");
goto free_ctx_dev;
}
}
// inicializamos los punteros a los canales
chn0 = iio_device_get_channel(dev, ANALOG_IN0);
chn1 = iio_device_get_channel(dev, ANALOG_IN1);
chn2 = iio_device_get_channel(dev, ANALOG_IN2);
chn3 = iio_device_get_channel(dev, ANALOG_IN3);
chn_NOTUSED1 = iio_device_get_channel(dev, ANALOG_IN_NOTUSED1);
chn_NOTUSED2 = iio_device_get_channel(dev, ANALOG_IN_NOTUSED2);
chn_NOTUSED3 = iio_device_get_channel(dev, ANALOG_IN_NOTUSED3);
chn_NOTUSED4 = iio_device_get_channel(dev, ANALOG_IN_NOTUSED4);
chn_NOTUSED5 = iio_device_get_channel(dev, ANALOG_IN_NOTUSED5);
chn_NOTUSED6 = iio_device_get_channel(dev, ANALOG_IN_NOTUSED6);
chn_NOTUSED7 = iio_device_get_channel(dev, ANALOG_IN_NOTUSED7);
// deshabilitar todos los canales, se habilitarán de a uno para accederlos.
iio_channel_disable(chn0);
iio_channel_disable(chn1);
iio_channel_disable(chn2);
iio_channel_disable(chn3);
iio_channel_disable(chn_NOTUSED1);
iio_channel_disable(chn_NOTUSED2);
iio_channel_disable(chn_NOTUSED3);
iio_channel_disable(chn_NOTUSED4);
iio_channel_disable(chn_NOTUSED5);
iio_channel_disable(chn_NOTUSED6);
iio_channel_disable(chn_NOTUSED7);
// TODO: agregar etiquetas de salida para liberar recursos en casos de error
return true;
// liberar contexto y device
free_ctx_dev:
iio_context_destroy(ctx);
ctx = NULL;
dev = NULL;
return false;
}
bool ADC_leer_canal(uint8_t canal){
// debemos crear un buffer que nos permita almacenar una determinada
// cantidad de muestras de los 4 canales activos, 2 bytes por cada canal.
struct iio_channel *chn;
timeval_t tiempo;
ssize_t nbytes_rx;
char *p_dat, *p_end;
ptrdiff_t p_inc;
// averiguo el canal
switch(canal){
case ANALOG_IN0: chn = chn0; break;
case ANALOG_IN1: chn = chn1; break;
case ANALOG_IN2: chn = chn2; break;
case ANALOG_IN3: chn = chn3; break;
default : chn = NULL;
}
iio_channel_enable(chn);
if (iio_buf) {
iio_buffer_destroy(iio_buf);
iio_buf = NULL;
}
iio_buf = iio_device_create_buffer(dev, 16, false);
if (!iio_buf) {
char buf_test[256];
iio_strerror(-(int)errno, buf_test, sizeof(buf_test));
printf("Create buffer failed : %s\n", buf_test);
return false;
}
// tomo el tiempo
gettimeofday(&tiempo, NULL);
//canales Refill
nbytes_rx = iio_buffer_refill(iio_buf);
if (nbytes_rx < 0) {
printf("Error refilling buf %d\n", (int) nbytes_rx);
}
// READ: Get pointers to RX buf and read IQ from RX buf port 0
p_inc = iio_buffer_step(iio_buf);
p_end = iio_buffer_end(iio_buf);
printf("\n%lu.%lu Leídos en buffer refill: %d canal %d\n"
, tiempo.tv_sec
, tiempo.tv_usec
, nbytes_rx
, canal
);
for (p_dat = (char*) iio_buffer_first(iio_buf, chn); p_dat < p_end;
p_dat += p_inc) {
printf("%02x,", ((int16_t*) p_dat)[0]);
}
iio_channel_disable(chn);
printf("\n");
return true;
}
int main(int argc, char **argv)
{
// inicialización de conversor
ADC_init();
while (true)
{
ADC_leer_canal(ANALOG_IN0);
ADC_leer_canal(ANALOG_IN1);
ADC_leer_canal(ANALOG_IN2);
ADC_leer_canal(ANALOG_IN3);
} //cierro while infinito
} /* main() */
Looking forward a soon response and a possible best solution.
Thanks in advanced daniel_m.
Regards,
Martin