forked from espressif/esp-idf
Merge branch 'change/bs_cmake_cleanup' into 'master'
change(bs): some refactor to the bitscrambler component See merge request espressif/esp-idf!36148
This commit is contained in:
@@ -1,29 +1,14 @@
|
|||||||
idf_build_get_property(target IDF_TARGET)
|
idf_build_get_property(target IDF_TARGET)
|
||||||
|
if(${target} STREQUAL "linux")
|
||||||
|
return() # This component is not supported by the POSIX/Linux simulator
|
||||||
|
endif()
|
||||||
|
|
||||||
set(srcs)
|
set(srcs)
|
||||||
set(include_dirs)
|
|
||||||
set(priv_requires)
|
|
||||||
|
|
||||||
set(my_priv_requires "soc" "hal" "esp_hw_support" "esp_mm")
|
|
||||||
|
|
||||||
if(CONFIG_SOC_BITSCRAMBLER_SUPPORTED)
|
if(CONFIG_SOC_BITSCRAMBLER_SUPPORTED)
|
||||||
list(APPEND srcs "bitscrambler.c" "bitscrambler_loopback.c")
|
list(APPEND srcs "src/bitscrambler.c" "src/bitscrambler_loopback.c" "src/bitscrambler_${target}.c")
|
||||||
list(APPEND include_dirs "include")
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Note that (according to the docs) "The values of REQUIRES and PRIV_REQUIRES
|
|
||||||
# should not depend on any configuration choices (CONFIG_xxx macros)." We work
|
|
||||||
# around that by setting the actual priv_requires value in the target checks,
|
|
||||||
# rather than make it depend on CONFIG_SOC_BITSCRAMBLER_SUPPORTED.
|
|
||||||
|
|
||||||
if(target STREQUAL "esp32p4")
|
|
||||||
list(APPEND srcs "bitscrambler_esp32p4.c")
|
|
||||||
set(priv_requires ${my_priv_requires})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
|
|
||||||
idf_component_register(SRCS ${srcs}
|
idf_component_register(SRCS ${srcs}
|
||||||
PRIV_REQUIRES ${priv_requires}
|
PRIV_REQUIRES "esp_mm"
|
||||||
INCLUDE_DIRS ${include_dirs}
|
INCLUDE_DIRS "include")
|
||||||
PRIV_INCLUDE_DIRS "priv_include"
|
|
||||||
)
|
|
||||||
|
@@ -1,22 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
//This file contains private functions for interop between bitscrambler.c
|
|
||||||
//and bitscrambler_loopback.c.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "bitscrambler_private.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void bitscrambler_loopback_free(bitscrambler_handle_t bs);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
@@ -1,23 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
//This file contains private functions for interop between bitscrambler.c
|
|
||||||
//and bitscrambler_loopback.c.
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include "soc/bitscrambler_peri_select.h"
|
|
||||||
#include "hal/bitscrambler_ll.h"
|
|
||||||
|
|
||||||
typedef struct bitscrambler_t bitscrambler_t;
|
|
||||||
|
|
||||||
struct bitscrambler_t {
|
|
||||||
bitscrambler_config_t cfg;
|
|
||||||
bitscrambler_dev_t *hw;
|
|
||||||
bool loopback; //true if this is a loopback bitscrambler, i.e. the RX
|
|
||||||
//channel is also claimed
|
|
||||||
};
|
|
||||||
|
|
||||||
esp_err_t bitscrambler_init_loopback(bitscrambler_handle_t handle, const bitscrambler_config_t *config);
|
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -7,15 +7,36 @@
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
|
#include "soc/soc_caps.h"
|
||||||
#include "hal/bitscrambler_types.h"
|
#include "hal/bitscrambler_types.h"
|
||||||
|
#if SOC_BITSCRAMBLER_SUPPORTED
|
||||||
#include "soc/bitscrambler_peri_select.h"
|
#include "soc/bitscrambler_peri_select.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Declare a BitScrambler binary program.
|
||||||
|
*
|
||||||
|
* This macro declares an external reference to a BitScrambler binary program.
|
||||||
|
* The binary program is expected to be linked into the binary with a specific
|
||||||
|
* naming convention.
|
||||||
|
*
|
||||||
|
* @param VAR The variable name to declare.
|
||||||
|
* @param NAME The name of the binary program.
|
||||||
|
*/
|
||||||
#define BITSCRAMBLER_PROGRAM(VAR, NAME) extern const uint8_t VAR[] asm("_binary_bitscrambler_program_" NAME "_start")
|
#define BITSCRAMBLER_PROGRAM(VAR, NAME) extern const uint8_t VAR[] asm("_binary_bitscrambler_program_" NAME "_start")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handle for the bitscrambler instance.
|
||||||
|
*
|
||||||
|
* This typedef defines a handle for a bitscrambler instance, which is used to
|
||||||
|
* manage and interact with the bitscrambler. The handle is a pointer to an
|
||||||
|
* opaque structure, meaning that the internal details of the structure are
|
||||||
|
* hidden from the user.
|
||||||
|
*/
|
||||||
typedef struct bitscrambler_t *bitscrambler_handle_t;
|
typedef struct bitscrambler_t *bitscrambler_handle_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "driver/bitscrambler.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef esp_err_t (*bitscrambler_extra_clean_up_func_t)(bitscrambler_handle_t bs, void* user_ctx);
|
||||||
|
|
||||||
|
esp_err_t bitscrambler_register_extra_clean_up(bitscrambler_handle_t handle, bitscrambler_extra_clean_up_func_t clean_up, void* user_ctx);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -8,8 +8,6 @@
|
|||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "driver/bitscrambler.h"
|
#include "driver/bitscrambler.h"
|
||||||
#include "bitscrambler_private.h"
|
#include "bitscrambler_private.h"
|
||||||
#include "bitscrambler_loopback_private.h"
|
|
||||||
#include "soc/soc.h"
|
|
||||||
#include "hal/bitscrambler_ll.h"
|
#include "hal/bitscrambler_ll.h"
|
||||||
#include "esp_private/periph_ctrl.h"
|
#include "esp_private/periph_ctrl.h"
|
||||||
|
|
||||||
@@ -42,7 +40,7 @@ typedef struct {
|
|||||||
uint8_t unused;
|
uint8_t unused;
|
||||||
} bitscrambler_program_hdr_t;
|
} bitscrambler_program_hdr_t;
|
||||||
|
|
||||||
#define INST_LEN_WORDS 9 //length of one instruction in 32-bit words as defined by HW
|
#define INST_LEN_WORDS BITSCRAMBLER_LL_INST_LEN_WORDS
|
||||||
|
|
||||||
// For now, hardware only has one TX and on RX unit. Need to make this more flexible if we get
|
// For now, hardware only has one TX and on RX unit. Need to make this more flexible if we get
|
||||||
// non-specific and/or more channels.
|
// non-specific and/or more channels.
|
||||||
@@ -251,18 +249,33 @@ esp_err_t bitscrambler_load_lut(bitscrambler_handle_t handle, void *lut, size_t
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
esp_err_t bitscrambler_register_extra_clean_up(bitscrambler_handle_t handle, bitscrambler_extra_clean_up_func_t clean_up, void* user_ctx)
|
||||||
|
{
|
||||||
|
if (!handle) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
handle->extra_clean_up = clean_up;
|
||||||
|
handle->clean_up_user_ctx = user_ctx;
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
void bitscrambler_free(bitscrambler_handle_t handle)
|
void bitscrambler_free(bitscrambler_handle_t handle)
|
||||||
{
|
{
|
||||||
|
if (!handle) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
disable_clocks(handle);
|
disable_clocks(handle);
|
||||||
if (handle->loopback) {
|
if (handle->loopback) {
|
||||||
atomic_flag_clear(&tx_in_use);
|
atomic_flag_clear(&tx_in_use);
|
||||||
atomic_flag_clear(&rx_in_use);
|
atomic_flag_clear(&rx_in_use);
|
||||||
bitscrambler_loopback_free(handle);
|
|
||||||
} else if (handle->cfg.dir == BITSCRAMBLER_DIR_TX) {
|
} else if (handle->cfg.dir == BITSCRAMBLER_DIR_TX) {
|
||||||
atomic_flag_clear(&tx_in_use);
|
atomic_flag_clear(&tx_in_use);
|
||||||
} else if (handle->cfg.dir == BITSCRAMBLER_DIR_RX) {
|
} else if (handle->cfg.dir == BITSCRAMBLER_DIR_RX) {
|
||||||
atomic_flag_clear(&rx_in_use);
|
atomic_flag_clear(&rx_in_use);
|
||||||
}
|
}
|
||||||
|
if (handle->extra_clean_up) {
|
||||||
|
handle->extra_clean_up(handle, handle->clean_up_user_ctx);
|
||||||
|
}
|
||||||
free(handle);
|
free(handle);
|
||||||
}
|
}
|
||||||
|
|
@@ -1,40 +1,43 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include "driver/bitscrambler.h"
|
|
||||||
#include "bitscrambler_private.h"
|
|
||||||
#include "bitscrambler_loopback_private.h"
|
|
||||||
#include "esp_private/gdma.h"
|
|
||||||
#include "hal/dma_types.h"
|
|
||||||
#include "hal/cache_ll.h"
|
|
||||||
#include "hal/gdma_ll.h"
|
|
||||||
#include "bitscrambler_soc_specific.h"
|
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/semphr.h"
|
#include "freertos/semphr.h"
|
||||||
|
#include "driver/bitscrambler.h"
|
||||||
|
#include "esp_private/gdma.h"
|
||||||
|
#include "esp_private/gdma_link.h"
|
||||||
|
#include "esp_private/bitscrambler.h"
|
||||||
|
#include "hal/dma_types.h"
|
||||||
|
#include "bitscrambler_private.h"
|
||||||
|
#include "bitscrambler_soc_specific.h"
|
||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
#include "esp_check.h"
|
#include "esp_check.h"
|
||||||
#include "soc/ahb_dma_struct.h"
|
|
||||||
#include "esp_heap_caps.h"
|
#include "esp_heap_caps.h"
|
||||||
#include "esp_cache.h"
|
#include "esp_cache.h"
|
||||||
#include "esp_dma_utils.h"
|
#include "esp_dma_utils.h"
|
||||||
|
|
||||||
const static char *TAG = "bs_loop";
|
const static char *TAG = "bs_loop";
|
||||||
|
|
||||||
//Note: given that the first member is a bitscrambler_t, this can be safely passed to
|
|
||||||
//any of the non-loopback bitscrambler functions.
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bitscrambler_t bs;
|
bitscrambler_t bs;
|
||||||
dma_descriptor_t *tx_desc_link; // descriptor link list, the length of the link is determined by the copy buffer size
|
|
||||||
dma_descriptor_t *rx_desc_link; // descriptor link list, the length of the link is determined by the copy buffer size
|
|
||||||
gdma_channel_handle_t tx_channel; // GDMA TX channel handle
|
gdma_channel_handle_t tx_channel; // GDMA TX channel handle
|
||||||
gdma_channel_handle_t rx_channel; // GDMA RX channel handle
|
gdma_channel_handle_t rx_channel; // GDMA RX channel handle
|
||||||
|
gdma_link_list_handle_t tx_link_list; // GDMA TX link list handle, the length of the link is determined by the copy buffer size
|
||||||
|
gdma_link_list_handle_t rx_link_list; // GDMA RX link list handle, the length of the link is determined by the copy buffer size
|
||||||
SemaphoreHandle_t sema_done;
|
SemaphoreHandle_t sema_done;
|
||||||
size_t max_transfer_sz_bytes;
|
size_t max_transfer_sz_bytes;
|
||||||
} bitscrambler_loopback_t;
|
} bitscrambler_loopback_t;
|
||||||
|
|
||||||
|
/// @brief make sure bs is indeed the first member of bitscrambler_loopback_t so we can cast it to a bitscrambler_t and safely passed to
|
||||||
|
// any of the non-loopback bitscrambler functions.
|
||||||
|
_Static_assert(offsetof(bitscrambler_loopback_t, bs) == 0, "bs needs to be 1st member of bitscrambler_loopback_t");
|
||||||
|
|
||||||
|
static void bitscrambler_loopback_free(bitscrambler_loopback_t *bsl);
|
||||||
|
static esp_err_t bitscrambler_loopback_cleanup(bitscrambler_handle_t bs, void* user_ctx);
|
||||||
|
|
||||||
static esp_err_t new_dma_channel(const gdma_channel_alloc_config_t *cfg, gdma_channel_handle_t *handle, int bus)
|
static esp_err_t new_dma_channel(const gdma_channel_alloc_config_t *cfg, gdma_channel_handle_t *handle, int bus)
|
||||||
{
|
{
|
||||||
esp_err_t ret = ESP_OK;
|
esp_err_t ret = ESP_OK;
|
||||||
@@ -63,8 +66,6 @@ static IRAM_ATTR bool trans_done_cb(gdma_channel_handle_t dma_chan, gdma_event_d
|
|||||||
|
|
||||||
esp_err_t bitscrambler_loopback_create(bitscrambler_handle_t *handle, int attach_to, size_t max_transfer_sz_bytes)
|
esp_err_t bitscrambler_loopback_create(bitscrambler_handle_t *handle, int attach_to, size_t max_transfer_sz_bytes)
|
||||||
{
|
{
|
||||||
///make sure bs is indeed the first member of bitscrambler_loopback_t so we can cast it to a bitscrambler_t
|
|
||||||
_Static_assert(offsetof(bitscrambler_loopback_t, bs) == 0, "bs needs to be 1st member of bitscrambler_loopback_t");
|
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
@@ -85,6 +86,9 @@ esp_err_t bitscrambler_loopback_create(bitscrambler_handle_t *handle, int attach
|
|||||||
};
|
};
|
||||||
ESP_GOTO_ON_ERROR(bitscrambler_init_loopback(&bs->bs, &cfg), err, TAG, "failed bitscrambler init for loopback");
|
ESP_GOTO_ON_ERROR(bitscrambler_init_loopback(&bs->bs, &cfg), err, TAG, "failed bitscrambler init for loopback");
|
||||||
|
|
||||||
|
// register extra cleanup function to free loopback resources
|
||||||
|
bitscrambler_register_extra_clean_up(&bs->bs, bitscrambler_loopback_cleanup, bs);
|
||||||
|
|
||||||
bs->sema_done = xSemaphoreCreateBinary();
|
bs->sema_done = xSemaphoreCreateBinary();
|
||||||
if (!bs->sema_done) {
|
if (!bs->sema_done) {
|
||||||
goto err;
|
goto err;
|
||||||
@@ -93,19 +97,21 @@ esp_err_t bitscrambler_loopback_create(bitscrambler_handle_t *handle, int attach
|
|||||||
bs->max_transfer_sz_bytes = max_transfer_sz_bytes;
|
bs->max_transfer_sz_bytes = max_transfer_sz_bytes;
|
||||||
int desc_ct = (max_transfer_sz_bytes + DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED - 1) / DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED;
|
int desc_ct = (max_transfer_sz_bytes + DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED - 1) / DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED;
|
||||||
int bus = g_bitscrambler_periph_desc[attach_to].bus;
|
int bus = g_bitscrambler_periph_desc[attach_to].bus;
|
||||||
uint32_t caps = (bus == SOC_GDMA_BUS_AXI) ? MALLOC_CAP_DMA_DESC_AXI : MALLOC_CAP_DMA_DESC_AHB;
|
|
||||||
size_t align = (bus == SOC_GDMA_BUS_AXI) ? 8 : 4;
|
size_t align = (bus == SOC_GDMA_BUS_AXI) ? 8 : 4;
|
||||||
bs->rx_desc_link = heap_caps_aligned_calloc(align, desc_ct, sizeof(dma_descriptor_t), caps);
|
|
||||||
bs->tx_desc_link = heap_caps_aligned_calloc(align, desc_ct, sizeof(dma_descriptor_t), caps);
|
// create DMA link list for TX and RX
|
||||||
if (!bs->rx_desc_link || !bs->tx_desc_link) {
|
gdma_link_list_config_t dma_link_cfg = {
|
||||||
ret = ESP_ERR_NO_MEM;
|
.buffer_alignment = 4,
|
||||||
goto err;
|
.item_alignment = align,
|
||||||
}
|
.num_items = desc_ct,
|
||||||
|
};
|
||||||
|
ESP_GOTO_ON_ERROR(gdma_new_link_list(&dma_link_cfg, &bs->tx_link_list), err, TAG, "failed to create TX link list");
|
||||||
|
ESP_GOTO_ON_ERROR(gdma_new_link_list(&dma_link_cfg, &bs->rx_link_list), err, TAG, "failed to create RX link list");
|
||||||
|
|
||||||
// create TX channel and RX channel, they should reside in the same DMA pair
|
// create TX channel and RX channel, they should reside in the same DMA pair
|
||||||
gdma_channel_alloc_config_t tx_alloc_config = {
|
gdma_channel_alloc_config_t tx_alloc_config = {
|
||||||
.flags.reserve_sibling = 1,
|
|
||||||
.direction = GDMA_CHANNEL_DIRECTION_TX,
|
.direction = GDMA_CHANNEL_DIRECTION_TX,
|
||||||
|
.flags.reserve_sibling = 1,
|
||||||
};
|
};
|
||||||
ESP_GOTO_ON_ERROR(new_dma_channel(&tx_alloc_config, &bs->tx_channel, bus), err, TAG, "failed to create GDMA TX channel");
|
ESP_GOTO_ON_ERROR(new_dma_channel(&tx_alloc_config, &bs->tx_channel, bus), err, TAG, "failed to create GDMA TX channel");
|
||||||
gdma_channel_alloc_config_t rx_alloc_config = {
|
gdma_channel_alloc_config_t rx_alloc_config = {
|
||||||
@@ -132,18 +138,13 @@ esp_err_t bitscrambler_loopback_create(bitscrambler_handle_t *handle, int attach
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
bitscrambler_loopback_free(&bs->bs);
|
bitscrambler_loopback_free(bs);
|
||||||
free(bs);
|
free(bs);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
//note this is never called directly; bitscrambler_free calls this to clear
|
static void bitscrambler_loopback_free(bitscrambler_loopback_t *bsl)
|
||||||
//the loopback-specific things of a loopback bitscrambler.
|
|
||||||
//bitscrambler_loopback_create also calls this in an error situation, so
|
|
||||||
//we should only delete not-NULL members.
|
|
||||||
void bitscrambler_loopback_free(bitscrambler_handle_t bs)
|
|
||||||
{
|
{
|
||||||
bitscrambler_loopback_t *bsl = (bitscrambler_loopback_t*)bs;
|
|
||||||
if (bsl->rx_channel) {
|
if (bsl->rx_channel) {
|
||||||
gdma_disconnect(bsl->rx_channel);
|
gdma_disconnect(bsl->rx_channel);
|
||||||
gdma_del_channel(bsl->rx_channel);
|
gdma_del_channel(bsl->rx_channel);
|
||||||
@@ -152,36 +153,22 @@ void bitscrambler_loopback_free(bitscrambler_handle_t bs)
|
|||||||
gdma_disconnect(bsl->tx_channel);
|
gdma_disconnect(bsl->tx_channel);
|
||||||
gdma_del_channel(bsl->tx_channel);
|
gdma_del_channel(bsl->tx_channel);
|
||||||
}
|
}
|
||||||
|
if (bsl->tx_link_list) {
|
||||||
|
gdma_del_link_list(bsl->tx_link_list);
|
||||||
|
}
|
||||||
|
if (bsl->rx_link_list) {
|
||||||
|
gdma_del_link_list(bsl->rx_link_list);
|
||||||
|
}
|
||||||
if (bsl->sema_done) {
|
if (bsl->sema_done) {
|
||||||
vSemaphoreDelete(bsl->sema_done);
|
vSemaphoreDelete(bsl->sema_done);
|
||||||
}
|
}
|
||||||
free(bsl->rx_desc_link);
|
|
||||||
free(bsl->tx_desc_link);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fill_dma_links(dma_descriptor_t *link, void *buffer, size_t len_bytes, int set_eof)
|
static esp_err_t bitscrambler_loopback_cleanup(bitscrambler_handle_t bs, void* user_ctx)
|
||||||
{
|
{
|
||||||
uint8_t *buffer_p = (uint8_t*)buffer;
|
bitscrambler_loopback_t *bsl = (bitscrambler_loopback_t*)user_ctx;
|
||||||
int link_ct = 0;
|
bitscrambler_loopback_free(bsl);
|
||||||
for (int p = 0; p < len_bytes; p += DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED) {
|
return ESP_OK;
|
||||||
int seg_len = len_bytes - p;
|
|
||||||
if (seg_len > DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED) {
|
|
||||||
seg_len = DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED;
|
|
||||||
}
|
|
||||||
link[link_ct].dw0.size = seg_len;
|
|
||||||
link[link_ct].dw0.length = seg_len;
|
|
||||||
link[link_ct].dw0.err_eof = 0;
|
|
||||||
link[link_ct].dw0.suc_eof = 0;
|
|
||||||
link[link_ct].dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA;
|
|
||||||
link[link_ct].buffer = &buffer_p[p];
|
|
||||||
link[link_ct].next = &link[link_ct + 1];
|
|
||||||
link_ct++;
|
|
||||||
}
|
|
||||||
link[link_ct - 1].next = NULL; //fix last entry to end transaction
|
|
||||||
if (set_eof) {
|
|
||||||
link[link_ct - 1].dw0.suc_eof = 1;
|
|
||||||
}
|
|
||||||
return link_ct;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -232,18 +219,33 @@ esp_err_t bitscrambler_loopback_run(bitscrambler_handle_t bs, void *buffer_in, s
|
|||||||
gdma_reset(bsl->tx_channel);
|
gdma_reset(bsl->tx_channel);
|
||||||
bitscrambler_reset(bs);
|
bitscrambler_reset(bs);
|
||||||
|
|
||||||
int link_ct_in = fill_dma_links(bsl->tx_desc_link, buffer_in, length_bytes_in, 1);
|
// mount in and out buffer to the DMA link list
|
||||||
int link_ct_out = fill_dma_links(bsl->rx_desc_link, buffer_out, length_bytes_out, 0);
|
gdma_buffer_mount_config_t in_buf_mount_config = {
|
||||||
|
.buffer = buffer_in,
|
||||||
|
.length = length_bytes_in,
|
||||||
|
.flags = {
|
||||||
|
.mark_eof = true,
|
||||||
|
.mark_final = true,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
gdma_link_mount_buffers(bsl->tx_link_list, 0, &in_buf_mount_config, 1, NULL);
|
||||||
|
gdma_buffer_mount_config_t out_buf_mount_config = {
|
||||||
|
.buffer = buffer_out,
|
||||||
|
.length = length_bytes_out,
|
||||||
|
.flags = {
|
||||||
|
.mark_eof = false,
|
||||||
|
.mark_final = true,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
gdma_link_mount_buffers(bsl->rx_link_list, 0, &out_buf_mount_config, 1, NULL);
|
||||||
|
|
||||||
//Note: we add the ESP_CACHE_MSYNC_FLAG_UNALIGNED flag for now as otherwise esp_cache_msync will complain about
|
//Note: we add the ESP_CACHE_MSYNC_FLAG_UNALIGNED flag for now as otherwise esp_cache_msync will complain about
|
||||||
//the size not being aligned... we miss out on a check to see if the address is aligned this way. This needs to
|
//the size not being aligned... we miss out on a check to see if the address is aligned this way. This needs to
|
||||||
//be improved, but potentially needs a fix in esp_cache_msync not to check the size.
|
//be improved, but potentially needs a fix in esp_cache_msync not to check the size.
|
||||||
|
|
||||||
esp_cache_msync(bsl->rx_desc_link, link_ct_out * sizeof(dma_descriptor_t), ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED);
|
|
||||||
esp_cache_msync(bsl->tx_desc_link, link_ct_in * sizeof(dma_descriptor_t), ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED);
|
|
||||||
esp_cache_msync(buffer_in, length_bytes_in, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED);
|
esp_cache_msync(buffer_in, length_bytes_in, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED);
|
||||||
gdma_start(bsl->rx_channel, (intptr_t)bsl->rx_desc_link);
|
|
||||||
gdma_start(bsl->tx_channel, (intptr_t)bsl->tx_desc_link);
|
gdma_start(bsl->rx_channel, gdma_link_get_head_addr(bsl->rx_link_list));
|
||||||
|
gdma_start(bsl->tx_channel, gdma_link_get_head_addr(bsl->tx_link_list));
|
||||||
bitscrambler_start(bs);
|
bitscrambler_start(bs);
|
||||||
|
|
||||||
int timeout_ms = (length_bytes_out + length_bytes_in) / (BS_MIN_BYTES_PER_SEC / 1000);
|
int timeout_ms = (length_bytes_out + length_bytes_in) / (BS_MIN_BYTES_PER_SEC / 1000);
|
||||||
@@ -259,14 +261,7 @@ esp_err_t bitscrambler_loopback_run(bitscrambler_handle_t bs, void *buffer_in, s
|
|||||||
esp_cache_msync(buffer_out, length_bytes_out, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
|
esp_cache_msync(buffer_out, length_bytes_out, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
|
||||||
|
|
||||||
if (bytes_written) {
|
if (bytes_written) {
|
||||||
size_t l = 0;
|
*bytes_written = gdma_link_count_buffer_size_till_eof(bsl->rx_link_list, 0);
|
||||||
for (int i = 0; i < link_ct_out; i++) {
|
|
||||||
l += bsl->rx_desc_link[i].dw0.length;
|
|
||||||
if (bsl->rx_desc_link[i].dw0.suc_eof) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*bytes_written = l;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include "hal/bitscrambler_ll.h"
|
||||||
|
#include "esp_private/bitscrambler.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct bitscrambler_t bitscrambler_t;
|
||||||
|
|
||||||
|
struct bitscrambler_t {
|
||||||
|
bitscrambler_config_t cfg;
|
||||||
|
bitscrambler_dev_t *hw;
|
||||||
|
bitscrambler_extra_clean_up_func_t extra_clean_up; // Optional extra clean-up function
|
||||||
|
void* clean_up_user_ctx; // User context for extra clean-up function
|
||||||
|
bool loopback; //true if this is a loopback bitscrambler, i.e. the RX channel is also claimed
|
||||||
|
};
|
||||||
|
|
||||||
|
esp_err_t bitscrambler_init_loopback(bitscrambler_handle_t handle, const bitscrambler_config_t *config);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -8,9 +8,17 @@
|
|||||||
#include "esp_private/gdma.h"
|
#include "esp_private/gdma.h"
|
||||||
#include "soc/bitscrambler_peri_select.h"
|
#include "soc/bitscrambler_peri_select.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
gdma_trigger_t dma_trigger;
|
gdma_trigger_t dma_trigger;
|
||||||
int bus;
|
int bus;
|
||||||
} bitscrambler_periph_desc_t;
|
} bitscrambler_periph_desc_t;
|
||||||
|
|
||||||
extern const bitscrambler_periph_desc_t g_bitscrambler_periph_desc[];
|
extern const bitscrambler_periph_desc_t g_bitscrambler_periph_desc[];
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
#include "unity_test_utils.h"
|
#include "unity_test_utils.h"
|
||||||
#include "driver/bitscrambler.h"
|
#include "driver/bitscrambler.h"
|
||||||
#include "driver/bitscrambler_loopback.h"
|
#include "driver/bitscrambler_loopback.h"
|
||||||
#include "esp_dma_utils.h"
|
#include "esp_heap_caps.h"
|
||||||
|
|
||||||
BITSCRAMBLER_PROGRAM(bitscrambler_program_trivial, "trivial");
|
BITSCRAMBLER_PROGRAM(bitscrambler_program_trivial, "trivial");
|
||||||
BITSCRAMBLER_PROGRAM(bitscrambler_program_timeout, "timeout");
|
BITSCRAMBLER_PROGRAM(bitscrambler_program_timeout, "timeout");
|
||||||
@@ -33,6 +33,7 @@ TEST_CASE("Basic BitScrambler I/O", "[bs]")
|
|||||||
bitscrambler_free(bs);
|
bitscrambler_free(bs);
|
||||||
|
|
||||||
TEST_ASSERT_EQUAL_HEX8_ARRAY(data_in, data_out, len);
|
TEST_ASSERT_EQUAL_HEX8_ARRAY(data_in, data_out, len);
|
||||||
|
TEST_ASSERT_EQUAL(len, res_len);
|
||||||
|
|
||||||
free(data_in);
|
free(data_in);
|
||||||
free(data_out);
|
free(data_out);
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -141,13 +141,14 @@ esp_err_t gdma_del_link_list(gdma_link_list_handle_t list)
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t gdma_link_mount_buffers(gdma_link_list_handle_t list, uint32_t start_item_index, const gdma_buffer_mount_config_t *buf_config_array, size_t num_buf, uint32_t *end_item_index)
|
esp_err_t gdma_link_mount_buffers(gdma_link_list_handle_t list, int start_item_index, const gdma_buffer_mount_config_t *buf_config_array, size_t num_buf, int *end_item_index)
|
||||||
{
|
{
|
||||||
ESP_RETURN_ON_FALSE(list && buf_config_array && num_buf, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
ESP_RETURN_ON_FALSE(list && buf_config_array && num_buf, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||||
ESP_RETURN_ON_FALSE(start_item_index < list->num_items, ESP_ERR_INVALID_ARG, TAG, "invalid start item index");
|
|
||||||
size_t buffer_alignment = list->buffer_alignment;
|
size_t buffer_alignment = list->buffer_alignment;
|
||||||
size_t item_size = list->item_size;
|
size_t item_size = list->item_size;
|
||||||
uint32_t list_item_capacity = list->num_items;
|
uint32_t list_item_capacity = list->num_items;
|
||||||
|
// ensure the start_item_index is between 0 and `list_item_capacity - 1`
|
||||||
|
start_item_index = (start_item_index % list_item_capacity + list_item_capacity) % list_item_capacity;
|
||||||
size_t max_buffer_mount_length = ALIGN_DOWN(GDMA_MAX_BUFFER_SIZE_PER_LINK_ITEM, buffer_alignment);
|
size_t max_buffer_mount_length = ALIGN_DOWN(GDMA_MAX_BUFFER_SIZE_PER_LINK_ITEM, buffer_alignment);
|
||||||
uint32_t begin_item_idx = start_item_index;
|
uint32_t begin_item_idx = start_item_index;
|
||||||
gdma_link_list_item_t *lli_nc = NULL;
|
gdma_link_list_item_t *lli_nc = NULL;
|
||||||
@@ -155,7 +156,7 @@ esp_err_t gdma_link_mount_buffers(gdma_link_list_handle_t list, uint32_t start_i
|
|||||||
uint32_t num_items_avail = 0;
|
uint32_t num_items_avail = 0;
|
||||||
// if the link list is responsible for checking the ownership, we need to skip the items that are owned by the DMA
|
// if the link list is responsible for checking the ownership, we need to skip the items that are owned by the DMA
|
||||||
if (list->flags.check_owner) {
|
if (list->flags.check_owner) {
|
||||||
for (uint32_t i = 0; i < list_item_capacity; i++) {
|
for (int i = 0; i < list_item_capacity; i++) {
|
||||||
lli_nc = (gdma_link_list_item_t *)(list->items_nc + (i + start_item_index) % list_item_capacity * item_size);
|
lli_nc = (gdma_link_list_item_t *)(list->items_nc + (i + start_item_index) % list_item_capacity * item_size);
|
||||||
if (lli_nc->dw0.owner == GDMA_LLI_OWNER_CPU) {
|
if (lli_nc->dw0.owner == GDMA_LLI_OWNER_CPU) {
|
||||||
num_items_avail++;
|
num_items_avail++;
|
||||||
@@ -166,8 +167,8 @@ esp_err_t gdma_link_mount_buffers(gdma_link_list_handle_t list, uint32_t start_i
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check alignment and length for each buffer
|
// check alignment and length for each buffer
|
||||||
for (size_t i = 0; i < num_buf; i++) {
|
for (size_t bi = 0; bi < num_buf; bi++) {
|
||||||
const gdma_buffer_mount_config_t *config = &buf_config_array[i];
|
const gdma_buffer_mount_config_t *config = &buf_config_array[bi];
|
||||||
uint8_t *buf = (uint8_t *)config->buffer;
|
uint8_t *buf = (uint8_t *)config->buffer;
|
||||||
size_t len = config->length;
|
size_t len = config->length;
|
||||||
// check the buffer alignment
|
// check the buffer alignment
|
||||||
@@ -183,8 +184,8 @@ esp_err_t gdma_link_mount_buffers(gdma_link_list_handle_t list, uint32_t start_i
|
|||||||
lli_nc->next = (gdma_link_list_item_t *)(list->items + start_item_index * item_size);
|
lli_nc->next = (gdma_link_list_item_t *)(list->items + start_item_index * item_size);
|
||||||
|
|
||||||
begin_item_idx = start_item_index;
|
begin_item_idx = start_item_index;
|
||||||
for (size_t i = 0; i < num_buf; i++) {
|
for (size_t bi = 0; bi < num_buf; bi++) {
|
||||||
const gdma_buffer_mount_config_t *config = &buf_config_array[i];
|
const gdma_buffer_mount_config_t *config = &buf_config_array[bi];
|
||||||
uint8_t *buf = (uint8_t *)config->buffer;
|
uint8_t *buf = (uint8_t *)config->buffer;
|
||||||
size_t len = config->length;
|
size_t len = config->length;
|
||||||
// skip zero-length buffer
|
// skip zero-length buffer
|
||||||
@@ -193,7 +194,7 @@ esp_err_t gdma_link_mount_buffers(gdma_link_list_handle_t list, uint32_t start_i
|
|||||||
}
|
}
|
||||||
uint32_t num_items_need = (len + max_buffer_mount_length - 1) / max_buffer_mount_length;
|
uint32_t num_items_need = (len + max_buffer_mount_length - 1) / max_buffer_mount_length;
|
||||||
// mount the buffer to the link list
|
// mount the buffer to the link list
|
||||||
for (uint32_t i = 0; i < num_items_need; i++) {
|
for (int i = 0; i < num_items_need; i++) {
|
||||||
lli_nc = (gdma_link_list_item_t *)(list->items_nc + (i + begin_item_idx) % list_item_capacity * item_size);
|
lli_nc = (gdma_link_list_item_t *)(list->items_nc + (i + begin_item_idx) % list_item_capacity * item_size);
|
||||||
lli_nc->buffer = buf;
|
lli_nc->buffer = buf;
|
||||||
lli_nc->dw0.length = len > max_buffer_mount_length ? max_buffer_mount_length : len;
|
lli_nc->dw0.length = len > max_buffer_mount_length ? max_buffer_mount_length : len;
|
||||||
@@ -232,16 +233,25 @@ esp_err_t gdma_link_concat(gdma_link_list_handle_t first_link, int first_link_it
|
|||||||
{
|
{
|
||||||
ESP_RETURN_ON_FALSE(first_link && second_link, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
ESP_RETURN_ON_FALSE(first_link && second_link, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||||
gdma_link_list_item_t *lli_nc = NULL;
|
gdma_link_list_item_t *lli_nc = NULL;
|
||||||
lli_nc = (gdma_link_list_item_t *)(first_link->items_nc + (first_link->num_items + first_link_item_index) % first_link->num_items * first_link->item_size);
|
// ensure the first_link_item_index is between 0 and `num_items - 1`
|
||||||
lli_nc->next = (gdma_link_list_item_t *)(second_link->items + (second_link->num_items + second_link_item_index) % second_link->num_items * second_link->item_size);
|
int num_items = first_link->num_items;
|
||||||
|
first_link_item_index = (first_link_item_index % num_items + num_items) % num_items;
|
||||||
|
lli_nc = (gdma_link_list_item_t *)(first_link->items_nc + first_link_item_index * first_link->item_size);
|
||||||
|
// ensure the second_link_item_index is between 0 and `num_items - 1`
|
||||||
|
num_items = second_link->num_items;
|
||||||
|
second_link_item_index = (second_link_item_index % num_items + num_items) % num_items;
|
||||||
|
// concatenate the two link lists
|
||||||
|
lli_nc->next = (gdma_link_list_item_t *)(second_link->items + second_link_item_index * second_link->item_size);
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t gdma_link_set_owner(gdma_link_list_handle_t list, int item_index, gdma_lli_owner_t owner)
|
esp_err_t gdma_link_set_owner(gdma_link_list_handle_t list, int item_index, gdma_lli_owner_t owner)
|
||||||
{
|
{
|
||||||
ESP_RETURN_ON_FALSE_ISR(list, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
ESP_RETURN_ON_FALSE_ISR(list, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||||
ESP_RETURN_ON_FALSE_ISR(item_index < list->num_items, ESP_ERR_INVALID_ARG, TAG, "invalid item index");
|
int num_items = list->num_items;
|
||||||
gdma_link_list_item_t *lli = (gdma_link_list_item_t *)(list->items_nc + (list->num_items + item_index) % list->num_items * list->item_size);
|
// ensure the item_index is between 0 and `num_items - 1`
|
||||||
|
item_index = (item_index % num_items + num_items) % num_items;
|
||||||
|
gdma_link_list_item_t *lli = (gdma_link_list_item_t *)(list->items_nc + item_index * list->item_size);
|
||||||
lli->dw0.owner = owner;
|
lli->dw0.owner = owner;
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
@@ -249,8 +259,31 @@ esp_err_t gdma_link_set_owner(gdma_link_list_handle_t list, int item_index, gdma
|
|||||||
esp_err_t gdma_link_get_owner(gdma_link_list_handle_t list, int item_index, gdma_lli_owner_t *owner)
|
esp_err_t gdma_link_get_owner(gdma_link_list_handle_t list, int item_index, gdma_lli_owner_t *owner)
|
||||||
{
|
{
|
||||||
ESP_RETURN_ON_FALSE_ISR(list && owner, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
ESP_RETURN_ON_FALSE_ISR(list && owner, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||||
ESP_RETURN_ON_FALSE_ISR(item_index < list->num_items, ESP_ERR_INVALID_ARG, TAG, "invalid item index");
|
int num_items = list->num_items;
|
||||||
gdma_link_list_item_t *lli = (gdma_link_list_item_t *)(list->items_nc + (list->num_items + item_index) % list->num_items * list->item_size);
|
// ensure the item_index is between 0 and `num_items - 1`
|
||||||
|
item_index = (item_index % num_items + num_items) % num_items;
|
||||||
|
gdma_link_list_item_t *lli = (gdma_link_list_item_t *)(list->items_nc + item_index * list->item_size);
|
||||||
*owner = lli->dw0.owner;
|
*owner = lli->dw0.owner;
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t gdma_link_count_buffer_size_till_eof(gdma_link_list_handle_t list, int start_item_index)
|
||||||
|
{
|
||||||
|
if (!list) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int num_items = list->num_items;
|
||||||
|
// ensure the start_item_index is between 0 and `num_items - 1`
|
||||||
|
start_item_index = (start_item_index % num_items + num_items) % num_items;
|
||||||
|
size_t buf_size = 0;
|
||||||
|
gdma_link_list_item_t *lli_nc = NULL;
|
||||||
|
for (int i = 0; i < num_items; i++) {
|
||||||
|
lli_nc = (gdma_link_list_item_t *)(list->items_nc + (start_item_index + i) % num_items * list->item_size);
|
||||||
|
buf_size += lli_nc->dw0.length;
|
||||||
|
// break if the current item is the last one or the EOF item
|
||||||
|
if (lli_nc->dw0.suc_eof || lli_nc->next == NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buf_size;
|
||||||
|
}
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -91,7 +91,7 @@ typedef struct {
|
|||||||
* - ESP_ERR_INVALID_ARG: Mount the buffer failed because of invalid argument
|
* - ESP_ERR_INVALID_ARG: Mount the buffer failed because of invalid argument
|
||||||
* - ESP_FAIL: Mount the buffer failed because of other error
|
* - ESP_FAIL: Mount the buffer failed because of other error
|
||||||
*/
|
*/
|
||||||
esp_err_t gdma_link_mount_buffers(gdma_link_list_handle_t list, uint32_t start_item_index, const gdma_buffer_mount_config_t *buf_config_array, size_t num_buf, uint32_t *end_item_index);
|
esp_err_t gdma_link_mount_buffers(gdma_link_list_handle_t list, int start_item_index, const gdma_buffer_mount_config_t *buf_config_array, size_t num_buf, int *end_item_index);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the address of the head item in the link list
|
* @brief Get the address of the head item in the link list
|
||||||
@@ -164,6 +164,16 @@ esp_err_t gdma_link_set_owner(gdma_link_list_handle_t list, int item_index, gdma
|
|||||||
*/
|
*/
|
||||||
esp_err_t gdma_link_get_owner(gdma_link_list_handle_t list, int item_index, gdma_lli_owner_t *owner);
|
esp_err_t gdma_link_get_owner(gdma_link_list_handle_t list, int item_index, gdma_lli_owner_t *owner);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the size of the buffer that is mounted to the link list until the eof item (inclusive)
|
||||||
|
*
|
||||||
|
* @param[in] list Link list handle, allocated by `gdma_new_link_list`
|
||||||
|
* @param[in] start_item_index Index of the first item in the link list to be calculated
|
||||||
|
* @return Size of the buffer that is mounted to the link list until the eof item (inclusive).
|
||||||
|
* If the link list is empty or invalid, return 0.
|
||||||
|
*/
|
||||||
|
size_t gdma_link_count_buffer_size_till_eof(gdma_link_list_handle_t list, int start_item_index);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@@ -22,6 +22,8 @@ extern "C" {
|
|||||||
|
|
||||||
#define BITSCRAMBLER_LL_GET_HW(num) (((num) == 0) ? (&BITSCRAMBLER) : NULL)
|
#define BITSCRAMBLER_LL_GET_HW(num) (((num) == 0) ? (&BITSCRAMBLER) : NULL)
|
||||||
|
|
||||||
|
#define BITSCRAMBLER_LL_INST_LEN_WORDS 9 //length of one instruction in 32-bit words as defined by HW
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Select peripheral BitScrambler is attached to
|
* @brief Select peripheral BitScrambler is attached to
|
||||||
*
|
*
|
||||||
|
@@ -193,6 +193,10 @@ Resource allocation and program loading
|
|||||||
|
|
||||||
In loopback mode, a BitScrambler object is created using :cpp:func:`bitscrambler_loopback_create`. If there is a BitScrambler peripheral matching the requested characteristics, this function will return a handle to it. You can then use :cpp:func:`bitscrambler_load_program` to load a program into it, then call :cpp:func:`bitscrambler_loopback_run` to transform a memory buffer using the loaded program. You can call :cpp:func:`bitscrambler_loopback_run` any number of times; it's also permissible to use :cpp:func:`bitscrambler_load_program` to change programs between calls. Finally, to free the hardware resources and clean up memory, call :cpp:func:`bitscrambler_free`.
|
In loopback mode, a BitScrambler object is created using :cpp:func:`bitscrambler_loopback_create`. If there is a BitScrambler peripheral matching the requested characteristics, this function will return a handle to it. You can then use :cpp:func:`bitscrambler_load_program` to load a program into it, then call :cpp:func:`bitscrambler_loopback_run` to transform a memory buffer using the loaded program. You can call :cpp:func:`bitscrambler_loopback_run` any number of times; it's also permissible to use :cpp:func:`bitscrambler_load_program` to change programs between calls. Finally, to free the hardware resources and clean up memory, call :cpp:func:`bitscrambler_free`.
|
||||||
|
|
||||||
|
Application Example
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
* :example:`peripherals/bitscrambler` demonstrates how to use the BitScrambler loopback mode to transform a buffer of data into a different format.
|
||||||
|
|
||||||
API Reference
|
API Reference
|
||||||
-------------
|
-------------
|
||||||
|
@@ -5,4 +5,8 @@
|
|||||||
cmake_minimum_required(VERSION 3.16)
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
|
|
||||||
|
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
|
||||||
|
idf_build_set_property(MINIMAL_BUILD ON)
|
||||||
|
|
||||||
project(bitscrambler_example)
|
project(bitscrambler_example)
|
||||||
|
@@ -23,6 +23,15 @@ See the Getting Started Guide for full steps to configure and use ESP-IDF to bui
|
|||||||
|
|
||||||
## Example Output
|
## Example Output
|
||||||
|
|
||||||
|
```text
|
||||||
|
I (305) bs_example: BitScrambler example main
|
||||||
|
BitScrambler program complete. Input 40, output 40 bytes:
|
||||||
|
FF 00 00 00 00 00 00 00
|
||||||
|
80 80 80 80 80 80 80 80
|
||||||
|
01 02 04 08 10 20 40 80
|
||||||
|
00 FF 00 FF 00 FF 00 FF
|
||||||
|
FF 00 FF 00 FF 00 FF 00
|
||||||
|
```
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
|
|
||||||
idf_component_register(SRCS "bitscrambler_example_main.c"
|
idf_component_register(SRCS "bitscrambler_example_main.c"
|
||||||
PRIV_REQUIRES "esp_driver_bitscrambler"
|
PRIV_REQUIRES "esp_driver_bitscrambler"
|
||||||
INCLUDE_DIRS ".")
|
INCLUDE_DIRS ".")
|
||||||
|
|
||||||
target_bitscrambler_add_src("example.bsasm")
|
target_bitscrambler_add_src("example.bsasm")
|
||||||
|
@@ -1,22 +1,17 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: CC0-1.0
|
* SPDX-License-Identifier: CC0-1.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/unistd.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include "esp_err.h"
|
|
||||||
#include "esp_log.h"
|
|
||||||
#include "esp_check.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "driver/bitscrambler_loopback.h"
|
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include "esp_log.h"
|
||||||
#include "esp_heap_caps.h"
|
#include "esp_heap_caps.h"
|
||||||
|
#include "driver/bitscrambler_loopback.h"
|
||||||
|
|
||||||
//Assign a symbol to the example bitscrambler program. Note that the actual
|
//Assign a symbol to the example bitscrambler program. Note that the actual
|
||||||
//assembly and including in the binary happens in the CMakeLists.txt file.
|
//assembly and including in the binary happens in the CMakeLists.txt file.
|
||||||
|
@@ -1,10 +1,13 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||||
|
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||||
|
|
||||||
# Example bitscrambler program. Reads in 8 bytes and spits out 8 bytes are
|
# Example bitscrambler program. Reads in 8 bytes and spits out 8 bytes are
|
||||||
# the 'rotated' version of the input bytes. Specifically, output byte 0
|
# the 'rotated' version of the input bytes. Specifically, output byte 0
|
||||||
# consists of bit 0 of input byte 0, bit 0 of input byte 1, bit 0 of input
|
# consists of bit 0 of input byte 0, bit 0 of input byte 1, bit 0 of input
|
||||||
# byte 2 etc. Output byte 1 consists of bit 1 of input byte 0, bit 1 of
|
# byte 2 etc. Output byte 1 consists of bit 1 of input byte 0, bit 1 of
|
||||||
# input byte 1, bit 1 of input byte 2, etc.
|
# input byte 1, bit 1 of input byte 2, etc.
|
||||||
|
|
||||||
cfg trailing_bytes 64 #If we have an EOF on the input, we still
|
cfg trailing_bytes 8 #If we have an EOF on the input, we still
|
||||||
#need to process the 64 bits in M0/M1
|
#need to process the 64 bits in M0/M1
|
||||||
cfg prefetch true #We expect M0/M1 to be filled
|
cfg prefetch true #We expect M0/M1 to be filled
|
||||||
cfg lut_width_bits 8 #Not really applicable here
|
cfg lut_width_bits 8 #Not really applicable here
|
||||||
|
@@ -0,0 +1,21 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
|
import pytest
|
||||||
|
from pytest_embedded import Dut
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.esp32p4
|
||||||
|
@pytest.mark.generic
|
||||||
|
def test_bitscrambler_loopback_example(dut: Dut) -> None:
|
||||||
|
dut.expect_exact('BitScrambler example main', timeout=5)
|
||||||
|
dut.expect_exact('BitScrambler program complete. Input 40, output 40 bytes')
|
||||||
|
|
||||||
|
expected_lines = [
|
||||||
|
'FF 00 00 00 00 00 00 00',
|
||||||
|
'80 80 80 80 80 80 80 80',
|
||||||
|
'01 02 04 08 10 20 40 80',
|
||||||
|
'00 FF 00 FF 00 FF 00 FF',
|
||||||
|
'FF 00 FF 00 FF 00 FF 00',
|
||||||
|
]
|
||||||
|
for line in expected_lines:
|
||||||
|
dut.expect_exact(line)
|
Reference in New Issue
Block a user