Обсуждаем контроллеры компании Atmel.
Ответить

Re: arduino и конденсатор

Вт окт 22, 2019 14:02:51

Точно. Про else забыл. Но подобный макрос изврат в любом случае. Лучше уж inline:

Код:
static inline void lighton(void)
{
    PORTB |= (1 << PB3);
    DDRB |= (1 << DDRB3);
}

Re: arduino и конденсатор

Вт окт 22, 2019 14:13:18

Макрос - не изврат, а вполне себе стандартная практика. А inline - не панацея. Это всего-лишь хинт компилятору. Не факт, что будет инлайн. Ладно еще с avr-gcc, на другой платформе, например PIC с XC8 там вообще всё плохо с этим.
Плюс макрос можно закинуть в .h и вызывать из разных .c.

Re: arduino и конденсатор

Вт окт 22, 2019 14:32:49

Макрос - не изврат, а вполне себе стандартная практика.


Макрос норм, но подобный макрос изврат ещё тот.

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


Если не использовать опции оптимизации, то точно не будет. А если делать -Os - что для avr-gcc strongly recommended - то всё норм.
Или использовать __attribute__((always_inline)).

Ладно еще с avr-gcc, на другой платформе, например PIC с XC8 там вообще всё плохо с этим.


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

Плюс макрос можно закинуть в .h и вызывать из разных .c.


Так и static inline тоже - никаких проблем. Так и используют. Вот, хотя бы, list.h - https://github.com/torvalds/linux/blob/ ... nux/list.h .

Добавлено after 2 minutes:
Макрос - не изврат, а вполне себе стандартная практика.


И, кстати, одно другому не противоречит ;-) :-). Это не перестаёт быть извратом от того, что его часто используют.

Re: arduino и конденсатор

Вт окт 22, 2019 15:32:44

__attribute__((always_inline)).

Есть только в gcc. Страдает переносимость кода. Хотя если она не нужна, можно и inline конечно. Если точно уверены в своём компиляторе. Ядру Linux-то пофиг на накладные расходы, если они возникнут. А для МК это критично.
Но для записи битика в пару регистров честно не вижу смысла городить функцию. Диод ставить куда больший изврат )))

PS: Там еще могут быть нюансы при вызове из прерывания.

Добавлено after 14 minutes 20 seconds:
А если делать -Os - что для avr-gcc strongly recommended - то всё норм.

А вот как раз таки наоборот. При -Os делается rcall:
Код:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/cpufunc.h>
#include <stdbool.h>

static inline void lighton(void) {
    PORTB |= (1 << PB3);
    DDRB |= (1 << PB3);
}

static inline void lightoff(void) {
    PORTB &= ~(1 << PB3);
    DDRB &= ~(1 << PB3);
}

ISR(INT0_vect) {
    lighton();
}

int main() {
  lightoff();
  _NOP();
  lighton();
  while(true);
}


avr-gcc -std=gnu11 -Os -g -mmcu=atmega8 inline.c -o inline && avr-objdump -d inline > inline.lss
inline.lss:
Код:
...
00000038 <lighton>:
  38:   c3 9a           sbi     0x18, 3 ; 24
  3a:   bb 9a           sbi     0x17, 3 ; 23
  3c:   08 95           ret

0000003e <__vector_1>:
  3e:   1f 92           push    r1
  40:   0f 92           push    r0
  42:   0f b6           in      r0, 0x3f        ; 63
  44:   0f 92           push    r0
  46:   11 24           eor     r1, r1
  48:   2f 93           push    r18
  4a:   3f 93           push    r19
  4c:   4f 93           push    r20
  4e:   5f 93           push    r21
  50:   6f 93           push    r22
  52:   7f 93           push    r23
  54:   8f 93           push    r24
  56:   9f 93           push    r25
  58:   af 93           push    r26
  5a:   bf 93           push    r27
  5c:   ef 93           push    r30
  5e:   ff 93           push    r31
  60:   eb df           rcall   .-42            ; 0x38 <lighton>
  62:   ff 91           pop     r31
  64:   ef 91           pop     r30
  66:   bf 91           pop     r27
  68:   af 91           pop     r26
  6a:   9f 91           pop     r25
  6c:   8f 91           pop     r24
  6e:   7f 91           pop     r23
  70:   6f 91           pop     r22
  72:   5f 91           pop     r21
  74:   4f 91           pop     r20
  76:   3f 91           pop     r19
  78:   2f 91           pop     r18
  7a:   0f 90           pop     r0
  7c:   0f be           out     0x3f, r0        ; 63
  7e:   0f 90           pop     r0
  80:   1f 90           pop     r1
  82:   18 95           reti

00000084 <main>:
  84:   c3 98           cbi     0x18, 3 ; 24
  86:   bb 98           cbi     0x17, 3 ; 23
  88:   00 00           nop
  8a:   d6 df           rcall   .-84            ; 0x38 <lighton>
  8c:   ff cf           rjmp    .-2             ; 0x8c <main+0x8>
...


Забавно, но такой простой пример выдает с -Os код больше, чем с -Og/-O1 из-за всех этих телодвижений со стеком. -O1 действительно делает инлайн:
Код:
00000044 <__vector_1>:
  44:   1f 92           push    r1
  46:   0f 92           push    r0
  48:   0f b6           in      r0, 0x3f        ; 63
  4a:   0f 92           push    r0
  4c:   11 24           eor     r1, r1
  4e:   c3 9a           sbi     0x18, 3 ; 24
  50:   bb 9a           sbi     0x17, 3 ; 23
  52:   0f 90           pop     r0
  54:   0f be           out     0x3f, r0        ; 63
  56:   0f 90           pop     r0
  58:   1f 90           pop     r1
  5a:   18 95           reti

Re: arduino и конденсатор

Вт окт 22, 2019 16:43:35

__attribute__((always_inline)).

Есть только в gcc. Страдает переносимость кода. Хотя если она не нужна, можно и inline конечно. Если точно уверены в своём компиляторе. Ядру Linux-то пофиг на накладные расходы, если они возникнут. А для МК это критично.


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

Но для записи битика в пару регистров честно не вижу смысла городить функцию.


Если это делается двумя выражениями, как выше, плюс do/while(0), то уж лучше функция. Хотя, это субъективно. Каждый сам определяет, когда нужно остановиться :-).

Диод ставить куда больший изврат )))


Для обучения норм :-).

А если делать -Os - что для avr-gcc strongly recommended - то всё норм.

А вот как раз таки наоборот. При -Os делается rcall:


rcall делается с ISR. Если эту конструкцию убрать, то с inline всё норм.

Re: arduino и конденсатор

Вт окт 22, 2019 18:09:06

do { ... } while(0) макро из моего примера подставляется в 2 инструкции asm sbi/cbi. Всегда и везде. Даже с отключенной оптимизацией сами do {} while(0) ни во что не собираются и не дают накладных расходов. Это просто что-то противоположное синтаксическому сахару.
А rcall делается, в случае с функций, что из main(), что из ISR. Вы соберите мой пример сами. С -Os он у меня вроде 146 байт занимал. С -O1 уже 96 байт. Вот и оптимизация по размеру ) А всё из-за тонны вызовов push/pop для сохранения регистров. А вовсе не из-за rcall конечно же.

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

Мне как-то несколько байт не хватало ) Пришлось пожертвовать читаемостью кода и все функции запихнуть одной простыней. Зато влезло в текущий МК, который был под рукой и который не надо было покупать. Это когда речь о личных поделках.
А в серийных ус-ах порой разница в цене за счет серийности может встать в существенную сумму. Всякое бывает.

Хотя, это субъективно. Каждый сам определяет, когда нужно остановиться :-).

Именно. На самом деле не критично в большинстве случаев. Мне просто максос с do {} while(0) никак читаемость кода не ухудшает, я к ним привык, они много кем используются. Но случаи бывают разные. )

Re: arduino и конденсатор

Ср окт 23, 2019 12:12:35

А rcall делается, в случае с функций, что из main(), что из ISR.


Вы меня не так поняли. Если убрать это из кода:

Код:
ISR(INT0_vect) {
    lighton();
}


То вызовов функции не будет в main. Она будет инлайниться. Если эту часть кода оставить, то везде будет вызов lighton и только lightoff будет инлайниться. Видимо, действительно, прерывания вносят что-то своё тут.

Мне как-то несколько байт не хватало ) Пришлось пожертвовать читаемостью кода и все функции запихнуть одной простыней. Зато влезло в текущий МК, который был под рукой и который не надо было покупать. Это когда речь о личных поделках.


Прикольно :-).

А в серийных ус-ах порой разница в цене за счет серийности может встать в существенную сумму. Всякое бывает.


Ну, смотря какое серийное производство. Если это промышленное оборудование какое-то, то цена контроллера потеряется среди прочего оборудования, которое он будет мониторить/управлять. И в этом случае для стабильности и надёжности лучше выбрать что-то помощнее и с большей памятью, что бы не извращаться с исходным кодом, ибо больше хаков - больше потенциальных ошибок.

Re: arduino и конденсатор

Ср окт 23, 2019 14:21:44

То вызовов функции не будет в main. Она будет инлайниться.

Не хочет )

inline.c:
Код:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/cpufunc.h>
#include <stdbool.h>

static inline void lighton(void) {
    PORTB |= (1 << PB3);
    DDRB |= (1 << PB3);
}

static inline void lightoff(void) {
    PORTB &= ~(1 << PB3);
    DDRB &= ~(1 << PB3);
}

void fn() {
  lighton();
}

int main() {
  fn();
  _NOP();
  lightoff();
  _NOP();
  lighton();
  while(true);
}


Выхлоп -Os:
Код:
...
00000038 <lighton>:
  38:   c3 9a           sbi     0x18, 3 ; 24
  3a:   bb 9a           sbi     0x17, 3 ; 23
  3c:   08 95           ret

0000003e <fn>:
  3e:   fc cf           rjmp    .-8             ; 0x38 <lighton>

00000040 <main>:
  40:   fb df           rcall   .-10            ; 0x38 <lighton>
  42:   00 00           nop
  44:   c3 98           cbi     0x18, 3 ; 24
  46:   bb 98           cbi     0x17, 3 ; 23
  48:   00 00           nop
  4a:   f6 df           rcall   .-20            ; 0x38 <lighton>
  4c:   ff cf           rjmp    .-2             ; 0x4c <main+0xc>
...


А с макросом, что из ISR, что из обычных функций rcall/rjmp не будет )
Последний раз редактировалось NStorm Ср окт 23, 2019 14:27:40, всего редактировалось 1 раз.

Re: arduino и конденсатор

Ср окт 23, 2019 14:24:38

Ужжшшш выбирайте Си или ассемблер.
8)
Надо хоть под каким-нибудь для начала более-менее разобраться.
:wink:

Re: arduino и конденсатор

Ср окт 23, 2019 15:34:21

То вызовов функции не будет в main. Она будет инлайниться.

Не хочет )


Да. Точно. Не подумал проверить вызов внутри функции. В этом случае только __attribute__((always_inline)) помогает.

Re: arduino и конденсатор

Ср окт 23, 2019 18:05:49

NStorm, а вы уверены что static inline void у вас действительно inline ,
у меня к примеру что static inline void что static void - одно и то же.
А вот если так указать static inline __attribute__((__always_inline__)) void , то уже совсем другое.

И наиболее оптимальная схема
СпойлерИзображение
Если R1 сделать равным R2 300 кОм будет и плавное включение.

Re: arduino и конденсатор

Ср окт 23, 2019 19:35:27

Dimon456, я не знаю о чем вы. Я написал, что я уверен, что static inline в определенных случаях становитсяы по факту вовсе не inline, а обычной функцией. И это нормальное поведение в соответствии со стандартом. А __attribute__((__always_inline__)) это нестандартное расширение gcc, о чем я тоже писал уже.

Re: arduino и конденсатор

Чт окт 24, 2019 06:08:06

NStorm, приведите пример.

Re: arduino и конденсатор

Чт окт 24, 2019 07:11:58

Dimon456, я несколько раз проверял: gcc при нормальной оптимизации (-O2) static inline обычно раскрывает и подставляет куда нужно. А вот при -Os он оформляет ее как функцию, тратя уйму ресурсов на работу со стеком… Выше уже было про это: в некоторых случаях static inline при -Os приводят к увеличению объема кода…
Вот с sdcc похуже: этот гад творит что хочет!

Re: arduino и конденсатор

Чт окт 24, 2019 08:20:09

Dimon456, а выше что? Прочитайте тему целиком пожалуйста, все примеры приведены, всё раскрыто и расписано.

Добавлено after 4 minutes 27 seconds:
Eddy_Em, так и есть, я о том же. Соб-но выше даже показал выхлоп ассемблерный с разными опциями оптимизации на примерах. Но какие-то еще примеры просят )

Re: arduino и конденсатор

Чт окт 24, 2019 14:19:56

Давайте я тогда свой пример приведу
СпойлерСледующий код-1
Код:
 static inline void lighton(void) {
    PORTB |= (1 << PB3);
    DDRB |= (1 << PB3);
}

static inline void lightoff(void) {
    PORTB &= ~(1 << PB3);
    DDRB &= ~(1 << PB3);
}

void fn(void) {
  lighton();
}

ISR(INT0_vect) {
    lighton();
}

int main(void) {
  fn();
  _NOP();
  lightoff();
  _NOP();
  lighton();
  while(true);
}
компилируется в 232 байта. -Os
На выходе имеем
Код:
00000080 <lighton>:
  80:   2b 9a          sbi   0x05, 3   ; 5
  82:   23 9a          sbi   0x04, 3   ; 4
  84:   08 95          ret

00000086 <fn>:
  86:   0c 94 40 00    jmp   0x80   ; 0x80 <lighton>

0000008a <__vector_1>:
  8a:   1f 92          push   r1
  8c:   0f 92          push   r0
  8e:   0f b6          in   r0, 0x3f   ; 63
  90:   0f 92          push   r0
  92:   11 24          eor   r1, r1
  94:   2f 93          push   r18
  96:   3f 93          push   r19
  98:   4f 93          push   r20
  9a:   5f 93          push   r21
  9c:   6f 93          push   r22
  9e:   7f 93          push   r23
  a0:   8f 93          push   r24
  a2:   9f 93          push   r25
  a4:   af 93          push   r26
  a6:   bf 93          push   r27
  a8:   ef 93          push   r30
  aa:   ff 93          push   r31

  ac:   0e 94 40 00    call   0x80   ; 0x80 <lighton>

  b0:   ff 91          pop   r31
  b2:   ef 91          pop   r30
  b4:   bf 91          pop   r27
  b6:   af 91          pop   r26
  b8:   9f 91          pop   r25
  ba:   8f 91          pop   r24
  bc:   7f 91          pop   r23
  be:   6f 91          pop   r22
  c0:   5f 91          pop   r21
  c2:   4f 91          pop   r20
  c4:   3f 91          pop   r19
  c6:   2f 91          pop   r18
  c8:   0f 90          pop   r0
  ca:   0f be          out   0x3f, r0   ; 63
  cc:   0f 90          pop   r0
  ce:   1f 90          pop   r1
  d0:   18 95          reti

000000d2 <main>:
  d2:   0e 94 40 00    call   0x80   ; 0x80 <lighton>
  d6:   00 00          nop
  d8:   2b 98          cbi   0x05, 3   ; 5
  da:   23 98          cbi   0x04, 3   ; 4
  dc:   00 00          nop
  de:   0e 94 40 00    call   0x80   ; 0x80 <lighton>
  e2:   ff cf          rjmp   .-2         ; 0xe2 <main+0x10>


Теперь так, код-2
Код:
 static void lighton(void) {
    PORTB |= (1 << PB3);
    DDRB |= (1 << PB3);
}

 static void lightoff(void) {
    PORTB &= ~(1 << PB3);
    DDRB &= ~(1 << PB3);
}

void fn(void) {
  lighton();
}

ISR(INT0_vect) {
    lighton();
}

int main(void) {
  fn();
  _NOP();
  lightoff();
  _NOP();
  lighton();
  while(true);
}
По прежнему 232 байта. -Os
На выходе
Код:
00000080 <lighton>:
  80:   2b 9a          sbi   0x05, 3   ; 5
  82:   23 9a          sbi   0x04, 3   ; 4
  84:   08 95          ret

00000086 <fn>:
  86:   0c 94 40 00    jmp   0x80   ; 0x80 <lighton>

0000008a <__vector_1>:
  8a:   1f 92          push   r1
  8c:   0f 92          push   r0
  8e:   0f b6          in   r0, 0x3f   ; 63
  90:   0f 92          push   r0
  92:   11 24          eor   r1, r1
  94:   2f 93          push   r18
  96:   3f 93          push   r19
  98:   4f 93          push   r20
  9a:   5f 93          push   r21
  9c:   6f 93          push   r22
  9e:   7f 93          push   r23
  a0:   8f 93          push   r24
  a2:   9f 93          push   r25
  a4:   af 93          push   r26
  a6:   bf 93          push   r27
  a8:   ef 93          push   r30
  aa:   ff 93          push   r31

  ac:   0e 94 40 00    call   0x80   ; 0x80 <lighton>

  b0:   ff 91          pop   r31
  b2:   ef 91          pop   r30
  b4:   bf 91          pop   r27
  b6:   af 91          pop   r26
  b8:   9f 91          pop   r25
  ba:   8f 91          pop   r24
  bc:   7f 91          pop   r23
  be:   6f 91          pop   r22
  c0:   5f 91          pop   r21
  c2:   4f 91          pop   r20
  c4:   3f 91          pop   r19
  c6:   2f 91          pop   r18
  c8:   0f 90          pop   r0
  ca:   0f be          out   0x3f, r0   ; 63
  cc:   0f 90          pop   r0
  ce:   1f 90          pop   r1
  d0:   18 95          reti

000000d2 <main>:
  d2:   0e 94 40 00    call   0x80   ; 0x80 <lighton>
  d6:   00 00          nop
  d8:   2b 98          cbi   0x05, 3   ; 5
  da:   23 98          cbi   0x04, 3   ; 4
  dc:   00 00          nop
  de:   0e 94 40 00    call   0x80   ; 0x80 <lighton>
  e2:   ff cf          rjmp   .-2         ; 0xe2 <main+0x10>

Теперь такой код-3
Код:
#define INLINE static inline __attribute__((__always_inline__))


 INLINE void lighton(void) {
    PORTB |= (1 << PB3);
    DDRB |= (1 << PB3);
}

 INLINE void lightoff(void) {
    PORTB &= ~(1 << PB3);
    DDRB &= ~(1 << PB3);
}

void fn(void) {
  lighton();
}

ISR(INT0_vect) {
    lighton();
}

int main(void) {
  fn();
  _NOP();
  lightoff();
  _NOP();
  lighton();
  while(true);
}
компилируется уже в 162 байта. -Os
и на выходе
Код:
00000080 <fn>:
  80:   2b 9a          sbi   0x05, 3   ; 5
  82:   23 9a          sbi   0x04, 3   ; 4
  84:   08 95          ret

00000086 <__vector_1>:
  86:   2b 9a          sbi   0x05, 3   ; 5
  88:   23 9a          sbi   0x04, 3   ; 4
  8a:   18 95          reti

0000008c <main>:
  8c:   0e 94 40 00    call   0x80   ; 0x80 <fn>
  90:   00 00          nop
  92:   2b 98          cbi   0x05, 3   ; 5
  94:   23 98          cbi   0x04, 3   ; 4
  96:   00 00          nop
  98:   2b 9a          sbi   0x05, 3   ; 5
  9a:   23 9a          sbi   0x04, 3   ; 4
  9c:   ff cf          rjmp   .-2         ; 0x9c <main+0x10>
Не хотите в void fn(void) добавить INLINE void fn(void)?

Re: arduino и конденсатор

Чт окт 24, 2019 14:54:43

Dimon456, вы не так поняли :-). Насчёт того, что __attribute__((always_inline)) работает никто не сомневается. Разговор был про то, что inline не всегда работает. И в этом, в принципе, тоже никто не сомневается. А изначально разговор был о равнозначной по функциональности замене define функцией с inline. Вывод такой, что кому надо не только gcc, то лучше define.

Добавлено after 1 minute 58 seconds:
И наиболее оптимальная схема
Изображение


Я ж правильно понимаю, что R2 можно безболезненно убрать в случае, когда pin переключается с 1 на 0(без HiZ)? Т.е. его единственная задача убирать наводки с базы в случае, когда на пине HiZ, так?

Re: arduino и конденсатор

Чт окт 24, 2019 16:42:51

R2 служит для разрядки конденсатора С1 пока транзистор не закроется.
Два варианта схемы с HiZ.
1- R1=2кОм R2 300кОм, моментальное включение, плавное погасание.
2- R1=300кОм R2 300кОм, плавное включение, плавное погасание.

Один варианта схемы без HiZ.
R1=300кОм R2 убрать, плавное включение, плавное погасание (разряд конденсатора через пин порта).

Re: arduino и конденсатор

Чт окт 24, 2019 19:20:07

Один варианта схемы без HiZ.
R1=300кОм R2 убрать, плавное включение, плавное погасание (разряд конденсатора через пин порта).


Если конденсатор разряжается через пин, а не через транзистор, то никакого плавного погасания нет. Если же добавить слева R1 диод, то всё норм.

Хотя, нет. Наверное будет с 300 КОм. У меня нет таких больших, я с 10 КОм проверял.

Re: arduino и конденсатор

Вс окт 27, 2019 08:49:09

По "оптимальной схеме"
Изображение

Господа, откуда тут будет плавное зажигание-угасание?
Конденсатор через R1 заряжается до момента открывания транзистора, потом будет короткий период действительно плавного открывания транзистора, но потом напряжение на конденсаторе останется равным напряжению падения на открытом переходе база-эммитер.....
Т.е. условно, конденсатор заряжается до 0.55 вольта через резистор, потом начинает открываться транзистор и... всё.... при 0.65-0.7 вольта заряд ёмкости прекратится..... И из всей схемы плавность работает в диапазоне 100-200 мВ...
Либо ставить большую емкость надо, что бы плавносьт была заметна глазу....
"Помоему так" (ц) Иа

Как вариант - вижу перенос светодиода с резистором в эммитерную цепь... получаем каскад с ОК (эммитерный повторитель).
Тогда плавное зажигание светодиода будет начинаться от 1.5-2 вольт на базе (зависит от падения напряжения на переходе светодиода) и до полного питания (в случае 5 вольт питания - диапазон 2..5 вольт).
Либо менять биполярник на какой то полевик низковольтный.

Dimon456, Т.е. с точки зрения оптимизации gcc static в случае inline-функций - зло?

И кто-нибудь, подскажите сакральный смысл static в определении функций в чистом Си (не ++)?
Ответить