แนะนำผู้เริ่มต้นใหม่ STM32F4 discovery โดยkeil บทที่3 GPIO

บทความคัดลอกจากอีเลคทูเดย์ เพื่อเก็บเป็นคลังข้อมูล http://www.electoday.com/index.php/topic,10211.0.html Tongue out

 

1 สร้าง Floder ชื่อ GPIO  ขึ้นมา
2 ทำการเพื่ม File  system_stm32f4xx.c และ stm32f4xx.hไว้ใน Floder
3 ทำการสร้างโปรเจคใหม่ เลือก เบอร์ IC stm32f407VG และให้ ADD File startup_stm32f4.s
เข้ามาด้วย  เพื่อที่จะได้ไม่ต้องไปก๊อปมาจาก Lib st ให้ยุ่งยากอีก  ความสำคัญคือมันจะช่วยจัดการค่า
เบื้องต้นให้กับ IC ให้พร้อมรับการโปรแกรมและการทำงาน ถ้าไม่มี  MCU จะ compiler ไม่ผ่าน
4 เขียนClode และ save โปรเจคเป็นนามสกุล .C

เว๊ปไซด์อ้างอิงและให้อ่านศึกษาต่อยอด
http://blog.mark-stevens.co.uk/?p=854
http://jeremyherbert.net/get/stm32f4_getting_started
http://www.farrellf.com/projects/hardware/2012-06-28_STM32F4_Basics:_GPIOs/

ขั้นตอนแรกการควบคุม GPIO ครับ
ขา IC แต่ละขา มีหน้าที่ทำงานต่างๆ และต่างกัน ในขาเดียวกันอาจมีสามหรือสี่ฟังก์ชันในขาเดียวกัน หรือ ไม่มีหน้าที่เลย (NC)
แล้ว NC มีไว้ทำอะไร  ประโยชน์ที่เห็นมี 2 อย่าง    (1)  ไว้ช่วยยึดตัว IC   (2)  ความสวยงามของตัวถัง ถ้าไม่มีไม่เท่

กลับมาต่อครับ   มารู้จัก รีจีสเตอร์ที่ควบคุม GPIOกัน

ถ้าท่านใช้ขาที่เลือกเป็น Digital Output จะต้องดูที่รีจีสเตอร์ MODER

GPIO จะมีขาให้ใช้มากสุด 15 ขา หรือ 15 bit     เช่น GPIOA 0;........GPIOA14 , GPIOA15 .
ขา GPIO แต่ละบิด จะใช้  2 บิตของรีจีสเตอร์ MODER ควบคุม ดังนี้
GPIO(Bit0)  =  MODER Bit0(x) กับ MODER Bit1(y) ควบคุม
GPIO(Bit1)  =  MODER Bit2(x) กับ MODER Bit3(y) ควบคุม
GPIO(Bit2)  =  MODER Bit4(x) กับ MODER Bit5(y) ควบคุม
.                      .
.                      .
GPIO(Bit14)  =  MODER Bit28(x) กับ MODER Bit29(y) ควบคุม
GPIO(Bit15)  =  MODER Bit30(x) กับ MODER Bit31(y) ควบคุม

(x),(y) คือค่าทางลอจิของบิตนั้นๆ
Output  ต้อง Set x = 1, Set y  = 0     อ้างอิงจาก Reference Manual RM0090 หน้า186/1422 ST
เช่นต้องการให้  Bit 0, Bit 1 ของ GPIOA เป็น เอาท์พุต ได้  GPIOA->MODER   =    0x00000005;
ต้องการให้  Bit 0, Bit 15 ของ GPIOB เป็น เอาท์พุต ได้     GPIOB->MODER   =    0x10000001;

ถัดมา รีจีสเตอร์ปรับความเร็วที่GPIO 
เราสามารถปรับความเร็วของขาแต่ละขาได้จากรีจีสเตอร์ OSPEEDR  ครับ 32bit คล้าย MODER
GPIO(Bit0)  =  OSPEEDR Bit0(x) กับ OSPEEDR Bit1(y) ควบคุม
GPIO(Bit1)  =  OSPEEDR Bit2(x) กับ OSPEEDR Bit3(y) ควบคุม
GPIO(Bit2)  =  OSPEEDR Bit4(x) กับ OSPEEDR Bit5(y) ควบคุม
.                      .
.                      .
GPIO(Bit14)  =  OSPEEDR Bit28(x)  กับ OSPEEDR Bit29(y) ควบคุม
GPIO(Bit15)  =  OSPEEDR Bit30(x)  กับ OSPEEDR Bit31(y) ควบคุม
(x),(y) คือค่าทางลอจิของบิตนั้นๆ
(x =  0,  y  = 0)  ขานั้นจะมีความเร็วสูงสุดแค่  2 Mhz อ้างอิงจาก Reference Manual RM0090 หน้า199/1422 ST
(x =  0,  y  = 1)  ขานั้นจะมีความเร็วสูงสุดแค่  25 Mhz
(x =  1,  y  = 0)  ขานั้นจะมีความเร็วสูงสุดแค่  50 Mhz
(x =  1,  y  = 1)  ขานั้นจะมีความเร็วสูงสุดแค่  100 Mhz
ตัวอย่าง
ต้องการขา GPIOB Bit0 เป็น 25Mhz Bit15 เป็น 100Mhz ได้ GPIOB->SPEEDR  = 0xC0000001;

ถัดมารีจีสเตอร์ PUPDR ใช้ในการทำ พูอัป พูดาว ของตัวต้านทานที่ขานั้นๆ หลักการคล้ายกับ MODER,OSPEEDR
GPIO(Bit0)  =  PUPDR Bit0(x) กับ PUPDR Bit1(y) ควบคุม
GPIO(Bit1)  =  PUPDR Bit2(x) กับ PUPDR Bit3(y) ควบคุม
GPIO(Bit2)  =  PUPDR Bit4(x) กับ PUPDR Bit5(y) ควบคุม
.                      .
.                      .
GPIO(Bit14)  =  PUPDR Bit28(x)  กับ PUPDR Bit29(y) ควบคุม
GPIO(Bit15)  =  PUPDR Bit30(x)  กับ PUPDR Bit31(y) ควบคุม
(x =  0,  y  = 0)  No Pull-up, No Pull-down อ้างอิงจาก Reference Manual RM0090 หน้า200/1422 ST
(x =  0,  y  = 1)  Pull-up
(x =  1,  y  = 0)  Pull-down
(x =  1,  y  = 1)  (ไม่ใช้งาน ไม่เกิดอะไรขึ้น)

อีกตัวที่สำคัญคือ รีจีสเตอร์ OTYPER
OTYPER จะมีแค่  15 bit ตามจำนวนขาของ GPIO ดังนั้นคำสั่งจะมีแค่ ลอจิก 0 กับ 1
GPIO(Bit0)  =  OTYPER Bit0(x)
GPIO(Bit1)  =  OTYPER Bit1(x)
.                       .
GPIO(Bit15)  =  OTYPER Bit15(x)
ถ้า x = 0  bitนั้น  =  Output Push-Pull
ถ้า x = 1  bitนั้น  =  Output Open drain
..............................................................................
GPIOx   ชื่อของ Port ต่างๆ เช่น GPIOA,GPIOB......
GPIOx-> เป็นรูปแบบการใช้งาน
GPIOA->ODR  เมื่อ ODR คือการกระทำตัวรีจีสเตอร์ทั้ง 32bit หมายเหตุ รีจีสเตอร์มี 32bit แต่ว่าขาที่ต่อ
ไม่จำเป็นต้องมี 32 ขา ในค่ายของ ST cortex M จะมีขาให้ใช้มากสุด  15 ขา หรือ 15bit

ตัวอย่าง GPIOA->ODR   = 0x1000F281; แต่รีจีสเตอร์ GPIOA แสดงออกที่ขาได้แค่ 0xF281

ใน #include "stm32f4xx.h"  จะมีการบบรจุตัวอ้างอิงใช้สือความหมายแทนค่าระดับ bit และ แทนรีจีสเตอร์ได้
เราสามารถนำค่าเหล่านั้นมาใช้เพื่อสื่อความหมายในการเขียนโปรแกรมได้

/******************  Bits definition for GPIO_MODER register  *****************/
#define GPIO_MODER_MODER0                    ((uint32_t)0x00000003)       //   เซ็ทเป็น อะนาล็ก บิท 0
#define GPIO_MODER_MODER0_0                  ((uint32_t)0x00000001)     //   เซ็ทเป็น  เอาท์พุท  บิท 0
#define GPIO_MODER_MODER0_1                  ((uint32_t)0x00000002)    //    เซ็ทเป็นขาฟังก์ชันร่วม บิท 0

#define GPIO_MODER_MODER1                    ((uint32_t)0x0000000C)       //   เซ็ทเป็น อะนาล็ก บิท 1
#define GPIO_MODER_MODER1_0                  ((uint32_t)0x00000004)     //   เซ็ทเป็น  เอาท์พุท  บิท 1
#define GPIO_MODER_MODER1_1                  ((uint32_t)0x00000008)     //    เซ็ทเป็นขาฟังก์ชันร่วม บิท 1

#define GPIO_MODER_MODER2                    ((uint32_t)0x00000030)
#define GPIO_MODER_MODER2_0                  ((uint32_t)0x00000010)
#define GPIO_MODER_MODER2_1                  ((uint32_t)0x00000020)

#define GPIO_MODER_MODER3                    ((uint32_t)0x000000C0)
#define GPIO_MODER_MODER3_0                  ((uint32_t)0x00000040)
#define GPIO_MODER_MODER3_1                  ((uint32_t)0x00000080)

#define GPIO_MODER_MODER4                    ((uint32_t)0x00000300)
#define GPIO_MODER_MODER4_0                  ((uint32_t)0x00000100)
#define GPIO_MODER_MODER4_1                  ((uint32_t)0x00000200)

#define GPIO_MODER_MODER5                    ((uint32_t)0x00000C00)
#define GPIO_MODER_MODER5_0                  ((uint32_t)0x00000400)
#define GPIO_MODER_MODER5_1                  ((uint32_t)0x00000800)

#define GPIO_MODER_MODER6                    ((uint32_t)0x00003000)
#define GPIO_MODER_MODER6_0                  ((uint32_t)0x00001000)
#define GPIO_MODER_MODER6_1                  ((uint32_t)0x00002000)

#define GPIO_MODER_MODER7                    ((uint32_t)0x0000C000)
#define GPIO_MODER_MODER7_0                  ((uint32_t)0x00004000)
#define GPIO_MODER_MODER7_1                  ((uint32_t)0x00008000)

#define GPIO_MODER_MODER8                    ((uint32_t)0x00030000)
#define GPIO_MODER_MODER8_0                  ((uint32_t)0x00010000)
#define GPIO_MODER_MODER8_1                  ((uint32_t)0x00020000)

#define GPIO_MODER_MODER9                    ((uint32_t)0x000C0000)
#define GPIO_MODER_MODER9_0                  ((uint32_t)0x00040000)
#define GPIO_MODER_MODER9_1                  ((uint32_t)0x00080000)

#define GPIO_MODER_MODER10                   ((uint32_t)0x00300000)
#define GPIO_MODER_MODER10_0                 ((uint32_t)0x00100000)
#define GPIO_MODER_MODER10_1                 ((uint32_t)0x00200000)

#define GPIO_MODER_MODER11                   ((uint32_t)0x00C00000)
#define GPIO_MODER_MODER11_0                 ((uint32_t)0x00400000)
#define GPIO_MODER_MODER11_1                 ((uint32_t)0x00800000)

#define GPIO_MODER_MODER12                   ((uint32_t)0x03000000)
#define GPIO_MODER_MODER12_0                 ((uint32_t)0x01000000)
#define GPIO_MODER_MODER12_1                 ((uint32_t)0x02000000)

#define GPIO_MODER_MODER13                   ((uint32_t)0x0C000000)
#define GPIO_MODER_MODER13_0                 ((uint32_t)0x04000000)
#define GPIO_MODER_MODER13_1                 ((uint32_t)0x08000000)

#define GPIO_MODER_MODER14                   ((uint32_t)0x30000000)
#define GPIO_MODER_MODER14_0                 ((uint32_t)0x10000000)
#define GPIO_MODER_MODER14_1                 ((uint32_t)0x20000000)

#define GPIO_MODER_MODER15                   ((uint32_t)0xC0000000)     //   เซ็ทเป็น อะนาล็ก บิท 15
#define GPIO_MODER_MODER15_0                 ((uint32_t)0x40000000)   //   เซ็ทเป็น  เอาท์พุท  บิท 1
#define GPIO_MODER_MODER15_1                 ((uint32_t)0x80000000)  //    เซ็ทเป็นขาฟังก์ชันร่วม บิท 15

เช่นต้องการให้  Bit 0, Bit 1 ของ GPIOA เป็น เอาท์พุต ได้  GPIOA->MODER   =  GPIO_MODER_MODER0_0|GPIO_MODER_MODER1_0 ;
ต้องการให้  Bit 0, Bit 15 ของ GPIOB เป็น เอาท์พุต ได้     GPIOB->MODER   =  GPIO_MODER_MODER0_0|GPIO_MODER_MODER15_0 ;

สุดท้ายอย่าลืมปล่อยสัญญาณ clock ให้ Port ที่ใช้งานด้วยครับเดี๋ยวจะไม่ทำงานกัน หลับปุ๋ย

 

#include"stm32f4xx.h"

void delay(long signed count)    //  ฟังก์ชันหน่วงเวลา
           {
            while(count--);
           }

void clock()   // ฟังก์ชัน ฐานเวลา
   {
                 RCC->CFGR      =   RCC_CFGR_HPRE_DIV1|RCC_CFGR_PPRE1_DIV4|RCC_CFGR_PPRE2_DIV2 ;
                 RCC->CR        =   0;
                 RCC->CR       |=   RCC_CR_HSEON;  // ให้ HSE Xtal เป็น ฐานเวลาหลัก     
                 while (!(RCC->CR & 0x00020000));//   รอเวลาให้  Xtal osc ทำงาน
                 RCC->PLLCFGR   =   (RCC_PLLCFGR_PLLQ_2|RCC_PLLCFGR_PLLQ_1|RCC_PLLCFGR_PLLQ_0
                                                 |RCC_PLLCFGR_PLLSRC_HSE);
                 RCC->PLLCFGR  |=   (RCC_PLLCFGR_PLLN_8 |RCC_PLLCFGR_PLLN_6 |RCC_PLLCFGR_PLLN_4);
                 // เซ็ทค่าความถี่ และตัวคูณต่าง  ดูข้อมูลใน  Ref-manual stm32f407xx
                 // หัวข้อการเซ็ทอัป system clock
                 RCC->CR       |=    RCC_CR_PLLON;      // สั่งให้ตัวคูณ PLL ทำงาน
                 while (!(RCC->CR & 0x02000000));      // รอจนกว่า PLL พร้อมทำงาน
                 FLASH->ACR     =    0x00000605;        // จัดเวลา Flash ROM is 5 Wait state
                 RCC->CFGR     |=    0x00000002;        //  เลือกสัญญาณหลัก System PLL On
                 while ((RCC->CFGR & 0x0000000F) != 0x0000000A); // รอระบบ Wait system Pll พร้อมทำงาน
                }

int main(void)   //  ฟังก์ชันโปรแกรมหลัก
                    {
                      clock();
                      GPIOD->OSPEEDR =   0xFFFF;   // Set Speed GPIOD is 100Mhz
      RCC->AHB1ENR    |=   0x08;     // Open clock to GPIOD
      GPIOD->MODER    =    (GPIO_OSPEEDER_OSPEEDR15_0 |GPIO_OSPEEDER_OSPEEDR14_0 |
                                                         GPIO_OSPEEDER_OSPEEDR13_0 |GPIO_OSPEEDER_OSPEEDR12_0);
                      // Set GPIO  D.15,D.14,D.13,D.12 is Output

                      while(1)  // ลูปวนค่าไม่รู้จบ
                                {
                                 GPIOD->ODR  ^=  0xF000;   // กลับค่าจากค่าเดิมก่อนหน้านี้
                                 delay(50000000);
}




                    }