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 13:00:10 2015 +0100
Revision:
526:7c4bdfe6a168
Parent:
525:c320967f86b9
Child:
548:1abac31e188e
Synchronized with git revision cdff09e6b6c486eb58fb5e968f3191c8480b0567

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

Silabs - Fix unblock/block declaration, implement gpio_is_connected

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