1 /*
2  * This file is part of the MicroPython project, http://micropython.org/
3  *
4  * The MIT License (MIT)
5  *
6  * Copyright (c) 2017 "Eric Poulsen" <eric@zyxod.com>
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 <stdio.h>
28 #include <stdint.h>
29 #include <string.h>
30 
31 #include "py/runtime.h"
32 #include "py/stream.h"
33 #include "py/mphal.h"
34 #include "extmod/machine_spi.h"
35 #include "modmachine.h"
36 
37 #include "aos_hal_spi.h"
38 #include "ulog/ulog.h"
39 
40 #if MICROPY_PY_MACHINE
41 
42 #define LOG_TAG "machine_hw_spi"
43 
44 typedef enum{
45     SPI_NUM_0 = 0,  /*!< SPI port 0 */
46     SPI_NUM_1 ,     /*!< SPI port 1 */
47     SPI_NUM_MAX
48 } spi_port_t;
49 
50 typedef struct _machine_hw_spi_obj_t {
51     mp_obj_base_t base;
52     uint8_t port;
53     spi_dev_t spi;
54 } machine_hw_spi_obj_t;
55 
56 // Static objects mapping to HSPI and VSPI hardware peripherals
57 STATIC machine_hw_spi_obj_t machine_hw_spi_obj[2] = {0};
58 
machine_hw_spi_deinit_internal(machine_hw_spi_obj_t * self)59 STATIC void machine_hw_spi_deinit_internal(machine_hw_spi_obj_t *self) {
60     spi_dev_t *spi = &self->spi;
61     aos_hal_spi_finalize(spi);
62     self->base.type = NULL;
63 }
64 
machine_hw_spi_init_internal(machine_hw_spi_obj_t * self,bool first_init)65 STATIC int32_t machine_hw_spi_init_internal(machine_hw_spi_obj_t *self, bool first_init) {
66     spi_dev_t *spi = &self->spi;
67     int32_t ret = -1;
68 
69     if (!first_init) {
70         ret = aos_hal_spi_finalize(spi);
71         if(ret != 0) {
72             LOGE(LOG_TAG, "aos_hal_spi_finalize fail, ret = %d\n", ret);
73         }
74         self->base.type = NULL;
75         return ret;
76     }
77 
78     // Initialize the SPI bus
79     ret = aos_hal_spi_init(spi);
80     if(ret != 0) {
81         mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("invalid configuration"));
82     }
83 
84     return ret;
85 }
86 
machine_hw_spi_deinit(mp_obj_base_t * self_in)87 STATIC void machine_hw_spi_deinit(mp_obj_base_t *self_in) {
88     machine_hw_spi_obj_t *self = (machine_hw_spi_obj_t *)self_in;
89     spi_dev_t *spi = &self->spi;
90 
91     int32_t ret = aos_hal_spi_finalize(spi);
92     if(ret != 0) {
93         LOGE(LOG_TAG, "aos_hal_spi_finalize fail, ret = %d\n", ret);
94     }
95     self->base.type = NULL;
96 }
97 
machine_hw_spi_transfer(mp_obj_base_t * self_in,size_t len,const uint8_t * src,uint8_t * dest)98 STATIC void machine_hw_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) {
99     machine_hw_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
100     spi_dev_t *spi = &self->spi;
101     int32_t ret = -1;
102 
103     MP_THREAD_GIL_EXIT();
104     if(dest == NULL) {  // send operation
105         ret = aos_hal_spi_send(spi, src, len, HAL_WAIT_FOREVER);
106         if(ret != 0 ) {
107             LOGE(LOG_TAG, "aos_hal_spi_send fail, ret = %d\n", ret);
108         }
109     } else if(src == dest) {
110         ret = aos_hal_spi_recv(spi, dest, len, HAL_WAIT_FOREVER);
111         if(ret != 0 ) {
112             LOGE(LOG_TAG, "aos_hal_spi_recv fail, ret = %d\n", ret);
113         }
114     } else {
115         ret = aos_hal_spi_send_recv(spi, (uint8_t *)src, dest, len, HAL_WAIT_FOREVER);
116         if(ret != 0 ) {
117             LOGE(LOG_TAG, "aos_hal_spi_send_recv fail, ret = %d\n", ret);
118         }
119     }
120     MP_THREAD_GIL_ENTER();
121 }
122 
123 /******************************************************************************/
124 // MicroPython bindings for hw_spi
125 
machine_hw_spi_print(const mp_print_t * print,mp_obj_t self_in,mp_print_kind_t kind)126 STATIC void machine_hw_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
127     machine_hw_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
128     spi_dev_t *spi = &self->spi;
129     spi_config_t *cfg = &spi->config;
130     mp_printf(print, "SPI(id=%u, role=%u, polarity=%u, mode=%u, t_mode=%u, freq=%u, serial_len=%d, data_size=%d, cs=%d)",
131         spi->port, cfg->role, cfg->firstbit, cfg->mode, cfg->t_mode, cfg->freq, cfg->serial_len, cfg->data_size, cfg->cs);
132 }
133 
machine_hw_spi_init(mp_obj_base_t * self_in,size_t n_args,const mp_obj_t * pos_args,mp_map_t * kw_args)134 STATIC void machine_hw_spi_init(mp_obj_base_t *self_in, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
135     machine_hw_spi_obj_t *self = (machine_hw_spi_obj_t *)self_in;
136 
137     enum { ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit, ARG_mode, ARG_len};
138     static const mp_arg_t allowed_args[] = {
139         { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 500000} },
140         { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
141         { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
142         { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SPI_DATA_SIZE_8BIT} },
143         { MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = MICROPY_PY_MACHINE_SPI_MSB} },
144         { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SPI_ROLE_MASTER} },
145         { MP_QSTR_len, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_SPI_SERAIL_LEN} },
146     };
147 
148     mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
149     mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
150 
151     spi_dev_t *spi = &self->spi;
152 
153     spi->config.role = args[ARG_mode].u_int;
154     spi->config.firstbit = args[ARG_firstbit].u_int;
155     spi->config.mode = (args[ARG_phase].u_int << 1) | args[ARG_polarity].u_int;
156     spi->config.freq = args[ARG_baudrate].u_int;
157     spi->config.serial_len = args[ARG_len].u_int;
158     spi->config.data_size = args[ARG_bits].u_int;
159 
160     machine_hw_spi_init_internal(self, false);
161 }
162 
machine_hw_spi_make_new(const mp_obj_type_t * type,size_t n_args,size_t n_kw,const mp_obj_t * all_args)163 mp_obj_t machine_hw_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
164 
165     enum { ARG_id, ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit, ARG_mode, ARG_len, ARG_sck, ARG_mosi, ARG_miso};
166     static const mp_arg_t allowed_args[] = {
167         { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_int = 0} },
168         { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 500000} },
169         { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
170         { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
171         { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SPI_DATA_SIZE_8BIT} },
172         { MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = MICROPY_PY_MACHINE_SPI_MSB} },
173         { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SPI_ROLE_MASTER} },
174         { MP_QSTR_len, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_SPI_SERAIL_LEN} },
175         { MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
176         { MP_QSTR_mosi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
177         { MP_QSTR_miso, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
178     };
179     mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
180     mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
181 
182     // Get SPI bus
183     mp_int_t port = mp_obj_get_int(args[ARG_id].u_obj);
184     if (!(SPI_NUM_0 <= port && port < SPI_NUM_MAX)) {
185         mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("SPI(%d) doesn't exist"), port);
186     }
187 
188     machine_hw_spi_obj_t *self;
189     if (port == 0) {
190         self = &machine_hw_spi_obj[0];
191     } else {
192         self = &machine_hw_spi_obj[1];
193     }
194     self->port = port;
195 
196     bool first_init = false;
197     if (self->base.type == NULL) {
198         // Created for the first time, set default pins
199         self->base.type = &machine_hw_spi_type;
200         first_init = true;
201     }
202 
203     spi_dev_t *spi = &self->spi;
204     spi->port = port;
205     spi->config.role = args[ARG_mode].u_int;
206     spi->config.firstbit = args[ARG_firstbit].u_int;
207     spi->config.mode = (args[ARG_phase].u_int << 1) | args[ARG_polarity].u_int;
208     spi->config.t_mode = SPI_TRANSFER_DMA;
209     spi->config.freq = args[ARG_baudrate].u_int;
210     spi->config.serial_len = args[ARG_len].u_int;
211     spi->config.data_size = args[ARG_bits].u_int;
212     spi->config.cs = SPI_CS_EN;
213     spi->priv = NULL;
214 
215     machine_hw_spi_init_internal(self, first_init);
216 
217     return MP_OBJ_FROM_PTR(self);
218 }
219 
220 STATIC const mp_machine_spi_p_t machine_hw_spi_p = {
221     .init = machine_hw_spi_init,
222     .deinit = machine_hw_spi_deinit,
223     .transfer = machine_hw_spi_transfer,
224 };
225 
226 const mp_obj_type_t machine_hw_spi_type = {
227     { &mp_type_type },
228     .name = MP_QSTR_SPI,
229     .print = machine_hw_spi_print,
230     .make_new = machine_hw_spi_make_new,
231     .protocol = &machine_hw_spi_p,
232     .locals_dict = (mp_obj_dict_t *)&mp_machine_spi_locals_dict,
233 };
234 
235 #endif