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:
Fri Sep 25 14:15:10 2015 +0100
Revision:
627:4fa1328d9c60
Parent:
593:78ee8643776a
Synchronized with git revision fe238a91ab7a4d1d72c4cab9da04967c619d54ad

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

Silicon Labs - Add support for low-power async Serial

Who changed what in which revision?

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