blob: 3ce733199a3cb2f1bbcfd8a7ab467229134d1adc [file] [log] [blame]
Kévin Redon93717e42018-07-08 13:26:15 +02001/* ----------------------------------------------------------------------------
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
46#include "ringbuffer.h"
47
48/*----------------------------------------------------------------------------
49 * Definitions
50 *----------------------------------------------------------------------------*/
51
52/*----------------------------------------------------------------------------
53 * Variables
54 *----------------------------------------------------------------------------*/
55
56/** Is Console Initialized. */
57static uint8_t _ucIsConsoleInitialized=0;
58/** Ring buffer to queue data to be sent */
59static ringbuf uart_tx_buffer;
60
61/**
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{
Kévin Redon33d1eb72018-07-08 13:58:12 +020069 const Pin pPins[] = CONSOLE_PINS;
70 Uart *pUart = CONSOLE_UART;
Kévin Redon93717e42018-07-08 13:26:15 +020071
Kévin Redon33d1eb72018-07-08 13:58:12 +020072 /* Configure PIO */
73 PIO_Configure(pPins, PIO_LISTSIZE(pPins));
Kévin Redon93717e42018-07-08 13:26:15 +020074
Kévin Redon33d1eb72018-07-08 13:58:12 +020075 /* Configure PMC */
76 PMC->PMC_PCER0 = 1 << CONSOLE_ID;
Kévin Redon93717e42018-07-08 13:26:15 +020077
Kévin Redon33d1eb72018-07-08 13:58:12 +020078 /* Reset and disable receiver & transmitter */
79 pUart->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX
80 | UART_CR_RXDIS | UART_CR_TXDIS;
Kévin Redon93717e42018-07-08 13:26:15 +020081
Kévin Redon33d1eb72018-07-08 13:58:12 +020082 /* Configure mode */
83 pUart->UART_MR = UART_MR_PAR_NO;
Kévin Redon93717e42018-07-08 13:26:15 +020084
Kévin Redon33d1eb72018-07-08 13:58:12 +020085 /* Configure baudrate */
86 /* Asynchronous, no oversampling */
87 pUart->UART_BRGR = (masterClock / baudrate) / 16;
Kévin Redon93717e42018-07-08 13:26:15 +020088
Kévin Redon33d1eb72018-07-08 13:58:12 +020089 /* Disable PDC channel */
90 pUart->UART_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS;
Kévin Redon93717e42018-07-08 13:26:15 +020091
Kévin Redon33d1eb72018-07-08 13:58:12 +020092 /* Reset transmit ring buffer */
93 rbuf_reset(&uart_tx_buffer);
Kévin Redon93717e42018-07-08 13:26:15 +020094
Kévin Redon33d1eb72018-07-08 13:58:12 +020095 /* Enable TX interrupts */
96 pUart->UART_IER = UART_IER_TXRDY;
97 NVIC_EnableIRQ(CONSOLE_IRQ);
98
99 /* Enable receiver and transmitter */
100 pUart->UART_CR = UART_CR_RXEN | UART_CR_TXEN;
Kévin Redon93717e42018-07-08 13:26:15 +0200101
Kévin Redon33d1eb72018-07-08 13:58:12 +0200102 /* Remember the configuration is complete */
103 _ucIsConsoleInitialized=1 ;
Kévin Redon93717e42018-07-08 13:26:15 +0200104}
105
106/**
107 * \brief Disables the USART peripheral and related IRQ
108 */
109void UART_Exit(void)
110{
111 if (!_ucIsConsoleInitialized) {
112 return;
113 }
114
115 Uart *pUart = CONSOLE_UART;
116 pUart->UART_IDR = UART_IDR_TXRDY;
117 pUart->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX | UART_CR_RXDIS | UART_CR_TXDIS | UART_CR_RSTSTA;
118 PMC->PMC_PCDR0 = 1 << CONSOLE_ID;
119 NVIC_DisableIRQ(CONSOLE_IRQ);
120}
121
122/** Interrupt Service routine to transmit queued data */
123void CONSOLE_ISR(void)
124{
125 Uart *uart = CONSOLE_UART;
126 if (uart->UART_SR & UART_SR_TXRDY) {
127 if (!rbuf_is_empty(&uart_tx_buffer)) {
128 uart->UART_THR = rbuf_read(&uart_tx_buffer);
129 } else {
130 uart->UART_IDR = UART_IER_TXRDY;
131 }
132 }
133}
134
135/**
136 * \brief Outputs a character on the UART line.
137 *
138 * \note This function is synchronous (i.e. uses polling).
139 * \param c Character to send.
140 */
141extern void UART_PutChar( uint8_t c )
142{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200143 Uart *pUart = CONSOLE_UART ;
Kévin Redon93717e42018-07-08 13:26:15 +0200144
Kévin Redon33d1eb72018-07-08 13:58:12 +0200145 /* Initialize console is not already done */
146 if ( !_ucIsConsoleInitialized )
147 {
148 UART_Configure(CONSOLE_BAUDRATE, BOARD_MCK);
149 }
Kévin Redon93717e42018-07-08 13:26:15 +0200150
Kévin Redon33d1eb72018-07-08 13:58:12 +0200151 /* Only store input if buffer is not full, else drop it */
152 if (!rbuf_is_full(&uart_tx_buffer)) {
153 rbuf_write(&uart_tx_buffer, c);
154 if (!(pUart->UART_IMR & UART_IMR_TXRDY)) {
155 pUart->UART_IER = UART_IER_TXRDY;
156 CONSOLE_ISR();
157 }
158 }
Kévin Redon93717e42018-07-08 13:26:15 +0200159}
160
161/**
162 * \brief Input a character from the UART line.
163 *
164 * \note This function is synchronous
165 * \return character received.
166 */
167extern uint32_t UART_GetChar( void )
168{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200169 Uart *pUart = CONSOLE_UART ;
Kévin Redon93717e42018-07-08 13:26:15 +0200170
Kévin Redon33d1eb72018-07-08 13:58:12 +0200171 if ( !_ucIsConsoleInitialized )
172 {
173 UART_Configure(CONSOLE_BAUDRATE, BOARD_MCK);
174 }
Kévin Redon93717e42018-07-08 13:26:15 +0200175
Kévin Redon33d1eb72018-07-08 13:58:12 +0200176 while ( (pUart->UART_SR & UART_SR_RXRDY) == 0 )
177 WDT_Restart(WDT);
Kévin Redon93717e42018-07-08 13:26:15 +0200178
Kévin Redon33d1eb72018-07-08 13:58:12 +0200179 return pUart->UART_RHR ;
Kévin Redon93717e42018-07-08 13:26:15 +0200180}
181
182/**
183 * \brief Check if there is Input from UART line.
184 *
185 * \return true if there is Input.
186 */
187extern uint32_t UART_IsRxReady( void )
188{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200189 Uart *pUart = CONSOLE_UART;
Kévin Redon93717e42018-07-08 13:26:15 +0200190
Kévin Redon33d1eb72018-07-08 13:58:12 +0200191 if ( !_ucIsConsoleInitialized )
192 {
193 UART_Configure( CONSOLE_BAUDRATE, BOARD_MCK ) ;
194 }
Kévin Redon93717e42018-07-08 13:26:15 +0200195
Kévin Redon33d1eb72018-07-08 13:58:12 +0200196 return (pUart->UART_SR & UART_SR_RXRDY) > 0 ;
Kévin Redon93717e42018-07-08 13:26:15 +0200197}
198
199/**
200 * Displays the content of the given frame on the UART0.
201 *
202 * \param pucFrame Pointer to the frame to dump.
203 * \param dwSize Buffer size in bytes.
204 */
205extern void UART_DumpFrame( uint8_t* pucFrame, uint32_t dwSize )
206{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200207 uint32_t dw ;
Kévin Redon93717e42018-07-08 13:26:15 +0200208
Kévin Redon33d1eb72018-07-08 13:58:12 +0200209 for ( dw=0 ; dw < dwSize ; dw++ )
210 {
211 printf( "%02X ", pucFrame[dw] ) ;
212 }
Kévin Redon93717e42018-07-08 13:26:15 +0200213
Kévin Redon33d1eb72018-07-08 13:58:12 +0200214 printf( "\n\r" ) ;
Kévin Redon93717e42018-07-08 13:26:15 +0200215}
216
217/**
218 * Displays the content of the given buffer on the UART0.
219 *
220 * \param pucBuffer Pointer to the buffer to dump.
221 * \param dwSize Buffer size in bytes.
222 * \param dwAddress Start address to display
223 */
224extern void UART_DumpMemory( uint8_t* pucBuffer, uint32_t dwSize, uint32_t dwAddress )
225{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200226 uint32_t i ;
227 uint32_t j ;
228 uint32_t dwLastLineStart ;
229 uint8_t* pucTmp ;
Kévin Redon93717e42018-07-08 13:26:15 +0200230
Kévin Redon33d1eb72018-07-08 13:58:12 +0200231 for ( i=0 ; i < (dwSize / 16) ; i++ )
232 {
233 printf( "0x%08X: ", (unsigned int)(dwAddress + (i*16)) ) ;
234 pucTmp = (uint8_t*)&pucBuffer[i*16] ;
Kévin Redon93717e42018-07-08 13:26:15 +0200235
Kévin Redon33d1eb72018-07-08 13:58:12 +0200236 for ( j=0 ; j < 4 ; j++ )
237 {
238 printf( "%02X%02X%02X%02X ", pucTmp[0], pucTmp[1], pucTmp[2], pucTmp[3] ) ;
239 pucTmp += 4 ;
240 }
Kévin Redon93717e42018-07-08 13:26:15 +0200241
Kévin Redon33d1eb72018-07-08 13:58:12 +0200242 pucTmp=(uint8_t*)&pucBuffer[i*16] ;
Kévin Redon93717e42018-07-08 13:26:15 +0200243
Kévin Redon33d1eb72018-07-08 13:58:12 +0200244 for ( j=0 ; j < 16 ; j++ )
245 {
246 UART_PutChar( *pucTmp++ ) ;
247 }
Kévin Redon93717e42018-07-08 13:26:15 +0200248
Kévin Redon33d1eb72018-07-08 13:58:12 +0200249 printf( "\n\r" ) ;
250 }
Kévin Redon93717e42018-07-08 13:26:15 +0200251
Kévin Redon33d1eb72018-07-08 13:58:12 +0200252 if ( (dwSize%16) != 0 )
253 {
254 dwLastLineStart=dwSize - (dwSize%16) ;
Kévin Redon93717e42018-07-08 13:26:15 +0200255
Kévin Redon33d1eb72018-07-08 13:58:12 +0200256 printf( "0x%08X: ", (unsigned int)(dwAddress + dwLastLineStart) ) ;
257 for ( j=dwLastLineStart ; j < dwLastLineStart+16 ; j++ )
258 {
259 if ( (j!=dwLastLineStart) && (j%4 == 0) )
260 {
261 printf( " " ) ;
262 }
Kévin Redon93717e42018-07-08 13:26:15 +0200263
Kévin Redon33d1eb72018-07-08 13:58:12 +0200264 if ( j < dwSize )
265 {
266 printf( "%02X", pucBuffer[j] ) ;
267 }
268 else
269 {
270 printf(" ") ;
271 }
272 }
Kévin Redon93717e42018-07-08 13:26:15 +0200273
Kévin Redon33d1eb72018-07-08 13:58:12 +0200274 printf( " " ) ;
275 for ( j=dwLastLineStart ; j < dwSize ; j++ )
276 {
277 UART_PutChar( pucBuffer[j] ) ;
278 }
Kévin Redon93717e42018-07-08 13:26:15 +0200279
Kévin Redon33d1eb72018-07-08 13:58:12 +0200280 printf( "\n\r" ) ;
281 }
Kévin Redon93717e42018-07-08 13:26:15 +0200282}
283
284/**
285 * Reads an integer
286 *
287 * \param pdwValue Pointer to the uint32_t variable to contain the input value.
288 */
289extern uint32_t UART_GetInteger( uint32_t* pdwValue )
290{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200291 uint8_t ucKey ;
292 uint8_t ucNbNb=0 ;
293 uint32_t dwValue=0 ;
Kévin Redon93717e42018-07-08 13:26:15 +0200294
Kévin Redon33d1eb72018-07-08 13:58:12 +0200295 while ( 1 )
296 {
297 ucKey=UART_GetChar() ;
298 UART_PutChar( ucKey ) ;
Kévin Redon93717e42018-07-08 13:26:15 +0200299
Kévin Redon33d1eb72018-07-08 13:58:12 +0200300 if ( ucKey >= '0' && ucKey <= '9' )
301 {
302 dwValue = (dwValue * 10) + (ucKey - '0');
303 ucNbNb++ ;
304 }
305 else
306 {
307 if ( ucKey == 0x0D || ucKey == ' ' )
308 {
309 if ( ucNbNb == 0 )
310 {
311 printf( "\n\rWrite a number and press ENTER or SPACE!\n\r" ) ;
312 return 0 ;
313 }
314 else
315 {
316 printf( "\n\r" ) ;
317 *pdwValue=dwValue ;
Kévin Redon93717e42018-07-08 13:26:15 +0200318
Kévin Redon33d1eb72018-07-08 13:58:12 +0200319 return 1 ;
320 }
321 }
322 else
323 {
324 printf( "\n\r'%c' not a number!\n\r", ucKey ) ;
Kévin Redon93717e42018-07-08 13:26:15 +0200325
Kévin Redon33d1eb72018-07-08 13:58:12 +0200326 return 0 ;
327 }
328 }
329 WDT_Restart(WDT);
330 }
Kévin Redon93717e42018-07-08 13:26:15 +0200331}
332
333/**
334 * Reads an integer and check the value
335 *
336 * \param pdwValue Pointer to the uint32_t variable to contain the input value.
337 * \param dwMin Minimum value
338 * \param dwMax Maximum value
339 */
340extern uint32_t UART_GetIntegerMinMax( uint32_t* pdwValue, uint32_t dwMin, uint32_t dwMax )
341{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200342 uint32_t dwValue=0 ;
Kévin Redon93717e42018-07-08 13:26:15 +0200343
Kévin Redon33d1eb72018-07-08 13:58:12 +0200344 if ( UART_GetInteger( &dwValue ) == 0 )
345 {
346 return 0 ;
347 }
Kévin Redon93717e42018-07-08 13:26:15 +0200348
Kévin Redon33d1eb72018-07-08 13:58:12 +0200349 if ( dwValue < dwMin || dwValue > dwMax )
Kévin Redon93717e42018-07-08 13:26:15 +0200350 {
Kévin Redon33d1eb72018-07-08 13:58:12 +0200351 printf( "\n\rThe number have to be between %d and %d\n\r", (int)dwMin, (int)dwMax ) ;
Kévin Redon93717e42018-07-08 13:26:15 +0200352
Kévin Redon33d1eb72018-07-08 13:58:12 +0200353 return 0 ;
354 }
Kévin Redon93717e42018-07-08 13:26:15 +0200355
Kévin Redon33d1eb72018-07-08 13:58:12 +0200356 printf( "\n\r" ) ;
Kévin Redon93717e42018-07-08 13:26:15 +0200357
Kévin Redon33d1eb72018-07-08 13:58:12 +0200358 *pdwValue = dwValue ;
Kévin Redon93717e42018-07-08 13:26:15 +0200359
Kévin Redon33d1eb72018-07-08 13:58:12 +0200360 return 1 ;
Kévin Redon93717e42018-07-08 13:26:15 +0200361}
362
363/**
364 * Reads an hexadecimal number
365 *
366 * \param pdwValue Pointer to the uint32_t variable to contain the input value.
367 */
368extern uint32_t UART_GetHexa32( uint32_t* pdwValue )
369{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200370 uint8_t ucKey ;
371 uint32_t dw = 0 ;
372 uint32_t dwValue = 0 ;
Kévin Redon93717e42018-07-08 13:26:15 +0200373
Kévin Redon33d1eb72018-07-08 13:58:12 +0200374 for ( dw=0 ; dw < 8 ; dw++ )
375 {
376 ucKey = UART_GetChar() ;
377 UART_PutChar( ucKey ) ;
Kévin Redon93717e42018-07-08 13:26:15 +0200378
Kévin Redon33d1eb72018-07-08 13:58:12 +0200379 if ( ucKey >= '0' && ucKey <= '9' )
380 {
381 dwValue = (dwValue * 16) + (ucKey - '0') ;
382 }
383 else
384 {
385 if ( ucKey >= 'A' && ucKey <= 'F' )
386 {
387 dwValue = (dwValue * 16) + (ucKey - 'A' + 10) ;
388 }
389 else
390 {
391 if ( ucKey >= 'a' && ucKey <= 'f' )
392 {
393 dwValue = (dwValue * 16) + (ucKey - 'a' + 10) ;
394 }
395 else
396 {
397 printf( "\n\rIt is not a hexa character!\n\r" ) ;
Kévin Redon93717e42018-07-08 13:26:15 +0200398
Kévin Redon33d1eb72018-07-08 13:58:12 +0200399 return 0 ;
400 }
401 }
402 }
403 }
Kévin Redon93717e42018-07-08 13:26:15 +0200404
Kévin Redon33d1eb72018-07-08 13:58:12 +0200405 printf("\n\r" ) ;
406 *pdwValue = dwValue ;
Kévin Redon93717e42018-07-08 13:26:15 +0200407
Kévin Redon33d1eb72018-07-08 13:58:12 +0200408 return 1 ;
Kévin Redon93717e42018-07-08 13:26:15 +0200409}
410
411#if defined __ICCARM__ /* IAR Ewarm 5.41+ */
412/**
413 * \brief Outputs a character on the UART.
414 *
415 * \param c Character to output.
416 *
417 * \return The character that was output.
418 */
419extern WEAK signed int putchar( signed int c )
420{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200421 UART_PutChar( c ) ;
Kévin Redon93717e42018-07-08 13:26:15 +0200422
Kévin Redon33d1eb72018-07-08 13:58:12 +0200423 return c ;
Kévin Redon93717e42018-07-08 13:26:15 +0200424}
425#endif // defined __ICCARM__
426