diff options
Diffstat (limited to 'util_spi_stress')
-rw-r--r-- | util_spi_stress/Makefile | 66 | ||||
-rw-r--r-- | util_spi_stress/readme.md | 93 | ||||
-rw-r--r-- | util_spi_stress/src/util_spi_stress.c | 292 |
3 files changed, 451 insertions, 0 deletions
diff --git a/util_spi_stress/Makefile b/util_spi_stress/Makefile new file mode 100644 index 0000000..23e3c88 --- /dev/null +++ b/util_spi_stress/Makefile @@ -0,0 +1,66 @@ +### Application-specific constants + +APP_NAME := util_spi_stress + +### Environment constants + +LGW_PATH ?= ../libloragw +ARCH ?= +CROSS_COMPILE ?= + +### External constant definitions +# must get library build option to know if mpsse must be linked or not + +include $(LGW_PATH)/library.cfg + +### Constant symbols + +CC := $(CROSS_COMPILE)gcc +AR := $(CROSS_COMPILE)ar + +CFLAGS=-O2 -Wall -Wextra -std=c99 -Iinc -I. + +OBJDIR = obj + +### Constants for LoRa concentrator HAL library +# List the library sub-modules that are used by the application + +LGW_INC = $(LGW_PATH)/inc/config.h +LGW_INC += $(LGW_PATH)/inc/loragw_reg.h + +### Linking options + +LIBS := -lloragw -lrt -lm + +### General build targets + +all: $(APP_NAME) + +clean: + rm -f $(OBJDIR)/*.o + rm -f $(APP_NAME) + +### HAL library (do no force multiple library rebuild even with 'make -B') + +$(LGW_PATH)/inc/config.h: + @if test ! -f $@; then \ + $(MAKE) all -C $(LGW_PATH); \ + fi + +$(LGW_PATH)/libloragw.a: $(LGW_INC) + @if test ! -f $@; then \ + $(MAKE) all -C $(LGW_PATH); \ + fi + +### Main program compilation and assembly + +$(OBJDIR): + mkdir -p $(OBJDIR) + +$(OBJDIR)/$(APP_NAME).o: src/$(APP_NAME).c $(LGW_INC) | $(OBJDIR) + $(CC) -c $(CFLAGS) -I$(LGW_PATH)/inc $< -o $@ + +$(APP_NAME): $(OBJDIR)/$(APP_NAME).o $(LGW_PATH)/libloragw.a + $(CC) -L$(LGW_PATH) $< -o $@ $(LIBS) + +### EOF diff --git a/util_spi_stress/readme.md b/util_spi_stress/readme.md new file mode 100644 index 0000000..7848b0f --- /dev/null +++ b/util_spi_stress/readme.md @@ -0,0 +1,93 @@ + / _____) _ | | + ( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | + (______/|_____)_|_|_| \__)_____)\____)_| |_| + (C)2013 Semtech-Cycleo + +LoRa concentrator SPI stress test +================================== + +1. Introduction +---------------- + +This software is used to check the reliability of the link between the host +platform (on which the program is run) and the LoRa concentrator register file +that is the interface through which all interaction with the LoRa concentrator +happens. + +2. Dependencies +---------------- + +This program only access the LoRa concentrator HAL library through its +loragw_reg "named registers" access sub-module. + +It was tested with v1.3.0 of the libloragw library, and should be compatible +with any later version of the library and the hardware, assuming the registers +used for the tests are still present. + +The registers used are: + * LGW_VERSION + * LGW_IMPLICIT_PAYLOAD_LENGHT + * LGW_FSK_REF_PATTERN_LSB + * LGW_RX_DATA_BUF_ADDR + * LGW_RX_DATA_BUF_DATA + +A data buffer accessible through the 2 registers above must be implemented. + +3. Usage +--------- + +The tests run forever or until an error is detected. +Press Ctrl+C to stop the application. + +When an error is detected, diagnosis information are displayed. Please refer to +the source code for more details on what is displayed for diagnosis. + +All tests use pseudo-random data generated by the rand() function. The random +generator is not seeded, and the same sequence of data will be use each time the +program is launched. + +Basically, some random data is written, read back and then compared to the +initial written data. Some "useless" read on others registers might be inserted +to be sure that the data read back is coming from the hardware, and not from the +internal buffer(s) of the software driver(s). + +Test 1 > R/W on a simple 8-bit register + +Test 2 > R/W on a simple 8-bit register with interstitial reads on VERSION + +Test 3 > R/W on a 32-bit register (short SPI bursts access) + +Test 4 > data buffer R/W (long SPI bursts access) + +4. License +----------- + +Copyright (c) 2013, SEMTECH S.A. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +* Neither the name of the Semtech corporation nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL SEMTECH S.A. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*EOF*
\ No newline at end of file diff --git a/util_spi_stress/src/util_spi_stress.c b/util_spi_stress/src/util_spi_stress.c new file mode 100644 index 0000000..6cc5f04 --- /dev/null +++ b/util_spi_stress/src/util_spi_stress.c @@ -0,0 +1,292 @@ +/* + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + (C)2013 Semtech-Cycleo + +Description: + SPI stress test + +License: Revised BSD License, see LICENSE.TXT file include in the project +Maintainer: Sylvain Miermont +*/ + + +/* -------------------------------------------------------------------------- */ +/* --- DEPENDANCIES --------------------------------------------------------- */ + +/* fix an issue between POSIX and C99 */ +#if __STDC_VERSION__ >= 199901L + #define _XOPEN_SOURCE 600 +#else + #define _XOPEN_SOURCE 500 +#endif + +#include <stdint.h> /* C99 types */ +#include <stdbool.h> /* bool type */ +#include <stdio.h> /* printf fprintf sprintf fopen fputs */ + +#include <signal.h> /* sigaction */ +#include <unistd.h> /* getopt access */ +#include <stdlib.h> /* rand */ + +#include "loragw_reg.h" + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE MACROS ------------------------------------------------------- */ + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#define MSG(args...) fprintf(stderr, args) /* message that is destined to the user */ + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE CONSTANTS ---------------------------------------------------- */ + +#define VERS 103 +#define READS_WHEN_ERROR 16 /* number of times a read is repeated if there is a read error */ +#define BUFF_SIZE 1024 /* maximum number of bytes that we can write in sx1301 RX data buffer */ +#define DEFAULT_TX_NOTCH_FREQ 129E3 + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE VARIABLES (GLOBAL) ------------------------------------------- */ + +/* signal handling variables */ +struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */ +static int exit_sig = 0; /* 1 -> application terminates cleanly (shut down hardware, close open files, etc) */ +static int quit_sig = 0; /* 1 -> application terminates without shutting down the hardware */ + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */ + +static void sig_handler(int sigio); + +void usage (void); + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */ + +static void sig_handler(int sigio) { + if (sigio == SIGQUIT) { + quit_sig = 1;; + } else if ((sigio == SIGINT) || (sigio == SIGTERM)) { + exit_sig = 1; + } +} + +/* describe command line options */ +void usage(void) { + MSG( "Available options:\n"); + MSG( " -h print this help\n"); + MSG( " -t <int> specify which test you want to run (1-4)\n"); +} + +/* -------------------------------------------------------------------------- */ +/* --- MAIN FUNCTION -------------------------------------------------------- */ + +int main(int argc, char **argv) +{ + int i; + int xi = 0; + + /* application option */ + int test_number = 1; + int cycle_number = 0; + int repeats_per_cycle = 1000; + bool error = false; + + /* in/out variables */ + int32_t test_value; + int32_t read_value; + int32_t rb1, rb2, rb3; /* interstitial readbacks, to flush buffers if needed */ + + /* data buffer */ + int32_t test_addr; + uint8_t test_buff[BUFF_SIZE]; + uint8_t read_buff[BUFF_SIZE]; + + /* parse command line options */ + while ((i = getopt (argc, argv, "ht:")) != -1) { + switch (i) { + case 'h': + usage(); + return EXIT_FAILURE; + break; + + case 't': + i = sscanf(optarg, "%i", &xi); + if ((i != 1) || (xi < 1) || (xi > 4)) { + MSG("ERROR: invalid test number\n"); + return EXIT_FAILURE; + } else { + test_number = xi; + } + break; + + default: + MSG("ERROR: argument parsing use -h option for help\n"); + usage(); + return EXIT_FAILURE; + } + } + MSG("INFO: Starting LoRa concentrator SPI stress-test number %i\n", test_number); + + /* configure signal handling */ + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = 0; + sigact.sa_handler = sig_handler; + sigaction(SIGQUIT, &sigact, NULL); + sigaction(SIGINT, &sigact, NULL); + sigaction(SIGTERM, &sigact, NULL); + + /* start SPI link */ + i = lgw_connect(false, DEFAULT_TX_NOTCH_FREQ); + if (i != LGW_REG_SUCCESS) { + MSG("ERROR: lgw_connect() did not return SUCCESS"); + return EXIT_FAILURE; + } + + if (test_number == 1) { + /* single 8b register R/W stress test */ + while ((quit_sig != 1) && (exit_sig != 1)) { + printf("Cycle %i > ", cycle_number); + for (i=0; i<repeats_per_cycle; ++i) { + test_value = (rand() % 256); + lgw_reg_w(LGW_IMPLICIT_PAYLOAD_LENGHT, test_value); + lgw_reg_r(LGW_IMPLICIT_PAYLOAD_LENGHT, &read_value); + if (read_value != test_value) { + error = true; + break; + } + } + if (error) { + printf("error during the %ith iteration: write 0x%02X, read 0x%02X\n", i+1, test_value, read_value); + printf("Repeat read of target register:"); + for (i=0; i<READS_WHEN_ERROR; ++i) { + lgw_reg_r(LGW_IMPLICIT_PAYLOAD_LENGHT, &read_value); + printf(" 0x%02X", read_value); + } + printf("\n"); + return EXIT_FAILURE; + } else { + printf("did %i R/W on an 8 bits reg with no error\n", repeats_per_cycle); + ++cycle_number; + } + } + } else if (test_number == 2) { + /* single 8b register R/W with interstitial VERSION check stress test */ + while ((quit_sig != 1) && (exit_sig != 1)) { + printf("Cycle %i > ", cycle_number); + for (i=0; i<repeats_per_cycle; ++i) { + test_value = (rand() % 256); + lgw_reg_r(LGW_VERSION, &rb1); + lgw_reg_w(LGW_IMPLICIT_PAYLOAD_LENGHT, test_value); + lgw_reg_r(LGW_VERSION, &rb2); + lgw_reg_r(LGW_IMPLICIT_PAYLOAD_LENGHT, &read_value); + lgw_reg_r(LGW_VERSION, &rb3); + if ((rb1 != VERS) || (rb2 != VERS) || (rb3 != VERS) || (read_value != test_value)) { + error = true; + break; + } + } + if (error) { + printf("error during the %ith iteration: write %02X, read %02X, version (%i, %i, %i)\n", i+1, test_value, read_value, rb1, rb2, rb3); + printf("Repeat read of target register:"); + for (i=0; i<READS_WHEN_ERROR; ++i) { + lgw_reg_r(LGW_IMPLICIT_PAYLOAD_LENGHT, &read_value); + printf(" 0x%02X", read_value); + } + printf("\n"); + return EXIT_FAILURE; + } else { + printf("did %i R/W on an 8 bits reg with no error\n", repeats_per_cycle); + ++cycle_number; + } + } + } else if (test_number == 3) { + /* 32b register R/W stress test */ + while ((quit_sig != 1) && (exit_sig != 1)) { + printf("Cycle %i > ", cycle_number); + for (i=0; i<repeats_per_cycle; ++i) { + test_value = (rand() & 0x0000FFFF); + test_value += (int32_t)(rand() & 0x0000FFFF) << 16; + lgw_reg_w(LGW_FSK_REF_PATTERN_LSB, test_value); + lgw_reg_r(LGW_FSK_REF_PATTERN_LSB, &read_value); + if (read_value != test_value) { + error = true; + break; + } + } + if (error) { + printf("error during the %ith iteration: write 0x%08X, read 0x%08X\n", i+1, test_value, read_value); + printf("Repeat read of target register:"); + for (i=0; i<READS_WHEN_ERROR; ++i) { + lgw_reg_r(LGW_FSK_REF_PATTERN_LSB, &read_value); + printf(" 0x%08X", read_value); + } + printf("\n"); + return EXIT_FAILURE; + } else { + printf("did %i R/W on a 32 bits reg with no error\n", repeats_per_cycle); + ++cycle_number; + } + } + } else if (test_number == 4) { + /* databuffer R/W stress test */ + while ((quit_sig != 1) && (exit_sig != 1)) { + for (i=0; i<BUFF_SIZE; ++i) { + test_buff[i] = rand() & 0xFF; + } + printf("Cycle %i > ", cycle_number); + test_addr = rand() & 0xFFFF; + lgw_reg_w(LGW_RX_DATA_BUF_ADDR, test_addr); /* write at random offset in memory */ + lgw_reg_wb(LGW_RX_DATA_BUF_DATA, test_buff, BUFF_SIZE); + lgw_reg_w(LGW_RX_DATA_BUF_ADDR, test_addr); /* go back to start of segment */ + lgw_reg_rb(LGW_RX_DATA_BUF_DATA, read_buff, BUFF_SIZE); + for (i=0; ((i<BUFF_SIZE) && (test_buff[i] == read_buff[i])); ++i); + if (i != BUFF_SIZE) { + printf("error during the buffer comparison\n"); + printf("Written values:\n"); + for (i=0; i<BUFF_SIZE; ++i) { + printf(" %02X ", test_buff[i]); + if (i%16 == 15) printf("\n"); + } + printf("\n"); + printf("Read values:\n"); + for (i=0; i<BUFF_SIZE; ++i) { + printf(" %02X ", read_buff[i]); + if (i%16 == 15) printf("\n"); + } + printf("\n"); + lgw_reg_w(LGW_RX_DATA_BUF_ADDR, test_addr); /* go back to start of segment */ + lgw_reg_rb(LGW_RX_DATA_BUF_DATA, read_buff, BUFF_SIZE); + printf("Re-read values:\n"); + for (i=0; i<BUFF_SIZE; ++i) { + printf(" %02X ", read_buff[i]); + if (i%16 == 15) printf("\n"); + } + printf("\n"); + return EXIT_FAILURE; + } else { + printf("did a %i-byte R/W on a data buffer with no error\n", BUFF_SIZE); + ++cycle_number; + } + } + } else { + MSG("ERROR: invalid test number"); + usage(); + } + + /* close SPI link */ + i = lgw_disconnect(); + if (i != LGW_REG_SUCCESS) { + MSG("ERROR: lgw_disconnect() did not return SUCCESS"); + return EXIT_FAILURE; + } + + MSG("INFO: Exiting LoRa concentrator SPI stress-test program\n"); + return EXIT_SUCCESS; +} + +/* --- EOF ------------------------------------------------------------------ */ + |