Сб янв 06, 2018 09:37:02
Сб янв 06, 2018 12:07:47
Сб янв 06, 2018 12:55:36
Сб янв 06, 2018 14:42:39
Сб янв 06, 2018 14:48:02
; i2c_slave implementation
; needs int0
; needs 2 high and 1 low register and one pointer (z)
.include "tn13def.inc"
.equ i2c_pin = PINB
.equ i2c_port = PORTB
.equ i2c_dir = DDRB
;.equ i2c_bitSCL = 0
;.equ i2c_bitSDA = 1
.equ i2c_bitSCL = 2
.equ i2c_bitSDA = 1
.equ i2c_valSCL = 1<<i2c_bitSCL
.equ i2c_valSDA = 1<<i2c_bitSDA
.def i2c_data = r16
.def i2c_state = r17
.def i2c_SREG = r8
.equ i2c_slaveAddr = 0x52
;macros
.macro i2c_waitSCL_low
i2c_waitSCL_low0: sbic i2c_pin, i2c_bitSCL
rjmp i2c_waitSCL_low0
.endm
;macros
.macro i2c_waitSCL_high
i2c_waitSCL_high0: sbis i2c_pin, i2c_bitSCL
rjmp i2c_waitSCL_high0
.endm
.macro i2c_readAddress
; reads the address into @0
; this is shorter than readByte, because we do not need to detect a stop condition
ldi @0, 0x01
i2c_readAddress0:
i2c_waitSCL_high
clc
sbic i2c_pin, i2c_bitSDA
sec
rol @0
i2c_waitSCL_low
brcc i2c_readAddress0
.endm
.macro i2c_readByte ; returns when scl is low, after last bit
; reads one byte into @0
; read the first bit (here could also come a stop condition or a rep-start)
i2c_waitSCL_high
in @0, i2c_pin
andi @0, i2c_valSDA | i2c_valSCL
i2c_readByte2:
in i2c_state, i2c_pin
andi i2c_state, i2c_valSDA | i2c_valSCL
cp i2c_state, @0
breq i2c_readByte2 ; nothing happend
andi i2c_state, i2c_valSCL
breq i2c_readByte3 ; first bit recieved
andi @0, i2c_valSDA
brne i2c_repStart ; rep-start-condition
i2c_return ; stop-condition
i2c_readByte3:
andi @0, i2c_valSDA
breq i2c_readByte4
ldi @0, 0x03
i2c_readByte4:
ori @0, 0x02 ; end-mark for finish
i2c_readByte0:
i2c_waitSCL_high
clc
sbic i2c_pin, i2c_bitSDA
i2c_readByte1:
sec
rol @0
i2c_waitSCL_low
brcc i2c_readByte0
.endm
.macro i2c_writeByte ;returns when scl is low, after last bit
sec
i2c_writeByte0:
rol @0
breq i2c_writeByte3
brcc i2c_writeByte1
cbi i2c_dir, i2c_bitSDA
rjmp i2c_writeByte2
i2c_writeByte1:
sbi i2c_dir, i2c_bitSDA
;rjmp i2c_writeByte2
i2c_writeByte2: ;sda = bit now
i2c_waitSCL_high ; wait one clock pulse
i2c_waitSCL_low
clc
rjmp i2c_writeByte0
i2c_writeByte3: ; transmittion finished
cbi i2c_dir, i2c_bitSDA
.endm
.macro i2c_getAck ; returns when scl is low, after ack
i2c_waitSCL_high
andi @0, 0xFE
sbis i2c_pin, i2c_bitSDA
ori @0, 0x01
i2c_waitSCL_low
.endm
.macro i2c_putAck ; returns if scl is low, after ack
sbi i2c_dir, i2c_bitSDA
i2c_waitSCL_high
i2c_waitSCL_low
cbi i2c_dir, i2c_bitSDA
.endm
.macro i2c_handleInterrupts ; this must be called between a putWaitState and remWaitState
; needs a high register for temporary usage
; remove interrupt-bit from GIFR
ldi @0, 0x40
out GIFR, @0
sei ; switch interrupts to on
nop ; do nothing
nop ; max. number of 2 interrupts
cli ; switch interrupts to off
.endm
.macro i2c_putWaitState
sbi i2c_dir, i2c_bitSCL
.endm
.macro i2c_remWaitState
cbi i2c_dir, i2c_bitSCL
.endm
.macro i2c_putByte ; store a recieved byte, could be a call
; this must be the address -> z-register
mov zl, @0
clr zh
.endm
.macro i2c_getByte ; get a byte for transmittion, could be a call
cpi zl, 10
brlt i2c_getByte0
clr zl
clr zh
i2c_getByte0:
ld @0, z+
.endm
.macro i2c_addressed ; this device has been addressed, could be a call
; and take more than only a few clock cycles
.endm
.macro i2c_return ; return from interrupt, restore SREG, restore Interrupts
ldi i2c_data, 0x40
out GIFR, i2c_data ; clear interrupt flag
out SREG, i2c_SREG
reti
.endm
i2c_int_data:
; only proceed on when start condition happened:
sbis i2c_pin, i2c_bitSCL
reti ; the scl line was low -> normal change of sda line
in i2c_SREG, SREG ; the scl line was high -> start condition detected
i2c_repStart:
i2c_waitSCL_low
; handle the i2c_start_condition
i2c_readAddress i2c_data ; read the address byte
; decode the address
mov i2c_state, i2c_data
andi i2c_state, 0x01
andi i2c_data, 0xFE
cpi i2c_data, i2c_slaveAddr
breq i2c_addressMatch ; if address matches, handle this
i2c_return ; else return and wait for next start condition
i2c_addressMatch:
; this device has been addressed -> give ack
i2c_putAck
i2c_putWaitState
i2c_addressed
rjmp i2c_readNextByte1
;i2c_write: ; master write mode
; i2c_putAck
i2c_readNextByte:
i2c_putWaitState
i2c_readNextByte1:
i2c_handleInterrupts i2c_data ; handle some interrupts if needed
sbrc i2c_state, 0 ; if master-read-mode
rjmp i2c_read ; read the thing
i2c_remWaitState ; remove wait-state
; else master-write
i2c_readByte i2c_data ; read one byte. this must also detect a stop-condition
i2c_putAck ; give the ack
i2c_putWaitState ; put the wait state
i2c_putByte i2c_data ; store the recieved byte internally
i2c_remWaitState
rjmp i2c_readNextByte1 ; and wait for next byte
i2c_read: ; master read mode
i2c_getByte i2c_data ; get the next byte to be read
i2c_remWaitState
i2c_writeByte i2c_data
i2c_getAck i2c_state
sbrc i2c_state, 0
rjmp i2c_readNextByte ; read the next byte
; no more bytes to read, the master didn't acknowled
i2c_return
i2c_init:
; initialize the peripheral
cbi i2c_port, i2c_bitSDA
cbi i2c_port, i2c_bitSCL
cbi i2c_dir, i2c_bitSDA
cbi i2c_dir, i2c_bitSCL
;initialize interrupt
ldi i2c_data, 0x40
out GIMSK, i2c_data
in i2c_data, MCUCR
andi i2c_data, 0xFC
;falling edge of int0
ori i2c_data, 0x02
out MCUCR, i2c_data
ret
Сб янв 06, 2018 15:08:44
Сб янв 06, 2018 15:24:44
Сб янв 06, 2018 21:01:24
Сб янв 06, 2018 22:30:48
Так не бывает. Можно, конечно, циклически опрашивать линию SCL, но тогда контроллер только этим и будет заниматься.
ВСЕ программные реализации slave I2C используют прерывание INT0 (либо INT1) для того, чтобы контроллер мог еще чем-то осмысленным заниматься.
Вс янв 07, 2018 07:31:43
Вс янв 07, 2018 08:21:16
Если Вам надо использовать внешнее прерывание для декодирования манчестера, используйте PCINT0
Вс янв 07, 2018 08:44:58
Вс янв 07, 2018 21:53:37
Вс янв 07, 2018 22:43:42
Пн янв 08, 2018 14:08:03
Пн янв 08, 2018 19:15:33
Пн янв 08, 2018 19:25:39
Пн янв 08, 2018 21:51:14
У меня почему то такая же идея промелькнула и именно про SPI, потому что прост как три копейки.Z_h_e писал(а):Вы можете любой свой протокол придумать
Пн янв 08, 2018 22:51:04
Вт янв 09, 2018 16:27:04