forked from espressif/esp-idf
Compare commits
51 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb56d86fde | ||
|
|
db2223818b | ||
|
|
099ae5a1d9 | ||
|
|
9b4e911359 | ||
|
|
00fec53d76 | ||
|
|
ba5f0585af | ||
|
|
bcaac485d3 | ||
|
|
5ce10cb58c | ||
|
|
cba7efc9d2 | ||
|
|
364c0c4ace | ||
|
|
be02f6b423 | ||
|
|
4522476e72 | ||
|
|
6313ea0088 | ||
|
|
735f02c4b7 | ||
|
|
d6df10edaf | ||
|
|
d02d2d5170 | ||
|
|
80c013ee5a | ||
|
|
f2347e5729 | ||
|
|
8cfb0b207a | ||
|
|
6d253b4394 | ||
|
|
50dc31103f | ||
|
|
3af5384a24 | ||
|
|
283c47cbba | ||
|
|
4ae01aed27 | ||
|
|
a5a692ef8c | ||
|
|
3c532e4532 | ||
|
|
2e8d7fa36d | ||
|
|
674cf7520e | ||
|
|
c990ca4e20 | ||
|
|
5b061a0530 | ||
|
|
43d2f940b2 | ||
|
|
a5533a0b5d | ||
|
|
5f56d65405 | ||
|
|
fcf9c3d882 | ||
|
|
a7ad8bc873 | ||
|
|
438c9bcb35 | ||
|
|
328e689cf1 | ||
|
|
13732c5753 | ||
|
|
2544d737c5 | ||
|
|
8bd10b4808 | ||
|
|
a975ba6cef | ||
|
|
9189e1006d | ||
|
|
bc8a84e9e4 | ||
|
|
efe499113c | ||
|
|
7331ee2af2 | ||
|
|
f323fe5fee | ||
|
|
291c4a4fd3 | ||
|
|
9b1bd0a09f | ||
|
|
0ba566e0c6 | ||
|
|
7d2baa3c3d | ||
|
|
530dedbc2d |
@@ -34,6 +34,7 @@ variables:
|
||||
python $APPLY_BOT_FILTER_SCRIPT || exit 0
|
||||
|
||||
before_script:
|
||||
- source tools/ci/setup_python.sh
|
||||
# apply bot filter in before script
|
||||
- *apply_bot_filter
|
||||
# add gitlab ssh key
|
||||
@@ -54,6 +55,7 @@ before_script:
|
||||
|
||||
.do_nothing_before:
|
||||
before_script: &do_nothing_before
|
||||
- source tools/ci/setup_python.sh
|
||||
# apply bot filter in before script
|
||||
- *apply_bot_filter
|
||||
- echo "Not setting up GitLab key, not fetching submodules"
|
||||
@@ -61,6 +63,7 @@ before_script:
|
||||
|
||||
.add_gitlab_key_before:
|
||||
before_script: &add_gitlab_key_before
|
||||
- source tools/ci/setup_python.sh
|
||||
# apply bot filter in before script
|
||||
- *apply_bot_filter
|
||||
- echo "Not fetching submodules"
|
||||
@@ -291,9 +294,7 @@ push_to_github:
|
||||
- echo -e "Host github.com\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config
|
||||
- git remote remove github &>/dev/null || true
|
||||
- git remote add github git@github.com:espressif/esp-idf.git
|
||||
# Need separate push commands for tag builds and for branch builds
|
||||
- "[ -n \"${CI_COMMIT_TAG}\" ] && git push github ${CI_COMMIT_TAG}"
|
||||
- "[ -z \"${CI_COMMIT_TAG}\" ] && git push github ${CI_COMMIT_SHA}:refs/heads/${CI_COMMIT_REF_NAME}"
|
||||
- tools/ci/push_to_github.sh
|
||||
|
||||
deploy_docs:
|
||||
stage: host_test
|
||||
|
||||
@@ -27,6 +27,7 @@ SECTIONS
|
||||
.iram1.text :
|
||||
{
|
||||
. = ALIGN (16);
|
||||
_loader_text_start = ABSOLUTE(.);
|
||||
*(.entry.text)
|
||||
*(.init.literal)
|
||||
*(.init)
|
||||
@@ -126,6 +127,7 @@ SECTIONS
|
||||
*(.fini)
|
||||
*(.gnu.version)
|
||||
_text_end = ABSOLUTE(.);
|
||||
_loader_text_end = ABSOLUTE(.);
|
||||
_etext = .;
|
||||
} > iram_seg
|
||||
|
||||
|
||||
34
components/bootloader_support/include/bootloader_util.h
Normal file
34
components/bootloader_support/include/bootloader_util.h
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright 2018 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
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/**
|
||||
* @brief Check if half-open intervals overlap
|
||||
*
|
||||
* @param start1 interval 1 start
|
||||
* @param end1 interval 1 end
|
||||
* @param start2 interval 2 start
|
||||
* @param end2 interval 2 end
|
||||
* @return true iff [start1; end1) overlaps [start2; end2)
|
||||
*/
|
||||
static inline bool bootloader_util_regions_overlap(
|
||||
const intptr_t start1, const intptr_t end1,
|
||||
const intptr_t start2, const intptr_t end2)
|
||||
{
|
||||
return (end1 > start2 && end2 > start1) ||
|
||||
!(end1 <= start2 || end2 <= start1);
|
||||
}
|
||||
@@ -81,6 +81,8 @@ typedef struct {
|
||||
|
||||
_Static_assert(sizeof(esp_image_header_t) == 24, "binary image header should be 24 bytes");
|
||||
|
||||
#define ESP_IMAGE_HASH_LEN 32 /* Length of the appended SHA-256 digest */
|
||||
|
||||
/* Header of binary image segment */
|
||||
typedef struct {
|
||||
uint32_t load_addr;
|
||||
@@ -142,6 +144,16 @@ esp_err_t esp_image_load(esp_image_load_mode_t mode, const esp_partition_pos_t *
|
||||
*/
|
||||
esp_err_t esp_image_verify_bootloader(uint32_t *length);
|
||||
|
||||
/**
|
||||
* @brief Verify the bootloader image.
|
||||
*
|
||||
* @param[out] Metadata for the image. Only valid if result is ESP_OK.
|
||||
*
|
||||
* @return As per esp_image_load_metadata().
|
||||
*/
|
||||
esp_err_t esp_image_verify_bootloader_data(esp_image_metadata_t *data);
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t drom_addr;
|
||||
uint32_t drom_load_addr;
|
||||
|
||||
@@ -23,10 +23,11 @@
|
||||
#include <bootloader_flash.h>
|
||||
#include <bootloader_random.h>
|
||||
#include <bootloader_sha.h>
|
||||
#include "bootloader_util.h"
|
||||
|
||||
static const char *TAG = "esp_image";
|
||||
|
||||
#define HASH_LEN 32 /* SHA-256 digest length */
|
||||
#define HASH_LEN ESP_IMAGE_HASH_LEN
|
||||
|
||||
#define SIXTEEN_MB 0x1000000
|
||||
#define ESP_ROM_CHECKSUM_INITIAL 0xEF
|
||||
@@ -42,6 +43,10 @@ static const char *TAG = "esp_image";
|
||||
(Means loaded code isn't executable until after the secure boot check.)
|
||||
*/
|
||||
static uint32_t ram_obfs_value[2];
|
||||
|
||||
/* Range of IRAM used by the loader, defined in ld script */
|
||||
extern int _loader_text_start;
|
||||
extern int _loader_text_end;
|
||||
#endif
|
||||
|
||||
/* Return true if load_addr is an address the bootloader should load into */
|
||||
@@ -286,18 +291,41 @@ static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segme
|
||||
(do_load)?"load":(is_mapping)?"map":"");
|
||||
}
|
||||
|
||||
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
/* Before loading segment, check it doesn't clobber bootloader RAM. */
|
||||
if (do_load) {
|
||||
/* Before loading segment, check it doesn't clobber bootloader RAM... */
|
||||
uint32_t end_addr = load_addr + data_len;
|
||||
if (end_addr < 0x40000000) {
|
||||
const intptr_t load_end = load_addr + data_len;
|
||||
if (load_end <= (intptr_t) SOC_DIRAM_DRAM_HIGH) {
|
||||
/* Writing to DRAM */
|
||||
intptr_t sp = (intptr_t)get_sp();
|
||||
if (end_addr > sp - STACK_LOAD_HEADROOM) {
|
||||
ESP_LOGE(TAG, "Segment %d end address 0x%08x too high (bootloader stack 0x%08x liimit 0x%08x)",
|
||||
index, end_addr, sp, sp - STACK_LOAD_HEADROOM);
|
||||
if (load_end > sp - STACK_LOAD_HEADROOM) {
|
||||
/* Bootloader .data/.rodata/.bss is above the stack, so this
|
||||
* also checks that we aren't overwriting these segments.
|
||||
*
|
||||
* TODO: This assumes specific arrangement of sections we have
|
||||
* in the ESP32. Rewrite this in a generic way to support other
|
||||
* layouts.
|
||||
*/
|
||||
ESP_LOGE(TAG, "Segment %d end address 0x%08x too high (bootloader stack 0x%08x limit 0x%08x)",
|
||||
index, load_end, sp, sp - STACK_LOAD_HEADROOM);
|
||||
return ESP_ERR_IMAGE_INVALID;
|
||||
}
|
||||
} else {
|
||||
/* Writing to IRAM */
|
||||
const intptr_t loader_iram_start = (intptr_t) &_loader_text_start;
|
||||
const intptr_t loader_iram_end = (intptr_t) &_loader_text_end;
|
||||
|
||||
if (bootloader_util_regions_overlap(loader_iram_start, loader_iram_end,
|
||||
load_addr, load_end)) {
|
||||
ESP_LOGE(TAG, "Segment %d (0x%08x-0x%08x) overlaps bootloader IRAM (0x%08x-0x%08x)",
|
||||
index, load_addr, load_end, loader_iram_start, loader_iram_end);
|
||||
return ESP_ERR_IMAGE_INVALID;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // BOOTLOADER_BUILD
|
||||
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
uint32_t free_page_count = spi_flash_mmap_get_free_pages(SPI_FLASH_MMAP_DATA);
|
||||
ESP_LOGD(TAG, "free data page_count 0x%08x",free_page_count);
|
||||
@@ -441,19 +469,28 @@ static bool should_load(uint32_t load_addr)
|
||||
esp_err_t esp_image_verify_bootloader(uint32_t *length)
|
||||
{
|
||||
esp_image_metadata_t data;
|
||||
const esp_partition_pos_t bootloader_part = {
|
||||
.offset = ESP_BOOTLOADER_OFFSET,
|
||||
.size = ESP_PARTITION_TABLE_OFFSET - ESP_BOOTLOADER_OFFSET,
|
||||
};
|
||||
esp_err_t err = esp_image_load(ESP_IMAGE_VERIFY,
|
||||
&bootloader_part,
|
||||
&data);
|
||||
esp_err_t err = esp_image_verify_bootloader_data(&data);
|
||||
if (length != NULL) {
|
||||
*length = (err == ESP_OK) ? data.image_len : 0;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t esp_image_verify_bootloader_data(esp_image_metadata_t *data)
|
||||
{
|
||||
if (data == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
const esp_partition_pos_t bootloader_part = {
|
||||
.offset = ESP_BOOTLOADER_OFFSET,
|
||||
.size = ESP_PARTITION_TABLE_OFFSET - ESP_BOOTLOADER_OFFSET,
|
||||
};
|
||||
return esp_image_load(ESP_IMAGE_VERIFY,
|
||||
&bootloader_part,
|
||||
data);
|
||||
}
|
||||
|
||||
|
||||
static esp_err_t verify_checksum(bootloader_sha256_handle_t sha_handle, uint32_t checksum_word, esp_image_metadata_t *data)
|
||||
{
|
||||
uint32_t unpadded_length = data->image_len;
|
||||
|
||||
@@ -62,6 +62,11 @@ esp_err_t esp_flash_encrypt_check_and_update(void)
|
||||
|
||||
static esp_err_t initialise_flash_encryption(void)
|
||||
{
|
||||
if (REG_READ(EFUSE_BLK0_RDATA6_REG) & EFUSE_CODING_SCHEME_M) {
|
||||
ESP_LOGE(TAG, "Flash Encryption is currently not supported on hardware with 3/4 Coding Scheme (CODING_SCHEME efuse set)");
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/* Before first flash encryption pass, need to initialise key & crypto config */
|
||||
|
||||
/* Generate key */
|
||||
|
||||
@@ -50,7 +50,7 @@ static bool secure_boot_generate(uint32_t image_len){
|
||||
const uint32_t *image;
|
||||
|
||||
/* hardware secure boot engine only takes full blocks, so round up the
|
||||
image length. The additional data should all be 0xFF.
|
||||
image length. The additional data should all be 0xFF (or the appended SHA, if it falls in the same block).
|
||||
*/
|
||||
if (image_len % sizeof(digest.iv) != 0) {
|
||||
image_len = (image_len / sizeof(digest.iv) + 1) * sizeof(digest.iv);
|
||||
@@ -104,14 +104,20 @@ static inline void burn_efuses()
|
||||
|
||||
esp_err_t esp_secure_boot_permanently_enable(void) {
|
||||
esp_err_t err;
|
||||
uint32_t image_len = 0;
|
||||
if (esp_secure_boot_enabled())
|
||||
{
|
||||
ESP_LOGI(TAG, "bootloader secure boot is already enabled, continuing..");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
err = esp_image_verify_bootloader(&image_len);
|
||||
if (REG_READ(EFUSE_BLK0_RDATA6_REG) & EFUSE_CODING_SCHEME_M) {
|
||||
ESP_LOGE(TAG, "Secure Boot is currently not supported on hardware with 3/4 Coding Scheme (CODING_SCHEME efuse set)");
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/* Verify the bootloader */
|
||||
esp_image_metadata_t bootloader_data = { 0 };
|
||||
err = esp_image_verify_bootloader_data(&bootloader_data);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "bootloader image appears invalid! error %d", err);
|
||||
return err;
|
||||
@@ -150,6 +156,11 @@ esp_err_t esp_secure_boot_permanently_enable(void) {
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Generating secure boot digest...");
|
||||
uint32_t image_len = bootloader_data.image_len;
|
||||
if(bootloader_data.image.hash_appended) {
|
||||
/* Secure boot digest doesn't cover the hash */
|
||||
image_len -= ESP_IMAGE_HASH_LEN;
|
||||
}
|
||||
if (false == secure_boot_generate(image_len)){
|
||||
ESP_LOGE(TAG, "secure boot generation failed");
|
||||
return ESP_FAIL;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "unity.h"
|
||||
|
||||
#include "bootloader_util.h"
|
||||
#include "esp_partition.h"
|
||||
#include "esp_ota_ops.h"
|
||||
#include "esp_image_format.h"
|
||||
@@ -47,3 +48,21 @@ TEST_CASE("Verify unit test app image", "[bootloader_support]")
|
||||
TEST_ASSERT_TRUE(data.image_len <= running->size);
|
||||
}
|
||||
|
||||
TEST_CASE("Test regions_overlap", "[bootloader_support]")
|
||||
{
|
||||
TEST_ASSERT( bootloader_util_regions_overlap(1, 2, 1, 2) );
|
||||
|
||||
TEST_ASSERT( bootloader_util_regions_overlap(1, 2, 0, 2) );
|
||||
TEST_ASSERT( bootloader_util_regions_overlap(1, 2, 1, 3) );
|
||||
TEST_ASSERT( bootloader_util_regions_overlap(1, 2, 0, 3) );
|
||||
|
||||
TEST_ASSERT( bootloader_util_regions_overlap(0, 2, 1, 2) );
|
||||
TEST_ASSERT( bootloader_util_regions_overlap(1, 3, 1, 2) );
|
||||
TEST_ASSERT( bootloader_util_regions_overlap(0, 3, 1, 2) );
|
||||
|
||||
TEST_ASSERT( !bootloader_util_regions_overlap(2, 3, 1, 2) );
|
||||
TEST_ASSERT( !bootloader_util_regions_overlap(1, 2, 2, 3) );
|
||||
|
||||
TEST_ASSERT( !bootloader_util_regions_overlap(3, 4, 1, 2) );
|
||||
TEST_ASSERT( !bootloader_util_regions_overlap(1, 2, 3, 4) );
|
||||
}
|
||||
|
||||
@@ -65,6 +65,23 @@ static void btm_gen_resolve_paddr_cmpl(tSMP_ENC *p)
|
||||
p_cb->set_local_privacy_cback = NULL;
|
||||
}
|
||||
|
||||
if (btm_cb.ble_ctr_cb.inq_var.adv_mode == BTM_BLE_ADV_ENABLE){
|
||||
BTM_TRACE_DEBUG("Advertise with new resolvable private address, now.");
|
||||
/**
|
||||
* Restart advertising, using new resolvable private address
|
||||
*/
|
||||
btm_ble_stop_adv();
|
||||
btm_ble_start_adv();
|
||||
}
|
||||
if (btm_cb.ble_ctr_cb.inq_var.state == BTM_BLE_SCANNING){
|
||||
BTM_TRACE_DEBUG("Scan with new resolvable private address, now.");
|
||||
/**
|
||||
* Restart scaning, using new resolvable private address
|
||||
*/
|
||||
btm_ble_stop_scan();
|
||||
btm_ble_start_scan();
|
||||
}
|
||||
|
||||
/* start a periodical timer to refresh random addr */
|
||||
btu_stop_timer_oneshot(&p_cb->raddr_timer_ent);
|
||||
#if (BTM_BLE_CONFORMANCE_TESTING == TRUE)
|
||||
|
||||
@@ -170,16 +170,6 @@ tBTM_STATUS BTM_SetDiscoverability (UINT16 inq_mode, UINT16 window, UINT16 inter
|
||||
BOOLEAN cod_limited;
|
||||
|
||||
BTM_TRACE_API ("BTM_SetDiscoverability\n");
|
||||
#if (BLE_INCLUDED == TRUE && BLE_INCLUDED == TRUE)
|
||||
if (controller_get_interface()->supports_ble()) {
|
||||
if (btm_ble_set_discoverability((UINT16)(inq_mode))
|
||||
== BTM_SUCCESS) {
|
||||
btm_cb.btm_inq_vars.discoverable_mode &= (~BTM_BLE_DISCOVERABLE_MASK);
|
||||
btm_cb.btm_inq_vars.discoverable_mode |= (inq_mode & BTM_BLE_DISCOVERABLE_MASK);
|
||||
}
|
||||
}
|
||||
inq_mode &= ~BTM_BLE_DISCOVERABLE_MASK;
|
||||
#endif
|
||||
|
||||
/*** Check mode parameter ***/
|
||||
if (inq_mode > BTM_MAX_DISCOVERABLE) {
|
||||
@@ -601,17 +591,6 @@ tBTM_STATUS BTM_SetConnectability (UINT16 page_mode, UINT16 window, UINT16 inter
|
||||
|
||||
BTM_TRACE_API ("BTM_SetConnectability\n");
|
||||
|
||||
#if (BLE_INCLUDED == TRUE && BLE_INCLUDED == TRUE)
|
||||
if (controller_get_interface()->supports_ble()) {
|
||||
if (btm_ble_set_connectability(page_mode) != BTM_SUCCESS) {
|
||||
return BTM_NO_RESOURCES;
|
||||
}
|
||||
p_inq->connectable_mode &= (~BTM_BLE_CONNECTABLE_MASK);
|
||||
p_inq->connectable_mode |= (page_mode & BTM_BLE_CONNECTABLE_MASK);
|
||||
}
|
||||
page_mode &= ~BTM_BLE_CONNECTABLE_MASK;
|
||||
#endif
|
||||
|
||||
/*** Check mode parameter ***/
|
||||
if (page_mode != BTM_NON_CONNECTABLE && page_mode != BTM_CONNECTABLE) {
|
||||
return (BTM_ILLEGAL_VALUE);
|
||||
|
||||
@@ -354,15 +354,17 @@ static void sdp_copy_raw_data (tCONN_CB *p_ccb, BOOLEAN offset)
|
||||
type = *p++;
|
||||
p = sdpu_get_len_from_type (p, type, &list_len);
|
||||
}
|
||||
if (list_len && list_len < cpy_len ) {
|
||||
if (list_len < cpy_len ) {
|
||||
cpy_len = list_len;
|
||||
}
|
||||
#if (SDP_DEBUG_RAW == TRUE)
|
||||
SDP_TRACE_WARNING("list_len :%d cpy_len:%d raw_size:%d raw_used:%d\n",
|
||||
SDP_TRACE_DEBUG("list_len :%d cpy_len:%d raw_size:%d raw_used:%d\n",
|
||||
list_len, cpy_len, p_ccb->p_db->raw_size, p_ccb->p_db->raw_used);
|
||||
#endif
|
||||
memcpy (&p_ccb->p_db->raw_data[p_ccb->p_db->raw_used], p, cpy_len);
|
||||
p_ccb->p_db->raw_used += cpy_len;
|
||||
if (cpy_len != 0){
|
||||
memcpy (&p_ccb->p_db->raw_data[p_ccb->p_db->raw_used], p, cpy_len);
|
||||
p_ccb->p_db->raw_used += cpy_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -131,7 +131,7 @@ typedef enum {
|
||||
* ESP_BLE_PWR_TYPE_SCAN : for scan.
|
||||
* ESP_BLE_PWR_TYPE_DEFAULT : if each connection's TX power is not set, it will use this default value.
|
||||
* if neither in scan mode nor in adv mode, it will use this default value.
|
||||
* If none of power type is set, system will use ESP_PWR_LVL_P1 as default for ADV/SCAN/CONN0-9.
|
||||
* If none of power type is set, system will use ESP_PWR_LVL_P3 as default for ADV/SCAN/CONN0-9.
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_BLE_PWR_TYPE_CONN_HDL0 = 0, /*!< For connection handle 0 */
|
||||
@@ -153,14 +153,22 @@ typedef enum {
|
||||
* @brief Bluetooth TX power level(index), it's just a index corresponding to power(dbm).
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_PWR_LVL_N14 = 0, /*!< Corresponding to -14dbm */
|
||||
ESP_PWR_LVL_N11 = 1, /*!< Corresponding to -11dbm */
|
||||
ESP_PWR_LVL_N8 = 2, /*!< Corresponding to -8dbm */
|
||||
ESP_PWR_LVL_N5 = 3, /*!< Corresponding to -5dbm */
|
||||
ESP_PWR_LVL_N2 = 4, /*!< Corresponding to -2dbm */
|
||||
ESP_PWR_LVL_P1 = 5, /*!< Corresponding to 1dbm */
|
||||
ESP_PWR_LVL_P4 = 6, /*!< Corresponding to 4dbm */
|
||||
ESP_PWR_LVL_P7 = 7, /*!< Corresponding to 7dbm */
|
||||
ESP_PWR_LVL_N12 = 0, /*!< Corresponding to -12dbm */
|
||||
ESP_PWR_LVL_N9 = 1, /*!< Corresponding to -9dbm */
|
||||
ESP_PWR_LVL_N6 = 2, /*!< Corresponding to -6dbm */
|
||||
ESP_PWR_LVL_N3 = 3, /*!< Corresponding to -3dbm */
|
||||
ESP_PWR_LVL_N0 = 4, /*!< Corresponding to 0dbm */
|
||||
ESP_PWR_LVL_P3 = 5, /*!< Corresponding to +3dbm */
|
||||
ESP_PWR_LVL_P6 = 6, /*!< Corresponding to +6dbm */
|
||||
ESP_PWR_LVL_P9 = 7, /*!< Corresponding to +9dbm */
|
||||
ESP_PWR_LVL_N14 = ESP_PWR_LVL_N12, /*!< Backward compatibility! Setting to -14dbm will actually result to -12dbm */
|
||||
ESP_PWR_LVL_N11 = ESP_PWR_LVL_N9, /*!< Backward compatibility! Setting to -11dbm will actually result to -9dbm */
|
||||
ESP_PWR_LVL_N8 = ESP_PWR_LVL_N6, /*!< Backward compatibility! Setting to -8dbm will actually result to -6dbm */
|
||||
ESP_PWR_LVL_N5 = ESP_PWR_LVL_N3, /*!< Backward compatibility! Setting to -5dbm will actually result to -3dbm */
|
||||
ESP_PWR_LVL_N2 = ESP_PWR_LVL_N0, /*!< Backward compatibility! Setting to -2dbm will actually result to 0dbm */
|
||||
ESP_PWR_LVL_P1 = ESP_PWR_LVL_P3, /*!< Backward compatibility! Setting to +1dbm will actually result to +3dbm */
|
||||
ESP_PWR_LVL_P4 = ESP_PWR_LVL_P6, /*!< Backward compatibility! Setting to +4dbm will actually result to +6dbm */
|
||||
ESP_PWR_LVL_P7 = ESP_PWR_LVL_P9, /*!< Backward compatibility! Setting to +7dbm will actually result to +9dbm */
|
||||
} esp_power_level_t;
|
||||
|
||||
/**
|
||||
@@ -180,7 +188,6 @@ esp_err_t esp_ble_tx_power_set(esp_ble_power_type_t power_type, esp_power_level_
|
||||
*/
|
||||
esp_power_level_t esp_ble_tx_power_get(esp_ble_power_type_t power_type);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Initialize BT controller to allocate task and other resource.
|
||||
* @param cfg: Initial configuration of BT controller.
|
||||
|
||||
Submodule components/bt/lib updated: 96e7e06e0b...979dd2c742
@@ -46,7 +46,7 @@ typedef enum {
|
||||
* @brief This is a configuration structure for a SPI bus.
|
||||
*
|
||||
* You can use this structure to specify the GPIO pins of the bus. Normally, the driver will use the
|
||||
* GPIO matrix to route the signals. An exception is made when all signals either can be routed through
|
||||
* GPIO matrix to route the signals. An exception is made when all signals either can be routed through
|
||||
* the IO_MUX or are -1. In that case, the IO_MUX is used, allowing for >40MHz speeds.
|
||||
*
|
||||
* @note Be advised that the slave driver does not use the quadwp/quadhd lines and fields in spi_bus_config_t refering to these lines will be ignored and can thus safely be left uninitialized.
|
||||
@@ -81,20 +81,20 @@ bool spicommon_periph_free(spi_host_device_t host);
|
||||
|
||||
/**
|
||||
* @brief Try to claim a SPI DMA channel
|
||||
*
|
||||
*
|
||||
* Call this if your driver wants to use SPI with a DMA channnel.
|
||||
*
|
||||
*
|
||||
* @param dma_chan channel to claim
|
||||
*
|
||||
*
|
||||
* @return True if success; false otherwise.
|
||||
*/
|
||||
bool spicommon_dma_chan_claim(int dma_chan);
|
||||
|
||||
/**
|
||||
* @brief Return the SPI DMA channel so other driver can claim it, or just to power down DMA.
|
||||
*
|
||||
*
|
||||
* @param dma_chan channel to return
|
||||
*
|
||||
*
|
||||
* @return True if success; false otherwise.
|
||||
*/
|
||||
bool spicommon_dma_chan_free(int dma_chan);
|
||||
@@ -107,7 +107,7 @@ bool spicommon_dma_chan_free(int dma_chan);
|
||||
* @brief Connect a SPI peripheral to GPIO pins
|
||||
*
|
||||
* This routine is used to connect a SPI peripheral to the IO-pads and DMA channel given in
|
||||
* the arguments. Depending on the IO-pads requested, the routing is done either using the
|
||||
* the arguments. Depending on the IO-pads requested, the routing is done either using the
|
||||
* IO_mux or using the GPIO matrix.
|
||||
*
|
||||
* @param host SPI peripheral to be routed
|
||||
@@ -116,7 +116,7 @@ bool spicommon_dma_chan_free(int dma_chan);
|
||||
* @param flags Combination of SPICOMMON_BUSFLAG_* flags
|
||||
* @param[out] is_native A value of 'true' will be written to this address if the GPIOs can be
|
||||
* routed using the IO_mux, 'false' if the GPIO matrix is used.
|
||||
* @return
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG if parameter is invalid
|
||||
* - ESP_OK on success
|
||||
*/
|
||||
@@ -126,7 +126,7 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
|
||||
* @brief Free the IO used by a SPI peripheral
|
||||
*
|
||||
* @param host SPI peripheral to be freed
|
||||
* @return
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG if parameter is invalid
|
||||
* - ESP_OK on success
|
||||
*/
|
||||
@@ -180,6 +180,26 @@ void spicommon_setup_dma_desc_links(lldesc_t *dmadesc, int len, const uint8_t *d
|
||||
*/
|
||||
spi_dev_t *spicommon_hw_for_host(spi_host_device_t host);
|
||||
|
||||
|
||||
/** Temporarily connect CS signal input to high to avoid slave detecting unexpected transactions.
|
||||
*
|
||||
* @note Don't use this in the application.
|
||||
*
|
||||
* @param host The spi host.
|
||||
*/
|
||||
void spicommon_freeze_cs(spi_host_device_t host);
|
||||
|
||||
/** Use this function instead of cs_initial to avoid overwrite the output config
|
||||
* This is used in test by internal gpio matrix connections
|
||||
*
|
||||
* @note Don't use this in the application.
|
||||
*
|
||||
* @param host The spi host.
|
||||
* @param cs_io_num GPIO number of the CS pin.
|
||||
* @param iomux The peripheral is using iomux pins.
|
||||
*/
|
||||
void spicommon_restore_cs(spi_host_device_t host, int cs_io_num, bool iomux);
|
||||
|
||||
/**
|
||||
* @brief Get the IRQ source for a specific SPI host
|
||||
*
|
||||
@@ -201,10 +221,10 @@ typedef void(*dmaworkaround_cb_t)(void *arg);
|
||||
* @note In some (well-defined) cases in the ESP32 (at least rev v.0 and v.1), a SPI DMA channel will get confused. This can be remedied
|
||||
* by resetting the SPI DMA hardware in case this happens. Unfortunately, the reset knob used for thsi will reset _both_ DMA channels, and
|
||||
* as such can only done safely when both DMA channels are idle. These functions coordinate this.
|
||||
*
|
||||
*
|
||||
* Essentially, when a reset is needed, a driver can request this using spicommon_dmaworkaround_req_reset. This is supposed to be called
|
||||
* with an user-supplied function as an argument. If both DMA channels are idle, this call will reset the DMA subsystem and return true.
|
||||
* If the other DMA channel is still busy, it will return false; as soon as the other DMA channel is done, however, it will reset the
|
||||
* with an user-supplied function as an argument. If both DMA channels are idle, this call will reset the DMA subsystem and return true.
|
||||
* If the other DMA channel is still busy, it will return false; as soon as the other DMA channel is done, however, it will reset the
|
||||
* DMA subsystem and call the callback. The callback is then supposed to be used to continue the SPI drivers activity.
|
||||
*
|
||||
* @param dmachan DMA channel associated with the SPI host that needs a reset
|
||||
|
||||
@@ -329,6 +329,7 @@ void spicommon_cs_initialize(spi_host_device_t host, int cs_io_num, int cs_num,
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[cs_io_num], 1);
|
||||
} else {
|
||||
//Use GPIO matrix
|
||||
gpio_set_direction(cs_io_num, GPIO_MODE_INPUT_OUTPUT);
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[cs_io_num], PIN_FUNC_GPIO);
|
||||
gpio_matrix_out(cs_io_num, io_signal[host].spics_out[cs_num], false, false);
|
||||
if (cs_num == 0) gpio_matrix_in(cs_io_num, io_signal[host].spics_in, false);
|
||||
@@ -371,6 +372,26 @@ void IRAM_ATTR spicommon_setup_dma_desc_links(lldesc_t *dmadesc, int len, const
|
||||
dmadesc[n - 1].qe.stqe_next = NULL;
|
||||
}
|
||||
|
||||
void spicommon_freeze_cs(spi_host_device_t host)
|
||||
{
|
||||
gpio_matrix_in(0x38, io_signal[host].spics_in, false);
|
||||
}
|
||||
|
||||
static void IOMUX_IN(uint32_t gpio, uint32_t signal_idx)
|
||||
{
|
||||
GPIO.func_in_sel_cfg[signal_idx].sig_in_sel = 0;
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[gpio]);
|
||||
}
|
||||
|
||||
void spicommon_restore_cs(spi_host_device_t host, int cs_io_num, bool iomux)
|
||||
{
|
||||
if (iomux) {
|
||||
IOMUX_IN(cs_io_num, io_signal[host].spics_in);
|
||||
} else {
|
||||
gpio_matrix_in(cs_io_num, io_signal[host].spics_in, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Code for workaround for DMA issue in ESP32 v0/v1 silicon
|
||||
|
||||
@@ -21,13 +21,13 @@ is a combination of SPI port and CS pin, plus some information about the specifi
|
||||
|
||||
The essence of the interface to a device is a set of queues; one per device. The idea is that to send something to a SPI
|
||||
device, you allocate a transaction descriptor. It contains some information about the transfer like the lenghth, address,
|
||||
command etc, plus pointers to transmit and receive buffer. The address of this block gets pushed into the transmit queue.
|
||||
The SPI driver does its magic, and sends and retrieves the data eventually. The data gets written to the receive buffers,
|
||||
command etc, plus pointers to transmit and receive buffer. The address of this block gets pushed into the transmit queue.
|
||||
The SPI driver does its magic, and sends and retrieves the data eventually. The data gets written to the receive buffers,
|
||||
if needed the transaction descriptor is modified to indicate returned parameters and the entire thing goes into the return
|
||||
queue, where whatever software initiated the transaction can retrieve it.
|
||||
|
||||
The entire thing is run from the SPI interrupt handler. If SPI is done transmitting/receiving but nothing is in the queue,
|
||||
it will not clear the SPI interrupt but just disable it. This way, when a new thing is sent, pushing the packet into the send
|
||||
The entire thing is run from the SPI interrupt handler. If SPI is done transmitting/receiving but nothing is in the queue,
|
||||
it will not clear the SPI interrupt but just disable it. This way, when a new thing is sent, pushing the packet into the send
|
||||
queue and re-enabling the interrupt will trigger the interrupt again, which can then take care of the sending.
|
||||
*/
|
||||
|
||||
@@ -67,8 +67,8 @@ typedef struct spi_device_t spi_device_t;
|
||||
|
||||
|
||||
/// struct to hold private transaction data (like tx and rx buffer for DMA).
|
||||
typedef struct {
|
||||
spi_transaction_t *trans;
|
||||
typedef struct {
|
||||
spi_transaction_t *trans;
|
||||
uint32_t *buffer_to_send; //equals to tx_data, if SPI_TRANS_USE_RXDATA is applied; otherwise if original buffer wasn't in DMA-capable memory, this gets the address of a temporary buffer that is;
|
||||
//otherwise sets to the original buffer or NULL if no buffer is assigned.
|
||||
uint32_t *buffer_to_rcv; // similar to buffer_to_send
|
||||
@@ -140,10 +140,10 @@ esp_err_t spi_bus_initialize(spi_host_device_t host, const spi_bus_config_t *bus
|
||||
goto nomem;
|
||||
}
|
||||
#endif //CONFIG_PM_ENABLE
|
||||
|
||||
|
||||
spicommon_bus_initialize_io(host, bus_config, dma_chan, SPICOMMON_BUSFLAG_MASTER|SPICOMMON_BUSFLAG_QUAD, &native);
|
||||
spihost[host]->no_gpio_matrix=native;
|
||||
|
||||
|
||||
spihost[host]->dma_chan=dma_chan;
|
||||
if (dma_chan == 0) {
|
||||
spihost[host]->max_transfer_sz = 32;
|
||||
@@ -180,7 +180,7 @@ esp_err_t spi_bus_initialize(spi_host_device_t host, const spi_bus_config_t *bus
|
||||
spihost[host]->hw->slave.wr_sta_inten=0;
|
||||
|
||||
//Force a transaction done interrupt. This interrupt won't fire yet because we initialized the SPI interrupt as
|
||||
//disabled. This way, we can just enable the SPI interrupt and the interrupt handler will kick in, handling
|
||||
//disabled. This way, we can just enable the SPI interrupt and the interrupt handler will kick in, handling
|
||||
//any transactions that are queued.
|
||||
spihost[host]->hw->slave.trans_inten=1;
|
||||
spihost[host]->hw->slave.trans_done=1;
|
||||
@@ -271,7 +271,6 @@ esp_err_t spi_bus_add_device(spi_host_device_t host, spi_device_interface_config
|
||||
|
||||
//Set CS pin, CS options
|
||||
if (dev_config->spics_io_num >= 0) {
|
||||
gpio_set_direction(dev_config->spics_io_num, GPIO_MODE_OUTPUT);
|
||||
spicommon_cs_initialize(host, dev_config->spics_io_num, freecs, spihost[host]->no_gpio_matrix == false);
|
||||
}
|
||||
if (dev_config->flags&SPI_DEVICE_CLK_AS_CS) {
|
||||
@@ -397,7 +396,7 @@ static void IRAM_ATTR spi_intr(void *arg)
|
||||
/*------------ deal with the in-flight transaction -----------------*/
|
||||
if (host->cur_cs != NO_CS) {
|
||||
spi_transaction_t *cur_trans = host->cur_trans_buf.trans;
|
||||
//Okay, transaction is done.
|
||||
//Okay, transaction is done.
|
||||
if (host->cur_trans_buf.buffer_to_rcv && host->dma_chan == 0 ) {
|
||||
//Need to copy from SPI regs to result buffer.
|
||||
for (int x=0; x < cur_trans->rxlength; x+=32) {
|
||||
@@ -411,7 +410,7 @@ static void IRAM_ATTR spi_intr(void *arg)
|
||||
//Call post-transaction callback, if any
|
||||
if (host->device[host->cur_cs]->cfg.post_cb) host->device[host->cur_cs]->cfg.post_cb(cur_trans);
|
||||
//Return transaction descriptor.
|
||||
xQueueSendFromISR(host->device[host->cur_cs]->ret_queue, &host->cur_trans_buf, &do_yield);
|
||||
xQueueSendFromISR(host->device[host->cur_cs]->ret_queue, &host->cur_trans_buf, &do_yield);
|
||||
prevCs=host->cur_cs;
|
||||
host->cur_cs = NO_CS;
|
||||
}
|
||||
@@ -443,7 +442,7 @@ static void IRAM_ATTR spi_intr(void *arg)
|
||||
host->cur_cs=i;
|
||||
//We should be done with the transmission.
|
||||
assert(host->hw->cmd.usr == 0);
|
||||
|
||||
|
||||
//Reconfigure according to device settings, but only if we change CSses.
|
||||
if (i!=prevCs) {
|
||||
//Assumes a hardcoded 80MHz Fapb for now. ToDo: figure out something better once we have
|
||||
@@ -453,7 +452,7 @@ static void IRAM_ATTR spi_intr(void *arg)
|
||||
//Configure bit order
|
||||
host->hw->ctrl.rd_bit_order=(dev->cfg.flags & SPI_DEVICE_RXBIT_LSBFIRST)?1:0;
|
||||
host->hw->ctrl.wr_bit_order=(dev->cfg.flags & SPI_DEVICE_TXBIT_LSBFIRST)?1:0;
|
||||
|
||||
|
||||
//Configure polarity
|
||||
//SPI iface needs to be configured for a delay in some cases.
|
||||
int nodelay=0;
|
||||
@@ -548,7 +547,7 @@ static void IRAM_ATTR spi_intr(void *arg)
|
||||
host->hw->dma_in_link.start=1;
|
||||
}
|
||||
} else {
|
||||
//DMA temporary workaround: let RX DMA work somehow to avoid the issue in ESP32 v0/v1 silicon
|
||||
//DMA temporary workaround: let RX DMA work somehow to avoid the issue in ESP32 v0/v1 silicon
|
||||
if (host->dma_chan != 0 ) {
|
||||
host->hw->dma_in_link.addr=0;
|
||||
host->hw->dma_in_link.start=1;
|
||||
@@ -601,17 +600,38 @@ static void IRAM_ATTR spi_intr(void *arg)
|
||||
host->hw->user.usr_addr=addrlen?1:0;
|
||||
host->hw->user.usr_command=cmdlen?1:0;
|
||||
|
||||
// output command will be sent from bit 7 to 0 of command_value, and then bit 15 to 8 of the same register field.
|
||||
if ((dev->cfg.flags & SPI_DEVICE_TXBIT_LSBFIRST)==0) {
|
||||
/* Output command will be sent from bit 7 to 0 of command_value, and
|
||||
* then bit 15 to 8 of the same register field. Shift and swap to send
|
||||
* more straightly.
|
||||
*/
|
||||
uint16_t command = trans->cmd << (16-cmdlen); //shift to MSB
|
||||
host->hw->user2.usr_command_value = (command>>8)|(command<<8); //swap the first and second byte
|
||||
// shift the address to MSB of addr (and maybe slv_wr_status) register.
|
||||
// output address will be sent from MSB to LSB of addr register, then comes the MSB to LSB of slv_wr_status register.
|
||||
if (addrlen>32) {
|
||||
host->hw->addr = trans->addr >> (addrlen- 32);
|
||||
|
||||
// shift the address to MSB of addr (and maybe slv_wr_status) register.
|
||||
// output address will be sent from MSB to LSB of addr register, then comes the MSB to LSB of slv_wr_status register.
|
||||
if (addrlen > 32) {
|
||||
host->hw->addr = trans->addr >> (addrlen - 32);
|
||||
host->hw->slv_wr_status = trans->addr << (64 - addrlen);
|
||||
} else {
|
||||
host->hw->addr = trans->addr << (32 - addrlen);
|
||||
}
|
||||
} else {
|
||||
/* The output command start from bit0 to bit 15, kept as is.
|
||||
* The output address start from the LSB of the highest byte, i.e.
|
||||
* addr[24] -> addr[31]
|
||||
* ...
|
||||
* addr[0] -> addr[7]
|
||||
* slv_wr_status[24] -> slv_wr_status[31]
|
||||
* ...
|
||||
* slv_wr_status[0] -> slv_wr_status[7]
|
||||
* So swap the byte order to let the LSB sent first.
|
||||
*/
|
||||
host->hw->user2.usr_command_value = trans->cmd;
|
||||
uint64_t addr = __builtin_bswap64(trans->addr);
|
||||
host->hw->addr = addr>>32;
|
||||
host->hw->slv_wr_status = addr;
|
||||
}
|
||||
|
||||
host->hw->user.usr_mosi=( (!(dev->cfg.flags & SPI_DEVICE_HALFDUPLEX) && trans_buf->buffer_to_rcv) || trans_buf->buffer_to_send)?1:0;
|
||||
host->hw->user.usr_miso=(trans_buf->buffer_to_rcv)?1:0;
|
||||
@@ -630,13 +650,13 @@ esp_err_t spi_device_queue_trans(spi_device_handle_t handle, spi_transaction_t *
|
||||
esp_err_t ret = ESP_OK;
|
||||
BaseType_t r;
|
||||
SPI_CHECK(handle!=NULL, "invalid dev handle", ESP_ERR_INVALID_ARG);
|
||||
//check transmission length
|
||||
//check transmission length
|
||||
SPI_CHECK((trans_desc->flags & SPI_TRANS_USE_RXDATA)==0 ||trans_desc->rxlength <= 32, "rxdata transfer > 32 bits without configured DMA", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK((trans_desc->flags & SPI_TRANS_USE_TXDATA)==0 ||trans_desc->length <= 32, "txdata transfer > 32 bits without configured DMA", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK(trans_desc->length <= handle->host->max_transfer_sz*8, "txdata transfer > host maximum", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK(trans_desc->rxlength <= handle->host->max_transfer_sz*8, "rxdata transfer > host maximum", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK((handle->cfg.flags & SPI_DEVICE_HALFDUPLEX) || trans_desc->rxlength <= trans_desc->length, "rx length > tx length in full duplex mode", ESP_ERR_INVALID_ARG);
|
||||
//check working mode
|
||||
//check working mode
|
||||
SPI_CHECK(!((trans_desc->flags & (SPI_TRANS_MODE_DIO|SPI_TRANS_MODE_QIO)) && (handle->cfg.flags & SPI_DEVICE_3WIRE)), "incompatible iface params", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK(!((trans_desc->flags & (SPI_TRANS_MODE_DIO|SPI_TRANS_MODE_QIO)) && (!(handle->cfg.flags & SPI_DEVICE_HALFDUPLEX))), "incompatible iface params", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK( !(handle->cfg.flags & SPI_DEVICE_HALFDUPLEX) || handle->host->dma_chan == 0 || !(trans_desc->flags & SPI_TRANS_USE_RXDATA || trans_desc->rx_buffer != NULL)
|
||||
@@ -655,7 +675,7 @@ esp_err_t spi_device_queue_trans(spi_device_handle_t handle, spi_transaction_t *
|
||||
// rx memory assign
|
||||
if ( trans_desc->flags & SPI_TRANS_USE_RXDATA ) {
|
||||
trans_buf.buffer_to_rcv = (uint32_t*)&trans_desc->rx_data[0];
|
||||
} else {
|
||||
} else {
|
||||
//if not use RXDATA neither rx_buffer, buffer_to_rcv assigned to NULL
|
||||
trans_buf.buffer_to_rcv = trans_desc->rx_buffer;
|
||||
}
|
||||
@@ -668,12 +688,12 @@ esp_err_t spi_device_queue_trans(spi_device_handle_t handle, spi_transaction_t *
|
||||
goto clean_up;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const uint32_t *txdata;
|
||||
// tx memory assign
|
||||
if ( trans_desc->flags & SPI_TRANS_USE_TXDATA ) {
|
||||
txdata = (uint32_t*)&trans_desc->tx_data[0];
|
||||
} else {
|
||||
} else {
|
||||
//if not use TXDATA neither tx_buffer, tx data assigned to NULL
|
||||
txdata = trans_desc->tx_buffer ;
|
||||
}
|
||||
@@ -686,11 +706,11 @@ esp_err_t spi_device_queue_trans(spi_device_handle_t handle, spi_transaction_t *
|
||||
goto clean_up;
|
||||
}
|
||||
memcpy( trans_buf.buffer_to_send, txdata, (trans_desc->length+7)/8 );
|
||||
} else {
|
||||
} else {
|
||||
// else use the original buffer (forced-conversion) or assign to NULL
|
||||
trans_buf.buffer_to_send = (uint32_t*)txdata;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_pm_lock_acquire(handle->host->pm_lock);
|
||||
#endif
|
||||
@@ -710,10 +730,10 @@ clean_up:
|
||||
// free malloc-ed buffer (if needed) before return.
|
||||
if ( (void*)trans_buf.buffer_to_rcv != trans_desc->rx_buffer && (void*)trans_buf.buffer_to_rcv != &trans_desc->rx_data[0] ) {
|
||||
free( trans_buf.buffer_to_rcv );
|
||||
}
|
||||
}
|
||||
if ( (void*)trans_buf.buffer_to_send!= trans_desc->tx_buffer && (void*)trans_buf.buffer_to_send != &trans_desc->tx_data[0] ) {
|
||||
free( trans_buf.buffer_to_send );
|
||||
}
|
||||
}
|
||||
assert( ret != ESP_OK );
|
||||
return ret;
|
||||
}
|
||||
@@ -722,12 +742,12 @@ esp_err_t spi_device_get_trans_result(spi_device_handle_t handle, spi_transactio
|
||||
{
|
||||
BaseType_t r;
|
||||
spi_trans_priv trans_buf;
|
||||
|
||||
|
||||
SPI_CHECK(handle!=NULL, "invalid dev handle", ESP_ERR_INVALID_ARG);
|
||||
r=xQueueReceive(handle->ret_queue, (void*)&trans_buf, ticks_to_wait);
|
||||
if (!r) {
|
||||
// The memory occupied by rx and tx DMA buffer destroyed only when receiving from the queue (transaction finished).
|
||||
// If timeout, wait and retry.
|
||||
// If timeout, wait and retry.
|
||||
// Every on-flight transaction request occupies internal memory as DMA buffer if needed.
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
@@ -736,12 +756,12 @@ esp_err_t spi_device_get_trans_result(spi_device_handle_t handle, spi_transactio
|
||||
|
||||
if ( (void*)trans_buf.buffer_to_send != &(*trans_desc)->tx_data[0] && trans_buf.buffer_to_send != (*trans_desc)->tx_buffer ) {
|
||||
free( trans_buf.buffer_to_send );
|
||||
}
|
||||
}
|
||||
|
||||
//copy data from temporary DMA-capable buffer back to IRAM buffer and free the temporary one.
|
||||
if ( (void*)trans_buf.buffer_to_rcv != &(*trans_desc)->rx_data[0] && trans_buf.buffer_to_rcv != (*trans_desc)->rx_buffer ) {
|
||||
if ( (*trans_desc)->flags & SPI_TRANS_USE_RXDATA ) {
|
||||
memcpy( (uint8_t*)&(*trans_desc)->rx_data[0], trans_buf.buffer_to_rcv, ((*trans_desc)->rxlength+7)/8 );
|
||||
memcpy( (uint8_t*)&(*trans_desc)->rx_data[0], trans_buf.buffer_to_rcv, ((*trans_desc)->rxlength+7)/8 );
|
||||
} else {
|
||||
memcpy( (*trans_desc)->rx_buffer, trans_buf.buffer_to_rcv, ((*trans_desc)->rxlength+7)/8 );
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ static const char *SPI_TAG = "spi_slave";
|
||||
#define VALID_HOST(x) (x>SPI_HOST && x<=VSPI_HOST)
|
||||
|
||||
typedef struct {
|
||||
int id;
|
||||
spi_slave_interface_config_t cfg;
|
||||
intr_handle_t intr;
|
||||
spi_dev_t *hw;
|
||||
@@ -79,7 +80,7 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
|
||||
|
||||
spi_chan_claimed=spicommon_periph_claim(host);
|
||||
SPI_CHECK(spi_chan_claimed, "host already in use", ESP_ERR_INVALID_STATE);
|
||||
|
||||
|
||||
if ( dma_chan != 0 ) {
|
||||
dma_chan_claimed=spicommon_dma_chan_claim(dma_chan);
|
||||
if ( !dma_chan_claimed ) {
|
||||
@@ -92,10 +93,12 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
|
||||
if (spihost[host] == NULL) goto nomem;
|
||||
memset(spihost[host], 0, sizeof(spi_slave_t));
|
||||
memcpy(&spihost[host]->cfg, slave_config, sizeof(spi_slave_interface_config_t));
|
||||
spihost[host]->id = host;
|
||||
|
||||
spicommon_bus_initialize_io(host, bus_config, dma_chan, SPICOMMON_BUSFLAG_SLAVE, &native);
|
||||
gpio_set_direction(slave_config->spics_io_num, GPIO_MODE_INPUT);
|
||||
spicommon_cs_initialize(host, slave_config->spics_io_num, 0, native == false);
|
||||
spicommon_cs_initialize(host, slave_config->spics_io_num, 0, native==false);
|
||||
// The slave DMA suffers from unexpected transactions. Forbid reading if DMA is enabled by disabling the CS line.
|
||||
if (dma_chan != 0) spicommon_freeze_cs(host);
|
||||
spihost[host]->no_gpio_matrix = native;
|
||||
spihost[host]->dma_chan = dma_chan;
|
||||
if (dma_chan != 0) {
|
||||
@@ -239,9 +242,9 @@ esp_err_t spi_slave_queue_trans(spi_host_device_t host, const spi_slave_transact
|
||||
BaseType_t r;
|
||||
SPI_CHECK(VALID_HOST(host), "invalid host", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK(spihost[host], "host not slave", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK(spihost[host]->dma_chan == 0 || trans_desc->tx_buffer==NULL || esp_ptr_dma_capable(trans_desc->tx_buffer),
|
||||
SPI_CHECK(spihost[host]->dma_chan == 0 || trans_desc->tx_buffer==NULL || esp_ptr_dma_capable(trans_desc->tx_buffer),
|
||||
"txdata not in DMA-capable memory", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK(spihost[host]->dma_chan == 0 || trans_desc->rx_buffer==NULL || esp_ptr_dma_capable(trans_desc->rx_buffer),
|
||||
SPI_CHECK(spihost[host]->dma_chan == 0 || trans_desc->rx_buffer==NULL || esp_ptr_dma_capable(trans_desc->rx_buffer),
|
||||
"rxdata not in DMA-capable memory", ESP_ERR_INVALID_ARG);
|
||||
|
||||
SPI_CHECK(trans_desc->length <= spihost[host]->max_transfer_sz * 8, "data transfer > host maximum", ESP_ERR_INVALID_ARG);
|
||||
@@ -325,8 +328,11 @@ static void IRAM_ATTR spi_intr(void *arg)
|
||||
if (!host->hw->slave.trans_done) return;
|
||||
|
||||
if (host->cur_trans) {
|
||||
// When DMA is enabled, the slave rx dma suffers from unexpected transactions. Forbid reading until transaction ready.
|
||||
if (host->dma_chan != 0) spicommon_freeze_cs(host->id);
|
||||
|
||||
//when data of cur_trans->length are all sent, the slv_rdata_bit
|
||||
//will be the length sent-1 (i.e. cur_trans->length-1 ), otherwise
|
||||
//will be the length sent-1 (i.e. cur_trans->length-1 ), otherwise
|
||||
//the length sent.
|
||||
host->cur_trans->trans_len = host->hw->slv_rd_bit.slv_rdata_bit;
|
||||
if ( host->cur_trans->trans_len == host->cur_trans->length - 1 ) {
|
||||
@@ -433,6 +439,9 @@ static void IRAM_ATTR spi_intr(void *arg)
|
||||
host->hw->user.usr_mosi = (trans->tx_buffer == NULL) ? 0 : 1;
|
||||
host->hw->user.usr_miso = (trans->rx_buffer == NULL) ? 0 : 1;
|
||||
|
||||
//The slave rx dma get disturbed by unexpected transaction. Only connect the CS when slave is ready.
|
||||
if (host->dma_chan != 0) spicommon_restore_cs(host->id, host->cfg.spics_io_num, host->no_gpio_matrix);
|
||||
|
||||
//Kick off transfer
|
||||
host->hw->cmd.usr = 1;
|
||||
if (host->cfg.post_setup_cb) host->cfg.post_setup_cb(trans);
|
||||
|
||||
@@ -390,7 +390,7 @@ TEST_CASE("SPI Master DMA test, TX and RX in different regions", "[spi]")
|
||||
trans[4].rxlength = 8*4;
|
||||
trans[4].tx_buffer = data_drom;
|
||||
trans[4].flags = SPI_TRANS_USE_RXDATA;
|
||||
|
||||
|
||||
trans[5].length = 8*4;
|
||||
trans[5].flags = SPI_TRANS_USE_RXDATA | SPI_TRANS_USE_TXDATA;
|
||||
|
||||
@@ -412,7 +412,7 @@ TEST_CASE("SPI Master DMA test, TX and RX in different regions", "[spi]")
|
||||
}
|
||||
|
||||
|
||||
static inline void int_connect( uint32_t gpio, uint32_t sigo, uint32_t sigi )
|
||||
static inline void int_connect( uint32_t gpio, uint32_t sigo, uint32_t sigi )
|
||||
{
|
||||
gpio_matrix_out( gpio, sigo, false, false );
|
||||
gpio_matrix_in( gpio, sigi, false );
|
||||
@@ -430,7 +430,7 @@ TEST_CASE("SPI Master DMA test: length, start, not aligned", "[spi]")
|
||||
esp_err_t ret;
|
||||
spi_device_handle_t spi;
|
||||
spi_bus_config_t buscfg={
|
||||
.miso_io_num=PIN_NUM_MISO,
|
||||
.miso_io_num=PIN_NUM_MISO,
|
||||
.mosi_io_num=PIN_NUM_MOSI,
|
||||
.sclk_io_num=PIN_NUM_CLK,
|
||||
.quadwp_io_num=-1,
|
||||
@@ -441,7 +441,7 @@ TEST_CASE("SPI Master DMA test: length, start, not aligned", "[spi]")
|
||||
.mode=0, //SPI mode 0
|
||||
.spics_io_num=PIN_NUM_CS, //CS pin
|
||||
.queue_size=7, //We want to be able to queue 7 transactions at a time
|
||||
.pre_cb=NULL,
|
||||
.pre_cb=NULL,
|
||||
};
|
||||
//Initialize the SPI bus
|
||||
ret=spi_bus_initialize(HSPI_HOST, &buscfg, 1);
|
||||
@@ -454,14 +454,14 @@ TEST_CASE("SPI Master DMA test: length, start, not aligned", "[spi]")
|
||||
int_connect( PIN_NUM_MOSI, HSPID_OUT_IDX, HSPIQ_IN_IDX );
|
||||
|
||||
memset(rx_buf, 0x66, 320);
|
||||
|
||||
|
||||
for ( int i = 0; i < 8; i ++ ) {
|
||||
memset( rx_buf, 0x66, sizeof(rx_buf));
|
||||
|
||||
spi_transaction_t t = {};
|
||||
t.length = 8*(i+1);
|
||||
t.rxlength = 0;
|
||||
t.tx_buffer = tx_buf+2*i;
|
||||
t.tx_buffer = tx_buf+2*i;
|
||||
t.rx_buffer = rx_buf + i;
|
||||
|
||||
if ( i == 1 ) {
|
||||
@@ -470,7 +470,7 @@ TEST_CASE("SPI Master DMA test: length, start, not aligned", "[spi]")
|
||||
} else if ( i == 2 ) {
|
||||
//test rx length != tx_length
|
||||
t.rxlength = t.length - 8;
|
||||
}
|
||||
}
|
||||
spi_device_transmit( spi, &t );
|
||||
|
||||
for( int i = 0; i < 16; i ++ ) {
|
||||
@@ -486,7 +486,7 @@ TEST_CASE("SPI Master DMA test: length, start, not aligned", "[spi]")
|
||||
} else {
|
||||
//normal check
|
||||
TEST_ASSERT( memcmp(t.tx_buffer, t.rx_buffer, t.length/8)==0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_ASSERT(spi_bus_remove_device(spi) == ESP_OK);
|
||||
@@ -495,14 +495,15 @@ TEST_CASE("SPI Master DMA test: length, start, not aligned", "[spi]")
|
||||
|
||||
static const char MASTER_TAG[] = "test_master";
|
||||
static const char SLAVE_TAG[] = "test_slave";
|
||||
DRAM_ATTR static uint8_t master_send[] = {0x93, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0xaa, 0xcc, 0xff, 0xee, 0x55, 0x77, 0x88, 0x43};
|
||||
//DRAM_ATTR static uint8_t master_send[] = {0x93, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0xaa, 0xcc, 0xff, 0xee, 0x55, 0x77, 0x88, 0x43};
|
||||
DRAM_ATTR static uint8_t slave_send[] = { 0xaa, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x13, 0x57, 0x9b, 0xdf, 0x24, 0x68, 0xac, 0xe0 };
|
||||
|
||||
/*
|
||||
static void master_init( spi_device_handle_t* spi, int mode, uint32_t speed)
|
||||
{
|
||||
esp_err_t ret;
|
||||
spi_bus_config_t buscfg={
|
||||
.miso_io_num=PIN_NUM_MISO,
|
||||
.miso_io_num=PIN_NUM_MISO,
|
||||
.mosi_io_num=PIN_NUM_MOSI,
|
||||
.sclk_io_num=PIN_NUM_CLK,
|
||||
.quadwp_io_num=-1,
|
||||
@@ -513,7 +514,7 @@ static void master_init( spi_device_handle_t* spi, int mode, uint32_t speed)
|
||||
.mode=mode, //SPI mode 0
|
||||
.spics_io_num=PIN_NUM_CS, //CS pin
|
||||
.queue_size=16, //We want to be able to queue 7 transactions at a time
|
||||
.pre_cb=NULL,
|
||||
.pre_cb=NULL,
|
||||
.cs_ena_pretrans = 0,
|
||||
};
|
||||
//Initialize the SPI bus
|
||||
@@ -546,6 +547,7 @@ static void slave_init(int mode, int dma_chan)
|
||||
//Initialize SPI slave interface
|
||||
TEST_ESP_OK( spi_slave_initialize(VSPI_HOST, &buscfg, &slvcfg, dma_chan) );
|
||||
}
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
uint32_t len;
|
||||
@@ -604,6 +606,7 @@ static void task_slave(void* arg)
|
||||
t.tx_buffer = txdata.start;
|
||||
t.rx_buffer = recvbuf+4;
|
||||
//loop until trans_len != 0 to skip glitches
|
||||
memset(recvbuf, 0x66, sizeof(recvbuf));
|
||||
do {
|
||||
TEST_ESP_OK( spi_slave_transmit( VSPI_HOST, &t, portMAX_DELAY ) );
|
||||
} while ( t.trans_len == 0 );
|
||||
@@ -613,118 +616,177 @@ static void task_slave(void* arg)
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("SPI master variable cmd & addr test","[spi]")
|
||||
#define TEST_SPI_HOST HSPI_HOST
|
||||
#define TEST_SLAVE_HOST VSPI_HOST
|
||||
|
||||
static uint8_t bitswap(uint8_t in)
|
||||
{
|
||||
uint8_t *tx_buf=master_send;
|
||||
uint8_t rx_buf[320];
|
||||
uint8_t *rx_buf_ptr = rx_buf;
|
||||
uint8_t out = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
out = out >> 1;
|
||||
if (in&0x80) out |= 0x80;
|
||||
in = in << 1;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
spi_slave_task_context_t slave_context = {};
|
||||
esp_err_t err = init_slave_context( &slave_context );
|
||||
TEST_ASSERT( err == ESP_OK );
|
||||
#define SPI_BUS_TEST_DEFAULT_CONFIG() {\
|
||||
.miso_io_num=PIN_NUM_MISO, \
|
||||
.mosi_io_num=PIN_NUM_MOSI,\
|
||||
.sclk_io_num=PIN_NUM_CLK,\
|
||||
.quadwp_io_num=-1,\
|
||||
.quadhd_io_num=-1\
|
||||
}
|
||||
|
||||
#define SPI_DEVICE_TEST_DEFAULT_CONFIG() {\
|
||||
.clock_speed_hz=10*1000*1000,\
|
||||
.mode=0,\
|
||||
.spics_io_num=PIN_NUM_CS,\
|
||||
.queue_size=16,\
|
||||
.pre_cb=NULL, \
|
||||
.cs_ena_pretrans = 0,\
|
||||
.cs_ena_posttrans = 0,\
|
||||
}
|
||||
|
||||
#define SPI_SLAVE_TEST_DEFAULT_CONFIG() {\
|
||||
.mode=0,\
|
||||
.spics_io_num=PIN_NUM_CS,\
|
||||
.queue_size=3,\
|
||||
.flags=0,\
|
||||
}
|
||||
|
||||
void test_cmd_addr(spi_slave_task_context_t *slave_context, bool lsb_first)
|
||||
{
|
||||
spi_device_handle_t spi;
|
||||
//initial master, mode 0, 1MHz
|
||||
master_init( &spi, 0, 1*1000*1000 );
|
||||
//initial slave, mode 0, no dma
|
||||
slave_init(0, 0);
|
||||
ESP_LOGI(MASTER_TAG, ">>>>>>>>> TEST %s FIRST <<<<<<<<<<<", lsb_first?"LSB":"MSB");
|
||||
|
||||
//do internal connection
|
||||
//initial master, mode 0, 1MHz
|
||||
spi_bus_config_t buscfg=SPI_BUS_TEST_DEFAULT_CONFIG();
|
||||
TEST_ESP_OK(spi_bus_initialize(TEST_SPI_HOST, &buscfg, 1));
|
||||
spi_device_interface_config_t devcfg=SPI_DEVICE_TEST_DEFAULT_CONFIG();
|
||||
devcfg.clock_speed_hz = 1*1000*1000;
|
||||
if (lsb_first) devcfg.flags |= SPI_DEVICE_BIT_LSBFIRST;
|
||||
TEST_ESP_OK(spi_bus_add_device(TEST_SPI_HOST, &devcfg, &spi));
|
||||
|
||||
//connecting pins to two peripherals breaks the output, fix it.
|
||||
int_connect( PIN_NUM_MOSI, HSPID_OUT_IDX, VSPIQ_IN_IDX );
|
||||
int_connect( PIN_NUM_MISO, VSPIQ_OUT_IDX, HSPID_IN_IDX );
|
||||
int_connect( PIN_NUM_CS, HSPICS0_OUT_IDX, VSPICS0_IN_IDX );
|
||||
int_connect( PIN_NUM_CLK, HSPICLK_OUT_IDX, VSPICLK_IN_IDX );
|
||||
|
||||
for (int i= 0; i < 8; i++) {
|
||||
//prepare slave tx data
|
||||
slave_txdata_t slave_txdata = (slave_txdata_t) {
|
||||
.start = slave_send,
|
||||
.len = 256,
|
||||
};
|
||||
xQueueSend(slave_context->data_to_send, &slave_txdata, portMAX_DELAY);
|
||||
|
||||
vTaskDelay(50);
|
||||
//prepare master tx data
|
||||
int cmd_bits = (i+1)*2;
|
||||
int addr_bits = 56-8*i;
|
||||
int round_up = (cmd_bits+addr_bits+7)/8*8;
|
||||
addr_bits = round_up - cmd_bits;
|
||||
|
||||
spi_transaction_ext_t trans = (spi_transaction_ext_t) {
|
||||
.base = {
|
||||
.flags = SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR,
|
||||
.addr = 0x456789abcdef0123,
|
||||
.cmd = 0xcdef,
|
||||
},
|
||||
.command_bits = cmd_bits,
|
||||
.address_bits = addr_bits,
|
||||
};
|
||||
|
||||
ESP_LOGI( MASTER_TAG, "===== test%d =====", i );
|
||||
ESP_LOGI(MASTER_TAG, "cmd_bits: %d, addr_bits: %d", cmd_bits, addr_bits);
|
||||
TEST_ESP_OK(spi_device_transmit(spi, (spi_transaction_t*)&trans));
|
||||
//wait for both master and slave end
|
||||
|
||||
size_t rcv_len;
|
||||
slave_rxdata_t *rcv_data = xRingbufferReceive(slave_context->data_received, &rcv_len, portMAX_DELAY);
|
||||
rcv_len-=4;
|
||||
uint8_t *buffer = rcv_data->data;
|
||||
|
||||
ESP_LOGI(SLAVE_TAG, "trans_len: %d", rcv_len);
|
||||
TEST_ASSERT_EQUAL(rcv_len, (rcv_data->len+7)/8);
|
||||
TEST_ASSERT_EQUAL(rcv_data->len, cmd_bits+addr_bits);
|
||||
ESP_LOG_BUFFER_HEX("slave rx", buffer, rcv_len);
|
||||
|
||||
uint16_t cmd_expected = trans.base.cmd & (BIT(cmd_bits) - 1);
|
||||
uint64_t addr_expected = trans.base.addr & ((1ULL<<addr_bits) - 1);
|
||||
|
||||
uint8_t *data_ptr = buffer;
|
||||
uint16_t cmd_got = *(uint16_t*)data_ptr;
|
||||
data_ptr += cmd_bits/8;
|
||||
cmd_got = __builtin_bswap16(cmd_got);
|
||||
cmd_got = cmd_got >> (16-cmd_bits);
|
||||
int remain_bits = cmd_bits % 8;
|
||||
|
||||
uint64_t addr_got = *(uint64_t*)data_ptr;
|
||||
data_ptr += 8;
|
||||
addr_got = __builtin_bswap64(addr_got);
|
||||
addr_got = (addr_got << remain_bits);
|
||||
addr_got |= (*data_ptr >> (8-remain_bits));
|
||||
addr_got = addr_got >> (64-addr_bits);
|
||||
|
||||
if (lsb_first) {
|
||||
cmd_got = __builtin_bswap16(cmd_got);
|
||||
addr_got = __builtin_bswap64(addr_got);
|
||||
|
||||
uint8_t *swap_ptr = (uint8_t*)&cmd_got;
|
||||
swap_ptr[0] = bitswap(swap_ptr[0]);
|
||||
swap_ptr[1] = bitswap(swap_ptr[1]);
|
||||
cmd_got = cmd_got >> (16-cmd_bits);
|
||||
|
||||
swap_ptr = (uint8_t*)&addr_got;
|
||||
for (int j = 0; j < 8; j++) swap_ptr[j] = bitswap(swap_ptr[j]);
|
||||
addr_got = addr_got >> (64-addr_bits);
|
||||
}
|
||||
|
||||
ESP_LOGI(SLAVE_TAG, "cmd_got: %04X, addr_got: %08X%08X", cmd_got, (uint32_t)(addr_got>>32), (uint32_t)addr_got);
|
||||
|
||||
TEST_ASSERT_EQUAL_HEX16(cmd_expected, cmd_got);
|
||||
if (addr_bits > 0) {
|
||||
TEST_ASSERT_EQUAL_HEX32(addr_expected, addr_got);
|
||||
TEST_ASSERT_EQUAL_HEX32(addr_expected >> 8, addr_got >> 8);
|
||||
}
|
||||
|
||||
//clean
|
||||
vRingbufferReturnItem(slave_context->data_received, buffer);
|
||||
}
|
||||
|
||||
TEST_ASSERT(spi_bus_remove_device(spi) == ESP_OK);
|
||||
TEST_ASSERT(spi_bus_free(TEST_SPI_HOST) == ESP_OK);
|
||||
}
|
||||
|
||||
TEST_CASE("SPI master variable cmd & addr test","[spi]")
|
||||
{
|
||||
spi_slave_task_context_t slave_context = {};
|
||||
esp_err_t err = init_slave_context( &slave_context );
|
||||
TEST_ASSERT( err == ESP_OK );
|
||||
TaskHandle_t handle_slave;
|
||||
xTaskCreate( task_slave, "spi_slave", 4096, &slave_context, 0, &handle_slave);
|
||||
|
||||
slave_txdata_t slave_txdata[16];
|
||||
spi_transaction_ext_t trans[16];
|
||||
for( int i= 0; i < 16; i ++ ) {
|
||||
//prepare slave tx data
|
||||
slave_txdata[i] = (slave_txdata_t) {
|
||||
.start = slave_send + 4*(i%3),
|
||||
.len = 256,
|
||||
};
|
||||
xQueueSend( slave_context.data_to_send, &slave_txdata[i], portMAX_DELAY );
|
||||
//prepare master tx data
|
||||
trans[i] = (spi_transaction_ext_t) {
|
||||
.base = {
|
||||
.flags = SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR,
|
||||
.addr = 0x456789ab,
|
||||
.cmd = 0xcdef,
|
||||
//initial slave, mode 0, no dma
|
||||
int dma_chan = 0;
|
||||
int slave_mode = 0;
|
||||
spi_bus_config_t slv_buscfg=SPI_BUS_TEST_DEFAULT_CONFIG();
|
||||
spi_slave_interface_config_t slvcfg=SPI_SLAVE_TEST_DEFAULT_CONFIG();
|
||||
slvcfg.mode = slave_mode;
|
||||
//Initialize SPI slave interface
|
||||
TEST_ESP_OK( spi_slave_initialize(TEST_SLAVE_HOST, &slv_buscfg, &slvcfg, dma_chan) );
|
||||
|
||||
.length = 8*i,
|
||||
.tx_buffer = tx_buf+i,
|
||||
.rx_buffer = rx_buf_ptr,
|
||||
},
|
||||
.command_bits = ((i+1)%3) * 8,
|
||||
.address_bits = ((i/3)%5) * 8,
|
||||
};
|
||||
if ( trans[i].base.length == 0 ) {
|
||||
trans[i].base.tx_buffer = NULL;
|
||||
trans[i].base.rx_buffer = NULL;
|
||||
} else {
|
||||
rx_buf_ptr += (trans[i].base.length + 31)/32*4;
|
||||
}
|
||||
}
|
||||
|
||||
vTaskDelay(10);
|
||||
|
||||
for ( int i = 0; i < 16; i ++ ) {
|
||||
TEST_ESP_OK (spi_device_queue_trans( spi, (spi_transaction_t*)&trans[i], portMAX_DELAY ) );
|
||||
vTaskDelay(10);
|
||||
}
|
||||
|
||||
for( int i= 0; i < 16; i ++ ) {
|
||||
//wait for both master and slave end
|
||||
ESP_LOGI( MASTER_TAG, "===== test%d =====", i );
|
||||
spi_transaction_ext_t *t;
|
||||
size_t rcv_len;
|
||||
spi_device_get_trans_result( spi, (spi_transaction_t**)&t, portMAX_DELAY );
|
||||
TEST_ASSERT( t == &trans[i] );
|
||||
if ( trans[i].base.length != 0 ) {
|
||||
ESP_LOG_BUFFER_HEX( "master tx", trans[i].base.tx_buffer, trans[i].base.length/8 );
|
||||
ESP_LOG_BUFFER_HEX( "master rx", trans[i].base.rx_buffer, trans[i].base.length/8 );
|
||||
} else {
|
||||
ESP_LOGI( "master tx", "no data" );
|
||||
ESP_LOGI( "master rx", "no data" );
|
||||
}
|
||||
|
||||
slave_rxdata_t *rcv_data = xRingbufferReceive( slave_context.data_received, &rcv_len, portMAX_DELAY );
|
||||
uint8_t *buffer = rcv_data->data;
|
||||
rcv_len = rcv_data->len;
|
||||
ESP_LOGI(SLAVE_TAG, "trans_len: %d", rcv_len);
|
||||
ESP_LOG_BUFFER_HEX( "slave tx", slave_txdata[i].start, (rcv_len+7)/8);
|
||||
ESP_LOG_BUFFER_HEX( "slave rx", buffer, (rcv_len+7)/8);
|
||||
//check result
|
||||
uint8_t *ptr_addr = (uint8_t*)&t->base.addr;
|
||||
uint8_t *ptr_cmd = (uint8_t*)&t->base.cmd;
|
||||
for ( int j = 0; j < t->command_bits/8; j ++ ) {
|
||||
TEST_ASSERT_EQUAL( buffer[j], ptr_cmd[t->command_bits/8-j-1] );
|
||||
}
|
||||
for ( int j = 0; j < t->address_bits/8; j ++ ) {
|
||||
TEST_ASSERT_EQUAL( buffer[t->command_bits/8+j], ptr_addr[t->address_bits/8-j-1] );
|
||||
}
|
||||
if ( t->base.length != 0) {
|
||||
TEST_ASSERT_EQUAL_HEX8_ARRAY(t->base.tx_buffer, buffer + (t->command_bits + t->address_bits)/8, t->base.length/8);
|
||||
TEST_ASSERT_EQUAL_HEX8_ARRAY(slave_txdata[i].start + (t->command_bits + t->address_bits)/8, t->base.rx_buffer, t->base.length/8);
|
||||
}
|
||||
TEST_ASSERT_EQUAL( t->base.length + t->command_bits + t->address_bits, rcv_len );
|
||||
|
||||
//clean
|
||||
vRingbufferReturnItem( slave_context.data_received, buffer );
|
||||
}
|
||||
test_cmd_addr(&slave_context, false);
|
||||
test_cmd_addr(&slave_context, true);
|
||||
|
||||
vTaskDelete( handle_slave );
|
||||
handle_slave = 0;
|
||||
|
||||
deinit_slave_context(&slave_context);
|
||||
|
||||
TEST_ASSERT(spi_slave_free(VSPI_HOST) == ESP_OK);
|
||||
|
||||
TEST_ASSERT(spi_bus_remove_device(spi) == ESP_OK);
|
||||
TEST_ASSERT(spi_bus_free(HSPI_HOST) == ESP_OK);
|
||||
TEST_ASSERT(spi_slave_free(TEST_SLAVE_HOST) == ESP_OK);
|
||||
|
||||
ESP_LOGI(MASTER_TAG, "test passed.");
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ esp_err_t system_event_eth_connected_handle_default(system_event_t *event)
|
||||
|
||||
tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_ETH, ð_ip);
|
||||
|
||||
if (!(ip4_addr_isany_val(eth_ip.ip) || ip4_addr_isany_val(eth_ip.netmask) || ip4_addr_isany_val(eth_ip.gw))) {
|
||||
if (!(ip4_addr_isany_val(eth_ip.ip) || ip4_addr_isany_val(eth_ip.netmask))) {
|
||||
system_event_t evt;
|
||||
|
||||
//notify event
|
||||
@@ -214,7 +214,7 @@ esp_err_t system_event_sta_connected_handle_default(system_event_t *event)
|
||||
tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &sta_ip);
|
||||
tcpip_adapter_get_old_ip_info(TCPIP_ADAPTER_IF_STA, &sta_old_ip);
|
||||
|
||||
if (!(ip4_addr_isany_val(sta_ip.ip) || ip4_addr_isany_val(sta_ip.netmask) || ip4_addr_isany_val(sta_ip.gw))) {
|
||||
if (!(ip4_addr_isany_val(sta_ip.ip) || ip4_addr_isany_val(sta_ip.netmask))) {
|
||||
system_event_t evt;
|
||||
|
||||
evt.event_id = SYSTEM_EVENT_STA_GOT_IP;
|
||||
|
||||
@@ -18,8 +18,23 @@
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
|
||||
typedef enum {
|
||||
ESP_SPIRAM_SIZE_32MBITS = 0, /*!< SPI RAM size is 32 MBits */
|
||||
ESP_SPIRAM_SIZE_64MBITS = 1, /*!< SPI RAM size is 64 MBits */
|
||||
ESP_SPIRAM_SIZE_INVALID, /*!< SPI RAM size is invalid */
|
||||
} esp_spiram_size_t;
|
||||
|
||||
/**
|
||||
* @brief get SPI RAM size
|
||||
* @return
|
||||
* - ESP_SPIRAM_SIZE_INVALID if SPI RAM not enabled or not valid
|
||||
* - SPI RAM size
|
||||
*/
|
||||
esp_spiram_size_t esp_spiram_get_chip_size();
|
||||
|
||||
/**
|
||||
* @brief Initialize spiram interface/hardware. Normally called from cpu_start.c.
|
||||
*
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "esp_err.h"
|
||||
#include "esp_wifi_types.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_wifi.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -161,6 +162,15 @@ void *wifi_realloc( void *ptr, size_t size );
|
||||
*/
|
||||
void *wifi_calloc( size_t n, size_t size );
|
||||
|
||||
/**
|
||||
* @brief Update WiFi MAC time
|
||||
*
|
||||
* @param uint32_t time_delta : time duration since the WiFi/BT common clock is disabled
|
||||
*
|
||||
* @return Always returns ESP_OK
|
||||
*/
|
||||
esp_err_t esp_wifi_internal_update_mac_time( uint32_t time_delta );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -117,6 +117,8 @@ extern "C" {
|
||||
#define ESP_ROM_SPIFLASH_WR_PROTECT (ESP_ROM_SPIFLASH_BP0|ESP_ROM_SPIFLASH_BP1|ESP_ROM_SPIFLASH_BP2)
|
||||
#define ESP_ROM_SPIFLASH_QE BIT9
|
||||
|
||||
#define FLASH_ID_GD25LQ32C 0xC86016
|
||||
|
||||
typedef enum {
|
||||
ESP_ROM_SPIFLASH_QIO_MODE = 0,
|
||||
ESP_ROM_SPIFLASH_QOUT_MODE,
|
||||
|
||||
@@ -224,6 +224,7 @@ PROVIDE ( lld_evt_env = 0x3ffb9704 );
|
||||
PROVIDE ( lld_evt_elt_wait_get = 0x400468e4 );
|
||||
PROVIDE ( lld_evt_get_next_free_slot = 0x4004692c );
|
||||
PROVIDE ( lld_pdu_adv_pk_desc_tab = 0x3ff98c70 );
|
||||
PROVIDE ( lld_pdu_tx_flush_list = 0x4004a760 );
|
||||
PROVIDE ( lld_pdu_llcp_pk_desc_tab = 0x3ff98b68 );
|
||||
PROVIDE ( lld_pdu_pack = 0x4004ab14 );
|
||||
PROVIDE ( LLM_AA_CT1 = 0x3ff98d8a );
|
||||
|
||||
Submodule components/esp32/lib updated: e923fea4e8...a0181fa817
@@ -36,6 +36,7 @@
|
||||
#include "phy_init_data.h"
|
||||
#include "esp_coexist.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
#include "esp_wifi_internal.h"
|
||||
|
||||
static const char* TAG = "phy_init";
|
||||
|
||||
@@ -44,6 +45,24 @@ static int s_phy_rf_init_count = 0;
|
||||
|
||||
static _lock_t s_phy_rf_init_lock;
|
||||
|
||||
static inline void phy_update_wifi_mac_time(bool en_clock_stopped)
|
||||
{
|
||||
static uint32_t s_common_clock_disable_time = 0;
|
||||
|
||||
if (en_clock_stopped) {
|
||||
s_common_clock_disable_time = esp_timer_get_time();
|
||||
} else {
|
||||
if (s_common_clock_disable_time) {
|
||||
uint64_t now = esp_timer_get_time();
|
||||
uint32_t diff = now - s_common_clock_disable_time;
|
||||
|
||||
esp_wifi_internal_update_mac_time(diff);
|
||||
s_common_clock_disable_time = 0;
|
||||
ESP_LOGD(TAG, "wifi mac time delta: %u", diff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t esp_phy_rf_init(const esp_phy_init_data_t* init_data,
|
||||
esp_phy_calibration_mode_t mode, esp_phy_calibration_data_t* calibration_data)
|
||||
{
|
||||
@@ -51,6 +70,8 @@ esp_err_t esp_phy_rf_init(const esp_phy_init_data_t* init_data,
|
||||
|
||||
_lock_acquire(&s_phy_rf_init_lock);
|
||||
if (s_phy_rf_init_count == 0) {
|
||||
// Update WiFi MAC time before WiFi/BT common clock is enabled
|
||||
phy_update_wifi_mac_time( false );
|
||||
// Enable WiFi/BT common peripheral clock
|
||||
periph_module_enable(PERIPH_WIFI_BT_COMMON_MODULE);
|
||||
ESP_LOGV(TAG, "register_chipv7_phy, init_data=%p, cal_data=%p, mode=%d",
|
||||
@@ -76,6 +97,8 @@ esp_err_t esp_phy_rf_deinit(void)
|
||||
if (s_phy_rf_init_count == 1) {
|
||||
// Disable PHY and RF.
|
||||
phy_close_rf();
|
||||
// Update WiFi MAC time before disalbe WiFi/BT common peripheral clock
|
||||
phy_update_wifi_mac_time(true);
|
||||
// Disable WiFi/BT common peripheral clock. Do not disable clock for hardware RNG
|
||||
periph_module_disable(PERIPH_WIFI_BT_COMMON_MODULE);
|
||||
} else {
|
||||
|
||||
@@ -23,6 +23,7 @@ we add more types of external RAM memory, this can be made into a more intellige
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_spiram.h"
|
||||
#include "spiram_psram.h"
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
@@ -102,6 +103,22 @@ void IRAM_ATTR esp_spiram_init_cache()
|
||||
#endif
|
||||
}
|
||||
|
||||
esp_spiram_size_t esp_spiram_get_chip_size()
|
||||
{
|
||||
if (!spiram_inited) {
|
||||
ESP_LOGE(TAG, "SPI RAM not initialized");
|
||||
return ESP_SPIRAM_SIZE_INVALID;
|
||||
}
|
||||
psram_size_t psram_size = psram_get_size();
|
||||
switch (psram_size) {
|
||||
case PSRAM_SIZE_32MBITS:
|
||||
return ESP_SPIRAM_SIZE_32MBITS;
|
||||
case PSRAM_SIZE_64MBITS:
|
||||
return ESP_SPIRAM_SIZE_64MBITS;
|
||||
default:
|
||||
return ESP_SPIRAM_SIZE_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t esp_spiram_init()
|
||||
{
|
||||
|
||||
@@ -39,26 +39,39 @@
|
||||
#if CONFIG_SPIRAM_SUPPORT
|
||||
|
||||
//Commands for PSRAM chip
|
||||
#define PSRAM_READ 0x03
|
||||
#define PSRAM_FAST_READ 0x0B
|
||||
#define PSRAM_FAST_READ_DUMMY 0x3
|
||||
#define PSRAM_FAST_READ_QUAD 0xEB
|
||||
#define PSRAM_WRITE 0x02
|
||||
#define PSRAM_QUAD_WRITE 0x38
|
||||
#define PSRAM_ENTER_QMODE 0x35
|
||||
#define PSRAM_EXIT_QMODE 0xF5
|
||||
#define PSRAM_RESET_EN 0x66
|
||||
#define PSRAM_RESET 0x99
|
||||
#define PSRAM_SET_BURST_LEN 0xC0
|
||||
#define PSRAM_DEVICE_ID 0x9F
|
||||
#define PSRAM_READ 0x03
|
||||
#define PSRAM_FAST_READ 0x0B
|
||||
#define PSRAM_FAST_READ_DUMMY 0x3
|
||||
#define PSRAM_FAST_READ_QUAD 0xEB
|
||||
#define PSRAM_FAST_READ_QUAD_DUMMY 0x5
|
||||
#define PSRAM_WRITE 0x02
|
||||
#define PSRAM_QUAD_WRITE 0x38
|
||||
#define PSRAM_ENTER_QMODE 0x35
|
||||
#define PSRAM_EXIT_QMODE 0xF5
|
||||
#define PSRAM_RESET_EN 0x66
|
||||
#define PSRAM_RESET 0x99
|
||||
#define PSRAM_SET_BURST_LEN 0xC0
|
||||
#define PSRAM_DEVICE_ID 0x9F
|
||||
|
||||
#if CONFIG_SPIRAM_TYPE_ESPPSRAM32
|
||||
typedef enum {
|
||||
PSRAM_CLK_MODE_NORM = 0, /*!< Normal SPI mode */
|
||||
PSRAM_CLK_MODE_DCLK = 1, /*!< Two extra clock cycles after CS is set high level */
|
||||
} psram_clk_mode_t;
|
||||
|
||||
#define PSRAM_MFG_ID_M 0xff
|
||||
#define PSRAM_MFG_ID_S 8
|
||||
#define PSRAM_MFG_ID_V 0x5d
|
||||
#define PSRAM_ID_KGD_M 0xff
|
||||
#define PSRAM_ID_KGD_S 8
|
||||
#define PSRAM_ID_KGD 0x5d
|
||||
#define PSRAM_ID_EID_M 0xff
|
||||
#define PSRAM_ID_EID_S 16
|
||||
|
||||
#endif
|
||||
#define PSRAM_KGD(id) (((id) >> PSRAM_ID_KGD_S) & PSRAM_ID_KGD_M)
|
||||
#define PSRAM_EID(id) (((id) >> PSRAM_ID_EID_S) & PSRAM_ID_EID_M)
|
||||
#define PSRAM_IS_VALID(id) (PSRAM_KGD(id) == PSRAM_ID_KGD)
|
||||
|
||||
// PSRAM_EID = 0x26 or 0x4x ----> 64MBit psram
|
||||
// PSRAM_EID = 0x20 ------------> 32MBit psram
|
||||
#define PSRAM_IS_64MBIT(id) ((PSRAM_EID(id) == 0x26) || ((PSRAM_EID(id) & 0xf0) == 0x40))
|
||||
#define PSRAM_IS_32MBIT_VER0(id) (PSRAM_EID(id) == 0x20)
|
||||
|
||||
// IO-pins for PSRAM. These need to be in the VDD_SIO power domain because all chips we
|
||||
// currently support are 1.8V parts.
|
||||
@@ -98,6 +111,8 @@ typedef enum {
|
||||
} psram_spi_num_t;
|
||||
|
||||
static psram_cache_mode_t s_psram_mode = PSRAM_CACHE_MAX;
|
||||
static psram_clk_mode_t s_clk_mode = PSRAM_CLK_MODE_DCLK;
|
||||
static uint32_t s_psram_id = 0;
|
||||
|
||||
/* dummy_len_plus values defined in ROM for SPI flash configuration */
|
||||
extern uint8_t g_rom_spiflash_dummy_len_plus[];
|
||||
@@ -286,7 +301,7 @@ static int psram_cmd_config(psram_spi_num_t spi_num, psram_cmd_t* pInData)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void psram_cmd_end(int spi_num) {
|
||||
static void psram_cmd_end(int spi_num) {
|
||||
while (READ_PERI_REG(SPI_CMD_REG(spi_num)) & SPI_USR);
|
||||
WRITE_PERI_REG(SPI_USER_REG(spi_num), backup_usr[spi_num]);
|
||||
WRITE_PERI_REG(SPI_USER1_REG(spi_num), backup_usr1[spi_num]);
|
||||
@@ -298,17 +313,19 @@ static void psram_disable_qio_mode(psram_spi_num_t spi_num)
|
||||
{
|
||||
psram_cmd_t ps_cmd;
|
||||
uint32_t cmd_exit_qpi;
|
||||
switch (s_psram_mode) {
|
||||
case PSRAM_CACHE_F80M_S80M:
|
||||
cmd_exit_qpi = PSRAM_EXIT_QMODE;
|
||||
ps_cmd.txDataBitLen = 8;
|
||||
break;
|
||||
case PSRAM_CACHE_F80M_S40M:
|
||||
case PSRAM_CACHE_F40M_S40M:
|
||||
default:
|
||||
cmd_exit_qpi = PSRAM_EXIT_QMODE << 8;
|
||||
ps_cmd.txDataBitLen = 16;
|
||||
break;
|
||||
cmd_exit_qpi = PSRAM_EXIT_QMODE;
|
||||
ps_cmd.txDataBitLen = 8;
|
||||
if (s_clk_mode == PSRAM_CLK_MODE_DCLK) {
|
||||
switch (s_psram_mode) {
|
||||
case PSRAM_CACHE_F80M_S80M:
|
||||
break;
|
||||
case PSRAM_CACHE_F80M_S40M:
|
||||
case PSRAM_CACHE_F40M_S40M:
|
||||
default:
|
||||
cmd_exit_qpi = PSRAM_EXIT_QMODE << 8;
|
||||
ps_cmd.txDataBitLen = 16;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ps_cmd.txData = &cmd_exit_qpi;
|
||||
ps_cmd.cmd = 0;
|
||||
@@ -328,29 +345,34 @@ static void psram_read_id(uint32_t* dev_id)
|
||||
{
|
||||
psram_spi_num_t spi_num = PSRAM_SPI_1;
|
||||
psram_disable_qio_mode(spi_num);
|
||||
uint32_t addr = (PSRAM_DEVICE_ID << 24) | 0;
|
||||
uint32_t dummy_bits = 0;
|
||||
uint32_t dummy_bits = 0 + extra_dummy;
|
||||
psram_cmd_t ps_cmd;
|
||||
switch (s_psram_mode) {
|
||||
case PSRAM_CACHE_F80M_S80M:
|
||||
dummy_bits = 0 + extra_dummy;
|
||||
ps_cmd.cmdBitLen = 0;
|
||||
break;
|
||||
case PSRAM_CACHE_F80M_S40M:
|
||||
case PSRAM_CACHE_F40M_S40M:
|
||||
default:
|
||||
dummy_bits = 0 + extra_dummy;
|
||||
ps_cmd.cmdBitLen = 2; //this two bits is used to delay 2 clock cycle
|
||||
break;
|
||||
|
||||
uint32_t addr = 0;
|
||||
ps_cmd.addrBitLen = 3 * 8;
|
||||
ps_cmd.cmd = PSRAM_DEVICE_ID;
|
||||
ps_cmd.cmdBitLen = 8;
|
||||
if (s_clk_mode == PSRAM_CLK_MODE_DCLK) {
|
||||
switch (s_psram_mode) {
|
||||
case PSRAM_CACHE_F80M_S80M:
|
||||
break;
|
||||
case PSRAM_CACHE_F80M_S40M:
|
||||
case PSRAM_CACHE_F40M_S40M:
|
||||
default:
|
||||
ps_cmd.cmdBitLen = 2; //this two bits is used to delay 2 clock cycle
|
||||
ps_cmd.cmd = 0;
|
||||
addr = (PSRAM_DEVICE_ID << 24) | 0;
|
||||
ps_cmd.addrBitLen = 4 * 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ps_cmd.cmd = 0;
|
||||
ps_cmd.addr = &addr;
|
||||
ps_cmd.addrBitLen = 4 * 8;
|
||||
ps_cmd.txDataBitLen = 0;
|
||||
ps_cmd.txData = NULL;
|
||||
ps_cmd.rxDataBitLen = 4 * 8;
|
||||
ps_cmd.rxData = dev_id;
|
||||
ps_cmd.dummyBitLen = dummy_bits;
|
||||
|
||||
psram_cmd_config(spi_num, &ps_cmd);
|
||||
psram_clear_spi_fifo(spi_num);
|
||||
psram_cmd_recv_start(spi_num, ps_cmd.rxData, ps_cmd.rxDataBitLen / 8, PSRAM_CMD_SPI);
|
||||
@@ -362,15 +384,18 @@ static esp_err_t IRAM_ATTR psram_enable_qio_mode(psram_spi_num_t spi_num)
|
||||
{
|
||||
psram_cmd_t ps_cmd;
|
||||
uint32_t addr = (PSRAM_ENTER_QMODE << 24) | 0;
|
||||
switch (s_psram_mode) {
|
||||
case PSRAM_CACHE_F80M_S80M:
|
||||
ps_cmd.cmdBitLen = 0;
|
||||
break;
|
||||
case PSRAM_CACHE_F80M_S40M:
|
||||
case PSRAM_CACHE_F40M_S40M:
|
||||
default:
|
||||
ps_cmd.cmdBitLen = 2;
|
||||
break;
|
||||
|
||||
ps_cmd.cmdBitLen = 0;
|
||||
if (s_clk_mode == PSRAM_CLK_MODE_DCLK) {
|
||||
switch (s_psram_mode) {
|
||||
case PSRAM_CACHE_F80M_S80M:
|
||||
break;
|
||||
case PSRAM_CACHE_F80M_S40M:
|
||||
case PSRAM_CACHE_F40M_S40M:
|
||||
default:
|
||||
ps_cmd.cmdBitLen = 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ps_cmd.cmd = 0;
|
||||
ps_cmd.addr = &addr;
|
||||
@@ -473,6 +498,17 @@ static void IRAM_ATTR psram_gpio_config(psram_cache_mode_t mode)
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
|
||||
}
|
||||
|
||||
psram_size_t psram_get_size()
|
||||
{
|
||||
if (PSRAM_IS_32MBIT_VER0(s_psram_id)) {
|
||||
return PSRAM_SIZE_32MBITS;
|
||||
} else if (PSRAM_IS_64MBIT(s_psram_id)) {
|
||||
return PSRAM_SIZE_64MBITS;
|
||||
} else {
|
||||
return PSRAM_SIZE_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
//psram gpio init , different working frequency we have different solutions
|
||||
esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vaddrmode) //psram init
|
||||
{
|
||||
@@ -489,17 +525,6 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* note: If the third mode(80Mhz+80Mhz) is enabled, VSPI port will be occupied by the system,
|
||||
Application code should never touch VSPI hardware in this case. We try to stop applications
|
||||
from doing this using the drivers by claiming the port for ourselves*/
|
||||
if (mode == PSRAM_CACHE_F80M_S80M) {
|
||||
periph_module_enable(PERIPH_VSPI_MODULE);
|
||||
bool r=spicommon_periph_claim(VSPI_HOST);
|
||||
if (!r) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
}
|
||||
|
||||
WRITE_PERI_REG(GPIO_ENABLE_W1TC_REG, BIT(PSRAM_CLK_IO) | BIT(PSRAM_CS_IO)); //DISABLE OUPUT FOR IO16/17
|
||||
assert(mode < PSRAM_CACHE_MAX && "we don't support any other mode for now.");
|
||||
s_psram_mode = mode;
|
||||
@@ -514,21 +539,7 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad
|
||||
psram_spi_init(PSRAM_SPI_1, mode);
|
||||
CLEAR_PERI_REG_MASK(SPI_USER_REG(PSRAM_SPI_1), SPI_CS_HOLD);
|
||||
gpio_matrix_out(PSRAM_CS_IO, SPICS1_OUT_IDX, 0, 0);
|
||||
gpio_matrix_out(PSRAM_CLK_IO, VSPICLK_OUT_IDX, 0, 0);
|
||||
//use spi3 clock,but use spi1 data/cs wires
|
||||
//We get a solid 80MHz clock from SPI3 by setting it up, starting a transaction, waiting until it
|
||||
//is in progress, then cutting the clock (but not the reset!) to that peripheral.
|
||||
WRITE_PERI_REG(SPI_ADDR_REG(PSRAM_SPI_3), 32 << 24);
|
||||
WRITE_PERI_REG(SPI_CLOCK_REG(PSRAM_SPI_3), SPI_CLK_EQU_SYSCLK_M); //SET 80M AND CLEAR OTHERS
|
||||
SET_PERI_REG_MASK(SPI_CMD_REG(PSRAM_SPI_3), SPI_FLASH_READ_M);
|
||||
uint32_t spi_status;
|
||||
while (1) {
|
||||
spi_status = READ_PERI_REG(SPI_EXT2_REG(PSRAM_SPI_3));
|
||||
if (spi_status != 0 && spi_status != 1) {
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN_2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
gpio_matrix_out(PSRAM_CLK_IO, SPICLK_OUT_IDX, 0, 0);
|
||||
break;
|
||||
case PSRAM_CACHE_F80M_S40M:
|
||||
case PSRAM_CACHE_F40M_S40M:
|
||||
@@ -554,13 +565,59 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad
|
||||
WRITE_PERI_REG(GPIO_ENABLE_W1TS_REG, BIT(PSRAM_CS_IO)| BIT(PSRAM_CLK_IO));
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[PSRAM_CS_IO], PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[PSRAM_CLK_IO], PIN_FUNC_GPIO);
|
||||
uint32_t id;
|
||||
psram_read_id(&id);
|
||||
if (((id >> PSRAM_MFG_ID_S) & PSRAM_MFG_ID_M) != PSRAM_MFG_ID_V) {
|
||||
|
||||
psram_read_id(&s_psram_id);
|
||||
if (!PSRAM_IS_VALID(s_psram_id)) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
uint32_t flash_id = g_rom_flashchip.device_id;
|
||||
if (flash_id == FLASH_ID_GD25LQ32C) {
|
||||
// Set drive ability for 1.8v flash in 80Mhz.
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA0_U, FUN_DRV_V, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA1_U, FUN_DRV_V, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA2_U, FUN_DRV_V, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA3_U, FUN_DRV_V, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CMD_U, FUN_DRV_V, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV_V, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[PSRAM_CS_IO], FUN_DRV_V, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[PSRAM_CLK_IO], FUN_DRV_V, 3, FUN_DRV_S);
|
||||
}
|
||||
if (PSRAM_IS_64MBIT(s_psram_id)) {
|
||||
// For this psram, we don't need any extra clock cycles after cs get back to high level
|
||||
s_clk_mode = PSRAM_CLK_MODE_NORM;
|
||||
gpio_matrix_out(PSRAM_INTERNAL_IO_28, SIG_GPIO_OUT_IDX, 0, 0);
|
||||
gpio_matrix_out(PSRAM_INTERNAL_IO_29, SIG_GPIO_OUT_IDX, 0, 0);
|
||||
gpio_matrix_out(PSRAM_CLK_IO, SPICLK_OUT_IDX, 0, 0);
|
||||
} else if (PSRAM_IS_32MBIT_VER0(s_psram_id)) {
|
||||
s_clk_mode = PSRAM_CLK_MODE_DCLK;
|
||||
if (mode == PSRAM_CACHE_F80M_S80M) {
|
||||
/* note: If the third mode(80Mhz+80Mhz) is enabled for 32MBit 1V8 psram, VSPI port will be
|
||||
occupied by the system.
|
||||
Application code should never touch VSPI hardware in this case. We try to stop applications
|
||||
from doing this using the drivers by claiming the port for ourselves */
|
||||
periph_module_enable(PERIPH_VSPI_MODULE);
|
||||
bool r=spicommon_periph_claim(VSPI_HOST);
|
||||
if (!r) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
gpio_matrix_out(PSRAM_CLK_IO, VSPICLK_OUT_IDX, 0, 0);
|
||||
//use spi3 clock,but use spi1 data/cs wires
|
||||
//We get a solid 80MHz clock from SPI3 by setting it up, starting a transaction, waiting until it
|
||||
//is in progress, then cutting the clock (but not the reset!) to that peripheral.
|
||||
WRITE_PERI_REG(SPI_ADDR_REG(PSRAM_SPI_3), 32 << 24);
|
||||
WRITE_PERI_REG(SPI_CLOCK_REG(PSRAM_SPI_3), SPI_CLK_EQU_SYSCLK_M); //SET 80M AND CLEAR OTHERS
|
||||
SET_PERI_REG_MASK(SPI_CMD_REG(PSRAM_SPI_3), SPI_FLASH_READ_M);
|
||||
uint32_t spi_status;
|
||||
while (1) {
|
||||
spi_status = READ_PERI_REG(SPI_EXT2_REG(PSRAM_SPI_3));
|
||||
if (spi_status != 0 && spi_status != 1) {
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN_2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
psram_enable_qio_mode(PSRAM_SPI_1);
|
||||
|
||||
psram_cache_init(mode, vaddrmode);
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -579,27 +636,15 @@ static void IRAM_ATTR psram_cache_init(psram_cache_mode_t psram_cache_mode, psra
|
||||
CLEAR_PERI_REG_MASK(SPI_DATE_REG(0), BIT(31)); //flash 1 div clk,80+40;
|
||||
CLEAR_PERI_REG_MASK(SPI_DATE_REG(0), BIT(30)); //pre clk div , ONLY IF SPI/SRAM@ DIFFERENT SPEED,JUST FOR SPI0. FLASH DIV 2+SRAM DIV4
|
||||
WRITE_PERI_REG(SPI_CLOCK_REG(0), SPI_CLK_EQU_SYSCLK_M); //SET 1DIV CLOCK AND RESET OTHER PARAMS
|
||||
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_RD_SRAM_DUMMY_M); //enable cache read dummy
|
||||
SET_PERI_REG_BITS(SPI_CACHE_SCTRL_REG(0), SPI_SRAM_DUMMY_CYCLELEN_V, PSRAM_FAST_READ_DUMMY + extra_dummy,
|
||||
SPI_SRAM_DUMMY_CYCLELEN_S); //dummy, psram cache : 40m--+1dummy,80m--+2dummy
|
||||
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_CACHE_SRAM_USR_RCMD_M); //enable user mode for cache read command
|
||||
break;
|
||||
case PSRAM_CACHE_F80M_S40M:
|
||||
SET_PERI_REG_MASK(SPI_DATE_REG(0), BIT(31)); //flash 1 div clk
|
||||
CLEAR_PERI_REG_MASK(SPI_DATE_REG(0), BIT(30)); //pre clk div , ONLY IF SPI/SRAM@ DIFFERENT SPEED,JUST FOR SPI0.
|
||||
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_RD_SRAM_DUMMY_M); //enable cache read dummy
|
||||
SET_PERI_REG_BITS(SPI_CACHE_SCTRL_REG(0), SPI_SRAM_DUMMY_CYCLELEN_V, PSRAM_FAST_READ_DUMMY + extra_dummy,
|
||||
SPI_SRAM_DUMMY_CYCLELEN_S); //dummy, psram cache : 40m--+1dummy,80m--+2dummy
|
||||
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_CACHE_SRAM_USR_RCMD_M); //enable user mode for cache read command
|
||||
break;
|
||||
case PSRAM_CACHE_F40M_S40M:
|
||||
default:
|
||||
CLEAR_PERI_REG_MASK(SPI_DATE_REG(0), BIT(31)); //flash 1 div clk
|
||||
CLEAR_PERI_REG_MASK(SPI_DATE_REG(0), BIT(30)); //pre clk div
|
||||
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_RD_SRAM_DUMMY_M); //enable cache read dummy
|
||||
SET_PERI_REG_BITS(SPI_CACHE_SCTRL_REG(0), SPI_SRAM_DUMMY_CYCLELEN_V, PSRAM_FAST_READ_DUMMY + extra_dummy,
|
||||
SPI_SRAM_DUMMY_CYCLELEN_S); //dummy, psram cache : 40m--+1dummy,80m--+2dummy
|
||||
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_CACHE_SRAM_USR_RCMD_M); //enable user mode for cache read command
|
||||
break;
|
||||
}
|
||||
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_CACHE_SRAM_USR_WCMD_M); // cache write command enable
|
||||
@@ -607,30 +652,38 @@ static void IRAM_ATTR psram_cache_init(psram_cache_mode_t psram_cache_mode, psra
|
||||
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_SRAM_QIO_M); //enable qio mode for cache command
|
||||
CLEAR_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_SRAM_DIO_M); //disable dio mode for cache command
|
||||
|
||||
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_RD_SRAM_DUMMY_M); //enable cache read dummy
|
||||
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_CACHE_SRAM_USR_RCMD_M); //enable user mode for cache read command
|
||||
SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_BITLEN, 7,
|
||||
SPI_CACHE_SRAM_USR_WR_CMD_BITLEN_S);
|
||||
SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_VALUE, PSRAM_QUAD_WRITE,
|
||||
SPI_CACHE_SRAM_USR_WR_CMD_VALUE_S); //0x38
|
||||
SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_V, 7,
|
||||
SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_S);
|
||||
SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_VALUE_V, PSRAM_FAST_READ_QUAD,
|
||||
SPI_CACHE_SRAM_USR_RD_CMD_VALUE_S); //0x0b
|
||||
SET_PERI_REG_BITS(SPI_CACHE_SCTRL_REG(0), SPI_SRAM_DUMMY_CYCLELEN_V, PSRAM_FAST_READ_QUAD_DUMMY + extra_dummy,
|
||||
SPI_SRAM_DUMMY_CYCLELEN_S); //dummy, psram cache : 40m--+1dummy,80m--+2dummy
|
||||
|
||||
//config sram cache r/w command
|
||||
switch (psram_cache_mode) {
|
||||
case PSRAM_CACHE_F80M_S80M: //in this mode , no delay is needed
|
||||
SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_BITLEN, 7,
|
||||
SPI_CACHE_SRAM_USR_WR_CMD_BITLEN_S);
|
||||
SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_VALUE, PSRAM_QUAD_WRITE,
|
||||
SPI_CACHE_SRAM_USR_WR_CMD_VALUE_S); //0x38
|
||||
SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_V, 7,
|
||||
SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_S);
|
||||
SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_VALUE_V, PSRAM_FAST_READ,
|
||||
SPI_CACHE_SRAM_USR_RD_CMD_VALUE_S); //0x0b
|
||||
break;
|
||||
case PSRAM_CACHE_F80M_S40M: //is sram is @40M, need 2 cycles of delay
|
||||
case PSRAM_CACHE_F40M_S40M:
|
||||
default:
|
||||
SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_V, 15,
|
||||
SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_S); //read command length, 2 bytes(1byte for delay),sending in qio mode in cache
|
||||
SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_VALUE_V, ((PSRAM_FAST_READ) << 8),
|
||||
SPI_CACHE_SRAM_USR_RD_CMD_VALUE_S); //0x0b, read command value,(0x00 for delay,0x0b for cmd)
|
||||
SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_BITLEN, 15,
|
||||
SPI_CACHE_SRAM_USR_WR_CMD_BITLEN_S); //write command length,2 bytes(1byte for delay,send in qio mode in cache)
|
||||
SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_VALUE, ((PSRAM_QUAD_WRITE) << 8),
|
||||
SPI_CACHE_SRAM_USR_WR_CMD_VALUE_S); //0x38, write command value,(0x00 for delay)
|
||||
if (s_clk_mode == PSRAM_CLK_MODE_DCLK) {
|
||||
SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_V, 15,
|
||||
SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_S); //read command length, 2 bytes(1byte for delay),sending in qio mode in cache
|
||||
SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_VALUE_V, ((PSRAM_FAST_READ_QUAD) << 8),
|
||||
SPI_CACHE_SRAM_USR_RD_CMD_VALUE_S); //0x0b, read command value,(0x00 for delay,0x0b for cmd)
|
||||
SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_BITLEN, 15,
|
||||
SPI_CACHE_SRAM_USR_WR_CMD_BITLEN_S); //write command length,2 bytes(1byte for delay,send in qio mode in cache)
|
||||
SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_VALUE, ((PSRAM_QUAD_WRITE) << 8),
|
||||
SPI_CACHE_SRAM_USR_WR_CMD_VALUE_S); //0x38, write command value,(0x00 for delay)
|
||||
SET_PERI_REG_BITS(SPI_CACHE_SCTRL_REG(0), SPI_SRAM_DUMMY_CYCLELEN_V, PSRAM_FAST_READ_QUAD_DUMMY + extra_dummy,
|
||||
SPI_SRAM_DUMMY_CYCLELEN_S); //dummy, psram cache : 40m--+1dummy,80m--+2dummy
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -653,6 +706,11 @@ static void IRAM_ATTR psram_cache_init(psram_cache_mode_t psram_cache_mode, psra
|
||||
|
||||
CLEAR_PERI_REG_MASK(SPI_PIN_REG(0), SPI_CS1_DIS_M); //ENABLE SPI0 CS1 TO PSRAM(CS0--FLASH; CS1--SRAM)
|
||||
|
||||
if (s_clk_mode == PSRAM_CLK_MODE_NORM) { //different
|
||||
SET_PERI_REG_MASK(SPI_USER_REG(0), SPI_CS_HOLD);
|
||||
// Set cs time.
|
||||
SET_PERI_REG_BITS(SPI_CTRL2_REG(0), SPI_HOLD_TIME_V, 1, SPI_HOLD_TIME_S);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // CONFIG_SPIRAM_SUPPORT
|
||||
|
||||
@@ -26,6 +26,11 @@ typedef enum {
|
||||
PSRAM_CACHE_MAX,
|
||||
} psram_cache_mode_t;
|
||||
|
||||
typedef enum {
|
||||
PSRAM_SIZE_32MBITS = 0,
|
||||
PSRAM_SIZE_64MBITS = 1,
|
||||
PSRAM_SIZE_MAX,
|
||||
} psram_size_t;
|
||||
|
||||
/*
|
||||
See the TRM, chapter PID/MPU/MMU, header 'External RAM' for the definitions of these modes.
|
||||
@@ -34,12 +39,21 @@ Important is that NORMAL works with the app CPU cache disabled, but gives huge c
|
||||
issues when both app and pro CPU are enabled. LOWHIGH and EVENODD do not have these coherency
|
||||
issues but cannot be used when the app CPU cache is disabled.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
PSRAM_VADDR_MODE_NORMAL=0, ///< App and pro CPU use their own flash cache for external RAM access
|
||||
PSRAM_VADDR_MODE_LOWHIGH, ///< App and pro CPU share external RAM caches: pro CPU has low 2M, app CPU has high 2M
|
||||
PSRAM_VADDR_MODE_EVENODD, ///< App and pro CPU share external RAM caches: pro CPU does even 32yte ranges, app does odd ones.
|
||||
} psram_vaddr_mode_t;
|
||||
|
||||
/**
|
||||
* @brief get psram size
|
||||
* @return
|
||||
* - PSRAM_SIZE_MAX if psram not enabled or not valid
|
||||
* - PSRAM size
|
||||
*/
|
||||
psram_size_t psram_get_size();
|
||||
|
||||
/**
|
||||
* @brief psram cache enable function
|
||||
*
|
||||
|
||||
@@ -147,7 +147,7 @@ esp_err_t esp_efuse_mac_get_default(uint8_t* mac)
|
||||
esp_err_t system_efuse_read_mac(uint8_t *mac) __attribute__((alias("esp_efuse_mac_get_default")));
|
||||
esp_err_t esp_efuse_read_mac(uint8_t *mac) __attribute__((alias("esp_efuse_mac_get_default")));
|
||||
|
||||
esp_err_t esp_derive_mac(uint8_t* local_mac, const uint8_t* universal_mac)
|
||||
esp_err_t esp_derive_local_mac(uint8_t* local_mac, const uint8_t* universal_mac)
|
||||
{
|
||||
uint8_t idx;
|
||||
|
||||
@@ -201,7 +201,7 @@ esp_err_t esp_read_mac(uint8_t* mac, esp_mac_type_t type)
|
||||
mac[5] += 1;
|
||||
}
|
||||
else if (UNIVERSAL_MAC_ADDR_NUM == TWO_UNIVERSAL_MAC_ADDR) {
|
||||
esp_derive_mac(mac, efuse_mac);
|
||||
esp_derive_local_mac(mac, efuse_mac);
|
||||
}
|
||||
break;
|
||||
case ESP_MAC_BT:
|
||||
@@ -220,7 +220,7 @@ esp_err_t esp_read_mac(uint8_t* mac, esp_mac_type_t type)
|
||||
}
|
||||
else if (UNIVERSAL_MAC_ADDR_NUM == TWO_UNIVERSAL_MAC_ADDR) {
|
||||
efuse_mac[5] += 1;
|
||||
esp_derive_mac(mac, efuse_mac);
|
||||
esp_derive_local_mac(mac, efuse_mac);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
Submodule components/esptool_py/esptool updated: 4dab24e1b2...59b8dd8bfe
@@ -107,6 +107,23 @@ config LWIP_ETHARP_TRUST_IP_MAC
|
||||
So the recommendation is to disable this option.
|
||||
Here the LAN peer means the other side to which the ESP station or soft-AP is connected.
|
||||
|
||||
config ESP_GRATUITOUS_ARP
|
||||
bool "Send gratuitous ARP periodically"
|
||||
default y
|
||||
help
|
||||
Enable this option allows to send gratuitous ARP periodically.
|
||||
|
||||
This option solve the compatibility issues.If the ARP table of the AP is old, and the AP
|
||||
doesn't send ARP request to update it's ARP table, this will lead to the STA sending IP packet fail.
|
||||
Thus we send gratuitous ARP periodically to let AP update it's ARP table.
|
||||
|
||||
config GARP_TMR_INTERVAL
|
||||
int "GARP timer interval(seconds)"
|
||||
default 60
|
||||
depends on ESP_GRATUITOUS_ARP
|
||||
help
|
||||
Set the timer interval for gratuitous ARP. The default value is 60s
|
||||
|
||||
config TCPIP_RECVMBOX_SIZE
|
||||
int "TCPIP task receive mail box size"
|
||||
default 32
|
||||
|
||||
@@ -945,38 +945,33 @@ lwip_netconn_do_close_internal(struct netconn *conn WRITE_DELAYED_PARAM SIG_CLO
|
||||
#endif /* LWIP_SO_LINGER */
|
||||
} else {
|
||||
if (err == ERR_MEM) {
|
||||
/* Closing failed because of memory shortage */
|
||||
if (netconn_is_nonblocking(conn)) {
|
||||
/* Nonblocking close failed */
|
||||
close_finished = 1;
|
||||
err = ERR_WOULDBLOCK;
|
||||
} else {
|
||||
/* Blocking close, check the timeout */
|
||||
/* Closing failed because of memory shortage, try again later. Even for
|
||||
nonblocking netconns, we have to wait since no standard socket application
|
||||
is prepared for close failing because of resource shortage.
|
||||
Check the timeout: this is kind of an lwip addition to the standard sockets:
|
||||
we wait for some time when failing to allocate a segment for the FIN */
|
||||
#if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
|
||||
s32_t close_timeout = LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT;
|
||||
/* this is kind of an lwip addition to the standard sockets: we wait
|
||||
for some time when failing to allocate a segment for the FIN */
|
||||
s32_t close_timeout = LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT;
|
||||
#if LWIP_SO_SNDTIMEO
|
||||
if (conn->send_timeout > 0) {
|
||||
close_timeout = conn->send_timeout;
|
||||
}
|
||||
if (conn->send_timeout > 0) {
|
||||
close_timeout = conn->send_timeout;
|
||||
}
|
||||
#endif /* LWIP_SO_SNDTIMEO */
|
||||
#if LWIP_SO_LINGER
|
||||
if (conn->linger >= 0) {
|
||||
/* use linger timeout (seconds) */
|
||||
close_timeout = conn->linger * 1000U;
|
||||
}
|
||||
if (conn->linger >= 0) {
|
||||
/* use linger timeout (seconds) */
|
||||
close_timeout = conn->linger * 1000U;
|
||||
}
|
||||
#endif
|
||||
if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >= close_timeout) {
|
||||
if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >= close_timeout) {
|
||||
#else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
|
||||
if (conn->current_msg->msg.sd.polls_left == 0) {
|
||||
if (conn->current_msg->msg.sd.polls_left == 0) {
|
||||
#endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
|
||||
close_finished = 1;
|
||||
if (close) {
|
||||
/* in this case, we want to RST the connection */
|
||||
tcp_abort(tpcb);
|
||||
err = ERR_OK;
|
||||
}
|
||||
close_finished = 1;
|
||||
if (close) {
|
||||
/* in this case, we want to RST the connection */
|
||||
tcp_abort(tpcb);
|
||||
err = ERR_OK;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -266,11 +266,11 @@ do{\
|
||||
}\
|
||||
}while(0)
|
||||
|
||||
#define LWIP_SET_CLOSE_FLAG(_flag) \
|
||||
#define LWIP_SET_CLOSE_FLAG() \
|
||||
do{\
|
||||
LWIP_SOCK_LOCK(__sock);\
|
||||
LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("mark sock closing\n"));\
|
||||
__sock->state = (_flag);\
|
||||
__sock->state = LWIP_SOCK_CLOSING;\
|
||||
LWIP_SOCK_UNLOCK(__sock);\
|
||||
}while(0)
|
||||
|
||||
@@ -3312,11 +3312,8 @@ int
|
||||
lwip_close_r(int s)
|
||||
{
|
||||
LWIP_API_LOCK();
|
||||
LWIP_SET_CLOSE_FLAG(LWIP_SOCK_CLOSING);
|
||||
LWIP_SET_CLOSE_FLAG();
|
||||
__ret = lwip_close(s);
|
||||
if (EWOULDBLOCK == __sock->err) {
|
||||
LWIP_SET_CLOSE_FLAG(LWIP_SOCK_OPEN);
|
||||
}
|
||||
LWIP_API_UNLOCK();
|
||||
}
|
||||
|
||||
|
||||
@@ -332,6 +332,16 @@ netif_set_addr(struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *
|
||||
|
||||
#endif /* LWIP_IPV4*/
|
||||
|
||||
/**
|
||||
* Set the netif flags for GARP
|
||||
*/
|
||||
#if ESP_GRATUITOUS_ARP
|
||||
void netif_set_garp_flag(struct netif *netif)
|
||||
{
|
||||
netif->flags |= NETIF_FLAG_GARP;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Remove a network interface from the list of lwIP netifs.
|
||||
*
|
||||
|
||||
@@ -70,6 +70,10 @@
|
||||
extern void dhcps_coarse_tmr(void);
|
||||
#endif
|
||||
|
||||
#if ESP_GRATUITOUS_ARP
|
||||
extern void garp_tmr(void);
|
||||
#endif
|
||||
|
||||
/** This array contains all stack-internal cyclic timers. To get the number of
|
||||
* timers, use LWIP_ARRAYSIZE() */
|
||||
const struct lwip_cyclic_timer lwip_cyclic_timers[] = {
|
||||
@@ -84,6 +88,9 @@ const struct lwip_cyclic_timer lwip_cyclic_timers[] = {
|
||||
#endif /* IP_REASSEMBLY */
|
||||
#if LWIP_ARP
|
||||
{ARP_TMR_INTERVAL, HANDLER(etharp_tmr)},
|
||||
#if ESP_GRATUITOUS_ARP
|
||||
{GARP_TMR_INTERVAL, HANDLER(garp_tmr)},
|
||||
#endif
|
||||
#endif /* LWIP_ARP */
|
||||
#if LWIP_DHCP
|
||||
{DHCP_COARSE_TIMER_MSECS, HANDLER(dhcp_coarse_tmr)},
|
||||
|
||||
@@ -99,6 +99,11 @@ extern "C" {
|
||||
* Set by the netif driver in its init function. */
|
||||
#define NETIF_FLAG_MLD6 0x40U
|
||||
|
||||
#if ESP_GRATUITOUS_ARP
|
||||
/** If set, the netif will send gratuitous ARP periodically */
|
||||
#define NETIF_FLAG_GARP 0x80U
|
||||
#endif
|
||||
|
||||
#if LWIP_CHECKSUM_CTRL_PER_NETIF
|
||||
#define NETIF_CHECKSUM_GEN_IP 0x0001
|
||||
#define NETIF_CHECKSUM_GEN_UDP 0x0002
|
||||
@@ -362,6 +367,11 @@ struct netif *netif_add(struct netif *netif,
|
||||
void netif_set_addr(struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *netmask,
|
||||
const ip4_addr_t *gw);
|
||||
#endif /* LWIP_IPV4 */
|
||||
|
||||
#if ESP_GRATUITOUS_ARP
|
||||
void netif_set_garp_flag(struct netif *netif);
|
||||
#endif
|
||||
|
||||
void netif_remove(struct netif * netif);
|
||||
|
||||
/* Returns a network interface given its name. The name is of the form
|
||||
|
||||
@@ -318,8 +318,12 @@
|
||||
* The formula expects settings to be either '0' or '1'.
|
||||
*/
|
||||
#ifndef MEMP_NUM_SYS_TIMEOUT
|
||||
#if ESP_LWIP
|
||||
#define MEMP_NUM_SYS_TIMEOUT (LWIP_TCP + IP_REASSEMBLY + (LWIP_ARP + (ESP_GRATUITOUS_ARP ? 1 : 0)) + (2*LWIP_DHCP + (ESP_DHCPS_TIMER ? 1 : 0)) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + (PPP_SUPPORT*6*MEMP_NUM_PPP_PCB) + (LWIP_IPV6 ? (1 + LWIP_IPV6_REASS + LWIP_IPV6_MLD) : 0))
|
||||
#else
|
||||
#define MEMP_NUM_SYS_TIMEOUT (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + (PPP_SUPPORT*6*MEMP_NUM_PPP_PCB) + (LWIP_IPV6 ? (1 + LWIP_IPV6_REASS + LWIP_IPV6_MLD) : 0))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* MEMP_NUM_NETBUF: the number of struct netbufs.
|
||||
|
||||
@@ -102,6 +102,11 @@ struct etharp_q_entry {
|
||||
};
|
||||
#endif /* ARP_QUEUEING */
|
||||
|
||||
#if ESP_GRATUITOUS_ARP
|
||||
#define GARP_TMR_INTERVAL (CONFIG_GARP_TMR_INTERVAL*1000UL)
|
||||
void garp_tmr(void);
|
||||
#endif
|
||||
|
||||
#define etharp_init() /* Compatibility define, no init needed. */
|
||||
void etharp_tmr(void);
|
||||
s8_t etharp_find_addr(struct netif *netif, const ip4_addr_t *ipaddr,
|
||||
|
||||
@@ -732,6 +732,7 @@
|
||||
#define ESP_DHCP_TIMER 1
|
||||
#define ESP_LWIP_LOGI(...) ESP_LOGI("lwip", __VA_ARGS__)
|
||||
#define ESP_PING 1
|
||||
#define ESP_GRATUITOUS_ARP CONFIG_ESP_GRATUITOUS_ARP
|
||||
|
||||
#define TCP_WND_DEFAULT CONFIG_TCP_WND_DEFAULT
|
||||
#define TCP_SND_BUF_DEFAULT CONFIG_TCP_SND_BUF_DEFAULT
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
#include "lwip/snmp.h"
|
||||
#include "lwip/dhcp.h"
|
||||
#include "lwip/autoip.h"
|
||||
#include "lwip/netif.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@@ -129,6 +130,20 @@ static u8_t etharp_cached_entry;
|
||||
|
||||
static err_t etharp_request_dst(struct netif *netif, const ip4_addr_t *ipaddr, const struct eth_addr* hw_dst_addr);
|
||||
|
||||
#if ESP_GRATUITOUS_ARP
|
||||
void garp_tmr(void)
|
||||
{
|
||||
struct netif* garp_netif = NULL;
|
||||
|
||||
for (garp_netif = netif_list; garp_netif != NULL; garp_netif = garp_netif->next) {
|
||||
if (netif_is_up(garp_netif) && netif_is_link_up(garp_netif) && !ip4_addr_isany_val(*netif_ip4_addr(garp_netif))) {
|
||||
if ((garp_netif->flags & NETIF_FLAG_ETHARP) && (garp_netif->flags & NETIF_FLAG_GARP)) {
|
||||
etharp_gratuitous(garp_netif);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ARP_QUEUEING
|
||||
/**
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "lwip/ip6_addr.h"
|
||||
#include "lwip/nd6.h"
|
||||
#include "lwip/priv/tcpip_priv.h"
|
||||
#include "lwip/netif.h"
|
||||
#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
|
||||
#include "lwip/dns.h"
|
||||
#endif
|
||||
@@ -175,6 +176,11 @@ esp_err_t tcpip_adapter_start(tcpip_adapter_if_t tcpip_if, uint8_t *mac, tcpip_a
|
||||
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 ESP_GRATUITOUS_ARP
|
||||
if (tcpip_if == TCPIP_ADAPTER_IF_STA || tcpip_if == TCPIP_ADAPTER_IF_ETH) {
|
||||
netif_set_garp_flag(esp_netif[tcpip_if]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (tcpip_if == TCPIP_ADAPTER_IF_AP) {
|
||||
|
||||
14
tools/ci/push_to_github.sh
Executable file
14
tools/ci/push_to_github.sh
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
|
||||
# gitlab-ci script to push current tested revision (tag or branch) to github
|
||||
|
||||
set -ex
|
||||
|
||||
if [ -n "${CI_COMMIT_TAG}" ]; then
|
||||
# for tags
|
||||
git push github "${CI_COMMIT_TAG}"
|
||||
else
|
||||
# for branches
|
||||
git push github "${CI_COMMIT_SHA}:refs/heads/${CI_COMMIT_REF_NAME}"
|
||||
fi
|
||||
|
||||
49
tools/ci/setup_python.sh
Normal file
49
tools/ci/setup_python.sh
Normal file
@@ -0,0 +1,49 @@
|
||||
#! /bin/bash
|
||||
|
||||
# Regexp for matching job names which are incompatible with Python 3
|
||||
py3_incomp='assign_test|UT|IT'
|
||||
|
||||
if [ -z ${PYTHON_VER+x} ] || [[ $CI_JOB_NAME =~ $py3_incomp ]]; then
|
||||
# Use this version of the Python interpreter if it was not defined before or
|
||||
# the given job is not compatible with Python 3
|
||||
PYTHON_VER=2.7.15
|
||||
fi
|
||||
|
||||
if [ -f /opt/pyenv/activate ];
|
||||
then
|
||||
source /opt/pyenv/activate
|
||||
pyenv global $PYTHON_VER || {
|
||||
echo 'Python' $PYTHON_VER 'is not installed.'
|
||||
INSTALLED_PY_VERS=$(pyenv versions --bare)
|
||||
|
||||
while [ ${#PYTHON_VER} -gt 0 ]
|
||||
do
|
||||
echo 'Tring to locate a match for' $PYTHON_VER
|
||||
|
||||
for ver in ${INSTALLED_PY_VERS[@]}
|
||||
do
|
||||
if [[ $ver == $PYTHON_VER* ]];
|
||||
then
|
||||
pyenv global $ver
|
||||
break 2
|
||||
fi
|
||||
done
|
||||
|
||||
# Removing last character and trying to find some match.
|
||||
# For example, if 3.4.8 was selected but isn't installed then it will try to
|
||||
# find some other installed 3.4.X version, and then some 3.X.X version.
|
||||
PYTHON_VER=${PYTHON_VER: : -1}
|
||||
done
|
||||
}
|
||||
python --version || {
|
||||
echo 'No matching Python interpreter is found!'
|
||||
exit 1
|
||||
}
|
||||
elif command -v python -V 1>/dev/null 2>&1;
|
||||
then
|
||||
python --version
|
||||
echo 'No /opt/pyenv/activate exists and Python from path is used.'
|
||||
else
|
||||
echo 'No /opt/pyenv/activate exists and no Python interpreter is found!'
|
||||
exit 1
|
||||
fi
|
||||
Reference in New Issue
Block a user