blob: 3a00e49f49cd490780944e544aaf4c0a905302b1 [file] [log] [blame]
Kévin Redon93717e42018-07-08 13:26:15 +02001/* ----------------------------------------------------------------------------
2 * ATMEL Microcontroller Software Support
3 * ----------------------------------------------------------------------------
4 * Copyright (c) 2009, Atmel Corporation
Kévin Redon1836ac02018-08-02 15:02:05 +02005 * Copyright (c) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
Kévin Redon93717e42018-07-08 13:26:15 +02006 *
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * - Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the disclaimer below.
14 *
15 * Atmel's name may not be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
21 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * ----------------------------------------------------------------------------
29 */
30
31/**
32 * \file
33 *
34 * Implements UART console.
35 *
36 */
37
38/*----------------------------------------------------------------------------
39 * Headers
40 *----------------------------------------------------------------------------*/
41
42#include "board.h"
43
44#include <stdio.h>
45#include <stdint.h>
46
47#include "ringbuffer.h"
48
49/*----------------------------------------------------------------------------
50 * Definitions
51 *----------------------------------------------------------------------------*/
52
53/*----------------------------------------------------------------------------
54 * Variables
55 *----------------------------------------------------------------------------*/
56
57/** Is Console Initialized. */
58static uint8_t _ucIsConsoleInitialized=0;
59/** Ring buffer to queue data to be sent */
60static ringbuf uart_tx_buffer;
61
62/**
63 * \brief Configures an USART peripheral with the specified parameters.
64 *
65 * \param baudrate Baudrate at which the USART should operate (in Hz).
66 * \param masterClock Frequency of the system master clock (in Hz).
67 */
68extern void UART_Configure( uint32_t baudrate, uint32_t masterClock)
69{
Kévin Redon33d1eb72018-07-08 13:58:12 +020070 const Pin pPins[] = CONSOLE_PINS;
71 Uart *pUart = CONSOLE_UART;
Kévin Redon93717e42018-07-08 13:26:15 +020072
Kévin Redon33d1eb72018-07-08 13:58:12 +020073 /* Configure PIO */
74 PIO_Configure(pPins, PIO_LISTSIZE(pPins));
Kévin Redon93717e42018-07-08 13:26:15 +020075
Kévin Redon33d1eb72018-07-08 13:58:12 +020076 /* Configure PMC */
77 PMC->PMC_PCER0 = 1 << CONSOLE_ID;
Kévin Redon93717e42018-07-08 13:26:15 +020078
Kévin Redon33d1eb72018-07-08 13:58:12 +020079 /* Reset and disable receiver & transmitter */
80 pUart->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX
81 | UART_CR_RXDIS | UART_CR_TXDIS;
Kévin Redon93717e42018-07-08 13:26:15 +020082
Kévin Redon33d1eb72018-07-08 13:58:12 +020083 /* Configure mode */
84 pUart->UART_MR = UART_MR_PAR_NO;
Kévin Redon93717e42018-07-08 13:26:15 +020085
Kévin Redon33d1eb72018-07-08 13:58:12 +020086 /* Configure baudrate */
87 /* Asynchronous, no oversampling */
88 pUart->UART_BRGR = (masterClock / baudrate) / 16;
Kévin Redon93717e42018-07-08 13:26:15 +020089
Kévin Redon33d1eb72018-07-08 13:58:12 +020090 /* Disable PDC channel */
91 pUart->UART_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS;
Kévin Redon93717e42018-07-08 13:26:15 +020092
Kévin Redon33d1eb72018-07-08 13:58:12 +020093 /* Reset transmit ring buffer */
94 rbuf_reset(&uart_tx_buffer);
Kévin Redon93717e42018-07-08 13:26:15 +020095
Kévin Redon33d1eb72018-07-08 13:58:12 +020096 /* Enable TX interrupts */
97 pUart->UART_IER = UART_IER_TXRDY;
98 NVIC_EnableIRQ(CONSOLE_IRQ);
99
100 /* Enable receiver and transmitter */
101 pUart->UART_CR = UART_CR_RXEN | UART_CR_TXEN;
Kévin Redon93717e42018-07-08 13:26:15 +0200102
Kévin Redon33d1eb72018-07-08 13:58:12 +0200103 /* Remember the configuration is complete */
104 _ucIsConsoleInitialized=1 ;
Kévin Redon93717e42018-07-08 13:26:15 +0200105}
106
107/**
108 * \brief Disables the USART peripheral and related IRQ
109 */
110void UART_Exit(void)
111{
112 if (!_ucIsConsoleInitialized) {
113 return;
114 }
115
116 Uart *pUart = CONSOLE_UART;
117 pUart->UART_IDR = UART_IDR_TXRDY;
118 pUart->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX | UART_CR_RXDIS | UART_CR_TXDIS | UART_CR_RSTSTA;
119 PMC->PMC_PCDR0 = 1 << CONSOLE_ID;
120 NVIC_DisableIRQ(CONSOLE_IRQ);
121}
122
123/** Interrupt Service routine to transmit queued data */
124void CONSOLE_ISR(void)
125{
126 Uart *uart = CONSOLE_UART;
127 if (uart->UART_SR & UART_SR_TXRDY) {
128 if (!rbuf_is_empty(&uart_tx_buffer)) {
129 uart->UART_THR = rbuf_read(&uart_tx_buffer);
130 } else {
131 uart->UART_IDR = UART_IER_TXRDY;
132 }
133 }
134}
135
136/**
137 * \brief Outputs a character on the UART line.
138 *
Kévin Redon1836ac02018-08-02 15:02:05 +0200139 * \note This function is asynchronous (i.e. uses a buffer and interrupt to complete the transfer).
Kévin Redon93717e42018-07-08 13:26:15 +0200140 * \param c Character to send.
141 */
Kévin Redon1836ac02018-08-02 15:02:05 +0200142void UART_PutChar( uint8_t uc )
Kévin Redon93717e42018-07-08 13:26:15 +0200143{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200144 Uart *pUart = CONSOLE_UART ;
Kévin Redon93717e42018-07-08 13:26:15 +0200145
Kévin Redon33d1eb72018-07-08 13:58:12 +0200146 /* Initialize console is not already done */
147 if ( !_ucIsConsoleInitialized )
148 {
149 UART_Configure(CONSOLE_BAUDRATE, BOARD_MCK);
150 }
Kévin Redon93717e42018-07-08 13:26:15 +0200151
Kévin Redon33d1eb72018-07-08 13:58:12 +0200152 if (!rbuf_is_full(&uart_tx_buffer)) {
Kévin Redon1836ac02018-08-02 15:02:05 +0200153 rbuf_write(&uart_tx_buffer, uc);
Kévin Redon33d1eb72018-07-08 13:58:12 +0200154 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/**
Kévin Redon1836ac02018-08-02 15:02:05 +0200162 * \brief Outputs a character on the UART line.
163 *
164 * \note This function is synchronous (i.e. uses polling and blocks until the transfer is complete).
165 * \param c Character to send.
166 */
167void UART_PutChar_Sync( uint8_t uc )
168{
169 Uart *pUart = CONSOLE_UART ;
170
171 /* Initialize console is not already done */
172 if ( !_ucIsConsoleInitialized )
173 {
174 UART_Configure(CONSOLE_BAUDRATE, BOARD_MCK);
175 }
176
177 while (!(pUart->UART_SR & UART_SR_TXRDY)); /* Wait for transfer buffer to be empty */
178 pUart->UART_THR = uc; /* Send data to UART peripheral */
179 while (!(pUart->UART_SR & UART_SR_TXRDY)); /* Wait for transfer buffer to transferred to shift register */
180 while (!(pUart->UART_SR & UART_SR_TXEMPTY)); /* Wait for transfer shift register to be empty (i.e. transfer is complete) */
181}
182
183/**
Kévin Redon93717e42018-07-08 13:26:15 +0200184 * \brief Input a character from the UART line.
185 *
186 * \note This function is synchronous
187 * \return character received.
188 */
189extern uint32_t UART_GetChar( void )
190{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200191 Uart *pUart = CONSOLE_UART ;
Kévin Redon93717e42018-07-08 13:26:15 +0200192
Kévin Redon33d1eb72018-07-08 13:58:12 +0200193 if ( !_ucIsConsoleInitialized )
194 {
195 UART_Configure(CONSOLE_BAUDRATE, BOARD_MCK);
196 }
Kévin Redon93717e42018-07-08 13:26:15 +0200197
Kévin Redon33d1eb72018-07-08 13:58:12 +0200198 while ( (pUart->UART_SR & UART_SR_RXRDY) == 0 )
199 WDT_Restart(WDT);
Kévin Redon93717e42018-07-08 13:26:15 +0200200
Kévin Redon33d1eb72018-07-08 13:58:12 +0200201 return pUart->UART_RHR ;
Kévin Redon93717e42018-07-08 13:26:15 +0200202}
203
204/**
205 * \brief Check if there is Input from UART line.
206 *
207 * \return true if there is Input.
208 */
209extern uint32_t UART_IsRxReady( void )
210{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200211 Uart *pUart = CONSOLE_UART;
Kévin Redon93717e42018-07-08 13:26:15 +0200212
Kévin Redon33d1eb72018-07-08 13:58:12 +0200213 if ( !_ucIsConsoleInitialized )
214 {
215 UART_Configure( CONSOLE_BAUDRATE, BOARD_MCK ) ;
216 }
Kévin Redon93717e42018-07-08 13:26:15 +0200217
Kévin Redon33d1eb72018-07-08 13:58:12 +0200218 return (pUart->UART_SR & UART_SR_RXRDY) > 0 ;
Kévin Redon93717e42018-07-08 13:26:15 +0200219}
220
221/**
222 * Displays the content of the given frame on the UART0.
223 *
224 * \param pucFrame Pointer to the frame to dump.
225 * \param dwSize Buffer size in bytes.
226 */
227extern void UART_DumpFrame( uint8_t* pucFrame, uint32_t dwSize )
228{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200229 uint32_t dw ;
Kévin Redon93717e42018-07-08 13:26:15 +0200230
Kévin Redon33d1eb72018-07-08 13:58:12 +0200231 for ( dw=0 ; dw < dwSize ; dw++ )
232 {
233 printf( "%02X ", pucFrame[dw] ) ;
234 }
Kévin Redon93717e42018-07-08 13:26:15 +0200235
Kévin Redon33d1eb72018-07-08 13:58:12 +0200236 printf( "\n\r" ) ;
Kévin Redon93717e42018-07-08 13:26:15 +0200237}
238
239/**
240 * Displays the content of the given buffer on the UART0.
241 *
242 * \param pucBuffer Pointer to the buffer to dump.
243 * \param dwSize Buffer size in bytes.
244 * \param dwAddress Start address to display
245 */
246extern void UART_DumpMemory( uint8_t* pucBuffer, uint32_t dwSize, uint32_t dwAddress )
247{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200248 uint32_t i ;
249 uint32_t j ;
250 uint32_t dwLastLineStart ;
251 uint8_t* pucTmp ;
Kévin Redon93717e42018-07-08 13:26:15 +0200252
Kévin Redon33d1eb72018-07-08 13:58:12 +0200253 for ( i=0 ; i < (dwSize / 16) ; i++ )
254 {
255 printf( "0x%08X: ", (unsigned int)(dwAddress + (i*16)) ) ;
256 pucTmp = (uint8_t*)&pucBuffer[i*16] ;
Kévin Redon93717e42018-07-08 13:26:15 +0200257
Kévin Redon33d1eb72018-07-08 13:58:12 +0200258 for ( j=0 ; j < 4 ; j++ )
259 {
260 printf( "%02X%02X%02X%02X ", pucTmp[0], pucTmp[1], pucTmp[2], pucTmp[3] ) ;
261 pucTmp += 4 ;
262 }
Kévin Redon93717e42018-07-08 13:26:15 +0200263
Kévin Redon33d1eb72018-07-08 13:58:12 +0200264 pucTmp=(uint8_t*)&pucBuffer[i*16] ;
Kévin Redon93717e42018-07-08 13:26:15 +0200265
Kévin Redon33d1eb72018-07-08 13:58:12 +0200266 for ( j=0 ; j < 16 ; j++ )
267 {
268 UART_PutChar( *pucTmp++ ) ;
269 }
Kévin Redon93717e42018-07-08 13:26:15 +0200270
Kévin Redon33d1eb72018-07-08 13:58:12 +0200271 printf( "\n\r" ) ;
272 }
Kévin Redon93717e42018-07-08 13:26:15 +0200273
Kévin Redon33d1eb72018-07-08 13:58:12 +0200274 if ( (dwSize%16) != 0 )
275 {
276 dwLastLineStart=dwSize - (dwSize%16) ;
Kévin Redon93717e42018-07-08 13:26:15 +0200277
Kévin Redon33d1eb72018-07-08 13:58:12 +0200278 printf( "0x%08X: ", (unsigned int)(dwAddress + dwLastLineStart) ) ;
279 for ( j=dwLastLineStart ; j < dwLastLineStart+16 ; j++ )
280 {
281 if ( (j!=dwLastLineStart) && (j%4 == 0) )
282 {
283 printf( " " ) ;
284 }
Kévin Redon93717e42018-07-08 13:26:15 +0200285
Kévin Redon33d1eb72018-07-08 13:58:12 +0200286 if ( j < dwSize )
287 {
288 printf( "%02X", pucBuffer[j] ) ;
289 }
290 else
291 {
292 printf(" ") ;
293 }
294 }
Kévin Redon93717e42018-07-08 13:26:15 +0200295
Kévin Redon33d1eb72018-07-08 13:58:12 +0200296 printf( " " ) ;
297 for ( j=dwLastLineStart ; j < dwSize ; j++ )
298 {
299 UART_PutChar( pucBuffer[j] ) ;
300 }
Kévin Redon93717e42018-07-08 13:26:15 +0200301
Kévin Redon33d1eb72018-07-08 13:58:12 +0200302 printf( "\n\r" ) ;
303 }
Kévin Redon93717e42018-07-08 13:26:15 +0200304}
305
306/**
307 * Reads an integer
308 *
309 * \param pdwValue Pointer to the uint32_t variable to contain the input value.
310 */
311extern uint32_t UART_GetInteger( uint32_t* pdwValue )
312{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200313 uint8_t ucKey ;
314 uint8_t ucNbNb=0 ;
315 uint32_t dwValue=0 ;
Kévin Redon93717e42018-07-08 13:26:15 +0200316
Kévin Redon33d1eb72018-07-08 13:58:12 +0200317 while ( 1 )
318 {
319 ucKey=UART_GetChar() ;
320 UART_PutChar( ucKey ) ;
Kévin Redon93717e42018-07-08 13:26:15 +0200321
Kévin Redon33d1eb72018-07-08 13:58:12 +0200322 if ( ucKey >= '0' && ucKey <= '9' )
323 {
324 dwValue = (dwValue * 10) + (ucKey - '0');
325 ucNbNb++ ;
326 }
327 else
328 {
329 if ( ucKey == 0x0D || ucKey == ' ' )
330 {
331 if ( ucNbNb == 0 )
332 {
333 printf( "\n\rWrite a number and press ENTER or SPACE!\n\r" ) ;
334 return 0 ;
335 }
336 else
337 {
338 printf( "\n\r" ) ;
339 *pdwValue=dwValue ;
Kévin Redon93717e42018-07-08 13:26:15 +0200340
Kévin Redon33d1eb72018-07-08 13:58:12 +0200341 return 1 ;
342 }
343 }
344 else
345 {
346 printf( "\n\r'%c' not a number!\n\r", ucKey ) ;
Kévin Redon93717e42018-07-08 13:26:15 +0200347
Kévin Redon33d1eb72018-07-08 13:58:12 +0200348 return 0 ;
349 }
350 }
351 WDT_Restart(WDT);
352 }
Kévin Redon93717e42018-07-08 13:26:15 +0200353}
354
355/**
356 * Reads an integer and check the value
357 *
358 * \param pdwValue Pointer to the uint32_t variable to contain the input value.
359 * \param dwMin Minimum value
360 * \param dwMax Maximum value
361 */
362extern uint32_t UART_GetIntegerMinMax( uint32_t* pdwValue, uint32_t dwMin, uint32_t dwMax )
363{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200364 uint32_t dwValue=0 ;
Kévin Redon93717e42018-07-08 13:26:15 +0200365
Kévin Redon33d1eb72018-07-08 13:58:12 +0200366 if ( UART_GetInteger( &dwValue ) == 0 )
367 {
368 return 0 ;
369 }
Kévin Redon93717e42018-07-08 13:26:15 +0200370
Kévin Redon33d1eb72018-07-08 13:58:12 +0200371 if ( dwValue < dwMin || dwValue > dwMax )
Kévin Redon93717e42018-07-08 13:26:15 +0200372 {
Kévin Redon33d1eb72018-07-08 13:58:12 +0200373 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 +0200374
Kévin Redon33d1eb72018-07-08 13:58:12 +0200375 return 0 ;
376 }
Kévin Redon93717e42018-07-08 13:26:15 +0200377
Kévin Redon33d1eb72018-07-08 13:58:12 +0200378 printf( "\n\r" ) ;
Kévin Redon93717e42018-07-08 13:26:15 +0200379
Kévin Redon33d1eb72018-07-08 13:58:12 +0200380 *pdwValue = dwValue ;
Kévin Redon93717e42018-07-08 13:26:15 +0200381
Kévin Redon33d1eb72018-07-08 13:58:12 +0200382 return 1 ;
Kévin Redon93717e42018-07-08 13:26:15 +0200383}
384
385/**
386 * Reads an hexadecimal number
387 *
388 * \param pdwValue Pointer to the uint32_t variable to contain the input value.
389 */
390extern uint32_t UART_GetHexa32( uint32_t* pdwValue )
391{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200392 uint8_t ucKey ;
393 uint32_t dw = 0 ;
394 uint32_t dwValue = 0 ;
Kévin Redon93717e42018-07-08 13:26:15 +0200395
Kévin Redon33d1eb72018-07-08 13:58:12 +0200396 for ( dw=0 ; dw < 8 ; dw++ )
397 {
398 ucKey = UART_GetChar() ;
399 UART_PutChar( ucKey ) ;
Kévin Redon93717e42018-07-08 13:26:15 +0200400
Kévin Redon33d1eb72018-07-08 13:58:12 +0200401 if ( ucKey >= '0' && ucKey <= '9' )
402 {
403 dwValue = (dwValue * 16) + (ucKey - '0') ;
404 }
405 else
406 {
407 if ( ucKey >= 'A' && ucKey <= 'F' )
408 {
409 dwValue = (dwValue * 16) + (ucKey - 'A' + 10) ;
410 }
411 else
412 {
413 if ( ucKey >= 'a' && ucKey <= 'f' )
414 {
415 dwValue = (dwValue * 16) + (ucKey - 'a' + 10) ;
416 }
417 else
418 {
419 printf( "\n\rIt is not a hexa character!\n\r" ) ;
Kévin Redon93717e42018-07-08 13:26:15 +0200420
Kévin Redon33d1eb72018-07-08 13:58:12 +0200421 return 0 ;
422 }
423 }
424 }
425 }
Kévin Redon93717e42018-07-08 13:26:15 +0200426
Kévin Redon33d1eb72018-07-08 13:58:12 +0200427 printf("\n\r" ) ;
428 *pdwValue = dwValue ;
Kévin Redon93717e42018-07-08 13:26:15 +0200429
Kévin Redon33d1eb72018-07-08 13:58:12 +0200430 return 1 ;
Kévin Redon93717e42018-07-08 13:26:15 +0200431}
432
433#if defined __ICCARM__ /* IAR Ewarm 5.41+ */
434/**
435 * \brief Outputs a character on the UART.
436 *
437 * \param c Character to output.
438 *
439 * \return The character that was output.
440 */
441extern WEAK signed int putchar( signed int c )
442{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200443 UART_PutChar( c ) ;
Kévin Redon93717e42018-07-08 13:26:15 +0200444
Kévin Redon33d1eb72018-07-08 13:58:12 +0200445 return c ;
Kévin Redon93717e42018-07-08 13:26:15 +0200446}
447#endif // defined __ICCARM__
448