FMF-ART / mbed-dev-lib

Fork of mbed-dev by mbed official

Committer:
mbed_official
Date:
Tue Nov 17 10:15:10 2015 +0000
Revision:
22:9c52de9bc1d7
Parent:
0:9b334a45a8ff
Child:
50:a417edff4437
Synchronized with git revision 8c540341dd44e9b99388db7b8389d756a7103dfd

Full URL: https://github.com/mbedmicro/mbed/commit/8c540341dd44e9b99388db7b8389d756a7103dfd/

Bugfixes to EFM32 serial, spi and sleep HAL

Who changed what in which revision?

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