日曜技術者のメモ

趣味でやった事のメモ書きです。

LPC1114+CMSIS Libraryでprintfを使ってみた

LPC11xx_cmsis2_Libに実装されているUARTSend関数を使ってシリアル出力していたが
文字列以外の表示が面倒なのでprintfを使えるようにした。

今の所2種類の方法で動いたので両方メモしておく。

試した環境

  • LPCXpresso_7.7.2_379
  • LPCXpresso1114_cmsis2.zipをインポート済み
      C:\nxp\LPCXpresso_7.7.2_379\lpcxpresso\Examples\NXP\LPC1000\LPC11xxにある
  • Redlib(none)
  • LPC-Link2(Semihostingを使う際は必要)

Semihostingを使う

LPC-Link2があるならSemihostingを使うとLPCXpresso上でprintfの結果が見える。
使い方も簡単でNew projectC Project (Semihosted)を選ぶだけ。

f:id:ginnyu-tei:20150429093708j:plain

出てきたサンプルコードを実行するとLPCXpresso上のConsoleにHello Worldが表示される。

f:id:ginnyu-tei:20150429094256j:plain

syscallを実装してUART経由でprintfを使う

New project->C Projectで作成したプロジェクト上でprintfを呼び出すと
Redlib(none)ではSystemcallが実装されていないのでリンク時エラーが発生する。

c:/nxp/lpcxpresso_7.7.2_379/lpcxpresso/tools/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/lib/armv6-m\libcr_c.a(fpprintf.o): In function `printf':
fpprintf.c:(.text.printf+0x38): undefined reference to `__sys_write'
c:/nxp/lpcxpresso_7.7.2_379/lpcxpresso/tools/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/lib/armv6-m\libcr_c.a(_deferredlazyseek.o): In function `__flsbuf':
_deferredlazyseek.c:(.text.__flsbuf+0x88): undefined reference to `__sys_istty'
c:/nxp/lpcxpresso_7.7.2_379/lpcxpresso/tools/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/lib/armv6-m\libcr_c.a(_writebuf.o): In function `_Cwritebuf':
_writebuf.c:(.text._Cwritebuf+0x16): undefined reference to `__sys_flen'
_writebuf.c:(.text._Cwritebuf+0x26): undefined reference to `__sys_seek'
_writebuf.c:(.text._Cwritebuf+0x3a): undefined reference to `__sys_write'
c:/nxp/lpcxpresso_7.7.2_379/lpcxpresso/tools/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/lib/armv6-m\libcr_c.a(alloc.o): In function `_Csys_alloc':
alloc.c:(.text._Csys_alloc+0xe): undefined reference to `__sys_write'
alloc.c:(.text._Csys_alloc+0x12): undefined reference to `__sys_appexit'
c:/nxp/lpcxpresso_7.7.2_379/lpcxpresso/tools/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/lib/armv6-m\libcr_c.a(fseek.o): In function `fseek':
fseek.c:(.text.fseek+0x18): undefined reference to `__sys_istty'
fseek.c:(.text.fseek+0x3c): undefined reference to `__sys_flen'
collect2.exe: error: ld returned 1 exit status

Systemcallの定義はlibconfig-arm.hに記述されているので適当に実装してみた。
以下サンプルコード

#ifdef __USE_CMSIS
#include "LPC11xx.h"
#endif

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "uart.h"

#include <cr_section_macros.h>

// TODO: insert other include files here

// TODO: insert other definitions and declarations here
void uart_putc(const char);

////////////////////////// Systemcall //////////////////////////
int __sys_write(int iFileHandle, char *pcBuffer, int iLength)
{
    int n;
    for (n = 0; n < iLength; n++) {
        if (pcBuffer[n] == '\n'){
            uart_putc('\r');
        }
        uart_putc(pcBuffer[n]);
    }
    return iLength;
}
int __sys_istty(int handle)
{
    return 1;
}
int __sys_flen(int handle)
{
    return 0;
}
int __sys_seek(int handle, int pos)
{
    return 0;
}
void __sys_appexit (void)
{

}
////////////////////////// UART ////////////////////////
// send a character via TXD
void uart_putc(const char c) {
    // Wait for TX buffer empty
    while (!(LPC_UART->LSR & LSR_THRE));
    // Put a character
    LPC_UART->THR = c;
}
////////////////////////// Main //////////////////////////
int main(void) {
    UARTInit(115200);
    // Force the counter to be placed into memory
    volatile static int i = 0 ;
    // Enter an infinite loop, just incrementing a counter
    while(1) {
        i++ ;
        if (i % 1000000 == 0){
            printf("i = %d(dec) ",i);
            printf("%08x(hex)\n",i);
        }
    }
    return 0 ;
}

uart_putc関数はエレキジャックのHPにあったコード*1
そのまま使わせて頂きました。

実行するとUARTからprintfの結果が送られてくる。

i = 1000000(dec) 000f4240(hex)
i = 2000000(dec) 001e8480(hex)
i = 3000000(dec) 002dc6c0(hex)
i = 4000000(dec) 003d0900(hex)

scanf

printfが動作したので、ついでにscanfも実装しようとしたがうまく動かなかった。

__sys_read__sys_read_cを追加で実装したが
デバック実行でブレイクポイントを設定しても止まらなかった。

Redlib内の動きが分かれば良いのだが
ソースコードは公開されていない為scanfの実装はあきらめる。

参考にしたサイト

mbed + GCCでprintfを使う: Todotaniのはやり物Log