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