Микроконтролери и електроника
http://mcu-bg.com/mcu_site/

Глобални променливи и прекъсвания
http://mcu-bg.com/mcu_site/viewtopic.php?f=3&t=7374
Страница 1 от 3

Автор:  i_dachev [ Сря Дек 09, 2009 10:58 am ]
Заглавие:  Глобални променливи и прекъсвания

Чудя се ако декларирам глобална променлива която е 16 или повече бита за
PIC18 процесор и използвам C18 компилатор, то няма ли да има проблем
ако ползвам променливата в нормална функция и прекъсване.

За пример следния код:

volatile int g_p;

void main() {
int l_p;
...

l_p = g_p;

...
}

isr...
void isr() {
...
g_p = 0xFF40;
...
}

...

Проблема който виждам е че присвояването на l_p = g_p не е атомарно.
Дали има инструкции на PIC18, които могат да го направят атомарно от гледна
точка на прекъсването?

Автор:  Цецо [ Сря Дек 09, 2009 11:26 am ]
Заглавие: 

Не. Ако ползваш едни и същи обекти които не са атомични (бит и байт при PIC18) в прекъсване и основната програма - твоя е грижата да синхронизираш достъпа до тях.

Най просто е да забраниш прекъсванията при достъп до променливата в основната програма. Но не винаги е универсално решение.

Автор:  i_dachev [ Сря Дек 09, 2009 11:55 am ]
Заглавие: 

Хм и аз така предложих, но немога да измисля нещо по-добро
от това с кратко забраняване на прекъсванията някой да има идеи?

Автор:  zaphod [ Сря Дек 09, 2009 11:57 am ]
Заглавие: 

както каза цецо, забраната за прекъсване в общия случай не е решение. става когато времето на защитената операция е некритично като закъснение за прекъсването, но ако е по-голямо от критичното, не става. тогава си трябва синхронизиращ примитив, нямам идея в 18ките има ли такива. но само за четене на един инт, става си и със забрана на прекъсването.

Автор:  i_dachev [ Сря Дек 09, 2009 12:21 pm ]
Заглавие: 

Аз имам идея да ползвам допълнително един байт за синхронизация.
Ако е вдигнат тоя байт/бит няма да пипам стойността от прекъсването.
Ако не е променям.

Слагам флага преди да прочета глобалната променлива и го свалям след края.

Автор:  Цецо [ Сря Дек 09, 2009 1:09 pm ]
Заглавие: 

Специално в случая който излагаш, забраната на прекъсванията е най-оптималния вариант.

Пускане/спиране на прекъсване в ПИК е манипулация на един бит - т.е. един клок. Няма как да направиш нещо по бързо. Т.е. и да сложиш специален бит (семафор) който да ти "защитава" променливата - нищо съществено няма да постигнеш като бързодействие или памет, напротив ще се забавиш.

Виж ако защитената секция е по голяма по размер и се налага преоритет (или последователност) при обработката и т.н.... тогава вече трябва да мислиш за нещо по сложно... Всъщност тогава вече е време да почнеш да четеш "що е то RTOS" :):):)

Автор:  Реконструктор [ Сря Дек 09, 2009 9:37 pm ]
Заглавие: 

Ето ви едно извращение - C++ за микроконтролери. :D Това е защитена променлива, която не налага забраната на прекъсванията.

Прикачени файлове:
svar.h [562 Байта]
252 пъти

Автор:  i_dachev [ Чет Дек 10, 2009 10:13 am ]
Заглавие: 

:) това е безсмислен код :) или трябва да ти обяснят подробно,
къде им е трябвало това чудо на програмирането

Автор:  smtp [ Чет Дек 10, 2009 10:34 am ]
Заглавие: 

i_dachev написа:
:) това е безсмислен код :) или трябва да ти обяснят подробно,
къде им е трябвало това чудо на програмирането


кода си е напълно смислен (за теб е явно прекалено сложен) !

някой ден (след 10г примерно), когато почне да пишеш мнооого по-сложни/големи неща ще схванеш идеята която е: четене на коректни данни които не са в процес на модифициране!

PS: това че е c++ няма никакво значение - само е по удобно!

Автор:  zaphod [ Чет Дек 10, 2009 10:34 am ]
Заглавие: 

i_dachev написа:
Аз имам идея да ползвам допълнително един байт за синхронизация.
Ако е вдигнат тоя байт/бит няма да пипам стойността от прекъсването.
Ако не е променям.

Слагам флага преди да прочета глобалната променлива и го свалям след края.

ще изтърваш семпли така. може да не ти пука конкретно в тая ситуация, но пък какво ти пука и да забраниш прекъсването? в случая е уместно, операцията е къса, няма да опескаш нищо, а няма да изтърваш семпли.

Автор:  Zdrav [ Чет Дек 10, 2009 10:53 am ]
Заглавие: 

Реконструктор написа:
Ето ви едно извращение - C++ за микроконтролери. :D Това е защитена променлива, която не налага забраната на прекъсванията.


Добре, а какво ще стане ако при рефрешването на m_Shadow(между байтовете, нали то също не е атомик), дойде прекъсване,в което се ползва CShadowVar::Get().
Ето тук:
Код:
void RefreshShadow()
   {
      do
      {
         m_bRefreshing = 0;
         m_Shadow = m_Original;  // <-------- Тук
      }
      while(m_bRefreshing);   
   }


Или този код е само за случаите в които Get() се ползва само от основната нишка, а Set() асинхронно в прекъсване...

Автор:  tolstolob [ Чет Дек 10, 2009 11:16 am ]
Заглавие: 

Най-добре си забрани прекъсванията и си копирай променливата. За 16-битова променлива копирането би трябвало да отнеме 4 цикъла + евентуално 1 за превключване на банката, което не е болка за умиране.

Автор:  Реконструктор [ Чет Дек 10, 2009 1:14 pm ]
Заглавие: 

Zdrav написа:
Реконструктор написа:
Ето ви едно извращение - C++ за микроконтролери. :D Това е защитена променлива, която не налага забраната на прекъсванията.


Добре, а какво ще стане ако при рефрешването на m_Shadow(между байтовете, нали то също не е атомик), дойде прекъсване,в което се ползва CShadowVar::Get().
Ето тук:
Код:
void RefreshShadow()
   {
      do
      {
         m_bRefreshing = 0;
         m_Shadow = m_Original;  // <-------- Тук
      }
      while(m_bRefreshing);   
   }



Или този код е само за случаите в които Get() се ползва само от основната нишка, а Set() асинхронно в прекъсване...


Ще се дигне m_bRefreshing и цикъла ще се повтори. Това е целия смисъл.

Автор:  Zdrav [ Чет Дек 10, 2009 1:48 pm ]
Заглавие: 

Реконструктор погледни сорса който си приложил. При викане на Get() не се вдига m_bRefreshing!!!
Аз предлагам ето така:
Код:
#ifndef __SVAR_H__
#define __SVAR_H__

#include <stdint.h>

// Shadow variable definition

template <typename T>
class CShadowVar
{
private:
   T         m_Original;
   T         m_Shadow;


public:
   CShadowVar()
   {
      m_Original = 0;
      m_Shadow = 0;
   }

   void Set(T NewVal)
   {
      m_Original = NewVal;
   }

   T Get()
   {
      do
      {
         m_Shadow = m_Original;
      }
      while(m_Shadow != m_Original);
      return m_Shadow;
   }
};

#endif



Разбира се ако латентноста на прекъсванията е толкова критична. Ако не е и аз съм за варианта със забраняване/разрешаване на прекъсванията.

Автор:  perlsite [ Чет Дек 10, 2009 4:54 pm ]
Заглавие: 

Винаги може да се омаже кода и не мисля, че по този начин може да се реши проблема точно защото и след като излезне от while цикъла, преди да върне метода, респективно да се ползва стойността може да бъде променена.
Само решение с някаква опашка и dispatcher може да помогне, където всяка операция се поставя в опашка и винаги се изпълнява серийно.

Страница 1 от 3 Часовете са според зоната UTC + 2 часа [ DST ]
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/