Перейти к содержанию
    

MSP430 - снова вопросы от чайника

Опять я :) теперь нужен еще буфер - для АЦП. посмотрите, пожалуйста, нормально ли написана функция чтения? :)

Та же структура

 typedef struct CharBuffer
{
    unsigned char* Data;            
    int NData;                        
    int cData;            
    int pWrite;                        
    int pRead;                        
}
CharBuffer;
#define sizeADCBufR 100
struct CharBuffer stADCBufR;
unsigned char ADCBufR[sizeADCBufR];

stADCBufR.NData = sizeADCBufR;
    stADCBufR.Data = ADCBufR;
    BufferReset(&stADCBufR);

 

Функция записи - записывает по байтам два int числа, функции записи и чтения байта описаны выше

int WriteADCbuf(CharBuffer* pBuffer, int* data, int size)    
{    if((pBuffer->NData-pBuffer->cData)<2*size+1)return 1;
    for( int j = 0; j < size; j++)    
    {        
        BufferWrite(pBuffer, (data[j]&0xFF));
        BufferWrite(pBuffer, (data[j]>>8));
    }
    return 0;
}

Чтение в две переменных

void ReadADCbuf(CharBuffer* pBuffer, int* data0, int* data1)
{    
  unsigned char Dat[4];
   BufferRead(pBuffer, &Dat[0]);
  BufferRead(pBuffer, &Dat[1]);
  *data0=((Dat[0]&0x00FF)|((Dat[1]<<8)&0xFF00));
   BufferRead(pBuffer, &Dat[2]);
  BufferRead(pBuffer, &Dat[3]);
*data1=((Dat[2]&0x00FF)|((Dat[3]<<8)&0xFF00));
  
}

Вызов

ReadADCbuf(&stADCBufR, &Vr0, &Vr1)

Правильно ли склеиваю? И вообще - что-то с ней, по-моему, не то :)

Еще вопрос - как правильно работать с WDT? Я просто останавливаю его при начальной инициализации, и все. Но говорят, что это не правильно, нужно постоянно обращаться к нему, чтобы избежать зависания процессора. Как это делать - обращаться постоянно в цикле for(;;)?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

И еще :) Мне нужно обмениваться с двумя устройствами. Что лучше - использовать второй модуль USART1 или можно просто многопроцессорный формат в USART0? Нужно уже рисовать схему

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

И еще :) Мне нужно обмениваться с двумя устройствами.

Обычно при обмене кто-то главный (master), а кто-то подчиненный (slave).

Как старшинство распределено среди этого трио?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Обычно при обмене кто-то главный (master), а кто-то подчиненный (slave).

Как старшинство распределено среди этого трио?

одно устройство принимает команды с компьютера(от оператора) и на основании их руководит вторым устройством(передает команды и принимает ответные данные). :) Как-то так

Вопрос про функцию снимается, а вот про WDT? Что, если перезапускать его в прерываниях таймера через каждые сколько-то мс? Как вообще обычно им пользуются?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

одно устройство принимает команды с компьютера(от оператора) и на основании их руководит вторым устройством(передает команды и принимает ответные данные). :) Как-то так
Раз есть второй аппаратный UART, то грешнО его не использовать.

а вот про WDT? Что, если перезапускать его в прерываниях таймера через каждые сколько-то мс? Как вообще обычно им пользуются?
Лично я его обычно использую как таймер системных тиков, т.к. у него приоритет прерывания один из самых высоких :) Если же вас интересует теория, то где бы вы не сбрасывали WatchDog он должен сбрасываться только после анализа нескольких флагов, которые устанавливаются в разных ответственных местах программы. Вы можете сбрасывать WDT в прерывании таймера, но не просто по факту попадания в это прерывания, а только если выполняются все условия "попадания" в различные другие части программы. В те, куда программный код обязательно должен привести в промежутках между сбросом WDT.

Кстати, от "защелкивания" или экстремальных случаев воздействия статики на MSP430 внутренний WatchDog не спасает.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Лично я его обычно использую как таймер системных тиков, т.к. у него приоритет прерывания один из самых высоких :) Если же вас интересует теория, то где бы вы не сбрасывали WatchDog он должен сбрасываться только после анализа нескольких флагов, которые устанавливаются в разных ответственных местах программы. Вы можете сбрасывать WDT в прерывании таймера, но не просто по факту попадания в это прерывания, а только если выполняются все условия "попадания" в различные другие части программы. В те, куда программный код обязательно должен привести в промежутках между сбросом WDT.

Кстати, от "защелкивания" или экстремальных случаев воздействия статики на MSP430 внутренний WatchDog не спасает.

Ага, а я вот как раз хотела сначала настроить в сторожевом режиме, а потом просто сбрасывать WDTCNTCL в прерываниях таймера :) Не все так просто...

То есть, вы не используете WDT в сторожевом режиме, и ничего страшного не случается? :)

И вот еще более важные вопросы -

У меня куча массивов, если объявлять их в main, они начинают забивать стек, если как глобальные - то ведь память, отведенная под глобальные константы ограничена. Как быть? Можно ли как-то программно увеличить размер стека?

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ага, а я вот как раз хотела сначала настроить в сторожевом режиме, а потом просто сбрасывать WDTCNTCL в прерываниях таймера :) Не все так просто...

То есть, вы не используете WDT в сторожевом режиме, и ничего страшного не случается? :)

А что там должно "страшного" случиться? :cranky: Режим интервального таймера для WDT является штатным и документированным. Если вы сомневаетесь в помехоустойчивости, то вообще-то помехоустойчивость устройства в бОльшей степени определяется конструктивными и схемотехническими (трассировка платы, расположение и подключение внешних и внутренних цепей и т.п.) особенностями устройства, а не использованием WatchDog ;)

И вот еще более важные вопросы -

У меня куча массивов, если объявлять их в main, они начинают забивать стек, если как глобальные - то ведь память, отведенная под глобальные константы ограничена. Как быть? Можно ли как-то программно увеличить размер стека?

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

В Plain C и ANSI C используются четыре типа переменных:

1. register (регистровые), размещаются в регистрах (хотя компиляторы чаще всего плюют на это указание). Область "видимости" текущая функция/контейнер. При выходе из функции/контейнера не сохраняются.

2. auto (автоматические или локальные), размещаются на стеке (или в регистрах, опять же по прихоти компилятора). Область "видимости" текущая функция, контейнер. При выходе из функции/контейнера не сохраняются.

3. global (глобальные), размещаются на постоянной основе в ОЗУ, в области данных. Область видимости весь текущий модуль. А объявленные с квалификатором extern могут быть "видны" в любом другом модуле проекта.

4. static (статические), размещаются на постоянной основе в ОЗУ, в области данных. Область "видимости" текущая функция (если объявление внутри функции) или текущий модуль (если объявление как глобальной снаружи какой-либо функции). При выходе из функции сохраняются. Но статические переменные не могут быть использованы в других модулях проекта и квалификатор extern к ним неприменим.

В IAR для MSP430 принято, что область данных (глобальных и статических переменных) располагается "снизу" ОЗУ, а стек "сверху" и "растет" ей навстречу. Для того, чтобы хоть как-то контролировать стек в Plain C, вы можете сами организовать "кучу" (HEAP). Для этого создайте большой глобальный массив и располагайте свои временные "массивчики" внутри его. Но для этого нужно будет научиться (если еще не научились) пользоваться указателями, обязательно контролируя выходы их (указателей) за границы выделенных "массивчиков" и глобального массива кучи.

А вообще в map-файле, который можно генерировать с помощью конфигурирования опций IAR, указан размер стека при использовании каждой функции.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В IAR для MSP430 принято, что область данных (глобальных и статических переменных) располагается "снизу" ОЗУ, а стек "сверху" и "растет" ей навстречу. Для того, чтобы хоть как-то контролировать стек в Plain C, вы можете сами организовать "кучу" (HEAP). Для этого создайте большой глобальный массив и располагайте свои временные "массивчики" внутри его. Но для этого нужно будет научиться (если еще не научились) пользоваться указателями, обязательно контролируя выходы их (указателей) за границы выделенных "массивчиков" и глобального массива кучи.

А вообще в map-файле, который можно генерировать с помощью конфигурирования опций IAR, указан размер стека при использовании каждой функции.

Все же пока не ясно :05: Есть массивы, которые объявлены в main, они висят в стеке, потом при вызове какой-нибудь функции, создаются еще локальные - и забивают в этот момент стек. я вижу размер стека, вижу, что заполнен, но как же быть, если массив нужен? Объявить большой глобальный - да, но если не хватит памяти, отведенной под глобальные переменные?

Кстати, в руководстве, которое вы часто поминаете, сказано, что при начальной инициализации, нужно инициализировать указатель стека(указав вершину ОЗУ). Как записывается инициализация SP? :)

Изменено пользователем Daria

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Все же пока не ясно :05: Есть массивы, которые объявлены в main, они висят в стеке, потом при вызове какой-нибудь функции, создаются еще локальные - и забивают в этот момент стек.
Пример из программы можете привести, где по-вашему создаются локальные копии массивов локальных переменных?

я вижу размер стека, вижу, что заполнен, но как же быть, если массив нужен? Объявить большой глобальный - да, но если не хватит памяти, отведенной под глобальные переменные?
Либо вы не совсем аккуратно программируете, либо выбранный кристалл (размер имеющегося у него ОЗУ) не соответствует вашей задаче.

Кстати, в руководстве, которое вы часто поминаете, сказано, что при начальной инициализации, нужно инициализировать указатель стека(указав вершину ОЗУ). Как записывается инициализация SP? :)
Поскольку вы программируете на Си, а не на ассемблере, то задачей инициализации указателя стека и очисткой/инициализацией глобальных и статических переменных, находящихся в сегменте DATA_Z, занимается сам компилятор. Все это делается в процедуре StartUp, которая выполняется ДО вызова функции main. Надеюсь вы в курсе, что main это тоже функция и у нее есть пролог и эпилог, как и у подавляющего большинства других функций? Вот если бы вы писали программу полностью на ASM, то инициализацию указателя стека и инициализацию/очистку глобальных переменных пришлось бы писать тоже вам. Вручную ;)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Либо вы не совсем аккуратно программируете, либо выбранный кристалл (размер имеющегося у него ОЗУ) не соответствует вашей задаче.

Однозначно, первое :) ОЗУ = 2 КВ. Но я поняла, в чем дело - это не стек забивался, а размер stack heap был по умолчанию задан 50 байт. :) Я не тормоз, я медленный газ :biggrin: Но теперь все вроде в порядке.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Опять я :)

Такой вопрос - такое впечатление, что мне может не хватить размера ОЗУ - вычислений оказывается надо делать много, куча массивов данных. Как быть - возможен ли такой вариант - писать что-то (например, массивы ко-тов фильтров) во flash, чтобы они не висели в стеке?

Еще про WDT :) Что, если в программе будет какой-то невыявленный при испытаниях глюк, который выявится уже в процессе использования? Проц зависнет где-нибудь в прерывании... и будет висеть. А WDT это дело предотвратит. Так или не так? :)

Изменено пользователем Daria

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Как быть - возможен ли такой вариант - писать что-то (например, массивы ко-тов фильтров) во flash, чтобы они не висели в стеке?
Возможен. Объявляйте их с квалификатором const. Но при этом они становятся неизменяемыми.

Еще про WDT :) Что, если в программе будет какой-то невыявленный при испытаниях глюк, который выявится уже в процессе использования? Проц зависнет где-нибудь в прерывании... и будет висеть. А WDT это дело предотвратит. Так или не так? :)
Так. Именно для этого его и придумали. Надо лишь Придумать алгоритм его периодического сбрасывания, чтобы он не сбросил вашу штатно работающую программу и чтобы при подвисании одной части он не продолжал успешно сбрасываться в другой.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Такой вопрос. Почему-то не получается объявить фукнцию, работающую с двумерным массивом, размер которого можно бы было передавать как формальный параметр. На function(float а[][]) ругается, а если писать function (float** a), а потом передавать конкретный массив float m[5][5] как function(m), то функция вообще не выполняется, хотя никаких ошибок не пишет : :07: Как это вообще делается? :05:

И еще - есть уравнение четвертой степени ax^4+bx^3+cx^2+dx+e=0

Как бы можно было реализовать его решение, если коэффициенты a,b,c,d,e будут вычислены по данным АЦП? Это вообще возможно на таком кристалле? Ну, есть методы решения уравнений в общем виде - метод деления отрезка пополам, например. Но во-первых, нужно знать область, на которой функция меняет знак, во-вторых искать пределы последовательностей :07: Если вдруг кто-нибудь когда-нибудь делал, подскажите.

А про массив - обязательно подскажите! :biggrin:

Изменено пользователем Daria

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Такой вопрос. Почему-то не получается объявить фукнцию, работающую с двумерным массивом, размер которого можно бы было передавать как формальный параметр. На function(float а[][]) ругается, а если писать function (float** a), а потом передавать конкретный массив float m[5][5] как function(m), то функция вообще не выполняется, хотя никаких ошибок не пишет : :07: Как это вообще делается? :05:
Вы поймите, что многомерные массивы это лишь такая человеческая абстракция. В памяти МК многомерные массивы все равно представляются в виде одномерных участков оперативной памяти.

У вас многомерный массив переменных типа float. Единичным элементом массива является переменная типа float. Так вот и передавайте в функцию указатель на переменную типа float.

Объявление функции

void func (float *ptr);

Вызов функции

func(&a[0][0]);

либо

float *ptr=&a[0][0];
func(ptr);

Если же вы хотите, чтобы в результате выполнения функции передаваемый указатель тоже изменился, только тогда нужно передавать указатель на указатель.

void func (float **pFptr)
{ float *ptr=pFptr;

  ...

  *pFptr=ptr;
}

вызов функции

float *ptr=&a[0][0];
func(&ptr);

Насчет второй части вопроса, увы! не могу подсказать :( Не настолько я силен в математике :laughing:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Начиная с 99 года в С стало возможно описывать массивы с переменной длинной, IAR этот стандарт поддерживает. Кстати, в Фортране подобное было с самого начала, не прошло и полвека. :)

Ниже примеры из текста стандарта ISO/IEC 9899:1999

EXAMPLE 3 The following declarations demonstrate the compatibility rules for variably modified types.
   extern int n;
   extern int m;
   void fcompat(void)
   {
      int  a[n][6][m];
      int  (*p)[4][n+1];
      int  c[n][n][6][m];
      int  (*r)[n][n][n+1];
      p = a; // invalid: not compatible because  4 != 6
      r = c; // compatible, but defined behavior only if
             // n == 6 and m == n+1
   }

EXAMPLE 4 All declarations of variably modified (VM) types have to be at either block scope or
function prototype scope. Array objects declared with the static or extern storage-class specifier
cannot have a variable length array (VLA) type. However, an object declared with the static storageclass
specifier can have a VM type (that is, a pointer to a VLA type). Finally, all identifiers declared with a
VM type have to be ordinary identifiers and cannot, therefore, be members of structures or unions.

   extern int n;
   int A[n];             // invalid: file scope VLA
   extern int (*p2)[n];  // invalid: file scope VM
   int B[100];           // valid: file scope but not VM

   void fvla(int m, int C[m][m]); // valid: VLA with prototype scope

   void fvla(int m, int C[m][m]) // valid: adjusted to auto pointer to VLA
   {
      typedef int VLA[m][m];     // valid: block scope typedef VLA

      struct tag {
         int (*y)[n];     // invalid: y not ordinary identifier
         int z[n];        // invalid: z not ordinary identifier
      };
      int D[m];                  // valid: auto VLA
      static int E[m];           // invalid: static block scope VLA
      extern int F[m];           // invalid: F has linkage and is VLA
      int (*s)[m];               // valid: auto pointer to VLA
      extern int (*r)[m];        // invalid: r has linkage and points to VLA
      static int (*q)[m] = &B;   // valid: q is a static block pointer to VLA
   }

 

Примерно так должно работать (не проверял):

float func( int i; int j; float a[i][j] )
{
   float s = 0.0;
   for( int ii = 0; ii < i; ii++)
      for( int jj = 0; jj < j; jj++)
         s += a[ii][jj];

   return s;
}

float m[5][5];
float mm[25][3];

func( 5, 5, m );
func( sizeof(mm)/sizeof(mm[0]), sizeof(mm[0])/sizeof(mm[0][0]), mm );

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...