Blue Pill 120kb ?

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Предыстория достаточно банальная: прикинул, что нужно для проекта, все проверил на беспаечной макетке, убедился, что работает. Все распаял, напечатал корпус и засунул в него. Теперь: пиши себе софт - не хочу!

Но постепенно запас свободной памяти стал уменьшаться. Был даже курьез: для вывода числа в строку попытался использовать sprintf(). Объем занятой памяти сразу подскочил с 49к до 63к. 63к при доступных 64к и далеком от завершения проекте - это катастрофа! Локально, конечно, проблему я решил, заменив sprintf на короткую функцию объемом в десятки байтов, которая делает ровно то, что мне нужно, и ничего лишнего. И в дальнейшем стал за расходом памяти пристально следить.

Но, чудес не бывает - объем программы на настоящий момент перевалил за 57к. Так что осталось совсем немного. Что делать?

Ну, первое, обратить внимание, естественно, на stm32f103cb. Поиск, однако, показал, что найти плату на 103cb в конструктиве Blue Pill весьма проблематично. Почему-то мне попадались исключительно Maple Mini, которые отличаются от Blue Pill расположением выводов.

Можно, конечно, попытаться переделать существующую плату либо сделать новую. Но геморрой!

Ну и вообще пайка мне как-то удовольствия не доставляет.

В И-нете полно информации, что у обычного 103c8, оказывается не 64, а на самом деле 128к памяти. В принципе, информация правдоподобная, т.к. проще выпускать несколько разных камней по одной маске, ав потом распределять методом отбраковки. Ну а т.к. дешевых камней, как правило, нужно существенно больше, то помимо отбраковки в число дешевых попадают и вполне исправные. Правда - никаких гарантий!

Ну да ладно.

Полей в дэйташит, а именно на стр. 34, где и расположена карта памяти. И вот что любопытно: под область flach там отведено ровно 128к с 0x08000000 по 0x0801ffff. Что, собственно, и следовало ожидать. Но интересно другое: отчет о загрузке явно указывает:

Found Runtime: [0x1eaf:0x0003] devnum=1, cfg=0, intf=0, alt=2, name="STM32duino bootloader v1.0  Upload to Flash 0x8002000"
 
Т.е. загрузка скетча осуществляется не с начала flash'а, а на 8к выше. Но, позвольте! Если мы сдвигаем начало загрузки на 8к, значит, из 64к у нас остается только 56к. Но при этом прошивка объемом 63к помещается и прекрасно работает!
Может, эти 8к входят в число тех примерно 15к, которые "весят" минимальный скетч?
Проверил: - нет, адреса функций и констант при объеме прошивки 19к могут быть и 300 и 18000 выше границы 0x8002000. 
Другими словами, flash выше первых 64к определенно имеется и, более того, надежно работает.
Экспериментально выяснил, что, отсчитывая от 0x8002000, прекрасно читается область объемом 120к. Т.е. те самые пресловутые 128к за вычетом "откушенных" 8к снизу.
При попытке прочесть выше этой границы программа перестает работать. Т.е. совсем. Точнее, управление у нее забирается и передается какой-то другой программе, которая сама по себе мигает светодиодом.
Но не суть.
Подготовил прошивку объемом 122252 байт, что равно 119.4к. Точно подгонять под 120к я поленился. И, как выяснил, все записанное прекрасно (и, главное, - правильно!) читается.
Это на первом попавшемся камне. На других, естественно, нужно проверять.
 
скетч:
// попытка чтения flash выше 0x8002000+0x1e000=0x8020000 приводит к зависанию, до этого читается "255"
//#include "arr44k.c"
#include "arr100k.c"

byte aRAM[8] = {0,1,2,3,4,5,6,7};
const byte aFLASH[8] = {8,9,10,11,12,13,14,15};

int ledState = LOW;             // ledState used to set the LED
unsigned long previousMillis = 0;        // will store last time LED was updated
const long interval = 1000;           // interval at which to blink (milliseconds)

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(115200);
  while(!Serial);
  Serial.print("Setup:  ");
  Serial.print((uint32_t)setup, HEX);
  Serial.print(", ");
  Serial.println((uint32_t)setup - 0x8002000);
  Serial.print("aRAM:   ");
  Serial.print((uint32_t)aRAM, HEX);
  Serial.print(", ");
  Serial.println((uint32_t)aRAM - 0x20000000);
  Serial.print("aFLASH: ");
  Serial.print((uint32_t)aFLASH, HEX);
  Serial.print(", ");
  Serial.println((uint32_t)aFLASH - 0x8002000);
  int n_succ = 0, n_fail = 0;
  uint32_t t0 = millis();
//  for(int i = 0; i < size_arr44k; i++) {
//    if(arr44k[i] == i)
  for(int i = 0; i < size_arr100k; i++) {
    if(arr100k[i] == i)
      n_succ++;
    else
      n_fail++;
  }
  uint32_t t1 = millis();
  Serial.print("Test results: success: ");
  Serial.print(n_succ);
  Serial.print(", fail: ");
  Serial.print(n_fail);
  Serial.print(", elapsed time: ");
  Serial.println(t1-t0);
}

void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
//    ledState = !ledState;
    digitalWrite(LED_BUILTIN, ledState = !ledState);
  }
  if(Serial.available()) {
    char ch = Serial.read();
    if(ch == 'd') {
      int n = Serial.parseInt();
      Serial.println(n, HEX);
      for(int i = 0; i < 16; i++) {
        byte* b = (byte*)(n + i + 0x8002000);
        Serial.print(*b);
        Serial.print(' ');
      }
      Serial.println();
    }
  }
}

в скетче используется включаемый файл с данными (константами) на 100к, который, собственно, и используется для проверки, что читается именно то, что записано. По понятным соображениям весь его приводить я не буду:

const int size_arr100k = 25600;

const int arr100k[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,   //  0.0625 k
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,   //  0.125 k
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,   //  0.1875 k
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,   //  0.25 k
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,   //  0.3125 k
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,   //  0.375 k
96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,   //  0.4375 k
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,   //  0.5 k
128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,   //  0.5625 k
144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,   //  0.625 k
160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,   //  0.6875 k
176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,   //  0.75 k
192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,   //  0.8125 k
208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,   //  0.875 k
224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,   //  0.9375 k
240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255,   //  1 k
256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271,   //  1.0625 k
...

25552, 25553, 25554, 25555, 25556, 25557, 25558, 25559, 25560, 25561, 25562, 25563, 25564, 25565, 25566, 25567,   //  99.875 k
25568, 25569, 25570, 25571, 25572, 25573, 25574, 25575, 25576, 25577, 25578, 25579, 25580, 25581, 25582, 25583,   //  99.9375 k
25584, 25585, 25586, 25587, 25588, 25589, 25590, 25591, 25592, 25593, 25594, 25595, 25596, 25597, 25598, 25599  //  100 k
};

но при желании каждый может создать его сам при помощи следующей функции:

ofstream outf;

// функция для изготовления массива констант для проверки объема памяти stm32f103c8t6
void makeArray(int size, const char * fname) {
    char fn[32];
    strcpy_s(fn, 28, fname);
    strcat_s(fn, 31, ".c");
    outf.open(fn);
    outf << "const int size_" << fname << " = " << (size / sizeof(int)) << ';' << endl << endl;
    outf << "const int " << fname << "[] = {" << endl;
    for (int i = 0; i < (size / sizeof(int)); i++) {
        outf << i;
        if(i != (size / sizeof(int) - 1))
            outf << ", ";
        if ((i % 16) == 15)
            outf << "  //  " << (i+1)*sizeof(int)/1024.0 << " k" << endl;
    }
    outf << "};" << endl;
    outf.close();
}

 

 

b707
Offline
Зарегистрирован: 26.05.2017

Это можно выяснить значительно проще. Когда вы прошиваете в Блюпилл ардуиновский загрузчик - утилита Flash Load Demonstrator сразу пишет, сколько в вашем чипе памяти:

 

В прошлом году все Блюпиллы. что я купил на Али - были 128К. В последнее время все чаще 64к

nik182
Offline
Зарегистрирован: 04.05.2015

Везёт тебе. Мне на пару десятков ни разу 128 не написал.  

slider
Offline
Зарегистрирован: 17.06.2014
-NMi-
Offline
Зарегистрирован: 20.08.2018

andriano пишет:

При попытке прочесть выше этой границы программа перестает работать. Т.е. совсем. Точнее, управление у нее забирается и передается какой-то другой программе, которая сама по себе мигает светодиодом.
Но не суть.

Пральна, этт тибе не дурдуина - куда хачу, туда и "руки сую" - эта, панимашъ, эстЭэмина))))))))))))

Вообще у STM32 есть отдельный вектор на случай "чтения байта (слова) из ниоткуда" , т.о. просто взять "любой" адрес и произвести чтение (запись похоже тоже) НЕЛЬЗЯ!

По поводу зависания: если собирать в "кубе" - он на этот вектор ставит "затычку" вида while(1) .

А ток вообще тема интересная, пейшите исчо))))))))))))))))))))

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

b707 пишет:

Это можно выяснить значительно проще. Когда вы прошиваете в Блюпилл ардуиновский загрузчик - утилита Flash Load Demonstrator сразу пишет, сколько в вашем чипе памяти:

 

В прошлом году все Блюпиллы. что я купил на Али - были 128К. В последнее время все чаще 64к

Ну да, через ST-Link Utillity видно то же самое. Правда, беру два контроллера из одной партии, у одного показывает 128к, другого - 64к, но размещенный выше скетч одинаково показывает наличие по 120к у каждого.

Интересно другое: в Ардуино не может быть BluePill с 64 кбайтами памяти, может быть либо только 56к, либо 120к, т.к. загрузка прошивки осуществляется на 8к выше нижней границы flash. Но что-то мне не попадались массовые жалобы на невозможность прошить в stmduino более 56к.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

-NMi- пишет:

Пральна, этт тибе не дурдуина - куда хачу, туда и "руки сую" - эта, панимашъ, эстЭэмина))))))))))))

Вообще у STM32 есть отдельный вектор на случай "чтения байта (слова) из ниоткуда" , т.о. просто взять "любой" адрес и произвести чтение (запись похоже тоже) НЕЛЬЗЯ!

По поводу зависания: если собирать в "кубе" - он на этот вектор ставит "затычку" вида while(1) .

А ток вообще тема интересная, пейшите исчо))))))))))))))))))))

Лично у меня (как, думаю, у любого, кто хоть что-то читал про защищенный режим Intel386+) такое поведение камня удивления не вызывает. Просто отметил как факт.

А где собирался загрузчик для stmduino, я не знаю. Но если бы было просто while(1), светодиод вряд ли бы мигал. Впрочем, зависит от того, что внутри этого самого while.