Работа с буферами по прерываниям в реальном времени

прием, с помощью которого можно превращать любые данные в любые другие, только неизвестно, в какие
 
1 2 3 4

Xan

координатор

AXT>> PS: Товарищи модераторы, перенесите этот буфферосрач куда-нибудь пожалуйста, в теме про топлива он явно ни к чему. Начиная отсюда Топлива на нитрате натрия. [AXT#17.12.14 12:29]
varban> Угу, только доберусь до компа.

В тред "Споры с СашейПро".
Там самое место.
 

varban

администратор
★★★
Xan> В тред "Споры с СашейПро".
Xan> Там самое место.

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

Еще хочу попросить инженеров-вольнодумцев дожать тему и сделать доброе дело :)

Быть добру! © Non Conformist ;)
 39.0.2171.9539.0.2171.95

+
-
edit
 

SashaMaks
SashaPro

аксакал

SashaMaks>> Ты предлагаешь прервать запись на флешку? А это делать-то можно?
AXT> Зависит от типа. Между блоков можно у всех. Внутри блока — есть варианты:

Для начала сверим правильность того, что ты предложил по алгоритму с применением асинхронных прерываний и с двойной буферизацией ("пинг-понг").
Это алгоритм прерывания с АЦП и записи данных на Фешку:

code text
  1. ISR(ADCA_CH0_vect, ISR_BLOCK)
  2. {
  3.         switch (Buffer_Select) {
  4.                 case 1:
  5.                         if (!ADC_Log1){
  6.                                 ADC_Buffer1[ADC_I1] = ADC_ResultCh_GetWord(&ADCA.CH0);
  7.                                 if (ADC_I1 = 255){
  8.                                         ADC_Log1 = true;
  9.                                         Buffer_Select = 2;
  10.                                 }
  11.                                 ADC_I1++;
  12.                         }                      
  13.                         break;
  14.                 case 2:
  15.                         if (!ADC_Log2){
  16.                                 ADC_Buffer2[ADC_I2] = ADC_ResultCh_GetWord(&ADCA.CH0);
  17.                                 if (ADC_I2 = 255){
  18.                                         ADC_Log2 = true;
  19.                                         Buffer_Select = 1;
  20.                                 }
  21.                                 ADC_I2++;
  22.                         }                      
  23.                         break;
  24.         }
  25. }
  26. void ADC_Data_Write (void)
  27. {
  28.         if (ADC_Log1){
  29.                 f_write(&file1, ADC_Buffer1, cnt, &s2);
  30.                 ADC_Log1 = false;
  31.         }
  32.         if (ADC_Log2){
  33.                 f_write(&file1, ADC_Buffer2, cnt, &s2);
  34.                 ADC_Log2 = false;
  35.         }      
  36. }

Ну и сам бесконечный цикл:
code text
  1. //Инициализация буферов значениями по умолчанию 100
  2. for (uint16_t I = 0; I < 256; ++I) {
  3.         ADC_Buffer1[I] = 100;
  4.         ADC_Buffer2[I] = 100;
  5. }
  6. for (;;) {
  7.         ADC_Data_Write();
  8. }

Думаю, всё должно быть понятно.
Это сообщение редактировалось 20.12.2014 в 00:17
+
+1
-
edit
 

Xan

координатор

SashaMaks> Думаю, всё должно быть понятно.

На троечку.
Направление верное, но этот текст работать не будет, там три ошибки.

И непонятно, зачем ты частоту отсчётов задаёшь скоростью работы АЦП. Это не гибко.
Правильно — от таймера.
 

SashaMaks
SashaPro

аксакал

Xan> На троечку.
Xan> Направление верное, но этот текст работать не будет, там три ошибки.

Да, Дельфи - страшная сила)))

code text
  1. ISR(ADCA_CH0_vect, ISR_BLOCK)
  2. {
  3.         switch (Buffer_Select) {
  4.                 case 1:
  5.                         ADC_Buffer1[ADC_I1] = ADC_ResultCh_GetWord(&ADCA.CH0);
  6.                         if (ADC_I1 == 255){
  7.                                 ADC_Log1 = true;
  8.                                 Buffer_Select = 2;
  9.                         }
  10.                         ADC_I1++;              
  11.                         break;
  12.                 case 2:
  13.                         ADC_Buffer2[ADC_I2] = ADC_ResultCh_GetWord(&ADCA.CH0);
  14.                         if (ADC_I2 == 255){
  15.                                 ADC_Log2 = true;
  16.                                 Buffer_Select = 1;
  17.                         }
  18.                         ADC_I2++;              
  19.                         break;
  20.         }
  21. }
  22.  
  23. void ADC_Data_Write (void)
  24. {
  25.         if (ADC_Log1){
  26.                 f_write(&file1, ADC_Buffer1, cnt, &s2);
  27.                 ADC_Log1 = false;
  28.         }
  29.         if (ADC_Log2){
  30.                 f_write(&file1, ADC_Buffer2, cnt, &s2);
  31.                 ADC_Log2 = false;
  32.         }      
  33. }


Xan> И непонятно, зачем ты частоту отсчётов задаёшь скоростью работы АЦП. Это не гибко.
Xan> Правильно — от таймера.

Сойдет. Сейчас это не важно.

Xan

координатор

SashaMaks> Да, Дельфи - страшная сила)))

1. Это не Дельфя, это Си.
2. Ошибок стало меньше, но только потому, что ты не весь текст скопировал. :D
 

SashaMaks
SashaPro

аксакал

Xan> 1. Это не Дельфя, это Си.
Xan> 2. Ошибок стало меньше, но только потому, что ты не весь текст скопировал. :D

Это всё, вероятно, очень весело. Если тебе в коде чего-то не нравится так и напиши сразу. Что не скопировал, то выше написано.
+
-
edit
 

SashaMaks
SashaPro

аксакал

varban> Еще хочу попросить инженеров-вольнодумцев дожать тему и сделать доброе дело :)

Что-то энтузиазма у инженеров-вольнодумцев по убавилось как-то.
Скучно даже, а тут ведь столько всего интересного...
+
-
edit
 

Floyd

аксакал

SashaMaks> Скучно даже, а тут ведь столько всего интересного...

У тебя в цикле перманентная запись ;)

Я бы писал только по признаку заполнения буфера, набрал 512 байт - отправил их на запись. Чтобы всегда удовлетворить обработчик прерывания, в состоянии когда буфер будет "залочен" выгрузкой, буферов должно быть минимум два и переключаться они должны "по кругу" (реализуется через указатели).

Все оставшееся время, когда прерывания не обрабатываются, математика не вычисляется, данные не выгружаются - устройство должно спать, а не выполнять холостые циклы перерабатывая энергию в тепло ;)
 34.034.0
+
-
edit
 

SashaMaks
SashaPro

аксакал

Floyd> У тебя в цикле перманентная запись ;)

Какая запись? А по русски можно?

Floyd> Я бы писал только по признаку заполнения буфера

Что это поменяет?

Floyd> буферов должно быть минимум два...

Так у меня и есть два буфера: ADC_Buffer1 и ADC_Buffer2. Указатели не увеличивают количество буферов.

Floyd> устройство должно спать, а не выполнять холостые циклы перерабатывая энергию в тепло ;)

А это что меняет?
+
-
edit
 

Floyd

аксакал

Floyd>> У тебя в цикле перманентная запись ;)
SashaMaks> Какая запись? А по русски можно?

code text
  1. for (;;) {
  2. ADC_Data_Write();
  3. }


Floyd>> Я бы писал только по признаку заполнения буфера
SashaMaks> Что это поменяет?

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

Floyd>> буферов должно быть минимум два...
SashaMaks> Так у меня и есть два буфера: ADC_Buffer1 и ADC_Buffer2. Указатели не увеличивают количество буферов.

действительно, указатель указывает на активный :)

Floyd>> устройство должно спать, а не выполнять холостые циклы перерабатывая энергию в тепло ;)
SashaMaks> А это что меняет?

Энергопотребление, искренне ваш КО. Тебя же беспокоило 100% утилизации ядра? А в твоем случае оно всегда будет 100%

: Power Management and Sleep Modes

Use of the SLEEP instruction can allow an application to reduce its power comsumption considerably. AVR devices can be put into different sleep modes. Refer to the datasheet for the details relating to the device you are using. There are several macros provided in this header file to actually put the device into sleep mode. The simplest way is to optionally set the desired sleep mode using set_sleep_mode() (it usually defaults to idle mode where the CPU is put on sleep but all peripheral clocks are still running), and then call sleep_mode(). // Дальше — www.nongnu.org
 
 34.034.0
Это сообщение редактировалось 20.12.2014 в 20:47
+
-
edit
 

SashaMaks
SashaPro

аксакал

Как же всё запущено.

Floyd> Во-первых - формируется полный пакет данных, во-вторых данные пишутся пачкой, а не по несколько байт.

Ну вот функция записи буфера.
f_write(&file1, ADC_Buffer1, cnt, &s2);
&file1 - указатель на файл
ADC_Buffer1 - буфер с указателем на его первый элемент (поэтому без &).
cnt - размер пакета записи кратный 512 - стольким и равен.
&s2 - указатель на переменную в которую записывается информация о количестве фактически записанных байтов.

Где ты тут увидел запись по несколько байт или по капли?

Floyd> Энергопотребление, искренне ваш КО. Тебя же беспокоило 100% утилизации ядра? А в твоем случае оно всегда будет 100%

Нет, не это меня беспокоило. Тут тема просто некорректно выхваченная из контекста:

Топлива на нитрате натрия. [SashaMaks#03.12.14 14:41]

… … … … Не стоило так категорично писать. Инерционность датчика оказалась ни при чём. Частота тоже не при делах. Скачки - это ожидание записи буфера на флешку, размер которого, как известно для файловой системы FAT, не может быть меньше 512 байт. Любая попытка что-то считать или записать, даже 1 байт с неё, приводит к чтению или записи всех последующих 512 байтов (это 256 циферок в 16 битного размера с данными). И всё это пока делается софтом через проц побайтно. Если при частоте проца 32МГц и…// Ракетомодельный
 

Беспокоила меня запись данных со скачками по времени при полной загрузке АЦП. Неравномерность временных интервалов измерений искажает сигнал или данные с датчика.
+
-
edit
 

Floyd

аксакал

SashaMaks> Как же всё запущено.
Ну, тебе виднее :)

PS:
SashaMaks> Беспокоила меня запись данных со скачками по времени при полной загрузке АЦП. Неравномерность временных интервалов измерений искажает сигнал или данные с датчика.

Используй прерывание от таймера, а запись может быть и асинхронной.

PPS: Апломб эпический :)
 34.034.0
Это сообщение редактировалось 20.12.2014 в 21:48
+
-
edit
 

SashaMaks
SashaPro

аксакал

Floyd> Используй прерывание от таймера, а запись может быть и асинхронной.

Может, так и было, так и оставлю. Только буфер записывается от 4096 тактов до где-то 8000 и прерывать этот процесс когда вздумается нельзя. А АЦП может выдавать инфу каждые 160 тактов (200кГц при частоте ЦП 32МГц), поэтому протиснуть этот буфер на флешку за 160 тактов невозможно, не нарушив равномерность данных по времени. Вот и возникает задержка по времени периодически, когда идет запись буфера.
+
-
edit
 

Floyd

аксакал

Floyd>> Используй прерывание от таймера, а запись может быть и асинхронной.
SashaMaks> Только буфер записывается от 4096 тактов до где-то 8000 и прерывать этот процесс когда вздумается нельзя.

SPI можно прерывать, при условии что шина будет эксклюзивна на протяжении всей транзакции.
 34.034.0
+
-
edit
 

SashaMaks
SashaPro

аксакал

Floyd> SPI можно прерывать, при условии что шина будет эксклюзивна на протяжении всей транзакции.

Честно пытался это сделать, не получилось. Хотел вызвать ошибку, которые на ПК обычно вызывают BSOD. Но на XMega есть куча всего, что не даёт свершиться такой глупости. В целом организован, видимо, очень даже неплохой аппаратный алгоритм диспетчера задач для периферии и ЦП. Но если есть диспетчеризация задач, значит прерывания в любой момент времени не возможны, так как есть квантование процессов и о равных интервалах времени придётся забыть. Кстати алгоритм диспетчеризации - это неотъемлемый и важный компонент ОС. Поэтому я и писал, что нет у Xana в его примере никакой ОС.

Короче говоря, если пытаться делать через прерывание записи буфера, то уменьшается частота вызовов этих самых прерываний, из-за работы диспетчеризации. Поэтому с АЦП получилось получить лишь 21кГц данных. Если на эту частоту, как и в моём изначальном алгоритме наложить ещё 16 кратное суммирование, то частота данных на выходе будет соответственно всего лишь 1300Гц. Это максимум возможного, так как загрузка ЦП 100%. Но точность по оси Y будет ниже, так как АЦП работает на порядок более низкой частоте. Сейчас я переписал обратно на свой алгоритм с частотой работы АЦП в 200кГц и 256 суммирований на частоту данных почти 800Гц. Пока что это самый лучший результат без потери точности по времени. Хотя так же можно уменьшить суммирование до 160 и поднять частоту данных до 1200Гц. Алгоритм очень гибкий.
+
-
edit
 

Floyd

аксакал

Floyd>> SPI можно прерывать, при условии что шина будет эксклюзивна на протяжении всей транзакции.
SashaMaks> В целом организован, видимо, очень даже неплохой аппаратный алгоритм диспетчера задач для периферии и ЦП.

Это обыкновенный микроконтроллер, хоть и навороченный. В нем нет никакого планировщика.

SashaMaks> Но если есть диспетчеризация задач, значит прерывания в любой момент времени не возможны, так как есть квантование процессов и о равных интервалах времени придётся забыть.

А как по твоему работает твой ПК? ;)

Прерывание на то и прерывание что никак не зависит от обычного функционирования процессора. Некоторые из них можно запретить, но не более. Более того, квантование - есть обычно прерывание от таймера :) А таймер - это вообще отдельный такой девайс не зависящий от тактирования процессора. Ты же замечал что при отсутствии нагрузки у тебя процессор работает с более низкой частотой и это не означает что у тебя в это время таймер работает медленнее :)
 39.0.2171.9539.0.2171.95
RU Серокой #21.12.2014 18:10  @Floyd#21.12.2014 17:56
+
+1
-
edit
 

Серокой

координатор
★★★
Floyd> А таймер - это вообще отдельный такой девайс не зависящий от тактирования процессора.
За всех не скажу, скажу за MIPS. Там есть таймер в ядре, который работает от тактовой процессора (и прерывание по совпадению count с compare), а есть внешние таймеры, работающие от внешней частоты.
Причём для работы, скажем, ОС-Линукса, достаточно первого таймера.
Больше не раскалятся ваши колосники. Мамонты пятилеток сбили свои клыки. ©  
+
-
edit
 

SashaMaks
SashaPro

аксакал

Floyd> Это обыкновенный микроконтроллер, хоть и навороченный. В нем нет никакого планировщика.

Я не про планировщик писал, а про диспетчеризацию задач. Условно простой алгоритм, который автоматически блокирует все прерывания, когда их делать нельзя, и те ждут в очереди, пока не снимется блокировка.

Floyd> Прерывание на то и прерывание что никак не зависит от обычного функционирования процессора.

Не зависит, но есть устройство, которое отвечает за работу самих прерываний.

Floyd> Некоторые из них можно запретить, но не более.

Запрещаются все прерывания а не по выбору.

Floyd> Более того, квантование - есть обычно прерывание от таймера :)

Квантование - это не таймер.
+
+1
-
edit
 

Floyd

аксакал

SashaMaks> Запрещаются все прерывания а не по выбору.

Слушай, ты реально утомляешь. С тобой дискутировать, как в стенку стучать.
Ладно бы аргументировал, а то каждый ответ односложен и самоуверен.


Если речь идет о Xmega:

The Non-Maskable Interrupt (NMI) is a special interrupt that cannot be disabled, and
is used to for system critical interrupts. NMI is used for critical failures such as a
failure in the crystal oscillator.
 




The XMEGA A1 device has one NMI source, the Crystal Oscillator Failure NMI.
If a crystal is used as system clock, the clock from the crystal oscillator is monitored.
If for some reason the crystal clock stops (e.g. due to physical damage to the crystal)
an NMI is generated and the internal 2 MHz RC oscillator takes over as system clock.
Since an NMI interrupt by definition cannot be disabled, there is no available
mechanism to disable the NMI from software once enabled. The only way to disable
the NMI is to reset the MCU, which will bring back the initial state where the NMI is
disabled. Refer to application note AVR1003 covering the XMEGA Clock System for
more information about crystal failure detection and the clock system in general.
 
 39.0.2171.9539.0.2171.95
+
-
edit
 

SashaMaks
SashaPro

аксакал

Floyd> Слушай, ты реально утомляешь. С тобой дискутировать, как в стенку стучать.
Floyd> Ладно бы аргументировал, а то каждый ответ односложен и самоуверен.
Floyd> Если речь идет о Xmega:

А ты похож на проигравшего спорщика, который цепляется за любую последнюю соломинку. :D

Прерывания от переферии не являются прерываниями NMI! Я как раз хотел вызвать критическую ошибку от прерывания, чтобы сработало прерывание NMI. Но XMega хорошо защищена от сбоев в работе собственных устройств.
RU SashaMaks #21.12.2014 19:13  @SashaMaks#21.12.2014 18:59
+
-
edit
 

SashaMaks
SashaPro

аксакал

SashaMaks> Я как раз хотел вызвать критическую ошибку от прерывания, чтобы сработало прерывание NMI.

Наиболее известный для всех результат работы такого прерывания NMI является BSOD:
+
-
edit
 

Floyd

аксакал

SashaMaks> А ты похож на проигравшего спорщика, который цепляется за любую последнюю соломинку. :D

А, тут спор оказывется. Интересно кого с кем ? :)
 34.034.0
+
-
edit
 

SashaMaks
SashaPro

аксакал

Floyd> А, тут спор оказывется.

Ты и это только сейчас заметил))) Или это для тебя что-то меняет?

Floyd> Интересно кого с кем ? :)

Ну как же, все участники очевидны:
Сторона А: AXT, Xan, Floyd.
Сторона Б: SashaMaks.
+
-
edit
 

Floyd

аксакал

SashaMaks> Ну как же, все участники очевидны:
SashaMaks> Сторона А: AXT, Xan, Floyd.
SashaMaks> Сторона Б: SashaMaks.

ты явно мне льстишь :D
 34.034.0
1 2 3 4

в начало страницы | новое
 
Поиск
Настройки
Твиттер сайта
Статистика
Рейтинг@Mail.ru