esp8266: add support for this chip
Many thanks to cnlohr for the nosdk8266 project: https://github.com/cnlohr/nosdk8266
Этот коммит содержится в:
родитель
0b9b293651
коммит
2ce17a1892
11 изменённых файлов: 489 добавлений и 31 удалений
3
Makefile
3
Makefile
|
@ -356,6 +356,9 @@ ifneq ($(AVR), 0)
|
|||
endif
|
||||
ifneq ($(XTENSA), 0)
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32-wroom-32 examples/blinky1
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=nodemcu examples/blinky1
|
||||
@$(MD5SUM) test.bin
|
||||
endif
|
||||
$(TINYGO) build -size short -o test.hex -target=hifive1b examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
|
|
|
@ -292,10 +292,11 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case "esp32":
|
||||
// Special format for the ESP32 chip (parsed by the ROM bootloader).
|
||||
case "esp32", "esp8266":
|
||||
// Special format for the ESP family of chips (parsed by the ROM
|
||||
// bootloader).
|
||||
tmppath = filepath.Join(dir, "main"+outext)
|
||||
err := makeESP32FirmareImage(executable, tmppath)
|
||||
err := makeESPFirmareImage(executable, tmppath, outputBinaryFormat)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -22,15 +22,15 @@ type espImageSegment struct {
|
|||
data []byte
|
||||
}
|
||||
|
||||
// makeESP32Firmare converts an input ELF file to an image file for the ESP32
|
||||
// chip. This is a special purpose image format just for the ESP32 chip, and is
|
||||
// parsed by the on-chip mask ROM bootloader.
|
||||
// makeESPFirmare converts an input ELF file to an image file for an ESP32 or
|
||||
// ESP8266 chip. This is a special purpose image format just for the ESP chip
|
||||
// family, and is parsed by the on-chip mask ROM bootloader.
|
||||
//
|
||||
// The following documentation has been used:
|
||||
// https://github.com/espressif/esptool/wiki/Firmware-Image-Format
|
||||
// https://github.com/espressif/esp-idf/blob/8fbb63c2a701c22ccf4ce249f43aded73e134a34/components/bootloader_support/include/esp_image_format.h#L58
|
||||
// https://github.com/espressif/esptool/blob/master/esptool.py
|
||||
func makeESP32FirmareImage(infile, outfile string) error {
|
||||
func makeESPFirmareImage(infile, outfile, format string) error {
|
||||
inf, err := elf.Open(infile)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -79,26 +79,49 @@ func makeESP32FirmareImage(infile, outfile string) error {
|
|||
outf := &bytes.Buffer{}
|
||||
|
||||
// Image header.
|
||||
// Details: https://github.com/espressif/esp-idf/blob/8fbb63c2/components/bootloader_support/include/esp_image_format.h#L58
|
||||
binary.Write(outf, binary.LittleEndian, struct {
|
||||
magic uint8
|
||||
segment_count uint8
|
||||
spi_mode uint8
|
||||
spi_speed_size uint8
|
||||
entry_addr uint32
|
||||
wp_pin uint8
|
||||
spi_pin_drv [3]uint8
|
||||
reserved [11]uint8
|
||||
hash_appended bool
|
||||
}{
|
||||
magic: 0xE9,
|
||||
segment_count: byte(len(segments)),
|
||||
spi_mode: 0, // irrelevant, replaced by esptool when flashing
|
||||
spi_speed_size: 0, // spi_speed, spi_size: replaced by esptool when flashing
|
||||
entry_addr: uint32(inf.Entry),
|
||||
wp_pin: 0xEE, // disable WP pin
|
||||
hash_appended: true, // add a SHA256 hash
|
||||
})
|
||||
switch format {
|
||||
case "esp32":
|
||||
// Header format:
|
||||
// https://github.com/espressif/esp-idf/blob/8fbb63c2/components/bootloader_support/include/esp_image_format.h#L58
|
||||
binary.Write(outf, binary.LittleEndian, struct {
|
||||
magic uint8
|
||||
segment_count uint8
|
||||
spi_mode uint8
|
||||
spi_speed_size uint8
|
||||
entry_addr uint32
|
||||
wp_pin uint8
|
||||
spi_pin_drv [3]uint8
|
||||
reserved [11]uint8
|
||||
hash_appended bool
|
||||
}{
|
||||
magic: 0xE9,
|
||||
segment_count: byte(len(segments)),
|
||||
spi_mode: 0, // irrelevant, replaced by esptool when flashing
|
||||
spi_speed_size: 0, // spi_speed, spi_size: replaced by esptool when flashing
|
||||
entry_addr: uint32(inf.Entry),
|
||||
wp_pin: 0xEE, // disable WP pin
|
||||
hash_appended: true, // add a SHA256 hash
|
||||
})
|
||||
case "esp8266":
|
||||
// Header format:
|
||||
// https://github.com/espressif/esptool/wiki/Firmware-Image-Format
|
||||
// Basically a truncated version of the ESP32 header.
|
||||
binary.Write(outf, binary.LittleEndian, struct {
|
||||
magic uint8
|
||||
segment_count uint8
|
||||
spi_mode uint8
|
||||
spi_speed_size uint8
|
||||
entry_addr uint32
|
||||
}{
|
||||
magic: 0xE9,
|
||||
segment_count: byte(len(segments)),
|
||||
spi_mode: 0, // irrelevant, replaced by esptool when flashing
|
||||
spi_speed_size: 0x20, // spi_speed, spi_size: replaced by esptool when flashing
|
||||
entry_addr: uint32(inf.Entry),
|
||||
})
|
||||
default:
|
||||
return fmt.Errorf("builder: unknown binary format %#v, expected esp32 or esp8266", format)
|
||||
}
|
||||
|
||||
// Write all segments to the image.
|
||||
// https://github.com/espressif/esptool/wiki/Firmware-Image-Format#segment
|
||||
|
@ -119,9 +142,11 @@ func makeESP32FirmareImage(infile, outfile string) error {
|
|||
outf.Write(make([]byte, 15-outf.Len()%16))
|
||||
outf.WriteByte(checksum)
|
||||
|
||||
// SHA256 hash (to protect against image corruption, not for security).
|
||||
hash := sha256.Sum256(outf.Bytes())
|
||||
outf.Write(hash[:])
|
||||
if format == "esp32" {
|
||||
// SHA256 hash (to protect against image corruption, not for security).
|
||||
hash := sha256.Sum256(outf.Bytes())
|
||||
outf.Write(hash[:])
|
||||
}
|
||||
|
||||
// Write the image to the output file.
|
||||
return ioutil.WriteFile(outfile, outf.Bytes(), 0666)
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 2fc335802cf97309ec4035caf276746b53efbd5b
|
||||
Subproject commit d9b58694cef35b39ddf61c07ef7e6347d6ec3cbd
|
6
src/device/esp/esp8266.S
Обычный файл
6
src/device/esp/esp8266.S
Обычный файл
|
@ -0,0 +1,6 @@
|
|||
|
||||
.section .text.tinygo_scanCurrentStack
|
||||
.global tinygo_scanCurrentStack
|
||||
tinygo_scanCurrentStack:
|
||||
// TODO: save callee saved registers on the stack
|
||||
j tinygo_scanstack
|
21
src/machine/board_nodemcu.go
Обычный файл
21
src/machine/board_nodemcu.go
Обычный файл
|
@ -0,0 +1,21 @@
|
|||
// +build nodemcu
|
||||
|
||||
// Pinout for the NodeMCU dev kit.
|
||||
|
||||
package machine
|
||||
|
||||
// GPIO pins on the NodeMCU board.
|
||||
const (
|
||||
D0 Pin = 16
|
||||
D1 Pin = 5
|
||||
D2 Pin = 4
|
||||
D3 Pin = 0
|
||||
D4 Pin = 2
|
||||
D5 Pin = 14
|
||||
D6 Pin = 12
|
||||
D7 Pin = 13
|
||||
D8 Pin = 15
|
||||
)
|
||||
|
||||
// Onboard blue LED (on the AI-Thinker module).
|
||||
const LED = D4
|
159
src/machine/machine_esp8266.go
Обычный файл
159
src/machine/machine_esp8266.go
Обычный файл
|
@ -0,0 +1,159 @@
|
|||
// +build esp8266
|
||||
|
||||
package machine
|
||||
|
||||
import (
|
||||
"device/esp"
|
||||
"runtime/volatile"
|
||||
)
|
||||
|
||||
func CPUFrequency() uint32 {
|
||||
return 80000000 // 80MHz
|
||||
}
|
||||
|
||||
type PinMode uint8
|
||||
|
||||
const (
|
||||
PinOutput PinMode = iota
|
||||
PinInput
|
||||
)
|
||||
|
||||
// Pins that are fixed by the chip.
|
||||
const (
|
||||
UART_TX_PIN Pin = 1
|
||||
UART_RX_PIN Pin = 3
|
||||
)
|
||||
|
||||
// Pin functions are not trivial. The below array maps a pin number (GPIO
|
||||
// number) to the pad as used in the IO mux.
|
||||
// Tables with the mapping:
|
||||
// https://www.esp8266.com/wiki/doku.php?id=esp8266_gpio_pin_allocations#pin_functions
|
||||
// https://www.espressif.com/sites/default/files/documentation/ESP8266_Pin_List_0.xls
|
||||
var pinPadMapping = [...]uint8{
|
||||
12: 0,
|
||||
13: 1,
|
||||
14: 2,
|
||||
15: 3,
|
||||
3: 4,
|
||||
1: 5,
|
||||
6: 6,
|
||||
7: 7,
|
||||
8: 8,
|
||||
9: 9,
|
||||
10: 10,
|
||||
11: 11,
|
||||
0: 12,
|
||||
2: 13,
|
||||
4: 14,
|
||||
5: 15,
|
||||
}
|
||||
|
||||
// getPad returns the pad number and the register to configure this pad.
|
||||
func (p Pin) getPad() (uint8, *volatile.Register32) {
|
||||
pad := pinPadMapping[p]
|
||||
var reg *volatile.Register32
|
||||
switch pad {
|
||||
case 0:
|
||||
reg = &esp.IO_MUX.IO_MUX_MTDI
|
||||
case 1:
|
||||
reg = &esp.IO_MUX.IO_MUX_MTCK
|
||||
case 2:
|
||||
reg = &esp.IO_MUX.IO_MUX_MTMS
|
||||
case 3:
|
||||
reg = &esp.IO_MUX.IO_MUX_MTDO
|
||||
case 4:
|
||||
reg = &esp.IO_MUX.IO_MUX_U0RXD
|
||||
case 5:
|
||||
reg = &esp.IO_MUX.IO_MUX_U0TXD
|
||||
case 6:
|
||||
reg = &esp.IO_MUX.IO_MUX_SD_CLK
|
||||
case 7:
|
||||
reg = &esp.IO_MUX.IO_MUX_SD_DATA0
|
||||
case 8:
|
||||
reg = &esp.IO_MUX.IO_MUX_SD_DATA1
|
||||
case 9:
|
||||
reg = &esp.IO_MUX.IO_MUX_SD_DATA2
|
||||
case 10:
|
||||
reg = &esp.IO_MUX.IO_MUX_SD_DATA3
|
||||
case 11:
|
||||
reg = &esp.IO_MUX.IO_MUX_SD_CMD
|
||||
case 12:
|
||||
reg = &esp.IO_MUX.IO_MUX_GPIO0
|
||||
case 13:
|
||||
reg = &esp.IO_MUX.IO_MUX_GPIO2
|
||||
case 14:
|
||||
reg = &esp.IO_MUX.IO_MUX_GPIO4
|
||||
case 15:
|
||||
reg = &esp.IO_MUX.IO_MUX_GPIO5
|
||||
}
|
||||
return pad, reg
|
||||
}
|
||||
|
||||
// Configure sets the given pin as output or input pin.
|
||||
func (p Pin) Configure(config PinConfig) {
|
||||
switch config.Mode {
|
||||
case PinInput, PinOutput:
|
||||
pad, reg := p.getPad()
|
||||
if pad >= 12 { // pin 0, 2, 4, 5
|
||||
reg.Set(0 << 4) // function 0 at bit position 4
|
||||
} else {
|
||||
reg.Set(3 << 4) // function 3 at bit position 4
|
||||
}
|
||||
if config.Mode == PinOutput {
|
||||
esp.GPIO.GPIO_ENABLE_W1TS.Set(1 << p)
|
||||
} else {
|
||||
esp.GPIO.GPIO_ENABLE_W1TC.Set(1 << p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set sets the output value of this pin to high (true) or low (false).
|
||||
func (p Pin) Set(value bool) {
|
||||
if value {
|
||||
esp.GPIO.GPIO_OUT_W1TS.Set(1 << p)
|
||||
} else {
|
||||
esp.GPIO.GPIO_OUT_W1TC.Set(1 << p)
|
||||
}
|
||||
}
|
||||
|
||||
// Return the register and mask to enable a given GPIO pin. This can be used to
|
||||
// implement bit-banged drivers.
|
||||
//
|
||||
// Warning: only use this on an output pin!
|
||||
func (p Pin) PortMaskSet() (*uint32, uint32) {
|
||||
return &esp.GPIO.GPIO_OUT_W1TS.Reg, 1 << p
|
||||
}
|
||||
|
||||
// Return the register and mask to disable a given GPIO pin. This can be used to
|
||||
// implement bit-banged drivers.
|
||||
//
|
||||
// Warning: only use this on an output pin!
|
||||
func (p Pin) PortMaskClear() (*uint32, uint32) {
|
||||
return &esp.GPIO.GPIO_OUT_W1TC.Reg, 1 << p
|
||||
}
|
||||
|
||||
// UART0 is a hardware UART that supports both TX and RX.
|
||||
var UART0 = UART{Buffer: NewRingBuffer()}
|
||||
|
||||
type UART struct {
|
||||
Buffer *RingBuffer
|
||||
}
|
||||
|
||||
// Configure the UART baud rate. TX and RX pins are fixed by the hardware so
|
||||
// cannot be modified and will be ignored.
|
||||
func (uart UART) Configure(config UARTConfig) {
|
||||
if config.BaudRate == 0 {
|
||||
config.BaudRate = 115200
|
||||
}
|
||||
esp.UART0.UART_CLKDIV.Set(CPUFrequency() / config.BaudRate)
|
||||
}
|
||||
|
||||
// WriteByte writes a single byte to the output buffer. Note that the hardware
|
||||
// includes a buffer of 128 bytes which will be used first.
|
||||
func (uart UART) WriteByte(c byte) error {
|
||||
for (esp.UART0.UART_STATUS.Get()>>16)&0xff >= 128 {
|
||||
// Wait until the TX buffer has room.
|
||||
}
|
||||
esp.UART0.UART_FIFO.Set(uint32(c))
|
||||
return nil
|
||||
}
|
115
src/runtime/runtime_esp8266.go
Обычный файл
115
src/runtime/runtime_esp8266.go
Обычный файл
|
@ -0,0 +1,115 @@
|
|||
// +build esp8266
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"device"
|
||||
"device/esp"
|
||||
"machine"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type timeUnit int64
|
||||
|
||||
var currentTime timeUnit = 0
|
||||
|
||||
func putchar(c byte) {
|
||||
machine.UART0.WriteByte(c)
|
||||
}
|
||||
|
||||
// Write to the internal control bus (using I2C?).
|
||||
// Signature found here:
|
||||
// https://github.com/espressif/ESP8266_RTOS_SDK/blob/14171de0/components/esp8266/include/esp8266/rom_functions.h#L54
|
||||
//export rom_i2c_writeReg
|
||||
func rom_i2c_writeReg(block, host_id, reg_add, data uint8)
|
||||
|
||||
func postinit() {}
|
||||
|
||||
//export main
|
||||
func main() {
|
||||
// Clear .bss section. .data has already been loaded by the ROM bootloader.
|
||||
preinit()
|
||||
|
||||
// Initialize PLL.
|
||||
// I'm not quite sure what this magic incantation means, but it does set the
|
||||
// esp8266 to the right clock speed. Without this, it is running too slow.
|
||||
rom_i2c_writeReg(103, 4, 1, 136)
|
||||
rom_i2c_writeReg(103, 4, 2, 145)
|
||||
|
||||
// Initialize UART.
|
||||
machine.UART0.Configure(machine.UARTConfig{})
|
||||
|
||||
// Initialize timer. Bits:
|
||||
// ENABLE: timer enable
|
||||
// ROLLOVER: automatically reload when hitting 0
|
||||
// PRESCALE: divide by 256
|
||||
esp.TIMER.FRC1_CTRL.Set(
|
||||
esp.TIMER_FRC1_CTRL_TIMER_ENABLE | esp.TIMER_FRC1_CTRL_ROLLOVER | esp.TIMER_FRC1_CTRL_PRESCALE_DIVIDER_DEVIDED_BY_256<<esp.TIMER_FRC1_CTRL_PRESCALE_DIVIDER_Pos)
|
||||
esp.TIMER.FRC1_LOAD.Set(0x3fffff) // set all 22 bits to 1
|
||||
esp.TIMER.FRC1_COUNT.Set(0x3fffff) // set all 22 bits to 1
|
||||
|
||||
run()
|
||||
|
||||
// Fallback: if main ever returns, hang the CPU.
|
||||
abort()
|
||||
}
|
||||
|
||||
//go:extern _sbss
|
||||
var _sbss [0]byte
|
||||
|
||||
//go:extern _ebss
|
||||
var _ebss [0]byte
|
||||
|
||||
func preinit() {
|
||||
// Initialize .bss: zero-initialized global variables.
|
||||
ptr := unsafe.Pointer(&_sbss)
|
||||
for ptr != unsafe.Pointer(&_ebss) {
|
||||
*(*uint32)(ptr) = 0
|
||||
ptr = unsafe.Pointer(uintptr(ptr) + 4)
|
||||
}
|
||||
}
|
||||
|
||||
func ticks() timeUnit {
|
||||
// Get the counter value of the timer. It is 22 bits and starts with all
|
||||
// ones (0x3fffff). To make it easier to work with, let it count upwards.
|
||||
count := 0x3fffff - esp.TIMER.FRC1_COUNT.Get()
|
||||
|
||||
// Replace the lowest 22 bits of the current time with the counter.
|
||||
newTime := (currentTime &^ 0x3fffff) | timeUnit(count)
|
||||
|
||||
// If there was an overflow, the new time will be lower than the current
|
||||
// time, so will need to add (1<<22).
|
||||
if newTime < currentTime {
|
||||
newTime += 0x400000
|
||||
}
|
||||
|
||||
// Update the timestamp for the next call to ticks().
|
||||
currentTime = newTime
|
||||
|
||||
return currentTime
|
||||
}
|
||||
|
||||
const asyncScheduler = false
|
||||
|
||||
const tickNanos = 3200 // time.Second / (80MHz / 256)
|
||||
|
||||
func ticksToNanoseconds(ticks timeUnit) int64 {
|
||||
return int64(ticks) * tickNanos
|
||||
}
|
||||
|
||||
func nanosecondsToTicks(ns int64) timeUnit {
|
||||
return timeUnit(ns / tickNanos)
|
||||
}
|
||||
|
||||
// sleepTicks busy-waits until the given number of ticks have passed.
|
||||
func sleepTicks(d timeUnit) {
|
||||
sleepUntil := ticks() + d
|
||||
for ticks() < sleepUntil {
|
||||
}
|
||||
}
|
||||
|
||||
func abort() {
|
||||
for {
|
||||
device.Asm("waiti 0")
|
||||
}
|
||||
}
|
15
targets/esp8266.json
Обычный файл
15
targets/esp8266.json
Обычный файл
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"inherits": ["xtensa"],
|
||||
"cpu": "esp8266",
|
||||
"build-tags": ["esp8266", "esp"],
|
||||
"linker": "xtensa-esp32-elf-ld",
|
||||
"cflags": [
|
||||
"-mcpu=esp8266"
|
||||
],
|
||||
"linkerscript": "targets/esp8266.ld",
|
||||
"extra-files": [
|
||||
"src/device/esp/esp8266.S"
|
||||
],
|
||||
"binary-format": "esp8266",
|
||||
"flash-command": "esptool.py --chip=esp8266 --port {port} write_flash 0x00000 {bin} -fm qio"
|
||||
}
|
109
targets/esp8266.ld
Обычный файл
109
targets/esp8266.ld
Обычный файл
|
@ -0,0 +1,109 @@
|
|||
/* Linker script for the ESP8266 */
|
||||
|
||||
MEMORY
|
||||
{
|
||||
/* Data RAM. Allows byte access. */
|
||||
DRAM (rw) : ORIGIN = 0x3FFE8000, LENGTH = 80K
|
||||
/* Instruction RAM. */
|
||||
IRAM (x) : ORIGIN = 0x40100000, LENGTH = 32K
|
||||
}
|
||||
|
||||
/* The entry point. It is set in the image flashed to the chip, so must be
|
||||
* defined.
|
||||
*/
|
||||
ENTRY(main)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/* Mutable global variables.
|
||||
*/
|
||||
.data : ALIGN(4)
|
||||
{
|
||||
_sdata = ABSOLUTE(.);
|
||||
*(.data)
|
||||
*(.data.*)
|
||||
} >DRAM
|
||||
|
||||
/* Constant global variables.
|
||||
* Note that they still need to be loaded in RAM because the ESP8266 doesn't
|
||||
* allow byte access to flash.
|
||||
*/
|
||||
.rodata : ALIGN(4)
|
||||
{
|
||||
*(.rodata)
|
||||
*(.rodata.*)
|
||||
} >DRAM
|
||||
|
||||
/* Global variables that are mutable and zero-initialized.
|
||||
*/
|
||||
.bss (NOLOAD) : ALIGN(4)
|
||||
{
|
||||
. = ALIGN (4);
|
||||
_sbss = ABSOLUTE(.);
|
||||
*(.bss)
|
||||
*(.bss.*)
|
||||
. = ALIGN (4);
|
||||
_ebss = ABSOLUTE(.);
|
||||
} >DRAM
|
||||
|
||||
/* Constant literals and code. Loaded into IRAM for now. Eventually, most
|
||||
* code should be executed directly from flash.
|
||||
* Note that literals must be before code for the l32r instruction to work.
|
||||
*/
|
||||
.text : ALIGN(4)
|
||||
{
|
||||
*(.literal .text)
|
||||
*(.literal.* .text.*)
|
||||
} >IRAM
|
||||
}
|
||||
|
||||
_globals_start = _sdata;
|
||||
_globals_end = _ebss;
|
||||
_heap_start = _ebss;
|
||||
_heap_end = ORIGIN(DRAM) + LENGTH(DRAM);
|
||||
|
||||
/* It appears that the stack is set to 0x3ffffff0 when main is called.
|
||||
* Be conservative and scan all the way up to the end of the RAM.
|
||||
*/
|
||||
_stack_top = 0x40000000;
|
||||
|
||||
/* Functions normally provided by a libc.
|
||||
* Source:
|
||||
* https://github.com/espressif/ESP8266_NONOS_SDK/blob/master/ld/eagle.rom.addr.v6.ld
|
||||
*/
|
||||
memcpy = 0x4000df48;
|
||||
memmove = 0x4000e04c;
|
||||
memset = 0x4000e190;
|
||||
|
||||
/* Compiler runtime functions provided by the ROM.
|
||||
* Source:
|
||||
* https://github.com/espressif/ESP8266_NONOS_SDK/blob/master/ld/eagle.rom.addr.v6.ld
|
||||
*/
|
||||
__adddf3 = 0x4000c538;
|
||||
__addsf3 = 0x4000c180;
|
||||
__divdf3 = 0x4000cb94;
|
||||
__divdi3 = 0x4000ce60;
|
||||
__divsi3 = 0x4000dc88;
|
||||
__extendsfdf2 = 0x4000cdfc;
|
||||
__fixdfsi = 0x4000ccb8;
|
||||
__fixunsdfsi = 0x4000cd00;
|
||||
__fixunssfsi = 0x4000c4c4;
|
||||
__floatsidf = 0x4000e2f0;
|
||||
__floatsisf = 0x4000e2ac;
|
||||
__floatunsidf = 0x4000e2e8;
|
||||
__floatunsisf = 0x4000e2a4;
|
||||
__muldf3 = 0x4000c8f0;
|
||||
__muldi3 = 0x40000650;
|
||||
__mulsf3 = 0x4000c3dc;
|
||||
__subdf3 = 0x4000c688;
|
||||
__subsf3 = 0x4000c268;
|
||||
__truncdfsf2 = 0x4000cd5c;
|
||||
__udivdi3 = 0x4000d310;
|
||||
__udivsi3 = 0x4000e21c;
|
||||
__umoddi3 = 0x4000d770;
|
||||
__umodsi3 = 0x4000e268;
|
||||
__umulsidi3 = 0x4000dcf0;
|
||||
|
||||
/* Proprietary ROM function needed for proper clock configuration.
|
||||
*/
|
||||
rom_i2c_writeReg = 0x400072d8;
|
4
targets/nodemcu.json
Обычный файл
4
targets/nodemcu.json
Обычный файл
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"inherits": ["esp8266"],
|
||||
"build-tags": ["nodemcu"]
|
||||
}
|
Загрузка…
Создание таблицы
Сослаться в новой задаче