esp-open-rtos/core/app_main.c

490 lines
16 KiB
C
Raw Normal View History

/* Implementation of libmain/app_main.o from the Espressif SDK.
*
* This contains most of the startup code for the SDK/OS, some event handlers,
* etc.
*
* Part of esp-open-rtos
* Copyright (C) 2015 Superhouse Automation Pty Ltd
* BSD Licensed as described in the file LICENSE
*/
#include <string.h>
#include <FreeRTOS.h>
#include <task.h>
#include <lwip/tcpip.h>
#include "common_macros.h"
#include "xtensa_ops.h"
#include "esp/rom.h"
#include "esp/uart.h"
#include "esp/iomux_regs.h"
#include "esp/spi_regs.h"
#include "esp/dport_regs.h"
#include "esp/wdev_regs.h"
#include "esp/wdt_regs.h"
#include "esp/rtcmem_regs.h"
#include "esp/hwrand.h"
#include "os_version.h"
#include "espressif/esp_common.h"
#include "espressif/phy_info.h"
#include "esplibs/libmain.h"
#include "esplibs/libnet80211.h"
#include "esplibs/libphy.h"
#include "esplibs/libpp.h"
#include "sysparam.h"
/* This is not declared in any header file (but arguably should be) */
void user_init(void);
#define BOOT_INFO_SIZE 28
// These are the offsets of these values within the RTCMEM regions. It appears
// that the ROM saves them to RTCMEM before calling us, and we pull them out of
// there to display them in startup messages (not sure why it works that way).
#define RTCMEM_BACKUP_PHY_VER 31
#define RTCMEM_SYSTEM_PP_VER 62
2015-08-26 00:22:38 +00:00
extern uint32_t _bss_start;
extern uint32_t _bss_end;
// user_init_flag -- .bss+0x0
uint8_t sdk_user_init_flag;
// info -- .bss+0x4
struct sdk_info_st sdk_info;
// xUserTaskHandle -- .bss+0x28
2016-11-05 10:04:03 +00:00
TaskHandle_t sdk_xUserTaskHandle;
// xWatchDogTaskHandle -- .bss+0x2c
2016-11-05 10:04:03 +00:00
TaskHandle_t sdk_xWatchDogTaskHandle;
/* Static function prototypes */
static void IRAM get_otp_mac_address(uint8_t *buf);
static void IRAM set_spi0_divisor(uint32_t divisor);
static void zero_bss(void);
static void init_networking(sdk_phy_info_t *phy_info, uint8_t *mac_addr);
static void init_g_ic(void);
static void user_start_phase2(void);
2015-08-30 19:11:08 +00:00
static void dump_flash_sector(uint32_t start_sector, uint32_t length);
static void dump_flash_config_sectors(uint32_t start_sector);
// .Lfunc001 -- .text+0x14
static void IRAM get_otp_mac_address(uint8_t *buf) {
uint32_t otp_flags;
uint32_t otp_id0, otp_id1;
uint32_t otp_vendor_id;
otp_flags = DPORT.OTP_CHIPID;
otp_id1 = DPORT.OTP_MAC1;
otp_id0 = DPORT.OTP_MAC0;
if (!(otp_flags & 0x8000)) {
//FIXME: do we really need this check?
printf("Firmware ONLY supports ESP8266!!!\n");
abort();
}
if (otp_id0 == 0 && otp_id1 == 0) {
printf("empty otp\n");
abort();
}
if (otp_flags & 0x1000) {
// If bit 12 is set, it indicates that the vendor portion of the MAC
// address is stored in DPORT.OTP_MAC2.
otp_vendor_id = DPORT.OTP_MAC2;
buf[0] = otp_vendor_id >> 16;
buf[1] = otp_vendor_id >> 8;
buf[2] = otp_vendor_id;
} else {
// If bit 12 is clear, there's no MAC vendor in DPORT.OTP_MAC2, so
// default to the Espressif MAC vendor prefix instead.
buf[1] = 0xfe;
buf[0] = 0x18;
buf[2] = 0x34;
}
buf[3] = otp_id1 >> 8;
buf[4] = otp_id1;
buf[5] = otp_id0 >> 24;
}
// .Lfunc002 -- .text+0xa0
static void IRAM set_spi0_divisor(uint32_t divisor) {
int cycle_len, half_cycle_len, clkdiv;
if (divisor < 2) {
clkdiv = 0;
SPI(0).CTRL0 |= SPI_CTRL0_CLOCK_EQU_SYS_CLOCK;
IOMUX.CONF |= IOMUX_CONF_SPI0_CLOCK_EQU_SYS_CLOCK;
} else {
cycle_len = divisor - 1;
half_cycle_len = (divisor / 2) - 1;
clkdiv = VAL2FIELD(SPI_CTRL0_CLOCK_NUM, cycle_len)
| VAL2FIELD(SPI_CTRL0_CLOCK_HIGH, half_cycle_len)
| VAL2FIELD(SPI_CTRL0_CLOCK_LOW, cycle_len);
SPI(0).CTRL0 &= ~SPI_CTRL0_CLOCK_EQU_SYS_CLOCK;
IOMUX.CONF &= ~IOMUX_CONF_SPI0_CLOCK_EQU_SYS_CLOCK;
}
SPI(0).CTRL0 = SET_FIELD(SPI(0).CTRL0, SPI_CTRL0_CLOCK, clkdiv);
}
static void IRAM default_putc(char c) {
uart_putc(0, c);
}
void init_newlib_locks(void);
extern uint8_t sdk_wDevCtrl[];
void nano_malloc_insert_chunk(void *start, size_t size);
// .text+0x258
void IRAM sdk_user_start(void) {
uint32_t buf32[sizeof(struct sdk_g_ic_saved_st) / 4];
uint8_t *buf8 = (uint8_t *)buf32;
uint32_t flash_speed_divisor;
uint32_t flash_sectors;
uint32_t flash_size;
int boot_slot;
uint32_t cksum_magic;
uint32_t cksum_len;
uint32_t cksum_value;
uint32_t ic_flash_addr;
uint32_t sysparam_addr;
sysparam_status_t status;
SPI(0).USER0 |= SPI_USER0_CS_SETUP;
sdk_SPIRead(0, buf32, 4);
switch (buf8[3] & 0x0f) {
case 0xf: // 80 MHz
flash_speed_divisor = 1;
break;
case 0x0: // 40 MHz
flash_speed_divisor = 2;
break;
case 0x1: // 26 MHz
flash_speed_divisor = 3;
break;
case 0x2: // 20 MHz
flash_speed_divisor = 4;
break;
default: // Invalid -- Assume 40 MHz
flash_speed_divisor = 2;
}
switch (buf8[3] >> 4) {
case 0x0: // 4 Mbit (512 KByte)
flash_sectors = 128;
break;
case 0x1: // 2 Mbit (256 Kbyte)
flash_sectors = 64;
break;
case 0x2: // 8 Mbit (1 Mbyte)
flash_sectors = 256;
break;
case 0x3: // 16 Mbit (2 Mbyte)
flash_sectors = 512;
break;
case 0x4: // 32 Mbit (4 Mbyte)
flash_sectors = 1024;
break;
default: // Invalid -- Assume 4 Mbit (512 KByte)
flash_sectors = 128;
}
//FIXME: we should probably calculate flash_sectors by starting with flash_size and dividing by sdk_flashchip.sector_size instead of vice-versa.
flash_size = flash_sectors * 4096;
sdk_flashchip.chip_size = flash_size;
set_spi0_divisor(flash_speed_divisor);
sdk_SPIRead(flash_size - 4096, buf32, BOOT_INFO_SIZE);
boot_slot = buf8[0] ? 1 : 0;
cksum_magic = buf32[1];
cksum_len = buf32[3 + boot_slot];
cksum_value = buf32[5 + boot_slot];
ic_flash_addr = (flash_sectors - 3 + boot_slot) * sdk_flashchip.sector_size;
sdk_SPIRead(ic_flash_addr, buf32, sizeof(struct sdk_g_ic_saved_st));
Cache_Read_Enable(0, 0, 1);
zero_bss();
sdk_os_install_putc1(default_putc);
/* HACK Reclaim a region of unused bss from wdev.o. This would not be
* necessary if the source code to wdev were available, and then it would
* not be a fragmented area, but the extra memory is desparately needed and
* it is in very useful dram. */
nano_malloc_insert_chunk((void *)(sdk_wDevCtrl + 0x2190), 8000);
init_newlib_locks();
if (cksum_magic == 0xffffffff) {
// No checksum required
} else if ((cksum_magic == 0x55aa55aa) &&
(sdk_system_get_checksum(buf8, cksum_len) == cksum_value)) {
// Checksum OK
} else {
// Bad checksum or bad cksum_magic value
dump_flash_config_sectors(flash_sectors - 4);
//FIXME: should we halt here? (original SDK code doesn't)
}
memcpy(&sdk_g_ic.s, buf32, sizeof(struct sdk_g_ic_saved_st));
// By default, put the sysparam region just below the config sectors at the
// top of the flash space, and allowing one extra sector spare.
sysparam_addr = flash_size - (5 + DEFAULT_SYSPARAM_SECTORS) * sdk_flashchip.sector_size;
status = sysparam_init(sysparam_addr, flash_size);
if (status == SYSPARAM_NOTFOUND) {
status = sysparam_create_area(sysparam_addr, DEFAULT_SYSPARAM_SECTORS, false);
if (status == SYSPARAM_OK) {
status = sysparam_init(sysparam_addr, 0);
}
}
if (status != SYSPARAM_OK) {
printf("WARNING: Could not initialize sysparams (%d)!\n", status);
}
user_start_phase2();
}
// .text+0x3a8
2016-11-05 10:04:03 +00:00
void IRAM vApplicationStackOverflowHook(TaskHandle_t task, char *task_name) {
printf("Task stack overflow (high water mark=%lu name=\"%s\")\n", uxTaskGetStackHighWaterMark(task), task_name);
}
// .text+0x3d8
2017-03-20 19:56:17 +00:00
void __attribute__((weak)) IRAM vApplicationIdleHook(void) {
2015-09-20 21:09:30 +00:00
printf("idle %u\n", WDEV.SYS_TIME);
}
// .text+0x404
2017-03-20 19:56:17 +00:00
void __attribute__((weak)) IRAM vApplicationTickHook(void) {
2015-09-20 21:09:30 +00:00
printf("tick %u\n", WDEV.SYS_TIME);
}
// .Lfunc005 -- .irom0.text+0x8
static void zero_bss(void) {
uint32_t *addr;
2015-08-26 00:22:38 +00:00
for (addr = &_bss_start; addr < &_bss_end; addr++) {
*addr = 0;
}
}
// .Lfunc006 -- .irom0.text+0x70
static void init_networking(sdk_phy_info_t *phy_info, uint8_t *mac_addr) {
// The call to sdk_register_chipv6_phy appears to change the bus clock,
// perhaps from 40MHz to 26MHz, at least it has such an effect on the uart
// baud rate. The caller flushes the TX fifos.
if (sdk_register_chipv6_phy(phy_info)) {
printf("FATAL: sdk_register_chipv6_phy failed");
abort();
}
// The boot rom initializes uart0 for a 115200 baud rate but the bus clock
// does not appear to be as expected so the initial baud rate is actually
// 74906. On a cold boot, to keep the 74906 baud rate the uart0 divisor
// would need to changed here to 74906. On a warm boot the bus clock is
// expected to have already been set so the boot baud rate is 115200.
// Reset the rate here and settle on a 115200 baud rate.
if (sdk_rst_if.reason > 0) {
uart_set_baud(0, 115200);
uart_set_baud(1, 115200);
}
sdk_phy_disable_agc();
sdk_ieee80211_phy_init(sdk_g_ic.s.phy_mode);
sdk_lmacInit();
sdk_wDev_Initialize();
sdk_pp_attach();
2015-08-26 00:22:38 +00:00
sdk_ieee80211_ifattach(&sdk_g_ic, mac_addr);
_xt_isr_mask(1);
DPORT.DPORT0 = SET_FIELD(DPORT.DPORT0, DPORT_DPORT0_FIELD0, 1);
sdk_pm_attach();
sdk_phy_enable_agc();
2015-08-26 00:22:38 +00:00
sdk_cnx_attach(&sdk_g_ic);
sdk_wDevEnableRx();
}
// .Lfunc007 -- .irom0.text+0x148
static void init_g_ic(void) {
if (sdk_g_ic.s.wifi_mode == 0xff) {
sdk_g_ic.s.wifi_mode = 2;
}
sdk_wifi_softap_set_default_ssid();
if (sdk_g_ic.s._unknown30d < 1 || sdk_g_ic.s._unknown30d > 14) {
sdk_g_ic.s._unknown30d = 1;
}
if (sdk_g_ic.s._unknown544 < 100 || sdk_g_ic.s._unknown544 > 60000) {
sdk_g_ic.s._unknown544 = 100;
}
if (sdk_g_ic.s._unknown30e == 1 || sdk_g_ic.s._unknown30e > 4) {
sdk_g_ic.s._unknown30e = 0;
}
bzero(sdk_g_ic.s._unknown2ac, sizeof(sdk_g_ic.s._unknown2ac));
if (sdk_g_ic.s._unknown30f > 1) {
sdk_g_ic.s._unknown30f = 0;
}
if (sdk_g_ic.s._unknown310 > 4) {
sdk_g_ic.s._unknown310 = 4;
}
2017-06-06 02:47:21 +00:00
if (sdk_g_ic.s.sta_ssid.ssid_length == 0xffffffff) {
bzero(&sdk_g_ic.s.sta_ssid, sizeof(sdk_g_ic.s.sta_ssid));
bzero(&sdk_g_ic.s.sta_password, sizeof(sdk_g_ic.s.sta_password));
}
sdk_g_ic.s.wifi_led_enable = 0;
if (sdk_g_ic.s.sta_bssid_set > 1) {
sdk_g_ic.s.sta_bssid_set = 0;
}
if (sdk_g_ic.s.ap_number > 5) {
sdk_g_ic.s.ap_number = 1;
}
if (sdk_g_ic.s.phy_mode < 1 || sdk_g_ic.s.phy_mode > 3) {
sdk_g_ic.s.phy_mode = PHY_MODE_11N;
}
}
// .irom0.text+0x398
void sdk_wdt_init(void) {
WDT.CTRL &= ~WDT_CTRL_ENABLE;
DPORT.INT_ENABLE |= DPORT_INT_ENABLE_WDT;
WDT.REG1 = 0x0000000b;
WDT.REG2 = 0x0000000c;
WDT.CTRL |= WDT_CTRL_FLAG3 | WDT_CTRL_FLAG4 | WDT_CTRL_FLAG5;
WDT.CTRL = SET_FIELD(WDT.CTRL, WDT_CTRL_FIELD0, 0);
WDT.CTRL |= WDT_CTRL_ENABLE;
sdk_pp_soft_wdt_init();
}
extern void *xPortSupervisorStackPointer;
// .irom0.text+0x474
void sdk_user_init_task(void *params) {
int phy_ver, pp_ver;
/* The start up stack is not used after scheduling has started, so all of
* the top area of RAM which was stack can be used for the dynamic heap. */
xPortSupervisorStackPointer = (void *)0x40000000;
sdk_ets_timer_init();
printf("\nESP-Open-SDK ver: %s compiled @ %s %s\n", OS_VERSION_STR, __DATE__, __TIME__);
phy_ver = RTCMEM_BACKUP[RTCMEM_BACKUP_PHY_VER] >> 16;
printf("phy ver: %d, ", phy_ver);
pp_ver = RTCMEM_SYSTEM[RTCMEM_SYSTEM_PP_VER];
printf("pp ver: %d.%d\n\n", (pp_ver >> 8) & 0xff, pp_ver & 0xff);
user_init();
sdk_user_init_flag = 1;
sdk_wifi_mode_set(sdk_g_ic.s.wifi_mode);
if (sdk_g_ic.s.wifi_mode == 1) {
sdk_wifi_station_start();
netif_set_default(sdk_g_ic.v.station_netif_info->netif);
}
if (sdk_g_ic.s.wifi_mode == 2) {
sdk_wifi_softap_start();
netif_set_default(sdk_g_ic.v.softap_netif_info->netif);
}
if (sdk_g_ic.s.wifi_mode == 3) {
sdk_wifi_station_start();
sdk_wifi_softap_start();
netif_set_default(sdk_g_ic.v.softap_netif_info->netif);
}
if (sdk_wifi_station_get_auto_connect()) {
sdk_wifi_station_connect();
}
vTaskDelete(NULL);
}
extern void (*__init_array_start)(void);
extern void (*__init_array_end)(void);
// .Lfunc009 -- .irom0.text+0x5b4
static __attribute__((noinline)) void user_start_phase2(void) {
uint8_t *buf;
sdk_phy_info_t phy_info, default_phy_info;
sdk_system_rtc_mem_read(0, &sdk_rst_if, sizeof(sdk_rst_if));
if (sdk_rst_if.reason > 3) {
// Bad reason. Probably garbage.
bzero(&sdk_rst_if, sizeof(sdk_rst_if));
}
buf = malloc(sizeof(sdk_rst_if));
bzero(buf, sizeof(sdk_rst_if));
sdk_system_rtc_mem_write(0, buf, sizeof(sdk_rst_if));
free(buf);
sdk_sleep_reset_analog_rtcreg_8266();
get_otp_mac_address(sdk_info.sta_mac_addr);
sdk_wifi_softap_cacl_mac(sdk_info.softap_mac_addr, sdk_info.sta_mac_addr);
sdk_info.softap_ipaddr.addr = 0x0104a8c0; // 192.168.4.1
sdk_info.softap_netmask.addr = 0x00ffffff; // 255.255.255.0
sdk_info.softap_gw.addr = 0x0104a8c0; // 192.168.4.1
init_g_ic();
read_saved_phy_info(&phy_info);
get_default_phy_info(&default_phy_info);
if (phy_info.version != default_phy_info.version) {
/* Versions don't match, use default for PHY info
(may be a blank config sector, or a new default version.)
*/
memcpy(&phy_info, &default_phy_info, sizeof(sdk_phy_info_t));
}
// Disable default buffering on stdout
setbuf(stdout, NULL);
// Wait for UARTs to finish sending anything in their queues.
uart_flush_txfifo(0);
uart_flush_txfifo(1);
init_networking(&phy_info, sdk_info.sta_mac_addr);
srand(hwrand()); /* seed libc rng */
// Set intial CPU clock speed to 160MHz if necessary
_Static_assert(configCPU_CLOCK_HZ == 80000000 || configCPU_CLOCK_HZ == 160000000, "FreeRTOSConfig must define initial clock speed as either 80MHz or 160MHz");
sdk_system_update_cpu_freq(configCPU_CLOCK_HZ / 1000000);
// Call gcc constructor functions
void (**ctor)(void);
for ( ctor = &__init_array_start; ctor != &__init_array_end; ++ctor) {
(*ctor)();
}
tcpip_init(NULL, NULL);
sdk_wdt_init();
2016-10-21 09:40:36 +00:00
xTaskCreate(sdk_user_init_task, "uiT", 1024, 0, 14, &sdk_xUserTaskHandle);
vTaskStartScheduler();
}
// .Lfunc010 -- .irom0.text+0x710
2015-08-30 19:11:08 +00:00
static void dump_flash_sector(uint32_t start_sector, uint32_t length) {
uint8_t *buf;
int bufsize, i;
bufsize = (length + 3) & 0xfffc;
buf = malloc(bufsize);
2015-08-30 19:11:08 +00:00
sdk_spi_flash_read(start_sector * sdk_flashchip.sector_size, (uint32_t *)buf
, bufsize);
for (i = 0; i < length; i++) {
if ((i & 0xf) == 0) {
if (i) {
printf("\n");
}
printf("%04x:", i);
}
2015-08-30 19:11:08 +00:00
printf(" %02x", buf[i]);
}
printf("\n");
free(buf);
}
// .Lfunc011 -- .irom0.text+0x790
static __attribute__((noinline)) void dump_flash_config_sectors(uint32_t start_sector) {
printf("system param error\n");
2015-08-30 19:11:08 +00:00
// Note: original SDK code didn't dump PHY info
printf("phy_info:\n");
dump_flash_sector(start_sector, sizeof(sdk_phy_info_t));
2015-08-30 19:11:08 +00:00
printf("\ng_ic saved 0:\n");
dump_flash_sector(start_sector + 1, sizeof(struct sdk_g_ic_saved_st));
printf("\ng_ic saved 1:\n");
dump_flash_sector(start_sector + 2, sizeof(struct sdk_g_ic_saved_st));
printf("\nboot info:\n");
dump_flash_sector(start_sector + 3, BOOT_INFO_SIZE);
}