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