So-net無料ブログ作成

SCI送信用リングバッファをMC908QB8に移植した [プログラム三昧]このエントリーを含むはてなブックマーク#

HCS08 Unleashedに掲載されていたSCI送信用リングバッファをMC908QB8に移植してみました。

某所で「リングバッファのサンプル・プログラムが無いか」と質問がありました。 「HCS08 Unleashed にあるよ」と、書こうとしてターゲットがMC908QB8であることに気が付きました。 そのままでは、使えないので、MC908QB8向けに移植します。

使用するハードウェアは、ほこりをかぶっていたDEMO908QB8デモボードです。 家中、ジャンパを探し回って、ようやく動かすことができました。

リングバッファの移植に必要なのは、HCS08MC908QB8のレジスタ・ビットの対照表です。 移植するために書き換えたレジスタ・ビットは、以下のとおりです。

HCS08MC908QB8概要
SCI1C2_TIESCC2_SCTIE割り込み許可ビット
SCI1S1_TDRESCS1_SCTE送信データ書き込み可能フラグ
SCI1DSCDR送信データレジスタ

リング・バッファ以外の部分、たとえば、ボーレートの設定やSCIの起動などは、参考サイトにある文章を参考にさせていただきました。 って、これは自分で書いた文章だよ。

デバッガから起動すると動くのに、スタンドアローンでは様子が変わるという、ありがちな問題も発生しました。 私の場合、「Watch Dog (COP) に与える餌が間に合わなかった」のと「一部のポートがフラフラしていた」のが原因でした。

COPはディセーブル、全ポートにプルアップ、で解決です。

というわけで、プログラムの完成です。 内容は、デモボード上のSW1/SW2を定期的に見に行って、押されていたらSCIにメッセージを表示するというものです。 このプログラム自身は、リングバッファを使っている恩恵は全く受けないのですが、サンプルとしては十分でしょう。

#include <hidef.h> /* for EnableInterrupts macro */
#include "derivative.h" /* include peripheral declarations */

#define     TX_BUF_SIZE     (32)

//--------------------------------------------------------------
//  Variables.
//--------------------------------------------------------------
#pragma DATA_SEG __SHORT_SEG MY_ZEROPAGE
byte tx_buf_read_pointer;
byte tx_buf_write_pointer;
struct {
  char tx_buf_empty:1;
} flags;

#pragma DATA_SEG DEFAULT
byte tx_buffer[TX_BUF_SIZE];

//--------------------------------------------------------------
//  initOSC() : void
//  Initialize the Oscillator Module (OSC)
//  The BUSCLK is adjusted to 3.2MHz.
//  CGMXCLK (BUSCLKx4) is used by ESCI.
//  See p100 of MC68HC908QB8 Data Sheet, Rev.1
//--------------------------------------------------------------
void initOSC() {
  // load trim value to adjust BUSCLK to 3.2MHz
  OSCTRIM = Optional;   // Adjust trim for internal OSC
  OSCSC_ICFS = 0b10;    // Select 12.8MHz as internal OSC
}

//--------------------------------------------------------------
//  initBaudRate() : void
//  Initialize the baud rate of ESCI to 1200bps.
//  The CGMXCLK is assumed as a 12.8MHz clock.
//  DETAIL:
//    SCP  =    01 for BPD=3
//    SCR  =   011 for BD=8
//    PDS  =   101 for PD=6
//    PSSB = 11110 for PDFA=0.9375
//    Baud Rate = 12.8MHz / (64 * BPD * BD * (PD + PDFA))
//              = 1201 baud
//  See p130 of MC68HC908QB8 Data Sheet, Rev.1
//--------------------------------------------------------------
void initBaudRate() {
  SCBR_SCP   =    0b01;  // BPD  = 3
  SCBR_SCR   =   0b011;  // BD   = 8
  SCPSC_PDS  =   0b101;  // PD   = 6
  SCPSC_PSSB = 0b11110;  // PDFA = 0.9375
}

//--------------------------------------------------------------
//  initESCI() : void
//  Initialize the Enhanced Serial Communication Interface (ESCI)
//--------------------------------------------------------------
void initESCI() {
  SCC1_ENSCI = 1;       // Enables ESCI module
  SCC2_TE = 1;          // Enables transmitter
}

//--------------------------------------------------------------
//  isr_sctx() : void
//  Interrupt sevice routine for SCI-TX
//--------------------------------------------------------------
void __interrupt VectorNumber_SCITransmit isr_sctx(void) {
  if (tx_buf_read_pointer == tx_buf_write_pointer) {
    SCC2_SCTIE = 0;             // Disable the interrupt
    flags.tx_buf_empty = 1;     // Set empty flag
  } else {
    if (SCS1_SCTE) {
      SCDR = tx_buffer[tx_buf_read_pointer];
      tx_buf_read_pointer++;
      tx_buf_read_pointer &= TX_BUF_SIZE - 1;
    }
  }
}

//--------------------------------------------------------------
//  sci_putc(byte) : void
//  Put a character into the ring buffer.
//--------------------------------------------------------------
void sci_putc(const byte data) {
  SCC2_SCTIE = 0;               // Disable the interrupt  
  flags.tx_buf_empty = 0;
  tx_buffer[tx_buf_write_pointer] = data;
  tx_buf_write_pointer++;
  tx_buf_write_pointer &= TX_BUF_SIZE - 1;
  SCC2_SCTIE = 1;               // Enable the interrupt  
}

//--------------------------------------------------------------
//  sci_puts(byte *) : void
//  Put a string into the ring buffer.
//--------------------------------------------------------------
void sci_puts(const byte *s) {
  while (*s) {
    sci_putc(*s++);
  }
}

//--------------------------------------------------------------
//  initQueue() : void
//  Initialize the queue related variable.
//--------------------------------------------------------------
void initQueue(void) {
  tx_buf_read_pointer = 0;      // Initialize READ pointer
  tx_buf_write_pointer = 0;     // Initialize WRITE pointer
  flags.tx_buf_empty = 1;       // Set empty flag
}

//--------------------------------------------------------------
//  main() : void
//--------------------------------------------------------------
void main(void) {
  word i;

  CONFIG1 = 0x01;       // Disable COP
  PTAPUE = 0x3F;        // Enable all port pull-up
  PTBPUE = 0xFF;        // Enable all port pull-up
  
  initOSC();            // Initialize OSC module
  initBaudRate();       // Initialize baud rate
  initESCI();           // Initialize ESCI module
  initQueue();          // Prepare QUEUE

  EnableInterrupts; /* enable interrupts */
  /* include your code here */

  for(;;) {
    if (!PTA_PTA5) {
      sci_puts("SW1 PUSHED\r\n");
    }
    if (!PTA_PTA4) {
      sci_puts("SW2 PUSHED\r\n");
    }
    // a delay
    for (i = 0; i < 30000; i++) {
    }
    __RESET_WATCHDOG(); /* feeds the dog */
  } /* loop forever */
  /* please make sure that you never leave main */
}

おっと、忘れてた。 Project.prmを変更して"RAM"領域を広げておかないと、バッファが配置できなかったのでした。

/* This is a linker parameter file for the mc68hc908qb8 */

NAMES END /* CodeWarrior will pass all the needed files to the linker by command line. But here you may add your own files too. */

SEGMENTS /* Here all RAM/ROM areas of the device are listed. Used in PLACEMENT below. */
    Z_RAM                    =  READ_WRITE   0x0040 TO 0x007F;
    RAM                      =  READ_WRITE   0x0080 TO 0x013F;
    ROM                      =  READ_ONLY    0xDE00 TO 0xFDFF;
    ROM1                     =  READ_ONLY    0xFFB0 TO 0xFFBD;
    ROM2                     =  READ_ONLY    0xFFC2 TO 0xFFCF;
 /* INTVECTS                 =  READ_ONLY    0xFFDE TO 0xFFFF; Reserved for Interrupt Vectors */
END

PLACEMENT /* Here all predefined and user segments are placed into the SEGMENTS defined above. */
    DEFAULT_RAM,                        /* non-zero page variables */
                                        INTO  RAM;

    _PRESTART,                          /* startup code */
    STARTUP,                            /* startup data structures */
    ROM_VAR,                            /* constant variables */
    STRINGS,                            /* string literals */
    VIRTUAL_TABLE_SEGMENT,              /* C++ virtual table segment */
    DEFAULT_ROM,
    COPY                                /* copy down information: how to initialize variables */
                                        INTO  ROM; /* ,ROM1,ROM2: To use "ROM1,ROM2" as well, pass the option -OnB=b to the compiler */

    _DATA_ZEROPAGE,                     /* zero page variables */
    MY_ZEROPAGE                         INTO  Z_RAM;
END

STACKSIZE 0x30

VECTOR 0 _Startup /* Reset vector: this is the default entry point for an application. */

参考サイト

003A QB8でもシリアル通信
ESCIの使い方なんて、すっかり忘れていました。 一番参考になったのは、その昔自分で書いた文章だったというオチ。
ScTec
HCS08 Unleashedの筆者のサイトです。 日本語でもなく、英語でもなく、スペイン語(だったっけ?)なのが辛いところです。 書籍のエラッタ、書籍に掲載されているソースコードも入手できます。

参考文献

HCS08 Unleashed: Designer's Guide to the HCS08 Microcontrollers

HCS08 Unleashed: Designer's Guide to the HCS08 Microcontrollers

  • 作者: Fabio Pereira
  • 出版社/メーカー: Booksurge Llc
  • 発売日: 2007/11/13
  • メディア: ペーパーバック

nice!(0)  コメント(3)  トラックバック(0)  このエントリーを含むはてなブックマーク#

nice! 0

コメント 3

hamayan

質問でーす。
1.flags.tx_buf_emptyの使い方が良く判りません。

2.tx_buf_write_pointer &= TX_BUF_SIZE - 1;
はバッファサイズが2の乗数であると言う大前提が存在しますので、後々思わぬトラップにならないでしょうか。

by hamayan (2009-04-02 11:45) 

hamayan

もう一つ質問です。

ボーレートが高ければ問題が表面化し難いのですが、とんでもなく低い時、リングバッファへの書き込みで上書きチェックを行わない場合、変なデータが送られる事にならないでしょうか。

by hamayan (2009-04-02 11:54) 

noritan

> flags.tx_buf_emptyの使い方が良く判りません。

HCS08 Unleashed のプログラムに書いてあったので、そのまま残しています。書籍のプログラムでも、セット・リセットするだけで参照されていません。

> tx_buf_write_pointer &= TX_BUF_SIZE - 1;

書籍のプログラムでは、if (tc_buf_write_pointer >= TX_BUF_SIZE) … となっていましたが、エラッタの記述(Tsuneo さんのお勧め)に従って変更しています。

> リングバッファへの書き込みで上書きチェックを行わない場合

もちろん、リングバッファがあふれたらデータは壊れてしまいます。書籍のプログラムでもオーバフロー検出は行われていなかったので、そのまま移植してあります。

ProcessorExpert を使っちゃえという、解決方法ももちろんあります。

by noritan (2009-04-02 14:25) 

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

トラックバックの受付は締め切りました

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。