mbed library sources

Dependents:   Encrypted my_mbed lklk CyaSSL_DTLS_Cellular ... more

Superseded

This library was superseded by mbed-dev - https://os.mbed.com/users/mbed_official/code/mbed-dev/.

Development branch of the mbed library sources. This library is kept in synch with the latest changes from the mbed SDK and it is not guaranteed to work.

If you are looking for a stable and tested release, please import one of the official mbed library releases:

Import librarymbed

The official Mbed 2 C/C++ SDK provides the software platform and libraries to build your applications.

Committer:
mbed_official
Date:
Tue Apr 28 11:45:12 2015 +0100
Revision:
525:c320967f86b9
Child:
526:7c4bdfe6a168
Synchronized with git revision 299385b8331142b9dc524da7a986536f60b14553

Full URL: https://github.com/mbedmicro/mbed/commit/299385b8331142b9dc524da7a986536f60b14553/

Add in Silicon Labs targets with asynchronous API support

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mbed_official 525:c320967f86b9 1 /* mbed Microcontroller Library
mbed_official 525:c320967f86b9 2 * Copyright (c) 2006-2013 ARM Limited
mbed_official 525:c320967f86b9 3 *
mbed_official 525:c320967f86b9 4 * Licensed under the Apache License, Version 2.0 (the "License");
mbed_official 525:c320967f86b9 5 * you may not use this file except in compliance with the License.
mbed_official 525:c320967f86b9 6 * You may obtain a copy of the License at
mbed_official 525:c320967f86b9 7 *
mbed_official 525:c320967f86b9 8 * http://www.apache.org/licenses/LICENSE-2.0
mbed_official 525:c320967f86b9 9 *
mbed_official 525:c320967f86b9 10 * Unless required by applicable law or agreed to in writing, software
mbed_official 525:c320967f86b9 11 * distributed under the License is distributed on an "AS IS" BASIS,
mbed_official 525:c320967f86b9 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
mbed_official 525:c320967f86b9 13 * See the License for the specific language governing permissions and
mbed_official 525:c320967f86b9 14 * limitations under the License.
mbed_official 525:c320967f86b9 15 */
mbed_official 525:c320967f86b9 16 #include "device.h"
mbed_official 525:c320967f86b9 17 #include "clocking.h"
mbed_official 525:c320967f86b9 18 #if DEVICE_SPI
mbed_official 525:c320967f86b9 19
mbed_official 525:c320967f86b9 20 #include "mbed_assert.h"
mbed_official 525:c320967f86b9 21 #include "PeripheralPins.h"
mbed_official 525:c320967f86b9 22 #include "pinmap.h"
mbed_official 525:c320967f86b9 23 #include "pinmap_function.h"
mbed_official 525:c320967f86b9 24 #include "error.h"
mbed_official 525:c320967f86b9 25
mbed_official 525:c320967f86b9 26 #include "dma_api.h"
mbed_official 525:c320967f86b9 27 #include "dma_api_HAL.h"
mbed_official 525:c320967f86b9 28 #include "spi_api.h"
mbed_official 525:c320967f86b9 29 #include "em_usart.h"
mbed_official 525:c320967f86b9 30 #include "em_cmu.h"
mbed_official 525:c320967f86b9 31 #include "em_dma.h"
mbed_official 525:c320967f86b9 32 #include "sleep_api.h"
mbed_official 525:c320967f86b9 33
mbed_official 525:c320967f86b9 34 static uint16_t fill_word = SPI_FILL_WORD;
mbed_official 525:c320967f86b9 35 #define SPI_LEAST_ACTIVE_SLEEPMODE EM1
mbed_official 525:c320967f86b9 36
mbed_official 525:c320967f86b9 37 inline CMU_Clock_TypeDef spi_get_clock_tree(spi_t *obj) {
mbed_official 525:c320967f86b9 38 switch ((int)obj->spi.spi) {
mbed_official 525:c320967f86b9 39 #ifdef USART0
mbed_official 525:c320967f86b9 40 case SPI_0:
mbed_official 525:c320967f86b9 41 return cmuClock_USART0;
mbed_official 525:c320967f86b9 42 #endif
mbed_official 525:c320967f86b9 43 #ifdef USART1
mbed_official 525:c320967f86b9 44 case SPI_1:
mbed_official 525:c320967f86b9 45 return cmuClock_USART1;
mbed_official 525:c320967f86b9 46 #endif
mbed_official 525:c320967f86b9 47 #ifdef USART2
mbed_official 525:c320967f86b9 48 case SPI_2:
mbed_official 525:c320967f86b9 49 return cmuClock_USART2;
mbed_official 525:c320967f86b9 50 #endif
mbed_official 525:c320967f86b9 51 default:
mbed_official 525:c320967f86b9 52 error("Spi module not available.. Out of bound access.");
mbed_official 525:c320967f86b9 53 return cmuClock_HFPER;
mbed_official 525:c320967f86b9 54 }
mbed_official 525:c320967f86b9 55 }
mbed_official 525:c320967f86b9 56
mbed_official 525:c320967f86b9 57 inline uint8_t spi_get_index(spi_t *obj)
mbed_official 525:c320967f86b9 58 {
mbed_official 525:c320967f86b9 59 uint8_t index = 0;
mbed_official 525:c320967f86b9 60 switch ((int)obj->spi.spi) {
mbed_official 525:c320967f86b9 61 #ifdef USART0
mbed_official 525:c320967f86b9 62 case SPI_0:
mbed_official 525:c320967f86b9 63 index = 0;
mbed_official 525:c320967f86b9 64 break;
mbed_official 525:c320967f86b9 65 #endif
mbed_official 525:c320967f86b9 66 #ifdef USART1
mbed_official 525:c320967f86b9 67 case SPI_1:
mbed_official 525:c320967f86b9 68 index = 1;
mbed_official 525:c320967f86b9 69 break;
mbed_official 525:c320967f86b9 70 #endif
mbed_official 525:c320967f86b9 71 #ifdef USART2
mbed_official 525:c320967f86b9 72 case SPI_2:
mbed_official 525:c320967f86b9 73 index = 2;
mbed_official 525:c320967f86b9 74 break;
mbed_official 525:c320967f86b9 75 #endif
mbed_official 525:c320967f86b9 76 default:
mbed_official 525:c320967f86b9 77 error("Spi module not available.. Out of bound access.");
mbed_official 525:c320967f86b9 78 break;
mbed_official 525:c320967f86b9 79 }
mbed_official 525:c320967f86b9 80 return index;
mbed_official 525:c320967f86b9 81 }
mbed_official 525:c320967f86b9 82
mbed_official 525:c320967f86b9 83 uint8_t spi_get_module(spi_t *obj) {
mbed_official 525:c320967f86b9 84 return spi_get_index(obj);
mbed_official 525:c320967f86b9 85 }
mbed_official 525:c320967f86b9 86
mbed_official 525:c320967f86b9 87 static void usart_init(spi_t *obj, uint32_t baudrate, USART_Databits_TypeDef databits, bool master, USART_ClockMode_TypeDef clockMode )
mbed_official 525:c320967f86b9 88 {
mbed_official 525:c320967f86b9 89 USART_InitSync_TypeDef init = USART_INITSYNC_DEFAULT;
mbed_official 525:c320967f86b9 90 init.enable = usartDisable;
mbed_official 525:c320967f86b9 91 init.baudrate = baudrate;
mbed_official 525:c320967f86b9 92 init.databits = databits;
mbed_official 525:c320967f86b9 93 init.master = master;
mbed_official 525:c320967f86b9 94 init.msbf = 1;
mbed_official 525:c320967f86b9 95 init.clockMode = clockMode;
mbed_official 525:c320967f86b9 96
mbed_official 525:c320967f86b9 97 /* Determine the reference clock, because the correct clock is not set up at init time */
mbed_official 525:c320967f86b9 98 init.refFreq = REFERENCE_FREQUENCY;
mbed_official 525:c320967f86b9 99
mbed_official 525:c320967f86b9 100 USART_InitSync(obj->spi.spi, &init);
mbed_official 525:c320967f86b9 101 }
mbed_official 525:c320967f86b9 102
mbed_official 525:c320967f86b9 103 void spi_preinit(spi_t *obj, PinName mosi, PinName miso, PinName clk, PinName cs)
mbed_official 525:c320967f86b9 104 {
mbed_official 525:c320967f86b9 105 SPIName spi_mosi = (SPIName) pinmap_peripheral(mosi, PinMap_SPI_MOSI);
mbed_official 525:c320967f86b9 106 SPIName spi_miso = (SPIName) pinmap_peripheral(miso, PinMap_SPI_MISO);
mbed_official 525:c320967f86b9 107 SPIName spi_clk = (SPIName) pinmap_peripheral(clk, PinMap_SPI_CLK);
mbed_official 525:c320967f86b9 108 SPIName spi_cs = (SPIName) pinmap_peripheral(cs, PinMap_SPI_CS);
mbed_official 525:c320967f86b9 109 SPIName spi_data = (SPIName) pinmap_merge(spi_mosi, spi_miso);
mbed_official 525:c320967f86b9 110 SPIName spi_ctrl = (SPIName) pinmap_merge(spi_clk, spi_cs);
mbed_official 525:c320967f86b9 111
mbed_official 525:c320967f86b9 112 obj->spi.spi = (USART_TypeDef *) pinmap_merge(spi_data, spi_ctrl);
mbed_official 525:c320967f86b9 113 MBED_ASSERT((int) obj->spi.spi != NC);
mbed_official 525:c320967f86b9 114
mbed_official 525:c320967f86b9 115 if (cs != NC) { /* Slave mode */
mbed_official 525:c320967f86b9 116 obj->spi.master = false;
mbed_official 525:c320967f86b9 117 } else {
mbed_official 525:c320967f86b9 118 obj->spi.master = true;
mbed_official 525:c320967f86b9 119 }
mbed_official 525:c320967f86b9 120
mbed_official 525:c320967f86b9 121 uint32_t loc_mosi = pin_location(mosi, PinMap_SPI_MOSI);
mbed_official 525:c320967f86b9 122 uint32_t loc_miso = pin_location(miso, PinMap_SPI_MISO);
mbed_official 525:c320967f86b9 123 uint32_t loc_clk = pin_location(clk, PinMap_SPI_CLK);
mbed_official 525:c320967f86b9 124 uint32_t loc_cs = pin_location(cs, PinMap_SPI_CS);
mbed_official 525:c320967f86b9 125 uint32_t loc_data = pinmap_merge(loc_mosi, loc_miso);
mbed_official 525:c320967f86b9 126 uint32_t loc_ctrl = pinmap_merge(loc_clk, loc_cs);
mbed_official 525:c320967f86b9 127 obj->spi.location = pinmap_merge(loc_data, loc_ctrl);
mbed_official 525:c320967f86b9 128 MBED_ASSERT(obj->spi.location != NC);
mbed_official 525:c320967f86b9 129
mbed_official 525:c320967f86b9 130 obj->spi.dmaOptionsTX.dmaUsageState = DMA_USAGE_OPPORTUNISTIC;
mbed_official 525:c320967f86b9 131 }
mbed_official 525:c320967f86b9 132
mbed_official 525:c320967f86b9 133 void spi_enable_pins(spi_t *obj, uint8_t enable, PinName mosi, PinName miso, PinName clk, PinName cs)
mbed_official 525:c320967f86b9 134 {
mbed_official 525:c320967f86b9 135 if (enable) {
mbed_official 525:c320967f86b9 136 if (obj->spi.master) { /* Master mode */
mbed_official 525:c320967f86b9 137 /* Either mosi or miso can be NC */
mbed_official 525:c320967f86b9 138 if (mosi != NC) {
mbed_official 525:c320967f86b9 139 pin_mode(mosi, PushPull);
mbed_official 525:c320967f86b9 140 }
mbed_official 525:c320967f86b9 141 if (miso != NC) {
mbed_official 525:c320967f86b9 142 pin_mode(miso, Input);
mbed_official 525:c320967f86b9 143 }
mbed_official 525:c320967f86b9 144 pin_mode(clk, PushPull);
mbed_official 525:c320967f86b9 145 /* Don't set cs pin, since we toggle it manually */
mbed_official 525:c320967f86b9 146 } else { /* Slave mode */
mbed_official 525:c320967f86b9 147 if (mosi != NC) {
mbed_official 525:c320967f86b9 148 pin_mode(mosi, Input);
mbed_official 525:c320967f86b9 149 }
mbed_official 525:c320967f86b9 150 if (miso != NC) {
mbed_official 525:c320967f86b9 151 pin_mode(miso, PushPull);
mbed_official 525:c320967f86b9 152 }
mbed_official 525:c320967f86b9 153 pin_mode(clk, Input);
mbed_official 525:c320967f86b9 154 pin_mode(cs, Input);
mbed_official 525:c320967f86b9 155 }
mbed_official 525:c320967f86b9 156 } else {
mbed_official 525:c320967f86b9 157 // TODO_LP return PinMode to the previous state
mbed_official 525:c320967f86b9 158 if (obj->spi.master) { /* Master mode */
mbed_official 525:c320967f86b9 159 /* Either mosi or miso can be NC */
mbed_official 525:c320967f86b9 160 if (mosi != NC) {
mbed_official 525:c320967f86b9 161 pin_mode(mosi, Disabled);
mbed_official 525:c320967f86b9 162 }
mbed_official 525:c320967f86b9 163 if (miso != NC) {
mbed_official 525:c320967f86b9 164 pin_mode(miso, Disabled);
mbed_official 525:c320967f86b9 165 }
mbed_official 525:c320967f86b9 166 pin_mode(clk, Disabled);
mbed_official 525:c320967f86b9 167 /* Don't set cs pin, since we toggle it manually */
mbed_official 525:c320967f86b9 168 } else { /* Slave mode */
mbed_official 525:c320967f86b9 169 if (mosi != NC) {
mbed_official 525:c320967f86b9 170 pin_mode(mosi, Disabled);
mbed_official 525:c320967f86b9 171 }
mbed_official 525:c320967f86b9 172 if (miso != NC) {
mbed_official 525:c320967f86b9 173 pin_mode(miso, Disabled);
mbed_official 525:c320967f86b9 174 }
mbed_official 525:c320967f86b9 175 pin_mode(clk, Disabled);
mbed_official 525:c320967f86b9 176 pin_mode(cs, Disabled);
mbed_official 525:c320967f86b9 177 }
mbed_official 525:c320967f86b9 178 }
mbed_official 525:c320967f86b9 179
mbed_official 525:c320967f86b9 180 /* Enabling pins and setting location */
mbed_official 525:c320967f86b9 181 uint32_t route = USART_ROUTE_CLKPEN | (obj->spi.location << _USART_ROUTE_LOCATION_SHIFT);
mbed_official 525:c320967f86b9 182
mbed_official 525:c320967f86b9 183 if (mosi != NC) {
mbed_official 525:c320967f86b9 184 route |= USART_ROUTE_TXPEN;
mbed_official 525:c320967f86b9 185 }
mbed_official 525:c320967f86b9 186 if (miso != NC) {
mbed_official 525:c320967f86b9 187 route |= USART_ROUTE_RXPEN;
mbed_official 525:c320967f86b9 188 }
mbed_official 525:c320967f86b9 189 if (!obj->spi.master) {
mbed_official 525:c320967f86b9 190 route |= USART_ROUTE_CSPEN;
mbed_official 525:c320967f86b9 191 }
mbed_official 525:c320967f86b9 192 obj->spi.spi->ROUTE = route;
mbed_official 525:c320967f86b9 193 }
mbed_official 525:c320967f86b9 194
mbed_official 525:c320967f86b9 195 void spi_enable(spi_t *obj, uint8_t enable)
mbed_official 525:c320967f86b9 196 {
mbed_official 525:c320967f86b9 197 USART_Enable(obj->spi.spi, (enable ? usartEnable : usartDisable));
mbed_official 525:c320967f86b9 198 }
mbed_official 525:c320967f86b9 199
mbed_official 525:c320967f86b9 200 void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName clk, PinName cs)
mbed_official 525:c320967f86b9 201 {
mbed_official 525:c320967f86b9 202 CMU_ClockEnable(cmuClock_HFPER, true);
mbed_official 525:c320967f86b9 203 spi_preinit(obj, mosi, miso, clk, cs);
mbed_official 525:c320967f86b9 204 CMU_ClockEnable(spi_get_clock_tree(obj), true);
mbed_official 525:c320967f86b9 205 usart_init(obj, 100000, usartDatabits8, true, usartClockMode0);
mbed_official 525:c320967f86b9 206
mbed_official 525:c320967f86b9 207 spi_enable_pins(obj, true, mosi, miso, clk, cs);
mbed_official 525:c320967f86b9 208 spi_enable(obj, true);
mbed_official 525:c320967f86b9 209 }
mbed_official 525:c320967f86b9 210
mbed_official 525:c320967f86b9 211 void spi_enable_event(spi_t *obj, uint32_t event, uint8_t enable)
mbed_official 525:c320967f86b9 212 {
mbed_official 525:c320967f86b9 213 if(enable) obj->spi.event |= event;
mbed_official 525:c320967f86b9 214 else obj->spi.event &= ~event;
mbed_official 525:c320967f86b9 215 }
mbed_official 525:c320967f86b9 216
mbed_official 525:c320967f86b9 217 /****************************************************************************
mbed_official 525:c320967f86b9 218 * void spi_enable_interrupt(spi_t *obj, uint32_t handler, uint8_t enable)
mbed_official 525:c320967f86b9 219 *
mbed_official 525:c320967f86b9 220 * This will enable the interrupt in NVIC for the associated USART RX channel
mbed_official 525:c320967f86b9 221 *
mbed_official 525:c320967f86b9 222 * * obj: pointer to spi object
mbed_official 525:c320967f86b9 223 * * handler: pointer to interrupt handler for this channel
mbed_official 525:c320967f86b9 224 * * enable: Whether to enable (true) or disable (false) the interrupt
mbed_official 525:c320967f86b9 225 *
mbed_official 525:c320967f86b9 226 ****************************************************************************/
mbed_official 525:c320967f86b9 227 void spi_enable_interrupt(spi_t *obj, uint32_t handler, uint8_t enable)
mbed_official 525:c320967f86b9 228 {
mbed_official 525:c320967f86b9 229 IRQn_Type IRQvector;
mbed_official 525:c320967f86b9 230
mbed_official 525:c320967f86b9 231 switch ((uint32_t)obj->spi.spi) {
mbed_official 525:c320967f86b9 232 #ifdef USART0
mbed_official 525:c320967f86b9 233 case USART_0:
mbed_official 525:c320967f86b9 234 IRQvector = USART0_RX_IRQn;
mbed_official 525:c320967f86b9 235 break;
mbed_official 525:c320967f86b9 236 #endif
mbed_official 525:c320967f86b9 237 #ifdef USART1
mbed_official 525:c320967f86b9 238 case USART_1:
mbed_official 525:c320967f86b9 239 IRQvector = USART1_RX_IRQn;
mbed_official 525:c320967f86b9 240 break;
mbed_official 525:c320967f86b9 241 #endif
mbed_official 525:c320967f86b9 242 #ifdef USART2
mbed_official 525:c320967f86b9 243 case USART_2:
mbed_official 525:c320967f86b9 244 IRQvector = USART2_RX_IRQn;
mbed_official 525:c320967f86b9 245 break;
mbed_official 525:c320967f86b9 246 #endif
mbed_official 525:c320967f86b9 247 default:
mbed_official 525:c320967f86b9 248 error("Undefined SPI peripheral");
mbed_official 525:c320967f86b9 249 return;
mbed_official 525:c320967f86b9 250 }
mbed_official 525:c320967f86b9 251
mbed_official 525:c320967f86b9 252 if (enable == true) {
mbed_official 525:c320967f86b9 253 NVIC_SetVector(IRQvector, handler);
mbed_official 525:c320967f86b9 254 USART_IntEnable(obj->spi.spi, USART_IEN_RXDATAV);
mbed_official 525:c320967f86b9 255 NVIC_EnableIRQ(IRQvector);
mbed_official 525:c320967f86b9 256 }
mbed_official 525:c320967f86b9 257 else {
mbed_official 525:c320967f86b9 258 NVIC_SetVector(IRQvector, handler);
mbed_official 525:c320967f86b9 259 USART_IntDisable(obj->spi.spi, USART_IEN_RXDATAV);
mbed_official 525:c320967f86b9 260 NVIC_DisableIRQ(IRQvector);
mbed_official 525:c320967f86b9 261 }
mbed_official 525:c320967f86b9 262 }
mbed_official 525:c320967f86b9 263
mbed_official 525:c320967f86b9 264 void spi_format(spi_t *obj, int bits, int mode, int slave)
mbed_official 525:c320967f86b9 265 {
mbed_official 525:c320967f86b9 266 /* Bits: values between 4 and 16 are valid */
mbed_official 525:c320967f86b9 267 MBED_ASSERT(bits >= 4 && bits <= 16);
mbed_official 525:c320967f86b9 268 obj->spi.bits = bits;
mbed_official 525:c320967f86b9 269 /* 0x01 = usartDatabits4, etc, up to 0x0D = usartDatabits16 */
mbed_official 525:c320967f86b9 270 USART_Databits_TypeDef databits = (USART_Databits_TypeDef) (bits - 3);
mbed_official 525:c320967f86b9 271
mbed_official 525:c320967f86b9 272 USART_ClockMode_TypeDef clockMode;
mbed_official 525:c320967f86b9 273 MBED_ASSERT(mode >= 0 && mode <= 3);
mbed_official 525:c320967f86b9 274 switch (mode) {
mbed_official 525:c320967f86b9 275 case 0:
mbed_official 525:c320967f86b9 276 clockMode = usartClockMode0;
mbed_official 525:c320967f86b9 277 break;
mbed_official 525:c320967f86b9 278 case 1:
mbed_official 525:c320967f86b9 279 clockMode = usartClockMode1;
mbed_official 525:c320967f86b9 280 break;
mbed_official 525:c320967f86b9 281 case 2:
mbed_official 525:c320967f86b9 282 clockMode = usartClockMode2;
mbed_official 525:c320967f86b9 283 break;
mbed_official 525:c320967f86b9 284 case 3:
mbed_official 525:c320967f86b9 285 clockMode = usartClockMode3;
mbed_official 525:c320967f86b9 286 break;
mbed_official 525:c320967f86b9 287 default:
mbed_official 525:c320967f86b9 288 clockMode = usartClockMode0;
mbed_official 525:c320967f86b9 289 }
mbed_official 525:c320967f86b9 290
mbed_official 525:c320967f86b9 291 //save state
mbed_official 525:c320967f86b9 292 uint32_t route = obj->spi.spi->ROUTE;
mbed_official 525:c320967f86b9 293 uint32_t iflags = obj->spi.spi->IEN;
mbed_official 525:c320967f86b9 294 bool enabled = (obj->spi.spi->STATUS & (USART_STATUS_RXENS | USART_STATUS_TXENS)) != 0;
mbed_official 525:c320967f86b9 295
mbed_official 525:c320967f86b9 296 usart_init(obj, 100000, databits, (slave ? false : true), clockMode);
mbed_official 525:c320967f86b9 297
mbed_official 525:c320967f86b9 298 //restore state
mbed_official 525:c320967f86b9 299 obj->spi.spi->ROUTE = route;
mbed_official 525:c320967f86b9 300 obj->spi.spi->IEN = iflags;
mbed_official 525:c320967f86b9 301
mbed_official 525:c320967f86b9 302 if(enabled) spi_enable(obj, enabled);
mbed_official 525:c320967f86b9 303 }
mbed_official 525:c320967f86b9 304
mbed_official 525:c320967f86b9 305 void spi_frequency(spi_t *obj, int hz)
mbed_official 525:c320967f86b9 306 {
mbed_official 525:c320967f86b9 307 USART_BaudrateSyncSet(obj->spi.spi, REFERENCE_FREQUENCY, hz);
mbed_official 525:c320967f86b9 308 }
mbed_official 525:c320967f86b9 309
mbed_official 525:c320967f86b9 310 /* Read/Write */
mbed_official 525:c320967f86b9 311
mbed_official 525:c320967f86b9 312 void spi_write(spi_t *obj, int value)
mbed_official 525:c320967f86b9 313 {
mbed_official 525:c320967f86b9 314 if (obj->spi.bits <= 8) {
mbed_official 525:c320967f86b9 315 USART_Tx(obj->spi.spi, (uint8_t) value);
mbed_official 525:c320967f86b9 316 } else if (obj->spi.bits == 9) {
mbed_official 525:c320967f86b9 317 USART_TxExt(obj->spi.spi, (uint16_t) value & 0x1FF);
mbed_official 525:c320967f86b9 318 } else {
mbed_official 525:c320967f86b9 319 USART_TxDouble(obj->spi.spi, (uint16_t) value);
mbed_official 525:c320967f86b9 320 }
mbed_official 525:c320967f86b9 321 }
mbed_official 525:c320967f86b9 322
mbed_official 525:c320967f86b9 323 int spi_read(spi_t *obj)
mbed_official 525:c320967f86b9 324 {
mbed_official 525:c320967f86b9 325 if (obj->spi.bits <= 8) {
mbed_official 525:c320967f86b9 326 return (int) obj->spi.spi->RXDATA;
mbed_official 525:c320967f86b9 327 } else if (obj->spi.bits == 9) {
mbed_official 525:c320967f86b9 328 return (int) obj->spi.spi->RXDATAX & 0x1FF;
mbed_official 525:c320967f86b9 329 } else {
mbed_official 525:c320967f86b9 330 return (int) obj->spi.spi->RXDOUBLE;
mbed_official 525:c320967f86b9 331 }
mbed_official 525:c320967f86b9 332 }
mbed_official 525:c320967f86b9 333
mbed_official 525:c320967f86b9 334 int spi_read_asynch(spi_t *obj)
mbed_official 525:c320967f86b9 335 {
mbed_official 525:c320967f86b9 336 return spi_read(obj);
mbed_official 525:c320967f86b9 337 }
mbed_official 525:c320967f86b9 338
mbed_official 525:c320967f86b9 339 int spi_master_write(spi_t *obj, int value)
mbed_official 525:c320967f86b9 340 {
mbed_official 525:c320967f86b9 341 spi_write(obj, value);
mbed_official 525:c320967f86b9 342
mbed_official 525:c320967f86b9 343 /* Wait for transmission of last byte */
mbed_official 525:c320967f86b9 344 while (!(obj->spi.spi->STATUS & USART_STATUS_TXC)) {
mbed_official 525:c320967f86b9 345 sleep(); // TODO_LP this might break other code, write should be separate from read?
mbed_official 525:c320967f86b9 346 }
mbed_official 525:c320967f86b9 347
mbed_official 525:c320967f86b9 348 return spi_read(obj);
mbed_official 525:c320967f86b9 349 }
mbed_official 525:c320967f86b9 350
mbed_official 525:c320967f86b9 351 inline uint8_t spi_master_tx_ready(spi_t *obj)
mbed_official 525:c320967f86b9 352 {
mbed_official 525:c320967f86b9 353 return (obj->spi.spi->STATUS & USART_STATUS_TXBL) ? true : false;
mbed_official 525:c320967f86b9 354 }
mbed_official 525:c320967f86b9 355
mbed_official 525:c320967f86b9 356 uint8_t spi_master_rx_ready(spi_t *obj)
mbed_official 525:c320967f86b9 357 {
mbed_official 525:c320967f86b9 358 return (obj->spi.spi->STATUS & USART_STATUS_RXDATAV) ? true : false;
mbed_official 525:c320967f86b9 359 }
mbed_official 525:c320967f86b9 360
mbed_official 525:c320967f86b9 361 uint8_t spi_master_tx_int_flag(spi_t *obj)
mbed_official 525:c320967f86b9 362 {
mbed_official 525:c320967f86b9 363 return (obj->spi.spi->IF & USART_IF_TXBL) ? true : false;
mbed_official 525:c320967f86b9 364 }
mbed_official 525:c320967f86b9 365
mbed_official 525:c320967f86b9 366 uint8_t spi_master_rx_int_flag(spi_t *obj)
mbed_official 525:c320967f86b9 367 {
mbed_official 525:c320967f86b9 368 return (obj->spi.spi->IF & (USART_IF_RXDATAV | USART_IF_RXFULL)) ? true : false;
mbed_official 525:c320967f86b9 369 }
mbed_official 525:c320967f86b9 370
mbed_official 525:c320967f86b9 371 void spi_master_read_asynch_complete(spi_t *obj)
mbed_official 525:c320967f86b9 372 {
mbed_official 525:c320967f86b9 373 obj->spi.spi->IFC = USART_IFC_RXFULL; // in case it got full
mbed_official 525:c320967f86b9 374 }
mbed_official 525:c320967f86b9 375
mbed_official 525:c320967f86b9 376 void spi_master_write_asynch_complete(spi_t *obj)
mbed_official 525:c320967f86b9 377 {
mbed_official 525:c320967f86b9 378 obj->spi.spi->IFC = USART_IFC_TXC;
mbed_official 525:c320967f86b9 379 }
mbed_official 525:c320967f86b9 380
mbed_official 525:c320967f86b9 381 void spi_irq_handler(spi_t *obj)
mbed_official 525:c320967f86b9 382 {
mbed_official 525:c320967f86b9 383 spi_read(obj); //TODO_LP store data to the object?
mbed_official 525:c320967f86b9 384 }
mbed_official 525:c320967f86b9 385
mbed_official 525:c320967f86b9 386 uint8_t spi_active(spi_t *obj)
mbed_official 525:c320967f86b9 387 {
mbed_official 525:c320967f86b9 388 switch(obj->spi.dmaOptionsTX.dmaUsageState) {
mbed_official 525:c320967f86b9 389 case DMA_USAGE_TEMPORARY_ALLOCATED:
mbed_official 525:c320967f86b9 390 return true;
mbed_official 525:c320967f86b9 391 case DMA_USAGE_ALLOCATED:
mbed_official 525:c320967f86b9 392 /* Check whether the allocated DMA channel is active */
mbed_official 525:c320967f86b9 393 return(DMA_ChannelEnabled(obj->spi.dmaOptionsTX.dmaChannel) || DMA_ChannelEnabled(obj->spi.dmaOptionsRX.dmaChannel));
mbed_official 525:c320967f86b9 394 default:
mbed_official 525:c320967f86b9 395 /* Check whether interrupt for spi is enabled */
mbed_official 525:c320967f86b9 396 return (obj->spi.spi->IEN & (USART_IEN_RXDATAV | USART_IEN_TXBL)) ? true : false;
mbed_official 525:c320967f86b9 397 }
mbed_official 525:c320967f86b9 398 }
mbed_official 525:c320967f86b9 399
mbed_official 525:c320967f86b9 400 void spi_buffer_set(spi_t *obj, void *tx, uint32_t tx_length, void *rx, uint32_t rx_length, uint8_t bit_width)
mbed_official 525:c320967f86b9 401 {
mbed_official 525:c320967f86b9 402 uint32_t i;
mbed_official 525:c320967f86b9 403 uint16_t *tx_ptr = (uint16_t *) tx;
mbed_official 525:c320967f86b9 404
mbed_official 525:c320967f86b9 405 tx_length *= (bit_width >> 3);
mbed_official 525:c320967f86b9 406 rx_length *= (bit_width >> 3);
mbed_official 525:c320967f86b9 407
mbed_official 525:c320967f86b9 408 obj->tx_buff.buffer = tx;
mbed_official 525:c320967f86b9 409 obj->rx_buff.buffer = rx;
mbed_official 525:c320967f86b9 410 obj->tx_buff.length = tx_length;
mbed_official 525:c320967f86b9 411 obj->rx_buff.length = rx_length;
mbed_official 525:c320967f86b9 412 obj->tx_buff.pos = 0;
mbed_official 525:c320967f86b9 413 obj->rx_buff.pos = 0;
mbed_official 525:c320967f86b9 414 obj->tx_buff.width = bit_width;
mbed_official 525:c320967f86b9 415 obj->rx_buff.width = bit_width;
mbed_official 525:c320967f86b9 416
mbed_official 525:c320967f86b9 417 if((obj->spi.bits == 9) && (tx != 0)) {
mbed_official 525:c320967f86b9 418 // Make sure we don't have inadvertent non-zero bits outside 9-bit frames which could trigger unwanted operation
mbed_official 525:c320967f86b9 419 for(i = 0; i < (tx_length / 2); i++) {
mbed_official 525:c320967f86b9 420 tx_ptr[i] &= 0x1FF;
mbed_official 525:c320967f86b9 421 }
mbed_official 525:c320967f86b9 422 }
mbed_official 525:c320967f86b9 423 }
mbed_official 525:c320967f86b9 424
mbed_official 525:c320967f86b9 425 static void spi_buffer_tx_write(spi_t *obj)
mbed_official 525:c320967f86b9 426 {
mbed_official 525:c320967f86b9 427 uint32_t data;
mbed_official 525:c320967f86b9 428 // This routine gets triggered on TXBL (= buffer empty), so check to see if we can write a double value
mbed_official 525:c320967f86b9 429 if (obj->spi.bits % 9 != 0) {
mbed_official 525:c320967f86b9 430 // No special 9-bit scenario
mbed_official 525:c320967f86b9 431 if((obj->tx_buff.pos < obj->tx_buff.length - 1) && ((obj->tx_buff.pos & 0x1) == 0)) {
mbed_official 525:c320967f86b9 432 // write double frame
mbed_official 525:c320967f86b9 433 if (obj->tx_buff.buffer == (void *)0) {
mbed_official 525:c320967f86b9 434 data = SPI_FILL_WORD;
mbed_official 525:c320967f86b9 435 } else {
mbed_official 525:c320967f86b9 436 uint16_t *tx = (uint16_t *)(obj->tx_buff.buffer);
mbed_official 525:c320967f86b9 437 data = tx[obj->tx_buff.pos / 2] & 0xFFFF;
mbed_official 525:c320967f86b9 438 }
mbed_official 525:c320967f86b9 439 obj->tx_buff.pos += 2;
mbed_official 525:c320967f86b9 440 obj->spi.spi->TXDOUBLE = data;
mbed_official 525:c320967f86b9 441 } else if (obj->tx_buff.pos < obj->tx_buff.length) {
mbed_official 525:c320967f86b9 442 // write single frame
mbed_official 525:c320967f86b9 443 if (obj->tx_buff.buffer == (void *)0) {
mbed_official 525:c320967f86b9 444 data = SPI_FILL_WORD & 0xFF;
mbed_official 525:c320967f86b9 445 } else {
mbed_official 525:c320967f86b9 446 uint8_t *tx = (uint8_t *)(obj->tx_buff.buffer);
mbed_official 525:c320967f86b9 447 data = tx[obj->tx_buff.pos] & 0xFF;
mbed_official 525:c320967f86b9 448 }
mbed_official 525:c320967f86b9 449 obj->tx_buff.pos++;
mbed_official 525:c320967f86b9 450 obj->spi.spi->TXDATA = data;
mbed_official 525:c320967f86b9 451 }
mbed_official 525:c320967f86b9 452 } else {
mbed_official 525:c320967f86b9 453 // 9-bit frame
mbed_official 525:c320967f86b9 454 if(obj->tx_buff.pos < obj->tx_buff.length - 3) {
mbed_official 525:c320967f86b9 455 // write double frame
mbed_official 525:c320967f86b9 456 if (obj->tx_buff.buffer == (void *)0) {
mbed_official 525:c320967f86b9 457 data = ((SPI_FILL_WORD & 0x01FF) << 16) | (SPI_FILL_WORD & 0x1FF);
mbed_official 525:c320967f86b9 458 } else {
mbed_official 525:c320967f86b9 459 uint32_t *tx = (uint32_t *)(obj->tx_buff.buffer);
mbed_official 525:c320967f86b9 460 data = tx[obj->tx_buff.pos / 4] & 0x01FF01FF;
mbed_official 525:c320967f86b9 461 }
mbed_official 525:c320967f86b9 462 obj->tx_buff.pos += 4;
mbed_official 525:c320967f86b9 463 obj->spi.spi->TXDOUBLEX = data;
mbed_official 525:c320967f86b9 464 } else if (obj->tx_buff.pos < obj->tx_buff.length - 1) {
mbed_official 525:c320967f86b9 465 // write single frame
mbed_official 525:c320967f86b9 466 if (obj->tx_buff.buffer == (void *)0) {
mbed_official 525:c320967f86b9 467 data = SPI_FILL_WORD & 0x01FF;
mbed_official 525:c320967f86b9 468 } else {
mbed_official 525:c320967f86b9 469 uint16_t *tx = (uint16_t *)(obj->tx_buff.buffer);
mbed_official 525:c320967f86b9 470 data = tx[obj->tx_buff.pos / 2] & 0x01FF;
mbed_official 525:c320967f86b9 471 }
mbed_official 525:c320967f86b9 472 obj->tx_buff.pos += 2;
mbed_official 525:c320967f86b9 473 obj->spi.spi->TXDATAX = data;
mbed_official 525:c320967f86b9 474 }
mbed_official 525:c320967f86b9 475 }
mbed_official 525:c320967f86b9 476 }
mbed_official 525:c320967f86b9 477
mbed_official 525:c320967f86b9 478 static void spi_buffer_rx_read(spi_t *obj)
mbed_official 525:c320967f86b9 479 {
mbed_official 525:c320967f86b9 480 if (obj->spi.bits % 9 != 0) {
mbed_official 525:c320967f86b9 481 if ((obj->spi.spi->STATUS & USART_STATUS_RXFULL) && (obj->rx_buff.pos < obj->rx_buff.length - 1) && ((obj->rx_buff.pos % 2) == 0)) {
mbed_official 525:c320967f86b9 482 // Read max 16 bits from buffer to speed things up
mbed_official 525:c320967f86b9 483 uint32_t data = (uint32_t)obj->spi.spi->RXDOUBLE; //read the data but store only if rx is set and not full
mbed_official 525:c320967f86b9 484 if (obj->rx_buff.buffer) {
mbed_official 525:c320967f86b9 485 uint16_t *rx = (uint16_t *)(obj->rx_buff.buffer);
mbed_official 525:c320967f86b9 486 rx[obj->rx_buff.pos / 2] = data & 0xFFFF;
mbed_official 525:c320967f86b9 487 obj->rx_buff.pos += 2;
mbed_official 525:c320967f86b9 488 }
mbed_official 525:c320967f86b9 489 } else if ((obj->spi.spi->STATUS & (USART_STATUS_RXDATAV | USART_STATUS_RXFULL)) && (obj->rx_buff.pos < obj->rx_buff.length)) {
mbed_official 525:c320967f86b9 490 // Read 8 bits from buffer
mbed_official 525:c320967f86b9 491 while((obj->spi.spi->STATUS & (USART_STATUS_RXDATAV | USART_STATUS_RXFULL)) && (obj->rx_buff.pos < obj->rx_buff.length)) {
mbed_official 525:c320967f86b9 492 uint32_t data = (uint32_t)obj->spi.spi->RXDATA; //read the data but store only if rx is set and not full
mbed_official 525:c320967f86b9 493 if (obj->rx_buff.buffer) {
mbed_official 525:c320967f86b9 494 uint8_t *rx = (uint8_t *)(obj->rx_buff.buffer);
mbed_official 525:c320967f86b9 495 rx[obj->rx_buff.pos] = data & 0xFF;
mbed_official 525:c320967f86b9 496 obj->rx_buff.pos++;
mbed_official 525:c320967f86b9 497 }
mbed_official 525:c320967f86b9 498 }
mbed_official 525:c320967f86b9 499 } else if (obj->spi.spi->STATUS & USART_STATUS_RXFULL) {
mbed_official 525:c320967f86b9 500 // Read from the buffer to lower the interrupt flag
mbed_official 525:c320967f86b9 501 volatile uint32_t data = (uint32_t)obj->spi.spi->RXDOUBLE;
mbed_official 525:c320967f86b9 502 } else if (obj->spi.spi->STATUS & USART_STATUS_RXDATAV) {
mbed_official 525:c320967f86b9 503 // Read from the buffer to lower the interrupt flag
mbed_official 525:c320967f86b9 504 volatile uint32_t data = (uint32_t)obj->spi.spi->RXDATA;
mbed_official 525:c320967f86b9 505 }
mbed_official 525:c320967f86b9 506 } else {
mbed_official 525:c320967f86b9 507 // Data bits is multiple of 9, so use the extended registers
mbed_official 525:c320967f86b9 508 if ((obj->spi.spi->STATUS & USART_STATUS_RXFULL) && (obj->rx_buff.pos < obj->rx_buff.length - 3) && ((obj->rx_buff.pos % 4) == 0)) {
mbed_official 525:c320967f86b9 509 // Read max 18 bits from buffer to speed things up
mbed_official 525:c320967f86b9 510 uint32_t data = (uint32_t)obj->spi.spi->RXDOUBLEX; //read the data but store only if rx is set and will not overflow
mbed_official 525:c320967f86b9 511 if (obj->rx_buff.buffer) {
mbed_official 525:c320967f86b9 512 uint16_t *rx = (uint16_t *)(obj->rx_buff.buffer);
mbed_official 525:c320967f86b9 513 rx[obj->rx_buff.pos / 2] = data & 0x000001FF;
mbed_official 525:c320967f86b9 514 rx[(obj->rx_buff.pos / 2) + 1] = (data & 0x01FF0000) >> 16;
mbed_official 525:c320967f86b9 515 obj->rx_buff.pos += 4;
mbed_official 525:c320967f86b9 516 }
mbed_official 525:c320967f86b9 517 } else if ((obj->spi.spi->STATUS & (USART_STATUS_RXDATAV | USART_STATUS_RXFULL)) && (obj->rx_buff.pos < obj->rx_buff.length - 1)) {
mbed_official 525:c320967f86b9 518 // Read 9 bits from buffer
mbed_official 525:c320967f86b9 519 while((obj->spi.spi->STATUS & (USART_STATUS_RXDATAV | USART_STATUS_RXFULL)) && (obj->rx_buff.pos < obj->rx_buff.length - 1)) {
mbed_official 525:c320967f86b9 520 uint32_t data = (uint32_t)obj->spi.spi->RXDATAX; //read the data but store only if rx is set and not full
mbed_official 525:c320967f86b9 521 if (obj->rx_buff.buffer) {
mbed_official 525:c320967f86b9 522 uint16_t *rx = (uint16_t *)(obj->rx_buff.buffer);
mbed_official 525:c320967f86b9 523 rx[obj->rx_buff.pos / 2] = data & 0x01FF;
mbed_official 525:c320967f86b9 524 obj->rx_buff.pos += 2;
mbed_official 525:c320967f86b9 525 }
mbed_official 525:c320967f86b9 526 }
mbed_official 525:c320967f86b9 527 } else if (obj->spi.spi->STATUS & USART_STATUS_RXFULL) {
mbed_official 525:c320967f86b9 528 // Read from the buffer to lower the interrupt flag
mbed_official 525:c320967f86b9 529 volatile uint32_t data = (uint32_t)obj->spi.spi->RXDOUBLEX;
mbed_official 525:c320967f86b9 530 } else if (obj->spi.spi->STATUS & USART_STATUS_RXDATAV) {
mbed_official 525:c320967f86b9 531 // Read from the buffer to lower the interrupt flag
mbed_official 525:c320967f86b9 532 volatile uint32_t data = (uint32_t)obj->spi.spi->RXDATAX;
mbed_official 525:c320967f86b9 533 }
mbed_official 525:c320967f86b9 534 }
mbed_official 525:c320967f86b9 535 }
mbed_official 525:c320967f86b9 536
mbed_official 525:c320967f86b9 537 int spi_master_write_asynch(spi_t *obj)
mbed_official 525:c320967f86b9 538 {
mbed_official 525:c320967f86b9 539 int ndata = 0;
mbed_official 525:c320967f86b9 540 while ((obj->tx_buff.pos < obj->tx_buff.length) && (obj->spi.spi->STATUS & USART_STATUS_TXBL)) {
mbed_official 525:c320967f86b9 541 spi_buffer_tx_write(obj);
mbed_official 525:c320967f86b9 542 ndata++;
mbed_official 525:c320967f86b9 543 }
mbed_official 525:c320967f86b9 544 return ndata;
mbed_official 525:c320967f86b9 545 }
mbed_official 525:c320967f86b9 546
mbed_official 525:c320967f86b9 547 int spi_master_read_asynch(spi_t *obj)
mbed_official 525:c320967f86b9 548 {
mbed_official 525:c320967f86b9 549 int ndata = 0;
mbed_official 525:c320967f86b9 550 while ((obj->rx_buff.pos < obj->rx_buff.length) && (obj->spi.spi->STATUS & (USART_STATUS_RXDATAV | USART_STATUS_RXFULL))) {
mbed_official 525:c320967f86b9 551 spi_buffer_rx_read(obj);
mbed_official 525:c320967f86b9 552 ndata++;
mbed_official 525:c320967f86b9 553 }
mbed_official 525:c320967f86b9 554 // all sent but still more to receive? need to align tx buffer
mbed_official 525:c320967f86b9 555 if ((obj->tx_buff.pos >= obj->tx_buff.length) && (obj->rx_buff.pos < obj->rx_buff.length)) {
mbed_official 525:c320967f86b9 556 obj->tx_buff.buffer = (void *)0;
mbed_official 525:c320967f86b9 557 obj->tx_buff.length = obj->rx_buff.length;
mbed_official 525:c320967f86b9 558 }
mbed_official 525:c320967f86b9 559
mbed_official 525:c320967f86b9 560 return ndata;
mbed_official 525:c320967f86b9 561 }
mbed_official 525:c320967f86b9 562
mbed_official 525:c320967f86b9 563 uint8_t spi_buffer_rx_empty(spi_t *obj)
mbed_official 525:c320967f86b9 564 {
mbed_official 525:c320967f86b9 565 return (obj->rx_buff.pos >= obj->rx_buff.length ? true : false );
mbed_official 525:c320967f86b9 566 }
mbed_official 525:c320967f86b9 567
mbed_official 525:c320967f86b9 568 uint8_t spi_buffer_tx_empty(spi_t *obj)
mbed_official 525:c320967f86b9 569 {
mbed_official 525:c320967f86b9 570 return (obj->tx_buff.pos >= obj->tx_buff.length ? true : false );
mbed_official 525:c320967f86b9 571 }
mbed_official 525:c320967f86b9 572
mbed_official 525:c320967f86b9 573 //TODO_LP implement slave
mbed_official 525:c320967f86b9 574
mbed_official 525:c320967f86b9 575 int spi_slave_receive(spi_t *obj)
mbed_official 525:c320967f86b9 576 {
mbed_official 525:c320967f86b9 577 if (obj->spi.bits <= 9) {
mbed_official 525:c320967f86b9 578 return (obj->spi.spi->STATUS & USART_STATUS_RXDATAV) ? 1 : 0;
mbed_official 525:c320967f86b9 579 } else {
mbed_official 525:c320967f86b9 580 return (obj->spi.spi->STATUS & USART_STATUS_RXFULL) ? 1 : 0;
mbed_official 525:c320967f86b9 581 }
mbed_official 525:c320967f86b9 582 }
mbed_official 525:c320967f86b9 583
mbed_official 525:c320967f86b9 584 int spi_slave_read(spi_t *obj)
mbed_official 525:c320967f86b9 585 {
mbed_official 525:c320967f86b9 586 return spi_read(obj);
mbed_official 525:c320967f86b9 587 }
mbed_official 525:c320967f86b9 588
mbed_official 525:c320967f86b9 589 void spi_slave_write(spi_t *obj, int value)
mbed_official 525:c320967f86b9 590 {
mbed_official 525:c320967f86b9 591 spi_write(obj, value);
mbed_official 525:c320967f86b9 592 }
mbed_official 525:c320967f86b9 593
mbed_official 525:c320967f86b9 594 uint32_t spi_event_check(spi_t *obj)
mbed_official 525:c320967f86b9 595 {
mbed_official 525:c320967f86b9 596 uint32_t requestedEvent = obj->spi.event;
mbed_official 525:c320967f86b9 597 uint32_t event = 0;
mbed_official 525:c320967f86b9 598 uint8_t quit = spi_buffer_rx_empty(obj) & spi_buffer_tx_empty(obj);
mbed_official 525:c320967f86b9 599 if (((requestedEvent & SPI_EVENT_COMPLETE) != 0) && (quit == true)) {
mbed_official 525:c320967f86b9 600 event |= SPI_EVENT_COMPLETE;
mbed_official 525:c320967f86b9 601 }
mbed_official 525:c320967f86b9 602
mbed_official 525:c320967f86b9 603 if(quit == true) {
mbed_official 525:c320967f86b9 604 event |= SPI_EVENT_INTERNAL_TRANSFER_COMPLETE;
mbed_official 525:c320967f86b9 605 }
mbed_official 525:c320967f86b9 606
mbed_official 525:c320967f86b9 607 return event;
mbed_official 525:c320967f86b9 608 }
mbed_official 525:c320967f86b9 609 /******************************************
mbed_official 525:c320967f86b9 610 * void transferComplete(uint channel, bool primary, void* user)
mbed_official 525:c320967f86b9 611 *
mbed_official 525:c320967f86b9 612 * Callback function which gets called upon DMA transfer completion
mbed_official 525:c320967f86b9 613 * the user-defined pointer is pointing to the CPP-land thunk
mbed_official 525:c320967f86b9 614 ******************************************/
mbed_official 525:c320967f86b9 615 void transferComplete(unsigned int channel, bool primary, void *user)
mbed_official 525:c320967f86b9 616 {
mbed_official 525:c320967f86b9 617 (void) channel;
mbed_official 525:c320967f86b9 618 (void) primary;
mbed_official 525:c320967f86b9 619
mbed_official 525:c320967f86b9 620 /* User pointer should be a thunk to CPP land */
mbed_official 525:c320967f86b9 621 if (user != NULL) {
mbed_official 525:c320967f86b9 622 ((DMACallback)user)();
mbed_official 525:c320967f86b9 623 }
mbed_official 525:c320967f86b9 624 }
mbed_official 525:c320967f86b9 625
mbed_official 525:c320967f86b9 626 /******************************************
mbed_official 525:c320967f86b9 627 * bool spi_allocate_dma(spi_t *obj);
mbed_official 525:c320967f86b9 628 * (helper function for spi_enable_dma)
mbed_official 525:c320967f86b9 629 *
mbed_official 525:c320967f86b9 630 * This function will request two DMA channels from the DMA API if needed
mbed_official 525:c320967f86b9 631 * by the hint provided. They will be allocated to the SPI object pointed to.
mbed_official 525:c320967f86b9 632 *
mbed_official 525:c320967f86b9 633 * return value: whether the channels were acquired successfully (true) or not.
mbed_official 525:c320967f86b9 634 ******************************************/
mbed_official 525:c320967f86b9 635 bool spi_allocate_dma(spi_t *obj) {
mbed_official 525:c320967f86b9 636 int dmaChannelIn, dmaChannelOut;
mbed_official 525:c320967f86b9 637 dmaChannelIn = dma_channel_allocate(DMA_CAP_NONE);
mbed_official 525:c320967f86b9 638 if (dmaChannelIn == DMA_ERROR_OUT_OF_CHANNELS) {
mbed_official 525:c320967f86b9 639 return false;
mbed_official 525:c320967f86b9 640 }
mbed_official 525:c320967f86b9 641 dmaChannelOut = dma_channel_allocate(DMA_CAP_NONE);
mbed_official 525:c320967f86b9 642 if (dmaChannelOut == DMA_ERROR_OUT_OF_CHANNELS) {
mbed_official 525:c320967f86b9 643 dma_channel_free(dmaChannelIn);
mbed_official 525:c320967f86b9 644 return false;
mbed_official 525:c320967f86b9 645 }
mbed_official 525:c320967f86b9 646
mbed_official 525:c320967f86b9 647 obj->spi.dmaOptionsTX.dmaChannel = dmaChannelOut;
mbed_official 525:c320967f86b9 648 obj->spi.dmaOptionsRX.dmaChannel = dmaChannelIn;
mbed_official 525:c320967f86b9 649 return true;
mbed_official 525:c320967f86b9 650 }
mbed_official 525:c320967f86b9 651
mbed_official 525:c320967f86b9 652 /******************************************
mbed_official 525:c320967f86b9 653 * void spi_enable_dma(spi_t *obj, DMAUsage state)
mbed_official 525:c320967f86b9 654 *
mbed_official 525:c320967f86b9 655 * This function tries to allocate DMA as indicated by the hint (state).
mbed_official 525:c320967f86b9 656 * There are three possibilities:
mbed_official 525:c320967f86b9 657 * * state = NEVER:
mbed_official 525:c320967f86b9 658 * if there were channels allocated by state = ALWAYS, they will be released
mbed_official 525:c320967f86b9 659 * * state = OPPORTUNITIC:
mbed_official 525:c320967f86b9 660 * if there are channels available, they will get used, but freed upon transfer completion
mbed_official 525:c320967f86b9 661 * * state = ALWAYS
mbed_official 525:c320967f86b9 662 * if there are channels available, they will get allocated and not be freed until state changes
mbed_official 525:c320967f86b9 663 ******************************************/
mbed_official 525:c320967f86b9 664 void spi_enable_dma(spi_t *obj, DMAUsage state)
mbed_official 525:c320967f86b9 665 {
mbed_official 525:c320967f86b9 666 if (state == DMA_USAGE_ALWAYS && obj->spi.dmaOptionsTX.dmaUsageState != DMA_USAGE_ALLOCATED) {
mbed_official 525:c320967f86b9 667 /* Try to allocate channels */
mbed_official 525:c320967f86b9 668 if (spi_allocate_dma(obj)) {
mbed_official 525:c320967f86b9 669 obj->spi.dmaOptionsTX.dmaUsageState = DMA_USAGE_ALLOCATED;
mbed_official 525:c320967f86b9 670 } else {
mbed_official 525:c320967f86b9 671 obj->spi.dmaOptionsTX.dmaUsageState = state;
mbed_official 525:c320967f86b9 672 }
mbed_official 525:c320967f86b9 673 } else if (state == DMA_USAGE_OPPORTUNISTIC) {
mbed_official 525:c320967f86b9 674 if (obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_ALLOCATED) {
mbed_official 525:c320967f86b9 675 /* Channels have already been allocated previously by an ALWAYS state, so after this transfer, we will release them */
mbed_official 525:c320967f86b9 676 obj->spi.dmaOptionsTX.dmaUsageState = DMA_USAGE_TEMPORARY_ALLOCATED;
mbed_official 525:c320967f86b9 677 } else {
mbed_official 525:c320967f86b9 678 /* Try to allocate channels */
mbed_official 525:c320967f86b9 679 if (spi_allocate_dma(obj)) {
mbed_official 525:c320967f86b9 680 obj->spi.dmaOptionsTX.dmaUsageState = DMA_USAGE_TEMPORARY_ALLOCATED;
mbed_official 525:c320967f86b9 681 } else {
mbed_official 525:c320967f86b9 682 obj->spi.dmaOptionsTX.dmaUsageState = state;
mbed_official 525:c320967f86b9 683 }
mbed_official 525:c320967f86b9 684 }
mbed_official 525:c320967f86b9 685 } else if (state == DMA_USAGE_NEVER) {
mbed_official 525:c320967f86b9 686 /* If channels are allocated, get rid of them */
mbed_official 525:c320967f86b9 687 if (obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_ALLOCATED) {
mbed_official 525:c320967f86b9 688 dma_channel_free(obj->spi.dmaOptionsTX.dmaChannel);
mbed_official 525:c320967f86b9 689 dma_channel_free(obj->spi.dmaOptionsRX.dmaChannel);
mbed_official 525:c320967f86b9 690 }
mbed_official 525:c320967f86b9 691 obj->spi.dmaOptionsTX.dmaUsageState = DMA_USAGE_NEVER;
mbed_official 525:c320967f86b9 692 }
mbed_official 525:c320967f86b9 693 }
mbed_official 525:c320967f86b9 694
mbed_official 525:c320967f86b9 695 /******************************************
mbed_official 525:c320967f86b9 696 * void spi_master_dma_channel_setup(spi_t *obj)
mbed_official 525:c320967f86b9 697 *
mbed_official 525:c320967f86b9 698 * This function will setup the DMA configuration for SPI transfers
mbed_official 525:c320967f86b9 699 *
mbed_official 525:c320967f86b9 700 * The channel numbers are fetched from the SPI instance, so this function
mbed_official 525:c320967f86b9 701 * should only be called when those channels have actually been allocated.
mbed_official 525:c320967f86b9 702 ******************************************/
mbed_official 525:c320967f86b9 703 static void spi_master_dma_channel_setup(spi_t *obj, void* callback)
mbed_official 525:c320967f86b9 704 {
mbed_official 525:c320967f86b9 705 DMA_CfgChannel_TypeDef rxChnlCfg;
mbed_official 525:c320967f86b9 706 DMA_CfgChannel_TypeDef txChnlCfg;
mbed_official 525:c320967f86b9 707
mbed_official 525:c320967f86b9 708 /* Setting up channel for rx. */
mbed_official 525:c320967f86b9 709 obj->spi.dmaOptionsRX.dmaCallback.cbFunc = transferComplete;
mbed_official 525:c320967f86b9 710 obj->spi.dmaOptionsRX.dmaCallback.userPtr = callback;
mbed_official 525:c320967f86b9 711
mbed_official 525:c320967f86b9 712 rxChnlCfg.highPri = false;
mbed_official 525:c320967f86b9 713 rxChnlCfg.enableInt = true;
mbed_official 525:c320967f86b9 714 rxChnlCfg.cb = &(obj->spi.dmaOptionsRX.dmaCallback);
mbed_official 525:c320967f86b9 715
mbed_official 525:c320967f86b9 716 /* Setting up channel for tx. */
mbed_official 525:c320967f86b9 717 obj->spi.dmaOptionsTX.dmaCallback.cbFunc = transferComplete;
mbed_official 525:c320967f86b9 718 obj->spi.dmaOptionsTX.dmaCallback.userPtr = callback;
mbed_official 525:c320967f86b9 719
mbed_official 525:c320967f86b9 720 txChnlCfg.highPri = false;
mbed_official 525:c320967f86b9 721 txChnlCfg.enableInt = true;
mbed_official 525:c320967f86b9 722 txChnlCfg.cb = &(obj->spi.dmaOptionsTX.dmaCallback);
mbed_official 525:c320967f86b9 723
mbed_official 525:c320967f86b9 724 switch ((int)obj->spi.spi) {
mbed_official 525:c320967f86b9 725 #ifdef USART0
mbed_official 525:c320967f86b9 726 case SPI_0:
mbed_official 525:c320967f86b9 727 rxChnlCfg.select = DMAREQ_USART0_RXDATAV;
mbed_official 525:c320967f86b9 728 txChnlCfg.select = DMAREQ_USART0_TXEMPTY;
mbed_official 525:c320967f86b9 729 break;
mbed_official 525:c320967f86b9 730 #endif
mbed_official 525:c320967f86b9 731 #ifdef USART1
mbed_official 525:c320967f86b9 732 case SPI_1:
mbed_official 525:c320967f86b9 733 rxChnlCfg.select = DMAREQ_USART1_RXDATAV;
mbed_official 525:c320967f86b9 734 txChnlCfg.select = DMAREQ_USART1_TXEMPTY;
mbed_official 525:c320967f86b9 735 break;
mbed_official 525:c320967f86b9 736 #endif
mbed_official 525:c320967f86b9 737 #ifdef USART2
mbed_official 525:c320967f86b9 738 case SPI_2:
mbed_official 525:c320967f86b9 739 rxChnlCfg.select = DMAREQ_USART2_RXDATAV;
mbed_official 525:c320967f86b9 740 txChnlCfg.select = DMAREQ_USART2_TXEMPTY;
mbed_official 525:c320967f86b9 741 break;
mbed_official 525:c320967f86b9 742 #endif
mbed_official 525:c320967f86b9 743 default:
mbed_official 525:c320967f86b9 744 error("Spi module not available.. Out of bound access.");
mbed_official 525:c320967f86b9 745 break;
mbed_official 525:c320967f86b9 746 }
mbed_official 525:c320967f86b9 747 DMA_CfgChannel(obj->spi.dmaOptionsRX.dmaChannel, &rxChnlCfg);
mbed_official 525:c320967f86b9 748 DMA_CfgChannel(obj->spi.dmaOptionsTX.dmaChannel, &txChnlCfg);
mbed_official 525:c320967f86b9 749 }
mbed_official 525:c320967f86b9 750
mbed_official 525:c320967f86b9 751 /******************************************
mbed_official 525:c320967f86b9 752 * void spi_activate_dma(spi_t *obj, void* rxdata, void* txdata, int length)
mbed_official 525:c320967f86b9 753 *
mbed_official 525:c320967f86b9 754 * This function will start the DMA engine for SPI transfers
mbed_official 525:c320967f86b9 755 *
mbed_official 525:c320967f86b9 756 * * rxdata: pointer to RX buffer, if needed.
mbed_official 525:c320967f86b9 757 * * txdata: pointer to TX buffer, if needed. Else FF's.
mbed_official 525:c320967f86b9 758 * * tx_length: how many bytes will get sent.
mbed_official 525:c320967f86b9 759 * * 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 525:c320967f86b9 760 ******************************************/
mbed_official 525:c320967f86b9 761 static void spi_activate_dma(spi_t *obj, void* rxdata, void* txdata, int tx_length, int rx_length) {
mbed_official 525:c320967f86b9 762 /* DMA descriptors */
mbed_official 525:c320967f86b9 763 DMA_CfgDescr_TypeDef rxDescrCfg;
mbed_official 525:c320967f86b9 764 DMA_CfgDescr_TypeDef txDescrCfg;
mbed_official 525:c320967f86b9 765
mbed_official 525:c320967f86b9 766 /* Save amount of TX done by DMA */
mbed_official 525:c320967f86b9 767 obj->tx_buff.pos = tx_length;
mbed_official 525:c320967f86b9 768
mbed_official 525:c320967f86b9 769 if(obj->spi.bits != 9) {
mbed_official 525:c320967f86b9 770 /* Only activate RX DMA if a receive buffer is specified */
mbed_official 525:c320967f86b9 771 if (rxdata != NULL) {
mbed_official 525:c320967f86b9 772 // Setting up channel descriptor
mbed_official 525:c320967f86b9 773 rxDescrCfg.dstInc = dmaDataInc1;
mbed_official 525:c320967f86b9 774 rxDescrCfg.srcInc = dmaDataIncNone;
mbed_official 525:c320967f86b9 775 rxDescrCfg.size = dmaDataSize1;
mbed_official 525:c320967f86b9 776 rxDescrCfg.arbRate = dmaArbitrate1;
mbed_official 525:c320967f86b9 777 rxDescrCfg.hprot = 0;
mbed_official 525:c320967f86b9 778 DMA_CfgDescr(obj->spi.dmaOptionsRX.dmaChannel, true, &rxDescrCfg);
mbed_official 525:c320967f86b9 779
mbed_official 525:c320967f86b9 780 // Clear RX registers - Useful if previous command transfered don't
mbed_official 525:c320967f86b9 781 obj->spi.spi->CMD = USART_CMD_CLEARRX;
mbed_official 525:c320967f86b9 782
mbed_official 525:c320967f86b9 783 /* Activate RX channel */
mbed_official 525:c320967f86b9 784 DMA_ActivateBasic(obj->spi.dmaOptionsRX.dmaChannel, true, false, rxdata, (void *)&(obj->spi.spi->RXDATA),
mbed_official 525:c320967f86b9 785 rx_length - 1);
mbed_official 525:c320967f86b9 786 }
mbed_official 525:c320967f86b9 787
mbed_official 525:c320967f86b9 788 // buffer with all FFs.
mbed_official 525:c320967f86b9 789 /* Setting up channel descriptor */
mbed_official 525:c320967f86b9 790 txDescrCfg.dstInc = dmaDataIncNone;
mbed_official 525:c320967f86b9 791 txDescrCfg.srcInc = (txdata == 0 ? dmaDataIncNone : (obj->spi.bits <= 8 ? dmaDataInc1 : dmaDataInc2)); //Do not increment source pointer when there is no transmit buffer
mbed_official 525:c320967f86b9 792 txDescrCfg.size = (obj->spi.bits <= 8 ? dmaDataSize1 : dmaDataSize2); //When frame size > 9, we can use TXDOUBLE to save bandwidth
mbed_official 525:c320967f86b9 793 txDescrCfg.arbRate = dmaArbitrate1;
mbed_official 525:c320967f86b9 794 txDescrCfg.hprot = 0;
mbed_official 525:c320967f86b9 795 DMA_CfgDescr(obj->spi.dmaOptionsTX.dmaChannel, true, &txDescrCfg);
mbed_official 525:c320967f86b9 796
mbed_official 525:c320967f86b9 797 /* Clear TX registers */
mbed_official 525:c320967f86b9 798 obj->spi.spi->CMD = USART_CMD_CLEARTX;
mbed_official 525:c320967f86b9 799
mbed_official 525:c320967f86b9 800 /* Activate TX channel */
mbed_official 525:c320967f86b9 801 DMA_ActivateBasic( obj->spi.dmaOptionsTX.dmaChannel,
mbed_official 525:c320967f86b9 802 true,
mbed_official 525:c320967f86b9 803 false,
mbed_official 525:c320967f86b9 804 (obj->spi.bits <= 8 ? (void *)&(obj->spi.spi->TXDATA) : (void *)&(obj->spi.spi->TXDOUBLE)), //When frame size > 9, point to TXDOUBLE
mbed_official 525:c320967f86b9 805 (txdata == 0 ? &fill_word : txdata), // When there is nothing to transmit, point to static fill word
mbed_official 525:c320967f86b9 806 (obj->spi.bits <= 8 ? tx_length - 1 : (tx_length / 2) - 1)); // When using TXDOUBLE, recalculate transfer length
mbed_official 525:c320967f86b9 807 } else {
mbed_official 525:c320967f86b9 808 /* Frame size == 9 */
mbed_official 525:c320967f86b9 809 /* Only activate RX DMA if a receive buffer is specified */
mbed_official 525:c320967f86b9 810 if (rxdata != NULL) {
mbed_official 525:c320967f86b9 811 // Setting up channel descriptor
mbed_official 525:c320967f86b9 812 rxDescrCfg.dstInc = dmaDataInc2;
mbed_official 525:c320967f86b9 813 rxDescrCfg.srcInc = dmaDataIncNone;
mbed_official 525:c320967f86b9 814 rxDescrCfg.size = dmaDataSize2;
mbed_official 525:c320967f86b9 815 rxDescrCfg.arbRate = dmaArbitrate1;
mbed_official 525:c320967f86b9 816 rxDescrCfg.hprot = 0;
mbed_official 525:c320967f86b9 817 DMA_CfgDescr(obj->spi.dmaOptionsRX.dmaChannel, true, &rxDescrCfg);
mbed_official 525:c320967f86b9 818
mbed_official 525:c320967f86b9 819 // Clear RX registers - Useful if previous command transfered don't
mbed_official 525:c320967f86b9 820 obj->spi.spi->CMD = USART_CMD_CLEARRX;
mbed_official 525:c320967f86b9 821
mbed_official 525:c320967f86b9 822 /* Activate RX channel */
mbed_official 525:c320967f86b9 823 DMA_ActivateBasic(obj->spi.dmaOptionsRX.dmaChannel, true, false, rxdata, (void *)&(obj->spi.spi->RXDATAX),
mbed_official 525:c320967f86b9 824 (rx_length / 2) - 1);
mbed_official 525:c320967f86b9 825 }
mbed_official 525:c320967f86b9 826
mbed_official 525:c320967f86b9 827 /* Setting up channel descriptor */
mbed_official 525:c320967f86b9 828 txDescrCfg.dstInc = dmaDataIncNone;
mbed_official 525:c320967f86b9 829 txDescrCfg.srcInc = (txdata == 0 ? dmaDataIncNone : dmaDataInc2); //Do not increment source pointer when there is no transmit buffer
mbed_official 525:c320967f86b9 830 txDescrCfg.size = dmaDataSize2; //When frame size > 9, we can use TXDOUBLE to save bandwidth
mbed_official 525:c320967f86b9 831 txDescrCfg.arbRate = dmaArbitrate1;
mbed_official 525:c320967f86b9 832 txDescrCfg.hprot = 0;
mbed_official 525:c320967f86b9 833 DMA_CfgDescr(obj->spi.dmaOptionsTX.dmaChannel, true, &txDescrCfg);
mbed_official 525:c320967f86b9 834
mbed_official 525:c320967f86b9 835 /* Clear TX registers */
mbed_official 525:c320967f86b9 836 obj->spi.spi->CMD = USART_CMD_CLEARTX;
mbed_official 525:c320967f86b9 837
mbed_official 525:c320967f86b9 838 /* Activate TX channel */
mbed_official 525:c320967f86b9 839 DMA_ActivateBasic( obj->spi.dmaOptionsTX.dmaChannel,
mbed_official 525:c320967f86b9 840 true,
mbed_official 525:c320967f86b9 841 false,
mbed_official 525:c320967f86b9 842 (void *)&(obj->spi.spi->TXDATAX), //When frame size > 9, point to TXDOUBLE
mbed_official 525:c320967f86b9 843 (txdata == 0 ? &fill_word : txdata), // When there is nothing to transmit, point to static fill word
mbed_official 525:c320967f86b9 844 (tx_length / 2) - 1); // When using TXDOUBLE, recalculate transfer length
mbed_official 525:c320967f86b9 845 }
mbed_official 525:c320967f86b9 846 }
mbed_official 525:c320967f86b9 847
mbed_official 525:c320967f86b9 848 /********************************************************************
mbed_official 525:c320967f86b9 849 * spi_master_transfer_dma(spi_t *obj, void *rxdata, void *txdata, int length, DMACallback cb, DMAUsage hint)
mbed_official 525:c320967f86b9 850 *
mbed_official 525:c320967f86b9 851 * Start an SPI transfer by using DMA and the supplied hint for DMA useage
mbed_official 525:c320967f86b9 852 *
mbed_official 525:c320967f86b9 853 * * obj: pointer to specific SPI instance
mbed_official 525:c320967f86b9 854 * * rxdata: pointer to rx buffer. If null, we will assume only TX is relevant, and RX will be ignored.
mbed_official 525:c320967f86b9 855 * * txdata: pointer to TX buffer. If null, we will assume only the read is relevant, and will send FF's for reading back.
mbed_official 525:c320967f86b9 856 * * length: How many bytes should be written/read.
mbed_official 525:c320967f86b9 857 * * cb: thunk pointer into CPP-land to get the spi object
mbed_official 525:c320967f86b9 858 * * hint: hint for the requested DMA useage.
mbed_official 525:c320967f86b9 859 * * NEVER: do not use DMA, but use IRQ instead
mbed_official 525:c320967f86b9 860 * * OPPORTUNISTIC: use DMA if there are channels available, but return them after the transfer.
mbed_official 525:c320967f86b9 861 * * ALWAYS: use DMA if channels are available, and hold on to the channels after the transfer.
mbed_official 525:c320967f86b9 862 * If the previous transfer has kept the channel, that channel will continue to get used.
mbed_official 525:c320967f86b9 863 *
mbed_official 525:c320967f86b9 864 ********************************************************************/
mbed_official 525:c320967f86b9 865 void spi_master_transfer_dma(spi_t *obj, void *txdata, void *rxdata, int tx_length, int rx_length, void* cb, DMAUsage hint) {
mbed_official 525:c320967f86b9 866 /* Init DMA here to include it in the power figure */
mbed_official 525:c320967f86b9 867 dma_init();
mbed_official 525:c320967f86b9 868 /* If the DMA channels are already allocated, we can assume they have been setup already */
mbed_official 525:c320967f86b9 869 if (hint != DMA_USAGE_NEVER && obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_ALLOCATED) {
mbed_official 525:c320967f86b9 870 /* setup has already been done, so just activate the transfer */
mbed_official 525:c320967f86b9 871 spi_activate_dma(obj, rxdata, txdata, tx_length, rx_length);
mbed_official 525:c320967f86b9 872 } else if (hint == DMA_USAGE_NEVER) {
mbed_official 525:c320967f86b9 873 /* use IRQ */
mbed_official 525:c320967f86b9 874 obj->spi.spi->IFC = 0xFFFFFFFF;
mbed_official 525:c320967f86b9 875 spi_master_write_asynch(obj);
mbed_official 525:c320967f86b9 876 spi_enable_interrupt(obj, (uint32_t)cb, true);
mbed_official 525:c320967f86b9 877 } else {
mbed_official 525:c320967f86b9 878 /* try to acquire channels */
mbed_official 525:c320967f86b9 879 dma_init();
mbed_official 525:c320967f86b9 880 spi_enable_dma(obj, hint);
mbed_official 525:c320967f86b9 881
mbed_official 525:c320967f86b9 882 /* decide between DMA and IRQ */
mbed_official 525:c320967f86b9 883 if (obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_ALLOCATED || obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) {
mbed_official 525:c320967f86b9 884 /* disable the interrupts that may have been left open previously */
mbed_official 525:c320967f86b9 885 spi_enable_interrupt(obj, (uint32_t)cb, false);
mbed_official 525:c320967f86b9 886
mbed_official 525:c320967f86b9 887 /* DMA channels are allocated, so do their setup */
mbed_official 525:c320967f86b9 888 spi_master_dma_channel_setup(obj, cb);
mbed_official 525:c320967f86b9 889 /* and activate the transfer */
mbed_official 525:c320967f86b9 890 spi_activate_dma(obj, rxdata, txdata, tx_length, rx_length);
mbed_official 525:c320967f86b9 891 } else {
mbed_official 525:c320967f86b9 892 /* DMA is unavailable, so fall back to IRQ */
mbed_official 525:c320967f86b9 893 obj->spi.spi->IFC = 0xFFFFFFFF;
mbed_official 525:c320967f86b9 894 spi_master_write_asynch(obj);
mbed_official 525:c320967f86b9 895 spi_enable_interrupt(obj, (uint32_t)cb, true);
mbed_official 525:c320967f86b9 896 }
mbed_official 525:c320967f86b9 897 }
mbed_official 525:c320967f86b9 898 }
mbed_official 525:c320967f86b9 899
mbed_official 525:c320967f86b9 900 /** Begin the SPI transfer. Buffer pointers and lengths are specified in tx_buff and rx_buff
mbed_official 525:c320967f86b9 901 *
mbed_official 525:c320967f86b9 902 * @param[in] obj The SPI object which holds the transfer information
mbed_official 525:c320967f86b9 903 * @param[in] tx The buffer to send
mbed_official 525:c320967f86b9 904 * @param[in] tx_length The number of words to transmit
mbed_official 525:c320967f86b9 905 * @param[in] rx The buffer to receive
mbed_official 525:c320967f86b9 906 * @param[in] rx_length The number of words to receive
mbed_official 525:c320967f86b9 907 * @param[in] bit_width The bit width of buffer words
mbed_official 525:c320967f86b9 908 * @param[in] event The logical OR of events to be registered
mbed_official 525:c320967f86b9 909 * @param[in] handler SPI interrupt handler
mbed_official 525:c320967f86b9 910 * @param[in] hint A suggestion for how to use DMA with this transfer
mbed_official 525:c320967f86b9 911 */
mbed_official 525:c320967f86b9 912 void spi_master_transfer(spi_t *obj, void *tx, size_t tx_length, void *rx, size_t rx_length, uint8_t bit_width, uint32_t handler, uint32_t event, DMAUsage hint) {
mbed_official 525:c320967f86b9 913 if( spi_active(obj) ) return;
mbed_official 525:c320967f86b9 914
mbed_official 525:c320967f86b9 915 /* update fill word if on 9-bit frame size */
mbed_official 525:c320967f86b9 916 if(obj->spi.bits == 9) fill_word = SPI_FILL_WORD & 0x1FF;
mbed_official 525:c320967f86b9 917 else fill_word = SPI_FILL_WORD;
mbed_official 525:c320967f86b9 918
mbed_official 525:c320967f86b9 919 /* check corner case */
mbed_official 525:c320967f86b9 920 if(tx_length == 0) {
mbed_official 525:c320967f86b9 921 tx_length = rx_length;
mbed_official 525:c320967f86b9 922 tx = (void*) 0;
mbed_official 525:c320967f86b9 923 }
mbed_official 525:c320967f86b9 924
mbed_official 525:c320967f86b9 925 /* First, set the buffer */
mbed_official 525:c320967f86b9 926 spi_buffer_set(obj, tx, tx_length, rx, rx_length, bit_width);
mbed_official 525:c320967f86b9 927
mbed_official 525:c320967f86b9 928 /* Then, enable the events */
mbed_official 525:c320967f86b9 929 spi_enable_event(obj, SPI_EVENT_ALL, false);
mbed_official 525:c320967f86b9 930 spi_enable_event(obj, event, true);
mbed_official 525:c320967f86b9 931
mbed_official 525:c320967f86b9 932 /* Be tricky on how we handle increased bit widths in the buffer... Handling on byte-basis */
mbed_official 525:c320967f86b9 933 // div 8 = shift right 3
mbed_official 525:c320967f86b9 934 tx_length = tx_length * (bit_width >> 3);
mbed_official 525:c320967f86b9 935 rx_length = rx_length * (bit_width >> 3);
mbed_official 525:c320967f86b9 936
mbed_official 525:c320967f86b9 937 // Set the sleep mode
mbed_official 525:c320967f86b9 938 blockSleepMode(SPI_LEAST_ACTIVE_SLEEPMODE);
mbed_official 525:c320967f86b9 939
mbed_official 525:c320967f86b9 940 /* And kick off the transfer */
mbed_official 525:c320967f86b9 941 spi_master_transfer_dma(obj, tx, rx, tx_length, rx_length, (void*)handler, hint);
mbed_official 525:c320967f86b9 942 }
mbed_official 525:c320967f86b9 943
mbed_official 525:c320967f86b9 944
mbed_official 525:c320967f86b9 945 /********************************************************************
mbed_official 525:c320967f86b9 946 * uint32_t spi_irq_handler_generic(spi_t* obj)
mbed_official 525:c320967f86b9 947 *
mbed_official 525:c320967f86b9 948 * handler which should get called by CPP-land when either a DMA or SPI IRQ gets fired for a SPI transaction.
mbed_official 525:c320967f86b9 949 *
mbed_official 525:c320967f86b9 950 * * obj: pointer to the specific SPI instance
mbed_official 525:c320967f86b9 951 *
mbed_official 525:c320967f86b9 952 * return: event mask. Currently only 0 or SPI_EVENT_COMPLETE upon transfer completion.
mbed_official 525:c320967f86b9 953 *
mbed_official 525:c320967f86b9 954 ********************************************************************/
mbed_official 525:c320967f86b9 955 uint32_t spi_irq_handler_asynch(spi_t* obj) {
mbed_official 525:c320967f86b9 956
mbed_official 525:c320967f86b9 957 /* Determine whether the current scenario is DMA or IRQ, and act accordingly */
mbed_official 525:c320967f86b9 958
mbed_official 525:c320967f86b9 959 if (obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_ALLOCATED || obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) {
mbed_official 525:c320967f86b9 960 /* DMA implementation */
mbed_official 525:c320967f86b9 961
mbed_official 525:c320967f86b9 962 /* If there is an RX transfer ongoing, wait for it to finish */
mbed_official 525:c320967f86b9 963 if (DMA_ChannelEnabled(obj->spi.dmaOptionsRX.dmaChannel)) {
mbed_official 525:c320967f86b9 964 /* Check if we need to kick off TX transfer again to force more incoming data. */
mbed_official 525:c320967f86b9 965 if (!DMA_ChannelEnabled(obj->spi.dmaOptionsTX.dmaChannel) && (obj->tx_buff.pos < obj->rx_buff.length)) {
mbed_official 525:c320967f86b9 966 //Save state of TX transfer amount
mbed_official 525:c320967f86b9 967 int length_diff = obj->rx_buff.length - obj->tx_buff.pos;
mbed_official 525:c320967f86b9 968 obj->tx_buff.pos = obj->rx_buff.length;
mbed_official 525:c320967f86b9 969
mbed_official 525:c320967f86b9 970 //Kick off a new DMA transfer
mbed_official 525:c320967f86b9 971 DMA_CfgDescr_TypeDef txDescrCfg;
mbed_official 525:c320967f86b9 972
mbed_official 525:c320967f86b9 973 if(obj->spi.bits != 9) {
mbed_official 525:c320967f86b9 974 fill_word = SPI_FILL_WORD;
mbed_official 525:c320967f86b9 975 /* Setting up channel descriptor */
mbed_official 525:c320967f86b9 976 txDescrCfg.dstInc = dmaDataIncNone;
mbed_official 525:c320967f86b9 977 txDescrCfg.srcInc = dmaDataIncNone; //Do not increment source pointer when there is no transmit buffer
mbed_official 525:c320967f86b9 978 txDescrCfg.size = (obj->spi.bits <= 8 ? dmaDataSize1 : dmaDataSize2); //When frame size > 9, we can use TXDOUBLE to save bandwidth
mbed_official 525:c320967f86b9 979 txDescrCfg.arbRate = dmaArbitrate1;
mbed_official 525:c320967f86b9 980 txDescrCfg.hprot = 0;
mbed_official 525:c320967f86b9 981 DMA_CfgDescr(obj->spi.dmaOptionsTX.dmaChannel, true, &txDescrCfg);
mbed_official 525:c320967f86b9 982
mbed_official 525:c320967f86b9 983 /* Activate TX channel */
mbed_official 525:c320967f86b9 984 DMA_ActivateBasic( obj->spi.dmaOptionsTX.dmaChannel,
mbed_official 525:c320967f86b9 985 true,
mbed_official 525:c320967f86b9 986 false,
mbed_official 525:c320967f86b9 987 (obj->spi.bits <= 8 ? (void *)&(obj->spi.spi->TXDATA) : (void *)&(obj->spi.spi->TXDOUBLE)), //When frame size > 9, point to TXDOUBLE
mbed_official 525:c320967f86b9 988 &fill_word, // When there is nothing to transmit, point to static fill word
mbed_official 525:c320967f86b9 989 (obj->spi.bits <= 8 ? length_diff - 1 : (length_diff / 2) - 1)); // When using TXDOUBLE, recalculate transfer length
mbed_official 525:c320967f86b9 990 } else {
mbed_official 525:c320967f86b9 991 /* Setting up channel descriptor */
mbed_official 525:c320967f86b9 992 fill_word = SPI_FILL_WORD & 0x1FF;
mbed_official 525:c320967f86b9 993 txDescrCfg.dstInc = dmaDataIncNone;
mbed_official 525:c320967f86b9 994 txDescrCfg.srcInc = dmaDataIncNone; //Do not increment source pointer when there is no transmit buffer
mbed_official 525:c320967f86b9 995 txDescrCfg.size = dmaDataSize2; //When frame size > 9, we can use TXDOUBLE to save bandwidth
mbed_official 525:c320967f86b9 996 txDescrCfg.arbRate = dmaArbitrate1;
mbed_official 525:c320967f86b9 997 txDescrCfg.hprot = 0;
mbed_official 525:c320967f86b9 998 DMA_CfgDescr(obj->spi.dmaOptionsTX.dmaChannel, true, &txDescrCfg);
mbed_official 525:c320967f86b9 999
mbed_official 525:c320967f86b9 1000 DMA_ActivateBasic( obj->spi.dmaOptionsTX.dmaChannel,
mbed_official 525:c320967f86b9 1001 true,
mbed_official 525:c320967f86b9 1002 false,
mbed_official 525:c320967f86b9 1003 (void *)&(obj->spi.spi->TXDATAX), //When frame size > 9, point to TXDOUBLE
mbed_official 525:c320967f86b9 1004 &fill_word, // When there is nothing to transmit, point to static fill word
mbed_official 525:c320967f86b9 1005 (length_diff / 2) - 1);
mbed_official 525:c320967f86b9 1006 }
mbed_official 525:c320967f86b9 1007 }
mbed_official 525:c320967f86b9 1008 else return 0;
mbed_official 525:c320967f86b9 1009 }
mbed_official 525:c320967f86b9 1010
mbed_official 525:c320967f86b9 1011 /* If there is still a TX transfer ongoing (tx_length > rx_length), wait for it to finish */
mbed_official 525:c320967f86b9 1012 if (DMA_ChannelEnabled(obj->spi.dmaOptionsTX.dmaChannel)) {
mbed_official 525:c320967f86b9 1013 return 0;
mbed_official 525:c320967f86b9 1014 }
mbed_official 525:c320967f86b9 1015
mbed_official 525:c320967f86b9 1016 /* Release the dma channels if they were opportunistically allocated */
mbed_official 525:c320967f86b9 1017 if (obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) {
mbed_official 525:c320967f86b9 1018 dma_channel_free(obj->spi.dmaOptionsTX.dmaChannel);
mbed_official 525:c320967f86b9 1019 dma_channel_free(obj->spi.dmaOptionsRX.dmaChannel);
mbed_official 525:c320967f86b9 1020 obj->spi.dmaOptionsTX.dmaUsageState = DMA_USAGE_OPPORTUNISTIC;
mbed_official 525:c320967f86b9 1021 }
mbed_official 525:c320967f86b9 1022
mbed_official 525:c320967f86b9 1023 unblockSleepMode(SPI_LEAST_ACTIVE_SLEEPMODE);
mbed_official 525:c320967f86b9 1024
mbed_official 525:c320967f86b9 1025 /* return to CPP land to say we're finished */
mbed_official 525:c320967f86b9 1026 return SPI_EVENT_COMPLETE;
mbed_official 525:c320967f86b9 1027 } else {
mbed_official 525:c320967f86b9 1028 /* IRQ implementation */
mbed_official 525:c320967f86b9 1029 if (spi_master_rx_int_flag(obj)) {
mbed_official 525:c320967f86b9 1030 spi_master_read_asynch(obj);
mbed_official 525:c320967f86b9 1031 }
mbed_official 525:c320967f86b9 1032
mbed_official 525:c320967f86b9 1033 if (spi_master_tx_int_flag(obj)) {
mbed_official 525:c320967f86b9 1034 spi_master_write_asynch(obj);
mbed_official 525:c320967f86b9 1035 }
mbed_official 525:c320967f86b9 1036
mbed_official 525:c320967f86b9 1037 uint32_t event = spi_event_check(obj);
mbed_official 525:c320967f86b9 1038 if (event & SPI_EVENT_INTERNAL_TRANSFER_COMPLETE) {
mbed_official 525:c320967f86b9 1039 /* disable interrupts */
mbed_official 525:c320967f86b9 1040 spi_enable_interrupt(obj, (uint32_t)NULL, false);
mbed_official 525:c320967f86b9 1041
mbed_official 525:c320967f86b9 1042 unblockSleepMode(SPI_LEAST_ACTIVE_SLEEPMODE);
mbed_official 525:c320967f86b9 1043
mbed_official 525:c320967f86b9 1044 /* Return the event back to userland */
mbed_official 525:c320967f86b9 1045 return event;
mbed_official 525:c320967f86b9 1046 }
mbed_official 525:c320967f86b9 1047
mbed_official 525:c320967f86b9 1048 return 0;
mbed_official 525:c320967f86b9 1049 }
mbed_official 525:c320967f86b9 1050 }
mbed_official 525:c320967f86b9 1051
mbed_official 525:c320967f86b9 1052 /** Abort an SPI transfer
mbed_official 525:c320967f86b9 1053 *
mbed_official 525:c320967f86b9 1054 * @param obj The SPI peripheral to stop
mbed_official 525:c320967f86b9 1055 */
mbed_official 525:c320967f86b9 1056 void spi_abort_asynch(spi_t *obj) {
mbed_official 525:c320967f86b9 1057 // If we're not currently transferring, then there's nothing to do here
mbed_official 525:c320967f86b9 1058 if(spi_active(obj) != 0) return;
mbed_official 525:c320967f86b9 1059
mbed_official 525:c320967f86b9 1060 // Determine whether we're running DMA or interrupt
mbed_official 525:c320967f86b9 1061 if (obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_ALLOCATED || obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) {
mbed_official 525:c320967f86b9 1062 // Cancel the DMA transfers
mbed_official 525:c320967f86b9 1063 DMA_ChannelEnable(obj->spi.dmaOptionsTX.dmaChannel, false);
mbed_official 525:c320967f86b9 1064 DMA_ChannelEnable(obj->spi.dmaOptionsRX.dmaChannel, false);
mbed_official 525:c320967f86b9 1065
mbed_official 525:c320967f86b9 1066 /* Release the dma channels if they were opportunistically allocated */
mbed_official 525:c320967f86b9 1067 if (obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) {
mbed_official 525:c320967f86b9 1068 dma_channel_free(obj->spi.dmaOptionsTX.dmaChannel);
mbed_official 525:c320967f86b9 1069 dma_channel_free(obj->spi.dmaOptionsRX.dmaChannel);
mbed_official 525:c320967f86b9 1070 obj->spi.dmaOptionsTX.dmaUsageState = DMA_USAGE_OPPORTUNISTIC;
mbed_official 525:c320967f86b9 1071 }
mbed_official 525:c320967f86b9 1072
mbed_official 525:c320967f86b9 1073 } else {
mbed_official 525:c320967f86b9 1074 // Interrupt implementation: switch off interrupts
mbed_official 525:c320967f86b9 1075 spi_enable_interrupt(obj, (uint32_t)NULL, false);
mbed_official 525:c320967f86b9 1076 }
mbed_official 525:c320967f86b9 1077
mbed_official 525:c320967f86b9 1078 // Release sleep mode block
mbed_official 525:c320967f86b9 1079 unblockSleepMode(SPI_LEAST_ACTIVE_SLEEPMODE);
mbed_official 525:c320967f86b9 1080 }
mbed_official 525:c320967f86b9 1081
mbed_official 525:c320967f86b9 1082 #endif