.include "D:\avrasm\tavrasm\APPNOTES\m8def.inc"
;================================================================================
;                      Работа с Flash
;                 ATmega8, Freq=14,7456Mhz
;-Комманды:
;-0xD7               ;Чтение Статус Регистра
;-0x84               ;Комманда записи в буф1
;-0x87               ;Комманда записи в буф2
;-0xD1               ;Чтение из первого буффера, на низкой скорости!
;-0x83               ;Комманда записи первого буффера во Flash, с пред стиранием
;-0x88               ;Комманда записи первого буффера в Flash,без стирания 
;-0x89               ;Комманда записи второго буффера в Flash,без стирания 
;-0xD2               ;Комманда чтения из Flash
;-0x03               ;Команда не прерывного чтения из Flash (Low Frequency) 
;-0x50               ;Стирание блока
;-0xC7,0x94,0x80,9A  ;Полное стирание чипа(Может глюкать)
;================================================================================

.cseg
.org 0

    ldi r31,LOW(RAMEND)    ; Стек
    out spl,r31
    ldi r31,HIGH(RAMEND)
    out sph,r31 

    clr r30
    clr r31

;************************************************************
;Настройка портов
;************************************************************

    ldi r16,0xff                         ;Присвоение константы
    out DDRC,r16                         ;PORTС на вывод  
                                         ;Светодиоды 

    ldi r16,(0<<PinD2)|(0<<PinD3)        ;PinD2,D3 На вход
    out DDRD,r16

    ldi r16,(1<<PinD2)|(1<<PinD3)        ;Подтягивающий резистор
    out PortD,r16 

;**********************************************************
;Настройка SPI
;**********************************************************

    ser r16
    out PortB,r16

    ldi r16,(1<<PinB3)|(1<<PinB5)|(1<<PinB0) ;На выход
    out DDRB,r16                             ;PinB3 - MOSI
                                             ;PinB5 - SCK
                                             ;PinB0 - CS

    ldi r16,(1<<SPE)|(1<<MSTR)               ;Включаем SPI,Мастер                                          
    out SPCR,r16                             ;частота fck/4

;**************************************************************
;~Старт~
;Ждем нажатия кнопки
;**************************************************************

    clr r20

GetPin: 

   rcall Timer

   com r20
   out PortC,r20        ;Мигаем и ждем нажатия 

   sbic PinD,PinD3      ;Пропустить если бит в порту очищен
   rjmp GetPinD2

   ser r16
   out PortC,r16

   rjmp Record          ;На запись!!!

GetPinD2:

   rcall Timer

   sbic PinD,PinD2      ;Пропустить если бит в порту очищен
   rjmp GetPin

;***********************************************************
;~Чтение~
;Настройки USART, Передача.
;***********************************************************

   ldi r18,0x00     ;Настраиваем регистры управления
   out UCSRA,r18

   ldi r18,0x08     ;На передачу
   out UCSRB,r18  

   ldi r18,0x86     ;Выбора режима работы, синхр, не синхр
   out UCSRC,r18    ;режим четности/нечетности
                    ;Количество стоп-битов
                    ;настроили на 8 бит, асинхронно

   ldi r18,0x00     ;Выбор скорости
   out UBRRH,r18
   ldi r18,0x07     ;0x07 для 115200
   out UBRRL,r18   
 
;***********************************************************
;Чтение flash 
;***********************************************************

   rcall CheckFlash      ;Проверем готовность

   cbi PortB,0           ;CS=0

   ldi r16, 0x03         ;Команда не прерывного чтения из Flash
   rcall SPI_WR

;***********************************************************

   clr r16
   rcall SPI_WR          ;Адрес, все 0
   clr r16
   rcall SPI_WR
   clr r16
   rcall SPI_WR

;**********************************************************
;Читаем Flash и передаем на комп
;**********************************************************
         
ReadFlash:              

   ldi r16,0             ;Пошлем 0
   rcall SPI_WR

   rcall USART_Transmit  ;Отправляем на комп 
 
   rjmp ReadFlash


;*************************************************************
;Передаем на комп
;*************************************************************

USART_Transmit: 

   sbis UCSRA,UDRE
   rjmp USART_Transmit    ;Ждем очистки буффера передатчика
   out UDR,r16            ;Отправляем данные

   ret




;*************************************************************
;~Запись~
;************************************************************* 

Record:

   ser r16
   out PortC,r16

   rcall EraseChip      ;Полное стирание!

   clr r16
   out PortC,r16

;**************************************************************
;~Запись во Flash~
;Запись в первый буффер
;**************************************************************

WriteFlashNext:      

   rcall CheckFlash      ;Проверем готовность

   cbi PortB,0           ;CS=0

   ldi r16, 0x84         ;Комманда записи в буф1
   rcall SPI_WR

;************** Адрес в буффере *********************************

   clr r16               ;Адрес состоит из 3 байтов
   rcall SPI_WR          ;Пошлем адрес = 0

   clr r16               
   rcall SPI_WR          

   clr r16               
   rcall SPI_WR          

   rcall Send528Bytes    ;Наши 528 байтов

   sbi PortB,0           ;CS=1

;****************************************************************
;Запись во Flash, из первого буфера
;****************************************************************

   rcall CheckFlash      ;Проверем готовность

   cbi PortB,0           ;CS=0

   ldi r16, 0x88         ;Команда записи первого буфера в Flash
   rcall SPI_WR

;**************************************************************
;Счетчик страниц
;**************************************************************

    push ZL                     
    push ZH               ;Сохраним значение регистров 

    lsl ZL                ;Тут будем двигать биты 
    rol ZH                ;На две позиции влево

    lsl ZL                ;Логический сдвиг влево
    rol ZH                ;Циклический сдвиг влево через C

    mov r16,ZH
    rcall SPI_WR          ;Пошлем адрес страницы 

    mov r16,ZL
    rcall SPI_WR

    clr r16
    rcall SPI_WR
  
    pop ZH                ;Восстановим значение счетного 
    pop ZL                ;регистра
  
    cpi ZL,150            ;150 страниц записано?
    breq ExitRec

    ADIW ZL,1             ;Сложить константу и слово
                          ;Увеличим счетчик страниц на 1
    out PortC,ZL          ;Мигаем

    sbi PortB,0           ;CS=1

   rjmp WriteFlashNext  

;**************************************************************

ExitRec:

   sbi PortB,0            ;CS=1
 
   rjmp GetPin
 




;**************************************************************
;Запись 528 байт в буфер
;**************************************************************

Send528Bytes:

   ldi r18,2
  
Next255Bit:

   ser r17
 
BuffWrite:

   ldi r16,'#'
   rcall SPI_WR         ;Шлем по SPI

   dec r17
   brne BuffWrite

   dec r18
   brne Next255Bit      ;Пошлем вторую пачку 255байт

;***************** Пошлем последние 18байтов ******************

   ldi r17,18

SendNext18:

   ldi r16,'!'
   rcall SPI_WR

   dec r17
   brne SendNext18

   ret

;*************************************************************
;Полное стирание чипа
;*************************************************************

EraseChip:

CycleKill:

    rcall CheckFlash      ;Ready!?

    cbi PortB,0           ;CS=0

    ldi r16,0x50          ;Команда стирания блока
    rcall SPI_WR

    push ZL                     
    push ZH               ;Сохраним регистры

    lsl ZL                ;Тут будем двигать биты 
    rol ZH                ;На 5 позиции влево

    lsl ZL                ;Логический сдвиг влево
    rol ZH                ;Циклический сдвиг влево через C

    lsl ZL                
    rol ZH                

    lsl ZL                
    rol ZH                

    lsl ZL               
    rol ZH                

    mov r16,ZH
    rcall SPI_WR          ;Пошлем адрес блока

    mov r16,ZL
    rcall SPI_WR

    clr r16
    rcall SPI_WR
  
    pop ZH                ;Восстановим регистры
    pop ZL                
  
    cpi ZL,255
    breq CheckZH 
  
Exit:

    adiw ZL,1             ;Сложить константу и слово
                          ;Увеличим счетчик блоков на 1

    sbi PortB,0           ;CS=1
  
    rjmp CycleKill

CheckZH:                

    cpi ZH,0b00000001     ;Проверка, все ли блоки стерты
    brne Exit             ;Перейдем если не равно

    sbi PortB,0           ;CS=1

    clr ZL
    clr ZH

    ret


;*************************************************************
;Проверка готовности Flash
;*************************************************************

CheckFlash:

   cbi PortB,0           ;CS=0

   ldi r16, 0xD7         ;Команда чтения статус регистра
   rcall SPI_WR

Read_Status:

   ldi r16,0             ;Пошлем пустую команду
   rcall SPI_WR

   sbrs r16,7            ;Проверяем 7 бит (RDY/BUSY)
   rjmp Read_Status

   sbi PortB,0           ;CS=1

   ret


;*************************************************************
;Передача, Прием по ISP
;*************************************************************

SPI_WR:

   out SPDR,r16   ;Посылаем

Wait:             ;Ждем когда закончится передача

   sbis SPSR,SPIF
   rjmp Wait

   in r16,SPDR    ;Считываем
  
   ret

;*************************************************************

Timer:
          
          ldi r16,0
          ldi r17,0
          ldi r18,8

Loop:     dec r16
          brne loop     ;Перейти если 0

          dec r17
          brne loop    

          dec r18
          brne loop     

          ret









