Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
mySPI/mySPI.h@1:df1ae6d3fd03, 2018-11-13 (annotated)
- Committer:
- lukofsky
- Date:
- Tue Nov 13 19:27:58 2018 +0000
- Revision:
- 1:df1ae6d3fd03
Memulator;
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
lukofsky | 1:df1ae6d3fd03 | 1 | //////////////////////////////////////////////////////////////////////// |
lukofsky | 1:df1ae6d3fd03 | 2 | // NOTE: no change |
lukofsky | 1:df1ae6d3fd03 | 3 | //////////////////////////////////////////////////////////////////////// |
lukofsky | 1:df1ae6d3fd03 | 4 | |
lukofsky | 1:df1ae6d3fd03 | 5 | /* mbed Microcontroller Library |
lukofsky | 1:df1ae6d3fd03 | 6 | |
lukofsky | 1:df1ae6d3fd03 | 7 | * Copyright (c) 2006-2015 ARM Limited |
lukofsky | 1:df1ae6d3fd03 | 8 | |
lukofsky | 1:df1ae6d3fd03 | 9 | * |
lukofsky | 1:df1ae6d3fd03 | 10 | |
lukofsky | 1:df1ae6d3fd03 | 11 | * Licensed under the Apache License, Version 2.0 (the "License"); |
lukofsky | 1:df1ae6d3fd03 | 12 | |
lukofsky | 1:df1ae6d3fd03 | 13 | * you may not use this file except in compliance with the License. |
lukofsky | 1:df1ae6d3fd03 | 14 | |
lukofsky | 1:df1ae6d3fd03 | 15 | * You may obtain a copy of the License at |
lukofsky | 1:df1ae6d3fd03 | 16 | |
lukofsky | 1:df1ae6d3fd03 | 17 | * |
lukofsky | 1:df1ae6d3fd03 | 18 | |
lukofsky | 1:df1ae6d3fd03 | 19 | * http://www.apache.org/licenses/LICENSE-2.0 |
lukofsky | 1:df1ae6d3fd03 | 20 | |
lukofsky | 1:df1ae6d3fd03 | 21 | * |
lukofsky | 1:df1ae6d3fd03 | 22 | |
lukofsky | 1:df1ae6d3fd03 | 23 | * Unless required by applicable law or agreed to in writing, software |
lukofsky | 1:df1ae6d3fd03 | 24 | |
lukofsky | 1:df1ae6d3fd03 | 25 | * distributed under the License is distributed on an "AS IS" BASIS, |
lukofsky | 1:df1ae6d3fd03 | 26 | |
lukofsky | 1:df1ae6d3fd03 | 27 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
lukofsky | 1:df1ae6d3fd03 | 28 | |
lukofsky | 1:df1ae6d3fd03 | 29 | * See the License for the specific language governing permissions and |
lukofsky | 1:df1ae6d3fd03 | 30 | |
lukofsky | 1:df1ae6d3fd03 | 31 | * limitations under the License. |
lukofsky | 1:df1ae6d3fd03 | 32 | |
lukofsky | 1:df1ae6d3fd03 | 33 | */ |
lukofsky | 1:df1ae6d3fd03 | 34 | |
lukofsky | 1:df1ae6d3fd03 | 35 | #ifndef MBED_SPI_H |
lukofsky | 1:df1ae6d3fd03 | 36 | |
lukofsky | 1:df1ae6d3fd03 | 37 | #define MBED_SPI_H |
lukofsky | 1:df1ae6d3fd03 | 38 | |
lukofsky | 1:df1ae6d3fd03 | 39 | |
lukofsky | 1:df1ae6d3fd03 | 40 | |
lukofsky | 1:df1ae6d3fd03 | 41 | #include "platform/platform.h" |
lukofsky | 1:df1ae6d3fd03 | 42 | |
lukofsky | 1:df1ae6d3fd03 | 43 | |
lukofsky | 1:df1ae6d3fd03 | 44 | |
lukofsky | 1:df1ae6d3fd03 | 45 | #if defined (DEVICE_SPI) || defined(DOXYGEN_ONLY) |
lukofsky | 1:df1ae6d3fd03 | 46 | |
lukofsky | 1:df1ae6d3fd03 | 47 | |
lukofsky | 1:df1ae6d3fd03 | 48 | |
lukofsky | 1:df1ae6d3fd03 | 49 | #include "platform/PlatformMutex.h" |
lukofsky | 1:df1ae6d3fd03 | 50 | |
lukofsky | 1:df1ae6d3fd03 | 51 | #include "hal/spi_api.h" |
lukofsky | 1:df1ae6d3fd03 | 52 | |
lukofsky | 1:df1ae6d3fd03 | 53 | #include "platform/SingletonPtr.h" |
lukofsky | 1:df1ae6d3fd03 | 54 | |
lukofsky | 1:df1ae6d3fd03 | 55 | #include "platform/NonCopyable.h" |
lukofsky | 1:df1ae6d3fd03 | 56 | |
lukofsky | 1:df1ae6d3fd03 | 57 | |
lukofsky | 1:df1ae6d3fd03 | 58 | |
lukofsky | 1:df1ae6d3fd03 | 59 | #if DEVICE_SPI_ASYNCH |
lukofsky | 1:df1ae6d3fd03 | 60 | |
lukofsky | 1:df1ae6d3fd03 | 61 | #include "platform/CThunk.h" |
lukofsky | 1:df1ae6d3fd03 | 62 | |
lukofsky | 1:df1ae6d3fd03 | 63 | #include "hal/dma_api.h" |
lukofsky | 1:df1ae6d3fd03 | 64 | |
lukofsky | 1:df1ae6d3fd03 | 65 | #include "platform/CircularBuffer.h" |
lukofsky | 1:df1ae6d3fd03 | 66 | |
lukofsky | 1:df1ae6d3fd03 | 67 | #include "platform/FunctionPointer.h" |
lukofsky | 1:df1ae6d3fd03 | 68 | |
lukofsky | 1:df1ae6d3fd03 | 69 | #include "platform/Transaction.h" |
lukofsky | 1:df1ae6d3fd03 | 70 | |
lukofsky | 1:df1ae6d3fd03 | 71 | #endif |
lukofsky | 1:df1ae6d3fd03 | 72 | |
lukofsky | 1:df1ae6d3fd03 | 73 | |
lukofsky | 1:df1ae6d3fd03 | 74 | |
lukofsky | 1:df1ae6d3fd03 | 75 | namespace mbed { |
lukofsky | 1:df1ae6d3fd03 | 76 | |
lukofsky | 1:df1ae6d3fd03 | 77 | /** \addtogroup drivers */ |
lukofsky | 1:df1ae6d3fd03 | 78 | |
lukofsky | 1:df1ae6d3fd03 | 79 | |
lukofsky | 1:df1ae6d3fd03 | 80 | |
lukofsky | 1:df1ae6d3fd03 | 81 | /** A SPI Master, used for communicating with SPI slave devices |
lukofsky | 1:df1ae6d3fd03 | 82 | |
lukofsky | 1:df1ae6d3fd03 | 83 | * |
lukofsky | 1:df1ae6d3fd03 | 84 | |
lukofsky | 1:df1ae6d3fd03 | 85 | * The default format is set to 8-bits, mode 0, and a clock frequency of 1MHz |
lukofsky | 1:df1ae6d3fd03 | 86 | |
lukofsky | 1:df1ae6d3fd03 | 87 | * |
lukofsky | 1:df1ae6d3fd03 | 88 | |
lukofsky | 1:df1ae6d3fd03 | 89 | * Most SPI devices will also require Chip Select and Reset signals. These |
lukofsky | 1:df1ae6d3fd03 | 90 | |
lukofsky | 1:df1ae6d3fd03 | 91 | * can be controlled using DigitalOut pins |
lukofsky | 1:df1ae6d3fd03 | 92 | |
lukofsky | 1:df1ae6d3fd03 | 93 | * |
lukofsky | 1:df1ae6d3fd03 | 94 | |
lukofsky | 1:df1ae6d3fd03 | 95 | * @note Synchronization level: Thread safe |
lukofsky | 1:df1ae6d3fd03 | 96 | |
lukofsky | 1:df1ae6d3fd03 | 97 | * |
lukofsky | 1:df1ae6d3fd03 | 98 | |
lukofsky | 1:df1ae6d3fd03 | 99 | * Example: |
lukofsky | 1:df1ae6d3fd03 | 100 | |
lukofsky | 1:df1ae6d3fd03 | 101 | * @code |
lukofsky | 1:df1ae6d3fd03 | 102 | |
lukofsky | 1:df1ae6d3fd03 | 103 | * // Send a byte to a SPI slave, and record the response |
lukofsky | 1:df1ae6d3fd03 | 104 | |
lukofsky | 1:df1ae6d3fd03 | 105 | * |
lukofsky | 1:df1ae6d3fd03 | 106 | |
lukofsky | 1:df1ae6d3fd03 | 107 | * #include "mbed.h" |
lukofsky | 1:df1ae6d3fd03 | 108 | |
lukofsky | 1:df1ae6d3fd03 | 109 | * |
lukofsky | 1:df1ae6d3fd03 | 110 | |
lukofsky | 1:df1ae6d3fd03 | 111 | * // hardware ssel (where applicable) |
lukofsky | 1:df1ae6d3fd03 | 112 | |
lukofsky | 1:df1ae6d3fd03 | 113 | * //SPI device(p5, p6, p7, p8); // mosi, miso, sclk, ssel |
lukofsky | 1:df1ae6d3fd03 | 114 | |
lukofsky | 1:df1ae6d3fd03 | 115 | * |
lukofsky | 1:df1ae6d3fd03 | 116 | |
lukofsky | 1:df1ae6d3fd03 | 117 | * // software ssel |
lukofsky | 1:df1ae6d3fd03 | 118 | |
lukofsky | 1:df1ae6d3fd03 | 119 | * SPI device(p5, p6, p7); // mosi, miso, sclk |
lukofsky | 1:df1ae6d3fd03 | 120 | |
lukofsky | 1:df1ae6d3fd03 | 121 | * DigitalOut cs(p8); // ssel |
lukofsky | 1:df1ae6d3fd03 | 122 | |
lukofsky | 1:df1ae6d3fd03 | 123 | * |
lukofsky | 1:df1ae6d3fd03 | 124 | |
lukofsky | 1:df1ae6d3fd03 | 125 | * int main() { |
lukofsky | 1:df1ae6d3fd03 | 126 | |
lukofsky | 1:df1ae6d3fd03 | 127 | * // hardware ssel (where applicable) |
lukofsky | 1:df1ae6d3fd03 | 128 | |
lukofsky | 1:df1ae6d3fd03 | 129 | * //int response = device.write(0xFF); |
lukofsky | 1:df1ae6d3fd03 | 130 | |
lukofsky | 1:df1ae6d3fd03 | 131 | * |
lukofsky | 1:df1ae6d3fd03 | 132 | |
lukofsky | 1:df1ae6d3fd03 | 133 | * device.lock(); |
lukofsky | 1:df1ae6d3fd03 | 134 | |
lukofsky | 1:df1ae6d3fd03 | 135 | * // software ssel |
lukofsky | 1:df1ae6d3fd03 | 136 | |
lukofsky | 1:df1ae6d3fd03 | 137 | * cs = 0; |
lukofsky | 1:df1ae6d3fd03 | 138 | |
lukofsky | 1:df1ae6d3fd03 | 139 | * int response = device.write(0xFF); |
lukofsky | 1:df1ae6d3fd03 | 140 | |
lukofsky | 1:df1ae6d3fd03 | 141 | * cs = 1; |
lukofsky | 1:df1ae6d3fd03 | 142 | |
lukofsky | 1:df1ae6d3fd03 | 143 | * device.unlock(); |
lukofsky | 1:df1ae6d3fd03 | 144 | |
lukofsky | 1:df1ae6d3fd03 | 145 | * |
lukofsky | 1:df1ae6d3fd03 | 146 | |
lukofsky | 1:df1ae6d3fd03 | 147 | * } |
lukofsky | 1:df1ae6d3fd03 | 148 | |
lukofsky | 1:df1ae6d3fd03 | 149 | * @endcode |
lukofsky | 1:df1ae6d3fd03 | 150 | |
lukofsky | 1:df1ae6d3fd03 | 151 | * @ingroup drivers |
lukofsky | 1:df1ae6d3fd03 | 152 | |
lukofsky | 1:df1ae6d3fd03 | 153 | */ |
lukofsky | 1:df1ae6d3fd03 | 154 | |
lukofsky | 1:df1ae6d3fd03 | 155 | class SPI : private NonCopyable<SPI> { |
lukofsky | 1:df1ae6d3fd03 | 156 | |
lukofsky | 1:df1ae6d3fd03 | 157 | |
lukofsky | 1:df1ae6d3fd03 | 158 | |
lukofsky | 1:df1ae6d3fd03 | 159 | public: |
lukofsky | 1:df1ae6d3fd03 | 160 | |
lukofsky | 1:df1ae6d3fd03 | 161 | |
lukofsky | 1:df1ae6d3fd03 | 162 | |
lukofsky | 1:df1ae6d3fd03 | 163 | /** Create a SPI master connected to the specified pins |
lukofsky | 1:df1ae6d3fd03 | 164 | |
lukofsky | 1:df1ae6d3fd03 | 165 | * |
lukofsky | 1:df1ae6d3fd03 | 166 | |
lukofsky | 1:df1ae6d3fd03 | 167 | * mosi or miso can be specified as NC if not used |
lukofsky | 1:df1ae6d3fd03 | 168 | |
lukofsky | 1:df1ae6d3fd03 | 169 | * |
lukofsky | 1:df1ae6d3fd03 | 170 | |
lukofsky | 1:df1ae6d3fd03 | 171 | * @param mosi SPI Master Out, Slave In pin |
lukofsky | 1:df1ae6d3fd03 | 172 | |
lukofsky | 1:df1ae6d3fd03 | 173 | * @param miso SPI Master In, Slave Out pin |
lukofsky | 1:df1ae6d3fd03 | 174 | |
lukofsky | 1:df1ae6d3fd03 | 175 | * @param sclk SPI Clock pin |
lukofsky | 1:df1ae6d3fd03 | 176 | |
lukofsky | 1:df1ae6d3fd03 | 177 | * @param ssel SPI chip select pin |
lukofsky | 1:df1ae6d3fd03 | 178 | |
lukofsky | 1:df1ae6d3fd03 | 179 | */ |
lukofsky | 1:df1ae6d3fd03 | 180 | |
lukofsky | 1:df1ae6d3fd03 | 181 | SPI(PinName mosi, PinName miso, PinName sclk, PinName ssel = NC); |
lukofsky | 1:df1ae6d3fd03 | 182 | |
lukofsky | 1:df1ae6d3fd03 | 183 | |
lukofsky | 1:df1ae6d3fd03 | 184 | |
lukofsky | 1:df1ae6d3fd03 | 185 | /** Configure the data transmission format |
lukofsky | 1:df1ae6d3fd03 | 186 | |
lukofsky | 1:df1ae6d3fd03 | 187 | * |
lukofsky | 1:df1ae6d3fd03 | 188 | |
lukofsky | 1:df1ae6d3fd03 | 189 | * @param bits Number of bits per SPI frame (4 - 16) |
lukofsky | 1:df1ae6d3fd03 | 190 | |
lukofsky | 1:df1ae6d3fd03 | 191 | * @param mode Clock polarity and phase mode (0 - 3) |
lukofsky | 1:df1ae6d3fd03 | 192 | |
lukofsky | 1:df1ae6d3fd03 | 193 | * |
lukofsky | 1:df1ae6d3fd03 | 194 | |
lukofsky | 1:df1ae6d3fd03 | 195 | * @code |
lukofsky | 1:df1ae6d3fd03 | 196 | |
lukofsky | 1:df1ae6d3fd03 | 197 | * mode | POL PHA |
lukofsky | 1:df1ae6d3fd03 | 198 | |
lukofsky | 1:df1ae6d3fd03 | 199 | * -----+-------- |
lukofsky | 1:df1ae6d3fd03 | 200 | |
lukofsky | 1:df1ae6d3fd03 | 201 | * 0 | 0 0 |
lukofsky | 1:df1ae6d3fd03 | 202 | |
lukofsky | 1:df1ae6d3fd03 | 203 | * 1 | 0 1 |
lukofsky | 1:df1ae6d3fd03 | 204 | |
lukofsky | 1:df1ae6d3fd03 | 205 | * 2 | 1 0 |
lukofsky | 1:df1ae6d3fd03 | 206 | |
lukofsky | 1:df1ae6d3fd03 | 207 | * 3 | 1 1 |
lukofsky | 1:df1ae6d3fd03 | 208 | |
lukofsky | 1:df1ae6d3fd03 | 209 | * @endcode |
lukofsky | 1:df1ae6d3fd03 | 210 | |
lukofsky | 1:df1ae6d3fd03 | 211 | */ |
lukofsky | 1:df1ae6d3fd03 | 212 | |
lukofsky | 1:df1ae6d3fd03 | 213 | void format(int bits, int mode = 0); |
lukofsky | 1:df1ae6d3fd03 | 214 | |
lukofsky | 1:df1ae6d3fd03 | 215 | |
lukofsky | 1:df1ae6d3fd03 | 216 | |
lukofsky | 1:df1ae6d3fd03 | 217 | /** Set the spi bus clock frequency |
lukofsky | 1:df1ae6d3fd03 | 218 | |
lukofsky | 1:df1ae6d3fd03 | 219 | * |
lukofsky | 1:df1ae6d3fd03 | 220 | |
lukofsky | 1:df1ae6d3fd03 | 221 | * @param hz SCLK frequency in hz (default = 1MHz) |
lukofsky | 1:df1ae6d3fd03 | 222 | |
lukofsky | 1:df1ae6d3fd03 | 223 | */ |
lukofsky | 1:df1ae6d3fd03 | 224 | |
lukofsky | 1:df1ae6d3fd03 | 225 | void frequency(int hz = 1000000); |
lukofsky | 1:df1ae6d3fd03 | 226 | |
lukofsky | 1:df1ae6d3fd03 | 227 | |
lukofsky | 1:df1ae6d3fd03 | 228 | |
lukofsky | 1:df1ae6d3fd03 | 229 | /** Write to the SPI Slave and return the response |
lukofsky | 1:df1ae6d3fd03 | 230 | |
lukofsky | 1:df1ae6d3fd03 | 231 | * |
lukofsky | 1:df1ae6d3fd03 | 232 | |
lukofsky | 1:df1ae6d3fd03 | 233 | * @param value Data to be sent to the SPI slave |
lukofsky | 1:df1ae6d3fd03 | 234 | |
lukofsky | 1:df1ae6d3fd03 | 235 | * |
lukofsky | 1:df1ae6d3fd03 | 236 | |
lukofsky | 1:df1ae6d3fd03 | 237 | * @returns |
lukofsky | 1:df1ae6d3fd03 | 238 | |
lukofsky | 1:df1ae6d3fd03 | 239 | * Response from the SPI slave |
lukofsky | 1:df1ae6d3fd03 | 240 | |
lukofsky | 1:df1ae6d3fd03 | 241 | */ |
lukofsky | 1:df1ae6d3fd03 | 242 | |
lukofsky | 1:df1ae6d3fd03 | 243 | virtual int write(int value); |
lukofsky | 1:df1ae6d3fd03 | 244 | |
lukofsky | 1:df1ae6d3fd03 | 245 | |
lukofsky | 1:df1ae6d3fd03 | 246 | |
lukofsky | 1:df1ae6d3fd03 | 247 | /** Write to the SPI Slave and obtain the response |
lukofsky | 1:df1ae6d3fd03 | 248 | |
lukofsky | 1:df1ae6d3fd03 | 249 | * |
lukofsky | 1:df1ae6d3fd03 | 250 | |
lukofsky | 1:df1ae6d3fd03 | 251 | * The total number of bytes sent and received will be the maximum of |
lukofsky | 1:df1ae6d3fd03 | 252 | |
lukofsky | 1:df1ae6d3fd03 | 253 | * tx_length and rx_length. The bytes written will be padded with the |
lukofsky | 1:df1ae6d3fd03 | 254 | |
lukofsky | 1:df1ae6d3fd03 | 255 | * value 0xff. |
lukofsky | 1:df1ae6d3fd03 | 256 | |
lukofsky | 1:df1ae6d3fd03 | 257 | * |
lukofsky | 1:df1ae6d3fd03 | 258 | |
lukofsky | 1:df1ae6d3fd03 | 259 | * @param tx_buffer Pointer to the byte-array of data to write to the device |
lukofsky | 1:df1ae6d3fd03 | 260 | |
lukofsky | 1:df1ae6d3fd03 | 261 | * @param tx_length Number of bytes to write, may be zero |
lukofsky | 1:df1ae6d3fd03 | 262 | |
lukofsky | 1:df1ae6d3fd03 | 263 | * @param rx_buffer Pointer to the byte-array of data to read from the device |
lukofsky | 1:df1ae6d3fd03 | 264 | |
lukofsky | 1:df1ae6d3fd03 | 265 | * @param rx_length Number of bytes to read, may be zero |
lukofsky | 1:df1ae6d3fd03 | 266 | |
lukofsky | 1:df1ae6d3fd03 | 267 | * @returns |
lukofsky | 1:df1ae6d3fd03 | 268 | |
lukofsky | 1:df1ae6d3fd03 | 269 | * The number of bytes written and read from the device. This is |
lukofsky | 1:df1ae6d3fd03 | 270 | |
lukofsky | 1:df1ae6d3fd03 | 271 | * maximum of tx_length and rx_length. |
lukofsky | 1:df1ae6d3fd03 | 272 | |
lukofsky | 1:df1ae6d3fd03 | 273 | */ |
lukofsky | 1:df1ae6d3fd03 | 274 | |
lukofsky | 1:df1ae6d3fd03 | 275 | virtual int write(const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length); |
lukofsky | 1:df1ae6d3fd03 | 276 | |
lukofsky | 1:df1ae6d3fd03 | 277 | |
lukofsky | 1:df1ae6d3fd03 | 278 | |
lukofsky | 1:df1ae6d3fd03 | 279 | /** Acquire exclusive access to this SPI bus |
lukofsky | 1:df1ae6d3fd03 | 280 | |
lukofsky | 1:df1ae6d3fd03 | 281 | */ |
lukofsky | 1:df1ae6d3fd03 | 282 | |
lukofsky | 1:df1ae6d3fd03 | 283 | virtual void lock(void); |
lukofsky | 1:df1ae6d3fd03 | 284 | |
lukofsky | 1:df1ae6d3fd03 | 285 | |
lukofsky | 1:df1ae6d3fd03 | 286 | |
lukofsky | 1:df1ae6d3fd03 | 287 | /** Release exclusive access to this SPI bus |
lukofsky | 1:df1ae6d3fd03 | 288 | |
lukofsky | 1:df1ae6d3fd03 | 289 | */ |
lukofsky | 1:df1ae6d3fd03 | 290 | |
lukofsky | 1:df1ae6d3fd03 | 291 | virtual void unlock(void); |
lukofsky | 1:df1ae6d3fd03 | 292 | |
lukofsky | 1:df1ae6d3fd03 | 293 | |
lukofsky | 1:df1ae6d3fd03 | 294 | |
lukofsky | 1:df1ae6d3fd03 | 295 | /** Set default write data |
lukofsky | 1:df1ae6d3fd03 | 296 | |
lukofsky | 1:df1ae6d3fd03 | 297 | * SPI requires the master to send some data during a read operation. |
lukofsky | 1:df1ae6d3fd03 | 298 | |
lukofsky | 1:df1ae6d3fd03 | 299 | * Different devices may require different default byte values. |
lukofsky | 1:df1ae6d3fd03 | 300 | |
lukofsky | 1:df1ae6d3fd03 | 301 | * For example: A SD Card requires default bytes to be 0xFF. |
lukofsky | 1:df1ae6d3fd03 | 302 | |
lukofsky | 1:df1ae6d3fd03 | 303 | * |
lukofsky | 1:df1ae6d3fd03 | 304 | |
lukofsky | 1:df1ae6d3fd03 | 305 | * @param data Default character to be transmitted while read operation |
lukofsky | 1:df1ae6d3fd03 | 306 | |
lukofsky | 1:df1ae6d3fd03 | 307 | */ |
lukofsky | 1:df1ae6d3fd03 | 308 | |
lukofsky | 1:df1ae6d3fd03 | 309 | void set_default_write_value(char data); |
lukofsky | 1:df1ae6d3fd03 | 310 | |
lukofsky | 1:df1ae6d3fd03 | 311 | |
lukofsky | 1:df1ae6d3fd03 | 312 | |
lukofsky | 1:df1ae6d3fd03 | 313 | #if DEVICE_SPI_ASYNCH |
lukofsky | 1:df1ae6d3fd03 | 314 | |
lukofsky | 1:df1ae6d3fd03 | 315 | |
lukofsky | 1:df1ae6d3fd03 | 316 | |
lukofsky | 1:df1ae6d3fd03 | 317 | /** Start non-blocking SPI transfer using 8bit buffers. |
lukofsky | 1:df1ae6d3fd03 | 318 | |
lukofsky | 1:df1ae6d3fd03 | 319 | * |
lukofsky | 1:df1ae6d3fd03 | 320 | |
lukofsky | 1:df1ae6d3fd03 | 321 | * This function locks the deep sleep until any event has occurred |
lukofsky | 1:df1ae6d3fd03 | 322 | |
lukofsky | 1:df1ae6d3fd03 | 323 | * |
lukofsky | 1:df1ae6d3fd03 | 324 | |
lukofsky | 1:df1ae6d3fd03 | 325 | * @param tx_buffer The TX buffer with data to be transfered. If NULL is passed, |
lukofsky | 1:df1ae6d3fd03 | 326 | |
lukofsky | 1:df1ae6d3fd03 | 327 | * the default SPI value is sent |
lukofsky | 1:df1ae6d3fd03 | 328 | |
lukofsky | 1:df1ae6d3fd03 | 329 | * @param tx_length The length of TX buffer in bytes |
lukofsky | 1:df1ae6d3fd03 | 330 | |
lukofsky | 1:df1ae6d3fd03 | 331 | * @param rx_buffer The RX buffer which is used for received data. If NULL is passed, |
lukofsky | 1:df1ae6d3fd03 | 332 | |
lukofsky | 1:df1ae6d3fd03 | 333 | * received data are ignored |
lukofsky | 1:df1ae6d3fd03 | 334 | |
lukofsky | 1:df1ae6d3fd03 | 335 | * @param rx_length The length of RX buffer in bytes |
lukofsky | 1:df1ae6d3fd03 | 336 | |
lukofsky | 1:df1ae6d3fd03 | 337 | * @param callback The event callback function |
lukofsky | 1:df1ae6d3fd03 | 338 | |
lukofsky | 1:df1ae6d3fd03 | 339 | * @param event The logical OR of events to modify. Look at spi hal header file for SPI events. |
lukofsky | 1:df1ae6d3fd03 | 340 | |
lukofsky | 1:df1ae6d3fd03 | 341 | * @return Zero if the transfer has started, or -1 if SPI peripheral is busy |
lukofsky | 1:df1ae6d3fd03 | 342 | |
lukofsky | 1:df1ae6d3fd03 | 343 | */ |
lukofsky | 1:df1ae6d3fd03 | 344 | |
lukofsky | 1:df1ae6d3fd03 | 345 | template<typename Type> |
lukofsky | 1:df1ae6d3fd03 | 346 | |
lukofsky | 1:df1ae6d3fd03 | 347 | int transfer(const Type *tx_buffer, int tx_length, Type *rx_buffer, int rx_length, const event_callback_t &callback, int event = SPI_EVENT_COMPLETE) |
lukofsky | 1:df1ae6d3fd03 | 348 | |
lukofsky | 1:df1ae6d3fd03 | 349 | { |
lukofsky | 1:df1ae6d3fd03 | 350 | |
lukofsky | 1:df1ae6d3fd03 | 351 | if (spi_active(&_spi)) { |
lukofsky | 1:df1ae6d3fd03 | 352 | |
lukofsky | 1:df1ae6d3fd03 | 353 | return queue_transfer(tx_buffer, tx_length, rx_buffer, rx_length, sizeof(Type) * 8, callback, event); |
lukofsky | 1:df1ae6d3fd03 | 354 | |
lukofsky | 1:df1ae6d3fd03 | 355 | } |
lukofsky | 1:df1ae6d3fd03 | 356 | |
lukofsky | 1:df1ae6d3fd03 | 357 | start_transfer(tx_buffer, tx_length, rx_buffer, rx_length, sizeof(Type) * 8, callback, event); |
lukofsky | 1:df1ae6d3fd03 | 358 | |
lukofsky | 1:df1ae6d3fd03 | 359 | return 0; |
lukofsky | 1:df1ae6d3fd03 | 360 | |
lukofsky | 1:df1ae6d3fd03 | 361 | } |
lukofsky | 1:df1ae6d3fd03 | 362 | |
lukofsky | 1:df1ae6d3fd03 | 363 | |
lukofsky | 1:df1ae6d3fd03 | 364 | |
lukofsky | 1:df1ae6d3fd03 | 365 | /** Abort the on-going SPI transfer, and continue with transfer's in the queue if any. |
lukofsky | 1:df1ae6d3fd03 | 366 | |
lukofsky | 1:df1ae6d3fd03 | 367 | */ |
lukofsky | 1:df1ae6d3fd03 | 368 | |
lukofsky | 1:df1ae6d3fd03 | 369 | void abort_transfer(); |
lukofsky | 1:df1ae6d3fd03 | 370 | |
lukofsky | 1:df1ae6d3fd03 | 371 | |
lukofsky | 1:df1ae6d3fd03 | 372 | |
lukofsky | 1:df1ae6d3fd03 | 373 | /** Clear the transaction buffer |
lukofsky | 1:df1ae6d3fd03 | 374 | |
lukofsky | 1:df1ae6d3fd03 | 375 | */ |
lukofsky | 1:df1ae6d3fd03 | 376 | |
lukofsky | 1:df1ae6d3fd03 | 377 | void clear_transfer_buffer(); |
lukofsky | 1:df1ae6d3fd03 | 378 | |
lukofsky | 1:df1ae6d3fd03 | 379 | |
lukofsky | 1:df1ae6d3fd03 | 380 | |
lukofsky | 1:df1ae6d3fd03 | 381 | /** Clear the transaction buffer and abort on-going transfer. |
lukofsky | 1:df1ae6d3fd03 | 382 | |
lukofsky | 1:df1ae6d3fd03 | 383 | */ |
lukofsky | 1:df1ae6d3fd03 | 384 | |
lukofsky | 1:df1ae6d3fd03 | 385 | void abort_all_transfers(); |
lukofsky | 1:df1ae6d3fd03 | 386 | |
lukofsky | 1:df1ae6d3fd03 | 387 | |
lukofsky | 1:df1ae6d3fd03 | 388 | |
lukofsky | 1:df1ae6d3fd03 | 389 | /** Configure DMA usage suggestion for non-blocking transfers |
lukofsky | 1:df1ae6d3fd03 | 390 | |
lukofsky | 1:df1ae6d3fd03 | 391 | * |
lukofsky | 1:df1ae6d3fd03 | 392 | |
lukofsky | 1:df1ae6d3fd03 | 393 | * @param usage The usage DMA hint for peripheral |
lukofsky | 1:df1ae6d3fd03 | 394 | |
lukofsky | 1:df1ae6d3fd03 | 395 | * @return Zero if the usage was set, -1 if a transaction is on-going |
lukofsky | 1:df1ae6d3fd03 | 396 | |
lukofsky | 1:df1ae6d3fd03 | 397 | */ |
lukofsky | 1:df1ae6d3fd03 | 398 | |
lukofsky | 1:df1ae6d3fd03 | 399 | int set_dma_usage(DMAUsage usage); |
lukofsky | 1:df1ae6d3fd03 | 400 | |
lukofsky | 1:df1ae6d3fd03 | 401 | |
lukofsky | 1:df1ae6d3fd03 | 402 | |
lukofsky | 1:df1ae6d3fd03 | 403 | protected: |
lukofsky | 1:df1ae6d3fd03 | 404 | |
lukofsky | 1:df1ae6d3fd03 | 405 | /** SPI IRQ handler |
lukofsky | 1:df1ae6d3fd03 | 406 | |
lukofsky | 1:df1ae6d3fd03 | 407 | * |
lukofsky | 1:df1ae6d3fd03 | 408 | |
lukofsky | 1:df1ae6d3fd03 | 409 | */ |
lukofsky | 1:df1ae6d3fd03 | 410 | |
lukofsky | 1:df1ae6d3fd03 | 411 | void irq_handler_asynch(void); |
lukofsky | 1:df1ae6d3fd03 | 412 | |
lukofsky | 1:df1ae6d3fd03 | 413 | |
lukofsky | 1:df1ae6d3fd03 | 414 | |
lukofsky | 1:df1ae6d3fd03 | 415 | /** Common transfer method |
lukofsky | 1:df1ae6d3fd03 | 416 | |
lukofsky | 1:df1ae6d3fd03 | 417 | * |
lukofsky | 1:df1ae6d3fd03 | 418 | |
lukofsky | 1:df1ae6d3fd03 | 419 | * @param tx_buffer The TX buffer with data to be transfered. If NULL is passed, |
lukofsky | 1:df1ae6d3fd03 | 420 | |
lukofsky | 1:df1ae6d3fd03 | 421 | * the default SPI value is sent |
lukofsky | 1:df1ae6d3fd03 | 422 | |
lukofsky | 1:df1ae6d3fd03 | 423 | * @param tx_length The length of TX buffer in bytes |
lukofsky | 1:df1ae6d3fd03 | 424 | |
lukofsky | 1:df1ae6d3fd03 | 425 | * @param rx_buffer The RX buffer which is used for received data. If NULL is passed, |
lukofsky | 1:df1ae6d3fd03 | 426 | |
lukofsky | 1:df1ae6d3fd03 | 427 | * received data are ignored |
lukofsky | 1:df1ae6d3fd03 | 428 | |
lukofsky | 1:df1ae6d3fd03 | 429 | * @param rx_length The length of RX buffer in bytes |
lukofsky | 1:df1ae6d3fd03 | 430 | |
lukofsky | 1:df1ae6d3fd03 | 431 | * @param bit_width The buffers element width |
lukofsky | 1:df1ae6d3fd03 | 432 | |
lukofsky | 1:df1ae6d3fd03 | 433 | * @param callback The event callback function |
lukofsky | 1:df1ae6d3fd03 | 434 | |
lukofsky | 1:df1ae6d3fd03 | 435 | * @param event The logical OR of events to modify |
lukofsky | 1:df1ae6d3fd03 | 436 | |
lukofsky | 1:df1ae6d3fd03 | 437 | * @return Zero if the transfer has started or was added to the queue, or -1 if SPI peripheral is busy/buffer is full |
lukofsky | 1:df1ae6d3fd03 | 438 | |
lukofsky | 1:df1ae6d3fd03 | 439 | */ |
lukofsky | 1:df1ae6d3fd03 | 440 | |
lukofsky | 1:df1ae6d3fd03 | 441 | int transfer(const void *tx_buffer, int tx_length, void *rx_buffer, int rx_length, unsigned char bit_width, const event_callback_t &callback, int event); |
lukofsky | 1:df1ae6d3fd03 | 442 | |
lukofsky | 1:df1ae6d3fd03 | 443 | |
lukofsky | 1:df1ae6d3fd03 | 444 | |
lukofsky | 1:df1ae6d3fd03 | 445 | /** |
lukofsky | 1:df1ae6d3fd03 | 446 | |
lukofsky | 1:df1ae6d3fd03 | 447 | * |
lukofsky | 1:df1ae6d3fd03 | 448 | |
lukofsky | 1:df1ae6d3fd03 | 449 | * @param tx_buffer The TX buffer with data to be transfered. If NULL is passed, |
lukofsky | 1:df1ae6d3fd03 | 450 | |
lukofsky | 1:df1ae6d3fd03 | 451 | * the default SPI value is sent |
lukofsky | 1:df1ae6d3fd03 | 452 | |
lukofsky | 1:df1ae6d3fd03 | 453 | * @param tx_length The length of TX buffer in bytes |
lukofsky | 1:df1ae6d3fd03 | 454 | |
lukofsky | 1:df1ae6d3fd03 | 455 | * @param rx_buffer The RX buffer which is used for received data. If NULL is passed, |
lukofsky | 1:df1ae6d3fd03 | 456 | |
lukofsky | 1:df1ae6d3fd03 | 457 | * received data are ignored |
lukofsky | 1:df1ae6d3fd03 | 458 | |
lukofsky | 1:df1ae6d3fd03 | 459 | * @param rx_length The length of RX buffer in bytes |
lukofsky | 1:df1ae6d3fd03 | 460 | |
lukofsky | 1:df1ae6d3fd03 | 461 | * @param bit_width The buffers element width |
lukofsky | 1:df1ae6d3fd03 | 462 | |
lukofsky | 1:df1ae6d3fd03 | 463 | * @param callback The event callback function |
lukofsky | 1:df1ae6d3fd03 | 464 | |
lukofsky | 1:df1ae6d3fd03 | 465 | * @param event The logical OR of events to modify |
lukofsky | 1:df1ae6d3fd03 | 466 | |
lukofsky | 1:df1ae6d3fd03 | 467 | * @return Zero if a transfer was added to the queue, or -1 if the queue is full |
lukofsky | 1:df1ae6d3fd03 | 468 | |
lukofsky | 1:df1ae6d3fd03 | 469 | */ |
lukofsky | 1:df1ae6d3fd03 | 470 | |
lukofsky | 1:df1ae6d3fd03 | 471 | int queue_transfer(const void *tx_buffer, int tx_length, void *rx_buffer, int rx_length, unsigned char bit_width, const event_callback_t &callback, int event); |
lukofsky | 1:df1ae6d3fd03 | 472 | |
lukofsky | 1:df1ae6d3fd03 | 473 | |
lukofsky | 1:df1ae6d3fd03 | 474 | |
lukofsky | 1:df1ae6d3fd03 | 475 | /** Configures a callback, spi peripheral and initiate a new transfer |
lukofsky | 1:df1ae6d3fd03 | 476 | |
lukofsky | 1:df1ae6d3fd03 | 477 | * |
lukofsky | 1:df1ae6d3fd03 | 478 | |
lukofsky | 1:df1ae6d3fd03 | 479 | * @param tx_buffer The TX buffer with data to be transfered. If NULL is passed, |
lukofsky | 1:df1ae6d3fd03 | 480 | |
lukofsky | 1:df1ae6d3fd03 | 481 | * the default SPI value is sent |
lukofsky | 1:df1ae6d3fd03 | 482 | |
lukofsky | 1:df1ae6d3fd03 | 483 | * @param tx_length The length of TX buffer in bytes |
lukofsky | 1:df1ae6d3fd03 | 484 | |
lukofsky | 1:df1ae6d3fd03 | 485 | * @param rx_buffer The RX buffer which is used for received data. If NULL is passed, |
lukofsky | 1:df1ae6d3fd03 | 486 | |
lukofsky | 1:df1ae6d3fd03 | 487 | * received data are ignored |
lukofsky | 1:df1ae6d3fd03 | 488 | |
lukofsky | 1:df1ae6d3fd03 | 489 | * @param rx_length The length of RX buffer in bytes |
lukofsky | 1:df1ae6d3fd03 | 490 | |
lukofsky | 1:df1ae6d3fd03 | 491 | * @param bit_width The buffers element width |
lukofsky | 1:df1ae6d3fd03 | 492 | |
lukofsky | 1:df1ae6d3fd03 | 493 | * @param callback The event callback function |
lukofsky | 1:df1ae6d3fd03 | 494 | |
lukofsky | 1:df1ae6d3fd03 | 495 | * @param event The logical OR of events to modify |
lukofsky | 1:df1ae6d3fd03 | 496 | |
lukofsky | 1:df1ae6d3fd03 | 497 | */ |
lukofsky | 1:df1ae6d3fd03 | 498 | |
lukofsky | 1:df1ae6d3fd03 | 499 | void start_transfer(const void *tx_buffer, int tx_length, void *rx_buffer, int rx_length, unsigned char bit_width, const event_callback_t &callback, int event); |
lukofsky | 1:df1ae6d3fd03 | 500 | |
lukofsky | 1:df1ae6d3fd03 | 501 | |
lukofsky | 1:df1ae6d3fd03 | 502 | |
lukofsky | 1:df1ae6d3fd03 | 503 | private: |
lukofsky | 1:df1ae6d3fd03 | 504 | |
lukofsky | 1:df1ae6d3fd03 | 505 | /** Lock deep sleep only if it is not yet locked */ |
lukofsky | 1:df1ae6d3fd03 | 506 | |
lukofsky | 1:df1ae6d3fd03 | 507 | void lock_deep_sleep(); |
lukofsky | 1:df1ae6d3fd03 | 508 | |
lukofsky | 1:df1ae6d3fd03 | 509 | |
lukofsky | 1:df1ae6d3fd03 | 510 | |
lukofsky | 1:df1ae6d3fd03 | 511 | /** Unlock deep sleep in case it is locked */ |
lukofsky | 1:df1ae6d3fd03 | 512 | |
lukofsky | 1:df1ae6d3fd03 | 513 | void unlock_deep_sleep(); |
lukofsky | 1:df1ae6d3fd03 | 514 | |
lukofsky | 1:df1ae6d3fd03 | 515 | |
lukofsky | 1:df1ae6d3fd03 | 516 | |
lukofsky | 1:df1ae6d3fd03 | 517 | |
lukofsky | 1:df1ae6d3fd03 | 518 | |
lukofsky | 1:df1ae6d3fd03 | 519 | #if TRANSACTION_QUEUE_SIZE_SPI |
lukofsky | 1:df1ae6d3fd03 | 520 | |
lukofsky | 1:df1ae6d3fd03 | 521 | |
lukofsky | 1:df1ae6d3fd03 | 522 | |
lukofsky | 1:df1ae6d3fd03 | 523 | /** Start a new transaction |
lukofsky | 1:df1ae6d3fd03 | 524 | |
lukofsky | 1:df1ae6d3fd03 | 525 | * |
lukofsky | 1:df1ae6d3fd03 | 526 | |
lukofsky | 1:df1ae6d3fd03 | 527 | * @param data Transaction data |
lukofsky | 1:df1ae6d3fd03 | 528 | |
lukofsky | 1:df1ae6d3fd03 | 529 | */ |
lukofsky | 1:df1ae6d3fd03 | 530 | |
lukofsky | 1:df1ae6d3fd03 | 531 | void start_transaction(transaction_t *data); |
lukofsky | 1:df1ae6d3fd03 | 532 | |
lukofsky | 1:df1ae6d3fd03 | 533 | |
lukofsky | 1:df1ae6d3fd03 | 534 | |
lukofsky | 1:df1ae6d3fd03 | 535 | /** Dequeue a transaction |
lukofsky | 1:df1ae6d3fd03 | 536 | |
lukofsky | 1:df1ae6d3fd03 | 537 | * |
lukofsky | 1:df1ae6d3fd03 | 538 | |
lukofsky | 1:df1ae6d3fd03 | 539 | */ |
lukofsky | 1:df1ae6d3fd03 | 540 | |
lukofsky | 1:df1ae6d3fd03 | 541 | void dequeue_transaction(); |
lukofsky | 1:df1ae6d3fd03 | 542 | |
lukofsky | 1:df1ae6d3fd03 | 543 | static CircularBuffer<Transaction<SPI>, TRANSACTION_QUEUE_SIZE_SPI> _transaction_buffer; |
lukofsky | 1:df1ae6d3fd03 | 544 | |
lukofsky | 1:df1ae6d3fd03 | 545 | #endif |
lukofsky | 1:df1ae6d3fd03 | 546 | |
lukofsky | 1:df1ae6d3fd03 | 547 | |
lukofsky | 1:df1ae6d3fd03 | 548 | |
lukofsky | 1:df1ae6d3fd03 | 549 | #endif |
lukofsky | 1:df1ae6d3fd03 | 550 | |
lukofsky | 1:df1ae6d3fd03 | 551 | |
lukofsky | 1:df1ae6d3fd03 | 552 | |
lukofsky | 1:df1ae6d3fd03 | 553 | public: |
lukofsky | 1:df1ae6d3fd03 | 554 | |
lukofsky | 1:df1ae6d3fd03 | 555 | virtual ~SPI() |
lukofsky | 1:df1ae6d3fd03 | 556 | |
lukofsky | 1:df1ae6d3fd03 | 557 | { |
lukofsky | 1:df1ae6d3fd03 | 558 | |
lukofsky | 1:df1ae6d3fd03 | 559 | } |
lukofsky | 1:df1ae6d3fd03 | 560 | |
lukofsky | 1:df1ae6d3fd03 | 561 | |
lukofsky | 1:df1ae6d3fd03 | 562 | |
lukofsky | 1:df1ae6d3fd03 | 563 | protected: |
lukofsky | 1:df1ae6d3fd03 | 564 | |
lukofsky | 1:df1ae6d3fd03 | 565 | spi_t _spi; |
lukofsky | 1:df1ae6d3fd03 | 566 | |
lukofsky | 1:df1ae6d3fd03 | 567 | |
lukofsky | 1:df1ae6d3fd03 | 568 | |
lukofsky | 1:df1ae6d3fd03 | 569 | #if DEVICE_SPI_ASYNCH |
lukofsky | 1:df1ae6d3fd03 | 570 | |
lukofsky | 1:df1ae6d3fd03 | 571 | CThunk<SPI> _irq; |
lukofsky | 1:df1ae6d3fd03 | 572 | |
lukofsky | 1:df1ae6d3fd03 | 573 | event_callback_t _callback; |
lukofsky | 1:df1ae6d3fd03 | 574 | |
lukofsky | 1:df1ae6d3fd03 | 575 | DMAUsage _usage; |
lukofsky | 1:df1ae6d3fd03 | 576 | |
lukofsky | 1:df1ae6d3fd03 | 577 | bool _deep_sleep_locked; |
lukofsky | 1:df1ae6d3fd03 | 578 | |
lukofsky | 1:df1ae6d3fd03 | 579 | #endif |
lukofsky | 1:df1ae6d3fd03 | 580 | |
lukofsky | 1:df1ae6d3fd03 | 581 | |
lukofsky | 1:df1ae6d3fd03 | 582 | |
lukofsky | 1:df1ae6d3fd03 | 583 | void aquire(void); |
lukofsky | 1:df1ae6d3fd03 | 584 | |
lukofsky | 1:df1ae6d3fd03 | 585 | static SPI *_owner; |
lukofsky | 1:df1ae6d3fd03 | 586 | |
lukofsky | 1:df1ae6d3fd03 | 587 | static SingletonPtr<PlatformMutex> _mutex; |
lukofsky | 1:df1ae6d3fd03 | 588 | |
lukofsky | 1:df1ae6d3fd03 | 589 | int _bits; |
lukofsky | 1:df1ae6d3fd03 | 590 | |
lukofsky | 1:df1ae6d3fd03 | 591 | int _mode; |
lukofsky | 1:df1ae6d3fd03 | 592 | |
lukofsky | 1:df1ae6d3fd03 | 593 | int _hz; |
lukofsky | 1:df1ae6d3fd03 | 594 | |
lukofsky | 1:df1ae6d3fd03 | 595 | char _write_fill; |
lukofsky | 1:df1ae6d3fd03 | 596 | |
lukofsky | 1:df1ae6d3fd03 | 597 | |
lukofsky | 1:df1ae6d3fd03 | 598 | |
lukofsky | 1:df1ae6d3fd03 | 599 | private: |
lukofsky | 1:df1ae6d3fd03 | 600 | |
lukofsky | 1:df1ae6d3fd03 | 601 | /* Private acquire function without locking/unlocking |
lukofsky | 1:df1ae6d3fd03 | 602 | |
lukofsky | 1:df1ae6d3fd03 | 603 | * Implemented in order to avoid duplicate locking and boost performance |
lukofsky | 1:df1ae6d3fd03 | 604 | |
lukofsky | 1:df1ae6d3fd03 | 605 | */ |
lukofsky | 1:df1ae6d3fd03 | 606 | |
lukofsky | 1:df1ae6d3fd03 | 607 | void _acquire(void); |
lukofsky | 1:df1ae6d3fd03 | 608 | |
lukofsky | 1:df1ae6d3fd03 | 609 | }; |
lukofsky | 1:df1ae6d3fd03 | 610 | |
lukofsky | 1:df1ae6d3fd03 | 611 | |
lukofsky | 1:df1ae6d3fd03 | 612 | |
lukofsky | 1:df1ae6d3fd03 | 613 | } // namespace mbed |
lukofsky | 1:df1ae6d3fd03 | 614 | |
lukofsky | 1:df1ae6d3fd03 | 615 | |
lukofsky | 1:df1ae6d3fd03 | 616 | |
lukofsky | 1:df1ae6d3fd03 | 617 | #endif |
lukofsky | 1:df1ae6d3fd03 | 618 | |
lukofsky | 1:df1ae6d3fd03 | 619 | |
lukofsky | 1:df1ae6d3fd03 | 620 | |
lukofsky | 1:df1ae6d3fd03 | 621 | #endif |