MNT Reform: Open Source Portable Computer https://mntre.com/reform
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

336 lines
9.4KB

  1. ;*************************************************************************
  2. ; Title : I2C (Single) Master Implementation
  3. ; Author: Peter Fleury <pfleury@gmx.ch>
  4. ; based on Atmel Appl. Note AVR300
  5. ; File: $Id: i2cmaster.S,v 1.13 2015/09/16 11:21:00 peter Exp $
  6. ; Software: AVR-GCC 4.x
  7. ; Target: any AVR device
  8. ;
  9. ; DESCRIPTION
  10. ; Basic routines for communicating with I2C slave devices. This
  11. ; "single" master implementation is limited to one bus master on the
  12. ; I2C bus.
  13. ;
  14. ; Based on the Atmel Application Note AVR300, corrected and adapted
  15. ; to GNU assembler and AVR-GCC C call interface
  16. ; Replaced the incorrect quarter period delays found in AVR300 with
  17. ; half period delays.
  18. ;
  19. ; USAGE
  20. ; These routines can be called from C, refere to file i2cmaster.h.
  21. ; See example test_i2cmaster.c
  22. ; Adapt the SCL and SDA port and pin definitions and eventually
  23. ; the delay routine to your target !
  24. ; Use 4.7k pull-up resistor on the SDA and SCL pin.
  25. ;
  26. ; NOTES
  27. ; The I2C routines can be called either from non-interrupt or
  28. ; interrupt routines, not both.
  29. ;
  30. ;*************************************************************************
  31. #include <avr/io.h>
  32. #undef SCL_PORT
  33. #undef SCL_DDR
  34. ;******----- Adapt these SCA and SCL port and pin definition to your target !!
  35. ;
  36. #define SDA 1 // SDA Port D, Pin 4
  37. #define SCL 2 // SCL Port D, Pin 5
  38. #define SDA_PORT PORTB // SDA Port D
  39. #define SCL_PORT PORTB // SCL Port D
  40. ;******----------------------------------------------------------------------
  41. ;-- map the IO register back into the IO address space
  42. #define SDA_DDR (_SFR_IO_ADDR(SDA_PORT) - 1)
  43. #define SCL_DDR (_SFR_IO_ADDR(SCL_PORT) - 1)
  44. #define SDA_OUT _SFR_IO_ADDR(SDA_PORT)
  45. #define SCL_OUT _SFR_IO_ADDR(SCL_PORT)
  46. #define SDA_IN (_SFR_IO_ADDR(SDA_PORT) - 2)
  47. #define SCL_IN (_SFR_IO_ADDR(SCL_PORT) - 2)
  48. #ifndef __tmp_reg__
  49. #define __tmp_reg__ 0
  50. #endif
  51. .section .text
  52. ;*************************************************************************
  53. ; delay half period
  54. ; For I2C in normal mode (100kHz), use T/2 > 5us
  55. ; For I2C in fast mode (400kHz), use T/2 > 1.25us
  56. ;*************************************************************************
  57. .stabs "",100,0,0,i2c_delay_T2
  58. .stabs "i2cmaster.S",100,0,0,i2c_delay_T2
  59. .func i2c_delay_T2 ; delay 5.0 microsec with 4 Mhz crystal
  60. i2c_delay_T2: ; 3 cycles
  61. #if F_CPU <= 4000000UL
  62. rjmp 1f ; 2 "
  63. 1: rjmp 2f ; 2 "
  64. 2: rjmp 3f ; 2 "
  65. 3: rjmp 4f ; 2 "
  66. 4: rjmp 5f ; 2 "
  67. 5: rjmp 6f ; 2 "
  68. 6: nop ; 1 "
  69. ret ; 4 " total 20 cyles = 5.0 microsec with 4 Mhz crystal
  70. #elif F_CPU <= 8000000UL
  71. push r24 ; 2 cycle
  72. ldi r24, 7 ; 1 cycle
  73. nop ; 1 cycle
  74. 1: sbiw r24, 1 ; 2 cycle
  75. brne 1b ; 2 or 1 cycle, 4 cycles per loop
  76. pop r24 ; 2 ycle
  77. ret ; 4 cycle = total 60 cycles = 5.0 microsec with 12 Mhz crystal
  78. #elif F_CPU <= 12000000UL
  79. push r24 ; 2 cycle
  80. ldi r24, 12 ; 1 cycle
  81. nop ; 1 cycle
  82. 1: sbiw r24, 1 ; 2 cycle
  83. brne 1b ; 2 or 1 cycle, 4 cycles per loop
  84. pop r24 ; 2 ycle
  85. ret ; 4 cycle = total 60 cycles = 5.0 microsec with 12 Mhz crystal
  86. #elif F_CPU <= 16000000UL
  87. push r24 ; 2 cycle
  88. ldi r24, 17 ; 1 cycle
  89. nop ; 1 cycle
  90. 1: sbiw r24, 1 ; 2 cycle
  91. brne 1b ; 2 or 1 cycle, 4 cycles per loop
  92. pop r24 ; 2 ycle
  93. ret ; 4 cycle = total 80 cycles = 5.0 microsec with 16 Mhz crystal
  94. #else
  95. push r24 ; 2 cycle
  96. ldi r24, 22 ; 1 cycle
  97. nop ; 1 cycle
  98. 1: sbiw r24, 1 ; 2 cycle
  99. brne 1b ; 2 or 1 cycle, 4 cycles per loop
  100. pop r24 ; 2 ycle
  101. ret ; 4 cycle = total 100 cycles = 5.0 microsec with 20 Mhz crystal
  102. #endif
  103. .endfunc ;
  104. ;*************************************************************************
  105. ; Initialization of the I2C bus interface. Need to be called only once
  106. ;
  107. ; extern void i2c_init(void)
  108. ;*************************************************************************
  109. .global i2c_init
  110. .func i2c_init
  111. i2c_init:
  112. cbi SDA_DDR,SDA ;release SDA
  113. cbi SCL_DDR,SCL ;release SCL
  114. cbi SDA_OUT,SDA
  115. cbi SCL_OUT,SCL
  116. ret
  117. .endfunc
  118. ;*************************************************************************
  119. ; Issues a start condition and sends address and transfer direction.
  120. ; return 0 = device accessible, 1= failed to access device
  121. ;
  122. ; extern unsigned char i2c_start(unsigned char addr);
  123. ; addr = r24, return = r25(=0):r24
  124. ;*************************************************************************
  125. .global i2c_start
  126. .func i2c_start
  127. i2c_start:
  128. sbi SDA_DDR,SDA ;force SDA low
  129. rcall i2c_delay_T2 ;delay T/2
  130. rcall i2c_write ;write address
  131. ret
  132. .endfunc
  133. ;*************************************************************************
  134. ; Issues a repeated start condition and sends address and transfer direction.
  135. ; return 0 = device accessible, 1= failed to access device
  136. ;
  137. ; extern unsigned char i2c_rep_start(unsigned char addr);
  138. ; addr = r24, return = r25(=0):r24
  139. ;*************************************************************************
  140. .global i2c_rep_start
  141. .func i2c_rep_start
  142. i2c_rep_start:
  143. sbi SCL_DDR,SCL ;force SCL low
  144. rcall i2c_delay_T2 ;delay T/2
  145. cbi SDA_DDR,SDA ;release SDA
  146. rcall i2c_delay_T2 ;delay T/2
  147. cbi SCL_DDR,SCL ;release SCL
  148. rcall i2c_delay_T2 ;delay T/2
  149. sbi SDA_DDR,SDA ;force SDA low
  150. rcall i2c_delay_T2 ;delay T/2
  151. rcall i2c_write ;write address
  152. ret
  153. .endfunc
  154. ;*************************************************************************
  155. ; Issues a start condition and sends address and transfer direction.
  156. ; If device is busy, use ack polling to wait until device is ready
  157. ;
  158. ; extern void i2c_start_wait(unsigned char addr);
  159. ; addr = r24
  160. ;*************************************************************************
  161. .global i2c_start_wait
  162. .func i2c_start_wait
  163. i2c_start_wait:
  164. mov __tmp_reg__,r24
  165. i2c_start_wait1:
  166. sbi SDA_DDR,SDA ;force SDA low
  167. rcall i2c_delay_T2 ;delay T/2
  168. mov r24,__tmp_reg__
  169. rcall i2c_write ;write address
  170. tst r24 ;if device not busy -> done
  171. breq i2c_start_wait_done
  172. rcall i2c_stop ;terminate write operation
  173. rjmp i2c_start_wait1 ;device busy, poll ack again
  174. i2c_start_wait_done:
  175. ret
  176. .endfunc
  177. ;*************************************************************************
  178. ; Terminates the data transfer and releases the I2C bus
  179. ;
  180. ; extern void i2c_stop(void)
  181. ;*************************************************************************
  182. .global i2c_stop
  183. .func i2c_stop
  184. i2c_stop:
  185. sbi SCL_DDR,SCL ;force SCL low
  186. sbi SDA_DDR,SDA ;force SDA low
  187. rcall i2c_delay_T2 ;delay T/2
  188. cbi SCL_DDR,SCL ;release SCL
  189. rcall i2c_delay_T2 ;delay T/2
  190. cbi SDA_DDR,SDA ;release SDA
  191. rcall i2c_delay_T2 ;delay T/2
  192. ret
  193. .endfunc
  194. ;*************************************************************************
  195. ; Send one byte to I2C device
  196. ; return 0 = write successful, 1 = write failed
  197. ;
  198. ; extern unsigned char i2c_write( unsigned char data );
  199. ; data = r24, return = r25(=0):r24
  200. ;*************************************************************************
  201. .global i2c_write
  202. .func i2c_write
  203. i2c_write:
  204. sec ;set carry flag
  205. rol r24 ;shift in carry and out bit one
  206. rjmp i2c_write_first
  207. i2c_write_bit:
  208. lsl r24 ;if transmit register empty
  209. i2c_write_first:
  210. breq i2c_get_ack
  211. sbi SCL_DDR,SCL ;force SCL low
  212. brcc i2c_write_low
  213. nop
  214. cbi SDA_DDR,SDA ;release SDA
  215. rjmp i2c_write_high
  216. i2c_write_low:
  217. sbi SDA_DDR,SDA ;force SDA low
  218. rjmp i2c_write_high
  219. i2c_write_high:
  220. rcall i2c_delay_T2 ;delay T/2
  221. cbi SCL_DDR,SCL ;release SCL
  222. rcall i2c_delay_T2 ;delay T/2
  223. rjmp i2c_write_bit
  224. i2c_get_ack:
  225. sbi SCL_DDR,SCL ;force SCL low
  226. cbi SDA_DDR,SDA ;release SDA
  227. rcall i2c_delay_T2 ;delay T/2
  228. cbi SCL_DDR,SCL ;release SCL
  229. i2c_ack_wait:
  230. sbis SCL_IN,SCL ;wait SCL high (in case wait states are inserted)
  231. rjmp i2c_ack_wait
  232. clr r24 ;return 0
  233. sbic SDA_IN,SDA ;if SDA high -> return 1
  234. ldi r24,1
  235. rcall i2c_delay_T2 ;delay T/2
  236. clr r25
  237. ret
  238. .endfunc
  239. ;*************************************************************************
  240. ; read one byte from the I2C device, send ack or nak to device
  241. ; (ack=1, send ack, request more data from device
  242. ; ack=0, send nak, read is followed by a stop condition)
  243. ;
  244. ; extern unsigned char i2c_read(unsigned char ack);
  245. ; ack = r24, return = r25(=0):r24
  246. ; extern unsigned char i2c_readAck(void);
  247. ; extern unsigned char i2c_readNak(void);
  248. ; return = r25(=0):r24
  249. ;*************************************************************************
  250. .global i2c_readAck
  251. .global i2c_readNak
  252. .global i2c_read
  253. .func i2c_read
  254. i2c_readNak:
  255. clr r24
  256. rjmp i2c_read
  257. i2c_readAck:
  258. ldi r24,0x01
  259. i2c_read:
  260. ldi r23,0x01 ;data = 0x01
  261. i2c_read_bit:
  262. sbi SCL_DDR,SCL ;force SCL low
  263. cbi SDA_DDR,SDA ;release SDA (from previous ACK)
  264. rcall i2c_delay_T2 ;delay T/2
  265. cbi SCL_DDR,SCL ;release SCL
  266. rcall i2c_delay_T2 ;delay T/2
  267. i2c_read_stretch:
  268. sbis SCL_IN, SCL ;loop until SCL is high (allow slave to stretch SCL)
  269. rjmp i2c_read_stretch
  270. clc ;clear carry flag
  271. sbic SDA_IN,SDA ;if SDA is high
  272. sec ; set carry flag
  273. rol r23 ;store bit
  274. brcc i2c_read_bit ;while receive register not full
  275. i2c_put_ack:
  276. sbi SCL_DDR,SCL ;force SCL low
  277. cpi r24,1
  278. breq i2c_put_ack_low ;if (ack=0)
  279. cbi SDA_DDR,SDA ; release SDA
  280. rjmp i2c_put_ack_high
  281. i2c_put_ack_low: ;else
  282. sbi SDA_DDR,SDA ; force SDA low
  283. i2c_put_ack_high:
  284. rcall i2c_delay_T2 ;delay T/2
  285. cbi SCL_DDR,SCL ;release SCL
  286. i2c_put_ack_wait:
  287. sbis SCL_IN,SCL ;wait SCL high
  288. rjmp i2c_put_ack_wait
  289. rcall i2c_delay_T2 ;delay T/2
  290. mov r24,r23
  291. clr r25
  292. ret
  293. .endfunc