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

  • 9 Replies
  • 4347 Views
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กัน


Register ที่ควรศึกษา


  GPIOx->MODER   
  GPIOx->OTYPER                  0-PushPull, 1-OpenDrain
  GPIOx->OSPEEDR              Output SPEED Register    : 00-2, 01-25, 10-50, 11-100 [MHz]
  GPIOx->PUPDR                   PullUp PullDown Register : 00-none, 01-Pup, 10-Pdn, 11-reserved
  GPIOx->IDR                        Input Data Register
  GPIOx->ODR                      Output Data Register
  GPIOx->BSRRL                    Bit Set Reset Register Hi: bit  sets  PortPin
  GPIOx->BSRRH                   Bit Set Reset Register Lo: bit resets PortPin
  GPIOx->LCKR                     LoCK Register
  GPIOx->AFR[0]                   Alternative Function Register Lo - select 1of16
  GPIOx->AFR[1]                   Alternative Function Register Hi - select 1of16


 
ถ้าท่านใช้ขาที่เลือกเป็น 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 ที่ใช้งานด้วยครับเดี๋ยวจะไม่ทำงานกัน หลับปุ๋ย


 



Code: [Select]
#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);
}




                    }   

หรืออีกรูปแบบ
Code: [Select]
#include"stm32f4xx.h"

//CPU 8 Mhz Xtal OSC and PLL is 168Mhz   
//AHB  system clock 168 Mhz
//APB1 system clock  42 Mhz
//APB2 system clock  84 Mhz

void delay(long signed count)
           {
            for(;count>0;count--);
           }
void clock_setup(void)
{
RCC->CFGR    =    0;         
RCC->CR        =    0;
RCC->CR       |=  0x00010000;  // select HSE Xtal is main clock
                                 while (!(RCC->CR & 0x00020000));// wait time to Xtal osc stability
                                 RCC->PLLCFGR  =   0x07405408;      // Set PLL   M=8, N=336, P=2 ve Q=7
RCC->CR |= 0x01000000;            // PLL On
                                 while(!(RCC->CR & 0x02000000))
                                 FLASH->ACR = 0x00000605;        // Flash ROM is 5 Wait state
                                 RCC->CFGR |= 0x00000002;        // System PLL On
                                 while ((RCC->CFGR & 0x0000000F) != 0x0000000A); //
}
int main(void)
                    {
                      clock_setup();
                      GPIOD->OSPEEDR     =    0xFFFF;  // Set Speed GPIOD is 100Mhz
                      RCC->AHB1ENR       |=    0x08;    // Open clock to GPIOD
                      GPIOD->MODER        =    0x55000000;  // Set GPIO  D.15,D.14,D.13,D.12 is Output
                      while(1)
                                 {
                                   GPIOD->ODR  ^=  0xF000;
                                   delay(50000000);
                                 }
}


}




*

Offline tha

  • *****
  • 1072
    • View Profile
 เสร็จแล้วหนึ่งโปรเจ็คไฟกระพริบสี่ดวงพร้อมกัน ชักจะเป็นแล้วครับ Thank! :D

งง เรื่องการเซ็ตอัพมาตั้งแต่บทแรกเลยครับ มีพื้นฐานมาแค่ arduino พี่ๆมีคำแนะนำไหมครับ T^T
ซัพเฉพาะ เยอะมากเริ่มจากไหนดีครับ

สุดยอดเลยครับ เขียน STM32 ได้โดยไม่ต้องง้อ Library
น่าจะลด code size ลงได้เยอะมาก


*

Offline tha

  • *****
  • 1072
    • View Profile
ซื้อบอร์ดใหม่มาแล้วครับ ที่เคยศึกษาไว้ลืมไปหมดแล้ว มีโพสต์ก็ดีอย่างนี้แหละครับ ข้อมูลยังอยู่  >:(

*

Offline spiin

  • **
  • 26
    • View Profile

*

Offline Irumi

  • *
  • 16
    • View Profile
 มีข้อสงสัยเกี่ยวกับ GPIOx->OSPEEDR  อยากสอบถามครับ
 คือ OSPEED มีความเกี่ยวข้องกับ System Clock config หรือไม่ครับ ถ้าผมใช้ board stm32d401re nucleo ซึ่ง maximum clock คือ 84MHz ถ้าเลือกใช้ OSPEED = 100MHz จะมีปัญหาไหมครับ