Меню
+7 (495) 785-95-25
sale@lcard.ru
sale@lcard.ru
Спасибо, все собралось.
Добрый день!
Пытаюсь собрать библиотеки для е502 под Эльбрус. СMake прошел без ошибок, а вот при сборке первое с чем столкнулся - вот такое сообщение:
lcc: ошибка: неизвестная опция "-Wlogical-op"
Подскажите как эту опцию в опциях компилятора убрать.
ага, вот теперь понятна где ошибка была - я либо делал частоту больше частоты фрейма, либо меньше... с этим понятно. Теперь мне осталось только определиться с задержкой на достоверность цифровых данных..
а ведь точно -поставил частоту строго равной частоте фрейма и цифры стали правильными.. спасибо, буду пытать дальше
нет конечно.. а что нужно точное соответствие?
покрутил частоту X502_SetDinFreq.. чем меньше частота, тем ситуация меняется в сторону данных с АЦП. При 500 Гц получаю
12 11 1
12 11 0
12 11 0
12 11 1
ну так далее.. Но данные (якобы) с АЦП все равно неправильные идут, как случайные.
Если убрать разрешение синхронного ввода, то аналоговые данные в порядке.
сделал упрощенный вариант: только чтение 11 аналоговых каналов и 1 цифровой. Получил следующее
12 7 1
12 4 1
12 0 1
...
12 0 1
здесь первая цифра - то что возвращает Recv, вторая - adc_size и последняя - inp_size...
Куда делись данные с АЦП?
сейчас приведу все в порядок (это замет немного времени) и сделаю...
вот спасибо! Этот вариант заработал. Сразу после
err = X502_StreamsEnable(m_dev, X502_STREAM_ADC);
if(err < 0)
{
qDebug() << QString("error stream enable (%1)").arg(err);
return;
}
err = X502_StreamsStart(m_dev);
if(err < 0)
{
qDebug() << QString("error stream start (%1)").arg(err);
return;
}я вставил
app->dio_thread->start();
emit startDio();и все пошло.. До этого варианта я не додумался, наверное при последовательно старте потоков поток с цифровыми данными стартовал почему-то первым..
Если вы от меня не устали
, то может попробуем еще раз вернуться к полностью синхронному? обмену
разобрался немного и поправил свои ошибки в варианте раздельных потоков: запускаю последовательно два потока:
1. В первом потоке - синхронное чтение данных с АЦП
qint32 err = X502_StreamsEnable(m_dev, X502_STREAM_ADC);
if(err < 0)
{
qDebug() << QString("error stream enable (%1)").arg(err);
return;
}
err = X502_StreamsStart(m_dev);
if(err < 0)
{
qDebug() << QString("error stream start (%1)").arg(err);
return;
}
m_bRun = true;
while(m_bRun)
{
qint32 rcv_size = X502_Recv(m_dev, (uint32_t*)buffer, count, 2000);
if(rcv_size <= 0)
{
qDebug() << QString("error received adc data (%1)").arg(rcv_size);
}
quint32 adc_size = rcv_size;
qint32 err = X502_ProcessAdcData(m_dev, (uint32_t*)buffer, adc_data, (uint32_t*)&adc_size, X502_PROC_FLAGS_VOLT);
if(err < 0)
{
qDebug() << QString("error processing data (%1)").arg(err);
}
}
app->rza->adcReady();
}2. второй поток - асинхронное чтение/запись цифровых данных
while(m_bRun)
{
out_buff[0] = address;
if(m_relays != 0)
{
out_buff[0] |= m_relays;
if(m_startRelay)
{
m_startRelay = false;
}
}
out_buff[0] |= 0x4000;
err = X502_AsyncOutDig(m_dev, out_buff[0], 0);
if(err < 0)
{
qDebug() << QString("error write digital data (%1)").arg(err);
}
err = X502_AsyncInDig(m_dev, (uint32_t*)inp_buff);
if(err < 0)
{
qDebug() << QString("error read digital data");
}
if(m_relays == 0)
{
m_inputs[address++] = inp_buff[0];
if(address == 6) address = 0;
}
else
{
m_relays = 0;
m_status[address] = inp_buff[0];
address = 0;
}
}
}Сразу после старта поток 1 (чтение АЦП) выдает ошибку: "error stream enable (-15)" (Истекло время ожидания освобождения мьютекса). Если я запускаю или 1=й поток или 2-й, то по отдельности все работает.
А на счет картинок (если я правильно понял тут возникло непонимание?) - то на первой - это нормальный результат: амплитуды стабильны, относительные фазы тоже.
А на второй картинке изображены просто мгновенные значения из серии, в течении времени амплитуды нестабильны ( я бы сказал произвольные), относительные фазы тоже не соответствуют входным. Т.е. вектора входных сигналов произвольно болтаются относительно друг-друга.
Пока оставим это и если можно попытаемся разобраться почему поток с синхронным вводом с АЦП не хочет совмещаться с потоком асинхронного ввода с цифровых входов.
вынес асинхронный ввод/вывод цифровых данных в отдельный поток. Данные с АЦП принимаются нормально, но с цифровых входов ничего не читается. Прямо заколдованный круг какой-то. Если в АЦП-шном цикле заменяю чтение с АЦП на чтение цифровых данных - все ок..
вот здесь два снимка экрана: https://cloud.mail.ru/public/GexC/rRb8ANWSN
В обоих случаях на вход АЦП подаю три напряжения и три тока. После приема данных и ДПФ в левой части прорисовываются амплитуды, а в правой - круговые диаграммы амплитуда-фаза. На первом рисунке (2016-10-18 09-27-42) просто сбор данных с АЦП, на втором (2016-10-18 09-29-51) - сбор данных с АЦП и синхронное чтение входного регистра.
В связи с тем что как-то не получается совместить чтение аналоговых и цифровых сигналов не может ли это быть связано с тем, что я использую упрощенную версию Е502 (без микроконтроллера и ЦАП)?
Вернулся к синхронному варианту: чисто синхронный ввод и прием данных с АЦП... что-то вообще начался бардак с АЦП-шными данными.Код примерно такой:
qint32 rcv_size = X502_Recv(m_dev, (uint32_t*)buffer, count + 1, 2000);
quint32 adc_size = count;
quint32 inp_size = 1;
qint32 err = X502_ProcessData(m_dev, (uint32_t*)buffer, rcv_size, X502_PROC_FLAGS_VOLT, adc_data, (uint32_t*)&adc_size, (uint32_t*)inp_buff, (uint32_t*)&inp_size);т.е. я хочу принять только слово с цифровых входов.
При инициализации я задаю (дополнительно к параметрам АЦП):
double fDIO = fAdcFrame;
X502_SetDinFreq(m_dev, &fDIO);
X502_StreamsEnable(m_dev, X502_STREAM_DIN);если это это убрать и убрать добавление 1 к числу каналов АЦП (т.е. вернуться к приему только данных с АЦП), то все работает нормально.
Все это интересно конечно, но пока я отвлекся на аналоговые входы.
И я вот что обнаружил. На АЦП подаю три фазы напряжения, сдвинутые на 0, 120 и 240 градусов. Код основного цикла выглядит так:
while(m_bRun)
{
out_buff[0] = address;
if(m_relays != 0)
{
out_buff[0] |= m_relays;
if(m_startRelay)
{
m_startRelay = false;
counter = 0;
}
}
out_buff[0] |= 0x4000;
err = X502_AsyncOutDig(m_dev, out_buff[0], 0);
rcv_size = X502_Recv(m_dev, (uint32_t*)buffer, count, 2000);
adc_size = rcv_size;
err = X502_ProcessAdcData(m_dev, (uint32_t*)buffer, adc_data, (uint32_t*)&adc_size, X502_PROC_FLAGS_VOLT);
err = X502_AsyncInDig(m_dev, (uint32_t*)inp_buff);
if(m_relays == 0)
{
m_inputs[address++] = inp_buff[0];
if(address == 6) address = 0;
}
else
{
counter++;
if(counter == 2)
{
counter = 0;
m_relays = 0;
m_status[address] = inp_buff[0];
address = 0;
}
}
app->rza->adcReady();
}Теперь изменяю амплитуду или относительную фазу любого напряжения... в данных с АЦП ничего не меняется. Перезапускаю программу - все ок, пошли правильные данные.
Убираю из цикла асинхронный обмен с цифровыми портами:
while(m_bRun)
{
rcv_size = X502_Recv(m_dev, (uint32_t*)buffer, count, 2000);
adc_size = rcv_size;
err = X502_ProcessAdcData(m_dev, (uint32_t*)buffer, adc_data, (uint32_t*)&adc_size, X502_PROC_FLAGS_VOLT);
app->rza->adcReady();
}Все встает на свои места, изменения входных напряжений сразу видны в данных с АЦП.
Я опять что не так делаю или такая смесь синхронного и асинхронного вызова недопустима?
именно так - то что вводится зависит от 4-го бита. Если он 0, то читаются статусы с регистров одного типа, если 1 - то на железке выполняются некоторые действия и читаются уже другая статусная информация. Причем в этом случае установка 4-го бита, адреса (3 мл.бита) и содержимое старших битов происходит асинхронно из другого потока и время чтения вообще говоря имеет вторичное значение, поскольку статусная информация появится только через несколько миллисекунд, тогда как в случае нулевого 4-го бита чем быстрее тем лучше.
да, примерно так.. только есть еще один вариант - в адрес может асинхронно по времени добавляться 4 бит, а в а старшие биты - некоторая управляющая информация для внешнего оборудования.. Тогда при чтении должен читаться регистр состояний. Т.е. все несколько сложнее простого перебора чтения внешних данных по адресам от 0 до 5.
Вот спасибо, обновление прошивки помогло для случая асинхронного вывода/ввода - эта странная ошибка исчезла.
Для синхронного варианта вроде помог следующий вариант; добавил счетчик после чтения входных данных типа вот такого:
counter++;
if(counter == 20)
{
counter = 0;
m_inputs[address++] = inp_buff[0];
if(address == 6) address = 0;
}т.е. только на 20-й раз считаю данные действительными при неизменном значении адреса.. но похоже это мало чем будет отличаться по скорости с асинхронным вариантом
Помогите пожалуйста разобраться с синхронным вводом выводом. Вот такой код
void QAdcObject::init()
{
RzaApplication* app = (RzaApplication*)qApp;
char serial[2][X502_SERIAL_SIZE];
qint32 err, devs;
if(m_dev != 0)
{
m_bRun = false;
X502_Close(m_dev);
X502_Free(m_dev);
}
err = E502_UsbGetSerialList(serial, 2, X502_GETDEVS_FLAGS_ONLY_NOT_OPENED, (uint32_t*)&devs);
if(devs == 0)
{
qDebug() << "no device found";
return;
}
m_dev = X502_Create();
err = E502_OpenUsb(m_dev, serial[0]);
if(err != 0)
{
qDebug() << "open e502 failed";
X502_Free(m_dev);
m_dev = 0;
return;
}
X502_SetMode(m_dev, X502_MODE_FPGA);
err = X502_SetLChannelCount(m_dev, app->m_channel.count());
for(int i = 0; i < app->m_channel.count(); i++)
{
err = X502_SetLChannel(m_dev, i, i, X502_LCH_MODE_COMM, X502_ADC_RANGE_10, 1);
}
X502_SetSyncMode(m_dev, X502_SYNC_INTERNAL);
X502_SetSyncStartMode(m_dev, X502_SYNC_INTERNAL);
double fAcq = 2000000.0, fAdcFrame = 50.0 * (double)app->m_pnts;
err = X502_SetAdcFreq(m_dev, &fAcq, &fAdcFrame);
X502_StreamsEnable(m_dev, X502_STREAM_ADC);
X502_SetDinFreq(m_dev, &fAdcFrame);
X502_StreamsEnable(m_dev, X502_STREAM_DIN);
X502_SetOutFreq(m_dev, &fAdcFrame);
X502_StreamsEnable(m_dev, X502_STREAM_DOUT);
err = X502_Configure(m_dev, 0);
memset(m_inputs, 0, sizeof(quint16) * 6);
}
void QAdcObject::startAdc()
{
RzaApplication* app = (RzaApplication*)qApp;
qint32 buffer[256];
qint32 rcv_size, adc_size, inp_size, err;
X502_PreloadStart(m_dev);
out_buff[0] = 0;
err = X502_PrepareData(m_dev, 0, 0, (uint32_t*)out_buff, 1, 0x0, (uint32_t*)buffer);
err = X502_Send(m_dev, (uint32_t*)buffer, 1, 2000);
X502_StreamsStart(m_dev);
m_bRun = true;
int count = app->m_channel.count();
address = 0;
m_relays = 0;
int counter = 0;
while(m_bRun)
{
rcv_size = count;
out_buff[0] = address;
err = X502_PrepareData(m_dev, 0, 0, (uint32_t*)out_buff, 1, 0x0, (uint32_t*)buffer);
err = X502_Send(m_dev, (uint32_t*)buffer, 1, 2000);
rcv_size = X502_Recv(m_dev, (uint32_t*)buffer, count + 1, 2000);
adc_size = count;
inp_size = 1;
err = X502_ProcessData(m_dev, (uint32_t*)buffer, rcv_size, X502_PROC_FLAGS_VOLT, adc_data, (uint32_t*)&adc_size,
(uint32_t*)inp_buff, (uint32_t*)&inp_size);
m_inputs[address++] = inp_buff[0];
if(address == 6) address = 0;
}
}
X502_StreamsStop(m_dev);
}ОС - Линукс, частота АЦП (на канал) 2 МГц, сбора кадра - 4 кГц, число каналов АЦП - 11.
Кроме сбора аналоговых данных от этой функции необходимо еще чтение 16 разрядов с цифровых входов по адресу некоторого внешнего регистра, указанному в out_buff[0] (3 мл.бита от 0 до 6).. Для простоты текста я не привожу вывода сообщений об ошибках потому что в этом варианте их нет.
А вот и не получается. Такое ощущение, что синхронная запись не выполняется, для всех значений в out_buff[0] читается одно и тоже значение в inp_buff[0].
Если все тоже самое сделать (запись/чтение цифровых данных) в асинхронном режиме, то все работает (конечно при соответствующих изменениях в функции инициализации). Но этот вариант слишком медленный для моей задачи.
Да, кстати, еще замечание: при асинхронной записи функция
X502_AsyncOutDig(m_dev, out_buff[0], 0)
возвращает ошибку с кодом 1004. В списке кодов ошибок такого кода нет, но тем не менее в асинхронном режиме запись работает.
Если необходимо могу выложить код асинхронного варианта.
Ну вот и все, ура! Проработало почти 3-е суток, сбоев нет. Поздравляю, баг исправлен, тему можно закрывать. По мере переноса е502 на другие платформы буду вас извещать.
Эльбрус у нас конечно есть и планируются еще приобретения, есть удаленный доступ к машине с Эльбрусом. так что тут все ок. Avahi - это да, это нам не нужно.
Новая прошивка проработала день без проблем, посмотрим что будет утром.
На Эльбрусе стоит Линукс их (МЦСТ) сборки, последняя версия ядра, которую они выпускают - 3.14. Насколько я знаю они его делали для ВПК, так что ручками в ядре как-то ковырялись на предмет защиты, закладок и прочего.
Есть Qt4 (на ней все работает), я пытался собрать ту же апликуху на их сборке Qt5 - почему-то работать не захотела.. GUI у них - на XFCE4. libusb - в наличии. Я сделал одну попытку собрать e502 под Эльбрус из исходников, уже не помню почему, но не получилось, типа каких-то пакетов не хватило.. так что к этом вопросу вскоре вернусь.. для нас это один из важных вопросов на сегодня. Если удастся раздобыть плату с Байкалом - то на нее тоже будем софт переносить
Все установил как описано и запустил тестирование.. теперь это надолго
. в РОСЕ6 не смог установить lboot - почему-то не находит библиотеку libmodbus.so.5: в пакетах ее почему-то нет, ручками поставил ее из github и собрал - не помогло..
пришлось все проделать в Mint- все встало легко и быстро.
Вообще (просто для информации) хочу сказать - мы благодарны вам за оперативную поддержку и рассчитываем на ваши девайсы, в разработке у нас терминалы защиты, где основным элементов внешнего интерфейса ставим Е502. Причем в качестве рабочих станций используем как машинки Интел/АМД так и Эльбрус.. Это кстати возможно отдельная будет тема - перенос пакетов e502/x502 на Эльбрус.
Ну да, иногда эта пара вызовов не помогает и все сбивается в непрерывную череду ошибок.. но все равно факт: на USB 3.0 200 кГц работало всю ночь, а 2 кГц все еще работает без ошибок (уже больше 3-х часов). Возможно стек немного другой...
Для чистоты эксперимента возвращаю обмен на USB 2.0.
вот, все интереснее и интереснее.. Посмотрел на datasheet микроконтроллера, там USB 2.0, а я оказывается вчера подключил в USB-3.0 и все, ошибки похоже исчезли. Сейчас еще подожду (на 2 кГц) немного и верну подключение на USB 2.0..
и еще такой вопрос: когда возникает ошибка обработки было бы неплохо как бы перезапустить синхронный сбор. Я использовал вариант
Х502_streamStop();
X502_StreamStart();
не очень красиво, но как правило помогало восстановить синхронный сбор данных (хотя очевидно и с потерями). А что нет другого пути ре-инициализировать синхронный сбор?
Адрес: 117105, Москва, Варшавское шоссе, д. 5, корп. 4
Многоканальный телефон: +7 (495) 785-95-25
Письма и запросы: lcard@lcard.ru
Отдел продаж: sale@lcard.ru
Мы работаем с юридическими и физическими лицами, пожалуйста, прикладывайте реквизиты при оформлении заказа
Техническая поддержка: support@lcard.ru
Время работы: с 9-00 до 19-00 мск