Jim Carver
/
mbed-cloud-workshop-connect
Fork for workshops
Embed:
(wiki syntax)
Show/hide line numbers
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 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