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:
Mon Jul 20 09:00:09 2015 +0100
Revision:
593:78ee8643776a
Parent:
564:24a7119bd73a
Child:
627:4fa1328d9c60
Synchronized with git revision a68b724d07788e6389ea4d52c622aad767953758

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

[Silicon Labs] Bring EFM32 HAL up to date

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