Главная » Микроконтроллеры
Призовой фонд
на март 2017 г.
1. UNI-T UT-39C
Паяльник
2. Тестер компонентов LCR-T4
Паяльник
3. 100 руб.
От пользователей

Программа загрузчика кода

Ниже приведен пример простого загрузчика, использующего USART для связи через COM-порт компьютера (схема такого подключения находится в разделе “Отладка”). Загрузчик занимает менее 128 слов памяти программ и, поэтому, целиком помещается в Boot Loader Section наименьшего размера.

Существует два варианта запуска boot-loader. В первом из них обращение к коду загрузчика происходит из тела основной программы, расположенного в Application Section. В ином случае, сбросом FUSE-бита BOOTRST, положение вектора сброса можно перенести непосредственно в Boot Loader Section и запускать загрузчик каждый раз при старте устройства. В примере на рис.3 реализован второй способ управления. Рассмотрим его подробнее.

После сброса микроконтроллер начинает выполнять программу с адреса SMALLBOOTSTART = 0xF80 (BOOTSZ1:BOOTSZ0 = 11). После инициализации стека и настроек USART, управляющая программа переходит к проверке определенного условия, указывающего на необходимость модификации FLASH-памяти. В данном случае таким условием, выбранным произвольным образом, является логический уровень на выводе PB0. Если линия закорочена на землю (присутствует лог.0), то происходит вызов подпрограммы загрузчика. В противном случае происходит передача управления на нулевой адрес, т.е. в самое начало прикладной программы.

        .nolist
        .include "m8def.inc"
        .list

    .equ XTAL = 3686     ;частота генератора в кГц
    .equ BAUD = 115200   ;необходимая скорость обмена в бит/с
    .equ NB = ((10000*XTAL)/(16*BAUD)-5)/10

    .def temp  = R16     ;вспомогательный регистр
    
        .cseg
        .org  SMALLBOOTSTART

      ldi   temp,low(RAMEND) ;инициализация стека
	  out   SPL,temp
	  ldi   temp,high(RAMEND)
	  out   SPH,temp
	  clr   temp        ;задаем параметры USART: 115200, 8-N-1 
      out   UBRRH,temp
      ldi   temp,NB   
      out   UBRRL,temp
      ldi   temp,(1<< RXEN)|(1<< TXEN)   
      out   UCSRB,temp
      ldi   temp,(1<< URSEL)|(1<< UCSZ0)|(1<< UCSZ1)
      out   UCSRC,temp
	  sbi   PORTB,PB0   ;подключаем к линии 0 порта B 
	  nop               ;внутренней pull-up резистор
	  sbis  PINB,PB0    ;если на выводе PB0 лог.0, то 
      rcall boot_loader ;запускаем загрузчик
      rjmp  0 ;если лог.1, то переходим к основной программе 
 
;            Подпрограмма загрузчик 
; R16 - регистр для приема/передачи данных по USART 
; R17 - регистр для промежуточных операций 
; R18 - используется как счетчик слов
; ZH:ZL - регистр с адресом страницы и указатель на строку
; R1,R0 - используются с инструкцией spm

boot_loader: 
      rcall getc       ;принимаем через порт команду
      cpi   R16,'D'    ;если "D", то передаем строку
      brne  bl1
      rjmp  device_id  ;подтверждения присутствия на линии
 bl1: cpi   R16,'F'    ;если "F", то переходим к
      brne  bl2
      rjmp  read_fuse  ;чтению FUSE-битов и ячеек защиты
 bl2: cpi   R16,'P'    ;если "P", то переходим к 
	  brne  bl3
	  rjmp  program_flash ;программированию страницы FLASH-памяти
 bl3: cpi   R16,'R'    ;если "R", то переходим к 
	  brne  bl4
	  rjmp  read_flash ;чтению страницы FLASH-памяти 
 bl4: cpi   R16,'E'    ;если "E", то переходим к
  	  brne  bl5 
	  rjmp  erase_flash;стиранию страницы FLASH-памяти
 bl5: cpi   R16,'O'    ;если "O", то завершение подпрограммы
      brne  bl6
	  ret              ;если принят иной символ, то возвращаем  
 bl6: rcall put_err    ;символ ошибки "?" 
      rjmp  boot_loader
		
device_id:  
      ldi   ZH,high(2*id_string);заносим в указатель Z адрес
      ldi   ZL,low(2*id_string) ;начала строки подтверждения
 di1: lpm   R16,Z+   ;передаем символы до тех пор, пока
      tst   R16      ;не встретится 0 (конец строки)
      breq  boot_loader
      rcall putc
      rjmp  di1

read_fuse:
	  ldi   R17,(1<< BLBSET)|(1<< SPMEN)
	  clr   ZH
      clr   ZL
      out   SPMCR,R17 
	  lpm   R16,Z ;считываем младший байт конфигурации
	  rcall putc
	  ldi   ZL,1
      out   SPMCR,R17 
	  lpm   R16,Z ;считываем содержимое ячеек защиты
	  rcall putc
      ldi   ZL,3
      out   SPMCR,R17 
	  lpm   R16,Z ;считываем старший байт конфигурации
	  rcall putc
      rjmp  boot_loader

program_flash:
      rcall get_adr ;принимаем адрес страницы
      ldi   R16,(1<< PGERS)|(1<< SPMEN)
	  rcall do_spm  ;стираем страницу
	  ldi   R18,PAGESIZE ;инициализируем счетчик слов
 pf1: rcall getc    ;принимаем младший байт кода
      mov   R0,R16
	  rcall getc    ;принимаем старший байт кода
	  mov   R1,R16
 	  ldi   R16,1<< SPMEN
	  rcall do_spm  ;заносим слово в буфер записи 
	  adiw  ZH:ZL,2
	  dec   R18     ;повторяем 32 раза
	  brne  pf1 
      subi  ZL,PAGESIZE ;восстанавливаем адрес страницы
      sbci  ZH,0
	  ldi   R16,(1<< PGWRT)|(1<< SPMEN)  
	  rcall do_spm  ;записываем страницу
      rcall put_ret ;отсылаем символ подтверждения "!"
	  rjmp  boot_loader

read_flash:   
      rcall get_adr ;принимаем адрес страницы
      ldi   R16,(1<< RWWSRE)|(1<< SPMEN)
	  rcall do_spm  ;разрешаем доступ к области RWW
      ldi   R18,PAGESIZE ;инициализируем счетчик слов
 rf1: lpm   R16,Z+
      rcall putc    ;передаем младший байт кода
	  lpm   R16,Z+
      rcall putc    ;передаем старший байт кода
	  dec   R18     ;повторяем 32 раза
	  brne  rf1
	  rcall put_ret ;отсылаем символ подтверждения "!"
	  rjmp  boot_loader

erase_flash:		
      rcall get_adr
	  ldi   R16,(1<< PGERS)|(1<< SPMEN)
	  rcall do_spm  ;стираем страницу
      rcall put_ret ;отсылаем символ подтверждения "!"
	  rjmp  boot_loader

;         Подпрограмма запуска команды spm
; R16 - байт для передачи кода в регистр SPMCR 
do_spm: 
      in    R17,SPMCR ;ожидаем пока не закончится предыдущая
      sbrc  R17,SPMEN ;операция 
	  rjmp  do_spm
 ds1: sbic  EECR,EEWE ;ожидаем пока не закончится запись 
	  rjmp  ds1       ;в EEPROM-память
	  out   SPMCR,R16 ;модифицируем регистр SPMCR
	  spm             ;в течении 4-х циклов выполняем команду spm
      ret

;           Подпрограмма передачи байта 
; R16 - байт для передачи на входе в подпрограмму 
putc:
      sbis  UCSRA,UDRE ;ожидаем пока освободится регистр 
      rjmp  putc       ;данных передатчика USART
      out   UDR,R16    ;передаем байт данных
      ret

;            Подпрограмма приема байта 
; R16 - принятый байт на выходе из подпрограммы
getc:   
      sbis  UCSRA,RXC  ;ожидаем пока не будет принят байт       
      rjmp  getc
      in    R16,UDR    ;переносим байт в рабочий регистр
      ret

;       Подпрограмма приема адреса страницы
; ZH:ZL - принятый адрес на выходе из подпрограммы
get_adr:
      rcall getc    ;принимаем младший байт адреса страницы
	  mov   ZL,R16          
      rcall getc    ;принимаем старший байт адреса страницы
	  mov   ZH,R16
	  ret

;  Подпрограмма передачи символа подтверждения "!"
put_ret:
      ldi   R16,'!'
      rcall putc             
      ret

;     Подпрограмма передачи символа ошибки "?"
put_err:
      ldi   R16,'?'       
      rcall putc             
      ret

id_string:   ;строка подтверждения 
   .db  "ATmega8",0

Скачать исходник asm и прошивку hex

Перейти к следующей части:

Теги:

Котов Игорь Юрьевич Опубликована: 2012 г. 0 0
Я собрал 0 0
x

Оценить статью

  • Техническая грамотность
  • Актуальность материала
  • Изложение материала
  • Полезность устройства
  • Повторяемость устройства
  • Орфография
0

Средний балл статьи: 0 Проголосовало: 0 чел.

Комментарии (1) | Я собрал (0) | Подписаться

0
Leonid #
Как выйти обратно в основную программу из загрузчика?
Ответить
Добавить комментарий
Имя:
E-mail:
не публикуется
Текст:
Защита от спама:
В чем измеряется сила тока?
Файлы:
 
Для выбора нескольких файлов использйте CTRL

Программатор Pickit3
Программатор Pickit3
Печатная плата для усилителя "LM3886 + AD825" Бокс для хранения компонентов
вверх