/*JSON{ "type" : "method", "class" : "SPI", "name" : "write", "generate" : "jswrap_spi_write", "params" : [ ["data","JsVarArray",["One or more items to write. May be ints, strings, arrays, or objects of the form `{data: ..., count:#}`.","If the last argument is a pin, it is taken to be the NSS pin"]] ] } Write a character or array of characters to SPI - without reading the result back. For maximum speeds, please pass either Strings or Typed Arrays as arguments. */ void jswrap_spi_write(JsVar *parent, JsVar *args) { NOT_USED(parent); IOEventFlags device = jsiGetDeviceFromClass(parent); spi_sender spiSend; spi_sender_data spiSendData; if (!jsspiGetSendFunction(parent, &spiSend, &spiSendData)) return; Pin nss_pin = PIN_UNDEFINED; // If the last value is a pin, use it as the NSS pin JsVarInt len = jsvGetArrayLength(args); if (len>0) { JsVar *last = jsvGetArrayItem(args, len-1); // look at the last value if (jsvIsPin(last)) { nss_pin = jshGetPinFromVar(last); jsvUnLock(jsvArrayPop(args)); } jsvUnLock(last); } // we're only sending (no receive) if (DEVICE_IS_SPI(device)) jshSPISetReceive(device, false); // assert NSS if (nss_pin!=PIN_UNDEFINED) jshPinOutput(nss_pin, false); // Write data jsvIterateCallback(args, (void (*)(int, void *))spiSend, &spiSendData); // Wait until SPI send is finished, and flush data if (DEVICE_IS_SPI(device)) jshSPIWait(device); // de-assert NSS if (nss_pin!=PIN_UNDEFINED) jshPinOutput(nss_pin, true); }
/*JSON{ "type" : "method", "class" : "SPI", "name" : "setup", "generate" : "jswrap_spi_setup", "params" : [ ["options","JsVar",["An optional structure containing extra information on initialising the SPI port","Please note that baud rate is set to the nearest that can be managed - which may be -+ 50%","```{sck:pin, miso:pin, mosi:pin, baud:integer=100000, mode:integer=0, order:'msb'/'lsb'='msb' }```","If sck,miso and mosi are left out, they will automatically be chosen. However if one or more is specified then the unspecified pins will not be set up.","You can find out which pins to use by looking at [your board's reference page](#boards) and searching for pins with the `SPI` marker.","The SPI ```mode``` is between 0 and 3 - see http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus#Clock_polarity_and_phase","On STM32F1-based parts, you cannot mix AF and non-AF pins (SPI pins are usually grouped on the chip - and you can't mix pins from two groups). Espruino will not warn you about this."]] ] } Set up this SPI port as an SPI Master. */ void jswrap_spi_setup(JsVar *parent, JsVar *options) { IOEventFlags device = jsiGetDeviceFromClass(parent); JshSPIInfo inf; jsspiPopulateSPIInfo(&inf, options); if (DEVICE_IS_SPI(device)) { jshSPISetup(device, &inf); #ifdef LINUX if (jsvIsObject(options)) { jsvUnLock(jsvObjectSetChild(parent, "path", jsvObjectGetChild(options, "path", 0))); } #endif } else if (device == EV_NONE) { // software mode - at least configure pins properly if (inf.pinSCK != PIN_UNDEFINED) jshPinSetState(inf.pinSCK, JSHPINSTATE_GPIO_OUT); if (inf.pinMISO != PIN_UNDEFINED) jshPinSetState(inf.pinMISO, JSHPINSTATE_GPIO_IN); if (inf.pinMOSI != PIN_UNDEFINED) jshPinSetState(inf.pinMOSI, JSHPINSTATE_GPIO_OUT); } else return; // Set up options, so we can initialise it on startup if (options) jsvUnLock(jsvSetNamedChild(parent, options, DEVICE_OPTIONS_NAME)); else jsvRemoveNamedChild(parent, DEVICE_OPTIONS_NAME); }
/*JSON{ "type" : "method", "class" : "SPI", "name" : "send4bit", "generate" : "jswrap_spi_send4bit", "params" : [ ["data","JsVar","The data to send - either an integer, array, or string"], ["bit0","int32","The 4 bits to send for a 0 (MSB first)"], ["bit1","int32","The 4 bits to send for a 1 (MSB first)"], ["nss_pin","pin","An nSS pin - this will be lowered before SPI output and raised afterwards (optional). There will be a small delay between when this is lowered and when sending starts, and also between sending finishing and it being raised."] ] } Send data down SPI, using 4 bits for each 'real' bit (MSB first). This can be useful for faking one-wire style protocols Sending multiple bytes in one call to send is preferable as they can then be transmitted end to end. Using multiple calls to send() will result in significantly slower transmission speeds. */ void jswrap_spi_send4bit(JsVar *parent, JsVar *srcdata, int bit0, int bit1, Pin nss_pin) { NOT_USED(parent); IOEventFlags device = jsiGetDeviceFromClass(parent); if (!DEVICE_IS_SPI(device)) { jsExceptionHere(JSET_ERROR, "SPI.send4bit only works on hardware SPI"); return; } jshSPISet16(device, true); // 16 bit output if (bit0==0 && bit1==0) { bit0 = 0x01; bit1 = 0x03; } bit0 = bit0 & 0x0F; bit1 = bit1 & 0x0F; if (!jshIsDeviceInitialised(device)) { JshSPIInfo inf; jshSPIInitInfo(&inf); jshSPISetup(device, &inf); } // we're just sending (no receive) jshSPISetReceive(device, false); // assert NSS if (nss_pin!=PIN_UNDEFINED) jshPinOutput(nss_pin, false); // send data if (jsvIsNumeric(srcdata)) { jsspiSend4bit(device, (unsigned char)jsvGetInteger(srcdata), bit0, bit1); } else if (jsvIsIterable(srcdata)) { jshInterruptOff(); JsvIterator it; jsvIteratorNew(&it, srcdata); while (jsvIteratorHasElement(&it)) { unsigned char in = (unsigned char)jsvIteratorGetIntegerValue(&it); jsspiSend4bit(device, in, bit0, bit1); jsvIteratorNext(&it); } jsvIteratorFree(&it); jshInterruptOn(); } else { jsExceptionHere(JSET_ERROR, "Variable type %t not suited to transmit operation", srcdata); } jshSPIWait(device); // wait until SPI send finished and clear the RX buffer // de-assert NSS if (nss_pin!=PIN_UNDEFINED) jshPinOutput(nss_pin, true); jshSPISet16(device, false); // back to 8 bit }
void jshSPISetup(IOEventFlags device, JshSPIInfo *inf) { assert(DEVICE_IS_SPI(device)); if (ioDevices[device]) close(ioDevices[device]); ioDevices[device] = 0; char path[256]; if (jshGetDevicePath(device, path, sizeof(path))) { ioDevices[device] = open(path, O_RDWR | O_NOCTTY | O_NONBLOCK); if (!ioDevices[device]) { jsError("Open of path %s failed", path); } else { } } else { jsError("No path defined for device"); } }
/*JSON{ "type" : "staticmethod", "class" : "CC3000", "name" : "connect", "generate" : "jswrap_cc3000_connect", "params" : [ ["spi", "JsVar", "Device to use for SPI (or undefined to use the default). SPI should be 1,000,000 baud, and set to 'mode 1'"], ["cs", "pin", "The pin to use for Chip Select"], ["en", "pin", "The pin to use for Enable"], ["irq", "pin", "The pin to use for Interrupts"] ], "return" : ["JsVar","A WLAN Object"], "return_object" : "WLAN" } Initialise the CC3000 and return a WLAN object */ JsVar *jswrap_cc3000_connect(JsVar *spi, Pin cs, Pin en, Pin irq) { IOEventFlags spiDevice; if (spi) { spiDevice = jsiGetDeviceFromClass(spi); if (!DEVICE_IS_SPI(spiDevice)) { jsExceptionHere(JSET_ERROR, "Expecting SPI device, got %q", spi); return 0; } } else { // SPI config // SPI config JshSPIInfo inf; jshSPIInitInfo(&inf); inf.pinSCK = WLAN_CLK_PIN; inf.pinMISO = WLAN_MISO_PIN; inf.pinMOSI = WLAN_MOSI_PIN; inf.baudRate = 1000000; inf.spiMode = SPIF_SPI_MODE_1; // Mode 1 CPOL= 0 CPHA= 1 jshSPISetup(WLAN_SPI, &inf); spiDevice = WLAN_SPI; } if (!jshIsPinValid(cs)) cs = WLAN_CS_PIN; if (!jshIsPinValid(en)) en = WLAN_EN_PIN; if (!jshIsPinValid(irq)) irq = WLAN_IRQ_PIN; JsNetwork net; networkCreate(&net, JSNETWORKTYPE_CC3000); net.data.device = spiDevice; net.data.pinCS = cs; net.data.pinEN = en; net.data.pinIRQ = irq; networkSet(&net); JsVar *wlanObj = jspNewObject(0, "WLAN"); cc3000_initialise(wlanObj); networkFree(&net); return wlanObj; }
/*JSON{ "type" : "method", "class" : "SPI", "name" : "setup", "generate" : "jswrap_spi_setup", "params" : [ ["options","JsVar",["An optional structure containing extra information on initialising the SPI port","Please note that baud rate is set to the nearest that can be managed - which may be -+ 50%","```{sck:pin, miso:pin, mosi:pin, baud:integer=100000, mode:integer=0, order:'msb'/'lsb'='msb' }```","If sck,miso and mosi are left out, they will automatically be chosen. However if one or more is specified then the unspecified pins will not be set up.","You can find out which pins to use by looking at [your board's reference page](#boards) and searching for pins with the `SPI` marker.","The SPI ```mode``` is between 0 and 3 - see http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus#Clock_polarity_and_phase","On STM32F1-based parts, you cannot mix AF and non-AF pins (SPI pins are usually grouped on the chip - and you can't mix pins from two groups). Espruino will not warn you about this."]] ] } Set up this SPI port as an SPI Master. */ void jswrap_spi_setup( JsVar *parent, //!< The variable that is the class instance of this function. JsVar *options //!< The options controlling SPI. ) { // // Design: The options variable is a JS Object which contains a series of settings. These // settings are parsed by `jsspiPopulateSPIInfo` to populate a C structure of type // `JshSPIInfo`. // // The options are also hung off the class instance variable in a property symbolically called // DEVICE_OPTIONS_NAME ("_options"). // IOEventFlags device = jsiGetDeviceFromClass(parent); JshSPIInfo inf; // Debug // jsiConsolePrintf("jswrap_spi_setup called parent=%v, options=%v\n", parent, options); jsspiPopulateSPIInfo(&inf, options); if (DEVICE_IS_SPI(device)) { jshSPISetup(device, &inf); #ifdef LINUX if (jsvIsObject(options)) { jsvObjectSetChildAndUnLock(parent, "path", jsvObjectGetChild(options, "path", 0)); } #endif } else if (device == EV_NONE) { // software mode - at least configure pins properly if (inf.pinSCK != PIN_UNDEFINED) jshPinSetState(inf.pinSCK, JSHPINSTATE_GPIO_OUT); if (inf.pinMISO != PIN_UNDEFINED) jshPinSetState(inf.pinMISO, JSHPINSTATE_GPIO_IN); if (inf.pinMOSI != PIN_UNDEFINED) jshPinSetState(inf.pinMOSI, JSHPINSTATE_GPIO_OUT); } else return; // Set up options, so we can initialise it on startup if (options) jsvUnLock(jsvSetNamedChild(parent, options, DEVICE_OPTIONS_NAME)); else jsvRemoveNamedChild(parent, DEVICE_OPTIONS_NAME); }
/** * Send data through SPI. * The data can be in a variety of formats including: * * `numeric` - A single byte is transmitted. * * `string` - Each character in the string is transmitted. * * `iterable` - An iterable object is transmitted. * \return the Received bytes (MISO). This is byte array. */ JsVar *jswrap_spi_send( JsVar *parent, //!< A description of the SPI device to send data through. JsVar *srcdata, //!< The data to send through SPI. Pin nss_pin //!< The pin to toggle low then high (CS) ) { // Debug // jsiConsolePrintf("jswrap_spi_send called: parent=%j, srcdata=%j, nss_pin=%p\n", parent, srcdata, nss_pin); NOT_USED(parent); IOEventFlags device = jsiGetDeviceFromClass(parent); jswrap_spi_send_data data; if (!jsspiGetSendFunction(parent, &data.spiSend, &data.spiSendData)) return 0; JsVar *dst = 0; // we're sending and receiving if (DEVICE_IS_SPI(device)) jshSPISetReceive(device, true); // assert NSS if (nss_pin!=PIN_UNDEFINED) jshPinOutput(nss_pin, false); // Now that we are setup, we can send the data. // Handle the data being a single byte value if (jsvIsNumeric(srcdata)) { int r = data.spiSend((unsigned char)jsvGetInteger(srcdata), &data.spiSendData); if (r<0) r = data.spiSend(-1, &data.spiSendData); dst = jsvNewFromInteger(r); // retrieve the byte (no send!) } // Handle the data being a string else if (jsvIsString(srcdata)) { dst = jsvNewFromEmptyString(); JsvStringIterator it; jsvStringIteratorNew(&it, srcdata, 0); int incount = 0, outcount = 0; while (jsvStringIteratorHasChar(&it) && !jspIsInterrupted()) { unsigned char in = (unsigned char)jsvStringIteratorGetChar(&it); incount++; int out = data.spiSend(in, &data.spiSendData); if (out>=0) { outcount++; char outc = (char)out; jsvAppendStringBuf(dst, (char*)&outc, 1); } jsvStringIteratorNext(&it); } jsvStringIteratorFree(&it); // finally add the remaining bytes (no send!) while (outcount < incount && !jspIsInterrupted()) { outcount++; unsigned char out = (unsigned char)data.spiSend(-1, &data.spiSendData); jsvAppendStringBuf(dst, (char*)&out, 1); } } // Handle the data being an iterable. else { int nBytes = jsvIterateCallbackCount(srcdata); dst = jsvNewTypedArray(ARRAYBUFFERVIEW_UINT8, nBytes); if (dst) { data.rxAmt = data.txAmt = 0; jsvArrayBufferIteratorNew(&data.it, dst, 0); // Write data jsvIterateCallback(srcdata, (void (*)(int, void *))jswrap_spi_send_cb, &data); // Wait until SPI send is finished, and flush data while (data.rxAmt < data.txAmt && !jspIsInterrupted()) jswrap_spi_send_cb(-1, &data); jsvArrayBufferIteratorFree(&data.it); } } // de-assert NSS if (nss_pin!=PIN_UNDEFINED) jshPinOutput(nss_pin, true); return dst; }
/*JSON{ "type" : "staticmethod", "class" : "WIZnet", "name" : "connect", "generate" : "jswrap_wiznet_connect", "params" : [ ["spi", "JsVar", "Device to use for SPI (or undefined to use the default)"], ["cs", "pin", "The pin to use for Chip Select"] ], "return" : ["JsVar","An Ethernet Object"], "return_object" : "Ethernet" } Initialise the WIZnet module and return an Ethernet object */ JsVar *jswrap_wiznet_connect(JsVar *spi, Pin cs) { IOEventFlags spiDevice; if (spi) { spiDevice = jsiGetDeviceFromClass(spi); if (!DEVICE_IS_SPI(spiDevice)) { jsExceptionHere(JSET_ERROR, "Expecting SPI device, got %q", spi); return 0; } } else { // SPI config JshSPIInfo inf; jshSPIInitInfo(&inf); inf.pinSCK = ETH_CLK_PIN; inf.pinMISO = ETH_MISO_PIN; inf.pinMOSI = ETH_MOSI_PIN; inf.baudRate = 1000000; inf.spiMode = SPIF_SPI_MODE_0; jshSPISetup(ETH_SPI, &inf); spiDevice = ETH_SPI; } if (!jshIsPinValid(cs)) cs = ETH_CS_PIN; JsNetwork net; networkCreate(&net, JSNETWORKTYPE_W5500); net.data.device = spiDevice; net.data.pinCS = cs; networkSet(&net); JsVar *ethObj = jspNewObject(0, "Ethernet"); // CS Configuration jshSetPinStateIsManual(net.data.pinCS, false); jshPinOutput(net.data.pinCS, 1); // de-assert CS // Initialise WIZnet functions reg_wizchip_cs_cbfunc(wizchip_select, wizchip_deselect); reg_wizchip_spi_cbfunc(wizchip_read, wizchip_write); /* wizchip initialize*/ uint8_t tmp; uint8_t memsize[2][8] = { {2,2,2,2,2,2,2,2}, {2,2,2,2,2,2,2,2}}; if(ctlwizchip(CW_INIT_WIZCHIP,(void*)memsize) == -1) { jsiConsolePrint("WIZnet Initialize failed.\r\n"); networkFree(&net); return 0; } #if _WIZCHIP_ == 5500 /* PHY link status check - W5100 doesn't have this */ do { if(ctlwizchip(CW_GET_PHYLINK, (void*)&tmp) == -1) { jsiConsolePrint("Unknown PHY Link status.\r\n"); networkFree(&net); return 0; } } while (tmp == PHY_LINK_OFF); #endif networkFree(&net); networkState = NETWORKSTATE_ONLINE; return ethObj; }
JsVar *jswrap_spi_send(JsVar *parent, JsVar *srcdata, Pin nss_pin) { NOT_USED(parent); IOEventFlags device = jsiGetDeviceFromClass(parent); jswrap_spi_send_data data; if (!jsspiGetSendFunction(parent, &data.spiSend, &data.spiSendData)) return 0; JsVar *dst = 0; // we're sending and receiving if (DEVICE_IS_SPI(device)) jshSPISetReceive(device, true); // assert NSS if (nss_pin!=PIN_UNDEFINED) jshPinOutput(nss_pin, false); // send data if (jsvIsNumeric(srcdata)) { int r = data.spiSend((unsigned char)jsvGetInteger(srcdata), &data.spiSendData); if (r<0) r = data.spiSend(-1, &data.spiSendData); dst = jsvNewFromInteger(r); // retrieve the byte (no send!) } else if (jsvIsString(srcdata)) { dst = jsvNewFromEmptyString(); JsvStringIterator it; jsvStringIteratorNew(&it, srcdata, 0); int incount = 0, outcount = 0; while (jsvStringIteratorHasChar(&it) && !jspIsInterrupted()) { unsigned char in = (unsigned char)jsvStringIteratorGetChar(&it); incount++; int out = data.spiSend(in, &data.spiSendData); if (out>=0) { outcount++; char outc = (char)out; jsvAppendStringBuf(dst, (char*)&outc, 1); } jsvStringIteratorNext(&it); } jsvStringIteratorFree(&it); // finally add the remaining bytes (no send!) while (outcount < incount && !jspIsInterrupted()) { outcount++; unsigned char out = (unsigned char)data.spiSend(-1, &data.spiSendData); jsvAppendStringBuf(dst, (char*)&out, 1); } } else { int nBytes = jsvIterateCallbackCount(srcdata); dst = jsvNewTypedArray(ARRAYBUFFERVIEW_UINT8, nBytes); if (dst) { data.rxAmt = data.txAmt = 0; jsvArrayBufferIteratorNew(&data.it, dst, 0); // Write data jsvIterateCallback(srcdata, (void (*)(int, void *))jswrap_spi_send_cb, &data); // Wait until SPI send is finished, and flush data while (data.rxAmt < data.txAmt && !jspIsInterrupted()) jswrap_spi_send_cb(-1, &data); jsvArrayBufferIteratorFree(&data.it); } } // de-assert NSS if (nss_pin!=PIN_UNDEFINED) jshPinOutput(nss_pin, true); return dst; }