Disco-L475VG-IOT / wifi-ism43362
Committer:
marcel1691
Date:
Wed Oct 03 14:03:01 2018 +0000
Revision:
0:62e55edab701
WiFi ISM43363

Who changed what in which revision?

UserRevisionLine numberNew contents of line
marcel1691 0:62e55edab701 1 /**
marcel1691 0:62e55edab701 2 * @file BufferedSpi.cpp
marcel1691 0:62e55edab701 3 * @brief Software Buffer - Extends mbed SPI functionallity
marcel1691 0:62e55edab701 4 * @author Armelle Duboc
marcel1691 0:62e55edab701 5 * @version 1.0
marcel1691 0:62e55edab701 6 * @see
marcel1691 0:62e55edab701 7 *
marcel1691 0:62e55edab701 8 * Copyright (c) STMicroelectronics 2017
marcel1691 0:62e55edab701 9 *
marcel1691 0:62e55edab701 10 * Licensed under the Apache License, Version 2.0 (the "License");
marcel1691 0:62e55edab701 11 * you may not use this file except in compliance with the License.
marcel1691 0:62e55edab701 12 * You may obtain a copy of the License at
marcel1691 0:62e55edab701 13 *
marcel1691 0:62e55edab701 14 * http://www.apache.org/licenses/LICENSE-2.0
marcel1691 0:62e55edab701 15 *
marcel1691 0:62e55edab701 16 * Unless required by applicable law or agreed to in writing, software
marcel1691 0:62e55edab701 17 * distributed under the License is distributed on an "AS IS" BASIS,
marcel1691 0:62e55edab701 18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
marcel1691 0:62e55edab701 19 * See the License for the specific language governing permissions and
marcel1691 0:62e55edab701 20 * limitations under the License.
marcel1691 0:62e55edab701 21 */
marcel1691 0:62e55edab701 22
marcel1691 0:62e55edab701 23 #include "BufferedSpi.h"
marcel1691 0:62e55edab701 24 #include <stdarg.h>
marcel1691 0:62e55edab701 25 #include "mbed_debug.h"
marcel1691 0:62e55edab701 26 #include "mbed_error.h"
marcel1691 0:62e55edab701 27
marcel1691 0:62e55edab701 28 // change to true to add few SPI debug lines
marcel1691 0:62e55edab701 29 #define local_debug false
marcel1691 0:62e55edab701 30
marcel1691 0:62e55edab701 31 extern "C" int BufferedPrintfC(void *stream, int size, const char *format, va_list arg);
marcel1691 0:62e55edab701 32
marcel1691 0:62e55edab701 33 void BufferedSpi::DatareadyRising(void)
marcel1691 0:62e55edab701 34 {
marcel1691 0:62e55edab701 35 if (_cmddata_rdy_rising_event == 1) {
marcel1691 0:62e55edab701 36 _cmddata_rdy_rising_event = 0;
marcel1691 0:62e55edab701 37 }
marcel1691 0:62e55edab701 38 }
marcel1691 0:62e55edab701 39
marcel1691 0:62e55edab701 40 int BufferedSpi::wait_cmddata_rdy_high(void)
marcel1691 0:62e55edab701 41 {
marcel1691 0:62e55edab701 42 Timer timer;
marcel1691 0:62e55edab701 43 timer.start();
marcel1691 0:62e55edab701 44
marcel1691 0:62e55edab701 45 /* wait for dataready = 1 */
marcel1691 0:62e55edab701 46 while (dataready.read() == 0) {
marcel1691 0:62e55edab701 47 if (timer.read_ms() > _timeout) {
marcel1691 0:62e55edab701 48 debug_if(local_debug, "ERROR: SPI write timeout\r\n");
marcel1691 0:62e55edab701 49 return -1;
marcel1691 0:62e55edab701 50 }
marcel1691 0:62e55edab701 51 }
marcel1691 0:62e55edab701 52
marcel1691 0:62e55edab701 53 _cmddata_rdy_rising_event = 1;
marcel1691 0:62e55edab701 54
marcel1691 0:62e55edab701 55 return 0;
marcel1691 0:62e55edab701 56 }
marcel1691 0:62e55edab701 57
marcel1691 0:62e55edab701 58 int BufferedSpi::wait_cmddata_rdy_rising_event(void)
marcel1691 0:62e55edab701 59 {
marcel1691 0:62e55edab701 60 Timer timer;
marcel1691 0:62e55edab701 61 timer.start();
marcel1691 0:62e55edab701 62
marcel1691 0:62e55edab701 63 while (_cmddata_rdy_rising_event == 1) {
marcel1691 0:62e55edab701 64 if (timer.read_ms() > _timeout) {
marcel1691 0:62e55edab701 65 _cmddata_rdy_rising_event = 0;
marcel1691 0:62e55edab701 66 if (dataready.read() == 1) {
marcel1691 0:62e55edab701 67 debug_if(local_debug, "ERROR: We missed rising event !! (timemout=%d)\r\n", _timeout);
marcel1691 0:62e55edab701 68 }
marcel1691 0:62e55edab701 69 debug_if(local_debug, "ERROR: SPI read timeout\r\n");
marcel1691 0:62e55edab701 70 return -1;
marcel1691 0:62e55edab701 71 }
marcel1691 0:62e55edab701 72 }
marcel1691 0:62e55edab701 73
marcel1691 0:62e55edab701 74 return 0;
marcel1691 0:62e55edab701 75 }
marcel1691 0:62e55edab701 76
marcel1691 0:62e55edab701 77 BufferedSpi::BufferedSpi(PinName mosi, PinName miso, PinName sclk, PinName _nss, PinName _datareadypin,
marcel1691 0:62e55edab701 78 uint32_t buf_size, uint32_t tx_multiple, const char *name)
marcel1691 0:62e55edab701 79 : SPI(mosi, miso, sclk, NC), nss(_nss), _txbuf((uint32_t)(tx_multiple * buf_size)), _rxbuf(buf_size), dataready(_datareadypin)
marcel1691 0:62e55edab701 80 {
marcel1691 0:62e55edab701 81 this->_buf_size = buf_size;
marcel1691 0:62e55edab701 82 this->_tx_multiple = tx_multiple;
marcel1691 0:62e55edab701 83 this->_sigio_event = 0;
marcel1691 0:62e55edab701 84
marcel1691 0:62e55edab701 85 _datareadyInt = new InterruptIn(_datareadypin);
marcel1691 0:62e55edab701 86 _datareadyInt->rise(callback(this, &BufferedSpi::DatareadyRising));
marcel1691 0:62e55edab701 87
marcel1691 0:62e55edab701 88 _cmddata_rdy_rising_event = 1;
marcel1691 0:62e55edab701 89
marcel1691 0:62e55edab701 90 return;
marcel1691 0:62e55edab701 91 }
marcel1691 0:62e55edab701 92
marcel1691 0:62e55edab701 93 BufferedSpi::~BufferedSpi(void)
marcel1691 0:62e55edab701 94 {
marcel1691 0:62e55edab701 95
marcel1691 0:62e55edab701 96 return;
marcel1691 0:62e55edab701 97 }
marcel1691 0:62e55edab701 98
marcel1691 0:62e55edab701 99 void BufferedSpi::frequency(int hz)
marcel1691 0:62e55edab701 100 {
marcel1691 0:62e55edab701 101 SPI::frequency(hz);
marcel1691 0:62e55edab701 102 }
marcel1691 0:62e55edab701 103
marcel1691 0:62e55edab701 104 void BufferedSpi::format(int bits, int mode)
marcel1691 0:62e55edab701 105 {
marcel1691 0:62e55edab701 106 SPI::format(bits, mode);
marcel1691 0:62e55edab701 107 }
marcel1691 0:62e55edab701 108
marcel1691 0:62e55edab701 109 void BufferedSpi::disable_nss()
marcel1691 0:62e55edab701 110 {
marcel1691 0:62e55edab701 111 nss = 1;
marcel1691 0:62e55edab701 112 wait_us(15);
marcel1691 0:62e55edab701 113 }
marcel1691 0:62e55edab701 114
marcel1691 0:62e55edab701 115 void BufferedSpi::enable_nss()
marcel1691 0:62e55edab701 116 {
marcel1691 0:62e55edab701 117 nss = 0;
marcel1691 0:62e55edab701 118 wait_us(15);
marcel1691 0:62e55edab701 119 }
marcel1691 0:62e55edab701 120
marcel1691 0:62e55edab701 121 int BufferedSpi::readable(void)
marcel1691 0:62e55edab701 122 {
marcel1691 0:62e55edab701 123 return _rxbuf.available(); // note: look if things are in the buffer
marcel1691 0:62e55edab701 124 }
marcel1691 0:62e55edab701 125
marcel1691 0:62e55edab701 126 int BufferedSpi::writeable(void)
marcel1691 0:62e55edab701 127 {
marcel1691 0:62e55edab701 128 return 1; // buffer allows overwriting by design, always true
marcel1691 0:62e55edab701 129 }
marcel1691 0:62e55edab701 130
marcel1691 0:62e55edab701 131 int BufferedSpi::getc(void)
marcel1691 0:62e55edab701 132 {
marcel1691 0:62e55edab701 133 if (_rxbuf.available()) {
marcel1691 0:62e55edab701 134 return _rxbuf;
marcel1691 0:62e55edab701 135 } else {
marcel1691 0:62e55edab701 136 return -1;
marcel1691 0:62e55edab701 137 }
marcel1691 0:62e55edab701 138 }
marcel1691 0:62e55edab701 139
marcel1691 0:62e55edab701 140 int BufferedSpi::putc(int c)
marcel1691 0:62e55edab701 141 {
marcel1691 0:62e55edab701 142 _txbuf = (char)c;
marcel1691 0:62e55edab701 143
marcel1691 0:62e55edab701 144 return c;
marcel1691 0:62e55edab701 145 }
marcel1691 0:62e55edab701 146
marcel1691 0:62e55edab701 147 void BufferedSpi::flush_txbuf(void)
marcel1691 0:62e55edab701 148 {
marcel1691 0:62e55edab701 149 _txbuf.clear();
marcel1691 0:62e55edab701 150 }
marcel1691 0:62e55edab701 151
marcel1691 0:62e55edab701 152 int BufferedSpi::puts(const char *s)
marcel1691 0:62e55edab701 153 {
marcel1691 0:62e55edab701 154 if (s != NULL) {
marcel1691 0:62e55edab701 155 const char *ptr = s;
marcel1691 0:62e55edab701 156
marcel1691 0:62e55edab701 157 while (*(ptr) != 0) {
marcel1691 0:62e55edab701 158 _txbuf = *(ptr++);
marcel1691 0:62e55edab701 159 }
marcel1691 0:62e55edab701 160 _txbuf = '\n'; // done per puts definition
marcel1691 0:62e55edab701 161 BufferedSpi::txIrq(); // only write to hardware in one place
marcel1691 0:62e55edab701 162 return (ptr - s) + 1;
marcel1691 0:62e55edab701 163 }
marcel1691 0:62e55edab701 164 return 0;
marcel1691 0:62e55edab701 165 }
marcel1691 0:62e55edab701 166
marcel1691 0:62e55edab701 167 extern "C" size_t BufferedSpiThunk(void *buf_spi, const void *s, size_t length)
marcel1691 0:62e55edab701 168 {
marcel1691 0:62e55edab701 169 BufferedSpi *buffered_spi = (BufferedSpi *)buf_spi;
marcel1691 0:62e55edab701 170 return buffered_spi->buffwrite(s, length);
marcel1691 0:62e55edab701 171 }
marcel1691 0:62e55edab701 172
marcel1691 0:62e55edab701 173 int BufferedSpi::printf(const char *format, ...)
marcel1691 0:62e55edab701 174 {
marcel1691 0:62e55edab701 175 va_list arg;
marcel1691 0:62e55edab701 176 va_start(arg, format);
marcel1691 0:62e55edab701 177 int r = BufferedPrintfC((void *)this, this->_buf_size, format, arg);
marcel1691 0:62e55edab701 178 va_end(arg);
marcel1691 0:62e55edab701 179 return r;
marcel1691 0:62e55edab701 180 }
marcel1691 0:62e55edab701 181
marcel1691 0:62e55edab701 182 ssize_t BufferedSpi::buffwrite(const void *s, size_t length)
marcel1691 0:62e55edab701 183 {
marcel1691 0:62e55edab701 184 /* flush buffer from previous message */
marcel1691 0:62e55edab701 185 this->flush_txbuf();
marcel1691 0:62e55edab701 186
marcel1691 0:62e55edab701 187 if (wait_cmddata_rdy_high() < 0) {
marcel1691 0:62e55edab701 188 debug_if(local_debug, "BufferedSpi::buffwrite timeout (%d)\r\n", _timeout);
marcel1691 0:62e55edab701 189 return -1;
marcel1691 0:62e55edab701 190 }
marcel1691 0:62e55edab701 191
marcel1691 0:62e55edab701 192 this->enable_nss();
marcel1691 0:62e55edab701 193
marcel1691 0:62e55edab701 194 if (s != NULL && length > 0) {
marcel1691 0:62e55edab701 195 /* 1st fill _txbuf */
marcel1691 0:62e55edab701 196 const char *ptr = (const char *)s;
marcel1691 0:62e55edab701 197 const char *end = ptr + length;
marcel1691 0:62e55edab701 198
marcel1691 0:62e55edab701 199 while (ptr != end) {
marcel1691 0:62e55edab701 200 _txbuf = *(ptr++);
marcel1691 0:62e55edab701 201 }
marcel1691 0:62e55edab701 202 if (length & 1) { /* padding to send the last char */
marcel1691 0:62e55edab701 203 _txbuf = '\n';
marcel1691 0:62e55edab701 204 length++;
marcel1691 0:62e55edab701 205 }
marcel1691 0:62e55edab701 206
marcel1691 0:62e55edab701 207 /* 2nd write in SPI */
marcel1691 0:62e55edab701 208 BufferedSpi::txIrq(); // only write to hardware in one place
marcel1691 0:62e55edab701 209
marcel1691 0:62e55edab701 210 this->disable_nss();
marcel1691 0:62e55edab701 211 return ptr - (const char *)s;
marcel1691 0:62e55edab701 212 }
marcel1691 0:62e55edab701 213 this->disable_nss();
marcel1691 0:62e55edab701 214
marcel1691 0:62e55edab701 215 return 0;
marcel1691 0:62e55edab701 216 }
marcel1691 0:62e55edab701 217
marcel1691 0:62e55edab701 218 ssize_t BufferedSpi::buffsend(size_t length)
marcel1691 0:62e55edab701 219 {
marcel1691 0:62e55edab701 220 /* wait for dataready = 1 */
marcel1691 0:62e55edab701 221 if (wait_cmddata_rdy_high() < 0) {
marcel1691 0:62e55edab701 222 debug_if(local_debug, "BufferedSpi::buffsend timeout (%d)\r\n", _timeout);
marcel1691 0:62e55edab701 223 return -1;
marcel1691 0:62e55edab701 224 }
marcel1691 0:62e55edab701 225
marcel1691 0:62e55edab701 226 this->enable_nss();
marcel1691 0:62e55edab701 227
marcel1691 0:62e55edab701 228 /* _txbuffer is already filled with data to send */
marcel1691 0:62e55edab701 229 /* check if _txbuffer needs padding to send the last char */
marcel1691 0:62e55edab701 230 if (length & 1) {
marcel1691 0:62e55edab701 231 _txbuf = '\n';
marcel1691 0:62e55edab701 232 length++;
marcel1691 0:62e55edab701 233 }
marcel1691 0:62e55edab701 234 BufferedSpi::txIrq(); // only write to hardware in one place
marcel1691 0:62e55edab701 235
marcel1691 0:62e55edab701 236 this->disable_nss();
marcel1691 0:62e55edab701 237
marcel1691 0:62e55edab701 238 return length;
marcel1691 0:62e55edab701 239 }
marcel1691 0:62e55edab701 240
marcel1691 0:62e55edab701 241 ssize_t BufferedSpi::read()
marcel1691 0:62e55edab701 242 {
marcel1691 0:62e55edab701 243 return this->read(0);
marcel1691 0:62e55edab701 244 }
marcel1691 0:62e55edab701 245
marcel1691 0:62e55edab701 246 ssize_t BufferedSpi::read(uint32_t max)
marcel1691 0:62e55edab701 247 {
marcel1691 0:62e55edab701 248 uint32_t len = 0;
marcel1691 0:62e55edab701 249 uint8_t FirstRemoved = 1;
marcel1691 0:62e55edab701 250 int tmp;
marcel1691 0:62e55edab701 251
marcel1691 0:62e55edab701 252 disable_nss();
marcel1691 0:62e55edab701 253
marcel1691 0:62e55edab701 254 /* wait for data ready is up */
marcel1691 0:62e55edab701 255 if (wait_cmddata_rdy_rising_event() != 0) {
marcel1691 0:62e55edab701 256 debug_if(local_debug, "BufferedSpi::read timeout (%d)\r\n", _timeout);
marcel1691 0:62e55edab701 257 return -1;
marcel1691 0:62e55edab701 258 }
marcel1691 0:62e55edab701 259
marcel1691 0:62e55edab701 260 enable_nss();
marcel1691 0:62e55edab701 261 while (dataready.read() == 1 && (len < (_buf_size - 2))) {
marcel1691 0:62e55edab701 262 tmp = SPI::write(0xAA); // dummy write to receive 2 bytes
marcel1691 0:62e55edab701 263
marcel1691 0:62e55edab701 264 if (!((len == 0) && (tmp == 0x0A0D) && (FirstRemoved))) {
marcel1691 0:62e55edab701 265 /* do not take into account the 2 firts \r \n char in the buffer */
marcel1691 0:62e55edab701 266 if ((max == 0) || (len < max)) {
marcel1691 0:62e55edab701 267 _rxbuf = (char)(tmp & 0x00FF);
marcel1691 0:62e55edab701 268 _rxbuf = (char)((tmp >> 8) & 0xFF);
marcel1691 0:62e55edab701 269 len += 2;
marcel1691 0:62e55edab701 270 }
marcel1691 0:62e55edab701 271 } else {
marcel1691 0:62e55edab701 272 FirstRemoved = 0;
marcel1691 0:62e55edab701 273 }
marcel1691 0:62e55edab701 274 }
marcel1691 0:62e55edab701 275 disable_nss();
marcel1691 0:62e55edab701 276
marcel1691 0:62e55edab701 277 if (len >= _buf_size) {
marcel1691 0:62e55edab701 278 debug_if(local_debug, "firmware ERROR ES_WIFI_ERROR_STUFFING_FOREVER\r\n");
marcel1691 0:62e55edab701 279 return -1;
marcel1691 0:62e55edab701 280 }
marcel1691 0:62e55edab701 281
marcel1691 0:62e55edab701 282 debug_if(local_debug, "SPI READ %d BYTES\r\n", len);
marcel1691 0:62e55edab701 283
marcel1691 0:62e55edab701 284 return len;
marcel1691 0:62e55edab701 285 }
marcel1691 0:62e55edab701 286
marcel1691 0:62e55edab701 287 void BufferedSpi::txIrq(void)
marcel1691 0:62e55edab701 288 {
marcel1691 0:62e55edab701 289 /* write everything available in the _txbuffer */
marcel1691 0:62e55edab701 290 int value = 0;
marcel1691 0:62e55edab701 291 int dbg_cnt = 0;
marcel1691 0:62e55edab701 292 while (_txbuf.available() && (_txbuf.getNbAvailable() > 0)) {
marcel1691 0:62e55edab701 293 value = _txbuf.get();
marcel1691 0:62e55edab701 294 if (_txbuf.available() && ((_txbuf.getNbAvailable() % 2) != 0)) {
marcel1691 0:62e55edab701 295 value |= ((_txbuf.get() << 8) & 0XFF00);
marcel1691 0:62e55edab701 296 SPI::write(value);
marcel1691 0:62e55edab701 297 dbg_cnt++;
marcel1691 0:62e55edab701 298 }
marcel1691 0:62e55edab701 299 }
marcel1691 0:62e55edab701 300 debug_if(local_debug, "SPI Sent %d BYTES\r\n", 2 * dbg_cnt);
marcel1691 0:62e55edab701 301 // disable the TX interrupt when there is nothing left to send
marcel1691 0:62e55edab701 302 BufferedSpi::attach(NULL, BufferedSpi::TxIrq);
marcel1691 0:62e55edab701 303 // trigger callback if necessary
marcel1691 0:62e55edab701 304 if (_cbs[TxIrq]) {
marcel1691 0:62e55edab701 305 _cbs[TxIrq]();
marcel1691 0:62e55edab701 306 }
marcel1691 0:62e55edab701 307 return;
marcel1691 0:62e55edab701 308 }
marcel1691 0:62e55edab701 309
marcel1691 0:62e55edab701 310 void BufferedSpi::prime(void)
marcel1691 0:62e55edab701 311 {
marcel1691 0:62e55edab701 312 BufferedSpi::txIrq(); // only write to hardware in one place
marcel1691 0:62e55edab701 313 return;
marcel1691 0:62e55edab701 314 }
marcel1691 0:62e55edab701 315
marcel1691 0:62e55edab701 316 void BufferedSpi::attach(Callback<void()> func, IrqType type)
marcel1691 0:62e55edab701 317 {
marcel1691 0:62e55edab701 318 _cbs[type] = func;
marcel1691 0:62e55edab701 319 }
marcel1691 0:62e55edab701 320
marcel1691 0:62e55edab701 321 void BufferedSpi::sigio(Callback<void()> func)
marcel1691 0:62e55edab701 322 {
marcel1691 0:62e55edab701 323 core_util_critical_section_enter();
marcel1691 0:62e55edab701 324 _sigio_cb = func;
marcel1691 0:62e55edab701 325 if (_sigio_cb) {
marcel1691 0:62e55edab701 326 if (_sigio_event == 1) {
marcel1691 0:62e55edab701 327 _sigio_cb();
marcel1691 0:62e55edab701 328 _sigio_event = 0;
marcel1691 0:62e55edab701 329 }
marcel1691 0:62e55edab701 330 }
marcel1691 0:62e55edab701 331 core_util_critical_section_exit();
marcel1691 0:62e55edab701 332 }
marcel1691 0:62e55edab701 333