mbed library sources. Supersedes mbed-src.

Fork of mbed-dev by mbed official

Committer:
Anna Bridge
Date:
Wed Jan 17 15:23:54 2018 +0000
Revision:
181:96ed750bd169
Parent:
170:19eb464bc2be
mbed-dev libray. Release version 158

Who changed what in which revision?

UserRevisionLine numberNew contents of line
<> 149:156823d33999 1 /*******************************************************************************
<> 149:156823d33999 2 * Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved.
<> 149:156823d33999 3 *
<> 149:156823d33999 4 * Permission is hereby granted, free of charge, to any person obtaining a
<> 149:156823d33999 5 * copy of this software and associated documentation files (the "Software"),
<> 149:156823d33999 6 * to deal in the Software without restriction, including without limitation
<> 149:156823d33999 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
<> 149:156823d33999 8 * and/or sell copies of the Software, and to permit persons to whom the
<> 149:156823d33999 9 * Software is furnished to do so, subject to the following conditions:
<> 149:156823d33999 10 *
<> 149:156823d33999 11 * The above copyright notice and this permission notice shall be included
<> 149:156823d33999 12 * in all copies or substantial portions of the Software.
<> 149:156823d33999 13 *
<> 149:156823d33999 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
<> 149:156823d33999 15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
<> 149:156823d33999 16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
<> 149:156823d33999 17 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
<> 149:156823d33999 18 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
<> 149:156823d33999 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
<> 149:156823d33999 20 * OTHER DEALINGS IN THE SOFTWARE.
<> 149:156823d33999 21 *
<> 149:156823d33999 22 * Except as contained in this notice, the name of Maxim Integrated
<> 149:156823d33999 23 * Products, Inc. shall not be used except as stated in the Maxim Integrated
<> 149:156823d33999 24 * Products, Inc. Branding Policy.
<> 149:156823d33999 25 *
<> 149:156823d33999 26 * The mere transfer of this software does not imply any licenses
<> 149:156823d33999 27 * of trade secrets, proprietary technology, copyrights, patents,
<> 149:156823d33999 28 * trademarks, maskwork rights, or any other form of intellectual
<> 149:156823d33999 29 * property whatsoever. Maxim Integrated Products, Inc. retains all
<> 149:156823d33999 30 * ownership rights.
<> 149:156823d33999 31 *******************************************************************************
<> 149:156823d33999 32 */
<> 149:156823d33999 33
<> 149:156823d33999 34 #include <string.h>
<> 149:156823d33999 35 #include "mbed_assert.h"
<> 149:156823d33999 36 #include "cmsis.h"
<> 149:156823d33999 37 #include "spi_api.h"
<> 149:156823d33999 38 #include "spi_multi_api.h"
<> 149:156823d33999 39 #include "pinmap.h"
<> 149:156823d33999 40 #include "ioman_regs.h"
<> 149:156823d33999 41 #include "clkman_regs.h"
<> 149:156823d33999 42 #include "PeripheralPins.h"
<> 149:156823d33999 43
<> 149:156823d33999 44 #define DEFAULT_CHAR 8
<> 149:156823d33999 45 #define DEFAULT_MODE 0
<> 149:156823d33999 46 #define DEFAULT_FREQ 1000000
<> 149:156823d33999 47
<> 149:156823d33999 48 // BYTE maximums for FIFO and page writes; FIFO depth spec'd as 16-bit words
<> 149:156823d33999 49 #define SPI_MAX_BYTE_LEN (MXC_CFG_SPI_FIFO_DEPTH * 2)
<> 149:156823d33999 50 #define SPI_MAX_PAGE_LEN (MXC_CFG_SPI_FIFO_DEPTH * 2)
<> 149:156823d33999 51
<> 149:156823d33999 52 #if DEVICE_SPI_ASYNCH
<> 149:156823d33999 53 // Instance references for async transactions
<> 149:156823d33999 54 static struct spi_s *state[MXC_CFG_SPI_INSTANCES] = {NULL};
<> 149:156823d33999 55 #endif
<> 149:156823d33999 56
<> 149:156823d33999 57 //******************************************************************************
<> 149:156823d33999 58 void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel)
<> 149:156823d33999 59 {
<> 149:156823d33999 60 // Make sure pins are pointing to the same SPI instance
<> 149:156823d33999 61 SPIName spi_mosi = (SPIName)pinmap_peripheral(mosi, PinMap_SPI_MOSI);
<> 149:156823d33999 62 SPIName spi_miso = (SPIName)pinmap_peripheral(miso, PinMap_SPI_MISO);
<> 149:156823d33999 63 SPIName spi_sclk = (SPIName)pinmap_peripheral(sclk, PinMap_SPI_SCLK);
<> 149:156823d33999 64 SPIName spi_ssel = (SPIName)pinmap_peripheral(ssel, PinMap_SPI_SSEL);
<> 149:156823d33999 65
<> 149:156823d33999 66 SPIName spi_data = (SPIName)pinmap_merge(spi_mosi, spi_miso);
<> 149:156823d33999 67 SPIName spi_cntl;
<> 149:156823d33999 68
<> 149:156823d33999 69 // Give the application the option to manually control Slave Select
<> 149:156823d33999 70 if ((SPIName)spi_ssel != (SPIName)NC) {
<> 149:156823d33999 71 spi_cntl = (SPIName)pinmap_merge(spi_sclk, spi_ssel);
<> 149:156823d33999 72 // Slave select is currently limited to slave select zero. If others are
<> 149:156823d33999 73 // to be supported a function to map PinName to a value suitable for use
<> 149:156823d33999 74 // in mstr_cfg.slave_sel will be required.
<> 149:156823d33999 75 obj->spi.ssel = 0;
<> 149:156823d33999 76 } else {
<> 149:156823d33999 77 spi_cntl = spi_sclk;
<> 149:156823d33999 78 obj->spi.ssel = -1;
<> 149:156823d33999 79 }
<> 149:156823d33999 80
<> 149:156823d33999 81 SPIName spi = (SPIName)pinmap_merge(spi_data, spi_cntl);
<> 149:156823d33999 82
<> 149:156823d33999 83 MBED_ASSERT((SPIName)spi != (SPIName)NC);
<> 149:156823d33999 84
<> 149:156823d33999 85 // Set the obj pointer to the proper SPI Instance
<> 149:156823d33999 86 obj->spi.spi = (mxc_spi_regs_t*)spi;
<> 149:156823d33999 87
<> 149:156823d33999 88 // Set the SPI index and FIFOs
<> 149:156823d33999 89 obj->spi.index = MXC_SPI_GET_IDX(obj->spi.spi);
<> 149:156823d33999 90 obj->spi.fifo = MXC_SPI_GET_SPI_FIFO(obj->spi.index);
<> 149:156823d33999 91
<> 149:156823d33999 92 // Configure the pins
<> 149:156823d33999 93 pinmap_pinout(mosi, PinMap_SPI_MOSI);
<> 149:156823d33999 94 pinmap_pinout(miso, PinMap_SPI_MISO);
<> 149:156823d33999 95 pinmap_pinout(sclk, PinMap_SPI_SCLK);
<> 149:156823d33999 96 pinmap_pinout(ssel, PinMap_SPI_SSEL);
<> 149:156823d33999 97
<> 149:156823d33999 98 #if DEVICE_SPI_ASYNCH
<> 149:156823d33999 99 // Configure default page size; size is known to async interface
<> 149:156823d33999 100 obj->spi.spi->mstr_cfg = (obj->spi.spi->mstr_cfg & ~MXC_F_SPI_MSTR_CFG_PAGE_SIZE) | MXC_S_SPI_MSTR_CFG_PAGE_32B;
<> 149:156823d33999 101 #endif
<> 149:156823d33999 102
<> 149:156823d33999 103 // Enable SPI and FIFOs
<> 149:156823d33999 104 obj->spi.spi->gen_ctrl = (MXC_F_SPI_GEN_CTRL_SPI_MSTR_EN |
<> 149:156823d33999 105 MXC_F_SPI_GEN_CTRL_TX_FIFO_EN |
<> 149:156823d33999 106 MXC_F_SPI_GEN_CTRL_RX_FIFO_EN );
<> 149:156823d33999 107
<> 149:156823d33999 108 obj->spi.sclk = sclk; // save the sclk PinName in the object as a key for Quad SPI pin mapping lookup
<> 149:156823d33999 109 spi_master_width(obj, 0); // default this for Single SPI communications
<> 149:156823d33999 110 }
<> 149:156823d33999 111
<> 149:156823d33999 112 //******************************************************************************
<> 149:156823d33999 113 void spi_format(spi_t *obj, int bits, int mode, int slave)
<> 149:156823d33999 114 {
<> 149:156823d33999 115 // Check the validity of the inputs
<> 149:156823d33999 116 MBED_ASSERT(((bits >= 1) && (bits <= 32)) && ((mode >= 0) && (mode <= 3)));
<> 149:156823d33999 117
<> 149:156823d33999 118 // Only supports master mode
<> 149:156823d33999 119 MBED_ASSERT(!slave);
<> 149:156823d33999 120
<> 149:156823d33999 121 // Save formatting data
<> 149:156823d33999 122 obj->spi.bits = bits;
<> 149:156823d33999 123
<> 149:156823d33999 124 // Set the mode
<> 149:156823d33999 125 MXC_SET_FIELD(&obj->spi.spi->mstr_cfg, MXC_F_SPI_MSTR_CFG_SPI_MODE, mode << MXC_F_SPI_MSTR_CFG_SPI_MODE_POS);
<> 149:156823d33999 126 }
<> 149:156823d33999 127
<> 149:156823d33999 128 //******************************************************************************
<> 149:156823d33999 129 void spi_frequency(spi_t *obj, int hz)
<> 149:156823d33999 130 {
<> 149:156823d33999 131 // Maximum frequency is half the system frequency
<> 149:156823d33999 132 MBED_ASSERT((unsigned int)hz <= (SystemCoreClock / 2));
<> 149:156823d33999 133 unsigned clocks = ((SystemCoreClock / 2) / hz);
<> 149:156823d33999 134
<> 149:156823d33999 135 // Figure out the divider ratio
<> 149:156823d33999 136 int clk_div = 1;
<> 149:156823d33999 137 while (clk_div < 10) {
<> 149:156823d33999 138 if (clocks < 0x10) {
<> 149:156823d33999 139 break;
<> 149:156823d33999 140 }
<> 149:156823d33999 141 clk_div++;
<> 149:156823d33999 142 clocks = clocks >> 1;
<> 149:156823d33999 143 }
<> 149:156823d33999 144
<> 149:156823d33999 145 // Turn on the SPI clock
<> 149:156823d33999 146 if (obj->spi.index == 0) {
<> 149:156823d33999 147 MXC_CLKMAN->sys_clk_ctrl_11_spi0 = clk_div;
<> 149:156823d33999 148 } else if (obj->spi.index == 1) {
<> 149:156823d33999 149 MXC_CLKMAN->sys_clk_ctrl_12_spi1 = clk_div;
<> 149:156823d33999 150 } else if (obj->spi.index == 2) {
<> 149:156823d33999 151 MXC_CLKMAN->sys_clk_ctrl_13_spi2 = clk_div;
<> 149:156823d33999 152 } else {
<> 149:156823d33999 153 MBED_ASSERT(0);
<> 149:156823d33999 154 }
<> 149:156823d33999 155
<> 149:156823d33999 156 // Set the number of clocks to hold sclk high and low
<> 149:156823d33999 157 MXC_SET_FIELD(&obj->spi.spi->mstr_cfg, (MXC_F_SPI_MSTR_CFG_SCK_HI_CLK | MXC_F_SPI_MSTR_CFG_SCK_LO_CLK),
<> 149:156823d33999 158 ((clocks << MXC_F_SPI_MSTR_CFG_SCK_HI_CLK_POS) | (clocks << MXC_F_SPI_MSTR_CFG_SCK_LO_CLK_POS)));
<> 149:156823d33999 159 }
<> 149:156823d33999 160
<> 149:156823d33999 161 //******************************************************************************
<> 149:156823d33999 162 void spi_master_width(spi_t *obj, SpiWidth width)
<> 149:156823d33999 163 {
<> 149:156823d33999 164 // Save the width to be used in the SPI header
<> 149:156823d33999 165 switch (width) {
<> 149:156823d33999 166 case WidthSingle:
<> 149:156823d33999 167 obj->spi.width = MXC_S_SPI_FIFO_WIDTH_SINGLE;
<> 149:156823d33999 168 break;
<> 149:156823d33999 169 case WidthDual:
<> 149:156823d33999 170 obj->spi.width = MXC_S_SPI_FIFO_WIDTH_DUAL;
<> 149:156823d33999 171 break;
<> 149:156823d33999 172 case WidthQuad:
<> 149:156823d33999 173 obj->spi.width = MXC_S_SPI_FIFO_WIDTH_QUAD;
<> 149:156823d33999 174 // do pin mapping for SDIO[2] and SDIO[3] if Quad SPI is selected
<> 149:156823d33999 175 pinmap_pinout(obj->spi.sclk, PinMap_SPI_QUAD);
<> 149:156823d33999 176 break;
<> 149:156823d33999 177 default:
<> 149:156823d33999 178 MBED_ASSERT(0);
<> 149:156823d33999 179 }
<> 149:156823d33999 180 }
<> 149:156823d33999 181
<> 149:156823d33999 182 //******************************************************************************
<> 149:156823d33999 183 /** Performs a master write or read transaction
<> 149:156823d33999 184 *
<> 149:156823d33999 185 * @param[in] obj The SPI peripheral to use for sending
<> 149:156823d33999 186 * @param[in] value The value to send
<> 149:156823d33999 187 * @param[in] direction Direction of the transaction, TX, RX or both
<> 149:156823d33999 188 * @return Returns the value received during send
<> 149:156823d33999 189 */
<> 149:156823d33999 190 static int spi_master_transaction(spi_t *obj, int value, uint32_t direction)
<> 149:156823d33999 191 {
<> 149:156823d33999 192 int bits;
<> 149:156823d33999 193
<> 149:156823d33999 194 // Create the header
<> 149:156823d33999 195 uint16_t header = (direction | // direction based on SPI object
<> 149:156823d33999 196 MXC_S_SPI_FIFO_UNIT_BITS | // unit size
<> 149:156823d33999 197 ((obj->spi.bits == 32) ? 0 : obj->spi.bits << MXC_F_SPI_FIFO_SIZE_POS) | // Number of units
<> 149:156823d33999 198 obj->spi.width | // I/O width
<> 149:156823d33999 199 ((obj->spi.ssel == -1) ? 0 : 1 << MXC_F_SPI_FIFO_DASS_POS));
<> 149:156823d33999 200
<> 149:156823d33999 201 // Send the message header
<> 149:156823d33999 202 *obj->spi.fifo->trans_16 = header;
<> 149:156823d33999 203
<> 149:156823d33999 204 // Send the data
<> 149:156823d33999 205 if (obj->spi.bits < 17) {
<> 149:156823d33999 206 *obj->spi.fifo->trans_16 = (uint16_t)value;
<> 149:156823d33999 207 } else {
<> 149:156823d33999 208 *obj->spi.fifo->trans_32 = (uint32_t)value;
<> 149:156823d33999 209 }
<> 149:156823d33999 210
<> 149:156823d33999 211 // Get the data
<> 149:156823d33999 212 bits = obj->spi.bits;
<> 149:156823d33999 213 int result = 0;
<> 149:156823d33999 214 int i = 0;
<> 149:156823d33999 215 while (bits > 0) {
<> 149:156823d33999 216 // Wait for data
<> 149:156823d33999 217 while (((obj->spi.spi->fifo_ctrl & MXC_F_SPI_FIFO_CTRL_RX_FIFO_USED)
<> 149:156823d33999 218 >> MXC_F_SPI_FIFO_CTRL_RX_FIFO_USED_POS) < 1);
<> 149:156823d33999 219
<> 149:156823d33999 220 result |= (*obj->spi.fifo->rslts_8 << (i++*8));
<> 149:156823d33999 221 bits-=8;
<> 149:156823d33999 222 }
<> 149:156823d33999 223
<> 149:156823d33999 224 return result;
<> 149:156823d33999 225 }
<> 149:156823d33999 226
<> 149:156823d33999 227 //******************************************************************************
<> 149:156823d33999 228 int spi_master_write(spi_t *obj, int value)
<> 149:156823d33999 229 {
<> 149:156823d33999 230 // set the fifo direction for full duplex, TX and RX simultaneously
<> 149:156823d33999 231 return spi_master_transaction(obj, value, MXC_S_SPI_FIFO_DIR_BOTH);
<> 149:156823d33999 232 }
<> 149:156823d33999 233
Kojto 170:19eb464bc2be 234 int spi_master_block_write(spi_t *obj, const char *tx_buffer, int tx_length,
Kojto 170:19eb464bc2be 235 char *rx_buffer, int rx_length, char write_fill) {
AnnaBridge 167:e84263d55307 236 int total = (tx_length > rx_length) ? tx_length : rx_length;
AnnaBridge 167:e84263d55307 237
AnnaBridge 167:e84263d55307 238 for (int i = 0; i < total; i++) {
Kojto 170:19eb464bc2be 239 char out = (i < tx_length) ? tx_buffer[i] : write_fill;
AnnaBridge 167:e84263d55307 240 char in = spi_master_write(obj, out);
AnnaBridge 167:e84263d55307 241 if (i < rx_length) {
AnnaBridge 167:e84263d55307 242 rx_buffer[i] = in;
AnnaBridge 167:e84263d55307 243 }
AnnaBridge 167:e84263d55307 244 }
AnnaBridge 167:e84263d55307 245
AnnaBridge 167:e84263d55307 246 return total;
AnnaBridge 167:e84263d55307 247 }
AnnaBridge 167:e84263d55307 248
<> 149:156823d33999 249 //******************************************************************************
<> 149:156823d33999 250 int spi_master_read(spi_t *obj)
<> 149:156823d33999 251 {
<> 149:156823d33999 252 return spi_master_transaction(obj, 0xFF, MXC_S_SPI_FIFO_DIR_RX);
<> 149:156823d33999 253 }
<> 149:156823d33999 254
<> 149:156823d33999 255 //******************************************************************************
<> 149:156823d33999 256 // spi_busy() is part of the synchronous API, it is not used by the asynchronous API.
<> 149:156823d33999 257 int spi_busy(spi_t *obj)
<> 149:156823d33999 258 {
<> 149:156823d33999 259 return !(obj->spi.spi->intfl & MXC_F_SPI_INTFL_TX_READY);
<> 149:156823d33999 260 }
<> 149:156823d33999 261
<> 149:156823d33999 262 #if DEVICE_SPI_ASYNCH
<> 149:156823d33999 263 //******************************************************************************
<> 149:156823d33999 264 static uint32_t spi_master_read_rxfifo(mxc_spi_regs_t *spim, mxc_spi_fifo_regs_t *fifo, uint8_t *data, uint32_t len)
<> 149:156823d33999 265 {
<> 149:156823d33999 266 uint32_t num = 0;
<> 149:156823d33999 267 uint32_t avail = ((spim->fifo_ctrl & MXC_F_SPI_FIFO_CTRL_RX_FIFO_USED) >> MXC_F_SPI_FIFO_CTRL_RX_FIFO_USED_POS);
<> 149:156823d33999 268
<> 149:156823d33999 269 // Get data from the RXFIFO
<> 149:156823d33999 270 while (avail && (len - num)) {
<> 149:156823d33999 271 // Save data from the RXFIFO
<> 149:156823d33999 272 if ((avail >= 4) && ((len - num) >= 4)) {
<> 149:156823d33999 273 uint32_t temp = *fifo->rslts_32;
<> 149:156823d33999 274 data[num++] = temp;
<> 149:156823d33999 275 data[num++] = temp >> 8;
<> 149:156823d33999 276 data[num++] = temp >> 16;
<> 149:156823d33999 277 data[num++] = temp >> 24;
<> 149:156823d33999 278 avail -= 4;
<> 149:156823d33999 279 } else if ((avail >= 2) && ((len - num) >= 2)) {
<> 149:156823d33999 280 uint16_t temp = *fifo->rslts_16;
<> 149:156823d33999 281 data[num++] = temp;
<> 149:156823d33999 282 data[num++] = temp >> 8;
<> 149:156823d33999 283 avail -= 2;
<> 149:156823d33999 284 } else {
<> 149:156823d33999 285 data[num++] = *fifo->rslts_8;
<> 149:156823d33999 286 avail--;
<> 149:156823d33999 287 }
<> 149:156823d33999 288
<> 149:156823d33999 289 // Check to see if there is more data in the FIFO
<> 149:156823d33999 290 if (avail == 0) {
<> 149:156823d33999 291 avail = ((spim->fifo_ctrl & MXC_F_SPI_FIFO_CTRL_RX_FIFO_USED) >> MXC_F_SPI_FIFO_CTRL_RX_FIFO_USED_POS);
<> 149:156823d33999 292 }
<> 149:156823d33999 293 }
<> 149:156823d33999 294
<> 149:156823d33999 295 return num;
<> 149:156823d33999 296 }
<> 149:156823d33999 297
<> 149:156823d33999 298 //******************************************************************************
<> 149:156823d33999 299 static uint32_t spi_master_transfer_handler(spi_t *obj)
<> 149:156823d33999 300 {
<> 149:156823d33999 301 uint8_t read;
<> 149:156823d33999 302 uint8_t write;
<> 149:156823d33999 303 uint16_t header;
<> 149:156823d33999 304 uint32_t pages;
<> 149:156823d33999 305 uint32_t bytes;
<> 149:156823d33999 306 uint32_t inten;
<> 149:156823d33999 307 unsigned remain;
<> 149:156823d33999 308 unsigned bytes_read;
<> 149:156823d33999 309 unsigned head_rem_temp;
<> 149:156823d33999 310 unsigned avail;
<> 149:156823d33999 311 struct spi_s *req = &obj->spi;
<> 149:156823d33999 312 mxc_spi_regs_t *spim = obj->spi.spi;
<> 149:156823d33999 313 mxc_spi_fifo_regs_t *fifo = obj->spi.fifo;
<> 149:156823d33999 314
<> 149:156823d33999 315 inten = 0;
<> 149:156823d33999 316
<> 149:156823d33999 317 // Figure out if we're reading
<> 149:156823d33999 318 read = (req->rx_data != NULL) ? 1 : 0;
<> 149:156823d33999 319
<> 149:156823d33999 320 // Figure out if we're writing
<> 149:156823d33999 321 write = (req->tx_data != NULL) ? 1 : 0;
<> 149:156823d33999 322
<> 149:156823d33999 323 // Read byte from the FIFO if we are reading
<> 149:156823d33999 324 if (read) {
<> 149:156823d33999 325
<> 149:156823d33999 326 // Read all of the data in the RXFIFO, or until we don't need anymore
<> 149:156823d33999 327 bytes_read = spi_master_read_rxfifo(spim, fifo, &req->rx_data[req->read_num], (req->len - req->read_num));
<> 149:156823d33999 328
<> 149:156823d33999 329 req->read_num += bytes_read;
<> 149:156823d33999 330
<> 149:156823d33999 331 // Adjust head_rem if we are only reading
<> 149:156823d33999 332 if (!write && (req->head_rem > 0)) {
<> 149:156823d33999 333 req->head_rem -= bytes_read;
<> 149:156823d33999 334 }
<> 149:156823d33999 335
<> 149:156823d33999 336 // Figure out how many bytes we have left to read
<> 149:156823d33999 337 if (req->head_rem > 0) {
<> 149:156823d33999 338 remain = req->head_rem;
<> 149:156823d33999 339 } else {
<> 149:156823d33999 340 remain = req->len - req->read_num;
<> 149:156823d33999 341 }
<> 149:156823d33999 342
<> 149:156823d33999 343 if (remain) {
<> 149:156823d33999 344
<> 149:156823d33999 345 // Set the RX interrupts
<> 149:156823d33999 346 if (remain > MXC_CFG_SPI_FIFO_DEPTH) {
<> 149:156823d33999 347 spim->fifo_ctrl = ((spim->fifo_ctrl & ~MXC_F_SPI_FIFO_CTRL_RX_FIFO_AF_LVL) |
<> 149:156823d33999 348 ((MXC_CFG_SPI_FIFO_DEPTH - 2) << MXC_F_SPI_FIFO_CTRL_RX_FIFO_AF_LVL_POS));
<> 149:156823d33999 349 } else {
<> 149:156823d33999 350 spim->fifo_ctrl = ((spim->fifo_ctrl & ~MXC_F_SPI_FIFO_CTRL_RX_FIFO_AF_LVL) |
<> 149:156823d33999 351 ((remain - 1) << MXC_F_SPI_FIFO_CTRL_RX_FIFO_AF_LVL_POS));
<> 149:156823d33999 352 }
<> 149:156823d33999 353
<> 149:156823d33999 354 inten |= MXC_F_SPI_INTEN_RX_FIFO_AF;
<> 149:156823d33999 355 }
<> 149:156823d33999 356 }
<> 149:156823d33999 357
<> 149:156823d33999 358 // Figure out how many bytes we have left to send headers for
<> 149:156823d33999 359 if (write) {
<> 149:156823d33999 360 remain = req->len - req->write_num;
<> 149:156823d33999 361 } else {
<> 149:156823d33999 362 remain = req->len - req->read_num;
<> 149:156823d33999 363 }
<> 149:156823d33999 364
<> 149:156823d33999 365 // See if we need to send a new header
<> 149:156823d33999 366 if ((req->head_rem <= 0) && remain) {
<> 149:156823d33999 367
<> 149:156823d33999 368 // Set the transaction configuration in the header
<> 149:156823d33999 369 header = ((write | (read << 1)) << MXC_F_SPI_FIFO_DIR_POS) | (req->width << MXC_F_SPI_FIFO_WIDTH_POS);
<> 149:156823d33999 370
<> 149:156823d33999 371 if (remain >= SPI_MAX_BYTE_LEN) {
<> 149:156823d33999 372
<> 149:156823d33999 373 // Send a 32 byte header
<> 149:156823d33999 374 if (remain == SPI_MAX_BYTE_LEN) {
<> 149:156823d33999 375
<> 149:156823d33999 376 header |= (MXC_S_SPI_FIFO_UNIT_BYTES | MXC_F_SPI_FIFO_DASS);
<> 149:156823d33999 377
<> 149:156823d33999 378 // Save the number of bytes we need to write to the FIFO
<> 149:156823d33999 379 bytes = SPI_MAX_BYTE_LEN;
<> 149:156823d33999 380
<> 149:156823d33999 381 } else {
<> 149:156823d33999 382 // Send in increments of 32 byte pages
<> 149:156823d33999 383 header |= MXC_S_SPI_FIFO_UNIT_PAGES;
<> 149:156823d33999 384 pages = remain / SPI_MAX_PAGE_LEN;
<> 149:156823d33999 385
<> 149:156823d33999 386 if (pages >= 32) {
<> 149:156823d33999 387 // 0 maps to 32 in the header
<> 149:156823d33999 388 bytes = 32 * SPI_MAX_PAGE_LEN;
<> 149:156823d33999 389 } else {
<> 149:156823d33999 390 header |= (pages << MXC_F_SPI_FIFO_SIZE_POS);
<> 149:156823d33999 391 bytes = pages * SPI_MAX_PAGE_LEN;
<> 149:156823d33999 392 }
<> 149:156823d33999 393
<> 149:156823d33999 394 // Check if this is the last header we will send
<> 149:156823d33999 395 if ((remain - bytes) == 0) {
<> 149:156823d33999 396 header |= MXC_F_SPI_FIFO_DASS;
<> 149:156823d33999 397 }
<> 149:156823d33999 398 }
<> 149:156823d33999 399
<> 149:156823d33999 400 fifo->trans_16[0] = header;
<> 149:156823d33999 401
<> 149:156823d33999 402 // Save the number of bytes we need to write to the FIFO
<> 149:156823d33999 403 req->head_rem = bytes;
<> 149:156823d33999 404
<> 149:156823d33999 405 } else {
<> 149:156823d33999 406 // Send final header with the number of bytes remaining and de-assert the SS at the end of the transaction
<> 149:156823d33999 407 header |= (MXC_S_SPI_FIFO_UNIT_BYTES | (remain << MXC_F_SPI_FIFO_SIZE_POS) | MXC_F_SPI_FIFO_DASS);
<> 149:156823d33999 408 fifo->trans_16[0] = header;
<> 149:156823d33999 409 req->head_rem = remain;
<> 149:156823d33999 410 }
<> 149:156823d33999 411 }
<> 149:156823d33999 412
<> 149:156823d33999 413 // Put data into the FIFO if we are writing
<> 149:156823d33999 414 remain = req->len - req->write_num;
<> 149:156823d33999 415 head_rem_temp = req->head_rem;
<> 149:156823d33999 416 if (write && head_rem_temp) {
<> 149:156823d33999 417
<> 149:156823d33999 418 // Fill the FIFO
<> 149:156823d33999 419 avail = (MXC_CFG_SPI_FIFO_DEPTH - ((spim->fifo_ctrl & MXC_F_SPI_FIFO_CTRL_TX_FIFO_USED) >> MXC_F_SPI_FIFO_CTRL_TX_FIFO_USED_POS));
<> 149:156823d33999 420
<> 149:156823d33999 421 // Use memcpy for everything except the last byte in odd length transactions
<> 149:156823d33999 422 while ((avail >= 2) && (head_rem_temp >= 2)) {
<> 149:156823d33999 423
<> 149:156823d33999 424 unsigned length;
<> 149:156823d33999 425 if (head_rem_temp < avail) {
<> 149:156823d33999 426 length = head_rem_temp;
<> 149:156823d33999 427 } else {
<> 149:156823d33999 428 length = avail;
<> 149:156823d33999 429 }
<> 149:156823d33999 430
<> 149:156823d33999 431 // Only memcpy even numbers
<> 149:156823d33999 432 length = ((length / 2) * 2);
<> 149:156823d33999 433
<> 149:156823d33999 434 memcpy((void*)fifo->trans_32, &(req->tx_data[req->write_num]), length);
<> 149:156823d33999 435
<> 149:156823d33999 436 head_rem_temp -= length;
<> 149:156823d33999 437 req->write_num += length;
<> 149:156823d33999 438
<> 149:156823d33999 439 avail = (MXC_CFG_SPI_FIFO_DEPTH - ((spim->fifo_ctrl & MXC_F_SPI_FIFO_CTRL_TX_FIFO_USED) >> MXC_F_SPI_FIFO_CTRL_TX_FIFO_USED_POS));
<> 149:156823d33999 440 }
<> 149:156823d33999 441
<> 149:156823d33999 442 // Copy the last byte and pad with 0xF0 to not get confused as header
<> 149:156823d33999 443 if ((avail >= 1) && (head_rem_temp == 1)) {
<> 149:156823d33999 444
<> 149:156823d33999 445 // Write the last byte
<> 149:156823d33999 446 fifo->trans_16[0] = (0xF000 | req->tx_data[req->write_num]);
<> 149:156823d33999 447
<> 149:156823d33999 448 avail -= 1;
<> 149:156823d33999 449 req->write_num += 1;
<> 149:156823d33999 450 head_rem_temp -= 1;
<> 149:156823d33999 451 }
<> 149:156823d33999 452
<> 149:156823d33999 453 req->head_rem = head_rem_temp;
<> 149:156823d33999 454 remain = req->len - req->write_num;
<> 149:156823d33999 455
<> 149:156823d33999 456 // Set the TX interrupts
<> 149:156823d33999 457 if (remain) {
<> 149:156823d33999 458
<> 149:156823d33999 459 // Set the TX FIFO almost empty interrupt if we have to refill
<> 149:156823d33999 460 spim->fifo_ctrl = ((spim->fifo_ctrl & ~MXC_F_SPI_FIFO_CTRL_TX_FIFO_AE_LVL) |
<> 149:156823d33999 461 ((MXC_CFG_SPI_FIFO_DEPTH - 2) << MXC_F_SPI_FIFO_CTRL_TX_FIFO_AE_LVL_POS));
<> 149:156823d33999 462
<> 149:156823d33999 463 inten |= MXC_F_SPI_INTEN_TX_FIFO_AE;
<> 149:156823d33999 464 }
<> 149:156823d33999 465 }
<> 149:156823d33999 466
<> 149:156823d33999 467 // Check to see if we've finished reading and writing
<> 149:156823d33999 468 if (((read && (req->read_num == req->len)) || !read) &&
<> 149:156823d33999 469 ((req->write_num == req->len) || !write)) {
<> 149:156823d33999 470
<> 149:156823d33999 471 // Disable interrupts
<> 149:156823d33999 472 spim->inten = 0;
<> 149:156823d33999 473 }
<> 149:156823d33999 474
<> 149:156823d33999 475 // Enable the SPIM interrupts
<> 149:156823d33999 476 return inten;
<> 149:156823d33999 477 }
<> 149:156823d33999 478
<> 149:156823d33999 479 //******************************************************************************
<> 149:156823d33999 480 void spi_master_transfer(spi_t *obj, const void *tx, size_t tx_length, void *rx, size_t rx_length, uint8_t bit_width, uint32_t handler, uint32_t event, DMAUsage hint)
<> 149:156823d33999 481 {
<> 149:156823d33999 482 MBED_ASSERT(tx_length == rx_length);
<> 149:156823d33999 483 MBED_ASSERT(bit_width == obj->spi.bits);
<> 149:156823d33999 484
<> 149:156823d33999 485 // Save object reference for callback
<> 149:156823d33999 486 state[obj->spi.index] = &obj->spi;
<> 149:156823d33999 487
<> 149:156823d33999 488 // Initialize request info
<> 149:156823d33999 489 obj->spi.tx_data = tx;
<> 149:156823d33999 490 obj->spi.rx_data = rx;
<> 149:156823d33999 491 obj->spi.len = tx_length;
<> 149:156823d33999 492 obj->spi.callback = (void(*)())handler;
<> 149:156823d33999 493 obj->spi.event = event;
<> 149:156823d33999 494 // Clear transfer state
<> 149:156823d33999 495 obj->spi.read_num = 0;
<> 149:156823d33999 496 obj->spi.write_num = 0;
<> 149:156823d33999 497 obj->spi.head_rem = 0;
<> 149:156823d33999 498
<> 149:156823d33999 499 NVIC_EnableIRQ(MXC_SPI_GET_IRQ(obj->spi.index));
<> 149:156823d33999 500
<> 149:156823d33999 501 obj->spi.spi->inten = spi_master_transfer_handler(obj);
<> 149:156823d33999 502 }
<> 149:156823d33999 503
<> 149:156823d33999 504 //******************************************************************************
<> 149:156823d33999 505 uint32_t spi_irq_handler_asynch(spi_t *obj)
<> 149:156823d33999 506 {
<> 149:156823d33999 507 mxc_spi_regs_t *spim = obj->spi.spi;
<> 149:156823d33999 508 uint32_t flags;
<> 149:156823d33999 509
<> 149:156823d33999 510 // Clear the interrupt flags
<> 149:156823d33999 511 spim->inten = 0;
<> 149:156823d33999 512 flags = spim->intfl;
<> 149:156823d33999 513 spim->intfl = flags;
<> 149:156823d33999 514
<> 149:156823d33999 515 // Figure out if this SPIM has an active request
<> 149:156823d33999 516 if (flags) {
<> 149:156823d33999 517 if ((spim->inten = spi_master_transfer_handler(obj)) != 0) {
<> 149:156823d33999 518 return 0;
<> 149:156823d33999 519 }
<> 149:156823d33999 520 }
<> 149:156823d33999 521
<> 149:156823d33999 522 state[obj->spi.index] = NULL;
<> 149:156823d33999 523
<> 149:156823d33999 524 return SPI_EVENT_COMPLETE;
<> 149:156823d33999 525 }
<> 149:156823d33999 526
<> 149:156823d33999 527 //******************************************************************************
<> 149:156823d33999 528 uint8_t spi_active(spi_t *obj)
<> 149:156823d33999 529 {
<> 149:156823d33999 530 mxc_spi_regs_t *spim = obj->spi.spi;
<> 149:156823d33999 531
<> 149:156823d33999 532 // Check to see if there are any ongoing transactions
<> 149:156823d33999 533 if ((state[obj->spi.index] == NULL) &&
<> 149:156823d33999 534 !(spim->fifo_ctrl & MXC_F_SPI_FIFO_CTRL_TX_FIFO_USED)) {
<> 149:156823d33999 535 return 0;
<> 149:156823d33999 536 }
<> 149:156823d33999 537
<> 149:156823d33999 538 return 1;
<> 149:156823d33999 539 }
<> 149:156823d33999 540
<> 149:156823d33999 541 //******************************************************************************
<> 149:156823d33999 542 void spi_abort_asynch(spi_t *obj)
<> 149:156823d33999 543 {
<> 149:156823d33999 544 mxc_spi_regs_t *spim = obj->spi.spi;
<> 149:156823d33999 545
<> 149:156823d33999 546 // Disable interrupts, clear the flags
<> 149:156823d33999 547 spim->inten = 0;
<> 149:156823d33999 548 spim->intfl = spim->intfl;
<> 149:156823d33999 549
<> 149:156823d33999 550 // Reset the SPIM to cancel the on ongoing transaction
<> 149:156823d33999 551 spim->gen_ctrl &= ~(MXC_F_SPI_GEN_CTRL_SPI_MSTR_EN);
<> 149:156823d33999 552 spim->gen_ctrl |= (MXC_F_SPI_GEN_CTRL_SPI_MSTR_EN);
<> 149:156823d33999 553
<> 149:156823d33999 554 state[obj->spi.index] = NULL;
<> 149:156823d33999 555 }
<> 149:156823d33999 556
<> 149:156823d33999 557 //******************************************************************************
<> 149:156823d33999 558 static void SPI_IRQHandler(int spim_num)
<> 149:156823d33999 559 {
<> 149:156823d33999 560 if (state[spim_num] != NULL) {
<> 149:156823d33999 561 if (state[spim_num]->callback != NULL) {
<> 149:156823d33999 562 state[spim_num]->callback();
<> 149:156823d33999 563 return;
<> 149:156823d33999 564 }
<> 149:156823d33999 565 }
<> 149:156823d33999 566 mxc_spi_regs_t *spim = MXC_SPI_GET_SPI(spim_num);
<> 149:156823d33999 567 spim->inten = 0;
<> 149:156823d33999 568 }
<> 149:156823d33999 569
<> 149:156823d33999 570 //******************************************************************************
<> 149:156823d33999 571 void SPI0_IRQHandler(void) { SPI_IRQHandler(0); }
<> 149:156823d33999 572 void SPI1_IRQHandler(void) { SPI_IRQHandler(1); }
<> 149:156823d33999 573 void SPI2_IRQHandler(void) { SPI_IRQHandler(2); }
<> 149:156823d33999 574
<> 149:156823d33999 575 #endif