mbed library sources. Supersedes mbed-src.

Dependents:   BREAK_SENSOR_LED

Fork of mbed-dev by mbed official

Committer:
Anythingconnected
Date:
Mon Dec 18 10:14:27 2017 +0000
Revision:
180:d79f997829d6
Parent:
176:447f873cad2f
Getting byte by byte read to work

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
AnnaBridge 172:7d866c31b3c5 74 #if DEVICE_SPI_ASYNCH
AnnaBridge 172:7d866c31b3c5 75 static void spi_enable_vector_interrupt(spi_t *obj, uint32_t handler, uint8_t enable);
AnnaBridge 172:7d866c31b3c5 76 static void spi_master_enable_interrupt(spi_t *obj, uint8_t enable);
AnnaBridge 172:7d866c31b3c5 77 static uint32_t spi_master_write_asynch(spi_t *obj, uint32_t tx_limit);
AnnaBridge 172:7d866c31b3c5 78 static uint32_t spi_master_read_asynch(spi_t *obj);
AnnaBridge 172:7d866c31b3c5 79 static uint32_t spi_event_check(spi_t *obj);
AnnaBridge 172:7d866c31b3c5 80 static void spi_enable_event(spi_t *obj, uint32_t event, uint8_t enable);
AnnaBridge 172:7d866c31b3c5 81 static void spi_buffer_set(spi_t *obj, const void *tx, size_t tx_length, void *rx, size_t rx_length);
AnnaBridge 172:7d866c31b3c5 82 static void spi_check_dma_usage(DMAUsage *dma_usage, int *dma_ch_tx, int *dma_ch_rx);
AnnaBridge 172:7d866c31b3c5 83 static uint8_t spi_get_data_width(spi_t *obj);
AnnaBridge 172:7d866c31b3c5 84 static int spi_is_tx_complete(spi_t *obj);
AnnaBridge 172:7d866c31b3c5 85 static int spi_is_rx_complete(spi_t *obj);
AnnaBridge 172:7d866c31b3c5 86 static int spi_writeable(spi_t * obj);
AnnaBridge 172:7d866c31b3c5 87 static int spi_readable(spi_t * obj);
AnnaBridge 172:7d866c31b3c5 88 static void spi_dma_handler_tx(uint32_t id, uint32_t event_dma);
AnnaBridge 172:7d866c31b3c5 89 static void spi_dma_handler_rx(uint32_t id, uint32_t event_dma);
AnnaBridge 172:7d866c31b3c5 90 static uint32_t spi_fifo_depth(spi_t *obj);
AnnaBridge 172:7d866c31b3c5 91 #endif
AnnaBridge 172:7d866c31b3c5 92
AnnaBridge 172:7d866c31b3c5 93 static uint32_t spi_modinit_mask = 0;
AnnaBridge 172:7d866c31b3c5 94
AnnaBridge 172:7d866c31b3c5 95 static const struct nu_modinit_s spi_modinit_tab[] = {
AnnaBridge 172:7d866c31b3c5 96 {SPI_0, SPI0_MODULE, CLK_CLKSEL2_SPI0SEL_PCLK0, MODULE_NoMsk, SPI0_RST, SPI0_IRQn, &spi0_var},
AnnaBridge 172:7d866c31b3c5 97 {SPI_1, SPI1_MODULE, CLK_CLKSEL2_SPI1SEL_PCLK1, MODULE_NoMsk, SPI1_RST, SPI1_IRQn, &spi1_var},
AnnaBridge 172:7d866c31b3c5 98 {SPI_2, SPI2_MODULE, CLK_CLKSEL2_SPI2SEL_PCLK0, MODULE_NoMsk, SPI2_RST, SPI2_IRQn, &spi2_var},
AnnaBridge 172:7d866c31b3c5 99 {SPI_3, SPI3_MODULE, CLK_CLKSEL2_SPI3SEL_PCLK1, MODULE_NoMsk, SPI3_RST, SPI3_IRQn, &spi3_var},
AnnaBridge 172:7d866c31b3c5 100 {SPI_4, SPI4_MODULE, CLK_CLKSEL2_SPI4SEL_PCLK0, MODULE_NoMsk, SPI4_RST, SPI4_IRQn, &spi4_var},
AnnaBridge 172:7d866c31b3c5 101
AnnaBridge 172:7d866c31b3c5 102 {NC, 0, 0, 0, 0, (IRQn_Type) 0, NULL}
AnnaBridge 172:7d866c31b3c5 103 };
AnnaBridge 172:7d866c31b3c5 104
AnnaBridge 172:7d866c31b3c5 105 void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel)
AnnaBridge 172:7d866c31b3c5 106 {
AnnaBridge 172:7d866c31b3c5 107 // Determine which SPI_x the pins are used for
AnnaBridge 172:7d866c31b3c5 108 uint32_t spi_mosi = pinmap_peripheral(mosi, PinMap_SPI_MOSI);
AnnaBridge 172:7d866c31b3c5 109 uint32_t spi_miso = pinmap_peripheral(miso, PinMap_SPI_MISO);
AnnaBridge 172:7d866c31b3c5 110 uint32_t spi_sclk = pinmap_peripheral(sclk, PinMap_SPI_SCLK);
AnnaBridge 172:7d866c31b3c5 111 uint32_t spi_ssel = pinmap_peripheral(ssel, PinMap_SPI_SSEL);
AnnaBridge 172:7d866c31b3c5 112 uint32_t spi_data = pinmap_merge(spi_mosi, spi_miso);
AnnaBridge 172:7d866c31b3c5 113 uint32_t spi_cntl = pinmap_merge(spi_sclk, spi_ssel);
AnnaBridge 172:7d866c31b3c5 114 obj->spi.spi = (SPIName) pinmap_merge(spi_data, spi_cntl);
AnnaBridge 172:7d866c31b3c5 115 MBED_ASSERT((int)obj->spi.spi != NC);
AnnaBridge 172:7d866c31b3c5 116
AnnaBridge 172:7d866c31b3c5 117 const struct nu_modinit_s *modinit = get_modinit(obj->spi.spi, spi_modinit_tab);
AnnaBridge 172:7d866c31b3c5 118 MBED_ASSERT(modinit != NULL);
AnnaBridge 172:7d866c31b3c5 119 MBED_ASSERT(modinit->modname == (int) obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 120
AnnaBridge 172:7d866c31b3c5 121 // Reset this module
AnnaBridge 172:7d866c31b3c5 122 SYS_ResetModule(modinit->rsetidx);
AnnaBridge 172:7d866c31b3c5 123
AnnaBridge 172:7d866c31b3c5 124 // Select IP clock source
AnnaBridge 172:7d866c31b3c5 125 CLK_SetModuleClock(modinit->clkidx, modinit->clksrc, modinit->clkdiv);
AnnaBridge 172:7d866c31b3c5 126 // Enable IP clock
AnnaBridge 172:7d866c31b3c5 127 CLK_EnableModuleClock(modinit->clkidx);
AnnaBridge 172:7d866c31b3c5 128
AnnaBridge 172:7d866c31b3c5 129 pinmap_pinout(mosi, PinMap_SPI_MOSI);
AnnaBridge 172:7d866c31b3c5 130 pinmap_pinout(miso, PinMap_SPI_MISO);
AnnaBridge 172:7d866c31b3c5 131 pinmap_pinout(sclk, PinMap_SPI_SCLK);
AnnaBridge 172:7d866c31b3c5 132 pinmap_pinout(ssel, PinMap_SPI_SSEL);
AnnaBridge 172:7d866c31b3c5 133
AnnaBridge 172:7d866c31b3c5 134 obj->spi.pin_mosi = mosi;
AnnaBridge 172:7d866c31b3c5 135 obj->spi.pin_miso = miso;
AnnaBridge 172:7d866c31b3c5 136 obj->spi.pin_sclk = sclk;
AnnaBridge 172:7d866c31b3c5 137 obj->spi.pin_ssel = ssel;
AnnaBridge 172:7d866c31b3c5 138
AnnaBridge 172:7d866c31b3c5 139
AnnaBridge 172:7d866c31b3c5 140 #if DEVICE_SPI_ASYNCH
AnnaBridge 172:7d866c31b3c5 141 obj->spi.dma_usage = DMA_USAGE_NEVER;
AnnaBridge 172:7d866c31b3c5 142 obj->spi.event = 0;
AnnaBridge 172:7d866c31b3c5 143 obj->spi.dma_chn_id_tx = DMA_ERROR_OUT_OF_CHANNELS;
AnnaBridge 172:7d866c31b3c5 144 obj->spi.dma_chn_id_rx = DMA_ERROR_OUT_OF_CHANNELS;
AnnaBridge 172:7d866c31b3c5 145 #endif
AnnaBridge 172:7d866c31b3c5 146
AnnaBridge 172:7d866c31b3c5 147 // Mark this module to be inited.
AnnaBridge 172:7d866c31b3c5 148 int i = modinit - spi_modinit_tab;
AnnaBridge 172:7d866c31b3c5 149 spi_modinit_mask |= 1 << i;
AnnaBridge 172:7d866c31b3c5 150 }
AnnaBridge 172:7d866c31b3c5 151
AnnaBridge 172:7d866c31b3c5 152 void spi_free(spi_t *obj)
AnnaBridge 172:7d866c31b3c5 153 {
AnnaBridge 172:7d866c31b3c5 154 #if DEVICE_SPI_ASYNCH
AnnaBridge 172:7d866c31b3c5 155 if (obj->spi.dma_chn_id_tx != DMA_ERROR_OUT_OF_CHANNELS) {
AnnaBridge 172:7d866c31b3c5 156 dma_channel_free(obj->spi.dma_chn_id_tx);
AnnaBridge 172:7d866c31b3c5 157 obj->spi.dma_chn_id_tx = DMA_ERROR_OUT_OF_CHANNELS;
AnnaBridge 172:7d866c31b3c5 158 }
AnnaBridge 172:7d866c31b3c5 159 if (obj->spi.dma_chn_id_rx != DMA_ERROR_OUT_OF_CHANNELS) {
AnnaBridge 172:7d866c31b3c5 160 dma_channel_free(obj->spi.dma_chn_id_rx);
AnnaBridge 172:7d866c31b3c5 161 obj->spi.dma_chn_id_rx = DMA_ERROR_OUT_OF_CHANNELS;
AnnaBridge 172:7d866c31b3c5 162 }
AnnaBridge 172:7d866c31b3c5 163 #endif
AnnaBridge 172:7d866c31b3c5 164
AnnaBridge 172:7d866c31b3c5 165 SPI_Close((SPI_T *) NU_MODBASE(obj->spi.spi));
AnnaBridge 172:7d866c31b3c5 166
AnnaBridge 172:7d866c31b3c5 167 const struct nu_modinit_s *modinit = get_modinit(obj->spi.spi, spi_modinit_tab);
AnnaBridge 172:7d866c31b3c5 168 MBED_ASSERT(modinit != NULL);
AnnaBridge 172:7d866c31b3c5 169 MBED_ASSERT(modinit->modname == (int) obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 170
AnnaBridge 172:7d866c31b3c5 171 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 172 NVIC_DisableIRQ(modinit->irq_n);
AnnaBridge 172:7d866c31b3c5 173
AnnaBridge 172:7d866c31b3c5 174 // Disable IP clock
AnnaBridge 172:7d866c31b3c5 175 CLK_DisableModuleClock(modinit->clkidx);
AnnaBridge 172:7d866c31b3c5 176
AnnaBridge 172:7d866c31b3c5 177 // Mark this module to be deinited.
AnnaBridge 172:7d866c31b3c5 178 int i = modinit - spi_modinit_tab;
AnnaBridge 172:7d866c31b3c5 179 spi_modinit_mask &= ~(1 << i);
AnnaBridge 172:7d866c31b3c5 180 }
AnnaBridge 172:7d866c31b3c5 181 void spi_format(spi_t *obj, int bits, int mode, int slave)
AnnaBridge 172:7d866c31b3c5 182 {
AnnaBridge 172:7d866c31b3c5 183 MBED_ASSERT(bits >= NU_SPI_FRAME_MIN && bits <= NU_SPI_FRAME_MAX);
AnnaBridge 172:7d866c31b3c5 184
AnnaBridge 172:7d866c31b3c5 185 SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 186
AnnaBridge 172:7d866c31b3c5 187 // NOTE 1: All configurations should be ready before enabling SPI peripheral.
AnnaBridge 172:7d866c31b3c5 188 // NOTE 2: Re-configuration is allowed only as SPI peripheral is idle.
AnnaBridge 172:7d866c31b3c5 189 while (SPI_IS_BUSY(spi_base));
AnnaBridge 172:7d866c31b3c5 190 SPI_DISABLE(spi_base);
AnnaBridge 172:7d866c31b3c5 191
AnnaBridge 172:7d866c31b3c5 192 SPI_Open(spi_base,
AnnaBridge 172:7d866c31b3c5 193 slave ? SPI_SLAVE : SPI_MASTER,
AnnaBridge 172:7d866c31b3c5 194 (mode == 0) ? SPI_MODE_0 : (mode == 1) ? SPI_MODE_1 : (mode == 2) ? SPI_MODE_2 : SPI_MODE_3,
AnnaBridge 172:7d866c31b3c5 195 bits,
AnnaBridge 172:7d866c31b3c5 196 SPI_GetBusClock(spi_base));
AnnaBridge 172:7d866c31b3c5 197 // NOTE: Hardcode to be MSB first.
AnnaBridge 172:7d866c31b3c5 198 SPI_SET_MSB_FIRST(spi_base);
AnnaBridge 172:7d866c31b3c5 199
AnnaBridge 172:7d866c31b3c5 200 if (! slave) {
AnnaBridge 172:7d866c31b3c5 201 // Master
AnnaBridge 172:7d866c31b3c5 202 if (obj->spi.pin_ssel != NC) {
AnnaBridge 172:7d866c31b3c5 203 // Configure SS as low active.
AnnaBridge 172:7d866c31b3c5 204 SPI_EnableAutoSS(spi_base, SPI_SS, SPI_SS_ACTIVE_LOW);
AnnaBridge 172:7d866c31b3c5 205 } else {
AnnaBridge 172:7d866c31b3c5 206 SPI_DisableAutoSS(spi_base);
AnnaBridge 172:7d866c31b3c5 207 }
AnnaBridge 172:7d866c31b3c5 208 } else {
AnnaBridge 172:7d866c31b3c5 209 // Slave
AnnaBridge 172:7d866c31b3c5 210 // Configure SS as low active.
AnnaBridge 172:7d866c31b3c5 211 spi_base->SSCTL &= ~SPI_SSCTL_SSACTPOL_Msk;
AnnaBridge 172:7d866c31b3c5 212 }
AnnaBridge 172:7d866c31b3c5 213
AnnaBridge 172:7d866c31b3c5 214 // NOTE: M451's/M480's SPI_Open() will enable SPI transfer (SPI_CTL_SPIEN_Msk). This will violate judgement of spi_active(). Disable it.
AnnaBridge 172:7d866c31b3c5 215 SPI_DISABLE(spi_base);
AnnaBridge 172:7d866c31b3c5 216 }
AnnaBridge 172:7d866c31b3c5 217
AnnaBridge 172:7d866c31b3c5 218 void spi_frequency(spi_t *obj, int hz)
AnnaBridge 172:7d866c31b3c5 219 {
AnnaBridge 172:7d866c31b3c5 220 SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 221
AnnaBridge 172:7d866c31b3c5 222 while (SPI_IS_BUSY(spi_base));
AnnaBridge 172:7d866c31b3c5 223 SPI_DISABLE(spi_base);
AnnaBridge 172:7d866c31b3c5 224
AnnaBridge 172:7d866c31b3c5 225 SPI_SetBusClock((SPI_T *) NU_MODBASE(obj->spi.spi), hz);
AnnaBridge 172:7d866c31b3c5 226 }
AnnaBridge 172:7d866c31b3c5 227
AnnaBridge 172:7d866c31b3c5 228
AnnaBridge 172:7d866c31b3c5 229 int spi_master_write(spi_t *obj, int value)
AnnaBridge 172:7d866c31b3c5 230 {
AnnaBridge 172:7d866c31b3c5 231 SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 232
AnnaBridge 172:7d866c31b3c5 233 // NOTE: Data in receive FIFO can be read out via ICE.
AnnaBridge 172:7d866c31b3c5 234 SPI_ENABLE(spi_base);
AnnaBridge 172:7d866c31b3c5 235
AnnaBridge 172:7d866c31b3c5 236 // Wait for tx buffer empty
AnnaBridge 172:7d866c31b3c5 237 while(! spi_writeable(obj));
AnnaBridge 172:7d866c31b3c5 238 SPI_WRITE_TX(spi_base, value);
AnnaBridge 172:7d866c31b3c5 239
AnnaBridge 172:7d866c31b3c5 240 // Wait for rx buffer full
AnnaBridge 172:7d866c31b3c5 241 while (! spi_readable(obj));
AnnaBridge 172:7d866c31b3c5 242 int value2 = SPI_READ_RX(spi_base);
AnnaBridge 172:7d866c31b3c5 243
AnnaBridge 172:7d866c31b3c5 244 SPI_DISABLE(spi_base);
AnnaBridge 172:7d866c31b3c5 245
AnnaBridge 172:7d866c31b3c5 246 return value2;
AnnaBridge 172:7d866c31b3c5 247 }
AnnaBridge 172:7d866c31b3c5 248
AnnaBridge 172:7d866c31b3c5 249 int spi_master_block_write(spi_t *obj, const char *tx_buffer, int tx_length,
AnnaBridge 172:7d866c31b3c5 250 char *rx_buffer, int rx_length, char write_fill) {
AnnaBridge 172:7d866c31b3c5 251 int total = (tx_length > rx_length) ? tx_length : rx_length;
AnnaBridge 172:7d866c31b3c5 252
AnnaBridge 172:7d866c31b3c5 253 for (int i = 0; i < total; i++) {
AnnaBridge 172:7d866c31b3c5 254 char out = (i < tx_length) ? tx_buffer[i] : write_fill;
AnnaBridge 172:7d866c31b3c5 255 char in = spi_master_write(obj, out);
AnnaBridge 172:7d866c31b3c5 256 if (i < rx_length) {
AnnaBridge 172:7d866c31b3c5 257 rx_buffer[i] = in;
AnnaBridge 172:7d866c31b3c5 258 }
AnnaBridge 172:7d866c31b3c5 259 }
AnnaBridge 172:7d866c31b3c5 260
AnnaBridge 172:7d866c31b3c5 261 return total;
AnnaBridge 172:7d866c31b3c5 262 }
AnnaBridge 172:7d866c31b3c5 263
AnnaBridge 172:7d866c31b3c5 264 #if DEVICE_SPISLAVE
AnnaBridge 172:7d866c31b3c5 265 int spi_slave_receive(spi_t *obj)
AnnaBridge 172:7d866c31b3c5 266 {
AnnaBridge 172:7d866c31b3c5 267 SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 268
AnnaBridge 172:7d866c31b3c5 269 SPI_ENABLE(spi_base);
AnnaBridge 172:7d866c31b3c5 270
AnnaBridge 172:7d866c31b3c5 271 return spi_readable(obj);
AnnaBridge 172:7d866c31b3c5 272 };
AnnaBridge 172:7d866c31b3c5 273
AnnaBridge 172:7d866c31b3c5 274 int spi_slave_read(spi_t *obj)
AnnaBridge 172:7d866c31b3c5 275 {
AnnaBridge 172:7d866c31b3c5 276 SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 277
AnnaBridge 172:7d866c31b3c5 278 SPI_ENABLE(spi_base);
AnnaBridge 172:7d866c31b3c5 279
AnnaBridge 172:7d866c31b3c5 280 // Wait for rx buffer full
AnnaBridge 172:7d866c31b3c5 281 while (! spi_readable(obj));
AnnaBridge 172:7d866c31b3c5 282 int value = SPI_READ_RX(spi_base);
AnnaBridge 172:7d866c31b3c5 283 return value;
AnnaBridge 172:7d866c31b3c5 284 }
AnnaBridge 172:7d866c31b3c5 285
AnnaBridge 172:7d866c31b3c5 286 void spi_slave_write(spi_t *obj, int value)
AnnaBridge 172:7d866c31b3c5 287 {
AnnaBridge 172:7d866c31b3c5 288 SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 289
AnnaBridge 172:7d866c31b3c5 290 SPI_ENABLE(spi_base);
AnnaBridge 172:7d866c31b3c5 291
AnnaBridge 172:7d866c31b3c5 292 // Wait for tx buffer empty
AnnaBridge 172:7d866c31b3c5 293 while(! spi_writeable(obj));
AnnaBridge 172:7d866c31b3c5 294 SPI_WRITE_TX(spi_base, value);
AnnaBridge 172:7d866c31b3c5 295 }
AnnaBridge 172:7d866c31b3c5 296 #endif
AnnaBridge 172:7d866c31b3c5 297
AnnaBridge 172:7d866c31b3c5 298 #if DEVICE_SPI_ASYNCH
AnnaBridge 172:7d866c31b3c5 299 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 300 {
AnnaBridge 172:7d866c31b3c5 301 SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 302 SPI_SET_DATA_WIDTH(spi_base, bit_width);
AnnaBridge 172:7d866c31b3c5 303
AnnaBridge 172:7d866c31b3c5 304 obj->spi.dma_usage = hint;
AnnaBridge 172:7d866c31b3c5 305 spi_check_dma_usage(&obj->spi.dma_usage, &obj->spi.dma_chn_id_tx, &obj->spi.dma_chn_id_rx);
AnnaBridge 172:7d866c31b3c5 306 uint32_t data_width = spi_get_data_width(obj);
AnnaBridge 172:7d866c31b3c5 307 // Conditions to go DMA way:
AnnaBridge 172:7d866c31b3c5 308 // (1) No DMA support for non-8 multiple data width.
AnnaBridge 172:7d866c31b3c5 309 // (2) tx length >= rx length. Otherwise, as tx DMA is done, no bus activity for remaining rx.
AnnaBridge 172:7d866c31b3c5 310 if ((data_width % 8) ||
AnnaBridge 172:7d866c31b3c5 311 (tx_length < rx_length)) {
AnnaBridge 172:7d866c31b3c5 312 obj->spi.dma_usage = DMA_USAGE_NEVER;
AnnaBridge 172:7d866c31b3c5 313 dma_channel_free(obj->spi.dma_chn_id_tx);
AnnaBridge 172:7d866c31b3c5 314 obj->spi.dma_chn_id_tx = DMA_ERROR_OUT_OF_CHANNELS;
AnnaBridge 172:7d866c31b3c5 315 dma_channel_free(obj->spi.dma_chn_id_rx);
AnnaBridge 172:7d866c31b3c5 316 obj->spi.dma_chn_id_rx = DMA_ERROR_OUT_OF_CHANNELS;
AnnaBridge 172:7d866c31b3c5 317 }
AnnaBridge 172:7d866c31b3c5 318
AnnaBridge 172:7d866c31b3c5 319 // SPI IRQ is necessary for both interrupt way and DMA way
AnnaBridge 172:7d866c31b3c5 320 spi_enable_event(obj, event, 1);
AnnaBridge 172:7d866c31b3c5 321 spi_buffer_set(obj, tx, tx_length, rx, rx_length);
AnnaBridge 172:7d866c31b3c5 322
AnnaBridge 172:7d866c31b3c5 323 SPI_ENABLE(spi_base);
AnnaBridge 172:7d866c31b3c5 324
AnnaBridge 172:7d866c31b3c5 325 if (obj->spi.dma_usage == DMA_USAGE_NEVER) {
AnnaBridge 172:7d866c31b3c5 326 // Interrupt way
AnnaBridge 172:7d866c31b3c5 327 spi_master_write_asynch(obj, spi_fifo_depth(obj) / 2);
AnnaBridge 172:7d866c31b3c5 328 spi_enable_vector_interrupt(obj, handler, 1);
AnnaBridge 172:7d866c31b3c5 329 spi_master_enable_interrupt(obj, 1);
AnnaBridge 172:7d866c31b3c5 330 } else {
AnnaBridge 172:7d866c31b3c5 331 // DMA way
AnnaBridge 172:7d866c31b3c5 332 const struct nu_modinit_s *modinit = get_modinit(obj->spi.spi, spi_modinit_tab);
AnnaBridge 172:7d866c31b3c5 333 MBED_ASSERT(modinit != NULL);
AnnaBridge 172:7d866c31b3c5 334 MBED_ASSERT(modinit->modname == (int) obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 335
AnnaBridge 172:7d866c31b3c5 336 PDMA_T *pdma_base = dma_modbase();
AnnaBridge 172:7d866c31b3c5 337
AnnaBridge 172:7d866c31b3c5 338 // Configure tx DMA
AnnaBridge 172:7d866c31b3c5 339 pdma_base->CHCTL |= 1 << obj->spi.dma_chn_id_tx; // Enable this DMA channel
AnnaBridge 172:7d866c31b3c5 340 PDMA_SetTransferMode(obj->spi.dma_chn_id_tx,
AnnaBridge 172:7d866c31b3c5 341 ((struct nu_spi_var *) modinit->var)->pdma_perp_tx, // Peripheral connected to this PDMA
AnnaBridge 172:7d866c31b3c5 342 0, // Scatter-gather disabled
AnnaBridge 172:7d866c31b3c5 343 0); // Scatter-gather descriptor address
AnnaBridge 172:7d866c31b3c5 344 PDMA_SetTransferCnt(obj->spi.dma_chn_id_tx,
AnnaBridge 172:7d866c31b3c5 345 (data_width == 8) ? PDMA_WIDTH_8 : (data_width == 16) ? PDMA_WIDTH_16 : PDMA_WIDTH_32,
AnnaBridge 172:7d866c31b3c5 346 tx_length);
AnnaBridge 172:7d866c31b3c5 347 PDMA_SetTransferAddr(obj->spi.dma_chn_id_tx,
AnnaBridge 172:7d866c31b3c5 348 (uint32_t) tx, // NOTE:
AnnaBridge 172:7d866c31b3c5 349 // NUC472: End of source address
AnnaBridge 172:7d866c31b3c5 350 // M451/M480: Start of source address
AnnaBridge 172:7d866c31b3c5 351 PDMA_SAR_INC, // Source address incremental
AnnaBridge 172:7d866c31b3c5 352 (uint32_t) &spi_base->TX, // Destination address
AnnaBridge 172:7d866c31b3c5 353 PDMA_DAR_FIX); // Destination address fixed
AnnaBridge 172:7d866c31b3c5 354 PDMA_SetBurstType(obj->spi.dma_chn_id_tx,
AnnaBridge 172:7d866c31b3c5 355 PDMA_REQ_SINGLE, // Single mode
AnnaBridge 172:7d866c31b3c5 356 0); // Burst size
AnnaBridge 172:7d866c31b3c5 357 PDMA_EnableInt(obj->spi.dma_chn_id_tx,
AnnaBridge 172:7d866c31b3c5 358 PDMA_INT_TRANS_DONE); // Interrupt type
AnnaBridge 172:7d866c31b3c5 359 // Register DMA event handler
AnnaBridge 172:7d866c31b3c5 360 dma_set_handler(obj->spi.dma_chn_id_tx, (uint32_t) spi_dma_handler_tx, (uint32_t) obj, DMA_EVENT_ALL);
AnnaBridge 172:7d866c31b3c5 361
AnnaBridge 172:7d866c31b3c5 362 // Configure rx DMA
AnnaBridge 172:7d866c31b3c5 363 pdma_base->CHCTL |= 1 << obj->spi.dma_chn_id_rx; // Enable this DMA channel
AnnaBridge 172:7d866c31b3c5 364 PDMA_SetTransferMode(obj->spi.dma_chn_id_rx,
AnnaBridge 172:7d866c31b3c5 365 ((struct nu_spi_var *) modinit->var)->pdma_perp_rx, // Peripheral connected to this PDMA
AnnaBridge 172:7d866c31b3c5 366 0, // Scatter-gather disabled
AnnaBridge 172:7d866c31b3c5 367 0); // Scatter-gather descriptor address
AnnaBridge 172:7d866c31b3c5 368 PDMA_SetTransferCnt(obj->spi.dma_chn_id_rx,
AnnaBridge 172:7d866c31b3c5 369 (data_width == 8) ? PDMA_WIDTH_8 : (data_width == 16) ? PDMA_WIDTH_16 : PDMA_WIDTH_32,
AnnaBridge 172:7d866c31b3c5 370 rx_length);
AnnaBridge 172:7d866c31b3c5 371 PDMA_SetTransferAddr(obj->spi.dma_chn_id_rx,
AnnaBridge 172:7d866c31b3c5 372 (uint32_t) &spi_base->RX, // Source address
AnnaBridge 172:7d866c31b3c5 373 PDMA_SAR_FIX, // Source address fixed
AnnaBridge 172:7d866c31b3c5 374 (uint32_t) rx, // NOTE:
AnnaBridge 172:7d866c31b3c5 375 // NUC472: End of destination address
AnnaBridge 172:7d866c31b3c5 376 // M451/M480: Start of destination address
AnnaBridge 172:7d866c31b3c5 377 PDMA_DAR_INC); // Destination address incremental
AnnaBridge 172:7d866c31b3c5 378 PDMA_SetBurstType(obj->spi.dma_chn_id_rx,
AnnaBridge 172:7d866c31b3c5 379 PDMA_REQ_SINGLE, // Single mode
AnnaBridge 172:7d866c31b3c5 380 0); // Burst size
AnnaBridge 172:7d866c31b3c5 381 PDMA_EnableInt(obj->spi.dma_chn_id_rx,
AnnaBridge 172:7d866c31b3c5 382 PDMA_INT_TRANS_DONE); // Interrupt type
AnnaBridge 172:7d866c31b3c5 383 // Register DMA event handler
AnnaBridge 172:7d866c31b3c5 384 dma_set_handler(obj->spi.dma_chn_id_rx, (uint32_t) spi_dma_handler_rx, (uint32_t) obj, DMA_EVENT_ALL);
AnnaBridge 172:7d866c31b3c5 385
AnnaBridge 172:7d866c31b3c5 386 // Start tx/rx DMA transfer
AnnaBridge 172:7d866c31b3c5 387 spi_enable_vector_interrupt(obj, handler, 1);
AnnaBridge 172:7d866c31b3c5 388 // NOTE: It is safer to start rx DMA first and then tx DMA. Otherwise, receive FIFO is subject to overflow by tx DMA.
AnnaBridge 172:7d866c31b3c5 389 SPI_TRIGGER_RX_PDMA(((SPI_T *) NU_MODBASE(obj->spi.spi)));
AnnaBridge 172:7d866c31b3c5 390 SPI_TRIGGER_TX_PDMA(((SPI_T *) NU_MODBASE(obj->spi.spi)));
AnnaBridge 172:7d866c31b3c5 391 spi_master_enable_interrupt(obj, 1);
AnnaBridge 172:7d866c31b3c5 392 }
AnnaBridge 172:7d866c31b3c5 393 }
AnnaBridge 172:7d866c31b3c5 394
AnnaBridge 172:7d866c31b3c5 395 /**
AnnaBridge 172:7d866c31b3c5 396 * Abort an SPI transfer
AnnaBridge 172:7d866c31b3c5 397 * This is a helper function for event handling. When any of the events listed occurs, the HAL will abort any ongoing
AnnaBridge 172:7d866c31b3c5 398 * transfers
AnnaBridge 172:7d866c31b3c5 399 * @param[in] obj The SPI peripheral to stop
AnnaBridge 172:7d866c31b3c5 400 */
AnnaBridge 172:7d866c31b3c5 401 void spi_abort_asynch(spi_t *obj)
AnnaBridge 172:7d866c31b3c5 402 {
AnnaBridge 172:7d866c31b3c5 403 SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 404 PDMA_T *pdma_base = dma_modbase();
AnnaBridge 172:7d866c31b3c5 405
AnnaBridge 172:7d866c31b3c5 406 if (obj->spi.dma_usage != DMA_USAGE_NEVER) {
AnnaBridge 172:7d866c31b3c5 407 // Receive FIFO Overrun in case of tx length > rx length on DMA way
AnnaBridge 172:7d866c31b3c5 408 if (spi_base->STATUS & SPI_STATUS_RXOVIF_Msk) {
AnnaBridge 172:7d866c31b3c5 409 spi_base->STATUS = SPI_STATUS_RXOVIF_Msk;
AnnaBridge 172:7d866c31b3c5 410 }
AnnaBridge 172:7d866c31b3c5 411
AnnaBridge 172:7d866c31b3c5 412 if (obj->spi.dma_chn_id_tx != DMA_ERROR_OUT_OF_CHANNELS) {
AnnaBridge 172:7d866c31b3c5 413 PDMA_DisableInt(obj->spi.dma_chn_id_tx, PDMA_INT_TRANS_DONE);
AnnaBridge 172:7d866c31b3c5 414 // NOTE: On NUC472, next PDMA transfer will fail with PDMA_STOP() called. Cause is unknown.
AnnaBridge 172:7d866c31b3c5 415 pdma_base->CHCTL &= ~(1 << obj->spi.dma_chn_id_tx);
AnnaBridge 172:7d866c31b3c5 416 }
AnnaBridge 172:7d866c31b3c5 417 SPI_DISABLE_TX_PDMA(((SPI_T *) NU_MODBASE(obj->spi.spi)));
AnnaBridge 172:7d866c31b3c5 418
AnnaBridge 172:7d866c31b3c5 419 if (obj->spi.dma_chn_id_rx != DMA_ERROR_OUT_OF_CHANNELS) {
AnnaBridge 172:7d866c31b3c5 420 PDMA_DisableInt(obj->spi.dma_chn_id_rx, PDMA_INT_TRANS_DONE);
AnnaBridge 172:7d866c31b3c5 421 // NOTE: On NUC472, next PDMA transfer will fail with PDMA_STOP() called. Cause is unknown.
AnnaBridge 172:7d866c31b3c5 422 pdma_base->CHCTL &= ~(1 << obj->spi.dma_chn_id_rx);
AnnaBridge 172:7d866c31b3c5 423 }
AnnaBridge 172:7d866c31b3c5 424 SPI_DISABLE_RX_PDMA(((SPI_T *) NU_MODBASE(obj->spi.spi)));
AnnaBridge 172:7d866c31b3c5 425 }
AnnaBridge 172:7d866c31b3c5 426
AnnaBridge 172:7d866c31b3c5 427 // Necessary for both interrupt way and DMA way
AnnaBridge 172:7d866c31b3c5 428 spi_enable_vector_interrupt(obj, 0, 0);
AnnaBridge 172:7d866c31b3c5 429 spi_master_enable_interrupt(obj, 0);
AnnaBridge 172:7d866c31b3c5 430
AnnaBridge 172:7d866c31b3c5 431 // NOTE: SPI H/W may get out of state without the busy check.
AnnaBridge 172:7d866c31b3c5 432 while (SPI_IS_BUSY(spi_base));
AnnaBridge 172:7d866c31b3c5 433 SPI_DISABLE(spi_base);
AnnaBridge 172:7d866c31b3c5 434
AnnaBridge 172:7d866c31b3c5 435 SPI_ClearRxFIFO(spi_base);
AnnaBridge 172:7d866c31b3c5 436 SPI_ClearTxFIFO(spi_base);
AnnaBridge 172:7d866c31b3c5 437 }
AnnaBridge 172:7d866c31b3c5 438
AnnaBridge 172:7d866c31b3c5 439 /**
AnnaBridge 172:7d866c31b3c5 440 * Handle the SPI interrupt
AnnaBridge 172:7d866c31b3c5 441 * Read frames until the RX FIFO is empty. Write at most as many frames as were read. This way,
AnnaBridge 172:7d866c31b3c5 442 * it is unlikely that the RX FIFO will overflow.
AnnaBridge 172:7d866c31b3c5 443 * @param[in] obj The SPI peripheral that generated the interrupt
AnnaBridge 172:7d866c31b3c5 444 * @return
AnnaBridge 172:7d866c31b3c5 445 */
AnnaBridge 172:7d866c31b3c5 446 uint32_t spi_irq_handler_asynch(spi_t *obj)
AnnaBridge 172:7d866c31b3c5 447 {
AnnaBridge 172:7d866c31b3c5 448 // Check for SPI events
AnnaBridge 172:7d866c31b3c5 449 uint32_t event = spi_event_check(obj);
AnnaBridge 172:7d866c31b3c5 450 if (event) {
AnnaBridge 172:7d866c31b3c5 451 spi_abort_asynch(obj);
AnnaBridge 172:7d866c31b3c5 452 }
AnnaBridge 172:7d866c31b3c5 453
AnnaBridge 172:7d866c31b3c5 454 return (obj->spi.event & event) | ((event & SPI_EVENT_COMPLETE) ? SPI_EVENT_INTERNAL_TRANSFER_COMPLETE : 0);
AnnaBridge 172:7d866c31b3c5 455 }
AnnaBridge 172:7d866c31b3c5 456
AnnaBridge 172:7d866c31b3c5 457 uint8_t spi_active(spi_t *obj)
AnnaBridge 172:7d866c31b3c5 458 {
AnnaBridge 172:7d866c31b3c5 459 SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 460
AnnaBridge 172:7d866c31b3c5 461 return (spi_base->CTL & SPI_CTL_SPIEN_Msk);
AnnaBridge 172:7d866c31b3c5 462 }
AnnaBridge 172:7d866c31b3c5 463
AnnaBridge 172:7d866c31b3c5 464 static int spi_writeable(spi_t * obj)
AnnaBridge 172:7d866c31b3c5 465 {
AnnaBridge 172:7d866c31b3c5 466 // Receive FIFO must not be full to avoid receive FIFO overflow on next transmit/receive
AnnaBridge 172:7d866c31b3c5 467 return (! SPI_GET_TX_FIFO_FULL_FLAG(((SPI_T *) NU_MODBASE(obj->spi.spi))));
AnnaBridge 172:7d866c31b3c5 468 }
AnnaBridge 172:7d866c31b3c5 469
AnnaBridge 172:7d866c31b3c5 470 static int spi_readable(spi_t * obj)
AnnaBridge 172:7d866c31b3c5 471 {
AnnaBridge 172:7d866c31b3c5 472 return ! SPI_GET_RX_FIFO_EMPTY_FLAG(((SPI_T *) NU_MODBASE(obj->spi.spi)));
AnnaBridge 172:7d866c31b3c5 473 }
AnnaBridge 172:7d866c31b3c5 474
AnnaBridge 172:7d866c31b3c5 475 static void spi_enable_event(spi_t *obj, uint32_t event, uint8_t enable)
AnnaBridge 172:7d866c31b3c5 476 {
AnnaBridge 172:7d866c31b3c5 477 obj->spi.event &= ~SPI_EVENT_ALL;
AnnaBridge 172:7d866c31b3c5 478 obj->spi.event |= (event & SPI_EVENT_ALL);
AnnaBridge 172:7d866c31b3c5 479 if (event & SPI_EVENT_RX_OVERFLOW) {
AnnaBridge 172:7d866c31b3c5 480 SPI_EnableInt((SPI_T *) NU_MODBASE(obj->spi.spi), SPI_FIFO_RXOV_INT_MASK);
AnnaBridge 172:7d866c31b3c5 481 }
AnnaBridge 172:7d866c31b3c5 482 }
AnnaBridge 172:7d866c31b3c5 483
AnnaBridge 172:7d866c31b3c5 484 static void spi_enable_vector_interrupt(spi_t *obj, uint32_t handler, uint8_t enable)
AnnaBridge 172:7d866c31b3c5 485 {
AnnaBridge 172:7d866c31b3c5 486 const struct nu_modinit_s *modinit = get_modinit(obj->spi.spi, spi_modinit_tab);
AnnaBridge 172:7d866c31b3c5 487 MBED_ASSERT(modinit != NULL);
AnnaBridge 172:7d866c31b3c5 488 MBED_ASSERT(modinit->modname == (int) obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 489
AnnaBridge 172:7d866c31b3c5 490 if (enable) {
AnnaBridge 172:7d866c31b3c5 491 NVIC_SetVector(modinit->irq_n, handler);
AnnaBridge 172:7d866c31b3c5 492 NVIC_EnableIRQ(modinit->irq_n);
AnnaBridge 172:7d866c31b3c5 493 } else {
AnnaBridge 172:7d866c31b3c5 494 NVIC_DisableIRQ(modinit->irq_n);
AnnaBridge 172:7d866c31b3c5 495 }
AnnaBridge 172:7d866c31b3c5 496 }
AnnaBridge 172:7d866c31b3c5 497
AnnaBridge 172:7d866c31b3c5 498 static void spi_master_enable_interrupt(spi_t *obj, uint8_t enable)
AnnaBridge 172:7d866c31b3c5 499 {
AnnaBridge 172:7d866c31b3c5 500 SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 501
AnnaBridge 172:7d866c31b3c5 502 if (enable) {
AnnaBridge 172:7d866c31b3c5 503 uint32_t fifo_depth = spi_fifo_depth(obj);
AnnaBridge 172:7d866c31b3c5 504 SPI_SetFIFO(spi_base, fifo_depth / 2, fifo_depth / 2);
AnnaBridge 172:7d866c31b3c5 505 // Enable tx/rx FIFO threshold interrupt
AnnaBridge 172:7d866c31b3c5 506 SPI_EnableInt(spi_base, SPI_FIFO_RXTH_INT_MASK | SPI_FIFO_TXTH_INT_MASK);
AnnaBridge 172:7d866c31b3c5 507 } else {
AnnaBridge 172:7d866c31b3c5 508 SPI_DisableInt(spi_base, SPI_FIFO_RXTH_INT_MASK | SPI_FIFO_TXTH_INT_MASK);
AnnaBridge 172:7d866c31b3c5 509 }
AnnaBridge 172:7d866c31b3c5 510 }
AnnaBridge 172:7d866c31b3c5 511
AnnaBridge 172:7d866c31b3c5 512 static uint32_t spi_event_check(spi_t *obj)
AnnaBridge 172:7d866c31b3c5 513 {
AnnaBridge 172:7d866c31b3c5 514 SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 515 uint32_t event = 0;
AnnaBridge 172:7d866c31b3c5 516
AnnaBridge 172:7d866c31b3c5 517 if (obj->spi.dma_usage == DMA_USAGE_NEVER) {
AnnaBridge 172:7d866c31b3c5 518 uint32_t n_rec = spi_master_read_asynch(obj);
AnnaBridge 172:7d866c31b3c5 519 spi_master_write_asynch(obj, n_rec);
AnnaBridge 172:7d866c31b3c5 520 }
AnnaBridge 172:7d866c31b3c5 521
AnnaBridge 172:7d866c31b3c5 522 if (spi_is_tx_complete(obj) && spi_is_rx_complete(obj)) {
AnnaBridge 172:7d866c31b3c5 523 event |= SPI_EVENT_COMPLETE;
AnnaBridge 172:7d866c31b3c5 524 }
AnnaBridge 172:7d866c31b3c5 525
AnnaBridge 172:7d866c31b3c5 526 // Receive FIFO Overrun
AnnaBridge 172:7d866c31b3c5 527 if (spi_base->STATUS & SPI_STATUS_RXOVIF_Msk) {
AnnaBridge 172:7d866c31b3c5 528 spi_base->STATUS = SPI_STATUS_RXOVIF_Msk;
AnnaBridge 172:7d866c31b3c5 529 // In case of tx length > rx length on DMA way
AnnaBridge 172:7d866c31b3c5 530 if (obj->spi.dma_usage == DMA_USAGE_NEVER) {
AnnaBridge 172:7d866c31b3c5 531 event |= SPI_EVENT_RX_OVERFLOW;
AnnaBridge 172:7d866c31b3c5 532 }
AnnaBridge 172:7d866c31b3c5 533 }
AnnaBridge 172:7d866c31b3c5 534
AnnaBridge 172:7d866c31b3c5 535 // Receive Time-Out
AnnaBridge 172:7d866c31b3c5 536 if (spi_base->STATUS & SPI_STATUS_RXTOIF_Msk) {
AnnaBridge 172:7d866c31b3c5 537 spi_base->STATUS = SPI_STATUS_RXTOIF_Msk;
AnnaBridge 172:7d866c31b3c5 538 // Not using this IF. Just clear it.
AnnaBridge 172:7d866c31b3c5 539 }
AnnaBridge 172:7d866c31b3c5 540 // Transmit FIFO Under-Run
AnnaBridge 172:7d866c31b3c5 541 if (spi_base->STATUS & SPI_STATUS_TXUFIF_Msk) {
AnnaBridge 172:7d866c31b3c5 542 spi_base->STATUS = SPI_STATUS_TXUFIF_Msk;
AnnaBridge 172:7d866c31b3c5 543 event |= SPI_EVENT_ERROR;
AnnaBridge 172:7d866c31b3c5 544 }
AnnaBridge 172:7d866c31b3c5 545
AnnaBridge 172:7d866c31b3c5 546 return event;
AnnaBridge 172:7d866c31b3c5 547 }
AnnaBridge 172:7d866c31b3c5 548
AnnaBridge 172:7d866c31b3c5 549 /**
AnnaBridge 172:7d866c31b3c5 550 * Send words from the SPI TX buffer until the send limit is reached or the TX FIFO is full
AnnaBridge 172:7d866c31b3c5 551 * tx_limit is provided to ensure that the number of SPI frames (words) in flight can be managed.
AnnaBridge 172:7d866c31b3c5 552 * @param[in] obj The SPI object on which to operate
AnnaBridge 172:7d866c31b3c5 553 * @param[in] tx_limit The maximum number of words to send
AnnaBridge 172:7d866c31b3c5 554 * @return The number of SPI words that have been transfered
AnnaBridge 172:7d866c31b3c5 555 */
AnnaBridge 172:7d866c31b3c5 556 static uint32_t spi_master_write_asynch(spi_t *obj, uint32_t tx_limit)
AnnaBridge 172:7d866c31b3c5 557 {
AnnaBridge 172:7d866c31b3c5 558 uint32_t n_words = 0;
AnnaBridge 172:7d866c31b3c5 559 uint32_t tx_rmn = obj->tx_buff.length - obj->tx_buff.pos;
AnnaBridge 172:7d866c31b3c5 560 uint32_t rx_rmn = obj->rx_buff.length - obj->rx_buff.pos;
AnnaBridge 172:7d866c31b3c5 561 uint32_t max_tx = NU_MAX(tx_rmn, rx_rmn);
AnnaBridge 172:7d866c31b3c5 562 max_tx = NU_MIN(max_tx, tx_limit);
AnnaBridge 172:7d866c31b3c5 563 uint8_t data_width = spi_get_data_width(obj);
AnnaBridge 172:7d866c31b3c5 564 uint8_t bytes_per_word = (data_width + 7) / 8;
AnnaBridge 172:7d866c31b3c5 565 uint8_t *tx = (uint8_t *)(obj->tx_buff.buffer) + bytes_per_word * obj->tx_buff.pos;
AnnaBridge 172:7d866c31b3c5 566 SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 567
AnnaBridge 172:7d866c31b3c5 568 while ((n_words < max_tx) && spi_writeable(obj)) {
AnnaBridge 172:7d866c31b3c5 569 if (spi_is_tx_complete(obj)) {
AnnaBridge 172:7d866c31b3c5 570 // Transmit dummy as transmit buffer is empty
AnnaBridge 172:7d866c31b3c5 571 SPI_WRITE_TX(spi_base, 0);
AnnaBridge 172:7d866c31b3c5 572 } else {
AnnaBridge 172:7d866c31b3c5 573 switch (bytes_per_word) {
AnnaBridge 172:7d866c31b3c5 574 case 4:
AnnaBridge 172:7d866c31b3c5 575 SPI_WRITE_TX(spi_base, nu_get32_le(tx));
AnnaBridge 172:7d866c31b3c5 576 tx += 4;
AnnaBridge 172:7d866c31b3c5 577 break;
AnnaBridge 172:7d866c31b3c5 578 case 2:
AnnaBridge 172:7d866c31b3c5 579 SPI_WRITE_TX(spi_base, nu_get16_le(tx));
AnnaBridge 172:7d866c31b3c5 580 tx += 2;
AnnaBridge 172:7d866c31b3c5 581 break;
AnnaBridge 172:7d866c31b3c5 582 case 1:
AnnaBridge 172:7d866c31b3c5 583 SPI_WRITE_TX(spi_base, *((uint8_t *) tx));
AnnaBridge 172:7d866c31b3c5 584 tx += 1;
AnnaBridge 172:7d866c31b3c5 585 break;
AnnaBridge 172:7d866c31b3c5 586 }
AnnaBridge 172:7d866c31b3c5 587
AnnaBridge 172:7d866c31b3c5 588 obj->tx_buff.pos ++;
AnnaBridge 172:7d866c31b3c5 589 }
AnnaBridge 172:7d866c31b3c5 590 n_words ++;
AnnaBridge 172:7d866c31b3c5 591 }
AnnaBridge 172:7d866c31b3c5 592
AnnaBridge 172:7d866c31b3c5 593 //Return the number of words that have been sent
AnnaBridge 172:7d866c31b3c5 594 return n_words;
AnnaBridge 172:7d866c31b3c5 595 }
AnnaBridge 172:7d866c31b3c5 596
AnnaBridge 172:7d866c31b3c5 597 /**
AnnaBridge 172:7d866c31b3c5 598 * Read SPI words out of the RX FIFO
AnnaBridge 172:7d866c31b3c5 599 * Continues reading words out of the RX FIFO until the following condition is met:
AnnaBridge 172:7d866c31b3c5 600 * o There are no more words in the FIFO
AnnaBridge 172:7d866c31b3c5 601 * OR BOTH OF:
AnnaBridge 172:7d866c31b3c5 602 * o At least as many words as the TX buffer have been received
AnnaBridge 172:7d866c31b3c5 603 * o At least as many words as the RX buffer have been received
AnnaBridge 172:7d866c31b3c5 604 * This way, RX overflows are not generated when the TX buffer size exceeds the RX buffer size
AnnaBridge 172:7d866c31b3c5 605 * @param[in] obj The SPI object on which to operate
AnnaBridge 172:7d866c31b3c5 606 * @return Returns the number of words extracted from the RX FIFO
AnnaBridge 172:7d866c31b3c5 607 */
AnnaBridge 172:7d866c31b3c5 608 static uint32_t spi_master_read_asynch(spi_t *obj)
AnnaBridge 172:7d866c31b3c5 609 {
AnnaBridge 172:7d866c31b3c5 610 uint32_t n_words = 0;
AnnaBridge 172:7d866c31b3c5 611 uint32_t tx_rmn = obj->tx_buff.length - obj->tx_buff.pos;
AnnaBridge 172:7d866c31b3c5 612 uint32_t rx_rmn = obj->rx_buff.length - obj->rx_buff.pos;
AnnaBridge 172:7d866c31b3c5 613 uint32_t max_rx = NU_MAX(tx_rmn, rx_rmn);
AnnaBridge 172:7d866c31b3c5 614 uint8_t data_width = spi_get_data_width(obj);
AnnaBridge 172:7d866c31b3c5 615 uint8_t bytes_per_word = (data_width + 7) / 8;
AnnaBridge 172:7d866c31b3c5 616 uint8_t *rx = (uint8_t *)(obj->rx_buff.buffer) + bytes_per_word * obj->rx_buff.pos;
AnnaBridge 172:7d866c31b3c5 617 SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 618
AnnaBridge 172:7d866c31b3c5 619 while ((n_words < max_rx) && spi_readable(obj)) {
AnnaBridge 172:7d866c31b3c5 620 if (spi_is_rx_complete(obj)) {
AnnaBridge 172:7d866c31b3c5 621 // Disregard as receive buffer is full
AnnaBridge 172:7d866c31b3c5 622 SPI_READ_RX(spi_base);
AnnaBridge 172:7d866c31b3c5 623 } else {
AnnaBridge 172:7d866c31b3c5 624 switch (bytes_per_word) {
AnnaBridge 172:7d866c31b3c5 625 case 4: {
AnnaBridge 172:7d866c31b3c5 626 uint32_t val = SPI_READ_RX(spi_base);
AnnaBridge 172:7d866c31b3c5 627 nu_set32_le(rx, val);
AnnaBridge 172:7d866c31b3c5 628 rx += 4;
AnnaBridge 172:7d866c31b3c5 629 break;
AnnaBridge 172:7d866c31b3c5 630 }
AnnaBridge 172:7d866c31b3c5 631 case 2: {
AnnaBridge 172:7d866c31b3c5 632 uint16_t val = SPI_READ_RX(spi_base);
AnnaBridge 172:7d866c31b3c5 633 nu_set16_le(rx, val);
AnnaBridge 172:7d866c31b3c5 634 rx += 2;
AnnaBridge 172:7d866c31b3c5 635 break;
AnnaBridge 172:7d866c31b3c5 636 }
AnnaBridge 172:7d866c31b3c5 637 case 1:
AnnaBridge 172:7d866c31b3c5 638 *rx ++ = SPI_READ_RX(spi_base);
AnnaBridge 172:7d866c31b3c5 639 break;
AnnaBridge 172:7d866c31b3c5 640 }
AnnaBridge 172:7d866c31b3c5 641
AnnaBridge 172:7d866c31b3c5 642 obj->rx_buff.pos ++;
AnnaBridge 172:7d866c31b3c5 643 }
AnnaBridge 172:7d866c31b3c5 644 n_words ++;
AnnaBridge 172:7d866c31b3c5 645 }
AnnaBridge 172:7d866c31b3c5 646
AnnaBridge 172:7d866c31b3c5 647 // Return the number of words received
AnnaBridge 172:7d866c31b3c5 648 return n_words;
AnnaBridge 172:7d866c31b3c5 649 }
AnnaBridge 172:7d866c31b3c5 650
AnnaBridge 172:7d866c31b3c5 651 static void spi_buffer_set(spi_t *obj, const void *tx, size_t tx_length, void *rx, size_t rx_length)
AnnaBridge 172:7d866c31b3c5 652 {
AnnaBridge 172:7d866c31b3c5 653 obj->tx_buff.buffer = (void *) tx;
AnnaBridge 172:7d866c31b3c5 654 obj->tx_buff.length = tx_length;
AnnaBridge 172:7d866c31b3c5 655 obj->tx_buff.pos = 0;
AnnaBridge 172:7d866c31b3c5 656 obj->tx_buff.width = spi_get_data_width(obj);
AnnaBridge 172:7d866c31b3c5 657 obj->rx_buff.buffer = rx;
AnnaBridge 172:7d866c31b3c5 658 obj->rx_buff.length = rx_length;
AnnaBridge 172:7d866c31b3c5 659 obj->rx_buff.pos = 0;
AnnaBridge 172:7d866c31b3c5 660 obj->rx_buff.width = spi_get_data_width(obj);
AnnaBridge 172:7d866c31b3c5 661 }
AnnaBridge 172:7d866c31b3c5 662
AnnaBridge 172:7d866c31b3c5 663 static void spi_check_dma_usage(DMAUsage *dma_usage, int *dma_ch_tx, int *dma_ch_rx)
AnnaBridge 172:7d866c31b3c5 664 {
AnnaBridge 172:7d866c31b3c5 665 if (*dma_usage != DMA_USAGE_NEVER) {
AnnaBridge 172:7d866c31b3c5 666 if (*dma_ch_tx == DMA_ERROR_OUT_OF_CHANNELS) {
AnnaBridge 172:7d866c31b3c5 667 *dma_ch_tx = dma_channel_allocate(DMA_CAP_NONE);
AnnaBridge 172:7d866c31b3c5 668 }
AnnaBridge 172:7d866c31b3c5 669 if (*dma_ch_rx == DMA_ERROR_OUT_OF_CHANNELS) {
AnnaBridge 172:7d866c31b3c5 670 *dma_ch_rx = dma_channel_allocate(DMA_CAP_NONE);
AnnaBridge 172:7d866c31b3c5 671 }
AnnaBridge 172:7d866c31b3c5 672
AnnaBridge 172:7d866c31b3c5 673 if (*dma_ch_tx == DMA_ERROR_OUT_OF_CHANNELS || *dma_ch_rx == DMA_ERROR_OUT_OF_CHANNELS) {
AnnaBridge 172:7d866c31b3c5 674 *dma_usage = DMA_USAGE_NEVER;
AnnaBridge 172:7d866c31b3c5 675 }
AnnaBridge 172:7d866c31b3c5 676 }
AnnaBridge 172:7d866c31b3c5 677
AnnaBridge 172:7d866c31b3c5 678 if (*dma_usage == DMA_USAGE_NEVER) {
AnnaBridge 172:7d866c31b3c5 679 dma_channel_free(*dma_ch_tx);
AnnaBridge 172:7d866c31b3c5 680 *dma_ch_tx = DMA_ERROR_OUT_OF_CHANNELS;
AnnaBridge 172:7d866c31b3c5 681 dma_channel_free(*dma_ch_rx);
AnnaBridge 172:7d866c31b3c5 682 *dma_ch_rx = DMA_ERROR_OUT_OF_CHANNELS;
AnnaBridge 172:7d866c31b3c5 683 }
AnnaBridge 172:7d866c31b3c5 684 }
AnnaBridge 172:7d866c31b3c5 685
AnnaBridge 172:7d866c31b3c5 686 static uint8_t spi_get_data_width(spi_t *obj)
AnnaBridge 172:7d866c31b3c5 687 {
AnnaBridge 172:7d866c31b3c5 688 SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 689
AnnaBridge 172:7d866c31b3c5 690 uint32_t data_width = ((spi_base->CTL & SPI_CTL_DWIDTH_Msk) >> SPI_CTL_DWIDTH_Pos);
AnnaBridge 172:7d866c31b3c5 691 if (data_width == 0) {
AnnaBridge 172:7d866c31b3c5 692 data_width = 32;
AnnaBridge 172:7d866c31b3c5 693 }
AnnaBridge 172:7d866c31b3c5 694
AnnaBridge 172:7d866c31b3c5 695 return data_width;
AnnaBridge 172:7d866c31b3c5 696 }
AnnaBridge 172:7d866c31b3c5 697
AnnaBridge 172:7d866c31b3c5 698 static int spi_is_tx_complete(spi_t *obj)
AnnaBridge 172:7d866c31b3c5 699 {
AnnaBridge 172:7d866c31b3c5 700 return (obj->tx_buff.pos == obj->tx_buff.length);
AnnaBridge 172:7d866c31b3c5 701 }
AnnaBridge 172:7d866c31b3c5 702
AnnaBridge 172:7d866c31b3c5 703 static int spi_is_rx_complete(spi_t *obj)
AnnaBridge 172:7d866c31b3c5 704 {
AnnaBridge 172:7d866c31b3c5 705 return (obj->rx_buff.pos == obj->rx_buff.length);
AnnaBridge 172:7d866c31b3c5 706 }
AnnaBridge 172:7d866c31b3c5 707
AnnaBridge 172:7d866c31b3c5 708 static void spi_dma_handler_tx(uint32_t id, uint32_t event_dma)
AnnaBridge 172:7d866c31b3c5 709 {
AnnaBridge 172:7d866c31b3c5 710 spi_t *obj = (spi_t *) id;
AnnaBridge 172:7d866c31b3c5 711
AnnaBridge 172:7d866c31b3c5 712 // FIXME: Pass this error to caller
AnnaBridge 172:7d866c31b3c5 713 if (event_dma & DMA_EVENT_ABORT) {
AnnaBridge 172:7d866c31b3c5 714 }
AnnaBridge 172:7d866c31b3c5 715 // Expect SPI IRQ will catch this transfer done event
AnnaBridge 172:7d866c31b3c5 716 if (event_dma & DMA_EVENT_TRANSFER_DONE) {
AnnaBridge 172:7d866c31b3c5 717 obj->tx_buff.pos = obj->tx_buff.length;
AnnaBridge 172:7d866c31b3c5 718 }
AnnaBridge 172:7d866c31b3c5 719 // FIXME: Pass this error to caller
AnnaBridge 172:7d866c31b3c5 720 if (event_dma & DMA_EVENT_TIMEOUT) {
AnnaBridge 172:7d866c31b3c5 721 }
AnnaBridge 172:7d866c31b3c5 722
AnnaBridge 172:7d866c31b3c5 723 const struct nu_modinit_s *modinit = get_modinit(obj->spi.spi, spi_modinit_tab);
AnnaBridge 172:7d866c31b3c5 724 MBED_ASSERT(modinit != NULL);
AnnaBridge 172:7d866c31b3c5 725 MBED_ASSERT(modinit->modname == (int) obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 726
AnnaBridge 172:7d866c31b3c5 727 void (*vec)(void) = (void (*)(void)) NVIC_GetVector(modinit->irq_n);
AnnaBridge 172:7d866c31b3c5 728 vec();
AnnaBridge 172:7d866c31b3c5 729 }
AnnaBridge 172:7d866c31b3c5 730
AnnaBridge 172:7d866c31b3c5 731 static void spi_dma_handler_rx(uint32_t id, uint32_t event_dma)
AnnaBridge 172:7d866c31b3c5 732 {
AnnaBridge 172:7d866c31b3c5 733 spi_t *obj = (spi_t *) id;
AnnaBridge 172:7d866c31b3c5 734
AnnaBridge 172:7d866c31b3c5 735 // FIXME: Pass this error to caller
AnnaBridge 172:7d866c31b3c5 736 if (event_dma & DMA_EVENT_ABORT) {
AnnaBridge 172:7d866c31b3c5 737 }
AnnaBridge 172:7d866c31b3c5 738 // Expect SPI IRQ will catch this transfer done event
AnnaBridge 172:7d866c31b3c5 739 if (event_dma & DMA_EVENT_TRANSFER_DONE) {
AnnaBridge 172:7d866c31b3c5 740 obj->rx_buff.pos = obj->rx_buff.length;
AnnaBridge 172:7d866c31b3c5 741 }
AnnaBridge 172:7d866c31b3c5 742 // FIXME: Pass this error to caller
AnnaBridge 172:7d866c31b3c5 743 if (event_dma & DMA_EVENT_TIMEOUT) {
AnnaBridge 172:7d866c31b3c5 744 }
AnnaBridge 172:7d866c31b3c5 745
AnnaBridge 172:7d866c31b3c5 746 const struct nu_modinit_s *modinit = get_modinit(obj->spi.spi, spi_modinit_tab);
AnnaBridge 172:7d866c31b3c5 747 MBED_ASSERT(modinit != NULL);
AnnaBridge 172:7d866c31b3c5 748 MBED_ASSERT(modinit->modname == (int) obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 749
AnnaBridge 172:7d866c31b3c5 750 void (*vec)(void) = (void (*)(void)) NVIC_GetVector(modinit->irq_n);
AnnaBridge 172:7d866c31b3c5 751 vec();
AnnaBridge 172:7d866c31b3c5 752 }
AnnaBridge 172:7d866c31b3c5 753
AnnaBridge 172:7d866c31b3c5 754 /** Return FIFO depth of the SPI peripheral
AnnaBridge 172:7d866c31b3c5 755 *
AnnaBridge 172:7d866c31b3c5 756 * @details
AnnaBridge 172:7d866c31b3c5 757 * M487
AnnaBridge 172:7d866c31b3c5 758 * SPI0 8
AnnaBridge 172:7d866c31b3c5 759 * SPI1/2/3/4 8 if data width <=16; 4 otherwise
AnnaBridge 172:7d866c31b3c5 760 */
AnnaBridge 172:7d866c31b3c5 761 static uint32_t spi_fifo_depth(spi_t *obj)
AnnaBridge 172:7d866c31b3c5 762 {
AnnaBridge 172:7d866c31b3c5 763 SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
AnnaBridge 172:7d866c31b3c5 764
AnnaBridge 172:7d866c31b3c5 765 if (spi_base == SPI0) {
AnnaBridge 172:7d866c31b3c5 766 return 8;
AnnaBridge 172:7d866c31b3c5 767 }
AnnaBridge 172:7d866c31b3c5 768
AnnaBridge 172:7d866c31b3c5 769 return (spi_get_data_width(obj) <= 16) ? 8 : 4;
AnnaBridge 172:7d866c31b3c5 770 }
AnnaBridge 172:7d866c31b3c5 771
AnnaBridge 172:7d866c31b3c5 772 #endif
AnnaBridge 172:7d866c31b3c5 773
AnnaBridge 172:7d866c31b3c5 774 #endif