My favorites | Sign in
Project Home Downloads Wiki Issues Source
Checkout   Browse   Changes    
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
-- Title: i2c hardware slave ISR
-- Author: Sebastien Lelong, Joep Suijs, Copyright (c) 2008-2009, all rights reserved.
-- Adapted-by: Joep Suijs, Albert Faber
-- Compiler: >=2.4i
-- Revision: $Revision$
--
-- This file is part of jallib (http://jallib.googlecode.com)
-- Released under the ZLIB license (http://www.opensource.org/licenses/zlib-license.html)
--
-- Description: this library provides an ISR to implement
-- a stateful i2c hardware slave. This is a jalv2 implementation of
-- Microchip Application Note AN734.
-- --
-- According to AN734, there are 5 possible i2c states. During ISR, each
-- of this states are detected. This ISR provides a standard skeleton to implement
-- an i2c hardware slaves, while client code must implement several callbacks
-- the ISR is expecting to call while processing states.
-- --
-- Here there are:
-- - procedure i2c_hw_slave_on_state_1(byte in _trash):
-- called when i2c address matches (master starts a talk)
-- --
-- - procedure i2c_hw_slave_on_state_2(byte in rcv):
-- called when master is writing a byte. Slave is thus
-- receiving this byte. This callback takes this bytes as
-- argument
-- --
-- - procedure i2c_hw_slave_on_state_3():
-- called when master wants to read a byte from slave. Thus,
-- slave should send a byte (for instance, using i2c_hw_slave_write_i2c
-- from i2c_hw_slave.jal library)
-- --
-- - procedure i2c_hw_slave_on_state_4():
-- called when master still wants to read a byte from slave. That is,
-- master required to read (state 3) and now still want to read a byte
-- --
-- - procedure i2c_hw_slave_on_state_5():
-- called when master does not want to talk to slave anymore
-- usually a good place to reset data or slave's logic
-- --
-- - procedure i2c_hw_slave_on_error():
-- called when something wrong happens. You can do what you want in
-- this case, like resetting the PIC, log some information using usart, ...
-- => called any cases other than states 1, 2, 3, 4 or 5
--
--
-- Sources:
-- - AN734: http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1824&appnote=en011798
--

-- enable line below to enable testing of the clock stretching feature
-- it will add an additional delay of 200us in the interrupt handler
-- so were sure that clock stretching is required for 100 KHz I2C operation

-- const bit I2C_HW_SLAVE_TEST_CLOCK_STRETCHING == 1


if defined( I2C_HW_SLAVE_TEST_CLOCK_STRETCHING ) == true then
include delay
end if

-- i2c ISR handler. Detects states a call appropriate procedures
procedure i2c_hw_slave_isr_handler() is
pragma interrupt
if ! PIR1_SSPIF then
return
end if

-- Test code to simulate a large delay in the I2C interrupt handling
-- to test if the clock stretching feature is working properly
if defined( I2C_HW_SLAVE_TEST_CLOCK_STRETCHING ) == true then
delay_10us( 20 )
end if

PIR1_SSPIF = false
tmpstat = SSPSTAT

if(defined(i2c_debug) == true) then
; queue01_nb = "*"
; print_byte_hex(queue01_nb, tmpstat)
queue01_nb = "#"
print_byte_hex(queue01_nb, sspcon1)
end if

; check for overflow
if (SSPCON1_SSPOV) then
var byte _trash = i2c_hw_slave_read_i2c()
_trash = i2c_hw_slave_read_i2c()
SSPCON1_SSPOV = false
end if

-- if this constant is defined and true, call start & stop handlers.
if(defined(i2c_enable_start_stop_interrupts) == true) then
if i2c_enable_start_stop_interrupts == true then

if (tmpstat & 0b_0000_1111) == 0b_0000_1000 then
i2c_hw_slave_on_start();
return
end if
if (tmpstat & 0b_0011_0000) == 0b_0011_0000 then
i2c_hw_slave_on_stop();
return
end if

end if
end if

-- mask out unimportant bit
tmpstat = tmpstat & 0b_0010_1101

-- State machine for PIC18f is slightly different, therefore specific
-- code for PIC16 and PIC18
if defined(i2c_old_statemachine) == true then

-- state 1: write operation, last byte is address, buffer full
-- byte is an address, it we get here, we just know master
-- wants to talk to us, in a new write operation...
-- and we also know address is recognized (BF is set, see spec)
-- anyway, we must read buffer to reset BF bit
-- (buffer actually contains previously detected address, that's
-- why it's usually ignored)
--
-- => call i2c_hw_slave_on_state_1(byte)
if (tmpstat ^ 0b_0000_1001) == false
then
var byte _trash = i2c_hw_slave_read_i2c()
i2c_hw_slave_on_state_1(_trash)

-- state 2: write operation, last byte is data, buffer full
-- master wants to write, it sends a byte
--
-- => call i2c_hw_slave_on_state_2(byte)
--
-- (note: at a write-only sequence, fast masters give a stop (clearing bit3)
-- before we can read the register. The or statment is handles this)
elsif ((tmpstat | 0b_0000_1000) ^ 0b_0010_1001) == false
then
var byte rcv = i2c_hw_slave_read_i2c()
i2c_hw_slave_on_state_2(rcv)

if ((tmpstat & 0b_0000_1000) == false) then
SSPCON1_CKP = 1
end if
-- state 3: read operation, last byte is address, buffer empty
-- master wants to get a value from us
--
-- => call i2c_hw_slave_on_state_3()
elsif (tmpstat ^ 0b_0000_1100) == false
then
i2c_hw_slave_on_state_3()

-- state 4: read operation, last byte is data, buffer empty
-- master still wants to get a value from us
--
-- => call i2c_hw_slave_on_state_4()
elsif (tmpstat ^ 0b_00101100) == false
then
i2c_hw_slave_on_state_4()

-- state 5: nack
-- master doesn't want to talk with us anymore
--
-- => call i2c_hw_slave_on_state_5()
elsif (tmpstat ^ 0b_0010_1000) == false
then
-- AN734 does not talk about setting CKP, whereas spec says
-- it must be set. Some people say it can be error prone.
SSPCON1_CKP = 1
i2c_hw_slave_on_state_5()

-- state not recognized... Error !
else
-- something went wrong, that is, XOR operations did not match
-- SSPSTAT bits
SSPCON1_CKP = 1
i2c_hw_slave_on_error()
end if
else
-- slightly modified statemachine for PIC18F devices
-- see AN734 revision B for additional details

-- state 1: write operation, last byte is address, buffer full
-- byte is an address, it we get here, we just know master
-- wants to talk to us, in a new write operation...
-- and we also know address is recognized (BF is set, see spec)
-- anyway, we must read buffer to reset BF bit
-- (buffer actually contains previously detected address, that's
-- why it's usually ignored)
--
-- => call i2c_hw_slave_on_state_1(byte)
if (tmpstat ^ 0b_0000_1001) == false
then
var byte _trash = i2c_hw_slave_read_i2c()
i2c_hw_slave_on_state_1(_trash)

-- state 2: write operation, last byte is data, buffer full
-- master wants to write, it sends a byte
--
-- => call i2c_hw_slave_on_state_2(byte)
--
-- (note: at a write-only sequence, fast masters give a stop (clearing bit3)
-- before we can read the register. The or statment is handles this)
elsif ((tmpstat | 0b_0000_1000) ^ 0b_0010_1001) == false
then
var byte rcv = i2c_hw_slave_read_i2c()
i2c_hw_slave_on_state_2(rcv)

-- state 3: read operation, last byte is address, buffer empty
-- master wants to get a value from us
--
-- => call i2c_hw_slave_on_state_3()
-- Mask BF flag for newer statemachines
elsif ((tmpstat & 0b_1111_1110) ^ 0b_0000_1100) == false
then
-- clear BF flag by clearing SSPBUF, required for PIC18f devices
-- with a new version of the i2c statemachine (see also AN734)
var byte _trash = i2c_hw_slave_read_i2c()

i2c_hw_slave_on_state_3()


elsif ((tmpstat & 0b_1111_1011) ^ 0b_0010_1000) == false
then

-- check CKP bit to distinguish between state 4 and 5
if ( SSPCON1_CKP == 0 ) then

-- state 4: read operation, last byte is data, buffer empty
-- master still wants to get a value from us
--
-- => call i2c_hw_slave_on_state_4()
-- Don't check R/W flag, use CKP bit instead
i2c_hw_slave_on_state_4()

else

-- state 5: nack
-- master doesn't want to talk with us anymore
--
-- => call i2c_hw_slave_on_state_5()
-- AN734 does not talk about setting CKP, whereas spec says
-- it must be set. Some people say it can be error prone.
-- SSPCON1_CKP = 1
i2c_hw_slave_on_state_5()
end if

-- state not recognized... Error !
else
-- something went wrong, that is, XOR operations did not match
-- SSPSTAT bits
i2c_hw_slave_on_error()
end if

-- always clear CKP so clock line will be released (HW will set CKP
-- bit when clock stretching feature is enabled
SSPCON1_CKP = 1
end if

end procedure

Change log

r2929 by robhamerling on Jan 17, 2012   Diff
 Updates of libraries and samples for new
naming conventions
 of USART and MSSP modules.

Go to: 
Project members, sign in to write a code review

Older revisions

r2760 by sebastien.lelong on Jul 31, 2011   Diff
added Revision: field + svn:keywords
Revision property on all existing
*.jal files. Also add to normalize EOL
chars to avoid mixed ones
r1193 by sebastien.lelong on Aug 13, 2009   Diff
added i2c_hardware_aliases +
conditional include
r1159 by a.fa...@chello.nl on Aug 4, 2009   Diff
fixed i2c HW slave clock stretching
for PIC18 devices
All revisions of this file

File info

Size: 9668 bytes, 260 lines

File properties

svn:keywords
Revision
Powered by Google Project Hosting