mbed library sources

Dependents:   Encrypted my_mbed lklk CyaSSL_DTLS_Cellular ... more

Superseded

This library was superseded by mbed-dev - https://os.mbed.com/users/mbed_official/code/mbed-dev/.

Development branch of the mbed library sources. This library is kept in synch with the latest changes from the mbed SDK and it is not guaranteed to work.

If you are looking for a stable and tested release, please import one of the official mbed library releases:

Import librarymbed

The official Mbed 2 C/C++ SDK provides the software platform and libraries to build your applications.

Committer:
mbed_official
Date:
Wed Jul 01 09:45:11 2015 +0100
Revision:
579:53297373a894
Child:
592:a274ee790e56
Synchronized with git revision d5b4d2ab9c47edb4dc5776e7177b0c2263459081

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

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