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 |