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