1842 views|1 replies

13

Posts

0

Resources
The OP
 

[AG32VF407 Review] Developing Customized LED Peripherals for AG32VF407 Based on FPGA [Copy link]

 This post was last edited by lenxvp on 2023-9-3 08:03

The most powerful function of this chip is to customize AG32VF407 with FPGA.

The difference from the previous article [AG32VF407 Review] FPGA Project Initial Exploration of Using FPGA to Control GPIO is that the FPGA logic implemented in this article can be controlled by the MCU, while in the previous article the MCU was not involved in the control and the LED was completely controlled by the FPGA logic.

Let's first clarify several types of IP. This only represents my own understanding and has nothing to do with the official. If it is wrong, please correct me.

First of all, let’s talk about the chip IP. I haven’t figured out whether AG32VF407 is an independent IP core outside the FPGA chip or a hard core or soft core implemented on the FPGA. This is related to whether modifying the FPGA logic will cover the chip core. My general understanding is that it should be a RISC-V hard core + FPGA structure similar to Zynq. The hard core structure is fixed and cannot be modified, that is, modifying the FPGA logic will not delete the MCU logic. With this chip IP, we can develop its software like an ordinary MCU.

Then there are several predefined IPs provided by the official, that is, IPs made by the official that are independent of the chip IP. They can be understood as detachable peripherals. These IPs are optional functions provided by the official. At present, I understand that there are two, ahb_slave and analog. There may be others, but I don’t understand them thoroughly. These predefined IPs are introduced in platformio.ini through the ip_name attribute.

Finally, there is the custom IP, which is the IP developed by our users themselves. There are two types of IP. One is the complete IP that includes the chip IP. The generated HDL file will contain the call to the chip IP. The advantage is that the chip can be predefined. For example, if we add the LED flashing logic to it, then when we download the logic to the chip, the LED will flash automatically without software conversion of the chip.

There is also a kind of IP officially called portable IP, which does not include chip IP. Like the predefined IP above, it is equivalent to an expandable function package. The advantage is that it is decoupled from the MCU and can focus on the development of customized peripherals without causing unnecessary impact on the MCU. In the following example, we use portable IP to develop a simple customized LED peripheral.

The following examples are based on the document "agrv2k Logic Setup - .pdf" and the official ahb_slave example. The document can be found in the AGM32 peripharals feature document. ahb_slave is in the examples directory of the source code.

1. Project preparation

Create a new directory called ip_led, copy the platformio.ini, top.ve files and src directory from the ahb_slave directory to this directory, and then open this directory with vs_code

Clear top.ve and add the following content. LED_OUT is the LED pin controlled by our LED controller. OUTPUT means that the pin is output.

SYSCLK 120

HSECLK 8

LED_OUT PIN_32:OUTPUT # LED1

Open and modify platformio.ini, mainly modify the ip_name attribute to ip_led, and add the logic_ip = true attribute to make it a portable IP

Then use the platformio command to generate the FPGA project. Click the platformio icon in the right column of VS_Code and select release - Custom - Prepare IP.

After completion, the logic folder will be automatically generated. Use quartus to open the ip_led.qpf project file in the logic folder. Now we can develop our custom peripherals.

2. Customize LED peripheral logic

Let's first implement some simple LED peripheral functions. For peripherals on the MCU, most of the time we control them through registers. Common registers include control, status, and parameters. Let's first define a register structure for LED peripherals, as follows:

struct LED_Typedef
{
  uint32_t ctrl;    // 控制寄存器
  uint32_t status;  // 状态寄存器
  uint32_t period;  // PWM周期寄存器
  uint32_t duty;    // PWM占空比寄存器
};

The above are the four registers we need to implement on the FPGA logic. The address width of AG32VF407 is 32, so we also use 32-bit registers. In the ctrl control register, we use three bits to control the LED peripheral function.

Bit[0] is the peripheral enable bit. Setting it to 1 enables the LED peripheral. Bit[1] is the output mode. 0 uses pure level and 1 uses PWM. Bit[2] sets the current output level of the LED pin.

The status register only uses bit[0] to indicate the current level of the LED pin. Peroid and duty are only used in PWM mode, and the bit width is 32 bits.

Before introducing the HDL code of LED peripherals, we also need to briefly understand the protocols for interaction between MCU and FPGA, namely AHB and APB protocols. They are part of the AMBA bus specification launched by ARM. You can download its specification document for free on the ARM official website. These protocols are communication protocols between chips. AHB is used for high-speed peripherals and APB is used for low-speed peripherals. From a structural point of view, MCU can directly access AHP, while APB needs to be transferred through AHB. In our IP, for convenience, we directly use AHB protocol instead of APB. Even if our LED peripherals should belong to low-speed peripherals, there are many specific protocol contents of AHB, which will not be expanded here. Those who are interested can study it by themselves.

Those who are familiar with ARM chip development should know that we access peripherals through a memory address. Similarly, we also need to map our LED peripherals to an address that can be accessed by the AHP protocol. The memory mapping description can be found in the AG32VF407 Datasheet document. External AHB is used to expand the memory address space. Using this address will not conflict with existing peripherals. Our LED peripherals directly use the address 0x60000000 as the peripheral address.

After determining the register and memory address, you can proceed with FPGA logic development. First, provide a general development idea

First of all, we need to connect to the AHB protocol for communication with the MCU. We can learn about the use of the AHB protocol by studying the ahb_slave example. Our peripheral is an AHB slave and needs to respond to the host according to the protocol requirements. According to the address and data transmitted by AHB, we determine the register that the host wants to access and perform corresponding processing.

Then the host's register settings are reflected in the peripheral function. For our LED peripheral, it is to set the state of the LED pin and generate PWM timing according to the parameters set in the PWM related registers.

Finally, the status of the peripheral is synchronized to the status register. If the peripheral has DMA and interrupt functions, corresponding processing is required.

My code mainly includes three files, that is, three main modules. The top-level one is the ip_led module, which is responsible for connecting to the AHB protocol and parsing the register address. The led_ctrl module is responsible for the main behavior logic of the LED peripherals. The pwm module mainly generates the PWM timing. The specific code will be given at the end of the post. The code itself is not complicated, but you need to be familiar with the development logic of FPGA.

After the code is written, simply compile it on quartus to check for errors. The formal compilation is in supra software. You can refer to the previous article and open the project for compilation. Note that the project opened by supra is actually in the logic directory.

After compiling, go to VS_Code, compile it first, then use Update_Logic to solidify the hardware logic on the chip, and then we develop an example to operate our LED peripherals

3. Software Development

Write the following code in src/main.c

#include "board.h"

struct LED_Typedef
{
  uint32_t ctrl;    // 控制寄存器
  uint32_t status;  // 状态寄存器
  uint32_t period;  // PWM周期寄存器
  uint32_t duty;    // PWM占空比寄存器
};

int main(void)
{
  // uint32_t status ;
  // This will init clock and uart on the board
  board_init();

  struct LED_Typedef *LED= (struct LED_Typedef*)MMIO_BASE;

  // LED->period = 120 * 1000;
  // LED->duty = 30 * 1000;
  LED->ctrl = 0x01U;


  while (1) {
    UTIL_IdleUs(100e3);
    LED->ctrl = 0x01U;
    UTIL_IdleUs(100e3);
    LED->ctrl = 0x05U;
    // status = LED->status;
  }
}

Here we use the LED peripheral to control the LED light on the board to flash. Compile and download, and you can see the LED flashing.

Here I also tested the status register reading and PWM mode, but it was not successful. The FPGA code is not perfect yet, and I will make modifications later when I have time.

The following project files ip_led.zip (7.37 MB, downloads: 39)
This post is from Domestic Chip Exchange

Latest reply

My PWM mode is turned on. You defined the period_r reg but did not use it. You need to compare it with period_cnt, then set period_cnt to zero and start counting again.   Details Published on 2023-9-22 11:41
 
 

1

Posts

0

Resources
2
 

My PWM mode is turned on. You defined the period_r reg but did not use it. You need to compare it with period_cnt, then set period_cnt to zero and start counting again.

This post is from Domestic Chip Exchange
 
 
 

Just looking around
Find a datasheet?

EEWorld Datasheet Technical Support

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号
快速回复 返回顶部 Return list