之前筆記:
Zynq上的儲存器介面與差分時鐘與DDR3_zynq ddr3-CSDN部落格
使用Axi Lite介面訪問暫存器列表作為緩衝區_兩個引數共用axi lite中一個暫存器-CSDN部落格
PS與PL互聯與SCU以及PG082_pl能不能用ps-gtr-CSDN部落格
ZYNQ上互聯的AXI主要有三種:
AXI LITE
AXI HP
AXI ACP
AXI LITE(GP)
用途:
通訊UART,I2C,SPI,CAN等介面
作為PS儲存資料到PL端方便互動的緩衝區;
特色:
32位資料位寬,不可突發;
生成方式:
用途1.自然選通產生的以上介面的以AXI GP口的形式輸出的;
用途2.建立IP的時候選擇AXI介面:
非常注意:
直接生成的方法至今仍存在BUG,需要採用此方法解決:
Vitis IDE 2021.1 custom AXI IP core compile error (xilinx.com)
參考操作程式碼:
官方參考:注意!GP口每次操作的偏移量都是4個位元組!因為是32位埠!
/**************************** Type Definitions *****************************/ /** * * Write a value to a AXILITE_REG_DEEPTH256 register. A 32 bit write is performed. * If the component is implemented in a smaller width, only the least * significant data is written. * * @param BaseAddress is the base address of the AXILITE_REG_DEEPTH256device. * @param RegOffset is the register offset from the base to write to. * @param Data is the data written to the register. * * @return None. * * @note * C-style signature: * void AXILITE_REG_DEEPTH256_mWriteReg(u32 BaseAddress, unsigned RegOffset, u32 Data) * */ #define AXILITE_REG_DEEPTH256_mWriteReg(BaseAddress, RegOffset, Data) \ Xil_Out32((BaseAddress) + (RegOffset), (u32)(Data)) /** * * Read a value from a AXILITE_REG_DEEPTH256 register. A 32 bit read is performed. * If the component is implemented in a smaller width, only the least * significant data is read from the register. The most significant data * will be read as 0. * * @param BaseAddress is the base address of the AXILITE_REG_DEEPTH256 device. * @param RegOffset is the register offset from the base to write to. * * @return Data is the data from the register. * * @note * C-style signature: * u32 AXILITE_REG_DEEPTH256_mReadReg(u32 BaseAddress, unsigned RegOffset) * */ #define AXILITE_REG_DEEPTH256_mReadReg(BaseAddress, RegOffset) \ Xil_In32((BaseAddress) + (RegOffset)) /************************** Function Prototypes ****************************/ /** * * Run a self-test on the driver/device. Note this may be a destructive test if * resets of the device are performed. * * If the hardware system is not built correctly, this function may never * return to the caller. * * @param baseaddr_p is the base address of the AXILITE_REG_DEEPTH256 instance to be worked on. * * @return * * - XST_SUCCESS if all self-test code passed * - XST_FAILURE if any self-test code failed * * @note Caching must be turned off for this function to work. * @note Self test may fail if data memory and device are not on the same bus. * */ XStatus AXILITE_REG_DEEPTH256_Reg_SelfTest(void * baseaddr_p);
自己封裝的函式讀寫單個和多個:
函式1:讀寫多個資料;
void Axi_WriteRamA(u8 *Data_addr_point, u32 Write_ByteLong){ int i; for ( i = 0; i < Write_ByteLong; i++) { AXI_REG_LIST_mWriteReg(Axi_RamA_BaseAddr,i*4 ,*(Data_addr_point + i)); } } void Axi_ReadRamB(u8 *Data_addr_point, u32 Read_ByteLong){ int i; u32 Read_Data_Origin; for ( i = 0; i < Read_ByteLong; i++) { Read_Data_Origin = AXI_REG_LIST_mReadReg(Axi_RamB_BaseAddr, i*4); *(Data_addr_point + i) = (u8) Read_Data_Origin; } }
void Axi_ReadRamA(u8 *Data_addr_point, u32 Read_ByteLong){ int i; u32 Read_Data_Origin; for ( i = 0; i < Read_ByteLong; i++) { Read_Data_Origin = AXI_REG_LIST_mReadReg(Axi_RamA_BaseAddr, i*4); *(Data_addr_point + i) = (u8) Read_Data_Origin; } } void Axi_WriteRamB(u8 *Data_addr_point, u32 Write_ByteLong){ int i; for ( i = 0; i < Write_ByteLong; i++) { AXI_REG_LIST_mWriteReg(Axi_RamB_BaseAddr,i*4 ,*(Data_addr_point + i)); } }
使用示例1:
描述:
1.接收Uart資料並且校驗;
2.校驗成功則關閉硬中斷,向CPU1傳送軟中斷,把Uart接收到的陣列寫入指定的PL暫存器地址(地址A);
void Uart0_IntrHandler(void *CallBackRef, u32 Event, unsigned int EventData) { if (Event == XUARTPS_EVENT_RECV_TOUT) { TotalReceivedCount = EventData; if (TotalReceivedCount == 8 && RecvBuffer[0] == 0x55 && RecvBuffer[1] == 0x55 && RecvBuffer[2] == 0x00 && RecvBuffer[3] == 0x01) { XScuGic_Disable(&GIC_SGI_instance_point, Interrupt_ID_Hardware_1); XScuGic_Disable(&GIC_SGI_instance_point, Interrupt_ID_Hardware_0); Axi_WriteRamA(RecvBuffer,TotalReceivedCount); printf("Close SPI\n\r"); XScuGic_SoftwareIntr(&GIC_SGI_instance_point, Interrupt_ID_SGI_15, XSCUGIC_SPI_CPU1_MASK); } else if(TotalReceivedCount == 8 && RecvBuffer[0] == 0x66) { XScuGic_Enable(&GIC_SGI_instance_point, Interrupt_ID_Hardware_0); printf("Open SPI\n\r"); } } XUartPs_Recv(&Uart_Instance_point, RecvBuffer, TEST_BUFFER_SIZE); }
使用示例2:
描述:
1.CPU1接收CPU0的軟中斷,據此讀取地址A的數值並校驗;
2.校驗成功則把地址A的數值寫入地址B,並且向CPU0傳送軟中斷;
使用示例3:
描述:
CPU0接收CPU1的軟中斷,據此讀取地址B的數值並UART傳送;
void SGI_IntrHandler(void *CallBackRef){ Axi_ReadRamB(SendBuffer,8); XUartPs_Send(&Uart_Instance_point, SendBuffer, 8); print("SG0!\n\r"); }
函式2:
/***************************** Include Files *******************************/ #include "axilite_reg_deepth256.h" /************************** Function Definitions ***************************/ /** * * @param BaseAddress : 寫入緩衝區基地址 * @param Addr_Offset : 寫入緩衝區的地址偏移量(會佔用多少空間) * @param data :寫入緩衝區的具體資料 * @return none * ***************************************************************************/ void AxiLite_W_Single(u32 BaseAddress, u32 Addr_Offset, u32 data){ AXILITE_REG_DEEPTH256_mWriteReg(BaseAddress, Addr_Offset << 2, data); } /** * * @param BaseAddress : 寫入緩衝區基地址 * @param Data_addr_point : 即將寫入緩衝區的陣列所在的基地址 * @param Write_ByteLong :即將寫入緩衝區的陣列長度 * @return none * ***************************************************************************/ void AxiLite_W_Serial(u32 BaseAddress, u8 *Data_addr_point, u32 Write_ByteLong){ int i; for ( i = 0; i < Write_ByteLong; i++) { AXILITE_REG_DEEPTH256_mWriteReg(BaseAddress,i*4 ,*(Data_addr_point + i)); } } /** * * @param BaseAddress : 讀出緩衝區基地址 * @param Data_addr_point :存放讀出陣列的緩衝區基地址 * @param Read_ByteLong :讀出陣列的長度 * @return 讀出資料. * * 讀出指定緩衝區的指定長度的資料存入某個區域 * * (Data_addr_point + i) = (u32) Read_Data_Origin;將所讀出的資料賦值給指定的區域 * ***************************************************************************/ u32 AxiLite_R_Single(u32 BaseAddress, u32 Addr_Offset){ return AXILITE_REG_DEEPTH256_mReadReg(BaseAddress, Addr_Offset <<2); } /** * * @param BaseAddress : 讀出緩衝區基地址 * @param Data_addr_point :存放讀出陣列的緩衝區基地址 * @param Read_ByteLong :讀出陣列的長度 * @return 讀出資料. * * 讀出指定緩衝區的指定長度的資料存入某個區域 * * (Data_addr_point + i) = (u32) Read_Data_Origin;將所讀出的資料賦值給指定的區域 * ***************************************************************************/ void AxiLite_R_Serial(u32 BaseAddress, u32 *Data_addr_point, u32 Read_ByteLong){ int i; u32 Read_Data_Origin; for ( i = 0; i < Read_ByteLong; i++) { Read_Data_Origin = AXILITE_REG_DEEPTH256_mReadReg(BaseAddress, i*4); *(Data_addr_point + i) = (u32) Read_Data_Origin; } }
使用範例:
描述:將TCP傳送的資料包寫入指定暫存器並且讀出給PL端使用;
if (recv_buf[0] == 0x55 && recv_buf[1] == 0x55 && recv_buf[2] == 0x55 && recv_buf[3] == 0x55 && recv_buf[4] == 0x55 && recv_buf[5] == 0x55 && recv_buf[6] == 0x55 && recv_buf[7] == 0x55 ) { u32 RegAddr; u32 Direct_RW_Flag; u32 RegData = 0; RegAddr = recv_buf[8]; Direct_RW_Flag = recv_buf[9]; /* 將解析的配置資料寫入指定好的PL端暫存器地址 */ if(Direct_RW_Flag == 0){ RegData = recv_buf[10]<<24; RegData |= recv_buf[11]<<16; RegData |= recv_buf[12]<<8; RegData |= recv_buf[13]<<0; if(RegAddr == 1){ ImageWeigh = RegData; xil_printf("ConfigSet ImageWeigh!\r\n"); } if(RegAddr == 2){ ImageHeigh = RegData; xil_printf("ConfigSet ImageHeigh!\r\n"); } if(RegAddr == 3){ ReadBack_Flag = RegData; xil_printf("ConfigSet ReadBack_Flag!\r\n"); } AxiLite_W_Single(AXI_ConFig_list_BaseAddr, RegAddr, RegData); RegData = AxiLite_R_Single(AXI_ConFig_list_BaseAddr, RegAddr); recv_buf[10] = (RegData>>24) & 0xff; recv_buf[11] = (RegData>>16) & 0xff; recv_buf[12] = (RegData>>8 ) & 0xff; recv_buf[13] = (RegData>>0 ) & 0xff; if((lwip_send(sock, recv_buf, read_bytes, 0))<0){ xil_printf("%s : Send Error!\r\n",sock); break; } } }