mbed library sources. Supersedes mbed-src.
Dependents: Nucleo_Hello_Encoder BLE_iBeaconScan AM1805_DEMO DISCO-F429ZI_ExportTemplate1 ... more
targets/TARGET_Analog_Devices/TARGET_ADUCM302X/TARGET_ADUCM3029/api/spi_api.c
- Committer:
- AnnaBridge
- Date:
- 2019-02-20
- Revision:
- 189:f392fc9709a3
- Parent:
- 180:96ed750bd169
File content as of revision 189:f392fc9709a3:
/******************************************************************************* * Copyright (c) 2010-2017 Analog Devices, Inc. * * 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. * - Modified versions of the software must be conspicuously marked as such. * - This software is licensed solely and exclusively for use with processors * manufactured by or for Analog Devices, Inc. * - This software may not be combined or merged with other code in any manner * that would cause the software to become subject to terms and conditions * which differ from those listed here. * - Neither the name of Analog Devices, Inc. nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * - The use of this software may or may not infringe the patent rights of one * or more patent holders. This license does not release you from the * requirement that you obtain separate licenses from these patent holders * to use this software. * * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON- * INFRINGEMENT, TITLE, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL ANALOG DEVICES, INC. OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, DAMAGES ARISING OUT OF * CLAIMS OF INTELLECTUAL PROPERTY RIGHTS INFRINGEMENT; 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. ******************************************************************************/ #include <math.h> #include "mbed_assert.h" #include "spi_api.h" #if DEVICE_SPI #include "cmsis.h" #include "pinmap.h" #include "mbed_error.h" #include "PeripheralPins.h" #include "drivers/spi/adi_spi.h" #if defined(BUILD_SPI_MI_DYNAMIC) #if defined(ADI_DEBUG) #warning "BUILD_SPI_MI_DYNAMIC is defined. Memory allocation for SPI will be dynamic" int adi_spi_memtype = 0; #endif #else /******************************************************************************* ADI_SPI_DEV_DATA_TYPE Instance memory containing memory pointer should guarantee 4 byte alignmnet. *******************************************************************************/ ADI_SPI_HANDLE spi_Handle0; uint32_t spi_Mem0[(ADI_SPI_MEMORY_SIZE + 3)/4]; ADI_SPI_HANDLE spi_Handle1; uint32_t spi_Mem1[(ADI_SPI_MEMORY_SIZE + 3)/4]; ADI_SPI_HANDLE spi_Handle2; uint32_t spi_Mem2[(ADI_SPI_MEMORY_SIZE + 3)/4]; #if defined(ADI_DEBUG) #warning "BUILD_SPI_MI_DYNAMIC is NOT defined. Memory allocation for SPI will be static" int adi_spi_memtype = 1; #endif #endif /** Initialize the SPI peripheral * * Configures the pins used by SPI, sets a default format and frequency, and enables the peripheral * @param[out] obj The SPI object to initialize * @param[in] mosi The pin to use for MOSI * @param[in] miso The pin to use for MISO * @param[in] sclk The pin to use for SCLK * @param[in] ssel The pin to use for SSEL */ void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel) { // determine the SPI to use uint32_t spi_mosi = pinmap_peripheral(mosi, PinMap_SPI_MOSI); uint32_t spi_miso = pinmap_peripheral(miso, PinMap_SPI_MISO); uint32_t spi_sclk = pinmap_peripheral(sclk, PinMap_SPI_SCLK); uint32_t spi_ssel = pinmap_peripheral(ssel, PinMap_SPI_SSEL); uint32_t spi_data = pinmap_merge(spi_mosi, spi_miso); uint32_t spi_cntl = pinmap_merge(spi_sclk, spi_ssel); ADI_SPI_HANDLE *pSPI_Handle; uint32_t *SPI_Mem; ADI_SPI_RESULT SPI_Return = ADI_SPI_SUCCESS; uint32_t nDeviceNum = 0; ADI_SPI_CHIP_SELECT spi_cs = ADI_SPI_CS_NONE; #if defined(BUILD_SPI_MI_DYNAMIC) if (mosi == SPI0_MOSI) { nDeviceNum = SPI_0; } else if (mosi == SPI1_MOSI) { nDeviceNum = SPI_1; } else if (mosi == SPI2_MOSI) { nDeviceNum = SPI_2; } pSPI_Handle = &obj->SPI_Handle; obj->pSPI_Handle = pSPI_Handle; SPI_Mem = obj->SPI_Mem; #else if (mosi == SPI0_MOSI) { nDeviceNum = SPI_0; pSPI_Handle = &spi_Handle0; SPI_Mem = &spi_Mem0[0]; } else if (mosi == SPI1_MOSI) { nDeviceNum = SPI_1; pSPI_Handle = &spi_Handle1; SPI_Mem = &spi_Mem1[0]; } else if (mosi == SPI2_MOSI) { nDeviceNum = SPI_2; pSPI_Handle = &spi_Handle2; SPI_Mem = &spi_Mem2[0]; } obj->pSPI_Handle = pSPI_Handle; #endif obj->instance = pinmap_merge(spi_data, spi_cntl); MBED_ASSERT((int)obj->instance != NC); // pin out the spi pins pinmap_pinout(mosi, PinMap_SPI_MOSI); pinmap_pinout(miso, PinMap_SPI_MISO); pinmap_pinout(sclk, PinMap_SPI_SCLK); if (ssel != NC) { pinmap_pinout(ssel, PinMap_SPI_SSEL); } SystemCoreClockUpdate(); SPI_Return = adi_spi_Open(nDeviceNum, SPI_Mem, ADI_SPI_MEMORY_SIZE, pSPI_Handle); if (SPI_Return) { obj->error = SPI_EVENT_ERROR; return; } if (ssel != NC) { if ( (ssel == SPI0_CS0) || (ssel == SPI1_CS0) || (ssel == SPI2_CS0)) { spi_cs = ADI_SPI_CS0; } else if ( (ssel == SPI0_CS1) || (ssel == SPI1_CS1) || (ssel == SPI2_CS1)) { spi_cs = ADI_SPI_CS1; } else if ( (ssel == SPI0_CS2) || (ssel == SPI1_CS2) || (ssel == SPI2_CS2)) { spi_cs = ADI_SPI_CS2; } else if ( (ssel == SPI0_CS3) || (ssel == SPI1_CS3) || (ssel == SPI2_CS3)) { spi_cs = ADI_SPI_CS3; } SPI_Return = adi_spi_SetChipSelect(*pSPI_Handle, spi_cs); if (SPI_Return) { obj->error = SPI_EVENT_ERROR; return; } } } /** Release a SPI object * * TODO: spi_free is currently unimplemented * This will require reference counting at the C++ level to be safe * * Return the pins owned by the SPI object to their reset state * Disable the SPI peripheral * Disable the SPI clock * @param[in] obj The SPI object to deinitialize */ void spi_free(spi_t *obj) { ADI_SPI_HANDLE SPI_Handle; ADI_SPI_RESULT SPI_Return = ADI_SPI_SUCCESS; SPI_Handle = *obj->pSPI_Handle; SPI_Return = adi_spi_Close(SPI_Handle); if (SPI_Return) { obj->error = SPI_EVENT_ERROR; return; } } /** Configure the SPI format * * Set the number of bits per frame, configure clock polarity and phase, shift order and master/slave mode. * The default bit order is MSB. * @param[in,out] obj The SPI object to configure * @param[in] bits The number of bits per frame * @param[in] mode The SPI mode (clock polarity, phase, and shift direction) * @param[in] slave Zero for master mode or non-zero for slave mode * ** Configure the data transmission format * * @param bits Number of bits per SPI frame (4 - 16) * @param mode Clock polarity and phase mode (0 - 3) * * @code * mode | POL PHA * -----+-------- * 0 | 0 0 * 1 | 0 1 * 2 | 1 0 * 3 | 1 1 * @endcode bool phase; true : trailing-edge false : leading-edge bool polarity; true : CPOL=1 (idle high) polarity false : CPOL=0 (idle-low) polarity */ void spi_format(spi_t *obj, int bits, int mode, int slave) { ADI_SPI_HANDLE SPI_Handle; ADI_SPI_RESULT SPI_Return = ADI_SPI_SUCCESS; bool phase; bool polarity; bool master; SPI_Handle = *obj->pSPI_Handle; if ((uint32_t)mode & 0x1) { phase = true; } else { phase = false; } SPI_Return = adi_spi_SetClockPhase(SPI_Handle, phase); if (SPI_Return) { obj->error = SPI_EVENT_ERROR; return; } if ((uint32_t)mode & 0x2) { polarity = true; } else { polarity = false; } SPI_Return = adi_spi_SetClockPolarity(SPI_Handle, polarity); if (SPI_Return) { obj->error = SPI_EVENT_ERROR; return; } master = !((bool)slave); SPI_Return = adi_spi_SetMasterMode(SPI_Handle, master); if (SPI_Return) { obj->error = SPI_EVENT_ERROR; return; } } /** Set the SPI baud rate * * Actual frequency may differ from the desired frequency due to available dividers and bus clock * Configures the SPI peripheral's baud rate * @param[in,out] obj The SPI object to configure * @param[in] hz The baud rate in Hz */ void spi_frequency(spi_t *obj, int hz) { ADI_SPI_HANDLE SPI_Handle; ADI_SPI_RESULT SPI_Return = ADI_SPI_SUCCESS; SPI_Handle = *obj->pSPI_Handle; SPI_Return = adi_spi_SetBitrate(SPI_Handle, (uint32_t) hz); if (SPI_Return) { obj->error = SPI_EVENT_ERROR; return; } } /** Write a byte out in master mode and receive a value * * @param[in] obj The SPI peripheral to use for sending * @param[in] value The value to send * @return Returns the value received during send */ int spi_master_write(spi_t *obj, int value) { ADI_SPI_TRANSCEIVER transceive; uint8_t TxBuf; uint8_t RxBuf; ADI_SPI_HANDLE SPI_Handle; ADI_SPI_RESULT SPI_Return = ADI_SPI_SUCCESS; TxBuf = (uint8_t)value; transceive.pReceiver = &RxBuf; transceive.ReceiverBytes = 1; /* link transceive data size to the remaining count */ transceive.nRxIncrement = 1; /* auto increment buffer */ transceive.pTransmitter = &TxBuf; /* initialize data attributes */ transceive.TransmitterBytes = 1; /* link transceive data size to the remaining count */ transceive.nTxIncrement = 1; /* auto increment buffer */ transceive.bDMA = false; transceive.bRD_CTL = false; SPI_Handle = *obj->pSPI_Handle; SPI_Return = adi_spi_MasterReadWrite(SPI_Handle, &transceive); if (SPI_Return) { obj->error = SPI_EVENT_ERROR; return 1; } return((int)RxBuf); } /** Write a block out in master mode and receive a value * * The total number of bytes sent and recieved will be the maximum of * tx_length and rx_length. The bytes written will be padded with the * value 0xff. * * @param[in] obj The SPI peripheral to use for sending * @param[in] tx_buffer Pointer to the byte-array of data to write to the device * @param[in] tx_length Number of bytes to write, may be zero * @param[in] rx_buffer Pointer to the byte-array of data to read from the device * @param[in] rx_length Number of bytes to read, may be zero * @param[in] write_fill Default data transmitted while performing a read * @returns * The number of bytes written and read from the device. This is * maximum of tx_length and rx_length. */ int spi_master_block_write(spi_t *obj, const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length, char write_fill) { ADI_SPI_TRANSCEIVER transceive; ADI_SPI_HANDLE SPI_Handle; ADI_SPI_RESULT SPI_Return = ADI_SPI_SUCCESS; transceive.pReceiver = (uint8_t*)rx_buffer; transceive.ReceiverBytes = rx_length; /* link transceive data size to the remaining count */ transceive.nRxIncrement = 1; /* auto increment buffer */ transceive.pTransmitter = (uint8_t*)tx_buffer; /* initialize data attributes */ transceive.TransmitterBytes = tx_length; /* link transceive data size to the remaining count */ transceive.nTxIncrement = 1; /* auto increment buffer */ transceive.bDMA = false; transceive.bRD_CTL = false; SPI_Handle = *obj->pSPI_Handle; SPI_Return = adi_spi_MasterReadWrite(SPI_Handle, &transceive); if (SPI_Return) { obj->error = SPI_EVENT_ERROR; return -1; } else { return((int)tx_length); } } #endif