Уменьшение размера программирования функций
У меня есть код Arduino, который использует библиотеку I2CDev для управления MPU-6050. Я новичок в кодировании и скопировал и вставил большую часть кода из примеров, которые нашел. У меня начинает заканчиваться место для программирования на моем Arduino, и я обнаружил, что одна строка кода занимает 21%, или 6000 байт памяти программирования. Я нашел функцию, к которой относилась эта строка, и показал ее ниже.
Ссылку на библиотеку I2CDev можно также найти на Github здесь: https://github.com/jrowberg/i2cdevlib
Есть ли способ уменьшить его? Может кто-нибудь объяснить мне, почему он занимает так много места? Спасибо!
uint8_t MPU6050::dmpInitialize() {
// сброс устройства
DEBUG_PRINTLN(F("\n\nResetting MPU6050..."));
reset();
delay(30); // ждем после сброса
// включить режим сна и цикл пробуждения
/*Serial.println(F("Enabling sleep mode..."));
setSleepEnabled(true);
Serial.println(F("Enabling wake cycle..."));
setWakeCycleEnabled(true);*/
// отключить спящий режим
DEBUG_PRINTLN(F("Disabling sleep mode..."));
setSleepEnabled(false);
// получить аппаратную версию MPU
DEBUG_PRINTLN(F("Selecting user bank 16..."));
setMemoryBank(0x10, true, true);
DEBUG_PRINTLN(F("Selecting memory byte 6..."));
setMemoryStartAddress(0x06);
DEBUG_PRINTLN(F("Checking hardware revision..."));
DEBUG_PRINT(F("Revision @ user[16][6] = "));
DEBUG_PRINTLNF(readMemoryByte(), HEX);
DEBUG_PRINTLN(F("Resetting memory bank selection to 0..."));
setMemoryBank(0, false, false);
// проверка OTP банка на действительность
DEBUG_PRINTLN(F("Reading OTP bank valid flag..."));
DEBUG_PRINT(F("OTP bank is "));
DEBUG_PRINTLN(getOTPBankValid() ? F("valid!") : F("invalid!"));
// получить смещения гироскопа X/Y/Z
DEBUG_PRINTLN(F("Reading gyro offset TC values..."));
int8_t xgOffsetTC = getXGyroOffsetTC();
int8_t ygOffsetTC = getYGyroOffsetTC();
int8_t zgOffsetTC = getZGyroOffsetTC();
DEBUG_PRINT(F("X gyro offset = "));
DEBUG_PRINTLN(xgOffsetTC);
DEBUG_PRINT(F("Y gyro offset = "));
DEBUG_PRINTLN(ygOffsetTC);
DEBUG_PRINT(F("Z gyro offset = "));
DEBUG_PRINTLN(zgOffsetTC);
// настройка странных рабских штучек (?)
DEBUG_PRINTLN(F("Setting slave 0 address to 0x7F..."));
setSlaveAddress(0, 0x7F);
DEBUG_PRINTLN(F("Disabling I2C Master mode..."));
setI2CMasterModeEnabled(false);
DEBUG_PRINTLN(F("Setting slave 0 address to 0x68 (self)..."));
setSlaveAddress(0, 0x68);
DEBUG_PRINTLN(F("Resetting I2C Master control..."));
resetI2CMaster();
delay(20);
// загрузить код DMP в банки памяти
DEBUG_PRINT(F("Writing DMP code to MPU memory banks ("));
DEBUG_PRINT(MPU6050_DMP_CODE_SIZE);
DEBUG_PRINTLN(F(" bytes)"));
if (writeProgMemoryBlock(dmpMemory, MPU6050_DMP_CODE_SIZE)) {
DEBUG_PRINTLN(F("Success! DMP code written and verified."));
// запись конфигурации DMP
DEBUG_PRINT(F("Writing DMP configuration to MPU memory banks ("));
DEBUG_PRINT(MPU6050_DMP_CONFIG_SIZE);
DEBUG_PRINTLN(F(" bytes in config def)"));
if (writeProgDMPConfigurationSet(dmpConfig, MPU6050_DMP_CONFIG_SIZE)) {
DEBUG_PRINTLN(F("Success! DMP configuration written and verified."));
DEBUG_PRINTLN(F("Setting clock source to Z Gyro..."));
setClockSource(MPU6050_CLOCK_PLL_ZGYRO);
DEBUG_PRINTLN(F("Setting DMP and FIFO_OFLOW interrupts enabled..."));
setIntEnabled(0x12);
DEBUG_PRINTLN(F("Setting sample rate to 200Hz..."));
setRate(4); // 1 кГц/(1 + 4) = 200 Гц
DEBUG_PRINTLN(F("Setting external frame sync to TEMP_OUT_L[0]..."));
setExternalFrameSync(MPU6050_EXT_SYNC_TEMP_OUT_L);
DEBUG_PRINTLN(F("Setting DLPF bandwidth to 42Hz..."));
setDLPFMode(MPU6050_DLPF_BW_42);
DEBUG_PRINTLN(F("Setting gyro sensitivity to +/- 2000 deg/sec..."));
setFullScaleGyroRange(MPU6050_GYRO_FS_2000);
DEBUG_PRINTLN(F("Setting DMP programm start address"));
//записать начальный адрес MSB в регистр
setDMPConfig1(0x03);
//записать начальный адрес LSB в регистр
setDMPConfig2(0x00);
DEBUG_PRINTLN(F("Clearing OTP Bank flag..."));
setOTPBankValid(false);
DEBUG_PRINTLN(F("Setting X/Y/Z gyro offset TCs to previous values..."));
setXGyroOffsetTC(xgOffsetTC);
setYGyroOffsetTC(ygOffsetTC);
setZGyroOffsetTC(zgOffsetTC);
DEBUG_PRINTLN(F("Setting X/Y/Z gyro user offsets to zero..."));
//setXGyroOffset(0);
//setYGyroOffset(0);
//setZGyroOffset(0);
DEBUG_PRINTLN(F("Writing final memory update 1/7 (function unknown)..."));
uint8_t dmpUpdate[16], j;
uint16_t pos = 0;
for (j = 0; j < 4 || j < dmpUpdate[2] + 3; j++, pos++) dmpUpdate[j] = pgm_read_byte(&dmpUpdates[pos]);
writeMemoryBlock(dmpUpdate + 3, dmpUpdate[2], dmpUpdate[0], dmpUpdate[1]);
DEBUG_PRINTLN(F("Writing final memory update 2/7 (function unknown)..."));
for (j = 0; j < 4 || j < dmpUpdate[2] + 3; j++, pos++) dmpUpdate[j] = pgm_read_byte(&dmpUpdates[pos]);
writeMemoryBlock(dmpUpdate + 3, dmpUpdate[2], dmpUpdate[0], dmpUpdate[1]);
DEBUG_PRINTLN(F("Resetting FIFO..."));
resetFIFO();
DEBUG_PRINTLN(F("Reading FIFO count..."));
uint16_t fifoCount = getFIFOCount();
uint8_t fifoBuffer[128];
DEBUG_PRINT(F("Current FIFO count="));
DEBUG_PRINTLN(fifoCount);
getFIFOBytes(fifoBuffer, fifoCount);
DEBUG_PRINTLN(F("Setting motion detection threshold to 2..."));
setMotionDetectionThreshold(2);
DEBUG_PRINTLN(F("Setting zero-motion detection threshold to 156..."));
setZeroMotionDetectionThreshold(156);
DEBUG_PRINTLN(F("Setting motion detection duration to 80..."));
setMotionDetectionDuration(80);
DEBUG_PRINTLN(F("Setting zero-motion detection duration to 0..."));
setZeroMotionDetectionDuration(0);
DEBUG_PRINTLN(F("Resetting FIFO..."));
resetFIFO();
DEBUG_PRINTLN(F("Enabling FIFO..."));
setFIFOEnabled(true);
DEBUG_PRINTLN(F("Enabling DMP..."));
setDMPEnabled(true);
DEBUG_PRINTLN(F("Resetting DMP..."));
resetDMP();
DEBUG_PRINTLN(F("Writing final memory update 3/7 (function unknown)..."));
for (j = 0; j < 4 || j < dmpUpdate[2] + 3; j++, pos++) dmpUpdate[j] = pgm_read_byte(&dmpUpdates[pos]);
writeMemoryBlock(dmpUpdate + 3, dmpUpdate[2], dmpUpdate[0], dmpUpdate[1]);
DEBUG_PRINTLN(F("Writing final memory update 4/7 (function unknown)..."));
for (j = 0; j < 4 || j < dmpUpdate[2] + 3; j++, pos++) dmpUpdate[j] = pgm_read_byte(&dmpUpdates[pos]);
writeMemoryBlock(dmpUpdate + 3, dmpUpdate[2], dmpUpdate[0], dmpUpdate[1]);
DEBUG_PRINTLN(F("Writing final memory update 5/7 (function unknown)..."));
for (j = 0; j < 4 || j < dmpUpdate[2] + 3; j++, pos++) dmpUpdate[j] = pgm_read_byte(&dmpUpdates[pos]);
writeMemoryBlock(dmpUpdate + 3, dmpUpdate[2], dmpUpdate[0], dmpUpdate[1]);
DEBUG_PRINTLN(F("Waiting for FIFO count > 2..."));
while ((fifoCount = getFIFOCount()) < 3);
DEBUG_PRINT(F("Current FIFO count="));
DEBUG_PRINTLN(fifoCount);
DEBUG_PRINTLN(F("Reading FIFO data..."));
getFIFOBytes(fifoBuffer, fifoCount);
DEBUG_PRINTLN(F("Reading interrupt status..."));
DEBUG_PRINT(F("Current interrupt status="));
DEBUG_PRINTLNF(getIntStatus(), HEX);
DEBUG_PRINTLN(F("Reading final memory update 6/7 (function unknown)..."));
for (j = 0; j < 4 || j < dmpUpdate[2] + 3; j++, pos++) dmpUpdate[j] = pgm_read_byte(&dmpUpdates[pos]);
readMemoryBlock(dmpUpdate + 3, dmpUpdate[2], dmpUpdate[0], dmpUpdate[1]);
DEBUG_PRINTLN(F("Waiting for FIFO count > 2..."));
while ((fifoCount = getFIFOCount()) < 3);
DEBUG_PRINT(F("Current FIFO count="));
DEBUG_PRINTLN(fifoCount);
DEBUG_PRINTLN(F("Reading FIFO data..."));
getFIFOBytes(fifoBuffer, fifoCount);
DEBUG_PRINTLN(F("Reading interrupt status..."));
DEBUG_PRINT(F("Current interrupt status="));
DEBUG_PRINTLNF(getIntStatus(), HEX);
DEBUG_PRINTLN(F("Writing final memory update 7/7 (function unknown)..."));
for (j = 0; j < 4 || j < dmpUpdate[2] + 3; j++, pos++) dmpUpdate[j] = pgm_read_byte(&dmpUpdates[pos]);
writeMemoryBlock(dmpUpdate + 3, dmpUpdate[2], dmpUpdate[0], dmpUpdate[1]);
DEBUG_PRINTLN(F("DMP is good to go! Finally."));
DEBUG_PRINTLN(F("Disabling DMP (you turn it on later)..."));
setDMPEnabled(false);
DEBUG_PRINTLN(F("Setting up internal 42-byte (default) DMP packet buffer..."));
dmpPacketSize = 42;
/*if ((dmpPacketBuffer = (uint8_t *)malloc(42)) == 0) {
return 3; // TODO: правильный код ошибки при отсутствии памяти
}*/
DEBUG_PRINTLN(F("Resetting FIFO and clearing INT status one last time..."));
resetFIFO();
getIntStatus();
} else {
DEBUG_PRINTLN(F("ERROR! DMP configuration verification failed."));
return 2; // загрузка блока конфигурации не удалась
}
} else {
DEBUG_PRINTLN(F("ERROR! DMP code verification failed."));
return 1; // загрузка основного двоичного блока не удалась
}
return 0; // успех
}
@M.Schindler, 👍0
Обсуждение1 ответ
Лучший ответ:
Одна строка кода не использует 6000 байт памяти. Однако если она вызывает функцию, которая в противном случае не была бы вызвана, то компилятор должен включить функцию.
Так, например, если у вас есть функция, которая занимает 6000 байт, но вы ее не вызываете, то компилятор может пропустить саму функцию.
Предположим, что DEBUG_PRINTLN что-то делает, тогда я насчитаю там 2480 байт строковых литералов. Следовательно, ваша функция займет как минимум 2480 байт. И это вызывается 71 раз, так что если DEBUG_PRINTLN занимает (скажем) 10 байт для вызова каждый раз, это еще 710 байт. Мы уже достигли 3190 байт. Другие вещи (не связанные с отладкой) также, вероятно, занимают довольно много байт.
У меня начинает заканчиваться место для программирования на моем Arduino
Это не проблема, пока у вас фактически не закончится место. Кого волнует, что вы используете 99% доступной памяти?
Тот факт, что что-то вызывает скачок в использовании памяти, сам по себе не является причиной для беспокойства. Например, этот набросок:
void setup() {
Serial.begin(115200);
int a;
Serial.println (a);
}
void loop() { }
Скомпилировал для Uno с использованием IDE 1.6.9 и получил:
Sketch uses 2,122 bytes (6%) of program storage space. Maximum is 32,256 bytes.
Итак, 2122 байта. Теперь измените a
на float:
void setup() {
Serial.begin(115200);
float a;
Serial.println (a);
}
void loop() { }
Теперь он использует 3668 байт:
Sketch uses 3,668 bytes (11%) of program storage space. Maximum is 32,256 bytes. That's another 1,546 bytes just by changing one variable's type.
Однако, если вы добавите вторую такую переменную, это не займет еще 1546 байт.
void setup() {
Serial.begin(115200);
float a;
float b;
Serial.println (a);
Serial.println (b);
}
void loop() { }
Это использует всего лишь еще 18 байт:
Sketch uses 3,686 bytes (11%) of program storage space. Maximum is 32,256 bytes.
Другими словами, библиотека с плавающей точкой теперь включена компилятором. Это единовременный скачок в использовании. Конечно, если я сейчас что-то сделаю с I2C, произойдет еще один скачок, поскольку будет загружена эта дополнительная библиотека.
Да, извините за недоразумение. Единственная строка была в коде arduino. Затем я открыл функцию, на которую ссылалась эта строка, и вставил ее выше. Мой вопрос: что в этой функции занимает так много места?, @M.Schindler
Что в **какой** функции? Можете, пожалуйста, быть более четким?, @Nick Gammon
Что делает DEBUG_PRINTLN? Постарайтесь разместить достаточно информации, чтобы мы могли ответить на ваш вопрос., @Nick Gammon
См. мой измененный ответ., @Nick Gammon
Вы могли бы сэкономить **много** памяти, заменив эти довольно многословные отладочные сообщения чем-то вроде DEBUG_PRINTLN(F("1"))
(а затем 2 и так далее) и иметь электронную таблицу, которая скажет вам, что означает каждое из них. Вы работаете на микроконтроллере, а не на ПК с 20 гигабайтами оперативной памяти., @Nick Gammon
Поэтому я попробовал удалить строки DEBUG_PRINT, и это вообще не изменило размер кода. Нужно ли включать DEBUG_PRINT где-то еще в коде, чтобы он работал?, @M.Schindler
Было бы полезно показать код/макрос для DEBUG_PRINT, чтобы можно было ответить на этот вопрос. Вполне возможно, что это макрос, который ничего не делает, пока что-то (вроде DEBUG
) не определено., @Nick Gammon
См. измененный ответ о том, что код библиотеки необходимо включить только один раз., @Nick Gammon
- Как подключить MPU9250 к NodeMCU с помощью SPI или I2C Slave?
- Изменение адреса I2C MPU-6050
- MPU6050 не выдает выход
- MPU-9250 IMU на SPI, внешнем датчике или магнитометре с использованием мастера I2C
- Использование MPU-6050 без I2C
- Почему Wire.write дважды?
- Сбой при записи данных MPU-6050 на SD-карту
- Мультиплексор Adafruit MPU-6050 и adafruit I2C
Какая линия? Поставьте на нее маркер и ссылайтесь на нее в своем вопросе., @Nick Gammon
Многие строки PLINTLN не очень полезны. Большинство из них — просто комментарии. Удаление их или преобразование в обычные комментарии уменьшило бы размер., @Gerben
Не существует волшебного рецепта для уменьшения размера кода. Единственное общее правило: «удали все, что не является строго необходимым», но вы не сможете использовать это правило, если вы действительно не понимаете, что делает программа. Тем не менее, вы можете начать с того, чтобы посмотреть, какие функции занимают больше всего места. Cf [Определение того, какой раздел кода использует больше всего флэш-памяти](https://arduinoprosto.ru/q/12684)., @Edgar Bonet
Я знаю, что вы новичок в кодировании... Мне просто интересно, почему вам не пришло в голову удалить команды
DEBUG_PRINTLN(
, @jsotola@jsotola, это было первое, что я попробовал, но это вообще не изменило размер кода., @M.Schindler
Неважно, используете ли вы 90% памяти вашей программы, при условии, что ваш код делает все, что вы хотите. Действительно ли у вас может закончиться память программы?, @Nick Gammon