@@ -45,9 +45,11 @@ circ_buf_t read_buffer;
45
45
uint8_t read_buffer_data [BUFFER_SIZE ];
46
46
47
47
struct {
48
+ // Number of bytes pending to be transferred. This is 0 if there is no
49
+ // ongoing transfer and the uart_handler processed the last transfer.
50
+ volatile uint32_t tx_size ;
51
+
48
52
uint8_t rx ;
49
- uint8_t tx ;
50
- uint8_t tx_active ;
51
53
} cb_buf ;
52
54
53
55
void uart_handler (uint32_t event );
@@ -61,6 +63,7 @@ void clear_buffers(void)
61
63
int32_t uart_initialize (void )
62
64
{
63
65
clear_buffers ();
66
+ cb_buf .tx_size = 0 ;
64
67
Driver_USART0 .Initialize (uart_handler );
65
68
Driver_USART0 .PowerControl (ARM_POWER_FULL );
66
69
@@ -70,8 +73,11 @@ int32_t uart_initialize(void)
70
73
int32_t uart_uninitialize (void )
71
74
{
72
75
USART_INSTANCE .Control (ARM_USART_CONTROL_RX , 0 );
76
+ USART_INSTANCE .Control (ARM_USART_ABORT_RECEIVE , 0U );
77
+ Driver_USART0 .PowerControl (ARM_POWER_OFF );
73
78
Driver_USART0 .Uninitialize ();
74
79
clear_buffers ();
80
+ cb_buf .tx_size = 0 ;
75
81
76
82
return 1 ;
77
83
}
@@ -153,6 +159,11 @@ int32_t uart_set_configuration(UART_Configuration *config)
153
159
154
160
NVIC_DisableIRQ (USART_IRQ );
155
161
clear_buffers ();
162
+
163
+ // If there was no Receive() call in progress aborting it is harmless.
164
+ USART_INSTANCE .Control (ARM_USART_CONTROL_RX , 0U );
165
+ USART_INSTANCE .Control (ARM_USART_ABORT_RECEIVE , 0U );
166
+
156
167
uint32_t r = USART_INSTANCE .Control (control , config -> Baudrate );
157
168
if (r != ARM_DRIVER_OK ) {
158
169
return 0 ;
@@ -177,10 +188,42 @@ int32_t uart_write_free(void)
177
188
return circ_buf_count_free (& write_buffer );
178
189
}
179
190
191
+ // Start a new TX transfer if there are bytes pending to be transferred on the
192
+ // write_buffer buffer. The transferred bytes are not removed from the circular
193
+ // by this function, only the event handler will remove them once the transfer
194
+ // is done.
195
+ static void uart_start_tx_transfer () {
196
+ uint32_t tx_size = 0 ;
197
+ const uint8_t * buf = circ_buf_peek (& write_buffer , & tx_size );
198
+ if (tx_size > BUFFER_SIZE / 4 ) {
199
+ // The bytes being transferred remain on the circular buffer memory
200
+ // until the transfer is done. Limiting the UART transfer size
201
+ // allows the uart_handler to clear those bytes earlier.
202
+ tx_size = BUFFER_SIZE / 4 ;
203
+ }
204
+ cb_buf .tx_size = tx_size ;
205
+ if (tx_size ) {
206
+ USART_INSTANCE .Send (buf , tx_size );
207
+ }
208
+ }
209
+
180
210
int32_t uart_write_data (uint8_t * data , uint16_t size )
181
211
{
212
+ if (size == 0 ) {
213
+ return 0 ;
214
+ }
215
+
182
216
uint32_t cnt = circ_buf_write (& write_buffer , data , size );
183
- NVIC_SetPendingIRQ (USART_IRQ );
217
+ if (cb_buf .tx_size == 0 ) {
218
+ // There's no pending transfer and the value of cb_buf.tx_size will not
219
+ // change to non-zero by the event handler once it is zero. Note that it
220
+ // is entirely possible that we transferred all the bytes we added to
221
+ // the circular buffer in this function by the time we are in this
222
+ // branch, in that case uart_start_tx_transfer() would not schedule any
223
+ // transfer.
224
+ uart_start_tx_transfer ();
225
+ }
226
+
184
227
return cnt ;
185
228
}
186
229
@@ -202,13 +245,8 @@ void uart_handler(uint32_t event) {
202
245
USART_INSTANCE .Receive (& (cb_buf .rx ), 1 );
203
246
}
204
247
205
- if ((event & ARM_USART_EVENT_SEND_COMPLETE ) || !cb_buf .tx_active ) {
206
- if (circ_buf_count_used (& write_buffer ) > 0 ) {
207
- cb_buf .tx_active = true;
208
- cb_buf .tx = circ_buf_pop (& write_buffer );
209
- USART_INSTANCE .Send (& (cb_buf .tx ), 1 );
210
- } else {
211
- cb_buf .tx_active = false;
212
- }
248
+ if (event & ARM_USART_EVENT_SEND_COMPLETE ) {
249
+ circ_buf_pop_n (& write_buffer , cb_buf .tx_size );
250
+ uart_start_tx_transfer ();
213
251
}
214
252
}
0 commit comments