Color Oled(SSD1331) connect to STMicroelectronics Nucleo-F466

Dependencies:   ssd1331

Committer:
kadonotakashi
Date:
Thu Oct 11 02:27:46 2018 +0000
Revision:
3:f3764f852aa8
Parent:
0:8fdf9a60065b
Nucreo 446 + SSD1331 test version;

Who changed what in which revision?

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