Российский производитель и разработчик сертифицированного измерительного оборудования с 1987 года


linux, l154, вывод на ЦАП

Вы не вошли.

 Поиск | Регистрация | Вход 

Алексей Войтылов
20.07.2003 19:18:56
#1

Гость

linux, l154, вывод на ЦАП

Описание системы:
SuSE linux 7.3, kernel 2.4.10, gcc 2.95.3, lcdrv-1.0.22
плата l-154

Проблема:
Не могу вывести на ЦАП правильное значение. Происходит следующее: по умолчанию стоит отсчет 0. Начинаем изменять напряжение, когда проходим отсчет 255-256, все сбрасывается на то же состояние, как и в отсчете 0. Хотя должно работать до отсчета 4095 (12 бит). То-есть вместо напряжений -5.12 - +5.12 имеем диапазон -5.12 - -4.48. Я так понял, что ЦАП внезапно превратился из 12 в 8-битный.
При этом работа с АЦП - нормальная, в нормальном диапазоне 0-4095 (т.е. полные 12 бит).
Разумеется, при этом в DOS все работает правильно.

Буду благодарен за любое решение проблемы
(возможно, эта версия драйвера перестала работать с l-154? предыдущие версии драйвера не пробовал, если кто-нибудь успешно использовал ЦАП, отзовитесь.) Можно фикс в виде хака, но нужен 12 бит ЦАП.

Алексей Войтылов

Ivan
21.07.2003 17:30:30
#2

Гость

Re: linux, l154, вывод на ЦАП

Да, значение обрезалось до 8 бит.
Завтра утром будет выложена новая версия, где это исправлено.

Исправления в файле "drivers/drv154.c":

static int set_sample(BOARD_STRUCT *b, int channel, int value)
{
outw(value, b->base + REG_DATA);  /* было outb(...) */
return 0;
}

Спасибо за обнаруженную ошибку.

Алексей Войтылов
29.07.2003 18:59:20
#3

Гость

Re: linux, l154, вывод на ЦАП

Всегда пожалуйста.

1.  А почему в reset() то не исправили?
Еще как-то непонятно, почему в reset() стоит outb(0,...). Например на моей карточке это приводит к выводу -5.12 при выключении. Нехорошо. Должно быть что-то вроде
#define ZERO 0
...
outw(ZERO,...)
а то по всему коду лазить... Я знаю, что это можно установить перемычкой, но.

2. Не работает следующий код как надо:

int main(int argc, char *argv) {
    int i,k, j, device, number_of_channels=3, length=10, freq=2000;       

    channel_info ci;
    int log_channels[3]={0xC0, 0xC1, 0xC2};
    int outsample[2]={4095, 2048};
    short *buffer;

buffer=(short*)malloc(length*sizeof(short));
    device = open("/dev/xdsp0", O_RDWR);
    for(k=0;k<2;k++)
    {
            ci.channel=0;
        ci.gain=0;
        ci.number=0;
        ci.sample=outsample[k];
   
        ioctl(device, LDSP_SAMPLE_OUT, &ci);
        ioctl(device, SNDCTL_DSP_SPEED, &freq);
        for(i=0;i<number_of_channels;i++) {
        ci.channel=i;
        ci.log_channel=log_channels[i];
        ci.gain=0;
        ci.number=i;
        ci.sample=-1;
        ioctl(device, LDSP_SET_CHANNEL, &ci);
        }
   
        ioctl(device, SNDCTL_DSP_CHANNELS, &number_of_channels);   
            read(device, buffer,
number_of_channels*length*sizeof(short));                    

for(i=0;i<length;i++){
        for(j=0;j<number_of_channels;j++){
            printf("%d//t", buffer[number_of_channels*i+j]);       

        }
        printf("%d//n", k);
        }
    }
    close(device);
    free(buffer);
    return 0;
}


Не могу уяснить почему, но работает только ветка с k=0; ветка с k=1 хоть и выдает значение на ЦАП, с АЦП читает бред. Если сделать close(device); device=open(...), все нормально. Но непонято, зачем это нужно, здесь даже длины буфера совпадают. К тому же при этом сбрасывается текущее значение ЦАП (см пт. 1). Поясните, что я не так делаю.

3. Непонятен следующий момент. Хочется на ЦАП выдавать периодический сигнал (синус, например), не заботясь об этом. Как это реализовать с помощью прерываний (в смысле как использовать таймеры на плате, чтобы вновь запускался период синуса)? При этом, разумеется, хочется что-то читать с АЦП. Как это сочетается с ключем O_NONBLOCK?

За ТТХ в первое сообщение.

Алексей Войтылов

Алексей Войтылов
29.07.2003 19:01:24
#4

Гость

Re: linux, l154, вывод на ЦАП

Вдогонку. Проясните разницу между ci.channel, ci.log_channel и ci.number

Ivan
04.08.2003 18:33:45
#5

Гость

Re: linux, l154, вывод на ЦАП

1. Исправил. Теперь на ЦАП будет выдаваться 0V...

2. Функция read() предназначена для непрерывного ввода/вывода, она возвращает из внутреннего буфера данные, которые считываются туда ранее по прерыванию от таймера. Установка одиночного отсчета с помощью LDSP_SET_CHANNEL случайным образом попадет куда-то в середину кадра.
Если нужно после вывода одиночного отсчета на ЦАП сразу считать несколько одиночных отсчетов с АЦП - используйте LDSP_SAMPLE_IN. Если нужен непрерывный синхронный ввод/вывод - данные выводятся в выходной буфер ЦАП с помощью write().

3. Можно сделать отдельный поток, который непрерывно выводит через write() один и тот же блок данных, или просто отобразить буфер ЦАП через mmap().

По поводу полей структуры:
ci.channel - код канала без коэффициента усиления
ci.number - номер канала в таблице.
ci.log_channel - логический номер канала, вычисляется и заполняется драйвером.