2013年4月16日 星期二

作業系統之前的程式 for stm32f4discovery (2) - 點亮 led, c version

the 1st edition: 20130416 (2)
the 2nd edition: 20160922

toolchain 的使用已經不在困擾我, 困難的是 cpu arm 架構與硬體平台, 這可要看不少資料。通過開發環境的試鍊後, 我打算點亮 led 燈來做為第一個 c 語言的練習程式。

fig 1 http://www.st.com/resource/en/schematic_pack/stm32f4discovery_sch.zip MB997.pdf

不過沒想到這支作業系統之前的程式一開始就難倒我, 難點在於 io 的部份, 不像前一個程式, 這個程式會用到平台相關的程式碼, 點亮 led, 得先要查詢接腳資料, 而查詢接腳資料是很磨人的, 我從這裡的範例程式修改而來。這是 st 公司提供的 library, 可以省下不少看 datasheet 的功夫, 也可幫助程式 port 到其他 st 平台, 是很重要的參考資料。經過三年後 (20160922), 我終於知道要從 fig 1 的文件來得知這個資訊, 這是為什麼要針對 PD12 ~ 15 來設定的原因。

fig 2


而透過 fig 2 得知到初始化 AHB1 mygpio_led.c L253, 因為 GPIO 接腳就接在這個 bus 上。

一樣化繁為簡, 將程式庫的部份抽取出來, 簡化成一個小的作業系統之前的程式。
  2 #include "stm32f4xx_gpio.h"
  3 #include "stm32f4xx.h" 
stm32f4xx_gpio.h, stm32f4xx.h, 從範例程式裡頭挖出來小改一下, 我已經把需要的相關程式碼
抽取出來放在 mygpio_led.c, 只有 stm32.h 和 mygpio_led.c, stm32.ld, 但不要以為這隻程式就很容易看, 得需要查閱 datasheet, 找出相關的暫存器設定方法。

大部份是 gpio, rcc 的 macro。stm32.h 是 coretex-m3 之 stm32 嵌入式系統設計的範例。由於沒有 SDRAM 控制器, 省下這部份的程式碼, lucky!!

stm32.h
 1 #ifndef STM32_H
 2 #define STM32_H
 3 #define GPIOB_CRL     (*(volatile unsigned long *)0x40010c00)
 4 #define GPIOB_BSRR    (*(volatile unsigned long *)0x40010c10)
 5 #define GPIOB_BRR     (*(volatile unsigned long *)0x40010c14)
 6 #define RCC_APB2ENR   (*(volatile unsigned long *)0x40021018)
 7 #define STACK_SIZE 64
 8 extern unsigned long _etext;
 9 extern unsigned long _data;
10 extern unsigned long _edata;
11 extern unsigned long _bss;
12 extern unsigned long _ebss;
13 
14 void ResetISR(void)
15 {
16   unsigned long *pulSrc, *pulDest;
17 
18   pulSrc = &_etext;
19   for (pulDest = &_data; pulDest < &_edata;)
20     *pulDest++ = *pulSrc++;
21   for (pulDest = &_bss; pulDest < &_ebss;)
22     *pulDest++ = 0;
23 
24   main();
25 }
26 
27 typedef void (*pfnISR)(void);
28 __attribute__((section(".stackares")))
29 static unsigned long pulStack[STACK_SIZE];
30 
31 
32 __attribute__((section(".isr_vector")))
33 pfnISR VectorTable[]=
34 {
35   (pfnISR)((unsigned long)pulStack+sizeof(pulStack)),
36   ResetISR
37 };
38 
39 #endif

mygpio_led.c
  1 #include "stm32.h"
  2 
  3 #define RCC_AHB1Periph_GPIOA             ((uint32_t)0x00000001)
  4 #define RCC_AHB1Periph_GPIOB             ((uint32_t)0x00000002)
  5 #define RCC_AHB1Periph_GPIOC             ((uint32_t)0x00000004)
  6 #define RCC_AHB1Periph_GPIOD             ((uint32_t)0x00000008)
  7 #define RCC_AHB1Periph_GPIOE             ((uint32_t)0x00000010)
  8 #define RCC_AHB1Periph_GPIOF             ((uint32_t)0x00000020)
  9 #define RCC_AHB1Periph_GPIOG             ((uint32_t)0x00000040)
 10 #define RCC_AHB1Periph_GPIOH             ((uint32_t)0x00000080)
 11 #define RCC_AHB1Periph_GPIOI             ((uint32_t)0x00000100)
 12 
 13 #define PERIPH_BASE    ((uint32_t)0x40000000) /*!< Peripheral base address in the alias region */
 14 #define AHB1PERIPH_BASE       (PERIPH_BASE + 0x00020000)
 15 #define RCC_BASE              (AHB1PERIPH_BASE + 0x3800)
 16 #define RCC                 ((RCC_TypeDef *) RCC_BASE)
 17 
 18 #define GPIOD_BASE            (AHB1PERIPH_BASE + 0x0C00)
 19 #define GPIOD               ((GPIO_TypeDef *) GPIOD_BASE)
 20 
 21 #define GPIO_OSPEEDER_OSPEEDR0               ((uint32_t)0x00000003)
 22 #define GPIO_OTYPER_OT_0                     ((uint32_t)0x00000001)
 23 #define GPIO_PUPDR_PUPDR0                    ((uint32_t)0x00000003)
 24 
 25 typedef signed int int32_t;
 26 typedef signed short int int16_t;
 27 typedef signed char int8_t;
 28 
 29 typedef unsigned int uint32_t;
 30 typedef unsigned short int uint16_t;
 31 typedef unsigned char uint8_t;
 32 #define     __IO    volatile 
 33 typedef struct
 34 {
 35   __IO uint32_t CR;            /*!< RCC clock control register, Address offset: 0x00 */
 36   __IO uint32_t PLLCFGR;       /*!< RCC PLL configuration register, Address offset: 0x04 */
 37   __IO uint32_t CFGR;          /*!< RCC clock configuration register, Address offset: 0x08 */
 38   __IO uint32_t CIR;           /*!< RCC clock interrupt register, Address offset: 0x0C */
 39   __IO uint32_t AHB1RSTR;      /*!< RCC AHB1 peripheral reset register, Address offset: 0x10 */
 40   __IO uint32_t AHB2RSTR;      /*!< RCC AHB2 peripheral reset register, Address offset: 0x14 */
 41   __IO uint32_t AHB3RSTR;      /*!< RCC AHB3 peripheral reset register, Address offset: 0x18 */
 42   uint32_t      RESERVED0;     /*!< Reserved, 0x1C                                                                    */
 43   __IO uint32_t APB1RSTR;      /*!< RCC APB1 peripheral reset register, Address offset: 0x20 */
 44   __IO uint32_t APB2RSTR;      /*!< RCC APB2 peripheral reset register, Address offset: 0x24 */
 45   uint32_t      RESERVED1[2];  /*!< Reserved, 0x28-0x2C                                                               */
 46   __IO uint32_t AHB1ENR;       /*!< RCC AHB1 peripheral clock register, Address offset: 0x30 */
 47   __IO uint32_t AHB2ENR;       /*!< RCC AHB2 peripheral clock register, Address offset: 0x34 */
 48   __IO uint32_t AHB3ENR;       /*!< RCC AHB3 peripheral clock register, Address offset: 0x38 */
 49   uint32_t      RESERVED2;     /*!< Reserved, 0x3C                                                                    */
 50   __IO uint32_t APB1ENR;       /*!< RCC APB1 peripheral clock enable register, Address offset: 0x40 */
 51   __IO uint32_t APB2ENR;       /*!< RCC APB2 peripheral clock enable register, Address offset: 0x44 */
 52   uint32_t      RESERVED3[2];  /*!< Reserved, 0x48-0x4C                                                               */
 53   __IO uint32_t AHB1LPENR;     /*!< RCC AHB1 peripheral clock enable in low power mode register, Address offset: 0x50 */
 54   __IO uint32_t AHB2LPENR;     /*!< RCC AHB2 peripheral clock enable in low power mode register, Address offset: 0x54 */
 55   __IO uint32_t AHB3LPENR;     /*!< RCC AHB3 peripheral clock enable in low power mode register, Address offset: 0x58 */
 56   uint32_t      RESERVED4;     /*!< Reserved, 0x5C                                                                    */
 57   __IO uint32_t APB1LPENR;     /*!< RCC APB1 peripheral clock enable in low power mode register, Address offset: 0x60 */
 58   __IO uint32_t APB2LPENR;     /*!< RCC APB2 peripheral clock enable in low power mode register, Address offset: 0x64 */
 59   uint32_t      RESERVED5[2];  /*!< Reserved, 0x68-0x6C                                                               */
 60   __IO uint32_t BDCR;          /*!< RCC Backup domain control register,                          Address offset: 0x70 */
 61   __IO uint32_t CSR;           /*!< RCC clock control & status register,                         Address offset: 0x74 */
 62   uint32_t      RESERVED6[2];  /*!< Reserved, 0x78-0x7C                                                               */
 63   __IO uint32_t SSCGR;         /*!< RCC spread spectrum clock generation register,               Address offset: 0x80 */
 64   __IO uint32_t PLLI2SCFGR;    /*!< RCC PLLI2S configuration register,                           Address offset: 0x84 */
 65 } RCC_TypeDef;
 66 
 67 
 68 typedef struct
 69 {
 70   __IO uint32_t MODER;    /*!< GPIO port mode register,               Address offset: 0x00      */
 71   __IO uint32_t OTYPER;   /*!< GPIO port output type register,        Address offset: 0x04      */
 72   __IO uint32_t OSPEEDR;  /*!< GPIO port output speed register,       Address offset: 0x08      */
 73   __IO uint32_t PUPDR;    /*!< GPIO port pull-up/pull-down register,  Address offset: 0x0C      */
 74   __IO uint32_t IDR;      /*!< GPIO port input data register,         Address offset: 0x10      */
 75   __IO uint32_t ODR;      /*!< GPIO port output data register,        Address offset: 0x14      */
 76   __IO uint16_t BSRRL;    /*!< GPIO port bit set/reset low register,  Address offset: 0x18      */
 77   __IO uint16_t BSRRH;    /*!< GPIO port bit set/reset high register, Address offset: 0x1A      */
 78   __IO uint32_t LCKR;     /*!< GPIO port configuration lock register, Address offset: 0x1C      */
 79   __IO uint32_t AFR[2];   /*!< GPIO alternate function registers,     Address offset: 0x20-0x24 */
 80 } GPIO_TypeDef;
 81 
 82 #define GPIO_MODER_MODER0                    ((uint32_t)0x00000003)
 83 
 84 typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState;
 85 
 86 typedef enum
 87 { 
 88   GPIO_OType_PP = 0x00,
 89   GPIO_OType_OD = 0x01
 90 }GPIOOType_TypeDef;
 91 
 92 typedef enum
 93 { 
 94   GPIO_PuPd_NOPULL = 0x00,
 95   GPIO_PuPd_UP     = 0x01,
 96   GPIO_PuPd_DOWN   = 0x02
 97 }GPIOPuPd_TypeDef;
 98 
 99 typedef enum
100 { 
101   GPIO_Mode_IN   = 0x00, /*!< GPIO Input Mode */
102   GPIO_Mode_OUT  = 0x01, /*!< GPIO Output Mode */
103   GPIO_Mode_AF   = 0x02, /*!< GPIO Alternate function Mode */
104   GPIO_Mode_AN   = 0x03  /*!< GPIO Analog Mode */
105 }GPIOMode_TypeDef;
106 
107 typedef enum
108 { 
109   GPIO_Speed_2MHz   = 0x00, /*!< Low speed */
110   GPIO_Speed_25MHz  = 0x01, /*!< Medium speed */
111   GPIO_Speed_50MHz  = 0x02, /*!< Fast speed */
112   GPIO_Speed_100MHz = 0x03  /*!< High speed on 30 pF (80 MHz Output max speed on 15 pF) */
113 }GPIOSpeed_TypeDef;
114 
115 #define GPIO_Pin_0                 ((uint16_t)0x0001)  /* Pin 0 selected */
116 #define GPIO_Pin_1                 ((uint16_t)0x0002)  /* Pin 1 selected */
117 #define GPIO_Pin_2                 ((uint16_t)0x0004)  /* Pin 2 selected */
118 #define GPIO_Pin_3                 ((uint16_t)0x0008)  /* Pin 3 selected */
119 #define GPIO_Pin_4                 ((uint16_t)0x0010)  /* Pin 4 selected */
120 #define GPIO_Pin_5                 ((uint16_t)0x0020)  /* Pin 5 selected */
121 #define GPIO_Pin_6                 ((uint16_t)0x0040)  /* Pin 6 selected */
122 #define GPIO_Pin_7                 ((uint16_t)0x0080)  /* Pin 7 selected */
123 #define GPIO_Pin_8                 ((uint16_t)0x0100)  /* Pin 8 selected */
124 #define GPIO_Pin_9                 ((uint16_t)0x0200)  /* Pin 9 selected */
125 #define GPIO_Pin_10                ((uint16_t)0x0400)  /* Pin 10 selected */
126 #define GPIO_Pin_11                ((uint16_t)0x0800)  /* Pin 11 selected */
127 #define GPIO_Pin_12                ((uint16_t)0x1000)  /* Pin 12 selected */
128 #define GPIO_Pin_13                ((uint16_t)0x2000)  /* Pin 13 selected */
129 #define GPIO_Pin_14                ((uint16_t)0x4000)  /* Pin 14 selected */
130 #define GPIO_Pin_15                ((uint16_t)0x8000)  /* Pin 15 selected */
131 #define GPIO_Pin_All               ((uint16_t)0xFFFF)  /* All pins selected */
132 
133 typedef struct
134 {
135   uint32_t GPIO_Pin;              /*!< Specifies the GPIO pins to be configured.
136                                        This parameter can be any value of @ref GPIO_pins_define */
137 
138   GPIOMode_TypeDef GPIO_Mode;     /*!< Specifies the operating mode for the selected pins.
139                                        This parameter can be a value of @ref GPIOMode_TypeDef */
140 
141   GPIOSpeed_TypeDef GPIO_Speed;   /*!< Specifies the speed for the selected pins.
142                                        This parameter can be a value of @ref GPIOSpeed_TypeDef */
143 
144   GPIOOType_TypeDef GPIO_OType;   /*!< Specifies the operating output type for the selected pins.
145                                        This parameter can be a value of @ref GPIOOType_TypeDef */
146 
147   GPIOPuPd_TypeDef GPIO_PuPd;     /*!< Specifies the operating Pull-up/Pull down for the selected pins.
148                                        This parameter can be a value of @ref GPIOPuPd_TypeDef */
149 }GPIO_InitTypeDef;
150 
151 void Delay(uint32_t delay )
152 {
153   while(delay) delay--;
154 }
155 
156 void RCC_AHB1PeriphClockCmd(uint32_t RCC_AHB1Periph, FunctionalState NewState)
157 { 
158   /* Check the parameters */
159   //assert_param(IS_RCC_AHB1_CLOCK_PERIPH(RCC_AHB1Periph));
160   
161   //assert_param(IS_FUNCTIONAL_STATE(NewState));
162   if (NewState != DISABLE)
163   {
164     RCC->AHB1ENR |= RCC_AHB1Periph;
165   } 
166   else
167   { 
168     RCC->AHB1ENR &= ~RCC_AHB1Periph;
169   }
170 }  
171 
172 #define RCC_AHB1Periph_GPIOD             ((uint32_t)0x00000008)
173 
174 
175 void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
176 {
177   uint32_t pinpos = 0x00, pos = 0x00 , currentpin = 0x00;
178 
179 #if 0
180   /* Check the parameters */
181   assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
182   assert_param(IS_GPIO_PIN(GPIO_InitStruct->GPIO_Pin));
183   assert_param(IS_GPIO_MODE(GPIO_InitStruct->GPIO_Mode));
184   assert_param(IS_GPIO_PUPD(GPIO_InitStruct->GPIO_PuPd));
185 #endif
186   /* -------------------------Configure the port pins---------------- */
187   /*-- GPIO Mode Configuration --*/
188   for (pinpos = 0x00; pinpos < 0x10; pinpos++)
189   {
190     pos = ((uint32_t)0x01) << pinpos;
191     /* Get the port pins position */
192     currentpin = (GPIO_InitStruct->GPIO_Pin) & pos;
193 
194     if (currentpin == pos)
195     {
196       GPIOx->MODER  &= ~(GPIO_MODER_MODER0 << (pinpos * 2));
197       GPIOx->MODER |= (((uint32_t)GPIO_InitStruct->GPIO_Mode) << (pinpos * 2));
198 
199       if ((GPIO_InitStruct->GPIO_Mode == GPIO_Mode_OUT) || (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_AF))
200       {
201         /* Check Speed mode parameters */
202         //assert_param(IS_GPIO_SPEED(GPIO_InitStruct->GPIO_Speed));
203 
204         /* Speed mode configuration */
205         GPIOx->OSPEEDR &= ~(GPIO_OSPEEDER_OSPEEDR0 << (pinpos * 2));
206         GPIOx->OSPEEDR |= ((uint32_t)(GPIO_InitStruct->GPIO_Speed) << (pinpos * 2));
207 
208         /* Check Output mode parameters */
209         //assert_param(IS_GPIO_OTYPE(GPIO_InitStruct->GPIO_OType));
210 
211         /* Output mode configuration*/
212         GPIOx->OTYPER  &= ~((GPIO_OTYPER_OT_0) << ((uint16_t)pinpos)) ;
213         GPIOx->OTYPER |= (uint16_t)(((uint16_t)GPIO_InitStruct->GPIO_OType) << ((uint16_t)pinpos));
214       }
215 
216       /* Pull-up Pull down resistor configuration*/
217       GPIOx->PUPDR &= ~(GPIO_PUPDR_PUPDR0 << ((uint16_t)pinpos * 2));
218       GPIOx->PUPDR |= (((uint32_t)GPIO_InitStruct->GPIO_PuPd) << (pinpos * 2));
219     }
220   }
221 }
222 
223 void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
224 {   
225   /* Check the parameters */
226   //assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
227   //assert_param(IS_GPIO_PIN(GPIO_Pin));
228     
229   GPIOx->BSRRL = GPIO_Pin;
230 } 
231 
232 
233 void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
234 {
235   /* Check the parameters */
236   //assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
237   //assert_param(IS_GPIO_PIN(GPIO_Pin));
238 
239   GPIOx->BSRRH = GPIO_Pin;
240 }
241 
242 int main(void)
243 {
244     //init_led();
245     GPIO_InitTypeDef GPIO_InitStructure;
246     
247     #if 0
248     /* Enable GPIO C clock. */
249     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
250     #endif
251 
252     /* GPIOD Periph clock enable */
253     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
254 
255   /* Configure PD12, PD13, PD14 and PD15 in output pushpull mode */
256   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13| GPIO_Pin_14| GPIO_Pin_15;
257   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
258   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
259   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
260   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
261   GPIO_Init(GPIOD, &GPIO_InitStructure);
262 
263       
264   while (1)
265   {     
266     /* PD12 to be toggled, green */
267     GPIO_SetBits(GPIOD, GPIO_Pin_12);
268     GPIO_SetBits(GPIOD, GPIO_Pin_11);
269         
270     /* Insert delay */ 
271     Delay(0x3FFFFF);
272 
273 #if 1
274     /* PD13 to be toggled, orange */
275     GPIO_SetBits(GPIOD, GPIO_Pin_13);
276 
277     /* Insert delay */
278     Delay(0x3FFFFF);
279 #endif    
280     /* PD14 to be toggled, ref */
281     GPIO_SetBits(GPIOD, GPIO_Pin_14);
282       
283     /* Insert delay */
284     Delay(0x3FFFFF);
285 #if 1
286     /* PD15 to be toggled, blue */
287     GPIO_SetBits(GPIOD, GPIO_Pin_15);
288     /* Insert delay */
289     Delay(0x5FFFFF);
290 #endif
291     GPIO_ResetBits(GPIOD, GPIO_Pin_11 | GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);
292 
293     /* Insert delay */
294     Delay(0x6FFFFF);
295   }
296 
297 
320 }

stm32.ld
 1 MEMORY
 2 {
 3   FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 1024K
 4   SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 192K
 5 }
 6 
 7 SECTIONS
 8 {
 9   .text :
10   {
11     KEEP(*(.isr_vector .isr_vector.*))
12     *(.text .text.*)
13     *(.rodata .rodata*)
14     _etext = .;
15   } > FLASH
16   .data : AT (_etext)
17   {
18     _data = .;
19     *(.data .data.*)
20     _edata = .;
21   } > SRAM
22   .bss(NOLOAD) :
23   {
24     _bss = .;
25     *(.bss .bss.*)
26     *(COMMON)
27     . = ALIGN(4);
28     _ebss = .;
29   } > SRAM
30   .stackarea(NOLOAD) :
31   {
32     . = ALIGN(8);
33     *(.stackarea .stackares.*)
34     . = ALIGN(8);
35   }
36   . = ALIGN(4);
37   _end = .;
38 }

程式結果就是先閃綠燈, 閃紅燈在一起熄滅, 如此循環下去。



fig 3 使用 saleae logic 16 抓取 30 秒
而在 20160814 買了 saleae logic 16 之後, 我就可以測量 GPIO 訊號, 請參考 fig 3 的接法,  ch1 接在 PD12, ch2 接在 PD13。

fig 4 rx1 (ch1) 是 PD12 - green led
fig 4 sync (ch2) 是 PD 13 - orange led

再參考 fig 4, 當 rx1, sync 一起降下來的時候, 就是同時暗掉, 升上去時就是亮燈。

也可以得知 Delay(0x3FFFFF); 大概是 4 秒左右, 在這時候的我還沒有可以正確設定 timer 的能力, 不過現在我知道要怎麼設定了。

fig 4 使用 saleae logic 16 抓取 30 秒

我要解說的部份只和開機程式有關, IO 部份請自己搞定, 這不是文章的重點。和 x86 不同, cortex-m3 可以「完全」使用 c 語言來寫開機程式, 而不像 x86 需要 inline 組合語言。一開機, 位址 0~3 存放的值會被填到 sp, 完成 stack 設定, 在 c 語言中完成最重要的設定。

再來是 bss section:

stm32.h
13 void ResetISR(void)
14 {
15   unsigned long *pulSrc, *pulDest;
16 
17   pulSrc = &_etext;
18   for (pulDest = &_data; pulDest < &_edata;)
19     *pulDest++ = *pulSrc++;
20   for (pulDest = &_bss; pulDest < &_ebss;)
21     *pulDest++ = 0;
22 
23   main();
24 }

這段 code 便是在初使化 .bss, .data, 就這樣完成 c startup code, 完全不需要組合語言介入, 厲害的設計。

也許你想知道 .bss, .data 為什麼要初始化, 這不是很容易寫在 blog 上, 用個例子簡單說明:

int a=6;
void func()
{
  static int i;
}

a 位於 .data, i 位於 .bss, 在程式執行時, a 要是 6, 而 i 要是 0, 這不是憑空得來的, 初始化 .bss, .data 就是在完成這樣的工作, 我知道, 這只能解除你一半的疑惑, 你一定想知道更多吧!

那 x86 的 bss section 也可以這樣寫嗎?由於有名的 segment address, 你得先確定你指的位址 0x100 真的是絕對位址 0x100 嗎?這是很容易搞亂的。

而透過 link script, section(".isr_vector") 會被放到 0 開頭的位址, 達到 0~3 是 stack value, 4 ~ 7 是 reset handle 的目的, 進而透過 ResetISR call main 去執行 main()。

簡單的 gpio led 程式並沒有想像中簡單吧, 所以像是 arduino 之類的開發版將這些困難都隱藏起來是花了不少苦心, 不過我的學習方式正是要把隱藏在冰山下的真像挖出來, 這也是為什麼又過了三年, 還是只在 gpio led 打轉。

按照之前的慣例, 下一個應該是 c++ 的版本, 不過 ...

source code:
https://github.com/descent/stm32f4_prog/tree/master/led

補充 stm32 p103 模擬器中的初始化程式碼:

stm32_p103_demos/libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/startup/gcc_ride7/startup_stm32f10x_md.s

 1     .section .text.Reset_Handler
 2  .weak Reset_Handler
 3  .type Reset_Handler, %function
 4 Reset_Handler: 
 5 
 6 /* Copy the data segment initializers from flash to SRAM */  
 7   movs r1, #0
 8   b LoopCopyDataInit
 9 
10 CopyDataInit:
11  ldr r3, =_sidata
12  ldr r3, [r3, r1]
13  str r3, [r0, r1]
14  adds r1, r1, #4
15     
16 LoopCopyDataInit:
17  ldr r0, =_sdata
18  ldr r3, =_edata
19  adds r2, r0, r1
20  cmp r2, r3
21  bcc CopyDataInit
22  ldr r2, =_sbss
23  b LoopFillZerobss
24 /* Zero fill the bss segment. */  
25 FillZerobss:
26  movs r3, #0
27  str r3, [r2], #4
28     
29 LoopFillZerobss:
30  ldr r3, = _ebss
31  cmp r2, r3
32  bcc FillZerobss
33 /* Call the clock system intitialization function.*/
34   bl  SystemInit  
35 /* Call the application's entry point.*/
36  bl main
37  bx lr    
38 .size Reset_Handler, .-Reset_Handler
L36 會 call main

ref:
gpio gpio push-pull or open drain:

介紹一些 arm 指令:
http://jnotes.googlecode.com/svn-history/r105/trunk/Notes/NotesOnCM3/stm32WithGCC.html

books: coretex-m3 之 stm32 嵌入式系統設計

沒有留言:

張貼留言

使用 google 的 reCAPTCHA 驗證碼, 總算可以輕鬆留言了。

我實在受不了 spam 了, 又不想讓大家的眼睛花掉, 只好放棄匿名留言。這是沒辦法中的辦法了。留言的朋友需要有 google 帳號。