mbed library sources

Fork of mbed-src by mbed official

Committer:
mbed_official
Date:
Fri Jul 17 09:15:10 2015 +0100
Revision:
592:a274ee790e56
Parent:
579:53297373a894
Synchronized with git revision e7144f83a8d75df80c4877936b6ffe552b0be9e6

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

More API implementation for SAMR21

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mbed_official 579:53297373a894 1 /* mbed Microcontroller Library
mbed_official 579:53297373a894 2 * Copyright (c) 2006-2013 ARM Limited
mbed_official 579:53297373a894 3 *
mbed_official 579:53297373a894 4 * Licensed under the Apache License, Version 2.0 (the "License");
mbed_official 579:53297373a894 5 * you may not use this file except in compliance with the License.
mbed_official 579:53297373a894 6 * You may obtain a copy of the License at
mbed_official 579:53297373a894 7 *
mbed_official 579:53297373a894 8 * http://www.apache.org/licenses/LICENSE-2.0
mbed_official 579:53297373a894 9 *
mbed_official 579:53297373a894 10 * Unless required by applicable law or agreed to in writing, software
mbed_official 579:53297373a894 11 * distributed under the License is distributed on an "AS IS" BASIS,
mbed_official 579:53297373a894 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
mbed_official 579:53297373a894 13 * See the License for the specific language governing permissions and
mbed_official 579:53297373a894 14 * limitations under the License.
mbed_official 579:53297373a894 15 */
mbed_official 579:53297373a894 16 #include "mbed_assert.h"
mbed_official 579:53297373a894 17 #include "spi_api.h"
mbed_official 579:53297373a894 18
mbed_official 579:53297373a894 19 #include <math.h>
mbed_official 579:53297373a894 20
mbed_official 579:53297373a894 21 #include "cmsis.h"
mbed_official 579:53297373a894 22 #include "pinmap.h"
mbed_official 579:53297373a894 23 #include "sercom.h"
mbed_official 579:53297373a894 24
mbed_official 592:a274ee790e56 25 #include "pinmap_function.h"
mbed_official 579:53297373a894 26
mbed_official 592:a274ee790e56 27 #define SPI_MOSI_INDEX 0
mbed_official 592:a274ee790e56 28 #define SPI_MISO_INDEX 1
mbed_official 592:a274ee790e56 29 #define SPI_SCLK_INDEX 2
mbed_official 592:a274ee790e56 30 #define SPI_SSEL_INDEX 3
mbed_official 579:53297373a894 31
mbed_official 579:53297373a894 32 /**
mbed_official 579:53297373a894 33 * \brief SPI modes enum
mbed_official 579:53297373a894 34 *
mbed_official 579:53297373a894 35 * SPI mode selection.
mbed_official 579:53297373a894 36 */
mbed_official 579:53297373a894 37 enum spi_mode {
mbed_official 579:53297373a894 38 /** Master mode. */
mbed_official 579:53297373a894 39 SPI_MODE_MASTER = 1,
mbed_official 579:53297373a894 40 /** Slave mode. */
mbed_official 579:53297373a894 41 SPI_MODE_SLAVE = 0,
mbed_official 579:53297373a894 42 };
mbed_official 579:53297373a894 43
mbed_official 579:53297373a894 44 #if DEVICE_SPI_ASYNCH
mbed_official 579:53297373a894 45 #define pSPI_S(obj) (&obj->spi)
mbed_official 579:53297373a894 46 #define pSPI_SERCOM(obj) obj->spi.spi
mbed_official 579:53297373a894 47 #else
mbed_official 579:53297373a894 48 #define pSPI_S(obj) (obj)
mbed_official 579:53297373a894 49 #define pSPI_SERCOM(obj) (obj->spi)
mbed_official 579:53297373a894 50 #endif
mbed_official 579:53297373a894 51 #define _SPI(obj) pSPI_SERCOM(obj)->SPI
mbed_official 579:53297373a894 52
mbed_official 579:53297373a894 53 /** SPI default baud rate. */
mbed_official 579:53297373a894 54 #define SPI_DEFAULT_BAUD 50000//100000
mbed_official 579:53297373a894 55
mbed_official 579:53297373a894 56
mbed_official 579:53297373a894 57 /** SPI timeout value. */
mbed_official 579:53297373a894 58 # define SPI_TIMEOUT 10000
mbed_official 579:53297373a894 59
mbed_official 579:53297373a894 60 extern uint8_t g_sys_init;
mbed_official 579:53297373a894 61 uint16_t dummy_fill_word = 0xFFFF;
mbed_official 579:53297373a894 62
mbed_official 579:53297373a894 63
mbed_official 579:53297373a894 64 static inline bool spi_is_syncing(spi_t *obj)
mbed_official 579:53297373a894 65 {
mbed_official 579:53297373a894 66 /* Sanity check arguments */
mbed_official 579:53297373a894 67 MBED_ASSERT(obj);
mbed_official 579:53297373a894 68
mbed_official 579:53297373a894 69 /* Return synchronization status */
mbed_official 579:53297373a894 70 return (_SPI(obj).SYNCBUSY.reg);
mbed_official 579:53297373a894 71 }
mbed_official 579:53297373a894 72
mbed_official 579:53297373a894 73 static inline void spi_enable(spi_t *obj)
mbed_official 579:53297373a894 74 {
mbed_official 579:53297373a894 75 /* Sanity check arguments */
mbed_official 579:53297373a894 76 MBED_ASSERT(obj);
mbed_official 579:53297373a894 77
mbed_official 579:53297373a894 78 /* Wait until the synchronization is complete */
mbed_official 579:53297373a894 79 while (spi_is_syncing(obj));
mbed_official 579:53297373a894 80
mbed_official 579:53297373a894 81 /* Enable SPI */
mbed_official 579:53297373a894 82 _SPI(obj).CTRLA.reg |= SERCOM_SPI_CTRLA_ENABLE;
mbed_official 579:53297373a894 83 }
mbed_official 579:53297373a894 84
mbed_official 579:53297373a894 85 static inline void spi_disable(spi_t *obj)
mbed_official 579:53297373a894 86 {
mbed_official 579:53297373a894 87 /* Sanity check arguments */
mbed_official 579:53297373a894 88 MBED_ASSERT(obj);
mbed_official 579:53297373a894 89
mbed_official 579:53297373a894 90 /* Wait until the synchronization is complete */
mbed_official 579:53297373a894 91 while (spi_is_syncing(obj));
mbed_official 579:53297373a894 92
mbed_official 579:53297373a894 93 /* Disable SPI */
mbed_official 579:53297373a894 94 _SPI(obj).CTRLA.reg &= ~SERCOM_SPI_CTRLA_ENABLE;
mbed_official 579:53297373a894 95 }
mbed_official 579:53297373a894 96
mbed_official 579:53297373a894 97 static inline bool spi_is_write_complete(spi_t *obj)
mbed_official 579:53297373a894 98 {
mbed_official 579:53297373a894 99 /* Sanity check arguments */
mbed_official 579:53297373a894 100 MBED_ASSERT(obj);
mbed_official 579:53297373a894 101
mbed_official 579:53297373a894 102 /* Check interrupt flag */
mbed_official 579:53297373a894 103 return (_SPI(obj).INTFLAG.reg & SERCOM_SPI_INTFLAG_TXC);
mbed_official 579:53297373a894 104 }
mbed_official 579:53297373a894 105
mbed_official 579:53297373a894 106 static inline bool spi_is_ready_to_write(spi_t *obj)
mbed_official 579:53297373a894 107 {
mbed_official 579:53297373a894 108 /* Sanity check arguments */
mbed_official 579:53297373a894 109 MBED_ASSERT(obj);
mbed_official 579:53297373a894 110
mbed_official 579:53297373a894 111 /* Check interrupt flag */
mbed_official 579:53297373a894 112 return (_SPI(obj).INTFLAG.reg & SERCOM_SPI_INTFLAG_DRE);
mbed_official 579:53297373a894 113 }
mbed_official 579:53297373a894 114
mbed_official 579:53297373a894 115 static inline bool spi_is_ready_to_read(spi_t *obj)
mbed_official 579:53297373a894 116 {
mbed_official 579:53297373a894 117 /* Sanity check arguments */
mbed_official 579:53297373a894 118 MBED_ASSERT(obj);
mbed_official 579:53297373a894 119
mbed_official 579:53297373a894 120 /* Check interrupt flag */
mbed_official 579:53297373a894 121 return (_SPI(obj).INTFLAG.reg & SERCOM_SPI_INTFLAG_RXC);
mbed_official 579:53297373a894 122 }
mbed_official 579:53297373a894 123
mbed_official 579:53297373a894 124 static inline bool spi_write(spi_t *obj, uint16_t tx_data)
mbed_official 579:53297373a894 125 {
mbed_official 579:53297373a894 126 /* Sanity check arguments */
mbed_official 579:53297373a894 127 MBED_ASSERT(obj);
mbed_official 579:53297373a894 128
mbed_official 579:53297373a894 129 /* Check if the data register has been copied to the shift register */
mbed_official 579:53297373a894 130 if (!spi_is_ready_to_write(obj)) {
mbed_official 579:53297373a894 131 /* Data register has not been copied to the shift register, return */
mbed_official 579:53297373a894 132 return false;
mbed_official 579:53297373a894 133 }
mbed_official 579:53297373a894 134
mbed_official 579:53297373a894 135 /* Write the character to the DATA register */
mbed_official 579:53297373a894 136 _SPI(obj).DATA.reg = tx_data & SERCOM_SPI_DATA_MASK;
mbed_official 579:53297373a894 137
mbed_official 579:53297373a894 138 return true;
mbed_official 579:53297373a894 139 }
mbed_official 579:53297373a894 140
mbed_official 579:53297373a894 141 static inline bool spi_read(spi_t *obj, uint16_t *rx_data)
mbed_official 579:53297373a894 142 {
mbed_official 579:53297373a894 143 /* Sanity check arguments */
mbed_official 579:53297373a894 144 MBED_ASSERT(obj);
mbed_official 579:53297373a894 145
mbed_official 579:53297373a894 146 /* Check if data is ready to be read */
mbed_official 579:53297373a894 147 if (!spi_is_ready_to_read(obj)) {
mbed_official 579:53297373a894 148 /* No data has been received, return */
mbed_official 579:53297373a894 149 return false;
mbed_official 579:53297373a894 150 }
mbed_official 579:53297373a894 151
mbed_official 579:53297373a894 152 /* Check if data is overflown */
mbed_official 579:53297373a894 153 if (_SPI(obj).STATUS.reg & SERCOM_SPI_STATUS_BUFOVF) {
mbed_official 579:53297373a894 154 /* Clear overflow flag */
mbed_official 579:53297373a894 155 _SPI(obj).STATUS.reg |= SERCOM_SPI_STATUS_BUFOVF;
mbed_official 579:53297373a894 156 }
mbed_official 579:53297373a894 157
mbed_official 579:53297373a894 158 /* Read the character from the DATA register */
mbed_official 579:53297373a894 159 if (_SPI(obj).CTRLB.bit.CHSIZE == 1) {
mbed_official 579:53297373a894 160 *rx_data = (_SPI(obj).DATA.reg & SERCOM_SPI_DATA_MASK);
mbed_official 579:53297373a894 161 } else {
mbed_official 579:53297373a894 162 *rx_data = (uint8_t)_SPI(obj).DATA.reg;
mbed_official 579:53297373a894 163 }
mbed_official 579:53297373a894 164
mbed_official 579:53297373a894 165 return true;
mbed_official 579:53297373a894 166 }
mbed_official 579:53297373a894 167
mbed_official 592:a274ee790e56 168 static uint32_t spi_find_mux_settings(spi_t *obj)
mbed_official 592:a274ee790e56 169 {
mbed_official 592:a274ee790e56 170 /* Sanity check arguments */
mbed_official 592:a274ee790e56 171 MBED_ASSERT(obj);
mbed_official 592:a274ee790e56 172 uint8_t i_dipo;
mbed_official 592:a274ee790e56 173 uint8_t i_dopo;
mbed_official 592:a274ee790e56 174 uint32_t dipo = 0;
mbed_official 592:a274ee790e56 175 uint32_t dopo = 0;
mbed_official 592:a274ee790e56 176 uint32_t mux_pad;
mbed_official 592:a274ee790e56 177
mbed_official 592:a274ee790e56 178 uint32_t mux_settings = 0;
mbed_official 592:a274ee790e56 179
mbed_official 592:a274ee790e56 180 uint32_t sercom_index = _sercom_get_sercom_inst_index(pSPI_SERCOM(obj));
mbed_official 592:a274ee790e56 181
mbed_official 592:a274ee790e56 182 if (pSPI_S(obj)->mode == SPI_MODE_MASTER) {
mbed_official 592:a274ee790e56 183 i_dipo = SPI_MISO_INDEX;
mbed_official 592:a274ee790e56 184 i_dopo = SPI_MOSI_INDEX;
mbed_official 592:a274ee790e56 185 } else {
mbed_official 592:a274ee790e56 186 i_dipo = SPI_MOSI_INDEX;
mbed_official 592:a274ee790e56 187 i_dopo = SPI_MISO_INDEX;
mbed_official 592:a274ee790e56 188 }
mbed_official 592:a274ee790e56 189
mbed_official 592:a274ee790e56 190 /* Find MUX setting */
mbed_official 592:a274ee790e56 191 if (pSPI_S(obj)->pins[i_dipo] != NC) {
mbed_official 592:a274ee790e56 192 /* Set Data input MUX padding for master */
mbed_official 592:a274ee790e56 193 mux_pad = pinmap_pad_sercom(pSPI_S(obj)->pins[i_dipo], sercom_index);
mbed_official 592:a274ee790e56 194 if (mux_pad != NC) {
mbed_official 592:a274ee790e56 195 /* MUX pad value is same as DIPO value */
mbed_official 592:a274ee790e56 196 dipo = mux_pad;
mbed_official 592:a274ee790e56 197 mux_settings |= ((dipo << SERCOM_SPI_CTRLA_DIPO_Pos) & SERCOM_SPI_CTRLA_DIPO_Msk);
mbed_official 592:a274ee790e56 198 }
mbed_official 592:a274ee790e56 199 }
mbed_official 592:a274ee790e56 200
mbed_official 592:a274ee790e56 201 if (pSPI_S(obj)->pins[i_dopo] != NC) {
mbed_official 592:a274ee790e56 202 /* Set Data output MUX padding for master */
mbed_official 592:a274ee790e56 203 mux_pad = pinmap_pad_sercom(pSPI_S(obj)->pins[i_dopo], sercom_index);
mbed_official 592:a274ee790e56 204 if (mux_pad != NC) {
mbed_official 592:a274ee790e56 205 if (mux_pad != 0) {
mbed_official 592:a274ee790e56 206 dopo = mux_pad - 1;
mbed_official 592:a274ee790e56 207 } else {
mbed_official 592:a274ee790e56 208 if (3 == pinmap_pad_sercom(pSPI_S(obj)->pins[SPI_SCLK_INDEX], sercom_index)) {
mbed_official 592:a274ee790e56 209 dopo = 3;
mbed_official 592:a274ee790e56 210 } else {
mbed_official 592:a274ee790e56 211 dopo = 0;
mbed_official 592:a274ee790e56 212 }
mbed_official 592:a274ee790e56 213 }
mbed_official 592:a274ee790e56 214 mux_settings |= ((dopo << SERCOM_SPI_CTRLA_DOPO_Pos) & SERCOM_SPI_CTRLA_DOPO_Msk);
mbed_official 592:a274ee790e56 215 }
mbed_official 592:a274ee790e56 216 }
mbed_official 592:a274ee790e56 217
mbed_official 592:a274ee790e56 218 return mux_settings;
mbed_official 592:a274ee790e56 219 }
mbed_official 592:a274ee790e56 220
mbed_official 579:53297373a894 221 /**
mbed_official 579:53297373a894 222 * \defgroup GeneralSPI SPI Configuration Functions
mbed_official 579:53297373a894 223 * @{
mbed_official 579:53297373a894 224 */
mbed_official 579:53297373a894 225
mbed_official 579:53297373a894 226 /** Initialize the SPI peripheral
mbed_official 579:53297373a894 227 *
mbed_official 579:53297373a894 228 * Configures the pins used by SPI, sets a default format and frequency, and enables the peripheral
mbed_official 579:53297373a894 229 * @param[out] obj The SPI object to initialize
mbed_official 579:53297373a894 230 * @param[in] mosi The pin to use for MOSI
mbed_official 579:53297373a894 231 * @param[in] miso The pin to use for MISO
mbed_official 579:53297373a894 232 * @param[in] sclk The pin to use for SCLK
mbed_official 579:53297373a894 233 * @param[in] ssel The pin to use for SSEL
mbed_official 579:53297373a894 234 */
mbed_official 579:53297373a894 235 void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel)
mbed_official 579:53297373a894 236 {
mbed_official 592:a274ee790e56 237 /* Sanity check arguments */
mbed_official 592:a274ee790e56 238 MBED_ASSERT(obj);
mbed_official 592:a274ee790e56 239 MBED_ASSERT(sclk != NC);
mbed_official 592:a274ee790e56 240
mbed_official 579:53297373a894 241 uint16_t baud = 0;
mbed_official 579:53297373a894 242 uint32_t ctrla = 0;
mbed_official 579:53297373a894 243 uint32_t ctrlb = 0;
mbed_official 579:53297373a894 244 enum status_code error_code;
mbed_official 579:53297373a894 245
mbed_official 579:53297373a894 246 if (g_sys_init == 0) {
mbed_official 579:53297373a894 247 system_init();
mbed_official 579:53297373a894 248 g_sys_init = 1;
mbed_official 579:53297373a894 249 }
mbed_official 579:53297373a894 250
mbed_official 592:a274ee790e56 251 /* Calculate SERCOM instance from pins */
mbed_official 592:a274ee790e56 252 uint32_t sercom_index = pinmap_find_sercom(mosi, miso, sclk, ssel);
mbed_official 592:a274ee790e56 253 pSPI_SERCOM(obj) = (Sercom*)pinmap_peripheral_sercom(NC, sercom_index);
mbed_official 579:53297373a894 254
mbed_official 579:53297373a894 255 /* Disable SPI */
mbed_official 579:53297373a894 256 spi_disable(obj);
mbed_official 579:53297373a894 257
mbed_official 579:53297373a894 258 /* Check if reset is in progress. */
mbed_official 579:53297373a894 259 if (_SPI(obj).CTRLA.reg & SERCOM_SPI_CTRLA_SWRST) {
mbed_official 579:53297373a894 260 return;
mbed_official 579:53297373a894 261 }
mbed_official 592:a274ee790e56 262
mbed_official 579:53297373a894 263 uint32_t pm_index, gclk_index;
mbed_official 579:53297373a894 264 #if (SAML21)
mbed_official 579:53297373a894 265 if (sercom_index == 5) {
mbed_official 579:53297373a894 266 pm_index = MCLK_APBDMASK_SERCOM5_Pos;
mbed_official 579:53297373a894 267 gclk_index = SERCOM5_GCLK_ID_CORE;
mbed_official 579:53297373a894 268 } else {
mbed_official 579:53297373a894 269 pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos;
mbed_official 579:53297373a894 270 gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
mbed_official 579:53297373a894 271 }
mbed_official 579:53297373a894 272 #else
mbed_official 579:53297373a894 273 pm_index = sercom_index + PM_APBCMASK_SERCOM0_Pos;
mbed_official 579:53297373a894 274 gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
mbed_official 579:53297373a894 275 #endif
mbed_official 579:53297373a894 276
mbed_official 579:53297373a894 277 /* Turn on module in PM */
mbed_official 579:53297373a894 278 #if (SAML21)
mbed_official 579:53297373a894 279 if (sercom_index == 5) {
mbed_official 579:53297373a894 280 system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBD, 1 << pm_index);
mbed_official 579:53297373a894 281 } else {
mbed_official 579:53297373a894 282 system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index);
mbed_official 579:53297373a894 283 }
mbed_official 579:53297373a894 284 #else
mbed_official 579:53297373a894 285 system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index);
mbed_official 579:53297373a894 286 #endif
mbed_official 579:53297373a894 287
mbed_official 579:53297373a894 288 /* Set up the GCLK for the module */
mbed_official 579:53297373a894 289 struct system_gclk_chan_config gclk_chan_conf;
mbed_official 579:53297373a894 290 system_gclk_chan_get_config_defaults(&gclk_chan_conf);
mbed_official 579:53297373a894 291 gclk_chan_conf.source_generator = GCLK_GENERATOR_0;
mbed_official 579:53297373a894 292 system_gclk_chan_set_config(gclk_index, &gclk_chan_conf);
mbed_official 579:53297373a894 293 system_gclk_chan_enable(gclk_index);
mbed_official 579:53297373a894 294 sercom_set_gclk_generator(GCLK_GENERATOR_0, false);
mbed_official 579:53297373a894 295
mbed_official 579:53297373a894 296 /* Set the SERCOM in SPI master mode */
mbed_official 579:53297373a894 297 _SPI(obj).CTRLA.reg |= SERCOM_SPI_CTRLA_MODE(0x3);
mbed_official 579:53297373a894 298 pSPI_S(obj)->mode = SPI_MODE_MASTER;
mbed_official 579:53297373a894 299
mbed_official 579:53297373a894 300 /* TODO: Do pin muxing here */
mbed_official 579:53297373a894 301 struct system_pinmux_config pin_conf;
mbed_official 579:53297373a894 302 system_pinmux_get_config_defaults(&pin_conf);
mbed_official 579:53297373a894 303 pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT;
mbed_official 579:53297373a894 304
mbed_official 592:a274ee790e56 305 pSPI_S(obj)->pins[SPI_MOSI_INDEX] = mosi;
mbed_official 592:a274ee790e56 306 pSPI_S(obj)->pins[SPI_MISO_INDEX] = miso;
mbed_official 592:a274ee790e56 307 pSPI_S(obj)->pins[SPI_SCLK_INDEX] = sclk;
mbed_official 592:a274ee790e56 308 pSPI_S(obj)->pins[SPI_SSEL_INDEX] = ssel;
mbed_official 579:53297373a894 309 /* Configure the SERCOM pins according to the user configuration */
mbed_official 579:53297373a894 310 for (uint8_t pad = 0; pad < 4; pad++) {
mbed_official 592:a274ee790e56 311 uint32_t current_pin = pSPI_S(obj)->pins[pad];
mbed_official 592:a274ee790e56 312 if (current_pin != NC) {
mbed_official 592:a274ee790e56 313 pin_conf.mux_position = pinmap_function_sercom(current_pin, sercom_index);
mbed_official 592:a274ee790e56 314 if ((uint8_t)NC != pin_conf.mux_position) {
mbed_official 592:a274ee790e56 315 system_pinmux_pin_set_config(current_pin, &pin_conf);
mbed_official 592:a274ee790e56 316 }
mbed_official 579:53297373a894 317 }
mbed_official 579:53297373a894 318 }
mbed_official 579:53297373a894 319
mbed_official 579:53297373a894 320 /* Get baud value, based on baudrate and the internal clock frequency */
mbed_official 579:53297373a894 321 uint32_t internal_clock = system_gclk_chan_get_hz(gclk_index);
mbed_official 579:53297373a894 322 //internal_clock = 8000000;
mbed_official 579:53297373a894 323 error_code = _sercom_get_sync_baud_val(SPI_DEFAULT_BAUD, internal_clock, &baud);
mbed_official 579:53297373a894 324 if (error_code != STATUS_OK) {
mbed_official 579:53297373a894 325 /* Baud rate calculation error */
mbed_official 579:53297373a894 326 return;
mbed_official 579:53297373a894 327 }
mbed_official 579:53297373a894 328 _SPI(obj).BAUD.reg = (uint8_t)baud;
mbed_official 579:53297373a894 329
mbed_official 592:a274ee790e56 330 /* TODO: Find MUX settings */
mbed_official 592:a274ee790e56 331 ctrla |= spi_find_mux_settings(obj);
mbed_official 579:53297373a894 332
mbed_official 579:53297373a894 333 /* Set SPI character size */
mbed_official 579:53297373a894 334 ctrlb |= SERCOM_SPI_CTRLB_CHSIZE(0);
mbed_official 579:53297373a894 335
mbed_official 579:53297373a894 336 /* Enable receiver */
mbed_official 579:53297373a894 337 ctrlb |= SERCOM_SPI_CTRLB_RXEN;
mbed_official 579:53297373a894 338
mbed_official 579:53297373a894 339 /* Write CTRLA register */
mbed_official 579:53297373a894 340 _SPI(obj).CTRLA.reg |= ctrla;
mbed_official 579:53297373a894 341
mbed_official 579:53297373a894 342 /* Write CTRLB register */
mbed_official 579:53297373a894 343 _SPI(obj).CTRLB.reg |= ctrlb;
mbed_official 579:53297373a894 344
mbed_official 579:53297373a894 345 /* Enable SPI */
mbed_official 579:53297373a894 346 spi_enable(obj);
mbed_official 579:53297373a894 347 }
mbed_official 579:53297373a894 348
mbed_official 579:53297373a894 349 /** Release a SPI object
mbed_official 579:53297373a894 350 *
mbed_official 579:53297373a894 351 * TODO: spi_free is currently unimplemented
mbed_official 579:53297373a894 352 * This will require reference counting at the C++ level to be safe
mbed_official 579:53297373a894 353 *
mbed_official 579:53297373a894 354 * Return the pins owned by the SPI object to their reset state
mbed_official 579:53297373a894 355 * Disable the SPI peripheral
mbed_official 579:53297373a894 356 * Disable the SPI clock
mbed_official 579:53297373a894 357 * @param[in] obj The SPI object to deinitialize
mbed_official 579:53297373a894 358 */
mbed_official 579:53297373a894 359 void spi_free(spi_t *obj)
mbed_official 579:53297373a894 360 {
mbed_official 579:53297373a894 361 // [TODO]
mbed_official 579:53297373a894 362 }
mbed_official 579:53297373a894 363
mbed_official 579:53297373a894 364 /** Configure the SPI format
mbed_official 579:53297373a894 365 *
mbed_official 579:53297373a894 366 * Set the number of bits per frame, configure clock polarity and phase, shift order and master/slave mode
mbed_official 579:53297373a894 367 * @param[in,out] obj The SPI object to configure
mbed_official 579:53297373a894 368 * @param[in] bits The number of bits per frame
mbed_official 579:53297373a894 369 * @param[in] mode The SPI mode (clock polarity, phase, and shift direction)
mbed_official 579:53297373a894 370 * @param[in] slave Zero for master mode or non-zero for slave mode
mbed_official 579:53297373a894 371 */
mbed_official 579:53297373a894 372 void spi_format(spi_t *obj, int bits, int mode, int slave)
mbed_official 579:53297373a894 373 {
mbed_official 592:a274ee790e56 374 PinMode pull_mode;
mbed_official 592:a274ee790e56 375 /* Sanity check arguments */
mbed_official 592:a274ee790e56 376 MBED_ASSERT(obj);
mbed_official 592:a274ee790e56 377
mbed_official 579:53297373a894 378 /* Disable SPI */
mbed_official 579:53297373a894 379 spi_disable(obj);
mbed_official 579:53297373a894 380
mbed_official 592:a274ee790e56 381
mbed_official 579:53297373a894 382 if (slave) {
mbed_official 579:53297373a894 383 /* Set the SERCOM in SPI mode */
mbed_official 579:53297373a894 384 _SPI(obj).CTRLA.bit.MODE = 0x2;
mbed_official 579:53297373a894 385 pSPI_S(obj)->mode = SPI_MODE_SLAVE;
mbed_official 592:a274ee790e56 386 pull_mode = PullNone;
mbed_official 592:a274ee790e56 387 /* Enable PLOADEN to avoid sending dummy character by slave */
mbed_official 592:a274ee790e56 388 _SPI(obj).CTRLB.bit.PLOADEN = 1;
mbed_official 579:53297373a894 389 } else {
mbed_official 592:a274ee790e56 390 /* Set the SERCOM in SPI mode */
mbed_official 592:a274ee790e56 391 _SPI(obj).CTRLA.bit.MODE = 0x3;
mbed_official 592:a274ee790e56 392 pSPI_S(obj)->mode = SPI_MODE_MASTER;
mbed_official 592:a274ee790e56 393 pull_mode = PullUp;
mbed_official 579:53297373a894 394 }
mbed_official 579:53297373a894 395
mbed_official 592:a274ee790e56 396 /* Change pull mode of pins */
mbed_official 592:a274ee790e56 397 for (uint8_t pad = 0; pad < 4; pad++) {
mbed_official 592:a274ee790e56 398 if (pSPI_S(obj)->pins[pad] != NC) {
mbed_official 592:a274ee790e56 399 pin_mode(pSPI_S(obj)->pins[pad], pull_mode);
mbed_official 592:a274ee790e56 400 }
mbed_official 592:a274ee790e56 401 }
mbed_official 592:a274ee790e56 402
mbed_official 592:a274ee790e56 403 /* Change MUX settings */
mbed_official 592:a274ee790e56 404 uint32_t ctrla = _SPI(obj).CTRLA.reg;
mbed_official 592:a274ee790e56 405 ctrla &= ~(SERCOM_SPI_CTRLA_DIPO_Msk | SERCOM_SPI_CTRLA_DOPO_Msk);
mbed_official 592:a274ee790e56 406 ctrla |= spi_find_mux_settings(obj);
mbed_official 592:a274ee790e56 407 _SPI(obj).CTRLA.reg = ctrla;
mbed_official 579:53297373a894 408
mbed_official 579:53297373a894 409 /* Set SPI Frame size - only 8-bit and 9-bit supported now */
mbed_official 579:53297373a894 410 _SPI(obj).CTRLB.bit.CHSIZE = (bits > 8)? 1 : 0;
mbed_official 579:53297373a894 411
mbed_official 579:53297373a894 412 /* Set SPI Clock Phase */
mbed_official 579:53297373a894 413 _SPI(obj).CTRLA.bit.CPHA = (mode & 0x01)? 1 : 0;
mbed_official 579:53297373a894 414
mbed_official 579:53297373a894 415 /* Set SPI Clock Polarity */
mbed_official 579:53297373a894 416 _SPI(obj).CTRLA.bit.CPOL = (mode & 0x02)? 1 : 0;
mbed_official 579:53297373a894 417
mbed_official 579:53297373a894 418 /* Enable SPI */
mbed_official 579:53297373a894 419 spi_enable(obj);
mbed_official 579:53297373a894 420 }
mbed_official 579:53297373a894 421
mbed_official 579:53297373a894 422 /** Set the SPI baud rate
mbed_official 579:53297373a894 423 *
mbed_official 579:53297373a894 424 * Actual frequency may differ from the desired frequency due to available dividers and bus clock
mbed_official 579:53297373a894 425 * Configures the SPI peripheral's baud rate
mbed_official 579:53297373a894 426 * @param[in,out] obj The SPI object to configure
mbed_official 579:53297373a894 427 * @param[in] hz The baud rate in Hz
mbed_official 579:53297373a894 428 */
mbed_official 579:53297373a894 429 void spi_frequency(spi_t *obj, int hz)
mbed_official 579:53297373a894 430 {
mbed_official 579:53297373a894 431 uint16_t baud = 0;
mbed_official 592:a274ee790e56 432 /* Sanity check arguments */
mbed_official 592:a274ee790e56 433 MBED_ASSERT(obj);
mbed_official 579:53297373a894 434
mbed_official 579:53297373a894 435 /* Disable SPI */
mbed_official 579:53297373a894 436 spi_disable(obj);
mbed_official 579:53297373a894 437
mbed_official 579:53297373a894 438 /* Find frequency of the internal SERCOMi_GCLK_ID_CORE */
mbed_official 579:53297373a894 439 uint32_t sercom_index = _sercom_get_sercom_inst_index(pSPI_SERCOM(obj));
mbed_official 579:53297373a894 440 uint32_t gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
mbed_official 579:53297373a894 441 uint32_t internal_clock = system_gclk_chan_get_hz(gclk_index);
mbed_official 579:53297373a894 442
mbed_official 579:53297373a894 443 /* Get baud value, based on baudrate and the internal clock frequency */
mbed_official 579:53297373a894 444 enum status_code error_code = _sercom_get_sync_baud_val(hz, internal_clock, &baud);
mbed_official 579:53297373a894 445
mbed_official 579:53297373a894 446 if (error_code != STATUS_OK) {
mbed_official 579:53297373a894 447 /* Baud rate calculation error, return status code */
mbed_official 579:53297373a894 448 /* Enable SPI */
mbed_official 579:53297373a894 449 spi_enable(obj);
mbed_official 579:53297373a894 450 return;
mbed_official 579:53297373a894 451 }
mbed_official 579:53297373a894 452
mbed_official 579:53297373a894 453 _SPI(obj).BAUD.reg = (uint8_t)baud;
mbed_official 579:53297373a894 454
mbed_official 579:53297373a894 455 /* Enable SPI */
mbed_official 579:53297373a894 456 spi_enable(obj);
mbed_official 579:53297373a894 457 }
mbed_official 579:53297373a894 458
mbed_official 579:53297373a894 459 /**@}*/
mbed_official 579:53297373a894 460 /**
mbed_official 579:53297373a894 461 * \defgroup SynchSPI Synchronous SPI Hardware Abstraction Layer
mbed_official 579:53297373a894 462 * @{
mbed_official 579:53297373a894 463 */
mbed_official 579:53297373a894 464
mbed_official 579:53297373a894 465 /** Write a byte out in master mode and receive a value
mbed_official 579:53297373a894 466 *
mbed_official 579:53297373a894 467 * @param[in] obj The SPI peripheral to use for sending
mbed_official 579:53297373a894 468 * @param[in] value The value to send
mbed_official 579:53297373a894 469 * @return Returns the value received during send
mbed_official 579:53297373a894 470 */
mbed_official 579:53297373a894 471 int spi_master_write(spi_t *obj, int value)
mbed_official 579:53297373a894 472 {
mbed_official 579:53297373a894 473 uint16_t rx_data = 0;
mbed_official 579:53297373a894 474
mbed_official 579:53297373a894 475 /* Sanity check arguments */
mbed_official 579:53297373a894 476 MBED_ASSERT(obj);
mbed_official 579:53297373a894 477
mbed_official 579:53297373a894 478 #if DEVICE_SPI_ASYNCH
mbed_official 579:53297373a894 479 if (obj->spi.status == STATUS_BUSY) {
mbed_official 579:53297373a894 480 /* Check if the SPI module is busy with a job */
mbed_official 579:53297373a894 481 return 0;
mbed_official 579:53297373a894 482 }
mbed_official 579:53297373a894 483 #endif
mbed_official 579:53297373a894 484
mbed_official 579:53297373a894 485 /* Wait until the module is ready to write the character */
mbed_official 579:53297373a894 486 while (!spi_is_ready_to_write(obj));
mbed_official 579:53297373a894 487
mbed_official 579:53297373a894 488 /* Write data */
mbed_official 579:53297373a894 489 spi_write(obj, value);
mbed_official 579:53297373a894 490
mbed_official 579:53297373a894 491 if (!(_SPI(obj).CTRLB.bit.RXEN)) {
mbed_official 579:53297373a894 492 return 0;
mbed_official 579:53297373a894 493 }
mbed_official 579:53297373a894 494
mbed_official 579:53297373a894 495 /* Wait until the module is ready to read the character */
mbed_official 579:53297373a894 496 while (!spi_is_ready_to_read(obj));
mbed_official 579:53297373a894 497
mbed_official 579:53297373a894 498 /* Read data */
mbed_official 579:53297373a894 499 spi_read(obj, &rx_data);
mbed_official 579:53297373a894 500
mbed_official 579:53297373a894 501 return rx_data;
mbed_official 579:53297373a894 502 }
mbed_official 579:53297373a894 503
mbed_official 579:53297373a894 504 /** Check if a value is available to read
mbed_official 579:53297373a894 505 *
mbed_official 579:53297373a894 506 * @param[in] obj The SPI peripheral to check
mbed_official 579:53297373a894 507 * @return non-zero if a value is available
mbed_official 579:53297373a894 508 */
mbed_official 579:53297373a894 509 int spi_slave_receive(spi_t *obj)
mbed_official 579:53297373a894 510 {
mbed_official 579:53297373a894 511 /* Sanity check arguments */
mbed_official 579:53297373a894 512 MBED_ASSERT(obj);
mbed_official 579:53297373a894 513
mbed_official 579:53297373a894 514 return spi_is_ready_to_read(obj);
mbed_official 579:53297373a894 515 }
mbed_official 579:53297373a894 516
mbed_official 579:53297373a894 517 /** Get a received value out of the SPI receive buffer in slave mode
mbed_official 579:53297373a894 518 *
mbed_official 579:53297373a894 519 * Blocks until a value is available
mbed_official 579:53297373a894 520 * @param[in] obj The SPI peripheral to read
mbed_official 579:53297373a894 521 * @return The value received
mbed_official 579:53297373a894 522 */
mbed_official 579:53297373a894 523 int spi_slave_read(spi_t *obj)
mbed_official 579:53297373a894 524 {
mbed_official 579:53297373a894 525 int i;
mbed_official 579:53297373a894 526 uint16_t rx_data = 0;
mbed_official 579:53297373a894 527
mbed_official 579:53297373a894 528 /* Sanity check arguments */
mbed_official 579:53297373a894 529 MBED_ASSERT(obj);
mbed_official 579:53297373a894 530
mbed_official 579:53297373a894 531 /* Check for timeout period */
mbed_official 579:53297373a894 532 for (i = 0; i < SPI_TIMEOUT; i++) {
mbed_official 579:53297373a894 533 if (spi_is_ready_to_read(obj)) {
mbed_official 579:53297373a894 534 break;
mbed_official 579:53297373a894 535 }
mbed_official 579:53297373a894 536 }
mbed_official 579:53297373a894 537 if (i == SPI_TIMEOUT) {
mbed_official 579:53297373a894 538 /* Not ready to read data within timeout period */
mbed_official 579:53297373a894 539 return 0;
mbed_official 579:53297373a894 540 }
mbed_official 579:53297373a894 541
mbed_official 579:53297373a894 542 /* Read data */
mbed_official 579:53297373a894 543 spi_read(obj, &rx_data);
mbed_official 579:53297373a894 544
mbed_official 579:53297373a894 545 return rx_data;
mbed_official 579:53297373a894 546 }
mbed_official 579:53297373a894 547
mbed_official 579:53297373a894 548 /** Write a value to the SPI peripheral in slave mode
mbed_official 579:53297373a894 549 *
mbed_official 579:53297373a894 550 * Blocks until the SPI peripheral can be written to
mbed_official 579:53297373a894 551 * @param[in] obj The SPI peripheral to write
mbed_official 579:53297373a894 552 * @param[in] value The value to write
mbed_official 579:53297373a894 553 */
mbed_official 579:53297373a894 554 void spi_slave_write(spi_t *obj, int value)
mbed_official 579:53297373a894 555 {
mbed_official 579:53297373a894 556 int i;
mbed_official 579:53297373a894 557
mbed_official 579:53297373a894 558 /* Sanity check arguments */
mbed_official 579:53297373a894 559 MBED_ASSERT(obj);
mbed_official 579:53297373a894 560
mbed_official 579:53297373a894 561 /* Check for timeout period */
mbed_official 579:53297373a894 562 for (i = 0; i < SPI_TIMEOUT; i++) {
mbed_official 579:53297373a894 563 if (spi_is_ready_to_write(obj)) {
mbed_official 579:53297373a894 564 break;
mbed_official 579:53297373a894 565 }
mbed_official 579:53297373a894 566 }
mbed_official 579:53297373a894 567 if (i == SPI_TIMEOUT) {
mbed_official 579:53297373a894 568 /* Not ready to write data within timeout period */
mbed_official 579:53297373a894 569 return;
mbed_official 579:53297373a894 570 }
mbed_official 579:53297373a894 571
mbed_official 579:53297373a894 572 /* Write data */
mbed_official 579:53297373a894 573 spi_write(obj, value);
mbed_official 579:53297373a894 574 }
mbed_official 579:53297373a894 575
mbed_official 579:53297373a894 576 /** Checks if the specified SPI peripheral is in use
mbed_official 579:53297373a894 577 *
mbed_official 579:53297373a894 578 * @param[in] obj The SPI peripheral to check
mbed_official 579:53297373a894 579 * @return non-zero if the peripheral is currently transmitting
mbed_official 579:53297373a894 580 */
mbed_official 579:53297373a894 581 int spi_busy(spi_t *obj)
mbed_official 579:53297373a894 582 {
mbed_official 579:53297373a894 583 /* Sanity check arguments */
mbed_official 579:53297373a894 584 MBED_ASSERT(obj);
mbed_official 579:53297373a894 585
mbed_official 579:53297373a894 586 return spi_is_write_complete(obj);
mbed_official 579:53297373a894 587 }
mbed_official 579:53297373a894 588
mbed_official 579:53297373a894 589 /** Get the module number
mbed_official 579:53297373a894 590 *
mbed_official 579:53297373a894 591 * @param[in] obj The SPI peripheral to check
mbed_official 579:53297373a894 592 * @return The module number
mbed_official 579:53297373a894 593 */
mbed_official 579:53297373a894 594 uint8_t spi_get_module(spi_t *obj)
mbed_official 579:53297373a894 595 {
mbed_official 579:53297373a894 596 /* Sanity check arguments */
mbed_official 579:53297373a894 597 MBED_ASSERT(obj);
mbed_official 579:53297373a894 598 return _sercom_get_sercom_inst_index(pSPI_SERCOM(obj));
mbed_official 579:53297373a894 599 }
mbed_official 579:53297373a894 600
mbed_official 579:53297373a894 601
mbed_official 579:53297373a894 602 #if DEVICE_SPI_ASYNCH
mbed_official 579:53297373a894 603 /**
mbed_official 579:53297373a894 604 * \defgroup AsynchSPI Asynchronous SPI Hardware Abstraction Layer
mbed_official 579:53297373a894 605 * @{
mbed_official 579:53297373a894 606 */
mbed_official 579:53297373a894 607
mbed_official 579:53297373a894 608
mbed_official 579:53297373a894 609 /**
mbed_official 579:53297373a894 610 * \internal
mbed_official 579:53297373a894 611 * Writes a character from the TX buffer to the Data register.
mbed_official 579:53297373a894 612 *
mbed_official 579:53297373a894 613 * \param[in,out] module Pointer to SPI software instance struct
mbed_official 579:53297373a894 614 */
mbed_official 579:53297373a894 615 static void _spi_write_async(spi_t *obj)
mbed_official 579:53297373a894 616 {
mbed_official 579:53297373a894 617 /* Sanity check arguments */
mbed_official 579:53297373a894 618 MBED_ASSERT(obj);
mbed_official 579:53297373a894 619
mbed_official 579:53297373a894 620 uint16_t data_to_send;
mbed_official 579:53297373a894 621 uint8_t *tx_buffer = obj->tx_buff.buffer;
mbed_official 579:53297373a894 622
mbed_official 579:53297373a894 623 /* Do nothing if we are at the end of buffer */
mbed_official 579:53297373a894 624 if (obj->tx_buff.pos < obj->tx_buff.length) {
mbed_official 579:53297373a894 625 /* Write value will be at least 8-bits long */
mbed_official 579:53297373a894 626 if (tx_buffer) {
mbed_official 579:53297373a894 627 data_to_send = tx_buffer[obj->tx_buff.pos];
mbed_official 579:53297373a894 628 } else {
mbed_official 579:53297373a894 629 data_to_send = dummy_fill_word;
mbed_official 579:53297373a894 630 }
mbed_official 579:53297373a894 631 /* Increment 8-bit index */
mbed_official 579:53297373a894 632 obj->tx_buff.pos++;
mbed_official 579:53297373a894 633
mbed_official 579:53297373a894 634 if (_SPI(obj).CTRLB.bit.CHSIZE == 1) {
mbed_official 579:53297373a894 635 if (tx_buffer)
mbed_official 579:53297373a894 636 data_to_send |= (tx_buffer[obj->tx_buff.pos] << 8);
mbed_official 579:53297373a894 637 /* Increment 8-bit index */
mbed_official 579:53297373a894 638 obj->tx_buff.pos++;
mbed_official 579:53297373a894 639 }
mbed_official 579:53297373a894 640 } else {
mbed_official 579:53297373a894 641 /* Write a dummy packet */
mbed_official 579:53297373a894 642 /* TODO: Current implementation do not enter this condition, remove if not needed */
mbed_official 579:53297373a894 643 data_to_send = dummy_fill_word;
mbed_official 579:53297373a894 644 }
mbed_official 579:53297373a894 645
mbed_official 579:53297373a894 646 /* Write the data to send*/
mbed_official 579:53297373a894 647 _SPI(obj).DATA.reg = data_to_send & SERCOM_SPI_DATA_MASK;
mbed_official 579:53297373a894 648
mbed_official 579:53297373a894 649 /* Check for error */
mbed_official 579:53297373a894 650 if ((_SPI(obj).INTFLAG.reg & SERCOM_SPI_INTFLAG_ERROR) && (obj->spi.mask & SPI_EVENT_ERROR)) {
mbed_official 579:53297373a894 651 obj->spi.event |= SPI_EVENT_ERROR;
mbed_official 579:53297373a894 652 }
mbed_official 579:53297373a894 653 }
mbed_official 579:53297373a894 654
mbed_official 579:53297373a894 655 /**
mbed_official 579:53297373a894 656 * \internal
mbed_official 579:53297373a894 657 * Reads a character from the Data register to the RX buffer.
mbed_official 579:53297373a894 658 *
mbed_official 579:53297373a894 659 * \param[in,out] module Pointer to SPI software instance struct
mbed_official 579:53297373a894 660 */
mbed_official 579:53297373a894 661 static void _spi_read_async(spi_t *obj)
mbed_official 579:53297373a894 662 {
mbed_official 579:53297373a894 663 /* Sanity check arguments */
mbed_official 579:53297373a894 664 MBED_ASSERT(obj);
mbed_official 579:53297373a894 665
mbed_official 579:53297373a894 666 uint8_t *rx_buffer = obj->rx_buff.buffer;
mbed_official 579:53297373a894 667
mbed_official 579:53297373a894 668 /* Check if data is overflown */
mbed_official 579:53297373a894 669 if (_SPI(obj).STATUS.reg & SERCOM_SPI_STATUS_BUFOVF) {
mbed_official 579:53297373a894 670 /* Clear overflow flag */
mbed_official 579:53297373a894 671 _SPI(obj).STATUS.reg |= SERCOM_SPI_STATUS_BUFOVF;
mbed_official 579:53297373a894 672 if (obj->spi.mask & SPI_EVENT_RX_OVERFLOW) {
mbed_official 579:53297373a894 673 /* Set overflow error */
mbed_official 579:53297373a894 674 obj->spi.event |= SPI_EVENT_RX_OVERFLOW;
mbed_official 579:53297373a894 675 return;
mbed_official 579:53297373a894 676 }
mbed_official 579:53297373a894 677 }
mbed_official 579:53297373a894 678
mbed_official 579:53297373a894 679 /* Read data, either valid, or dummy */
mbed_official 579:53297373a894 680 uint16_t received_data = (_SPI(obj).DATA.reg & SERCOM_SPI_DATA_MASK);
mbed_official 579:53297373a894 681
mbed_official 579:53297373a894 682 /* Do nothing if we are at the end of buffer */
mbed_official 579:53297373a894 683 if ((obj->rx_buff.pos >= obj->rx_buff.length) && rx_buffer) {
mbed_official 579:53297373a894 684 return;
mbed_official 579:53297373a894 685 }
mbed_official 579:53297373a894 686
mbed_official 579:53297373a894 687 /* Read value will be at least 8-bits long */
mbed_official 579:53297373a894 688 rx_buffer[obj->rx_buff.pos] = received_data;
mbed_official 579:53297373a894 689 /* Increment 8-bit index */
mbed_official 579:53297373a894 690 obj->rx_buff.pos++;
mbed_official 579:53297373a894 691
mbed_official 579:53297373a894 692 if (_SPI(obj).CTRLB.bit.CHSIZE == 1) {
mbed_official 579:53297373a894 693 /* 9-bit data, write next received byte to the buffer */
mbed_official 579:53297373a894 694 rx_buffer[obj->rx_buff.pos] = (received_data >> 8);
mbed_official 579:53297373a894 695 /* Increment 8-bit index */
mbed_official 579:53297373a894 696 obj->rx_buff.pos++;
mbed_official 579:53297373a894 697 }
mbed_official 579:53297373a894 698
mbed_official 579:53297373a894 699 /* Check for error */
mbed_official 579:53297373a894 700 if ((_SPI(obj).INTFLAG.reg & SERCOM_SPI_INTFLAG_ERROR) && (obj->spi.mask & SPI_EVENT_ERROR)) {
mbed_official 579:53297373a894 701 obj->spi.event |= SPI_EVENT_ERROR;
mbed_official 579:53297373a894 702 }
mbed_official 579:53297373a894 703 }
mbed_official 579:53297373a894 704
mbed_official 579:53297373a894 705 /**
mbed_official 579:53297373a894 706 * \internal
mbed_official 579:53297373a894 707 * Clears all interrupt flags of SPI
mbed_official 579:53297373a894 708 *
mbed_official 579:53297373a894 709 * \param[in,out] module Pointer to SPI software instance struct
mbed_official 579:53297373a894 710 */
mbed_official 579:53297373a894 711 static void _spi_clear_interrupts(spi_t *obj)
mbed_official 579:53297373a894 712 {
mbed_official 592:a274ee790e56 713 /* Sanity check arguments */
mbed_official 592:a274ee790e56 714 MBED_ASSERT(obj);
mbed_official 592:a274ee790e56 715
mbed_official 579:53297373a894 716 uint8_t sercom_index = _sercom_get_sercom_inst_index(obj->spi.spi);
mbed_official 579:53297373a894 717
mbed_official 579:53297373a894 718 /* Clear all interrupts */
mbed_official 579:53297373a894 719 _SPI(obj).INTENCLR.reg =
mbed_official 579:53297373a894 720 SERCOM_SPI_INTFLAG_DRE |
mbed_official 579:53297373a894 721 SERCOM_SPI_INTFLAG_TXC |
mbed_official 579:53297373a894 722 SERCOM_SPI_INTFLAG_RXC |
mbed_official 579:53297373a894 723 SERCOM_SPI_INTFLAG_ERROR;
mbed_official 579:53297373a894 724 NVIC_DisableIRQ(SERCOM0_IRQn + sercom_index);
mbed_official 579:53297373a894 725 NVIC_SetVector((SERCOM0_IRQn + sercom_index), (uint32_t)NULL);
mbed_official 579:53297373a894 726 }
mbed_official 579:53297373a894 727
mbed_official 579:53297373a894 728 /**
mbed_official 579:53297373a894 729 * \internal
mbed_official 579:53297373a894 730 * Starts transceive of buffers with a given length
mbed_official 579:53297373a894 731 *
mbed_official 579:53297373a894 732 * \param[in,out] obj Pointer to SPI software instance struct
mbed_official 579:53297373a894 733 *
mbed_official 579:53297373a894 734 */
mbed_official 592:a274ee790e56 735 static enum status_code _spi_transceive_buffer(spi_t *obj)
mbed_official 579:53297373a894 736 {
mbed_official 579:53297373a894 737 /* Sanity check arguments */
mbed_official 579:53297373a894 738 MBED_ASSERT(obj);
mbed_official 579:53297373a894 739
mbed_official 579:53297373a894 740 uint16_t interrupt_status = _SPI(obj).INTFLAG.reg;
mbed_official 579:53297373a894 741 interrupt_status &= _SPI(obj).INTENSET.reg;
mbed_official 579:53297373a894 742
mbed_official 579:53297373a894 743 if (interrupt_status & SERCOM_SPI_INTFLAG_DRE) {
mbed_official 579:53297373a894 744 /* Clear DRE interrupt */
mbed_official 579:53297373a894 745 _SPI(obj).INTENCLR.reg = SERCOM_SPI_INTFLAG_DRE;
mbed_official 579:53297373a894 746 /* Write data */
mbed_official 579:53297373a894 747 _spi_write_async(obj);
mbed_official 579:53297373a894 748 /* Set TXC interrupt */
mbed_official 579:53297373a894 749 _SPI(obj).INTENSET.reg |= SERCOM_SPI_INTFLAG_TXC;
mbed_official 579:53297373a894 750 }
mbed_official 579:53297373a894 751 if (interrupt_status & SERCOM_SPI_INTFLAG_TXC) {
mbed_official 579:53297373a894 752 /* Clear TXC interrupt */
mbed_official 579:53297373a894 753 _SPI(obj).INTENCLR.reg = SERCOM_SPI_INTFLAG_TXC;
mbed_official 579:53297373a894 754 if ((obj->rx_buff.buffer) && (obj->rx_buff.pos < obj->rx_buff.length)) {
mbed_official 579:53297373a894 755 while (!spi_is_ready_to_read(obj));
mbed_official 579:53297373a894 756 _spi_read_async(obj);
mbed_official 579:53297373a894 757 if ((obj->tx_buff.pos >= obj->tx_buff.length) && (obj->tx_buff.length < obj->rx_buff.length)) {
mbed_official 579:53297373a894 758 obj->tx_buff.length = obj->rx_buff.length;
mbed_official 579:53297373a894 759 obj->tx_buff.buffer = 0;
mbed_official 579:53297373a894 760 }
mbed_official 579:53297373a894 761 }
mbed_official 579:53297373a894 762 if (obj->tx_buff.pos < obj->tx_buff.length) {
mbed_official 579:53297373a894 763 /* Set DRE interrupt */
mbed_official 579:53297373a894 764 _SPI(obj).INTENSET.reg |= SERCOM_SPI_INTFLAG_DRE;
mbed_official 579:53297373a894 765 }
mbed_official 579:53297373a894 766 }
mbed_official 579:53297373a894 767
mbed_official 579:53297373a894 768 if (obj->spi.event & (SPI_EVENT_ERROR | SPI_EVENT_RX_OVERFLOW) || (interrupt_status & SERCOM_SPI_INTFLAG_ERROR)) {
mbed_official 579:53297373a894 769 /* Clear all interrupts */
mbed_official 579:53297373a894 770 _spi_clear_interrupts(obj);
mbed_official 579:53297373a894 771
mbed_official 579:53297373a894 772 if (interrupt_status & SERCOM_SPI_INTFLAG_ERROR) {
mbed_official 579:53297373a894 773 obj->spi.event = STATUS_ERR_BAD_DATA;
mbed_official 579:53297373a894 774 }
mbed_official 579:53297373a894 775
mbed_official 579:53297373a894 776 /* Transfer interrupted, invoke the callback function */
mbed_official 579:53297373a894 777 if (obj->spi.event & SPI_EVENT_RX_OVERFLOW) {
mbed_official 579:53297373a894 778 obj->spi.status = STATUS_ERR_OVERFLOW;
mbed_official 579:53297373a894 779 } else {
mbed_official 579:53297373a894 780 obj->spi.status = STATUS_ERR_BAD_DATA;
mbed_official 579:53297373a894 781 }
mbed_official 592:a274ee790e56 782 return obj->spi.status;
mbed_official 579:53297373a894 783 }
mbed_official 579:53297373a894 784
mbed_official 579:53297373a894 785 if ((obj->tx_buff.pos >= obj->tx_buff.length) && (obj->rx_buff.pos >= obj->rx_buff.length) && (interrupt_status & SERCOM_SPI_INTFLAG_TXC)) {
mbed_official 579:53297373a894 786 /* Clear all interrupts */
mbed_official 579:53297373a894 787 _spi_clear_interrupts(obj);
mbed_official 579:53297373a894 788
mbed_official 579:53297373a894 789 /* Transfer complete, invoke the callback function */
mbed_official 579:53297373a894 790 obj->spi.event = SPI_EVENT_INTERNAL_TRANSFER_COMPLETE;
mbed_official 579:53297373a894 791 obj->spi.status = STATUS_OK;
mbed_official 579:53297373a894 792 }
mbed_official 592:a274ee790e56 793
mbed_official 592:a274ee790e56 794 return obj->spi.status;
mbed_official 579:53297373a894 795 }
mbed_official 579:53297373a894 796
mbed_official 579:53297373a894 797 /** Begin the SPI transfer. Buffer pointers and lengths are specified in tx_buff and rx_buff
mbed_official 579:53297373a894 798 *
mbed_official 579:53297373a894 799 * @param[in] obj The SPI object which holds the transfer information
mbed_official 579:53297373a894 800 * @param[in] tx The buffer to send
mbed_official 579:53297373a894 801 * @param[in] tx_length The number of words to transmit
mbed_official 579:53297373a894 802 * @param[out]rx The buffer to receive
mbed_official 579:53297373a894 803 * @param[in] rx_length The number of words to receive
mbed_official 579:53297373a894 804 * @param[in] bit_width The bit width of buffer words
mbed_official 579:53297373a894 805 * @param[in] event The logical OR of events to be registered
mbed_official 579:53297373a894 806 * @param[in] handler SPI interrupt handler
mbed_official 579:53297373a894 807 * @param[in] hint A suggestion for how to use DMA with this transfer **< DMA currently not implemented >**
mbed_official 579:53297373a894 808 */
mbed_official 579:53297373a894 809 void spi_master_transfer(spi_t *obj, const void *tx, size_t tx_length, void *rx, size_t rx_length, uint8_t bit_width, uint32_t handler, uint32_t event, DMAUsage hint)
mbed_official 579:53297373a894 810 {
mbed_official 579:53297373a894 811 uint16_t dummy_read;
mbed_official 579:53297373a894 812 /* Sanity check arguments */
mbed_official 579:53297373a894 813 MBED_ASSERT(obj);
mbed_official 579:53297373a894 814
mbed_official 579:53297373a894 815 uint8_t sercom_index = _sercom_get_sercom_inst_index(obj->spi.spi);
mbed_official 579:53297373a894 816
mbed_official 579:53297373a894 817 obj->spi.tx_buffer = tx;
mbed_official 579:53297373a894 818 obj->tx_buff.buffer = tx;
mbed_official 579:53297373a894 819 obj->tx_buff.pos = 0;
mbed_official 579:53297373a894 820 if (tx) {
mbed_official 579:53297373a894 821 /* Only two bit rates supported now */
mbed_official 579:53297373a894 822 obj->tx_buff.length = tx_length * ((bit_width > 8)? 2 : 1);
mbed_official 579:53297373a894 823 } else {
mbed_official 579:53297373a894 824 if (rx) {
mbed_official 579:53297373a894 825 obj->tx_buff.length = rx_length * ((bit_width > 8)? 2 : 1);
mbed_official 579:53297373a894 826 } else {
mbed_official 579:53297373a894 827 /* Nothing to transfer */
mbed_official 579:53297373a894 828 return;
mbed_official 579:53297373a894 829 }
mbed_official 579:53297373a894 830 }
mbed_official 579:53297373a894 831
mbed_official 579:53297373a894 832 obj->spi.rx_buffer = rx;
mbed_official 579:53297373a894 833 obj->rx_buff.buffer = rx;
mbed_official 579:53297373a894 834 obj->rx_buff.pos = 0;
mbed_official 579:53297373a894 835 if (rx) {
mbed_official 579:53297373a894 836 /* Only two bit rates supported now */
mbed_official 579:53297373a894 837 obj->rx_buff.length = rx_length * ((bit_width > 8)? 2 : 1);
mbed_official 579:53297373a894 838 } else {
mbed_official 579:53297373a894 839 /* Disable RXEN */
mbed_official 579:53297373a894 840 spi_disable(obj);
mbed_official 579:53297373a894 841 _SPI(obj).CTRLB.bit.RXEN = 0;
mbed_official 579:53297373a894 842 spi_enable(obj);
mbed_official 579:53297373a894 843 obj->rx_buff.length = 0;
mbed_official 579:53297373a894 844 }
mbed_official 579:53297373a894 845
mbed_official 579:53297373a894 846 /* Clear data buffer if there is anything pending to read */
mbed_official 579:53297373a894 847 while (spi_is_ready_to_read(obj)) {
mbed_official 579:53297373a894 848 dummy_read = _SPI(obj).DATA.reg;
mbed_official 579:53297373a894 849 }
mbed_official 579:53297373a894 850
mbed_official 579:53297373a894 851 obj->spi.mask = event;
mbed_official 579:53297373a894 852
mbed_official 579:53297373a894 853 obj->spi.dma_usage = hint;
mbed_official 579:53297373a894 854
mbed_official 579:53297373a894 855 /*if (hint == DMA_USAGE_NEVER) {** TEMP: Commented as DMA is not implemented now */
mbed_official 579:53297373a894 856 /* Use irq method */
mbed_official 579:53297373a894 857 uint16_t irq_mask = 0;
mbed_official 579:53297373a894 858 obj->spi.status = STATUS_BUSY;
mbed_official 579:53297373a894 859
mbed_official 579:53297373a894 860 /* Enable interrupt */
mbed_official 592:a274ee790e56 861 NVIC_SetVector((SERCOM0_IRQn + sercom_index), handler);
mbed_official 579:53297373a894 862 NVIC_EnableIRQ(SERCOM0_IRQn + sercom_index);
mbed_official 579:53297373a894 863
mbed_official 579:53297373a894 864 /* Clear all interrupts */
mbed_official 579:53297373a894 865 _SPI(obj).INTENCLR.reg = SERCOM_SPI_INTFLAG_TXC | SERCOM_SPI_INTFLAG_RXC | SERCOM_SPI_INTFLAG_ERROR;
mbed_official 579:53297373a894 866 _SPI(obj).INTFLAG.reg = SERCOM_SPI_INTFLAG_TXC | SERCOM_SPI_INTFLAG_ERROR;
mbed_official 579:53297373a894 867 _SPI(obj).STATUS.reg |= SERCOM_SPI_STATUS_BUFOVF;
mbed_official 579:53297373a894 868
mbed_official 579:53297373a894 869 /* Set SPI interrupts */
mbed_official 579:53297373a894 870 if (tx) {
mbed_official 579:53297373a894 871 irq_mask |= SERCOM_SPI_INTFLAG_DRE;
mbed_official 579:53297373a894 872 }
mbed_official 579:53297373a894 873 if (event & SPI_EVENT_ERROR) {
mbed_official 579:53297373a894 874 irq_mask |= SERCOM_SPI_INTFLAG_ERROR;
mbed_official 579:53297373a894 875 }
mbed_official 579:53297373a894 876 _SPI(obj).INTENSET.reg = irq_mask;
mbed_official 579:53297373a894 877 /*} ** TEMP: Commented as DMA is not implemented now */
mbed_official 579:53297373a894 878 }
mbed_official 579:53297373a894 879
mbed_official 579:53297373a894 880 /** The asynchronous IRQ handler
mbed_official 579:53297373a894 881 *
mbed_official 579:53297373a894 882 * Reads the received values out of the RX FIFO, writes values into the TX FIFO and checks for transfer termination
mbed_official 579:53297373a894 883 * conditions, such as buffer overflows or transfer complete.
mbed_official 579:53297373a894 884 * @param[in] obj The SPI object which holds the transfer information
mbed_official 579:53297373a894 885 * @return event flags if a transfer termination condition was met or 0 otherwise.
mbed_official 579:53297373a894 886 */
mbed_official 579:53297373a894 887 uint32_t spi_irq_handler_asynch(spi_t *obj)
mbed_official 579:53297373a894 888 {
mbed_official 592:a274ee790e56 889 /* Sanity check arguments */
mbed_official 592:a274ee790e56 890 MBED_ASSERT(obj);
mbed_official 592:a274ee790e56 891
mbed_official 579:53297373a894 892 uint32_t transfer_event = 0;
mbed_official 579:53297373a894 893
mbed_official 579:53297373a894 894 /*if (obj->spi.dma_usage == DMA_USAGE_NEVER) {** TEMP: Commented as DMA is not implemented now */
mbed_official 579:53297373a894 895 /* IRQ method */
mbed_official 592:a274ee790e56 896 if (STATUS_BUSY != _spi_transceive_buffer(obj)) {
mbed_official 592:a274ee790e56 897 transfer_event = obj->spi.event & (obj->spi.mask | SPI_EVENT_INTERNAL_TRANSFER_COMPLETE);
mbed_official 579:53297373a894 898 }
mbed_official 579:53297373a894 899 /*}** TEMP: Commented as DMA is not implemented now */
mbed_official 579:53297373a894 900 return transfer_event;
mbed_official 579:53297373a894 901 }
mbed_official 579:53297373a894 902
mbed_official 579:53297373a894 903 /** Attempts to determine if the SPI peripheral is already in use.
mbed_official 579:53297373a894 904 * @param[in] obj The SPI object to check for activity
mbed_official 579:53297373a894 905 * @return non-zero if the SPI port is active or zero if it is not.
mbed_official 579:53297373a894 906 */
mbed_official 579:53297373a894 907 uint8_t spi_active(spi_t *obj)
mbed_official 579:53297373a894 908 {
mbed_official 592:a274ee790e56 909 /* Sanity check arguments */
mbed_official 592:a274ee790e56 910 MBED_ASSERT(obj);
mbed_official 592:a274ee790e56 911
mbed_official 579:53297373a894 912 /* Check if the SPI module is busy with a job */
mbed_official 579:53297373a894 913 return (obj->spi.status == STATUS_BUSY);
mbed_official 579:53297373a894 914 }
mbed_official 579:53297373a894 915
mbed_official 579:53297373a894 916 /** Abort an SPI transfer
mbed_official 579:53297373a894 917 *
mbed_official 579:53297373a894 918 * @param obj The SPI peripheral to stop
mbed_official 579:53297373a894 919 */
mbed_official 579:53297373a894 920 void spi_abort_asynch(spi_t *obj)
mbed_official 579:53297373a894 921 {
mbed_official 579:53297373a894 922 /* Sanity check arguments */
mbed_official 579:53297373a894 923 MBED_ASSERT(obj);
mbed_official 579:53297373a894 924
mbed_official 579:53297373a894 925 uint8_t sercom_index = _sercom_get_sercom_inst_index(obj->spi.spi);
mbed_official 579:53297373a894 926
mbed_official 579:53297373a894 927 /* Clear all interrupts */
mbed_official 579:53297373a894 928 _SPI(obj).INTENCLR.reg =
mbed_official 579:53297373a894 929 SERCOM_SPI_INTFLAG_DRE |
mbed_official 579:53297373a894 930 SERCOM_SPI_INTFLAG_TXC |
mbed_official 579:53297373a894 931 SERCOM_SPI_INTFLAG_RXC |
mbed_official 579:53297373a894 932 SERCOM_SPI_INTFLAG_ERROR;
mbed_official 579:53297373a894 933
mbed_official 579:53297373a894 934 // TODO: Disable and remove irq handler
mbed_official 579:53297373a894 935 NVIC_DisableIRQ(SERCOM0_IRQn + sercom_index);
mbed_official 579:53297373a894 936 NVIC_SetVector((SERCOM0_IRQn + sercom_index), (uint32_t)NULL);
mbed_official 579:53297373a894 937
mbed_official 579:53297373a894 938 obj->spi.status = STATUS_ABORTED;
mbed_official 579:53297373a894 939 }
mbed_official 579:53297373a894 940
mbed_official 579:53297373a894 941 #endif /* DEVICE_SPI_ASYNCH */