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
|
endif
|
||||||
ifneq ($(XTENSA), 0)
|
ifneq ($(XTENSA), 0)
|
||||||
$(TINYGO) build -size short -o test.bin -target=esp32-wroom-32 examples/blinky1
|
$(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
|
endif
|
||||||
$(TINYGO) build -size short -o test.hex -target=hifive1b examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=hifive1b examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
|
|
|
@ -292,10 +292,11 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case "esp32":
|
case "esp32", "esp8266":
|
||||||
// Special format for the ESP32 chip (parsed by the ROM bootloader).
|
// Special format for the ESP family of chips (parsed by the ROM
|
||||||
|
// bootloader).
|
||||||
tmppath = filepath.Join(dir, "main"+outext)
|
tmppath = filepath.Join(dir, "main"+outext)
|
||||||
err := makeESP32FirmareImage(executable, tmppath)
|
err := makeESPFirmareImage(executable, tmppath, outputBinaryFormat)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,15 +22,15 @@ type espImageSegment struct {
|
||||||
data []byte
|
data []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// makeESP32Firmare converts an input ELF file to an image file for the ESP32
|
// makeESPFirmare converts an input ELF file to an image file for an ESP32 or
|
||||||
// chip. This is a special purpose image format just for the ESP32 chip, and is
|
// ESP8266 chip. This is a special purpose image format just for the ESP chip
|
||||||
// parsed by the on-chip mask ROM bootloader.
|
// family, and is parsed by the on-chip mask ROM bootloader.
|
||||||
//
|
//
|
||||||
// The following documentation has been used:
|
// The following documentation has been used:
|
||||||
// https://github.com/espressif/esptool/wiki/Firmware-Image-Format
|
// 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/esp-idf/blob/8fbb63c2a701c22ccf4ce249f43aded73e134a34/components/bootloader_support/include/esp_image_format.h#L58
|
||||||
// https://github.com/espressif/esptool/blob/master/esptool.py
|
// 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)
|
inf, err := elf.Open(infile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -79,26 +79,49 @@ func makeESP32FirmareImage(infile, outfile string) error {
|
||||||
outf := &bytes.Buffer{}
|
outf := &bytes.Buffer{}
|
||||||
|
|
||||||
// Image header.
|
// Image header.
|
||||||
// Details: https://github.com/espressif/esp-idf/blob/8fbb63c2/components/bootloader_support/include/esp_image_format.h#L58
|
switch format {
|
||||||
binary.Write(outf, binary.LittleEndian, struct {
|
case "esp32":
|
||||||
magic uint8
|
// Header format:
|
||||||
segment_count uint8
|
// https://github.com/espressif/esp-idf/blob/8fbb63c2/components/bootloader_support/include/esp_image_format.h#L58
|
||||||
spi_mode uint8
|
binary.Write(outf, binary.LittleEndian, struct {
|
||||||
spi_speed_size uint8
|
magic uint8
|
||||||
entry_addr uint32
|
segment_count uint8
|
||||||
wp_pin uint8
|
spi_mode uint8
|
||||||
spi_pin_drv [3]uint8
|
spi_speed_size uint8
|
||||||
reserved [11]uint8
|
entry_addr uint32
|
||||||
hash_appended bool
|
wp_pin uint8
|
||||||
}{
|
spi_pin_drv [3]uint8
|
||||||
magic: 0xE9,
|
reserved [11]uint8
|
||||||
segment_count: byte(len(segments)),
|
hash_appended bool
|
||||||
spi_mode: 0, // irrelevant, replaced by esptool when flashing
|
}{
|
||||||
spi_speed_size: 0, // spi_speed, spi_size: replaced by esptool when flashing
|
magic: 0xE9,
|
||||||
entry_addr: uint32(inf.Entry),
|
segment_count: byte(len(segments)),
|
||||||
wp_pin: 0xEE, // disable WP pin
|
spi_mode: 0, // irrelevant, replaced by esptool when flashing
|
||||||
hash_appended: true, // add a SHA256 hash
|
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.
|
// Write all segments to the image.
|
||||||
// https://github.com/espressif/esptool/wiki/Firmware-Image-Format#segment
|
// 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.Write(make([]byte, 15-outf.Len()%16))
|
||||||
outf.WriteByte(checksum)
|
outf.WriteByte(checksum)
|
||||||
|
|
||||||
// SHA256 hash (to protect against image corruption, not for security).
|
if format == "esp32" {
|
||||||
hash := sha256.Sum256(outf.Bytes())
|
// SHA256 hash (to protect against image corruption, not for security).
|
||||||
outf.Write(hash[:])
|
hash := sha256.Sum256(outf.Bytes())
|
||||||
|
outf.Write(hash[:])
|
||||||
|
}
|
||||||
|
|
||||||
// Write the image to the output file.
|
// Write the image to the output file.
|
||||||
return ioutil.WriteFile(outfile, outf.Bytes(), 0666)
|
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"]
|
||||||
|
}
|
Загрузка…
Создание таблицы
Сослаться в новой задаче