blob: e52cd514d4382ffa317664aa38b3fb98af31b1de [file] [log] [blame]
Christina Quast8be71e42014-12-02 13:06:01 +01001/* ----------------------------------------------------------------------------
2 * ATMEL Microcontroller Software Support
3 * ----------------------------------------------------------------------------
4 * Copyright (c) 2009, Atmel Corporation
5 *
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * - Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the disclaimer below.
13 *
14 * Atmel's name may not be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
20 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 * ----------------------------------------------------------------------------
28 */
29
30/**
31 * \file
32 *
33 * Implements UART console.
34 *
35 */
36
37/*----------------------------------------------------------------------------
38 * Headers
39 *----------------------------------------------------------------------------*/
40
41#include "board.h"
42
43#include <stdio.h>
44#include <stdint.h>
45
Kévin Redoneac1bec2018-06-25 15:55:33 +020046#include "ringbuffer.h"
47
Christina Quast8be71e42014-12-02 13:06:01 +010048/*----------------------------------------------------------------------------
49 * Definitions
50 *----------------------------------------------------------------------------*/
51
Christina Quast8be71e42014-12-02 13:06:01 +010052/*----------------------------------------------------------------------------
53 * Variables
54 *----------------------------------------------------------------------------*/
55
56/** Is Console Initialized. */
Kévin Redoneac1bec2018-06-25 15:55:33 +020057static uint8_t _ucIsConsoleInitialized=0;
58/** Ring buffer to queue data to be sent */
59static ringbuf uart_tx_buffer;
Christina Quast8be71e42014-12-02 13:06:01 +010060
Christina Quast8be71e42014-12-02 13:06:01 +010061/**
62 * \brief Configures an USART peripheral with the specified parameters.
63 *
64 * \param baudrate Baudrate at which the USART should operate (in Hz).
65 * \param masterClock Frequency of the system master clock (in Hz).
66 */
67extern void UART_Configure( uint32_t baudrate, uint32_t masterClock)
68{
69 const Pin pPins[] = CONSOLE_PINS;
Kévin Redoneac1bec2018-06-25 15:55:33 +020070 Uart *pUart = CONSOLE_UART;
Christina Quast8be71e42014-12-02 13:06:01 +010071
72 /* Configure PIO */
73 PIO_Configure(pPins, PIO_LISTSIZE(pPins));
74
75 /* Configure PMC */
76 PMC->PMC_PCER0 = 1 << CONSOLE_ID;
77
78 /* Reset and disable receiver & transmitter */
79 pUart->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX
80 | UART_CR_RXDIS | UART_CR_TXDIS;
81
82 /* Configure mode */
83 pUart->UART_MR = UART_MR_PAR_NO;
84
85 /* Configure baudrate */
86 /* Asynchronous, no oversampling */
87 pUart->UART_BRGR = (masterClock / baudrate) / 16;
88
89 /* Disable PDC channel */
90 pUart->UART_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS;
91
Kévin Redoneac1bec2018-06-25 15:55:33 +020092 /* Reset transmit ring buffer */
93 rbuf_reset(&uart_tx_buffer);
94
95 /* Enable TX interrupts */
96 pUart->UART_IER = UART_IER_TXRDY;
97 NVIC_EnableIRQ(CONSOLE_IRQ);
98
Christina Quast8be71e42014-12-02 13:06:01 +010099 /* Enable receiver and transmitter */
100 pUart->UART_CR = UART_CR_RXEN | UART_CR_TXEN;
101
Kévin Redoneac1bec2018-06-25 15:55:33 +0200102 /* Remember the configuration is complete */
Christina Quast8be71e42014-12-02 13:06:01 +0100103 _ucIsConsoleInitialized=1 ;
104}
105
Kévin Redoneac1bec2018-06-25 15:55:33 +0200106/** Interrupt Service routine to transmit queued data */
107void CONSOLE_ISR(void)
108{
109 Uart *uart = CONSOLE_UART;
110 if (uart->UART_SR & UART_SR_TXRDY) {
111 if (!rbuf_is_empty(&uart_tx_buffer)) {
112 //uart->UART_IER = UART_IER_TXRDY;
113 uart->UART_THR = rbuf_read(&uart_tx_buffer);
114 } else {
115 uart->UART_IDR = UART_IER_TXRDY;
116 }
117 }
118}
119
Christina Quast8be71e42014-12-02 13:06:01 +0100120/**
121 * \brief Outputs a character on the UART line.
122 *
123 * \note This function is synchronous (i.e. uses polling).
124 * \param c Character to send.
125 */
126extern void UART_PutChar( uint8_t c )
127{
Kévin Redoneac1bec2018-06-25 15:55:33 +0200128 Uart *pUart = CONSOLE_UART ;
Christina Quast8be71e42014-12-02 13:06:01 +0100129
Kévin Redoneac1bec2018-06-25 15:55:33 +0200130 /* Initialize console is not already done */
Christina Quast8be71e42014-12-02 13:06:01 +0100131 if ( !_ucIsConsoleInitialized )
132 {
133 UART_Configure(CONSOLE_BAUDRATE, BOARD_MCK);
134 }
135
Kévin Redoneac1bec2018-06-25 15:55:33 +0200136 /* Wait until there is space in the buffer */
137 while (rbuf_is_full(&uart_tx_buffer)) {
138 if (pUart->UART_SR & UART_SR_TXEMPTY) {
139 pUart->UART_IER = UART_IER_TXRDY;
140 CONSOLE_ISR();
141 }
142 }
Christina Quast8be71e42014-12-02 13:06:01 +0100143
Kévin Redoneac1bec2018-06-25 15:55:33 +0200144 /* Put character into buffer */
145 rbuf_write(&uart_tx_buffer, c);
146 if (pUart->UART_SR & UART_SR_TXEMPTY) {
147 pUart->UART_IER = UART_IER_TXRDY;
148 CONSOLE_ISR();
149 }
Christina Quast8be71e42014-12-02 13:06:01 +0100150}
151
152/**
153 * \brief Input a character from the UART line.
154 *
155 * \note This function is synchronous
156 * \return character received.
157 */
158extern uint32_t UART_GetChar( void )
159{
Kévin Redoneac1bec2018-06-25 15:55:33 +0200160 Uart *pUart = CONSOLE_UART ;
Christina Quast8be71e42014-12-02 13:06:01 +0100161
162 if ( !_ucIsConsoleInitialized )
163 {
164 UART_Configure(CONSOLE_BAUDRATE, BOARD_MCK);
165 }
166
Harald Welte02d0ec62017-05-20 14:46:29 +0100167 while ( (pUart->UART_SR & UART_SR_RXRDY) == 0 )
168 WDT_Restart(WDT);
Christina Quast8be71e42014-12-02 13:06:01 +0100169
170 return pUart->UART_RHR ;
171}
172
173/**
174 * \brief Check if there is Input from UART line.
175 *
176 * \return true if there is Input.
177 */
178extern uint32_t UART_IsRxReady( void )
179{
Kévin Redoneac1bec2018-06-25 15:55:33 +0200180 Uart *pUart = CONSOLE_UART;
Christina Quast8be71e42014-12-02 13:06:01 +0100181
182 if ( !_ucIsConsoleInitialized )
183 {
184 UART_Configure( CONSOLE_BAUDRATE, BOARD_MCK ) ;
185 }
186
187 return (pUart->UART_SR & UART_SR_RXRDY) > 0 ;
188}
189
190/**
191 * Displays the content of the given frame on the UART0.
192 *
193 * \param pucFrame Pointer to the frame to dump.
194 * \param dwSize Buffer size in bytes.
195 */
196extern void UART_DumpFrame( uint8_t* pucFrame, uint32_t dwSize )
197{
198 uint32_t dw ;
199
200 for ( dw=0 ; dw < dwSize ; dw++ )
201 {
202 printf( "%02X ", pucFrame[dw] ) ;
203 }
204
205 printf( "\n\r" ) ;
206}
207
208/**
209 * Displays the content of the given buffer on the UART0.
210 *
211 * \param pucBuffer Pointer to the buffer to dump.
212 * \param dwSize Buffer size in bytes.
213 * \param dwAddress Start address to display
214 */
215extern void UART_DumpMemory( uint8_t* pucBuffer, uint32_t dwSize, uint32_t dwAddress )
216{
217 uint32_t i ;
218 uint32_t j ;
219 uint32_t dwLastLineStart ;
220 uint8_t* pucTmp ;
221
222 for ( i=0 ; i < (dwSize / 16) ; i++ )
223 {
224 printf( "0x%08X: ", (unsigned int)(dwAddress + (i*16)) ) ;
225 pucTmp = (uint8_t*)&pucBuffer[i*16] ;
226
227 for ( j=0 ; j < 4 ; j++ )
228 {
229 printf( "%02X%02X%02X%02X ", pucTmp[0], pucTmp[1], pucTmp[2], pucTmp[3] ) ;
230 pucTmp += 4 ;
231 }
232
233 pucTmp=(uint8_t*)&pucBuffer[i*16] ;
234
235 for ( j=0 ; j < 16 ; j++ )
236 {
237 UART_PutChar( *pucTmp++ ) ;
238 }
239
240 printf( "\n\r" ) ;
241 }
242
243 if ( (dwSize%16) != 0 )
244 {
245 dwLastLineStart=dwSize - (dwSize%16) ;
246
247 printf( "0x%08X: ", (unsigned int)(dwAddress + dwLastLineStart) ) ;
248 for ( j=dwLastLineStart ; j < dwLastLineStart+16 ; j++ )
249 {
250 if ( (j!=dwLastLineStart) && (j%4 == 0) )
251 {
252 printf( " " ) ;
253 }
254
255 if ( j < dwSize )
256 {
257 printf( "%02X", pucBuffer[j] ) ;
258 }
259 else
260 {
261 printf(" ") ;
262 }
263 }
264
265 printf( " " ) ;
266 for ( j=dwLastLineStart ; j < dwSize ; j++ )
267 {
268 UART_PutChar( pucBuffer[j] ) ;
269 }
270
271 printf( "\n\r" ) ;
272 }
273}
274
275/**
276 * Reads an integer
277 *
278 * \param pdwValue Pointer to the uint32_t variable to contain the input value.
279 */
280extern uint32_t UART_GetInteger( uint32_t* pdwValue )
281{
282 uint8_t ucKey ;
283 uint8_t ucNbNb=0 ;
284 uint32_t dwValue=0 ;
285
286 while ( 1 )
287 {
288 ucKey=UART_GetChar() ;
289 UART_PutChar( ucKey ) ;
290
291 if ( ucKey >= '0' && ucKey <= '9' )
292 {
293 dwValue = (dwValue * 10) + (ucKey - '0');
294 ucNbNb++ ;
295 }
296 else
297 {
298 if ( ucKey == 0x0D || ucKey == ' ' )
299 {
300 if ( ucNbNb == 0 )
301 {
302 printf( "\n\rWrite a number and press ENTER or SPACE!\n\r" ) ;
303 return 0 ;
304 }
305 else
306 {
307 printf( "\n\r" ) ;
308 *pdwValue=dwValue ;
309
310 return 1 ;
311 }
312 }
313 else
314 {
315 printf( "\n\r'%c' not a number!\n\r", ucKey ) ;
316
317 return 0 ;
318 }
319 }
Harald Welte02d0ec62017-05-20 14:46:29 +0100320 WDT_Restart(WDT);
Christina Quast8be71e42014-12-02 13:06:01 +0100321 }
322}
323
324/**
325 * Reads an integer and check the value
326 *
327 * \param pdwValue Pointer to the uint32_t variable to contain the input value.
328 * \param dwMin Minimum value
329 * \param dwMax Maximum value
330 */
331extern uint32_t UART_GetIntegerMinMax( uint32_t* pdwValue, uint32_t dwMin, uint32_t dwMax )
332{
333 uint32_t dwValue=0 ;
334
335 if ( UART_GetInteger( &dwValue ) == 0 )
336 {
337 return 0 ;
338 }
339
340 if ( dwValue < dwMin || dwValue > dwMax )
341 {
342 printf( "\n\rThe number have to be between %d and %d\n\r", (int)dwMin, (int)dwMax ) ;
343
344 return 0 ;
345 }
346
347 printf( "\n\r" ) ;
348
349 *pdwValue = dwValue ;
350
351 return 1 ;
352}
353
354/**
355 * Reads an hexadecimal number
356 *
357 * \param pdwValue Pointer to the uint32_t variable to contain the input value.
358 */
359extern uint32_t UART_GetHexa32( uint32_t* pdwValue )
360{
361 uint8_t ucKey ;
362 uint32_t dw = 0 ;
363 uint32_t dwValue = 0 ;
364
365 for ( dw=0 ; dw < 8 ; dw++ )
366 {
367 ucKey = UART_GetChar() ;
368 UART_PutChar( ucKey ) ;
369
370 if ( ucKey >= '0' && ucKey <= '9' )
371 {
372 dwValue = (dwValue * 16) + (ucKey - '0') ;
373 }
374 else
375 {
376 if ( ucKey >= 'A' && ucKey <= 'F' )
377 {
378 dwValue = (dwValue * 16) + (ucKey - 'A' + 10) ;
379 }
380 else
381 {
382 if ( ucKey >= 'a' && ucKey <= 'f' )
383 {
384 dwValue = (dwValue * 16) + (ucKey - 'a' + 10) ;
385 }
386 else
387 {
388 printf( "\n\rIt is not a hexa character!\n\r" ) ;
389
390 return 0 ;
391 }
392 }
393 }
394 }
395
396 printf("\n\r" ) ;
397 *pdwValue = dwValue ;
398
399 return 1 ;
400}
401
402#if defined __ICCARM__ /* IAR Ewarm 5.41+ */
403/**
404 * \brief Outputs a character on the UART.
405 *
406 * \param c Character to output.
407 *
408 * \return The character that was output.
409 */
410extern WEAK signed int putchar( signed int c )
411{
412 UART_PutChar( c ) ;
413
414 return c ;
415}
416#endif // defined __ICCARM__
417