📜 ⬆️ ⬇️

Distributed control system based on SoC FPGA

Realization of the FPGA firmware bundle, NIOS microcontroller software and Linux management software based on Altera Cyclone V SoC using Avalon Mailbox to create a distributed control system based on them.

Introduction


In a distributed control system, many different tasks have to be solved at different levels.

Some tasks should be solved at the level of an embedded PC with a full OS. A full-fledged OS is good because it has already implemented and debugged many useful tools, such as multithreading, ready-made drivers, libraries, various frameworks and so on. And all this can be developed in high-level languages, especially without going into implementation details at the lower level.

There are tasks that are conveniently solved at the microcontroller level (hereinafter referred to as MK), either without an OS at all (bare-metal), or with minimalistic real-time OSs. Here, the key role is played by the possibility of debugging software inside the OS via JTAG and tracking what is happening at the periphery of the MC at any break-point.
')
And there are tasks that should be solved already at the level of the FPGA, since no microcontroller may be enough for competent parallel control of different high-frequency electronics, for example, stepper drive drivers with data processing of encoders and speed controllers. In such tasks, the processor is simply superfluous.

The number of actuators and their various functions in the control system increases dramatically when it comes to device development, for example, with a three-degree manipulator, two-three servomotors, a dozen discrete devices, a lot of peripherals on all popular interfaces (SPI, I2C, UART and etc.) and complex logic with mathematical analysis inside. And the whole control system is very convenient to arrange on one chip in general, which will actually be done. As a result, all three levels of PC-MK-FPGA control and their interactions will move inside the crystal.

In this case, the task of creating a transport level, which links all this complex logic to each other, inevitably arises. For the MK-FPGA bundle, this is solved, in fact, by creating the next peripheral device on the MK common bus with its own set of registers. But the task of creating a PC-MK transport level will be solved a little differently.

For experiments, we need a real or virtual machine with Ubuntu 16.04 on board.
The source code for all programs is available on GitHub .

Management System Architecture


Imagine that all actuators of the control system PK-MK-FPGA are reduced to parallel I / O ports. For example, as sensors and actuators, we will limit ourselves to a set of buttons and LEDs, and we will manage them from the terminal command line.



All elements of the FPGA, including MK, will be synthesized. Part of the PC is already integrated into the chip and is based on the Cortex A9, the tires of which are derived in the FPGA and can be used directly. Therefore, all that has to be done is to connect the modules necessary for communication with the synthesized nodes in the FPGA via standard tools to the OS kernel.
As a hardware platform, we use the DE0-Nano-SoC kit.

Getting FPGA firmware


Let's take as a basis the base my_first_hps-fpga_base project from the DE0-Nano-SoC CD-ROM set (rev.B0 / rev.C0 Board) . The project contains a pre-configured environment with correctly set FPGA ports, a ready-made Cyclone V Hard Processor System unit with configured memory parameters and a set of auxiliary elements in Qsys. To work with the project, we need Quartus Prime 15.1 with the Cyclone V Support Package and the SoC Embedded Design Suite .

Let's make some changes to the project. Add the NIOS core, memory for it (16 KB 32-bit width) and JTAG port. We indicate in the NIOS parameters the addresses of the vectors from the added memory.



Avalon Mailbox is simplex, so we need two modules (like the RX and TX lines of a regular UART). The interrupt signal of each of the modules must be connected to the processor for which the module is receiving.

Add one port (8 bit) of input and output for further testing of the system.

After adding all the elements you can make automatic selection of addresses and interrupts.



Let's create ports for buttons and LEDs in the code of the upper module.

// Ports wire [7:0] port_out; assign LED = port_out; wire [7:0] port_in; assign port_in = {{2{1'b0}}, SW, KEY}; 

Connect the ports to the soc_system.

  // FPGA Partion .port_out_export(port_out), // port_out.export .port_in_export(port_in), // port_in.export 

We will assemble the project and get the FPGA firmware, on the basis of which we will continue to work.

Algorithm


So, create a system that will do the following:



On the side of MK


In the NIOS II EDS environment, which in essence is Eclipse with all the necessary plug-ins, we will create a new soc_nios project from the “NIOS II Application and BSP” template. The result will be two projects: direct firmware and BSP.

First of all, you need to immediately assemble a BSP, but not in the traditional way. Instead, in the context menu of the soc_nios_bsp project, you need to select the BSP Editor item in the NIOS II menu and enable the enable_small_c_library and enable_reduced_device_drivers options so that the firmware does not grow. Then build by clicking Generate . Further, since the build parameters are preserved, you can rebuild the BSP simply by selecting the Generate BSP item in the NIOS II menu.

In the system.h file from the BSP project, you can see all the parameters of the MK peripherals that were previously added to the Qsys scheme.

You can read more about NIOS and how to build projects for it here .

To solve the problem at the level of MK, we need:



It remains to collect the project. The NIOS firmware size should be less than 16 Kb.
To test the firmware on the hardware, you need to create a new debugger configuration. After the FPGA firmware from the Quartus Programmer in the Debug Configurations menu, select the NIOS II Hardware option, update all interfaces and in the Target Connections tab we find jtaguart_1 . This is the same JTAG for NIOS, which we previously added to Qsys.

Now you can start debugging from Eclipse. If everything is done correctly, the message “Turn the switch ON to activate the timer” should appear in the NIOS II console.

PC side


Installing Linux on the board


In detail, the whole process is described here in sections 1 through 10. It is recommended to use more recent fresh versions of the toolchain , bootloader and kernel than those that can be found by reference. Please note that for building this version of the bootloader, the toolchain with the compiler above version 6 will not work.

To generate a device tree, instead of the proposed sopc2dts utility, it is better to use the sopc2dts.jar script, and you can specify --type dtb right away .

To get the system it is strongly recommended to use the freshest Buildroot . To build, you must force the CC environment variables as the path to arm-linux-gnueabihf-gcc and CXX as the path to arm-linux-gnueabihf-g ++ from the toolchain. Next, enter the used versions of the compiler, the kernel and the library (the system itself prompts them during the build process). In the configuration of the toolchain when configuring Buildroot, you must specify the path to the toolchain, as well as the prefix $ (ARCH) -linux-gnueabihf and enable support for SSP, RPC and C ++.
For convenience, you can add nano, mc, and openssh packages to Buildroot.
Next, we will collect all the top-level software in Eclipse with the GNU MCU Eclipse plug-in plug-in . Create a new workspace for ARM projects and in the global Eclipse settings in the Workspace Tools Path section, specify the appropriate path to the installed version of Linaro.

Driver


First of all, let's make a driver for Mailboxes. Create a new nios_mailbox project from the Hello World ARM C Project template in Eclipse.

In the project settings, turn off the “Use default build command” and “Generate Makefiles automatically” options, since to build the kernel module you will need the command make TARGET = nios_mailbox TARGET_DIR = Default . Add two new CROSS_COMPILE and KDIR entries to the environment variables, pointing to the full path with the tulchain prefix and the path to the kernel sources, respectively. Add __GNUC__, __KERNEL__ and MODULE to the list of defines. Everything. Now you can write code.

The kernel module will respond to an interrupt from hardware and must somehow communicate this to the application world. For this purpose we need to create our own signal.

  #define NIOS_MAILBOX_REALTIME_SIGNO 44 

The driver will be created on the basis of platform_device, each Mailbox will be like a miscdevice, and ultimately the system will be visible as a device file in the / dev directory. More details about the drivers and generally you can read here . It is important to understand that we can theoretically have as many Mailboxes as we like, and the driver is one for all, and it should initialize and number them all.

If you don’t specifically go into details, the driver development comes down to the implementation of standard read and write operations to the file, plus a small bonus in the form of a special ioctl () function, which is needed for the id of the process that uses it to pass to the driver. This is necessary in order to know which process in the system signals the occurrence of a hardware interrupt. The interrupt handler itself looks pretty simple and is very similar to its counterpart in NIOS.

  static irq_handler_t nios_mailbox_isr(int irq, void *pdev) { struct nios_mailbox_dev *dev = (struct nios_mailbox_dev*)platform_get_drvdata(pdev); spin_lock(&dev->lock); //NOTE: Order is important! CMD register should be read after PTR register dev->data[1] = ioread32(dev->regs + ALTERA_AVALON_MAILBOX_SIMPLE_PTR_OFST * sizeof(u32)); dev->data[0] = ioread32(dev->regs + ALTERA_AVALON_MAILBOX_SIMPLE_CMD_OFST * sizeof(u32)); spin_unlock(&dev->lock); if(dev->task) { send_sig_info(dev->sinfo.si_signo, &dev->sinfo, dev->task); } return (irq_handler_t)IRQ_HANDLED; } 

It remains to collect the project. To do this, we need to write a special Makefile. It will look like this.

  all: @echo 'KDIR=$(KDIR)' @echo 'CROSS_COMPILE=$(CROSS_COMPILE)' @if [ ! -d $(CURDIR)/$(TARGET_DIR) ]; then mkdir $(CURDIR)/$(TARGET_DIR); fi cp $(TARGET).c $(CURDIR)/$(TARGET_DIR) cp $(TARGET).h $(CURDIR)/$(TARGET_DIR) cp Kbuild $(CURDIR)/$(TARGET_DIR) $(MAKE) -C $(KDIR) ARCH=arm M=$(CURDIR)/$(TARGET_DIR) clean: rm -rf main $(CURDIR)/$(TARGET_DIR) 

And we will also need to create a Kbuild file with one line.

  obj-m := $(TARGET).o 

Let's collect the project in the traditional way. As a result, we get the kernel module nios_mailbox.ko , which we copy onto the system and install it using insmod. If everything is done correctly, in a Linux console opened via USB, when you press the corresponding button on the board, a message from the kernel “[.........] NIOS Mailbox new mail!” Should appear.

Of course, the driver would need to add a buffer for the received interrupt data, since the reading by the application program may not keep pace with the data stream from the iron. And the driver itself is better to assemble with the stripped option, to save space in the embedded system. However, these questions will be left to the reader for independent study.

application


So we got to writing a console application. Create a new project soc_test in the Eclipse project from the Hello World ARM C ++ Project template. In the Settings section of the Target Processor, select the cortex-a9 architecture, in the Cross ARM GNU G ++ Linker, add -pthread . In the Build Artifact tab, you can remove the file extension. All other settings can be left as default.

To solve the problem at the application level, we need:



It remains to collect the project. As a result, we obtain an executable file for the ARM-9 architecture, which we copy to the system. If everything is done correctly, then after launch, the message “Enter command (” read ”(“ r ”),“ write ”(“ w ”),“ reverse ”),“ q ”to exit" will appear in the console.

Run and check the system


Installing the kernel module is added to the autoload for Linux.

We will assemble a new version of the NIOS firmware, removing the entire debugging output from the program in JTAG. Let's convert the firmware to hex format by running the command “elf2hex --input = soc_nios.elf --output = soc_nios.hex --width = 32 --base = 0x4000 --end = 0x7fff --record = 4” in SoC EDS 15.1 Command Shell . The resulting firmware must be added as an initialization file for NIOS memory in Qsys, then rebuild Qsys, rebuild the FPGA project and write the new firmware to the memory card.



Download and immediately launch the test application. And if everything was done correctly, then we get a working system.

findings


Do not be afraid to use such complex bundles as FPGA-MK-PC based on SoC in your projects. This article demonstrated that implementing such a system is not so difficult. You can even add several microcontrollers and link them together in a similar way.

The control system, created on the basis of the principles outlined above, was introduced by the author into one of the electronic devices and proved its efficiency in the real world.

Source: https://habr.com/ru/post/353680/


All Articles