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:
antti
2016-11-17 16:36:10 +08:00
committed by Ivan Grokhotkov
parent 383d987697
commit d390449371
59 changed files with 5215 additions and 15 deletions

View 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

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

View 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]);
}
}

View 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

View 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);
}

View 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

View 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

View 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);
}

View 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);
}

View 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);
}