In this manual you will learn to create a shared library(.so) for your embedded Intel ARM SoC using ARM Development Studio IDE . so you can use on Python on your Linux on you Intel ARM SoC.

Introduction:

Designing shared libraries (.SO in Linux, or .DLL in Windows) can be highly beneficial in software development, particularly in the context of embedded systems, for several reasons:

  1. Code Reusability: Shared libraries enable code reuse, allowing multiple applications or components to access the same set of functions or resources without duplicating the code. This leads to a more efficient and modular software development process.

  2. Space Efficiency: In embedded systems, where resources like memory and storage are often limited, shared libraries can save space by allowing multiple applications to share the same code. This reduces the overall memory footprint of the system.

  3. Version Management: Shared libraries provide a clear and structured way to manage software versions. When you need to update or fix a particular piece of code, you can update the library once, and all applications using it will automatically benefit from the changes. This simplifies version control and maintenance.

  4. Interoperability: Libraries allow for better interoperability among different components of a system. They can serve as an interface between various software modules, making it easier to integrate different parts of an embedded system.

  5. Encapsulation: Shared libraries encapsulate functionality, providing a clear API (Application Programming Interface) for interacting with the code. This abstraction helps in hiding implementation details and allows developers to focus on using the library without having to understand its internal workings.

  6. Load-Time and Run-Time Flexibility: Shared libraries can be loaded at either load-time (when an application starts) or run-time (dynamically) based on the system's requirements. This flexibility can be crucial for optimizing system resource usage.

  7. Security: Libraries can be designed to enforce security and access control, ensuring that only authorized components can use certain functionality. This helps in maintaining system integrity and data security.

  8. Hot Patching: In some cases, shared libraries can be updated without needing to restart the entire system. This is particularly useful in situations where system downtime is unacceptable or challenging to achieve.

  9. Language Independence: Libraries can be written in different programming languages, making it possible to leverage code written in various languages within the same embedded system.

  10. Portability: Shared libraries can be moved from one system to another with relative ease, provided that the target system has the necessary libraries or can dynamically link to them. This can simplify the deployment and distribution of software on different embedded platforms.

  11. Faster Development: Shared libraries can speed up software development because developers can focus on building higher-level application logic instead of reinventing low-level functionality.

However, it's important to note that designing and managing shared libraries also introduces some complexities, such as version compatibility issues and the need for well-defined APIs. Nevertheless, the benefits they offer in terms of code reuse, resource efficiency, and modular software design make them a valuable tool in software development for embedded systems.

 

Using shared libraries for accessing GPIOs or peripherals in embedded systems can offer several advantages over directly using kernel modules or sysfs for this purpose:

1. Portability: Shared libraries can be designed to provide a unified and consistent API for interacting with GPIOs and peripherals, abstracting the underlying hardware details. This allows you to write your application code in a more hardware-independent manner, making it easier to port the software to different platforms without rewriting the entire codebase.

2. User-Space Access: Kernel modules typically require kernel-space code, which can be complex and less accessible to application developers. Shared libraries operate in user space, making them more accessible to developers who may not be familiar with kernel programming, and allowing them to interact with GPIOs and peripherals more easily.

3. Easier Debugging: Debugging user-space code is generally easier than kernel-space code, and shared libraries facilitate this by keeping most of the code within user space. This can streamline the development and debugging process.

4. Flexibility and Customization: Shared libraries can be customized and extended to include additional features or modifications to suit your specific application requirements. This flexibility allows you to tailor the library to your exact needs without modifying the kernel or loading/unloading kernel modules.

5. Reduced System Instability: Kernel modules can potentially destabilize an embedded system if they contain bugs or incompatibilities with the kernel. By using shared libraries, any issues with the library are less likely to affect the entire system since it operates in user space and can be isolated.

6. No Need for Kernel Module Management: Using shared libraries eliminates the need to deal with kernel module management, such as loading and unloading modules and ensuring compatibility with different kernel versions. This simplifies the software deployment process.

7. Performance Optimization: Shared libraries can be optimized for performance since they operate in user space and can be tailored to the specific needs of an application. This level of control can lead to more efficient resource usage.

8. API Abstraction: Shared libraries can offer a higher-level, abstracted API that simplifies the interaction with GPIOs and peripherals, reducing the complexity of writing and maintaining low-level kernel code.

9. Application Isolation: By using shared libraries, you can isolate the behavior of your application from the underlying hardware and the kernel. This can enhance system stability and security by limiting the potential impact of application errors or vulnerabilities.

10. Licensing and Legal Considerations: Some kernel modules may be subject to open-source licensing requirements, which can be restrictive. Using shared libraries can offer more flexibility in terms of licensing and legal compliance.

However, it's essential to carefully design and maintain these shared libraries to ensure that they provide a stable and secure interface for accessing GPIOs and peripherals. Additionally, for some specific use cases or when dealing with highly specialized hardware, using kernel modules or sysfs might still be the preferred approach, as they offer more direct access to the hardware and can provide real-time capabilities. The choice between shared libraries and kernel modules depends on the specific requirements of your embedded system and the trade-offs you are willing to make.

 

Procedure

  1. Open ARM Development Studio IDE and create a new library project, and Select C++ project.


  2. Then select "Shared library", select the Toolchain on Linux you are using, and name the project as "library_example", then press Finish.

  3. Create 2 new files “foo.h” and “foo.cpp”, under src.
  4. Write on the foo.h file the following.
    #ifndef FOO_H_
    #define FOO_H_
    
    extern "C" {
    	int foo(int number);
    }
    
    
    #endif /* FOO_H_ */
    ​
  5. Write on the foo.cpp file
    #include <stdio.h>
    
    extern "C" {
    	int foo(int number);
    }
    
    int foo(int number)
    {
        printf("Hello, I am a shared library\n");
        printf("your return is %d\n",(number+1));
        return ((number+1));
    }
    ​
  6. Then build the library.


  7. Once the library is compiled you will get a “.so” file which you now can use your shared library. For this you need to copy the liblibrary_example.so file to your rootfs using i.e WinSCP.
  8. Now time to build test it with python.

     #!/usr/bin/python
    from ctypes import CDLL, byref, c_int
    
    lib = CDLL("/home/root/libtest_shared.so")
    data=lib.foo(10)
    print(data);​
  9. you should see at the output:
    Hello, I am a shared library
    your return is 11
    11​

 

 

 

In this manual you will learn to create a shared library(.so) for your embedded ARM using Vitis. so you can use on Python on Petalinux.

 

Introduction

Designing shared libraries (.SO in Linux, or .DLL in Windows) can be highly beneficial in software development, particularly in the context of embedded systems, for several reasons:

  1. Code Reusability: Shared libraries enable code reuse, allowing multiple applications or components to access the same set of functions or resources without duplicating the code. This leads to a more efficient and modular software development process.

  2. Space Efficiency: In embedded systems, where resources like memory and storage are often limited, shared libraries can save space by allowing multiple applications to share the same code. This reduces the overall memory footprint of the system.

  3. Version Management: Shared libraries provide a clear and structured way to manage software versions. When you need to update or fix a particular piece of code, you can update the library once, and all applications using it will automatically benefit from the changes. This simplifies version control and maintenance.

  4. Interoperability: Libraries allow for better interoperability among different components of a system. They can serve as an interface between various software modules, making it easier to integrate different parts of an embedded system.

  5. Encapsulation: Shared libraries encapsulate functionality, providing a clear API (Application Programming Interface) for interacting with the code. This abstraction helps in hiding implementation details and allows developers to focus on using the library without having to understand its internal workings.

  6. Load-Time and Run-Time Flexibility: Shared libraries can be loaded at either load-time (when an application starts) or run-time (dynamically) based on the system's requirements. This flexibility can be crucial for optimizing system resource usage.

  7. Security: Libraries can be designed to enforce security and access control, ensuring that only authorized components can use certain functionality. This helps in maintaining system integrity and data security.

  8. Hot Patching: In some cases, shared libraries can be updated without needing to restart the entire system. This is particularly useful in situations where system downtime is unacceptable or challenging to achieve.

  9. Language Independence: Libraries can be written in different programming languages, making it possible to leverage code written in various languages within the same embedded system.

  10. Portability: Shared libraries can be moved from one system to another with relative ease, provided that the target system has the necessary libraries or can dynamically link to them. This can simplify the deployment and distribution of software on different embedded platforms.

  11. Faster Development: Shared libraries can speed up software development because developers can focus on building higher-level application logic instead of reinventing low-level functionality.

However, it's important to note that designing and managing shared libraries also introduces some complexities, such as version compatibility issues and the need for well-defined APIs. Nevertheless, the benefits they offer in terms of code reuse, resource efficiency, and modular software design make them a valuable tool in software development for embedded systems.

 

Using shared libraries for accessing GPIOs or peripherals in embedded systems can offer several advantages over directly using kernel modules or sysfs for this purpose:

1. Portability: Shared libraries can be designed to provide a unified and consistent API for interacting with GPIOs and peripherals, abstracting the underlying hardware details. This allows you to write your application code in a more hardware-independent manner, making it easier to port the software to different platforms without rewriting the entire codebase.

2. User-Space Access: Kernel modules typically require kernel-space code, which can be complex and less accessible to application developers. Shared libraries operate in user space, making them more accessible to developers who may not be familiar with kernel programming, and allowing them to interact with GPIOs and peripherals more easily.

3. Easier Debugging: Debugging user-space code is generally easier than kernel-space code, and shared libraries facilitate this by keeping most of the code within user space. This can streamline the development and debugging process.

4. Flexibility and Customization: Shared libraries can be customized and extended to include additional features or modifications to suit your specific application requirements. This flexibility allows you to tailor the library to your exact needs without modifying the kernel or loading/unloading kernel modules.

5. Reduced System Instability: Kernel modules can potentially destabilize an embedded system if they contain bugs or incompatibilities with the kernel. By using shared libraries, any issues with the library are less likely to affect the entire system since it operates in user space and can be isolated.

6. No Need for Kernel Module Management: Using shared libraries eliminates the need to deal with kernel module management, such as loading and unloading modules and ensuring compatibility with different kernel versions. This simplifies the software deployment process.

7. Performance Optimization: Shared libraries can be optimized for performance since they operate in user space and can be tailored to the specific needs of an application. This level of control can lead to more efficient resource usage.

8. API Abstraction: Shared libraries can offer a higher-level, abstracted API that simplifies the interaction with GPIOs and peripherals, reducing the complexity of writing and maintaining low-level kernel code.

9. Application Isolation: By using shared libraries, you can isolate the behavior of your application from the underlying hardware and the kernel. This can enhance system stability and security by limiting the potential impact of application errors or vulnerabilities.

10. Licensing and Legal Considerations: Some kernel modules may be subject to open-source licensing requirements, which can be restrictive. Using shared libraries can offer more flexibility in terms of licensing and legal compliance.

However, it's essential to carefully design and maintain these shared libraries to ensure that they provide a stable and secure interface for accessing GPIOs and peripherals. Additionally, for some specific use cases or when dealing with highly specialized hardware, using kernel modules or sysfs might still be the preferred approach, as they offer more direct access to the hardware and can provide real-time capabilities. The choice between shared libraries and kernel modules depends on the specific requirements of your embedded system and the trade-offs you are willing to make.

Procedure

  1. Open Vitis and create a new library project.
  2. Select the target platform you want to work with(your platform hardware).

  3. Select Shared library and name it “test_shared”

  4. Select either C or C++ as template.

  5. Create 2 new files “foo.h” and “foo.cpp”, under src.

  6. Write on the foo.h file the following.

    #ifndef foo_h__
    #define foo_h__
    
    extern "C" {
        int foo(int number);
    }
    
    
    #endif  // foo_h__
    
  7. Write on the foo.cpp file:
    #include <stdio.h>
    
    extern "C" {
        int foo(int number);
    }
    
    int foo(int number)
    {
        printf("Hello, I am a shared library\n");
        printf("your return is %d\n",(number+1));
        return (number+1);
    }
    ​
  8. Then build the library.

  9. Once the library is compiled you will get a “.so” file which you now can use your shared library.. For this you need to copy the libtest_shared.so file to your rootfs using i.e WinSCP.

  10. Now time to build test it with python.

     #!/usr/bin/python
    from ctypes import CDLL, byref, c_int
    
    lib = CDLL("/home/root/libtest_shared.so")
    data=lib.foo(10)
    print(data);
    
  11. you should see at the output:

    Hello, I am a shared library
    your return is 11
    11
    

 

 

 

Written by Holguer Andres

Requirements:

  1. DE0-NANO-SOC with and SD-CARD preloaded with the following Linux Image (compiled and customized by Holguer Andres).
  2. Putty

Procedure:

  • Using putty open the Linux Terminal through the UART port at 115200 bps.
  • On the Console type:
    nano /etc/inittab​

  • As you can observe in the next image, and highlighted in red, all the initial system processes init with ":sysinit:" and next to this a command or a script that is going to be run on the initialization of the system.

     

  • To see how it works, we are going to modify the file rcS by typing the following:

    nano /etc/init.d/rcS
    
  • once you have typed the previous console line, the nano editor is going to show you on the console the file rcS, and you are going to add the line highlighted in red 'fpgalover.com'

  •  Now save and exit.

  • Type on the console 'reboot' to restart the system

    reboot
  •  once the system is relaunched, you will see at the beginning a new line message that contains what you just have written on the rcS file.

  • Now it is your time to add your own script to the inittab file and execute what you desire!

 

 References

  1. https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/5/html/Installation_Guide/s1-boot-init-shutdown-sysv.html
  2. http://stackoverflow.com/questions/10408816/how-do-i-use-the-nohup-command-without-getting-nohup-out

 

Written by This email address is being protected from spambots. You need JavaScript enabled to view it.

 

Nios® II is an softcore 32-bit processor developed by Altera to be implemented over all Altera (INTEL) FPGA and SoC families. 

Some NIOS-II-e Gen2 features:

  • No license required.
  • Use fewer than 700 logic elements.
  • 6-stage pipeline runnning up to 30 DMIPS at 175 MHz in Nios II /e "economy" processor (Dhrystones 2.1 benchmark).
  • Deterministic and jitter free real-time performance.
  • Vector Interrupt Controller.
  • Custom instructions (ability to use FPGA hardware to accelerate a function).
  • Supported by industry-leading real-time operating systems (RTOS).
  • Nios II fast processor core can use a memory management unit (MMU) to run embedded Linux* operating system.

One way to optimize hardware resources use of Nios-II processor is implementing an real Time Operating System (RTOS) and NIOS-II is a excellent processor to run RTOS. Nios-II processor  is supported by a lot of RTOS and one of the most popular and robust is the FreeRTOS.

Some FreeRTOS features:

  • Free for use in commercial applications.
  • Scalable, simple and easy to use.
  • Simple - the core of the RTOS kernel is contained in only 3 .C files.
  • Scheduler can be configured for both preemptive or cooperative operation
  • Free tutorial books and training to educate engineers

In this article, we present all steps to implement the last FreeRTOS (v9.0) versión over the NIOS-II processor.  All step presented area developed in Quartus II 17.0 version and tested in DE0-nano development board.

Create Project using "DE0 Nano System Builder"

Open project using Quartus 17

From Quartus: File, Open Project..

Create NIOS-II instantiation using Qsys tool

  • From Quartus: Tools, Qsys..
  • Save as niosII.qsys
  • From IP catalog, include this components and configure.
IP component Name of component in project Detailed Configuration
clock_source clock_50
altera_nios2_gen2 cpu

 

altera_avalon_sysid_qsys sys_id
altera_avalon_new_sdram_controller sdram  
altera_avalon_epcs_flash_controller epcs  
altpll sys_pll

 

clock_source sys_clk  
altera_avalon_timer sys_clk_timer  
clock_source ram_clk  
altera_avalon_jtag_uart jtag  
altera_up_avalon_parallel_port LED_Pio  
altera_up_avalon_parallel_port Button_Pio  
altera_up_avalon_parallel_port Switch_Pio  
altera_avalon_uart uart  
altera_up_avalon_parallel_port IO_Pio  
  • Interconnect all components included in project in the next way.

 

Generate HDL of NIOS-II instantiation.

  • From Qsys: Generate, Generate HDL...

 

 Connect NIOS-II HDL with FPGA hardware pins.

  • write follow code in Quartus project, verilog file.
 niosII u0 (
.clk_clk (CLOCK_50), // clk.clk
.epcs_dclk (EPCS_DCLK), // epcs.dclk
.epcs_sce (EPCS_NCSO), // .sce
.epcs_sdo (EPCS_ASDO), // .sdo
.epcs_data0 (EPCS_DATA0), // .data0
.port_led_export (LED), // port_led.export
.port_key_export (KEY), // port_key.export
.port_sw_export (SW), // port_sw.export
.port_gpio_0_export (GPIO_0[31:0]), // port_gpio_0.export
.ram_clk_clk (DRAM_CLK), // ram_clk.clk
.reset_reset_n (1'b1), // reset.reset_n 
.uart_rxd (GPIO_0[32]), // uart.rxd
.uart_txd (GPIO_0[33]), // .txd
.sdram_addr (DRAM_ADDR), // sdram.addr
.sdram_ba (DRAM_BA), // .ba
.sdram_cas_n (DRAM_CAS_N), // .cas_n
.sdram_cke (DRAM_CKE), // .cke
.sdram_cs_n (DRAM_CS_N), // .cs_n
.sdram_dq (DRAM_DQ), // .dq
.sdram_dqm (DRAM_DQM), // .dqm
.sdram_ras_n (DRAM_RAS_N), // .ras_n
.sdram_we_n (DRAM_WE_N) // .we_n
); 

Include NIOS-II HDL to Quartus Project

  • From Quartus: Project, Add/Remove files in Project..
  • Add niosII.qsys file to project. 

 

Compile Quartus project

  • From Quartus: Processing, Start Compilation.

 Programming FPGA DE0-nano.

  • From Quartus: Tools, Programmer
  • click over Start Button

Create C/C++ project from Eclipse IDE

  • From Quartus: Tools, Nios II Sofware Build Tool for Eclipse.
  • Select a workspace
  • From Eclipse: File, New, Nios II Application and BSP from Template

  • Create NIOS II application from template
    • Nios II SOPC: Search for niosII. sopcinfo in to project folder
    • Project Name: Whatever you want
    • Project Template: Hello World
    • Finish

 Import FreeRTOS to Eclipse Project

  • Include FreeRTOS folders to compile path in properties of Eclipse Nios Project.

 

Edit hello_wolrd.c to create task and run FreeRTOS.

In this example, in hello_wolrd.c are created two task. This is the "hello_world.c" code. Copy and paste in your own eclipse project.

/*
 *
 * [File Name]     hello_world.c
 * [Platform]      DE0-nano
 * [Project]       NiosII & FreeRTOS
 * [Version]       1.00
 * [Author]        ea.rincon11 - ErnestoARC
 * [Date]          24/07/2017
 * [Language]      'C'
 * [History]       1.20 - Edited from original file included in FreeRTOS V9.0.0 Nios Example
 */
//-----------------------------------------------------------------------
// Standard C/C++ Includes
//-----------------------------------------------------------------------
#include <stddef.h>
#include <stdio.h>
#include <string.h>
//-----------------------------------------------------------------------
// Scheduler Includes
//-----------------------------------------------------------------------
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "partest.h"
//-----------------------------------------------------------------------
// Constants
//-----------------------------------------------------------------------
/* The rate at which the Print out message controlled by the 'Task1' */
#define mainTASK1_PERIOD	( 500 )
/* The rate at which the Print out message controlled by the 'Task2' */
#define mainTASK2_PERIOD	( 1000 )
 
/* Priority definitions for the tasks in the demo application. */
#define mainTASK1_PRIORITY		( tskIDLE_PRIORITY + 1 )
/* Priority definitions for the tasks in the demo application. */
#define mainTASK2_PRIORITY		( tskIDLE_PRIORITY + 2 )
//-----------------------------------------------------------------------
// Function Prototypes
//-----------------------------------------------------------------------
static void prvPrintTask1( void *pvParameters );
static void prvPrintTask2( void *pvParameters );
//-----------------------------------------------------------------------
// Main Function
//-----------------------------------------------------------------------
int main()
{
	/* Configure any hardware required for this demo. */
	vParTestInitialise();
 
	printf("Hello from Nios II!\n");
 
	/* prvPrintTask1 uses sprintf so requires more stack. */
	xTaskCreate( prvPrintTask1, "Task1", configMINIMAL_STACK_SIZE, NULL, mainTASK1_PRIORITY, NULL );
	/* prvPrintTask2 uses sprintf so requires more stack. */
	xTaskCreate( prvPrintTask2, "Task2", configMINIMAL_STACK_SIZE, NULL, mainTASK2_PRIORITY, NULL );
 
      /* Finally start the scheduler. */
	vTaskStartScheduler();
 
	/* Will only reach here if there is insufficient heap available to start
	the scheduler. */
	for( ;; );
 
  return 0;
}
/*-----------------------------------------------------------*/
static void prvPrintTask1( void *pvParameters )
{
	for( ;; )
	{
		/* Wait until it is time to run the tests again. */
		vTaskDelay( mainTASK1_PERIOD / portTICK_PERIOD_MS);
 
        /* Print out an message */
        printf( "NIOS II Task1\r\n" );
        /*Control LED 1 DE0-NANO*/
        vParTestToggleLED(1);
	}
}
/*-----------------------------------------------------------*/
static void prvPrintTask2( void *pvParameters )
{
	for( ;; )
	{
		/* Wait until it is time to run the tests again. */
		vTaskDelay( mainTASK2_PERIOD / portTICK_PERIOD_MS);
 
        /* Print out an message */
        printf( "NIOS II Task2\r\n" );
 
        /*Control LED 2 DE0-NANO*/
        vParTestToggleLED(2);
	}
}
/*-----------------------------------------------------------*/
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////

 

Compile and Program FreeRTOS Project into FPGA with NiosII

  • From eclipse: Project Build All
  • From eclipse: Run, Debug Configurations...
  • Click DEBUG and RUN debugger

 

Download complete project.

If you don´t want follow this steps, then download the Quartus, Qsys and Eclipse project.