(2016年6月5日)
PIC32MX + Pinguino コンパイラの活用法を、iruka さんが精力的に研究されている。ORANGE pico の特設ページもある。これはぜひフォローして行きたい。
まずは、UART(シリアル転送)経由のブートローダを作成してみた。ブートローダをうまく作ってやると、プログラムの書き換えにいちいち PICkit を持ち出さなくてよいので、快適に開発することができる。
iruka さんの GitHub ページから、ORANGE pico プロジェクトのファイルを丸ごとダウンロードする。samples
ディレクトリの中に uart_bootloader
があるので、これをとりあえず複製しておく。
まず、Pinguino 関連のディレクトリを変更する。また、PROC
は 32MX270F256B
とする。本当は 32MX170F256B
だけど、違いは USB の有無だけで、バイナリのビルドには支障ない。また、コンパイラのファイル名が異なるので、BINPREFIX
という変数を新たに導入。
--- ../uart_bootloader/Makefile 2016-05-15 18:42:13.000000000 +0900
+++ Makefile 2016-05-29 22:21:38.000000000 +0900
@@ -1,8 +1,9 @@
-SHELL = cmd.exe
-HOME = C:\pinguino-11
+#SHELL = cmd.exe
+PHOME = /opt/Pinguino/v11
BOARD = PIC32_PINGUINO_220
-PROC = 32MX220F032B
+PROC = 32MX270F256B
+BINPREFIX = mips-elf-
# ------------------------------------------------------------------------------
# Makefile.win32 \ 32-bit Pinguino
パスの区切りをスラッシュに変更。また、rm
, cp
, mv
を本来のコマンド名に変更。
@@ -14,21 +15,21 @@
# ------------------------------------------------------------------------------
SRCDIR = .
-P32DIR = $(HOME)\p32
-P32CORE = $(HOME)\compilers\p32
-BINDIR = $(P32CORE)\bin
-INCDIR = $(P32DIR)\include
-LKRDIR = $(P32DIR)\lkr
-OBJDIR = $(P32DIR)\obj\non-free
-
-INCLUDEDIRS = -I$(INCDIR)\non-free \
- -I$(INCDIR)\pinguino\core \
- -I$(INCDIR)\pinguino\libraries \
+P32DIR = $(PHOME)/p32
+P32CORE = $(PHOME)/compilers/p32
+BINDIR = $(P32CORE)/bin
+INCDIR = $(P32DIR)/include
+LKRDIR = $(P32DIR)/lkr
+OBJDIR = $(P32DIR)/obj/non-free
+
+INCLUDEDIRS = -I$(INCDIR)/non-free \
+ -I$(INCDIR)/pinguino/core \
+ -I$(INCDIR)/pinguino/libraries \
-I$(LKRDIR) \
-I$(PDEDIR) \
-I$(OBJDIR)
-LIBDIRS = -L$(OBJDIR)\usb
+LIBDIRS = -L$(OBJDIR)/usb
# ------------------------------------------------------------------------------
# Include object list $(OBJS)
@@ -88,12 +89,15 @@ # commands
# ------------------------------------------------------------------------------
-CC = $(BINDIR)\p32-gcc.exe
-OBJC = $(BINDIR)\p32-objcopy.exe
+CC = $(BINDIR)/$(BINPREFIX)gcc
+OBJC = $(BINDIR)/avr-objcopy
LIBS = -lm -lgcc -lc
-RM = @del
-CP = @copy
-MV = @move
+#RM = @del
+#CP = @copy
+#MV = @move
+RM = rm
+CP = cp
+MV = mv
# ------------------------------------------------------------------------------
# flags
オリジナルはボーレートを 500000 としているが、無難な 115200 に変更。また、README
を読むとわかる通り、iruka さんは 8 MHz 水晶を追加して実験している。ORANGE pico type S は水晶無しなので、この設定を変更する。
@@ -108,6 +112,7 @@
# Option: CHANGE BAUDRATE
#CFLAGS += -DBAUDRATE=115200
+CFLAGS += -DUSE_INTERNAL_FRC_OSC
LDFLAGS = $(LIBDIRS) $(LIBS)
@@ -118,7 +123,7 @@
-Wl,--defsym,_min_heap_size=$(HEAP_SIZE) \
-Wl,-Map=$(SRCDIR)\output.map \
-T$(LKRSCRIPT) \
- -T$(LKRDIR)\elf32pic32mx.x
+ -T$(LKRDIR)/elf32pic32mx.x
#-------------------------------------------------------------------------------
# rules
@@ -133,21 +138,19 @@
all: $(OBJS)
@echo $(CC) *OBJS* -o $(SRCDIR)\main32.elf
- @$(CC) $(ELF_FLAGS) $(LDFLAGS) $(CFLAGS) -o $(SRCDIR)\main32.elf \
- $(OBJS) \
- $(HOME)/user/source/obj/non-free/$(PROC).o \
- -lm -lgcc -lc
- $(OBJC) -O ihex $(SRCDIR)\main32.elf $(SRCDIR)\main32.hex
- hex2dump main32.hex >main32.dmp
- $(BINDIR)\p32-objdump -S main32.elf > main32.lss
- hex2pickit3 main32.hex pickit3.hex
+ @$(CC) $(ELF_FLAGS) $(LDFLAGS) $(CFLAGS) -o $(SRCDIR)/main32.elf \
+ $(OBJS) $(OBJDIR)/$(PROC).o -lm -lgcc -lc
+ $(OBJC) -O ihex $(SRCDIR)/main32.elf $(SRCDIR)/main32.hex
+ #hex2dump $(SRCDIR)/main32.hex >$(SRCDIR)/main32.dmp
+ $(BINDIR)/$(BINPREFIX)objdump -S $(SRCDIR)/main32.elf > $(SRCDIR)/main32.lss
+ hex2pickit3 $(SRCDIR)/main32.hex $(SRCDIR)/pickit3.hex
clean:
-$(RM) main32.elf
-$(RM) *.o
exec:
- $(OBJC) -O ihex $(SRCDIR)\main32.elf $(SRCDIR)\main32.hex
+ $(OBJC) -O ihex $(SRCDIR)/main32.elf $(SRCDIR)/main32.hex
correct:
@@ -159,4 +162,3 @@
@echo $(CC) -c $< -o $@
@$(CC) $(ELF_FLAGS) $(CFLAGS) -c $< -o $@
config.c:
内蔵 RC 発振を使って 48 MHz 動作させるための設定。
--- ../uart_bootloader/config.c 2016-05-15 18:42:13.000000000 +0900
+++ config.c 2016-05-29 18:08:05.000000000 +0900
@@ -26,8 +26,8 @@
#ifdef USE_INTERNAL_FRC_OSC // RC OSC
#define CONFIG_FPLLIDIV IDIV_1 /* 4 MHz -> 4 MHz */
#define CONFIG_UPLLIDIV IDIV_1 /* 4 MHz -> 4 MHz */
-#define CONFIG_FNOSC FRC /* RC */
-#define CONFIG_POSCMOD 0 /* Primary Osillator is EC (External) */
+#define CONFIG_FNOSC FRCPLL /* RC + PLL */
+#define CONFIG_POSCMOD 2 /* Primary Osillator is HS mode */
#define CONFIG_FSOSCEN 0 /* Secondary Osillator is Disabled */
#define CONFIG_OSCIOFNC 0 /* CLKO output Enabled */
#define CONFIG_FCKSM CSECMD /* Clock Switching Enabled */
main.c:
InitializeFRC()
の呼び出しを削除。この関数はどこにも定義されていない。
--- ../uart_bootloader/main.c 2016-05-15 18:42:13.000000000 +0900
+++ main.c 2016-05-30 23:44:55.000000000 +0900
@@ -209,7 +210,7 @@
SoftwareKey = (unsigned int *)0xA0000000;
#ifdef USE_INTERNAL_FRC_OSC // RC OSC
- InitializeFRC();
+/* InitializeFRC(); */
#endif
#if 1
Makefile:
_LINUX_
を定義。また、rs232c-unix.c
は完全に新設。なお、Mac で 64 ビットモードでコンパイルすると fprintf
の表示が一部乱れるので、-arch i386
で強制的に 32 ビットモードでコンパイルしている。
--- ../uart_bootloader/hostpc/Makefile 2016-05-15 18:42:13.000000000 +0900
+++ hostpc/Makefile 2016-06-04 15:08:55.000000000 +0900
@@ -1,6 +1,6 @@
CC = gcc
-EXECS = uartmon32.exe
-EXECF = uartflash32.exe
+EXECS = uartmon32
+EXECF = uartflash32
#
# uartmon32
@@ -16,7 +16,7 @@
mips-opc.o \
mips16-opc.o \
usb-uart.o \
- rs232c.o \
+ rs232c-unix.o \
#
# uartflash32
@@ -26,15 +26,18 @@
util.o \
codebuf.o \
usb-uart.o \
- rs232c.o \
+ rs232c-unix.o \
#
-CFLAGS = -DWIN -DWINVER=0x0500 -Wall
-WIN32LIB= -lkernel32 -luser32 -lgdi32 -lsetupapi
+#CFLAGS = -DWIN -DWINVER=0x0500 -Wall
+#WIN32LIB= -lkernel32 -luser32 -lgdi32 -lsetupapi
#forDEBUG
#
-CFLAGS += -DDEBUG
+#CFLAGS += -DDEBUG
+
+CFLAGS = -D_LINUX_ -O2 -g
+CFLAGS += -arch i386
all: $(EXECS) $(EXECF)
@@ -43,10 +46,10 @@
$(CC) $(CFLAGS) -c $*.c
$(EXECS): $(OBJS)
- $(CC) $(OBJS) -s $(LDFLAGS) $(WIN32LIB) -o $(EXECS)
+ $(CC) $(OBJS) $(CFLAGS) $(LDFLAGS) $(WIN32LIB) -o $(EXECS)
$(EXECF): $(OBJF)
- $(CC) $(OBJF) -s $(LDFLAGS) $(WIN32LIB) -o $(EXECF)
+ $(CC) $(OBJF) $(CFLAGS) $(LDFLAGS) $(WIN32LIB) -o $(EXECF)
clean:
rm -f $(EXECS) $(EXECF) *.o core
uartflash.c:
Unix 系では、シリアルデバイス名を指定する必要がある。そこで、ファイル名の前にデバイス名を指定するように変更。(あと、デバッグ用に verbose
という変数を導入して fprintf()
をあちこち挿入してあるが、これは本質的ではない)
--- ../uart_bootloader/hostpc/uartflash.c 2016-05-15 18:42:13.000000000 +0900
+++ hostpc/uartflash.c 2016-06-03 00:53:09.000000000 +0900
@@ -8,6 +8,7 @@
#include <string.h>
#include <ctype.h>
#include <math.h>
+#include <unistd.h>
#ifndef _LINUX_
#include <windows.h>
@@ -23,13 +24,20 @@
#define DEFAULT_SERIAL "*"
#define END_MASK 0xfffff
+extern int verbose;
char HELP_USAGE[]= {
"* UARTflash32 Ver 0.1 (" __DATE__ ")\n"
"Usage is\n"
+#ifdef _LINUX_
+ " " CMD_NAME " [Options] devicename <hexfile.hex>\n"
+#else
" " CMD_NAME " [Options] <hexfile.hex>\n"
+#endif
"Options\n"
+#ifndef _LINUX_
" -p[:XXXX] ... Select serial number (default=" DEFAULT_SERIAL ").\n"
+#endif
" -r ... Run after write.\n"
" -v ... Verify.\n"
" -E ... Erase.\n"
@@ -432,7 +440,7 @@
#else
UsbEraseTargetROM(FLASH_BASE+addr , pages);
#endif
- Sleep(8);
+ usleep(8000);
Flash_Lock();
}
return 0;
@@ -691,6 +699,7 @@
* メイン
*********************************************************************
*/
+
void getopt_p(char *s)
{
if (s) {
@@ -735,19 +744,27 @@
* メイン
*********************************************************************
*/
+extern int verbose;
+
int main(int argc,char **argv)
{
int errcnt, ret_val; //,retry;
int dev_flash_size=0;
int dev_flash_used=0;
+#ifdef _LINUX_
+ int required_nargs = 3;
+#else
+ int required_nargs = 2;
+#endif
+
//オプション解析.
Getopt(argc,argv,"i");
if(IsOpt('h') || IsOpt('?') || IsOpt('/')) {
usage();
exit(EXIT_SUCCESS);
}
- if((argc<2)&& (!IsOpt('r')) && (!IsOpt('E')) && (!IsOpt('p')) ) {
+ if((argc 0)
+ fprintf(stderr, "Reading hex file %s...\n", argv[required_nargs - 1]);
+ read_hexfile(argv[required_nargs - 1]); // HEXファイルの読み込み.
modify_start_addr( opt_s & 0x7ffff );
if(IsOpt('v')==0) { // ベリファイのときは書き込みをしない.
+ if (verbose > 0)
+ fprintf(stderr, "Erasing flash.\n");
erase_flash();
Flash_Unlock();
+ if (verbose > 0)
+ fprintf(stderr, "Start writing hex data.\n");
write_hexdata(); // 書き込み.
// 合否判定.
util.c:
Sleep()
など、未実装の関数を実装する。また、UartInit()
をデバイス名付きで呼ぶために UartInitWithName()
という関数を新設。
--- ../uart_bootloader/hostpc/util.c 2016-05-15 18:42:13.000000000 +0900
+++ hostpc/util.c 2016-06-03 01:02:33.000000000 +0900
@@ -27,6 +27,7 @@
#include <stdlib.h>
#include <memory.h>
#include <time.h>
+#include <unistd.h>
#include "monit.h"
#include "portlist.h"
@@ -38,6 +39,8 @@
#define VERBOSE 0
+int verbose = 0;
+
typedef struct {
uint start,size;
} Region;
@@ -61,6 +64,40 @@
0xa0000000,
};
+#if defined(_LINUX_)
+void Sleep(int msec)
+{
+ usleep(msec * 1000);
+}
+
+void strupr(char *s)
+{
+ while (*s != 0) {
+ if (*s >= 'a' && *s <= 'z')
+ *s -= 'a' - 'A';
+ }
+}
+
+int stricmp(char *s1,char *s2)
+{
+ return strcasecmp(s1, s2);
+}
+
+int getch(void)
+{
+ extern int RS_keyInput(void);
+ return RS_keyInput();
+}
+
+int kbhit(void)
+{
+ extern int RS_keyavailable(void);
+ return RS_keyavailable();
+}
+
+
+#endif
+
//static
int check_region(int addr,int size)
{
@@ -800,8 +837,8 @@
#define BUFF_SIZE 256
#define DEBUG_PKTDUMP 0 // パケットをダンプする.
-//#define BAUDRATE 115200
-#define BAUDRATE 500000
+#define BAUDRATE 115200
+//#define BAUDRATE 500000
static int dev_id = 0; // ターゲットID: 0x25 もしくは 0x14 だけを許容.
@@ -998,6 +1036,19 @@
return flash_get_status();
}
+int UartInitWithName(char *devname)
+{
+ if (verbose > 0)
+ fprintf(stderr, "Initializing Uart %s.\n", devname);
+ RS_init(devname, BAUDRATE); /* No return on error */
+ if (verbose > 0)
+ fprintf(stderr, "Sending 0xaa/0x55 sequence.\n");
+ RS_putc(0xaa);
+ RS_putc(0x55);
+ return flash_get_status();
+}
+
+
/*********************************************************************
* 終了
*********************************************************************
@@ -1008,7 +1059,7 @@
unsigned char buf[BUFF_SIZE];
memset(buf , 0xff, sizeof(buf) );
RS_putdata( buf , PACKET_SIZE+1 );
- Sleep(1);
+ usleep(1000);
}
RS_exit();
return 0;
--- ../uart_bootloader/hostpc/util.h 2016-05-15 18:42:13.000000000 +0900
+++ hostpc/util.h 2016-05-29 19:44:47.000000000 +0900
@@ -18,6 +18,7 @@
int hidCommand(int cmd,int arg1,int arg2,int arg3);
int hidasp_cmd(const unsigned char cmd[4], unsigned char res[4]);
int UartInit(int com_n);
+int UartInitWithName(char *devname);
int UartExit(void);
#define ZZ printf("%s:%d: ZZ\n",__FILE__,__LINE__);
gr.c:
グラフィック関係のダミー関数を定義する。
--- ../uart_bootloader/hostpc/gr.c 2016-05-15 18:42:13.000000000 +0900
+++ hostpc/gr.c 2016-06-04 00:29:43.000000000 +0900
@@ -731,4 +731,31 @@
init_bitmap(bpp);
}
#else
+
+/* Dummy functions */
+int gr_break(void)
+{
+ return 0;
+}
+
+void gr_close(void)
+{
+}
+
+void gr_init(int width,int height,int bpp,int color)
+{
+}
+
+void gr_pset(int x,int y,int color)
+{
+}
+
+void gr_puts(int x,int y,char *s,int color,int bkcolor,int fontsize)
+{
+}
+
+void gr_vline(int x1,int y1,int x2,int y2,int c)
+{
+}
+
#endif
Makefile
の中に hex2pickit3
の呼び出しがある。これは、hex ファイルを PICkit3 での書き込みに適するようにアドレス変換するもので、iruka さんのウェブサイトにある。ダウンロード: hex2pickit3.zip
そのまま make
すると、hex2pickit3.exe
という実行ファイルができる。これを hex2pickit3
にリネームし、パスの通ったディレクトリ(例えば /usr/local/bin
)に置いておく。
生成されたファームウェアの hex は下の通り。ブートローダ本体は 0x1FC0000C
〜0x1FC00BBB
で、3 KB のブートローダ領域に収まっている。実行開始位置の 0x1FC00000
にはブートローダ先頭へのジャンプ命令が入っている。
:020000041FC01B
:10000C0000A01D3C0020BD270060624101A01C3CEB ← プログラム本体
:10001C0000809C270260094020582001801E2A7D08
:10002C008449497D0260894000E0DC4102608B40DC
:10003C0000A0083C0400082500A0093CF00229257A
:10004C00000000AD040008252B080901FCFF20145A
:10005C0000000000C09F083CBC0B082500A0093C18
(中略)
:100B500000016330FDFF6010000000000060604194
:100B600080BF023C206044AC0800E003206060418C
:100B7000F56424670068071080811F1ED10204D528
:100B8000049501490148A2E8F7617564A0E8006591
:100B9000F46405671F1AB400246702EA066106B40C
:100BA000B1671F1AFD00D0670110006850677464B8
:080BB000A0E80065200000A090
:040BB8000000000039
:020000041FC01B
:0C000000C09F1A3C0C005A270800400367 ← lui k0,0x9FC0; addiu k0,k0,12; jr k0
:040BF000FFFFFFCF35 ← コンフィグレーションレジスタ
:040BF400F878F9FF95
:040BF800594A60FFF7
:040BFC00EFFFFF7F89
:04000005BFC0000078 ← スタートアドレス 0xBFC00000
:00000001FF
ホスト側ツールは、hostpc
でビルドする。書き込みツールの uartflash32
とモニタツールの uartmon32
ができる。
ファームウェア pickit3.hex
を PICkit3 で ORANGE pico に書き込む。
2016-06-06T00:05:18+0900 - Loading hex file. Please wait...
Loading code from /Users/(中略)/uart_bootloader_TN/pickit3.hex...
2016-06-06T00:05:19+0900 - Hex file loaded successfully.
2016-06-06T00:05:30+0900 - Programming...
The following memory area(s) will be programmed:
boot config memory
configuration memory
Device Erased...
Programming...
Programming/Verify complete
2016-06-06T00:05:35+0900 - Programming complete
Pass Count: 4
USB-シリアルを JP7 に接続し、ORANGE pico の電源を入れてから uartmon32
を立ち上げる。
MacBook:hostpc nagata$ ./uartmon32 /dev/cu.usbserial-A1032L8X
TARGET DEV_ID=32 VER=1.1(Bootloader) FLASH=9d000000,40000
MIPS> l 1fc00000 1fc00040 # 逆アセンブル
1fc00000 3c1a9fc0 lui k0,0x9fc0
1fc00004 275a000c addiu k0,k0,12
1fc00008 03400008 jr k0
1fc0000c 3c1da000 lui sp,0xa000
1fc00010 27bd2000 addiu sp,sp,8192
1fc00014 41626000 di v0
1fc00018 3c1ca001 lui gp,0xa001
1fc0001c 279c8000 addiu gp,gp,-32768
1fc00020 40096002 mfc0 t1,$12,2
1fc00024 01205820 add t3,t1,zero
1fc00028 7d2a1e80 ext t2,t1,0x1a,0x4
1fc0002c 7d494984 ins t1,t2,0x6,0x4
1fc00030 40896002 mtc0 t1,$12,2
1fc00034 41dce000 wrpgpr gp,gp
1fc00038 408b6002 mtc0 t3,$12,2
1fc0003c 3c08a000 lui t0,0xa000
1fc00040 25080004 addiu t0,t0,4
1fc00044 3c09a000 lui t1,0xa000
MIPS> d 1fc00bf0 1fc00bff # メモリダンプ
1fc00bf0 ff ff ff cf f8 78 f9 ff 59 4a 60 ff ef ff ff 7f
MIPS>