USBホストになれるCH559入門 その2 UART0でテキスト出力

概要

前回は開発環境の構築とLチカをしました。このままだとデバッグができないので、UART0を使ってみたいと思います。

接続

こんな感じで開発ボードのTXとUSBシリアルのRXを接続します。本当はGNDも接続したほうがいいですが、同じPCに接続されているのでGNDは省略可能です。(ノイズが乗りやすいので本当は接続したほうがいいです)

USB-Serial(3.3V)Dev Board
RXTX
GNDGND

また、ESP32やその他のマイコンに接続してあげても大丈夫です。マイコンの場合には受信速度を変更した場合にはファームウエアの転送しなおしになるので、今回はUSBシリアル変換を使っています。

また、開発ボードのUART0の信号レベルは上記で調べたところ、3.4Vぐらいでした。5V系のマイコンと接続すると問題が起こりそうなので、ESP32などの3.3V系のマイコンがよいと思います。USBシリアル変換も3.3Vモードで動かしています。今回は受信だけなので、開発ボードのTXのみ接続しているので、あまり信号レベルは気にしなくても大丈夫な気もしますが、マイコンと送受信しようとしたときに問題になると思います。

コード

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

int UART0Receive()
{
    while (!RI)
        ;
    RI = 0;
    return SBUF;
}

int UART0Send(int c)
{
    while (!TI)
        ;
    TI = 0;
    SBUF = c & 0xFF;
    return c;
}

int getchar()
{
    return UART0Receive();
}

int putchar(int c)
{
    return UART0Send(c);
}

static inline void delay()
{
    uint32_t i;
    for (i = 0; i < (120000UL); i++)
    {
        __asm__("nop");
    }
}

void main()
{
    unsigned long x;
    uint32_t baud = 115200;

    // Clock Setting
    SAFE_MOD = 0x55;
    SAFE_MOD = 0xAA;
    CLOCK_CFG &= ~MASK_SYS_CK_DIV;
    CLOCK_CFG |= 6;
    PLL_CFG = ((24 << 0) | (6 << 5)) & 255;
    SAFE_MOD = 0xFF;
    delay();

    // UART0 Setting
    PORT_CFG |= bP0_OC;
    P0_DIR |= bTXD_;
    P0_PU |= bTXD_ | bRXD_;
    PIN_FUNC |= bUART0_PIN_X;

    SM0 = 0;
    SM1 = 1;
    SM2 = 0;
    REN = 1;
    PCON |= SMOD;
    x = (((unsigned long)FREQ_SYS / 8) / baud + 1) / 2;

    TMOD = TMOD & ~bT1_GATE & ~bT1_CT & ~MASK_T1_MOD | bT1_M1;
    T2MOD = T2MOD | bTMR_CLK | bT1_CLK;
    TH1 = (256 - x) & 255;
    TR1 = 1;
    TI = 1;

    while (1)
    {
        printf("Test build=%s, baud=%ld\n", __TIME__, baud);
        delay();
    }
}

まだあまり整理されていないコードですが、これでUART0が利用できるようになります。

受信部分

int UART0Receive()
{
    while (!RI)
        ;
    RI = 0;
    return SBUF;
}

RIがReceive Interrupt flagで、受信すると1になります。0の場合にはループして受信待ちをして、1になったらUART0のバッファであるSBUFから読み取ります。

送信部分

int UART0Send(int c)
{
    while (!TI)
        ;
    TI = 0;
    SBUF = c & 0xFF;
    return c;
}

送信部分は同じように、Transmit Interrupt flagのTIが1になるまでループして、1になったらSBUFにデータを書き込みます。

標準出力

int getchar()
{
    return UART0Receive();
}

int putchar(int c)
{
    return UART0Send(c);
}

getchar()とputchar()を作成することで、標準出力の処理を定義できます。上記の場合にはUART0に接続してあげています。CH559はUSBシリアルにもなるので、マイコンのようにUSB接続でそのままシリアル出力をすることも可能です。

標準出力の設定をすることで、printf()の出力が受信できるようになりました。内部のレジスタの状態などを把握するためにデバッグ出力は必須なので、次回以降はprintf()を使って状態を出力しながら開発ができるようになります。

初期化部分

    uint32_t baud = 115200;

いろいろ初期化していますが、今回は細かい解説は割愛させていただきます。次回にデータシートを読みながらパラメータを確認する予定です。

さて、上記の変数がUART0の転送速度になります。いろいろ初期化に応じて設定可能速度の範囲が変わりますが、概ね設定できる速度は以下の範囲になります。

  • 19200
  • 38400
  • 57600
  • 74880
  • 115200
  • 230400
  • 250000
  • 500000
  • 1000000

これはArduino IDEのシリアルモニタで設定できる値で試してあります。今回のコードですと一番遅いのが19200ですので、9600では利用できません。

CH559は内部に12MHzの水晶が内蔵されており、このクロックを元に動いています。内部的には24倍した288MHzを分周した値で設定可能で、CPU周波数は48MHzに設定してあるはずです。UART0では概ね3MHzのクロックを分周した値が利用可能です。

一番はやい設定速度はM5StickCなどと同じ2で割った1.5MHzになります。Arduino IDEのシリアルモニタでは3で割った1MHzが最速ですね。UARTはチェックサムなどがなく、速度が早くなると安定しなくなるので注意しましょう。ちなみに3MHzを設定可能な最大値の255で割ると11765になるので、9600の設定はできません。

まとめ

上記にコード一式を置いてあります。今回はとりあえずUARTで内部の状態を出力できるようになりました。次回はデータシートを読みながら、Lチカと今回設定した値の意味を調べていきたいと思います。

続編

コメント

タイトルとURLをコピーしました