เขียนไฟกระพริบทดสอบความเร็วของ STM32F103 ได้ความเร็วน้อยกว่าที่คิด

  • 8 Replies
  • 5475 Views
ลองเขียนไฟกระพริบทดสอบความเร็วของ STM32F103 ดังนี้ครับ
Code: [Select]
// main.c

#include "stm32f10x_lib.h"
#include "platform_config.h"

GPIO_InitTypeDef GPIO_InitStructure;
ErrorStatus HSEStartUpStatus;

void RCC_Configuration(void);
void NVIC_Configuration(void);

/*******************************************************************************
* Function Name  : main
* Description    : Main program.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void main(void)
{
#ifdef DEBUG
  debug();
#endif

  /* System Clocks Configuration **********************************************/
  RCC_Configuration();   

  /* NVIC Configuration *******************************************************/
  NVIC_Configuration();
 
  /* Initial LED */
  RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIO_LED, ENABLE );
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Pin = LED1_PIN;
  GPIO_Init( LED_PORT, &GPIO_InitStructure );
 
  while(1)
  {
    GPIO_SetBits( LED_PORT, LED1_PIN );
    GPIO_ResetBits( LED_PORT, LED1_PIN );
  }
}

/*******************************************************************************
* Function Name  : RCC_Configuration
* Description    : Configures the different system clocks.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void RCC_Configuration(void)
{   
  /* RCC system reset(for debug purpose) */
  RCC_DeInit();

  /* Enable HSE */
  RCC_HSEConfig(RCC_HSE_ON);

  /* Wait till HSE is ready */
  HSEStartUpStatus = RCC_WaitForHSEStartUp();

  if(HSEStartUpStatus == SUCCESS)
  {
    /* Enable Prefetch Buffer */
    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

    /* Flash 2 wait state */
    FLASH_SetLatency(FLASH_Latency_2);
 
    /* HCLK = SYSCLK */
    RCC_HCLKConfig(RCC_SYSCLK_Div1);
 
    /* PCLK2 = HCLK */
    RCC_PCLK2Config(RCC_HCLK_Div1);

    /* PCLK1 = HCLK/2 */
    RCC_PCLK1Config(RCC_HCLK_Div2);

    /* PLLCLK = 8MHz * 9 = 72 MHz */
    RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);

    /* Enable PLL */
    RCC_PLLCmd(ENABLE);

    /* Wait till PLL is ready */
    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
    {
    }

    /* Select PLL as system clock source */
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

    /* Wait till PLL is used as system clock source */
    while(RCC_GetSYSCLKSource() != 0x08)
    {
    }
  }
}

/*******************************************************************************
* Function Name  : NVIC_Configuration
* Description    : Configures Vector Table base location.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void NVIC_Configuration(void)
{
#ifdef  VECT_TAB_RAM 
  /* Set the Vector Table base location at 0x20000000 */
  NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else  /* VECT_TAB_FLASH  */
  /* Set the Vector Table base location at 0x08000000 */
  NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);   
#endif
}

#ifdef  DEBUG
/*******************************************************************************
* Function Name  : assert_failed
* Description    : Reports the name of the source file and the source line number
*                  where the assert_param error has occurred.
* Input          : - file: pointer to the source file name
*                  - line: assert_param error line source number
* Output         : None
* Return         : None
*******************************************************************************/
void assert_failed(u8* file, u32 line)
{
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

  /* Infinite loop */
  while (1)
  {
  }
}
#endif



ผลที่ได้บน Logic Analyzer อ่านค่าได้ประมาณ 0.333 us สำหรับช่วง On/Off
สิ่งที่ผมคิดว่าเกี่ยวข้องกับความเร็ว คือ
1. System Clock ได้ถูกตั้งไว้ที่ 72MHz
Code: [Select]
/* PLLCLK = 8MHz * 9 = 72 MHz */
    RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
[\code]

2. Clock ของ APB2 ตั้งไว้เท่ากับความเร็วของ System Clock คือ 72MHz
Code: [Select]
/* PCLK2 = HCLK */
    RCC_PCLK2Config(RCC_HCLK_Div1);

3. ค่า Initial ของพอร์ต ซึ่งตั้งไว้ที่ความเร็วสูงสุด 50MHz
Code: [Select]
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

ผมได้ทำการตามเข้าไปในฟังก์ชัน GPIO_SetBits,  GPIO_ResetBits เจอการทำงานแค่คำสั่งเดียว
ผมคิดว่าผลที่ได้ น่าจะเร็วกว่านี้ ไม่ทราบต้องเซ็ตอะไรเพิ่มเติมอะไรอีกครับ ไม่รู้ว่าสิ่งที่ผมเข้าใจถูกต้องหรือไม่ ช่วยชี้แนะด้วยครับ

สิ่งที่น่าสนใจ
1 ประมวลผลที่ความถี่ 72Mhz  (90MIPS) 
2 แฟตแมมโมลี่  การอ่านต้องใช้เวลาถึง 2สเต็ท
3 GPIOmax 50Mhz เอาอะไรมาวัดไม่มีบอก บอกแค่ทำงานได้สูงสุด 50Mhz แต่คล็อกที่ป้อน 72Mhz
4 ตามข้อ3 และข้อ2 นั้นคือ ที่72Mhz  เปลี่ยนค่าลอจิกจาก 1=> 0  ได้ความถี่สูงสุด 36Mhz
5  และ  ถ้าทำจากลอจิก 0=>1  ใช้ความถี่ อีกเท่า  แสดงว่าเราทำสัญญาณออกได้แค่  18Mhz เร็วสุด
6 และถ้าเป็นคำสั่งวนลูปกลับมา เสียค่าเวลาจั๊มกลับมาที่ตำแหน่งโปรแกรมก็จะได้ความถี่ ไม่เกิน 18Mhz แน่นอน
7 ถ้าใช้เวลา system clock.c  ในไลบารี จะถูก เซ็ทค่าเป็น 72Mhz ที่ความถี่ Xtal 8Mhz  (PLL_9)
   ลองเปลี่ยนจาก PLL_9 เป็น  2 ถึง 15 ดูครับ สังเกตุความแตกต่าง

บางที บริษัทก็บอกจุดขายที่สุงๆไว้ แต่ไม่เน้นจุดอ่อน  นั้นคือ ไม่ได้ปิดบัง ไม่ได้ไม่บอก  แต่ต้องอ่านให้ครบ ;D

เร็วที่คอร์ ก็เหมือนกับ CPU คอมพิวเตอร์ เร็วเป็นกิกที่การประมวลผล แต่ไม่ได้หมายความว่า GPIO จะทำได้เร็วตาม
บางค่ายเอาแต่ความเร็ว คอร์เป็นจุดขาย ในหน้าแรกๆแต่พอดูไปเรื่อย GIPO /2  Mem/2  แต่อย่างว่า
ถ้าทำให้ทุกอย่างทำงานเร็วเท่ากัน  ราคาคงแพงน่าดู     และที่สำคัญ ไม่มีความจำเป็นต้องให้ โมดูลเร็วเท่าประมวลผล
การอินเตอร์เฟส  I/O ก็เป็นปัญหาได้เร็วไป หาอุปกรณ์ต่อด้วยยาก เกิด บัคI/O   TPLH/TPHL  delay time เป็นต้น

ขอบคุณท่าน deejun มากครับ

ผลการทดลองมีดังนี้






จากผลการทดลอง ผมมีความคิดเห็นว่า ความเร็วของ GPIO มีแนวโน้มสามารถเพิ่มขึ้นไปเรื่อยๆ ตามค่าของตัวคูณความถี่ สูงสุดที่ x16 ได้ความเร็วประมาณ 2.66MHz ถึงกระนั้นก็ยังไม่ถึง 18MHz ที่ความเร็วสูงสุดตามที่ท่าน deejun บอก ส่วนความเร็วของ CPU ผมไม่มั่นใจว่าความเร็วสูงสุดอยู่ที่ตรงไหน เอาอะไรมาเช็ค ใน Datasheet บอกว่า Fmax = 48/72 MHz ความหมายของตัวเลขสองตัวนี้คืออะไรครับ

เท่าที่ผมเคยลองวัด เอาท์ที่หน้าตาดีเป็นพลัล ดูดี logic 0  ประมาณ 0.2V   logic 1 ประมาณ 3.1V
ความถี่ประมาณ  5Mhz เอาท์ออก และถ้าสูงไปเรื่อยๆ จากการสั่งในโปรแกรม  หน้าตาจะเริ่มเป็นสี่เหลี่ยนคางหมู
มีแดมปิ้งเข้ามาผสมด้วย  และยิ่งสูงขึ้น มันจะกลายเป็นสามเหลี่ยม  ขึ้นกลับ ค่า TPHLและTPLH ทางด้านดิจิตอล 
logic 0 อาจลงไม่ถึง 0V ของจริง  อาจจะ  1V หรือมากกว่า  logic 1 อาจไม่ใช่ 3.3V อาจทำได้แค่ 2.5-2.8v
หรือน้อยกว่า ค่าสลับไปมา จนทำไม่ทัน 

เท่าที่ศึกษา  50Mhz หมายความค่า เป็น GPIO Input ที่สามารถรับรู้ ความเป็น Logic 0 และlogic 1 ได้เร็วสุด
แยกข้อมูลทางอินพุตเร็วสุด

ระวังเครื่องวัดด้วยครับ  ไม่ว่าจะเป็นสโคปดิจิติอล หรือ logic analyzer  จะใช้หลักการ sampling สัญญาณเข้ามา
ถ้าแมมโมรี่น้อยๆ  ถึงจะsampling สูง   เวลามัน sampling แล้ว จะต้องเก็บในแมมโมรี่แล้วส่งออก  ถ้าแมมน้อย
อาจเกิดการทับซ้อนของข้อมูล  เวลาแสดงผลก็ทำให้ผิดพลาดไม่ใช้รูปแบบที่จริงก็ได้ครับ 

https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=%2Fpublic%2FSTe2ecommunities%2Fmcu%2FLists%2Fcortex%5Fmx%5Fstm32%2FMaximum%20Output%20Speed&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B&currentviews=919

https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=%2Fpublic%2FSTe2ecommunities%2Fmcu%2FLists%2Fcortex%5Fmx%5Fstm32%2FTrue%20performance%20of%20STM32&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B&currentviews=17748

ถ้าจะวิเคราะห์กันจริงๆ ต้องไปดูแอสเซมบี้ครับ ว่า 1 คำสั่งมันใช้กี่ instruction เราถึงได้ความเร็วในการประมวลผลของมันจริงๆครับ
รับเขียนโปรแกรม ออกแบบวงจร ไปจนถึง PCB
ไมโคร : 8/16/32 bit  ทุกตระกูล
สนใจติดต่อ
saintentex@gmail.com
หรือ 081-1846590

จับมาให้เห็นกันจ๊ะๆครับ :D
รูปที่ deejun1  ในลูป for มี  GPIOC->ODR  = 0; และ GPIOC->ODR = 1;
ซ้ำๆอยู่ มากกว่า 300ครั้ง ก่อนจะวนลูปกลับมาเริ่มใหม่


รูปที่2  deejun2 ในลูป for มี  GPIOC->ODR  = 0; และ GPIOC->ODR = 1;
เหมือนตัวอย่างของเจ้าของกระทู้ที่ทำ รอบเดียวกระโดดกลับมาใหม่ เห็นได้ชัดเจนถึง ช่วงเวลา
กระโดดกลับมา นานมาก 

รูปที่3 deejun3  ในลูป for มี  GPIOC->ODR  = 0; และ GPIOC->ODR = 1;
ซ้ำๆอยู่ มากกว่า 20 ครั้ง ก่อนจะวนลูปกลับมาเริ่มใหม่ จะเห็นว่าช่วงกระโดด for หรือ while
ใช้เวลามาก

       

ขอบคุณมากครับ
แนวคิดดูใน Asm ของท่าน Paekung น่าสนใจครับ ควรที่จะเป็นอย่างนั้น

ของท่าน deejun ทำได้ถึง 17.99MHz ถือว่าสูงมาก ผมต้องตั้งค่าอะไรผิดแน่ๆ
วันนี้ไปซื้อหนังสือ ปฏิบัติการไมโครคอนโทรลเลอร์ Arm Cortex M3 กับ STM32 ของ INEX มาอ่าน ขออ่านก่อนคืบหน้ายังไงเดี๋ยวมาเล่าให้ฟังครับ
(ขอบคุณมากครับที่อุตสาห์จิ้มสโคปมาให้ดูเลย)

*

Offline gui

  • ***
  • 111
    • View Profile
เสริมนิดนึงครับ
จากรูป deejun01 เป็นตามทฤษฎี สายส่ง (transmission) ถ้าสัญญาณสี่เหลี่ยมเรามีการเปลี่ยนแปลงเร็วมากๆ จะต้องพิจารณาลายทองแดงที่ต่อออกจากขาไอซีมายังอุปกรณ์เป็นสายส่ง  ถ้าไม่แมตช์อิมพีแดนซ์กัน จะทำให้เกิด Overshoot ตามรูป เลย เจ้า Overshoot ทำให้แรงดันที่พอร์ตมากกว่า Vcc มาก อีกช่วงทำให้แรงดันติดลบได้ ถ้ามากเกินทำให้พอร์ตนั้นๆ พังได้ครับ
ปล. ตามรูปก็เกินไม่มากครับ ไม่น่าเป็นอะไรครับ