roboforum.ru

Технический форум по робототехнике.

Bootloader для MiniBot 2.х

Bootloader для MiniBot 2.х

EdGull » 20 дек 2009, 20:57

Т.к. у нас с MibbiM появилась острая необходимость в перепрошивке роботов по радиоканалу потому что мы с ним уманались лазить под стол и перетыкивать программаторский разъем, решили всё таки добить бутлоадер.

Данный код проверял на МиниБоте 2.1 т.е. с закороченными Rx и Tx, при получениие P пишет Programming.
Т.е. всё Ок

Код: Выделить всёРазвернуть
$regfile = "m32DEF.dat"
$crystal = 7372800
$baud = 115200
$hwstack = 64
$swstack = 64
$framesize = 64

'светодиоды

Config Pinc.6 = Output : Led Alias Portc.6 : Led = 0


Dim S As Byte
Dim Tmp1 As Byte


Waitms 500


For Tmp1 = 1 To 255
   Print "Wait P for programming -" ; Tmp1
   Waitms 100
   S = Inkey()
   If S = 80 Then
      Print ""
      Print "Programing!!!"
      'Jmp $3800
      Wait 3
   End If
Next

Do
   Led = 1 : Waitms 250
   Led = 0 : Waitms 250
Loop



'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
'                    B O O T  L O A D E R
'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

'The fusebit FE is set so that we have 512 bytes for the boot code
'Only a part is used btw
'But it sets the bootstart address to 1E00 hex. which happens to be in the M161 too

'The $boot diretive will bind the code below into address specified
'This will generate large files with FFFF opcode from the end of the normal program to the start
'of the bootcode
'Note that the bootloader is written in ASM. This because the bootloader may not call routines from
'the main program. Why? Because during programming they get erased!

'$boot = $3800

'no interrupts are allowed during bootloader programming
Disable Interrupts


'Standard Intel hex file can be sent
':10 0000 00 0C 94 2400189500001895000018950000 25
':00 0000 01 FF
' size , address,record type, data, checksum
'The sample bootloader does not use the checksum

'The same baudrate is used as the main program is using
'but we can change it here when we like. Just unremark the next line and/or change it
'But take in mind that the bootloader sender must use the same baud rate !!!
'Baud = 19200


clr r18                                          ; word counter for written data
clr r23                                          ; page counter

rcall _erase_page                                ; erase first page

_read_lines:
  rcall _rec_line                                ; get line into SRAM pointed by X
  ldi r26,$61                                    ; point to start of line
  clr r27
  ld r24,x+                                      ; get char in r24
  rcall _hex2number                              ; convert result in r17
  ld r24,x+
  rcall _hex2number2                             ; convert second char , r17 holds the number of hex pairs to get
  mov r19,r17                                    ; number of entries
  tst r19
  brne _readnext                                 ; not the end record
  rjmp _write_last_page                          ; final line so write the last page

_readnext:
  adiw xl,6                                      ; point to first pair
_readnextpair:
  ld r24,x+                                      ; get char in r24
  rcall _hex2number                              ; convert result in r17
  ld r24,x+
  rcall _hex2number2                             ; convert second char , r17 holds the data
  mov r0,r17                                     ; save in r0
  dec r19                                        ; adjust pair data counter
  ld r24,x+                                      ; get char in r24
  rcall _hex2number                              ; convert result in r17
  ld r24,x+
  rcall _hex2number2                             ; convert second char , r17 holds the data
  mov r1,r17                                     ; save data
  rcall _write_page                              ; write into page buffer
  cpi r18,64                                     ; page is 128 bytes is 64 words
  breq _writeit                                  ; write page since it is full
_lbl1:
  dec r19                                        ; adjust data pair
  brne _readnextpair                             ; more data
  rjmp _read_lines                               ; next line

_writeit:
  rcall _save_page                               ; save page
  rcall _erase_page                              ; erase next page
  Rjmp _lbl1                                     ; continue

_write_last_page:
  rcall _save_page                               ; save last page
  rjmp _exit_page                                ; exit needs a reset



' get 1 byte from serial port and store in R24
_recbyte:
  Sbis USR, 7                                    ; Wait for character
  rjmp _recbyte
  in r24, UDR                                    ; get byte
Ret

'get one line from the serial port and store in location pointed by X
_rec_line:
  ldi r26,$60                                    ; point to first location in SRAM
  clr r27
_rec_line5:
  sbis usr,5
  rjmp _rec_line5
  ldi r24, 63 ; ?
  !out udr,r24                                   ; show ? so we know we can send next line
_rec_line1:
  rcall _recbyte                                 ; get byte
  cpi r24,13                                     ; enter?
  breq _rec_line2                                ; yes ready
  st x+,r24                                      ; no so store in sram buffer
  rjmp _rec_line1                                ; next byte
_rec_line2:
  clr r24                                        ; string terminator
  st x,r24
ret

' convert HEX byte in r24 into bin value , on exit byte in r17
_hex2number:
  clr r17
_hex2number4:
  Subi R24,65                                    ; subtract 65
  Brcc _hex2number3                              ; in case carry was cleared
  Subi R24,249                                   ; not
_hex2number3:
  Subi R24,246
  Add R17,R24                                    ; add to accu
ret

';called for the second byte
_hex2number2:
  Lsl R17                                        ; shift data
  Lsl R17
  Lsl R17
  Lsl R17
  rjmp _hex2number4                              ; handle the conversion


'page address in z7-z13
_erase_page:
  mov r31,r23                                    ; page address
  lsr r31                                        ; get z8-z13 shift ls bit into carry
  clr r30
  ror r30                                        ; get z7
  ldi r24,3                                      ; page erase command
  rcall _do_spm
  clr r16 ; page cleared indicator
ret

_write_page:
  mov r31,r23                                    ; page address z8-z13
  lsr r31
  clr r30
  ror r30                                        ; carry to z7

  mov r24,r18                                    ; word address buffer counter
  lsl r24
  add r30,r24                                    ; z1-z6
  ldi r24,1                                      ; buffer fill
  rcall _do_spm
  inc r18
ret


_save_page:
'z0-z6 must be 0
'z7-z13 is the page address
'r0 and r1 are ignored
  mov r31,r23
  lsr r31
  clr r30
  ror r30

  ldi r24,5                                       ; write page
  rcall _do_spm
  clr r18                                         ; page word address counter
  inc r23                                         ; page counter
ret

_exit_page:
  in r24,spmcr
  sbrs r24,asb
  rjmp _exit_page1
  ldi r24,17
  rcall _do_spm
  rjmp _exit_page
_exit_page1:
End


'; execute spm instruction , data in R24
_do_spm:
  sbic eecr, eewe
  rjmp _Do_spm
!  Out Spmcr , R24
  spm
!.obj Ffff                                         ; needs FFFF according to datasheet
  nop
_wait_spm:
  In r24,spmcr
  sbrc r24, 0
  rjmp _wait_spm
ret

End

Re: Bootloader для MiniBot 2.х

кулер 23 » 20 дек 2009, 21:19

Надо будет попробовать :)

Re: Bootloader для MiniBot 2.х

EdGull » 20 дек 2009, 21:24

нечего пока пробывать, пока еще не готово
и всё будет заточено под радиоканал, которого если я не ошибаюсь у тебя нет.

Re: Bootloader для MiniBot 2.х

avr123.nm.ru » 20 дек 2009, 21:33

Можно подробней чуть расказать как им пользоваться ? В чем обсобенность "под радиоканал" ?

Re: Bootloader для MiniBot 2.х

SMT » 20 дек 2009, 23:13

То есть вот так можно периодически ожидать получения в UART специального символа и перейти на адрес бутлоадера?

Re: Bootloader для MiniBot 2.х

EdGull » 20 дек 2009, 23:43

2Авр небольшие особенности связанные с архитектурой МиниБота, для конечного пользоввателя это будет прозрачно, поэтому интереса не представляет.
2SMT Естественно. Всегда можно перейти на нужную метку.
Только мы в будущем будем посылать не символ, а служебное слово-команду.
Наверное это будет "Prog"

Re: Bootloader для MiniBot 2.х

EdGull » 07 янв 2010, 20:27

текущие версии ниже

пример основного кода.
важным является переход к бутзагрузчику, осуществляемый кодом:
Код: Выделить всёРазвернуть
   If S = "boot" Then
      Goto &H3C00
   End If

Код: Выделить всёРазвернуть
$regfile = "m32DEF.dat"
$crystal = 7372800
$baud = 115200

$hwstack = 64
$swstack = 64
$framesize = 64

' Светодиод для индикации процесса. Мигающий красный - прошивка, горящий зеленый - успешное завершение
Config Pinc.4 = Output : Led_r1 Alias Portc.4 : Led_r1 = 0
Config Pinc.5 = Output : Led_g1 Alias Portc.5 : Led_g1 = 0
Config Pinc.6 = Output : Led_r2 Alias Portc.6 : Led_r2 = 0
Config Pinc.7 = Output : Led_g2 Alias Portc.7 : Led_g2 = 0

Config Pind.2 = Input : Button Alias Pind.2

Dim S As String * 20
   Dim Arr(20) As Byte At S Overlay
   Dim Substr As String * 18 At Arr(3) Overlay

' процедуры
Declare Sub Printf(byval S As String)
   Dim Text As String * 50

S = "abcd"
Wait 3
Do
   Input S Noecho
   If S = "boot" Then
      Toggle Led_g2
      Goto &H3C00
   End If
   Call Printf( "")
   Mid(s , 1 , 1) = "'"
   Call Printf(s)
Loop


Sub Printf(byval S As String)
   Local Cnt As Byte
   Local Len1 As Byte
   Local Buf As String * 1
   Reset Ucsrb.rxen
   Len1 = Len(s)
   For Cnt = 1 To Len1
      Bitwait Ucsra.udre , Set                              ' ожидаю момента, когда можно загрузить новые данные
      Buf = Mid(s , Cnt , 1)
      Udr = Asc(buf)
   Next
      Bitwait Ucsra.udre , Set
      Udr = 13
      Bitwait Ucsra.udre , Set
      Udr = 10
      Set Ucsra.txc                                         ' очищаю флаг прерывания
      Bitwait Ucsra.txc , Set                               ' жду пока передатчик не передаст весь пакет (из внутреннего буфера, не UDR)
   Set Ucsrb.rxen
End Sub

Re: Bootloader для MiniBot 2.х

MiBBiM » 07 янв 2010, 20:27

PC-часть, написана на Borland Delphi 7, екзешник нужно подсовывать баскому вместо нативного stk500.exe
Вложения
stk500.rar
екзек
(172.64 КиБ) Скачиваний: 5
stk500-emu.rar
сырцы
(20.38 КиБ) Скачиваний: 5
Последний раз редактировалось MiBBiM 07 янв 2010, 21:18, всего редактировалось 1 раз.

Re: Bootloader для MiniBot 2.х

EdGull » 07 янв 2010, 20:55

boot

Код: Выделить всёРазвернуть

'----------------------------------------------------------------
'                          (c) 2010
'@Author: mibbim
'@Description: Бутлоадер для Мега32 робота МиниБот
'-----------------------------------------------------------------
' !!!!!!!ТОЛЬКО ДЛЯ МЕГА32!!!!!!
$prog &HFF , &HBD , &HCA , &H00                             ' generated. Take care that the chip supports all fuse bytes.
$crystal = 7372800                                          '8000000
$baud = 115200                                              '38400                                             'this loader uses serial com
' Не использовать буферизованный ввод, ибо прерывания ЗАПРЕЩЕНЫ

$regfile = "m32def.dat"

' процедуры
Declare Sub Chr_print(byval S As Byte)

' mega32
$loader = $3c00                                             ' 1024 слова занимает бут
Const Maxwordbit = 6                                        ' Z6 is maximum bit
Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0


Const Maxword =(2 ^ Maxwordbit) * 2                         ' 128
Const Maxwordshift = Maxwordbit + 1

' Используемые переменные
Dim Bstatus As Byte , Bretries As Byte , Bblock As Byte , Bblocklocal As Byte
Dim Bcsum1 As Byte , Bcsum2 As Byte , Buf(128) As Byte , Csum As Byte
Dim J As Byte , Spmcrval As Byte                            ' self program command byte value

Dim Z As Long                                               ' Z указатель
Dim Vl As Byte , Vh As Byte                                 ' Два байта будут использованы для данных
Dim Wrd As Word , Page As Word                              ' Адреса страницы и слова
Dim Bkind As Byte , Bstarted As Byte

Disable Interrupts                                          ' Прерывания не используются!!!


                                                'wait 100 msec sec
'We start with receiving a file. The PC must send this binary file

' Константы для управляющих символов
Const Nak = &H15
Const Ack = &H06
Const Can = &H18

' Светодиод для индикации процесса. Мигающий красный - прошивка, горящий зеленый - успешное завершение
Config Pinc.4 = Output : Led_r1 Alias Portc.4 : Led_r1 = 0
Config Pinc.5 = Output : Led_g1 Alias Portc.5 : Led_g1 = 0
Config Pinc.6 = Output : Led_r2 Alias Portc.6 : Led_r2 = 0
Config Pinc.7 = Output : Led_g2 Alias Portc.7 : Led_g2 = 0


$timeout = 3500000                                          ' Таймаут для выхода
' Если лоадер сбоит, увеличиваем значение таймаута

Bretries = 10                                               ' Пробуем 5 раз
Testfor123:
Bstatus = Waitkey()                                         'wait for the loader to send a byte

If Bstatus = 123 Then                                       ' "{", 0x7B
   Call Chr_print(ack)
   Bkind = 0                                                ' Переход в режим FLASH лодера, Bkind = 0
   Goto Loader
Elseif Bstatus = 124 Then                                   ' "|"
   Call Chr_print(ack)
   Bkind = 1                                                ' Переход в режим EPPROM лодера, Bkind = 1
   Goto Loader
Elseif Bstatus <> 0 Then
   Decr Bretries
   If Bretries <> 0 Then Goto Testfor123                    ' Неверный символ, пробуем ещё раз
End If

For J = 1 To 10                                             ' Простая индикация того, что мы переходим по нормальному ресет вектору 0x0000
   Toggle Led_r1 : Waitms 100
Next
Goto _reset                                                 ' Переход по адресу 0x0000 на начало программы


' Процедура лоадера, реализует Xmodem-checksum
Loader:
  Do
     Bstatus = Waitkey()
  Loop Until Bstatus = 125                                  ' Очистка буфера


  For J = 1 To 3                                            ' Простая индикация того, что мы переходим по нормальному ресет вектору 0x0000 (!!!) или таки прошли в бутлоадер??
     Toggle Led_r1 : Waitms 50
  Next

  If Bkind = 0 Then                                         ' Если в режиме FLASH программатора
     Spmcrval = 3 : Gosub Do_spm                            ' стирание страницы по адресу Z
     Spmcrval = 17 : Gosub Do_spm                           ' разрешить доступ к RWW памяти (стирание буфера)
  End If


Bretries = 10                                               ' Количество попыток

Do
  Bstarted = 0                                              ' Мы ещё не стартовали
  Csum = 0                                                  ' Чексумма = 0 при старте
  Call Chr_print(nak)                                       ' Первый раз шлем nack
  Do
    Bstatus = Waitkey()                                     ' Ждем статус-байт
    Select Case Bstatus
       Case 1:                                              ' Начало заголовка, PC готов слать данные
            Incr Bblocklocal                                'increase local block count
            Csum = 1                                        'checksum is 1
            Bblock = Waitkey() : Csum = Csum + Bblock       'get block
            Bcsum1 = Waitkey() : Csum = Csum + Bcsum1       'get checksum first byte
            For J = 1 To 128                                'get 128 bytes
              Buf(j) = Waitkey() : Csum = Csum + Buf(j)
            Next
            Bcsum2 = Waitkey()                              'get second checksum byte
            If Bblocklocal = Bblock And Bcsum2 = Csum Then  'are the blocks and the checksum the same?
               Gosub Writepage                              'yes go write the page
               Call Chr_print(ack)                          'acknowledge
            Else
               Call Chr_print(nak)                          'blocks do not match, so send nack
            End If
       Case 4:                                              ' end of transmission , file is transmitted
             If Wrd > 0 And Bkind = 0 Then                  'if there was something left in the page
                 Wrd = 0                                    'Z pointer needs wrd to be 0
                 Spmcrval = 5 : Gosub Do_spm                'write page
                 Spmcrval = 17 : Gosub Do_spm               ' re-enable page
             End If
             Call Chr_print(ack)                            ' send ack and ready

             Led_g1 = 1                                     ' simple indication that we are finished and ok
             Led_r1 = 0
             Waitms 20
             Goto _reset                                    ' start new program
       Case Can:                                            ' PC aborts transmission
             Goto _reset                                    ' ready
       Case Else
          Exit Do                                           ' no valid data
    End Select
  Loop
  If Bretries > 0 Then                                      'attempte left?
     Waitms 1000
     Decr Bretries                                          'decrease attempts
  Else
     Goto _reset                                            'reset chip
  End If
Loop


'(
Spmcrval:
1 - запись регистровой пары R0 : R1 в Z
3 - стирание страницы по адресу Z
5 - запись страницы по адресу Z
17 - разрешить доступ к Rww памяти(стирание буфера)

')

'write one or more pages
Writepage:
If Bkind = 0 Then                                          ' FLASH лоадер
   For J = 1 To 128 Step 2                                  'we write 2 bytes into a page
      Vl = Buf(j) : Vh = Buf(j + 1)                         'get Low and High bytes
      lds r0, {vl}                                          'store them into r0 and r1 registers
      lds r1, {vh}
      Spmcrval = 1 : Gosub Do_spm                           'write value into page at word address
      Wrd = Wrd + 2                                         ' word address increases with 2 because LS bit of Z is not used
      If Wrd = Maxword Then                                 ' page is full
          Wrd = 0                                           'Z pointer needs wrd to be 0
          Spmcrval = 5 : Gosub Do_spm                       'write page
          Spmcrval = 17 : Gosub Do_spm                      ' re-enable page

          Page = Page + 1                                   'next page
          Spmcrval = 3 : Gosub Do_spm                       ' erase  next page
          Spmcrval = 17 : Gosub Do_spm                      ' re-enable page
      End If
   Next

Else                                                       ' EEPROM лоадер
     For J = 1 To 128
       Writeeeprom Buf(j) , Wrd
       Wrd = Wrd + 1
     Next
End If
Toggle Led_r1 : Waitms 10 : Toggle Led_r1                  'indication that we write
Return


Do_spm:
  Bitwait Spmcsr.0 , Reset                                  ' check for previous SPM complete
  Bitwait Eecr.1 , Reset                                    'wait for eeprom

  Z = Page                                                  'make equal to page
  Shift Z , Left , Maxwordshift                             'shift to proper place
  Z = Z + Wrd                                               'add word
  lds r30,{Z}
  lds r31,{Z+1}

  #if _romsize > 65536
      lds r24,{Z+2}
      sts rampz,r24                                         ' we need to set rampz also for the M128
  #endif

  Spmcsr = Spmcrval                                         'assign register
  spm                                                       'this is an asm instruction
  nop
  nop
Return


Sub Chr_print(byval S As Byte)
   Reset Ucsrb.rxen
      Bitwait Ucsra.udre , Set
      Udr = S
      Set Ucsra.txc                                         ' очищаю флаг прерывания
      Bitwait Ucsra.txc , Set                               ' жду пока передатчик не передаст весь пакет (из внутреннего буфера, не UDR)
   Set Ucsrb.rxen
End Sub


Re: Bootloader для MiniBot 2.х

MiBBiM » 09 янв 2010, 00:00

как-то я забыл упомянуть, что это все действительно работает :D
необходимые настройки:
09.01.png

где путь до stk500.exe - это путь до моей прожки, ком-порт соответственно порт, на котором висит минибот.
войти в режим бутлодера можно несколькими способами:
  • первый и самый брутальный - перезапуском питания минибота.
  • второй: программа до начала прошивки шлет комбинацию "boot"+chr(13), соответственно где-то в прошивке её можно обрабатывать и делать goto
  • третий: любой ваш способ (например, по прерыванию от кнопки), конструкция перехода выглядит так: goto &H3C00
после входа в режим бута жмем F4 и вуаля :good:
09.011.png
09.011.png (3.73 КиБ) Просмотров: 3695

Re: Bootloader для MiniBot 2.х

setar » 09 апр 2010, 18:27

Бутлоадер работает только по радиоканалу,
или через USB тоже будет работать ?

Re: Bootloader для MiniBot 2.х

EdGull » 09 апр 2010, 21:07

по уарту, а вот как он туда попадет через USB или по радиоканалу это тебе решать

Re: Bootloader для MiniBot 2.х

setar » 12 апр 2010, 10:51

есть предложение в подобных темах держать перезаписываемым и прикреплённым первый пост, в котором самое свежее чтобы было, а ниже историю как обычно

Re: Bootloader для MiniBot 2.х

Myp » 14 май 2010, 18:48

так господа
а в первый минибот это вкорячить можно надеюсь?

Re: Bootloader для MiniBot 2.х

galex1981 » 14 май 2010, 22:06

Конечно можно! Бутлоадер реализуется для МК а не для версии минибота


Rambler\'s Top100 Mail.ru counter