This commit is contained in:
刘可亮
2024-10-30 16:50:31 +08:00
parent 0ef85b55da
commit 661e71562d
458 changed files with 46555 additions and 12133 deletions

View File

@@ -8,6 +8,7 @@ src = []
if GetDepend('AIC_QSPI_DRV_TEST') and GetDepend('RT_USING_FINSH'):
src = Glob('test_qspidev.c')
src += Glob('test_spibit.c')
src += Glob('test_spi.c')
src += Glob('test_spi_async.c')
if GetDepend('AIC_QSPI_DRV_V11') and GetDepend('AIC_CHIP_D13X'):
src += Glob('test_spislave*.c')

View File

@@ -0,0 +1,319 @@
/*
* Copyright (c) 2024, ArtInChip Technology Co., Ltd
*
* SPDX-License-Identifier: Apache-2.0
*
* Authors: Jiji Chen <jiji.chen@artinchip.com>
*/
#include <string.h>
#include <finsh.h>
#include <rtdevice.h>
#include <aic_core.h>
#define USAGE \
"test_spi help : Get this information.\n" \
"test_spi attach <bus name> <dev name> : Attach device to SPI bus.\n" \
"test_spi init <name> <mode> <freq> : Initialize SPI for device.\n" \
"test_spi send <len> : Send data.\n" \
"example:\n" \
"test_spi attach spi3 spidev\n" \
"test_spi init spidev 0 50000000\n" \
"test_spi send 32\n" \
"test_spi transfer 32\n" \
"test_spi send_recv 33 128\n" \
static void spi_usage(void)
{
printf("%s", USAGE);
}
static void show_speed(char *msg, u32 len, u32 us)
{
u32 tmp, speed;
/* Split to serval step to avoid overflow */
tmp = 1000 * len;
tmp = tmp / us;
tmp = 1000 * tmp;
speed = tmp / 1024;
printf("%s: %d byte, %d us -> %d KB/s\n", msg, len, us, speed);
}
static void hex_dump(uint8_t *data, unsigned long len)
{
unsigned long i = 0;
printf("\n");
for (i = 0; i < len; i++) {
if (i && (i % 16) == 0)
printf("\n");
printf("%02x ", data[i]);
}
printf("\n");
}
static struct rt_spi_device *g_spi;
static int test_spi_attach(int argc, char **argv)
{
struct rt_spi_device *spi_device = RT_NULL;
char *bus_name, *dev_name;
rt_err_t result = RT_EOK;
if (argc != 3) {
spi_usage();
return -1;
}
bus_name = argv[1];
dev_name = argv[2];
RT_ASSERT(bus_name != RT_NULL);
RT_ASSERT(dev_name != RT_NULL);
spi_device =
(struct rt_spi_device *)rt_malloc(sizeof(struct rt_spi_device));
if (spi_device == RT_NULL) {
printf("malloc failed.\n");
return -RT_ERROR;
}
result = rt_spi_bus_attach_device(spi_device, dev_name,
bus_name, RT_NULL);
if (result != RT_EOK && spi_device != NULL)
rt_free(spi_device);
return result;
}
static int test_spi_init(int argc, char **argv)
{
struct rt_spi_configuration spi_cfg;
struct rt_device *dev;
char *name;
int ret = 0;
if (argc != 4) {
printf("Argument error, please see help information.\n");
return -1;
}
name = argv[1];
g_spi = (struct rt_spi_device *)rt_device_find(name);
if (!g_spi) {
printf("Failed to get device in name %s\n", name);
return -1;
}
dev = (struct rt_device *)g_spi;
if (dev->type != RT_Device_Class_SPIDevice) {
g_spi = NULL;
printf("%s is not SPI device.\n", name);
return -1;
}
rt_memset(&spi_cfg, 0, sizeof(spi_cfg));
spi_cfg.mode = atol(argv[2]);
spi_cfg.max_hz = atol(argv[3]);
ret = rt_spi_configure(g_spi, &spi_cfg);
if (ret < 0) {
printf("qspi configure failure.\n");
return ret;
}
return 0;
}
static void test_spi_send_recv(int argc, char **argv)
{
unsigned long send_len, recv_len, align_len, start_us;
uint8_t *send_buf, *recv_buf;
rt_err_t ret;
if (!g_spi) {
printf("SPI device is not init yet.\n");
return;
}
if (argc < 3) {
printf("Argument is not correct, please see help for more information.\n");
return;
}
send_len = 0;
send_len = strtoul(argv[1], NULL, 0);
recv_len = strtoul(argv[2], NULL, 0);
/* transfer len can not be 0 */
if (!send_len || !recv_len)
return;
align_len = roundup(send_len, CACHE_LINE_SIZE);
send_buf = aicos_malloc_align(0, align_len, CACHE_LINE_SIZE);
u8 *temp = send_buf;
int k;
for (k = 0; k < send_len; k++) {
*temp = k & 0xff;
temp++;
}
align_len = roundup(recv_len, CACHE_LINE_SIZE);
recv_buf = aicos_malloc_align(0, align_len, CACHE_LINE_SIZE);
rt_memset(recv_buf, 0xee, recv_len);
if (send_buf == NULL || recv_buf == NULL) {
printf("Low memory!\n");
return;
} else {
printf("send len %ld, recv len %ld\n", send_len, recv_len);
}
rt_spi_take_bus((struct rt_spi_device *)g_spi);
start_us = aic_get_time_us();
ret = rt_spi_send_then_recv(g_spi, (void *)send_buf, send_len, (void *)recv_buf, recv_len);
show_speed("spi send recv speed", send_len + recv_len, aic_get_time_us() - start_us);
if (ret != 0) {
printf("Send_recv data failed. ret = %ld\n", ret);
}
rt_spi_release_bus((struct rt_spi_device *)g_spi);
if (send_buf)
aicos_free_align(0, send_buf);
if (recv_buf) {
printf("receive data:\n");
hex_dump(recv_buf, recv_len);
printf("\n");
aicos_free_align(0, recv_buf);
}
}
static void test_spi_send(int argc, char **argv)
{
unsigned long data_len, align_len, start_us;
uint8_t *data;
rt_size_t ret;
if (!g_spi) {
printf("SPI device is not init yet.\n");
return;
}
if (argc < 2) {
printf("Argument is not correct, please see help for more information.\n");
return;
}
data_len = 0;
data_len = strtoul(argv[1], NULL, 0);
data = RT_NULL;
if (data_len) {
align_len = roundup(data_len, CACHE_LINE_SIZE);
data = aicos_malloc_align(0, align_len, CACHE_LINE_SIZE);
u8 *temp = data;
int k;
for (k = 0; k < data_len; k++) {
*temp = k & 0xff;
temp++;
}
}
if (data == NULL) {
printf("Low memory!\n");
return;
} else {
printf("data len %ld\n", data_len);
}
rt_spi_take_bus((struct rt_spi_device *)g_spi);
start_us = aic_get_time_us();
ret = rt_spi_transfer(g_spi, (void *)data, NULL, data_len);
show_speed("spi send speed", data_len, aic_get_time_us() - start_us);
if (ret != data_len) {
printf("Send data failed. ret 0x%x\n", (int)ret);
}
rt_spi_release_bus((struct rt_spi_device *)g_spi);
if (data)
aicos_free_align(0, data);
}
static void test_spi_treansfer(int argc, char **argv)
{
unsigned long data_len, align_len, start_us;
uint8_t *data, *recv;
rt_size_t ret;
if (!g_spi) {
printf("SPI device is not init yet.\n");
return;
}
if (argc < 2) {
printf("Argument is not correct, please see help for more information.\n");
return;
}
data_len = 0;
data_len = strtoul(argv[1], NULL, 0);
data = RT_NULL;
if (data_len) {
align_len = roundup(data_len, CACHE_LINE_SIZE);
data = aicos_malloc_align(0, align_len, CACHE_LINE_SIZE);
recv = aicos_malloc_align(0, align_len, CACHE_LINE_SIZE);
u8 *temp = data;
int k;
for (k = 0; k < data_len; k++) {
*temp = k & 0xff;
temp++;
}
rt_memset(recv, 0xee, align_len);
}
if (data == NULL) {
printf("Low memory!\n");
return;
} else {
printf("data len %ld\n", data_len);
}
rt_spi_take_bus((struct rt_spi_device *)g_spi);
start_us = aic_get_time_us();
ret = rt_spi_transfer(g_spi, (void *)data, (void *)recv, data_len);
show_speed("spi transfer speed", data_len, aic_get_time_us() - start_us);
if (ret != data_len) {
printf("Transfer data failed. ret 0x%x\n", (int)ret);
}
rt_spi_release_bus((struct rt_spi_device *)g_spi);
if (data)
aicos_free_align(0, data);
if (recv) {
printf("receive data:\n");
hex_dump(recv, data_len);
printf("\n");
aicos_free_align(0, recv);
}
}
static void cmd_test_spi(int argc, char **argv)
{
if (argc < 2)
goto help;
if (!rt_strcmp(argv[1], "help")) {
goto help;
} else if (!rt_strcmp(argv[1], "attach")) {
test_spi_attach(argc - 1, &argv[1]);
return;
} else if (!rt_strcmp(argv[1], "init")) {
test_spi_init(argc - 1, &argv[1]);
return;
} else if (!rt_strcmp(argv[1], "send_recv")) {
test_spi_send_recv(argc - 1, &argv[1]);
return;
} else if (!rt_strcmp(argv[1], "send")) {
test_spi_send(argc - 1, &argv[1]);
return;
} else if (!rt_strcmp(argv[1], "transfer")) {
test_spi_treansfer(argc - 1, &argv[1]);
return;
}
help:
spi_usage();
}
MSH_CMD_EXPORT_ALIAS(cmd_test_spi, test_spi, Test SPI);

View File

@@ -32,8 +32,8 @@
/* All data should be 4 bytes aligned. */
#define CMD_SIZE 4
#define STATUS_SIZE 4
#define PKT_SIZE TEST_BUF_SIZE
// #define PKT_SIZE 256
// #define PKT_SIZE TEST_BUF_SIZE
#define PKT_SIZE 256
int test_qspi_slave_controller_init(u32 id, u32 bus_width,
qspi_slave_async_cb cb, void *priv,

View File

@@ -28,27 +28,38 @@ struct qspirecv_state {
u32 bus_width;
qspi_slave_handle handle;
u8 *work_buf;
u8 *tx_buf;
u32 data_len;
};
static struct qspirecv_state g_state;
extern void slave_dump_data(char *msg, u8 *buf, u32 len);
#define USAGE \
"spirecv help : Get this information.\n" \
"spirecv start <spi_id> <bus_width> <rxtx> <data_len>\n" \
" rxtx: 0(default) - rx only; 1 - tx only; 2 - full duplex transfer, bus_width should be 1.\n" \
" data_len: 256 as default, the len master transfer should be 4 align, if not, you have to set it.\n" \
"spirecv stop : stop the spi slave using.\n" \
"example:\n" \
"spirecv start 3 1 2 2048\n" \
"spirecv stop\n" \
static void qspi_usage(void)
{
printf("%s", USAGE);
}
static int recv_new_data(struct qspirecv_state *state, u8 *buf, u32 len)
static int recv_new_data(struct qspirecv_state *state, u8 *tx, u8 *rx, u32 len)
{
struct qspi_transfer t;
int ret;
memset(&t, 0, sizeof(t));
t.rx_data = buf;
t.tx_data = tx;
t.rx_data = rx;
t.data_len = len;
// memset(buf, 0, len);
// printf("%s, reset rx fifo\n", __func__);
hal_qspi_slave_fifo_reset(&state->handle, HAL_QSPI_RX_FIFO);
ret = hal_qspi_slave_transfer_async(&state->handle, &t);
if (ret < 0)
@@ -61,6 +72,7 @@ static void qspirecv_slave_async_callback(qspi_slave_handle *h, void *priv)
struct qspirecv_state *state = priv;
int status, cnt;
u32 *p32, cksum;
u8 *p;
status = hal_qspi_slave_get_status(&state->handle);
cnt = 0;
@@ -69,18 +81,43 @@ static void qspirecv_slave_async_callback(qspi_slave_handle *h, void *priv)
* status OK:
* TRANSFER DONE or CS INVALID
*/
// p = state->work_buf;
p = state->work_buf;
cnt = hal_qspi_slave_transfer_count(&state->handle);
printf("%s, status %d, cnt %d\n", __func__, status, cnt);
p32 = (void *)state->work_buf;
cksum = 0;
for (int i = 0; i<PKT_SIZE/4; i++) {
cksum += *p32;
p32++;
if (state->work_buf) {
p32 = (void *)state->work_buf;
cksum = 0;
for (int i = 0; i<g_state.data_len/4; i++) {
cksum += *p32;
p32++;
}
printf("cksum 0x%x\n", cksum);
slave_dump_data("Recv data", p, cnt);
}
printf("cksum 0x%x\n", cksum);
recv_new_data(state, state->work_buf, PKT_SIZE);
// slave_dump_data("Data", p, cnt);
if (g_state.work_buf) {
aicos_free_align(0, g_state.work_buf);
g_state.work_buf = aicos_malloc_align(0, g_state.data_len, CACHE_LINE_SIZE);
if (g_state.work_buf == NULL) {
printf("malloc failure.\n");
return;
}
rt_memset(g_state.work_buf, 0x2E, g_state.data_len);
}
if (g_state.tx_buf) {
aicos_free_align(0, g_state.tx_buf);
g_state.tx_buf = aicos_malloc_align(0, g_state.data_len, CACHE_LINE_SIZE);
if (g_state.tx_buf == NULL) {
printf("malloc failure.\n");
return;
}
rt_memset(g_state.tx_buf, 0x2E, g_state.data_len);
rt_memset(g_state.tx_buf, 0xA4, 16);
}
recv_new_data(state, state->tx_buf, state->work_buf, g_state.data_len);
} else {
/* Error process */
printf("%s, status %d\n", __func__, status);
@@ -89,7 +126,7 @@ static void qspirecv_slave_async_callback(qspi_slave_handle *h, void *priv)
static int test_qspirecv_start(int argc, char **argv)
{
unsigned long val;
unsigned long val, rxtx = 0;
int ret;
if (argc < 2) {
@@ -99,13 +136,45 @@ static int test_qspirecv_start(int argc, char **argv)
val = strtol(argv[1], NULL, 10);
g_state.qspi_id = val;
g_state.bus_width = 1; // Default is 1
if (g_state.work_buf == NULL)
g_state.work_buf =
aicos_malloc_align(0, TEST_BUF_SIZE, CACHE_LINE_SIZE);
if (argc >= 3) {
val = strtol(argv[2], NULL, 10);
g_state.bus_width = val;
}
if (argc >= 4) {
rxtx = strtol(argv[3], NULL, 10);
}
if (argc >= 5)
g_state.data_len = strtol(argv[4], NULL, 10);
else
g_state.data_len = PKT_SIZE;
/* rx or Full duplex mode */
if (rxtx == 0 || rxtx == 2) {
if (g_state.work_buf == NULL)
g_state.work_buf = aicos_malloc_align(0, g_state.data_len, CACHE_LINE_SIZE);
if (g_state.work_buf == NULL) {
printf("malloc failure.\n");
return -1;
}
rt_memset(g_state.work_buf, 0x2E, g_state.data_len);
}
/* tx or Full duplex mode */
if (rxtx == 1 || rxtx == 2) {
if (g_state.tx_buf == NULL)
g_state.tx_buf = aicos_malloc_align(0, g_state.data_len, CACHE_LINE_SIZE);
if (g_state.tx_buf == NULL) {
printf("malloc failure.\n");
return -1;
}
rt_memset(g_state.tx_buf, 0x2E, g_state.data_len);
rt_memset(g_state.tx_buf, 0xA4, 16);
}
ret = test_qspi_slave_controller_init(g_state.qspi_id, g_state.bus_width,
qspirecv_slave_async_callback, &g_state,
&g_state.handle);
@@ -115,7 +184,7 @@ static int test_qspirecv_start(int argc, char **argv)
}
/* Start with waiting command */
recv_new_data(&g_state, g_state.work_buf, PKT_SIZE);
recv_new_data(&g_state, g_state.tx_buf, g_state.work_buf, g_state.data_len);
return 0;
}
@@ -126,6 +195,10 @@ static int test_qspirecv_stop(int argc, char **argv)
aicos_free_align(0, g_state.work_buf);
g_state.work_buf = NULL;
}
if (g_state.tx_buf) {
aicos_free_align(0, g_state.tx_buf);
g_state.tx_buf = NULL;
}
return 0;
}
@@ -147,5 +220,4 @@ help:
qspi_usage();
}
MSH_CMD_EXPORT_ALIAS(cmd_test_qspislave_receiver, spirecv, Test QSPI Slave);