24x01 I2C на ATTINY13 без TWI19.12.2020 15:47
/*
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<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<
© Habrahabr.ru