Мелкие вопросы по МК и ПЛИС.

Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Ответить
Открыл глаза
Сообщения: 63
Зарегистрирован: Вс фев 03, 2013 13:11:59

Сообщение Резистор »

Всё. Разобрался. Можно использовать Eclipse. Вот здесь - http://www.ibm.com/developerworks/ru/li ... #resources всё написано.
Реклама
Chettuser

Сообщение Chettuser »

Кроссплатформенных IDE не так много. :) Эклиспз - самый знаменитый.
Реклама
Вымогатель припоя
Сообщения: 574
Зарегистрирован: Вт ноя 02, 2010 17:46:37

Сообщение pokk »

Здравствуйте, думал что с рабой АПЦ разобрался а оказалось нет вылез какой-то странный глюк который не как не могу отловить.
АЦП работает в режиме автоматического перезапуска с частотой 12 кГц и тактовая частотой АЦП 156 кГц. Прерывания внутри АЦП разрешены для работы таймера.
После того как добавил обработку значений АЦП по одному из входов(подано постоянное напряжение) постоянно начала возникать ошибка. Начал разбираться и пришёл к тому что из регистра ADCW поступает не те значения, после того как упростил код до минимума(код ниже) выяснилось, что переключение каналов идёт как-то не так как надо. С начало всё работает по каналу I1 идёт значения I1 по I2 идёт I2, а потом бац и они поменялись местами (в обработчике канала I2 приходят значения с канала I1 ) а потом опять нормально до поры до времени. В изначальном варианте (каналов 6 и есть обработка с них) такое происходило редко примерно пару раз в минут 30, но после того как добавил туда задержу в 200 тактов процессора (примерно 2 такта АПЦ) перед запись в регистр ADMUX эти ошибки стали сыпаться постоянно.

Результат из терминала:
Спойлер

Код: Выделить всё

12:57:12.908> 231) ADCW_HIGEST=000 01023 ;
12:57:17.462> 232) ADCW_HIGEST=000 01023 ;
12:57:18.963> 233) I1=000 00647 ;
12:57:23.514> 234) I1=000 00647 ;
12:57:25.013> 235) ADCW_HIGEST=000 01023 ;
12:57:29.504> 236) ADCW_HIGEST=000 01023 ;
12:57:34.060> 237) ADCW_HIGEST=000 01023 ;
12:57:38.554> 238) ADCW_HIGEST=000 01023 ;
12:57:39.114> 239) I1=000 00647 ;
12:57:40.114> 240) I1=000 00647 ;
В случае если запретить прерывания в АЦП то смена каналов не наблюдается (или очень редко может не дождался ) думал что такое может происходить из за нарушения атомарности операций которые работают с регистрами. перед рабой с регистром ADCW и ADMUX по запрещал прерывания но нечего не изменилось. Где-то читал что может флаг ADIF не сбрасываться. При сбросе его в ручную тоже не помогло.

по этому у меня возникли два вопроса:
1) Как правильно переключать каналы в АЦП (После двух тактов АЦП или в течении ?)
2) Как может влиять прерывания от таймера на переключение каналов ?


Код упрошенного варианта
Спойлер

Код: Выделить всё

////=============ADC_initialization==========
//ADCSRA=(1<<ADEN) | (1<<ADSC) | (1<<ADFR) | (0<<ADIF) | (1<<ADIE) | (1<<ADPS2) | (1<<ADPS1) | (0<<ADPS0);
////====================
interrupt [ADC_INT] void adc_isr(void){
unsigned int temp_adc=0;
#asm("sei")  
    switch(adc_main){         
        case I1_MAIN:{
             adc_main=I2_MAIN;    //  Переход на измерения следующего канала
             #asm("cli") // запрещаем прерывание
             temp_adc=ADCW;
             #asm("sei")                
             ADC_BUF->test_int[4]=temp_adc;  //записали в буфер(данный буфер выдаётся в UART по запросу)
                           if(temp_adc<1000){     // нормальное значение АЦП 0x3FF
                             DEBUGER("I1=",0,temp_adc,var2);  //  выдаётся в терминал если есть не соответствие
                           }               
            ADMUX_TEMP=2;          //I1 переключаемся на канал I1 через итерацию с задержкой в 200 тактов
            temp_adc=0;
            break;
        }    
        case I2_MAIN:{  
            #asm("cli")
            temp_adc=ADCW;
            #asm("sei")                   
        // Нормально значение АПЦ около 647 
                           if(temp_adc>700){DEBUGER("ADCW_HIGEST=",0,temp_adc,var2);}            
                           if(temp_adc<600){DEBUGER("ADC_INT_ADCW=",0,temp_adc,var2);
                             LED_GREEN_DOWN();
                           }            
                ADC_BUF->test_int[1]=temp_adc; 
                adc_main=I1_MAIN;
                ADMUX_TEMP=3; //I2
            break;   
        }
        default:{
            adc_main=I1_MAIN;            
            DEBUGER("adc_main=error",0,0,MESEGER);
            break;        
        }
    }
    #include <nop2.c> //200 тактов
    #asm("cli") // запрещаем прерывание           
    ADMUX=ADMUX_TEMP;
    #asm("sei")       
    } 
Сверлит текстолит когтями
Аватара пользователя
Сообщения: 1262
Зарегистрирован: Пн дек 08, 2008 10:58:48
Откуда: Винница

Сообщение urry »

рекомендую просмотреть ассемблерный листинг - с вашей стороны имеет место глубокое непонимание работы прерывания. Вложенность прерываний в авр не поддерживается - когда наступает одно, остальные запрещаются. Компилятор при возникновении прерывания производит действия со стеком , направленные на сохранение контекста прерывания - а при окончании - восстанавливает контекст. Их можно увидеть, только просматривая листинг асма. разрешая принудительно прерывания внутри - вы разрушаете стек. Сохранение - восстановление контекста служит для того, чтобы при возврате из прерывания в точку, откуда оно вызвалось, содержимое флагов (бит зеро, например) было таким же, как и до вызова прерывания. В самом прерывании флаги могут быть изменены. Ну если "на пальцах" объяснить.
Контактная информация:
Реклама
Эиком - электронные компоненты и радиодетали
Вымогатель припоя
Сообщения: 574
Зарегистрирован: Вт ноя 02, 2010 17:46:37

Сообщение pokk »

Я как-то разбирался вопросом (почему столько много таков идёт на вход/выход прерывания) по этому не много представляю что он сохраняет. Только мне не понятен момент почему стэк разрушается после прерывания в прерывании ? К примеру работает маин тут возникает прерывание к АЦП место где мы остановились запихиваем в стэк и запихиваем регистры (контекст) и дальше работаем в прерывании по АЦП изменили половину регистров тут раз ещё одно прерывание от таймера и тут опять сохраняем место возврата и контекст в стэк после выполнения обработчика в таймере мы возвращаемся в обработчик АЦП и достаём от туда контекст ацп.

Думал что может при прерывании АПЦ и таймера разные регистры сохранять посмотрел в ассемблерный листинг одинаковые сохраняет.
Спойлер

Код: Выделить всё

_adc_isr:
	ST   -Y,R0
	ST   -Y,R1
	ST   -Y,R15
	ST   -Y,R22
	ST   -Y,R23
	ST   -Y,R24
	ST   -Y,R25
	ST   -Y,R26
	ST   -Y,R27
	ST   -Y,R30
	ST   -Y,R31
	IN   R30,RAMPZ
	ST   -Y,R30
	IN   R30,SREG
	ST   -Y,R30
=================
	.CSEG
_timer1_ovf_isr:
	ST   -Y,R0
	ST   -Y,R1
	ST   -Y,R15
	ST   -Y,R22
	ST   -Y,R23
	ST   -Y,R24
	ST   -Y,R25
	ST   -Y,R26
	ST   -Y,R27
	ST   -Y,R30
	ST   -Y,R31
	IN   R30,RAMPZ
	ST   -Y,R30
	IN   R30,SREG
	ST   -Y,R30
Если то что я написал не поддерживаться то что происходит после прерывания в прерывании ?
Реклама
Сверлит текстолит когтями
Аватара пользователя
Сообщения: 1262
Зарегистрирован: Пн дек 08, 2008 10:58:48
Откуда: Винница

Сообщение urry »

регистры одинаковые, содержание в них разное. :) Допустим, вошли в прерывание - в стеке сохраняем значение 1, 2, 3 и адрес ,куда мы попадаем после выполнения прерывания. Заходит следующее прерывание, сохраняет свой адрес и значение 4, 5, 6. Первым выходит, скажем, первое прерывание - забирает себе из стека чужие значения 4, 5, 6 и возвращается тоже на чужой адрес.
Каша.
Если ОЧЕНЬ необходимо, повторяю, ОЧЕНЬ - такие куски (прерывание в прерывании) реализуются на асме с полным потактовым контролем и полным осознанием того, что должно быть, естественно, не используя встроенного механизма компилятора. Встречается довольно редко.
Контактная информация:
Реклама
Друг Кота
Сообщения: 4583
Зарегистрирован: Вс дек 05, 2010 06:10:34
Откуда: ЮВ

Сообщение HHIMERA »

Сохраняете то вручную... во время сохранения может произойти очередное прерывание... контекст нарушен...
По поводу стека... даже у STM8, где Nested interrupt и хардварное сохранение контекста в референсе сияет мессага...
Warning: A stack overflow may occur without notifying the software of
the failure.

Заботиться о размере стека и кучи юзер должен сам... а не надеяться на "по умолчанию"...
"Я не даю готовых решений, я заставляю думать!"(С)
Друг Кота
Аватара пользователя
Сообщения: 3872
Зарегистрирован: Пт янв 29, 2010 10:27:40
Откуда: Москва

Сообщение Engineer_Keen »

С порядком внесения/извлечения в стек все по идее должно быть в порядке не зависимо от того что вызывается - прерывание из прерывания или подпрограмма из подпрограммы, ну если компилятор конечно не дурак (а он, как правило - дурак :))) ), но...
pokk писал(а):работаем в прерывании по АЦП изменили половину регистров тут раз ещё одно прерывание от таймера
А если вдруг случится прерывание от этого же АЦП? Получится рекурсия и стек просто рано или поздно переполнится. Ну это конечно в случае, если забить на время выполнения прерываний. Так что если разрешаете прерывание внутри прерывания, то все нужно точно рассчитывать и гарантировать невозможность такой рекурсии. Тут выше все правильно сказали про контроль в таких случаях и как такое сделать не на ассемблере я честно говоря не представляю.
Неправильно собранная из неисправных деталей схема нуждается в отладке и сразу не работает... (С)
Вымогатель припоя
Сообщения: 574
Зарегистрирован: Вт ноя 02, 2010 17:46:37

Сообщение pokk »

Engineer_Keen, а я вот наоборот не представляю что куда на ассемблере вставлять =). На выполнения кода в обработчике АЦП есть 833 такта =) по прогонял его в AVR studio там было максимум 300 тактов а так в основном около 100. А вот сколько таймер тактов занимает не в курсе, но программа писалась на принципе зашёл выполнил пару действий перестроил таймер вышел. Сейчас осциллографом по смотрю сколько времени обработчик АЦП занимает(с учётом таймера).
Друг Кота
Аватара пользователя
Сообщения: 3872
Зарегистрирован: Пт янв 29, 2010 10:27:40
Откуда: Москва

Сообщение Engineer_Keen »

ИМХО 300 тактов для прерывания это весьма дохрена... Такое можно позволить если контроллеру больше заняться нечем.
Хотя зная что сишные компиляторы во всех подпрограммах когда надо и не надо сохраняют в стек половину регистрового файла, я не удивляюсь.
Обычно либо прерывание короткое, буквально несколько действий с регистрами/периферией, либо вообще только сохранить значение (с того же АЦП) и какой-нибудь глобальный флаг выставить, чтобы по нему потом в основном цикле вызвать обработчик этого значения. Например сохранить в памяти значение АЦП и выставить флаг для его обработки - 14 тактов. Ни один таймер с минимальным делителем за такое время не успеет переполниться и прерывание от него не пропадет.
Неправильно собранная из неисправных деталей схема нуждается в отладке и сразу не работает... (С)
Вымогатель припоя
Сообщения: 574
Зарегистрирован: Вт ноя 02, 2010 17:46:37

Сообщение pokk »

Ага я уже подумал что не совсем правильно у меня АЦП организованно но уже многое понаписано.
В общем замерил осциллографом время выполнения обработчика АЦП с разрешёнными прерываниями получилось что колеблется от 357 тактов до 588. (неправильно измерил в основном 240 а при двух прерываниях в ацп около 600)
Походу я уже наблюдал переполнение стэк у меня было такое что она работает работает а потом бац и main запускается с инициализацией всей периферией, но это я отладчик делал через usart а он переполнялся ошибками.

В данном случае я думал что нету переполнения стэка, так как если бы он был то программа бы совсем слетела у меня в maine идёт связь по usart он бы перестал работать или в таймере опрос температурного датчика завис.

Думаю это ошибка связанна стем как у меня переключение каналов происходит, то что выставляю mux во время преобразования и он только переключится через одно преобразование.
Последний раз редактировалось pokk Пт сен 19, 2014 04:40:38, всего редактировалось 1 раз.
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18682
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

pokk, я включился в тему поздно и могу кой-чего не знать, поэтому если скажу что-то уже сказанное - прошу извинить.

после просмотра вашего кода у меня появилось нескольковопросов:
Спойлер

Код: Выделить всё

////=============ADC_initialization==========
//ADCSRA=(1<<ADEN) | (1<<ADSC) | (1<<ADFR) | (0<<ADIF) | (1<<ADIE) | (1<<ADPS2) | (1<<ADPS1) | (0<<ADPS0);
////====================
interrupt [ADC_INT] void adc_isr(void){
unsigned int temp_adc=0;
#asm("sei")  
    switch(adc_main){         
        case I1_MAIN:{
             adc_main=I2_MAIN;    //  Переход на измерения следующего канала
             #asm("cli") // запрещаем прерывание
             temp_adc=ADCW;
             #asm("sei")                
             ADC_BUF->test_int[4]=temp_adc;  //записали в буфер(данный буфер выдаётся в UART по запросу)
                           if(temp_adc<1000){     // нормальное значение АЦП 0x3FF
                             DEBUGER("I1=",0,temp_adc,var2);  //  выдаётся в терминал если есть не соответствие
                           }               
            ADMUX_TEMP=2;          //I1 переключаемся на канал I1 через итерацию с задержкой в 200 тактов
            temp_adc=0;
            break;
        }    
        case I2_MAIN:{  
            #asm("cli")
            temp_adc=ADCW;
            #asm("sei")                   
        // Нормально значение АПЦ около 647 
                           if(temp_adc>700){DEBUGER("ADCW_HIGEST=",0,temp_adc,var2);}            
                           if(temp_adc<600){DEBUGER("ADC_INT_ADCW=",0,temp_adc,var2);
                             LED_GREEN_DOWN();
                           }            
                ADC_BUF->test_int[1]=temp_adc; 
                adc_main=I1_MAIN;
                ADMUX_TEMP=3; //I2
            break;   
        }
        default:{
            adc_main=I1_MAIN;            
            DEBUGER("adc_main=error",0,0,MESEGER);
            break;        
        }
    }
    #include <nop2.c> //200 тактов
    #asm("cli") // запрещаем прерывание           
    ADMUX=ADMUX_TEMP;
    #asm("sei")       
    }
1. вы представляете, для чего вы делаете запрет и последующее разрешение прерываний в обработчике прерывния?
2. вы представляете себе последствия таких действий?
3. это на самом деле необходимо для вашего алгоритма?
4. DEBUGER - это функция? вы представляете себе последствия вызова функций из обработчика прерываний?

я так думаю, что 300-500 ваших тактов на обработчик - исключительно следствие того, что вы смутно представляете себе ответы на эти вопросы. могу дать несколько советов общего характера:
1. никогда не запрещайте прерывания в обработчике прерываний - это лишнее.
2. без крайней необходимости и четкого понимания этой необходимости никогда не разрешайте прерывания внутри обработчика прерываний. в некоторых случаях последствия будут катастрофическими.
3. всеми силами избегайте обращения к функциям из обработчика прерываний. в крайнем случае используйте только статические функции из этого же программного модуля.
4. никогда не используйте библиотечные функции ввода-вывода в обработчиках прерываний (типа printf)
5. всеми силами стремитесь не ипользовать в обработчике прерываний различных программных задержек.

будете соблюдать эти правила - проблем у вас будет существенно меньше.

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

Мой уютный бложик... заходите!
Контактная информация:
Друг Кота
Аватара пользователя
Сообщения: 3872
Зарегистрирован: Пт янв 29, 2010 10:27:40
Откуда: Москва

Сообщение Engineer_Keen »

Кстати, вот эта вот фигня "DEBUGER()" возвращается когда вся строка отправлена или она только запускает передачу и возвращается сразу? Если первое, да еще и завязанное на п.4 из поста выше, то... Короче переделать...
И какая частота контроллера? На 8МГц к примеру, 588 тактов это примерно 13.6кГц, довольно близко к 12кГц, почти впритык.
Остальное ARV сказал...
Неправильно собранная из неисправных деталей схема нуждается в отладке и сразу не работает... (С)
Опытный кот
Сообщения: 773
Зарегистрирован: Пн сен 01, 2014 20:38:54

Сообщение MisHel64 »

urry писал(а):регистры одинаковые, содержание в них разное. :) Допустим, вошли в прерывание - в стеке сохраняем значение 1, 2, 3 и адрес ,куда мы попадаем после выполнения прерывания. Заходит следующее прерывание, сохраняет свой адрес и значение 4, 5, 6. Первым выходит, скажем, первое прерывание - забирает себе из стека чужие значения 4, 5, 6 и возвращается тоже на чужой адрес.
Каша.
Не будет никакой каши. Сначала отработает второе прерывание, и оно должно вычистить все за собой, и только после этого свою работу продолжит обработчик перового прерывания. Просто тупо, завершить обработку первого прерывания, не получится до завершения второго. Это же очевидно!
Опытный кот
Сообщения: 822
Зарегистрирован: Вс июн 02, 2013 12:23:03

Сообщение amd9800 »

Из выше сказанного можно понять что когда программа входит в прерывании тогда отключаются все прерывания?
И нету смысла их включать и отключать?
Друг Кота
Аватара пользователя
Сообщения: 3872
Зарегистрирован: Пт янв 29, 2010 10:27:40
Откуда: Москва

Сообщение Engineer_Keen »

amd9800 писал(а):Из выше сказанного можно понять что когда программа входит в прерывании тогда отключаются все прерывания?
Да ,при заходе в обработчик прерывания аппаратно сбрасывается глобальный флаг разрешения прерывании. При выходе из прерывания, он так же аппаратно устанавливается в "1"...
amd9800 писал(а):И нету смысла их включать и отключать?
... следовательно отключать смысла нет 100%, а включать только если очень сильно нужно реализовать например какую-либо хитрую систему приоритетов прерываний, в 99% случаев этого делать не следует, лучше переосмыслить структуру программы.
Неправильно собранная из неисправных деталей схема нуждается в отладке и сразу не работает... (С)
Опытный кот
Сообщения: 822
Зарегистрирован: Вс июн 02, 2013 12:23:03

Сообщение amd9800 »

"Engineer_Keen" - огромное спасибо

На данном этапе решил поработать с LCD дисплеями. Но тут я понял что мне надо использовать данные типа string. В высокоуровневых языках как java там все ясно. А в "С" столкнулся с определенными моментами. Как такого типа string нету и надо использовать массив char и еще работать с указателями да еще для функций LCD надо учитывать в какой памяти хранятся данные. Отдельная функция в зависимости от типа данных.

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

Например - Voltage = 5.02V
Таким образом "Voltage = " и "V" не меняются, а "5.02" может принимать разные значения.
Для фиксированной части вроде определил что объявляю переменную указатель

Код: Выделить всё

flash unsigned char *vv="Voltage "
lcd_putsf(vv);
Но вот вопрос как вывести на экран само значение "5.02" ?

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

Код: Выделить всё

unsigned char *s="C";
lcd_puts(s);

Но если вывожу на экран символы по коду тогда после самого символа появляется еще и пробел.

Код: Выделить всё

unsigned char cc=66;
unsigned char *cj;

сj=&cc;
lcd_puts(cj);
Вымогатель припоя
Сообщения: 574
Зарегистрирован: Вт ноя 02, 2010 17:46:37

Сообщение pokk »

ARV,
ARV писал(а): 1. вы представляете, для чего вы делаете запрет и последующее разрешение прерываний в обработчике прерывния?
2. вы представляете себе последствия таких действий?
3. это на самом деле необходимо для вашего алгоритма?
4. DEBUGER - это функция? вы представляете себе последствия вызова функций из обработчика прерываний?
1. Я исключал версию что данный глюк возникает из за нарушения атомарности работы с регистрами ADCW
2. Прерывание от таймера может не сработать по этому там одну строчку и запрещал что бы было всё быстро.
3. В таймере крутится программная реализации протокола 1-wire написанная в духе конечных автоматах. По этому могут быть маленькие задержки.
4. Да функция написана мною. Она заносит указатель на строку в буфер и ADCW. в главном цикле из этого буфера всё передаётся. Последствия вызова функций в обработчике не очень представляю разве что переполнения стэка может случится
в исходной версией программы этой функции не будет.
я так думаю, что 300-500 ваших тактов на обработчик - исключительно следствие того, что вы смутно представляете себе ответы на эти вопросы.
Что-то вчера вечером перемудрил не так померил в основном (с выкл прерываниями) это 250 тактов (оно так и есть 200 nop 30 вход/выход из прерываний и 20 на 5-10 операций остаётся).
а при включенных прерываниях доходит до того что таймер два раза успевает обработчик АЦП прервать. Соответственно обработчик АЦП растягивается до 600 тактов.
ну и вообще, ваш код весьма "грязный" - подумайте над его упрощением. как правило, лаконичный код проще понимать и отлаживать, да и чаще всего он меньше проблем вызывает...
А вот про это можно по подробней ? что не так ? что не читабельно ? В CV можно всё по сворачивать =)) и он получается компактный.

Engineer_Keen, Про функцию DEBUGER выше написал пункт 4 (вроде как в 40 тактов укладывается )
Частота 10 МГц это 833 такта на обработку АЦП. так что есть ещё запас около 300 тактов

Возник ещё один вопрос после того как изменили регистр MUX во время преобразования суда из даташита он заблокирован и не переключится а переключится на последнем такте АЦП перед завершением преобразования. Т.е почти перед входом в следующий обработчик прерывания ?
Друг Кота
Аватара пользователя
Сообщения: 20093
Зарегистрирован: Чт сен 18, 2008 12:27:21
Откуда: Столица Мира Санкт-Петербург

Сообщение Gudd-Head »

Физически в какой памяти у АВРок хранятся фьюзы? Сколько раз их можно перешивать?
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
Друг Кота
Аватара пользователя
Сообщения: 3872
Зарегистрирован: Пт янв 29, 2010 10:27:40
Откуда: Москва

Сообщение Engineer_Keen »

Вроде как во флеше. Их даже можно из самой программы прочитать через LPM. Значит и ресурс как у флеша (10к).
Неправильно собранная из неисправных деталей схема нуждается в отладке и сразу не работает... (С)
Ответить

Вернуться в «Разные вопросы по МК»