ZYNQ学习 GPIO
EMIO (1)什么是EMIO?
PS与PL端之间的接口,EMIO是扩展的MIO,当PS端的引脚不够用的时候,可以通过EMIO进行扩展,使用PL端的引脚
(2)如何使用MIO的输入?
XGpioPs_SetDirectionPin(&gpiops_inst, MIO_KEY, 0); 直接设置为0即可
GPIO中断 (1)中断控制器怎么确定是哪个引脚的中断?
判断INT_MASK,如果某个引脚的该寄存器被屏蔽,即该引脚没有产生中断
判断INT_STAT,如果两个引脚的INT_MASK都没有被屏蔽,就判断INT_STAT,某个引脚该寄存器拉高,即该引脚产生中断
(2)中断配置代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 void SetupInterruptSystem (XScuGic *GicInstancePtr, XGpioPs *Gpio, u16 GpioIntrId) { IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID); XScuGic_CfgInitialize(GicInstancePtr, IntcConfig, IntcConfig->CpuBaseAddress); Xil_ExceptionInit(); Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, GicInstancePtr); XScuGic_Enable(GicInstancePtr, GpioIntrId); Xil_ExceptionEnableMask(); XScuGic_Connect(GicInstancePtr, GpioIntrId, (Xil_ExceptionHandler)IntrHandler, (void *)Gpio); XGpioPs_SetIntrTypePin(Gpio, MIO_KEY, XGPIOPS_IRQ_TYPE_EDGE_FALLING); XGpioPs_IntrClearPin(Gpio, MIO_KEY); XGpioPs_IntrEnablePin(Gpio, MIO_KEY); } void IntrHandler () { printf ("IRQ Test!\n\r" ); key_press = 1 ; XGpioPs_IntrDisablePin(&gpiops_inst, MIO_KEY); }
AXI_GPIO (1)AXI_GPIO是一种由FPGA资源搭建的软核,不像PS部分的GPIO有自己的电路,AXI_GPIO没有实际的硬件电路,由用户通过PL端自行配置使用
<AXI GPIO 框架>
<编程指导>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 main函数: gpiops_cfg_ptr = XGpioPs_LookupConfig(GPIOPS_ID); XGpioPs_CfgInitialize(&gpiops_inst, gpiops_cfg_ptr, gpiops_cfg_ptr->BaseAddr); XGpio_Initialize(&AXI_Gpio, AXI_GPIO_DEVICE_ID); XGpioPs_SetDirectionPin(&gpiops_inst, MIO_LED0, 1 ); XGpioPs_SetOutputEnablePin(&gpiops_inst, MIO_LED0, 1 ); XGpio_SetDataDirection(&AXI_Gpio, GPIO_CHANNEL1, 0x00000001 ); SetupInterruptSystem(&Intc, &AXI_Gpio, AXI_GPIO_INTERRUPT_ID); void SetupInterruptSystem (XScuGic *GicInstancePtr, XGpio *AXI_Gpio, u16 AXI_GpioIntrId) { IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID); XScuGic_CfgInitialize(GicInstancePtr, IntcConfig, IntcConfig->CpuBaseAddress); XScuGic_SetPriorityTriggerType(GicInstancePtr, AXI_GpioIntrId, 0xA0 , 0x1 ); Xil_ExceptionInit(); Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, GicInstancePtr); Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ); XScuGic_Connect(GicInstancePtr, AXI_GpioIntrId, (Xil_ExceptionHandler)IntrHandler, (void *)AXI_Gpio); XScuGic_Enable(GicInstancePtr, AXI_GpioIntrId); XGpio_InterruptGlobalEnable(AXI_Gpio); XGpio_InterruptEnable(AXI_Gpio, 0x00000001 ); } void IntrHandler () { printf ("IRQ Test!\n\r" ); key_press = 1 ; XGpio_InterruptDisable(&AXI_Gpio, 0x00000001 ); }
自定义IP核 (1)基础知识参考ug1118,实操流程参考ZYNQ小系统板之嵌入式SDK开发指南
(2)自定义IP核,可以实现将模块集成到IP库中。在 Vivado 软件中,通过创建和封装 IP 向导的方式来自定义 IP 核,支持将当前工程、工程中的模块或者指定文件目录封装成 IP 核,当然也可以创建一个带有 AXI4 接口的 IP 核,用于 PS 和 PL 的数据通信。
程序固化实验
(1)ZYNQ包括PL和PS,程序固化时,不能单独固化PL的部分,PL的启动依赖于PS,因此需要固化PS再固化PL程序
(2)程序固化就是将FSBL文件、bit流文件和用户程序合成BOOT.bin文件
(3)BOOT.bin文件拷贝到SD卡,可以直接从SD卡中启动;通过JTAG将BOOT烧录到QSPI FLASH中,可以从QSPI FLASH中启动(该两种方式均不易丢失,掉电后重新上电,仍可以读取程序并运行)
UART串口中断
(1)xintc和xscugic有什么区别?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 #include "xparameters.h" #include "xuartps.h" #include "xscugic.h" #include "xil_exception.h" #include "stdio.h" #define UART_DEVICE_ID XPAR_XUARTPS_0_DEVICE_ID #define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID #define UART_INT_IRQ_ID XPS_UART0_INT_ID #define TRIGGER_LEVEL 1 #define BAUDRATE 115200 XUartPs UartPs; XScuGic InterruptController; int UART_init (XUartPs *UartInstPtr) ;int INTR_init (XUartPs *UartInstPtr, XScuGic *IntcInstPtr) ;void IntrHandler (void *CallbackRef) ;int main () { int uart_init_state = UART_init(&UartPs); if (XST_FAILURE == uart_init_state) { printf ("UART Failed!\n\r" ); return XST_FAILURE; } int intr_init_state = INTR_init(&UartPs, &InterruptController); if (XST_FAILURE == intr_init_state) { return XST_FAILURE; } while (1 ){ } return XST_SUCCESS; } int UART_init (XUartPs *UartInstPtr) { int Status; XUartPs_Config *Config; Config = XUartPs_LookupConfig(UART_DEVICE_ID); if (NULL == Config) { return XST_FAILURE; } XUartPs_CfgInitialize(UartInstPtr, Config, Config->BaseAddress); Status = XUartPs_SelfTest(UartInstPtr); if (Status != XST_SUCCESS) { return XST_FAILURE; } XUartPs_SetOperMode(UartInstPtr, XUARTPS_OPER_MODE_NORMAL); XUartPs_SetBaudRate(UartInstPtr, BAUDRATE); XUartPs_SetFifoThreshold(UartInstPtr, TRIGGER_LEVEL); return Status; } int INTR_init (XUartPs *UartInstPtr, XScuGic *IntcInstPtr) { int Status; XScuGic_Config *IntcConfig; IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID); Status = XScuGic_CfgInitialize(IntcInstPtr, IntcConfig, IntcConfig->CpuBaseAddress); if (Status != XST_SUCCESS) { return XST_FAILURE; } Xil_ExceptionInit(); Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, IntcInstPtr); Xil_ExceptionEnable(); XScuGic_Connect(IntcInstPtr, UART_INT_IRQ_ID, (Xil_ExceptionHandler)IntrHandler, UartInstPtr); XScuGic_Enable(IntcInstPtr, UART_INT_IRQ_ID); XUartPs_SetInterruptMask(UartInstPtr, XUARTPS_IXR_RXOVR); return Status; } void IntrHandler (void *CallbackRef) { u8 rev_data; u32 IsrStatus; XUartPs *uart_instance_ptr = (XUartPs *)CallbackRef; IsrStatus = XUartPs_ReadReg(uart_instance_ptr->Config.BaseAddress, XUARTPS_IMR_OFFSET); IsrStatus &= XUartPs_ReadReg(uart_instance_ptr->Config.BaseAddress, XUARTPS_ISR_OFFSET); if ((IsrStatus & (u32)XUARTPS_IXR_RXOVR) != (u32)0 ) { rev_data = XUartPs_RecvByte(uart_instance_ptr->Config.BaseAddress); XUartPs_WriteReg(uart_instance_ptr->Config.BaseAddress, XUARTPS_ISR_OFFSET, IsrStatus); } XUartPs_SendByte(uart_instance_ptr->Config.BaseAddress, rev_data); }
定时器中断 定时器简介
(1)所有的私有定时器和看门狗定时器的时钟是1/2系统时钟,也就是333.333MHz
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 #include "xparameters.h" #include "xgpiops.h" #include "xstatus.h" #include "xplatform_info.h" #include <xil_printf.h> #include "xscutimer.h" #include "xscugic.h" #define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID #define TIMER_DEVICE_ID XPAR_XSCUTIMER_0_DEVICE_ID #define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID #define TIMER_INTR_ID XPAR_SCUTIMER_INTR #define MIOLED0 7 #define TIMER_LOAD_VALUE 0x3F94067 XGpioPs Gpio; XScuTimer TimerInstance; XScuGic IntcInstance; int MIO_init () ;int TIMER_init (XScuGic *IntcInstancePtr, XScuTimer * TimerInstancePtr) ;int INTR_init (XScuGic *IntcInstancePtr, XScuTimer * TimerInstancePtr) ;void timer_intr_handler (void *CallBackRef) ;int main (void ) { print ("Timer Test\r\n" ); MIO_init (); TIMER_init (&IntcInstance, &TimerInstance); INTR_init (&IntcInstance, &TimerInstance); XScuTimer_Start (&TimerInstance); while (1 ) { } return XST_SUCCESS; } int MIO_init () { int Status; XGpioPs_Config *ConfigPtr; ConfigPtr = XGpioPs_LookupConfig (GPIO_DEVICE_ID); Status = XGpioPs_CfgInitialize (&Gpio, ConfigPtr, ConfigPtr->BaseAddr); if (Status != XST_SUCCESS) return XST_FAILURE; XGpioPs_SetDirectionPin (&Gpio, MIOLED0, 1 ); XGpioPs_SetOutputEnablePin (&Gpio, MIOLED0, 1 ); return XST_SUCCESS; } int TIMER_init (XScuGic *IntcInstancePtr, XScuTimer * TimerInstancePtr) { int Status; XScuTimer_Config *ConfigPtr; ConfigPtr = XScuTimer_LookupConfig (TIMER_DEVICE_ID); Status = XScuTimer_CfgInitialize (TimerInstancePtr, ConfigPtr, ConfigPtr->BaseAddr); if (Status != XST_SUCCESS) { return XST_FAILURE; } Status = XScuTimer_SelfTest (TimerInstancePtr); if (Status != XST_SUCCESS) { return XST_FAILURE; } XScuTimer_LoadTimer (TimerInstancePtr, TIMER_LOAD_VALUE); XScuTimer_EnableAutoReload (TimerInstancePtr); return XST_SUCCESS; } int INTR_init (XScuGic *IntcInstancePtr, XScuTimer * TimerInstancePtr) { int Status; XScuGic_Config *IntcConfig; IntcConfig = XScuGic_LookupConfig (INTC_DEVICE_ID); if (NULL == IntcConfig) { return XST_FAILURE; } Status = XScuGic_CfgInitialize (IntcInstancePtr, IntcConfig, IntcConfig->CpuBaseAddress); if (Status != XST_SUCCESS) { return XST_FAILURE; } Xil_ExceptionInit (); Xil_ExceptionRegisterHandler (XIL_EXCEPTION_ID_IRQ_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, IntcInstancePtr); Xil_ExceptionEnable (); Status = XScuGic_Connect (IntcInstancePtr, TIMER_INTR_ID, (Xil_ExceptionHandler)timer_intr_handler, (void *)TimerInstancePtr); if (Status != XST_SUCCESS) { return Status; } XScuGic_Enable (IntcInstancePtr, TIMER_INTR_ID); XScuTimer_EnableInterrupt (TimerInstancePtr); return XST_SUCCESS; } void timer_intr_handler (void *CallBackRef) { static int led_state = 0 ; XScuTimer *TimerInstancePtr = (XScuTimer *) CallBackRef; if (XScuTimer_IsExpired (TimerInstancePtr)) { XScuTimer_ClearInterruptStatus (TimerInstancePtr); XGpioPs_WritePin (&Gpio, MIOLED0, led_state); led_state = ~led_state; } }
PS XADC接口 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 #include "xparameters.h" #include "xadcps.h" #include "stdio.h" #include "sleep.h" #define XADC_DEVICE_ID XPAR_XADCPS_0_DEVICE_ID static XAdcPs XAdcInst; int ps_xadc_init (u16 XAdcDeviceId) ;void ps_xadc_print (XAdcPs *XAdcInstPtr) ;int XAdcFractionToInt (float FloatNum) ;int main (void ) { int Status; Status = ps_xadc_init(XADC_DEVICE_ID); if (Status != XST_SUCCESS) { xil_printf("adcps polled printf Example Failed\r\n" ); return XST_FAILURE; } xil_printf("Successfully ran adcps polled printf Example\r\n" ); while (1 ){ u32 TempRawData = XAdcPs_GetAdcData(&XAdcInst, XADCPS_CH_TEMP); float TempData = XAdcPs_RawToTemperature(TempRawData); printf ("The Current Temperature is %0d.%03d Centigrades.\r\n" , (int ) (TempData), XAdcFractionToInt(TempData)); sleep(1 ); } return XST_SUCCESS; } int ps_xadc_init (u16 XAdcDeviceId) { int Status; XAdcPs_Config *ConfigPtr; XAdcPs *XAdcInstPtr = &XAdcInst; ConfigPtr = XAdcPs_LookupConfig(XAdcDeviceId); if (ConfigPtr == NULL ) { return XST_FAILURE; } XAdcPs_CfgInitialize(XAdcInstPtr, ConfigPtr, ConfigPtr->BaseAddress); Status = XAdcPs_SelfTest(XAdcInstPtr); if (Status != XST_SUCCESS) { return XST_FAILURE; } XAdcPs_SetSequencerMode(XAdcInstPtr, XADCPS_SEQ_MODE_SAFE); } void ps_xadc_print (XAdcPs *XAdcInstPtr) { printf ("start the XAdc Polled Example. \r\n" ); u32 TempRawData = XAdcPs_GetAdcData(XAdcInstPtr, XADCPS_CH_TEMP); float TempData = XAdcPs_RawToTemperature(TempRawData); printf ("The Current Temperature is %0d.%03d Centigrades.\r\n" , (int ) (TempData), XAdcFractionToInt(TempData)); TempRawData = XAdcPs_GetMinMaxMeasurement(XAdcInstPtr, XADCPS_MAX_TEMP); float MaxData = XAdcPs_RawToTemperature(TempRawData); printf ("The Maximum Temperature is %0d.%03d Centigrades. \r\n" , (int ) (MaxData), XAdcFractionToInt(MaxData)); TempRawData = XAdcPs_GetMinMaxMeasurement(XAdcInstPtr, XADCPS_MIN_TEMP); float MinData = XAdcPs_RawToTemperature(TempRawData & 0xFFF0 ); printf ("The Minimum Temperature is %0d.%03d Centigrades. \r\n" , (int ) (MinData), XAdcFractionToInt(MinData)); u32 VccPintRawData = XAdcPs_GetAdcData(XAdcInstPtr, XADCPS_CH_VCCPINT); float VccPintData = XAdcPs_RawToVoltage(VccPintRawData); printf ("The Current VCCPINT is %0d.%03d Volts. \r\n" , (int ) (VccPintData), XAdcFractionToInt(VccPintData)); VccPintRawData = XAdcPs_GetMinMaxMeasurement(XAdcInstPtr, XADCPS_MAX_VCCPINT); MaxData = XAdcPs_RawToVoltage(VccPintRawData); printf ("The Maximum VCCPINT is %0d.%03d Volts. \r\n" , (int ) (MaxData), XAdcFractionToInt(MaxData)); VccPintRawData = XAdcPs_GetMinMaxMeasurement(XAdcInstPtr, XADCPS_MIN_VCCPINT); MinData = XAdcPs_RawToVoltage(VccPintRawData); printf ("The Minimum VCCPINT is %0d.%03d Volts. \r\n" , (int ) (MinData), XAdcFractionToInt(MinData)); u32 VccPauxRawData = XAdcPs_GetAdcData(XAdcInstPtr, XADCPS_CH_VCCPAUX); float VccPauxData = XAdcPs_RawToVoltage(VccPauxRawData); printf ("The Current VCCPAUX is %0d.%03d Volts. \r\n" , (int ) (VccPauxData), XAdcFractionToInt(VccPauxData)); VccPauxRawData = XAdcPs_GetMinMaxMeasurement(XAdcInstPtr, XADCPS_MAX_VCCPAUX); MaxData = XAdcPs_RawToVoltage(VccPauxRawData); printf ("The Maximum VCCPAUX is %0d.%03d Volts. \r\n" , (int ) (MaxData), XAdcFractionToInt(MaxData)); VccPauxRawData = XAdcPs_GetMinMaxMeasurement(XAdcInstPtr, XADCPS_MIN_VCCPAUX); MinData = XAdcPs_RawToVoltage(VccPauxRawData); printf ("The Minimum VCCPAUX is %0d.%03d Volts. \r\n" , (int ) (MinData), XAdcFractionToInt(MinData)); u32 VccPdroRawData = XAdcPs_GetAdcData(XAdcInstPtr, XADCPS_CH_VCCPDRO); VccPintData = XAdcPs_RawToVoltage(VccPdroRawData); printf ("The Current VCCPDDRO is %0d.%03d Volts. \r\n" , (int ) (VccPintData), XAdcFractionToInt(VccPintData)); VccPdroRawData = XAdcPs_GetMinMaxMeasurement(XAdcInstPtr, XADCPS_MAX_VCCPDRO); MaxData = XAdcPs_RawToVoltage(VccPdroRawData); printf ("The Maximum VCCPDDRO is %0d.%03d Volts. \r\n" , (int ) (MaxData), XAdcFractionToInt(MaxData)); VccPdroRawData = XAdcPs_GetMinMaxMeasurement(XAdcInstPtr, XADCPS_MIN_VCCPDRO); MinData = XAdcPs_RawToVoltage(VccPdroRawData); printf ("The Minimum VCCPDDRO is %0d.%03d Volts. \r\n" , (int ) (MinData), XAdcFractionToInt(MinData)); printf ("Exiting the XAdc Polled Example. \r\n" ); } int XAdcFractionToInt (float FloatNum) { float Temp; Temp = FloatNum; if (FloatNum < 0 ) { Temp = -(FloatNum); } return ( ((int )((Temp -(float )((int )Temp)) * (1000.0f )))); }
FLASH flash简介
flash分类
QSPI FLASH接口 (1)四根数据线,读写更快
SD卡 SD卡简介 (1)SD 卡共有 9 个引脚线,可工作在 SDIO 模式或者 SPI 模式。在 SDIO 模式下,共用到 CLK、CMD、DAT[3:0] 六根信号线;在 SPI 模式下,共用到 CS(SDIO_DAT[3])、CLK(SDIO_CLK)、MISO(SDIO_DAT[0])、MOSI(SDIO_CMD)四根信号线。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 #include "xparameters.h" #include "xil_printf.h" #include "ff.h" #include "xdevcfg.h" #define FILE_NAME "ZDYZ.txt" const char src_str[30 ] = "zynq xilink" ; static FATFS fatfs; int platform_init_fs () { FRESULT status; TCHAR *Path = "0:/" ; BYTE work[FF_MAX_SS]; status = f_mount (&fatfs, Path, 1 ); if (status != FR_OK) { xil_printf ("Volume is not FAT formated; formating FAT\r\n" ); status = f_mkfs (Path, FM_FAT32, 0 , work, sizeof (work)); if (status != FR_OK) { xil_printf ("Unable to format FATfs\r\n" ); return -1 ; } status = f_mount (&fatfs, Path, 1 ); if (status != FR_OK) { xil_printf ("Unable to mount FATfs\r\n" ); return -1 ; } } return 0 ; } int sd_mount () { FRESULT status; status = platform_init_fs (); if (status){ xil_printf ("ERROR: f_mount returned %d!\n" ,status); return XST_FAILURE; } return XST_SUCCESS; } int sd_write_data (char *file_name,u32 src_addr,u32 byte_len) { FIL fil; UINT bw; f_open (&fil,file_name,FA_CREATE_ALWAYS | FA_WRITE); f_lseek (&fil, 0 ); f_write (&fil,(void *) src_addr,byte_len,&bw); f_close (&fil); return 0 ; } int sd_read_data (char *file_name,u32 src_addr,u32 byte_len) { FIL fil; UINT br; f_open (&fil,file_name,FA_READ); f_lseek (&fil,0 ); f_read (&fil,(void *)src_addr,byte_len,&br); f_close (&fil); return 0 ; } int main () { int status,len; char dest_str[30 ] = "" ; status = sd_mount (); if (status != XST_SUCCESS){ xil_printf ("Failed to open SD card!\n" ); return 0 ; } else xil_printf ("Success to open SD card!\n" ); len = strlen (src_str); sd_write_data (FILE_NAME,(u32)src_str,len); sd_read_data (FILE_NAME,(u32)dest_str,len); if (strcmp (src_str, dest_str) == 0 ) xil_printf ("src_str is equal to dest_str,SD card test success!\n" ); else xil_printf ("src_str is not equal to dest_str,SD card test failed!\n" ); return 0 ; }
AXI协议 (参考:AXI4协议学习:架构、信号定义、工作时序和握手机制-CSDN博客 )
AXI定义
AXI,(advanced extensible interface) 高级扩展接口,属于AMBA(advanced microcontroller bus architecture)高级微控制器总线架构。
AXI分类
AXI4:高性能存储器映射接口,大量数据通信,用于处理器访问存储器等需要指定地址的高速数据传输场景,支持突发传输模式,一个地址传输256个数据。
AXI4-Lite:简化版的AXI4接口,少量数据的存储器映射通信,提供单个数据传输,用于低速外设的访问,不支持突发数据传输模式。
AXI-Stream:高速数据流传输接口,非存储映射接口,即不需要地址 ,用于视频、PCIE、DMA和高速AD等场景,支持不限数据长度的突发传输模式 。(通常可以使用AXI Direct Memory Access (DMA) engines将Stream移进或移出内存)
AXI工作方式 (1)AXI规范描述了单个AXI主(master)从(slave)之间的接口。
(2)多个Master和Slave之间的内存映射可以通过Xilinx AXI Interconnect IP 和 AXI SmartConnect IP 连接在一起
(3)数据可以同时在主->从和从->主两个方向传输。数据传输的大小可以变化。AXI4 中的限制是最多256 个数据传输的突发事务。AXI4-Lite 只允许每个事务进行1 个数据传输。
(4)AXI4 和 AXI4-Lite有5个独立的数据通道(参考 PDF INI0022dD)
每一个独立的通道都包含一组信息信号(读写地址、数据等信号)、VALID信号和READY信号,用于提供双向握手机制
信息源端使用VALID信号表示当前通道地址、数据和控制信息什么时候有效;信息目的端使用READY信号表示什么时候可以接收信息;读数据通道和写数据通道都包含一个LAST信号,用于表示传输的最后一个数据。
读数据通道和写数据通道都包含各自的地址通道,地址通道携带了请求所需的地址和信息
读数据通道从机——>主机,包含了读数据和读响应的信息,读响应的信号用于表示传输是否完成
写数据通道主机——>从机,包含了写数据,通过WSTRB信号表示当前数据的那个字节有效
写响应通道从机——>主机,包含了写响应信号,用于表示写操作是否完成
所有的五个通道都是通过相同的VALID/READY握手处理来传输地址、数据和控制信息,双向握手的机制意味着主机和从机之间传输数据时,都可以控制传输的速率
只有当VALID和READY信号都为高,传输才会开始
AXI时序示例
突发读示例
ARVALID和ARREADY都拉高,地址有效,地址传输到从机
RVALID和RREADY都拉高,数据传输到从机
RLAST与第四个数据D3同步,表示最后一个数据
重叠突发读示例
可以连续发送多个地址,两个突发读也是连续的,但是都有自己的结束RLAST
突发写时序
从机接收到数据后,向主机发送一个写响应,表明写事务已经完成