dey-examples: add libdigiapix SPI example

https://jira.digi.com/browse/DEL-4865

Signed-off-by: David Escalona <david.escalona@digi.com>
This commit is contained in:
David Escalona 2017-09-15 10:11:49 +02:00
parent 1e2358f5bf
commit 6c65df5c68
4 changed files with 578 additions and 0 deletions

6
apix-spi-example/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
apix-spi-example
*.o
.cproject
.project
.settings/
*~

37
apix-spi-example/Makefile Normal file
View File

@ -0,0 +1,37 @@
#
# Copyright 2017, Digi International Inc.
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
#
BINARY := apix-spi-example
CFLAGS += -Wall -O2
CFLAGS += $(shell pkg-config --cflags libdigiapix)
LDLIBS += $(shell pkg-config --libs libdigiapix)
.PHONY: all
all: $(BINARY)
$(BINARY): main.o
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
.PHONY: install
install: $(BINARY)
install -d $(DESTDIR)/usr/bin
install -m 0755 $^ $(DESTDIR)/usr/bin/
.PHONY: clean
clean:
-rm -f *.o $(BINARY)

120
apix-spi-example/README.md Normal file
View File

@ -0,0 +1,120 @@
Digi APIX SPI Example Application
==================================
The example application writes a page of an external EEPROM memory with random
data and then reads the data back to validate it.
Most of EEPROM memories are compatible with the sample specifying the page size and
the number of address bytes.
The SPI connections for the sample depends on the running platform:
- **CCIMX6 SBC**: SPI connector of the board.
- VCC: Pin 1
- GND: Pin 8
- SPI-1 CLK: Pin 2
- SPI-1 MISO: Pin 3
- SPI-1 MOSI: Pin 4
- SPI-1 SS0: Pin 5
- **CCIMX6UL SBC Express**: Expansion connector of the board.
- VCC: Pin 17
- GND: Pin 20
- SPI-3 CLK: Pin 23
- SPI-3 MISO: Pin 21
- SPI-3 MOSI: Pin 19
- SPI-3 SS0: Pin 24
- **CCIMX6UL SBC Pro**: SPI connector of the board.
- VCC: Pin 1
- GND: Pin 8
- SPI-1 CLK: Pin 2
- SPI-1 MISO: Pin 3
- SPI-1 MOSI: Pin 4
- SPI-1 SS0: Pin 5
The following device tree modifications are required for the sample to work:
- **CCIMX6 SBC**:
```
&ecspi1 {
status = "okay";
spidev@0 {
reg = <0>;
compatible = "spidev";
spi-max-frequency = <1000000>;
status = "okay";
};
};
```
- **CCIMX6UL SBC Express**:
```
&ecspi3 {
status = "okay";
spidev@0 {
reg = <0>;
compatible = "spidev";
spi-max-frequency = <1000000>;
status = "okay";
};
};
```
- **CCIMX6UL SBC Pro**:
```
&ecspi1 {
status = "okay";
spidev@0 {
reg = <0>;
compatible = "spidev";
spi-max-frequency = <1000000>;
status = "okay";
};
};
```
Running the application
-----------------------
Once the binary is in the target, launch the application:
```
root@ccimx6ulstarter:~# ./apix-spi-example
Example application using libdigiapix SPI support
Usage: apix-spi-example <spi-dev> <spi-ss> <address-size> <page-size> <page-index>
<spi-dev> SPI device index to use
<spi-ss> SPI slave index to use
<address-size> Number of EEPROM memory address bytes
<page-size> EEPROM memory page size in bytes
<page-index> EEPROM memory page index to use
Aliases for SPI can be configured in the library config file
```
Compiling the application
-------------------------
This example can be compiled using a Digi Embedded Yocto based toolchain. Make
sure to source the corresponding toolchain of the platform you are using, e.g:
```
$ . <DEY-toolchain-path>/environment-setup-cortexa7hf-neon-dey-linux-gnueabi
$ make
```
More information about [Digi Embedded Yocto](https://github.com/digi-embedded/meta-digi).
License
-------
Copyright 2017, Digi International Inc.
Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.

415
apix-spi-example/main.c Normal file
View File

@ -0,0 +1,415 @@
/*
* Copyright 2017, Digi International Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include <errno.h>
#include <libgen.h>
#include <limits.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <libdigiapix/spi.h>
#define ARG_SPI_DEVICE 0
#define ARG_SPI_SLAVE 1
#define BUFF_SIZE 256
#define WREN 0x06
#define WRDI 0x04
#define WRITE 0x02
#define READ 0x03
#define RDSR 0x05
#define CLK_MODE SPI_CLK_MODE_0
#define CHIP_SELECT SPI_CS_ACTIVE_LOW
#define BIT_ORDER SPI_BO_MSB_FIRST
#define MAX_BUS_SPEED 1000000 /* 1MHz */
#define BITS_PER_WORD SPI_BPW_8
#define OPERATION_BYTES 1
static spi_t *spi_dev;
static unsigned int page_size, address_bytes = 0;
static uint8_t *tx_buffer;
static uint8_t *rx_buffer;
/*
* usage_and_exit() - Show usage information and exit with 'exitval' return
* value
*/
static void usage_and_exit(char *name, int exitval)
{
fprintf(stdout,
"Example application using libdigiapix SPI support\n"
"\n"
"Usage: %s <spi-dev> <spi-ss> <address-size> <page-size> <page-index>\n\n"
"<spi-dev> SPI device index to use\n"
"<spi-ss> SPI slave index to use\n"
"<address-size> Number of EEPROM memory address bytes\n"
"<page-size> EEPROM memory page size in bytes\n"
"<page-index> EEPROM memory page index to use\n"
"\n"
"Aliases for SPI can be configured in the library config file\n"
"\n", name);
exit(exitval);
}
/*
* cleanup() - Frees all the allocated memory before exiting
*/
static void cleanup(void)
{
/* Free spi */
spi_free(spi_dev);
/* Free buffers */
free(tx_buffer);
free(rx_buffer);
}
/*
* sigaction_handler() - Handler to execute after receiving a signal
*/
static void sigaction_handler(int signum)
{
/* 'atexit' executes the cleanup function */
exit(EXIT_FAILURE);
}
/*
* register_signals() - Registers program signals
*/
static void register_signals(void)
{
struct sigaction action;
action.sa_handler = sigaction_handler;
action.sa_flags = 0;
sigemptyset(&action.sa_mask);
sigaction(SIGHUP, &action, NULL);
sigaction(SIGINT, &action, NULL);
sigaction(SIGTERM, &action, NULL);
}
/*
* enable_write() - Sets the SPI write enable bit.
*
* Return: EXIT_SUCCESS on success, EXIT_FAILURE otherwise.
*/
static int enable_write(void)
{
uint8_t write_data[1] = {0};
printf("[INFO] Setting write enable bit...\n");
write_data[0] = WREN;
return spi_write(spi_dev, write_data, sizeof(write_data));
}
/*
* read_status_register() - Reads the SPI status register.
*
* @status: Variable to store the read status.
*
* Return: EXIT_SUCCESS on success, EXIT_FAILURE otherwise.
*/
static int read_status_register(uint8_t *status)
{
uint8_t write_data[2] = {0};
uint8_t read_data[2] = {0};
printf("[INFO] Reading status register...\n");
write_data[0] = RDSR;
if (spi_transfer(spi_dev, write_data, read_data, 2) != EXIT_SUCCESS) {
return EXIT_FAILURE;
}
printf("[INFO] SPI Status Register is 0x%02x\n", read_data[1]);
*status = read_data[1];
return EXIT_SUCCESS;
}
/*
* write_page() - Writes an EEPROM page with the given data.
*
* @page_index: index of the EEPROM page to write.
* @data: the data to write.
*
* Return: EXIT_SUCCESS on success, EXIT_FAILURE otherwise.
*/
static int write_page(int page_index, uint8_t* data)
{
uint8_t *write_data;
uint16_t page_address = page_size * page_index;
uint8_t status = 0;
int i, ret = 0;
/* Create the page write buffer */
write_data = (uint8_t *)calloc(page_size + OPERATION_BYTES + address_bytes,
sizeof(uint8_t));
if (write_data == NULL) {
printf("Unable to allocate memory to write the page.");
return EXIT_FAILURE;
}
printf("[INFO] Writing %d bytes to page %d at address 0x%x...\n", page_size,
page_index, page_address);
write_data[0] = WRITE; // Operation.
for (i = 0; i < address_bytes; i++) {
write_data[i + OPERATION_BYTES] = (page_address >> (8 * (address_bytes -
i -1)));
}
/* Fill the data array. */
for (i = 0; i < page_size; i++) {
write_data[(i + OPERATION_BYTES + address_bytes)] = data[i];
}
/* Perform the write operation. */
if (spi_write(spi_dev, write_data, page_size + OPERATION_BYTES +
address_bytes) != EXIT_SUCCESS) {
free(write_data);
return EXIT_FAILURE;
}
/* Wait for the operation to complete. */
do {
/* Read the status register to check the WIP (write-in-progress) bit. */
ret = read_status_register(&status);
if (ret != EXIT_SUCCESS) {
free(write_data);
return EXIT_FAILURE;
}
/* Check the WIP (write-in-progress) status bit. */
if (status & 0x01) {
printf("[INFO] Write in progress...\n");
usleep(1);
} else {
printf("[INFO] Write finished!\n");
}
} while (status & 0x1);
free(write_data);
return EXIT_SUCCESS;
}
/*
* read_page() - Reads an EEPROM page.
*
* @page_index: index of the EEPROM page to read.
* @data: buffer to store the read data in.
*
* Return: EXIT_SUCCESS on success, EXIT_FAILURE otherwise.
*/
static int read_page(int page_index, uint8_t* data)
{
uint8_t *write_data;
uint8_t *read_data;
uint16_t page_address;
int i = 0;
page_address = page_size * page_index;
/* Create the buffers */
write_data = (uint8_t *)calloc(page_size + OPERATION_BYTES + address_bytes,
sizeof(uint8_t));
read_data = (uint8_t *)calloc(page_size + OPERATION_BYTES + address_bytes,
sizeof(uint8_t));
if (write_data == NULL || read_data == NULL) {
printf("Unable to allocate memory to read the page.");
return EXIT_FAILURE;
}
printf("[INFO] Reading page %d at address 0x%x...\n", page_index,
page_address);
write_data[0] = READ; // Operation.
for (i = 0; i < address_bytes; i++) {
write_data[i + OPERATION_BYTES] = (page_address >> (8 * (address_bytes -
i -1)));
}
/* Perform the read operation with a transfer */
if (spi_transfer(spi_dev, write_data, read_data, page_size +
OPERATION_BYTES + address_bytes) != EXIT_SUCCESS) {
free(write_data);
free(read_data);
return EXIT_FAILURE;
}
for (i = 0; i < page_size; i++) {
data[i] = read_data[(i + OPERATION_BYTES + address_bytes)];
}
free(write_data);
free(read_data);
return EXIT_SUCCESS;
}
/*
* parse_argument() - Parses the given string argument and returns the
* corresponding integer value
*
* @argv: Argument to parse in string format.
* @arg_type: Type of the argument to parse.
*
* Return: The parsed integer argument, -1 on error.
*/
static int parse_argument(char *argv, int arg_type)
{
char *endptr;
long value;
errno = 0;
value = strtol(argv, &endptr, 10);
if ((errno == ERANGE && (value == LONG_MAX || value == LONG_MIN))
|| (errno != 0 && value == 0))
return -1;
if (endptr == argv) {
switch (arg_type) {
case ARG_SPI_DEVICE:
return spi_get_device(endptr);
case ARG_SPI_SLAVE:
return spi_get_slave(endptr);
default:
return -1;
}
}
return value;
}
int main(int argc, char *argv[])
{
int spi_device, spi_slave, page_index, i = 0;
spi_transfer_cfg_t transfer_mode = {0};
char *name = basename(argv[0]);
/* Check input parameters */
if (argc != 6)
usage_and_exit(name, EXIT_FAILURE);
/* Parse command line arguments */
spi_device = parse_argument(argv[1], ARG_SPI_DEVICE);
spi_slave = parse_argument(argv[2], ARG_SPI_SLAVE);
address_bytes = atoi(argv[3]);
page_size = atoi(argv[4]);
page_index = atoi(argv[5]);
if (spi_device < 0 || spi_slave < 0) {
printf("Unable to parse SPI device/slave arguments\n");
return EXIT_FAILURE;
}
if (address_bytes <= 0) {
printf("Address bytes must be greater than 0\n");
return EXIT_FAILURE;
}
if (page_size <= 0) {
printf("Page size must be greater than 0\n");
return EXIT_FAILURE;
}
if (page_index < 0) {
printf("Page index must be greater or equal than 0\n");
return EXIT_FAILURE;
}
/* Register signals and exit cleanup function */
atexit(cleanup);
register_signals();
/* Request SPI */
spi_dev = spi_request((unsigned)spi_device, (unsigned)spi_slave);
if (!spi_dev) {
printf("Failed to initialize SPI\n");
return EXIT_FAILURE;
}
/* Configure the transfer mode */
transfer_mode.clk_mode = CLK_MODE;
transfer_mode.chip_select = CHIP_SELECT;
transfer_mode.bit_order = BIT_ORDER;
if (spi_set_transfer_mode(spi_dev, &transfer_mode) != EXIT_SUCCESS) {
printf("Failed to configure SPI transfer mode\n");
return EXIT_FAILURE;
}
/* Configure the bits-per-word */
if (spi_set_bits_per_word(spi_dev, BITS_PER_WORD) != EXIT_SUCCESS) {
printf("Failed to configure SPI bits-per-word\n");
return EXIT_FAILURE;
}
/* Configure the max bus speed */
if (spi_set_speed(spi_dev, MAX_BUS_SPEED) != EXIT_SUCCESS) {
printf("Failed to configure SPI max bus speed\n");
return EXIT_FAILURE;
}
/* Set the write-enable bit. */
if (enable_write() != EXIT_SUCCESS) {
printf("Failed to set the write-enable bit\n");
return EXIT_FAILURE;
}
/* Initialize the write and read buffers */
tx_buffer = (uint8_t *)calloc(page_size, sizeof(uint8_t));
rx_buffer = (uint8_t *)calloc(page_size, sizeof(uint8_t));
if (tx_buffer == NULL || rx_buffer == NULL) {
printf("Failed to initialize read/write buffers\n");
return EXIT_FAILURE;
}
/* Fill the data to write with random bytes. */
srand(time(NULL));
for (i = 0; i < (page_size); i++) {
tx_buffer[i] = rand() % 255;
}
/* Write the page. */
if (write_page(page_index, tx_buffer) != EXIT_SUCCESS) {
printf("Write page failed\n");
return EXIT_FAILURE;
}
/* Read the page. */
if (read_page(page_index, rx_buffer) != EXIT_SUCCESS) {
printf("Read page failed\n");
return EXIT_FAILURE;
}
/* Validate the read data. */
printf("[INFO] Validating read data...\n");
for (i = 0; i < page_size; i++) {
printf(" Byte %d: Write 0x%02x - Read 0x%02x", i,
tx_buffer[i], rx_buffer[i]);
if (tx_buffer[i] == rx_buffer[i]) {
printf(" - Correct\n");
} else {
printf(" - Incorrect\n");
}
}
/* 'atexit' executes the cleanup function */
return EXIT_SUCCESS;
}