Manh Pham / Mbed OS Nucleo_rtos_basic_ir_controller
Committer:
manhpham
Date:
Sat Apr 07 09:22:54 2018 +0000
Revision:
0:c8673aa96267
Nucleo_rtos_basic_ir_controller

Who changed what in which revision?

UserRevisionLine numberNew contents of line
manhpham 0:c8673aa96267 1 /***************************************************************************//**
manhpham 0:c8673aa96267 2 * @file spi_api.c
manhpham 0:c8673aa96267 3 *******************************************************************************
manhpham 0:c8673aa96267 4 * @section License
manhpham 0:c8673aa96267 5 * <b>(C) Copyright 2015 Silicon Labs, http://www.silabs.com</b>
manhpham 0:c8673aa96267 6 *******************************************************************************
manhpham 0:c8673aa96267 7 *
manhpham 0:c8673aa96267 8 * SPDX-License-Identifier: Apache-2.0
manhpham 0:c8673aa96267 9 *
manhpham 0:c8673aa96267 10 * Licensed under the Apache License, Version 2.0 (the "License"); you may
manhpham 0:c8673aa96267 11 * not use this file except in compliance with the License.
manhpham 0:c8673aa96267 12 * You may obtain a copy of the License at
manhpham 0:c8673aa96267 13 *
manhpham 0:c8673aa96267 14 * http://www.apache.org/licenses/LICENSE-2.0
manhpham 0:c8673aa96267 15 *
manhpham 0:c8673aa96267 16 * Unless required by applicable law or agreed to in writing, software
manhpham 0:c8673aa96267 17 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
manhpham 0:c8673aa96267 18 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
manhpham 0:c8673aa96267 19 * See the License for the specific language governing permissions and
manhpham 0:c8673aa96267 20 * limitations under the License.
manhpham 0:c8673aa96267 21 *
manhpham 0:c8673aa96267 22 ******************************************************************************/
manhpham 0:c8673aa96267 23
manhpham 0:c8673aa96267 24 #include "device.h"
manhpham 0:c8673aa96267 25 #include "clocking.h"
manhpham 0:c8673aa96267 26 #if DEVICE_SPI
manhpham 0:c8673aa96267 27
manhpham 0:c8673aa96267 28 #include "mbed_assert.h"
manhpham 0:c8673aa96267 29 #include "mbed_power_mgmt.h"
manhpham 0:c8673aa96267 30 #include "PeripheralPins.h"
manhpham 0:c8673aa96267 31 #include "pinmap.h"
manhpham 0:c8673aa96267 32 #include "pinmap_function.h"
manhpham 0:c8673aa96267 33 #include "mbed_error.h"
manhpham 0:c8673aa96267 34
manhpham 0:c8673aa96267 35 #include "dma_api.h"
manhpham 0:c8673aa96267 36 #include "dma_api_HAL.h"
manhpham 0:c8673aa96267 37 #include "serial_api_HAL.h"
manhpham 0:c8673aa96267 38 #include "spi_api.h"
manhpham 0:c8673aa96267 39 #include "em_usart.h"
manhpham 0:c8673aa96267 40 #include "em_cmu.h"
manhpham 0:c8673aa96267 41 #include "em_dma.h"
manhpham 0:c8673aa96267 42 #include "sleep_api.h"
manhpham 0:c8673aa96267 43
manhpham 0:c8673aa96267 44 static uint16_t fill_word = SPI_FILL_WORD;
manhpham 0:c8673aa96267 45
manhpham 0:c8673aa96267 46 static inline CMU_Clock_TypeDef spi_get_clock_tree(spi_t *obj)
manhpham 0:c8673aa96267 47 {
manhpham 0:c8673aa96267 48 switch ((int)obj->spi.spi) {
manhpham 0:c8673aa96267 49 #ifdef USART0
manhpham 0:c8673aa96267 50 case SPI_0:
manhpham 0:c8673aa96267 51 return cmuClock_USART0;
manhpham 0:c8673aa96267 52 #endif
manhpham 0:c8673aa96267 53 #ifdef USART1
manhpham 0:c8673aa96267 54 case SPI_1:
manhpham 0:c8673aa96267 55 return cmuClock_USART1;
manhpham 0:c8673aa96267 56 #endif
manhpham 0:c8673aa96267 57 #ifdef USART2
manhpham 0:c8673aa96267 58 case SPI_2:
manhpham 0:c8673aa96267 59 return cmuClock_USART2;
manhpham 0:c8673aa96267 60 #endif
manhpham 0:c8673aa96267 61 #ifdef USART3
manhpham 0:c8673aa96267 62 case SPI_3:
manhpham 0:c8673aa96267 63 return cmuClock_USART3;
manhpham 0:c8673aa96267 64 #endif
manhpham 0:c8673aa96267 65 #ifdef USART4
manhpham 0:c8673aa96267 66 case SPI_4:
manhpham 0:c8673aa96267 67 return cmuClock_USART4;
manhpham 0:c8673aa96267 68 #endif
manhpham 0:c8673aa96267 69 #ifdef USART5
manhpham 0:c8673aa96267 70 case SPI_5:
manhpham 0:c8673aa96267 71 return cmuClock_USART5;
manhpham 0:c8673aa96267 72 #endif
manhpham 0:c8673aa96267 73 default:
manhpham 0:c8673aa96267 74 error("Spi module not available.. Out of bound access.");
manhpham 0:c8673aa96267 75 return cmuClock_HFPER;
manhpham 0:c8673aa96267 76 }
manhpham 0:c8673aa96267 77 }
manhpham 0:c8673aa96267 78
manhpham 0:c8673aa96267 79 static inline uint8_t spi_get_index(spi_t *obj)
manhpham 0:c8673aa96267 80 {
manhpham 0:c8673aa96267 81 uint8_t index = 0;
manhpham 0:c8673aa96267 82 switch ((int)obj->spi.spi) {
manhpham 0:c8673aa96267 83 #ifdef USART0
manhpham 0:c8673aa96267 84 case SPI_0:
manhpham 0:c8673aa96267 85 index = 0;
manhpham 0:c8673aa96267 86 break;
manhpham 0:c8673aa96267 87 #endif
manhpham 0:c8673aa96267 88 #ifdef USART1
manhpham 0:c8673aa96267 89 case SPI_1:
manhpham 0:c8673aa96267 90 index = 1;
manhpham 0:c8673aa96267 91 break;
manhpham 0:c8673aa96267 92 #endif
manhpham 0:c8673aa96267 93 #ifdef USART2
manhpham 0:c8673aa96267 94 case SPI_2:
manhpham 0:c8673aa96267 95 index = 2;
manhpham 0:c8673aa96267 96 break;
manhpham 0:c8673aa96267 97 #endif
manhpham 0:c8673aa96267 98 #ifdef USART3
manhpham 0:c8673aa96267 99 case SPI_3:
manhpham 0:c8673aa96267 100 index = 3;
manhpham 0:c8673aa96267 101 break;
manhpham 0:c8673aa96267 102 #endif
manhpham 0:c8673aa96267 103 #ifdef USART4
manhpham 0:c8673aa96267 104 case SPI_4:
manhpham 0:c8673aa96267 105 index = 4;
manhpham 0:c8673aa96267 106 break;
manhpham 0:c8673aa96267 107 #endif
manhpham 0:c8673aa96267 108 #ifdef USART5
manhpham 0:c8673aa96267 109 case SPI_5:
manhpham 0:c8673aa96267 110 index = 5;
manhpham 0:c8673aa96267 111 break;
manhpham 0:c8673aa96267 112 #endif
manhpham 0:c8673aa96267 113 default:
manhpham 0:c8673aa96267 114 error("Spi module not available.. Out of bound access.");
manhpham 0:c8673aa96267 115 break;
manhpham 0:c8673aa96267 116 }
manhpham 0:c8673aa96267 117 return index;
manhpham 0:c8673aa96267 118 }
manhpham 0:c8673aa96267 119
manhpham 0:c8673aa96267 120 uint8_t spi_get_module(spi_t *obj)
manhpham 0:c8673aa96267 121 {
manhpham 0:c8673aa96267 122 return spi_get_index(obj);
manhpham 0:c8673aa96267 123 }
manhpham 0:c8673aa96267 124
manhpham 0:c8673aa96267 125 static void usart_init(spi_t *obj, uint32_t baudrate, USART_Databits_TypeDef databits, bool master, USART_ClockMode_TypeDef clockMode )
manhpham 0:c8673aa96267 126 {
manhpham 0:c8673aa96267 127 USART_InitSync_TypeDef init = USART_INITSYNC_DEFAULT;
manhpham 0:c8673aa96267 128 init.enable = usartDisable;
manhpham 0:c8673aa96267 129 init.baudrate = baudrate;
manhpham 0:c8673aa96267 130 init.databits = databits;
manhpham 0:c8673aa96267 131 init.master = master;
manhpham 0:c8673aa96267 132 init.msbf = 1;
manhpham 0:c8673aa96267 133 init.clockMode = clockMode;
manhpham 0:c8673aa96267 134
manhpham 0:c8673aa96267 135 /* Determine the reference clock, because the correct clock may not be set up at init time (e.g. before main()) */
manhpham 0:c8673aa96267 136 init.refFreq = REFERENCE_FREQUENCY;
manhpham 0:c8673aa96267 137
manhpham 0:c8673aa96267 138 USART_InitSync(obj->spi.spi, &init);
manhpham 0:c8673aa96267 139 }
manhpham 0:c8673aa96267 140
manhpham 0:c8673aa96267 141 void spi_preinit(spi_t *obj, PinName mosi, PinName miso, PinName clk, PinName cs)
manhpham 0:c8673aa96267 142 {
manhpham 0:c8673aa96267 143 SPIName spi_mosi = (SPIName) pinmap_peripheral(mosi, PinMap_SPI_MOSI);
manhpham 0:c8673aa96267 144 SPIName spi_miso = (SPIName) pinmap_peripheral(miso, PinMap_SPI_MISO);
manhpham 0:c8673aa96267 145 SPIName spi_clk = (SPIName) pinmap_peripheral(clk, PinMap_SPI_CLK);
manhpham 0:c8673aa96267 146 SPIName spi_cs = (SPIName) pinmap_peripheral(cs, PinMap_SPI_CS);
manhpham 0:c8673aa96267 147 SPIName spi_data = (SPIName) pinmap_merge(spi_mosi, spi_miso);
manhpham 0:c8673aa96267 148 SPIName spi_ctrl = (SPIName) pinmap_merge(spi_clk, spi_cs);
manhpham 0:c8673aa96267 149
manhpham 0:c8673aa96267 150 obj->spi.spi = (USART_TypeDef *) pinmap_merge(spi_data, spi_ctrl);
manhpham 0:c8673aa96267 151 MBED_ASSERT((unsigned int) obj->spi.spi != NC);
manhpham 0:c8673aa96267 152
manhpham 0:c8673aa96267 153 if (cs != NC) { /* Slave mode */
manhpham 0:c8673aa96267 154 obj->spi.master = false;
manhpham 0:c8673aa96267 155 } else {
manhpham 0:c8673aa96267 156 obj->spi.master = true;
manhpham 0:c8673aa96267 157 }
manhpham 0:c8673aa96267 158
manhpham 0:c8673aa96267 159 #if defined(_SILICON_LABS_32B_PLATFORM_1)
manhpham 0:c8673aa96267 160 // On P1, we need to ensure all pins are on same location
manhpham 0:c8673aa96267 161 uint32_t loc_mosi = pin_location(mosi, PinMap_SPI_MOSI);
manhpham 0:c8673aa96267 162 uint32_t loc_miso = pin_location(miso, PinMap_SPI_MISO);
manhpham 0:c8673aa96267 163 uint32_t loc_clk = pin_location(clk, PinMap_SPI_CLK);
manhpham 0:c8673aa96267 164 uint32_t loc_cs = pin_location(cs, PinMap_SPI_CS);
manhpham 0:c8673aa96267 165 uint32_t loc_data = pinmap_merge(loc_mosi, loc_miso);
manhpham 0:c8673aa96267 166 uint32_t loc_ctrl = pinmap_merge(loc_clk, loc_cs);
manhpham 0:c8673aa96267 167 obj->spi.location = pinmap_merge(loc_data, loc_ctrl);
manhpham 0:c8673aa96267 168 MBED_ASSERT(obj->spi.location != NC);
manhpham 0:c8673aa96267 169 #endif
manhpham 0:c8673aa96267 170
manhpham 0:c8673aa96267 171 obj->spi.dmaOptionsTX.dmaUsageState = DMA_USAGE_OPPORTUNISTIC;
manhpham 0:c8673aa96267 172 }
manhpham 0:c8673aa96267 173
manhpham 0:c8673aa96267 174 void spi_enable_pins(spi_t *obj, uint8_t enable, PinName mosi, PinName miso, PinName clk, PinName cs)
manhpham 0:c8673aa96267 175 {
manhpham 0:c8673aa96267 176 if (enable) {
manhpham 0:c8673aa96267 177 if (obj->spi.master) { /* Master mode */
manhpham 0:c8673aa96267 178 /* Either mosi or miso can be NC */
manhpham 0:c8673aa96267 179 if (mosi != NC) {
manhpham 0:c8673aa96267 180 pin_mode(mosi, PushPull);
manhpham 0:c8673aa96267 181 }
manhpham 0:c8673aa96267 182 if (miso != NC) {
manhpham 0:c8673aa96267 183 pin_mode(miso, Input);
manhpham 0:c8673aa96267 184 }
manhpham 0:c8673aa96267 185 pin_mode(clk, PushPull);
manhpham 0:c8673aa96267 186 /* Don't set cs pin, since we toggle it manually */
manhpham 0:c8673aa96267 187 } else { /* Slave mode */
manhpham 0:c8673aa96267 188 if (mosi != NC) {
manhpham 0:c8673aa96267 189 pin_mode(mosi, Input);
manhpham 0:c8673aa96267 190 }
manhpham 0:c8673aa96267 191 if (miso != NC) {
manhpham 0:c8673aa96267 192 pin_mode(miso, PushPull);
manhpham 0:c8673aa96267 193 }
manhpham 0:c8673aa96267 194 pin_mode(clk, Input);
manhpham 0:c8673aa96267 195 pin_mode(cs, Input);
manhpham 0:c8673aa96267 196 }
manhpham 0:c8673aa96267 197 } else {
manhpham 0:c8673aa96267 198 // TODO_LP return PinMode to the previous state
manhpham 0:c8673aa96267 199 if (obj->spi.master) { /* Master mode */
manhpham 0:c8673aa96267 200 /* Either mosi or miso can be NC */
manhpham 0:c8673aa96267 201 if (mosi != NC) {
manhpham 0:c8673aa96267 202 pin_mode(mosi, Disabled);
manhpham 0:c8673aa96267 203 }
manhpham 0:c8673aa96267 204 if (miso != NC) {
manhpham 0:c8673aa96267 205 pin_mode(miso, Disabled);
manhpham 0:c8673aa96267 206 }
manhpham 0:c8673aa96267 207 pin_mode(clk, Disabled);
manhpham 0:c8673aa96267 208 /* Don't set cs pin, since we toggle it manually */
manhpham 0:c8673aa96267 209 } else { /* Slave mode */
manhpham 0:c8673aa96267 210 if (mosi != NC) {
manhpham 0:c8673aa96267 211 pin_mode(mosi, Disabled);
manhpham 0:c8673aa96267 212 }
manhpham 0:c8673aa96267 213 if (miso != NC) {
manhpham 0:c8673aa96267 214 pin_mode(miso, Disabled);
manhpham 0:c8673aa96267 215 }
manhpham 0:c8673aa96267 216 pin_mode(clk, Disabled);
manhpham 0:c8673aa96267 217 pin_mode(cs, Disabled);
manhpham 0:c8673aa96267 218 }
manhpham 0:c8673aa96267 219 }
manhpham 0:c8673aa96267 220
manhpham 0:c8673aa96267 221 /* Enabling pins and setting location */
manhpham 0:c8673aa96267 222 #ifdef _USART_ROUTEPEN_RESETVALUE
manhpham 0:c8673aa96267 223 uint32_t route = USART_ROUTEPEN_CLKPEN;
manhpham 0:c8673aa96267 224
manhpham 0:c8673aa96267 225 obj->spi.spi->ROUTELOC0 &= ~_USART_ROUTELOC0_CLKLOC_MASK;
manhpham 0:c8673aa96267 226 obj->spi.spi->ROUTELOC0 |= pin_location(clk, PinMap_SPI_CLK)<<_USART_ROUTELOC0_CLKLOC_SHIFT;
manhpham 0:c8673aa96267 227 if (mosi != NC) {
manhpham 0:c8673aa96267 228 route |= USART_ROUTEPEN_TXPEN;
manhpham 0:c8673aa96267 229 obj->spi.spi->ROUTELOC0 &= ~_USART_ROUTELOC0_TXLOC_MASK;
manhpham 0:c8673aa96267 230 obj->spi.spi->ROUTELOC0 |= pin_location(mosi, PinMap_SPI_MOSI)<<_USART_ROUTELOC0_TXLOC_SHIFT;
manhpham 0:c8673aa96267 231 }
manhpham 0:c8673aa96267 232 if (miso != NC) {
manhpham 0:c8673aa96267 233 route |= USART_ROUTEPEN_RXPEN;
manhpham 0:c8673aa96267 234 obj->spi.spi->ROUTELOC0 &= ~_USART_ROUTELOC0_RXLOC_MASK;
manhpham 0:c8673aa96267 235 obj->spi.spi->ROUTELOC0 |= pin_location(miso, PinMap_SPI_MISO)<<_USART_ROUTELOC0_RXLOC_SHIFT;
manhpham 0:c8673aa96267 236 }
manhpham 0:c8673aa96267 237 if (!obj->spi.master) {
manhpham 0:c8673aa96267 238 route |= USART_ROUTEPEN_CSPEN;
manhpham 0:c8673aa96267 239 obj->spi.spi->ROUTELOC0 &= ~_USART_ROUTELOC0_CSLOC_MASK;
manhpham 0:c8673aa96267 240 obj->spi.spi->ROUTELOC0 |= pin_location(cs, PinMap_SPI_CS)<<_USART_ROUTELOC0_CSLOC_SHIFT;
manhpham 0:c8673aa96267 241 }
manhpham 0:c8673aa96267 242 obj->spi.location = obj->spi.spi->ROUTELOC0;
manhpham 0:c8673aa96267 243 obj->spi.route = route;
manhpham 0:c8673aa96267 244 obj->spi.spi->ROUTEPEN = route;
manhpham 0:c8673aa96267 245 }
manhpham 0:c8673aa96267 246 #else
manhpham 0:c8673aa96267 247 uint32_t route = USART_ROUTE_CLKPEN;
manhpham 0:c8673aa96267 248
manhpham 0:c8673aa96267 249 if (mosi != NC) {
manhpham 0:c8673aa96267 250 route |= USART_ROUTE_TXPEN;
manhpham 0:c8673aa96267 251 }
manhpham 0:c8673aa96267 252 if (miso != NC) {
manhpham 0:c8673aa96267 253 route |= USART_ROUTE_RXPEN;
manhpham 0:c8673aa96267 254 }
manhpham 0:c8673aa96267 255 if (!obj->spi.master) {
manhpham 0:c8673aa96267 256 route |= USART_ROUTE_CSPEN;
manhpham 0:c8673aa96267 257 }
manhpham 0:c8673aa96267 258 route |= obj->spi.location << _USART_ROUTE_LOCATION_SHIFT;
manhpham 0:c8673aa96267 259 obj->spi.spi->ROUTE = route;
manhpham 0:c8673aa96267 260 obj->spi.route = route;
manhpham 0:c8673aa96267 261 }
manhpham 0:c8673aa96267 262 #endif
manhpham 0:c8673aa96267 263 void spi_enable(spi_t *obj, uint8_t enable)
manhpham 0:c8673aa96267 264 {
manhpham 0:c8673aa96267 265 USART_Enable(obj->spi.spi, (enable ? usartEnable : usartDisable));
manhpham 0:c8673aa96267 266 }
manhpham 0:c8673aa96267 267
manhpham 0:c8673aa96267 268 void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName clk, PinName cs)
manhpham 0:c8673aa96267 269 {
manhpham 0:c8673aa96267 270 CMU_ClockEnable(cmuClock_HFPER, true);
manhpham 0:c8673aa96267 271 spi_preinit(obj, mosi, miso, clk, cs);
manhpham 0:c8673aa96267 272 CMU_ClockEnable(spi_get_clock_tree(obj), true);
manhpham 0:c8673aa96267 273 usart_init(obj, 100000, usartDatabits8, true, usartClockMode0);
manhpham 0:c8673aa96267 274
manhpham 0:c8673aa96267 275 spi_enable_pins(obj, true, mosi, miso, clk, cs);
manhpham 0:c8673aa96267 276 spi_enable(obj, true);
manhpham 0:c8673aa96267 277 }
manhpham 0:c8673aa96267 278
manhpham 0:c8673aa96267 279 void spi_enable_event(spi_t *obj, uint32_t event, uint8_t enable)
manhpham 0:c8673aa96267 280 {
manhpham 0:c8673aa96267 281 if(enable) obj->spi.event |= event;
manhpham 0:c8673aa96267 282 else obj->spi.event &= ~event;
manhpham 0:c8673aa96267 283 }
manhpham 0:c8673aa96267 284
manhpham 0:c8673aa96267 285 /****************************************************************************
manhpham 0:c8673aa96267 286 * void spi_enable_interrupt(spi_t *obj, uint32_t handler, uint8_t enable)
manhpham 0:c8673aa96267 287 *
manhpham 0:c8673aa96267 288 * This will enable the interrupt in NVIC for the associated USART RX channel
manhpham 0:c8673aa96267 289 *
manhpham 0:c8673aa96267 290 * * obj: pointer to spi object
manhpham 0:c8673aa96267 291 * * handler: pointer to interrupt handler for this channel
manhpham 0:c8673aa96267 292 * * enable: Whether to enable (true) or disable (false) the interrupt
manhpham 0:c8673aa96267 293 *
manhpham 0:c8673aa96267 294 ****************************************************************************/
manhpham 0:c8673aa96267 295 void spi_enable_interrupt(spi_t *obj, uint32_t handler, uint8_t enable)
manhpham 0:c8673aa96267 296 {
manhpham 0:c8673aa96267 297 IRQn_Type IRQvector;
manhpham 0:c8673aa96267 298
manhpham 0:c8673aa96267 299 switch ((uint32_t)obj->spi.spi) {
manhpham 0:c8673aa96267 300 #ifdef USART0
manhpham 0:c8673aa96267 301 case USART_0:
manhpham 0:c8673aa96267 302 IRQvector = USART0_RX_IRQn;
manhpham 0:c8673aa96267 303 break;
manhpham 0:c8673aa96267 304 #endif
manhpham 0:c8673aa96267 305 #ifdef USART1
manhpham 0:c8673aa96267 306 case USART_1:
manhpham 0:c8673aa96267 307 IRQvector = USART1_RX_IRQn;
manhpham 0:c8673aa96267 308 break;
manhpham 0:c8673aa96267 309 #endif
manhpham 0:c8673aa96267 310 #ifdef USART2
manhpham 0:c8673aa96267 311 case USART_2:
manhpham 0:c8673aa96267 312 IRQvector = USART2_RX_IRQn;
manhpham 0:c8673aa96267 313 break;
manhpham 0:c8673aa96267 314 #endif
manhpham 0:c8673aa96267 315 #ifdef USART3
manhpham 0:c8673aa96267 316 case USART_3:
manhpham 0:c8673aa96267 317 IRQvector = USART3_RX_IRQn;
manhpham 0:c8673aa96267 318 break;
manhpham 0:c8673aa96267 319 #endif
manhpham 0:c8673aa96267 320 #ifdef USART4
manhpham 0:c8673aa96267 321 case USART_4:
manhpham 0:c8673aa96267 322 IRQvector = USART4_RX_IRQn;
manhpham 0:c8673aa96267 323 break;
manhpham 0:c8673aa96267 324 #endif
manhpham 0:c8673aa96267 325 #ifdef USART5
manhpham 0:c8673aa96267 326 case USART_5:
manhpham 0:c8673aa96267 327 IRQvector = USART5_RX_IRQn;
manhpham 0:c8673aa96267 328 break;
manhpham 0:c8673aa96267 329 #endif
manhpham 0:c8673aa96267 330 default:
manhpham 0:c8673aa96267 331 error("Undefined SPI peripheral");
manhpham 0:c8673aa96267 332 return;
manhpham 0:c8673aa96267 333 }
manhpham 0:c8673aa96267 334
manhpham 0:c8673aa96267 335 if (enable == true) {
manhpham 0:c8673aa96267 336 NVIC_SetVector(IRQvector, handler);
manhpham 0:c8673aa96267 337 USART_IntEnable(obj->spi.spi, USART_IEN_RXDATAV);
manhpham 0:c8673aa96267 338 NVIC_EnableIRQ(IRQvector);
manhpham 0:c8673aa96267 339 } else {
manhpham 0:c8673aa96267 340 NVIC_SetVector(IRQvector, handler);
manhpham 0:c8673aa96267 341 USART_IntDisable(obj->spi.spi, USART_IEN_RXDATAV);
manhpham 0:c8673aa96267 342 NVIC_DisableIRQ(IRQvector);
manhpham 0:c8673aa96267 343 }
manhpham 0:c8673aa96267 344 }
manhpham 0:c8673aa96267 345
manhpham 0:c8673aa96267 346 void spi_format(spi_t *obj, int bits, int mode, int slave)
manhpham 0:c8673aa96267 347 {
manhpham 0:c8673aa96267 348 /* Bits: values between 4 and 16 are valid */
manhpham 0:c8673aa96267 349 MBED_ASSERT(bits >= 4 && bits <= 16);
manhpham 0:c8673aa96267 350 obj->spi.bits = bits;
manhpham 0:c8673aa96267 351 /* 0x01 = usartDatabits4, etc, up to 0x0D = usartDatabits16 */
manhpham 0:c8673aa96267 352 USART_Databits_TypeDef databits = (USART_Databits_TypeDef) (bits - 3);
manhpham 0:c8673aa96267 353
manhpham 0:c8673aa96267 354 USART_ClockMode_TypeDef clockMode;
manhpham 0:c8673aa96267 355 MBED_ASSERT(mode >= 0 && mode <= 3);
manhpham 0:c8673aa96267 356 switch (mode) {
manhpham 0:c8673aa96267 357 case 0:
manhpham 0:c8673aa96267 358 clockMode = usartClockMode0;
manhpham 0:c8673aa96267 359 break;
manhpham 0:c8673aa96267 360 case 1:
manhpham 0:c8673aa96267 361 clockMode = usartClockMode1;
manhpham 0:c8673aa96267 362 break;
manhpham 0:c8673aa96267 363 case 2:
manhpham 0:c8673aa96267 364 clockMode = usartClockMode2;
manhpham 0:c8673aa96267 365 break;
manhpham 0:c8673aa96267 366 case 3:
manhpham 0:c8673aa96267 367 clockMode = usartClockMode3;
manhpham 0:c8673aa96267 368 break;
manhpham 0:c8673aa96267 369 default:
manhpham 0:c8673aa96267 370 clockMode = usartClockMode0;
manhpham 0:c8673aa96267 371 }
manhpham 0:c8673aa96267 372 uint32_t iflags = obj->spi.spi->IEN;
manhpham 0:c8673aa96267 373 bool enabled = (obj->spi.spi->STATUS & (USART_STATUS_RXENS | USART_STATUS_TXENS)) != 0;
manhpham 0:c8673aa96267 374
manhpham 0:c8673aa96267 375 usart_init(obj, 100000, databits, (slave ? false : true), clockMode);
manhpham 0:c8673aa96267 376
manhpham 0:c8673aa96267 377 //restore state
manhpham 0:c8673aa96267 378 #ifdef _USART_ROUTEPEN_RESETVALUE
manhpham 0:c8673aa96267 379 obj->spi.spi->ROUTEPEN = obj->spi.route;
manhpham 0:c8673aa96267 380 obj->spi.spi->ROUTELOC0 = obj->spi.location;
manhpham 0:c8673aa96267 381 #else
manhpham 0:c8673aa96267 382 obj->spi.spi->ROUTE = obj->spi.route;
manhpham 0:c8673aa96267 383 #endif
manhpham 0:c8673aa96267 384 obj->spi.spi->IEN = iflags;
manhpham 0:c8673aa96267 385
manhpham 0:c8673aa96267 386 if(enabled) spi_enable(obj, enabled);
manhpham 0:c8673aa96267 387 }
manhpham 0:c8673aa96267 388
manhpham 0:c8673aa96267 389 void spi_frequency(spi_t *obj, int hz)
manhpham 0:c8673aa96267 390 {
manhpham 0:c8673aa96267 391 USART_BaudrateSyncSet(obj->spi.spi, REFERENCE_FREQUENCY, hz);
manhpham 0:c8673aa96267 392 }
manhpham 0:c8673aa96267 393
manhpham 0:c8673aa96267 394 /* Read/Write */
manhpham 0:c8673aa96267 395
manhpham 0:c8673aa96267 396 void spi_write(spi_t *obj, int value)
manhpham 0:c8673aa96267 397 {
manhpham 0:c8673aa96267 398 if (obj->spi.bits <= 8) {
manhpham 0:c8673aa96267 399 USART_Tx(obj->spi.spi, (uint8_t) value);
manhpham 0:c8673aa96267 400 } else if (obj->spi.bits == 9) {
manhpham 0:c8673aa96267 401 USART_TxExt(obj->spi.spi, (uint16_t) value & 0x1FF);
manhpham 0:c8673aa96267 402 } else {
manhpham 0:c8673aa96267 403 USART_TxDouble(obj->spi.spi, (uint16_t) value);
manhpham 0:c8673aa96267 404 }
manhpham 0:c8673aa96267 405 }
manhpham 0:c8673aa96267 406
manhpham 0:c8673aa96267 407 int spi_read(spi_t *obj)
manhpham 0:c8673aa96267 408 {
manhpham 0:c8673aa96267 409 if (obj->spi.bits <= 8) {
manhpham 0:c8673aa96267 410 return (int) obj->spi.spi->RXDATA;
manhpham 0:c8673aa96267 411 } else if (obj->spi.bits == 9) {
manhpham 0:c8673aa96267 412 return (int) obj->spi.spi->RXDATAX & 0x1FF;
manhpham 0:c8673aa96267 413 } else {
manhpham 0:c8673aa96267 414 return (int) obj->spi.spi->RXDOUBLE;
manhpham 0:c8673aa96267 415 }
manhpham 0:c8673aa96267 416 }
manhpham 0:c8673aa96267 417
manhpham 0:c8673aa96267 418 int spi_read_asynch(spi_t *obj)
manhpham 0:c8673aa96267 419 {
manhpham 0:c8673aa96267 420 return spi_read(obj);
manhpham 0:c8673aa96267 421 }
manhpham 0:c8673aa96267 422
manhpham 0:c8673aa96267 423 int spi_master_write(spi_t *obj, int value)
manhpham 0:c8673aa96267 424 {
manhpham 0:c8673aa96267 425 spi_write(obj, value);
manhpham 0:c8673aa96267 426
manhpham 0:c8673aa96267 427 /* Wait for transmission of last byte */
manhpham 0:c8673aa96267 428 while (!(obj->spi.spi->STATUS & USART_STATUS_TXC)) {
manhpham 0:c8673aa96267 429 }
manhpham 0:c8673aa96267 430
manhpham 0:c8673aa96267 431 return spi_read(obj);
manhpham 0:c8673aa96267 432 }
manhpham 0:c8673aa96267 433
manhpham 0:c8673aa96267 434 int spi_master_block_write(spi_t *obj, const char *tx_buffer, int tx_length,
manhpham 0:c8673aa96267 435 char *rx_buffer, int rx_length, char write_fill) {
manhpham 0:c8673aa96267 436 int total = (tx_length > rx_length) ? tx_length : rx_length;
manhpham 0:c8673aa96267 437
manhpham 0:c8673aa96267 438 for (int i = 0; i < total; i++) {
manhpham 0:c8673aa96267 439 char out = (i < tx_length) ? tx_buffer[i] : write_fill;
manhpham 0:c8673aa96267 440 char in = spi_master_write(obj, out);
manhpham 0:c8673aa96267 441 if (i < rx_length) {
manhpham 0:c8673aa96267 442 rx_buffer[i] = in;
manhpham 0:c8673aa96267 443 }
manhpham 0:c8673aa96267 444 }
manhpham 0:c8673aa96267 445
manhpham 0:c8673aa96267 446 return total;
manhpham 0:c8673aa96267 447 }
manhpham 0:c8673aa96267 448
manhpham 0:c8673aa96267 449 inline uint8_t spi_master_tx_ready(spi_t *obj)
manhpham 0:c8673aa96267 450 {
manhpham 0:c8673aa96267 451 return (obj->spi.spi->STATUS & USART_STATUS_TXBL) ? true : false;
manhpham 0:c8673aa96267 452 }
manhpham 0:c8673aa96267 453
manhpham 0:c8673aa96267 454 uint8_t spi_master_rx_ready(spi_t *obj)
manhpham 0:c8673aa96267 455 {
manhpham 0:c8673aa96267 456 return (obj->spi.spi->STATUS & USART_STATUS_RXDATAV) ? true : false;
manhpham 0:c8673aa96267 457 }
manhpham 0:c8673aa96267 458
manhpham 0:c8673aa96267 459 uint8_t spi_master_tx_int_flag(spi_t *obj)
manhpham 0:c8673aa96267 460 {
manhpham 0:c8673aa96267 461 return (obj->spi.spi->IF & USART_IF_TXBL) ? true : false;
manhpham 0:c8673aa96267 462 }
manhpham 0:c8673aa96267 463
manhpham 0:c8673aa96267 464 uint8_t spi_master_rx_int_flag(spi_t *obj)
manhpham 0:c8673aa96267 465 {
manhpham 0:c8673aa96267 466 return (obj->spi.spi->IF & (USART_IF_RXDATAV | USART_IF_RXFULL)) ? true : false;
manhpham 0:c8673aa96267 467 }
manhpham 0:c8673aa96267 468
manhpham 0:c8673aa96267 469 void spi_master_read_asynch_complete(spi_t *obj)
manhpham 0:c8673aa96267 470 {
manhpham 0:c8673aa96267 471 obj->spi.spi->IFC = USART_IFC_RXFULL; // in case it got full
manhpham 0:c8673aa96267 472 }
manhpham 0:c8673aa96267 473
manhpham 0:c8673aa96267 474 void spi_master_write_asynch_complete(spi_t *obj)
manhpham 0:c8673aa96267 475 {
manhpham 0:c8673aa96267 476 obj->spi.spi->IFC = USART_IFC_TXC;
manhpham 0:c8673aa96267 477 }
manhpham 0:c8673aa96267 478
manhpham 0:c8673aa96267 479 void spi_irq_handler(spi_t *obj)
manhpham 0:c8673aa96267 480 {
manhpham 0:c8673aa96267 481 spi_read(obj); //TODO_LP store data to the object?
manhpham 0:c8673aa96267 482 }
manhpham 0:c8673aa96267 483
manhpham 0:c8673aa96267 484 uint8_t spi_active(spi_t *obj)
manhpham 0:c8673aa96267 485 {
manhpham 0:c8673aa96267 486 switch(obj->spi.dmaOptionsTX.dmaUsageState) {
manhpham 0:c8673aa96267 487 case DMA_USAGE_TEMPORARY_ALLOCATED:
manhpham 0:c8673aa96267 488 return true;
manhpham 0:c8673aa96267 489 case DMA_USAGE_ALLOCATED:
manhpham 0:c8673aa96267 490 /* Check whether the allocated DMA channel is active */
manhpham 0:c8673aa96267 491 #ifdef LDMA_PRESENT
manhpham 0:c8673aa96267 492 return(LDMAx_ChannelEnabled(obj->spi.dmaOptionsTX.dmaChannel) || LDMAx_ChannelEnabled(obj->spi.dmaOptionsRX.dmaChannel));
manhpham 0:c8673aa96267 493 #else
manhpham 0:c8673aa96267 494 return(DMA_ChannelEnabled(obj->spi.dmaOptionsTX.dmaChannel) || DMA_ChannelEnabled(obj->spi.dmaOptionsRX.dmaChannel));
manhpham 0:c8673aa96267 495 #endif
manhpham 0:c8673aa96267 496 default:
manhpham 0:c8673aa96267 497 /* Check whether interrupt for spi is enabled */
manhpham 0:c8673aa96267 498 return (obj->spi.spi->IEN & (USART_IEN_RXDATAV | USART_IEN_TXBL)) ? true : false;
manhpham 0:c8673aa96267 499 }
manhpham 0:c8673aa96267 500 }
manhpham 0:c8673aa96267 501
manhpham 0:c8673aa96267 502 void spi_buffer_set(spi_t *obj, const void *tx, uint32_t tx_length, void *rx, uint32_t rx_length, uint8_t bit_width)
manhpham 0:c8673aa96267 503 {
manhpham 0:c8673aa96267 504 uint32_t i;
manhpham 0:c8673aa96267 505 uint16_t *tx_ptr = (uint16_t *) tx;
manhpham 0:c8673aa96267 506
manhpham 0:c8673aa96267 507 obj->tx_buff.buffer = (void *)tx;
manhpham 0:c8673aa96267 508 obj->rx_buff.buffer = rx;
manhpham 0:c8673aa96267 509 obj->tx_buff.length = tx_length;
manhpham 0:c8673aa96267 510 obj->rx_buff.length = rx_length;
manhpham 0:c8673aa96267 511 obj->tx_buff.pos = 0;
manhpham 0:c8673aa96267 512 obj->rx_buff.pos = 0;
manhpham 0:c8673aa96267 513 obj->tx_buff.width = bit_width;
manhpham 0:c8673aa96267 514 obj->rx_buff.width = bit_width;
manhpham 0:c8673aa96267 515
manhpham 0:c8673aa96267 516 if((obj->spi.bits == 9) && (tx != 0)) {
manhpham 0:c8673aa96267 517 // Make sure we don't have inadvertent non-zero bits outside 9-bit frames which could trigger unwanted operation
manhpham 0:c8673aa96267 518 for(i = 0; i < (tx_length / 2); i++) {
manhpham 0:c8673aa96267 519 tx_ptr[i] &= 0x1FF;
manhpham 0:c8673aa96267 520 }
manhpham 0:c8673aa96267 521 }
manhpham 0:c8673aa96267 522 }
manhpham 0:c8673aa96267 523
manhpham 0:c8673aa96267 524 static void spi_buffer_tx_write(spi_t *obj)
manhpham 0:c8673aa96267 525 {
manhpham 0:c8673aa96267 526 uint32_t data = 0;
manhpham 0:c8673aa96267 527
manhpham 0:c8673aa96267 528 // Interpret buffer according to declared width
manhpham 0:c8673aa96267 529 if (!obj->tx_buff.buffer) {
manhpham 0:c8673aa96267 530 data = SPI_FILL_WORD;
manhpham 0:c8673aa96267 531 } else if (obj->tx_buff.width == 32) {
manhpham 0:c8673aa96267 532 uint32_t * tx = (uint32_t *)obj->tx_buff.buffer;
manhpham 0:c8673aa96267 533 data = tx[obj->tx_buff.pos];
manhpham 0:c8673aa96267 534 } else if (obj->tx_buff.width == 16) {
manhpham 0:c8673aa96267 535 uint16_t * tx = (uint16_t *)obj->tx_buff.buffer;
manhpham 0:c8673aa96267 536 data = tx[obj->tx_buff.pos];
manhpham 0:c8673aa96267 537 } else {
manhpham 0:c8673aa96267 538 uint8_t * tx = (uint8_t *)obj->tx_buff.buffer;
manhpham 0:c8673aa96267 539 data = tx[obj->tx_buff.pos];
manhpham 0:c8673aa96267 540 }
manhpham 0:c8673aa96267 541 obj->tx_buff.pos++;
manhpham 0:c8673aa96267 542
manhpham 0:c8673aa96267 543 // Send buffer
manhpham 0:c8673aa96267 544 if (obj->spi.bits > 9) {
manhpham 0:c8673aa96267 545 obj->spi.spi->TXDOUBLE = data;
manhpham 0:c8673aa96267 546 } else if (obj->spi.bits == 9) {
manhpham 0:c8673aa96267 547 obj->spi.spi->TXDATAX = data;
manhpham 0:c8673aa96267 548 } else {
manhpham 0:c8673aa96267 549 obj->spi.spi->TXDATA = data;
manhpham 0:c8673aa96267 550 }
manhpham 0:c8673aa96267 551 }
manhpham 0:c8673aa96267 552
manhpham 0:c8673aa96267 553 static void spi_buffer_rx_read(spi_t *obj)
manhpham 0:c8673aa96267 554 {
manhpham 0:c8673aa96267 555 uint32_t data;
manhpham 0:c8673aa96267 556
manhpham 0:c8673aa96267 557 if (obj->spi.spi->STATUS & USART_STATUS_RXDATAV) {
manhpham 0:c8673aa96267 558 // Read from the FIFO
manhpham 0:c8673aa96267 559 if (obj->spi.bits > 9) {
manhpham 0:c8673aa96267 560 data = obj->spi.spi->RXDOUBLE;
manhpham 0:c8673aa96267 561 } else if (obj->spi.bits == 9) {
manhpham 0:c8673aa96267 562 data = obj->spi.spi->RXDATAX;
manhpham 0:c8673aa96267 563 } else {
manhpham 0:c8673aa96267 564 data = obj->spi.spi->RXDATA;
manhpham 0:c8673aa96267 565 }
manhpham 0:c8673aa96267 566
manhpham 0:c8673aa96267 567 // If there is room in the buffer, store the data
manhpham 0:c8673aa96267 568 if (obj->rx_buff.buffer && obj->rx_buff.pos < obj->rx_buff.length) {
manhpham 0:c8673aa96267 569 if (obj->rx_buff.width == 32) {
manhpham 0:c8673aa96267 570 uint32_t * rx = (uint32_t *)(obj->rx_buff.buffer);
manhpham 0:c8673aa96267 571 rx[obj->rx_buff.pos] = data;
manhpham 0:c8673aa96267 572 } else if (obj->rx_buff.width == 16) {
manhpham 0:c8673aa96267 573 uint16_t * rx = (uint16_t *)(obj->rx_buff.buffer);
manhpham 0:c8673aa96267 574 rx[obj->rx_buff.pos] = data;
manhpham 0:c8673aa96267 575 } else {
manhpham 0:c8673aa96267 576 uint8_t * rx = (uint8_t *)(obj->rx_buff.buffer);
manhpham 0:c8673aa96267 577 rx[obj->rx_buff.pos] = data;
manhpham 0:c8673aa96267 578 }
manhpham 0:c8673aa96267 579 obj->rx_buff.pos++;
manhpham 0:c8673aa96267 580 }
manhpham 0:c8673aa96267 581 }
manhpham 0:c8673aa96267 582 }
manhpham 0:c8673aa96267 583
manhpham 0:c8673aa96267 584 int spi_master_write_asynch(spi_t *obj)
manhpham 0:c8673aa96267 585 {
manhpham 0:c8673aa96267 586 int ndata = 0;
manhpham 0:c8673aa96267 587 while ((obj->tx_buff.pos < obj->tx_buff.length) && (obj->spi.spi->STATUS & USART_STATUS_TXBL)) {
manhpham 0:c8673aa96267 588 spi_buffer_tx_write(obj);
manhpham 0:c8673aa96267 589 ndata++;
manhpham 0:c8673aa96267 590 }
manhpham 0:c8673aa96267 591 return ndata;
manhpham 0:c8673aa96267 592 }
manhpham 0:c8673aa96267 593
manhpham 0:c8673aa96267 594 int spi_master_read_asynch(spi_t *obj)
manhpham 0:c8673aa96267 595 {
manhpham 0:c8673aa96267 596 int ndata = 0;
manhpham 0:c8673aa96267 597 while ((obj->rx_buff.pos < obj->rx_buff.length) && (obj->spi.spi->STATUS & (USART_STATUS_RXDATAV | USART_STATUS_RXFULL))) {
manhpham 0:c8673aa96267 598 spi_buffer_rx_read(obj);
manhpham 0:c8673aa96267 599 ndata++;
manhpham 0:c8673aa96267 600 }
manhpham 0:c8673aa96267 601 // all sent but still more to receive? need to align tx buffer
manhpham 0:c8673aa96267 602 if ((obj->tx_buff.pos >= obj->tx_buff.length) && (obj->rx_buff.pos < obj->rx_buff.length)) {
manhpham 0:c8673aa96267 603 obj->tx_buff.buffer = (void *)0;
manhpham 0:c8673aa96267 604 obj->tx_buff.length = obj->rx_buff.length;
manhpham 0:c8673aa96267 605 }
manhpham 0:c8673aa96267 606
manhpham 0:c8673aa96267 607 return ndata;
manhpham 0:c8673aa96267 608 }
manhpham 0:c8673aa96267 609
manhpham 0:c8673aa96267 610 uint8_t spi_buffer_rx_empty(spi_t *obj)
manhpham 0:c8673aa96267 611 {
manhpham 0:c8673aa96267 612 return (obj->rx_buff.pos >= obj->rx_buff.length ? true : false );
manhpham 0:c8673aa96267 613 }
manhpham 0:c8673aa96267 614
manhpham 0:c8673aa96267 615 uint8_t spi_buffer_tx_empty(spi_t *obj)
manhpham 0:c8673aa96267 616 {
manhpham 0:c8673aa96267 617 return (obj->tx_buff.pos >= obj->tx_buff.length ? true : false );
manhpham 0:c8673aa96267 618 }
manhpham 0:c8673aa96267 619
manhpham 0:c8673aa96267 620 //TODO_LP implement slave
manhpham 0:c8673aa96267 621
manhpham 0:c8673aa96267 622 int spi_slave_receive(spi_t *obj)
manhpham 0:c8673aa96267 623 {
manhpham 0:c8673aa96267 624 if (obj->spi.bits <= 9) {
manhpham 0:c8673aa96267 625 return (obj->spi.spi->STATUS & USART_STATUS_RXDATAV) ? 1 : 0;
manhpham 0:c8673aa96267 626 } else {
manhpham 0:c8673aa96267 627 return (obj->spi.spi->STATUS & USART_STATUS_RXFULL) ? 1 : 0;
manhpham 0:c8673aa96267 628 }
manhpham 0:c8673aa96267 629 }
manhpham 0:c8673aa96267 630
manhpham 0:c8673aa96267 631 int spi_slave_read(spi_t *obj)
manhpham 0:c8673aa96267 632 {
manhpham 0:c8673aa96267 633 return spi_read(obj);
manhpham 0:c8673aa96267 634 }
manhpham 0:c8673aa96267 635
manhpham 0:c8673aa96267 636 void spi_slave_write(spi_t *obj, int value)
manhpham 0:c8673aa96267 637 {
manhpham 0:c8673aa96267 638 spi_write(obj, value);
manhpham 0:c8673aa96267 639 }
manhpham 0:c8673aa96267 640
manhpham 0:c8673aa96267 641 uint32_t spi_event_check(spi_t *obj)
manhpham 0:c8673aa96267 642 {
manhpham 0:c8673aa96267 643 uint32_t requestedEvent = obj->spi.event;
manhpham 0:c8673aa96267 644 uint32_t event = 0;
manhpham 0:c8673aa96267 645 uint8_t quit = spi_buffer_rx_empty(obj) & spi_buffer_tx_empty(obj);
manhpham 0:c8673aa96267 646 if (((requestedEvent & SPI_EVENT_COMPLETE) != 0) && (quit == true)) {
manhpham 0:c8673aa96267 647 event |= SPI_EVENT_COMPLETE;
manhpham 0:c8673aa96267 648 }
manhpham 0:c8673aa96267 649
manhpham 0:c8673aa96267 650 if(quit == true) {
manhpham 0:c8673aa96267 651 event |= SPI_EVENT_INTERNAL_TRANSFER_COMPLETE;
manhpham 0:c8673aa96267 652 }
manhpham 0:c8673aa96267 653
manhpham 0:c8673aa96267 654 return event;
manhpham 0:c8673aa96267 655 }
manhpham 0:c8673aa96267 656 /******************************************
manhpham 0:c8673aa96267 657 * void transferComplete(uint channel, bool primary, void* user)
manhpham 0:c8673aa96267 658 *
manhpham 0:c8673aa96267 659 * Callback function which gets called upon DMA transfer completion
manhpham 0:c8673aa96267 660 * the user-defined pointer is pointing to the CPP-land thunk
manhpham 0:c8673aa96267 661 ******************************************/
manhpham 0:c8673aa96267 662 void transferComplete(unsigned int channel, bool primary, void *user)
manhpham 0:c8673aa96267 663 {
manhpham 0:c8673aa96267 664 (void) channel;
manhpham 0:c8673aa96267 665 (void) primary;
manhpham 0:c8673aa96267 666
manhpham 0:c8673aa96267 667 /* User pointer should be a thunk to CPP land */
manhpham 0:c8673aa96267 668 if (user != NULL) {
manhpham 0:c8673aa96267 669 ((DMACallback)user)();
manhpham 0:c8673aa96267 670 }
manhpham 0:c8673aa96267 671 }
manhpham 0:c8673aa96267 672
manhpham 0:c8673aa96267 673 /******************************************
manhpham 0:c8673aa96267 674 * bool spi_allocate_dma(spi_t *obj);
manhpham 0:c8673aa96267 675 * (helper function for spi_enable_dma)
manhpham 0:c8673aa96267 676 *
manhpham 0:c8673aa96267 677 * This function will request two DMA channels from the DMA API if needed
manhpham 0:c8673aa96267 678 * by the hint provided. They will be allocated to the SPI object pointed to.
manhpham 0:c8673aa96267 679 *
manhpham 0:c8673aa96267 680 * return value: whether the channels were acquired successfully (true) or not.
manhpham 0:c8673aa96267 681 ******************************************/
manhpham 0:c8673aa96267 682 bool spi_allocate_dma(spi_t *obj)
manhpham 0:c8673aa96267 683 {
manhpham 0:c8673aa96267 684 int dmaChannelIn, dmaChannelOut;
manhpham 0:c8673aa96267 685 dmaChannelIn = dma_channel_allocate(DMA_CAP_NONE);
manhpham 0:c8673aa96267 686 if (dmaChannelIn == DMA_ERROR_OUT_OF_CHANNELS) {
manhpham 0:c8673aa96267 687 return false;
manhpham 0:c8673aa96267 688 }
manhpham 0:c8673aa96267 689 dmaChannelOut = dma_channel_allocate(DMA_CAP_NONE);
manhpham 0:c8673aa96267 690 if (dmaChannelOut == DMA_ERROR_OUT_OF_CHANNELS) {
manhpham 0:c8673aa96267 691 dma_channel_free(dmaChannelIn);
manhpham 0:c8673aa96267 692 return false;
manhpham 0:c8673aa96267 693 }
manhpham 0:c8673aa96267 694
manhpham 0:c8673aa96267 695 obj->spi.dmaOptionsTX.dmaChannel = dmaChannelOut;
manhpham 0:c8673aa96267 696 obj->spi.dmaOptionsRX.dmaChannel = dmaChannelIn;
manhpham 0:c8673aa96267 697 return true;
manhpham 0:c8673aa96267 698 }
manhpham 0:c8673aa96267 699
manhpham 0:c8673aa96267 700 /******************************************
manhpham 0:c8673aa96267 701 * void spi_enable_dma(spi_t *obj, DMAUsage state)
manhpham 0:c8673aa96267 702 *
manhpham 0:c8673aa96267 703 * This function tries to allocate DMA as indicated by the hint (state).
manhpham 0:c8673aa96267 704 * There are three possibilities:
manhpham 0:c8673aa96267 705 * * state = NEVER:
manhpham 0:c8673aa96267 706 * if there were channels allocated by state = ALWAYS, they will be released
manhpham 0:c8673aa96267 707 * * state = OPPORTUNITIC:
manhpham 0:c8673aa96267 708 * if there are channels available, they will get used, but freed upon transfer completion
manhpham 0:c8673aa96267 709 * * state = ALWAYS
manhpham 0:c8673aa96267 710 * if there are channels available, they will get allocated and not be freed until state changes
manhpham 0:c8673aa96267 711 ******************************************/
manhpham 0:c8673aa96267 712 void spi_enable_dma(spi_t *obj, DMAUsage state)
manhpham 0:c8673aa96267 713 {
manhpham 0:c8673aa96267 714 if (state == DMA_USAGE_ALWAYS && obj->spi.dmaOptionsTX.dmaUsageState != DMA_USAGE_ALLOCATED) {
manhpham 0:c8673aa96267 715 /* Try to allocate channels */
manhpham 0:c8673aa96267 716 if (spi_allocate_dma(obj)) {
manhpham 0:c8673aa96267 717 obj->spi.dmaOptionsTX.dmaUsageState = DMA_USAGE_ALLOCATED;
manhpham 0:c8673aa96267 718 } else {
manhpham 0:c8673aa96267 719 obj->spi.dmaOptionsTX.dmaUsageState = state;
manhpham 0:c8673aa96267 720 }
manhpham 0:c8673aa96267 721 } else if (state == DMA_USAGE_OPPORTUNISTIC) {
manhpham 0:c8673aa96267 722 if (obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_ALLOCATED) {
manhpham 0:c8673aa96267 723 /* Channels have already been allocated previously by an ALWAYS state, so after this transfer, we will release them */
manhpham 0:c8673aa96267 724 obj->spi.dmaOptionsTX.dmaUsageState = DMA_USAGE_TEMPORARY_ALLOCATED;
manhpham 0:c8673aa96267 725 } else {
manhpham 0:c8673aa96267 726 /* Try to allocate channels */
manhpham 0:c8673aa96267 727 if (spi_allocate_dma(obj)) {
manhpham 0:c8673aa96267 728 obj->spi.dmaOptionsTX.dmaUsageState = DMA_USAGE_TEMPORARY_ALLOCATED;
manhpham 0:c8673aa96267 729 } else {
manhpham 0:c8673aa96267 730 obj->spi.dmaOptionsTX.dmaUsageState = state;
manhpham 0:c8673aa96267 731 }
manhpham 0:c8673aa96267 732 }
manhpham 0:c8673aa96267 733 } else if (state == DMA_USAGE_NEVER) {
manhpham 0:c8673aa96267 734 /* If channels are allocated, get rid of them */
manhpham 0:c8673aa96267 735 if (obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_ALLOCATED) {
manhpham 0:c8673aa96267 736 dma_channel_free(obj->spi.dmaOptionsTX.dmaChannel);
manhpham 0:c8673aa96267 737 dma_channel_free(obj->spi.dmaOptionsRX.dmaChannel);
manhpham 0:c8673aa96267 738 }
manhpham 0:c8673aa96267 739 obj->spi.dmaOptionsTX.dmaUsageState = DMA_USAGE_NEVER;
manhpham 0:c8673aa96267 740 }
manhpham 0:c8673aa96267 741 }
manhpham 0:c8673aa96267 742
manhpham 0:c8673aa96267 743 #ifdef LDMA_PRESENT
manhpham 0:c8673aa96267 744 /************************************************************************************
manhpham 0:c8673aa96267 745 * DMA helper functions *
manhpham 0:c8673aa96267 746 ************************************************************************************/
manhpham 0:c8673aa96267 747 /******************************************
manhpham 0:c8673aa96267 748 * static void serial_dmaTransferComplete(uint channel, bool primary, void* user)
manhpham 0:c8673aa96267 749 *
manhpham 0:c8673aa96267 750 * Callback function which gets called upon DMA transfer completion
manhpham 0:c8673aa96267 751 * the user-defined pointer is pointing to the CPP-land thunk
manhpham 0:c8673aa96267 752 ******************************************/
manhpham 0:c8673aa96267 753 static void serial_dmaTransferComplete(unsigned int channel, bool primary, void *user)
manhpham 0:c8673aa96267 754 {
manhpham 0:c8673aa96267 755
manhpham 0:c8673aa96267 756 /* User pointer should be a thunk to CPP land */
manhpham 0:c8673aa96267 757 if (user != NULL) {
manhpham 0:c8673aa96267 758 ((DMACallback)user)();
manhpham 0:c8673aa96267 759 }
manhpham 0:c8673aa96267 760 }
manhpham 0:c8673aa96267 761 static void spi_master_dma_channel_setup(spi_t *obj, void* callback)
manhpham 0:c8673aa96267 762 {
manhpham 0:c8673aa96267 763 obj->spi.dmaOptionsRX.dmaCallback.userPtr = callback;
manhpham 0:c8673aa96267 764 }
manhpham 0:c8673aa96267 765 #else
manhpham 0:c8673aa96267 766 /******************************************
manhpham 0:c8673aa96267 767 * void spi_master_dma_channel_setup(spi_t *obj)
manhpham 0:c8673aa96267 768 *
manhpham 0:c8673aa96267 769 * This function will setup the DMA configuration for SPI transfers
manhpham 0:c8673aa96267 770 *
manhpham 0:c8673aa96267 771 * The channel numbers are fetched from the SPI instance, so this function
manhpham 0:c8673aa96267 772 * should only be called when those channels have actually been allocated.
manhpham 0:c8673aa96267 773 ******************************************/
manhpham 0:c8673aa96267 774 static void spi_master_dma_channel_setup(spi_t *obj, void* callback)
manhpham 0:c8673aa96267 775 {
manhpham 0:c8673aa96267 776 DMA_CfgChannel_TypeDef rxChnlCfg;
manhpham 0:c8673aa96267 777 DMA_CfgChannel_TypeDef txChnlCfg;
manhpham 0:c8673aa96267 778
manhpham 0:c8673aa96267 779 /* Setting up channel for rx. */
manhpham 0:c8673aa96267 780 obj->spi.dmaOptionsRX.dmaCallback.cbFunc = transferComplete;
manhpham 0:c8673aa96267 781 obj->spi.dmaOptionsRX.dmaCallback.userPtr = callback;
manhpham 0:c8673aa96267 782
manhpham 0:c8673aa96267 783 rxChnlCfg.highPri = false;
manhpham 0:c8673aa96267 784 rxChnlCfg.enableInt = true;
manhpham 0:c8673aa96267 785 rxChnlCfg.cb = &(obj->spi.dmaOptionsRX.dmaCallback);
manhpham 0:c8673aa96267 786
manhpham 0:c8673aa96267 787 /* Setting up channel for tx. */
manhpham 0:c8673aa96267 788 obj->spi.dmaOptionsTX.dmaCallback.cbFunc = transferComplete;
manhpham 0:c8673aa96267 789 obj->spi.dmaOptionsTX.dmaCallback.userPtr = callback;
manhpham 0:c8673aa96267 790
manhpham 0:c8673aa96267 791 txChnlCfg.highPri = false;
manhpham 0:c8673aa96267 792 txChnlCfg.enableInt = true;
manhpham 0:c8673aa96267 793 txChnlCfg.cb = &(obj->spi.dmaOptionsTX.dmaCallback);
manhpham 0:c8673aa96267 794
manhpham 0:c8673aa96267 795 switch ((int)obj->spi.spi) {
manhpham 0:c8673aa96267 796 #ifdef USART0
manhpham 0:c8673aa96267 797 case SPI_0:
manhpham 0:c8673aa96267 798 rxChnlCfg.select = DMAREQ_USART0_RXDATAV;
manhpham 0:c8673aa96267 799 txChnlCfg.select = DMAREQ_USART0_TXEMPTY;
manhpham 0:c8673aa96267 800 break;
manhpham 0:c8673aa96267 801 #endif
manhpham 0:c8673aa96267 802 #ifdef USART1
manhpham 0:c8673aa96267 803 case SPI_1:
manhpham 0:c8673aa96267 804 rxChnlCfg.select = DMAREQ_USART1_RXDATAV;
manhpham 0:c8673aa96267 805 txChnlCfg.select = DMAREQ_USART1_TXEMPTY;
manhpham 0:c8673aa96267 806 break;
manhpham 0:c8673aa96267 807 #endif
manhpham 0:c8673aa96267 808 #ifdef USART2
manhpham 0:c8673aa96267 809 case SPI_2:
manhpham 0:c8673aa96267 810 rxChnlCfg.select = DMAREQ_USART2_RXDATAV;
manhpham 0:c8673aa96267 811 txChnlCfg.select = DMAREQ_USART2_TXEMPTY;
manhpham 0:c8673aa96267 812 break;
manhpham 0:c8673aa96267 813 #endif
manhpham 0:c8673aa96267 814 #ifdef USART3
manhpham 0:c8673aa96267 815 case SPI_3:
manhpham 0:c8673aa96267 816 rxChnlCfg.select = DMAREQ_USART3_RXDATAV;
manhpham 0:c8673aa96267 817 txChnlCfg.select = DMAREQ_USART3_TXEMPTY;
manhpham 0:c8673aa96267 818 break;
manhpham 0:c8673aa96267 819 #endif
manhpham 0:c8673aa96267 820 #ifdef USART4
manhpham 0:c8673aa96267 821 case SPI_4:
manhpham 0:c8673aa96267 822 rxChnlCfg.select = DMAREQ_USART4_RXDATAV;
manhpham 0:c8673aa96267 823 txChnlCfg.select = DMAREQ_USART4_TXEMPTY;
manhpham 0:c8673aa96267 824 break;
manhpham 0:c8673aa96267 825 #endif
manhpham 0:c8673aa96267 826 #ifdef USART5
manhpham 0:c8673aa96267 827 case SPI_5:
manhpham 0:c8673aa96267 828 rxChnlCfg.select = DMAREQ_USART5_RXDATAV;
manhpham 0:c8673aa96267 829 txChnlCfg.select = DMAREQ_USART5_TXEMPTY;
manhpham 0:c8673aa96267 830 break;
manhpham 0:c8673aa96267 831 #endif
manhpham 0:c8673aa96267 832 default:
manhpham 0:c8673aa96267 833 error("Spi module not available.. Out of bound access.");
manhpham 0:c8673aa96267 834 break;
manhpham 0:c8673aa96267 835 }
manhpham 0:c8673aa96267 836 DMA_CfgChannel(obj->spi.dmaOptionsRX.dmaChannel, &rxChnlCfg);
manhpham 0:c8673aa96267 837 DMA_CfgChannel(obj->spi.dmaOptionsTX.dmaChannel, &txChnlCfg);
manhpham 0:c8673aa96267 838 }
manhpham 0:c8673aa96267 839 #endif // LDMA_PRESENT
manhpham 0:c8673aa96267 840 /******************************************
manhpham 0:c8673aa96267 841 * void spi_activate_dma(spi_t *obj, void* rxdata, void* txdata, int length)
manhpham 0:c8673aa96267 842 *
manhpham 0:c8673aa96267 843 * This function will start the DMA engine for SPI transfers
manhpham 0:c8673aa96267 844 *
manhpham 0:c8673aa96267 845 * * rxdata: pointer to RX buffer, if needed.
manhpham 0:c8673aa96267 846 * * txdata: pointer to TX buffer, if needed. Else FF's.
manhpham 0:c8673aa96267 847 * * tx_length: how many bytes will get sent.
manhpham 0:c8673aa96267 848 * * rx_length: how many bytes will get received. If > tx_length, TX will get padded with n lower bits of SPI_FILL_WORD.
manhpham 0:c8673aa96267 849 ******************************************/
manhpham 0:c8673aa96267 850 #ifdef LDMA_PRESENT
manhpham 0:c8673aa96267 851 static void spi_activate_dma(spi_t *obj, void* rxdata, const void* txdata, int tx_length, int rx_length)
manhpham 0:c8673aa96267 852 {
manhpham 0:c8673aa96267 853 LDMA_PeripheralSignal_t dma_periph;
manhpham 0:c8673aa96267 854
manhpham 0:c8673aa96267 855 if(rxdata) {
manhpham 0:c8673aa96267 856 volatile const void *source_addr;
manhpham 0:c8673aa96267 857 /* Select RX source address. 9 bit frame length requires to use extended register.
manhpham 0:c8673aa96267 858 10 bit and larger frame requires to use RXDOUBLE register. */
manhpham 0:c8673aa96267 859 switch((int)obj->spi.spi) {
manhpham 0:c8673aa96267 860 #ifdef USART0
manhpham 0:c8673aa96267 861 case USART_0:
manhpham 0:c8673aa96267 862 dma_periph = ldmaPeripheralSignal_USART0_RXDATAV;
manhpham 0:c8673aa96267 863 break;
manhpham 0:c8673aa96267 864 #endif
manhpham 0:c8673aa96267 865 #ifdef USART1
manhpham 0:c8673aa96267 866 case USART_1:
manhpham 0:c8673aa96267 867 dma_periph = ldmaPeripheralSignal_USART1_RXDATAV;
manhpham 0:c8673aa96267 868 break;
manhpham 0:c8673aa96267 869 #endif
manhpham 0:c8673aa96267 870 #ifdef USART2
manhpham 0:c8673aa96267 871 case USART_2:
manhpham 0:c8673aa96267 872 dma_periph = ldmaPeripheralSignal_USART2_RXDATAV;
manhpham 0:c8673aa96267 873 break;
manhpham 0:c8673aa96267 874 #endif
manhpham 0:c8673aa96267 875 #ifdef USART3
manhpham 0:c8673aa96267 876 case USART_3:
manhpham 0:c8673aa96267 877 dma_periph = ldmaPeripheralSignal_USART3_RXDATAV;
manhpham 0:c8673aa96267 878 break;
manhpham 0:c8673aa96267 879 #endif
manhpham 0:c8673aa96267 880 #ifdef USART4
manhpham 0:c8673aa96267 881 case USART_4:
manhpham 0:c8673aa96267 882 dma_periph = ldmaPeripheralSignal_USART4_RXDATAV;
manhpham 0:c8673aa96267 883 break;
manhpham 0:c8673aa96267 884 #endif
manhpham 0:c8673aa96267 885 #ifdef USART5
manhpham 0:c8673aa96267 886 case USART_5:
manhpham 0:c8673aa96267 887 dma_periph = ldmaPeripheralSignal_USART5_RXDATAV;
manhpham 0:c8673aa96267 888 break;
manhpham 0:c8673aa96267 889 #endif
manhpham 0:c8673aa96267 890 default:
manhpham 0:c8673aa96267 891 EFM_ASSERT(0);
manhpham 0:c8673aa96267 892 while(1);
manhpham 0:c8673aa96267 893 break;
manhpham 0:c8673aa96267 894 }
manhpham 0:c8673aa96267 895
manhpham 0:c8673aa96267 896 if (obj->spi.bits <= 8) {
manhpham 0:c8673aa96267 897 source_addr = &obj->spi.spi->RXDATA;
manhpham 0:c8673aa96267 898 } else if (obj->spi.bits == 9) {
manhpham 0:c8673aa96267 899 source_addr = &obj->spi.spi->RXDATAX;
manhpham 0:c8673aa96267 900 } else {
manhpham 0:c8673aa96267 901 source_addr = &obj->spi.spi->RXDOUBLE;
manhpham 0:c8673aa96267 902 }
manhpham 0:c8673aa96267 903
manhpham 0:c8673aa96267 904 LDMA_TransferCfg_t xferConf = LDMA_TRANSFER_CFG_PERIPHERAL(dma_periph);
manhpham 0:c8673aa96267 905 LDMA_Descriptor_t desc = LDMA_DESCRIPTOR_SINGLE_P2M_BYTE(source_addr, rxdata, rx_length);
manhpham 0:c8673aa96267 906
manhpham 0:c8673aa96267 907 if(obj->spi.bits >= 9){
manhpham 0:c8673aa96267 908 desc.xfer.size = ldmaCtrlSizeHalf;
manhpham 0:c8673aa96267 909 }
manhpham 0:c8673aa96267 910
manhpham 0:c8673aa96267 911 if (obj->tx_buff.width == 32) {
manhpham 0:c8673aa96267 912 if (obj->spi.bits >= 9) {
manhpham 0:c8673aa96267 913 desc.xfer.dstInc = ldmaCtrlDstIncTwo;
manhpham 0:c8673aa96267 914 } else {
manhpham 0:c8673aa96267 915 desc.xfer.dstInc = ldmaCtrlDstIncFour;
manhpham 0:c8673aa96267 916 }
manhpham 0:c8673aa96267 917 } else if (obj->tx_buff.width == 16) {
manhpham 0:c8673aa96267 918 if (obj->spi.bits >= 9) {
manhpham 0:c8673aa96267 919 desc.xfer.dstInc = ldmaCtrlDstIncOne;
manhpham 0:c8673aa96267 920 } else {
manhpham 0:c8673aa96267 921 desc.xfer.dstInc = ldmaCtrlDstIncTwo;
manhpham 0:c8673aa96267 922 }
manhpham 0:c8673aa96267 923 } else {
manhpham 0:c8673aa96267 924 desc.xfer.dstInc = ldmaCtrlDstIncOne;
manhpham 0:c8673aa96267 925 }
manhpham 0:c8673aa96267 926
manhpham 0:c8673aa96267 927 LDMAx_StartTransfer(obj->spi.dmaOptionsRX.dmaChannel, &xferConf, &desc, serial_dmaTransferComplete,obj->spi.dmaOptionsRX.dmaCallback.userPtr);
manhpham 0:c8673aa96267 928 }
manhpham 0:c8673aa96267 929
manhpham 0:c8673aa96267 930 volatile void *target_addr;
manhpham 0:c8673aa96267 931
manhpham 0:c8673aa96267 932 /* Select TX target address. 9 bit frame length requires to use extended register.
manhpham 0:c8673aa96267 933 10 bit and larger frame requires to use TXDOUBLE register. */
manhpham 0:c8673aa96267 934 switch ((int)obj->spi.spi) {
manhpham 0:c8673aa96267 935 case USART_0:
manhpham 0:c8673aa96267 936 dma_periph = ldmaPeripheralSignal_USART0_TXBL;
manhpham 0:c8673aa96267 937 break;
manhpham 0:c8673aa96267 938 case USART_1:
manhpham 0:c8673aa96267 939 dma_periph = ldmaPeripheralSignal_USART1_TXBL;
manhpham 0:c8673aa96267 940 break;
manhpham 0:c8673aa96267 941 default:
manhpham 0:c8673aa96267 942 EFM_ASSERT(0);
manhpham 0:c8673aa96267 943 while(1);
manhpham 0:c8673aa96267 944 break;
manhpham 0:c8673aa96267 945 }
manhpham 0:c8673aa96267 946
manhpham 0:c8673aa96267 947 if (obj->spi.bits <= 8) {
manhpham 0:c8673aa96267 948 target_addr = &obj->spi.spi->TXDATA;
manhpham 0:c8673aa96267 949 } else if (obj->spi.bits == 9) {
manhpham 0:c8673aa96267 950 target_addr = &obj->spi.spi->TXDATAX;
manhpham 0:c8673aa96267 951 } else {
manhpham 0:c8673aa96267 952 target_addr = &obj->spi.spi->TXDOUBLE;
manhpham 0:c8673aa96267 953 }
manhpham 0:c8673aa96267 954
manhpham 0:c8673aa96267 955 /* Check the transmit length, and split long transfers to smaller ones */
manhpham 0:c8673aa96267 956 int max_length = 1024;
manhpham 0:c8673aa96267 957 #ifdef _LDMA_CH_CTRL_XFERCNT_MASK
manhpham 0:c8673aa96267 958 max_length = (_LDMA_CH_CTRL_XFERCNT_MASK>>_LDMA_CH_CTRL_XFERCNT_SHIFT)+1;
manhpham 0:c8673aa96267 959 #endif
manhpham 0:c8673aa96267 960 if (tx_length > max_length) {
manhpham 0:c8673aa96267 961 tx_length = max_length;
manhpham 0:c8673aa96267 962 }
manhpham 0:c8673aa96267 963
manhpham 0:c8673aa96267 964 /* Save amount of TX done by DMA */
manhpham 0:c8673aa96267 965 obj->tx_buff.pos += tx_length;
manhpham 0:c8673aa96267 966
manhpham 0:c8673aa96267 967 LDMA_TransferCfg_t xferConf = LDMA_TRANSFER_CFG_PERIPHERAL(dma_periph);
manhpham 0:c8673aa96267 968 LDMA_Descriptor_t desc = LDMA_DESCRIPTOR_SINGLE_M2P_BYTE((txdata ? txdata : &fill_word), target_addr, tx_length);
manhpham 0:c8673aa96267 969
manhpham 0:c8673aa96267 970 if (obj->spi.bits >= 9) {
manhpham 0:c8673aa96267 971 desc.xfer.size = ldmaCtrlSizeHalf;
manhpham 0:c8673aa96267 972 }
manhpham 0:c8673aa96267 973
manhpham 0:c8673aa96267 974 if (!txdata) {
manhpham 0:c8673aa96267 975 desc.xfer.srcInc = ldmaCtrlSrcIncNone;
manhpham 0:c8673aa96267 976 } else if (obj->tx_buff.width == 32) {
manhpham 0:c8673aa96267 977 if (obj->spi.bits >= 9) {
manhpham 0:c8673aa96267 978 desc.xfer.srcInc = ldmaCtrlSrcIncTwo;
manhpham 0:c8673aa96267 979 } else {
manhpham 0:c8673aa96267 980 desc.xfer.srcInc = ldmaCtrlSrcIncFour;
manhpham 0:c8673aa96267 981 }
manhpham 0:c8673aa96267 982 } else if (obj->tx_buff.width == 16) {
manhpham 0:c8673aa96267 983 if (obj->spi.bits >= 9) {
manhpham 0:c8673aa96267 984 desc.xfer.srcInc = ldmaCtrlSrcIncOne;
manhpham 0:c8673aa96267 985 } else {
manhpham 0:c8673aa96267 986 desc.xfer.srcInc = ldmaCtrlSrcIncTwo;
manhpham 0:c8673aa96267 987 }
manhpham 0:c8673aa96267 988 } else {
manhpham 0:c8673aa96267 989 desc.xfer.srcInc = ldmaCtrlSrcIncOne;
manhpham 0:c8673aa96267 990 }
manhpham 0:c8673aa96267 991
manhpham 0:c8673aa96267 992 // Kick off DMA TX
manhpham 0:c8673aa96267 993 LDMAx_StartTransfer(obj->spi.dmaOptionsTX.dmaChannel, &xferConf, &desc, serial_dmaTransferComplete,obj->spi.dmaOptionsTX.dmaCallback.userPtr);
manhpham 0:c8673aa96267 994 }
manhpham 0:c8673aa96267 995
manhpham 0:c8673aa96267 996 #else
manhpham 0:c8673aa96267 997 /******************************************
manhpham 0:c8673aa96267 998 * void spi_activate_dma(spi_t *obj, void* rxdata, void* txdata, int length)
manhpham 0:c8673aa96267 999 *
manhpham 0:c8673aa96267 1000 * This function will start the DMA engine for SPI transfers
manhpham 0:c8673aa96267 1001 *
manhpham 0:c8673aa96267 1002 * * rxdata: pointer to RX buffer, if needed.
manhpham 0:c8673aa96267 1003 * * txdata: pointer to TX buffer, if needed. Else FF's.
manhpham 0:c8673aa96267 1004 * * tx_length: how many bytes will get sent.
manhpham 0:c8673aa96267 1005 * * rx_length: how many bytes will get received. If > tx_length, TX will get padded with n lower bits of SPI_FILL_WORD.
manhpham 0:c8673aa96267 1006 ******************************************/
manhpham 0:c8673aa96267 1007 static void spi_activate_dma(spi_t *obj, void* rxdata, const void* txdata, int tx_length, int rx_length)
manhpham 0:c8673aa96267 1008 {
manhpham 0:c8673aa96267 1009 /* DMA descriptors */
manhpham 0:c8673aa96267 1010 DMA_CfgDescr_TypeDef rxDescrCfg;
manhpham 0:c8673aa96267 1011 DMA_CfgDescr_TypeDef txDescrCfg;
manhpham 0:c8673aa96267 1012
manhpham 0:c8673aa96267 1013 /* Split up transfers if the length is larger than what the DMA supports. */
manhpham 0:c8673aa96267 1014 const int DMA_MAX_TRANSFER = (_DMA_CTRL_N_MINUS_1_MASK >> _DMA_CTRL_N_MINUS_1_SHIFT);
manhpham 0:c8673aa96267 1015
manhpham 0:c8673aa96267 1016 if (tx_length > DMA_MAX_TRANSFER) {
manhpham 0:c8673aa96267 1017 tx_length = DMA_MAX_TRANSFER;
manhpham 0:c8673aa96267 1018 }
manhpham 0:c8673aa96267 1019 if (rx_length > DMA_MAX_TRANSFER) {
manhpham 0:c8673aa96267 1020 rx_length = DMA_MAX_TRANSFER;
manhpham 0:c8673aa96267 1021 }
manhpham 0:c8673aa96267 1022
manhpham 0:c8673aa96267 1023 /* Save amount of TX done by DMA */
manhpham 0:c8673aa96267 1024 obj->tx_buff.pos += tx_length;
manhpham 0:c8673aa96267 1025 obj->rx_buff.pos += rx_length;
manhpham 0:c8673aa96267 1026
manhpham 0:c8673aa96267 1027 /* Only activate RX DMA if a receive buffer is specified */
manhpham 0:c8673aa96267 1028 if (rxdata != NULL) {
manhpham 0:c8673aa96267 1029 // Setting up channel descriptor
manhpham 0:c8673aa96267 1030 if (obj->rx_buff.width == 32) {
manhpham 0:c8673aa96267 1031 rxDescrCfg.dstInc = dmaDataInc4;
manhpham 0:c8673aa96267 1032 } else if (obj->rx_buff.width == 16) {
manhpham 0:c8673aa96267 1033 rxDescrCfg.dstInc = dmaDataInc2;
manhpham 0:c8673aa96267 1034 } else {
manhpham 0:c8673aa96267 1035 rxDescrCfg.dstInc = dmaDataInc1;
manhpham 0:c8673aa96267 1036 }
manhpham 0:c8673aa96267 1037 rxDescrCfg.srcInc = dmaDataIncNone;
manhpham 0:c8673aa96267 1038 rxDescrCfg.size = (obj->spi.bits <= 8 ? dmaDataSize1 : dmaDataSize2); //When frame size >= 9, use RXDOUBLE
manhpham 0:c8673aa96267 1039 rxDescrCfg.arbRate = dmaArbitrate1;
manhpham 0:c8673aa96267 1040 rxDescrCfg.hprot = 0;
manhpham 0:c8673aa96267 1041 DMA_CfgDescr(obj->spi.dmaOptionsRX.dmaChannel, true, &rxDescrCfg);
manhpham 0:c8673aa96267 1042
manhpham 0:c8673aa96267 1043 void * rx_reg;
manhpham 0:c8673aa96267 1044 if (obj->spi.bits > 9) {
manhpham 0:c8673aa96267 1045 rx_reg = (void *)&obj->spi.spi->RXDOUBLE;
manhpham 0:c8673aa96267 1046 } else if (obj->spi.bits == 9) {
manhpham 0:c8673aa96267 1047 rx_reg = (void *)&obj->spi.spi->RXDATAX;
manhpham 0:c8673aa96267 1048 } else {
manhpham 0:c8673aa96267 1049 rx_reg = (void *)&obj->spi.spi->RXDATA;
manhpham 0:c8673aa96267 1050 }
manhpham 0:c8673aa96267 1051
manhpham 0:c8673aa96267 1052 /* Activate RX channel */
manhpham 0:c8673aa96267 1053 DMA_ActivateBasic(obj->spi.dmaOptionsRX.dmaChannel,
manhpham 0:c8673aa96267 1054 true,
manhpham 0:c8673aa96267 1055 false,
manhpham 0:c8673aa96267 1056 rxdata,
manhpham 0:c8673aa96267 1057 rx_reg,
manhpham 0:c8673aa96267 1058 rx_length - 1);
manhpham 0:c8673aa96267 1059 }
manhpham 0:c8673aa96267 1060
manhpham 0:c8673aa96267 1061 // buffer with all FFs.
manhpham 0:c8673aa96267 1062 /* Setting up channel descriptor */
manhpham 0:c8673aa96267 1063 txDescrCfg.dstInc = dmaDataIncNone;
manhpham 0:c8673aa96267 1064 if (txdata == 0) {
manhpham 0:c8673aa96267 1065 // Don't increment source when there is no transmit buffer
manhpham 0:c8673aa96267 1066 txDescrCfg.srcInc = dmaDataIncNone;
manhpham 0:c8673aa96267 1067 } else {
manhpham 0:c8673aa96267 1068 if (obj->tx_buff.width == 32) {
manhpham 0:c8673aa96267 1069 txDescrCfg.srcInc = dmaDataInc4;
manhpham 0:c8673aa96267 1070 } else if (obj->tx_buff.width == 16) {
manhpham 0:c8673aa96267 1071 txDescrCfg.srcInc = dmaDataInc2;
manhpham 0:c8673aa96267 1072 } else {
manhpham 0:c8673aa96267 1073 txDescrCfg.srcInc = dmaDataInc1;
manhpham 0:c8673aa96267 1074 }
manhpham 0:c8673aa96267 1075 }
manhpham 0:c8673aa96267 1076 txDescrCfg.size = (obj->spi.bits <= 8 ? dmaDataSize1 : dmaDataSize2); //When frame size >= 9, use TXDOUBLE
manhpham 0:c8673aa96267 1077 txDescrCfg.arbRate = dmaArbitrate1;
manhpham 0:c8673aa96267 1078 txDescrCfg.hprot = 0;
manhpham 0:c8673aa96267 1079 DMA_CfgDescr(obj->spi.dmaOptionsTX.dmaChannel, true, &txDescrCfg);
manhpham 0:c8673aa96267 1080
manhpham 0:c8673aa96267 1081 void * tx_reg;
manhpham 0:c8673aa96267 1082 if (obj->spi.bits > 9) {
manhpham 0:c8673aa96267 1083 tx_reg = (void *)&obj->spi.spi->TXDOUBLE;
manhpham 0:c8673aa96267 1084 } else if (obj->spi.bits == 9) {
manhpham 0:c8673aa96267 1085 tx_reg = (void *)&obj->spi.spi->TXDATAX;
manhpham 0:c8673aa96267 1086 } else {
manhpham 0:c8673aa96267 1087 tx_reg = (void *)&obj->spi.spi->TXDATA;
manhpham 0:c8673aa96267 1088 }
manhpham 0:c8673aa96267 1089
manhpham 0:c8673aa96267 1090 /* Activate TX channel */
manhpham 0:c8673aa96267 1091 DMA_ActivateBasic(obj->spi.dmaOptionsTX.dmaChannel,
manhpham 0:c8673aa96267 1092 true,
manhpham 0:c8673aa96267 1093 false,
manhpham 0:c8673aa96267 1094 tx_reg,
manhpham 0:c8673aa96267 1095 (txdata == 0 ? &fill_word : (void *)txdata), // When there is nothing to transmit, point to static fill word
manhpham 0:c8673aa96267 1096 (tx_length - 1));
manhpham 0:c8673aa96267 1097 }
manhpham 0:c8673aa96267 1098 #endif //LDMA_PRESENT
manhpham 0:c8673aa96267 1099 /********************************************************************
manhpham 0:c8673aa96267 1100 * spi_master_transfer_dma(spi_t *obj, void *rxdata, void *txdata, int length, DMACallback cb, DMAUsage hint)
manhpham 0:c8673aa96267 1101 *
manhpham 0:c8673aa96267 1102 * Start an SPI transfer by using DMA and the supplied hint for DMA useage
manhpham 0:c8673aa96267 1103 *
manhpham 0:c8673aa96267 1104 * * obj: pointer to specific SPI instance
manhpham 0:c8673aa96267 1105 * * rxdata: pointer to rx buffer. If null, we will assume only TX is relevant, and RX will be ignored.
manhpham 0:c8673aa96267 1106 * * txdata: pointer to TX buffer. If null, we will assume only the read is relevant, and will send FF's for reading back.
manhpham 0:c8673aa96267 1107 * * length: How many bytes should be written/read.
manhpham 0:c8673aa96267 1108 * * cb: thunk pointer into CPP-land to get the spi object
manhpham 0:c8673aa96267 1109 * * hint: hint for the requested DMA useage.
manhpham 0:c8673aa96267 1110 * * NEVER: do not use DMA, but use IRQ instead
manhpham 0:c8673aa96267 1111 * * OPPORTUNISTIC: use DMA if there are channels available, but return them after the transfer.
manhpham 0:c8673aa96267 1112 * * ALWAYS: use DMA if channels are available, and hold on to the channels after the transfer.
manhpham 0:c8673aa96267 1113 * If the previous transfer has kept the channel, that channel will continue to get used.
manhpham 0:c8673aa96267 1114 *
manhpham 0:c8673aa96267 1115 ********************************************************************/
manhpham 0:c8673aa96267 1116 void spi_master_transfer_dma(spi_t *obj, const void *txdata, void *rxdata, int tx_length, int rx_length, void* cb, DMAUsage hint)
manhpham 0:c8673aa96267 1117 {
manhpham 0:c8673aa96267 1118 /* Init DMA here to include it in the power figure */
manhpham 0:c8673aa96267 1119 dma_init();
manhpham 0:c8673aa96267 1120 /* Clear TX and RX registers */
manhpham 0:c8673aa96267 1121 obj->spi.spi->CMD = USART_CMD_CLEARTX;
manhpham 0:c8673aa96267 1122 obj->spi.spi->CMD = USART_CMD_CLEARRX;
manhpham 0:c8673aa96267 1123 /* If the DMA channels are already allocated, we can assume they have been setup already */
manhpham 0:c8673aa96267 1124 if (hint != DMA_USAGE_NEVER && obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_ALLOCATED) {
manhpham 0:c8673aa96267 1125 /* setup has already been done, so just activate the transfer */
manhpham 0:c8673aa96267 1126 spi_activate_dma(obj, rxdata, txdata, tx_length, rx_length);
manhpham 0:c8673aa96267 1127 } else if (hint == DMA_USAGE_NEVER) {
manhpham 0:c8673aa96267 1128 /* use IRQ */
manhpham 0:c8673aa96267 1129 obj->spi.spi->IFC = 0xFFFFFFFF;
manhpham 0:c8673aa96267 1130 spi_master_write_asynch(obj);
manhpham 0:c8673aa96267 1131 spi_enable_interrupt(obj, (uint32_t)cb, true);
manhpham 0:c8673aa96267 1132 } else {
manhpham 0:c8673aa96267 1133 /* try to acquire channels */
manhpham 0:c8673aa96267 1134 dma_init();
manhpham 0:c8673aa96267 1135 spi_enable_dma(obj, hint);
manhpham 0:c8673aa96267 1136
manhpham 0:c8673aa96267 1137 /* decide between DMA and IRQ */
manhpham 0:c8673aa96267 1138 if (obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_ALLOCATED || obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) {
manhpham 0:c8673aa96267 1139 /* disable the interrupts that may have been left open previously */
manhpham 0:c8673aa96267 1140 spi_enable_interrupt(obj, (uint32_t)cb, false);
manhpham 0:c8673aa96267 1141
manhpham 0:c8673aa96267 1142 /* DMA channels are allocated, so do their setup */
manhpham 0:c8673aa96267 1143 spi_master_dma_channel_setup(obj, cb);
manhpham 0:c8673aa96267 1144 /* and activate the transfer */
manhpham 0:c8673aa96267 1145 spi_activate_dma(obj, rxdata, txdata, tx_length, rx_length);
manhpham 0:c8673aa96267 1146 } else {
manhpham 0:c8673aa96267 1147 /* DMA is unavailable, so fall back to IRQ */
manhpham 0:c8673aa96267 1148 obj->spi.spi->IFC = 0xFFFFFFFF;
manhpham 0:c8673aa96267 1149 spi_master_write_asynch(obj);
manhpham 0:c8673aa96267 1150 spi_enable_interrupt(obj, (uint32_t)cb, true);
manhpham 0:c8673aa96267 1151 }
manhpham 0:c8673aa96267 1152 }
manhpham 0:c8673aa96267 1153 }
manhpham 0:c8673aa96267 1154
manhpham 0:c8673aa96267 1155 /** Begin the SPI transfer. Buffer pointers and lengths are specified in tx_buff and rx_buff
manhpham 0:c8673aa96267 1156 *
manhpham 0:c8673aa96267 1157 * @param[in] obj The SPI object which holds the transfer information
manhpham 0:c8673aa96267 1158 * @param[in] tx The buffer to send
manhpham 0:c8673aa96267 1159 * @param[in] tx_length The number of words to transmit
manhpham 0:c8673aa96267 1160 * @param[in] rx The buffer to receive
manhpham 0:c8673aa96267 1161 * @param[in] rx_length The number of words to receive
manhpham 0:c8673aa96267 1162 * @param[in] bit_width The bit width of buffer words
manhpham 0:c8673aa96267 1163 * @param[in] event The logical OR of events to be registered
manhpham 0:c8673aa96267 1164 * @param[in] handler SPI interrupt handler
manhpham 0:c8673aa96267 1165 * @param[in] hint A suggestion for how to use DMA with this transfer
manhpham 0:c8673aa96267 1166 */
manhpham 0:c8673aa96267 1167 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)
manhpham 0:c8673aa96267 1168 {
manhpham 0:c8673aa96267 1169 if( spi_active(obj) ) return;
manhpham 0:c8673aa96267 1170
manhpham 0:c8673aa96267 1171 /* update fill word if on 9-bit frame size */
manhpham 0:c8673aa96267 1172 if(obj->spi.bits == 9) fill_word = SPI_FILL_WORD & 0x1FF;
manhpham 0:c8673aa96267 1173 else fill_word = SPI_FILL_WORD;
manhpham 0:c8673aa96267 1174
manhpham 0:c8673aa96267 1175 /* check corner case */
manhpham 0:c8673aa96267 1176 if(tx_length == 0) {
manhpham 0:c8673aa96267 1177 tx_length = rx_length;
manhpham 0:c8673aa96267 1178 tx = (void*) 0;
manhpham 0:c8673aa96267 1179 }
manhpham 0:c8673aa96267 1180
manhpham 0:c8673aa96267 1181 /* First, set the buffer */
manhpham 0:c8673aa96267 1182 spi_buffer_set(obj, tx, tx_length, rx, rx_length, bit_width);
manhpham 0:c8673aa96267 1183
manhpham 0:c8673aa96267 1184 /* Then, enable the events */
manhpham 0:c8673aa96267 1185 spi_enable_event(obj, SPI_EVENT_ALL, false);
manhpham 0:c8673aa96267 1186 spi_enable_event(obj, event, true);
manhpham 0:c8673aa96267 1187
manhpham 0:c8673aa96267 1188 // Set the sleep mode
manhpham 0:c8673aa96267 1189 sleep_manager_lock_deep_sleep();
manhpham 0:c8673aa96267 1190
manhpham 0:c8673aa96267 1191 /* And kick off the transfer */
manhpham 0:c8673aa96267 1192 spi_master_transfer_dma(obj, tx, rx, tx_length, rx_length, (void*)handler, hint);
manhpham 0:c8673aa96267 1193 }
manhpham 0:c8673aa96267 1194
manhpham 0:c8673aa96267 1195
manhpham 0:c8673aa96267 1196 /********************************************************************
manhpham 0:c8673aa96267 1197 * uint32_t spi_irq_handler_generic(spi_t* obj)
manhpham 0:c8673aa96267 1198 *
manhpham 0:c8673aa96267 1199 * handler which should get called by CPP-land when either a DMA or SPI IRQ gets fired for a SPI transaction.
manhpham 0:c8673aa96267 1200 *
manhpham 0:c8673aa96267 1201 * * obj: pointer to the specific SPI instance
manhpham 0:c8673aa96267 1202 *
manhpham 0:c8673aa96267 1203 * return: event mask. Currently only 0 or SPI_EVENT_COMPLETE upon transfer completion.
manhpham 0:c8673aa96267 1204 *
manhpham 0:c8673aa96267 1205 ********************************************************************/
manhpham 0:c8673aa96267 1206 #ifdef LDMA_PRESENT
manhpham 0:c8673aa96267 1207 uint32_t spi_irq_handler_asynch(spi_t* obj)
manhpham 0:c8673aa96267 1208 {
manhpham 0:c8673aa96267 1209 if (obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_ALLOCATED || obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) {
manhpham 0:c8673aa96267 1210 /* DMA implementation */
manhpham 0:c8673aa96267 1211 /* If there is still data in the TX buffer, setup a new transfer. */
manhpham 0:c8673aa96267 1212 if (obj->tx_buff.pos < obj->tx_buff.length) {
manhpham 0:c8673aa96267 1213 /* Find position and remaining length without modifying tx_buff. */
manhpham 0:c8673aa96267 1214 void* tx_pointer = (char*)obj->tx_buff.buffer + obj->tx_buff.pos;
manhpham 0:c8673aa96267 1215 uint32_t tx_length = obj->tx_buff.length - obj->tx_buff.pos;
manhpham 0:c8673aa96267 1216
manhpham 0:c8673aa96267 1217 /* Begin transfer. Rely on spi_activate_dma to split up the transfer further. */
manhpham 0:c8673aa96267 1218 spi_activate_dma(obj, obj->rx_buff.buffer, tx_pointer, tx_length, obj->rx_buff.length);
manhpham 0:c8673aa96267 1219
manhpham 0:c8673aa96267 1220 return 0;
manhpham 0:c8673aa96267 1221 }
manhpham 0:c8673aa96267 1222 /* If there is an RX transfer ongoing, wait for it to finish */
manhpham 0:c8673aa96267 1223 if (LDMAx_ChannelEnabled(obj->spi.dmaOptionsRX.dmaChannel)) {
manhpham 0:c8673aa96267 1224 /* Check if we need to kick off TX transfer again to force more incoming data. */
manhpham 0:c8673aa96267 1225 if (LDMA_TransferDone(obj->spi.dmaOptionsTX.dmaChannel) && (obj->tx_buff.pos < obj->rx_buff.length)) {
manhpham 0:c8673aa96267 1226 void* tx_pointer = (char*)obj->tx_buff.buffer + obj->tx_buff.pos;
manhpham 0:c8673aa96267 1227 uint32_t tx_length = obj->tx_buff.length - obj->tx_buff.pos;
manhpham 0:c8673aa96267 1228 /* Begin transfer. Rely on spi_activate_dma to split up the transfer further. */
manhpham 0:c8673aa96267 1229 spi_activate_dma(obj, obj->rx_buff.buffer, tx_pointer, tx_length, obj->rx_buff.length);
manhpham 0:c8673aa96267 1230 } else return 0;
manhpham 0:c8673aa96267 1231 }
manhpham 0:c8673aa96267 1232 /* If there is still a TX transfer ongoing (tx_length > rx_length), wait for it to finish */
manhpham 0:c8673aa96267 1233 if (!LDMA_TransferDone(obj->spi.dmaOptionsTX.dmaChannel)) {
manhpham 0:c8673aa96267 1234 return 0;
manhpham 0:c8673aa96267 1235 }
manhpham 0:c8673aa96267 1236 /* Release the dma channels if they were opportunistically allocated */
manhpham 0:c8673aa96267 1237 if (obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) {
manhpham 0:c8673aa96267 1238 dma_channel_free(obj->spi.dmaOptionsTX.dmaChannel);
manhpham 0:c8673aa96267 1239 dma_channel_free(obj->spi.dmaOptionsRX.dmaChannel);
manhpham 0:c8673aa96267 1240 obj->spi.dmaOptionsTX.dmaUsageState = DMA_USAGE_OPPORTUNISTIC;
manhpham 0:c8673aa96267 1241 }
manhpham 0:c8673aa96267 1242
manhpham 0:c8673aa96267 1243 /* Wait transmit to complete, before user code is indicated*/
manhpham 0:c8673aa96267 1244 while(!(obj->spi.spi->STATUS & USART_STATUS_TXC));
manhpham 0:c8673aa96267 1245 sleep_manager_unlock_deep_sleep();
manhpham 0:c8673aa96267 1246 /* return to CPP land to say we're finished */
manhpham 0:c8673aa96267 1247 return SPI_EVENT_COMPLETE;
manhpham 0:c8673aa96267 1248 } else {
manhpham 0:c8673aa96267 1249 /* IRQ implementation */
manhpham 0:c8673aa96267 1250 if (spi_master_rx_int_flag(obj)) {
manhpham 0:c8673aa96267 1251 spi_master_read_asynch(obj);
manhpham 0:c8673aa96267 1252 }
manhpham 0:c8673aa96267 1253
manhpham 0:c8673aa96267 1254 if (spi_master_tx_int_flag(obj)) {
manhpham 0:c8673aa96267 1255 spi_master_write_asynch(obj);
manhpham 0:c8673aa96267 1256 }
manhpham 0:c8673aa96267 1257
manhpham 0:c8673aa96267 1258 uint32_t event = spi_event_check(obj);
manhpham 0:c8673aa96267 1259 if (event & SPI_EVENT_INTERNAL_TRANSFER_COMPLETE) {
manhpham 0:c8673aa96267 1260 /* disable interrupts */
manhpham 0:c8673aa96267 1261 spi_enable_interrupt(obj, (uint32_t)NULL, false);
manhpham 0:c8673aa96267 1262
manhpham 0:c8673aa96267 1263 sleep_manager_unlock_deep_sleep();
manhpham 0:c8673aa96267 1264 /* Return the event back to userland */
manhpham 0:c8673aa96267 1265 return event;
manhpham 0:c8673aa96267 1266 }
manhpham 0:c8673aa96267 1267
manhpham 0:c8673aa96267 1268 return 0;
manhpham 0:c8673aa96267 1269 }
manhpham 0:c8673aa96267 1270 }
manhpham 0:c8673aa96267 1271 #else
manhpham 0:c8673aa96267 1272 uint32_t spi_irq_handler_asynch(spi_t* obj)
manhpham 0:c8673aa96267 1273 {
manhpham 0:c8673aa96267 1274
manhpham 0:c8673aa96267 1275 /* Determine whether the current scenario is DMA or IRQ, and act accordingly */
manhpham 0:c8673aa96267 1276
manhpham 0:c8673aa96267 1277 if (obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_ALLOCATED || obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) {
manhpham 0:c8673aa96267 1278 /* DMA implementation */
manhpham 0:c8673aa96267 1279
manhpham 0:c8673aa96267 1280 /* If there is still data in the TX buffer, setup a new transfer. */
manhpham 0:c8673aa96267 1281 if (obj->tx_buff.pos < obj->tx_buff.length) {
manhpham 0:c8673aa96267 1282 /* If there is still a TX transfer ongoing, let it finish
manhpham 0:c8673aa96267 1283 * before (if necessary) kicking off a new transfer */
manhpham 0:c8673aa96267 1284 if (DMA_ChannelEnabled(obj->spi.dmaOptionsTX.dmaChannel)) {
manhpham 0:c8673aa96267 1285 return 0;
manhpham 0:c8673aa96267 1286 }
manhpham 0:c8673aa96267 1287 /* Find position and remaining length without modifying tx_buff. */
manhpham 0:c8673aa96267 1288 void * tx_pointer;
manhpham 0:c8673aa96267 1289 if (obj->tx_buff.width == 32) {
manhpham 0:c8673aa96267 1290 tx_pointer = ((uint32_t *)obj->tx_buff.buffer) + obj->tx_buff.pos;
manhpham 0:c8673aa96267 1291 } else if (obj->tx_buff.width == 16) {
manhpham 0:c8673aa96267 1292 tx_pointer = ((uint16_t *)obj->tx_buff.buffer) + obj->tx_buff.pos;
manhpham 0:c8673aa96267 1293 } else {
manhpham 0:c8673aa96267 1294 tx_pointer = ((uint8_t *)obj->tx_buff.buffer) + obj->tx_buff.pos;
manhpham 0:c8673aa96267 1295 }
manhpham 0:c8673aa96267 1296 uint32_t tx_length = obj->tx_buff.length - obj->tx_buff.pos;
manhpham 0:c8673aa96267 1297
manhpham 0:c8673aa96267 1298 /* Refresh RX transfer too if it exists */
manhpham 0:c8673aa96267 1299 void * rx_pointer = NULL;
manhpham 0:c8673aa96267 1300 if (obj->rx_buff.pos < obj->rx_buff.length) {
manhpham 0:c8673aa96267 1301 if (obj->rx_buff.width == 32) {
manhpham 0:c8673aa96267 1302 rx_pointer = ((uint32_t *)obj->rx_buff.buffer) + obj->rx_buff.pos;
manhpham 0:c8673aa96267 1303 } else if (obj->rx_buff.width == 16) {
manhpham 0:c8673aa96267 1304 rx_pointer = ((uint16_t *)obj->rx_buff.buffer) + obj->rx_buff.pos;
manhpham 0:c8673aa96267 1305 } else {
manhpham 0:c8673aa96267 1306 rx_pointer = ((uint8_t *)obj->rx_buff.buffer) + obj->rx_buff.pos;
manhpham 0:c8673aa96267 1307 }
manhpham 0:c8673aa96267 1308 }
manhpham 0:c8673aa96267 1309 uint32_t rx_length = obj->rx_buff.length - obj->rx_buff.pos;
manhpham 0:c8673aa96267 1310
manhpham 0:c8673aa96267 1311 /* Wait for the previous transfer to complete. */
manhpham 0:c8673aa96267 1312 while(!(obj->spi.spi->STATUS & USART_STATUS_TXC));
manhpham 0:c8673aa96267 1313
manhpham 0:c8673aa96267 1314 /* Begin transfer. Rely on spi_activate_dma to split up the transfer further. */
manhpham 0:c8673aa96267 1315 spi_activate_dma(obj, rx_pointer, tx_pointer, tx_length, rx_length);
manhpham 0:c8673aa96267 1316
manhpham 0:c8673aa96267 1317 return 0;
manhpham 0:c8673aa96267 1318 }
manhpham 0:c8673aa96267 1319
manhpham 0:c8673aa96267 1320 /* If an RX transfer is ongoing, continue processing RX data */
manhpham 0:c8673aa96267 1321 if (DMA_ChannelEnabled(obj->spi.dmaOptionsRX.dmaChannel)) {
manhpham 0:c8673aa96267 1322 /* Check if we need to kick off TX transfer again to force more incoming data. */
manhpham 0:c8673aa96267 1323 if (!DMA_ChannelEnabled(obj->spi.dmaOptionsTX.dmaChannel) && (obj->rx_buff.pos < obj->rx_buff.length)) {
manhpham 0:c8673aa96267 1324 //Save state of TX transfer amount
manhpham 0:c8673aa96267 1325 int length_diff = obj->rx_buff.length - obj->rx_buff.pos;
manhpham 0:c8673aa96267 1326 obj->tx_buff.pos = obj->rx_buff.length;
manhpham 0:c8673aa96267 1327
manhpham 0:c8673aa96267 1328 //Kick off a new DMA transfer
manhpham 0:c8673aa96267 1329 DMA_CfgDescr_TypeDef txDescrCfg;
manhpham 0:c8673aa96267 1330
manhpham 0:c8673aa96267 1331 fill_word = SPI_FILL_WORD;
manhpham 0:c8673aa96267 1332 /* Setting up channel descriptor */
manhpham 0:c8673aa96267 1333 txDescrCfg.dstInc = dmaDataIncNone;
manhpham 0:c8673aa96267 1334 txDescrCfg.srcInc = dmaDataIncNone; //Do not increment source pointer when there is no transmit buffer
manhpham 0:c8673aa96267 1335 txDescrCfg.size = (obj->spi.bits <= 8 ? dmaDataSize1 : dmaDataSize2); //When frame size > 9, we can use TXDOUBLE to save bandwidth
manhpham 0:c8673aa96267 1336 txDescrCfg.arbRate = dmaArbitrate1;
manhpham 0:c8673aa96267 1337 txDescrCfg.hprot = 0;
manhpham 0:c8673aa96267 1338 DMA_CfgDescr(obj->spi.dmaOptionsTX.dmaChannel, true, &txDescrCfg);
manhpham 0:c8673aa96267 1339
manhpham 0:c8673aa96267 1340 void * tx_reg;
manhpham 0:c8673aa96267 1341 if (obj->spi.bits > 9) {
manhpham 0:c8673aa96267 1342 tx_reg = (void *)&obj->spi.spi->TXDOUBLE;
manhpham 0:c8673aa96267 1343 } else if (obj->spi.bits == 9) {
manhpham 0:c8673aa96267 1344 tx_reg = (void *)&obj->spi.spi->TXDATAX;
manhpham 0:c8673aa96267 1345 } else {
manhpham 0:c8673aa96267 1346 tx_reg = (void *)&obj->spi.spi->TXDATA;
manhpham 0:c8673aa96267 1347 }
manhpham 0:c8673aa96267 1348
manhpham 0:c8673aa96267 1349 /* Activate TX channel */
manhpham 0:c8673aa96267 1350 DMA_ActivateBasic(obj->spi.dmaOptionsTX.dmaChannel,
manhpham 0:c8673aa96267 1351 true,
manhpham 0:c8673aa96267 1352 false,
manhpham 0:c8673aa96267 1353 tx_reg, //When frame size > 9, point to TXDOUBLE
manhpham 0:c8673aa96267 1354 &fill_word, // When there is nothing to transmit, point to static fill word
manhpham 0:c8673aa96267 1355 length_diff - 1);
manhpham 0:c8673aa96267 1356 } else {
manhpham 0:c8673aa96267 1357 /* Nothing to do */
manhpham 0:c8673aa96267 1358 return 0;
manhpham 0:c8673aa96267 1359 }
manhpham 0:c8673aa96267 1360 }
manhpham 0:c8673aa96267 1361
manhpham 0:c8673aa96267 1362 /* Release the dma channels if they were opportunistically allocated */
manhpham 0:c8673aa96267 1363 if (obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) {
manhpham 0:c8673aa96267 1364 dma_channel_free(obj->spi.dmaOptionsTX.dmaChannel);
manhpham 0:c8673aa96267 1365 dma_channel_free(obj->spi.dmaOptionsRX.dmaChannel);
manhpham 0:c8673aa96267 1366 obj->spi.dmaOptionsTX.dmaUsageState = DMA_USAGE_OPPORTUNISTIC;
manhpham 0:c8673aa96267 1367 }
manhpham 0:c8673aa96267 1368
manhpham 0:c8673aa96267 1369 /* Wait for transmit to complete, before user code is indicated */
manhpham 0:c8673aa96267 1370 while(!(obj->spi.spi->STATUS & USART_STATUS_TXC));
manhpham 0:c8673aa96267 1371 sleep_manager_unlock_deep_sleep();
manhpham 0:c8673aa96267 1372
manhpham 0:c8673aa96267 1373 /* return to CPP land to say we're finished */
manhpham 0:c8673aa96267 1374 return SPI_EVENT_COMPLETE;
manhpham 0:c8673aa96267 1375 } else {
manhpham 0:c8673aa96267 1376 /* IRQ implementation */
manhpham 0:c8673aa96267 1377 if (spi_master_rx_int_flag(obj)) {
manhpham 0:c8673aa96267 1378 spi_master_read_asynch(obj);
manhpham 0:c8673aa96267 1379 }
manhpham 0:c8673aa96267 1380
manhpham 0:c8673aa96267 1381 if (spi_master_tx_int_flag(obj)) {
manhpham 0:c8673aa96267 1382 spi_master_write_asynch(obj);
manhpham 0:c8673aa96267 1383 }
manhpham 0:c8673aa96267 1384
manhpham 0:c8673aa96267 1385 uint32_t event = spi_event_check(obj);
manhpham 0:c8673aa96267 1386 if (event & SPI_EVENT_INTERNAL_TRANSFER_COMPLETE) {
manhpham 0:c8673aa96267 1387 /* disable interrupts */
manhpham 0:c8673aa96267 1388 spi_enable_interrupt(obj, (uint32_t)NULL, false);
manhpham 0:c8673aa96267 1389
manhpham 0:c8673aa96267 1390 /* Wait for transmit to complete, before user code is indicated */
manhpham 0:c8673aa96267 1391 while(!(obj->spi.spi->STATUS & USART_STATUS_TXC));
manhpham 0:c8673aa96267 1392 sleep_manager_unlock_deep_sleep();
manhpham 0:c8673aa96267 1393
manhpham 0:c8673aa96267 1394 /* Return the event back to userland */
manhpham 0:c8673aa96267 1395 return event;
manhpham 0:c8673aa96267 1396 }
manhpham 0:c8673aa96267 1397
manhpham 0:c8673aa96267 1398 return 0;
manhpham 0:c8673aa96267 1399 }
manhpham 0:c8673aa96267 1400 }
manhpham 0:c8673aa96267 1401 #endif // LDMA_PRESENT
manhpham 0:c8673aa96267 1402 /** Abort an SPI transfer
manhpham 0:c8673aa96267 1403 *
manhpham 0:c8673aa96267 1404 * @param obj The SPI peripheral to stop
manhpham 0:c8673aa96267 1405 */
manhpham 0:c8673aa96267 1406 void spi_abort_asynch(spi_t *obj)
manhpham 0:c8673aa96267 1407 {
manhpham 0:c8673aa96267 1408 // If we're not currently transferring, then there's nothing to do here
manhpham 0:c8673aa96267 1409 if(spi_active(obj) != 0) return;
manhpham 0:c8673aa96267 1410
manhpham 0:c8673aa96267 1411 // Determine whether we're running DMA or interrupt
manhpham 0:c8673aa96267 1412 if (obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_ALLOCATED || obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) {
manhpham 0:c8673aa96267 1413 // Cancel the DMA transfers
manhpham 0:c8673aa96267 1414 #ifdef LDMA_PRESENT
manhpham 0:c8673aa96267 1415 LDMA_StopTransfer(obj->spi.dmaOptionsTX.dmaChannel);
manhpham 0:c8673aa96267 1416 LDMA_StopTransfer(obj->spi.dmaOptionsRX.dmaChannel);
manhpham 0:c8673aa96267 1417 #else
manhpham 0:c8673aa96267 1418 DMA_ChannelEnable(obj->spi.dmaOptionsTX.dmaChannel, false);
manhpham 0:c8673aa96267 1419 DMA_ChannelEnable(obj->spi.dmaOptionsRX.dmaChannel, false);
manhpham 0:c8673aa96267 1420 #endif
manhpham 0:c8673aa96267 1421 /* Release the dma channels if they were opportunistically allocated */
manhpham 0:c8673aa96267 1422 if (obj->spi.dmaOptionsTX.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) {
manhpham 0:c8673aa96267 1423 dma_channel_free(obj->spi.dmaOptionsTX.dmaChannel);
manhpham 0:c8673aa96267 1424 dma_channel_free(obj->spi.dmaOptionsRX.dmaChannel);
manhpham 0:c8673aa96267 1425 obj->spi.dmaOptionsTX.dmaUsageState = DMA_USAGE_OPPORTUNISTIC;
manhpham 0:c8673aa96267 1426 }
manhpham 0:c8673aa96267 1427
manhpham 0:c8673aa96267 1428 } else {
manhpham 0:c8673aa96267 1429 // Interrupt implementation: switch off interrupts
manhpham 0:c8673aa96267 1430 spi_enable_interrupt(obj, (uint32_t)NULL, false);
manhpham 0:c8673aa96267 1431 }
manhpham 0:c8673aa96267 1432
manhpham 0:c8673aa96267 1433 // Release sleep mode block
manhpham 0:c8673aa96267 1434 sleep_manager_unlock_deep_sleep();
manhpham 0:c8673aa96267 1435 }
manhpham 0:c8673aa96267 1436
manhpham 0:c8673aa96267 1437 #endif