{"id":45,"date":"2015-01-08T10:43:38","date_gmt":"2015-01-08T10:43:38","guid":{"rendered":"http:\/\/carsten.familie-schumann.info\/blog\/?p=45"},"modified":"2015-01-08T10:47:44","modified_gmt":"2015-01-08T10:47:44","slug":"speicher-beim-stm32-cortex-m3cortex-m0-sparen","status":"publish","type":"post","link":"https:\/\/carsten.familie-schumann.info\/blog\/2015\/01\/speicher-beim-stm32-cortex-m3cortex-m0-sparen\/","title":{"rendered":"Speicher beim STM32 (Cortex-M3\/Cortex-M0) sparen"},"content":{"rendered":"<p>In der letzten Zeit programmiere ich recht viel mit dem STM32. Dabei handelt es sich um einen Microcontroller mit ARM-v7 Kern (Cortex-M0, Cortex-M3, Cortex-M4), der sich grob im Preisniveau von AVRs bewegt, aber deutlich performanter ist. Seitens des Herstellers (ST Microelectronics) wird eine angenehm nutzbare Firmware-Library (Standard Peripherals Library) mitgeliefert, sodass man eigentlich direkt starten kann. Achsoo, GCC gibts nat\u00fcrlich auch als Compiler: . Das ganze wird dann unter Eclipse programmiert und mit OpenOCD debuggt.<\/p>\n<p>Jetzt aber zum eigentlichen Thema. Wenn man n\u00e4mlich wie von ST in den Beispielen der Firmware-Library die Peripherie initialisiert, dann sieht das in etwa so aus:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\nRCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);\r\n\r\nGPIO_InitTypeDef gpio;\r\ngpio.GPIO_Mode = GPIO_Mode_OUT;\r\ngpio.GPIO_OType = GPIO_OType_PP;\r\ngpio.GPIO_PuPd = GPIO_PuPd_NOPULL;\r\ngpio.GPIO_Speed = GPIO_Speed_Level_1;\r\ngpio.GPIO_Pin = GPIO_Pin_14 | GPIO_Pin_15;\r\nGPIO_Init(GPIOC, &amp;amp;gpio);\r\n<\/pre>\n<p>Zum einen ist dieser Code recht un\u00fcbersichtlich, zum anderen passiert aber hier etwas, was man eigentlich gar nicht m\u00f6chte. Zuerst wird n\u00e4mlich auf dem Stack Speicher f\u00fcr die Struktur reserviert, dann im Programm Feld f\u00fcr Feld mit Werten gef\u00fcllt und danach an die Init-Funktion \u00fcbergeben. Im Assembler sieht das \u00fcbrigens so aus:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);\r\n 800899a:\t2380      \tmovs\tr3, #128\t; 0x80\r\n 800899c:\t031b      \tlsls\tr3, r3, #12\r\n 800899e:\t1c18      \tadds\tr0, r3, #0\r\n 80089a0:\t2101      \tmovs\tr1, #1\r\n 80089a2:\tf7fa f919 \tbl\t8002bd8 &lt;RCC_AHBPeriphClockCmd&gt;\r\n\r\n  GPIO_InitTypeDef gpio;\r\n  gpio.GPIO_Mode = GPIO_Mode_OUT;\r\n 80089a6:\t1c3b      \tadds\tr3, r7, #0\r\n 80089a8:\t2201      \tmovs\tr2, #1\r\n 80089aa:\t711a      \tstrb\tr2, &#x5B;r3, #4]\r\n  gpio.GPIO_OType = GPIO_OType_PP;\r\n 80089ac:\t1c3b      \tadds\tr3, r7, #0\r\n 80089ae:\t2200      \tmovs\tr2, #0\r\n 80089b0:\t719a      \tstrb\tr2, &#x5B;r3, #6]\r\n  gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;\r\n 80089b2:\t1c3b      \tadds\tr3, r7, #0\r\n 80089b4:\t2200      \tmovs\tr2, #0\r\n 80089b6:\t71da      \tstrb\tr2, &#x5B;r3, #7]\r\n  gpio.GPIO_Speed = GPIO_Speed_Level_1;\r\n 80089b8:\t1c3b      \tadds\tr3, r7, #0\r\n 80089ba:\t2200      \tmovs\tr2, #0\r\n 80089bc:\t715a      \tstrb\tr2, &#x5B;r3, #5]\r\n  gpio.GPIO_Pin = GPIO_Pin_14 | GPIO_Pin_15;\r\n 80089be:\t1c3b      \tadds\tr3, r7, #0\r\n 80089c0:\t22c0      \tmovs\tr2, #192\t; 0xc0\r\n 80089c2:\t0212      \tlsls\tr2, r2, #8\r\n 80089c4:\t601a      \tstr\tr2, &#x5B;r3, #0]\r\n  GPIO_Init(GPIOC, &amp;gpio);\r\n 80089c6:\t4a04      \tldr\tr2, &#x5B;pc, #16]\t; (80089d8 &lt;DIR_Config+0x44&gt;)\r\n 80089c8:\t1c3b      \tadds\tr3, r7, #0\r\n 80089ca:\t1c10      \tadds\tr0, r2, #0\r\n 80089cc:\t1c19      \tadds\tr1, r3, #0\r\n 80089ce:\tf7f9 fddb \tbl\t8002588 &lt;GPIO_Init&gt;\r\n<\/pre>\n<p>Ziemlich aufwendig f\u00fcr ein wenig Initialisierung, die sich nie \u00e4ndert, gell? In Summe sind das 56 Bytes Programmcode.<\/p>\n<p>Wenn man nun geschickt C99-Struct-Initialisierungen mit ein paar Speichermodifiern kombiniert, so erh\u00e4lt man folgenden Code, der effektiv das Gleiche macht:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n  \/* GPIOC Periph clock enable *\/\r\n  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);\r\n\r\n  const GPIO_InitTypeDef gpio = {\r\n      .GPIO_Mode = GPIO_Mode_OUT,\r\n      .GPIO_OType = GPIO_OType_PP,\r\n      .GPIO_PuPd = GPIO_PuPd_NOPULL,\r\n      .GPIO_Speed = GPIO_Speed_Level_1,\r\n      .GPIO_Pin = GPIO_Pin_14 | GPIO_Pin_15\r\n  };\r\n\r\n  GPIO_Init(GPIOC, &amp;gpio);\r\n<\/pre>\n<p>Zus\u00e4tzlich kann man noch die Funktionssignatur der Funktion GPIO_Init \u00e4ndern, sodass man einen Pointer \u00fcbergibt, an dem sich weder die Adresse noch der Inhalt \u00e4ndert:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\nvoid GPIO_Init(GPIO_TypeDef* GPIOx, const GPIO_InitTypeDef* const GPIO_InitStruct);\r\n<\/pre>\n<p>Damit werden die Daten nicht erst im RAM aufbereitet und dann an die GPIO_Init \u00fcbergeben sondern die Funktion bekommt direkt die Flash-Adresse der Daten \u00fcbergeben. Das Ergebnis sieht erstaunlich simpel im Assembler-Code aus:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);\r\n 800899a:\t2380      \tmovs\tr3, #128\t; 0x80\r\n 800899c:\t031b      \tlsls\tr3, r3, #12\r\n 800899e:\t1c18      \tadds\tr0, r3, #0\r\n 80089a0:\t2101      \tmovs\tr1, #1\r\n 80089a2:\tf7fa f919 \tbl\t8002bd8 &lt;RCC_AHBPeriphClockCmd&gt;\r\n  const GPIO_InitTypeDef gpio = {...}\r\n 80089a6:\t1c3b      \tadds\tr3, r7, #0\r\n 80089a8:\t4a05      \tldr\tr2, &#x5B;pc, #20]\t; (80089c0 &lt;DIR_Config+0x2c&gt;)\r\n 80089aa:\tca03      \tldmia\tr2!, {r0, r1}\r\n 80089ac:\tc303      \tstmia\tr3!, {r0, r1}\r\n  GPIO_Init(GPIOC, &amp;gpio);\r\n 80089ae:\t4a05      \tldr\tr2, &#x5B;pc, #20]\t; (80089c4 &lt;DIR_Config+0x30&gt;)\r\n 80089b0:\t1c3b      \tadds\tr3, r7, #0\r\n 80089b2:\t1c10      \tadds\tr0, r2, #0\r\n 80089b4:\t1c19      \tadds\tr1, r3, #0\r\n 80089b6:\tf7f9 fde7 \tbl\t8002588 &lt;GPIO_Init&gt;\r\n<\/pre>\n<p>Macht in Summe 32 Bytes Programmcode. Also haben wir uns einen Haufen Anweisungen, Stack-Speicher in Gr\u00f6\u00dfe der Struktur und 24 Bytes (43%) Code gespart. Das mag in erster Instanz l\u00e4cherlich wirken, jedoch wird bei der Initialisierung mehr als ein Pin initialisiert. Prinzipiell l\u00e4sst sich dieser Trick n\u00e4mlich auch bei DMA-, ADC-, TIMer-, DAC-, &#8230;. -Initialisierungen verwenden.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In der letzten Zeit programmiere ich recht viel mit dem STM32. Dabei handelt es sich um einen Microcontroller mit ARM-v7 Kern (Cortex-M0, Cortex-M3, Cortex-M4), der sich grob im Preisniveau von AVRs bewegt, aber deutlich performanter ist. Seitens des Herstellers (ST Microelectronics) wird eine angenehm nutzbare Firmware-Library (Standard Peripherals Library) mitgeliefert, sodass man eigentlich direkt starten&#8230;<br \/><a class=\"read-more-button\" href=\"https:\/\/carsten.familie-schumann.info\/blog\/2015\/01\/speicher-beim-stm32-cortex-m3cortex-m0-sparen\/\">Mehr Lesen<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[],"class_list":["post-45","post","type-post","status-publish","format-standard","hentry","category-programmierung"],"_links":{"self":[{"href":"https:\/\/carsten.familie-schumann.info\/blog\/wp-json\/wp\/v2\/posts\/45","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/carsten.familie-schumann.info\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/carsten.familie-schumann.info\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/carsten.familie-schumann.info\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/carsten.familie-schumann.info\/blog\/wp-json\/wp\/v2\/comments?post=45"}],"version-history":[{"count":11,"href":"https:\/\/carsten.familie-schumann.info\/blog\/wp-json\/wp\/v2\/posts\/45\/revisions"}],"predecessor-version":[{"id":56,"href":"https:\/\/carsten.familie-schumann.info\/blog\/wp-json\/wp\/v2\/posts\/45\/revisions\/56"}],"wp:attachment":[{"href":"https:\/\/carsten.familie-schumann.info\/blog\/wp-json\/wp\/v2\/media?parent=45"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/carsten.familie-schumann.info\/blog\/wp-json\/wp\/v2\/categories?post=45"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/carsten.familie-schumann.info\/blog\/wp-json\/wp\/v2\/tags?post=45"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}