Embedded Peripherals IP User Guide

ID 683130
Date 9/18/2024
Public
Document Table of Contents
1. Introduction 2. Avalon® -ST Multi-Channel Shared Memory FIFO Core 3. Avalon® -ST Single-Clock and Dual-Clock FIFO Cores 4. Avalon® -ST Serial Peripheral Interface Core 5. SPI Core 6. SPI Agent/JTAG to Avalon® Host Bridge Cores 7. Intel eSPI Agent Core 8. eSPI to LPC Bridge Core 9. Ethernet MDIO Core 10. Intel FPGA 16550 Compatible UART Core 11. UART Core 12. JTAG UART Core 13. Intel FPGA Avalon® Mailbox Core 14. Intel FPGA Avalon® Mutex Core 15. Intel FPGA Avalon® I2C (Host) Core 16. Intel FPGA I2C Agent to Avalon® -MM Host Bridge Core 17. Intel FPGA Avalon® Compact Flash Core 18. EPCS/EPCQA Serial Flash Controller Core 19. Intel FPGA Serial Flash Controller Core 20. Intel FPGA Serial Flash Controller II Core 21. Intel FPGA Generic QUAD SPI Controller Core 22. Intel FPGA Generic QUAD SPI Controller II Core 23. Interval Timer Core 24. Intel FPGA Avalon FIFO Memory Core 25. On-Chip Memory (RAM and ROM) Intel FPGA IP 26. On-Chip Memory II (RAM or ROM) Intel FPGA IP 27. Optrex 16207 LCD Controller Core 28. PIO Core 29. PLL Cores 30. DMA Controller Core 31. Modular Scatter-Gather DMA Core 32. Scatter-Gather DMA Controller Core 33. SDRAM Controller Core 34. Tri-State SDRAM Core 35. Video Sync Generator and Pixel Converter Cores 36. Intel FPGA Interrupt Latency Counter Core 37. Performance Counter Unit Core 38. Vectored Interrupt Controller Core 39. Avalon® -ST Data Pattern Generator and Checker Cores 40. Avalon® -ST Test Pattern Generator and Checker Cores 41. System ID Peripheral Core 42. Avalon® Packets to Transactions Converter Core 43. Avalon® -ST Multiplexer and Demultiplexer Cores 44. Avalon® -ST Bytes to Packets and Packets to Bytes Converter Cores 45. Avalon® -ST Delay Core 46. Avalon® -ST Round Robin Scheduler Core 47. Avalon® -ST Splitter Core 48. Avalon® -MM DDR Memory Half Rate Bridge Core 49. Intel FPGA GMII to RGMII Converter Core 50. HPS GMII to RGMII Adapter Intel® FPGA IP 51. Intel FPGA MII to RMII Converter Core 52. HPS GMII to TSE 1000BASE-X/SGMII PCS Bridge Core Intel® FPGA IP 53. Intel FPGA HPS EMAC to Multi-rate PHY GMII Adapter Core 54. Intel FPGA MSI to GIC Generator Core 55. Cache Coherency Translator Intel® FPGA IP 56. Lightweight UART Core

56.5.1. HAL System Library Support

The Intel-provided driver implements a HAL character-mode device driver that integrates into the HAL system library for Nios II and Nios V processors systems.
HAL users should access the Lightweight UART via the familiar HAL API and the ANSI C standard library, rather than accessing the Lightweight UART registers. ioctl() requests are defined that allow HAL users to control the hardware-dependent aspects of the Lightweight UART.
Note: If your program uses the HAL device driver to access the Lightweight UART hardware, accessing the device registers directly interferes with the correct behavior of the driver.

The driver supports the CTS/RTS control signals when they are enabled in Platform Designer. Refer to Driver Options: Fast vs. Small Implementations.

The following code demonstrates the simplest possible usage, printing a message to stdout using printf(), sending data, receiving data, using ioctl, using EOP, using EH and set TRBK.

Note:
  1. In the first example, the system contains a Lighweight UART core, and the HAL system library has been configured to use this device for stdout.
  2. Except the first example, all of the examples use the JTAG UART as stdout for debugging purpose.

Example: Printing Characters to a Lightweight UART Core as stdout

#include <stdio.h>
int main ()
{
    printf("Hello world.\n");
    return 0;
}

The following three example codes demonstrate reading characters from and sending messages to another Lightweight UART device using the C standard library. In these three examples, the system contains a Lightweight UART core, that is not necessarily configured as the stdout device.

In this case, the program treats the device like any other node in the HAL file system.

For more information about the HAL system library, refer to the Nios II Software Developer's Handbook.

Example: Sending Data via File Pointer

#include <stdio.h>
#include "system.h"
#define ELEMENT_SIZE 1
/* this is a simple program to send data via lw uart.*/
int main()
{
      FILE* fp;
      int ret_val;
      /* open file pointer with device name, that can be found in system.h */
      fp = fopen (INTEL_LW_UART_0_NAME, "r+");
      if(NULL==fp)
      {
          printf("Device not found\n");
      }
      else
          {
          ret_val = fprintf(fp,"Hello LW UART.\n"); /* using fprintf*/
          if (0>ret_val)
              {
                  printf("write error!\n");
              }
          char msg[] = "Hello again.\n";
          int msg_size = sizeof(msg)-1; /* -1 because of null terminator in c string*/
          ret_val = fwrite (msg, ELEMENT_SIZE, msg_size, fp); /* using fwrite*/
           if (msg_size>ret_val) 
              {
                  printf("write error!\n");
              }
         }
         ret_val = fclose(fp);
         if( 0 != ret_val) 
          {
                  printf(“unable to close\n”);
          }
      return 0;
}

Example: Sending Data via File Descriptor

#include <stdio.h>
#include "system.h"
#include <fcntl.h>
#include <unistd.h>
/* this is a simple program to send data via lw uart.*/
int main()
{
    int ret_val;
    int fd;
    char msg[] = "Hello LW UART.\n";
    int msg_size = sizeof(msg)-1; /* -1 because of null terminator in c string*/
    /* open file descriptor with device name, that can be found in system.h */
    fd = open(INTEL_LW_UART_0_NAME, O_RDWR);
    if(0==fd)
    {
        printf("Device not found\n");
    }
    else
    {
        ret_val = write(fd,msg, msg_size);
        if (msg_size>ret_val)
        {
            printf("write error!\n");
        }
    }
    ret_val = close(fd);
    if (0!=ret_val) 
    {
    printf("unable to close!\n");
    }
    return 0;
}

Example: Receiving Data

#include <stdio.h>
#include "system.h"
#define ELEMENT_SIZE 1
#define READ_SIZE 15
#define BUFF_SIZE 100
/* this is a simple program to read data via lw uart.*/
int main()
{
    FILE* fp;
    int ret_val;
    char msg_buf[BUFF_SIZE];
    char * buf_ptr;
    /* open file pointer with device name, that can be found in system.h */
    fp = fopen (INTEL_LW_UART_1_NAME, "r+");
    if(NULL==fp)
    {
        printf("Device not found\n");
    }
    else
    {
        buf_ptr = msg_buf;
        ret_val = fread (buf_ptr, ELEMENT_SIZE, READ_SIZE, fp);
        if(READ_SIZE>ret_val)
        {
            printf("read error!\n");
        }
        else
        {
            printf("Read: %*.*s", ret_val,ret_val, msg_buf);
        }
    }
    ret_val = fclose(fp);
    if (0!=ret_val)
    {
        printf("unable to close!\n");
    }
return 0;
}
Note:
  1. This example is only for receiving data. A complete system is required to send data.
  2. If rx timeout is disabled, you must ensure that there are at least READ_SIZE byte of data available in the driver rx buffer.

Example: Using IOCTL

#include <stdio.h>
#include "system.h"
#include <fcntl.h>
#include "sys/alt_errno.h"
#include <sys/ioctl.h>
#include <sys/termios.h>
#include <unistd.h>
/*this is a simple test to test IOCTL*/
int main()
{
    int fd;
    FILE * fp=NULL;
    int err_save, ret_val;
    struct termios term;
    fd = open(INTEL_LW_UART_0_NAME, O_RDWR);
    if(0==fd)
    {
        printf("Device not found\n");
    }
    else
    {
        /* lock access */
        ret_val = ioctl (fd, TIOCEXCL, NULL);
        if(0 == ret_val)
        {
            ALT_ERRNO = 0;
            fp = fopen (INTEL_LW_UART_0_NAME, "r+");
            err_save = ALT_ERRNO;
            if(NULL == fp)
            {
                printf("EC %d! File is locked!\n", err_save);
            }
        /* unlock access */
        ret_val = ioctl (fd, TIOCNXCL, NULL);
        if(0 == ret_val)
        {
            ALT_ERRNO = 0;
            fp = fopen (INTEL_LW_UART_0_NAME, "r+");
            err_save = ALT_ERRNO;
            if(NULL != fp)
            {
                printf("EC %d! File unlocked.\n", err_save);
            }
            /* change baudrate */
            ret_val = ioctl (fd, TIOCMGET, &term);
            if(0!=ret_val)
            {
                /* should not happened in this example*/
                printf("EC=%d, TIOCMGET failed!\n", ret_val);
            }
            printf("orignal baudrate %ld\n", term.c_ispeed);
            term.c_ispeed = 57600;
            term.c_ospeed = term.c_ispeed;
            ret_val = ioctl (fd, TIOCMSET, &term);
            if(0!=ret_val)
            {
                /* should not happened in this example*/
                printf("EC=%d, TIOCMSET failed!\n", ret_val);
            }
            else
            {
                ret_val = ioctl (fd, TIOCMGET, &term);
                if(0!=ret_val)
                {
                    /* should not happened in this example*/
                    printf("EC=%d, TIOCMGET failed!\n", ret_val);
                }
                printf("changed baudrate %ld\n", term.c_ispeed);
            }
            ret_val = fclose(fp);
            if (0>ret_val)
            {
                printf("unable to close!\n");
            }
            }
        }
    }
    ret_val = close(fd);
    if (0!=ret_val) 
    {
        printf("unable to close!\n");
    }
return 0;
}
Note: You must enable the IOCTL and disable the small driver.

Example: Using EOP

#include <stdio.h>
#include "system.h"
#include "intel_lw_uart.h"
void eop_user_cb_func(void)
{
    printf("eop detected!\n");
}
int main()
{
    int fd; 
    FILE* fp;
    int ret_val;
    fp = fopen (INTEL_LW_UART_1_NAME, "r+");
    if(NULL==fp)
    {
        printf("Device not found\n");
    }
    else
    {
        fd = fileno(fp); /*fd can be obtained via fp*/
        /*configure eop feature.*/
        ret_val = intel_lw_uart_init_eop(fd, eop_user_cb_func,'A');
        if(0!=ret_val)
        {
            printf("eop configuration failed!\n");
        }
    }
    ret_val = fclose(fp);
    if (0!=ret_val) 
    {
        printf("unable to close!\n");
    }
    return 0;
}
Note: The eop call back function is called when the eop interrupt is triggered. The example expects other Lightweight UART is transmitting. If the complete system is not available, you can test this by creating two Lightweight UART instances and manually cross their transmitters and receivers.

Example: Using EH

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include "system.h"
#include "intel_lw_uart.h"
#include "intel_lw_uart_regs.h"
void eh_user_cb_func(void* base, alt_u32 status)
{
    if(status &INTEL_LW_UART_CONTROL_ROE_MSK) 
    {
        printf("Base 0x%p rx over run error\n", base);
    }
    if(status &INTEL_LW_UART_CONTROL_TOE_MSK)
    {
        printf("Base 0x%p tx over run error\n", base);
    }
    if(status &INTEL_LW_UART_CONTROL_RUE_MSK)
    {
        printf("Base 0x%p rx under run error\n", base);
    }
    if(status &INTEL_LW_UART_CONTROL_FE_MSK)
    {
        printf("Base 0x%p frame error\n", base);
    }
    if(status &INTEL_LW_UART_CONTROL_PE_MSK)
    {
        printf("Base 0x%p frame error\n", base);
    }
    if(status &INTEL_LW_UART_CONTROL_BRK_MSK)
    {
        printf("Base 0x%p rx break error\n", base);
    }
}
int main()
{
    int fd;
    int ret_val;
    fd = open (INTEL_LW_UART_0_NAME, O_RDWR);
    if(0==fd)
    {
        printf("Device not found\n");
    }
    else
    {
        /*configure eh feature.*/
        ret_val = intel_lw_uart_init_eh(fd, eh_user_cb_func);
        if(0!=ret_val)
        {
            printf("eh configuration failed!\n");
        }
    }
    /* trigger rx underrun error */
    (void)IORD_INTEL_LW_UART_RXDATA(INTEL_LW_UART_0_BASE);
    ret_val = close(fd);
    if (0!=ret_val)
    {
        printf("unable to close!\n");
    }
    return 0;
}
Note: The eh callback function is called when the “e”(exception) interrupt is triggered. You should not use switch case in the call back function, as more than one exception can occur at a time.

Example: Setting TRBK

#include <stdio.h>
#include "system.h"
#include "intel_lw_uart.h"
#include <fcntl.h>
#include <unistd.h>
#include "intel_lw_uart_regs.h"

int main()
{
    int fd;
    int ret_val;
    fd = open(INTEL_LW_UART_0_NAME, O_RDWR);
    if(0==fd)
    {
        printf("Device not found\n");
    }
    else
    {
        ret_val=intel_lw_uart_set_trbk(fd, INTEL_LW_UART_TRBK_ENABLE);
        if(0!=ret_val)
        {
            printf("trbk configuration failed!\n");
        }
        usleep(100);
        ret_val=intel_lw_uart_set_trbk(fd, INTEL_LW_UART_TRBK_DISABLE);
        if(0!=ret_val)
        {
            printf("trbk configuration failed!\n");
        }
    }
    ret_val = close(fd);
    if (0!=ret_val) 
    {
        printf("unable to close!\n");
    }
return 0;
}

Note: The Setting TRBK example sets the TRBK control, that stops the TX FIFO from shifting and in addition, flushes both data in TX FIFO and TX driver buffer. You must reset this control to resume sending.

Example: Assert RTS for Small Driver

#include <stdio.h>
#include "system.h"
#include "intel_lw_uart_regs.h"

#define ELEMENT_SIZE 1
/*This is a simple program to send data via lw uart.*/
int main()
{
    FILE* fp;
    int ret_val;
    alt_u32 control;
    /*open file pointer with device name, that can be found in system.h*/
    fp = fopen(INTEL_LW_UART_0_NAME,"r+");
    if(NULL==fp)
    {
        printf("Device not found\n");
    }
    else
    {
        /* Assert RTS to transmit */
        control = IORD_INTEL_LW_UART_CONTROL(INTEL_LW_UART_0_BASE);
        CONTROL |= INTEL_LW_UART_CONTROL_RTS_MASK;
        IOWR_INTEL_LW_UART_CONTROL(INTEL_LW_UART_0_BASE, control);

        ret_val=fprintf(fp,"Hello LW UART.\n";    /* using fprintf*/
        if(0!=ret_val)
        {
            printf("write error!\n");
        }
    }
    ret_val=fclose(fp);
    if(0!=ret_val) 
    {
        printf("unable to close!\n");
    }

    /* Deassert RTS */
    control&=INTEL_LW_UART_CONTROL_RTS_MSK;
    IOWR_INTEL_LW_UART_CONTROL(INTEL_LW_UART_0_BASE, control);

return 0;
}
Note: Small driver also disables the Hardware Flow Control code in the driver. If you enable the Small driver and Hard Flow Control features together in Platform Designer, any assertion or deassertion of RTS bit in Control Register has to be done manually in your application, as shown in the example above.