test(BitScrambler): added more basic test cases

e.g. to test different eof mode, prefetch mode
This commit is contained in:
morris
2025-03-04 18:55:16 +08:00
parent cf169a402b
commit ee668ee658
15 changed files with 143 additions and 11 deletions

View File

@@ -224,7 +224,10 @@ esp_err_t bitscrambler_load_program(bitscrambler_handle_t bs, const void *progra
//Set options from header
bitscrambler_ll_set_lut_width(bs->hw, bs->cfg.dir, hdr.lut_width);
bitscrambler_ll_enable_prefetch_on_reset(bs->hw, bs->cfg.dir, hdr.prefetch);
bitscrambler_ll_set_eof_mode(bs->hw, bs->cfg.dir, hdr.eof_on);
// the bitscrambler assembler (bsasm.py) treats 'eof_on=1' as "upstream", a.k.a, read from upstream
// quote from bsasm.py: {'op': 'eof_on', 'default': 1, 'enum': {'upstream': 1, 'downstream': 0}},
bitscrambler_eof_mode_t eof_mode = hdr.eof_on ? BITSCRAMBLER_EOF_MODE_READ : BITSCRAMBLER_EOF_MODE_WRITE;
bitscrambler_ll_set_eof_mode(bs->hw, bs->cfg.dir, eof_mode);
bitscrambler_ll_set_tailing_bits(bs->hw, bs->cfg.dir, hdr.trailing_bits);
//fixed options
bitscrambler_ll_set_dummy_mode(bs->hw, bs->cfg.dir, BITSCRAMBLER_DUMMY_MODE_DUMMY);

View File

@@ -132,6 +132,7 @@ esp_err_t bitscrambler_loopback_create(bitscrambler_handle_t *handle, int attach
gdma_strategy_config_t gdma_strategy_conf = {
.auto_update_desc = true,
.owner_check = false,
.eof_till_data_popped = true,
};
gdma_apply_strategy(bs->rx_channel, &gdma_strategy_conf);
gdma_apply_strategy(bs->tx_channel, &gdma_strategy_conf);

View File

@@ -16,3 +16,5 @@ idf_component_register(SRCS ${srcs}
target_bitscrambler_add_src("timeout.bsasm")
target_bitscrambler_add_src("trivial.bsasm")
target_bitscrambler_add_src("eof_upstream.bsasm")
target_bitscrambler_add_src("eof_downstream.bsasm")

View File

@@ -0,0 +1,13 @@
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
cfg prefetch false # disable data prefetch
cfg eof_on downstream # set EOF on downstream
cfg trailing_bytes 4
loop:
read 8 # because of prefetch is disabled, we need to read 8 bits manually
set 0..15 L, # don't care what the input is, just pull up/down the output data
set 16..31 H,
write 32,
jmp loop

View File

@@ -0,0 +1,13 @@
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
cfg prefetch false # disable data prefetch
cfg eof_on upstream # set EOF on upstream
cfg trailing_bytes 1
loop:
read 8 # because of prefetch is disabled, we need to read 8 bits manually
set 0..15 L, # don't care what the input is, just pull up/down the output data
set 16..31 H,
write 32,
jmp loop

View File

@@ -13,6 +13,8 @@
BITSCRAMBLER_PROGRAM(bitscrambler_program_trivial, "trivial");
BITSCRAMBLER_PROGRAM(bitscrambler_program_timeout, "timeout");
BITSCRAMBLER_PROGRAM(bitscrambler_program_eof_upstream, "eof_upstream");
BITSCRAMBLER_PROGRAM(bitscrambler_program_eof_downstream, "eof_downstream");
TEST_CASE("Basic BitScrambler I/O", "[bs]")
{
@@ -54,3 +56,61 @@ TEST_CASE("Timeout on stuck program", "[bs]")
free(data_in);
free(data_out);
}
TEST_CASE("BitScrambler with EOF counted on upstream", "[bs]")
{
const size_t len = 32;
uint8_t *data_in = heap_caps_aligned_calloc(8, 1, len, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
uint32_t *data_out = heap_caps_aligned_calloc(8, 1, len * 4, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
TEST_ASSERT_NOT_NULL(data_in);
TEST_ASSERT_NOT_NULL(data_out);
bitscrambler_handle_t bs;
TEST_ESP_OK(bitscrambler_loopback_create(&bs, SOC_BITSCRAMBLER_ATTACH_I2S0, len * 4));
TEST_ESP_OK(bitscrambler_load_program(bs, bitscrambler_program_eof_upstream));
size_t res_len = 0;
TEST_ESP_OK(bitscrambler_loopback_run(bs, data_in, len, data_out, len * 4, &res_len));
bitscrambler_free(bs);
printf("BitScrambler program complete. Input %zu, output %zu bytes:\n", len, res_len);
for (size_t i = 0; i < res_len / 4; i++) {
printf("%08lX ", data_out[i]);
if (i % 4 == 3) {
printf("\n");
}
TEST_ASSERT_EQUAL(0xFFFF0000, data_out[i]);
}
TEST_ASSERT_EQUAL(len * 4, res_len);
free(data_in);
free(data_out);
}
TEST_CASE("BitScrambler with EOF counted on downstream", "[bs]")
{
const size_t len = 32;
uint8_t *data_in = heap_caps_aligned_calloc(8, 1, len, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
uint32_t *data_out = heap_caps_aligned_calloc(8, 1, len * 4, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
TEST_ASSERT_NOT_NULL(data_in);
TEST_ASSERT_NOT_NULL(data_out);
bitscrambler_handle_t bs;
TEST_ESP_OK(bitscrambler_loopback_create(&bs, SOC_BITSCRAMBLER_ATTACH_I2S0, len * 4));
TEST_ESP_OK(bitscrambler_load_program(bs, bitscrambler_program_eof_downstream));
size_t res_len = 0;
TEST_ESP_OK(bitscrambler_loopback_run(bs, data_in, len, data_out, len * 4, &res_len));
bitscrambler_free(bs);
printf("BitScrambler program complete. Input %zu, output %zu bytes:\n", len, res_len);
for (size_t i = 0; i < res_len / 4; i++) {
printf("%08lX ", data_out[i]);
if (i % 4 == 3) {
printf("\n");
}
TEST_ASSERT_EQUAL(0xFFFF0000, data_out[i]);
}
TEST_ASSERT_EQUAL(len * 4, res_len);
free(data_in);
free(data_out);
}

View File

@@ -1,3 +1,6 @@
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
cfg trailing_bytes 0 #End program as soon as the input EOFs.
cfg prefetch true #We expect M0/M1 to be filled
cfg lut_width_bits 8 #Not really applicable here

View File

@@ -1,8 +1,11 @@
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
# Example bitscrambler program. Does nothing but forward all bytes.
cfg trailing_bytes 12 # Let M0/M1 empty when EOF on input is found
cfg eof_on upstream
cfg trailing_bytes 8 # Let M0/M1 empty when EOF on input is found
cfg prefetch true # We expect M0/M1 to be filled
cfg lut_width_bits 8 # Not really applicable here
loop:
set 0..31 0..31,

View File

@@ -280,6 +280,21 @@ static inline bitscrambler_state_t bitscrambler_ll_get_current_state(bitscramble
return BITSCRAMBLER_STATE_UNKNOWN;
}
/**
* @brief Return if the bitscrambler FIFO is ready
*
* @note For TX, means the outfifo is not empty, then we can start the peripheral to transmit the data
* For RX, means the infifo is not full, then we can start the peripheral to receive the data
*
* @param hw BitScrambler hardware instance address.
* @param dir Direction, BITSCRAMBLER_DIR_TX or BITSCRAMBLER_DIR_RX
* @return true if FIFO is ready, false otherwise
*/
static inline bool bitscrambler_ll_is_fifo_ready(bitscrambler_dev_t *hw, bitscrambler_direction_t dir)
{
return hw->state[dir].fifo_empty;
}
/**
* @brief Enable the bus clock for BitScrambler module
*/

View File

@@ -280,6 +280,21 @@ static inline bitscrambler_state_t bitscrambler_ll_get_current_state(bitscramble
return BITSCRAMBLER_STATE_UNKNOWN;
}
/**
* @brief Return if the bitscrambler FIFO is ready
*
* @note For TX, means the outfifo is not empty, then we can start the peripheral to transmit the data
* For RX, means the infifo is not full, then we can start the peripheral to receive the data
*
* @param hw BitScrambler hardware instance address.
* @param dir Direction, BITSCRAMBLER_DIR_TX or BITSCRAMBLER_DIR_RX
* @return true if FIFO is ready, false otherwise
*/
static inline bool bitscrambler_ll_is_fifo_ready(bitscrambler_dev_t *hw, bitscrambler_direction_t dir)
{
return hw->state[dir].fifo_empty;
}
/**
* @brief Enable the bus clock for BitScrambler module
*/

View File

@@ -62,6 +62,9 @@ typedef enum {
/**
* @brief Commands to set the state of bitscrambler
*
* @note Pause->Run, bitscrambler can continue from the last instruction;
* Halt->Run, bitscrambler will start from the first instruction;
*/
typedef enum {
BITSCRAMBLER_SET_STATE_RUN, /*!< Run */

View File

@@ -163,7 +163,7 @@ Meta-instructions set global BitScrambler configuration. Meta-instructions are a
Global configuration meta-instructions
""""""""""""""""""""""""""""""""""""""
- ``cfg prefetch true|false``: If prefetch is set to ``true``, the BitScrambler will read 64 bits from the input DMA stream into the input register at startup. If set to ``false``, the input register is initialized to zero. This setting defaults to ``true`` if not specified.
- ``cfg prefetch true|false``: If prefetch is set to ``true``, the BitScrambler will read 64 bits from the input DMA stream into the input register at startup. If set to ``false``, the input register is initialized to zero. This setting defaults to ``true`` if not specified. Please note, if the prefetch is enabled while the input stream can't provide at least 64 bits of data, the BitScrambler will hang.
- ``cfg eof_on upstream|downstream``: After the input stream ends, the BitScrambler will still process a certain amount of 'trailing' dummy bytes so it can flush any data contained in its registers. This setting indicates from where the data will be counted: ``upstream`` makes the bitscrambler count the bytes being read, ``downstream`` makes it count the bytes being written. This defaults to ``upstream`` if not specified.
- ``cfg trailing_bytes N``: This indicates how many dummy bytes will be read or written (depending on the ``eof_on`` setting) before the BitScrambler indicates an end-of-stream on its output. This defaults to ``0`` if not specified.
- ``cfg lut_width_bits 8|16|32``: This selects the bus width of the LUT output RAM, in bits. The LUT can be 2048x8 bits, 1024x16 bits or 512x32 bits in size. This defaults to ``32`` if not specified.

View File

@@ -163,7 +163,7 @@
全局配置元指令
"""""""""""""""
- ``cfg prefetch true|false``:如果 ``prefetch`` 设置为 ``true``,则比特调节器启动时从输入 DMA 流中读取 64 位数据到输入寄存器中。如果设置为 ``false``,输入寄存器将被初始化为零。默认为 ``true``
- ``cfg prefetch true|false``:如果 ``prefetch`` 设置为 ``true``,则比特调节器启动时从输入 DMA 流中读取 64 位数据到输入寄存器中。如果设置为 ``false``,输入寄存器将被初始化为零。默认为 ``true``请注意,如果启用了 prefetch 但是输入流无法提供至少 64 位的数据,比特调节器会发生挂起。
- ``cfg eof_on upstream|downstream``:输入流结束后,比特调节器仍会计算一定量的“尾随”填充字节,以便清空其寄存器中可能存储的数据。此设置表示的是尾随字节的来源:如果设置为 ``upstream``,比特调节器从输入流中读取一定数量的填充字节,如果设置为 ``downstream``,比特调节器会等待写入足够的字节。默认为 ``upstream``
- ``cfg trailing_bytes N``:该设置指示比特调节器在指示输出流结束之前,需要读取或写入(取决于 ``eof_on`` 设置)多少个填充字节。默认值为 ``0``
- ``cfg lut_width_bits 8|16|32``:该设置选择 LUT 输出 RAM 的总线宽度单位。LUT 的大小可以是 2048×8 位、1024×16 位或 512×32 位。默认值为 ``32``

View File

@@ -31,12 +31,13 @@ void app_main(void)
{
ESP_LOGI(TAG, "BitScrambler example main");
size_t test_data_len = sizeof(testdata);
uint8_t* result_buf = heap_caps_calloc(test_data_len, 1, MALLOC_CAP_DMA);
size_t input_data_len = sizeof(testdata);
size_t output_data_len = input_data_len; // because the example BitScrambler program doesn't increase or decrease the data length
uint8_t* result_buf = heap_caps_calloc(output_data_len, 1, MALLOC_CAP_DMA);
assert(result_buf);
size_t result_buf_size = heap_caps_get_allocated_size(result_buf);
assert(result_buf_size >= test_data_len);
assert(result_buf_size >= output_data_len);
bitscrambler_handle_t bs;
ESP_ERROR_CHECK(bitscrambler_loopback_create(&bs, SOC_BITSCRAMBLER_ATTACH_I2S0, result_buf_size));
@@ -44,10 +45,10 @@ void app_main(void)
size_t result_len;
// we can even use a const array as the input data because the DMA can read data from the Flash region
ESP_ERROR_CHECK(bitscrambler_loopback_run(bs, (void*)testdata, test_data_len, result_buf, result_buf_size, &result_len));
ESP_ERROR_CHECK(bitscrambler_loopback_run(bs, (void*)testdata, input_data_len, result_buf, result_buf_size, &result_len));
bitscrambler_free(bs);
printf("BitScrambler program complete. Input %zu, output %zu bytes:\n", test_data_len, result_len);
printf("BitScrambler program complete. Input %zu, output %zu bytes:\n", input_data_len, result_len);
for (size_t i = 0; i < result_len; i++) {
printf("%02X ", result_buf[i]);
if ((i & 7) == 7) {

View File

@@ -7,10 +7,10 @@
# 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.
cfg eof_on downstream
cfg trailing_bytes 8 #If we have an EOF on the input, we still
#need to process the 64 bits in M0/M1
cfg prefetch true #We expect M0/M1 to be filled
cfg lut_width_bits 8 #Not really applicable here
loop:
# Note: we start with 64 bits in M0 and M1, so we can immediately start outputting.