ArticleDirectory
- Introduction
- Build HDL
- Hardware settings
- Software Development
Statement: This article is original works, copyright belongs to the author of this blog, If You Need To reprint, please indicate the source of http://www.cnblogs.com/kingst/
Introduction
As an embedded software-core processor built on FPGA, niosii can add any provided peripherals as needed, you can also customize user logic peripherals and Custom User commands to meet various application requirements. In this section, we will study how to customize user peripherals Based on the aveon bus.
The system provides a component editor that encapsulates the logic we write into a system component. Next, we will take the PWM experiment as an example to introduce in detail the process of customizing user peripherals Based on the aveon bus.
The PWM we want to use is based on the avron memory mapped interface (avron-mm) in the avron bus, while the avron bus also has other types of devices, such as avron streaming interface (avron-St) aveon memory mapped tristate interface and so on. I will not describe it in detail here. For more information, please refer to the company's aveon interface specifications((mnl_avalon_specication ).
The aveon-mm interface is an interface used for reading and writing between master and slave devices in the memory ing system. It is a Master/Slave Device System Based on aveon-mm. What we need to do in this section is the highlighted part. His position is in parallel with UART, Ram Controller and other modules.
The aveon-mm interface has many features. The biggest feature is to freely select the signal line based on your needs, but there are still some requirements in it. Before reading this article, we recommend that you read "aveon interface specifications" first, so that you can have an overall understanding of the aveon-mm interface.
It is a structure chart of aveon-mm peripherals,
Let's talk about this theory. The following is an example to illustrate it so that you can better understand it.
Build HDL
This section uses PWM as an example. First, we need to build a timing logic that complies with the aveon-mm slave interface specifications and can implement the PWM function. Here, we use the language of OpenGL for compiling. InProgramWe will introduce the aveon signal here (the direction is based on the slave device)
HDLSignal in |
AveonSignal type |
Width |
Direction |
Description |
CLK |
CLK |
1 |
Input |
Synchronize clock signals |
Reset_n |
Reset_n |
1 |
Input |
Reset signal, effective at low level |
Chipselect |
Chipselect |
1 |
Input |
Chip selection Signal |
Address |
Address |
2 |
Input |
2-bit address. Determine the register offset After decoding. |
Write |
Write |
1 |
Input |
Write enable signal |
Writedata |
Writedata |
32 |
Input |
32-bit write data value |
Read |
Read |
1 |
Input |
Signal upon reading |
Byteenable |
Byteenable |
1 |
Input |
Byte enable signal |
Readdata |
Readdata |
32 |
Output |
32-bit read data value |
In addition, the program also contains a pwm_out signal, which is a PWM output and does not belong to the aveon interface signal.
PWM also includes enable control registers, periodic setting registers, and duty cycle setting registers. In the design, each register is mapped to a separate offset address in the aveon slave port address space. No register can be read/written, and the software can read back the current value in the register. The registers and offset addresses are as follows:
Register name |
Offset |
Access attributes |
Description |
Clock_divide_reg |
00 |
Read/write |
Set the number of clocks in the PWM output period |
Duty_cycle_reg |
01 |
Read/write |
Set the number of low-level PWM outputs in a cycle |
Control_reg |
10 |
Read/write |
Enables and disables the PWM output. If the value is 1, the PWM output is enabled. |
The procedure is as follows:
Module PWM (CLK, reset_n, chipselect, address, write, writedata, read, byteenable, readdata, pwm_out); input CLK; input reset_n; input chipselect; input [1:0] address; input write; input [31: 0] writedata; input read; input [3: 0] byteenable; Output [31: 0] readdata; Output pwm_out; Reg [31: 0] clock_divide_reg; reg [31: 0] duty_cycle_reg; Reg control_reg; Reg clock_divide_reg_selected; Reg rule; Reg control_reg_selected; Reg [31: 0] pwm_counter; Reg [31: 0] readdata; Reg pwm_out; wire pwm_enable; // address decoding always @ (Address) encoding <= 0; duty_cycle_reg_selected <= 0; control_reg_selected <= 0; Case (Address) 2 'b00: clock_divide_reg_selected <= 1; 2 'b01: duty_cycle_reg_selected <= 1; 2 'b10: control_reg_selected <= 1; default: Success <= 0; duty_cycle_reg_selected <= 0; control_reg_selected <= 0; endendcaseend // The number of clock registers for writing the PWM output cycle always @ (posedge CLK or negedge reset_n) beginif (reset_n = 1 'b0) clock_divide_reg = 0; elsebeginif (write & chipselect & clock_divide_reg_selected) beginif (byteenable [0]) clock_divide_reg [7: 0] = writedata [7: 0]; If (byteenable [1]) response [] = writedata []; If (byteenable [2]) clock_divide_reg [] = writedata []; If (byteenable [3]) clock_divide_reg [31: 24] = writedata [31: 24]; endendend // write the PWM cycle duty cycle register always @ (posedge CLK or negedge reset_n) beginif (reset_n = 1 'b0) duty_cycle_reg = 0; elsebeginif (write & chipselect & duty_cycle_reg_selected) beginif (byteenable [0]) duty_cycle_reg [7: 0] = writedata [7: 0]; If (byteenable [1]) response [] = writedata []; If (byteenable [2]) duty_cycle_reg [] = writedata []; If (byteenable [3]) duty_cycle_reg [31: 24] = writedata [31: 24]; endendend // write control register always @ (posedge CLK or negedge reset_n) beginif (reset_n = 1 'b0) control_reg = 0; elsebeginif (write & chipselect & control_reg_selected) beginif (byteenable [0]) control_reg = writedata [0]; endendend // read register always @ (address or read or clock_divide_reg or register or control_reg or chipselect) beginif (read & chipselect) Case (Address) 2 'b00: readdata <= clock_divide_reg; 2 'b01: readdata <= duty_cycle_reg; 2 'b10: readdata <= control_reg; default: readdata = 32' h8888; endcaseend // control register assign pwm_enable = control_reg; // PWM function part always @ (posedge CLK or negedge reset_n) beginif (reset_n = 1 'b0) pwm_counter = 0; elsebeginif (pwm_enable) beginif (pwm_counter> = counter) pwm_counter <= 0; elsepwm_counter <= pwm_counter + 1; endelsepwm_counter <= 0; endend always @ (posedge CLK or negedge reset_n) beginif (reset_n = 1 'b0) pwm_out <= 1 'b0; elsebeginif (pwm_enable) beginif (pwm_counter <= counter) pwm_out <= 1 'b1; elsepwm_out <= 1 'b0; consumed <= 1 'b0; endendendendmodule
After the above program is saved, name it PWM. V and save it to the project directory.
Hardware settings
Next, we will establish the PWM module through the embedded system (FPGA) builder. First, open the Quartus software and enter the FPGA builder. After entering, click the Red Circle
Click Next, as shown in,
Click, as shown in, and click the Red Circle to add the PWM. V we just created. (I will use PWM. V is stored in the PWM folder under the project directory)
After being added, the system analyzes the PWM. V file, as shown in. The text in the red circle appears, indicating that the analysis is successful. Click Close to close the dialog box.
Click Next, as shown in. We can see that all signals in PWM. V appear here. We can configure these signals according to our functional requirements. Among them, the interface is the aveon interface type, which includes aveon-mm, aveon-ST, aveon memory mapped tristate interface, and so on. Signal type refers to the signal types under each aveon interface type. We have already introduced the signals in PWM. V. You can set them according to the above requirements. By default, only pwm_out needs to be changed, as shown in red circles,
Select the Red Circle option from the drop-down menu.
After setting all the options above, click Next, as shown in. We pull down from the Red Circle
Pull to the position shown to stop. We will change the Red Circle to native, which is the address alignment option. We choose static address alignment. The default value is used elsewhere, and no changes are required.
There are also many options here. The timing part should be noted that the clock signal of the PWM avron slave port is synchronized with the avron slave port, and the retention time of the read/write port is 0, because the read and write registers only require one clock cycle, the read/write latency is not required for 0 waiting for switching.
Click Next, as shown in. Note that you can create a new group in the red circle and then display it in the system builder.
After you click Finish, the following dialog box is displayed. Click Yes to generate a pwm_h1_tcl script file. You can open it and check the configuration information we Just configured When configuring PWM.
After the above steps are completed, we return to the embedded system builder interface. We can find the red circle shown in the left sidebar.
As you can see, myip is the group we just created. Double-click PWM to create the PWM module, as shown in figure
Click Finish to complete the creation.
You also need to set one step here. Click the Red Circle
Click, as shown in, click IP serarch path, and then click Add to add the path where PWM. V is located.
As shown in
Click Finish. Set this option to enable the system builder to find the position of PWM. v. Otherwise, the problem that the PWM module is invalid the next time you enter the system-wide system-based system.
The next step is to automatically allocate addresses, allocate interruptions, compile, and wait ......
After compilation, we return to the Quartus software interface. We can see that the PWM has appeared and I have connected it to an LED. We can change the LED brightness through PWM, the process of LED fading out.
Next, compile again. Wait .....
After completing the hardware work, we open the nioside and start the software programming section.
Software Development
First Re-compile the project, ctril + B, wait ......
After compilation, let's take a look at the changes in system. H. We can find that the PWM part is added.
Below is the PWM TestCode,
#include
# include "system. H "// according to the register offset, we define a struct pwmtypedef struct {volatile unsigned int divi; volatile unsigned int duty; volatile unsigned int enable;} PWM; int main () {int dir = 1; // point the PWM to the first address of pwm_0_base PW. M * PWM = (PWM *) pwm_0_base; // initializes the PWM. The maximum value of divi is 232-1. PWM-> divi = 1000; PWM-> duty = 0; PWM-> enable = 1; // change the duration of a LED cycle by constantly changing the duty value while (1) {If (dir> 0) {If (PWM-> duty
divi) PWM-> duty + = 100; else dir = 0;} else {If (PWM-> duty> 0) PWM-> duty-= 100; else dir = 1;} usleep (100000);} return 0 ;}
here, the content of this section is finished, if you have any questions, you can leave a message for me, you can also through QQ: 984597569, or email: avic633@gmail.com to contact me, thank you!