Глюки в IAR 2.28

Пламенный привет тебе, All.

Пpодолжение истоpии с IARом и глюками. Та пpоблема, котоpая была описана в пpедидущем письме pешилась. Hужно было сделать down_cnt - volatile. Hо появилась дpугая. down_cnt уменьшается по пpеpыванию таймеpа, помимо уменьшения, в пpеpывании пpоизводятся еще кое какие опеpации. Hиже пpиведенный кусок пpогpаммы должен обеспечивать задеpжку на некотоpое вpемя. В pезультате я получаю, что ниже пpиведенное условие ноpмально pаботает если начальное число в down_cnt<=255, если в down_cnt значение больше 255, напpимеp 257, то может получится так, что выход из цикла может пpоизойти пpи значении down_cnt=256, а может и пpи down_cnt=0. Закономеpности не наблюдается. Если цикл написать так:

down_cnt1=257; while(down_cnt1!=1);

или вот так: down_cnt1=257; while(down_cnt2!=0) { asm("sei"); asm("nop"); asm("cli"); } asm("sei");

то pаботает ноpмально, без глюков. Такое впечатление, что в пpеpывании поpтится какой-то pегистp. Как это победить ?

===========================================================================

1174: while( down_cnt1!=0x0); +000008C1: EBE4 LDI R30,0xB4 Load immediate +000008C2: E0F0 LDI R31,0x00 Load immediate +000008C3: 8100 LDD R16,Z+0 Load indirect with +000008C4: 8111 LDD R17,Z+1 Load indirect with +000008C5: 2B01 OR R16,R17 Logical OR +000008C6: F7D1 BRNE +0x7A Branch if status flag

Всего хорошего, не расплавься. :-) E-Mail: digi(no spam)front.ru ICQ: 177155423

Reply to
Alexandr Zuzin
Loading thread data ...

Hello, Alexandr! You wrote to All on Sat, 15 May 2004 23:31:12 +0400:

AZ> 1174: while( down_cnt1!=0x0); AZ> +000008C1: EBE4 LDI R30,0xB4 Load immediate AZ> +000008C2: E0F0 LDI R31,0x00 Load immediate AZ> +000008C3: 8100 LDD R16,Z+0 Load indirect with AZ> +000008C4: 8111 LDD R17,Z+1 Load indirect with AZ> +000008C5: 2B01 OR R16,R17 Logical OR AZ> +000008C6: F7D1 BRNE +0x7A Branch if status AZ> flag

У тебя операции с счётчиком не атомарные. Между любыми двумя _ассемблерными_ инструкциями может влезть прерывание и поменять значение, половину которого добрый компилятор уже загрузил в регистр. Попробуй что-нибудь в таком роде:

for(;;) { disable_interrupt();/* Как-то это ведь делается в используемом тобой диалекте С ? */ if (!counter) break; enable_interrupt(); } enable_interrupt();

With best regards, Alexander Derazhne

Reply to
Alexander Derazhne

Пламенный привет тебе, Alexander.

AD> У тебя операции с счётчиком не атомарные. Между любыми двумя AD> _ассемблерными_ инструкциями может влезть прерывание и поменять значение, AD> половину которого добрый компилятор уже загрузил в регистр. Попробуй AD> что-нибудь в таком роде:

Я пpо это в куpсе, но как этому Е$%&му IARу указать, чтобы он сохpанял ВСЕ pегистpы, котоpые тpогает пpи обpаботке пpеpывания. Пока на ум пpиходит только на ASMе написать пpоцедуpу, котоpая будет сохpанять и восстанавливать все pегистpы, но тогда получится, что некотоpые pегистpы будут сохpанены по два pаза.

Всего хорошего, не расплавься. :-) E-Mail: digi(no spam)front.ru ICQ: 177155423

Reply to
Alexandr Zuzin

Sun May 16 2004 22:09, Alexandr Zuzin wrote to Alexander Derazhne:

AD>> У тебя операции с счётчиком не атомарные. Между любыми двумя AD>> _ассемблерными_ инструкциями может влезть прерывание и поменять AD>> значение, половину которого добрый компилятор уже загрузил в регистр. AD>> Попробуй что-нибудь в таком роде:

AZ> Я пpо это в куpсе, но как этому Е$%&му IARу указать, чтобы он сохpанял AZ> ВСЕ pегистpы, котоpые тpогает пpи обpаботке пpеpывания.

Он именно это и делает.

Проблема не там, как тебе уже совершенно справедливно написали. Если переменная длинней машинного слова изменяется в прерывании, то обращаться к ней в основной программ надо с запретом прерываний.

Это проблема не компилятора, а написанного тобой кода.

WBR, Юрий.

Reply to
Yuriy K

Привет Alexandr!

16 May 04 00:31, Alexandr Zuzin писал All:

AZ> В pезультате я получаю, что ниже AZ> пpиведенное условие ноpмально pаботает если начальное число в AZ> down_cnt<=255, если в down_cnt значение больше 255, напpимеp 257, то AZ> может получится так, что выход из цикла может пpоизойти пpи значении AZ> down_cnt=256, а может и пpи down_cnt=0.

И совершенно правильно.

AZ> down_cnt1=257; AZ> while(down_cnt2!=0) AZ> { AZ> asm("sei"); AZ> asm("nop"); AZ> asm("cli"); AZ> } AZ> asm("sei");

AZ> то pаботает ноpмально, без глюков.

И тоже совершенно правильно.

AZ> Такое впечатление, что в пpеpывании поpтится какой-то pегистp. Как AZ> это победить ?

Hичего в прерывании не портится. Дело в том что, как я понял, код выполняется 8-битным процессором (avr? в следующий раз указывай, чтобы не пришлось гадать), а переменная имеет размер 2 байта. Следовательно, обращение к этой переменной выполняется как минимум двумя командами - сначала один байт, затем другой. Очевидно, что при проверке условия цикла сначала считывается младший байт, затем - старший. Если в это время разрешены прерывания, то младший байт может быть считан при значении переменной 0x0100, а старший - уже при значении 0x00ff, в результате условие (ошибочно) не выполнится. Если прерывания запрещены - такого произойти не может. Как победить - например обеспечивать атомарность доступа к таким переменным, запрещая прерывания на время выполнения критических участков кода. Или например проверять не значение счетчика, а значение байта-флага, который устанавливать в обработчике прерывания при достижении счетчиком нуля. Может и еще как-то - зависит от конкретной задачи. Короче говоря - грамотно проектировать программу, учитывая особенности железа.

И постеснялся бы ты такой сабж писать. Судя по предыдущему письму, ты и язык знаешь весьма слабо, и суть глюка не понял, а уже берешься обвинять компилятор. Вот когда будешь уверен, что в исходном коде нет криминала, и выяснишь, что именно компилятор выполняет неверно - вот тогда пиши такой сабж, приводи исходный код, результат работы компилятора и свои комментарии, где тут баг. Это я к тому, что в 90% жалоб в этой эхе на "глюки компилятора xxx" виноват оказывается не компилятор, а желобщик - в незнании языка, незнании компилятора, незнании особенностей процессора, обычной невнимательности и т.п...

Всего наилучшего, [Team PCAD 2000] Алексей М. ... Вышла корова в чисто поле, да всё его и запачкала.

Reply to
Alex Mogilnikov

Hello, Alexandr! You wrote to Alexander Derazhne on Sun, 16 May 2004 21:09:08 +0400:

AD>> У тебя операции с счётчиком не атомарные. Между любыми двумя AD>> _ассемблерными_ инструкциями может влезть прерывание и поменять AD>> значение, половину которого добрый компилятор уже загрузил в AD>> регистр. Попробуй что-нибудь в таком роде:

AZ> Я пpо это в куpсе, но как этому Е$%&му IARу указать, чтобы он AZ> сохpанял ВСЕ pегистpы, котоpые тpогает пpи обpаботке пpеpывания. AZ> Пока на ум пpиходит только на ASMе написать пpоцедуpу, котоpая будет AZ> сохpанять и восстанавливать все pегистpы, но тогда получится, что AZ> некотоpые pегистpы будут сохpанены по два pаза.

Ты не вкурил суть происходящего. У тебя по сути есть два асинхронных процесса, конкурирующих за доступ к разделяемому ресурсу - счётчику. В случае настоящих _процессов_ приходится применять семафоры. Поскольку один из твоих "процессов" обработчик прерывания и никакая ОС твои тылы не прикрывает, то единственным доступным семафором оказывается флажок разрешения прерывания. Это не глюк компилятора, это особенности работы в "многозадачной среде". Сохранение регистров тут не при чём.

With best regards, Alexander Derazhne

Reply to
Alexander Derazhne

Привет Alexander!

17 May 04 02:35, Alexander Derazhne писал Alexandr Zuzin:

AD> Поскольку один из твоих "процессов" обработчик прерывания и AD> никакая ОС твои тылы не прикрывает, то единственным доступным AD> семафором оказывается флажок разрешения прерывания.

Единственным - если только решать данную конкретную проблему "в лоб". Такие вещи продумывают еще на этапе проектирования, и в зависимости от особенностей задачи вариантов может оказаться много. Hапример такой:

volatile char done;

void interrupt(void) { ... if(counter && --counter == 0) done = true; }

int main(void) { ... while(!done); }

Здесь вообще не требуется запрещать прерывания, поскольку counter не является разделяемой переменной, а доступ к done - атомарный.

Всего наилучшего, [Team PCAD 2000] Алексей М. ... Hе место портит человека, а человек место.

Reply to
Alex Mogilnikov

Hello, Alex! You wrote to Alexander Derazhne on Mon, 17 May 2004 15:33:49 +0400:

AD>> Поскольку один из твоих "процессов" обработчик прерывания и AD>> никакая ОС твои тылы не прикрывает, то единственным доступным AD>> семафором оказывается флажок разрешения прерывания.

AM> Единственным - если только решать данную конкретную проблему "в AM> лоб". Такие вещи продумывают еще на этапе проектирования, и в AM> зависимости от особенностей задачи вариантов может оказаться много. AM> Hапример такой:

AM> volatile char done;

AM> void interrupt(void) AM> { AM> ... AM> if(counter && --counter == 0) done = true; AM> }

AM> int main(void) AM> { AM> ... AM> while(!done); AM> }

AM> Здесь вообще не требуется запрещать прерывания, поскольку AM> counter не является разделяемой переменной, а доступ к done - AM> атомарный.

Угу. Зато танцы начнутся на этапе установки значений counter и done. Видимо, всё-таки можно обойтись без запрета прерываний, но до чего громоздко получится!

With best regards, Alexander Derazhne

Reply to
Alexander Derazhne

Пламенный привет тебе, Alex.

AZ>> В pезультате я получаю, что ниже AZ>> пpиведенное условие ноpмально pаботает если начальное число в AZ>> down_cnt<=255, если в down_cnt значение больше 255, напpимеp 257, то AZ>> может получится так, что выход из цикла может пpоизойти пpи значении AZ>> down_cnt=256, а может и пpи down_cnt=0.

AM> И постеснялся бы ты такой сабж писать. Судя по предыдущему письму, AM> ты и язык знаешь весьма слабо, и суть глюка не понял, а уже берешься AM> обвинять компилятор. Вот когда будешь уверен, что в исходном коде нет AM> криминала, и выяснишь, что именно компилятор выполняет неверно - вот AM> тогда пиши такой сабж, приводи исходный код, результат работы AM> компилятора и свои комментарии, где тут баг. Это я к тому, что в 90% AM> жалоб в этой эхе на "глюки компилятора xxx" виноват оказывается не AM> компилятор, а желобщик - в незнании языка, незнании компилятора, AM> незнании особенностей процессора, обычной невнимательности и т.п...

Спасибо, pазъяснили. Посыпаю голову пеплом. Тема закpыта

Всего хорошего, не расплавься. :-) E-Mail: digi(no spam)front.ru ICQ: 177155423

Reply to
Alexandr Zuzin

Привет Alexander!

17 May 04 19:26, Alexander Derazhne писал Alex Mogilnikov:

AD> Угу. Зато танцы начнутся на этапе установки значений counter и AD> done. Видимо, всё-таки можно обойтись без запрета прерываний, но до AD> чего громоздко получится!

Возможно. А еще, возможно, в системе существует много разных прерываний, часть из которых запрещать можно и нужно, а часть - никак нельзя... Короче говоря, обо всех этих тонкостях голова разработчика должна поболеть заранее, чтобы потом сюрпризы не повылезали на этапе испытаний... :)

Всего наилучшего, [Team PCAD 2000] Алексей М. ... Северо-Кавказская межрегиональная ассоциация анонимных соискателей.

Reply to
Alex Mogilnikov

Hello, Alex! You wrote to Alexander Derazhne on Tue, 18 May 2004 00:56:49 +0400:

AD>> Угу. Зато танцы начнутся на этапе установки значений counter и AD>> done. Видимо, всё-таки можно обойтись без запрета прерываний, но до AD>> чего громоздко получится!

AM> Возможно. А еще, возможно, в системе существует много разных AM> прерываний, часть из которых запрещать можно и нужно, а часть - AM> никак нельзя... Короче говоря, обо всех этих тонкостях голова AM> разработчика должна поболеть заранее, чтобы потом сюрпризы не AM> повылезали на этапе испытаний... :)

Если "на этапе испытаний", то ещё ничего. Вот если у Заказчика....

With best regards, Alexander Derazhne

Reply to
Alexander Derazhne
18-May-04 00:56 Alex Mogilnikov wrote to Alexander Derazhne:

AD>> Угу. Зато танцы начнутся на этапе установки значений counter и AD>> done. Видимо, всё-таки можно обойтись без запрета прерываний, но до AD>> чего громоздко получится!

AM> Возможно. А еще, возможно, в системе существует много разных прерываний, AM> часть из которых запрещать можно и нужно, а часть - никак нельзя... Вот поэтому у меня подобные counter-ы объявлены static в отдельном файле с обработчиком таймерного прерывания и рядом лежат какие-нибудь init_timeout( val) и is_timeout_expired() (сейчас кто-то :-) напомнит как это хорошо делать на C++ :-) ) и уж они-то решают - толи все прерывания запрещать, толи только одно нужное (и при смене оного, скажем, с переполнения таймера на compare менять нужно в одном месте), толи ещё как.

AM> Короче AM> говоря, обо всех этих тонкостях голова разработчика должна поболеть AM> заранее, чтобы потом сюрпризы не повылезали на этапе испытаний... :) "Так отож"

wbr,

Reply to
Oleksandr Redchuk

AZ> кусок пpогpаммы должен обеспечивать задеpжку на некотоpое вpемя. В AZ> pезультате я AZ> получаю, что ниже пpиведенное условие ноpмально pаботает если начальное AZ> число в AZ> down_cnt<=255, если в down_cnt значение больше 255, напpимеp 257, то может AZ> получится так, что выход из цикла может пpоизойти пpи значении AZ> down_cnt=256, а AZ> может и пpи down_cnt=0. Закономеpности не наблюдается. Если цикл написать AZ> так:

AZ> Такое впечатление, что в пpеpывании поpтится какой-то pегистp. Как это AZ> победить?

Портится ячейка памяти, ДВА БАЙТА, в которой сохраняется 16-разрядная переменная. Процессор же 8-разрядный. Чего тут ещё думать?

Z+0=0, Z+1=1

AZ> +000008C3: 8100 LDD R16,Z+0 Load indirect with

<ПРЕРЫВАHИЕ...., [Z+0]=FF, [Z+1]=0>

AZ> +000008C4: 8111 LDD R17,Z+1 Load indirect with AZ> +000008C5: 2B01 OR R16,R17 Logical OR AZ> +000008C6: F7D1 BRNE +0x7A Branch if status flag

R16:R17 == 256.

Reply to
Kirill Frolov

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.