概要
LチカとUARTデバッグをしたところで、ドキュメントの翻訳をしていました。今回ある程度翻訳が進んできたので、Lチカのコードを再度ドキュメントを見ながら解析してきたいと思います。
Lチカソースコード
#include <stdint.h>
#include "ch559.h"
static inline void delay()
{
uint32_t i;
for (i = 0; i < (120000UL); i++)
{
__asm__("nop");
}
}
void main()
{
PORT_CFG = 0b00101101;
P1_DIR = 0b11110000;
P1 = 0x00;
AIN4 = 0; // P1_4
AIN5 = 1; // P1_5
AIN6 = 0; // P1_6
AIN7 = 1; // P1_7
while (1)
{
delay();
AIN4 = !AIN4;
AIN5 = !AIN5;
delay();
AIN4 = !AIN4;
AIN5 = !AIN5;
AIN6 = !AIN6;
AIN7 = !AIN7;
}
}
上記がコードになります。
PORT_CFG設定
PORT_CFG = 0b00101101;
上記を確認してみます。
SFR(PORT_CFG, 0xC6); // port 0/1/2/3 config
#define bP3_DRV 0x80 // P3 driving capability: 0=5mA, 1=20mA
#define bP2_DRV 0x40 // P2 driving capability: 0=5mA, 1=20mA
#define bP1_DRV 0x20 // P1 driving capability: 0=5mA, 1=10mA
#define bP0_DRV 0x10 // P0 driving capability: 0=5mA, 1=20mA
#define bP3_OC 0x08 // P3 open-drain output enable: 0=push-pull output, 1=open-drain output
#define bP2_OC 0x04 // P2 open-drain output enable: 0=push-pull output, 1=open-drain output
#define bP1_OC 0x02 // P1 open-drain output enable: 0=push-pull output, 1=open-drain output
#define bP0_OC 0x01 // P0 open-drain output enable: 0=push-pull output, 1=open-drain output
定義を検索していると上記があります。0xC6ですね。定義の下にあるのが実際に設定する値だと思われます。
上記のドキュメントをあわせて見ていくことにします。
設定名 | ビット | 初期値 | 設定した値 | 備考 |
bP3_DRV | 0x80 | 0 | 0 | P3ドライブ能力 0=5mA, 1=20mA |
bP2_DRV | 0x40 | 0 | 0 | P2ドライブ能力 0=5mA, 1=20mA |
bP1_DRV | 0x20 | 0 | 1 | P1ドライブ能力 0=5mA, 1=10mA |
bP0_DRV | 0x10 | 0 | 0 | P0ドライブ能力 0=5mA, 1=20mA |
bP3_OC | 0x08 | 1 | 1 | P3出力種別 0=プッシュプル, 1=オープンドレイン |
bP2_OC | 0x04 | 1 | 1 | P1出力種別 0=プッシュプル, 1=オープンドレイン |
bP1_OC | 0x02 | 1 | 0 | P0出力種別 0=プッシュプル, 1=オープンドレイン |
bP0_OC | 0x01 | 1 | 1 | P3出力種別 0=プッシュプル, 1=オープンドレイン |
上記の設定になります。P1を出力に使うのでドライブ能力を5mAから10mAに引き上げています。Lチカだけだったら5mAでも大丈夫かもしれません。
あとは初期値がオープンドレインになっていますので、P1のみプッシュプルに指定しています。
//PORT_CFG = 0b00101101;
PORT_CFG = bP1_DRV | bP3_OC | bP2_OC | bP0_OC;
つまり、上記の書き方のほうがフレンドリですね。
PORT_CFG |= bP1_DRV; // P1 10mA drive
PORT_CFG &= ~bP1_OC; // P1 push-pull
個別に設定したほうが本当はわかりやすい気がします。ちなみにこの2つは設定しなくてもLチカできました。今回はP1_DIRの設定が重要でした。
P1_DIR設定
P1_DIR = 0b11110000;
上記で入出力の方向を設定しているはずです。
SFR(P1_DIR, 0xBA); // port 1 direction
上記の設定でした。こちらにはビット定義がないのかな。P1以外は定義がありましたがP1は汎用IOに主に使うのでないのかもしれません。
設定名 | ビット | 初期値 | 設定した値 | 備考 |
– | 0x80 | 0 | 1 | P1_7入出力 0:入力, 1:出力 |
– | 0x40 | 0 | 1 | P1_6入出力 0:入力, 1:出力 |
– | 0x20 | 0 | 1 | P1_5入出力 0:入力, 1:出力 |
– | 0x10 | 0 | 1 | P1_4入出力 0:入力, 1:出力 |
– | 0x08 | 0 | 0 | P1_3入出力 0:入力, 1:出力 |
– | 0x04 | 0 | 0 | P1_2入出力 0:入力, 1:出力 |
– | 0x02 | 0 | 0 | P1_1入出力 0:入力, 1:出力 |
– | 0x01 | 0 | 0 | P1_0入出力 0:入力, 1:出力 |
上記を設定していますね。P1にある8ピンから後半の4ピンを出力に設定しています。
//P1_DIR = 0b11110000;
//P1_DIR = ( 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 );
P1_DIR |= 1 << 7; // P1_7 Output
P1_DIR |= 1 << 6; // P1_6 Output
P1_DIR |= 1 << 5; // P1_5 Output
P1_DIR |= 1 << 4; // P1_4 Output
こちらも直値よりはもう少しわかりやすい表記のほうが良さそうですね。本当はラッパー関数で設定したほうがいいのかもしれません。
SBITとSFR関数ってなんだ?
8051はビット単位でのアクセスが可能な命令があるみたいで、特殊な拡張のようです。
__sfr __atat (0x80) P0; /* special function register P0 at location 0x80 */
上記のように宣言するとP0という名前で0x80のレジスタにアクセス可能です。
SFR(P0, 0x80); // port 0 input & output
実際に定義は上記のようにしていますので、どこかで置換しているはずです。
#if defined (SDCC) || defined (__SDCC)
# define SBIT(name, addr, bit) __sbit __at(addr+bit) name
# define SFR(name, addr) __sfr __at(addr) name
# define SFRX(name, addr) __xdata volatile unsigned char __at(addr) name
# define SFR16(name, addr) __sfr16 __at(((addr+1U)<<8) | addr) name
# define SFR16E(name, fulladdr) __sfr16 __at(fulladdr) name
# define SFR16LEX(name, addr) __xdata volatile unsigned short __at(addr) name
# define SFR32(name, addr) __sfr32 __at(((addr+3UL)<<24) | ((addr+2UL)<<16) | ((addr+1UL)<<8) | addr) name
# define SFR32E(name, fulladdr) __sfr32 __at(fulladdr) name
C:\Program Files\SDCC\include\mcs51\compiler.hで上記の定義がありました。ここで変換しているんですね。
SBIT(P0_7, 0x80, 7);
SBIT(P0_6, 0x80, 6);
SBIT(P0_5, 0x80, 5);
SBIT(P0_4, 0x80, 4);
SBIT(P0_3, 0x80, 3);
SBIT(P0_2, 0x80, 2);
SBIT(P0_1, 0x80, 1);
SBIT(P0_0, 0x80, 0);
SBITは上記のように定義しています。
__sbit __atat (0xd7) CY; /* CY (Carry FlagFlagsCarry flag) */
実際には上記の形式に変換されているはずです。
まとめ
UART部分もやりたかったのですが、翻訳が終わっていないので次回にしたいと思います。
コメント