esp-open-rtos/core/app_main.c
Angus Gratton 7526a1fd0c app_main: Refactor to use uart.h functions instead of raw register access
This removes the automatic insertion of CR ahead of LF by the SDK putc
function when called inside the SDK (although we'd already replaced
printf, so most were bypassing this putc function anyhow.)
2015-10-06 18:14:05 +11:00

495 lines
15 KiB
C

/* 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 "os_version.h"
#include "espressif/esp_common.h"
#include "sdk_internal.h"
/* This is not declared in any header file (but arguably should be) */
void user_init(void);
#define BOOT_INFO_SIZE 28
//TODO: phy_info should probably be a struct (no idea about its organization, though)
#define PHY_INFO_SIZE 128
// 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
#define halt() while (1) {}
extern uint32_t _bss_start;
extern uint32_t _bss_end;
// .Ldata003 -- .irom.text+0x0
static const uint8_t IROM default_phy_info[PHY_INFO_SIZE] = {
0x05, 0x00, 0x04, 0x02, 0x05, 0x05, 0x05, 0x02,
0x05, 0x00, 0x04, 0x05, 0x05, 0x04, 0x05, 0x05,
0x04, 0xfe, 0xfd, 0xff, 0xf0, 0xf0, 0xf0, 0xe0,
0xe0, 0xe0, 0xe1, 0x0a, 0xff, 0xff, 0xf8, 0x00,
0xf8, 0xf8, 0x52, 0x4e, 0x4a, 0x44, 0x40, 0x38,
0x00, 0x00, 0x01, 0x01, 0x02, 0x03, 0x04, 0x05,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xe1, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x93, 0x43, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
// user_init_flag -- .bss+0x0
uint8_t sdk_user_init_flag;
// info -- .bss+0x4
struct sdk_info_st sdk_info;
// xUserTaskHandle -- .bss+0x28
xTaskHandle sdk_xUserTaskHandle;
// xWatchDogTaskHandle -- .bss+0x2c
xTaskHandle 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(uint8_t *phy_info, uint8_t *mac_addr);
static void init_g_ic(void);
static void dump_excinfo(void);
static void user_start_phase2(void);
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");
halt();
}
if (otp_id0 == 0 && otp_id1 == 0) {
printf("empty otp\n");
halt();
}
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);
}
// .text+0x148
void IRAM sdk_user_fatal_exception_handler(void) {
if (!sdk_NMIIrqIsOn) {
vPortEnterCritical();
do {
DPORT.DPORT0 &= 0xffffffe0;
} while (DPORT.DPORT0 & 0x00000001);
}
Cache_Read_Disable();
Cache_Read_Enable(0, 0, 1);
dump_excinfo();
uart_flush_txfifo(0);
uart_flush_txfifo(1);
sdk_system_restart_in_nmi();
halt();
}
static void IRAM default_putc(char c) {
uart_putc(0, c);
}
// .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;
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);
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));
user_start_phase2();
}
// .text+0x3a8
void IRAM vApplicationStackOverflowHook(xTaskHandle task, char *task_name) {
printf("\"%s\"(stack_size = %lu) overflow the heap_size.\n", task_name, uxTaskGetStackHighWaterMark(task));
}
// .text+0x3d8
void IRAM vApplicationIdleHook(void) {
printf("idle %u\n", WDEV.SYS_TIME);
}
// .text+0x404
void IRAM vApplicationTickHook(void) {
printf("tick %u\n", WDEV.SYS_TIME);
}
// .Lfunc005 -- .irom0.text+0x8
static void zero_bss(void) {
uint32_t *addr;
for (addr = &_bss_start; addr < &_bss_end; addr++) {
*addr = 0;
}
}
// .Lfunc006 -- .irom0.text+0x70
static void init_networking(uint8_t *phy_info, uint8_t *mac_addr) {
if (sdk_register_chipv6_phy(phy_info)) {
printf("FATAL: sdk_register_chipv6_phy failed");
halt();
}
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();
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();
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;
}
if (sdk_g_ic.s._unknown1e4._unknown1e4 == 0xffffffff) {
bzero(&sdk_g_ic.s._unknown1e4, sizeof(sdk_g_ic.s._unknown1e4));
bzero(&sdk_g_ic.s._unknown20f, sizeof(sdk_g_ic.s._unknown20f));
}
sdk_g_ic.s.wifi_led_enable = 0;
if (sdk_g_ic.s._unknown281 > 1) {
sdk_g_ic.s._unknown281 = 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;
}
}
// .Lfunc008 -- .irom0.text+0x2a0
static void dump_excinfo(void) {
uint32_t exccause, epc1, epc2, epc3, excvaddr, depc, excsave1;
uint32_t excinfo[8];
RSR(exccause, exccause);
printf("Fatal exception (%d): \n", (int)exccause);
RSR(epc1, epc1);
RSR(epc2, epc2);
RSR(epc3, epc3);
RSR(excvaddr, excvaddr);
RSR(depc, depc);
RSR(excsave1, excsave1);
printf("%s=0x%08x\n", "epc1", epc1);
printf("%s=0x%08x\n", "epc2", epc2);
printf("%s=0x%08x\n", "epc3", epc3);
printf("%s=0x%08x\n", "excvaddr", excvaddr);
printf("%s=0x%08x\n", "depc", depc);
printf("%s=0x%08x\n", "excsave1", excsave1);
sdk_system_rtc_mem_read(0, excinfo, 32); // Why?
excinfo[0] = 2;
excinfo[1] = exccause;
excinfo[2] = epc1;
excinfo[3] = epc2;
excinfo[4] = epc3;
excinfo[5] = excvaddr;
excinfo[6] = depc;
excinfo[7] = excsave1;
sdk_system_rtc_mem_write(0, excinfo, 32);
}
// .irom0.text+0x368
int sdk_uart_rx_one_char(char *buf) {
/* This functions returns 1 instead of -1 on error,
but is otherwise the same. Unsure if anyone checks the
result for a specific value though.
*/
return uart_getc_nowait(0) ? 1 : 0;
}
// .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();
}
// .irom0.text+0x474
void sdk_user_init_task(void *params) {
int phy_ver, pp_ver;
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);
}
// .Lfunc009 -- .irom0.text+0x5b4
static void user_start_phase2(void) {
uint8_t *buf;
uint8_t *phy_info;
sdk_system_rtc_mem_read(0, &sdk_rst_if, sizeof(sdk_rst_if));
if (sdk_rst_if.version > 3) {
// Bad version number. 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._unknown0 = 0x0104a8c0;
sdk_info._unknown1 = 0x00ffffff;
sdk_info._unknown2 = 0x0104a8c0;
init_g_ic();
phy_info = malloc(PHY_INFO_SIZE);
sdk_spi_flash_read(sdk_flashchip.chip_size - sdk_flashchip.sector_size * 4, (uint32_t *)phy_info, PHY_INFO_SIZE);
// Wait for UARTs to finish sending anything in their queues.
uart_flush_txfifo(0);
uart_flush_txfifo(1);
if (phy_info[0] != 5) {
// Bad version byte. Discard what we read and use default values
// instead.
memcpy(phy_info, default_phy_info, PHY_INFO_SIZE);
}
init_networking(phy_info, sdk_info.sta_mac_addr);
free(phy_info);
tcpip_init(NULL, NULL);
sdk_wdt_init();
xTaskCreate(sdk_user_init_task, (signed char *)"uiT", 1024, 0, 14, &sdk_xUserTaskHandle);
vTaskStartScheduler();
}
// .Lfunc010 -- .irom0.text+0x710
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);
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);
}
printf(" %02x", buf[i]);
}
printf("\n");
free(buf);
}
// .Lfunc011 -- .irom0.text+0x790
static void dump_flash_config_sectors(uint32_t start_sector) {
printf("system param error\n");
// Note: original SDK code didn't dump PHY info
printf("phy_info:\n");
dump_flash_sector(start_sector, PHY_INFO_SIZE);
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);
}