2016年1月22日 星期五
核心空間配置記憶體 kmalloc() 和 kfree()
void *kmalloc(size_t size, gfp_t flags)
kmalloc一次最多能申請的記憶體大小由include/Linux/Kmalloc_size.h的內容來決定,
kmalloc一次最多能申請大小為131702B也就是128KB的連續物理記憶體。
flags 的參數如下:
GFP_ATOMIC : 用於interrupt handler 或任何行程外環境的程式..絕不休眠
GFP_KERNEL : 一般核心記憶體配置..有可能休眠
GFP_USER : 配置記憶體給user-sapce...有可能休眠
GFP_HIGHUSER : 類似 GFP_USER. 但是從高位址區取得空間...
還有一些... 我就沒有打了
高位址區(High memory address) 是一種可供32 bit平台存取大量記憶體的機制...
kmalloc() 能夠配置的記憶體容量是有上限的(因為配置出來的空間是連續的實體記憶體...這樣的空間很少)
,而且上限取決硬體平台與核心組態選項...如果你想維持程式的可移植性...就別期待能夠配置超過128KB的記憶體 ....
核心空間的cache用法如下
kmem_cache_t *kmem_cache_create(name, size, offset, flags)
name : 通常是一串簡短的文字串
offset : 是第一個物件在記憶頁的起始位置....
flag :
SLAB_NO_REAP : 保護cache不因系統短缺記憶體而縮減其容量
SLAB_HWCACHE_ALIGN: 此旗標要求每個資料物件都要對齊一條塊取線....
SLAB_CACHE_DMA : 要求每一個資料物件都配置在DMA可存取的記憶體
成功建立cache後 妳可以呼叫kmem_cache_alloc為配置cache
void * kmem_cache_alloc(*cache, flags)....
void *vmalloc(unsigned long size).... (v 是virtual的意思)
其作用為在虛擬位址空間(virtual space)配置一段連續的記憶體...
vmalloc() 所得到的每一頁的記憶體...都是個別呼叫alloc_page()所得來的...
在某些場合中,對記憶體區的請求不是很頻繁,較高的記憶體訪問時間也可以接受,
這樣就可以分配一段線性連續,物理不連續的地址,帶來的好處是一次可以分配較大塊的記憶體。
vmalloc對一次能分配的記憶體大小沒有明確限制。出於性能考慮,應謹慎使用vmalloc函數
void * ioremap (unsigned long offset, unsigned long size)
ioremap是一種更直接的記憶體分配方式,使用時直接指定物理起始地址和需要分配記憶體的大小,
然後將該段物理地址映射到核心地址空間。
ioremap用到的物理地址空間都是事先確定的,和上面的幾種記憶體分配方式並不太一樣。
並不是分配一段新的物理記憶體。
ioremap多用於設備驅動,可以讓CPU直接訪問外部設備的IO空間。
ioremap能映射的記憶體由原有的物理記憶體空間決定,所以沒有進行測試。
get_zero_page(unsigned int flags)
回傳一個指向新記憶頁的指標...而page的內容全部都是0
__get_free_page(unsigned int flags)
類似於get_zero_page() , 但是不清除原來的內容
__get_free_page(unsigned int flags,unsigned int order)
配置一個cross-page的連續記憶體(在實體記憶體上是連續的)...並傳回一個指向記憶體第一個位元組的
指標
這裡的flag 理論上和 kmalloc() 所使用的flag相同... 通常以 GFP_KERNEL和 GFP_ATOMIC最為常使用
Reference : Linux 驅動程式第三版
Reference : http://welkinchen.pixnet.net/blog/post/44174948-%E5%B8%B8%E7%94%A8%E6%A0%B8%E5%BF%83%E8%A8%98%E6%86%B6%E9%AB%94%E5%88%86%E9%85%8D%E5%87%BD%E6%95%B8
grove dht sensor (溫度..濕度)
雖然說對這顆sensor 已經很熟...不過這次買的starter kit 裡面有...也就順便study一下
原理和protocol 都和以前一樣...只是它包好了一個function...你可以直接呼叫去讀值
直接看sample code
# module_type: # DHT11 0 # DHT22 1 # DHT21 2 # DHT2301 3
[ temp,hum ] = dht(dht_sensor_port,0) #Get the temperature and Humidity from the DHT sensor
其實就一行code....
dht(port_num, module_type)
module 的數值有四種.....由於我們的是DHT11 ....所以填0...
然後直接就把 溫度和濕度放在變數 temp 和 hum...很方便吧.....
當然我們還是來看看它是怎麼實做出來的....
整個 source code在Reference 2可以看到
// pull the pin high and wait 250 milliseconds | |
digitalWrite(_pin, HIGH); | |
delay(250); |
一開始....先把 GPIO 拉High 維持 250ms
data[0] = data[1] = data[2] = data[3] = data[4] = 0;
先把data[0] 到 data[4] 初始化
// now pull it low for ~20 milliseconds
pinMode(_pin, OUTPUT);
digitalWrite(_pin, LOW);
delay(20);
digitalWrite(_pin, HIGH);
delayMicroseconds(40);
pinMode(_pin, INPUT);
然後再拉Low ....維持 20 ms
然後再拉High....維持 40 us.....
接下來把pin改成input mode...
define MAXTIMINGS 85
for ( i=0; i< MAXTIMINGS; i++) { | |
counter = 0; | |
while (digitalRead(_pin) == laststate) { | |
counter++; | |
delayMicroseconds(1); | |
if (counter == 255) { | |
break; | |
} | |
} | |
laststate = digitalRead(_pin); | |
if (counter == 255) break; | |
// ignore first 3 transitions | |
if ((i >= 4) && (i%2 == 0)) { | |
// shove each bit into the storage bytes | |
data[j/8] <<= 1; | |
if (counter > _count) | |
data[j/8] |= 1; | |
j++; | |
} | |
} |
他用一個for loop..... 最多跑85次
接下用一個 while loop...一直去check 現在讀到的value和之前讀到的value有沒有一樣
如果有一樣...就去睡覺1us....讓cpu可以去做其他事情
這個while loop會check到現在讀出來的level和上次是不一樣的
counter紀錄這段時間有多久...單位us
他這邊有個check error的機制就是當時間已經超過 255us...
它就會終止迴圈....然後認為這次的傳輸是失敗的
counter=0
while (digitalRead(_pin) == laststate){
counter++;
delayMicroseconds(1);}
if (counter == 255) break;
接下來就是去check 這次的counter有多久...
如果counter大於 _count....就為這次的傳輸是傳 '1'
如果counter沒有大於_count...代表這次的傳輸是傳'0'...也就是不需要做任何事
然後由於他是MSB先傳....所以要做bit 的shift....
至於_count是一開始物件初始化的時候會決定 .....datasheet來看...應該是30或是40
然後前四個傳輸不要管....從第5個(i>=4)開始看...而且只看偶數(i%2)......
因為我們觸發的條件是edge...但是一次傳輸有兩個edge...
但我有點搞不懂是...為什麼前四個傳輸不看
if ((i >= 4) && (i%2 == 0)) {
data[j/8] <<= 1;
if (counter > _count)
data[j/8] |= 1;
j++;}
最後再check CRC
// check we read 40 bits and that the checksum matches
if ((j >= 40) && (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) ) {
return true; }
check CRC的方式也和之前一樣....
大體上來說和之前實作的dht11一樣....
Reference 1 : http://www.seeedstudio.com/wiki/Grove_-_Temperature_and_Humidity_Sensor
Reference 2 : https://github.com/Seeed-Studio/Grove_Temperature_And_Humidity_Sensor/blob/master/DHT.cpp
grove sound sensor
從他的wiki來看....它其實就是一個微型的麥克風 加上 LM358去放大...
然後輸出就是類比信號....
直接看sample code吧
# Read the sound level sensor_value = grovepi.analogRead(sound_sensor)
因為是類比信號....其實就直接呼叫 grovepi.analogRead 去讀值就好啦...
Reference : http://www.seeedstudio.com/wiki/Grove_-_Sound_Sensor
grovepi light sensor (Light Dependent Resistor)
這個sensor也是蠻好玩的....它的輸出電阻和他所感受的光源成反比...
從他的wiki來看就知道
Resistance decreases as luminance increases
從他的spec 來看
Specifications
- Voltage: 3-5V
- Supply Current: 0.5-3mA
- Light resistance: 20KΩ
- Dark resistance: 1MΩ
- Response time: 20-30 secs
- Peak Wavelength: 540 nm
- Ambient temperature: -30~70℃
最亮時...輸出電阻為 20KO...
最暗時...輸出電阻為 1MO...
所以其實就只要去讀他的類比輸出就可以了....
由於我們有grovepi 的shield...他上面的IC就有類比輸入.....所以我們只要呼叫
analogRead() 去把值讀回來.....
因為sensor_value的數值為 0~1023..
然後帶上他的公式.... 轉換成K歐姆....
# Get sensor value sensor_value = grovepi.analogRead(light_sensor) # Calculate resistance of sensor in K resistance = (float)(1023 - sensor_value) * 10 / sensor_value
但如果以後要自己實做的話...因為Raspberry 沒有類比輸入輸出....所以考慮用mcp3002 來用...
Grovepi Ultrasonic Ranger 的詳細研究
這顆sensor 蠻好玩的... 它可以用超音波的量測方式...來測量在他前面的障礙物的距離....
然後它所提供的sample code非常簡單...
# GrovePi + Grove Ultrasonic Ranger from grovepi import * # Connect the Grove Ultrasonic Ranger to digital port D4 # SIG,NC,VCC,GND ultrasonic_ranger = 4 while True: try: # Read distance value from Ultrasonic print ultrasonicRead(ultrasonic_ranger) except TypeError: print "Error" except IOError: print "Error"
他就直接呼叫 ultrasonicRead(port_num);
就可以得到距離值....用是很好用....不過以後要移植平台時...這樣就不行了
所以還是來研究一下他去怎麼實作的
從他的連結所下載的ultrasonic.zip來看
它提供了兩個function....
一種是 measure in centimeter.....
一種是 measure in inch
那來看看他的實作 ....
/*The measured distance from the range 0 to 400 Centimeters*/
void Ultrasonic::MeasureInCentimeters(void)
{
pinMode(_pin, OUTPUT);
digitalWrite(_pin, LOW);
delayMicroseconds(2);
digitalWrite(_pin, HIGH);
delayMicroseconds(5);
digitalWrite(_pin,LOW);
pinMode(_pin,INPUT);
duration = pulseIn(_pin,HIGH);
RangeInCentimeters = duration/29/2;
}
從這段code來看....
1.set low 2ms
2. set high 5ms
3. 然後set low之後...設成input mode
4. 接下來量取 ultrasonic 這次傳輸(拉high一段時間...再拉low)....level為high的時間為多少
5. 得到的答案就是 duration_time /29/2
其實它的原理就是用超音波的速度*時間來得到 距離...由於時間是算來回的時間
所以要除以2......
音波的速度為 每秒 330公尺...這是一個大概值....以公式來說就是 331.5 + 0.6*溫度
如果以室溫20度來說....速度大概就是 331.5*0.6*20 = 343 (m/s)
從上段的code來看.... pulseIn 所回傳的單位是 微秒(10^-6)
t*10^-6 * 343 /2*100 = t*0.0343/2 = t/29/2
公式就是這樣來的....
Reference 1: http://www.seeedstudio.com/wiki/Grove_-_Ultrasonic_Ranger
Reference 2: http://www.seeedstudio.com/wiki/images/9/95/Ultrasonic.zip
Reference 3: https://developer.mbed.org/cookbook/Seeed-grove-ultrasonic-ranger
Reference 4: Make :感測器運用Arduino 和Raspberry Pi 感測的專題與實驗
訂閱:
文章 (Atom)