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

Subversion Repositories neorv32

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

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

powered by: WebSVN 2.1.0

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