Color Oled(SSD1331) connect to STMicroelectronics Nucleo-F466

Dependencies:   ssd1331

Committer:
kadonotakashi
Date:
Wed Oct 10 00:33:53 2018 +0000
Revision:
0:8fdf9a60065b
how to make mbed librry

Who changed what in which revision?

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