Add essl to component manager
This commit is contained in:
parent
f09da9b79a
commit
fe588a4815
|
@ -15,6 +15,6 @@ jobs:
|
|||
- name: Upload components to component service
|
||||
uses: espressif/upload-components-ci-action@v1
|
||||
with:
|
||||
directories: "bdc_motor;cbor;jsmn;led_strip;libsodium;pid_ctrl;qrcode;nghttp;sh2lib;expat;esp_encrypted_img;coap;pcap;json_generator;json_parser;usb/usb_host_cdc_acm;usb/usb_host_msc;usb/usb_host_uvc"
|
||||
directories: "bdc_motor;cbor;jsmn;led_strip;libsodium;pid_ctrl;qrcode;nghttp;sh2lib;expat;esp_encrypted_img;coap;pcap;json_generator;json_parser;usb/usb_host_cdc_acm;usb/usb_host_msc;usb/usb_host_uvc;esp_serial_slave_link"
|
||||
namespace: "espressif"
|
||||
api_token: ${{ secrets.IDF_COMPONENT_API_TOKEN }}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
idf_component_register(SRCS "essl.c"
|
||||
"essl_sdio.c"
|
||||
"essl_spi.c"
|
||||
INCLUDE_DIRS "include"
|
||||
REQUIRES "sdmmc"
|
||||
"driver"
|
||||
PRIV_INCLUDE_DIRS "."
|
||||
"include/esp_serial_slave_link"
|
||||
)
|
|
@ -0,0 +1,202 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
|
@ -0,0 +1,9 @@
|
|||
# Espressif Serial Slave Link (ESSL) component
|
||||
|
||||
This component used to reside in [esp-idf](https://github.com/espressif/esp-idf) project as its component.
|
||||
|
||||
It's used on the HOST, to communicate with ESP chips as SLAVE via SDIO/SPI slave HD mode.
|
||||
|
||||
The port layer (`essl_sdio.c/essl_spi.c`) are currently only written to run on ESP chips in master mode, but you may also modify them to work on more platforms.
|
||||
|
||||
See more documentation: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/protocols/esp_serial_slave_link.html
|
|
@ -0,0 +1,234 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include "essl.h"
|
||||
#include "essl_internal.h"
|
||||
|
||||
#define TIME_EXPIRED_SINCE_CORE(start, end, timeout, max) (bool)((end)>=(start)? \
|
||||
((end)-(start)>(timeout)) :\
|
||||
((max)-(timeout)>(start)-(end)))
|
||||
|
||||
#define TIME_EXPIRED_SINCE(start, end, timeout) TIME_EXPIRED_SINCE_CORE(start, end, timeout, UINT32_MAX)
|
||||
|
||||
#define MINUS_UNTIL_ZERO(a, b) ( ((a) > (b)) ? ((a)-(b)): 0)
|
||||
|
||||
#define TIME_REMAIN_CORE(start, end, timeout, max) ((end)>=(start)?\
|
||||
MINUS_UNTIL_ZERO(timeout, (end)-(start)):\
|
||||
MINUS_UNTIL_ZERO((start)-(end), (max)-(timeout)))
|
||||
|
||||
#define TIME_REMAIN(start, end, timeout) TIME_REMAIN_CORE(start, end, timeout, UINT32_MAX)
|
||||
|
||||
|
||||
#define ESSL_MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
__attribute__((unused)) static const char TAG[] = "esp_serial_slave_link";
|
||||
|
||||
#define _CHECK_EXECUTE_CMD(DEV, CMD, STR, ...) do{ \
|
||||
if ((DEV) == NULL) { \
|
||||
return ESP_ERR_INVALID_ARG; \
|
||||
} \
|
||||
if ((DEV)->CMD) { \
|
||||
return (DEV)->CMD((DEV)->args,##__VA_ARGS__); \
|
||||
} else { \
|
||||
ESP_LOGE(TAG, STR); \
|
||||
return ESP_ERR_NOT_SUPPORTED; \
|
||||
} } while(0)
|
||||
|
||||
#define CHECK_EXECUTE_CMD(DEV, CMD, ...) _CHECK_EXECUTE_CMD(DEV, CMD, #CMD" not supported for the current device.",##__VA_ARGS__)
|
||||
|
||||
|
||||
esp_err_t essl_init(essl_handle_t handle, uint32_t wait_ms)
|
||||
{
|
||||
CHECK_EXECUTE_CMD(handle, init, wait_ms);
|
||||
}
|
||||
|
||||
esp_err_t essl_wait_for_ready(essl_handle_t handle, uint32_t wait_ms)
|
||||
{
|
||||
CHECK_EXECUTE_CMD(handle, wait_for_ready, wait_ms);
|
||||
}
|
||||
|
||||
esp_err_t essl_send_packet(essl_handle_t handle, const void *start, size_t length, uint32_t wait_ms)
|
||||
{
|
||||
if (handle == NULL || start == NULL || length == 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (handle->send_packet == NULL) {
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
esp_err_t err;
|
||||
const uint32_t timeout_ticks = pdMS_TO_TICKS(wait_ms);
|
||||
|
||||
uint32_t pre = xTaskGetTickCount();
|
||||
uint32_t now;
|
||||
uint32_t remain_wait_ms = 0;
|
||||
|
||||
do {
|
||||
now = xTaskGetTickCount();
|
||||
remain_wait_ms = pdTICKS_TO_MS(TIME_REMAIN(pre, now, timeout_ticks));
|
||||
err = handle->send_packet(handle->args, start, length, remain_wait_ms);
|
||||
if (err == ESP_OK) {
|
||||
break;
|
||||
} else if (err != ESP_ERR_NOT_FOUND) {
|
||||
return err;
|
||||
} // else ESP_ERR_NOT_FOUND
|
||||
//the slave is not ready, retry
|
||||
} while (remain_wait_ms > 0);
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t essl_get_packet(essl_handle_t handle, void *out_data, size_t size, size_t *out_length, uint32_t wait_ms)
|
||||
{
|
||||
if (handle == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (out_data == NULL || size == 0 || out_length == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (handle->get_packet == NULL || handle->update_rx_data_size == NULL || handle->get_rx_data_size == NULL) {
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
esp_err_t err;
|
||||
const uint32_t timeout_ticks = pdMS_TO_TICKS(wait_ms);
|
||||
|
||||
uint32_t pre = xTaskGetTickCount();
|
||||
uint32_t now = 3;
|
||||
uint32_t wait_remain_ms = 0;
|
||||
int data_available = handle->get_rx_data_size(handle->args);
|
||||
|
||||
// if there is already enough data to read, skip the length update.
|
||||
if (data_available < size) {
|
||||
//loop until timeout, or there is at least one byte
|
||||
do {
|
||||
now = xTaskGetTickCount();
|
||||
wait_remain_ms = pdTICKS_TO_MS(TIME_REMAIN(pre, now, timeout_ticks));
|
||||
err = handle->update_rx_data_size(handle->args, wait_remain_ms);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
data_available = handle->get_rx_data_size(handle->args);
|
||||
if (data_available > 0) {
|
||||
break;
|
||||
}
|
||||
} while (wait_remain_ms > 0);
|
||||
}
|
||||
|
||||
if (data_available == 0) {
|
||||
//the slave has no data to send
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
int len = ESSL_MIN(data_available, size);
|
||||
now = xTaskGetTickCount();
|
||||
wait_remain_ms = pdTICKS_TO_MS(TIME_REMAIN(pre, now, timeout_ticks));
|
||||
err = handle->get_packet(handle->args, out_data, len, wait_remain_ms);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
*out_length = len;
|
||||
if (len < data_available) {
|
||||
return ESP_ERR_NOT_FINISHED;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t essl_get_tx_buffer_num(essl_handle_t handle, uint32_t *out_tx_num, uint32_t wait_ms)
|
||||
{
|
||||
if (handle == NULL || out_tx_num == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (handle->update_tx_buffer_num == NULL || handle->get_tx_buffer_num == NULL) {
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
esp_err_t err = handle->update_tx_buffer_num(handle->args, wait_ms);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
*out_tx_num = handle->get_tx_buffer_num(handle->args);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t essl_get_rx_data_size(essl_handle_t handle, uint32_t *out_rx_size, uint32_t wait_ms)
|
||||
{
|
||||
if (handle == NULL || out_rx_size == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (handle->update_rx_data_size == NULL || handle->get_rx_data_size == NULL) {
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
esp_err_t err = handle->update_rx_data_size(handle->args, wait_ms);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
*out_rx_size = handle->get_rx_data_size(handle->args);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t essl_write_reg(essl_handle_t handle, uint8_t addr, uint8_t value, uint8_t *value_o, uint32_t wait_ms)
|
||||
{
|
||||
CHECK_EXECUTE_CMD(handle, write_reg, addr, value, value_o, wait_ms);
|
||||
}
|
||||
|
||||
esp_err_t essl_read_reg(essl_handle_t handle, uint8_t add, uint8_t *value_o, uint32_t wait_ms)
|
||||
{
|
||||
CHECK_EXECUTE_CMD(handle, read_reg, add, value_o, wait_ms);
|
||||
}
|
||||
|
||||
esp_err_t essl_wait_int(essl_handle_t handle, TickType_t wait_ms)
|
||||
{
|
||||
CHECK_EXECUTE_CMD(handle, wait_int, wait_ms);
|
||||
}
|
||||
|
||||
esp_err_t essl_reset_cnt(essl_handle_t handle)
|
||||
{
|
||||
if (handle == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (handle->reset_cnt == NULL) {
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
handle->reset_cnt(handle->args);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t essl_clear_intr(essl_handle_t handle, uint32_t intr_mask, uint32_t wait_ms)
|
||||
{
|
||||
CHECK_EXECUTE_CMD(handle, clear_intr, intr_mask, wait_ms);
|
||||
}
|
||||
|
||||
esp_err_t essl_get_intr(essl_handle_t handle, uint32_t *intr_raw, uint32_t *intr_st, uint32_t wait_ms)
|
||||
{
|
||||
if (intr_raw == NULL && intr_st == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
CHECK_EXECUTE_CMD(handle, get_intr, intr_raw, intr_st, wait_ms);
|
||||
}
|
||||
|
||||
esp_err_t essl_set_intr_ena(essl_handle_t handle, uint32_t ena_mask, uint32_t wait_ms)
|
||||
{
|
||||
CHECK_EXECUTE_CMD(handle, set_intr_ena, ena_mask, wait_ms);
|
||||
}
|
||||
|
||||
esp_err_t essl_get_intr_ena(essl_handle_t handle, uint32_t *ena_mask_o, uint32_t wait_ms)
|
||||
{
|
||||
if (ena_mask_o == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
CHECK_EXECUTE_CMD(handle, get_intr_ena, ena_mask_o, wait_ms);
|
||||
}
|
||||
|
||||
esp_err_t essl_send_slave_intr(essl_handle_t handle, uint32_t intr_mask, uint32_t wait_ms)
|
||||
{
|
||||
CHECK_EXECUTE_CMD(handle, send_slave_intr, intr_mask, wait_ms);
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <esp_types.h>
|
||||
#include <esp_err.h>
|
||||
|
||||
/** Context used by the ``esp_serial_slave_link`` component.
|
||||
*/
|
||||
struct essl_dev_t {
|
||||
void *args;
|
||||
|
||||
esp_err_t (*init)(void *ctx, uint32_t wait_ms);
|
||||
|
||||
esp_err_t (*wait_for_ready)(void *ctx, uint32_t wait_ms);
|
||||
esp_err_t (*update_tx_buffer_num)(void *ctx, uint32_t wait_ms);
|
||||
esp_err_t (*update_rx_data_size)(void *ctx, uint32_t wait_ms);
|
||||
esp_err_t (*send_packet)(void *ctx, const void *start, size_t length, uint32_t wait_ms);
|
||||
esp_err_t (*get_packet)(void *ctx, void *out_data, size_t size, uint32_t wait_ms);
|
||||
esp_err_t (*write_reg)(void *ctx, uint8_t addr, uint8_t value, uint8_t *value_o, uint32_t wait_ms);
|
||||
esp_err_t (*read_reg)(void *ctx, uint8_t add, uint8_t *value_o, uint32_t wait_ms);
|
||||
esp_err_t (*wait_int)(void *ctx, uint32_t wait_ms);
|
||||
esp_err_t (*clear_intr)(void *ctx, uint32_t intr_mask, uint32_t wait_ms);
|
||||
esp_err_t (*get_intr)(void *ctx, uint32_t *intr_raw, uint32_t *intr_st, uint32_t wait_ms);
|
||||
esp_err_t (*set_intr_ena)(void *ctx, uint32_t ena_mask, uint32_t wait_ms);
|
||||
esp_err_t (*get_intr_ena)(void *ctx, uint32_t *ena_mask_o, uint32_t wait_ms);
|
||||
esp_err_t (*send_slave_intr)(void *ctx, uint32_t intr_mask, uint32_t wait_ms);
|
||||
|
||||
uint32_t (*get_tx_buffer_num)(void *ctx);
|
||||
uint32_t (*get_rx_data_size)(void *ctx);
|
||||
void (*reset_cnt)(void *ctx);
|
||||
};
|
||||
|
||||
typedef struct essl_dev_t essl_dev_t;
|
|
@ -0,0 +1,499 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "soc/soc_caps.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdmmc_cmd.h"
|
||||
#include "driver/sdmmc_defs.h"
|
||||
|
||||
#include "essl_internal.h"
|
||||
#include "essl_sdio.h"
|
||||
|
||||
#if SOC_SDIO_SLAVE_SUPPORTED
|
||||
#include "soc/host_reg.h"
|
||||
|
||||
static const char TAG[] = "essl_sdio";
|
||||
|
||||
#define HOST_SLCHOST_CONF_W_REG(pos) (HOST_SLCHOST_CONF_W0_REG+pos+(pos>23?4:0)+(pos>31?12:0))
|
||||
|
||||
#define ESSL_CMD53_END_ADDR 0x1f800
|
||||
|
||||
#define TX_BUFFER_MAX 0x1000
|
||||
#define TX_BUFFER_MASK 0xFFF
|
||||
#define RX_BYTE_MAX 0x100000
|
||||
#define RX_BYTE_MASK 0xFFFFF
|
||||
|
||||
#define FUNC1_EN_MASK (BIT(1))
|
||||
|
||||
/**
|
||||
* Initialize ``void`` over SDIO by this macro.
|
||||
*/
|
||||
#define ESSL_SDIO_DEFAULT_CONTEXT() (essl_dev_t){\
|
||||
.init = essl_sdio_init, \
|
||||
.wait_for_ready = essl_sdio_wait_for_ready, \
|
||||
.get_tx_buffer_num = essl_sdio_get_tx_buffer_num,\
|
||||
.update_tx_buffer_num = essl_sdio_update_tx_buffer_num,\
|
||||
.get_rx_data_size = essl_sdio_get_rx_data_size,\
|
||||
.update_rx_data_size = essl_sdio_update_rx_data_size,\
|
||||
.send_packet = essl_sdio_send_packet,\
|
||||
.get_packet = essl_sdio_get_packet,\
|
||||
.write_reg = essl_sdio_write_reg,\
|
||||
.read_reg = essl_sdio_read_reg,\
|
||||
.wait_int = essl_sdio_wait_int,\
|
||||
.send_slave_intr = essl_sdio_send_slave_intr, \
|
||||
.get_intr = essl_sdio_get_intr, \
|
||||
.clear_intr = essl_sdio_clear_intr, \
|
||||
.set_intr_ena = essl_sdio_set_intr_ena, \
|
||||
.reset_cnt = essl_sdio_reset_cnt, \
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
//common part
|
||||
uint16_t buffer_size;
|
||||
///< All data that do not fully fill a buffer is still counted as one buffer. E.g. 10 bytes data costs 2 buffers if the size is 8 bytes per buffer.
|
||||
///< Buffer size of the slave pre-defined between host and slave before communication.
|
||||
size_t tx_sent_buffers; ///< Counter holding the amount of buffers already sent to ESP32 slave. Should be set to 0 when initialization.
|
||||
size_t tx_sent_buffers_latest; ///< The latest reading (from the slave) of counter holding the amount of buffers loaded. Should be set to 0 when initialization.
|
||||
size_t rx_got_bytes; ///< Counter holding the amount of bytes already received from ESP32 slave. Should be set to 0 when initialization.
|
||||
size_t rx_got_bytes_latest; ///< The latest reading (from the slave) of counter holding the amount of bytes to send. Should be set to 0 when initialization.
|
||||
|
||||
sdmmc_card_t *card; ///< Initialized sdmmc_cmd card
|
||||
uint16_t block_size;
|
||||
///< If this is too large, it takes time to send stuff bits; while if too small, intervals between blocks cost much.
|
||||
///< Should be set according to length of data, and larger than ``TRANS_LEN_MAX/511``.
|
||||
///< Block size of the SDIO function 1. After the initialization this will hold the value the slave really do. Valid value is 1-2048.
|
||||
} essl_sdio_context_t;
|
||||
|
||||
|
||||
esp_err_t essl_sdio_update_tx_buffer_num(void *arg, uint32_t wait_ms);
|
||||
esp_err_t essl_sdio_update_rx_data_size(void *arg, uint32_t wait_ms);
|
||||
|
||||
static inline esp_err_t essl_sdio_write_byte(sdmmc_card_t *card, uint32_t addr, uint8_t val, uint8_t *val_o)
|
||||
{
|
||||
return sdmmc_io_write_byte(card, 1, addr & 0x3FF, val, val_o);
|
||||
}
|
||||
|
||||
static inline esp_err_t essl_sdio_write_bytes(sdmmc_card_t *card, uint32_t addr, uint8_t *val, int len)
|
||||
{
|
||||
return sdmmc_io_write_bytes(card, 1, addr & 0x3FF, val, len);
|
||||
}
|
||||
|
||||
static inline esp_err_t essl_sdio_read_byte(sdmmc_card_t *card, uint32_t addr, uint8_t *val_o)
|
||||
{
|
||||
return sdmmc_io_read_byte(card, 1, addr & 0x3FF, val_o);
|
||||
}
|
||||
|
||||
static inline esp_err_t essl_sdio_read_bytes(sdmmc_card_t *card, uint32_t addr, uint8_t *val_o, int len)
|
||||
{
|
||||
return sdmmc_io_read_bytes(card, 1, addr & 0x3FF, val_o, len);
|
||||
}
|
||||
|
||||
esp_err_t essl_sdio_init_dev(essl_handle_t *out_handle, const essl_sdio_config_t *config)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
essl_sdio_context_t *arg = NULL;
|
||||
essl_dev_t *dev = NULL;
|
||||
arg = (essl_sdio_context_t *)heap_caps_malloc(sizeof(essl_sdio_context_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||
dev = (essl_dev_t *)heap_caps_malloc(sizeof(essl_dev_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||
|
||||
if (arg == NULL || dev == NULL) {
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
*dev = ESSL_SDIO_DEFAULT_CONTEXT();
|
||||
dev->args = arg;
|
||||
|
||||
*arg = (essl_sdio_context_t) {
|
||||
.card = config->card,
|
||||
.block_size = 0x200,
|
||||
.buffer_size = config->recv_buffer_size,
|
||||
.tx_sent_buffers = 0,
|
||||
.rx_got_bytes = 0,
|
||||
};
|
||||
|
||||
*out_handle = dev;
|
||||
return ESP_OK;
|
||||
|
||||
cleanup:
|
||||
free(arg);
|
||||
free(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t essl_sdio_deinit_dev(essl_handle_t handle)
|
||||
{
|
||||
if (handle) {
|
||||
free (handle->args);
|
||||
}
|
||||
free(handle);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t essl_sdio_init(void *arg, uint32_t wait_ms)
|
||||
{
|
||||
essl_sdio_context_t *ctx = arg;
|
||||
esp_err_t err;
|
||||
uint8_t ioe = 0;
|
||||
sdmmc_card_t *card = ctx->card;
|
||||
|
||||
err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_FN_ENABLE, &ioe);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
ESP_LOGD(TAG, "IOE: 0x%02"PRIx8, ioe);
|
||||
|
||||
uint8_t ior = 0;
|
||||
err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_FN_READY, &ior);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
ESP_LOGD(TAG, "IOR: 0x%02"PRIx8, ior);
|
||||
|
||||
// enable function 1
|
||||
ioe |= FUNC1_EN_MASK;
|
||||
err = sdmmc_io_write_byte(card, 0, SD_IO_CCCR_FN_ENABLE, ioe, &ioe);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
ESP_LOGD(TAG, "IOE: 0x%02"PRIx8, ioe);
|
||||
|
||||
// wait for the card to become ready
|
||||
while ((ior & FUNC1_EN_MASK) == 0) {
|
||||
err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_FN_READY, &ior);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
ESP_LOGD(TAG, "IOR: 0x%02"PRIx8, ior);
|
||||
}
|
||||
|
||||
// get interrupt status
|
||||
uint8_t ie = 0;
|
||||
err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_INT_ENABLE, &ie);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
ESP_LOGD(TAG, "IE: 0x%02"PRIx8, ie);
|
||||
|
||||
// enable interrupts for function 1&2 and master enable
|
||||
ie |= BIT(0) | FUNC1_EN_MASK;
|
||||
err = sdmmc_io_write_byte(card, 0, SD_IO_CCCR_INT_ENABLE, ie, &ie);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
ESP_LOGD(TAG, "IE: 0x%02"PRIx8, ie);
|
||||
|
||||
// get bus width register
|
||||
uint8_t bus_width = 0;
|
||||
err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_BUS_WIDTH, &bus_width);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
ESP_LOGD(TAG, "BUS_WIDTH: 0x%02"PRIx8, bus_width);
|
||||
|
||||
// enable continuous SPI interrupts
|
||||
bus_width |= CCCR_BUS_WIDTH_ECSI;
|
||||
err = sdmmc_io_write_byte(card, 0, SD_IO_CCCR_BUS_WIDTH, bus_width, &bus_width);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
ESP_LOGD(TAG, "BUS_WIDTH: 0x%02"PRIx8, bus_width);
|
||||
|
||||
uint16_t bs = 512;
|
||||
const uint8_t *bs_u8 = (const uint8_t *) &bs;
|
||||
uint16_t bs_read = 0;
|
||||
uint8_t *bs_read_u8 = (uint8_t *) &bs_read;
|
||||
// Set block sizes for functions 0 to 512 bytes
|
||||
ESP_ERROR_CHECK(sdmmc_io_read_byte(card, 0, SD_IO_CCCR_BLKSIZEL, &bs_read_u8[0]));
|
||||
ESP_ERROR_CHECK(sdmmc_io_read_byte(card, 0, SD_IO_CCCR_BLKSIZEH, &bs_read_u8[1]));
|
||||
ESP_LOGD(TAG, "Function 0 BS: %d", (unsigned int) bs_read);
|
||||
|
||||
ESP_ERROR_CHECK(sdmmc_io_write_byte(card, 0, SD_IO_CCCR_BLKSIZEL, bs_u8[0], NULL));
|
||||
ESP_ERROR_CHECK(sdmmc_io_write_byte(card, 0, SD_IO_CCCR_BLKSIZEH, bs_u8[1], NULL));
|
||||
ESP_ERROR_CHECK(sdmmc_io_read_byte(card, 0, SD_IO_CCCR_BLKSIZEL, &bs_read_u8[0]));
|
||||
ESP_ERROR_CHECK(sdmmc_io_read_byte(card, 0, SD_IO_CCCR_BLKSIZEH, &bs_read_u8[1]));
|
||||
ESP_LOGD(TAG, "Function 0 BS: %d", (unsigned int) bs_read);
|
||||
|
||||
// Set block sizes for functions 1 to given value (default value = 512).
|
||||
if (ctx->block_size > 0 && ctx->block_size <= 2048) {
|
||||
bs = ctx->block_size;
|
||||
} else {
|
||||
bs = 512;
|
||||
}
|
||||
size_t offset = SD_IO_FBR_START * 1;
|
||||
ESP_ERROR_CHECK(sdmmc_io_read_byte(card, 0, offset + SD_IO_CCCR_BLKSIZEL, &bs_read_u8[0]));
|
||||
ESP_ERROR_CHECK(sdmmc_io_read_byte(card, 0, offset + SD_IO_CCCR_BLKSIZEH, &bs_read_u8[1]));
|
||||
ESP_LOGD(TAG, "Function 1 BS: %d", (unsigned int) bs_read);
|
||||
|
||||
ESP_ERROR_CHECK(sdmmc_io_write_byte(card, 0, offset + SD_IO_CCCR_BLKSIZEL, bs_u8[0], NULL));
|
||||
ESP_ERROR_CHECK(sdmmc_io_write_byte(card, 0, offset + SD_IO_CCCR_BLKSIZEH, bs_u8[1], NULL));
|
||||
ESP_ERROR_CHECK(sdmmc_io_read_byte(card, 0, offset + SD_IO_CCCR_BLKSIZEL, &bs_read_u8[0]));
|
||||
ESP_ERROR_CHECK(sdmmc_io_read_byte(card, 0, offset + SD_IO_CCCR_BLKSIZEH, &bs_read_u8[1]));
|
||||
ESP_LOGD(TAG, "Function 1 BS: %d", (unsigned int) bs_read);
|
||||
|
||||
if (bs_read != ctx->block_size) {
|
||||
ESP_LOGW(TAG, "Function1 block size %d different than set value %d", bs_read, ctx->block_size);
|
||||
ctx->block_size = bs_read;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t essl_sdio_wait_for_ready(void *arg, uint32_t wait_ms)
|
||||
{
|
||||
ESP_LOGV(TAG, "wait_for_ioready");
|
||||
esp_err_t err;
|
||||
sdmmc_card_t *card = ((essl_sdio_context_t *)arg)->card;
|
||||
// wait for the card to become ready
|
||||
uint8_t ior = 0;
|
||||
while ((ior & FUNC1_EN_MASK) == 0) {
|
||||
err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_FN_READY, &ior);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
ESP_LOGD(TAG, "IOR: 0x%02x", ior);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t essl_sdio_send_packet(void *arg, const void *start, size_t length, uint32_t wait_ms)
|
||||
{
|
||||
essl_sdio_context_t *ctx = arg;
|
||||
uint16_t buffer_size = ctx->buffer_size;
|
||||
int buffer_used = (length + buffer_size - 1) / buffer_size;
|
||||
esp_err_t err;
|
||||
|
||||
if (essl_sdio_get_tx_buffer_num(arg) < buffer_used) {
|
||||
//slave has no enough buffer, try update for once
|
||||
esp_err_t err = essl_sdio_update_tx_buffer_num(arg, wait_ms);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
if (essl_sdio_get_tx_buffer_num(arg) < buffer_used) {
|
||||
ESP_LOGV(TAG, "buffer is not enough: %d, %d required.", ctx->tx_sent_buffers_latest, ctx->tx_sent_buffers + buffer_used);
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG, "send_packet: len: %d", length);
|
||||
|
||||
uint8_t *start_ptr = (uint8_t *)start;
|
||||
uint32_t len_remain = length;
|
||||
do {
|
||||
const int block_size = 512;
|
||||
/* Though the driver supports to split packet of unaligned size into
|
||||
* length of 4x and 1~3, we still send aligned size of data to get
|
||||
* higher effeciency. The length is determined by the SDIO address, and
|
||||
* the remainning will be discard by the slave hardware.
|
||||
*/
|
||||
int block_n = len_remain / block_size;
|
||||
int len_to_send;
|
||||
if (block_n) {
|
||||
len_to_send = block_n * block_size;
|
||||
err = sdmmc_io_write_blocks(ctx->card, 1, ESSL_CMD53_END_ADDR - len_remain, start_ptr, len_to_send);
|
||||
} else {
|
||||
len_to_send = len_remain;
|
||||
err = sdmmc_io_write_bytes(ctx->card, 1, ESSL_CMD53_END_ADDR - len_remain, start_ptr, (len_to_send + 3) & (~3));
|
||||
}
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
start_ptr += len_to_send;
|
||||
len_remain -= len_to_send;
|
||||
} while (len_remain);
|
||||
|
||||
ctx->tx_sent_buffers += buffer_used;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t essl_sdio_get_packet(void *arg, void *out_data, size_t size, uint32_t wait_ms)
|
||||
{
|
||||
essl_sdio_context_t *ctx = arg;
|
||||
esp_err_t err;
|
||||
|
||||
ESP_LOGV(TAG, "get_packet: read size=%d", size);
|
||||
if (essl_sdio_get_rx_data_size(arg) < size) {
|
||||
err = essl_sdio_update_rx_data_size(arg, wait_ms);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
if (essl_sdio_get_rx_data_size(arg) < size) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *start = out_data;
|
||||
uint32_t len_remain = size;
|
||||
do {
|
||||
const int block_size = 512; //currently our driver don't support block size other than 512
|
||||
int len_to_send;
|
||||
|
||||
int block_n = len_remain / block_size;
|
||||
if (block_n != 0) {
|
||||
len_to_send = block_n * block_size;
|
||||
err = sdmmc_io_read_blocks(ctx->card, 1, ESSL_CMD53_END_ADDR - len_remain, start, len_to_send);
|
||||
} else {
|
||||
len_to_send = len_remain;
|
||||
/* though the driver supports to split packet of unaligned size into length
|
||||
* of 4x and 1~3, we still get aligned size of data to get higher
|
||||
* effeciency. The length is determined by the SDIO address, and the
|
||||
* remainning will be ignored by the slave hardware.
|
||||
*/
|
||||
err = sdmmc_io_read_bytes(ctx->card, 1, ESSL_CMD53_END_ADDR - len_remain, start, (len_to_send + 3) & (~3));
|
||||
}
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
start += len_to_send;
|
||||
len_remain -= len_to_send;
|
||||
ctx->rx_got_bytes += len_to_send;
|
||||
} while (len_remain != 0);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
uint32_t essl_sdio_get_tx_buffer_num(void *arg)
|
||||
{
|
||||
essl_sdio_context_t *ctx = arg;
|
||||
ESP_LOGV(TAG, "tx latest: %d, sent: %d", ctx->tx_sent_buffers_latest, ctx->tx_sent_buffers);
|
||||
return (ctx->tx_sent_buffers_latest + TX_BUFFER_MAX - ctx->tx_sent_buffers) % TX_BUFFER_MAX;
|
||||
}
|
||||
|
||||
esp_err_t essl_sdio_update_tx_buffer_num(void *arg, uint32_t wait_ms)
|
||||
{
|
||||
essl_sdio_context_t *ctx = arg;
|
||||
uint32_t len;
|
||||
esp_err_t err;
|
||||
|
||||
err = essl_sdio_read_bytes(ctx->card, HOST_SLC0HOST_TOKEN_RDATA_REG, (uint8_t *) &len, 4);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
len = (len >> 16)&TX_BUFFER_MASK;
|
||||
ctx->tx_sent_buffers_latest = len;
|
||||
ESP_LOGV(TAG, "update_tx_buffer_num: %d", (unsigned int)len);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
uint32_t essl_sdio_get_rx_data_size(void *arg)
|
||||
{
|
||||
essl_sdio_context_t *ctx = arg;
|
||||
ESP_LOGV(TAG, "rx latest: %d, read: %d", ctx->rx_got_bytes_latest, ctx->rx_got_bytes);
|
||||
return (ctx->rx_got_bytes_latest + RX_BYTE_MAX - ctx->rx_got_bytes) % RX_BYTE_MAX;
|
||||
}
|
||||
|
||||
esp_err_t essl_sdio_update_rx_data_size(void *arg, uint32_t wait_ms)
|
||||
{
|
||||
essl_sdio_context_t *ctx = arg;
|
||||
uint32_t len;
|
||||
esp_err_t err;
|
||||
|
||||
ESP_LOGV(TAG, "get_rx_data_size: got_bytes: %d", ctx->rx_got_bytes);
|
||||
err = essl_sdio_read_bytes(ctx->card, HOST_SLCHOST_PKT_LEN_REG, (uint8_t *) &len, 4);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
len &= RX_BYTE_MASK;
|
||||
ctx->rx_got_bytes_latest = len;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
esp_err_t essl_sdio_write_reg(void *arg, uint8_t addr, uint8_t value, uint8_t *value_o, uint32_t wait_ms)
|
||||
{
|
||||
ESP_LOGV(TAG, "write_reg: 0x%02"PRIX8, value);
|
||||
// addrress over range
|
||||
if (addr >= 60) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
//W7 is reserved for interrupts
|
||||
if (addr >= 28) {
|
||||
addr += 4;
|
||||
}
|
||||
return essl_sdio_write_byte(((essl_sdio_context_t *)arg)->card, HOST_SLCHOST_CONF_W_REG(addr), value, value_o);
|
||||
}
|
||||
|
||||
esp_err_t essl_sdio_read_reg(void *arg, uint8_t add, uint8_t *value_o, uint32_t wait_ms)
|
||||
{
|
||||
ESP_LOGV(TAG, "read_reg");
|
||||
// address over range
|
||||
if (add >= 60) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
//W7 is reserved for interrupts
|
||||
if (add >= 28) {
|
||||
add += 4;
|
||||
}
|
||||
esp_err_t ret = essl_sdio_read_byte(((essl_sdio_context_t *)arg)->card, HOST_SLCHOST_CONF_W_REG(add), value_o);
|
||||
ESP_LOGV(TAG, "reg: %02"PRIX8, *value_o);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t essl_sdio_clear_intr(void *arg, uint32_t intr_mask, uint32_t wait_ms)
|
||||
{
|
||||
ESP_LOGV(TAG, "clear_intr: %08"PRIX32, intr_mask);
|
||||
return essl_sdio_write_bytes(((essl_sdio_context_t *) arg)->card, HOST_SLC0HOST_INT_CLR_REG, (uint8_t *) &intr_mask, 4);
|
||||
}
|
||||
|
||||
esp_err_t essl_sdio_get_intr(void *arg, uint32_t *intr_raw, uint32_t *intr_st, uint32_t wait_ms)
|
||||
{
|
||||
essl_sdio_context_t *ctx = arg;
|
||||
esp_err_t r;
|
||||
ESP_LOGV(TAG, "get_intr");
|
||||
if (intr_raw == NULL && intr_st == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (intr_raw != NULL) {
|
||||
r = essl_sdio_read_bytes(ctx->card, HOST_SLC0HOST_INT_RAW_REG, (uint8_t *) intr_raw, 4);
|
||||
if (r != ESP_OK) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
if (intr_st != NULL) {
|
||||
r = essl_sdio_read_bytes(ctx->card, HOST_SLC0HOST_INT_ST_REG, (uint8_t *) intr_st, 4);
|
||||
if (r != ESP_OK) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t essl_sdio_set_intr_ena(void *arg, uint32_t ena_mask, uint32_t wait_ms)
|
||||
{
|
||||
ESP_LOGV(TAG, "set_intr_ena: %08"PRIX32, ena_mask);
|
||||
return essl_sdio_write_bytes(((essl_sdio_context_t *)arg)->card, HOST_SLC0HOST_FUNC1_INT_ENA_REG,
|
||||
(uint8_t *) &ena_mask, 4);
|
||||
}
|
||||
|
||||
esp_err_t essl_sdio_get_intr_ena(void *arg, uint32_t *ena_mask_o, uint32_t wait_ms)
|
||||
{
|
||||
ESP_LOGV(TAG, "get_intr_ena");
|
||||
esp_err_t ret = essl_sdio_read_bytes(((essl_sdio_context_t *)arg)->card, HOST_SLC0HOST_FUNC1_INT_ENA_REG,
|
||||
(uint8_t *) ena_mask_o, 4);
|
||||
ESP_LOGV(TAG, "ena: %08"PRIX32, *ena_mask_o);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t essl_sdio_send_slave_intr(void *arg, uint32_t intr_mask, uint32_t wait_ms)
|
||||
{
|
||||
//Only 8 bits available
|
||||
ESP_LOGV(TAG, "send_slave_intr: %02"PRIx8, (uint8_t)intr_mask);
|
||||
return essl_sdio_write_byte(((essl_sdio_context_t *)arg)->card, HOST_SLCHOST_CONF_W7_REG + 0, (uint8_t)intr_mask, NULL);
|
||||
}
|
||||
|
||||
esp_err_t essl_sdio_wait_int(void *arg, uint32_t wait_ms)
|
||||
{
|
||||
return sdmmc_io_wait_int(((essl_sdio_context_t *)arg)->card, wait_ms);
|
||||
}
|
||||
|
||||
void essl_sdio_reset_cnt(void *arg)
|
||||
{
|
||||
essl_sdio_context_t *ctx = arg;
|
||||
ctx->rx_got_bytes = 0;
|
||||
ctx->tx_sent_buffers = 0;
|
||||
}
|
||||
|
||||
#endif // #if SOC_SDIO_SLAVE_SUPPORTED
|
|
@ -0,0 +1,491 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_memory_utils.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
|
||||
#include "driver/spi_master.h"
|
||||
#include "hal/spi_types.h"
|
||||
#include "hal/spi_ll.h"
|
||||
|
||||
#include "essl_internal.h"
|
||||
#include "essl_spi.h"
|
||||
|
||||
/**
|
||||
* Initialise device function list of SPI by this macro.
|
||||
*/
|
||||
#define ESSL_SPI_DEFAULT_DEV_FUNC() (essl_dev_t) {\
|
||||
.get_tx_buffer_num = essl_spi_get_tx_buffer_num,\
|
||||
.update_tx_buffer_num = essl_spi_update_tx_buffer_num,\
|
||||
.get_rx_data_size = essl_spi_get_rx_data_size,\
|
||||
.update_rx_data_size = essl_spi_update_rx_data_size,\
|
||||
.send_packet = essl_spi_send_packet,\
|
||||
.get_packet = essl_spi_get_packet,\
|
||||
.write_reg = essl_spi_write_reg,\
|
||||
.read_reg = essl_spi_read_reg,\
|
||||
}
|
||||
|
||||
static const char TAG[] = "essl_spi";
|
||||
|
||||
typedef struct {
|
||||
spi_device_handle_t spi; // Pointer to SPI device handle.
|
||||
/* Master TX, Slave RX */
|
||||
struct {
|
||||
size_t sent_buf_num; // Number of TX buffers that has been sent out by the master.
|
||||
size_t slave_rx_buf_num; // Number of RX buffers laoded by the slave.
|
||||
uint16_t tx_buffer_size; /* Buffer size for Master TX / Slave RX direction.
|
||||
* Data with length within this size will still be regarded as one buffer.
|
||||
* E.g. 10 bytes data costs 2 buffers if the size is 8 bytes per buffer. */
|
||||
uint8_t tx_sync_reg; // The pre-negotiated register ID for Master-TX-SLAVE-RX synchronization. 1 word (4 Bytes) will be reserved for the synchronization.
|
||||
} master_out;
|
||||
/* Master RX, Slave TX */
|
||||
struct {
|
||||
size_t received_bytes; // Number of the RX bytes that has been received by the Master.
|
||||
size_t slave_tx_bytes; // Number of the TX bytes that has been loaded by the Slave
|
||||
uint8_t rx_sync_reg; // The pre-negotiated register ID for Master-RX-SLAVE-TX synchronization. 1 word (4 Bytes) will be reserved for the synchronization.
|
||||
} master_in;
|
||||
} essl_spi_context_t;
|
||||
|
||||
static uint16_t get_hd_command(spi_command_t cmd_t, uint32_t flags)
|
||||
{
|
||||
spi_line_mode_t line_mode = {
|
||||
.cmd_lines = 1,
|
||||
};
|
||||
|
||||
if (flags & SPI_TRANS_MODE_DIO) {
|
||||
line_mode.data_lines = 2;
|
||||
if (flags & SPI_TRANS_MODE_DIOQIO_ADDR) {
|
||||
line_mode.addr_lines = 2;
|
||||
} else {
|
||||
line_mode.addr_lines = 1;
|
||||
}
|
||||
} else if (flags & SPI_TRANS_MODE_QIO) {
|
||||
line_mode.data_lines = 4;
|
||||
if (flags & SPI_TRANS_MODE_DIOQIO_ADDR) {
|
||||
line_mode.addr_lines = 4;
|
||||
} else {
|
||||
line_mode.addr_lines = 1;
|
||||
}
|
||||
} else {
|
||||
line_mode.data_lines = 1;
|
||||
line_mode.addr_lines = 1;
|
||||
}
|
||||
|
||||
return spi_ll_get_slave_hd_command(cmd_t, line_mode);
|
||||
}
|
||||
|
||||
static int get_hd_dummy_bits(uint32_t flags)
|
||||
{
|
||||
spi_line_mode_t line_mode = {};
|
||||
|
||||
if (flags & SPI_TRANS_MODE_DIO) {
|
||||
line_mode.data_lines = 2;
|
||||
} else if (flags & SPI_TRANS_MODE_QIO) {
|
||||
line_mode.data_lines = 4;
|
||||
} else {
|
||||
line_mode.data_lines = 1;
|
||||
}
|
||||
|
||||
return spi_ll_get_slave_hd_dummy_bits(line_mode);
|
||||
}
|
||||
|
||||
esp_err_t essl_spi_rdbuf(spi_device_handle_t spi, uint8_t *out_data, int addr, int len, uint32_t flags)
|
||||
{
|
||||
spi_transaction_ext_t t = {
|
||||
.base = {
|
||||
.cmd = get_hd_command(SPI_CMD_HD_RDBUF, flags),
|
||||
.addr = addr % 72,
|
||||
.rxlength = len * 8,
|
||||
.rx_buffer = out_data,
|
||||
.flags = flags | SPI_TRANS_VARIABLE_DUMMY,
|
||||
},
|
||||
.dummy_bits = get_hd_dummy_bits(flags),
|
||||
};
|
||||
|
||||
return spi_device_transmit(spi, (spi_transaction_t *)&t);
|
||||
}
|
||||
|
||||
esp_err_t essl_spi_rdbuf_polling(spi_device_handle_t spi, uint8_t *out_data, int addr, int len, uint32_t flags)
|
||||
{
|
||||
spi_transaction_ext_t t = {
|
||||
.base = {
|
||||
.cmd = get_hd_command(SPI_CMD_HD_RDBUF, flags),
|
||||
.addr = addr % 72,
|
||||
.rxlength = len * 8,
|
||||
.rx_buffer = out_data,
|
||||
.flags = flags | SPI_TRANS_VARIABLE_DUMMY,
|
||||
},
|
||||
.dummy_bits = get_hd_dummy_bits(flags),
|
||||
};
|
||||
|
||||
return spi_device_polling_transmit(spi, (spi_transaction_t *)&t);
|
||||
}
|
||||
|
||||
esp_err_t essl_spi_wrbuf(spi_device_handle_t spi, const uint8_t *data, int addr, int len, uint32_t flags)
|
||||
{
|
||||
spi_transaction_ext_t t = {
|
||||
.base = {
|
||||
.cmd = get_hd_command(SPI_CMD_HD_WRBUF, flags),
|
||||
.addr = addr % 72,
|
||||
.length = len * 8,
|
||||
.tx_buffer = data,
|
||||
.flags = flags | SPI_TRANS_VARIABLE_DUMMY,
|
||||
},
|
||||
.dummy_bits = get_hd_dummy_bits(flags),
|
||||
};
|
||||
return spi_device_transmit(spi, (spi_transaction_t *)&t);
|
||||
}
|
||||
|
||||
esp_err_t essl_spi_wrbuf_polling(spi_device_handle_t spi, const uint8_t *data, int addr, int len, uint32_t flags)
|
||||
{
|
||||
spi_transaction_ext_t t = {
|
||||
.base = {
|
||||
.cmd = get_hd_command(SPI_CMD_HD_WRBUF, flags),
|
||||
.addr = addr % 72,
|
||||
.length = len * 8,
|
||||
.tx_buffer = data,
|
||||
.flags = flags | SPI_TRANS_VARIABLE_DUMMY,
|
||||
},
|
||||
.dummy_bits = get_hd_dummy_bits(flags),
|
||||
};
|
||||
return spi_device_polling_transmit(spi, (spi_transaction_t *)&t);
|
||||
}
|
||||
|
||||
esp_err_t essl_spi_rddma_seg(spi_device_handle_t spi, uint8_t *out_data, int seg_len, uint32_t flags)
|
||||
{
|
||||
spi_transaction_ext_t t = {
|
||||
.base = {
|
||||
.cmd = get_hd_command(SPI_CMD_HD_RDDMA, flags),
|
||||
.rxlength = seg_len * 8,
|
||||
.rx_buffer = out_data,
|
||||
.flags = flags | SPI_TRANS_VARIABLE_DUMMY,
|
||||
},
|
||||
.dummy_bits = get_hd_dummy_bits(flags),
|
||||
};
|
||||
return spi_device_transmit(spi, (spi_transaction_t *)&t);
|
||||
}
|
||||
|
||||
esp_err_t essl_spi_rddma_done(spi_device_handle_t spi, uint32_t flags)
|
||||
{
|
||||
spi_transaction_t end_t = {
|
||||
.cmd = get_hd_command(SPI_CMD_HD_INT0, flags),
|
||||
.flags = flags,
|
||||
};
|
||||
return spi_device_transmit(spi, &end_t);
|
||||
}
|
||||
|
||||
esp_err_t essl_spi_rddma(spi_device_handle_t spi, uint8_t *out_data, int len, int seg_len, uint32_t flags)
|
||||
{
|
||||
if (!esp_ptr_dma_capable(out_data) || ((intptr_t)out_data % 4) != 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
seg_len = (seg_len > 0) ? seg_len : len;
|
||||
|
||||
uint8_t *read_ptr = out_data;
|
||||
esp_err_t ret = ESP_OK;
|
||||
while (len > 0) {
|
||||
int send_len = MIN(seg_len, len);
|
||||
|
||||
ret = essl_spi_rddma_seg(spi, read_ptr, send_len, flags);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
len -= send_len;
|
||||
read_ptr += send_len;
|
||||
}
|
||||
return essl_spi_rddma_done(spi, flags);
|
||||
}
|
||||
|
||||
esp_err_t essl_spi_wrdma_seg(spi_device_handle_t spi, const uint8_t *data, int seg_len, uint32_t flags)
|
||||
{
|
||||
spi_transaction_ext_t t = {
|
||||
.base = {
|
||||
.cmd = get_hd_command(SPI_CMD_HD_WRDMA, flags),
|
||||
.length = seg_len * 8,
|
||||
.tx_buffer = data,
|
||||
.flags = flags | SPI_TRANS_VARIABLE_DUMMY,
|
||||
},
|
||||
.dummy_bits = get_hd_dummy_bits(flags),
|
||||
};
|
||||
return spi_device_transmit(spi, (spi_transaction_t *)&t);
|
||||
}
|
||||
|
||||
esp_err_t essl_spi_wrdma_done(spi_device_handle_t spi, uint32_t flags)
|
||||
{
|
||||
spi_transaction_t end_t = {
|
||||
.cmd = get_hd_command(SPI_CMD_HD_WR_END, flags),
|
||||
.flags = flags,
|
||||
};
|
||||
return spi_device_transmit(spi, &end_t);
|
||||
}
|
||||
|
||||
esp_err_t essl_spi_wrdma(spi_device_handle_t spi, const uint8_t *data, int len, int seg_len, uint32_t flags)
|
||||
{
|
||||
if (!esp_ptr_dma_capable(data)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
seg_len = (seg_len > 0) ? seg_len : len;
|
||||
|
||||
while (len > 0) {
|
||||
int send_len = MIN(seg_len, len);
|
||||
|
||||
esp_err_t ret = essl_spi_wrdma_seg(spi, data, send_len, flags);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
len -= send_len;
|
||||
data += send_len;
|
||||
}
|
||||
|
||||
return essl_spi_wrdma_done(spi, flags);
|
||||
}
|
||||
|
||||
esp_err_t essl_spi_int(spi_device_handle_t spi, int int_n, uint32_t flags)
|
||||
{
|
||||
spi_transaction_t end_t = {
|
||||
.cmd = get_hd_command(SPI_CMD_HD_INT0 + int_n, flags),
|
||||
.flags = flags,
|
||||
};
|
||||
return spi_device_transmit(spi, &end_t);
|
||||
}
|
||||
|
||||
//------------------------------------ APPEND MODE ----------------------------------//
|
||||
static uint32_t essl_spi_get_rx_data_size(void *arg);
|
||||
static esp_err_t essl_spi_update_rx_data_size(void *arg, uint32_t wait_ms);
|
||||
static uint32_t essl_spi_get_tx_buffer_num(void *arg);
|
||||
static esp_err_t essl_spi_update_tx_buffer_num(void *arg, uint32_t wait_ms);
|
||||
|
||||
esp_err_t essl_spi_init_dev(essl_handle_t *out_handle, const essl_spi_config_t *init_config)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(init_config->spi, ESP_ERR_INVALID_STATE, TAG, "Check SPI initialization first");
|
||||
ESP_RETURN_ON_FALSE(init_config->tx_sync_reg <= (SOC_SPI_MAXIMUM_BUFFER_SIZE - 1) * 4, ESP_ERR_INVALID_ARG, TAG, "GPSPI supports %d-byte-width internal registers", SOC_SPI_MAXIMUM_BUFFER_SIZE);
|
||||
ESP_RETURN_ON_FALSE(init_config->rx_sync_reg <= (SOC_SPI_MAXIMUM_BUFFER_SIZE - 1) * 4, ESP_ERR_INVALID_ARG, TAG, "GPSPI supports %d-byte-width internal registers", SOC_SPI_MAXIMUM_BUFFER_SIZE);
|
||||
ESP_RETURN_ON_FALSE(init_config->tx_sync_reg != init_config->rx_sync_reg, ESP_ERR_INVALID_ARG, TAG, "Should use different word of registers for synchronization");
|
||||
|
||||
essl_spi_context_t *context = calloc(1, sizeof(essl_spi_context_t));
|
||||
essl_dev_t *dev = calloc(1, sizeof(essl_dev_t));
|
||||
if (!context || !dev) {
|
||||
free(context);
|
||||
free(dev);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
*context = (essl_spi_context_t) {
|
||||
.spi = *init_config->spi,
|
||||
.master_out.tx_buffer_size = init_config->tx_buf_size,
|
||||
.master_out.tx_sync_reg = init_config->tx_sync_reg,
|
||||
.master_in.rx_sync_reg = init_config->rx_sync_reg
|
||||
};
|
||||
|
||||
*dev = ESSL_SPI_DEFAULT_DEV_FUNC();
|
||||
dev->args = context;
|
||||
|
||||
*out_handle = dev;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t essl_spi_deinit_dev(essl_handle_t handle)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_STATE, TAG, "ESSL SPI is not in use");
|
||||
free(handle->args);
|
||||
free(handle);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void essl_spi_reset_cnt(void *arg)
|
||||
{
|
||||
essl_spi_context_t *ctx = arg;
|
||||
if (ctx) {
|
||||
ctx->master_out.sent_buf_num = 0;
|
||||
ctx->master_in.received_bytes = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------ RX ----------------------------------//
|
||||
esp_err_t essl_spi_read_reg(void *arg, uint8_t addr, uint8_t *out_value, uint32_t wait_ms)
|
||||
{
|
||||
essl_spi_context_t *ctx = arg;
|
||||
ESP_RETURN_ON_FALSE(arg, ESP_ERR_INVALID_STATE, TAG, "Check ESSL SPI initialization first");
|
||||
uint8_t reserved_1_head = ctx->master_out.tx_sync_reg < ctx->master_in.rx_sync_reg ? ctx->master_out.tx_sync_reg : ctx->master_in.rx_sync_reg;
|
||||
uint8_t reserved_1_tail = reserved_1_head + 3;
|
||||
uint8_t reserved_2_head = ctx->master_out.tx_sync_reg < ctx->master_in.rx_sync_reg ? ctx->master_in.rx_sync_reg : ctx->master_out.tx_sync_reg;
|
||||
uint8_t reserved_2_tail = reserved_2_head + 3;
|
||||
ESP_RETURN_ON_FALSE(addr < reserved_1_head || (addr > reserved_1_tail && addr < reserved_2_head) || addr > reserved_2_tail, ESP_ERR_INVALID_ARG, TAG, "Invalid address");
|
||||
|
||||
return essl_spi_rdbuf(ctx->spi, out_value, addr, sizeof(uint8_t), 0);
|
||||
}
|
||||
|
||||
static uint32_t essl_spi_get_rx_data_size(void *arg)
|
||||
{
|
||||
essl_spi_context_t *ctx = arg;
|
||||
ESP_LOGV(TAG, "slave tx buffer: %d bytes, master has read: %d bytes", ctx->master_in.slave_tx_bytes, ctx->master_in.received_bytes);
|
||||
return ctx->master_in.slave_tx_bytes - ctx->master_in.received_bytes;
|
||||
}
|
||||
|
||||
static esp_err_t essl_spi_update_rx_data_size(void *arg, uint32_t wait_ms)
|
||||
{
|
||||
essl_spi_context_t *ctx = arg;
|
||||
uint32_t updated_size = 0;
|
||||
uint32_t previous_size = 0;
|
||||
esp_err_t ret;
|
||||
|
||||
ret = essl_spi_rdbuf_polling(ctx->spi, (uint8_t *)&previous_size, ctx->master_in.rx_sync_reg, sizeof(uint32_t), 0);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read until the last 2 reading result are same. Reason:
|
||||
* SPI transaction is carried on per 1 Byte. So when Master is reading the shared register, if the
|
||||
* register value is changed by Slave at this time, Master may get wrong data.
|
||||
*/
|
||||
while (1) {
|
||||
ret = essl_spi_rdbuf_polling(ctx->spi, (uint8_t *)&updated_size, ctx->master_in.rx_sync_reg, sizeof(uint32_t), 0);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
if (updated_size == previous_size) {
|
||||
ctx->master_in.slave_tx_bytes = updated_size;
|
||||
ESP_LOGV(TAG, "updated: slave prepared tx buffer is: %d bytes", (unsigned int)updated_size);
|
||||
return ret;
|
||||
}
|
||||
previous_size = updated_size;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t essl_spi_get_packet(void *arg, void *out_data, size_t size, uint32_t wait_ms)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(arg, ESP_ERR_INVALID_STATE, TAG, "Check ESSL SPI initialization first");
|
||||
if (!esp_ptr_dma_capable(out_data) || ((intptr_t)out_data % 4) != 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
essl_spi_context_t *ctx = arg;
|
||||
esp_err_t ret;
|
||||
|
||||
if (essl_spi_get_rx_data_size(arg) < size) {
|
||||
/**
|
||||
* For realistic situation, usually there will be a large overhead (Slave will load large amount of data),
|
||||
* so here we only update the Slave's TX size when the last-updated size is smaller than what Master requires.
|
||||
*/
|
||||
ret = essl_spi_update_rx_data_size(arg, wait_ms);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
//Slave still did not load enough size of buffer
|
||||
if (essl_spi_get_rx_data_size(arg) < size) {
|
||||
ESP_LOGV(TAG, "slave buffer: %d is not enough, %d is required", ctx->master_in.slave_tx_bytes, ctx->master_in.received_bytes + size);
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG, "get_packet: size to read is: %d", size);
|
||||
ret = essl_spi_rddma_seg(ctx->spi, out_data, size, 0);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
ctx->master_in.received_bytes += size;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
//------------------------------------ TX ----------------------------------//
|
||||
esp_err_t essl_spi_write_reg(void *arg, uint8_t addr, uint8_t value, uint8_t *out_value, uint32_t wait_ms)
|
||||
{
|
||||
essl_spi_context_t *ctx = arg;
|
||||
ESP_RETURN_ON_FALSE(arg, ESP_ERR_INVALID_STATE, TAG, "Check ESSL SPI initialization first");
|
||||
uint8_t reserved_1_head = ctx->master_out.tx_sync_reg < ctx->master_in.rx_sync_reg ? ctx->master_out.tx_sync_reg : ctx->master_in.rx_sync_reg;
|
||||
uint8_t reserved_1_tail = reserved_1_head + 3;
|
||||
uint8_t reserved_2_head = ctx->master_out.tx_sync_reg < ctx->master_in.rx_sync_reg ? ctx->master_in.rx_sync_reg : ctx->master_out.tx_sync_reg;
|
||||
uint8_t reserved_2_tail = reserved_2_head + 3;
|
||||
ESP_RETURN_ON_FALSE(addr < reserved_1_head || (addr > reserved_1_tail && addr < reserved_2_head) || addr > reserved_2_tail, ESP_ERR_INVALID_ARG, TAG, "Invalid address");
|
||||
ESP_RETURN_ON_FALSE(out_value == NULL, ESP_ERR_NOT_SUPPORTED, TAG, "This feature is not supported");
|
||||
|
||||
return essl_spi_wrbuf(ctx->spi, &value, addr, sizeof(uint8_t), 0);
|
||||
}
|
||||
|
||||
static uint32_t essl_spi_get_tx_buffer_num(void *arg)
|
||||
{
|
||||
essl_spi_context_t *ctx = arg;
|
||||
ESP_LOGV(TAG, "slave rx buffer: %d, master has sent: %d", ctx->master_out.slave_rx_buf_num, ctx->master_out.sent_buf_num);
|
||||
return ctx->master_out.slave_rx_buf_num - ctx->master_out.sent_buf_num;
|
||||
}
|
||||
|
||||
static esp_err_t essl_spi_update_tx_buffer_num(void *arg, uint32_t wait_ms)
|
||||
{
|
||||
essl_spi_context_t *ctx = arg;
|
||||
uint32_t updated_num = 0;
|
||||
uint32_t previous_size = 0;
|
||||
esp_err_t ret;
|
||||
|
||||
ret = essl_spi_rdbuf_polling(ctx->spi, (uint8_t *)&previous_size, ctx->master_out.tx_sync_reg, sizeof(uint32_t), 0);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read until the last 2 reading result are same. Reason:
|
||||
* SPI transaction is carried on per 1 Byte. So when Master is reading the shared register, if the
|
||||
* register value is changed by Slave at this time, Master may get wrong data.
|
||||
*/
|
||||
while (1) {
|
||||
ret = essl_spi_rdbuf_polling(ctx->spi, (uint8_t *)&updated_num, ctx->master_out.tx_sync_reg, sizeof(uint32_t), 0);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
if (updated_num == previous_size) {
|
||||
ctx->master_out.slave_rx_buf_num = updated_num;
|
||||
ESP_LOGV(TAG, "updated: slave prepared rx buffer: %d", (unsigned int)updated_num);
|
||||
return ret;
|
||||
}
|
||||
previous_size = updated_num;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t essl_spi_send_packet(void *arg, const void *data, size_t size, uint32_t wait_ms)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(arg, ESP_ERR_INVALID_STATE, TAG, "Check ESSL SPI initialization first");
|
||||
if (!esp_ptr_dma_capable(data)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
essl_spi_context_t *ctx = arg;
|
||||
esp_err_t ret;
|
||||
uint32_t buf_num_to_use = (size + ctx->master_out.tx_buffer_size - 1) / ctx->master_out.tx_buffer_size;
|
||||
|
||||
if (essl_spi_get_tx_buffer_num(arg) < buf_num_to_use) {
|
||||
/**
|
||||
* For realistic situation, usually there will be a large overhead (Slave will load enough number of RX buffers),
|
||||
* so here we only update the Slave's RX buffer number when the last-updated number is smaller than what Master requires.
|
||||
*/
|
||||
ret = essl_spi_update_tx_buffer_num(arg, wait_ms);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
//Slave still did not load a sufficient amount of buffers
|
||||
if (essl_spi_get_tx_buffer_num(arg) < buf_num_to_use) {
|
||||
ESP_LOGV(TAG, "slave buffer: %"PRIu32" is not enough, %"PRIu32" is required", (uint32_t)ctx->master_out.slave_rx_buf_num, (uint32_t)ctx->master_out.sent_buf_num + buf_num_to_use);
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG, "send_packet: size to write is: %zu", size);
|
||||
ret = essl_spi_wrdma_seg(ctx->spi, data, size, 0);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
ctx->master_out.sent_buf_num += buf_num_to_use;
|
||||
|
||||
return essl_spi_wrdma_done(ctx->spi, 0);
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
version: "1.0.0"
|
||||
description: "Espressif Serial Slave Link Library"
|
||||
url: https://github.com/espressif/idf-extra-components/tree/master/esp_serial_slave_link
|
||||
dependencies:
|
||||
idf: ">=5.0"
|
|
@ -0,0 +1,226 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "esp_err.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct essl_dev_t;
|
||||
/// Handle of an ESSL device
|
||||
typedef struct essl_dev_t *essl_handle_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize the slave.
|
||||
*
|
||||
* @param handle Handle of an ESSL device.
|
||||
* @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.
|
||||
* @return
|
||||
* - ESP_OK: If success
|
||||
* - ESP_ERR_NOT_SUPPORTED: Current device does not support this function.
|
||||
* - Other value returned from lower layer `init`.
|
||||
*/
|
||||
esp_err_t essl_init(essl_handle_t handle, uint32_t wait_ms);
|
||||
|
||||
/** Wait for interrupt of an ESSL slave device.
|
||||
*
|
||||
* @param handle Handle of an ESSL device.
|
||||
* @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: If success
|
||||
* - ESP_ERR_NOT_SUPPORTED: Current device does not support this function.
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_wait_for_ready(essl_handle_t handle, uint32_t wait_ms);
|
||||
|
||||
/** Get buffer num for the host to send data to the slave. The buffers are size of ``buffer_size``.
|
||||
*
|
||||
* @param handle Handle of a ESSL device.
|
||||
* @param out_tx_num Output of buffer num that host can send data to ESSL slave.
|
||||
* @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Success
|
||||
* - ESP_ERR_NOT_SUPPORTED: This API is not supported in this mode
|
||||
* - One of the error codes from SDMMC/SPI host controller
|
||||
*/
|
||||
esp_err_t essl_get_tx_buffer_num(essl_handle_t handle, uint32_t *out_tx_num, uint32_t wait_ms);
|
||||
|
||||
/** Get the size, in bytes, of the data that the ESSL slave is ready to send
|
||||
*
|
||||
* @param handle Handle of an ESSL device.
|
||||
* @param out_rx_size Output of data size to read from slave, in bytes
|
||||
* @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Success
|
||||
* - ESP_ERR_NOT_SUPPORTED: This API is not supported in this mode
|
||||
* - One of the error codes from SDMMC/SPI host controller
|
||||
*/
|
||||
esp_err_t essl_get_rx_data_size(essl_handle_t handle, uint32_t *out_rx_size, uint32_t wait_ms);
|
||||
|
||||
|
||||
/** Reset the counters of this component. Usually you don't need to do this unless you know the slave is reset.
|
||||
*
|
||||
* @param handle Handle of an ESSL device.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Success
|
||||
* - ESP_ERR_NOT_SUPPORTED: This API is not supported in this mode
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument, handle is not init.
|
||||
*/
|
||||
esp_err_t essl_reset_cnt(essl_handle_t handle);
|
||||
|
||||
/** Send a packet to the ESSL Slave. The Slave receives the packet into buffers whose size is ``buffer_size`` (configured during initialization).
|
||||
*
|
||||
* @param handle Handle of an ESSL device.
|
||||
* @param start Start address of the packet to send
|
||||
* @param length Length of data to send, if the packet is over-size, the it will be divided into blocks and hold into different buffers automatically.
|
||||
* @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument, handle is not init or other argument is not valid.
|
||||
* - ESP_ERR_TIMEOUT: No buffer to use, or error ftrom SDMMC host controller.
|
||||
* - ESP_ERR_NOT_FOUND: Slave is not ready for receiving.
|
||||
* - ESP_ERR_NOT_SUPPORTED: This API is not supported in this mode
|
||||
* - One of the error codes from SDMMC/SPI host controller.
|
||||
*/
|
||||
esp_err_t essl_send_packet(essl_handle_t handle, const void *start, size_t length, uint32_t wait_ms);
|
||||
|
||||
/** Get a packet from ESSL slave.
|
||||
*
|
||||
* @param handle Handle of an ESSL device.
|
||||
* @param[out] out_data Data output address
|
||||
* @param size The size of the output buffer, if the buffer is smaller than the size of data to receive from slave, the driver returns ``ESP_ERR_NOT_FINISHED``
|
||||
* @param[out] out_length Output of length the data actually received from slave.
|
||||
* @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success: All the data has been read from the slave.
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument, The handle is not initialized or the other arguments are invalid.
|
||||
* - ESP_ERR_NOT_FINISHED: Read was successful, but there is still data remaining.
|
||||
* - ESP_ERR_NOT_FOUND: Slave is not ready to send data.
|
||||
* - ESP_ERR_NOT_SUPPORTED: This API is not supported in this mode
|
||||
* - One of the error codes from SDMMC/SPI host controller.
|
||||
*/
|
||||
esp_err_t essl_get_packet(essl_handle_t handle, void *out_data, size_t size, size_t *out_length, uint32_t wait_ms);
|
||||
|
||||
/** Write general purpose R/W registers (8-bit) of ESSL slave.
|
||||
*
|
||||
* @param handle Handle of an ESSL device.
|
||||
* @param addr Address of register to write. For SDIO, valid address: 0-59. For SPI, see ``essl_spi.h``
|
||||
* @param value Value to write to the register.
|
||||
* @param value_o Output of the returned written value.
|
||||
* @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.
|
||||
*
|
||||
* @note sdio 28-31 are reserved, the lower API helps to skip.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - One of the error codes from SDMMC/SPI host controller
|
||||
*/
|
||||
esp_err_t essl_write_reg(essl_handle_t handle, uint8_t addr, uint8_t value, uint8_t *value_o, uint32_t wait_ms);
|
||||
|
||||
/** Read general purpose R/W registers (8-bit) of ESSL slave.
|
||||
*
|
||||
* @param handle Handle of a ``essl`` device.
|
||||
* @param add Address of register to read. For SDIO, Valid address: 0-27, 32-63 (28-31 reserved, return interrupt bits on read). For SPI, see ``essl_spi.h``
|
||||
* @param value_o Output value read from the register.
|
||||
* @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - One of the error codes from SDMMC/SPI host controller
|
||||
*/
|
||||
esp_err_t essl_read_reg(essl_handle_t handle, uint8_t add, uint8_t *value_o, uint32_t wait_ms);
|
||||
|
||||
/** wait for an interrupt of the slave
|
||||
*
|
||||
* @param handle Handle of an ESSL device.
|
||||
* @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: If interrupt is triggered.
|
||||
* - ESP_ERR_NOT_SUPPORTED: Current device does not support this function.
|
||||
* - ESP_ERR_TIMEOUT: No interrupts before timeout.
|
||||
*/
|
||||
esp_err_t essl_wait_int(essl_handle_t handle, uint32_t wait_ms);
|
||||
|
||||
/** Clear interrupt bits of ESSL slave. All the bits set in the mask will be cleared, while other bits will stay the same.
|
||||
*
|
||||
* @param handle Handle of an ESSL device.
|
||||
* @param intr_mask Mask of interrupt bits to clear.
|
||||
* @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Success
|
||||
* - ESP_ERR_NOT_SUPPORTED: Current device does not support this function.
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_clear_intr(essl_handle_t handle, uint32_t intr_mask, uint32_t wait_ms);
|
||||
|
||||
/** Get interrupt bits of ESSL slave.
|
||||
*
|
||||
* @param handle Handle of an ESSL device.
|
||||
* @param intr_raw Output of the raw interrupt bits. Set to NULL if only masked bits are read.
|
||||
* @param intr_st Output of the masked interrupt bits. set to NULL if only raw bits are read.
|
||||
* @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Success
|
||||
* - ESP_INVALID_ARG: If both ``intr_raw`` and ``intr_st`` are NULL.
|
||||
* - ESP_ERR_NOT_SUPPORTED: Current device does not support this function.
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_get_intr(essl_handle_t handle, uint32_t *intr_raw, uint32_t *intr_st, uint32_t wait_ms);
|
||||
|
||||
/** Set interrupt enable bits of ESSL slave. The slave only sends interrupt on the line when there is a bit both the raw status and the enable are set.
|
||||
*
|
||||
* @param handle Handle of an ESSL device.
|
||||
* @param ena_mask Mask of the interrupt bits to enable.
|
||||
* @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Success
|
||||
* - ESP_ERR_NOT_SUPPORTED: Current device does not support this function.
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_set_intr_ena(essl_handle_t handle, uint32_t ena_mask, uint32_t wait_ms);
|
||||
|
||||
/** Get interrupt enable bits of ESSL slave.
|
||||
*
|
||||
* @param handle Handle of an ESSL device.
|
||||
* @param ena_mask_o Output of interrupt bit enable mask.
|
||||
* @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_get_intr_ena(essl_handle_t handle, uint32_t *ena_mask_o, uint32_t wait_ms);
|
||||
|
||||
/** Send interrupts to slave. Each bit of the interrupt will be triggered.
|
||||
*
|
||||
* @param handle Handle of an ESSL device.
|
||||
* @param intr_mask Mask of interrupt bits to send to slave.
|
||||
* @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Success
|
||||
* - ESP_ERR_NOT_SUPPORTED: Current device does not support this function.
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_send_slave_intr(essl_handle_t handle, uint32_t intr_mask, uint32_t wait_ms);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,247 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
// ESP SDIO slave link used by the ESP host to communicate with ESP SDIO slave.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "driver/sdmmc_host.h"
|
||||
|
||||
#include "esp_serial_slave_link/essl.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// Configuration for the ESSL SDIO device
|
||||
typedef struct {
|
||||
sdmmc_card_t *card; ///< The initialized sdmmc card pointer of the slave.
|
||||
int recv_buffer_size; ///< The pre-negotiated recv buffer size used by both the host and the slave.
|
||||
} essl_sdio_config_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize the ESSL SDIO device and get its handle.
|
||||
*
|
||||
* @param out_handle Output of the handle.
|
||||
* @param config Configuration for the ESSL SDIO device.
|
||||
* @return
|
||||
* - ESP_OK: on success
|
||||
* - ESP_ERR_NO_MEM: memory exhausted.
|
||||
*/
|
||||
esp_err_t essl_sdio_init_dev(essl_handle_t *out_handle, const essl_sdio_config_t *config);
|
||||
|
||||
/**
|
||||
* @brief Deinitialize and free the space used by the ESSL SDIO device.
|
||||
*
|
||||
* @param handle Handle of the ESSL SDIO device to deinit.
|
||||
* @return
|
||||
* - ESP_OK: on success
|
||||
* - ESP_ERR_INVALID_ARG: wrong handle passed
|
||||
*/
|
||||
esp_err_t essl_sdio_deinit_dev(essl_handle_t handle);
|
||||
|
||||
//Please call `essl_` functions witout `sdio` instead of calling these functions directly.
|
||||
/** @cond */
|
||||
/**
|
||||
* SDIO Initialize process of an ESSL SDIO slave device.
|
||||
*
|
||||
* @param arg Context of the ``essl`` component. Send to other functions later.
|
||||
* @param wait_ms Time to wait before operation is done, in ms.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if success
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_sdio_init(void *arg, uint32_t wait_ms);
|
||||
|
||||
/**
|
||||
* Wait for interrupt of an ESSL SDIO slave device.
|
||||
*
|
||||
* @param arg Context of the ``essl`` component.
|
||||
* @param wait_ms Time to wait before operation is done, in ms.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if success
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_sdio_wait_for_ready(void *arg, uint32_t wait_ms);
|
||||
|
||||
/**
|
||||
* Get buffer num for the host to send data to the slave. The buffers are size of ``buffer_size``.
|
||||
*
|
||||
* @param arg Context of the component.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
uint32_t essl_sdio_get_tx_buffer_num(void *arg);
|
||||
|
||||
/** Get amount of data the ESSL SDIO slave preparing to send to host.
|
||||
*
|
||||
* @param arg Context of the component.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
uint32_t essl_sdio_get_rx_data_size(void *arg);
|
||||
|
||||
/**
|
||||
* Send a packet to the ESSL SDIO slave. The slave receive the packet into buffers whose size is ``buffer_size`` in the arg.
|
||||
*
|
||||
* @param arg Context of the component.
|
||||
* @param start Start address of the packet to send
|
||||
* @param length Length of data to send, if the packet is over-size, the it will be divided into blocks and hold into different buffers automatically.
|
||||
* @param wait_ms Time to wait before timeout, in ms.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_TIMEOUT No buffer to use, or error ftrom SDMMC host controller
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_sdio_send_packet(void *arg, const void *start, size_t length, uint32_t wait_ms);
|
||||
|
||||
/**
|
||||
* Get a packet from an ESSL SDIO slave.
|
||||
*
|
||||
* @param arg Context of the component.
|
||||
* @param[out] out_data Data output address
|
||||
* @param size The size of the output buffer, if the buffer is smaller than the size of data to receive from slave, the driver returns ``ESP_ERR_NOT_FINISHED``
|
||||
* @param wait_ms Time to wait before timeout, in ms.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success, all the data are read from the slave.
|
||||
* - ESP_ERR_NOT_FINISHED Read success, while there're data remaining.
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_sdio_get_packet(void *arg, void *out_data, size_t size, uint32_t wait_ms);
|
||||
|
||||
/**
|
||||
* Wait for the interrupt from the SDIO slave.
|
||||
*
|
||||
* @param arg Context of the component.
|
||||
* @param wait_ms Time to wait before timeout, in ms.
|
||||
* @return
|
||||
* - ESP_ERR_NOT_SUPPORTED: if the interrupt line is not initialized properly.
|
||||
* - ESP_OK: if interrupt happened
|
||||
* - ESP_ERR_TIMEOUT: if timeout before interrupt happened.
|
||||
* - or other values returned from the `io_int_wait` member of the `card->host` structure.
|
||||
*/
|
||||
esp_err_t essl_sdio_wait_int(void *arg, uint32_t wait_ms);
|
||||
|
||||
/**
|
||||
* Clear interrupt bits of an ESSL SDIO slave. All the bits set in the mask will be cleared, while other bits will stay the same.
|
||||
*
|
||||
* @param arg Context of the component.
|
||||
* @param intr_mask Mask of interrupt bits to clear.
|
||||
* @param wait_ms Time to wait before timeout, in ms.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_sdio_clear_intr(void *arg, uint32_t intr_mask, uint32_t wait_ms);
|
||||
|
||||
/**
|
||||
* Get interrupt bits of an ESSL SDIO slave.
|
||||
*
|
||||
* @param arg Context of the component.
|
||||
* @param intr_raw Output of the raw interrupt bits. Set to NULL if only masked bits are read.
|
||||
* @param intr_st Output of the masked interrupt bits. set to NULL if only raw bits are read.
|
||||
* @param wait_ms Time to wait before timeout, in ms.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_INVALID_ARG if both ``intr_raw`` and ``intr_st`` are NULL.
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_sdio_get_intr(void *arg, uint32_t *intr_raw, uint32_t *intr_st, uint32_t wait_ms);
|
||||
|
||||
/**
|
||||
* Set interrupt enable bits of an ESSL SDIO slave. The slave only sends interrupt on the line when there is a bit both the raw status and the enable are set.
|
||||
*
|
||||
* @param arg Context of the component.
|
||||
* @param ena_mask Mask of the interrupt bits to enable.
|
||||
* @param wait_ms Time to wait before timeout, in ms.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_sdio_set_intr_ena(void *arg, uint32_t ena_mask, uint32_t wait_ms);
|
||||
|
||||
/**
|
||||
* Get interrupt enable bits of an ESSL SDIO slave.
|
||||
*
|
||||
* @param arg Context of the component.
|
||||
* @param ena_mask_o Output of interrupt bit enable mask.
|
||||
* @param wait_ms Time to wait before timeout, in ms.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_sdio_get_intr_ena(void *arg, uint32_t *ena_mask_o, uint32_t wait_ms);
|
||||
|
||||
/**
|
||||
* Write general purpose R/W registers (8-bit) of an ESSL SDIO slave.
|
||||
*
|
||||
* @param arg Context of the component.
|
||||
* @param addr Address of register to write. Valid address: 0-27, 32-63 (28-31 reserved).
|
||||
* @param value Value to write to the register.
|
||||
* @param wait_ms Time to wait before timeout, in ms.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Address not valid.
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_sdio_write_reg(void *arg, uint8_t addr, uint8_t value, uint8_t *value_o, uint32_t wait_ms);
|
||||
|
||||
/**
|
||||
* Read general purpose R/W registers (8-bit) of an ESSL SDIO slave.
|
||||
*
|
||||
* @param arg Context of the component.
|
||||
* @param add Address of register to read. Valid address: 0-27, 32-63 (28-31 reserved, return interrupt bits on read).
|
||||
* @param value Output value read from the register.
|
||||
* @param wait_ms Time to wait before timeout, in ms.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Address not valid.
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_sdio_read_reg(void *arg, uint8_t add, uint8_t *value_o, uint32_t wait_ms);
|
||||
|
||||
/**
|
||||
* Send interrupts to slave. Each bit of the interrupt will be triggered.
|
||||
*
|
||||
* @param arg Context of the component.
|
||||
* @param intr_mask Mask of interrupt bits to send to slave.
|
||||
* @param wait_ms Time to wait before timeout, in ms.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_sdio_send_slave_intr(void *arg, uint32_t intr_mask, uint32_t wait_ms);
|
||||
|
||||
/**
|
||||
* @brief Reset the counter on the host side.
|
||||
*
|
||||
* @note Only call when you know the slave has reset its counter, or there will be inconsistent between the master and the slave.
|
||||
*
|
||||
* @param arg Context of the component.
|
||||
*/
|
||||
void essl_sdio_reset_cnt(void *arg);
|
||||
|
||||
/** @endcond */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,312 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "driver/spi_master.h"
|
||||
|
||||
#include "esp_serial_slave_link/essl.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// Configuration of ESSL SPI device
|
||||
typedef struct {
|
||||
spi_device_handle_t *spi; ///< Pointer to SPI device handle.
|
||||
uint32_t tx_buf_size; ///< The pre-negotiated Master TX buffer size used by both the host and the slave.
|
||||
uint8_t tx_sync_reg; ///< The pre-negotiated register ID for Master-TX-SLAVE-RX synchronization. 1 word (4 Bytes) will be reserved for the synchronization.
|
||||
uint8_t rx_sync_reg; ///< The pre-negotiated register ID for Master-RX-Slave-TX synchronization. 1 word (4 Bytes) will be reserved for the synchronization.
|
||||
} essl_spi_config_t;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// APIs for DMA Append Mode
|
||||
// This mode has a better performance for continuous Half Duplex SPI transactions.
|
||||
//
|
||||
// * You can use the ``essl_spi_init_dev`` and ``essl_spi_deinit_dev`` together with APIs in ``essl.h`` to communicate
|
||||
// with ESP SPI Slaves in Half Duplex DMA Append Mode. See example for SPI SLAVE HALFDUPLEX APPEND MODE.
|
||||
// * You can also use the following APIs to create your own logic.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* @brief Initialize the ESSL SPI device function list and get its handle
|
||||
*
|
||||
* @param[out] out_handle Output of the handle
|
||||
* @param init_config Configuration for the ESSL SPI device
|
||||
* @return
|
||||
* - ESP_OK: On success
|
||||
* - ESP_ERR_NO_MEM: Memory exhausted
|
||||
* - ESP_ERR_INVALID_STATE: SPI driver is not initialized
|
||||
* - ESP_ERR_INVALID_ARG: Wrong register ID
|
||||
*/
|
||||
esp_err_t essl_spi_init_dev(essl_handle_t *out_handle, const essl_spi_config_t *init_config);
|
||||
|
||||
/**
|
||||
* @brief Deinitialize the ESSL SPI device and free the memory used by the device
|
||||
*
|
||||
* @param handle Handle of the ESSL SPI device
|
||||
* @return
|
||||
* - ESP_OK: On success
|
||||
* - ESP_ERR_INVALID_STATE: ESSL SPI is not in use
|
||||
*/
|
||||
esp_err_t essl_spi_deinit_dev(essl_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Read from the shared registers
|
||||
*
|
||||
* @note The registers for Master/Slave synchronization are reserved. Do not use them. (see `rx_sync_reg` in `essl_spi_config_t`)
|
||||
*
|
||||
* @param arg Context of the component. (Member ``arg`` from ``essl_handle_t``)
|
||||
* @param addr Address of the shared registers. (Valid: 0 ~ SOC_SPI_MAXIMUM_BUFFER_SIZE, registers for M/S sync are reserved, see note1).
|
||||
* @param[out] out_value Read buffer for the shared registers.
|
||||
* @param wait_ms Time to wait before timeout (reserved for future use, user should set this to 0).
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - ESP_ERR_INVALID_STATE: ESSL SPI has not been initialized.
|
||||
* - ESP_ERR_INVALID_ARG: The address argument is not valid. See note 1.
|
||||
* - or other return value from :cpp:func:`spi_device_transmit`.
|
||||
*/
|
||||
esp_err_t essl_spi_read_reg(void *arg, uint8_t addr, uint8_t *out_value, uint32_t wait_ms);
|
||||
|
||||
/**
|
||||
* @brief Get a packet from Slave
|
||||
*
|
||||
* @param arg Context of the component. (Member ``arg`` from ``essl_handle_t``)
|
||||
* @param[out] out_data Output data address
|
||||
* @param size The size of the output data.
|
||||
* @param wait_ms Time to wait before timeout (reserved for future use, user should set this to 0).
|
||||
* @return
|
||||
* - ESP_OK: On Success
|
||||
* - ESP_ERR_INVALID_STATE: ESSL SPI has not been initialized.
|
||||
* - ESP_ERR_INVALID_ARG: The output data address is neither DMA capable nor 4 byte-aligned
|
||||
* - ESP_ERR_INVALID_SIZE: Master requires ``size`` bytes of data but Slave did not load enough bytes.
|
||||
*/
|
||||
esp_err_t essl_spi_get_packet(void *arg, void *out_data, size_t size, uint32_t wait_ms);
|
||||
|
||||
/**
|
||||
* @brief Write to the shared registers
|
||||
*
|
||||
* @note The registers for Master/Slave synchronization are reserved. Do not use them. (see `tx_sync_reg` in `essl_spi_config_t`)
|
||||
* @note Feature of checking the actual written value (``out_value``) is not supported.
|
||||
*
|
||||
* @param arg Context of the component. (Member ``arg`` from ``essl_handle_t``)
|
||||
* @param addr Address of the shared registers. (Valid: 0 ~ SOC_SPI_MAXIMUM_BUFFER_SIZE, registers for M/S sync are reserved, see note1)
|
||||
* @param value Buffer for data to send, should be align to 4.
|
||||
* @param[out] out_value Not supported, should be set to NULL.
|
||||
* @param wait_ms Time to wait before timeout (reserved for future use, user should set this to 0).
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - ESP_ERR_INVALID_STATE: ESSL SPI has not been initialized.
|
||||
* - ESP_ERR_INVALID_ARG: The address argument is not valid. See note 1.
|
||||
* - ESP_ERR_NOT_SUPPORTED: Should set ``out_value`` to NULL. See note 2.
|
||||
* - or other return value from :cpp:func:`spi_device_transmit`.
|
||||
*
|
||||
*/
|
||||
esp_err_t essl_spi_write_reg(void *arg, uint8_t addr, uint8_t value, uint8_t *out_value, uint32_t wait_ms);
|
||||
|
||||
/**
|
||||
* @brief Send a packet to Slave
|
||||
*
|
||||
* @param arg Context of the component. (Member ``arg`` from ``essl_handle_t``)
|
||||
* @param data Address of the data to send
|
||||
* @param size Size of the data to send.
|
||||
* @param wait_ms Time to wait before timeout (reserved for future use, user should set this to 0).
|
||||
* @return
|
||||
* - ESP_OK: On success
|
||||
* - ESP_ERR_INVALID_STATE: ESSL SPI has not been initialized.
|
||||
* - ESP_ERR_INVALID_ARG: The data address is not DMA capable
|
||||
* - ESP_ERR_INVALID_SIZE: Master will send ``size`` bytes of data but Slave did not load enough RX buffer
|
||||
*/
|
||||
esp_err_t essl_spi_send_packet(void *arg, const void *data, size_t size, uint32_t wait_ms);
|
||||
|
||||
/**
|
||||
* @brief Reset the counter in Master context
|
||||
*
|
||||
* @note Shall only be called if the slave has reset its counter. Else, Slave and Master would be desynchronized
|
||||
*
|
||||
* @param arg Context of the component. (Member ``arg`` from ``essl_handle_t``)
|
||||
*/
|
||||
void essl_spi_reset_cnt(void *arg);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Basic commands to communicate with the SPI Slave HD on ESP32-S2
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* @brief Read the shared buffer from the slave in ISR way
|
||||
*
|
||||
* @note The slave's HW doesn't guarantee the data in one SPI transaction is consistent. It sends data in unit of byte.
|
||||
* In other words, if the slave SW attempts to update the shared register when a rdbuf SPI transaction is in-flight,
|
||||
* the data got by the master will be the combination of bytes of different writes of slave SW.
|
||||
*
|
||||
* @note ``out_data`` should be prepared in words and in the DRAM. The buffer may be written in words
|
||||
* by the DMA. When a byte is written, the remaining bytes in the same word will also be
|
||||
* overwritten, even the ``len`` is shorter than a word.
|
||||
*
|
||||
* @param spi SPI device handle representing the slave
|
||||
* @param[out] out_data Buffer for read data, strongly suggested to be in the DRAM and aligned to 4
|
||||
* @param addr Address of the slave shared buffer
|
||||
* @param len Length to read
|
||||
* @param flags `SPI_TRANS_*` flags to control the transaction mode of the transaction to send.
|
||||
* @return
|
||||
* - ESP_OK: on success
|
||||
* - or other return value from :cpp:func:`spi_device_transmit`.
|
||||
*/
|
||||
esp_err_t essl_spi_rdbuf(spi_device_handle_t spi, uint8_t *out_data, int addr, int len, uint32_t flags);
|
||||
|
||||
/**
|
||||
* @brief Read the shared buffer from the slave in polling way
|
||||
*
|
||||
* @note ``out_data`` should be prepared in words and in the DRAM. The buffer may be written in words
|
||||
* by the DMA. When a byte is written, the remaining bytes in the same word will also be
|
||||
* overwritten, even the ``len`` is shorter than a word.
|
||||
*
|
||||
* @param spi SPI device handle representing the slave
|
||||
* @param[out] out_data Buffer for read data, strongly suggested to be in the DRAM and aligned to 4
|
||||
* @param addr Address of the slave shared buffer
|
||||
* @param len Length to read
|
||||
* @param flags `SPI_TRANS_*` flags to control the transaction mode of the transaction to send.
|
||||
* @return
|
||||
* - ESP_OK: on success
|
||||
* - or other return value from :cpp:func:`spi_device_transmit`.
|
||||
*/
|
||||
esp_err_t essl_spi_rdbuf_polling(spi_device_handle_t spi, uint8_t *out_data, int addr, int len, uint32_t flags);
|
||||
|
||||
/**
|
||||
* @brief Write the shared buffer of the slave in ISR way
|
||||
*
|
||||
* @note ``out_data`` should be prepared in words and in the DRAM. The buffer may be written in words
|
||||
* by the DMA. When a byte is written, the remaining bytes in the same word will also be
|
||||
* overwritten, even the ``len`` is shorter than a word.
|
||||
*
|
||||
* @param spi SPI device handle representing the slave
|
||||
* @param data Buffer for data to send, strongly suggested to be in the DRAM
|
||||
* @param addr Address of the slave shared buffer,
|
||||
* @param len Length to write
|
||||
* @param flags `SPI_TRANS_*` flags to control the transaction mode of the transaction to send.
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - or other return value from :cpp:func:`spi_device_transmit`.
|
||||
*/
|
||||
esp_err_t essl_spi_wrbuf(spi_device_handle_t spi, const uint8_t *data, int addr, int len, uint32_t flags);
|
||||
|
||||
/**
|
||||
* @brief Write the shared buffer of the slave in polling way
|
||||
*
|
||||
* @note ``out_data`` should be prepared in words and in the DRAM. The buffer may be written in words
|
||||
* by the DMA. When a byte is written, the remaining bytes in the same word will also be
|
||||
* overwritten, even the ``len`` is shorter than a word.
|
||||
*
|
||||
* @param spi SPI device handle representing the slave
|
||||
* @param data Buffer for data to send, strongly suggested to be in the DRAM
|
||||
* @param addr Address of the slave shared buffer,
|
||||
* @param len Length to write
|
||||
* @param flags `SPI_TRANS_*` flags to control the transaction mode of the transaction to send.
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - or other return value from :cpp:func:`spi_device_polling_transmit`.
|
||||
*/
|
||||
esp_err_t essl_spi_wrbuf_polling(spi_device_handle_t spi, const uint8_t *data, int addr, int len, uint32_t flags);
|
||||
|
||||
/**
|
||||
* @brief Receive long buffer in segments from the slave through its DMA.
|
||||
*
|
||||
* @note This function combines several :cpp:func:`essl_spi_rddma_seg` and one
|
||||
* :cpp:func:`essl_spi_rddma_done` at the end. Used when the slave is working in segment mode.
|
||||
*
|
||||
* @param spi SPI device handle representing the slave
|
||||
* @param[out] out_data Buffer to hold the received data, strongly suggested to be in the DRAM and aligned to 4
|
||||
* @param len Total length of data to receive.
|
||||
* @param seg_len Length of each segment, which is not larger than the maximum transaction length
|
||||
* allowed for the spi device. Suggested to be multiples of 4. When set < 0, means send
|
||||
* all data in one segment (the ``rddma_done`` will still be sent.)
|
||||
* @param flags `SPI_TRANS_*` flags to control the transaction mode of the transaction to send.
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - or other return value from :cpp:func:`spi_device_transmit`.
|
||||
*/
|
||||
esp_err_t essl_spi_rddma(spi_device_handle_t spi, uint8_t *out_data, int len, int seg_len, uint32_t flags);
|
||||
|
||||
/**
|
||||
* @brief Read one data segment from the slave through its DMA.
|
||||
*
|
||||
* @note To read long buffer, call :cpp:func:`essl_spi_rddma` instead.
|
||||
*
|
||||
* @param spi SPI device handle representing the slave
|
||||
* @param[out] out_data Buffer to hold the received data. strongly suggested to be in the DRAM and aligned to 4
|
||||
* @param seg_len Length of this segment
|
||||
* @param flags `SPI_TRANS_*` flags to control the transaction mode of the transaction to send.
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - or other return value from :cpp:func:`spi_device_transmit`.
|
||||
*/
|
||||
esp_err_t essl_spi_rddma_seg(spi_device_handle_t spi, uint8_t *out_data, int seg_len, uint32_t flags);
|
||||
|
||||
/**
|
||||
* @brief Send the ``rddma_done`` command to the slave. Upon receiving this command, the slave will
|
||||
* stop sending the current buffer even there are data unsent, and maybe prepare the next buffer to
|
||||
* send.
|
||||
*
|
||||
* @note This is required only when the slave is working in segment mode.
|
||||
*
|
||||
* @param spi SPI device handle representing the slave
|
||||
* @param flags `SPI_TRANS_*` flags to control the transaction mode of the transaction to send.
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - or other return value from :cpp:func:`spi_device_transmit`.
|
||||
*/
|
||||
esp_err_t essl_spi_rddma_done(spi_device_handle_t spi, uint32_t flags);
|
||||
|
||||
/**
|
||||
* @brief Send long buffer in segments to the slave through its DMA.
|
||||
*
|
||||
* @note This function combines several :cpp:func:`essl_spi_wrdma_seg` and one
|
||||
* :cpp:func:`essl_spi_wrdma_done` at the end. Used when the slave is working in segment mode.
|
||||
*
|
||||
* @param spi SPI device handle representing the slave
|
||||
* @param data Buffer for data to send, strongly suggested to be in the DRAM
|
||||
* @param len Total length of data to send.
|
||||
* @param seg_len Length of each segment, which is not larger than the maximum transaction length
|
||||
* allowed for the spi device. Suggested to be multiples of 4. When set < 0, means send
|
||||
* all data in one segment (the ``wrdma_done`` will still be sent.)
|
||||
* @param flags `SPI_TRANS_*` flags to control the transaction mode of the transaction to send.
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - or other return value from :cpp:func:`spi_device_transmit`.
|
||||
*/
|
||||
esp_err_t essl_spi_wrdma(spi_device_handle_t spi, const uint8_t *data, int len, int seg_len, uint32_t flags);
|
||||
|
||||
/**
|
||||
* @brief Send one data segment to the slave through its DMA.
|
||||
*
|
||||
* @note To send long buffer, call :cpp:func:`essl_spi_wrdma` instead.
|
||||
*
|
||||
* @param spi SPI device handle representing the slave
|
||||
* @param data Buffer for data to send, strongly suggested to be in the DRAM
|
||||
* @param seg_len Length of this segment
|
||||
* @param flags `SPI_TRANS_*` flags to control the transaction mode of the transaction to send.
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - or other return value from :cpp:func:`spi_device_transmit`.
|
||||
*/
|
||||
esp_err_t essl_spi_wrdma_seg(spi_device_handle_t spi, const uint8_t *data, int seg_len, uint32_t flags);
|
||||
|
||||
/**
|
||||
* @brief Send the ``wrdma_done`` command to the slave. Upon receiving this command, the slave will
|
||||
* stop receiving, process the received data, and maybe prepare the next buffer to receive.
|
||||
*
|
||||
* @note This is required only when the slave is working in segment mode.
|
||||
*
|
||||
* @param spi SPI device handle representing the slave
|
||||
* @param flags `SPI_TRANS_*` flags to control the transaction mode of the transaction to send.
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - or other return value from :cpp:func:`spi_device_transmit`.
|
||||
*/
|
||||
esp_err_t essl_spi_wrdma_done(spi_device_handle_t spi, uint32_t flags);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
// NOTE: From the view of master
|
||||
#define CMD_HD_WRBUF_REG 0x01
|
||||
#define CMD_HD_RDBUF_REG 0x02
|
||||
#define CMD_HD_WRDMA_REG 0x03
|
||||
#define CMD_HD_RDDMA_REG 0x04
|
||||
|
||||
#define CMD_HD_ONEBIT_MODE 0x00
|
||||
#define CMD_HD_DOUT_MODE 0x10
|
||||
#define CMD_HD_QOUT_MODE 0x20
|
||||
#define CMD_HD_DIO_MODE 0x50
|
||||
#define CMD_HD_QIO_MODE 0xA0
|
||||
|
||||
#define CMD_HD_SEG_END_REG 0x05
|
||||
#define CMD_HD_EN_QPI_REG 0x06
|
||||
#define CMD_HD_WR_END_REG 0x07
|
||||
#define CMD_HD_INT0_REG 0x08
|
||||
#define CMD_HD_INT1_REG 0x09
|
||||
#define CMD_HD_INT2_REG 0x0A
|
||||
#define CMD_HD_EX_QPI_REG 0xDD
|
||||
|
||||
#define SPI_SLAVE_HD_BUFFER_SIZE 64
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// NOTE: From the view of master
|
||||
#define CMD_HD_WRBUF_REG 0x01
|
||||
#define CMD_HD_RDBUF_REG 0x02
|
||||
#define CMD_HD_WRDMA_REG 0x03
|
||||
#define CMD_HD_RDDMA_REG 0x04
|
||||
|
||||
#define CMD_HD_ONEBIT_MODE 0x00
|
||||
#define CMD_HD_DOUT_MODE 0x10
|
||||
#define CMD_HD_QOUT_MODE 0x20
|
||||
#define CMD_HD_DIO_MODE 0x50
|
||||
#define CMD_HD_QIO_MODE 0xA0
|
||||
|
||||
#define CMD_HD_SEG_END_REG 0x05
|
||||
#define CMD_HD_EN_QPI_REG 0x06
|
||||
#define CMD_HD_WR_END_REG 0x07
|
||||
#define CMD_HD_INT0_REG 0x08
|
||||
#define CMD_HD_INT1_REG 0x09
|
||||
#define CMD_HD_INT2_REG 0x0A
|
||||
#define CMD_HD_EX_QPI_REG 0xDD
|
||||
|
||||
#define SPI_SLAVE_HD_BUFFER_SIZE 64
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// NOTE: From the view of master
|
||||
#define CMD_HD_WRBUF_REG 0x01
|
||||
#define CMD_HD_RDBUF_REG 0x02
|
||||
#define CMD_HD_WRDMA_REG 0x03
|
||||
#define CMD_HD_RDDMA_REG 0x04
|
||||
|
||||
#define CMD_HD_ONEBIT_MODE 0x00
|
||||
#define CMD_HD_DOUT_MODE 0x10
|
||||
#define CMD_HD_QOUT_MODE 0x20
|
||||
#define CMD_HD_DIO_MODE 0x50
|
||||
#define CMD_HD_QIO_MODE 0xA0
|
||||
|
||||
#define CMD_HD_SEG_END_REG 0x05
|
||||
#define CMD_HD_EN_QPI_REG 0x06
|
||||
#define CMD_HD_WR_END_REG 0x07
|
||||
#define CMD_HD_INT0_REG 0x08
|
||||
#define CMD_HD_INT1_REG 0x09
|
||||
#define CMD_HD_INT2_REG 0x0A
|
||||
#define CMD_HD_EX_QPI_REG 0xDD
|
||||
|
||||
#define SPI_SLAVE_HD_BUFFER_SIZE 72
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// NOTE: From the view of master
|
||||
#define CMD_HD_WRBUF_REG 0x01
|
||||
#define CMD_HD_RDBUF_REG 0x02
|
||||
#define CMD_HD_WRDMA_REG 0x03
|
||||
#define CMD_HD_RDDMA_REG 0x04
|
||||
|
||||
#define CMD_HD_ONEBIT_MODE 0x00
|
||||
#define CMD_HD_DOUT_MODE 0x10
|
||||
#define CMD_HD_QOUT_MODE 0x20
|
||||
#define CMD_HD_DIO_MODE 0x50
|
||||
#define CMD_HD_QIO_MODE 0xA0
|
||||
|
||||
#define CMD_HD_SEG_END_REG 0x05
|
||||
#define CMD_HD_EN_QPI_REG 0x06
|
||||
#define CMD_HD_WR_END_REG 0x07
|
||||
#define CMD_HD_INT0_REG 0x08
|
||||
#define CMD_HD_INT1_REG 0x09
|
||||
#define CMD_HD_INT2_REG 0x0A
|
||||
#define CMD_HD_EX_QPI_REG 0xDD
|
||||
|
||||
#define SPI_SLAVE_HD_BUFFER_SIZE 64
|
|
@ -14,7 +14,7 @@ endif()
|
|||
|
||||
# 3. Add here if the component is compatible with IDF >= v5.0
|
||||
if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "5.0")
|
||||
list(APPEND EXTRA_COMPONENT_DIRS ../bdc_motor ../led_strip ../sh2lib ../nghttp)
|
||||
list(APPEND EXTRA_COMPONENT_DIRS ../bdc_motor ../led_strip ../sh2lib ../nghttp ../esp_serial_slave_link)
|
||||
endif()
|
||||
|
||||
# !This section should NOT be touched when adding new component!
|
||||
|
|
Loading…
Reference in New Issue