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