From 39fe51924e65147b77fd32e466cfeb54a1d64d5d Mon Sep 17 00:00:00 2001 From: Liu Zhi Fu Date: Thu, 26 Jan 2017 15:33:23 +0800 Subject: [PATCH 001/112] esp32: update wifi lib to fix two datapath issues 1. fix ampdu<->mpdu<->ampdu switch may cause rx slow issue by put mpdu into ampdu reorder queue 2. fix each ac first sending always fail issue by adding retry --- components/esp32/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp32/lib b/components/esp32/lib index 6e50eb85a..45414a677 160000 --- a/components/esp32/lib +++ b/components/esp32/lib @@ -1 +1 @@ -Subproject commit 6e50eb85a07d12ded45d8765fc82bb7ab929e441 +Subproject commit 45414a6778e1bf2855f18a8c6b954d5cf575bb40 From 64e6e7a0ae306a29313426c87e5c2e091e5ee079 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 31 Jan 2017 12:38:43 +1100 Subject: [PATCH 002/112] mbedtls: Use two MPI multiplications when multiply operands too large Allows RSA4096 via hardware crypto operations. See github #139 https://github.com/espressif/esp-idf/issues/139 --- components/mbedtls/port/esp_bignum.c | 83 ++++++++- components/mbedtls/test/test_rsa.c | 240 +++++++++++++++++++++++++++ 2 files changed, 318 insertions(+), 5 deletions(-) create mode 100644 components/mbedtls/test/test_rsa.c diff --git a/components/mbedtls/port/esp_bignum.c b/components/mbedtls/port/esp_bignum.c index 5cce103ea..1dd7ea447 100644 --- a/components/mbedtls/port/esp_bignum.c +++ b/components/mbedtls/port/esp_bignum.c @@ -43,6 +43,9 @@ static const __attribute__((unused)) char *TAG = "bignum"; +#define ciL (sizeof(mbedtls_mpi_uint)) /* chars in limb */ +#define biL (ciL << 3) /* bits in limb */ + #if defined(CONFIG_MBEDTLS_MPI_USE_INTERRUPT) static SemaphoreHandle_t op_complete_sem; @@ -72,6 +75,7 @@ void esp_mpi_acquire_hardware( void ) { /* newlib locks lazy initialize on ESP-IDF */ _lock_acquire(&mpi_lock); + REG_SET_BIT(DPORT_PERI_CLK_EN_REG, DPORT_PERI_EN_RSA); /* also clear reset on digital signature, otherwise RSA is held in reset */ REG_CLR_BIT(DPORT_PERI_RST_EN_REG, @@ -82,6 +86,8 @@ void esp_mpi_acquire_hardware( void ) while(REG_READ(RSA_CLEAN_REG) != 1); + // Note: from enabling RSA clock to here takes about 1.3us + #ifdef CONFIG_MBEDTLS_MPI_USE_INTERRUPT rsa_isr_initialise(); #endif @@ -416,6 +422,7 @@ static int modular_multiply_finish(mbedtls_mpi *Z, const mbedtls_mpi *X, const m #if defined(MBEDTLS_MPI_MUL_MPI_ALT) /* MBEDTLS_MPI_MUL_MPI_ALT */ static int mpi_mult_mpi_failover_mod_mult(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t num_words); +static int mpi_mult_mpi_overlong(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t Y_bits, size_t words_result); /* Z = X * Y */ int mbedtls_mpi_mul_mpi( mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y ) @@ -468,12 +475,19 @@ int mbedtls_mpi_mul_mpi( mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi if (words_mult * 32 > 2048) { /* Calculate new length of Z */ words_z = bits_to_hardware_words(bits_x + bits_y); - if (words_z * 32 > 4096) { - ESP_LOGE(TAG, "ERROR: %d bit result %d bits * %d bits too large for hardware unit\n", words_z * 32, bits_x, bits_y); - return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; - } - else { + if (words_z * 32 <= 4096) { + /* Note: it's possible to use mpi_mult_mpi_overlong + for this case as well, but it's very slightly + slower and requires a memory allocation. + */ return mpi_mult_mpi_failover_mod_mult(Z, X, Y, words_z); + } else { + /* Still too long for the hardware unit... */ + if(bits_y > bits_x) { + return mpi_mult_mpi_overlong(Z, X, Y, bits_y, words_z); + } else { + return mpi_mult_mpi_overlong(Z, Y, X, bits_x, words_z); + } } } @@ -561,5 +575,64 @@ static int mpi_mult_mpi_failover_mod_mult(mbedtls_mpi *Z, const mbedtls_mpi *X, return ret; } +/* Deal with the case when X & Y are too long for the hardware unit, by splitting one operand + into two halves. + + Y must be the longer operand + + Slice Y into Yp, Ypp such that: + Yp = lower 'b' bits of Y + Ypp = upper 'b' bits of Y (right shifted) + + Such that + Z = X * Y + Z = X * (Yp + Ypp<p, + .n = limbs_slice, + .s = Y->s + }; + /* Ypp holds upper bits of Y, right shifted (also reuses Y's array contents) */ + const mbedtls_mpi Ypp = { + .p = Y->p + limbs_slice, + .n = limbs_y - limbs_slice, + .s = Y->s + }; + mbedtls_mpi_init(&Ztemp); + + /* Grow Z to result size early, avoid interim allocations */ + mbedtls_mpi_grow(Z, words_result); + + /* Get result Ztemp = Yp * X (need temporary variable Ztemp) */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi(&Ztemp, X, &Yp) ); + + /* Z = Ypp * Y */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi(Z, X, &Ypp) ); + + /* Z = Z << b */ + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l(Z, limbs_slice * biL) ); + + /* Z += Ztemp */ + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi(Z, Z, &Ztemp) ); + + cleanup: + mbedtls_mpi_free(&Ztemp); + + return ret; +} + #endif /* MBEDTLS_MPI_MUL_MPI_ALT */ diff --git a/components/mbedtls/test/test_rsa.c b/components/mbedtls/test/test_rsa.c new file mode 100644 index 000000000..df6d8f238 --- /dev/null +++ b/components/mbedtls/test/test_rsa.c @@ -0,0 +1,240 @@ +/* mbedTLS RSA functionality tests + + Focus on testing functionality where we use ESP32 hardware + accelerated crypto features. + +*/ +#include +#include +#include +#include +#include "mbedtls/rsa.h" +#include "mbedtls/pk.h" +#include "mbedtls/x509_crt.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "unity.h" +#include "sdkconfig.h" + +/* Taken from openssl s_client -connect api.gigafive.com:443 -showcerts + */ +static const char *rsa4096_cert = "-----BEGIN CERTIFICATE-----\n"\ + "MIIExzCCA6+gAwIBAgIBAzANBgkqhkiG9w0BAQsFADCBkjELMAkGA1UEBhMCVVMx\n"\ + "CzAJBgNVBAgMAkNBMRQwEgYDVQQHDAtTYW50YSBDbGFyYTElMCMGA1UECgwcR2ln\n"\ + "YWZpdmUgVGVjaG5vbG9neSBQYXJ0bmVyczEZMBcGA1UEAwwQR2lnYWZpdmUgUm9v\n"\ + "dCBDQTEeMBwGCSqGSIb3DQEJARYPY2FAZ2lnYWZpdmUuY29tMB4XDTE2MDgyNzE2\n"\ + "NDYyM1oXDTI2MDgyNTE2NDYyM1owgZcxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJD\n"\ + "QTEUMBIGA1UEBwwLU2FudGEgQ2xhcmExKTAnBgNVBAoMIEdpZ2FmaXZlIFRlY2hu\n"\ + "b2xvZ3kgUGFydG5lcnMgTExDMRkwFwYDVQQDDBBhcGkuZ2lnYWZpdmUuY29tMR8w\n"\ + "HQYJKoZIhvcNAQkBFhBjcmxAZ2lnYWZpdmUuY29tMIICIjANBgkqhkiG9w0BAQEF\n"\ + "AAOCAg8AMIICCgKCAgEAof82VrEpXMpsI/ddW6RLeTeSYtxiXZZkRbDKN6otYgEk\n"\ + "vA8yRbzei2cO2A/8+Erhe9beYLAMXWF+bjoUAFwnuIcbmufgHprOYzX/7CYXCsrH\n"\ + "LrJfVF6kvjCXy2W3xSvgh8ZgHNWnBGzl13tq19Fz8x0AhK5GQ9608oJCbnQjpVSI\n"\ + "lZDl3JVOifCeXf2c7nMhVOC/reTeto0Gbchs8Ox50WyojmfYbVjOQcA7f8p1eI+D\n"\ + "XUJK01cUGVu6/KarVArGHh5LsiyXOadbyeyOXPmjyrgarG3IIBeQSNECfJZPc/OW\n"\ + "lFszjU4YLDckI4x+tReiuFQbQPN5sDplcEldmZZm/8XD36ddvAaDds+SYlPXxDK7\n"\ + "7L8RBVUG2Ylc9YZf7RE6IMDmdQmsCZDX0VxySYEmzv5lnAx4mzzaXcgS+kHMOLyK\n"\ + "n9UxmpzwQoqqC9tMZqwRaeKW1njR1dSwQLqirBPfGCWKkpkpm7C3HEfeeLrasral\n"\ + "aPf6LAwN3A4ZKHa5Jmne7W+1eYS1aTXOAOLIPcXRAh1B80H+SusIdM9d6vk2YTIg\n"\ + "khwGQV3sgM6nIO5+T/8z141UEjWbtP7pb/u0+G9Cg7TwvRoO2UukxdvOwNto1G2e\n"\ + "J3rKB/JSYsYWnPHvvh9XR+55PZ4iCf9Rqw/IP82uyGipR9gxlHqN8WhMTj9tNEkC\n"\ + "AwEAAaMhMB8wHQYDVR0OBBYEFISCemcSriz1HFhRXluw9H+Bv9lEMA0GCSqGSIb3\n"\ + "DQEBCwUAA4IBAQCMetK0xe6Y/uZpb1ARh+hHYcHI3xI+IG4opWJeoB1gDh/xpNAW\n"\ + "j6t5MGbLoqNMBXbqL26hnKVspyvCxw7ebI5ZJgjtbrD1t+0D8yrgIZzr7AWGA9Hj\n"\ + "WIHqDHGDxwkmfjVVPmuO3l5RtJmL6KV6kVL2bOvVI6gECpFLddmOTtg+iXDfSw3x\n"\ + "0+ueMYKr8QLF+TCxfzQTHvTHvOJtcZHecc1n7PYbRmI2p7tV6RoBpV69oM6NAVUV\n"\ + "i2QoSxm0pYzDzavOaxwhEPHT34Tpg6fwXy1QokFD9OtxRFtdpTjL3bMWpatZE+ba\n"\ + "cjvvf0utMW5fNjTTxu1nnpuxZM3ifTCqZJ+9\n"\ + "-----END CERTIFICATE-----\n"; + +/* Root cert from openssl s_client -connect google.com:443 -showcerts + */ +static const char *rsa2048_cert = "-----BEGIN CERTIFICATE-----\n"\ + "MIIDfTCCAuagAwIBAgIDErvmMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT\n"\ + "MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0\n"\ + "aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDIwNTIxMDQwMDAwWhcNMTgwODIxMDQwMDAw\n"\ + "WjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UE\n"\ + "AxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\n"\ + "CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9m\n"\ + "OSm9BXiLnTjoBbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIu\n"\ + "T8rxh0PBFpVXLVDviS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6c\n"\ + "JmTM386DGXHKTubU1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmR\n"\ + "Cw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5asz\n"\ + "PeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo4HwMIHtMB8GA1UdIwQYMBaAFEjm\n"\ + "aPkr0rKV10fYIyAQTzOYkJ/UMB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrM\n"\ + "TjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjA6BgNVHR8EMzAxMC+g\n"\ + "LaArhilodHRwOi8vY3JsLmdlb3RydXN0LmNvbS9jcmxzL3NlY3VyZWNhLmNybDBO\n"\ + "BgNVHSAERzBFMEMGBFUdIAAwOzA5BggrBgEFBQcCARYtaHR0cHM6Ly93d3cuZ2Vv\n"\ + "dHJ1c3QuY29tL3Jlc291cmNlcy9yZXBvc2l0b3J5MA0GCSqGSIb3DQEBBQUAA4GB\n"\ + "AHbhEm5OSxYShjAGsoEIz/AIx8dxfmbuwu3UOx//8PDITtZDOLC5MH0Y0FWDomrL\n"\ + "NhGc6Ehmo21/uBPUR/6LWlxz/K7ZGzIZOKuXNBSqltLroxwUCEm2u+WR74M26x1W\n"\ + "b8ravHNjkOR/ez4iyz0H7V84dJzjA1BOoa+Y7mHyhD8S\n"\ + "-----END CERTIFICATE-----\n"; + +/* Some random input bytes to public key encrypt */ +static const uint8_t pki_input[4096/8] = { + 0, 1, 4, 6, 7, 9, 33, 103, 49, 11, 56, 211, 67, 92 }; + +/* Result of an RSA4096 operation using cert's public key + (raw PKI, no padding/etc) */ +static const uint8_t pki_rsa4096_output[] = { + 0x91, 0x87, 0xcd, 0x04, 0x80, 0x7c, 0x8b, 0x0b, + 0x0c, 0xc0, 0x38, 0x37, 0x7a, 0xe3, 0x2c, 0x94, + 0xea, 0xc4, 0xcb, 0x83, 0x2c, 0x77, 0x71, 0x14, + 0x11, 0x85, 0x16, 0x61, 0xd3, 0x64, 0x2a, 0x0f, + 0xf9, 0x6b, 0x45, 0x04, 0x66, 0x5d, 0x15, 0xf1, + 0xcf, 0x69, 0x77, 0x90, 0xb9, 0x41, 0x68, 0xa9, + 0xa6, 0xfd, 0x94, 0xdc, 0x6a, 0xce, 0xc7, 0xb6, + 0x41, 0xd9, 0x44, 0x3c, 0x02, 0xb6, 0xc7, 0x26, + 0xce, 0xec, 0x66, 0x21, 0xa8, 0xe8, 0xf4, 0xa9, + 0x33, 0x4a, 0x6c, 0x28, 0x0f, 0x50, 0x30, 0x32, + 0x28, 0x00, 0xbb, 0x2c, 0xc3, 0x44, 0x72, 0x31, + 0x93, 0xd4, 0xde, 0x29, 0x6b, 0xfa, 0x31, 0xfd, + 0x3a, 0x05, 0xc6, 0xb1, 0x28, 0x43, 0x57, 0x20, + 0xf7, 0xf8, 0x13, 0x0c, 0x4a, 0x80, 0x00, 0xab, + 0x1f, 0xe8, 0x88, 0xad, 0x56, 0xf2, 0xda, 0x5a, + 0x50, 0xe9, 0x02, 0x09, 0x21, 0x2a, 0xfc, 0x82, + 0x68, 0x34, 0xf9, 0x04, 0xa3, 0x25, 0xe1, 0x0f, + 0xa8, 0x77, 0x29, 0x94, 0xb6, 0x9d, 0x5a, 0x08, + 0x33, 0x8d, 0x27, 0x6a, 0xc0, 0x3b, 0xad, 0x91, + 0x8a, 0x83, 0xa9, 0x2e, 0x48, 0xcd, 0x67, 0xa3, + 0x3a, 0x35, 0x41, 0x85, 0xfa, 0x3f, 0x61, 0x1f, + 0x80, 0xeb, 0xcd, 0x5a, 0xc5, 0x14, 0x7b, 0xab, + 0x9c, 0x45, 0x11, 0xd2, 0x25, 0x9a, 0x16, 0xeb, + 0x9c, 0xfa, 0xbe, 0x73, 0x18, 0xbd, 0x25, 0x8e, + 0x99, 0x6d, 0xb3, 0xbc, 0xac, 0x2d, 0xa2, 0x53, + 0xe8, 0x7c, 0x38, 0x1b, 0x7a, 0x75, 0xff, 0x76, + 0x4f, 0x48, 0x5b, 0x39, 0x20, 0x5a, 0x7b, 0x82, + 0xd3, 0x33, 0x33, 0x2a, 0xab, 0x6a, 0x7a, 0x42, + 0x1d, 0x1f, 0xd1, 0x61, 0x58, 0xd7, 0x38, 0x52, + 0xdf, 0xb0, 0x61, 0x98, 0x63, 0xb7, 0xa1, 0x4e, + 0xdb, 0x9b, 0xcb, 0xb7, 0x85, 0xc4, 0x3e, 0x03, + 0xe5, 0x59, 0x50, 0x28, 0x5a, 0x4d, 0x7f, 0x53, + 0x2e, 0x99, 0x1d, 0x6d, 0x85, 0x27, 0x78, 0x34, + 0x5e, 0xae, 0xc9, 0x1b, 0x37, 0x96, 0xde, 0x40, + 0x87, 0x35, 0x3c, 0x1f, 0xe0, 0x8f, 0xfb, 0x3a, + 0x58, 0x0e, 0x60, 0xe9, 0x06, 0xbd, 0x83, 0x03, + 0x92, 0xde, 0x5e, 0x69, 0x28, 0xb1, 0x00, 0xeb, + 0x44, 0xca, 0x3c, 0x49, 0x03, 0x10, 0xa8, 0x84, + 0xa6, 0xbb, 0xd5, 0xda, 0x98, 0x8c, 0x6f, 0xa3, + 0x0f, 0x39, 0xf3, 0xa7, 0x7d, 0xd5, 0x3b, 0xe2, + 0x85, 0x12, 0xda, 0xa4, 0x4d, 0x80, 0x97, 0xcb, + 0x11, 0xe0, 0x89, 0x90, 0xff, 0x5b, 0x72, 0x19, + 0x59, 0xd1, 0x39, 0x23, 0x9f, 0xb0, 0x00, 0xe2, + 0x45, 0x72, 0xc6, 0x9a, 0xbc, 0xe1, 0xd1, 0x51, + 0x6b, 0x35, 0xd2, 0x49, 0xbf, 0xb6, 0xfe, 0xab, + 0x09, 0xf7, 0x9d, 0xa4, 0x6e, 0x69, 0xb6, 0xf9, + 0xde, 0xe3, 0x57, 0x0c, 0x1a, 0x96, 0xf1, 0xcc, + 0x1c, 0x92, 0xdb, 0x44, 0xf4, 0x45, 0xfa, 0x8f, + 0x87, 0xcf, 0xf4, 0xd2, 0xa1, 0xf8, 0x69, 0x18, + 0xcf, 0xdc, 0xa0, 0x1f, 0xb0, 0x26, 0xad, 0x81, + 0xab, 0xdf, 0x78, 0x18, 0xa2, 0x74, 0xba, 0x2f, + 0xec, 0x70, 0xa2, 0x1f, 0x56, 0xee, 0xff, 0xc9, + 0xfe, 0xb1, 0xe1, 0x9b, 0xea, 0x0e, 0x33, 0x14, + 0x5f, 0x6e, 0xca, 0xee, 0x02, 0x56, 0x5a, 0x67, + 0x42, 0x9a, 0xbf, 0x55, 0xc0, 0x0f, 0x8e, 0x01, + 0x67, 0x63, 0x6e, 0xd1, 0x57, 0xf7, 0xf1, 0xc6, + 0x92, 0x9e, 0xb5, 0x45, 0xe1, 0x50, 0x58, 0x94, + 0x20, 0x90, 0x6a, 0x29, 0x2d, 0x4b, 0xd1, 0xb5, + 0x68, 0x63, 0xb5, 0xe6, 0xd8, 0x6e, 0x84, 0x80, + 0xad, 0xe6, 0x03, 0x1e, 0x51, 0xc2, 0xa8, 0x6d, + 0x84, 0xec, 0x2d, 0x7c, 0x61, 0x02, 0xd1, 0xda, + 0xf5, 0x94, 0xfa, 0x2d, 0xa6, 0xed, 0x89, 0x6a, + 0x6a, 0xda, 0x07, 0x5d, 0x83, 0xfc, 0x43, 0x76, + 0x7c, 0xca, 0x8c, 0x00, 0xfc, 0xb9, 0x2c, 0x23, +}; + +static const uint8_t pki_rsa2048_output[] = { + 0x47, 0x0b, 0xe5, 0x8a, 0xcd, 0x2f, 0x78, 0x07, + 0x69, 0x69, 0x70, 0xff, 0x81, 0xdf, 0x96, 0xf0, + 0xed, 0x82, 0x3a, 0x3d, 0x46, 0xab, 0xe9, 0xc3, + 0xb5, 0xd9, 0xca, 0xa2, 0x05, 0xa9, 0xf6, 0x6e, + 0xad, 0x6c, 0xe0, 0xd1, 0xa2, 0xb4, 0xf2, 0x78, + 0x4a, 0x93, 0xfc, 0x45, 0xe1, 0x9b, 0xdd, 0x62, + 0xf9, 0x66, 0x2a, 0x14, 0x38, 0x12, 0xb6, 0x50, + 0x0b, 0xe3, 0x53, 0x9c, 0x12, 0x56, 0xf1, 0xb7, + 0x83, 0xd5, 0xf3, 0x24, 0x81, 0xcc, 0x5a, 0xeb, + 0xec, 0xac, 0x68, 0xa8, 0x0c, 0xd7, 0x84, 0x7a, + 0xbb, 0x77, 0x7b, 0xd5, 0x5b, 0xcf, 0x7b, 0x25, + 0xd0, 0x75, 0x80, 0x21, 0x12, 0x97, 0x6b, 0xe1, + 0xb6, 0x51, 0x12, 0x52, 0x6e, 0x01, 0x92, 0xb7, + 0xcc, 0x70, 0x4b, 0x46, 0x11, 0x98, 0x5a, 0x84, + 0x1c, 0x90, 0x45, 0x0f, 0x15, 0x77, 0xdb, 0x79, + 0xe8, 0xff, 0x1f, 0xaa, 0x58, 0x95, 0xce, 0x3c, + 0x65, 0x0c, 0x66, 0x29, 0xe1, 0x9c, 0x41, 0xbb, + 0xde, 0x65, 0xb8, 0x29, 0x36, 0x94, 0xbd, 0x87, + 0x93, 0x39, 0xc5, 0xeb, 0x49, 0x21, 0xc1, 0xeb, + 0x48, 0xbd, 0x19, 0x13, 0x4d, 0x40, 0x90, 0x88, + 0xc6, 0x12, 0xd9, 0xf7, 0xdd, 0xc8, 0x4f, 0x89, + 0xc0, 0x91, 0xf8, 0xeb, 0xcf, 0xe3, 0x12, 0x17, + 0x88, 0x9c, 0x88, 0xf4, 0xf5, 0xae, 0xf4, 0x15, + 0xfe, 0x17, 0xf6, 0xa4, 0x74, 0x49, 0x02, 0x05, + 0x11, 0x3b, 0x92, 0x25, 0x39, 0x2c, 0x4b, 0x08, + 0x19, 0x76, 0x13, 0x8d, 0xf9, 0xda, 0xae, 0xdf, + 0x30, 0xda, 0xcc, 0xbb, 0x3f, 0xb9, 0xb0, 0xd6, + 0x5c, 0x78, 0x4b, 0x2b, 0x35, 0x51, 0x17, 0x48, + 0xf5, 0xd4, 0x39, 0x7e, 0x05, 0x83, 0x68, 0x86, + 0x44, 0x5f, 0x56, 0x1d, 0x2c, 0x53, 0xd3, 0x64, + 0x3a, 0xb2, 0x0c, 0x4a, 0x85, 0xd6, 0x5b, 0x7e, + 0xf9, 0xe9, 0x50, 0x29, 0x5d, 0x4f, 0xcc, 0xc9, +}; + +_Static_assert(sizeof(pki_rsa2048_output) == 2048/8, "rsa2048 output is wrong size"); +_Static_assert(sizeof(pki_rsa4096_output) == 4096/8, "rsa4096 output is wrong size"); + +static void test_cert(const char *cert, const uint8_t *expected_output, size_t output_len); + +TEST_CASE("mbedtls RSA4096 cert", "[mbedtls]") +{ + + test_cert(rsa4096_cert, pki_rsa4096_output, 4096/8); +} + +TEST_CASE("mbedtls RSA2048 cert", "[mbedtls]") +{ + test_cert(rsa2048_cert, pki_rsa2048_output, 2048/8); +} + +static void test_cert(const char *cert, const uint8_t *expected_output, size_t output_len) +{ + mbedtls_x509_crt crt; + mbedtls_rsa_context *rsa; + char buf[output_len]; + + bzero(buf, output_len); + + mbedtls_x509_crt_init(&crt); + + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0, + -mbedtls_x509_crt_parse(&crt, + (const uint8_t *)cert, + strlen(cert)+1), + "parse cert"); + + rsa = mbedtls_pk_rsa(crt.pk); + TEST_ASSERT_NOT_NULL(rsa); + + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0, + -mbedtls_rsa_check_pubkey(rsa), + "check cert pubkey"); + + mbedtls_x509_crt_info(buf, sizeof(buf), "", &crt); + puts(buf); + + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0, + -mbedtls_rsa_public(rsa, pki_input, (uint8_t *)buf), + "RSA PK operation"); + + /* + // Dump buffer for debugging + for(int i = 0; i < output_len; i++) { + printf("0x%02x, ", buf[i]); + } + printf("\n"); + */ + + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_output, buf, output_len); + + mbedtls_x509_crt_free(&crt); +} From 84590ec0a4815e84cf32f790db5060f07ef98f7c Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Tue, 31 Jan 2017 17:23:25 +0200 Subject: [PATCH 003/112] FATFS enable support for multiple drives Current implementation has drive numbers and paths hardcoded to support only one FATFS drive. Arduino has it's own SPI driver to allow compatibility and flexibility. With the MR it is possible to have up to ```_VOLUMES``` drives connected (SPI, SDMMC and others) at the same time and accessed through VFS --- components/fatfs/src/diskio.c | 45 +++++++++-- components/fatfs/src/diskio.h | 7 ++ components/fatfs/src/esp_vfs_fat.h | 14 ++++ components/fatfs/src/vfs_fat.c | 113 +++++++++++++++++++++------ components/fatfs/src/vfs_fat_sdmmc.c | 23 ++++-- 5 files changed, 166 insertions(+), 36 deletions(-) diff --git a/components/fatfs/src/diskio.c b/components/fatfs/src/diskio.c index 004cfc5be..915bb8e2c 100644 --- a/components/fatfs/src/diskio.c +++ b/components/fatfs/src/diskio.c @@ -18,39 +18,70 @@ #include static const char* TAG = "ff_diskio"; -static ff_diskio_impl_t s_impls[_VOLUMES] = { { 0 } }; +static ff_diskio_impl_t * s_impls[_VOLUMES]; static sdmmc_card_t* s_cards[_VOLUMES] = { NULL }; +static bool s_impls_initialized = false; PARTITION VolToPart[] = { {0, 1}, /* Logical drive 0 ==> Physical drive 0, 1st partition */ {1, 0} /* Logical drive 1 ==> Physical drive 1, auto detection */ }; +BYTE ff_disk_getpdrv() +{ + BYTE i; + for(i=0; i<_VOLUMES; i++) { + if (!s_impls[i]) { + return i; + } + } + return 0xFF; +} + void ff_diskio_register(BYTE pdrv, const ff_diskio_impl_t* discio_impl) { assert(pdrv < _VOLUMES); - memcpy(&s_impls[pdrv], discio_impl, sizeof(ff_diskio_impl_t)); + + if (!s_impls_initialized) { + s_impls_initialized = true; + memset(s_impls, 0, _VOLUMES * sizeof(ff_diskio_impl_t*)); + } + + if (s_impls[pdrv]) { + ff_diskio_impl_t* im = s_impls[pdrv]; + s_impls[pdrv] = NULL; + free(im); + } + + if (!discio_impl) { + return; + } + + ff_diskio_impl_t * impl = (ff_diskio_impl_t *)malloc(sizeof(ff_diskio_impl_t)); + assert(impl != NULL); + memcpy(impl, discio_impl, sizeof(ff_diskio_impl_t)); + s_impls[pdrv] = impl; } DSTATUS ff_disk_initialize (BYTE pdrv) { - return s_impls[pdrv].init(pdrv); + return s_impls[pdrv]->init(pdrv); } DSTATUS ff_disk_status (BYTE pdrv) { - return s_impls[pdrv].status(pdrv); + return s_impls[pdrv]->status(pdrv); } DRESULT ff_disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count) { - return s_impls[pdrv].read(pdrv, buff, sector, count); + return s_impls[pdrv]->read(pdrv, buff, sector, count); } DRESULT ff_disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) { - return s_impls[pdrv].write(pdrv, buff, sector, count); + return s_impls[pdrv]->write(pdrv, buff, sector, count); } DRESULT ff_disk_ioctl (BYTE pdrv, BYTE cmd, void* buff) { - return s_impls[pdrv].ioctl(pdrv, cmd, buff); + return s_impls[pdrv]->ioctl(pdrv, cmd, buff); } DWORD get_fattime(void) diff --git a/components/fatfs/src/diskio.h b/components/fatfs/src/diskio.h index 7c224809f..2fd27a864 100644 --- a/components/fatfs/src/diskio.h +++ b/components/fatfs/src/diskio.h @@ -76,6 +76,13 @@ void ff_diskio_register(BYTE pdrv, const ff_diskio_impl_t* discio_impl); */ void ff_diskio_register_sdmmc(BYTE pdrv, sdmmc_card_t* card); +/** + * Get next available drive number + * + * @return 0xFF on fail, else the drive number + */ +BYTE ff_disk_getpdrv(); + /* Disk Status Bits (DSTATUS) */ #define STA_NOINIT 0x01 /* Drive not initialized */ diff --git a/components/fatfs/src/esp_vfs_fat.h b/components/fatfs/src/esp_vfs_fat.h index 087d6cf77..6dbef5cfb 100644 --- a/components/fatfs/src/esp_vfs_fat.h +++ b/components/fatfs/src/esp_vfs_fat.h @@ -57,6 +57,20 @@ esp_err_t esp_vfs_fat_register(const char* base_path, const char* fat_drive, */ esp_err_t esp_vfs_fat_unregister(); +/** + * @brief Un-register FATFS from VFS + * + * @note FATFS structure returned by esp_vfs_fat_register is destroyed after + * this call. Make sure to call f_mount function to unmount it before + * calling esp_vfs_fat_unregister. + * @param base_path path prefix where FATFS is registered. This is the same + * used when esp_vfs_fat_register was called + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_STATE if FATFS is not registered in VFS + */ +esp_err_t esp_vfs_fat_unregister_ctx(const char* base_path); + /** * @brief Configuration arguments for esp_vfs_fat_sdmmc_mount function */ diff --git a/components/fatfs/src/vfs_fat.c b/components/fatfs/src/vfs_fat.c index 4ef387b43..6390fbcf7 100644 --- a/components/fatfs/src/vfs_fat.c +++ b/components/fatfs/src/vfs_fat.c @@ -28,6 +28,7 @@ typedef struct { char fat_drive[8]; + char base_path[ESP_VFS_PATH_MAX]; size_t max_files; FATFS fs; FIL files[0]; @@ -42,7 +43,6 @@ typedef struct { struct dirent cur_dirent; } vfs_fat_dir_t; - static const char* TAG = "vfs_fat"; static size_t vfs_fat_write(void* p, int fd, const void * data, size_t size); @@ -64,15 +64,42 @@ static int vfs_fat_closedir(void* ctx, DIR* pdir); static int vfs_fat_mkdir(void* ctx, const char* name, mode_t mode); static int vfs_fat_rmdir(void* ctx, const char* name); - -static char s_base_path[ESP_VFS_PATH_MAX]; +static vfs_fat_ctx_t* s_fat_ctxs[_VOLUMES] = { NULL, NULL }; +//compatibility static vfs_fat_ctx_t* s_fat_ctx = NULL; +static unsigned char esp_vfs_fat_get_ctx(const char* base_path) +{ + for(unsigned char i=0; i<_VOLUMES; i++) { + if (s_fat_ctxs[i] && !strcmp(s_fat_ctxs[i]->base_path, base_path)) { + return i; + } + } + return _VOLUMES; +} + +static unsigned char esp_vfs_fat_get_empty_ctx() +{ + for(unsigned char i=0; i<_VOLUMES; i++) { + if (!s_fat_ctxs[i]) { + return i; + } + } + return _VOLUMES; +} + esp_err_t esp_vfs_fat_register(const char* base_path, const char* fat_drive, size_t max_files, FATFS** out_fs) { - if (s_fat_ctx) { + unsigned char ctx = esp_vfs_fat_get_ctx(base_path); + if (ctx < _VOLUMES) { return ESP_ERR_INVALID_STATE; } + + ctx = esp_vfs_fat_get_empty_ctx(); + if (ctx == _VOLUMES) { + return ESP_ERR_NO_MEM; + } + const esp_vfs_t vfs = { .flags = ESP_VFS_FLAG_CONTEXT_PTR, .write_p = &vfs_fat_write, @@ -95,22 +122,49 @@ esp_err_t esp_vfs_fat_register(const char* base_path, const char* fat_drive, siz .rmdir_p = &vfs_fat_rmdir }; size_t ctx_size = sizeof(vfs_fat_ctx_t) + max_files * sizeof(FIL); - s_fat_ctx = (vfs_fat_ctx_t*) calloc(1, ctx_size); - if (s_fat_ctx == NULL) { + vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) calloc(1, ctx_size); + if (fat_ctx == NULL) { return ESP_ERR_NO_MEM; } - s_fat_ctx->max_files = max_files; - strncpy(s_fat_ctx->fat_drive, fat_drive, sizeof(s_fat_ctx->fat_drive) - 1); - *out_fs = &s_fat_ctx->fs; - esp_err_t err = esp_vfs_register(base_path, &vfs, s_fat_ctx); + fat_ctx->max_files = max_files; + + strncpy(fat_ctx->fat_drive, fat_drive, sizeof(fat_ctx->fat_drive) - 1); + fat_ctx->fat_drive[sizeof(fat_ctx->fat_drive) - 1] = 0; + + strncpy(fat_ctx->base_path, base_path, sizeof(fat_ctx->base_path) - 1); + fat_ctx->base_path[sizeof(fat_ctx->base_path) - 1] = 0; + + esp_err_t err = esp_vfs_register(base_path, &vfs, fat_ctx); if (err != ESP_OK) { - free(s_fat_ctx); - s_fat_ctx = NULL; + free(fat_ctx); return err; } - _lock_init(&s_fat_ctx->lock); - strncpy(s_base_path, base_path, sizeof(s_base_path) - 1); - s_base_path[sizeof(s_base_path) - 1] = 0; + + _lock_init(&fat_ctx->lock); + s_fat_ctxs[ctx] = fat_ctx; + + //compatibility + s_fat_ctx = fat_ctx; + + *out_fs = &fat_ctx->fs; + + return ESP_OK; +} + +esp_err_t esp_vfs_fat_unregister_ctx(const char* base_path) +{ + unsigned char ctx = esp_vfs_fat_get_ctx(base_path); + if (ctx == _VOLUMES) { + return ESP_ERR_INVALID_STATE; + } + vfs_fat_ctx_t* fat_ctx = s_fat_ctxs[ctx]; + esp_err_t err = esp_vfs_unregister(fat_ctx->base_path); + if (err != ESP_OK) { + return err; + } + _lock_close(&fat_ctx->lock); + free(fat_ctx); + s_fat_ctxs[ctx] = NULL; return ESP_OK; } @@ -119,12 +173,10 @@ esp_err_t esp_vfs_fat_unregister() if (s_fat_ctx == NULL) { return ESP_ERR_INVALID_STATE; } - esp_err_t err = esp_vfs_unregister(s_base_path); + esp_err_t err = esp_vfs_fat_unregister_ctx(s_fat_ctx->base_path); if (err != ESP_OK) { return err; } - _lock_close(&s_fat_ctx->lock); - free(s_fat_ctx); s_fat_ctx = NULL; return ESP_OK; } @@ -197,11 +249,19 @@ static void file_cleanup(vfs_fat_ctx_t* ctx, int fd) memset(&ctx->files[fd], 0, sizeof(FIL)); } +#define vfs_fat_fix_path(ctx, path) \ + if (((vfs_fat_ctx_t*)ctx)->fat_drive[0]) { \ + char buf_ ## path[strlen(path)+strlen(((vfs_fat_ctx_t*)ctx)->fat_drive)+1]; \ + sprintf(buf_ ## path,"%s%s", ((vfs_fat_ctx_t*)ctx)->fat_drive, path); \ + path = (const char *)buf_ ## path; \ + } + static int vfs_fat_open(void* ctx, const char * path, int flags, int mode) { + vfs_fat_fix_path(ctx, path); ESP_LOGV(TAG, "%s: path=\"%s\", flags=%x, mode=%x", __func__, path, flags, mode); vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx; - _lock_acquire(&s_fat_ctx->lock); + _lock_acquire(&fat_ctx->lock); int fd = get_next_fd(fat_ctx); if (fd < 0) { ESP_LOGE(TAG, "open: no free file descriptors"); @@ -218,7 +278,7 @@ static int vfs_fat_open(void* ctx, const char * path, int flags, int mode) goto out; } out: - _lock_release(&s_fat_ctx->lock); + _lock_release(&fat_ctx->lock); return fd; } @@ -257,7 +317,7 @@ static ssize_t vfs_fat_read(void* ctx, int fd, void * dst, size_t size) static int vfs_fat_close(void* ctx, int fd) { vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx; - _lock_acquire(&s_fat_ctx->lock); + _lock_acquire(&fat_ctx->lock); FIL* file = &fat_ctx->files[fd]; FRESULT res = f_close(file); file_cleanup(fat_ctx, fd); @@ -267,7 +327,7 @@ static int vfs_fat_close(void* ctx, int fd) errno = fresult_to_errno(res); rc = -1; } - _lock_release(&s_fat_ctx->lock); + _lock_release(&fat_ctx->lock); return rc; } @@ -308,6 +368,7 @@ static int vfs_fat_fstat(void* ctx, int fd, struct stat * st) static int vfs_fat_stat(void* ctx, const char * path, struct stat * st) { + vfs_fat_fix_path(ctx, path); FILINFO info; FRESULT res = f_stat(path, &info); if (res != FR_OK) { @@ -337,6 +398,7 @@ static int vfs_fat_stat(void* ctx, const char * path, struct stat * st) static int vfs_fat_unlink(void* ctx, const char *path) { + vfs_fat_fix_path(ctx, path); FRESULT res = f_unlink(path); if (res != FR_OK) { ESP_LOGD(TAG, "%s: fresult=%d", __func__, res); @@ -348,6 +410,8 @@ static int vfs_fat_unlink(void* ctx, const char *path) static int vfs_fat_link(void* ctx, const char* n1, const char* n2) { + vfs_fat_fix_path(ctx, n1); + vfs_fat_fix_path(ctx, n2); const size_t copy_buf_size = 4096; void* buf = malloc(copy_buf_size); if (buf == NULL) { @@ -402,6 +466,8 @@ fail1: static int vfs_fat_rename(void* ctx, const char *src, const char *dst) { + vfs_fat_fix_path(ctx, src); + vfs_fat_fix_path(ctx, dst); FRESULT res = f_rename(src, dst); if (res != FR_OK) { ESP_LOGD(TAG, "%s: fresult=%d", __func__, res); @@ -413,6 +479,7 @@ static int vfs_fat_rename(void* ctx, const char *src, const char *dst) static DIR* vfs_fat_opendir(void* ctx, const char* name) { + vfs_fat_fix_path(ctx, name); vfs_fat_dir_t* fat_dir = calloc(1, sizeof(vfs_fat_dir_t)); if (!fat_dir) { errno = ENOMEM; @@ -517,6 +584,7 @@ static void vfs_fat_seekdir(void* ctx, DIR* pdir, long offset) static int vfs_fat_mkdir(void* ctx, const char* name, mode_t mode) { (void) mode; + vfs_fat_fix_path(ctx, name); FRESULT res = f_mkdir(name); if (res != FR_OK) { ESP_LOGD(TAG, "%s: fresult=%d", __func__, res); @@ -528,6 +596,7 @@ static int vfs_fat_mkdir(void* ctx, const char* name, mode_t mode) static int vfs_fat_rmdir(void* ctx, const char* name) { + vfs_fat_fix_path(ctx, name); FRESULT res = f_unlink(name); if (res != FR_OK) { ESP_LOGD(TAG, "%s: fresult=%d", __func__, res); diff --git a/components/fatfs/src/vfs_fat_sdmmc.c b/components/fatfs/src/vfs_fat_sdmmc.c index e5956dd7b..f5e4c5099 100644 --- a/components/fatfs/src/vfs_fat_sdmmc.c +++ b/components/fatfs/src/vfs_fat_sdmmc.c @@ -22,6 +22,7 @@ static const char* TAG = "vfs_fat_sdmmc"; static sdmmc_card_t* s_card = NULL; +static uint8_t s_pdrv = 0; esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path, const sdmmc_host_t* host_config, @@ -56,11 +57,18 @@ esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path, } // connect SDMMC driver to FATFS - ff_diskio_register_sdmmc(0, s_card); + BYTE pdrv = ff_disk_getpdrv(); + if (pdrv == 0xFF) { + ESP_LOGD(TAG, "the maximum count of volumes is already mounted"); + goto fail; + } + ff_diskio_register_sdmmc(pdrv, s_card); + s_pdrv = pdrv; + char drv[3] = {(char)('0' + pdrv), ':', 0}; // connect FATFS to VFS FATFS* fs; - err = esp_vfs_fat_register(base_path, "", mount_config->max_files, &fs); + err = esp_vfs_fat_register(base_path, drv, mount_config->max_files, &fs); if (err == ESP_ERR_INVALID_STATE) { // it's okay, already registered with VFS } else if (err != ESP_OK) { @@ -69,7 +77,7 @@ esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path, } // Try to mount partition - FRESULT res = f_mount(fs, "", 1); + FRESULT res = f_mount(fs, drv, 1); if (res != FR_OK) { err = ESP_FAIL; ESP_LOGW(TAG, "failed to mount card (%d)", res); @@ -79,7 +87,7 @@ esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path, ESP_LOGW(TAG, "partitioning card"); DWORD plist[] = {100, 0, 0, 0}; workbuf = malloc(workbuf_size); - res = f_fdisk(0, plist, workbuf); + res = f_fdisk(s_pdrv, plist, workbuf); if (res != FR_OK) { err = ESP_FAIL; ESP_LOGD(TAG, "f_fdisk failed (%d)", res); @@ -94,7 +102,7 @@ esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path, } free(workbuf); ESP_LOGW(TAG, "mounting again"); - res = f_mount(fs, "", 0); + res = f_mount(fs, drv, 0); if (res != FR_OK) { err = ESP_FAIL; ESP_LOGD(TAG, "f_mount failed after formatting (%d)", res); @@ -105,7 +113,7 @@ esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path, fail: free(workbuf); - esp_vfs_unregister(base_path); + esp_vfs_fat_unregister_ctx(base_path); free(s_card); s_card = NULL; return err; @@ -117,7 +125,8 @@ esp_err_t esp_vfs_fat_sdmmc_unmount() return ESP_ERR_INVALID_STATE; } // unmount - f_mount(0, "", 0); + char drv[3] = {(char)('0' + s_pdrv), ':', 0}; + f_mount(0, drv, 0); // release SD driver free(s_card); s_card = NULL; From a57b6326e3ffb9e664033eac28ab26078a62b4b5 Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Tue, 31 Jan 2017 17:43:22 +0200 Subject: [PATCH 004/112] Fix ```if``` breaking the path --- components/fatfs/src/vfs_fat.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/components/fatfs/src/vfs_fat.c b/components/fatfs/src/vfs_fat.c index 6390fbcf7..e85666f1d 100644 --- a/components/fatfs/src/vfs_fat.c +++ b/components/fatfs/src/vfs_fat.c @@ -250,11 +250,9 @@ static void file_cleanup(vfs_fat_ctx_t* ctx, int fd) } #define vfs_fat_fix_path(ctx, path) \ - if (((vfs_fat_ctx_t*)ctx)->fat_drive[0]) { \ - char buf_ ## path[strlen(path)+strlen(((vfs_fat_ctx_t*)ctx)->fat_drive)+1]; \ - sprintf(buf_ ## path,"%s%s", ((vfs_fat_ctx_t*)ctx)->fat_drive, path); \ - path = (const char *)buf_ ## path; \ - } + char buf_ ## path[strlen(path)+strlen(((vfs_fat_ctx_t*)ctx)->fat_drive)+1]; \ + sprintf(buf_ ## path,"%s%s", ((vfs_fat_ctx_t*)ctx)->fat_drive, path); \ + path = (const char *)buf_ ## path; static int vfs_fat_open(void* ctx, const char * path, int flags, int mode) { From 972c6f0caea1d9ec0bb23693859f8c75e18a5fc1 Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Wed, 1 Feb 2017 17:55:25 +0200 Subject: [PATCH 005/112] implement review recomendations --- components/fatfs/src/diskio.c | 7 ++-- components/fatfs/src/diskio.h | 14 +++++-- components/fatfs/src/esp_vfs_fat.h | 10 ++++- components/fatfs/src/vfs_fat.c | 56 ++++++++++++++-------------- components/fatfs/src/vfs_fat_sdmmc.c | 29 ++++++++++---- 5 files changed, 72 insertions(+), 44 deletions(-) diff --git a/components/fatfs/src/diskio.c b/components/fatfs/src/diskio.c index 915bb8e2c..c61702f51 100644 --- a/components/fatfs/src/diskio.c +++ b/components/fatfs/src/diskio.c @@ -27,15 +27,16 @@ PARTITION VolToPart[] = { {1, 0} /* Logical drive 1 ==> Physical drive 1, auto detection */ }; -BYTE ff_disk_getpdrv() +esp_err_t ff_diskio_get_drive(BYTE* out_pdrv) { BYTE i; for(i=0; i<_VOLUMES; i++) { if (!s_impls[i]) { - return i; + *out_pdrv = i; + return ESP_OK; } } - return 0xFF; + return ESP_ERR_NOT_FOUND; } void ff_diskio_register(BYTE pdrv, const ff_diskio_impl_t* discio_impl) diff --git a/components/fatfs/src/diskio.h b/components/fatfs/src/diskio.h index 2fd27a864..64d5d5b8d 100644 --- a/components/fatfs/src/diskio.h +++ b/components/fatfs/src/diskio.h @@ -58,16 +58,19 @@ typedef struct { } ff_diskio_impl_t; /** - * Register diskio driver for given drive number. + * Register or unregister diskio driver for given drive number. * * When FATFS library calls one of disk_xxx functions for driver number pdrv, * corresponding function in discio_impl for given pdrv will be called. * * @param pdrv drive number - * @param discio_impl pointer to ff_diskio_impl_t structure with diskio functions + * @param discio_impl pointer to ff_diskio_impl_t structure with diskio functions + * or NULL to unregister and free previously registered drive */ void ff_diskio_register(BYTE pdrv, const ff_diskio_impl_t* discio_impl); +#define ff_diskio_unregister(pdrv_) ff_diskio_register(pdrv_, NULL) + /** * Register SD/MMC diskio driver * @@ -79,9 +82,12 @@ void ff_diskio_register_sdmmc(BYTE pdrv, sdmmc_card_t* card); /** * Get next available drive number * - * @return 0xFF on fail, else the drive number + * @param out_pdrv pointer to the byte to set if successful + * + * @return ESP_OK on success + * ESP_ERR_NOT_FOUND if all drives are attached */ -BYTE ff_disk_getpdrv(); +esp_err_t ff_diskio_get_drive(BYTE* out_pdrv); /* Disk Status Bits (DSTATUS) */ diff --git a/components/fatfs/src/esp_vfs_fat.h b/components/fatfs/src/esp_vfs_fat.h index 6dbef5cfb..9c39198da 100644 --- a/components/fatfs/src/esp_vfs_fat.h +++ b/components/fatfs/src/esp_vfs_fat.h @@ -51,18 +51,24 @@ esp_err_t esp_vfs_fat_register(const char* base_path, const char* fat_drive, * @note FATFS structure returned by esp_vfs_fat_register is destroyed after * this call. Make sure to call f_mount function to unmount it before * calling esp_vfs_fat_unregister. + * This function is left for compatibility and will be changed in + * future versions to accept base_path and replace the method below * @return * - ESP_OK on success * - ESP_ERR_INVALID_STATE if FATFS is not registered in VFS */ -esp_err_t esp_vfs_fat_unregister(); +esp_err_t esp_vfs_fat_unregister() __attribute__((deprecated)); /** * @brief Un-register FATFS from VFS * * @note FATFS structure returned by esp_vfs_fat_register is destroyed after * this call. Make sure to call f_mount function to unmount it before - * calling esp_vfs_fat_unregister. + * calling esp_vfs_fat_unregister_ctx. + * Difference between this function and the one above is that this one + * will release the correct drive, while the one above will release + * the last registered one + * * @param base_path path prefix where FATFS is registered. This is the same * used when esp_vfs_fat_register was called * @return diff --git a/components/fatfs/src/vfs_fat.c b/components/fatfs/src/vfs_fat.c index e85666f1d..10e207482 100644 --- a/components/fatfs/src/vfs_fat.c +++ b/components/fatfs/src/vfs_fat.c @@ -65,12 +65,12 @@ static int vfs_fat_mkdir(void* ctx, const char* name, mode_t mode); static int vfs_fat_rmdir(void* ctx, const char* name); static vfs_fat_ctx_t* s_fat_ctxs[_VOLUMES] = { NULL, NULL }; -//compatibility +//backwards-compatibility with esp_vfs_fat_unregister() static vfs_fat_ctx_t* s_fat_ctx = NULL; -static unsigned char esp_vfs_fat_get_ctx(const char* base_path) +static size_t find_context_index_by_path(const char* base_path) { - for(unsigned char i=0; i<_VOLUMES; i++) { + for(size_t i=0; i<_VOLUMES; i++) { if (s_fat_ctxs[i] && !strcmp(s_fat_ctxs[i]->base_path, base_path)) { return i; } @@ -78,9 +78,9 @@ static unsigned char esp_vfs_fat_get_ctx(const char* base_path) return _VOLUMES; } -static unsigned char esp_vfs_fat_get_empty_ctx() +static size_t find_unused_context_index() { - for(unsigned char i=0; i<_VOLUMES; i++) { + for(size_t i=0; i<_VOLUMES; i++) { if (!s_fat_ctxs[i]) { return i; } @@ -90,12 +90,12 @@ static unsigned char esp_vfs_fat_get_empty_ctx() esp_err_t esp_vfs_fat_register(const char* base_path, const char* fat_drive, size_t max_files, FATFS** out_fs) { - unsigned char ctx = esp_vfs_fat_get_ctx(base_path); + size_t ctx = find_context_index_by_path(base_path); if (ctx < _VOLUMES) { return ESP_ERR_INVALID_STATE; } - ctx = esp_vfs_fat_get_empty_ctx(); + ctx = find_unused_context_index(); if (ctx == _VOLUMES) { return ESP_ERR_NO_MEM; } @@ -127,12 +127,8 @@ esp_err_t esp_vfs_fat_register(const char* base_path, const char* fat_drive, siz return ESP_ERR_NO_MEM; } fat_ctx->max_files = max_files; - - strncpy(fat_ctx->fat_drive, fat_drive, sizeof(fat_ctx->fat_drive) - 1); - fat_ctx->fat_drive[sizeof(fat_ctx->fat_drive) - 1] = 0; - - strncpy(fat_ctx->base_path, base_path, sizeof(fat_ctx->base_path) - 1); - fat_ctx->base_path[sizeof(fat_ctx->base_path) - 1] = 0; + strlcpy(fat_ctx->fat_drive, fat_drive, sizeof(fat_ctx->fat_drive) - 1); + strlcpy(fat_ctx->base_path, base_path, sizeof(fat_ctx->base_path) - 1); esp_err_t err = esp_vfs_register(base_path, &vfs, fat_ctx); if (err != ESP_OK) { @@ -153,7 +149,7 @@ esp_err_t esp_vfs_fat_register(const char* base_path, const char* fat_drive, siz esp_err_t esp_vfs_fat_unregister_ctx(const char* base_path) { - unsigned char ctx = esp_vfs_fat_get_ctx(base_path); + size_t ctx = find_context_index_by_path(base_path); if (ctx == _VOLUMES) { return ESP_ERR_INVALID_STATE; } @@ -249,14 +245,20 @@ static void file_cleanup(vfs_fat_ctx_t* ctx, int fd) memset(&ctx->files[fd], 0, sizeof(FIL)); } -#define vfs_fat_fix_path(ctx, path) \ - char buf_ ## path[strlen(path)+strlen(((vfs_fat_ctx_t*)ctx)->fat_drive)+1]; \ - sprintf(buf_ ## path,"%s%s", ((vfs_fat_ctx_t*)ctx)->fat_drive, path); \ - path = (const char *)buf_ ## path; +static void prepend_drive_to_path(void * ctx, const char * path, const char * path2){ + static char buf[FILENAME_MAX+3]; + static char buf2[FILENAME_MAX+3]; + sprintf(buf, "%s%s", ((vfs_fat_ctx_t*)ctx)->fat_drive, path); + path = (const char *)buf; + if(path2){ + sprintf(buf2, "%s%s", ((vfs_fat_ctx_t*)ctx)->fat_drive, path2); + path2 = (const char *)buf; + } +} static int vfs_fat_open(void* ctx, const char * path, int flags, int mode) { - vfs_fat_fix_path(ctx, path); + prepend_drive_to_path(ctx, path, NULL); ESP_LOGV(TAG, "%s: path=\"%s\", flags=%x, mode=%x", __func__, path, flags, mode); vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx; _lock_acquire(&fat_ctx->lock); @@ -366,7 +368,7 @@ static int vfs_fat_fstat(void* ctx, int fd, struct stat * st) static int vfs_fat_stat(void* ctx, const char * path, struct stat * st) { - vfs_fat_fix_path(ctx, path); + prepend_drive_to_path(ctx, path, NULL); FILINFO info; FRESULT res = f_stat(path, &info); if (res != FR_OK) { @@ -396,7 +398,7 @@ static int vfs_fat_stat(void* ctx, const char * path, struct stat * st) static int vfs_fat_unlink(void* ctx, const char *path) { - vfs_fat_fix_path(ctx, path); + prepend_drive_to_path(ctx, path, NULL); FRESULT res = f_unlink(path); if (res != FR_OK) { ESP_LOGD(TAG, "%s: fresult=%d", __func__, res); @@ -408,8 +410,7 @@ static int vfs_fat_unlink(void* ctx, const char *path) static int vfs_fat_link(void* ctx, const char* n1, const char* n2) { - vfs_fat_fix_path(ctx, n1); - vfs_fat_fix_path(ctx, n2); + prepend_drive_to_path(ctx, n1, n2); const size_t copy_buf_size = 4096; void* buf = malloc(copy_buf_size); if (buf == NULL) { @@ -464,8 +465,7 @@ fail1: static int vfs_fat_rename(void* ctx, const char *src, const char *dst) { - vfs_fat_fix_path(ctx, src); - vfs_fat_fix_path(ctx, dst); + prepend_drive_to_path(ctx, src, dst); FRESULT res = f_rename(src, dst); if (res != FR_OK) { ESP_LOGD(TAG, "%s: fresult=%d", __func__, res); @@ -477,7 +477,7 @@ static int vfs_fat_rename(void* ctx, const char *src, const char *dst) static DIR* vfs_fat_opendir(void* ctx, const char* name) { - vfs_fat_fix_path(ctx, name); + prepend_drive_to_path(ctx, name, NULL); vfs_fat_dir_t* fat_dir = calloc(1, sizeof(vfs_fat_dir_t)); if (!fat_dir) { errno = ENOMEM; @@ -582,7 +582,7 @@ static void vfs_fat_seekdir(void* ctx, DIR* pdir, long offset) static int vfs_fat_mkdir(void* ctx, const char* name, mode_t mode) { (void) mode; - vfs_fat_fix_path(ctx, name); + prepend_drive_to_path(ctx, name, NULL); FRESULT res = f_mkdir(name); if (res != FR_OK) { ESP_LOGD(TAG, "%s: fresult=%d", __func__, res); @@ -594,7 +594,7 @@ static int vfs_fat_mkdir(void* ctx, const char* name, mode_t mode) static int vfs_fat_rmdir(void* ctx, const char* name) { - vfs_fat_fix_path(ctx, name); + prepend_drive_to_path(ctx, name, NULL); FRESULT res = f_unlink(name); if (res != FR_OK) { ESP_LOGD(TAG, "%s: fresult=%d", __func__, res); diff --git a/components/fatfs/src/vfs_fat_sdmmc.c b/components/fatfs/src/vfs_fat_sdmmc.c index f5e4c5099..16effdce2 100644 --- a/components/fatfs/src/vfs_fat_sdmmc.c +++ b/components/fatfs/src/vfs_fat_sdmmc.c @@ -13,6 +13,7 @@ // limitations under the License. #include +#include #include "esp_log.h" #include "esp_vfs.h" #include "esp_vfs_fat.h" @@ -23,6 +24,7 @@ static const char* TAG = "vfs_fat_sdmmc"; static sdmmc_card_t* s_card = NULL; static uint8_t s_pdrv = 0; +static char * s_base_path = NULL; esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path, const sdmmc_host_t* host_config, @@ -36,6 +38,20 @@ esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path, if (s_card != NULL) { return ESP_ERR_INVALID_STATE; } + + // connect SDMMC driver to FATFS + BYTE pdrv = 0xFF; + if (ff_diskio_get_drive(&pdrv) != ESP_OK || pdrv == 0xFF) { + ESP_LOGD(TAG, "the maximum count of volumes is already mounted"); + return ESP_ERR_NO_MEM; + } + + s_base_path = strdup(base_path); + if(!s_base_path){ + ESP_LOGD(TAG, "could not copy base_path"); + return ESP_ERR_NO_MEM; + } + // enable SDMMC sdmmc_host_init(); @@ -56,12 +72,6 @@ esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path, *out_card = s_card; } - // connect SDMMC driver to FATFS - BYTE pdrv = ff_disk_getpdrv(); - if (pdrv == 0xFF) { - ESP_LOGD(TAG, "the maximum count of volumes is already mounted"); - goto fail; - } ff_diskio_register_sdmmc(pdrv, s_card); s_pdrv = pdrv; char drv[3] = {(char)('0' + pdrv), ':', 0}; @@ -114,6 +124,7 @@ esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path, fail: free(workbuf); esp_vfs_fat_unregister_ctx(base_path); + ff_diskio_unregister(pdrv); free(s_card); s_card = NULL; return err; @@ -128,8 +139,12 @@ esp_err_t esp_vfs_fat_sdmmc_unmount() char drv[3] = {(char)('0' + s_pdrv), ':', 0}; f_mount(0, drv, 0); // release SD driver + ff_diskio_unregister(s_pdrv); free(s_card); s_card = NULL; sdmmc_host_deinit(); - return esp_vfs_fat_unregister(); + esp_err_t err = esp_vfs_fat_unregister_ctx(s_base_path); + free(s_base_path); + s_base_path = NULL; + return err; } From 0eeda99a8cac1634b4a279549bf6d3f7833eb315 Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Thu, 2 Feb 2017 12:24:38 +0200 Subject: [PATCH 006/112] pick better name for unregister function and update docs --- components/fatfs/src/esp_vfs_fat.h | 2 +- components/fatfs/src/vfs_fat.c | 4 ++-- components/fatfs/src/vfs_fat_sdmmc.c | 4 ++-- docs/api/storage/fatfs.rst | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/components/fatfs/src/esp_vfs_fat.h b/components/fatfs/src/esp_vfs_fat.h index 9c39198da..4e27dce69 100644 --- a/components/fatfs/src/esp_vfs_fat.h +++ b/components/fatfs/src/esp_vfs_fat.h @@ -75,7 +75,7 @@ esp_err_t esp_vfs_fat_unregister() __attribute__((deprecated)); * - ESP_OK on success * - ESP_ERR_INVALID_STATE if FATFS is not registered in VFS */ -esp_err_t esp_vfs_fat_unregister_ctx(const char* base_path); +esp_err_t esp_vfs_fat_unregister_path(const char* base_path); /** * @brief Configuration arguments for esp_vfs_fat_sdmmc_mount function diff --git a/components/fatfs/src/vfs_fat.c b/components/fatfs/src/vfs_fat.c index 10e207482..ecc3b1102 100644 --- a/components/fatfs/src/vfs_fat.c +++ b/components/fatfs/src/vfs_fat.c @@ -147,7 +147,7 @@ esp_err_t esp_vfs_fat_register(const char* base_path, const char* fat_drive, siz return ESP_OK; } -esp_err_t esp_vfs_fat_unregister_ctx(const char* base_path) +esp_err_t esp_vfs_fat_unregister_path(const char* base_path) { size_t ctx = find_context_index_by_path(base_path); if (ctx == _VOLUMES) { @@ -169,7 +169,7 @@ esp_err_t esp_vfs_fat_unregister() if (s_fat_ctx == NULL) { return ESP_ERR_INVALID_STATE; } - esp_err_t err = esp_vfs_fat_unregister_ctx(s_fat_ctx->base_path); + esp_err_t err = esp_vfs_fat_unregister_path(s_fat_ctx->base_path); if (err != ESP_OK) { return err; } diff --git a/components/fatfs/src/vfs_fat_sdmmc.c b/components/fatfs/src/vfs_fat_sdmmc.c index 16effdce2..ea6093633 100644 --- a/components/fatfs/src/vfs_fat_sdmmc.c +++ b/components/fatfs/src/vfs_fat_sdmmc.c @@ -123,7 +123,7 @@ esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path, fail: free(workbuf); - esp_vfs_fat_unregister_ctx(base_path); + esp_vfs_fat_unregister_path(base_path); ff_diskio_unregister(pdrv); free(s_card); s_card = NULL; @@ -143,7 +143,7 @@ esp_err_t esp_vfs_fat_sdmmc_unmount() free(s_card); s_card = NULL; sdmmc_host_deinit(); - esp_err_t err = esp_vfs_fat_unregister_ctx(s_base_path); + esp_err_t err = esp_vfs_fat_unregister_path(s_base_path); free(s_base_path); s_base_path = NULL; return err; diff --git a/docs/api/storage/fatfs.rst b/docs/api/storage/fatfs.rst index d2efc87ab..6dd04ae3e 100644 --- a/docs/api/storage/fatfs.rst +++ b/docs/api/storage/fatfs.rst @@ -8,7 +8,7 @@ Additionally, FatFs has been modified to support run-time pluggable disk IO laye Using FatFs with VFS -------------------- -``esp_vfs_fat.h`` header file defines functions to connect FatFs with VFS. ``esp_vfs_fat_register`` function allocates a ``FATFS`` structure, and registers a given path prefix in VFS. Subsequent operations on files starting with this prefix are forwarded to FatFs APIs. ``esp_vfs_fat_unregister`` function deletes the registration with VFS, and frees the ``FATFS`` structure. +``esp_vfs_fat.h`` header file defines functions to connect FatFs with VFS. ``esp_vfs_fat_register`` function allocates a ``FATFS`` structure, and registers a given path prefix in VFS. Subsequent operations on files starting with this prefix are forwarded to FatFs APIs. ``esp_vfs_fat_unregister_path`` function deletes the registration with VFS, and frees the ``FATFS`` structure. Most applications will use the following flow when working with ``esp_vfs_fat_`` functions: @@ -28,12 +28,12 @@ Most applications will use the following flow when working with ``esp_vfs_fat_`` 8. Call ``ff_diskio_register`` with NULL ``ff_diskio_impl_t*`` argument and the same drive number. -9. Call ``esp_vfs_fat_unregister`` to remove FatFs from VFS, and free the ``FATFS`` structure allocated on step 1. +9. Call ``esp_vfs_fat_unregister_path`` with the path where the file system is mounted to remove FatFs from VFS, and free the ``FATFS`` structure allocated on step 1. Convenience functions, ``esp_vfs_fat_sdmmc_mount`` and ``esp_vfs_fat_sdmmc_unmount``, which wrap these steps and also handle SD card initialization, are described in the next section. .. doxygenfunction:: esp_vfs_fat_register -.. doxygenfunction:: esp_vfs_fat_unregister +.. doxygenfunction:: esp_vfs_fat_unregister_path Using FatFs with VFS and SD cards From 68cba2a1fbc29438af3927512c99bc6769352695 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Mon, 30 Jan 2017 14:29:50 +1100 Subject: [PATCH 007/112] Bootloader: Support switching to Quad I/O mode during boot process --- .../bootloader/src/main/bootloader_start.c | 30 ++- components/bootloader/src/main/component.mk | 1 + .../bootloader/src/main/flash_qio_mode.c | 187 ++++++++++++++++++ .../bootloader/src/main/flash_qio_mode.h | 29 +++ components/esp32/include/rom/spi_flash.h | 15 +- components/esp32/ld/esp32.rom.ld | 2 + components/esptool_py/Kconfig.projbuild | 24 +-- make/test_build_system.sh | 4 +- 8 files changed, 262 insertions(+), 30 deletions(-) create mode 100644 components/bootloader/src/main/flash_qio_mode.c create mode 100644 components/bootloader/src/main/flash_qio_mode.h diff --git a/components/bootloader/src/main/bootloader_start.c b/components/bootloader/src/main/bootloader_start.c index a374c4306..7793896be 100644 --- a/components/bootloader/src/main/bootloader_start.c +++ b/components/bootloader/src/main/bootloader_start.c @@ -46,6 +46,7 @@ #include "bootloader_random.h" #include "bootloader_config.h" #include "rtc.h" +#include "flash_qio_mode.h" extern int _bss_start; extern int _bss_end; @@ -263,6 +264,10 @@ void bootloader_main() ESP_LOGI(TAG, "Enabling RNG early entropy source..."); bootloader_random_enable(); +#if CONFIG_FLASHMODE_QIO || CONFIG_FLASHMODE_QOUT + bootloader_enable_qio_mode(); +#endif + if(esp_image_load_header(0x1000, true, &fhdr) != ESP_OK) { ESP_LOGE(TAG, "failed to load bootloader header!"); return; @@ -632,28 +637,21 @@ void print_flash_info(const esp_image_header_t* phdr) } ESP_LOGI(TAG, "SPI Speed : %s", str ); - switch ( phdr->spi_mode ) { - case ESP_IMAGE_SPI_MODE_QIO: + /* SPI mode could have been set to QIO during boot already, + so test the SPI registers not the flash header */ + uint32_t spi_ctrl = REG_READ(SPI_CTRL_REG(0)); + if (spi_ctrl & SPI_FREAD_QIO) { str = "QIO"; - break; - case ESP_IMAGE_SPI_MODE_QOUT: + } else if (spi_ctrl & SPI_FREAD_QUAD) { str = "QOUT"; - break; - case ESP_IMAGE_SPI_MODE_DIO: + } else if (spi_ctrl & SPI_FREAD_DIO) { str = "DIO"; - break; - case ESP_IMAGE_SPI_MODE_DOUT: + } else if (spi_ctrl & SPI_FREAD_DUAL) { str = "DOUT"; - break; - case ESP_IMAGE_SPI_MODE_FAST_READ: + } else if (spi_ctrl & SPI_FASTRD_MODE) { str = "FAST READ"; - break; - case ESP_IMAGE_SPI_MODE_SLOW_READ: + } else { str = "SLOW READ"; - break; - default: - str = "DIO"; - break; } ESP_LOGI(TAG, "SPI Mode : %s", str ); diff --git a/components/bootloader/src/main/component.mk b/components/bootloader/src/main/component.mk index 73cd9287d..35f54ade6 100644 --- a/components/bootloader/src/main/component.mk +++ b/components/bootloader/src/main/component.mk @@ -8,6 +8,7 @@ LINKER_SCRIPTS := \ esp32.bootloader.ld \ $(IDF_PATH)/components/esp32/ld/esp32.rom.ld \ + $(IDF_PATH)/components/esp32/ld/esp32.peripherals.ld \ esp32.bootloader.rom.ld COMPONENT_ADD_LDFLAGS := -L $(COMPONENT_PATH) -lmain $(addprefix -T ,$(LINKER_SCRIPTS)) diff --git a/components/bootloader/src/main/flash_qio_mode.c b/components/bootloader/src/main/flash_qio_mode.c new file mode 100644 index 000000000..19383232c --- /dev/null +++ b/components/bootloader/src/main/flash_qio_mode.c @@ -0,0 +1,187 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include +#include +#include "flash_qio_mode.h" +#include "esp_log.h" +#include "rom/spi_flash.h" +#include "soc/spi_struct.h" +#include "sdkconfig.h" + +/* SPI flash controller */ +#define SPIFLASH SPI1 + +/* SPI commands (actual on-wire commands not SPI controller bitmasks) + Suitable for use with the execute_flash_command static function. +*/ +#define CMD_RDID 0x9F +#define CMD_WRSR 0x01 +#define CMD_WRSR2 0x31 /* Not all SPI flash uses this command */ +#define CMD_WREN 0x06 +#define CMD_WRDI 0x04 +#define CMD_RDSR 0x05 +#define CMD_RDSR2 0x35 /* Not all SPI flash uses this command */ + +static const char *TAG = "qio_mode"; + +typedef struct __attribute__((packed)) { + const char *manufacturer; + uint8_t mfg_id; /* 8-bit JEDEC manufacturer ID */ + uint16_t flash_id; /* 16-bit JEDEC flash chip ID */ + uint16_t id_mask; /* Bits to match on in flash chip ID */ + uint8_t read_status_command; + uint8_t write_status_command; + uint8_t status_qio_bit; /* Currently assumes same bit for read/write status */ +} qio_info_t; + +/* Array of known flash chips and data to enable Quad I/O mode + + Manufacturer & flash ID can be tested by running "esptool.py + flash_id" + + If manufacturer ID matches, and flash ID ORed with flash ID mask + matches, enable_qio_mode() will execute "Read Cmd", test if bit + number "QIE Bit" is set, and if not set it will call "Write Cmd" + with this bit set. + + Searching of this table stops when the first match is found. + + (This table currently makes a lot of assumptions about how Quad I/O + mode is enabled, some flash chips in future may require more complex + handlers - for example a function pointer to a handler function.) + */ +const static qio_info_t chip_data[] = { +/* Manufacturer, mfg_id, flash_id, id mask, Read Cmd, Write Cmd, QIE Bit */ + { "MXIC", 0xC2, 0x2000, 0xFF00, CMD_RDSR, CMD_WRSR, 6 }, + { "ISSI", 0x9D, 0x4000, 0xFF00, CMD_RDSR, CMD_WRSR, 6 }, + + /* Final entry is default entry, if no other IDs have matched. + + This approach works for chips including: + GigaDevice (mfg ID 0xC8, flash IDs including 4016), + FM25Q32 (mfg ID 0xA1, flash IDs including 4016) + */ + { NULL, 0xFF, 0xFFFF, 0xFFFF, CMD_RDSR2, CMD_WRSR2, 1 }, /* Bit 9 of status register (second byte) */ +}; + +#define NUM_CHIPS (sizeof(chip_data) / sizeof(qio_info_t)) + +static void enable_qio_mode(uint8_t read_status_command, + uint8_t write_status_command, + uint8_t status_qio_bit); + +/* Generic function to use the "user command" SPI controller functionality + to send commands to the SPI flash and read the respopnse. + + The command passed here is always the on-the-wire command given to the SPI flash unit. +*/ +static uint32_t execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len); + +void bootloader_enable_qio_mode(void) +{ + uint32_t raw_flash_id; + uint8_t mfg_id; + uint16_t flash_id; + int i; + + ESP_LOGD(TAG, "Probing for QIO mode enable..."); + SPI_Wait_Idle(&g_rom_flashchip); + + /* Set up some of the SPIFLASH user/ctrl variables which don't change + while we're probing using execute_flash_command() */ + SPIFLASH.ctrl.val = 0; + SPIFLASH.user.usr_dummy = 0; + SPIFLASH.user.usr_addr = 0; + SPIFLASH.user.usr_command = 1; + SPIFLASH.user2.usr_command_bitlen = 7; + + raw_flash_id = execute_flash_command(CMD_RDID, 0, 0, 24); + ESP_LOGD(TAG, "Raw SPI flash chip id 0x%x", raw_flash_id); + + mfg_id = raw_flash_id & 0xFF; + flash_id = (raw_flash_id >> 16) | (raw_flash_id & 0xFF00); + ESP_LOGD(TAG, "Manufacturer ID 0x%02x chip ID 0x%04x", mfg_id, flash_id); + + for (i = 0; i < NUM_CHIPS-1; i++) { + const qio_info_t *chip = &chip_data[i]; + if (mfg_id == chip->mfg_id && (flash_id & chip->id_mask) == (chip->flash_id & chip->id_mask)) { + ESP_LOGI(TAG, "Enabling QIO for flash chip %s", chip_data[i].manufacturer); + break; + } + } + + if (i == NUM_CHIPS - 1) { + ESP_LOGI(TAG, "Enabling default flash chip QIO"); + } + + enable_qio_mode(chip_data[i].read_status_command, + chip_data[i].write_status_command, + chip_data[i].status_qio_bit); +} + +static void enable_qio_mode(uint8_t read_status_command, + uint8_t write_status_command, + uint8_t status_qio_bit) +{ + uint32_t status_len = (status_qio_bit + 8) & ~7; /* 8, 16, 24 bit status values */ + uint32_t status; + + SPI_Wait_Idle(&g_rom_flashchip); + + status = execute_flash_command(read_status_command, 0, 0, status_len); + ESP_LOGD(TAG, "Initial flash chip status 0x%x", status); + + if ((status & (1< 0; + SPIFLASH.miso_dlen.usr_miso_dbitlen = miso_len ? (miso_len - 1) : 0; + SPIFLASH.user.usr_mosi = mosi_len > 0; + SPIFLASH.mosi_dlen.usr_mosi_dbitlen = mosi_len ? (mosi_len - 1) : 0; + SPIFLASH.data_buf[0] = mosi_data; + + SPIFLASH.cmd.usr = 1; + while(SPIFLASH.cmd.usr != 0) + { } + + return SPIFLASH.data_buf[0]; +} diff --git a/components/bootloader/src/main/flash_qio_mode.h b/components/bootloader/src/main/flash_qio_mode.h new file mode 100644 index 000000000..9efa1313e --- /dev/null +++ b/components/bootloader/src/main/flash_qio_mode.h @@ -0,0 +1,29 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief Enable Quad I/O mode in bootloader (if configured) + * + * Queries attached SPI flash ID and sends correct SPI flash + * commands to enable QIO or QOUT mode, then enables this mode. + */ +void bootloader_enable_qio_mode(void); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp32/include/rom/spi_flash.h b/components/esp32/include/rom/spi_flash.h index 44098475d..a9d617e75 100644 --- a/components/esp32/include/rom/spi_flash.h +++ b/components/esp32/include/rom/spi_flash.h @@ -504,12 +504,25 @@ void SPI_Write_Encrypt_Disable(void); * @param uint32_t len : Length to write, should be 32 bytes aligned. * * @return SPI_FLASH_RESULT_OK : Data written successfully. - * SPI_FLASH_RESULT_ERR : Encrypto write error. + * SPI_FLASH_RESULT_ERR : Encryption write error. * SPI_FLASH_RESULT_TIMEOUT : Encrypto write timeout. */ SpiFlashOpResult SPI_Encrypt_Write(uint32_t flash_addr, uint32_t *data, uint32_t len); +/** @brief Wait until SPI flash write operation is complete + * + * @note Please do not call this function in SDK. + * + * Reads the Write In Progress bit of the SPI flash status register, + * repeats until this bit is zero (indicating write complete). + * + * @return SPI_FLASH_RESULT_OK : Write is complete + * SPI_FLASH_RESULT_ERR : Error while reading status. + */ +SpiFlashOpResult SPI_Wait_Idle(SpiFlashChip *spi); + + /** @brief Global SpiFlashChip structure used by ROM functions * */ diff --git a/components/esp32/ld/esp32.rom.ld b/components/esp32/ld/esp32.rom.ld index 7543fa42a..4c36ed09e 100644 --- a/components/esp32/ld/esp32.rom.ld +++ b/components/esp32/ld/esp32.rom.ld @@ -1563,6 +1563,8 @@ PROVIDE ( SPI_Write_Encrypt_Disable = 0x40062e60 ); PROVIDE ( SPI_Write_Encrypt_Enable = 0x40062df4 ); /* This is static function, but can be used, not generated by script*/ PROVIDE ( SPI_write_status = 0x400622f0 ); +/* This is static function, but can be used, not generated by script */ +PROVIDE ( SPI_Wait_Idle = 0x400622c0 ); PROVIDE ( srand = 0x40001004 ); PROVIDE ( __sread = 0x40001118 ); PROVIDE ( __srefill_r = 0x400593d4 ); diff --git a/components/esptool_py/Kconfig.projbuild b/components/esptool_py/Kconfig.projbuild index edff88c55..3ce1b7f3f 100644 --- a/components/esptool_py/Kconfig.projbuild +++ b/components/esptool_py/Kconfig.projbuild @@ -46,30 +46,32 @@ config ESPTOOLPY_COMPRESSED decompress it on the fly before flashing it. For most payloads, this should result in a speed increase. -choice ESPTOOLPY_FLASHMODE +choice FLASHMODE prompt "Flash SPI mode" - default ESPTOOLPY_FLASHMODE_DIO + default FLASHMODE_DIO help Mode the flash chip is flashed in, as well as the default mode for the binary to run in. -config ESPTOOLPY_FLASHMODE_QIO +config FLASHMODE_QIO bool "QIO" -config ESPTOOLPY_FLASHMODE_QOUT +config FLASHMODE_QOUT bool "QOUT" -config ESPTOOLPY_FLASHMODE_DIO +config FLASHMODE_DIO bool "DIO" -config ESPTOOLPY_FLASHMODE_DOUT +config FLASHMODE_DOUT bool "DOUT" endchoice +# Note: we use esptool.py to flash bootloader in +# dio mode for QIO/QOUT, bootloader then upgrades +# itself to quad mode during initialisation config ESPTOOLPY_FLASHMODE string - default "qio" if ESPTOOLPY_FLASHMODE_QIO - default "qout" if ESPTOOLPY_FLASHMODE_QOUT - default "dio" if ESPTOOLPY_FLASHMODE_DIO - default "dout" if ESPTOOLPY_FLASHMODE_DOUT - + default "dio" if FLASHMODE_QIO + default "dio" if FLASHMODE_QOUT + default "dio" if FLASHMODE_DIO + default "dout" if FLASHMODE_DOUT choice ESPTOOLPY_FLASHFREQ prompt "Flash SPI speed" diff --git a/make/test_build_system.sh b/make/test_build_system.sh index 5d24e2a94..4e72f457b 100755 --- a/make/test_build_system.sh +++ b/make/test_build_system.sh @@ -148,9 +148,9 @@ function run_tests() make assert_rebuilt ${APP_BINS} ${BOOTLOADER_BINS} - print_status "Touching peripherals ld file should only re-link app" + print_status "Touching app-only ld file should only re-link app" take_build_snapshot - touch ${IDF_PATH}/components/esp32/ld/esp32.peripherals.ld + touch ${IDF_PATH}/components/esp32/ld/esp32.common.ld make assert_rebuilt ${APP_BINS} assert_not_rebuilt ${BOOTLOADER_BINS} From 76d4f65ff9061caf5151aca86df1ffb06745fe6a Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 1 Feb 2017 13:14:09 +1100 Subject: [PATCH 008/112] bootloader: Add more flexible QIO support, for non-orthogonal command sets Should allow enabling QIO mode on WinBond (not yet tested). --- .../bootloader/src/main/flash_qio_mode.c | 87 ++++++++++++++----- 1 file changed, 65 insertions(+), 22 deletions(-) diff --git a/components/bootloader/src/main/flash_qio_mode.c b/components/bootloader/src/main/flash_qio_mode.c index 19383232c..c1afc1e03 100644 --- a/components/bootloader/src/main/flash_qio_mode.c +++ b/components/bootloader/src/main/flash_qio_mode.c @@ -35,16 +35,33 @@ static const char *TAG = "qio_mode"; +typedef unsigned (*read_status_fn_t)(); +typedef void (*write_status_fn_t)(unsigned); + typedef struct __attribute__((packed)) { const char *manufacturer; uint8_t mfg_id; /* 8-bit JEDEC manufacturer ID */ uint16_t flash_id; /* 16-bit JEDEC flash chip ID */ uint16_t id_mask; /* Bits to match on in flash chip ID */ - uint8_t read_status_command; - uint8_t write_status_command; - uint8_t status_qio_bit; /* Currently assumes same bit for read/write status */ + read_status_fn_t read_status_fn; + write_status_fn_t write_status_fn; + uint8_t status_qio_bit; } qio_info_t; +/* Read 8 bit status using RDSR command */ +static unsigned read_status_8b_rdsr(); +/* Read 8 bit status (second byte) using RDSR2 command */ +static unsigned read_status_8b_rdsr2(); +/* read 16 bit status using RDSR & RDSR2 (low and high bytes) */ +static unsigned read_status_16b_rdsr_rdsr2(); + +/* Write 8 bit status using WRSR */ +static void write_status_8b_wrsr(unsigned new_status); +/* Write 8 bit status (second byte) using WRSR2 */ +static void write_status_8b_wrsr2(unsigned new_status); +/* Write 16 bit status using WRSR */ +static void write_status_16b_wrsr(unsigned new_status); + /* Array of known flash chips and data to enable Quad I/O mode Manufacturer & flash ID can be tested by running "esptool.py @@ -56,29 +73,26 @@ typedef struct __attribute__((packed)) { with this bit set. Searching of this table stops when the first match is found. - - (This table currently makes a lot of assumptions about how Quad I/O - mode is enabled, some flash chips in future may require more complex - handlers - for example a function pointer to a handler function.) */ const static qio_info_t chip_data[] = { -/* Manufacturer, mfg_id, flash_id, id mask, Read Cmd, Write Cmd, QIE Bit */ - { "MXIC", 0xC2, 0x2000, 0xFF00, CMD_RDSR, CMD_WRSR, 6 }, - { "ISSI", 0x9D, 0x4000, 0xFF00, CMD_RDSR, CMD_WRSR, 6 }, +/* Manufacturer, mfg_id, flash_id, id mask, Read Status, Write Status, QIE Bit */ + { "MXIC", 0xC2, 0x2000, 0xFF00, read_status_8b_rdsr, write_status_8b_wrsr, 6 }, + { "ISSI", 0x9D, 0x4000, 0xFF00, read_status_8b_rdsr, write_status_8b_wrsr, 6 }, + { "WinBond", 0xEF, 0x4000, 0xFF00, read_status_16b_rdsr_rdsr2, write_status_16b_wrsr, 9 }, /* Final entry is default entry, if no other IDs have matched. This approach works for chips including: GigaDevice (mfg ID 0xC8, flash IDs including 4016), - FM25Q32 (mfg ID 0xA1, flash IDs including 4016) + FM25Q32 (QOUT mode only, mfg ID 0xA1, flash IDs including 4016) */ - { NULL, 0xFF, 0xFFFF, 0xFFFF, CMD_RDSR2, CMD_WRSR2, 1 }, /* Bit 9 of status register (second byte) */ + { NULL, 0xFF, 0xFFFF, 0xFFFF, read_status_8b_rdsr2, write_status_8b_wrsr2, 1 }, }; #define NUM_CHIPS (sizeof(chip_data) / sizeof(qio_info_t)) -static void enable_qio_mode(uint8_t read_status_command, - uint8_t write_status_command, +static void enable_qio_mode(read_status_fn_t read_status_fn, + write_status_fn_t write_status_fn, uint8_t status_qio_bit); /* Generic function to use the "user command" SPI controller functionality @@ -125,30 +139,29 @@ void bootloader_enable_qio_mode(void) ESP_LOGI(TAG, "Enabling default flash chip QIO"); } - enable_qio_mode(chip_data[i].read_status_command, - chip_data[i].write_status_command, + enable_qio_mode(chip_data[i].read_status_fn, + chip_data[i].write_status_fn, chip_data[i].status_qio_bit); } -static void enable_qio_mode(uint8_t read_status_command, - uint8_t write_status_command, +static void enable_qio_mode(read_status_fn_t read_status_fn, + write_status_fn_t write_status_fn, uint8_t status_qio_bit) { - uint32_t status_len = (status_qio_bit + 8) & ~7; /* 8, 16, 24 bit status values */ uint32_t status; SPI_Wait_Idle(&g_rom_flashchip); - status = execute_flash_command(read_status_command, 0, 0, status_len); + status = read_status_fn(); ESP_LOGD(TAG, "Initial flash chip status 0x%x", status); if ((status & (1< Date: Wed, 1 Feb 2017 18:04:07 +1100 Subject: [PATCH 009/112] test_build_system.sh: Produce less output to avoid CI log limit --- make/test_build_system.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/make/test_build_system.sh b/make/test_build_system.sh index 4e72f457b..cc7cc9e12 100755 --- a/make/test_build_system.sh +++ b/make/test_build_system.sh @@ -29,7 +29,9 @@ [ -z ${TMP} ] && TMP="/tmp" # override ESP_IDF_TEMPLATE_GIT to point to a local dir if you're testing and want fast iterations [ -z ${ESP_IDF_TEMPLATE_GIT} ] && ESP_IDF_TEMPLATE_GIT=https://github.com/espressif/esp-idf-template.git -export V=1 + +# uncomment next line to produce a lot more debug output +#export V=1 function run_tests() { @@ -133,7 +135,7 @@ function run_tests() # make a copy of esp-idf and CRLFify it CRLF_ESPIDF=${TESTDIR}/esp-idf-crlf mkdir -p ${CRLF_ESPIDF} - cp -rv ${IDF_PATH}/* ${CRLF_ESPIDF} + cp -r ${IDF_PATH}/* ${CRLF_ESPIDF} # don't CRLFify executable files, as Linux will fail to execute them find ${CRLF_ESPIDF} -type f ! -perm 755 -exec unix2dos {} \; make IDF_PATH=${CRLF_ESPIDF} || failure "Failed to build with CRLFs in source" From 25e2b07010116c935d7278bdbd4608faa07d783c Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Fri, 17 Feb 2017 15:51:58 +0800 Subject: [PATCH 010/112] components/openssl : Fix compilation error when openssl debugging is enabled --- components/openssl/platform/ssl_pm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/openssl/platform/ssl_pm.c b/components/openssl/platform/ssl_pm.c index 1281965e2..711af1770 100755 --- a/components/openssl/platform/ssl_pm.c +++ b/components/openssl/platform/ssl_pm.c @@ -646,13 +646,13 @@ void ssl_pm_set_bufflen(SSL *ssl, int len) long ssl_pm_get_verify_result(const SSL *ssl) { - long ret; + uint32_t ret; long verify_result; struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; ret = mbedtls_ssl_get_verify_result(&ssl_pm->ssl); if (ret) { - SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_get_verify_result() return -0x%x", -ret); + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_get_verify_result() return 0x%x", ret); verify_result = X509_V_ERR_UNSPECIFIED; } else verify_result = X509_V_OK; From 1f3a2e900ca3432a447f6e1df1b8c7b28c118ff3 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Fri, 17 Feb 2017 12:43:55 +1100 Subject: [PATCH 011/112] docs: Improve/clarify partition, OTA & SPI flash docs Related to #313 https://github.com/espressif/esp-idf/issues/313 --- components/app_update/esp_ota_ops.c | 4 +- components/app_update/include/esp_ota_ops.h | 101 ++++++---- .../bootloader/src/main/bootloader_start.c | 11 +- .../include/esp_flash_encrypt.h | 2 +- components/spi_flash/README.rst | 183 +++++++++--------- docs/api/storage/spi_flash.rst | 41 ++++ docs/api/system/index.rst | 2 +- docs/api/system/intr_alloc.rst | 77 +++++--- docs/api/system/ota.rst | 46 ++++- docs/general-notes.rst | 1 + docs/partition-tables.rst | 59 ++++-- 11 files changed, 340 insertions(+), 187 deletions(-) diff --git a/components/app_update/esp_ota_ops.c b/components/app_update/esp_ota_ops.c index c702a203e..efd697d07 100644 --- a/components/app_update/esp_ota_ops.c +++ b/components/app_update/esp_ota_ops.c @@ -82,7 +82,7 @@ esp_err_t esp_ota_begin(const esp_partition_t *partition, size_t image_size, esp return ESP_ERR_NO_MEM; } - // if input image size is 0 or OTA_SIZE_UNKNOWN, will erase all areas in this partition + // If input image size is 0 or OTA_SIZE_UNKNOWN, erase entire partition if ((image_size == 0) || (image_size == OTA_SIZE_UNKNOWN)) { ret = esp_partition_erase_range(partition, 0, partition->size); } else { @@ -301,7 +301,7 @@ static esp_err_t esp_rewrite_ota_data(esp_partition_subtype_t subtype) //so current ota app sub type id is x , dest bin subtype is y,total ota app count is n //seq will add (x + n*1 + 1 - seq)%n if (SUB_TYPE_ID(subtype) >= ota_app_count) { - return ESP_ERR_NOT_FOUND; + return ESP_ERR_INVALID_ARG; } ret = esp_partition_mmap(find_partition, 0, find_partition->size, SPI_FLASH_MMAP_DATA, &result, &ota_data_map); diff --git a/components/app_update/include/esp_ota_ops.h b/components/app_update/include/esp_ota_ops.h index fe3307763..dbe53b9f4 100755 --- a/components/app_update/include/esp_ota_ops.h +++ b/components/app_update/include/esp_ota_ops.h @@ -27,57 +27,75 @@ extern "C" { #endif -#define OTA_SIZE_UNKNOWN 0xffffffff +#define OTA_SIZE_UNKNOWN 0xffffffff /*!< Used for esp_ota_begin() if new image size is unknown */ -#define ESP_ERR_OTA_BASE 0x1500 /*!< base error code for ota_ops api */ -#define ESP_ERR_OTA_PARTITION_CONFLICT (ESP_ERR_OTA_BASE + 0x01) /*!< want to write or erase current running partition */ -#define ESP_ERR_OTA_SELECT_INFO_INVALID (ESP_ERR_OTA_BASE + 0x02) /*!< ota data partition info is error */ -#define ESP_ERR_OTA_VALIDATE_FAILED (ESP_ERR_OTA_BASE + 0x03) /*!< validate ota image failed */ +#define ESP_ERR_OTA_BASE 0x1500 /*!< Base error code for ota_ops api */ +#define ESP_ERR_OTA_PARTITION_CONFLICT (ESP_ERR_OTA_BASE + 0x01) /*!< Error if request was to write or erase the current running partition */ +#define ESP_ERR_OTA_SELECT_INFO_INVALID (ESP_ERR_OTA_BASE + 0x02) /*!< Error if OTA data partition contains invalid content */ +#define ESP_ERR_OTA_VALIDATE_FAILED (ESP_ERR_OTA_BASE + 0x03) /*!< Error if OTA app image is invalid */ /** - * @brief Opaque handle for application update obtained from app_ops. + * @brief Opaque handle for an application OTA update + * + * esp_ota_begin() returns a handle which is then used for subsequent + * calls to esp_ota_write() and esp_ota_end(). */ typedef uint32_t esp_ota_handle_t; /** - * @brief format input partition in flash to 0xFF as input image size, - * if unkown image size ,pass 0x0 or 0xFFFFFFFF, it will erase all the - * partition ,Otherwise, erase the required range - * - * @param partition Pointer to partition structure which need to be updated - * Must be non-NULL. - * @param image_size size of image need to be updated - * @param out_handle handle which should be used for esp_ota_write or esp_ota_end call + * @brief Commence an OTA update writing to the specified partition. - * @return: - * - ESP_OK: if format ota image OK - * - ESP_ERR_OTA_PARTITION_CONFLICT: operate current running bin - * - ESP_ERR_OTA_SELECT_INFO_INVALID: ota bin select info invalid + * The specified partition is erased to the specified image size. + * + * If image size is not yet known, pass OTA_SIZE_UNKNOWN which will + * cause the entire partition to be erased. + * + * On success, this function allocates memory that remains in use + * until esp_ota_end() is called with the returned handle. + * + * @param partition Pointer to info for partition which will receive the OTA update. Required. + * @param image_size Size of new OTA app image. Partition will be erased in order to receive this size of image. If 0 or OTA_SIZE_UNKNOWN, the entire partition is erased. + * @param out_handle On success, returns a handle which should be used for subsequent esp_ota_write() and esp_ota_end() calls. + + * @return + * - ESP_OK: OTA operation commenced successfully. + * - ESP_ERR_INVALID_ARG: partition or out_handle arguments were NULL. + * - ESP_ERR_NO_MEM: Cannot allocate memory for OTA operation. + * - ESP_ERR_OTA_PARTITION_CONFLICT: Partition is currently in use, cannot update. + * - ESP_ERR_OTA_SELECT_INFO_INVALID: The OTA data partition contains invalid data. + * - ESP_ERR_INVALID_SIZE: Partition doesn't fit in configured flash size. + * - ESP_ERR_FLASH_OP_TIMEOUT or ESP_ERR_FLASH_OP_FAIL: Flash write failed. */ esp_err_t esp_ota_begin(const esp_partition_t* partition, size_t image_size, esp_ota_handle_t* out_handle); /** - * @brief Write data to input input partition + * @brief Write OTA update data to partition * - * @param handle Handle obtained from esp_ota_begin - * @param data Pointer to data write to flash - * @param size data size of recieved data + * This function can be called multiple times as + * data is received during the OTA operation. Data is written + * sequentially to the partition. * - * @return: - * - ESP_OK: if write flash data OK - * - ESP_ERR_OTA_PARTITION_CONFLICT: operate current running bin - * - ESP_ERR_OTA_SELECT_INFO_INVALID: ota bin select info invalid + * @param handle Handle obtained from esp_ota_begin + * @param data Data buffer to write + * @param size Size of data buffer in bytes. + * + * @return + * - ESP_OK: Data was written to flash successfully. + * - ESP_ERR_INVALID_ARG: handle is invalid. + * - ESP_ERR_OTA_VALIDATE_FAILED: First byte of image contains invalid app image magic byte. + * - ESP_ERR_FLASH_OP_TIMEOUT or ESP_ERR_FLASH_OP_FAIL: Flash write failed. + * - ESP_ERR_OTA_SELECT_INFO_INVALID: OTA data partition has invalid contents */ esp_err_t esp_ota_write(esp_ota_handle_t handle, const void* data, size_t size); - + /** - * @brief Finish the update and validate written data + * @brief Finish OTA update and validate newly written app image. * - * @param handle Handle obtained from esp_ota_begin. + * @param handle Handle obtained from esp_ota_begin(). * * @note After calling esp_ota_end(), the handle is no longer valid and any memory associated with it is freed (regardless of result). * - * @return: + * @return * - ESP_OK: Newly written OTA app image is valid. * - ESP_ERR_NOT_FOUND: OTA handle was not found. * - ESP_ERR_INVALID_ARG: Handle was never written to. @@ -87,24 +105,25 @@ esp_err_t esp_ota_write(esp_ota_handle_t handle, const void* data, size_t size); esp_err_t esp_ota_end(esp_ota_handle_t handle); /** - * @brief Set next boot partition, call system_restart() will switch to run it + * @brief Configure OTA data for a new boot partition * - * @note if you want switch to run a bin file - * has never been checked before,please validate it's signature firstly + * @note If this function returns ESP_OK, calling esp_restart() will boot the newly configured app partition. * - * @param partition Pointer to partition structure which need to boot + * @param partition Pointer to info for partition containing app image to boot. * - * @return: - * - ESP_OK: if set next boot partition OK - * - ESP_ERR_OTA_SELECT_INFO_INVALID: ota bin select info invalid + * @return + * - ESP_OK: OTA data updated, next reboot will use specified partition. + * - ESP_ERR_INVALID_ARG: partition argument was NULL or didn't point to a valid OTA partition of type "app". + * - ESP_ERR_OTA_VALIDATE_FAILED: Partition contained invalid app image. Also returned if secure boot is enabled and signature validation failed. + * - ESP_ERR_NOT_FOUND: OTA data partition not found. + * - ESP_ERR_FLASH_OP_TIMEOUT or ESP_ERR_FLASH_OP_FAIL: Flash erase or write failed. */ esp_err_t esp_ota_set_boot_partition(const esp_partition_t* partition); /** - * @brief Get partition info of current running image - * - * @return pointer to esp_partition_t structure, or NULL if no partition is found or - * operate flash failed,This pointer is valid for the lifetime of the application. + * @brief Get partition info of currently running app + * + * @return Pointer to info for partition structure, or NULL if no partition is found or flash read operation failed. Returned pointer is valid for the lifetime of the application. */ const esp_partition_t* esp_ota_get_boot_partition(void); diff --git a/components/bootloader/src/main/bootloader_start.c b/components/bootloader/src/main/bootloader_start.c index 43066aa3d..ea56aa480 100644 --- a/components/bootloader/src/main/bootloader_start.c +++ b/components/bootloader/src/main/bootloader_start.c @@ -106,14 +106,13 @@ void IRAM_ATTR call_start_cpu0() } -/** - * @function : load_partition_table - * @description: Parse partition table, get useful data such as location of - * OTA info sector, factory app sector, and test app sector. +/** @brief Load partition table * - * @inputs: bs bootloader state structure used to save the data - * @return: return true, if the partition table is loaded (and MD5 checksum is valid) + * Parse partition table, get useful data such as location of + * OTA data partition, factory app partition, and test app partition. * + * @param bs bootloader state structure used to save read data + * @return return true if the partition table was succesfully loaded and MD5 checksum is valid. */ bool load_partition_table(bootloader_state_t* bs) { diff --git a/components/bootloader_support/include/esp_flash_encrypt.h b/components/bootloader_support/include/esp_flash_encrypt.h index 09e365724..ba370644a 100644 --- a/components/bootloader_support/include/esp_flash_encrypt.h +++ b/components/bootloader_support/include/esp_flash_encrypt.h @@ -33,7 +33,7 @@ * * @return true if flash encryption is enabled. */ -static inline IRAM_ATTR bool esp_flash_encryption_enabled(void) { +static inline /** @cond */ IRAM_ATTR /** @endcond */ bool esp_flash_encryption_enabled(void) { uint32_t flash_crypt_cnt = REG_GET_FIELD(EFUSE_BLK0_RDATA0_REG, EFUSE_RD_FLASH_CRYPT_CNT); /* __builtin_parity is in flash, so we calculate parity inline */ bool enabled = false; diff --git a/components/spi_flash/README.rst b/components/spi_flash/README.rst index b479c3b0e..da953f0cf 100644 --- a/components/spi_flash/README.rst +++ b/components/spi_flash/README.rst @@ -1,15 +1,15 @@ -SPI flash related APIs -====================== +SPI Flash APIs +============== Overview -------- -Spi_flash component contains APIs related to reading, writing, erasing, +The spi_flash component contains APIs related to reading, writing, erasing, memory mapping data in the external SPI flash. It also has higher-level -APIs which work with partition table and partitions. +APIs which work with partitions defined in the :doc:`partition table `. -Note that all the functionality is limited to the "main" flash chip, -i.e. the flash chip from which program runs. For ``spi_flash_*`` functions, -this is software limitation. Underlying ROM functions which work with SPI flash +Note that all the functionality is limited to the "main" SPI flash chip, +the same SPI flash chip from which program runs. For ``spi_flash_*`` functions, +this is a software limitation. The underlying ROM functions which work with SPI flash do not have provisions for working with flash chips attached to SPI peripherals other than SPI0. @@ -24,74 +24,113 @@ This is the set of APIs for working with data in flash: - ``spi_flash_erase_range`` used to erase range of addresses in flash - ``spi_flash_get_chip_size`` returns flash chip size, in bytes, as configured in menuconfig -There are some data alignment limitations which need to be considered when using -spi_flash_read/spi_flash_write functions: +Generally, try to avoid using the raw SPI flash functions in favour of +partition-specific functions. -- buffer in RAM must be 4-byte aligned -- size must be 4-byte aligned -- address in flash must be 4-byte aligned +SPI Flash Size +-------------- -These alignment limitations are purely software, and should be removed in future -versions. +The SPI flash size is configured by writing a field in the software bootloader +image header, flashed at offset 0x1000. -It is assumed that correct SPI flash chip size is set at compile time using -menuconfig. While run-time detection of SPI flash chip size is possible, it is -not implemented yet. Applications which need this (e.g. to provide one firmware -binary for different flash sizes) can do flash chip size detection and set -the correct flash chip size in ``chip_size`` member of ``g_rom_flashchip`` -structure. This size is used by ``spi_flash_*`` functions for bounds checking. +By default, the SPI flash size is detected by esptool.py when this bootloader is +written to flash, and the header is updated with the correct +size. Alternatively, it is possible to generate a fixed flash size by disabling +detection in ``make menuconfig`` (under Serial Flasher Config). -SPI flash APIs disable instruction and data caches while reading/writing/erasing. -See implementation notes below on details how this happens. For application -this means that at some periods of time, code can not be run from flash, -and constant data can not be fetched from flash by the CPU. This is not an -issue for normal code which runs in a task, because SPI flash APIs prevent -other tasks from running while caches are disabled. This is an issue for -interrupt handlers, which can still be called while flash operation is in -progress. If the interrupt handler is not placed into IRAM, there is a -possibility that interrupt will happen at the time when caches are disabled, -which will cause an illegal instruction exception. +If it is necessary to override the configured flash size at runtime, is is +possible to set the ``chip_size`` member of ``g_rom_flashchip`` structure. This +size is used by ``spi_flash_*`` functions (in both software & ROM) for bounds +checking. -To prevent this, make sure that all ISR code, and all functions called from ISR -code are placed into IRAM, or are located in ROM. Most useful C library -functions are located in ROM, so they can be called from ISR. +Concurrency Constraints +----------------------- -To place a function into IRAM, use ``IRAM_ATTR`` attribute, e.g.:: +Because the SPI flash is also used for firmware execution (via the instruction & +data caches), these caches much be disabled while reading/writing/erasing. This +means that both CPUs must be running code from IRAM and only reading data from +DRAM while flash write operations occur. - #include "esp_attr.h" - - void IRAM_ATTR gpio_isr_handler(void* arg) - { - // ... - } - -When flash encryption is enabled, ``spi_flash_read`` will read data as it is -stored in flash (without decryption), and ``spi_flash_write`` will write data -in plain text. In other words, ``spi_flash_read/write`` APIs don't have -provisions to deal with encrypted data. +Refer to the :ref:`application memory layout ` documentation for +an explanation of the differences between IRAM, DRAM and flash cache. +To avoid reading flash cache accidentally, when one CPU commences a flash write +or erase operation the other CPU is put into a blocked state and all +non-IRAM-safe interrupts are disabled on both CPUs, until the flash operation +completes. + +.. _iram-safe-interrupt-handlers: + +IRAM-Safe Interrupt Handlers +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If you have an interrupt handler that you want to execute even when a flash +operation is in progress (for example, for low latency operations), set the +``ESP_INTR_FLAG_IRAM`` flag when the :doc:`interrupt handler is registered +`. + +You must ensure all data and functions accessed by these interrupt handlers are +located in IRAM or DRAM. This includes any functions that the handler calls. + +Use the ``IRAM_ATTR`` attribute for functions:: + + #include "esp_attr.h" + + void IRAM_ATTR gpio_isr_handler(void* arg) + { + // ... + } + +Use the ``DRAM_ATTR`` and ``DRAM_STR`` attributes for constant data:: + + void IRAM_ATTR gpio_isr_handler(void* arg) + { + const static DRAM_ATTR uint8_t INDEX_DATA[] = { 45, 33, 12, 0 }; + const static char *MSG = DRAM_STR("I am a string stored in RAM"); + } + +Note that knowing which data should be marked with ``DRAM_ATTR`` can be hard, +the compiler will sometimes recognise that a variable or expression is constant +(even if it is not marked ``const``) and optimise it into flash, unless it is +marked with ``DRAM_ATTR``. + +If a function or symbol is not correctly put into IRAM/DRAM and the interrupt +handler reads from the flash cache during a flash operation, it will cause a +crash due to Illegal Instruction exception (for code which should be in IRAM) or +garbage data to be read (for constant data which should be in DRAM). Partition table APIs -------------------- -ESP-IDF uses partition table to maintain information about various regions of +ESP-IDF projects use a partition table to maintain information about various regions of SPI flash memory (bootloader, various application binaries, data, filesystems). -More information about partition tables can be found in docs/partition_tables.rst. +More information about partition tables can be found :doc:`here `. This component provides APIs to enumerate partitions found in the partition table and perform operations on them. These functions are declared in ``esp_partition.h``: -- ``esp_partition_find`` used to search partition table for entries with specific type, returns an opaque iterator +- ``esp_partition_find`` used to search partition table for entries with + specific type, returns an opaque iterator - ``esp_partition_get`` returns a structure describing the partition, for the given iterator - ``esp_partition_next`` advances iterator to the next partition found - ``esp_partition_iterator_release`` releases iterator returned by ``esp_partition_find`` -- ``esp_partition_find_first`` is a convenience function which returns structure describing the first partition found by esp_partition_find -- ``esp_partition_read``, ``esp_partition_write``, ``esp_partition_erase_range`` are equivalent to ``spi_flash_read``, ``spi_flash_write``, ``spi_flash_erase_range``, but operate within partition boundaries +- ``esp_partition_find_first`` is a convenience function which returns structure + describing the first partition found by esp_partition_find +- ``esp_partition_read``, ``esp_partition_write``, ``esp_partition_erase_range`` + are equivalent to ``spi_flash_read``, ``spi_flash_write``, + ``spi_flash_erase_range``, but operate within partition boundaries Most application code should use ``esp_partition_*`` APIs instead of lower level ``spi_flash_*`` APIs. Partition APIs do bounds checking and calculate correct offsets in flash based on data stored in partition table. +SPI Flash Encryption +-------------------- + +It is possible to encrypt SPI flash contents, and have it transparenlty decrypted by hardware. + +Refer to the :doc:`Flash Encryption documentation ` for more details. + Memory mapping APIs ------------------- @@ -105,10 +144,10 @@ about memory mapping hardware. Note that some number of 64KB pages is used to map the application itself into memory, so the actual number of available 64KB pages may be less. - + Reading data from flash using a memory mapped region is the only way to decrypt -contents of flash when flash encryption is enabled. Decryption is performed at -hardware level. +contents of flash when :doc:`flash encryption ` is enabled. +Decryption is performed at hardware level. Memory mapping APIs are declared in ``esp_spi_flash.h`` and ``esp_partition.h``: @@ -119,40 +158,8 @@ Memory mapping APIs are declared in ``esp_spi_flash.h`` and ``esp_partition.h``: Differences between ``spi_flash_mmap`` and ``esp_partition_mmap`` are as follows: - ``spi_flash_mmap`` must be given a 64KB aligned physical address -- ``esp_partition_mmap`` may be given an arbitrary offset within the partition, it will adjust returned pointer to mapped memory as necessary +- ``esp_partition_mmap`` may be given an arbitrary offset within the partition, + it will adjust returned pointer to mapped memory as necessary Note that because memory mapping happens in 64KB blocks, it may be possible to -read data outside of the partition provided to ``esp_partition_mmap``. - -Implementation notes --------------------- - -In order to perform some flash operations, we need to make sure both CPUs -are not running any code from flash for the duration of the flash operation. -In a single-core setup this is easy: we disable interrupts/scheduler and do -the flash operation. In the dual-core setup this is slightly more complicated. -We need to make sure that the other CPU doesn't run any code from flash. - - -When SPI flash API is called on CPU A (can be PRO or APP), we start -spi_flash_op_block_func function on CPU B using esp_ipc_call API. This API -wakes up high priority task on CPU B and tells it to execute given function, -in this case spi_flash_op_block_func. This function disables cache on CPU B and -signals that cache is disabled by setting s_flash_op_can_start flag. -Then the task on CPU A disables cache as well, and proceeds to execute flash -operation. - -While flash operation is running, interrupts can still run on CPUs A and B. -We assume that all interrupt code is placed into RAM. Once interrupt allocation -API is added, we should add a flag to request interrupt to be disabled for -the duration of flash operations. - -Once flash operation is complete, function on CPU A sets another flag, -s_flash_op_complete, to let the task on CPU B know that it can re-enable -cache and release the CPU. Then the function on CPU A re-enables the cache on -CPU A as well and returns control to the calling code. - -Additionally, all API functions are protected with a mutex (s_flash_op_mutex). - -In a single core environment (CONFIG_FREERTOS_UNICORE enabled), we simply -disable both caches, no inter-CPU communication takes place. +read data outside of the partition provided to ``esp_partition_mmap``. diff --git a/docs/api/storage/spi_flash.rst b/docs/api/storage/spi_flash.rst index 5725ceb0c..f941a3888 100644 --- a/docs/api/storage/spi_flash.rst +++ b/docs/api/storage/spi_flash.rst @@ -1,5 +1,12 @@ .. include:: ../../../components/spi_flash/README.rst +See also +-------- + +- :doc:`Partition Table documentation ` +- :doc:`Over The Air Update (OTA) API ` provides high-level API for updating app firmware stored in flash. +- :doc:`Non-Volatile Storage (NVS) API ` provides a structured API for storing small items of data in SPI flash. + API Reference ------------- @@ -63,3 +70,37 @@ Functions .. doxygenfunction:: esp_partition_mmap .. doxygenfunction:: esp_flash_encryption_enabled +.. _spi-flash-implementation-details: + +Implementation details +---------------------- + +In order to perform some flash operations, we need to make sure both CPUs +are not running any code from flash for the duration of the flash operation. +In a single-core setup this is easy: we disable interrupts/scheduler and do +the flash operation. In the dual-core setup this is slightly more complicated. +We need to make sure that the other CPU doesn't run any code from flash. + + +When SPI flash API is called on CPU A (can be PRO or APP), we start +spi_flash_op_block_func function on CPU B using esp_ipc_call API. This API +wakes up high priority task on CPU B and tells it to execute given function, +in this case spi_flash_op_block_func. This function disables cache on CPU B and +signals that cache is disabled by setting s_flash_op_can_start flag. +Then the task on CPU A disables cache as well, and proceeds to execute flash +operation. + +While flash operation is running, interrupts can still run on CPUs A and B. +We assume that all interrupt code is placed into RAM. Once interrupt allocation +API is added, we should add a flag to request interrupt to be disabled for +the duration of flash operations. + +Once flash operation is complete, function on CPU A sets another flag, +s_flash_op_complete, to let the task on CPU B know that it can re-enable +cache and release the CPU. Then the function on CPU A re-enables the cache on +CPU A as well and returns control to the calling code. + +Additionally, all API functions are protected with a mutex (s_flash_op_mutex). + +In a single core environment (CONFIG_FREERTOS_UNICORE enabled), we simply +disable both caches, no inter-CPU communication takes place. diff --git a/docs/api/system/index.rst b/docs/api/system/index.rst index a7d5d3901..321dc70d3 100644 --- a/docs/api/system/index.rst +++ b/docs/api/system/index.rst @@ -7,7 +7,7 @@ System API Memory Allocation Interrupt Allocation Watchdogs - OTA + Over The Air Updates (OTA) Deep Sleep Logging diff --git a/docs/api/system/intr_alloc.rst b/docs/api/system/intr_alloc.rst index 015cc32cd..8abe47e0f 100644 --- a/docs/api/system/intr_alloc.rst +++ b/docs/api/system/intr_alloc.rst @@ -32,30 +32,56 @@ even when the int for DevB was cleared) the interrupt is never serviced.) Multicore issues ---------------- -Peripherals that can generate interrupts can be divided in two types: external peripherals, outside the Xtensa -cores in the ESP32, and internal peripherals, inside the ESP32. Interrupt handling differs slightly between -these two types of peripherals. +Peripherals that can generate interrupts can be divided in two types: -Each Xtensa core has its own set of internal peripherals: three timer comparators, a performance monitor and two -software interrupts. These peripherals can only be configured from the core they are associated with. When -generating an interrupt, the interrupt they generate is hard-wired to their associated core; it's not possible -to have e.g. an internal timer comparator of one core generate an interrupt on another core. That is why these -sources can only be managed using a task running on that specific core. Internal interrupt sources are still -allocatable using esp_intr_alloc as normal, but they cannot be shared and will always have a fixed interrupt -level (namely, the one associated in hardware with the peripheral). Internal interrupt sources are defined -in esp_intr_alloc.h as ETS_INTERNAL_*_INTR_SOURCE. + - External peripherals, within the ESP32 but outside the Xtensa cores themselves. Most ESP32 peripherals are of this type. + - Internal peripherals, part of the Xtensa CPU cores themselves. -The remaining interrupt slots in both cores are wired to an interrupt multiplexer, which can be used to -route any external interrupt source to any of these interrupt slots. Allocating an external interrupt will always -allocate it on the core that does the allocation, and freeing the interrupt should always happen on the same -core. Disabling and enabling the interrupt from another core is allowed, however. External interrupts can -share an interrupt slot bu passing ESP_INTR_FLAG_SHARED as a flag to esp_intr_alloc. External interrupt sources -are defined in soc/soc.h as ETS_*_INTR_SOURCE. +Interrupt handling differs slightly between these two types of peripherals. -Care should be taken when allocating an interrupt using a task not pinned to a certain core; while running -code not in a critical secion, these tasks can migrate between cores at any moment, possibly making an -interrupt operation fail because of the reasons mentioned above. It is advised to always use -xTaskCreatePinnedToCore with a specific CoreID argument to create tasks that will handle interrupts. +Internal peripheral interrupts +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Each Xtensa CPU core has its own set of six internal peripherals: + + - Three timer comparators + - A performance monitor + - Two software interrupts. + +Internal interrupt sources are defined in esp_intr_alloc.h as ``ETS_INTERNAL_*_INTR_SOURCE``. + +These peripherals can only be configured from the core they are associated with. When generating an interrupt, +the interrupt they generate is hard-wired to their associated core; it's not possible to have e.g. an internal +timer comparator of one core generate an interrupt on another core. That is why these sources can only be managed +using a task running on that specific core. Internal interrupt sources are still allocatable using esp_intr_alloc +as normal, but they cannot be shared and will always have a fixed interrupt level (namely, the one associated in +hardware with the peripheral). + +External Peripheral Interrupts +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The remaining interrupt sources are from external peripherals. These are defined in soc/soc.h as ``ETS_*_INTR_SOURCE``. + +Non-internal interrupt slots in both CPU cores are wired to an interrupt multiplexer, which can be used to +route any external interrupt source to any of these interrupt slots. + +- Allocating an external interrupt will always allocate it on the core that does the allocation. +- Freeing an external interrupt must always happen on the same core it was allocated on. +- Disabling and enabling external interrupts from another core is allowed. +- Multiple external interrupt sources can share an interrupt slot by passing ``ESP_INTR_FLAG_SHARED`` as a flag to esp_intr_alloc(). + +Care should be taken when calling esp_intr_alloc() from a task which is not pinned to a core. During task switching, these tasks can migrate between cores. Therefore it is impossible to tell which CPU the interrupt is allocated on, which makes it difficult to free the interrupt handle and may also cause debugging difficulties. It is advised to use xTaskCreatePinnedToCore() with a specific CoreID argument to create tasks that will allocate interrupts. In the case of internal interrupt sources, this is required. + +IRAM-Safe Interrupt Handlers +---------------------------- + +The ``ESP_INTR_FLAG_IRAM`` flag registers an interrupt handler that always runs from IRAM (and reads all its data from DRAM), and therefore does not need to be disabled during flash erase and write operations. + +This is useful for interrupts which need a guaranteed minimum execution latency, as flash write and erase operations can be slow (erases can take tens or hundreds of milliseconds to complete). + +It can also be useful to keep an interrupt handler in IRAM if it is called very frequently, to avoid flash cache misses. + +Refer to the :ref:`SPI flash API documentation ` for more details. Application Example ------------------- @@ -86,15 +112,6 @@ Macros .. doxygendefine:: ESP_INTR_FLAG_IRAM .. doxygendefine:: ESP_INTR_FLAG_INTRDISABLED -Type Definitions -^^^^^^^^^^^^^^^^ - -Enumerations -^^^^^^^^^^^^ - -Structures -^^^^^^^^^^ - Functions ^^^^^^^^^ diff --git a/docs/api/system/ota.rst b/docs/api/system/ota.rst index 6ea4ea1f8..3fd0dd25c 100644 --- a/docs/api/system/ota.rst +++ b/docs/api/system/ota.rst @@ -1,10 +1,47 @@ -OTA -=== +Over The Air Updates (OTA) +========================== + +OTA Process Overview +^^^^^^^^^^^^^^^^^^^^ + +The OTA update mechanism allows a device to update itself based on data received while the normal firmware is running +(for example, over WiFi or Bluetooth.) + +OTA requires configuring the :doc:`Partition Table ` of the device with at least two "OTA app slot" +partitions (ie `ota_0` and `ota_1`) and an "OTA Data Partition". + +The OTA operation functions write a new app firmware image to whichever OTA app slot is not currently being used for +booting. Once the image is verified, the OTA Data partition is updated to specify that this image should be used for the +next boot. + +.. _ota_data_partition: + +OTA Data Partition +^^^^^^^^^^^^^^^^^^ + +An OTA data partition (type ``data``, subtype ``ota``) must be included in the :doc:`Partition Table ` +of any project which uses the OTA functions. + +For factory boot settings, the OTA data partition should contain no data (all bytes erased to 0xFF). In this case the +esp-idf software bootloader will boot the factory app if it is present in the the partition table. If no factory app is +included in the partition table, the first available OTA slot (usually ``ota_0``) is booted. + +After the first OTA update, the OTA data partition is updated to specify which OTA app slot partition should be booted next. + +The OTA data partition is two flash sectors (0x2000 bytes) in size, to prevent problems if there is a power failure +while it is being written. Sectors are independently erased and written with matching data, and if they disagree a +counter field is used to determine which sector was written more recently. + +See also +-------- + +* :doc:`Partition Table documentation ` +* :doc:`Lower-Level SPI Flash/Partition API ` Application Example ------------------- - -Demonstration of OTA (over the air) firmware update workflow: :example:`system/ota`. + +End-to-end example of OTA firmware update workflow: :example:`system/ota`. API Reference ------------- @@ -21,6 +58,7 @@ Macros .. doxygendefine:: ESP_ERR_OTA_PARTITION_CONFLICT .. doxygendefine:: ESP_ERR_OTA_SELECT_INFO_INVALID .. doxygendefine:: ESP_ERR_OTA_VALIDATE_FAILED +.. doxygendefine:: OTA_SIZE_UNKNOWN Type Definitions ^^^^^^^^^^^^^^^^ diff --git a/docs/general-notes.rst b/docs/general-notes.rst index 6597337a1..8f3c03045 100644 --- a/docs/general-notes.rst +++ b/docs/general-notes.rst @@ -55,6 +55,7 @@ While PRO CPU does initialization in ``start_cpu0`` function, APP CPU spins in ` Main task is the task which runs ``app_main`` function. Main task stack size and priority can be configured in ``menuconfig``. Application can use this task for initial application-specific setup, for example to launch other tasks. Application can also use main task for event loops and other general purpose activities. If ``app_main`` function returns, main task is deleted. +.. _memory-layout: Application memory layout ------------------------- diff --git a/docs/partition-tables.rst b/docs/partition-tables.rst index d45a540c6..afe880a2b 100644 --- a/docs/partition-tables.rst +++ b/docs/partition-tables.rst @@ -46,7 +46,6 @@ Here is the summary printed for the "Factory app, two OTA definitions" configura * The type of all three are set as "app", but the subtype varies between the factory app at 0x10000 and the next two "OTA" apps. * There is also a new "ota data" slot, which holds the data for OTA updates. The bootloader consults this data in order to know which app to execute. If "ota data" is empty, it will execute the factory app. - Creating Custom Tables ---------------------- @@ -61,7 +60,7 @@ The CSV format is the same format as printed in the summaries shown above. Howev factory, app, factory, 0x10000, 1M ota_0, app, ota_0, , 1M ota_1, app, ota_1, , 1M - + * Whitespace between fields is ignored, and so is any line starting with # (comments). * Each non-comment line in the CSV file is a partition definition. * Only the offset for the first partition is supplied. The gen_esp32part.py tool fills in each remaining offset to start after the preceding partition. @@ -74,16 +73,50 @@ Name field can be any meaningful name. It is not significant to the ESP32. Names Type field ~~~~~~~~~~ -Type field can be specified as app (0) or data (1). Or it can be a number 0-254 (or as hex 0x00-0xFE). Types 0x00-0x3F are reserved for Espressif. If your application needs to store data, please add a custom partition type in the range 0x40-0xFE. +Partition type field can be specified as app (0) or data (1). Or it can be a number 0-254 (or as hex 0x00-0xFE). Types 0x00-0x3F are reserved for esp-idf core functions. -The bootloader ignores any types other than 0 & 1. +If your application needs to store data, please add a custom partition type in the range 0x40-0xFE. + +The bootloader ignores any partition types other than app (0) & data (1). Subtype ~~~~~~~ -When type is "app", the subtype field can be specified as factory (0), ota_0 (0x10) ... ota_15 (0x1F) and test (0x20). Or it can be any number 0-255 (0x00-0xFF). The bootloader will execute the factory app unless there it sees a partition of type data/ota, in which case it reads this partition to determine which OTA image to boot +The 8-bit subtype field is specific to a given partition type. -When type is "data", the subtype field can be specified as ota (0), phy (1), nvs (2). Or it can be a number 0x00-0xFF. The bootloader ignores all data subtypes except for ota. Subtypes 0-0x7f are reserved for Espressif use. To create custom data partition subtypes use "data" type, and choose any unused subtype in 0x80-0xFF range. If you are porting a filesystem to the ESP-IDF, consider opening a PR to add the new subtype to esp_partition.h file. +esp-idf currently only specifies the meaning of the subtype field for "app" and "data" partition types. + +App Subtypes +~~~~~~~~~~~~ + +When type is "app", the subtype field can be specified as factory (0), ota_0 (0x10) ... ota_15 (0x1F) or test (0x20). + +- factory (0) is the default app partition. The bootloader will execute the factory app unless there it sees a partition of type data/ota, in which case it reads this partition to determine which OTA image to boot. + + - OTA never updates the factory partition. + - If you want to conserve flash usage in an OTA project, you can remove the factory partition and use ota_0 instead. +- ota_0 (0x10) ... ota_15 (0x1F) are the OTA app slots. Refer to the :doc:`OTA documentation ` for more details, which then use the OTA data partition to configure which app slot the bootloader should boot. If using OTA, an application should have at least two OTA application slots (ota_0 & ota_1). Refer to the :doc:`OTA documentation ` for more details. +- test (0x2) is a reserved subtype for factory test procedures. It is not currently supported by the esp-idf bootloader. + +Data Subtypes +~~~~~~~~~~~~~ + +When type is "data", the subtype field can be specified as ota (0), phy (1), nvs (2). + +- ota (0) is the :ref:`OTA data partition ` which stores information about the currently selected OTA application. This partition should be 0x2000 bytes in size. Refer to the :ref:`OTA documentation ` for more details. +- phy (1) is for storing PHY initialisation data. This allows PHY to be configured per-device, instead of in firmware. + + - In the default configuration, the phy partition is not used and PHY initialisation data is compiled into the app itself. As such, this partition can be removed from the partition table to save space. + - To load PHY data from this partition, run ``make menuconfig`` and enable "Component Config" -> "PHY" -> "Use a partition to store PHY init data". You will also need to flash your devices with phy init data as the esp-idf build system does not do this automatically. +- nvs (2) is for the :doc:`Non-Volatile Storage (NVS) API `. + + - NVS is used to store per-device PHY calibration data (different to initialisation data). + - NVS is used to store WiFi data if the :doc:`esp_wifi_set_storage(WIFI_STORAGE_FLASH) ` initialisation function is used. + - The NVS API can also be used for other application data. + - It is strongly recommended that you include an NVS partition of at least 0x3000 bytes in your project. + - If using NVS API to store a lot of data, increase the NVS partition size from the default 0x6000 bytes. + +Other data subtypes are reserved for future esp-idf uses. Offset & Size ~~~~~~~~~~~~~ @@ -92,28 +125,26 @@ Only the first offset field is required (we recommend using 0x10000). Partitions App partitions have to be at offsets aligned to 0x10000 (64K). If you leave the offset field blank, the tool will automatically align the partition. If you specify an unaligned offset for an app partition, the tool will return an error. -Sizes and offsets can be specified as decimal numbers, hex numbers with the prefix 0x, or size multipliers M or K (1024 and 1024*1024 bytes). - -NVS data partition has to be at least 0x3000 bytes long, and OTA data parition has to be 0x2000 bytes long. If you are using NVS in your application to store a lot of data, consider using a custom partition table with larger NVS partition. +Sizes and offsets can be specified as decimal numbers, hex numbers with the prefix 0x, or size multipliers K or M (1024 and 1024*1024 bytes). Generating Binary Partition Table --------------------------------- -The partition table which is flashed to the ESP32 is in a binary format, not CSV. The tool bin/gen_esp32part.py is used to convert between CSV and binary formats. +The partition table which is flashed to the ESP32 is in a binary format, not CSV. The tool :component_file:`partition_table/gen_esp32part.py` is used to convert between CSV and binary formats. -If you configure the partition table CSV name in ``make menuconfig`` and then ``make partition_table``, this conversion is done for you. +If you configure the partition table CSV name in ``make menuconfig`` and then ``make partition_table``, this conversion is done as part of the build process. To convert CSV to Binary manually:: - python bin/gen_esp32part.py --verify input_partitions.csv binary_partitions.bin + python gen_esp32part.py --verify input_partitions.csv binary_partitions.bin To convert binary format back to CSV:: - python bin/gen_esp32part.py --verify binary_partitions.bin input_partitions.csv + python gen_esp32part.py --verify binary_partitions.bin input_partitions.csv To display the contents of a binary partition table on stdout (this is how the summaries displayed when running `make partition_table` are generated:: - python bin/gen_esp32part.py binary_partitions.bin + python gen_esp32part.py binary_partitions.bin ``gen_esp32part.py`` takes one optional argument, ``--verify``, which will also verify the partition table during conversion (checking for overlapping partitions, unaligned partitions, etc.) From abf87b000d3ae6af326b2cbbd39dbac7b61645b8 Mon Sep 17 00:00:00 2001 From: Yulong Date: Mon, 20 Feb 2017 08:50:02 -0500 Subject: [PATCH 012/112] component/bt:fixed the write ccc crash bug error --- components/bt/bluedroid/stack/gatt/gatt_db.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/components/bt/bluedroid/stack/gatt/gatt_db.c b/components/bt/bluedroid/stack/gatt/gatt_db.c index 03919d483..bb9bfc5f7 100644 --- a/components/bt/bluedroid/stack/gatt/gatt_db.c +++ b/components/bt/bluedroid/stack/gatt/gatt_db.c @@ -597,11 +597,14 @@ UINT16 gatts_add_char_descr (tGATT_SVC_DB *p_db, tGATT_PERM perm, } p_char_dscptr->p_value->attr_val.attr_len = attr_val->attr_len; p_char_dscptr->p_value->attr_val.attr_max_len = attr_val->attr_max_len; - if (attr_val->attr_val != NULL) { + if (attr_val->attr_max_len != 0) { p_char_dscptr->p_value->attr_val.attr_val = GKI_getbuf(attr_val->attr_max_len); if (p_char_dscptr->p_value->attr_val.attr_val != NULL) { memset(p_char_dscptr->p_value->attr_val.attr_val, 0, attr_val->attr_max_len); - memcpy(p_char_dscptr->p_value->attr_val.attr_val, attr_val->attr_val, attr_val->attr_len); + if(attr_val->attr_val != NULL) { + memcpy(p_char_dscptr->p_value->attr_val.attr_val, + attr_val->attr_val, attr_val->attr_len); + } } } } @@ -873,7 +876,7 @@ tGATT_STATUS gatts_write_attr_value_by_handle(tGATT_SVC_DB *p_db, } if (p_attr->p_value != NULL && (p_attr->p_value->attr_val.attr_max_len >= - offset + len)) { + offset + len) && p_attr->p_value->attr_val.attr_val != NULL) { memcpy(p_attr->p_value->attr_val.attr_val + offset, p_value, len); p_attr->p_value->attr_val.attr_len = len + offset; return GATT_SUCCESS; From 55693b1168d4d6f9b97445b92dedb066599fe133 Mon Sep 17 00:00:00 2001 From: Tian Hao Date: Tue, 21 Feb 2017 17:46:59 +0800 Subject: [PATCH 013/112] component/bt : add option to release about 30K from BT if BLE only 1. later BT/BLE will be separated by BT/BLE macro, but this option should use when user make sure that in BLE only mode. --- components/bt/Kconfig | 9 +++++++++ components/bt/bt.c | 23 +++++++++++++++++++++-- components/bt/lib | 2 +- components/esp32/heap_alloc_caps.c | 6 ++++++ 4 files changed, 37 insertions(+), 3 deletions(-) diff --git a/components/bt/Kconfig b/components/bt/Kconfig index d2227868c..63dce8d1f 100644 --- a/components/bt/Kconfig +++ b/components/bt/Kconfig @@ -17,6 +17,15 @@ config BLUEDROID_MEM_DEBUG help Bluedroid memory debug +config BT_DRAM_RELEASE + bool "Release DRAM from Classic BT controller" + depends on BT_ENABLED + default n + help + This option should only be used when BLE only. + Open this option will release about 30K DRAM from Classic BT. + The released DRAM will be used as system heap memory. + # Memory reserved at start of DRAM for Bluetooth stack config BT_RESERVE_DRAM hex diff --git a/components/bt/bt.c b/components/bt/bt.c index 6a81d11ac..4943b9acb 100644 --- a/components/bt/bt.c +++ b/components/bt/bt.c @@ -32,9 +32,14 @@ #if CONFIG_BT_ENABLED +/* Bluetooth system and controller config */ +#define BTDM_CFG_BT_EM_RELEASE (1<<0) +#define BTDM_CFG_BT_DATA_RELEASE (1<<1) +/* Other reserved for future */ + /* not for user call, so don't put to include file */ extern void btdm_osi_funcs_register(void *osi_funcs); -extern void btdm_controller_init(void); +extern void btdm_controller_init(uint32_t config_mask); extern void btdm_controller_schedule(void); extern void btdm_controller_deinit(void); extern int btdm_controller_enable(esp_bt_mode_t mode); @@ -154,11 +159,25 @@ void esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callback) API_vhci_host_register_callback((const vhci_host_callback_t *)callback); } +static uint32_t btdm_config_mask_load(void) +{ + uint32_t mask = 0x0; + +#ifdef CONFIG_BT_DRAM_RELEASE + mask |= (BTDM_CFG_BT_EM_RELEASE | BTDM_CFG_BT_DATA_RELEASE); +#endif + return mask; +} + static void bt_controller_task(void *pvParam) { + uint32_t btdm_cfg_mask = 0; + btdm_osi_funcs_register(&osi_funcs); - btdm_controller_init(); + btdm_cfg_mask = btdm_config_mask_load(); + btdm_controller_init(btdm_cfg_mask); + btdm_controller_status = ESP_BT_CONTROLLER_STATUS_INITED; /* Loop */ diff --git a/components/bt/lib b/components/bt/lib index dbac82b5c..9f9f6a004 160000 --- a/components/bt/lib +++ b/components/bt/lib @@ -1 +1 @@ -Subproject commit dbac82b5c2694f2639161b0a2b3c0bd8c7d3efc5 +Subproject commit 9f9f6a004e42519f54555c42a037b8ef25bf2238 diff --git a/components/esp32/heap_alloc_caps.c b/components/esp32/heap_alloc_caps.c index a4ff870f3..7d2a26e64 100644 --- a/components/esp32/heap_alloc_caps.c +++ b/components/esp32/heap_alloc_caps.c @@ -193,8 +193,14 @@ void heap_alloc_caps_init() { disable_mem_region((void*)0x3ffe0000, (void*)0x3ffe8000); //knock out ROM data region #if CONFIG_BT_ENABLED +#if CONFIG_BT_DRAM_RELEASE + disable_mem_region((void*)0x3ffb0000, (void*)0x3ffb3000); //knock out BT data region + disable_mem_region((void*)0x3ffb8000, (void*)0x3ffbbb28); //knock out BT data region + disable_mem_region((void*)0x3ffbdb28, (void*)0x3ffc0000); //knock out BT data region +#else disable_mem_region((void*)0x3ffb0000, (void*)0x3ffc0000); //knock out BT data region #endif +#endif #if CONFIG_MEMMAP_TRACEMEM #if CONFIG_MEMMAP_TRACEMEM_TWOBANKS From 093dd9810188e53141aacf06235151c328abeb81 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Fri, 17 Feb 2017 18:26:43 +1100 Subject: [PATCH 014/112] spi_flash: Add new phys2cache & cache2phys functions to query flash cache mappings --- components/spi_flash/flash_mmap.c | 82 +++++++++++++++++--- components/spi_flash/include/esp_spi_flash.h | 36 +++++++++ components/spi_flash/test/test_mmap.c | 69 ++++++++++++++++ docs/api/storage/spi_flash.rst | 3 + 4 files changed, 180 insertions(+), 10 deletions(-) diff --git a/components/spi_flash/flash_mmap.c b/components/spi_flash/flash_mmap.c index f8d2e3297..64319a070 100644 --- a/components/spi_flash/flash_mmap.c +++ b/components/spi_flash/flash_mmap.c @@ -74,16 +74,23 @@ static uint32_t s_mmap_last_handle = 0; static void IRAM_ATTR spi_flash_mmap_init() { + if (s_mmap_page_refcnt[0] != 0) { + return; /* mmap data already initialised */ + } + for (int i = 0; i < REGIONS_COUNT * PAGES_PER_REGION; ++i) { uint32_t entry_pro = DPORT_PRO_FLASH_MMU_TABLE[i]; uint32_t entry_app = DPORT_APP_FLASH_MMU_TABLE[i]; if (entry_pro != entry_app) { // clean up entries used by boot loader - entry_pro = 0; - DPORT_PRO_FLASH_MMU_TABLE[i] = 0; + entry_pro = INVALID_ENTRY_VAL; + DPORT_PRO_FLASH_MMU_TABLE[i] = INVALID_ENTRY_VAL; } - if ((entry_pro & 0x100) == 0 && (i == 0 || i == PRO_IRAM0_FIRST_USABLE_PAGE || entry_pro != 0)) { + if ((entry_pro & INVALID_ENTRY_VAL) == 0 && (i == 0 || i == PRO_IRAM0_FIRST_USABLE_PAGE || entry_pro != 0)) { s_mmap_page_refcnt[i] = 1; + } else { + DPORT_PRO_FLASH_MMU_TABLE[i] = INVALID_ENTRY_VAL; + DPORT_APP_FLASH_MMU_TABLE[i] = INVALID_ENTRY_VAL; } } } @@ -108,9 +115,7 @@ esp_err_t IRAM_ATTR spi_flash_mmap(size_t src_addr, size_t size, spi_flash_mmap_ did_flush = spi_flash_ensure_unmodified_region(src_addr, size); - if (s_mmap_page_refcnt[0] == 0) { - spi_flash_mmap_init(); - } + spi_flash_mmap_init(); // figure out the memory region where we should look for pages int region_begin; // first page to check int region_size; // number of pages to check @@ -139,7 +144,7 @@ esp_err_t IRAM_ATTR spi_flash_mmap(size_t src_addr, size_t size, spi_flash_mmap_ int pos; for (pos = start; pos < start + page_count; ++pos, ++page) { int table_val = (int) DPORT_PRO_FLASH_MMU_TABLE[pos]; - uint8_t refcnt = s_mmap_page_refcnt[pos]; + uint8_t refcnt = s_mmap_page_refcnt[pos]; if (refcnt != 0 && table_val != page) { break; } @@ -229,9 +234,7 @@ void IRAM_ATTR spi_flash_munmap(spi_flash_mmap_handle_t handle) void spi_flash_mmap_dump() { - if (s_mmap_page_refcnt[0] == 0) { - spi_flash_mmap_init(); - } + spi_flash_mmap_init(); mmap_entry_t* it; for (it = LIST_FIRST(&s_mmap_entries_head); it != NULL; it = LIST_NEXT(it, entries)) { printf("handle=%d page=%d count=%d\n", it->handle, it->page, it->count); @@ -305,3 +308,62 @@ static inline IRAM_ATTR bool update_written_pages(size_t start_addr, size_t leng } return false; } + + +uint32_t spi_flash_cache2phys(const void *cached) +{ + intptr_t c = (intptr_t)cached; + size_t cache_page; + if (c >= VADDR1_START_ADDR && c < VADDR1_FIRST_USABLE_ADDR) { + /* IRAM address, doesn't map to flash */ + return SPI_FLASH_CACHE2PHYS_FAIL; + } + else if (c < VADDR1_FIRST_USABLE_ADDR) { + /* expect cache is in DROM */ + cache_page = (c - VADDR0_START_ADDR) / SPI_FLASH_MMU_PAGE_SIZE; + } else { + /* expect cache is in IROM */ + cache_page = (c - VADDR1_START_ADDR) / SPI_FLASH_MMU_PAGE_SIZE + 64; + } + + if (cache_page >= 256) { + /* cached address was not in IROM or DROM */ + return SPI_FLASH_CACHE2PHYS_FAIL; + } + uint32_t phys_page = DPORT_PRO_FLASH_MMU_TABLE[cache_page]; + if (phys_page == INVALID_ENTRY_VAL) { + /* page is not mapped */ + return SPI_FLASH_CACHE2PHYS_FAIL; + } + uint32_t phys_offs = phys_page * SPI_FLASH_MMU_PAGE_SIZE; + return phys_offs | (c & (SPI_FLASH_MMU_PAGE_SIZE-1)); +} + + +const void *spi_flash_phys2cache(uint32_t phys_offs, spi_flash_mmap_memory_t memory) +{ + uint32_t phys_page = phys_offs / SPI_FLASH_MMU_PAGE_SIZE; + int start, end, page_delta; + intptr_t base; + + if (memory == SPI_FLASH_MMAP_DATA) { + start = 0; + end = 64; + base = VADDR0_START_ADDR; + page_delta = 0; + } else { + start = PRO_IRAM0_FIRST_USABLE_PAGE; + end = 256; + base = VADDR1_START_ADDR; + page_delta = 64; + } + + for (int i = start; i < end; i++) { + if (DPORT_PRO_FLASH_MMU_TABLE[i] == phys_page) { + i -= page_delta; + intptr_t cache_page = base + (SPI_FLASH_MMU_PAGE_SIZE * i); + return (const void *) (cache_page | (phys_offs & (SPI_FLASH_MMU_PAGE_SIZE-1))); + } + } + return NULL; +} diff --git a/components/spi_flash/include/esp_spi_flash.h b/components/spi_flash/include/esp_spi_flash.h index 060d598ec..40720af38 100644 --- a/components/spi_flash/include/esp_spi_flash.h +++ b/components/spi_flash/include/esp_spi_flash.h @@ -197,6 +197,42 @@ void spi_flash_munmap(spi_flash_mmap_handle_t handle); */ void spi_flash_mmap_dump(); + +#define SPI_FLASH_CACHE2PHYS_FAIL UINT32_MAX /* #include #include +#include #include #include "test_config.h" @@ -65,6 +66,11 @@ TEST_CASE("Can mmap into data address space", "[mmap]") const void *ptr2; ESP_ERROR_CHECK( spi_flash_mmap(start - 0x10000, 0x20000, SPI_FLASH_MMAP_DATA, &ptr2, &handle2) ); printf("mmap_res: handle=%d ptr=%p\n", handle2, ptr2); + + TEST_ASSERT_EQUAL_HEX32(start - 0x10000, spi_flash_cache2phys(ptr2)); + TEST_ASSERT_EQUAL_PTR(ptr2, spi_flash_phys2cache(start - 0x10000, SPI_FLASH_MMAP_DATA)); + TEST_ASSERT_EQUAL_PTR((intptr_t)ptr2 + 0x12000, spi_flash_phys2cache(start - 0x10000 + 0x12000, SPI_FLASH_MMAP_DATA)); + spi_flash_mmap_dump(); printf("Mapping %x (+%x)\n", start, 0x10000); @@ -72,6 +78,11 @@ TEST_CASE("Can mmap into data address space", "[mmap]") const void *ptr3; ESP_ERROR_CHECK( spi_flash_mmap(start, 0x10000, SPI_FLASH_MMAP_DATA, &ptr3, &handle3) ); printf("mmap_res: handle=%d ptr=%p\n", handle3, ptr3); + + TEST_ASSERT_EQUAL_HEX32(start, spi_flash_cache2phys(ptr3)); + TEST_ASSERT_EQUAL_PTR(ptr3, spi_flash_phys2cache(start, SPI_FLASH_MMAP_DATA)); + TEST_ASSERT_EQUAL_PTR((intptr_t)ptr3 + 0x4444, spi_flash_phys2cache(start + 0x4444, SPI_FLASH_MMAP_DATA)); + spi_flash_mmap_dump(); printf("Unmapping handle1\n"); @@ -84,6 +95,8 @@ TEST_CASE("Can mmap into data address space", "[mmap]") printf("Unmapping handle3\n"); spi_flash_munmap(handle3); + + TEST_ASSERT_EQUAL_PTR(NULL, spi_flash_phys2cache(start, SPI_FLASH_MMAP_DATA)); } TEST_CASE("flash_mmap invalidates just-written data", "[spi_flash]") @@ -131,3 +144,59 @@ TEST_CASE("flash_mmap invalidates just-written data", "[spi_flash]") spi_flash_munmap(handle1); } + +TEST_CASE("phys2cache/cache2phys basic checks", "[spi_flash]") +{ + uint8_t buf_a[32], buf_b[32]; + + /* esp_partition_find is in IROM */ + uint32_t phys = spi_flash_cache2phys(esp_partition_find); + TEST_ASSERT_NOT_EQUAL(SPI_FLASH_CACHE2PHYS_FAIL, phys); + TEST_ASSERT_EQUAL_PTR(esp_partition_find, spi_flash_phys2cache(phys, SPI_FLASH_MMAP_INST)); + TEST_ASSERT_EQUAL_PTR(NULL, spi_flash_phys2cache(phys, SPI_FLASH_MMAP_DATA)); + + /* Read the flash @ 'phys' and compare it to the data we get via cache */ + memcpy(buf_a, esp_partition_find, sizeof(buf_a)); + spi_flash_read(phys, buf_b, sizeof(buf_b)); + TEST_ASSERT_EQUAL_HEX8_ARRAY(buf_a, buf_b, sizeof(buf_b)); + + /* spi_flash_mmap is in IRAM */ + printf("%p\n", spi_flash_mmap); + TEST_ASSERT_EQUAL_HEX32(SPI_FLASH_CACHE2PHYS_FAIL, + spi_flash_cache2phys(spi_flash_mmap)); + + /* 'start' should be in DROM */ + phys = spi_flash_cache2phys(&start); + TEST_ASSERT_NOT_EQUAL(SPI_FLASH_CACHE2PHYS_FAIL, phys); + TEST_ASSERT_EQUAL_PTR(&start, + spi_flash_phys2cache(phys, SPI_FLASH_MMAP_DATA)); + TEST_ASSERT_EQUAL_PTR(NULL, spi_flash_phys2cache(phys, SPI_FLASH_MMAP_INST)); + + /* Read the flash @ 'phys' and compare it to the data we get via cache */ + memcpy(buf_a, &start, sizeof(start)); + spi_flash_read(phys, buf_b, sizeof(start)); + TEST_ASSERT_EQUAL_HEX8_ARRAY(buf_a, buf_b, sizeof(start)); +} + +TEST_CASE("mmap consistent with phys2cache/cache2phys", "[spi_flash]") +{ + spi_flash_mmap_handle_t handle = 0; + const void *ptr = NULL; + const size_t test_size = 2 * SPI_FLASH_MMU_PAGE_SIZE; + + TEST_ASSERT_EQUAL_HEX(SPI_FLASH_CACHE2PHYS_FAIL, spi_flash_cache2phys(ptr)); + + ESP_ERROR_CHECK( spi_flash_mmap(TEST_REGION_START, test_size, SPI_FLASH_MMAP_DATA, &ptr, &handle) ); + TEST_ASSERT_NOT_NULL(ptr); + TEST_ASSERT_NOT_EQUAL(0, handle); + + TEST_ASSERT_EQUAL_HEX(TEST_REGION_START, spi_flash_cache2phys(ptr)); + TEST_ASSERT_EQUAL_HEX(TEST_REGION_START + 1024, spi_flash_cache2phys((void *)((intptr_t)ptr + 1024))); + TEST_ASSERT_EQUAL_HEX(TEST_REGION_START + 3000, spi_flash_cache2phys((void *)((intptr_t)ptr + 3000))); + /* this pointer lands in a different MMU table entry */ + TEST_ASSERT_EQUAL_HEX(TEST_REGION_START + test_size - 4, spi_flash_cache2phys((void *)((intptr_t)ptr + test_size - 4))); + + spi_flash_munmap(handle); + + TEST_ASSERT_EQUAL_HEX(SPI_FLASH_CACHE2PHYS_FAIL, spi_flash_cache2phys(ptr)); +} diff --git a/docs/api/storage/spi_flash.rst b/docs/api/storage/spi_flash.rst index f941a3888..4bf5e37a9 100644 --- a/docs/api/storage/spi_flash.rst +++ b/docs/api/storage/spi_flash.rst @@ -26,6 +26,7 @@ Macros .. doxygendefine:: SPI_FLASH_SEC_SIZE .. doxygendefine:: SPI_FLASH_MMU_PAGE_SIZE .. doxygendefine:: ESP_PARTITION_SUBTYPE_OTA +.. doxygendefine:: SPI_FLASH_CACHE2PHYS_FAIL Type Definitions ^^^^^^^^^^^^^^^^ @@ -59,6 +60,8 @@ Functions .. doxygenfunction:: spi_flash_mmap .. doxygenfunction:: spi_flash_munmap .. doxygenfunction:: spi_flash_mmap_dump +.. doxygenfunction:: spi_flash_cache2phys +.. doxygenfunction:: spi_flash_phys2cache .. doxygenfunction:: esp_partition_find .. doxygenfunction:: esp_partition_find_first .. doxygenfunction:: esp_partition_get From 6a2d152086bec132ec014602827f2811f8f65713 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Mon, 20 Feb 2017 14:24:08 +1100 Subject: [PATCH 015/112] spi_flash tests: Refactor mmap tests to be run in any order --- components/spi_flash/test/test_mmap.c | 65 ++++++++++++++++++++------- 1 file changed, 48 insertions(+), 17 deletions(-) diff --git a/components/spi_flash/test/test_mmap.c b/components/spi_flash/test/test_mmap.c index 4bf3c5a45..facc1ffde 100644 --- a/components/spi_flash/test/test_mmap.c +++ b/components/spi_flash/test/test_mmap.c @@ -19,33 +19,59 @@ static uint32_t buffer[1024]; static const uint32_t start = 0x100000; static const uint32_t end = 0x200000; +static spi_flash_mmap_handle_t handle1, handle2, handle3; -TEST_CASE("Prepare data for mmap tests", "[mmap]") +static void setup_mmap_tests() { + /* clean up any mmap handles left over from failed tests */ + if (handle1) { + spi_flash_munmap(handle1); + handle1 = 0; + } + if (handle2) { + spi_flash_munmap(handle2); + handle2 = 0; + } + if (handle3) { + spi_flash_munmap(handle3); + handle3 = 0; + } + + /* prepare flash contents */ srand(0); for (int block = start / 0x10000; block < end / 0x10000; ++block) { - printf("Writing block %d\n", block); for (int sector = 0; sector < 16; ++sector) { + uint32_t abs_sector = (block) * 16 + sector; + uint32_t sector_offs = abs_sector * SPI_FLASH_SEC_SIZE; + bool sector_needs_write = false; + + ESP_ERROR_CHECK( spi_flash_read(sector_offs, buffer, sizeof(buffer)) ); + for (uint32_t word = 0; word < 1024; ++word) { uint32_t val = rand(); if (block == start / 0x10000 && sector == 0 && word == 0) { - printf("first word: %08x\n", val); + printf("setup_mmap_tests(): first prepped word: %08x\n", val); + } + if (buffer[word] != val) { + buffer[word] = val; + sector_needs_write = true; } - buffer[word] = val; } - uint32_t abs_sector = (block) * 16 + sector; - printf("Writing sector %d\n", abs_sector); - ESP_ERROR_CHECK( spi_flash_erase_sector((uint16_t) abs_sector) ); - ESP_ERROR_CHECK( spi_flash_write(abs_sector * SPI_FLASH_SEC_SIZE, (const uint8_t *) buffer, sizeof(buffer)) ); + /* Only rewrite the sector if it has changed */ + if (sector_needs_write) { + printf("setup_mmap_tests(): Prepping sector %d\n", abs_sector); + ESP_ERROR_CHECK( spi_flash_erase_sector((uint16_t) abs_sector) ); + ESP_ERROR_CHECK( spi_flash_write(sector_offs, (const uint8_t *) buffer, sizeof(buffer)) ); + } } } } TEST_CASE("Can mmap into data address space", "[mmap]") { + setup_mmap_tests(); printf("Mapping %x (+%x)\n", start, end - start); - spi_flash_mmap_handle_t handle1; const void *ptr1; ESP_ERROR_CHECK( spi_flash_mmap(start, end - start, SPI_FLASH_MMAP_DATA, &ptr1, &handle1) ); printf("mmap_res: handle=%d ptr=%p\n", handle1, ptr1); @@ -62,19 +88,16 @@ TEST_CASE("Can mmap into data address space", "[mmap]") } } printf("Mapping %x (+%x)\n", start - 0x10000, 0x20000); - spi_flash_mmap_handle_t handle2; const void *ptr2; ESP_ERROR_CHECK( spi_flash_mmap(start - 0x10000, 0x20000, SPI_FLASH_MMAP_DATA, &ptr2, &handle2) ); printf("mmap_res: handle=%d ptr=%p\n", handle2, ptr2); TEST_ASSERT_EQUAL_HEX32(start - 0x10000, spi_flash_cache2phys(ptr2)); TEST_ASSERT_EQUAL_PTR(ptr2, spi_flash_phys2cache(start - 0x10000, SPI_FLASH_MMAP_DATA)); - TEST_ASSERT_EQUAL_PTR((intptr_t)ptr2 + 0x12000, spi_flash_phys2cache(start - 0x10000 + 0x12000, SPI_FLASH_MMAP_DATA)); spi_flash_mmap_dump(); printf("Mapping %x (+%x)\n", start, 0x10000); - spi_flash_mmap_handle_t handle3; const void *ptr3; ESP_ERROR_CHECK( spi_flash_mmap(start, 0x10000, SPI_FLASH_MMAP_DATA, &ptr3, &handle3) ); printf("mmap_res: handle=%d ptr=%p\n", handle3, ptr3); @@ -87,25 +110,29 @@ TEST_CASE("Can mmap into data address space", "[mmap]") printf("Unmapping handle1\n"); spi_flash_munmap(handle1); + handle1 = 0; spi_flash_mmap_dump(); printf("Unmapping handle2\n"); spi_flash_munmap(handle2); + handle2 = 0; spi_flash_mmap_dump(); printf("Unmapping handle3\n"); spi_flash_munmap(handle3); + handle3 = 0; TEST_ASSERT_EQUAL_PTR(NULL, spi_flash_phys2cache(start, SPI_FLASH_MMAP_DATA)); } TEST_CASE("flash_mmap invalidates just-written data", "[spi_flash]") { - spi_flash_mmap_handle_t handle1; const void *ptr1; const size_t test_size = 128; + setup_mmap_tests(); + if (esp_flash_encryption_enabled()) { TEST_IGNORE_MESSAGE("flash encryption enabled, spi_flash_write_encrypted() test won't pass as-is"); } @@ -123,6 +150,7 @@ TEST_CASE("flash_mmap invalidates just-written data", "[spi_flash]") /* unmap the erased region */ spi_flash_munmap(handle1); + handle1 = 0; /* write flash region to 0xEE */ uint8_t buf[test_size]; @@ -143,6 +171,7 @@ TEST_CASE("flash_mmap invalidates just-written data", "[spi_flash]") TEST_ASSERT_EQUAL_HEX8_ARRAY(buf, ptr1, test_size); spi_flash_munmap(handle1); + handle1 = 0; } TEST_CASE("phys2cache/cache2phys basic checks", "[spi_flash]") @@ -180,15 +209,16 @@ TEST_CASE("phys2cache/cache2phys basic checks", "[spi_flash]") TEST_CASE("mmap consistent with phys2cache/cache2phys", "[spi_flash]") { - spi_flash_mmap_handle_t handle = 0; const void *ptr = NULL; const size_t test_size = 2 * SPI_FLASH_MMU_PAGE_SIZE; + setup_mmap_tests(); + TEST_ASSERT_EQUAL_HEX(SPI_FLASH_CACHE2PHYS_FAIL, spi_flash_cache2phys(ptr)); - ESP_ERROR_CHECK( spi_flash_mmap(TEST_REGION_START, test_size, SPI_FLASH_MMAP_DATA, &ptr, &handle) ); + ESP_ERROR_CHECK( spi_flash_mmap(TEST_REGION_START, test_size, SPI_FLASH_MMAP_DATA, &ptr, &handle1) ); TEST_ASSERT_NOT_NULL(ptr); - TEST_ASSERT_NOT_EQUAL(0, handle); + TEST_ASSERT_NOT_EQUAL(0, handle1); TEST_ASSERT_EQUAL_HEX(TEST_REGION_START, spi_flash_cache2phys(ptr)); TEST_ASSERT_EQUAL_HEX(TEST_REGION_START + 1024, spi_flash_cache2phys((void *)((intptr_t)ptr + 1024))); @@ -196,7 +226,8 @@ TEST_CASE("mmap consistent with phys2cache/cache2phys", "[spi_flash]") /* this pointer lands in a different MMU table entry */ TEST_ASSERT_EQUAL_HEX(TEST_REGION_START + test_size - 4, spi_flash_cache2phys((void *)((intptr_t)ptr + test_size - 4))); - spi_flash_munmap(handle); + spi_flash_munmap(handle1); + handle1 = 0; TEST_ASSERT_EQUAL_HEX(SPI_FLASH_CACHE2PHYS_FAIL, spi_flash_cache2phys(ptr)); } From 25f739c183f4ace9b7e239ac15c02f6d020bc251 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Mon, 20 Feb 2017 14:02:39 +1100 Subject: [PATCH 016/112] ota ops: Add new functions esp_ota_get_next_update_partition / esp_ota_get_running_partition * Update OTA example to use these. * Refactor esp_ota_begin() to return ESP_ERR_OTA_PARTITION_CONFLICT as documented --- components/app_update/esp_ota_ops.c | 74 +++++++++++++++ components/app_update/include/esp_ota_ops.h | 40 +++++++- components/app_update/test/component.mk | 5 + components/app_update/test/test_ota_ops.c | 40 ++++++++ .../bootloader_support/src/esp_image_format.c | 10 ++ components/spi_flash/include/esp_partition.h | 2 +- docs/api/system/ota.rst | 2 + .../system/ota/main/{ota.c => ota_example.c} | 92 +++++++------------ 8 files changed, 201 insertions(+), 64 deletions(-) create mode 100644 components/app_update/test/component.mk create mode 100644 components/app_update/test/test_ota_ops.c rename examples/system/ota/main/{ota.c => ota_example.c} (78%) diff --git a/components/app_update/esp_ota_ops.c b/components/app_update/esp_ota_ops.c index efd697d07..ca46765c7 100644 --- a/components/app_update/esp_ota_ops.c +++ b/components/app_update/esp_ota_ops.c @@ -33,6 +33,7 @@ #include "esp_ota_ops.h" #include "rom/queue.h" #include "rom/crc.h" +#include "soc/dport_reg.h" #include "esp_log.h" @@ -75,6 +76,9 @@ esp_err_t esp_ota_begin(const esp_partition_t *partition, size_t image_size, esp if ((partition == NULL) || (out_handle == NULL)) { return ESP_ERR_INVALID_ARG; } + if (partition == esp_ota_get_running_partition()) { + return ESP_ERR_OTA_PARTITION_CONFLICT; + } ota_ops_entry_t *new_entry = (ota_ops_entry_t *) calloc(sizeof(ota_ops_entry_t), 1); @@ -446,3 +450,73 @@ const esp_partition_t *esp_ota_get_boot_partition(void) return esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL); } } + + +const esp_partition_t* esp_ota_get_running_partition(void) +{ + /* Find the flash address of this exact function. By definition that is part + of the currently running firmware. Then find the enclosing partition. */ + + size_t phys_offs = spi_flash_cache2phys(esp_ota_get_running_partition); + + assert (phys_offs != SPI_FLASH_CACHE2PHYS_FAIL); /* indicates cache2phys lookup is buggy */ + + esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_APP, + ESP_PARTITION_SUBTYPE_ANY, + NULL); + assert(it != NULL); /* has to be at least one app partition */ + + while (it != NULL) { + const esp_partition_t *p = esp_partition_get(it); + if (p->address <= phys_offs && p->address + p->size > phys_offs) { + esp_partition_iterator_release(it); + return p; + } + it = esp_partition_next(it); + } + esp_partition_iterator_release(it); + return NULL; +} + + +const esp_partition_t* esp_ota_get_next_update_partition(const esp_partition_t *start_from) +{ + const esp_partition_t *result = NULL; + bool next_is_result = false; + if (start_from == NULL) { + start_from = esp_ota_get_running_partition(); + } + assert (start_from != NULL); + + /* Two possibilities: either we want the OTA partition immediately after the + current running OTA partition, or we want the first OTA partition we see (for + the case when the last OTA partition is the running partition, or if the current + running partition is not OTA.) + */ + + esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_APP, + ESP_PARTITION_SUBTYPE_ANY, + NULL); + while (it != NULL) { + const esp_partition_t *p = esp_partition_get(it); + if(p->subtype >= ESP_PARTITION_SUBTYPE_APP_OTA_0 + && p->subtype < ESP_PARTITION_SUBTYPE_APP_OTA_MAX) { + /* is OTA partition */ + if (p == start_from || p->address == start_from->address) { + next_is_result = true; /* next OTA partition is the one */ + } + else if (next_is_result) { + result = p; /* this is it! */ + break; + } + else if (result == NULL) { + result = p; /* first OTA partition is the fallback */ + } + } + it = esp_partition_next(it); + } + + esp_partition_iterator_release(it); + return result; + +} diff --git a/components/app_update/include/esp_ota_ops.h b/components/app_update/include/esp_ota_ops.h index dbe53b9f4..8f99b2330 100755 --- a/components/app_update/include/esp_ota_ops.h +++ b/components/app_update/include/esp_ota_ops.h @@ -59,9 +59,10 @@ typedef uint32_t esp_ota_handle_t; * @return * - ESP_OK: OTA operation commenced successfully. - * - ESP_ERR_INVALID_ARG: partition or out_handle arguments were NULL. + * - ESP_ERR_INVALID_ARG: partition or out_handle arguments were NULL, or partition doesn't point to a non OTA app partition. * - ESP_ERR_NO_MEM: Cannot allocate memory for OTA operation. - * - ESP_ERR_OTA_PARTITION_CONFLICT: Partition is currently in use, cannot update. + * - ESP_ERR_OTA_PARTITION_CONFLICT: Partition holds the currently running firmware, cannot update in place. + * - ESP_ERR_NOT_FOUND: Partition argument not found in partition table. * - ESP_ERR_OTA_SELECT_INFO_INVALID: The OTA data partition contains invalid data. * - ESP_ERR_INVALID_SIZE: Partition doesn't fit in configured flash size. * - ESP_ERR_FLASH_OP_TIMEOUT or ESP_ERR_FLASH_OP_FAIL: Flash write failed. @@ -121,12 +122,45 @@ esp_err_t esp_ota_end(esp_ota_handle_t handle); esp_err_t esp_ota_set_boot_partition(const esp_partition_t* partition); /** - * @brief Get partition info of currently running app + * @brief Get partition info of currently configured boot app + * + * If esp_ota_set_boot_partition() has been called, the partition which was set by that function will be returned. + * + * If esp_ota_set_boot_partition() has not been called, the result is + * equivalent to esp_ota_get_running_partition(). * * @return Pointer to info for partition structure, or NULL if no partition is found or flash read operation failed. Returned pointer is valid for the lifetime of the application. */ const esp_partition_t* esp_ota_get_boot_partition(void); + +/** + * @brief Get partition info of currently running app + * + * This function is different to esp_ota_get_boot_partition() in that + * it ignores any change of selected boot partition caused by + * esp_ota_set_boot_partition(). Only the app whose code is currently + * running will have its partition information returned. + * + * @return Pointer to info for partition structure, or NULL if no partition is found or flash read operation failed. Returned pointer is valid for the lifetime of the application. + */ +const esp_partition_t* esp_ota_get_running_partition(void); + + +/** + * @brief Return the next OTA app partition which should be written with a new firmware. + * + * Call this function to find an OTA app partition which can be passed to esp_ota_begin(). + * + * Finds next partition round-robin, starting from the current running partition. + * + * @param start_from If set, treat this partition info as describing the current running partition. Can be NULL, in which case esp_ota_get_running_partition() is used to find the currently running partition. The result of this function is never the same as this argument. + * + * @return Pointer to info for partition which should be updated next. NULL result indicates invalid OTA data partition, or that no eligible OTA app slot partition was found. + * + */ +const esp_partition_t* esp_ota_get_next_update_partition(const esp_partition_t *start_from); + #ifdef __cplusplus } #endif diff --git a/components/app_update/test/component.mk b/components/app_update/test/component.mk new file mode 100644 index 000000000..5dd172bdb --- /dev/null +++ b/components/app_update/test/component.mk @@ -0,0 +1,5 @@ +# +#Component Makefile +# + +COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive diff --git a/components/app_update/test/test_ota_ops.c b/components/app_update/test/test_ota_ops.c new file mode 100644 index 000000000..c5bfc2ebe --- /dev/null +++ b/components/app_update/test/test_ota_ops.c @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include +#include + +#include +#include + + +/* These OTA tests currently don't assume an OTA partition exists + on the device, so they're a bit limited +*/ + +TEST_CASE("esp_ota_begin() verifies arguments", "[ota]") +{ + const esp_partition_t *running = esp_ota_get_running_partition(); + esp_partition_t partition; + static esp_ota_handle_t handle = 0; + + if (handle != 0) { /* clean up from any previous test */ + esp_ota_end(handle); + handle = 0; + } + + /* running partition & configured boot partition are same */ + TEST_ASSERT_NOT_NULL(running); + + /* trying to 'begin' on running partition fails */ + TEST_ASSERT_NOT_EQUAL(ESP_OK, esp_ota_begin(running, OTA_SIZE_UNKNOWN, &handle)); + TEST_ASSERT_EQUAL(0, handle); + + memcpy(&partition, running, sizeof(esp_partition_t)); + partition.address--; + + /* non existent partition fails */ + TEST_ASSERT_EQUAL_HEX(ESP_ERR_NOT_FOUND, esp_ota_begin(&partition, OTA_SIZE_UNKNOWN, &handle)); + TEST_ASSERT_EQUAL(0, handle); +} diff --git a/components/bootloader_support/src/esp_image_format.c b/components/bootloader_support/src/esp_image_format.c index 8b156680c..942ffd4bf 100644 --- a/components/bootloader_support/src/esp_image_format.c +++ b/components/bootloader_support/src/esp_image_format.c @@ -108,6 +108,16 @@ esp_err_t esp_image_basic_verify(uint32_t src_addr, bool log_errors, uint32_t *p *p_length = 0; } + if (src_addr % SPI_FLASH_MMU_PAGE_SIZE != 0) { + /* Image must start on a 64KB boundary + + (This is not a technical limitation, only the flash mapped regions need to be 64KB aligned. But the most + consistent way to do this is to have all the offsets internal to the image correctly 64KB aligned, and then + start the image on a 64KB boundary also.) + */ + return ESP_ERR_INVALID_ARG; + } + err = esp_image_load_header(src_addr, log_errors, &image_header); if (err != ESP_OK) { return err; diff --git a/components/spi_flash/include/esp_partition.h b/components/spi_flash/include/esp_partition.h index 28f8551dc..ba1327ab7 100644 --- a/components/spi_flash/include/esp_partition.h +++ b/components/spi_flash/include/esp_partition.h @@ -63,7 +63,7 @@ typedef enum { ESP_PARTITION_SUBTYPE_APP_OTA_13 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 13,//!< OTA partition 13 ESP_PARTITION_SUBTYPE_APP_OTA_14 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 14,//!< OTA partition 14 ESP_PARTITION_SUBTYPE_APP_OTA_15 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 15,//!< OTA partition 15 - ESP_PARTITION_SUBTYPE_APP_OTA_MAX = 15, //!< Max subtype of OTA partition + ESP_PARTITION_SUBTYPE_APP_OTA_MAX = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 16,//!< Max subtype of OTA partition ESP_PARTITION_SUBTYPE_APP_TEST = 0x20, //!< Test application partition ESP_PARTITION_SUBTYPE_DATA_OTA = 0x00, //!< OTA selection partition diff --git a/docs/api/system/ota.rst b/docs/api/system/ota.rst index 3fd0dd25c..eaabeae3a 100644 --- a/docs/api/system/ota.rst +++ b/docs/api/system/ota.rst @@ -71,5 +71,7 @@ Functions .. doxygenfunction:: esp_ota_begin .. doxygenfunction:: esp_ota_write .. doxygenfunction:: esp_ota_end +.. doxygenfunction:: esp_ota_get_running_partition .. doxygenfunction:: esp_ota_set_boot_partition .. doxygenfunction:: esp_ota_get_boot_partition +.. doxygenfunction:: esp_ota_get_next_update_partition diff --git a/examples/system/ota/main/ota.c b/examples/system/ota/main/ota_example.c similarity index 78% rename from examples/system/ota/main/ota.c rename to examples/system/ota/main/ota_example.c index 2dfda1c82..06ed81e63 100644 --- a/examples/system/ota/main/ota.c +++ b/examples/system/ota/main/ota_example.c @@ -33,17 +33,14 @@ static const char *TAG = "ota"; /*an ota data write buffer ready to write to the flash*/ -char ota_write_data[BUFFSIZE + 1] = { 0 }; +static char ota_write_data[BUFFSIZE + 1] = { 0 }; /*an packet receive buffer*/ -char text[BUFFSIZE + 1] = { 0 }; +static char text[BUFFSIZE + 1] = { 0 }; /* an image total length*/ -int binary_file_length = 0; +static int binary_file_length = 0; /*socket id*/ -int socket_id = -1; -char http_request[64] = {0}; -/* operate handle : uninitialized value is zero ,every ota begin would exponential growth*/ -esp_ota_handle_t out_handle = 0; -esp_partition_t operate_partition; +static int socket_id = -1; +static char http_request[64] = {0}; /* FreeRTOS event group to signal when we are connected & ready to make a request */ static EventGroupHandle_t wifi_event_group; @@ -109,7 +106,7 @@ static int read_until(char *buffer, char delim, int len) * return true if packet including \r\n\r\n that means http packet header finished,start to receive packet body * otherwise return false * */ -static bool read_past_http_header(char text[], int total_len, esp_ota_handle_t out_handle) +static bool read_past_http_header(char text[], int total_len, esp_ota_handle_t update_handle) { /* i means current position */ int i = 0, i_read_len = 0; @@ -122,7 +119,7 @@ static bool read_past_http_header(char text[], int total_len, esp_ota_handle_t o /*copy first http packet body to write buffer*/ memcpy(ota_write_data, &(text[i + 2]), i_write_len); - esp_err_t err = esp_ota_write( out_handle, (const void *)ota_write_data, i_write_len); + esp_err_t err = esp_ota_write( update_handle, (const void *)ota_write_data, i_write_len); if (err != ESP_OK) { ESP_LOGE(TAG, "Error: esp_ota_write failed! err=0x%x", err); return false; @@ -170,48 +167,6 @@ bool connect_to_http_server() return false; } -bool ota_init() -{ - esp_err_t err; - const esp_partition_t *esp_current_partition = esp_ota_get_boot_partition(); - if (esp_current_partition->type != ESP_PARTITION_TYPE_APP) { - ESP_LOGE(TAG, "Error: esp_current_partition->type != ESP_PARTITION_TYPE_APP"); - return false; - } - - esp_partition_t find_partition; - memset(&operate_partition, 0, sizeof(esp_partition_t)); - /*choose which OTA image should we write to*/ - switch (esp_current_partition->subtype) { - case ESP_PARTITION_SUBTYPE_APP_FACTORY: - find_partition.subtype = ESP_PARTITION_SUBTYPE_APP_OTA_0; - break; - case ESP_PARTITION_SUBTYPE_APP_OTA_0: - find_partition.subtype = ESP_PARTITION_SUBTYPE_APP_OTA_1; - break; - case ESP_PARTITION_SUBTYPE_APP_OTA_1: - find_partition.subtype = ESP_PARTITION_SUBTYPE_APP_OTA_0; - break; - default: - break; - } - find_partition.type = ESP_PARTITION_TYPE_APP; - - const esp_partition_t *partition = esp_partition_find_first(find_partition.type, find_partition.subtype, NULL); - assert(partition != NULL); - memset(&operate_partition, 0, sizeof(esp_partition_t)); - err = esp_ota_begin( partition, OTA_SIZE_UNKNOWN, &out_handle); - if (err != ESP_OK) { - ESP_LOGE(TAG, "esp_ota_begin failed err=0x%x!", err); - return false; - } else { - memcpy(&operate_partition, partition, sizeof(esp_partition_t)); - ESP_LOGI(TAG, "esp_ota_begin init OK"); - return true; - } - return false; -} - void __attribute__((noreturn)) task_fatal_error() { ESP_LOGE(TAG, "Exiting task due to fatal error..."); @@ -226,7 +181,19 @@ void __attribute__((noreturn)) task_fatal_error() void main_task(void *pvParameter) { esp_err_t err; + /* update handle : set by esp_ota_begin(), must be freed via esp_ota_end() */ + esp_ota_handle_t update_handle = 0 ; + const esp_partition_t *update_partition = NULL; + ESP_LOGI(TAG, "Starting OTA example..."); + + const esp_partition_t *configured = esp_ota_get_boot_partition(); + const esp_partition_t *running = esp_ota_get_running_partition(); + + assert(configured == running); /* fresh from reset, should be running from configured boot partition */ + ESP_LOGI(TAG, "Running partition type %d subtype %d (offset 0x%08x)", + configured->type, configured->subtype, configured->address); + /* Wait for the callback to set the CONNECTED_BIT in the event group. */ @@ -252,12 +219,17 @@ void main_task(void *pvParameter) ESP_LOGI(TAG, "Send GET request to server succeeded"); } - if ( ota_init() ) { - ESP_LOGI(TAG, "OTA Init succeeded"); - } else { - ESP_LOGE(TAG, "OTA Init failed"); + update_partition = esp_ota_get_next_update_partition(NULL); + ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%x", + update_partition->subtype, update_partition->address); + assert(update_partition != NULL); + + err = esp_ota_begin(update_partition, OTA_SIZE_UNKNOWN, &update_handle); + if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_ota_begin failed, error=%d", err); task_fatal_error(); } + ESP_LOGI(TAG, "esp_ota_begin succeeded"); bool resp_body_start = false, flag = true; /*deal with all receive packet*/ @@ -270,10 +242,10 @@ void main_task(void *pvParameter) task_fatal_error(); } else if (buff_len > 0 && !resp_body_start) { /*deal with response header*/ memcpy(ota_write_data, text, buff_len); - resp_body_start = read_past_http_header(text, buff_len, out_handle); + resp_body_start = read_past_http_header(text, buff_len, update_handle); } else if (buff_len > 0 && resp_body_start) { /*deal with response body*/ memcpy(ota_write_data, text, buff_len); - err = esp_ota_write( out_handle, (const void *)ota_write_data, buff_len); + err = esp_ota_write( update_handle, (const void *)ota_write_data, buff_len); if (err != ESP_OK) { ESP_LOGE(TAG, "Error: esp_ota_write failed! err=0x%x", err); task_fatal_error(); @@ -291,11 +263,11 @@ void main_task(void *pvParameter) ESP_LOGI(TAG, "Total Write binary data length : %d", binary_file_length); - if (esp_ota_end(out_handle) != ESP_OK) { + if (esp_ota_end(update_handle) != ESP_OK) { ESP_LOGE(TAG, "esp_ota_end failed!"); task_fatal_error(); } - err = esp_ota_set_boot_partition(&operate_partition); + err = esp_ota_set_boot_partition(update_partition); if (err != ESP_OK) { ESP_LOGE(TAG, "esp_ota_set_boot_partition failed! err=0x%x", err); task_fatal_error(); From 902382f622c77410bd05ee6720b51ffc1b707a59 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Mon, 20 Feb 2017 16:02:29 +1100 Subject: [PATCH 017/112] ota ops: Verify partition argument passed to esp_ota_begin() --- components/app_update/esp_ota_ops.c | 74 +++++++++++++------- components/app_update/include/esp_ota_ops.h | 2 +- components/spi_flash/include/esp_partition.h | 20 ++++++ components/spi_flash/partition.c | 22 ++++++ 4 files changed, 91 insertions(+), 27 deletions(-) diff --git a/components/app_update/esp_ota_ops.c b/components/app_update/esp_ota_ops.c index ca46765c7..f9d545767 100644 --- a/components/app_update/esp_ota_ops.c +++ b/components/app_update/esp_ota_ops.c @@ -43,7 +43,7 @@ typedef struct ota_ops_entry_ { uint32_t handle; - esp_partition_t part; + const esp_partition_t *part; uint32_t erased_size; uint32_t wrote_size; #ifdef CONFIG_FLASH_ENCRYPTION_ENABLED @@ -69,21 +69,35 @@ static ota_select s_ota_select[2]; const static char *TAG = "esp_ota_ops"; +/* Return true if this is an OTA app partition */ +static bool is_ota_partition(const esp_partition_t *p) +{ + return (p != NULL + && p->type == ESP_PARTITION_TYPE_APP + && p->subtype >= ESP_PARTITION_SUBTYPE_APP_OTA_0 + && p->subtype < ESP_PARTITION_SUBTYPE_APP_OTA_MAX); +} + esp_err_t esp_ota_begin(const esp_partition_t *partition, size_t image_size, esp_ota_handle_t *out_handle) { + ota_ops_entry_t *new_entry; esp_err_t ret = ESP_OK; if ((partition == NULL) || (out_handle == NULL)) { return ESP_ERR_INVALID_ARG; } - if (partition == esp_ota_get_running_partition()) { - return ESP_ERR_OTA_PARTITION_CONFLICT; + + partition = esp_partition_verify(partition); + if (partition == NULL) { + return ESP_ERR_NOT_FOUND; } - ota_ops_entry_t *new_entry = (ota_ops_entry_t *) calloc(sizeof(ota_ops_entry_t), 1); + if (!is_ota_partition(partition)) { + return ESP_ERR_INVALID_ARG; + } - if (new_entry == 0) { - return ESP_ERR_NO_MEM; + if (partition == esp_ota_get_running_partition()) { + return ESP_ERR_OTA_PARTITION_CONFLICT; } // If input image size is 0 or OTA_SIZE_UNKNOWN, erase entire partition @@ -94,11 +108,14 @@ esp_err_t esp_ota_begin(const esp_partition_t *partition, size_t image_size, esp } if (ret != ESP_OK) { - free(new_entry); - new_entry = NULL; return ret; } + new_entry = (ota_ops_entry_t *) calloc(sizeof(ota_ops_entry_t), 1); + if (new_entry == NULL) { + return ESP_ERR_NO_MEM; + } + LIST_INSERT_HEAD(&s_ota_ops_entries_head, new_entry, entries); if ((image_size == 0) || (image_size == OTA_SIZE_UNKNOWN)) { @@ -107,7 +124,7 @@ esp_err_t esp_ota_begin(const esp_partition_t *partition, size_t image_size, esp new_entry->erased_size = image_size; } - memcpy(&new_entry->part, partition, sizeof(esp_partition_t)); + new_entry->part = partition; new_entry->handle = ++s_ota_ops_last_handle; *out_handle = new_entry->handle; return ESP_OK; @@ -169,7 +186,7 @@ esp_err_t esp_ota_write(esp_ota_handle_t handle, const void *data, size_t size) } #endif - ret = esp_partition_write(&it->part, it->wrote_size, data_bytes, size); + ret = esp_partition_write(it->part, it->wrote_size, data_bytes, size); if(ret == ESP_OK){ it->wrote_size += size; } @@ -219,13 +236,13 @@ esp_err_t esp_ota_end(esp_ota_handle_t handle) } #endif - if (esp_image_basic_verify(it->part.address, true, &image_size) != ESP_OK) { + if (esp_image_basic_verify(it->part->address, true, &image_size) != ESP_OK) { ret = ESP_ERR_OTA_VALIDATE_FAILED; goto cleanup; } #ifdef CONFIG_SECURE_BOOT_ENABLED - ret = esp_secure_boot_verify_signature(it->part.address, image_size); + ret = esp_secure_boot_verify_signature(it->part->address, image_size); if (ret != ESP_OK) { ret = ESP_ERR_OTA_VALIDATE_FAILED; goto cleanup; @@ -474,8 +491,8 @@ const esp_partition_t* esp_ota_get_running_partition(void) } it = esp_partition_next(it); } - esp_partition_iterator_release(it); - return NULL; + + abort(); /* Partition table is invalid or corrupt */ } @@ -485,13 +502,16 @@ const esp_partition_t* esp_ota_get_next_update_partition(const esp_partition_t * bool next_is_result = false; if (start_from == NULL) { start_from = esp_ota_get_running_partition(); + } else { + start_from = esp_partition_verify(start_from); } assert (start_from != NULL); + /* at this point, 'start_from' points to actual partition table data in flash */ - /* Two possibilities: either we want the OTA partition immediately after the - current running OTA partition, or we want the first OTA partition we see (for - the case when the last OTA partition is the running partition, or if the current - running partition is not OTA.) + + /* Two possibilities: either we want the OTA partition immediately after the current running OTA partition, or we + want the first OTA partition in the table (for the case when the last OTA partition is the running partition, or + if the current running partition is not OTA.) */ esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_APP, @@ -499,19 +519,21 @@ const esp_partition_t* esp_ota_get_next_update_partition(const esp_partition_t * NULL); while (it != NULL) { const esp_partition_t *p = esp_partition_get(it); - if(p->subtype >= ESP_PARTITION_SUBTYPE_APP_OTA_0 - && p->subtype < ESP_PARTITION_SUBTYPE_APP_OTA_MAX) { - /* is OTA partition */ - if (p == start_from || p->address == start_from->address) { - next_is_result = true; /* next OTA partition is the one */ + if(is_ota_partition(p)) { + if (result == NULL) { + /* Default to first OTA partition we find, + will be used if nothing else matches */ + result = p; + } + + if (p == start_from) { + /* Next OTA partition is the one to use */ + next_is_result = true; } else if (next_is_result) { result = p; /* this is it! */ break; } - else if (result == NULL) { - result = p; /* first OTA partition is the fallback */ - } } it = esp_partition_next(it); } diff --git a/components/app_update/include/esp_ota_ops.h b/components/app_update/include/esp_ota_ops.h index 8f99b2330..33c03030a 100755 --- a/components/app_update/include/esp_ota_ops.h +++ b/components/app_update/include/esp_ota_ops.h @@ -59,7 +59,7 @@ typedef uint32_t esp_ota_handle_t; * @return * - ESP_OK: OTA operation commenced successfully. - * - ESP_ERR_INVALID_ARG: partition or out_handle arguments were NULL, or partition doesn't point to a non OTA app partition. + * - ESP_ERR_INVALID_ARG: partition or out_handle arguments were NULL, or partition doesn't point to an OTA app partition. * - ESP_ERR_NO_MEM: Cannot allocate memory for OTA operation. * - ESP_ERR_OTA_PARTITION_CONFLICT: Partition holds the currently running firmware, cannot update in place. * - ESP_ERR_NOT_FOUND: Partition argument not found in partition table. diff --git a/components/spi_flash/include/esp_partition.h b/components/spi_flash/include/esp_partition.h index ba1327ab7..f3d5a424a 100644 --- a/components/spi_flash/include/esp_partition.h +++ b/components/spi_flash/include/esp_partition.h @@ -165,6 +165,26 @@ esp_partition_iterator_t esp_partition_next(esp_partition_iterator_t iterator); */ void esp_partition_iterator_release(esp_partition_iterator_t iterator); +/** + * @brief Verify partition data + * + * Given a pointer to partition data, verify this partition exists in the partition table (all fields match.) + * + * This function is also useful to take partition data which may be in a RAM buffer and convert it to a pointer to the + * permanent partition data stored in flash. + * + * Pointers returned from this function can be compared directly to the address of any pointer returned from + * esp_partition_get(), as a test for equality. + * + * @param partition Pointer to partition data to verify. Must be non-NULL. All fields of this structure must match the + * partition table entry in flash for this function to return a successful match. + * + * @return + * - If partition not found, returns NULL. + * - If found, returns a pointer to the esp_partition_t structure in flash. This pointer is always valid for the lifetime of the application. + */ +const esp_partition_t *esp_partition_verify(const esp_partition_t *partition); + /** * @brief Read data from the partition * diff --git a/components/spi_flash/partition.c b/components/spi_flash/partition.c index 76036b305..58153cd7f 100644 --- a/components/spi_flash/partition.c +++ b/components/spi_flash/partition.c @@ -200,6 +200,28 @@ const esp_partition_t* esp_partition_get(esp_partition_iterator_t iterator) return iterator->info; } +const esp_partition_t *esp_partition_verify(const esp_partition_t *partition) +{ + assert(partition != NULL); + const char *label = (strlen(partition->label) > 0) ? partition->label : NULL; + esp_partition_iterator_t it = esp_partition_find(partition->type, + partition->subtype, + label); + while (it != NULL) { + const esp_partition_t *p = esp_partition_get(it); + /* Can't memcmp() whole structure here as padding contents may be different */ + if (p->address == partition->address + && partition->size == p->size + && partition->encrypted == p->encrypted) { + esp_partition_iterator_release(it); + return p; + } + it = esp_partition_next(it); + } + esp_partition_iterator_release(it); + return NULL; +} + esp_err_t esp_partition_read(const esp_partition_t* partition, size_t src_offset, void* dst, size_t size) { From 4170b8c32efd2278323cbf945825e6337680b6aa Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Mon, 20 Feb 2017 16:02:45 +1100 Subject: [PATCH 018/112] partition iterator: Free iterator when reaching end of linked list --- components/spi_flash/partition.c | 1 + 1 file changed, 1 insertion(+) diff --git a/components/spi_flash/partition.c b/components/spi_flash/partition.c index 58153cd7f..89ad9807e 100644 --- a/components/spi_flash/partition.c +++ b/components/spi_flash/partition.c @@ -85,6 +85,7 @@ esp_partition_iterator_t esp_partition_next(esp_partition_iterator_t it) assert(it); // iterator reached the end of linked list? if (it->next_item == NULL) { + esp_partition_iterator_release(it); return NULL; } _lock_acquire(&s_partition_list_lock); From f687725e97b10c85a561a3a71dc18d319243712e Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 21 Feb 2017 13:40:42 +1100 Subject: [PATCH 019/112] unit tests: Use a unit test app partition table, configure spi_flash to use data partition --- .../spi_flash/test/test_flash_encryption.c | 44 +++++++----- components/spi_flash/test/test_mmap.c | 69 +++++++++++-------- components/spi_flash/test/test_read_write.c | 36 ++++++---- components/spi_flash/test/test_spi_flash.c | 2 - .../components/unity/include/test_utils.h | 18 ++--- .../components/unity/test_utils.c | 25 +++++++ .../partition_table_unit_test_app.csv | 12 ++++ tools/unit-test-app/sdkconfig | 68 ++++++++++++++---- 8 files changed, 190 insertions(+), 84 deletions(-) rename components/spi_flash/test/test_config.h => tools/unit-test-app/components/unity/include/test_utils.h (63%) create mode 100644 tools/unit-test-app/components/unity/test_utils.c create mode 100644 tools/unit-test-app/partition_table_unit_test_app.csv diff --git a/components/spi_flash/test/test_flash_encryption.c b/components/spi_flash/test/test_flash_encryption.c index b8d8018ae..16579930c 100644 --- a/components/spi_flash/test/test_flash_encryption.c +++ b/components/spi_flash/test/test_flash_encryption.c @@ -4,23 +4,35 @@ #include #include +#include #include #include #include -#include "test_config.h" - static void test_encrypted_write(size_t offset, const uint8_t *data, size_t length); static void verify_erased_flash(size_t offset, size_t length); +static size_t start; + +static void setup_tests() +{ + if (start == 0) { + const esp_partition_t *part = get_test_data_partition(); + start = part->address; + printf("Test data partition @ 0x%x\n", start); + } +} + TEST_CASE("test 16 byte encrypted writes", "[spi_flash]") { + setup_tests(); + if (!esp_flash_encryption_enabled()) { TEST_IGNORE_MESSAGE("flash encryption disabled, skipping spi_flash_write_encrypted() tests"); } TEST_ASSERT_EQUAL_HEX(ESP_OK, - spi_flash_erase_sector(TEST_REGION_START / SPI_FLASH_SEC_SIZE)); + spi_flash_erase_sector(start / SPI_FLASH_SEC_SIZE)); uint8_t fortyeight_bytes[0x30]; // 0, 1, 2, 3, 4... 47 for(int i = 0; i < sizeof(fortyeight_bytes); i++) { @@ -29,38 +41,38 @@ TEST_CASE("test 16 byte encrypted writes", "[spi_flash]") /* Verify unaligned start or length fails */ TEST_ASSERT_EQUAL_HEX(ESP_ERR_INVALID_ARG, - spi_flash_write_encrypted(TEST_REGION_START+1, fortyeight_bytes, 32)); + spi_flash_write_encrypted(start+1, fortyeight_bytes, 32)); TEST_ASSERT_EQUAL_HEX(ESP_ERR_INVALID_SIZE, - spi_flash_write_encrypted(TEST_REGION_START, fortyeight_bytes, 15)); + spi_flash_write_encrypted(start, fortyeight_bytes, 15)); /* ensure nothing happened to the flash yet */ - verify_erased_flash(TEST_REGION_START, 0x20); + verify_erased_flash(start, 0x20); /* Write 32 byte block, this is the "normal" encrypted write */ - test_encrypted_write(TEST_REGION_START, fortyeight_bytes, 0x20); - verify_erased_flash(TEST_REGION_START + 0x20, 0x20); + test_encrypted_write(start, fortyeight_bytes, 0x20); + verify_erased_flash(start + 0x20, 0x20); /* Slip in an unaligned spi_flash_read_encrypted() test */ uint8_t buf[0x10]; - spi_flash_read_encrypted(TEST_REGION_START+0x10, buf, 0x10); + spi_flash_read_encrypted(start+0x10, buf, 0x10); TEST_ASSERT_EQUAL_HEX8_ARRAY(fortyeight_bytes+0x10, buf, 16); /* Write 16 bytes unaligned */ - test_encrypted_write(TEST_REGION_START + 0x30, fortyeight_bytes, 0x10); + test_encrypted_write(start + 0x30, fortyeight_bytes, 0x10); /* the 16 byte regions before and after the 16 bytes we just wrote should still be 0xFF */ - verify_erased_flash(TEST_REGION_START + 0x20, 0x10); - verify_erased_flash(TEST_REGION_START + 0x40, 0x10); + verify_erased_flash(start + 0x20, 0x10); + verify_erased_flash(start + 0x40, 0x10); /* Write 48 bytes starting at a 32-byte aligned offset */ - test_encrypted_write(TEST_REGION_START + 0x40, fortyeight_bytes, 0x30); + test_encrypted_write(start + 0x40, fortyeight_bytes, 0x30); /* 16 bytes after this write should still be 0xFF -unencrypted- */ - verify_erased_flash(TEST_REGION_START + 0x70, 0x10); + verify_erased_flash(start + 0x70, 0x10); /* Write 48 bytes starting at a 16-byte aligned offset */ - test_encrypted_write(TEST_REGION_START + 0x90, fortyeight_bytes, 0x30); + test_encrypted_write(start + 0x90, fortyeight_bytes, 0x30); /* 16 bytes after this write should still be 0xFF -unencrypted- */ - verify_erased_flash(TEST_REGION_START + 0x120, 0x10); + verify_erased_flash(start + 0x120, 0x10); } static void test_encrypted_write(size_t offset, const uint8_t *data, size_t length) diff --git a/components/spi_flash/test/test_mmap.c b/components/spi_flash/test/test_mmap.c index facc1ffde..a2ef0fd56 100644 --- a/components/spi_flash/test/test_mmap.c +++ b/components/spi_flash/test/test_mmap.c @@ -11,18 +11,27 @@ #include #include -#include "test_config.h" +#include "test_utils.h" static uint32_t buffer[1024]; -/* read-only region used for mmap tests */ -static const uint32_t start = 0x100000; -static const uint32_t end = 0x200000; +/* read-only region used for mmap tests, intialised in setup_mmap_tests() */ +static uint32_t start; +static uint32_t end; static spi_flash_mmap_handle_t handle1, handle2, handle3; static void setup_mmap_tests() { + if (start == 0) { + const esp_partition_t *part = get_test_data_partition(); + start = part->address; + end = part->address + part->size; + printf("Test data partition @ 0x%x - 0x%x\n", start, end); + } + TEST_ASSERT(end > start); + TEST_ASSERT(end - start >= 512*1024); + /* clean up any mmap handles left over from failed tests */ if (handle1) { spi_flash_munmap(handle1); @@ -41,7 +50,7 @@ static void setup_mmap_tests() srand(0); for (int block = start / 0x10000; block < end / 0x10000; ++block) { for (int sector = 0; sector < 16; ++sector) { - uint32_t abs_sector = (block) * 16 + sector; + uint32_t abs_sector = (block * 16) + sector; uint32_t sector_offs = abs_sector * SPI_FLASH_SEC_SIZE; bool sector_needs_write = false; @@ -50,7 +59,7 @@ static void setup_mmap_tests() for (uint32_t word = 0; word < 1024; ++word) { uint32_t val = rand(); if (block == start / 0x10000 && sector == 0 && word == 0) { - printf("setup_mmap_tests(): first prepped word: %08x\n", val); + printf("setup_mmap_tests(): first prepped word: 0x%08x (flash holds 0x%08x)\n", val, buffer[word]); } if (buffer[word] != val) { buffer[word] = val; @@ -67,7 +76,7 @@ static void setup_mmap_tests() } } -TEST_CASE("Can mmap into data address space", "[mmap]") +TEST_CASE("Can mmap into data address space", "[spi_flash]") { setup_mmap_tests(); @@ -81,9 +90,11 @@ TEST_CASE("Can mmap into data address space", "[mmap]") srand(0); const uint32_t *data = (const uint32_t *) ptr1; for (int block = 0; block < (end - start) / 0x10000; ++block) { + printf("block %d\n", block); for (int sector = 0; sector < 16; ++sector) { + printf("sector %d\n", sector); for (uint32_t word = 0; word < 1024; ++word) { - TEST_ASSERT_EQUAL_UINT32(rand(), data[(block * 16 + sector) * 1024 + word]); + TEST_ASSERT_EQUAL_HEX32(rand(), data[(block * 16 + sector) * 1024 + word]); } } } @@ -137,10 +148,10 @@ TEST_CASE("flash_mmap invalidates just-written data", "[spi_flash]") TEST_IGNORE_MESSAGE("flash encryption enabled, spi_flash_write_encrypted() test won't pass as-is"); } - ESP_ERROR_CHECK( spi_flash_erase_sector(TEST_REGION_START / SPI_FLASH_SEC_SIZE) ); + ESP_ERROR_CHECK( spi_flash_erase_sector(start / SPI_FLASH_SEC_SIZE) ); /* map erased test region to ptr1 */ - ESP_ERROR_CHECK( spi_flash_mmap(TEST_REGION_START, test_size, SPI_FLASH_MMAP_DATA, &ptr1, &handle1) ); + ESP_ERROR_CHECK( spi_flash_mmap(start, test_size, SPI_FLASH_MMAP_DATA, &ptr1, &handle1) ); printf("mmap_res ptr1: handle=%d ptr=%p\n", handle1, ptr1); /* verify it's all 0xFF */ @@ -155,14 +166,14 @@ TEST_CASE("flash_mmap invalidates just-written data", "[spi_flash]") /* write flash region to 0xEE */ uint8_t buf[test_size]; memset(buf, 0xEE, test_size); - ESP_ERROR_CHECK( spi_flash_write(TEST_REGION_START, buf, test_size) ); + ESP_ERROR_CHECK( spi_flash_write(start, buf, test_size) ); /* re-map the test region at ptr1. this is a fresh mmap call so should trigger a cache flush, ensuring we see the updated flash. */ - ESP_ERROR_CHECK( spi_flash_mmap(TEST_REGION_START, test_size, SPI_FLASH_MMAP_DATA, &ptr1, &handle1) ); + ESP_ERROR_CHECK( spi_flash_mmap(start, test_size, SPI_FLASH_MMAP_DATA, &ptr1, &handle1) ); printf("mmap_res ptr1 #2: handle=%d ptr=%p\n", handle1, ptr1); /* assert that ptr1 now maps to the new values on flash, @@ -176,7 +187,9 @@ TEST_CASE("flash_mmap invalidates just-written data", "[spi_flash]") TEST_CASE("phys2cache/cache2phys basic checks", "[spi_flash]") { - uint8_t buf_a[32], buf_b[32]; + uint8_t buf[64]; + + static const uint8_t constant_data[] = { 1, 2, 3, 7, 11, 16, 3, 88 }; /* esp_partition_find is in IROM */ uint32_t phys = spi_flash_cache2phys(esp_partition_find); @@ -184,27 +197,25 @@ TEST_CASE("phys2cache/cache2phys basic checks", "[spi_flash]") TEST_ASSERT_EQUAL_PTR(esp_partition_find, spi_flash_phys2cache(phys, SPI_FLASH_MMAP_INST)); TEST_ASSERT_EQUAL_PTR(NULL, spi_flash_phys2cache(phys, SPI_FLASH_MMAP_DATA)); - /* Read the flash @ 'phys' and compare it to the data we get via cache */ - memcpy(buf_a, esp_partition_find, sizeof(buf_a)); - spi_flash_read(phys, buf_b, sizeof(buf_b)); - TEST_ASSERT_EQUAL_HEX8_ARRAY(buf_a, buf_b, sizeof(buf_b)); + /* Read the flash @ 'phys' and compare it to the data we get via regular cache access */ + spi_flash_read(phys, buf, sizeof(buf)); + TEST_ASSERT_EQUAL_HEX32_ARRAY((void *)esp_partition_find, buf, sizeof(buf)/sizeof(uint32_t)); /* spi_flash_mmap is in IRAM */ printf("%p\n", spi_flash_mmap); TEST_ASSERT_EQUAL_HEX32(SPI_FLASH_CACHE2PHYS_FAIL, spi_flash_cache2phys(spi_flash_mmap)); - /* 'start' should be in DROM */ - phys = spi_flash_cache2phys(&start); + /* 'constant_data' should be in DROM */ + phys = spi_flash_cache2phys(&constant_data); TEST_ASSERT_NOT_EQUAL(SPI_FLASH_CACHE2PHYS_FAIL, phys); - TEST_ASSERT_EQUAL_PTR(&start, + TEST_ASSERT_EQUAL_PTR(&constant_data, spi_flash_phys2cache(phys, SPI_FLASH_MMAP_DATA)); TEST_ASSERT_EQUAL_PTR(NULL, spi_flash_phys2cache(phys, SPI_FLASH_MMAP_INST)); - /* Read the flash @ 'phys' and compare it to the data we get via cache */ - memcpy(buf_a, &start, sizeof(start)); - spi_flash_read(phys, buf_b, sizeof(start)); - TEST_ASSERT_EQUAL_HEX8_ARRAY(buf_a, buf_b, sizeof(start)); + /* Read the flash @ 'phys' and compare it to the data we get via normal cache access */ + spi_flash_read(phys, buf, sizeof(constant_data)); + TEST_ASSERT_EQUAL_HEX8_ARRAY(constant_data, buf, sizeof(constant_data)); } TEST_CASE("mmap consistent with phys2cache/cache2phys", "[spi_flash]") @@ -216,15 +227,15 @@ TEST_CASE("mmap consistent with phys2cache/cache2phys", "[spi_flash]") TEST_ASSERT_EQUAL_HEX(SPI_FLASH_CACHE2PHYS_FAIL, spi_flash_cache2phys(ptr)); - ESP_ERROR_CHECK( spi_flash_mmap(TEST_REGION_START, test_size, SPI_FLASH_MMAP_DATA, &ptr, &handle1) ); + ESP_ERROR_CHECK( spi_flash_mmap(start, test_size, SPI_FLASH_MMAP_DATA, &ptr, &handle1) ); TEST_ASSERT_NOT_NULL(ptr); TEST_ASSERT_NOT_EQUAL(0, handle1); - TEST_ASSERT_EQUAL_HEX(TEST_REGION_START, spi_flash_cache2phys(ptr)); - TEST_ASSERT_EQUAL_HEX(TEST_REGION_START + 1024, spi_flash_cache2phys((void *)((intptr_t)ptr + 1024))); - TEST_ASSERT_EQUAL_HEX(TEST_REGION_START + 3000, spi_flash_cache2phys((void *)((intptr_t)ptr + 3000))); + TEST_ASSERT_EQUAL_HEX(start, spi_flash_cache2phys(ptr)); + TEST_ASSERT_EQUAL_HEX(start + 1024, spi_flash_cache2phys((void *)((intptr_t)ptr + 1024))); + TEST_ASSERT_EQUAL_HEX(start + 3000, spi_flash_cache2phys((void *)((intptr_t)ptr + 3000))); /* this pointer lands in a different MMU table entry */ - TEST_ASSERT_EQUAL_HEX(TEST_REGION_START + test_size - 4, spi_flash_cache2phys((void *)((intptr_t)ptr + test_size - 4))); + TEST_ASSERT_EQUAL_HEX(start + test_size - 4, spi_flash_cache2phys((void *)((intptr_t)ptr + test_size - 4))); spi_flash_munmap(handle1); handle1 = 0; diff --git a/components/spi_flash/test/test_read_write.c b/components/spi_flash/test/test_read_write.c index 37edbbb94..aca485032 100644 --- a/components/spi_flash/test/test_read_write.c +++ b/components/spi_flash/test/test_read_write.c @@ -21,16 +21,24 @@ #include #include +#include #include #include #include "../cache_utils.h" #include "soc/timer_group_struct.h" #include "soc/timer_group_reg.h" -#include "test_config.h" - /* Base offset in flash for tests. */ -#define FLASH_BASE TEST_REGION_START +static size_t start; + +static void setup_tests() +{ + if (start == 0) { + const esp_partition_t *part = get_test_data_partition(); + start = part->address; + printf("Test data partition @ 0x%x\n", start); + } +} #ifndef CONFIG_SPI_FLASH_MINIMAL_TEST #define CONFIG_SPI_FLASH_MINIMAL_TEST 1 @@ -66,21 +74,22 @@ static void IRAM_ATTR test_read(int src_off, int dst_off, int len) fprintf(stderr, "src=%d dst=%d len=%d\n", src_off, dst_off, len); memset(src_buf, 0xAA, sizeof(src_buf)); fill(((char *) src_buf) + src_off, src_off, len); - ESP_ERROR_CHECK(spi_flash_erase_sector((FLASH_BASE + src_off) / SPI_FLASH_SEC_SIZE)); + ESP_ERROR_CHECK(spi_flash_erase_sector((start + src_off) / SPI_FLASH_SEC_SIZE)); spi_flash_disable_interrupts_caches_and_other_cpu(); - SpiFlashOpResult rc = SPIWrite(FLASH_BASE, src_buf, sizeof(src_buf)); + SpiFlashOpResult rc = SPIWrite(start, src_buf, sizeof(src_buf)); spi_flash_enable_interrupts_caches_and_other_cpu(); TEST_ASSERT_EQUAL_INT(rc, SPI_FLASH_RESULT_OK); memset(dst_buf, 0x55, sizeof(dst_buf)); memset(dst_gold, 0x55, sizeof(dst_gold)); fill(dst_gold + dst_off, src_off, len); - ESP_ERROR_CHECK(spi_flash_read(FLASH_BASE + src_off, dst_buf + dst_off, len)); + ESP_ERROR_CHECK(spi_flash_read(start + src_off, dst_buf + dst_off, len)); TEST_ASSERT_EQUAL_INT(cmp_or_dump(dst_buf, dst_gold, sizeof(dst_buf)), 0); } TEST_CASE("Test spi_flash_read", "[spi_flash_read]") { + setup_tests(); #if CONFIG_SPI_FLASH_MINIMAL_TEST test_read(0, 0, 0); test_read(0, 0, 4); @@ -137,7 +146,7 @@ static void IRAM_ATTR test_write(int dst_off, int src_off, int len) memset(src_buf, 0x55, sizeof(src_buf)); fill(src_buf + src_off, src_off, len); // Fills with 0xff - ESP_ERROR_CHECK(spi_flash_erase_sector((FLASH_BASE + dst_off) / SPI_FLASH_SEC_SIZE)); + ESP_ERROR_CHECK(spi_flash_erase_sector((start + dst_off) / SPI_FLASH_SEC_SIZE)); memset(dst_gold, 0xff, sizeof(dst_gold)); if (len > 0) { int pad_left_off = (dst_off & ~3U); @@ -148,9 +157,9 @@ static void IRAM_ATTR test_write(int dst_off, int src_off, int len) } fill(dst_gold + dst_off, src_off, len); } - ESP_ERROR_CHECK(spi_flash_write(FLASH_BASE + dst_off, src_buf + src_off, len)); + ESP_ERROR_CHECK(spi_flash_write(start + dst_off, src_buf + src_off, len)); spi_flash_disable_interrupts_caches_and_other_cpu(); - SpiFlashOpResult rc = SPIRead(FLASH_BASE, dst_buf, sizeof(dst_buf)); + SpiFlashOpResult rc = SPIRead(start, dst_buf, sizeof(dst_buf)); spi_flash_enable_interrupts_caches_and_other_cpu(); TEST_ASSERT_EQUAL_INT(rc, SPI_FLASH_RESULT_OK); TEST_ASSERT_EQUAL_INT(cmp_or_dump(dst_buf, dst_gold, sizeof(dst_buf)), 0); @@ -158,6 +167,7 @@ static void IRAM_ATTR test_write(int dst_off, int src_off, int len) TEST_CASE("Test spi_flash_write", "[spi_flash_write]") { + setup_tests(); #if CONFIG_SPI_FLASH_MINIMAL_TEST test_write(0, 0, 0); test_write(0, 0, 4); @@ -202,8 +212,8 @@ TEST_CASE("Test spi_flash_write", "[spi_flash_write]") * NB: At the moment these only support aligned addresses, because memcpy * is not aware of the 32-but load requirements for these regions. */ - ESP_ERROR_CHECK(spi_flash_write(FLASH_BASE, (char *) 0x40000000, 16)); - ESP_ERROR_CHECK(spi_flash_write(FLASH_BASE, (char *) 0x40070000, 16)); - ESP_ERROR_CHECK(spi_flash_write(FLASH_BASE, (char *) 0x40078000, 16)); - ESP_ERROR_CHECK(spi_flash_write(FLASH_BASE, (char *) 0x40080000, 16)); + ESP_ERROR_CHECK(spi_flash_write(start, (char *) 0x40000000, 16)); + ESP_ERROR_CHECK(spi_flash_write(start, (char *) 0x40070000, 16)); + ESP_ERROR_CHECK(spi_flash_write(start, (char *) 0x40078000, 16)); + ESP_ERROR_CHECK(spi_flash_write(start, (char *) 0x40080000, 16)); } diff --git a/components/spi_flash/test/test_spi_flash.c b/components/spi_flash/test/test_spi_flash.c index 90d0cc1fd..008286a48 100644 --- a/components/spi_flash/test/test_spi_flash.c +++ b/components/spi_flash/test/test_spi_flash.c @@ -7,8 +7,6 @@ #include #include -#include "test_config.h" - struct flash_test_ctx { uint32_t offset; bool fail; diff --git a/components/spi_flash/test/test_config.h b/tools/unit-test-app/components/unity/include/test_utils.h similarity index 63% rename from components/spi_flash/test/test_config.h rename to tools/unit-test-app/components/unity/include/test_utils.h index 45e73661b..2fad41a10 100644 --- a/components/spi_flash/test/test_config.h +++ b/tools/unit-test-app/components/unity/include/test_utils.h @@ -1,4 +1,4 @@ -// Copyright 2010-2016 Espressif Systems (Shanghai) PTE LTD +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -11,14 +11,14 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. - -// Common header for SPI flash test data #pragma once -/* Define a region of flash we can mess up for testing... +// Utilities for esp-idf unit tests + +#include + +/* Return the 'flash_test' custom data partition (type 0x55) + defined in the custom partition table. +*/ +const esp_partition_t *get_test_data_partition(); - This is pretty ugly, better to do something with a partition but - this is OK for now. - */ -#define TEST_REGION_START 0x180000 -#define TEST_REGION_END 0x1E0000 diff --git a/tools/unit-test-app/components/unity/test_utils.c b/tools/unit-test-app/components/unity/test_utils.c new file mode 100644 index 000000000..416853a7f --- /dev/null +++ b/tools/unit-test-app/components/unity/test_utils.c @@ -0,0 +1,25 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "unity.h" +#include "test_utils.h" + +const esp_partition_t *get_test_data_partition() +{ + /* This user type/subtype (0x55) is set in + partition_table_unit_test_app.csv */ + const esp_partition_t *result = esp_partition_find_first(0x55, 0x55, NULL); + TEST_ASSERT_NOT_NULL(result); /* means partition table set wrong */ + return result; +} diff --git a/tools/unit-test-app/partition_table_unit_test_app.csv b/tools/unit-test-app/partition_table_unit_test_app.csv new file mode 100644 index 000000000..b6e57b4ed --- /dev/null +++ b/tools/unit-test-app/partition_table_unit_test_app.csv @@ -0,0 +1,12 @@ +# Special partition table for unit test app +# +# Name, Type, SubType, Offset, Size, Flags +# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +nvs, data, nvs, 0x9000, 0x4000 +otadata, data, ota, 0xd000, 0x2000 +phy_init, data, phy, 0xf000, 0x1000 +factory, 0, 0, 0x10000, 1M +ota_0, 0, ota_0, , 1M +ota_1, 0, ota_1, , 1M +# flash_test partition used for SPI flash tests +flash_test, 0x55, 0x55, , 512K diff --git a/tools/unit-test-app/sdkconfig b/tools/unit-test-app/sdkconfig index 14b31e0d1..2945dbaf6 100644 --- a/tools/unit-test-app/sdkconfig +++ b/tools/unit-test-app/sdkconfig @@ -21,12 +21,10 @@ CONFIG_LOG_BOOTLOADER_LEVEL_WARN=y CONFIG_LOG_BOOTLOADER_LEVEL=2 # -# Secure boot configuration +# Security features # -CONFIG_SECURE_BOOTLOADER_DISABLED=y -# CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH is not set -# CONFIG_SECURE_BOOTLOADER_REFLASHABLE is not set -# CONFIG_SECURE_BOOTLOADER_ENABLED is not set +# CONFIG_SECURE_BOOT_ENABLED is not set +# CONFIG_FLASH_ENCRYPTION_ENABLED is not set # # Serial flasher config @@ -56,39 +54,58 @@ CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y # CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set # CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set CONFIG_ESPTOOLPY_FLASHSIZE="2MB" +CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y +CONFIG_ESPTOOLPY_BEFORE_RESET=y +# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set +# CONFIG_ESPTOOLPY_BEFORE_ESP32R0 is not set +CONFIG_ESPTOOLPY_BEFORE="default_reset" +CONFIG_ESPTOOLPY_AFTER_RESET=y +# CONFIG_ESPTOOLPY_AFTER_NORESET is not set +CONFIG_ESPTOOLPY_AFTER="hard_reset" +# CONFIG_MONITOR_BAUD_9600B is not set +# CONFIG_MONITOR_BAUD_57600B is not set +CONFIG_MONITOR_BAUD_115200B=y +# CONFIG_MONITOR_BAUD_230400B is not set +# CONFIG_MONITOR_BAUD_921600B is not set +# CONFIG_MONITOR_BAUD_2MB is not set +# CONFIG_MONITOR_BAUD_OTHER is not set +CONFIG_MONITOR_BAUD_OTHER_VAL=115200 +CONFIG_MONITOR_BAUD=115200 # # Partition Table # -CONFIG_PARTITION_TABLE_SINGLE_APP=y +# CONFIG_PARTITION_TABLE_SINGLE_APP is not set # CONFIG_PARTITION_TABLE_TWO_OTA is not set -# CONFIG_PARTITION_TABLE_CUSTOM is not set -CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partition_table_unit_test_app.csv" CONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET=0x10000 -CONFIG_PARTITION_TABLE_FILENAME="partitions_singleapp.csv" +CONFIG_PARTITION_TABLE_FILENAME="partition_table_unit_test_app.csv" CONFIG_APP_OFFSET=0x10000 -CONFIG_PHY_DATA_OFFSET=0xf000 +CONFIG_PHY_DATA_OFFSET= CONFIG_OPTIMIZATION_LEVEL_DEBUG=y # CONFIG_OPTIMIZATION_LEVEL_RELEASE is not set # # Component config # -CONFIG_BTC_TASK_STACK_SIZE=2048 +# CONFIG_BT_ENABLED is not set CONFIG_BT_RESERVE_DRAM=0 # -# ESP32-specific config +# ESP32-specific # # CONFIG_ESP32_DEFAULT_CPU_FREQ_80 is not set # CONFIG_ESP32_DEFAULT_CPU_FREQ_160 is not set CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240 -# CONFIG_ESP32_ENABLE_STACK_WIFI is not set -# CONFIG_ESP32_ENABLE_STACK_BT is not set CONFIG_MEMMAP_SMP=y # CONFIG_MEMMAP_TRACEMEM is not set CONFIG_TRACEMEM_RESERVE_DRAM=0x0 +# CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH is not set +# CONFIG_ESP32_ENABLE_COREDUMP_TO_UART is not set +CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE=y +# CONFIG_ESP32_ENABLE_COREDUMP is not set CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32 CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2048 CONFIG_MAIN_TASK_STACK_SIZE=4096 @@ -115,8 +132,17 @@ CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1=y # CONFIG_ESP32_TIME_SYSCALL_USE_FRC1 is not set # CONFIG_ESP32_TIME_SYSCALL_USE_NONE is not set CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC=y +CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY=0 +CONFIG_WIFI_ENABLED=y +CONFIG_ESP32_WIFI_RX_BUFFER_NUM=10 +CONFIG_PHY_ENABLED=y + +# +# PHY +# CONFIG_ESP32_PHY_AUTO_INIT=y # CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION is not set +CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20 CONFIG_ESP32_PHY_MAX_TX_POWER=20 # CONFIG_ETHERNET is not set @@ -126,7 +152,6 @@ CONFIG_ESP32_PHY_MAX_TX_POWER=20 # CONFIG_FREERTOS_UNICORE is not set CONFIG_FREERTOS_CORETIMER_0=y # CONFIG_FREERTOS_CORETIMER_1 is not set -# CONFIG_FREERTOS_CORETIMER_2 is not set CONFIG_FREERTOS_HZ=1000 CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y # CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE is not set @@ -161,7 +186,13 @@ CONFIG_LOG_COLORS=y CONFIG_LWIP_MAX_SOCKETS=4 CONFIG_LWIP_THREAD_LOCAL_STORAGE_INDEX=0 # CONFIG_LWIP_SO_REUSE is not set +# CONFIG_LWIP_SO_RCVBUF is not set CONFIG_LWIP_DHCP_MAX_NTP_SERVERS=1 +# CONFIG_LWIP_IP_FRAG is not set +# CONFIG_LWIP_IP_REASSEMBLY is not set +CONFIG_TCP_MAXRTX=12 +CONFIG_TCP_SYNMAXRTX=6 +# CONFIG_LWIP_DHCP_DOES_ARP_CHECK is not set # # mbedTLS @@ -175,6 +206,13 @@ CONFIG_MBEDTLS_HARDWARE_SHA=y CONFIG_MBEDTLS_HAVE_TIME=y # CONFIG_MBEDTLS_HAVE_TIME_DATE is not set +# +# OpenSSL +# +# CONFIG_OPENSSL_DEBUG is not set +CONFIG_OPENSSL_ASSERT_DO_NOTHING=y +# CONFIG_OPENSSL_ASSERT_EXIT is not set + # # SPI Flash driver # From 080350a745b8e101675857c2843f83ec616260e0 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 21 Feb 2017 14:08:09 +1100 Subject: [PATCH 020/112] ota ops: Rewrite esp_ota_get_next_update_partition() to be more predictable, add unit tests --- components/app_update/esp_ota_ops.c | 49 ++++++++++++----------- components/app_update/test/test_ota_ops.c | 46 +++++++++++++++++++++ 2 files changed, 71 insertions(+), 24 deletions(-) diff --git a/components/app_update/esp_ota_ops.c b/components/app_update/esp_ota_ops.c index f9d545767..e8bfd01bc 100644 --- a/components/app_update/esp_ota_ops.c +++ b/components/app_update/esp_ota_ops.c @@ -498,7 +498,7 @@ const esp_partition_t* esp_ota_get_running_partition(void) const esp_partition_t* esp_ota_get_next_update_partition(const esp_partition_t *start_from) { - const esp_partition_t *result = NULL; + const esp_partition_t *default_ota = NULL; bool next_is_result = false; if (start_from == NULL) { start_from = esp_ota_get_running_partition(); @@ -512,33 +512,34 @@ const esp_partition_t* esp_ota_get_next_update_partition(const esp_partition_t * /* Two possibilities: either we want the OTA partition immediately after the current running OTA partition, or we want the first OTA partition in the table (for the case when the last OTA partition is the running partition, or if the current running partition is not OTA.) + + This loop iterates subtypes instead of using esp_partition_find, so we + get all OTA partitions in a known order (low slot to high slot). */ - esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_APP, - ESP_PARTITION_SUBTYPE_ANY, - NULL); - while (it != NULL) { - const esp_partition_t *p = esp_partition_get(it); - if(is_ota_partition(p)) { - if (result == NULL) { - /* Default to first OTA partition we find, - will be used if nothing else matches */ - result = p; - } - - if (p == start_from) { - /* Next OTA partition is the one to use */ - next_is_result = true; - } - else if (next_is_result) { - result = p; /* this is it! */ - break; - } + for (esp_partition_subtype_t t = ESP_PARTITION_SUBTYPE_APP_OTA_0; + t != ESP_PARTITION_SUBTYPE_APP_OTA_MAX; + t++) { + const esp_partition_t *p = esp_partition_find_first(ESP_PARTITION_TYPE_APP, t, NULL); + if (p == NULL) { + continue; + } + + if (default_ota == NULL) { + /* Default to first OTA partition we find, + will be used if nothing else matches */ + default_ota = p; + } + + if (p == start_from) { + /* Next OTA partition is the one to use */ + next_is_result = true; + } + else if (next_is_result) { + return p; } - it = esp_partition_next(it); } - esp_partition_iterator_release(it); - return result; + return default_ota; } diff --git a/components/app_update/test/test_ota_ops.c b/components/app_update/test/test_ota_ops.c index c5bfc2ebe..e0a7864b5 100644 --- a/components/app_update/test/test_ota_ops.c +++ b/components/app_update/test/test_ota_ops.c @@ -6,6 +6,7 @@ #include #include +#include #include @@ -38,3 +39,48 @@ TEST_CASE("esp_ota_begin() verifies arguments", "[ota]") TEST_ASSERT_EQUAL_HEX(ESP_ERR_NOT_FOUND, esp_ota_begin(&partition, OTA_SIZE_UNKNOWN, &handle)); TEST_ASSERT_EQUAL(0, handle); } + +TEST_CASE("esp_ota_get_next_update_partition logic", "[ota]") +{ + const esp_partition_t *running = esp_ota_get_running_partition(); + const esp_partition_t *factory = esp_partition_find_first(ESP_PARTITION_TYPE_APP, + ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL); + const esp_partition_t *ota_0 = esp_partition_find_first(ESP_PARTITION_TYPE_APP, + ESP_PARTITION_SUBTYPE_APP_OTA_0, NULL); + const esp_partition_t *ota_1 = esp_partition_find_first(ESP_PARTITION_TYPE_APP, + ESP_PARTITION_SUBTYPE_APP_OTA_1, NULL); + const esp_partition_t *ota_2 = esp_partition_find_first(ESP_PARTITION_TYPE_APP, + ESP_PARTITION_SUBTYPE_APP_OTA_2, NULL); + + TEST_ASSERT_NOT_NULL(running); + TEST_ASSERT_NOT_NULL(factory); + TEST_ASSERT_NOT_NULL(ota_0); + TEST_ASSERT_NOT_NULL(ota_1); + TEST_ASSERT_NULL(ota_2); /* this partition shouldn't exist in test partition table */ + + TEST_ASSERT_EQUAL_PTR(factory, running); /* this may not be true if/when we get OTA tests that do OTA updates */ + + /* (The test steps verify subtypes before verifying pointer equality, because the failure messages are more readable + this way.) + */ + + /* Factory app OTA updates OTA 0 slot */ + const esp_partition_t *p = esp_ota_get_next_update_partition(NULL); + TEST_ASSERT_EQUAL_HEX8(ESP_PARTITION_SUBTYPE_APP_OTA_0, p->subtype); + TEST_ASSERT_EQUAL_PTR(ota_0, p); + + p = esp_ota_get_next_update_partition(factory); + TEST_ASSERT_EQUAL_HEX8(ESP_PARTITION_SUBTYPE_APP_OTA_0, p->subtype); + TEST_ASSERT_EQUAL_PTR(ota_0, p); + + + /* OTA slot 0 updates OTA slot 1 */ + p = esp_ota_get_next_update_partition(ota_0); + TEST_ASSERT_EQUAL_HEX8(ESP_PARTITION_SUBTYPE_APP_OTA_1, p->subtype); + TEST_ASSERT_EQUAL_PTR(ota_1, p); + /* OTA slot 1 updates OTA slot 0 */ + p = esp_ota_get_next_update_partition(ota_1); + TEST_ASSERT_EQUAL_HEX8(ESP_PARTITION_SUBTYPE_APP_OTA_0, p->subtype);; + TEST_ASSERT_EQUAL_PTR(ota_0, p); +} + From c3d5f8e7668aae97de48bf13e72f5dcb4ecce66b Mon Sep 17 00:00:00 2001 From: Tian Zhong Xing Date: Mon, 20 Feb 2017 18:09:32 +0800 Subject: [PATCH 021/112] app_update: fix logic error when update ota info --- components/app_update/esp_ota_ops.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/app_update/esp_ota_ops.c b/components/app_update/esp_ota_ops.c index e8bfd01bc..96e32cecf 100644 --- a/components/app_update/esp_ota_ops.c +++ b/components/app_update/esp_ota_ops.c @@ -342,9 +342,9 @@ static esp_err_t esp_rewrite_ota_data(esp_partition_subtype_t subtype) } if (s_ota_select[0].ota_seq >= s_ota_select[1].ota_seq) { - return rewrite_ota_seq((SUB_TYPE_ID(subtype) + 1) % ota_app_count + i * ota_app_count, 0, find_partition); - } else { return rewrite_ota_seq((SUB_TYPE_ID(subtype) + 1) % ota_app_count + i * ota_app_count, 1, find_partition); + } else { + return rewrite_ota_seq((SUB_TYPE_ID(subtype) + 1) % ota_app_count + i * ota_app_count, 0, find_partition); } } else if (ota_select_valid(&s_ota_select[0])) { From cc13b0ea058e81d8f893d4883bd6818ba36b7f2c Mon Sep 17 00:00:00 2001 From: Wangjialin Date: Tue, 24 Jan 2017 12:32:30 +0800 Subject: [PATCH 022/112] deep sleep: allow wakeup from touch sensor interrupt --- components/esp32/deep_sleep.c | 6 ++++++ components/esp32/include/esp_deep_sleep.h | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/components/esp32/deep_sleep.c b/components/esp32/deep_sleep.c index 4d672402e..1c2b60361 100644 --- a/components/esp32/deep_sleep.c +++ b/components/esp32/deep_sleep.c @@ -177,6 +177,12 @@ esp_err_t esp_deep_sleep_enable_timer_wakeup(uint64_t time_in_us) return ESP_OK; } +esp_err_t esp_deep_sleep_enable_touchpad_wakeup() +{ + s_config.wakeup_triggers |= TOUCH_TRIG_EN; + return ESP_OK; +} + esp_err_t esp_deep_sleep_enable_ext0_wakeup(gpio_num_t gpio_num, int level) { if (level < 0 || level > 1) { diff --git a/components/esp32/include/esp_deep_sleep.h b/components/esp32/include/esp_deep_sleep.h index aba74b30d..fda075eb2 100644 --- a/components/esp32/include/esp_deep_sleep.h +++ b/components/esp32/include/esp_deep_sleep.h @@ -68,6 +68,13 @@ esp_err_t esp_deep_sleep_enable_ulp_wakeup(); */ esp_err_t esp_deep_sleep_enable_timer_wakeup(uint64_t time_in_us); +/** + * @brief Enable wakeup by touch sensor + * @return + * - ESP_OK on success + */ +esp_err_t esp_deep_sleep_enable_touchpad_wakeup(); + /** * @brief Enable wakeup using a pin * From fb261c0bd5f118d3d7298332594f705e3855ac3a Mon Sep 17 00:00:00 2001 From: Wangjialin Date: Tue, 24 Jan 2017 15:53:59 +0800 Subject: [PATCH 023/112] 1. deal with conflicting wakeup triggers 2. modify deep_sleep.rst, add description of touch wakeup. --- components/esp32/deep_sleep.c | 17 ++++++++++++++++- components/esp32/include/esp_deep_sleep.h | 7 ++++++- docs/api/system/deep_sleep.rst | 9 +++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/components/esp32/deep_sleep.c b/components/esp32/deep_sleep.c index 1c2b60361..2b76025e0 100644 --- a/components/esp32/deep_sleep.c +++ b/components/esp32/deep_sleep.c @@ -163,6 +163,10 @@ void system_deep_sleep(uint64_t) __attribute__((alias("esp_deep_sleep"))); esp_err_t esp_deep_sleep_enable_ulp_wakeup() { #ifdef CONFIG_ULP_COPROC_ENABLED + if(s_config.wakeup_triggers & RTC_TOUCH_TRIG_EN) { + ESP_LOGE(TAG, "Conflict wake-up triggers: touch"); + return ESP_ERR_INVALID_STATE; + } s_config.wakeup_triggers |= RTC_SAR_TRIG_EN; return ESP_OK; #else @@ -179,7 +183,11 @@ esp_err_t esp_deep_sleep_enable_timer_wakeup(uint64_t time_in_us) esp_err_t esp_deep_sleep_enable_touchpad_wakeup() { - s_config.wakeup_triggers |= TOUCH_TRIG_EN; + if (s_config.wakeup_triggers & (RTC_SAR_TRIG_EN | RTC_EXT_EVENT0_TRIG_EN)) { + ESP_LOGE(TAG, "Conflict wake-up triggers: ulp/ext0"); + return ESP_ERR_INVALID_STATE; + } + s_config.wakeup_triggers |= RTC_TOUCH_TRIG_EN; return ESP_OK; } @@ -191,6 +199,10 @@ esp_err_t esp_deep_sleep_enable_ext0_wakeup(gpio_num_t gpio_num, int level) if (!RTC_GPIO_IS_VALID_GPIO(gpio_num)) { return ESP_ERR_INVALID_ARG; } + if (s_config.wakeup_triggers & RTC_TOUCH_TRIG_EN) { + ESP_LOGE(TAG, "Conflict wake-up triggers: touch"); + return ESP_ERR_INVALID_STATE; + } s_config.ext0_rtc_gpio_num = rtc_gpio_desc[gpio_num].rtc_num; s_config.ext0_trigger_level = level; s_config.wakeup_triggers |= RTC_EXT_EVENT0_TRIG_EN; @@ -346,6 +358,9 @@ static uint32_t get_power_down_flags() if (s_config.wakeup_triggers & (RTC_SAR_TRIG_EN | RTC_EXT_EVENT0_TRIG_EN)) { s_config.pd_options[ESP_PD_DOMAIN_RTC_PERIPH] = ESP_PD_OPTION_ON; + } else if (s_config.wakeup_triggers & RTC_TOUCH_TRIG_EN) { + // We have to set power down PERIPH so as to enable wake-up from touch sensor. + s_config.pd_options[ESP_PD_DOMAIN_RTC_PERIPH] = ESP_PD_OPTION_OFF; } } diff --git a/components/esp32/include/esp_deep_sleep.h b/components/esp32/include/esp_deep_sleep.h index fda075eb2..47a8a15aa 100644 --- a/components/esp32/include/esp_deep_sleep.h +++ b/components/esp32/include/esp_deep_sleep.h @@ -53,9 +53,10 @@ typedef enum { /** * @brief Enable wakeup by ULP coprocessor + * @note ulp wakeup conflicts with touch wakeup. * @return * - ESP_OK on success - * - ESP_ERR_INVALID_STATE if ULP co-processor is not enabled. + * - ESP_ERR_INVALID_STATE if ULP co-processor is not enabled or if wakeup triggers conflict */ esp_err_t esp_deep_sleep_enable_ulp_wakeup(); @@ -70,8 +71,10 @@ esp_err_t esp_deep_sleep_enable_timer_wakeup(uint64_t time_in_us); /** * @brief Enable wakeup by touch sensor + * @note Can not set touch wake-up if ulp or ext0 wake-up is enabled. * @return * - ESP_OK on success + * - ESP_ERR_INVALID_STATE if wakeup triggers conflict */ esp_err_t esp_deep_sleep_enable_touchpad_wakeup(); @@ -87,6 +90,7 @@ esp_err_t esp_deep_sleep_enable_touchpad_wakeup(); * @note This function does not modify pin configuration. The pin is * configured in esp_deep_sleep_start, immediately before * entering deep sleep. + * @note This ext0 wakeup conflicts with touch wakeup. * * @param gpio_num GPIO number used as wakeup source. Only GPIOs which are have RTC * functionality can be used: 0,2,4,12-15,25-27,32-39. @@ -95,6 +99,7 @@ esp_err_t esp_deep_sleep_enable_touchpad_wakeup(); * - ESP_OK on success * - ESP_ERR_INVALID_ARG if the selected GPIO is not an RTC GPIO, * or the mode is invalid + * - ESP_ERR_INVALID_STATE if wakeup triggers conflict */ esp_err_t esp_deep_sleep_enable_ext0_wakeup(gpio_num_t gpio_num, int level); diff --git a/docs/api/system/deep_sleep.rst b/docs/api/system/deep_sleep.rst index 87986026d..0b83062a4 100644 --- a/docs/api/system/deep_sleep.rst +++ b/docs/api/system/deep_sleep.rst @@ -26,6 +26,15 @@ The following function can be used to enable deep sleep wakeup using a timer. .. doxygenfunction:: esp_deep_sleep_enable_timer_wakeup +Touch pad +^^^^^ + +RTC IO module contains logic to trigger wakeup when a touch sensor interrupt occurs. You need to configure the touch pad interrupt before the chip starts deep sleep. + +Note that, for now, this wakeup requires RTC peripherals to be powered off during deep sleep. + +.. doxygenfunction:: esp_deep_sleep_enable_touchpad_wakeup + External wakeup (ext0) ^^^^^^^^^^^^^^^^^^^^^^ From 0483548a39bd5b9523d56b0bca37d07fbafd8f6b Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Thu, 26 Jan 2017 11:50:04 +0800 Subject: [PATCH 024/112] ulp: fix I_{RD,WR}_REG definitions - I_RD_REG used the wrong union member (.rd_reg) due to a copy-paste mistake - Peripheral register address in bits[7:0] should be given in words, not in bytes Fixes https://github.com/espressif/esp-idf/issues/297 --- components/ulp/include/esp32/ulp.h | 6 ++--- components/ulp/test/test_ulp.c | 39 ++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/components/ulp/include/esp32/ulp.h b/components/ulp/include/esp32/ulp.h index f4e37e924..66865c5b9 100644 --- a/components/ulp/include/esp32/ulp.h +++ b/components/ulp/include/esp32/ulp.h @@ -307,7 +307,7 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) { * This instruction can access RTC_CNTL_, RTC_IO_, and SENS_ peripheral registers. */ #define I_WR_REG(reg, low_bit, high_bit, val) {.wr_reg = {\ - .addr = reg & 0xff, \ + .addr = (reg & 0xff) / sizeof(uint32_t), \ .periph_sel = SOC_REG_TO_ULP_PERIPH_SEL(reg), \ .data = val, \ .low = low_bit, \ @@ -320,8 +320,8 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) { * R0 = reg[high_bit : low_bit] * This instruction can access RTC_CNTL_, RTC_IO_, and SENS_ peripheral registers. */ -#define I_RD_REG(reg, low_bit, high_bit, val) {.wr_reg = {\ - .addr = reg & 0xff, \ +#define I_RD_REG(reg, low_bit, high_bit) {.rd_reg = {\ + .addr = (reg & 0xff) / sizeof(uint32_t), \ .periph_sel = SOC_REG_TO_ULP_PERIPH_SEL(reg), \ .unused = 0, \ .low = low_bit, \ diff --git a/components/ulp/test/test_ulp.c b/components/ulp/test/test_ulp.c index f04178623..7ee0dbf9f 100644 --- a/components/ulp/test/test_ulp.c +++ b/components/ulp/test/test_ulp.c @@ -121,6 +121,45 @@ TEST_CASE("ulp wakeup test", "[ulp][ignore]") esp_deep_sleep_start(); } +TEST_CASE("ulp can write and read peripheral registers", "[ulp]") +{ + assert(CONFIG_ULP_COPROC_RESERVE_MEM >= 260 && "this test needs ULP_COPROC_RESERVE_MEM option set in menuconfig"); + CLEAR_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN); + memset(RTC_SLOW_MEM, 0, CONFIG_ULP_COPROC_RESERVE_MEM); + REG_WRITE(RTC_CNTL_STORE1_REG, 0x89abcdef); + + const ulp_insn_t program[] = { + I_MOVI(R1, 64), + I_RD_REG(RTC_CNTL_STORE1_REG, 0, 15), + I_ST(R0, R1, 0), + I_RD_REG(RTC_CNTL_STORE1_REG, 4, 11), + I_ST(R0, R1, 1), + I_RD_REG(RTC_CNTL_STORE1_REG, 16, 31), + I_ST(R0, R1, 2), + I_RD_REG(RTC_CNTL_STORE1_REG, 20, 27), + I_ST(R0, R1, 3), + I_WR_REG(RTC_CNTL_STORE0_REG, 0, 7, 0x89), + I_WR_REG(RTC_CNTL_STORE0_REG, 8, 15, 0xab), + I_WR_REG(RTC_CNTL_STORE0_REG, 16, 23, 0xcd), + I_WR_REG(RTC_CNTL_STORE0_REG, 24, 31, 0xef), + I_LD(R0, R1, 4), + I_ADDI(R0, R0, 1), + I_ST(R0, R1, 4), + I_END(0) + }; + size_t size = sizeof(program)/sizeof(ulp_insn_t); + TEST_ESP_OK(ulp_process_macros_and_load(0, program, &size)); + TEST_ESP_OK(ulp_run(0)); + vTaskDelay(100/portTICK_PERIOD_MS); + + TEST_ASSERT_EQUAL_HEX32(0xefcdab89, REG_READ(RTC_CNTL_STORE0_REG)); + TEST_ASSERT_EQUAL_HEX16(0xcdef, RTC_SLOW_MEM[64] & 0xffff); + TEST_ASSERT_EQUAL_HEX16(0xde, RTC_SLOW_MEM[65] & 0xffff); + TEST_ASSERT_EQUAL_HEX16(0x89ab, RTC_SLOW_MEM[66] & 0xffff); + TEST_ASSERT_EQUAL_HEX16(0x9a, RTC_SLOW_MEM[67] & 0xffff); + TEST_ASSERT_EQUAL_HEX32(1 | (15 << 21) | (1 << 16), RTC_SLOW_MEM[68]); +} + TEST_CASE("ulp controls RTC_IO", "[ulp][ignore]") { assert(CONFIG_ULP_COPROC_RESERVE_MEM >= 260 && "this test needs ULP_COPROC_RESERVE_MEM option set in menuconfig"); From 611e510c4993b9eff3e977461e9355a367200700 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 20 Feb 2017 15:44:29 +0800 Subject: [PATCH 025/112] ulp: add I_SLEEP instruction and improve comments --- components/ulp/include/esp32/ulp.h | 31 +++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/components/ulp/include/esp32/ulp.h b/components/ulp/include/esp32/ulp.h index 66865c5b9..9620a5ac9 100644 --- a/components/ulp/include/esp32/ulp.h +++ b/components/ulp/include/esp32/ulp.h @@ -271,7 +271,12 @@ _Static_assert(sizeof(ulp_insn_t) == 4, "ULP coprocessor instruction size should .cycles = cycles_ } } /** - * Halt the coprocessor + * Halt the coprocessor. + * + * This instruction halts the coprocessor, but keeps ULP timer active. + * As such, ULP program will be restarted again by timer. + * To stop the program and prevent the timer from restarting the program, + * use I_END(0) instruction. */ #define I_HALT() { .halt = {\ .unused = 0, \ @@ -331,7 +336,10 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) { /** * End program. * - * If wake == 1, wake up main CPU. + * This instruction halts the coprocessor, and disables the ULP timer. + * If wake == 1, the main CPU is woken up from deep sleep. + * To stop the program but allow it to be restarted by timer, use I_HALT() + * or I_SLEEP() instructions. */ #define I_END(wake) { .end = { \ .wakeup = wake, \ @@ -339,15 +347,28 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) { .sub_opcode = SUB_OPCODE_END, \ .opcode = OPCODE_END } } +/** + * End program and restart it after given amount of time. + * + * Time to restart the program is determined by the value of + * SENS_SLEEP_CYCLES_Sx register, where x == timer_idx. + * There are 5 SENS_SLEEP_CYCLES_Sx registers, so 0 <= timer_idx < 5. + */ +#define I_SLEEP(timer_idx) { .sleep = { \ + .cycle_sel = timer_idx, \ + .unused = 0, \ + .sub_opcode = SUB_OPCODE_SLEEP, \ + .opcode = OPCODE_END } } + /** * Store value from register reg_val into RTC memory. * * The value is written to an offset calculated by adding value of * reg_addr register and offset_ field (this offset is expressed in 32-bit words). * 32 bits written to RTC memory are built as follows: - * - 5 MSBs are zero - * - next 11 bits hold the PC of current instruction, expressed in 32-bit words - * - next 16 bits hold the actual value to be written + * - bits [31:21] hold the PC of current instruction, expressed in 32-bit words + * - bits [20:16] = 5'b1 + * - bits [15:0] are assigned the contents of reg_val * * RTC_SLOW_MEM[addr + offset_] = { 5'b0, insn_PC[10:0], val[15:0] } */ From 07ff47f1039c53075aad550e736c5c15bc5db2fd Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Fri, 27 Jan 2017 23:36:52 +0800 Subject: [PATCH 026/112] deep sleep: clarify compatibility issues between wakeup sources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ULP and touch FSMs in ESP32 revisions 0 and 1 do not operate correctly if RTC_PERIPH power domain is force powered on (ESP_PD_OPTION_ON). Both ULP and touch still work, but clock frequency of the ULP may be incorrect and touch values may be off by considerable amount. As such, when these wakeup modes are used, RTC_PERIPH power domain has to be set to ESP_PD_OPTION_AUTO (or, in the current implementation, ESP_PD_OPTION_OFF — though this will change in the future when _OFF will actually *force* the power domain to be powered off). Because EXT0 wakeup source requires RTC_PERIPH to be powered ON, mark ULP and touch wakeup sources as incompatible with EXT0. Workaround for this is to use EXT1 wakeup source instead, which offers similar or better functions without having to keep RTC_PERIPH powered on. --- components/esp32/deep_sleep.c | 25 +++++++++++------------ components/esp32/include/esp_deep_sleep.h | 16 ++++++++++++--- docs/api/system/deep_sleep.rst | 14 ++++++++----- 3 files changed, 34 insertions(+), 21 deletions(-) diff --git a/components/esp32/deep_sleep.c b/components/esp32/deep_sleep.c index 2b76025e0..c6785375d 100644 --- a/components/esp32/deep_sleep.c +++ b/components/esp32/deep_sleep.c @@ -163,8 +163,8 @@ void system_deep_sleep(uint64_t) __attribute__((alias("esp_deep_sleep"))); esp_err_t esp_deep_sleep_enable_ulp_wakeup() { #ifdef CONFIG_ULP_COPROC_ENABLED - if(s_config.wakeup_triggers & RTC_TOUCH_TRIG_EN) { - ESP_LOGE(TAG, "Conflict wake-up triggers: touch"); + if(s_config.wakeup_triggers & RTC_EXT_EVENT0_TRIG_EN) { + ESP_LOGE(TAG, "Conflicting wake-up trigger: ext0"); return ESP_ERR_INVALID_STATE; } s_config.wakeup_triggers |= RTC_SAR_TRIG_EN; @@ -183,8 +183,8 @@ esp_err_t esp_deep_sleep_enable_timer_wakeup(uint64_t time_in_us) esp_err_t esp_deep_sleep_enable_touchpad_wakeup() { - if (s_config.wakeup_triggers & (RTC_SAR_TRIG_EN | RTC_EXT_EVENT0_TRIG_EN)) { - ESP_LOGE(TAG, "Conflict wake-up triggers: ulp/ext0"); + if (s_config.wakeup_triggers & (RTC_EXT_EVENT0_TRIG_EN)) { + ESP_LOGE(TAG, "Conflicting wake-up trigger: ext0"); return ESP_ERR_INVALID_STATE; } s_config.wakeup_triggers |= RTC_TOUCH_TRIG_EN; @@ -199,8 +199,8 @@ esp_err_t esp_deep_sleep_enable_ext0_wakeup(gpio_num_t gpio_num, int level) if (!RTC_GPIO_IS_VALID_GPIO(gpio_num)) { return ESP_ERR_INVALID_ARG; } - if (s_config.wakeup_triggers & RTC_TOUCH_TRIG_EN) { - ESP_LOGE(TAG, "Conflict wake-up triggers: touch"); + if (s_config.wakeup_triggers & (RTC_TOUCH_TRIG_EN | RTC_SAR_TRIG_EN)) { + ESP_LOGE(TAG, "Conflicting wake-up triggers: touch / ULP"); return ESP_ERR_INVALID_STATE; } s_config.ext0_rtc_gpio_num = rtc_gpio_desc[gpio_num].rtc_num; @@ -351,15 +351,14 @@ static uint32_t get_power_down_flags() s_config.pd_options[ESP_PD_DOMAIN_RTC_FAST_MEM] = ESP_PD_OPTION_ON; } - // RTC_PERIPH is needed for EXT0 wakeup and for ULP. - // If RTC_PERIPH is auto, and both EXT0 and ULP aren't enabled, - // power down RTC_PERIPH. + // RTC_PERIPH is needed for EXT0 wakeup. + // If RTC_PERIPH is auto, and EXT0 isn't enabled, power down RTC_PERIPH. if (s_config.pd_options[ESP_PD_DOMAIN_RTC_PERIPH] == ESP_PD_OPTION_AUTO) { - if (s_config.wakeup_triggers & - (RTC_SAR_TRIG_EN | RTC_EXT_EVENT0_TRIG_EN)) { + if (s_config.wakeup_triggers & RTC_EXT_EVENT0_TRIG_EN) { s_config.pd_options[ESP_PD_DOMAIN_RTC_PERIPH] = ESP_PD_OPTION_ON; - } else if (s_config.wakeup_triggers & RTC_TOUCH_TRIG_EN) { - // We have to set power down PERIPH so as to enable wake-up from touch sensor. + } else if (s_config.wakeup_triggers & (RTC_TOUCH_TRIG_EN | RTC_SAR_TRIG_EN)) { + // In both rev. 0 and rev. 1 of ESP32, forcing power up of RTC_PERIPH + // prevents ULP timer and touch FSMs from working correctly. s_config.pd_options[ESP_PD_DOMAIN_RTC_PERIPH] = ESP_PD_OPTION_OFF; } } diff --git a/components/esp32/include/esp_deep_sleep.h b/components/esp32/include/esp_deep_sleep.h index 47a8a15aa..ed53b9496 100644 --- a/components/esp32/include/esp_deep_sleep.h +++ b/components/esp32/include/esp_deep_sleep.h @@ -53,7 +53,10 @@ typedef enum { /** * @brief Enable wakeup by ULP coprocessor - * @note ulp wakeup conflicts with touch wakeup. + * @note In revisions 0 and 1 of the ESP32, ULP wakeup source + * can not be used when RTC_PERIPH power domain is forced + * to be powered on (ESP_PD_OPTION_ON) or when ext0 wakeup + * source is used. * @return * - ESP_OK on success * - ESP_ERR_INVALID_STATE if ULP co-processor is not enabled or if wakeup triggers conflict @@ -71,7 +74,12 @@ esp_err_t esp_deep_sleep_enable_timer_wakeup(uint64_t time_in_us); /** * @brief Enable wakeup by touch sensor - * @note Can not set touch wake-up if ulp or ext0 wake-up is enabled. + * + * @note In revisions 0 and 1 of the ESP32, touch wakeup source + * can not be used when RTC_PERIPH power domain is forced + * to be powered on (ESP_PD_OPTION_ON) or when ext0 wakeup + * source is used. + * * @return * - ESP_OK on success * - ESP_ERR_INVALID_STATE if wakeup triggers conflict @@ -90,7 +98,9 @@ esp_err_t esp_deep_sleep_enable_touchpad_wakeup(); * @note This function does not modify pin configuration. The pin is * configured in esp_deep_sleep_start, immediately before * entering deep sleep. - * @note This ext0 wakeup conflicts with touch wakeup. + * + * @note In revisions 0 and 1 of the ESP32, ext0 wakeup source + * can not be used together with touch or ULP wakeup sources. * * @param gpio_num GPIO number used as wakeup source. Only GPIOs which are have RTC * functionality can be used: 0,2,4,12-15,25-27,32-39. diff --git a/docs/api/system/deep_sleep.rst b/docs/api/system/deep_sleep.rst index 0b83062a4..14904881a 100644 --- a/docs/api/system/deep_sleep.rst +++ b/docs/api/system/deep_sleep.rst @@ -31,7 +31,7 @@ Touch pad RTC IO module contains logic to trigger wakeup when a touch sensor interrupt occurs. You need to configure the touch pad interrupt before the chip starts deep sleep. -Note that, for now, this wakeup requires RTC peripherals to be powered off during deep sleep. +Revisions 0 and 1 of the ESP32 only support this wakeup mode when RTC peripherals are not forced to be powered on (i.e. ESP_PD_DOMAIN_RTC_PERIPH should be set to ESP_PD_OPTION_AUTO). .. doxygenfunction:: esp_deep_sleep_enable_touchpad_wakeup @@ -43,6 +43,8 @@ RTC IO module contains logic to trigger wakeup when one of RTC GPIOs is set to a Because RTC IO module is enabled in this mode, internal pullup or pulldown resistors can also be used. They need to be configured by the application using ``rtc_gpio_pullup_en`` and ``rtc_gpio_pulldown_en`` functions, before calling ``esp_deep_sleep_start``. +In revisions 0 and 1 of the ESP32, this wakeup source is incompatible with ULP and touch wakeup sources. + .. doxygenfunction:: esp_deep_sleep_enable_ext0_wakeup External wakeup (ext1) @@ -50,8 +52,8 @@ External wakeup (ext1) RTC controller contains logic to trigger wakeup using multiple RTC GPIOs. One of the two logic functions can be used to trigger wakeup: - - wake up if any of the selected pins is low - - wake up if all the selected pins are high + - wake up if any of the selected pins is high (``ESP_EXT1_WAKEUP_ANY_HIGH``) + - wake up if all the selected pins are low (``ESP_EXT1_WAKEUP_ALL_LOW``) This wakeup source is implemented by the RTC controller. As such, RTC peripherals and RTC memories can be powered off in this mode. However, if RTC peripherals are powered down, internal pullup and pulldown resistors will be disabled. To use internal pullup or pulldown resistors, request RTC peripherals power domain to be kept on during deep sleep, and configure pullup/pulldown resistors using ``rtc_gpio_`` functions, before entering deep sleep:: @@ -69,7 +71,9 @@ The following function can be used to enable this wakeup mode: ULP coprocessor wakeup ^^^^^^^^^^^^^^^^^^^^^^ -ULP coprocessor can run while the chip is in deep sleep, and may be used to poll sensors, monitor ADC or touch sensor values, and wake up the chip when a specific event is detected. ULP coprocessor is part of RTC peripherals power domain, and it runs the program stored in RTC slow memeory. Therefore RTC peripherals and RTC slow memory will be powered on during deep sleep if this wakeup mode is requested. +ULP coprocessor can run while the chip is in deep sleep, and may be used to poll sensors, monitor ADC or touch sensor values, and wake up the chip when a specific event is detected. ULP coprocessor is part of RTC peripherals power domain, and it runs the program stored in RTC slow memeory. RTC slow memory will be powered on during deep sleep if this wakeup mode is requested. RTC peripherals will be automatically powered on before ULP coprocessor starts running the program; once the program stops running, RTC peripherals are automatically powered down again. + +Revisions 0 and 1 of the ESP32 only support this wakeup mode when RTC peripherals are not forced to be powered on (i.e. ESP_PD_DOMAIN_RTC_PERIPH should be set to ESP_PD_OPTION_AUTO). The following function can be used to enable this wakeup mode: @@ -80,7 +84,7 @@ Power-down of RTC peripherals and memories By default, ``esp_deep_sleep_start`` function will power down all RTC power domains which are not needed by the enabled wakeup sources. To override this behaviour, the following function is provided: -Note: on the first revision of the ESP32, RTC fast memory will always be kept enabled in deep sleep, so that the deep sleep stub can run after reset. This can be overriden, if the application doesn't need clean reset behaviour after deep sleep. +Note: in revision 0 of the ESP32, RTC fast memory will always be kept enabled in deep sleep, so that the deep sleep stub can run after reset. This can be overriden, if the application doesn't need clean reset behaviour after deep sleep. If some variables in the program are placed into RTC slow memory (for example, using ``RTC_DATA_ATTR`` attribute), RTC slow memory will be kept powered on by default. This can be overriden using ``esp_deep_sleep_pd_config`` function, if desired. From a64181f14f3e0f48104b4c84eeaf7f9a1104160c Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Fri, 27 Jan 2017 23:48:00 +0800 Subject: [PATCH 027/112] deep sleep: add functions to check wakeup cause This change adds esp_deep_sleep_get_wakeup_cause, which returns the source which has caused wakeup from deep sleep. Similar to esp_deep_sleep_get_ext1_wakeup_status, a function is added to check touch pad wakeup status: esp_deep_sleep_get_touchpad_wakeup_status. This function returns the touch pad which has caused wakeup. --- components/esp32/deep_sleep.c | 35 +++++++++++++++++++++-- components/esp32/include/esp_deep_sleep.h | 31 ++++++++++++++++++++ docs/api/system/deep_sleep.rst | 13 ++++++++- 3 files changed, 76 insertions(+), 3 deletions(-) diff --git a/components/esp32/deep_sleep.c b/components/esp32/deep_sleep.c index c6785375d..aadb6067e 100644 --- a/components/esp32/deep_sleep.c +++ b/components/esp32/deep_sleep.c @@ -191,6 +191,16 @@ esp_err_t esp_deep_sleep_enable_touchpad_wakeup() return ESP_OK; } +touch_pad_t esp_deep_sleep_get_touchpad_wakeup_status() +{ + if (esp_deep_sleep_get_wakeup_cause() != ESP_DEEP_SLEEP_WAKEUP_TOUCHPAD) { + return TOUCH_PAD_MAX; + } + uint32_t touch_mask = REG_GET_FIELD(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_MEAS_EN); + assert(touch_mask != 0 && "wakeup reason is RTC_TOUCH_TRIG_EN but SENS_TOUCH_MEAS_EN is zero"); + return (touch_pad_t) (__builtin_ffs(touch_mask) - 1); +} + esp_err_t esp_deep_sleep_enable_ext0_wakeup(gpio_num_t gpio_num, int level) { if (level < 0 || level > 1) { @@ -294,8 +304,7 @@ static void ext1_wakeup_prepare() uint64_t esp_deep_sleep_get_ext1_wakeup_status() { - int wakeup_reason = REG_GET_FIELD(RTC_CNTL_WAKEUP_STATE_REG, RTC_CNTL_WAKEUP_CAUSE); - if (wakeup_reason != RTC_EXT_EVENT1_TRIG) { + if (esp_deep_sleep_get_wakeup_cause() != ESP_DEEP_SLEEP_WAKEUP_EXT1) { return 0; } uint32_t status = REG_GET_FIELD(RTC_CNTL_EXT_WAKEUP1_STATUS_REG, RTC_CNTL_EXT_WAKEUP1_STATUS); @@ -314,6 +323,28 @@ uint64_t esp_deep_sleep_get_ext1_wakeup_status() return gpio_mask; } +esp_deep_sleep_wakeup_cause_t esp_deep_sleep_get_wakeup_cause() +{ + if (rtc_get_reset_reason(0) != DEEPSLEEP_RESET) { + return ESP_DEEP_SLEEP_WAKEUP_UNDEFINED; + } + + uint32_t wakeup_cause = REG_GET_FIELD(RTC_CNTL_WAKEUP_STATE_REG, RTC_CNTL_WAKEUP_CAUSE); + if (wakeup_cause & RTC_EXT_EVENT0_TRIG) { + return ESP_DEEP_SLEEP_WAKEUP_EXT0; + } else if (wakeup_cause & RTC_EXT_EVENT1_TRIG) { + return ESP_DEEP_SLEEP_WAKEUP_EXT1; + } else if (wakeup_cause & RTC_TIMER_EXPIRE) { + return ESP_DEEP_SLEEP_WAKEUP_TIMER; + } else if (wakeup_cause & RTC_TOUCH_TRIG) { + return ESP_DEEP_SLEEP_WAKEUP_TOUCHPAD; + } else if (wakeup_cause & RTC_SAR_TRIG) { + return ESP_DEEP_SLEEP_WAKEUP_ULP; + } else { + return ESP_DEEP_SLEEP_WAKEUP_UNDEFINED; + } +} + esp_err_t esp_deep_sleep_pd_config(esp_deep_sleep_pd_domain_t domain, esp_deep_sleep_pd_option_t option) { diff --git a/components/esp32/include/esp_deep_sleep.h b/components/esp32/include/esp_deep_sleep.h index ed53b9496..61d3642b5 100644 --- a/components/esp32/include/esp_deep_sleep.h +++ b/components/esp32/include/esp_deep_sleep.h @@ -17,6 +17,7 @@ #include #include "esp_err.h" #include "driver/gpio.h" +#include "driver/touch_pad.h" #ifdef __cplusplus extern "C" { @@ -50,6 +51,18 @@ typedef enum { ESP_PD_OPTION_AUTO //!< Keep power domain enabled in deep sleep, if it is needed by one of the wakeup options. Otherwise power it down. } esp_deep_sleep_pd_option_t; +/** + * @brief Deep sleep wakeup cause + */ +typedef enum { + ESP_DEEP_SLEEP_WAKEUP_UNDEFINED, //! Wakeup was not caused by deep sleep + ESP_DEEP_SLEEP_WAKEUP_EXT0, //! Wakeup caused by external signal using RTC_IO + ESP_DEEP_SLEEP_WAKEUP_EXT1, //! Wakeup caused by external signal using RTC_CNTL + ESP_DEEP_SLEEP_WAKEUP_TIMER, //! Wakeup caused by timer + ESP_DEEP_SLEEP_WAKEUP_TOUCHPAD, //! Wakeup caused by touchpad + ESP_DEEP_SLEEP_WAKEUP_ULP, //! Wakeup caused by ULP program +} esp_deep_sleep_wakeup_cause_t; + /** * @brief Enable wakeup by ULP coprocessor @@ -86,6 +99,15 @@ esp_err_t esp_deep_sleep_enable_timer_wakeup(uint64_t time_in_us); */ esp_err_t esp_deep_sleep_enable_touchpad_wakeup(); +/** + * @brief Get the touch pad which caused wakeup + * + * If wakeup was caused by another source, this function will return TOUCH_PAD_MAX; + * + * @return touch pad which caused wakeup + */ +touch_pad_t esp_deep_sleep_get_touchpad_wakeup_status(); + /** * @brief Enable wakeup using a pin * @@ -210,6 +232,15 @@ void esp_deep_sleep(uint64_t time_in_us) __attribute__((noreturn)); */ void system_deep_sleep(uint64_t time_in_us) __attribute__((noreturn, deprecated)); + +/** + * @brief Get the source which caused deep sleep wakeup + * + * @return wakeup cause, or ESP_DEEP_SLEEP_WAKEUP_UNDEFINED if reset reason is other than deep sleep reset. + */ +esp_deep_sleep_wakeup_cause_t esp_deep_sleep_get_wakeup_cause(); + + /** * @brief Default stub to run on wake from deep sleep. * diff --git a/docs/api/system/deep_sleep.rst b/docs/api/system/deep_sleep.rst index 14904881a..aacb25218 100644 --- a/docs/api/system/deep_sleep.rst +++ b/docs/api/system/deep_sleep.rst @@ -27,7 +27,7 @@ The following function can be used to enable deep sleep wakeup using a timer. .. doxygenfunction:: esp_deep_sleep_enable_timer_wakeup Touch pad -^^^^^ +^^^^^^^^^ RTC IO module contains logic to trigger wakeup when a touch sensor interrupt occurs. You need to configure the touch pad interrupt before the chip starts deep sleep. @@ -100,6 +100,17 @@ The following function can be used to enter deep sleep once wakeup sources are c .. doxygenfunction:: esp_deep_sleep_start +Checking deep sleep wakeup cause +-------------------------------- + +The following function can be used to check which wakeup source has triggered wakeup from deep sleep mode. For touch pad and ext1 wakeup sources, it is possible to identify pin or touch pad which has caused wakeup. + +.. doxygenfunction:: esp_deep_sleep_get_wakeup_cause +.. doxygenenum:: esp_deep_sleep_wakeup_cause_t +.. doxygenfunction:: esp_deep_sleep_get_touchpad_wakeup_status +.. doxygenfunction:: esp_deep_sleep_get_ext1_wakeup_status + + Application Example ------------------- From dbf60eb9222e6a16cf00f0ddcb61c774fa62e5dd Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Fri, 27 Jan 2017 23:48:50 +0800 Subject: [PATCH 028/112] rtc: fix typo in RTC_CNTL_SLOWCLK_FREQ macro name --- components/esp32/include/soc/rtc_cntl_reg.h | 2 +- components/newlib/time.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/esp32/include/soc/rtc_cntl_reg.h b/components/esp32/include/soc/rtc_cntl_reg.h index d99cec186..40d65f21f 100644 --- a/components/esp32/include/soc/rtc_cntl_reg.h +++ b/components/esp32/include/soc/rtc_cntl_reg.h @@ -240,7 +240,7 @@ #define RTC_CNTL_TIME_VALID_S 30 /* frequency of RTC slow clock, Hz */ -#define RTC_CTNL_SLOWCLK_FREQ 150000 +#define RTC_CNTL_SLOWCLK_FREQ 150000 #define RTC_CNTL_TIME0_REG (DR_REG_RTCCNTL_BASE + 0x10) /* RTC_CNTL_TIME_LO : RO ;bitpos:[31:0] ;default: 32'h0 ; */ diff --git a/components/newlib/time.c b/components/newlib/time.c index 7595ab82b..fc7dec645 100644 --- a/components/newlib/time.c +++ b/components/newlib/time.c @@ -52,7 +52,7 @@ static uint64_t get_rtc_time_us() uint64_t low = READ_PERI_REG(RTC_CNTL_TIME0_REG); uint64_t high = READ_PERI_REG(RTC_CNTL_TIME1_REG); uint64_t ticks = (high << 32) | low; - return ticks * 100 / (RTC_CTNL_SLOWCLK_FREQ / 10000); // scale RTC_CTNL_SLOWCLK_FREQ to avoid overflow + return ticks * 100 / (RTC_CNTL_SLOWCLK_FREQ / 10000); // scale RTC_CNTL_SLOWCLK_FREQ to avoid overflow } #endif // WITH_RTC From d0d2c4cb49a3bedba4ed0655d13949feea70eb23 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 20 Feb 2017 15:44:49 +0800 Subject: [PATCH 029/112] esp32,ulp: add tests for TSENS --- components/esp32/test/test_tsens.c | 20 ++++++++++++ components/ulp/include/esp32/ulp.h | 14 +++++++- components/ulp/test/test_ulp.c | 52 ++++++++++++++++++++++++++++++ components/ulp/ulp.c | 3 ++ 4 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 components/esp32/test/test_tsens.c diff --git a/components/esp32/test/test_tsens.c b/components/esp32/test/test_tsens.c new file mode 100644 index 000000000..ff2660d1b --- /dev/null +++ b/components/esp32/test/test_tsens.c @@ -0,0 +1,20 @@ +#include +#include "unity.h" +#include "rom/ets_sys.h" +#include "soc/rtc_cntl_reg.h" +#include "soc/sens_reg.h" + +TEST_CASE("can control TSENS using registers", "[rtc][ignore]") +{ + SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR, 3, SENS_FORCE_XPD_SAR_S); + SET_PERI_REG_BITS(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_CLK_DIV, 10, SENS_TSENS_CLK_DIV_S); + CLEAR_PERI_REG_MASK(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_POWER_UP); + CLEAR_PERI_REG_MASK(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_DUMP_OUT); + SET_PERI_REG_MASK(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_POWER_UP_FORCE); + SET_PERI_REG_MASK(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_POWER_UP); + ets_delay_us(100); + SET_PERI_REG_MASK(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_DUMP_OUT); + ets_delay_us(5); + int res = GET_PERI_REG_BITS2(SENS_SAR_SLAVE_ADDR3_REG, SENS_TSENS_OUT, SENS_TSENS_OUT_S); + printf("res=%d\n", res); +} diff --git a/components/ulp/include/esp32/ulp.h b/components/ulp/include/esp32/ulp.h index 9620a5ac9..6d4bb18b1 100644 --- a/components/ulp/include/esp32/ulp.h +++ b/components/ulp/include/esp32/ulp.h @@ -222,7 +222,7 @@ typedef union { struct { uint32_t dreg : 2; /*!< Register where to store temperature measurement result */ uint32_t wait_delay: 14; /*!< Cycles to wait after measurement is done */ - uint32_t cycles: 12; /*!< Cycles used to perform measurement */ + uint32_t reserved: 12; /*!< Reserved, set to 0 */ uint32_t opcode: 4; /*!< Opcode (OPCODE_TSENS) */ } tsens; /*!< Format of TSENS instruction */ @@ -360,6 +360,18 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) { .sub_opcode = SUB_OPCODE_SLEEP, \ .opcode = OPCODE_END } } +/** + * Perform temperature sensor measurement and store it into reg_dest. + * + * Delay can be set between 1 and ((1 << 14) - 1). Higher values give + * higher measurement resolution. + */ +#define I_TSENS(reg_dest, delay) { .tsens = { \ + .dreg = reg_dest, \ + .wait_delay = delay, \ + .reserved = 0, \ + .opcode = OPCODE_TSENS } } + /** * Store value from register reg_val into RTC memory. * diff --git a/components/ulp/test/test_ulp.c b/components/ulp/test/test_ulp.c index 7ee0dbf9f..6a9d40253 100644 --- a/components/ulp/test/test_ulp.c +++ b/components/ulp/test/test_ulp.c @@ -207,3 +207,55 @@ TEST_CASE("ulp controls RTC_IO", "[ulp][ignore]") esp_deep_sleep_start(); } + +TEST_CASE("ulp can use TSENS in deep sleep", "[ulp][ignore]") +{ + assert(CONFIG_ULP_COPROC_RESERVE_MEM >= 260 && "this test needs ULP_COPROC_RESERVE_MEM option set in menuconfig"); + + hexdump(RTC_SLOW_MEM, CONFIG_ULP_COPROC_RESERVE_MEM / 4); + printf("\n\n"); + memset(RTC_SLOW_MEM, 0, CONFIG_ULP_COPROC_RESERVE_MEM); + + // Allow TSENS to be controlled by the ULP + SET_PERI_REG_BITS(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_CLK_DIV, 10, SENS_TSENS_CLK_DIV_S); + SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR, 3, SENS_FORCE_XPD_SAR_S); + CLEAR_PERI_REG_MASK(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_POWER_UP); + CLEAR_PERI_REG_MASK(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_DUMP_OUT); + CLEAR_PERI_REG_MASK(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_POWER_UP_FORCE); + + // data start offset + size_t offset = 20; + // number of samples to collect + RTC_SLOW_MEM[offset] = (CONFIG_ULP_COPROC_RESERVE_MEM) / 4 - offset - 8; + // sample counter + RTC_SLOW_MEM[offset + 1] = 0; + + const ulp_insn_t program[] = { + I_MOVI(R1, offset), // r1 <- offset + I_LD(R2, R1, 1), // r2 <- counter + I_LD(R3, R1, 0), // r3 <- length + I_SUBI(R3, R3, 1), // end = length - 1 + I_SUBR(R3, R3, R2), // r3 = length - counter + M_BXF(1), // if overflow goto 1: + I_WR_REG(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR_S, SENS_FORCE_XPD_SAR_S + 1, 3), + I_TSENS(R0, 16383), // r0 <- tsens + I_WR_REG(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR_S, SENS_FORCE_XPD_SAR_S + 1, 0), + I_ST(R0, R2, offset + 4), + I_ADDI(R2, R2, 1), // counter += 1 + I_ST(R2, R1, 1), // save counter + I_SLEEP(0), // enter sleep + I_HALT(), + M_LABEL(1), // done with measurements + I_END(0), // stop ULP timer + I_HALT() + }; + + size_t size = sizeof(program)/sizeof(ulp_insn_t); + TEST_ESP_OK(ulp_process_macros_and_load(0, program, &size)); + assert(offset >= size); + + TEST_ESP_OK(ulp_run(0)); + esp_deep_sleep_enable_timer_wakeup(4000000); + esp_deep_sleep_start(); +} + diff --git a/components/ulp/ulp.c b/components/ulp/ulp.c index 60fa292f7..424a468c3 100644 --- a/components/ulp/ulp.c +++ b/components/ulp/ulp.c @@ -271,6 +271,9 @@ esp_err_t ulp_run(uint32_t entry_point) CLEAR_PERI_REG_MASK(SENS_SAR_START_FORCE_REG, SENS_ULP_CP_FORCE_START_TOP_M); // make sure voltage is raised when RTC 8MCLK is enabled SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_I2C_FOLW_8M); + SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_CORE_FOLW_8M); + SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_SLEEP_FOLW_8M); + SET_PERI_REG_BITS(SENS_ULP_CP_SLEEP_CYC0_REG, SENS_SLEEP_CYCLES_S0, 1000, SENS_SLEEP_CYCLES_S0_S); // enable ULP timer SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN); return ESP_OK; From 7df75c00c706889ff990191379688f6eb6261ec7 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 20 Feb 2017 15:25:16 +0800 Subject: [PATCH 030/112] ulp: fix a bug that ULP may not be restarted correctly --- components/ulp/ulp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/ulp/ulp.c b/components/ulp/ulp.c index 424a468c3..c7ac15b49 100644 --- a/components/ulp/ulp.c +++ b/components/ulp/ulp.c @@ -265,6 +265,8 @@ esp_err_t ulp_run(uint32_t entry_point) { // disable ULP timer CLEAR_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN); + // wait for at least 1 RTC_SLOW_CLK cycle + ets_delay_us(10); // set entry point SET_PERI_REG_BITS(SENS_SAR_START_FORCE_REG, SENS_PC_INIT_V, entry_point, SENS_PC_INIT_S); // disable force start From cdf122baa0e75f6f8e7cd21da421c1778a72a7ba Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 20 Feb 2017 15:37:39 +0800 Subject: [PATCH 031/112] ulp: add I_WR_REG instruction test --- components/ulp/test/test_ulp.c | 54 ++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/components/ulp/test/test_ulp.c b/components/ulp/test/test_ulp.c index 6a9d40253..7f1bb5da7 100644 --- a/components/ulp/test/test_ulp.c +++ b/components/ulp/test/test_ulp.c @@ -160,6 +160,60 @@ TEST_CASE("ulp can write and read peripheral registers", "[ulp]") TEST_ASSERT_EQUAL_HEX32(1 | (15 << 21) | (1 << 16), RTC_SLOW_MEM[68]); } +TEST_CASE("ULP I_WR_REG instruction test", "[ulp]") +{ + assert(CONFIG_ULP_COPROC_RESERVE_MEM >= 260 && "this test needs ULP_COPROC_RESERVE_MEM option set in menuconfig"); + memset(RTC_SLOW_MEM, 0, CONFIG_ULP_COPROC_RESERVE_MEM); + typedef struct { + int low; + int width; + } wr_reg_test_item_t; + + const wr_reg_test_item_t test_items[] = { + {0, 1}, {0, 2}, {0, 3}, {0, 4}, {0, 5}, {0, 6}, {0, 7}, {0, 8}, + {3, 1}, {3, 2}, {3, 3}, {3, 4}, {3, 5}, {3, 6}, {3, 7}, {3, 8}, + {15, 1}, {15, 2}, {15, 3}, {15, 4}, {15, 5}, {15, 6}, {15, 7}, {15, 8}, + {16, 1}, {16, 2}, {16, 3}, {16, 4}, {16, 5}, {16, 6}, {16, 7}, {16, 8}, + {18, 1}, {18, 2}, {18, 3}, {18, 4}, {18, 5}, {18, 6}, {18, 7}, {18, 8}, + {24, 1}, {24, 2}, {24, 3}, {24, 4}, {24, 5}, {24, 6}, {24, 7}, {24, 8}, + }; + + const size_t test_items_count = + sizeof(test_items)/sizeof(test_items[0]); + for (size_t i = 0; i < test_items_count; ++i) { + const uint32_t mask = (uint32_t) (((1ULL << test_items[i].width) - 1) << test_items[i].low); + const uint32_t not_mask = ~mask; + printf("#%2d: low: %2d width: %2d mask: %08x expected: %08x ", i, + test_items[i].low, test_items[i].width, + mask, not_mask); + + REG_WRITE(RTC_CNTL_STORE0_REG, 0xffffffff); + REG_WRITE(RTC_CNTL_STORE1_REG, 0x00000000); + const ulp_insn_t program[] = { + I_WR_REG(RTC_CNTL_STORE0_REG, + test_items[i].low, + test_items[i].low + test_items[i].width - 1, + 0), + I_WR_REG(RTC_CNTL_STORE1_REG, + test_items[i].low, + test_items[i].low + test_items[i].width - 1, + 0xff & ((1 << test_items[i].width) - 1)), + I_END(0), + I_HALT() + }; + size_t size = sizeof(program)/sizeof(ulp_insn_t); + ulp_process_macros_and_load(0, program, &size); + ulp_run(0); + vTaskDelay(10/portTICK_PERIOD_MS); + uint32_t clear = REG_READ(RTC_CNTL_STORE0_REG); + uint32_t set = REG_READ(RTC_CNTL_STORE1_REG); + printf("clear: %08x set: %08x\n", clear, set); + TEST_ASSERT_EQUAL_HEX32(not_mask, clear); + TEST_ASSERT_EQUAL_HEX32(mask, set); + } +} + + TEST_CASE("ulp controls RTC_IO", "[ulp][ignore]") { assert(CONFIG_ULP_COPROC_RESERVE_MEM >= 260 && "this test needs ULP_COPROC_RESERVE_MEM option set in menuconfig"); From 0fcc8918ddc65b0bf0c4b4099b126df60d7cd435 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 20 Feb 2017 15:40:21 +0800 Subject: [PATCH 032/112] ulp: add I_WR_REG_BIT convenience macro --- components/ulp/include/esp32/ulp.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/components/ulp/include/esp32/ulp.h b/components/ulp/include/esp32/ulp.h index 6d4bb18b1..3978e7086 100644 --- a/components/ulp/include/esp32/ulp.h +++ b/components/ulp/include/esp32/ulp.h @@ -333,6 +333,14 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) { .high = high_bit, \ .opcode = OPCODE_RD_REG } } +/** + * Set or clear a bit in the peripheral register. + * + * Sets bit (1 << shift) of register reg to value val. + * This instruction can access RTC_CNTL_, RTC_IO_, and SENS_ peripheral registers. + */ +#define I_WR_REG_BIT(reg, shift, val) I_WR_REG(reg, shift, shift, val) + /** * End program. * From 0465528431fc63359d12c9514cfb17b6040e20fc Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 21 Feb 2017 12:11:51 +0800 Subject: [PATCH 033/112] =?UTF-8?q?ulp:=20don=E2=80=99t=20override=20SENS?= =?UTF-8?q?=5FSLEEP=5FCYCLES=5FS0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SENS_SLEEP_CYCLES_S0 may be set by the application to control ULP program timer. --- components/ulp/ulp.c | 1 - 1 file changed, 1 deletion(-) diff --git a/components/ulp/ulp.c b/components/ulp/ulp.c index c7ac15b49..a6e462d1b 100644 --- a/components/ulp/ulp.c +++ b/components/ulp/ulp.c @@ -275,7 +275,6 @@ esp_err_t ulp_run(uint32_t entry_point) SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_I2C_FOLW_8M); SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_CORE_FOLW_8M); SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_SLEEP_FOLW_8M); - SET_PERI_REG_BITS(SENS_ULP_CP_SLEEP_CYC0_REG, SENS_SLEEP_CYCLES_S0, 1000, SENS_SLEEP_CYCLES_S0_S); // enable ULP timer SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN); return ESP_OK; From 5cab04075e3cd86d8eb939cf0a4ea2a58dbce66f Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Wed, 22 Feb 2017 14:59:15 +0800 Subject: [PATCH 034/112] ulp: rename I_SLEEP, redefine I_WAKE, add I_ADC, add tests This fixes incorrect descriptions of I_END/I_SLEEP instructions and changes the definition of I_END. New instruction, I_WAKE, is added, which wakes up the SoC. Macro for ADC instruction is defined, and new tests are added. --- components/ulp/include/esp32/ulp.h | 70 ++++++++++--- components/ulp/test/test_ulp.c | 160 +++++++++++++++++++++++++++-- 2 files changed, 211 insertions(+), 19 deletions(-) diff --git a/components/ulp/include/esp32/ulp.h b/components/ulp/include/esp32/ulp.h index 3978e7086..7b434a06a 100644 --- a/components/ulp/include/esp32/ulp.h +++ b/components/ulp/include/esp32/ulp.h @@ -81,7 +81,7 @@ extern "C" { #define B_CMP_L 0 /*!< Branch if R0 is less than an immediate */ #define B_CMP_GE 1 /*!< Branch if R0 is greater than or equal to an immediate */ -#define OPCODE_END 9 /*!< Stop executing the program (not implemented yet) */ +#define OPCODE_END 9 /*!< Stop executing the program */ #define SUB_OPCODE_END 0 /*!< Stop executing the program and optionally wake up the chip */ #define SUB_OPCODE_SLEEP 1 /*!< Stop executing the program and run it again after selected interval */ @@ -342,27 +342,56 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) { #define I_WR_REG_BIT(reg, shift, val) I_WR_REG(reg, shift, shift, val) /** - * End program. + * Wake the SoC from deep sleep. * - * This instruction halts the coprocessor, and disables the ULP timer. - * If wake == 1, the main CPU is woken up from deep sleep. - * To stop the program but allow it to be restarted by timer, use I_HALT() - * or I_SLEEP() instructions. + * This instruction initiates wake up from deep sleep. + * Use esp_deep_sleep_enable_ulp_wakeup to enable deep sleep wakeup + * triggered by the ULP before going into deep sleep. + * Note that ULP program will still keep running until the I_HALT + * instruction, and it will still be restarted by timer at regular + * intervals, even when the SoC is woken up. + * + * To stop the ULP program, use I_HALT instruction. + * + * To disable the timer which start ULP program, use I_END() + * instruction. I_END instruction clears the + * RTC_CNTL_ULP_CP_SLP_TIMER_EN_S bit of RTC_CNTL_STATE0_REG + * register, which controls the ULP timer. */ -#define I_END(wake) { .end = { \ - .wakeup = wake, \ +#define I_WAKE() { .end = { \ + .wakeup = 1, \ .unused = 0, \ .sub_opcode = SUB_OPCODE_END, \ .opcode = OPCODE_END } } /** - * End program and restart it after given amount of time. + * Stop ULP program timer. * - * Time to restart the program is determined by the value of - * SENS_SLEEP_CYCLES_Sx register, where x == timer_idx. - * There are 5 SENS_SLEEP_CYCLES_Sx registers, so 0 <= timer_idx < 5. + * This is a convenience macro which disables the ULP program timer. + * Once this instruction is used, ULP program will not be restarted + * anymore until ulp_run function is called. + * + * ULP program will continue running after this instruction. To stop + * the currently running program, use I_HALT(). */ -#define I_SLEEP(timer_idx) { .sleep = { \ +#define I_END() \ + I_WR_REG_BIT(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN_S, 0) +/** + * Select the time interval used to run ULP program. + * + * This instructions selects which of the SENS_SLEEP_CYCLES_Sx + * registers' value is used by the ULP program timer. + * When the ULP program stops at I_HALT instruction, ULP program + * timer start counting. When the counter reaches the value of + * the selected SENS_SLEEP_CYCLES_Sx register, ULP program + * start running again from the start address (passed to the ulp_run + * function). + * There are 5 SENS_SLEEP_CYCLES_Sx registers, so 0 <= timer_idx < 5. + * + * By default, SENS_SLEEP_CYCLES_S0 register is used by the ULP + * program timer. + */ +#define I_SLEEP_CYCLE_SEL(timer_idx) { .sleep = { \ .cycle_sel = timer_idx, \ .unused = 0, \ .sub_opcode = SUB_OPCODE_SLEEP, \ @@ -380,6 +409,21 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) { .reserved = 0, \ .opcode = OPCODE_TSENS } } +/** + * Perform ADC measurement and store result in reg_dest. + * + * adc_idx selects ADC (0 or 1). + * pad_idx selects ADC pad (0 - 7). + */ +#define I_ADC(reg_dest, adc_idx, pad_idx) { .adc = {\ + .dreg = reg_dest, \ + .mux = pad_idx + 1, \ + .sar_sel = adc_idx, \ + .unused1 = 0, \ + .cycles = 0, \ + .unused2 = 0, \ + .opcode = OPCODE_ADC } } + /** * Store value from register reg_val into RTC memory. * diff --git a/components/ulp/test/test_ulp.c b/components/ulp/test/test_ulp.c index 7f1bb5da7..4f62c3c0b 100644 --- a/components/ulp/test/test_ulp.c +++ b/components/ulp/test/test_ulp.c @@ -112,7 +112,9 @@ TEST_CASE("ulp wakeup test", "[ulp][ignore]") I_MOVI(R2, 42), I_MOVI(R3, 15), I_ST(R2, R3, 0), - I_END(1) + I_WAKE(), + I_END(), + I_HALT() }; size_t size = sizeof(program)/sizeof(ulp_insn_t); ulp_process_macros_and_load(0, program, &size); @@ -145,7 +147,8 @@ TEST_CASE("ulp can write and read peripheral registers", "[ulp]") I_LD(R0, R1, 4), I_ADDI(R0, R0, 1), I_ST(R0, R1, 4), - I_END(0) + I_END(), + I_HALT() }; size_t size = sizeof(program)/sizeof(ulp_insn_t); TEST_ESP_OK(ulp_process_macros_and_load(0, program, &size)); @@ -198,7 +201,7 @@ TEST_CASE("ULP I_WR_REG instruction test", "[ulp]") test_items[i].low, test_items[i].low + test_items[i].width - 1, 0xff & ((1 << test_items[i].width) - 1)), - I_END(0), + I_END(), I_HALT() }; size_t size = sizeof(program)/sizeof(ulp_insn_t); @@ -242,7 +245,9 @@ TEST_CASE("ulp controls RTC_IO", "[ulp][ignore]") M_LABEL(5), M_BX(4), M_LABEL(6), - I_END(1) // wake up the SoC + I_WAKE(), // wake up the SoC + I_END(), // stop ULP program timer + I_HALT() }; const gpio_num_t led_gpios[] = { GPIO_NUM_2, @@ -261,6 +266,72 @@ TEST_CASE("ulp controls RTC_IO", "[ulp][ignore]") esp_deep_sleep_start(); } +TEST_CASE("ulp power consumption in deep sleep", "[ulp]") +{ + assert(CONFIG_ULP_COPROC_RESERVE_MEM >= 4 && "this test needs ULP_COPROC_RESERVE_MEM option set in menuconfig"); + ulp_insn_t insn = I_HALT(); + RTC_SLOW_MEM[0] = *(uint32_t*) &insn; + + REG_WRITE(SENS_ULP_CP_SLEEP_CYC0_REG, 0x8000); + + ulp_run(0); + + esp_deep_sleep_enable_ulp_wakeup(); + esp_deep_sleep_enable_timer_wakeup(10 * 1000000); + esp_deep_sleep_start(); +} + +TEST_CASE("ulp timer setting", "[ulp]") +{ + /* + * Run a simple ULP program which increments the counter, for one second. + * Program calls I_HALT each time and gets restarted by the timer. + * Compare the expected number of times the program runs with the actual. + */ + assert(CONFIG_ULP_COPROC_RESERVE_MEM >= 32 && "this test needs ULP_COPROC_RESERVE_MEM option set in menuconfig"); + memset(RTC_SLOW_MEM, 0, CONFIG_ULP_COPROC_RESERVE_MEM); + + const int offset = 6; + const ulp_insn_t program[] = { + I_MOVI(R1, offset), // r1 <- offset + I_LD(R2, R1, 0), // load counter + I_ADDI(R2, R2, 1), // counter += 1 + I_ST(R2, R1, 0), // save counter + I_HALT(), + }; + + size_t size = sizeof(program)/sizeof(ulp_insn_t); + TEST_ESP_OK(ulp_process_macros_and_load(0, program, &size)); + assert(offset >= size && "data offset needs to be greater or equal to program size"); + TEST_ESP_OK(ulp_run(0)); + // disable the ULP program timer — we will enable it later + CLEAR_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN); + + const uint32_t cycles_to_test[] = {0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000}; + const size_t tests_count = sizeof(cycles_to_test) / sizeof(cycles_to_test[0]); + for (size_t i = 0; i < tests_count; ++i) { + // zero out the counter + RTC_SLOW_MEM[offset] = 0; + // set the number of slow clock cycles + REG_WRITE(SENS_ULP_CP_SLEEP_CYC0_REG, cycles_to_test[i]); + // enable the timer and wait for a second + SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN); + vTaskDelay(1000 / portTICK_PERIOD_MS); + // get the counter value and stop the timer + uint32_t counter = RTC_SLOW_MEM[offset] & 0xffff; + CLEAR_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN); + // compare the actual and expected numbers of iterations of ULP program + float expected_period = (cycles_to_test[i] + 16) / (float) RTC_CNTL_SLOWCLK_FREQ + 5 / 8e6f; + float error = 1.0f - counter * expected_period; + printf("%u\t%u\t%.01f\t%.04f\n", cycles_to_test[i], counter, 1.0f / expected_period, error); + // Should be within 15% + TEST_ASSERT_INT_WITHIN(15, 0, (int) error * 100); + // Note: currently RTC_CNTL_SLOWCLK_FREQ is ballpark value — we need to determine it + // Precisely by running calibration similar to the one done in deep sleep. + // This may cause the test to fail on some chips which have the slow clock frequency + // way off. + } +} TEST_CASE("ulp can use TSENS in deep sleep", "[ulp][ignore]") { @@ -297,10 +368,87 @@ TEST_CASE("ulp can use TSENS in deep sleep", "[ulp][ignore]") I_ST(R0, R2, offset + 4), I_ADDI(R2, R2, 1), // counter += 1 I_ST(R2, R1, 1), // save counter - I_SLEEP(0), // enter sleep + I_HALT(), // enter sleep + M_LABEL(1), // done with measurements + I_END(), // stop ULP timer + I_WAKE(), // initiate wakeup + I_HALT() + }; + + size_t size = sizeof(program)/sizeof(ulp_insn_t); + TEST_ESP_OK(ulp_process_macros_and_load(0, program, &size)); + assert(offset >= size); + + TEST_ESP_OK(ulp_run(0)); + esp_deep_sleep_enable_timer_wakeup(4000000); + esp_deep_sleep_enable_ulp_wakeup(); + esp_deep_sleep_start(); +} + +TEST_CASE("can use ADC in deep sleep", "[ulp][ignore]") +{ + assert(CONFIG_ULP_COPROC_RESERVE_MEM >= 260 && "this test needs ULP_COPROC_RESERVE_MEM option set in menuconfig"); + + hexdump(RTC_SLOW_MEM, CONFIG_ULP_COPROC_RESERVE_MEM / 4); + printf("\n\n"); + memset(RTC_SLOW_MEM, 0, CONFIG_ULP_COPROC_RESERVE_MEM); + + SET_PERI_REG_BITS(SENS_SAR_START_FORCE_REG, SENS_SAR1_BIT_WIDTH, 3, SENS_SAR1_BIT_WIDTH_S); + SET_PERI_REG_BITS(SENS_SAR_START_FORCE_REG, SENS_SAR2_BIT_WIDTH, 3, SENS_SAR2_BIT_WIDTH_S); + + SET_PERI_REG_BITS(SENS_SAR_READ_CTRL_REG, SENS_SAR1_SAMPLE_BIT, 0x3, SENS_SAR1_SAMPLE_BIT_S); + SET_PERI_REG_BITS(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_SAMPLE_BIT, 0x3, SENS_SAR2_SAMPLE_BIT_S); + + CLEAR_PERI_REG_MASK(SENS_SAR_MEAS_START2_REG, SENS_MEAS2_START_FORCE); + CLEAR_PERI_REG_MASK(SENS_SAR_MEAS_START1_REG, SENS_MEAS1_START_FORCE); + + SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR, 0, SENS_FORCE_XPD_SAR_S); + SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_AMP, 2, SENS_FORCE_XPD_AMP_S); + +// SAR1 invert result + SET_PERI_REG_MASK(SENS_SAR_READ_CTRL_REG, SENS_SAR1_DATA_INV); + SET_PERI_REG_MASK(SENS_SAR_READ_CTRL_REG, SENS_SAR2_DATA_INV); + + +// const int adc = 1; +// const int channel = 1; +// const int atten = 3; +// const int gpio_num = 0; + + const int adc = 0; + const int channel = 0; + const int atten = 0; + const int gpio_num = 36; + + rtc_gpio_init(gpio_num); + + CLEAR_PERI_REG_MASK(SENS_SAR_MEAS_START1_REG, SENS_SAR1_EN_PAD_FORCE_M); + CLEAR_PERI_REG_MASK(SENS_SAR_MEAS_START2_REG, SENS_SAR2_EN_PAD_FORCE_M); + + SET_PERI_REG_BITS(SENS_SAR_ATTEN1_REG, 3, atten, 2 * channel); //set SAR1 attenuation + SET_PERI_REG_BITS(SENS_SAR_ATTEN2_REG, 3, atten, 2 * channel); //set SAR2 attenuation + + // data start offset + size_t offset = 20; + // number of samples to collect + RTC_SLOW_MEM[offset] = (CONFIG_ULP_COPROC_RESERVE_MEM) / 4 - offset - 8; + // sample counter + RTC_SLOW_MEM[offset + 1] = 0; + + const ulp_insn_t program[] = { + I_MOVI(R1, offset), // r1 <- offset + I_LD(R2, R1, 1), // r2 <- counter + I_LD(R3, R1, 0), // r3 <- length + I_SUBI(R3, R3, 1), // end = length - 1 + I_SUBR(R3, R3, R2), // r3 = length - counter + M_BXF(1), // if overflow goto 1: + I_ADC(R0, adc, channel), // r0 <- ADC + I_ST(R0, R2, offset + 4), + I_ADDI(R2, R2, 1), // counter += 1 + I_ST(R2, R1, 1), // save counter I_HALT(), M_LABEL(1), // done with measurements - I_END(0), // stop ULP timer + I_END(), // stop ULP program timer I_HALT() }; From e96d653c9ecff6d90113bcead8ef003050d87562 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Wed, 22 Feb 2017 17:04:11 +0800 Subject: [PATCH 035/112] ulp: make sure I_WAKE instruction works with ULP timer disabled Setting ULP_CP_WAKEUP_FORCE_EN forces ULP wakeup to work even if the ULP timer has already been disabled. --- components/esp32/deep_sleep.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/esp32/deep_sleep.c b/components/esp32/deep_sleep.c index aadb6067e..55e92a05e 100644 --- a/components/esp32/deep_sleep.c +++ b/components/esp32/deep_sleep.c @@ -126,6 +126,9 @@ void IRAM_ATTR esp_deep_sleep_start() if (s_config.wakeup_triggers & EXT_EVENT1_TRIG_EN) { ext1_wakeup_prepare(); } + if (s_config.wakeup_triggers & SAR_TRIG_EN) { + SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_WAKEUP_FORCE_EN); + } // TODO: move timer wakeup configuration into a similar function // once rtc_sleep is opensourced. From 4af5f572f49f21d23af3c21073178a9c40828503 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Sat, 28 Jan 2017 00:00:31 +0800 Subject: [PATCH 036/112] add deep sleep wake up example --- docs/api/system/deep_sleep.rst | 1 + examples/system/deep_sleep/Makefile | 9 + examples/system/deep_sleep/README.md | 11 + .../system/deep_sleep/main/Kconfig.projbuild | 20 ++ examples/system/deep_sleep/main/component.mk | 3 + .../deep_sleep/main/deep_sleep_wakeup.c | 296 ++++++++++++++++++ examples/system/deep_sleep/sdkconfig.defaults | 7 + 7 files changed, 347 insertions(+) create mode 100644 examples/system/deep_sleep/Makefile create mode 100644 examples/system/deep_sleep/README.md create mode 100644 examples/system/deep_sleep/main/Kconfig.projbuild create mode 100644 examples/system/deep_sleep/main/component.mk create mode 100644 examples/system/deep_sleep/main/deep_sleep_wakeup.c create mode 100644 examples/system/deep_sleep/sdkconfig.defaults diff --git a/docs/api/system/deep_sleep.rst b/docs/api/system/deep_sleep.rst index aacb25218..c66127d63 100644 --- a/docs/api/system/deep_sleep.rst +++ b/docs/api/system/deep_sleep.rst @@ -116,3 +116,4 @@ Application Example Implementation of basic functionality of deep sleep is shown in :example:`protocols/sntp` example, where ESP module is periodically waken up to retrive time from NTP server. +More extensive example in :example:`system/deep_sleep` illustrates usage of various deep sleep wakeup triggers and ULP coprocessor programming. diff --git a/examples/system/deep_sleep/Makefile b/examples/system/deep_sleep/Makefile new file mode 100644 index 000000000..4d0fae132 --- /dev/null +++ b/examples/system/deep_sleep/Makefile @@ -0,0 +1,9 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := deep_sleep + +include $(IDF_PATH)/make/project.mk + diff --git a/examples/system/deep_sleep/README.md b/examples/system/deep_sleep/README.md new file mode 100644 index 000000000..3d4438de7 --- /dev/null +++ b/examples/system/deep_sleep/README.md @@ -0,0 +1,11 @@ +# Example: deep sleep + +This example illustrates usage of deep sleep mode and various wakeup sources. + +The following wake up sources are configured: + +- Timer: wake up the chip in 20 seconds +- EXT1: wake up the chip if any of the two buttons are pressed (GPIO25, GPIO26) +- Touch: wake up the chip if any of the touch pads are pressed (GPIO32, GPIO33) +- ULP: wake up when the chip temperature changes by more than ~5 degrees Celsius (this value hasn't been characterized exactly yet). + diff --git a/examples/system/deep_sleep/main/Kconfig.projbuild b/examples/system/deep_sleep/main/Kconfig.projbuild new file mode 100644 index 000000000..cb8632d68 --- /dev/null +++ b/examples/system/deep_sleep/main/Kconfig.projbuild @@ -0,0 +1,20 @@ +menu "Example Configuration" + +config ENABLE_TOUCH_WAKEUP + bool "Enable touch wake up" + default y + help + This option enables wake up from deep sleep using touch pads + TOUCH8 and TOUCH9, which correspond to GPIO33 and GPIO32. + +config ENABLE_ULP_TEMPERATURE_WAKEUP + bool "Enable temperature monitoring by ULP" + default y + help + This option enables wake up from deep sleep using ULP. + ULP program monitors the on-chip temperature sensor and + wakes up the chip when the temperature goes outside of + the window defined by the initial temperature and a threshold + around it. + +endmenu \ No newline at end of file diff --git a/examples/system/deep_sleep/main/component.mk b/examples/system/deep_sleep/main/component.mk new file mode 100644 index 000000000..44bd2b527 --- /dev/null +++ b/examples/system/deep_sleep/main/component.mk @@ -0,0 +1,3 @@ +# +# Main Makefile. This is basically the same as a component makefile. +# diff --git a/examples/system/deep_sleep/main/deep_sleep_wakeup.c b/examples/system/deep_sleep/main/deep_sleep_wakeup.c new file mode 100644 index 000000000..959fdfbad --- /dev/null +++ b/examples/system/deep_sleep/main/deep_sleep_wakeup.c @@ -0,0 +1,296 @@ +/* Deep sleep wake up example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include +#include +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_deep_sleep.h" +#include "esp_log.h" +#include "esp32/ulp.h" +#include "driver/touch_pad.h" +#include "driver/adc.h" +#include "driver/rtc_io.h" +#include "soc/rtc_cntl_reg.h" +#include "soc/sens_reg.h" + +static RTC_DATA_ATTR struct timeval sleep_enter_time; + +#ifdef CONFIG_ENABLE_ULP_TEMPERATURE_WAKEUP + +/* + * Offset (in 32-bit words) in RTC Slow memory where the data is placed + * by the ULP coprocessor. It can be chosen to be any value greater or equal + * to ULP program size, and less than the CONFIG_ULP_COPROC_RESERVE_MEM/4 - 6, + * where 6 is the number of words used by the ULP coprocessor. + */ +#define ULP_DATA_OFFSET 36 + +_Static_assert(ULP_DATA_OFFSET < CONFIG_ULP_COPROC_RESERVE_MEM/4 - 6, + "ULP_DATA_OFFSET is set too high, or CONFIG_ULP_COPROC_RESERVE_MEM is not sufficient"); + +/** + * @brief Start ULP temperature monitoring program + * + * This function loads a program into the RTC Slow memory and starts up the ULP. + * The program monitors on-chip temperature sensor and wakes up the SoC when + * the temperature goes lower or higher than certain thresholds. + */ +static void start_ulp_temperature_monitoring(); + +/** + * @brief Utility function which reads data written by ULP program + * + * @param offset offset from ULP_DATA_OFFSET in RTC Slow memory, in words + * @return lower 16-bit part of the word writable by the ULP + */ +static inline uint16_t ulp_data_read(size_t offset) +{ + return RTC_SLOW_MEM[ULP_DATA_OFFSET + offset] & 0xffff; +} + +/** + * @brief Utility function which writes data to be ready by ULP program + * + * @param offset offset from ULP_DATA_OFFSET in RTC Slow memory, in words + * @param value lower 16-bit part of the word to be stored + */ +static inline void ulp_data_write(size_t offset, uint16_t value) +{ + RTC_SLOW_MEM[ULP_DATA_OFFSET + offset] = value; +} + +#endif // CONFIG_ENABLE_ULP_TEMPERATURE_WAKEUP + +#ifdef CONFIG_ENABLE_TOUCH_WAKEUP +static void calibrate_touch_pad(touch_pad_t pad); +#endif + +void app_main() +{ + struct timeval now; + gettimeofday(&now, NULL); + int sleep_time_ms = (now.tv_sec - sleep_enter_time.tv_sec) * 1000 + (now.tv_usec - sleep_enter_time.tv_usec) / 1000; + + switch (esp_deep_sleep_get_wakeup_cause()) { + case ESP_DEEP_SLEEP_WAKEUP_EXT1: { + uint64_t wakeup_pin_mask = esp_deep_sleep_get_ext1_wakeup_status(); + if (wakeup_pin_mask != 0) { + int pin = __builtin_ffsll(wakeup_pin_mask) - 1; + printf("Wake up from GPIO %d\n", pin); + } else { + printf("Wake up from GPIO\n"); + } + break; + } + case ESP_DEEP_SLEEP_WAKEUP_TIMER: { + printf("Wake up from timer. Time spent in deep sleep: %dms\n", sleep_time_ms); + break; + } +#ifdef CONFIG_ENABLE_TOUCH_WAKEUP + case ESP_DEEP_SLEEP_WAKEUP_TOUCHPAD: { + printf("Wake up from touch on pad %d\n", esp_deep_sleep_get_touchpad_wakeup_status()); + break; + } +#endif // CONFIG_ENABLE_TOUCH_WAKEUP +#ifdef CONFIG_ENABLE_ULP_TEMPERATURE_WAKEUP + case ESP_DEEP_SLEEP_WAKEUP_ULP: { + printf("Wake up from ULP\n"); + int16_t diff_high = (int16_t) ulp_data_read(3); + int16_t diff_low = (int16_t) ulp_data_read(4); + if (diff_high < 0) { + printf("High temperature alarm was triggered\n"); + } else if (diff_low < 0) { + printf("Low temperature alarm was triggered\n"); + } else { + assert(false && "temperature has stayed within limits, but got ULP wakeup\n"); + } + break; + } +#endif // CONFIG_ENABLE_ULP_TEMPERATURE_WAKEUP + case ESP_DEEP_SLEEP_WAKEUP_UNDEFINED: + default: + printf("Not a deep sleep reset\n"); + } + +#ifdef CONFIG_ENABLE_ULP_TEMPERATURE_WAKEUP + if (esp_deep_sleep_get_wakeup_cause() != ESP_DEEP_SLEEP_WAKEUP_UNDEFINED) { + printf("ULP did %d temperature measurements in %d ms\n", ulp_data_read(1), sleep_time_ms); + printf("Initial T=%d, latest T=%d\n", ulp_data_read(0), ulp_data_read(2)); + } +#endif // CONFIG_ENABLE_ULP_TEMPERATURE_WAKEUP + + vTaskDelay(1000 / portTICK_PERIOD_MS); + + const int wakeup_time_sec = 20; + printf("Enabling timer wakeup, %ds\n", wakeup_time_sec); + esp_deep_sleep_enable_timer_wakeup(wakeup_time_sec * 1000000); + + const int ext_wakeup_pin_1 = 25; + const uint64_t ext_wakeup_pin_1_mask = 1ULL << ext_wakeup_pin_1; + const int ext_wakeup_pin_2 = 26; + const uint64_t ext_wakeup_pin_2_mask = 1ULL << ext_wakeup_pin_2; + + printf("Enabling EXT1 wakeup on pins GPIO%d, GPIO%d\n", ext_wakeup_pin_1, ext_wakeup_pin_2); + esp_deep_sleep_enable_ext1_wakeup(ext_wakeup_pin_1_mask | ext_wakeup_pin_2_mask, ESP_EXT1_WAKEUP_ANY_HIGH); + +#ifdef CONFIG_ENABLE_TOUCH_WAKEUP + touch_pad_init(); + calibrate_touch_pad(TOUCH_PAD_NUM8); + calibrate_touch_pad(TOUCH_PAD_NUM9); + printf("Enabling touch pad wakeup\n"); + esp_deep_sleep_enable_touchpad_wakeup(); +#endif // CONFIG_ENABLE_TOUCH_WAKEUP + +#ifdef CONFIG_ENABLE_ULP_TEMPERATURE_WAKEUP + printf("Enabling ULP wakeup\n"); + esp_deep_sleep_enable_ulp_wakeup(); +#endif + + printf("Entering deep sleep\n"); + gettimeofday(&sleep_enter_time, NULL); + +#ifdef CONFIG_ENABLE_ULP_TEMPERATURE_WAKEUP + start_ulp_temperature_monitoring(); +#endif + + esp_deep_sleep_start(); +} + +#ifdef CONFIG_ENABLE_TOUCH_WAKEUP +static void calibrate_touch_pad(touch_pad_t pad) +{ + touch_pad_config(pad, 1000); + + int avg = 0; + const size_t calibration_count = 128; + for (int i = 0; i < calibration_count; ++i) { + uint16_t val; + touch_pad_read(pad, &val); + avg += val; + } + avg /= calibration_count; + const int min_reading = 300; + if (avg < min_reading) { + printf("Touch pad #%d average reading is too low: %d (expecting at least %d). " + "Not using for deep sleep wakeup.\n", pad, avg, min_reading); + touch_pad_config(pad, 0); + } else { + int threshold = avg - 100; + printf("Touch pad #%d average: %d, wakeup threshold set to %d.\n", pad, avg, threshold); + touch_pad_config(pad, threshold); + } +} +#endif // CONFIG_ENABLE_TOUCH_WAKEUP + +#ifdef CONFIG_ENABLE_ULP_TEMPERATURE_WAKEUP +static void start_ulp_temperature_monitoring() +{ + /* + * This ULP program monitors the on-chip temperature sensor and wakes the chip up when + * the temperature goes outside of certain window. + * When the program runs for the first time, it saves the temperature measurement, + * it is considered initial temperature (T0). + * + * On each subsequent run, temperature measured and compared to T0. + * If the measured value is higher than T0 + max_temp_diff or lower than T0 - max_temp_diff, + * the chip is woken up from deep sleep. + */ + + /* Temperature difference threshold which causes wakeup + * With settings here (TSENS_CLK_DIV=2, 8000 cycles), + * TSENS measurement is done in units of 0.73 degrees Celsius. + * Therefore, max_temp_diff below is equivalent to ~2.2 degrees Celsius. + */ + const int16_t max_temp_diff = 3; + + // Number of measurements ULP should do per second + const uint32_t measurements_per_sec = 5; + + // Allow TSENS to be controlled by the ULP + SET_PERI_REG_BITS(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_CLK_DIV, 2, SENS_TSENS_CLK_DIV_S); + SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR, 3, SENS_FORCE_XPD_SAR_S); + CLEAR_PERI_REG_MASK(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_POWER_UP); + CLEAR_PERI_REG_MASK(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_DUMP_OUT); + CLEAR_PERI_REG_MASK(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_POWER_UP_FORCE); + + // Clear the part of RTC_SLOW_MEM reserved for the ULP. Makes debugging easier. + memset(RTC_SLOW_MEM, 0, CONFIG_ULP_COPROC_RESERVE_MEM); + + // The first word of memory (at data offset) is used to store the initial temperature (T0) + // Zero it out here, then ULP will update it on the first run. + ulp_data_write(0, 0); + // The second word is used to store measurement count, zero it out as well. + ulp_data_write(1, 0); + + const ulp_insn_t program[] = { + // load data offset into R2 + I_MOVI(R2, ULP_DATA_OFFSET), + // load/increment/store measurement counter using R1 + I_LD(R1, R2, 1), + I_ADDI(R1, R1, 1), + I_ST(R1, R2, 1), + // enable temperature sensor + I_WR_REG(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR_S, SENS_FORCE_XPD_SAR_S + 1, 3), + // do temperature measurement and store result in R3 + I_TSENS(R3, 8000), + // disable temperature sensor + I_WR_REG(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR_S, SENS_FORCE_XPD_SAR_S + 1, 0), + // Save current measurement at offset+2 + I_ST(R3, R2, 2), + // load initial value into R0 + I_LD(R0, R2, 0), + // if threshold value >=1 (i.e. initialized), goto 1 + M_BGE(1, 1), + // otherwise, save the current value as initial (T0) + I_MOVR(R0, R3), + I_ST(R0, R2, 0), + M_LABEL(1), + // check if the temperature is greater or equal (T0 + max_temp_diff) + // uses R1 as scratch register, difference is saved at offset + 3 + I_ADDI(R1, R0, max_temp_diff - 1), + I_SUBR(R1, R1, R3), + I_ST(R1, R2, 3), + M_BXF(2), + // check if the temperature is less or equal (T0 - max_temp_diff) + // uses R1 as scratch register, difference is saved at offset + 4 + I_SUBI(R1, R0, max_temp_diff - 1), + I_SUBR(R1, R3, R1), + I_ST(R1, R2, 4), + M_BXF(2), + // temperature is within (T0 - max_temp_diff; T0 + max_temp_diff) + // stop ULP until the program timer starts it again + I_HALT(), + M_LABEL(2), + // temperature is out of bounds + // disable ULP program timer + I_WR_REG_BIT(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN_S, 0), + // initiate wakeup of the SoC + I_WAKE(), + // stop the ULP program + I_HALT() + }; + + // Load ULP program into RTC_SLOW_MEM, at offset 0 + size_t size = sizeof(program)/sizeof(ulp_insn_t); + ESP_ERROR_CHECK( ulp_process_macros_and_load(0, program, &size) ); + assert(size < ULP_DATA_OFFSET && "ULP_DATA_OFFSET needs to be greater or equal to the program size"); + + // Set ULP wakeup period + const uint32_t sleep_cycles = RTC_CNTL_SLOWCLK_FREQ / measurements_per_sec; + REG_WRITE(SENS_ULP_CP_SLEEP_CYC0_REG, sleep_cycles); + + // Start ULP + ESP_ERROR_CHECK( ulp_run(0) ); +} +#endif // CONFIG_ENABLE_ULP_TEMPERATURE_WAKEUP + diff --git a/examples/system/deep_sleep/sdkconfig.defaults b/examples/system/deep_sleep/sdkconfig.defaults new file mode 100644 index 000000000..dd7da3f88 --- /dev/null +++ b/examples/system/deep_sleep/sdkconfig.defaults @@ -0,0 +1,7 @@ +CONFIG_ESP32_DEFAULT_CPU_FREQ_80=y +CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=80 +CONFIG_ULP_COPROC_ENABLED=y +CONFIG_ULP_COPROC_RESERVE_MEM=512 +CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1=y +CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC=y +CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY=500 From b5826978892da8230ac0084c4d8e22ab6844f43a Mon Sep 17 00:00:00 2001 From: Tian Hao Date: Thu, 23 Feb 2017 17:32:46 +0800 Subject: [PATCH 037/112] component/bt : add adv/scan start complete event 1. indicate adv/scan start complete success or failed 2. controller do limit of adv/scan concurrence, so add some codes to report adv/scan start failed or not. --- .../bluedroid/api/include/esp_gap_ble_api.h | 14 ++++ components/bt/bluedroid/bta/dm/bta_dm_act.c | 21 ++++-- components/bt/bluedroid/bta/dm/bta_dm_api.c | 7 +- components/bt/bluedroid/bta/dm/bta_dm_int.h | 4 +- components/bt/bluedroid/bta/include/bta_api.h | 9 ++- .../btc/profile/std/gap/btc_gap_ble.c | 65 ++++++++++++++++--- .../bt/bluedroid/stack/btm/btm_ble_gap.c | 38 +++++++---- docs/api/bluetooth/esp_gap_ble.rst | 6 ++ .../bluetooth/gatt_client/main/gattc_demo.c | 6 ++ .../bluetooth/gatt_server/main/gatts_demo.c | 6 ++ .../main/gatts_table_creat_demo.c | 6 ++ 11 files changed, 149 insertions(+), 33 deletions(-) diff --git a/components/bt/bluedroid/api/include/esp_gap_ble_api.h b/components/bt/bluedroid/api/include/esp_gap_ble_api.h index 64aff1fb1..8b5882d27 100644 --- a/components/bt/bluedroid/api/include/esp_gap_ble_api.h +++ b/components/bt/bluedroid/api/include/esp_gap_ble_api.h @@ -46,6 +46,8 @@ typedef enum { ESP_GAP_BLE_SCAN_RESULT_EVT, /*!< When one scan result ready, the event comes each time */ ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT, /*!< When raw advertising data set complete, the event comes */ ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT, /*!< When raw advertising data set complete, the event comes */ + ESP_GAP_BLE_ADV_START_COMPLETE_EVT, /*!< When start advertising complete, the event comes */ + ESP_GAP_BLE_SCAN_START_COMPLETE_EVT, /*!< When start scan complete, the event comes */ } esp_gap_ble_cb_event_t; /// Advertising data maximum length @@ -284,6 +286,18 @@ typedef union { struct ble_scan_rsp_data_raw_cmpl_evt_param { esp_bt_status_t status; /*!< Indicate the set raw advertising data operation success status */ } scan_rsp_data_raw_cmpl; /*!< Event parameter of ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT */ + /** + * @brief ESP_GAP_BLE_ADV_START_COMPLETE_EVT + */ + struct ble_adv_start_cmpl_evt_param { + esp_bt_status_t status; /*!< Indicate advertising start operation success status */ + } adv_start_cmpl; /*!< Event parameter of ESP_GAP_BLE_ADV_START_COMPLETE_EVT */ + /** + * @brief ESP_GAP_BLE_SCAN_START_COMPLETE_EVT + */ + struct ble_scan_start_cmpl_evt_param { + esp_bt_status_t status; /*!< Indicate scan start operation success status */ + } scan_start_cmpl; /*!< Event parameter of ESP_GAP_BLE_SCAN_START_COMPLETE_EVT */ } esp_ble_gap_cb_param_t; /** diff --git a/components/bt/bluedroid/bta/dm/bta_dm_act.c b/components/bt/bluedroid/bta/dm/bta_dm_act.c index 66eb55dac..8ebd3a8f3 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_act.c +++ b/components/bt/bluedroid/bta/dm/bta_dm_act.c @@ -4534,12 +4534,11 @@ void bta_dm_ble_observe (tBTA_DM_MSG *p_data) bta_dm_search_cb.p_scan_cback = p_data->ble_observe.p_cback; if ((status = BTM_BleObserve(TRUE, p_data->ble_observe.duration, bta_dm_observe_results_cb, bta_dm_observe_cmpl_cb)) != BTM_CMD_STARTED) { - tBTA_DM_SEARCH data; APPL_TRACE_WARNING(" %s BTM_BleObserve failed. status %d\n", __FUNCTION__, status); - data.inq_cmpl.num_resps = 0; - if (bta_dm_search_cb.p_scan_cback) { - bta_dm_search_cb.p_scan_cback(BTA_DM_INQ_CMPL_EVT, &data); - } + } + if (p_data->ble_observe.p_start_scan_cback) { + status = (status == BTM_CMD_STARTED ? BTA_SUCCESS : BTA_FAILURE); + p_data->ble_observe.p_start_scan_cback(status); } } else { bta_dm_search_cb.p_scan_cback = NULL; @@ -4576,13 +4575,21 @@ void bta_dm_ble_set_adv_params (tBTA_DM_MSG *p_data) *******************************************************************************/ void bta_dm_ble_set_adv_params_all (tBTA_DM_MSG *p_data) { - BTM_BleSetAdvParamsStartAdv(p_data->ble_set_adv_params_all.adv_int_min, + tBTA_STATUS status = BTA_FAILURE; + + if (BTM_BleSetAdvParamsStartAdv(p_data->ble_set_adv_params_all.adv_int_min, p_data->ble_set_adv_params_all.adv_int_max, p_data->ble_set_adv_params_all.adv_type, p_data->ble_set_adv_params_all.addr_type_own, p_data->ble_set_adv_params_all.p_dir_bda, p_data->ble_set_adv_params_all.channel_map, - p_data->ble_set_adv_params_all.adv_filter_policy); + p_data->ble_set_adv_params_all.adv_filter_policy) == BTM_SUCCESS) { + status = BTA_SUCCESS; + } + + if (p_data->ble_set_adv_params_all.p_start_adv_cback) { + (*p_data->ble_set_adv_params_all.p_start_adv_cback)(status); + } } /******************************************************************************* diff --git a/components/bt/bluedroid/bta/dm/bta_dm_api.c b/components/bt/bluedroid/bta/dm/bta_dm_api.c index 132d2ea8f..413d6de55 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_api.c +++ b/components/bt/bluedroid/bta/dm/bta_dm_api.c @@ -1009,7 +1009,7 @@ void BTA_DmSetBleAdvParams (UINT16 adv_int_min, UINT16 adv_int_max, void BTA_DmSetBleAdvParamsAll (UINT16 adv_int_min, UINT16 adv_int_max, UINT8 adv_type, tBLE_ADDR_TYPE addr_type_own, tBTM_BLE_ADV_CHNL_MAP chnl_map, tBTM_BLE_AFP adv_fil_pol, - tBLE_BD_ADDR *p_dir_bda) + tBLE_BD_ADDR *p_dir_bda, tBTA_START_ADV_CMPL_CBACK p_start_adv_cb) { #if BLE_INCLUDED == TRUE tBTA_DM_API_BLE_ADV_PARAMS_ALL *p_msg; @@ -1029,6 +1029,7 @@ void BTA_DmSetBleAdvParamsAll (UINT16 adv_int_min, UINT16 adv_int_max, p_msg->addr_type_own = addr_type_own; p_msg->channel_map = chnl_map; p_msg->adv_filter_policy = adv_fil_pol; + p_msg->p_start_adv_cback = p_start_adv_cb; if (p_dir_bda != NULL) { p_msg->p_dir_bda = (tBLE_BD_ADDR *)(p_msg + 1); memcpy(p_msg->p_dir_bda, p_dir_bda, sizeof(tBLE_BD_ADDR)); @@ -2127,7 +2128,8 @@ void BTA_DmCloseACL(BD_ADDR bd_addr, BOOLEAN remove_dev, tBTA_TRANSPORT transpor ** *******************************************************************************/ extern void BTA_DmBleObserve(BOOLEAN start, UINT8 duration, - tBTA_DM_SEARCH_CBACK *p_results_cb) + tBTA_DM_SEARCH_CBACK *p_results_cb, + tBTA_START_SCAN_CMPL_CBACK *p_start_scan_cb) { tBTA_DM_API_BLE_OBSERVE *p_msg; @@ -2140,6 +2142,7 @@ extern void BTA_DmBleObserve(BOOLEAN start, UINT8 duration, p_msg->start = start; p_msg->duration = duration; p_msg->p_cback = p_results_cb; + p_msg->p_start_scan_cback = p_start_scan_cb; bta_sys_sendmsg(p_msg); } diff --git a/components/bt/bluedroid/bta/dm/bta_dm_int.h b/components/bt/bluedroid/bta/dm/bta_dm_int.h index 7475ad254..9c5cbc4d8 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_int.h +++ b/components/bt/bluedroid/bta/dm/bta_dm_int.h @@ -471,7 +471,8 @@ typedef struct { BT_HDR hdr; BOOLEAN start; UINT16 duration; - tBTA_DM_SEARCH_CBACK *p_cback; + tBTA_DM_SEARCH_CBACK *p_cback; + tBTA_START_SCAN_CMPL_CBACK *p_start_scan_cback; } tBTA_DM_API_BLE_OBSERVE; typedef struct { @@ -506,6 +507,7 @@ typedef struct { tBTM_BLE_ADV_CHNL_MAP channel_map; tBTM_BLE_AFP adv_filter_policy; tBLE_BD_ADDR *p_dir_bda; + tBTA_START_ADV_CMPL_CBACK *p_start_adv_cback; } tBTA_DM_API_BLE_ADV_PARAMS_ALL; diff --git a/components/bt/bluedroid/bta/include/bta_api.h b/components/bt/bluedroid/bta/include/bta_api.h index 1b97dc4fc..8e4b927aa 100644 --- a/components/bt/bluedroid/bta/include/bta_api.h +++ b/components/bt/bluedroid/bta/include/bta_api.h @@ -400,6 +400,8 @@ typedef struct { typedef void (tBTA_SET_ADV_DATA_CMPL_CBACK) (tBTA_STATUS status); +typedef void (tBTA_START_ADV_CMPL_CBACK) (tBTA_STATUS status); + /* advertising channel map */ #define BTA_BLE_ADV_CHNL_37 BTM_BLE_ADV_CHNL_37 #define BTA_BLE_ADV_CHNL_38 BTM_BLE_ADV_CHNL_38 @@ -1095,6 +1097,8 @@ typedef void (tBTA_BLE_SCAN_SETUP_CBACK) (tBTA_BLE_BATCH_SCAN_EVT evt, tBTA_DM_BLE_REF_VALUE ref_value, tBTA_STATUS status); +typedef void (tBTA_START_SCAN_CMPL_CBACK) (tBTA_STATUS status); + typedef void (tBTA_BLE_TRACK_ADV_CMPL_CBACK)(int action, tBTA_STATUS status, tBTA_DM_BLE_PF_AVBL_SPACE avbl_space, tBTA_DM_BLE_REF_VALUE ref_value); @@ -1891,7 +1895,7 @@ extern void BTA_DmSetBleAdvParams (UINT16 adv_int_min, UINT16 adv_int_max, extern void BTA_DmSetBleAdvParamsAll (UINT16 adv_int_min, UINT16 adv_int_max, UINT8 adv_type, tBLE_ADDR_TYPE addr_type_own, tBTM_BLE_ADV_CHNL_MAP chnl_map, tBTM_BLE_AFP adv_fil_pol, - tBLE_BD_ADDR *p_dir_bda); + tBLE_BD_ADDR *p_dir_bda, tBTA_START_ADV_CMPL_CBACK p_start_adv_cb); /******************************************************************************* @@ -1997,7 +2001,8 @@ extern void BTA_DmSetEncryption(BD_ADDR bd_addr, tBTA_TRANSPORT transport, ** *******************************************************************************/ extern void BTA_DmBleObserve(BOOLEAN start, UINT8 duration, - tBTA_DM_SEARCH_CBACK *p_results_cb); + tBTA_DM_SEARCH_CBACK *p_results_cb, + tBTA_START_SCAN_CMPL_CBACK *p_start_scan_cb); extern void BTA_DmBleStopAdvertising(void); diff --git a/components/bt/bluedroid/btc/profile/std/gap/btc_gap_ble.c b/components/bt/bluedroid/btc/profile/std/gap/btc_gap_ble.c index 339ff6842..8fea801b0 100644 --- a/components/bt/bluedroid/btc/profile/std/gap/btc_gap_ble.c +++ b/components/bt/bluedroid/btc/profile/std/gap/btc_gap_ble.c @@ -367,7 +367,26 @@ static void btc_ble_set_scan_rsp_data_raw(uint8_t *raw_scan_rsp, uint32_t raw_sc BTA_DmBleSetScanRspRaw(raw_scan_rsp, raw_scan_rsp_len, p_scan_rsp_data_cback); } -static void btc_ble_start_advertising (esp_ble_adv_params_t *ble_adv_params) +static void btc_start_adv_callback(tBTA_STATUS status) +{ + esp_ble_gap_cb_param_t param; + bt_status_t ret; + btc_msg_t msg; + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_GAP_BLE; + msg.act = ESP_GAP_BLE_ADV_START_COMPLETE_EVT; + param.adv_start_cmpl.status = status; + + ret = btc_transfer_context(&msg, ¶m, + sizeof(esp_ble_gap_cb_param_t), NULL); + + if (ret != BT_STATUS_SUCCESS) { + LOG_ERROR("%s btc_transfer_context failed\n", __func__); + } +} + +static void btc_ble_start_advertising (esp_ble_adv_params_t *ble_adv_params, tBTA_START_ADV_CMPL_CBACK start_adv_cback) { tBLE_BD_ADDR peer_addr; @@ -398,7 +417,8 @@ static void btc_ble_start_advertising (esp_ble_adv_params_t *ble_adv_params) ble_adv_params->own_addr_type, ble_adv_params->channel_map, ble_adv_params->adv_filter_policy, - &peer_addr); + &peer_addr, + start_adv_cback); } @@ -487,12 +507,33 @@ static void btc_search_callback(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data btc_transfer_context(&msg, ¶m, sizeof(esp_ble_gap_cb_param_t), NULL); } - -static void btc_ble_start_scanning(uint8_t duration, tBTA_DM_SEARCH_CBACK *results_cb) +static void btc_start_scan_callback(tBTA_STATUS status) { - if ((duration != 0) && (results_cb != NULL)) { + esp_ble_gap_cb_param_t param; + bt_status_t ret; + btc_msg_t msg; + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_GAP_BLE; + msg.act = ESP_GAP_BLE_SCAN_START_COMPLETE_EVT; + param.scan_start_cmpl.status = status; + + + ret = btc_transfer_context(&msg, ¶m, + sizeof(esp_ble_gap_cb_param_t), NULL); + + if (ret != BT_STATUS_SUCCESS) { + LOG_ERROR("%s btc_transfer_context failed\n", __func__); + } +} + +static void btc_ble_start_scanning(uint8_t duration, + tBTA_DM_SEARCH_CBACK *results_cb, + tBTA_START_SCAN_CMPL_CBACK *start_scan_cb) +{ + if ((duration != 0) && (results_cb != NULL) && (start_scan_cb != NULL)) { ///Start scan the device - BTA_DmBleObserve(true, duration, results_cb); + BTA_DmBleObserve(true, duration, results_cb, start_scan_cb); } else { LOG_ERROR("The scan duration or p_results_cb invalid\n"); } @@ -501,7 +542,7 @@ static void btc_ble_start_scanning(uint8_t duration, tBTA_DM_SEARCH_CBACK *resul static void btc_ble_stop_scanning(void) { uint8_t duration = 0; - BTA_DmBleObserve(false, duration, NULL); + BTA_DmBleObserve(false, duration, NULL, NULL); } @@ -576,6 +617,12 @@ void btc_gap_ble_cb_handler(btc_msg_t *msg) case ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT: btc_gap_ble_cb_to_app(ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT, param); break; + case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: + btc_gap_ble_cb_to_app(ESP_GAP_BLE_ADV_START_COMPLETE_EVT, param); + break; + case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT: + btc_gap_ble_cb_to_app(ESP_GAP_BLE_SCAN_START_COMPLETE_EVT, param); + break; default: break; @@ -695,13 +742,13 @@ void btc_gap_ble_call_handler(btc_msg_t *msg) btc_ble_set_scan_params(&arg->set_scan_param.scan_params, btc_scan_params_callback); break; case BTC_GAP_BLE_ACT_START_SCAN: - btc_ble_start_scanning(arg->start_scan.duration, btc_search_callback); + btc_ble_start_scanning(arg->start_scan.duration, btc_search_callback, btc_start_scan_callback); break; case BTC_GAP_BLE_ACT_STOP_SCAN: btc_ble_stop_scanning(); break; case BTC_GAP_BLE_ACT_START_ADV: - btc_ble_start_advertising(&arg->start_adv.adv_params); + btc_ble_start_advertising(&arg->start_adv.adv_params, btc_start_adv_callback); break; case BTC_GAP_BLE_ACT_STOP_ADV: btc_ble_stop_advertising(); diff --git a/components/bt/bluedroid/stack/btm/btm_ble_gap.c b/components/bt/bluedroid/stack/btm/btm_ble_gap.c index 4cfce3b66..07c63b496 100644 --- a/components/bt/bluedroid/stack/btm/btm_ble_gap.c +++ b/components/bt/bluedroid/stack/btm/btm_ble_gap.c @@ -2935,14 +2935,18 @@ tBTM_STATUS btm_ble_start_scan(void) tBTM_BLE_INQ_CB *p_inq = &btm_cb.ble_ctr_cb.inq_var; tBTM_STATUS status = BTM_CMD_STARTED; - /* start scan, disable duplicate filtering */ - if (!btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_ENABLE, p_inq->scan_duplicate_filter)) { + if (p_inq->adv_mode != BTM_BLE_ADV_DISABLE) { status = BTM_NO_RESOURCES; } else { - if (p_inq->scan_type == BTM_BLE_SCAN_MODE_ACTI) { - btm_ble_set_topology_mask(BTM_BLE_STATE_ACTIVE_SCAN_BIT); + /* start scan, disable duplicate filtering */ + if (!btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_ENABLE, p_inq->scan_duplicate_filter)) { + status = BTM_NO_RESOURCES; } else { - btm_ble_set_topology_mask(BTM_BLE_STATE_PASSIVE_SCAN_BIT); + if (p_inq->scan_type == BTM_BLE_SCAN_MODE_ACTI) { + btm_ble_set_topology_mask(BTM_BLE_STATE_ACTIVE_SCAN_BIT); + } else { + btm_ble_set_topology_mask(BTM_BLE_STATE_PASSIVE_SCAN_BIT); + } } } return status; @@ -2961,15 +2965,17 @@ void btm_ble_stop_scan(void) { BTM_TRACE_EVENT ("btm_ble_stop_scan "); - /* Clear the inquiry callback if set */ - btm_cb.ble_ctr_cb.inq_var.scan_type = BTM_BLE_SCAN_MODE_NONE; + if (btm_cb.ble_ctr_cb.inq_var.adv_mode == BTM_BLE_ADV_DISABLE) { + /* Clear the inquiry callback if set */ + btm_cb.ble_ctr_cb.inq_var.scan_type = BTM_BLE_SCAN_MODE_NONE; - /* stop discovery now */ - btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE); + /* stop discovery now */ + btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE); - btm_update_scanner_filter_policy(SP_ADV_ALL); + btm_update_scanner_filter_policy(SP_ADV_ALL); - btm_cb.ble_ctr_cb.wl_state &= ~BTM_BLE_WL_SCAN; + btm_cb.ble_ctr_cb.wl_state &= ~BTM_BLE_WL_SCAN; + } } /******************************************************************************* ** @@ -3089,9 +3095,15 @@ static BOOLEAN btm_ble_adv_states_operation(BTM_TOPOLOGY_FUNC_PTR *p_handler, UI *******************************************************************************/ tBTM_STATUS btm_ble_start_adv(void) { + tBTM_BLE_CB *p_ble_cb = & btm_cb.ble_ctr_cb; tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var; tBTM_STATUS rt = BTM_NO_RESOURCES; BTM_TRACE_EVENT ("btm_ble_start_adv\n"); + + if (BTM_BLE_IS_OBS_ACTIVE(p_ble_cb->scan_activity)) { + return BTM_NO_RESOURCES; + } + if (!btm_ble_adv_states_operation (btm_ble_topology_check, p_cb->evt_type)) { return BTM_WRONG_MODE; } @@ -3133,10 +3145,12 @@ tBTM_STATUS btm_ble_start_adv(void) *******************************************************************************/ tBTM_STATUS btm_ble_stop_adv(void) { + tBTM_BLE_CB *p_ble_cb = & btm_cb.ble_ctr_cb; tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var; tBTM_STATUS rt = BTM_SUCCESS; - if (p_cb->adv_mode == BTM_BLE_ADV_ENABLE) { + if (p_cb->adv_mode == BTM_BLE_ADV_ENABLE + && !BTM_BLE_IS_OBS_ACTIVE(p_ble_cb->scan_activity)) { if (btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_DISABLE)) { p_cb->fast_adv_on = FALSE; p_cb->adv_mode = BTM_BLE_ADV_DISABLE; diff --git a/docs/api/bluetooth/esp_gap_ble.rst b/docs/api/bluetooth/esp_gap_ble.rst index fea937630..41bffa095 100644 --- a/docs/api/bluetooth/esp_gap_ble.rst +++ b/docs/api/bluetooth/esp_gap_ble.rst @@ -93,6 +93,12 @@ Structures .. doxygenstruct:: esp_ble_gap_cb_param_t::ble_scan_rsp_data_raw_cmpl_evt_param :members: +.. doxygenstruct:: esp_ble_gap_cb_param_t::ble_adv_start_cmpl_evt_param + :members: + +.. doxygenstruct:: esp_ble_gap_cb_param_t::ble_scan_start_cmpl_evt_param + :members: + Functions ^^^^^^^^^ diff --git a/examples/bluetooth/gatt_client/main/gattc_demo.c b/examples/bluetooth/gatt_client/main/gattc_demo.c index 4a2fa0051..290448491 100644 --- a/examples/bluetooth/gatt_client/main/gattc_demo.c +++ b/examples/bluetooth/gatt_client/main/gattc_demo.c @@ -295,6 +295,12 @@ static void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *par esp_ble_gap_start_scanning(duration); break; } + case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT: + //scan start complete event to indicate scan start successfully or failed + if (param->scan_start_cmpl.status != ESP_BT_STATUS_SUCCESS) { + ESP_LOGE(GATTC_TAG, "Scan start failed\n"); + } + break; case ESP_GAP_BLE_SCAN_RESULT_EVT: { esp_ble_gap_cb_param_t *scan_result = (esp_ble_gap_cb_param_t *)param; switch (scan_result->scan_rst.search_evt) { diff --git a/examples/bluetooth/gatt_server/main/gatts_demo.c b/examples/bluetooth/gatt_server/main/gatts_demo.c index acbf9195a..39d33286a 100644 --- a/examples/bluetooth/gatt_server/main/gatts_demo.c +++ b/examples/bluetooth/gatt_server/main/gatts_demo.c @@ -151,6 +151,12 @@ static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param case ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT: esp_ble_gap_start_advertising(&test_adv_params); break; + case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: + //advertising start complete event to indicate advertising start successfully or failed + if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) { + ESP_LOGE(GATTS_TAG, "Advertising start failed\n"); + } + break; default: break; } diff --git a/examples/bluetooth/gatt_server_service_table/main/gatts_table_creat_demo.c b/examples/bluetooth/gatt_server_service_table/main/gatts_table_creat_demo.c index 71baf1842..9bb03e7e8 100644 --- a/examples/bluetooth/gatt_server_service_table/main/gatts_table_creat_demo.c +++ b/examples/bluetooth/gatt_server_service_table/main/gatts_table_creat_demo.c @@ -203,6 +203,12 @@ static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: esp_ble_gap_start_advertising(&heart_rate_adv_params); break; + case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: + //advertising start complete event to indicate advertising start successfully or failed + if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) { + ESP_LOGE(GATTS_TABLE_TAG, "Advertising start failed\n"); + } + break; default: break; } From eb1fbaabce08d9ff405e06b759748c6d09c08b14 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Fri, 24 Feb 2017 14:45:17 +1100 Subject: [PATCH 038/112] lwip: Refactor support for L2 pbuf free notification into each driver Makes it easier to handle different drivers enabled at compile/link time. --- components/lwip/core/pbuf.c | 24 +++++++++-------------- components/lwip/include/lwip/lwip/netif.h | 4 ++++ components/lwip/include/lwip/lwip/pbuf.h | 12 +++--------- components/lwip/port/netif/ethernetif.c | 14 ++++++++----- components/lwip/port/netif/wlanif.c | 10 +++++++--- 5 files changed, 32 insertions(+), 32 deletions(-) diff --git a/components/lwip/core/pbuf.c b/components/lwip/core/pbuf.c index b95481749..84dcc3103 100755 --- a/components/lwip/core/pbuf.c +++ b/components/lwip/core/pbuf.c @@ -78,11 +78,6 @@ #include -#if ESP_LWIP -#include "esp_wifi_internal.h" -#include "esp_eth.h" -#endif - #define SIZEOF_STRUCT_PBUF LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf)) /* Since the pool is created in memp, PBUF_POOL_BUFSIZE will be automatically aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */ @@ -350,10 +345,10 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) p->ref = 1; /* set flags */ p->flags = 0; - + #if ESP_LWIP - p->user_buf = NULL; - p->user_flag = PBUF_USER_FLAG_OWNER_NULL; + p->l2_owner = NULL; + p->l2_buf = NULL; #endif LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p)); @@ -720,14 +715,13 @@ pbuf_free(struct pbuf *p) memp_free(MEMP_PBUF_POOL, p); /* is this a ROM or RAM referencing pbuf? */ } else if (type == PBUF_ROM || type == PBUF_REF) { - + #if ESP_LWIP - if (type == PBUF_REF && p->user_flag == PBUF_USER_FLAG_OWNER_WIFI ) { - esp_wifi_internal_free_rx_buffer(p->user_buf); - } - if (type == PBUF_REF && p->user_flag == PBUF_USER_FLAG_OWNER_ETH ) { - esp_eth_free_rx_buf(p->user_buf); - } + if (p->l2_owner != NULL + && p->l2_buf != NULL + && p->l2_owner->l2_buffer_free_notify != NULL) { + p->l2_owner->l2_buffer_free_notify(p->l2_buf); + } #endif memp_free(MEMP_PBUF, p); /* type == PBUF_RAM */ diff --git a/components/lwip/include/lwip/lwip/netif.h b/components/lwip/include/lwip/lwip/netif.h index 34e6d4489..13cbb798e 100755 --- a/components/lwip/include/lwip/lwip/netif.h +++ b/components/lwip/include/lwip/lwip/netif.h @@ -330,6 +330,10 @@ struct netif { u16_t loop_cnt_current; #endif /* LWIP_LOOPBACK_MAX_PBUFS */ #endif /* ENABLE_LOOPBACK */ + +#if ESP_LWIP + void (*l2_buffer_free_notify)(void *user_buf); /* Allows LWIP to notify driver when a L2-supplied pbuf can be freed */ +#endif }; #if LWIP_CHECKSUM_CTRL_PER_NETIF diff --git a/components/lwip/include/lwip/lwip/pbuf.h b/components/lwip/include/lwip/lwip/pbuf.h index d84aabaf8..42146f6fc 100755 --- a/components/lwip/include/lwip/lwip/pbuf.h +++ b/components/lwip/include/lwip/lwip/pbuf.h @@ -105,12 +105,6 @@ typedef enum { /** indicates this pbuf includes a TCP FIN flag */ #define PBUF_FLAG_TCP_FIN 0x20U -#if ESP_LWIP -#define PBUF_USER_FLAG_OWNER_NULL 0 -#define PBUF_USER_FLAG_OWNER_WIFI 1 -#define PBUF_USER_FLAG_OWNER_ETH 2 -#endif - struct pbuf { /** next pbuf in singly linked pbuf chain */ struct pbuf *next; @@ -142,10 +136,10 @@ struct pbuf { * the stack itself, or pbuf->next pointers from a chain. */ u16_t ref; - + #if ESP_LWIP - void *user_buf; - u8_t user_flag; + struct netif *l2_owner; + void *l2_buf; #endif }; diff --git a/components/lwip/port/netif/ethernetif.c b/components/lwip/port/netif/ethernetif.c index 90a5b241b..1930c5e4b 100644 --- a/components/lwip/port/netif/ethernetif.c +++ b/components/lwip/port/netif/ethernetif.c @@ -82,7 +82,10 @@ ethernet_low_level_init(struct netif *netif) netif->flags |= NETIF_FLAG_IGMP; #endif #endif - /* Do whatever else is needed to initialize interface. */ + +#ifndef CONFIG_EMAC_L2_TO_L3_RX_BUF_MODE + netif->l2_buffer_free_notify = esp_eth_free_rx_buf; +#endif } /** @@ -152,11 +155,12 @@ ethernetif_input(struct netif *netif, void *buffer, uint16_t len) if(buffer== NULL || netif == NULL) goto _exit; -#if CONFIG_EMAC_L2_TO_L3_RX_BUF_MODE +#ifdef CONFIG_EMAC_L2_TO_L3_RX_BUF_MODE p = pbuf_alloc(PBUF_RAW, len, PBUF_RAM); if (p == NULL) { return; } + p->l2_owner = NULL; memcpy(p->payload, buffer, len); /* full packet send to tcpip_thread to process */ @@ -171,13 +175,13 @@ if (netif->input(p, netif) != ERR_OK) { return; } p->payload = buffer; - p->user_flag = PBUF_USER_FLAG_OWNER_ETH; - p->user_buf = buffer; + p->l2_owner = netif; + p->l2_buf = buffer; /* full packet send to tcpip_thread to process */ if (netif->input(p, netif) != ERR_OK) { LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); - p->user_flag = PBUF_USER_FLAG_OWNER_NULL; + p->l2_owner = NULL; pbuf_free(p); } #endif diff --git a/components/lwip/port/netif/wlanif.c b/components/lwip/port/netif/wlanif.c index f9def4921..9f454230a 100644 --- a/components/lwip/port/netif/wlanif.c +++ b/components/lwip/port/netif/wlanif.c @@ -84,7 +84,9 @@ low_level_init(struct netif *netif) #endif #endif - /* Do whatever else is needed to initialize interface. */ +#if !ESP_L2_TO_L3_COPY + netif->l2_buffer_free_notify = esp_wifi_internal_free_rx_buffer; +#endif } /** @@ -119,6 +121,7 @@ low_level_output(struct netif *netif, struct pbuf *p) LWIP_DEBUGF(PBUF_DEBUG, ("low_level_output: pbuf is a list, application may has bug")); q = pbuf_alloc(PBUF_RAW_TX, p->tot_len, PBUF_RAM); if (q != NULL) { + q->l2_owner = NULL; pbuf_copy(q, p); } else { return ERR_MEM; @@ -154,6 +157,7 @@ wlanif_input(struct netif *netif, void *buffer, u16_t len, void* eb) esp_wifi_internal_free_rx_buffer(eb); return; } + p->l2_owner = NULL; memcpy(p->payload, buffer, len); esp_wifi_internal_free_rx_buffer(eb); #else @@ -163,8 +167,8 @@ wlanif_input(struct netif *netif, void *buffer, u16_t len, void* eb) return; } p->payload = buffer; - p->user_buf = eb; - p->user_flag = PBUF_USER_FLAG_OWNER_WIFI; + p->l2_owner = netif; + p->l2_buf = eb; #endif /* full packet send to tcpip_thread to process */ From d9252b36451bbbea5357024cf72a0e7439ecb1a1 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Fri, 24 Feb 2017 14:46:23 +1100 Subject: [PATCH 039/112] wifi event_default_handlers/tcpip_adapter: Support disabling WiFi, keeping Ethernet --- components/esp32/event_default_handlers.c | 82 ++++++++++--------- components/tcpip_adapter/tcpip_adapter_lwip.c | 30 +++++-- 2 files changed, 68 insertions(+), 44 deletions(-) diff --git a/components/esp32/event_default_handlers.c b/components/esp32/event_default_handlers.c index c09775ab9..0c7ec2ac5 100644 --- a/components/esp32/event_default_handlers.c +++ b/components/esp32/event_default_handlers.c @@ -45,14 +45,9 @@ do{\ }\ } while(0) -typedef esp_err_t (*system_event_handle_fn_t)(system_event_t *e); - -typedef struct { - system_event_id_t event_id; - system_event_handle_fn_t event_handle; -} system_event_handle_t; - +typedef esp_err_t (*system_event_handler_t)(system_event_t *e); +#ifdef CONFIG_WIFI_ENABLED static esp_err_t system_event_ap_start_handle_default(system_event_t *event); static esp_err_t system_event_ap_stop_handle_default(system_event_t *event); static esp_err_t system_event_sta_start_handle_default(system_event_t *event); @@ -60,39 +55,50 @@ static esp_err_t system_event_sta_stop_handle_default(system_event_t *event); static esp_err_t system_event_sta_connected_handle_default(system_event_t *event); static esp_err_t system_event_sta_disconnected_handle_default(system_event_t *event); static esp_err_t system_event_sta_got_ip_default(system_event_t *event); +#endif +#ifdef CONFIG_ETHERNET static esp_err_t system_event_eth_start_handle_default(system_event_t *event); static esp_err_t system_event_eth_stop_handle_default(system_event_t *event); static esp_err_t system_event_eth_connected_handle_default(system_event_t *event); static esp_err_t system_event_eth_disconnected_handle_default(system_event_t *event); +#endif -static system_event_handle_t g_system_event_handle_table[] = { - {SYSTEM_EVENT_WIFI_READY, NULL}, - {SYSTEM_EVENT_SCAN_DONE, NULL}, - {SYSTEM_EVENT_STA_START, system_event_sta_start_handle_default}, - {SYSTEM_EVENT_STA_STOP, system_event_sta_stop_handle_default}, - {SYSTEM_EVENT_STA_CONNECTED, system_event_sta_connected_handle_default}, - {SYSTEM_EVENT_STA_DISCONNECTED, system_event_sta_disconnected_handle_default}, - {SYSTEM_EVENT_STA_AUTHMODE_CHANGE, NULL}, - {SYSTEM_EVENT_STA_GOT_IP, system_event_sta_got_ip_default}, - {SYSTEM_EVENT_STA_WPS_ER_SUCCESS, NULL}, - {SYSTEM_EVENT_STA_WPS_ER_FAILED, NULL}, - {SYSTEM_EVENT_STA_WPS_ER_TIMEOUT, NULL}, - {SYSTEM_EVENT_STA_WPS_ER_PIN, NULL}, - {SYSTEM_EVENT_AP_START, system_event_ap_start_handle_default}, - {SYSTEM_EVENT_AP_STOP, system_event_ap_stop_handle_default}, - {SYSTEM_EVENT_AP_STACONNECTED, NULL}, - {SYSTEM_EVENT_AP_STADISCONNECTED, NULL}, - {SYSTEM_EVENT_AP_PROBEREQRECVED, NULL}, - {SYSTEM_EVENT_AP_STA_GOT_IP6, NULL}, - {SYSTEM_EVENT_ETH_START, system_event_eth_start_handle_default}, - {SYSTEM_EVENT_ETH_STOP, system_event_eth_stop_handle_default}, - {SYSTEM_EVENT_ETH_CONNECTED, system_event_eth_connected_handle_default}, - {SYSTEM_EVENT_ETH_DISCONNECTED, system_event_eth_disconnected_handle_default}, - {SYSTEM_EVENT_ETH_GOT_IP, NULL}, - {SYSTEM_EVENT_MAX, NULL}, +/* Default event handler functions + + Any entry in this table which is disabled by config will have a NULL handler. +*/ +static const system_event_handler_t default_event_handlers[SYSTEM_EVENT_MAX] = { +#ifdef CONFIG_WIFI_ENABLED + [SYSTEM_EVENT_WIFI_READY] = NULL, + [SYSTEM_EVENT_SCAN_DONE] = NULL, + [SYSTEM_EVENT_STA_START] = system_event_sta_start_handle_default, + [SYSTEM_EVENT_STA_STOP] = system_event_sta_stop_handle_default, + [SYSTEM_EVENT_STA_CONNECTED] = system_event_sta_connected_handle_default, + [SYSTEM_EVENT_STA_DISCONNECTED] = system_event_sta_disconnected_handle_default, + [SYSTEM_EVENT_STA_AUTHMODE_CHANGE] = NULL, + [SYSTEM_EVENT_STA_GOT_IP] = system_event_sta_got_ip_default, + [SYSTEM_EVENT_STA_WPS_ER_SUCCESS] = NULL, + [SYSTEM_EVENT_STA_WPS_ER_FAILED] = NULL, + [SYSTEM_EVENT_STA_WPS_ER_TIMEOUT] = NULL, + [SYSTEM_EVENT_STA_WPS_ER_PIN] = NULL, + [SYSTEM_EVENT_AP_START] = system_event_ap_start_handle_default, + [SYSTEM_EVENT_AP_STOP] = system_event_ap_stop_handle_default, + [SYSTEM_EVENT_AP_STACONNECTED] = NULL, + [SYSTEM_EVENT_AP_STADISCONNECTED] = NULL, + [SYSTEM_EVENT_AP_PROBEREQRECVED] = NULL, + [SYSTEM_EVENT_AP_STA_GOT_IP6] = NULL, +#endif +#ifdef CONFIG_ETHERNET + [SYSTEM_EVENT_ETH_START] = system_event_eth_start_handle_default, + [SYSTEM_EVENT_ETH_STOP] = system_event_eth_stop_handle_default, + [SYSTEM_EVENT_ETH_CONNECTED] = system_event_eth_connected_handle_default, + [SYSTEM_EVENT_ETH_DISCONNECTED] = system_event_eth_disconnected_handle_default, + [SYSTEM_EVENT_ETH_GOT_IP] = NULL, +#endif }; +#ifdef CONFIG_ETHERNET esp_err_t system_event_eth_start_handle_default(system_event_t *event) { tcpip_adapter_ip_info_t eth_ip; @@ -121,7 +127,6 @@ esp_err_t system_event_eth_connected_handle_default(system_event_t *event) tcpip_adapter_dhcpc_get_status(TCPIP_ADAPTER_IF_ETH, &status); if (status == TCPIP_ADAPTER_DHCP_INIT) { - tcpip_adapter_dhcpc_start(TCPIP_ADAPTER_IF_ETH); } else if (status == TCPIP_ADAPTER_DHCP_STOPPED) { tcpip_adapter_ip_info_t eth_ip; @@ -149,9 +154,9 @@ esp_err_t system_event_eth_disconnected_handle_default(system_event_t *event) tcpip_adapter_down(TCPIP_ADAPTER_IF_ETH); return ESP_OK; } +#endif - - +#ifdef CONFIG_WIFI_ENABLED static esp_err_t system_event_sta_got_ip_default(system_event_t *event) { WIFI_API_CALL_CHECK("esp_wifi_internal_set_sta_ip", esp_wifi_internal_set_sta_ip(), ESP_OK); @@ -245,6 +250,7 @@ esp_err_t system_event_sta_disconnected_handle_default(system_event_t *event) WIFI_API_CALL_CHECK("esp_wifi_internal_reg_rxcb", esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_STA, NULL), ESP_OK); return ESP_OK; } +#endif static esp_err_t esp_system_event_debug(system_event_t *event) { @@ -377,10 +383,10 @@ esp_err_t esp_event_process_default(system_event_t *event) } esp_system_event_debug(event); - if ((event->event_id < SYSTEM_EVENT_MAX) && (event->event_id == g_system_event_handle_table[event->event_id].event_id)) { - if (g_system_event_handle_table[event->event_id].event_handle) { + if ((event->event_id < SYSTEM_EVENT_MAX)) { + if (default_event_handlers[event->event_id] != NULL) { ESP_LOGV(TAG, "enter default callback"); - g_system_event_handle_table[event->event_id].event_handle(event); + default_event_handlers[event->event_id](event); ESP_LOGV(TAG, "exit default callback"); } } else { diff --git a/components/tcpip_adapter/tcpip_adapter_lwip.c b/components/tcpip_adapter/tcpip_adapter_lwip.c index 40f235d54..80a0ba132 100644 --- a/components/tcpip_adapter/tcpip_adapter_lwip.c +++ b/components/tcpip_adapter/tcpip_adapter_lwip.c @@ -60,8 +60,27 @@ void tcpip_adapter_init(void) } } +static netif_init_fn tcpip_if_to_netif_init_fn(tcpip_adapter_if_t tcpip_if) +{ + switch(tcpip_if) { +#ifdef CONFIG_WIFI_ENABLED + case TCPIP_ADAPTER_IF_AP: + case TCPIP_ADAPTER_IF_STA: + return wlanif_init; +#endif +#ifdef CONFIG_ETHERNET + case TCPIP_ADAPTER_IF_ETH: + return ethernetif_init; +#endif + default: + return NULL; + } +} + esp_err_t tcpip_adapter_start(tcpip_adapter_if_t tcpip_if, uint8_t *mac, tcpip_adapter_ip_info_t *ip_info) { + netif_init_fn netif_init; + if (tcpip_if >= TCPIP_ADAPTER_IF_MAX || mac == NULL || ip_info == NULL) { return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS; } @@ -72,11 +91,10 @@ esp_err_t tcpip_adapter_start(tcpip_adapter_if_t tcpip_if, uint8_t *mac, tcpip_a return ESP_ERR_NO_MEM; } memcpy(esp_netif[tcpip_if]->hwaddr, mac, NETIF_MAX_HWADDR_LEN); - if (tcpip_if == TCPIP_ADAPTER_IF_AP || tcpip_if == TCPIP_ADAPTER_IF_STA) { - netif_add(esp_netif[tcpip_if], &ip_info->ip, &ip_info->netmask, &ip_info->gw, NULL, wlanif_init, tcpip_input); - } else if (tcpip_if == TCPIP_ADAPTER_IF_ETH) { - netif_add(esp_netif[tcpip_if], &ip_info->ip, &ip_info->netmask, &ip_info->gw, NULL, ethernetif_init, tcpip_input); - } + + netif_init = tcpip_if_to_netif_init_fn(tcpip_if); + assert(netif_init != NULL); + netif_add(esp_netif[tcpip_if], &ip_info->ip, &ip_info->netmask, &ip_info->gw, NULL, netif_init, tcpip_input); } if (tcpip_if == TCPIP_ADAPTER_IF_AP) { @@ -757,4 +775,4 @@ esp_err_t tcpip_adapter_get_hostname(tcpip_adapter_if_t tcpip_if, const char **h #endif } -#endif +#endif /* CONFIG_TCPIP_LWIP */ From fd0edae75a4dafc4dc46369ce96ee89a91a22cc4 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Fri, 24 Feb 2017 14:56:29 +1100 Subject: [PATCH 040/112] ethernet example: Disable WiFi, enable Ethernet in default config Ref: https://esp32.com/viewtopic.php?f=2&t=1249 --- examples/ethernet/ethernet/sdkconfig.defaults | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 examples/ethernet/ethernet/sdkconfig.defaults diff --git a/examples/ethernet/ethernet/sdkconfig.defaults b/examples/ethernet/ethernet/sdkconfig.defaults new file mode 100644 index 000000000..b4f4c3c1c --- /dev/null +++ b/examples/ethernet/ethernet/sdkconfig.defaults @@ -0,0 +1,2 @@ +# CONFIG_WIFI_ENABLED is not set +CONFIG_ETHERNET=y From ff81e1750449474e710b5dc291c017bbd59d7bb3 Mon Sep 17 00:00:00 2001 From: qiyueixa Date: Fri, 24 Feb 2017 15:19:31 +0800 Subject: [PATCH 041/112] wifi: fix issue in setting channel before sniffer is enabled --- components/esp32/include/esp_wifi.h | 1 + components/esp32/lib | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/components/esp32/include/esp_wifi.h b/components/esp32/include/esp_wifi.h index 0f7e2996e..9f3b1ed70 100755 --- a/components/esp32/include/esp_wifi.h +++ b/components/esp32/include/esp_wifi.h @@ -422,6 +422,7 @@ esp_err_t esp_wifi_get_bandwidth(wifi_interface_t ifx, wifi_bandwidth_t *bw); * @brief Set primary/secondary channel of ESP32 * * @attention 1. This is a special API for sniffer + * @attention 2. This API should be called after esp_wifi_start() or esp_wifi_set_promiscuous() * * @param primary for HT20, primary is the channel number, for HT40, primary is the primary channel * @param second for HT20, second is ignored, for HT40, second is the second channel diff --git a/components/esp32/lib b/components/esp32/lib index ed85cf915..0be74cb72 160000 --- a/components/esp32/lib +++ b/components/esp32/lib @@ -1 +1 @@ -Subproject commit ed85cf9156f2ef358c29d07fb849a73c5758eecb +Subproject commit 0be74cb72fba4502a685c9f0df26689592018f78 From c17e05040ae6c18895a414950538ddfd5e9c5419 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Fri, 24 Feb 2017 21:04:22 +0800 Subject: [PATCH 042/112] vfs_fat_sdmmc: if card init fails, fail cleanly This fixes the issue with sdmmc_host not returned to clean state after a failed attempt to mount the card, with no SD card in the slot. --- components/fatfs/src/vfs_fat_sdmmc.c | 12 +++++++++--- components/fatfs/test/test_fatfs.c | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/components/fatfs/src/vfs_fat_sdmmc.c b/components/fatfs/src/vfs_fat_sdmmc.c index e5956dd7b..77620f5d8 100644 --- a/components/fatfs/src/vfs_fat_sdmmc.c +++ b/components/fatfs/src/vfs_fat_sdmmc.c @@ -39,14 +39,19 @@ esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path, sdmmc_host_init(); // enable card slot - sdmmc_host_init_slot(host_config->slot, slot_config); + esp_err_t err = sdmmc_host_init_slot(host_config->slot, slot_config); + if (err != ESP_OK) { + return err; + } + s_card = malloc(sizeof(sdmmc_card_t)); if (s_card == NULL) { - return ESP_ERR_NO_MEM; + err = ESP_ERR_NO_MEM; + goto fail; } // probe and initialize card - esp_err_t err = sdmmc_card_init(host_config, s_card); + err = sdmmc_card_init(host_config, s_card); if (err != ESP_OK) { ESP_LOGD(TAG, "sdmmc_card_init failed 0x(%x)", err); goto fail; @@ -104,6 +109,7 @@ esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path, return ESP_OK; fail: + sdmmc_host_deinit(); free(workbuf); esp_vfs_unregister(base_path); free(s_card); diff --git a/components/fatfs/test/test_fatfs.c b/components/fatfs/test/test_fatfs.c index 4f6482740..d518652bc 100644 --- a/components/fatfs/test/test_fatfs.c +++ b/components/fatfs/test/test_fatfs.c @@ -52,6 +52,25 @@ static void create_file_with_text(const char* name, const char* text) TEST_ASSERT_EQUAL(0, fclose(f)); } +TEST_CASE("Mount fails cleanly without card inserted", "[fatfs][ignore]") +{ + HEAP_SIZE_CAPTURE(); + sdmmc_host_t host = SDMMC_HOST_DEFAULT(); + sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); + esp_vfs_fat_sdmmc_mount_config_t mount_config = { + .format_if_mount_failed = false, + .max_files = 5 + }; + + for (int i = 0; i < 3; ++i) { + printf("Initializing card, attempt %d ", i); + esp_err_t err = esp_vfs_fat_sdmmc_mount("/sdcard", &host, &slot_config, &mount_config, NULL); + printf(" err=%d\n", err); + TEST_ESP_ERR(ESP_FAIL, err); + } + HEAP_SIZE_CHECK(0); +} + TEST_CASE("can create and write file on sd card", "[fatfs][ignore]") { HEAP_SIZE_CAPTURE(); From 75115e1d83134e7647934e94ad2526adcc955986 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Fri, 24 Feb 2017 21:50:05 +0800 Subject: [PATCH 043/112] spi_flash: fix mmap not working for SPI_FLASH_MMAP_INST --- components/spi_flash/flash_mmap.c | 4 +-- components/spi_flash/test/test_mmap.c | 46 +++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/components/spi_flash/flash_mmap.c b/components/spi_flash/flash_mmap.c index f8d2e3297..8d284c60a 100644 --- a/components/spi_flash/flash_mmap.c +++ b/components/spi_flash/flash_mmap.c @@ -122,7 +122,7 @@ esp_err_t IRAM_ATTR spi_flash_mmap(size_t src_addr, size_t size, spi_flash_mmap_ region_addr = VADDR0_START_ADDR; } else { // only part of VAddr1 is usable, so adjust for that - region_begin = VADDR1_FIRST_USABLE_ADDR; + region_begin = PRO_IRAM0_FIRST_USABLE_PAGE; region_size = 3 * 64 - region_begin; region_addr = VADDR1_FIRST_USABLE_ADDR; } @@ -177,7 +177,7 @@ esp_err_t IRAM_ATTR spi_flash_mmap(size_t src_addr, size_t size, spi_flash_mmap_ new_entry->count = page_count; new_entry->handle = ++s_mmap_last_handle; *out_handle = new_entry->handle; - *out_ptr = (void*) (region_addr + start * SPI_FLASH_MMU_PAGE_SIZE); + *out_ptr = (void*) (region_addr + (start - region_begin) * SPI_FLASH_MMU_PAGE_SIZE); ret = ESP_OK; } diff --git a/components/spi_flash/test/test_mmap.c b/components/spi_flash/test/test_mmap.c index 464a87642..7d9689fea 100644 --- a/components/spi_flash/test/test_mmap.c +++ b/components/spi_flash/test/test_mmap.c @@ -86,6 +86,52 @@ TEST_CASE("Can mmap into data address space", "[mmap]") spi_flash_munmap(handle3); } +TEST_CASE("Can mmap into instruction address space", "[mmap]") +{ + printf("Mapping %x (+%x)\n", start, end - start); + spi_flash_mmap_handle_t handle1; + const void *ptr1; + ESP_ERROR_CHECK( spi_flash_mmap(start, end - start, SPI_FLASH_MMAP_INST, &ptr1, &handle1) ); + printf("mmap_res: handle=%d ptr=%p\n", handle1, ptr1); + + spi_flash_mmap_dump(); + + srand(0); + const uint32_t *data = (const uint32_t *) ptr1; + for (int block = 0; block < (end - start) / 0x10000; ++block) { + for (int sector = 0; sector < 16; ++sector) { + for (uint32_t word = 0; word < 1024; ++word) { + TEST_ASSERT_EQUAL_UINT32(rand(), data[(block * 16 + sector) * 1024 + word]); + } + } + } + printf("Mapping %x (+%x)\n", start - 0x10000, 0x20000); + spi_flash_mmap_handle_t handle2; + const void *ptr2; + ESP_ERROR_CHECK( spi_flash_mmap(start - 0x10000, 0x20000, SPI_FLASH_MMAP_DATA, &ptr2, &handle2) ); + printf("mmap_res: handle=%d ptr=%p\n", handle2, ptr2); + spi_flash_mmap_dump(); + + printf("Mapping %x (+%x)\n", start, 0x10000); + spi_flash_mmap_handle_t handle3; + const void *ptr3; + ESP_ERROR_CHECK( spi_flash_mmap(start, 0x10000, SPI_FLASH_MMAP_DATA, &ptr3, &handle3) ); + printf("mmap_res: handle=%d ptr=%p\n", handle3, ptr3); + spi_flash_mmap_dump(); + + printf("Unmapping handle1\n"); + spi_flash_munmap(handle1); + spi_flash_mmap_dump(); + + printf("Unmapping handle2\n"); + spi_flash_munmap(handle2); + spi_flash_mmap_dump(); + + printf("Unmapping handle3\n"); + spi_flash_munmap(handle3); + +} + TEST_CASE("flash_mmap invalidates just-written data", "[spi_flash]") { spi_flash_mmap_handle_t handle1; From d9c649d26e071811c1777020c2f0ac0e0bda36ce Mon Sep 17 00:00:00 2001 From: qiyueixa Date: Fri, 24 Feb 2017 22:08:54 +0800 Subject: [PATCH 044/112] wifi: fix issue in setting channel API --- components/esp32/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp32/lib b/components/esp32/lib index 0be74cb72..28c6ee924 160000 --- a/components/esp32/lib +++ b/components/esp32/lib @@ -1 +1 @@ -Subproject commit 0be74cb72fba4502a685c9f0df26689592018f78 +Subproject commit 28c6ee924ca6efc71bb77dcb040efd07d4d8a000 From 3050f06a8ddc30a70d5b4752b38aa51755a64160 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Mon, 27 Feb 2017 11:46:16 +1100 Subject: [PATCH 045/112] FreeRTOS: Support setting task name max length Ref: https://esp32.com/viewtopic.php?f=13&t=1297&p=5762 --- components/freertos/Kconfig | 11 +++++++++++ components/freertos/include/freertos/FreeRTOSConfig.h | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/components/freertos/Kconfig b/components/freertos/Kconfig index ee2b289ef..c28287644 100644 --- a/components/freertos/Kconfig +++ b/components/freertos/Kconfig @@ -164,6 +164,17 @@ config FREERTOS_LEGACY_TICK_HOOK endif #FREERTOS_LEGACY_HOOKS +config FREERTOS_MAX_TASK_NAME_LEN + int "Maximum task name length" + range 1 256 + default 16 + help + Changes the maximum task name length. Each task allocated will + include this many bytes for a task name. Using a shorter value + saves a small amount of RAM, a longer value allows more complex + names. + + For most uses, the default of 16 is OK. menuconfig FREERTOS_DEBUG_INTERNALS bool "Debug FreeRTOS internals" diff --git a/components/freertos/include/freertos/FreeRTOSConfig.h b/components/freertos/include/freertos/FreeRTOSConfig.h index 9deb9f4b5..4f4033039 100644 --- a/components/freertos/include/freertos/FreeRTOSConfig.h +++ b/components/freertos/include/freertos/FreeRTOSConfig.h @@ -187,7 +187,7 @@ #define configAPPLICATION_ALLOCATED_HEAP 1 #define configTOTAL_HEAP_SIZE (&_heap_end - &_heap_start)//( ( size_t ) (64 * 1024) ) -#define configMAX_TASK_NAME_LEN ( 16 ) +#define configMAX_TASK_NAME_LEN ( CONFIG_FREERTOS_MAX_TASK_NAME_LEN ) #define configUSE_TRACE_FACILITY 0 /* Used by vTaskList in main.c */ #define configUSE_STATS_FORMATTING_FUNCTIONS 0 /* Used by vTaskList in main.c */ #define configUSE_TRACE_FACILITY_2 0 /* Provided by Xtensa port patch */ From 47a5851d4599498c5a1f9b612242b9362bb9250f Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Mon, 27 Feb 2017 11:49:46 +1100 Subject: [PATCH 046/112] freertos: Move the "set debug watchpoint as stack overflow check" out of debugging internals Place it near the other stack overflow kconfig items, instead. --- components/freertos/Kconfig | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/components/freertos/Kconfig b/components/freertos/Kconfig index c28287644..04821cd5f 100644 --- a/components/freertos/Kconfig +++ b/components/freertos/Kconfig @@ -76,6 +76,24 @@ config FREERTOS_CHECK_STACKOVERFLOW_CANARY (configCHECK_FOR_STACK_OVERFLOW=2) endchoice +config FREERTOS_WATCHPOINT_END_OF_STACK + bool "Set a debug watchpoint as a stack overflow check" + default n + help + FreeRTOS can check if a stack has overflown its bounds by checking either the value of + the stack pointer or by checking the integrity of canary bytes. (See FREERTOS_CHECK_STACKOVERFLOW + for more information.) These checks only happen on a context switch, and the situation that caused + the stack overflow may already be long gone by then. This option will use the debug memory + watchpoint 1 (the second one) to allow breaking into the debugger (or panic'ing) as soon as any + of the last 32 bytes on the stack of a task are overwritten. The side effect is that using gdb, you + effectively only have one watchpoint; the 2nd one is overwritten as soon as a task switch happens. + + This check only triggers if the stack overflow writes within 4 bytes of the end of the stack, rather than + overshooting further, so it is worth combining this approach with one of the other stack overflow check methods. + + When this watchpoint is hit, gdb will stop with a SIGTRAP message. When no OCD is attached, esp-idf + will panic on an unhandled debug exception. + config FREERTOS_THREAD_LOCAL_STORAGE_POINTERS int "Amount of thread local storage pointers" range 0 256 if !WIFI_ENABLED @@ -203,22 +221,6 @@ config FREERTOS_PORTMUX_DEBUG_RECURSIVE portMUX usage. endif #FREERTOS_UNICORE - -config FREERTOS_WATCHPOINT_END_OF_STACK - bool "Set a debug watchpoint at the end of each stack" - default n - help - FreeRTOS can check if a stack has overflown its bounds by checking either the value of - the stack pointer or by checking the integrity of canary bytes. (See FREERTOS_CHECK_STACKOVERFLOW - for more information.) These checks only happen on a context switch, and the situation that caused - the stack overflow may already be long gone by then. This option will use the debug memory - watchpoint 1 (the second one) to allow breaking into the debugger (or panic'ing) as soon as any - of the last 32 bytes on the stack of a task are overwritten. The side effect is that using gdb, you - effectively only have one watchpoint; the 2nd one is overwritten as soon as a task switch happens. - - When this watchpoint is hit, gdb will stop with a SIGTRAP message. When no OCD is attached, esp-idf - will panic on an unhandled debug exception. - endif # FREERTOS_DEBUG_INTERNALS endmenu From 03ea45046da4625285857b85a4035b1b7ae5802d Mon Sep 17 00:00:00 2001 From: Liu Han Date: Mon, 27 Feb 2017 14:47:48 +0800 Subject: [PATCH 047/112] lwip: Change max number of open sockets --- components/lwip/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lwip/Kconfig b/components/lwip/Kconfig index 0070ef466..03d3ca776 100644 --- a/components/lwip/Kconfig +++ b/components/lwip/Kconfig @@ -18,7 +18,7 @@ config L2_TO_L3_COPY config LWIP_MAX_SOCKETS int "Max number of open sockets" - range 1 16 + range 1 32 default 10 help Sockets take up a certain amount of memory, and allowing fewer From c6420792f2aad638ee0e165cdceb93400b4960e2 Mon Sep 17 00:00:00 2001 From: XiaXiaotian Date: Mon, 27 Feb 2017 16:48:04 +0800 Subject: [PATCH 048/112] 1. Do not disable clock for generating random number. 2. And fix the bug that system crashes if call esp_wifi_stop() twice. --- components/esp32/lib | 2 +- components/esp32/phy_init.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/esp32/lib b/components/esp32/lib index 28c6ee924..965f7400f 160000 --- a/components/esp32/lib +++ b/components/esp32/lib @@ -1 +1 @@ -Subproject commit 28c6ee924ca6efc71bb77dcb040efd07d4d8a000 +Subproject commit 965f7400f339dc1e4566cea232602e225b1e4085 diff --git a/components/esp32/phy_init.c b/components/esp32/phy_init.c index 34e1a9f00..f70aa4a50 100644 --- a/components/esp32/phy_init.c +++ b/components/esp32/phy_init.c @@ -84,8 +84,8 @@ esp_err_t esp_phy_rf_deinit(void) if (s_phy_rf_init_count == 1) { // Disable PHY and RF. TODO: convert this function to another one. pm_close_rf(); - // Disable WiFi peripheral clock - CLEAR_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, 0x87cf); + // Disable WiFi peripheral clock. Do not disable clock for generating random number. + CLEAR_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, 0x874f); } else { #if CONFIG_SW_COEXIST_ENABLE coex_deinit(); From f36c909528469f601d41ae23308f26562f12d350 Mon Sep 17 00:00:00 2001 From: XiaXiaotian Date: Mon, 27 Feb 2017 19:54:22 +0800 Subject: [PATCH 049/112] update phy and rtc lib 1. RTC V214: modify APLL function for the chip of ECO version. 2. Add API phy_close_rf() and use it in esp_phy_deinit() instead of pm_close_rf(). 3. RTC V213: fix BT will not work when BT-init is called more than once. --- components/esp32/lib | 2 +- components/esp32/phy_init.c | 4 ++-- components/esp32/rtc.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/esp32/lib b/components/esp32/lib index 965f7400f..7b06303c0 160000 --- a/components/esp32/lib +++ b/components/esp32/lib @@ -1 +1 @@ -Subproject commit 965f7400f339dc1e4566cea232602e225b1e4085 +Subproject commit 7b06303c0fa416aea7f86b7596e84db367189066 diff --git a/components/esp32/phy_init.c b/components/esp32/phy_init.c index f70aa4a50..ccb53fe35 100644 --- a/components/esp32/phy_init.c +++ b/components/esp32/phy_init.c @@ -82,8 +82,8 @@ esp_err_t esp_phy_rf_deinit(void) _lock_acquire(&s_phy_rf_init_lock); if (s_phy_rf_init_count == 1) { - // Disable PHY and RF. TODO: convert this function to another one. - pm_close_rf(); + // Disable PHY and RF. + phy_close_rf(); // Disable WiFi peripheral clock. Do not disable clock for generating random number. CLEAR_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, 0x874f); } else { diff --git a/components/esp32/rtc.h b/components/esp32/rtc.h index f21d0da83..e1262a1ca 100644 --- a/components/esp32/rtc.h +++ b/components/esp32/rtc.h @@ -138,7 +138,7 @@ uint32_t rtc_sleep(uint32_t cycles_h, uint32_t cycles_l, uint32_t wakeup_opt, ui /** * @brief Shutdown PHY and RF. TODO: convert this function to another one. */ -void pm_close_rf(void); +void phy_close_rf(void); #ifdef __cplusplus } From d0f8fb9b939a9850763b7c3f90dc21346f567842 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 28 Feb 2017 10:59:23 +1100 Subject: [PATCH 050/112] freertos Kconfig: Thread local storage pointer feature required for WiFi or Ethernet --- components/freertos/Kconfig | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/components/freertos/Kconfig b/components/freertos/Kconfig index 04821cd5f..b4bcfc3fe 100644 --- a/components/freertos/Kconfig +++ b/components/freertos/Kconfig @@ -95,16 +95,19 @@ config FREERTOS_WATCHPOINT_END_OF_STACK will panic on an unhandled debug exception. config FREERTOS_THREAD_LOCAL_STORAGE_POINTERS - int "Amount of thread local storage pointers" - range 0 256 if !WIFI_ENABLED - range 1 256 if WIFI_ENABLED + int "Number of thread local storage pointers" + range 0 256 if !(WIFI_ENABLED || ETHERNET) + range 1 256 if WIFI_ENABLED || ETHERNET default 1 help FreeRTOS has the ability to store per-thread pointers in the task - control block. This controls the amount of pointers available; - 0 turns off this functionality. + control block. This controls the number of pointers available. - If using the WiFi stack, this value must be at least 1. + Value 0 turns off this functionality. + + If using the LWIP TCP/IP stack (with WiFi or Ethernet), this value must be at least 1. See the + LWIP_THREAD_LOCAL_STORAGE_INDEX config item in LWIP configuration to determine which thread-local-storage + pointer is reserved for LWIP. choice FREERTOS_ASSERT prompt "FreeRTOS assertions" From 20212ee8231476e2030944cb29d269620f701401 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 28 Feb 2017 12:06:36 +1100 Subject: [PATCH 051/112] freertos: Fix cross-core usage of event groups Fixes & re-enabled broken unit tests Adds per-event-group spinlock instead of single global lock --- components/freertos/event_groups.c | 32 ++++++++----- .../freertos/test/test_freertos_eventgroups.c | 46 ++++++++++++------- 2 files changed, 50 insertions(+), 28 deletions(-) diff --git a/components/freertos/event_groups.c b/components/freertos/event_groups.c index 902a4ad72..69903817f 100644 --- a/components/freertos/event_groups.c +++ b/components/freertos/event_groups.c @@ -119,13 +119,10 @@ typedef struct xEventGroupDefinition UBaseType_t uxEventGroupNumber; #endif + portMUX_TYPE eventGroupMux; } EventGroup_t; -/* Again: one mux for all events. Maybe this can be made more granular. ToDo: look into that. -JD */ -static portMUX_TYPE xEventGroupMux = portMUX_INITIALIZER_UNLOCKED; - - /*-----------------------------------------------------------*/ /* @@ -156,6 +153,8 @@ EventGroup_t *pxEventBits; traceEVENT_GROUP_CREATE_FAILED(); } + vPortCPUInitializeMutex(&pxEventBits->eventGroupMux); + return ( EventGroupHandle_t ) pxEventBits; } /*-----------------------------------------------------------*/ @@ -176,6 +175,7 @@ BaseType_t xTimeoutOccurred = pdFALSE; #endif vTaskSuspendAll(); + taskENTER_CRITICAL(&pxEventBits->eventGroupMux); { uxOriginalBitValue = pxEventBits->uxEventBits; @@ -217,6 +217,7 @@ BaseType_t xTimeoutOccurred = pdFALSE; } } } + taskEXIT_CRITICAL( &pxEventBits->eventGroupMux ); xAlreadyYielded = xTaskResumeAll(); if( xTicksToWait != ( TickType_t ) 0 ) @@ -239,7 +240,7 @@ BaseType_t xTimeoutOccurred = pdFALSE; if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 ) { /* The task timed out, just return the current event bit value. */ - taskENTER_CRITICAL( &xEventGroupMux ); + taskENTER_CRITICAL( &pxEventBits->eventGroupMux ); { uxReturn = pxEventBits->uxEventBits; @@ -256,7 +257,7 @@ BaseType_t xTimeoutOccurred = pdFALSE; mtCOVERAGE_TEST_MARKER(); } } - taskEXIT_CRITICAL( &xEventGroupMux ); + taskEXIT_CRITICAL( &pxEventBits->eventGroupMux ); xTimeoutOccurred = pdTRUE; } @@ -295,6 +296,7 @@ BaseType_t xTimeoutOccurred = pdFALSE; #endif vTaskSuspendAll(); + taskENTER_CRITICAL( &pxEventBits->eventGroupMux ); { const EventBits_t uxCurrentEventBits = pxEventBits->uxEventBits; @@ -361,6 +363,7 @@ BaseType_t xTimeoutOccurred = pdFALSE; traceEVENT_GROUP_WAIT_BITS_BLOCK( xEventGroup, uxBitsToWaitFor ); } } + taskEXIT_CRITICAL( &pxEventBits->eventGroupMux ); xAlreadyYielded = xTaskResumeAll(); if( xTicksToWait != ( TickType_t ) 0 ) @@ -382,7 +385,7 @@ BaseType_t xTimeoutOccurred = pdFALSE; if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 ) { - taskENTER_CRITICAL( &xEventGroupMux ); + taskENTER_CRITICAL( &pxEventBits->eventGroupMux ); { /* The task timed out, just return the current event bit value. */ uxReturn = pxEventBits->uxEventBits; @@ -405,7 +408,7 @@ BaseType_t xTimeoutOccurred = pdFALSE; mtCOVERAGE_TEST_MARKER(); } } - taskEXIT_CRITICAL( &xEventGroupMux ); + taskEXIT_CRITICAL( &pxEventBits->eventGroupMux ); /* Prevent compiler warnings when trace macros are not used. */ xTimeoutOccurred = pdFALSE; @@ -434,7 +437,7 @@ EventBits_t uxReturn; configASSERT( xEventGroup ); configASSERT( ( uxBitsToClear & eventEVENT_BITS_CONTROL_BYTES ) == 0 ); - taskENTER_CRITICAL( &xEventGroupMux ); + taskENTER_CRITICAL( &pxEventBits->eventGroupMux ); { traceEVENT_GROUP_CLEAR_BITS( xEventGroup, uxBitsToClear ); @@ -445,7 +448,7 @@ EventBits_t uxReturn; /* Clear the bits. */ pxEventBits->uxEventBits &= ~uxBitsToClear; } - taskEXIT_CRITICAL( &xEventGroupMux ); + taskEXIT_CRITICAL( &pxEventBits->eventGroupMux ); return uxReturn; } @@ -498,7 +501,9 @@ BaseType_t xMatchFound = pdFALSE; pxList = &( pxEventBits->xTasksWaitingForBits ); pxListEnd = listGET_END_MARKER( pxList ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */ + vTaskSuspendAll(); + taskENTER_CRITICAL(&pxEventBits->eventGroupMux); { traceEVENT_GROUP_SET_BITS( xEventGroup, uxBitsToSet ); @@ -570,6 +575,7 @@ BaseType_t xMatchFound = pdFALSE; bit was set in the control word. */ pxEventBits->uxEventBits &= ~uxBitsToClear; } + taskEXIT_CRITICAL(&pxEventBits->eventGroupMux); ( void ) xTaskResumeAll(); return pxEventBits->uxEventBits; @@ -578,10 +584,11 @@ BaseType_t xMatchFound = pdFALSE; void vEventGroupDelete( EventGroupHandle_t xEventGroup ) { -EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup; -const List_t *pxTasksWaitingForBits = &( pxEventBits->xTasksWaitingForBits ); + EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup; + const List_t *pxTasksWaitingForBits = &( pxEventBits->xTasksWaitingForBits ); vTaskSuspendAll(); + taskENTER_CRITICAL( &pxEventBits->eventGroupMux ); { traceEVENT_GROUP_DELETE( xEventGroup ); @@ -593,6 +600,7 @@ const List_t *pxTasksWaitingForBits = &( pxEventBits->xTasksWaitingForBits ); ( void ) xTaskRemoveFromUnorderedEventList( pxTasksWaitingForBits->xListEnd.pxNext, eventUNBLOCKED_DUE_TO_BIT_SET ); } + taskEXIT_CRITICAL( &pxEventBits->eventGroupMux ); vPortFree( pxEventBits ); } ( void ) xTaskResumeAll(); diff --git a/components/freertos/test/test_freertos_eventgroups.c b/components/freertos/test/test_freertos_eventgroups.c index 32dee2d20..dce770af5 100644 --- a/components/freertos/test/test_freertos_eventgroups.c +++ b/components/freertos/test/test_freertos_eventgroups.c @@ -11,9 +11,10 @@ #define BIT_RESPONSE(TASK) (1 << (TASK+1)) #define ALL_RESPONSE_BITS (((1 << NUM_TASKS) - 1) << 1) -static const int NUM_TASKS = 4; -static const int COUNT = 4000; +static const int NUM_TASKS = 8; +static const int COUNT = 1000; static EventGroupHandle_t eg; +static SemaphoreHandle_t done_sem; static void task_event_group_call_response(void *param) { @@ -32,15 +33,14 @@ static void task_event_group_call_response(void *param) } printf("Task %d done\n", task_num); - - /* Delay is due to not-yet-fixed bug with deleting tasks at same time */ - vTaskDelay(100 / portTICK_PERIOD_MS); + xSemaphoreGive(done_sem); vTaskDelete(NULL); } -TEST_CASE("FreeRTOS Event Groups", "[freertos][ignore]") +TEST_CASE("FreeRTOS Event Groups", "[freertos]") { eg = xEventGroupCreate(); + done_sem = xSemaphoreCreateCounting(NUM_TASKS, 0); /* Note: task_event_group_call_response all have higher priority than us, so will block together. @@ -50,7 +50,7 @@ TEST_CASE("FreeRTOS Event Groups", "[freertos][ignore]") for (int c = 0; c < NUM_TASKS; c++) { xTaskCreatePinnedToCore(task_event_group_call_response, "tsk_call_resp", 4096, (void *)c, configMAX_PRIORITIES - 1, NULL, c % portNUM_PROCESSORS); } - /* Scheduler weirdness, if we don't sleep a few ticks here then the tasks on the other CPU aren't running yet... */ + /* Scheduler weirdness (bug?), if we don't sleep a few ticks here then the tasks on the other CPU aren't running yet... */ vTaskDelay(10); for (int i = 0; i < COUNT; i++) { @@ -60,11 +60,17 @@ TEST_CASE("FreeRTOS Event Groups", "[freertos][ignore]") /* signal all tasks with "CALL" bit... */ xEventGroupSetBits(eg, BIT_CALL); - while (xEventGroupWaitBits(eg, ALL_RESPONSE_BITS, true, true, portMAX_DELAY) != ALL_RESPONSE_BITS) { - } + TEST_ASSERT_EQUAL(ALL_RESPONSE_BITS, xEventGroupWaitBits(eg, ALL_RESPONSE_BITS, true, true, 100 / portMAX_DELAY)); } -} + /* Ensure all tasks cleaned up correctly */ + for (int c = 0; c < NUM_TASKS; c++) { + TEST_ASSERT( xSemaphoreTake(done_sem, 100/portTICK_PERIOD_MS) ); + } + + vSemaphoreDelete(done_sem); + vEventGroupDelete(eg); +} #define BIT_DONE(X) (1<<(NUM_TASKS+1+X)) @@ -82,24 +88,32 @@ static void task_test_sync(void *param) } int after_done = xEventGroupSetBits(eg, BIT_DONE(task_num)); - printf("Done %d = %x\n", task_num, after_done); + printf("Done %d = 0x%08x\n", task_num, after_done); - /* Delay is due to not-yet-fixed bug with deleting tasks at same time */ - vTaskDelay(100 / portTICK_PERIOD_MS); + xSemaphoreGive(done_sem); vTaskDelete(NULL); } -TEST_CASE("FreeRTOS Event Group Sync", "[freertos][ignore]") +TEST_CASE("FreeRTOS Event Group Sync", "[freertos]") { eg = xEventGroupCreate(); + done_sem = xSemaphoreCreateCounting(NUM_TASKS, 0); for (int c = 0; c < NUM_TASKS; c++) { xTaskCreatePinnedToCore(task_test_sync, "task_test_sync", 4096, (void *)c, configMAX_PRIORITIES - 1, NULL, c % portNUM_PROCESSORS); } for (int c = 0; c < NUM_TASKS; c++) { - printf("Waiting on %d (%x)\n", c, BIT_DONE(c)); - xEventGroupWaitBits(eg, BIT_DONE(c), false, false, portMAX_DELAY); + printf("Waiting on %d (0x%08x)\n", c, BIT_DONE(c)); + TEST_ASSERT( xEventGroupWaitBits(eg, BIT_DONE(c), false, false, portMAX_DELAY) ); } + + /* Ensure all tasks cleaned up correctly */ + for (int c = 0; c < NUM_TASKS; c++) { + TEST_ASSERT( xSemaphoreTake(done_sem, 100/portTICK_PERIOD_MS) ); + } + + vSemaphoreDelete(done_sem); + vEventGroupDelete(eg); } From 8de26e434cf9585726be9ca1e1f4396b8caba52e Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 28 Feb 2017 15:13:30 +1100 Subject: [PATCH 052/112] freertos: Schedule tasks immediately when they are created on opposite core --- components/freertos/tasks.c | 96 +++++++++++-------- .../freertos/test/test_freertos_eventgroups.c | 21 ++-- 2 files changed, 66 insertions(+), 51 deletions(-) diff --git a/components/freertos/tasks.c b/components/freertos/tasks.c index 0804bb3eb..b37e59254 100644 --- a/components/freertos/tasks.c +++ b/components/freertos/tasks.c @@ -1046,25 +1046,59 @@ UBaseType_t x; } /*-----------------------------------------------------------*/ -static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode, const BaseType_t xCoreID ) +static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode, BaseType_t xCoreID ) { - TCB_t *curTCB; - BaseType_t i; + TCB_t *curTCB, *tcb0, *tcb1; /* Ensure interrupts don't access the task lists while the lists are being updated. */ taskENTER_CRITICAL(&xTaskQueueMutex); { uxCurrentNumberOfTasks++; - //If the task has no affinity and nothing is scheduled on this core, just throw it this core. - //If it has affinity, throw it on the core that needs it if nothing is already scheduled there. - BaseType_t xMyCore = xCoreID; - if ( xMyCore == tskNO_AFFINITY) xMyCore = xPortGetCoreID(); - if( pxCurrentTCB[ xMyCore ] == NULL ) + + // Determine which core this task starts on + if ( xCoreID == tskNO_AFFINITY ) + { + if ( portNUM_PROCESSORS == 1 ) + { + xCoreID = 0; + } + else + { + // if the task has no affinity, put it on either core if nothing is currently scheduled there. Failing that, + // put it on the core where it will preempt the lowest priority running task. If neither of these are true, + // queue it on the currently running core. + tcb0 = pxCurrentTCB[0]; + tcb1 = pxCurrentTCB[1]; + if ( tcb0 == NULL ) + { + xCoreID = 0; + } + else if ( tcb1 == NULL ) + { + xCoreID = 1; + } + else if ( tcb0->uxPriority < pxNewTCB->uxPriority && tcb0->uxPriority < tcb1->uxPriority ) + { + xCoreID = 0; + } + else if ( tcb1->uxPriority < pxNewTCB->uxPriority ) + { + xCoreID = 1; + } + else + { + xCoreID = xPortGetCoreID(); // Both CPU have higher priority tasks running on them, so this won't run yet + } + } + } + + // If nothing is running on this core, put the new task there now + if( pxCurrentTCB[ xCoreID ] == NULL ) { /* There are no other tasks, or all the other tasks are in the suspended state - make this the current task. */ - pxCurrentTCB[ xMyCore ] = pxNewTCB; + pxCurrentTCB[ xCoreID ] = pxNewTCB; if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 ) { @@ -1090,19 +1124,11 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode so far. */ if( xSchedulerRunning == pdFALSE ) { - /* Scheduler isn't running yet. We need to determine on which CPU to run this task. */ - for ( i=0; iuxPriority <= pxNewTCB->uxPriority ) { - /* Can we schedule this task on core i? */ - if (xCoreID == tskNO_AFFINITY || xCoreID == i) - { - /* Schedule if nothing is scheduled yet, or overwrite a task of lower prio. */ - if ( pxCurrentTCB[i] == NULL || pxCurrentTCB[i]->uxPriority <= pxNewTCB->uxPriority ) - { - pxCurrentTCB[i] = pxNewTCB; - break; - } - } + pxCurrentTCB[xCoreID] = pxNewTCB; } } else @@ -1130,37 +1156,27 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode if( xSchedulerRunning != pdFALSE ) { - taskENTER_CRITICAL(&xTaskQueueMutex); - curTCB = pxCurrentTCB[ xPortGetCoreID() ]; + taskENTER_CRITICAL(&xTaskQueueMutex); + + curTCB = pxCurrentTCB[ xCoreID ]; /* Scheduler is running. If the created task is of a higher priority than an executing task - then it should run now. - ToDo: This only works for the current core. If a task is scheduled on an other processor, - the other processor will keep running the task it's working on, and only switch to the newer - task on a timer interrupt. */ - //No mux here, uxPriority is mostly atomic and there's not really any harm if this check misfires. - if( curTCB->uxPriority < pxNewTCB->uxPriority ) + then it should run now. + */ + if( curTCB == NULL || curTCB->uxPriority < pxNewTCB->uxPriority ) { - /* Scheduler is running. If the created task is of a higher priority than an executing task - then it should run now. - No mux here, uxPriority is mostly atomic and there's not really any harm if this check misfires. - */ - if( tskCAN_RUN_HERE( xCoreID ) && curTCB->uxPriority < pxNewTCB->uxPriority ) + if( xCoreID == xPortGetCoreID() ) { taskYIELD_IF_USING_PREEMPTION_MUX(&xTaskQueueMutex); } - else if( xCoreID != xPortGetCoreID() ) { + else { taskYIELD_OTHER_CORE(xCoreID, pxNewTCB->uxPriority); } - else - { - mtCOVERAGE_TEST_MARKER(); - } } else { mtCOVERAGE_TEST_MARKER(); } - taskEXIT_CRITICAL(&xTaskQueueMutex); + taskEXIT_CRITICAL(&xTaskQueueMutex); } else { diff --git a/components/freertos/test/test_freertos_eventgroups.c b/components/freertos/test/test_freertos_eventgroups.c index dce770af5..f32c20ade 100644 --- a/components/freertos/test/test_freertos_eventgroups.c +++ b/components/freertos/test/test_freertos_eventgroups.c @@ -25,8 +25,7 @@ static void task_event_group_call_response(void *param) for (int i = 0; i < COUNT; i++) { /* Wait until the common "call" bit is set, starts off all tasks (clear on return) */ - while (!xEventGroupWaitBits(eg, BIT_CALL, true, false, portMAX_DELAY)) { - } + TEST_ASSERT( xEventGroupWaitBits(eg, BIT_CALL, true, false, portMAX_DELAY) ); /* Set our individual "response" bit */ xEventGroupSetBits(eg, BIT_RESPONSE(task_num)); @@ -42,25 +41,25 @@ TEST_CASE("FreeRTOS Event Groups", "[freertos]") eg = xEventGroupCreate(); done_sem = xSemaphoreCreateCounting(NUM_TASKS, 0); - /* Note: task_event_group_call_response all have higher priority than us, so will block together. + /* Note: task_event_group_call_response all have higher priority than this task, so on this core + they will always preempt this task. - This is important because we need to know they'll all have blocked on BIT_CALL each time we - signal it, or they get out of sync. + This is important because we need to know all tasks have blocked on BIT_CALL each time we signal it, + or they get out of sync. */ for (int c = 0; c < NUM_TASKS; c++) { xTaskCreatePinnedToCore(task_event_group_call_response, "tsk_call_resp", 4096, (void *)c, configMAX_PRIORITIES - 1, NULL, c % portNUM_PROCESSORS); } - /* Scheduler weirdness (bug?), if we don't sleep a few ticks here then the tasks on the other CPU aren't running yet... */ - vTaskDelay(10); + + /* Tasks all start instantly, but this task will resume running at the same time as the higher priority tasks on the + other processor may still be setting up, so give a tick for them to also block on BIT_CALL... */ + vTaskDelay(1); for (int i = 0; i < COUNT; i++) { - if (i % 100 == 0) { - //printf("Call %d\n", i); - } /* signal all tasks with "CALL" bit... */ xEventGroupSetBits(eg, BIT_CALL); - TEST_ASSERT_EQUAL(ALL_RESPONSE_BITS, xEventGroupWaitBits(eg, ALL_RESPONSE_BITS, true, true, 100 / portMAX_DELAY)); + TEST_ASSERT_EQUAL_HEX16(ALL_RESPONSE_BITS, xEventGroupWaitBits(eg, ALL_RESPONSE_BITS, true, true, 100 / portMAX_DELAY)); } /* Ensure all tasks cleaned up correctly */ From 2230b2c8bce812a51a14144176119b6bb4bb4bc7 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 28 Feb 2017 15:31:40 +1100 Subject: [PATCH 053/112] freertos tests: Enable test_freertos_task_delete --- components/freertos/test/test_freertos_task_delete.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/components/freertos/test/test_freertos_task_delete.c b/components/freertos/test/test_freertos_task_delete.c index d8cc2755e..68a6683fc 100644 --- a/components/freertos/test/test_freertos_task_delete.c +++ b/components/freertos/test/test_freertos_task_delete.c @@ -10,13 +10,17 @@ static void task_delete_self(void *param) { printf("Task %p running on core %d. Deleting shortly...\n", xTaskGetCurrentTaskHandle(), xPortGetCoreID()); + vTaskDelay(5); vTaskDelete(NULL); } -TEST_CASE("FreeRTOS Delete Tasks", "[freertos][ignore]") +TEST_CASE("FreeRTOS Delete Tasks", "[freertos]") { + uint32_t before_count = uxTaskGetNumberOfTasks(); + xTaskCreatePinnedToCore(task_delete_self, "tsk_self_a", 4096, NULL, configMAX_PRIORITIES - 1, NULL, 0); xTaskCreatePinnedToCore(task_delete_self, "tsk_self_a", 4096, NULL, configMAX_PRIORITIES - 1, NULL, 0); + TEST_ASSERT_EQUAL(before_count + 2, uxTaskGetNumberOfTasks()); vTaskDelay(200 / portTICK_PERIOD_MS); - printf("Done?\n"); + TEST_ASSERT_EQUAL(before_count, uxTaskGetNumberOfTasks()); } From f3687f7177f094288ab8e0fa0d9bbcde6ca419f4 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 28 Feb 2017 15:11:54 +0800 Subject: [PATCH 054/112] spi_flash: fix memory leak when spi_flash_mmap arguments are invalid Check src_addr and size first, then allocate new_entry. --- components/spi_flash/flash_mmap.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/spi_flash/flash_mmap.c b/components/spi_flash/flash_mmap.c index 8d284c60a..d67bdc85b 100644 --- a/components/spi_flash/flash_mmap.c +++ b/components/spi_flash/flash_mmap.c @@ -93,16 +93,16 @@ esp_err_t IRAM_ATTR spi_flash_mmap(size_t src_addr, size_t size, spi_flash_mmap_ { esp_err_t ret; bool did_flush, need_flush = false; - mmap_entry_t* new_entry = (mmap_entry_t*) malloc(sizeof(mmap_entry_t)); - if (new_entry == 0) { - return ESP_ERR_NO_MEM; - } if (src_addr & 0xffff) { return ESP_ERR_INVALID_ARG; } if (src_addr + size > g_rom_flashchip.chip_size) { return ESP_ERR_INVALID_ARG; } + mmap_entry_t* new_entry = (mmap_entry_t*) malloc(sizeof(mmap_entry_t)); + if (new_entry == 0) { + return ESP_ERR_NO_MEM; + } spi_flash_disable_interrupts_caches_and_other_cpu(); From 98f8594151b992b62518b7fba2da81620b3e9f5f Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 1 Mar 2017 12:01:07 +1100 Subject: [PATCH 055/112] esp32 dport_reg.h: Fix typo in register bit names --- components/esp32/include/soc/dport_reg.h | 4 ++-- components/esp32/system_api.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/esp32/include/soc/dport_reg.h b/components/esp32/include/soc/dport_reg.h index ef231e316..131d0d8ab 100644 --- a/components/esp32/include/soc/dport_reg.h +++ b/components/esp32/include/soc/dport_reg.h @@ -1038,8 +1038,8 @@ #define DPORT_CORE_RST_EN_REG (DR_REG_DPORT_BASE + 0x0D0) /* DPORT_CORE_RST : R/W ;bitpos:[31:0] ;default: 32'h0 ; */ /*description: */ -#define DPROT_RW_BTLP_RST (BIT(10)) -#define DPROT_RW_BTMAC_RST (BIT(9)) +#define DPORT_RW_BTLP_RST (BIT(10)) +#define DPORT_RW_BTMAC_RST (BIT(9)) #define DPORT_MACPWR_RST (BIT(8)) #define DPORT_EMAC_RST (BIT(7)) #define DPORT_SDIO_HOST_RST (BIT(6)) diff --git a/components/esp32/system_api.c b/components/esp32/system_api.c index d984af78a..60e3d8598 100644 --- a/components/esp32/system_api.c +++ b/components/esp32/system_api.c @@ -132,7 +132,7 @@ void IRAM_ATTR esp_restart_noos() DPORT_BB_RST | DPORT_FE_RST | DPORT_MAC_RST | DPORT_BT_RST | DPORT_BTMAC_RST | DPORT_SDIO_RST | DPORT_SDIO_HOST_RST | DPORT_EMAC_RST | DPORT_MACPWR_RST | - DPROT_RW_BTMAC_RST | DPROT_RW_BTLP_RST); + DPORT_RW_BTMAC_RST | DPORT_RW_BTLP_RST); REG_WRITE(DPORT_CORE_RST_EN_REG, 0); // Reset timer/spi/uart From 4d67a2ba8bcc37a8f5a59444f2ab542a38633bf6 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 1 Mar 2017 12:02:04 +1100 Subject: [PATCH 056/112] esp32 phy_init: Move DPORT Wifi clock masks to macro values Amended fix for c642079 !534 --- .../bootloader_support/src/bootloader_random.c | 5 +++++ components/esp32/include/soc/dport_reg.h | 16 ++++++++++++++++ components/esp32/phy_init.c | 6 +++--- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/components/bootloader_support/src/bootloader_random.c b/components/bootloader_support/src/bootloader_random.c index 5a00d0cf5..fe5a019f8 100644 --- a/components/bootloader_support/src/bootloader_random.c +++ b/components/bootloader_support/src/bootloader_random.c @@ -62,6 +62,11 @@ void bootloader_fill_random(void *buffer, size_t length) void bootloader_random_enable(void) { + /* Ensure the hardware RNG is enabled following a soft reset. This should always be the case already (this clock is + never disabled while the CPU is running), this is a "belts and braces" type check. + */ + SET_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_RNG_EN); + /* Enable SAR ADC in test mode to feed ADC readings of the 1.1V reference via I2S into the RNG entropy input. diff --git a/components/esp32/include/soc/dport_reg.h b/components/esp32/include/soc/dport_reg.h index 131d0d8ab..141b05b4a 100644 --- a/components/esp32/include/soc/dport_reg.h +++ b/components/esp32/include/soc/dport_reg.h @@ -1035,6 +1035,22 @@ #define DPORT_WIFI_CLK_EN_V 0xFFFFFFFF #define DPORT_WIFI_CLK_EN_S 0 +/* Mask for all Wifi clock bits - 0, 1, 2, 3, 6, 7, 8, 9, 10, 15 */ +#define DPORT_WIFI_CLK_WIFI_EN 0x000007cf +#define DPORT_WIFI_CLK_WIFI_EN_M ((DPORT_WIFI_CLK_WIFI_EN_V)<<(DPORT_WIFI_CLK_WIFI_EN_S)) +#define DPORT_WIFI_CLK_WIFI_EN_V 0x1FF +#define DPORT_WIFI_CLK_WIFI_EN_S 0 +/* Mask for all Bluetooth clock bits - 11, 16, 17 */ +#define DPORT_WIFI_CLK_BT_EN 0x61 +#define DPORT_WIFI_CLK_BT_EN_M ((DPORT_WIFI_CLK_BT_EN_V)<<(DPORT_WIFI_CLK_BT_EN_S)) +#define DPORT_WIFI_CLK_BT_EN_V 0x61 +#define DPORT_WIFI_CLK_BT_EN_S 11 +/* Remaining single bit clock masks */ +#define DPORT_WIFI_CLK_SDIOSLAVE_EN BIT(4) +#define DPORT_WIFI_CLK_SDIO_HOST_EN BIT(13) +#define DPORT_WIFI_CLK_EMAC_EN BIT(14) +#define DPORT_WIFI_CLK_RNG_EN BIT(15) + #define DPORT_CORE_RST_EN_REG (DR_REG_DPORT_BASE + 0x0D0) /* DPORT_CORE_RST : R/W ;bitpos:[31:0] ;default: 32'h0 ; */ /*description: */ diff --git a/components/esp32/phy_init.c b/components/esp32/phy_init.c index ccb53fe35..5fbeeb7c8 100644 --- a/components/esp32/phy_init.c +++ b/components/esp32/phy_init.c @@ -60,7 +60,7 @@ esp_err_t esp_phy_rf_init(const esp_phy_init_data_t* init_data, } } // Enable WiFi peripheral clock - SET_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, 0x87cf); + SET_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_WIFI_EN | DPORT_WIFI_CLK_RNG_EN); ESP_LOGV(TAG, "register_chipv7_phy, init_data=%p, cal_data=%p, mode=%d", init_data, calibration_data, mode); phy_set_wifi_mode_only(0); @@ -84,8 +84,8 @@ esp_err_t esp_phy_rf_deinit(void) if (s_phy_rf_init_count == 1) { // Disable PHY and RF. phy_close_rf(); - // Disable WiFi peripheral clock. Do not disable clock for generating random number. - CLEAR_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, 0x874f); + // Disable WiFi peripheral clock. Do not disable clock for hardware RNG + CLEAR_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_WIFI_EN); } else { #if CONFIG_SW_COEXIST_ENABLE coex_deinit(); From bf7f0bf52cc8f14566fb479d4b3145d057ae60d2 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Wed, 1 Mar 2017 11:12:10 +0800 Subject: [PATCH 057/112] make: look for TEST_COMPONENTS in all component directories fixes https://github.com/espressif/esp-idf/issues/354 --- make/project.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make/project.mk b/make/project.mk index 04015a8a8..d5a72c5d1 100644 --- a/make/project.mk +++ b/make/project.mk @@ -134,7 +134,7 @@ endif # If TEST_COMPONENTS is set, create variables for building unit tests ifdef TEST_COMPONENTS -override TEST_COMPONENTS := $(foreach comp,$(TEST_COMPONENTS),$(wildcard $(IDF_PATH)/components/$(comp)/test)) +override TEST_COMPONENTS := $(foreach comp,$(TEST_COMPONENTS),$(firstword $(foreach dir,$(COMPONENT_DIRS),$(wildcard $(dir)/$(comp)/test)))) TEST_COMPONENT_PATHS := $(TEST_COMPONENTS) TEST_COMPONENT_NAMES := $(foreach comp,$(TEST_COMPONENTS),$(lastword $(subst /, ,$(dir $(comp))))_test) endif From 3b3c3210a670d40325bb3af7f900989599777e71 Mon Sep 17 00:00:00 2001 From: Liu Zhi Fu Date: Wed, 1 Mar 2017 13:37:36 +0800 Subject: [PATCH 058/112] lwip: fix bool options default value wrong issue menuconfig options with bool type should use 'y/n' to use the default value, instead of '1/0' --- components/lwip/Kconfig | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/components/lwip/Kconfig b/components/lwip/Kconfig index 0070ef466..f99b6fe8a 100644 --- a/components/lwip/Kconfig +++ b/components/lwip/Kconfig @@ -2,7 +2,7 @@ menu "LWIP" config L2_TO_L3_COPY bool "Enable copy between Layer2 and Layer3 packets" - default 0 + default n help If this feature is enabled, all traffic from layer2(WIFI Driver) will be copied to a new buffer before sending it to layer3(LWIP stack), freeing @@ -35,14 +35,14 @@ config LWIP_THREAD_LOCAL_STORAGE_INDEX config LWIP_SO_REUSE bool "Enable SO_REUSEADDR option" - default 0 + default n help Enabling this option allows binding to a port which remains in TIME_WAIT. config LWIP_SO_RCVBUF bool "Enable SO_RCVBUF option" - default 0 + default n help Enabling this option allows checking for available data on a netconn. @@ -57,14 +57,14 @@ config LWIP_DHCP_MAX_NTP_SERVERS config LWIP_IP_FRAG bool "Enable fragment outgoing IP packets" - default 0 + default n help Enabling this option allows fragmenting outgoing IP packets if their size exceeds MTU. config LWIP_IP_REASSEMBLY bool "Enable reassembly incoming fragmented IP packets" - default 0 + default n help Enabling this option allows reassemblying incoming fragmented IP packets. @@ -84,7 +84,7 @@ config TCP_SYNMAXRTX config LWIP_DHCP_DOES_ARP_CHECK bool "Enable an ARP check on the offered address" - default 1 + default y help Enabling this option allows check if the offered IP address is not already in use by another host on the network. From 23f933a78d66b92507e53d9dca4b6424c5d1a849 Mon Sep 17 00:00:00 2001 From: XiaXiaotian Date: Wed, 1 Mar 2017 20:42:46 +0800 Subject: [PATCH 059/112] mac address: add user set mac address add menuconfig for user to set mac address of wifi, bt and ethernet. --- components/bt/Kconfig | 9 ++++++ components/esp32/Kconfig | 18 +++++++++++ components/esp32/include/esp_system.h | 20 +++++++++++++ components/esp32/lib | 2 +- components/esp32/system_api.c | 43 +++++++++++++++++++++++++++ components/ethernet/Kconfig | 9 ++++++ components/ethernet/emac_main.c | 3 +- 7 files changed, 101 insertions(+), 3 deletions(-) diff --git a/components/bt/Kconfig b/components/bt/Kconfig index 63dce8d1f..e4a72654f 100644 --- a/components/bt/Kconfig +++ b/components/bt/Kconfig @@ -3,6 +3,15 @@ menuconfig BT_ENABLED help Select this option to enable Bluetooth stack and show the submenu with Bluetooth configuration choices. +config ESP_MAC_OFFSET_BT_ + int "MAC address offset value of WiFi station" + depends on BT_ENABLED + range 0 255 + default 2 + help + The offset value of bluetooth MAC address from the MAC address which is read from efuse. + This offset value must be different from that of WiFi softap, WiFi station and ethernet. + config BTC_TASK_STACK_SIZE int "Bluetooth event (callback to application) task stack size" depends on BT_ENABLED diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index 8aa0ed3b5..361ddccd5 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -481,6 +481,24 @@ menuconfig WIFI_ENABLED help Select this option to enable WiFi stack and show the submenu with WiFi configuration choices. +config ESP_MAC_OFFSET_WIFI_STA + int "MAC address offset value of WiFi station" + depends on WIFI_ENABLED + range 0 255 + default 0 + help + The offset value of WiFi station MAC address from the MAC address which is read from efuse. + This offset value must be different from that of WiFi softap, bluetooth and ethernet. + +config ESP_MAC_OFFSET_WIFI_SOFTAP + int "MAC address offset value of WiFi softap" + depends on WIFI_ENABLED + range 0 255 + default 1 + help + The offset value of WiFi softap MAC address from the MAC address which is read from efuse. + This offset value must be different from that of WiFi station, bluetooth and ethernet. + config SW_COEXIST_ENABLE bool "Software controls WiFi/Bluetooth coexistence" depends on WIFI_ENABLED && BT_ENABLED diff --git a/components/esp32/include/esp_system.h b/components/esp32/include/esp_system.h index 30701761a..b127d56fe 100644 --- a/components/esp32/include/esp_system.h +++ b/components/esp32/include/esp_system.h @@ -24,6 +24,13 @@ extern "C" { #endif +enum { + ESP_MAC_WIFI_STA, + ESP_MAC_WIFI_SOFTAP, + ESP_MAC_BT, + ESP_MAC_ETH, +}; + /** * @attention application don't need to call this function anymore. It do nothing and will * be removed in future version. @@ -115,6 +122,19 @@ esp_err_t esp_efuse_read_mac(uint8_t* mac); */ esp_err_t system_efuse_read_mac(uint8_t mac[6]) __attribute__ ((deprecated)); +/** + * @brief Read hardware MAC address and set MAC address of the interface. + * + * This function first reads hardware MAC address from efuse. Then set the MAC address of the interface + * including wifi station, wifi softap, bluetooth and ethernet according to the offset value in menuconfig. + * + * @param mac MAC address of the interface, length: 6 bytes. + * @param interface interface, 0:wifi station, 1:wifi softap, 2:bluetooth, 3:ethernet. + * + * @return ESP_OK on success + */ +esp_err_t esp_read_mac(uint8_t* mac, int interface); + /** * Get SDK version * diff --git a/components/esp32/lib b/components/esp32/lib index 7b06303c0..e22ec1a51 160000 --- a/components/esp32/lib +++ b/components/esp32/lib @@ -1 +1 @@ -Subproject commit 7b06303c0fa416aea7f86b7596e84db367189066 +Subproject commit e22ec1a5140dca2bb44f9bfb3147911fa4ebb8fe diff --git a/components/esp32/system_api.c b/components/esp32/system_api.c index d984af78a..36b8b6b58 100644 --- a/components/esp32/system_api.c +++ b/components/esp32/system_api.c @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include + #include "esp_system.h" #include "esp_attr.h" #include "esp_wifi.h" @@ -72,6 +74,47 @@ esp_err_t esp_efuse_read_mac(uint8_t* mac) esp_err_t system_efuse_read_mac(uint8_t mac[6]) __attribute__((alias("esp_efuse_read_mac"))); +esp_err_t esp_read_mac(uint8_t* mac, int interface) +{ + uint8_t efuse_mac[6]; + + if (mac == NULL) { + ESP_LOGE(TAG, "mac address param is NULL"); + abort(); + } + + esp_efuse_read_mac(efuse_mac); + + switch (interface) { +#if CONFIG_WIFI_ENABLED + case ESP_MAC_WIFI_STA: + memcpy(mac, efuse_mac, 6); + mac[5] += CONFIG_ESP_MAC_OFFSET_WIFI_STA; + break; + case ESP_MAC_WIFI_SOFTAP: + memcpy(mac, efuse_mac, 6); + mac[5] += CONFIG_ESP_MAC_OFFSET_WIFI_SOFTAP; + break; +#endif +#if CONFIG_BT_ENABLED + case ESP_MAC_WIFI_BT: + memcpy(mac, efuse_mac, 6); + mac[5] += CONFIG_ESP_MAC_OFFSET_BT; + break; +#endif +#if CONFIG_ETHERNET + case ESP_MAC_WIFI_ETH: + memcpy(mac, efuse_mac, 6); + mac[5] += CONFIG_ESP_MAC_OFFSET_ETH; + break; +#endif + default: + ESP_LOGW(TAG, "wrong mac type"); + break; + } + + return ESP_OK; +} void esp_restart_noos() __attribute__ ((noreturn)); diff --git a/components/ethernet/Kconfig b/components/ethernet/Kconfig index 46e86cc60..230e53cdc 100644 --- a/components/ethernet/Kconfig +++ b/components/ethernet/Kconfig @@ -4,6 +4,15 @@ menuconfig ETHERNET help Select this option to enable ethernet driver and show the submenu with ethernet features. +config ESP_MAC_OFFSET_ETH + int "MAC address offset value of ethernet" + depends on ETHERNET + range 0 255 + default 3 + help + The offset value of ethernet MAC address from the MAC address which is read from efuse. + This offset value must be different from that of WiFi softap, bluetooth and WiFi station. + config DMA_RX_BUF_NUM int "Number of DMA RX buffers" range 3 20 diff --git a/components/ethernet/emac_main.c b/components/ethernet/emac_main.c index 5479ec399..8c93a1830 100644 --- a/components/ethernet/emac_main.c +++ b/components/ethernet/emac_main.c @@ -75,8 +75,7 @@ esp_err_t emac_post(emac_sig_t sig, emac_par_t par); static void emac_macaddr_init(void) { - esp_efuse_read_mac(&(emac_config.macaddr[0])); - emac_config.macaddr[5] = emac_config.macaddr[5] + 3; + esp_read_mac(&(emac_config.macaddr[0]), ESP_MAC_ETH); } void esp_eth_get_mac(uint8_t mac[6]) From 66199b1efee01e533ee22a2c3aa9d79abb9ad82c Mon Sep 17 00:00:00 2001 From: Liu Zhi Fu Date: Wed, 1 Mar 2017 14:48:27 +0800 Subject: [PATCH 060/112] Check DHCP rebind timer before checking dhcp release timer in cause they have the same value. lwip: modify dhcp timer granularity from 60s to 1s Current DHCP granularity is 60 seconds, it's not accurate, it can cause DHCP release/rebind/renew timer timeout at the same time, also it may renew/rebind/release at wrong time, thus cause problem. --- components/lwip/core/ipv4/dhcp.c | 56 ++++++++++++++++++++ components/lwip/include/lwip/lwip/dhcp.h | 14 ++--- components/lwip/include/lwip/port/lwipopts.h | 1 + 3 files changed, 64 insertions(+), 7 deletions(-) diff --git a/components/lwip/core/ipv4/dhcp.c b/components/lwip/core/ipv4/dhcp.c index 86336d4f7..1f180511e 100755 --- a/components/lwip/core/ipv4/dhcp.c +++ b/components/lwip/core/ipv4/dhcp.c @@ -550,10 +550,17 @@ dhcp_t1_timeout(struct netif *netif) DHCP_STATE_RENEWING, not DHCP_STATE_BOUND */ dhcp_renew(netif); /* Calculate next timeout */ +#if ESP_DHCP_TIMER + if (((netif->dhcp->t2_timeout - dhcp->lease_used) / 2) >= (60 + DHCP_COARSE_TIMER_SECS / 2) ) + { + netif->dhcp->t1_renew_time = (netif->dhcp->t2_timeout - dhcp->lease_used) / 2; + } +#else if (((netif->dhcp->t2_timeout - dhcp->lease_used) / 2) >= ((60 + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS)) { netif->dhcp->t1_renew_time = ((netif->dhcp->t2_timeout - dhcp->lease_used) / 2); } +#endif } } @@ -576,10 +583,17 @@ dhcp_t2_timeout(struct netif *netif) DHCP_STATE_REBINDING, not DHCP_STATE_BOUND */ dhcp_rebind(netif); /* Calculate next timeout */ +#if ESP_DHCP_TIMER + if (((netif->dhcp->t0_timeout - dhcp->lease_used) / 2) >= (60 + DHCP_COARSE_TIMER_SECS / 2)) + { + netif->dhcp->t2_rebind_time = ((netif->dhcp->t0_timeout - dhcp->lease_used) / 2); + } +#else if (((netif->dhcp->t0_timeout - dhcp->lease_used) / 2) >= ((60 + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS)) { netif->dhcp->t2_rebind_time = ((netif->dhcp->t0_timeout - dhcp->lease_used) / 2); } +#endif } } @@ -1060,6 +1074,47 @@ dhcp_bind(struct netif *netif) /* reset time used of lease */ dhcp->lease_used = 0; +#if ESP_DHCP_TIMER + if (dhcp->offered_t0_lease != 0xffffffffUL) { + /* set renewal period timer */ + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t0 renewal timer %"U32_F" secs\n", dhcp->offered_t0_lease)); + timeout = dhcp->offered_t0_lease; + dhcp->t0_timeout = timeout; + if (dhcp->t0_timeout == 0) { + dhcp->t0_timeout = 120; + } + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t0_lease*1000)); + } + + /* temporary DHCP lease? */ + if (dhcp->offered_t1_renew != 0xffffffffUL) { + /* set renewal period timer */ + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t1 renewal timer %"U32_F" secs\n", dhcp->offered_t1_renew)); + timeout = dhcp->offered_t1_renew; + dhcp->t1_timeout = timeout; + if (dhcp->t1_timeout == 0) { + dhcp->t1_timeout = dhcp->t0_timeout>>1; + } + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t1_renew*1000)); + dhcp->t1_renew_time = dhcp->t1_timeout; + } + /* set renewal period timer */ + if (dhcp->offered_t2_rebind != 0xffffffffUL) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t2 rebind timer %"U32_F" secs\n", dhcp->offered_t2_rebind)); + timeout = dhcp->offered_t2_rebind; + dhcp->t2_timeout = timeout; + if (dhcp->t2_timeout == 0) { + dhcp->t2_timeout = (dhcp->t0_timeout>>3)*7; + } + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t2_rebind*1000)); + dhcp->t2_rebind_time = dhcp->t2_timeout; + } + + /* If we have sub 1 minute lease, t2 and t1 will kick in at the same time. */ + if ((dhcp->t1_timeout >= dhcp->t2_timeout) && (dhcp->t2_timeout > 0)) { + dhcp->t1_timeout = 0; + } +#else if (dhcp->offered_t0_lease != 0xffffffffUL) { /* set renewal period timer */ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t0 renewal timer %"U32_F" secs\n", dhcp->offered_t0_lease)); @@ -1108,6 +1163,7 @@ dhcp_bind(struct netif *netif) if ((dhcp->t1_timeout >= dhcp->t2_timeout) && (dhcp->t2_timeout > 0)) { dhcp->t1_timeout = 0; } +#endif if (dhcp->subnet_mask_given) { /* copy offered network mask */ diff --git a/components/lwip/include/lwip/lwip/dhcp.h b/components/lwip/include/lwip/lwip/dhcp.h index c3a057ac0..f282c8ab4 100755 --- a/components/lwip/include/lwip/lwip/dhcp.h +++ b/components/lwip/include/lwip/lwip/dhcp.h @@ -45,7 +45,7 @@ extern "C" { #endif /** period (in seconds) of the application calling dhcp_coarse_tmr() */ -#define DHCP_COARSE_TIMER_SECS 60 +#define DHCP_COARSE_TIMER_SECS 1 /** period (in milliseconds) of the application calling dhcp_coarse_tmr() */ #define DHCP_COARSE_TIMER_MSECS (DHCP_COARSE_TIMER_SECS * 1000UL) /** period (in milliseconds) of the application calling dhcp_fine_tmr() */ @@ -76,12 +76,12 @@ struct dhcp struct dhcp_msg *msg_out; /* outgoing msg */ u16_t options_out_len; /* outgoing msg options length */ u16_t request_timeout; /* #ticks with period DHCP_FINE_TIMER_SECS for request timeout */ - u16_t t1_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for renewal time */ - u16_t t2_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for rebind time */ - u16_t t1_renew_time; /* #ticks with period DHCP_COARSE_TIMER_SECS until next renew try */ - u16_t t2_rebind_time; /* #ticks with period DHCP_COARSE_TIMER_SECS until next rebind try */ - u16_t lease_used; /* #ticks with period DHCP_COARSE_TIMER_SECS since last received DHCP ack */ - u16_t t0_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for lease time */ + u32_t t1_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for renewal time */ + u32_t t2_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for rebind time */ + u32_t t1_renew_time; /* #ticks with period DHCP_COARSE_TIMER_SECS until next renew try */ + u32_t t2_rebind_time; /* #ticks with period DHCP_COARSE_TIMER_SECS until next rebind try */ + u32_t lease_used; /* #ticks with period DHCP_COARSE_TIMER_SECS since last received DHCP ack */ + u32_t t0_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for lease time */ ip_addr_t server_ip_addr; /* dhcp server address that offered this lease (ip_addr_t because passed to UDP) */ ip4_addr_t offered_ip_addr; ip4_addr_t offered_sn_mask; diff --git a/components/lwip/include/lwip/port/lwipopts.h b/components/lwip/include/lwip/port/lwipopts.h index dc8264947..60d7ecf21 100644 --- a/components/lwip/include/lwip/port/lwipopts.h +++ b/components/lwip/include/lwip/port/lwipopts.h @@ -602,6 +602,7 @@ #define ESP_LIGHT_SLEEP 1 #define ESP_L2_TO_L3_COPY CONFIG_L2_TO_L3_COPY #define ESP_CNT_DEBUG 0 +#define ESP_DHCP_TIMER 1 #define TCP_WND_DEFAULT (4*TCP_MSS) #define TCP_SND_BUF_DEFAULT (2*TCP_MSS) From fabe0493c2c1a189efa579353c17f81d63df3dd3 Mon Sep 17 00:00:00 2001 From: XiaXiaotian Date: Wed, 1 Mar 2017 20:42:46 +0800 Subject: [PATCH 061/112] mac address: add user set mac address add menuconfig for user to set mac address of wifi, bt and ethernet. --- components/bt/Kconfig | 9 ++++++ components/esp32/Kconfig | 18 +++++++++++ components/esp32/include/esp_system.h | 20 +++++++++++++ components/esp32/lib | 2 +- components/esp32/system_api.c | 43 +++++++++++++++++++++++++++ components/ethernet/Kconfig | 9 ++++++ components/ethernet/emac_main.c | 3 +- 7 files changed, 101 insertions(+), 3 deletions(-) diff --git a/components/bt/Kconfig b/components/bt/Kconfig index 63dce8d1f..1dd04bb0b 100644 --- a/components/bt/Kconfig +++ b/components/bt/Kconfig @@ -3,6 +3,15 @@ menuconfig BT_ENABLED help Select this option to enable Bluetooth stack and show the submenu with Bluetooth configuration choices. +config ESP_MAC_OFFSET_BT + int "MAC address offset value of WiFi station" + depends on BT_ENABLED + range 0 255 + default 2 + help + The offset value of bluetooth MAC address from the MAC address which is read from efuse. + This offset value must be different from that of WiFi softap, WiFi station and ethernet. + config BTC_TASK_STACK_SIZE int "Bluetooth event (callback to application) task stack size" depends on BT_ENABLED diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index 8aa0ed3b5..361ddccd5 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -481,6 +481,24 @@ menuconfig WIFI_ENABLED help Select this option to enable WiFi stack and show the submenu with WiFi configuration choices. +config ESP_MAC_OFFSET_WIFI_STA + int "MAC address offset value of WiFi station" + depends on WIFI_ENABLED + range 0 255 + default 0 + help + The offset value of WiFi station MAC address from the MAC address which is read from efuse. + This offset value must be different from that of WiFi softap, bluetooth and ethernet. + +config ESP_MAC_OFFSET_WIFI_SOFTAP + int "MAC address offset value of WiFi softap" + depends on WIFI_ENABLED + range 0 255 + default 1 + help + The offset value of WiFi softap MAC address from the MAC address which is read from efuse. + This offset value must be different from that of WiFi station, bluetooth and ethernet. + config SW_COEXIST_ENABLE bool "Software controls WiFi/Bluetooth coexistence" depends on WIFI_ENABLED && BT_ENABLED diff --git a/components/esp32/include/esp_system.h b/components/esp32/include/esp_system.h index 30701761a..b127d56fe 100644 --- a/components/esp32/include/esp_system.h +++ b/components/esp32/include/esp_system.h @@ -24,6 +24,13 @@ extern "C" { #endif +enum { + ESP_MAC_WIFI_STA, + ESP_MAC_WIFI_SOFTAP, + ESP_MAC_BT, + ESP_MAC_ETH, +}; + /** * @attention application don't need to call this function anymore. It do nothing and will * be removed in future version. @@ -115,6 +122,19 @@ esp_err_t esp_efuse_read_mac(uint8_t* mac); */ esp_err_t system_efuse_read_mac(uint8_t mac[6]) __attribute__ ((deprecated)); +/** + * @brief Read hardware MAC address and set MAC address of the interface. + * + * This function first reads hardware MAC address from efuse. Then set the MAC address of the interface + * including wifi station, wifi softap, bluetooth and ethernet according to the offset value in menuconfig. + * + * @param mac MAC address of the interface, length: 6 bytes. + * @param interface interface, 0:wifi station, 1:wifi softap, 2:bluetooth, 3:ethernet. + * + * @return ESP_OK on success + */ +esp_err_t esp_read_mac(uint8_t* mac, int interface); + /** * Get SDK version * diff --git a/components/esp32/lib b/components/esp32/lib index 7b06303c0..e22ec1a51 160000 --- a/components/esp32/lib +++ b/components/esp32/lib @@ -1 +1 @@ -Subproject commit 7b06303c0fa416aea7f86b7596e84db367189066 +Subproject commit e22ec1a5140dca2bb44f9bfb3147911fa4ebb8fe diff --git a/components/esp32/system_api.c b/components/esp32/system_api.c index d984af78a..7f1243f5d 100644 --- a/components/esp32/system_api.c +++ b/components/esp32/system_api.c @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include + #include "esp_system.h" #include "esp_attr.h" #include "esp_wifi.h" @@ -72,6 +74,47 @@ esp_err_t esp_efuse_read_mac(uint8_t* mac) esp_err_t system_efuse_read_mac(uint8_t mac[6]) __attribute__((alias("esp_efuse_read_mac"))); +esp_err_t esp_read_mac(uint8_t* mac, int interface) +{ + uint8_t efuse_mac[6]; + + if (mac == NULL) { + ESP_LOGE(TAG, "mac address param is NULL"); + abort(); + } + + esp_efuse_read_mac(efuse_mac); + + switch (interface) { +#if CONFIG_WIFI_ENABLED + case ESP_MAC_WIFI_STA: + memcpy(mac, efuse_mac, 6); + mac[5] += CONFIG_ESP_MAC_OFFSET_WIFI_STA; + break; + case ESP_MAC_WIFI_SOFTAP: + memcpy(mac, efuse_mac, 6); + mac[5] += CONFIG_ESP_MAC_OFFSET_WIFI_SOFTAP; + break; +#endif +#if CONFIG_BT_ENABLED + case ESP_MAC_BT: + memcpy(mac, efuse_mac, 6); + mac[5] += CONFIG_ESP_MAC_OFFSET_BT; + break; +#endif +#if CONFIG_ETHERNET + case ESP_MAC_ETH: + memcpy(mac, efuse_mac, 6); + mac[5] += CONFIG_ESP_MAC_OFFSET_ETH; + break; +#endif + default: + ESP_LOGW(TAG, "wrong mac type"); + break; + } + + return ESP_OK; +} void esp_restart_noos() __attribute__ ((noreturn)); diff --git a/components/ethernet/Kconfig b/components/ethernet/Kconfig index 46e86cc60..230e53cdc 100644 --- a/components/ethernet/Kconfig +++ b/components/ethernet/Kconfig @@ -4,6 +4,15 @@ menuconfig ETHERNET help Select this option to enable ethernet driver and show the submenu with ethernet features. +config ESP_MAC_OFFSET_ETH + int "MAC address offset value of ethernet" + depends on ETHERNET + range 0 255 + default 3 + help + The offset value of ethernet MAC address from the MAC address which is read from efuse. + This offset value must be different from that of WiFi softap, bluetooth and WiFi station. + config DMA_RX_BUF_NUM int "Number of DMA RX buffers" range 3 20 diff --git a/components/ethernet/emac_main.c b/components/ethernet/emac_main.c index 5479ec399..8c93a1830 100644 --- a/components/ethernet/emac_main.c +++ b/components/ethernet/emac_main.c @@ -75,8 +75,7 @@ esp_err_t emac_post(emac_sig_t sig, emac_par_t par); static void emac_macaddr_init(void) { - esp_efuse_read_mac(&(emac_config.macaddr[0])); - emac_config.macaddr[5] = emac_config.macaddr[5] + 3; + esp_read_mac(&(emac_config.macaddr[0]), ESP_MAC_ETH); } void esp_eth_get_mac(uint8_t mac[6]) From d3eede21107059d2e376e8ac2df98feb0c0f38ce Mon Sep 17 00:00:00 2001 From: XiaXiaotian Date: Thu, 2 Mar 2017 14:57:45 +0800 Subject: [PATCH 062/112] mac address: add the number of MAC address generated from efuse for user to choose 1. Add the number of MAC address generated from efuse for user to choose. 2. Add MAC address derive method. --- components/bt/Kconfig | 9 ---- components/bt/bt.c | 1 - components/esp32/Kconfig | 40 ++++++++------- components/esp32/include/esp_system.h | 42 ++++++++++++++-- components/esp32/system_api.c | 72 +++++++++++++++++++++------ components/ethernet/Kconfig | 9 ---- 6 files changed, 115 insertions(+), 58 deletions(-) diff --git a/components/bt/Kconfig b/components/bt/Kconfig index 1dd04bb0b..63dce8d1f 100644 --- a/components/bt/Kconfig +++ b/components/bt/Kconfig @@ -3,15 +3,6 @@ menuconfig BT_ENABLED help Select this option to enable Bluetooth stack and show the submenu with Bluetooth configuration choices. -config ESP_MAC_OFFSET_BT - int "MAC address offset value of WiFi station" - depends on BT_ENABLED - range 0 255 - default 2 - help - The offset value of bluetooth MAC address from the MAC address which is read from efuse. - This offset value must be different from that of WiFi softap, WiFi station and ethernet. - config BTC_TASK_STACK_SIZE int "Bluetooth event (callback to application) task stack size" depends on BT_ENABLED diff --git a/components/bt/bt.c b/components/bt/bt.c index 9af9dd0ed..e8f4204ef 100644 --- a/components/bt/bt.c +++ b/components/bt/bt.c @@ -45,7 +45,6 @@ extern void btdm_controller_deinit(void); extern int btdm_controller_enable(esp_bt_mode_t mode); extern int btdm_controller_disable(esp_bt_mode_t mode); extern void btdm_rf_bb_init(void); -extern int esp_read_mac(uint8_t *mac, int type); /* VHCI function interface */ typedef struct vhci_host_callback { diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index 361ddccd5..eea04a332 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -105,6 +105,28 @@ config MEMMAP_SPISRAM main memory map. Enable this if you have this hardware and want to use it in the same way as on-chip RAM. +choice NUMBER_OF_MAC_ADDRESS_GENERATED_FROM_EFUSE + bool "Number of MAC address generated from the hardware MAC address in efuse" + default FOUR_MAC_ADDRESS_FROM_EFUSE + help + Config the number of MAC address which is generated from the hardware MAC address in efuse. + If the number is two, the MAC addresses of WiFi station and bluetooth are generated from + the hardware MAC address in efuse. The MAC addresses of WiFi softap and ethernet are derived + from that of WiFi station and bluetooth respectively. + If the number is four, the MAC addresses of WiFi station, WiFi softap, bluetooth and ethernet + are all generated from the hardware MAC address in efuse. + +config TWO_MAC_ADDRESS_FROM_EFUSE + bool "Two" +config FOUR_MAC_ADDRESS_FROM_EFUSE + bool "Four" +endchoice + +config NUMBER_OF_MAC_ADDRESS_GENERATED_FROM_EFUSE + int + default 2 if TWO_MAC_ADDRESS_FROM_EFUSE + default 4 if FOUR_MAC_ADDRESS_FROM_EFUSE + config SYSTEM_EVENT_QUEUE_SIZE int "System event queue size" default 32 @@ -481,24 +503,6 @@ menuconfig WIFI_ENABLED help Select this option to enable WiFi stack and show the submenu with WiFi configuration choices. -config ESP_MAC_OFFSET_WIFI_STA - int "MAC address offset value of WiFi station" - depends on WIFI_ENABLED - range 0 255 - default 0 - help - The offset value of WiFi station MAC address from the MAC address which is read from efuse. - This offset value must be different from that of WiFi softap, bluetooth and ethernet. - -config ESP_MAC_OFFSET_WIFI_SOFTAP - int "MAC address offset value of WiFi softap" - depends on WIFI_ENABLED - range 0 255 - default 1 - help - The offset value of WiFi softap MAC address from the MAC address which is read from efuse. - This offset value must be different from that of WiFi station, bluetooth and ethernet. - config SW_COEXIST_ENABLE bool "Software controls WiFi/Bluetooth coexistence" depends on WIFI_ENABLED && BT_ENABLED diff --git a/components/esp32/include/esp_system.h b/components/esp32/include/esp_system.h index b127d56fe..9a88743b8 100644 --- a/components/esp32/include/esp_system.h +++ b/components/esp32/include/esp_system.h @@ -24,12 +24,16 @@ extern "C" { #endif -enum { +typedef enum { ESP_MAC_WIFI_STA, ESP_MAC_WIFI_SOFTAP, ESP_MAC_BT, ESP_MAC_ETH, -}; +} esp_mac_type_t; + +#define TWO_MAC_ADDRESS_FROM_EFUSE 2 +#define FOUR_MAC_ADDRESS_FROM_EFUSE 4 +#define NUM_MAC_ADDRESS_FROM_EFUSE CONFIG_NUMBER_OF_MAC_ADDRESS_GENERATED_FROM_EFUSE /** * @attention application don't need to call this function anymore. It do nothing and will @@ -126,14 +130,42 @@ esp_err_t system_efuse_read_mac(uint8_t mac[6]) __attribute__ ((deprecated)); * @brief Read hardware MAC address and set MAC address of the interface. * * This function first reads hardware MAC address from efuse. Then set the MAC address of the interface - * including wifi station, wifi softap, bluetooth and ethernet according to the offset value in menuconfig. + * including wifi station, wifi softap, bluetooth and ethernet. * * @param mac MAC address of the interface, length: 6 bytes. - * @param interface interface, 0:wifi station, 1:wifi softap, 2:bluetooth, 3:ethernet. + * @param type type of MAC address, 0:wifi station, 1:wifi softap, 2:bluetooth, 3:ethernet. * * @return ESP_OK on success */ -esp_err_t esp_read_mac(uint8_t* mac, int interface); +esp_err_t esp_read_mac(uint8_t* mac, esp_mac_type_t type); + +/** + * @brief Derive MAC address. + * + * This function derives a local MAC address from an universal MAC address. + * Addresses can either be universally administered addresses or locally administered addresses. + * A universally administered address is uniquely assigned to a device by its manufacturer. + * The first three octets (in transmission order) identify the organization that issued the identifier + * and are known as the Organizationally Unique Identifier (OUI).[4] The remainder of the address + * (three octets for MAC-48 and EUI-48 or five for EUI-64) are assigned by that organization in nearly + * any manner they please, subject to the constraint of uniqueness. A locally administered address is + * assigned to a device by a network administrator, overriding the burned-in address. + * Universally administered and locally administered addresses are distinguished by setting + * the second-least-significant bit of the first octet of the address. This bit is also referred to + * as the U/L bit, short for Universal/Local, which identifies how the address is administered. + * If the bit is 0, the address is universally administered. If it is 1, the address is locally administered. + * In the example address 06-00-00-00-00-00 the first octet is 06 (hex), the binary form of which is 00000110, + * where the second-least-significant bit is 1. Therefore, it is a locally administered address.[7] Consequently, + * this bit is 0 in all OUIs. + * In ESP32, universal MAC address is generated from the hardware MAC address in efuse. + * Local MAC address is derived from the universal MAC address. + * + * @param dst_mac Derived local MAC address, length: 6 bytes. + * @param src_mac Source universal MAC address, length: 6 bytes. + * + * @return ESP_OK on success + */ +esp_err_t esp_derive_mac(uint8_t* dst_mac, const uint8_t* src_mac); /** * Get SDK version diff --git a/components/esp32/system_api.c b/components/esp32/system_api.c index 7f1243f5d..429ef867e 100644 --- a/components/esp32/system_api.c +++ b/components/esp32/system_api.c @@ -74,42 +74,82 @@ esp_err_t esp_efuse_read_mac(uint8_t* mac) esp_err_t system_efuse_read_mac(uint8_t mac[6]) __attribute__((alias("esp_efuse_read_mac"))); -esp_err_t esp_read_mac(uint8_t* mac, int interface) +esp_err_t esp_derive_mac(uint8_t* dst_mac, const uint8_t* src_mac) +{ + uint8_t idx; + + if (dst_mac == NULL || src_mac == NULL) { + ESP_LOGE(TAG, "mac address param is NULL"); + return ESP_ERR_INVALID_ARG; + } + + memcpy(dst_mac, src_mac, 6); + for (idx = 0; idx < 64; idx++) { + dst_mac[0] = src_mac[0] | 0x02; + dst_mac[0] ^= idx << 2; + + if (memcmp(dst_mac, src_mac, 6)) { + break; + } + } + + return ESP_OK; +} + +esp_err_t esp_read_mac(uint8_t* mac, esp_mac_type_t type) { uint8_t efuse_mac[6]; if (mac == NULL) { ESP_LOGE(TAG, "mac address param is NULL"); - abort(); + return ESP_ERR_INVALID_ARG; } + if (type < ESP_MAC_WIFI_STA || type > ESP_MAC_ETH) { + ESP_LOGE(TAG, "mac type is incorrect"); + return ESP_ERR_INVALID_ARG; + } + + _Static_assert(NUM_MAC_ADDRESS_FROM_EFUSE == FOUR_MAC_ADDRESS_FROM_EFUSE \ + || NUM_MAC_ADDRESS_FROM_EFUSE == TWO_MAC_ADDRESS_FROM_EFUSE, \ + "incorrect NUM_MAC_ADDRESS_FROM_EFUSE value"); + esp_efuse_read_mac(efuse_mac); - switch (interface) { -#if CONFIG_WIFI_ENABLED + switch (type) { case ESP_MAC_WIFI_STA: memcpy(mac, efuse_mac, 6); - mac[5] += CONFIG_ESP_MAC_OFFSET_WIFI_STA; break; case ESP_MAC_WIFI_SOFTAP: - memcpy(mac, efuse_mac, 6); - mac[5] += CONFIG_ESP_MAC_OFFSET_WIFI_SOFTAP; + if (NUM_MAC_ADDRESS_FROM_EFUSE == FOUR_MAC_ADDRESS_FROM_EFUSE) { + memcpy(mac, efuse_mac, 6); + mac[5] += 1; + } + else if (NUM_MAC_ADDRESS_FROM_EFUSE == TWO_MAC_ADDRESS_FROM_EFUSE) { + esp_derive_mac(mac, efuse_mac); + } break; -#endif -#if CONFIG_BT_ENABLED case ESP_MAC_BT: memcpy(mac, efuse_mac, 6); - mac[5] += CONFIG_ESP_MAC_OFFSET_BT; + if (NUM_MAC_ADDRESS_FROM_EFUSE == FOUR_MAC_ADDRESS_FROM_EFUSE) { + mac[5] += 2; + } + else if (NUM_MAC_ADDRESS_FROM_EFUSE == TWO_MAC_ADDRESS_FROM_EFUSE) { + mac[5] += 1; + } break; -#endif -#if CONFIG_ETHERNET case ESP_MAC_ETH: - memcpy(mac, efuse_mac, 6); - mac[5] += CONFIG_ESP_MAC_OFFSET_ETH; + if (NUM_MAC_ADDRESS_FROM_EFUSE == FOUR_MAC_ADDRESS_FROM_EFUSE) { + memcpy(mac, efuse_mac, 6); + mac[5] += 3; + } + else if (NUM_MAC_ADDRESS_FROM_EFUSE == TWO_MAC_ADDRESS_FROM_EFUSE) { + efuse_mac[5] += 1; + esp_derive_mac(mac, efuse_mac); + } break; -#endif default: - ESP_LOGW(TAG, "wrong mac type"); + ESP_LOGW(TAG, "incorrect mac type"); break; } diff --git a/components/ethernet/Kconfig b/components/ethernet/Kconfig index 230e53cdc..46e86cc60 100644 --- a/components/ethernet/Kconfig +++ b/components/ethernet/Kconfig @@ -4,15 +4,6 @@ menuconfig ETHERNET help Select this option to enable ethernet driver and show the submenu with ethernet features. -config ESP_MAC_OFFSET_ETH - int "MAC address offset value of ethernet" - depends on ETHERNET - range 0 255 - default 3 - help - The offset value of ethernet MAC address from the MAC address which is read from efuse. - This offset value must be different from that of WiFi softap, bluetooth and WiFi station. - config DMA_RX_BUF_NUM int "Number of DMA RX buffers" range 3 20 From 6739d5b99f3343be192556e1e71c586a0d03aa43 Mon Sep 17 00:00:00 2001 From: Jeroen Domburg Date: Mon, 27 Feb 2017 16:34:19 +0800 Subject: [PATCH 063/112] Add xPortInIsrContext function + unit test. This function returns true when the current CPU runs in an interrupt handler context. --- components/esp32/include/soc/cpu.h | 10 ---- .../freertos/include/freertos/portable.h | 6 +++ components/freertos/port.c | 19 ++++++- .../test/test_freertos_isinisrcontext.c | 51 +++++++++++++++++++ components/newlib/locks.c | 5 +- 5 files changed, 77 insertions(+), 14 deletions(-) create mode 100644 components/freertos/test/test_freertos_isinisrcontext.c diff --git a/components/esp32/include/soc/cpu.h b/components/esp32/include/soc/cpu.h index 2e0ac7de8..7e1301345 100644 --- a/components/esp32/include/soc/cpu.h +++ b/components/esp32/include/soc/cpu.h @@ -36,16 +36,6 @@ static inline void *get_sp() return sp; } -/* Return true if the CPU is in an interrupt context - (PS.UM == 0) -*/ -static inline bool cpu_in_interrupt_context(void) -{ - uint32_t ps; - RSR(PS, ps); - return (ps & PS_UM) == 0; -} - /* Functions to set page attributes for Region Protection option in the CPU. * See Xtensa ISA Reference manual for explanation of arguments (section 4.6.3.2). */ diff --git a/components/freertos/include/freertos/portable.h b/components/freertos/include/freertos/portable.h index 0c10ac36e..e46ec17fb 100644 --- a/components/freertos/include/freertos/portable.h +++ b/components/freertos/include/freertos/portable.h @@ -194,6 +194,12 @@ void vPortYieldOtherCore( BaseType_t coreid) PRIVILEGED_FUNCTION; */ void vPortSetStackWatchpoint( void* pxStackStart ); +/* + * Returns true if the current core is in ISR context; low prio ISR, med prio ISR or timer tick ISR. High prio ISRs + * aren't detected here, but they normally cannot call C code, so that should not be an issue anyway. + */ +BaseType_t xPortInIsrContext(); + /* * The structures and methods of manipulating the MPU are contained within the * port layer. diff --git a/components/freertos/port.c b/components/freertos/port.c index 3c26edfab..756e14295 100644 --- a/components/freertos/port.c +++ b/components/freertos/port.c @@ -115,7 +115,7 @@ extern void _xt_coproc_init(void); /*-----------------------------------------------------------*/ unsigned port_xSchedulerRunning[portNUM_PROCESSORS] = {0}; // Duplicate of inaccessible xSchedulerRunning; needed at startup to avoid counting nesting -unsigned port_interruptNesting[portNUM_PROCESSORS] = {0}; // Interrupt nesting level +unsigned port_interruptNesting[portNUM_PROCESSORS] = {0}; // Interrupt nesting level. Increased/decreased in portasm.c, _frxt_int_enter/_frxt_int_exit /*-----------------------------------------------------------*/ @@ -256,9 +256,24 @@ void vPortStoreTaskMPUSettings( xMPU_SETTINGS *xMPUSettings, const struct xMEMOR #endif +/* + * Returns true if the current core is in ISR context; low prio ISR, med prio ISR or timer tick ISR. High prio ISRs + * aren't detected here, but they normally cannot call C code, so that should not be an issue anyway. + */ +BaseType_t xPortInIsrContext() +{ + unsigned int irqStatus; + BaseType_t ret; + irqStatus=portENTER_CRITICAL_NESTED(); + ret=(port_interruptNesting[xPortGetCoreID()] != 0); + portEXIT_CRITICAL_NESTED(irqStatus); + return ret; +} + + void vPortAssertIfInISR() { - configASSERT(port_interruptNesting[xPortGetCoreID()]==0) + configASSERT(xPortInIsrContext()); } /* diff --git a/components/freertos/test/test_freertos_isinisrcontext.c b/components/freertos/test/test_freertos_isinisrcontext.c new file mode 100644 index 000000000..9c7d31c27 --- /dev/null +++ b/components/freertos/test/test_freertos_isinisrcontext.c @@ -0,0 +1,51 @@ +/* + See if xPortInIsrContext works +*/ + +#include +#include +#include "rom/ets_sys.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "freertos/queue.h" +#include "freertos/xtensa_api.h" +#include "unity.h" +#include "esp_intr_alloc.h" +#include "xtensa/hal.h" + +static volatile int in_int_context, int_handled; + + +static void testint(void *arg) { + xthal_set_ccompare(1, xthal_get_ccount()+8000000000); + ets_printf("INT!\n"); + if (xPortInIsrContext()) in_int_context++; + int_handled++; +} + + +static void testthread(void *arg) { + intr_handle_t handle; + in_int_context=0; + int_handled=0; + TEST_ASSERT(!xPortInIsrContext()); + xthal_set_ccompare(2, xthal_get_ccount()+8000000); + esp_intr_alloc(ETS_INTERNAL_TIMER1_INTR_SOURCE, 0, &testint, NULL, &handle); + vTaskDelay(100 / portTICK_PERIOD_MS); + TEST_ASSERT(int_handled); + TEST_ASSERT(in_int_context); + esp_intr_free(handle); + vTaskDelete(NULL); +} + + +TEST_CASE("xPortInIsrContext test", "[freertos]") +{ + xTaskCreatePinnedToCore(testthread, "tst" , 4096, NULL, 3, NULL, 0); + vTaskDelay(150 / portTICK_PERIOD_MS); + xTaskCreatePinnedToCore(testthread, "tst" , 4096, NULL, 3, NULL, 1); + vTaskDelay(150 / portTICK_PERIOD_MS); +} + diff --git a/components/newlib/locks.c b/components/newlib/locks.c index 21b974a1f..c143e3a3d 100644 --- a/components/newlib/locks.c +++ b/components/newlib/locks.c @@ -21,6 +21,7 @@ #include "freertos/semphr.h" #include "freertos/portmacro.h" #include "freertos/task.h" +#include "freertos/portable.h" /* Notes on our newlib lock implementation: * @@ -126,7 +127,7 @@ static int IRAM_ATTR lock_acquire_generic(_lock_t *lock, uint32_t delay, uint8_t } BaseType_t success; - if (cpu_in_interrupt_context()) { + if (xPortInIsrContext()) { /* In ISR Context */ if (mutex_type == queueQUEUE_TYPE_RECURSIVE_MUTEX) { abort(); /* recursive mutexes make no sense in ISR context */ @@ -180,7 +181,7 @@ static void IRAM_ATTR lock_release_generic(_lock_t *lock, uint8_t mutex_type) { return; } - if (cpu_in_interrupt_context()) { + if (xPortInIsrContext()) { if (mutex_type == queueQUEUE_TYPE_RECURSIVE_MUTEX) { abort(); /* indicates logic bug, it shouldn't be possible to lock recursively in ISR */ } From abdd8feebb7a022f6890de0b72bc241703bbc611 Mon Sep 17 00:00:00 2001 From: Liu Zhi Fu Date: Tue, 21 Feb 2017 14:52:25 +0800 Subject: [PATCH 064/112] esp32: menuconfig adds some WiFi options 1. Add options to enable/disable AMPDU 2. Add options to enable/disable WIFI NVS 3. Add options to configure WiFi RX/TX buffer number --- components/esp32/Kconfig | 56 ++++++++++++++++++++++++++--- components/esp32/include/esp_task.h | 12 ------- components/esp32/include/esp_wifi.h | 44 ++++++++++++++++++++--- components/esp32/lib | 2 +- 4 files changed, 91 insertions(+), 23 deletions(-) diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index eea04a332..ab1e04e80 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -513,15 +513,61 @@ config SW_COEXIST_ENABLE automatically managed, no user intervention is required. -config ESP32_WIFI_RX_BUFFER_NUM - int "Max number of WiFi RX buffers" +config ESP32_WIFI_STATIC_RX_BUFFER_NUM + int "Max number of WiFi static RX buffers" depends on WIFI_ENABLED range 2 25 default 10 help - Set the number of WiFi rx buffers. Each buffer takes approximately 1.6KB of RAM. - Larger number for higher throughput but more memory. Smaller number for lower - throughput but less memory. + Set the number of WiFi static rx buffers. Each buffer takes approximately 1.6KB of RAM. + The static rx buffers are allocated when esp_wifi_init is called, they are not freed + until esp_wifi_deinit is called. + WiFi hardware use these buffers to receive packets, generally larger number for higher + throughput but more memory, smaller number for lower throughput but less memory. + +config ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM + int "Max number of WiFi dynamic RX buffers" + depends on WIFI_ENABLED + range 0 64 + default 0 + help + Set the number of WiFi dynamic rx buffers, 0 means no limitation for dynamic rx buffer + allocation. The size of dynamic rx buffers is not fixed. + For each received packet in static rx buffers, WiFi driver makes a copy + to dynamic rx buffers and then deliver it to high layer stack. The dynamic rx buffer + is freed when the application, such as socket, successfully received the packet. + For some applications, the WiFi driver receiving speed is faster than application + consuming speed, we may run out of memory if no limitation for the dynamic rx buffer + number. Generally the number of dynamic rx buffer should be no less than static + rx buffer number if it is not 0. + +config ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM + int "Max number of WiFi dynamic TX buffers" + depends on WIFI_ENABLED + range 16 64 + default 32 + help + Set the number of WiFi dynamic tx buffers, 0 means no limitation for dynamic tx buffer + allocation. The size of dynamic tx buffers is not fixed. + For each tx packet from high layer stack, WiFi driver make a copy of it. For some applications, + especially the UDP application, the high layer deliver speed is faster than the WiFi tx + speed, we may run out of memory if no limitation for the dynamic tx buffer number. + + +config ESP32_WIFI_AMPDU_ENABLED + bool "WiFi AMPDU" + depends on WIFI_ENABLED + default y + help + Select this option to enable AMPDU feature + + +config ESP32_WIFI_NVS_ENABLED + bool "WiFi NVS flash" + depends on WIFI_ENABLED + default y + help + Select this option to enable WiFi NVS flash config PHY_ENABLED bool diff --git a/components/esp32/include/esp_task.h b/components/esp32/include/esp_task.h index bb028bf48..04f3178a1 100644 --- a/components/esp32/include/esp_task.h +++ b/components/esp32/include/esp_task.h @@ -31,18 +31,6 @@ #define ESP_TASK_PRIO_MAX (configMAX_PRIORITIES) #define ESP_TASK_PRIO_MIN (0) -/* Wifi library task */ -#define ESP_TASKD_WATCHDOG_PRIO (ESP_TASK_PRIO_MAX - 1) -#define ESP_TASKD_WATCHDOG_STACK 2048 -#define ESP_TASK_WPA2_PRIO (ESP_TASK_PRIO_MAX - 1) -#define ESP_TASK_WPA2_STACK 2048 -#define ESP_TASKD_WIFI_PRIO (ESP_TASK_PRIO_MAX - 2) -#define ESP_TASKD_WIFI_STACK 8196 -#define ESP_TASKD_WIFI_TIMER_PRIO (ESP_TASK_PRIO_MAX - 3) -#define ESP_TASKD_WIFI_TIMER_STACK 2048 -#define ESP_TASK_WPS_PRIO (ESP_TASK_PRIO_MIN + 2) -#define ESP_TASK_WPS_STACK 2048 - /* Bt contoller Task */ /* controller */ #define ESP_TASK_BT_CONTROLLER_PRIO (ESP_TASK_PRIO_MAX - 1) diff --git a/components/esp32/include/esp_wifi.h b/components/esp32/include/esp_wifi.h index 9f3b1ed70..2312bc08a 100755 --- a/components/esp32/include/esp_wifi.h +++ b/components/esp32/include/esp_wifi.h @@ -94,14 +94,45 @@ extern "C" { * @brief WiFi stack configuration parameters passed to esp_wifi_init call. */ typedef struct { - system_event_handler_t event_handler; /**< WiFi event handler */ - uint32_t rx_buf_num; /**< WiFi RX buffer number */ + system_event_handler_t event_handler; /**< WiFi event handler */ + int static_rx_buf_num; /**< WiFi static RX buffer number */ + int dynamic_rx_buf_num; /**< WiFi dynamic RX buffer number */ + int dynamic_tx_buf_num; /**< WiFi dynamic TX buffer number */ + int ampdu_enable; /**< WiFi AMPDU feature enable flag */ + int nvs_enable; /**< WiFi NVS flash enable flag */ + int nano_enable; /**< Nano option for printf/scan family enable flag */ + int magic; /**< WiFi init magic number, it should be the last field */ } wifi_init_config_t; +#if CONFIG_ESP32_WIFI_AMPDU_ENABLED +#define WIFI_AMPDU_ENABLED 1 +#else +#define WIFI_AMPDU_ENABLED 0 +#endif + +#if CONFIG_ESP32_WIFI_NVS_ENABLED +#define WIFI_NVS_ENABLED 1 +#else +#define WIFI_NVS_ENABLED 0 +#endif + +#if CONFIG_NEWLIB_NANO_FORMAT +#define WIFI_NANO_FORMAT_ENABLED 1 +#else +#define WIFI_NANO_FORMAT_ENABLED 0 +#endif + +#define WIFI_INIT_CONFIG_MAGIC 0x1F2F3F4F #ifdef CONFIG_WIFI_ENABLED #define WIFI_INIT_CONFIG_DEFAULT() { \ .event_handler = &esp_event_send, \ - .rx_buf_num = CONFIG_ESP32_WIFI_RX_BUFFER_NUM, \ + .static_rx_buf_num = CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM,\ + .dynamic_rx_buf_num = CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM,\ + .dynamic_tx_buf_num = CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM,\ + .ampdu_enable = WIFI_AMPDU_ENABLED,\ + .nvs_enable = WIFI_NVS_ENABLED,\ + .nano_enable = WIFI_NANO_FORMAT_ENABLED,\ + .magic = WIFI_INIT_CONFIG_MAGIC\ }; #else #define WIFI_INIT_CONFIG_DEFAULT #error Wifi is disabled in config, WIFI_INIT_CONFIG_DEFAULT will not work @@ -113,8 +144,11 @@ typedef struct { * WiFi NVS structure etc, this WiFi also start WiFi task * * @attention 1. This API must be called before all other WiFi API can be called - * @attention 2. event_handler field in cfg should be set to a valid event handler function. - * In most cases, use the WIFI_INIT_CONFIG_DEFAULT macro which sets esp_event_send(). + * @attention 2. Always use WIFI_INIT_CONFIG_DEFAULT macro to init the config to default values, this can + * guarantee all the fields got correct value when more fields are added into wifi_init_config_t + * in future release. If you want to set your owner initial values, overwrite the default values + * which are set by WIFI_INIT_CONFIG_DEFAULT, please be notified that the field 'magic' of + * wifi_init_config_t should always be WIFI_INIT_CONFIG_MAGIC! * * @param config provide WiFi init configuration * diff --git a/components/esp32/lib b/components/esp32/lib index e22ec1a51..57b2234ed 160000 --- a/components/esp32/lib +++ b/components/esp32/lib @@ -1 +1 @@ -Subproject commit e22ec1a5140dca2bb44f9bfb3147911fa4ebb8fe +Subproject commit 57b2234ed3a501ddbc36bdc032e1714d2838608d From 65b7b22c09eedb14a412ebdbf8179e2df80d7bfb Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Thu, 2 Mar 2017 19:35:28 +0800 Subject: [PATCH 065/112] esp32: update io_mux_reg.h to latest version fixes https://github.com/espressif/esp-idf/issues/349 --- components/esp32/include/soc/io_mux_reg.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/esp32/include/soc/io_mux_reg.h b/components/esp32/include/soc/io_mux_reg.h index de8fe7ec9..459a97009 100644 --- a/components/esp32/include/soc/io_mux_reg.h +++ b/components/esp32/include/soc/io_mux_reg.h @@ -88,7 +88,7 @@ static inline void __attribute__ ((deprecated)) PIN_PULLDWN_EN(uint32_t PIN_NAME #define FUNC_GPIO0_GPIO0_0 0 #define PERIPHS_IO_MUX_U0TXD_U (DR_REG_IO_MUX_BASE +0x88) -#define FUNC_U0TXD_EMAC_RXD2 3 +#define FUNC_U0TXD_EMAC_RXD2 5 #define FUNC_U0TXD_GPIO1 2 #define FUNC_U0TXD_CLK_OUT3 1 #define FUNC_U0TXD_U0TXD 0 @@ -181,7 +181,7 @@ static inline void __attribute__ ((deprecated)) PIN_PULLDWN_EN(uint32_t PIN_NAME #define PERIPHS_IO_MUX_MTMS_U (DR_REG_IO_MUX_BASE +0x30) #define FUNC_MTMS_EMAC_TXD2 5 #define FUNC_MTMS_SD_CLK 4 -#define FUNC_MTMS_HS2_CLk 3 +#define FUNC_MTMS_HS2_CLK 3 #define FUNC_MTMS_GPIO14 2 #define FUNC_MTMS_HSPICLK 1 #define FUNC_MTMS_MTMS 0 From e335f19a4d8efacdaca45e269cf4a8d5c9a9c415 Mon Sep 17 00:00:00 2001 From: "rudi ;-)" Date: Sun, 26 Feb 2017 04:13:39 +0100 Subject: [PATCH 066/112] examples/ethernet: typo, better named Merges #382 https://github.com/espressif/esp-idf/pull/382 --- examples/ethernet/ethernet/main/ethernet_main.c | 2 +- examples/ethernet/ethernet/main/tlk110_phy.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/ethernet/ethernet/main/ethernet_main.c b/examples/ethernet/ethernet/main/ethernet_main.c index 6419c4184..d406ab4dc 100644 --- a/examples/ethernet/ethernet/main/ethernet_main.c +++ b/examples/ethernet/ethernet/main/ethernet_main.c @@ -45,7 +45,7 @@ void phy_tlk110_check_phy_init(void) { while((esp_eth_smi_read(BASIC_MODE_STATUS_REG) & AUTO_NEGOTIATION_COMPLETE ) != AUTO_NEGOTIATION_COMPLETE) {}; - while((esp_eth_smi_read(PHY_STATUS_REG) & AUTO_NEGTIATION_STATUS ) != AUTO_NEGTIATION_STATUS) + while((esp_eth_smi_read(PHY_STATUS_REG) & AUTO_NEGOTIATION_STATUS ) != AUTO_NEGOTIATION_STATUS) {}; while((esp_eth_smi_read(CABLE_DIAGNOSTIC_CONTROL_REG) & DIAGNOSTIC_DONE ) != DIAGNOSTIC_DONE) {}; diff --git a/examples/ethernet/ethernet/main/tlk110_phy.h b/examples/ethernet/ethernet/main/tlk110_phy.h index a21bc57ae..87d512c42 100644 --- a/examples/ethernet/ethernet/main/tlk110_phy.h +++ b/examples/ethernet/ethernet/main/tlk110_phy.h @@ -23,7 +23,7 @@ #define RMII_ENHANCED_MODE BIT(9) #define PHY_STATUS_REG (0x10) -#define AUTO_NEGTIATION_STATUS BIT(4) +#define AUTO_NEGOTIATION_STATUS BIT(4) #define DUPLEX_STATUS BIT(2) #define SPEED_STATUS BIT(1) From f4c47872816c5cb73d1315ab5a004cc640c2ddcb Mon Sep 17 00:00:00 2001 From: "rudi ;-)" Date: Tue, 21 Feb 2017 02:52:27 +0100 Subject: [PATCH 067/112] examples/ethernet: Same sense of meaning SW_STRAP Merges #366 #367 https://github.com/espressif/esp-idf/pull/366 https://github.com/espressif/esp-idf/pull/367 --- examples/ethernet/ethernet/main/ethernet_main.c | 2 +- examples/ethernet/ethernet/main/tlk110_phy.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/ethernet/ethernet/main/ethernet_main.c b/examples/ethernet/ethernet/main/ethernet_main.c index d406ab4dc..f76bd1d76 100644 --- a/examples/ethernet/ethernet/main/ethernet_main.c +++ b/examples/ethernet/ethernet/main/ethernet_main.c @@ -108,7 +108,7 @@ void phy_tlk110_init(void) while (esp_eth_smi_read(PHY_IDENTIFIER_REG) != OUI_MSB_21TO6_DEF) { } - esp_eth_smi_write(SOFTWARE_STRAP_CONTROL_REG, DEFAULT_PHY_CONFIG |SW_STRAP_CONFIG_DONE); + esp_eth_smi_write(SW_STRAP_CONTROL_REG, DEFAULT_PHY_CONFIG | SW_STRAP_CONFIG_DONE); ets_delay_us(300); diff --git a/examples/ethernet/ethernet/main/tlk110_phy.h b/examples/ethernet/ethernet/main/tlk110_phy.h index 87d512c42..63236edeb 100644 --- a/examples/ethernet/ethernet/main/tlk110_phy.h +++ b/examples/ethernet/ethernet/main/tlk110_phy.h @@ -13,7 +13,7 @@ #define PARTNER_ASM_DIR BIT(11) #define PARTNER_PAUSE BIT(10) -#define SOFTWARE_STRAP_CONTROL_REG (0x9) +#define SW_STRAP_CONTROL_REG (0x9) #define SW_STRAP_CONFIG_DONE BIT(15) #define AUTO_MDIX_ENABLE BIT(14) #define AUTO_NEGOTIATION_ENABLE BIT(13) From c08a2871e67ee7003fabee6332a1326d7a4c7368 Mon Sep 17 00:00:00 2001 From: Daniel Campora Date: Mon, 20 Feb 2017 00:42:58 +0000 Subject: [PATCH 068/112] sdmmc: Add width field to the slot config. Therefore if the width is set to 1, you can choose to only configure the CLK, DAT0 and CMD pins. Merges #361 https://github.com/espressif/esp-idf/pull/361 --- components/driver/include/driver/sdmmc_host.h | 2 ++ components/driver/sdmmc_host.c | 23 ++++++++++++------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/components/driver/include/driver/sdmmc_host.h b/components/driver/include/driver/sdmmc_host.h index 0f56c266a..f9f4f7d37 100644 --- a/components/driver/include/driver/sdmmc_host.h +++ b/components/driver/include/driver/sdmmc_host.h @@ -50,6 +50,7 @@ extern "C" { typedef struct { gpio_num_t gpio_cd; ///< GPIO number of card detect signal gpio_num_t gpio_wp; ///< GPIO number of write protect signal + uint8_t width; ///< Bus width used by the slot (might be less than the max width supported) } sdmmc_slot_config_t; #define SDMMC_SLOT_NO_CD ((gpio_num_t) -1) ///< indicates that card detect line is not used @@ -61,6 +62,7 @@ typedef struct { #define SDMMC_SLOT_CONFIG_DEFAULT() {\ .gpio_cd = SDMMC_SLOT_NO_CD, \ .gpio_wp = SDMMC_SLOT_NO_WP, \ + .width = 4, \ } /** diff --git a/components/driver/sdmmc_host.c b/components/driver/sdmmc_host.c index 400c85b88..54c7997b0 100644 --- a/components/driver/sdmmc_host.c +++ b/components/driver/sdmmc_host.c @@ -302,17 +302,24 @@ esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t* slot_config) // Configure pins const sdmmc_slot_info_t* pslot = &s_slot_info[slot]; + + if (slot_config->width > pslot->width) { + return ESP_ERR_INVALID_ARG; + } + configure_pin(pslot->clk); configure_pin(pslot->cmd); configure_pin(pslot->d0); - configure_pin(pslot->d1); - configure_pin(pslot->d2); - configure_pin(pslot->d3); - if (pslot->width == 8) { - configure_pin(pslot->d4); - configure_pin(pslot->d5); - configure_pin(pslot->d6); - configure_pin(pslot->d7); + if (slot_config->width >= 4) { + configure_pin(pslot->d1); + configure_pin(pslot->d2); + configure_pin(pslot->d3); + if (slot_config->width == 8) { + configure_pin(pslot->d4); + configure_pin(pslot->d5); + configure_pin(pslot->d6); + configure_pin(pslot->d7); + } } if (gpio_cd != -1) { gpio_set_direction(gpio_cd, GPIO_MODE_INPUT); From 7bb4c8521a1cda1f0ec0dd0ded139888d8c7c24b Mon Sep 17 00:00:00 2001 From: gbcwbz Date: Sun, 19 Feb 2017 19:33:08 +0800 Subject: [PATCH 069/112] docs: Fix typo in build-system.rst Merges #355 https://github.com/espressif/esp-idf/pull/355 --- docs/build-system.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/build-system.rst b/docs/build-system.rst index b3abbd28f..ea4925f74 100644 --- a/docs/build-system.rst +++ b/docs/build-system.rst @@ -144,7 +144,7 @@ The minimal ``component.mk`` file is an empty file(!). If the file is empty, the See `example component makefiles` for more complete component makefile examples. -Note that there is a different between an empty ``component.mk`` file (which invokes default component build behaviour) and no ``component.mk`` file (which means no default component build behaviour will occur.) It is possible for a component to have no `component.mk` file, if it only contains other files which influence the project configuration or build process. +Note that there is a difference between an empty ``component.mk`` file (which invokes default component build behaviour) and no ``component.mk`` file (which means no default component build behaviour will occur.) It is possible for a component to have no `component.mk` file, if it only contains other files which influence the project configuration or build process. .. component variables: From 3119f936abac87e522fc03a947e087528aeaa955 Mon Sep 17 00:00:00 2001 From: alarruskain Date: Fri, 17 Feb 2017 11:02:00 +0100 Subject: [PATCH 070/112] lwip: Fix hostname set in tcpip_adapter_lwip Hostname for each interface is not correctly stored in "hostinfo" variable. Merges #350 https://github.com/espressif/esp-idf/pull/350 --- components/tcpip_adapter/tcpip_adapter_lwip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/tcpip_adapter/tcpip_adapter_lwip.c b/components/tcpip_adapter/tcpip_adapter_lwip.c index 40f235d54..6e1661754 100644 --- a/components/tcpip_adapter/tcpip_adapter_lwip.c +++ b/components/tcpip_adapter/tcpip_adapter_lwip.c @@ -713,7 +713,7 @@ esp_err_t tcpip_adapter_set_hostname(tcpip_adapter_if_t tcpip_if, const char *ho { #if LWIP_NETIF_HOSTNAME struct netif *p_netif; - static char hostinfo[TCPIP_HOSTNAME_MAX_SIZE + 1][TCPIP_ADAPTER_IF_MAX]; + static char hostinfo[TCPIP_ADAPTER_IF_MAX][TCPIP_HOSTNAME_MAX_SIZE + 1]; if (tcpip_if >= TCPIP_ADAPTER_IF_MAX || hostname == NULL) { return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS; From da723ca11d331c160da2a941fd0036ffef2ad658 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 2 Mar 2017 14:50:58 +1100 Subject: [PATCH 071/112] lwip: Use strlcpy() instead of memcpy() to copy hostname to static buffer --- components/tcpip_adapter/tcpip_adapter_lwip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/tcpip_adapter/tcpip_adapter_lwip.c b/components/tcpip_adapter/tcpip_adapter_lwip.c index 6e1661754..c98825ec6 100644 --- a/components/tcpip_adapter/tcpip_adapter_lwip.c +++ b/components/tcpip_adapter/tcpip_adapter_lwip.c @@ -726,7 +726,7 @@ esp_err_t tcpip_adapter_set_hostname(tcpip_adapter_if_t tcpip_if, const char *ho p_netif = esp_netif[tcpip_if]; if (p_netif != NULL) { memset(hostinfo[tcpip_if], 0, sizeof(hostinfo[tcpip_if])); - memcpy(hostinfo[tcpip_if], hostname, strlen(hostname)); + strlcpy(hostinfo[tcpip_if], hostname, sizeof(hostinfo[tcpip_if])); p_netif->hostname = hostinfo[tcpip_if]; return ESP_OK; } else { From ec31b39989cae74d8322840b933cea432e1d59b7 Mon Sep 17 00:00:00 2001 From: Anne Jan Brouwer Date: Fri, 17 Feb 2017 01:58:44 +0100 Subject: [PATCH 072/112] Added missing platform.h to mbedtls ssl.h There was a missing definition of mbedtls_time_t See for example: https://travis-ci.org/SHA2017-badge/Firmware/jobs/202459377 Merges #348 https://github.com/espressif/esp-idf/pull/348 --- components/mbedtls/include/mbedtls/ssl.h | 1 + 1 file changed, 1 insertion(+) diff --git a/components/mbedtls/include/mbedtls/ssl.h b/components/mbedtls/include/mbedtls/ssl.h index 82c07607f..7e1a17c81 100644 --- a/components/mbedtls/include/mbedtls/ssl.h +++ b/components/mbedtls/include/mbedtls/ssl.h @@ -29,6 +29,7 @@ #include MBEDTLS_CONFIG_FILE #endif +#include "platform.h" #include "bignum.h" #include "ecp.h" From e14d65d7047c9fdce08eea1e7aba67db91197695 Mon Sep 17 00:00:00 2001 From: Neil Kolban Date: Mon, 13 Feb 2017 23:03:04 -0600 Subject: [PATCH 073/112] Update to ESP_ERROR_CHECK See request from ESP_Angus here: https://esp32.com/viewtopic.php?f=18&t=1179 Merges #339 https://github.com/espressif/esp-idf/pull/339 --- components/esp32/include/esp_err.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp32/include/esp_err.h b/components/esp32/include/esp_err.h index b6a1e8b42..059b59735 100644 --- a/components/esp32/include/esp_err.h +++ b/components/esp32/include/esp_err.h @@ -45,7 +45,7 @@ typedef int32_t esp_err_t; * and terminate the program in case the code is not ESP_OK. * Prints the failed statement to serial output. */ -#define ESP_ERROR_CHECK(x) do { esp_err_t rc = (x); if (rc != ESP_OK) { assert(0 && #x);} } while(0); +#define ESP_ERROR_CHECK(x) do { esp_err_t rc = (x); if (rc != ESP_OK) { ESP_LOGE("err", "esp_err_t = %d", rc); assert(0 && #x);} } while(0); #ifdef __cplusplus } From e08cf27b8afd78bb9c9054edc813c964fbf67a30 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 2 Mar 2017 15:40:49 +1100 Subject: [PATCH 074/112] esp_err: add NDEBUG guard, comment about flash cache Follow-up to 316b040 --- components/esp32/include/esp_err.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/components/esp32/include/esp_err.h b/components/esp32/include/esp_err.h index 059b59735..fe8c004fa 100644 --- a/components/esp32/include/esp_err.h +++ b/components/esp32/include/esp_err.h @@ -44,8 +44,15 @@ typedef int32_t esp_err_t; * Macro which can be used to check the error code, * and terminate the program in case the code is not ESP_OK. * Prints the failed statement to serial output. + * + * Note: this macro is not safe to use if flash cache + * may be disabled. */ +#ifdef NDEBUG +#define ESP_ERROR_CHECK(x) +#else #define ESP_ERROR_CHECK(x) do { esp_err_t rc = (x); if (rc != ESP_OK) { ESP_LOGE("err", "esp_err_t = %d", rc); assert(0 && #x);} } while(0); +#endif #ifdef __cplusplus } From 41e29d7384e1280dd54c55b8199f5150c4e9bf4d Mon Sep 17 00:00:00 2001 From: Daniel Bovensiepen Date: Fri, 7 Oct 2016 23:31:24 +0800 Subject: [PATCH 075/112] docs/linux-setup: Install dependencies for Ubuntu 16.04 Not sure which Ubuntu is used in the installation guide but for the latest LTS release 16.04 we need libtool-bin for compiling crosstool-NG proper Merges #46 https://github.com/espressif/esp-idf/pull/46 --- docs/linux-setup.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/linux-setup.rst b/docs/linux-setup.rst index 94d77f360..50c1609a3 100644 --- a/docs/linux-setup.rst +++ b/docs/linux-setup.rst @@ -83,6 +83,10 @@ In any case, here are the steps to compile the toolchain yourself. sudo apt-get install gawk gperf grep gettext libncurses-dev python python-dev automake bison flex texinfo help2man libtool + - Ubuntu 16.04:: + + sudo apt-get install gawk gperf grep gettext python python-dev automake bison flex texinfo help2man libtool libtool-bin + - Debian:: TODO From 2575d1dd70a1082f10d15fe021c1020dfef8be7a Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 2 Mar 2017 16:07:28 +1100 Subject: [PATCH 076/112] docs/*-setup: Use --enable-local instead of --prefix=$PWD for ct-ng --- docs/linux-setup.rst | 8 +++++--- docs/macos-setup.rst | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/linux-setup.rst b/docs/linux-setup.rst index 50c1609a3..d3b8597cd 100644 --- a/docs/linux-setup.rst +++ b/docs/linux-setup.rst @@ -77,14 +77,16 @@ If you can't think of a reason why you need to build it yourself, then probably In any case, here are the steps to compile the toolchain yourself. +(Note: You will also need the prerequisite packages mentioned in step 0, above.) + - Install dependencies: - - Ubuntu:: + - Ubuntu pre-16.04:: sudo apt-get install gawk gperf grep gettext libncurses-dev python python-dev automake bison flex texinfo help2man libtool - Ubuntu 16.04:: - + sudo apt-get install gawk gperf grep gettext python python-dev automake bison flex texinfo help2man libtool libtool-bin - Debian:: @@ -100,7 +102,7 @@ Download ``crosstool-NG`` and build it:: cd ~/esp git clone -b xtensa-1.22.x https://github.com/espressif/crosstool-NG.git cd crosstool-NG - ./bootstrap && ./configure --prefix=$PWD && make install + ./bootstrap && ./configure --enable-local && make install Build the toolchain:: diff --git a/docs/macos-setup.rst b/docs/macos-setup.rst index eeed9e4e2..e8f8257b2 100644 --- a/docs/macos-setup.rst +++ b/docs/macos-setup.rst @@ -89,7 +89,7 @@ Download ``crosstool-NG`` and build it:: cd ~/esp git clone -b xtensa-1.22.x https://github.com/espressif/crosstool-NG.git cd crosstool-NG - ./bootstrap && ./configure --prefix=$PWD && make install + ./bootstrap && ./configure --enable-local && make install Build the toolchain:: From 8ce94d5bd3765c0f7973cf4c0f2335d67e69891b Mon Sep 17 00:00:00 2001 From: lucashutchinson Date: Thu, 2 Mar 2017 16:41:03 +1300 Subject: [PATCH 077/112] ble: Fix ble_adv data truncation Fixed issue with ble_adv data being truncated after the 31st octet due to an incorrect length passed in a memcpy. Merges #389 https://github.com/espressif/esp-idf/pull/389 --- components/bt/bluedroid/btc/profile/std/gap/btc_gap_ble.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/bt/bluedroid/btc/profile/std/gap/btc_gap_ble.c b/components/bt/bluedroid/btc/profile/std/gap/btc_gap_ble.c index 8fea801b0..9e158c592 100644 --- a/components/bt/bluedroid/btc/profile/std/gap/btc_gap_ble.c +++ b/components/bt/bluedroid/btc/profile/std/gap/btc_gap_ble.c @@ -476,8 +476,7 @@ static void btc_search_callback(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data param.scan_rst.ble_addr_type = p_data->inq_res.ble_addr_type; param.scan_rst.ble_evt_type = p_data->inq_res.ble_evt_type; param.scan_rst.flag = p_data->inq_res.flag; - memcpy(param.scan_rst.ble_adv, p_data->inq_res.p_eir, - ESP_BLE_ADV_DATA_LEN_MAX); + memcpy(param.scan_rst.ble_adv, p_data->inq_res.p_eir, sizeof(param.scan_rst.ble_adv)); break; } case BTA_DM_INQ_CMPL_EVT: { From a4a790030d5d3783b74ac804b05bf954c711621d Mon Sep 17 00:00:00 2001 From: Derek Gregory Date: Sat, 28 Jan 2017 00:47:09 -0800 Subject: [PATCH 078/112] component/bt: fix bug where uuid was not reset in btc_gatts_act_create_attr_tab. Merges #307 https://github.com/espressif/esp-idf/pull/307 --- components/bt/bluedroid/btc/profile/std/gatt/btc_gatts.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/bt/bluedroid/btc/profile/std/gatt/btc_gatts.c b/components/bt/bluedroid/btc/profile/std/gatt/btc_gatts.c index 2ba3ec0f1..da8d4d5f6 100644 --- a/components/bt/bluedroid/btc/profile/std/gatt/btc_gatts.c +++ b/components/bt/bluedroid/btc/profile/std/gatt/btc_gatts.c @@ -182,13 +182,16 @@ static void btc_gatts_act_create_attr_tab(esp_gatts_attr_db_t *gatts_attr_db, future_t *future_p; esp_ble_gatts_cb_param_t param; - //set the attribute table create service flag to ture + //set the attribute table create service flag to true btc_creat_tab_env.is_tab_creat_svc = true; btc_creat_tab_env.num_handle = max_nb_attr; for(int i = 0; i < max_nb_attr; i++){ if(gatts_attr_db[i].att_desc.uuid_length== ESP_UUID_LEN_16){ uuid = (gatts_attr_db[i].att_desc.uuid_p[1] << 8) + (gatts_attr_db[i].att_desc.uuid_p[0]); } + else{ + continue; + } future_p = future_new(); if (future_p == NULL) { LOG_ERROR("%s failed:no mem\n", __func__); From 6ee5a1e49267a70e6fede6e2f9b8bc276be3f8f8 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 2 Mar 2017 17:18:44 +1100 Subject: [PATCH 079/112] sdmmc: Use slot width as default slot_config width parameter, instead of 4 Ref #361 https://github.com/espressif/esp-idf/pull/361 --- components/driver/include/driver/sdmmc_host.h | 3 ++- components/driver/sdmmc_host.c | 10 +++++++--- docs/api/storage/sdmmc.rst | 1 + 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/components/driver/include/driver/sdmmc_host.h b/components/driver/include/driver/sdmmc_host.h index f9f4f7d37..dc3e9ef6b 100644 --- a/components/driver/include/driver/sdmmc_host.h +++ b/components/driver/include/driver/sdmmc_host.h @@ -55,6 +55,7 @@ typedef struct { #define SDMMC_SLOT_NO_CD ((gpio_num_t) -1) ///< indicates that card detect line is not used #define SDMMC_SLOT_NO_WP ((gpio_num_t) -1) ///< indicates that write protect line is not used +#define SDMMC_SLOT_WIDTH_DEFAULT 0 ///< use the default width for the slot (8 for slot 0, 4 for slot 1) /** * Macro defining default configuration of SDMMC host slot @@ -62,7 +63,7 @@ typedef struct { #define SDMMC_SLOT_CONFIG_DEFAULT() {\ .gpio_cd = SDMMC_SLOT_NO_CD, \ .gpio_wp = SDMMC_SLOT_NO_WP, \ - .width = 4, \ + .width = SDMMC_SLOT_WIDTH_DEFAULT, \ } /** diff --git a/components/driver/sdmmc_host.c b/components/driver/sdmmc_host.c index 54c7997b0..706a1e3fe 100644 --- a/components/driver/sdmmc_host.c +++ b/components/driver/sdmmc_host.c @@ -299,22 +299,26 @@ esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t* slot_config) } int gpio_cd = slot_config->gpio_cd; int gpio_wp = slot_config->gpio_wp; + uint8_t slot_width = slot_config->width; // Configure pins const sdmmc_slot_info_t* pslot = &s_slot_info[slot]; - if (slot_config->width > pslot->width) { + if (slot_width == SDMMC_SLOT_WIDTH_DEFAULT) { + slot_width = pslot->width; + } + else if (slot_width > pslot->width) { return ESP_ERR_INVALID_ARG; } configure_pin(pslot->clk); configure_pin(pslot->cmd); configure_pin(pslot->d0); - if (slot_config->width >= 4) { + if (slot_width >= 4) { configure_pin(pslot->d1); configure_pin(pslot->d2); configure_pin(pslot->d3); - if (slot_config->width == 8) { + if (slot_width == 8) { configure_pin(pslot->d4); configure_pin(pslot->d5); configure_pin(pslot->d6); diff --git a/docs/api/storage/sdmmc.rst b/docs/api/storage/sdmmc.rst index fe2e5c27f..4ea2f6260 100644 --- a/docs/api/storage/sdmmc.rst +++ b/docs/api/storage/sdmmc.rst @@ -79,6 +79,7 @@ Of all the funtions listed below, only ``sdmmc_host_init``, ``sdmmc_host_init_sl .. doxygendefine:: SDMMC_HOST_SLOT_0 .. doxygendefine:: SDMMC_HOST_SLOT_1 .. doxygendefine:: SDMMC_HOST_DEFAULT +.. doxygendefine:: SDMMC_SLOT_WIDTH_DEFAULT .. doxygenfunction:: sdmmc_host_init_slot From 3442d4d463b9c94fdfbeaac39349f7ad30e16ee6 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 2 Mar 2017 15:21:03 +1100 Subject: [PATCH 080/112] spi_flash: Add spi_flash_cache_enabled() test function --- components/spi_flash/cache_utils.c | 6 +++ components/spi_flash/include/esp_spi_flash.h | 6 +++ .../spi_flash/test/test_cache_disabled.c | 53 +++++++++++++++++++ docs/api/storage/spi_flash.rst | 1 + 4 files changed, 66 insertions(+) create mode 100644 components/spi_flash/test/test_cache_disabled.c diff --git a/components/spi_flash/cache_utils.c b/components/spi_flash/cache_utils.c index 5e880ab49..6d0dd9184 100644 --- a/components/spi_flash/cache_utils.c +++ b/components/spi_flash/cache_utils.c @@ -275,3 +275,9 @@ static void IRAM_ATTR spi_flash_restore_cache(uint32_t cpuid, uint32_t saved_sta } } + +IRAM_ATTR bool spi_flash_cache_enabled() +{ + return REG_GET_BIT(DPORT_PRO_CACHE_CTRL_REG, DPORT_PRO_CACHE_ENABLE) + && REG_GET_BIT(DPORT_APP_CACHE_CTRL_REG, DPORT_APP_CACHE_ENABLE); +} diff --git a/components/spi_flash/include/esp_spi_flash.h b/components/spi_flash/include/esp_spi_flash.h index 40720af38..00797b8df 100644 --- a/components/spi_flash/include/esp_spi_flash.h +++ b/components/spi_flash/include/esp_spi_flash.h @@ -233,6 +233,12 @@ size_t spi_flash_cache2phys(const void *cached); */ const void *spi_flash_phys2cache(size_t phys_offs, spi_flash_mmap_memory_t memory); +/** @brief Check at runtime if flash cache is enabled on both CPUs + * + * @return true if both CPUs have flash cache enabled, false otherwise. + */ +bool spi_flash_cache_enabled(); + /** * @brief SPI flash critical section enter function. */ diff --git a/components/spi_flash/test/test_cache_disabled.c b/components/spi_flash/test/test_cache_disabled.c new file mode 100644 index 000000000..8caa7e83f --- /dev/null +++ b/components/spi_flash/test/test_cache_disabled.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "../cache_utils.h" + +static QueueHandle_t result_queue; + +static IRAM_ATTR void cache_test_task(void *arg) +{ + bool do_disable = (bool)arg; + bool result; + if(do_disable) { + spi_flash_disable_interrupts_caches_and_other_cpu(); + } + result = spi_flash_cache_enabled(); + if (do_disable) { + spi_flash_enable_interrupts_caches_and_other_cpu(); + } + + TEST_ASSERT( xQueueSendToBack(result_queue, &result, 0) ); + vTaskDelete(NULL); +} + +TEST_CASE("spi_flash_cache_enabled() works on both CPUs", "[spi_flash]") +{ + result_queue = xQueueCreate(1, sizeof(bool)); + + for(int cpu = 0; cpu < portNUM_PROCESSORS; cpu++) { + for(int disable = 0; disable <= 1; disable++) { + bool do_disable = disable; + bool result; + printf("Testing cpu %d disabled %d\n", cpu, do_disable); + + xTaskCreatePinnedToCore(cache_test_task, "cache_check_task", + 2048, (void *)do_disable, configMAX_PRIORITIES-1, NULL, cpu); + + TEST_ASSERT( xQueueReceive(result_queue, &result, 2) ); + TEST_ASSERT_EQUAL(!do_disable, result); + } + } + + vQueueDelete(result_queue); +} + diff --git a/docs/api/storage/spi_flash.rst b/docs/api/storage/spi_flash.rst index 4bf5e37a9..c42aedb4b 100644 --- a/docs/api/storage/spi_flash.rst +++ b/docs/api/storage/spi_flash.rst @@ -62,6 +62,7 @@ Functions .. doxygenfunction:: spi_flash_mmap_dump .. doxygenfunction:: spi_flash_cache2phys .. doxygenfunction:: spi_flash_phys2cache +.. doxygenfunction:: spi_flash_cache_enabled .. doxygenfunction:: esp_partition_find .. doxygenfunction:: esp_partition_find_first .. doxygenfunction:: esp_partition_get From d6f183fbb9c3ceec82b37a527fad00e1754ecbe5 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 2 Mar 2017 17:22:22 +1100 Subject: [PATCH 081/112] esp_err: Use separate code path for ESP_ERROR_CHECK assertion * Minimum code size overhead * Makes function safe to use when flash cache is disabled Builds on #339 https://github.com/espressif/esp-idf/pull/339 --- components/esp32/include/esp_err.h | 34 ++++++++++++++----- components/esp32/panic.c | 23 ++++++++++--- components/nvs_flash/test_nvs_host/Makefile | 1 + .../test_nvs_host/esp_error_check_stub.cpp | 9 +++++ 4 files changed, 53 insertions(+), 14 deletions(-) create mode 100644 components/nvs_flash/test_nvs_host/esp_error_check_stub.cpp diff --git a/components/esp32/include/esp_err.h b/components/esp32/include/esp_err.h index fe8c004fa..c7beafd37 100644 --- a/components/esp32/include/esp_err.h +++ b/components/esp32/include/esp_err.h @@ -11,10 +11,10 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -#ifndef __ESP_ERR_H__ -#define __ESP_ERR_H__ +#pragma once #include +#include #include #ifdef __cplusplus @@ -40,22 +40,38 @@ typedef int32_t esp_err_t; #define ESP_ERR_WIFI_BASE 0x3000 /*!< Starting number of WiFi error codes */ +void _esp_error_check_failed(esp_err_t rc, const char *file, int line, const char *function, const char *expression) __attribute__((noreturn)); + +#ifndef __ASSERT_FUNC +/* This won't happen on IDF, which defines __ASSERT_FUNC in assert.h, but it does happen when building on the host which + uses /usr/include/assert.h or equivalent. +*/ +#ifdef __ASSERT_FUNCTION +#define __ASSERT_FUNC __ASSERT_FUNCTION /* used in glibc assert.h */ +#else +#define __ASSERT_FUNC "??" +#endif +#endif + /** * Macro which can be used to check the error code, * and terminate the program in case the code is not ESP_OK. - * Prints the failed statement to serial output. + * Prints the error code, error location, and the failed statement to serial output. * - * Note: this macro is not safe to use if flash cache - * may be disabled. + * Disabled if assertions are disabled. */ #ifdef NDEBUG -#define ESP_ERROR_CHECK(x) +#define ESP_ERROR_CHECK(x) do { (x); } while (0) #else -#define ESP_ERROR_CHECK(x) do { esp_err_t rc = (x); if (rc != ESP_OK) { ESP_LOGE("err", "esp_err_t = %d", rc); assert(0 && #x);} } while(0); +#define ESP_ERROR_CHECK(x) do { \ + esp_err_t rc = (x); \ + if (rc != ESP_OK) { \ + _esp_error_check_failed(rc, __FILE__, __LINE__, \ + __ASSERT_FUNC, #x); \ + } \ + } while(0); #endif #ifdef __cplusplus } #endif - -#endif /* __ESP_ERR_H__ */ diff --git a/components/esp32/panic.c b/components/esp32/panic.c index 4f0497d6e..cd426344e 100644 --- a/components/esp32/panic.c +++ b/components/esp32/panic.c @@ -34,6 +34,7 @@ #include "esp_attr.h" #include "esp_err.h" #include "esp_core_dump.h" +#include "esp_spi_flash.h" /* Panic handlers; these get called when an unhandled exception occurs or the assembly-level @@ -107,11 +108,8 @@ void __attribute__((weak)) vApplicationStackOverflowHook( TaskHandle_t xTask, s static bool abort_called; -void abort() +static __attribute__((noreturn)) inline void invoke_abort() { -#if !CONFIG_ESP32_PANIC_SILENT_REBOOT - ets_printf("abort() was called at PC 0x%08x\n", (intptr_t)__builtin_return_address(0) - 3); -#endif abort_called = true; while(1) { __asm__ ("break 0,0"); @@ -119,6 +117,14 @@ void abort() } } +void abort() +{ +#if !CONFIG_ESP32_PANIC_SILENT_REBOOT + ets_printf("abort() was called at PC 0x%08x\n", (intptr_t)__builtin_return_address(0) - 3); +#endif + invoke_abort(); +} + static const char *edesc[] = { "IllegalInstruction", "Syscall", "InstructionFetchError", "LoadStoreError", @@ -441,4 +447,11 @@ void esp_clear_watchpoint(int no) } } - +void _esp_error_check_failed(esp_err_t rc, const char *file, int line, const char *function, const char *expression) +{ + ets_printf("ESP_ERROR_CHECK failed: esp_err_t 0x%x at 0x%08x\n", rc, (intptr_t)__builtin_return_address(0) - 3); + if (spi_flash_cache_enabled()) { // strings may be in flash cache + ets_printf("file: \"%s\" line %d\nfunc: %s\nexpression: %s\n", file, line, function, expression); + } + invoke_abort(); +} diff --git a/components/nvs_flash/test_nvs_host/Makefile b/components/nvs_flash/test_nvs_host/Makefile index 600621396..133762992 100644 --- a/components/nvs_flash/test_nvs_host/Makefile +++ b/components/nvs_flash/test_nvs_host/Makefile @@ -2,6 +2,7 @@ TEST_PROGRAM=test_nvs all: $(TEST_PROGRAM) SOURCE_FILES = \ + esp_error_check_stub.cpp \ $(addprefix ../src/, \ nvs_types.cpp \ nvs_api.cpp \ diff --git a/components/nvs_flash/test_nvs_host/esp_error_check_stub.cpp b/components/nvs_flash/test_nvs_host/esp_error_check_stub.cpp new file mode 100644 index 000000000..9cff4af31 --- /dev/null +++ b/components/nvs_flash/test_nvs_host/esp_error_check_stub.cpp @@ -0,0 +1,9 @@ +#include "catch.hpp" +#include "esp_err.h" + +void _esp_error_check_failed(esp_err_t rc, const char *file, int line, const char *function, const char *expression) +{ + printf("ESP_ERROR_CHECK failed: esp_err_t 0x%x at %p\n", rc, __builtin_return_address(0)); + printf("file: \"%s\" line %d\nfunc: %s\nexpression: %s\n", file, line, function, expression); + abort(); +} From 5f82322ffad4ab3fcb21ba27424c9e508704af3e Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Fri, 3 Mar 2017 12:19:24 +1100 Subject: [PATCH 082/112] docs/eclipse: Add considerations for PATH, PYTHONPATH Thanks to @motla who mentioned these on github: https://github.com/espressif/esp-idf/pull/157#issuecomment-271109920 --- docs/eclipse-setup.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/eclipse-setup.rst b/docs/eclipse-setup.rst index 140e81e17..aa53d171e 100644 --- a/docs/eclipse-setup.rst +++ b/docs/eclipse-setup.rst @@ -49,7 +49,9 @@ Project Properties * Click "Add..." again, and enter name ``IDF_PATH``. The value should be the full path where ESP-IDF is installed. -*All users, continue with these steps:* +* Edit the ``PATH`` environment variable. Keep the current value, and append the path to the Xtensa toolchain that will installed as part of IDF setup (``something/xtensa-esp32-elf/bin``) if this is not already listed on the PATH. + +* On macOS, add a ``PYTHONPATH`` environment variable and set it to ``/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages``. This is so that the system Python, which has pyserial installed as part of the setup steps, overrides any built-in Eclipse Python. Navigate to "C/C++ General" -> "Preprocessor Include Paths" property page: From 5ea9097dbdd471674e4b4a77230b9e17ef0eb41c Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Fri, 3 Feb 2017 16:08:17 +1100 Subject: [PATCH 083/112] esptool: Update to latest v2.0 beta version * New "espefuse.py set_flash_voltage" command to easily set a fix VDD_SDIO regulator voltage (1.8V, 3.3V or disabled). * Fixes bugs when flashing files with non-4-byte aligned lengths (doesn't effect esp-idf image files) * README improvements --- components/esptool_py/esptool | 2 +- examples/storage/sd_card/README.md | 25 ++++++++++++------------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/components/esptool_py/esptool b/components/esptool_py/esptool index e9e9179f6..c1d00094d 160000 --- a/components/esptool_py/esptool +++ b/components/esptool_py/esptool @@ -1 +1 @@ -Subproject commit e9e9179f6fc3f2ecfc568987d3224b5e53a05f06 +Subproject commit c1d00094d564451636b01308625119901e2257ac diff --git a/examples/storage/sd_card/README.md b/examples/storage/sd_card/README.md index b125716ea..47fb59925 100644 --- a/examples/storage/sd_card/README.md +++ b/examples/storage/sd_card/README.md @@ -37,25 +37,24 @@ GPIO2 pin is used as a bootstrapping pin, and should be low to enter UART downlo ### Note about GPIO12 -GPIO12 is used as a bootstrapping pin to select output voltage of an internal regulator which powers the flash chip. +GPIO12 is used as a bootstrapping pin to select output voltage of an internal regulator which powers the flash chip (VDD_SDIO). This pin has an internal pulldown so if left unconnected it will read low at reset (selecting default 3.3V operation). When adding a pullup to this pin for SD card operation, consider the following: -- For boards which don't use the internal regulator, GPIO12 can be pulled high. -- On boards which use the internal regulator and a 3.3V flash chip, GPIO12 should be pulled up high, which is compatible with SD card operation. -- For boards which use 3.3V flash chip, GPIO12 needs to be low at reset. - * In this case, internal pullup can be enabled using a `gpio_pullup_en(GPIO_NUM_12);` call. Most SD cards work fine when an internal pullup on GPIO12 line is enabled. Note that if ESP32 experiences a power-on reset while the SD card is sending data, high level on GPIO12 can be latched into the bootstrapping register, and ESP32 will enter a boot loop until external reset with correct GPIO12 level is applied. - * Another option is to program flash voltage selection efuses: set `XPD_SDIO_TIEH=1`, `XPD_SDIO_FORCE=1`, and `XPD_SDIO_REG = 1`. This will permanently select 3.3V output voltage for the internal regulator, and GPIO12 will not be used as a bootstrapping pin anymore. Then it is safe to connect a pullup resistor to GPIO12. This option is suggested for production use. +- For boards which don't use the internal regulator (VDD_SDIO) to power the flash, GPIO12 can be pulled high. +- For boards which use 1.8V flash chip, GPIO12 needs to be pulled high at reset. This is fully compatible with SD card operation. +- On boards which use the internal regulator and a 3.3V flash chip, GPIO12 must be low at reset. This is incompatible with SD card operation. + * In most cases, external pullup can be omitted and an internal pullup can be enabled using a `gpio_pullup_en(GPIO_NUM_12);` call. Most SD cards work fine when an internal pullup on GPIO12 line is enabled. Note that if ESP32 experiences a power-on reset while the SD card is sending data, high level on GPIO12 can be latched into the bootstrapping register, and ESP32 will enter a boot loop until external reset with correct GPIO12 level is applied. + * Another option is to burn the flash voltage selection efuses. This will permanently select 3.3V output voltage for the internal regulator, and GPIO12 will not be used as a bootstrapping pin. Then it is safe to connect a pullup resistor to GPIO12. This option is suggested for production use. -The following commands can be used to program flash voltage selection efuses **to 3.3V**: +The following command can be used to program flash voltage selection efuses **to 3.3V**: ```sh - # Override flash regulator configuration using efuses - components/esptool_py/esptool/espefuse.py burn_efuse XPD_SDIO_FORCE - # Select 3.3V output voltage - components/esptool_py/esptool/espefuse.py burn_efuse XPD_SDIO_TIEH - # Enable internal voltage regulator - components/esptool_py/esptool/espefuse.py burn_efuse XPD_SDIO_REG + components/esptool_py/esptool/espefuse.py set_flash_voltage 3.3V ``` +This command will burn the `XPD_SDIO_TIEH`, `XPD_SDIO_FORCE`, and `XPD_SDIO_REG` efuses. With all three burned to value 1, the internal VDD_SDIO flash voltage regulator is permanently enabled at 3.3V. See the technical reference manual for more details. + +`espefuse.py` has a `--do-not-confirm` option if running from an automated flashing script. + ## 4-line and 1-line modes By default, example code uses the following initializer for SDMMC host peripheral configuration: From 527720fb5b2dc052144169e3c7695e79dea99876 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Fri, 3 Mar 2017 11:22:25 +1100 Subject: [PATCH 084/112] esptool: Update esptool.py to integrate reset fix for older dev boards Originally marked "Reset with ESP32R0 Windows workaround", but proven to be necessary on some other platforms as well. This is now integrated into the default esptool.py reset behaviour. Closes #305 https://github.com/espressif/esp-idf/issues/305 --- components/esptool_py/Kconfig.projbuild | 8 -------- components/esptool_py/esptool | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/components/esptool_py/Kconfig.projbuild b/components/esptool_py/Kconfig.projbuild index 3ce1b7f3f..84ca5d683 100644 --- a/components/esptool_py/Kconfig.projbuild +++ b/components/esptool_py/Kconfig.projbuild @@ -140,24 +140,16 @@ choice ESPTOOLPY_BEFORE wired from the serial port to the ESP32. Most USB development boards do this internally. - The "Reset with ESP32R0 Windows workaround" option works - around an automatic reset bug in hardware, when using Windows - with some development boards. This fix only works if you're - using a silicon revision 0 ESP32. - config ESPTOOLPY_BEFORE_RESET bool "Reset to bootloader" config ESPTOOLPY_BEFORE_NORESET bool "No reset" -config ESPTOOLPY_BEFORE_ESP32R0 - bool "Reset with ESP32R0 Windows workaround" endchoice config ESPTOOLPY_BEFORE string default "default_reset" if ESPTOOLPY_BEFORE_RESET default "no_reset" if ESPTOOLPY_BEFORE_NORESET - default "esp32r0" if ESPTOOLPY_BEFORE_ESP32R0 choice ESPTOOLPY_AFTER prompt "After flashing" diff --git a/components/esptool_py/esptool b/components/esptool_py/esptool index c1d00094d..907273664 160000 --- a/components/esptool_py/esptool +++ b/components/esptool_py/esptool @@ -1 +1 @@ -Subproject commit c1d00094d564451636b01308625119901e2257ac +Subproject commit 907273664ada32fc33f3fbfeba99550512c67e4d From 3db4402f3cc4b21ba32f37401260de03a73b24ed Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 7 Feb 2017 15:05:18 +1100 Subject: [PATCH 085/112] uart driver: Remove UART ISR handler from IRAM Doesn't change example behaviour, as ISR wasn't being registered as ESP_INTR_FLAG_IRAM. --- components/driver/include/driver/uart.h | 3 ++- components/driver/uart.c | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/components/driver/include/driver/uart.h b/components/driver/include/driver/uart.h index 23635df27..748735c5d 100644 --- a/components/driver/include/driver/uart.h +++ b/components/driver/include/driver/uart.h @@ -478,7 +478,8 @@ esp_err_t uart_intr_config(uart_port_t uart_num, const uart_intr_config_t *intr_ * @param uart_queue UART event queue handle (out param). On success, a new queue handle is written here to provide * access to UART events. If set to NULL, driver will not use an event queue. * @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred) - * ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info. + * ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info. Do not set ESP_INTR_FLAG_IRAM here + * (the driver's ISR handler is not located in IRAM) * * @return * - ESP_OK Success diff --git a/components/driver/uart.c b/components/driver/uart.c index a40d58b30..e254bce03 100644 --- a/components/driver/uart.c +++ b/components/driver/uart.c @@ -470,7 +470,7 @@ esp_err_t uart_intr_config(uart_port_t uart_num, const uart_intr_config_t *intr_ } //internal isr handler for default driver code. -static void IRAM_ATTR uart_rx_intr_handler_default(void *param) +static void uart_rx_intr_handler_default(void *param) { uart_obj_t *p_uart = (uart_obj_t*) param; uint8_t uart_num = p_uart->uart_num; @@ -1002,6 +1002,9 @@ esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_b ESP_LOGE(UART_TAG, "UART driver already installed"); return ESP_FAIL; } + + assert((intr_alloc_flags & ESP_INTR_FLAG_IRAM) == 0); /* uart_rx_intr_handler_default is not in IRAM */ + uart_isr_register(uart_num, uart_rx_intr_handler_default, p_uart_obj[uart_num], intr_alloc_flags, &p_uart_obj[uart_num]->intr_handle); uart_intr_config_t uart_intr = { .intr_enable_mask = UART_RXFIFO_FULL_INT_ENA_M From f4faa3646ead8d7b0e0adf1183162fcf435910b9 Mon Sep 17 00:00:00 2001 From: He Yin Ling Date: Fri, 3 Mar 2017 14:06:07 +0800 Subject: [PATCH 086/112] CI: support running CI test on release branches --- .gitlab-ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 96bc56e3e..c65477051 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -167,6 +167,7 @@ test_report: only: - master - triggers + - /^release\/v.*$/ tags: - report variables: @@ -287,6 +288,7 @@ check_doc_links: when: on_success only: - master + - /^release\/v.*$/ - triggers allow_failure: true From 99102af79eb3d4cc34601a8497b821ac786e3f79 Mon Sep 17 00:00:00 2001 From: Liu Zhi Fu Date: Fri, 3 Mar 2017 18:06:05 +0800 Subject: [PATCH 087/112] esp32: update wifi lib to fix mpdu len error Fix mpdu len error which impact espressif smartconfig --- components/esp32/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp32/lib b/components/esp32/lib index 57b2234ed..e87433558 160000 --- a/components/esp32/lib +++ b/components/esp32/lib @@ -1 +1 @@ -Subproject commit 57b2234ed3a501ddbc36bdc032e1714d2838608d +Subproject commit e8743355806ed3671f7b0ef8bac1ea63909daaf3 From bc020da4f552fd812e38024a768ba1a133756086 Mon Sep 17 00:00:00 2001 From: Tian Hao Date: Fri, 3 Mar 2017 18:42:27 +0800 Subject: [PATCH 088/112] add extra check before bluedroid init and disable --- components/bt/bluedroid/api/esp_bt_main.c | 61 +++++++++++++---------- 1 file changed, 35 insertions(+), 26 deletions(-) diff --git a/components/bt/bluedroid/api/esp_bt_main.c b/components/bt/bluedroid/api/esp_bt_main.c index 5f7265e99..549865e74 100644 --- a/components/bt/bluedroid/api/esp_bt_main.c +++ b/components/bt/bluedroid/api/esp_bt_main.c @@ -19,13 +19,13 @@ #include "bt.h" #include "future.h" -static bool esp_already_enable = false; -static bool esp_already_init = false; +static bool bd_already_enable = false; +static bool bd_already_init = false; esp_bluedroid_status_t esp_bluedroid_get_status(void) { - if (esp_already_init) { - if (esp_already_enable) { + if (bd_already_init) { + if (bd_already_enable) { return ESP_BLUEDROID_STATUS_ENABLED; } else { return ESP_BLUEDROID_STATUS_INITIALIZED; @@ -40,15 +40,20 @@ esp_err_t esp_bluedroid_enable(void) btc_msg_t msg; future_t **future_p; - if (esp_already_enable) { - LOG_ERROR("%s already enable\n", __func__); + if (!bd_already_init) { + LOG_ERROR("Bludroid not initialised\n"); + return ESP_ERR_INVALID_STATE; + } + + if (bd_already_enable) { + LOG_ERROR("Bluedroid already enabled\n"); return ESP_ERR_INVALID_STATE; } future_p = btc_main_get_future_p(BTC_MAIN_ENABLE_FUTURE); *future_p = future_new(); if (*future_p == NULL) { - LOG_ERROR("%s failed\n", __func__); + LOG_ERROR("Bluedroid enable failed\n"); return ESP_ERR_NO_MEM; } @@ -58,11 +63,11 @@ esp_err_t esp_bluedroid_enable(void) btc_transfer_context(&msg, NULL, 0, NULL); if (future_await(*future_p) == FUTURE_FAIL) { - LOG_ERROR("%s failed\n", __func__); + LOG_ERROR("Bluedroid enable failed\n"); return ESP_FAIL; } - esp_already_enable = true; + bd_already_enable = true; return ESP_OK; } @@ -72,15 +77,15 @@ esp_err_t esp_bluedroid_disable(void) btc_msg_t msg; future_t **future_p; - if (!esp_already_enable) { - LOG_ERROR("%s already disable\n", __func__); + if (!bd_already_enable) { + LOG_ERROR("Bluedroid already disabled\n"); return ESP_ERR_INVALID_STATE; } future_p = btc_main_get_future_p(BTC_MAIN_DISABLE_FUTURE); *future_p = future_new(); if (*future_p == NULL) { - LOG_ERROR("%s failed\n", __func__); + LOG_ERROR("Bluedroid disable failed\n"); return ESP_ERR_NO_MEM; } @@ -90,11 +95,11 @@ esp_err_t esp_bluedroid_disable(void) btc_transfer_context(&msg, NULL, 0, NULL); if (future_await(*future_p) == FUTURE_FAIL) { - LOG_ERROR("%s failed\n", __func__); + LOG_ERROR("Bluedroid disable failed\n"); return ESP_FAIL; } - esp_already_enable = false; + bd_already_enable = false; return ESP_OK; } @@ -105,19 +110,19 @@ esp_err_t esp_bluedroid_init(void) future_t **future_p; if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) { - LOG_ERROR("%s conroller not init\n", __func__); + LOG_ERROR("Conroller not initialised\n"); return ESP_ERR_INVALID_STATE; } - if (esp_already_init) { - LOG_ERROR("%s already init\n", __func__); + if (bd_already_init) { + LOG_ERROR("Bluedroid already initialised\n"); return ESP_ERR_INVALID_STATE; } future_p = btc_main_get_future_p(BTC_MAIN_INIT_FUTURE); *future_p = future_new(); if (*future_p == NULL) { - LOG_ERROR("%s failed\n", __func__); + LOG_ERROR("Bluedroid initialise failed\n"); return ESP_ERR_NO_MEM; } @@ -129,11 +134,11 @@ esp_err_t esp_bluedroid_init(void) btc_transfer_context(&msg, NULL, 0, NULL); if (future_await(*future_p) == FUTURE_FAIL) { - LOG_ERROR("%s failed\n", __func__); + LOG_ERROR("Bluedroid initialise failed\n"); return ESP_FAIL; } - esp_already_init = true; + bd_already_init = true; return ESP_OK; } @@ -144,15 +149,20 @@ esp_err_t esp_bluedroid_deinit(void) btc_msg_t msg; future_t **future_p; - if (!esp_already_init) { - LOG_ERROR("%s already deinit\n", __func__); + if (!bd_already_init) { + LOG_ERROR("Bluedroid already de-initialised\n"); + return ESP_ERR_INVALID_STATE; + } + + if (bd_already_enable) { + LOG_ERROR("Bludroid already enabled, do disable first\n"); return ESP_ERR_INVALID_STATE; } future_p = btc_main_get_future_p(BTC_MAIN_DEINIT_FUTURE); *future_p = future_new(); if (*future_p == NULL) { - LOG_ERROR("%s failed\n", __func__); + LOG_ERROR("Bluedroid de-initialise failed\n"); return ESP_ERR_NO_MEM; } @@ -162,15 +172,14 @@ esp_err_t esp_bluedroid_deinit(void) btc_transfer_context(&msg, NULL, 0, NULL); if (future_await(*future_p) == FUTURE_FAIL) { - LOG_ERROR("%s failed\n", __func__); + LOG_ERROR("Bluedroid de-initialise failed\n"); return ESP_FAIL; } btc_deinit(); - esp_already_init = false; + bd_already_init = false; return ESP_OK; } - From 66552c228c4c8bffbc9e3b3ecb3a57b2a2bc8258 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Sat, 4 Mar 2017 14:56:41 +0800 Subject: [PATCH 089/112] unit-test-app: default to 4MB flash --- tools/unit-test-app/sdkconfig | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/tools/unit-test-app/sdkconfig b/tools/unit-test-app/sdkconfig index 2945dbaf6..e9ad8e637 100644 --- a/tools/unit-test-app/sdkconfig +++ b/tools/unit-test-app/sdkconfig @@ -38,10 +38,10 @@ CONFIG_ESPTOOLPY_BAUD_921600B=y CONFIG_ESPTOOLPY_BAUD_OTHER_VAL=115200 CONFIG_ESPTOOLPY_BAUD=921600 CONFIG_ESPTOOLPY_COMPRESSED=y -# CONFIG_ESPTOOLPY_FLASHMODE_QIO is not set -# CONFIG_ESPTOOLPY_FLASHMODE_QOUT is not set -CONFIG_ESPTOOLPY_FLASHMODE_DIO=y -# CONFIG_ESPTOOLPY_FLASHMODE_DOUT is not set +# CONFIG_FLASHMODE_QIO is not set +# CONFIG_FLASHMODE_QOUT is not set +CONFIG_FLASHMODE_DIO=y +# CONFIG_FLASHMODE_DOUT is not set CONFIG_ESPTOOLPY_FLASHMODE="dio" # CONFIG_ESPTOOLPY_FLASHFREQ_80M is not set CONFIG_ESPTOOLPY_FLASHFREQ_40M=y @@ -49,11 +49,11 @@ CONFIG_ESPTOOLPY_FLASHFREQ_40M=y # CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set CONFIG_ESPTOOLPY_FLASHFREQ="40m" # CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set -CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y -# CONFIG_ESPTOOLPY_FLASHSIZE_4MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_2MB is not set +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y # CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set # CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set -CONFIG_ESPTOOLPY_FLASHSIZE="2MB" +CONFIG_ESPTOOLPY_FLASHSIZE="4MB" CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y CONFIG_ESPTOOLPY_BEFORE_RESET=y # CONFIG_ESPTOOLPY_BEFORE_NORESET is not set @@ -106,6 +106,9 @@ CONFIG_TRACEMEM_RESERVE_DRAM=0x0 # CONFIG_ESP32_ENABLE_COREDUMP_TO_UART is not set CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE=y # CONFIG_ESP32_ENABLE_COREDUMP is not set +# CONFIG_TWO_MAC_ADDRESS_FROM_EFUSE is not set +CONFIG_FOUR_MAC_ADDRESS_FROM_EFUSE=y +CONFIG_NUMBER_OF_MAC_ADDRESS_GENERATED_FROM_EFUSE=4 CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32 CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2048 CONFIG_MAIN_TASK_STACK_SIZE=4096 @@ -134,13 +137,17 @@ CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1=y CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC=y CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY=0 CONFIG_WIFI_ENABLED=y -CONFIG_ESP32_WIFI_RX_BUFFER_NUM=10 +CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=10 +CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=0 +CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM=32 +CONFIG_ESP32_WIFI_AMPDU_ENABLED=y +CONFIG_ESP32_WIFI_NVS_ENABLED=y CONFIG_PHY_ENABLED=y # # PHY # -CONFIG_ESP32_PHY_AUTO_INIT=y +CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y # CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION is not set CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20 CONFIG_ESP32_PHY_MAX_TX_POWER=20 @@ -157,6 +164,7 @@ CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y # CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE is not set # CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL is not set CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y +# CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK is not set CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=3 CONFIG_FREERTOS_ASSERT_FAIL_ABORT=y # CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE is not set @@ -165,6 +173,7 @@ CONFIG_FREERTOS_BREAK_ON_SCHEDULER_START_JTAG=y # CONFIG_ENABLE_MEMORY_DEBUG is not set CONFIG_FREERTOS_ISR_STACKSIZE=1536 # CONFIG_FREERTOS_LEGACY_HOOKS is not set +CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16 # CONFIG_FREERTOS_DEBUG_INTERNALS is not set # From 06274ff5a5613a3690e61082475eb32dffe025a1 Mon Sep 17 00:00:00 2001 From: Wu Jian Gang Date: Fri, 3 Mar 2017 20:58:49 +0800 Subject: [PATCH 090/112] Merge branch 'bugfix/fix_mpdu_len_error' into 'master' esp32: update wifi lib to fix mpdu len error Fix mpdu len error which impact espressif smartconfig See merge request !552 --- components/esp32/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp32/lib b/components/esp32/lib index 57b2234ed..e87433558 160000 --- a/components/esp32/lib +++ b/components/esp32/lib @@ -1 +1 @@ -Subproject commit 57b2234ed3a501ddbc36bdc032e1714d2838608d +Subproject commit e8743355806ed3671f7b0ef8bac1ea63909daaf3 From c01dff82630d816c835fc7b4a7610c14684a25e8 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Fri, 3 Mar 2017 17:41:58 +0800 Subject: [PATCH 091/112] Merge branch 'feature/run_test_on_release_branches' into 'master' CI: support running CI test on release branches Patches will be cherry-picked to release branches after it's released. Therefore we need to run test jobs with the same strategy as master. See merge request !551 --- .gitlab-ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 96bc56e3e..c65477051 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -167,6 +167,7 @@ test_report: only: - master - triggers + - /^release\/v.*$/ tags: - report variables: @@ -287,6 +288,7 @@ check_doc_links: when: on_success only: - master + - /^release\/v.*$/ - triggers allow_failure: true From fa09c8af615c777fb4295a183d0dcb1585df3fd7 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Sat, 4 Mar 2017 15:34:03 +0800 Subject: [PATCH 092/112] spi_flash: fix partitions order Pointer to the tail of linked list was never set, so partitions were added to the head, instead of adding them to the tail. --- components/spi_flash/partition.c | 1 + 1 file changed, 1 insertion(+) diff --git a/components/spi_flash/partition.c b/components/spi_flash/partition.c index 89ad9807e..94d6ff6a6 100644 --- a/components/spi_flash/partition.c +++ b/components/spi_flash/partition.c @@ -184,6 +184,7 @@ static esp_err_t load_partitions() } else { SLIST_INSERT_AFTER(last, item, next); } + last = item; } spi_flash_munmap(handle); return ESP_OK; From 4bf96e99b347be5e179b2ae8b15beb84855cdc6b Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Sat, 4 Mar 2017 15:34:51 +0800 Subject: [PATCH 093/112] partition_table: update unit test - change order of assert arguments to (expected, actual) - set expected partition count to 3 to match the new partition table - use the new get_test_partition facility - check that partitions are listed in correct order - remove leftover debugging printfs --- .../partition_table/test/test_partition.c | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/components/partition_table/test/test_partition.c b/components/partition_table/test/test_partition.c index a26822280..6cb13bd9a 100644 --- a/components/partition_table/test/test_partition.c +++ b/components/partition_table/test/test_partition.c @@ -1,6 +1,7 @@ #include #include #include "unity.h" +#include "test_utils.h" #include "esp_partition.h" @@ -9,26 +10,30 @@ TEST_CASE("Can read partition table", "[partition]") const esp_partition_t *p = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_ANY, NULL); TEST_ASSERT_NOT_NULL(p); - TEST_ASSERT_EQUAL(p->address, 0x10000); - TEST_ASSERT_EQUAL(p->subtype, ESP_PARTITION_SUBTYPE_APP_FACTORY); + TEST_ASSERT_EQUAL(0x10000, p->address); + TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_FACTORY, p->subtype); esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, NULL); TEST_ASSERT_NOT_NULL(it); int count = 0; + const esp_partition_t* prev = NULL; for (; it != NULL; it = esp_partition_next(it)) { const esp_partition_t *p = esp_partition_get(it); TEST_ASSERT_NOT_NULL(p); + if (prev) { + TEST_ASSERT_TRUE_MESSAGE(prev->address < p->address, "incorrect partition order"); + } + prev = p; ++count; } esp_partition_iterator_release(it); - TEST_ASSERT_EQUAL(count, 2); - - printf("%d\n", __builtin_clz(count)); + TEST_ASSERT_EQUAL(3, count); } TEST_CASE("Can write, read, mmap partition", "[partition][ignore]") { - const esp_partition_t *p = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, NULL); + const esp_partition_t *p = get_test_data_partition(); + printf("Using partition %s at 0x%x, size 0x%x\n", p->label, p->address, p->size); TEST_ASSERT_NOT_NULL(p); const size_t max_size = 2 * SPI_FLASH_SEC_SIZE; uint8_t *data = (uint8_t *) malloc(max_size); @@ -46,9 +51,6 @@ TEST_CASE("Can write, read, mmap partition", "[partition][ignore]") } for (size_t i = 0; i < block_size / 4; ++i) { ((uint32_t *) (data))[i] = rand(); - if (i == 0 && offset == 0) { - printf("write: %08x\n", ((uint32_t *) (data))[i]); - } } TEST_ASSERT_EQUAL(ESP_OK, esp_partition_write(p, offset, data, block_size)); } From d7903002152b01a41166353c12dac73e16fe8def Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Sat, 4 Mar 2017 17:48:44 +0800 Subject: [PATCH 094/112] spi_flash: fix stale data being read from mmaped region The issue that cache entries are not invalidated correctly sometimes can also be reproduced for non-encrypted flash as well. This change updates the workaround to do Cache_Flush, enabling it for non-encrypted flash, and adds a unit test. --- components/spi_flash/flash_mmap.c | 4 ++-- components/spi_flash/test/test_mmap.c | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/components/spi_flash/flash_mmap.c b/components/spi_flash/flash_mmap.c index b2177e8b2..221d2ced6 100644 --- a/components/spi_flash/flash_mmap.c +++ b/components/spi_flash/flash_mmap.c @@ -187,12 +187,12 @@ esp_err_t IRAM_ATTR spi_flash_mmap(size_t src_addr, size_t size, spi_flash_mmap_ } /* This is a temporary fix for an issue where some - encrypted cache reads may see stale data. + cache reads may see stale data. Working on a long term fix that doesn't require invalidating entire cache. */ - if (esp_flash_encryption_enabled() && !did_flush && need_flush) { + if (!did_flush && need_flush) { Cache_Flush(0); Cache_Flush(1); } diff --git a/components/spi_flash/test/test_mmap.c b/components/spi_flash/test/test_mmap.c index 220b2b8de..d61ad77b1 100644 --- a/components/spi_flash/test/test_mmap.c +++ b/components/spi_flash/test/test_mmap.c @@ -138,6 +138,8 @@ TEST_CASE("Can mmap into data address space", "[spi_flash]") TEST_CASE("Can mmap into instruction address space", "[mmap]") { + setup_mmap_tests(); + printf("Mapping %x (+%x)\n", start, end - start); spi_flash_mmap_handle_t handle1; const void *ptr1; @@ -288,3 +290,23 @@ TEST_CASE("mmap consistent with phys2cache/cache2phys", "[spi_flash]") TEST_ASSERT_EQUAL_HEX(SPI_FLASH_CACHE2PHYS_FAIL, spi_flash_cache2phys(ptr)); } + +TEST_CASE("munmap followed by mmap flushes cache", "[spi_flash]") +{ + setup_mmap_tests(); + + const esp_partition_t *p = get_test_data_partition(); + + const uint32_t* data; + spi_flash_mmap_handle_t handle; + TEST_ESP_OK( esp_partition_mmap(p, 0, SPI_FLASH_MMU_PAGE_SIZE, + SPI_FLASH_MMAP_DATA, (const void **) &data, &handle) ); + uint32_t buf[16]; + memcpy(buf, data, sizeof(buf)); + + spi_flash_munmap(handle); + TEST_ESP_OK( esp_partition_mmap(p, SPI_FLASH_MMU_PAGE_SIZE, SPI_FLASH_MMU_PAGE_SIZE, + SPI_FLASH_MMAP_DATA, (const void **) &data, &handle) ); + TEST_ASSERT_NOT_EQUAL(0, memcmp(buf, data, sizeof(buf))); +} + From abe8e405976599f7717d6c24f067507c3c08b958 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Sat, 4 Mar 2017 18:17:59 +0800 Subject: [PATCH 095/112] ci: fix release branch being pushed into master Also fix variable quoting issue in link check build. --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c65477051..27663db32 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -232,7 +232,7 @@ push_master_to_github: - chmod 600 ~/.ssh/id_rsa - echo -e "Host github.com\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config - git remote add github git@github.com:espressif/esp-idf.git - - git push --follow-tags github HEAD:master + - git push --follow-tags github HEAD deploy_docs: @@ -270,7 +270,7 @@ check_doc_links: - triggers script: # must be triggered with CHECK_LINKS=Yes, otherwise exit without test - - test $CHECK_LINKS = "Yes" || exit 0 + - test "$CHECK_LINKS" = "Yes" || exit 0 # can only run on master branch (otherwise the commit is not on Github yet) - test "${CI_BUILD_REF_NAME}" = "master" || exit 0 - cd docs From 2955b20f2ebbd813b077f4fd34818cae7935c2f7 Mon Sep 17 00:00:00 2001 From: island Date: Mon, 6 Mar 2017 17:20:45 +0800 Subject: [PATCH 096/112] bt component: fix bluetooth gatt packets process bugs 1. Add process of prepare write request packets 2. Add process of execute write request packets 3. Add process of reliable write request packets 4. Fix bug of processing read blob request packets 5. Fix bug of processing write request packets 6. Optimize error check and process in stack --- components/bt/bluedroid/api/esp_gatts_api.c | 45 +++ components/bt/bluedroid/stack/gatt/gatt_db.c | 185 +++++++--- components/bt/bluedroid/stack/gatt/gatt_sr.c | 335 +++++++++++++++--- .../bt/bluedroid/stack/gatt/gatt_utils.c | 21 ++ .../bluedroid/stack/gatt/include/gatt_int.h | 37 ++ .../bt/bluedroid/stack/include/gatt_api.h | 2 + 6 files changed, 511 insertions(+), 114 deletions(-) diff --git a/components/bt/bluedroid/api/esp_gatts_api.c b/components/bt/bluedroid/api/esp_gatts_api.c index f5ebe59a2..3a31d7959 100644 --- a/components/bt/bluedroid/api/esp_gatts_api.c +++ b/components/bt/bluedroid/api/esp_gatts_api.c @@ -142,6 +142,28 @@ esp_err_t esp_ble_gatts_add_char(uint16_t service_handle, esp_bt_uuid_t *char_ return ESP_ERR_INVALID_STATE; } + /* parameter validation check */ + if ((control != NULL) && (control->auto_rsp == GATT_STACK_RSP)){ + if (char_val == NULL){ + LOG_ERROR("Error in %s, line=%d, for stack respond attribute, char_val should not be NULL here\n",\ + __func__, __LINE__); + return ESP_ERR_INVALID_ARG; + } + else if (char_val->attr_max_len == 0){ + LOG_ERROR("Error in %s, line=%d, for stack respond attribute, attribute max length should not be 0\n",\ + __func__, __LINE__); + return ESP_ERR_INVALID_ARG; + } + } + + if (char_val != NULL){ + if (char_val->attr_len > char_val->attr_max_len){ + LOG_ERROR("Error in %s, line=%d,attribute actual length should not be larger than max length\n",\ + __func__, __LINE__); + return ESP_ERR_INVALID_ARG; + } + } + memset(&arg, 0, sizeof(btc_ble_gatts_args_t)); msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GATTS; @@ -175,6 +197,29 @@ esp_err_t esp_ble_gatts_add_char_descr (uint16_t service_handle, if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { return ESP_ERR_INVALID_STATE; } + + /* parameter validation check */ + if ((control != NULL) && (control->auto_rsp == GATT_STACK_RSP)){ + if (char_descr_val == NULL){ + LOG_ERROR("Error in %s, line=%d, for stack respond attribute, char_descr_val should not be NULL here\n",\ + __func__, __LINE__); + return ESP_ERR_INVALID_ARG; + } + else if (char_descr_val->attr_max_len == 0){ + LOG_ERROR("Error in %s, line=%d, for stack respond attribute, attribute max length should not be 0\n",\ + __func__, __LINE__); + return ESP_ERR_INVALID_ARG; + } + } + + if (char_descr_val != NULL){ + if (char_descr_val->attr_len > char_descr_val->attr_max_len){ + LOG_ERROR("Error in %s, line=%d,attribute actual length should not be larger than max length\n",\ + __func__, __LINE__); + return ESP_ERR_INVALID_ARG; + } + } + memset(&arg, 0, sizeof(btc_ble_gatts_args_t)); msg.sig = BTC_SIG_API_CALL; diff --git a/components/bt/bluedroid/stack/gatt/gatt_db.c b/components/bt/bluedroid/stack/gatt/gatt_db.c index bb9bfc5f7..60749a0f4 100644 --- a/components/bt/bluedroid/stack/gatt/gatt_db.c +++ b/components/bt/bluedroid/stack/gatt/gatt_db.c @@ -268,14 +268,22 @@ static tGATT_STATUS read_attr_value (void *p_attr, status = GATT_SUCCESS; } } else { /* characteristic description or characteristic value */ - if (p_attr16->control.auto_rsp == GATT_RSP_BY_STACK) { - if (p_attr16->p_value != NULL && p_attr16->p_value->attr_val.attr_val != NULL) { - uint8_t *value = p_attr16->p_value->attr_val.attr_val + offset; - len = (mtu >= p_attr16->p_value->attr_val.attr_len) ? (p_attr16->p_value->attr_val.attr_len) : mtu; - ARRAY_TO_STREAM(p, value, len); + if (p_attr16->p_value == NULL || p_attr16->p_value->attr_val.attr_val == NULL) { + status = GATT_ESP_ERROR; + } + /*if offset equal to max_len, should respond with zero byte value + //if offset is greater than max_len, should respond with an error*/ + else if (offset > p_attr16->p_value->attr_val.attr_len){ + status = GATT_INVALID_OFFSET; + } + else { + UINT8 *value = (UINT8 *)(p_attr16->p_value->attr_val.attr_val) + offset; + UINT16 len_left = p_attr16->p_value->attr_val.attr_len - offset; + len = (mtu >= len_left) ? (len_left) : mtu; + ARRAY_TO_STREAM(p, value, len); + status = GATT_STACK_RSP; } - status = GATT_STACK_RSP; } else { status = GATT_PENDING; @@ -463,6 +471,28 @@ UINT16 gatts_add_characteristic (tGATT_SVC_DB *p_db, tGATT_PERM perm, tBT_UUID uuid = {LEN_UUID_16, {GATT_UUID_CHAR_DECLARE}}; GATT_TRACE_DEBUG("gatts_add_characteristic perm=0x%0x property=0x%0x\n", perm, property); + /* parameter validation check */ + if ((control != NULL) && (control->auto_rsp == GATT_STACK_RSP)){ + if (attr_val == NULL){ + GATT_TRACE_ERROR("Error in %s, line=%d, for stack respond attribute, attr_val should not be NULL here\n",\ + __func__, __LINE__); + return 0; + } + else if (attr_val->attr_max_len == 0){ + GATT_TRACE_ERROR("Error in %s, line=%d, for stack respond attribute, attribute max length should not be 0\n",\ + __func__, __LINE__); + return 0; + } + } + + if (attr_val != NULL){ + if (attr_val->attr_len > attr_val->attr_max_len){ + GATT_TRACE_ERROR("Error in %s, line=%d,attribute actual length should not be larger than max length\n",\ + __func__, __LINE__); + return 0; + } + } + if ((p_char_decl = (tGATT_ATTR16 *)allocate_attr_in_db(p_db, &uuid, GATT_PERM_READ)) != NULL) { if (!copy_extra_byte_in_db(p_db, (void **)&p_char_decl->p_value, sizeof(tGATT_CHAR_DECL))) { @@ -483,10 +513,9 @@ UINT16 gatts_add_characteristic (tGATT_SVC_DB *p_db, tGATT_PERM perm, p_char_val->control.auto_rsp = control->auto_rsp; } else { p_char_val->control.auto_rsp = GATT_RSP_DEFAULT; - } - if (attr_val != NULL) { + if (attr_val != NULL) { if (!copy_extra_byte_in_db(p_db, (void **)&p_char_val->p_value, sizeof(tGATT_ATTR_VAL))) { deallocate_attr_in_db(p_db, p_char_val); return 0; @@ -496,12 +525,23 @@ UINT16 gatts_add_characteristic (tGATT_SVC_DB *p_db, tGATT_PERM perm, p_char_val->p_value->attr_val.attr_len = attr_val->attr_len; p_char_val->p_value->attr_val.attr_max_len = attr_val->attr_max_len; p_char_val->p_value->attr_val.attr_val = GKI_getbuf(attr_val->attr_max_len); - if (p_char_val->p_value->attr_val.attr_val != NULL) { - GATT_TRACE_DEBUG("attribute value not NULL"); - memcpy(p_char_val->p_value->attr_val.attr_val, attr_val->attr_val, attr_val->attr_len); + if (p_char_val->p_value->attr_val.attr_val == NULL) { + deallocate_attr_in_db(p_db, p_char_decl); + deallocate_attr_in_db(p_db, p_char_val); + GATT_TRACE_ERROR("Warning in %s, line=%d, insufficient resource to allocate for attribute value\n", __func__, __LINE__); + return 0; + } + + //initiate characteristic attribute value part + memset(p_char_val->p_value->attr_val.attr_val, 0, attr_val->attr_max_len); + if (attr_val->attr_val != NULL) { + if (attr_val->attr_max_len < attr_val->attr_len){ + GATT_TRACE_ERROR("Error in %s, Line=%d, attribute actual length(%d) should not larger than max size(%d)\n", + __func__, __LINE__, attr_val->attr_len, attr_val->attr_max_len); + } + UINT16 actual_len = (attr_val->attr_max_len < attr_val->attr_len) ? (attr_val->attr_max_len) : (attr_val->attr_len); + memcpy(p_char_val->p_value->attr_val.attr_val, attr_val->attr_val, actual_len); } - } else { - p_char_val->p_value = NULL; } return p_char_val->handle; @@ -582,14 +622,37 @@ UINT16 gatts_add_char_descr (tGATT_SVC_DB *p_db, tGATT_PERM perm, GATT_TRACE_DEBUG("gatts_add_char_descr uuid=0x%04x\n", p_descr_uuid->uu.uuid16); + /* parameter validation check */ + if ((control != NULL) && (control->auto_rsp == GATT_STACK_RSP)){ + if (attr_val == NULL){ + GATT_TRACE_ERROR("Error in %s, line=%d, for stack respond attribute, attr_val should not be NULL here\n",\ + __func__, __LINE__); + return 0; + } + else if (attr_val->attr_max_len == 0){ + GATT_TRACE_ERROR("Error in %s, line=%d, for stack respond attribute, attribute max length should not be 0\n",\ + __func__, __LINE__); + return 0; + } + } + + if (attr_val != NULL){ + if (attr_val->attr_len > attr_val->attr_max_len){ + GATT_TRACE_ERROR("Error in %s, line=%d,attribute actual length should not be larger than max length\n",\ + __func__, __LINE__); + return 0; + } + } + + /* Add characteristic descriptors */ if ((p_char_dscptr = (tGATT_ATTR16 *)allocate_attr_in_db(p_db, p_descr_uuid, perm)) == NULL) { + deallocate_attr_in_db(p_db, p_char_dscptr); GATT_TRACE_DEBUG("gatts_add_char_descr Fail for adding char descriptors."); return 0; - } else { - if (control != NULL) { - p_char_dscptr->control.auto_rsp = control->auto_rsp; - } + } + else { + p_char_dscptr->control.auto_rsp = (control == NULL) ? GATT_RSP_DEFAULT : (control->auto_rsp); if (attr_val != NULL) { if (!copy_extra_byte_in_db(p_db, (void **)&p_char_dscptr->p_value, sizeof(tGATT_ATTR_VAL))) { deallocate_attr_in_db(p_db, p_char_dscptr); @@ -599,12 +662,16 @@ UINT16 gatts_add_char_descr (tGATT_SVC_DB *p_db, tGATT_PERM perm, p_char_dscptr->p_value->attr_val.attr_max_len = attr_val->attr_max_len; if (attr_val->attr_max_len != 0) { p_char_dscptr->p_value->attr_val.attr_val = GKI_getbuf(attr_val->attr_max_len); - if (p_char_dscptr->p_value->attr_val.attr_val != NULL) { - memset(p_char_dscptr->p_value->attr_val.attr_val, 0, attr_val->attr_max_len); - if(attr_val->attr_val != NULL) { - memcpy(p_char_dscptr->p_value->attr_val.attr_val, - attr_val->attr_val, attr_val->attr_len); - } + if (p_char_dscptr->p_value->attr_val.attr_val == NULL) { + deallocate_attr_in_db(p_db, p_char_dscptr); + GATT_TRACE_ERROR("Warning in %s, line=%d, insufficient resource to allocate for descriptor value\n", __func__, __LINE__); + return 0; + } + + //initiate characteristic attribute value part + memset(p_char_dscptr->p_value->attr_val.attr_val, 0, attr_val->attr_max_len); + if(attr_val->attr_val != NULL) { + memcpy(p_char_dscptr->p_value->attr_val.attr_val, attr_val->attr_val, attr_val->attr_len); } } } @@ -628,7 +695,7 @@ UINT16 gatts_add_char_descr (tGATT_SVC_DB *p_db, tGATT_PERM perm, ** *******************************************************************************/ tGATT_STATUS gatts_set_attribute_value(tGATT_SVC_DB *p_db, UINT16 attr_handle, - UINT16 length, UINT8 *value) + UINT16 length, UINT8 *value) { tGATT_ATTR16 *p_cur; @@ -640,51 +707,48 @@ tGATT_STATUS gatts_set_attribute_value(tGATT_SVC_DB *p_db, UINT16 attr_handle, GATT_TRACE_DEBUG("gatts_set_attribute_value Fail:p_db->p_attr_list is NULL.\n"); return GATT_INVALID_PDU; } + if ((length > 0) && (value == NULL)){ + GATT_TRACE_ERROR("Error in %s, line=%d, value should not be NULL here\n",__func__, __LINE__); + return GATT_INVALID_PDU; + } p_cur = (tGATT_ATTR16 *) p_db->p_attr_list; while (p_cur != NULL) { if (p_cur->handle == attr_handle) { - + /* for characteristic should not be set, return GATT_NOT_FOUND */ if (p_cur->uuid_type == GATT_ATTR_UUID_TYPE_16) { switch (p_cur->uuid) { - case GATT_UUID_PRI_SERVICE: - case GATT_UUID_SEC_SERVICE: - case GATT_UUID_CHAR_DECLARE: - case GATT_UUID_INCLUDE_SERVICE: - return GATT_NOT_FOUND; - default: - if (p_cur->p_value != NULL && p_cur->p_value->attr_val.attr_max_len < length) { - GATT_TRACE_ERROR("gatts_set_attribute_vaule failt:Invalid value length"); - return GATT_INVALID_ATTR_LEN; - } else if (p_cur->p_value != NULL && p_cur->p_value->attr_val.attr_max_len > 0) { - memcpy(p_cur->p_value->attr_val.attr_val, value, length); - p_cur->p_value->attr_val.attr_len = length; - } else { - return GATT_INVALID_ATTR_LEN; - } - break; - } - } else { - if (p_cur->p_value != NULL && p_cur->p_value->attr_val.attr_max_len < length) { - GATT_TRACE_ERROR("gatts_set_attribute_vaule failt:Invalid value length"); - } else if (p_cur->p_value != NULL && p_cur->p_value->attr_val.attr_max_len > 0) { - memcpy(p_cur->p_value->attr_val.attr_val, value, length); - p_cur->p_value->attr_val.attr_len = length; - } else { - return GATT_INVALID_ATTR_LEN; + case GATT_UUID_PRI_SERVICE: + case GATT_UUID_SEC_SERVICE: + case GATT_UUID_CHAR_DECLARE: + return GATT_NOT_FOUND; + break; } } + + /* in other cases, value can be set*/ + if ((p_cur->p_value == NULL) || (p_cur->p_value->attr_val.attr_val == NULL) \ + || (p_cur->p_value->attr_val.attr_max_len == 0)){ + GATT_TRACE_ERROR("Error in %s, line=%d, attribute value should not be NULL here\n", __func__, __LINE__); + return GATT_NOT_FOUND; + } + else if (p_cur->p_value->attr_val.attr_max_len < length) { + GATT_TRACE_ERROR("gatts_set_attribute_value failed:Invalid value length"); + return GATT_INVALID_ATTR_LEN; + } + else{ + memcpy(p_cur->p_value->attr_val.attr_val, value, length); + p_cur->p_value->attr_val.attr_len = length; + } break; } - p_cur = p_cur->p_next; } return GATT_SUCCESS; } - /******************************************************************************* ** ** Function gatts_get_attribute_value @@ -875,20 +939,27 @@ tGATT_STATUS gatts_write_attr_value_by_handle(tGATT_SVC_DB *p_db, return GATT_APP_RSP; } - if (p_attr->p_value != NULL && (p_attr->p_value->attr_val.attr_max_len >= - offset + len) && p_attr->p_value->attr_val.attr_val != NULL) { + if ((p_attr->p_value != NULL) && + (p_attr->p_value->attr_val.attr_max_len >= offset + len) && + p_attr->p_value->attr_val.attr_val != NULL) { memcpy(p_attr->p_value->attr_val.attr_val + offset, p_value, len); p_attr->p_value->attr_val.attr_len = len + offset; return GATT_SUCCESS; - } else { - return GATT_NOT_LONG; + } + else if (p_attr->p_value->attr_val.attr_max_len < offset + len){ + GATT_TRACE_DEBUG("Remote device try to write with a length larger then attribute's max length\n"); + return GATT_INVALID_ATTR_LEN; + } + else if ((p_attr->p_value == NULL) || (p_attr->p_value->attr_val.attr_val == NULL)){ + GATT_TRACE_ERROR("Error in %s, line=%d, %s should not be NULL here\n", __func__, __LINE__, \ + (p_attr->p_value == NULL) ? "p_value" : "attr_val.attr_val"); + return GATT_ESP_ERROR; } } p_attr = (tGATT_ATTR16 *)p_attr->p_next; } - } return status; diff --git a/components/bt/bluedroid/stack/gatt/gatt_sr.c b/components/bt/bluedroid/stack/gatt/gatt_sr.c index 2d34a0504..317eaaca7 100644 --- a/components/bt/bluedroid/stack/gatt/gatt_sr.c +++ b/components/bt/bluedroid/stack/gatt/gatt_sr.c @@ -33,6 +33,42 @@ #define GATT_MTU_REQ_MIN_LEN 2 + +/******************************************************************************* +** +** Function gatt_send_packet +** +** Description This function is called to send gatt packets directly + +** +** Returns status +** +*******************************************************************************/ +tGATT_STATUS gatt_send_packet (tGATT_TCB *p_tcb, UINT8 *p_data, UINT16 len) +{ + BT_HDR *p_msg = NULL; + UINT8 *p_m = NULL; + UINT16 buf_len; + tGATT_STATUS status; + + if (len > p_tcb->payload_size){ + return GATT_ILLEGAL_PARAMETER; + } + + buf_len = (UINT16)(sizeof(BT_HDR) + p_tcb->payload_size + L2CAP_MIN_OFFSET); + if ((p_msg = (BT_HDR *)GKI_getbuf(buf_len)) == NULL) { + return GATT_NO_RESOURCES; + } + + memset(p_msg, 0, buf_len); + p_msg->len = len; + p_m = (UINT8 *)(p_msg + 1) + L2CAP_MIN_OFFSET; + memcpy(p_m, p_data, len); + + status = attp_send_sr_msg(p_tcb, p_msg); + return status; +} + /******************************************************************************* ** ** Function gatt_sr_enqueue_cmd @@ -300,7 +336,11 @@ void gatt_process_exec_write_req (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, U UINT32 trans_id = 0; tGATT_IF gatt_if; UINT16 conn_id; - + UINT16 queue_num = 0; + BOOLEAN is_prepare_write_valid = FALSE; + BOOLEAN is_need_dequeue_sr_cmd = FALSE; + tGATT_PREPARE_WRITE_RECORD *prepare_record = NULL; + tGATT_PREPARE_WRITE_QUEUE_DATA * queue_data = NULL; UNUSED(len); #if GATT_CONFORMANCE_TESTING == TRUE @@ -319,11 +359,63 @@ void gatt_process_exec_write_req (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, U /* mask the flag */ flag &= GATT_PREP_WRITE_EXEC; + prepare_record = &(p_tcb->prepare_write_record); + queue_num = prepare_record->queue._count; + - /* no prep write is queued */ + //if received prepare_write packets include stack_rsp and app_rsp, + //stack respond to execute_write only when stack_rsp handle has invalid_offset + //or invalid_length error; + //app need to respond to execute_write if it has received app_rsp handle packets + if (((prepare_record->error_code_app == GATT_SUCCESS) && + (prepare_record->total_num == queue_num)) + || (flag == GATT_PREP_WRITE_CANCEL)){ + tGATT_EXEC_WRITE_RSP gatt_exec_write_rsp; + gatt_exec_write_rsp.op_code = GATT_RSP_EXEC_WRITE; + gatt_send_packet(p_tcb, (UINT8 *)(&gatt_exec_write_rsp), sizeof(gatt_exec_write_rsp)); + gatt_dequeue_sr_cmd(p_tcb); + if (flag != GATT_PREP_WRITE_CANCEL){ + is_prepare_write_valid = TRUE; + } + GATT_TRACE_DEBUG("Send execute_write_rsp\n"); + } + else if ((prepare_record->error_code_app == GATT_SUCCESS) && + (prepare_record->total_num > queue_num)){ + //No error for stack_rsp's handles and there exist some app_rsp's handles, + //so exec_write_rsp depends to app's response; but stack_rsp's data is valid + //TODO: there exist problem if stack_rsp's data is valid but app_rsp's data is not valid. + is_prepare_write_valid = TRUE; + } + else if(prepare_record->total_num < queue_num) { + GATT_TRACE_ERROR("Error in %s, line=%d, prepare write total number(=%d) \ + should not smaller than prepare queue number(=%d)\n", \ + __func__, __LINE__,prepare_record->total_num, queue_num); + } + else if (prepare_record->error_code_app != GATT_SUCCESS){ + GATT_TRACE_DEBUG("Send error code for execute_write, code=0x%x\n", prepare_record->error_code_app); + is_need_dequeue_sr_cmd = (prepare_record->total_num == queue_num) ? TRUE : FALSE; + gatt_send_error_rsp(p_tcb, prepare_record->error_code_app, GATT_REQ_EXEC_WRITE, 0, is_need_dequeue_sr_cmd); + } + + //dequeue prepare write data + while(GKI_getfirst(&(prepare_record->queue))) { + queue_data = GKI_dequeue(&(prepare_record->queue)); + if (is_prepare_write_valid){ + if((queue_data->p_attr->p_value != NULL) && (queue_data->p_attr->p_value->attr_val.attr_val != NULL)){ + memcpy(queue_data->p_attr->p_value->attr_val.attr_val+queue_data->offset, queue_data->value, queue_data->len); + } + } + GKI_freebuf(queue_data); + } + + /* according to ble spec, even if there is no prep write queued, + * need to respond execute_write_response + * Note: exec_write_rsp callback should be called after all data has been written*/ if (!gatt_sr_is_prep_cnt_zero(p_tcb)) { - trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, 0); - gatt_sr_copy_prep_cnt_to_cback_cnt(p_tcb); + if (prepare_record->total_num > queue_num){ + trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, 0); + gatt_sr_copy_prep_cnt_to_cback_cnt(p_tcb); + } for (i = 0; i < GATT_MAX_APPS; i++) { if (p_tcb->prep_cnt[i]) { @@ -336,10 +428,10 @@ void gatt_process_exec_write_req (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, U p_tcb->prep_cnt[i] = 0; } } - } else { /* nothing needs to be executed , send response now */ - GATT_TRACE_ERROR("gatt_process_exec_write_req: no prepare write pending"); - gatt_send_error_rsp(p_tcb, GATT_ERROR, GATT_REQ_EXEC_WRITE, 0, FALSE); } + + prepare_record->total_num = 0; + prepare_record->error_code_app = GATT_SUCCESS; } /******************************************************************************* @@ -987,54 +1079,29 @@ void gatts_process_read_by_type_req(tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, void gatts_process_write_req (tGATT_TCB *p_tcb, UINT8 i_rcb, UINT16 handle, UINT8 op_code, UINT16 len, UINT8 *p_data) { - UINT16 buf_len = (UINT16)(sizeof(BT_HDR) + p_tcb->payload_size + L2CAP_MIN_OFFSET); tGATTS_DATA sr_data; UINT32 trans_id; tGATT_STATUS status; - UINT8 sec_flag, key_size, *p = p_data, *p_m; + UINT8 sec_flag, key_size, *p = p_data; tGATT_SR_REG *p_sreg; UINT16 conn_id, offset = 0; - BT_HDR *p_msg = NULL; + memset(&sr_data, 0, sizeof(tGATTS_DATA)); + sr_data.write_req.need_rsp = FALSE; - if ((p_msg = (BT_HDR *)GKI_getbuf(buf_len)) == NULL) { - GATT_TRACE_ERROR("gatts_process_write_req failed. no resources.\n"); - } - - memset(p_msg, 0, buf_len); - p_m = (UINT8 *)(p_msg + 1) + L2CAP_MIN_OFFSET; - *p_m ++ = op_code + 1; - p_msg->len = 1; - buf_len = p_tcb->payload_size - 1; - switch (op_code) { - case GATT_REQ_PREPARE_WRITE: - sr_data.write_req.is_prep = TRUE; - STREAM_TO_UINT16(sr_data.write_req.offset, p); - UINT16_TO_STREAM(p_m, sr_data.write_req.is_prep); - offset = sr_data.write_req.offset; - len -= 2; - /* fall through */ case GATT_SIGN_CMD_WRITE: if (op_code == GATT_SIGN_CMD_WRITE) { - GATT_TRACE_DEBUG("Write CMD with data sigining" ); + GATT_TRACE_DEBUG("Write CMD with data signing" ); len -= GATT_AUTH_SIGN_LEN; } /* fall through */ case GATT_CMD_WRITE: case GATT_REQ_WRITE: - if (op_code == GATT_REQ_WRITE || op_code == GATT_REQ_PREPARE_WRITE) { - sr_data.write_req.need_rsp = TRUE; - if(op_code == GATT_REQ_PREPARE_WRITE){ - memcpy(p_m, p, len); - p_msg->len += len; - } - } sr_data.write_req.handle = handle; sr_data.write_req.len = len; if (len != 0 && p != NULL) { memcpy (sr_data.write_req.value, p, len); - } break; } @@ -1059,42 +1126,194 @@ void gatts_process_write_req (tGATT_TCB *p_tcb, UINT8 i_rcb, UINT16 handle, conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_sreg->gatt_if); status = gatts_write_attr_value_by_handle(gatt_cb.sr_reg[i_rcb].p_db, handle, offset, p, len); - if((sr_data.write_req.need_rsp == TRUE) && (status == GATT_APP_RSP)){ + if((op_code == GATT_REQ_WRITE) && (status == GATT_APP_RSP)){ sr_data.write_req.need_rsp = TRUE; status = GATT_PENDING; } - else{ - sr_data.write_req.need_rsp = FALSE; - } - gatt_sr_send_req_callback(conn_id, trans_id, GATTS_REQ_TYPE_WRITE, &sr_data); - - if (status == GATT_SUCCESS) { - attp_send_sr_msg(p_tcb, p_msg); - gatt_dequeue_sr_cmd(p_tcb); - } else { - GKI_freebuf(p_msg); - } - - } else { - GATT_TRACE_ERROR("max pending command, send error\n"); + } + else { + GATT_TRACE_ERROR("Error in %s, line=%d, max pending command, send error\n", __func__, __LINE__); status = GATT_BUSY; /* max pending command, application error */ } } + //test isl + GATT_TRACE_ERROR("!!!write opcode=0x%x, need_rsp=0x%x, status=0x%x\n",op_code, sr_data.write_req.need_rsp, status); - /* in theroy BUSY is not possible(should already been checked), protected check */ - if (status != GATT_PENDING && status != GATT_BUSY && status != GATT_SUCCESS && - (op_code == GATT_REQ_PREPARE_WRITE || op_code == GATT_REQ_WRITE)) { - gatt_send_error_rsp (p_tcb, status, op_code, handle, FALSE); - gatt_dequeue_sr_cmd(p_tcb); + /* response should be sent only for write_request */ + if ((op_code == GATT_REQ_WRITE) && (sr_data.write_req.need_rsp == FALSE)){ + if (status == GATT_SUCCESS){ + tGATT_WRITE_REQ_RSP gatt_write_req_rsp; + gatt_write_req_rsp.op_code = GATT_RSP_WRITE; + gatt_send_packet(p_tcb, (UINT8 *)(&gatt_write_req_rsp), sizeof(gatt_write_req_rsp)); + gatt_dequeue_sr_cmd(p_tcb); + } + else if (status != GATT_PENDING){ + /* note: in case of GATT_BUSY, will respond this application error to remote device */ + gatt_send_error_rsp (p_tcb, status, op_code, handle, TRUE); + } } + return; } + +/******************************************************************************* + ** + ** Function gatts_attr_process_preapre_write + ** + ** Description This function is called to process the prepare write request + ** from client. + ** + ** Returns void + ** + *******************************************************************************/ +void gatt_attr_process_prepare_write (tGATT_TCB *p_tcb, UINT8 i_rcb, UINT16 handle, + UINT8 op_code, UINT16 len, UINT8 *p_data) +{ + tGATT_STATUS status; + tGATT_PREPARE_WRITE_QUEUE_DATA * queue_data = NULL; + tGATT_ATTR16 *p_attr; + tGATT_ATTR16 *p_attr_temp; + tGATTS_DATA sr_data; + UINT32 trans_id = 0; + UINT8 sec_flag, key_size, *p = p_data; + tGATT_SR_REG *p_sreg; + UINT16 conn_id, offset = 0; + tGATT_SVC_DB *p_db; + BOOLEAN is_need_prepare_write_rsp = FALSE; + BOOLEAN is_need_queue_data = FALSE; + tGATT_PREPARE_WRITE_RECORD *prepare_record = NULL; + memset(&sr_data, 0, sizeof(tGATTS_DATA)); + + //get offset from p_data + STREAM_TO_UINT16(offset, p); + len -= 2; + p_sreg = &gatt_cb.sr_reg[i_rcb]; + conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_sreg->gatt_if); + //prepare_record = &(prepare_write_record); + prepare_record = &(p_tcb->prepare_write_record); + + gatt_sr_get_sec_info(p_tcb->peer_bda, + p_tcb->transport, + &sec_flag, + &key_size); + + status = gatts_write_attr_perm_check (gatt_cb.sr_reg[i_rcb].p_db, + op_code, + handle, + sr_data.write_req.offset, + p, + len, + sec_flag, + key_size); + + if (status == GATT_SUCCESS){ + if ((trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, handle)) != 0) { + p_db = gatt_cb.sr_reg[i_rcb].p_db; + if (p_db && p_db->p_attr_list) { + p_attr = (tGATT_ATTR16 *)p_db->p_attr_list; + while (p_attr && handle >= p_attr->handle) { + if (p_attr->handle == handle ) { + p_attr_temp = p_attr; + if (p_attr->control.auto_rsp == GATT_RSP_BY_APP) { + status = GATT_APP_RSP; + } + else if (p_attr->p_value != NULL && + offset > p_attr->p_value->attr_val.attr_max_len) { + status = GATT_INVALID_OFFSET; + is_need_prepare_write_rsp = TRUE; + is_need_queue_data = TRUE; + } + else if (p_attr->p_value != NULL && + ((offset + len) > p_attr->p_value->attr_val.attr_max_len)){ + status = GATT_INVALID_ATTR_LEN; + is_need_prepare_write_rsp = TRUE; + is_need_queue_data = TRUE; + } + else if (p_attr->p_value == NULL) { + LOG_ERROR("Error in %s, attribute of handle 0x%x not allocate value buffer\n", + __func__, handle); + status = GATT_ESP_ERROR; + } + else { + //valid prepare write request, need to send response and queue the data + //status: GATT_SUCCESS + is_need_prepare_write_rsp = TRUE; + is_need_queue_data = TRUE; + } + } + p_attr = (tGATT_ATTR16 *)p_attr->p_next; + } + } + } + else{ + status = GATT_ESP_ERROR; + GATT_TRACE_ERROR("Error in %s, Line %d: GATT BUSY\n", __func__, __LINE__); + } + } + + if (is_need_queue_data){ + queue_data = (tGATT_PREPARE_WRITE_QUEUE_DATA *)GKI_getbuf(len + sizeof(tGATT_PREPARE_WRITE_QUEUE_DATA)); + if (queue_data == NULL){ + status = GATT_PREPARE_Q_FULL; + } + else { + queue_data->p_attr = p_attr_temp; + queue_data->len = len; + queue_data->handle = handle; + queue_data->offset = offset; + memcpy(queue_data->value, p, len); + GKI_enqueue(&(prepare_record->queue), queue_data); + } + } + + if (is_need_prepare_write_rsp){ + //send prepare write response + if (queue_data != NULL){ + queue_data->op_code = op_code + 1; + //5: op_code 1 + handle 2 + offset 2 + tGATT_STATUS rsp_send_status = gatt_send_packet(p_tcb, &(queue_data->op_code), queue_data->len + 5); + gatt_sr_update_prep_cnt(p_tcb, p_sreg->gatt_if, TRUE, FALSE); + gatt_dequeue_sr_cmd(p_tcb); + + if (rsp_send_status != GATT_SUCCESS){ + LOG_ERROR("Error in %s, line=%d, fail to send prepare_write_rsp, status=0x%x\n", + __func__, __LINE__, rsp_send_status); + } + } + else{ + LOG_ERROR("Error in %s, line=%d, queue_data should not be NULL here, fail to send prepare_write_rsp\n", + __func__, __LINE__); + } + } + + if ((status == GATT_APP_RSP) || (is_need_prepare_write_rsp)){ + prepare_record->total_num++; + memset(&sr_data, 0, sizeof(sr_data)); + sr_data.write_req.is_prep = TRUE; + sr_data.write_req.handle = handle; + sr_data.write_req.offset = offset; + sr_data.write_req.len = len; + sr_data.write_req.need_rsp = (status == GATT_APP_RSP) ? TRUE : FALSE; + memcpy(sr_data.write_req.value, p, len); + gatt_sr_send_req_callback(conn_id, trans_id, GATTS_REQ_TYPE_WRITE, &sr_data); + } + else{ + gatt_send_error_rsp(p_tcb, status, GATT_REQ_PREPARE_WRITE, handle, TRUE); + } + + if ((prepare_record->error_code_app == GATT_SUCCESS) + && ((status == GATT_INVALID_OFFSET) || (status == GATT_INVALID_ATTR_LEN))){ + prepare_record->error_code_app = status; + } + +} + /******************************************************************************* ** ** Function gatts_process_read_req @@ -1226,9 +1445,11 @@ void gatts_process_attribute_req (tGATT_TCB *p_tcb, UINT8 op_code, case GATT_REQ_WRITE: /* write char/char descriptor value */ case GATT_CMD_WRITE: case GATT_SIGN_CMD_WRITE: - case GATT_REQ_PREPARE_WRITE: gatts_process_write_req(p_tcb, i, handle, op_code, len, p); break; + + case GATT_REQ_PREPARE_WRITE: + gatt_attr_process_prepare_write (p_tcb, i, handle, op_code, len, p); default: break; } diff --git a/components/bt/bluedroid/stack/gatt/gatt_utils.c b/components/bt/bluedroid/stack/gatt/gatt_utils.c index 09f4e8df2..60f99966b 100644 --- a/components/bt/bluedroid/stack/gatt/gatt_utils.c +++ b/components/bt/bluedroid/stack/gatt/gatt_utils.c @@ -116,6 +116,26 @@ void gatt_free_pending_enc_queue(tGATT_TCB *p_tcb) } } +/******************************************************************************* +** +** Function gatt_free_pending_prepare_write_queue +** +** Description Free all buffers in pending prepare write packets queue +** +** Returns None +** +*******************************************************************************/ +void gatt_free_pending_prepare_write_queue(tGATT_TCB *p_tcb) +{ + GATT_TRACE_DEBUG("gatt_free_pending_prepare_write_queue"); + /* release all queued prepare write packets */ + while (!GKI_queue_is_empty(&(p_tcb->prepare_write_record.queue))) { + GKI_freebuf (GKI_dequeue (&(p_tcb->prepare_write_record.queue))); + } + p_tcb->prepare_write_record.total_num = 0; + p_tcb->prepare_write_record.error_code_app = GATT_SUCCESS; +} + /******************************************************************************* ** ** Function gatt_delete_dev_from_srv_chg_clt_list @@ -2108,6 +2128,7 @@ void gatt_cleanup_upon_disc(BD_ADDR bda, UINT16 reason, tBT_TRANSPORT transport) btu_stop_timer (&p_tcb->conf_timer_ent); gatt_free_pending_ind(p_tcb); gatt_free_pending_enc_queue(p_tcb); + gatt_free_pending_prepare_write_queue(p_tcb); for (i = 0; i < GATT_MAX_APPS; i ++) { p_reg = &gatt_cb.cl_rcb[i]; diff --git a/components/bt/bluedroid/stack/gatt/include/gatt_int.h b/components/bt/bluedroid/stack/gatt/include/gatt_int.h index c9622a24c..9aca0c5df 100644 --- a/components/bt/bluedroid/stack/gatt/include/gatt_int.h +++ b/components/bt/bluedroid/stack/gatt/include/gatt_int.h @@ -133,6 +133,16 @@ typedef struct { UINT8 reason; } tGATT_ERROR; +/* Execute write response structure */ +typedef struct { + UINT8 op_code; +}__attribute__((packed)) tGATT_EXEC_WRITE_RSP; + +/* Write request response structure */ +typedef struct { + UINT8 op_code; +}__attribute__((packed)) tGATT_WRITE_REQ_RSP; + /* server response message to ATT protocol */ typedef union { @@ -329,6 +339,32 @@ typedef struct { UINT16 count; } tGATT_SRV_LIST_INFO; +/* prepare write queue data */ +typedef struct{ + //len: length of value + tGATT_ATTR16 *p_attr; + UINT16 len; + UINT8 op_code; + UINT16 handle; + UINT16 offset; + UINT8 value[2]; +}__attribute__((packed)) tGATT_PREPARE_WRITE_QUEUE_DATA; + +/* structure to store prepare write packts information */ +typedef struct{ + //only store prepare write packets which need + //to be responded by stack (not by application) + BUFFER_Q queue; + + //store the total number of prepare write packets + //including that should be responded by stack or by application + UINT16 total_num; + + //store application error code for prepare write, + //invalid offset && invalid length + UINT8 error_code_app; +}tGATT_PREPARE_WRITE_RECORD; + typedef struct { BUFFER_Q pending_enc_clcb; /* pending encryption channel q */ tGATT_SEC_ACTION sec_act; @@ -362,6 +398,7 @@ typedef struct { BOOLEAN in_use; UINT8 tcb_idx; + tGATT_PREPARE_WRITE_RECORD prepare_write_record; /* prepare write packets record */ } tGATT_TCB; diff --git a/components/bt/bluedroid/stack/include/gatt_api.h b/components/bt/bluedroid/stack/include/gatt_api.h index 9360d4fbf..42812a5be 100644 --- a/components/bt/bluedroid/stack/include/gatt_api.h +++ b/components/bt/bluedroid/stack/include/gatt_api.h @@ -65,6 +65,8 @@ #define GATT_CONGESTED 0x8f #define GATT_STACK_RSP 0x90 #define GATT_APP_RSP 0x91 +//Error caused by customer application or stack bug +#define GATT_ESP_ERROR 0X9f /* 0xE0 ~ 0xFC reserved for future use */ #define GATT_CCC_CFG_ERR 0xFD /* Client Characteristic Configuration Descriptor Improperly Configured */ From 870389b3ba548af30cfefc961aa86a03c45d4396 Mon Sep 17 00:00:00 2001 From: wangmengyang Date: Mon, 6 Mar 2017 21:50:54 +0800 Subject: [PATCH 097/112] component/bt: optimize stack size of Bluetooth Tasks and make them be configurable according to the CONFIG_NEWLIB_NANO_FORMAT option --- components/bt/bluedroid/osi/include/thread.h | 34 ++++++++++---------- components/esp32/include/esp_task.h | 8 ++++- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/components/bt/bluedroid/osi/include/thread.h b/components/bt/bluedroid/osi/include/thread.h index 61e9487ea..01df95388 100644 --- a/components/bt/bluedroid/osi/include/thread.h +++ b/components/bt/bluedroid/osi/include/thread.h @@ -20,7 +20,7 @@ #include "freertos/FreeRTOS.h" #include "freertos/queue.h" #include "freertos/task.h" - +#include "esp_task.h" #include "bt_defs.h" #define portBASE_TYPE int @@ -43,25 +43,25 @@ enum { SIG_BTIF_WORK = 0xff }; -#define HCI_HOST_TASK_STACK_SIZE 1500 -#define HCI_HOST_TASK_PRIO (configMAX_PRIORITIES - 2) -#define HCI_HOST_TASK_NAME "hciHostT" -#define HCI_HOST_QUEUE_NUM 40 +#define HCI_HOST_TASK_STACK_SIZE (2048 + BT_TASK_EXTRA_STACK_SIZE) +#define HCI_HOST_TASK_PRIO (configMAX_PRIORITIES - 2) +#define HCI_HOST_TASK_NAME "hciHostT" +#define HCI_HOST_QUEUE_NUM 40 -#define HCI_H4_TASK_STACK_SIZE 1500 -#define HCI_H4_TASK_PRIO (configMAX_PRIORITIES - 3) -#define HCI_H4_TASK_NAME "hciH4T" -#define HCI_H4_QUEUE_NUM 60 +#define HCI_H4_TASK_STACK_SIZE (2048 + BT_TASK_EXTRA_STACK_SIZE) +#define HCI_H4_TASK_PRIO (configMAX_PRIORITIES - 3) +#define HCI_H4_TASK_NAME "hciH4T" +#define HCI_H4_QUEUE_NUM 60 -#define BTU_TASK_STACK_SIZE 4096 -#define BTU_TASK_PRIO (configMAX_PRIORITIES - 4) -#define BTU_TASK_NAME "btuT" -#define BTU_QUEUE_NUM 50 +#define BTU_TASK_STACK_SIZE (3584 + BT_TASK_EXTRA_STACK_SIZE) +#define BTU_TASK_PRIO (configMAX_PRIORITIES - 4) +#define BTU_TASK_NAME "btuT" +#define BTU_QUEUE_NUM 50 -#define BTC_TASK_STACK_SIZE CONFIG_BTC_TASK_STACK_SIZE //by menuconfig -#define BTC_TASK_NAME "btcT" -#define BTC_TASK_PRIO (configMAX_PRIORITIES - 5) -#define BTC_TASK_QUEUE_NUM 20 +#define BTC_TASK_STACK_SIZE (CONFIG_BTC_TASK_STACK_SIZE + BT_TASK_EXTRA_STACK_SIZE) //by menuconfig +#define BTC_TASK_NAME "btcT" +#define BTC_TASK_PRIO (configMAX_PRIORITIES - 5) +#define BTC_TASK_QUEUE_NUM 20 void btu_task_post(uint32_t sig); void hci_host_task_post(void); diff --git a/components/esp32/include/esp_task.h b/components/esp32/include/esp_task.h index 04f3178a1..bd2636264 100644 --- a/components/esp32/include/esp_task.h +++ b/components/esp32/include/esp_task.h @@ -34,7 +34,13 @@ /* Bt contoller Task */ /* controller */ #define ESP_TASK_BT_CONTROLLER_PRIO (ESP_TASK_PRIO_MAX - 1) -#define ESP_TASK_BT_CONTROLLER_STACK 4096 +#ifdef CONFIG_NEWLIB_NANO_FORMAT +#define BT_TASK_EXTRA_STACK_SIZE (0) +#else +#define BT_TASK_EXTRA_STACK_SIZE (512) +#endif +#define ESP_TASK_BT_CONTROLLER_STACK (3584 + BT_TASK_EXTRA_STACK_SIZE) + /* idf task */ #define ESP_TASKD_EVENT_PRIO (ESP_TASK_PRIO_MAX - 5) From 41890f15b98fd5050abb3a804194474d571aee42 Mon Sep 17 00:00:00 2001 From: Krzysztof Date: Sun, 26 Feb 2017 08:45:50 +0100 Subject: [PATCH 098/112] - examples: add 'Capacitive touch sensor read' example - examples: add 'Capacitive touch sensor interrupts' example - Code review comments implemented - use only one image - add external picture of ESP32 Demo Board V2 --- .../peripherals/touch_pad_interrupt/Makefile | 8 ++ .../peripherals/touch_pad_interrupt/README.md | 30 +++++ .../touch_pad_interrupt/main/component.mk | 5 + .../main/tp_interrupt_main.c | 109 ++++++++++++++++++ examples/peripherals/touch_pad_read/Makefile | 8 ++ examples/peripherals/touch_pad_read/README.md | 24 ++++ .../touch_pad_read/main/component.mk | 5 + .../touch_pad_read/main/tp_read_main.c | 45 ++++++++ 8 files changed, 234 insertions(+) create mode 100644 examples/peripherals/touch_pad_interrupt/Makefile create mode 100644 examples/peripherals/touch_pad_interrupt/README.md create mode 100644 examples/peripherals/touch_pad_interrupt/main/component.mk create mode 100644 examples/peripherals/touch_pad_interrupt/main/tp_interrupt_main.c create mode 100644 examples/peripherals/touch_pad_read/Makefile create mode 100644 examples/peripherals/touch_pad_read/README.md create mode 100644 examples/peripherals/touch_pad_read/main/component.mk create mode 100644 examples/peripherals/touch_pad_read/main/tp_read_main.c diff --git a/examples/peripherals/touch_pad_interrupt/Makefile b/examples/peripherals/touch_pad_interrupt/Makefile new file mode 100644 index 000000000..b4a0d859e --- /dev/null +++ b/examples/peripherals/touch_pad_interrupt/Makefile @@ -0,0 +1,8 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := touch_pad_interrupt + +include $(IDF_PATH)/make/project.mk diff --git a/examples/peripherals/touch_pad_interrupt/README.md b/examples/peripherals/touch_pad_interrupt/README.md new file mode 100644 index 000000000..341a86855 --- /dev/null +++ b/examples/peripherals/touch_pad_interrupt/README.md @@ -0,0 +1,30 @@ +# Touch Pad Interrupt Example + +Demonstrates how to set up ESP32's capacitive touch pad peripheral to trigger interrupt when a pad is touched. + +Application has been developed and tested using [ESP32 Demo Board V2](https://dl.espressif.com/dl/schematics/ESP32-Demo-Board-V2_sch.pdf) that has ten capacitive sensor pads T0 to T9 exposed. + +![alt text](http://dl.espressif.com/dl/schematics/pictures/esp32-demo-board-v2.jpg "ESP32 Demo Board V2") + +The following output is shown when a pad is touched: + +``` +I (6303) Touch pad: Waiting for any pad being touched... +I (6733) Touch pad: T6 activated! +I (7333) Touch pad: T5 activated! +I (7723) Touch pad: T3 activated! +I (8043) Touch pad: T2 activated! +I (8883) Touch pad: T4 activated! +I (9523) Touch pad: T7 activated! +I (12503) Touch pad: Waiting for any pad being touched... +I (15483) Touch pad: T6 activated! +I (16253) Touch pad: T5 activated! +I (17903) Touch pad: Waiting for any pad being touched... +I (22903) Touch pad: Waiting for any pad being touched... +``` + +Note: Sensing threshold is set up automatically at start up by performing simple calibration. Application is reading current value for each pad and assuming half of this value as the sensing threshold. Do not touch pads on application start up, otherwise sensing may not work correctly. + +For a simpler example how to configure and read capacitive touch pads, please refer to [touch_pad_read](../touch_pad_read). + +See the README.md file in the upper level 'examples' directory for more information about examples. diff --git a/examples/peripherals/touch_pad_interrupt/main/component.mk b/examples/peripherals/touch_pad_interrupt/main/component.mk new file mode 100644 index 000000000..dfe125be7 --- /dev/null +++ b/examples/peripherals/touch_pad_interrupt/main/component.mk @@ -0,0 +1,5 @@ +# +# "main" pseudo-component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) + diff --git a/examples/peripherals/touch_pad_interrupt/main/tp_interrupt_main.c b/examples/peripherals/touch_pad_interrupt/main/tp_interrupt_main.c new file mode 100644 index 000000000..fd4fe5b27 --- /dev/null +++ b/examples/peripherals/touch_pad_interrupt/main/tp_interrupt_main.c @@ -0,0 +1,109 @@ +/* Touch Pad Interrupt Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_system.h" +#include "nvs_flash.h" +#include "esp_log.h" + +#include "driver/touch_pad.h" +#include "soc/rtc_cntl_reg.h" +#include "soc/sens_reg.h" + +static const char* TAG = "Touch pad"; + +static bool touch_pad_activated[TOUCH_PAD_MAX]; + + +/* + Read values sensed at all available touch pads. + Use half of read value as the threshold + to trigger interrupt when the pad is touched. + Note: this routine demonstrates a simple way + to configure activation threshold for the touch pads. + Do not touch any pads when this routine + is running (on application start). + */ +static void touch_pad_set_thresholds(void) +{ + uint16_t touch_value; + for (int i=0; i> i) & 0x01) { + touch_pad_activated[i] = true; + } + } + } +} + + +void app_main() +{ + ESP_LOGI(TAG, "Starting"); + nvs_flash_init(); + + // Initialize touch pad peripheral + ESP_LOGI(TAG, "Initializing touch pad"); + touch_pad_init(); + touch_pad_set_thresholds(); + touch_pad_isr_handler_register(touch_pad_rtc_intr, NULL, 0, NULL); + + // Start a task to show what pads have been touched + xTaskCreate(&touch_pad_read_task, "touch_pad_read_task", 2048, NULL, 5, NULL); +} diff --git a/examples/peripherals/touch_pad_read/Makefile b/examples/peripherals/touch_pad_read/Makefile new file mode 100644 index 000000000..6116edf6e --- /dev/null +++ b/examples/peripherals/touch_pad_read/Makefile @@ -0,0 +1,8 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := touch_pad_read + +include $(IDF_PATH)/make/project.mk diff --git a/examples/peripherals/touch_pad_read/README.md b/examples/peripherals/touch_pad_read/README.md new file mode 100644 index 000000000..6ce92cf4a --- /dev/null +++ b/examples/peripherals/touch_pad_read/README.md @@ -0,0 +1,24 @@ +# Touch Pad Read Example + +Read and display raw values from capacitive touch pad sensors. + +Once configured, ESP32 is continuously measuring capacitance of touch pad sensors. Measurement is reflected as numeric value inversely related to sensor's capacitance. The capacitance is bigger when sensor is touched with a finger and the measured value smaller. In opposite situation, when finger is released, capacitance is smaller and the measured value bigger. + +To detect when a sensor is touched and when not, each particular design should be calibrated by obtaining both measurements for each individual sensor. Then a threshold between both values should be established. Using specific threshold, API is then able to distinguish whether specific sensor is touched or released. + +ESP32 supports reading up to ten capacitive touch pad sensors T0 - T9, connected to specific GPIO pins. For information on available pins please refer to [Technical Reference Manual](http://espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf). Application initializes all ten sensor pads. Then in a loop reads sensors T0 - T9 and displays obtained values (after a colon) on a serial terminal: + +``` +T0: 486 T1: 1 T2: 559 T3: 567 T4: 871 T5: 522 T6:1174 T7:1531 T8:1508 T9:1640 +T0: 485 T1: 1 T2: 559 T3: 568 T4: 871 T5: 521 T6:1176 T7:1536 T8:1509 T9:1635 +T0: 485 T1: 1 T2: 559 T3: 568 T4: 871 T5: 521 T6:1172 T7:1536 T8:1507 T9:1640 +T0: 11 T1: 1 T2: 558 T3: 568 T4: 871 T5: 522 T6:1172 T7:1535 T8:1507 T9:1638 +``` + +Above log is prepared using [ESP32 Demo Board V2](https://dl.espressif.com/dl/schematics/ESP32-Demo-Board-V2_sch.pdf) that has all ten pad sensors exposed. Values will be different depending on layout of pads on particular board. + +![alt text](http://dl.espressif.com/dl/schematics/pictures/esp32-demo-board-v2.jpg "ESP32 Demo Board V2") + +There is another similar example that demonstrates how to perform simple calibration and trigger an interrupt when a pat is touched - see [touch_pad_interrupt](../touch_pad_interrupt). + +See the README.md file in the upper level 'examples' directory for more information about examples. diff --git a/examples/peripherals/touch_pad_read/main/component.mk b/examples/peripherals/touch_pad_read/main/component.mk new file mode 100644 index 000000000..dfe125be7 --- /dev/null +++ b/examples/peripherals/touch_pad_read/main/component.mk @@ -0,0 +1,5 @@ +# +# "main" pseudo-component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) + diff --git a/examples/peripherals/touch_pad_read/main/tp_read_main.c b/examples/peripherals/touch_pad_read/main/tp_read_main.c new file mode 100644 index 000000000..accfe5027 --- /dev/null +++ b/examples/peripherals/touch_pad_read/main/tp_read_main.c @@ -0,0 +1,45 @@ +/* Touch Pad Read Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_system.h" +#include "nvs_flash.h" + +#include "driver/touch_pad.h" + + +/* + Read values sensed at all available touch pads. + Print out values in a loop on a serial monitor. + */ +void touch_pad_read_task(void *pvParameter) +{ + while (1) { + uint16_t touch_value; + for (int i=0; i Date: Tue, 7 Mar 2017 10:16:52 +1100 Subject: [PATCH 099/112] unit tests: Make UnitTestParser ignore non-directories inside 'components' dirs --- tools/unit-test-app/UnitTestParser.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/unit-test-app/UnitTestParser.py b/tools/unit-test-app/UnitTestParser.py index 26f90a026..d3fa1efb0 100644 --- a/tools/unit-test-app/UnitTestParser.py +++ b/tools/unit-test-app/UnitTestParser.py @@ -1,5 +1,6 @@ import yaml import os +import os.path import re import sys import shutil @@ -41,7 +42,7 @@ class Parser(object): def parse_test_folders(cls): test_folder_paths = list() os.chdir(os.path.join(IDF_PATH, "components")) - component_dirs = os.listdir(".") + component_dirs = [d for d in os.listdir(".") if os.path.isdir(d)] for dir in component_dirs: os.chdir(dir) if "test" in os.listdir("."): From 5ffe5474acc5f5ff7a2d74ff57f8bc865c489fef Mon Sep 17 00:00:00 2001 From: island Date: Tue, 7 Mar 2017 19:55:21 +0800 Subject: [PATCH 100/112] bt component: optimize gatt debug information --- components/bt/bluedroid/api/esp_gatts_api.c | 8 ++++---- components/bt/bluedroid/stack/gatt/gatt_db.c | 10 +++++----- components/bt/bluedroid/stack/gatt/gatt_sr.c | 6 ++---- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/components/bt/bluedroid/api/esp_gatts_api.c b/components/bt/bluedroid/api/esp_gatts_api.c index 3a31d7959..3e5d8f581 100644 --- a/components/bt/bluedroid/api/esp_gatts_api.c +++ b/components/bt/bluedroid/api/esp_gatts_api.c @@ -158,8 +158,8 @@ esp_err_t esp_ble_gatts_add_char(uint16_t service_handle, esp_bt_uuid_t *char_ if (char_val != NULL){ if (char_val->attr_len > char_val->attr_max_len){ - LOG_ERROR("Error in %s, line=%d,attribute actual length should not be larger than max length\n",\ - __func__, __LINE__); + LOG_ERROR("Error in %s, line=%d,attribute actual length (%d) should not be larger than max length (%d)\n",\ + __func__, __LINE__, char_val->attr_len, char_val->attr_max_len); return ESP_ERR_INVALID_ARG; } } @@ -214,8 +214,8 @@ esp_err_t esp_ble_gatts_add_char_descr (uint16_t service_handle, if (char_descr_val != NULL){ if (char_descr_val->attr_len > char_descr_val->attr_max_len){ - LOG_ERROR("Error in %s, line=%d,attribute actual length should not be larger than max length\n",\ - __func__, __LINE__); + LOG_ERROR("Error in %s, line=%d,attribute actual length (%d) should not be larger than max length (%d)\n",\ + __func__, __LINE__, char_descr_val->attr_len, char_descr_val->attr_max_len); return ESP_ERR_INVALID_ARG; } } diff --git a/components/bt/bluedroid/stack/gatt/gatt_db.c b/components/bt/bluedroid/stack/gatt/gatt_db.c index 60749a0f4..3f9066d05 100644 --- a/components/bt/bluedroid/stack/gatt/gatt_db.c +++ b/components/bt/bluedroid/stack/gatt/gatt_db.c @@ -528,7 +528,7 @@ UINT16 gatts_add_characteristic (tGATT_SVC_DB *p_db, tGATT_PERM perm, if (p_char_val->p_value->attr_val.attr_val == NULL) { deallocate_attr_in_db(p_db, p_char_decl); deallocate_attr_in_db(p_db, p_char_val); - GATT_TRACE_ERROR("Warning in %s, line=%d, insufficient resource to allocate for attribute value\n", __func__, __LINE__); + GATT_TRACE_WARNING("Warning in %s, line=%d, insufficient resource to allocate for attribute value\n", __func__, __LINE__); return 0; } @@ -536,7 +536,7 @@ UINT16 gatts_add_characteristic (tGATT_SVC_DB *p_db, tGATT_PERM perm, memset(p_char_val->p_value->attr_val.attr_val, 0, attr_val->attr_max_len); if (attr_val->attr_val != NULL) { if (attr_val->attr_max_len < attr_val->attr_len){ - GATT_TRACE_ERROR("Error in %s, Line=%d, attribute actual length(%d) should not larger than max size(%d)\n", + GATT_TRACE_ERROR("Error in %s, Line=%d, attribute actual length (%d) should not larger than max size (%d)\n", __func__, __LINE__, attr_val->attr_len, attr_val->attr_max_len); } UINT16 actual_len = (attr_val->attr_max_len < attr_val->attr_len) ? (attr_val->attr_max_len) : (attr_val->attr_len); @@ -638,8 +638,8 @@ UINT16 gatts_add_char_descr (tGATT_SVC_DB *p_db, tGATT_PERM perm, if (attr_val != NULL){ if (attr_val->attr_len > attr_val->attr_max_len){ - GATT_TRACE_ERROR("Error in %s, line=%d,attribute actual length should not be larger than max length\n",\ - __func__, __LINE__); + GATT_TRACE_ERROR("Error in %s, line=%d,attribute actual length (%d) should not be larger than max length (%d)\n",\ + __func__, __LINE__, attr_val->attr_len, attr_val->attr_max_len); return 0; } } @@ -664,7 +664,7 @@ UINT16 gatts_add_char_descr (tGATT_SVC_DB *p_db, tGATT_PERM perm, p_char_dscptr->p_value->attr_val.attr_val = GKI_getbuf(attr_val->attr_max_len); if (p_char_dscptr->p_value->attr_val.attr_val == NULL) { deallocate_attr_in_db(p_db, p_char_dscptr); - GATT_TRACE_ERROR("Warning in %s, line=%d, insufficient resource to allocate for descriptor value\n", __func__, __LINE__); + GATT_TRACE_WARNING("Warning in %s, line=%d, insufficient resource to allocate for descriptor value\n", __func__, __LINE__); return 0; } diff --git a/components/bt/bluedroid/stack/gatt/gatt_sr.c b/components/bt/bluedroid/stack/gatt/gatt_sr.c index 317eaaca7..4afcab794 100644 --- a/components/bt/bluedroid/stack/gatt/gatt_sr.c +++ b/components/bt/bluedroid/stack/gatt/gatt_sr.c @@ -387,8 +387,8 @@ void gatt_process_exec_write_req (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, U is_prepare_write_valid = TRUE; } else if(prepare_record->total_num < queue_num) { - GATT_TRACE_ERROR("Error in %s, line=%d, prepare write total number(=%d) \ - should not smaller than prepare queue number(=%d)\n", \ + GATT_TRACE_ERROR("Error in %s, line=%d, prepare write total number (%d) \ + should not smaller than prepare queue number (%d)\n", \ __func__, __LINE__,prepare_record->total_num, queue_num); } else if (prepare_record->error_code_app != GATT_SUCCESS){ @@ -1141,8 +1141,6 @@ void gatts_process_write_req (tGATT_TCB *p_tcb, UINT8 i_rcb, UINT16 handle, status = GATT_BUSY; /* max pending command, application error */ } } - //test isl - GATT_TRACE_ERROR("!!!write opcode=0x%x, need_rsp=0x%x, status=0x%x\n",op_code, sr_data.write_req.need_rsp, status); /* response should be sent only for write_request */ if ((op_code == GATT_REQ_WRITE) && (sr_data.write_req.need_rsp == FALSE)){ From 624ad1bd8beb822de3c472f0540c1b1672330f4e Mon Sep 17 00:00:00 2001 From: XiaXiaotian Date: Wed, 8 Mar 2017 10:55:40 +0800 Subject: [PATCH 101/112] wifi deinit: update esp_wifi_deinit() 1. move ets_timer_deinit() to wifi_deinit() 2. delete wifi api mutex when wifi deinit --- components/esp32/include/esp_wifi.h | 1 - components/esp32/lib | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/components/esp32/include/esp_wifi.h b/components/esp32/include/esp_wifi.h index 2312bc08a..05a686a36 100755 --- a/components/esp32/include/esp_wifi.h +++ b/components/esp32/include/esp_wifi.h @@ -164,7 +164,6 @@ esp_err_t esp_wifi_init(wifi_init_config_t *config); * Free all resource allocated in esp_wifi_init and stop WiFi task * * @attention 1. This API should be called if you want to remove WiFi driver from the system - * @attention 2. This API can not be called yet and will be done in the future. * * @return ESP_OK: succeed */ diff --git a/components/esp32/lib b/components/esp32/lib index e87433558..ffe5a4c14 160000 --- a/components/esp32/lib +++ b/components/esp32/lib @@ -1 +1 @@ -Subproject commit e8743355806ed3671f7b0ef8bac1ea63909daaf3 +Subproject commit ffe5a4c14fe9c933c776fadc62fa9d409929e6f9 From cde4072f251fa6c154a27aa5c993625d7e72512d Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Wed, 8 Mar 2017 16:19:58 +0800 Subject: [PATCH 102/112] ulp: ignore tests which use deep sleep --- components/ulp/test/test_ulp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/ulp/test/test_ulp.c b/components/ulp/test/test_ulp.c index 4f62c3c0b..b653c48a8 100644 --- a/components/ulp/test/test_ulp.c +++ b/components/ulp/test/test_ulp.c @@ -64,7 +64,7 @@ TEST_CASE("ulp add test", "[ulp]") TEST_ASSERT_EQUAL(10 + 11, RTC_SLOW_MEM[18] & 0xffff); } -TEST_CASE("ulp branch test", "[ulp][ignore]") +TEST_CASE("ulp branch test", "[ulp]") { assert(CONFIG_ULP_COPROC_RESERVE_MEM >= 260 && "this test needs ULP_COPROC_RESERVE_MEM option set in menuconfig"); memset(RTC_SLOW_MEM, 0, CONFIG_ULP_COPROC_RESERVE_MEM); @@ -266,7 +266,7 @@ TEST_CASE("ulp controls RTC_IO", "[ulp][ignore]") esp_deep_sleep_start(); } -TEST_CASE("ulp power consumption in deep sleep", "[ulp]") +TEST_CASE("ulp power consumption in deep sleep", "[ulp][ignore]") { assert(CONFIG_ULP_COPROC_RESERVE_MEM >= 4 && "this test needs ULP_COPROC_RESERVE_MEM option set in menuconfig"); ulp_insn_t insn = I_HALT(); From 3543d8170c4658933d13c2c66996e1895fe20ac8 Mon Sep 17 00:00:00 2001 From: island Date: Wed, 8 Mar 2017 17:00:56 +0800 Subject: [PATCH 103/112] =?UTF-8?q?bt=20component:=20update=20if=E2=80=A6e?= =?UTF-8?q?lse=20code=20style?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/bt/bluedroid/stack/gatt/gatt_db.c | 9 +++------ components/bt/bluedroid/stack/gatt/gatt_sr.c | 18 ++++++------------ 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/components/bt/bluedroid/stack/gatt/gatt_db.c b/components/bt/bluedroid/stack/gatt/gatt_db.c index 3f9066d05..525375a05 100644 --- a/components/bt/bluedroid/stack/gatt/gatt_db.c +++ b/components/bt/bluedroid/stack/gatt/gatt_db.c @@ -276,8 +276,7 @@ static tGATT_STATUS read_attr_value (void *p_attr, //if offset is greater than max_len, should respond with an error*/ else if (offset > p_attr16->p_value->attr_val.attr_len){ status = GATT_INVALID_OFFSET; - } - else { + } else { UINT8 *value = (UINT8 *)(p_attr16->p_value->attr_val.attr_val) + offset; UINT16 len_left = p_attr16->p_value->attr_val.attr_len - offset; len = (mtu >= len_left) ? (len_left) : mtu; @@ -650,8 +649,7 @@ UINT16 gatts_add_char_descr (tGATT_SVC_DB *p_db, tGATT_PERM perm, deallocate_attr_in_db(p_db, p_char_dscptr); GATT_TRACE_DEBUG("gatts_add_char_descr Fail for adding char descriptors."); return 0; - } - else { + } else { p_char_dscptr->control.auto_rsp = (control == NULL) ? GATT_RSP_DEFAULT : (control->auto_rsp); if (attr_val != NULL) { if (!copy_extra_byte_in_db(p_db, (void **)&p_char_dscptr->p_value, sizeof(tGATT_ATTR_VAL))) { @@ -736,8 +734,7 @@ tGATT_STATUS gatts_set_attribute_value(tGATT_SVC_DB *p_db, UINT16 attr_handle, else if (p_cur->p_value->attr_val.attr_max_len < length) { GATT_TRACE_ERROR("gatts_set_attribute_value failed:Invalid value length"); return GATT_INVALID_ATTR_LEN; - } - else{ + } else{ memcpy(p_cur->p_value->attr_val.attr_val, value, length); p_cur->p_value->attr_val.attr_len = length; } diff --git a/components/bt/bluedroid/stack/gatt/gatt_sr.c b/components/bt/bluedroid/stack/gatt/gatt_sr.c index 4afcab794..d43a3a2c8 100644 --- a/components/bt/bluedroid/stack/gatt/gatt_sr.c +++ b/components/bt/bluedroid/stack/gatt/gatt_sr.c @@ -1135,8 +1135,7 @@ void gatts_process_write_req (tGATT_TCB *p_tcb, UINT8 i_rcb, UINT16 handle, trans_id, GATTS_REQ_TYPE_WRITE, &sr_data); - } - else { + } else { GATT_TRACE_ERROR("Error in %s, line=%d, max pending command, send error\n", __func__, __LINE__); status = GATT_BUSY; /* max pending command, application error */ } @@ -1237,8 +1236,7 @@ void gatt_attr_process_prepare_write (tGATT_TCB *p_tcb, UINT8 i_rcb, UINT16 hand LOG_ERROR("Error in %s, attribute of handle 0x%x not allocate value buffer\n", __func__, handle); status = GATT_ESP_ERROR; - } - else { + } else { //valid prepare write request, need to send response and queue the data //status: GATT_SUCCESS is_need_prepare_write_rsp = TRUE; @@ -1248,8 +1246,7 @@ void gatt_attr_process_prepare_write (tGATT_TCB *p_tcb, UINT8 i_rcb, UINT16 hand p_attr = (tGATT_ATTR16 *)p_attr->p_next; } } - } - else{ + } else{ status = GATT_ESP_ERROR; GATT_TRACE_ERROR("Error in %s, Line %d: GATT BUSY\n", __func__, __LINE__); } @@ -1259,8 +1256,7 @@ void gatt_attr_process_prepare_write (tGATT_TCB *p_tcb, UINT8 i_rcb, UINT16 hand queue_data = (tGATT_PREPARE_WRITE_QUEUE_DATA *)GKI_getbuf(len + sizeof(tGATT_PREPARE_WRITE_QUEUE_DATA)); if (queue_data == NULL){ status = GATT_PREPARE_Q_FULL; - } - else { + } else { queue_data->p_attr = p_attr_temp; queue_data->len = len; queue_data->handle = handle; @@ -1283,8 +1279,7 @@ void gatt_attr_process_prepare_write (tGATT_TCB *p_tcb, UINT8 i_rcb, UINT16 hand LOG_ERROR("Error in %s, line=%d, fail to send prepare_write_rsp, status=0x%x\n", __func__, __LINE__, rsp_send_status); } - } - else{ + } else{ LOG_ERROR("Error in %s, line=%d, queue_data should not be NULL here, fail to send prepare_write_rsp\n", __func__, __LINE__); } @@ -1300,8 +1295,7 @@ void gatt_attr_process_prepare_write (tGATT_TCB *p_tcb, UINT8 i_rcb, UINT16 hand sr_data.write_req.need_rsp = (status == GATT_APP_RSP) ? TRUE : FALSE; memcpy(sr_data.write_req.value, p, len); gatt_sr_send_req_callback(conn_id, trans_id, GATTS_REQ_TYPE_WRITE, &sr_data); - } - else{ + } else{ gatt_send_error_rsp(p_tcb, status, GATT_REQ_PREPARE_WRITE, handle, TRUE); } From a74f3f9fd731fecd6467fdbd1801399a09a84c45 Mon Sep 17 00:00:00 2001 From: island Date: Wed, 8 Mar 2017 17:09:05 +0800 Subject: [PATCH 104/112] bt component: code style update --- components/bt/bluedroid/api/esp_gatts_api.c | 3 +-- components/bt/bluedroid/stack/gatt/gatt_db.c | 19 +++++++----------- components/bt/bluedroid/stack/gatt/gatt_sr.c | 21 +++++++------------- 3 files changed, 15 insertions(+), 28 deletions(-) diff --git a/components/bt/bluedroid/api/esp_gatts_api.c b/components/bt/bluedroid/api/esp_gatts_api.c index 3e5d8f581..318dd25bf 100644 --- a/components/bt/bluedroid/api/esp_gatts_api.c +++ b/components/bt/bluedroid/api/esp_gatts_api.c @@ -148,8 +148,7 @@ esp_err_t esp_ble_gatts_add_char(uint16_t service_handle, esp_bt_uuid_t *char_ LOG_ERROR("Error in %s, line=%d, for stack respond attribute, char_val should not be NULL here\n",\ __func__, __LINE__); return ESP_ERR_INVALID_ARG; - } - else if (char_val->attr_max_len == 0){ + } else if (char_val->attr_max_len == 0){ LOG_ERROR("Error in %s, line=%d, for stack respond attribute, attribute max length should not be 0\n",\ __func__, __LINE__); return ESP_ERR_INVALID_ARG; diff --git a/components/bt/bluedroid/stack/gatt/gatt_db.c b/components/bt/bluedroid/stack/gatt/gatt_db.c index 525375a05..ae4f6430f 100644 --- a/components/bt/bluedroid/stack/gatt/gatt_db.c +++ b/components/bt/bluedroid/stack/gatt/gatt_db.c @@ -272,9 +272,9 @@ static tGATT_STATUS read_attr_value (void *p_attr, if (p_attr16->p_value == NULL || p_attr16->p_value->attr_val.attr_val == NULL) { status = GATT_ESP_ERROR; } - /*if offset equal to max_len, should respond with zero byte value - //if offset is greater than max_len, should respond with an error*/ else if (offset > p_attr16->p_value->attr_val.attr_len){ + /*if offset equal to max_len, should respond with zero byte value + //if offset is greater than max_len, should respond with an error*/ status = GATT_INVALID_OFFSET; } else { UINT8 *value = (UINT8 *)(p_attr16->p_value->attr_val.attr_val) + offset; @@ -476,8 +476,7 @@ UINT16 gatts_add_characteristic (tGATT_SVC_DB *p_db, tGATT_PERM perm, GATT_TRACE_ERROR("Error in %s, line=%d, for stack respond attribute, attr_val should not be NULL here\n",\ __func__, __LINE__); return 0; - } - else if (attr_val->attr_max_len == 0){ + } else if (attr_val->attr_max_len == 0){ GATT_TRACE_ERROR("Error in %s, line=%d, for stack respond attribute, attribute max length should not be 0\n",\ __func__, __LINE__); return 0; @@ -627,8 +626,7 @@ UINT16 gatts_add_char_descr (tGATT_SVC_DB *p_db, tGATT_PERM perm, GATT_TRACE_ERROR("Error in %s, line=%d, for stack respond attribute, attr_val should not be NULL here\n",\ __func__, __LINE__); return 0; - } - else if (attr_val->attr_max_len == 0){ + } else if (attr_val->attr_max_len == 0){ GATT_TRACE_ERROR("Error in %s, line=%d, for stack respond attribute, attribute max length should not be 0\n",\ __func__, __LINE__); return 0; @@ -730,8 +728,7 @@ tGATT_STATUS gatts_set_attribute_value(tGATT_SVC_DB *p_db, UINT16 attr_handle, || (p_cur->p_value->attr_val.attr_max_len == 0)){ GATT_TRACE_ERROR("Error in %s, line=%d, attribute value should not be NULL here\n", __func__, __LINE__); return GATT_NOT_FOUND; - } - else if (p_cur->p_value->attr_val.attr_max_len < length) { + } else if (p_cur->p_value->attr_val.attr_max_len < length) { GATT_TRACE_ERROR("gatts_set_attribute_value failed:Invalid value length"); return GATT_INVALID_ATTR_LEN; } else{ @@ -942,12 +939,10 @@ tGATT_STATUS gatts_write_attr_value_by_handle(tGATT_SVC_DB *p_db, memcpy(p_attr->p_value->attr_val.attr_val + offset, p_value, len); p_attr->p_value->attr_val.attr_len = len + offset; return GATT_SUCCESS; - } - else if (p_attr->p_value->attr_val.attr_max_len < offset + len){ + } else if (p_attr->p_value->attr_val.attr_max_len < offset + len){ GATT_TRACE_DEBUG("Remote device try to write with a length larger then attribute's max length\n"); return GATT_INVALID_ATTR_LEN; - } - else if ((p_attr->p_value == NULL) || (p_attr->p_value->attr_val.attr_val == NULL)){ + } else if ((p_attr->p_value == NULL) || (p_attr->p_value->attr_val.attr_val == NULL)){ GATT_TRACE_ERROR("Error in %s, line=%d, %s should not be NULL here\n", __func__, __LINE__, \ (p_attr->p_value == NULL) ? "p_value" : "attr_val.attr_val"); return GATT_ESP_ERROR; diff --git a/components/bt/bluedroid/stack/gatt/gatt_sr.c b/components/bt/bluedroid/stack/gatt/gatt_sr.c index d43a3a2c8..79d518398 100644 --- a/components/bt/bluedroid/stack/gatt/gatt_sr.c +++ b/components/bt/bluedroid/stack/gatt/gatt_sr.c @@ -378,20 +378,17 @@ void gatt_process_exec_write_req (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, U is_prepare_write_valid = TRUE; } GATT_TRACE_DEBUG("Send execute_write_rsp\n"); - } - else if ((prepare_record->error_code_app == GATT_SUCCESS) && + } else if ((prepare_record->error_code_app == GATT_SUCCESS) && (prepare_record->total_num > queue_num)){ //No error for stack_rsp's handles and there exist some app_rsp's handles, //so exec_write_rsp depends to app's response; but stack_rsp's data is valid //TODO: there exist problem if stack_rsp's data is valid but app_rsp's data is not valid. is_prepare_write_valid = TRUE; - } - else if(prepare_record->total_num < queue_num) { + } else if(prepare_record->total_num < queue_num) { GATT_TRACE_ERROR("Error in %s, line=%d, prepare write total number (%d) \ should not smaller than prepare queue number (%d)\n", \ __func__, __LINE__,prepare_record->total_num, queue_num); - } - else if (prepare_record->error_code_app != GATT_SUCCESS){ + } else if (prepare_record->error_code_app != GATT_SUCCESS){ GATT_TRACE_DEBUG("Send error code for execute_write, code=0x%x\n", prepare_record->error_code_app); is_need_dequeue_sr_cmd = (prepare_record->total_num == queue_num) ? TRUE : FALSE; gatt_send_error_rsp(p_tcb, prepare_record->error_code_app, GATT_REQ_EXEC_WRITE, 0, is_need_dequeue_sr_cmd); @@ -1148,8 +1145,7 @@ void gatts_process_write_req (tGATT_TCB *p_tcb, UINT8 i_rcb, UINT16 handle, gatt_write_req_rsp.op_code = GATT_RSP_WRITE; gatt_send_packet(p_tcb, (UINT8 *)(&gatt_write_req_rsp), sizeof(gatt_write_req_rsp)); gatt_dequeue_sr_cmd(p_tcb); - } - else if (status != GATT_PENDING){ + } else if (status != GATT_PENDING){ /* note: in case of GATT_BUSY, will respond this application error to remote device */ gatt_send_error_rsp (p_tcb, status, op_code, handle, TRUE); } @@ -1219,20 +1215,17 @@ void gatt_attr_process_prepare_write (tGATT_TCB *p_tcb, UINT8 i_rcb, UINT16 hand p_attr_temp = p_attr; if (p_attr->control.auto_rsp == GATT_RSP_BY_APP) { status = GATT_APP_RSP; - } - else if (p_attr->p_value != NULL && + } else if (p_attr->p_value != NULL && offset > p_attr->p_value->attr_val.attr_max_len) { status = GATT_INVALID_OFFSET; is_need_prepare_write_rsp = TRUE; is_need_queue_data = TRUE; - } - else if (p_attr->p_value != NULL && + } else if (p_attr->p_value != NULL && ((offset + len) > p_attr->p_value->attr_val.attr_max_len)){ status = GATT_INVALID_ATTR_LEN; is_need_prepare_write_rsp = TRUE; is_need_queue_data = TRUE; - } - else if (p_attr->p_value == NULL) { + } else if (p_attr->p_value == NULL) { LOG_ERROR("Error in %s, attribute of handle 0x%x not allocate value buffer\n", __func__, handle); status = GATT_ESP_ERROR; From 0db8b00b8aced2367d9226bccb1fa5210d034733 Mon Sep 17 00:00:00 2001 From: Jeroen Domburg Date: Wed, 25 Jan 2017 17:25:50 +0800 Subject: [PATCH 105/112] tight 28k --- components/esp32/cpu_start.c | 15 +- components/esp32/heap_alloc_caps.c | 45 ++- .../esp32/include/esp_heap_alloc_caps.h | 11 + components/esp32/include/heap_alloc_caps.h | 34 -- components/esp32/ld/esp32.rom.ld | 343 +++++++++--------- 5 files changed, 243 insertions(+), 205 deletions(-) delete mode 100644 components/esp32/include/heap_alloc_caps.h diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index cf2008350..2dbfffd5a 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -38,7 +38,7 @@ #include "tcpip_adapter.h" -#include "heap_alloc_caps.h" +#include "esp_heap_alloc_caps.h" #include "sdkconfig.h" #include "esp_system.h" #include "esp_spi_flash.h" @@ -106,8 +106,6 @@ void IRAM_ATTR call_start_cpu0() memset(&_rtc_bss_start, 0, (&_rtc_bss_end - &_rtc_bss_start) * sizeof(_rtc_bss_start)); } - // Initialize heap allocator - heap_alloc_caps_init(); ESP_EARLY_LOGI(TAG, "Pro cpu up."); @@ -131,6 +129,15 @@ void IRAM_ATTR call_start_cpu0() ESP_EARLY_LOGI(TAG, "Single core mode"); CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN); #endif + + /* Initialize heap allocator. WARNING: This *needs* to happen *after* the app cpu has booted. + If the heap allocator is initialized first, it will put free memory linked list items into + memory also used by the ROM. Starting the app cpu will let its ROM initialize that memory, + corrupting those linked lists. Initializing the allocator *after* the app cpu has booted + works around this problem. */ + heap_alloc_caps_init(); + + ESP_EARLY_LOGI(TAG, "Pro cpu start user code"); start_cpu0(); } @@ -250,6 +257,8 @@ static void main_task(void* args) // Now that the application is about to start, disable boot watchdogs REG_CLR_BIT(TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN_S); REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN); + //Enable allocation in region where the startup stacks were located. + heap_alloc_enable_nonos_stack_tag(); app_main(); vTaskDelete(NULL); } diff --git a/components/esp32/heap_alloc_caps.c b/components/esp32/heap_alloc_caps.c index 7d2a26e64..565dd9b8f 100644 --- a/components/esp32/heap_alloc_caps.c +++ b/components/esp32/heap_alloc_caps.c @@ -36,6 +36,7 @@ hardwiring addresses. //Amount of priority slots for the tag descriptors. #define NO_PRIOS 3 + typedef struct { const char *name; uint32_t prio[NO_PRIOS]; @@ -46,6 +47,9 @@ typedef struct { Tag descriptors. These describe the capabilities of a bit of memory that's tagged with the index into this table. Each tag contains NO_PRIOS entries; later entries are only taken if earlier ones can't fulfill the memory request. Make sure there are never more than HEAPREGIONS_MAX_TAGCOUNT (in heap_regions.h) tags (ex the last empty marker) + +WARNING: The current code assumes the ROM stacks are located in tag 1; no allocation from this tag can be done until +the FreeRTOS scheduler has started. */ static const tag_desc_t tag_desc[]={ { "DRAM", { MALLOC_CAP_DMA|MALLOC_CAP_8BIT, MALLOC_CAP_32BIT, 0 }, false}, //Tag 0: Plain ole D-port RAM @@ -89,8 +93,8 @@ This array is *NOT* const because it gets modified depending on what pools are/a static HeapRegionTagged_t regions[]={ { (uint8_t *)0x3F800000, 0x20000, 15, 0}, //SPI SRAM, if available { (uint8_t *)0x3FFAE000, 0x2000, 0, 0}, //pool 16 <- used for rom code - { (uint8_t *)0x3FFB0000, 0x8000, 0, 0}, //pool 15 <- can be used for BT - { (uint8_t *)0x3FFB8000, 0x8000, 0, 0}, //pool 14 <- can be used for BT + { (uint8_t *)0x3FFB0000, 0x8000, 0, 0}, //pool 15 <- if BT is enabled, used as BT HW shared memory + { (uint8_t *)0x3FFB8000, 0x8000, 0, 0}, //pool 14 <- if BT is enabled, used data memory for BT ROM functions. { (uint8_t *)0x3FFC0000, 0x2000, 0, 0}, //pool 10-13, mmu page 0 { (uint8_t *)0x3FFC2000, 0x2000, 0, 0}, //pool 10-13, mmu page 1 { (uint8_t *)0x3FFC4000, 0x2000, 0, 0}, //pool 10-13, mmu page 2 @@ -134,6 +138,16 @@ static HeapRegionTagged_t regions[]={ { NULL, 0, 0, 0} //end }; +/* For the startup code, the stacks live in memory tagged by this tag. Hence, we only enable allocating from this tag + once FreeRTOS has started up completely. */ +#define NONOS_STACK_TAG 1 + +static bool nonos_stack_in_use=true; + +void heap_alloc_enable_nonos_stack_tag() +{ + nonos_stack_in_use=false; +} //Modify regions array to disable the given range of memory. static void disable_mem_region(void *from, void *to) { @@ -185,12 +199,24 @@ void heap_alloc_caps_init() { //Disable the bits of memory where this code is loaded. disable_mem_region(&_data_start, &_heap_start); //DRAM used by bss/data static variables disable_mem_region(&_init_start, &_iram_text_end); //IRAM used by code - disable_mem_region((void*)0x3ffae000, (void*)0x3ffb0000); //knock out ROM data region disable_mem_region((void*)0x40070000, (void*)0x40078000); //CPU0 cache region disable_mem_region((void*)0x40078000, (void*)0x40080000); //CPU1 cache region - // TODO: this region should be checked, since we don't need to knock out all region finally - disable_mem_region((void*)0x3ffe0000, (void*)0x3ffe8000); //knock out ROM data region + /* Warning: The ROM stack is located in the 0x3ffe0000 area. We do not specifically disable that area here because + after the scheduler has started, the ROM stack is not used anymore by anything. We handle it instead by not allowing + any mallocs from tag 1 (the IRAM/DRAM region) until the scheduler has started. + + The 0x3ffe0000 region also contains static RAM for various ROM functions. The following lines knocks + out the regions for UART and ETSC, so these functions are usable. Libraries like xtos, which are + not usable in FreeRTOS anyway, are commented out in the linker script so they cannot be used; we + do not disable their memory regions here and they will be used as general purpose heap memory. + + Enabling the heap allocator for this region but disabling allocation here until FreeRTOS is started up + is a somewhat risky action in theory, because on initializing the allocator, it will go and write linked + list entries at the start and end of all regions. For the ESP32, these linked list entries happen to end + up in a region that is not touched by the stack; they can be placed safely there.*/ + disable_mem_region((void*)0x3ffe0000, (void*)0x3ffe0440); //knock out ROM PRO data region + disable_mem_region((void*)0x3ffe4000, (void*)0x3ffe4350); //knock out ROM APP data region #if CONFIG_BT_ENABLED #if CONFIG_BT_DRAM_RELEASE @@ -198,8 +224,11 @@ void heap_alloc_caps_init() { disable_mem_region((void*)0x3ffb8000, (void*)0x3ffbbb28); //knock out BT data region disable_mem_region((void*)0x3ffbdb28, (void*)0x3ffc0000); //knock out BT data region #else - disable_mem_region((void*)0x3ffb0000, (void*)0x3ffc0000); //knock out BT data region + disable_mem_region((void*)0x3ffb0000, (void*)0x3ffc0000); //knock out BT hardware shared memory & BT data region #endif + disable_mem_region((void*)0x3ffae000, (void*)0x3ffaff10); //knock out ROM data region, inc region needed for BT ROM routines +#else + disable_mem_region((void*)0x3ffae000, (void*)0x3ffae2a0); //knock out ROM data region #endif #if CONFIG_MEMMAP_TRACEMEM @@ -317,6 +346,10 @@ void *pvPortMallocCaps( size_t xWantedSize, uint32_t caps ) for (prio=0; prio>>>> btdm data */ + From e5f54a9dbdb117df3132726de5304ed08a591450 Mon Sep 17 00:00:00 2001 From: Jeroen Domburg Date: Wed, 25 Jan 2017 17:46:26 +0800 Subject: [PATCH 106/112] Validate more GPIO ROM functions for non-use of static RAM --- components/esp32/ld/esp32.rom.ld | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/components/esp32/ld/esp32.rom.ld b/components/esp32/ld/esp32.rom.ld index 05687e2df..bed42c988 100644 --- a/components/esp32/ld/esp32.rom.ld +++ b/components/esp32/ld/esp32.rom.ld @@ -1677,21 +1677,11 @@ replace them and this way we can re-use the fixed RAM addresses these routines n */ /* PROVIDE ( gpio_init = 0x40009c20 ); -PROVIDE ( gpio_input_get = 0x40009b88 ); -PROVIDE ( gpio_input_get_high = 0x40009b9c ); PROVIDE ( gpio_intr_ack = 0x40009dd4 ); PROVIDE ( gpio_intr_ack_high = 0x40009e1c ); PROVIDE ( gpio_intr_handler_register = 0x40009e6c ); PROVIDE ( gpio_intr_pending = 0x40009cec ); PROVIDE ( gpio_intr_pending_high = 0x40009cf8 ); -PROVIDE ( gpio_matrix_in = 0x40009edc ); -PROVIDE ( gpio_matrix_out = 0x40009f0c ); -PROVIDE ( gpio_pad_hold = 0x4000a734 ); -PROVIDE ( gpio_pad_pulldown = 0x4000a348 ); -PROVIDE ( gpio_pad_pullup = 0x4000a22c ); -PROVIDE ( gpio_pad_select_gpio = 0x40009fdc ); -PROVIDE ( gpio_pad_set_drv = 0x4000a11c ); -PROVIDE ( gpio_pad_unhold = 0x4000a484 ); PROVIDE ( gpio_pending_mask = 0x3ffe0038 ); PROVIDE ( gpio_pending_mask_high = 0x3ffe0044 ); PROVIDE ( gpio_pin_intr_state_set = 0x40009d04 ); @@ -1703,6 +1693,16 @@ PROVIDE ( gpio_register_set = 0x40009bbc ); /* These are still part of that driver, but have been verified not to use static RAM, so they can be used. */ PROVIDE ( gpio_output_set = 0x40009b24 ); PROVIDE ( gpio_output_set_high = 0x40009b5c ); +PROVIDE ( gpio_input_get = 0x40009b88 ); +PROVIDE ( gpio_input_get_high = 0x40009b9c ); +PROVIDE ( gpio_matrix_in = 0x40009edc ); +PROVIDE ( gpio_matrix_out = 0x40009f0c ); +PROVIDE ( gpio_pad_select_gpio = 0x40009fdc ); +PROVIDE ( gpio_pad_set_drv = 0x4000a11c ); +PROVIDE ( gpio_pad_pulldown = 0x4000a348 ); +PROVIDE ( gpio_pad_pullup = 0x4000a22c ); +PROVIDE ( gpio_pad_hold = 0x4000a734 ); +PROVIDE ( gpio_pad_unhold = 0x4000a484 ); /* These functions are part of the non-os kernel (etsc). From 37d56b0e8a6c9e032835926ee93df2cb6c75da43 Mon Sep 17 00:00:00 2001 From: Jeroen Domburg Date: Fri, 27 Jan 2017 15:01:51 +0800 Subject: [PATCH 107/112] Add small testcase --- components/freertos/test/test_malloc.c | 49 ++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 components/freertos/test/test_malloc.c diff --git a/components/freertos/test/test_malloc.c b/components/freertos/test/test_malloc.c new file mode 100644 index 000000000..d7f146450 --- /dev/null +++ b/components/freertos/test/test_malloc.c @@ -0,0 +1,49 @@ +/* + Test for multicore FreeRTOS. This test spins up threads, fiddles with queues etc. +*/ + +#include +#include +#include "rom/ets_sys.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "freertos/queue.h" +#include "freertos/xtensa_api.h" +#include "unity.h" +#include "soc/uart_reg.h" +#include "soc/dport_reg.h" +#include "soc/io_mux_reg.h" + +static int tryAllocMem() { + int **mem; + int i, noAllocated, j; + mem=malloc(sizeof(int)*1024); + if (!mem) return 0; + for (i=0; i<1024; i++) { + mem[i]=malloc(1024); + if (mem[i]==NULL) break; + for (j=0; j<1024/4; j++) mem[i][j]=(0xdeadbeef); + } + noAllocated=i; + for (i=0; i Date: Wed, 8 Mar 2017 19:27:30 +0800 Subject: [PATCH 108/112] MR suggestions --- components/esp32/heap_alloc_caps.c | 20 ++++++++++---------- components/esp32/include/heap_alloc_caps.h | 3 +++ components/esp32/ld/esp32.rom.ld | 2 +- 3 files changed, 14 insertions(+), 11 deletions(-) create mode 100644 components/esp32/include/heap_alloc_caps.h diff --git a/components/esp32/heap_alloc_caps.c b/components/esp32/heap_alloc_caps.c index 565dd9b8f..6597ca7f0 100644 --- a/components/esp32/heap_alloc_caps.c +++ b/components/esp32/heap_alloc_caps.c @@ -215,27 +215,27 @@ void heap_alloc_caps_init() { is a somewhat risky action in theory, because on initializing the allocator, it will go and write linked list entries at the start and end of all regions. For the ESP32, these linked list entries happen to end up in a region that is not touched by the stack; they can be placed safely there.*/ - disable_mem_region((void*)0x3ffe0000, (void*)0x3ffe0440); //knock out ROM PRO data region - disable_mem_region((void*)0x3ffe4000, (void*)0x3ffe4350); //knock out ROM APP data region + disable_mem_region((void*)0x3ffe0000, (void*)0x3ffe0440); //Reserve ROM PRO data region + disable_mem_region((void*)0x3ffe4000, (void*)0x3ffe4350); //Reserve ROM APP data region #if CONFIG_BT_ENABLED #if CONFIG_BT_DRAM_RELEASE - disable_mem_region((void*)0x3ffb0000, (void*)0x3ffb3000); //knock out BT data region - disable_mem_region((void*)0x3ffb8000, (void*)0x3ffbbb28); //knock out BT data region - disable_mem_region((void*)0x3ffbdb28, (void*)0x3ffc0000); //knock out BT data region + disable_mem_region((void*)0x3ffb0000, (void*)0x3ffb3000); //Reserve BT data region + disable_mem_region((void*)0x3ffb8000, (void*)0x3ffbbb28); //Reserve BT data region + disable_mem_region((void*)0x3ffbdb28, (void*)0x3ffc0000); //Reserve BT data region #else - disable_mem_region((void*)0x3ffb0000, (void*)0x3ffc0000); //knock out BT hardware shared memory & BT data region + disable_mem_region((void*)0x3ffb0000, (void*)0x3ffc0000); //Reserve BT hardware shared memory & BT data region #endif - disable_mem_region((void*)0x3ffae000, (void*)0x3ffaff10); //knock out ROM data region, inc region needed for BT ROM routines + disable_mem_region((void*)0x3ffae000, (void*)0x3ffaff10); //Reserve ROM data region, inc region needed for BT ROM routines #else - disable_mem_region((void*)0x3ffae000, (void*)0x3ffae2a0); //knock out ROM data region + disable_mem_region((void*)0x3ffae000, (void*)0x3ffae2a0); //Reserve ROM data region #endif #if CONFIG_MEMMAP_TRACEMEM #if CONFIG_MEMMAP_TRACEMEM_TWOBANKS - disable_mem_region((void*)0x3fff8000, (void*)0x40000000); //knock out trace mem region + disable_mem_region((void*)0x3fff8000, (void*)0x40000000); //Reserve trace mem region #else - disable_mem_region((void*)0x3fff8000, (void*)0x3fffc000); //knock out trace mem region + disable_mem_region((void*)0x3fff8000, (void*)0x3fffc000); //Reserve trace mem region #endif #endif diff --git a/components/esp32/include/heap_alloc_caps.h b/components/esp32/include/heap_alloc_caps.h new file mode 100644 index 000000000..edab15d52 --- /dev/null +++ b/components/esp32/include/heap_alloc_caps.h @@ -0,0 +1,3 @@ +#pragma once +#warning heap_alloc_caps.h has been renamed to esp_heap_alloc_caps.h. The old header file is deprecated and will be removed in v3.0. +#include "esp_heap_alloc_caps.h" diff --git a/components/esp32/ld/esp32.rom.ld b/components/esp32/ld/esp32.rom.ld index bed42c988..6cbd2fc74 100644 --- a/components/esp32/ld/esp32.rom.ld +++ b/components/esp32/ld/esp32.rom.ld @@ -1675,7 +1675,7 @@ PROVIDE ( uart_tx_wait_idle = 0x40009278 ); These functions are part of the ROM GPIO driver. We do not use them; the provided esp-idf functions replace them and this way we can re-use the fixed RAM addresses these routines need. */ -/* +/* <-- So you don't read over it: This comment disables the next lines. PROVIDE ( gpio_init = 0x40009c20 ); PROVIDE ( gpio_intr_ack = 0x40009dd4 ); PROVIDE ( gpio_intr_ack_high = 0x40009e1c ); From ab5bbfa74bed2bef28ad62e14b64a26b3ef51b34 Mon Sep 17 00:00:00 2001 From: Jeroen Domburg Date: Wed, 8 Mar 2017 19:44:57 +0800 Subject: [PATCH 109/112] Malloc test: tabs -> spaces, fix description --- components/freertos/test/test_malloc.c | 48 +++++++++++++------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/components/freertos/test/test_malloc.c b/components/freertos/test/test_malloc.c index d7f146450..7bcc291e3 100644 --- a/components/freertos/test/test_malloc.c +++ b/components/freertos/test/test_malloc.c @@ -1,5 +1,5 @@ /* - Test for multicore FreeRTOS. This test spins up threads, fiddles with queues etc. + Generic test for malloc/free */ #include @@ -17,33 +17,33 @@ #include "soc/io_mux_reg.h" static int tryAllocMem() { - int **mem; - int i, noAllocated, j; - mem=malloc(sizeof(int)*1024); - if (!mem) return 0; - for (i=0; i<1024; i++) { - mem[i]=malloc(1024); - if (mem[i]==NULL) break; - for (j=0; j<1024/4; j++) mem[i][j]=(0xdeadbeef); - } - noAllocated=i; - for (i=0; i Date: Tue, 17 Jan 2017 11:55:04 +0800 Subject: [PATCH 110/112] deep sleep: add notice that pads used for wakeup will be configured as RTC GPIOs Closes https://github.com/espressif/esp-idf/issues/245 --- docs/api/system/deep_sleep.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/api/system/deep_sleep.rst b/docs/api/system/deep_sleep.rst index c66127d63..407b14bae 100644 --- a/docs/api/system/deep_sleep.rst +++ b/docs/api/system/deep_sleep.rst @@ -45,6 +45,8 @@ Because RTC IO module is enabled in this mode, internal pullup or pulldown resis In revisions 0 and 1 of the ESP32, this wakeup source is incompatible with ULP and touch wakeup sources. +.. warning:: After wake up from deep sleep, IO pad used for wakeup will be configured as RTC IO. Before using this pad as digital GPIO, reconfigure it using ``rtc_gpio_deinit(gpio_num)`` function. + .. doxygenfunction:: esp_deep_sleep_enable_ext0_wakeup External wakeup (ext1) @@ -60,6 +62,8 @@ This wakeup source is implemented by the RTC controller. As such, RTC peripheral esp_deep_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); gpio_pullup_dis(gpio_num); gpio_pulldown_en(gpio_num); + +.. warning:: After wake up from deep sleep, IO pad(s) used for wakeup will be configured as RTC IO. Before using these pads as digital GPIOs, reconfigure them using ``rtc_gpio_deinit(gpio_num)`` function. The following function can be used to enable this wakeup mode: From 123b6f88dca5961a69debf7735aefa6d26155a05 Mon Sep 17 00:00:00 2001 From: island Date: Thu, 9 Mar 2017 15:36:22 +0800 Subject: [PATCH 111/112] component/bt: modify BLE advertising type error --- .../bt/bluedroid/stack/include/btm_ble_api.h | 59 +++++++++++-------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/components/bt/bluedroid/stack/include/btm_ble_api.h b/components/bt/bluedroid/stack/include/btm_ble_api.h index 6eb078386..4d3f5f889 100644 --- a/components/bt/bluedroid/stack/include/btm_ble_api.h +++ b/components/bt/bluedroid/stack/include/btm_ble_api.h @@ -310,30 +310,41 @@ typedef void (tBTM_RAND_ENC_CB) (tBTM_RAND_ENC *p1); typedef UINT32 tBTM_BLE_AD_MASK; -#define BTM_BLE_AD_TYPE_FLAG HCI_EIR_FLAGS_TYPE /* 0x01 */ -#define BTM_BLE_AD_TYPE_16SRV_PART HCI_EIR_MORE_16BITS_UUID_TYPE /* 0x02 */ -#define BTM_BLE_AD_TYPE_16SRV_CMPL HCI_EIR_COMPLETE_16BITS_UUID_TYPE /* 0x03 */ -#define BTM_BLE_AD_TYPE_32SRV_PART HCI_EIR_MORE_32BITS_UUID_TYPE /* 0x04 */ -#define BTM_BLE_AD_TYPE_32SRV_CMPL HCI_EIR_COMPLETE_32BITS_UUID_TYPE /* 0x05 */ -#define BTM_BLE_AD_TYPE_128SRV_PART HCI_EIR_MORE_128BITS_UUID_TYPE /* 0x06 */ -#define BTM_BLE_AD_TYPE_128SRV_CMPL HCI_EIR_COMPLETE_128BITS_UUID_TYPE /* 0x07 */ -#define BTM_BLE_AD_TYPE_NAME_SHORT HCI_EIR_SHORTENED_LOCAL_NAME_TYPE /* 0x08 */ -#define BTM_BLE_AD_TYPE_NAME_CMPL HCI_EIR_COMPLETE_LOCAL_NAME_TYPE /* 0x09 */ -#define BTM_BLE_AD_TYPE_TX_PWR HCI_EIR_TX_POWER_LEVEL_TYPE /* 0x0A */ -#define BTM_BLE_AD_TYPE_DEV_CLASS 0x0D -#define BTM_BLE_AD_TYPE_SM_TK 0x10 -#define BTM_BLE_AD_TYPE_SM_OOB_FLAG 0x11 -#define BTM_BLE_AD_TYPE_INT_RANGE 0x12 -#define BTM_BLE_AD_TYPE_SOL_SRV_UUID 0x14 -#define BTM_BLE_AD_TYPE_128SOL_SRV_UUID 0x15 -#define BTM_BLE_AD_TYPE_SERVICE_DATA 0x16 -#define BTM_BLE_AD_TYPE_PUBLIC_TARGET 0x17 -#define BTM_BLE_AD_TYPE_RANDOM_TARGET 0x18 -#define BTM_BLE_AD_TYPE_APPEARANCE 0x19 -#define BTM_BLE_AD_TYPE_ADV_INT 0x1a -#define BTM_BLE_AD_TYPE_32SOL_SRV_UUID 0x1b -#define BTM_BLE_AD_TYPE_32SERVICE_DATA 0x1c -#define BTM_BLE_AD_TYPE_128SERVICE_DATA 0x1d +#define BTM_BLE_AD_TYPE_FLAG HCI_EIR_FLAGS_TYPE /* 0x01 */ +#define BTM_BLE_AD_TYPE_16SRV_PART HCI_EIR_MORE_16BITS_UUID_TYPE /* 0x02 */ +#define BTM_BLE_AD_TYPE_16SRV_CMPL HCI_EIR_COMPLETE_16BITS_UUID_TYPE /* 0x03 */ +#define BTM_BLE_AD_TYPE_32SRV_PART HCI_EIR_MORE_32BITS_UUID_TYPE /* 0x04 */ +#define BTM_BLE_AD_TYPE_32SRV_CMPL HCI_EIR_COMPLETE_32BITS_UUID_TYPE /* 0x05 */ +#define BTM_BLE_AD_TYPE_128SRV_PART HCI_EIR_MORE_128BITS_UUID_TYPE /* 0x06 */ +#define BTM_BLE_AD_TYPE_128SRV_CMPL HCI_EIR_COMPLETE_128BITS_UUID_TYPE /* 0x07 */ +#define BTM_BLE_AD_TYPE_NAME_SHORT HCI_EIR_SHORTENED_LOCAL_NAME_TYPE /* 0x08 */ +#define BTM_BLE_AD_TYPE_NAME_CMPL HCI_EIR_COMPLETE_LOCAL_NAME_TYPE /* 0x09 */ +#define BTM_BLE_AD_TYPE_TX_PWR HCI_EIR_TX_POWER_LEVEL_TYPE /* 0x0A */ +#define BTM_BLE_AD_TYPE_DEV_CLASS 0x0D +#define BTM_BLE_AD_TYPE_SM_TK 0x10 +#define BTM_BLE_AD_TYPE_SM_OOB_FLAG 0x11 +#define BTM_BLE_AD_TYPE_INT_RANGE 0x12 +#define BTM_BLE_AD_TYPE_SOL_SRV_UUID 0x14 +#define BTM_BLE_AD_TYPE_128SOL_SRV_UUID 0x15 +#define BTM_BLE_AD_TYPE_SERVICE_DATA 0x16 +#define BTM_BLE_AD_TYPE_PUBLIC_TARGET 0x17 +#define BTM_BLE_AD_TYPE_RANDOM_TARGET 0x18 +#define BTM_BLE_AD_TYPE_APPEARANCE 0x19 +#define BTM_BLE_AD_TYPE_ADV_INT 0x1a +#define BTM_BLE_AD_TYPE_LE_DEV_ADDR 0x1b +#define BTM_BLE_AD_TYPE_LE_ROLE 0x1c +#define BTM_BLE_AD_TYPE_SPAIR_C256 0x1d +#define BTM_BLE_AD_TYPE_SPAIR_R256 0x1e +#define BTM_BLE_AD_TYPE_32SOL_SRV_UUID 0x1f +#define BTM_BLE_AD_TYPE_32SERVICE_DATA 0x20 +#define BTM_BLE_AD_TYPE_128SERVICE_DATA 0x21 +#define BTM_BLE_AD_TYPE_LE_SECURE_CONFIRM 0x22 +#define BTM_BLE_AD_TYPE_LE_SECURE_RANDOM 0x23 +#define BTM_BLE_AD_TYPE_URI 0x24 +#define BTM_BLE_AD_TYPE_INDOOR_POSITION 0x25 +#define BTM_BLE_AD_TYPE_TRANS_DISC_DATA 0x26 +#define BTM_BLE_AD_TYPE_LE_SUPPORT_FEATURE 0x27 +#define BTM_BLE_AD_TYPE_CHAN_MAP_UPDATE 0x28 #define BTM_BLE_AD_TYPE_MANU HCI_EIR_MANUFACTURER_SPECIFIC_TYPE /* 0xff */ typedef UINT8 tBTM_BLE_AD_TYPE; From 17a4a2527d5580f1fe36d823f6fd8839b0a46a5b Mon Sep 17 00:00:00 2001 From: Jeroen Domburg Date: Thu, 9 Mar 2017 19:59:09 +0800 Subject: [PATCH 112/112] MR things --- components/esp32/heap_alloc_caps.c | 10 +++++----- components/esp32/include/esp_heap_alloc_caps.h | 7 ++++--- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/components/esp32/heap_alloc_caps.c b/components/esp32/heap_alloc_caps.c index 6597ca7f0..1c6df9491 100644 --- a/components/esp32/heap_alloc_caps.c +++ b/components/esp32/heap_alloc_caps.c @@ -206,15 +206,15 @@ void heap_alloc_caps_init() { after the scheduler has started, the ROM stack is not used anymore by anything. We handle it instead by not allowing any mallocs from tag 1 (the IRAM/DRAM region) until the scheduler has started. - The 0x3ffe0000 region also contains static RAM for various ROM functions. The following lines knocks - out the regions for UART and ETSC, so these functions are usable. Libraries like xtos, which are + The 0x3ffe0000 region also contains static RAM for various ROM functions. The following lines + reserve the regions for UART and ETSC, so these functions are usable. Libraries like xtos, which are not usable in FreeRTOS anyway, are commented out in the linker script so they cannot be used; we do not disable their memory regions here and they will be used as general purpose heap memory. Enabling the heap allocator for this region but disabling allocation here until FreeRTOS is started up - is a somewhat risky action in theory, because on initializing the allocator, it will go and write linked - list entries at the start and end of all regions. For the ESP32, these linked list entries happen to end - up in a region that is not touched by the stack; they can be placed safely there.*/ + is a somewhat risky action in theory, because on initializing the allocator, vPortDefineHeapRegionsTagged + will go and write linked list entries at the start and end of all regions. For the ESP32, these linked + list entries happen to end up in a region that is not touched by the stack; they can be placed safely there.*/ disable_mem_region((void*)0x3ffe0000, (void*)0x3ffe0440); //Reserve ROM PRO data region disable_mem_region((void*)0x3ffe4000, (void*)0x3ffe4350); //Reserve ROM APP data region diff --git a/components/esp32/include/esp_heap_alloc_caps.h b/components/esp32/include/esp_heap_alloc_caps.h index 7a9844d16..e1021c30b 100644 --- a/components/esp32/include/esp_heap_alloc_caps.h +++ b/components/esp32/include/esp_heap_alloc_caps.h @@ -41,9 +41,10 @@ void heap_alloc_caps_init(); /** * @brief Enable the memory region where the startup stacks are located for allocation * - * On startup, the pro/app CPUs have a certain stack frame, so we cannot do allocations - * in the regions these stack frames are. When FreeRTOS is completely started, they do - * not use that memory anymore and allocation there can be re-enabled. + * On startup, the pro/app CPUs have a certain memory region they use as stack, so we + * cannot do allocations in the regions these stack frames are. When FreeRTOS is + * completely started, they do not use that memory anymore and allocation there can + * be re-enabled. */ void heap_alloc_enable_nonos_stack_tag();