Главная » Микроконтроллеры
Призовой фонд
на сентябрь 2017 г.
1. 1000 руб
PCBWay
2. Осциллограф DSO138
Паяльник
3. Тестер компонентов MG328
Паяльник
4. 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
Регулятор мощности 2 кВт Ветрогенератор
вверх