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

Subversion Repositories neorv32

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

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 30 zero_gravi
 * @warning The 'UART_SIM_MODE' compiler flag will redirect all UART TX data to the simulation output. Use this for simulations only!
75
 *
76 2 zero_gravi
 * @param[in] baudrate Targeted BAUD rate (e.g. 9600).
77
 * @param[in] rx_irq Enable RX interrupt (data received) when 1.
78
 * @param[in] tx_irq Enable TX interrupt (transmission done) when 1.
79
 **************************************************************************/
80
void neorv32_uart_setup(uint32_t baudrate, uint8_t rx_irq, uint8_t tx_irq) {
81
 
82
  UART_CT = 0; // reset
83
 
84
  // raw baud rate prescaler
85 12 zero_gravi
  uint32_t clock = SYSINFO_CLK;
86 2 zero_gravi
  uint16_t i = 0; // BAUD rate divisor
87
  uint8_t p = 0; // prsc = CLK/2
88
  while (clock >= 2*baudrate) {
89
    clock -= 2*baudrate;
90
    i++;
91
  }
92
 
93
  // find clock prsc
94
  while (i >= 0x0fff) {
95
    if ((p == 2) || (p == 4))
96
      i >>= 3;
97
    else
98
      i >>= 1;
99
    p++;
100
  }
101
 
102
  uint32_t prsc = (uint32_t)p;
103
  prsc = prsc << UART_CT_PRSC0;
104
 
105
  uint32_t baud = (uint32_t)i;
106
  baud = baud << UART_CT_BAUD00;
107
 
108
  uint32_t uart_en = 1;
109
  uart_en = uart_en << UART_CT_EN;
110
 
111
  uint32_t rx_irq_en = (uint32_t)(rx_irq & 1);
112
  rx_irq_en = rx_irq_en << UART_CT_RX_IRQ;
113
 
114
  uint32_t tx_irq_en = (uint32_t)(tx_irq & 1);
115
  tx_irq_en = tx_irq_en << UART_CT_TX_IRQ;
116
 
117 30 zero_gravi
  /* Enable the UART for SIM mode. */
118
  /* Only use this for simulation! */
119
#ifdef UART_SIM_MODE
120
  #warning UART_SIM_MODE enabled! Sending all UART.TX to text.io simulation output instead of real UART transmitter. Use this for simulations only!
121
  uint32_t sim_mode = 1 << UART_CT_SIM_MODE;
122
#else
123
  uint32_t sim_mode = 0;
124
#endif
125
 
126
  UART_CT = prsc | baud | uart_en | rx_irq_en | tx_irq_en | sim_mode;
127 2 zero_gravi
}
128
 
129
 
130
/**********************************************************************//**
131
 * Disable UART.
132
 **************************************************************************/
133
void neorv32_uart_disable(void) {
134
 
135
  UART_CT &= ~((uint32_t)(1 << UART_CT_EN));
136
}
137
 
138
 
139
/**********************************************************************//**
140
 * Send single char via UART.
141
 *
142
 * @note This function is blocking.
143
 *
144
 * @param[in] c Char to be send.
145
 **************************************************************************/
146
void neorv32_uart_putc(char c) {
147
 
148 30 zero_gravi
#ifdef UART_SIM_MODE
149
  UART_DATA = ((uint32_t)c) << UART_DATA_LSB;
150 3 zero_gravi
#else
151 2 zero_gravi
  // wait for previous transfer to finish
152
  while ((UART_CT & (1<<UART_CT_TX_BUSY)) != 0);
153
  UART_DATA = ((uint32_t)c) << UART_DATA_LSB;
154 3 zero_gravi
#endif
155 2 zero_gravi
}
156
 
157
 
158
/**********************************************************************//**
159 23 zero_gravi
 * Check if UART TX is busy.
160
 *
161
 * @note This function is blocking.
162
 *
163
 * @return 0 if idle, 1 if busy
164
 **************************************************************************/
165
int neorv32_uart_tx_busy(void) {
166
 
167
  if ((UART_CT & (1<<UART_CT_TX_BUSY)) != 0) {
168
    return 1;
169
  }
170
  return 0;
171
}
172
 
173
 
174
/**********************************************************************//**
175 2 zero_gravi
 * Get char from UART.
176
 *
177
 * @note This function is blocking.
178
 *
179
 * @return Received char.
180
 **************************************************************************/
181
char neorv32_uart_getc(void) {
182
 
183
  uint32_t d = 0;
184
  while (1) {
185
    d = UART_DATA;
186
    if ((d & (1<<UART_DATA_AVAIL)) != 0) { // char received?
187
      return (char)d;
188
    }
189
  }
190
}
191
 
192
 
193
/**********************************************************************//**
194
 * Check if UARt has received a char.
195
 *
196
 * @note This function is non-blocking.
197
 * @note Use neorv32_uart_char_received_get(void) to get the char.
198
 *
199
 * @return =!0 when a char has been received.
200
 **************************************************************************/
201
int neorv32_uart_char_received(void) {
202
 
203
  if ((UART_DATA & (1<<UART_DATA_AVAIL)) != 0) {
204
    return 1;
205
  }
206
  else {
207
    return 0;
208
  }
209
}
210
 
211
 
212
/**********************************************************************//**
213
 * Get a received char.
214
 *
215
 * @note This function is non-blocking.
216
 * @note Should only be used in combination with neorv32_uart_char_received(void).
217
 *
218
 * @return Received char.
219
 **************************************************************************/
220
char neorv32_uart_char_received_get(void) {
221
 
222
  return (char)UART_DATA;
223
}
224
 
225
 
226
/**********************************************************************//**
227
 * Print string (zero-terminated) via UART. Print full line break "\r\n" for every '\n'.
228
 *
229
 * @note This function is blocking.
230
 *
231
 * @param[in] s Pointer to string.
232
 **************************************************************************/
233 22 zero_gravi
void neorv32_uart_print(const char *s) {
234 2 zero_gravi
 
235
  char c = 0;
236
  while ((c = *s++)) {
237
    if (c == '\n') {
238
      neorv32_uart_putc('\r');
239
    }
240
    neorv32_uart_putc(c);
241
  }
242
}
243
 
244
 
245
/**********************************************************************//**
246
 * Private function for 'neorv32_printf' to convert into decimal.
247
 *
248
 * @param[in] x Unsigned input number.
249
 * @param[in,out] res Pointer for storing the reuslting number string (11 chars).
250
 **************************************************************************/
251
static void __neorv32_uart_itoa(uint32_t x, char *res) {
252
 
253 22 zero_gravi
  static const char numbers[] = "0123456789";
254 2 zero_gravi
  char buffer1[11];
255
  uint16_t i, j;
256
 
257
  buffer1[10] = '\0';
258
  res[10] = '\0';
259
 
260
  // convert
261
  for (i=0; i<10; i++) {
262
    buffer1[i] = numbers[x%10];
263
    x /= 10;
264
  }
265
 
266
  // delete 'leading' zeros
267
  for (i=9; i!=0; i--) {
268
    if (buffer1[i] == '0')
269
      buffer1[i] = '\0';
270
    else
271
      break;
272
  }
273
 
274
  // reverse
275
  j = 0;
276
  do {
277
    if (buffer1[i] != '\0')
278
      res[j++] = buffer1[i];
279
  } while (i--);
280
 
281
  res[j] = '\0'; // terminate result string
282
}
283
 
284
 
285
/**********************************************************************//**
286
 * Private function for 'neorv32_printf' to convert into hexadecimal.
287
 *
288
 * @param[in] x Unsigned input number.
289
 * @param[in,out] res Pointer for storing the reuslting number string (9 chars).
290
 **************************************************************************/
291
static void __neorv32_uart_tohex(uint32_t x, char *res) {
292
 
293 22 zero_gravi
  static const char symbols[] = "0123456789abcdef";
294 2 zero_gravi
 
295
  int i;
296
  for (i=0; i<8; i++) { // nibble by bibble
297
    uint32_t num_tmp = x >> (4*i);
298
    res[7-i] = (char)symbols[num_tmp & 0x0f];
299
  }
300
 
301
  res[8] = '\0'; // terminate result string
302
}
303
 
304
 
305
/**********************************************************************//**
306
 * Custom version of 'printf' function.
307
 *
308
 * @note This function is blocking.
309
 *
310
 * @param[in] format Pointer to format string.
311
 *
312
 * <TABLE>
313
 * <TR><TD>%s</TD><TD>String (array of chars, zero-terminated)</TD></TR>
314
 * <TR><TD>%c</TD><TD>Single char</TD></TR>
315
 * <TR><TD>%i</TD><TD>32-bit signed number, printed as decimal</TD></TR>
316
 * <TR><TD>%u</TD><TD>32-bit unsigned number, printed as decimal</TD></TR>
317
 * <TR><TD>%x</TD><TD>32-bit number, printed as 8-char hexadecimal</TD></TR>
318
 * </TABLE>
319
 **************************************************************************/
320 22 zero_gravi
void neorv32_uart_printf(const char *format, ...) {
321 2 zero_gravi
 
322
  char c, string_buf[11];
323
  int32_t n;
324
 
325
  va_list a;
326
  va_start(a, format);
327
 
328
  while ((c = *format++)) {
329
    if (c == '%') {
330
      c = *format++;
331
      switch (c) {
332
        case 's': // string
333
          neorv32_uart_print(va_arg(a, char*));
334
          break;
335
        case 'c': // char
336
          neorv32_uart_putc((char)va_arg(a, int));
337
          break;
338
        case 'i': // 32-bit signed
339
          n = (int32_t)va_arg(a, int32_t);
340
          if (n < 0) {
341
            n = -n;
342
            neorv32_uart_putc('-');
343
          }
344
          __neorv32_uart_itoa((uint32_t)n, string_buf);
345
          neorv32_uart_print(string_buf);
346
          break;
347
        case 'u': // 32-bit unsigned
348
          __neorv32_uart_itoa(va_arg(a, uint32_t), string_buf);
349
          neorv32_uart_print(string_buf);
350
          break;
351
        case 'x': // 32-bit hexadecimal
352
          __neorv32_uart_tohex(va_arg(a, uint32_t), string_buf);
353
          neorv32_uart_print(string_buf);
354
          break;
355
        default:
356
          return;
357
      }
358
    }
359
    else {
360
      if (c == '\n') {
361
        neorv32_uart_putc('\r');
362
      }
363
      neorv32_uart_putc(c);
364
    }
365
  }
366
  va_end(a);
367
}
368
 
369
 
370
/**********************************************************************//**
371
 * Simplified custom version of 'scanf' function.
372
 *
373
 * @note This function is blocking.
374
 *
375
 * @param[in,out] buffer Pointer to array of chars to store string.
376
 * @param[in] max_size Maximum number of chars to sample.
377
 * @param[in] echo Echo UART input when 1.
378
 * @return Number of chars read.
379
 **************************************************************************/
380
int neorv32_uart_scan(char *buffer, int max_size, int echo) {
381
 
382
  char c = 0;
383
  int length = 0;
384
 
385
  while (1) {
386
    c = neorv32_uart_getc();
387
    if (c == '\b') { // BACKSPACE
388
      if (length != 0) {
389
        if (echo) {
390
          neorv32_uart_print("\b \b"); // delete last char in console
391
        }
392
        buffer--;
393
        length--;
394
      }
395
    }
396
    else if (c == '\r') // carriage return
397
      break;
398
    else if ((c >= ' ') && (c <= '~') && (length < (max_size-1))) {
399
      if (echo) {
400
        neorv32_uart_putc(c); // echo
401
      }
402
      *buffer++ = c;
403
      length++;
404
    }
405
  }
406
  *buffer = '\0'; // terminate string
407
 
408
  return length;
409
}
410
 

powered by: WebSVN 2.1.0

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