| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE.md file. | |
| 4 | |
| 5 #include "platforms/stm/disco_fletch/src/uart.h" | |
| 6 | |
| 7 #include <stdlib.h> | |
| 8 | |
| 9 #include <stm32f7xx_hal.h> | |
| 10 | |
| 11 #include "src/shared/atomic.h" | |
| 12 #include "src/shared/utils.h" | |
| 13 | |
| 14 // Reference to the instance in the code generated by STM32CubeMX. | |
| 15 extern UART_HandleTypeDef huart1; | |
| 16 | |
| 17 // TODO(sgjesse): Get rid of these global variables. These global | |
| 18 // variables are accessed from the interrupt handlers. | |
| 19 static osSemaphoreId sem_; | |
| 20 static uint32_t error = 0; | |
| 21 | |
| 22 // Bits set from interrupt handlers. | |
| 23 const int kReceivedBit = 1 << 0; | |
| 24 const int kTransmittedBit = 1 << 1; | |
| 25 const int kErrorBit = 1 << 2; | |
| 26 static fletch::Atomic<uint32_t> interrupt_flags; | |
| 27 | |
| 28 const int kRxBufferSize = 511; | |
| 29 const int kTxBufferSize = 511; | |
| 30 | |
| 31 // C trampoline for the interrupt handling thread. | |
| 32 void __UartTask(void const* argument) { | |
| 33 Uart* uart = const_cast<Uart*>(reinterpret_cast<const Uart*>(argument)); | |
| 34 uart->Task(); | |
| 35 } | |
| 36 | |
| 37 Uart::Uart() { | |
| 38 uart_ = &huart1; | |
| 39 rx_buffer_ = new CircularBuffer(kRxBufferSize); | |
| 40 tx_mutex_ = fletch::Platform::CreateMutex(); | |
| 41 tx_buffer_ = new CircularBuffer(kTxBufferSize); | |
| 42 tx_pending_ = false; | |
| 43 error_count_ = 0; | |
| 44 | |
| 45 // Semaphore for signaling from interrupt handlers. A maximum of | |
| 46 // three tokens - one for data received and one for data transmitted | |
| 47 // and one for error. | |
| 48 semaphore_ = osSemaphoreCreate(osSemaphore(semaphore_def_), 3); | |
| 49 // Store in global variable for access from interrupt handlers. | |
| 50 sem_ = semaphore_; | |
| 51 } | |
| 52 | |
| 53 void Uart::Start() { | |
| 54 // Start thread for handling interrupts. | |
| 55 osThreadDef(UART_TASK, __UartTask, osPriorityHigh, 0, 1024); | |
| 56 osThreadCreate(osThread(UART_TASK), this); | |
| 57 | |
| 58 // Start receiving. | |
| 59 HAL_UART_Receive_IT(uart_, &rx_data_, 1); | |
| 60 } | |
| 61 | |
| 62 size_t Uart::Read(uint8_t* buffer, size_t count) { | |
| 63 return rx_buffer_->Read(buffer, count, CircularBuffer::kBlock); | |
| 64 } | |
| 65 | |
| 66 size_t Uart::Write(const uint8_t* buffer, size_t count) { | |
| 67 size_t written = tx_buffer_->Write(buffer, count, CircularBuffer::kBlock); | |
| 68 | |
| 69 fletch::ScopedLock lock(tx_mutex_); | |
| 70 EnsureTransmission(); | |
| 71 return written; | |
| 72 } | |
| 73 | |
| 74 void Uart::Task() { | |
| 75 // Process notifications from the interrupt handlers. | |
| 76 for (;;) { | |
| 77 // Wait for an interrupt to be processed. | |
| 78 osSemaphoreWait(semaphore_, osWaitForever); | |
| 79 // Read the flags and set them to zero. | |
| 80 uint32_t flags = interrupt_flags.exchange(0); | |
| 81 | |
| 82 if ((flags & kReceivedBit) != 0) { | |
| 83 // Don't block when writing to the buffer. Buffer overrun will | |
| 84 // cause lost data. | |
| 85 rx_buffer_->Write(&rx_data_, 1, CircularBuffer::kDontBlock); | |
| 86 | |
| 87 // Start receiving of next byte. | |
| 88 HAL_StatusTypeDef status = HAL_UART_Receive_IT(uart_, &rx_data_, 1); | |
| 89 if (status != HAL_OK) { | |
| 90 fletch::Print::Error("HAL_UART_Receive_IT returned %d\n", status); | |
| 91 } | |
| 92 } | |
| 93 | |
| 94 if ((flags & kTransmittedBit) != 0) { | |
| 95 fletch::ScopedLock lock(tx_mutex_); | |
| 96 tx_pending_ = false; | |
| 97 EnsureTransmission(); | |
| 98 } | |
| 99 | |
| 100 if ((flags & kErrorBit) != 0) { | |
| 101 // Ignore errors for now. | |
| 102 error_count_++; | |
| 103 error = 0; | |
| 104 // Setup interrupt for next byte. | |
| 105 HAL_StatusTypeDef status = HAL_UART_Receive_IT(uart_, &rx_data_, 1); | |
| 106 if (status != HAL_OK) { | |
| 107 fletch::Print::Error("HAL_UART_Receive_IT returned %d\n", status); | |
| 108 } | |
| 109 } | |
| 110 } | |
| 111 } | |
| 112 | |
| 113 void Uart::EnsureTransmission() { | |
| 114 if (!tx_pending_) { | |
| 115 // Don't block when there is nothing to send. | |
| 116 int bytes = tx_buffer_->Read( | |
| 117 tx_data_, kTxBlockSize, CircularBuffer::kDontBlock); | |
| 118 if (bytes > 0) { | |
| 119 HAL_StatusTypeDef status = HAL_UART_Transmit_IT(uart_, tx_data_, bytes); | |
| 120 if (status != HAL_OK) { | |
| 121 fletch::Print::Error("HAL_UART_Transmit_IT returned %d\n", status); | |
| 122 } | |
| 123 tx_pending_ = true; | |
| 124 } | |
| 125 } | |
| 126 } | |
| 127 | |
| 128 // Shared return from interrupt handler. Will set the specified flag | |
| 129 // and transfer control to the thread handling interrupts. | |
| 130 static void ReturnFromInterrupt(UART_HandleTypeDef *huart, uint32_t flag) { | |
| 131 // Set the requested bit. | |
| 132 uint32_t flags = interrupt_flags; | |
| 133 uint32_t new_flags = flags |= flag; | |
| 134 bool success = false; | |
| 135 while (!success) { | |
| 136 success = | |
| 137 interrupt_flags.compare_exchange_weak(flags, new_flags); | |
| 138 } | |
| 139 | |
| 140 // Pass control to the thread handling interrupts. | |
| 141 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; | |
| 142 osSemaphoreRelease(sem_); | |
| 143 portEND_SWITCHING_ISR(xHigherPriorityTaskWoken); | |
| 144 } | |
| 145 | |
| 146 extern "C" void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { | |
| 147 ReturnFromInterrupt(huart, kReceivedBit); | |
| 148 } | |
| 149 | |
| 150 extern "C" void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) { | |
| 151 ReturnFromInterrupt(huart, kTransmittedBit); | |
| 152 } | |
| 153 | |
| 154 extern "C" void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) { | |
| 155 error = HAL_UART_GetError(huart); | |
| 156 | |
| 157 // Clear all errors. | |
| 158 __HAL_UART_CLEAR_OREFLAG(&huart1); | |
| 159 __HAL_UART_CLEAR_FEFLAG(&huart1); | |
| 160 __HAL_UART_CLEAR_PEFLAG(&huart1); | |
| 161 __HAL_UART_CLEAR_NEFLAG(&huart1); | |
| 162 | |
| 163 ReturnFromInterrupt(huart, kErrorBit); | |
| 164 } | |
| OLD | NEW |