mbed library sources. Supersedes mbed-src.

Dependents:   Nucleo_Hello_Encoder BLE_iBeaconScan AM1805_DEMO DISCO-F429ZI_ExportTemplate1 ... more

Committer:
AnnaBridge
Date:
Wed Feb 20 22:31:08 2019 +0000
Revision:
189:f392fc9709a3
Parent:
186:707f6e361f3e
mbed library release version 165

Who changed what in which revision?

UserRevisionLine numberNew contents of line
AnnaBridge 172:7d866c31b3c5 1 /* mbed Microcontroller Library
AnnaBridge 172:7d866c31b3c5 2 * Copyright (c) 2015-2016 Nuvoton
AnnaBridge 172:7d866c31b3c5 3 *
AnnaBridge 172:7d866c31b3c5 4 * Licensed under the Apache License, Version 2.0 (the "License");
AnnaBridge 172:7d866c31b3c5 5 * you may not use this file except in compliance with the License.
AnnaBridge 172:7d866c31b3c5 6 * You may obtain a copy of the License at
AnnaBridge 172:7d866c31b3c5 7 *
AnnaBridge 172:7d866c31b3c5 8 * http://www.apache.org/licenses/LICENSE-2.0
AnnaBridge 172:7d866c31b3c5 9 *
AnnaBridge 172:7d866c31b3c5 10 * Unless required by applicable law or agreed to in writing, software
AnnaBridge 172:7d866c31b3c5 11 * distributed under the License is distributed on an "AS IS" BASIS,
AnnaBridge 172:7d866c31b3c5 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
AnnaBridge 172:7d866c31b3c5 13 * See the License for the specific language governing permissions and
AnnaBridge 172:7d866c31b3c5 14 * limitations under the License.
AnnaBridge 172:7d866c31b3c5 15 */
AnnaBridge 172:7d866c31b3c5 16
AnnaBridge 172:7d866c31b3c5 17 #include "spi_api.h"
AnnaBridge 172:7d866c31b3c5 18
AnnaBridge 172:7d866c31b3c5 19 #if DEVICE_SPI
AnnaBridge 172:7d866c31b3c5 20
AnnaBridge 172:7d866c31b3c5 21 #include "cmsis.h"
AnnaBridge 172:7d866c31b3c5 22 #include "pinmap.h"
AnnaBridge 172:7d866c31b3c5 23 #include "PeripheralPins.h"
AnnaBridge 172:7d866c31b3c5 24 #include "nu_modutil.h"
AnnaBridge 172:7d866c31b3c5 25 #include "nu_miscutil.h"
AnnaBridge 172:7d866c31b3c5 26 #include "nu_bitutil.h"
AnnaBridge 172:7d866c31b3c5 27
AnnaBridge 172:7d866c31b3c5 28 #if DEVICE_SPI_ASYNCH
AnnaBridge 172:7d866c31b3c5 29 #include "dma_api.h"
AnnaBridge 172:7d866c31b3c5 30 #include "dma.h"
AnnaBridge 172:7d866c31b3c5 31 #endif
AnnaBridge 172:7d866c31b3c5 32
AnnaBridge 172:7d866c31b3c5 33 #define NU_SPI_FRAME_MIN 8
AnnaBridge 172:7d866c31b3c5 34 #define NU_SPI_FRAME_MAX 32
AnnaBridge 172:7d866c31b3c5 35
AnnaBridge 172:7d866c31b3c5 36 struct nu_spi_var {
AnnaBridge 172:7d866c31b3c5 37 #if DEVICE_SPI_ASYNCH
AnnaBridge 172:7d866c31b3c5 38 uint8_t pdma_perp_tx;
AnnaBridge 172:7d866c31b3c5 39 uint8_t pdma_perp_rx;
AnnaBridge 172:7d866c31b3c5 40 #endif
AnnaBridge 172:7d866c31b3c5 41 };
AnnaBridge 172:7d866c31b3c5 42
AnnaBridge 172:7d866c31b3c5 43 static struct nu_spi_var spi0_var = {
AnnaBridge 172:7d866c31b3c5 44 #if DEVICE_SPI_ASYNCH
AnnaBridge 172:7d866c31b3c5 45 .pdma_perp_tx = PDMA_SPI0_TX,
AnnaBridge 172:7d866c31b3c5 46 .pdma_perp_rx = PDMA_SPI0_RX
AnnaBridge 172:7d866c31b3c5 47 #endif
AnnaBridge 172:7d866c31b3c5 48 };
AnnaBridge 172:7d866c31b3c5 49 static struct nu_spi_var spi1_var = {
AnnaBridge 172:7d866c31b3c5 50 #if DEVICE_SPI_ASYNCH
AnnaBridge 172:7d866c31b3c5 51 .pdma_perp_tx = PDMA_SPI1_TX,
AnnaBridge 172:7d866c31b3c5 52 .pdma_perp_rx = PDMA_SPI1_RX
AnnaBridge 172:7d866c31b3c5 53 #endif
AnnaBridge 172:7d866c31b3c5 54 };
AnnaBridge 172:7d866c31b3c5 55 static struct nu_spi_var spi2_var = {
AnnaBridge 172:7d866c31b3c5 56 #if DEVICE_SPI_ASYNCH
AnnaBridge 172:7d866c31b3c5 57 .pdma_perp_tx = PDMA_SPI2_TX,
AnnaBridge 172:7d866c31b3c5 58 .pdma_perp_rx = PDMA_SPI2_RX
AnnaBridge 172:7d866c31b3c5 59 #endif
AnnaBridge 172:7d866c31b3c5 60 };
AnnaBridge 172:7d866c31b3c5 61 static struct nu_spi_var spi3_var = {
AnnaBridge 172:7d866c31b3c5 62 #if DEVICE_SPI_ASYNCH
AnnaBridge 172:7d866c31b3c5 63 .pdma_perp_tx = PDMA_SPI3_TX,
AnnaBridge 172:7d866c31b3c5 64 .pdma_perp_rx = PDMA_SPI3_RX
AnnaBridge 172:7d866c31b3c5 65 #endif
AnnaBridge 172:7d866c31b3c5 66 };
AnnaBridge 172:7d866c31b3c5 67 static struct nu_spi_var spi4_var = {
AnnaBridge 172:7d866c31b3c5 68 #if DEVICE_SPI_ASYNCH
AnnaBridge 172:7d866c31b3c5 69 .pdma_perp_tx = PDMA_SPI4_TX,
AnnaBridge 172:7d866c31b3c5 70 .pdma_perp_rx = PDMA_SPI4_RX
AnnaBridge 172:7d866c31b3c5 71 #endif
AnnaBridge 172:7d866c31b3c5 72 };
AnnaBridge 172:7d866c31b3c5 73
Anna Bridge 186:707f6e361f3e 74 /* Synchronous version of SPI_ENABLE()/SPI_DISABLE() macros
Anna Bridge 186:707f6e361f3e 75 *
Anna Bridge 186:707f6e361f3e 76 * The SPI peripheral clock is asynchronous with the system clock. In order to make sure the SPI
Anna Bridge 186:707f6e361f3e 77 * control logic is enabled/disabled, this bit indicates the real status of SPI controller.
Anna Bridge 186:707f6e361f3e 78 *
Anna Bridge 186:707f6e361f3e 79 * NOTE: All configurations shall be ready before calling SPI_ENABLE_SYNC().
Anna Bridge 186:707f6e361f3e 80 * NOTE: Before changing the configurations of SPIx_CTL, SPIx_CLKDIV, SPIx_SSCTL and SPIx_FIFOCTL registers,
Anna Bridge 186:707f6e361f3e 81 * user shall clear the SPIEN (SPIx_CTL[0]) and confirm the SPIENSTS (SPIx_STATUS[15]) is 0
Anna Bridge 186:707f6e361f3e 82 * (by SPI_DISABLE_SYNC here).
Anna Bridge 186:707f6e361f3e 83 */
Anna Bridge 186:707f6e361f3e 84 __STATIC_INLINE void SPI_ENABLE_SYNC(SPI_T *spi_base)
Anna Bridge 186:707f6e361f3e 85 {
Anna Bridge 186:707f6e361f3e 86 if (! (spi_base->CTL & SPI_CTL_SPIEN_Msk)) {
Anna Bridge 186:707f6e361f3e 87 SPI_ENABLE(spi_base);
Anna Bridge 186:707f6e361f3e 88 }
Anna Bridge 186:707f6e361f3e 89 while (! (spi_base->STATUS & SPI_STATUS_SPIENSTS_Msk));
Anna Bridge 186:707f6e361f3e 90 }
Anna Bridge 186:707f6e361f3e 91 __STATIC_INLINE void SPI_DISABLE_SYNC(SPI_T *spi_base)
Anna Bridge 186:707f6e361f3e 92 {
Anna Bridge 186:707f6e361f3e 93 if (spi_base->CTL & SPI_CTL_SPIEN_Msk) {
Anna Bridge 186:707f6e361f3e 94 // NOTE: SPI H/W may get out of state without the busy check.
Anna Bridge 186:707f6e361f3e 95 while (SPI_IS_BUSY(spi_base));
Anna Bridge 186:707f6e361f3e 96
Anna Bridge 186:707f6e361f3e 97 SPI_DISABLE(spi_base);
Anna Bridge 186:707f6e361f3e 98 }
Anna Bridge 186:707f6e361f3e 99 while (spi_base->STATUS & SPI_STATUS_SPIENSTS_Msk);
Anna Bridge 186:707f6e361f3e 100 }
Anna Bridge 186:707f6e361f3e 101
AnnaBridge 172:7d866c31b3c5 102 #if DEVICE_SPI_ASYNCH
AnnaBridge 172:7d866c31b3c5 103 static void spi_enable_vector_interrupt(spi_t *obj, uint32_t handler, uint8_t enable);
AnnaBridge 172:7d866c31b3c5 104 static void spi_master_enable_interrupt(spi_t *obj, uint8_t enable);
AnnaBridge 172:7d866c31b3c5 105 static uint32_t spi_master_write_asynch(spi_t *obj, uint32_t tx_limit);
AnnaBridge 172:7d866c31b3c5 106 static uint32_t spi_master_read_asynch(spi_t *obj);
AnnaBridge 172:7d866c31b3c5 107 static uint32_t spi_event_check(spi_t *obj);
AnnaBridge 172:7d866c31b3c5 108 static void spi_enable_event(spi_t *obj, uint32_t event, uint8_t enable);
AnnaBridge 172:7d866c31b3c5 109 static void spi_buffer_set(spi_t *obj, const void *tx, size_t tx_length, void *rx, size_t rx_length);
AnnaBridge 172:7d866c31b3c5 110 static void spi_check_dma_usage(DMAUsage *dma_usage, int *dma_ch_tx, int *dma_ch_rx);
AnnaBridge 172:7d866c31b3c5 111 static uint8_t spi_get_data_width(spi_t *obj);
AnnaBridge 172:7d866c31b3c5 112 static int spi_is_tx_complete(spi_t *obj);
AnnaBridge 172:7d866c31b3c5 113 static int spi_is_rx_complete(spi_t *obj);
AnnaBridge 172:7d866c31b3c5 114 static int spi_writeable(spi_t * obj);
AnnaBridge 172:7d866c31b3c5 115 static int spi_readable(spi_t * obj);
AnnaBridge 172:7d866c31b3c5 116 static void spi_dma_handler_tx(uint32_t id, uint32_t event_dma);
AnnaBridge 172:7d866c31b3c5 117 static void spi_dma_handler_rx(uint32_t id, uint32_t event_dma);
AnnaBridge 172:7d866c31b3c5 118 static uint32_t spi_fifo_depth(spi_t *obj);
AnnaBridge 172:7d866c31b3c5 119 #endif
AnnaBridge 172:7d866c31b3c5 120
AnnaBridge 172:7d866c31b3c5 121 static uint32_t spi_modinit_mask = 0;
AnnaBridge 172:7d866c31b3c5 122
AnnaBridge 172:7d866c31b3c5 123 static const struct nu_modinit_s spi_modinit_tab[] = {
AnnaBridge 172:7d866c31b3c5 124 {SPI_0, SPI0_MODULE, CLK_CLKSEL2_SPI0SEL_PCLK0, MODULE_NoMsk, SPI0_RST, SPI0_IRQn, &spi0_var},
AnnaBridge 172:7d866c31b3c5 125 {SPI_1, SPI1_MODULE, CLK_CLKSEL2_SPI1SEL_PCLK1, MODULE_NoMsk, SPI1_RST, SPI1_IRQn, &spi1_var},
AnnaBridge 172:7d866c31b3c5 126 {SPI_2, SPI2_MODULE, CLK_CLKSEL2_SPI2SEL_PCLK0, MODULE_NoMsk, SPI2_RST, SPI2_IRQn, &spi2_var},
AnnaBridge 172:7d866c31b3c5 127 {SPI_3, SPI3_MODULE, CLK_CLKSEL2_SPI3SEL_PCLK1, MODULE_NoMsk, SPI3_RST, SPI3_IRQn, &spi3_var},
AnnaBridge 172:7d866c31b3c5 128 {SPI_4, SPI4_MODULE, CLK_CLKSEL2_SPI4SEL_PCLK0, MODULE_NoMsk, SPI4_RST, SPI4_IRQn, &spi4_var},
AnnaBridge 172:7d866c31b3c5 129
AnnaBridge 172:7d866c31b3c5 130 {NC, 0, 0, 0, 0, (IRQn_Type) 0, NULL}
AnnaBridge 172:7d866c31b3c5 131 };
AnnaBridge 172:7d866c31b3c5 132
AnnaBridge 172:7d866c31b3c5 133 void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel)
AnnaBridge 172:7d866c31b3c5 134 {
AnnaBridge 172:7d866c31b3c5 135 // Determine which SPI_x the pins are used for
AnnaBridge 172:7d866c31b3c5 136 uint32_t spi_mosi = pinmap_peripheral(mosi, PinMap_SPI_MOSI);
AnnaBridge 172:7d866c31b3c5 137 uint32_t spi_miso = pinmap_peripheral(miso, PinMap_SPI_MISO);
AnnaBridge 172:7d866c31b3c5 138 uint32_t spi_sclk = pinmap_peripheral(sclk, PinMap_SPI_SCLK);
AnnaBridge 172:7d866c31b3c5 139 uint32_t spi_ssel = pinmap_peripheral(ssel, PinMap_SPI_SSEL);
AnnaBridge 172:7d866c31b3c5 140 uint32_t spi_data = pinmap_merge(spi_mosi, spi_miso);
AnnaBridge 172:7d866c31b3c5 141 uint32_t spi_cntl = pinmap_merge(spi_sclk, spi_ssel);
AnnaBridge 172:7d866c31b3c5 142 obj->spi.spi = (SPIName) pinmap_merge(spi_data, spi_cntl);
AnnaBridge 172:7d866c31b3c5 143 MBED_ASSERT((int)obj->spi.spi != NC);
AnnaBridge 172:7d866c31b3c5 144
AnnaBridge 172:7d866c31b3c5 145 const struct nu_modinit_s *modinit = get_modinit(obj->spi.spi, spi_modinit_tab);
AnnaBridge 172:7d866c31b3c5 146 MBED_ASSERT(modinit != NULL);
AnnaBridge 172:7d866c31b3c5 147 MBED_ASSERT(modinit->modname == (int) obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 148
AnnaBridge 172:7d866c31b3c5 149 // Reset this module
AnnaBridge 172:7d866c31b3c5 150 SYS_ResetModule(modinit->rsetidx);
AnnaBridge 172:7d866c31b3c5 151
AnnaBridge 172:7d866c31b3c5 152 // Select IP clock source
AnnaBridge 172:7d866c31b3c5 153 CLK_SetModuleClock(modinit->clkidx, modinit->clksrc, modinit->clkdiv);
AnnaBridge 172:7d866c31b3c5 154 // Enable IP clock
AnnaBridge 172:7d866c31b3c5 155 CLK_EnableModuleClock(modinit->clkidx);
AnnaBridge 172:7d866c31b3c5 156
AnnaBridge 172:7d866c31b3c5 157 pinmap_pinout(mosi, PinMap_SPI_MOSI);
AnnaBridge 172:7d866c31b3c5 158 pinmap_pinout(miso, PinMap_SPI_MISO);
AnnaBridge 172:7d866c31b3c5 159 pinmap_pinout(sclk, PinMap_SPI_SCLK);
AnnaBridge 172:7d866c31b3c5 160 pinmap_pinout(ssel, PinMap_SPI_SSEL);
AnnaBridge 172:7d866c31b3c5 161
AnnaBridge 172:7d866c31b3c5 162 obj->spi.pin_mosi = mosi;
AnnaBridge 172:7d866c31b3c5 163 obj->spi.pin_miso = miso;
AnnaBridge 172:7d866c31b3c5 164 obj->spi.pin_sclk = sclk;
AnnaBridge 172:7d866c31b3c5 165 obj->spi.pin_ssel = ssel;
AnnaBridge 172:7d866c31b3c5 166
AnnaBridge 172:7d866c31b3c5 167
AnnaBridge 172:7d866c31b3c5 168 #if DEVICE_SPI_ASYNCH
AnnaBridge 172:7d866c31b3c5 169 obj->spi.dma_usage = DMA_USAGE_NEVER;
AnnaBridge 172:7d866c31b3c5 170 obj->spi.event = 0;
AnnaBridge 172:7d866c31b3c5 171 obj->spi.dma_chn_id_tx = DMA_ERROR_OUT_OF_CHANNELS;
AnnaBridge 172:7d866c31b3c5 172 obj->spi.dma_chn_id_rx = DMA_ERROR_OUT_OF_CHANNELS;
Anna Bridge 186:707f6e361f3e 173
Anna Bridge 186:707f6e361f3e 174 /* NOTE: We use vector to judge if asynchronous transfer is on-going (spi_active).
Anna Bridge 186:707f6e361f3e 175 * At initial time, asynchronous transfer is not on-going and so vector must
Anna Bridge 186:707f6e361f3e 176 * be cleared to zero for correct judgement. */
Anna Bridge 186:707f6e361f3e 177 NVIC_SetVector(modinit->irq_n, 0);
AnnaBridge 172:7d866c31b3c5 178 #endif
AnnaBridge 172:7d866c31b3c5 179
AnnaBridge 172:7d866c31b3c5 180 // Mark this module to be inited.
AnnaBridge 172:7d866c31b3c5 181 int i = modinit - spi_modinit_tab;
AnnaBridge 172:7d866c31b3c5 182 spi_modinit_mask |= 1 << i;
AnnaBridge 172:7d866c31b3c5 183 }
AnnaBridge 172:7d866c31b3c5 184
AnnaBridge 172:7d866c31b3c5 185 void spi_free(spi_t *obj)
AnnaBridge 172:7d866c31b3c5 186 {
AnnaBridge 172:7d866c31b3c5 187 #if DEVICE_SPI_ASYNCH
AnnaBridge 172:7d866c31b3c5 188 if (obj->spi.dma_chn_id_tx != DMA_ERROR_OUT_OF_CHANNELS) {
AnnaBridge 172:7d866c31b3c5 189 dma_channel_free(obj->spi.dma_chn_id_tx);
AnnaBridge 172:7d866c31b3c5 190 obj->spi.dma_chn_id_tx = DMA_ERROR_OUT_OF_CHANNELS;
AnnaBridge 172:7d866c31b3c5 191 }
AnnaBridge 172:7d866c31b3c5 192 if (obj->spi.dma_chn_id_rx != DMA_ERROR_OUT_OF_CHANNELS) {
AnnaBridge 172:7d866c31b3c5 193 dma_channel_free(obj->spi.dma_chn_id_rx);
AnnaBridge 172:7d866c31b3c5 194 obj->spi.dma_chn_id_rx = DMA_ERROR_OUT_OF_CHANNELS;
AnnaBridge 172:7d866c31b3c5 195 }
AnnaBridge 172:7d866c31b3c5 196 #endif
AnnaBridge 172:7d866c31b3c5 197
AnnaBridge 172:7d866c31b3c5 198 SPI_Close((SPI_T *) NU_MODBASE(obj->spi.spi));
AnnaBridge 172:7d866c31b3c5 199
AnnaBridge 172:7d866c31b3c5 200 const struct nu_modinit_s *modinit = get_modinit(obj->spi.spi, spi_modinit_tab);
AnnaBridge 172:7d866c31b3c5 201 MBED_ASSERT(modinit != NULL);
AnnaBridge 172:7d866c31b3c5 202 MBED_ASSERT(modinit->modname == (int) obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 203
AnnaBridge 172:7d866c31b3c5 204 SPI_DisableInt(((SPI_T *) NU_MODBASE(obj->spi.spi)), (SPI_FIFO_RXOV_INT_MASK | SPI_FIFO_RXTH_INT_MASK | SPI_FIFO_TXTH_INT_MASK));
AnnaBridge 172:7d866c31b3c5 205 NVIC_DisableIRQ(modinit->irq_n);
AnnaBridge 172:7d866c31b3c5 206
AnnaBridge 172:7d866c31b3c5 207 // Disable IP clock
AnnaBridge 172:7d866c31b3c5 208 CLK_DisableModuleClock(modinit->clkidx);
AnnaBridge 172:7d866c31b3c5 209
AnnaBridge 172:7d866c31b3c5 210 // Mark this module to be deinited.
AnnaBridge 172:7d866c31b3c5 211 int i = modinit - spi_modinit_tab;
AnnaBridge 172:7d866c31b3c5 212 spi_modinit_mask &= ~(1 << i);
AnnaBridge 172:7d866c31b3c5 213 }
Anna Bridge 186:707f6e361f3e 214
AnnaBridge 172:7d866c31b3c5 215 void spi_format(spi_t *obj, int bits, int mode, int slave)
AnnaBridge 172:7d866c31b3c5 216 {
AnnaBridge 172:7d866c31b3c5 217 MBED_ASSERT(bits >= NU_SPI_FRAME_MIN && bits <= NU_SPI_FRAME_MAX);
AnnaBridge 172:7d866c31b3c5 218
AnnaBridge 172:7d866c31b3c5 219 SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 220
Anna Bridge 186:707f6e361f3e 221 SPI_DISABLE_SYNC(spi_base);
AnnaBridge 172:7d866c31b3c5 222
AnnaBridge 172:7d866c31b3c5 223 SPI_Open(spi_base,
AnnaBridge 172:7d866c31b3c5 224 slave ? SPI_SLAVE : SPI_MASTER,
AnnaBridge 172:7d866c31b3c5 225 (mode == 0) ? SPI_MODE_0 : (mode == 1) ? SPI_MODE_1 : (mode == 2) ? SPI_MODE_2 : SPI_MODE_3,
AnnaBridge 172:7d866c31b3c5 226 bits,
AnnaBridge 172:7d866c31b3c5 227 SPI_GetBusClock(spi_base));
AnnaBridge 172:7d866c31b3c5 228 // NOTE: Hardcode to be MSB first.
AnnaBridge 172:7d866c31b3c5 229 SPI_SET_MSB_FIRST(spi_base);
AnnaBridge 172:7d866c31b3c5 230
AnnaBridge 172:7d866c31b3c5 231 if (! slave) {
AnnaBridge 172:7d866c31b3c5 232 // Master
AnnaBridge 172:7d866c31b3c5 233 if (obj->spi.pin_ssel != NC) {
AnnaBridge 172:7d866c31b3c5 234 // Configure SS as low active.
AnnaBridge 172:7d866c31b3c5 235 SPI_EnableAutoSS(spi_base, SPI_SS, SPI_SS_ACTIVE_LOW);
AnnaBridge 172:7d866c31b3c5 236 } else {
AnnaBridge 172:7d866c31b3c5 237 SPI_DisableAutoSS(spi_base);
AnnaBridge 172:7d866c31b3c5 238 }
AnnaBridge 172:7d866c31b3c5 239 } else {
AnnaBridge 172:7d866c31b3c5 240 // Slave
AnnaBridge 172:7d866c31b3c5 241 // Configure SS as low active.
AnnaBridge 172:7d866c31b3c5 242 spi_base->SSCTL &= ~SPI_SSCTL_SSACTPOL_Msk;
AnnaBridge 172:7d866c31b3c5 243 }
AnnaBridge 172:7d866c31b3c5 244
Anna Bridge 186:707f6e361f3e 245 /* NOTE: M451's/M480's/M2351's SPI_Open() will enable SPI transfer (SPI_CTL_SPIEN_Msk).
Anna Bridge 186:707f6e361f3e 246 * We cannot use SPI_CTL_SPIEN_Msk for judgement of spi_active().
Anna Bridge 186:707f6e361f3e 247 * Judge with vector instead. */
AnnaBridge 172:7d866c31b3c5 248 }
AnnaBridge 172:7d866c31b3c5 249
AnnaBridge 172:7d866c31b3c5 250 void spi_frequency(spi_t *obj, int hz)
AnnaBridge 172:7d866c31b3c5 251 {
AnnaBridge 172:7d866c31b3c5 252 SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 253
Anna Bridge 186:707f6e361f3e 254 SPI_DISABLE_SYNC(spi_base);
AnnaBridge 172:7d866c31b3c5 255
AnnaBridge 172:7d866c31b3c5 256 SPI_SetBusClock((SPI_T *) NU_MODBASE(obj->spi.spi), hz);
AnnaBridge 172:7d866c31b3c5 257 }
AnnaBridge 172:7d866c31b3c5 258
AnnaBridge 172:7d866c31b3c5 259
AnnaBridge 172:7d866c31b3c5 260 int spi_master_write(spi_t *obj, int value)
AnnaBridge 172:7d866c31b3c5 261 {
AnnaBridge 172:7d866c31b3c5 262 SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 263
AnnaBridge 172:7d866c31b3c5 264 // NOTE: Data in receive FIFO can be read out via ICE.
Anna Bridge 186:707f6e361f3e 265 SPI_ENABLE_SYNC(spi_base);
AnnaBridge 172:7d866c31b3c5 266
AnnaBridge 172:7d866c31b3c5 267 // Wait for tx buffer empty
AnnaBridge 172:7d866c31b3c5 268 while(! spi_writeable(obj));
AnnaBridge 172:7d866c31b3c5 269 SPI_WRITE_TX(spi_base, value);
AnnaBridge 172:7d866c31b3c5 270
AnnaBridge 172:7d866c31b3c5 271 // Wait for rx buffer full
AnnaBridge 172:7d866c31b3c5 272 while (! spi_readable(obj));
AnnaBridge 172:7d866c31b3c5 273 int value2 = SPI_READ_RX(spi_base);
AnnaBridge 172:7d866c31b3c5 274
Anna Bridge 186:707f6e361f3e 275 /* We don't call SPI_DISABLE_SYNC here for performance. */
AnnaBridge 172:7d866c31b3c5 276
AnnaBridge 172:7d866c31b3c5 277 return value2;
AnnaBridge 172:7d866c31b3c5 278 }
AnnaBridge 172:7d866c31b3c5 279
AnnaBridge 172:7d866c31b3c5 280 int spi_master_block_write(spi_t *obj, const char *tx_buffer, int tx_length,
AnnaBridge 172:7d866c31b3c5 281 char *rx_buffer, int rx_length, char write_fill) {
AnnaBridge 172:7d866c31b3c5 282 int total = (tx_length > rx_length) ? tx_length : rx_length;
AnnaBridge 172:7d866c31b3c5 283
AnnaBridge 172:7d866c31b3c5 284 for (int i = 0; i < total; i++) {
AnnaBridge 172:7d866c31b3c5 285 char out = (i < tx_length) ? tx_buffer[i] : write_fill;
AnnaBridge 172:7d866c31b3c5 286 char in = spi_master_write(obj, out);
AnnaBridge 172:7d866c31b3c5 287 if (i < rx_length) {
AnnaBridge 172:7d866c31b3c5 288 rx_buffer[i] = in;
AnnaBridge 172:7d866c31b3c5 289 }
AnnaBridge 172:7d866c31b3c5 290 }
AnnaBridge 172:7d866c31b3c5 291
AnnaBridge 172:7d866c31b3c5 292 return total;
AnnaBridge 172:7d866c31b3c5 293 }
AnnaBridge 172:7d866c31b3c5 294
AnnaBridge 172:7d866c31b3c5 295 #if DEVICE_SPISLAVE
AnnaBridge 172:7d866c31b3c5 296 int spi_slave_receive(spi_t *obj)
AnnaBridge 172:7d866c31b3c5 297 {
AnnaBridge 172:7d866c31b3c5 298 SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 299
Anna Bridge 186:707f6e361f3e 300 SPI_ENABLE_SYNC(spi_base);
AnnaBridge 172:7d866c31b3c5 301
AnnaBridge 172:7d866c31b3c5 302 return spi_readable(obj);
AnnaBridge 172:7d866c31b3c5 303 };
AnnaBridge 172:7d866c31b3c5 304
AnnaBridge 172:7d866c31b3c5 305 int spi_slave_read(spi_t *obj)
AnnaBridge 172:7d866c31b3c5 306 {
AnnaBridge 172:7d866c31b3c5 307 SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 308
Anna Bridge 186:707f6e361f3e 309 SPI_ENABLE_SYNC(spi_base);
AnnaBridge 172:7d866c31b3c5 310
AnnaBridge 172:7d866c31b3c5 311 // Wait for rx buffer full
AnnaBridge 172:7d866c31b3c5 312 while (! spi_readable(obj));
AnnaBridge 172:7d866c31b3c5 313 int value = SPI_READ_RX(spi_base);
AnnaBridge 172:7d866c31b3c5 314 return value;
AnnaBridge 172:7d866c31b3c5 315 }
AnnaBridge 172:7d866c31b3c5 316
AnnaBridge 172:7d866c31b3c5 317 void spi_slave_write(spi_t *obj, int value)
AnnaBridge 172:7d866c31b3c5 318 {
AnnaBridge 172:7d866c31b3c5 319 SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 320
Anna Bridge 186:707f6e361f3e 321 SPI_ENABLE_SYNC(spi_base);
AnnaBridge 172:7d866c31b3c5 322
AnnaBridge 172:7d866c31b3c5 323 // Wait for tx buffer empty
AnnaBridge 172:7d866c31b3c5 324 while(! spi_writeable(obj));
AnnaBridge 172:7d866c31b3c5 325 SPI_WRITE_TX(spi_base, value);
AnnaBridge 172:7d866c31b3c5 326 }
AnnaBridge 172:7d866c31b3c5 327 #endif
AnnaBridge 172:7d866c31b3c5 328
AnnaBridge 172:7d866c31b3c5 329 #if DEVICE_SPI_ASYNCH
AnnaBridge 172:7d866c31b3c5 330 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)
AnnaBridge 172:7d866c31b3c5 331 {
AnnaBridge 172:7d866c31b3c5 332 SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 333 SPI_SET_DATA_WIDTH(spi_base, bit_width);
AnnaBridge 172:7d866c31b3c5 334
AnnaBridge 172:7d866c31b3c5 335 obj->spi.dma_usage = hint;
AnnaBridge 172:7d866c31b3c5 336 spi_check_dma_usage(&obj->spi.dma_usage, &obj->spi.dma_chn_id_tx, &obj->spi.dma_chn_id_rx);
AnnaBridge 172:7d866c31b3c5 337 uint32_t data_width = spi_get_data_width(obj);
AnnaBridge 172:7d866c31b3c5 338 // Conditions to go DMA way:
AnnaBridge 172:7d866c31b3c5 339 // (1) No DMA support for non-8 multiple data width.
AnnaBridge 172:7d866c31b3c5 340 // (2) tx length >= rx length. Otherwise, as tx DMA is done, no bus activity for remaining rx.
AnnaBridge 172:7d866c31b3c5 341 if ((data_width % 8) ||
AnnaBridge 172:7d866c31b3c5 342 (tx_length < rx_length)) {
AnnaBridge 172:7d866c31b3c5 343 obj->spi.dma_usage = DMA_USAGE_NEVER;
AnnaBridge 172:7d866c31b3c5 344 dma_channel_free(obj->spi.dma_chn_id_tx);
AnnaBridge 172:7d866c31b3c5 345 obj->spi.dma_chn_id_tx = DMA_ERROR_OUT_OF_CHANNELS;
AnnaBridge 172:7d866c31b3c5 346 dma_channel_free(obj->spi.dma_chn_id_rx);
AnnaBridge 172:7d866c31b3c5 347 obj->spi.dma_chn_id_rx = DMA_ERROR_OUT_OF_CHANNELS;
AnnaBridge 172:7d866c31b3c5 348 }
AnnaBridge 172:7d866c31b3c5 349
AnnaBridge 172:7d866c31b3c5 350 // SPI IRQ is necessary for both interrupt way and DMA way
AnnaBridge 172:7d866c31b3c5 351 spi_enable_event(obj, event, 1);
AnnaBridge 172:7d866c31b3c5 352 spi_buffer_set(obj, tx, tx_length, rx, rx_length);
AnnaBridge 172:7d866c31b3c5 353
Anna Bridge 186:707f6e361f3e 354 SPI_ENABLE_SYNC(spi_base);
AnnaBridge 172:7d866c31b3c5 355
AnnaBridge 172:7d866c31b3c5 356 if (obj->spi.dma_usage == DMA_USAGE_NEVER) {
AnnaBridge 172:7d866c31b3c5 357 // Interrupt way
AnnaBridge 172:7d866c31b3c5 358 spi_master_write_asynch(obj, spi_fifo_depth(obj) / 2);
AnnaBridge 172:7d866c31b3c5 359 spi_enable_vector_interrupt(obj, handler, 1);
AnnaBridge 172:7d866c31b3c5 360 spi_master_enable_interrupt(obj, 1);
AnnaBridge 172:7d866c31b3c5 361 } else {
AnnaBridge 172:7d866c31b3c5 362 // DMA way
AnnaBridge 172:7d866c31b3c5 363 const struct nu_modinit_s *modinit = get_modinit(obj->spi.spi, spi_modinit_tab);
AnnaBridge 172:7d866c31b3c5 364 MBED_ASSERT(modinit != NULL);
AnnaBridge 172:7d866c31b3c5 365 MBED_ASSERT(modinit->modname == (int) obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 366
AnnaBridge 172:7d866c31b3c5 367 PDMA_T *pdma_base = dma_modbase();
AnnaBridge 172:7d866c31b3c5 368
AnnaBridge 172:7d866c31b3c5 369 // Configure tx DMA
AnnaBridge 172:7d866c31b3c5 370 pdma_base->CHCTL |= 1 << obj->spi.dma_chn_id_tx; // Enable this DMA channel
AnnaBridge 172:7d866c31b3c5 371 PDMA_SetTransferMode(obj->spi.dma_chn_id_tx,
AnnaBridge 172:7d866c31b3c5 372 ((struct nu_spi_var *) modinit->var)->pdma_perp_tx, // Peripheral connected to this PDMA
AnnaBridge 172:7d866c31b3c5 373 0, // Scatter-gather disabled
AnnaBridge 172:7d866c31b3c5 374 0); // Scatter-gather descriptor address
AnnaBridge 172:7d866c31b3c5 375 PDMA_SetTransferCnt(obj->spi.dma_chn_id_tx,
AnnaBridge 172:7d866c31b3c5 376 (data_width == 8) ? PDMA_WIDTH_8 : (data_width == 16) ? PDMA_WIDTH_16 : PDMA_WIDTH_32,
AnnaBridge 172:7d866c31b3c5 377 tx_length);
AnnaBridge 172:7d866c31b3c5 378 PDMA_SetTransferAddr(obj->spi.dma_chn_id_tx,
AnnaBridge 172:7d866c31b3c5 379 (uint32_t) tx, // NOTE:
AnnaBridge 172:7d866c31b3c5 380 // NUC472: End of source address
AnnaBridge 172:7d866c31b3c5 381 // M451/M480: Start of source address
AnnaBridge 172:7d866c31b3c5 382 PDMA_SAR_INC, // Source address incremental
AnnaBridge 172:7d866c31b3c5 383 (uint32_t) &spi_base->TX, // Destination address
AnnaBridge 172:7d866c31b3c5 384 PDMA_DAR_FIX); // Destination address fixed
AnnaBridge 172:7d866c31b3c5 385 PDMA_SetBurstType(obj->spi.dma_chn_id_tx,
AnnaBridge 172:7d866c31b3c5 386 PDMA_REQ_SINGLE, // Single mode
AnnaBridge 172:7d866c31b3c5 387 0); // Burst size
AnnaBridge 172:7d866c31b3c5 388 PDMA_EnableInt(obj->spi.dma_chn_id_tx,
AnnaBridge 172:7d866c31b3c5 389 PDMA_INT_TRANS_DONE); // Interrupt type
AnnaBridge 172:7d866c31b3c5 390 // Register DMA event handler
AnnaBridge 172:7d866c31b3c5 391 dma_set_handler(obj->spi.dma_chn_id_tx, (uint32_t) spi_dma_handler_tx, (uint32_t) obj, DMA_EVENT_ALL);
AnnaBridge 172:7d866c31b3c5 392
AnnaBridge 172:7d866c31b3c5 393 // Configure rx DMA
AnnaBridge 172:7d866c31b3c5 394 pdma_base->CHCTL |= 1 << obj->spi.dma_chn_id_rx; // Enable this DMA channel
AnnaBridge 172:7d866c31b3c5 395 PDMA_SetTransferMode(obj->spi.dma_chn_id_rx,
AnnaBridge 172:7d866c31b3c5 396 ((struct nu_spi_var *) modinit->var)->pdma_perp_rx, // Peripheral connected to this PDMA
AnnaBridge 172:7d866c31b3c5 397 0, // Scatter-gather disabled
AnnaBridge 172:7d866c31b3c5 398 0); // Scatter-gather descriptor address
AnnaBridge 172:7d866c31b3c5 399 PDMA_SetTransferCnt(obj->spi.dma_chn_id_rx,
AnnaBridge 172:7d866c31b3c5 400 (data_width == 8) ? PDMA_WIDTH_8 : (data_width == 16) ? PDMA_WIDTH_16 : PDMA_WIDTH_32,
AnnaBridge 172:7d866c31b3c5 401 rx_length);
AnnaBridge 172:7d866c31b3c5 402 PDMA_SetTransferAddr(obj->spi.dma_chn_id_rx,
AnnaBridge 172:7d866c31b3c5 403 (uint32_t) &spi_base->RX, // Source address
AnnaBridge 172:7d866c31b3c5 404 PDMA_SAR_FIX, // Source address fixed
AnnaBridge 172:7d866c31b3c5 405 (uint32_t) rx, // NOTE:
AnnaBridge 172:7d866c31b3c5 406 // NUC472: End of destination address
AnnaBridge 172:7d866c31b3c5 407 // M451/M480: Start of destination address
AnnaBridge 172:7d866c31b3c5 408 PDMA_DAR_INC); // Destination address incremental
AnnaBridge 172:7d866c31b3c5 409 PDMA_SetBurstType(obj->spi.dma_chn_id_rx,
AnnaBridge 172:7d866c31b3c5 410 PDMA_REQ_SINGLE, // Single mode
AnnaBridge 172:7d866c31b3c5 411 0); // Burst size
AnnaBridge 172:7d866c31b3c5 412 PDMA_EnableInt(obj->spi.dma_chn_id_rx,
AnnaBridge 172:7d866c31b3c5 413 PDMA_INT_TRANS_DONE); // Interrupt type
AnnaBridge 172:7d866c31b3c5 414 // Register DMA event handler
AnnaBridge 172:7d866c31b3c5 415 dma_set_handler(obj->spi.dma_chn_id_rx, (uint32_t) spi_dma_handler_rx, (uint32_t) obj, DMA_EVENT_ALL);
AnnaBridge 172:7d866c31b3c5 416
Anna Bridge 186:707f6e361f3e 417 /* Start tx/rx DMA transfer
Anna Bridge 186:707f6e361f3e 418 *
Anna Bridge 186:707f6e361f3e 419 * If we have both PDMA and SPI interrupts enabled and PDMA priority is lower than SPI priority,
Anna Bridge 186:707f6e361f3e 420 * we would trap in SPI interrupt handler endlessly with the sequence:
Anna Bridge 186:707f6e361f3e 421 *
Anna Bridge 186:707f6e361f3e 422 * 1. PDMA TX transfer done interrupt occurs and is well handled.
Anna Bridge 186:707f6e361f3e 423 * 2. SPI RX FIFO threshold interrupt occurs. Trap here because PDMA RX transfer done interrupt doesn't get handled.
Anna Bridge 186:707f6e361f3e 424 * 3. PDMA RX transfer done interrupt occurs but it cannot be handled due to above.
Anna Bridge 186:707f6e361f3e 425 *
Anna Bridge 186:707f6e361f3e 426 * To fix it, we don't enable SPI TX/RX threshold interrupts but keep SPI vector handler set to be called
Anna Bridge 186:707f6e361f3e 427 * in PDMA TX/RX transfer done interrupt handlers (spi_dma_handler_tx/spi_dma_handler_rx).
Anna Bridge 186:707f6e361f3e 428 */
Anna Bridge 186:707f6e361f3e 429 NVIC_SetVector(modinit->irq_n, handler);
Anna Bridge 186:707f6e361f3e 430
Anna Bridge 186:707f6e361f3e 431 /* Order to enable PDMA TX/RX functions
Anna Bridge 186:707f6e361f3e 432 *
Anna Bridge 186:707f6e361f3e 433 * H/W spec: In SPI Master mode with full duplex transfer, if both TX and RX PDMA functions are
Anna Bridge 186:707f6e361f3e 434 * enabled, RX PDMA function cannot be enabled prior to TX PDMA function. User can enable
Anna Bridge 186:707f6e361f3e 435 * TX PDMA function firstly or enable both functions simultaneously.
Anna Bridge 186:707f6e361f3e 436 * Per real test, it is safer to start RX PDMA first and then TX PDMA. Otherwise, receive FIFO is
Anna Bridge 186:707f6e361f3e 437 * subject to overflow by TX DMA.
Anna Bridge 186:707f6e361f3e 438 *
Anna Bridge 186:707f6e361f3e 439 * With the above conflicts, we enable PDMA TX/RX functions simultaneously.
Anna Bridge 186:707f6e361f3e 440 */
Anna Bridge 186:707f6e361f3e 441 spi_base->PDMACTL |= (SPI_PDMACTL_TXPDMAEN_Msk | SPI_PDMACTL_RXPDMAEN_Msk);
Anna Bridge 186:707f6e361f3e 442
Anna Bridge 186:707f6e361f3e 443 /* Don't enable SPI TX/RX threshold interrupts as commented above */
AnnaBridge 172:7d866c31b3c5 444 }
AnnaBridge 172:7d866c31b3c5 445 }
AnnaBridge 172:7d866c31b3c5 446
AnnaBridge 172:7d866c31b3c5 447 /**
AnnaBridge 172:7d866c31b3c5 448 * Abort an SPI transfer
AnnaBridge 172:7d866c31b3c5 449 * This is a helper function for event handling. When any of the events listed occurs, the HAL will abort any ongoing
AnnaBridge 172:7d866c31b3c5 450 * transfers
AnnaBridge 172:7d866c31b3c5 451 * @param[in] obj The SPI peripheral to stop
AnnaBridge 172:7d866c31b3c5 452 */
AnnaBridge 172:7d866c31b3c5 453 void spi_abort_asynch(spi_t *obj)
AnnaBridge 172:7d866c31b3c5 454 {
AnnaBridge 172:7d866c31b3c5 455 SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 456 PDMA_T *pdma_base = dma_modbase();
AnnaBridge 172:7d866c31b3c5 457
AnnaBridge 172:7d866c31b3c5 458 if (obj->spi.dma_usage != DMA_USAGE_NEVER) {
AnnaBridge 172:7d866c31b3c5 459 // Receive FIFO Overrun in case of tx length > rx length on DMA way
AnnaBridge 172:7d866c31b3c5 460 if (spi_base->STATUS & SPI_STATUS_RXOVIF_Msk) {
AnnaBridge 172:7d866c31b3c5 461 spi_base->STATUS = SPI_STATUS_RXOVIF_Msk;
AnnaBridge 172:7d866c31b3c5 462 }
AnnaBridge 172:7d866c31b3c5 463
AnnaBridge 172:7d866c31b3c5 464 if (obj->spi.dma_chn_id_tx != DMA_ERROR_OUT_OF_CHANNELS) {
AnnaBridge 172:7d866c31b3c5 465 PDMA_DisableInt(obj->spi.dma_chn_id_tx, PDMA_INT_TRANS_DONE);
AnnaBridge 172:7d866c31b3c5 466 // NOTE: On NUC472, next PDMA transfer will fail with PDMA_STOP() called. Cause is unknown.
AnnaBridge 172:7d866c31b3c5 467 pdma_base->CHCTL &= ~(1 << obj->spi.dma_chn_id_tx);
AnnaBridge 172:7d866c31b3c5 468 }
AnnaBridge 172:7d866c31b3c5 469 SPI_DISABLE_TX_PDMA(((SPI_T *) NU_MODBASE(obj->spi.spi)));
AnnaBridge 172:7d866c31b3c5 470
AnnaBridge 172:7d866c31b3c5 471 if (obj->spi.dma_chn_id_rx != DMA_ERROR_OUT_OF_CHANNELS) {
AnnaBridge 172:7d866c31b3c5 472 PDMA_DisableInt(obj->spi.dma_chn_id_rx, PDMA_INT_TRANS_DONE);
AnnaBridge 172:7d866c31b3c5 473 // NOTE: On NUC472, next PDMA transfer will fail with PDMA_STOP() called. Cause is unknown.
AnnaBridge 172:7d866c31b3c5 474 pdma_base->CHCTL &= ~(1 << obj->spi.dma_chn_id_rx);
AnnaBridge 172:7d866c31b3c5 475 }
AnnaBridge 172:7d866c31b3c5 476 SPI_DISABLE_RX_PDMA(((SPI_T *) NU_MODBASE(obj->spi.spi)));
AnnaBridge 172:7d866c31b3c5 477 }
AnnaBridge 172:7d866c31b3c5 478
AnnaBridge 172:7d866c31b3c5 479 // Necessary for both interrupt way and DMA way
AnnaBridge 172:7d866c31b3c5 480 spi_enable_vector_interrupt(obj, 0, 0);
AnnaBridge 172:7d866c31b3c5 481 spi_master_enable_interrupt(obj, 0);
AnnaBridge 172:7d866c31b3c5 482
Anna Bridge 186:707f6e361f3e 483 /* Necessary for accessing FIFOCTL below */
Anna Bridge 186:707f6e361f3e 484 SPI_DISABLE_SYNC(spi_base);
AnnaBridge 172:7d866c31b3c5 485
AnnaBridge 172:7d866c31b3c5 486 SPI_ClearRxFIFO(spi_base);
AnnaBridge 172:7d866c31b3c5 487 SPI_ClearTxFIFO(spi_base);
AnnaBridge 172:7d866c31b3c5 488 }
AnnaBridge 172:7d866c31b3c5 489
AnnaBridge 172:7d866c31b3c5 490 /**
AnnaBridge 172:7d866c31b3c5 491 * Handle the SPI interrupt
AnnaBridge 172:7d866c31b3c5 492 * Read frames until the RX FIFO is empty. Write at most as many frames as were read. This way,
AnnaBridge 172:7d866c31b3c5 493 * it is unlikely that the RX FIFO will overflow.
AnnaBridge 172:7d866c31b3c5 494 * @param[in] obj The SPI peripheral that generated the interrupt
AnnaBridge 172:7d866c31b3c5 495 * @return
AnnaBridge 172:7d866c31b3c5 496 */
AnnaBridge 172:7d866c31b3c5 497 uint32_t spi_irq_handler_asynch(spi_t *obj)
AnnaBridge 172:7d866c31b3c5 498 {
AnnaBridge 172:7d866c31b3c5 499 // Check for SPI events
AnnaBridge 172:7d866c31b3c5 500 uint32_t event = spi_event_check(obj);
AnnaBridge 172:7d866c31b3c5 501 if (event) {
AnnaBridge 172:7d866c31b3c5 502 spi_abort_asynch(obj);
AnnaBridge 172:7d866c31b3c5 503 }
AnnaBridge 172:7d866c31b3c5 504
AnnaBridge 172:7d866c31b3c5 505 return (obj->spi.event & event) | ((event & SPI_EVENT_COMPLETE) ? SPI_EVENT_INTERNAL_TRANSFER_COMPLETE : 0);
AnnaBridge 172:7d866c31b3c5 506 }
AnnaBridge 172:7d866c31b3c5 507
AnnaBridge 172:7d866c31b3c5 508 uint8_t spi_active(spi_t *obj)
AnnaBridge 172:7d866c31b3c5 509 {
Anna Bridge 186:707f6e361f3e 510 const struct nu_modinit_s *modinit = get_modinit(obj->spi.spi, spi_modinit_tab);
Anna Bridge 186:707f6e361f3e 511 MBED_ASSERT(modinit != NULL);
Anna Bridge 186:707f6e361f3e 512 MBED_ASSERT(modinit->modname == (int) obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 513
Anna Bridge 186:707f6e361f3e 514 /* Vector will be cleared when asynchronous transfer is finished or aborted.
Anna Bridge 186:707f6e361f3e 515 Use it to judge if asynchronous transfer is on-going. */
Anna Bridge 186:707f6e361f3e 516 uint32_t vec = NVIC_GetVector(modinit->irq_n);
Anna Bridge 186:707f6e361f3e 517 return vec ? 1 : 0;
AnnaBridge 172:7d866c31b3c5 518 }
AnnaBridge 172:7d866c31b3c5 519
AnnaBridge 172:7d866c31b3c5 520 static int spi_writeable(spi_t * obj)
AnnaBridge 172:7d866c31b3c5 521 {
AnnaBridge 172:7d866c31b3c5 522 // Receive FIFO must not be full to avoid receive FIFO overflow on next transmit/receive
AnnaBridge 172:7d866c31b3c5 523 return (! SPI_GET_TX_FIFO_FULL_FLAG(((SPI_T *) NU_MODBASE(obj->spi.spi))));
AnnaBridge 172:7d866c31b3c5 524 }
AnnaBridge 172:7d866c31b3c5 525
AnnaBridge 172:7d866c31b3c5 526 static int spi_readable(spi_t * obj)
AnnaBridge 172:7d866c31b3c5 527 {
AnnaBridge 172:7d866c31b3c5 528 return ! SPI_GET_RX_FIFO_EMPTY_FLAG(((SPI_T *) NU_MODBASE(obj->spi.spi)));
AnnaBridge 172:7d866c31b3c5 529 }
AnnaBridge 172:7d866c31b3c5 530
AnnaBridge 172:7d866c31b3c5 531 static void spi_enable_event(spi_t *obj, uint32_t event, uint8_t enable)
AnnaBridge 172:7d866c31b3c5 532 {
AnnaBridge 172:7d866c31b3c5 533 obj->spi.event &= ~SPI_EVENT_ALL;
AnnaBridge 172:7d866c31b3c5 534 obj->spi.event |= (event & SPI_EVENT_ALL);
AnnaBridge 172:7d866c31b3c5 535 if (event & SPI_EVENT_RX_OVERFLOW) {
AnnaBridge 172:7d866c31b3c5 536 SPI_EnableInt((SPI_T *) NU_MODBASE(obj->spi.spi), SPI_FIFO_RXOV_INT_MASK);
AnnaBridge 172:7d866c31b3c5 537 }
AnnaBridge 172:7d866c31b3c5 538 }
AnnaBridge 172:7d866c31b3c5 539
AnnaBridge 172:7d866c31b3c5 540 static void spi_enable_vector_interrupt(spi_t *obj, uint32_t handler, uint8_t enable)
AnnaBridge 172:7d866c31b3c5 541 {
AnnaBridge 172:7d866c31b3c5 542 const struct nu_modinit_s *modinit = get_modinit(obj->spi.spi, spi_modinit_tab);
AnnaBridge 172:7d866c31b3c5 543 MBED_ASSERT(modinit != NULL);
AnnaBridge 172:7d866c31b3c5 544 MBED_ASSERT(modinit->modname == (int) obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 545
AnnaBridge 172:7d866c31b3c5 546 if (enable) {
AnnaBridge 172:7d866c31b3c5 547 NVIC_SetVector(modinit->irq_n, handler);
AnnaBridge 172:7d866c31b3c5 548 NVIC_EnableIRQ(modinit->irq_n);
AnnaBridge 172:7d866c31b3c5 549 } else {
AnnaBridge 172:7d866c31b3c5 550 NVIC_DisableIRQ(modinit->irq_n);
Anna Bridge 186:707f6e361f3e 551 NVIC_SetVector(modinit->irq_n, 0);
AnnaBridge 172:7d866c31b3c5 552 }
AnnaBridge 172:7d866c31b3c5 553 }
AnnaBridge 172:7d866c31b3c5 554
AnnaBridge 172:7d866c31b3c5 555 static void spi_master_enable_interrupt(spi_t *obj, uint8_t enable)
AnnaBridge 172:7d866c31b3c5 556 {
AnnaBridge 172:7d866c31b3c5 557 SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 558
AnnaBridge 172:7d866c31b3c5 559 if (enable) {
AnnaBridge 172:7d866c31b3c5 560 uint32_t fifo_depth = spi_fifo_depth(obj);
AnnaBridge 172:7d866c31b3c5 561 SPI_SetFIFO(spi_base, fifo_depth / 2, fifo_depth / 2);
AnnaBridge 172:7d866c31b3c5 562 // Enable tx/rx FIFO threshold interrupt
AnnaBridge 172:7d866c31b3c5 563 SPI_EnableInt(spi_base, SPI_FIFO_RXTH_INT_MASK | SPI_FIFO_TXTH_INT_MASK);
AnnaBridge 172:7d866c31b3c5 564 } else {
AnnaBridge 172:7d866c31b3c5 565 SPI_DisableInt(spi_base, SPI_FIFO_RXTH_INT_MASK | SPI_FIFO_TXTH_INT_MASK);
AnnaBridge 172:7d866c31b3c5 566 }
AnnaBridge 172:7d866c31b3c5 567 }
AnnaBridge 172:7d866c31b3c5 568
AnnaBridge 172:7d866c31b3c5 569 static uint32_t spi_event_check(spi_t *obj)
AnnaBridge 172:7d866c31b3c5 570 {
AnnaBridge 172:7d866c31b3c5 571 SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 572 uint32_t event = 0;
AnnaBridge 172:7d866c31b3c5 573
AnnaBridge 172:7d866c31b3c5 574 if (obj->spi.dma_usage == DMA_USAGE_NEVER) {
AnnaBridge 172:7d866c31b3c5 575 uint32_t n_rec = spi_master_read_asynch(obj);
AnnaBridge 172:7d866c31b3c5 576 spi_master_write_asynch(obj, n_rec);
AnnaBridge 172:7d866c31b3c5 577 }
AnnaBridge 172:7d866c31b3c5 578
AnnaBridge 172:7d866c31b3c5 579 if (spi_is_tx_complete(obj) && spi_is_rx_complete(obj)) {
AnnaBridge 172:7d866c31b3c5 580 event |= SPI_EVENT_COMPLETE;
AnnaBridge 172:7d866c31b3c5 581 }
AnnaBridge 172:7d866c31b3c5 582
AnnaBridge 172:7d866c31b3c5 583 // Receive FIFO Overrun
AnnaBridge 172:7d866c31b3c5 584 if (spi_base->STATUS & SPI_STATUS_RXOVIF_Msk) {
AnnaBridge 172:7d866c31b3c5 585 spi_base->STATUS = SPI_STATUS_RXOVIF_Msk;
AnnaBridge 172:7d866c31b3c5 586 // In case of tx length > rx length on DMA way
AnnaBridge 172:7d866c31b3c5 587 if (obj->spi.dma_usage == DMA_USAGE_NEVER) {
AnnaBridge 172:7d866c31b3c5 588 event |= SPI_EVENT_RX_OVERFLOW;
AnnaBridge 172:7d866c31b3c5 589 }
AnnaBridge 172:7d866c31b3c5 590 }
AnnaBridge 172:7d866c31b3c5 591
AnnaBridge 172:7d866c31b3c5 592 // Receive Time-Out
AnnaBridge 172:7d866c31b3c5 593 if (spi_base->STATUS & SPI_STATUS_RXTOIF_Msk) {
AnnaBridge 172:7d866c31b3c5 594 spi_base->STATUS = SPI_STATUS_RXTOIF_Msk;
AnnaBridge 172:7d866c31b3c5 595 // Not using this IF. Just clear it.
AnnaBridge 172:7d866c31b3c5 596 }
AnnaBridge 172:7d866c31b3c5 597 // Transmit FIFO Under-Run
AnnaBridge 172:7d866c31b3c5 598 if (spi_base->STATUS & SPI_STATUS_TXUFIF_Msk) {
AnnaBridge 172:7d866c31b3c5 599 spi_base->STATUS = SPI_STATUS_TXUFIF_Msk;
AnnaBridge 172:7d866c31b3c5 600 event |= SPI_EVENT_ERROR;
AnnaBridge 172:7d866c31b3c5 601 }
AnnaBridge 172:7d866c31b3c5 602
AnnaBridge 172:7d866c31b3c5 603 return event;
AnnaBridge 172:7d866c31b3c5 604 }
AnnaBridge 172:7d866c31b3c5 605
AnnaBridge 172:7d866c31b3c5 606 /**
AnnaBridge 172:7d866c31b3c5 607 * Send words from the SPI TX buffer until the send limit is reached or the TX FIFO is full
AnnaBridge 172:7d866c31b3c5 608 * tx_limit is provided to ensure that the number of SPI frames (words) in flight can be managed.
AnnaBridge 172:7d866c31b3c5 609 * @param[in] obj The SPI object on which to operate
AnnaBridge 172:7d866c31b3c5 610 * @param[in] tx_limit The maximum number of words to send
AnnaBridge 172:7d866c31b3c5 611 * @return The number of SPI words that have been transfered
AnnaBridge 172:7d866c31b3c5 612 */
AnnaBridge 172:7d866c31b3c5 613 static uint32_t spi_master_write_asynch(spi_t *obj, uint32_t tx_limit)
AnnaBridge 172:7d866c31b3c5 614 {
AnnaBridge 172:7d866c31b3c5 615 uint32_t n_words = 0;
AnnaBridge 172:7d866c31b3c5 616 uint32_t tx_rmn = obj->tx_buff.length - obj->tx_buff.pos;
AnnaBridge 172:7d866c31b3c5 617 uint32_t rx_rmn = obj->rx_buff.length - obj->rx_buff.pos;
AnnaBridge 172:7d866c31b3c5 618 uint32_t max_tx = NU_MAX(tx_rmn, rx_rmn);
AnnaBridge 172:7d866c31b3c5 619 max_tx = NU_MIN(max_tx, tx_limit);
AnnaBridge 172:7d866c31b3c5 620 uint8_t data_width = spi_get_data_width(obj);
AnnaBridge 172:7d866c31b3c5 621 uint8_t bytes_per_word = (data_width + 7) / 8;
AnnaBridge 172:7d866c31b3c5 622 uint8_t *tx = (uint8_t *)(obj->tx_buff.buffer) + bytes_per_word * obj->tx_buff.pos;
AnnaBridge 172:7d866c31b3c5 623 SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 624
AnnaBridge 172:7d866c31b3c5 625 while ((n_words < max_tx) && spi_writeable(obj)) {
AnnaBridge 172:7d866c31b3c5 626 if (spi_is_tx_complete(obj)) {
AnnaBridge 172:7d866c31b3c5 627 // Transmit dummy as transmit buffer is empty
AnnaBridge 172:7d866c31b3c5 628 SPI_WRITE_TX(spi_base, 0);
AnnaBridge 172:7d866c31b3c5 629 } else {
AnnaBridge 172:7d866c31b3c5 630 switch (bytes_per_word) {
AnnaBridge 172:7d866c31b3c5 631 case 4:
AnnaBridge 172:7d866c31b3c5 632 SPI_WRITE_TX(spi_base, nu_get32_le(tx));
AnnaBridge 172:7d866c31b3c5 633 tx += 4;
AnnaBridge 172:7d866c31b3c5 634 break;
AnnaBridge 172:7d866c31b3c5 635 case 2:
AnnaBridge 172:7d866c31b3c5 636 SPI_WRITE_TX(spi_base, nu_get16_le(tx));
AnnaBridge 172:7d866c31b3c5 637 tx += 2;
AnnaBridge 172:7d866c31b3c5 638 break;
AnnaBridge 172:7d866c31b3c5 639 case 1:
AnnaBridge 172:7d866c31b3c5 640 SPI_WRITE_TX(spi_base, *((uint8_t *) tx));
AnnaBridge 172:7d866c31b3c5 641 tx += 1;
AnnaBridge 172:7d866c31b3c5 642 break;
AnnaBridge 172:7d866c31b3c5 643 }
AnnaBridge 172:7d866c31b3c5 644
AnnaBridge 172:7d866c31b3c5 645 obj->tx_buff.pos ++;
AnnaBridge 172:7d866c31b3c5 646 }
AnnaBridge 172:7d866c31b3c5 647 n_words ++;
AnnaBridge 172:7d866c31b3c5 648 }
AnnaBridge 172:7d866c31b3c5 649
AnnaBridge 172:7d866c31b3c5 650 //Return the number of words that have been sent
AnnaBridge 172:7d866c31b3c5 651 return n_words;
AnnaBridge 172:7d866c31b3c5 652 }
AnnaBridge 172:7d866c31b3c5 653
AnnaBridge 172:7d866c31b3c5 654 /**
AnnaBridge 172:7d866c31b3c5 655 * Read SPI words out of the RX FIFO
AnnaBridge 172:7d866c31b3c5 656 * Continues reading words out of the RX FIFO until the following condition is met:
AnnaBridge 172:7d866c31b3c5 657 * o There are no more words in the FIFO
AnnaBridge 172:7d866c31b3c5 658 * OR BOTH OF:
AnnaBridge 172:7d866c31b3c5 659 * o At least as many words as the TX buffer have been received
AnnaBridge 172:7d866c31b3c5 660 * o At least as many words as the RX buffer have been received
AnnaBridge 172:7d866c31b3c5 661 * This way, RX overflows are not generated when the TX buffer size exceeds the RX buffer size
AnnaBridge 172:7d866c31b3c5 662 * @param[in] obj The SPI object on which to operate
AnnaBridge 172:7d866c31b3c5 663 * @return Returns the number of words extracted from the RX FIFO
AnnaBridge 172:7d866c31b3c5 664 */
AnnaBridge 172:7d866c31b3c5 665 static uint32_t spi_master_read_asynch(spi_t *obj)
AnnaBridge 172:7d866c31b3c5 666 {
AnnaBridge 172:7d866c31b3c5 667 uint32_t n_words = 0;
AnnaBridge 172:7d866c31b3c5 668 uint32_t tx_rmn = obj->tx_buff.length - obj->tx_buff.pos;
AnnaBridge 172:7d866c31b3c5 669 uint32_t rx_rmn = obj->rx_buff.length - obj->rx_buff.pos;
AnnaBridge 172:7d866c31b3c5 670 uint32_t max_rx = NU_MAX(tx_rmn, rx_rmn);
AnnaBridge 172:7d866c31b3c5 671 uint8_t data_width = spi_get_data_width(obj);
AnnaBridge 172:7d866c31b3c5 672 uint8_t bytes_per_word = (data_width + 7) / 8;
AnnaBridge 172:7d866c31b3c5 673 uint8_t *rx = (uint8_t *)(obj->rx_buff.buffer) + bytes_per_word * obj->rx_buff.pos;
AnnaBridge 172:7d866c31b3c5 674 SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 675
AnnaBridge 172:7d866c31b3c5 676 while ((n_words < max_rx) && spi_readable(obj)) {
AnnaBridge 172:7d866c31b3c5 677 if (spi_is_rx_complete(obj)) {
AnnaBridge 172:7d866c31b3c5 678 // Disregard as receive buffer is full
AnnaBridge 172:7d866c31b3c5 679 SPI_READ_RX(spi_base);
AnnaBridge 172:7d866c31b3c5 680 } else {
AnnaBridge 172:7d866c31b3c5 681 switch (bytes_per_word) {
AnnaBridge 172:7d866c31b3c5 682 case 4: {
AnnaBridge 172:7d866c31b3c5 683 uint32_t val = SPI_READ_RX(spi_base);
AnnaBridge 172:7d866c31b3c5 684 nu_set32_le(rx, val);
AnnaBridge 172:7d866c31b3c5 685 rx += 4;
AnnaBridge 172:7d866c31b3c5 686 break;
AnnaBridge 172:7d866c31b3c5 687 }
AnnaBridge 172:7d866c31b3c5 688 case 2: {
AnnaBridge 172:7d866c31b3c5 689 uint16_t val = SPI_READ_RX(spi_base);
AnnaBridge 172:7d866c31b3c5 690 nu_set16_le(rx, val);
AnnaBridge 172:7d866c31b3c5 691 rx += 2;
AnnaBridge 172:7d866c31b3c5 692 break;
AnnaBridge 172:7d866c31b3c5 693 }
AnnaBridge 172:7d866c31b3c5 694 case 1:
AnnaBridge 172:7d866c31b3c5 695 *rx ++ = SPI_READ_RX(spi_base);
AnnaBridge 172:7d866c31b3c5 696 break;
AnnaBridge 172:7d866c31b3c5 697 }
AnnaBridge 172:7d866c31b3c5 698
AnnaBridge 172:7d866c31b3c5 699 obj->rx_buff.pos ++;
AnnaBridge 172:7d866c31b3c5 700 }
AnnaBridge 172:7d866c31b3c5 701 n_words ++;
AnnaBridge 172:7d866c31b3c5 702 }
AnnaBridge 172:7d866c31b3c5 703
AnnaBridge 172:7d866c31b3c5 704 // Return the number of words received
AnnaBridge 172:7d866c31b3c5 705 return n_words;
AnnaBridge 172:7d866c31b3c5 706 }
AnnaBridge 172:7d866c31b3c5 707
AnnaBridge 172:7d866c31b3c5 708 static void spi_buffer_set(spi_t *obj, const void *tx, size_t tx_length, void *rx, size_t rx_length)
AnnaBridge 172:7d866c31b3c5 709 {
AnnaBridge 172:7d866c31b3c5 710 obj->tx_buff.buffer = (void *) tx;
AnnaBridge 172:7d866c31b3c5 711 obj->tx_buff.length = tx_length;
AnnaBridge 172:7d866c31b3c5 712 obj->tx_buff.pos = 0;
AnnaBridge 172:7d866c31b3c5 713 obj->tx_buff.width = spi_get_data_width(obj);
AnnaBridge 172:7d866c31b3c5 714 obj->rx_buff.buffer = rx;
AnnaBridge 172:7d866c31b3c5 715 obj->rx_buff.length = rx_length;
AnnaBridge 172:7d866c31b3c5 716 obj->rx_buff.pos = 0;
AnnaBridge 172:7d866c31b3c5 717 obj->rx_buff.width = spi_get_data_width(obj);
AnnaBridge 172:7d866c31b3c5 718 }
AnnaBridge 172:7d866c31b3c5 719
AnnaBridge 172:7d866c31b3c5 720 static void spi_check_dma_usage(DMAUsage *dma_usage, int *dma_ch_tx, int *dma_ch_rx)
AnnaBridge 172:7d866c31b3c5 721 {
AnnaBridge 172:7d866c31b3c5 722 if (*dma_usage != DMA_USAGE_NEVER) {
AnnaBridge 172:7d866c31b3c5 723 if (*dma_ch_tx == DMA_ERROR_OUT_OF_CHANNELS) {
AnnaBridge 172:7d866c31b3c5 724 *dma_ch_tx = dma_channel_allocate(DMA_CAP_NONE);
AnnaBridge 172:7d866c31b3c5 725 }
AnnaBridge 172:7d866c31b3c5 726 if (*dma_ch_rx == DMA_ERROR_OUT_OF_CHANNELS) {
AnnaBridge 172:7d866c31b3c5 727 *dma_ch_rx = dma_channel_allocate(DMA_CAP_NONE);
AnnaBridge 172:7d866c31b3c5 728 }
AnnaBridge 172:7d866c31b3c5 729
AnnaBridge 172:7d866c31b3c5 730 if (*dma_ch_tx == DMA_ERROR_OUT_OF_CHANNELS || *dma_ch_rx == DMA_ERROR_OUT_OF_CHANNELS) {
AnnaBridge 172:7d866c31b3c5 731 *dma_usage = DMA_USAGE_NEVER;
AnnaBridge 172:7d866c31b3c5 732 }
AnnaBridge 172:7d866c31b3c5 733 }
AnnaBridge 172:7d866c31b3c5 734
AnnaBridge 172:7d866c31b3c5 735 if (*dma_usage == DMA_USAGE_NEVER) {
AnnaBridge 172:7d866c31b3c5 736 dma_channel_free(*dma_ch_tx);
AnnaBridge 172:7d866c31b3c5 737 *dma_ch_tx = DMA_ERROR_OUT_OF_CHANNELS;
AnnaBridge 172:7d866c31b3c5 738 dma_channel_free(*dma_ch_rx);
AnnaBridge 172:7d866c31b3c5 739 *dma_ch_rx = DMA_ERROR_OUT_OF_CHANNELS;
AnnaBridge 172:7d866c31b3c5 740 }
AnnaBridge 172:7d866c31b3c5 741 }
AnnaBridge 172:7d866c31b3c5 742
AnnaBridge 172:7d866c31b3c5 743 static uint8_t spi_get_data_width(spi_t *obj)
AnnaBridge 172:7d866c31b3c5 744 {
AnnaBridge 172:7d866c31b3c5 745 SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 746
AnnaBridge 172:7d866c31b3c5 747 uint32_t data_width = ((spi_base->CTL & SPI_CTL_DWIDTH_Msk) >> SPI_CTL_DWIDTH_Pos);
AnnaBridge 172:7d866c31b3c5 748 if (data_width == 0) {
AnnaBridge 172:7d866c31b3c5 749 data_width = 32;
AnnaBridge 172:7d866c31b3c5 750 }
AnnaBridge 172:7d866c31b3c5 751
AnnaBridge 172:7d866c31b3c5 752 return data_width;
AnnaBridge 172:7d866c31b3c5 753 }
AnnaBridge 172:7d866c31b3c5 754
AnnaBridge 172:7d866c31b3c5 755 static int spi_is_tx_complete(spi_t *obj)
AnnaBridge 172:7d866c31b3c5 756 {
AnnaBridge 172:7d866c31b3c5 757 return (obj->tx_buff.pos == obj->tx_buff.length);
AnnaBridge 172:7d866c31b3c5 758 }
AnnaBridge 172:7d866c31b3c5 759
AnnaBridge 172:7d866c31b3c5 760 static int spi_is_rx_complete(spi_t *obj)
AnnaBridge 172:7d866c31b3c5 761 {
AnnaBridge 172:7d866c31b3c5 762 return (obj->rx_buff.pos == obj->rx_buff.length);
AnnaBridge 172:7d866c31b3c5 763 }
AnnaBridge 172:7d866c31b3c5 764
AnnaBridge 172:7d866c31b3c5 765 static void spi_dma_handler_tx(uint32_t id, uint32_t event_dma)
AnnaBridge 172:7d866c31b3c5 766 {
AnnaBridge 172:7d866c31b3c5 767 spi_t *obj = (spi_t *) id;
AnnaBridge 172:7d866c31b3c5 768
Anna Bridge 186:707f6e361f3e 769 // TODO: Pass this error to caller
AnnaBridge 172:7d866c31b3c5 770 if (event_dma & DMA_EVENT_ABORT) {
AnnaBridge 172:7d866c31b3c5 771 }
AnnaBridge 172:7d866c31b3c5 772 // Expect SPI IRQ will catch this transfer done event
AnnaBridge 172:7d866c31b3c5 773 if (event_dma & DMA_EVENT_TRANSFER_DONE) {
AnnaBridge 172:7d866c31b3c5 774 obj->tx_buff.pos = obj->tx_buff.length;
AnnaBridge 172:7d866c31b3c5 775 }
Anna Bridge 186:707f6e361f3e 776 // TODO: Pass this error to caller
AnnaBridge 172:7d866c31b3c5 777 if (event_dma & DMA_EVENT_TIMEOUT) {
AnnaBridge 172:7d866c31b3c5 778 }
AnnaBridge 172:7d866c31b3c5 779
AnnaBridge 172:7d866c31b3c5 780 const struct nu_modinit_s *modinit = get_modinit(obj->spi.spi, spi_modinit_tab);
AnnaBridge 172:7d866c31b3c5 781 MBED_ASSERT(modinit != NULL);
AnnaBridge 172:7d866c31b3c5 782 MBED_ASSERT(modinit->modname == (int) obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 783
AnnaBridge 172:7d866c31b3c5 784 void (*vec)(void) = (void (*)(void)) NVIC_GetVector(modinit->irq_n);
AnnaBridge 172:7d866c31b3c5 785 vec();
AnnaBridge 172:7d866c31b3c5 786 }
AnnaBridge 172:7d866c31b3c5 787
AnnaBridge 172:7d866c31b3c5 788 static void spi_dma_handler_rx(uint32_t id, uint32_t event_dma)
AnnaBridge 172:7d866c31b3c5 789 {
AnnaBridge 172:7d866c31b3c5 790 spi_t *obj = (spi_t *) id;
AnnaBridge 172:7d866c31b3c5 791
Anna Bridge 186:707f6e361f3e 792 // TODO: Pass this error to caller
AnnaBridge 172:7d866c31b3c5 793 if (event_dma & DMA_EVENT_ABORT) {
AnnaBridge 172:7d866c31b3c5 794 }
AnnaBridge 172:7d866c31b3c5 795 // Expect SPI IRQ will catch this transfer done event
AnnaBridge 172:7d866c31b3c5 796 if (event_dma & DMA_EVENT_TRANSFER_DONE) {
AnnaBridge 172:7d866c31b3c5 797 obj->rx_buff.pos = obj->rx_buff.length;
AnnaBridge 172:7d866c31b3c5 798 }
Anna Bridge 186:707f6e361f3e 799 // TODO: Pass this error to caller
AnnaBridge 172:7d866c31b3c5 800 if (event_dma & DMA_EVENT_TIMEOUT) {
AnnaBridge 172:7d866c31b3c5 801 }
AnnaBridge 172:7d866c31b3c5 802
AnnaBridge 172:7d866c31b3c5 803 const struct nu_modinit_s *modinit = get_modinit(obj->spi.spi, spi_modinit_tab);
AnnaBridge 172:7d866c31b3c5 804 MBED_ASSERT(modinit != NULL);
AnnaBridge 172:7d866c31b3c5 805 MBED_ASSERT(modinit->modname == (int) obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 806
AnnaBridge 172:7d866c31b3c5 807 void (*vec)(void) = (void (*)(void)) NVIC_GetVector(modinit->irq_n);
AnnaBridge 172:7d866c31b3c5 808 vec();
AnnaBridge 172:7d866c31b3c5 809 }
AnnaBridge 172:7d866c31b3c5 810
AnnaBridge 172:7d866c31b3c5 811 /** Return FIFO depth of the SPI peripheral
AnnaBridge 172:7d866c31b3c5 812 *
AnnaBridge 172:7d866c31b3c5 813 * @details
AnnaBridge 172:7d866c31b3c5 814 * M487
AnnaBridge 172:7d866c31b3c5 815 * SPI0 8
AnnaBridge 172:7d866c31b3c5 816 * SPI1/2/3/4 8 if data width <=16; 4 otherwise
AnnaBridge 172:7d866c31b3c5 817 */
AnnaBridge 172:7d866c31b3c5 818 static uint32_t spi_fifo_depth(spi_t *obj)
AnnaBridge 172:7d866c31b3c5 819 {
AnnaBridge 172:7d866c31b3c5 820 SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 821
AnnaBridge 172:7d866c31b3c5 822 if (spi_base == SPI0) {
AnnaBridge 172:7d866c31b3c5 823 return 8;
AnnaBridge 172:7d866c31b3c5 824 }
AnnaBridge 172:7d866c31b3c5 825
AnnaBridge 172:7d866c31b3c5 826 return (spi_get_data_width(obj) <= 16) ? 8 : 4;
AnnaBridge 172:7d866c31b3c5 827 }
AnnaBridge 172:7d866c31b3c5 828
AnnaBridge 172:7d866c31b3c5 829 #endif
AnnaBridge 172:7d866c31b3c5 830
AnnaBridge 172:7d866c31b3c5 831 #endif