реклама на сайте
подробности

 
 
> CodeVision+указатели+прерывание, Искажение указателя при прерывании
troy97
сообщение Sep 25 2009, 06:53
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 20
Регистрация: 12-01-09
Из: Донецк, Украина
Пользователь №: 43 218



Написал вот такой код:
Код
interrupt [TIM2_OVF] void timer2_ovf_isr(void)
{
        // Stop timer
        TCCR2=0x00;

        if(get_incoming_pkt()==3){
        
                switch (check_command(myip)) {
                
                case 0:
                        strcpyf(service_msg, "Micro_device#0:not_a_command");
                        service_msg[13]=device_id;
                        send_to_server(service_msg, service_msg_len);                
                break;
                                
                case 1:
                        init_ip_arp_udp(mymac,myip);
                        strcpyf(service_msg, "Micro_device#0:IP_changed");
                        service_msg[13]=device_id;
                        send_to_server(service_msg, service_msg_len);                
                break;
                
                case 2:
                        strcpyf(service_msg, "Micro_device#0:comm_2_done");
                        service_msg[13]=device_id;
                        send_to_server(service_msg, service_msg_len);                
                break;                
      
                default:
                        strcpyf(service_msg, "Micro_device#0:command_Error");
                        service_msg[13]=device_id;
                        send_to_server(service_msg, service_msg_len);
                };                      
        };        
                
        // Start timer
        TCCR2=0x07;
        TCNT2=0x00;
} // end of interrupt


void main(void)

....
unsigned int* pointer;
......

          pointer=get_adc_data();
          for(i=0;i<6;i++){    
                data_msg[16+2*i]=(*(pointer+i))>>8; //MSB
                data_msg[16+2*i+1]=(*(pointer+i)) & 0xff; //LSB
          };

......


Проблема следующая: при возникновении прерывания во время работы с указателем, значения записываемые в data_msg[], искажаются.
При запрете прерываний на этот кусок кода, всё работает нормально.

Сообщение отредактировал troy97 - Sep 25 2009, 07:20
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов (1 - 11)
SasaVitebsk
сообщение Sep 25 2009, 08:33
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



1) Может pointer используется где-то в прерывании? Или i. Например она у вас глобальной объявлена, а в прерывании объявить забыли. Это единственное прерывание?
2) Может в прерывании, при работе с service_msg вы банально выходите за границы объявленой памяти и портите data_msg. Си ведь границы не определяет - на вас надеется.
Go to the top of the page
 
+Quote Post
Goodefine
сообщение Sep 25 2009, 14:03
Сообщение #3


Местный
***

Группа: Свой
Сообщений: 211
Регистрация: 6-08-07
Из: Приднестровье, Тирасполь
Пользователь №: 29 581



Цитата(troy97 @ Sep 25 2009, 09:53) *
...Проблема следующая...

Функцию get_adc_data() покажите...


--------------------
Любой, заслуживающий внимания, опыт приобретается себе в убыток...
Go to the top of the page
 
+Quote Post
troy97
сообщение Sep 25 2009, 16:39
Сообщение #4


Участник
*

Группа: Участник
Сообщений: 20
Регистрация: 12-01-09
Из: Донецк, Украина
Пользователь №: 43 218



1) pointer точно не используется в прерывании. i объявлена в начале main(), да и не на i подозрения т.к. сегодня отловил, что та же проблема, но реже, возникает если вырубать прерывания только на кусок с циклом for. Т.е. портится указатель даже на строке pointer=get_adc_data();
2) нет, размер service_msg не превышаю.

Привожу код get_adc_data():

CODE
unsigned int* get_adc_data(void)
{
unsigned char i;
unsigned int adc_data=0;
unsigned int analog_vals_arr[6]={0,0,0,0,0,0};

// ADC Clock frequency: 130,156 kHz
ADCSRA=0x86;// ADC enable; ADC int.disable; prescaler=64

TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
TCCR1B=0x03;// clk/64


do{
for (i=0; i<6; i++)
{
ADMUX&=0b11110000;
ADMUX|=i;
ADCSRA|=0x40;
while(!(ADCSRA & (1<<ADIF)));
ADCSRA|=(1<<ADIF);

adc_data=ADCW;
check(adc_data, i);

};

// check timer1 overflow flag
if (TIFR &= (1<<TOV1))
{
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
TIFR |= (1<<TOV1);
timer1(analog_vals_arr);
break;
};

}
while(1);

ADCSRA clrb(ADEN);//stop ADC
return (analog_vals_arr);
}


функция timer1 получает указатель analog_vals_arr и заполняет массив необходимыми значениями
Причина редактирования: Уменьшение видимого размера цитаты исходника.
Go to the top of the page
 
+Quote Post
Goodefine
сообщение Sep 25 2009, 19:06
Сообщение #5


Местный
***

Группа: Свой
Сообщений: 211
Регистрация: 6-08-07
Из: Приднестровье, Тирасполь
Пользователь №: 29 581



Попробуйте так:
Код
...
#asm("cli")
TCNT1H=0x00;
TCNT1L=0x00;
#asm("sei")
...
#asm("cli")
adc_data=ADCW;
#asm("sei")
...

ЗЫ. И что за while(1) ? Как программа оттуда выходит (если флаг не будет стоять)?

А стек увеличивать пробовали?..


--------------------
Любой, заслуживающий внимания, опыт приобретается себе в убыток...
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Sep 26 2009, 05:51
Сообщение #6


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



На вид: тяжеловесное прерывание. Может, в этот кусок кода лучше заходить из прерывания через setjmp/longjmp?
Go to the top of the page
 
+Quote Post
Sergey Reva
сообщение Sep 26 2009, 06:15
Сообщение #7


Участник
*

Группа: Участник
Сообщений: 70
Регистрация: 22-04-07
Из: Poltava/Kharkov
Пользователь №: 27 243



get_adc_data возвращает указатель на локальную переменную (созданую с стеке), естественно при входе в прерывание по тем адресам (где были значения analog_vals_arr) создаются другие локальные переменные. Нужно объявить analog_vals_arr как static, либо переделать get_adc_data так чтобы она заполняла переданый ей (указателем) массив.

p.s.
ладно, попробую поменять порядок слов smile.gif

Сообщение отредактировал Sergey Reva - Sep 26 2009, 06:36
Go to the top of the page
 
+Quote Post
troy97
сообщение Sep 26 2009, 06:26
Сообщение #8


Участник
*

Группа: Участник
Сообщений: 20
Регистрация: 12-01-09
Из: Донецк, Украина
Пользователь №: 43 218



Goodefine, попробую, но определено, что проблема не возникает, если перед самым return'ом из get_adc_data(), сбросить TCNT2, т.е. чтобы прерывание точно не попало на кусок с указателями. Из while(1), если TOV1 не установлен... никак не выходит... признаю свою вину.
"А стек увеличивать пробовали?.." - нет, а как?smile.gif

_Pasha, можно и так, а что это даст, если я правильно понимаю, то просто добавится ещё один прыжок, а время обработки прерывания останется тем же?

Sergey Reva, очень логично, сделаю, спасибо.

Сообщение отредактировал troy97 - Sep 26 2009, 06:29
Go to the top of the page
 
+Quote Post
Goodefine
сообщение Sep 26 2009, 18:41
Сообщение #9


Местный
***

Группа: Свой
Сообщений: 211
Регистрация: 6-08-07
Из: Приднестровье, Тирасполь
Пользователь №: 29 581



Цитата(troy97 @ Sep 26 2009, 09:26) *
"А стек увеличивать пробовали?.." - нет, а как?smile.gif

В свойствах проекта...


--------------------
Любой, заслуживающий внимания, опыт приобретается себе в убыток...
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Sep 27 2009, 18:40
Сообщение #10


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Цитата(Sergey Reva @ Sep 26 2009, 09:15) *
get_adc_data возвращает указатель на локальную переменную (созданую с стеке), естественно при входе в прерывание по тем адресам (где были значения analog_vals_arr) создаются другие локальные переменные. Нужно объявить analog_vals_arr как static, либо переделать get_adc_data так чтобы она заполняла переданый ей (указателем) массив.


+1.

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

Я бы не применял static, так как выглядит неестественно. Я бы либо сделал массив глобальным, либо объявил его в месте использования и передавал процедуре на неё указатель, как рекомендовал Sergey Reva.
Go to the top of the page
 
+Quote Post
troy97
сообщение Sep 28 2009, 06:53
Сообщение #11


Участник
*

Группа: Участник
Сообщений: 20
Регистрация: 12-01-09
Из: Донецк, Украина
Пользователь №: 43 218



Объявил массив в месте его использования, функции передаю указатель. Сегодня утром прошился, уже 1,5 часа полёт нормальный, надо ещё погонять, потом отпишусь.
Go to the top of the page
 
+Quote Post
troy97
сообщение Sep 29 2009, 09:53
Сообщение #12


Участник
*

Группа: Участник
Сообщений: 20
Регистрация: 12-01-09
Из: Донецк, Украина
Пользователь №: 43 218



Работает уже сутки без сбоев, всем большое спасибо за помощь!

Сообщение отредактировал troy97 - Sep 29 2009, 09:54
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 22nd July 2025 - 11:24
Рейтинг@Mail.ru


Страница сгенерированна за 0.01453 секунд с 7
ELECTRONIX ©2004-2016