added prescaler for 16 bit pwm in LPC1347 target

Fork of mbed-dev by mbed official

Committer:
JojoS
Date:
Sat Sep 10 15:32:04 2016 +0000
Revision:
147:ba84b7dc41a7
Parent:
144:ef7eb2e8f9f7
added prescaler for 16 bit timers (solution as in LPC11xx), default prescaler 31 for max 28 ms period time

Who changed what in which revision?

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