提交 be047ff7 编写于 作者: M Marcel Stör

Merge branch 'dev', 1.5.4.1 master drop

......@@ -34,6 +34,8 @@ If you also want to verify that all is well with your Markdown files you can ins
A note on Markdown *syntax*. As Mkdocs is Python-based it's no surprise it uses a [Python Markdown implementation](https://pythonhosted.org/Markdown/). The good news is that it sticks pretty closely to John Gruber's Markdown and also [supports tables and fenced code blocks](http://www.mkdocs.org/user-guide/writing-your-docs/#markdown-extensions) just like GitHub does.
A collection of doc-writing hints and tips is maintained on the [wiki](https://github.com/nodemcu/nodemcu-firmware/wiki/Notes-about-writing-docs).
If you're interested in some NodeMCU history you're welcome to read [issue #774](https://github.com/nodemcu/nodemcu-firmware/issues/774)
## Working with Git and GitHub
......
......@@ -3,10 +3,21 @@
.NOTPARALLEL:
# SDK version NodeMCU is locked to
SDK_VER:=1.5.1
SDK_FILE_VER:=$(SDK_VER)_16_01_08
SDK_FILE_ID:=1046
SDK_FILE_SHA1:=374f689a5f9e47690d7b4cd2fc1a1094f3fd5a4f
SDK_VER:=1.5.4.1
# no patch: SDK_BASE_VER equals SDK_VER and sdk dir depends on sdk_extracted
#SDK_BASE_VER:=SDK_VER
#SDK_DIR_DEPENDS:=sdk_extracted
# with patch: SDK_BASE_VER differs from SDK_VER and sdk dir depends on sdk_patched
SDK_BASE_VER:=1.5.4
SDK_DIR_DEPENDS:=sdk_patched
SDK_FILE_VER:=$(SDK_BASE_VER)_16_05_20
SDK_FILE_ID:=1469
SDK_FILE_SHA1:=868784bd37d47f31d52b81f133aa1fb70c58e17d
SDK_PATCH_VER:=$(SDK_VER)_patch_20160704
SDK_PATCH_ID:=1572
SDK_PATCH_SHA1:=388d9e91df74e3b49fca126da482cf822cf1ebf1
# Ensure we search "our" SDK before the tool-chain's SDK (if any)
TOP_DIR:=$(abspath $(dir $(lastword $(MAKEFILE_LIST))))
SDK_DIR:=$(TOP_DIR)/sdk/esp_iot_sdk_v$(SDK_VER)
......@@ -90,7 +101,7 @@ ESPTOOL ?= ../tools/esptool.py
CSRCS ?= $(wildcard *.c)
ASRCs ?= $(wildcard *.s)
ASRCS ?= $(wildcard *.S)
SUBDIRS ?= $(patsubst %/,%,$(dir $(wildcard */Makefile)))
SUBDIRS ?= $(patsubst %/,%,$(dir $(filter-out tools/Makefile,$(wildcard */Makefile))))
ODIR := .output
OBJODIR := $(ODIR)/$(TARGET)/$(FLAVOR)/obj
......@@ -112,6 +123,14 @@ OIMAGES := $(GEN_IMAGES:%=$(IMAGEODIR)/%)
BINODIR := $(ODIR)/$(TARGET)/$(FLAVOR)/bin
OBINS := $(GEN_BINS:%=$(BINODIR)/%)
ifndef PDIR
ifneq ($(wildcard $(TOP_DIR)/local/fs/*),)
SPECIAL_MKTARGETS += spiffs-image
else
SPECIAL_MKTARGETS += spiffs-image-remove
endif
endif
#
# Note:
# https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
......@@ -171,15 +190,25 @@ $(BINODIR)/%.bin: $(IMAGEODIR)/%.out
# Should be done in top-level makefile only
#
all: sdk_extracted pre_build .subdirs $(OBJS) $(OLIBS) $(OIMAGES) $(OBINS) $(SPECIAL_MKTARGETS)
all: $(SDK_DIR_DEPENDS) pre_build .subdirs $(OBJS) $(OLIBS) $(OIMAGES) $(OBINS) $(SPECIAL_MKTARGETS)
.PHONY: sdk_extracted
.PHONY: sdk_patched
sdk_extracted: $(TOP_DIR)/sdk/.extracted-$(SDK_VER)
sdk_extracted: $(TOP_DIR)/sdk/.extracted-$(SDK_BASE_VER)
sdk_patched: sdk_extracted $(TOP_DIR)/sdk/.patched-$(SDK_VER)
$(TOP_DIR)/sdk/.extracted-$(SDK_VER): $(TOP_DIR)/cache/esp_iot_sdk_v$(SDK_FILE_VER).zip
$(TOP_DIR)/sdk/.extracted-$(SDK_BASE_VER): $(TOP_DIR)/cache/esp_iot_sdk_v$(SDK_FILE_VER).zip
mkdir -p "$(dir $@)"
(cd "$(dir $@)" && rm -fr esp_iot_sdk_v$(SDK_VER) && unzip $(TOP_DIR)/cache/esp_iot_sdk_v$(SDK_VER)*.zip esp_iot_sdk_v$(SDK_VER)/lib/* esp_iot_sdk_v$(SDK_VER)/ld/eagle.rom.addr.v6.ld esp_iot_sdk_v$(SDK_VER)/include/* )
(cd "$(dir $@)" && rm -fr esp_iot_sdk_v$(SDK_VER) ESP8266_NONOS_SDK && unzip $(TOP_DIR)/cache/esp_iot_sdk_v$(SDK_FILE_VER).zip ESP8266_NONOS_SDK/lib/* ESP8266_NONOS_SDK/ld/eagle.rom.addr.v6.ld ESP8266_NONOS_SDK/include/* )
mv $(dir $@)/ESP8266_NONOS_SDK $(dir $@)/esp_iot_sdk_v$(SDK_VER)
rm -f $(SDK_DIR)/lib/liblwip.a
touch $@
$(TOP_DIR)/sdk/.patched-$(SDK_VER): $(TOP_DIR)/cache/esp_iot_sdk_v$(SDK_PATCH_VER).zip
mkdir -p "$(dir $@)/patch"
(cd "$(dir $@)/patch" && unzip $(TOP_DIR)/cache/esp_iot_sdk_v$(SDK_PATCH_VER)*.zip *.a && mv *.a $(SDK_DIR)/lib/)
rmdir $(dir $@)/patch
rm -f $(SDK_DIR)/lib/liblwip.a
touch $@
......@@ -188,6 +217,11 @@ $(TOP_DIR)/cache/esp_iot_sdk_v$(SDK_FILE_VER).zip:
wget --tries=10 --timeout=15 --waitretry=30 --read-timeout=20 --retry-connrefused http://bbs.espressif.com/download/file.php?id=$(SDK_FILE_ID) -O $@ || { rm -f "$@"; exit 1; }
(echo "$(SDK_FILE_SHA1) $@" | sha1sum -c -) || { rm -f "$@"; exit 1; }
$(TOP_DIR)/cache/esp_iot_sdk_v$(SDK_PATCH_VER).zip:
mkdir -p "$(dir $@)"
wget --tries=10 --timeout=15 --waitretry=30 --read-timeout=20 --retry-connrefused http://bbs.espressif.com/download/file.php?id=$(SDK_PATCH_ID) -O $@ || { rm -f "$@"; exit 1; }
(echo "$(SDK_PATCH_SHA1) $@" | sha1sum -c -) || { rm -f "$@"; exit 1; }
clean:
$(foreach d, $(SUBDIRS), $(MAKE) -C $(d) clean;)
$(RM) -r $(ODIR)/$(TARGET)/$(FLAVOR)
......@@ -218,11 +252,24 @@ endif
endif
endif
.PHONY: spiffs-image-remove
spiffs-image-remove:
$(MAKE) -C tools remove-image
.PHONY: spiffs-image
spiffs-image: bin/0x10000.bin
$(MAKE) -C tools
.PHONY: pre_build
ifneq ($(wildcard $(TOP_DIR)/server-ca.crt),)
pre_build:
pre_build: $(TOP_DIR)/app/modules/server-ca.crt.h
$(TOP_DIR)/app/modules/server-ca.crt.h: $(TOP_DIR)/server-ca.crt
python $(TOP_DIR)/tools/make_server_cert.py $(TOP_DIR)/server-ca.crt > $(TOP_DIR)/app/modules/server-ca.crt.h
DEFINES += -DHAVE_SSL_SERVER_CRT=\"server-ca.crt.h\"
else
pre_build:
......
# **NodeMCU 1.5.1** #
# **NodeMCU 1.5.4.1** #
[![Join the chat at https://gitter.im/nodemcu/nodemcu-firmware](https://img.shields.io/gitter/room/badges/shields.svg)](https://gitter.im/nodemcu/nodemcu-firmware?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Build Status](https://travis-ci.org/nodemcu/nodemcu-firmware.svg)](https://travis-ci.org/nodemcu/nodemcu-firmware)
[![Documentation Status](https://img.shields.io/badge/docs-master-yellow.svg?style=flat)](http://nodemcu.readthedocs.io/)
[![Documentation Status](https://img.shields.io/badge/docs-latest-yellow.svg?style=flat)](http://nodemcu.readthedocs.io/en/latest/)
[![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://github.com/nodemcu/nodemcu-firmware/blob/master/LICENSE)
### A Lua based firmware for ESP8266 WiFi SOC
NodeMCU is an [eLua](http://www.eluaproject.net/) based firmware for the [ESP8266 WiFi SOC from Espressif](http://espressif.com/en/products/esp8266/). The firmware is based on the [Espressif NON-OS SDK 1.5.1](http://bbs.espressif.com/viewtopic.php?f=46&p=5315) and uses a file system based on [spiffs](https://github.com/pellepl/spiffs). The code repository consists of 98.1% C-code that glues the thin Lua veneer to the SDK.
NodeMCU is an [eLua](http://www.eluaproject.net/) based firmware for the [ESP8266 WiFi SOC from Espressif](http://espressif.com/en/products/esp8266/). The firmware is based on the [Espressif NON-OS SDK 1.5.4.1](http://bbs.espressif.com/viewtopic.php?f=46&t=2376) and uses a file system based on [spiffs](https://github.com/pellepl/spiffs). The code repository consists of 98.1% C-code that glues the thin Lua veneer to the SDK.
The NodeMCU *firmware* is a companion project to the popular [NodeMCU dev kits](https://github.com/nodemcu/nodemcu-devkit-v1.0), ready-made open source development boards with ESP8266-12E chips.
......@@ -28,11 +28,11 @@ The NodeMCU programming model is similar to that of [Node.js](https://en.wikiped
-- a simple HTTP server
srv = net.createServer(net.TCP)
srv:listen(80, function(conn)
conn:on("receive", function(conn, payload)
conn:on("receive", function(sck, payload)
print(payload)
conn:send("<h1> Hello, NodeMCU.</h1>")
sck:send("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n<h1> Hello, NodeMCU.</h1>")
end)
conn:on("sent", function(conn) conn:close() end)
conn:on("sent", function(sck) sck:close() end)
end)
```
```lua
......@@ -46,6 +46,7 @@ wifi.sta.config("SSID", "password")
The entire [NodeMCU documentation](https://nodemcu.readthedocs.io) is maintained right in this repository at [/docs](docs). The fact that the API documentation is mainted in the same repository as the code that *provides* the API ensures consistency between the two. With every commit the documentation is rebuilt by Read the Docs and thus transformed from terse Markdown into a nicely browsable HTML site at [https://nodemcu.readthedocs.io](https://nodemcu.readthedocs.io).
- How to [build the firmware](https://nodemcu.readthedocs.io/en/dev/en/build/)
- How to [build the filesystem](https://nodemcu.readthedocs.io/en/dev/en/spiffs/)
- How to [flash the firmware](https://nodemcu.readthedocs.io/en/dev/en/flash/)
- How to [upload code and NodeMCU IDEs](https://nodemcu.readthedocs.io/en/dev/en/upload/)
- API documentation for every module
......@@ -54,7 +55,7 @@ The entire [NodeMCU documentation](https://nodemcu.readthedocs.io) is maintained
Due to the ever-growing number of modules available within NodeMCU, pre-built binaries are no longer made available. Use the automated [custom firmware build service](http://nodemcu-build.com/) to get the specific firmware configuration you need, or consult the [documentation](http://nodemcu.readthedocs.io/en/dev/en/build/) for other options to build your own firmware.
This projects uses two main branches, `master` and `dev`. `dev` is actively worked on and it's also where PRs should be created against. `master` thus can be considered "stable" even though there are no automated regression tests. The goal is to merge back to `master` roughly every 2 months. Depending on the current "heat" (issues, PRs) we accept changes to `dev` for 5-6 weeks and then hold back for 2-3 weeks before the next snap is completed.
This project uses two main branches, `master` and `dev`. `dev` is actively worked on and it's also where PRs should be created against. `master` thus can be considered "stable" even though there are no automated regression tests. The goal is to merge back to `master` roughly every 2 months. Depending on the current "heat" (issues, PRs) we accept changes to `dev` for 5-6 weeks and then hold back for 2-3 weeks before the next snap is completed.
A new tag is created every time `dev` is merged back to `master`. They are listed in the [releases section here on GitHub](https://github.com/nodemcu/nodemcu-firmware/releases). Tag names follow the \<SDK-version\>-master_yyyymmdd pattern.
......@@ -89,7 +90,7 @@ Edit `app/include/user_modules.h` and comment-out the `#define` statement for mo
Identify your firmware builds by editing `app/include/user_version.h`
```c
#define NODE_VERSION "NodeMCU 1.5.1+myname"
#define NODE_VERSION "NodeMCU 1.5.4.1+myname"
#ifndef BUILD_DATE
#define BUILD_DATE "YYYYMMDD"
#endif
......
......@@ -24,6 +24,7 @@ SPECIAL_MKTARGETS=$(APP_MKTARGETS)
SUBDIRS= \
user \
driver \
pcm \
platform \
libc \
lua \
......@@ -69,6 +70,7 @@ LD_FILE = $(LDDIR)/nodemcu.ld
COMPONENTS_eagle.app.v6 = \
user/libuser.a \
driver/libdriver.a \
pcm/pcm.a \
platform/libplatform.a \
task/libtask.a \
libc/liblibc.a \
......
......@@ -98,7 +98,7 @@ int coap_buildToken(const coap_buffer_t *tokbuf, const coap_header_t *hdr, uint8
p = buf + 4;
if ((hdr->tkl > 0) && (hdr->tkl != tokbuf->len))
return COAP_ERR_UNSUPPORTED;
if (hdr->tkl > 0)
c_memcpy(p, tokbuf->p, hdr->tkl);
......@@ -483,7 +483,7 @@ int coap_make_request(coap_rw_buffer_t *scratch, coap_packet_t *pkt, coap_msgtyp
if (uri->port != COAP_DEFAULT_PORT) {
pkt->opts[pkt->numopts].num = COAP_OPTION_URI_PORT;
res = coap_encode_var_bytes(scratch->p, uri->port);
res = coap_encode_var_bytes(scratch->p, uri->port);
pkt->opts[pkt->numopts].buf.len = res;
pkt->opts[pkt->numopts].buf.p = scratch->p;
scratch->p += res;
......@@ -496,7 +496,7 @@ int coap_make_request(coap_rw_buffer_t *scratch, coap_packet_t *pkt, coap_msgtyp
}
if (uri->query.length) {
res = coap_split_query(scratch, pkt, uri->query.s, uri->query.length);
res = coap_split_query(scratch, pkt, uri->query.s, uri->query.length);
}
pkt->payload.p = payload;
......@@ -546,7 +546,7 @@ next:
void coap_setup(void)
{
message_id = (unsigned short)rand(); // calculate only once
message_id = (unsigned short)os_random(); // calculate only once
}
inline int
......
......@@ -107,7 +107,6 @@ uint8_t onewire_reset(uint8_t pin)
noInterrupts();
DIRECT_WRITE_LOW(pin);
DIRECT_MODE_OUTPUT(pin); // drive output low
interrupts();
delayMicroseconds(480);
noInterrupts();
......@@ -126,19 +125,12 @@ uint8_t onewire_reset(uint8_t pin)
static void onewire_write_bit(uint8_t pin, uint8_t v)
{
if (v & 1) {
noInterrupts();
DIRECT_WRITE_LOW(pin);
DIRECT_MODE_OUTPUT(pin); // drive output low
delayMicroseconds(10);
DIRECT_WRITE_HIGH(pin); // drive output high
interrupts();
delayMicroseconds(55);
onewire_read_bit(pin);
} else {
noInterrupts();
DIRECT_WRITE_LOW(pin);
DIRECT_MODE_OUTPUT(pin); // drive output low
delayMicroseconds(65);
DIRECT_WRITE_HIGH(pin); // drive output high
DIRECT_MODE_INPUT(pin); // drive output high by the pull-up
interrupts();
delayMicroseconds(5);
}
......@@ -153,14 +145,14 @@ static uint8_t onewire_read_bit(uint8_t pin)
uint8_t r;
noInterrupts();
DIRECT_MODE_OUTPUT(pin);
DIRECT_WRITE_LOW(pin);
delayMicroseconds(3);
delayMicroseconds(5);
DIRECT_MODE_INPUT(pin); // let pin float, pull up will raise
delayMicroseconds(10);
delayMicroseconds(8);
r = DIRECT_READ(pin);
interrupts();
delayMicroseconds(53);
delayMicroseconds(52);
return r;
}
......@@ -177,10 +169,10 @@ void onewire_write(uint8_t pin, uint8_t v, uint8_t power /* = 0 */) {
for (bitMask = 0x01; bitMask; bitMask <<= 1) {
onewire_write_bit(pin, (bitMask & v)?1:0);
}
if ( !power) {
if ( power ) {
noInterrupts();
DIRECT_MODE_INPUT(pin);
DIRECT_WRITE_LOW(pin);
DIRECT_WRITE_HIGH(pin);
interrupts();
}
}
......@@ -189,10 +181,10 @@ void onewire_write_bytes(uint8_t pin, const uint8_t *buf, uint16_t count, bool p
uint16_t i;
for (i = 0 ; i < count ; i++)
onewire_write(pin, buf[i], owDefaultPower);
if (!power) {
if ( power ) {
noInterrupts();
DIRECT_MODE_INPUT(pin);
DIRECT_WRITE_LOW(pin);
DIRECT_WRITE_HIGH(pin);
interrupts();
}
}
......@@ -474,7 +466,7 @@ uint8_t onewire_crc8(const uint8_t *addr, uint8_t len)
uint8_t onewire_crc8(const uint8_t *addr, uint8_t len)
{
uint8_t crc = 0;
while (len--) {
uint8_t inbyte = *addr++;
uint8_t i;
......@@ -501,8 +493,8 @@ uint8_t onewire_crc8(const uint8_t *addr, uint8_t len)
// ReadBytes(net, buf+3, 10); // Read 6 data bytes, 2 0xFF, 2 CRC16
// if (!CheckCRC16(buf, 11, &buf[11])) {
// // Handle error.
// }
//
// }
//
// @param input - Array of bytes to checksum.
// @param len - How many bytes to use.
// @param inverted_crc - The two CRC16 bytes in the received data.
......
#include "platform.h"
#include "driver/sigma_delta.h"
......@@ -18,7 +19,7 @@ void sigma_delta_stop( void )
GPIO_SIGMA_DELTA_PRESCALE_SET(0x00) );
}
void sigma_delta_set_prescale_target( sint16 prescale, sint16 target )
void ICACHE_RAM_ATTR sigma_delta_set_prescale_target( sint16 prescale, sint16 target )
{
uint32_t prescale_mask, target_mask;
......
......@@ -70,7 +70,7 @@ void spi_master_init(uint8 spi_no, unsigned cpol, unsigned cpha, uint32_t clock_
if(spi_no>1) return; //handle invalid input number
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CS_SETUP|SPI_CS_HOLD|SPI_RD_BYTE_ORDER|SPI_WR_BYTE_ORDER|SPI_DOUTDIN);
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CS_SETUP|SPI_CS_HOLD|SPI_RD_BYTE_ORDER|SPI_WR_BYTE_ORDER);
// set clock polarity (Reference: http://bbs.espressif.com/viewtopic.php?f=49&t=1570)
// phase is dependent on polarity. See Issue #1161
......@@ -85,12 +85,10 @@ void spi_master_init(uint8 spi_no, unsigned cpol, unsigned cpha, uint32_t clock_
// Mode 3: MOSI is set on falling edge of clock
// Mode 0: MOSI is set on falling edge of clock
CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_CK_OUT_EDGE);
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CK_I_EDGE);
} else {
// Mode 2: MOSI is set on rising edge of clock
// Mode 1: MOSI is set on rising edge of clock
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CK_OUT_EDGE);
CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_CK_I_EDGE);
}
CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_FLASH_MODE|SPI_USR_MISO|SPI_USR_ADDR|SPI_USR_COMMAND|SPI_USR_DUMMY);
......@@ -98,31 +96,28 @@ void spi_master_init(uint8 spi_no, unsigned cpol, unsigned cpha, uint32_t clock_
//clear Dual or Quad lines transmission mode
CLEAR_PERI_REG_MASK(SPI_CTRL(spi_no), SPI_QIO_MODE|SPI_DIO_MODE|SPI_DOUT_MODE|SPI_QOUT_MODE);
// SPI clock = CPU clock / clock_div
// the divider needs to be a multiple of 2 to get a proper waveform shape
if ((clock_div & 0x01) != 0) {
// bump the divider to the next N*2
clock_div += 0x02;
if (clock_div > 1) {
uint8 i, k;
i = (clock_div / 40) ? (clock_div / 40) : 1;
k = clock_div / i;
WRITE_PERI_REG(SPI_CLOCK(spi_no),
(((i - 1) & SPI_CLKDIV_PRE) << SPI_CLKDIV_PRE_S) |
(((k - 1) & SPI_CLKCNT_N) << SPI_CLKCNT_N_S) |
((((k + 1) / 2 - 1) & SPI_CLKCNT_H) << SPI_CLKCNT_H_S) |
(((k - 1) & SPI_CLKCNT_L) << SPI_CLKCNT_L_S)); //clear bit 31,set SPI clock div
} else {
WRITE_PERI_REG(SPI_CLOCK(spi_no), SPI_CLK_EQU_SYSCLK); // 80Mhz speed
}
clock_div >>= 1;
// clip to maximum possible CLKDIV_PRE
clock_div = clock_div > SPI_CLKDIV_PRE ? SPI_CLKDIV_PRE : clock_div - 1;
WRITE_PERI_REG(SPI_CLOCK(spi_no),
((clock_div&SPI_CLKDIV_PRE)<<SPI_CLKDIV_PRE_S)|
((1&SPI_CLKCNT_N)<<SPI_CLKCNT_N_S)|
((0&SPI_CLKCNT_H)<<SPI_CLKCNT_H_S)|
((1&SPI_CLKCNT_L)<<SPI_CLKCNT_L_S)); //clear bit 31,set SPI clock div
if(spi_no==SPI){
WRITE_PERI_REG(PERIPHS_IO_MUX, 0x005);
WRITE_PERI_REG(PERIPHS_IO_MUX, 0x005 | (clock_div <= 1 ? 0x100 : 0));
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, 1);//configure io to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, 1);//configure io to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA0_U, 1);//configure io to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA1_U, 1);//configure io to spi mode
}
else if(spi_no==HSPI){
WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105);
WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105 | (clock_div <= 1 ? 0x200 : 0));
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2);//configure io to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2);//configure io to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2);//configure io to spi mode
......
/*
* Module for interfacing with Switec instrument steppers (and
* similar devices). These are the steppers that are used in automotive
* instrument panels and the like. Run off 5 volts at low current.
*
* Code inspired by:
*
* SwitecX25 Arduino Library
* Guy Carpenter, Clearwater Software - 2012
*
* Licensed under the BSD2 license, see license.txt for details.
*
* NodeMcu integration by Philip Gladstone, N1DQ
*/
#include "platform.h"
#include "c_types.h"
#include "../libc/c_stdlib.h"
#include "../libc/c_stdio.h"
#include "driver/switec.h"
#include "ets_sys.h"
#include "os_type.h"
#include "osapi.h"
#include "hw_timer.h"
#include "user_interface.h"
#include "task/task.h"
#define N_STATES 6
//
// First pin passed to setup corresponds to bit 3
// On the motor, the pins are arranged
//
// 4 1
//
// 3 2
//
// The direction of rotation can be reversed by reordering the pins
//
// State 3 2 1 0 A B Value
// 0 1 0 0 1 - - 0x9
// 1 0 0 0 1 . - 0x1
// 2 0 1 1 1 + . 0x7
// 3 0 1 1 0 + + 0x6
// 4 1 1 1 0 . + 0xE
// 5 1 0 0 0 - . 0x8
static const uint8_t stateMap[N_STATES] = {0x9, 0x1, 0x7, 0x6, 0xE, 0x8};
typedef struct {
uint8_t current_state;
uint8_t stopped;
int8_t dir;
uint32_t mask;
uint32_t pinstate[N_STATES];
uint32_t next_time;
int16_t target_step;
int16_t current_step;
uint16_t vel;
uint16_t max_vel;
uint16_t min_delay;
task_handle_t task_number;
} DATA;
static DATA *data[SWITEC_CHANNEL_COUNT];
static volatile char timer_active;
#define MAXVEL 255
// Note that this has to be global so that the compiler does not
// put it into ROM.
uint8_t switec_accel_table[][2] = {
{ 20, 3000 >> 4},
{ 50, 1500 >> 4},
{ 100, 1000 >> 4},
{ 150, 800 >> 4},
{ MAXVEL, 600 >> 4}
};
static void ICACHE_RAM_ATTR timer_interrupt(os_param_t);
#define TIMER_OWNER ((os_param_t) 'S')
// Just takes the channel number
int switec_close(uint32_t channel)
{
if (channel >= sizeof(data) / sizeof(data[0])) {
return -1;
}
DATA *d = data[channel];
if (!d) {
return 0;
}
if (!d->stopped) {
return -1;
}
// Set pins as input
gpio_output_set(0, 0, 0, d->mask);
data[channel] = NULL;
c_free(d);
// See if there are any other channels active
for (channel = 0; channel < sizeof(data)/sizeof(data[0]); channel++) {
if (data[channel]) {
break;
}
}
// If not, then disable the interrupt
if (channel >= sizeof(data) / sizeof(data[0])) {
platform_hw_timer_close(TIMER_OWNER);
}
return 0;
}
static __attribute__((always_inline)) inline void write_io(DATA *d)
{
uint32_t pin_state = d->pinstate[d->current_state];
gpio_output_set(pin_state, d->mask & ~pin_state, 0, 0);
}
static __attribute__((always_inline)) inline void step_up(DATA *d)
{
d->current_step++;
d->current_state = (d->current_state + 1) % N_STATES;
write_io(d);
}
static __attribute__((always_inline)) inline void step_down(DATA *d)
{
d->current_step--;
d->current_state = (d->current_state + N_STATES - 1) % N_STATES;
write_io(d);
}
static void ICACHE_RAM_ATTR timer_interrupt(os_param_t p)
{
// This function really is running at interrupt level with everything
// else masked off. It should take as little time as necessary.
//
(void) p;
int i;
uint32_t delay = 0xffffffff;
// Loop over the channels to figure out which one needs action
for (i = 0; i < sizeof(data) / sizeof(data[0]); i++) {
DATA *d = data[i];
if (!d || d->stopped) {
continue;
}
uint32_t now = system_get_time();
if (now < d->next_time) {
int need_to_wait = d->next_time - now;
if (need_to_wait < delay) {
delay = need_to_wait;
}
continue;
}
// This channel is past it's action time. Need to process it
// Are we done yet?
if (d->current_step == d->target_step && d->vel == 0) {
d->stopped = 1;
d->dir = 0;
task_post_low(d->task_number, 0);
continue;
}
// if stopped, determine direction
if (d->vel == 0) {
d->dir = d->current_step < d->target_step ? 1 : -1;
// do not set to 0 or it could go negative in case 2 below
d->vel = 1;
}
// Move the pointer by one step in the correct direction
if (d->dir > 0) {
step_up(d);
} else {
step_down(d);
}
// determine delta, number of steps in current direction to target.
// may be negative if we are headed away from target
int delta = d->dir > 0 ? d->target_step - d->current_step : d->current_step - d->target_step;
if (delta > 0) {
// case 1 : moving towards target (maybe under accel or decel)