added prescaler for 16 bit pwm in LPC1347 target

Fork of mbed-dev by mbed official

Committer:
mbed_official
Date:
Thu Jan 28 18:15:10 2016 +0000
Revision:
54:2a2065e67ef6
Parent:
50:a417edff4437
Child:
144:ef7eb2e8f9f7
Synchronized with git revision b5816d872d02a7420c05be91bea5f898b88d2e56

Full URL: https://github.com/mbedmicro/mbed/commit/b5816d872d02a7420c05be91bea5f898b88d2e56/

[Silicon Labs] Fix support for the RC oscillator

Who changed what in which revision?

UserRevisionLine numberNew contents of line
bogdanm 0:9b334a45a8ff 1 /***************************************************************************//**
bogdanm 0:9b334a45a8ff 2 * @file spi_api.c
bogdanm 0:9b334a45a8ff 3 *******************************************************************************
bogdanm 0:9b334a45a8ff 4 * @section License
bogdanm 0:9b334a45a8ff 5 * <b>(C) Copyright 2015 Silicon Labs, http://www.silabs.com</b>
bogdanm 0:9b334a45a8ff 6 *******************************************************************************
bogdanm 0:9b334a45a8ff 7 *
bogdanm 0:9b334a45a8ff 8 * Permission is granted to anyone to use this software for any purpose,
bogdanm 0:9b334a45a8ff 9 * including commercial applications, and to alter it and redistribute it
bogdanm 0:9b334a45a8ff 10 * freely, subject to the following restrictions:
bogdanm 0:9b334a45a8ff 11 *
bogdanm 0:9b334a45a8ff 12 * 1. The origin of this software must not be misrepresented; you must not
bogdanm 0:9b334a45a8ff 13 * claim that you wrote the original software.
bogdanm 0:9b334a45a8ff 14 * 2. Altered source versions must be plainly marked as such, and must not be
bogdanm 0:9b334a45a8ff 15 * misrepresented as being the original software.
bogdanm 0:9b334a45a8ff 16 * 3. This notice may not be removed or altered from any source distribution.
bogdanm 0:9b334a45a8ff 17 *
bogdanm 0:9b334a45a8ff 18 * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no
bogdanm 0:9b334a45a8ff 19 * obligation to support this Software. Silicon Labs is providing the
bogdanm 0:9b334a45a8ff 20 * Software "AS IS", with no express or implied warranties of any kind,
bogdanm 0:9b334a45a8ff 21 * including, but not limited to, any implied warranties of merchantability
bogdanm 0:9b334a45a8ff 22 * or fitness for any particular purpose or warranties against infringement
bogdanm 0:9b334a45a8ff 23 * of any proprietary rights of a third party.
bogdanm 0:9b334a45a8ff 24 *
bogdanm 0:9b334a45a8ff 25 * Silicon Labs will not be liable for any consequential, incidental, or
bogdanm 0:9b334a45a8ff 26 * special damages, or any other relief, or for any claim by any third party,
bogdanm 0:9b334a45a8ff 27 * arising from your use of this Software.
bogdanm 0:9b334a45a8ff 28 *
bogdanm 0:9b334a45a8ff 29 ******************************************************************************/
bogdanm 0:9b334a45a8ff 30
bogdanm 0:9b334a45a8ff 31 #include "device.h"
bogdanm 0:9b334a45a8ff 32 #include "clocking.h"
bogdanm 0:9b334a45a8ff 33 #if DEVICE_SPI
bogdanm 0:9b334a45a8ff 34
bogdanm 0:9b334a45a8ff 35 #include "mbed_assert.h"
bogdanm 0:9b334a45a8ff 36 #include "PeripheralPins.h"
bogdanm 0:9b334a45a8ff 37 #include "pinmap.h"
bogdanm 0:9b334a45a8ff 38 #include "pinmap_function.h"
bogdanm 0:9b334a45a8ff 39 #include "error.h"
bogdanm 0:9b334a45a8ff 40
bogdanm 0:9b334a45a8ff 41 #include "dma_api.h"
bogdanm 0:9b334a45a8ff 42 #include "dma_api_HAL.h"
mbed_official 50:a417edff4437 43 #include "serial_api_HAL.h"
bogdanm 0:9b334a45a8ff 44 #include "spi_api.h"
bogdanm 0:9b334a45a8ff 45 #include "em_usart.h"
bogdanm 0:9b334a45a8ff 46 #include "em_cmu.h"
bogdanm 0:9b334a45a8ff 47 #include "em_dma.h"
bogdanm 0:9b334a45a8ff 48 #include "sleep_api.h"
bogdanm 0:9b334a45a8ff 49 #include "sleepmodes.h"
bogdanm 0:9b334a45a8ff 50
bogdanm 0:9b334a45a8ff 51 static uint16_t fill_word = SPI_FILL_WORD;
mbed_official 50:a417edff4437 52
bogdanm 0:9b334a45a8ff 53 #define SPI_LEAST_ACTIVE_SLEEPMODE EM1
bogdanm 0:9b334a45a8ff 54
mbed_official 22:9c52de9bc1d7 55 static inline CMU_Clock_TypeDef spi_get_clock_tree(spi_t *obj)
bogdanm 0:9b334a45a8ff 56 {
bogdanm 0:9b334a45a8ff 57 switch ((int)obj->spi.spi) {
bogdanm 0:9b334a45a8ff 58 #ifdef USART0
bogdanm 0:9b334a45a8ff 59 case SPI_0:
bogdanm 0:9b334a45a8ff 60 return cmuClock_USART0;
bogdanm 0:9b334a45a8ff 61 #endif
bogdanm 0:9b334a45a8ff 62 #ifdef USART1
bogdanm 0:9b334a45a8ff 63 case SPI_1:
bogdanm 0:9b334a45a8ff 64 return cmuClock_USART1;
bogdanm 0:9b334a45a8ff 65 #endif
bogdanm 0:9b334a45a8ff 66 #ifdef USART2
bogdanm 0:9b334a45a8ff 67 case SPI_2:
bogdanm 0:9b334a45a8ff 68 return cmuClock_USART2;
bogdanm 0:9b334a45a8ff 69 #endif
bogdanm 0:9b334a45a8ff 70 default:
bogdanm 0:9b334a45a8ff 71 error("Spi module not available.. Out of bound access.");
bogdanm 0:9b334a45a8ff 72 return cmuClock_HFPER;
bogdanm 0:9b334a45a8ff 73 }
bogdanm 0:9b334a45a8ff 74 }
bogdanm 0:9b334a45a8ff 75
mbed_official 22:9c52de9bc1d7 76 static inline uint8_t spi_get_index(spi_t *obj)
bogdanm 0:9b334a45a8ff 77 {
bogdanm 0:9b334a45a8ff 78 uint8_t index = 0;
bogdanm 0:9b334a45a8ff 79 switch ((int)obj->spi.spi) {
bogdanm 0:9b334a45a8ff 80 #ifdef USART0
bogdanm 0:9b334a45a8ff 81 case SPI_0:
bogdanm 0:9b334a45a8ff 82 index = 0;
bogdanm 0:9b334a45a8ff 83 break;
bogdanm 0:9b334a45a8ff 84 #endif
bogdanm 0:9b334a45a8ff 85 #ifdef USART1
bogdanm 0:9b334a45a8ff 86 case SPI_1:
bogdanm 0:9b334a45a8ff 87 index = 1;
bogdanm 0:9b334a45a8ff 88 break;
bogdanm 0:9b334a45a8ff 89 #endif
bogdanm 0:9b334a45a8ff 90 #ifdef USART2
bogdanm 0:9b334a45a8ff 91 case SPI_2:
bogdanm 0:9b334a45a8ff 92 index = 2;
bogdanm 0:9b334a45a8ff 93 break;
bogdanm 0:9b334a45a8ff 94 #endif
bogdanm 0:9b334a45a8ff 95 default:
bogdanm 0:9b334a45a8ff 96 error("Spi module not available.. Out of bound access.");
bogdanm 0:9b334a45a8ff 97 break;
bogdanm 0:9b334a45a8ff 98 }
bogdanm 0:9b334a45a8ff 99 return index;
bogdanm 0:9b334a45a8ff 100 }
bogdanm 0:9b334a45a8ff 101
bogdanm 0:9b334a45a8ff 102 uint8_t spi_get_module(spi_t *obj)
bogdanm 0:9b334a45a8ff 103 {
bogdanm 0:9b334a45a8ff 104 return spi_get_index(obj);
bogdanm 0:9b334a45a8ff 105 }
bogdanm 0:9b334a45a8ff 106
bogdanm 0:9b334a45a8ff 107 static void usart_init(spi_t *obj, uint32_t baudrate, USART_Databits_TypeDef databits, bool master, USART_ClockMode_TypeDef clockMode )
bogdanm 0:9b334a45a8ff 108 {
bogdanm 0:9b334a45a8ff 109 USART_InitSync_TypeDef init = USART_INITSYNC_DEFAULT;
bogdanm 0:9b334a45a8ff 110 init.enable = usartDisable;
bogdanm 0:9b334a45a8ff 111 init.baudrate = baudrate;
bogdanm 0:9b334a45a8ff 112 init.databits = databits;
bogdanm 0:9b334a45a8ff 113 init.master = master;
mbed_official 50:a417edff4437 114 init.msbf = 1;
bogdanm 0:9b334a45a8ff 115 init.clockMode = clockMode;
bogdanm 0:9b334a45a8ff 116
mbed_official 50:a417edff4437 117 /* Determine the reference clock, because the correct clock may not be set up at init time (e.g. before main()) */
bogdanm 0:9b334a45a8ff 118 init.refFreq = REFERENCE_FREQUENCY;
bogdanm 0:9b334a45a8ff 119
bogdanm 0:9b334a45a8ff 120 USART_InitSync(obj->spi.spi, &init);
bogdanm 0:9b334a45a8ff 121 }
bogdanm 0:9b334a45a8ff 122
bogdanm 0:9b334a45a8ff 123 void spi_preinit(spi_t *obj, PinName mosi, PinName miso, PinName clk, PinName cs)
bogdanm 0:9b334a45a8ff 124 {
bogdanm 0:9b334a45a8ff 125 SPIName spi_mosi = (SPIName) pinmap_peripheral(mosi, PinMap_SPI_MOSI);
bogdanm 0:9b334a45a8ff 126 SPIName spi_miso = (SPIName) pinmap_peripheral(miso, PinMap_SPI_MISO);
bogdanm 0:9b334a45a8ff 127 SPIName spi_clk = (SPIName) pinmap_peripheral(clk, PinMap_SPI_CLK);
bogdanm 0:9b334a45a8ff 128 SPIName spi_cs = (SPIName) pinmap_peripheral(cs, PinMap_SPI_CS);
bogdanm 0:9b334a45a8ff 129 SPIName spi_data = (SPIName) pinmap_merge(spi_mosi, spi_miso);
bogdanm 0:9b334a45a8ff 130 SPIName spi_ctrl = (SPIName) pinmap_merge(spi_clk, spi_cs);
bogdanm 0:9b334a45a8ff 131
bogdanm 0:9b334a45a8ff 132 obj->spi.spi = (USART_TypeDef *) pinmap_merge(spi_data, spi_ctrl);
bogdanm 0:9b334a45a8ff 133 MBED_ASSERT((int) obj->spi.spi != NC);
bogdanm 0:9b334a45a8ff 134
bogdanm 0:9b334a45a8ff 135 if (cs != NC) { /* Slave mode */
bogdanm 0:9b334a45a8ff 136 obj->spi.master = false;
bogdanm 0:9b334a45a8ff 137 } else {
bogdanm 0:9b334a45a8ff 138 obj->spi.master = true;
bogdanm 0:9b334a45a8ff 139 }
bogdanm 0:9b334a45a8ff 140
mbed_official 50:a417edff4437 141 #if defined(_SILICON_LABS_32B_PLATFORM_1)
mbed_official 50:a417edff4437 142 // On P1, we need to ensure all pins are on same location
bogdanm 0:9b334a45a8ff 143 uint32_t loc_mosi = pin_location(mosi, PinMap_SPI_MOSI);
bogdanm 0:9b334a45a8ff 144 uint32_t loc_miso = pin_location(miso, PinMap_SPI_MISO);
bogdanm 0:9b334a45a8ff 145 uint32_t loc_clk = pin_location(clk, PinMap_SPI_CLK);
bogdanm 0:9b334a45a8ff 146 uint32_t loc_cs = pin_location(cs, PinMap_SPI_CS);
bogdanm 0:9b334a45a8ff 147 uint32_t loc_data = pinmap_merge(loc_mosi, loc_miso);
bogdanm 0:9b334a45a8ff 148 uint32_t loc_ctrl = pinmap_merge(loc_clk, loc_cs);
bogdanm 0:9b334a45a8ff 149 obj->spi.location = pinmap_merge(loc_data, loc_ctrl);
bogdanm 0:9b334a45a8ff 150 MBED_ASSERT(obj->spi.location != NC);
mbed_official 50:a417edff4437 151 #endif
bogdanm 0:9b334a45a8ff 152
bogdanm 0:9b334a45a8ff 153 obj->spi.dmaOptionsTX.dmaUsageState = DMA_USAGE_OPPORTUNISTIC;
bogdanm 0:9b334a45a8ff 154 }
bogdanm 0:9b334a45a8ff 155
bogdanm 0:9b334a45a8ff 156 void spi_enable_pins(spi_t *obj, uint8_t enable, PinName mosi, PinName miso, PinName clk, PinName cs)
bogdanm 0:9b334a45a8ff 157 {
bogdanm 0:9b334a45a8ff 158 if (enable) {
bogdanm 0:9b334a45a8ff 159 if (obj->spi.master) { /* Master mode */
bogdanm 0:9b334a45a8ff 160 /* Either mosi or miso can be NC */
bogdanm 0:9b334a45a8ff 161 if (mosi != NC) {
bogdanm 0:9b334a45a8ff 162 pin_mode(mosi, PushPull);
bogdanm 0:9b334a45a8ff 163 }
bogdanm 0:9b334a45a8ff 164 if (miso != NC) {
bogdanm 0:9b334a45a8ff 165 pin_mode(miso, Input);
bogdanm 0:9b334a45a8ff 166 }
bogdanm 0:9b334a45a8ff 167 pin_mode(clk, PushPull);
bogdanm 0:9b334a45a8ff 168 /* Don't set cs pin, since we toggle it manually */
bogdanm 0:9b334a45a8ff 169 } else { /* Slave mode */
bogdanm 0:9b334a45a8ff 170 if (mosi != NC) {
bogdanm 0:9b334a45a8ff 171 pin_mode(mosi, Input);
bogdanm 0:9b334a45a8ff 172 }
bogdanm 0:9b334a45a8ff 173 if (miso != NC) {
bogdanm 0:9b334a45a8ff 174 pin_mode(miso, PushPull);
bogdanm 0:9b334a45a8ff 175 }
bogdanm 0:9b334a45a8ff 176 pin_mode(clk, Input);
bogdanm 0:9b334a45a8ff 177 pin_mode(cs, Input);
bogdanm 0:9b334a45a8ff 178 }
bogdanm 0:9b334a45a8ff 179 } else {
bogdanm 0:9b334a45a8ff 180 // TODO_LP return PinMode to the previous state
bogdanm 0:9b334a45a8ff 181 if (obj->spi.master) { /* Master mode */
bogdanm 0:9b334a45a8ff 182 /* Either mosi or miso can be NC */
bogdanm 0:9b334a45a8ff 183 if (mosi != NC) {
bogdanm 0:9b334a45a8ff 184 pin_mode(mosi, Disabled);
bogdanm 0:9b334a45a8ff 185 }
bogdanm 0:9b334a45a8ff 186 if (miso != NC) {
bogdanm 0:9b334a45a8ff 187 pin_mode(miso, Disabled);
bogdanm 0:9b334a45a8ff 188 }
bogdanm 0:9b334a45a8ff 189 pin_mode(clk, Disabled);
bogdanm 0:9b334a45a8ff 190 /* Don't set cs pin, since we toggle it manually */
bogdanm 0:9b334a45a8ff 191 } else { /* Slave mode */
bogdanm 0:9b334a45a8ff 192 if (mosi != NC) {
bogdanm 0:9b334a45a8ff 193 pin_mode(mosi, Disabled);
bogdanm 0:9b334a45a8ff 194 }
bogdanm 0:9b334a45a8ff 195 if (miso != NC) {
bogdanm 0:9b334a45a8ff 196 pin_mode(miso, Disabled);
bogdanm 0:9b334a45a8ff 197 }
bogdanm 0:9b334a45a8ff 198 pin_mode(clk, Disabled);
bogdanm 0:9b334a45a8ff 199 pin_mode(cs, Disabled);
bogdanm 0:9b334a45a8ff 200 }
bogdanm 0:9b334a45a8ff 201 }
bogdanm 0:9b334a45a8ff 202
bogdanm 0:9b334a45a8ff 203 /* Enabling pins and setting location */
mbed_official 50:a417edff4437 204 #ifdef _USART_ROUTEPEN_RESETVALUE
mbed_official 50:a417edff4437 205 uint32_t route = USART_ROUTEPEN_CLKPEN;
mbed_official 50:a417edff4437 206 obj->spi.spi->ROUTELOC0 &= ~_USART_ROUTELOC0_CLKLOC_MASK;
mbed_official 50:a417edff4437 207 obj->spi.spi->ROUTELOC0 |= pin_location(clk, PinMap_SPI_CLK)<<_USART_ROUTELOC0_CLKLOC_SHIFT;
mbed_official 50:a417edff4437 208 if (mosi != NC) {
mbed_official 50:a417edff4437 209 route |= USART_ROUTEPEN_TXPEN;
mbed_official 50:a417edff4437 210 obj->spi.spi->ROUTELOC0 &= ~_USART_ROUTELOC0_TXLOC_MASK;
mbed_official 50:a417edff4437 211 obj->spi.spi->ROUTELOC0 |= pin_location(mosi, PinMap_SPI_MOSI)<<_USART_ROUTELOC0_TXLOC_SHIFT;
mbed_official 50:a417edff4437 212 }
mbed_official 50:a417edff4437 213 if (miso != NC) {
mbed_official 50:a417edff4437 214 route |= USART_ROUTEPEN_RXPEN;
mbed_official 50:a417edff4437 215 obj->spi.spi->ROUTELOC0 &= ~_USART_ROUTELOC0_RXLOC_MASK;
mbed_official 54:2a2065e67ef6 216 obj->spi.spi->ROUTELOC0 |= pin_location(miso, PinMap_SPI_MOSI)<<_USART_ROUTELOC0_RXLOC_SHIFT;
mbed_official 50:a417edff4437 217 }
mbed_official 50:a417edff4437 218 if (!obj->spi.master) {
mbed_official 50:a417edff4437 219 route |= USART_ROUTEPEN_CSPEN;
mbed_official 50:a417edff4437 220 obj->spi.spi->ROUTELOC0 &= ~_USART_ROUTELOC0_CSLOC_MASK;
mbed_official 54:2a2065e67ef6 221 obj->spi.spi->ROUTELOC0 |= pin_location(cs, PinMap_SPI_MOSI)<<_USART_ROUTELOC0_CSLOC_SHIFT;
mbed_official 50:a417edff4437 222 }
mbed_official 50:a417edff4437 223 obj->spi.spi->ROUTEPEN = route;
mbed_official 50:a417edff4437 224 }
mbed_official 50:a417edff4437 225 #else
bogdanm 0:9b334a45a8ff 226 uint32_t route = USART_ROUTE_CLKPEN | (obj->spi.location << _USART_ROUTE_LOCATION_SHIFT);
bogdanm 0:9b334a45a8ff 227
bogdanm 0:9b334a45a8ff 228 if (mosi != NC) {
bogdanm 0:9b334a45a8ff 229 route |= USART_ROUTE_TXPEN;
bogdanm 0:9b334a45a8ff 230 }
bogdanm 0:9b334a45a8ff 231 if (miso != NC) {
bogdanm 0:9b334a45a8ff 232 route |= USART_ROUTE_RXPEN;
bogdanm 0:9b334a45a8ff 233 }
bogdanm 0:9b334a45a8ff 234 if (!obj->spi.master) {
bogdanm 0:9b334a45a8ff 235 route |= USART_ROUTE_CSPEN;
bogdanm 0:9b334a45a8ff 236 }
bogdanm 0:9b334a45a8ff 237 obj->spi.spi->ROUTE = route;
bogdanm 0:9b334a45a8ff 238 }
mbed_official 50:a417edff4437 239 #endif
bogdanm 0:9b334a45a8ff 240 void spi_enable(spi_t *obj, uint8_t enable)
bogdanm 0:9b334a45a8ff 241 {
bogdanm 0:9b334a45a8ff 242 USART_Enable(obj->spi.spi, (enable ? usartEnable : usartDisable));
bogdanm 0:9b334a45a8ff 243 }
bogdanm 0:9b334a45a8ff 244
bogdanm 0:9b334a45a8ff 245 void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName clk, PinName cs)
bogdanm 0:9b334a45a8ff 246 {
bogdanm 0:9b334a45a8ff 247 CMU_ClockEnable(cmuClock_HFPER, true);
bogdanm 0:9b334a45a8ff 248 spi_preinit(obj, mosi, miso, clk, cs);
bogdanm 0:9b334a45a8ff 249 CMU_ClockEnable(spi_get_clock_tree(obj), true);
bogdanm 0:9b334a45a8ff 250 usart_init(obj, 100000, usartDatabits8, true, usartClockMode0);
bogdanm 0:9b334a45a8ff 251
bogdanm 0:9b334a45a8ff 252 spi_enable_pins(obj, true, mosi, miso, clk, cs);
bogdanm 0:9b334a45a8ff 253 spi_enable(obj, true);
bogdanm 0:9b334a45a8ff 254 }
bogdanm 0:9b334a45a8ff 255
bogdanm 0:9b334a45a8ff 256 void spi_enable_event(spi_t *obj, uint32_t event, uint8_t enable)
bogdanm 0:9b334a45a8ff 257 {
bogdanm 0:9b334a45a8ff 258 if(enable) obj->spi.event |= event;
bogdanm 0:9b334a45a8ff 259 else obj->spi.event &= ~event;
bogdanm 0:9b334a45a8ff 260 }
bogdanm 0:9b334a45a8ff 261
bogdanm 0:9b334a45a8ff 262 /****************************************************************************
bogdanm 0:9b334a45a8ff 263 * void spi_enable_interrupt(spi_t *obj, uint32_t handler, uint8_t enable)
bogdanm 0:9b334a45a8ff 264 *
bogdanm 0:9b334a45a8ff 265 * This will enable the interrupt in NVIC for the associated USART RX channel
bogdanm 0:9b334a45a8ff 266 *
bogdanm 0:9b334a45a8ff 267 * * obj: pointer to spi object
bogdanm 0:9b334a45a8ff 268 * * handler: pointer to interrupt handler for this channel
bogdanm 0:9b334a45a8ff 269 * * enable: Whether to enable (true) or disable (false) the interrupt
bogdanm 0:9b334a45a8ff 270 *
bogdanm 0:9b334a45a8ff 271 ****************************************************************************/
bogdanm 0:9b334a45a8ff 272 void spi_enable_interrupt(spi_t *obj, uint32_t handler, uint8_t enable)
bogdanm 0:9b334a45a8ff 273 {
bogdanm 0:9b334a45a8ff 274 IRQn_Type IRQvector;
bogdanm 0:9b334a45a8ff 275
bogdanm 0:9b334a45a8ff 276 switch ((uint32_t)obj->spi.spi) {
bogdanm 0:9b334a45a8ff 277 #ifdef USART0
bogdanm 0:9b334a45a8ff 278 case USART_0:
bogdanm 0:9b334a45a8ff 279 IRQvector = USART0_RX_IRQn;
bogdanm 0:9b334a45a8ff 280 break;
bogdanm 0:9b334a45a8ff 281 #endif
bogdanm 0:9b334a45a8ff 282 #ifdef USART1
bogdanm 0:9b334a45a8ff 283 case USART_1:
bogdanm 0:9b334a45a8ff 284 IRQvector = USART1_RX_IRQn;
bogdanm 0:9b334a45a8ff 285 break;
bogdanm 0:9b334a45a8ff 286 #endif
bogdanm 0:9b334a45a8ff 287 #ifdef USART2
bogdanm 0:9b334a45a8ff 288 case USART_2:
bogdanm 0:9b334a45a8ff 289 IRQvector = USART2_RX_IRQn;
bogdanm 0:9b334a45a8ff 290 break;
bogdanm 0:9b334a45a8ff 291 #endif
bogdanm 0:9b334a45a8ff 292 default:
bogdanm 0:9b334a45a8ff 293 error("Undefined SPI peripheral");
bogdanm 0:9b334a45a8ff 294 return;
bogdanm 0:9b334a45a8ff 295 }
bogdanm 0:9b334a45a8ff 296
bogdanm 0:9b334a45a8ff 297 if (enable == true) {
bogdanm 0:9b334a45a8ff 298 NVIC_SetVector(IRQvector, handler);
bogdanm 0:9b334a45a8ff 299 USART_IntEnable(obj->spi.spi, USART_IEN_RXDATAV);
bogdanm 0:9b334a45a8ff 300 NVIC_EnableIRQ(IRQvector);
bogdanm 0:9b334a45a8ff 301 } else {
bogdanm 0:9b334a45a8ff 302 NVIC_SetVector(IRQvector, handler);
bogdanm 0:9b334a45a8ff 303 USART_IntDisable(obj->spi.spi, USART_IEN_RXDATAV);
bogdanm 0:9b334a45a8ff 304 NVIC_DisableIRQ(IRQvector);
bogdanm 0:9b334a45a8ff 305 }
bogdanm 0:9b334a45a8ff 306 }
bogdanm 0:9b334a45a8ff 307
bogdanm 0:9b334a45a8ff 308 void spi_format(spi_t *obj, int bits, int mode, int slave)
bogdanm 0:9b334a45a8ff 309 {
bogdanm 0:9b334a45a8ff 310 /* Bits: values between 4 and 16 are valid */
bogdanm 0:9b334a45a8ff 311 MBED_ASSERT(bits >= 4 && bits <= 16);
bogdanm 0:9b334a45a8ff 312 obj->spi.bits = bits;
bogdanm 0:9b334a45a8ff 313 /* 0x01 = usartDatabits4, etc, up to 0x0D = usartDatabits16 */
bogdanm 0:9b334a45a8ff 314 USART_Databits_TypeDef databits = (USART_Databits_TypeDef) (bits - 3);
bogdanm 0:9b334a45a8ff 315
bogdanm 0:9b334a45a8ff 316 USART_ClockMode_TypeDef clockMode;
bogdanm 0:9b334a45a8ff 317 MBED_ASSERT(mode >= 0 && mode <= 3);
bogdanm 0:9b334a45a8ff 318 switch (mode) {
bogdanm 0:9b334a45a8ff 319 case 0:
bogdanm 0:9b334a45a8ff 320 clockMode = usartClockMode0;
bogdanm 0:9b334a45a8ff 321 break;
bogdanm 0:9b334a45a8ff 322 case 1:
bogdanm 0:9b334a45a8ff 323 clockMode = usartClockMode1;
bogdanm 0:9b334a45a8ff 324 break;
bogdanm 0:9b334a45a8ff 325 case 2:
bogdanm 0:9b334a45a8ff 326 clockMode = usartClockMode2;
bogdanm 0:9b334a45a8ff 327 break;
bogdanm 0:9b334a45a8ff 328 case 3:
bogdanm 0:9b334a45a8ff 329 clockMode = usartClockMode3;
bogdanm 0:9b334a45a8ff 330 break;
bogdanm 0:9b334a45a8ff 331 default:
bogdanm 0:9b334a45a8ff 332 clockMode = usartClockMode0;
bogdanm 0:9b334a45a8ff 333 }
bogdanm 0:9b334a45a8ff 334
bogdanm 0:9b334a45a8ff 335 //save state
mbed_official 50:a417edff4437 336 #ifdef _USART_ROUTEPEN_RESETVALUE
mbed_official 50:a417edff4437 337 uint32_t route = obj->spi.spi->ROUTEPEN;
mbed_official 50:a417edff4437 338 uint32_t loc = obj->spi.spi->ROUTELOC0;
mbed_official 50:a417edff4437 339 #else
bogdanm 0:9b334a45a8ff 340 uint32_t route = obj->spi.spi->ROUTE;
mbed_official 50:a417edff4437 341 #endif
bogdanm 0:9b334a45a8ff 342 uint32_t iflags = obj->spi.spi->IEN;
bogdanm 0:9b334a45a8ff 343 bool enabled = (obj->spi.spi->STATUS & (USART_STATUS_RXENS | USART_STATUS_TXENS)) != 0;
bogdanm 0:9b334a45a8ff 344
bogdanm 0:9b334a45a8ff 345 usart_init(obj, 100000, databits, (slave ? false : true), clockMode);
bogdanm 0:9b334a45a8ff 346
bogdanm 0:9b334a45a8ff 347 //restore state
mbed_official 50:a417edff4437 348 #ifdef _USART_ROUTEPEN_RESETVALUE
mbed_official 50:a417edff4437 349 obj->spi.spi->ROUTEPEN = route;
mbed_official 50:a417edff4437 350 obj->spi.spi->ROUTELOC0 = loc;
mbed_official 50:a417edff4437 351 #else
bogdanm 0:9b334a45a8ff 352 obj->spi.spi->ROUTE = route;
mbed_official 50:a417edff4437 353 #endif
bogdanm 0:9b334a45a8ff 354 obj->spi.spi->IEN = iflags;
bogdanm 0:9b334a45a8ff 355
bogdanm 0:9b334a45a8ff 356 if(enabled) spi_enable(obj, enabled);
bogdanm 0:9b334a45a8ff 357 }
bogdanm 0:9b334a45a8ff 358
bogdanm 0:9b334a45a8ff 359 void spi_frequency(spi_t *obj, int hz)
bogdanm 0:9b334a45a8ff 360 {
bogdanm 0:9b334a45a8ff 361 USART_BaudrateSyncSet(obj->spi.spi, REFERENCE_FREQUENCY, hz);
bogdanm 0:9b334a45a8ff 362 }
bogdanm 0:9b334a45a8ff 363
bogdanm 0:9b334a45a8ff 364 /* Read/Write */
bogdanm 0:9b334a45a8ff 365
bogdanm 0:9b334a45a8ff 366 void spi_write(spi_t *obj, int value)
bogdanm 0:9b334a45a8ff 367 {
bogdanm 0:9b334a45a8ff 368 if (obj->spi.bits <= 8) {
bogdanm 0:9b334a45a8ff 369 USART_Tx(obj->spi.spi, (uint8_t) value);
bogdanm 0:9b334a45a8ff 370 } else if (obj->spi.bits == 9) {
bogdanm 0:9b334a45a8ff 371 USART_TxExt(obj->spi.spi, (uint16_t) value & 0x1FF);
bogdanm 0:9b334a45a8ff 372 } else {
bogdanm 0:9b334a45a8ff 373 USART_TxDouble(obj->spi.spi, (uint16_t) value);
bogdanm 0:9b334a45a8ff 374 }
bogdanm 0:9b334a45a8ff 375 }
bogdanm 0:9b334a45a8ff 376
bogdanm 0:9b334a45a8ff 377 int spi_read(spi_t *obj)
bogdanm 0:9b334a45a8ff 378 {
bogdanm 0:9b334a45a8ff 379 if (obj->spi.bits <= 8) {
bogdanm 0:9b334a45a8ff 380 return (int) obj->spi.spi->RXDATA;
bogdanm 0:9b334a45a8ff 381 } else if (obj->spi.bits == 9) {
bogdanm 0:9b334a45a8ff 382 return (int) obj->spi.spi->RXDATAX & 0x1FF;
bogdanm 0:9b334a45a8ff 383 } else {
bogdanm 0:9b334a45a8ff 384 return (int) obj->spi.spi->RXDOUBLE;
bogdanm 0:9b334a45a8ff 385 }
bogdanm 0:9b334a45a8ff 386 }
bogdanm 0:9b334a45a8ff 387
bogdanm 0:9b334a45a8ff 388 int spi_read_asynch(spi_t *obj)
bogdanm 0:9b334a45a8ff 389 {
bogdanm 0:9b334a45a8ff 390 return spi_read(obj);
bogdanm 0:9b334a45a8ff 391 }
bogdanm 0:9b334a45a8ff 392
bogdanm 0:9b334a45a8ff 393 int spi_master_write(spi_t *obj, int value)
bogdanm 0:9b334a45a8ff 394 {
bogdanm 0:9b334a45a8ff 395 spi_write(obj, value);
bogdanm 0:9b334a45a8ff 396
bogdanm 0:9b334a45a8ff 397 /* Wait for transmission of last byte */
bogdanm 0:9b334a45a8ff 398 while (!(obj->spi.spi->STATUS & USART_STATUS_TXC)) {
bogdanm 0:9b334a45a8ff 399 }
bogdanm 0:9b334a45a8ff 400
bogdanm 0:9b334a45a8ff 401 return spi_read(obj);
bogdanm 0:9b334a45a8ff 402 }
bogdanm 0:9b334a45a8ff 403
bogdanm 0:9b334a45a8ff 404 inline uint8_t spi_master_tx_ready(spi_t *obj)
bogdanm 0:9b334a45a8ff 405 {
bogdanm 0:9b334a45a8ff 406 return (obj->spi.spi->STATUS & USART_STATUS_TXBL) ? true : false;
bogdanm 0:9b334a45a8ff 407 }
bogdanm 0:9b334a45a8ff 408
bogdanm 0:9b334a45a8ff 409 uint8_t spi_master_rx_ready(spi_t *obj)
bogdanm 0:9b334a45a8ff 410 {
bogdanm 0:9b334a45a8ff 411 return (obj->spi.spi->STATUS & USART_STATUS_RXDATAV) ? true : false;
bogdanm 0:9b334a45a8ff 412 }
bogdanm 0:9b334a45a8ff 413
bogdanm 0:9b334a45a8ff 414 uint8_t spi_master_tx_int_flag(spi_t *obj)
bogdanm 0:9b334a45a8ff 415 {
bogdanm 0:9b334a45a8ff 416 return (obj->spi.spi->IF & USART_IF_TXBL) ? true : false;
bogdanm 0:9b334a45a8ff 417 }
bogdanm 0:9b334a45a8ff 418
bogdanm 0:9b334a45a8ff 419 uint8_t spi_master_rx_int_flag(spi_t *obj)
bogdanm 0:9b334a45a8ff 420 {
bogdanm 0:9b334a45a8ff 421 return (obj->spi.spi->IF & (USART_IF_RXDATAV | USART_IF_RXFULL)) ? true : false;
bogdanm 0:9b334a45a8ff 422 }
bogdanm 0:9b334a45a8ff 423
bogdanm 0:9b334a45a8ff 424 void spi_master_read_asynch_complete(spi_t *obj)
bogdanm 0:9b334a45a8ff 425 {
bogdanm 0:9b334a45a8ff 426 obj->spi.spi->IFC = USART_IFC_RXFULL; // in case it got full
bogdanm 0:9b334a45a8ff 427 }
bogdanm 0:9b334a45a8ff 428
bogdanm 0:9b334a45a8ff 429 void spi_master_write_asynch_complete(spi_t *obj)
bogdanm 0:9b334a45a8ff 430 {
bogdanm 0:9b334a45a8ff 431 obj->spi.spi->IFC = USART_IFC_TXC;
bogdanm 0:9b334a45a8ff 432 }
bogdanm 0:9b334a45a8ff 433
bogdanm 0:9b334a45a8ff 434 void spi_irq_handler(spi_t *obj)
bogdanm 0:9b334a45a8ff 435 {
bogdanm 0:9b334a45a8ff 436 spi_read(obj); //TODO_LP store data to the object?
bogdanm 0:9b334a45a8ff 437 }
bogdanm 0:9b334a45a8ff 438
bogdanm 0:9b334a45a8ff 439 uint8_t spi_active(spi_t *obj)
bogdanm 0:9b334a45a8ff 440 {
bogdanm 0:9b334a45a8ff 441 switch(obj->spi.dmaOptionsTX.dmaUsageState) {
bogdanm 0:9b334a45a8ff 442 case DMA_USAGE_TEMPORARY_ALLOCATED:
bogdanm 0:9b334a45a8ff 443 return true;
bogdanm 0:9b334a45a8ff 444 case DMA_USAGE_ALLOCATED:
bogdanm 0:9b334a45a8ff 445 /* Check whether the allocated DMA channel is active */
mbed_official 50:a417edff4437 446 #ifdef LDMA_PRESENT
mbed_official 50:a417edff4437 447 return(LDMAx_ChannelEnabled(obj->spi.dmaOptionsTX.dmaChannel) || LDMAx_ChannelEnabled(obj->spi.dmaOptionsRX.dmaChannel));
mbed_official 50:a417edff4437 448 #else
bogdanm 0:9b334a45a8ff 449 return(DMA_ChannelEnabled(obj->spi.dmaOptionsTX.dmaChannel) || DMA_ChannelEnabled(obj->spi.dmaOptionsRX.dmaChannel));
mbed_official 50:a417edff4437 450 #endif
bogdanm 0:9b334a45a8ff 451 default:
bogdanm 0:9b334a45a8ff 452 /* Check whether interrupt for spi is enabled */
bogdanm 0:9b334a45a8ff 453 return (obj->spi.spi->IEN & (USART_IEN_RXDATAV | USART_IEN_TXBL)) ? true : false;
bogdanm 0:9b334a45a8ff 454 }
bogdanm 0:9b334a45a8ff 455 }
bogdanm 0:9b334a45a8ff 456
bogdanm 0:9b334a45a8ff 457 void spi_buffer_set(spi_t *obj, const void *tx, uint32_t tx_length, void *rx, uint32_t rx_length, uint8_t bit_width)
bogdanm 0:9b334a45a8ff 458 {
bogdanm 0:9b334a45a8ff 459 uint32_t i;
bogdanm 0:9b334a45a8ff 460 uint16_t *tx_ptr = (uint16_t *) tx;
bogdanm 0:9b334a45a8ff 461
bogdanm 0:9b334a45a8ff 462 obj->tx_buff.buffer = (void *)tx;
bogdanm 0:9b334a45a8ff 463 obj->rx_buff.buffer = rx;
bogdanm 0:9b334a45a8ff 464 obj->tx_buff.length = tx_length;
bogdanm 0:9b334a45a8ff 465 obj->rx_buff.length = rx_length;
bogdanm 0:9b334a45a8ff 466 obj->tx_buff.pos = 0;
bogdanm 0:9b334a45a8ff 467 obj->rx_buff.pos = 0;
bogdanm 0:9b334a45a8ff 468 obj->tx_buff.width = bit_width;
bogdanm 0:9b334a45a8ff 469 obj->rx_buff.width = bit_width;
bogdanm 0:9b334a45a8ff 470
bogdanm 0:9b334a45a8ff 471 if((obj->spi.bits == 9) && (tx != 0)) {
bogdanm 0:9b334a45a8ff 472 // Make sure we don't have inadvertent non-zero bits outside 9-bit frames which could trigger unwanted operation
bogdanm 0:9b334a45a8ff 473 for(i = 0; i < (tx_length / 2); i++) {
bogdanm 0:9b334a45a8ff 474 tx_ptr[i] &= 0x1FF;
bogdanm 0:9b334a45a8ff 475 }
bogdanm 0:9b334a45a8ff 476 }
bogdanm 0:9b334a45a8ff 477 }
bogdanm 0:9b334a45a8ff 478
bogdanm 0:9b334a45a8ff 479 static void spi_buffer_tx_write(spi_t *obj)
bogdanm 0:9b334a45a8ff 480 {
bogdanm 0:9b334a45a8ff 481 uint32_t data;
mbed_official 50:a417edff4437 482 if(obj->spi.bits >= 9) {
mbed_official 50:a417edff4437 483 // write double frame
mbed_official 50:a417edff4437 484 if (obj->tx_buff.buffer == (void *)0) {
mbed_official 50:a417edff4437 485 data = SPI_FILL_WORD;
mbed_official 50:a417edff4437 486 } else {
mbed_official 50:a417edff4437 487 uint16_t *tx = (uint16_t *)(obj->tx_buff.buffer);
mbed_official 50:a417edff4437 488 data = tx[obj->tx_buff.pos] & 0xFFFF;
bogdanm 0:9b334a45a8ff 489 }
mbed_official 50:a417edff4437 490 obj->tx_buff.pos += 1;
mbed_official 50:a417edff4437 491 if(obj->spi.bits == 9){
bogdanm 0:9b334a45a8ff 492 obj->spi.spi->TXDATAX = data;
mbed_official 50:a417edff4437 493 }else {
mbed_official 50:a417edff4437 494 obj->spi.spi->TXDOUBLE = data;
bogdanm 0:9b334a45a8ff 495 }
mbed_official 50:a417edff4437 496
mbed_official 50:a417edff4437 497 } else if (obj->tx_buff.pos < obj->tx_buff.length) {
mbed_official 50:a417edff4437 498 // write single frame
mbed_official 50:a417edff4437 499 if (obj->tx_buff.buffer == (void *)0) {
mbed_official 50:a417edff4437 500 data = SPI_FILL_WORD & 0xFF;
mbed_official 50:a417edff4437 501 } else {
mbed_official 50:a417edff4437 502 uint8_t *tx = (uint8_t *)(obj->tx_buff.buffer);
mbed_official 50:a417edff4437 503 data = tx[obj->tx_buff.pos] & 0xFF;
mbed_official 50:a417edff4437 504 }
mbed_official 50:a417edff4437 505 obj->tx_buff.pos++;
mbed_official 50:a417edff4437 506
mbed_official 50:a417edff4437 507 obj->spi.spi->TXDATA = data;
bogdanm 0:9b334a45a8ff 508 }
bogdanm 0:9b334a45a8ff 509 }
bogdanm 0:9b334a45a8ff 510
bogdanm 0:9b334a45a8ff 511 static void spi_buffer_rx_read(spi_t *obj)
bogdanm 0:9b334a45a8ff 512 {
bogdanm 0:9b334a45a8ff 513 if (obj->spi.bits % 9 != 0) {
bogdanm 0:9b334a45a8ff 514 if ((obj->spi.spi->STATUS & USART_STATUS_RXFULL) && (obj->rx_buff.pos < obj->rx_buff.length - 1) && ((obj->rx_buff.pos % 2) == 0)) {
bogdanm 0:9b334a45a8ff 515 // Read max 16 bits from buffer to speed things up
bogdanm 0:9b334a45a8ff 516 uint32_t data = (uint32_t)obj->spi.spi->RXDOUBLE; //read the data but store only if rx is set and not full
bogdanm 0:9b334a45a8ff 517 if (obj->rx_buff.buffer) {
bogdanm 0:9b334a45a8ff 518 uint16_t *rx = (uint16_t *)(obj->rx_buff.buffer);
bogdanm 0:9b334a45a8ff 519 rx[obj->rx_buff.pos / 2] = data & 0xFFFF;
bogdanm 0:9b334a45a8ff 520 obj->rx_buff.pos += 2;
bogdanm 0:9b334a45a8ff 521 }
bogdanm 0:9b334a45a8ff 522 } else if ((obj->spi.spi->STATUS & (USART_STATUS_RXDATAV | USART_STATUS_RXFULL)) && (obj->rx_buff.pos < obj->rx_buff.length)) {
bogdanm 0:9b334a45a8ff 523 // Read 8 bits from buffer
bogdanm 0:9b334a45a8ff 524 while((obj->spi.spi->STATUS & (USART_STATUS_RXDATAV | USART_STATUS_RXFULL)) && (obj->rx_buff.pos < obj->rx_buff.length)) {
bogdanm 0:9b334a45a8ff 525 uint32_t data = (uint32_t)obj->spi.spi->RXDATA; //read the data but store only if rx is set and not full
bogdanm 0:9b334a45a8ff 526 if (obj->rx_buff.buffer) {
bogdanm 0:9b334a45a8ff 527 uint8_t *rx = (uint8_t *)(obj->rx_buff.buffer);
bogdanm 0:9b334a45a8ff 528 rx[obj->rx_buff.pos] = data & 0xFF;
bogdanm 0:9b334a45a8ff 529 obj->rx_buff.pos++;
bogdanm 0:9b334a45a8ff 530 }
bogdanm 0:9b334a45a8ff 531 }
bogdanm 0:9b334a45a8ff 532 } else if (obj->spi.spi->STATUS & USART_STATUS_RXFULL) {
bogdanm 0:9b334a45a8ff 533 // Read from the buffer to lower the interrupt flag
bogdanm 0:9b334a45a8ff 534 volatile uint32_t data = (uint32_t)obj->spi.spi->RXDOUBLE;
bogdanm 0:9b334a45a8ff 535 } else if (obj->spi.spi->STATUS & USART_STATUS_RXDATAV) {
bogdanm 0:9b334a45a8ff 536 // Read from the buffer to lower the interrupt flag
bogdanm 0:9b334a45a8ff 537 volatile uint32_t data = (uint32_t)obj->spi.spi->RXDATA;
bogdanm 0:9b334a45a8ff 538 }
bogdanm 0:9b334a45a8ff 539 } else {
bogdanm 0:9b334a45a8ff 540 // Data bits is multiple of 9, so use the extended registers
bogdanm 0:9b334a45a8ff 541 if ((obj->spi.spi->STATUS & USART_STATUS_RXFULL) && (obj->rx_buff.pos < obj->rx_buff.length - 3) && ((obj->rx_buff.pos % 4) == 0)) {
bogdanm 0:9b334a45a8ff 542 // Read max 18 bits from buffer to speed things up
bogdanm 0:9b334a45a8ff 543 uint32_t data = (uint32_t)obj->spi.spi->RXDOUBLEX; //read the data but store only if rx is set and will not overflow
bogdanm 0:9b334a45a8ff 544 if (obj->rx_buff.buffer) {
bogdanm 0:9b334a45a8ff 545 uint16_t *rx = (uint16_t *)(obj->rx_buff.buffer);
bogdanm 0:9b334a45a8ff 546 rx[obj->rx_buff.pos / 2] = data & 0x000001FF;
bogdanm 0:9b334a45a8ff 547 rx[(obj->rx_buff.pos / 2) + 1] = (data & 0x01FF0000) >> 16;
bogdanm 0:9b334a45a8ff 548 obj->rx_buff.pos += 4;
bogdanm 0:9b334a45a8ff 549 }
bogdanm 0:9b334a45a8ff 550 } else if ((obj->spi.spi->STATUS & (USART_STATUS_RXDATAV | USART_STATUS_RXFULL)) && (obj->rx_buff.pos < obj->rx_buff.length - 1)) {
bogdanm 0:9b334a45a8ff 551 // Read 9 bits from buffer
bogdanm 0:9b334a45a8ff 552 while((obj->spi.spi->STATUS & (USART_STATUS_RXDATAV | USART_STATUS_RXFULL)) && (obj->rx_buff.pos < obj->rx_buff.length - 1)) {
bogdanm 0:9b334a45a8ff 553 uint32_t data = (uint32_t)obj->spi.spi->RXDATAX; //read the data but store only if rx is set and not full
bogdanm 0:9b334a45a8ff 554 if (obj->rx_buff.buffer) {
bogdanm 0:9b334a45a8ff 555 uint16_t *rx = (uint16_t *)(obj->rx_buff.buffer);
bogdanm 0:9b334a45a8ff 556 rx[obj->rx_buff.pos / 2] = data & 0x01FF;
bogdanm 0:9b334a45a8ff 557 obj->rx_buff.pos += 2;
bogdanm 0:9b334a45a8ff 558 }
bogdanm 0:9b334a45a8ff 559 }
bogdanm 0:9b334a45a8ff 560 } else if (obj->spi.spi->STATUS & USART_STATUS_RXFULL) {
bogdanm 0:9b334a45a8ff 561 // Read from the buffer to lower the interrupt flag
bogdanm 0:9b334a45a8ff 562 volatile uint32_t data = (uint32_t)obj->spi.spi->RXDOUBLEX;
bogdanm 0:9b334a45a8ff 563 } else if (obj->spi.spi->STATUS & USART_STATUS_RXDATAV) {
bogdanm 0:9b334a45a8ff 564 // Read from the buffer to lower the interrupt flag
bogdanm 0:9b334a45a8ff 565 volatile uint32_t data = (uint32_t)obj->spi.spi->RXDATAX;
bogdanm 0:9b334a45a8ff 566 }
bogdanm 0:9b334a45a8ff 567 }
bogdanm 0:9b334a45a8ff 568 }
bogdanm 0:9b334a45a8ff 569
bogdanm 0:9b334a45a8ff 570 int spi_master_write_asynch(spi_t *obj)
bogdanm 0:9b334a45a8ff 571 {
bogdanm 0:9b334a45a8ff 572 int ndata = 0;
bogdanm 0:9b334a45a8ff 573 while ((obj->tx_buff.pos < obj->tx_buff.length) && (obj->spi.spi->STATUS & USART_STATUS_TXBL)) {
bogdanm 0:9b334a45a8ff 574 spi_buffer_tx_write(obj);
bogdanm 0:9b334a45a8ff 575 ndata++;
bogdanm 0:9b334a45a8ff 576 }
bogdanm 0:9b334a45a8ff 577 return ndata;
bogdanm 0:9b334a45a8ff 578 }
bogdanm 0:9b334a45a8ff 579
bogdanm 0:9b334a45a8ff 580 int spi_master_read_asynch(spi_t *obj)
bogdanm 0:9b334a45a8ff 581 {
bogdanm 0:9b334a45a8ff 582 int ndata = 0;
bogdanm 0:9b334a45a8ff 583 while ((obj->rx_buff.pos < obj->rx_buff.length) && (obj->spi.spi->STATUS & (USART_STATUS_RXDATAV | USART_STATUS_RXFULL))) {
bogdanm 0:9b334a45a8ff 584 spi_buffer_rx_read(obj);
bogdanm 0:9b334a45a8ff 585 ndata++;
bogdanm 0:9b334a45a8ff 586 }
bogdanm 0:9b334a45a8ff 587 // all sent but still more to receive? need to align tx buffer
bogdanm 0:9b334a45a8ff 588 if ((obj->tx_buff.pos >= obj->tx_buff.length) && (obj->rx_buff.pos < obj->rx_buff.length)) {
bogdanm 0:9b334a45a8ff 589 obj->tx_buff.buffer = (void *)0;
bogdanm 0:9b334a45a8ff 590 obj->tx_buff.length = obj->rx_buff.length;
bogdanm 0:9b334a45a8ff 591 }
bogdanm 0:9b334a45a8ff 592
bogdanm 0:9b334a45a8ff 593 return ndata;
bogdanm 0:9b334a45a8ff 594 }
bogdanm 0:9b334a45a8ff 595
bogdanm 0:9b334a45a8ff 596 uint8_t spi_buffer_rx_empty(spi_t *obj)
bogdanm 0:9b334a45a8ff 597 {
bogdanm 0:9b334a45a8ff 598 return (obj->rx_buff.pos >= obj->rx_buff.length ? true : false );
bogdanm 0:9b334a45a8ff 599 }
bogdanm 0:9b334a45a8ff 600
bogdanm 0:9b334a45a8ff 601 uint8_t spi_buffer_tx_empty(spi_t *obj)
bogdanm 0:9b334a45a8ff 602 {
bogdanm 0:9b334a45a8ff 603 return (obj->tx_buff.pos >= obj->tx_buff.length ? true : false );
bogdanm 0:9b334a45a8ff 604 }
bogdanm 0:9b334a45a8ff 605
bogdanm 0:9b334a45a8ff 606 //TODO_LP implement slave
bogdanm 0:9b334a45a8ff 607
bogdanm 0:9b334a45a8ff 608 int spi_slave_receive(spi_t *obj)
bogdanm 0:9b334a45a8ff 609 {
bogdanm 0:9b334a45a8ff 610 if (obj->spi.bits <= 9) {
bogdanm 0:9b334a45a8ff 611 return (obj->spi.spi->STATUS & USART_STATUS_RXDATAV) ? 1 : 0;
bogdanm 0:9b334a45a8ff 612 } else {
bogdanm 0:9b334a45a8ff 613 return (obj->spi.spi->STATUS & USART_STATUS_RXFULL) ? 1 : 0;
bogdanm 0:9b334a45a8ff 614 }
bogdanm 0:9b334a45a8ff 615 }
bogdanm 0:9b334a45a8ff 616
bogdanm 0:9b334a45a8ff 617 int spi_slave_read(spi_t *obj)
bogdanm 0:9b334a45a8ff 618 {
bogdanm 0:9b334a45a8ff 619 return spi_read(obj);
bogdanm 0:9b334a45a8ff 620 }
bogdanm 0:9b334a45a8ff 621
bogdanm 0:9b334a45a8ff 622 void spi_slave_write(spi_t *obj, int value)
bogdanm 0:9b334a45a8ff 623 {
bogdanm 0:9b334a45a8ff 624 spi_write(obj, value);
bogdanm 0:9b334a45a8ff 625 }
bogdanm 0:9b334a45a8ff 626
bogdanm 0:9b334a45a8ff 627 uint32_t spi_event_check(spi_t *obj)
bogdanm 0:9b334a45a8ff 628 {
bogdanm 0:9b334a45a8ff 629 uint32_t requestedEvent = obj->spi.event;
bogdanm 0:9b334a45a8ff 630 uint32_t event = 0;
bogdanm 0:9b334a45a8ff 631 uint8_t quit = spi_buffer_rx_empty(obj) & spi_buffer_tx_empty(obj);
bogdanm 0:9b334a45a8ff 632 if (((requestedEvent & SPI_EVENT_COMPLETE) != 0) && (quit == true)) {
bogdanm 0:9b334a45a8ff 633 event |= SPI_EVENT_COMPLETE;
bogdanm 0:9b334a45a8ff 634 }
bogdanm 0:9b334a45a8ff 635
bogdanm 0:9b334a45a8ff 636 if(quit == true) {
bogdanm 0:9b334a45a8ff 637 event |= SPI_EVENT_INTERNAL_TRANSFER_COMPLETE;
bogdanm 0:9b334a45a8ff 638 }
bogdanm 0:9b334a45a8ff 639
bogdanm 0:9b334a45a8ff 640 return event;
bogdanm 0:9b334a45a8ff 641 }
bogdanm 0:9b334a45a8ff 642 /******************************************
bogdanm 0:9b334a45a8ff 643 * void transferComplete(uint channel, bool primary, void* user)
bogdanm 0:9b334a45a8ff 644 *
bogdanm 0:9b334a45a8ff 645 * Callback function which gets called upon DMA transfer completion
bogdanm 0:9b334a45a8ff 646 * the user-defined pointer is pointing to the CPP-land thunk
bogdanm 0:9b334a45a8ff 647 ******************************************/
bogdanm 0:9b334a45a8ff 648 void transferComplete(unsigned int channel, bool primary, void *user)
bogdanm 0:9b334a45a8ff 649 {
bogdanm 0:9b334a45a8ff 650 (void) channel;
bogdanm 0:9b334a45a8ff 651 (void) primary;
bogdanm 0:9b334a45a8ff 652
bogdanm 0:9b334a45a8ff 653 /* User pointer should be a thunk to CPP land */
bogdanm 0:9b334a45a8ff 654 if (user != NULL) {
bogdanm 0:9b334a45a8ff 655 ((DMACallback)user)();
bogdanm 0:9b334a45a8ff 656 }
bogdanm 0:9b334a45a8ff 657 }
bogdanm 0:9b334a45a8ff 658
bogdanm 0:9b334a45a8ff 659 /******************************************
bogdanm 0:9b334a45a8ff 660 * bool spi_allocate_dma(spi_t *obj);
bogdanm 0:9b334a45a8ff 661 * (helper function for spi_enable_dma)
bogdanm 0:9b334a45a8ff 662 *
bogdanm 0:9b334a45a8ff 663 * This function will request two DMA channels from the DMA API if needed
bogdanm 0:9b334a45a8ff 664 * by the hint provided. They will be allocated to the SPI object pointed to.
bogdanm 0:9b334a45a8ff 665 *
bogdanm 0:9b334a45a8ff 666 * return value: whether the channels were acquired successfully (true) or not.
bogdanm 0:9b334a45a8ff 667 ******************************************/
bogdanm 0:9b334a45a8ff 668 bool spi_allocate_dma(spi_t *obj)
bogdanm 0:9b334a45a8ff 669 {
bogdanm 0:9b334a45a8ff 670 int dmaChannelIn, dmaChannelOut;
bogdanm 0:9b334a45a8ff 671 dmaChannelIn = dma_channel_allocate(DMA_CAP_NONE);
bogdanm 0:9b334a45a8ff 672 if (dmaChannelIn == DMA_ERROR_OUT_OF_CHANNELS) {
bogdanm 0:9b334a45a8ff 673 return false;
bogdanm 0:9b334a45a8ff 674 }
bogdanm 0:9b334a45a8ff 675 dmaChannelOut = dma_channel_allocate(DMA_CAP_NONE);
bogdanm 0:9b334a45a8ff 676 if (dmaChannelOut == DMA_ERROR_OUT_OF_CHANNELS) {
bogdanm 0:9b334a45a8ff 677 dma_channel_free(dmaChannelIn);
bogdanm 0:9b334a45a8ff 678 return false;
bogdanm 0:9b334a45a8ff 679 }
bogdanm 0:9b334a45a8ff 680
bogdanm 0:9b334a45a8ff 681 obj->spi.dmaOptionsTX.dmaChannel = dmaChannelOut;
bogdanm 0:9b334a45a8ff 682 obj->spi.dmaOptionsRX.dmaChannel = dmaChannelIn;
bogdanm 0:9b334a45a8ff 683 return true;
bogdanm 0:9b334a45a8ff 684 }
bogdanm 0:9b334a45a8ff 685
bogdanm 0:9b334a45a8ff 686 /******************************************
bogdanm 0:9b334a45a8ff 687 * void spi_enable_dma(spi_t *obj, DMAUsage state)
bogdanm 0:9b334a45a8ff 688 *
bogdanm 0:9b334a45a8ff 689 * This function tries to allocate DMA as indicated by the hint (state).
bogdanm 0:9b334a45a8ff 690 * There are three possibilities:
bogdanm 0:9b334a45a8ff 691 * * state = NEVER:
mbed_official 50:a417edff4437 692 * if there were channels allocated by state = ALWAYS, they will be released
bogdanm 0:9b334a45a8ff 693 * * state = OPPORTUNITIC:
mbed_official 50:a417edff4437 694 * if there are channels available, they will get used, but freed upon transfer completion
mbed_official 50:a417edff4437 695 * * state = ALWAYS
mbed_official 50:a417edff4437 696 * if there are channels available, they will get allocated and not be freed until state changes
bogdanm 0:9b334a45a8ff 697 ******************************************/
bogdanm 0:9b334a45a8ff 698 void spi_enable_dma(spi_t *obj, DMAUsage state)
bogdanm 0:9b334a45a8ff 699 {
bogdanm 0:9b334a45a8ff 700 if (state == DMA_USAGE_ALWAYS && obj->spi.dmaOptionsTX.dmaUsageState != DMA_USAGE_ALLOCATED) {
bogdanm 0:9b334a45a8ff 701 /* Try to allocate channels */
bogdanm 0:9b334a45a8ff 702 if (spi_allocate_dma(obj)) {
bogdanm 0:9b334a45a8ff 703 obj->spi.dmaOptionsTX.dmaUsageState = DMA_USAGE_ALLOCATED;
bogdanm 0:9b334a45a8ff 704 } else {
bogdanm 0:9b334a45a8ff 705 obj->spi.dmaOptionsTX.dmaUsageState = state;
bogdanm 0:9b334a45a8ff 706 }
bogdanm 0:9b334a45a8ff 707 } else if (state == DMA_USAGE_OPPORTUNISTIC) {
bogdanm 0:9b334a45a8ff 708 if (obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_ALLOCATED) {
bogdanm 0:9b334a45a8ff 709 /* Channels have already been allocated previously by an ALWAYS state, so after this transfer, we will release them */
bogdanm 0:9b334a45a8ff 710 obj->spi.dmaOptionsTX.dmaUsageState = DMA_USAGE_TEMPORARY_ALLOCATED;
bogdanm 0:9b334a45a8ff 711 } else {
bogdanm 0:9b334a45a8ff 712 /* Try to allocate channels */
bogdanm 0:9b334a45a8ff 713 if (spi_allocate_dma(obj)) {
bogdanm 0:9b334a45a8ff 714 obj->spi.dmaOptionsTX.dmaUsageState = DMA_USAGE_TEMPORARY_ALLOCATED;
bogdanm 0:9b334a45a8ff 715 } else {
bogdanm 0:9b334a45a8ff 716 obj->spi.dmaOptionsTX.dmaUsageState = state;
bogdanm 0:9b334a45a8ff 717 }
bogdanm 0:9b334a45a8ff 718 }
bogdanm 0:9b334a45a8ff 719 } else if (state == DMA_USAGE_NEVER) {
bogdanm 0:9b334a45a8ff 720 /* If channels are allocated, get rid of them */
bogdanm 0:9b334a45a8ff 721 if (obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_ALLOCATED) {
bogdanm 0:9b334a45a8ff 722 dma_channel_free(obj->spi.dmaOptionsTX.dmaChannel);
bogdanm 0:9b334a45a8ff 723 dma_channel_free(obj->spi.dmaOptionsRX.dmaChannel);
bogdanm 0:9b334a45a8ff 724 }
bogdanm 0:9b334a45a8ff 725 obj->spi.dmaOptionsTX.dmaUsageState = DMA_USAGE_NEVER;
bogdanm 0:9b334a45a8ff 726 }
bogdanm 0:9b334a45a8ff 727 }
bogdanm 0:9b334a45a8ff 728
mbed_official 50:a417edff4437 729 #ifdef LDMA_PRESENT
mbed_official 50:a417edff4437 730 /************************************************************************************
mbed_official 50:a417edff4437 731 * DMA helper functions *
mbed_official 50:a417edff4437 732 ************************************************************************************/
mbed_official 50:a417edff4437 733 /******************************************
mbed_official 50:a417edff4437 734 * static void serial_dmaTransferComplete(uint channel, bool primary, void* user)
mbed_official 50:a417edff4437 735 *
mbed_official 50:a417edff4437 736 * Callback function which gets called upon DMA transfer completion
mbed_official 50:a417edff4437 737 * the user-defined pointer is pointing to the CPP-land thunk
mbed_official 50:a417edff4437 738 ******************************************/
mbed_official 50:a417edff4437 739 static void serial_dmaTransferComplete(unsigned int channel, bool primary, void *user)
mbed_official 50:a417edff4437 740 {
mbed_official 50:a417edff4437 741
mbed_official 50:a417edff4437 742 /* User pointer should be a thunk to CPP land */
mbed_official 50:a417edff4437 743 if (user != NULL) {
mbed_official 50:a417edff4437 744 ((DMACallback)user)();
mbed_official 50:a417edff4437 745 }
mbed_official 50:a417edff4437 746 }
mbed_official 50:a417edff4437 747 static void spi_master_dma_channel_setup(spi_t *obj, void* callback)
mbed_official 50:a417edff4437 748 {
mbed_official 50:a417edff4437 749 obj->spi.dmaOptionsRX.dmaCallback.userPtr = callback;
mbed_official 50:a417edff4437 750 }
mbed_official 50:a417edff4437 751 #else
bogdanm 0:9b334a45a8ff 752 /******************************************
bogdanm 0:9b334a45a8ff 753 * void spi_master_dma_channel_setup(spi_t *obj)
bogdanm 0:9b334a45a8ff 754 *
bogdanm 0:9b334a45a8ff 755 * This function will setup the DMA configuration for SPI transfers
bogdanm 0:9b334a45a8ff 756 *
bogdanm 0:9b334a45a8ff 757 * The channel numbers are fetched from the SPI instance, so this function
bogdanm 0:9b334a45a8ff 758 * should only be called when those channels have actually been allocated.
bogdanm 0:9b334a45a8ff 759 ******************************************/
bogdanm 0:9b334a45a8ff 760 static void spi_master_dma_channel_setup(spi_t *obj, void* callback)
bogdanm 0:9b334a45a8ff 761 {
bogdanm 0:9b334a45a8ff 762 DMA_CfgChannel_TypeDef rxChnlCfg;
bogdanm 0:9b334a45a8ff 763 DMA_CfgChannel_TypeDef txChnlCfg;
bogdanm 0:9b334a45a8ff 764
bogdanm 0:9b334a45a8ff 765 /* Setting up channel for rx. */
bogdanm 0:9b334a45a8ff 766 obj->spi.dmaOptionsRX.dmaCallback.cbFunc = transferComplete;
bogdanm 0:9b334a45a8ff 767 obj->spi.dmaOptionsRX.dmaCallback.userPtr = callback;
bogdanm 0:9b334a45a8ff 768
bogdanm 0:9b334a45a8ff 769 rxChnlCfg.highPri = false;
bogdanm 0:9b334a45a8ff 770 rxChnlCfg.enableInt = true;
bogdanm 0:9b334a45a8ff 771 rxChnlCfg.cb = &(obj->spi.dmaOptionsRX.dmaCallback);
bogdanm 0:9b334a45a8ff 772
bogdanm 0:9b334a45a8ff 773 /* Setting up channel for tx. */
bogdanm 0:9b334a45a8ff 774 obj->spi.dmaOptionsTX.dmaCallback.cbFunc = transferComplete;
bogdanm 0:9b334a45a8ff 775 obj->spi.dmaOptionsTX.dmaCallback.userPtr = callback;
bogdanm 0:9b334a45a8ff 776
bogdanm 0:9b334a45a8ff 777 txChnlCfg.highPri = false;
bogdanm 0:9b334a45a8ff 778 txChnlCfg.enableInt = true;
bogdanm 0:9b334a45a8ff 779 txChnlCfg.cb = &(obj->spi.dmaOptionsTX.dmaCallback);
bogdanm 0:9b334a45a8ff 780
bogdanm 0:9b334a45a8ff 781 switch ((int)obj->spi.spi) {
bogdanm 0:9b334a45a8ff 782 #ifdef USART0
bogdanm 0:9b334a45a8ff 783 case SPI_0:
bogdanm 0:9b334a45a8ff 784 rxChnlCfg.select = DMAREQ_USART0_RXDATAV;
bogdanm 0:9b334a45a8ff 785 txChnlCfg.select = DMAREQ_USART0_TXEMPTY;
bogdanm 0:9b334a45a8ff 786 break;
bogdanm 0:9b334a45a8ff 787 #endif
bogdanm 0:9b334a45a8ff 788 #ifdef USART1
bogdanm 0:9b334a45a8ff 789 case SPI_1:
bogdanm 0:9b334a45a8ff 790 rxChnlCfg.select = DMAREQ_USART1_RXDATAV;
bogdanm 0:9b334a45a8ff 791 txChnlCfg.select = DMAREQ_USART1_TXEMPTY;
bogdanm 0:9b334a45a8ff 792 break;
bogdanm 0:9b334a45a8ff 793 #endif
bogdanm 0:9b334a45a8ff 794 #ifdef USART2
bogdanm 0:9b334a45a8ff 795 case SPI_2:
bogdanm 0:9b334a45a8ff 796 rxChnlCfg.select = DMAREQ_USART2_RXDATAV;
bogdanm 0:9b334a45a8ff 797 txChnlCfg.select = DMAREQ_USART2_TXEMPTY;
bogdanm 0:9b334a45a8ff 798 break;
bogdanm 0:9b334a45a8ff 799 #endif
bogdanm 0:9b334a45a8ff 800 default:
bogdanm 0:9b334a45a8ff 801 error("Spi module not available.. Out of bound access.");
bogdanm 0:9b334a45a8ff 802 break;
bogdanm 0:9b334a45a8ff 803 }
bogdanm 0:9b334a45a8ff 804 DMA_CfgChannel(obj->spi.dmaOptionsRX.dmaChannel, &rxChnlCfg);
bogdanm 0:9b334a45a8ff 805 DMA_CfgChannel(obj->spi.dmaOptionsTX.dmaChannel, &txChnlCfg);
bogdanm 0:9b334a45a8ff 806 }
mbed_official 50:a417edff4437 807 #endif // LDMA_PRESENT
mbed_official 50:a417edff4437 808 /******************************************
mbed_official 50:a417edff4437 809 * void spi_activate_dma(spi_t *obj, void* rxdata, void* txdata, int length)
mbed_official 50:a417edff4437 810 *
mbed_official 50:a417edff4437 811 * This function will start the DMA engine for SPI transfers
mbed_official 50:a417edff4437 812 *
mbed_official 50:a417edff4437 813 * * rxdata: pointer to RX buffer, if needed.
mbed_official 50:a417edff4437 814 * * txdata: pointer to TX buffer, if needed. Else FF's.
mbed_official 50:a417edff4437 815 * * tx_length: how many bytes will get sent.
mbed_official 50:a417edff4437 816 * * rx_length: how many bytes will get received. If > tx_length, TX will get padded with n lower bits of SPI_FILL_WORD.
mbed_official 50:a417edff4437 817 ******************************************/
mbed_official 50:a417edff4437 818 #ifdef LDMA_PRESENT
mbed_official 50:a417edff4437 819 static void spi_activate_dma(spi_t *obj, void* rxdata, const void* txdata, int tx_length, int rx_length)
mbed_official 50:a417edff4437 820 {
mbed_official 50:a417edff4437 821 LDMA_PeripheralSignal_t dma_periph;
bogdanm 0:9b334a45a8ff 822
mbed_official 50:a417edff4437 823 if( txdata ) {
mbed_official 50:a417edff4437 824 volatile void *target_addr;
mbed_official 50:a417edff4437 825
mbed_official 50:a417edff4437 826 /* Select TX target address. 9 bit frame length requires to use extended register.
mbed_official 50:a417edff4437 827 10 bit and larger frame requires to use TXDOUBLE register. */
mbed_official 50:a417edff4437 828 switch((int)obj->spi.spi) {
mbed_official 50:a417edff4437 829 case USART_0:
mbed_official 50:a417edff4437 830 dma_periph = ldmaPeripheralSignal_USART0_TXBL;
mbed_official 50:a417edff4437 831 if(obj->spi.bits <= 8){
mbed_official 50:a417edff4437 832 target_addr = &USART0->TXDATA;
mbed_official 50:a417edff4437 833 }else if(obj->spi.bits == 9){
mbed_official 50:a417edff4437 834 target_addr = &USART0->TXDATAX;
mbed_official 50:a417edff4437 835 }else{
mbed_official 50:a417edff4437 836 target_addr = &USART0->TXDOUBLE;
mbed_official 50:a417edff4437 837 }
mbed_official 50:a417edff4437 838 break;
mbed_official 50:a417edff4437 839 case USART_1:
mbed_official 50:a417edff4437 840 dma_periph = ldmaPeripheralSignal_USART1_TXBL;
mbed_official 50:a417edff4437 841 if(obj->spi.bits <= 8){
mbed_official 50:a417edff4437 842 target_addr = &USART1->TXDATA;
mbed_official 50:a417edff4437 843 }else if(obj->spi.bits == 9){
mbed_official 50:a417edff4437 844 target_addr = &USART1->TXDATAX;
mbed_official 50:a417edff4437 845 }else{
mbed_official 50:a417edff4437 846 target_addr = &USART1->TXDOUBLE;
mbed_official 50:a417edff4437 847 }
mbed_official 50:a417edff4437 848 break;
mbed_official 50:a417edff4437 849 default:
mbed_official 50:a417edff4437 850 EFM_ASSERT(0);
mbed_official 50:a417edff4437 851 while(1);
mbed_official 50:a417edff4437 852 break;
mbed_official 50:a417edff4437 853 }
mbed_official 50:a417edff4437 854
mbed_official 50:a417edff4437 855 /* Check the transmit lenght, and split long transfers to smaller ones*/
mbed_official 50:a417edff4437 856 int max_length = 1024;
mbed_official 50:a417edff4437 857 #ifdef _LDMA_CH_CTRL_XFERCNT_MASK
mbed_official 50:a417edff4437 858 max_length = (_LDMA_CH_CTRL_XFERCNT_MASK>>_LDMA_CH_CTRL_XFERCNT_SHIFT)+1;
mbed_official 50:a417edff4437 859 #endif
mbed_official 50:a417edff4437 860 if(tx_length>max_length){
mbed_official 50:a417edff4437 861 tx_length = max_length;
mbed_official 50:a417edff4437 862 }
mbed_official 50:a417edff4437 863
mbed_official 50:a417edff4437 864 /* Save amount of TX done by DMA */
mbed_official 50:a417edff4437 865 obj->tx_buff.pos += tx_length;
mbed_official 50:a417edff4437 866
mbed_official 50:a417edff4437 867 LDMA_TransferCfg_t xferConf = LDMA_TRANSFER_CFG_PERIPHERAL(dma_periph);
mbed_official 50:a417edff4437 868 LDMA_Descriptor_t desc = LDMA_DESCRIPTOR_SINGLE_M2P_BYTE(txdata, target_addr, tx_length);
mbed_official 50:a417edff4437 869 if(obj->spi.bits >= 9){
mbed_official 50:a417edff4437 870 desc.xfer.size = ldmaCtrlSizeHalf;
mbed_official 50:a417edff4437 871 }
mbed_official 50:a417edff4437 872 LDMAx_StartTransfer(obj->spi.dmaOptionsTX.dmaChannel, &xferConf, &desc, serial_dmaTransferComplete,obj->spi.dmaOptionsRX.dmaCallback.userPtr);
mbed_official 50:a417edff4437 873
mbed_official 50:a417edff4437 874 }
mbed_official 50:a417edff4437 875 if(rxdata) {
mbed_official 50:a417edff4437 876 volatile const void *source_addr;
mbed_official 50:a417edff4437 877 /* Select RX source address. 9 bit frame length requires to use extended register.
mbed_official 50:a417edff4437 878 10 bit and larger frame requires to use RXDOUBLE register. */
mbed_official 50:a417edff4437 879 switch((int)obj->spi.spi) {
mbed_official 50:a417edff4437 880 case USART_0:
mbed_official 50:a417edff4437 881 dma_periph = ldmaPeripheralSignal_USART0_RXDATAV;
mbed_official 50:a417edff4437 882 if(obj->spi.bits <= 8){
mbed_official 50:a417edff4437 883 source_addr = &USART0->RXDATA;
mbed_official 50:a417edff4437 884 }else if(obj->spi.bits == 9){
mbed_official 50:a417edff4437 885 source_addr = &USART0->RXDATAX;
mbed_official 50:a417edff4437 886 }else{
mbed_official 50:a417edff4437 887 source_addr = &USART0->RXDOUBLE;
mbed_official 50:a417edff4437 888 }
mbed_official 50:a417edff4437 889 break;
mbed_official 50:a417edff4437 890 case USART_1:
mbed_official 50:a417edff4437 891 dma_periph = ldmaPeripheralSignal_USART1_RXDATAV;
mbed_official 50:a417edff4437 892 if(obj->spi.bits <= 8){
mbed_official 50:a417edff4437 893 source_addr = &USART1->RXDATA;
mbed_official 50:a417edff4437 894 }else if(obj->spi.bits == 9){
mbed_official 50:a417edff4437 895 source_addr = &USART1->RXDATAX;
mbed_official 50:a417edff4437 896 }else{
mbed_official 50:a417edff4437 897 source_addr = &USART1->RXDOUBLE;
mbed_official 50:a417edff4437 898 }
mbed_official 50:a417edff4437 899 break;
mbed_official 50:a417edff4437 900 default:
mbed_official 50:a417edff4437 901 EFM_ASSERT(0);
mbed_official 50:a417edff4437 902 while(1);
mbed_official 50:a417edff4437 903 break;
mbed_official 50:a417edff4437 904 }
mbed_official 50:a417edff4437 905
mbed_official 50:a417edff4437 906 LDMA_TransferCfg_t xferConf = LDMA_TRANSFER_CFG_PERIPHERAL(dma_periph);
mbed_official 50:a417edff4437 907 LDMA_Descriptor_t desc = LDMA_DESCRIPTOR_SINGLE_P2M_BYTE(source_addr, rxdata, rx_length);
mbed_official 50:a417edff4437 908 if(obj->spi.bits >= 9){
mbed_official 50:a417edff4437 909 desc.xfer.size = ldmaCtrlSizeHalf;
mbed_official 50:a417edff4437 910 }
mbed_official 50:a417edff4437 911 LDMAx_StartTransfer(obj->spi.dmaOptionsRX.dmaChannel, &xferConf, &desc, serial_dmaTransferComplete,obj->spi.dmaOptionsRX.dmaCallback.userPtr);
mbed_official 50:a417edff4437 912 }
mbed_official 50:a417edff4437 913 }
mbed_official 50:a417edff4437 914
mbed_official 50:a417edff4437 915 #else
bogdanm 0:9b334a45a8ff 916 /******************************************
bogdanm 0:9b334a45a8ff 917 * void spi_activate_dma(spi_t *obj, void* rxdata, void* txdata, int length)
bogdanm 0:9b334a45a8ff 918 *
bogdanm 0:9b334a45a8ff 919 * This function will start the DMA engine for SPI transfers
bogdanm 0:9b334a45a8ff 920 *
bogdanm 0:9b334a45a8ff 921 * * rxdata: pointer to RX buffer, if needed.
bogdanm 0:9b334a45a8ff 922 * * txdata: pointer to TX buffer, if needed. Else FF's.
bogdanm 0:9b334a45a8ff 923 * * tx_length: how many bytes will get sent.
bogdanm 0:9b334a45a8ff 924 * * rx_length: how many bytes will get received. If > tx_length, TX will get padded with n lower bits of SPI_FILL_WORD.
bogdanm 0:9b334a45a8ff 925 ******************************************/
bogdanm 0:9b334a45a8ff 926 static void spi_activate_dma(spi_t *obj, void* rxdata, const void* txdata, int tx_length, int rx_length)
bogdanm 0:9b334a45a8ff 927 {
bogdanm 0:9b334a45a8ff 928 /* DMA descriptors */
bogdanm 0:9b334a45a8ff 929 DMA_CfgDescr_TypeDef rxDescrCfg;
bogdanm 0:9b334a45a8ff 930 DMA_CfgDescr_TypeDef txDescrCfg;
bogdanm 0:9b334a45a8ff 931
bogdanm 0:9b334a45a8ff 932 /* Split up transfers if the tx length is larger than what the DMA supports. */
bogdanm 0:9b334a45a8ff 933 const int DMA_MAX_TRANSFER = (_DMA_CTRL_N_MINUS_1_MASK >> _DMA_CTRL_N_MINUS_1_SHIFT);
bogdanm 0:9b334a45a8ff 934
bogdanm 0:9b334a45a8ff 935 if (tx_length > DMA_MAX_TRANSFER) {
bogdanm 0:9b334a45a8ff 936 uint32_t max_length = DMA_MAX_TRANSFER;
bogdanm 0:9b334a45a8ff 937
bogdanm 0:9b334a45a8ff 938 /* Make sure only an even amount of bytes are transferred
bogdanm 0:9b334a45a8ff 939 if the width is larger than 8 bits. */
bogdanm 0:9b334a45a8ff 940 if (obj->spi.bits > 8) {
bogdanm 0:9b334a45a8ff 941 max_length = DMA_MAX_TRANSFER - (DMA_MAX_TRANSFER & 0x01);
bogdanm 0:9b334a45a8ff 942 }
bogdanm 0:9b334a45a8ff 943
bogdanm 0:9b334a45a8ff 944 /* Update length for current transfer. */
bogdanm 0:9b334a45a8ff 945 tx_length = max_length;
bogdanm 0:9b334a45a8ff 946 }
bogdanm 0:9b334a45a8ff 947
bogdanm 0:9b334a45a8ff 948 /* Save amount of TX done by DMA */
bogdanm 0:9b334a45a8ff 949 obj->tx_buff.pos += tx_length;
bogdanm 0:9b334a45a8ff 950
bogdanm 0:9b334a45a8ff 951 if(obj->spi.bits != 9) {
bogdanm 0:9b334a45a8ff 952 /* Only activate RX DMA if a receive buffer is specified */
bogdanm 0:9b334a45a8ff 953 if (rxdata != NULL) {
bogdanm 0:9b334a45a8ff 954 // Setting up channel descriptor
bogdanm 0:9b334a45a8ff 955 rxDescrCfg.dstInc = dmaDataInc1;
bogdanm 0:9b334a45a8ff 956 rxDescrCfg.srcInc = dmaDataIncNone;
bogdanm 0:9b334a45a8ff 957 rxDescrCfg.size = dmaDataSize1;
bogdanm 0:9b334a45a8ff 958 rxDescrCfg.arbRate = dmaArbitrate1;
bogdanm 0:9b334a45a8ff 959 rxDescrCfg.hprot = 0;
bogdanm 0:9b334a45a8ff 960 DMA_CfgDescr(obj->spi.dmaOptionsRX.dmaChannel, true, &rxDescrCfg);
bogdanm 0:9b334a45a8ff 961
bogdanm 0:9b334a45a8ff 962 /* Activate RX channel */
bogdanm 0:9b334a45a8ff 963 DMA_ActivateBasic(obj->spi.dmaOptionsRX.dmaChannel, true, false, rxdata, (void *)&(obj->spi.spi->RXDATA),
bogdanm 0:9b334a45a8ff 964 rx_length - 1);
bogdanm 0:9b334a45a8ff 965 }
bogdanm 0:9b334a45a8ff 966
bogdanm 0:9b334a45a8ff 967 // buffer with all FFs.
bogdanm 0:9b334a45a8ff 968 /* Setting up channel descriptor */
bogdanm 0:9b334a45a8ff 969 txDescrCfg.dstInc = dmaDataIncNone;
bogdanm 0:9b334a45a8ff 970 txDescrCfg.srcInc = (txdata == 0 ? dmaDataIncNone : (obj->spi.bits <= 8 ? dmaDataInc1 : dmaDataInc2)); //Do not increment source pointer when there is no transmit buffer
bogdanm 0:9b334a45a8ff 971 txDescrCfg.size = (obj->spi.bits <= 8 ? dmaDataSize1 : dmaDataSize2); //When frame size > 9, we can use TXDOUBLE to save bandwidth
bogdanm 0:9b334a45a8ff 972 txDescrCfg.arbRate = dmaArbitrate1;
bogdanm 0:9b334a45a8ff 973 txDescrCfg.hprot = 0;
bogdanm 0:9b334a45a8ff 974 DMA_CfgDescr(obj->spi.dmaOptionsTX.dmaChannel, true, &txDescrCfg);
bogdanm 0:9b334a45a8ff 975
bogdanm 0:9b334a45a8ff 976 /* Activate TX channel */
mbed_official 50:a417edff4437 977 DMA_ActivateBasic( obj->spi.dmaOptionsTX.dmaChannel,
bogdanm 0:9b334a45a8ff 978 true,
bogdanm 0:9b334a45a8ff 979 false,
bogdanm 0:9b334a45a8ff 980 (obj->spi.bits <= 8 ? (void *)&(obj->spi.spi->TXDATA) : (void *)&(obj->spi.spi->TXDOUBLE)), //When frame size > 9, point to TXDOUBLE
bogdanm 0:9b334a45a8ff 981 (txdata == 0 ? &fill_word : (void *)txdata), // When there is nothing to transmit, point to static fill word
mbed_official 50:a417edff4437 982 (tx_length - 1));
bogdanm 0:9b334a45a8ff 983 } else {
bogdanm 0:9b334a45a8ff 984 /* Frame size == 9 */
bogdanm 0:9b334a45a8ff 985 /* Only activate RX DMA if a receive buffer is specified */
bogdanm 0:9b334a45a8ff 986 if (rxdata != NULL) {
bogdanm 0:9b334a45a8ff 987 // Setting up channel descriptor
bogdanm 0:9b334a45a8ff 988 rxDescrCfg.dstInc = dmaDataInc2;
bogdanm 0:9b334a45a8ff 989 rxDescrCfg.srcInc = dmaDataIncNone;
bogdanm 0:9b334a45a8ff 990 rxDescrCfg.size = dmaDataSize2;
bogdanm 0:9b334a45a8ff 991 rxDescrCfg.arbRate = dmaArbitrate1;
bogdanm 0:9b334a45a8ff 992 rxDescrCfg.hprot = 0;
bogdanm 0:9b334a45a8ff 993 DMA_CfgDescr(obj->spi.dmaOptionsRX.dmaChannel, true, &rxDescrCfg);
bogdanm 0:9b334a45a8ff 994
bogdanm 0:9b334a45a8ff 995 /* Activate RX channel */
bogdanm 0:9b334a45a8ff 996 DMA_ActivateBasic(obj->spi.dmaOptionsRX.dmaChannel, true, false, rxdata, (void *)&(obj->spi.spi->RXDATAX),
bogdanm 0:9b334a45a8ff 997 (rx_length / 2) - 1);
bogdanm 0:9b334a45a8ff 998 }
bogdanm 0:9b334a45a8ff 999
bogdanm 0:9b334a45a8ff 1000 /* Setting up channel descriptor */
bogdanm 0:9b334a45a8ff 1001 txDescrCfg.dstInc = dmaDataIncNone;
bogdanm 0:9b334a45a8ff 1002 txDescrCfg.srcInc = (txdata == 0 ? dmaDataIncNone : dmaDataInc2); //Do not increment source pointer when there is no transmit buffer
bogdanm 0:9b334a45a8ff 1003 txDescrCfg.size = dmaDataSize2; //When frame size > 9, we can use TXDOUBLE to save bandwidth
bogdanm 0:9b334a45a8ff 1004 txDescrCfg.arbRate = dmaArbitrate1;
bogdanm 0:9b334a45a8ff 1005 txDescrCfg.hprot = 0;
bogdanm 0:9b334a45a8ff 1006 DMA_CfgDescr(obj->spi.dmaOptionsTX.dmaChannel, true, &txDescrCfg);
bogdanm 0:9b334a45a8ff 1007
bogdanm 0:9b334a45a8ff 1008 /* Activate TX channel */
mbed_official 50:a417edff4437 1009 DMA_ActivateBasic( obj->spi.dmaOptionsTX.dmaChannel,
bogdanm 0:9b334a45a8ff 1010 true,
bogdanm 0:9b334a45a8ff 1011 false,
bogdanm 0:9b334a45a8ff 1012 (void *)&(obj->spi.spi->TXDATAX), //When frame size > 9, point to TXDOUBLE
bogdanm 0:9b334a45a8ff 1013 (txdata == 0 ? &fill_word : (void *)txdata), // When there is nothing to transmit, point to static fill word
mbed_official 50:a417edff4437 1014 (tx_length - 1));
bogdanm 0:9b334a45a8ff 1015 }
bogdanm 0:9b334a45a8ff 1016 }
mbed_official 50:a417edff4437 1017 #endif //LDMA_PRESENT
bogdanm 0:9b334a45a8ff 1018 /********************************************************************
bogdanm 0:9b334a45a8ff 1019 * spi_master_transfer_dma(spi_t *obj, void *rxdata, void *txdata, int length, DMACallback cb, DMAUsage hint)
bogdanm 0:9b334a45a8ff 1020 *
bogdanm 0:9b334a45a8ff 1021 * Start an SPI transfer by using DMA and the supplied hint for DMA useage
bogdanm 0:9b334a45a8ff 1022 *
bogdanm 0:9b334a45a8ff 1023 * * obj: pointer to specific SPI instance
bogdanm 0:9b334a45a8ff 1024 * * rxdata: pointer to rx buffer. If null, we will assume only TX is relevant, and RX will be ignored.
bogdanm 0:9b334a45a8ff 1025 * * txdata: pointer to TX buffer. If null, we will assume only the read is relevant, and will send FF's for reading back.
bogdanm 0:9b334a45a8ff 1026 * * length: How many bytes should be written/read.
bogdanm 0:9b334a45a8ff 1027 * * cb: thunk pointer into CPP-land to get the spi object
bogdanm 0:9b334a45a8ff 1028 * * hint: hint for the requested DMA useage.
bogdanm 0:9b334a45a8ff 1029 * * NEVER: do not use DMA, but use IRQ instead
bogdanm 0:9b334a45a8ff 1030 * * OPPORTUNISTIC: use DMA if there are channels available, but return them after the transfer.
bogdanm 0:9b334a45a8ff 1031 * * ALWAYS: use DMA if channels are available, and hold on to the channels after the transfer.
bogdanm 0:9b334a45a8ff 1032 * If the previous transfer has kept the channel, that channel will continue to get used.
bogdanm 0:9b334a45a8ff 1033 *
bogdanm 0:9b334a45a8ff 1034 ********************************************************************/
bogdanm 0:9b334a45a8ff 1035 void spi_master_transfer_dma(spi_t *obj, const void *txdata, void *rxdata, int tx_length, int rx_length, void* cb, DMAUsage hint)
bogdanm 0:9b334a45a8ff 1036 {
bogdanm 0:9b334a45a8ff 1037 /* Init DMA here to include it in the power figure */
bogdanm 0:9b334a45a8ff 1038 dma_init();
mbed_official 50:a417edff4437 1039 /* Clear TX and RX registers */
mbed_official 50:a417edff4437 1040 obj->spi.spi->CMD = USART_CMD_CLEARTX;
mbed_official 50:a417edff4437 1041 obj->spi.spi->CMD = USART_CMD_CLEARRX;
bogdanm 0:9b334a45a8ff 1042 /* If the DMA channels are already allocated, we can assume they have been setup already */
bogdanm 0:9b334a45a8ff 1043 if (hint != DMA_USAGE_NEVER && obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_ALLOCATED) {
bogdanm 0:9b334a45a8ff 1044 /* setup has already been done, so just activate the transfer */
bogdanm 0:9b334a45a8ff 1045 spi_activate_dma(obj, rxdata, txdata, tx_length, rx_length);
bogdanm 0:9b334a45a8ff 1046 } else if (hint == DMA_USAGE_NEVER) {
bogdanm 0:9b334a45a8ff 1047 /* use IRQ */
bogdanm 0:9b334a45a8ff 1048 obj->spi.spi->IFC = 0xFFFFFFFF;
bogdanm 0:9b334a45a8ff 1049 spi_master_write_asynch(obj);
bogdanm 0:9b334a45a8ff 1050 spi_enable_interrupt(obj, (uint32_t)cb, true);
bogdanm 0:9b334a45a8ff 1051 } else {
bogdanm 0:9b334a45a8ff 1052 /* try to acquire channels */
bogdanm 0:9b334a45a8ff 1053 dma_init();
bogdanm 0:9b334a45a8ff 1054 spi_enable_dma(obj, hint);
bogdanm 0:9b334a45a8ff 1055
bogdanm 0:9b334a45a8ff 1056 /* decide between DMA and IRQ */
bogdanm 0:9b334a45a8ff 1057 if (obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_ALLOCATED || obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) {
bogdanm 0:9b334a45a8ff 1058 /* disable the interrupts that may have been left open previously */
bogdanm 0:9b334a45a8ff 1059 spi_enable_interrupt(obj, (uint32_t)cb, false);
bogdanm 0:9b334a45a8ff 1060
bogdanm 0:9b334a45a8ff 1061 /* DMA channels are allocated, so do their setup */
bogdanm 0:9b334a45a8ff 1062 spi_master_dma_channel_setup(obj, cb);
bogdanm 0:9b334a45a8ff 1063 /* and activate the transfer */
bogdanm 0:9b334a45a8ff 1064 spi_activate_dma(obj, rxdata, txdata, tx_length, rx_length);
bogdanm 0:9b334a45a8ff 1065 } else {
bogdanm 0:9b334a45a8ff 1066 /* DMA is unavailable, so fall back to IRQ */
bogdanm 0:9b334a45a8ff 1067 obj->spi.spi->IFC = 0xFFFFFFFF;
bogdanm 0:9b334a45a8ff 1068 spi_master_write_asynch(obj);
bogdanm 0:9b334a45a8ff 1069 spi_enable_interrupt(obj, (uint32_t)cb, true);
bogdanm 0:9b334a45a8ff 1070 }
bogdanm 0:9b334a45a8ff 1071 }
bogdanm 0:9b334a45a8ff 1072 }
bogdanm 0:9b334a45a8ff 1073
bogdanm 0:9b334a45a8ff 1074 /** Begin the SPI transfer. Buffer pointers and lengths are specified in tx_buff and rx_buff
bogdanm 0:9b334a45a8ff 1075 *
bogdanm 0:9b334a45a8ff 1076 * @param[in] obj The SPI object which holds the transfer information
bogdanm 0:9b334a45a8ff 1077 * @param[in] tx The buffer to send
bogdanm 0:9b334a45a8ff 1078 * @param[in] tx_length The number of words to transmit
bogdanm 0:9b334a45a8ff 1079 * @param[in] rx The buffer to receive
bogdanm 0:9b334a45a8ff 1080 * @param[in] rx_length The number of words to receive
bogdanm 0:9b334a45a8ff 1081 * @param[in] bit_width The bit width of buffer words
bogdanm 0:9b334a45a8ff 1082 * @param[in] event The logical OR of events to be registered
bogdanm 0:9b334a45a8ff 1083 * @param[in] handler SPI interrupt handler
bogdanm 0:9b334a45a8ff 1084 * @param[in] hint A suggestion for how to use DMA with this transfer
bogdanm 0:9b334a45a8ff 1085 */
bogdanm 0:9b334a45a8ff 1086 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)
bogdanm 0:9b334a45a8ff 1087 {
bogdanm 0:9b334a45a8ff 1088 if( spi_active(obj) ) return;
bogdanm 0:9b334a45a8ff 1089
bogdanm 0:9b334a45a8ff 1090 /* update fill word if on 9-bit frame size */
bogdanm 0:9b334a45a8ff 1091 if(obj->spi.bits == 9) fill_word = SPI_FILL_WORD & 0x1FF;
bogdanm 0:9b334a45a8ff 1092 else fill_word = SPI_FILL_WORD;
bogdanm 0:9b334a45a8ff 1093
bogdanm 0:9b334a45a8ff 1094 /* check corner case */
bogdanm 0:9b334a45a8ff 1095 if(tx_length == 0) {
bogdanm 0:9b334a45a8ff 1096 tx_length = rx_length;
bogdanm 0:9b334a45a8ff 1097 tx = (void*) 0;
bogdanm 0:9b334a45a8ff 1098 }
bogdanm 0:9b334a45a8ff 1099
bogdanm 0:9b334a45a8ff 1100 /* First, set the buffer */
bogdanm 0:9b334a45a8ff 1101 spi_buffer_set(obj, tx, tx_length, rx, rx_length, bit_width);
bogdanm 0:9b334a45a8ff 1102
bogdanm 0:9b334a45a8ff 1103 /* Then, enable the events */
bogdanm 0:9b334a45a8ff 1104 spi_enable_event(obj, SPI_EVENT_ALL, false);
bogdanm 0:9b334a45a8ff 1105 spi_enable_event(obj, event, true);
bogdanm 0:9b334a45a8ff 1106
bogdanm 0:9b334a45a8ff 1107 // Set the sleep mode
bogdanm 0:9b334a45a8ff 1108 blockSleepMode(SPI_LEAST_ACTIVE_SLEEPMODE);
bogdanm 0:9b334a45a8ff 1109
bogdanm 0:9b334a45a8ff 1110 /* And kick off the transfer */
bogdanm 0:9b334a45a8ff 1111 spi_master_transfer_dma(obj, tx, rx, tx_length, rx_length, (void*)handler, hint);
bogdanm 0:9b334a45a8ff 1112 }
bogdanm 0:9b334a45a8ff 1113
bogdanm 0:9b334a45a8ff 1114
bogdanm 0:9b334a45a8ff 1115 /********************************************************************
bogdanm 0:9b334a45a8ff 1116 * uint32_t spi_irq_handler_generic(spi_t* obj)
bogdanm 0:9b334a45a8ff 1117 *
bogdanm 0:9b334a45a8ff 1118 * handler which should get called by CPP-land when either a DMA or SPI IRQ gets fired for a SPI transaction.
bogdanm 0:9b334a45a8ff 1119 *
bogdanm 0:9b334a45a8ff 1120 * * obj: pointer to the specific SPI instance
bogdanm 0:9b334a45a8ff 1121 *
bogdanm 0:9b334a45a8ff 1122 * return: event mask. Currently only 0 or SPI_EVENT_COMPLETE upon transfer completion.
bogdanm 0:9b334a45a8ff 1123 *
bogdanm 0:9b334a45a8ff 1124 ********************************************************************/
mbed_official 50:a417edff4437 1125 #ifdef LDMA_PRESENT
mbed_official 50:a417edff4437 1126 uint32_t spi_irq_handler_asynch(spi_t* obj)
mbed_official 50:a417edff4437 1127 {
mbed_official 50:a417edff4437 1128 if (obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_ALLOCATED || obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) {
mbed_official 50:a417edff4437 1129 /* DMA implementation */
mbed_official 50:a417edff4437 1130 /* If there is still data in the TX buffer, setup a new transfer. */
mbed_official 50:a417edff4437 1131 if (obj->tx_buff.pos < obj->tx_buff.length) {
mbed_official 50:a417edff4437 1132 /* Find position and remaining length without modifying tx_buff. */
mbed_official 50:a417edff4437 1133 void* tx_pointer = (char*)obj->tx_buff.buffer + obj->tx_buff.pos;
mbed_official 50:a417edff4437 1134 uint32_t tx_length = obj->tx_buff.length - obj->tx_buff.pos;
mbed_official 50:a417edff4437 1135
mbed_official 50:a417edff4437 1136 /* Begin transfer. Rely on spi_activate_dma to split up the transfer further. */
mbed_official 50:a417edff4437 1137 spi_activate_dma(obj, obj->rx_buff.buffer, tx_pointer, tx_length, obj->rx_buff.length);
mbed_official 50:a417edff4437 1138
mbed_official 50:a417edff4437 1139 return 0;
mbed_official 50:a417edff4437 1140 }
mbed_official 50:a417edff4437 1141 /* If there is an RX transfer ongoing, wait for it to finish */
mbed_official 50:a417edff4437 1142 if (LDMAx_ChannelEnabled(obj->spi.dmaOptionsRX.dmaChannel)) {
mbed_official 50:a417edff4437 1143 /* Check if we need to kick off TX transfer again to force more incoming data. */
mbed_official 50:a417edff4437 1144 if (LDMA_TransferDone(obj->spi.dmaOptionsTX.dmaChannel) && (obj->tx_buff.pos < obj->rx_buff.length)) {
mbed_official 50:a417edff4437 1145 void* tx_pointer = (char*)obj->tx_buff.buffer + obj->tx_buff.pos;
mbed_official 50:a417edff4437 1146 uint32_t tx_length = obj->tx_buff.length - obj->tx_buff.pos;
mbed_official 50:a417edff4437 1147 /* Begin transfer. Rely on spi_activate_dma to split up the transfer further. */
mbed_official 50:a417edff4437 1148 spi_activate_dma(obj, obj->rx_buff.buffer, tx_pointer, tx_length, obj->rx_buff.length);
mbed_official 50:a417edff4437 1149 } else return 0;
mbed_official 50:a417edff4437 1150 }
mbed_official 50:a417edff4437 1151 /* If there is still a TX transfer ongoing (tx_length > rx_length), wait for it to finish */
mbed_official 50:a417edff4437 1152 if (!LDMA_TransferDone(obj->spi.dmaOptionsTX.dmaChannel)) {
mbed_official 50:a417edff4437 1153 return 0;
mbed_official 50:a417edff4437 1154 }
mbed_official 50:a417edff4437 1155 /* Release the dma channels if they were opportunistically allocated */
mbed_official 50:a417edff4437 1156 if (obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) {
mbed_official 50:a417edff4437 1157 dma_channel_free(obj->spi.dmaOptionsTX.dmaChannel);
mbed_official 50:a417edff4437 1158 dma_channel_free(obj->spi.dmaOptionsRX.dmaChannel);
mbed_official 50:a417edff4437 1159 obj->spi.dmaOptionsTX.dmaUsageState = DMA_USAGE_OPPORTUNISTIC;
mbed_official 50:a417edff4437 1160 }
mbed_official 50:a417edff4437 1161
mbed_official 50:a417edff4437 1162 /* Wait transmit to complete, before user code is indicated*/
mbed_official 50:a417edff4437 1163 while(!(obj->spi.spi->STATUS & USART_STATUS_TXC));
mbed_official 50:a417edff4437 1164 unblockSleepMode(SPI_LEAST_ACTIVE_SLEEPMODE);
mbed_official 50:a417edff4437 1165 /* return to CPP land to say we're finished */
mbed_official 50:a417edff4437 1166 return SPI_EVENT_COMPLETE;
mbed_official 50:a417edff4437 1167 } else {
mbed_official 50:a417edff4437 1168 /* IRQ implementation */
mbed_official 50:a417edff4437 1169 if (spi_master_rx_int_flag(obj)) {
mbed_official 50:a417edff4437 1170 spi_master_read_asynch(obj);
mbed_official 50:a417edff4437 1171 }
mbed_official 50:a417edff4437 1172
mbed_official 50:a417edff4437 1173 if (spi_master_tx_int_flag(obj)) {
mbed_official 50:a417edff4437 1174 spi_master_write_asynch(obj);
mbed_official 50:a417edff4437 1175 }
mbed_official 50:a417edff4437 1176
mbed_official 50:a417edff4437 1177 uint32_t event = spi_event_check(obj);
mbed_official 50:a417edff4437 1178 if (event & SPI_EVENT_INTERNAL_TRANSFER_COMPLETE) {
mbed_official 50:a417edff4437 1179 /* disable interrupts */
mbed_official 50:a417edff4437 1180 spi_enable_interrupt(obj, (uint32_t)NULL, false);
mbed_official 50:a417edff4437 1181
mbed_official 50:a417edff4437 1182 unblockSleepMode(SPI_LEAST_ACTIVE_SLEEPMODE);
mbed_official 50:a417edff4437 1183 /* Return the event back to userland */
mbed_official 50:a417edff4437 1184 return event;
mbed_official 50:a417edff4437 1185 }
mbed_official 50:a417edff4437 1186
mbed_official 50:a417edff4437 1187 return 0;
mbed_official 50:a417edff4437 1188 }
mbed_official 50:a417edff4437 1189 }
mbed_official 50:a417edff4437 1190 #else
bogdanm 0:9b334a45a8ff 1191 uint32_t spi_irq_handler_asynch(spi_t* obj)
bogdanm 0:9b334a45a8ff 1192 {
bogdanm 0:9b334a45a8ff 1193
bogdanm 0:9b334a45a8ff 1194 /* Determine whether the current scenario is DMA or IRQ, and act accordingly */
bogdanm 0:9b334a45a8ff 1195
bogdanm 0:9b334a45a8ff 1196 if (obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_ALLOCATED || obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) {
bogdanm 0:9b334a45a8ff 1197 /* DMA implementation */
bogdanm 0:9b334a45a8ff 1198
bogdanm 0:9b334a45a8ff 1199 /* If there is still data in the TX buffer, setup a new transfer. */
bogdanm 0:9b334a45a8ff 1200 if (obj->tx_buff.pos < obj->tx_buff.length) {
bogdanm 0:9b334a45a8ff 1201 /* Find position and remaining length without modifying tx_buff. */
bogdanm 0:9b334a45a8ff 1202 void* tx_pointer = (char*)obj->tx_buff.buffer + obj->tx_buff.pos;
bogdanm 0:9b334a45a8ff 1203 uint32_t tx_length = obj->tx_buff.length - obj->tx_buff.pos;
bogdanm 0:9b334a45a8ff 1204
bogdanm 0:9b334a45a8ff 1205 /* Begin transfer. Rely on spi_activate_dma to split up the transfer further. */
bogdanm 0:9b334a45a8ff 1206 spi_activate_dma(obj, obj->rx_buff.buffer, tx_pointer, tx_length, obj->rx_buff.length);
bogdanm 0:9b334a45a8ff 1207
bogdanm 0:9b334a45a8ff 1208 return 0;
bogdanm 0:9b334a45a8ff 1209 }
bogdanm 0:9b334a45a8ff 1210
bogdanm 0:9b334a45a8ff 1211 /* If there is an RX transfer ongoing, wait for it to finish */
bogdanm 0:9b334a45a8ff 1212 if (DMA_ChannelEnabled(obj->spi.dmaOptionsRX.dmaChannel)) {
bogdanm 0:9b334a45a8ff 1213 /* Check if we need to kick off TX transfer again to force more incoming data. */
bogdanm 0:9b334a45a8ff 1214 if (!DMA_ChannelEnabled(obj->spi.dmaOptionsTX.dmaChannel) && (obj->tx_buff.pos < obj->rx_buff.length)) {
bogdanm 0:9b334a45a8ff 1215 //Save state of TX transfer amount
bogdanm 0:9b334a45a8ff 1216 int length_diff = obj->rx_buff.length - obj->tx_buff.pos;
bogdanm 0:9b334a45a8ff 1217 obj->tx_buff.pos = obj->rx_buff.length;
bogdanm 0:9b334a45a8ff 1218
bogdanm 0:9b334a45a8ff 1219 //Kick off a new DMA transfer
bogdanm 0:9b334a45a8ff 1220 DMA_CfgDescr_TypeDef txDescrCfg;
bogdanm 0:9b334a45a8ff 1221
bogdanm 0:9b334a45a8ff 1222 if(obj->spi.bits != 9) {
bogdanm 0:9b334a45a8ff 1223 fill_word = SPI_FILL_WORD;
bogdanm 0:9b334a45a8ff 1224 /* Setting up channel descriptor */
bogdanm 0:9b334a45a8ff 1225 txDescrCfg.dstInc = dmaDataIncNone;
bogdanm 0:9b334a45a8ff 1226 txDescrCfg.srcInc = dmaDataIncNone; //Do not increment source pointer when there is no transmit buffer
bogdanm 0:9b334a45a8ff 1227 txDescrCfg.size = (obj->spi.bits <= 8 ? dmaDataSize1 : dmaDataSize2); //When frame size > 9, we can use TXDOUBLE to save bandwidth
bogdanm 0:9b334a45a8ff 1228 txDescrCfg.arbRate = dmaArbitrate1;
bogdanm 0:9b334a45a8ff 1229 txDescrCfg.hprot = 0;
bogdanm 0:9b334a45a8ff 1230 DMA_CfgDescr(obj->spi.dmaOptionsTX.dmaChannel, true, &txDescrCfg);
bogdanm 0:9b334a45a8ff 1231
bogdanm 0:9b334a45a8ff 1232 /* Activate TX channel */
mbed_official 50:a417edff4437 1233 DMA_ActivateBasic( obj->spi.dmaOptionsTX.dmaChannel,
bogdanm 0:9b334a45a8ff 1234 true,
bogdanm 0:9b334a45a8ff 1235 false,
bogdanm 0:9b334a45a8ff 1236 (obj->spi.bits <= 8 ? (void *)&(obj->spi.spi->TXDATA) : (void *)&(obj->spi.spi->TXDOUBLE)), //When frame size > 9, point to TXDOUBLE
bogdanm 0:9b334a45a8ff 1237 &fill_word, // When there is nothing to transmit, point to static fill word
bogdanm 0:9b334a45a8ff 1238 (obj->spi.bits <= 8 ? length_diff - 1 : (length_diff / 2) - 1)); // When using TXDOUBLE, recalculate transfer length
bogdanm 0:9b334a45a8ff 1239 } else {
bogdanm 0:9b334a45a8ff 1240 /* Setting up channel descriptor */
bogdanm 0:9b334a45a8ff 1241 fill_word = SPI_FILL_WORD & 0x1FF;
bogdanm 0:9b334a45a8ff 1242 txDescrCfg.dstInc = dmaDataIncNone;
bogdanm 0:9b334a45a8ff 1243 txDescrCfg.srcInc = dmaDataIncNone; //Do not increment source pointer when there is no transmit buffer
bogdanm 0:9b334a45a8ff 1244 txDescrCfg.size = dmaDataSize2; //When frame size > 9, we can use TXDOUBLE to save bandwidth
bogdanm 0:9b334a45a8ff 1245 txDescrCfg.arbRate = dmaArbitrate1;
bogdanm 0:9b334a45a8ff 1246 txDescrCfg.hprot = 0;
bogdanm 0:9b334a45a8ff 1247 DMA_CfgDescr(obj->spi.dmaOptionsTX.dmaChannel, true, &txDescrCfg);
bogdanm 0:9b334a45a8ff 1248
mbed_official 50:a417edff4437 1249 DMA_ActivateBasic( obj->spi.dmaOptionsTX.dmaChannel,
bogdanm 0:9b334a45a8ff 1250 true,
bogdanm 0:9b334a45a8ff 1251 false,
bogdanm 0:9b334a45a8ff 1252 (void *)&(obj->spi.spi->TXDATAX), //When frame size > 9, point to TXDOUBLE
bogdanm 0:9b334a45a8ff 1253 &fill_word, // When there is nothing to transmit, point to static fill word
bogdanm 0:9b334a45a8ff 1254 (length_diff / 2) - 1);
bogdanm 0:9b334a45a8ff 1255 }
bogdanm 0:9b334a45a8ff 1256 } else return 0;
bogdanm 0:9b334a45a8ff 1257 }
bogdanm 0:9b334a45a8ff 1258
bogdanm 0:9b334a45a8ff 1259 /* If there is still a TX transfer ongoing (tx_length > rx_length), wait for it to finish */
bogdanm 0:9b334a45a8ff 1260 if (DMA_ChannelEnabled(obj->spi.dmaOptionsTX.dmaChannel)) {
bogdanm 0:9b334a45a8ff 1261 return 0;
bogdanm 0:9b334a45a8ff 1262 }
bogdanm 0:9b334a45a8ff 1263
bogdanm 0:9b334a45a8ff 1264 /* Release the dma channels if they were opportunistically allocated */
bogdanm 0:9b334a45a8ff 1265 if (obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) {
bogdanm 0:9b334a45a8ff 1266 dma_channel_free(obj->spi.dmaOptionsTX.dmaChannel);
bogdanm 0:9b334a45a8ff 1267 dma_channel_free(obj->spi.dmaOptionsRX.dmaChannel);
bogdanm 0:9b334a45a8ff 1268 obj->spi.dmaOptionsTX.dmaUsageState = DMA_USAGE_OPPORTUNISTIC;
bogdanm 0:9b334a45a8ff 1269 }
bogdanm 0:9b334a45a8ff 1270
mbed_official 50:a417edff4437 1271 /* Wait transmit to complete, before user code is indicated*/
mbed_official 50:a417edff4437 1272 while(!(obj->spi.spi->STATUS & USART_STATUS_TXC));
bogdanm 0:9b334a45a8ff 1273 unblockSleepMode(SPI_LEAST_ACTIVE_SLEEPMODE);
bogdanm 0:9b334a45a8ff 1274
bogdanm 0:9b334a45a8ff 1275 /* return to CPP land to say we're finished */
bogdanm 0:9b334a45a8ff 1276 return SPI_EVENT_COMPLETE;
bogdanm 0:9b334a45a8ff 1277 } else {
bogdanm 0:9b334a45a8ff 1278 /* IRQ implementation */
bogdanm 0:9b334a45a8ff 1279 if (spi_master_rx_int_flag(obj)) {
bogdanm 0:9b334a45a8ff 1280 spi_master_read_asynch(obj);
bogdanm 0:9b334a45a8ff 1281 }
bogdanm 0:9b334a45a8ff 1282
bogdanm 0:9b334a45a8ff 1283 if (spi_master_tx_int_flag(obj)) {
bogdanm 0:9b334a45a8ff 1284 spi_master_write_asynch(obj);
bogdanm 0:9b334a45a8ff 1285 }
bogdanm 0:9b334a45a8ff 1286
bogdanm 0:9b334a45a8ff 1287 uint32_t event = spi_event_check(obj);
bogdanm 0:9b334a45a8ff 1288 if (event & SPI_EVENT_INTERNAL_TRANSFER_COMPLETE) {
bogdanm 0:9b334a45a8ff 1289 /* disable interrupts */
bogdanm 0:9b334a45a8ff 1290 spi_enable_interrupt(obj, (uint32_t)NULL, false);
bogdanm 0:9b334a45a8ff 1291
bogdanm 0:9b334a45a8ff 1292 unblockSleepMode(SPI_LEAST_ACTIVE_SLEEPMODE);
bogdanm 0:9b334a45a8ff 1293
bogdanm 0:9b334a45a8ff 1294 /* Return the event back to userland */
bogdanm 0:9b334a45a8ff 1295 return event;
bogdanm 0:9b334a45a8ff 1296 }
bogdanm 0:9b334a45a8ff 1297
bogdanm 0:9b334a45a8ff 1298 return 0;
bogdanm 0:9b334a45a8ff 1299 }
bogdanm 0:9b334a45a8ff 1300 }
mbed_official 50:a417edff4437 1301 #endif // LDMA_PRESENT
bogdanm 0:9b334a45a8ff 1302 /** Abort an SPI transfer
bogdanm 0:9b334a45a8ff 1303 *
bogdanm 0:9b334a45a8ff 1304 * @param obj The SPI peripheral to stop
bogdanm 0:9b334a45a8ff 1305 */
bogdanm 0:9b334a45a8ff 1306 void spi_abort_asynch(spi_t *obj)
bogdanm 0:9b334a45a8ff 1307 {
bogdanm 0:9b334a45a8ff 1308 // If we're not currently transferring, then there's nothing to do here
bogdanm 0:9b334a45a8ff 1309 if(spi_active(obj) != 0) return;
bogdanm 0:9b334a45a8ff 1310
bogdanm 0:9b334a45a8ff 1311 // Determine whether we're running DMA or interrupt
bogdanm 0:9b334a45a8ff 1312 if (obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_ALLOCATED || obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) {
bogdanm 0:9b334a45a8ff 1313 // Cancel the DMA transfers
mbed_official 50:a417edff4437 1314 #ifdef LDMA_PRESENT
mbed_official 50:a417edff4437 1315 LDMA_StopTransfer(obj->spi.dmaOptionsTX.dmaChannel);
mbed_official 50:a417edff4437 1316 LDMA_StopTransfer(obj->spi.dmaOptionsRX.dmaChannel);
mbed_official 50:a417edff4437 1317 #else
bogdanm 0:9b334a45a8ff 1318 DMA_ChannelEnable(obj->spi.dmaOptionsTX.dmaChannel, false);
bogdanm 0:9b334a45a8ff 1319 DMA_ChannelEnable(obj->spi.dmaOptionsRX.dmaChannel, false);
mbed_official 50:a417edff4437 1320 #endif
bogdanm 0:9b334a45a8ff 1321 /* Release the dma channels if they were opportunistically allocated */
bogdanm 0:9b334a45a8ff 1322 if (obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) {
bogdanm 0:9b334a45a8ff 1323 dma_channel_free(obj->spi.dmaOptionsTX.dmaChannel);
bogdanm 0:9b334a45a8ff 1324 dma_channel_free(obj->spi.dmaOptionsRX.dmaChannel);
bogdanm 0:9b334a45a8ff 1325 obj->spi.dmaOptionsTX.dmaUsageState = DMA_USAGE_OPPORTUNISTIC;
bogdanm 0:9b334a45a8ff 1326 }
bogdanm 0:9b334a45a8ff 1327
bogdanm 0:9b334a45a8ff 1328 } else {
bogdanm 0:9b334a45a8ff 1329 // Interrupt implementation: switch off interrupts
bogdanm 0:9b334a45a8ff 1330 spi_enable_interrupt(obj, (uint32_t)NULL, false);
bogdanm 0:9b334a45a8ff 1331 }
bogdanm 0:9b334a45a8ff 1332
bogdanm 0:9b334a45a8ff 1333 // Release sleep mode block
bogdanm 0:9b334a45a8ff 1334 unblockSleepMode(SPI_LEAST_ACTIVE_SLEEPMODE);
bogdanm 0:9b334a45a8ff 1335 }
bogdanm 0:9b334a45a8ff 1336
bogdanm 0:9b334a45a8ff 1337 #endif