ZYNQ AXI 片上互聯的再思考:AXI GP口/axi lite

NoNounknow發表於2024-03-18

之前筆記:

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位埠!

ZYNQ AXI 片上互聯的再思考:AXI GP口/axi lite
/**************************** 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);
View Code

自己封裝的函式讀寫單個和多個:

函式1:讀寫多個資料;

ZYNQ AXI 片上互聯的再思考:AXI GP口/axi lite
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;
    }
}
View Code
ZYNQ AXI 片上互聯的再思考:AXI GP口/axi lite
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));
    }
}
View Code

使用示例1:

描述:

1.接收Uart資料並且校驗;

2.校驗成功則關閉硬中斷,向CPU1傳送軟中斷,把Uart接收到的陣列寫入指定的PL暫存器地址(地址A);

ZYNQ AXI 片上互聯的再思考:AXI GP口/axi lite
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);
}
View Code

使用示例2:

描述:

1.CPU1接收CPU0的軟中斷,據此讀取地址A的數值並校驗;

2.校驗成功則把地址A的數值寫入地址B,並且向CPU0傳送軟中斷;

使用示例3:

描述:

CPU0接收CPU1的軟中斷,據此讀取地址B的數值並UART傳送;

ZYNQ AXI 片上互聯的再思考:AXI GP口/axi lite
void SGI_IntrHandler(void *CallBackRef){
      Axi_ReadRamB(SendBuffer,8);
      XUartPs_Send(&Uart_Instance_point, SendBuffer, 8);
      print("SG0!\n\r");
}
View Code

函式2:

ZYNQ AXI 片上互聯的再思考:AXI GP口/axi lite
/***************************** 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;
    }
}
View Code

使用範例:

描述:將TCP傳送的資料包寫入指定暫存器並且讀出給PL端使用;

ZYNQ AXI 片上互聯的再思考:AXI GP口/axi lite
        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;
                }
            }
        }
View Code

相關文章