Направление вывода на выход должно быть настроено. Если вы про это.oleg_4rk писал(а):Теперь вопрос, разве доступ к DDR* на чтение что-то меняет?
attiny13 таймер то работает, то нет
Re: attiny13 таймер то работает, то нет
- Реклама
Re: attiny13 таймер то работает, то нет
[uquote="shonty",url="/forum/viewtopic.php?p=4642322#p4642322"]
Это да. Но я не про это. Я про то, что, судя по всему, вот эта строка:
как раз и ломает всё. Где, pins[pin].type_reg = &DDRB.
Направление вывода на выход должно быть настроено. Если вы про это.[/uquote]oleg_4rk писал(а):Теперь вопрос, разве доступ к DDR* на чтение что-то меняет?
Это да. Но я не про это. Я про то, что, судя по всему, вот эта строка:
Код: Выделить всё
if (!(*pins[pin].type_reg & pins[pin].mask))
Ардуинщик. Не шарю в электронике.
Re: attiny13 таймер то работает, то нет
Oleg_4rk, у тебя в принципе не рабочий код, проблема как минимум в неатомарности записи в порт. Допустим в цикле происходит чтение из PORTB, модификация, затем вызывается прерывание в котором опять читается значение PORTB, тоглится бит и значение записывается обратно, после возврата из прерывания в PORTB пишется значение в котором бит затоглен еще не был. Следовательно нужно применять операции SBI/CBI, которые другие биты не затрагивают. Для тогла можно писать 1 в PINB. Работает не на всех AVR, но у tiny13 такое есть.
Re: attiny13 таймер то работает, то нет
[uquote="Adrift",url="/forum/viewtopic.php?p=4642328#p4642328"]Oleg_4rk, у тебя в принципе не рабочий код, проблема как минимум в неатомарности записи в порт. Допустим в цикле происходит чтение из PORTB, модификация, затем вызывается прерывание в котором опять читается значение PORTB, тоглится бит и значение записывается обратно, после возврата из прерывания в PORTB пишется значение в котором бит затоглен еще не был. Следовательно нужно применять операции SBI/CBI, которые другие биты не затрагивают. Для тогла можно писать 1 в PINB. Работает не на всех AVR, но у tiny13 такое есть.[/uquote]
Блин. Точно. Похоже дело в этом. Сейчас попробую исправить.
Блин. Точно. Похоже дело в этом. Сейчас попробую исправить.
Ардуинщик. Не шарю в электронике.
Re: attiny13 таймер то работает, то нет
Забористо вас вкрячило. Тринадцатая тинька через ардуину... Тинька - это строго асм, даже Си тут излишен, чрезмерен и бесполезен. А уж абдурина...
- Реклама
Re: attiny13 таймер то работает, то нет
[uquote="Adrift",url="/forum/viewtopic.php?p=4642328#p4642328"]Oleg_4rk, у тебя в принципе не рабочий код, проблема как минимум в неатомарности записи в порт. Допустим в цикле происходит чтение из PORTB, модификация, затем вызывается прерывание в котором опять читается значение PORTB, тоглится бит и значение записывается обратно, после возврата из прерывания в PORTB пишется значение в котором бит затоглен еще не был. Следовательно нужно применять операции SBI/CBI, которые другие биты не затрагивают. Для тогла можно писать 1 в PINB. Работает не на всех AVR, но у tiny13 такое есть.[/uquote]
Чё-т фигня какая-то выходит. sbi/cbi хотят константы. Т.е. мне в pin_write() их не получается применить. Ничего с переменными не нашёл, поэтому всё свелось с манипуляциями с SREG:
Но не работает чё-т. Добавил в код включение 3й ноги до while и внутри включение 1й ноги если SREG I-бит выставлен. ВОт так конец main выглядит:
Вырубаю питание и смотрю что при включении. И вот такая забавная фигня выходит - 
Первая строка это 0й пин, который по таймеру меняется; вторая - меняется при SREG; третья - до while.
Чё-т фигня какая-то выходит. sbi/cbi хотят константы. Т.е. мне в pin_write() их не получается применить. Ничего с переменными не нашёл, поэтому всё свелось с манипуляциями с SREG:
Код: Выделить всё
void
pin_write(uint8_t pin, uint8_t val)
{
uint8_t sreg_prev;
if (!(*pins[pin].type_reg & pins[pin].mask))
return;
sreg_prev = SREG;
cli();
if (val)
*pins[pin].out_reg |= pins[pin].mask;
else
*pins[pin].out_reg &= ~pins[pin].mask;
SREG = sreg_prev;
}
Код: Выделить всё
// ~100us
OCR0A = 15;
sei();
PORTB |= _BV(3);
while (1) {
if (bit_is_set(SREG, 7))
PORTB |= _BV(1);
else
PORTB &= ~(_BV(1));
if (pwm_width > pwm_width_on)
pin_write(PIN_D2, 1);
else if (pwm_width < pwm_width_off)
pin_write(PIN_D2, 0);
}
Первая строка это 0й пин, который по таймеру меняется; вторая - меняется при SREG; третья - до while.
- Вложения
-
- screenshot.png
- (4.98 КБ) 327 скачиваний
Ардуинщик. Не шарю в электронике.
Re: attiny13 таймер то работает, то нет
[uquote="oleg_4rk",url="/forum/viewtopic.php?p=4642392#p4642392"]ВОт так конец main выглядит:
[/uquote]
Так ничего не поменялось, теперь в pin_write() есть отключение прерываний, но добавились всякие PORTB |= _BV(1), где никакой защиты нет )
Код: Выделить всё
// ~100us
OCR0A = 15;
sei();
PORTB |= _BV(3);
while (1) {
if (bit_is_set(SREG, 7))
PORTB |= _BV(1);
else
PORTB &= ~(_BV(1));
if (pwm_width > pwm_width_on)
pin_write(PIN_D2, 1);
else if (pwm_width < pwm_width_off)
pin_write(PIN_D2, 0);
}
Так ничего не поменялось, теперь в pin_write() есть отключение прерываний, но добавились всякие PORTB |= _BV(1), где никакой защиты нет )
Re: attiny13 таймер то работает, то нет
Да блин
. Точно... Чё-т торможу под вечер уже. Ща.
Добавлено after 6 minutes 7 seconds:
Не помогло
. ВОт такой код сейчас:
Картина та же.
Запутался я уже. Оно и до этого не работало в общем, т.к. я ж эти дополнительные выводы 0/1 на ноги начал добавлять именно из-за того, что манипуляции с SREG не сработали. Или где-то ещё проблема.
Добавлено after 6 minutes 7 seconds:
Не помогло
Код: Выделить всё
// ~100us
OCR0A = 15;
sei();
asm("sbi %[io], %[bit]" :: [io] "I" (_SFR_IO_ADDR(PORTB)), [bit] "I" (3));
while (1) {
if (bit_is_set(SREG, 7))
asm("sbi %[io], %[bit]" :: [io] "I" (_SFR_IO_ADDR(PORTB)), [bit] "I" (1));
else
asm("cbi %[io], %[bit]" :: [io] "I" (_SFR_IO_ADDR(PORTB)), [bit] "I" (1));
if (pwm_width > pwm_width_on)
pin_write(PIN_D2, 1);
else if (pwm_width < pwm_width_off)
pin_write(PIN_D2, 0);
}
Запутался я уже. Оно и до этого не работало в общем, т.к. я ж эти дополнительные выводы 0/1 на ноги начал добавлять именно из-за того, что манипуляции с SREG не сработали. Или где-то ещё проблема.
Ардуинщик. Не шарю в электронике.
Re: attiny13 таймер то работает, то нет
Я не могу проверить, потому что AVR давно не занимаюсь. Если не работает, нужно упрощать... С пустым циклом все нормально? А если в цикле будут только SBI/CBI c задержками между ними?
Re: attiny13 таймер то работает, то нет
Кстати, PORTB |= компилятором и так переводится в sbi.
Вот здесь об этом написано - https://www.nongnu.org/avr-libc/user-ma ... __sfr.html
Добавлено after 7 minutes 14 seconds:
[uquote="Adrift",url="/forum/viewtopic.php?p=4642411#p4642411"]Я не могу проверить, потому что AVR давно не занимаюсь. Если не работает, нужно упрощать... С пустым циклом все нормально?[/uquote]
Так да.

Код: Выделить всё
97:test.c **** if (bit_is_set(SREG, 7))
181 .loc 1 97 3 view .LVU37
182 .loc 1 97 6 is_stmt 0 view .LVU38
183 0044 0FB6 in __tmp_reg__,__SREG__
184 0046 07FE sbrs __tmp_reg__,7
185 0048 00C0 rjmp .L4
98:test.c **** PORTB |= _BV(1);
186 .loc 1 98 4 is_stmt 1 view .LVU39
187 .loc 1 98 10 is_stmt 0 view .LVU40
188 004a C19A sbi 0x18,1
189 .L5:
99:test.c **** else
100:test.c **** PORTB &= ~(_BV(1));
101:test.c ****
...
214 .L4:
100:test.c ****
215 .loc 1 100 4 view .LVU50
100:test.c ****
216 .loc 1 100 10 is_stmt 0 view .LVU51
217 006e C198 cbi 0x18,1
218 0070 00C0 rjmp .L5
Добавлено after 7 minutes 14 seconds:
[uquote="Adrift",url="/forum/viewtopic.php?p=4642411#p4642411"]Я не могу проверить, потому что AVR давно не занимаюсь. Если не работает, нужно упрощать... С пустым циклом все нормально?[/uquote]
Так да.
Так тоже. Код:А если в цикле будут только SBI/CBI c задержками между ними?
Код: Выделить всё
while (1) {
PORTB |= _BV(1);
_delay_us(200);
PORTB &= ~(_BV(1));
}
- Вложения
-
- screenshot.png
- (9.66 КБ) 284 скачивания
Ардуинщик. Не шарю в электронике.
Re: attiny13 таймер то работает, то нет
[uquote="oleg_4rk",url="/forum/viewtopic.php?p=4642413#p4642413"]Кстати, PORTB |= компилятором и так переводится в sbi.[/uquote]
Не обязательно. Кстати, возможно именно поэтому убирание проверки DDR из начала pin_write() влияет на результат. Лишний код может заставить компилятор оставить функцию таковой, то есть не инлайнить ее и в таком случае там будет универсальный код работающий с адресами памяти, а не SBI/CBI.
Добавлено after 1 minute 55 seconds:
[uquote="oleg_4rk",url="/forum/viewtopic.php?p=4642413#p4642413"]Так тоже. Код:[/uquote]
Так ничего не увидишь, большая пауза минимизирует вероятность того, что прерывание произойдет в момент когда регистр PORTB был прочитан, но еще не записан. Пауза должна быть в несколько NOP. И опять же тут компилятор SBI/CBI наверняка вставит, если он умеет это делать...
Не обязательно. Кстати, возможно именно поэтому убирание проверки DDR из начала pin_write() влияет на результат. Лишний код может заставить компилятор оставить функцию таковой, то есть не инлайнить ее и в таком случае там будет универсальный код работающий с адресами памяти, а не SBI/CBI.
Добавлено after 1 minute 55 seconds:
[uquote="oleg_4rk",url="/forum/viewtopic.php?p=4642413#p4642413"]Так тоже. Код:
Код: Выделить всё
while (1) {
PORTB |= _BV(1);
_delay_us(200);
PORTB &= ~(_BV(1));
}
Так ничего не увидишь, большая пауза минимизирует вероятность того, что прерывание произойдет в момент когда регистр PORTB был прочитан, но еще не записан. Пауза должна быть в несколько NOP. И опять же тут компилятор SBI/CBI наверняка вставит, если он умеет это делать...
Re: attiny13 таймер то работает, то нет
[uquote="Adrift",url="/forum/viewtopic.php?p=4642417#p4642417"][uquote="oleg_4rk",url="/forum/viewtopic.php?p=4642413#p4642413"]Кстати, PORTB |= компилятором и так переводится в sbi.[/uquote]
Не обязательно. Кстати, возможно именно поэтому убирание проверки DDR из начала pin_write() влияет на результат. Лишний код может заставить компилятор оставить функцию таковой, то есть не инлайнить ее и в таком случае там будет универсальный код работающий с адресами памяти, а не SBI/CBI.[/uquote]
Ну хз. Так в доке написано. Давай верну как было с asm-вставками.
.

Код:
Добавлено after 9 minutes 30 seconds:
[uquote="Adrift",url="/forum/viewtopic.php?p=4642328#p4642328"]Следовательно нужно применять операции SBI/CBI, которые другие биты не затрагивают. Для тогла можно писать 1 в PINB. Работает не на всех AVR, но у tiny13 такое есть.[/uquote]
Сейчас глянул, кстати, насчёт этого. Удобная штука. В attiny25/45/85, atmega48/88/168/328/16u4/32u4 оно есть.
Не обязательно. Кстати, возможно именно поэтому убирание проверки DDR из начала pin_write() влияет на результат. Лишний код может заставить компилятор оставить функцию таковой, то есть не инлайнить ее и в таком случае там будет универсальный код работающий с адресами памяти, а не SBI/CBI.[/uquote]
Ну хз. Так в доке написано. Давай верну как было с asm-вставками.
Так тоже работает норм таймер. Но 1й пин теперь вначале часто дёргается, а потом режеТак ничего не увидишь, большая пауза минимизирует вероятность того, что прерывание произойдет в момент когда регистр PORTB был прочитан, но еще не записан. Пауза должна быть в несколько NOP.
Код:
Код: Выделить всё
while (1) {
asm("sbi %[io], %[bit]" :: [io] "I" (_SFR_IO_ADDR(PORTB)), [bit] "I" (1));
asm("nop");
asm("nop");
asm("nop");
asm("cbi %[io], %[bit]" :: [io] "I" (_SFR_IO_ADDR(PORTB)), [bit] "I" (1));
}
[uquote="Adrift",url="/forum/viewtopic.php?p=4642328#p4642328"]Следовательно нужно применять операции SBI/CBI, которые другие биты не затрагивают. Для тогла можно писать 1 в PINB. Работает не на всех AVR, но у tiny13 такое есть.[/uquote]
Сейчас глянул, кстати, насчёт этого. Удобная штука. В attiny25/45/85, atmega48/88/168/328/16u4/32u4 оно есть.
- Вложения
-
- screenshot.png
- (8.01 КБ) 262 скачивания
Ардуинщик. Не шарю в электронике.
Re: attiny13 таймер то работает, то нет
Запустил код в Compiler Explorer, для pin_write(), даже без проверки DDRB, генерит без SBI/CBI(-mmcu=attiny13 -Og):
Даже если инлайнить SBI не появляются. А для простых PORTB |= 4 они уже есть.
Похоже простейший цикл в котором будет RMW над портом, как и в pin_write(), должен выглядеть так:
Из-за volatile компилятор не знает во время компиляции, что имеет дело с PORTB и на SBI/CBI ничего не заменяет.
Код: Выделить всё
ldd r25,Z+6
or r24,r25
st X,r24Похоже простейший цикл в котором будет RMW над портом, как и в pin_write(), должен выглядеть так:
Код: Выделить всё
volatile uint16_t portb = 0x38;
while(1)
{
*(volatile uint8_t*)portb |= 1;
*(volatile uint8_t*)portb &= ~1;
}Re: attiny13 таймер то работает, то нет
Согласно доке PORTB |= 4; всегда будет заменяться на sbi и такое же с cbi. А дальше, насколько у оптимизатора получается вычислить константы на этапе компиляции. Но это сейчас не важно. Теперь-то код такой:
И по идее перезапись не должна пересекаться с прерыванием. Но чё-т не то.
Код: Выделить всё
void
pin_write(uint8_t pin, uint8_t val)
{
uint8_t sreg_prev;
if (!(*pins[pin].type_reg & pins[pin].mask))
return;
sreg_prev = SREG;
cli();
if (val)
*pins[pin].out_reg |= pins[pin].mask;
else
*pins[pin].out_reg &= ~pins[pin].mask;
SREG = sreg_prev;
}
Ардуинщик. Не шарю в электронике.
Re: attiny13 таймер то работает, то нет
Не по теме
если asm это ногодрыг, то си и выше это чего_дрыг?
Спойлер
Когда читаю подобные изыскания, невольно задумываюсь..если asm это ногодрыг, то си и выше это чего_дрыг?
Re: attiny13 таймер то работает, то нет
[uquote="oleg_4rk",url="/forum/viewtopic.php?p=4642656#p4642656"]И по идее перезапись не должна пересекаться с прерыванием. Но чё-т не то.[/uquote]
Хедер для cli() точно подключен? Можно написать cli555() и будет лишь предупреждение аж до gcc14, где это уже ошибка. Вместо cli555() компилятор вставляет непонятную хрень "rcall cli555" )
Попробуй так:
Хедер для cli() точно подключен? Можно написать cli555() и будет лишь предупреждение аж до gcc14, где это уже ошибка. Вместо cli555() компилятор вставляет непонятную хрень "rcall cli555" )
Попробуй так:
Код: Выделить всё
volatile uint16_t portb = 0x38;
while(1)
{
uint8_t sreg = SREG;
asm("cli");
*(volatile uint8_t*)portb |= 2;
*(volatile uint8_t*)portb &= ~2;
SREG = sreg;
}Re: attiny13 таймер то работает, то нет
[uquote="Adrift",url="/forum/viewtopic.php?p=4642667#p4642667"]Хедер для cli() точно подключен? Можно написать cli555() и будет лишь предупреждение аж до gcc14, где это уже ошибка. Вместо cli555() компилятор вставляет непонятную хрень "rcall cli555" )[/uquote]
Точно
:
Не знаю насчёт cli555(), а с cli() всё конкректно в avr/interrupt.h прописано:
Точно
Код: Выделить всё
13:pin.c **** cli();
58 .loc 1 13 2 is_stmt 1 view .LVU12
59 /* #APP */
60 ; 13 "pin.c" 1
61 0026 F894 cli
62 ; 0 "" 2
14:pin.c **** if (val)
Код: Выделить всё
# define cli() __asm__ __volatile__ ("cli" ::: "memory")
Ардуинщик. Не шарю в электронике.
Re: attiny13 таймер то работает, то нет
Oleg_4rk, что с моим примером, тоже не работает? Собственно из-за озвученной мной проблемы сплошные нули все равно не должно давать на пинах, значит есть что-то еще. Может и с линковкой что-то, например, в pin_write() вызывается __mulhi3, это длинное умножение и если оно вдруг от другой архитектуры, то там внутри может быть инструкция MUL, которой нет у tiny13 и мк, как вариант, просто виснет и никакой код не выполняется вообще, тогда таки будут одни нули ) А на mega328 все относительно нормально, хотя там, конечно, из-за неатомарности глючит тоже, просто этого можно и не заметить.
Re: attiny13 таймер то работает, то нет
[uquote="Adrift",url="/forum/viewtopic.php?p=4642681#p4642681"]Oleg_4rk, что с моим примером, тоже не работает?[/uquote]
Вот этот код:
Работает. И даёт такую картину:


Вроде работает, но какие-то провалы присутствуют. Но хотя бы работает таймер
.
Вот этот код:
Код: Выделить всё
volatile uint16_t portb = 0x38;
while(1)
{
uint8_t sreg = SREG;
asm("cli");
*(volatile uint8_t*)portb |= 2;
*(volatile uint8_t*)portb &= ~2;
SREG = sreg;
}
Похоже на то. Хз. Если всё вставляю в программу и собираю без своей библиотеки, то получается так:Собственно из-за озвученной мной проблемы сплошные нули все равно не должно давать на пинах, значит есть что-то еще. Может и с линковкой что-то,
Вроде работает, но какие-то провалы присутствуют. Но хотя бы работает таймер
- Вложения
-
- screenshot.png
- (5.38 КБ) 117 скачиваний
-
- screenshot.png
- (11.24 КБ) 111 скачиваний
Ардуинщик. Не шарю в электронике.
Re: attiny13 таймер то работает, то нет
[uquote="oleg_4rk",url="/forum/viewtopic.php?p=4642699#p4642699"]Вроде работает, но какие-то провалы присутствуют. Но хотя бы работает таймер
.[/uquote]
Провалы присутствуют потому что прерывания отключаются и хотя флаг таймер всегда выставляет через одинаковое время в обработчик периодически будет попадать с опозданием, не раньше момента включения прерываний.
Провалы присутствуют потому что прерывания отключаются и хотя флаг таймер всегда выставляет через одинаковое время в обработчик периодически будет попадать с опозданием, не раньше момента включения прерываний.


