高速フーリエ変換 CUDAで最適化版
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cutil.h>
#include <sys/time.h>
#include <unistd.h>
typedef struct __align__(8) {
float real;
float imaginary;
} Complex;
__device__ __host__ void initComplex( Complex *_arg_this, float _arg_real, float _arg_imaginary ) {
_arg_this->real = _arg_real;
_arg_this->imaginary = _arg_imaginary;
}
__device__ void addComplex( Complex *_arg_this, const Complex *_arg_left, const Complex *_arg_right ) {
_arg_this->real = _arg_left->real + _arg_right->real;
_arg_this->imaginary = _arg_left->imaginary + _arg_right->imaginary;
}
__device__ void multComplex( Complex *_arg_this, const Complex *_arg_left, const Complex *_arg_right ) {
_arg_this->real = _arg_left->real * _arg_right->real -
_arg_left->imaginary * _arg_right->imaginary;
_arg_this->imaginary = _arg_left->real * _arg_right->imaginary +
_arg_left->imaginary * _arg_right->real;
}
__device__ void divComplexByScalar( Complex *_arg_this, const Complex *_arg_left, float _arg_right ) {
_arg_this->real = _arg_left->real / _arg_right;
_arg_this->imaginary = _arg_left->imaginary / _arg_right;
}
typedef struct __align__(32) {
unsigned int size;
int inverse;
Complex *w_gpu;
} FFT;
int initFFT( FFT *_arg_this, unsigned int _arg_size, int _arg_inverse ) {
_arg_this->size = _arg_size;
_arg_this->inverse = _arg_inverse;
Complex *w = ( Complex* )malloc( sizeof( Complex ) * _arg_this->size );
if( !w )
return -1;
float direction = -1.0f;
if( _arg_this->inverse )
direction = 1.0f;
int counter;
for( counter = 0; counter != _arg_this->size; counter++ ) {
float angle = direction * 2.0 * M_PI * counter / _arg_this->size;
initComplex( w + counter, cosf( angle ), sinf( angle ) );
}
CUDA_SAFE_CALL( cudaMalloc( (void**) &_arg_this->w_gpu, sizeof( Complex ) * _arg_this->size ) );
CUDA_SAFE_CALL( cudaMemcpy( _arg_this->w_gpu, w, sizeof( Complex ) * _arg_this->size, cudaMemcpyHostToDevice ) );
free( w );
return 0;
}
void finalFFT( FFT *_arg_this ) {
CUDA_SAFE_CALL( cudaFree( _arg_this->w_gpu ) );
}
unsigned int flipBitFFT( FFT *_arg_this, unsigned int _arg_value ) {
int counter;
unsigned int temp = 0;
unsigned int log_size = log2f( _arg_this->size );
for( counter = 0; counter != log_size; counter++ ) {
temp <<= 1;
temp |= ( _arg_value >> counter ) & 0x01;
}
return temp;
}
void swapFFT( FFT *_arg_this, Complex *_arg_buffer ) {
unsigned int counter;
for( counter = 0; counter != _arg_this->size; counter++ ) {
unsigned int flipped = flipBitFFT( _arg_this, counter );
if( counter < flipped ) {
Complex temp = _arg_buffer[ counter ];
_arg_buffer[ counter ] = _arg_buffer[ flipped ];
_arg_buffer[ flipped ] = temp;
}
}
}
__global__ void processFFT( FFT *_arg_this, Complex *_arg_dest, Complex *_arg_src, unsigned int _arg_block_size ) {
unsigned int counter = ( blockIdx.x * blockDim.x ) + threadIdx.x;
unsigned int left = counter;
unsigned int right = ( counter & ~( _arg_block_size >> 1 ) ) | ( ~counter & ( _arg_block_size >> 1 ) );
if( left > right ) {
unsigned int temp = left;
left = right;
right = temp;
}
unsigned int w_step = _arg_this->size / _arg_block_size;
Complex m;
multComplex( &m, &_arg_this->w_gpu[ ( ( counter % _arg_block_size ) * w_step ) ], &_arg_src[ right ] );
addComplex( _arg_dest + counter, &_arg_src[ left ], &m );
}
__global__ void divFFT( FFT *_arg_this, Complex *_arg_buffer ) {
unsigned int counter = ( blockIdx.x * blockDim.x ) + threadIdx.x;
divComplexByScalar( _arg_buffer + counter, _arg_buffer + counter, _arg_this->size );
}
int runFFT( FFT *_arg_this, Complex *_arg_buffer ) {
swapFFT( _arg_this, _arg_buffer );
Complex *buffer;
CUDA_SAFE_CALL( cudaMalloc( (void**) &buffer, sizeof( Complex ) * _arg_this->size ) );
if( !buffer )
return -1;
Complex *swap;
CUDA_SAFE_CALL( cudaMalloc( (void**) &swap, sizeof( Complex ) * _arg_this->size ) );
if( !swap ) {
CUDA_SAFE_CALL( cudaFree( buffer ) );
return -1;
}
CUDA_SAFE_CALL( cudaMemcpy( (void*)buffer, (void*)_arg_buffer, sizeof( Complex ) * _arg_this->size, cudaMemcpyHostToDevice ) );
FFT *device_this;
CUDA_SAFE_CALL( cudaMalloc( (void**) &device_this, sizeof( FFT ) ) );
CUDA_SAFE_CALL( cudaMemcpy( (void*)device_this, (void*)_arg_this, sizeof( FFT ), cudaMemcpyHostToDevice ) );
int counter;
dim3 grid( 1, 1, 1 );
dim3 threads( 1, 1, 1 );
if( _arg_this->size >= 128 ) {
grid.x = _arg_this->size / 128;
threads.x = 128;
}
else {
threads.x = _arg_this->size;
}
for( counter = 2; counter <= _arg_this->size; counter <<= 1 ) {
processFFT<<< grid, threads >>>( device_this, swap, buffer, counter );
Complex *temp = swap;
swap = buffer;
buffer = temp;
CUDA_SAFE_CALL( cudaThreadSynchronize() );
}
if( _arg_this->inverse )
divFFT<<< grid, threads >>>( device_this, buffer );
CUDA_SAFE_CALL( cudaMemcpy( (void*)_arg_buffer, (void*)buffer, sizeof( Complex ) * _arg_this->size, cudaMemcpyDeviceToHost ) );
CUDA_SAFE_CALL( cudaFree( swap ) );
CUDA_SAFE_CALL( cudaFree( buffer ) );
return 0;
}
int main( int argc, char *argv[] ) {
CUT_DEVICE_INIT(argc, argv);
int size = 65536 * 64;
FFT test_fft;
initFFT( &test_fft, size, 0 );
FFT test_ifft;
initFFT( &test_ifft, size, 1 );
struct timeval tv[ 2 ];
Complex * buffer = ( Complex* )calloc( sizeof( Complex ), size );
buffer[ size / 2 ].real = 1000.0f;
gettimeofday(tv, NULL);
runFFT( &test_fft, buffer );
gettimeofday(tv + 1, NULL);
printf( "FFT time ( GPU ): %lf\n", ( (double)tv[ 1 ].tv_sec + (double)tv[ 1 ].tv_usec * 0.000001 ) -
( (double)tv[ 0 ].tv_sec + (double)tv[ 0 ].tv_usec * 0.000001 ) );
int counter;
for( counter = size * 0.8f; counter != size; counter++ ) {
buffer[ counter ].real = 0.0f;
buffer[ counter ].imaginary = 0.0f;
}
gettimeofday(tv, NULL);
runFFT( &test_ifft, buffer );
gettimeofday(tv + 1, NULL);
printf( "IFFT time ( GPU ): %lf\n", ( (double)tv[ 1 ].tv_sec + (double)tv[ 1 ].tv_usec * 0.000001 ) -
( (double)tv[ 0 ].tv_sec + (double)tv[ 0 ].tv_usec * 0.000001 ) );
CUT_EXIT(argc, argv);
return EXIT_SUCCESS;
}
$ nvcc fft.cu -lcutil -I$CUDA_DIR/sdk/common/inc/ -L$CUDA_DIR/sdk/lib -arch sm_11 -o fft -Xcompiler "-O2 -march=core2 -msse4 -mfpmath=sse -fno-math-errno -ffast-math -fforce-addr -fomit-frame-pointer -pipe -fstrength-reduce -fno-strict-aliasing -fstack-protector"
$ ./fft
Using device 0: GeForce 8400 GS
FFT time ( GPU ): 6.013794
IFFT time ( GPU ): 6.255594
Press ENTER to exit...
$ ./fft
Using device 0: GeForce 8400 GS
FFT time ( GPU ): 6.013794
IFFT time ( GPU ): 6.255594
Press ENTER to exit...
高速フーリエ変換 OpenMPで最適化版
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <unistd.h>
#include <omp.h>
typedef struct {
float real;
float imaginary;
} Complex;
void initComplex( Complex *_arg_this, float _arg_real, float _arg_imaginary ) {
_arg_this->real = _arg_real;
_arg_this->imaginary = _arg_imaginary;
}
void addComplex( Complex *_arg_this, const Complex *_arg_left, const Complex *_arg_right ) {
_arg_this->real = _arg_left->real + _arg_right->real;
_arg_this->imaginary = _arg_left->imaginary + _arg_right->imaginary;
}
void multComplex( Complex *_arg_this, const Complex *_arg_left, const Complex *_arg_right ) {
_arg_this->real = _arg_left->real * _arg_right->real -
_arg_left->imaginary * _arg_right->imaginary;
_arg_this->imaginary = _arg_left->real * _arg_right->imaginary +
_arg_left->imaginary * _arg_right->real;
}
void divComplexByScalar( Complex *_arg_this, const Complex *_arg_left, float _arg_right ) {
_arg_this->real = _arg_left->real / _arg_right;
_arg_this->imaginary = _arg_left->imaginary / _arg_right;
}
typedef struct {
unsigned int size;
int inverse;
Complex *w;
Complex *w_gpu;
} FFT;
int initFFT( FFT *_arg_this, unsigned int _arg_size, int _arg_inverse ) {
_arg_this->size = _arg_size;
_arg_this->inverse = _arg_inverse;
_arg_this->w = ( Complex* )malloc( sizeof( Complex ) * _arg_this->size );
if( !_arg_this->w )
return -1;
float direction = -1.0f;
if( _arg_this->inverse )
direction = 1.0f;
int counter;
for( counter = 0; counter != _arg_this->size; counter++ ) {
float angle = direction * 2.0 * M_PI * counter / _arg_this->size;
initComplex( _arg_this->w + counter, cosf( angle ), sinf( angle ) );
}
return 0;
}
void finalFFT( FFT *_arg_this ) {
free( _arg_this->w );
}
unsigned int flipBitFFT( FFT *_arg_this, unsigned int _arg_value ) {
int counter;
unsigned int temp = 0;
unsigned int log_size = (unsigned int)log2f( (float)_arg_this->size );
for( counter = 0; counter != log_size; counter++ ) {
temp <<= 1;
temp |= ( _arg_value >> counter ) & 0x01;
}
return temp;
}
void swapFFT( FFT *_arg_this, Complex *_arg_buffer ) {
unsigned int counter;
for( counter = 0; counter != _arg_this->size; counter++ ) {
unsigned int flipped = flipBitFFT( _arg_this, counter );
if( counter < flipped ) {
Complex temp = _arg_buffer[ counter ];
_arg_buffer[ counter ] = _arg_buffer[ flipped ];
_arg_buffer[ flipped ] = temp;
}
}
}
void processFFT( const FFT *_arg_this, Complex *_arg_dest, const Complex *_arg_src, unsigned int _arg_block_size ) {
unsigned int counter;
#pragma omp parallel private( counter )
for( counter = omp_get_thread_num(); counter < _arg_this->size; counter+= omp_get_num_threads() ) {
unsigned int left = counter;
unsigned int right = ( counter & ~( _arg_block_size >> 1 ) ) | ( ~counter & ( _arg_block_size >> 1 ) );
if( left > right ) {
unsigned int temp = left;
left = right;
right = temp;
}
unsigned int w_step = _arg_this->size / _arg_block_size;
Complex m;
multComplex( &m, _arg_this->w + ( ( counter % _arg_block_size ) * w_step ), _arg_src + right );
addComplex( _arg_dest + counter, _arg_src + left, &m );
}
}
void divFFT( FFT *_arg_this, Complex *_arg_buffer ) {
unsigned int counter;
#pragma omp parallel private( counter )
for( counter = omp_get_thread_num(); counter < _arg_this->size; counter+= omp_get_num_threads() )
divComplexByScalar( _arg_buffer + counter, _arg_buffer + counter, _arg_this->size );
}
int runFFT( FFT *_arg_this, Complex *_arg_buffer ) {
swapFFT( _arg_this, _arg_buffer );
Complex *swap = ( Complex* )malloc( sizeof( Complex ) * _arg_this->size );
if( !swap )
return -1;
Complex *original_swap = swap;
int counter;
for( counter = 2; counter <= _arg_this->size; counter <<= 1 ) {
processFFT( _arg_this, swap, _arg_buffer, counter );
Complex *temp = swap;
swap = _arg_buffer;
_arg_buffer = temp;
}
if( _arg_this->inverse )
divFFT( _arg_this, _arg_buffer );
if( swap != original_swap ) {
Complex *temp = swap;
swap = _arg_buffer;
_arg_buffer = temp;
memcpy( _arg_buffer, swap, sizeof( Complex ) * _arg_this->size );
}
free( original_swap );
return 0;
}
int main( int argc, char *argv[] ) {
int size = 65536 * 64;
FFT test_fft;
initFFT( &test_fft, size, 0 );
FFT test_ifft;
initFFT( &test_ifft, size, 1 );
struct timeval tv[ 2 ];
Complex * buffer = ( Complex* )calloc( sizeof( Complex ), size );
buffer[ size / 2 ].real = 1000.0f;
gettimeofday(tv, NULL);
runFFT( &test_fft, buffer );
gettimeofday(tv + 1, NULL);
printf( "FFT time ( CPU ): %lf\n", ( (double)tv[ 1 ].tv_sec + (double)tv[ 1 ].tv_usec * 0.000001 ) -
( (double)tv[ 0 ].tv_sec + (double)tv[ 0 ].tv_usec * 0.000001 ) );
int counter;
for( counter = size * 0.8f; counter != size; counter++ ) {
buffer[ counter ].real = 0.0f;
buffer[ counter ].imaginary = 0.0f;
}
gettimeofday(tv, NULL);
runFFT( &test_ifft, buffer );
gettimeofday(tv + 1, NULL);
printf( "IFFT time ( CPU ): %lf\n", ( (double)tv[ 1 ].tv_sec + (double)tv[ 1 ].tv_usec * 0.000001 ) -
( (double)tv[ 0 ].tv_sec + (double)tv[ 0 ].tv_usec * 0.000001 ) );
return EXIT_SUCCESS;
}
$ gcc fft.c -o fft -lm -O2 -march=core2 -msse4 -mfpmath=sse -fno-math-errno -ffast-math -fforce-addr -fomit-frame-pointer -pipe -fstrength-reduce -fno-strict-aliasing -fstack-protector -fopenmp
$ $ ./fft
FFT time ( CPU ): 2.270238
IFFT time ( CPU ): 2.610293
$ $ ./fft
FFT time ( CPU ): 2.270238
IFFT time ( CPU ): 2.610293
高速フーリエ変換 普通に実装版
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <unistd.h>
typedef struct {
float real;
float imaginary;
} Complex;
void initComplex( Complex *_arg_this, float _arg_real, float _arg_imaginary ) {
_arg_this->real = _arg_real;
_arg_this->imaginary = _arg_imaginary;
}
void addComplex( Complex *_arg_this, const Complex *_arg_left, const Complex *_arg_right ) {
_arg_this->real = _arg_left->real + _arg_right->real;
_arg_this->imaginary = _arg_left->imaginary + _arg_right->imaginary;
}
void multComplex( Complex *_arg_this, const Complex *_arg_left, const Complex *_arg_right ) {
_arg_this->real = _arg_left->real * _arg_right->real -
_arg_left->imaginary * _arg_right->imaginary;
_arg_this->imaginary = _arg_left->real * _arg_right->imaginary +
_arg_left->imaginary * _arg_right->real;
}
void divComplexByScalar( Complex *_arg_this, const Complex *_arg_left, float _arg_right ) {
_arg_this->real = _arg_left->real / _arg_right;
_arg_this->imaginary = _arg_left->imaginary / _arg_right;
}
typedef struct {
unsigned int size;
int inverse;
Complex *w;
} FFT;
int initFFT( FFT *_arg_this, unsigned int _arg_size, int _arg_inverse ) {
_arg_this->size = _arg_size;
_arg_this->inverse = _arg_inverse;
_arg_this->w = ( Complex* )malloc( sizeof( Complex ) * _arg_this->size );
if( !_arg_this->w )
return -1;
float direction = -1.0f;
if( _arg_this->inverse )
direction = 1.0f;
int counter;
for( counter = 0; counter != _arg_this->size; counter++ ) {
float angle = direction * 2.0 * M_PI * counter / _arg_this->size;
initComplex( _arg_this->w + counter, cosf( angle ), sinf( angle ) );
}
return 0;
}
void finalFFT( FFT *_arg_this ) {
free( _arg_this->w );
}
unsigned int flipBitFFT( FFT *_arg_this, unsigned int _arg_value ) {
int counter;
unsigned int temp = 0;
unsigned int log_size = log2f( _arg_this->size );
for( counter = 0; counter != log_size; counter++ ) {
temp <<= 1;
temp |= ( _arg_value >> counter ) & 0x01;
}
return temp;
}
void swapFFT( FFT *_arg_this, Complex *_arg_buffer ) {
unsigned int counter;
for( counter = 0; counter != _arg_this->size; counter++ ) {
unsigned int flipped = flipBitFFT( _arg_this, counter );
if( counter < flipped ) {
Complex temp = _arg_buffer[ counter ];
_arg_buffer[ counter ] = _arg_buffer[ flipped ];
_arg_buffer[ flipped ] = temp;
}
}
}
void processFFT( FFT *_arg_this, Complex *_arg_dest, Complex *_arg_src, unsigned int _arg_block_size ) {
unsigned int counter;
for( counter = 0; counter != _arg_this->size; counter++ ) {
unsigned int left = counter;
unsigned int right = ( counter & ~( _arg_block_size >> 1 ) ) | ( ~counter & ( _arg_block_size >> 1 ) );
if( left > right ) {
unsigned int temp = left;
left = right;
right = temp;
}
unsigned int w_step = _arg_this->size / _arg_block_size;
Complex m;
multComplex( &m, _arg_this->w + ( ( counter % _arg_block_size ) * w_step ), _arg_src + right );
addComplex( _arg_dest + counter, _arg_src + left, &m );
}
}
void divFFT( FFT *_arg_this, Complex *_arg_buffer ) {
unsigned int counter;
for( counter = 0; counter != _arg_this->size; counter++ )
divComplexByScalar( _arg_buffer + counter, _arg_buffer + counter, _arg_this->size );
}
int runFFT( FFT *_arg_this, Complex *_arg_buffer ) {
swapFFT( _arg_this, _arg_buffer );
Complex *swap = ( Complex* )malloc( sizeof( Complex ) * _arg_this->size );
if( !swap )
return -1;
Complex *original_swap = swap;
int counter;
for( counter = 2; counter <= _arg_this->size; counter <<= 1 ) {
processFFT( _arg_this, swap, _arg_buffer, counter );
Complex *temp = swap;
swap = _arg_buffer;
_arg_buffer = temp;
}
if( _arg_this->inverse )
divFFT( _arg_this, _arg_buffer );
if( swap != original_swap ) {
Complex *temp = swap;
swap = _arg_buffer;
_arg_buffer = temp;
memcpy( _arg_buffer, swap, sizeof( Complex ) * _arg_this->size );
}
free( original_swap );
return 0;
}
int main( int argc, char *argv[] ) {
int size = 65536 * 64;
FFT test_fft;
initFFT( &test_fft, size, 0 );
FFT test_ifft;
initFFT( &test_ifft, size, 1 );
struct timeval tv[ 2 ];
Complex * buffer = ( Complex* )calloc( sizeof( Complex ), size );
buffer[ size / 2 ].real = 1000.0f;
gettimeofday(tv, NULL);
runFFT( &test_fft, buffer );
gettimeofday(tv + 1, NULL);
printf( "FFT time ( CPU ): %lf\n", ( (double)tv[ 1 ].tv_sec + (double)tv[ 1 ].tv_usec * 0.000001 ) -
( (double)tv[ 0 ].tv_sec + (double)tv[ 0 ].tv_usec * 0.000001 ) );
int counter;
for( counter = size * 0.8f; counter != size; counter++ ) {
buffer[ counter ].real = 0.0f;
buffer[ counter ].imaginary = 0.0f;
}
gettimeofday(tv, NULL);
runFFT( &test_ifft, buffer );
gettimeofday(tv + 1, NULL);
printf( "IFFT time ( CPU ): %lf\n", ( (double)tv[ 1 ].tv_sec + (double)tv[ 1 ].tv_usec * 0.000001 ) -
( (double)tv[ 0 ].tv_sec + (double)tv[ 0 ].tv_usec * 0.000001 ) );
return EXIT_SUCCESS;
}
$ gcc fft.c -o fft -lm -O2 -march=core2 -msse4 -mfpmath=sse -fno-math-errno -ffast-math -fforce-addr -fomit-frame-pointer -pipe -fstrength-reduce -fno-strict-aliasing -fstack-protector
$ ./fft
FFT time ( CPU ): 3.480621
IFFT time ( CPU ): 3.864744
$ ./fft
FFT time ( CPU ): 3.480621
IFFT time ( CPU ): 3.864744
BeagleBoard
Pandoraがゲーム機じゃなかったら買ったんだがなぁ、とか日本でも売ってたら買ったんだがなぁという人は意外といるんじゃなかろうか。そんなときはBeagleBoardの出番かもしれない。
BeagleBoardはTIの最新のOMAP3530アプリケーションプロセッサを中心に構成されたシングルボードコンピュータで、Pandora同様その小さな基盤からは想像もつかない性能と安さを兼ね備えている。具体的なスペックは以下のとおり。
Texas Instruments社製ARM Cortex A8 OMAP3530プロセッサ搭載
DDR-SDRAM 128MB搭載
内蔵フラッシュメモリ256MB搭載
PowerVR SGXグラフィックプロセッサ(OpenGL ES2.0準拠 数百万ポリゴン毎秒)搭載
HDMI/S端子ビデオ出力搭載
SDHCカードスロットx1搭載
USBホストコントローラ搭載
Pandoraと異なりキーボード、液晶、ガワ、電波の飛ぶデバイスは無い。浮動小数点数に対応したSIMD命令、DSP、そしてこの手の板としては異常なほど強力なグラフィックアクセラレータを積んでいるため、組み込み基盤にマルチメディア関連の処理や、物理演算、リアルタイム3Dグラフィック、その他高速な浮動小数演算を必要とする処理をさせる必要がある場合に活躍するだろう。また、Debian ARMとUbuntu(HandheldMojo/Ubuntu9) ARMが動くことが確認されている。デスクトップLinuxとしてどの程度使えるかは以下のムービーがわかりやすい。
で、気になるお値段がビックリの$149
日本でもDigi-keyから17,865円$149で購入可能。
BeagleBoardはTIの最新のOMAP3530アプリケーションプロセッサを中心に構成されたシングルボードコンピュータで、Pandora同様その小さな基盤からは想像もつかない性能と安さを兼ね備えている。具体的なスペックは以下のとおり。
Texas Instruments社製ARM Cortex A8 OMAP3530プロセッサ搭載
DDR-SDRAM 128MB搭載
内蔵フラッシュメモリ256MB搭載
PowerVR SGXグラフィックプロセッサ(OpenGL ES2.0準拠 数百万ポリゴン毎秒)搭載
HDMI/S端子ビデオ出力搭載
SDHCカードスロットx1搭載
USBホストコントローラ搭載
Pandoraと異なりキーボード、液晶、ガワ、電波の飛ぶデバイスは無い。浮動小数点数に対応したSIMD命令、DSP、そしてこの手の板としては異常なほど強力なグラフィックアクセラレータを積んでいるため、組み込み基盤にマルチメディア関連の処理や、物理演算、リアルタイム3Dグラフィック、その他高速な浮動小数演算を必要とする処理をさせる必要がある場合に活躍するだろう。また、Debian ARMとUbuntu(HandheldMojo/Ubuntu9) ARMが動くことが確認されている。デスクトップLinuxとしてどの程度使えるかは以下のムービーがわかりやすい。
で、気になるお値段がビックリの$149
日本でもDigi-keyから
gumstix
久々の更新、いかした組み込みLinuxを2つほど紹介
gumstixは板ガムサイズのLinuxマシンを作るプロジェクト。
メイン基盤の仕様こそ簡素だが多彩な拡張ボードに対応し、組み立てPCの感覚で好きな構成にすることができる。現時点でもっとも高性能なverdex XL6Pの仕様は以下のとおり。
Marvell社製XScale PXA270 600MHz
128MB SDRAM
32MB 内蔵フラッシュメモリ
以上
これだけだと動いているのかどうかすら分からなくて切なくなってくるので拡張ボードを付けるのだが、よく使う拡張ボードを一式セットにしたgumpackなるものが存在する。例えばこんなやつ。えてして組み込みデバイスは個人で買おうとするとハードルが高いことが多いが、gumstixはgumstix storeで1個から購入出来る、という週末のハッキングに使いたいヤツにうれしい販売形態になっている。
ちなみに、gumstixの開発者サイトgumstix.netによると現行のverdexの後継、verdex proの開発が今年のQ3あたりでのリリースを目指して進行中らしい。
gumstixは板ガムサイズのLinuxマシンを作るプロジェクト。
メイン基盤の仕様こそ簡素だが多彩な拡張ボードに対応し、組み立てPCの感覚で好きな構成にすることができる。現時点でもっとも高性能なverdex XL6Pの仕様は以下のとおり。
Marvell社製XScale PXA270 600MHz
128MB SDRAM
32MB 内蔵フラッシュメモリ
以上
これだけだと動いているのかどうかすら分からなくて切なくなってくるので拡張ボードを付けるのだが、よく使う拡張ボードを一式セットにしたgumpackなるものが存在する。例えばこんなやつ。えてして組み込みデバイスは個人で買おうとするとハードルが高いことが多いが、gumstixはgumstix storeで1個から購入出来る、という週末のハッキングに使いたいヤツにうれしい販売形態になっている。
ちなみに、gumstixの開発者サイトgumstix.netによると現行のverdexの後継、verdex proの開発が今年のQ3あたりでのリリースを目指して進行中らしい。