顯示具有 STM32 標籤的文章。 顯示所有文章
顯示具有 STM32 標籤的文章。 顯示所有文章

2016年3月8日 星期二

[STM32] 如何取到STM32 MCU的Serial ID


unsigned int serial_id[3];

serial_id[0] = *((unsigned int *)0x1FFFF7E8));
serial_id[1] = *((unsigned int *)0x1FFFF7EC));
serial_id[2] = *((unsigned int *)0x1FFFF7F0));

Reference:
[1] http://www.keil.com/forum/58081/read-unique-id/

2014年1月1日 星期三

[STM32] 使用STM32F103CB TIMx 實做 us_delay

圖一

要使用STM32的Timer功能,首要條件,須要先搞清楚目前自己的RCC配置(圖一紅色框框),筆者的RCC設定為(system_stm32f10x.c)如下:

    /* HCLK = SYSCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;  // APB
    
    /* PCLK2 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1; // ABP1
   
    /* PCLK1 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2; // APB2 

清楚RCC設定後,再來就是TIMx的設定(以下使用TIM4做介紹),使用TIMx有2個小觀念要先建立,
  1. 決定1個Clock從High到Low的時間多久 ( TIMx_CNT)
  2. 決定幾個Clock之後要發出interrupt ( TIMx_ARR )
  3. TIMx_PSC 計算公式 : Counter Clock Frequency = fCK_PSC / (PSC[15:0] + 1)
搞清楚後,撰寫部分就簡單了,可參考以下us_delay的實做,

// 製作 us_delay :
// 1. 產生 6MHz的Counter Clock Frequency,即表示1Clock = 1/6 us
// 2. 1 us = 6 clock一個interrupt
// 3. Counter Clock Frequency = fCK_PSC / (PSC + 1)
//     6M = 72M / ( PSC + 1 ) => PSC = 72M/6M -1
//     因為 APB1不為1(RCC設定得知),所以fCK_PSC = 36M * 2= 72M

static __IO uint32_t TimingDelay;

static void RCC_Configuration()
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
}

static void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;

  /* Enable the TIM2 global Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

  NVIC_Init(&NVIC_InitStructure);
}

// 處理 interrupt
void Delay_IRQHandler(void)
{
  if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET)
  {
            TIM_ClearITPendingBit(TIM4 , TIM_FLAG_Update);
            if (TimingDelay != 0x00)
            {
                TimingDelay--;
            }
  }
}

void delay_us(__IO uint32_t nTime)
{
  TimingDelay = nTime;

  while(TimingDelay != 0);
}

void DelayInit()
{
  u16 PrescalerValue = 0;
  u32 CounterClock = 6000000; // 6M
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  
  RCC_Configuration();
  NVIC_Configuration();
   
  PrescalerValue = (uint16_t) (SystemCoreClock / CounterClock) - 1;
  TIM_TimeBaseStructure.TIM_Period = 6; // TIMx_ARR
  TIM_TimeBaseStructure.TIM_Prescaler = PrescalerValue; //TIMx_PSC
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
   
  TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
  TIM_Cmd(TIM4, ENABLE);
  TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);
}

Reference:
[1] STM32通用定时器(TIM2-5)基本用法
[2] STM32F1

2013年11月29日 星期五

[FreeRTOS] FreeRTOS 移植到 STM32F407Discovery

Porting FreeRTOS最快的方法,就是利用FreeRTOS官網提供DemoCode來改,不過因為DemoCode所使用的STM32 Driver都是比較舊的,而且程式碼又較複雜,所以還是整理一份比較乾淨的版本,掌握度會比較高。
  • FreeRTOS (使用STM32F407)
    圖一
    圖一是FreeRTOS Source目錄架構,這個資料夾是FreeRTOS的核心。而要使用FreeRTOS有幾個重點要注意,
    • Complier
      路徑:Source\portable\{ComplierVersion}\{CPU}\port.c
      • Complier : RVDS(Keil) or GCC
      • CPU : (ARM_CA9/ARM_CM3/ARM_CM4F)

    • MemoryManagement
      路徑:Source\MemMang\heap_X.c
      • X:heap有四個版本
    • FreeRTOSConfig.h
      路徑: Demo\{MCU}\FreeRTOSConfig.h
      • MCU: 這個檔案是根據MCU來設定,通常直接拿DemoCode的來用,不過還是要根據MCU的硬體來設定,所以我選用Demo\CORTEX_M4F_STM32F407ZG-S\FreeRTOSConfig.h
  • STM32 Driver
    • STM32F4xx_StdPeriph_Driver
      此資料夾是STM32的周邊Driver,通常會使用最新版,而我習慣使用GPIO來改。
    • Peripheral_Examples此資料夾是STM32的Demo程式,我習慣使用GPIO來做修改。
  • Porting
  • 圖二
    圖二為程式的目錄架構和要Import的檔案,而接下來就是如何讓FreeRTOS跟STM32綁在一下,有三個重要function需要介接
    • vPortSVCHandler();
    • xPortPendSVHandler();
    • xPortSysTickHandler(); 
    介接這三個Function,以下提供兩個方法
    • 1. 修改 startup_stm32f4xx.s
      將紅色框框的部分加入到startup_stm32f4xx.s
    圖三
    • 2. 修改FreeRTOSConfig.h將紅色框框的部分加入到FreeRTOSConfig.h (如果Complier時,發生multiply defined,記得把它助解,通常會是stm32f4xx_it.c檔案裡)
    圖四
    完成以上步驟,大致上就已經完成Porting部分,接下就是用他啦摟,

    #include "stm32f10x.h"
    #include "FreeRTOS.h"
    #include "task.h"

    void vTask( void *pvParameters )
    {  
        portTickType xLastWakeTime = xTaskGetTickCount();
       
        while(1)
        {
            // do something
            vTaskDelayUntil( &xLastWakeTime, ( 500 / portTICK_RATE_MS ) );
        }
    }

    int main ()
    {
        xTaskCreate( vTask, ( signed portCHAR * ) "Task1", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
        vTaskStartScheduler();

        while(1);
    }
  • Note
    Reference [4]
    是已經Porting FreeRTOS for STM32F407-Discovery

Reference:
[1] FreeRTOS 
[2] STM32F4 入門教學:FreeRTOS 移植
[3] STM32 Driver 
[4] DemoCode - STM32F407VG-FreeRTOS

2013年11月26日 星期二

[STM32] 如何使用Keil內建函數,printf & scanf

printf & scanf 在嵌入式系統來說,都是一個非常好用但奢侈的功能,但為了加速開發時程,往往不會希望花太多時間重寫一個這樣的功能,所以最容易的方式就是直接用。當然要使用這兩個函數必須指定要輸出/輸入到哪個地方,而最常被拿來使用的,就是USART了。在Keil上只要設定以下幾個部分: (以下使用Polling方式)
  • Use MicroLIB
    [Project] -> Options for Target ... -> [Target] -> [Use MicroLIB] 
圖一
  • Implement PUTCHAR_PROTOTYPE & GETCHAR_PROTOTYPE
  • #include <stdio.h>
    #define USART_TYPE        USART1

    #ifdef __GNUC__
      #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
      #define GETCHAR_PROTOTYPE int __io_getchar(void)
    #else
      #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
      #define GETCHAR_PROTOTYPE int fgetc(FILE *f)
    #endif /* __GNUC__ */

    // Implement
    PUTCHAR_PROTOTYPE
    {
      /* Write a character to the USART */
      USART_SendData(USART_TYPE, (u8) ch);

      /* Loop until the end of transmission */
      while(USART_GetFlagStatus(USART_TYPE, USART_FLAG_TXE) == RESET);
      return ch;
    }

    GETCHAR_PROTOTYPE
    {
       /* Loop until the end of receive */
       while(USART_GetFlagStatus(USART_TYPE, USART_FLAG_RXNE) == RESET);
     
       /* Read a character to the USART */
       return (USART_ReceiveData(USART_TYPE));

    }

  • 主程式 initial usart & 直接使用printf & scanf
  • #include<stdio.h>

    int main()
    {
            uint8_t data;
            USART_Init(); // 注意,記得要啟動要導向裝置
            while(1) {
                   scanf("%c\n",&data);
                   printf("Data = %c",data);
            }
    }

Reference:
[1] 在MDK使用printf&scanf

2013年11月25日 星期一

[STM32] 使用STM32F103CB USART功能之注意事項


在STM32撰寫 USART的程式碼,有幾個部份需要注意的
  1. 確認程式碼與要使用的腳位是否一致
  2. 確認Pin Mapping是否正確
  3. 確認雙方溝通的Baudrate是否一致
  4. 確認是使用Interrupt模式還是Polling模式
  5. 確認外部震盪器的值設定是否正確
基本上,1~4點,網路上都已經有清楚與完整的程式碼說明,但如果都已經確認程式碼沒問題了,但是還是無法正常傳送(Ex:有時候值是對的,有時候錯的),那使用示波器之前,你也可以先檢查你的 External oscillator (HSE/HSI)到底是幾Hz的,由於STM32的Sample Code的 External oscillator(HSE)是8MHz,不過從圖一可知道外接震盪器可接4~16Hz,故須注意此部分。 需要修改檔案 stm32f10x.h 的 HSE(High Speed External Clock Signal)和system_stm3210x.c的RCC部分。
  • stm32f10x.h 搜尋HSI和HSE修改成正確數值(圖二)。

圖二
  • system_stm3210x.c
  • 當把HSE修改成16000000Hz,必須做相對應的調整,首先找到SetSysClockTo72()
圖三
    • ADCCLK必須小於14MHZ,修正如下
    • 圖四
    • 開啟PLLXTPRE除二功能
    • /*  PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
      RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |  RCC_CFGR_PLLMULL));

      RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9 | RCC_CFGR_PLLXTPRE);
     

Reference: 
[1] STM32F1 入門教學:USART / UART 字元(Char)發送 
[2] 第四步:STM32固件库以及编程起步(GPIO,UART) 
[3] [STM32] 关于USART接收中断的BUG和注意事项  

2013年11月20日 星期三

[STM32] 驗證STM32103CB的USART Baudrate Value

圖一

BRR(Baud Rate Register)是用來設定USART Baudrate的Register,一開始設定baudrate=9600,從Debug發現BRR得到一個0x1D4C(圖一)的值,在好奇心的驅使下,我開始翻手冊,查知BRR的算法如下圖二

圖二
 所以說...,帶入baudrate =9600 、 F = 72000000Hz,可得USARTDIV=468.75,接下來是把這個值,存入BRR,方法為圖三,其中
  • DIV_Mantissa為整數部分
  • DIV_Fraction為小數部分

圖三
則 468 = 111010100b、0.75 = 1100b,故可得知468.75 = 1110101001100b = 0x1D4C

Note:

選擇baudrate,須注意不同的baudrate的有不同錯誤率,可參考圖四

圖四
 Reference :
 [1]  STM32F4 Series (RM0090 - Reference Manual)
 [2]  STM32F4 Series 

2013年11月7日 星期四

[STM32] MPU6050 陀螺儀/加速器換算方式

圖一(圖片來至google)

最近在研究Quadcopter,需要使用加速度計和陀螺儀來做為平衡的依據,而選用的晶片是MPU6050(如圖一),首先先簡易了解一下晶片的一些特性

1. 三軸陀螺儀(Gyroscope)
  •  數位輸出X,Y,Z的角速度(°C)
  •  Range : ±250, ±500, ±1000, and ±2000°/sec 
2.三軸加速度計(Accelerometer)
  •  數位輸出X,Y,Z的重力(g)
  •  Range : ±2g, ±4g, ±8g, and ±16g 
3.其他特性
  • 使用I2C與MCU溝通
  • 可以外加地磁計(Magnetometer),組成九軸偵測
4. Block Diagram
  • X/Y/Z  Accel、X/Y/Z-Gyro 經過ADC轉換,儲存Sensor Registers,最後再透過I2C介面提供data給MCU。
看完基本特性之後,開始研究程式碼,雖然官方有提供8051跟arduino的Source Code 不過我採用是由Harinadha Reddy Chintalapalli所提供的MP6050lib for STM32

#include "mpu6050.h"
int main()
{
     s16 Buffer[6]={0x00};
     MPU6050_Initialize();

    while ( 1 ) {
        // index:0~2 acceleration
        // 3~5 Angular rate
        MPU6050_GetRawAccelGyro(Buffer);  
    }
}


從Debug Mode,確定已經可以取到加速度和腳速度的值(圖二)。
圖二

但問題又來了,這些值,到底代表甚麼含義呢??還有要如何測試呢??
首先從MPU6050 Doucment得到以下幾個資訊(圖三)

圖三
  • 使用二的補數來表示正負號 
    • 正號 : 0x0000~0x7FFF ( 0 ~ 32767)
    • 負號 : 0x8000~0xFFFF ( 32768 ~ 65535 )
  • Gyroscope (AFS_SEL =  0)
    • 測量角速度
    • 131 LSB/°:表示一度使用131表示
      • 正號 : 0x0001~0x7FEE (  1 ~ 32750 )
      • 負號 : 0xFFFF~0x80C7 ( -1~-32750 )
    •  測試方式
      • 理論上,在靜止時,角速度的值應該都要為0,但從圖二可得知,實際上並不為0,會有一個誤差值,不過我測試的結果,大概誤差在正負1~2度左右,還在可接受範圍內。
      • 針對X/Y/Z軸,做順時針與逆時針旋轉,可得知值變化狀態

  • Accelerometer (AFS_SEL =  0)
    • 測量加速度
    • 16384 LSB/mg :表示1g使用16384表示
      • 正號: 0x0001~0x7FFF ( 0~ 32767 )
      • 負號: 0xFFFF~0x8000 (-1~-32768 )
    • 測試方式
      • 如果因為某些因素讓你無法得知,你的晶片方向,那你可以使加速度計來得知,因為只要是水平的放,那三軸中必有一軸須承受地心引力(1g),以圖三index[2](Z軸)的值為16700,而約等於16384,差不多為1G,而在90度的翻轉向X或Y軸(圖四),在觀察16384的值會落在哪個index上,就可以得知X,Y,Z三軸的位置。
        圖四

2013年11月5日 星期二

[STM32] Discovery USART1 (PA9\PA10不可用)

最近測試了Discovery USART,由於在Reference Manual上寫說,USART1 Mapping to PA9/PA10 or PB6/PB7,但是測試了半天,PA9/PA10這兩根PIN腳,總是無法正常work,最後這篇部落格(stm32f4-discovery USART1 (PA9\PA10不可用) )得知,結果是因為Discovery本身的硬體有點衝突,PA9/PA10跟一顆4.7uF的電容並聯(圖一),所以會造成無法產生正常的USART波形。

圖一

Reference:
[1] stm32f4-discovery USART1 (PA9\PA10不可用)
[2] Using USART1 on the STM32F4Discovery

2013年9月30日 星期一

[STM32] STM32 Bus

圖1. STM32F40x Block Diagram (By STM32 Reference Manual)

Bus是元件之間,交換資料的一個通道,我們從STM32 Discovery Block Diagram(由圖1)的顏色,得知Bus可分成高速(紅色)和低速兩種:
  • Advanced High Performance Bus
    •  AHB1
      • Max up to 168MHz
      • Connect to USB OTG HSDMA2DETHERNET MACDMA2DMA1BKPSRAMFlash interfaceRCCCRCGPIO_X(X=A…K)

    •  AHB2
      • Max up to 168MHz
      • Connect to RNGHASHCRYPDCMIUSB OTG FS

    •  AHB3
      • Connect to FSMC(External memory controller)

  • Advanced Peripheral Bus
    • APB1
      •  Max up to 42MHz
      • Connect to UART8UART7DACPWRCAN2CAN1I2C_X(X=1…3)UART5UART4USART3USART2I2S3extSPI3/I2S3SPI2/I2S2I2S2extÍWDGWWDGRTC&BKPTIM_X(X=14…12)TIM_X(X=7…2)

    • APB2
      • Max up to 84MHz
      • Connect to LCD-TFTSAI1SPI5SPI6TIM_X(X=9…11)EXTISYSCFGSPI4SPI1SDIOADC_X(X=1…3)USART6USART1TIM8TIM1

Reference :
[1] STM32 Clock Configuration
[2] STM32F4 SeriesSTM32F4 Series (RM0090 - Reference Manual)