SSブログ

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

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