2015年5月29日 星期五

直流無刷馬達BLDC



最近四軸飛行器很流行, 很多發行器裝的都是直流無刷馬達(BLDC). 所以拿來玩玩看, 其實CD ROM等光碟機、硬碟機裡面使用的馬達也是直流無刷馬達。
BLDC 之所以稱無刷直流馬達,是因為 BLDC 無須透過電刷進行電流換相,且馬達特性與 DC Motor 相同,轉速同樣由繞組線圈的電壓決定,與 DC Motor 相比少了噪音與電刷磨損的問題。

BLDC規格:

A2217 (1750KV)
1750KV值的意義為何? 愈大的KV值表示其轉速愈快1750KV表示每1伏特為1750 RPM (無負載時), RPM : 1分鐘幾轉; 若是10伏特,則有17500轉 (無負載時)。相關規格如下
工作電壓 :  6.5V~12V
電壓 電流     推力
8V       18.6A    816克
7.5V    16.9A   739克
7V       15.1A      653克
6.5V    13.6A   578克
11.1V  30A    1000克

BLDC為1750KV

線圈在內旋轉時不動

BLDC驅動電路板:

另外, BLDC 沒有辦法像DC馬達可直接通電旋轉,需透過驅動電路將單一直流電轉換成三相電流。底下這個BLDC驅動電路板, 給它PWM 訊號就可以由它送出三相訊號來控制BLDC. 
BLDC工作頻率和一般伺服馬達Servo 工作頻率一樣, 50HZ (週期為20000us), 試了一下這個驅動電路板, 一開始必須先送出一個pulse , 寛度是1000us就會進入初始狀態,也就是可以開始工作了, 接著再送出其他不同的pulse寛度就會旋轉,以這一顆BLDC, 實驗的結果是pulse 寛度 為 1300us~2000us。當pulse 寛度1300us開始旋轉, 愈接近2000us轉速愈快。若pulse 小於1300us 則停止轉動



 
BLDC驅動電路板 (3線連接馬達隨便接; 另外粗的2條是馬達電源接電源供應器; 3條細線給控制板電源, 其中白色為PWM訊號線)

驅動電路板拆解後正面, 控制板MCU為PIC
驅動電路板拆解後背面



DEMO 
 利用Raspberry Pi 搭配艾鍗擴充應用板上的16 channel PWM 來輸出PWM訊號以控制BLDC

艾鍗Pi擴充應用板,具16 channel PWM 輸出功能









2015年5月25日 星期一

在Raspberry Pi B+ & Pi2 上面學 Linux 驅動程式開發 -- GPIO Button 中斷 --

實驗名稱

    Raspberry Pi & Pi2, Linux 驅動程式開發 -- GPIO --

實驗目的

    簡單介紹在Raspberry Pi Linux 系統底下,如何使用GPIO。

使用材料及設備

    硬體: Raspberry Pi & Pi2, Ittraining Edu Kit 子板

    軟體: 可編譯 Linux Module 的 Raspbian 系統。

原理介紹

GPIO 是嵌入式系統中極為重要的功能,但是在一般的桌機與筆電系統之中卻很少見。一般MCU在操作GPIO時是直接透過寫入資料到對應的暫存器來控制其輸出入。但是在Raspberry pi 上則是透過 Linux 系統提供的 API 來操作GPIO。

本篇文章會使用艾鍗科技出產的教學子板來做示範-- 利用教學子板上的GPIO 按鍵來實作驅動程之中GPIO 中斷的使用方式。GPIO 按鍵按下後會去點亮GPIO LED。

無子板的話也可以使用麵包板自行實作電路達到相同的效果。



程式說明

程式碼內容

---------------- CODE -----------------

---------------- CODE -----------------

程式架構

此模組除了最基本的進入點函式 init_module() 和離開點函式cleanup_module()之外,還有這次的主題中斷處理函式 button_isr()。

中斷點處理函式 button_isr()被核心呼叫的時機為指定中斷訊號發生的時候。這樣的機制會在指定中斷處理函式和指定中斷訊號做連結(使用核心提供的函式)之後生效。

就此模組而言,按鈕的 GPIO 輸入電位產生 Rising-Edge (上緣觸發) 的變化時系統會發出一個特定中斷訊號給核心,然後核心就會去呼叫和此特定中斷訊號相對應的中斷處理函式 button_isr(); 切換 LED 的 GPIO 輸出電位,藉此控制LED的亮暗。


程式碼說明

程式碼一開始定義了指定按鈕使用 GPIO23,而LED 使用 GPIO27。所以在程式進入點使用了gpio_request(LED) 對系統提出使用該GPIO 的申請,成功的話回傳0,失敗的話回傳一個負值錯誤碼。再指定 LED 為輸出並初始輸出電位為 low : gpio_direction_output(LED, 0 ),回傳值為0表示成功。這兩個API函式的介面如下

int gpio_request(unsigned int gpio, const char *label);
int gpio_direction_output(unsigned int gpio, int value);

按鍵的 GPIO 部份,同樣要先向系統申請
使用: gpio_request(BUTTON)。如果該GPIO有相對應的中斷號碼,則可以使用函式 gpio_to_irq(BUTTON) ,會回傳對應該GPIO的中斷號碼,如果失敗的話會回傳一個負值。

int gpio_to_irq(unsigned int gpio);

知道中斷號碼之後,我們需要使用稍微複雜一點的函式註冊指定的中斷處理函式給指定的中斷號碼。

註冊中斷處理函式給對應的中斷號碼

request_irq( button_irq, button_isr ,IRQF_TRIGGER_RISING, MY_GPIO_INT_NAME, MY_DEV_NAME);

button_irq 為中斷號碼,是由函式 gpio_to_irq() 回傳得到,而 button_isr 是中斷處理函式的函式指標,經過註冊之後硬體引發該中斷號碼給核心,核心就會去執行button_isr() 函式。

設定值 IRQF_TRIGGER_RISING 是指定設定該 GPIO 當輸入電位由低向高變化的時候引發中斷(上緣觸發),當然還有其他的設定值如下緣觸發: IRQF_TRIGGER_FALLING ,設定時可以用符號 "|" 來做成上緣下緣都會觸發中斷的設定值: 

IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING

而 MY_GPIO_INT_NAME 為字串 "my_button_int",代表中斷名稱,在註冊成功之後會出現在系統檔案之中 /proc/interrupts。 可以用下列指令來顯示系統中目前所有的中斷名稱。系統裡面所有的中斷名稱可以使用指令 "cat /proc/interrupts" 顯示出來,裡面會有系統中所有的中斷訊號的資訊,包括引發的資數

而 MY_DEV_NAME 為字串 "my_device"。其實request_irq()的最後一個參數的資料形態為 ( void * ),這個指標會在呼叫中斷處理函式的時候從第二個參數傳入。如果你設計的中斷處理函式有需要用到一個自行維護的資料的話,可以透過這個指標傳入。沒有用到的話傳入NULL也行。只是這邊我們傳入該模組自行維護的模組名稱的字串進去。

而 request_irq() 註冊中斷處理函式成功的話會回傳 0 。之後在按下按鍵之後,放開按鍵的時候會讓 GPIO23 引發中斷訊號,該中斷訊號會有一個特定的中斷號碼,系統會依照接收到的中斷號碼去呼叫對應的中斷處理函式 button_isr()。

中斷處理函式

中斷處理函式的介面形式如下:

irqreturn_t button_isr(int irq, void * data);

系統在呼叫該中斷處理函式傳入的參數 irq 為對應的中斷號碼,Debug的時候有機會用到。而如前面所述 data 其實就是在註冊中斷處理函式給對應中斷號碼時最後一個傳入的指標(void *),此模組是傳入 MY_DEV_NAME 裝置名稱的字串指標,從範例碼來看,其實並沒有用到...。

呼叫 button_isr() 時,所做的事情就只是用 gpio_set_value() 來切換 LED 亮暗狀態。但是在中斷處理函式在運行的期間,會不希望因為其他中斷訊號引發造成程式中斷,所以會使用 local_irq_save(flags) 來關掉CPU受理其他中斷訊號的功能,等到函式要結束之時再使用 local_irq_restore(flags)來重新使CPU可以受理中斷訊號。

執行結果

因為按鍵會有開關彈跳的問題,所以一般處理按鍵開關類的輸入都會進行所謂 debounce 的處理。但是在這個範例之中並沒有特別去做這件事情,所以按鍵每按一下時,其實都會在短時間內引發隨機次數的中斷。處理這樣的問題有很多種手法,不過為了練習Linux Kernel API,所以下一篇文章會用 timer 的方式來處理。



2015年5月23日 星期六

Raspberry Pi硬體暫存器的設定方式



以BCM2835 C library 解說關於硬體暫存器的設定方式, 手邊請備妥Raspberry Pi  "BCM2835 ARM Peripherals" 以方便查閱。底下以GPIO 方式 解說,, 先說明要寫入或讀取的方法, 不解釋其設定後的物理意義.

 先跳到page 89 第六章 General Purpose I/O (GPIO) 閱讀, 將有助於下列code的理解.

// Physical addresses for various peripheral register sets
/// Base Physical Address of the BCM 2835 peripheral registers
#define BCM2835_PERI_BASE               0x20000000
/// Base Physical Address of the System Timer registers
#define BCM2835_ST_BASE (BCM2835_PERI_BASE + 0x3000)
/// Base Physical Address of the Pads registers
#define BCM2835_GPIO_PADS               (BCM2835_PERI_BASE + 0x100000)
/// Base Physical Address of the Clock/timer registers
#define BCM2835_CLOCK_BASE              (BCM2835_PERI_BASE + 0x101000)
/// Base Physical Address of the GPIO registers
#define BCM2835_GPIO_BASE               (BCM2835_PERI_BASE + 0x200000)
/// Base Physical Address of the SPI0 registers
#define BCM2835_SPI0_BASE               (BCM2835_PERI_BASE + 0x204000)

.....................

/// \brief bcm2835PortFunction
/// Port function select modes for bcm2835_gpio_fsel()
typedef enum
{
    BCM2835_GPIO_FSEL_INPT  = 0b000,   ///< Input
    BCM2835_GPIO_FSEL_OUTP  = 0b001,   ///< Output
    BCM2835_GPIO_FSEL_ALT0  = 0b100,   ///< Alternate function 0
    BCM2835_GPIO_FSEL_ALT1  = 0b101,   ///< Alternate function 1
    BCM2835_GPIO_FSEL_ALT2  = 0b110,   ///< Alternate function 2
    BCM2835_GPIO_FSEL_ALT3  = 0b111,   ///< Alternate function 3
    BCM2835_GPIO_FSEL_ALT4  = 0b011,   ///< Alternate function 4
    BCM2835_GPIO_FSEL_ALT5  = 0b010,   ///< Alternate function 5
    BCM2835_GPIO_FSEL_MASK  = 0b111    ///< Function select bits mask
} bcm2835FunctionSelect;


// Low level convenience functions
//

// Defines for GPIO
// The BCM2835 has 54 GPIO pins.
//      BCM2835 data sheet, Page 90 onwards.
/// GPIO register offsets from BCM2835_GPIO_BASE. Offsets into the GPIO Peripheral block in bytes per 6.1 Register View
#define BCM2835_GPFSEL0                      0x0000 ///< GPIO Function Select 0
#define BCM2835_GPFSEL1                      0x0004 ///< GPIO Function Select 1
#define BCM2835_GPFSEL2                      0x0008 ///< GPIO Function Select 2
#define BCM2835_GPFSEL3                      0x000c ///< GPIO Function Select 3
#define BCM2835_GPFSEL4                      0x0010 ///< GPIO Function Select 4
#define BCM2835_GPFSEL5                      0x0014 ///< GPIO Function Select 5
#define BCM2835_GPSET0                       0x001c ///< GPIO Pin Output Set 0
#define BCM2835_GPSET1                       0x0020 ///< GPIO Pin Output Set 1
#define BCM2835_GPCLR0                       0x0028 ///< GPIO Pin Output Clear 0
#define BCM2835_GPCLR1                       0x002c ///< GPIO Pin Output Clear 1


// Initialise this library.
int bcm2835_init(void)
{
    if (debug)
    {
bcm2835_pads = (uint32_t*)BCM2835_GPIO_PADS;
bcm2835_clk  = (uint32_t*)BCM2835_CLOCK_BASE;
bcm2835_gpio = (uint32_t*)BCM2835_GPIO_BASE;
bcm2835_pwm  = (uint32_t*)BCM2835_GPIO_PWM;
bcm2835_spi0 = (uint32_t*)BCM2835_SPI0_BASE;
bcm2835_bsc0 = (uint32_t*)BCM2835_BSC0_BASE;
bcm2835_bsc1 = (uint32_t*)BCM2835_BSC1_BASE;
bcm2835_st   = (uint32_t*)BCM2835_ST_BASE;
return 1; // Success
    }
    int memfd = -1;
    int ok = 0;
    // Open the master /dev/memory device
    if ((memfd = open("/dev/mem", O_RDWR | O_SYNC) ) < 0)
    {
fprintf(stderr, "bcm2835_init: Unable to open /dev/mem: %s\n",
strerror(errno)) ;
goto exit;
    }

    // GPIO:
   //mapmem內部即是進行mmap 系統呼叫, 將kenel map的硬體暫存器位址map到user-space裡,以方便進行 user space driver 開發
    bcm2835_gpio = (volatile uint32_t *)mapmem("gpio", BCM2835_BLOCK_SIZE, memfd, BCM2835_GPIO_BASE);
    if (bcm2835_gpio == MAP_FAILED) goto exit;


   ..............................
}


// Function select
// pin is a BCM2835 GPIO pin number NOT RPi pin number
//      There are 6 control registers, each control the functions of a block
//      of 10 pins.
//      Each control register has 10 sets of 3 bits per GPIO pin:
//
//      000 = GPIO Pin X is an input
//      001 = GPIO Pin X is an output
//      100 = GPIO Pin X takes alternate function 0
//      101 = GPIO Pin X takes alternate function 1
//      110 = GPIO Pin X takes alternate function 2
//      111 = GPIO Pin X takes alternate function 3
//      011 = GPIO Pin X takes alternate function 4
//      010 = GPIO Pin X takes alternate function 5
//
// So the 3 bits for port X are:
//      X / 10 + ((X % 10) * 3)



設定GPIO 功能
void bcm2835_gpio_fsel(uint8_t pin, uint8_t mode)
{
   
  //除以4 , 是因為bcm2835_gpio 為一個 int pointer, 所以加1 隠函移動4個byte了, 故除以4才能得    到正確位址
  //除以10 是為了計算GPIO pin 號碼在那一個 Function selects 的暫存器裡
      每一個暫存器(32 bit word) 管 GPIO 10 根 ,(3 bits per pin)

    volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPFSEL0/4 + (pin/10);

//  找到pin 的暫存器, 還要再找到這個pin 對應的bit, 故要再 shift  ((X % 10) * 3) bits 
    uint8_t   shift = (pin % 10) * 3;
    uint32_t  mask = BCM2835_GPIO_FSEL_MASK << shift;
    uint32_t  value = mode << shift;
    bcm2835_peri_set_bits(paddr, value, mask);
}

-----------------
// Set/clear only the bits in value covered by the mask
void bcm2835_peri_set_bits(volatile uint32_t* paddr, uint32_t value, uint32_t mask)
{


  // 先讀出原來的值 v, 再去改變要更新的欄位', 而其他欄位仍須保留原來的值
    uint32_t v = *paddr;

//   要改的欄位先清成0  ==> v & ~mask, 再去設定其value ==> OR (value & mask)
    v = (v & ~mask) | (value & mask);

   *paddr=v;
}


Note: volatile uint32_t* paddr  ,volatile 這個修飾字使compiler 針對paddr所指的硬體位址的存取, 不要進行任何最佳化的處理,以免產生其他site effect.








2015年5月22日 星期五

Python Maker 講座,基礎硬體控制Raspberry Pi 2 技術研討會。


活動簡介Theme
Python程式語言有著程式碼易學、易讀、清晰等特性,因而被廣泛作為入門程式語言教授,讓開發者可以更為專注系統的架構與功能的實現。Python 有非常豐富的函式庫,可以很方便達成、簡化許多功能。讓開發者可以迅速、簡單的完成各種日常工作,也足以應付許多中大型專案的需求。在 Python 不足以單獨應付需求的情況下,Python 也提供了與 C、C++、甚至 C# 或者 Java 程式溝通的介面。
此次講座我們將分享目前Open Hardware的發展現況與其應用,並且介紹如何使用Python程式語言在Raspberry Pi開放硬體平台上開發GPIO應用,達成控制RF無線通訊、藍牙通訊、液晶字元顯示模組、各類基礎GPIO功能應用。非常適合Maker族群快速上手、迅速整合各類元件,專注於各類創意的發想。最後 Raspberry Pi Education Kit 使用教學,讓你一次就上手。


活動首頁   |   艾鍗官網   |   FB粉絲團   |   實習影片

2015年5月13日 星期三

在Raspberry Pi B+ 上面學 Linux 驅動程式開發 -- GPIO

實驗名稱

    Raspberry Pi B+ , Linux 驅動程式開發 -- GPIO --

實驗目的

    簡單介紹在Raspberry Pi B+ Linux 系統底下,如何使用GPIO。

使用材料及設備

    硬體: Raspberry Pi B+

    軟體: 可編譯 Linux Module 的 Raspbian 系統。

原理介紹

GPIO 是嵌入式系統中極為重要的功能,但是在一般的桌機與筆電系統之中卻很少見。一般MCU在操作GPIO時是直接透過寫入資料到對應的暫存器來控制其輸出入。然而在 Raspberry Pi 的 Linux 系統底下因為虛擬記憶體空間的機制,使得無法如此直接使用,而須再透過系統函式得到一組記憶體映射位置之後,再透過該記憶體映射間接控制 GPIO。

本篇文章會使用艾鍗科技出產的教學子板來做示範-- 在模組之中控制GPIO點亮板子上的LED燈。無子板的話也可以使用麵包板自行實作電路達到相同的效果。


Pi 40 Pin Header

在Raspberry Pi B+ & Pi2 上面學 Linux 驅動程式開發 -- GPIO -- 使用 gpio library

實驗名稱

    Raspberry Pi B+ & Pi2, Linux 驅動程式開發 -- GPIO -- 使用 gpio library

實驗目的

    簡單介紹在Raspberry Pi Linux 系統底下,如何使用GPIO來撰寫模組。

使用材料及設備

    硬體: Raspberry Pi B+ or Pi2

    軟體: 可編譯 Linux Module 的 Raspbian 系統。

原理介紹

GPIO 是嵌入式系統中極為重要的功能,但是在一般的桌機與筆電系統之中卻很少見。一般MCU在操作GPIO時是直接透過寫入資料到對應的暫存器來控制其輸出入。然而在 Raspberry Pi 的 Linux 系統底下因為虛擬記憶體空間的機制,使得無法如此直接使用,而須再透過系統函式得到一組記憶體映射位置之後,再透過該記憶體映射間接控制 GPIO。

本篇文章會使用艾鍗科技出產的教學子板來做示範-- 在模組之中控制GPIO點亮板子上的LED燈。無子板的話也可以使用麵包板自行實作電路達到相同的效果。