Jump to content

    

Cortex-M3 от ST

Добрый день.

Требуется программно определять размер страницы флеш-памяти у Cortex-M3 процессоров от ST, в частности у семейства STM32F103.

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

Share this post


Link to post
Share on other sites

Насколько я понимаю, по содержимому DBGMCU_IDCODE и F_SIZE можно однозначно определить модель МК, а значит и все его характеристики.

А если совсем уж эмпирически, то записать данные в флэш, стереть сектор и посмотреть, сколько стёрлось.

Share this post


Link to post
Share on other sites
Насколько я понимаю, по содержимому DBGMCU_IDCODE и F_SIZE можно однозначно определить модель МК, а значит и все его характеристики.

А если совсем уж эмпирически, то записать данные в флэш, стереть сектор и посмотреть, сколько стёрлось.

Да, DBGMCU_IDCODE и F_SIZE мне будет достаточно. Спасибо.

Share this post


Link to post
Share on other sites

Оп-па.

Из errat'ы.

The DBGMCU_IDCODE and DBGMCU_CR debug registers are accessible only in debug

mode (not accessible by the user software). When these registers are read in user mode,

the returned value is 0x00.

 

Вопрос остается в силе. Как можно узнать размер страницы памяти, кроме как записать/стереть/посмотреть, что получилось.

Share this post


Link to post
Share on other sites
Оп-па.

Из errat'ы.

The DBGMCU_IDCODE and DBGMCU_CR debug registers are accessible only in debug

Такое верно для 101/102/103. В 100 идентификатор читается нормально, 105/107 вроде бы тоже (на практике не пробовал).

 

Вопрос остается в силе. Как можно узнать размер страницы памяти, кроме как записать/стереть/посмотреть, что получилось.

 

Есть еще ячейка служебной флеши по адресу 0x1FFFF7E0 (документирована даже - 30-ый раздел "Reference Manual"-а) - там размер флеша указан (если производитель при прошивке своей служебки ненакосячил).

Ну а полностью узнать какой процессор можно так:

static DWORD hal_stm32_id(void)
{
   DWORD fsize, clken, lock;

   lock = hal_lock_interrupt();
   {
       DWORD save;
       //
       // Выполняем распознавание 101/102/103 по тактируемым блокам
       // Кратковременно разрешаем тактирование USB и CAN,
       //
       save = RCC_APB1EN;
       RCC_APB1EN  =   save
                     | bRCC_CAN2EN
                     | bRCC_CAN1EN
                     | bRCC_USBEN;
       clken = RCC_APB1EN;
       //
       // Восстанавливаем исходное состояние тактирования
       //
       RCC_APB1EN   = save;
   }
   hal_unlock_interrupt(lock);

   if ((clken & bRCC_USBEN) == 0)
   {
       //
       // STM32F101xx - так как нет контроллера USB FS
       //
       clken = 101;
   }
   else
   {
       if ((clken & bRCC_CAN1EN) == 0)
       {
           //
           // STM32F102xx - так как нет контроллера CAN
           //
           clken = 102;
       }
       else
       {
           //
           // Это STM32F103 - так как есть и USB FS и CAN
           //
           clken = 103;
       }
   }

   fsize = SYSMEM_FSIZE & 0x0000FFFF;
   switch(DBGMCU_IDCODE & STM32_ID_MASK)
   {
       //
       // Процессоры 101/102/103 - 468BCDE имеют
       // недоступными регистр IDCODE в рабочем
       // режиме - читаются нули (см errata)
       //
       case STM32_ID_000:
       {
           switch(clken)
           {
               case 101:
               {
                   switch(fsize)
                   {
                       case 16:    return STM32F101x4_ID;
                       case 32:    return STM32F101x6_ID;
                       case 64:    return STM32F101x8_ID;
                       case 128:   return STM32F101xB_ID;
                       case 256:   return STM32F101xC_ID;
                       case 384:   return STM32F101xD_ID;
                       case 512:   return STM32F101xE_ID;
                   }
                   break;
               }
               case 102:
               {
                   switch(fsize)
                   {
                       case 16:    return STM32F102x4_ID;
                       case 32:    return STM32F102x6_ID;
                       case 64:    return STM32F102x8_ID;
                       case 128:   return STM32F102xB_ID;
                   }
                   break;
               }
               case 103:
               {
                   switch(fsize)
                   {
                       case 16:    return STM32F103x4_ID;
                       case 32:    return STM32F103x6_ID;
                       case 64:    return STM32F103x8_ID;
                       case 128:   return STM32F103xB_ID;
                       case 256:   return STM32F103xC_ID;
                       case 384:   return STM32F103xD_ID;
                       case 512:   return STM32F103xE_ID;
                   }
                   break;
               }
           }
           break;
       }
       case STM32_ID_420:
       {
           //
           // STM32F100-468B
           //
           switch(fsize)
           {
               case 16:    return STM32F100x4_ID;
               case 32:    return STM32F100x6_ID;
               case 64:    return STM32F100x8_ID;
               case 128:   return STM32F100xB_ID;
           }
           break;
       }
       case STM32_ID_428:
       {
           //
           // STM32F100-CDE
           //
           switch(fsize)
           {
               case 256:   return STM32F100xC_ID;
               case 384:   return STM32F100xD_ID;
               case 512:   return STM32F100xE_ID;
           }
           break;
       }
       case STM32_ID_410:
       {
           //
           // STM32F10x-8B
           //
           switch(clken)
           {
               case 101:
               {
                   switch(fsize)
                   {
                       case 64:    return STM32F101x8_ID;
                       case 128:   return STM32F101xB_ID;
                   }
                   break;
               }
               case 102:
               {
                   switch(fsize)
                   {
                       case 64:    return STM32F102x8_ID;
                       case 128:   return STM32F102xB_ID;
                   }
                   break;
               }
               case 103:
               {
                   switch(fsize)
                   {
                       case 64:    return STM32F103x8_ID;
                       case 128:   return STM32F103xB_ID;
                   }
                   break;
               }
           }
           break;
       }
       case STM32_ID_412:
       {
           //
           // STM32F10x-46
           //
           switch(clken)
           {
               case 101:
               {
                   switch(fsize)
                   {
                       case 16:    return STM32F101x4_ID;
                       case 32:    return STM32F101x6_ID;
                   }
                   break;
               }
               case 102:
               {
                   switch(fsize)
                   {
                       case 16:    return STM32F102x4_ID;
                       case 32:    return STM32F102x6_ID;
                   }
                   break;
               }
               case 103:
               {
                   switch(fsize)
                   {
                       case 16:    return STM32F103x4_ID;
                       case 32:    return STM32F103x6_ID;
                   }
                   break;
               }
           }
           break;
       }
       case STM32_ID_414:
       {
           //
           // STM32F10x-CDE
           //
           switch(clken)
           {
               case 101:
               {
                   switch(fsize)
                   {
                       case 256:   return STM32F101xC_ID;
                       case 384:   return STM32F101xD_ID;
                       case 512:   return STM32F101xE_ID;
                   }
                   break;
               }
               case 103:
               {
                   switch(fsize)
                   {
                       case 256:   return STM32F103xC_ID;
                       case 384:   return STM32F103xD_ID;
                       case 512:   return STM32F103xE_ID;
                   }
                   break;
               }
           }
           break;
       }
       case STM32_ID_430:
       {
           //
           // STM32F10x-FG
           //
           switch(clken)
           {
               case 101:
               {
                   switch(fsize)
                   {
                       case 768:   return STM32F101xF_ID;
                       case 1024:  return STM32F101xG_ID;
                   }
                   break;
               }
               case 103:
               {
                   switch(fsize)
                   {
                       case 768:   return STM32F103xF_ID;
                       case 1024:  return STM32F103xG_ID;
                   }
                   break;
               }
           }
           break;
       }
       case STM32_ID_418:
       {
           //
           // STM32F105/107 отличаем по блоку Ethernet
           //
           lock = hal_lock_interrupt();
           {
               DWORD save;

               save = RCC_AHBEN;
               RCC_AHBEN =   save
                           | bRCC_ETHMACEN;
               clken = RCC_AHBEN;
               //
               // Восстанавливаем исходное состояние тактирования
               //
               RCC_AHBEN = save;
           }
           hal_unlock_interrupt(lock);

           if (clken & bRCC_ETHMACEN)
           {
               switch(fsize)
               {
                   case 128:   return STM32F107xB_ID;
                   case 256:   return STM32F107xC_ID;
               }
           }
           else
           {
               switch(fsize)
               {
                   case 64:    return STM32F105x8_ID;
                   case 128:   return STM32F105xB_ID;
                   case 256:   return STM32F105xC_ID;
               }
           }
           break;
       }
       case STM32_ID_411:      // F20x/F21x
       case STM32_ID_413:      // F40x/F41x
       {
           //
           // Эти серии в рамках этой функции не поддерживаются
           //
           HAL_ASSERT(FALSE, "Not recognized chip ID");
           break;
       }
   }
   return 0;
}

Share this post


Link to post
Share on other sites
...

Ну а полностью узнать какой процессор можно так:

...

Ух ты, здорово. Буду переваривать.

 

Share this post


Link to post
Share on other sites
Требуется программно определять размер страницы флеш-памяти у Cortex-M3 процессоров от ST.... А есть ли какой способ узнать размер страницы памяти?

 

Интересно, а можно поинтересоваться, для чего это нужно и что это дает? B) По сути, например, мне нужно писать во flash когда я обновляю память программ или память данных flash через свой шифрованных загрузчик(в микроконтроллере), приспособленный под конкретную марку МК, и кабы тут уж все изначально понятно, сколько и какого объема сектора в чипе.

Share this post


Link to post
Share on other sites
flash когда я обновляю память программ или память данных flash через свой шифрованных загрузчик(в микроконтроллере), приспособленный под конкретную марку МК, и кабы тут уж все изначально понятно, сколько и какого объема сектора в чипе.

Да много чего дает, например единый загрузчик - у нас применяются 100, 101 и 103 в разных изделиях, с буквами от 'C' (256К флеша) до 'G' (1M флеша в двух банках). Причем в одно и то же изделие (на ту же печатную плату) , в зависимости от целевого заказчика, могут ставиться разные чипы. Объяснять производству куда какой загрузчик записывать, держать целую базу разных загрузчиков - это все издержки, вероятность ошибок и прочее.

Также есть набор софтовых-кубиков, например стек USB, прошитый в 100-ый, прочтет ID и аккуратно скажет что "ошиблись адресом" вместо исключения/зависания. В-общем, при имеющейся унификации по софту и железу, определять тип процессора во время исполнения отнюдь не вредно.

 

Share this post


Link to post
Share on other sites
Объяснять производству куда какой загрузчик записывать, держать целую базу разных загрузчиков - это все издержки, вероятность ошибок и прочее.

 

Извиняюсь за :bb-offtopic: . Если я правильно понял, в вашей компании имеется один универсальный загрузчик для устройств, основанных на МК семейства STM32F1xx, который шьется в любую плату на базе STM32F1хх. Если мое предположение верно, меня тогда интересует один тонкий момент, как тогда быть уверенным, что не особо продвинутый клиент, при желании обновить микропрограмму, не зашьет туда случайно прошивку, предназначенную для совсем другого изделия на STM32F1xx. У нас это решено жестко, введен ID код устройства в каждый загрузчик конкретного устройства, и при несовпадающей по ID прошивке идет соответствующее предупреждение. Получается именно так, что для каждого устройства свой отдельный загрузчик.

 

Share this post


Link to post
Share on other sites
другого изделия на STM32F1xx. У нас это решено жестко, введен ID код устройства в каждый загрузчик конкретного устройства, и при несовпадающей по ID прошивке идет соответствующее предупреждение. Получается именно так, что для каждого устройства свой отдельный загрузчик.

У нас примерно так и решено - только код не на каждый вид устройства, а на конкретную группу устройств. Причем чаще встречается разделение по коду между заказчиками - чтобы они между собой программами не менялись (получали только те софтовые фичи, за которые заплачено, грубо говоря). Таких кодов не очень много (порядка на два меньше чем типов устройств), и для каждого генерируется свой загрузчик (автоматизировано из одних и тех же исходников). Эти коды не зависят от типа процессора - назначаются фиксированно при появлении новой группы, не меняются десятилетиями, и хорошо известны на память всем вовлеченным сотрудникам - при том что сменилось уже несколько поколений процессоров. Процесс выбора загрузчика выглядит так - берем плату, смотрим тип процеcсора - пусть STM32, потом смотрим документы для кого эта партия плат, допустим "Заказчик 8", идем в папку BOOT/STM32 и берем там файл stm32_08.hex. При этом по факту на плате может быть и 100 и 101 и 103-ий процессор - никого на данном этапе это не заботит. Там же лежат автоматизирующие командные файлы, прошить загрузчик в несоответствующий ему процессор (допустим SAM7 в LPC17) практически нереально - утилиты выругаются.

 

Прошить не соответствующую рабочую прошивку теоретически возможно, такое даже изредка бывает (при разработке, единичные случаи, потому как в серии на конвеере такое не случается), но фатальных последствий не было за 12 лет использования загрузчиков ни разу. В первых изделиях начали было разводить "зоопарк" загрузчиков про который Вы говорите, и делать так же жестко как у Вас, но облом наступил быстро (темп 20-30 разных проектов в год), как выяснилось на практике последствий от неправильной прошивки обычно никаких, поэтому пришли к унифицированному загрузчику. Рабочий код при инициализации перифериии производит несколько проверок и блокируется "в случае чего" (а уж прошивка Cortex на ARM7TDMI виснет просто сразу, STM32/LPC17 виснут еще на инициализации основного генератора), грамотная схема учитывающая начальное состояние после сброса и с помехоподавляющими резисторами не дает палить порты при вероятных конфликтах, ну и загрузчик "всегда живой" и позволяет стереть зашитое "не то" и записать верную прошивку.

 

Часть заказчиков вообще покупает только софт - им просто процессоры с загрузчиком поставляются, выпускают они свою номенклатуру изделий самостоятельно. Тут без унифицированного загрузчика печалька была бы - поставляется это относительно крупными партиями (логистический гемор с "зарубежом" еще тот), а дальше заказчик смотрит на свои продажи и динамично регулирует свою номенклатуру.

 

Кстати, внести уникальный код изделия позволяет утилита, которой шьют загрузчики - банально через ключик командной строки. Не обязательно же идентификатор создавать на этапе компиляции - достаточно место для него выделить. Но это тоже как-то на практике не востребовано (ага, уже представил как я начинаю "грузить" производство требованиями зашивать еще один дополнительный код).

 

В-общем, победил прагматический принцип минимальной достаточности. Времени и людей всегда не хватает, если можно обойтись без "зоопарка", то это следует сделать.

 

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this