ラベル ARM の投稿を表示しています。 すべての投稿を表示
ラベル ARM の投稿を表示しています。 すべての投稿を表示

2014年5月23日金曜日

ARMでビットリバーサル

ARMでビットリバーサルを行う方法について

inline uint32_t REV(uint32_t din) {
    uint32_t dout;
    __asm__("REV %[Rd], %[Rs1]" : [Rd] "=r" (dout) : [Rs1] "r" (din));
    return(dout);
}

inline uint32_t RBIT(uint32_t din) {
    uint32_t dout;
    __asm__("RBIT %[Rd], %[Rs1]" : [Rd] "=r" (dout) : [Rs1] "r" (din));
    return(dout);

}


RBITがビットリバーサルです
RBIT命令は32bitのI/Oなので、8bitの入れ替えをしようと思うと予期しない結果になります
解決手段としては
1) ビットシフトで移動する
2) エンディアン変換で移動する
3) ポインタで正常な位置から読み出す
    (もしくは最初にポインタでオフセットした位置に書き込む)
という方法があります

1と3については説明は不要だと思います

2のエンディアン変換はREV関数で行います
これも32bitI/Oです


動作確認については
    uint32_t data = 0x12345678;
    uint8_t *p = (uint8_t*)&data;
       
    xprintf("%02X %02X %02X %02X\n", p[0], p[1], p[2], p[3]);
    data = REV(data);
    xprintf("%02X %02X %02X %02X\n", p[0], p[1], p[2], p[3]);
    data = RBIT(data);
    xprintf("%02X %02X %02X %02X\n", p[0], p[1], p[2], p[3]);
という感じ
1回目のprintfでは78 56 34 12が出てきます
2回目はエンディアンを入れ替えた12 34 56 78が出てきます
3回目はビットリバーサルした結果の1E 6A 2C 48が出てきます

8bit変数のビットリバーサルを行いたい場合は
REV(RBIT( (uint8_t)hoge ))
という感じになります
REVとRBITはどちらが先でもいいはずです

でもビットリバーサルをやりたいだけならビットシフトのほうがらくだと思います


追記:2014-07-04
core_cm3.hに__RBIT及び__REV関数がありました
どちらも引数は32bitが1個 戻り値が32bit それぞれ符号無しです
やっていることはほぼ同じです

2012年5月15日火曜日

ARMの変数型名

ARMは環境依存の変数型を無くすために普通のCとは違う名前で型が宣言されてます
ってことで その一覧です


通常の宣言 CMSISでの宣言
-
signed long - int32_t
- signed short - int16_t
- signed char - int18_t
- signed long const const int32_t
- signed short const const int16_t
- signed char const const int8_t
volatile signed long - __O int32_t
__IO int32_t
volatile signed short - __O int16_t
__IO int16_t
volatile signed char - __O int8_t
__IO int8_t
volatile signed long const __I int32_t
volatile signed short const __I int 16_t
volatile signed char const __I int8_t
- unsigned long - uint32_t
- unsigned short - uint16_t
- unsigned char - uint8_t
- unsigned long const const uint32_t
- unsigned short const const uint16_t
- unsigned char const const uint8_t
volatile unsigned long - __O uint32_t
__IO uint32_t
volatile unsigned short - __O uint16_t
__IO uint16_t
volatile unsigned char - __O uint8_t
__IO uint8_t
volatile unsigned long const __I uint32_t
volatile unsigned short const __I uint16_t
volatile unsigned char const __I uint8_t

↑の表のように 用途によって 色々と決まりごとがあるみたいです
(excelからコピペしただけなので見づらいですがご了承ください)

もちろん普通のCのようにintとかcharとかboolも可能ですが
この表に従ったほうが環境依存が減るので楽なんだそうです
覚えるのめんどくせーよ…

で ちょっと解説
かなり憶測を含んでるので間違ってたらごめんなさい
まず型の大きさですが
これはint+ビット数で決まります
コンパイラ依存のビットサイズじゃないので
移植が楽だけではなく 読むときにも楽なんだそうです

signed/unsignedですが まぁこれは説明しなくてもわかりますよね
符号あり/なしの区別です
符号ありはint 符号なしはuintです
constは定数か否かみたいな意味合いもありますが
組み込みの場合はRAMかROMかという違いもあります
でもまぁあまり意識することはないと思います

で 問題なのがvolatileっていう国の名前みたいなモノ
これはコンパイラの最適化を無効化するみたいな意味があります
例えば
uint8_t flag = 1;
while(flag) { ... }
というコードがあったて ブロックの中でflagを書き換えていない場合
コンパイラは
while(1) { ... }
と書き換えます

これは「どーせ値が変更されることはないんだから判定するだけムダ」という理由によるものですが
もしかしたらこのflagは割り込みで変更される可能性があるかもしれません
例えばシリアルの送信完了でRESETされる場合
本来は送信が終了されるまで待つだけのはずなのに
実際は無限ループに陥ってしまいます

これを回避するためにvolatileをつけることにより
「この変数は外部から変更されるので強い最適化はしないように」
ということになります

volatileについてはこのページがわかりやすいです

__IOだけでなく__Oも有るのは
コード中から間違って書き換えないように ということだと思います
が __Oを使う用途というのはあまり思いつかない(無いわけではない)


とりあえず こんなところですが
今まではARMでも普通にintとかcharとか使ってたけど
これから少しずつint32_tみたいな書き方に移行していこうかなぁ と 思ったり

2012年4月20日金曜日

STBeeMiniでタイマ割り込み

STBeeMiniでタイマ割り込みを実装してみました
とりあえず動いたので報告だけ
ソースは綺麗にしてからうpします

1mS毎に割り込みをかけてLEDをチカチカさせます
まぁ500Hzだと点滅なんぞわかりませんが

正確に500Hzじゃないのは
 水晶の精度か定数の設定か
計算上クロック1個分少ないと500.006945Hzになるので
多分定数のミスです
とりあえず ミリ秒単位で割り込みが出来れば1000カウントとunsigned longで起動時間管理が楽になるので いろいろ面白いことができると思う

タイマ割り込みと USART実装して あとADCが出来れば
データロガーとして使えるので 面白くなりそう

あとはprintfが使えれば文句ないんだけどなぁ…w

2012年4月8日日曜日

STBeeでUSART

やっと!STBeeで1バイト送信ができるようになった
なんで動かなかったかというと
USART_Cmd(USART1, ENABLE);を忘れていた
というか知らなかった という…
ってことで GPIOを初期設定後にASCII'A'を送信しつつLチカするコード↓
開発環境はストリナに書いてある方法です
アレ楽でいいね!!

#include "stm32f10x_conf.h"
#include <stdio.h>

#define GPDON(PIN) { GPIOD -> BSRR = _BV(PIN); }
#define GPDOF(PIN) { GPIOD -> BRR  = _BV(PIN); }
#define GPDSET(PIN, bit) { if(bit){ GPDON(PIN); }else{ GPDOF(PIN); } }


void Delay(volatile unsigned long delay)
{ while(delay) delay--; }

int main(void) {
    int flag;
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
                  
    // システムを初期化します(外部水晶をONにし72MHz動作に切り替えます)
    SystemInit();
                  
    // GPIO Dポートのクロックを有効にします
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

    // PD.4ポートを出力にします。PD.4=LED Lowで点灯
    GPIO_InitStructure.GPIO_Pin = _BV(4);
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOD, &GPIO_InitStructure); // 初期化関数を読み出します。

    // PA.9 Output
    GPIO_InitStructure.GPIO_Pin = _BV(9);
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
                  
    // PA.0ポートを入力に
    GPIO_InitStructure.GPIO_Pin = _BV(0);
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
   
    // USART init
    USART_InitStructure.USART_BaudRate = 9600;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Tx; /* | USART_Mode_Rx */ // ←受信機能を有効にするにはコメントアウトを解除

    USART_Init(USART1, &USART_InitStructure);
    USART_Cmd(USART1, ENABLE);
   
    for ( ; ; ) {
        USART_SendData(USART1, 'A');
        flag = !flag;
        GPDSET(4, flag);
        Delay(GPIO_ReadInputDataBit(GPIOA, 1) ? 2000000 : 1000000);
    }
}

なんか
Visual Studio→Word→Bloggerオンラインエディタ
で張り付けると
文字の色が保持されるかわりに タブが恐ろしいことになるんだよね
なんでだろう?
'\t'の扱いがVCでは半角スペース4文字だけどBloggerエディタだと違う とかかな?
追々直しますヾ(゚Д゚ )ォィォィ
↑修正しました 一部アレだけど まぁ 我慢してください

で、なぜprintfが使えないか
個人的に 正解率1割以下の勘を信じると
おそらくstdoutが無いんじゃないかと
だって シリアル出力だけで5系統あるわけじゃないですか(多分
んで それ以外にも ユーザーが作った出力があるかもしれない
となると stdoutを決めておくより
あとで定義したほうが自由度が高い
ってことじゃないかと

まぁエラーメッセージ的にはまったく違う理由っぽいですが

とりあえず そんな感じです

うー めんどくさいなぁ OS使いたいなぁ(((

2012年4月7日土曜日

STBeeでLチカ

今さらながらに
STBeeでLチカやってみました
ポートの入力/出力です


#include "stm32f10x_conf.h"

#define GPDON(PIN) { GPIOD -> BSRR = _BV(PIN); }
#define GPDOF(PIN) { GPIOD -> BRR  = _BV(PIN); }
#define GPDSET(PIN, bit) { if(bit){ GPDON(PIN); }else{ GPDOF(PIN); } }

void Delay(volatile unsigned long delay)
{ while(delay) delay--; }

int main(void) {
    int flag;

    GPIO_InitTypeDef GPIO_InitStructure;
                  
    // システムを初期化します(外部水晶をONにし72MHz動作に切り替えます)
    SystemInit();
                  
    // GPIO A/Dポートのクロックを有効にします
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);

    // PD.4ポートを出力にします。PD.4=LED Lowで点灯
    GPIO_InitStructure.GPIO_Pin = _BV(4);
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOD, &GPIO_InitStructure); // 初期化関数を読み出します。
                  
    // PA.0ポートを入力に
    GPIO_InitStructure.GPIO_Pin = _BV(0);
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
                                    
    for ( ; ; ) {
          flag = !flag;
          GPDSET(4, flag);
          Delay(GPIO_ReadInputDataBit(GPIOA, 1) ? 1000000 : 2000000);
    }
}


開発環境はストリナで配布されてるモノ
ユーザースイッチが押されているか押されていないかで点滅周期が変わるプログラム

とりあえず入出力ができるようになったので
あとは割り込みとシリアル通信が出来れば
かなり色々と遊べる
タイマ割り込み/シリアル通信/ADCが出来れば 最低限の缶サットは作れるしなぁ

割り込みはめんどくさそうだし
とりあえずUSARTとADCを目指して
PIC飛ばす前にSTBee飛ぶかも?(缶サット