367 lines
11 KiB
C
367 lines
11 KiB
C
/*****************************************************************************
|
|
* | File : dev_hardware_SPI.c
|
|
* | Author : Waveshare team
|
|
* | Function : Read and write /dev/SPI, hardware SPI
|
|
* | Info :
|
|
*----------------
|
|
* | This version: V1.0
|
|
* | Date : 2019-06-26
|
|
* | Info : Basic version
|
|
*
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
# of this software and associated documnetation files (the "Software"), to deal
|
|
# in the Software without restriction, including without limitation the rights
|
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
# copies of the Software, and to permit persons to whom the Software is
|
|
# furished to do so, subject to the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be included in
|
|
# all copies or substantial portions of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
# THE SOFTWARE.
|
|
#
|
|
******************************************************************************/
|
|
#include "dev_hardware_SPI.h"
|
|
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
|
|
#include <stdint.h>
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <getopt.h>
|
|
#include <fcntl.h>
|
|
#include <sys/ioctl.h>
|
|
#include <linux/types.h>
|
|
#include <linux/spi/spidev.h>
|
|
|
|
HARDWARE_SPI hardware_SPI;
|
|
|
|
static uint8_t bits = 8;
|
|
|
|
#define SPI_CS_HIGH 0x04 //Chip select high
|
|
#define SPI_LSB_FIRST 0x08 //LSB
|
|
#define SPI_3WIRE 0x10 //3-wire mode SI and SO same line
|
|
#define SPI_LOOP 0x20 //Loopback mode
|
|
#define SPI_NO_CS 0x40 //A single device occupies one SPI bus, so there is no chip select
|
|
#define SPI_READY 0x80 //Slave pull low to stop data transmission
|
|
|
|
struct spi_ioc_transfer tr;
|
|
|
|
|
|
/******************************************************************************
|
|
function: SPI port initialization
|
|
parameter:
|
|
SPI_device : Device name
|
|
Info:
|
|
/dev/spidev0.0
|
|
/dev/spidev0.1
|
|
******************************************************************************/
|
|
void DEV_HARDWARE_SPI_begin(char *SPI_device)
|
|
{
|
|
//device
|
|
int ret = 0;
|
|
if((hardware_SPI.fd = open(SPI_device, O_RDWR )) < 0) {
|
|
perror("Failed to open SPI device.\n");
|
|
printf("Failed to open SPI device\r\n");
|
|
DEV_HARDWARE_SPI_Debug("Failed to open SPI device\r\n");
|
|
exit(1);
|
|
} else {
|
|
printf("open : %s\r\n", SPI_device);
|
|
DEV_HARDWARE_SPI_Debug("open : %s\r\n", SPI_device);
|
|
}
|
|
hardware_SPI.mode = 0;
|
|
|
|
ret = ioctl(hardware_SPI.fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
|
|
if (ret == -1) {
|
|
printf("can't set bits per word\r\n");
|
|
DEV_HARDWARE_SPI_Debug("can't set bits per word\r\n");
|
|
}
|
|
|
|
ret = ioctl(hardware_SPI.fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
|
|
if (ret == -1) {
|
|
printf("can't get bits per word\r\n");
|
|
DEV_HARDWARE_SPI_Debug("can't get bits per word\r\n");
|
|
}
|
|
tr.bits_per_word = bits;
|
|
|
|
DEV_HARDWARE_SPI_Mode(SPI_MODE_0);
|
|
DEV_HARDWARE_SPI_ChipSelect(SPI_CS_Mode_LOW);
|
|
DEV_HARDWARE_SPI_SetBitOrder(SPI_BIT_ORDER_LSBFIRST);
|
|
DEV_HARDWARE_SPI_setSpeed(20000000);
|
|
DEV_HARDWARE_SPI_SetDataInterval(5);
|
|
}
|
|
|
|
void DEV_HARDWARE_SPI_beginSet(char *SPI_device, SPIMode mode, uint32_t speed)
|
|
{
|
|
//device
|
|
int ret = 0;
|
|
hardware_SPI.mode = 0;
|
|
if((hardware_SPI.fd = open(SPI_device, O_RDWR )) < 0) {
|
|
perror("Failed to open SPI device.\n");
|
|
exit(1);
|
|
} else {
|
|
DEV_HARDWARE_SPI_Debug("open : %s\r\n", SPI_device);
|
|
}
|
|
|
|
ret = ioctl(hardware_SPI.fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
|
|
if (ret == -1)
|
|
DEV_HARDWARE_SPI_Debug("can't set bits per word\r\n");
|
|
|
|
ret = ioctl(hardware_SPI.fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
|
|
if (ret == -1)
|
|
DEV_HARDWARE_SPI_Debug("can't get bits per word\r\n");
|
|
|
|
DEV_HARDWARE_SPI_Mode(mode);
|
|
DEV_HARDWARE_SPI_ChipSelect(SPI_CS_Mode_LOW);
|
|
DEV_HARDWARE_SPI_setSpeed(speed);
|
|
DEV_HARDWARE_SPI_SetDataInterval(0);
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
function: SPI device End
|
|
parameter:
|
|
Info:
|
|
******************************************************************************/
|
|
void DEV_HARDWARE_SPI_end(void)
|
|
{
|
|
hardware_SPI.mode = 0;
|
|
if (close(hardware_SPI.fd) != 0){
|
|
DEV_HARDWARE_SPI_Debug("Failed to close SPI device\r\n");
|
|
perror("Failed to close SPI device.\n");
|
|
}
|
|
}
|
|
|
|
/******************************************************************************
|
|
function: Set SPI speed
|
|
parameter:
|
|
Info: Return 1 success
|
|
Return -1 failed
|
|
******************************************************************************/
|
|
int DEV_HARDWARE_SPI_setSpeed(uint32_t speed)
|
|
{
|
|
uint32_t speed1 = hardware_SPI.speed;
|
|
|
|
hardware_SPI.speed = speed;
|
|
|
|
//Write speed
|
|
if (ioctl(hardware_SPI.fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) == -1) {
|
|
DEV_HARDWARE_SPI_Debug("can't set max speed hz\r\n");
|
|
hardware_SPI.speed = speed1;//Setting failure rate unchanged
|
|
return -1;
|
|
}
|
|
|
|
//Read the speed of just writing
|
|
if (ioctl(hardware_SPI.fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) == -1) {
|
|
DEV_HARDWARE_SPI_Debug("can't get max speed hz\r\n");
|
|
hardware_SPI.speed = speed1;//Setting failure rate unchanged
|
|
return -1;
|
|
}
|
|
hardware_SPI.speed = speed;
|
|
tr.speed_hz = hardware_SPI.speed;
|
|
return 1;
|
|
}
|
|
|
|
/******************************************************************************
|
|
function: Set SPI Mode
|
|
parameter:
|
|
Info:
|
|
SPIMode:
|
|
SPI_MODE0
|
|
SPI_MODE1
|
|
SPI_MODE2
|
|
SPI_MODE3
|
|
Return :
|
|
Return 1 success
|
|
Return -1 failed
|
|
******************************************************************************/
|
|
int DEV_HARDWARE_SPI_Mode(SPIMode mode)
|
|
{
|
|
hardware_SPI.mode &= 0xfC;//Clear low 2 digits
|
|
hardware_SPI.mode |= mode;//Setting mode
|
|
|
|
//Write device
|
|
if (ioctl(hardware_SPI.fd, SPI_IOC_WR_MODE, &hardware_SPI.mode) == -1) {
|
|
DEV_HARDWARE_SPI_Debug("can't set spi mode\r\n");
|
|
return -1;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/******************************************************************************
|
|
function: Set SPI CS Enable
|
|
parameter:
|
|
Info:
|
|
EN:
|
|
DISABLE
|
|
ENABLE
|
|
Return :
|
|
Return 1 success
|
|
Return -1 failed
|
|
******************************************************************************/
|
|
int DEV_HARDWARE_SPI_CSEN(SPICSEN EN)
|
|
{
|
|
if(EN == ENABLE){
|
|
hardware_SPI.mode |= SPI_NO_CS;
|
|
}else {
|
|
hardware_SPI.mode &= ~SPI_NO_CS;
|
|
}
|
|
//Write device
|
|
if (ioctl(hardware_SPI.fd, SPI_IOC_WR_MODE, &hardware_SPI.mode) == -1) {
|
|
DEV_HARDWARE_SPI_Debug("can't set spi CS EN\r\n");
|
|
return -1;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/******************************************************************************
|
|
function: Chip Select
|
|
parameter:
|
|
Info:
|
|
CS_Mode:
|
|
SPI_CS_Mode_LOW
|
|
SPI_CS_Mode_HIGH
|
|
SPI_CS_Mode_NONE
|
|
Return :
|
|
Return 1 success
|
|
Return -1 failed
|
|
******************************************************************************/
|
|
int DEV_HARDWARE_SPI_ChipSelect(SPIChipSelect CS_Mode)
|
|
{
|
|
if(CS_Mode == SPI_CS_Mode_HIGH){
|
|
hardware_SPI.mode |= SPI_CS_HIGH;
|
|
hardware_SPI.mode &= ~SPI_NO_CS;
|
|
DEV_HARDWARE_SPI_Debug("CS HIGH \r\n");
|
|
}else if(CS_Mode == SPI_CS_Mode_LOW){
|
|
hardware_SPI.mode &= ~SPI_CS_HIGH;
|
|
hardware_SPI.mode &= ~SPI_NO_CS;
|
|
}else if(CS_Mode == SPI_CS_Mode_NONE){
|
|
hardware_SPI.mode |= SPI_NO_CS;
|
|
}
|
|
|
|
if (ioctl(hardware_SPI.fd, SPI_IOC_WR_MODE, &hardware_SPI.mode) == -1) {
|
|
DEV_HARDWARE_SPI_Debug("can't set spi mode\r\n");
|
|
return -1;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/******************************************************************************
|
|
function: Sets the SPI bit order
|
|
parameter:
|
|
Info:
|
|
Order:
|
|
SPI_BIT_ORDER_LSBFIRST
|
|
SPI_BIT_ORDER_MSBFIRST
|
|
Return :
|
|
Return 1 success
|
|
Return -1 failed
|
|
******************************************************************************/
|
|
int DEV_HARDWARE_SPI_SetBitOrder(SPIBitOrder Order)
|
|
{
|
|
if(Order == SPI_BIT_ORDER_LSBFIRST){
|
|
hardware_SPI.mode |= SPI_LSB_FIRST;
|
|
DEV_HARDWARE_SPI_Debug("SPI_LSB_FIRST\r\n");
|
|
}else if(Order == SPI_BIT_ORDER_MSBFIRST){
|
|
hardware_SPI.mode &= ~SPI_LSB_FIRST;
|
|
DEV_HARDWARE_SPI_Debug("SPI_MSB_FIRST\r\n");
|
|
}
|
|
|
|
// DEV_HARDWARE_SPI_Debug("hardware_SPI.mode = 0x%02x\r\n", hardware_SPI.mode);
|
|
int fd = ioctl(hardware_SPI.fd, SPI_IOC_WR_MODE, &hardware_SPI.mode);
|
|
DEV_HARDWARE_SPI_Debug("fd = %d\r\n",fd);
|
|
if (fd == -1) {
|
|
DEV_HARDWARE_SPI_Debug("can't set spi SPI_LSB_FIRST\r\n");
|
|
return -1;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/******************************************************************************
|
|
function: Sets the SPI Bus Mode
|
|
parameter:
|
|
Info:
|
|
Order:
|
|
SPI_3WIRE_Mode
|
|
SPI_4WIRE_Mode
|
|
Return :
|
|
Return 1 success
|
|
Return -1 failed
|
|
******************************************************************************/
|
|
int DEV_HARDWARE_SPI_SetBusMode(BusMode mode)
|
|
{
|
|
if(mode == SPI_3WIRE_Mode){
|
|
hardware_SPI.mode |= SPI_3WIRE;
|
|
}else if(mode == SPI_4WIRE_Mode){
|
|
hardware_SPI.mode &= ~SPI_3WIRE;
|
|
}
|
|
if (ioctl(hardware_SPI.fd, SPI_IOC_WR_MODE, &hardware_SPI.mode) == -1) {
|
|
DEV_HARDWARE_SPI_Debug("can't set spi mode\r\n");
|
|
return -1;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/******************************************************************************
|
|
function:
|
|
Time interval after transmission of one byte during continuous transmission
|
|
parameter:
|
|
us : Interval time (us)
|
|
Info:
|
|
******************************************************************************/
|
|
void DEV_HARDWARE_SPI_SetDataInterval(uint16_t us)
|
|
{
|
|
hardware_SPI.delay = us;
|
|
tr.delay_usecs = hardware_SPI.delay;
|
|
}
|
|
|
|
/******************************************************************************
|
|
function: SPI port sends one byte of data
|
|
parameter:
|
|
buf : Sent data
|
|
Info:
|
|
******************************************************************************/
|
|
uint8_t DEV_HARDWARE_SPI_TransferByte(uint8_t buf)
|
|
{
|
|
uint8_t rbuf[1];
|
|
tr.len = 1;
|
|
tr.tx_buf = (unsigned long)&buf;
|
|
tr.rx_buf = (unsigned long)rbuf;
|
|
|
|
//ioctl Operation, transmission of data
|
|
if ( ioctl(hardware_SPI.fd, SPI_IOC_MESSAGE(1), &tr) < 1 )
|
|
DEV_HARDWARE_SPI_Debug("can't send spi message\r\n");
|
|
return rbuf[0];
|
|
}
|
|
|
|
/******************************************************************************
|
|
function: The SPI port reads a byte
|
|
parameter:
|
|
Info: Return read data
|
|
******************************************************************************/
|
|
int DEV_HARDWARE_SPI_Transfer(uint8_t *buf, uint32_t len)
|
|
{
|
|
tr.len = len;
|
|
tr.tx_buf = (unsigned long)buf;
|
|
tr.rx_buf = (unsigned long)buf;
|
|
|
|
//ioctl Operation, transmission of data
|
|
if (ioctl(hardware_SPI.fd, SPI_IOC_MESSAGE(1), &tr) < 1 ){
|
|
DEV_HARDWARE_SPI_Debug("can't send spi message\r\n");
|
|
return -1;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|