楽天市場
[無料でホームページを作成] [通報・削除依頼]

番外 ATTINY13A用ブートローダー

番外編
このページではPICではなくATTINY13A用のブートローダーをご紹介します。
ATTINY13A用のブートローダーを構築するにあたり、PIC10F322とATTINY13Aとのスペックの違いを示します。

img_20130625-005952.jpg

2013.07.07 追記
 本ページの内容がTiny AVR/PIC Bootloader+に正式採用されました。
 
http://sourceforge.net/p/tinypicbootload/discussion/?source=navbar


PIC10F322のブートローダーをベースにしてATTINY13A用のブートローダーを作成していきますが、
重要な留意点として以下の項目が挙げられます。

1.ATTINY13A用のブートローダーではEEPROMの書き込みをサポートする必要がある。
2.ATTINY13Aリセット時にブートローダーへジャンプさせる必要があるが、割り込みベクターが0x0001に存在するため、ジャンプコードを記述する領域が0x0000の1ワードしか無い。(PIC10F322では4ワード)
3.ともにソフトウエアでシリアルインターフェースを構成する必要があるが、ATTINY13Aの作動がPIC10F322に比べて 9.6/(16/4)= 2.4 倍以上早いので シリアルインターフェースの定数の見直しが必要。

上記2について補足しますと、 ATTINY13Aには相対ジャンプ(RJMP:1ワード記述)間接ジャンプ(IJMP:3ワード記述)の2種類のジャンプがあるのですが、先述の割り込みベクター位置との兼ね合いからIJMP命令を記述するためには先ずRJMP命令で割り込みベクター以外の場所にジャンプしてから改めてIJMP命令を実行するという、いわゆる2段ジャンプの記述が必要となります。  一方RJMPで許される相対アドレスは12ビット(-2048~+2047)である為(IJMPは全域可)プログラムフラッシュメモリのサイズがATTINY13Aよりも大きなATTINY85 などではフラッシュメモリの最後部にブートローダーが配置できません。

上記3について補足しますと、PIC10F322/8MHzではボーレート9600の場合1バイトあたりのサイクル数は、
(8/4)*1000 *1000/9600=208サイクルでしたが、ATTINY13Aでは同9.6*1000*1000/9600=1000サイクルとなります。

4.更にもうひとつの重要な問題点としてクロック発振周波数の問題が挙げられます。ATTINY13Aの工場校正値では
5Vで使用した場合、発振周波数が低めに設定される傾向がありますので、OSCCALレジスターの値を書き換える必要が
あります。OSCCALの校正値をブートローダー中に記述します。校正値は個体差がありますので、AATTINY13Aの場合は固体ごとにカスタムメイドのブートローダーとなります。

5.ブートローダーのホストプログロム
ファームウエアの留意点は以上ですが、ホスト側のプログラムも留意する必要があります。
幸いなことにオープンソースのTiny PIC Bootloader+というすばらしいホストプラグラムがありますので
これを改造して使わせてもらいました。改造の詳細についてはこのページで述べませんが、
改造のポイントを記述します。(新PIC10F322tinybldその2のページの記述も参考になります。)

①PIC10F322ではHEXファイル(転送するファイル)の先頭(0x0000)からの4ワードをアドレス0x019C~0x019Fの領域に強制コピーしていたが、ATTINY13Aではこれを止める。
②PIC10F322ではアドレス0x0000~0x0002の3ワードのコードをブートローダーへのジャンプコードに強制置換していたが、ATTINY13Aでは0x0000の1ワードのみ ブートローダーへのジャンプコードに 強制置換する。
③ATTINY13AのコンパイラではEEPROMのデータ(HEX)とプログラムコードのデータ(EEP)が別々に出力される。
このEEPファイルのデータを、非拡張ミッドレンジのPIC16F同様に、アドレス0x2100からコーディングされているように見せかける必要がある。


<ブートローダーのソースプログラム>


; change these lines accordingly to your application
.include "tn13adef.inc"
.equ    IdTypePIC=0x12        ; must exists in "piccodes.ini"
#define  max_flash 0x200        ; in WORDS, not bytes!!! (= 'max flash memory' from "piccodes.ini" divided by 2)

.equ    xtal = 9600000         ; you may also want to change: _HS_OSC _XT_OSC  
.equ    baud = 9600           ; standard TinyBld baud rates: 115200 or 19200

.equ        Calib = 0x66                      ; 9.6MHz Calibration value

#define    TX    3                              ; ATTINY13A TX Data output pin (i.e. 2 = PORTB,2)
#define    RX    4                              ; ATTINY13A RX Data input pin (i.e. 3 = PORTB,3)
#define    Direct_TX                          ; RS-232C TX Direct Connection(No use MAX232)
#define    Direct_RX                          ; RS-232C RX Direct Connection(No use MAX232)

; The above 10 lines can be changed and buid a bootloader for the desired frequency

;********************************************************************
; Tiny Bootloader ATTINY13A Size=100words
;
; This program is only available in Tiny PIC Bootloader +.
;
; Tiny PIC Bootloader +
; https://sourceforge.net/projects/tinypicbootload/
;
; !!!!! Set Fuse Bit SELFPRGEN=0,CKDIV8=1 and 9.6MHz Calibration value !!!!!
;
; Please add the following line to piccodes.ini
;
; $12, B, ATTINY 13, $400, 64, default, 32,
;
;********************************************************************


#define    first_address max_flash-100         ; 100 word in size

#define    crc     r20
#define    cnt1   r21
#define    flag     r22
#define    count  r23
#define    cn       r24
#define    rxd      r25

.cseg
;0000000000000000000000000 RESET 00000000000000000000000000

              .org       0x0000                           ;;Reset vector
              RJMP   IntrareBootloader

;&&&&&&&&&&&&&&&&&&&&&&& START &&&&&&&&&&&&&&&&&
;---------------------- Bootloader ----------------------
;
;PC_flash: C1h AddrH AddrL nr ...(DataLo DataHi)... crc
;PIC_response: id K K

               .org       first_address
;               nop
;               nop
;               nop
;               nop

               .org       first_address+4
IntrareBootloader:
               RCALL  INITReceive           ; wait for computer
               SUBI      rxd,0xC1                ; Expect C1
               BREQ    PC+2                     ; skip if C1
               RJMP    way_to_exit             ; connection errer or timeout
               LDI        rxd,IdTypePIC         ; send IdType
               RCALL  rs1tx
MainLoop:
               LDI        rxd,'K'                     ; send 'K'
mainl:
               RCALL  rs1tx
               CLR      crc                         ; clear Checksum
               RCALL  Receive                  ; get ADR_H
               MOV      r31,rxd                   ; set r31
               MOV      flag,rxd                   ; set flag
               RCALL   Receive                 ; get ADR_L
               MOV      r30,rxd                    ; set r30
               OUT       EEARL,rxd             ; set EEARL
               CLC                                    ; set PCPAGE:PCWORD
               ROL       r30
               ROL       r31
               RCALL   Receive                  ; get count
               MOV       count,rxd                ; set count
rcvoct:
               RCALL   Receive                  ; get Data(L)
               MOV      r0,rxd                      ; set Data(L)
               OUT       EEDR,rxd                ; set EEDR
               RCALL   Receive                  ; get Data(H)
               MOV       r1,rxd                     ; set Data(H)
               LDI         rxd,0x01                  ; write buffer
               RCALL   ctrl_flash
               ADIW      r30,2                       ; PCPAGE:PCWORD=PCPAGE:PCWORD+2
               SUBI       count,2                   ; count=count-2
               BRNE     rcvoct                     ; loop

               SBIW       r30,32                     ; PCPAGE:PCWORD=PCPAGE:PCWORD-32
               RCALL   Receive                   ; get Checksum
               BRNE     ziieroare                  ; Checksum error ?

               SBRC     flag,6                       ; is flash ?
               RJMP     eeprom
flash:
               LDI         rxd,0x03                   ; erase Flash Page
               RCALL   ctrl_flash
               LDI         rxd,0x05                   ; write Flash Page
               RCALL   ctrl_flash
               RJMP     MainLoop                 ; loop
eeprom:
               RCALL    w_eeprom                ; write EEPROM
               RJMP      MainLoop                ; loop
ziieroare:
               LDI          rxd,'N'                     ; send "N"
               RJMP      mainl                      ; retry

; ********************************************************************
;
; Write EEPROM
;
; Set EEARL/EEDR and call
;
; ********************************************************************

w_eeprom:
                SBI          EECR,EEMPE
                SBI          EECR,EEPE
                RET

; ********************************************************************
;
; Write and Erace flash/buffer
;
; Set R30:R31/R0:R1/rxd and call
;
; rxd:1 write buffer
; rxd:3 erase Flash Page
; rxd:5 write Flash Page
;
; ********************************************************************

ctrl_flash:
               OUT          SPMCSR,rxd
               SPM
               RET

; ********************************************************************
;
; RS-232C Send 1byte
;
; Set rxd and call
;
; ********************************************************************

rs1tx:
                LDI           cn,1+8+1                  ; 10-bit Data
                COM         rxd                          ; Data inverce
                RJMP       PC+5                       ; Start bit
                LSR          rxd                          ; shift right LSB to Carry [1]

#ifdef Direct_TX
                brcs          PC+2                       ; [2/1]
                cbi            PORTB,TX               ; set TX='0' if Carry='0' [2]
                brcc          PC+2                       ; [2/1]
                sbi            PORTB,TX                ; set TX='1' if Carry='1' [2]
#else
                brcs          PC+2
                sbi            PORTB,TX                ; set TX='1' if Carry='0'
                brcc          PC+2
                cbi            PORTB,TX                ; set TX='0' if Carry='1'
#endif

                rcall          bwait                        ; wait 1 bit [994]
                dec           cn                            ; [1]
                brne          PC-7                       ; [2] 1+7+994+1+2=1005

bwait:                                                       ; wait 1 bit
                rcall          bwait2                      ;3+494+494=991
bwait2:                                                     ; wait 1/2bit
                push          rxd                          ;2
                ldi              rxd,162                    ;1
                subi           rxd,1                        ;1
                brne          PC-1                       ;2/1
                pop            rxd                          ;2
                ret                                           ;4 2+1+(1+2)*162-1+2+4=494

; ********************************************************************
;
; INITReceive
;
; Set TX Port
;
; ********************************************************************

INITReceive:
                 SBI            DDRB,TX                 ; set TX Port
                 LDI            rxd,Calib                  ; set 9.6MHz Calibration value
                 OUT          OSCCAL,rxd

; ********************************************************************
;
; RS-232C Recieve 1byte with Timeout and Check Sum
;
; ********************************************************************

Receive:
                 LDI            cnt1,xtal/500000+1    ; for 20MHz => 11 => 1second
rpt2:
                 CLR           r28
                 CLR           r29
rptc:                                                            ; check Start bit
#ifdef Direct_RX
                 SBIS          PINB,RX
#else
                 SBIC          PINB,RX
#endif
                 RJMP         PC+4
                 RCALL       r1rx11                       ; get 1 byte
                 ADD           crc,rxd                      ; compute checksum
                 RET

                 SBIW          r28,1
                 BRNE         rptc
                 DEC           cnt1
                 BRNE         rpt2
way_to_exit:
                 RJMP        first_address               ; timeout:exit in all other cases

; ********************************************************************
;
; RS-232C Recieve 1byte
;
; Return in rxd
;
; ********************************************************************

rs1rx:
#ifdef Direct_RX
                  SBIS           PINB,RX
#else
                  SBIC           PINB,RX
#endif
                  RJMP         PC-1                         ; wait Start bit
r1rx11:
                  RCALL       bwait2                       ; wait 1/2 bit
                  LDI             cn,9                          ; 9-bit Data
                  ROR           rxd                            ; set Data [1]
                  RCALL       bwait                         ; wait 1 bit and set Carry=0 [994]

#ifdef Direct_RX
                  SBIS           PINB,RX                    ; [2/3]
#else
                  SBIC           PINB,RX
#endif

                  SEC                                            ; [1]
                  DEC            cn                            ; [1]
                  BRNE          PC-5                       ; [2] 1+994+3+1+1+2=1002
                  RET

; ********************************************************************
; After reset
; Do not expect the memory to be zero,
; Do not expect registers to be initialised like in catalog.




<HEXコード:上記ソースのコンパイル結果>

:020000020000FC
:020000009FC19E
:1003400043D0915C09F04FC092E12CD09BE42AD0BD
:1003500044273DD0F92F692F3AD0E92F9EBB8894CE
:10036000EE1FFF1F34D0792F32D0092E9DBB2FD026
:10037000192E91E014D032967250B1F7B09727D071
:1003800049F466FD05C093E00AD095E008D0DECFC1
:1003900003D0DCCF9EE4DBCFE29AE19A089597BFC9
:1003A000E89508958AE0909504C0969508F0C39862
:1003B00008F4C39A02D08A95C1F700D09F9392EABD
:1003C0009150F1F79F910895BB9A96E691BF54E141
:1003D000CC27DD27B49B03C009D0490F089521978E
:1003E000C9F75A95A9F7A8CFB49BFECFE7DF89E0FC
:0E03F0009795E3DFB49B08948A95D1F70895A2
:00000001FF