/***************************************************************************** * | 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 #include #include #include #include #include #include #include #include #include #include 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; }