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


Проблемы с записью данных платы L791

Вы не вошли.

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

Konstantin
25.04.2013 16:12:45
#1

Гость

Проблемы с записью данных платы L791

Здравствуйте.
Я написал программу записи звуковых данных (голоса) с 16 диф. каналов АЦП платы L791. Алгоритм следующий:
при запуске программы стартует детектор, который пробегает по всем каналам в кольцевом буфере в ожидании данных. Вот код потоковой функции:

void *DeviceAPI::detectThreadFunc(void *arg)
{
    CHECK;
    unsigned int *tmpposptr = posPoint;
    unsigned short *tmpbegptr = beginPoint;
    int channel = 0;
    int kadr = 0;
    DeviceAPI *obj = static_cast<DeviceAPI*>(arg);
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
    int *buf4byte = (int*)malloc(4);
    int *buf2byte = (int*)malloc(2);
    if (!(buf4byte && buf2byte))
    {
        fprintf(stderr,
                "->error allocated buffer buf4byte or buf2byte in detectThreadFunc/n");
        pthread_exit(0);
    }
    while (1)
    {
        CHECK;
        while (abs(tmpposptr[I_ADC_PCI_COUNT_L791] - (kadr + channel * 4))
                < 64 * 10)
            usleep(10);
        if (!obj->chanBusy(channel))
        {
            CHECK;
            memcpy(buf4byte, tmpbegptr + kadr + channel * 4, 4);
            *buf2byte = (*buf4byte & 0xFFFF);
            if (abs(*buf2byte) > 50)
            {
                obj->startRead(channel, kadr);
                usleep(1000);
            }

        }
        if ((channel += 1) == 16)
        {
            channel = 0;
            if ((kadr += 64) == obj->size) kadr = 0;
        }CHECK;
    }
    free(buf4byte);
    free(buf2byte);
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    pthread_exit(0);
    CHECK;
    return NULL;
}

Как только данные обнаружены на каком-либо канале, запускается поток чтения. Код ниже:
void *ThreadsManager::readThread(void *arg)
{
    CHECK;
    unsigned int *tmpposptr = posPoint;
    unsigned short *tmpbegptr = beginPoint;
    ThreadsManager *obj = static_cast<ThreadsManager*>(arg);
    const int chan = obj->param->chan;
    int kadr = obj->param->kadr;
    unsigned int silentCount = 0;
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
//    pthread_cleanup_push(obj->exitHandler, (void*)obj);
    int *buf4byte = (int*)malloc(4);
    int *buf2byte = (int*)malloc(2);
    if (!(buf4byte && buf2byte))
    {
        fprintf(stderr,
                "->error allocated buffer buf4byte or buf2byte in readThread/n");
        pthread_exit(0);
    }
    while (1)
    {
        while (abs(tmpposptr[0xF80 >> 2] - (kadr + chan * 4)) < 64 * 10)
            usleep(10);
        CHECK;
        memcpy(buf4byte, tmpbegptr + kadr + chan * 4, 4);
        *buf2byte = (*buf4byte & 0xFFFF) << 2;
        obj->writeData(buf2byte, 2, chan);
        if (abs(*buf2byte) < 200)
        {
            if ((silentCount += 1) == 100) break;
        }
        else
            silentCount = 0;
        if ((kadr += 64) == obj->size) kadr = 0;
        CHECK;
    }
    obj->saveToWav(obj->rate, chan);
    obj->threadBusy[chan] = false;
    CHECK;
    free(buf4byte);
    free(buf2byte);
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    pthread_exit(0);
//            pthread_cleanup_pop(1);
    return NULL;
}

И все вроде работает, но, данные пишутся с двух каналов одновременно. Даже если подключен один микрофон, пишутся одинаковые данные с двух каналов! Например если к 0 каналу подключен микрофон и на него начинают поступать данные, то запись стартует с 0 и 8 каналов... Данные одинаковые! По всей видимости из-за этого запись данных идет с прерываниями и частоту записи приходится дополнительно делить на 2(запись идет с частотой 256 КГц соответственно делим на 16, получаем 16КГц, приходится делить еще на 2 , т.е. 8КГц). Подскажите, пожалуйста, в чем может быть дело... Может я как-то не правильно рассчитал сдвиг указателя кольцевого буфера?
Если нужно могу выслать код всей программы на почту...

25.04.2013 16:36:51
#2

Инженер-электронщик
Откуда: "Л Кард"
Здесь с 21.04.2014
Сообщений: 4,597

Re: Проблемы с записью данных платы L791

Если опрашиваете не подключенный вход, то его нужно заземлить.

Konstantin
25.04.2013 16:44:22
#3

Гость

Re: Проблемы с записью данных платы L791

<"Если опрашиваете не подключенный вход, то его нужно заземлить.">
Забыл уточнить, что программа test.cpp из драйверов к плате, пишет 1 канал при таком же подключении... Я читал в документации к плате, что "висячие" каналы необходимо заземлить, а лучше вообще не опрашивать, но у меня немного другая ситуация... Данные пишутся одинаковым уровнем, они вообще идентичные с одинаковыми разрывами записи и одинаковым уровнем громкости... Я понимаю, что ошибка скорее всего в моей программе, но не могу понять, где конкретно...

Konstantin
26.04.2013 09:55:13
#4

Гость

Re: Проблемы с записью данных платы L791

Кажется, разобрался сам... Дело было в сдвиге указателя на кольцевой буфер. Поскольку указатель типа unsigned short, он сдвигался не на (kadr + chan * 4), а на (kadr + chan * 4)*2. Соответственно, после исправления (поделил на 2 величину сдвига (kadr + chan * 4)/2)запись пошла корректно с одного канала!
Но теперь другой вопрос, почему-то после прослушивания записи наблюдаются пропуски данных... Т.е. пропадают куски данных(звуковые, теряются слова, звуки...). Почему это может происходить? Вроде запись корректно идет?

Konstantin
26.04.2013 09:57:25
#5

Гость

Re: Проблемы с записью данных платы L791

Уточню... Пишу код для 64 битной операционной системы Linux. Может дело в этом:
memcpy(buf4byte, tmpbegptr + (kadr + chan * 4)/2, 4);
*buf2byte = (*buf4byte & 0xFFFF) << 2;
obj->writeData(buf2byte, 2, chan);

Насколько корректно это будет работать для 64-х битной системы??

26.04.2013 11:51:45
#6

Сотрудник "Л Кард"
Здесь с 18.04.2014
Сообщений: 810

Re: Проблемы с записью данных платы L791

Чтобы не биться с битностью, я бы посоветовал #include <stdint.h> или <cstdint> и использовать специально предназначенные для данных фиксированного размера типы uint32_t, int16_t и т.д. (у cstdint они в namespace std::).
Простые типы (char, short, int, long и т.д.) могут иметь разный размер на разных архитектурах, они лучше подходят для арифметики, но не там, где нужен обязательно фиксированный размер (например, данные пришли из устройства, считаны из файла с фиксированным двоичным форматом и т.п.)
Про big-endian/little-endian отдельная история.

Кроме того, я бы заменил все цифры, обозначающие размеры (4, 16, 64), на sizeof(). Если данные в массиве 32-битные, то лучше, чтобы и указатель на них (tmpbegptr) был uint32_t*, тогда и хитрить при вычислении индекса не надо (+1 = один отсчет).

Что касается пропусков, надо проверять, как сделан ввод-вывод и успевает ли программа обработать данные. Например, что делает метод DeviceAPI::writeData()?

Не понимаю, что там с чтением - ждете 10 кадров, из них берется только один отсчет?

И еще - я не знаю, критично ли это на современных головокружительно быстрых машинах, но код вообще-то выглядит изрядно неэффективным. Зачем-то 4 байта перегоняются через memcpy, потом на каждый отсчет вызывается метод объекта... плюс еще параллельно прямо из платы читают данные с разными смещениями от кадра несколько потоков.
Тут накладные расходы будут сотни, а то и тысячи процентов. (Хлебозавод печет булочки, их снимают с конвейера и развозят по магазинам - по одной булочке за поездку).

Я бы написал вообще все не так. Один поток чтения из устройства разбирает кадры на каналы и заполняет буферы (если надо - двойные), по мере накопления данных куда-то их отдает порциями...

Konstantin
26.04.2013 14:37:06
#7

Гость

Re: Проблемы с записью данных платы L791

Александр Е! Спасибо за ответ. Код действительно не оптимизирован. К сожалению у меня не дошли до этого руки, ибо очень спешу (сроки поджимают). Код изначально мной писался в 32 битной системе и про особенности 64 бит я как-то подзабыл... Пришлось делать костыли. А буфер я разбираю таким образом потому, что мне необходимо начинать запись с канала, как только на него поступили данные и только эти самые данные, а затем сохранять их в wav формате. Можно было бы стартовать сразу n потоков чтения из кольцевого буфера и уже в каждом потоке анализировать, пришли ли данные или нет... Не знаю насколько это было бы оптимальнее, ведь у меня в холостом режиме работает только один поток...
А насчет чтения, так вот это:
while (abs(tmpposptr[0xF80 >> 2] - (kadr + chan * 4)) < 64 * 10)
usleep(10);

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

obj->writeData(buf2byte, 2, chan) делает fwrite(buf2byte, 2, 1, fileDesc); В общих чертах, только через метод ofstream...
По логике (по моей:) никаких пропусков данных быть не должно... Если у Вас есть время, могу скинуть Вам полный рабочий код программы... Может что подскажите...

26.04.2013 16:12:49
#8

Сотрудник "Л Кард"
Здесь с 18.04.2014
Сообщений: 810

Re: Проблемы с записью данных платы L791

На 64-битном линуксе, если я не ошибаюсь, на самом деле отличается только размер long. Ну и размер указателей, конечно.

>Можно было бы стартовать сразу n потоков чтения из кольцевого буфера и уже в каждом потоке анализировать, пришли ли данные или нет

Почему не делать это в одном потоке? Ведь поток данных все равно один, они не приходят асинхронно с разных устройств. Демультиплексор каналов, разобрав кадры, может и амплитуду детектировать, и буферы заполнять.
Скажем, делаем массив переменных состояния сбора по каждому каналу. Например, struct { bool started; size_t nsamples; } chan_status[N_CHANNELS].
И потом проходим по каналам: где !started, там проверяем амплитуду на условие пуска, а где уже started, там записываем out_buf[nsamples++] и по заполнению буфера отдаем его куда-то наружу или заканчиваем сбор, если буферы большие на весь сеанс.

> obj->writeData(buf2byte, 2, chan) делает fwrite(buf2byte, 2, 1, fileDesc);

В файл по два байтика на отсчет с частотой дискретизации, умноженной на число каналов?! Хм.
Нет, конечно, iostream буферизует операции, да и операционная система не станет каждые 2 байта писать на диск. Но все же.

Константин, я не могу сказать, в том ли дело или где-то зарыта какая-то ошибка. Но я не исключаю, что просто не успевает записать на диск и происходит переполнение буфера.
Кстати, Вы можете это проверить по ADC_Ovf_Event регистра статуса.

И еще я не понимаю, как Вы работаете со счетчиками ADC_PCI_Count. Плата в режиме bus master?

26.04.2013 16:28:18
#9

Сотрудник "Л Кард"
Здесь с 18.04.2014
Сообщений: 810

Re: Проблемы с записью данных платы L791

Кстати, я не очень понимаю, зачем выделять динамически malloc(4) и malloc(2) (а чем не устроила просто локальная переменная?), но уж
int *buf2byte = (int*)malloc(2);
и потом запись
*buf2byte = ...
- это хороший шанс испортить память или получить segmentation fault.

Konstantin
26.04.2013 16:57:52
#10

Гость

Re: Проблемы с записью данных платы L791

Хм... Вообще идея насчет 1 потока достаточно интересна! Действительно, можно реализовать опрос каналов и запись данных в одном единственном потоке. У меня изначально представление об архитектуре будущей программы сложилось сразу как-то так "Диспетчер Файлов <- Потоки чтения для 16 каналов <- Детектор сигналов". Не знаю, от куда это взялось в моем мозгу... Я видел так: "постоянно работает детектор сигнала, сканируя все каналы, как только пришли данные, сразу происходит запуск отдельного потока чтения, в котором осуществляется основная работа. Пока он работает, на канале стоит статус busy".
Возможно в дальнейшем я переделаю всю структуру, и  оставлю только Диспетчер Файлов и непосредственно сам поток чтения...

Насчет записи, насколько я знаю iostream буферизирует данные сам, а потом только пишет. Поэтому я с буферизацией и не заморачивался, если быть точнее, то запись осуществляется как-то так :
(ofstream *)outFile->write((char*)buf2byte, 2);
А частота у меня 256/16 = 16 КГц. Думаете это много для 4-х ядерного процессора с частотой 2.7 ГГц?

Насчет переполнения буфера... Не успевает iostream? Тогда при чем здесь ADC_Ovf_Event? Буфер переполняется где? В потоке iostream? Не совсем понял, о каком буфере идет речь, уточните, пожалуйста...

Насчет счетчиков... Вы имеете в виду I_ADC_PCI_COUNT_L791? Да, плата в режиме bus master. Счетчик корректно отрабатывает, как мне кажется...
tmpposptr[I_ADC_PCI_COUNT_L791] во всех потоках показывает одинаковое значение (величину от 0 до 131072). Я его использую, для того, чтобы отследить заполнение кольцевого буфера.

26.04.2013 18:29:47
#11

Сотрудник "Л Кард"
Здесь с 18.04.2014
Сообщений: 810

Re: Проблемы с записью данных платы L791

> А частота у меня 256/16 = 16 КГц. Думаете это много для 4-х ядерного процессора с частотой 2.7 ГГц?
Не знаю. Загрузку CPU посмотрите и проверьте ADC_Ovf_Event.

>Не совсем понял, о каком буфере идет речь
О буфере АЦП. Карта работает асинхронно и поставляет данные с постоянной скоростью, т.е. программа должна обрабатывать их за заведомо меньшее время (в среднем на отсчет)

Насчет PCI_COUNT я не уверен, не занимаюсь L791. Хотя с функцией abs() кажется странным. Если Вы хотите получить расстояние от последней считанной позиции до убежавшего вперед по циклическому буферу счетчика, то скорее не abs(new-old), а
new = PCI_COUNT;
delta = (new >= old) ? new - old : BUF_LEN - old + new;
или, если BUF_LEN - заведомо степень двойки,
delta = (new - old) & (BUF_LEN - 1)
Потому что если new = old - 1, то буфер полон, а abs() при переходе через конец буфера начнет убывать.

Konstantin
27.04.2013 14:34:00
#12

Гость

Re: Проблемы с записью данных платы L791

<"Кстати, я не очень понимаю, зачем выделять динамически malloc(4) и malloc(2) (а чем не устроила просто локальная переменная?), но уж
int *buf2byte = (int*)malloc(2);
и потом запись
*buf2byte = ...
- это хороший шанс испортить память или получить segmentation fault.">

Локальные переменные? Т.е.
int buf4byte;
short buf2byte;
А как без memcpy забирать из буфера 4 байта? Поясните... Не совсем понял...

<"Потому что если new = old - 1, то буфер полон, а abs() при переходе через конец буфера начнет убывать.">
Я Вас понял, но у меня немного другая задумка была...
while (abs(tmpposptr[I_ADC_PCI_COUNT_L791] - (kadr + channel * 4))< 64 * 10)
usleep(10);

Этим циклом я поддерживаю стабильное отставание позиции считывания от позиции записи на 10 кадров... abs() как раз и нужен для перехода через конец кольцевого буфера. Таким образом я буду ждать, только когда позиция считывания приблизится к позиции записи больше, чем на 10 кадров. Поправьте, если ошибаюсь...

А насчет пропусков данных я уже и не знаю на что думать... Проверял позицию чтения и позицию записи, так обгона не происходит. Пауза отрабатывает и при переходе через конец буфера. Сейчас буду смотреть ADC_Ovf_Event и загрузку проца, но мне кажется, что дело в чем-то другом...

29.04.2013 11:50:52
#13

Сотрудник "Л Кард"
Здесь с 18.04.2014
Сообщений: 810

Re: Проблемы с записью данных платы L791

>int buf4byte;
>short buf2byte;
>А как без memcpy забирать из буфера 4 байта?

Вообще указатель на данные из платы (tmpbegptr) должен быть не unsigned short* (16-битный), а uint32_t*, потому что это соответствует разрядности данных, которые оттуда читаются.
Тогда забрать 4 байта можно оператором присваивания. Например:

volatile uint32_t* src_ptr; /* указатель на буфер карты */
uint32_t src_index; /* смещение в буфере src_ptr в ДВОЙНЫХ СЛОВАХ */
...
uint16_t sample = (uint16_t)((src_ptr[src_index] & 0xFFFF) << 2);

И никаких malloc, memcpy, и временная переменная на 4 байта не нужна.

Кстати, проверьте, как Вы вычисляете смещение в буфере. Я смотрю, в одном месте kadr + channel * 4, в другом - (kadr + channel) * 4. Как раз во избежание путаницы я и советую вычислять смещения не в байтах, а в "размерах того, на что указывает указатель", что соответствует синтаксису языка C, т.е.
*(ptr + n) есть то же, что ptr[n], и отстоит от ptr на (n * sizeof(*ptr)) байт.

>abs() как раз и нужен для перехода через конец кольцевого буфера. Таким образом я буду ждать, только когда позиция считывания приблизится к позиции записи больше, чем на 10 кадров.

Приблизится с какой стороны? Функция abs() просто не является корректным способом вычисления количества данных в кольцевом буфере.
Возьмем буфер из 8 ячеек:
[--] [--] [--] [--] [--] [--] [--] [--]
Теперь обозначим R позицию чтения, а W позицию записи. Занятые (записанные, но не забранные) ячейки обозначим "x".
Сравниваем abs(W-R) и buf_used = (W >= R) ? W - R : 8 - R + W (здесь 8 = размер буфера).
Пример 1.
[Rx] [W-] [--] [--] [--] [--] [--] [--]
Занята 1 ячейка.
R = 0, W = 1, abs(W-R) = 1, buf_used = 1-0 = 1

Пример 2. То же на другом месте
[W-] [--] [--] [--] [--] [--] [--] [Rx]
Занята 1 ячейка.
R = 7, W = 0, abs(W-R) = 7, buf_used = 8-7+0 = 1

Пример 3.
[Rx] [-x] [-x] [-x] [-x] [-x] [-x] [W-]
Занято 7 ячеек (буфер полон).
R = 0, W = 7, abs(W-R) = 7, buf_used = 7-0 = 7

Пример 4. То же в другом месте.
[-x] [-x] [-x] [-x] [-x] [-x] [W-] [Rx]
Занято 7 ячеек (буфер полон).
R = 7, W = 6, abs(W-R) = 1, buf_used = 8-7+6 = 7

Так понятно? smile

Konstantin
30.04.2013 09:17:57
#14

Гость

Re: Проблемы с записью данных платы L791

А src_index это kadr + channel размером 4 байта?
Смещение указателя кольцевого буфера у меня везде (kadr + channel*4)/2... Спасибо за пояснение, обязательно воспользуюсь Вашим советом!

Насчет abs(). У меня в программе чтение из кольцевого буфера всегда идет быстрее, чем запись в него, поэтому ни 3 ни 4 примеры не могут произойти. Во втором примере у меня в программе все будет нормально, т.к. если расстояние между W и R больше 10 кадров, то я продолжаю чтение из буфера...

30.04.2013 17:03:28
#15

Сотрудник "Л Кард"
Здесь с 18.04.2014
Сообщений: 810

Re: Проблемы с записью данных платы L791

src_index в моем примере - это количество 32-битных слов от начала буфера (потому что индекс массива DWORD/'ов). В каких там единицах у Вас kadr и channel - посчитайте, пожалуйста, сами smile

>всегда идет быстрее, чем запись в него, поэтому ни 3 ни 4 примеры не могут произойти
Каждый десятый апельсин у меня отравленный, но я никогда не ем больше восьми smile
Это просто арифметически неправильно, но да, если буфер никогда не бывает "почти полон", ошибка не проявится в этом коде. Пока Вы не сделаете что-то другое, например, начнете не только сравнивать этот abs() с маленьким порогом.

30.04.2013 18:41:41
#16

Сотрудник "Л Кард"
Здесь с 18.04.2014
Сообщений: 810

Re: Проблемы с записью данных платы L791

А нет, проявится, конечно, это я уже устал.
Пример 2 прекрасно будет возникать: буфер почти пуст, но abs() даст большое значение.
Причем это будет повторяться аккурат в каждом проходе буфера, потому что он циклический, т.е. позиция записи и бегущая за ней позиция чтения постоянно вертятся по буферу и регулярно проходят его конец.

Konstantin
06.05.2013 08:40:07
#17

Гость

Re: Проблемы с записью данных платы L791

<"Пример 2 прекрасно будет возникать: буфер почти пуст, но abs() даст большое значение.
Причем это будет повторяться аккурат в каждом проходе буфера, потому что он циклический, т.е. позиция записи и бегущая за ней позиция чтения постоянно вертятся по буферу и регулярно проходят его конец.">

Хорошо! Убедили! А если вот так:
while((abs(W-R)<10)&&(abs(W-R)<(size_of_buf-10)))
usleep(10);

Тут size_of_buf это полный размер буфера...

Konstantin
06.05.2013 08:42:15
#18

Гость

Re: Проблемы с записью данных платы L791

Блин, у Вас на форуме нельзя исправлять... Там ошибочка:

while((abs(W-R)<10)&&(abs(W-R)>(size_of_buf-10)))
usleep(10);

Ну вот так по идее...

Konstantin
07.05.2013 15:43:47
#19

Гость

Re: Проблемы с записью данных платы L791

Сейчас посмотрел свой предыдущий пост... Писал утром, видимо мозг не включился еще:) Там "или" в условии, вместо "и".

А по существу поста, после всех вышеприведенных доработок, пропуски данных остались. Попробую сделать дополнительную буферизацию перед записью в файл... Может поможет.

13.05.2013 10:52:11
#20

Сотрудник "Л Кард"
Здесь с 18.04.2014
Сообщений: 810

Re: Проблемы с записью данных платы L791

Константин, программа Ваша, Вы можете выбрать любую формулу, какая Вас устроит. Мне кажется более естественным использовать корректную формулу, отвечающую на вопрос "сколько ячеек в данный момент занято (свободно) в буфере" и сравнивать ее результат с порогом, что отражает "физику" процесса.
Формулу я приводил выше.

Сознательно неточные вычисления (например, верные только на подмножестве области определения) МОЖЕТ быть смысл использовать - в тех случаях, когда точное вычисление неприемлемо долго или ресурсоемко. Тогда действительно приходится заменять вычисление оценкой, причем в большинстве задач, по-видимому, выбирать формулу так, чтобы ошибка могла быть только в сторону перестраховки.

Но в данном случае правильная формула
((W >= R) ? W - R : size_of_buf - R + W) < 10
не сложнее, а, кажется, проще (быстрее) Вашего последнего варианта.

Ладно, это действительно все несущественно. А почему у Вас пропадают данные, проверьте. Посмотрите процент загрузки CPU программой, проверьте счетчики переполнений буфера платы. Мы это обсуждали выше.

Konstantin
20.05.2013 13:39:17
#21

Гость

Re: Проблемы с записью данных платы L791

Сделал буферизацию, и немного оптимизировал программу. Проверил загрузку процессора. Она в холостом режиме 7%, под нагрузкой 12-14%. Приемлемо.
ADC_Ovf_Event еще не посмотрел. Данные по прежнему теряются... Скажите Александр, а такой метод разбора 4 байт для каждого канала будет корректно работать в 64-битной среде?
uint16_t sample = new uint16_t[MAX_BUF_LEN/2];
sample[indedx] = (uint16_t)((src_ptr[src_index] & 0xFFFF) << 2);
В 64 битной системе операция "& 0xFFFF" будет правильно работать? Я раньше не сталкивался с 64 битной архитектурой...

20.05.2013 16:14:02
#22

Сотрудник "Л Кард"
Здесь с 18.04.2014
Сообщений: 810

Re: Проблемы с записью данных платы L791

>В 64 битной системе операция "& 0xFFFF" будет правильно работать?
Не пойму, что имеется в виду. Как она может работать некорректно? Это побитовое И с константой. Результат Вы явно преобразуете в uint16_t.

Konstantin
20.05.2013 16:37:57
#23

Гость

Re: Проблемы с записью данных платы L791

Ну, я знаю, например, что число 0xffffffff (или -1) для 64 битной системы некорректно.
Вот здесь http://www.viva64.com/ru/a/0004/
пример ошибки:
#define INVALID_RESULT (0xFFFFFFFFu)
size_t MyStrLen(const char *str) {
  if (str == NULL)
    return INVALID_RESULT;
  ...
  return n;
}
size_t len = MyStrLen(str);
if (len == (size_t)(-1))
  ShowError();
условие (len == (size_t)(-1)) не выполнится в 64 битной системе.
Поэтому я и спросил...

20.05.2013 19:13:42
#24

Сотрудник "Л Кард"
Здесь с 18.04.2014
Сообщений: 810

Re: Проблемы с записью данных платы L791

Потому что size_t в них 64-битный.
Тут ошибка в том, что явно задается константа в дополнительном коде, и если она будет интерпретирована как значение с типом большей разрядности, то получится положительное число.

#include <stdio.h>
int main(void)
{
signed char c = 0xFF;
int i = 0xFF;
printf("(int)c = %d i = %d/n", (int)c, i);
return 0;
}

OUTPUT:
(int)c = -1 i = 255

Причем gcc с большим уровнем warning/'ов говорит
"warning: conversion to /'signed char/' alters /'int/' constant value [-Wconversion]"

У Вас результат все равно преобразуется в uint16_t (кстати, можно и в int16_t), поэтому разрядность промежуточных вычислений не играет роли. И заодоно в linux x64 int 32-битный, только long и size_t - 64. Ну и указатели, разумеется.

Konstantin
24.05.2013 16:36:51
#25

Гость

Re: Проблемы с записью данных платы L791

Здравствуйте. Не хочу создавать отдельную тему... Вопрос к Poul.
Подскажите, пожалуйста, с какой частотой обновляется счетчик наполнения буфера для платы L791 (I_ADC_PCI_COUNT)? Я имею ввиду pp[I_ADC_PCI_COUNT] в Вашем примере test.cpp. Подозреваю, что перед его проверкой необходимо выставить паузу на некоторое время, вот только на какое? Жду Вашего ответа, спасибо!