FreeRTOS 10.4.3 porting process on a RISCV platform

A good memory is not as good as a bad pen. It is easy to summarize and refine on the one hand to record the transplantation experience, and on the other hand, to share, so that others can avoid some detours.

First of all sort out the transplant framework. FreeRTOS is still very simple. It is much lighter than heavy-duty systems such as RT-Thread and Nuttx. Therefore, FreeRTOS is generally not used in heavy-duty solutions with MMU. More applications are in industries such as industry. Embedded applications such as control or home appliances.

The overall transplantation framework is as follows:

Let's talk about the specific transplantation steps:

  1. Set up the build environment, prepare to use the already built environment on melis, and borrow "chickens". The goal is to transplant the FreeRTOS system, so this part is not focused on recording. In short, the environment has been built.
  2. Do you use sbi for the time being, and optimize it later, because compared with Melis, the system built by FreeRTOS is much simpler. Without supporting MMU, the entire FreeRTOS system plus applications can run in M ​​mode, and sbi will lose its existence. Necessary, but decided to keep it first and optimize it after the transplant is complete. There are three main considerations. 1. There are dependencies between the environment and sbi, including link scripts, some compilations, etc. I don’t want to touch it at this time. 2. SBI itself provides some vendor extension interfaces. These things are not certain for the time being. It won't be used. If it is omitted, it can be added back in some form in case of need, which is troublesome. So temporarily start with SBI, and then gradually do subtraction. 3. Use the encapsulated serial port driver in sbi to start the minimum system. To start with SBI, you need to make some minor modifications to the SBI firmware, the changes are as follows:
    1. diff --git a/firmware/fw_jump.S b/firmware/fw_jump.S
      index afbcec0..79b3de8 100644
      --- a/firmware/fw_jump.S
      +++ b/firmware/fw_jump.S
      @@ -84,7 +84,7 @@ fw_next_addr:
               * The next address should be returned in 'a0'
               */
       fw_next_mode:
      -       li      a0, PRV_S
      +       li      a0, PRV_M
              ret
      

      Modify the implementation of fw_next_addr, and use the returned next status to be PRV_M, that is, the next stage is M-Mode, S-Mode that is not run by Linux and Melis. The verification is as follows: 0x40010600 is the OS _star address, you can correctly jump out of SBI and enter this Address, indicating that the next CPU boot can be performed.  ,

    2. The following figure represents the open state of the current processor functional components. You can see that the I/D cache and PMU related mechanisms have been turned on.

      1.  mxstatus bit 30 bit 31 is 0b11, indicating that the system is running in machine mode.

  3. Develop the link script to determine the layout distribution of the ELF file after the final link. MMU is not enabled, so VA=PA as a whole, as shown in the figure below:
  4. Considerations about the start-up process
    1. All ISA-defined registers are in a certain state, including GPRS and FPU.
    2. Initialize the TLB, but the M mode does not access the page table. This is to access the high memory address in the S mode, because after mapping through the MMU, the physical memory can access 40 bits, not just the 39 bits defined by the VPA.
    3. Since the page table is built in the TLB, not in the memory, the TLB is initialized directly here. The page table in the TLB cannot be flushed out because the physical memory has no page table entries. (This is easy to meet, the mapping and access range is less than the TLB The capacity that can be mapped, TLB entries will not be swapped out, of course, if there is a TLB lock option, it will be more guaranteed.)
    4. Different from the frightening access of the Linux kernel to the FPU, in order to make FreeRTOS run at full speed, we are going to fully support the acceleration of the kernel FPU unit, and use SR_SD to indicate the state of the FPU register set to achieve lazy save/restore. (Use -mabi=lp64d or -mabi= lb64v compilation, linux kernel can only be compiled with -mabi=lp64, user mode only has the choice),
    5. Initialize the bringup stack and fill it with "ebreak" instructions to prevent accidents.
    6. The parameters passed to the kernel include startup time, the location of misa and sbi, which will be optimized by SBI later.

      1.  
  5. If you want to do your job well, you must first sharpen your tools. Regarding printing, after entering c, the most you want to see is printing. The efficiency of debugging and assembly for every problem is still relatively low. Here we are going to use the printf printing function in newlibc, and the bottom layer will connect _write_r to the debugged serial port driver in sbi. I encountered an episode in the middle. When I called printf for output, I actually entered the exception handle_exception. The analysis found that the original _write_r was used in the SBI package in the S mode, and the ecall instruction was called. This method is certainly possible in the S mode, but the problem is that we are going to run FreeRTOS in the M mode, so the program itself It runs in M ​​mode like SBI, and the mtvec register of M mode has been modified to a new handle_exception in the above process. Of course, SBI requests will not be processed here. The solution is to call SBI based on the "ecall" instruction Modified to directly call the sbi function. The analysis process is shown in the figure below:
    1. Force to stop at the entrance of handle_exceptions, print mepc,
    2. Found that mepc points to 0x4001b65a, decompile the elf file to find the corresponding location, and find that it is the "ecall" instruction:
    3.  Transplant the print driver in SBI into the system, get:
  6. Set the timer and use the built-in clic arch timer. This timer is driven by an external 24M crystal oscillator and can be used directly. Later, it will be used as the interrupt source of the system heartbeat to drive periodic scheduling.
  7. Develop the arch timer interrupt function, use the compare and value register in clic as the clock heartbeat source, and the value is driven by 24M. When the value and compare are equal, the interrupt is triggered. At this time, the compare of the next trigger point needs to be set in the interrupt processing. Value, the increment calculation method is 24000000/CONFIG_HZ, that is, the number of cycles between every two interrupts. First of all, refer to the linux approach to enable the Timer interrupt and External interrupt capability of the Machine Mode in trap_init.
  8. Turn on the clic arch timer. Note that the Mtime and Compare registers are similar to the tick generation mechanism in MIPS. This is the design of SIFive, and many vendors follow.
  9. The complete flow of the segment is shown in the figure below, and the last step triggers the scheduler:
  10. The interfaces that need to be customized include  xPortStartScheduler, pxPortInitialiseStack, vPortSetupTimerInterrupt, xPortStartFirstTask four interfaces, pay attention to the connection of the arch timer interrupt.
  11.  Context layout of the task scheduling site:
  12. Implement portasmHANDLE_INTERRUPT, vPortSetupTimerInterrupt definition, used to enable timer interrupt and peripheral interrupt processing interface, configCPU_CLOCK_HZ, configTICK_RATE_HZ set tick interrupt cycle
  13. Realize exception and interrupt handling, and hook the above-mentioned timer interrupt interface and peripheral interrupt interface to the exception handling process.
  14. Note that the stack organization at the interrupt site is the same as the stack organization at the task scheduling site, and it is also consistent with the stack layout when the task is initialized. Since preemption scheduling and active scheduling are both entered through an abnormal path, the processing in freeRTOS is very Consistent, there is no need to distinguish whether it is an interrupt dispatch site or a dispatch site where tasks are actively transferred, as shown in the following figure:

The main scheduler scheduling logic:

15: Transplantation results:

Summary: Regarding T-HEAD ICE, I have used many ICEs before. I feel that there is one thing in common, that is, a XILINX FPGA is built into many higher-cost ICE emulators. The main function of ICE is to convert PC debugging instructions to JTAG. For timing signals, there are many off-the-shelf conversion chips such as FT232, XILINX also play a role in protocol conversion, but FPGA logic will disappear when power is off. How does ICE ensure that the debugging logic does not disappear? After communicating with colleagues, I learned that there is generally a Flash or EEPROM built into the ICE to store the solidified logic, similar to the bitfile used in the FPGA physical verification phase. Each time the FPGA is powered on, the bitfile design logic will be loaded from the EEPROM. However, it is a bit nonsense that although CKLink Pro uses XINLINX FPGA as the main control, CKLink Lite is surprisingly saving and only uses STM32 as the main control. From the price, we can also see the obvious difference between the two, the former is Taobao 1200, the latter is only 200, the main control is changed, and 1,000 yuan is out.

end!

Guess you like

Origin blog.csdn.net/tugouxp/article/details/113111847