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