Electoday 2025

ไมโครคอนโทรลเลอร์ => ARM Processors => Topic started by: tha on September 08, 2020, 08:42:55 AM

Title: GPIO STM32F1
Post by: tha on September 08, 2020, 08:42:55 AM
เดี๋ยวจะมาแปลให้ดูนะ แต่จะไม่เอาทั้งหมดนะ อันไหนที่ยังไม่ได้ใช้ก็จะไม่แปล เดี๋ยวจะเยอะเกินไป เยอะมาก ก็ลองหัดแปลกัน คำศัพย์มีไม่กี่ตัว

9.1.7 Input configuration(การกำหนดค่าอินพุท)
เมื่อ I/O Port ถูกโปรแกรมเป็น Input:
  • The Output Buffer ถูกปิดการใช้งาน
  • The Schmitt Trigger Input ถูกทำให้ทำงาน
  • The weak pull-up and pull-down resistors ถูกทำให้ทำงานหรือไม่ขึ้นอยู่กับ input configuration (pull-up, pull-down or floating):
  • The data ที่แสดงบน  I/O pin จะถูกสุ่มเข้าไปใน Input Data Register ทุกๆ APB2 clock cycle
  • A read เข้าถึง the Input Data Register จะได้ the I/O State.

(https://i.imgur.com/l0RV2ve.png)
Title: Re: GPIO STM32F1
Post by: tha on September 08, 2020, 09:18:15 AM
ดู Reference Manual ตามไปด้วยนะ


9.1.8 Output configuration
เมื่อ the I/O Port ถูกโปรแกรมเป็น Output:
  • The Output Buffer ถูกเปิดการใช้งาน:
        – Open Drain Mode: A "0" ใน the Output register ทำให้ the N-MOS ทำงาน ขณะที่ "1" ใน the Output register
           ทำให้ the port อยู่ในสถานะไฮอิมพิแด๊นต์ (Hi-Z )(the P-MOS จะไม่ถูกทำให้ทำงานเลย)
          ( Open Drain นี้จะต้องมี power supply ภายนอกมาต่อกัย load แล้วอีกขาหนึ่งของ load ก็มาต่อที่ output pin อีกที คือจะลง
          กราวน์ภายในตัว mcu )
       – Push-Pull Mode: A "0" in the Output register ทำให้ the N-MOS ทำงาน ขณะที่ "1" ใน the Output register ทำให้
          P-MOS ทำงาน
        ( mcu จะเป็นตัวจ่ายไฟให้ load ภายนอก)
  • The Schmitt Trigger Input ถูกทำให้ทำงาน
  • The weak pull-up and pull-down resistors ถูกปิดการใช้งาน.
  • The data ที่แสดงบน  I/O pin จะถูกสุ่มเข้าไปใน Input Data Register ทุกๆ APB2 clock cycle
  • A read เข้าถึง the Input Data Register จะได้ the I/O state ใน open drain mode
  • A read เข้าถึง the Output Data register จะได้ค่าที่เขียนเป็นครั้งสุดท้ายใน Push-Pull mode

(https://i.imgur.com/rbiaG3W.png)
Title: Re: GPIO STM32F1
Post by: tha on September 08, 2020, 02:51:55 PM
(https://i.imgur.com/YwYelWW.png)

(https://i.imgur.com/bArSDTk.png)

ถ้าเราเลือกให้เป็น input mode (MODE[1:0]=00 เราสามารถเลือกให้เป็น input แบบไหนก็กำหนดใน bit config CNFy[1:0]: ตามนี้ได้เลย
   00: Analog mode
   01: Floating input (reset state)
   10: Input with pull-up / pull-down
ถ้าเลือก Input with pull-up / pull-down จะให้เป็นแบบ Input  pull-up ก็กำหนดให้ Port Output Data Register bit นั้นให้เป็น '1' หรือจะให้เป็นแบบ Input  pull-down ก็กำหนดให้ Port Output Data Register bit นั้นให้เป็น '0' ดูตาม Table 20 นะครับ

ถ้าเราเลือกเป็น output mode (MODE[1:0] > 00 เราสามารถเลือกให้เป็น output แบบไหนก็กำหนดใน bit config CNFy[1:0]: ตามนี้ได้เลย
   00: General purpose output push-pull
   01: General purpose output Open-drain
   10: Alternate function output Push-pull
   11: Alternate function output Open-drain

เราจะเลือก mode เป็นแบบไหนก็กำหนดได้ที่ bit mode MODEy[1:0]: ตามนี้ได้เลย
   00: Input mode (reset state)
   01: Output mode, max speed 10 MHz.
   10: Output mode, max speed 2 MHz.
   11: Output mode, max speed 50 MHz.
Title: Re: GPIO STM32F1
Post by: tha on September 08, 2020, 03:25:29 PM
อย่างเช่นถ้าเราต้องการให้บิต PA0 เป็น input แบบ Floating ก็กำหนดดังนี้

   GPIOA_CRL = 0x00000004; 

ลองไล่บิตดูนะว่าถูกต้องไหม
ถ้าเราต้องการให้บิต PA4 เป็น output แบบ General purpose output push-pull และ Output mode, max speed 50 MHz. อีกด้วย ก็กำหนดเพิ่มมาดังนี้

   GPIOA_CRL = 0x00030004;

ปล. ผิดพลาดอย่างไร ท่านใดทราบ กรุณาแนะนำด้วยนะครับ
Title: Re: GPIO STM32F1
Post by: tha on September 08, 2020, 04:02:10 PM
ถ้าใช้ HAL ก็จะเขียนได้เป็นแบบนี้

static void MX_GPIO_Init(void)
   {

     GPIO_InitTypeDef GPIO_InitStruct;

     /* GPIO Ports Clock Enable */
     __HAL_RCC_GPIOA_CLK_ENABLE();

          /*Configure GPIO pin : PA0 */
         GPIO_InitStruct.Pin = GPIO_PIN_0;
         GPIO_InitStruct.Mode = GPIO_MODE_INPUT; // digital Input
         GPIO_InitStruct.Pull = GPIO_NOPULL;
         HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
   
     /*Configure GPIO pins : PA4 */
     GPIO_InitStruct.Pin = GPIO_PIN_4;
     GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

   }

ก็เอาตัวอย่างมาจากนี้ครับ
https://simonmartin.ch/resources/stm32/dl/STM32%20Tutorial%2001%20-%20GPIO%20Operations%20using%20HAL%20(and%20FreeRTOS).pdf (https://simonmartin.ch/resources/stm32/dl/STM32%20Tutorial%2001%20-%20GPIO%20Operations%20using%20HAL%20(and%20FreeRTOS).pdf)

ปล. ผิดถูกอย่างไร แนะนำกันมาเลย ผิดก็แจ้งมานะครับจะได้แก้ไข รับทราบที่ถูกต้องกันทุกฝ่ายนะครับ
Title: Re: GPIO STM32F1
Post by: tha on September 08, 2020, 04:10:57 PM
GPIO_InitTypeDef GPIO_InitStruct;  // มันหมายถึงอะไร ท่านใดทราบก็แนะนำกันด้วยครับ เสริมมาเลย ไม่ต้องเกรงใจ จะได้แน่นๆ
Title: Re: GPIO STM32F1
Post by: dec on September 08, 2020, 08:34:14 PM
Quote from: tha on September 08, 2020, 04:10:57 PM
GPIO_InitTypeDef GPIO_InitStruct;  // มันหมายถึงอะไร ท่านใดทราบก็แนะนำกันด้วยครับ เสริมมาเลย ไม่ต้องเกรงใจ จะได้แน่นๆ

มันคือตัวแปร Structure ที่รวม config parameter ต่างๆ ของ GPIO ครับ มีไว้เพื่อใช้ Init GPIO โดยเฉพาะครับ

Style ของ ST เค้าชอบออกแบบ Function ให้การ Init มันจบใน Function เดียว อย่าง HAL_GPIO_Init
ถ้า implement ให้ส่งค่า config เป็น parameter ทั้งหมด parameter มันจะดูยืดยาวและรกมาก

HAL_GPIO_Init(GPIOA, GPIO_PIN_4, GPIO_MODE_OUTPUT_PP, GPIO_PULLUP, GPIO_SPEED_FREQ_HIGH, 0x00);

ST เลยนิยาม Structure มาตัวหนึ่งมารวม config ต่างๆ ที่เป็นไว้ ให้เซ็ตค่า
แล้วก็ส่ง Pointer to Structure ตัวนี้เป็น Parameter ไปแทน

HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
Title: Re: GPIO STM32F1
Post by: tha on September 09, 2020, 07:29:09 AM
ขอบคุณครับ คุณ dec
มาดู Port input data register กันต่อ
bits เหล่านี้อ่านได้เพียงอย่างเดียวและสามารถเข้าถึงได้เป็นแบบ Word mode เพียงอย่างเดียว. register บรรจุค่าอินพุทของ the corresponding(ที่ตรงกัน) I/O port.

(https://i.imgur.com/FclH86B.png)

เราจะกำหนดแบบนี้ได้ไหม

   unsigned long A;
   A = GPIOA_IDR;

หรือตามตัวอย่างเขา

   /* read PA0 */
   if(GPIOA -> IDR & GPIO_PIN_0)
   {
       /* user code*/
    }

หรืจะใช้ HAL library function

   /* read PCA0 */
   if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0))
   {
       /* user code */
   }
Title: Re: GPIO STM32F1
Post by: tha on September 09, 2020, 07:54:01 AM
หรือจะใช้อย่างนี้ ท่านใดแจ้งมาให้ทำแบบนี้ ถูกไหมอย่างนี้ การเช็ค input PA0 ที่มีการ pull-up สวิทช์ภายนอก

   unsigned long A;
   A = GPIOA_IDR;
   if(~(A)==0x00000001)
  {
   /* user code */
  }
Title: Re: GPIO STM32F1
Post by: tha on September 09, 2020, 08:42:46 AM
หรือถ้าให้ PA3 เป็น input สวิทช์ ก็กำหนดแบบนี้ก็ได้ ดูที่บิตของมันว่ามีค่าเป็นเลขฐานสิบหกเท่าไหร่นะครับ

   unsigned long A;
   A = GPIOA_IDR;
   if(~(A)==0x00000008)
  {
   /* user code */
  }
Title: Re: GPIO STM32F1
Post by: tha on September 09, 2020, 10:10:50 AM
output bits เหล่านี้อ่านและเขียนได้โดยการเขียนโปรแกรมและสามารถเข้าถึงได้เป็นแบบ Word mode เพียงอย่างเดียว

(https://i.imgur.com/ynHC5Uz.png)

ทำแบบนี้ได้ไหม ให้ PA4 ทำงานบิตเดียว

   GPIOx_ODR = 0x00000010;
   
หรือ off ทั้งหมด

   GPIOx_ODR = 0x00000000;

ตัวอย่างในไฟล์ pdf ที่ดาวน์โหลดมา

   Turning on an output pin
    /* turn on PA4 */
   GPIOA -> ODR |= GPIO_PIN_4;

   Turning off an output pin
   /* turn off PA4 */
   GPIOA -> ODR &= ~GPIO_PIN_4;

   Toggle an output pins state
   /* toggle PA4 */
   GPIOA -> ODR ^= GPIO_PIN_4;

หรือจะใช้ HAL library function
   /* set PA4 */
   HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
   /* reset PA4 */
   HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
   /* Toggle PA4 */
   HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_4);

ปล. เรื่องการอ่านอินพุท จะทำอย่างนี้ได้หรือเปล่า บิตอินพุทบิตอื่นมันจะอ่านมาได้เป็น '1' เหมือน AVR หรือเปล่า เดี๋ยวมาลองดูกัน พรุ่งนี้นะครับ
Title: Re: GPIO STM32F1
Post by: tha on September 09, 2020, 03:04:24 PM
-
Title: Re: GPIO STM32F1
Post by: tha on September 09, 2020, 05:31:54 PM
เจอปัญหาแล้วครับ สวิทช์มันมี pull-up ภายนอก ปกติจะเป็น '1' กดสวิทช์แล้วจะเป็น '0' ต้องใช้รูปแบบนี้ครับ
Quote
         /* Reset PB8 */
     HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);
     HAL_Delay(500);
     /* Reset PB8 */
     HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET);

     /* -3- Toggle IO in an infinite loop */
     while (1)
     {
        /* read AC0 */
        if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)==GPIO_PIN_RESET)  //Check if button pressed
        {
          /* Set PB8 */
          HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);
        }
        /* read PC13 */
        if(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13)==GPIO_PIN_RESET)
        {
          /* Reset PB8 */
          HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET);
        }
       /* Insert delay 100 ms */
       HAL_Delay(500);
     }

เอามาจากตัวอย่างนี้ https://www.engineersgarage.com/stm32/push-button-and-led-with-stm32f103/ (https://www.engineersgarage.com/stm32/push-button-and-led-with-stm32f103/)
Title: Re: GPIO STM32F1
Post by: tha on September 10, 2020, 07:25:34 PM
เดี๋ยวจะต่อบอร์ด ET-STM32F103RB กับจอ LCD16x2 นะครับ จะใช้ตัวต่อ ET-CONV 14 LCD เป็นตัวต่อบอร์ดกับจอ LCD16x2 ลองโปรแกรมตัวอย่างที่มากับบอร์ดที่เป็นโปรแกรม Keil ได้แล้ว แต่ยังไม่ได้แก้ให้เป็น System Workbench for STM32 ว่าจะทำมะรืนนะ

(https://i.imgur.com/4hPgwmo.png)

http://www.ett.co.th/catalog2013/THAI/Page_87.pdf (http://www.ett.co.th/catalog2013/THAI/Page_87.pdf)
Title: Re: GPIO STM32F1
Post by: tha on September 10, 2020, 07:43:18 PM
ถ้าจะต่อกับจอ GLCD5110 ก็จะทำแบบนี้

(https://i.imgur.com/MXxNExW.png)

(https://i.imgur.com/daml84V.png)

(https://i.imgur.com/4aCyiwN.png)

           Hardware Configuration
      GLCD5110   |   STM32 Port
      ------------|-----------
      (1)VCC      |   VCC
      (2)GND      |   GND
      (3)SCE      |   PC0
      (4)RESET          |   PC1
      (5)D/C      |   PC2
      (6)SDIN      |   PC3
      (7)SCK      |   PC4
      (8)LED      |   PC5 // หลอด LED มันมี 4 หลอด ผมเลยเอา PC5 ไปขับผ่านทรานซิสเตอร์อีกทีนะครับ กลัวจะขับโดยตรงไม่ไหว

ลองทำกันดูนะครับ หรือท่านใดมีไอเดียอื่นๆก็แก้ไขได้ง่ายๆ
เดี๋ยวจะแก้ไขโปรแกรมที่มีอยู่แล้วให้เป็น System Workbench for STM32 นะครับ ขอเวลาหน่อย
Title: Re: GPIO STM32F1
Post by: tha on September 10, 2020, 07:52:12 PM
-
Title: Re: GPIO STM32F1
Post by: tha on September 11, 2020, 02:10:36 PM
-
Title: Re: GPIO STM32F1
Post by: tha on September 11, 2020, 02:34:07 PM
โปรแกรมย่อย Delay uS ของ HAL ดูแล้วไม่มี
ของโปรแกรม Keil จะเป็นแบบนี้
Quote
   void DelayuS(vu32 nCount)
        { 
           while (nCount--);
         }
โปรแกรม Systme Workbench for STM32 มันคอมไพล์ไม่ผ่าน ผมเลยเปลี่ยนมาเป็นแบบนี้
Quote
        void DelayuS(volatile unsigned long nCount)
   {
     while (nCount--);
   }
vu32 = volatile unsigned long ถูกต้องไหม แต่โปรแกรมก็ทำงานได้นะครับ
volatile หมายถึงอะไร ผมก็ลืมแล้ว ท่านใดทราบ ช่วยอธิบายด้วยครับ
Title: Re: GPIO STM32F1
Post by: tha on September 11, 2020, 07:19:12 PM
-
Title: Re: GPIO STM32F1
Post by: dec on September 11, 2020, 09:50:34 PM
volatile เป็นการนิยามว่า memory หรือตัวแปรส่วนนี้มีความแปรปรวนครับ
จะมีผลก็ต่อเมื่อเราเปิด optimizer ครับ compiler จะไม่ optimize ตัวแปรหรือ memory ที่เป็น volatile
จะจัดการอย่างตรงไปตรงมา

โดยปกติ compiler จะมองว่า memory หรือตัวแปรจะเปลี่ยนค่าก็ต่อเมื่อถูกเซ็ตค่า

เช่น
a = 1;

แต่ compiler จะพิจารณาแค่ไฟล์ต่อไฟล์เท่านั้น เช่น

ในไฟล์ main.c มีการประกาศตัวแปร global
int a = 1;

แล้วก็มีการใช้งาน
while(a);

แต่ไม่มีการเปลี่ยนค่า a ใน main.c อีก

ส่วนในไฟล์ interrupt.c มีการเปลี่ยนค่าตัวแปร a
a = 0;

ถ้าเราเปิด optimizer ขณะที่ compiler ทำการ compile ไฟล์ main.c compiler ก็จะมองแค่ไฟล์ main.c ไฟล์เดียว
ไม่ได้สนใจว่า interrupt.c จะมี code อะไร ทำให้ compile เข้าใจว่า a มีค่าเป็น 1 แล้วก็ไม่มีการเปลี่ยนค่าอีก
compiler เลยทำการแทนที่ a ใน code main.c ด้วยค่า 1 เลยทั้งหมด แม้โปรแกรมจะทำงานมาถึงไฟล์ interrupt.c
และเปลี่ยนค่าตัวแปร a ไป ก็ไม่สามารถทำให้หลุดจาก while ได้

อีกกรณีก็พวก register ที่จะถูกเซ็ตค่าโดย hardware ตอน compile ตัว compiler จะมองว่ามันเป็นแค่
memory ตำแหน่งหนึ่ง แล้วก็มีการอ่านค่ามาอย่างเดียว ไม่มีการเซ็ตค่า ก็เสี่ยงที่จะถูก optimize ได้
เราจึงมักจะนิยาม register ให้เป็น volatile เพื่อป้องกันไม่ให้ compiler optimize ครับ

ส่วนใน function delay นั่น ถ้าตัวแปร nCount ไม่ใช่ volatile optimizer มันจะมองว่า while มันเป็น loop เปล่าๆ
และ nCount หลังจากหลุด while ไปแล้วมันก็ไม่ได้ใช้งานอะไร มันจะลบ loop ทิ้งเอาดื้อๆ เพราะมองว่ามันเสียเวลาโดยเปล่าประโยชน์
แต่ถ้า nCount เป็นตัวแปร volatile มันก็จะตัด loop ออกไม่ได้ เพราะ compiler จะไม่ optimize แต่แปร nCount และตัวแปร nCount
ต้องถูกนับลดและอ่านค่าอย่างตรงไปตรงมา ทำให้ loop ยังอยู่ครับ
Title: Re: GPIO STM32F1
Post by: tha on September 12, 2020, 08:06:05 AM
-
Title: Re: GPIO STM32F1
Post by: tha on September 12, 2020, 09:36:00 AM
-
Title: Re: GPIO STM32F1
Post by: tha on September 12, 2020, 09:54:47 AM
-
Title: Re: GPIO STM32F1
Post by: tha on September 12, 2020, 05:03:10 PM
-