Advantech / Mbed OS pelion-example-common
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers BufferedSpi.cpp Source File

BufferedSpi.cpp

Go to the documentation of this file.
00001 /**
00002  * @file    BufferedSpi.cpp
00003  * @brief   Software Buffer - Extends mbed SPI functionallity
00004  * @author  Armelle Duboc
00005  * @version 1.0
00006  * @see
00007  *
00008  * Copyright (c) STMicroelectronics 2017
00009  *
00010  * Licensed under the Apache License, Version 2.0 (the "License");
00011  * you may not use this file except in compliance with the License.
00012  * You may obtain a copy of the License at
00013  *
00014  *     http://www.apache.org/licenses/LICENSE-2.0
00015  *
00016  * Unless required by applicable law or agreed to in writing, software
00017  * distributed under the License is distributed on an "AS IS" BASIS,
00018  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00019  * See the License for the specific language governing permissions and
00020  * limitations under the License.
00021  */
00022 
00023 #include "BufferedSpi.h"
00024 #include <stdarg.h>
00025 #include "mbed_debug.h"
00026 #include "mbed_error.h"
00027 
00028 // change to true to add few SPI debug lines
00029 #define local_debug false
00030 
00031 extern "C" int BufferedPrintfC(void *stream, int size, const char *format, va_list arg);
00032 
00033 void BufferedSpi::DatareadyRising(void)
00034 {
00035     if (_cmddata_rdy_rising_event == 1) {
00036         _cmddata_rdy_rising_event = 0;
00037     }
00038 }
00039 
00040 int BufferedSpi::wait_cmddata_rdy_high(void)
00041 {
00042     Timer timer;
00043     timer.start();
00044 
00045     /* wait for dataready = 1 */
00046     while (dataready.read() == 0) {
00047         if (timer.read_ms() > _timeout) {
00048             debug_if(local_debug, "ERROR: SPI write timeout\r\n");
00049             return -1;
00050         }
00051     }
00052 
00053     _cmddata_rdy_rising_event = 1;
00054 
00055     return 0;
00056 }
00057 
00058 int BufferedSpi::wait_cmddata_rdy_rising_event(void)
00059 {
00060     Timer timer;
00061     timer.start();
00062 
00063     while (_cmddata_rdy_rising_event == 1) {
00064         if (timer.read_ms() > _timeout) {
00065             _cmddata_rdy_rising_event = 0;
00066             if (dataready.read() == 1) {
00067                 debug_if(local_debug, "ERROR: We missed rising event !! (timemout=%d)\r\n", _timeout);
00068             }
00069             debug_if(local_debug, "ERROR: SPI read timeout\r\n");
00070             return -1;
00071         }
00072     }
00073 
00074     return 0;
00075 }
00076 
00077 BufferedSpi::BufferedSpi(PinName mosi, PinName miso, PinName sclk, PinName _nss, PinName _datareadypin,
00078                          uint32_t buf_size, uint32_t tx_multiple, const char *name)
00079     : SPI(mosi, miso, sclk, NC), nss(_nss),  _txbuf((uint32_t)(tx_multiple * buf_size)), _rxbuf(buf_size), dataready(_datareadypin)
00080 {
00081     this->_buf_size = buf_size;
00082     this->_tx_multiple = tx_multiple;
00083     this->_sigio_event = 0;
00084 
00085     _datareadyInt = new InterruptIn(_datareadypin);
00086     _datareadyInt->rise(callback(this, &BufferedSpi::DatareadyRising));
00087 
00088     _cmddata_rdy_rising_event = 1;
00089     nss = 1;
00090     wait_us(15);
00091 
00092     return;
00093 }
00094 
00095 BufferedSpi::~BufferedSpi(void)
00096 {
00097 
00098     return;
00099 }
00100 
00101 void BufferedSpi::frequency(int hz)
00102 {
00103     SPI::frequency(hz);
00104 }
00105 
00106 void BufferedSpi::format(int bits, int mode)
00107 {
00108     SPI::format(bits, mode);
00109 }
00110 
00111 void BufferedSpi::disable_nss()
00112 {
00113     nss = 1;
00114     wait_us(15);
00115     unlock();
00116 }
00117 
00118 void BufferedSpi::enable_nss()
00119 {
00120     lock();
00121     nss = 0;
00122     wait_us(15);
00123 }
00124 
00125 int BufferedSpi::readable(void)
00126 {
00127     return _rxbuf.available();  // note: look if things are in the buffer
00128 }
00129 
00130 int BufferedSpi::writeable(void)
00131 {
00132     return 1;   // buffer allows overwriting by design, always true
00133 }
00134 
00135 int BufferedSpi::getc(void)
00136 {
00137     if (_rxbuf.available()) {
00138         return _rxbuf;
00139     } else {
00140         return -1;
00141     }
00142 }
00143 
00144 int BufferedSpi::putc(int c)
00145 {
00146     _txbuf = (char)c;
00147 
00148     return c;
00149 }
00150 
00151 void BufferedSpi::flush_txbuf(void)
00152 {
00153     _txbuf.clear();
00154 }
00155 
00156 int BufferedSpi::puts(const char *s)
00157 {
00158     if (s != NULL) {
00159         const char *ptr = s;
00160 
00161         while (*(ptr) != 0) {
00162             _txbuf = *(ptr++);
00163         }
00164         _txbuf = '\n';  // done per puts definition
00165         BufferedSpi::txIrq();                // only write to hardware in one place
00166         return (ptr - s) + 1;
00167     }
00168     return 0;
00169 }
00170 
00171 extern "C" size_t BufferedSpiThunk(void *buf_spi, const void *s, size_t length)
00172 {
00173     BufferedSpi *buffered_spi = (BufferedSpi *)buf_spi;
00174     return buffered_spi->buffwrite(s, length);
00175 }
00176 
00177 int BufferedSpi::printf(const char *format, ...)
00178 {
00179     va_list arg;
00180     va_start(arg, format);
00181     int r = BufferedPrintfC((void *)this, this->_buf_size, format, arg);
00182     va_end(arg);
00183     return r;
00184 }
00185 
00186 ssize_t BufferedSpi::buffwrite(const void *s, size_t length)
00187 {
00188     /* flush buffer from previous message */
00189     this->flush_txbuf();
00190 
00191     if (wait_cmddata_rdy_high() < 0) {
00192         debug_if(local_debug, "BufferedSpi::buffwrite timeout (%d)\r\n", _timeout);
00193         return -1;
00194     }
00195 
00196     this->enable_nss();
00197 
00198     if (s != NULL && length > 0) {
00199         /* 1st fill _txbuf */
00200         const char *ptr = (const char *)s;
00201         const char *end = ptr + length;
00202 
00203         while (ptr != end) {
00204             _txbuf = *(ptr++);
00205         }
00206         if (length & 1) { /* padding to send the last char */
00207             _txbuf = '\n';
00208             length++;
00209         }
00210 
00211         /* 2nd write in SPI */
00212         BufferedSpi::txIrq();                // only write to hardware in one place
00213 
00214         this->disable_nss();
00215         return ptr - (const char *)s;
00216     }
00217     this->disable_nss();
00218 
00219     return 0;
00220 }
00221 
00222 ssize_t BufferedSpi::buffsend(size_t length)
00223 {
00224     /* wait for dataready = 1 */
00225     if (wait_cmddata_rdy_high() < 0) {
00226         debug_if(local_debug, "BufferedSpi::buffsend timeout (%d)\r\n", _timeout);
00227         return -1;
00228     }
00229 
00230     this->enable_nss();
00231 
00232     /* _txbuffer is already filled with data to send */
00233     /* check if _txbuffer needs padding to send the last char */
00234     if (length & 1) {
00235         _txbuf = '\n';
00236         length++;
00237     }
00238     BufferedSpi::txIrq();                // only write to hardware in one place
00239 
00240     this->disable_nss();
00241 
00242     return length;
00243 }
00244 
00245 ssize_t BufferedSpi::read()
00246 {
00247     return this->read(0);
00248 }
00249 
00250 ssize_t BufferedSpi::read(uint32_t max)
00251 {
00252     uint32_t len = 0;
00253     uint8_t FirstRemoved = 1;
00254     int tmp;
00255 
00256     /* wait for data ready is up */
00257     if (wait_cmddata_rdy_rising_event() != 0) {
00258         debug_if(local_debug, "BufferedSpi::read timeout (%d)\r\n", _timeout);
00259         return -1;
00260     }
00261 
00262     enable_nss();
00263     while (dataready.read() == 1 && (len < (_buf_size - 2))) {
00264         tmp = SPI::write(0xAA);  // dummy write to receive 2 bytes
00265 
00266         if (!((len == 0) && (tmp == 0x0A0D) && (FirstRemoved))) {
00267             /* do not take into account the 2 firts \r \n char in the buffer */
00268             if ((max == 0) || (len < max)) {
00269                 _rxbuf = (char)(tmp & 0x00FF);
00270                 _rxbuf = (char)((tmp >> 8) & 0xFF);
00271                 len += 2;
00272             }
00273         } else {
00274             FirstRemoved = 0;
00275         }
00276     }
00277     disable_nss();
00278 
00279     if (len >= _buf_size) {
00280         debug_if(local_debug, "firmware ERROR ES_WIFI_ERROR_STUFFING_FOREVER\r\n");
00281         return -1;
00282     }
00283 
00284     debug_if(local_debug, "SPI READ %d BYTES\r\n", len);
00285 
00286     return len;
00287 }
00288 
00289 void BufferedSpi::txIrq(void)
00290 {
00291     /* write everything available in the _txbuffer */
00292     int value = 0;
00293     int dbg_cnt = 0;
00294     while (_txbuf.available() && (_txbuf.getNbAvailable() > 0)) {
00295         value = _txbuf.get();
00296         if (_txbuf.available() && ((_txbuf.getNbAvailable() % 2) != 0)) {
00297             value |= ((_txbuf.get() << 8) & 0XFF00);
00298             SPI::write(value);
00299             dbg_cnt++;
00300         }
00301     }
00302     debug_if(local_debug, "SPI Sent %d BYTES\r\n", 2 * dbg_cnt);
00303     // disable the TX interrupt when there is nothing left to send
00304     BufferedSpi::attach(NULL, BufferedSpi::TxIrq);
00305     // trigger callback if necessary
00306     if (_cbs[TxIrq]) {
00307         _cbs[TxIrq]();
00308     }
00309     return;
00310 }
00311 
00312 void BufferedSpi::prime(void)
00313 {
00314     BufferedSpi::txIrq();                // only write to hardware in one place
00315     return;
00316 }
00317 
00318 void BufferedSpi::attach(Callback<void()> func, IrqType type)
00319 {
00320     _cbs[type] = func;
00321 }
00322 
00323 void BufferedSpi::sigio(Callback<void()> func)
00324 {
00325     core_util_critical_section_enter();
00326     _sigio_cb = func;
00327     if (_sigio_cb) {
00328         if (_sigio_event == 1) {
00329             _sigio_cb();
00330             _sigio_event = 0;
00331         }
00332     }
00333     core_util_critical_section_exit();
00334 }
00335