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 00090 return; 00091 } 00092 00093 BufferedSpi::~BufferedSpi(void) 00094 { 00095 00096 return; 00097 } 00098 00099 void BufferedSpi::frequency(int hz) 00100 { 00101 SPI::frequency(hz); 00102 } 00103 00104 void BufferedSpi::format(int bits, int mode) 00105 { 00106 SPI::format(bits, mode); 00107 } 00108 00109 void BufferedSpi::disable_nss() 00110 { 00111 nss = 1; 00112 wait_us(15); 00113 } 00114 00115 void BufferedSpi::enable_nss() 00116 { 00117 nss = 0; 00118 wait_us(15); 00119 } 00120 00121 int BufferedSpi::readable(void) 00122 { 00123 return _rxbuf.available(); // note: look if things are in the buffer 00124 } 00125 00126 int BufferedSpi::writeable(void) 00127 { 00128 return 1; // buffer allows overwriting by design, always true 00129 } 00130 00131 int BufferedSpi::getc(void) 00132 { 00133 if (_rxbuf.available()) { 00134 return _rxbuf; 00135 } else { 00136 return -1; 00137 } 00138 } 00139 00140 int BufferedSpi::putc(int c) 00141 { 00142 _txbuf = (char)c; 00143 00144 return c; 00145 } 00146 00147 void BufferedSpi::flush_txbuf(void) 00148 { 00149 _txbuf.clear(); 00150 } 00151 00152 int BufferedSpi::puts(const char *s) 00153 { 00154 if (s != NULL) { 00155 const char *ptr = s; 00156 00157 while (*(ptr) != 0) { 00158 _txbuf = *(ptr++); 00159 } 00160 _txbuf = '\n'; // done per puts definition 00161 BufferedSpi::txIrq(); // only write to hardware in one place 00162 return (ptr - s) + 1; 00163 } 00164 return 0; 00165 } 00166 00167 extern "C" size_t BufferedSpiThunk(void *buf_spi, const void *s, size_t length) 00168 { 00169 BufferedSpi *buffered_spi = (BufferedSpi *)buf_spi; 00170 return buffered_spi->buffwrite(s, length); 00171 } 00172 00173 int BufferedSpi::printf(const char *format, ...) 00174 { 00175 va_list arg; 00176 va_start(arg, format); 00177 int r = BufferedPrintfC((void *)this, this->_buf_size, format, arg); 00178 va_end(arg); 00179 return r; 00180 } 00181 00182 ssize_t BufferedSpi::buffwrite(const void *s, size_t length) 00183 { 00184 /* flush buffer from previous message */ 00185 this->flush_txbuf(); 00186 00187 if (wait_cmddata_rdy_high() < 0) { 00188 debug_if(local_debug, "BufferedSpi::buffwrite timeout (%d)\r\n", _timeout); 00189 return -1; 00190 } 00191 00192 this->enable_nss(); 00193 00194 if (s != NULL && length > 0) { 00195 /* 1st fill _txbuf */ 00196 const char *ptr = (const char *)s; 00197 const char *end = ptr + length; 00198 00199 while (ptr != end) { 00200 _txbuf = *(ptr++); 00201 } 00202 if (length & 1) { /* padding to send the last char */ 00203 _txbuf = '\n'; 00204 length++; 00205 } 00206 00207 /* 2nd write in SPI */ 00208 BufferedSpi::txIrq(); // only write to hardware in one place 00209 00210 this->disable_nss(); 00211 return ptr - (const char *)s; 00212 } 00213 this->disable_nss(); 00214 00215 return 0; 00216 } 00217 00218 ssize_t BufferedSpi::buffsend(size_t length) 00219 { 00220 /* wait for dataready = 1 */ 00221 if (wait_cmddata_rdy_high() < 0) { 00222 debug_if(local_debug, "BufferedSpi::buffsend timeout (%d)\r\n", _timeout); 00223 return -1; 00224 } 00225 00226 this->enable_nss(); 00227 00228 /* _txbuffer is already filled with data to send */ 00229 /* check if _txbuffer needs padding to send the last char */ 00230 if (length & 1) { 00231 _txbuf = '\n'; 00232 length++; 00233 } 00234 BufferedSpi::txIrq(); // only write to hardware in one place 00235 00236 this->disable_nss(); 00237 00238 return length; 00239 } 00240 00241 ssize_t BufferedSpi::read() 00242 { 00243 return this->read(0); 00244 } 00245 00246 ssize_t BufferedSpi::read(uint32_t max) 00247 { 00248 uint32_t len = 0; 00249 uint8_t FirstRemoved = 1; 00250 int tmp; 00251 00252 disable_nss(); 00253 00254 /* wait for data ready is up */ 00255 if (wait_cmddata_rdy_rising_event() != 0) { 00256 debug_if(local_debug, "BufferedSpi::read timeout (%d)\r\n", _timeout); 00257 return -1; 00258 } 00259 00260 enable_nss(); 00261 while (dataready.read() == 1 && (len < (_buf_size - 2))) { 00262 tmp = SPI::write(0xAA); // dummy write to receive 2 bytes 00263 00264 if (!((len == 0) && (tmp == 0x0A0D) && (FirstRemoved))) { 00265 /* do not take into account the 2 firts \r \n char in the buffer */ 00266 if ((max == 0) || (len < max)) { 00267 _rxbuf = (char)(tmp & 0x00FF); 00268 _rxbuf = (char)((tmp >> 8) & 0xFF); 00269 len += 2; 00270 } 00271 } else { 00272 FirstRemoved = 0; 00273 } 00274 } 00275 disable_nss(); 00276 00277 if (len >= _buf_size) { 00278 debug_if(local_debug, "firmware ERROR ES_WIFI_ERROR_STUFFING_FOREVER\r\n"); 00279 return -1; 00280 } 00281 00282 debug_if(local_debug, "SPI READ %d BYTES\r\n", len); 00283 00284 return len; 00285 } 00286 00287 void BufferedSpi::txIrq(void) 00288 { 00289 /* write everything available in the _txbuffer */ 00290 int value = 0; 00291 int dbg_cnt = 0; 00292 while (_txbuf.available() && (_txbuf.getNbAvailable() > 0)) { 00293 value = _txbuf.get(); 00294 if (_txbuf.available() && ((_txbuf.getNbAvailable() % 2) != 0)) { 00295 value |= ((_txbuf.get() << 8) & 0XFF00); 00296 SPI::write(value); 00297 dbg_cnt++; 00298 } 00299 } 00300 debug_if(local_debug, "SPI Sent %d BYTES\r\n", 2 * dbg_cnt); 00301 // disable the TX interrupt when there is nothing left to send 00302 BufferedSpi::attach(NULL, BufferedSpi::TxIrq); 00303 // trigger callback if necessary 00304 if (_cbs[TxIrq]) { 00305 _cbs[TxIrq](); 00306 } 00307 return; 00308 } 00309 00310 void BufferedSpi::prime(void) 00311 { 00312 BufferedSpi::txIrq(); // only write to hardware in one place 00313 return; 00314 } 00315 00316 void BufferedSpi::attach(Callback<void()> func, IrqType type) 00317 { 00318 _cbs[type] = func; 00319 } 00320 00321 void BufferedSpi::sigio(Callback<void()> func) 00322 { 00323 core_util_critical_section_enter(); 00324 _sigio_cb = func; 00325 if (_sigio_cb) { 00326 if (_sigio_event == 1) { 00327 _sigio_cb(); 00328 _sigio_event = 0; 00329 } 00330 } 00331 core_util_critical_section_exit(); 00332 } 00333
Generated on Tue Jul 12 2022 16:24:08 by
1.7.2