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.
BufferedSpi.cpp
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
Generated on Tue Jul 12 2022 16:59:38 by
1.7.2