Rework ADC mode setting approach (#1285)

- Stop fighting against the SDK in terms of owning/writing the init_data block.
  NodeMCU included a default init_data block because originally the SDK did
  not, but by now it's not needed.

- Expose a way to reconfigure the ADC mode from Lua land. With most people
  using the cloud builder and not able to change the #define for byte 107
  this has been a pain point.

- Less confusion about which init_data has been used. Lua code can now simply
  state what mode it wants the ADC to be in, and not worry about the rest of
  the init_data complexities such as the init_data changing location due to
  flashing with wrong flash_size setting, or doing/not doing a chip-erase
  before loading new NodeMCU firmware.
This commit is contained in:
Johny Mattsson 2016-05-19 05:45:15 +10:00 committed by Marcel Stör
parent 9c9237ef5a
commit 30d354c290
8 changed files with 80 additions and 136 deletions

View File

@ -12,12 +12,6 @@
#define FLASH_AUTOSIZE
#define FLASH_SAFE_API
// Byte 107 of esp_init_data_default, only one of these 3 can be picked
#define ESP_INIT_DATA_ENABLE_READVDD33
//#define ESP_INIT_DATA_ENABLE_READADC
//#define ESP_INIT_DATA_FIXED_VDD33_VALUE 33
//
// This adds the asserts in LUA. It also adds some useful extras to the
// node module. This is all silent in normal operation and so can be enabled
// without any harm (except for the code size increase and slight slowdown)

View File

@ -24,10 +24,49 @@ static int adc_readvdd33( lua_State* L )
return 1;
}
// Lua: adc.force_init_mode(x)
static int adc_init107( lua_State *L )
{
uint8_t byte107 = luaL_checkinteger (L, 1);
uint32 init_sector = flash_safe_get_sec_num () - 4;
// Note 32bit alignment so we can safely cast to uint32 for the flash api
char init_data[SPI_FLASH_SEC_SIZE] __attribute__((aligned(4)));
if (SPI_FLASH_RESULT_OK != flash_safe_read (
init_sector * SPI_FLASH_SEC_SIZE,
(uint32 *)init_data, sizeof(init_data)))
return luaL_error(L, "flash read error");
// If it's already the correct value, we don't need to force it
if (init_data[107] == byte107)
{
lua_pushboolean (L, false);
return 1;
}
// Nope, it differs, we need to rewrite it
init_data[107] = byte107;
if (SPI_FLASH_RESULT_OK != flash_safe_erase_sector (init_sector))
return luaL_error(L, "flash erase error");
if (SPI_FLASH_RESULT_OK != flash_safe_write (
init_sector * SPI_FLASH_SEC_SIZE,
(uint32 *)init_data, sizeof(init_data)))
return luaL_error(L, "flash write error");
lua_pushboolean (L, true);
return 1;
}
// Module function map
static const LUA_REG_TYPE adc_map[] = {
{ LSTRKEY( "read" ), LFUNCVAL( adc_sample ) },
{ LSTRKEY( "readvdd33" ), LFUNCVAL( adc_readvdd33 ) },
{ LSTRKEY( "force_init_mode" ), LFUNCVAL( adc_init107 ) },
{ LSTRKEY( "INIT_ADC" ), LNUMVAL( 0x00 ) },
{ LSTRKEY( "INIT_VDD33" ),LNUMVAL( 0xff ) },
{ LNILKEY, LNILVAL }
};

View File

@ -521,8 +521,6 @@ static int node_bootreason (lua_State *L)
// Lua: restore()
static int node_restore (lua_State *L)
{
flash_init_data_default();
flash_init_data_blank();
system_restore();
return 0;
}

View File

@ -8,28 +8,6 @@
#include "spi_flash.h"
#include "c_stdio.h"
#if defined(ESP_INIT_DATA_ENABLE_READVDD33)
# define INIT_107 0xff
#elif defined(ESP_INIT_DATA_ENABLE_READADC)
# define INIT_107 0x00
#elif defined(ESP_INIT_DATA_FIXED_VDD33_VALUE)
# define INIT_107 ESP_INIT_DATA_FIXED_VDD33_VALUE
#else
# define INIT_107 0xff
#endif
static const uint8_t flash_init_data[128] =
{
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, INIT_107, 0x00, 0x00, 0x00, 0x00,
0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
uint32_t flash_detect_size_byte(void)
{
#define FLASH_BUFFER_SIZE_DETECT 32
@ -323,59 +301,6 @@ bool flash_rom_set_speed(uint32_t speed)
return true;
}
bool flash_init_data_default(void)
{
/* Can't copy directly from flash (which is where the default data lives)
* due to it being unmapped during the write, so bounce via ram buffer. */
uint8_t init_data[128];
os_memcpy (init_data, flash_init_data, 128);
// FLASH SEC - 4
// Dangerous, here are dinosaur infested!!!!!
// Reboot required!!!
// It will init system data to default!
bool result = false;
#if defined(FLASH_SAFE_API)
if (SPI_FLASH_RESULT_OK == flash_safe_erase_sector((flash_safe_get_sec_num() - 4)))
{
if (SPI_FLASH_RESULT_OK == flash_safe_write((flash_safe_get_sec_num() - 4) * SPI_FLASH_SEC_SIZE, (uint32 *)init_data, 128))
{
result = true;
}
}
#else
if (SPI_FLASH_RESULT_OK == spi_flash_erase_sector((flash_rom_get_sec_num() - 4)))
{
if (SPI_FLASH_RESULT_OK == spi_flash_write((flash_rom_get_sec_num() - 4) * SPI_FLASH_SEC_SIZE, (uint32 *)init_data, 128))
{
result = true;
}
}
#endif // defined(FLASH_SAFE_API)
return result;
}
bool flash_init_data_blank(void)
{
// FLASH SEC - 2
// Dangerous, here are dinosaur infested!!!!!
// Reboot required!!!
// It will init system config to blank!
bool result = false;
#if defined(FLASH_SAFE_API)
if ((SPI_FLASH_RESULT_OK == flash_safe_erase_sector((flash_safe_get_sec_num() - 2))) &&
(SPI_FLASH_RESULT_OK == flash_safe_erase_sector((flash_safe_get_sec_num() - 1))))
#else
if ((SPI_FLASH_RESULT_OK == spi_flash_erase_sector((flash_rom_get_sec_num() - 2))) &&
(SPI_FLASH_RESULT_OK == spi_flash_erase_sector((flash_rom_get_sec_num() - 1))))
#endif // defined(FLASH_SAFE_API)
{
result = true;
}
return result ;
}
uint8_t byte_of_aligned_array(const uint8_t *aligned_array, uint32_t index)
{
if ( (((uint32_t)aligned_array) % 4) != 0 )

View File

@ -100,9 +100,6 @@ bool flash_rom_set_size_byte(uint32_t);
uint16_t flash_rom_get_sec_num(void);
uint8_t flash_rom_get_mode(void);
uint32_t flash_rom_get_speed(void);
bool flash_init_data_written(void);
bool flash_init_data_default(void);
bool flash_init_data_blank(void);
uint8_t byte_of_aligned_array(const uint8_t* aligned_array, uint32_t index);
uint16_t word_of_aligned_array(const uint16_t *aligned_array, uint32_t index);
// uint8_t flash_rom_get_checksum(void);

View File

@ -33,13 +33,6 @@
static os_event_t *taskQueue;
/* Important: no_init_data CAN NOT be left as zero initialised, as that
* initialisation will happen after user_start_trampoline, but before
* the user_init, thus clobbering our state!
*/
static uint8_t no_init_data = 0xff;
/* Note: the trampoline *must* be explicitly put into the .text segment, since
* by the time it is invoked the irom has not yet been mapped. This naturally
* also goes for anything the trampoline itself calls.
@ -55,29 +48,6 @@ void TEXT_SECTION_ATTR user_start_trampoline (void)
rtctime_early_startup ();
#endif
/* Minimal early detection of missing esp_init_data.
* If it is missing, the SDK will write its own and thus we'd end up
* using that unless the flash size field is incorrect. This then leads
* to different esp_init_data being used depending on whether the user
* flashed with the right flash size or not (and the better option would
* be to flash with an *incorrect* flash size, counter-intuitively).
* To avoid that mess, we read out the flash size and do a test for
* esp_init_data based on that size. If it's missing, flag for later.
* If the flash size was incorrect, we'll end up fixing it all up
* anyway, so this ends up solving the conundrum. Only remaining issue
* is lack of spare code bytes in iram, so this is deliberately quite
* terse and not as readable as one might like.
*/
SPIFlashInfo sfi;
SPIRead (0, (uint32_t *)(&sfi), sizeof (sfi)); // Cache read not enabled yet, safe to use
if (sfi.size < 2) // Compensate for out-of-order 4mbit vs 2mbit values
sfi.size ^= 1;
uint32_t flash_end_addr = (256 * 1024) << sfi.size;
uint32_t init_data_hdr = 0xffffffff;
SPIRead (flash_end_addr - 4 * SPI_FLASH_SEC_SIZE, &init_data_hdr, sizeof (init_data_hdr));
no_init_data = (init_data_hdr == 0xffffffff);
call_user_start ();
}
@ -119,8 +89,6 @@ void nodemcu_init(void)
NODE_ERR("Self adjust flash size.\n");
// Fit hardware real flash size.
flash_rom_set_size_byte(flash_safe_get_size_byte());
// Write out init data at real location.
no_init_data = true;
if( !fs_format() )
{
@ -131,20 +99,15 @@ void nodemcu_init(void)
NODE_ERR( "format done.\n" );
}
fs_unmount(); // mounted by format.
// Reboot to get SDK to use (or write) init data at new location
system_restart ();
// Don't post the start_lua task, we're about to reboot...
return;
}
#endif // defined(FLASH_SAFE_API)
if (no_init_data)
{
NODE_ERR("Restore init data.\n");
// Flash init data at FLASHSIZE - 0x04000 Byte.
flash_init_data_default();
// Flash blank data at FLASHSIZE - 0x02000 Byte.
flash_init_data_blank();
// Reboot to make the new data come into effect
system_restart ();
}
#if defined ( BUILD_SPIFFS )
fs_mount();
// test_spiffs();

View File

@ -1,13 +1,41 @@
# ADC Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2014-12-24 | [Zeroday](https://github.com/funshine) | [Zeroday](https://github.com/funshine) | [adc.c](../../../app/modules/adc.c)|
| 2014-12-24 | [Zeroday](https://github.com/funshine) | [jmattsson](https://github.com/jmattsson) | [adc.c](../../../app/modules/adc.c)|
The ADC module provides access to the in-built ADC.
On the ESP8266 there is only a single-channel, which is multiplexed with the battery voltage. Depending on the setting in the "esp init data" (byte 107) one can either use the ADC to read an external voltage, or to read the system voltage, but not both.
On the ESP8266 there is only a single-channel, which is multiplexed with the battery voltage. Depending on the setting in the "esp init data" (byte 107) one can either use the ADC to read an external voltage, or to read the system voltage (vdd33), but not both.
The default setting in the NodeMCU firmware can be controlled via user_config.h at compile time, by defining one of ESP_INIT_DATA_ENABLE_READVDD33, ESP_INIT_DATA_ENABLE_READADC or ESP_INIT_DATA_FIXED_VDD33_VALUE. To change the setting at a later date, use Espressif's flash download tool to create a new init data block.
Which mode to use the ADC in can be configured via the `adc.force_init_mode()` function. Note that after switching from one to the other a system restart is required before the change takes effect.
## adc.force_init_mode()
Checks and if necessary reconfigures the ADC mode setting in the ESP init data block.
####Syntax
`adc.force_init_mode(mode_value)`
####Parameters
`mode_value` One of `adc.INIT_ADC` or `adc.INIT_VDD33`.
####Returns
True if the function had to change the mode, false if the mode was already configured. On a true return the ESP needs to be restarted for the change to take effect.
####Example
```lua
-- in you init.lua:
if adc.force_init_mode(adc.INIT_VDD33)
then
node.restart()
return -- don't bother continuing, the restart is scheduled
end
print("System voltage (mV):", adc.readvdd33(0))
```
####See also
[`node.restart()`](node.md#noderestart)
## adc.read()
@ -22,6 +50,8 @@ Samples the ADC.
####Returns
the sampled value (number)
If the ESP8266 has been configured to use the ADC for reading the system voltage, this function will always return 65535. This is a hardware and/or SDK limitation.
####Example
```lua
val = adc.read(0)

View File

@ -315,9 +315,7 @@ none
## node.restore()
Restores system configuration to defaults. Erases all stored WiFi settings, and resets the "esp init data" to the defaults. This function is intended as a last-resort without having to reflash the ESP altogether.
This also uses the SDK function `system_restore()`, which doesn't document precisely what it erases/restores.
Restores system configuration to defaults using the SDK function `system_restore()`, which doesn't document precisely what it erases/restores.
#### Syntax
`node.restore()`