forked from espressif/esp-idf
add unit tests to esp-idf
rename nvs host test folder, modify .gitlab-ci.yml remove unit-test-app build re-format unit test files remove extra newlines in project.mk some refactoring for unit test part in project.mk add build files of unit-test-app in gitignore add README.md for unit test app correct headings in README.md remove files and make minor tweaks in unit test app update .gitlab-ci.yml to use unit test app delete unused lines in component_wrapper.mk delete periph_i2s.h and lcd test add text floating point in components/esp32/test/Kconfig correct idf test build paths in .gitlab-ci.yml
This commit is contained in:
9
components/esp32/test/Kconfig
Normal file
9
components/esp32/test/Kconfig
Normal file
@@ -0,0 +1,9 @@
|
||||
menu "TESTS"
|
||||
|
||||
config FP_TEST_ENABLE
|
||||
bool "Enable test fp"
|
||||
default "y"
|
||||
help
|
||||
For FPGA single core CPU which has no floating point support, floating point test should be disabled.
|
||||
|
||||
endmenu
|
||||
17
components/esp32/test/component.mk
Normal file
17
components/esp32/test/component.mk
Normal file
@@ -0,0 +1,17 @@
|
||||
#
|
||||
#Component Makefile
|
||||
#
|
||||
|
||||
COMPONENT_EXTRA_CLEAN := test_tjpgd_logo.h
|
||||
|
||||
COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive
|
||||
|
||||
COMPONENT_SRCDIRS := . test_vectors
|
||||
|
||||
include $(IDF_PATH)/make/component_common.mk
|
||||
|
||||
test_tjpgd.o: test_tjpgd_logo.h
|
||||
|
||||
test_tjpgd_logo.h: $(COMPONENT_PATH)/logo.jpg
|
||||
$(summary) XXD logo.jpg
|
||||
$(Q) cd $(COMPONENT_PATH); xxd -i logo.jpg $(COMPONENT_BUILD_DIR)/test_tjpgd_logo.h
|
||||
BIN
components/esp32/test/logo.jpg
Normal file
BIN
components/esp32/test/logo.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.4 KiB |
293
components/esp32/test/test_ahb_arb.c
Normal file
293
components/esp32/test/test_ahb_arb.c
Normal file
@@ -0,0 +1,293 @@
|
||||
|
||||
#include <esp_types.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "rom/ets_sys.h"
|
||||
#include "rom/lldesc.h"
|
||||
#include "rom/gpio.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
|
||||
#include "unity.h"
|
||||
|
||||
#include "soc/uart_reg.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/gpio_reg.h"
|
||||
#include "soc/i2s_reg.h"
|
||||
|
||||
|
||||
#define DPORT_I2S0_CLK_EN (BIT(4))
|
||||
#define DPORT_I2S0_RST (BIT(4))
|
||||
|
||||
|
||||
/*
|
||||
This test tests the s32c1i instruction when the AHB bus is also used. To create some AHB traffic, we use the I2S interface
|
||||
to copy bytes over from one memory location to another. DO NOT USE the i2s routines inhere, they've been trial-and-error'ed until
|
||||
the point where they happened to do what I want.
|
||||
*/
|
||||
|
||||
static void lcdIfaceInit()
|
||||
{
|
||||
SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN);
|
||||
CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST);
|
||||
|
||||
//Init pins to i2s functions
|
||||
SET_PERI_REG_MASK(GPIO_ENABLE_W1TS_REG, (1 << 11) | (1 << 3) | (1 << 0) | (1 << 2) | (1 << 5) | (1 << 16) | (1 << 17) | (1 << 18) | (1 << 19) | (1 << 20)); //ENABLE GPIO oe_enable
|
||||
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO5_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO16_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO17_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO18_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO19_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO20_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, 2); //11
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO26_U, 0); //RS
|
||||
|
||||
WRITE_PERI_REG(GPIO_FUNC0_OUT_SEL_CFG_REG, (148 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC2_OUT_SEL_CFG_REG, (149 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC5_OUT_SEL_CFG_REG, (150 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC16_OUT_SEL_CFG_REG, (151 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC17_OUT_SEL_CFG_REG, (152 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC18_OUT_SEL_CFG_REG, (153 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC19_OUT_SEL_CFG_REG, (154 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC20_OUT_SEL_CFG_REG, (155 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC26_OUT_SEL_CFG_REG, (156 << GPIO_FUNC0_OUT_SEL_S)); //RS
|
||||
WRITE_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG_REG, (I2S0O_WS_OUT_IDX << GPIO_FUNC0_OUT_SEL_S));
|
||||
// WRITE_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG, (I2S0O_BCK_OUT_IDX<<GPIO_GPIO_FUNC0_OUT_SEL_S));
|
||||
|
||||
//GPIO_SET_GPIO_FUNC11_OUT_INV_SEL(1); //old
|
||||
WRITE_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG_REG, READ_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG_REG) | GPIO_FUNC11_OUT_INV_SEL);
|
||||
|
||||
//Reset I2S subsystem
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET);
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET);
|
||||
|
||||
WRITE_PERI_REG(I2S_CONF_REG(0), 0);//I2S_SIG_LOOPBACK);
|
||||
WRITE_PERI_REG(I2S_CONF2_REG(0), 0);
|
||||
|
||||
WRITE_PERI_REG(I2S_SAMPLE_RATE_CONF_REG(0),
|
||||
(16 << I2S_RX_BITS_MOD_S) |
|
||||
(16 << I2S_TX_BITS_MOD_S) |
|
||||
(1 << I2S_RX_BCK_DIV_NUM_S) |
|
||||
(1 << I2S_TX_BCK_DIV_NUM_S));
|
||||
WRITE_PERI_REG(I2S_CLKM_CONF_REG(0),
|
||||
I2S_CLKA_ENA | I2S_CLK_EN |
|
||||
(1 << I2S_CLKM_DIV_A_S) |
|
||||
(1 << I2S_CLKM_DIV_B_S) |
|
||||
(1 << I2S_CLKM_DIV_NUM_S));
|
||||
WRITE_PERI_REG(I2S_FIFO_CONF_REG(0),
|
||||
(32 << I2S_TX_DATA_NUM_S) | //Low watermark for IRQ
|
||||
(32 << I2S_RX_DATA_NUM_S));
|
||||
|
||||
WRITE_PERI_REG(I2S_CONF1_REG(0), I2S_RX_PCM_BYPASS | I2S_TX_PCM_BYPASS);
|
||||
|
||||
WRITE_PERI_REG(I2S_CONF_CHAN_REG(0), (2 << I2S_TX_CHAN_MOD_S) | (2 << I2S_RX_CHAN_MOD_S));
|
||||
|
||||
//Invert WS to active-low
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_RIGHT_FIRST | I2S_RX_RIGHT_FIRST);
|
||||
WRITE_PERI_REG(I2S_TIMING_REG(0), 0);
|
||||
}
|
||||
|
||||
|
||||
static volatile lldesc_t dmaDesc[2];
|
||||
|
||||
static void finishDma()
|
||||
{
|
||||
//No need to finish if no DMA transfer going on
|
||||
if (!(READ_PERI_REG(I2S_FIFO_CONF_REG(0))&I2S_DSCR_EN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Wait till fifo done
|
||||
while (!(READ_PERI_REG(I2S_INT_RAW_REG(0))&I2S_TX_REMPTY_INT_RAW)) ;
|
||||
//Wait for last bytes to leave i2s xmit thing
|
||||
//ToDo: poll bit in next hw
|
||||
// for (i=0; i<(1<<8); i++);
|
||||
while (!(READ_PERI_REG(I2S_STATE_REG(0))&I2S_TX_IDLE));
|
||||
|
||||
//Reset I2S for next transfer
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_START | I2S_RX_START);
|
||||
CLEAR_PERI_REG_MASK(I2S_OUT_LINK_REG(0), I2S_OUTLINK_START | I2S_INLINK_START);
|
||||
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_RESET | I2S_RX_FIFO_RESET);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_RESET | I2S_RX_FIFO_RESET);
|
||||
|
||||
// for (i=0; i<(1<<8); i++);
|
||||
while ((READ_PERI_REG(I2S_STATE_REG(0))&I2S_TX_FIFO_RESET_BACK));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
This is a very, very, very hacked up LCD routine which ends up basically doing a memcpy from sbuf to rbuf.
|
||||
*/
|
||||
static void sendRecvBufDma(uint16_t *sbuf, uint16_t *rbuf, int len)
|
||||
{
|
||||
//Fill DMA descriptor
|
||||
dmaDesc[0].length = len * 2;
|
||||
dmaDesc[0].size = len * 2;
|
||||
dmaDesc[0].owner = 1;
|
||||
dmaDesc[0].sosf = 0;
|
||||
dmaDesc[0].buf = (uint8_t *)sbuf;
|
||||
dmaDesc[0].offset = 0; //unused in hw
|
||||
dmaDesc[0].empty = 0;
|
||||
dmaDesc[0].eof = 1;
|
||||
dmaDesc[1].length = len * 2;
|
||||
dmaDesc[1].size = len * 2;
|
||||
dmaDesc[1].owner = 1;
|
||||
dmaDesc[1].sosf = 0;
|
||||
dmaDesc[1].buf = (uint8_t *)rbuf;
|
||||
dmaDesc[1].offset = 0; //unused in hw
|
||||
dmaDesc[1].empty = 0;
|
||||
dmaDesc[1].eof = 1;
|
||||
|
||||
//Reset DMA
|
||||
SET_PERI_REG_MASK(I2S_LC_CONF_REG(0), I2S_IN_RST | I2S_OUT_RST | I2S_AHBM_RST | I2S_AHBM_FIFO_RST);
|
||||
CLEAR_PERI_REG_MASK(I2S_LC_CONF_REG(0), I2S_IN_RST | I2S_OUT_RST | I2S_AHBM_RST | I2S_AHBM_FIFO_RST);
|
||||
|
||||
//Reset I2S FIFO
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_FIFO_RESET);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_FIFO_RESET);
|
||||
|
||||
//Set desc addr
|
||||
CLEAR_PERI_REG_MASK(I2S_OUT_LINK_REG(0), I2S_OUTLINK_ADDR);
|
||||
SET_PERI_REG_MASK(I2S_OUT_LINK_REG(0), ((uint32_t)(&dmaDesc[0]))&I2S_OUTLINK_ADDR);
|
||||
CLEAR_PERI_REG_MASK(I2S_IN_LINK_REG(0), I2S_INLINK_ADDR);
|
||||
SET_PERI_REG_MASK(I2S_IN_LINK_REG(0), ((uint32_t)(&dmaDesc[1]))&I2S_INLINK_ADDR);
|
||||
|
||||
SET_PERI_REG_MASK(I2S_FIFO_CONF_REG(0), I2S_DSCR_EN); //Enable DMA mode
|
||||
|
||||
WRITE_PERI_REG(I2S_RXEOF_NUM_REG(0), len);
|
||||
|
||||
//Enable and configure DMA
|
||||
WRITE_PERI_REG(I2S_LC_CONF_REG(0), I2S_OUT_DATA_BURST_EN |
|
||||
I2S_OUT_EOF_MODE | I2S_OUTDSCR_BURST_EN | I2S_OUT_DATA_BURST_EN |
|
||||
I2S_INDSCR_BURST_EN | I2S_MEM_TRANS_EN);
|
||||
|
||||
//Start transmission
|
||||
SET_PERI_REG_MASK(I2S_OUT_LINK_REG(0), I2S_OUTLINK_START);
|
||||
SET_PERI_REG_MASK(I2S_IN_LINK_REG(0), I2S_INLINK_START);
|
||||
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_START | I2S_RX_START);
|
||||
//Clear int flags
|
||||
WRITE_PERI_REG(I2S_INT_CLR_REG(0), 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
|
||||
#define DMALEN (2048-2)
|
||||
|
||||
static void tskLcd(void *pvParameters)
|
||||
{
|
||||
uint16_t *sbuf = malloc(DMALEN * 2);
|
||||
uint16_t *rbuf = malloc(DMALEN * 2);
|
||||
uint16_t xorval = 0;
|
||||
int x;
|
||||
lcdIfaceInit();
|
||||
// lcdFlush();
|
||||
while (1) {
|
||||
for (x = 0; x < DMALEN; x++) {
|
||||
sbuf[x] = x ^ xorval;
|
||||
}
|
||||
for (x = 0; x < DMALEN; x++) {
|
||||
rbuf[x] = 0; //clear rbuf
|
||||
}
|
||||
sendRecvBufDma(sbuf, rbuf, DMALEN);
|
||||
vTaskDelay(20 / portTICK_PERIOD_MS);
|
||||
finishDma();
|
||||
for (x = 0; x < DMALEN; x++) if (rbuf[x] != (x ^ xorval)) {
|
||||
printf("Rxbuf err! pos %d val %x xor %x", x, (int)rbuf[x], (int)xorval);
|
||||
}
|
||||
printf(".");
|
||||
fflush(stdout);
|
||||
xorval++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void test_s32c1i_lock(volatile int *lockvar, int lockval, int unlockval, volatile int *ctr);
|
||||
|
||||
static volatile int ctr = 0, state = 0;
|
||||
static volatile int lock = 0;
|
||||
|
||||
static void tskOne(void *pvParameters)
|
||||
{
|
||||
int x;
|
||||
int err = 0, run = 0;
|
||||
while (1) {
|
||||
ctr = 0; lock = 0;
|
||||
state = 1;
|
||||
for (x = 0; x < 16 * 1024; x++) {
|
||||
test_s32c1i_lock(&lock, 1, 0, &ctr);
|
||||
}
|
||||
vTaskDelay(60 / portTICK_PERIOD_MS);
|
||||
state = 2;
|
||||
if (ctr != 16 * 1024 * 2) {
|
||||
printf("Lock malfunction detected! Ctr=0x%x instead of %x\n", ctr, 16 * 1024 * 2);
|
||||
err++;
|
||||
}
|
||||
run++;
|
||||
printf("Run %d err %d\n", run, err);
|
||||
vTaskDelay(20 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
|
||||
#define FB2ADDR 0x40098000
|
||||
|
||||
static void tskTwo(void *pvParameters)
|
||||
{
|
||||
int x;
|
||||
int *p = (int *)FB2ADDR;
|
||||
int *s = (int *)test_s32c1i_lock;
|
||||
void (*test_s32c1i_lock2)(volatile int * lockvar, int lockval, int unlockval, volatile int * ctr) = (void *)FB2ADDR;
|
||||
volatile int w;
|
||||
int delay;
|
||||
for (x = 0; x < 100; x++) {
|
||||
*p++ = *s++; //copy routine to different pool
|
||||
}
|
||||
|
||||
while (1) {
|
||||
while (state != 1) ;
|
||||
for (x = 0; x < 16 * 1024; x++) {
|
||||
test_s32c1i_lock2(&lock, 2, 0, &ctr);
|
||||
//Some random delay to increase chance of weirdness
|
||||
if ((x & 0x1f) == 0) {
|
||||
delay = rand() & 0x1f;
|
||||
for (w = 0; w < delay; w++);
|
||||
}
|
||||
}
|
||||
while (state != 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("S32C1I vs AHB test (needs I2S)", "[hw]")
|
||||
{
|
||||
int i;
|
||||
TaskHandle_t th[3];
|
||||
state = 0;
|
||||
|
||||
printf("Creating tasks\n");
|
||||
xTaskCreatePinnedToCore(tskTwo , "tsktwo" , 2048, NULL, 3, &th[1], 1);
|
||||
xTaskCreatePinnedToCore(tskOne , "tskone" , 2048, NULL, 3, &th[0], 0);
|
||||
xTaskCreatePinnedToCore(tskLcd , "tsklcd" , 2048, NULL, 3, &th[2], 0);
|
||||
|
||||
// Let stuff run for 20s
|
||||
while (1) {
|
||||
vTaskDelay(20000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
//Shut down all the tasks
|
||||
for (i = 0; i < 3; i++) {
|
||||
vTaskDelete(th[i]);
|
||||
}
|
||||
}
|
||||
|
||||
51
components/esp32/test/test_ahb_arb_asm.S
Normal file
51
components/esp32/test/test_ahb_arb_asm.S
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
This little bit of code is executed in-place by one CPU, but copied to a different memory region
|
||||
by the other CPU. Make sure it stays position-independent.
|
||||
*/
|
||||
.text
|
||||
.align 4
|
||||
.global test_s32c1i_lock
|
||||
.type test_s32c1i_lock,@function
|
||||
//Args:
|
||||
//a2 - lock addr
|
||||
//a3 - val to lock with
|
||||
//a4 - val to unlock with
|
||||
//a5 - addr to increase
|
||||
test_s32c1i_lock:
|
||||
entry a1, 64
|
||||
wsr a4, SCOMPARE1
|
||||
lockloop:
|
||||
mov a6, a3
|
||||
s32c1i a6, a2, 0
|
||||
bne a4, a6, lockloop
|
||||
|
||||
l32i a6, a5, 0
|
||||
//Give other CPU the time to mess up the inc if the lock somehow malfunctions
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
addi a6, a6, 1
|
||||
s32i a6, a5, 0
|
||||
|
||||
|
||||
//No need to actually let this loop but hey, a hang indicates an error, right?
|
||||
wsr a3, SCOMPARE1
|
||||
unlockloop:
|
||||
mov a6, a4
|
||||
s32c1i a6, a2, 0
|
||||
bne a3, a6, unlockloop
|
||||
|
||||
retw
|
||||
132
components/esp32/test/test_fastbus.c
Normal file
132
components/esp32/test/test_fastbus.c
Normal file
@@ -0,0 +1,132 @@
|
||||
|
||||
#include <esp_types.h>
|
||||
#include <stdio.h>
|
||||
#include "rom/ets_sys.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "unity.h"
|
||||
#include "soc/uart_reg.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
|
||||
|
||||
/*
|
||||
This test tests the 'fast' peripherial bus at 0x3ff40000. This bus is connected directly to the core, and as such
|
||||
can receive 'speculative' reads, that is, reads that may or may not actually be executed in the code flow. This
|
||||
may mess with any FIFOs mapped in the region: if a byte gets dropped due to a missed speculative read, the fifo
|
||||
may advance to the next byte anyway.
|
||||
|
||||
This code tests reading/writing from the UART1 FIFO, using both cores. For this to work, it's required that the
|
||||
UARTs RX and TX lines are connected.
|
||||
*/
|
||||
|
||||
|
||||
void test_fastbus_cp(int fifo_addr, unsigned char *buf, int len, int *dummy);
|
||||
|
||||
static volatile int state = 0;
|
||||
static volatile int xor = 0;
|
||||
static unsigned char res[128];
|
||||
|
||||
static void tskOne(void *pvParameters)
|
||||
{
|
||||
int run = 0, err = 0;
|
||||
int x;
|
||||
int ct[256];
|
||||
volatile int w;
|
||||
int dummy;
|
||||
while (1) {
|
||||
state = 1;
|
||||
for (x = 0; x < 64; x++) {
|
||||
WRITE_PERI_REG(UART_FIFO_REG(1), x ^ xor);
|
||||
}
|
||||
for (w = 0; w < (1 << 14); w++); //delay
|
||||
state = 2;
|
||||
test_fastbus_cp(UART_FIFO_REG(1), &res[0], 64, &dummy);
|
||||
for (w = 0; w < (1 << 10); w++); //delay
|
||||
for (x = 0; x < 255; x++) {
|
||||
ct[x] = 0; //zero ctrs
|
||||
}
|
||||
for (x = 0; x < 128; x++) {
|
||||
ct[(int)res[x]^xor]++; //count values
|
||||
}
|
||||
for (x = 0; x < 255; x++) { //check counts
|
||||
if (ct[x] != (x < 128 ? 1 : 0)) {
|
||||
//Disregard first few loops; there may be crap in the fifo.
|
||||
if (run > 2) {
|
||||
err++;
|
||||
printf("Error! Received value %d %d times!\n", x, ct[x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
run++;
|
||||
if ((run & 255) == 0) {
|
||||
printf("Loop %d errct %d\n", run, err);
|
||||
}
|
||||
xor = (xor + 1) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
#define FB2ADDR 0x40098000
|
||||
|
||||
static void tskTwo(void *pvParameters)
|
||||
{
|
||||
int x;
|
||||
int dummy;
|
||||
int *p = (int *)FB2ADDR;
|
||||
int *s = (int *)test_fastbus_cp;
|
||||
for (x = 0; x < 100; x++) {
|
||||
*p++ = *s++;
|
||||
}
|
||||
void (*test_fastbus_cp2)(int fifo_addr, unsigned char * buf, int len, int * dummy) = (void *)FB2ADDR;
|
||||
|
||||
|
||||
while (1) {
|
||||
while (state != 1) ;
|
||||
for (x = 64; x < 128; x++) {
|
||||
WRITE_PERI_REG(UART_FIFO_REG(1), x ^ xor);
|
||||
}
|
||||
while (state != 2);
|
||||
test_fastbus_cp2(UART_FIFO_REG(1), &res[64], 64, &dummy);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO: split this thing into separate orthogonal tests
|
||||
TEST_CASE("Fast I/O bus test", "[hw]")
|
||||
{
|
||||
int i;
|
||||
if ((REG_UART_BASE(0) >> 16) != 0x3ff4) {
|
||||
printf("Error! Uart base isn't on fast bus.\n");
|
||||
TEST_ASSERT(0);
|
||||
}
|
||||
|
||||
PIN_PULLUP_DIS(PERIPHS_IO_MUX_SD_DATA3_U);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA2_U, FUNC_SD_DATA2_U1RXD);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA3_U, FUNC_SD_DATA3_U1TXD);
|
||||
|
||||
int reg_val = (1 << UART_RXFIFO_FULL_THRHD_S);
|
||||
WRITE_PERI_REG(UART_CONF1_REG(1), reg_val);
|
||||
WRITE_PERI_REG(UART_CLKDIV_REG(1), 0x30); //semi-random
|
||||
// CLEAR_PERI_REG_MASK(UART_INT_ENA_REG(1), UART_TXFIFO_EMPTY_INT_ENA|UART_RXFIFO_TOUT_INT_ENA);
|
||||
|
||||
TaskHandle_t th[2];
|
||||
printf("Creating tasks\n");
|
||||
xTaskCreatePinnedToCore(tskOne , "tskone" , 2048, NULL, 3, &th[0], 0);
|
||||
xTaskCreatePinnedToCore(tskTwo , "tsktwo" , 2048, NULL, 3, &th[1], 1);
|
||||
|
||||
// Let stuff run for 20s
|
||||
while (1) {
|
||||
vTaskDelay(20000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
//Shut down all the tasks
|
||||
for (i = 0; i < 2; i++) {
|
||||
vTaskDelete(th[i]);
|
||||
}
|
||||
xt_ints_off(1 << ETS_UART0_INUM);
|
||||
}
|
||||
|
||||
32
components/esp32/test/test_fastbus_asm.S
Normal file
32
components/esp32/test/test_fastbus_asm.S
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
This little bit of code is executed in-place by one CPU, but copied to a different memory region
|
||||
by the other CPU. Make sure it stays position-independent.
|
||||
*/
|
||||
.text
|
||||
.align 4
|
||||
.global test_fastbus_cp
|
||||
.type test_fastbus_cp,@function
|
||||
//Args:
|
||||
//a2 - fifo addr
|
||||
//a3 - buf addr
|
||||
//a4 - len
|
||||
//a5 - ptr to int to use
|
||||
test_fastbus_cp:
|
||||
entry a1,64
|
||||
back:
|
||||
beqi a4, 0, out //check if loop done
|
||||
s32i a4, a5, 0 //store value, for shits and/or giggles
|
||||
memw //make sure write happens
|
||||
l32i a4, a5, 0 //load value again, to thwart any prediction in the pipeline
|
||||
bbsi a4, 0, pred //Random jump to check predictive reads. Both branches should do the same.
|
||||
l32i a6, a2, 0 //read from fifo 1
|
||||
j predout
|
||||
pred:
|
||||
l32i a6, a2, 0 //read from fifo 2
|
||||
predout:
|
||||
s8i a6, a3, 0 //store result
|
||||
addi a3, a3, 1 //inc ptr
|
||||
addi a4, a4, -1 //next
|
||||
j back //loop again
|
||||
out:
|
||||
retw //and we are done
|
||||
195
components/esp32/test/test_fp.c
Normal file
195
components/esp32/test/test_fp.c
Normal file
@@ -0,0 +1,195 @@
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "unity.h"
|
||||
|
||||
#if CONFIG_FP_TEST_ENABLE
|
||||
static float addsf(float a, float b)
|
||||
{
|
||||
float result;
|
||||
asm volatile (
|
||||
"wfr f0, %1\n"
|
||||
"wfr f1, %2\n"
|
||||
"add.s f2, f0, f1\n"
|
||||
"rfr %0, f2\n"
|
||||
:"=r"(result):"r"(a), "r"(b)
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
static float mulsf(float a, float b)
|
||||
{
|
||||
float result;
|
||||
asm volatile (
|
||||
"wfr f0, %1\n"
|
||||
"wfr f1, %2\n"
|
||||
"mul.s f2, f0, f1\n"
|
||||
"rfr %0, f2\n"
|
||||
:"=r"(result):"r"(a), "r"(b)
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
static float divsf(float a, float b)
|
||||
{
|
||||
float result;
|
||||
asm volatile (
|
||||
"wfr f0, %1\n"
|
||||
"wfr f1, %2\n"
|
||||
"div0.s f3, f1 \n"
|
||||
"nexp01.s f4, f1 \n"
|
||||
"const.s f5, 1 \n"
|
||||
"maddn.s f5, f4, f3 \n"
|
||||
"mov.s f6, f3 \n"
|
||||
"mov.s f7, f1 \n"
|
||||
"nexp01.s f8, f0 \n"
|
||||
"maddn.s f6, f5, f3 \n"
|
||||
"const.s f5, 1 \n"
|
||||
"const.s f2, 0 \n"
|
||||
"neg.s f9, f8 \n"
|
||||
"maddn.s f5,f4,f6 \n"
|
||||
"maddn.s f2, f0, f3 \n"
|
||||
"mkdadj.s f7, f0 \n"
|
||||
"maddn.s f6,f5,f6 \n"
|
||||
"maddn.s f9,f4,f2 \n"
|
||||
"const.s f5, 1 \n"
|
||||
"maddn.s f5,f4,f6 \n"
|
||||
"maddn.s f2,f9,f6 \n"
|
||||
"neg.s f9, f8 \n"
|
||||
"maddn.s f6,f5,f6 \n"
|
||||
"maddn.s f9,f4,f2 \n"
|
||||
"addexpm.s f2, f7 \n"
|
||||
"addexp.s f6, f7 \n"
|
||||
"divn.s f2,f9,f6\n"
|
||||
"rfr %0, f2\n"
|
||||
:"=r"(result):"r"(a), "r"(b)
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
static float sqrtsf(float a)
|
||||
{
|
||||
float result;
|
||||
asm volatile (
|
||||
"wfr f0, %1\n"
|
||||
"sqrt0.s f2, f0\n"
|
||||
"const.s f5, 0\n"
|
||||
"maddn.s f5, f2, f2\n"
|
||||
"nexp01.s f3, f0\n"
|
||||
"const.s f4, 3\n"
|
||||
"addexp.s f3, f4\n"
|
||||
"maddn.s f4, f5, f3\n"
|
||||
"nexp01.s f5, f0\n"
|
||||
"neg.s f6, f5\n"
|
||||
"maddn.s f2, f4, f2\n"
|
||||
"const.s f1, 0\n"
|
||||
"const.s f4, 0\n"
|
||||
"const.s f7, 0\n"
|
||||
"maddn.s f1, f6, f2\n"
|
||||
"maddn.s f4, f2, f3\n"
|
||||
"const.s f6, 3\n"
|
||||
"maddn.s f7, f6, f2\n"
|
||||
"maddn.s f5, f1, f1\n"
|
||||
"maddn.s f6, f4, f2\n"
|
||||
"neg.s f3, f7\n"
|
||||
"maddn.s f1, f5, f3\n"
|
||||
"maddn.s f7, f6, f7\n"
|
||||
"mksadj.s f2, f0\n"
|
||||
"nexp01.s f5, f0\n"
|
||||
"maddn.s f5, f1, f1\n"
|
||||
"neg.s f3, f7\n"
|
||||
"addexpm.s f1, f2\n"
|
||||
"addexp.s f3, f2\n"
|
||||
"divn.s f1, f5, f3\n"
|
||||
"rfr %0, f1\n"
|
||||
:"=r"(result):"r"(a)
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
TEST_CASE("test FP add", "[fp]")
|
||||
{
|
||||
float a = 100.0f;
|
||||
float b = 0.5f;
|
||||
float c = addsf(a, b);
|
||||
float eps = c - 100.5f;
|
||||
printf("a=%g b=%g c=%g eps=%g\r\n", a, b, c, eps);
|
||||
TEST_ASSERT_TRUE(fabs(eps) < 0.000001);
|
||||
}
|
||||
|
||||
TEST_CASE("test FP mul", "[fp]")
|
||||
{
|
||||
float a = 100.0f;
|
||||
float b = 0.05f;
|
||||
float c = mulsf(a, b);
|
||||
float eps = c - 5.0f;
|
||||
printf("a=%g b=%g c=%g eps=%g\r\n", a, b, c, eps);
|
||||
TEST_ASSERT_TRUE(fabs(eps) < 0.000001);
|
||||
}
|
||||
|
||||
TEST_CASE("test FP div", "[fp]")
|
||||
{
|
||||
float a = 100.0f;
|
||||
float b = 5.0f;
|
||||
float c = divsf(a, b);
|
||||
float eps = c - 20.0f;
|
||||
printf("a=%g b=%g c=%g eps=%g\r\n", a, b, c, eps);
|
||||
TEST_ASSERT_TRUE(fabs(eps) < 0.000001);
|
||||
}
|
||||
|
||||
TEST_CASE("test FP sqrt", "[fp]")
|
||||
{
|
||||
float a = 100.0f;
|
||||
float c = sqrtsf(a);
|
||||
float eps = c - 10.0f;
|
||||
printf("a=%g c=%g eps=%g\r\n", a, c, eps);
|
||||
TEST_ASSERT_TRUE(fabs(eps) < 0.000001);
|
||||
}
|
||||
|
||||
|
||||
struct TestFPState {
|
||||
int fail;
|
||||
int done;
|
||||
};
|
||||
|
||||
static const int testFpIter = 100000;
|
||||
|
||||
static void tskTestFP(void *pvParameters)
|
||||
{
|
||||
struct TestFPState *state = (struct TestFPState *) pvParameters;
|
||||
for (int i = 0; i < testFpIter; ++i) {
|
||||
// calculate zero in a slightly obscure way
|
||||
float y = sqrtsf(addsf(1.0f, divsf(mulsf(sqrtsf(2), sqrtsf(2)), 2.0f)));
|
||||
y = mulsf(y, y);
|
||||
y = addsf(y, -2.0f);
|
||||
// check that result is not far from zero
|
||||
float eps = fabs(y);
|
||||
if (eps > 1e-6f) {
|
||||
state->fail++;
|
||||
printf("%s: i=%d y=%f eps=%f\r\n", __func__, i, y, eps);
|
||||
}
|
||||
}
|
||||
state->done++;
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
TEST_CASE("context switch saves FP registers", "[fp]")
|
||||
{
|
||||
struct TestFPState state;
|
||||
state.done = 0;
|
||||
state.fail = 0;
|
||||
xTaskCreatePinnedToCore(tskTestFP, "tsk1", 2048, &state, 3, NULL, 0);
|
||||
xTaskCreatePinnedToCore(tskTestFP, "tsk2", 2048, &state, 3, NULL, 0);
|
||||
xTaskCreatePinnedToCore(tskTestFP, "tsk3", 2048, &state, 3, NULL, 1);
|
||||
xTaskCreatePinnedToCore(tskTestFP, "tsk4", 2048, &state, 3, NULL, 0);
|
||||
while (state.done != 4) {
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
}
|
||||
if (state.fail) {
|
||||
const int total = testFpIter * 4;
|
||||
printf("Failed: %d, total: %d\r\n", state.fail, total);
|
||||
}
|
||||
TEST_ASSERT(state.fail == 0);
|
||||
}
|
||||
#endif
|
||||
77
components/esp32/test/test_miniz.c
Normal file
77
components/esp32/test/test_miniz.c
Normal file
@@ -0,0 +1,77 @@
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include "rom/miniz.h"
|
||||
#include "unity.h"
|
||||
|
||||
|
||||
#define DATASIZE (1024*64)
|
||||
|
||||
TEST_CASE("Test miniz compression/decompression", "[miniz]")
|
||||
{
|
||||
int x;
|
||||
char b;
|
||||
char *inbuf, *outbuf;
|
||||
tdefl_compressor *comp;
|
||||
tinfl_decompressor *decomp;
|
||||
tdefl_status status;
|
||||
size_t inbytes = 0, outbytes = 0, inpos = 0, outpos = 0, compsz;
|
||||
printf("Allocating data buffer and filling it with semi-random data\n");
|
||||
inbuf = malloc(DATASIZE);
|
||||
TEST_ASSERT(inbuf != NULL);
|
||||
srand(0);
|
||||
for (x = 0; x < DATASIZE; x++) {
|
||||
inbuf[x] = (x & 1) ? rand() & 0xff : 0;
|
||||
}
|
||||
printf("Allocating compressor & outbuf (%d bytes)\n", sizeof(tdefl_compressor));
|
||||
comp = malloc(sizeof(tdefl_compressor));
|
||||
TEST_ASSERT(comp != NULL);
|
||||
outbuf = malloc(DATASIZE);
|
||||
TEST_ASSERT(outbuf != NULL);
|
||||
printf("Compressing...\n");
|
||||
status = tdefl_init(comp, NULL, NULL, TDEFL_WRITE_ZLIB_HEADER | 1500);
|
||||
TEST_ASSERT(status == TDEFL_STATUS_OKAY);
|
||||
while (inbytes != DATASIZE) {
|
||||
outbytes = DATASIZE - outpos;
|
||||
inbytes = DATASIZE - inpos;
|
||||
tdefl_compress(comp, &inbuf[inpos], &inbytes, &outbuf[outpos], &outbytes, TDEFL_FINISH);
|
||||
printf("...Compressed %d into %d bytes\n", inbytes, outbytes);
|
||||
inpos += inbytes; outpos += outbytes;
|
||||
}
|
||||
compsz = outpos;
|
||||
free(comp);
|
||||
//Kill inbuffer
|
||||
for (x = 0; x < DATASIZE; x++) {
|
||||
inbuf[x] = 0;
|
||||
}
|
||||
free(inbuf);
|
||||
|
||||
inbuf = outbuf;
|
||||
outbuf = malloc(DATASIZE);
|
||||
TEST_ASSERT(outbuf != NULL);
|
||||
printf("Reinflating...\n");
|
||||
decomp = malloc(sizeof(tinfl_decompressor));
|
||||
TEST_ASSERT(decomp != NULL);
|
||||
tinfl_init(decomp);
|
||||
inpos = 0; outpos = 0;
|
||||
while (inbytes != compsz) {
|
||||
outbytes = DATASIZE - outpos;
|
||||
inbytes = compsz - inpos;
|
||||
tinfl_decompress(decomp, (const mz_uint8 *)&inbuf[inpos], &inbytes, (uint8_t *)outbuf, (mz_uint8 *)&outbuf[outpos], &outbytes, TINFL_FLAG_PARSE_ZLIB_HEADER);
|
||||
printf("...Decompressed %d into %d bytes\n", inbytes, outbytes);
|
||||
inpos += inbytes; outpos += outbytes;
|
||||
}
|
||||
printf("Checking if same...\n");
|
||||
srand(0);
|
||||
for (x = 0; x < DATASIZE; x++) {
|
||||
b = (x & 1) ? rand() & 0xff : 0;
|
||||
if (outbuf[x] != b) {
|
||||
printf("Pos %x: %hhx!=%hhx\n", x, outbuf[x], b);
|
||||
TEST_ASSERT(0);
|
||||
}
|
||||
}
|
||||
printf("Great Success!\n");
|
||||
free(inbuf);
|
||||
free(outbuf);
|
||||
free(decomp);
|
||||
}
|
||||
91
components/esp32/test/test_tjpgd.c
Normal file
91
components/esp32/test/test_tjpgd.c
Normal file
@@ -0,0 +1,91 @@
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include "rom/tjpgd.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "unity.h"
|
||||
|
||||
#include "test_tjpgd_logo.h"
|
||||
|
||||
typedef struct {
|
||||
const unsigned char *inData;
|
||||
int inPos;
|
||||
unsigned char *outData;
|
||||
int outW;
|
||||
int outH;
|
||||
} JpegDev;
|
||||
|
||||
|
||||
static UINT infunc(JDEC *decoder, BYTE *buf, UINT len)
|
||||
{
|
||||
JpegDev *jd = (JpegDev *)decoder->device;
|
||||
printf("Reading %d bytes from pos %d\n", len, jd->inPos);
|
||||
if (buf != NULL) {
|
||||
memcpy(buf, jd->inData + jd->inPos, len);
|
||||
}
|
||||
jd->inPos += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static UINT outfunc(JDEC *decoder, void *bitmap, JRECT *rect)
|
||||
{
|
||||
unsigned char *in = (unsigned char *)bitmap;
|
||||
unsigned char *out;
|
||||
int y;
|
||||
printf("Rect %d,%d - %d,%d\n", rect->top, rect->left, rect->bottom, rect->right);
|
||||
JpegDev *jd = (JpegDev *)decoder->device;
|
||||
for (y = rect->top; y <= rect->bottom; y++) {
|
||||
out = jd->outData + ((jd->outW * y) + rect->left) * 3;
|
||||
memcpy(out, in, ((rect->right - rect->left) + 1) * 3);
|
||||
in += ((rect->right - rect->left) + 1) * 3;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define TESTW 48
|
||||
#define TESTH 48
|
||||
#define WORKSZ 3100
|
||||
|
||||
TEST_CASE("Test JPEG decompression library", "[tjpgd]")
|
||||
{
|
||||
char aapix[] = " .:;+=xX$$";
|
||||
unsigned char *decoded, *p;
|
||||
char *work;
|
||||
int r;
|
||||
int x, y, v;
|
||||
JDEC decoder;
|
||||
JpegDev jd;
|
||||
decoded = malloc(48 * 48 * 3);
|
||||
for (x = 0; x < 48 * 48 * 3; x += 2) {
|
||||
decoded[x] = 0; decoded[x + 1] = 0xff;
|
||||
}
|
||||
work = malloc(WORKSZ);
|
||||
memset(work, 0, WORKSZ);
|
||||
|
||||
jd.inData = logo_jpg;
|
||||
jd.inPos = 0;
|
||||
jd.outData = decoded;
|
||||
jd.outW = TESTW;
|
||||
jd.outH = TESTH;
|
||||
|
||||
r = jd_prepare(&decoder, infunc, work, WORKSZ, (void *)&jd);
|
||||
TEST_ASSERT_EQUAL(r, JDR_OK);
|
||||
r = jd_decomp(&decoder, outfunc, 0);
|
||||
TEST_ASSERT_EQUAL(r, JDR_OK);
|
||||
|
||||
p = decoded + 2;
|
||||
for (y = 0; y < TESTH; y++) {
|
||||
for (x = 0; x < TESTH; x++) {
|
||||
v = ((*p) * (sizeof(aapix) - 2) * 2) / 256;
|
||||
printf("%c%c", aapix[v / 2], aapix[(v + 1) / 2]);
|
||||
p += 3;
|
||||
}
|
||||
printf("%c%c", ' ', '\n');
|
||||
}
|
||||
|
||||
free(work);
|
||||
free(decoded);
|
||||
}
|
||||
205
components/esp32/test/test_unal_dma.c
Normal file
205
components/esp32/test/test_unal_dma.c
Normal file
@@ -0,0 +1,205 @@
|
||||
|
||||
#include <esp_types.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "rom/ets_sys.h"
|
||||
#include "rom/lldesc.h"
|
||||
#include "rom/gpio.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "unity.h"
|
||||
|
||||
#include "soc/uart_reg.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/gpio_reg.h"
|
||||
#include "soc/i2s_reg.h"
|
||||
|
||||
|
||||
#define DPORT_I2S0_CLK_EN (BIT(4))
|
||||
#define DPORT_I2S0_RST (BIT(4))
|
||||
|
||||
static volatile lldesc_t dmaDesc[2];
|
||||
|
||||
|
||||
//hacked up routine to essentially do a memcpy() using dma. Supports max 4K-1 bytes.
|
||||
static void dmaMemcpy(void *in, void *out, int len)
|
||||
{
|
||||
volatile int i;
|
||||
SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN);
|
||||
CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST);
|
||||
|
||||
//Init pins to i2s functions
|
||||
SET_PERI_REG_MASK(GPIO_ENABLE_W1TS_REG, (1 << 11) | (1 << 3) | (1 << 0) | (1 << 2) | (1 << 5) | (1 << 16) | (1 << 17) | (1 << 18) | (1 << 19) | (1 << 20)); //ENABLE GPIO oe_enable
|
||||
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO5_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO16_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO17_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO18_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO19_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO20_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, 2); //11
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO26_U, 0); //RS
|
||||
|
||||
WRITE_PERI_REG(GPIO_FUNC0_OUT_SEL_CFG_REG, (148 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC2_OUT_SEL_CFG_REG, (149 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC5_OUT_SEL_CFG_REG, (150 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC16_OUT_SEL_CFG_REG, (151 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC17_OUT_SEL_CFG_REG, (152 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC18_OUT_SEL_CFG_REG, (153 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC19_OUT_SEL_CFG_REG, (154 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC20_OUT_SEL_CFG_REG, (155 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC26_OUT_SEL_CFG_REG, (156 << GPIO_FUNC0_OUT_SEL_S)); //RS
|
||||
WRITE_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG_REG, (I2S0O_WS_OUT_IDX << GPIO_FUNC0_OUT_SEL_S));
|
||||
// WRITE_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG, (I2S0O_BCK_OUT_IDX<<GPIO_GPIO_FUNC0_OUT_SEL_S));
|
||||
|
||||
//GPIO_SET_GPIO_FUNC11_OUT_INV_SEL(1); //old
|
||||
WRITE_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG_REG, READ_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG_REG) | GPIO_FUNC11_OUT_INV_SEL);
|
||||
|
||||
//Reset I2S subsystem
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET);
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET);
|
||||
|
||||
WRITE_PERI_REG(I2S_CONF_REG(0), 0);//I2S_I2S_SIG_LOOPBACK);
|
||||
WRITE_PERI_REG(I2S_CONF2_REG(0), 0);
|
||||
|
||||
WRITE_PERI_REG(I2S_SAMPLE_RATE_CONF_REG(0),
|
||||
(16 << I2S_RX_BITS_MOD_S) |
|
||||
(16 << I2S_TX_BITS_MOD_S) |
|
||||
(1 << I2S_RX_BCK_DIV_NUM_S) |
|
||||
(1 << I2S_TX_BCK_DIV_NUM_S));
|
||||
WRITE_PERI_REG(I2S_CLKM_CONF_REG(0),
|
||||
I2S_CLKA_ENA | I2S_CLK_EN |
|
||||
(1 << I2S_CLKM_DIV_A_S) |
|
||||
(1 << I2S_CLKM_DIV_B_S) |
|
||||
(1 << I2S_CLKM_DIV_NUM_S));
|
||||
WRITE_PERI_REG(I2S_FIFO_CONF_REG(0),
|
||||
(32 << I2S_TX_DATA_NUM_S) | //Low watermark for IRQ
|
||||
(32 << I2S_RX_DATA_NUM_S));
|
||||
|
||||
WRITE_PERI_REG(I2S_CONF1_REG(0), I2S_RX_PCM_BYPASS | I2S_TX_PCM_BYPASS);
|
||||
|
||||
WRITE_PERI_REG(I2S_CONF_CHAN_REG(0), (2 << I2S_TX_CHAN_MOD_S) | (2 << I2S_RX_CHAN_MOD_S));
|
||||
|
||||
//Invert WS to active-low
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_RIGHT_FIRST | I2S_RX_RIGHT_FIRST);
|
||||
WRITE_PERI_REG(I2S_TIMING_REG(0), 0);
|
||||
|
||||
//--
|
||||
//Fill DMA descriptor
|
||||
dmaDesc[0].length = len;
|
||||
dmaDesc[0].size = len;
|
||||
dmaDesc[0].owner = 1;
|
||||
dmaDesc[0].sosf = 0;
|
||||
dmaDesc[0].buf = (uint8_t *)in;
|
||||
dmaDesc[0].offset = 0; //unused in hw
|
||||
dmaDesc[0].empty = 0;
|
||||
dmaDesc[0].eof = 1;
|
||||
dmaDesc[1].length = len;
|
||||
dmaDesc[1].size = len;
|
||||
dmaDesc[1].owner = 1;
|
||||
dmaDesc[1].sosf = 0;
|
||||
dmaDesc[1].buf = (uint8_t *)out;
|
||||
dmaDesc[1].offset = 0; //unused in hw
|
||||
dmaDesc[1].empty = 0;
|
||||
dmaDesc[1].eof = 1;
|
||||
|
||||
//Reset DMA
|
||||
SET_PERI_REG_MASK(I2S_LC_CONF_REG(0), I2S_IN_RST | I2S_OUT_RST | I2S_AHBM_RST | I2S_AHBM_FIFO_RST);
|
||||
CLEAR_PERI_REG_MASK(I2S_LC_CONF_REG(0), I2S_IN_RST | I2S_OUT_RST | I2S_AHBM_RST | I2S_AHBM_FIFO_RST);
|
||||
|
||||
//Reset I2S FIFO
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_FIFO_RESET);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_FIFO_RESET);
|
||||
|
||||
//Set desc addr
|
||||
CLEAR_PERI_REG_MASK(I2S_OUT_LINK_REG(0), I2S_OUTLINK_ADDR);
|
||||
SET_PERI_REG_MASK(I2S_OUT_LINK_REG(0), ((uint32_t)(&dmaDesc[0]))&I2S_OUTLINK_ADDR);
|
||||
CLEAR_PERI_REG_MASK(I2S_IN_LINK_REG(0), I2S_INLINK_ADDR);
|
||||
SET_PERI_REG_MASK(I2S_IN_LINK_REG(0), ((uint32_t)(&dmaDesc[1]))&I2S_INLINK_ADDR);
|
||||
|
||||
SET_PERI_REG_MASK(I2S_FIFO_CONF_REG(0), I2S_DSCR_EN); //Enable DMA mode
|
||||
|
||||
WRITE_PERI_REG(I2S_RXEOF_NUM_REG(0), len);
|
||||
|
||||
//Enable and configure DMA
|
||||
WRITE_PERI_REG(I2S_LC_CONF_REG(0), I2S_OUT_DATA_BURST_EN |
|
||||
I2S_OUT_EOF_MODE | I2S_OUTDSCR_BURST_EN | I2S_OUT_DATA_BURST_EN |
|
||||
I2S_INDSCR_BURST_EN | I2S_MEM_TRANS_EN);
|
||||
|
||||
//Start transmission
|
||||
SET_PERI_REG_MASK(I2S_OUT_LINK_REG(0), I2S_OUTLINK_START);
|
||||
SET_PERI_REG_MASK(I2S_IN_LINK_REG(0), I2S_INLINK_START);
|
||||
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_START | I2S_RX_START);
|
||||
//Clear int flags
|
||||
WRITE_PERI_REG(I2S_INT_CLR_REG(0), 0xFFFFFFFF);
|
||||
//--
|
||||
//No need to finish if no DMA transfer going on
|
||||
if (!(READ_PERI_REG(I2S_FIFO_CONF_REG(0))&I2S_DSCR_EN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Wait till fifo done
|
||||
while (!(READ_PERI_REG(I2S_INT_RAW_REG(0))&I2S_TX_REMPTY_INT_RAW)) ;
|
||||
//Wait for last bytes to leave i2s xmit thing
|
||||
//ToDo: poll bit in next hw
|
||||
for (i = 0; i < (1 << 8); i++);
|
||||
while (!(READ_PERI_REG(I2S_STATE_REG(0))&I2S_TX_IDLE));
|
||||
|
||||
//Reset I2S for next transfer
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_START | I2S_RX_START);
|
||||
CLEAR_PERI_REG_MASK(I2S_OUT_LINK_REG(0), I2S_OUTLINK_START | I2S_INLINK_START);
|
||||
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_RESET | I2S_RX_FIFO_RESET);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_RESET | I2S_RX_FIFO_RESET);
|
||||
|
||||
// for (i=0; i<(1<<8); i++);
|
||||
while ((READ_PERI_REG(I2S_STATE_REG(0))&I2S_TX_FIFO_RESET_BACK));
|
||||
|
||||
}
|
||||
|
||||
|
||||
int mymemcmp(char *a, char *b, int len)
|
||||
{
|
||||
int x;
|
||||
for (x = 0; x < len; x++) {
|
||||
if (a[x] != b[x]) {
|
||||
printf("Not equal at byte %d. a=%x, b=%x\n", x, (int)a[x], (int)b[x]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST_CASE("Unaligned DMA test (needs I2S)", "[hw]")
|
||||
{
|
||||
int x;
|
||||
char src[2049], dest[2049];
|
||||
for (x = 0; x < sizeof(src); x++) {
|
||||
src[x] = x & 0xff;
|
||||
}
|
||||
|
||||
printf("Aligned dma\n");
|
||||
memset(dest, 0, 2049);
|
||||
dmaMemcpy(src, dest, 2048 + 1);
|
||||
TEST_ASSERT(mymemcmp(src, dest, 2048) == 0);
|
||||
printf("Src unaligned\n");
|
||||
dmaMemcpy(src + 1, dest, 2048 + 1);
|
||||
TEST_ASSERT(mymemcmp(src + 1, dest, 2048) == 0);
|
||||
printf("Dst unaligned\n");
|
||||
dmaMemcpy(src, dest + 1, 2048 + 2);
|
||||
TEST_ASSERT(mymemcmp(src, dest + 1, 2048) == 0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user