[Алгоритмы, Производство и разработка электроники] 24x01 I2C на ATTINY13 без TWI
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Казалось бы что тут такого сложного, ну 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
===========
Похожие новости:
- [Производство и разработка электроники] К вопросу о источниках, помехах и импортозамещении
- [Анализ и проектирование систем, Беспроводные технологии, Разработка для интернета вещей, Производство и разработка электроники] Как влияют помехи на ИК приемник
- [Анализ и проектирование систем, CAD/CAM, Производство и разработка электроники, Электроника для начинающих] Анализ целостности сигналов в PADS Professional (4/6)
- [Производство и разработка электроники] Усилитель звукового сигнала мощностью 600 Вт
- [Информационная безопасность, Локализация продуктов, Производство и разработка электроники] Russian microcontroller K1986BK025 based on the RISC-V processor core for smart electricity meters (перевод)
- [Алгоритмы, Производство и разработка электроники, Научно-популярное, Биотехнологии] Электронная амеба и задача коммивояжера
- [Delphi, Алгоритмы, C] Radix sort — выжать всё
- [Производство и разработка электроники, Презентации, Процессоры] Внезапно и неожиданно. Intel может перенести релиз Rocket Lake-S с марта на январь
- [Производство и разработка электроники, Компьютерное железо] Team Group заявила о готовности образцов потребительских модулей памяти DDR5
- [Поисковые технологии, Работа с видео, Алгоритмы, Социальные сети и сообщества] Как я создал собственный алгоритм YouTube (чтобы не тратить время впустую) (перевод)
Теги для поиска: #_algoritmy (Алгоритмы), #_proizvodstvo_i_razrabotka_elektroniki (Производство и разработка электроники), #_attiny13a, #_i2c, #_eeprom, #_assembler, #_algoritmy (
Алгоритмы
), #_proizvodstvo_i_razrabotka_elektroniki (
Производство и разработка электроники
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 19:57
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Казалось бы что тут такого сложного, ну I2C ну без TWI.Моя реальная задача обстояла чуть шире, в устройстве устанавливался чип в режиме "Reset" контроллера, для экономии места в программируемой логике, задача этого чипа состояла в том чтобы получив на входе короткий импульс как сигнал к началу генерации "длинного" сброса, чип удерживал одну из линий в течении довольно длительного промежутка времени в низком уровне (в программируемой логике можно было сделать цепочку из триггеров в качестве счетчика, но линейка триггеров занимала почти 80 ячеек в CPLD EPM240T100 и место там ой как нужно) к тому же этот чип должен был хранить данные полученный от внешнего устройства по шине I2C в режиме 1 (mode1).Вообще существует три режима I2C, 2-ой и 3-ий режимы рассчитаны на то что на шине I2C висит гирлянда из устройств, таким образом прежде чем начать работать с устройством на шине в режиме 2 и 3 нужно сначала выбрать устройство, затем уже отправлять в него адреса и данные. Режим 1 это простейший режим работы I2C, пользователь сразу отправляет в чип адрес по которому необходимо записать или прочитать данные и работает с данными.Вот собственно о чем я говорю (MODE1): А это MODE2: В общем-то тут всё итак понятно, но! Здесь есть три задачи:
В общем я так понимаю зачастую лирика мало кого интересует, тут CTRC+C и CTRL+V чаще применяется, поэтому выкладываю уже код.Только сперва Коментарии:
Загружаем откомпилированную программу (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 =========== Похожие новости:
Алгоритмы ), #_proizvodstvo_i_razrabotka_elektroniki ( Производство и разработка электроники ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 19:57
Часовой пояс: UTC + 5