1
+ /*
2
+ Copyright (c) 2011 Arduino. All right reserved.
3
+
4
+ This library is free software; you can redistribute it and/or
5
+ modify it under the terms of the GNU Lesser General Public
6
+ License as published by the Free Software Foundation; either
7
+ version 2.1 of the License, or (at your option) any later version.
8
+
9
+ This library is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
+ See the GNU Lesser General Public License for more details.
13
+
14
+ You should have received a copy of the GNU Lesser General Public
15
+ License along with this library; if not, write to the Free Software
16
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
+ */
18
+
19
+ // ****************************************************************************
20
+ // @Project Includes
21
+ // ****************************************************************************
22
+ #include " Uart.h"
23
+ #include " Arduino.h"
24
+
25
+ // ****************************************************************************
26
+ // @Local Functions
27
+ // ****************************************************************************
28
+
29
+ // Constructors ////////////////////////////////////////////////////////////////
30
+
31
+ Uart::Uart (XMC_UART_t *xmc_uart_config,
32
+ arduino::RingBuffer *rx_buffer,
33
+ arduino::RingBuffer *tx_buffer) {
34
+ _XMC_UART_config = xmc_uart_config;
35
+ _rx_buffer = rx_buffer;
36
+ _tx_buffer = tx_buffer;
37
+ }
38
+
39
+ // Public Methods //////////////////////////////////////////////////////////////
40
+
41
+ void Uart::begin (unsigned long baud) { begin (baud, SERIAL_8N1); }
42
+
43
+ void Uart::begin (unsigned long baud, unsigned short config) {
44
+ begin (baud, static_cast <XMC_UART_MODE_t>(config));
45
+ }
46
+
47
+ void Uart::begin (unsigned long baud, XMC_UART_MODE_t config) {
48
+ XMC_UART_CH_CONFIG_t uart_ch_config;
49
+ uart_ch_config.oversampling = 0 ; // Must be 0 or valid oversample for baud rate calculations
50
+ uart_ch_config.baudrate = baud;
51
+ uart_ch_config.data_bits = (uint8_t )(config & 0x00fU );
52
+ uart_ch_config.frame_length = uart_ch_config.data_bits ; // Set same as data bits length
53
+ uart_ch_config.parity_mode = (XMC_USIC_CH_PARITY_MODE_t)(config & ~0xffU );
54
+ uart_ch_config.stop_bits = (uint8_t )((config & 0x0f0U ) >> 4 );
55
+
56
+ XMC_UART_CH_Init (_XMC_UART_config->channel , &uart_ch_config);
57
+
58
+ // dx0 is UART RX: source must be set
59
+ XMC_USIC_CH_SetInputSource (_XMC_UART_config->channel , XMC_USIC_CH_INPUT_DX0,
60
+ _XMC_UART_config->input_source_dx0 );
61
+
62
+ // Additional input multiplexing
63
+ // Check if dx1 is used
64
+ if (_XMC_UART_config->input_source_dx1 != XMC_INPUT_INVALID)
65
+ XMC_USIC_CH_SetInputSource (_XMC_UART_config->channel , XMC_USIC_CH_INPUT_DX1,
66
+ _XMC_UART_config->input_source_dx1 );
67
+
68
+ // Check if dx2 is used
69
+ if (_XMC_UART_config->input_source_dx2 != XMC_INPUT_INVALID)
70
+ XMC_USIC_CH_SetInputSource (_XMC_UART_config->channel , XMC_USIC_CH_INPUT_DX2,
71
+ _XMC_UART_config->input_source_dx2 );
72
+
73
+ // Check if dx3 is used
74
+ if (_XMC_UART_config->input_source_dx3 != XMC_INPUT_INVALID)
75
+ XMC_USIC_CH_SetInputSource (_XMC_UART_config->channel , XMC_USIC_CH_INPUT_DX3,
76
+ _XMC_UART_config->input_source_dx3 );
77
+
78
+ XMC_UART_CH_EnableEvent (_XMC_UART_config->channel , XMC_UART_CH_EVENT_ALTERNATIVE_RECEIVE |
79
+ XMC_UART_CH_EVENT_STANDARD_RECEIVE);
80
+ XMC_USIC_CH_SetInterruptNodePointer (_XMC_UART_config->channel ,
81
+ XMC_USIC_CH_INTERRUPT_NODE_POINTER_RECEIVE,
82
+ _XMC_UART_config->irq_service_request );
83
+ XMC_USIC_CH_SetInterruptNodePointer (_XMC_UART_config->channel ,
84
+ XMC_USIC_CH_INTERRUPT_NODE_POINTER_ALTERNATE_RECEIVE,
85
+ _XMC_UART_config->irq_service_request );
86
+ XMC_USIC_CH_SetInterruptNodePointer (_XMC_UART_config->channel ,
87
+ XMC_USIC_CH_INTERRUPT_NODE_POINTER_TRANSMIT_BUFFER,
88
+ _XMC_UART_config->irq_service_request );
89
+ NVIC_SetPriority (_XMC_UART_config->irq_num , 3 );
90
+ NVIC_EnableIRQ (_XMC_UART_config->irq_num );
91
+
92
+ XMC_UART_CH_Start (_XMC_UART_config->channel );
93
+
94
+ // TX pin setup put here to avoid startup corrupted characters being first sent
95
+ XMC_GPIO_Init (_XMC_UART_config->tx .port , _XMC_UART_config->tx .pin ,
96
+ &(_XMC_UART_config->tx_config ));
97
+
98
+ XMC_GPIO_Init (_XMC_UART_config->rx .port , _XMC_UART_config->rx .pin ,
99
+ &(_XMC_UART_config->rx_config ));
100
+ }
101
+
102
+ void Uart::end (void ) {
103
+ // Wait for any outstanding data to be sent
104
+ flush ();
105
+ // Disable UART interrupt in NVIC
106
+ NVIC_DisableIRQ (_XMC_UART_config->irq_num );
107
+ // Clear any received data after stopping interrupts
108
+ _rx_buffer->_iHead = _rx_buffer->_iTail ;
109
+ }
110
+
111
+ void Uart::setInterruptPriority (uint32_t priority) {
112
+ NVIC_SetPriority (_XMC_UART_config->irq_num , priority & 0x03 );
113
+ }
114
+
115
+ uint32_t Uart::getInterruptPriority () { return NVIC_GetPriority (_XMC_UART_config->irq_num ); }
116
+
117
+ int Uart::available (void ) {
118
+ int head = _rx_buffer->_iHead ; // Snapshot index affected by irq
119
+ if (head >= _rx_buffer->_iTail )
120
+ return head - _rx_buffer->_iTail ;
121
+ return SERIAL_BUFFER_SIZE - _rx_buffer->_iTail + head;
122
+ }
123
+
124
+ int Uart::availableForWrite (void ) {
125
+ int tail = _tx_buffer->_iTail ; // Snapshot index affected by irq
126
+ if (_tx_buffer->_iHead >= tail)
127
+ return SERIAL_BUFFER_SIZE - 1 - _tx_buffer->_iHead + tail;
128
+ return tail - _tx_buffer->_iHead - 1 ;
129
+ }
130
+
131
+ int Uart::peek (void ) {
132
+ if (_rx_buffer->_iHead == _rx_buffer->_iTail )
133
+ return -1 ;
134
+ return _rx_buffer->_aucBuffer [_rx_buffer->_iTail ];
135
+ }
136
+
137
+ int Uart::read (void ) {
138
+ // if the head isn't ahead of the tail, we don't have any characters
139
+ if (_rx_buffer->_iHead == _rx_buffer->_iTail )
140
+ return -1 ;
141
+
142
+ uint8_t uc = _rx_buffer->_aucBuffer [_rx_buffer->_iTail ];
143
+ _rx_buffer->_iTail ++;
144
+ if (_rx_buffer->_iTail >= SERIAL_BUFFER_SIZE)
145
+ _rx_buffer->_iTail = 0 ;
146
+ return uc;
147
+ }
148
+
149
+ void Uart::flush (void ) {
150
+ while (_tx_buffer->_iHead != _tx_buffer->_iTail )
151
+ ; // wait for transmit data to be sent
152
+
153
+ while (XMC_USIC_CH_GetTransmitBufferStatus (_XMC_UART_config->channel ) ==
154
+ XMC_USIC_CH_TBUF_STATUS_BUSY)
155
+ ;
156
+ }
157
+
158
+ size_t Uart::write (const uint8_t uc_data) {
159
+ // Is the hardware currently busy?
160
+ #if defined(SERIAL_USE_U1C1)
161
+ if (_tx_buffer->_iTail != _tx_buffer->_iHead )
162
+ #else
163
+ if ((XMC_USIC_CH_GetTransmitBufferStatus (_XMC_UART_config->channel ) ==
164
+ XMC_USIC_CH_TBUF_STATUS_BUSY) ||
165
+ (_tx_buffer->_iTail != _tx_buffer->_iHead ))
166
+ #endif
167
+ {
168
+ // If busy we buffer
169
+ int nextWrite = _tx_buffer->_iHead + 1 ;
170
+ if (nextWrite >= SERIAL_BUFFER_SIZE)
171
+ nextWrite = 0 ;
172
+
173
+ // This should always be false but in case transmission is completed before buffer, we need
174
+ // to reenable IRQ
175
+ if (XMC_USIC_CH_GetTransmitBufferStatus (_XMC_UART_config->channel ) !=
176
+ XMC_USIC_CH_TBUF_STATUS_BUSY) {
177
+ XMC_UART_CH_EnableEvent (_XMC_UART_config->channel , XMC_UART_CH_EVENT_TRANSMIT_BUFFER);
178
+ XMC_UART_CH_Transmit (_XMC_UART_config->channel ,
179
+ _tx_buffer->_aucBuffer [_tx_buffer->_iTail ]);
180
+ _tx_buffer->_iTail ++;
181
+ if (_tx_buffer->_iTail >= SERIAL_BUFFER_SIZE)
182
+ _tx_buffer->_iTail %= SERIAL_BUFFER_SIZE; // If iTail is larger than Serial Buffer
183
+ // Size calculate the correct index value
184
+ }
185
+
186
+ unsigned long startTime = millis ();
187
+ while (_tx_buffer->_iTail == nextWrite) {
188
+ if (millis () - startTime > 1000 ) {
189
+ return 0 ; // Spin locks if we're about to overwrite the buffer. This continues once
190
+ // the data is
191
+ // sent
192
+ }
193
+ }
194
+
195
+ _tx_buffer->_aucBuffer [_tx_buffer->_iHead ] = uc_data;
196
+ _tx_buffer->_iHead = nextWrite;
197
+ } else {
198
+ // Make sure TX interrupt is enabled
199
+ XMC_UART_CH_EnableEvent (_XMC_UART_config->channel , XMC_UART_CH_EVENT_TRANSMIT_BUFFER);
200
+ // Bypass buffering and send character directly
201
+ XMC_UART_CH_Transmit (_XMC_UART_config->channel , uc_data);
202
+ }
203
+ return 1 ;
204
+ }
205
+
206
+ void Uart::IrqHandler (void ) {
207
+ uint32_t status = XMC_UART_CH_GetStatusFlag (_XMC_UART_config->channel );
208
+
209
+ // Did we receive data?
210
+ if ((status & (XMC_UART_CH_STATUS_FLAG_ALTERNATIVE_RECEIVE_INDICATION |
211
+ XMC_UART_CH_STATUS_FLAG_RECEIVE_INDICATION)) != 0U ) {
212
+ XMC_UART_CH_ClearStatusFlag (_XMC_UART_config->channel ,
213
+ (XMC_UART_CH_STATUS_FLAG_ALTERNATIVE_RECEIVE_INDICATION |
214
+ XMC_UART_CH_STATUS_FLAG_RECEIVE_INDICATION));
215
+
216
+ while (_XMC_UART_config->channel ->RBUFSR &
217
+ (USIC_CH_RBUFSR_RDV0_Msk | USIC_CH_RBUFSR_RDV1_Msk))
218
+ _rx_buffer->store_char (XMC_UART_CH_GetReceivedData (_XMC_UART_config->channel ));
219
+ }
220
+
221
+ // Do we need to keep sending data?
222
+ if ((status & XMC_UART_CH_STATUS_FLAG_TRANSMIT_BUFFER_INDICATION) != 0U ) {
223
+ XMC_UART_CH_ClearStatusFlag (_XMC_UART_config->channel ,
224
+ XMC_UART_CH_STATUS_FLAG_TRANSMIT_BUFFER_INDICATION);
225
+
226
+ if (_tx_buffer->_iTail != _tx_buffer->_iHead ) {
227
+ XMC_UART_CH_Transmit (_XMC_UART_config->channel ,
228
+ _tx_buffer->_aucBuffer [_tx_buffer->_iTail ]);
229
+ _tx_buffer->_iTail ++;
230
+ if (_tx_buffer->_iTail >= SERIAL_BUFFER_SIZE)
231
+ _tx_buffer->_iTail %= SERIAL_BUFFER_SIZE; // If iTail is larger than Serial Buffer
232
+ // Size calculate the correct index value
233
+ } else {
234
+ // Mask off transmit interrupt so we don't get it any more
235
+ XMC_UART_CH_DisableEvent (_XMC_UART_config->channel , XMC_UART_CH_EVENT_TRANSMIT_BUFFER);
236
+ }
237
+ }
238
+ }
239
+
240
+ // ****************************************************************************
241
+ // END OF FILE
242
+ // ****************************************************************************
0 commit comments