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