概要

 OpenSSMの細かな機能を説明します。組込機器となりますので、回路とファームウェアは密接に絡んでいることもあり、ハードウェア/ソフトウェアを同時に説明します。

 OpenSSMのファームウェアは、RTOS等の OSを使わず独自の環境下(プログラムライブラリ)に構築されています。最初は分かりにくい/理解しにくいと思われるところも多々あると思いますので、各ライブラリの説明ページを設けました。

 RTOSではマルチタスクが使えるため大変便利ですが、OpenSSMでは各タイマ割込をタスク代わりに使っています。また一部の処理では、イベントもどきの概念(あるいは、コルーチンに近い)を導入しています。

1.png

Fig.1 アプリケーション層とライブラリ(ドライバ)の関係

開発環境

 C言語で開発されています。ごくごく一部に、インラインアセンブラが使用されています。

  1. Microchip MPLAB
  2. Microchip C Compiler for PIC24

ライブラリについて

 ライブラリとなる対象は、他のソフトウェアへの流用が可能かどうかという点において決められています。そのハードウェアあるいはアプリケーション固有となる機能の場合は、ライブラリ化されていません。  ライブラリは、lib〜.c, lib〜.hと、libが接頭辞としてファイル名が決められています。また必ず lib〜.c, lib〜.hとペアでファイルが存在します。場合によっては、外部のテーブルを参照することがあり、その場合は table.hが必要になります。

ソースコード名ヘッダ名機能備考
libadc.clibadc.hA/D変換ドライバ
libdac.clibdac.hD/A変換ドライバ
libeeprom.clibeeprom.hI2C対応の EEPROMドライバ
libfontx2.clibfontx2.hFONTX2ドライバ (ASCIIフォントのみ)FONTX2のフォントファイルが別途必要
libps2.clibps2.hPS/2対応キーボードドライバ
librtc.clibrtc.hSoftware RTCドライバ
libuart.clibuart.hSoftware FIFO対応 UARTドライバ
libvideo.clibvideo.hNTSCビデオ出力/スーパーインポーズドライバ
table.ctable.h数値参照用のテーブル
types.hBOOL型など変数型の定義

アプリケーションについて

 OpenSSMのアプリケーション層に相当する部分は、下記のコードにまとめられています。  

ソースコード名ヘッダ名機能備考
main.cmain.h各初期化の呼び出し、main関数、メインループなど
config.cconfig.hEEPROMへのバックアップ/リストアを行う
extmeter.cextmeter.h外付けメータの制御を行う
screen.cscreen.h画面表示の制御及びキーボード入力処理を行う
ssm.cssm.hプロトコル処理を行う

その他

 開発の後半でスタックメモリが足りなくなってしまったので、かなりの関数を inline展開しています。ROMは比較的余裕があるので、実際のところは大したことないですが...

PIC24Fのオーバークロック

 PIC24Fでは、OSCTUNレジスタを操作することによって、内蔵 FRCのクロックを 8MHz±12%まで変更することができます。また 4倍の PLLを内蔵していますので、標準のクロック 8MHz * 4 = 32MHz (Fcy = 16MHz) を超えてオーバークロック状態で動作させることができます。

 これまで確認したところでは、特に目立った発熱もなく極めて安定して動作しているようです。また大変都合の良いことに、クロックを一番上まで上げた状態 (Fcy = 17.92MHz) だと、UARTのボーレート計算結果がよく、とても使いやすいです (fileOSCTUN and UART for PIC24F.xls)。

OpenSSMでは、OSC 8.96MHz, Fcy = 17.92MHz, Fcpu = 35.84MHz に設定しています

サンプルコード

 CLKDIVと OSCTUNレジスタを操作して、CPUクロックを変更します。また、この操作はいつでも実行できます。省電力にさせたいときはクロックを下げるなど、いろいろ使い道があります。

 詳しくは、PIC24Fのデータシートを参照してください

#include <p24FJ64GA002.h>

_CONFIG1(   JTAGEN_OFF &
            GCP_OFF &
            GWRP_OFF &
            BKBUG_OFF &
            WINDIS_OFF &
            COE_OFF &
            ICS_PGx1 &
            FWDTEN_ON &
            WDTPS_PS256) 

_CONFIG2(   IESO_OFF &
            FNOSC_FRCPLL &
            FCKSM_CSDCMD &
            OSCIOFNC_ON &
            IOL1WAY_OFF &
            I2C1SEL_PRI &
            POSCMOD_NONE)

int main(void)
{
    /* Fosc = 8.96MHz, Fcy = 17.92MHz, Core 35.84MHz */
    CLKDIV = 0;
    OSCTUN = 0b0000000000011111;

    while(1){
        ClrWdt();
    }

    return(0);
}

OSCTUNレジスタと CPUクロックの関係

OSCTUNOFFSETFRC (Hz)Fcy (Hz)
011111310.1200008,959,99817,919,996
011110300.1161298,929,03017,858,061
011101290.1122588,898,06317,796,125
011100280.1083878,867,09517,734,190
011011270.1045168,836,12717,672,255
011010260.1006458,805,16017,610,319
011001250.0967748,774,19217,548,384
011000240.0929038,743,22417,486,449
010111230.0890328,712,25717,424,513
010110220.0851618,681,28917,362,578
010101210.0812908,650,32117,300,643
010100200.0774198,619,35417,238,707
010011190.0735488,588,38617,176,772
010010180.0696778,557,41817,114,836
010001170.0658068,526,45117,052,901
010000160.0619358,495,48316,990,966
001111150.0580648,464,51516,929,030
001110140.0541938,433,54816,867,095
001101130.0503228,402,58016,805,160
001100120.0464528,371,61216,743,224
001011110.0425818,340,64416,681,289
001010100.0387108,309,67716,619,354
00100190.0348398,278,70916,557,418
00100080.0309688,247,74116,495,483
00011170.0270978,216,77416,433,548
00011060.0232268,185,80616,371,612
00010150.0193558,154,83816,309,677
00010040.0154848,123,87116,247,741
00001130.0116138,092,90316,185,806
00001020.0077428,061,93516,123,871
00000110.0038718,030,96816,061,935
00000000.0000008,000,00016,000,000
111111-1-0.0037507,970,00015,940,000
111110-2-0.0075007,940,00015,880,000
111101-3-0.0112507,910,00015,820,000
111100-4-0.0150007,880,00015,760,000
111011-5-0.0187507,850,00015,700,000
111010-6-0.0225007,820,00015,640,000
111001-7-0.0262507,790,00015,580,000
111000-8-0.0300007,760,00015,520,000
110111-9-0.0337507,730,00015,460,000
110110-10-0.0375007,700,00015,400,000
110101-11-0.0412507,670,00015,340,000
110100-12-0.0450007,640,00015,280,000
110011-13-0.0487507,610,00015,220,000
110010-14-0.0525007,580,00015,160,000
110001-15-0.0562507,550,00015,100,000
110000-16-0.0600007,520,00015,040,000
101111-17-0.0637507,490,00014,980,000
101110-18-0.0675007,460,00014,920,000
101101-19-0.0712507,430,00014,860,000
101100-20-0.0750007,400,00014,800,000
101011-21-0.0787507,370,00014,740,000
101010-22-0.0825007,340,00014,680,000
101001-23-0.0862507,310,00014,620,000
101000-24-0.0900007,280,00014,560,000
100111-25-0.0937507,250,00014,500,000
100110-26-0.0975007,220,00014,440,000
100101-27-0.1012507,190,00014,380,000
100100-28-0.1050007,160,00014,320,000
100011-29-0.1087507,130,00014,260,000
100010-30-0.1125007,100,00014,200,000
100001-31-0.1162507,070,00014,140,000
100000-32-0.1200007,040,00014,080,000

8.96MHzのときのボーレート設定一覧

 Low MODE / High MODEは、UARTの BRGHレジスタの設定を指しています。詳しくは、PIC24Fのデータシートを参照してください。

BaudrateFosc (MHz)PLLFcy (MHz)Low MODEHigh MODE
Calc BRGBRGCalc BaudrateErrorCalc BRGBRGCalc BaudrateError
92160089599982179199960.21527750701119999.7521.528%3.8611100264895999.80-2.778%
57600089599982179199960.944444011559999.88-2.778%6.7777760427559999.88-2.778%
50000089599982179199961.23999951559999.8812.000%7.9599988497777.67-0.444%
46080089599982179199961.4305550131559999.8821.528%8.7222200529447999.90-2.778%
25600089599982179199963.3749990233279999.949.375%16.4999960916263529.352.941%
25000089599982179199963.4799993279999.9412.000%16.91999617248888.83-0.444%
23040089599982179199963.8611100264223999.95-2.778%18.444440118235789.422.339%
15360089599982179199966.2916650396159999.964.167%28.1666601628154482.720.575%
12800089599982179199967.7499980478124444.42-2.778%33.9999921934127999.97-0.000%
11520089599982179199968.7222200529111999.98-2.778%37.8888802138114871.77-0.285%
76800895999821791999613.583330081474666.65-2.778%57.333320315777241.360.575%
64000895999821791999616.499996091665882.342.941%68.999984386963999.99-0.000%
57600895999821791999618.44444011858947.362.339%76.777760427757435.88-0.285%
56000895999821791999618.999995541955999.99-0.000%78.999982147955999.99-0.000%
51200895999821791999620.874995122150909.08-0.568%86.499980478651494.240.575%
38400895999821791999628.166660162838620.680.575%115.666640611638290.59-0.285%
28800895999821791999637.888880213828717.94-0.285%154.555520815528717.94-0.285%
19200895999821791999657.333320315719310.340.575%232.333281323219227.460.143%
16000895999821791999668.999984386916000.00-0.000%278.999937527916000.00-0.000%
14400895999821791999676.777760427714358.97-0.285%310.111041731014405.140.036%
96008959998217919996115.66664061169572.65-0.285%465.66656254669593.15-0.071%
72008959998217919996154.55552081557179.49-0.285%621.22208336217202.570.036%
48008959998217919996232.33328132324806.870.143%932.3331259324801.710.036%
40008959998217919996278.99993752794000.00-0.000%1118.9997511194000.00-0.000%
24008959998217919996465.66656254662398.29-0.071%1865.6662518662399.57-0.018%
18008959998217919996621.22208336211800.640.036%2487.88833324881799.92-0.004%
12008959998217919996932.3331259321200.430.036%3732.332537321200.110.009%
60089599982179199961865.666251866599.89-0.018%7465.6657466599.97-0.004%
30089599982179199963732.33253732300.030.009%14932.3314932300.010.002%

RTCドライバについて

 Microchip PIC24Fの内蔵タイマーを使用した Software RTC ドライバです。起動後のアワーメータ (tick、秒、分、時、日) と時刻 (ミリ秒, 秒、分, 時, 日) をカウントします。tickは、RTCドライバの基準時間単位です。標準では 0.1ミリ秒に設定されています。

仕様 

ソースコード

  1. librtc.c
  2. librtc.h
  3. table.c
  4. table.h
  5. types.h

回路図

 ありません。内部タイマーを使用しているのみで、ソフトウェアだけで動きます。

サンプルコード

#include <p24FJ64GA002.h>

#include "librtc.h"

_CONFIG1(   JTAGEN_OFF &
            GCP_OFF &
            GWRP_OFF &
            BKBUG_OFF &
            WINDIS_OFF &
            COE_OFF &
            ICS_PGx1 &
            FWDTEN_ON &
            WDTPS_PS256) 

_CONFIG2(   IESO_OFF &
            FNOSC_FRCPLL &
            FCKSM_CSDCMD &
            OSCIOFNC_ON &
            IOL1WAY_OFF &
            I2C1SEL_PRI &
            POSCMOD_NONE)

int main(void)
{
    unsigned int tick;

    /* Fosc = 8.96MHz, Fcy = 17.92MHz, Core 35.84MHz */
    CLKDIV = 0;
    OSCTUN = 0b0000000000011111;
    SRbits.IPL = 0;

    /* ポートの入出力モード設定 */
    /*          FEDCBA9876543210 */
    TRISA   = 0b0000000000000011;
    TRISB   = 0b0000111101100001;

    RTC_init();

    /* メインループ */
    tick = rtc.tick;
    while(1){
        ClrWdt();

        /* 100ms経過したら処理を行う */
        if(RTC_get_ticks(tick, rtc.tick) > 1000){
            /* 何かさせる */
        }
    }

    return(0);
}

分解能の変更方法

 標準では、1 tickの時間は 0.1ミリ秒ですが、下記のマクロを変更することで分解能を任意に変更できます。分解能を下げる (0.1ミリ秒より大きくする) と CPU負荷が下がり、分解能を上げる (0.1ミリ秒より小さくする) と CPU負荷も上がります。また、アワーメータの計算を正しく行うために、_T1Interrupt()関数内の時刻計算処理を修正してください。

 CPUクロックを動的に変更する場合は、RTC_init_timer()を適宜呼び出して PR1を初期化してください。


void __attribute__((interrupt, auto_psv)) _T1Interrupt(void)
{
    IFS0bits.T1IF = 0;

    /* tick is 0.1ms */
    rtc.tick++;
    if(rtc.tick % 10 != 0) return;

    /* ミリ秒 */
    rtc.msec++;
    rtc.msec = rtc.msec % 1000;
    if(rtc.msec != 0) return;

    /* 秒 */
    rtc.secmeter++;
    rtc.sec++;
    rtc.sec = rtc.sec % 60;
    if(rtc.sec != 0) return;

    /* 分 */
    rtc.minmeter++;
    rtc.min++;
    rtc.min = rtc.min % 60;
    if(rtc.min != 0) return;

    /* 時 */
    rtc.hourmeter++;
    rtc.hour++;
    rtc.hour = rtc.hour % 24;
    if(rtc.hour != 0) return;

    /* 日 */
    rtc.day++;

    return;
}
void RTC_init_timer(void)
{
    PR1 = cpu_fcy[ OSCTUN ] / 10000;        /* 0.1ミリ秒 */
    return;
}

void __attribute__((interrupt, auto_psv)) _T1Interrupt(void)
{
    IFS0bits.T1IF = 0;

    /* tick is 1ms */
    rtc.tick++;

    /* ミリ秒 */
    rtc.msec++;
    rtc.msec = rtc.msec % 1000;
    if(rtc.msec != 0) return;

    /* 秒 */
    rtc.secmeter++;
    rtc.sec++;
    rtc.sec = rtc.sec % 60;
    if(rtc.sec != 0) return;

    /* 分 */
    rtc.minmeter++;
    rtc.min++;
    rtc.min = rtc.min % 60;
    if(rtc.min != 0) return;

    /* 時 */
    rtc.hourmeter++;
    rtc.hour++;
    rtc.hour = rtc.hour % 24;
    if(rtc.hour != 0) return;

    /* 日 */
    rtc.day++;

    return;
}
void RTC_init_timer(void)
{
    PR1 = cpu_fcy[ OSCTUN ] /  1000;        /* 1ミリ秒 */
    return;
}

シリアル通信ドライバについて

 Microchip PIC24Fの UARTに Software FIFOを実装したシリアル ドライバ>です。 シリアルドライバは、PIC24Fのハードウェア UART 割込 (_U1TXInterrupt, _U2TXInterrupt, _U1RXInterrupt, _U2RXInterrupt) から呼ばれます。また、 2チャンネルの UARTに対して、送信/受信バッファサイズを任意に設定できます。

UARTxは、UART1またはUART2と置き換えてください

仕様

基板

RS-232RS-232C (D-Sub 9pin メス)
2400 〜 230kbps
送信バッファ 60byte
受信バッファ 8byte
OBD-IIISO-9141
4800bps
送信バッファ 50byte
受信バッファ 68byte

ファームウェア

通信速度300 〜 921.6kbps
FIFOバッファ有

ソースコード

  1. libuart.c
  2. libuart.h
  3. table.c
  4. table.h
  5. types.h

回路図

 PIC24Fの場合は、TXD/RXDをそれぞれ RPピンへ接続します。その後、ファームウェア側で RPピンに TXD/RXDの機能を設定します。したがって、RPピンであればどこに接続してもよく、非常に回路が組みやすくなっています。

 たとえば、ファームウェア書き換え用コネクタ (ICSP)の PGD/PGCピンに対して TXD/RXDを割り当て、デバッグ時のみシリアル通信を行うといったことが非常に簡単にできます。

UART.png

回路を変更するとき

 回路によって TX/RXのピンを変更する場合は、UARTx_init()関数内を変更してください。

バッファサイズの変更するとき

 libuart.hのマクロを変更してからコンパイルします。

#define UART1_TX_BUFFER_SIZE           128
#define UART1_RX_BUFFER_SIZE           128
#define UART2_TX_BUFFER_SIZE            50
#define UART2_RX_BUFFER_SIZE            70

サンプルコード

 送信/受信のサンプルソースコードです。回路図は、OpenSSM Rev.A を想定しています。

#include <p24FJ64GA002.h>

#include "table.h"
#include "libuart.h"

_CONFIG1(   JTAGEN_OFF &
            GCP_OFF &
            GWRP_OFF &
            BKBUG_OFF &
            WINDIS_OFF &
            COE_OFF &
            ICS_PGx1 &
            FWDTEN_ON &
            WDTPS_PS256) 

_CONFIG2(   IESO_OFF &
            FNOSC_FRCPLL &
            FCKSM_CSDCMD &
            OSCIOFNC_ON &
            IOL1WAY_OFF &
            I2C1SEL_PRI &
            POSCMOD_NONE) 

int main(void)
{
    int buf;

    /* Fosc = 8.96MHz, Fcy = 17.92MHz, Core 35.84MHz */
    CLKDIV = 0;
    OSCTUN = 0b0000000000011111;
    SRbits.IPL = 0;

    TRISA   = 0b0000000000000011;
    TRISB   = 0b0000111101100001;

    UART1_init(115200);
    UART2_init(  4800);

    /* 送信受信をループバック. エコー */
    while(1){
        ClrWdt();

        if((buf = UART1_getch()) > 0){
            UART1_putch(buf);
        }

        if((buf = UART2_getch()) > 0){
            UART2_putch(buf);
        }
    }

    return(0);
}
コンパイルの確認はしていません (^^;

参考文献

  1. Hyper Operating System (ITRON仕様OS) Ver.3 ソースコード (HOS-H8h Ver0.07)*1

ビデオドライバについて

 Microchip PIC24Fの SPIとタイマー割込を使用した Software ビデオ (NTSC) ドライバと文字表示を行うためのフォントドライバです。

 ビデオドライバは、モニタ出力 (通常の NTSC出力) とスーパーインポーズ出力に対応しています。スーパーインポーズ出力を行う場合は、外部のビデオ信号が必要となります。PIC24F内蔵の割り込みを使っているため非常に高速に描画することができ、フォアグラウンドの処理を邪魔しません (まさに OpenSSMが良い例でしょう)。また省電力機能にも対応しており、ビデオ表示を行いながら動的に CPUクロックを上げる/下げることもできます。

 フォントドライバは、FONTX2の半角文字フォントに対応しています。これまでいろいろな方が作成したフォントを、そのまま ROMに入れることができます。また、どんな変態フォントサイズ(^^; でも表示できます。

monitor_setup_ntsc.jpgsuperimpose_setup_ntsc.jpg

仕様

基板

ビデオ出力NTSC 4:3 ノーマルモード コンポジット白黒出力
RCAコネクタ メス
ビデオ出力は、黒色背景に白文字で描画されます
スーパーインポーズ入力NTSC 4:3 ノーマルモード コンポジットカラー/白黒出力
RCAコネクタ メス * 1個
NTSC以外 (PALなど) の映像入力は未対応
安物カメラでは信号波形がかなり汚いものがあり、画面が乱れる場合があります
スーパーインポーズ出力NTSC 4:3 ノーマルモード コンポジットカラー/白黒出力
RCAコネクタ メス * 1個
スーパーインポーズされた文字や図形は、白色で描画されます

ファームウェア

ビデオ/スーパーインポーズ出力同時使用不可
標準ビデオ解像度256×192ピクセル
32文字×12行
8×16ピクセルフォント (ぱうフォント)
最大ビデオ解像度*2288×224ピクセル
36文字×28行
8×8ピクセルフォント (美咲フォント)
ビデオオプション*3左右反転表示(バックカメラ等のため)
白黒反転表示
フォントドライバFONTX2ドライバ (ASCII文字のみ)
FONTX2に対応したフォントならば入れ替え可能

ソースコード

  1. libvideo.c
  2. libvideo.h
  3. libfontx2.c
  4. libfontx2.h
  5. table.c
  6. table.h
  7. types.h

回路図

 OpenSSM Rev.Aの回路図から、ビデオ信号に関する部分を抜粋しました。次のポイントに注意してください.

  1. 抵抗は、なるべく高精度品(±1%程度)を選定してください
  2. ダイオード D1は、Vref = 0.7V品を選定してください
  3. 電源は、+3.3V (VDD) と +5Vの 2つ必要です
  4. ビデオ出力とスーパーインポーズの回路は独立しています。どちらか1つだけ使うことも出来ます
schematic.png

ビデオ出力の概要

スーパーインポーズの概要

グラフの描き方 / グラフ関数の使い方

メータの描き方 / メータ関数の使い方

トラッカーの描き方 / トラッカー関数の使い方

フォントの変更のしかた

参考文献

  1. 後閑哲也, C言語ではじめる PIC24F活用ガイドブック, 技術評論社, 2007.
  2. トランジスタ技術SPECIAL No.52 ビデオ信号処理の徹底研究, CQ出版, 1996.

OBD-II Harness Drawing

 OpenSSMと自動車を接続する OBD-IIケーブルのハーネス図面です。

 市販の Ehternetケーブルを流用して、OBD-IIのケーブルとしています。

ハーネス図

ハーネス図のライセンスを確認する

 
OBD-II to 8P8C Cable Assembly.png

完成品

cable.jpg

ハーネス図の描き方

 カスタムケーブルを扱う/業者へ製造してもらう場合には、ハーネス図 (ケーブル加工図面、ケーブル加工の指図書) が必要となります。

世の中には、ハーネス図の描き方を解説した本がないんですよね... 完全にノウハウの世界です。誰か本を書かせてくれないかな〜 (^^;;

図面に描きいれる内容

 一般にハーネス図には、下記を入れます。

  1. コネクタとケーブルの模式図
    機械図面ではないので、鳥瞰図でなくとも良い。
  2. 結線図 (ネットリスト)
  3. 部品表 (メーカ名, 型番, 使用数量)
  4. 縮尺
  5. 加工公差
  6. 図番, 型番,
  7. 改訂履歴
  8. 設計, 製図, 検図, 承認等の責任の所在
  9. 著作権保護、図面の取扱上の注意
  10. RoHS対応の有無
すみません。OpenSSMのハーネス図は、かなり簡略化して描いてあります...

バグ

 OpenSSM開発中に見つけた ECUや Microchip PIC24F Series に関するバグをメモしておきます。すべて再現性がありますので、参考になると思います

もしかしたら Errataなどに書いてあるかもしれませんが... (^^;

ECU

ACCオフのあとも通信できることがある

 通常は ACC電源をオフにすると ECUと通信できなくなるが、通信したまま ACC電源をオフにすると、ごく希にそのまま ECUと通信できることがある。

再度、エンジンを始動するまでその状態が続く

恐らく ECUのバグ (^^;

PIC24F

割り込みルーチンに関して

 低レベル優先度の割り込み関数実行中に上位優先度の割り込み関数が呼ばれると、低レベル優先度の割り込み関数がその後実行されなくなる。この現象は、ほかの割り込み関数でも多発する。

 問題を解決するために、割込関数が呼ばれた直後に割込フラグを解除する。

OCxCONに関しては、毎回初期化しないといけない. こっちは仕様!?
 
  • OK
    void __attribute__((interrupt, auto_psv)) _OC4Interrupt(void)
    {
        IFS1bits.OC4IF = 0;
    
        CVRCONbits.CVR = dac >> 4;
        OC4CON = 0b0000000000000001;
        return;
    }
 
  • NG
    void __attribute__((interrupt, auto_psv)) _OC4Interrupt(void)
    {
        CVRCONbits.CVR = dac >> 4;
        OC4CON = 0b0000000000000001;
    
        IFS1bits.OC4IF = 0;
        return;
    }


*1 ライセンスには抵触しないと認識しています
*2 ファームウェアを書き換える必要があります
*3 ファームウェアを書き換える必要があります