Skip to content

#606. Initial framework for hardware SPI for ESP8266. #692

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Nov 10, 2015
16 changes: 10 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,7 @@ else ifdef ESP8266_512KB
# into ram (dram+iram) and the last 16KB are reserved for the SDK. That leaves 432KB (0x6C000).
EMBEDDED=1
USE_NET=1
#USE_FILESYSTEM=1
BOARD=ESP8266_BOARD
# We have to disable inlining to keep code size in check
OPTIMIZEFLAGS+=-Os -fno-inline-functions -std=gnu11 -fgnu89-inline -Wl,--allow-multiple-definition
Expand Down Expand Up @@ -986,7 +987,8 @@ libs/network/js/network_js.c

ifdef USE_ESP8266
DEFINES += -DUSE_ESP8266
WRAPPERSOURCES += libs/network/esp8266/jswrap_esp8266.c
WRAPPERSOURCES += libs/network/esp8266/jswrap_esp8266_network.c \
targets/esp8266/jswrap_esp8266.c
INCLUDE += -I$(ROOT)/libs/network/esp8266
SOURCES += \
libs/network/esp8266/network_esp8266.c\
Expand Down Expand Up @@ -1493,11 +1495,12 @@ LDFLAGS += -L$(ESP8266_SDK_ROOT)/lib \

# Extra source files specific to the ESP8266
SOURCES += targets/esp8266/uart.c \
targets/esp8266/user_main.c \
targets/esp8266/jshardware.c \
targets/esp8266/i2c_master.c \
targets/esp8266/esp8266_board_utils.c \
libs/network/esp8266/network_esp8266.c
targets/esp8266/spi.c \
targets/esp8266/user_main.c \
targets/esp8266/jshardware.c \
targets/esp8266/i2c_master.c \
targets/esp8266/esp8266_board_utils.c \
libs/network/esp8266/network_esp8266.c
# if using the hw_timer: targets/esp8266/hw_timer.c \

# The tool used for building the firmware and flashing
Expand Down Expand Up @@ -1602,6 +1605,7 @@ proj: $(PROJ_NAME).elf $(PROJ_NAME)_0x00000.bin $(PROJ_NAME)_0x10000.bin $(PROJ_
$(PROJ_NAME).elf: $(OBJS) $(LINKER_FILE)
$(Q)$(LD) $(OPTIMIZEFLAGS) -nostdlib -Wl,--no-check-sections -Wl,-static -r -o partial.o $(OBJS)
$(Q)$(OBJCOPY) --rename-section .text=.irom0.text --rename-section .literal=.irom0.literal partial.o
$(Q)$(OBJCOPY) --rename-section .force.text=.text partial.o
$(Q)$(LD) $(LDFLAGS) -Ttargets/esp8266/eagle.app.v6.0x10000.ld -o $@ partial.o -Wl,--start-group $(LIBS) -Wl,--end-group
$(Q)rm partial.o
$(Q)$(OBJDUMP) --headers -j .irom0.text -j .text $(PROJ_NAME).elf | tail -n +4
Expand Down
1 change: 1 addition & 0 deletions boards/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/__pycache__/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my build system I found that during build, my Python environment was writing python cache information. I can't imagine that we would want that in our build system so added a gitignore for it. If that is wrong, we can remove it.

2 changes: 1 addition & 1 deletion boards/ESP8266_12.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
'flash' : 1024,
'speed' : 80,
'usart' : 1,
'spi' : 0,
'spi' : 1,
'i2c' : 1,
'adc' : 1,
'dac' : 0,
Expand Down
2 changes: 1 addition & 1 deletion boards/ESP8266_BOARD.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
'flash' : 512,
'speed' : 80,
'usart' : 1,
'spi' : 0,
'spi' : 1,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice to also add it to the ESP8266_12.py board...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree ... there are a couple of issues floating around just now ... see Issue #675 for the one that is most relevant.

'i2c' : 1,
'adc' : 1,
'dac' : 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ of beta. */
#define _GCC_WRAP_STDINT_H
typedef long long int64_t;

#include "jswrap_esp8266.h"
#include "jswrap_esp8266_network.h"
#include "jsinteractive.h" // Pull inn the jsiConsolePrint function
#include "network.h"
#include "network_esp8266.h"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
* ----------------------------------------------------------------------------
*/

#ifndef LIBS_NETWORK_ESP8266_JSWRAP_ESP8266_H_
#define LIBS_NETWORK_ESP8266_JSWRAP_ESP8266_H_
#ifndef LIBS_NETWORK_ESP8266_JSWRAP_ESP8266_NETWORK_H_
#define LIBS_NETWORK_ESP8266_JSWRAP_ESP8266_NETWORK_H_
#include "jsvar.h"

// Deprecated
Expand Down Expand Up @@ -67,4 +67,4 @@ void jswrap_ESP8266_updateCPUFreq(JsVar *jsFreq);

void jswrap_ESP8266_init();

#endif /* LIBS_NETWORK_ESP8266_JSWRAP_ESP8266_H_ */
#endif /* LIBS_NETWORK_ESP8266_JSWRAP_ESP8266_NETWORK_H_ */
2 changes: 1 addition & 1 deletion src/jsdevices.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ volatile unsigned char ioHead=0, ioTail=0;
* Initialize all the devices.
*/
void jshInitDevices() { // called from jshInit
int i;
unsigned int i;
// setup flow control
for (i=0;i<sizeof(jshSerialDeviceStates) / sizeof(JshSerialDeviceState);i++)
jshSerialDeviceStates[i] = SDS_NONE;
Expand Down
100 changes: 85 additions & 15 deletions targets/esp8266/jshardware.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <espmissingincludes.h>
#include <uart.h>
#include <i2c_master.h>
#include <spi.h> // Include the MetalPhreak/ESP8266_SPI_Library headers.

//#define FAKE_STDLIB
#define _GCC_WRAP_STDINT_H
Expand Down Expand Up @@ -53,6 +54,10 @@ typedef long long int64_t;
// Address in RTC RAM where we save the time
#define RTC_TIME_ADDR (256/4) // start of "user data" in RTC RAM


static bool g_spiInitialized = false;
static int g_lastSPIRead = -1;

/**
* Transmit all the characters in the transmit buffer.
*
Expand Down Expand Up @@ -159,6 +164,8 @@ void jshReset() {
jshPinSetState(i, JSHPINSTATE_GPIO_IN);
}
*/
g_spiInitialized = false; // Flag the hardware SPI interface as un-initialized.
g_lastSPIRead = -1;
os_printf("< jshReset\n");
} // End of jshReset

Expand Down Expand Up @@ -588,26 +595,69 @@ void jshUSARTKick(
//===== SPI =====

/**
* Unknown
* Initialize the hardware SPI device.
* On the ESP8266, hardware SPI is implemented via a set of pins defined
* as follows:
*
* | GPIO | NodeMCU | Name | Function |
* |--------|---------|-------|----------|
* | GPIO12 | D6 | HMISO | MISO |
* | GPIO13 | D7 | HMOSI | MOSI |
* | GPIO14 | D5 | HSCLK | CLK |
* | GPIO15 | D8 | HCS | CS |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way to have more than one device on the SPI bus, i.e., by specifying a second chip select pin?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good question. This table and documentation comes from ESP8266 "stuff". I think that when one "drives" the ESP8266 hardware SPI, the SPI hardware knows to drive CS. I suspect that if we wanted to drive alternate devices, we would ignore the hardware CS and dedicate alternate pins to CS.

*
*/
void jshSPISetup(
IOEventFlags device, //!< Unknown
JshSPIInfo *inf //!< Unknown
IOEventFlags device, //!< The identity of the SPI device being initialized.
JshSPIInfo *inf //!< Flags for the SPI device.
) {
os_printf("ESP8266: jshSPISetup: device=%d, inf=0x%x\n", device, (int)inf);
// The device should be one of EV_SPI1, EV_SPI2 or EV_SPI3.
os_printf("> jshSPISetup - jshSPISetup: device=%d\n", device);
switch(device) {
case EV_SPI1:
os_printf(" - Device is SPI1\n");
// EV_SPI1 is the ESP8266 hardware SPI ...
spi_init(HSPI); // Initialize the hardware SPI components.
spi_clock(HSPI, CPU_CLK_FREQ / (inf->baudRate * 2), 2);
g_spiInitialized = true;
g_lastSPIRead = -1;
break;
case EV_SPI2:
os_printf(" - Device is SPI2\n");
break;
case EV_SPI3:
os_printf(" - Device is SPI3\n");
break;
default:
os_printf(" - Device is Unknown!!\n");
break;
}
if (inf != NULL) {
os_printf("baudRate=%d, baudRateSpec=%d, pinSCK=%d, pinMISO=%d, pinMOSI=%d, spiMode=%d, spiMSB=%d\n",
inf->baudRate, inf->baudRateSpec, inf->pinSCK, inf->pinMISO, inf->pinMOSI, inf->spiMode, inf->spiMSB);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems it would be good to return an error if the user specifies parameters that the implementation doesn't support.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These guards are an over-abundance of caution. The identies of available SPI interfaces are not user configurable but instead defined in the ESP8266_xxx.py files. Today we only have SPI1 but it is possible to have SPI2 and SPI3 as well. However, nothing a user can code at their JS level could result in triggering these alternate code paths.

}
os_printf("< jshSPISetup\n");
}

/** Send data through the given SPI device (if data>=0), and return the result
* of the previous send (or -1). If data<0, no data is sent and the function
* waits for data to be returned */
int jshSPISend(
IOEventFlags device, //!< Unknown
int data //!< Unknown
IOEventFlags device, //!< The identity of the SPI device through which data is being sent.
int data //!< The data to be sent or an indication that no data is to be sent.
) {
os_printf("ESP8266: jshSPISend\n");
return NAN;
if (device != EV_SPI1) {
return -1;
}
//os_printf("> jshSPISend - device=%d, data=%x\n", device, data);
int retData = g_lastSPIRead;
if (data >=0) {
g_lastSPIRead = spi_tx8(HSPI, data);
} else {
g_lastSPIRead = -1;
}
//os_printf("< jshSPISend\n");
return retData;
}


Expand All @@ -618,9 +668,15 @@ void jshSPISend16(
IOEventFlags device, //!< Unknown
int data //!< Unknown
) {
os_printf("ESP8266: jshSPISend16\n");
jshSPISend(device, data >> 8);
jshSPISend(device, data & 255);
//os_printf("> jshSPISend16 - device=%d, data=%x\n", device, data);
//jshSPISend(device, data >> 8);
//jshSPISend(device, data & 255);
if (device != EV_SPI1) {
return;
}

spi_tx16(HSPI, data);
//os_printf("< jshSPISend16\n");
}


Expand All @@ -631,7 +687,8 @@ void jshSPISet16(
IOEventFlags device, //!< Unknown
bool is16 //!< Unknown
) {
os_printf("ESP8266: jshSPISet16\n");
os_printf("> jshSPISet16 - device=%d, is16=%d\n", device, is16);
os_printf("< jshSPISet16\n");
}


Expand All @@ -641,11 +698,15 @@ void jshSPISet16(
void jshSPIWait(
IOEventFlags device //!< Unknown
) {
os_printf("ESP8266: jshSPIWait\n");
os_printf("> jshSPIWait - device=%d\n", device);
while(spi_busy(HSPI)) ;
os_printf("< jshSPIWait\n");
}

/** Set whether to use the receive interrupt or not */
void jshSPISetReceive(IOEventFlags device, bool isReceive) {
os_printf("> jshSPISetReceive - device=%d, isReceive=%d\n", device, isReceive);
os_printf("< jshSPISetReceive\n");
}

//===== I2C =====
Expand Down Expand Up @@ -948,8 +1009,17 @@ void jshUtilTimerReschedule(JsSysTime period) {
//===== Miscellaneous =====

bool jshIsDeviceInitialised(IOEventFlags device) {
os_printf("ESP8266: jshIsDeviceInitialised %d\n", device);
return true;
os_printf("> jshIsDeviceInitialised - %d\n", device);
bool retVal = true;
switch(device) {
case EV_SPI1:
retVal = g_spiInitialized;
break;
default:
break;
}
os_printf("< jshIsDeviceInitialised - %d\n", retVal);
return retVal;
} // End of jshIsDeviceInitialised

// the esp8266 doesn't have any temperature sensor
Expand Down
Loading