Initial commit

Dependencies:   FastPWM

Committer:
lypinator
Date:
Wed Sep 16 01:11:49 2020 +0000
Revision:
0:bb348c97df44
Added PWM

Who changed what in which revision?

UserRevisionLine numberNew contents of line
lypinator 0:bb348c97df44 1 /* mbed Microcontroller Library
lypinator 0:bb348c97df44 2 * Copyright (c) 2006-2017 ARM Limited
lypinator 0:bb348c97df44 3 *
lypinator 0:bb348c97df44 4 * Licensed under the Apache License, Version 2.0 (the "License");
lypinator 0:bb348c97df44 5 * you may not use this file except in compliance with the License.
lypinator 0:bb348c97df44 6 * You may obtain a copy of the License at
lypinator 0:bb348c97df44 7 *
lypinator 0:bb348c97df44 8 * http://www.apache.org/licenses/LICENSE-2.0
lypinator 0:bb348c97df44 9 *
lypinator 0:bb348c97df44 10 * Unless required by applicable law or agreed to in writing, software
lypinator 0:bb348c97df44 11 * distributed under the License is distributed on an "AS IS" BASIS,
lypinator 0:bb348c97df44 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
lypinator 0:bb348c97df44 13 * See the License for the specific language governing permissions and
lypinator 0:bb348c97df44 14 * limitations under the License.
lypinator 0:bb348c97df44 15 */
lypinator 0:bb348c97df44 16
lypinator 0:bb348c97df44 17 #if (DEVICE_SERIAL && DEVICE_INTERRUPTIN)
lypinator 0:bb348c97df44 18
lypinator 0:bb348c97df44 19 #include <errno.h>
lypinator 0:bb348c97df44 20 #include "UARTSerial.h"
lypinator 0:bb348c97df44 21 #include "platform/mbed_poll.h"
lypinator 0:bb348c97df44 22
lypinator 0:bb348c97df44 23 #if MBED_CONF_RTOS_PRESENT
lypinator 0:bb348c97df44 24 #include "rtos/Thread.h"
lypinator 0:bb348c97df44 25 #else
lypinator 0:bb348c97df44 26 #include "platform/mbed_wait_api.h"
lypinator 0:bb348c97df44 27 #endif
lypinator 0:bb348c97df44 28
lypinator 0:bb348c97df44 29 namespace mbed {
lypinator 0:bb348c97df44 30
lypinator 0:bb348c97df44 31 UARTSerial::UARTSerial(PinName tx, PinName rx, int baud) :
lypinator 0:bb348c97df44 32 SerialBase(tx, rx, baud),
lypinator 0:bb348c97df44 33 _blocking(true),
lypinator 0:bb348c97df44 34 _tx_irq_enabled(false),
lypinator 0:bb348c97df44 35 _rx_irq_enabled(true),
lypinator 0:bb348c97df44 36 _dcd_irq(NULL)
lypinator 0:bb348c97df44 37 {
lypinator 0:bb348c97df44 38 /* Attatch IRQ routines to the serial device. */
lypinator 0:bb348c97df44 39 SerialBase::attach(callback(this, &UARTSerial::rx_irq), RxIrq);
lypinator 0:bb348c97df44 40 }
lypinator 0:bb348c97df44 41
lypinator 0:bb348c97df44 42 UARTSerial::~UARTSerial()
lypinator 0:bb348c97df44 43 {
lypinator 0:bb348c97df44 44 delete _dcd_irq;
lypinator 0:bb348c97df44 45 }
lypinator 0:bb348c97df44 46
lypinator 0:bb348c97df44 47 void UARTSerial::dcd_irq()
lypinator 0:bb348c97df44 48 {
lypinator 0:bb348c97df44 49 wake();
lypinator 0:bb348c97df44 50 }
lypinator 0:bb348c97df44 51
lypinator 0:bb348c97df44 52 void UARTSerial::set_baud(int baud)
lypinator 0:bb348c97df44 53 {
lypinator 0:bb348c97df44 54 SerialBase::baud(baud);
lypinator 0:bb348c97df44 55 }
lypinator 0:bb348c97df44 56
lypinator 0:bb348c97df44 57 void UARTSerial::set_data_carrier_detect(PinName dcd_pin, bool active_high)
lypinator 0:bb348c97df44 58 {
lypinator 0:bb348c97df44 59 delete _dcd_irq;
lypinator 0:bb348c97df44 60 _dcd_irq = NULL;
lypinator 0:bb348c97df44 61
lypinator 0:bb348c97df44 62 if (dcd_pin != NC) {
lypinator 0:bb348c97df44 63 _dcd_irq = new InterruptIn(dcd_pin);
lypinator 0:bb348c97df44 64 if (active_high) {
lypinator 0:bb348c97df44 65 _dcd_irq->fall(callback(this, &UARTSerial::dcd_irq));
lypinator 0:bb348c97df44 66 } else {
lypinator 0:bb348c97df44 67 _dcd_irq->rise(callback(this, &UARTSerial::dcd_irq));
lypinator 0:bb348c97df44 68 }
lypinator 0:bb348c97df44 69 }
lypinator 0:bb348c97df44 70 }
lypinator 0:bb348c97df44 71
lypinator 0:bb348c97df44 72 void UARTSerial::set_format(int bits, Parity parity, int stop_bits)
lypinator 0:bb348c97df44 73 {
lypinator 0:bb348c97df44 74 api_lock();
lypinator 0:bb348c97df44 75 SerialBase::format(bits, parity, stop_bits);
lypinator 0:bb348c97df44 76 api_unlock();
lypinator 0:bb348c97df44 77 }
lypinator 0:bb348c97df44 78
lypinator 0:bb348c97df44 79 #if DEVICE_SERIAL_FC
lypinator 0:bb348c97df44 80 void UARTSerial::set_flow_control(Flow type, PinName flow1, PinName flow2)
lypinator 0:bb348c97df44 81 {
lypinator 0:bb348c97df44 82 api_lock();
lypinator 0:bb348c97df44 83 SerialBase::set_flow_control(type, flow1, flow2);
lypinator 0:bb348c97df44 84 api_unlock();
lypinator 0:bb348c97df44 85 }
lypinator 0:bb348c97df44 86 #endif
lypinator 0:bb348c97df44 87
lypinator 0:bb348c97df44 88 int UARTSerial::close()
lypinator 0:bb348c97df44 89 {
lypinator 0:bb348c97df44 90 /* Does not let us pass a file descriptor. So how to close ?
lypinator 0:bb348c97df44 91 * Also, does it make sense to close a device type file descriptor*/
lypinator 0:bb348c97df44 92 return 0;
lypinator 0:bb348c97df44 93 }
lypinator 0:bb348c97df44 94
lypinator 0:bb348c97df44 95 int UARTSerial::isatty()
lypinator 0:bb348c97df44 96 {
lypinator 0:bb348c97df44 97 return 1;
lypinator 0:bb348c97df44 98
lypinator 0:bb348c97df44 99 }
lypinator 0:bb348c97df44 100
lypinator 0:bb348c97df44 101 off_t UARTSerial::seek(off_t offset, int whence)
lypinator 0:bb348c97df44 102 {
lypinator 0:bb348c97df44 103 /*XXX lseek can be done theoratically, but is it sane to mark positions on a dynamically growing/shrinking
lypinator 0:bb348c97df44 104 * buffer system (from an interrupt context) */
lypinator 0:bb348c97df44 105 return -ESPIPE;
lypinator 0:bb348c97df44 106 }
lypinator 0:bb348c97df44 107
lypinator 0:bb348c97df44 108 int UARTSerial::sync()
lypinator 0:bb348c97df44 109 {
lypinator 0:bb348c97df44 110 api_lock();
lypinator 0:bb348c97df44 111
lypinator 0:bb348c97df44 112 while (!_txbuf.empty()) {
lypinator 0:bb348c97df44 113 api_unlock();
lypinator 0:bb348c97df44 114 // Doing better than wait would require TxIRQ to also do wake() when becoming empty. Worth it?
lypinator 0:bb348c97df44 115 wait_ms(1);
lypinator 0:bb348c97df44 116 api_lock();
lypinator 0:bb348c97df44 117 }
lypinator 0:bb348c97df44 118
lypinator 0:bb348c97df44 119 api_unlock();
lypinator 0:bb348c97df44 120
lypinator 0:bb348c97df44 121 return 0;
lypinator 0:bb348c97df44 122 }
lypinator 0:bb348c97df44 123
lypinator 0:bb348c97df44 124 void UARTSerial::sigio(Callback<void()> func)
lypinator 0:bb348c97df44 125 {
lypinator 0:bb348c97df44 126 core_util_critical_section_enter();
lypinator 0:bb348c97df44 127 _sigio_cb = func;
lypinator 0:bb348c97df44 128 if (_sigio_cb) {
lypinator 0:bb348c97df44 129 short current_events = poll(0x7FFF);
lypinator 0:bb348c97df44 130 if (current_events) {
lypinator 0:bb348c97df44 131 _sigio_cb();
lypinator 0:bb348c97df44 132 }
lypinator 0:bb348c97df44 133 }
lypinator 0:bb348c97df44 134 core_util_critical_section_exit();
lypinator 0:bb348c97df44 135 }
lypinator 0:bb348c97df44 136
lypinator 0:bb348c97df44 137 ssize_t UARTSerial::write(const void *buffer, size_t length)
lypinator 0:bb348c97df44 138 {
lypinator 0:bb348c97df44 139 size_t data_written = 0;
lypinator 0:bb348c97df44 140 const char *buf_ptr = static_cast<const char *>(buffer);
lypinator 0:bb348c97df44 141
lypinator 0:bb348c97df44 142 if (length == 0) {
lypinator 0:bb348c97df44 143 return 0;
lypinator 0:bb348c97df44 144 }
lypinator 0:bb348c97df44 145
lypinator 0:bb348c97df44 146 api_lock();
lypinator 0:bb348c97df44 147
lypinator 0:bb348c97df44 148 // Unlike read, we should write the whole thing if blocking. POSIX only
lypinator 0:bb348c97df44 149 // allows partial as a side-effect of signal handling; it normally tries to
lypinator 0:bb348c97df44 150 // write everything if blocking. Without signals we can always write all.
lypinator 0:bb348c97df44 151 while (data_written < length) {
lypinator 0:bb348c97df44 152
lypinator 0:bb348c97df44 153 if (_txbuf.full()) {
lypinator 0:bb348c97df44 154 if (!_blocking) {
lypinator 0:bb348c97df44 155 break;
lypinator 0:bb348c97df44 156 }
lypinator 0:bb348c97df44 157 do {
lypinator 0:bb348c97df44 158 api_unlock();
lypinator 0:bb348c97df44 159 wait_ms(1); // XXX todo - proper wait, WFE for non-rtos ?
lypinator 0:bb348c97df44 160 api_lock();
lypinator 0:bb348c97df44 161 } while (_txbuf.full());
lypinator 0:bb348c97df44 162 }
lypinator 0:bb348c97df44 163
lypinator 0:bb348c97df44 164 while (data_written < length && !_txbuf.full()) {
lypinator 0:bb348c97df44 165 _txbuf.push(*buf_ptr++);
lypinator 0:bb348c97df44 166 data_written++;
lypinator 0:bb348c97df44 167 }
lypinator 0:bb348c97df44 168
lypinator 0:bb348c97df44 169 core_util_critical_section_enter();
lypinator 0:bb348c97df44 170 if (!_tx_irq_enabled) {
lypinator 0:bb348c97df44 171 UARTSerial::tx_irq(); // only write to hardware in one place
lypinator 0:bb348c97df44 172 if (!_txbuf.empty()) {
lypinator 0:bb348c97df44 173 SerialBase::attach(callback(this, &UARTSerial::tx_irq), TxIrq);
lypinator 0:bb348c97df44 174 _tx_irq_enabled = true;
lypinator 0:bb348c97df44 175 }
lypinator 0:bb348c97df44 176 }
lypinator 0:bb348c97df44 177 core_util_critical_section_exit();
lypinator 0:bb348c97df44 178 }
lypinator 0:bb348c97df44 179
lypinator 0:bb348c97df44 180 api_unlock();
lypinator 0:bb348c97df44 181
lypinator 0:bb348c97df44 182 return data_written != 0 ? (ssize_t) data_written : (ssize_t) - EAGAIN;
lypinator 0:bb348c97df44 183 }
lypinator 0:bb348c97df44 184
lypinator 0:bb348c97df44 185 ssize_t UARTSerial::read(void *buffer, size_t length)
lypinator 0:bb348c97df44 186 {
lypinator 0:bb348c97df44 187 size_t data_read = 0;
lypinator 0:bb348c97df44 188
lypinator 0:bb348c97df44 189 char *ptr = static_cast<char *>(buffer);
lypinator 0:bb348c97df44 190
lypinator 0:bb348c97df44 191 if (length == 0) {
lypinator 0:bb348c97df44 192 return 0;
lypinator 0:bb348c97df44 193 }
lypinator 0:bb348c97df44 194
lypinator 0:bb348c97df44 195 api_lock();
lypinator 0:bb348c97df44 196
lypinator 0:bb348c97df44 197 while (_rxbuf.empty()) {
lypinator 0:bb348c97df44 198 if (!_blocking) {
lypinator 0:bb348c97df44 199 api_unlock();
lypinator 0:bb348c97df44 200 return -EAGAIN;
lypinator 0:bb348c97df44 201 }
lypinator 0:bb348c97df44 202 api_unlock();
lypinator 0:bb348c97df44 203 wait_ms(1); // XXX todo - proper wait, WFE for non-rtos ?
lypinator 0:bb348c97df44 204 api_lock();
lypinator 0:bb348c97df44 205 }
lypinator 0:bb348c97df44 206
lypinator 0:bb348c97df44 207 while (data_read < length && !_rxbuf.empty()) {
lypinator 0:bb348c97df44 208 _rxbuf.pop(*ptr++);
lypinator 0:bb348c97df44 209 data_read++;
lypinator 0:bb348c97df44 210 }
lypinator 0:bb348c97df44 211
lypinator 0:bb348c97df44 212 core_util_critical_section_enter();
lypinator 0:bb348c97df44 213 if (!_rx_irq_enabled) {
lypinator 0:bb348c97df44 214 UARTSerial::rx_irq(); // only read from hardware in one place
lypinator 0:bb348c97df44 215 if (!_rxbuf.full()) {
lypinator 0:bb348c97df44 216 SerialBase::attach(callback(this, &UARTSerial::rx_irq), RxIrq);
lypinator 0:bb348c97df44 217 _rx_irq_enabled = true;
lypinator 0:bb348c97df44 218 }
lypinator 0:bb348c97df44 219 }
lypinator 0:bb348c97df44 220 core_util_critical_section_exit();
lypinator 0:bb348c97df44 221
lypinator 0:bb348c97df44 222 api_unlock();
lypinator 0:bb348c97df44 223
lypinator 0:bb348c97df44 224 return data_read;
lypinator 0:bb348c97df44 225 }
lypinator 0:bb348c97df44 226
lypinator 0:bb348c97df44 227 bool UARTSerial::hup() const
lypinator 0:bb348c97df44 228 {
lypinator 0:bb348c97df44 229 return _dcd_irq && _dcd_irq->read() != 0;
lypinator 0:bb348c97df44 230 }
lypinator 0:bb348c97df44 231
lypinator 0:bb348c97df44 232 void UARTSerial::wake()
lypinator 0:bb348c97df44 233 {
lypinator 0:bb348c97df44 234 if (_sigio_cb) {
lypinator 0:bb348c97df44 235 _sigio_cb();
lypinator 0:bb348c97df44 236 }
lypinator 0:bb348c97df44 237 }
lypinator 0:bb348c97df44 238
lypinator 0:bb348c97df44 239 short UARTSerial::poll(short events) const
lypinator 0:bb348c97df44 240 {
lypinator 0:bb348c97df44 241
lypinator 0:bb348c97df44 242 short revents = 0;
lypinator 0:bb348c97df44 243 /* Check the Circular Buffer if space available for writing out */
lypinator 0:bb348c97df44 244
lypinator 0:bb348c97df44 245
lypinator 0:bb348c97df44 246 if (!_rxbuf.empty()) {
lypinator 0:bb348c97df44 247 revents |= POLLIN;
lypinator 0:bb348c97df44 248 }
lypinator 0:bb348c97df44 249
lypinator 0:bb348c97df44 250 /* POLLHUP and POLLOUT are mutually exclusive */
lypinator 0:bb348c97df44 251 if (hup()) {
lypinator 0:bb348c97df44 252 revents |= POLLHUP;
lypinator 0:bb348c97df44 253 } else if (!_txbuf.full()) {
lypinator 0:bb348c97df44 254 revents |= POLLOUT;
lypinator 0:bb348c97df44 255 }
lypinator 0:bb348c97df44 256
lypinator 0:bb348c97df44 257 /*TODO Handle other event types */
lypinator 0:bb348c97df44 258
lypinator 0:bb348c97df44 259 return revents;
lypinator 0:bb348c97df44 260 }
lypinator 0:bb348c97df44 261
lypinator 0:bb348c97df44 262 void UARTSerial::lock()
lypinator 0:bb348c97df44 263 {
lypinator 0:bb348c97df44 264 // This is the override for SerialBase.
lypinator 0:bb348c97df44 265 // No lock required as we only use SerialBase from interrupt or from
lypinator 0:bb348c97df44 266 // inside our own critical section.
lypinator 0:bb348c97df44 267 }
lypinator 0:bb348c97df44 268
lypinator 0:bb348c97df44 269 void UARTSerial::unlock()
lypinator 0:bb348c97df44 270 {
lypinator 0:bb348c97df44 271 // This is the override for SerialBase.
lypinator 0:bb348c97df44 272 }
lypinator 0:bb348c97df44 273
lypinator 0:bb348c97df44 274 void UARTSerial::api_lock(void)
lypinator 0:bb348c97df44 275 {
lypinator 0:bb348c97df44 276 _mutex.lock();
lypinator 0:bb348c97df44 277 }
lypinator 0:bb348c97df44 278
lypinator 0:bb348c97df44 279 void UARTSerial::api_unlock(void)
lypinator 0:bb348c97df44 280 {
lypinator 0:bb348c97df44 281 _mutex.unlock();
lypinator 0:bb348c97df44 282 }
lypinator 0:bb348c97df44 283
lypinator 0:bb348c97df44 284 void UARTSerial::rx_irq(void)
lypinator 0:bb348c97df44 285 {
lypinator 0:bb348c97df44 286 bool was_empty = _rxbuf.empty();
lypinator 0:bb348c97df44 287
lypinator 0:bb348c97df44 288 /* Fill in the receive buffer if the peripheral is readable
lypinator 0:bb348c97df44 289 * and receive buffer is not full. */
lypinator 0:bb348c97df44 290 while (!_rxbuf.full() && SerialBase::readable()) {
lypinator 0:bb348c97df44 291 char data = SerialBase::_base_getc();
lypinator 0:bb348c97df44 292 _rxbuf.push(data);
lypinator 0:bb348c97df44 293 }
lypinator 0:bb348c97df44 294
lypinator 0:bb348c97df44 295 if (_rx_irq_enabled && _rxbuf.full()) {
lypinator 0:bb348c97df44 296 SerialBase::attach(NULL, RxIrq);
lypinator 0:bb348c97df44 297 _rx_irq_enabled = false;
lypinator 0:bb348c97df44 298 }
lypinator 0:bb348c97df44 299
lypinator 0:bb348c97df44 300 /* Report the File handler that data is ready to be read from the buffer. */
lypinator 0:bb348c97df44 301 if (was_empty && !_rxbuf.empty()) {
lypinator 0:bb348c97df44 302 wake();
lypinator 0:bb348c97df44 303 }
lypinator 0:bb348c97df44 304 }
lypinator 0:bb348c97df44 305
lypinator 0:bb348c97df44 306 // Also called from write to start transfer
lypinator 0:bb348c97df44 307 void UARTSerial::tx_irq(void)
lypinator 0:bb348c97df44 308 {
lypinator 0:bb348c97df44 309 bool was_full = _txbuf.full();
lypinator 0:bb348c97df44 310 char data;
lypinator 0:bb348c97df44 311
lypinator 0:bb348c97df44 312 /* Write to the peripheral if there is something to write
lypinator 0:bb348c97df44 313 * and if the peripheral is available to write. */
lypinator 0:bb348c97df44 314 while (SerialBase::writeable() && _txbuf.pop(data)) {
lypinator 0:bb348c97df44 315 SerialBase::_base_putc(data);
lypinator 0:bb348c97df44 316 }
lypinator 0:bb348c97df44 317
lypinator 0:bb348c97df44 318 if (_tx_irq_enabled && _txbuf.empty()) {
lypinator 0:bb348c97df44 319 SerialBase::attach(NULL, TxIrq);
lypinator 0:bb348c97df44 320 _tx_irq_enabled = false;
lypinator 0:bb348c97df44 321 }
lypinator 0:bb348c97df44 322
lypinator 0:bb348c97df44 323 /* Report the File handler that data can be written to peripheral. */
lypinator 0:bb348c97df44 324 if (was_full && !_txbuf.full() && !hup()) {
lypinator 0:bb348c97df44 325 wake();
lypinator 0:bb348c97df44 326 }
lypinator 0:bb348c97df44 327 }
lypinator 0:bb348c97df44 328
lypinator 0:bb348c97df44 329 void UARTSerial::wait_ms(uint32_t millisec)
lypinator 0:bb348c97df44 330 {
lypinator 0:bb348c97df44 331 /* wait_ms implementation for RTOS spins until exact microseconds - we
lypinator 0:bb348c97df44 332 * want to just sleep until next tick.
lypinator 0:bb348c97df44 333 */
lypinator 0:bb348c97df44 334 #if MBED_CONF_RTOS_PRESENT
lypinator 0:bb348c97df44 335 rtos::Thread::wait(millisec);
lypinator 0:bb348c97df44 336 #else
lypinator 0:bb348c97df44 337 ::wait_ms(millisec);
lypinator 0:bb348c97df44 338 #endif
lypinator 0:bb348c97df44 339 }
lypinator 0:bb348c97df44 340 } //namespace mbed
lypinator 0:bb348c97df44 341
lypinator 0:bb348c97df44 342 #endif //(DEVICE_SERIAL && DEVICE_INTERRUPTIN)