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