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

2013年11月26日火曜日

STM32F1 ピン変化割り込み

STM32F1のピン変化割り込み EXTIの初期化方法について

今回は僕のボードの関係でPD1の立ち上がりエッジで割り込みが入るように設定する

クロックの供給

AFIOとGPIOのクロックを有効化する
一般的な有効化と同じ手順
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,   ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,  ENABLE);

今回はUART5 RXを使うためにGPIODを
JTAGを無効化するためにAFIOを 
それぞれクロックを供給していたので追加のコードは必要なかった
/*
  JTAGを無効化するにはAFIOを初期化して
  AFIO->MAPR = _BV(26);
  として26bitを立ててやればJTAGとSWJの両方を無効化できる
*/


GPIOの初期化

これも一般的な初期化の方法と同じ
GPIO_InitTypeDef GPIO_InitStructure;
で構造体を確保し
GPIO_InitStructure.GPIO_Pin = _BV(1);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOD, &GPIO_InitStructure);
でPD1を入力モードにした
IPUでもIPDでも問題ないはず

EXTIの有効化

GPIO_EXTILineConfig関数を使う
第一引数にポートを 第二引数にピンを指定する
これは一般的なGPIOAや_BV(0)といった指定方法ができない
GPIO_PortSourceGPIOAやGPIO_PinSource0というマクロを使う
今回はGPIODのピン1を使うので
GPIO_EXTILineConfig(GPIO_PortSourceGPIOD, GPIO_PinSource1);
という感じ
/*
  ヘッダファイルを見てみるとGPIO_PortSourceGPIOAは ((uint8_t)0x00) が Bは0x01 Cは0x02
  GPIO_PinSource0は ((uint8_t)0x00) が 1は0x01 2は0x02
  という感じで指定されている

  一般的なGPIOAやGPIOBはペリフェラルのポインタが
  _BVは #define _BV(n) ( 1 << (n) ) という指定でビットシフトしている
  そのため基本的にGPIO_PortSourceとGPIOxの互換性は全くない ピン指定も同じ
*/


EXTIの初期化

EXTI_Init関数を使う
EXTI_InitTypeDefポインタを引数にする
中身は 
    EXTI_Line
    EXTI_LineCmd
    EXTI_Mode
    EXTI_Trigger
の4個

LineはEXTI_Line0からEXTI_Line19の20個から選択
ピン0がLine0 ピン15がLine15という感じで割り付けられている
また16,17,18,19はそれぞれ電圧計国やRTCのアラーム等に設定されている

LineCmdは有効化するか否かをENABLE/DISABLEで選択
Modeは割り込みかイベントを選択 それぞれEXTI_Mode_InterruptとEXTI_Mode_Event
Triggerはどちらのエッジを使うか 
    EXTI_Trigger_Risingで立ち上がり
    EXTI_Trigger_Fallingで立ち下がり
    EXTI_Trigger_Rising_Fallingで両方
という感じ

今回はピン1の立ち上がりエッジで割り込み という設定なので
EXTI_Line1 ENABLE EXTI_Mode_Interrupt EXTI_Trigger_Rising
で初期化する

// PB1は立ち上がりで PC1は立ち下がりで とかの割り込みはどうするんだろう?

NVICの設定

NVICの設定は一般的な設定と同じ
ここは省略する
NVICのチャンネルはEXTI1_IRQn等を設定する

割り込みハンドラ

割り込みで呼び出される関数
void EXTI1_IRQHandler(void)
となる
中で EXTI_ClearITPendingBit(EXTI_Line1); でペンディングビットをクリアする必要がある
EXTI_GetITStatusを使ってLine1のペンディングビットを確認することができるけど EXTI1_IRQHandlerはLine1割り込みしか呼ばれないはずなのでGetで確認は不要のはず



上記の手順でEXTI割り込みが使えるようになる
しかし、ピン変化割り込みハンドラが呼ばれても、どのラインの割り込みか はわかるが
どのポートが割り込み操作のトリガになったかは判別できない気がする
例えばPA1とPB1の両方に割り込みを設定した場合、Px1が動いた と言うのはわかるんだが、それがAなのかBなのかは判断できない

あとPA1は立ち上がり PB1は立ち下がり とかだとRising_Fallingにして、ハンドラで確認する必要があるのか?

気が向いた時にでも調べておく必要がある

2013年10月15日火曜日

STM32F1 CANの速度

STM32F1のリファレンスマニュアル RM0008 Rev5 日本語版によるとCANの速度は以下のように説明されています


Rev14でも同じ内容です

実際にBaudRateを計算してみましょう
まずAPBクロックの周期とは
CAN1が接続されているAPB1のMax36MHzです
これでtPCLK = 36MHzの周期 = 0.027778マイクロ秒となります

次にtqですが ここにはBRP[9:0]というのが出てきます
これはCAN_BTRレジスタの中にあり
標準ペリフェラルライブラリ CAN_Initでは
((uint32_t)CAN_InitStruct->CAN_Prescaler - 1)
が他のレジスタとORで代入されています
つまりCAN_InitTypeDef.CAN_Prescalerに入れた値から1を引いた数が入ります
しかし計算時には1を足しているのでCAN_Prescaler*tPCLKとすることができます

Prescalerを6と仮定した場合
tq = Prescaler * tPCLK = 6 * 0.027778 = 0.166668
となります

tBS1とtBS1もTS1とTS2がありますが、これもCAN_BTRの中にあります
それぞれCAN_BS1_xtqとCAN_BS2_xtqという定数で設定し、1tqは0が 2tqは1が 3tqは2が~ という関係です
しかしこのレジスタも計算時に1を足しているので1tqが1 2tqが2として計算できます
CAN_StructInitではCAN_BS1_4tqおよびCAN_BS2_3tqが代入されるため
tBS1 = tq * BS1 = 0.166668 * 4 = 0.666672
tBS2 = tq * BS2 = 0.166668 * 3 = 0.500004
となります

NominalBitTimeはそれぞれを足し算しているだけですので
NominalBitTime = 1 * tq + tBS1 + tBS2 = 0.166668 + 0.666672 + 0.500004 = 1.333344
となります

BaudRateは1をこの数で割っているだけなので
1 / NominalBitTime = 1 / 1.333344 = 0.75
となり、ビットレートは0.75となります
しかし最初にtPCLKをマイクロ秒としているため、ビットレートの単位を合わせると0.75Mで、750kBit/secとなります
この結果はオシロスコープで実測した値とおおよそ一致します

実際にCANbusを使う場合はプリスケーラ10で450kbpsとなり、東陽テクニカのWebページを参考にした場合で100mほど距離の通信ができます
AWG23-24の線材を使った場合のノード数は100で、これは1m間隔に1ノード程度となります

一旦機器を設置してしまうとビットレートの変更は容易では無いため、実際にビットレートを設定する場合は設置する環境を十分に見積もった上で もしくは簡単にビットレートを変更できるように工夫するべきです
同一のCANバス内で複数のビットレートが混在することは許可されていないため、ビットレートの設定は十分に注意する必要があります

2013年10月8日火曜日

STM32F1 standard peripheral CAN

STM32F1のCAN周り覚書

なお古いライブラリ(少なくとも4年以上)を使っているので、最新とは違うかも

CanRxMsgの中身
    uint32_t StdId;
    uint32_t ExtId;
    uint8_t IDE;
    uint8_t RTR;
    uint8_t DLC;
    uint8_t Data[8];
    uint8_t FMI;

・StdId
標準の識別子 0から0x7FFの範囲

・ExtId
拡張識別子 0から0x1FFFFFFFの範囲

・IDE
受信したメッセージの識別子タイプ CAN_identifier_type

・RTR
受信したメッセージのフレームタイプ CAN_remote_transmission_request

・DLC
受信したフレームの長さ 0から8の範囲

・Data[8]
受信したデータ 配列は8バイト確保されている 有効なデータ数はDLC

・FMI
フィルタ関係?


CAN_identifier_typeについて
    #define CAN_ID_STD
    #define CAN_ID_EXT
    #define IS_CAN_IDTYPE(IDTYPE)
CANID_STDとCANID_EXTがある
それぞれ標準IDと拡張IDを示している
IS_CAN_IDTYPEは「引数がSTDかEXTならば0位外を返す」というマクロ
ただCAN_ID_STDもCAN_ID_EXTも中身はuint32_t
STDかEXTかを調べるには自分でifで判断する必要がある


CAN_remote_transmission_requestについて
    #define CAN_RTR_DATA
    #define CAN_RTR_REMOTE
    #define IS_CAN_RTR(RTR)
CAN_identifier_typeと同様

なお (CAN_RTR_DATA == CAN_ID_STD) == true という関係なので
例えばIS_CAN_IDTYPE(CAN_RTR_DATA)とやるとtrueになる(おそらく
このためIS_CAN_IDTYPEやIS_CAN_RTRはあまり信用しない方がいいはず


CAN_MessagePendingについて
宣言は以下のとおり
uint8_t CAN_MessagePending(CAN_TypeDef* CANx, uint8_t FIFONumber);

説明は以下
  * @brief  Returns the number of pending messages.
  * @param  CANx: where x can be 1 or 2 to to select the CAN peripheral.
  * @param  FIFONumber: Receive FIFO number, CAN_FIFO0 or CAN_FIFO1.
  * @retval NbMessage which is the number of pending message.
要約すると
説明:保留中のメッセージの数を返す
引数:CAN1もしくはCAN2 ペリフェラルを選択
引数:FIFOの選択 FIFO0もしくはFIFO1
戻り値:保留中のメッセージ数

何をする関数かというと、FIFOにたまっているメッセージ数を返す
中身は
(uint8_t)(CANx->RF0R&(uint32_t)0x03)
もしくは
(uint8_t)(CANx->RF1R&(uint32_t)0x03)
を引数に応じて返している

CanRxMsg構造体の中にはデータの有効性を確認するためのレジスタはない
また、CAN_Receive関数の中にもデータの存在を確認する処理はない
FIFOにデータが有ろうが無かろうがReceive関数を呼べばFIFOの中身を返してくる
しかしFIFOの中身が0であれば意味のない値になる
しかし意味がある値日意味のない値かは値から判断することはできない

実際にCANを使う場合は一定期間ごとにCAN_MessagePendingをポーリングして
戻り値>0が真の場合にCAN_Receiveを読んでデータを処理することになる


CANで1つのデータが一番短い時はRTRの37bit
1Mbpsで通信している場合40bitとして1回40マイクロ秒くらい
実際にはもっと長いけど、FIFOが4フレーム分3フレーム分しか無いことを考えるとかなり高速でポーリングする必要があるかも
といってもまぁものすごいクリティカルな用途でもなければ秒数百回程度ポーリングすれば十分なはず

最悪の場合スマートじゃないけどCanRxMsgの配列を作ってCAN受信割り込みでリングバッファに貯めこんで大容量のFIFOを作るってやり方もあるw

2013年9月16日月曜日

STM32F1でTIMのパラメータ

STM32F1のTIMのパラメータ
この関数は引数1で与えた周波数になるように引数2と引数3のポインタにパラメーターを書き込む

// 0:成功 
// 1:システムクロックで割り切れない周波数 
// 2:プリスケーラの設定中に丸め誤差が発生した 
uint8_t TIM_GetFreqencyPrameter(uint32_t Freqency, uint16_t *pPeriod, uint16_t *pPrescaler) {
    const uint32_t cSysFreq = 72 * 1000 * 1000;
    uint32_t per, pre;
    
    if (cSysFreq % Freqency) { return(1); }
    
    per = cSysFreq / Freqency;
    pre = 1;
    
    while (per > 0xFFFF) { per /= 10; pre *= 10; }
    
    if ((cSysFreq / per / pre) != Freqency) { return(2); }
    
    *pPeriod    = per - 1;
    *pPrescaler = pre - 1;
    
    return(0);

}

なおシステム周波数はcSysFreq変数に設定され、この例では72MHzとなっている
計算上完璧な周波数以外は1or2が返される
正常な場合は0が返され、ポインタに値が設定される


とりあえず軽く動作確認はしていますが、使うときは自己責任でどーぞ
例えば7Hzや11Hzは作成できません
11Hzは整数で割り切ることができないので1が帰ります
7Hzは整数で割り切ることができますが、0xFFFFより大きな数字になってしまうため、丸め誤差エラーが発生し2が帰ります

ラッパー関数を作ればサクッとタイマの初期化もできますが、信頼性は低いのであまり多様しないように

2013年9月8日日曜日

STM32F103でCAN通信(その2)

CANトランシーバIC"MCP2551"が届いたので
試してみました

ソースコードは以前の流用です


赤がCAN-H 黄色がCAN-L
緑はその差分

上のキャプチャはふたつのMCP2551のTXとRXをキャプチャしたもの

CAN1TXから出力された信号はCAN1RXとCAN2RXから出てきています

上の画像は
000010100101000011010101010010101010000010001111101110000010011000001000111000010110
という感じのビットになっており
分解すると
のようになります

送信したデータは
Idが0xA5のスタンダード
データ長は6で0xAA 0x55 0x00 0xFF 0x01 0x80
です

5bitほど足りませんが、CRCの最後2bitが1であると仮定した場合は辻褄が合います
データの4byte以降が9bitなのはビットスタッフの影響です

今はひとつのマイコンから送信しているだけなので、次は他のマイコンで受信 などをしてみたいですね
それができたらなが~いLANケーブルでも買ってきて長距離通信やってみようかな

2013年9月2日月曜日

STM32F1で送信バッファ

STM32F103VEで送信バッファを作ってみました
STM以外にも使えると思いますが


ヘッダファイルにdefineでUSART3writeLine(送信バッファを有効化するフラグ)とUSART3writeBufferSizeがあります
また、別の場所では #ifndef USART3writeLine で送信バッファを使わない送信関数もあります

送信バッファは受信バッファと違い、行識別等が不要なので関数2個といくつかの変数だけで実装可能です

2013年8月30日金曜日

STM32F103でCAN通信

STM32F103VE(事実上のSTBee)を使ったCAN通信のメモ
嘘偽りなく調べ物した時のメモとしてそのままブログのエディタを使ってるので可読性とかは気にしていません


2013年6月2日日曜日

STM32F103VET6を使う

前にRSでついでに買ったSTM32F103VET6ですが
やっと変換基板に載せたので
「こんなこと始めました」ということで 報告

STM32F103VET6について
RSの販売ページ

性能としては
ARM Cortex-M3
72MHz
ROM512k/RAM64k
100pinのQFP
という感じ
ピンピッチは0.5mmなので秋月の変換基板に載せることができます

ハンダ付けの方法についてはネットにいくらでも情報が転がっているので特には書きませんが
30Wのコテと鈴60%のハンダ それとハンダ吸い取り線でできます
0.5mmピッチはかなり前にFT232を実装して以来ですが、意外と 簡単に できます


水晶とか色々面倒なのでとりあえず内部クロックで動かしてみようかと思っているのですが
システムの初期化がよくわからなくて進んでないというのが現状です

予定としてはSTM32F4でぃすかばーがSWD接続のライタとして使えることが確認できたので
内部クロックを使ったLチカコードを試してみたいなーと思ったりしてます


PIC16F84Aとかは機能が少ない分初期化が楽だし
16F88だって内部クロックの初期化とかも比較的カンタンにできるんですが
さすがに32bitマイコンともなるとそう簡単には動いてくれなさそうな

2012年5月6日日曜日

STBeeでDAC

STBeeには12bitのDACが2本あります


PA4のDAC1とPA5のDAC2です
で これが使えれば面白そうだなぁと おもって
関数もADCより少ないので 楽にできそうだな と思って
試してみました