Platform drivers for Mbed.
Dependents: EVAL-CN0535-FMCZ EVAL-CN0535-FMCZ EVAL-AD568x-AD569x EVAL-AD7606 ... more
src/spi.cpp
- Committer:
- mahphalke
- Date:
- 2020-10-16
- Revision:
- 14:46aad38346a6
- Parent:
- 13:c446482b0360
- Child:
- 15:fd2c3c3038bf
File content as of revision 14:46aad38346a6:
/***************************************************************************//** * @file spi.cpp * @brief Implementation of SPI No-OS platform driver interfaces ******************************************************************************** * Copyright (c) 2019, 2020 Analog Devices, Inc. * * All rights reserved. * * This software is proprietary to Analog Devices, Inc. and its licensors. * By using this software you agree to the terms of the associated * Analog Devices Software License Agreement. *******************************************************************************/ /******************************************************************************/ /***************************** Include Files **********************************/ /******************************************************************************/ #include <stdio.h> #include <mbed.h> #include "platform_drivers.h" #include "spi_extra.h" /******************************************************************************/ /********************** Macros and Constants Definitions **********************/ /******************************************************************************/ #define SPI_16_BIT_FRAME 16 // SPI 16-bit frame size #define SPI_8_BIT_FRAME 8 // SPI 8-bit frame size /******************************************************************************/ /********************** Variables and User defined data types *****************/ /******************************************************************************/ static uint8_t spi_format_bytes = SPI_16_BIT_FRAME; // SPI format /******************************************************************************/ /************************ Functions Declarations ******************************/ /******************************************************************************/ /******************************************************************************/ /************************ Functions Definitions *******************************/ /******************************************************************************/ /** * @brief Initialize the SPI communication peripheral. * @param desc - The SPI descriptor. * @param init_param - The structure that contains the SPI parameters. * @return SUCCESS in case of success, FAILURE otherwise. */ int32_t spi_init_noos(struct spi_desc **desc, const struct spi_init_param *param) { mbed::SPI *spi; // pointer to new spi instance DigitalOut *ss; // pointer to new SS instance mbed_spi_desc *mbed_desc; // Pointer to mbed spi descriptor if (desc) { // Create the spi description object for the device spi_desc * new_desc = (spi_desc *)malloc(sizeof(spi_desc)); if (new_desc == NULL) { return FAILURE; } new_desc->chip_select = param->chip_select; new_desc->mode = param->mode; new_desc->max_speed_hz = param->max_speed_hz; // Configure and instantiate SPI protocol spi = new SPI( (PinName)(((mbed_spi_init_param *)param->extra)->spi_mosi_pin), (PinName)(((mbed_spi_init_param *)param->extra)->spi_miso_pin), (PinName)(((mbed_spi_init_param *)param->extra)->spi_clk_pin)); if (spi == NULL) { return FAILURE; } // Configure and instantiate slave select pin ss = new DigitalOut((PinName)(new_desc->chip_select)); if (ss == NULL) { return FAILURE; } // Create the SPI extra descriptor object to store new SPI instances mbed_desc = (mbed_spi_desc *)malloc(sizeof(mbed_spi_desc)); if (mbed_desc == NULL) { return FAILURE; } mbed_desc->spi_port = (SPI *)spi; mbed_desc->slave_select = (DigitalOut *)ss; new_desc->extra = (mbed_spi_desc *)mbed_desc; *desc = new_desc; /** NOTE: Actual frequency of SPI clk will be somewhat device dependent, relating to clock-settings, prescalars etc. If absolute SPI frequency is required, consult your device documentation. **/ spi->frequency(param->max_speed_hz); spi->format(SPI_16_BIT_FRAME, param->mode); // data write/read format spi_format_bytes = SPI_16_BIT_FRAME; spi->set_default_write_value(0x00); // code to write when reading back ss->write(GPIO_HIGH); // set SS high return SUCCESS; } return FAILURE; } /** * @brief Free the resources allocated by spi_init(). * @param desc - The SPI descriptor. * @return SUCCESS in case of success, FAILURE otherwise. */ int32_t spi_remove(struct spi_desc *desc) { if (desc) { // Free the SPI port object if ((SPI *)(((mbed_spi_desc *)(desc->extra))->spi_port)) { delete((SPI *)(((mbed_spi_desc *)(desc->extra))->spi_port)); } // Free the SS port object if ((DigitalOut *)(((mbed_spi_desc *)(desc->extra))->slave_select)) { delete((DigitalOut *)(((mbed_spi_desc *)(desc->extra))->slave_select)); } // Free the SPI extra descriptor object if ((mbed_spi_desc *)(desc->extra)) { free((mbed_spi_desc *)(desc->extra)); } // Free the SPI descriptor object free(desc); return SUCCESS; } return FAILURE; } /** * @brief Write and read data to/from SPI. * @param desc - The SPI descriptor. * @param data - The buffer with the transmitted/received data. * @param bytes_number - Number of bytes to write/read. * @return SUCCESS in case of success, FAILURE otherwise. */ int32_t spi_write_and_read(struct spi_desc *desc, uint8_t *data, uint16_t bytes_number) { mbed::SPI *spi; // pointer to new spi instance mbed::DigitalOut *ss; // pointer to new SS instance uint16_t num_of_words; // Number of words in SPI frame uint16_t rw_data; // SPI read data (16-bit) uint16_t data_index = 0; // Data index size_t byte; // Byte read/write index if (desc) { spi = (SPI *)(((mbed_spi_desc *)(desc->extra))->spi_port); ss = (DigitalOut *)(((mbed_spi_desc *)(desc->extra))->slave_select); /* Get the total number of words (16-bit) */ num_of_words = bytes_number / 2; /* Determine the data transmit/receive format based on parity of data */ if (!(bytes_number % 2)) { if (spi_format_bytes != SPI_16_BIT_FRAME) { spi->format(SPI_16_BIT_FRAME, desc->mode); spi_format_bytes = SPI_16_BIT_FRAME; } } else { if (spi_format_bytes != SPI_8_BIT_FRAME) { spi->format(SPI_8_BIT_FRAME, desc->mode); spi_format_bytes = SPI_8_BIT_FRAME; } } ss->write(GPIO_LOW); /* **Note: It is not possible to change the format of data transfer when SPI * communication is in progress. If format is attempted to change (from 8-bit * to 16-bit or vice a versa), the SPI communication is reset and master generates * a single Clock signal during format change. This triggers false transfer on slave * which results into incorrect data transfer. For this reason, the bytes with even parity * are transferred in 16-bit format and odd parity bytes are transferred in 8-bit format. * Application layer doesn't have any control to stop SPI reset during format change. */ if (!(bytes_number % 2)) { while (num_of_words) { /* Form a 16-bit data to be written (LE format) */ rw_data = ((uint16_t)data[data_index + 1] | ((uint16_t)data[data_index] << 8)); /* Transmit a 16-bit data over SPI */ rw_data = (uint16_t)spi->write(rw_data); /* Extract the MSB and LSB from 16-bit read data (LE format) */ data[data_index++] = (uint8_t)(rw_data >> 8); data[data_index++] = (uint8_t)rw_data; num_of_words--; } } else { for (byte = 0; byte < bytes_number; byte++) { data[byte] = spi->write(data[byte]); } } ss->write(GPIO_HIGH); return SUCCESS; } return FAILURE; }