1 /*
2 * This file is part of the MicroPython project, http://micropython.org/
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (c) 2016-2018 Damien P. George
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
25 */
26
27 #include "drivers/bus/spi.h"
28
mp_soft_spi_ioctl(void * self_in,uint32_t cmd)29 int mp_soft_spi_ioctl(void *self_in, uint32_t cmd) {
30 mp_soft_spi_obj_t *self = (mp_soft_spi_obj_t*)self_in;
31
32 switch (cmd) {
33 case MP_SPI_IOCTL_INIT:
34 mp_hal_pin_write(self->sck, self->polarity);
35 mp_hal_pin_output(self->sck);
36 mp_hal_pin_output(self->mosi);
37 mp_hal_pin_input(self->miso);
38 break;
39
40 case MP_SPI_IOCTL_DEINIT:
41 break;
42 }
43
44 return 0;
45 }
46
mp_soft_spi_transfer(void * self_in,size_t len,const uint8_t * src,uint8_t * dest)47 void mp_soft_spi_transfer(void *self_in, size_t len, const uint8_t *src, uint8_t *dest) {
48 mp_soft_spi_obj_t *self = (mp_soft_spi_obj_t*)self_in;
49 uint32_t delay_half = self->delay_half;
50
51 // only MSB transfer is implemented
52
53 // If a port defines MICROPY_HW_SOFTSPI_MIN_DELAY, and the configured
54 // delay_half is equal to this value, then the software SPI implementation
55 // will run as fast as possible, limited only by CPU speed and GPIO time.
56 #ifdef MICROPY_HW_SOFTSPI_MIN_DELAY
57 if (delay_half == MICROPY_HW_SOFTSPI_MIN_DELAY) {
58 for (size_t i = 0; i < len; ++i) {
59 uint8_t data_out = src[i];
60 uint8_t data_in = 0;
61 for (int j = 0; j < 8; ++j, data_out <<= 1) {
62 mp_hal_pin_write(self->mosi, (data_out >> 7) & 1);
63 mp_hal_pin_write(self->sck, 1 - self->polarity);
64 data_in = (data_in << 1) | mp_hal_pin_read(self->miso);
65 mp_hal_pin_write(self->sck, self->polarity);
66 }
67 if (dest != NULL) {
68 dest[i] = data_in;
69 }
70 }
71 return;
72 }
73 #endif
74
75 for (size_t i = 0; i < len; ++i) {
76 uint8_t data_out = src[i];
77 uint8_t data_in = 0;
78 for (int j = 0; j < 8; ++j, data_out <<= 1) {
79 mp_hal_pin_write(self->mosi, (data_out >> 7) & 1);
80 if (self->phase == 0) {
81 mp_hal_delay_us_fast(delay_half);
82 mp_hal_pin_write(self->sck, 1 - self->polarity);
83 } else {
84 mp_hal_pin_write(self->sck, 1 - self->polarity);
85 mp_hal_delay_us_fast(delay_half);
86 }
87 data_in = (data_in << 1) | mp_hal_pin_read(self->miso);
88 if (self->phase == 0) {
89 mp_hal_delay_us_fast(delay_half);
90 mp_hal_pin_write(self->sck, self->polarity);
91 } else {
92 mp_hal_pin_write(self->sck, self->polarity);
93 mp_hal_delay_us_fast(delay_half);
94 }
95 }
96 if (dest != NULL) {
97 dest[i] = data_in;
98 }
99 }
100 }
101
102 const mp_spi_proto_t mp_soft_spi_proto = {
103 .ioctl = mp_soft_spi_ioctl,
104 .transfer = mp_soft_spi_transfer,
105 };
106