blob: a47ba0cc8506c21d8937ae47b9564536bb2ec602 [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 Redon30f90a72018-07-03 15:59:51 +0200136 /* Only store input if buffer is not full, else drop it */
137 bool trigger_isr = false;
138 if (rbuf_is_empty(&uart_tx_buffer)) {
139 trigger_isr = true;
Kévin Redoneac1bec2018-06-25 15:55:33 +0200140 }
Kévin Redon30f90a72018-07-03 15:59:51 +0200141 if (!rbuf_is_full(&uart_tx_buffer)) {
142 rbuf_write(&uart_tx_buffer, c);
143 }
144 if (trigger_isr) {
Kévin Redoneac1bec2018-06-25 15:55:33 +0200145 pUart->UART_IER = UART_IER_TXRDY;
146 CONSOLE_ISR();
147 }
Christina Quast8be71e42014-12-02 13:06:01 +0100148}
149
150/**
151 * \brief Input a character from the UART line.
152 *
153 * \note This function is synchronous
154 * \return character received.
155 */
156extern uint32_t UART_GetChar( void )
157{
Kévin Redoneac1bec2018-06-25 15:55:33 +0200158 Uart *pUart = CONSOLE_UART ;
Christina Quast8be71e42014-12-02 13:06:01 +0100159
160 if ( !_ucIsConsoleInitialized )
161 {
162 UART_Configure(CONSOLE_BAUDRATE, BOARD_MCK);
163 }
164
Harald Welte02d0ec62017-05-20 14:46:29 +0100165 while ( (pUart->UART_SR & UART_SR_RXRDY) == 0 )
166 WDT_Restart(WDT);
Christina Quast8be71e42014-12-02 13:06:01 +0100167
168 return pUart->UART_RHR ;
169}
170
171/**
172 * \brief Check if there is Input from UART line.
173 *
174 * \return true if there is Input.
175 */
176extern uint32_t UART_IsRxReady( void )
177{
Kévin Redoneac1bec2018-06-25 15:55:33 +0200178 Uart *pUart = CONSOLE_UART;
Christina Quast8be71e42014-12-02 13:06:01 +0100179
180 if ( !_ucIsConsoleInitialized )
181 {
182 UART_Configure( CONSOLE_BAUDRATE, BOARD_MCK ) ;
183 }
184
185 return (pUart->UART_SR & UART_SR_RXRDY) > 0 ;
186}
187
188/**
189 * Displays the content of the given frame on the UART0.
190 *
191 * \param pucFrame Pointer to the frame to dump.
192 * \param dwSize Buffer size in bytes.
193 */
194extern void UART_DumpFrame( uint8_t* pucFrame, uint32_t dwSize )
195{
196 uint32_t dw ;
197
198 for ( dw=0 ; dw < dwSize ; dw++ )
199 {
200 printf( "%02X ", pucFrame[dw] ) ;
201 }
202
203 printf( "\n\r" ) ;
204}
205
206/**
207 * Displays the content of the given buffer on the UART0.
208 *
209 * \param pucBuffer Pointer to the buffer to dump.
210 * \param dwSize Buffer size in bytes.
211 * \param dwAddress Start address to display
212 */
213extern void UART_DumpMemory( uint8_t* pucBuffer, uint32_t dwSize, uint32_t dwAddress )
214{
215 uint32_t i ;
216 uint32_t j ;
217 uint32_t dwLastLineStart ;
218 uint8_t* pucTmp ;
219
220 for ( i=0 ; i < (dwSize / 16) ; i++ )
221 {
222 printf( "0x%08X: ", (unsigned int)(dwAddress + (i*16)) ) ;
223 pucTmp = (uint8_t*)&pucBuffer[i*16] ;
224
225 for ( j=0 ; j < 4 ; j++ )
226 {
227 printf( "%02X%02X%02X%02X ", pucTmp[0], pucTmp[1], pucTmp[2], pucTmp[3] ) ;
228 pucTmp += 4 ;
229 }
230
231 pucTmp=(uint8_t*)&pucBuffer[i*16] ;
232
233 for ( j=0 ; j < 16 ; j++ )
234 {
235 UART_PutChar( *pucTmp++ ) ;
236 }
237
238 printf( "\n\r" ) ;
239 }
240
241 if ( (dwSize%16) != 0 )
242 {
243 dwLastLineStart=dwSize - (dwSize%16) ;
244
245 printf( "0x%08X: ", (unsigned int)(dwAddress + dwLastLineStart) ) ;
246 for ( j=dwLastLineStart ; j < dwLastLineStart+16 ; j++ )
247 {
248 if ( (j!=dwLastLineStart) && (j%4 == 0) )
249 {
250 printf( " " ) ;
251 }
252
253 if ( j < dwSize )
254 {
255 printf( "%02X", pucBuffer[j] ) ;
256 }
257 else
258 {
259 printf(" ") ;
260 }
261 }
262
263 printf( " " ) ;
264 for ( j=dwLastLineStart ; j < dwSize ; j++ )
265 {
266 UART_PutChar( pucBuffer[j] ) ;
267 }
268
269 printf( "\n\r" ) ;
270 }
271}
272
273/**
274 * Reads an integer
275 *
276 * \param pdwValue Pointer to the uint32_t variable to contain the input value.
277 */
278extern uint32_t UART_GetInteger( uint32_t* pdwValue )
279{
280 uint8_t ucKey ;
281 uint8_t ucNbNb=0 ;
282 uint32_t dwValue=0 ;
283
284 while ( 1 )
285 {
286 ucKey=UART_GetChar() ;
287 UART_PutChar( ucKey ) ;
288
289 if ( ucKey >= '0' && ucKey <= '9' )
290 {
291 dwValue = (dwValue * 10) + (ucKey - '0');
292 ucNbNb++ ;
293 }
294 else
295 {
296 if ( ucKey == 0x0D || ucKey == ' ' )
297 {
298 if ( ucNbNb == 0 )
299 {
300 printf( "\n\rWrite a number and press ENTER or SPACE!\n\r" ) ;
301 return 0 ;
302 }
303 else
304 {
305 printf( "\n\r" ) ;
306 *pdwValue=dwValue ;
307
308 return 1 ;
309 }
310 }
311 else
312 {
313 printf( "\n\r'%c' not a number!\n\r", ucKey ) ;
314
315 return 0 ;
316 }
317 }
Harald Welte02d0ec62017-05-20 14:46:29 +0100318 WDT_Restart(WDT);
Christina Quast8be71e42014-12-02 13:06:01 +0100319 }
320}
321
322/**
323 * Reads an integer and check the value
324 *
325 * \param pdwValue Pointer to the uint32_t variable to contain the input value.
326 * \param dwMin Minimum value
327 * \param dwMax Maximum value
328 */
329extern uint32_t UART_GetIntegerMinMax( uint32_t* pdwValue, uint32_t dwMin, uint32_t dwMax )
330{
331 uint32_t dwValue=0 ;
332
333 if ( UART_GetInteger( &dwValue ) == 0 )
334 {
335 return 0 ;
336 }
337
338 if ( dwValue < dwMin || dwValue > dwMax )
339 {
340 printf( "\n\rThe number have to be between %d and %d\n\r", (int)dwMin, (int)dwMax ) ;
341
342 return 0 ;
343 }
344
345 printf( "\n\r" ) ;
346
347 *pdwValue = dwValue ;
348
349 return 1 ;
350}
351
352/**
353 * Reads an hexadecimal number
354 *
355 * \param pdwValue Pointer to the uint32_t variable to contain the input value.
356 */
357extern uint32_t UART_GetHexa32( uint32_t* pdwValue )
358{
359 uint8_t ucKey ;
360 uint32_t dw = 0 ;
361 uint32_t dwValue = 0 ;
362
363 for ( dw=0 ; dw < 8 ; dw++ )
364 {
365 ucKey = UART_GetChar() ;
366 UART_PutChar( ucKey ) ;
367
368 if ( ucKey >= '0' && ucKey <= '9' )
369 {
370 dwValue = (dwValue * 16) + (ucKey - '0') ;
371 }
372 else
373 {
374 if ( ucKey >= 'A' && ucKey <= 'F' )
375 {
376 dwValue = (dwValue * 16) + (ucKey - 'A' + 10) ;
377 }
378 else
379 {
380 if ( ucKey >= 'a' && ucKey <= 'f' )
381 {
382 dwValue = (dwValue * 16) + (ucKey - 'a' + 10) ;
383 }
384 else
385 {
386 printf( "\n\rIt is not a hexa character!\n\r" ) ;
387
388 return 0 ;
389 }
390 }
391 }
392 }
393
394 printf("\n\r" ) ;
395 *pdwValue = dwValue ;
396
397 return 1 ;
398}
399
400#if defined __ICCARM__ /* IAR Ewarm 5.41+ */
401/**
402 * \brief Outputs a character on the UART.
403 *
404 * \param c Character to output.
405 *
406 * \return The character that was output.
407 */
408extern WEAK signed int putchar( signed int c )
409{
410 UART_PutChar( c ) ;
411
412 return c ;
413}
414#endif // defined __ICCARM__
415