OpenCores
URL https://opencores.org/ocsvn/neorv32/neorv32/trunk

Subversion Repositories neorv32

[/] [neorv32/] [trunk/] [sw/] [lib/] [source/] [neorv32_uart.c] - Blame information for rev 42

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 zero_gravi
// #################################################################################################
2
// # << NEORV32: neorv32_uart.c - Universal Asynchronous Receiver/Transmitter (UART) HW Driver >>  #
3
// # ********************************************************************************************* #
4
// # BSD 3-Clause License                                                                          #
5
// #                                                                                               #
6
// # Copyright (c) 2020, Stephan Nolting. All rights reserved.                                     #
7
// #                                                                                               #
8
// # Redistribution and use in source and binary forms, with or without modification, are          #
9
// # permitted provided that the following conditions are met:                                     #
10
// #                                                                                               #
11
// # 1. Redistributions of source code must retain the above copyright notice, this list of        #
12
// #    conditions and the following disclaimer.                                                   #
13
// #                                                                                               #
14
// # 2. Redistributions in binary form must reproduce the above copyright notice, this list of     #
15
// #    conditions and the following disclaimer in the documentation and/or other materials        #
16
// #    provided with the distribution.                                                            #
17
// #                                                                                               #
18
// # 3. Neither the name of the copyright holder nor the names of its contributors may be used to  #
19
// #    endorse or promote products derived from this software without specific prior written      #
20
// #    permission.                                                                                #
21
// #                                                                                               #
22
// # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS   #
23
// # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF               #
24
// # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE    #
25
// # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,     #
26
// # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE #
27
// # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED    #
28
// # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING     #
29
// # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED  #
30
// # OF THE POSSIBILITY OF SUCH DAMAGE.                                                            #
31
// # ********************************************************************************************* #
32
// # The NEORV32 Processor - https://github.com/stnolting/neorv32              (c) Stephan Nolting #
33
// #################################################################################################
34
 
35
 
36
/**********************************************************************//**
37
 * @file neorv32_uart.c
38
 * @author Stephan Nolting
39
 * @brief Universal asynchronous receiver/transmitter (UART) HW driver source file.
40
 *
41
 * @note These functions should only be used if the UART unit was synthesized (IO_UART_USE = true).
42
 **************************************************************************/
43
 
44
#include "neorv32.h"
45
#include "neorv32_uart.h"
46
#include <string.h>
47
 
48
/// \cond
49
// Private functions
50
static void __neorv32_uart_itoa(uint32_t x, char *res) __attribute__((unused)); // GCC: do not ouput a warning when this variable is unused
51
static void __neorv32_uart_tohex(uint32_t x, char *res) __attribute__((unused)); // GCC: do not ouput a warning when this variable is unused
52
/// \endcond
53
 
54
 
55
/**********************************************************************//**
56
 * Check if UART unit was synthesized.
57
 *
58
 * @return 0 if UART was not synthesized, 1 if UART is available.
59
 **************************************************************************/
60
int neorv32_uart_available(void) {
61
 
62 12 zero_gravi
  if (SYSINFO_FEATURES & (1 << SYSINFO_FEATURES_IO_UART)) {
63 2 zero_gravi
    return 1;
64
  }
65
  else {
66
    return 0;
67
  }
68
}
69
 
70
 
71
/**********************************************************************//**
72
 * Enable and configure UART.
73
 *
74 36 zero_gravi
 * @warning The 'UART_SIM_MODE' compiler flag will configure UART for simulation mode: all UART TX data will be redirected to simulation output. Use this for simulations only!
75 34 zero_gravi
 * @warning To enable simulation mode add <USER_FLAGS+=-DUART_SIM_MODE> when compiling.
76 30 zero_gravi
 *
77 2 zero_gravi
 * @param[in] baudrate Targeted BAUD rate (e.g. 9600).
78 42 zero_gravi
 * @param[in] parity PArity configuration (00=off, 10=even, 11=odd).
79 2 zero_gravi
 * @param[in] rx_irq Enable RX interrupt (data received) when 1.
80
 * @param[in] tx_irq Enable TX interrupt (transmission done) when 1.
81
 **************************************************************************/
82 42 zero_gravi
void neorv32_uart_setup(uint32_t baudrate, uint8_t parity, uint8_t rx_irq, uint8_t tx_irq) {
83 2 zero_gravi
 
84
  UART_CT = 0; // reset
85
 
86 12 zero_gravi
  uint32_t clock = SYSINFO_CLK;
87 2 zero_gravi
  uint16_t i = 0; // BAUD rate divisor
88 36 zero_gravi
  uint8_t p = 0; // initial prsc = CLK/2
89
 
90
  // raw clock prescaler
91
#ifdef __riscv_div
92
  // use div instructions
93
  i = (uint16_t)(clock / (2*baudrate));
94
#else
95
  // division via repeated subtraction
96 2 zero_gravi
  while (clock >= 2*baudrate) {
97
    clock -= 2*baudrate;
98
    i++;
99
  }
100 36 zero_gravi
#endif
101 2 zero_gravi
 
102
  // find clock prsc
103
  while (i >= 0x0fff) {
104
    if ((p == 2) || (p == 4))
105
      i >>= 3;
106
    else
107
      i >>= 1;
108
    p++;
109
  }
110
 
111
  uint32_t prsc = (uint32_t)p;
112
  prsc = prsc << UART_CT_PRSC0;
113
 
114
  uint32_t baud = (uint32_t)i;
115
  baud = baud << UART_CT_BAUD00;
116
 
117
  uint32_t uart_en = 1;
118
  uart_en = uart_en << UART_CT_EN;
119
 
120 42 zero_gravi
  uint32_t parity_config = (uint32_t)(parity & 3);
121
  parity_config = parity_config << UART_CT_PMODE0;
122
 
123 2 zero_gravi
  uint32_t rx_irq_en = (uint32_t)(rx_irq & 1);
124
  rx_irq_en = rx_irq_en << UART_CT_RX_IRQ;
125
 
126
  uint32_t tx_irq_en = (uint32_t)(tx_irq & 1);
127
  tx_irq_en = tx_irq_en << UART_CT_TX_IRQ;
128
 
129 30 zero_gravi
  /* Enable the UART for SIM mode. */
130 42 zero_gravi
  /* USE THIS ONLY FOR SIMULATION! */
131 30 zero_gravi
#ifdef UART_SIM_MODE
132 35 zero_gravi
  #warning UART_SIM_MODE enabled! Sending all UART.TX data to text.io simulation output instead of real UART transmitter. Use this for simulations only!
133 30 zero_gravi
  uint32_t sim_mode = 1 << UART_CT_SIM_MODE;
134
#else
135
  uint32_t sim_mode = 0;
136
#endif
137
 
138 42 zero_gravi
  UART_CT = prsc | baud | uart_en | parity_config | rx_irq_en | tx_irq_en | sim_mode;
139 2 zero_gravi
}
140
 
141
 
142
/**********************************************************************//**
143
 * Disable UART.
144
 **************************************************************************/
145
void neorv32_uart_disable(void) {
146
 
147
  UART_CT &= ~((uint32_t)(1 << UART_CT_EN));
148
}
149
 
150
 
151
/**********************************************************************//**
152
 * Send single char via UART.
153
 *
154
 * @note This function is blocking.
155
 *
156
 * @param[in] c Char to be send.
157
 **************************************************************************/
158
void neorv32_uart_putc(char c) {
159
 
160 30 zero_gravi
#ifdef UART_SIM_MODE
161
  UART_DATA = ((uint32_t)c) << UART_DATA_LSB;
162 3 zero_gravi
#else
163 2 zero_gravi
  // wait for previous transfer to finish
164
  while ((UART_CT & (1<<UART_CT_TX_BUSY)) != 0);
165
  UART_DATA = ((uint32_t)c) << UART_DATA_LSB;
166 3 zero_gravi
#endif
167 2 zero_gravi
}
168
 
169
 
170
/**********************************************************************//**
171 23 zero_gravi
 * Check if UART TX is busy.
172
 *
173
 * @note This function is blocking.
174
 *
175
 * @return 0 if idle, 1 if busy
176
 **************************************************************************/
177
int neorv32_uart_tx_busy(void) {
178
 
179
  if ((UART_CT & (1<<UART_CT_TX_BUSY)) != 0) {
180
    return 1;
181
  }
182
  return 0;
183
}
184
 
185
 
186
/**********************************************************************//**
187 2 zero_gravi
 * Get char from UART.
188
 *
189 42 zero_gravi
 * @note This function is blocking and does not check for UART frame/parity errors.
190 2 zero_gravi
 *
191
 * @return Received char.
192
 **************************************************************************/
193
char neorv32_uart_getc(void) {
194
 
195
  uint32_t d = 0;
196
  while (1) {
197
    d = UART_DATA;
198
    if ((d & (1<<UART_DATA_AVAIL)) != 0) { // char received?
199
      return (char)d;
200
    }
201
  }
202
}
203
 
204
 
205
/**********************************************************************//**
206 42 zero_gravi
 * Get char from UART (and check errors).
207 2 zero_gravi
 *
208 42 zero_gravi
 * @note This function is non-blocking and checks for frame and parity errors.
209
 *
210
 * @param[in,out] data Received char.
211
 * @return Status code (0=nothing received, 1: char received without errors; -1: char received with frame error; -2: char received with parity error; -3 char received with frame & parity error).
212
 **************************************************************************/
213
int neorv32_uart_getc_secure(char *data) {
214
 
215
  uint32_t uart_rx = UART_DATA;
216
  if (uart_rx & (1<<UART_DATA_AVAIL)) { // char available at all?
217
 
218
    int status = 0;
219
 
220
    // check for frame error
221
    if (uart_rx & (1<<UART_DATA_FERR)) {
222
      status -= 1;
223
    }
224
 
225
    // check for parity error
226
    if (uart_rx & (1<<UART_DATA_PERR)) {
227
      status -= 2;
228
    }
229
 
230
    if (status == 0) {
231
      status = 1;
232
    }
233
 
234
    // get received byte
235
    *data =  (char)uart_rx;
236
 
237
    return status;
238
  }
239
  else {
240
    return 0;
241
  }
242
}
243
 
244
 
245
/**********************************************************************//**
246
 * Check if UART has received a char.
247
 *
248 2 zero_gravi
 * @note This function is non-blocking.
249
 * @note Use neorv32_uart_char_received_get(void) to get the char.
250
 *
251
 * @return =!0 when a char has been received.
252
 **************************************************************************/
253
int neorv32_uart_char_received(void) {
254
 
255
  if ((UART_DATA & (1<<UART_DATA_AVAIL)) != 0) {
256
    return 1;
257
  }
258
  else {
259
    return 0;
260
  }
261
}
262
 
263
 
264
/**********************************************************************//**
265
 * Get a received char.
266
 *
267
 * @note This function is non-blocking.
268
 * @note Should only be used in combination with neorv32_uart_char_received(void).
269
 *
270
 * @return Received char.
271
 **************************************************************************/
272
char neorv32_uart_char_received_get(void) {
273
 
274
  return (char)UART_DATA;
275
}
276
 
277
 
278
/**********************************************************************//**
279
 * Print string (zero-terminated) via UART. Print full line break "\r\n" for every '\n'.
280
 *
281
 * @note This function is blocking.
282
 *
283
 * @param[in] s Pointer to string.
284
 **************************************************************************/
285 22 zero_gravi
void neorv32_uart_print(const char *s) {
286 2 zero_gravi
 
287
  char c = 0;
288
  while ((c = *s++)) {
289
    if (c == '\n') {
290
      neorv32_uart_putc('\r');
291
    }
292
    neorv32_uart_putc(c);
293
  }
294
}
295
 
296
 
297
/**********************************************************************//**
298
 * Private function for 'neorv32_printf' to convert into decimal.
299
 *
300
 * @param[in] x Unsigned input number.
301
 * @param[in,out] res Pointer for storing the reuslting number string (11 chars).
302
 **************************************************************************/
303
static void __neorv32_uart_itoa(uint32_t x, char *res) {
304
 
305 22 zero_gravi
  static const char numbers[] = "0123456789";
306 2 zero_gravi
  char buffer1[11];
307
  uint16_t i, j;
308
 
309
  buffer1[10] = '\0';
310
  res[10] = '\0';
311
 
312
  // convert
313
  for (i=0; i<10; i++) {
314
    buffer1[i] = numbers[x%10];
315
    x /= 10;
316
  }
317
 
318
  // delete 'leading' zeros
319
  for (i=9; i!=0; i--) {
320
    if (buffer1[i] == '0')
321
      buffer1[i] = '\0';
322
    else
323
      break;
324
  }
325
 
326
  // reverse
327
  j = 0;
328
  do {
329
    if (buffer1[i] != '\0')
330
      res[j++] = buffer1[i];
331
  } while (i--);
332
 
333
  res[j] = '\0'; // terminate result string
334
}
335
 
336
 
337
/**********************************************************************//**
338
 * Private function for 'neorv32_printf' to convert into hexadecimal.
339
 *
340
 * @param[in] x Unsigned input number.
341
 * @param[in,out] res Pointer for storing the reuslting number string (9 chars).
342
 **************************************************************************/
343
static void __neorv32_uart_tohex(uint32_t x, char *res) {
344
 
345 22 zero_gravi
  static const char symbols[] = "0123456789abcdef";
346 2 zero_gravi
 
347
  int i;
348
  for (i=0; i<8; i++) { // nibble by bibble
349
    uint32_t num_tmp = x >> (4*i);
350
    res[7-i] = (char)symbols[num_tmp & 0x0f];
351
  }
352
 
353
  res[8] = '\0'; // terminate result string
354
}
355
 
356
 
357
/**********************************************************************//**
358
 * Custom version of 'printf' function.
359
 *
360
 * @note This function is blocking.
361
 *
362
 * @param[in] format Pointer to format string.
363
 *
364
 * <TABLE>
365
 * <TR><TD>%s</TD><TD>String (array of chars, zero-terminated)</TD></TR>
366
 * <TR><TD>%c</TD><TD>Single char</TD></TR>
367
 * <TR><TD>%i</TD><TD>32-bit signed number, printed as decimal</TD></TR>
368
 * <TR><TD>%u</TD><TD>32-bit unsigned number, printed as decimal</TD></TR>
369
 * <TR><TD>%x</TD><TD>32-bit number, printed as 8-char hexadecimal</TD></TR>
370
 * </TABLE>
371
 **************************************************************************/
372 22 zero_gravi
void neorv32_uart_printf(const char *format, ...) {
373 2 zero_gravi
 
374
  char c, string_buf[11];
375
  int32_t n;
376
 
377
  va_list a;
378
  va_start(a, format);
379
 
380
  while ((c = *format++)) {
381
    if (c == '%') {
382
      c = *format++;
383
      switch (c) {
384
        case 's': // string
385
          neorv32_uart_print(va_arg(a, char*));
386
          break;
387
        case 'c': // char
388
          neorv32_uart_putc((char)va_arg(a, int));
389
          break;
390
        case 'i': // 32-bit signed
391
          n = (int32_t)va_arg(a, int32_t);
392
          if (n < 0) {
393
            n = -n;
394
            neorv32_uart_putc('-');
395
          }
396
          __neorv32_uart_itoa((uint32_t)n, string_buf);
397
          neorv32_uart_print(string_buf);
398
          break;
399
        case 'u': // 32-bit unsigned
400
          __neorv32_uart_itoa(va_arg(a, uint32_t), string_buf);
401
          neorv32_uart_print(string_buf);
402
          break;
403
        case 'x': // 32-bit hexadecimal
404
          __neorv32_uart_tohex(va_arg(a, uint32_t), string_buf);
405
          neorv32_uart_print(string_buf);
406
          break;
407
        default:
408
          return;
409
      }
410
    }
411
    else {
412
      if (c == '\n') {
413
        neorv32_uart_putc('\r');
414
      }
415
      neorv32_uart_putc(c);
416
    }
417
  }
418
  va_end(a);
419
}
420
 
421
 
422
/**********************************************************************//**
423
 * Simplified custom version of 'scanf' function.
424
 *
425
 * @note This function is blocking.
426
 *
427
 * @param[in,out] buffer Pointer to array of chars to store string.
428
 * @param[in] max_size Maximum number of chars to sample.
429
 * @param[in] echo Echo UART input when 1.
430
 * @return Number of chars read.
431
 **************************************************************************/
432
int neorv32_uart_scan(char *buffer, int max_size, int echo) {
433
 
434
  char c = 0;
435
  int length = 0;
436
 
437
  while (1) {
438
    c = neorv32_uart_getc();
439
    if (c == '\b') { // BACKSPACE
440
      if (length != 0) {
441
        if (echo) {
442
          neorv32_uart_print("\b \b"); // delete last char in console
443
        }
444
        buffer--;
445
        length--;
446
      }
447
    }
448
    else if (c == '\r') // carriage return
449
      break;
450
    else if ((c >= ' ') && (c <= '~') && (length < (max_size-1))) {
451
      if (echo) {
452
        neorv32_uart_putc(c); // echo
453
      }
454
      *buffer++ = c;
455
      length++;
456
    }
457
  }
458
  *buffer = '\0'; // terminate string
459
 
460
  return length;
461
}
462
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.