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