Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Функции требующие статической памяти
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Операционные системы > Программирование
yanvasiij
Доброго времени суток!

Столкнулся с тем, что не хватает памяти на микроконтроллере. Начал копать и выяснил, что больше всего памяти потребляет вызов функции, которая у меня занимается вычислениями по калибровочным таблицам (кусочно-линейная аппроксимация). Поскольку мое устройство должно поддерживать большое количество датчиков, вызов этой функции осуществляется из разных мест программы. Добавления каждого нового вызова этой функции вызывает у меня увеличение потребления статической памяти. Я долго думал можно ли с этим что либо поделать, но так и не придумал. Ниже привожу примеры использования.\

Собственно сами функции:
CODE

float plaStraight (const float *calibrationTable, float delta, float minValue,
float maxValue, float inValue)
{
int i;
float outValue = minValue;
if (inValue > calibrationTable[i = 0])
while (maxValue >= outValue)
{
if (inValue < calibrationTable[++i])
return outValue + (inValue - calibrationTable[i-1]) * delta
/ (calibrationTable[i] - calibrationTable[i-1]);
outValue += delta;
};
return outValue;
}

float plaStraight (const float *calibrationTable, float delta, float minValue,
float maxValue, float inValue)
{
int i;
float outValue = minValue;
if (inValue > calibrationTable[i = 0])
while (maxValue >= outValue)
{
if (inValue < calibrationTable[++i])
return outValue + (inValue - calibrationTable[i-1]) * delta
/ (calibrationTable[i] - calibrationTable[i-1]);
outValue += delta;
};
return outValue;
}

float plaRevers (const float *calibrationTable, u32 len, float reversDelta,
float minValue, float inValue)
{
float outValue = calibrationTable[len - 1];
float inValue0 = minValue;
float straightDelta;
int i = 0;

outValue = calibrationTable[len - 1];
inValue0 = minValue;

if ( inValue > inValue0 )
{
while ( calibrationTable[len-1] >= outValue )
{
i++;
if ( inValue < (inValue0 + reversDelta) )
{
straightDelta = calibrationTable[i] - calibrationTable[i-1];
outValue = calibrationTable[i-1] +
((inValue - inValue0) * straightDelta / reversDelta);
return outValue;
}
outValue = calibrationTable[i];
inValue += reversDelta;
}
outValue = calibrationTable[len-1];
}
return outValue;
}



Пример класса, в котором используются эти функции

Код
class TermocoupleSProcessor: public TermocoupleProcessorBase
{
    public:

    virtual float calcTemperature (float eds)
        {
        return plaStraight (typeSCalibrationTable, 10.0, -50.0f, 1760.0f, eds); //<<<Добавления этой строчки приводит к большому выделению памяти
        }

    virtual float calcEds (float t)
        {
          return plaRevers(typeSCalibrationTable, CALIBRATION_TABLE_LEN, 10.0f, -50.0f, t);//<<<Добавления этой строчки приводит к большому выделению памяти
        }
        

    virtual void init (void)
    {
        sensorType = TermocoupleS;
        conversationIsReady = 0;
    }
};


Объекты я объявляю статически. Для каждого типа термопары у меня по два объекта соответствующего класса. Добавления вызова plaStraight и plaStraight в каждом подобном классе приводит к резкому возрастанию выделения статической памяти. В итоге у меня ее просто не хватает. Что можно с этим поделать, есть идеи?

megajohn
Цитата(yanvasiij @ Feb 24 2016, 08:01) *
Начал копать и выяснил, что больше всего памяти потребляет вызов функции
Добавления каждого нового вызова этой функции вызывает у меня увеличение потребления статической памяти


б-р-р-р, вы путаете понятия.
Каждый вызов функции увеличивает потребление стека. Но по выходу из функции размер стека возвращается к значению до вызова. Рекурсий у вас тут не видно

Цитата(yanvasiij @ Feb 24 2016, 08:01) *
Для каждого типа термопары у меня по два объекта соответствующего класса.


попробовать typeSCalibrationTable сделать как static const
yanvasiij
Цитата(megajohn @ Feb 24 2016, 10:46) *
б-р-р-р, каждый вызов функции увеличивает потребление стека. Но по выходу из функции размер стека возвращается к значению до вызова. Рекурсий у вас тут не видно



попробовать typeSCalibrationTable сделать как static const


Нет, в том то и дело, что работа со стеком это динамика, статически выделяемая память при компиляции тут не при чем (точнее она при чем только при указании размера стека). Я не спорю с тем фактом, что увеличением вызовов увеличит потребление стека, это я понимаю. Проблема в том, что у меня увеличивается объем выделенной статической памяти, на этапе компиляции (секция ZI-data), при увеличении точек входа в эту злосчастную функцию в программе.

typeSCalibrationTable уже как static const, я забыл это упомянуть.
AHTOXA
Цитата(yanvasiij @ Feb 24 2016, 10:59) *
typeSCalibrationTable уже как static const, я забыл это упомянуть.

Покажите определение. Скорее всего не хватает ещё одного const.
yanvasiij
Цитата(AHTOXA @ Feb 24 2016, 14:07) *
Покажите определение. Скорее всего не хватает ещё одного const.


Код
static const float typeSCalibrationTable[] = {
-0.226, -0.188, -0.145, -0.1, -0.051, 0, 0.054, 0.111, 0.171, 0.232, 0.296, 0.363,
... много много значений ...
};
shreck
А проц какой? Не AVR ли часом. Для него одного const мало. Надо еще __flash добавлять. Вроде так раньше было.
yanvasiij
Цитата(shreck @ Feb 24 2016, 16:59) *
А проц какой? Не AVR ли часом. Для него одного const мало. Надо еще __flash добавлять. Вроде так раньше было.


stm32f042
AHTOXA
А компилятор какой?
megajohn
Цитата(AHTOXA @ Feb 24 2016, 15:30) *
А компилятор какой?


по слову ZI-data определяется что это Keil
автор, попробуйте массив вынести из класса и подепить его через конструктор или Extern
yanvasiij
Цитата(megajohn @ Feb 24 2016, 17:44) *
по слову ZI-data определяется что это Keil
автор, попробуйте массив вынести из класса и подепить его через конструктор или Extern


Да компилятор keil.
Моя вина - не сказал. Так и было с самого начала, в классе лишь указатель на этот массив.
SSerge
Цитата(yanvasiij @ Feb 24 2016, 18:35) *
Код
static const float typeSCalibrationTable[] = {
-0.226, -0.188, -0.145, -0.1, -0.051, 0, 0.054, 0.111, 0.171, 0.232, 0.296, 0.363,
... много много значений ...
};

const в плюсах делает Ваш массив локальным в пределах единицы компиляции, так что static было писать не обязательно.
В результате в каждом .с файле, где этот массив используется появляется ещё одна его копия.

Если нужны константные данные, но доступные из разных файлов, объявляйте их как extern const, такая константа будет глобальной в проекте.
yanvasiij
Цитата(SSerge @ Feb 24 2016, 22:54) *
const в плюсах делает Ваш массив локальным в пределах единицы компиляции, так что static было писать не обязательно.
В результате в каждом .с файле, где этот массив используется появляется ещё одна его копия.

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


Спасибо, теперь буду знать. Но я использую указатель на этот массив, разве это должно приводить к такому значительному увеличению потребления статически выделенной оперативной памяти?
megajohn
Цитата(yanvasiij @ Feb 24 2016, 08:59) *
при увеличении точек входа в эту злосчастную функцию в программе.


как обход этой проблемы, могу предложить решение в лоб - сделать одну точку входа.
При RTOS это делается через очередь
yanvasiij
Цитата(megajohn @ Feb 26 2016, 01:21) *
как обход этой проблемы, могу предложить решение в лоб - сделать одну точку входа.
При RTOS это делается через очередь


Ну да, похоже придется так и сделать. Не очень красивый способ, как мне кажется, но когда я переделал таким образом потребление памяти уменьшилось в разы. У меня кстати нет ртос в этом проекте, слишком мало памяти у проца и слишком много всего надо впихнуть.
SSerge
Цитата(yanvasiij @ Feb 25 2016, 12:04) *
Спасибо, теперь буду знать. Но я использую указатель на этот массив, разве это должно приводить к такому значительному увеличению потребления статически выделенной оперативной памяти?

Если Вы используете в своей программе имя массива (которое является указателем на его первый элемент), то где-то должен существовать и сам массив, иначе получите ошибку при компиляции.
Если массив определяется в этом-же файле, то всё хорошо. Если массив в другом файле, компилятору нужно сообщить о его существовании и о его типе:
extern const float typeSCalibrationTable[];
чтобы компилятор знал что такой массив существует, но где-то высоко в горах, не в нашем файле.

Судя по тому, что у Вас сообщений об ошибках при компиляции нет, тут ситуация такая:
Вы скорее всего поместили объявление массива в .h файл и включаете его во все компилируемые .c файлы с помощью #include.
Но тогда получается что в каждом компилируемом файле появляется свой массив по имени typeSCalibrationTable, но он локальный, виден только в пределах .c файла, в другом .с файле тоже будет такой-же массив, тоже локальный в пределах своего файла.
Всё работает как надо, но массивы плодятся как кролики.

Как исправить:
Определите массив только в одном .c файле. Для С++ нужно писать
extern const float typeSCalibrationTable[]={ .... };
Для просто С можно без extern, в С массив и так будет глобальным ( а static как раз сделает его локальным со всеми вышеописанными проблемами).

Во всех остальных файлах помещаете описание, его можно поместить в подходящий .h или прямо в .с писать:
extern const float typeSCalibrationTable[];

Но это С-стиль, а в С++ можно сделать этот массив статическим членом подходящего класса и обращаться к нему как имя_класса::typeSCalibrationTable.
yanvasiij
Цитата(SSerge @ Feb 26 2016, 14:04) *
Если Вы используете в своей программе имя массива ...


Так и было сделано, typeSCalibrationTable[]={ .... } и подобные ему массивы объявлены в отдельных *.c файлах, внутри класса TermocoupleSProcessor используются лишь указатель на этот массив.


Код
extern const float *tcoupleScalibrationTable; //Таблица объявлена, где-то в другом месте

class TermocoupleProcessorBase : public BarrierSensorProcessorBase
{

    public:

...
    float const *tCoupleParams; /**< @brief Внутри класса лишь указатель на массив */
...

...
      //В некотором месте программы происходит назначение этого указателя
      tCoupleParams = tcoupleScalibrationTable;
...
};
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.