From aba75e12330d8e80b2d909ace0a419de85774317 Mon Sep 17 00:00:00 2001 From: Daniel Campora Date: Sun, 13 Sep 2015 21:44:09 +0200 Subject: [PATCH] cc3200: New SPI API. --- cc3200/mods/pybspi.c | 321 ++++++++++++++++----------------------- cc3200/mods/pybuart.c | 4 +- cc3200/qstrdefsport.h | 17 ++- docs/library/pyb.SPI.rst | 129 +++++++++------- tests/wipy/spi.py | 149 ++++++++++++++++++ tests/wipy/spi.py.exp | 35 +++++ 6 files changed, 403 insertions(+), 252 deletions(-) create mode 100644 tests/wipy/spi.py create mode 100644 tests/wipy/spi.py.exp diff --git a/cc3200/mods/pybspi.c b/cc3200/mods/pybspi.c index fcd121b38..20ba04cb4 100644 --- a/cc3200/mods/pybspi.c +++ b/cc3200/mods/pybspi.c @@ -43,28 +43,11 @@ #include "pybspi.h" #include "mpexception.h" #include "pybsleep.h" +#include "pybpin.h" +#include "pins.h" /// \moduleref pyb /// \class SPI - a master-driven serial protocol -/// -/// SPI is a serial protocol that is driven by a master. At the physical level -/// there are 3 lines: SCK, MOSI, MISO. -/// -/// See usage model of I2C; SPI is very similar. Main difference is -/// parameters to init the SPI bus: -/// -/// from pyb import SPI -/// spi = SPI(1, SPI.MASTER, baudrate=2000000, bits=8, polarity=0, phase=0, cs_polarity=SPI.ACTIVE_LOW) -/// -/// Only required parameter is the baudrate, in Hz. polarity and phase may be 0 or 1. -/// Bit accepts 8, 16, 32. Chip select values are ACTIVE_LOW and ACTIVE_HIGH -/// -/// Additional method for SPI: -/// -/// data = spi.send_recv(b'1234') # send 4 bytes and receive 4 bytes -/// buf = bytearray(4) -/// spi.send_recv(b'1234', buf) # send 4 bytes and receive 4 into buf -/// spi.send_recv(buf, buf) # send/recv 4 bytes from/to buf /****************************************************************************** DEFINE TYPES @@ -73,10 +56,6 @@ typedef struct _pyb_spi_obj_t { mp_obj_base_t base; uint baudrate; uint config; - vstr_t tx_vstr; - vstr_t rx_vstr; - uint tx_index; - uint rx_index; byte polarity; byte phase; byte submode; @@ -86,13 +65,15 @@ typedef struct _pyb_spi_obj_t { /****************************************************************************** DEFINE CONSTANTS ******************************************************************************/ -#define PYBSPI_DEF_BAUDRATE 1000000 // 1MHz +#define PYBSPI_FIRST_BIT_MSB 0 /****************************************************************************** DECLARE PRIVATE DATA ******************************************************************************/ STATIC pyb_spi_obj_t pyb_spi_obj = {.baudrate = 0}; +STATIC const mp_obj_t pyb_spi_def_pin[3] = {&pin_GP14, &pin_GP16, &pin_GP30}; + /****************************************************************************** DEFINE PRIVATE FUNCTIONS ******************************************************************************/ @@ -112,21 +93,19 @@ STATIC void pybspi_init (const pyb_spi_obj_t *self) { } STATIC void pybspi_tx (pyb_spi_obj_t *self, const void *data) { - uint32_t txdata = 0xFFFFFFFF; - if (data) { - switch (self->wlen) { - case 1: - txdata = (uint8_t)(*(char *)data); - break; - case 2: - txdata = (uint16_t)(*(uint16_t *)data); - break; - case 4: - txdata = (uint32_t)(*(uint32_t *)data); - break; - default: - return; - } + uint32_t txdata; + switch (self->wlen) { + case 1: + txdata = (uint8_t)(*(char *)data); + break; + case 2: + txdata = (uint16_t)(*(uint16_t *)data); + break; + case 4: + txdata = (uint32_t)(*(uint32_t *)data); + break; + default: + return; } MAP_SPIDataPut (GSPI_BASE, txdata); } @@ -151,11 +130,14 @@ STATIC void pybspi_rx (pyb_spi_obj_t *self, void *data) { } } -STATIC void pybspi_transfer (pyb_spi_obj_t *self, const char *txdata, char *rxdata, uint32_t len) { +STATIC void pybspi_transfer (pyb_spi_obj_t *self, const char *txdata, char *rxdata, uint32_t len, uint32_t *txchar) { + if (!self->baudrate) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible)); + } // send and receive the data MAP_SPICSEnable(GSPI_BASE); - for (int i = 0; i < len / self->wlen; i += self->wlen) { - pybspi_tx(self, txdata ? (const void *)&txdata[i] : NULL); + for (int i = 0; i < len; i += self->wlen) { + pybspi_tx(self, txdata ? (const void *)&txdata[i] : txchar); pybspi_rx(self, rxdata ? (void *)&rxdata[i] : NULL); } MAP_SPICSDisable(GSPI_BASE); @@ -166,40 +148,15 @@ STATIC void pybspi_transfer (pyb_spi_obj_t *self, const char *txdata, char *rxda /******************************************************************************/ STATIC void pyb_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { pyb_spi_obj_t *self = self_in; - if (self->baudrate > 0) { - mp_printf(print, "", - self->baudrate, (self->wlen * 8), self->polarity, self->phase, - (self->config & SPI_CS_ACTIVELOW) ? MP_QSTR_ACTIVE_LOW : MP_QSTR_ACTIVE_HIGH); + mp_printf(print, "SPI(0, SPI.MASTER, baudrate=%u, bits=%u, polarity=%u, phase=%u, firstbit=SPI.MSB)", + self->baudrate, (self->wlen * 8), self->polarity, self->phase); } else { - mp_print_str(print, ""); + mp_print_str(print, "SPI(0)"); } } -/// \method init(mode, *, baudrate=1000000, bits=8, polarity=0, phase=0, cs_polarity=SPI.ACTIVE_LOW) -/// -/// Initialise the SPI bus with the given parameters: -/// -/// - `mode` must be MASTER. -/// - `baudrate` is the SCK clock rate. -/// - `bits` is the transfer width size (8, 16, 32). -/// - `polarity` (0, 1). -/// - `phase` (0, 1). -/// - `cs_polarity` can be ACTIVE_LOW or ACTIVE_HIGH. -static const mp_arg_t pybspi_init_args[] = { - { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT, }, - { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = PYBSPI_DEF_BAUDRATE} }, - { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, - { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_cs_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SPI_CS_ACTIVELOW} }, -}; - -STATIC mp_obj_t pyb_spi_init_helper(pyb_spi_obj_t *self, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - // parse args - mp_arg_val_t args[MP_ARRAY_SIZE(pybspi_init_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(pybspi_init_args), pybspi_init_args, args); - +STATIC mp_obj_t pyb_spi_init_helper(pyb_spi_obj_t *self, mp_arg_val_t *args) { // verify that mode is master if (args[0].u_int != SPI_MODE_MASTER) { goto invalid_args; @@ -227,19 +184,36 @@ STATIC mp_obj_t pyb_spi_init_helper(pyb_spi_obj_t *self, mp_uint_t n_args, const goto invalid_args; } - uint cs = args[5].u_int; - if (cs != SPI_CS_ACTIVELOW && cs != SPI_CS_ACTIVEHIGH) { + uint firstbit = args[5].u_int; + if (firstbit != PYBSPI_FIRST_BIT_MSB) { goto invalid_args; } // build the configuration self->baudrate = args[1].u_int; self->wlen = args[2].u_int >> 3; - self->config = bits | cs | SPI_SW_CTRL_CS | SPI_4PIN_MODE | SPI_TURBO_OFF; + self->config = bits | SPI_CS_ACTIVELOW | SPI_SW_CTRL_CS | SPI_4PIN_MODE | SPI_TURBO_OFF; self->polarity = polarity; self->phase = phase; self->submode = (polarity << 1) | phase; + // assign the pins + mp_obj_t pins_o = args[6].u_obj; + if (pins_o != mp_const_none) { + mp_obj_t *pins; + mp_uint_t n_pins = 3; + if (pins_o == MP_OBJ_NULL) { + // use the default pins + pins = (mp_obj_t *)pyb_spi_def_pin; + } else { + mp_obj_get_array(pins_o, &n_pins, &pins); + if (n_pins != 3) { + goto invalid_args; + } + } + pin_assign_pins_af (pins, n_pins, PIN_TYPE_STD_PU, PIN_FN_SPI, 0); + } + // init the bus pybspi_init((const pyb_spi_obj_t *)self); @@ -252,32 +226,43 @@ invalid_args: nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); } -/// \classmethod \constructor(bus, ...) -/// -/// Construct an SPI object with the given baudrate. Bus can only be 1. -/// With no extra parameters, the SPI object is created but not -/// initialised (it has the settings from the last initialisation of -/// the bus, if any). If extra arguments are given, the bus is initialised. -/// See `init` for parameters of initialisation. -STATIC mp_obj_t pyb_spi_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { - // check arguments - mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); +static const mp_arg_t pyb_spi_init_args[] = { + { MP_QSTR_id, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_mode, MP_ARG_INT, {.u_int = SPI_MODE_MASTER} }, + { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1000000} }, // 1MHz + { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, + { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = PYBSPI_FIRST_BIT_MSB} }, + { MP_QSTR_pins, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, +}; +STATIC mp_obj_t pyb_spi_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *all_args) { + // parse args + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, all_args + n_args); + mp_arg_val_t args[MP_ARRAY_SIZE(pyb_spi_init_args)]; + mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), pyb_spi_init_args, args); + // check the peripheral id + if (args[0].u_int != 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); + } + + // setup the object pyb_spi_obj_t *self = &pyb_spi_obj; self->base.type = &pyb_spi_type; - if (n_args > 1 || n_kw > 0) { - // start the peripheral - mp_map_t kw_args; - mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); - pyb_spi_init_helper(self, n_args - 1, args + 1, &kw_args); - } + // start the peripheral + pyb_spi_init_helper(self, &args[1]); return self; } -STATIC mp_obj_t pyb_spi_init(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { - return pyb_spi_init_helper(args[0], n_args - 1, args + 1, kw_args); +STATIC mp_obj_t pyb_spi_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(pyb_spi_init_args) - 1]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), &pyb_spi_init_args[1], args); + return pyb_spi_init_helper(pos_args[0], args); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_init_obj, 1, pyb_spi_init); @@ -295,152 +280,112 @@ STATIC mp_obj_t pyb_spi_deinit(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_spi_deinit_obj, pyb_spi_deinit); -/// \method send(send, *, timeout=5000) -/// Send data on the bus: -/// -/// - `send` is the data to send (a byte to send, or a buffer object). -/// - `timeout` is the timeout in milliseconds to wait for the send. -/// -STATIC mp_obj_t pyb_spi_send (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - static const mp_arg_t allowed_args[] = { - { MP_QSTR_send, MP_ARG_REQUIRED | MP_ARG_OBJ, }, - { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, - }; - +STATIC mp_obj_t pyb_spi_write (mp_obj_t self_in, mp_obj_t buf) { // parse args - pyb_spi_obj_t *self = pos_args[0]; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + pyb_spi_obj_t *self = self_in; // get the buffer to send from mp_buffer_info_t bufinfo; uint8_t data[1]; - pyb_buf_get_for_send(args[0].u_obj, &bufinfo, data); + pyb_buf_get_for_send(buf, &bufinfo, data); // just send - pybspi_transfer(self, (const char *)bufinfo.buf, NULL, bufinfo.len); + pybspi_transfer(self, (const char *)bufinfo.buf, NULL, bufinfo.len, NULL); - return mp_const_none; + // return the number of bytes written + return mp_obj_new_int(bufinfo.len); } -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_send_obj, 1, pyb_spi_send); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_spi_write_obj, pyb_spi_write); -/// \method recv(recv, *, timeout=5000) -/// -/// Receive data on the bus: -/// -/// - `recv` can be an integer, which is the number of bytes to receive, -/// or a mutable buffer, which will be filled with received bytes. -/// - `timeout` is the timeout in milliseconds to wait for the receive. -/// -/// Return: if `recv` is an integer then a new buffer of the bytes received, -/// otherwise the same buffer that was passed in to `recv`. -STATIC mp_obj_t pyb_spi_recv(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +STATIC mp_obj_t pyb_spi_read(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { - { MP_QSTR_recv, MP_ARG_REQUIRED | MP_ARG_OBJ, }, - { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, + { MP_QSTR_nbytes, MP_ARG_REQUIRED | MP_ARG_OBJ, }, + { MP_QSTR_write, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0x00} }, }; // parse args pyb_spi_obj_t *self = pos_args[0]; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), allowed_args, args); // get the buffer to receive into vstr_t vstr; - mp_obj_t o_ret = pyb_buf_get_for_recv(args[0].u_obj, &vstr); + pyb_buf_get_for_recv(args[0].u_obj, &vstr); // just receive - pybspi_transfer(self, NULL, vstr.buf, vstr.len); + uint32_t write = args[1].u_int; + pybspi_transfer(self, NULL, vstr.buf, vstr.len, &write); // return the received data - if (o_ret != MP_OBJ_NULL) { - return o_ret; - } else { - return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); - } + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); } -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_recv_obj, 1, pyb_spi_recv); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_read_obj, 1, pyb_spi_read); -/// \method send_recv(send, recv=None, *, timeout=5000) -/// -/// Send and receive data on the bus at the same time: -/// -/// - `send` is the data to send (an integer to send, or a buffer object). -/// - `recv` is a mutable buffer which will be filled with received bytes. -/// It can be the same as `send`, or omitted. If omitted, a new buffer will -/// be created. -/// - `timeout` is the timeout in milliseconds to wait for the transaction to complete. -/// -/// Return: the buffer with the received bytes. -STATIC mp_obj_t pyb_spi_send_recv (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +STATIC mp_obj_t pyb_spi_readinto(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { - { MP_QSTR_send, MP_ARG_REQUIRED | MP_ARG_OBJ, }, - { MP_QSTR_recv, MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, + { MP_QSTR_buf, MP_ARG_REQUIRED | MP_ARG_OBJ, }, + { MP_QSTR_write, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0x00} }, }; // parse args pyb_spi_obj_t *self = pos_args[0]; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), allowed_args, args); - // get buffers to send from/receive to - mp_buffer_info_t bufinfo_send; + // get the buffer to receive into + vstr_t vstr; + pyb_buf_get_for_recv(args[0].u_obj, &vstr); + + // just receive + uint32_t write = args[1].u_int; + pybspi_transfer(self, NULL, vstr.buf, vstr.len, &write); + + // return the number of bytes received + return mp_obj_new_int(vstr.len); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_readinto_obj, 1, pyb_spi_readinto); + +STATIC mp_obj_t pyb_spi_write_readinto (mp_obj_t self, mp_obj_t writebuf, mp_obj_t readbuf) { + // get buffers to write from/read to + mp_buffer_info_t bufinfo_write; uint8_t data_send[1]; - mp_buffer_info_t bufinfo_recv; - vstr_t vstr_recv; - mp_obj_t o_ret; + mp_buffer_info_t bufinfo_read; - if (args[0].u_obj == args[1].u_obj) { - // same object for sending and receiving, it must be a r/w buffer - mp_get_buffer_raise(args[0].u_obj, &bufinfo_send, MP_BUFFER_RW); - bufinfo_recv = bufinfo_send; - o_ret = args[0].u_obj; + if (writebuf == readbuf) { + // same object for writing and reading, it must be a r/w buffer + mp_get_buffer_raise(writebuf, &bufinfo_write, MP_BUFFER_RW); + bufinfo_read = bufinfo_write; } else { - // get the buffer to send from - pyb_buf_get_for_send(args[0].u_obj, &bufinfo_send, data_send); + // get the buffer to write from + pyb_buf_get_for_send(writebuf, &bufinfo_write, data_send); - // get the buffer to receive into - if (args[1].u_obj == mp_const_none) { - // only the send was argument given, so create a fresh buffer of the send length - vstr_init_len(&vstr_recv, bufinfo_send.len); - bufinfo_recv.len = vstr_recv.len; - bufinfo_recv.buf = vstr_recv.buf; - o_ret = MP_OBJ_NULL; - } else { - // recv argument given - mp_get_buffer_raise(args[1].u_obj, &bufinfo_recv, MP_BUFFER_WRITE); - if (bufinfo_recv.len != bufinfo_send.len) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); - } - o_ret = args[1].u_obj; + // get the read buffer + mp_get_buffer_raise(readbuf, &bufinfo_read, MP_BUFFER_WRITE); + if (bufinfo_read.len != bufinfo_write.len) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); } } // send and receive - pybspi_transfer(self, (const char *)bufinfo_send.buf, bufinfo_recv.buf, bufinfo_send.len); + pybspi_transfer(self, (const char *)bufinfo_write.buf, bufinfo_read.buf, bufinfo_write.len, NULL); - // return the received data - if (o_ret != MP_OBJ_NULL) { - return o_ret; - } else { - return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr_recv); - } + // return the number of transferred bytes + return mp_obj_new_int(bufinfo_write.len); } -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_send_recv_obj, 1, pyb_spi_send_recv); +STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_spi_write_readinto_obj, pyb_spi_write_readinto); STATIC const mp_map_elem_t pyb_spi_locals_dict_table[] = { // instance methods { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_spi_init_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&pyb_spi_deinit_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&pyb_spi_send_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&pyb_spi_recv_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_send_recv), (mp_obj_t)&pyb_spi_send_recv_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&pyb_spi_write_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&pyb_spi_read_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_readinto), (mp_obj_t)&pyb_spi_readinto_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_write_readinto), (mp_obj_t)&pyb_spi_write_readinto_obj }, // class constants { MP_OBJ_NEW_QSTR(MP_QSTR_MASTER), MP_OBJ_NEW_SMALL_INT(SPI_MODE_MASTER) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ACTIVE_LOW), MP_OBJ_NEW_SMALL_INT(SPI_CS_ACTIVELOW) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ACTIVE_HIGH), MP_OBJ_NEW_SMALL_INT(SPI_CS_ACTIVEHIGH) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_MSB), MP_OBJ_NEW_SMALL_INT(PYBSPI_FIRST_BIT_MSB) }, }; STATIC MP_DEFINE_CONST_DICT(pyb_spi_locals_dict, pyb_spi_locals_dict_table); diff --git a/cc3200/mods/pybuart.c b/cc3200/mods/pybuart.c index 5c4aa1923..b1d74785b 100644 --- a/cc3200/mods/pybuart.c +++ b/cc3200/mods/pybuart.c @@ -454,7 +454,7 @@ STATIC mp_obj_t pyb_uart_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), pyb_uart_init_args, args); // work out the uart id - uint8_t uart_id; + uint uart_id; if (args[0].u_obj == mp_const_none) { if (args[5].u_obj != MP_OBJ_NULL) { mp_obj_t *pins; @@ -474,7 +474,7 @@ STATIC mp_obj_t pyb_uart_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t uart_id = mp_obj_get_int(args[0].u_obj); } - if (uart_id < PYB_UART_0 || uart_id > PYB_UART_1) { + if (uart_id > PYB_UART_1) { nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); } diff --git a/cc3200/qstrdefsport.h b/cc3200/qstrdefsport.h index 485ff4ec5..9d7e1ac64 100644 --- a/cc3200/qstrdefsport.h +++ b/cc3200/qstrdefsport.h @@ -339,21 +339,24 @@ Q(RTC_WAKE) // for SPI class Q(SPI) +Q(id) Q(mode) Q(baudrate) Q(bits) Q(polarity) Q(phase) -Q(cs_polarity) +Q(firstbit) Q(init) Q(deinit) -Q(send) -Q(recv) -Q(send_recv) -Q(timeout) +Q(write) +Q(read) +Q(readinto) +Q(write_readinto) +Q(nbytes) +Q(write) +Q(buf) Q(MASTER) -Q(ACTIVE_LOW) -Q(ACTIVE_HIGH) +Q(MSB) // for Timer class Q(Timer) diff --git a/docs/library/pyb.SPI.rst b/docs/library/pyb.SPI.rst index 37fdba921..3c540b279 100644 --- a/docs/library/pyb.SPI.rst +++ b/docs/library/pyb.SPI.rst @@ -10,7 +10,7 @@ there are 3 lines: SCK, MOSI, MISO. See usage model of I2C; SPI is very similar. Main difference is parameters to init the SPI bus:: - + from pyb import SPI spi = SPI(1, SPI.MASTER, baudrate=600000, polarity=1, phase=0, crc=0x7) @@ -19,44 +19,43 @@ there are 3 lines: SCK, MOSI, MISO. to sample data on the first or second clock edge respectively. Crc can be None for no CRC, or a polynomial specifier. + Additional methods for SPI:: + + data = spi.send_recv(b'1234') # send 4 bytes and receive 4 bytes + buf = bytearray(4) + spi.send_recv(b'1234', buf) # send 4 bytes and receive 4 into buf + spi.send_recv(buf, buf) # send/recv 4 bytes from/to buf + .. only:: port_wipy See usage model of I2C; SPI is very similar. Main difference is parameters to init the SPI bus:: - + from pyb import SPI - spi = SPI(1, SPI.MASTER, baudrate=1000000, polarity=0, phase=0, cs_polarity=SPI.ACTIVE_LOW) + spi = SPI(1, SPI.MASTER, baudrate=1000000, polarity=0, phase=0, firstbit=SPI.MSB) Only required parameter is mode, must be SPI.MASTER. Polarity can be 0 or 1, and is the level the idle clock line sits at. Phase can be 0 or 1 to sample data on the first or second clock edge respectively. -Additional methods for SPI:: - - data = spi.send_recv(b'1234') # send 4 bytes and receive 4 bytes - buf = bytearray(4) - spi.send_recv(b'1234', buf) # send 4 bytes and receive 4 into buf - spi.send_recv(buf, buf) # send/recv 4 bytes from/to buf - - Constructors ------------ .. only:: port_pyboard .. class:: pyb.SPI(bus, ...) - + Construct an SPI object on the given bus. ``bus`` can be 1 or 2. With no additional parameters, the SPI object is created but not initialised (it has the settings from the last initialisation of the bus, if any). If extra arguments are given, the bus is initialised. See ``init`` for parameters of initialisation. - + The physical pins of the SPI busses are: - + - ``SPI(1)`` is on the X position: ``(NSS, SCK, MISO, MOSI) = (X5, X6, X7, X8) = (PA4, PA5, PA6, PA7)`` - ``SPI(2)`` is on the Y position: ``(NSS, SCK, MISO, MOSI) = (Y5, Y6, Y7, Y8) = (PB12, PB13, PB14, PB15)`` - + At the moment, the NSS pin is not used by the SPI driver and is free for other use. @@ -76,13 +75,13 @@ Methods .. method:: spi.deinit() Turn off the SPI bus. - + .. only:: port_pyboard .. method:: spi.init(mode, baudrate=328125, \*, prescaler, polarity=1, phase=0, bits=8, firstbit=SPI.MSB, ti=False, crc=None) - + Initialise the SPI bus with the given parameters: - + - ``mode`` must be either ``SPI.MASTER`` or ``SPI.SLAVE``. - ``baudrate`` is the SCK clock rate (only sensible for a master). - ``prescaler`` is the prescaler to use to derive SCK from the APB bus frequency; @@ -92,66 +91,87 @@ Methods respectively. - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. - ``crc`` can be None for no CRC, or a polynomial specifier. - + Note that the SPI clock frequency will not always be the requested baudrate. The hardware only supports baudrates that are the APB bus frequency (see :meth:`pyb.freq`) divided by a prescaler, which can be 2, 4, 8, 16, 32, 64, 128 or 256. SPI(1) is on AHB2, and SPI(2) is on AHB1. For precise control over the SPI clock frequency, specify ``prescaler`` instead of ``baudrate``. - + Printing the SPI object will show you the computed baudrate and the chosen prescaler. .. only:: port_wipy - .. method:: spi.init(mode, baudrate=1000000, \*, polarity=0, phase=0, bits=8, nss=SPI.ACTIVE_LOW) - + .. method:: spi.init(mode, baudrate=1000000, \*, polarity=0, phase=0, bits=8, firstbit=SPI.MSB, pins=(CLK, MOSI, MISO)) + Initialise the SPI bus with the given parameters: - + - ``mode`` must be ``SPI.MASTER``. - ``baudrate`` is the SCK clock rate. - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. - ``phase`` can be 0 or 1 to sample data on the first or second clock edge respectively. - ``bits`` is the width of each transfer, accepted values are 8, 16 and 32. - - ``cs_polarity`` can be ``SPI.ACTIVE_LOW`` or ``SPI.ACTIVE_HIGH``. + - ``firstbit`` can be ``SPI.MSB`` only. + - ``pins`` is an optional tupple with the pins to assign to the SPI bus. + + .. method:: spi.write(buf) + + Write the data contained in ``buf``. + Returns the number of bytes written. + + .. method:: spi.read(nbytes, *, write=0x00) + + Read the ``nbytes`` while writing the data specified by ``write``. + Return the number of bytes read. + + .. method:: spi.readinto(buf, *, write=0x00) + + Read into the buffer specified by ``buf`` while writing the data specified by + ``write``. + Return the number of bytes read. + + .. method:: spi.write_readinto(write_buf, read_buf) + + Write from ``write_buf`` and read into ``read_buf``. Both buffers must have the + same length. + Returns the number of bytes written + +.. only:: port_pyboard + + .. method:: spi.recv(recv, \*, timeout=5000) - Note that the SPI clock frequency will not always be the requested baudrate. - Printing the SPI object will show you the computed baudrate and the chosen - prescaler. + Receive data on the bus: -.. method:: spi.recv(recv, \*, timeout=5000) + - ``recv`` can be an integer, which is the number of bytes to receive, + or a mutable buffer, which will be filled with received bytes. + - ``timeout`` is the timeout in milliseconds to wait for the receive. - Receive data on the bus: + Return value: if ``recv`` is an integer then a new buffer of the bytes received, + otherwise the same buffer that was passed in to ``recv``. + + .. method:: spi.send(send, \*, timeout=5000) - - ``recv`` can be an integer, which is the number of bytes to receive, - or a mutable buffer, which will be filled with received bytes. - - ``timeout`` is the timeout in milliseconds to wait for the receive. + Send data on the bus: - Return value: if ``recv`` is an integer then a new buffer of the bytes received, - otherwise the same buffer that was passed in to ``recv``. + - ``send`` is the data to send (an integer to send, or a buffer object). + - ``timeout`` is the timeout in milliseconds to wait for the send. -.. method:: spi.send(send, \*, timeout=5000) + Return value: ``None``. - Send data on the bus: + .. method:: spi.send_recv(send, recv=None, \*, timeout=5000) + + Send and receive data on the bus at the same time: - - ``send`` is the data to send (an integer to send, or a buffer object). - - ``timeout`` is the timeout in milliseconds to wait for the send. + - ``send`` is the data to send (an integer to send, or a buffer object). + - ``recv`` is a mutable buffer which will be filled with received bytes. + It can be the same as ``send``, or omitted. If omitted, a new buffer will + be created. + - ``timeout`` is the timeout in milliseconds to wait for the receive. - Return value: ``None``. - -.. method:: spi.send_recv(send, recv=None, \*, timeout=5000) - - Send and receive data on the bus at the same time: - - - ``send`` is the data to send (an integer to send, or a buffer object). - - ``recv`` is a mutable buffer which will be filled with received bytes. - It can be the same as ``send``, or omitted. If omitted, a new buffer will - be created. - - ``timeout`` is the timeout in milliseconds to wait for the receive. - - Return value: the buffer with the received bytes. + Return value: the buffer with the received bytes. Constants --------- @@ -174,7 +194,6 @@ Constants for initialising the SPI bus to master - .. data:: SPI.ACTIVE_LOW - .. data:: SPI.ACTIVE_HIGH - - selects the polarity of the NSS pin + .. data:: SPI.MSB + + set the first bit to be the most significant bit diff --git a/tests/wipy/spi.py b/tests/wipy/spi.py new file mode 100644 index 000000000..dc3d946de --- /dev/null +++ b/tests/wipy/spi.py @@ -0,0 +1,149 @@ +''' +SPI test for the CC3200 based boards. +''' + +from pyb import SPI +from pyb import Pin +import os +import pyb + +machine = os.uname().machine +if 'LaunchPad' in machine: + spi_pins = ('GP14', 'GP16', 'GP30') +elif 'WiPy' in machine: + spi_pins = ('GP14', 'GP16', 'GP30') +else: + raise Exception('Board not supported!') + +spi = SPI(0, SPI.MASTER, baudrate=2000000, polarity=0, phase=0, firstbit=SPI.MSB, pins=spi_pins) +print(spi) +spi = SPI(baudrate=5000000) +print(spi) +spi = SPI(0, SPI.MASTER, baudrate=200000, bits=16, polarity=0, phase=0) +print(spi) +spi = SPI(0, SPI.MASTER, baudrate=10000000, polarity=0, phase=1) +print(spi) +spi = SPI(0, SPI.MASTER, baudrate=5000000, bits=32, polarity=1, phase=0) +print(spi) +spi = SPI(0, SPI.MASTER, baudrate=10000000, polarity=1, phase=1) +print(spi) +spi.init(baudrate=20000000, polarity=0, phase=0) +print(spi) +spi=SPI() +print(spi) +SPI(mode=SPI.MASTER) +SPI(mode=SPI.MASTER, pins=spi_pins) +SPI(id=0, mode=SPI.MASTER, polarity=0, phase=0, pins=('GP14', 'GP16', 'GP15')) +SPI(0, SPI.MASTER, polarity=0, phase=0, pins=('GP31', 'GP16', 'GP15')) + +spi = SPI(0, SPI.MASTER, baudrate=10000000, polarity=0, phase=0, pins=spi_pins) +print(spi.write('123456') == 6) +buffer_r = bytearray(10) +print(spi.readinto(buffer_r) == 10) +print(spi.readinto(buffer_r, write=0x55) == 10) +read = spi.read(10) +print(len(read) == 10) +read = spi.read(10, write=0xFF) +print(len(read) == 10) +buffer_w = bytearray([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]) +print(spi.write_readinto(buffer_w, buffer_r) == 10) +print(buffer_w == buffer_r) + +# test all polaritiy and phase combinations +spi.init(polarity=1, phase=0, pins=None) +buffer_r = bytearray(10) +spi.write_readinto(buffer_w, buffer_r) +print(buffer_w == buffer_r) + +spi.init(polarity=1, phase=1, pins=None) +buffer_r = bytearray(10) +spi.write_readinto(buffer_w, buffer_r) +print(buffer_w == buffer_r) + +spi.init(polarity=0, phase=1, pins=None) +buffer_r = bytearray(10) +spi.write_readinto(buffer_w, buffer_r) +print(buffer_w == buffer_r) + +# test 16 and 32 bit transfers +buffer_w = bytearray([1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2]) +buffer_r = bytearray(12) +spi.init(SPI.MASTER, baudrate=10000000, bits=16, polarity=0, phase=0, pins=None) +print(spi.write_readinto(buffer_w, buffer_r) == 12) +print(buffer_w == buffer_r) + +buffer_r = bytearray(12) +spi.init(SPI.MASTER, baudrate=10000000, bits=32, polarity=0, phase=0, pins=None) +print(spi.write_readinto(buffer_w, buffer_r) == 12) +print(buffer_w == buffer_r) + +# check for memory leaks... +for i in range (0, 1000): + spi = SPI(0, SPI.MASTER, baudrate=1000000) + +# test deinit +spi = SPI(0, SPI.MASTER, baudrate=1000000) +spi.deinit() +print(spi) + +spi = SPI(0, SPI.MASTER, baudrate=1000000) +# next ones must fail +try: + spi = SPI(0, 10, baudrate=10000000, polarity=0, phase=0) +except: + print("Exception") + +try: + spi = SPI(0, mode=SPI.MASTER, baudrate=10000000, polarity=1, phase=2) +except: + print("Exception") + +try: + spi = SPI(1, mode=SPI.MASTER, baudrate=10000000, polarity=1, phase=1) +except: + print("Exception") + +try: + spi = SPI(0, mode=SPI.MASTER, baudrate=2000000, polarity=2, phase=0) +except: + print("Exception") + +try: + spi = SPI(0, mode=SPI.MASTER, baudrate=2000000, polarity=2, phase=0, firstbit=2) +except: + print("Exception") + +try: + spi = SPI(0, mode=SPI.MASTER, baudrate=2000000, polarity=2, phase=0, pins=('GP1', 'GP2')) +except: + print("Exception") + +try: + spi = SPI(0, mode=SPI.MASTER, baudrate=2000000, polarity=0, phase=0, bits=9) +except: + print("Exception") + +spi.deinit() +try: + spi.read(15) +except Exception: + print("Exception") + +try: + spi.spi.readinto(buffer_r) +except Exception: + print("Exception") + +try: + spi.spi.write('abc') +except Exception: + print("Exception") + +try: + spi.write_readinto(buffer_w, buffer_r) +except Exception: + print("Exception") + +# reinitialization must work +spi.init(baudrate=500000) +print(spi) diff --git a/tests/wipy/spi.py.exp b/tests/wipy/spi.py.exp new file mode 100644 index 000000000..cc4ff4022 --- /dev/null +++ b/tests/wipy/spi.py.exp @@ -0,0 +1,35 @@ +SPI(0, SPI.MASTER, baudrate=2000000, bits=8, polarity=0, phase=0, firstbit=SPI.MSB) +SPI(0, SPI.MASTER, baudrate=5000000, bits=8, polarity=0, phase=0, firstbit=SPI.MSB) +SPI(0, SPI.MASTER, baudrate=200000, bits=16, polarity=0, phase=0, firstbit=SPI.MSB) +SPI(0, SPI.MASTER, baudrate=10000000, bits=8, polarity=0, phase=1, firstbit=SPI.MSB) +SPI(0, SPI.MASTER, baudrate=5000000, bits=32, polarity=1, phase=0, firstbit=SPI.MSB) +SPI(0, SPI.MASTER, baudrate=10000000, bits=8, polarity=1, phase=1, firstbit=SPI.MSB) +SPI(0, SPI.MASTER, baudrate=20000000, bits=8, polarity=0, phase=0, firstbit=SPI.MSB) +SPI(0, SPI.MASTER, baudrate=1000000, bits=8, polarity=0, phase=0, firstbit=SPI.MSB) +True +True +True +True +True +True +True +True +True +True +True +True +True +True +SPI(0) +Exception +Exception +Exception +Exception +Exception +Exception +Exception +Exception +Exception +Exception +Exception +SPI(0, SPI.MASTER, baudrate=500000, bits=8, polarity=0, phase=0, firstbit=SPI.MSB)