1 /*
2 * This file is part of the MicroPython project, http://micropython.org/
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright 2021 NXP
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 <zephyr.h>
32 #include <drivers/spi.h>
33
34 #include "py/runtime.h"
35 #include "py/gc.h"
36 #include "py/mphal.h"
37 #include "py/mperrno.h"
38 #include "extmod/machine_spi.h"
39 #include "modmachine.h"
40
41 #if MICROPY_PY_MACHINE_SPI
42
43 #define DEFAULT_SPI_BAUDRATE (50000)
44 #define DEFAULT_SPI_POLARITY (0)
45 #define DEFAULT_SPI_PHASE (0)
46 #define DEFAULT_SPI_BITS (8)
47 #define DEFAULT_SPI_FIRSTBIT (SPI_TRANSFER_MSB)
48 #define SPI_LOOP (0) // For testing, enable loop mode by setting SPI_LOOP (1)
49
50 typedef struct _machine_hard_spi_obj_t {
51 mp_obj_base_t base;
52 const struct device *dev;
53 struct spi_config config;
54 } machine_hard_spi_obj_t;
55
machine_hard_spi_print(const mp_print_t * print,mp_obj_t self_in,mp_print_kind_t kind)56 STATIC void machine_hard_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
57 machine_hard_spi_obj_t *self = self_in;
58 mp_printf(print, "SPI(%s, baudrate=%u, polarity=%u, phase=%u, bits=%u, firstbit=%s)",
59 self->dev->name,
60 self->config.frequency,
61 (self->config.operation & 0x2) >> 1,
62 (self->config.operation & 0x4) >> 2,
63 (self->config.operation & ~0x1F) >> 5,
64 ((self->config.operation & 0x10) >> 4) == SPI_TRANSFER_MSB ? "MSB" : "LSB");
65 }
66
machine_hard_spi_make_new(const mp_obj_type_t * type,size_t n_args,size_t n_kw,const mp_obj_t * all_args)67 mp_obj_t machine_hard_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
68 enum {ARG_id, ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit, ARG_sck, ARG_mosi, ARG_miso};
69
70 static const mp_arg_t allowed_args[] = {
71 { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_OBJ },
72 { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = DEFAULT_SPI_BAUDRATE} },
73 { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_SPI_POLARITY} },
74 { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_SPI_PHASE} },
75 { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_SPI_BITS} },
76 { MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_SPI_FIRSTBIT} },
77 { MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
78 { MP_QSTR_mosi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
79 { MP_QSTR_miso, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
80 };
81
82 mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
83 mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
84
85 const char *dev_name = mp_obj_str_get_str(args[ARG_id].u_obj);
86 const struct device *dev = device_get_binding(dev_name);
87
88 if (dev == NULL) {
89 mp_raise_ValueError(MP_ERROR_TEXT("device not found"));
90 }
91
92 if ((args[ARG_sck].u_obj != MP_OBJ_NULL) || (args[ARG_miso].u_obj != MP_OBJ_NULL) || (args[ARG_mosi].u_obj != MP_OBJ_NULL)) {
93 mp_raise_NotImplementedError(MP_ERROR_TEXT("explicit choice of sck/miso/mosi is not implemented"));
94 }
95
96 struct spi_config cfg = {
97 .frequency = args[ARG_baudrate].u_int,
98 .operation = (SPI_OP_MODE_MASTER |
99 args[ARG_polarity].u_int << 1 |
100 args[ARG_phase].u_int << 2 |
101 SPI_LOOP << 3 |
102 args[ARG_firstbit].u_int << 4 |
103 args[ARG_bits].u_int << 5 |
104 SPI_LINES_SINGLE),
105 .slave = 0,
106 .cs = NULL
107 };
108
109 machine_hard_spi_obj_t *self = m_new_obj(machine_hard_spi_obj_t);
110
111 self->base.type = &machine_hard_spi_type;
112 self->dev = dev;
113 self->config = cfg;
114
115 return MP_OBJ_FROM_PTR(self);
116 }
117
machine_hard_spi_init(mp_obj_base_t * obj,size_t n_args,const mp_obj_t * pos_args,mp_map_t * kw_args)118 STATIC void machine_hard_spi_init(mp_obj_base_t *obj, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
119 enum {ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit};
120
121 static const mp_arg_t allowed_args[] = {
122 { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
123 { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
124 { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
125 { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
126 { MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
127 };
128
129 mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
130 mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
131
132 machine_hard_spi_obj_t *self = (machine_hard_spi_obj_t *)obj;
133
134 uint32_t baudrate;
135 uint16_t operation = self->config.operation;
136
137 if (args[ARG_baudrate].u_int != -1) {
138 baudrate = args[ARG_baudrate].u_int;
139 } else {
140 baudrate = self->config.frequency;
141 }
142
143 if (args[ARG_polarity].u_int != -1) {
144 operation = (operation & ~0x2) | (args[ARG_polarity].u_int << 1);
145 }
146
147 if (args[ARG_phase].u_int != -1) {
148 operation = (operation & ~0x4) | (args[ARG_phase].u_int << 2);
149 }
150
151 if (args[ARG_bits].u_int != -1) {
152 operation = (operation & 0x1F) | (args[ARG_bits].u_int << 5);
153 }
154
155 if (args[ARG_firstbit].u_int != -1) {
156 operation = (operation & ~0x10) | (args[ARG_firstbit].u_int << 4);
157 }
158
159 struct spi_config cfg = {
160 .frequency = baudrate,
161 .operation = operation,
162 .slave = 0,
163 .cs = NULL
164 };
165
166 self->config = cfg;
167 }
168
machine_hard_spi_transfer(mp_obj_base_t * obj,size_t len,const uint8_t * src,uint8_t * dest)169 STATIC void machine_hard_spi_transfer(mp_obj_base_t *obj, size_t len, const uint8_t *src, uint8_t *dest) {
170 machine_hard_spi_obj_t *self = (machine_hard_spi_obj_t *)obj;
171
172 int ret;
173
174 struct spi_buf tx_bufs[1];
175 tx_bufs[0].buf = (uint8_t *)src;
176 tx_bufs[0].len = len;
177 const struct spi_buf_set tx = {
178 .buffers = tx_bufs,
179 .count = ARRAY_SIZE(tx_bufs)
180 };
181
182 struct spi_buf rx_bufs[1];
183 rx_bufs[0].buf = dest;
184 rx_bufs[0].len = len;
185 const struct spi_buf_set rx = {
186 .buffers = rx_bufs,
187 .count = ARRAY_SIZE(rx_bufs)
188 };
189
190 ret = spi_transceive(self->dev, &self->config, &tx, &rx);
191
192 if (ret < 0) {
193 mp_raise_OSError(-ret);
194 }
195 }
196
197 STATIC const mp_machine_spi_p_t machine_hard_spi_p = {
198 .init = machine_hard_spi_init,
199 .transfer = machine_hard_spi_transfer,
200 };
201
202 const mp_obj_type_t machine_hard_spi_type = {
203 { &mp_type_type },
204 .name = MP_QSTR_SPI,
205 .print = machine_hard_spi_print,
206 .make_new = machine_hard_spi_make_new,
207 .protocol = &machine_hard_spi_p,
208 .locals_dict = (mp_obj_dict_t *)&mp_machine_spi_locals_dict,
209 };
210
211 #endif // MICROPY_PY_MACHINE_SPI
212