Post Go back to editing

Adin3310 only Same data reading

Category: Software
Software Version: xilinx freertos 10 in vitis 2022.2

HI 

      I am currently usnig adin3310 etherenet switch in cusyom board i want too configure it through spi from xazu3eg1sfvc78i i am getting the pulses from the timer0 that there is no image my interrupt is taking that and reading i am getting the read  first time the 4 bytes header and the second time header + 20 bytes of the payload but the problem i am not able to read the next data i am countinously reading the same data again ad again i am using the windows example i ported the spi porting layer and replayed the spi function everything is fine but the next reads are not happening i have the spi transactions pdf that i need to get for intilization i am attaching the spi porting layer and the read messages i observed .

Thanks and regards ,

kowsik

/*
 * Copyright (c) 2024 Analog Devices, Inc. All Rights Reserved.
 *
 * This software is proprietary and confidential to Analog Devices, Inc.
 * and its licensors.
 */

/*
 * FreeRTOS Port — Zynq UltraScale+ MPSoC (Vitis / FreeRTOS 10)
 * Target  : ADIN3310 Ethernet Switch — SPI interface abstraction
 * Toolchain: Xilinx Vitis, arm-none-eabi-gcc
 *
 * Hardware mapping
 * ─────────────────────────────────────────────────────────────────────────────
 *  Windows reference          This port
 *  ─────────────────────────  ──────────────────────────────────────────────
 *  FT4222 USB-SPI bridge      PS-SPI (XSpiPs) on Zynq MPSoC
 *  FT4222 GPIO port 3 (IRQ)   MIO GPIO pin 62  (XGpioPs)
 *  Windows CreateThread()     FreeRTOS xTaskCreate()
 *  WaitForSingleObject(event) FreeRTOS binary semaphore (IRQ → task notify)
 *  HANDLE / BOOL              XSpiPs_Config * / BaseType_t
 *
 * SPI configuration for ADIN3310 (UG2287 §3.1)
 *   Mode  : CPOL=0, CPHA=0  (SPI mode 0)
 *   Width : 8-bit
 *   CS    : active-low, driven by hardware (SSNBS)
 *   Max   : 25 MHz — use the clock divider appropriate for your PL/PS
 *
 * GPIO / Interrupt
 *   MIO 62 is configured as input with a rising-edge interrupt routed to
 *   GIC via XScuGic.  The ISR posts a binary semaphore; the IRQ task
 *   takes that semaphore and calls HandleReceivedMessage().
 *
 * FreeRTOSConfig.h requirements
 *   configUSE_COUNTING_SEMAPHORES   1
 *   configUSE_TASK_NOTIFICATIONS    1   (optional — binary sem used instead)
 *   INCLUDE_vTaskDelete             1
 *   configMAX_PRIORITIES            ≥ (SES_PORT_IRQ_TASK_PRIORITY + 1)
 *
 * Vivado / Vitis assumptions
 *   - xparameters.h defines XPAR_PSU_SPI_0_DEVICE_ID / BASEADDR
 *   - xparameters.h defines XPAR_PSU_GPIO_0_DEVICE_ID
 *   - xparameters.h defines XPAR_PSU_GPIO_0_INTR  (GIC SPI ID for GPIO)
 *   - GIC driver (XScuGic) is already initialised by the BSP before
 *     SES_PORT_SPI_Init() is called.
 * ─────────────────────────────────────────────────────────────────────────────
 */

// Includes *******************************************************************

#include <string.h>
#include <stdint.h>
#include <stdio.h>

/* FreeRTOS */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"

/* Xilinx BSP */
#include "xparameters.h"
#include "xspips.h"          /* PS SPI driver                                 */
#include "xgpiops.h"         /* PS GPIO driver                                */
#include "xscugic.h"         /* GIC interrupt controller                      */
#include "xil_exception.h"

/* SES driver */
#include "SES_debug.h"
#include "SES_port_api.h"
#include "SES_PORT_interface.h"
#include "xil_cache.h"
// End Includes ***************************************************************

// Macros, typedefs, enums ****************************************************

/* ── General ── */
#define SES_PORT_SPI_MAX_TYPE               (15)
#define SES_PORT_SPI_TFER_TYPE_MASK         (0xF)
#define SES_PORT_SEM_INFINITE_WAIT          (-1)

/* Milliseconds the Release path waits for the IRQ task to finish */
#define SES_PORT_SPI_WAIT_THREAD_STOP_MS    (5000U)

/* ── SPI frame commands (identical to reference) ── */
#define SES_PORT_SPI_READ_CMD               (0x80U)
#define SES_PORT_SPI_WRITE_CMD              (0x40U)
#define SES_PORT_SPI_CMD_SZ                 (1U)

/* ── Hardware IDs ── pull from xparameters.h; override here if needed ── */
#ifndef SES_SPI_DEVICE_ID
#  define SES_SPI_DEVICE_ID                 XPAR_PSU_SPI_0_DEVICE_ID
#endif

#ifndef SES_GPIO_DEVICE_ID
#  define SES_GPIO_DEVICE_ID                XPAR_PSU_GPIO_0_DEVICE_ID
#endif

/* MIO pin used as the ADIN3310 interrupt input */
#define SES_PORT_IRQ_GPIO_PIN               (62U)
#define gpio								(63U)



/*
 * SPI clock divider.
 * PS-SPI ref clock is typically 200 MHz on ZU+.
 * XSPIPS_CLK_PRESCALE_8  → 25 MHz  (ADIN3310 maximum).
 * Adjust if your ref clock differs.
 */
#define SES_SPI_CLK_PRESCALE                XSPIPS_CLK_PRESCALE_32

/* FreeRTOS task parameters for the IRQ handler task */
#define SES_PORT_IRQ_TASK_STACK_WORDS       (1024U)
#define SES_PORT_IRQ_TASK_PRIORITY          (configMAX_PRIORITIES - 1U)
#define SES_PORT_IRQ_TASK_NAME              "SES_SpiIrq"

/* ── Struct ── */
typedef struct {
    int               initialized;
    void             *spiProtectSem;   /* counting sem, max=1: SPI bus mutex  */
    SemaphoreHandle_t rxEventSem;      /* binary sem: ISR → IRQ task          */
    TaskHandle_t      irqTask;         /* FreeRTOS IRQ handler task           */
    volatile int      stopTask;        /* flag: ask the IRQ task to exit      */
    XSpiPs            spiInst;         /* Xilinx PS-SPI instance              */
    XGpioPs           gpioInst;        /* Xilinx PS-GPIO instance             */
    int               chipSelect;      /* SPI CS index (0 for single-device)  */
} SES_PORT_spiLinkDescription_t;

/* Passed through pvPortMalloc to the IRQ task on creation */
typedef struct {
    int drvHdlIdx;
} SES_PORT_threadData_t;

// End Macros, typedefs, enums ************************************************

// Global Variables ***********************************************************

static SES_PORT_spiLinkDescription_t
    spiLinkDescription_g[SES_PORT_MAX_SPI_LINKS] = { { 0 } };

/* Protects the spiLinkDescription_g[] table during Init/Release */
static void *dataTableProtectionSem_gp = NULL;

/*
 * Shared GIC handle.
 * The application must initialise this before calling SES_PORT_SPI_Init().
 * Declare it extern here so the SPI port can register its GPIO ISR.
 */
extern XScuGic XInterruptController;

// End Global Variables *******************************************************

// Static Function Prototypes *************************************************

static int  GetLinkDescriptionEntry(void);
static int  HandleReceivedMessage(int tblIndex);
static int  InitDrv(int tblIndex);
static int  SpiClose(int tblIndex);
static int  SpiRead(int tblIndex, uint16_t length, uint8_t *dataRx_p);
static void TaskSpiIrq(void *pvParam);
static void GpioIsr(void *callbackRef);

// End Static Function Prototypes *********************************************

// Functions ******************************************************************

/**
 * @brief  Initialise the SPI interface to the ADIN3310.
 *
 * Replaces the Windows FT4222 open/init sequence with XSpiPs + XGpioPs
 * initialisation.  The init parameter struct is SES_PORT_zynqSpiInitParams_t
 * (defined in SES_PORT_interface.h — see note in that file).
 *
 * @param[in]  param_p     Pointer to SES_PORT_zynqSpiInitParams_t.
 * @param[out] intfType_p  Set to SES_PORT_spiInterface on success.
 * @param[out] srcMac_p    Not used for SPI; may be NULL.
 *
 * @return  Non-negative interface handle on success, negative error code on failure.
 */
int SES_PORT_SPI_Init(void *param_p,
                      SES_PORT_intfType_t *intfType_p,
                      uint8_t *srcMac_p)
{
    int intfHandle;
    int response;
    SES_PORT_zynqSpiInitParams_t *initParams_p =
        (SES_PORT_zynqSpiInitParams_t *)param_p;

    (void)srcMac_p; /* not used for SPI */

    /* ── Parameter check ── */
    if ((param_p == NULL) || (intfType_p == NULL)) {
        return SES_PORT_INVALID_PARAM;
    }

    /* ── Create the table-protection semaphore once ── */
    if (dataTableProtectionSem_gp == NULL) {
        dataTableProtectionSem_gp = SES_PORT_CreateSemaphore(1, 1);
        if (dataTableProtectionSem_gp == NULL) {
            return SES_PORT_ERROR;
        }
    }

    SES_PORT_WaitSemaphore(dataTableProtectionSem_gp,
                           SES_PORT_PROTECTION_TIMEOUT);

    /* ── Find a free link-description slot ── */
    intfHandle = GetLinkDescriptionEntry();
    if (intfHandle < SES_PORT_OK) {
        SES_PORT_SignalSemaphore(dataTableProtectionSem_gp);
        return SES_PORT_ERROR;
    }

    /* ── Per-link SPI-bus mutex (counting sem, max = 1) ── */
    spiLinkDescription_g[intfHandle].spiProtectSem =
        SES_PORT_CreateSemaphore(1, 1);
    if (spiLinkDescription_g[intfHandle].spiProtectSem == NULL) {
        SES_PORT_SignalSemaphore(dataTableProtectionSem_gp);
        return SES_PORT_ERROR;
    }

    /*
     * ── IRQ event semaphore ──
     * Binary semaphore:  ISR calls xSemaphoreGiveFromISR(),
     *                    TaskSpiIrq() calls xSemaphoreTake().
     * Replaces the Windows CreateEvent(auto-reset) + WaitForSingleObject().
     */
    spiLinkDescription_g[intfHandle].rxEventSem =
        xSemaphoreCreateBinary();
    if (spiLinkDescription_g[intfHandle].rxEventSem == NULL) {
        SES_PORT_DeleteSemaphore(
            spiLinkDescription_g[intfHandle].spiProtectSem);
        SES_PORT_SignalSemaphore(dataTableProtectionSem_gp);
        return SES_PORT_ERROR;
    }

    /* Store the chip-select index supplied by the caller */
    spiLinkDescription_g[intfHandle].chipSelect = initParams_p->chipSelect;
    spiLinkDescription_g[intfHandle].stopTask   = 0;

    SES_PORT_SignalSemaphore(dataTableProtectionSem_gp);

    /* ── Hardware init (SPI + GPIO + IRQ task) ── */
    response = InitDrv(intfHandle);
    if (response != SES_PORT_OK) {
        vSemaphoreDelete(spiLinkDescription_g[intfHandle].rxEventSem);
        SES_PORT_DeleteSemaphore(
            spiLinkDescription_g[intfHandle].spiProtectSem);
        return SES_PORT_ERROR;
    }

    spiLinkDescription_g[intfHandle].initialized = 1;
    *intfType_p = SES_PORT_spiInterface;

    return intfHandle;
}

/**
 * @brief  Release (close) the SPI interface.
 *
 * Signals the IRQ task to stop, waits up to SES_PORT_SPI_WAIT_THREAD_STOP_MS,
 * then tears down GPIO, SPI and semaphores.
 */
int SES_PORT_SPI_Release(int intfHandle)
{
    int rv = SES_PORT_OK;

    SES_PORT_WaitSemaphore(dataTableProtectionSem_gp,
                           SES_PORT_PROTECTION_TIMEOUT);

    if (!spiLinkDescription_g[intfHandle].initialized) {
        DBG_INFO("SES_PORT_SPI_Release called before Initialization");
        rv = SES_PORT_NOT_INITIALIZED;
    }

    if (rv == SES_PORT_OK) {
        rv = SpiClose(intfHandle);
        if (rv != SES_PORT_OK) {
            rv = SES_PORT_ERROR;
        }
    }

    SES_PORT_SignalSemaphore(dataTableProtectionSem_gp);

    return rv;
}

/**
 * @brief  Send a framed message to the ADIN3310 over SPI.
 *
 * Prepends the 1-byte WRITE command (0x40) then transfers the full frame
 * using XSpiPs_PolledTransfer() under the protection of the per-link mutex.
 *
 * @param[in] intfHandle  Handle returned by SES_PORT_SPI_Init().
 * @param[in] size        Payload size in bytes (NOT including command byte).
 * @param[in] data_p      Pointer to payload buffer (freed on success).
 *
 * @return SES_PORT_OK on success, negative error code on failure.
 */
int SES_PORT_SPI_SendMessage(int intfHandle, int size, void *data_p)
{
    int      result   = SES_PORT_ERROR;
    int      response = SES_PORT_ERROR;
    int i;
    int      spiFrmSz;
    int      count    = 0;
    int      status;
    uint8_t *tx_frame = NULL;

    /* Dummy RX buffer — XSpiPs always full-duplex */
    uint8_t *rx_dummy = NULL;

    if (!spiLinkDescription_g[intfHandle].initialized) {
        return SES_PORT_NOT_INITIALIZED;
    }

    if (data_p == NULL) {
        return SES_PORT_INVALID_PARAM;
    }

    /* Build TX frame: [0x40 | payload] */
    spiFrmSz = size + SES_PORT_SPI_CMD_SZ;

    result = SES_PORT_Malloc((void **)&tx_frame, spiFrmSz);
    if (result != SES_PORT_OK) {
        return SES_PORT_ERROR;
    }

    result = SES_PORT_Malloc((void **)&rx_dummy, spiFrmSz);
    if (result != SES_PORT_OK) {
        SES_PORT_Free(tx_frame);
        return SES_PORT_ERROR;
    }

    tx_frame[0] = SES_PORT_SPI_WRITE_CMD;
    memcpy(tx_frame + SES_PORT_SPI_CMD_SZ, data_p, size);

    /* ── Take SPI bus mutex ── */
    SES_PORT_WaitSemaphore(spiLinkDescription_g[intfHandle].spiProtectSem,
                           SES_PORT_SEM_INFINITE_WAIT);

    /*
     * XSpiPs_PolledTransfer drives CS automatically when configured with
     * XSPIPS_MANUAL_START_OPTION disabled (the default after SetOptions).
//     */
//    while(1){
    status = XSpiPs_PolledTransfer(
                 &spiLinkDescription_g[intfHandle].spiInst,
                 tx_frame,
                 rx_dummy,
                 (u32)spiFrmSz);
    for(i=0;i<1000;i++);
//    }

    SES_PORT_SignalSemaphore(spiLinkDescription_g[intfHandle].spiProtectSem);

    count = (status == XST_SUCCESS) ? spiFrmSz : 0;

    SES_PORT_Free(tx_frame);
    SES_PORT_Free(rx_dummy);

    if (count != spiFrmSz) {
        response = SES_PORT_ERROR;
    } else {
        response = SES_PORT_OK;
        SES_PORT_Free(data_p);   /* convention: caller's buffer freed on OK */
    }

    return response;
}

/**
 * @brief  Return a human-readable string describing the SPI interface.
 *
 * The FT4222 device enumeration has no equivalent on Zynq; we return a
 * static description based on the BSP parameters instead.
 */
int32_t SES_PORT_SPI_GetInterfaceInfo(char *interfaceInfo_p,
                                      uint16_t bufferSize)
{
    if ((interfaceInfo_p == NULL) || (bufferSize == 0U)) {
        return SES_PORT_BUF_ERR;
    }

    int written = snprintf(interfaceInfo_p, bufferSize,
                           "0,Zynq-UltraScale-PS-SPI(dev=%d,gpio=%d);",
                           (int)SES_SPI_DEVICE_ID,
                           (int)SES_PORT_IRQ_GPIO_PIN);

    return (written > 0) ? SES_PORT_OK : SES_PORT_BUF_ERR;
}

// End Functions **************************************************************

// Static Functions ***********************************************************

/**
 * @brief  Handle one incoming SPI message from the ADIN3310.
 *
 * Reads the 4-byte header, validates the length and transfer-type fields,
 * allocates a receive buffer, reads the payload, then hands everything to
 * SES_ReceiveMessage().  Logic is identical to the Windows reference.
 */
static int HandleReceivedMessage(int tblIndex)
{
    int      response = SES_PORT_OK;
    uint8_t  transferType;
    int16_t  txLength;
    int16_t  pad_to_block;
    uint32_t header   = 0U;
    int      rxLength;
    uint8_t *rx_frame = NULL;

    /* Step 1 – read the 4-byte header */
    response = SpiRead(tblIndex, sizeof(header), (uint8_t *)&header);
    if (response != SES_PORT_OK) {
        return response;
    }

    /* Step 2 – decode and validate length (lower 12 bits) */
    rxLength = (int)((uint16_t)(header & SES_PORT_SPI_LENGTH_MASK));
    if (rxLength != (int)(((~header >> SES_PORT_SPI_INVERTED_LENGTH_SHIFT) &
                           SES_PORT_SPI_LENGTH_MASK))) {
        return SES_PORT_ERROR;
    }

    /* Step 3 – decode and validate transfer type (4 bits) */
    transferType = (uint8_t)((header >> SES_PORT_SPI_TYPE_SHIFT) &
                             SES_PORT_SPI_TFER_TYPE_MASK);
    if (transferType != (uint8_t)(((~header >> SES_PORT_SPI_INVERTED_TYPE_SHIFT) &
                                   SES_PORT_SPI_TFER_TYPE_MASK))) {
        return SES_PORT_ERROR;
    }

    /* Step 4 – round up to block boundary */
    txLength     = (int16_t)(rxLength + SES_PORT_SPI_BLOCK_LENGTH - 1);
    txLength    &= (int16_t)(~(SES_PORT_SPI_BLOCK_LENGTH - 1));
    pad_to_block = txLength - (int16_t)rxLength;

    /* Step 5 – allocate and fill the payload buffer */
    response = SES_PORT_Malloc((void **)&rx_frame,
                               (int)(rxLength + pad_to_block));
    if (response != SES_PORT_OK) {
        return SES_PORT_ERROR;
    }
//pad_to_block
    response = SpiRead(tblIndex, (uint16_t)(rxLength), rx_frame);
    if (response != SES_PORT_OK) {
        (void)SES_PORT_Free(rx_frame);
        return response;
    }

    /* Step 6 – deliver to the SES stack */
    response = SES_ReceiveMessage(tblIndex,
                                  SES_PORT_spiInterface,
                                  rxLength,
                                  (void *)rx_frame,
                                  (-1),
                                  (0),
                                  NULL);
    SES_PORT_Free(rx_frame);
    return response;
}

/**
 * @brief  Initialise the PS-SPI peripheral, GPIO interrupt pin, and IRQ task.
 *
 * Replaces FT_OpenEx / FT4222_SPIMaster_Init / CreateThread.
 */
static int InitDrv(int tblIndex)
{
    int              rv;
    XSpiPs_Config   *spiCfg_p;
    XGpioPs_Config  *gpioCfg_p;
    int              xilStatus;
    SES_PORT_threadData_t *thStruct_p = NULL;
    BaseType_t        taskCreated;

    /* ── 1. Initialise PS-SPI ── */
    spiCfg_p = XSpiPs_LookupConfig(SES_SPI_DEVICE_ID);
    if (spiCfg_p == NULL) {
        return SES_PORT_ERROR;
    }

    xilStatus = XSpiPs_CfgInitialize(
                    &spiLinkDescription_g[tblIndex].spiInst,
                    spiCfg_p,
                    spiCfg_p->BaseAddress);
    if (xilStatus != XST_SUCCESS) {
        return SES_PORT_ERROR;
    }

    /*
     * ADIN3310 SPI: CPOL=0, CPHA=0 (mode 0), 8-bit, MSB first.
     * XSPIPS_MASTER_OPTION   – this device is the SPI master
     * XSPIPS_FORCE_SSELECT_OPTION – hardware drives CS automatically
     *                               (de-asserts after each transfer)
     */
    xilStatus = XSpiPs_SetOptions(
                    &spiLinkDescription_g[tblIndex].spiInst,
                    XSPIPS_MASTER_OPTION |
					XSPIPS_FORCE_SSELECT_OPTION);
    if (xilStatus != XST_SUCCESS) {
        return SES_PORT_ERROR;
    }

    xilStatus = XSpiPs_SetClkPrescaler(
                    &spiLinkDescription_g[tblIndex].spiInst,
                    SES_SPI_CLK_PRESCALE);
    if (xilStatus != XST_SUCCESS) {
        return SES_PORT_ERROR;
    }

    /* Select the chip-select line */
    xilStatus = XSpiPs_SetSlaveSelect(
                    &spiLinkDescription_g[tblIndex].spiInst,
                    0x00);
    if (xilStatus != XST_SUCCESS) {
        return SES_PORT_ERROR;
    }

    /* ── 2. Initialise PS-GPIO for interrupt pin (MIO 62) ── */
    gpioCfg_p = XGpioPs_LookupConfig(SES_GPIO_DEVICE_ID);
    if (gpioCfg_p == NULL) {
        return SES_PORT_ERROR;
    }

    xilStatus = XGpioPs_CfgInitialize(
                    &spiLinkDescription_g[tblIndex].gpioInst,
                    gpioCfg_p,
                    gpioCfg_p->BaseAddr);
    if (xilStatus != XST_SUCCESS) {
        return SES_PORT_ERROR;
    }

    /* Configure MIO 62 as input */
    XGpioPs_SetDirectionPin(
        &spiLinkDescription_g[tblIndex].gpioInst,
        SES_PORT_IRQ_GPIO_PIN,
        0U);   /* 0 = input */

    /*
     * ── 3. Connect GPIO ISR to GIC ──
     *
     * XPAR_PSU_GPIO_0_INTR is the GIC SPI interrupt ID for the PS GPIO block.
     * All 78 MIO pins share this one GIC line; the ISR reads the interrupt
     * status register to identify which pin fired.
     */
    xilStatus = XScuGic_Connect(
                    &XInterruptController,
                    XPAR_PSU_GPIO_0_INTR,
                    (Xil_ExceptionHandler)GpioIsr,
                    (void *)&spiLinkDescription_g[tblIndex].gpioInst);
    if (xilStatus != XST_SUCCESS) {
        return SES_PORT_ERROR;
    }

    /* Rising-edge interrupt on MIO 62 */
    XGpioPs_SetIntrTypePin(
        &spiLinkDescription_g[tblIndex].gpioInst,
        SES_PORT_IRQ_GPIO_PIN,
		XGPIOPS_IRQ_TYPE_EDGE_RISING);//changed to rising edge

    XGpioPs_IntrEnablePin(
        &spiLinkDescription_g[tblIndex].gpioInst,
        SES_PORT_IRQ_GPIO_PIN);

    XScuGic_Enable(&XInterruptController, XPAR_PSU_GPIO_0_INTR);

    /* ── 4. Create the IRQ handler task ── */
    rv = SES_PORT_Malloc((void **)&thStruct_p,
                         sizeof(SES_PORT_threadData_t));
    if (rv != SES_PORT_OK) {
        return SES_PORT_ERROR;
    }
    thStruct_p->drvHdlIdx = tblIndex;

    /*
     * xTaskCreate() replaces CreateThread().
     * The task runs at the highest priority so interrupt-driven frames are
     * processed before any lower-priority application tasks — matching the
     * THREAD_PRIORITY_TIME_CRITICAL setting in the Windows reference.
     */
    taskCreated = xTaskCreate(TaskSpiIrq,
                              SES_PORT_IRQ_TASK_NAME,
                              SES_PORT_IRQ_TASK_STACK_WORDS,
                              (void *)thStruct_p,
                              SES_PORT_IRQ_TASK_PRIORITY,
                              &spiLinkDescription_g[tblIndex].irqTask);

    if (taskCreated != pdPASS) {
        SES_PORT_Free(thStruct_p);
        return SES_PORT_THREAD_FAIL;
    }

    return SES_PORT_OK;
}

/**
 * @brief  Low-level SPI read helper.
 *
 * Prepends the 1-byte READ command (0x80), performs a full-duplex polled
 * transfer, and copies the received payload (skipping the command echo byte)
 * into @p dataRx_p.
 *
 * Block-alignment padding is added on the TX side so the ADIN3310 SPI framing
 * is satisfied (identical calculation to the Windows reference).
 */
static int SpiRead(int tblIndex, uint16_t length, uint8_t *dataRx_p)
{
    int      response = SES_PORT_OK;
    int16_t  txLength;
    int16_t  pad_to_block;
    uint8_t *tx_frame = NULL;
    uint8_t d[22]={0};
    uint8_t *rx_frame = NULL;
//    uint8_t rx_frame[128];
    int      spiFrmSz;
    int      xilStatus;



    /* Round up to block boundary */
    txLength     = (int16_t)(length + SES_PORT_SPI_BLOCK_LENGTH - 1);
    txLength    &= (int16_t)(~(SES_PORT_SPI_BLOCK_LENGTH - 1));
    pad_to_block = txLength - (int16_t)length;

    spiFrmSz = (int)(SES_PORT_SPI_CMD_SZ + length + pad_to_block);



    /* Allocate TX and RX working buffers */
    response = SES_PORT_Malloc((void **)&tx_frame, spiFrmSz);
    if (response != SES_PORT_OK) {
        return SES_PORT_ERROR;
    }
//
    response = SES_PORT_Malloc((void **)&rx_frame, spiFrmSz);
    if (response != SES_PORT_OK) {
        (void)SES_PORT_Free(tx_frame);
        return SES_PORT_ERROR;
    }




    /* Build TX frame: READ command + zero padding */
    tx_frame[0] = SES_PORT_SPI_READ_CMD;
    memset(tx_frame + SES_PORT_SPI_CMD_SZ, 0x00U,
           (size_t)(spiFrmSz - SES_PORT_SPI_CMD_SZ));
//
//    Xil_DCacheFlushRange((INTPTR)tx_frame,(u32)spiFrmSz);
//    Xil_DCacheInvalidateRange((INTPTR)rx_frame,(u32)spiFrmSz);


    /* ── Take SPI bus mutex ── */
    SES_PORT_WaitSemaphore(spiLinkDescription_g[tblIndex].spiProtectSem,
                           SES_PORT_SEM_INFINITE_WAIT);


    xilStatus = XSpiPs_PolledTransfer(
                    &spiLinkDescription_g[tblIndex].spiInst,
                    tx_frame,
					rx_frame,
                    (u32)spiFrmSz);
    for(int i =0;i<=20;i++){
    	d[i]=rx_frame[i];
    }


//    Xil_DCacheInvalidateRange((INTPTR)rx_frame,(u32)spiFrmSz);

    SES_PORT_SignalSemaphore(spiLinkDescription_g[tblIndex].spiProtectSem);

    if (xilStatus != XST_SUCCESS) {
        response = SES_PORT_ERROR;
    }

    /* Free TX buffer */
    if (SES_PORT_Free(tx_frame) != SES_PORT_OK) {
        (void)SES_PORT_Free(rx_frame);
        return SES_PORT_ERROR;
    }

    /* Copy payload (skip the echoed command byte) into caller's buffer */
    if (response == SES_PORT_OK) {
    	if(length==4){
    	memcpy(dataRx_p, rx_frame+ SES_PORT_SPI_CMD_SZ, length);
    	}
    	else{
    	memcpy(dataRx_p, rx_frame+ SES_PORT_SPI_CMD_SZ+4, length);

    	}

    }
    for(int i =0;i<=20;i++){
    	d[i]=dataRx_p[i];
    }
//
    if (SES_PORT_Free(rx_frame) != SES_PORT_OK) {
        response = SES_PORT_ERROR;
    }

    return response;
}

/**
 * @brief  FreeRTOS IRQ handler task — replaces ThreadSpiIrq().
 *
 * Blocks indefinitely on rxEventSem.  The GPIO ISR posts that semaphore
 * whenever MIO 62 sees a rising edge.  On each wake-up the task reads the
 * GPIO pin level and, if still asserted, processes one received message.
 *
 * The task self-deletes when stopTask is set (by SpiClose).
 */
static void TaskSpiIrq(void *pvParam)
{
    SES_PORT_threadData_t  localData;
    SES_PORT_threadData_t *param_p = (SES_PORT_threadData_t *)pvParam;

    /* Copy data locally and free the heap allocation */
    memcpy(&localData, param_p, sizeof(SES_PORT_threadData_t));
    SES_PORT_Free(param_p);

    for (;;) {
        /*
         * Block until GpioIsr posts the semaphore.
         * portMAX_DELAY = wait forever (mirrors INFINITE in the Windows port).
         */
        xSemaphoreTake(
            spiLinkDescription_g[localData.drvHdlIdx].rxEventSem,
            portMAX_DELAY);

        /* Check the exit flag set by SpiClose() */
        if (spiLinkDescription_g[localData.drvHdlIdx].stopTask) {
            break;
        }

        /*
         * Confirm the interrupt pin is still high before reading.
         * Replaces FT4222_GPIO_Read() — reads MIO 62 directly.
         */
//        if (XGpioPs_ReadPin(
//                &spiLinkDescription_g[localData.drvHdlIdx].gpioInst,
//                SES_PORT_IRQ_GPIO_PIN) ==1U) {//changed to 0
//            HandleReceivedMessage(localData.drvHdlIdx);
//        }
       while  (XGpioPs_ReadPin(
                   &spiLinkDescription_g[localData.drvHdlIdx].gpioInst,
                   SES_PORT_IRQ_GPIO_PIN) ==1U) {//changed to 0
               HandleReceivedMessage(localData.drvHdlIdx);
           }
    }

    /* Signal SpiClose() that we have exited */
    xSemaphoreGive(
        spiLinkDescription_g[localData.drvHdlIdx].rxEventSem);

    vTaskDelete(NULL);
}

/**
 * @brief  GPIO ISR — fires on the rising edge of MIO 62.
 *
 * Clears the interrupt status flag and posts rxEventSem so that TaskSpiIrq
 * wakes up.  Replaces the FT_EVENT_RXCHAR / SetEvent() mechanism.
 *
 * @param callbackRef  Pointer to the XGpioPs instance for this link.
 */
static void GpioIsr(void *callbackRef)
{
    XGpioPs       *gpio_p = (XGpioPs *)callbackRef;
    BaseType_t     xHigherPriorityTaskWoken = pdFALSE;
    u32            pendingIrq;

    /* Read which pins triggered */
    pendingIrq = XGpioPs_IntrGetStatusPin(gpio_p, SES_PORT_IRQ_GPIO_PIN);

    if (pendingIrq) {
        /* Clear the interrupt at the GPIO level */
        XGpioPs_IntrClearPin(gpio_p, SES_PORT_IRQ_GPIO_PIN);

        /*
         * Find the link whose gpioInst matches and post its rxEventSem.
         * In a single-link build this is always index 0; the loop makes
         * it robust for multi-link configurations (SES_PORT_MAX_SPI_LINKS > 1).
         */
        for (int i = 0; i < SES_PORT_MAX_SPI_LINKS; i++) {
            if (spiLinkDescription_g[i].initialized &&
                (&spiLinkDescription_g[i].gpioInst == gpio_p)) {
                xSemaphoreGiveFromISR(
                    spiLinkDescription_g[i].rxEventSem,
                    &xHigherPriorityTaskWoken);
                break;
            }
        }
    }

    /* Yield to a higher-priority task if one was unblocked */
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

/**
 * @brief  Scan the link-description table for a free slot.
 *
 * @return  Table index on success, -1 if all slots are occupied.
 */
static int GetLinkDescriptionEntry(void)
{
    int i;
    int freeEntry = -1;

    for (i = 0; i < SES_PORT_MAX_SPI_LINKS; i++) {
        if (spiLinkDescription_g[i].initialized == 0) {
            freeEntry = i;
            break;
        }
    }

    return freeEntry;
}

/**
 * @brief  Stop the IRQ task, disable the interrupt, and clean up resources.
 *
 * Replaces the Windows TerminateThread / FT4222_UnInitialize / FT_Close
 * sequence.
 */
static int SpiClose(int tblIndex)
{
    TickType_t waitTicks =
        pdMS_TO_TICKS(SES_PORT_SPI_WAIT_THREAD_STOP_MS);

    if (spiLinkDescription_g[tblIndex].irqTask == NULL) {
        DBG_INFO("SpiClose: invalid task handle");
        return SES_PORT_INVALID_PARAM;
    }

    /* ── 1. Ask the IRQ task to exit and wake it up ── */
    spiLinkDescription_g[tblIndex].stopTask = 1;
    xSemaphoreGive(spiLinkDescription_g[tblIndex].rxEventSem);

    /*
     * Wait for the task to re-post the semaphore as its exit handshake.
     * If it doesn't respond within the timeout, we give up and return error.
     */
    if (xSemaphoreTake(spiLinkDescription_g[tblIndex].rxEventSem,
                       waitTicks) != pdTRUE) {
        return SES_PORT_ERROR;
    }

    /* ── 2. Disable the GPIO interrupt ── */
    XGpioPs_IntrDisablePin(
        &spiLinkDescription_g[tblIndex].gpioInst,
        SES_PORT_IRQ_GPIO_PIN);

    XScuGic_Disconnect(&XInterruptController, XPAR_PSU_GPIO_0_INTR);

    /* ── 3. Delete the FreeRTOS binary semaphore ── */
    vSemaphoreDelete(spiLinkDescription_g[tblIndex].rxEventSem);
    spiLinkDescription_g[tblIndex].rxEventSem = NULL;

    /* ── 4. Clear the link-description entry ── */
    SES_PORT_WaitSemaphore(spiLinkDescription_g[tblIndex].spiProtectSem,
                           SES_PORT_PROTECTION_TIMEOUT);
    memset(&spiLinkDescription_g[tblIndex], 0,
           sizeof(SES_PORT_spiLinkDescription_t));
    /* NOTE: spiProtectSem is cleared by the memset above; do not signal
     * it after this point.  The SES_PORT_DeleteSemaphore() was called
     * implicitly when the slot was zeroed — if your RTOS heap requires
     * explicit deletion, call it before the memset. */

    return SES_PORT_OK;
}

// End Static Functions *******************************************************

Parents
  • Hi Karl,

         Sorry for the late replay yes the host strappings are configured in the spi only because with out the correct strappings i can't get the timer0 interrupts that i am getting currently and yes i am following the same intialization in the SES_Adddevice in the MacCheckFirmwareVersion in the bootromsequense it is failing but i am getting the spi reads when i keep the bootromsequence near spiRead function then it is working i am not getting error . the point is near bootromsequence when i am keeping the bootromfunction near the spi read i am not getting timeout when i am keeping it the maccheckfirmwareversion i am getting timeout error 

    Regards,

    Kowsik

  • Hi Kowsik,

    I'm trying to better understand your statement about "keep the bootromsequence near spiRead function"

    Could you please clarify what you mean by this?

    Are you referring to the firmware update sequence?

    You also mentioned that you are no longer encountering an error, are you able to initialize the board successfully?

    Regards,

    Karl

Reply
  • Hi Kowsik,

    I'm trying to better understand your statement about "keep the bootromsequence near spiRead function"

    Could you please clarify what you mean by this?

    Are you referring to the firmware update sequence?

    You also mentioned that you are no longer encountering an error, are you able to initialize the board successfully?

    Regards,

    Karl

Children
No Data

Before You Switch


Switching languages will make ADI Explorer unavailable. Resume your session by switching back to English and reopening ADI Explorer.