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

Subversion Repositories neo430

[/] [neo430/] [trunk/] [neo430/] [sw/] [lib/] [neo430/] [source/] [neo430_uart.c] - Rev 198

Compare with Previous | Blame | View Log

// #################################################################################################
// #  < neo430_usart.c - Internal UARt driver functions >                                          #
// # ********************************************************************************************* #
// # BSD 3-Clause License                                                                          #
// #                                                                                               #
// # Copyright (c) 2020, Stephan Nolting. All rights reserved.                                     #
// #                                                                                               #
// # Redistribution and use in source and binary forms, with or without modification, are          #
// # permitted provided that the following conditions are met:                                     #
// #                                                                                               #
// # 1. Redistributions of source code must retain the above copyright notice, this list of        #
// #    conditions and the following disclaimer.                                                   #
// #                                                                                               #
// # 2. Redistributions in binary form must reproduce the above copyright notice, this list of     #
// #    conditions and the following disclaimer in the documentation and/or other materials        #
// #    provided with the distribution.                                                            #
// #                                                                                               #
// # 3. Neither the name of the copyright holder nor the names of its contributors may be used to  #
// #    endorse or promote products derived from this software without specific prior written      #
// #    permission.                                                                                #
// #                                                                                               #
// # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS   #
// # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF               #
// # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE    #
// # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,     #
// # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE #
// # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED    #
// # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING     #
// # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED  #
// # OF THE POSSIBILITY OF SUCH DAMAGE.                                                            #
// # ********************************************************************************************* #
// # The NEO430 Processor - https://github.com/stnolting/neo430                                    #
// #################################################################################################
 
#include "neo430.h"
#include "neo430_uart.h"
 
 
/* ------------------------------------------------------------
 * INFO Reset UART, set the Baud rate of UART transceiver
 * INFO UART_BAUD reg (8 bit) = f_main/(prsc*desired_BAUDRATE)
 * INFO PRSC (Baud register bits 10..8):
 *  0: CLK/2
 *  1: CLK/4
 *  2: CLK/8
 *  3: CLK/64
 *  4: CLK/128
 *  5: CLK/1024
 *  6: CLK/2048
 *  7: CLK/4096
 * PARAM actual baudrate to be used
 * ------------------------------------------------------------ */
void neo430_uart_setup(uint32_t baudrate){
 
  // raw baud rate prescaler
  uint32_t clock = CLOCKSPEED_32bit;
  uint16_t i = 0; // BAUD rate divisor
  uint8_t p = 0; // prsc = CLK/2
  while (clock >= 2*baudrate) {
    clock -= 2*baudrate;
    i++;
  }
 
  // find clock prsc
  while (i >= 256) {
    if ((p == 2) || (p == 4))
      i >>= 3;
    else
      i >>= 1;
    p++;
  }
 
  UART_CT = 0;
  UART_CT = (1<<UART_CT_EN) | ((uint16_t)p << UART_CT_PRSC0) | (i << UART_CT_BAUD0);
}
 
 
/* ------------------------------------------------------------
 * INFO Disable UART
 * ------------------------------------------------------------ */
void neo430_uart_disable(void){
 
  UART_CT = 0;
}
 
 
/* ------------------------------------------------------------
 * INFO Get current UARt baud rate
 * ------------------------------------------------------------ */
uint32_t neo430_uart_get_baudrate(void) {
 
  // Clock speed
  uint32_t clock = CLOCKSPEED_32bit;
 
  // prescaler
  uint16_t prsc;
  switch ((UART_CT >> 8) & 0x0007) {
    case 0:  prsc = 2; break;
    case 1:  prsc = 4; break;
    case 2:  prsc = 8; break;
    case 3:  prsc = 64; break;
    case 4:  prsc = 128; break;
    case 5:  prsc = 1024; break;
    case 6:  prsc = 2048; break;
    case 7:  prsc = 4096; break;
    default: prsc = 0; break;
  }
 
  uint16_t baud = UART_CT & 0x00FF;
  uint32_t baud_value = clock / (uint32_t)(prsc * baud);
 
  return baud_value;
}
 
 
/* ------------------------------------------------------------
 * INFO Send single char via internal UART
 * PARAM c char to send
 * ------------------------------------------------------------ */
void neo430_uart_putc(char c){
 
  // wait for previous transfer to finish
  while ((UART_CT & (1<<UART_CT_TX_BUSY)) != 0);
  UART_RTX = (uint16_t)c;
}
 
 
/* ------------------------------------------------------------
 * INFO Read single char from internal UART (wait until data available)
 * INFO This function is blocking!
 * RETURN received char
 * ------------------------------------------------------------ */
char neo430_uart_getc(void){
 
  uint16_t d = 0;
  while (1) {
    d = UART_RTX;
    if ((d & (1<<UART_RTX_AVAIL)) != 0) { // char received?
      return (char)d;
    }
  }
}
 
 
/* ------------------------------------------------------------
 * INFO Returns value !=0 if a char has received
 * RETURN 0 if no char available
 * ------------------------------------------------------------ */
uint16_t neo430_uart_char_received(void){
 
  return UART_RTX & (1<<UART_RTX_AVAIL);
}
 
 
/* ------------------------------------------------------------
 * INFO Returns char from UART RX unit
 * INFO Check if char present with <uart_char_received>
 * INFO This is the base for a non-blocking read access
 * RETURN received char
 * ------------------------------------------------------------ */
char neo430_uart_char_read(void){
 
  return (char)UART_RTX;
}
 
 
/* ------------------------------------------------------------
 * INFO Print zero-terminated string of chars via internal UART
 * PARAM *s pointer to source string
 * ------------------------------------------------------------ */
void neo430_uart_print(char *s){
 
  char c = 0;
  while ((c = *s++)) {
    neo430_uart_putc(c);
  }
}
 
 
/* ------------------------------------------------------------
 * INFO Print zero-terminated string of chars via internal UART
 * Prints true line break "\r\n" for every '\n'
 * PARAM *s pointer to source string
 * ------------------------------------------------------------ */
void neo430_uart_br_print(char *s){
 
  char c = 0;
  while ((c = *s++)) {
    if (c == '\n') {
      neo430_uart_putc('\r');
    }
    neo430_uart_putc(c);
  }
}
 
 
/* ------------------------------------------------------------
 * INFO Get string via UART, string is automatically zero-terminated.
 * Input is acknowledged by ENTER, local echo, chars can be deleted using BACKSPACE.
 * PARAM buffer to store string to
 * PARAM size of buffer (=max string length incl. zero-termination)
 * PARAM activate local echo when =! 0
 * RETURN Length of string (without zero-termination character)
 * ------------------------------------------------------------ */
uint16_t neo430_uart_scan(char *buffer, uint16_t max_size, uint16_t echo) {
 
  char c = 0;
  uint16_t length = 0;
 
  while (1) {
    c = neo430_uart_getc();
    if (c == '\b') { // BACKSPACE
      if (length != 0) {
        if (echo) {
          neo430_uart_print("\b \b"); // delete last char in console
        }
        buffer--;
        length--;
      }
    }
    else if (c == '\r') // carriage return
      break;
    else if ((c >= ' ') && (c <= '~') && (length < (max_size-1))) {
      if (echo) {
        neo430_uart_putc(c); // echo
      }
      *buffer++ = c;
      length++;
    }
  }
  *buffer = '\0'; // terminate string
 
  return length;
}
 
 
/* ------------------------------------------------------------
 * INFO Print single (capital) hexadecimal value (1 digit)
 * PARAM char to be printed
 * ------------------------------------------------------------ */
void neo430_uart_print_hex_char(char c) {
 
  char d = c & 15;
  if (d < 10)
    d += '0';
  else
    d += 'a'-10;
  neo430_uart_putc(d);
}
 
 
/* ------------------------------------------------------------
 * INFO Print 8-bit hexadecimal value (2 digits)
 * PARAM uint8_t value to be printed
 * ------------------------------------------------------------ */
void neo430_uart_print_hex_byte(uint8_t b) {
 
  neo430_uart_print_hex_char((char)(b >> 4));
  neo430_uart_print_hex_char((char)(b >> 0));
}
 
 
/* ------------------------------------------------------------
 * INFO Print 16-bit hexadecimal value (4 digits)
 * PARAM uint16_t value to be printed
 * ------------------------------------------------------------ */
void neo430_uart_print_hex_word(uint16_t w) {
 
  union uint16_u tmp;
  tmp.uint16 = w;
 
  neo430_uart_print_hex_byte(tmp.uint8[1]);
  neo430_uart_print_hex_byte(tmp.uint8[0]);
}
 
 
/* ------------------------------------------------------------
 * INFO Print 32-bit hexadecimal value (8 digits)
 * PARAM uint32_t value to be printed
 * ------------------------------------------------------------ */
void neo430_uart_print_hex_dword(uint32_t dw) {
 
  union uint32_u tmp;
  tmp.uint32 = dw;
 
  neo430_uart_print_hex_byte(tmp.uint8[3]);
  neo430_uart_print_hex_byte(tmp.uint8[2]);
  neo430_uart_print_hex_byte(tmp.uint8[1]);
  neo430_uart_print_hex_byte(tmp.uint8[0]);
}
 
 
/* ------------------------------------------------------------
 * INFO Print 64-bit hexadecimal value (16 digits)
 * PARAM uint64_t value to be printed
 * ------------------------------------------------------------ */
void neo430_uart_print_hex_qword(uint64_t qw) {
 
  union uint64_u tmp;
  tmp.uint64 = qw;
 
  neo430_uart_print_hex_byte(tmp.uint8[7]);
  neo430_uart_print_hex_byte(tmp.uint8[6]);
  neo430_uart_print_hex_byte(tmp.uint8[5]);
  neo430_uart_print_hex_byte(tmp.uint8[4]);
  neo430_uart_print_hex_byte(tmp.uint8[3]);
  neo430_uart_print_hex_byte(tmp.uint8[2]);
  neo430_uart_print_hex_byte(tmp.uint8[1]);
  neo430_uart_print_hex_byte(tmp.uint8[0]);
}
 
 
/* ------------------------------------------------------------
 * INFO Print 8-bit binary value (8 digits)
 * PARAM uint8_t value to be printed
 * ------------------------------------------------------------ */
void neo430_uart_print_bin_byte(uint8_t b) {
 
  uint8_t i;
  for (i=0x80; i!=0; i>>=1) {
    if (b & i)
      neo430_uart_putc('1');
    else
      neo430_uart_putc('0');
  }
}
 
 
/* ------------------------------------------------------------
 * INFO Print 16-bit binary value (16 digits)
 * PARAM uint16_t value to be printed
 * ------------------------------------------------------------ */
void neo430_uart_print_bin_word(uint16_t w) {
 
  union uint16_u tmp;
  tmp.uint16 = w;
 
  neo430_uart_print_bin_byte(tmp.uint8[1]);
  neo430_uart_print_bin_byte(tmp.uint8[0]);
}
 
 
/* ------------------------------------------------------------
 * INFO Print 32-bit binary value (32 digits)
 * PARAM uint32_t value to be printed
 * ------------------------------------------------------------ */
void neo430_uart_print_bin_dword(uint32_t dw) {
 
  union uint32_u tmp;
  tmp.uint32 = dw;
 
  neo430_uart_print_bin_byte(tmp.uint8[3]);
  neo430_uart_print_bin_byte(tmp.uint8[2]);
  neo430_uart_print_bin_byte(tmp.uint8[1]);
  neo430_uart_print_bin_byte(tmp.uint8[0]);
}
 
 
/* ------------------------------------------------------------
 * INFO Print 32-bit number as decimal number (10 digits)
 * INFO Slow custom version of itoa
 * PARAM 32-bit value to be printed as decimal number
 * PARAM show #leading_zeros leading zeros
 * PARAM pointer to array (11 elements!!!) to store conversion result string
 * ------------------------------------------------------------ */
void neo430_itoa(uint32_t x, uint16_t leading_zeros, char *res) {
 
  const char numbers[10] = "0123456789";
  char buffer1[11];
  uint16_t i, j;
 
  buffer1[10] = '\0';
  res[10] = '\0';
 
  // convert
  for (i=0; i<10; i++) {
    buffer1[i] = numbers[x%10];
    x /= 10;
  }
 
  // delete 'leading' zeros
  for (i=9; i!=leading_zeros; i--) {
    if (buffer1[i] == '0')
      buffer1[i] = '\0';
    else
      break;
  }
 
  // reverse
  j = 0;
  do {
    if (buffer1[i] != '\0')
      res[j++] = buffer1[i];
  } while (i--);
 
  res[j] = '\0'; // terminate result string
}
 
 
/* ------------------------------------------------------------
 * INFO Embedded version of the printf function with reduced functionality
 * INFO Only use this function if it is really required!
 * INFO It is large and slow... ;)
 * INFO Original from http://forum.43oh.com/topic/1289-tiny-printf-c-version/
 * PARAM Argument string
 * ------------------------------------------------------------ */
void neo430_printf(char *format, ...) {
 
  char c, string_buf[11];
  int32_t n;
 
  va_list a;
  va_start(a, format);
 
  while ((c = *format++)) {
    if (c == '%') {
      c = *format++;
      switch (c) {
        case 's': // string
          neo430_uart_print(va_arg(a, char*));
          break;
        case 'c': // char
          neo430_uart_putc((char)va_arg(a, int));
          break;
        case 'b': // unsigned 16-bit binary
          neo430_uart_print_bin_word(va_arg(a, unsigned int));
          break;
        case 'i': // 16-bit integer
          n = (int32_t)va_arg(a, int);
          if (n < 0) {
            n = -n;
            neo430_uart_putc('-');
          }
          neo430_itoa((uint32_t)n, 0, string_buf);
          neo430_uart_br_print(string_buf);
          break;
        case 'u': // 16-bit unsigned
          neo430_itoa((uint32_t)va_arg(a, unsigned int), 0, string_buf);
          neo430_uart_br_print(string_buf);
          break;
        case 'l': // 32-bit signed long
          n = (int32_t)va_arg(a, int32_t);
          if (n < 0) {
            n = -n;
            neo430_uart_putc('-');
          }
          neo430_itoa((uint32_t)n, 0, string_buf);
          neo430_uart_br_print(string_buf);
          break;
        case 'n': // 32-bit unsigned long
          neo430_itoa(va_arg(a, uint32_t), 0, string_buf);
          neo430_uart_br_print(string_buf);
          break;
        case 'x': // 16-bit hexadecimal
          neo430_uart_print_hex_word(va_arg(a, unsigned int));
          break;
        case 'X': // 32-bit hexadecimal
          neo430_uart_print_hex_dword(va_arg(a, uint32_t));
          break;
        default:
          return;
      }
    }
    else {
      if (c == '\n')
        neo430_uart_putc('\r');
      neo430_uart_putc(c);
    }
  }
  va_end(a);
}
 
 
/* ------------------------------------------------------------
 * INFO Convert N hex chars into uint32
 * PARAM Pointer to buffer with hex chars
 * PARAM Number of hex chars to convert (1..8)
 * RETURN Conversion result
 * ------------------------------------------------------------ */
uint32_t neo430_hexstr_to_uint(char *buffer, uint8_t length) {
 
  uint32_t res = 0, d = 0;
  char c = 0;
 
  while (length--) {
    c = *buffer++;
 
    if ((c >= '0') && (c <= '9'))
      d = (uint32_t)(c - '0');
    else if ((c >= 'a') && (c <= 'f'))
      d = (uint32_t)((c - 'a') + 10);
    else if ((c >= 'A') && (c <= 'F'))
      d = (uint32_t)((c - 'A') + 10);
    else
      d = 0;
 
    res = res + (d << (length*4));
  }
 
  return res;
}
 
 
/* ------------------------------------------------------------
 * INFO Return terminal cursor n positions
 * PARAM n positions
 * ------------------------------------------------------------ */
void neo430_uart_bs(uint16_t n) {
 
  while (n--) {
    neo430_uart_putc(0x08);
  }
}
 
 
/* ------------------------------------------------------------
 * INFO Print signed 32-bit fixed point number (num)
 * PARAM fpf_c: Number of bin fractional bits in input (max 32)
 * PARAM num_frac_digits_c: Number of fractional digits to show (max 8)
 * ------------------------------------------------------------ */
void neo430_uart_print_fpf_32(int32_t num, uint16_t fpf_c, uint16_t num_frac_digits_c) {
 
  uint16_t i;
 
  // make positive
  if (num < 0) {
    neo430_uart_putc('-');
    num = -num;
  }
  uint32_t num_int = (uint32_t)num;
 
 
  // print integer part
  char int_buf[11];
  neo430_itoa((uint32_t)(num_int >> fpf_c), 0, int_buf);
  neo430_uart_br_print(int_buf);
  neo430_uart_putc('.');
 
 
  // compute fractional resolution
  uint32_t frac_dec_base = 1;
  for (i=0; i<num_frac_digits_c; i++) {
    frac_dec_base = frac_dec_base * 10;
  }
  frac_dec_base = frac_dec_base >> 1;
 
  // compute fractional part's bit-insulation shift mask
  uint32_t frac_dec_mask = 1L << (fpf_c-1);
 
 
  // compute actual fractional part
  uint32_t frac_data = num_int & ((1 << fpf_c)-1); // only keep fractional bits
  uint32_t frac_sum = 1;
  for (i=0; i<fpf_c; i++) { // test each fractional bit
    if (frac_data & frac_dec_mask) { // insulate current fractional bit
      frac_sum += frac_dec_base;
    }
    frac_dec_mask >>= 1; // go from MSB to LSB
    frac_dec_base >>= 1;
  }
 
  // print fractional part
  char frac_buf[11];
  neo430_itoa((uint32_t)frac_sum, num_frac_digits_c-1, frac_buf);
  frac_buf[num_frac_digits_c] = '\0'; // truncate
  neo430_uart_br_print(frac_buf);
}
 
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

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