An example of getting started with ZYNQ -- timer interruption and program solidification

Keywords: Verilog SDK REST

I. Preface

In the APU system, the CPU performs the operation in the way of serial code execution, and the software mode is difficult to achieve accurate timing, so it is a better choice to call the internal timer hardware to complete timing. In this paper, timer interrupt control LED periodic flicker as an example to learn the use of private timer. At the same time, learn how to solidify the software program and the hardware bitstream file into the SD card, and realize the power on automatic configuration and start the custom system.

Function definition: the level of single LED connected with MIO changes in turn every 200ms through timer interruption, that is, it is on, it is off after 200ms, it is on again after 200ms, and the cycle is reciprocating.

Hardware platform: milianz702n

Software tool: VIVADO 2017.4+SDK

2, Hardware system construction

The private timer belongs to the special hardware resource in APU, and does not need to be configured in VIVADO. Due to the need to solidify the hardware and software system into the SD card, I/O connected to the SD controller is selected.

According to the schematic diagram, SD card is connected in mio40-47, which is also consistent with the description in UG585:

In this paper, we use PWM directly to produce the hardware system of the respiratory lamp effect engineering. We can more intuitively observe that the timer control LED and PWM control LED do not affect each other.

It is still to regenerate output files, generate HDL Wrapper, RUN Synthesis, Run Implementation, Generate bitstream, export Hardware with bitfile, Launch SDK. The rest of the tasks are completed in the SDK.

Three, software design

xilinx also provides documentation and sample programs on how to use private timers.

The timer related functions used in the software code are all from the sample program. The first step of using the private timer is to initialize the configuration of course. The old routine calls two functions, xscutimer? Lookupconfig and xscutimer? Cfginitialize. In order to ensure the periodic flashing of LED, it is necessary to enable the automatic overload of timer, so that the counter will be re counted every time the counter counting is completed. The most important thing is to write the count cycle value to the timer load register. In fact, the private timer is a decrement counter. When the maximum value is decremented to 0, timer interrupt will occur. For example, and convert the time length to be timed to the cycle value of the load counter?

Simply, n=t/T=t*f can calculate the loading value, where N, t and t refer to the time to be timed and the working clock period of the timer respectively. Because the working clock frequency of timer is always half of that of CPU, which is 333MHz in this system. This n = 200 * 10 ^ (- 3 * 333 * 10 ^ 6 = 666 * 10 ^ 5. The counter is a counting mode of N-1~0, and the loading value is minus 1 on the basis of N, and the corresponding hex value is 0x3F83C3F.

When the load is completed, the XScuTimer_Start timer is invoked. Finally, in the timer interrupt callback function, the MIO can be reversed to meet the functional expectations. In addition, some improvements have been made to the project of realizing the effect of breathing lamp by PWM. The software program is as follows:

  1 /*
  2  * main.c
  3  *
  4  *  Created on: 2020 February 22nd 2013
  5  *      Author: s
  6  */
  7 
  8 
  9 #include "environment.h"
 10 
 11 
 12 
 13 int main()
 14 {
 15     int Status;
 16     u8 i=0;
 17 
 18     freq_step_value = 10;
 19 
 20     Status = gpiops_initialize(&GpioPs,GPIOPS_DEVICE_ID);
 21     if (Status != XST_SUCCESS) {
 22         return XST_FAILURE;
 23     }
 24 
 25     Status = gpio_initialize(&Gpio,GPIO_DEVICE_ID);
 26     if (Status != XST_SUCCESS) {
 27         return XST_FAILURE;
 28     }
 29 
 30     Status = timer_initialize(&TimerInstance,TIMER_DEVICE_ID);
 31     if (Status != XST_SUCCESS) {
 32         return XST_FAILURE;
 33     }
 34     /*
 35      * Set the direction for the pin to be output and
 36     * Enable the Output enable for the LED Pin.
 37      */
 38     gpiops_setOutput(&GpioPs,MIO_OUT_PIN_INDEX);
 39 
 40     for(i=0;i<LOOP_NUM;i++){
 41         gpiops_setOutput(&GpioPs,EMIO_OUT_PIN_BASE_INDEX+i);
 42     }
 43 
 44     gpio_setDirect(&Gpio, 1,GPIO_CHANNEL1);
 45 
 46     Status = setupIntSystem(&Intc,&Gpio,&TimerInstance,
 47             INTC_GPIO_INTERRUPT_ID,TIMER_IRPT_INTR);
 48     if (Status != XST_SUCCESS) {
 49             return XST_FAILURE;
 50         }
 51 
 52     /*
 53     * Enable Auto reload mode.
 54     */
 55     XScuTimer_EnableAutoReload(&TimerInstance);
 56 
 57     /*
 58     * Load the timer counter register.
 59     */
 60     XScuTimer_LoadTimer(&TimerInstance, TIMER_LOAD_VALUE);
 61 
 62     /*
 63      * Start the timer counter and then wait for it
 64     * to timeout a number of times.
 65     */
 66     XScuTimer_Start(&TimerInstance);
 67 
 68 
 69 
 70     Status = pwm_led_setFreqStep(freq_step_value);
 71     if (Status != XST_SUCCESS) {
 72             return XST_FAILURE;
 73         }
 74 
 75     printf("Initialization finish.\n");
 76 
 77     while(1){
 78 
 79         for(i=0;i<LOOP_NUM;i++){
 80             if(int_flag == 0)
 81             {
 82                 gpiops_outputValue(&GpioPs, EMIO_OUT_PIN_BASE_INDEX+i, 0x1);
 83                 usleep(200*1000);
 84                 gpiops_outputValue(&GpioPs, EMIO_OUT_PIN_BASE_INDEX+i, 0x0);
 85             }
 86             else
 87             {
 88                 gpiops_outputValue(&GpioPs, EMIO_OUT_PIN_BASE_INDEX+LOOP_NUM-1-i, 0x1);
 89                 usleep(200*1000);
 90                 gpiops_outputValue(&GpioPs, EMIO_OUT_PIN_BASE_INDEX+LOOP_NUM-1-i, 0x0);
 91             }
 92         }
 93 
 94 
 95     }
 96     return 0;
 97 }
 98 
 99 
100 
101 int setupIntSystem(XScuGic *IntcInstancePtr,XGpio *gpioInstancePtr,
102         XScuTimer * TimerInstancePtr,u32 gpio_IntrId,u32 timer_IntrId)
103 {
104     int Result;
105     /*
106     * Initialize the interrupt controller driver so that it is ready to
107     * use.
108     */
109 
110     Result = gic_initialize(&Intc,INTC_DEVICE_ID);
111     if (Result != XST_SUCCESS) {
112             return XST_FAILURE;
113         }
114 
115     XScuGic_SetPriorityTriggerType(IntcInstancePtr, gpio_IntrId,
116                         0xA0, 0x3);
117 
118     /*
119     * Connect the interrupt handler that will be called when an
120      * interrupt occurs for the device.
121      */
122     Result = XScuGic_Connect(IntcInstancePtr, gpio_IntrId,
123                 (Xil_ExceptionHandler)GpioHandler, gpioInstancePtr);
124     if (Result != XST_SUCCESS) {
125         return Result;
126     }
127 
128     Result = XScuGic_Connect(IntcInstancePtr, timer_IntrId,
129                     (Xil_ExceptionHandler)TimerIntrHandler,
130                     (void *)TimerInstancePtr);
131     if (Result != XST_SUCCESS) {
132             return Result;
133         }
134 
135     /* Enable the interrupt for the GPIO device.*/
136     XScuGic_Enable(IntcInstancePtr, gpio_IntrId);
137 
138     /*
139      * Enable the GPIO channel interrupts so that push button can be
140     * detected and enable interrupts for the GPIO device
141     */
142     XGpio_InterruptEnable(gpioInstancePtr,GPIO_CHANNEL1);
143     XGpio_InterruptGlobalEnable(gpioInstancePtr);
144 
145     /*
146     * Enable the interrupt for the device.
147     */
148     XScuGic_Enable(IntcInstancePtr, timer_IntrId);
149     XScuTimer_EnableInterrupt(TimerInstancePtr);
150 
151     /*
152     * Initialize the exception table and register the interrupt
153     * controller handler with the exception table
154     */
155     exception_enable(&Intc);
156 
157     IntrFlag = 0;
158 
159     return XST_SUCCESS;
160 }
161 
162 void GpioHandler(void *CallbackRef)
163 {
164     XGpio *GpioPtr = (XGpio *)CallbackRef;
165     u32 gpio_inputValue;
166 
167 
168     /* Clear the Interrupt */
169     XGpio_InterruptClear(GpioPtr, GPIO_CHANNEL1);
170     printf("gpio interrupt.\n");
171 
172     //IntrFlag = 1;
173     gpio_inputValue = gpio_readValue(GpioPtr, 1);
174     switch(gpio_inputValue)
175     {
176     case 30:
177         //printf("button up\n");
178         usleep(5);
179         gpio_inputValue = gpio_readValue(GpioPtr, 1);
180         if(gpio_inputValue == 30){
181             freq_step_value = freq_step_value < FREQ_STEP_MAX ?
182                     freq_step_value+10 : freq_step_value;
183             printf("%d\n",freq_step_value);
184             pwm_led_setFreqStep(freq_step_value);
185         }
186         break;
187     case 29:
188         //printf("button center\n");
189         usleep(5);
190         gpio_inputValue = gpio_readValue(GpioPtr, 1);
191         if(gpio_inputValue == 29){
192             freq_step_value = FREQ_STEP_SET_VALUE;
193             pwm_led_setFreqStep(freq_step_value);
194         }
195         break;
196     case 27:
197         //printf("button left\n");
198         usleep(5);
199         gpio_inputValue = gpio_readValue(GpioPtr, 1);
200         if(gpio_inputValue == 27)
201             int_flag = 0;
202         break;
203     case 23:
204         //printf("button right\n");
205         usleep(5);
206         gpio_inputValue = gpio_readValue(GpioPtr, 1);
207         if(gpio_inputValue == 23)
208             int_flag = 1;
209         break;
210     case 15:
211         //print("button down\n");
212         usleep(5);
213         gpio_inputValue = gpio_readValue(GpioPtr, 1);
214         if(gpio_inputValue == 15){
215             freq_step_value = freq_step_value > FREQ_STEP_MIN ?
216                     freq_step_value-10 : freq_step_value;
217             printf("%d\n",freq_step_value);
218             pwm_led_setFreqStep(freq_step_value);
219         }
220         break;
221     }
222 
223 }
224 
225 void TimerIntrHandler(void *CallBackRef)
226 {
227     XScuTimer *TimerInstancePtr = (XScuTimer *) CallBackRef;
228 
229     XScuTimer_ClearInterruptStatus(TimerInstancePtr);
230 
231     gpiops_outputValue(&GpioPs, MIO_OUT_PIN_INDEX, sys_led_out);
232     sys_led_out  = sys_led_out == 0x0 ? 0x1 : 0x0;
233 }
main.c
 1 /*
 2  * timer.h
 3  *
 4  *  Created on: 2020 March 5th 2013
 5  *      Author: s
 6  */
 7 
 8 #ifndef SRC_TIMER_H_
 9 #define SRC_TIMER_H_
10 
11 #include "xscutimer.h"
12 
13 #define TIMER_DEVICE_ID        XPAR_XSCUTIMER_0_DEVICE_ID
14 #define TIMER_IRPT_INTR        XPAR_SCUTIMER_INTR
15 
16 //333*n(ms)*10^3-1 = 333*5*1000-1 = 1664999 0x1967E7
17 #define TIMER_LOAD_VALUE    0x3F83C3F
18 
19 int timer_initialize(XScuTimer * TimerInstancePtr,u16 TimerDeviceId);
20 
21 
22 #endif /* SRC_TIMER_H_ */
timer.h
 1 /*
 2  * timer.c
 3  *
 4  *  Created on: 2020 March 5th 2013
 5  *      Author: s
 6  */
 7 
 8 
 9 #include "timer.h"
10 
11 int timer_initialize(XScuTimer * TimerInstancePtr,u16 TimerDeviceId)
12 {
13     XScuTimer_Config *ConfigPtr;
14     /*
15     * Initialize the Scu Private Timer driver.
16     */
17     ConfigPtr = XScuTimer_LookupConfig(TimerDeviceId);
18 
19     /*
20     * This is where the virtual address would be used, this example
21     * uses physical address.
22     */
23     return XScuTimer_CfgInitialize(TimerInstancePtr, ConfigPtr,
24                     ConfigPtr->BaseAddr);
25 }
timer.c

Compared with the original program, the GpioHandler is added with the limitation of the maximum value of freq ﹣ step ﹣ value and the delay of key chattering.

4, Program curing

The FAT file system shall be used for the curing program of the project, the board level support package settings shall be changed, the xilffs library shall be checked and the BSP shall be regenerated.

Before curing the program, it is very necessary to understand the CPU startup process. This part of the concept mainly comes from the UG585 document. After power on reset, the hardware logic will select the start mode according to the high and low level of the start mode pin.

After some hardware initialization operations, execute the code in a ROM inside the CPU to start the whole system. The name of this ROM is BootROM. The program in BootROM is the first code executed by CPU. Its main task is to configure the system, copy the system image from boot device to OCM, and configure DDR operation.

Boot device can be Quad SPI, NAND, nor or SD card. Boot device stores boot image, which is composed of BootROM Header, FSBL and User Code. It can also include bitstream and software OS used to configure PL. Software boot is divided into three stages:

FSBL plays an organizational role, combining the ELF files generated by PS software and the bit files of PL hardware. The file is generated by xilinx's FSBL example project, and users do not need to pay attention to the internal implementation details.

The ELF file is automatically compiled and generated after the project is created. Click Xilinx - > create boot image. Add three files in the following order: fsdb.elf -- > bit -- >

After creating the image, the corresponding bin file will be generated, that is, the boot image described earlier.

We copy the BOOT.bin file to the empty SD card and use the dial switch to configure Boot Mode MIO Strapping Pins to start from the SD card. After power on, wait for a period of time for the LED lamp connected with MIO to flicker periodically. The frequency of PWM breathing lamp and the direction of running water lamp are changed according to the key, the system works normally, and the timer interrupt application and program curing are completed.

Posted by shumway on Sun, 08 Mar 2020 04:30:32 -0700