1 /**
2 * \file
3 *
4 * \brief Serial Peripheral Interface Driver for SAMB11
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 #include "spi_callback.h"
47
48 struct spi_module *_spi_instances[SPI_INST_NUM];
49
50 /**
51 * \internal
52 *
53 * Dummy byte to send when reading in master mode.
54 */
55 static uint16_t dummy_write;
56 static bool flag_direction_both[SPI_INST_NUM];
57
58 /**
59 * \internal
60 * Writes a character from the TX buffer to the Data register.
61 *
62 * \param[in,out] module Pointer to SPI software instance struct
63 */
_spi_write(struct spi_module * const module)64 static void _spi_write(
65 struct spi_module *const module)
66 {
67 /* Pointer to the hardware module instance */
68 Spi *const spi_hw = module->hw;
69
70 /* Write value will be at least 8-bits long */
71 uint16_t data_to_send = *(module->tx_buffer_ptr);
72 /* Increment 8-bit pointer */
73 (module->tx_buffer_ptr)++;
74
75 /* Write the data to send*/
76 spi_hw->TRANSMIT_DATA.reg = data_to_send & SPI_TRANSMIT_DATA_MASK;
77
78 /* Decrement remaining buffer length */
79 (module->remaining_tx_buffer_length)--;
80 }
81
82 /**
83 * \internal
84 * Reads a character from the Data register to the RX buffer.
85 *
86 * \param[in,out] module Pointer to SPI software instance struct
87 */
_spi_read(struct spi_module * const module)88 static void _spi_read(
89 struct spi_module *const module)
90 {
91 /* Pointer to the hardware module instance */
92 Spi *const spi_hw = module->hw;
93
94 uint16_t received_data = (spi_hw->RECEIVE_DATA.reg & SPI_RECEIVE_DATA_MASK);
95
96 /* Read value will be at least 8-bits long */
97 *(module->rx_buffer_ptr) = received_data;
98 /* Increment 8-bit pointer */
99 module->rx_buffer_ptr += 1;
100
101 /* Decrement length of the remaining buffer */
102 module->remaining_rx_buffer_length--;
103 }
104
105 #if CONF_SPI_MASTER_ENABLE == true
106 /**
107 * \internal
108 * Writes a dummy character to the Data register.
109 *
110 * \param[in,out] module Pointer to SPI software instance struct
111 */
_spi_write_dummy(struct spi_module * const module)112 static void _spi_write_dummy(
113 struct spi_module *const module)
114 {
115 /* Pointer to the hardware module instance */
116 Spi *const spi_hw = module->hw;
117
118 /* Write dummy byte */
119 spi_hw->TRANSMIT_DATA.reg = dummy_write;
120
121 /* Decrement remaining dummy buffer length */
122 module->remaining_dummy_buffer_length--;
123 }
124 #endif
125
126 /**
127 * \internal
128 * Writes a dummy character from the to the Data register.
129 *
130 * \param[in,out] module Pointer to SPI software instance struct
131 */
_spi_read_dummy(struct spi_module * const module)132 static void _spi_read_dummy(
133 struct spi_module *const module)
134 {
135 /* Pointer to the hardware module instance */
136 Spi *const spi_hw = module->hw;
137 uint16_t flush = 0;
138
139 /* Read dummy byte */
140 flush = spi_hw->RECEIVE_DATA.reg;
141 UNUSED(flush);
142
143 /* Decrement remaining dummy buffer length */
144 module->remaining_dummy_buffer_length--;
145 }
146
spi_rx0_isr_handler(void)147 void spi_rx0_isr_handler(void)
148 {
149 struct spi_module *module = _spi_instances[0];
150
151 /* get interrupt flags and mask out enabled callbacks */
152 uint32_t flags = module->hw->RECEIVE_STATUS.reg;
153 flags &= module->hw->RX_INTERRUPT_MASK.reg;
154
155 if (flags & SPI_RECEIVE_STATUS_RX_FIFO_NOT_EMPTY) {
156 if (module->hw->RECEIVE_STATUS.reg & SPI_RECEIVE_STATUS_FIFO_OVERRUN) {
157 if (module->dir != SPI_DIRECTION_WRITE) {
158 /* Store the error code */
159 module->status = STATUS_ERR_OVERFLOW;
160
161 /* End transaction */
162 module->dir = SPI_DIRECTION_IDLE;
163
164 module->hw->RX_INTERRUPT_MASK.reg &=
165 ~(SPI_RX_INTERRUPT_MASK_FIFO_OVERRUN_MASK |
166 SPI_RX_INTERRUPT_MASK_RX_FIFO_NOT_EMPTY_MASK);
167 /* Run callback if registered and enabled */
168 if ((module->enabled_callback & (1 << SPI_CALLBACK_ERROR)) &&
169 (module->registered_callback & (1 << SPI_CALLBACK_ERROR))) {
170 module->status = STATUS_ERR_OVERFLOW;
171 module->hw->RX_INTERRUPT_MASK.reg &=
172 ~(SPI_RX_INTERRUPT_MASK_FIFO_OVERRUN_MASK);
173 (module->callback[SPI_CALLBACK_ERROR])(module);
174 }
175 }
176 /* Flush */
177 uint16_t flush = module->hw->RECEIVE_DATA.reg;
178 UNUSED(flush);
179 } else {
180 if (module->dir == SPI_DIRECTION_WRITE) {
181 /* Flush receive buffer when writing */
182 _spi_read_dummy(module);
183 if (module->remaining_dummy_buffer_length == 0) {
184 module->hw->RX_INTERRUPT_MASK.reg &=
185 ~SPI_RX_INTERRUPT_MASK_FIFO_OVERRUN_MASK;
186 module->status = STATUS_OK;
187 module->dir = SPI_DIRECTION_IDLE;
188 ///* Run callback if registered and enabled */
189 //if ((module->enabled_callback & (1 << SPI_CALLBACK_BUFFER_TRANSMITTED)) &&
190 //(module->registered_callback & (1 << SPI_CALLBACK_BUFFER_TRANSMITTED))) {
191 //(module->callback[SPI_CALLBACK_BUFFER_TRANSMITTED])(module);
192 //}
193 }
194 } else {
195 _spi_read(module);
196 if (module->remaining_rx_buffer_length == 0) {
197 if(module->dir == SPI_DIRECTION_READ) {
198 if ((module->enabled_callback & (1 << SPI_CALLBACK_BUFFER_RECEIVED)) &&
199 (module->registered_callback & (1 << SPI_CALLBACK_BUFFER_RECEIVED))) {
200 module->status = STATUS_OK;
201 module->hw->RX_INTERRUPT_MASK.reg &=
202 ~(SPI_RX_INTERRUPT_MASK_RX_FIFO_NOT_EMPTY_MASK);
203 (module->callback[SPI_CALLBACK_BUFFER_RECEIVED])(module);
204 }
205 } else if (module->dir == SPI_DIRECTION_BOTH) {
206 if ((module->enabled_callback & (1 << SPI_CALLBACK_BUFFER_TRANSCEIVED)) &&
207 (module->registered_callback & (1 << SPI_CALLBACK_BUFFER_TRANSCEIVED))) {
208 module->hw->RX_INTERRUPT_MASK.reg &=
209 ~(SPI_RX_INTERRUPT_MASK_RX_FIFO_NOT_EMPTY_MASK);
210 if (flag_direction_both[0]) {
211 module->status = STATUS_OK;
212 flag_direction_both[0] = false;
213 (module->callback[SPI_CALLBACK_BUFFER_TRANSCEIVED])(module);
214 } else {
215 flag_direction_both[0] = true;
216 }
217 }
218 }
219 }
220 }
221 }
222 }
223 }
224
spi_tx0_isr_handler(void)225 void spi_tx0_isr_handler(void)
226 {
227 struct spi_module *module = _spi_instances[0];
228
229 /* get interrupt flags and mask out enabled callbacks */
230 uint32_t flags = module->hw->TRANSMIT_STATUS.reg;
231 flags &= module->hw->TX_INTERRUPT_MASK.reg;
232
233 if (flags & SPI_TRANSMIT_STATUS_TX_FIFO_NOT_FULL_1) {
234 # if CONF_SPI_MASTER_ENABLE == true
235 if ((module->mode == SPI_MODE_MASTER) &&
236 (module->dir == SPI_DIRECTION_READ)) {
237 /* Send dummy byte when reading in master mode */
238 _spi_write_dummy(module);
239 if (module->remaining_dummy_buffer_length == 0) {
240 /* Disable the Data Register Empty Interrupt */
241 module->hw->TX_INTERRUPT_MASK.reg &=
242 ~SPI_TX_INTERRUPT_MASK_TX_FIFO_NOT_FULL_MASK;
243 }
244 }
245 # endif
246 if (0
247 # if CONF_SPI_MASTER_ENABLE == true
248 || ((module->mode == SPI_MODE_MASTER) &&
249 (module->dir != SPI_DIRECTION_READ))
250 # endif
251 # if CONF_SPI_SLAVE_ENABLE == true
252 || ((module->mode == SPI_MODE_SLAVE) &&
253 (module->dir != SPI_DIRECTION_READ))
254 # endif
255 ) {
256 _spi_write(module);
257 if (module->remaining_tx_buffer_length == 0) {
258 module->hw->TX_INTERRUPT_MASK.reg &=
259 ~SPI_TX_INTERRUPT_MASK_TX_FIFO_NOT_FULL_MASK;
260 module->hw->TX_INTERRUPT_MASK.reg |=
261 SPI_TX_INTERRUPT_MASK_TX_FIFO_EMPTY_MASK;
262 }
263 }
264 }
265 if (flags & SPI_TRANSMIT_STATUS_TX_FIFO_EMPTY) {
266 if (module->dir == SPI_DIRECTION_WRITE) {
267 if ((module->enabled_callback & (1 << SPI_CALLBACK_BUFFER_TRANSMITTED)) &&
268 (module->registered_callback & (1 << SPI_CALLBACK_BUFFER_TRANSMITTED))) {
269 module->status = STATUS_OK;
270 /* Disable interrupt */
271 module->hw->TX_INTERRUPT_MASK.reg &=
272 ~SPI_TX_INTERRUPT_MASK_TX_FIFO_EMPTY_MASK;
273 (module->callback[SPI_CALLBACK_BUFFER_TRANSMITTED])(module);
274 }
275 } else if (module->dir == SPI_DIRECTION_BOTH) {
276 if ((module->enabled_callback & (1 << SPI_CALLBACK_BUFFER_TRANSCEIVED)) &&
277 (module->registered_callback & (1 << SPI_CALLBACK_BUFFER_TRANSCEIVED))) {
278 /* Disable interrupt */
279 module->hw->TX_INTERRUPT_MASK.reg &=
280 ~SPI_TX_INTERRUPT_MASK_TX_FIFO_EMPTY_MASK;
281 if (flag_direction_both[0]) {
282 module->status = STATUS_OK;
283 flag_direction_both[0] = false;
284 (module->callback[SPI_CALLBACK_BUFFER_TRANSCEIVED])(module);
285 } else {
286 flag_direction_both[0] = true;
287 }
288 }
289 }
290 }
291 }
292
spi_rx1_isr_handler(void)293 void spi_rx1_isr_handler(void)
294 {
295 struct spi_module *module = _spi_instances[1];
296
297 /* get interrupt flags and mask out enabled callbacks */
298 uint32_t flags = module->hw->RECEIVE_STATUS.reg;
299 flags &= module->hw->RX_INTERRUPT_MASK.reg;
300
301 if (flags & SPI_RECEIVE_STATUS_RX_FIFO_NOT_EMPTY) {
302 if (module->hw->RECEIVE_STATUS.reg & SPI_RECEIVE_STATUS_FIFO_OVERRUN) {
303 if (module->dir != SPI_DIRECTION_WRITE) {
304 /* Store the error code */
305 module->status = STATUS_ERR_OVERFLOW;
306
307 /* End transaction */
308 module->dir = SPI_DIRECTION_IDLE;
309
310 module->hw->RX_INTERRUPT_MASK.reg &=
311 ~(SPI_RX_INTERRUPT_MASK_FIFO_OVERRUN_MASK |
312 SPI_RX_INTERRUPT_MASK_RX_FIFO_NOT_EMPTY_MASK);
313 /* Run callback if registered and enabled */
314 if ((module->enabled_callback & (1 << SPI_CALLBACK_ERROR)) &&
315 (module->registered_callback & (1 << SPI_CALLBACK_ERROR))) {
316 module->status = STATUS_ERR_OVERFLOW;
317 module->hw->RX_INTERRUPT_MASK.reg &=
318 ~(SPI_RX_INTERRUPT_MASK_FIFO_OVERRUN_MASK);
319 (module->callback[SPI_CALLBACK_ERROR])(module);
320 }
321 }
322 /* Flush */
323 uint16_t flush = module->hw->RECEIVE_DATA.reg;
324 UNUSED(flush);
325 } else {
326 if (module->dir == SPI_DIRECTION_WRITE) {
327 /* Flush receive buffer when writing */
328 _spi_read_dummy(module);
329 if (module->remaining_dummy_buffer_length == 0) {
330 module->hw->RX_INTERRUPT_MASK.reg &=
331 ~SPI_RX_INTERRUPT_MASK_FIFO_OVERRUN_MASK;
332 module->status = STATUS_OK;
333 module->dir = SPI_DIRECTION_IDLE;
334 }
335 } else {
336 _spi_read(module);
337 if (module->remaining_rx_buffer_length == 0) {
338 if(module->dir == SPI_DIRECTION_READ) {
339 if ((module->enabled_callback & (1 << SPI_CALLBACK_BUFFER_RECEIVED)) &&
340 (module->registered_callback & (1 << SPI_CALLBACK_BUFFER_RECEIVED))) {
341 module->status = STATUS_OK;
342 module->hw->RX_INTERRUPT_MASK.reg &=
343 ~(SPI_RX_INTERRUPT_MASK_RX_FIFO_NOT_EMPTY_MASK);
344 (module->callback[SPI_CALLBACK_BUFFER_RECEIVED])(module);
345 }
346 } else if (module->dir == SPI_DIRECTION_BOTH) {
347 if ((module->enabled_callback & (1 << SPI_CALLBACK_BUFFER_TRANSCEIVED)) &&
348 (module->registered_callback & (1 << SPI_CALLBACK_BUFFER_TRANSCEIVED))) {
349 module->hw->RX_INTERRUPT_MASK.reg &=
350 ~(SPI_RX_INTERRUPT_MASK_RX_FIFO_NOT_EMPTY_MASK);
351 if (flag_direction_both[1]) {
352 module->status = STATUS_OK;
353 flag_direction_both[1] = false;
354 (module->callback[SPI_CALLBACK_BUFFER_TRANSCEIVED])(module);
355 } else {
356 flag_direction_both[1] = true;
357 }
358 }
359 }
360 }
361 }
362 }
363 }
364 }
365
spi_tx1_isr_handler(void)366 void spi_tx1_isr_handler(void)
367 {
368 struct spi_module *module = _spi_instances[1];
369
370 /* get interrupt flags and mask out enabled callbacks */
371 uint32_t flags = module->hw->TRANSMIT_STATUS.reg;
372 flags &= module->hw->TX_INTERRUPT_MASK.reg;
373
374 if (flags & SPI_TRANSMIT_STATUS_TX_FIFO_NOT_FULL_1) {
375 # if CONF_SPI_MASTER_ENABLE == true
376 if ((module->mode == SPI_MODE_MASTER) &&
377 (module->dir == SPI_DIRECTION_READ)) {
378 /* Send dummy byte when reading in master mode */
379 _spi_write_dummy(module);
380 if (module->remaining_dummy_buffer_length == 0) {
381 /* Disable the Data Register Empty Interrupt */
382 module->hw->TX_INTERRUPT_MASK.reg &=
383 ~SPI_TX_INTERRUPT_MASK_TX_FIFO_NOT_FULL_MASK;
384 }
385 }
386 # endif
387 if (0
388 # if CONF_SPI_MASTER_ENABLE == true
389 || ((module->mode == SPI_MODE_MASTER) &&
390 (module->dir != SPI_DIRECTION_READ))
391 # endif
392 # if CONF_SPI_SLAVE_ENABLE == true
393 || ((module->mode == SPI_MODE_SLAVE) &&
394 (module->dir != SPI_DIRECTION_READ))
395 # endif
396 ) {
397 _spi_write(module);
398 if (module->remaining_tx_buffer_length == 0) {
399 module->hw->TX_INTERRUPT_MASK.reg &=
400 ~SPI_TX_INTERRUPT_MASK_TX_FIFO_NOT_FULL_MASK;
401 module->hw->TX_INTERRUPT_MASK.reg |=
402 SPI_TX_INTERRUPT_MASK_TX_FIFO_EMPTY_MASK;
403 }
404 }
405 }
406 if (flags & SPI_TRANSMIT_STATUS_TX_FIFO_EMPTY) {
407 if (module->dir == SPI_DIRECTION_WRITE) {
408 if ((module->enabled_callback & (1 << SPI_CALLBACK_BUFFER_TRANSMITTED)) &&
409 (module->registered_callback & (1 << SPI_CALLBACK_BUFFER_TRANSMITTED))) {
410 module->status = STATUS_OK;
411 /* Disable interrupt */
412 module->hw->TX_INTERRUPT_MASK.reg &=
413 ~SPI_TX_INTERRUPT_MASK_TX_FIFO_EMPTY_MASK;
414 (module->callback[SPI_CALLBACK_BUFFER_TRANSMITTED])(module);
415 }
416 } else if (module->dir == SPI_DIRECTION_BOTH) {
417 if ((module->enabled_callback & (1 << SPI_CALLBACK_BUFFER_TRANSCEIVED)) &&
418 (module->registered_callback & (1 << SPI_CALLBACK_BUFFER_TRANSCEIVED))) {
419 /* Disable interrupt */
420 module->hw->TX_INTERRUPT_MASK.reg &=
421 ~SPI_TX_INTERRUPT_MASK_TX_FIFO_EMPTY_MASK;
422 if (flag_direction_both[1]) {
423 module->status = STATUS_OK;
424 flag_direction_both[1] = false;
425 (module->callback[SPI_CALLBACK_BUFFER_TRANSCEIVED])(module);
426 } else {
427 flag_direction_both[1] = true;
428 }
429 }
430 }
431 }
432 }
433
434 /**
435 * \brief Registers a SPI callback function
436 *
437 * Registers a callback function which is implemented by the user.
438 *
439 * \note The callback must be enabled by \ref spi_enable_callback, in order
440 * for the interrupt handler to call it when the conditions for the
441 * callback type are met.
442 *
443 * \param[in] module Pointer to SPI software instance struct
444 * \param[in] callback_func Pointer to callback function
445 * \param[in] callback_type Callback type given by an enum
446 *
447 */
spi_register_callback(struct spi_module * const module,spi_callback_t callback_func,enum spi_callback callback_type)448 void spi_register_callback(
449 struct spi_module *const module,
450 spi_callback_t callback_func,
451 enum spi_callback callback_type)
452 {
453 /* Sanity check arguments */
454 Assert(module);
455 Assert(callback_func);
456
457 /* Register callback function */
458 module->callback[callback_type] = callback_func;
459
460 /* Set the bit corresponding to the callback_type */
461 module->registered_callback |= (1 << callback_type);
462 }
463
464 /**
465 * \brief Unregisters a SPI callback function
466 *
467 * Unregisters a callback function which is implemented by the user.
468 *
469 * \param[in] module Pointer to SPI software instance struct
470 * \param[in] callback_type Callback type given by an enum
471 *
472 */
spi_unregister_callback(struct spi_module * const module,enum spi_callback callback_type)473 void spi_unregister_callback(
474 struct spi_module *const module,
475 enum spi_callback callback_type)
476 {
477 /* Sanity check arguments */
478 Assert(module);
479
480 /* Unregister callback function */
481 module->callback[callback_type] = NULL;
482
483 /* Clear the bit corresponding to the callback_type */
484 module->registered_callback &= ~(1 << callback_type);
485 }
486
487 /**
488 * \brief Enables callback
489 *
490 * Enables the callback function registered by the \ref spi_register_callback.
491 * The callback function will be called from the interrupt handler when the
492 * conditions for the callback type are met.
493 *
494 * \param[in] module Pointer to SPI software instance struct
495 * \param[in] callback_type Callback type given by an enum
496 */
spi_enable_callback(struct spi_module * const module,enum spi_callback callback_type)497 void spi_enable_callback(struct spi_module *const module,
498 enum spi_callback callback_type)
499 {
500 /* Sanity check arguments */
501 Assert(module);
502
503 /* Enable callback */
504 module->enabled_callback |= (1 << callback_type);
505 }
506
507 /**
508 * \brief Disables callback
509 *
510 * Disables the callback function registered by the \ref spi_register_callback.
511 * The callback function will not be called from the interrupt handler.
512 *
513 * \param[in] module Pointer to SPI software instance struct
514 * \param[in] callback_type Callback type given by an enum
515 */
spi_disable_callback(struct spi_module * const module,enum spi_callback callback_type)516 void spi_disable_callback(struct spi_module *const module,
517 enum spi_callback callback_type)
518 {
519 /* Sanity check arguments */
520 Assert(module);
521
522 /* Enable callback */
523 module->enabled_callback &= ~(1 << callback_type);
524 }
525
526 /**
527 * \internal
528 * Starts write of a buffer with a given length
529 *
530 * \param[in] module Pointer to SPI software instance struct
531 * \param[in] tx_data Pointer to data to be transmitted
532 * \param[in] length Length of data buffer
533 *
534 */
_spi_write_buffer(struct spi_module * const module,uint8_t * tx_data,uint16_t length)535 static void _spi_write_buffer(
536 struct spi_module *const module,
537 uint8_t *tx_data,
538 uint16_t length)
539 {
540 Assert(module);
541 Assert(tx_data);
542
543 /* Write parameters to the device instance */
544 module->remaining_tx_buffer_length = length;
545 module->remaining_dummy_buffer_length = length;
546 module->tx_buffer_ptr = tx_data;
547 module->status = STATUS_BUSY;
548
549 module->dir = SPI_DIRECTION_WRITE;
550
551 /* Get a pointer to the hardware module instance */
552 Spi *const hw = module->hw;
553
554 hw->TX_INTERRUPT_MASK.reg = SPI_TX_INTERRUPT_MASK_TX_FIFO_NOT_FULL_MASK;
555 }
556
557 /**
558 * \internal
559 * Setup SPI to read a buffer with a given length
560 *
561 * \param[in] module Pointer to SPI software instance struct
562 * \param[in] rx_data Pointer to data to be received
563 * \param[in] length Length of data buffer
564 *
565 */
_spi_read_buffer(struct spi_module * const module,uint8_t * rx_data,uint16_t length)566 static void _spi_read_buffer(
567 struct spi_module *const module,
568 uint8_t *rx_data,
569 uint16_t length)
570 {
571 Assert(module);
572 Assert(rx_data);
573
574 /* Set length for the buffer and the pointer, and let
575 * the interrupt handler do the rest */
576 module->remaining_rx_buffer_length = length;
577 module->remaining_dummy_buffer_length = length;
578 module->rx_buffer_ptr = rx_data;
579 module->status = STATUS_BUSY;
580
581 module->dir = SPI_DIRECTION_READ;
582
583 /* Get a pointer to the hardware module instance */
584 Spi *const hw = module->hw;
585
586 hw->RX_INTERRUPT_MASK.reg = SPI_RX_INTERRUPT_MASK_RX_FIFO_NOT_EMPTY_MASK;
587
588 #if CONF_SPI_MASTER_ENABLE == true
589 hw->TX_INTERRUPT_MASK.reg = SPI_TX_INTERRUPT_MASK_TX_FIFO_NOT_FULL_MASK;
590 #endif
591 }
592
593 /**
594 * \internal
595 * Starts transceive of buffers with a given length
596 *
597 * \param[in] module Pointer to SPI software instance struct
598 * \param[in] rx_data Pointer to data to be received
599 * \param[in] tx_data Pointer to data to be transmitted
600 * \param[in] length Length of data buffer
601 *
602 */
_spi_transceive_buffer(struct spi_module * const module,uint8_t * tx_data,uint8_t * rx_data,uint16_t length)603 static void _spi_transceive_buffer(
604 struct spi_module *const module,
605 uint8_t *tx_data,
606 uint8_t *rx_data,
607 uint16_t length)
608 {
609 Assert(module);
610 Assert(tx_data);
611
612 /* Write parameters to the device instance */
613 module->remaining_tx_buffer_length = length;
614 module->remaining_rx_buffer_length = length;
615 module->rx_buffer_ptr = rx_data;
616 module->tx_buffer_ptr = tx_data;
617 module->status = STATUS_BUSY;
618
619 module->dir = SPI_DIRECTION_BOTH;
620
621 if (module->hw == SPI0) {
622 flag_direction_both[0] = false;
623 } else if (module->hw == SPI1) {
624 flag_direction_both[1] = false;
625 }
626
627 /* Get a pointer to the hardware module instance */
628 Spi *const hw = module->hw;
629
630 /* Enable the Data Register Empty and RX Complete Interrupt */
631 hw->TX_INTERRUPT_MASK.reg = SPI_TX_INTERRUPT_MASK_TX_FIFO_NOT_FULL_MASK;
632 hw->RX_INTERRUPT_MASK.reg = SPI_RX_INTERRUPT_MASK_RX_FIFO_NOT_EMPTY_MASK;
633 }
634
635 /**
636 * \brief Asynchronous buffer write
637 *
638 * Sets up the driver to write to the SPI from a given buffer. If registered
639 * and enabled, a callback function will be called when the write is finished.
640 *
641 * \param[in] module Pointer to SPI software instance struct
642 * \param[out] tx_data Pointer to data buffer to receive
643 * \param[in] length Data buffer length
644 *
645 * \returns Status of the write request operation.
646 * \retval STATUS_OK If the operation completed successfully
647 * \retval STATUS_ERR_BUSY If the SPI was already busy with a write
648 * operation
649 * \retval STATUS_ERR_INVALID_ARG If requested write length was zero
650 */
spi_write_buffer_job(struct spi_module * const module,uint8_t * tx_data,uint16_t length)651 enum status_code spi_write_buffer_job(
652 struct spi_module *const module,
653 uint8_t *tx_data,
654 uint16_t length)
655 {
656 Assert(module);
657 Assert(tx_data);
658
659 if (length == 0) {
660 return STATUS_ERR_INVALID_ARG;
661 }
662
663 /* Check if the SPI is busy transmitting or slave waiting for TXC*/
664 if (module->status == STATUS_BUSY) {
665 return STATUS_BUSY;
666 }
667
668 /* Issue internal write */
669 _spi_write_buffer(module, tx_data, length);
670
671 return STATUS_OK;
672 }
673
674 /**
675 * \brief Asynchronous buffer read
676 *
677 * Sets up the driver to read from the SPI to a given buffer. If registered
678 * and enabled, a callback function will be called when the read is finished.
679 *
680 * \note If address matching is enabled for the slave, the first character
681 * received and placed in the RX buffer will be the address.
682 *
683 * \param[in] module Pointer to SPI software instance struct
684 * \param[out] rx_data Pointer to data buffer to receive
685 * \param[in] length Data buffer length
686 * \param[in] dummy Dummy character to send when reading in master mode
687 *
688 * \returns Status of the operation.
689 * \retval STATUS_OK If the operation completed successfully
690 * \retval STATUS_ERR_BUSY If the SPI was already busy with a read
691 * operation
692 * \retval STATUS_ERR_DENIED If the receiver is not enabled
693 * \retval STATUS_ERR_INVALID_ARG If requested read length was zero
694 */
spi_read_buffer_job(struct spi_module * const module,uint8_t * rx_data,uint16_t length,uint16_t dummy)695 enum status_code spi_read_buffer_job(
696 struct spi_module *const module,
697 uint8_t *rx_data,
698 uint16_t length,
699 uint16_t dummy)
700 {
701 /* Sanity check arguments */
702 Assert(module);
703 Assert(rx_data);
704
705 if (length == 0) {
706 return STATUS_ERR_INVALID_ARG;
707 }
708
709 /* Check if the SPI is busy transmitting or slave waiting for TXC*/
710 if (module->status == STATUS_BUSY) {
711 return STATUS_BUSY;
712 }
713
714 dummy_write = dummy;
715 /* Issue internal read */
716 _spi_read_buffer(module, rx_data, length);
717 return STATUS_OK;
718 }
719
720 /**
721 * \brief Asynchronous buffer write and read
722 *
723 * Sets up the driver to write and read to and from given buffers. If registered
724 * and enabled, a callback function will be called when the transfer is finished.
725 *
726 * \note If address matching is enabled for the slave, the first character
727 * received and placed in the RX buffer will be the address.
728 *
729 * \param[in] module Pointer to SPI software instance struct
730 * \param[in] tx_data Pointer to data buffer to send
731 * \param[out] rx_data Pointer to data buffer to receive
732 * \param[in] length Data buffer length
733 *
734 * \returns Status of the operation.
735 * \retval STATUS_OK If the operation completed successfully
736 * \retval STATUS_ERR_BUSY If the SPI was already busy with a read
737 * operation
738 * \retval STATUS_ERR_DENIED If the receiver is not enabled
739 * \retval STATUS_ERR_INVALID_ARG If requested read length was zero
740 */
spi_transceive_buffer_job(struct spi_module * const module,uint8_t * tx_data,uint8_t * rx_data,uint16_t length)741 enum status_code spi_transceive_buffer_job(
742 struct spi_module *const module,
743 uint8_t *tx_data,
744 uint8_t *rx_data,
745 uint16_t length)
746 {
747 /* Sanity check arguments */
748 Assert(module);
749 Assert(rx_data);
750
751 if (length == 0) {
752 return STATUS_ERR_INVALID_ARG;
753 }
754
755 /* Check if the SPI is busy transmitting or slave waiting for TXC*/
756 if (module->status == STATUS_BUSY) {
757 return STATUS_BUSY;
758 }
759
760 /* Issue internal transceive */
761 _spi_transceive_buffer(module, tx_data, rx_data, length);
762
763 return STATUS_OK;
764 }
765