0
> По стандарту С все нормально
а что говорит стандарт? я лично этого не понял. есть две функции, которые, казалось бы, должны давать один и тот же результат при одинаковых параметрах, но результат разный:
int foo2(int a, int b) {
  return a / b;
}
int foo1(int a) {
    return a / -1;
}


> int хранит симметричный диапазон от -32767 до 32767
диапазон-то как раз не симметричный: -32768 до 32767

> Впрочем, подобные грабли — визитная карточка С
ради интереса написал то же самое на java и на free pascal. результат одинаков:
foo1: -2147483648
foo2: -2147483648

т.е. делается софтверная проверка и процессорное исключение не допускается, просто переполняется переменная.

> Меня другое удивило — почему исключение floating point?
я не знаю как на винде, на unix всего один сигнал, который отвечает за все математически/арифметические исключения -SIGFPE, вот он и генерируется системой. а для того, чтобы все-таки различить исключение, нужно позвать fegetexceptflag и почекать нужный бит. а оболочка bash этого не делает, а просто говорит: был сигнал floating point exception, убил вашу программу.
  • avatar
  • rouming
  • 31 января 2013, 12:15
+1
Весь цимес в том, что именно процессор x86 генерирует исключение, как при делении на ноль. А стандарт С лишь отмалчивается, не делая никаких проверок и не уточняя результат на других процессорах, пущай программист сам думает.
  • avatar
  • rouming
  • 31 января 2013, 09:30
0
очевидно-то оно очевидно… как деление на 0, но, к сожалению, баги сами себя не пофиксят. кулхацкерам на заметку:
креш PostgreSQL или антивируса
креш Windows 8

а можно придумать такой код:
int foo1(int a) {
    return a / -1;
}

который, казалось бы, делает тоже самое, если 'a == INT_MIN', только вот компилятор сгенерирует такой код:
0000000000000010 <foo1>:
  10:	89 f8                	mov    %edi,%eax
  12:	f7 d8                	neg    %eax
  14:	c3                   	retq   

где инструкция neg — Two's Complement Negation (эквивалент return 0 — a) и никаких исключений процессора генерироваться не будет, а получим мы опять INT_MIN.

т.е. да, поведение неопределено, все согласно стандарту С.
  • avatar
  • rouming
  • 30 января 2013, 17:58
0
> параметр -F изменён на -f и… не происходит никаких изменений настроект порта :))

ну я брал вызов со своей lin машины, а на mac лишь посмотрел, что вызов такой есть. так что да, параметры могли и разъехаться. но если изменений никаких самого tty устройства не происходит, то скорее всего виной тому драйвер tty. например, мой виртуальный usb-com свисток устроен на cp2102 чипе, для которого в lin есть соответствующий драйвер, и для него все настройки stty сваливаются в cp210x_set_termios вызов. это я к тому, что, возможно, часть параметров stty выставляет как-нибудь иначе нежели скаченный консольный терминал (ну например не через tcsetattr вызов, а через какой-нибудь особенный ioctl, который не поддерживает ваш pl2303 драйвер). в любом случае, раз вы драйвер качали с сорсфорджа, его можно ковырнуть.

а вообще, на usb-com свистке можно быстро сделать простое usb устройство, не городя огород с v-usb: с контроллера пишите/читаете как uart, а на хосте читаете/пишите в само tty устройство. для домашней коленочной связки host<->usb<->uart<->avr оч удобно.

> и не выйдешь правильно, может вызвать коллапс и ступор у начинающего пользователя.
ну это как про vim:
«koandrew: Я первые несколько раз из него ресетом выходил» (C) bor
  • avatar
  • rouming
  • 26 января 2013, 13:18
+1
+1
Отличная статья. Даешь популяризацию AVR в массах яблочников.

Единственное, я хотел бы добавить, что можно не качать и не ставить никаких tty терминалов, а использовать имеющиеся тулзы.
Например, для tty девайса вы можете один раз выставить настройки командой stty:
$ stty -F /dev/ttyUSB0 cs8 9600 ignbrk -brkint -icrnl -imaxbel -opost -onlcr -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke noflsh -ixon -crtscts
после чего вы сможете открывать сам девайс из любого приложения, работающего на хосте, просто делая open, read, write;
а для интерактивного общения с контроллером использовать удобный консольный screen:
$ screen /dev/ttyUSB0 9600

ну это так, оптимизация.
  • avatar
  • rouming
  • 25 января 2013, 23:11
0
ат же ж. случайно ушло раньше.

> Та ви шо! А откройте апноту из статьи и посмотрите, как там сделано.
в апноте сказано, что «а мы здесь не учли переполнение. сделайте сами».

> Все примеры, что мне удалось найти, работают через Ж.
я обычно ищу сразу на западных ресурсах, в моем результате:
«google: avrfreaks capture input overflow interrupt»
первая ссылка
шестая ссылка
с шестой ссылки попадаем сразу практически на готовый код

> Это и есть та проблема, чтоя решил и поделился.
ясно. вы слишком много уделили времени на конкретные детали своей задачи, приправив это все соусом «лучшие идеи Светлой Стороны и только для вас». это несколько обескураживает
  • avatar
  • rouming
  • 15 января 2013, 12:50
0
> если что-то можно сделать быстро, зачем это делать медленно
вопрос конкретной задачи. так как это ваша задача, то вам и оптимизировать. я лишь рыбу набросал

> всё volatile между прочим
volatile там совершенно не нужен.
вы в цикле зовете функцию mcu_timers_manager, которая является sequence point (с99 standard, sequence point, annex c), т.е. барьером для компилятора, т.е. никаких оптимизацией применяться не будет. а вот код каждого обработчика прерывания _с_ volatile переменной будет создан куда неоптимальней, так как любая операция над volatile переменной обязует компилятор читать/писать в память, что совершенно не нужно. я несколько месяцев назад поднимал топик на эту тему we.easyelectronics.ru/Soft/skolzkaya-dorozhka-dlya-poklonnikov-volatile.html, там это обсуждалось.

> Показания плавают, и плавают не хило. Хотя частота стоит как влитая.
а что из этого следует? не понял

>
  • avatar
  • rouming
  • 15 января 2013, 12:32
0
для пущей наглядности:
(исходник диаграммы: goo.gl/S7v59)

  • avatar
  • rouming
  • 12 января 2013, 21:51
0
> А тот код делает проверку на флаг ovf, но оно могло произойти позже события захвата icr1.

ну представьте: мы копируем перменную. переполнение либо было либо еще нет. через N тактов узнаем, что переполнение было, тогда остается узнать, а затронуло ли случившееся переполнение наше значение, если:
1. значение >= половины, то мы скопировали раньше, чем фактически случилось переполнение, а значит компенсировать (прибавлять t1_ovf на единицу) не нужно.
2. значение < половины, то переполнение было раньше, а значит нужно сейчас отработать переполнение (t1_ovf +=1) и снять прерывание.

все это будет работать, если мы находимся в прерывании не дольше, чем половина оттикавшего таймера.
переполнить 15 бит (половина от TCNT1) — это много (ну с точки зрения нахождения в прерывании), а значит считаем, что обработчик прерывания, работающий дольше чем 32768 тиков таймера — написан неверно и это явно баг.

> И ещё события могли произойти в один такт

ну так ради этого и нужны все эти пляски и подпрыгивания с if ((TIFR & 1<<TOV1) && !(icr1 & 0x8000)),
только для устранения гонки этих двух событий.
  • avatar
  • rouming
  • 12 января 2013, 19:16
0
я не понял про «t1_ovf должен быть». ovf и icr1 никак не связаны между собой, это два асинхронных события.

ovf может быть выставлен асинхронно (если таймер асинхронный), не важно где мы сейчас находимся.
а вот icr1 либо уже «завернут» (было переполнение), тогда ovf обязательно уже выставлен,
либо icr1 не переполнялся еще, тогда нас и ovf не интересует, отловим в следующий раз.
  • avatar
  • rouming
  • 12 января 2013, 16:20
0
ах да, прощу прощения, это я неправ.
  • avatar
  • rouming
  • 12 января 2013, 12:58
0
хм. в комментариях подобного рода меня всегда ставит в тупик безапелляционность автора.
подсказка: вы неправы.
  • avatar
  • rouming
  • 12 января 2013, 12:35
0
1) смотрим в datasheet по atmega640
17 $0020 TIMER1 CAPT Timer/Counter1 Capture Event
21 $0028 TIMER1 OVF Timer/Counter1 Overflow

у capt приоритет выше.

2) что значит жирнее? где критерии? так как в любом из подходов есть потолок частоты (выше частоты самого кварца все равно не прыгнешь), и никаких четких рамок изначально не задавлось, то считаю потерю тактов на «жирность» допустимой.

3, 4, 5) переполнение t1_ovf, «выдача нуля при обрыве» — это логика вашей конкретной задачи, которую можно добавить простой веткой кода if.

вы начинаете объяснение со слов «Но вот беда. Атмельцы не сделали возможность сбрасывать/запускать таймер по событию!», "… Ну и нафига такая аппаратная капча, которая даёт не прогнозируемую и довольно приличную СОФТОВУЮ ошибку".

я приготовился услышать (увидеть) попытку решить описываемую проблему, которой, как оказалось, просто нет.

так вот лично мне по-прежнему (и как я понял из комментариев многим другим) не понятно, в чем суть?
я простой стандартной тряпкой кода показал, что никакой софтовой ошибки нет, что сброс таймера не нужен и лишний огород городить в общем-то тоже не нужно. а вы продолжаете настаивать на какой-то дополнительной логике вашей задачи, известной только вам: «Меня не интересуют обороты ниже 5%. Более того, по логике работы системы мне даже полезно, что ниже 5% выдаётся 0. И мне важно, чтоб 0 выдавался сразу, а не спустя Х переполнений.».

ну так и добавьте эту логику в «Тупой спобоб №1», будет ровно то же самое. тогда собственно зачем «Путь джедая»?
  • avatar
  • rouming
  • 11 января 2013, 01:21
0
Честно долго пытался понять собственно с чем идет борьба и какую проблему пытается решить автор. Так и не понял.
Объясните, чем плох стандартный подход? Никакого «секаса» с переполнением нет, бит OVF мониторим, код простой и очевидный:
uint16_t t1_ovf;
uint16_t prev_icr1;

ISR(TIMER1_OVF_vect)
{
  t1_ovf++;
}

ISR(TIMER1_CAPT_vect)
{
  uint32_t delta;
  uint16_t icr1 = ICR1;

  /* should we handle pended overflow right now? */
  if ((TIFR & 1<<TOV1) && !(icr1 & 0x8000)) {
    TIFR |= 1<<TOV1;
    t1_ovf++;
  }

  delta = ((1ul<<16) * t1_ovf) + icr1 - prev_icr1;

  t1_ovf = 0;
  prev_icr1 = icr1;

  /* do something with delta
     ....
   */
}
  • avatar
  • rouming
  • 08 января 2013, 23:51
0
а там рядом исходников не лежит? так как в исходниках самого gdb я не нашел упоминаний архитектуры stm8, а если разработчики st visual develop что-то пилили и не поделились исходниками, то они нарушили GPL.
возможно, что они просто используют gdb как клиент для своего jtag.
  • avatar
  • rouming
  • 08 января 2013, 09:54
0
я не понял, как это связано с отладочной информацией. вы _явно_ скомпилировались и слинковались с библиотекой, которая переопределила вызовы операций с памятью. точно так же вы можете использовать какие-то другие техники отладки памяти. из всего этого не следует, что при генерации и включении отладочной информации внезапно код станет медленнее и больше. это совсем разные вещи.
  • avatar
  • rouming
  • 12 декабря 2012, 16:24
0
хорошо. а «дебажный» RETI откуда появится в самом коде? и как отличить «дебажный» RETI от RETI самой программы?
  • avatar
  • rouming
  • 12 декабря 2012, 12:03
0
я бы перестал пользоваться компилятором, который без моего ведома пытается контроллировать доступ к памяти и что-то там расставляет. это такой overhead, что такую технику стоит применять в случае ловли какого-то конкретного бага (например, использовать valgrind). но еще раз. никакого отношения к дебажной информации это не имеет. это мета-информация (команды дебаггеру) которая может быть, а может и не быть.
  • avatar
  • rouming
  • 12 декабря 2012, 12:00
0
1. отладочная информация никак не влияет на объем _кода_. отладочная информация помогаяет дебаггеру раскрутить стек, понять по каким адресам / регистрам лежат локальные переменные и проч и проч. отладочную информацию можно держать отдельно от основной программы и загружать _только_ во время отладки.
2. на объем кода влияют опции компилятора, например опции оптимизации. с отладкой это вообще никак не связано.
3. очевидно, что из пункта 1 и 2 следует, что программа с отладочной информацией работает ровно точно так же, как и без.
4. простите, про RETI я вообще ничего не понял.
  • avatar
  • rouming
  • 12 декабря 2012, 11:33
0
ах, издержки перевода. в следующий раз буду приводить текст оригинала и сразу ссылку:
www.cplusplus.com/reference/memory/auto_ptr/
This class template provides a limited garbage collection facility for pointers, by allowing pointers to have the elements they point to automatically destroyed when the auto_ptr object is itself destroyed.
  • avatar
  • rouming
  • 26 ноября 2012, 18:51