[Алгоритмы, Производство и разработка электроники] 24x01 I2C на ATTINY13 без TWI

Автор Сообщение
news_bot ®

Стаж: 6 лет 9 месяцев
Сообщений: 27286

Создавать темы news_bot ® написал(а)
19-Дек-2020 16:31

Казалось бы что тут такого сложного, ну I2C ну без TWI.Моя реальная задача обстояла чуть шире, в устройстве устанавливался чип в режиме "Reset" контроллера, для экономии места в программируемой логике, задача этого чипа состояла в том чтобы получив на входе короткий импульс как сигнал к началу генерации "длинного" сброса, чип удерживал одну из линий в течении довольно длительного промежутка времени в низком уровне (в программируемой логике можно было сделать цепочку из триггеров в качестве счетчика, но линейка триггеров занимала почти 80 ячеек в CPLD EPM240T100 и место там ой как нужно) к тому же этот чип должен был хранить данные полученный от внешнего устройства по шине I2C в режиме 1 (mode1).Вообще существует три режима I2C, 2-ой и 3-ий режимы рассчитаны на то что на шине I2C висит гирлянда из устройств, таким образом прежде чем начать работать с устройством на шине в режиме 2 и 3 нужно сначала выбрать устройство, затем уже отправлять в него адреса и данные. Режим 1 это простейший режим работы I2C, пользователь сразу отправляет в чип адрес по которому необходимо записать или прочитать данные и работает с данными.Вот собственно о чем я говорю (MODE1):
А это MODE2:
В общем-то тут всё итак понятно, но! Здесь есть три задачи:
  • В ATTINY13 нет аппаратного I2C.
  • Чип должен выполнять ещё и сброс (хотя для данной статьи это не особо важно).
  • И финальная проблема 24x01 предполагает объем EEP 128 байт, а в данном чипе EEPROM объемом только 64 байта.
Первая проблема ставит задачу реализации протокола, в том числе отслеживание ошибок на шине, кодом, - тут для нас ассемблер, вторая задача это не особо сложная реализация алгоритма сброса, а вот третья задача выглядит чуть сложнее. Теоретически мы можем задействовать часть памяти FLASH не занятой нашей реализацией, но EEPROM можно писать побайтно, а FLASH только страницами, поэтому прежде чем записать во FLASH полученные данные я обязан сохранить состав всей страницы в памяти микроконтроллера, "подменить" полученные данные внутри страничного буфера, стереть страницу, записать новый состав страницы. При этом запись может попасться в смежные страницы, то есть на стыках. Таким образом я должен произвести запись в два этапа:
В общем я так понимаю зачастую лирика мало кого интересует, тут CTRC+C и CTRL+V чаще применяется, поэтому выкладываю уже код.Только сперва Коментарии:
  • CHIP_PINOUTS - Как расположить выводы на чипе (FT24Cxx - стандартная раскладка чипа I2C, InDRIVE_v4 - раскладка под реализацию с контроллером сброса).
  • I2C_MODE - Режим работы I2C (MODE_1 и MODE_2).
  • I2CPAGESIZE - размер страницы I2C при страничном режиме записи.
  • I2CEEPSIZE - общий объем памяти чипа (реализация в коде сначала использует 64 байта EEPROM, затем растягивает "остатки" во FLASH).
  • RESET_CNT - наличие контроллера сброса (ON - присутствует, OFF - отсутствует).
Собственно перейдем к проверке, достаем TLL866
Загружаем откомпилированную программу (AVR Studio v4), я пролистал в конец чтобы показать состав "псевдо EEP":
Ставим правильные конфигурационные биты и записываем микропрограмму в нашу ATTINY13:
Ага, а теперь не извлекая чип пишем его в режиме I2C EEPROM Mode1 с проверкой:
Работает. Что и требовалось.Код I2C EEP для ATTINY13
/*
  InDRIVE v4 Application (chip like: FT24C01, Selfprg Must Be Enabled!!! )
  Fuse BYTES
  Low(0x7A) :     High(0xEE) :
  SPIEN = 1    SELFPRGEN = 1
  EESAVE = 0    DWEN = 0
  WDTON = 0    BODLEVEL1 = 0
  CKDIV8 = 0    BODLEVEL0 = 0
  SUT1 = 0    RSTDISBL = 1
  SUT0 = 1
  CKSEL1 = 0
  CKSEL0 = 1
*/
.include "tn13def.inc"
/* On/Off Defines */
.equ  OFF      =0
.equ  ON      =1
/* Chip Pinouts */
.equ  FT24Cxx    =0
.equ  InDRIVE_v4  =1
/* Reset Controller Enable/Disable */
.equ  RESET_CNT  =OFF
/* Chip Pinouts Define: InDrivev4/Regular I2C Chip */
.equ  CHIP_PINOUTS  =FT24Cxx
.equ  DEBUG    =OFF
/* I2C Mode Define MODE 1/MODE 2 */
.equ  MODE_1    =1
.equ  MODE_2    =2
.EQU  I2C_MODE  =MODE_1
/* Define I2C Parameters */
/* Page Size for Write in BYTES 4/8/16 */
/* 128/256 Size in MODE 1 Protocol can't receive more than 128 Bytes */
.IF I2C_MODE == MODE_2
  .MESSAGE "Compile for I2C Mode 2"
.equ  I2C_PAGE_SIZE  =8
.equ  I2C_EEP_SIZE  =256
.ELSE
  .MESSAGE "Compile for I2C Mode 1"
.equ  I2C_PAGE_SIZE  =4
.equ  I2C_EEP_SIZE  =128
.ENDIF
/*
Modes Define
  A - Address
  iD - Data From Master
  oD - Data To Master
  MODE 1
    Write - [START][AAAAAAA0][iD + 0]...[iD + I2C_PAGE_SIZE - 1][STOP]
    Read -  [START][AAAAAAA1][oD + 0]...[oD + I2C_EEP_SIZE - 1][STOP]
  MODE 2
    Write - [START][10100000][AAAAAAAA][iD + 0]...[iD + I2C_PAGE_SIZE - 1][STOP]
    Read -  [START][10100001][oD + 0]...[oD + I2C_EEP_SIZE - 1][STOP]
*/
/*
  I2C slave, fSCL = 400kHz
  FULLY Implemented I2C Protocol for 24xx01/24xx02
  And RESET Controller FOR InDRIVE(v4)
**************************************************************
  ATTINY13A I2C Configuration
**************************************************************
     pin configuration InDRIVE v4:
                       ,---_---.
    (RESET/PB5)     nc |1     8| VCC
          (PB3)  inRST |2     7| SCL    (PB2)
          (PB4) outRST |3     6| EMU24X (PB1) SDA pin from CORE
                   GND |4     5| nc   (PB0) unused SDA pin
                       `-------'
     pin configuration FT24C01:
                       ,---_---.
    (RESET/PB5)     nc |1     8| VCC
            (PB3)    nc |2     7| nc    (PB2)
            (PB4)   nc |3     6| SCL   (PB1) SCL pin I2C
                   GND |4     5| SDA   (PB0) SDA pin I2C
                       `-------'
     pin configuration FT24C02:
                       ,---_---.
    (RESET/PB5)     A0 |1     8| VCC
            (PB3)    A1 |2     7| nc    (PB2)
            (PB4)   A2 |3     6| SCL   (PB1) SCL pin I2C
                   GND |4     5| SDA   (PB0) SDA pin I2C
                       `-------'
*/
/* Pins Define */
.IF CHIP_PINOUTS == InDRIVE_v4
  .MESSAGE "Chip Pinouts: InDRIVE v4"
.equ  EMU24X  = 1
.equ   SCL   = 2
.ELSE
.equ  EMU24X  = 0
.equ   SCL   = 1
  .MESSAGE "Chip Pinouts: Regular 24Cxx"
.ENDIF
.equ   SDA   = EMU24X
.equ   ACK   = SDA
.equ  inRST  = 3
.equ  outRST  = 4
.def  TMPnoINT    =R19
.def  Counter      =R3
.def  CounterInWrite  =R4
.def  SREGST      =R5
/* Real ATTINY13A FLASH Page SIZE In Bytes */
.equ  PAGESIZEB    =(PAGESIZE*2)
/* SRAM Mapping */
.DSEG
.IF I2C_MODE == MODE_2
  _I2c_device_inaddr:  .BYTE 1  /* MODE 2 Region */
  _I2c_device_myaddr:  .BYTE 1
.ENDIF
  _valSPMCSR: .BYTE 1
  _I2c_data_buffer:  .BYTE I2C_PAGE_SIZE
  _I2c_FLASH_buffer:  .BYTE PAGESIZEB
.cseg
/* Read/Write Pointers */
.def  I2c_start_addr  =R16
.def  I2c_wr_counter  =R17
.def  I2c_wr_pointer  =R18
.def  I2c_rd_pointer  =R21
.def  _PINB      =R20
.IF I2C_MODE != MODE_2
  .IF I2C_MODE != MODE_1
    .error "Invalid mode for I2C Selected, please correct I2C_MODE define"
  .ENDIF
.ENDIF
.cseg
.org 0//Reset
.IF RESET_CNT == ON
    rjmp  WaitinRSTHI    ;RESET
    reti          ;INT0addr  = 0x0001  ; External Interrupt 0
    rjmp  ResetInProcess  ;PCI0addr  = 0x0002  ; External Interrupt Request 0
.ELSE
    rjmp  main      ;RESET
    reti          ;INT0addr  = 0x0001  ; External Interrupt 0
    reti          ;PCI0addr  = 0x0002  ; External Interrupt Request 0
.ENDIF
    reti          ;OVF0addr  = 0x0003  ; Timer/Counter0 Overflow
    reti          ;ERDYaddr  = 0x0004  ; EEPROM Ready
    reti          ;ACIaddr  = 0x0005  ; Analog Comparator
    reti          ;OC0Aaddr  = 0x0006  ; Timer/Counter Compare Match A
    reti          ;OC0Baddr  = 0x0007  ; Timer/Counter Compare Match B
    reti          ;WDTaddr  = 0x0008  ; Watchdog Time-out
    reti          ;ADCCaddr  = 0x0009  ; ADC Conversion Complete
// *******************************************************************************************
// **   Reset Processor                                                               **
// *******************************************************************************************
.IF RESET_CNT == ON
  .MESSAGE "Reset Controller Function is: ON"
ResetInProcess:  ;Proccess reset
    sbic  pinb,inRST  ;Process reset on falling edge
    reti
WaitinRSTHI:
    cli
    ;Wait ~80 mS 0x04E360 on 9.6MHz
    ldi    R16,0x10
    ldi    R17,0xE3
    ldi    R18,0x60
    ;Set RESET Enable
    cbi    PORTB,outRST
_CntLO:
    dec    R18
    BRNE  _CntLO
_CntME:
    dec    R17
    BRNE  _CntLO
_CntHI:
    dec    R16
    BRNE  _CntLO
    ; And Clear Iterrupt flag for normal exit
    ldi    R16,(1 << PCIF)
    out    GIFR,R16
.ELSE
  .MESSAGE "Reset Controller Function is: OFF"
.ENDIF  // RESET_CNT == ON
// *******************************************************************************************************
// **   Main Programm                                                                 **
// *******************************************************************************************************
main:
    ;init STACK
    ldi    TMPnoINT,low(RAMEND)
    out    SPL,TMPnoINT
    ;init IO
    ldi    TMPnoINT,0x00
    out    MCUCR,TMPnoINT
    ;Outputs to HI (Pull UP)
    ldi    TMPnoINT,0xFF
    out    PORTB,TMPnoINT
.IF RESET_CNT == ON
    ;Output enable for outRST, all other for input
    sbi    PORTB, outRST
    sbi    PINB, inRST
    sbi    DDRB,outRST  ; Output Enable
    ;Init Interrupt
      ldi   TMPnoINT, (1 << inRST)  ; set pin change interrupt for inRST
      out   PCMSK, TMPnoINT
    ldi    TMPnoINT, (1<<PCIE)    ; unmask interrupt PCIE
    out    GIMSK,TMPnoINT
    SEI          ;Enable PCIE Int Processing
.ELSE
    CLI    ; Disable Reset Controller
.ENDIF
.IF I2C_MODE == MODE_2
    /* Set I2C Device Address */
    ldi    TMPnoINT, 0xA0
    sts    _I2c_device_myaddr,TMPnoINT
.ENDIF
    /* Clear Buffer Pointers */
    clr    I2c_wr_counter
    clr    I2c_wr_pointer
    clr    I2c_start_addr
    clr    I2c_rd_pointer
main_loop:
lI2c_get:
  sbi portb,ack
  sbis pinb,scl                                            ;wait for SCL&SDA=1
  rjmp lI2c_get
  sbis pinb,sda
  rjmp lI2c_get
lI2c_wait_for_start:
  sbis pinb,scl                                            ;wait for SCL=1,SDA=0 (START)
  rjmp lI2c_get
  sbic pinb,sda
  rjmp lI2c_wait_for_start
lI2c_get_0:                                                  ;clear receive area
.IF I2C_MODE == MODE_2
  clr r22
  sts _I2c_device_inaddr,r22
.ENDIF
lI2c_get_1:                                                  ;get 1st byte
  sbi portb,ack
lI2c_10:                                                     ;wait for SCL=0
  sbic pinb,scl
  rjmp lI2c_10
  ldi r22,8                                                ;bits to receive=8
.IF I2C_MODE == MODE_2
  lds r23,_I2c_device_myaddr                               ;I2C address->R23
.ENDIF
lI2c_11:
  in  _PINB, pinb
  sbrs _PINB,scl                                            ;wait for SCL=1
  rjmp lI2c_11
  sbrc _PINB,sda
  rjmp lI2c_13
lI2c_12:                                                     ;if SDA=0
  sbic pinb,sda
  rjmp lI2c_wait_for_start                                  ;  SDA 0->1? I2CSTOP! (unexpected: wait for next start)
  sbic pinb,scl
  rjmp lI2c_12                                              ;  loop while SCL=1
  clc                                                      ;  SDA=0->C
  rjmp lI2c_15
lI2c_13:                                                     ;if SDA=1
  sbis pinb,sda
  rjmp lI2c_get_1                                           ;  SDA 1->0? I2CSTART! (repeated start)
  sbic pinb,scl
  rjmp lI2c_13                                              ;  loop while SCL=1
  sec                                                      ;  SDA=1->C
lI2c_15:
  rol r24
  dec r22
  brne lI2c_11                                              ;loop to next bit
.IF I2C_MODE == MODE_2
  sts _I2c_device_inaddr,r24
  SUB r24,r23                                              ;my address?
  cpi r24,2
  brlo lI2c_ack_1
  rjmp lI2c_exit                                            ;  no: exit and wait for next start
.ENDIF
lI2c_ack_1:                                                  ;  yes: generate ack
  clr    I2c_wr_counter                ; Clear Write Buffer Pointers
  clr    I2c_wr_pointer
  clr    I2c_start_addr
  cbi portb,ack
  sbi ddrb,ack                                             ;pinb.ack = output (ACK)
lI2c_ack_10:
  sbis pinb,scl                                            ;wait for SCL=1
  rjmp lI2c_ack_10
lI2c_ack_11:
  sbic pinb,scl                                            ;wait for SCL=0
  rjmp lI2c_ack_11
/*************************************************************************
*    Select Read/Write
**************************************************************************/
.IF I2C_MODE == MODE_2
  cpi r24,0
  breq lI2c_get_2
.ELSE
  mov  I2c_start_addr,r24        ; Extract Received Address
  lsr I2c_start_addr          ; And Read/Write BIT
  mov I2c_rd_pointer,I2c_start_addr  ; Upadate Read Address
  brcs lI2c_send_new_byte
  rjmp  lI2c_ack_25
.ENDIF
/*************************************************************************
*    Sending Data to Master
**************************************************************************/
lI2c_send_new_byte:                                             ;read address received
  sbi ddrb,sda                                             ;pinb.sda = output (will send data)
/* Read From Flash */
  andi I2c_rd_pointer, (I2C_EEP_SIZE - 1)
  LDI  ZH,high(MemoryBlockFLASH<<1)
  LDI  ZL,low(MemoryBlockFLASH<<1)
  add ZL,I2c_rd_pointer
  inc I2c_rd_pointer
  lpm  R24, Z
  ldi r22,8
.IF DEBUG == 1
  rjmp lI2c_s1
/* Read From SRAM */
ReadFromSram:
  andi I2c_rd_pointer, (I2C_EEP_SIZE - 1)
  LDI  ZH,high(_I2c_device_inaddr)
  LDI  ZL,low(_I2c_device_inaddr)
  add ZL,I2c_rd_pointer
  inc I2c_rd_pointer
  ld  R24, Z
  ldi r22,8
.ENDIF
lI2c_s1:
  cbi portb,sda
  sbrc r24,7
  sbi portb,sda
lI2c_s2:
  sbis pinb,scl                                            ;wait for SCL=1
  rjmp lI2c_s2
  lsl r24
lI2c_s3:
  sbic pinb,scl                                            ;wait for SCL=0
  rjmp lI2c_s3
  dec r22
  brne lI2c_s1
  sbi portb,sda                                            ;pinb.sda = 0 (will generate ACK)
  cbi ddrb,sda                                             ;pinb.sda = input (will receive data)
lI2c_s4:                                                  ;wait acknowloge receive
  sbis pinb,scl                                            ;wait for SCL=1
  rjmp lI2c_s4
lI2c_s5:
  sbic pinb,scl                                            ;wait for SCL=0
  rjmp lI2c_s5
  sbis pinb,sda                      ;if answer received, - continue
  rjmp  lI2c_send_new_byte
  rjmp lI2c_wait_for_start_stop                             ;wait for next start/stop
/*************************************************************************
*    Receiving Data from Master
**************************************************************************/
.IF I2C_MODE == MODE_2
lI2c_get_2:                                                  ;write address received: get 2nd byte
  cbi ddrb,ack                                             ;pinb.ack = output (ACK)
lI2c_20:                                                     ;wait for SCL=0
  sbic pinb,scl
  rjmp lI2c_20
  ldi r22,8                                                ;bits to receive=8
lI2c_21:
  sbis pinb,scl                                            ;wait for SCL=1
  rjmp lI2c_21
  sbic pinb,sda
  rjmp lI2c_23
lI2c_22:                                                     ;if SDA=0
  sbic pinb,sda
  rjmp lI2c_stop                                            ;  SDA 0->1? I2CSTOP! (finish this sequence)
  sbic pinb,scl
  rjmp lI2c_22                                              ;  loop while SCL=1
  clc                                                      ;  SDA=0->C
  rjmp lI2c_25
lI2c_23:                                                     ;if SDA=1
  sbis pinb,sda
  rjmp lI2c_get_1                                           ;  SDA 1->0? I2CSTART! (repeated start)
  sbic pinb,scl
  rjmp lI2c_23                                              ;  loop while SCL=1
  sec                                                      ;  SDA=1->C
lI2c_25:
  rol r24
  dec r22
  brne lI2c_21                                              ;loop to next bit
  mov I2c_start_addr,r24                                         ;store received I2C address
  mov I2c_rd_pointer,I2c_start_addr            ; Upadate Read Address
.ENDIF
ReceiveAcknowloge:
  cbi  portb,sda
  sbi  ddrb,sda
lI2c_ack_21:
  sbis pinb,scl                                            ;wait for SCL=1
  rjmp lI2c_ack_21
  sbic pinb,sda
  rjmp lI2c_ack_23
lI2c_ack_22:                                                     ;if SDA=0
  sbic pinb,sda
  rjmp lI2c_stop                                            ;  SDA 0->1? I2CSTOP! (finish this sequence)
  sbic pinb,scl
  rjmp lI2c_ack_22                                              ;  loop while SCL=1
  rjmp lI2c_ack_25
lI2c_ack_23:                                                     ;if SDA=1
  sbis pinb,sda
  rjmp lI2c_get_1                                           ;  SDA 1->0? I2CSTART! (repeated start)
  sbic pinb,scl
  rjmp lI2c_ack_23                                              ;  loop while SCL=1
lI2c_ack_25:
  cbi ddrb,ack                                             ;pinb.ack = input
  LDI  ZH,high(_I2c_data_buffer)
  LDI  ZL,low(_I2c_data_buffer)
lI2c_get_3:                                                  ;get 3rd byte
lI2c_30:                                                     ;wait for SCL=0
  sbic pinb,scl
  rjmp lI2c_30
  ldi r22,8                                                ;bits to receive=8
  mov  TMPnoINT, I2c_wr_pointer
  andi TMPnoINT, (I2C_PAGE_SIZE - 1)
  add ZL,TMPnoINT
lI2c_31:
  sbis pinb,scl                                            ;wait for SCL=1
  rjmp lI2c_31
  sbic pinb,sda
  rjmp lI2c_33_
lI2c_32:                                                     ;if SDA=0
  sbic pinb,sda
  rjmp lI2c_stop_                                            ;  SDA 0->1? I2CSTOP! (finish this sequence)
  sbic pinb,scl
  rjmp lI2c_32                                              ;  loop while SCL=1
  clc                                                      ;  SDA=0->C
  rjmp lI2c_35
lI2c_33_:
lI2c_33:                                                     ;if SDA=1
  sbis pinb,sda
  rjmp lI2c_start_                                           ;  SDA 1->0? I2CSTART! (repeated start)
  sbic pinb,scl
  rjmp lI2c_33                                              ;  loop while SCL=1
  sec                                                      ;  SDA=1->C
lI2c_35:
  rol r24
  dec r22
  brne lI2c_31                                              ;loop to next bit
  inc I2c_wr_counter
  inc I2c_wr_pointer
  inc I2c_rd_pointer
  st  Z,R24
  rjmp ReceiveAcknowloge
lI2c_wait_for_start_stop:                                    ;wait for start/stop
lI2c_ss_1:
  sbis pinb,scl                                            ;wait for SCL=1
  rjmp lI2c_ss_1
  sbic pinb,sda
  rjmp lI2c_ss_3
lI2c_ss_2:                                                   ;if SDA=0
  sbic pinb,sda
  rjmp lI2c_stop                                            ;  SDA 0->1? I2CSTOP! (finish this sequence)
  sbic pinb,scl
  rjmp lI2c_ss_2                                            ;  loop while SCL=1
  rjmp lI2c_ss_1
lI2c_ss_3:                                                   ;if SDA=1
  sbis pinb,sda
  rjmp lI2c_get_1                                           ;  SDA 1->0? I2CSTART! (repeated start)
  sbic pinb,scl
  rjmp lI2c_ss_3                                            ;  loop while SCL=1
  rjmp lI2c_ss_1                                            ;  SDA=1->C
lI2c_stop_:
lI2c_stop:                                                   ;if stop,
  cbi  ddrb, sda
  cpi  I2c_wr_counter,0x00
  brne WriteFlashRom
lI2c_exit:
  rjmp lI2c_get
lI2c_start_:
  rjmp lI2c_get_1
WriteFlashRom:
  cli              ; Disable INTERRUPTS
  rcall WriteReceivedData
  clr    I2c_wr_counter                ; Clear Write Buffer Pointers
  clr    I2c_wr_pointer
  sei              ; Enable INTERRUPTS
  rjmp lI2c_get
/***********************************************************
*       Write internal FLASH by page
************************************************************/
//--------- Erase/Program Page FROM FLASH to SRAM
BackupFlashPage:
  ldi    YH,high(_I2c_FLASH_buffer) ; Load SRAM Buffer
  ldi    YL,low(_I2c_FLASH_buffer)
  mov    TMPnoINT, I2c_start_addr
  andi  TMPnoINT, ((I2C_EEP_SIZE - 1) & ~(PAGESIZEB - 1))
  ldi    ZH,high(MemoryBlockFLASH << 1)
  ldi    ZL,low(MemoryBlockFLASH << 1)
  adc    ZL,TMPnoINT
  brcc  NoIncBackupPage
  inc    ZH
NoIncBackupPage:
  ldi    R22, PAGESIZEB
BackupPageLoop:
  lpm    TMPnoINT,Z+
  st    Y+,TMPnoINT
  dec    R22
  brne  BackupPageLoop
  ret
//--------- Add received data to SRAM Page
WriteReceivedData:
  /* Have Data For Write ? */
  cpi    I2c_wr_counter,0x00
  brne  DataForWritePresent
  ret
DataForWritePresent:
  rcall BackupFlashPage
  ldi    YH,high(_I2c_FLASH_buffer) ; Load SRAM Backup Buffer Address
  ldi    YL,low(_I2c_FLASH_buffer)
  ldi    XH,high(_I2c_data_buffer) ; Load SRAM Receive Buffer Address
  ldi    XL,low(_I2c_data_buffer)
  mov    TMPnoINT, I2c_start_addr
  andi  TMPnoINT, (PAGESIZEB - 1)
  adc    YL,TMPnoINT
  brcc  NoIncPreparePage
  inc    YH
NoIncPreparePage:
  mov    CounterInWrite,TMPnoINT
  /* Make PAGE SIZE Window */
  cpi    I2c_wr_counter, I2C_PAGE_SIZE
  brlo  PreparePageLoop
  ldi    I2c_wr_counter, I2C_PAGE_SIZE
PreparePageLoop:
  ld    R22,X+
  st    Y+,R22
  dec    I2c_wr_counter
  breq  NormalPageWrite
  mov    TMPnoINT,CounterInWrite
  cpi    TMPnoINT, (PAGESIZEB - 1)
  brne  NoWritePageSizeExceeded
  rcall  Erase_page_by_SPM
  rcall  Write_Current_Page
  inc    CounterInWrite
  inc    I2c_start_addr
  dec    I2c_wr_pointer
  rjmp  WriteReceivedData
NoWritePageSizeExceeded:
  inc    CounterInWrite
  inc    I2c_start_addr
  dec    I2c_wr_pointer
  rjmp  PreparePageLoop
NormalPageWrite:
  rcall  Erase_page_by_SPM
  rcall  Write_Current_Page
  inc    I2c_start_addr
  dec    I2c_wr_pointer
  ret
//--------- Erase page
Erase_page_by_SPM:
  ldi    ZH,high(MemoryBlockFLASH << 1)
  ldi    ZL,low(MemoryBlockFLASH << 1)
  mov    TMPnoINT,I2c_start_addr
  andi   TMPnoINT, ((I2C_EEP_SIZE - 1) & ~(PAGESIZEB - 1)) /* Mask Maximum Data Size and Mask Out Real Flash Page Size */
  adc    ZL,TMPnoINT
  brcc  NoIncErasePage
  inc    ZH
NoIncErasePage:
  /* Load Erase Instruction */
  ldi    TMPnoINT, (1<<PGERS) | (1<<SPMEN)
  sts    _valSPMCSR, TMPnoINT
  rcall  Wait_spm  ;CPU Halted while erase
  ret
//Wite page
Write_Current_Page:
  ldi    XH,high(_I2c_FLASH_buffer) ; Load SRAM Backup Buffer Address
  ldi    XL,low(_I2c_FLASH_buffer)
  ldi    ZH,high(MemoryBlockFLASH << 1)
  ldi    ZL,low(MemoryBlockFLASH << 1)
  mov    TMPnoINT,I2c_start_addr
  andi   TMPnoINT, ((I2C_EEP_SIZE - 1) & ~(PAGESIZEB - 1)) /* Mask Maximum Data Size and Mask Out Real Flash Page Size */
  adc    ZL,TMPnoINT
  brcc  NoIncWritePage
  inc    ZH
NoIncWritePage:
  ldi    TMPnoINT, (PAGESIZE)
  mov    Counter, TMPnoINT
  movw  Y,Z      ; Store Z in Y reg
  clr    ZL      ;Clear Z
  clr    ZH
Fill_Page_Buffer_loop:
  ld    R0, X+
  ld    R1, X+
  ldi    TMPnoINT, (1<<SPMEN)  ;Write word into page buffer
  sts    _valSPMCSR, TMPnoINT
  rcall  Wait_spm  ;CPU Halted while erase
  adiw  Z, 2
  dec    Counter
  brne  Fill_Page_Buffer_loop
  movw  Z,Y      ; Restore Z from Y reg
  ldi   TMPnoINT, (1<<PGWRT) | (1<<SPMEN)
  sts    _valSPMCSR, TMPnoINT
  rcall  Wait_spm  ;CPU Halted while erase
  ret
Do_spm:
; check for previous SPM complete
Wait_spm:
  in  TMPnoINT, SPMCSR
  sbrc TMPnoINT, SPMEN
  rjmp Wait_spm
Wait_ee:
  sbic EECR, EEWE
  rjmp Wait_ee
; SPM timed sequence
  lds  TMPnoINT, _valSPMCSR
  out SPMCSR, TMPnoINT
  spm
  ret
.cseg
.org  (0x200 - (I2C_EEP_SIZE/2))
MemoryBlockFLASH:          ; Bytes in Flash
   .DB 0x55, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
   .DB 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
   .DB 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F
   .DB 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F
   .DB 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F
   .DB 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F
   .DB 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F
   .DB 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D
   ; Mark End of EEP DATA
.org  (0x1FF)
  .db 0x7E,0x7F
.MESSAGE "I2C For Read/Write Processing SELFPRGEN FUSE Must Be Enabled!!!"
.eseg
MemoryBlockEEP:          ; Bytes in EEP
   .DB 0x55, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
   .DB 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
   .DB 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F
   .DB 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F
Всем добра и успехов!!!Спасибо за внимание.
===========
Источник:
habr.com
===========

Похожие новости: Теги для поиска: #_algoritmy (Алгоритмы), #_proizvodstvo_i_razrabotka_elektroniki (Производство и разработка электроники), #_attiny13a, #_i2c, #_eeprom, #_assembler, #_algoritmy (
Алгоритмы
)
, #_proizvodstvo_i_razrabotka_elektroniki (
Производство и разработка электроники
)
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 22-Ноя 19:57
Часовой пояс: UTC + 5