1 /**
2 * \file
3 *
4 * \brief I2C Master Interrupt Driver for SAMB
5 *
6 * Copyright (c) 2015-2016 Atmel Corporation. All rights reserved.
7 *
8 * \asf_license_start
9 *
10 * \page License
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions are met:
14 *
15 * 1. Redistributions of source code must retain the above copyright notice,
16 * this list of conditions and the following disclaimer.
17 *
18 * 2. Redistributions in binary form must reproduce the above copyright notice,
19 * this list of conditions and the following disclaimer in the documentation
20 * and/or other materials provided with the distribution.
21 *
22 * 3. The name of Atmel may not be used to endorse or promote products derived
23 * from this software without specific prior written permission.
24 *
25 * 4. This software may only be redistributed and used in connection with an
26 * Atmel microcontroller product.
27 *
28 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
29 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
30 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
31 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
32 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
37 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
39 *
40 * \asf_license_stop
41 *
42 */
43 /*
44 * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
45 */
46
47 #include "i2c_slave_interrupt.h"
48
49 void *_i2c_instances;
50
51 /**
52 * \internal
53 * Reads next data. Used by interrupt handler to get next data byte from master.
54 *
55 * \param[in,out] module Pointer to software module structure
56 */
_i2c_slave_read(struct i2c_slave_module * const module)57 static void _i2c_slave_read(
58 struct i2c_slave_module *const module)
59 {
60 /* Sanity check */
61 Assert(module);
62 Assert(module->hw);
63
64 I2c *const i2c_module = module->hw;
65
66 /* Read byte from master and put in buffer. */
67 *(module->buffer++) = i2c_module->RECEIVE_DATA.reg;
68
69 /*Decrement remaining buffer length */
70 module->buffer_remaining--;
71 }
72
73 /**
74 * \internal
75 * Writes next data. Used by interrupt handler to send next data byte to master.
76 *
77 * \param[in,out] module Pointer to software module structure
78 */
_i2c_slave_write(struct i2c_slave_module * const module)79 static void _i2c_slave_write(
80 struct i2c_slave_module *const module)
81 {
82 /* Sanity check */
83 Assert(module);
84 Assert(module->hw);
85
86 I2c *const i2c_module = module->hw;
87
88 /* Write byte from buffer to master */
89 i2c_module->TRANSMIT_DATA.reg = *(module->buffer++);
90
91 /*Decrement remaining buffer length */
92 module->buffer_remaining--;
93 }
94
95 /**
96 * \brief Registers callback for the specified callback type
97 *
98 * Associates the given callback function with the
99 * specified callback type. To enable the callback, the
100 * \ref i2c_slave_enable_callback function must be used.
101 *
102 * \param[in,out] module Pointer to the software module struct
103 * \param[in] callback Pointer to the function desired for the
104 * specified callback
105 * \param[in] callback_type Callback type to register
106 */
i2c_slave_register_callback(struct i2c_slave_module * const module,i2c_slave_callback_t callback,enum i2c_slave_callback callback_type)107 void i2c_slave_register_callback(
108 struct i2c_slave_module *const module,
109 i2c_slave_callback_t callback,
110 enum i2c_slave_callback callback_type)
111 {
112 /* Sanity check. */
113 Assert(module);
114 Assert(module->hw);
115 Assert(callback);
116
117 /* Register callback. */
118 module->callbacks[callback_type] = callback;
119
120 /* Set corresponding bit to set callback as initiated. */
121 module->registered_callback |= (1 << callback_type);
122 }
123
124 /**
125 * \brief Unregisters callback for the specified callback type
126 *
127 * Removes the currently registered callback for the given callback
128 * type.
129 *
130 * \param[in,out] module Pointer to the software module struct
131 * \param[in] callback_type Callback type to unregister
132 */
i2c_slave_unregister_callback(struct i2c_slave_module * const module,enum i2c_slave_callback callback_type)133 void i2c_slave_unregister_callback(
134 struct i2c_slave_module *const module,
135 enum i2c_slave_callback callback_type)
136 {
137 /* Sanity check. */
138 Assert(module);
139 Assert(module->hw);
140
141 /* Register callback. */
142 module->callbacks[callback_type] = NULL;
143
144 /* Set corresponding bit to set callback as initiated. */
145 module->registered_callback &= ~(1 << callback_type);
146 }
147
148 /**
149 * \brief Initiates a reads packet operation
150 *
151 * Reads a data packet from the master. A write request must be initiated by
152 * the master before the packet can be read.
153 *
154 * The \ref I2C_SLAVE_CALLBACK_WRITE_REQUEST callback can be used to call this
155 * function.
156 *
157 * \param[in,out] module Pointer to software module struct
158 * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
159 *
160 * \return Status of starting asynchronously reading I<SUP>2</SUP>C packet.
161 * \retval STATUS_OK If reading was started successfully
162 * \retval STATUS_BUSY If module is currently busy with another transfer
163 */
i2c_slave_read_packet_job(struct i2c_slave_module * const module,struct i2c_slave_packet * const packet)164 enum status_code i2c_slave_read_packet_job(
165 struct i2c_slave_module *const module,
166 struct i2c_slave_packet *const packet)
167 {
168 /* Sanity check */
169 Assert(module);
170 Assert(module->hw);
171 Assert(packet);
172
173 I2c *const i2c_module = module->hw;
174
175 /* Check if the I2C module is busy doing async operation. */
176 if (module->buffer_remaining > 0) {
177 return STATUS_BUSY;
178 }
179
180 /* Save packet to software module. */
181 module->buffer = packet->data;
182 module->buffer_remaining = packet->data_length;
183 module->buffer_length = packet->data_length;
184 module->status = STATUS_BUSY;
185
186 /* Enable interrupts */
187 i2c_slave_rx_interrupt(i2c_module, true);
188
189 return STATUS_OK;
190 }
191
192 /**
193 * \brief Initiates a write packet operation
194 *
195 * Writes a data packet to the master. A read request must be initiated by
196 * the master before the packet can be written.
197 *
198 * The \ref I2C_SLAVE_CALLBACK_READ_REQUEST callback can be used to call this
199 * function.
200 *
201 * \param[in,out] module Pointer to software module struct
202 * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
203 *
204 * \return Status of starting writing I<SUP>2</SUP>C packet.
205 * \retval STATUS_OK If writing was started successfully
206 * \retval STATUS_BUSY If module is currently busy with another transfer
207 */
i2c_slave_write_packet_job(struct i2c_slave_module * const module,struct i2c_slave_packet * const packet)208 enum status_code i2c_slave_write_packet_job(
209 struct i2c_slave_module *const module,
210 struct i2c_slave_packet *const packet)
211 {
212 /* Sanity check */
213 Assert(module);
214 Assert(module->hw);
215 Assert(packet);
216
217 I2c *const i2c_module = module->hw;
218
219 if (module->buffer_remaining > 0) {
220 return STATUS_BUSY;
221 }
222
223 /* Save packet to software module. */
224 module->buffer = packet->data;
225 module->buffer_remaining = packet->data_length;
226 module->buffer_length = packet->data_length;
227 module->status = STATUS_BUSY;
228
229 /* Enable interrupts */
230 i2c_slave_tx_interrupt(i2c_module, true);
231
232 return STATUS_OK;
233 }
234
235 /**
236 * \internal Interrupt handler for I<SUP>2</SUP>C slave
237 *
238 * \param[in] instance I2C instance that triggered the interrupt
239 */
_i2c_slave_rx_isr_handler(void)240 void _i2c_slave_rx_isr_handler(void)
241 {
242 /* Get software module for callback handling. */
243 struct i2c_slave_module *module =
244 (struct i2c_slave_module*)_i2c_instances;
245
246 Assert(module);
247
248 I2c *const i2c_module = module->hw;
249
250 /* Combine callback registered and enabled masks. */
251 uint8_t callback_mask =
252 module->enabled_callback & module->registered_callback;
253
254 if (i2c_module->RECEIVE_STATUS.reg & I2C_RECEIVE_STATUS_RX_FIFO_NOT_EMPTY) {
255 if (!module->buffer_length && (module->buffer_length == module->buffer_remaining)) {
256 module->transfer_direction = I2C_TRANSFER_WRITE;
257 if (callback_mask & (1 << I2C_SLAVE_CALLBACK_WRITE_REQUEST)) {
258 /* Write to master complete */
259 module->callbacks[I2C_SLAVE_CALLBACK_WRITE_REQUEST](module);
260 }
261 }
262 /* Continue buffer write/read */
263 if (module->buffer_length > 0 && module->buffer_remaining > 0) {
264 _i2c_slave_read(module);
265 }
266 if (!module->buffer_remaining) {
267 module->status = STATUS_OK;
268 module->buffer_length = 0;
269 if (callback_mask & (1 << I2C_SLAVE_CALLBACK_WRITE_COMPLETE)) {
270 /* Write to master complete */
271 module->callbacks[I2C_SLAVE_CALLBACK_WRITE_COMPLETE](module);
272 }
273 }
274 }
275 if ((i2c_module->RECEIVE_STATUS.reg & I2C_RECEIVE_STATUS_NAK)) { //&&
276 //module->transfer_direction == I2C_TRANSFER_READ) {
277 /* Received NAK, master received completed. */
278 i2c_module->RX_INTERRUPT_MASK.bit.NAK_MASK = 0;
279 if (callback_mask & (1 << I2C_SLAVE_CALLBACK_READ_COMPLETE)) {
280 module->callbacks[I2C_SLAVE_CALLBACK_READ_COMPLETE](module);
281 }
282 }
283
284 if (module->hw == I2C0) {
285 NVIC_ClearPendingIRQ(I2C0_RX_IRQn);
286 } else if (module->hw == I2C1) {
287 NVIC_ClearPendingIRQ(I2C1_RX_IRQn);
288 }
289 }
290
_i2c_slave_tx_isr_handler(void)291 void _i2c_slave_tx_isr_handler(void)
292 {
293 /* Get software module for callback handling. */
294 struct i2c_slave_module *module =
295 (struct i2c_slave_module*)_i2c_instances;
296
297 Assert(module);
298
299 I2c *const i2c_module = module->hw;
300
301 /* Combine callback registered and enabled masks. */
302 uint8_t callback_mask =
303 module->enabled_callback & module->registered_callback;
304
305 if (!module->buffer_length && (module->buffer_length == module->buffer_remaining)) {
306 /* First timer interrupt */
307 module->transfer_direction = I2C_TRANSFER_READ;
308 if (callback_mask & (1 << I2C_SLAVE_CALLBACK_READ_REQUEST)) {
309 /* Write to master complete */
310 module->callbacks[I2C_SLAVE_CALLBACK_READ_REQUEST](module);
311 }
312 }
313 if (module->buffer_length > 0 && module->buffer_remaining > 0) {
314 _i2c_slave_write(module);
315 }
316 if (!module->buffer_remaining) {
317 module->status = STATUS_OK;
318 module->buffer_length = 0;
319 i2c_module->RX_INTERRUPT_MASK.bit.NAK_MASK = 0;
320 if (callback_mask & (1 << I2C_SLAVE_CALLBACK_READ_COMPLETE)) {
321 module->callbacks[I2C_SLAVE_CALLBACK_READ_COMPLETE](module);
322 }
323 }
324
325 if (module->hw == I2C0) {
326 NVIC_ClearPendingIRQ(I2C0_TX_IRQn);
327 } else if (module->hw == I2C1) {
328 NVIC_ClearPendingIRQ(I2C1_TX_IRQn);
329 }
330 }