Initial version.

This commit is contained in:
Gatsby Van
2023-12-20 00:11:03 +08:00
commit 416bd53733
1043 changed files with 293547 additions and 0 deletions
@@ -0,0 +1,184 @@
/***************************************************************************//**
* @file gpio.c
* @brief Implementation of the GPIO Interface
* @author Antoniu Miclaus ([email protected])
********************************************************************************
* Copyright 2020(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include <inttypes.h>
#include <stdlib.h>
#include "../../include/gpio.h"
#include "../../include/error.h"
/******************************************************************************/
/************************ Functions Definitions *******************************/
/******************************************************************************/
/**
* @brief Obtain the GPIO decriptor.
* @param desc - The GPIO descriptor.
* @param param - GPIO Initialization parameters.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t gpio_get(struct gpio_desc **desc,
const struct gpio_init_param *param)
{
if (!param)
return FAILURE;
if ((param->platform_ops->gpio_ops_get(desc, param)))
return FAILURE;
(*desc)->platform_ops = param->platform_ops;
return SUCCESS;
}
/**
* @brief Get the value of an optional GPIO.
* @param desc - The GPIO descriptor.
* @param param - GPIO Initialization parameters.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t gpio_get_optional(struct gpio_desc **desc,
const struct gpio_init_param *param)
{
if (!param || (param->number == -1)) {
*desc = NULL;
return SUCCESS;
}
if ((param->platform_ops->gpio_ops_get_optional(desc, param)))
return FAILURE;
(*desc)->platform_ops = param->platform_ops;
return SUCCESS;
}
/**
* @brief Free the resources allocated by gpio_get().
* @param desc - The GPIO descriptor.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t gpio_remove(struct gpio_desc *desc)
{
if (desc)
return desc->platform_ops->gpio_ops_remove(desc);
else
return SUCCESS;
}
/**
* @brief Enable the input direction of the specified GPIO.
* @param desc - The GPIO descriptor.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t gpio_direction_input(struct gpio_desc *desc)
{
if (desc)
return desc->platform_ops->gpio_ops_direction_input(desc);
else
return SUCCESS;
}
/**
* @brief Enable the output direction of the specified GPIO.
* @param desc - The GPIO descriptor.
* @param value - The value.
* Example: GPIO_HIGH
* GPIO_LOW
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t gpio_direction_output(struct gpio_desc *desc,
uint8_t value)
{
if (desc)
return desc->platform_ops->
gpio_ops_direction_output(desc, value);
else
return SUCCESS;
}
/**
* @brief Get the direction of the specified GPIO.
* @param desc - The GPIO descriptor.
* @param direction - The direction.
* Example: GPIO_OUT
* GPIO_IN
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t gpio_get_direction(struct gpio_desc *desc,
uint8_t *direction)
{
if (desc)
return desc->platform_ops->
gpio_ops_get_direction(desc, direction);
else
return SUCCESS;
}
/**
* @brief Set the value of the specified GPIO.
* @param desc - The GPIO descriptor.
* @param value - The value.
* Example: GPIO_HIGH
* GPIO_LOW
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t gpio_set_value(struct gpio_desc *desc,
uint8_t value)
{
if (desc)
return desc->platform_ops->gpio_ops_set_value(desc, value);
else
return SUCCESS;
}
/**
* @brief Get the value of the specified GPIO.
* @param desc - The GPIO descriptor.
* @param value - The value.
* Example: GPIO_HIGH
* GPIO_LOW
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t gpio_get_value(struct gpio_desc *desc,
uint8_t *value)
{
if (desc)
return desc->platform_ops->gpio_ops_get_value(desc, value);
else
return SUCCESS;
}
@@ -0,0 +1,153 @@
/***************************************************************************//**
* @file irq.c
* @brief Implementation of the IRQ Interface
* @author Andrei Porumb ([email protected])
********************************************************************************
* Copyright 2021(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include <inttypes.h>
#include <stdlib.h>
#include "../../include/irq.h"
#include "../../include/error.h"
/**
* @brief Initialize the IRQ interrupts.
* @param desc - The IRQ descriptor.
* @param param - The structure that contains the IRQ parameters.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t irq_ctrl_init(struct irq_ctrl_desc **desc,
const struct irq_init_param *param)
{
if (!param)
return FAILURE;
if ((param->platform_ops->init(desc, param)))
return FAILURE;
(*desc)->platform_ops = param->platform_ops;
return SUCCESS;
}
/**
* @brief Free the resources allocated by irq_ctrl_init().
* @param desc - The SPI descriptor.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t irq_ctrl_remove(struct irq_ctrl_desc *desc)
{
return desc->platform_ops->remove(desc);
}
/**
* @brief Register a callback to handle the irq events.
* @param desc - The IRQ controller descriptor.
* @param irq_id - Interrupt identifier.
* @param callback_desc - Callback descriptor
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t irq_register_callback(struct irq_ctrl_desc *desc, uint32_t irq_id,
struct callback_desc *callback_desc)
{
return desc->platform_ops->register_callback(desc, irq_id, callback_desc);
}
/**
* @brief Unregisters a generic IRQ handling function.
* @param desc - The IRQ controller descriptor.
* @param irq_id - Interrupt identifier.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t irq_unregister(struct irq_ctrl_desc *desc, uint32_t irq_id)
{
return desc->platform_ops->unregister(desc, irq_id);
}
/**
* @brief Enable global interrupts.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t irq_global_enable(struct irq_ctrl_desc *desc)
{
return desc->platform_ops->global_enable(desc);
}
/**
* @brief Disable global interrupts.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t irq_global_disable(struct irq_ctrl_desc *desc)
{
return desc->platform_ops->global_disable(desc);
}
/**
* @brief Set interrupt trigger level.
* @param desc - The IRQ controller descriptor.
* @param irq_id - Interrupt identifier.
* @param trig - New trigger level for the interrupt.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t irq_trigger_level_set(struct irq_ctrl_desc *desc, uint32_t irq_id,
enum irq_trig_level trig)
{
if(desc->platform_ops->trigger_level_set)
return desc->platform_ops->trigger_level_set(desc, irq_id, trig);
else
return ENOSYS;
}
/**
* @brief Enable specific interrupt.
* @param desc - The IRQ controller descriptor.
* @param irq_id - Interrupt identifier.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t irq_enable(struct irq_ctrl_desc *desc, uint32_t irq_id)
{
return desc->platform_ops->enable(desc, irq_id);
}
/**
* @brief Disable specific interrupt.
* @param desc - The IRQ controller descriptor.
* @param irq_id - Interrupt identifier.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t irq_disable(struct irq_ctrl_desc *desc, uint32_t irq_id)
{
return desc->platform_ops->disable(desc, irq_id);
}
@@ -0,0 +1,144 @@
/***************************************************************************//**
* @file spi.c
* @brief Implementation of the SPI Interface
* @author Antoniu Miclaus ([email protected])
********************************************************************************
* Copyright 2020(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include "../../include/spi.h"
#include "../../include/error.h"
/**
* @brief Initialize the SPI communication peripheral.
* @param desc - The SPI descriptor.
* @param param - The structure that contains the SPI parameters.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t spi_init(struct spi_desc **desc,
const struct spi_init_param *param)
{
if (!param)
return FAILURE;
if ((param->platform_ops->init(desc, param)))
return FAILURE;
(*desc)->platform_ops = param->platform_ops;
return SUCCESS;
}
/**
* @brief Free the resources allocated by spi_init().
* @param desc - The SPI descriptor.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t spi_remove(struct spi_desc *desc)
{
return desc->platform_ops->remove(desc);
}
/**
* @brief Write and read data to/from SPI.
* @param desc - The SPI descriptor.
* @param data - The buffer with the transmitted/received data.
* @param bytes_number - Number of bytes to write/read.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t spi_write_and_read(struct spi_desc *desc,
uint8_t *data,
uint16_t bytes_number)
{
return desc->platform_ops->write_and_read(desc, data, bytes_number);
}
/**
* @brief Write and read data to/from SPI in 3 wire mode.
* @param desc - The SPI descriptor.
* @param write_data - The buffer with the transmitted data.
* @param read_data - The buffer with the received data.
* @param write_bytes_number - Number of bytes to write.
* @param read_bytes_number - Number of bytes to read.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t spi_write_and_read_3wire(struct spi_desc *desc,
uint8_t *write_data,
uint8_t *read_data,
uint16_t write_bytes_number,
uint16_t read_bytes_number)
{
int ret;
if(desc->platform_ops->write_and_read_3wire != NULL){
return desc->platform_ops->write_and_read_3wire(desc, write_data, read_data,
write_bytes_number, read_bytes_number);
}
else{
return FAILURE;
}
}
/**
* @brief Iterate over head list and send all spi messages
* @param desc - The SPI descriptor.
* @param msgs - Array of messages.
* @param len - Number of messages in the array.
* @return SUCCESS in case of success, negativ error code otherwise.
*/
int32_t spi_transfer(struct spi_desc *desc, struct spi_msg *msgs, uint32_t len)
{
int32_t ret;
uint32_t i;
if (!desc || !desc->platform_ops)
return -EINVAL;
if (desc->platform_ops->transfer)
return desc->platform_ops->transfer(desc, msgs, len);
for (i = 0; i < len; i++) {
if (msgs[i].rx_buff != msgs[i].tx_buff || !msgs[i].tx_buff)
return -EINVAL;
ret = spi_write_and_read(desc, msgs[i].rx_buff,
msgs[i].bytes_number);
if (IS_ERR_VALUE(ret))
return ret;
}
return SUCCESS;
}
@@ -0,0 +1,328 @@
/***************************************************************************//**
* @file axi_dmac.c
* @brief Driver for the Analog Devices AXI-DMAC core.
* @author DBogdan ([email protected])
********************************************************************************
* Copyright 2018(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include "../../../include/axi_io.h"
#include "../../../include/error.h"
#include "../axi_dmac/axi_dmac.h"
/***************************************************************************//**
* @brief dma_isr
*******************************************************************************/
void axi_dmac_default_isr(void *instance)
{
struct axi_dmac *dmac = (struct axi_dmac *)instance;
uint32_t remaining_size, burst_size;
uint32_t reg_val;
/* Get interrupt sources and clear interrupts. */
axi_dmac_read(dmac, AXI_DMAC_REG_IRQ_PENDING, &reg_val);
axi_dmac_write(dmac, AXI_DMAC_REG_IRQ_PENDING, reg_val);
if ((reg_val & AXI_DMAC_IRQ_SOT) && (dmac->big_transfer.size != 0)) {
remaining_size = dmac->big_transfer.size -
dmac->big_transfer.size_done;
burst_size = (remaining_size <= dmac->transfer_max_size) ?
remaining_size : dmac->transfer_max_size;
dmac->big_transfer.size_done += burst_size;
dmac->big_transfer.address += burst_size;
switch (dmac->direction) {
case DMA_DEV_TO_MEM:
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_ADDRESS,
dmac->big_transfer.address);
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_STRIDE, 0x0);
break;
case DMA_MEM_TO_DEV:
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_ADDRESS,
dmac->big_transfer.address);
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_STRIDE, 0x0);
break;
default:
return; // Other directions are not supported yet
}
/* The current transfer was started and a new one is queued. */
axi_dmac_write(dmac, AXI_DMAC_REG_X_LENGTH,
burst_size);
axi_dmac_write(dmac, AXI_DMAC_REG_Y_LENGTH, 0x0);
axi_dmac_write(dmac, AXI_DMAC_REG_START_TRANSFER, 0x1);
}
if (reg_val & AXI_DMAC_IRQ_EOT) {
dmac->big_transfer.transfer_done = true;
dmac->big_transfer.address = 0;
dmac->big_transfer.size = 0;
dmac->big_transfer.size_done = 0;
}
}
/***************************************************************************//**
* @brief axi_dmac_read
*******************************************************************************/
int32_t axi_dmac_read(struct axi_dmac *dmac,
uint32_t reg_addr,
uint32_t *reg_data)
{
axi_io_read(dmac->base, reg_addr, reg_data);
return SUCCESS;
}
/***************************************************************************//**
* @brief axi_dmac_write
*******************************************************************************/
int32_t axi_dmac_write(struct axi_dmac *dmac,
uint32_t reg_addr,
uint32_t reg_data)
{
axi_io_write(dmac->base, reg_addr, reg_data);
return SUCCESS;
}
/***************************************************************************//**
* @brief axi_dmac_transfer_nonblock
*******************************************************************************/
int32_t axi_dmac_transfer_nonblocking(struct axi_dmac *dmac,
uint32_t address, uint32_t size)
{
uint32_t reg_val;
if (size == 0)
return SUCCESS; /* nothing to do */
axi_dmac_read(dmac, AXI_DMAC_REG_CTRL, &reg_val);
if (!(reg_val & AXI_DMAC_CTRL_ENABLE)) {
axi_dmac_write(dmac, AXI_DMAC_REG_CTRL, 0x0);
axi_dmac_write(dmac, AXI_DMAC_REG_CTRL, AXI_DMAC_CTRL_ENABLE);
axi_dmac_write(dmac, AXI_DMAC_REG_IRQ_MASK, 0x0);
}
axi_dmac_read(dmac, AXI_DMAC_REG_START_TRANSFER, &reg_val);
if (!(reg_val & 1)) {
switch (dmac->direction) {
case DMA_DEV_TO_MEM:
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_ADDRESS, address);
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_STRIDE, 0x0);
break;
case DMA_MEM_TO_DEV:
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_ADDRESS, address);
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_STRIDE, 0x0);
break;
default:
return FAILURE; // Other directions are not supported yet
}
if ((size - 1) > dmac->transfer_max_size) {
dmac->big_transfer.address = address;
dmac->big_transfer.size = size - 1;
dmac->big_transfer.size_done = dmac->transfer_max_size;
axi_dmac_write(dmac, AXI_DMAC_REG_X_LENGTH,
dmac->transfer_max_size);
axi_dmac_write(dmac, AXI_DMAC_REG_Y_LENGTH, 0x0);
axi_dmac_write(dmac, AXI_DMAC_REG_FLAGS, dmac->flags);
axi_dmac_write(dmac, AXI_DMAC_REG_START_TRANSFER, 0x1);
} else {
axi_dmac_write(dmac, AXI_DMAC_REG_X_LENGTH,
size - 1);
axi_dmac_write(dmac, AXI_DMAC_REG_Y_LENGTH, 0x0);
axi_dmac_write(dmac, AXI_DMAC_REG_FLAGS, dmac->flags);
axi_dmac_write(dmac, AXI_DMAC_REG_START_TRANSFER, 0x1);
}
} else {
return FAILURE;
}
return SUCCESS;
}
/***************************************************************************//**
* @brief axi_dmac_is_transfer_ready
*******************************************************************************/
int32_t axi_dmac_is_transfer_ready(struct axi_dmac *dmac, bool *rdy)
{
*rdy = dmac->big_transfer.transfer_done;
return SUCCESS;
}
/***************************************************************************//**
* @brief axi_dmac_transfer
*******************************************************************************/
int32_t axi_dmac_transfer(struct axi_dmac *dmac,
uint32_t address, uint32_t size)
{
uint32_t transfer_id;
uint32_t reg_val;
uint32_t timeout = 0;
if (size == 0)
return SUCCESS; /* nothing to do */
axi_dmac_write(dmac, AXI_DMAC_REG_CTRL, 0x0);
axi_dmac_write(dmac, AXI_DMAC_REG_CTRL, AXI_DMAC_CTRL_ENABLE);
axi_dmac_write(dmac, AXI_DMAC_REG_IRQ_MASK, 0x0);
axi_dmac_read(dmac, AXI_DMAC_REG_TRANSFER_ID, &transfer_id);
axi_dmac_read(dmac, AXI_DMAC_REG_IRQ_PENDING, &reg_val);
axi_dmac_write(dmac, AXI_DMAC_REG_IRQ_PENDING, reg_val);
switch (dmac->direction) {
case DMA_DEV_TO_MEM:
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_ADDRESS, address);
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_STRIDE, 0x0);
break;
case DMA_MEM_TO_DEV:
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_ADDRESS, address);
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_STRIDE, 0x0);
break;
default:
return FAILURE; // Other directions are not supported yet
}
if ((size - 1) > dmac->transfer_max_size) {
dmac->big_transfer.address = address;
dmac->big_transfer.size = size - 1;
dmac->big_transfer.size_done = dmac->transfer_max_size;
axi_dmac_write(dmac, AXI_DMAC_REG_X_LENGTH,
dmac->transfer_max_size);
axi_dmac_write(dmac, AXI_DMAC_REG_Y_LENGTH, 0x0);
axi_dmac_write(dmac, AXI_DMAC_REG_FLAGS, dmac->flags);
axi_dmac_write(dmac, AXI_DMAC_REG_START_TRANSFER, 0x1);
while(!dmac->big_transfer.transfer_done) {
timeout++;
if (timeout == UINT32_MAX)
return FAILURE;
}
dmac->big_transfer.address = 0;
dmac->big_transfer.size = 0;
dmac->big_transfer.size_done = 0;
return SUCCESS;
}
axi_dmac_write(dmac, AXI_DMAC_REG_X_LENGTH, size - 1);
axi_dmac_write(dmac, AXI_DMAC_REG_Y_LENGTH, 0x0);
axi_dmac_write(dmac, AXI_DMAC_REG_FLAGS, dmac->flags);
axi_dmac_write(dmac, AXI_DMAC_REG_START_TRANSFER, 0x1);
if (dmac->flags & DMA_CYCLIC)
return SUCCESS;
/* Wait until the new transfer is queued. */
do {
axi_dmac_read(dmac, AXI_DMAC_REG_START_TRANSFER, &reg_val);
} while(reg_val == 1);
/* Wait until the current transfer is completed. */
do {
axi_dmac_read(dmac, AXI_DMAC_REG_IRQ_PENDING, &reg_val);
if (reg_val == (AXI_DMAC_IRQ_SOT | AXI_DMAC_IRQ_EOT))
break;
} while(!dmac->big_transfer.transfer_done);
if (reg_val != (AXI_DMAC_IRQ_SOT | AXI_DMAC_IRQ_EOT))
axi_dmac_write(dmac, AXI_DMAC_REG_IRQ_PENDING, reg_val);
/* Wait until the transfer with the ID transfer_id is completed. */
do {
axi_dmac_read(dmac, AXI_DMAC_REG_TRANSFER_DONE, &reg_val);
} while((reg_val & (1u << transfer_id)) != (1u << transfer_id));
return SUCCESS;
}
/***************************************************************************//**
* @brief axi_dmac_init
*******************************************************************************/
int32_t axi_dmac_init(struct axi_dmac **dmac_core,
const struct axi_dmac_init *init)
{
struct axi_dmac *dmac;
dmac = (struct axi_dmac *)malloc(sizeof(*dmac));
if (!dmac)
return FAILURE;
dmac->name = init->name;
dmac->base = init->base;
dmac->direction = init->direction;
dmac->flags = init->flags;
dmac->transfer_max_size = -1;
dmac->big_transfer.address = 0;
dmac->big_transfer.size = 0;
dmac->big_transfer.size_done = 0;
axi_dmac_write(dmac, AXI_DMAC_REG_X_LENGTH, dmac->transfer_max_size);
axi_dmac_read(dmac, AXI_DMAC_REG_X_LENGTH, &dmac->transfer_max_size);
*dmac_core = dmac;
return SUCCESS;
}
/***************************************************************************//**
* @brief axi_dmac_remove
*******************************************************************************/
int32_t axi_dmac_remove(struct axi_dmac *dmac)
{
if(!dmac)
return FAILURE;
free(dmac);
return SUCCESS;
}
@@ -0,0 +1,124 @@
/***************************************************************************//**
* @file axi_dmac.h
* @brief Driver for the Analog Devices AXI-DMAC core.
* @author DBogdan ([email protected])
********************************************************************************
* Copyright 2018(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef AXI_DMAC_H_
#define AXI_DMAC_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdint.h>
#include "../../../../util/util.h"
/******************************************************************************/
/********************** Macros and Constants Definitions **********************/
/******************************************************************************/
#define AXI_DMAC_REG_IRQ_MASK 0x80
#define AXI_DMAC_REG_IRQ_PENDING 0x84
#define AXI_DMAC_IRQ_SOT BIT(0)
#define AXI_DMAC_IRQ_EOT BIT(1)
#define AXI_DMAC_REG_CTRL 0x400
#define AXI_DMAC_CTRL_ENABLE BIT(0)
#define AXI_DMAC_CTRL_PAUSE BIT(1)
#define AXI_DMAC_REG_TRANSFER_ID 0x404
#define AXI_DMAC_REG_START_TRANSFER 0x408
#define AXI_DMAC_REG_FLAGS 0x40c
#define AXI_DMAC_REG_DEST_ADDRESS 0x410
#define AXI_DMAC_REG_SRC_ADDRESS 0x414
#define AXI_DMAC_REG_X_LENGTH 0x418
#define AXI_DMAC_REG_Y_LENGTH 0x41c
#define AXI_DMAC_REG_DEST_STRIDE 0x420
#define AXI_DMAC_REG_SRC_STRIDE 0x424
#define AXI_DMAC_REG_TRANSFER_DONE 0x428
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
enum dma_direction {
DMA_DEV_TO_MEM,
DMA_MEM_TO_DEV
};
enum dma_flags {
DMA_CYCLIC = 1,
DMA_LAST = 2
};
struct axi_dma_transfer {
uint32_t size;
uint32_t address;
uint32_t size_done;
volatile bool transfer_done;
};
struct axi_dmac {
const char *name;
uint32_t base;
enum dma_direction direction;
uint32_t flags;
uint32_t transfer_max_size;
volatile struct axi_dma_transfer big_transfer;
};
struct axi_dmac_init {
const char *name;
uint32_t base;
enum dma_direction direction;
uint32_t flags;
};
/******************************************************************************/
/************************ Functions Declarations ******************************/
/******************************************************************************/
void axi_dmac_default_isr(void *instance);
int32_t axi_dmac_read(struct axi_dmac *dmac, uint32_t reg_addr,
uint32_t *reg_data);
int32_t axi_dmac_write(struct axi_dmac *dmac, uint32_t reg_addr,
uint32_t reg_data);
int32_t axi_dmac_transfer_nonblocking(struct axi_dmac *dmac,
uint32_t address, uint32_t size);
int32_t axi_dmac_is_transfer_ready(struct axi_dmac *dmac, bool *rdy);
int32_t axi_dmac_transfer(struct axi_dmac *dmac,
uint32_t address, uint32_t size);
int32_t axi_dmac_init(struct axi_dmac **adc_core,
const struct axi_dmac_init *init);
int32_t axi_dmac_remove(struct axi_dmac *dmac);
#endif
@@ -0,0 +1,978 @@
/*******************************************************************************
* @file spi_engine.c
* @brief Core implementation of the SPI Engine Driver.
* @author Sergiu Cuciurean ([email protected])
********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
/* In debug mode the printf function used in displaying the messages is causing
significant delays */
//#define DEBUG_LEVEL 2
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sleep.h>
#include <inttypes.h>
#include "spi_engine.h"
#include "../axi_dmac/axi_dmac.h"
#include "../../../include/axi_io.h"
#include "../../../include/error.h"
/**
* @brief Spi engine platform specific SPI platform ops structure
*/
const struct spi_platform_ops spi_eng_platform_ops = {
.init = &spi_engine_init,
.write_and_read = &spi_engine_spi_write_and_read,
.write_and_read_3wire = &spi_engine_spi_write_and_read_3wire,
.remove = &spi_engine_remove
};
/******************************************************************************/
/***************************** Static variables *******************************/
/******************************************************************************/
/**
* @brief Static variable used to sync transfers
*
*/
static uint8_t _sync_id = 0x01;
/******************************************************************************/
/************************** Functions Implementation **************************/
/******************************************************************************/
/**
* @brief Write SPI Engine's axi registers
*
* @param desc Decriptor containing SPI Engine's parameters
* @param reg_addr The address of the SPI Engine's axi register where the data
* will be written
* @param reg_data Data that will be written
* @return int32_t This function allways returns SUCCESS
*/
int32_t spi_engine_write(struct spi_engine_desc *desc,
uint32_t reg_addr,
uint32_t reg_data)
{
axi_io_write(desc->spi_engine_baseaddr, reg_addr, reg_data);
return SUCCESS;
}
/**
* @brief Read SPI Engine's axi registers
*
* @param desc Decriptor containing SPI Engine's parameters
* @param reg_addr The address of the SPI Engine's axi register from where the
* data where the data will be read
* @param reg_data Pointer where the read that will be stored
* @return int32_t This function allways returns SUCCESS
*/
int32_t spi_engine_read(struct spi_engine_desc *desc,
uint32_t reg_addr,
uint32_t *reg_data)
{
axi_io_read(desc->spi_engine_baseaddr, reg_addr, reg_data);
return SUCCESS;
}
/**
* @brief Set width of the transferred word over SPI
*
* @param desc Decriptor containing SPI interface parameters
* @param data_width The desired data width
* The supported values are:
* - 8
* - 16
* - 24
* - 32
*/
int32_t spi_engine_set_transfer_width(struct spi_desc *desc,
uint8_t data_width)
{
struct spi_engine_desc *desc_extra;
desc_extra = desc->extra;
if (data_width > desc_extra->max_data_width)
desc_extra->data_width = desc_extra->max_data_width;
else
desc_extra->data_width = data_width;
return SUCCESS;
}
/**
* @brief Set SPI engine clock frequency
*
* @param desc Decriptor containing SPI Engine's parameters
* @param speed_hz SPI engine transfer speed
*/
void spi_engine_set_speed(struct spi_desc *desc,
uint32_t speed_hz)
{
struct spi_engine_desc *desc_extra;
desc_extra = desc->extra;
desc_extra->clk_div = desc_extra->ref_clk_hz /
(2 * speed_hz) - 1;
}
/**
* @brief Set the number of words transferred in a single transaction
*
* @param desc Decriptor containing SPI Engine's parameters
* @param bytes_number The number of bytes to be converted
* @return uint8_t A number of words in which bytes_number can be grouped
*/
static uint8_t spi_get_words_number(struct spi_engine_desc *desc,
uint8_t bytes_number)
{
uint8_t xfer_word_len;
uint8_t words_number;
xfer_word_len = desc->data_width / 8;
words_number = bytes_number / xfer_word_len;
if ((bytes_number % xfer_word_len) != 0)
words_number++;
return words_number;
}
/**
* @brief Get the word length in bytes
*
* @param desc Decriptor containing SPI Engine's parameters
* @return uint8_t Number of bytes that fit in one word
*/
static uint8_t spi_get_word_length(struct spi_engine_desc *desc)
{
uint8_t word_length;
word_length = desc->data_width / 8;
return word_length;
}
/**
* @brief Compute the prescaler used to set the sleep period.
*
* @param desc Decriptor containing SPI interface parameters
* @param sleep_time_ns The amount of time where the transfer hangs
* @param sleep_div Clock prescaler
* @return int32_t This function allways returns SUCCESS
*/
static int32_t spi_get_sleep_div(struct spi_desc *desc,
uint32_t sleep_time_ns,
uint32_t *sleep_div)
{
struct spi_engine_desc *eng_desc;
eng_desc = desc->extra;
/*
* Engine Wiki:
*
* The frequency of the SCLK signal is derived from the
* module clock frequency using the following formula:
* f_sclk = f_clk / ((div + 1) * 2)
*/
*sleep_div = (desc->max_speed_hz / 1000000 * sleep_time_ns / 1000) /
((eng_desc->clk_div + 1) * 2) - 1;
return SUCCESS;
}
/**
* @brief Create a new commands queue used in a spi transfer
*
* @param fifo Command buffer, usually used in fifo mode
* @param cmd Command with witch the buffer will be initiated
* @return int32_t Failure if the memory allocation failed
*/
static int32_t spi_engine_queue_new_cmd(struct spi_engine_cmd_queue **fifo,
uint32_t cmd)
{
struct spi_engine_cmd_queue *local_fifo;
local_fifo = (spi_engine_cmd_queue*)malloc(sizeof(*local_fifo));
if(!local_fifo)
return FAILURE;
local_fifo->cmd = cmd;
local_fifo->next = NULL;
*fifo = local_fifo;
return SUCCESS;
}
/**
* @brief Add a command at the end of an existing queue
*
* @param fifo Command buffer, usually used in fifo mode
* @param cmd Command to be added
*/
static void spi_engine_queue_add_cmd(struct spi_engine_cmd_queue **fifo,
uint32_t cmd)
{
struct spi_engine_cmd_queue *to_add = NULL;
struct spi_engine_cmd_queue *local_fifo;
local_fifo = *fifo;
while (local_fifo->next != NULL) {
// Get the last element
local_fifo = local_fifo->next;
}
// Create a new element
spi_engine_queue_new_cmd(&to_add, cmd);
// Add as the next element
local_fifo->next = to_add;
}
/**
* @brief Add a command at the beginning of an existing queue
*
* @param fifo Command buffer, usually used in fifo mode
* @param cmd Command to be added
*/
static void spi_engine_queue_append_cmd(struct spi_engine_cmd_queue **fifo,
uint32_t cmd)
{
struct spi_engine_cmd_queue *to_add = NULL;
// Create a new element
spi_engine_queue_new_cmd(&to_add, cmd);
// Interchange the addresses
to_add->next = *fifo;
*fifo = to_add;
}
/**
* @brief Get the command from the beginning of the queue
*
* @param fifo Command buffer, usually used in fifo mode
* @param cmd Value of the command that was extracted
* @return int32_t Return FAILURE if the queue is empty
*/
static int32_t spi_engine_queue_get_cmd(struct spi_engine_cmd_queue **fifo,
uint32_t *cmd)
{
struct spi_engine_cmd_queue *local_fifo;
if (!*fifo)
return FAILURE;
local_fifo = *fifo;
*cmd = local_fifo->cmd;
if ((*fifo)->next) {
*fifo = local_fifo->next;
free(local_fifo);
} else {
free(*fifo);
*fifo = NULL;
}
return SUCCESS;
}
/**
* @brief Free the memory allocated by a queue
*
* @param fifo The queue that needs it's memory freed
* @return int32_t This function allways return SUCCESS
*/
static int32_t spi_engine_queue_free(struct spi_engine_cmd_queue **fifo)
{
if(*fifo && (*fifo)->next)
spi_engine_queue_free(&(*fifo)->next);
if((*fifo) != NULL) {
free(*fifo);
*fifo = NULL;
}
return SUCCESS;
}
/**
* @brief Write the SPI engine's command fifo
*
* @param desc Decriptor containing SPI Engine's parameters
* @param cmd The command that will be written
* @return int32_t Returns FAILURE if the the axi transfer failed
*/
static int32_t spi_engine_write_cmd_reg(struct spi_engine_desc *desc,
uint32_t cmd)
{
int32_t ret;
/* Check if offload is enabled */
if(desc->offload_config & (OFFLOAD_TX_EN | OFFLOAD_RX_EN)) {
ret = spi_engine_write(desc,
SPI_ENGINE_REG_OFFLOAD_CMD_MEM(0),
cmd);
} else {
ret = spi_engine_write(desc,
SPI_ENGINE_REG_CMD_FIFO,
cmd);
}
return ret;
}
/**
* @brief Write a transfer command to the SPI engine's command fifo
*
* @param desc Decriptor containing SPI Engine's parameters
* @param read_write Read/Write operation flag
* @param bytes_number Number of bytes to transfer
* @return int32_t This function allways returns SUCCESS
*/
static int32_t spi_engine_transfer(struct spi_engine_desc *desc,
uint8_t read_write,
uint8_t bytes_number)
{
uint8_t words_number;
words_number = spi_get_words_number(desc, bytes_number);
desc->offload_tx_len += words_number;
/*
* Engine Wiki:
*
* https://wiki.analog.com/resources/fpga/peripherals/spi_engine
*
* The words number is zero based
*/
spi_engine_write_cmd_reg(desc,
SPI_ENGINE_CMD_TRANSFER(read_write,
words_number - 1));
return SUCCESS;
}
/**
* @brief Change the state of the chip select port
*
* @param desc Decriptor containing SPI interface parameters
* @param assert Chip select state.
* The supported values are :
* -true (HIGH)
* -false (LOW)
*/
static void spi_engine_set_cs(struct spi_desc *desc,
bool assert)
{
uint8_t mask;
struct spi_engine_desc *eng_desc;
eng_desc = desc->extra;
mask = 0xFF;
/* Switch the state only of the selected chip select */
if (!assert)
mask ^= BIT(desc->chip_select);
spi_engine_write_cmd_reg(eng_desc,
SPI_ENGINE_CMD_ASSERT(eng_desc->cs_delay,
mask));
}
/**
* @brief Add a delay between the engine commands
*
* @param desc Decriptor containing SPI interface parameters
* @param sleep_time_ns Number of nanoseconds to sleep between commands
*/
static void spi_gen_sleep_ns(struct spi_desc *desc,
uint32_t sleep_time_ns)
{
uint32_t sleep_div;
struct spi_engine_desc *eng_desc;
eng_desc = desc->extra;
spi_get_sleep_div(desc, sleep_time_ns, &sleep_div);
spi_engine_write_cmd_reg(eng_desc, SPI_ENGINE_CMD_SLEEP(sleep_div));
}
/**
* @brief Spi engine command interpreter
*
* @param desc Decriptor containing SPI interface parameters
* @param cmd Command to send to the engine
* @return int32_t - SUCCESS if the command is transferred
* - FAILURE if the command format is invalid
*/
static int32_t spi_engine_write_cmd(struct spi_desc *desc,
uint32_t cmd)
{
uint8_t engine_command;
uint8_t parameter;
uint8_t modifier;
struct spi_engine_desc *desc_extra;
desc_extra = desc->extra;
engine_command = (cmd >> 12) & 0x0F;
modifier = (cmd >> 8) & 0x0F;
parameter = cmd & 0xFF;
switch(engine_command) {
case SPI_ENGINE_INST_TRANSFER:
spi_engine_transfer(desc_extra, modifier, parameter);
break;
case SPI_ENGINE_INST_ASSERT:
if(parameter == 0xFF) {
/* Set the CS HIGH */
spi_engine_set_cs(desc, true);
} else if(parameter == 0x00) {
/* Set the CS LOW */
spi_engine_set_cs(desc, false);
}
break;
/* The SYNC and SLEEP commands got the same value but different
modifier */
case SPI_ENGINE_INST_SYNC_SLEEP:
/* SYNC instruction */
if(modifier == 0x00) {
spi_engine_write_cmd_reg(desc_extra, cmd);
} else if(modifier == 0x01) {
spi_gen_sleep_ns(desc, parameter);
}
break;
case SPI_ENGINE_INST_CONFIG:
spi_engine_write_cmd_reg(desc_extra, cmd);
break;
default:
return FAILURE;
}
return SUCCESS;
}
/**
* @brief Prepare the command queue before sending it to the engine
*
* @param desc Decriptor containing SPI interface parameters
* @param msg Structure used to store the transfer messages
* @return int32_t This function allways returns SUCCESS
*/
static int32_t spi_engine_compile_message(struct spi_desc *desc,
struct spi_engine_msg *msg)
{
struct spi_engine_desc *desc_extra;
desc_extra = desc->extra;
/* Configure the prescaler */
spi_engine_queue_append_cmd(&msg->cmds,
SPI_ENGINE_CMD_CONFIG(
SPI_ENGINE_CMD_REG_CLK_DIV,
desc_extra->clk_div));
/* Set the data transfer length */
spi_engine_queue_append_cmd(&msg->cmds,
SPI_ENGINE_CMD_CONFIG(
SPI_ENGINE_CMD_DATA_TRANSFER_LEN,
desc_extra->data_width));
/*
* Configure the spi mode :
* - 3 wire
* - CPOL
* - CPHA
*/
spi_engine_queue_append_cmd(&msg->cmds,
SPI_ENGINE_CMD_CONFIG(
SPI_ENGINE_CMD_REG_CONFIG,
desc->mode));
/* Add a sync command to signal that the transfer has finished */
spi_engine_queue_add_cmd(&msg->cmds, SPI_ENGINE_CMD_SYNC(_sync_id));
return SUCCESS;
}
/**
* @brief Initiate a spi transfer (Blocking)
*
* @param desc Decriptor containing SPI interface parameters
* @param msg Structure used to store the transfer messages
* @return int32_t - SUCCESS if the transfer finished
* - FAILURE if the memory allocation failed
*/
static int32_t spi_engine_transfer_message(struct spi_desc *desc,
struct spi_engine_msg *msg)
{
uint32_t i;
uint32_t data;
uint32_t sync_id;
bool offload_en;
struct spi_engine_desc *desc_extra;
desc_extra = desc->extra;
spi_engine_compile_message(desc, msg);
offload_en = (desc_extra->offload_config & OFFLOAD_TX_EN) |
(desc_extra->offload_config & OFFLOAD_RX_EN);
/* Write the command fifo buffer */
while(msg->cmds != NULL) {
spi_engine_queue_get_cmd(&msg->cmds, &data);
spi_engine_write_cmd(desc, data);
}
/* Write a number of tx_length WORDS on the SDO line */
if(offload_en) {
for(i = 0; i < desc_extra->offload_tx_len; i++)
spi_engine_write(desc_extra,
SPI_ENGINE_REG_OFFLOAD_SDO_MEM(0),
msg->tx_buf[i]);
} else {
if(msg->tx_buf != NULL){
for(i = 0; i < msg->tx_length; i++)
spi_engine_write(desc_extra,
SPI_ENGINE_REG_SDO_DATA_FIFO,
msg->tx_buf[i]);
}
do {
spi_engine_read(desc_extra,
SPI_ENGINE_REG_SYNC_ID,
&sync_id);
}
/* Wait for the end sync signal */
while(sync_id != _sync_id);
_sync_id++;
/* Read a number of rx_length WORDS from the SDI line and store
them */
for(i = 0; i < msg->rx_length; i++) {
spi_engine_read(desc_extra,
SPI_ENGINE_REG_SDI_DATA_FIFO,
&data);
/* Store the rx data if rx buffer valid, flush sdi_fifo if
rx buffer is invalid.*/
if(msg->rx_buf != NULL){
msg->rx_buf[i] = data;
}
}
}
return SUCCESS;
}
/**
* @brief Initialize the spi engine
*
* @param desc Decriptor containing SPI interface parameters
* @param param Structure containing the spi init parameters
* @return int32_t - SUCCESS if the transfer finished
* - FAILURE if the memory allocation failed
*/
int32_t spi_engine_init(struct spi_desc **desc,
const struct spi_init_param *param)
{
uint32_t data_width = 0;
uint32_t spi_engine_version = 0;
struct spi_engine_desc *eng_desc;
struct spi_engine_init_param *spi_engine_init;
if (!param) {
return FAILURE;
}
*desc = malloc(sizeof(**desc));
if(! *desc) {
free(*desc);
return FAILURE;
}
eng_desc = (struct spi_engine_desc*)malloc(sizeof(*eng_desc));
if (!eng_desc)
return FAILURE;
spi_engine_init = param->extra;
(*desc)->max_speed_hz = param->max_speed_hz;
(*desc)->chip_select = param->chip_select;
(*desc)->mode = param->mode;
(*desc)->extra = eng_desc;
eng_desc->offload_config = OFFLOAD_DISABLED;
eng_desc->spi_engine_baseaddr = spi_engine_init->spi_engine_baseaddr;
eng_desc->type = spi_engine_init->type;
eng_desc->cs_delay = spi_engine_init->cs_delay;
eng_desc->ref_clk_hz = spi_engine_init->ref_clk_hz;
eng_desc->clk_div = eng_desc->ref_clk_hz /
(2 * param->max_speed_hz) - 1;
/* Perform a reset */
spi_engine_write(eng_desc, SPI_ENGINE_REG_RESET, 0x01);
usleep(1000);
spi_engine_write(eng_desc, SPI_ENGINE_REG_RESET, 0x00);
/* Get current data width */
spi_engine_read(eng_desc, SPI_ENGINE_REG_DATA_WIDTH, &data_width);
eng_desc->max_data_width = data_width;
spi_engine_set_transfer_width(*desc, spi_engine_init->data_width);
/* Get spi engine version */
spi_engine_read(eng_desc, SPI_ENGINE_REG_VERSION, &spi_engine_version);
printf("Spi engine v%"PRIu32".%"PRIu32".%"PRIu32" successfully initialized.\n",
(spi_engine_version >> 16),
((spi_engine_version >> 8) & 0xFF),
(spi_engine_version & 0xFF));
return SUCCESS;
}
/**
* @brief Write and read on the spi interface in 4-wire mode (full-duplex)
*
* @param desc Decriptor containing SPI interface parameters
* @param data Pointer to data buffer
* @param bytes_number Number of bytes to transfer
* @return int32_t - SUCCESS if the transfer finished
* - FAILURE if the memory allocation or transfer failed
*/
int32_t spi_engine_spi_write_and_read(struct spi_desc *desc,
uint8_t *data,
uint16_t bytes_number)
{
uint8_t word_len;
uint8_t words_number;
int32_t ret;
struct spi_engine_msg msg;
struct spi_engine_desc *desc_extra;
desc_extra = desc->extra;
/* If we want to access SPI interface and SPI engine offload module was
* activated, we need to disable it
* This is set in spi_engine_offload_init() */
desc_extra->offload_config = OFFLOAD_DISABLED;
/* This is set in spi_engine_offload_transfer() */
spi_engine_write(desc_extra, SPI_ENGINE_REG_OFFLOAD_CTRL(0), 0);
words_number = spi_get_words_number(desc_extra, bytes_number);
msg.cmds = (spi_engine_cmd_queue*)malloc(sizeof(*msg.cmds));
if (!msg.cmds)
return FAILURE;
msg.tx_buf =(uint32_t*)calloc(words_number, sizeof(msg.tx_buf[0]));
msg.rx_buf =(uint32_t*)calloc(words_number, sizeof(msg.rx_buf[0]));
msg.tx_length = words_number;
msg.rx_length = words_number;
/* Get the length of transferred word */
word_len = spi_get_word_length(desc_extra);
/* Make sure the CS is HIGH before starting a transaction */
msg.cmds->next = NULL;
msg.cmds->cmd = CS_HIGH;
// Assert select.
spi_engine_queue_add_cmd(&msg.cmds, CS_LOW);
// add read/write command
spi_engine_queue_add_cmd(&msg.cmds, WRITE_READ(bytes_number));
// Disable select.
spi_engine_queue_add_cmd(&msg.cmds, CS_HIGH);
/* Pack the bytes into engine WORDS */
for (int i = 0; i < bytes_number; i++)
msg.tx_buf[i / word_len] |= data[i] << (desc_extra->data_width-
(i % word_len + 1) * 8);
ret = spi_engine_transfer_message(desc, &msg);
for (int i = 0; i < bytes_number; i++)
data[i] = msg.rx_buf[(i) / word_len] >>
(desc_extra->data_width -
((i) % word_len + 1) * 8);
spi_engine_queue_free(&msg.cmds);
free(msg.tx_buf);
free(msg.rx_buf);
return ret;
}
/**
* @brief Write and read on the spi interface in 3-wire mode (half-duplex)
*
* @param desc Decriptor containing SPI interface parameters
* @param data Pointer to data buffer
* @param bytes_number Number of bytes to transfer
* @return int32_t - SUCCESS if the transfer finished
* - FAILURE if the memory allocation or transfer failed
*/
int32_t spi_engine_spi_write_and_read_3wire(struct spi_desc *desc,
uint8_t *write_data,
uint8_t *read_data,
uint16_t write_bytes_number,
uint16_t read_bytes_number)
{
uint8_t word_len;
uint8_t wr_words_number;
uint8_t rd_words_number;
int32_t ret;
struct spi_engine_msg msg;
struct spi_engine_desc *desc_extra;
desc_extra = desc->extra;
/* If we want to access SPI interface and SPI engine offload module was
* activated, we need to disable it
* This is set in spi_engine_offload_init() */
desc_extra->offload_config = OFFLOAD_DISABLED;
/* This is set in spi_engine_offload_transfer() */
spi_engine_write(desc_extra, SPI_ENGINE_REG_OFFLOAD_CTRL(0), 0);
wr_words_number = spi_get_words_number(desc_extra, write_bytes_number);
rd_words_number = spi_get_words_number(desc_extra, read_bytes_number);
msg.cmds = (spi_engine_cmd_queue*)malloc(sizeof(*msg.cmds));
if (!msg.cmds)
return FAILURE;
msg.tx_buf =(wr_words_number>0)?(uint32_t*)calloc(wr_words_number, sizeof(msg.tx_buf[0])):NULL;
msg.rx_buf =(rd_words_number>0)?(uint32_t*)calloc(rd_words_number, sizeof(msg.rx_buf[0])):NULL;
msg.tx_length = wr_words_number;
msg.rx_length = rd_words_number;
/* Get the length of transferred word */
word_len = spi_get_word_length(desc_extra);
/* Make sure the CS is HIGH before starting a transaction */
msg.cmds->next = NULL;
msg.cmds->cmd = CS_HIGH;
// Assert select.
spi_engine_queue_add_cmd(&msg.cmds, CS_LOW);
// add read/write command
if(write_bytes_number > 0)
spi_engine_queue_add_cmd(&msg.cmds, WRITE(write_bytes_number));
if(read_bytes_number > 0)
spi_engine_queue_add_cmd(&msg.cmds, READ(read_bytes_number));
// Disable select.
spi_engine_queue_add_cmd(&msg.cmds, CS_HIGH);
/* Pack the bytes into engine WORDS */
for (int i = 0; i < write_bytes_number; i++)
msg.tx_buf[i / word_len] |= write_data[i] << (desc_extra->data_width-
(i % word_len + 1) * 8);
ret = spi_engine_transfer_message(desc, &msg);
for (int i = 0; i < read_bytes_number; i++)
read_data[i] = msg.rx_buf[(i) / word_len] >>
(desc_extra->data_width -
((i) % word_len + 1) * 8);
spi_engine_queue_free(&msg.cmds);
free(msg.tx_buf);
free(msg.rx_buf);
return ret;
}
/**
* @brief Initialize the SPI engine's offload module
*
* @param desc Decriptor containing SPI interface parameters
* @param param Structure containing the offload init parameters
* @return int32_t This function allways returns SUCCESS
*/
int32_t spi_engine_offload_init(struct spi_desc *desc,
const struct spi_engine_offload_init_param *param)
{
struct spi_engine_desc *eng_desc;
struct axi_dmac_init dmac_init;
uint32_t dma_flags;
eng_desc = desc->extra;
eng_desc->offload_config = param->offload_config;
if(!(param->dma_flags))
dma_flags = DMA_CYCLIC;
else
dma_flags = *(param->dma_flags);
if(param->offload_config & OFFLOAD_TX_EN) {
dmac_init.name = "DAC DMAC";
dmac_init.base = param->tx_dma_baseaddr;
dmac_init.direction = DMA_MEM_TO_DEV;
dmac_init.flags = dma_flags;
axi_dmac_init(&eng_desc->offload_tx_dma, &dmac_init);
if(!eng_desc->offload_tx_dma)
return FAILURE;
}
if(param->offload_config & OFFLOAD_RX_EN) {
dmac_init.name = "ADC DMAC";
dmac_init.base = param->rx_dma_baseaddr;
dmac_init.direction = DMA_DEV_TO_MEM;
dmac_init.flags = dma_flags;
axi_dmac_init(&eng_desc->offload_rx_dma, &dmac_init);
if(!eng_desc->offload_rx_dma)
return FAILURE;
}
return SUCCESS;
}
/**
* @brief Initiate a SPI transfer in offload mode
*
* @param desc Decriptor containing SPI interface parameters
* @param msg Offload message that get's to be transferred
* @param no_samples Number of time the messages will be transferred
* @return int32_t This function allways returns SUCCESS
*/
int32_t spi_engine_offload_transfer(struct spi_desc *desc,
struct spi_engine_offload_message msg,
uint32_t no_samples)
{
struct spi_engine_msg transfer;
struct spi_engine_desc *eng_desc;
uint32_t i;
uint8_t word_length;
eng_desc = desc->extra;
/* Check if offload is disabled */
if(!((eng_desc->offload_config & OFFLOAD_TX_EN) |
(eng_desc->offload_config & OFFLOAD_RX_EN)))
return FAILURE;
spi_engine_write(eng_desc, SPI_ENGINE_REG_OFFLOAD_RESET(0), 1);
spi_engine_write(eng_desc, SPI_ENGINE_REG_OFFLOAD_RESET(0), 0);
eng_desc->offload_tx_len = 0;
eng_desc->offload_rx_len = 0;
transfer.cmds = (spi_engine_cmd_queue*)malloc(sizeof(*transfer.cmds));
if (!transfer.cmds)
return FAILURE;
transfer.tx_buf = msg.commands_data;
/* Load the commands into the message */
transfer.cmds->next = NULL;
transfer.cmds->cmd = msg.commands[0];
i = 1;
while(i < msg.no_commands) {
spi_engine_queue_add_cmd(&transfer.cmds, msg.commands[i++]);
}
spi_engine_transfer_message(desc, &transfer);
/* Start transfer */
spi_engine_write(eng_desc, SPI_ENGINE_REG_OFFLOAD_CTRL(0), 0x0001);
word_length = spi_get_word_length(eng_desc);
if(eng_desc->offload_config & OFFLOAD_TX_EN) {
axi_dmac_transfer(eng_desc->offload_tx_dma,
msg.tx_addr,
word_length * eng_desc->offload_tx_len *
no_samples);
}
if(eng_desc->offload_config & OFFLOAD_RX_EN) {
axi_dmac_transfer(eng_desc->offload_rx_dma,
msg.rx_addr,
word_length * eng_desc->offload_tx_len *
no_samples);
}
usleep(1000);
spi_engine_queue_free(&transfer.cmds);
return SUCCESS;
}
/**
* @brief Free the resources allocated by spi_init().
*
* @param desc Decriptor containing SPI interface parameters
* @return int32_t This function allways returns SUCCESS
*/
int32_t spi_engine_remove(struct spi_desc *desc)
{
struct spi_engine_desc *eng_desc;
eng_desc = desc->extra;
if(eng_desc->offload_config & OFFLOAD_TX_EN)
axi_dmac_remove(eng_desc->offload_tx_dma);
if(eng_desc->offload_config & OFFLOAD_RX_EN)
axi_dmac_remove(eng_desc->offload_rx_dma);
free(desc->extra);
free(desc);
return SUCCESS;
}
@@ -0,0 +1,231 @@
/*******************************************************************************
* @file spi_engine.h
* @brief Header file of SPI Engine core features.
* @author Sergiu Cuciurean ([email protected])
********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef SPI_ENGINE_H
#define SPI_ENGINE_H
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdint.h>
#include "spi_engine_private.h"
#include "../../platform/spi_extra.h"
/******************************************************************************/
/********************** Macros and Constants Definitions **********************/
/******************************************************************************/
#define OFFLOAD_DISABLED 0x00
#define OFFLOAD_TX_EN BIT(0)
#define OFFLOAD_RX_EN BIT(1)
#define OFFLOAD_TX_RX_EN OFFLOAD_TX_EN | OFFLOAD_RX_EN
#define SPI_ENGINE_MSG_QUEUE_END 0xFFFFFFFF
/* Spi engine commands */
#define WRITE_OR_READ(mode, no_bytes) ((SPI_ENGINE_INST_TRANSFER << 12) |\
((mode) << 8) | (no_bytes))
#define WRITE(no_bytes) ((SPI_ENGINE_INST_TRANSFER << 12) |\
(SPI_ENGINE_INSTRUCTION_TRANSFER_W << 8) | (no_bytes))
#define READ(no_bytes) ((SPI_ENGINE_INST_TRANSFER << 12) |\
(SPI_ENGINE_INSTRUCTION_TRANSFER_R << 8) | (no_bytes))
#define WRITE_READ(no_bytes) ((SPI_ENGINE_INST_TRANSFER << 12) |\
(SPI_ENGINE_INSTRUCTION_TRANSFER_RW << 8) | (no_bytes))
#define SLEEP(time) SPI_ENGINE_CMD_SLEEP(time & 0xF)
/* The delay and chip select parmeters are passed over the engine descriptor
and will be used inside the function call */
#define CS_HIGH SPI_ENGINE_CMD_ASSERT(0x00, 0xFF)
#define CS_LOW SPI_ENGINE_CMD_ASSERT(0x00, 0x00)
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
/**
* @struct spi_engine_init_param
* @brief Structure containing the init parameters needed by the SPI engine
*/
struct spi_engine_init_param {
/** SPI engine reference clock */
uint32_t ref_clk_hz;
/** Type of implementation */
enum xil_spi_type type;
/** Base address where the HDL core is situated */
uint32_t spi_engine_baseaddr;
/** Delay between the CS toggle and the start of SCLK */
uint32_t cs_delay;
/** Data with of one SPI transfer ( in bits ) */
uint8_t data_width;
};
/**
* @struct spi_engine_desc
* @brief Structure representing an SPI engine device
*/
struct spi_engine_desc {
/** SPI engine reference clock */
uint32_t ref_clk_hz;
/** Type of implementation */
enum xil_spi_type type;
/** Pointer to a DMAC used in transmission */
struct axi_dmac *offload_tx_dma;
/** Pointer to a DMAC used in reception */
struct axi_dmac *offload_rx_dma;
/** Offload's module transfer direction : TX, RX or both */
uint8_t offload_config;
/** Number of words that the module has to send */
uint8_t offload_tx_len;
/** Number of words that the module has to receive */
uint8_t offload_rx_len;
/** Base address where the HDL core is situated */
uint32_t spi_engine_baseaddr;
/** Base address where the RX DMAC core is situated */
uint32_t rx_dma_baseaddr;
/** Base address where the TX DMAC core is situated */
uint32_t tx_dma_baseaddr;
/** Delay between the CS toggle and the start of SCLK */
uint8_t cs_delay;
/** Clock divider used in transmission delays */
uint32_t clk_div;
/** Data with of one SPI transfer ( in bits ) */
uint8_t data_width;
/** The maximum data width supported by the engine */
uint8_t max_data_width;
};
/**
* @struct spi_engine_offload_init_param
* @brief Structure containing the init parameters needed by the offload module
*/
struct spi_engine_offload_init_param {
/** Base address where the RX DMAC core is situated */
uint32_t rx_dma_baseaddr;
/** Base address where the TX DMAC core is situated */
uint32_t tx_dma_baseaddr;
/** DMAC flags - if not initialized, the default value is DMA_CYCLIC */
uint32_t *dma_flags;
/** Offload's module transfer direction : TX, RX or both */
uint8_t offload_config;
};
/**
* @struct spi_engine_offload_message
* @brief Structure representing an offload message
*/
struct spi_engine_offload_message {
/** Pointer to the SPI engine commands buffer that will be sent.
* The available commands can be found at:
* https://wiki.analog.com/resources/fpga/peripherals/spi_engine/
*/
uint32_t *commands;
/** Length of the SPI engine commands buffer */
uint32_t no_commands;
/** Pointer of the data that will be sent over spi */
uint32_t *commands_data;
/** The address where the data that will be transmitted is situated */
uint32_t tx_addr;
/** The address where the data that will be received is situated */
uint32_t rx_addr;
};
/******************************************************************************/
/************************ Functions Declarations ******************************/
/******************************************************************************/
/**
* @brief Spi engine platform specific SPI platform ops structure
*/
extern const struct spi_platform_ops xil_spi_ops;
/* Write SPI Engine's axi registers */
int32_t spi_engine_write(struct spi_engine_desc *desc,
uint32_t reg_addr,
uint32_t reg_data);
/* Read SPI Engine's axi registers */
int32_t spi_engine_read(struct spi_engine_desc *desc,
uint32_t reg_addr,
uint32_t *reg_data);
/* Initialize the SPI engine device */
int32_t spi_engine_init(struct spi_desc **desc,
const struct spi_init_param *param);
/* Write and read data over SPI using the SPI engine */
int32_t spi_engine_spi_write_and_read(struct spi_desc *desc,
uint8_t *data,
uint16_t bytes_number);
/* Write and read data over SPI using the SPI engine in 3-wire mode */
int32_t spi_engine_spi_write_and_read_3wire(struct spi_desc *desc,
uint8_t *write_data,
uint8_t *read_data,
uint16_t write_bytes_number,
uint16_t read_bytes_number);
/* Free the resources used by the SPI engine device */
int32_t spi_engine_remove(struct spi_desc *desc);
/* Initialize the SPI engine offload module */
int32_t spi_engine_offload_init(struct spi_desc *desc,
const struct spi_engine_offload_init_param *param);
/* Write and read data over SPI using the offload module */
int32_t spi_engine_offload_transfer(struct spi_desc *desc,
struct spi_engine_offload_message msg,
uint32_t no_samples);
/* Set SPI transfer width */
int32_t spi_engine_set_transfer_width(struct spi_desc *desc,
uint8_t data_wdith);
/* Set SPI transfer speed */
void spi_engine_set_speed(struct spi_desc *desc,
uint32_t speed_hz);
#endif // SPI_ENGINE_H
@@ -0,0 +1,154 @@
/*******************************************************************************
* @file spi_engine_private.h
* @brief Private definitions of the SPI Engine
* @author Sergiu Cuciurean ([email protected])
********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef SPI_ENGINE_PRIVATE_H
#define SPI_ENGINE_PRIVATE_H
#include <stdint.h>
#include <stdbool.h>
#include "../../../include/spi.h"
#include "../../../../util/util.h"
/******************************************************************************/
/*************************** Spi Engine registers *****************************/
/******************************************************************************/
#define SPI_ENGINE_REG_VERSION 0x00
#define SPI_ENGINE_REG_DATA_WIDTH 0x0C
#define SPI_ENGINE_REG_RESET 0x40
#define SPI_ENGINE_REG_INT_ENABLE 0x80
#define SPI_ENGINE_REG_INT_PENDING 0x84
#define SPI_ENGINE_REG_INT_SOURCE 0x88
#define SPI_ENGINE_REG_SYNC_ID 0xC0
#define SPI_ENGINE_REG_CMD_FIFO_ROOM 0xD0
#define SPI_ENGINE_REG_SDO_FIFO_ROOM 0xD4
#define SPI_ENGINE_REG_SDI_FIFO_LEVEL 0xD8
#define SPI_ENGINE_REG_CMD_FIFO 0xE0
#define SPI_ENGINE_REG_SDO_DATA_FIFO 0xE4
#define SPI_ENGINE_REG_SDI_DATA_FIFO 0xE8
#define SPI_ENGINE_REG_SDI_DATA_FIFO_PEEK 0xEC
/******************************************************************************/
/************************ Spi Engine register parameters **********************/
/******************************************************************************/
#define SPI_ENGINE_INST_TRANSFER 0x00
#define SPI_ENGINE_INST_ASSERT 0x01
#define SPI_ENGINE_INST_CONFIG 0x02
#define SPI_ENGINE_INST_SYNC_SLEEP 0x03
#define SPI_ENGINE_INST_MISC 0x03
#define SPI_ENGINE_CMD_REG_CLK_DIV 0x00
#define SPI_ENGINE_CMD_REG_CONFIG 0x01
#define SPI_ENGINE_CMD_DATA_TRANSFER_LEN 0x02
#define SPI_ENGINE_MISC_SYNC 0x00
#define SPI_ENGINE_MISC_SLEEP 0x01
#define SPI_ENGINE_SYNC_TRANSFER_BEGIN BIT(1)
#define SPI_ENGINE_SYNC_TRANSFER_END BIT(2)
#define SPI_ENGINE_INT_CMD_ALMOST_EMPTY BIT(0)
#define SPI_ENGINE_INT_SDO_ALMOST_EMPTY BIT(1)
#define SPI_ENGINE_INT_SDI_ALMOST_FULL BIT(2)
#define SPI_ENGINE_INT_SYNC BIT(3)
#define SPI_ENGINE_OFFLOAD_CTRL_ENABLE BIT(0)
#define SPI_ENGINE_OFFLOAD_STATUS_ENABLED BIT(0)
#define SPI_ENGINE_CONFIG_CPHA BIT(0)
#define SPI_ENGINE_CONFIG_CPOL BIT(1)
#define SPI_ENGINE_CONFIG_3WIRE BIT(2)
#define SPI_ENGINE_VERSION_MAJOR(x) ((x >> 16) & 0xff)
#define SPI_ENGINE_VERSION_MINOR(x) ((x >> 8) & 0xff)
#define SPI_ENGINE_VERSION_PATCH(x) (x & 0xff)
/******************************************************************************/
/**************************** Spi Engine commands *****************************/
/******************************************************************************/
#define SPI_ENGINE_INSTRUCTION_TRANSFER_W 0x01
#define SPI_ENGINE_INSTRUCTION_TRANSFER_R 0x02
#define SPI_ENGINE_INSTRUCTION_TRANSFER_RW 0x03
#define SPI_ENGINE_REG_OFFLOAD_CTRL(x) (0x100 + (0x20 * x))
#define SPI_ENGINE_REG_OFFLOAD_STATUS(x) (0x104 + (0x20 * x))
#define SPI_ENGINE_REG_OFFLOAD_RESET(x) (0x108 + (0x20 * x))
#define SPI_ENGINE_REG_OFFLOAD_CMD_MEM(x) (0x110 + (0x20 * x))
#define SPI_ENGINE_REG_OFFLOAD_SDO_MEM(x) (0x114 + (0x20 * x))
#define SPI_ENGINE_CMD(inst, arg1, arg2) \
(((inst & 0x03) << 12) | \
((arg1 & 0x03) << 8) | arg2 )
#define SPI_ENGINE_CMD_TRANSFER(readwrite, n) \
SPI_ENGINE_CMD(SPI_ENGINE_INST_TRANSFER, \
(readwrite), (n))
#define SPI_ENGINE_CMD_ASSERT(delay, cs) \
SPI_ENGINE_CMD(SPI_ENGINE_INST_ASSERT, \
(delay), (cs))
#define SPI_ENGINE_CMD_CONFIG(reg, val) \
SPI_ENGINE_CMD(SPI_ENGINE_INST_CONFIG, \
(reg), (val))
#define SPI_ENGINE_CMD_SLEEP(delay) \
SPI_ENGINE_CMD(SPI_ENGINE_INST_MISC, \
SPI_ENGINE_MISC_SLEEP, \
(delay))
#define SPI_ENGINE_CMD_SYNC(id) \
SPI_ENGINE_CMD(SPI_ENGINE_INST_MISC, \
SPI_ENGINE_MISC_SYNC, \
(id))
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
typedef struct spi_engine_cmd_queue {
uint32_t cmd;
struct spi_engine_cmd_queue *next;
} spi_engine_cmd_queue;
typedef struct spi_engine_msg {
uint32_t *tx_buf;
uint32_t *rx_buf;
uint32_t tx_length;
uint32_t rx_length;
struct spi_engine_cmd_queue *cmds;
} spi_engine_msg;
#endif // SPI_ENGINE_PRIVATE_H
@@ -0,0 +1,129 @@
/***************************************************************************//**
* @file ad9516.c
* @brief Implementation of AD9680 Driver.
* @author DBogdan ([email protected])
********************************************************************************
* Copyright 2014-2016(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include "ad9516.h"
#include <stdlib.h>
#include <stdio.h>
#include "../../../include/error.h"
/***************************************************************************//**
* @brief ad9516_read
*******************************************************************************/
int32_t ad9516_read(struct ad9516_dev *dev,
uint16_t reg_addr,
uint8_t *reg_data)
{
uint8_t tx_buf[2];
uint8_t rx_buf[1];
int32_t ret;
tx_buf[0] = 0x80 | (reg_addr >> 8);
tx_buf[1] = reg_addr & 0xFF;
ret = spi_write_and_read_3wire(dev->spi_desc,
tx_buf, rx_buf, 2, 1);
*reg_data = rx_buf[0];
return ret;
}
/***************************************************************************//**
* @brief ad9516_write
*******************************************************************************/
int32_t ad9516_write(struct ad9516_dev *dev,
uint16_t reg_addr,
uint8_t reg_data)
{
uint8_t buf[3];
int32_t ret;
buf[0] = reg_addr >> 8;
buf[1] = reg_addr & 0xFF;
buf[2] = reg_data;
ret = spi_write_and_read_3wire(dev->spi_desc,
buf, NULL, 3, 0);
return ret;
}
/***************************************************************************//**
* @brief ad9516_init
*******************************************************************************/
int32_t ad9516_init(struct ad9516_dev **device,
const struct ad9516_init_param *init_param)
{
int ret = SUCCESS;
struct ad9516_dev *dev;
dev = (struct ad9516_dev *)malloc(sizeof(*dev));
if (!dev)
return FAILURE;
/* SPI */
ret = spi_init(&dev->spi_desc, init_param->spi_init);
*device = dev;
return ret;
}
/***************************************************************************//**
* @brief Free the resources allocated by ad9516_setup().
*
* @param dev - The device structure.
*
* @return SUCCESS in case of success, negative error code otherwise.
*******************************************************************************/
int32_t ad9516_remove(struct ad9516_dev *dev)
{
int32_t ret;
ret = spi_remove(dev->spi_desc);
free(dev);
return ret;
}
@@ -0,0 +1,89 @@
/***************************************************************************//**
* @file ad9516.h
* @brief Header file of ad9516 Driver.
* @author DBogdan ([email protected])
********************************************************************************
* Copyright 2014-2016(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef AD9516_H_
#define AD9516_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdint.h>
#include "../../../include/delay.h"
#include "../../../include/spi.h"
/******************************************************************************/
/********************** Macros and Constants Definitions **********************/
/******************************************************************************/
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
struct ad9516_dev {
/* SPI */
spi_desc *spi_desc;
};
struct ad9516_init_param {
/* SPI */
spi_init_param *spi_init;
};
struct ad9516_config {
uint16_t addr;
uint8_t value;
};
/******************************************************************************/
/************************ Functions Declarations ******************************/
/******************************************************************************/
int32_t ad9516_read(struct ad9516_dev *dev,
uint16_t reg_addr,
uint8_t *reg_data);
int32_t ad9516_write(struct ad9516_dev *dev,
uint16_t reg_addr,
uint8_t reg_data);
int32_t ad9516_init(struct ad9516_dev **device,
const struct ad9516_init_param *init_param);
int32_t ad9516_remove(struct ad9516_dev *dev);
#endif
@@ -0,0 +1,79 @@
/***************************************************************************//**
* @file xilinx/axi_io.c
* @brief Implementation of Xilinx AXI IO.
* @author Antoniu Miclaus ([email protected])
********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <xil_io.h>
#include "../../include/error.h"
#include "../../include/axi_io.h"
/******************************************************************************/
/************************ Functions Definitions *******************************/
/******************************************************************************/
/**
* @brief AXI IO Xilinx specific read function.
* @param base - Base address
* @param offset - Address offset
* @param data - variable where returned data is stored
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t axi_io_read(uint32_t base, uint32_t offset, uint32_t *data)
{
*data = Xil_In32(base + offset);
return SUCCESS;
}
/**
* @brief AXI IO Xilinx specific write function.
* @param base - Base address
* @param offset - Address offset
* @param data - data to be written.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t axi_io_write(uint32_t base, uint32_t offset, uint32_t data)
{
Xil_Out32(base + offset, data);
return SUCCESS;
}
@@ -0,0 +1,77 @@
/***************************************************************************//**
* @file xilinx/delay.c
* @brief Implementation of Xilinx Delay Functions.
* @author Antoniu Miclaus ([email protected])
********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include "../../include/delay.h"
#include <sleep.h>
/******************************************************************************/
/************************ Functions Definitions *******************************/
/******************************************************************************/
/**
* @brief Generate microseconds delay.
* @param usecs - Delay in microseconds.
* @return None.
*/
void udelay(uint32_t usecs)
{
#ifdef _XPARAMETERS_PS_H_
usleep(usecs);
#else
usleep(usecs / 20); // FIXME
#endif
}
/**
* @brief Generate miliseconds delay.
* @param msecs - Delay in miliseconds.
* @return None.
*/
void mdelay(uint32_t msecs)
{
#ifdef _XPARAMETERS_PS_H_
usleep(msecs * 1000);
#else
usleep(msecs * 50); // FIXME
#endif
}
@@ -0,0 +1,95 @@
/*******************************************************************************
* @file xilinx/gpio_extra.h
* @brief Header containing extra types used in the gpio driver
* @author scuciurean ([email protected])
********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef GPIO_EXTRA_H_
#define GPIO_EXTRA_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdint.h>
#include <stdbool.h>
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
/**
* @enum xil_gpio_type
* @brief Xilinx platform architecture sections
*/
typedef enum xil_gpio_type {
/** Programmable Logic */
GPIO_PL,
/** Processing System */
GPIO_PS
} xil_gpio_type;
/**
* @struct xil_gpio_init_param
* @brief Structure holding the initialization parameters for Xilinx platform
* specific GPIO parameters.
*/
typedef struct xil_gpio_init_param {
/** Xilinx architecture */
enum xil_gpio_type type;
/** Device ID */
uint32_t device_id;
} xil_gpio_init_param;
/**
* @struct xil_gpio_desc
* @brief Xilinx platform specific GPIO descriptor
*/
typedef struct xil_gpio_desc {
/** Xilinx architecture */
enum xil_gpio_type type;
/** Xilinx GPIO configuration */
void *config;
/** Xilinx GPIO Instance */
void *instance;
} xil_gpio_desc;
/**
* @brief Xilinx platform specific gpio platform ops structure
*/
extern const struct gpio_platform_ops xil_gpio_ops;
#endif
@@ -0,0 +1,91 @@
/*******************************************************************************
* @file irq_extra.h
* @brief Header containing types used in the irq driver.
* @author Cristian Pop ([email protected])
********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef IRQ_EXTRA_H_
#define IRQ_EXTRA_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdint.h>
#include "../../include/irq.h"
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
/**
* @enum xil_irq_type
* @brief Xilinx platform architecture sections
*/
enum xil_irq_type {
/** Programmable Logic */
IRQ_PL,
/** Processing System */
IRQ_PS
};
/**
* @struct xil_irq_init_param
* @brief Structure holding the initialization parameters for Xilinx platform
* specific IRQ parameters.
*/
struct xil_irq_init_param {
/** Xilinx architecture */
enum xil_irq_type type;
};
/**
* @struct xil_irq_desc
* @brief Xilinx platform specific IRQ descriptor
*/
struct xil_irq_desc {
/** Xilinx architecture */
enum xil_irq_type type;
/** Xilinx IRQ Instance */
void *instance;
};
/**
* @brief Xilinx specific IRQ platform ops structure
*/
extern const struct irq_platform_ops xil_irq_ops;
#endif
@@ -0,0 +1,115 @@
/*******************************************************************************
* @file xilinx/spi_extra.h
* @brief Header containing extra types used in the spi driver.
* @author scuciurean ([email protected])
********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef SPI_EXTRA_H_
#define SPI_EXTRA_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdint.h>
#include "../../include/spi.h"
/******************************************************************************/
/********************** Macros and Constants Definitions **********************/
/******************************************************************************/
#define SPI_CS_DECODE 0x01
#define SPI_DEASSERT_CURRENT_SS 0x0F
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
/**
* @enum xil_spi_type
* @brief Xilinx platform architecture sections
*/
enum xil_spi_type {
/** Programmable Logic */
SPI_PL,
/** Processing System */
SPI_PS,
/** SPI Engine */
SPI_ENGINE
};
/**
* @struct xil_spi_init_param
* @brief Structure holding the initialization parameters for Xilinx platform
* specific SPI parameters when using xil_spi_ops.
*/
typedef struct xil_spi_init_param {
/** Xilinx architecture */
enum xil_spi_type type;
/** SPI flags */
uint32_t flags;
} xil_spi_init_param;
/**
* @struct xil_spi_desc
* @brief Xilinx platform specific SPI descriptor
*/
typedef struct xil_spi_desc {
/** Xilinx architecture */
enum xil_spi_type type;
/** SPI flags */
uint32_t flags;
/** SPI configuration */
void *config;
/** SPI instance */
void *instance;
} xil_spi_desc;
/**
* @brief SPI engine platform ops structure
*/
extern const struct spi_platform_ops spi_eng_platform_ops;
/**
* @brief Xilinx specific SPI platform ops structure
*/
extern const struct spi_platform_ops xil_spi_ops;
/**
* @brief Xilinx SPI PS register functions. No extra param needed
*/
extern const struct spi_platform_ops xil_spi_reg_ops_pl;
#endif // SPI_EXTRA_H_
@@ -0,0 +1,107 @@
/*******************************************************************************
* @file xilinx/uart_extra.h
* @brief Header containing types used in the uart driver.
* @author Cristian Pop ([email protected])
********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef UART_EXTRA_H_
#define UART_EXTRA_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
/******************************************************************************/
/********************** Macros and Constants Definitions **********************/
/******************************************************************************/
#define UART_BUFF_LENGTH 256
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
/**
* @enum xil_uart_type
* @brief Xilinx platform architecture sections
*/
enum xil_uart_type {
/** Programmable Logic */
UART_PL,
/** Processing System */
UART_PS
};
/**
* @struct xil_uart_init_param
* @brief Structure holding the initialization parameters for Xilinx platform
* specific UART parameters.
*/
struct xil_uart_init_param {
/** Xilinx architecture */
enum xil_uart_type type;
/** Interrupt Request ID */
uint32_t irq_id;
/** Interrupt Request Descriptor */
struct irq_ctrl_desc *irq_desc;
};
/**
* @struct xil_uart_desc
* @brief Xilinx platform specific UART descriptor
*/
struct xil_uart_desc {
/** Xilinx architecture */
enum xil_uart_type type;
/** Interrupt Request ID */
uint32_t irq_id;
/** Interrupt Request Descriptor */
struct irq_ctrl_desc *irq_desc;
/** FIFO */
struct fifo_element *fifo;
/** FIFO read offset */
uint32_t fifo_read_offset;
/** UART Buffer */
char buff[UART_BUFF_LENGTH];
/** Number of bytes received */
uint32_t bytes_received;
/** Total number of errors */
uint32_t total_error_count;
/** UART Instance */
void *instance;
};
#endif
@@ -0,0 +1,464 @@
/***************************************************************************//**
* @file xilinx/xilinx_gpio.c
* @brief Implementation of Xilinx GPIO Generic Driver.
* @author Antoniu Miclaus ([email protected])
********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdlib.h>
#include <xparameters.h>
#ifdef XPAR_XGPIO_NUM_INSTANCES
#include <xgpio.h>
#endif
#ifdef XPAR_XGPIOPS_NUM_INSTANCES
#include <xgpiops.h>
#endif
#include "gpio_extra.h"
#include "../../include/error.h"
#include "../../include/gpio.h"
/******************************************************************************/
/************************ Functions Definitions *******************************/
/******************************************************************************/
/**
* @brief Prepare the GPIO decriptor.
* @param desc - The GPIO descriptor.
* @param param - The structure that contains the GPIO parameters.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t _gpio_init(struct gpio_desc *desc,
const struct gpio_init_param *param)
{
int32_t ret;
struct xil_gpio_desc *xdesc;
struct xil_gpio_init_param *xinit;
ret = FAILURE;
xdesc = desc->extra;
xinit = param->extra;
xdesc->type = xinit->type;
desc->number = param->number;
switch (xinit->type) {
case GPIO_PL:
#ifdef XGPIO_H
xdesc->instance = (XGpio *)malloc(sizeof(XGpio));
if(!xdesc->instance)
goto pl_error;
xdesc->config = XGpio_LookupConfig(xinit->device_id);
if(xdesc->config == NULL)
goto pl_error;
ret = XGpio_CfgInitialize(xdesc->instance,
xdesc->config,
((XGpio_Config*)xdesc->config)
->BaseAddress);
if(ret < 0)
goto pl_error;
break;
pl_error:
free(xdesc->instance);
#endif
goto error;
case GPIO_PS:
#ifdef XGPIOPS_H
xdesc->instance = (XGpioPs *)malloc(sizeof(XGpioPs));
if(!xdesc->instance)
goto ps_error;
xdesc->config = XGpioPs_LookupConfig(xinit->device_id);
if(xdesc->config == NULL)
goto ps_error;
ret = XGpioPs_CfgInitialize(xdesc->instance,
xdesc->config,
((XGpioPs_Config*)xdesc->config)->BaseAddr);
if(ret < 0)
goto ps_error;
break;
ps_error:
free(xdesc->instance);
#endif
goto error;
error:
default:
return FAILURE;
}
return SUCCESS;
}
/**
* @brief Obtain the GPIO decriptor.
* @param desc - The GPIO descriptor.
* @param param - GPIO initialization parameters
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t xil_gpio_get(struct gpio_desc **desc,
const struct gpio_init_param *param)
{
struct gpio_desc *descriptor;
struct xil_gpio_desc *extra;
int32_t ret;
descriptor = (struct gpio_desc *)malloc(sizeof(*descriptor));
extra = (struct xil_gpio_desc*)malloc(sizeof(*extra));
if (!descriptor || !extra)
return FAILURE;
descriptor->extra = extra;
ret = _gpio_init(descriptor, param);
if(ret != SUCCESS)
goto error;
*desc = descriptor;
return SUCCESS;
error:
free(extra);
free(descriptor);
return FAILURE;
}
/**
* @brief Get the value of an optional GPIO.
* @param desc - The GPIO descriptor.
* @param param - GPIO Initialization parameters.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t xil_gpio_get_optional(struct gpio_desc **desc,
const struct gpio_init_param *param)
{
if(param == NULL) {
*desc = NULL;
return SUCCESS;
}
return xil_gpio_get(desc, param);
}
/**
* @brief Free the resources allocated by gpio_get().
* @param desc - The GPIO descriptor.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t xil_gpio_remove(struct gpio_desc *desc)
{
if (desc != NULL) {
free(((xil_gpio_desc *)(desc->extra))->instance);
free(desc->extra);
free(desc);
}
return SUCCESS;
}
/**
* @brief Enable the input direction of the specified GPIO.
* @param desc - The GPIO descriptor.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t xil_gpio_direction_input(struct gpio_desc *desc)
{
struct xil_gpio_desc *extra;
#ifdef XGPIO_H
uint8_t pin = desc->number;
uint32_t channel = 1;
uint32_t config = 0;
#endif
extra = desc->extra;
switch (extra->type) {
case GPIO_PL:
#ifdef XGPIO_H
/* We assume that pin 32 is the first pin from channel 2 */
if (pin >= 32) {
channel = 2;
pin -= 32;
}
config = XGpio_GetDataDirection((XGpio *)extra->instance,
channel);
config |= (1 << pin);
XGpio_SetDataDirection((XGpio *)extra->instance,
channel,
config);
#endif
break;
case GPIO_PS:
#ifdef XGPIOPS_H
XGpioPs_SetDirectionPin(extra->instance,
desc->number,
GPIO_IN);
#endif
break;
default:
return FAILURE;
}
return SUCCESS;
}
/**
* @brief Enable the output direction of the specified GPIO.
* @param desc - The GPIO descriptor.
* @param value - The value.
* Example: GPIO_HIGH
* GPIO_LOW
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t xil_gpio_direction_output(struct gpio_desc *desc,
uint8_t value)
{
struct xil_gpio_desc *extra;
#ifdef XGPIO_H
uint8_t pin = desc->number;
uint8_t channel;
uint32_t reg_val;
#endif
extra = desc->extra;
switch (extra->type) {
case GPIO_PL:
#ifdef XGPIO_H
if (pin >= 32) {
channel = 2;
pin -= 32;
} else
channel = 1;
reg_val = XGpio_GetDataDirection(extra->instance,
channel);
reg_val &= ~(1 << pin);
XGpio_SetDataDirection(extra->instance,
channel,
reg_val);
reg_val = XGpio_DiscreteRead(extra->instance,
channel);
if(value)
reg_val |= (1 << pin);
else
reg_val &= ~(1 << pin);
XGpio_DiscreteWrite(extra->instance,
channel,
reg_val);
#endif
break;
case GPIO_PS:
#ifdef XGPIOPS_H
XGpioPs_SetDirectionPin(extra->instance,
desc->number,
GPIO_OUT);
XGpioPs_SetOutputEnablePin(extra->instance,
desc->number,
GPIO_OUT);
XGpioPs_WritePin(extra->instance,
desc->number,
value);
#endif
break;
default:
return FAILURE;
}
return SUCCESS;
}
/**
* @brief Get the direction of the specified GPIO.
* @param desc - The GPIO descriptor.
* @param direction - The direction.
* Example: GPIO_OUT
* GPIO_IN
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t xil_gpio_get_direction(struct gpio_desc *desc,
uint8_t *direction)
{
if (!desc)
return FAILURE;
struct xil_gpio_desc *extra;
uint8_t pin = desc->number;
#ifdef XGPIO_H
uint8_t channel;
#endif
extra = desc->extra;
switch (extra->type) {
case GPIO_PL:
#ifdef XGPIO_H
if (pin >= 32) {
channel = 2;
pin -= 32;
} else
channel = 1;
*direction = ((XGpio_GetDataDirection(extra->instance,
channel) >> pin) & 0x1) ^ 0x1;
#endif
break;
case GPIO_PS:
#ifdef XGPIOPS_H
*direction = XGpioPs_GetDirectionPin(extra->instance, pin);
#endif
break;
default:
return FAILURE;
}
return SUCCESS;
}
/**
* @brief Set the value of the specified GPIO.
* @param desc - The GPIO descriptor.
* @param value - The value.
* Example: GPIO_HIGH
* GPIO_LOW
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t xil_gpio_set_value(struct gpio_desc *desc,
uint8_t value)
{
struct xil_gpio_desc *extra;
#ifdef XGPIO_H
uint8_t pin = desc->number;
uint8_t channel;
uint32_t reg_val;
#endif
extra = desc->extra;
switch (extra->type) {
case GPIO_PL:
#ifdef XGPIO_H
if (pin >= 32) {
channel = 2;
pin -= 32;
} else
channel = 1;
reg_val = XGpio_DiscreteRead(extra->instance, channel);
if(value)
reg_val |= (1 << pin);
else
reg_val &= ~(1 << pin);
XGpio_DiscreteWrite(extra->instance, channel, reg_val);
#endif
break;
case GPIO_PS:
#ifdef XGPIOPS_H
XGpioPs_WritePin(extra->instance, desc->number, value);
#endif
break;
default:
return FAILURE;
}
return SUCCESS;
}
/**
* @brief Get the value of the specified GPIO.
* @param desc - The GPIO descriptor.
* @param value - The value.
* Example: GPIO_HIGH
* GPIO_LOW
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t xil_gpio_get_value(struct gpio_desc *desc,
uint8_t *value)
{
if (!desc)
return FAILURE;
struct xil_gpio_desc *extra;
uint8_t pin = desc->number;
#ifdef XGPIO_H
uint8_t channel;
#endif
extra = desc->extra;
switch (extra->type) {
case GPIO_PL:
#ifdef XGPIO_H
if (pin >= 32) {
channel = 2;
pin -= 32;
} else
channel = 1;
*value = (XGpio_DiscreteRead(extra->instance, channel) >> pin) & 0x01;
#endif
break;
case GPIO_PS:
#ifdef XGPIOPS_H
*value = XGpioPs_ReadPin(extra->instance, pin);
#endif
break;
default:
return FAILURE;
}
return SUCCESS;
}
/**
* @brief Xilinx platform specific GPIO platform ops structure
*/
const struct gpio_platform_ops xil_gpio_ops = {
.gpio_ops_get = &xil_gpio_get,
.gpio_ops_get_optional = &xil_gpio_get_optional,
.gpio_ops_remove = &xil_gpio_remove,
.gpio_ops_direction_input = &xil_gpio_direction_input,
.gpio_ops_direction_output = &xil_gpio_direction_output,
.gpio_ops_get_direction = &xil_gpio_get_direction,
.gpio_ops_set_value = &xil_gpio_set_value,
.gpio_ops_get_value = &xil_gpio_get_value,
};
@@ -0,0 +1,384 @@
/***************************************************************************//**
* @file xilinx/xilinx_irq.c
* @brief Implementation of Xilinx IRQ Generic Driver.
* @author Cristian Pop ([email protected])
********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <xparameters.h>
#include <stdlib.h>
#include "irq_extra.h"
#include "../../include/irq.h"
#include "../../include/error.h"
#ifdef XPAR_XSCUGIC_NUM_INSTANCES
#include <xscugic.h>
#endif
#ifdef XPAR_XINTC_NUM_INSTANCES
#include <xintc.h>
#endif
#ifdef XPAR_XTMRCTR_NUM_INSTANCES
#include <xtmrctr.h>
#endif
/******************************************************************************/
/************************ Functions Definitions *******************************/
/******************************************************************************/
/**
* @brief Initialize the IRQ interrupts.
* @param desc - The IRQ controller descriptor.
* @param param - The structure that contains the IRQ parameters.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t xil_irq_ctrl_init(struct irq_ctrl_desc **desc,
const struct irq_init_param *param)
{
int32_t status;
struct irq_ctrl_desc *descriptor;
struct xil_irq_desc *xil_dev;
#ifdef XSCUGIC_H
void *config;
#endif
descriptor = (struct irq_ctrl_desc *)calloc(1, sizeof *descriptor);
if(!descriptor)
return FAILURE;
xil_dev = (struct xil_irq_desc *)calloc(1, sizeof *xil_dev);
if(!xil_dev) {
free(descriptor);
return FAILURE;
}
Xil_ExceptionInit();
descriptor->irq_ctrl_id = param->irq_ctrl_id;
descriptor->extra = xil_dev;
xil_dev->type = ((struct xil_irq_init_param *)param->extra)->type;
switch(xil_dev->type) {
case IRQ_PS:
#ifdef XSCUGIC_H
xil_dev->instance = calloc(1, sizeof(XScuGic));
if(!xil_dev->instance)
goto error;
config = XScuGic_LookupConfig(descriptor->irq_ctrl_id);
if(!config)
goto ps_error;
status = XScuGic_CfgInitialize(xil_dev->instance, config,
((XScuGic_Config *)config)->CpuBaseAddress);
if (status != SUCCESS)
goto ps_error;
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler,
xil_dev->instance);
break;
ps_error:
free(xil_dev->instance);
#endif
goto error;
case IRQ_PL:
#ifdef XINTC_H
xil_dev->instance = calloc(1, sizeof(XIntc));
if(!xil_dev->instance)
goto error;
status = XIntc_Initialize(xil_dev->instance, descriptor->irq_ctrl_id);
if(status != SUCCESS)
goto pl_error;
status = XIntc_Start(xil_dev->instance, XIN_REAL_MODE);
if(status != SUCCESS)
goto pl_error;
break;
pl_error:
free(xil_dev->instance);
#endif
goto error;
default:
goto error;
break;
}
*desc = descriptor;
return SUCCESS;
error:
free(xil_dev);
free(descriptor);
return FAILURE;
}
/**
* @brief Enable global interrupts.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t xil_irq_global_enable(struct irq_ctrl_desc *desc)
{
/* Enable interrupts */
Xil_ExceptionEnable();
return SUCCESS;
}
/**
* @brief Disable global interrupts.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t xil_irq_global_disable(struct irq_ctrl_desc *desc)
{
/* Disable interrupts */
Xil_ExceptionDisable();
return SUCCESS;
}
/**
* @brief Enable specific interrupt.
* @param desc - The IRQ controller descriptor.
* @param irq_id - Interrupt identifier.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t xil_irq_enable(struct irq_ctrl_desc *desc, uint32_t irq_id)
{
struct xil_irq_desc *xil_dev = desc->extra;
switch(xil_dev->type) {
case IRQ_PS:
#ifdef XSCUGIC_H
XScuGic_Enable(xil_dev->instance, irq_id);
#endif
break;
case IRQ_PL:
#ifdef XINTC_H
XIntc_Enable(xil_dev->instance, irq_id);
#endif
break;
default:
return FAILURE;
}
return SUCCESS;
}
/**
* @brief Disable specific interrupt.
* @param desc - The IRQ controller descriptor.
* @param irq_id - Interrupt identifier.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t xil_irq_disable(struct irq_ctrl_desc *desc, uint32_t irq_id)
{
struct xil_irq_desc *xil_dev = desc->extra;
switch(xil_dev->type) {
case IRQ_PS:
#ifdef XSCUGIC_H
XScuGic_Disable(xil_dev->instance, irq_id);
#endif
break;
case IRQ_PL:
#ifdef XINTC_H
XIntc_Disable(xil_dev->instance, irq_id);
#endif
break;
default:
return FAILURE;
}
return SUCCESS;
}
/**
* @brief Register a callback to handle the irq events.
* @param desc - The IRQ controller descriptor.
* @param irq_id - Interrupt identifier.
* @param callback_desc - Callback descriptor
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t xil_irq_register_callback(struct irq_ctrl_desc *desc, uint32_t irq_id,
struct callback_desc *callback_desc)
{
struct xil_irq_desc *xil_dev = desc->extra;
switch(xil_dev->type) {
case IRQ_PS:
#ifdef XSCUGIC_H
return XScuGic_Connect(xil_dev->instance, irq_id,
(Xil_InterruptHandler) callback_desc->callback,
callback_desc->ctx);
#endif
break;
// case IRQ_PL:
//#ifdef XINTC_H
// if (irq_id == XPAR_AXI_INTC_AXI_TIMER_INTERRUPT_INTR) {
// int32_t ret;
//
// ret = XIntc_Connect(xil_dev->instance, irq_id,
// XTmrCtr_InterruptHandler, callback_desc->config);
// if (IS_ERR_VALUE(ret))
// return FAILURE;
// XTmrCtr_SetHandler(callback_desc->config,
// (XTmrCtr_Handler)callback_desc->callback,
// callback_desc->ctx);
//
// return SUCCESS;
// }
// return XIntc_Connect(xil_dev->instance, irq_id,
// (XInterruptHandler) callback_desc->callback,
// callback_desc->ctx);
//#endif
// break;
default:
break;
}
return FAILURE;
}
/**
* @brief Set interrupt trigger level.
* @param desc - The IRQ controller descriptor.
* @param irq_id - Interrupt identifier.
* @param trig - New trigger level for the interrupt.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t xil_irq_trigger_level_set(struct irq_ctrl_desc *desc, uint32_t irq_id,
enum irq_trig_level trig)
{
struct xil_irq_desc *xil_dev = desc->extra;
if(trig == IRQ_EDGE_BOTH)
return -EINVAL;
switch(xil_dev->type) {
case IRQ_PS:
#ifdef XSCUGIC_H
;
uint8_t priority, trigger;
XScuGic_GetPriorityTriggerType(xil_dev->instance, irq_id, &priority,
&trigger);
trigger = trig;
XScuGic_SetPriorityTriggerType(xil_dev->instance, irq_id, priority,
trigger);
return SUCCESS;
#endif
break;
case IRQ_PL:
#ifdef XINTC_H
/* Interrupt trigger determined in hardware. TODO: verify */
return SUCCESS;
#endif
break;
default:
break;
}
return FAILURE;
}
/**
* @brief Unregisters a generic IRQ handling function.
* @param desc - The IRQ controller descriptor.
* @param irq_id - Interrupt identifier.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t xil_irq_unregister(struct irq_ctrl_desc *desc, uint32_t irq_id)
{
struct xil_irq_desc *xil_dev = desc->extra;
switch(xil_dev->type) {
case IRQ_PS:
#ifdef XSCUGIC_H
XScuGic_Disconnect(xil_dev->instance, irq_id);
#endif
break;
case IRQ_PL:
#ifdef XINTC_H
XIntc_Disconnect(xil_dev->instance, irq_id);
#endif
break;
default:
return FAILURE;
}
return SUCCESS;
}
/**
* @brief Free the resources allocated by irq_ctrl_init().
* @param desc - The IRQ control descriptor.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t xil_irq_ctrl_remove(struct irq_ctrl_desc *desc)
{
struct xil_irq_desc *xil_dev = desc->extra;
free(xil_dev->instance);
free(desc->extra);
free(desc);
return SUCCESS;
}
/**
* @brief Xilinx platform specific IRQ platform ops structure
*/
const struct irq_platform_ops xil_irq_ops = {
.init = &xil_irq_ctrl_init,
.register_callback = &xil_irq_register_callback,
.unregister = &xil_irq_unregister,
.global_enable = &xil_irq_global_enable,
.global_disable = &xil_irq_global_disable,
.trigger_level_set = &xil_irq_trigger_level_set,
.enable = &xil_irq_enable,
.disable = &xil_irq_disable,
.remove = &xil_irq_ctrl_remove
};
@@ -0,0 +1,461 @@
/***************************************************************************//**
* @file xilinx/xilinx_spi.c
* @brief Implementation of Xilinx SPI Generic Driver.
* @author Antoniu Miclaus ([email protected])
********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdlib.h>
#include <xparameters.h>
#ifdef XPAR_XSPI_NUM_INSTANCES
#include <xspi.h>
#endif
#ifdef XPAR_XSPIPS_NUM_INSTANCES
#include <xspips.h>
#endif
#include "../../include/error.h"
#include "../../include/spi.h"
#include "spi_extra.h"
#if defined(PLATFORM_ZYNQ)
#define SPI_CLK_FREQ_HZ(dev) (XPAR_PS7_SPI_ ## dev ## _SPI_CLK_FREQ_HZ)
#define SPI_NUM_INSTANCES XPAR_XSPIPS_NUM_INSTANCES
#elif defined(PLATFORM_ZYNQMP)
#define SPI_CLK_FREQ_HZ(dev) (XPAR_PSU_SPI_ ## dev ## _SPI_CLK_FREQ_HZ)
#define SPI_NUM_INSTANCES XPAR_XSPIPS_NUM_INSTANCES
#else
#define SPI_NUM_INSTANCES 0
#endif
/******************************************************************************/
/************************ Functions Definitions *******************************/
/******************************************************************************/
/**
* @brief Initialize the hardware SPI peripherial
*
* @param xdesc Platform specific SPI descriptor
* @param xinit Platform specific SPI init param
* @return int32_t FAILURE if the device couldn't be found or configured
*/
static int32_t spi_init_pl(struct spi_desc *desc,
const struct spi_init_param *param)
{
#ifdef XSPI_H
int32_t ret;
struct xil_spi_desc *xdesc;
struct xil_spi_init_param *xinit;
xdesc = (xil_spi_desc*)malloc(sizeof(xil_spi_desc));
if(!xdesc) {
free(xdesc);
return FAILURE;
}
desc->extra = xdesc;
xinit = param->extra;
xdesc->type = xinit->type;
xdesc->flags = xinit->flags;
xdesc->instance = (XSpi*)calloc(1, sizeof(XSpi));
if(!xdesc->instance)
goto pl_error;
xdesc->config = XSpi_LookupConfig(param->device_id);
if(xdesc->config == NULL)
goto pl_error;
ret = XSpi_CfgInitialize(xdesc->instance,
xdesc->config,
((XSpi_Config*)xdesc->config)
->BaseAddress);
if(ret != SUCCESS)
goto pl_error;
ret = XSpi_Initialize(xdesc->instance, param->device_id);
if (ret != SUCCESS)
goto pl_error;
ret = XSpi_SetOptions(xdesc->instance,
XSP_MASTER_OPTION |
((desc->mode & SPI_CPOL) ?
XSP_CLK_ACTIVE_LOW_OPTION : 0) |
((desc->mode & SPI_CPHA) ?
XSP_CLK_PHASE_1_OPTION : 0));
if (ret != SUCCESS)
goto pl_error;
ret = XSpi_Start(xdesc->instance);
if (ret != SUCCESS)
goto pl_error;
XSpi_IntrGlobalDisable((XSpi *)(xdesc->instance));
return SUCCESS;
pl_error:
free(xdesc->instance);
free(xdesc);
#endif
return FAILURE;
}
/**
* @brief Initialize the hardware SPI peripherial
*
* @param xdesc Platform specific SPI descriptor
* @param xinit Platform specific SPI init param
* @return int32_t FAILURE if the device couldn't be found or configured
*/
static int32_t spi_init_ps(struct spi_desc *desc,
const struct spi_init_param *param)
{
#ifdef XSPIPS_H
int32_t ret;
struct xil_spi_desc *xdesc;
struct xil_spi_init_param *xinit;
const uint32_t prescaler_default = XSPIPS_CLK_PRESCALE_64;
const uint32_t prescaler_min = XSPIPS_CLK_PRESCALE_4;
const uint32_t prescaler_max = XSPIPS_CLK_PRESCALE_256;
uint32_t prescaler = 0u;
uint32_t input_clock = 0u;
xdesc = (xil_spi_desc*)malloc(sizeof(xil_spi_desc));
if(!xdesc) {
free(xdesc);
return FAILURE;
}
desc->extra = xdesc;
xinit = param->extra;
xdesc->type = xinit->type;
xdesc->flags = xinit->flags;
xdesc->instance = (XSpiPs*)malloc(sizeof(XSpiPs));
if(!xdesc->instance)
goto ps_error;
xdesc->config = XSpiPs_LookupConfig(param->device_id);
if(xdesc->config == NULL)
goto ps_error;
ret = XSpiPs_CfgInitialize(xdesc->instance,
xdesc->config,
((XSpiPs_Config*)xdesc->config)
->BaseAddress);
if(ret != SUCCESS)
goto ps_error;
switch (param->device_id) {
#if (SPI_NUM_INSTANCES >= 1)
case 0:
input_clock = SPI_CLK_FREQ_HZ(0);
break;
#endif
#if (SPI_NUM_INSTANCES >= 2)
case 1:
input_clock = SPI_CLK_FREQ_HZ(1);
break;
#endif
default:
goto ps_error;
};
if (desc->max_speed_hz != 0u) {
uint32_t div = input_clock / desc->max_speed_hz;
uint32_t rem = input_clock % desc->max_speed_hz;
uint32_t po2 = !(div & (div - 1)) && !rem;
// find the power of two just higher than div and
// store the exponent in prescaler
while(div) {
prescaler += 1;
div >>= 1u;
}
// this exponent - 1 is needed because of the way
// xilinx stores it into registers
if (prescaler)
prescaler -= 1;
// this exponent - 1 is needed when initial div was
// precisely a power of two
if (prescaler && po2)
prescaler -= 1;
if (prescaler < prescaler_min)
prescaler = prescaler_min;
if (prescaler > prescaler_max)
prescaler = prescaler_max;
} else
prescaler = prescaler_default;
ret = XSpiPs_SetClkPrescaler(xdesc->instance, prescaler);
if(ret != SUCCESS)
goto ps_error;
return SUCCESS;
ps_error:
free(xdesc->instance);
free(xdesc);
#endif
return FAILURE;
}
/**
* @brief Initialize the SPI communication peripheral.
* @param desc - The SPI descriptor.
* @param param - The structure that contains the SPI parameters.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t xil_spi_init(struct spi_desc **desc,
const struct spi_init_param *param)
{
int32_t ret;
enum xil_spi_type *spi_type;
if (!param) {
return FAILURE;
}
*desc = malloc(sizeof(**desc));
if(! *desc) {
free(*desc);
return FAILURE;
}
spi_type = param->extra;
if(!spi_type)
goto init_error;
(*desc)->max_speed_hz = param->max_speed_hz;
(*desc)->mode = param->mode;
(*desc)->bit_order = param->bit_order;
(*desc)->chip_select = param->chip_select;
switch (*spi_type) {
case SPI_PL:
ret = spi_init_pl(*desc, param);
break;
case SPI_PS:
ret = spi_init_ps(*desc, param);
break;
default:
goto init_error;
break;
}
if (ret != SUCCESS) {
init_error:
free(*desc);
return FAILURE;
}
return ret;
}
/**
* @brief Free the resources allocated by spi_init().
* @param desc - The SPI descriptor.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t xil_spi_remove(struct spi_desc *desc)
{
#ifdef XSPI_H
int32_t ret;
#endif
struct xil_spi_desc *xdesc = NULL;
enum xil_spi_type *spi_type;
spi_type = desc->extra;
if(!spi_type)
return FAILURE;
switch (*spi_type ) {
case SPI_PL:
#ifdef XSPI_H
xdesc = desc->extra;
if(!xdesc)
return FAILURE;
ret = XSpi_Stop((XSpi *)(xdesc->instance));
if(ret != SUCCESS)
goto error;
#endif
break;
case SPI_PS:
#ifdef XSPIPS_H
xdesc = desc->extra;
if(!xdesc)
return FAILURE;
#endif
break;
/* Intended fallthrough */
#ifdef XSPI_H
error:
#endif
default:
return FAILURE;
}
if(xdesc)
free(xdesc->instance);
free(desc->extra);
free(desc);
return SUCCESS;
}
/**
* @brief Write and read data to/from SPI.
* @param desc - The SPI descriptor.
* @param data - The buffer with the transmitted/received data.
* @param bytes_number - Number of bytes to write/read.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int32_t xil_spi_write_and_read(struct spi_desc *desc,
uint8_t *data,
uint16_t bytes_number)
{
int32_t ret;
#ifdef XSPI_H
uint32_t ctrl_reg;
#endif
struct xil_spi_desc *xdesc;
enum xil_spi_type *spi_type;
ret = FAILURE;
spi_type = desc->extra;
if(!spi_type)
return FAILURE;
xdesc = desc->extra;
switch (*spi_type) {
case SPI_PL:
#ifdef XSPI_H
ret = XSpi_SetOptions(xdesc->instance,
XSP_MASTER_OPTION |
((desc->mode & SPI_CPOL) ?
XSP_CLK_ACTIVE_LOW_OPTION : 0) |
((desc->mode & SPI_CPHA) ?
XSP_CLK_PHASE_1_OPTION : 0));
if (ret != SUCCESS)
goto error;
ctrl_reg = XSpi_GetControlReg(((XSpi*)xdesc->instance));
if (desc->bit_order == SPI_BIT_ORDER_LSB_FIRST)
ctrl_reg |= XSP_CR_LSB_MSB_FIRST_MASK;
else
ctrl_reg &= ~ XSP_CR_LSB_MSB_FIRST_MASK;
XSpi_SetControlReg(((XSpi*)xdesc->instance), ctrl_reg);
ret = XSpi_SetSlaveSelect(xdesc->instance,
0x01 << desc->chip_select);
if (ret != SUCCESS)
goto error;
ret = XSpi_Transfer(xdesc->instance,
data,
data,
bytes_number);
if (ret != SUCCESS)
goto error;
#endif
break;
case SPI_PS:
#ifdef XSPIPS_H
ret = XSpiPs_SetOptions(xdesc->instance,
XSPIPS_MASTER_OPTION |
((xdesc->flags & SPI_CS_DECODE) ?
XSPIPS_DECODE_SSELECT_OPTION : 0) |
XSPIPS_FORCE_SSELECT_OPTION |
((desc->mode & SPI_CPOL) ?
XSPIPS_CLK_ACTIVE_LOW_OPTION : 0) |
((desc->mode & SPI_CPHA) ?
XSPIPS_CLK_PHASE_1_OPTION : 0));
if (ret != SUCCESS)
goto error;
ret = XSpiPs_SetSlaveSelect(xdesc->instance,
desc->chip_select);
if (ret != SUCCESS)
goto error;
ret = XSpiPs_PolledTransfer(xdesc->instance,
data,
data,
bytes_number);
if (ret != SUCCESS)
goto error;
ret = XSpiPs_SetSlaveSelect(xdesc->instance, SPI_DEASSERT_CURRENT_SS);
if (ret != SUCCESS)
goto error;
#endif
break;
error:
default:
return FAILURE;
}
return ret;
}
/**
* @brief Xilinx platform specific SPI platform ops structure
*/
const struct spi_platform_ops xil_spi_ops = {
.init = &xil_spi_init,
.write_and_read = &xil_spi_write_and_read,
.write_and_read_3wire = NULL, // Not support.
.remove = &xil_spi_remove
};
@@ -0,0 +1,531 @@
/*******************************************************************************
* @file xilinx/xilinx_spi_pl.c
* @brief Driver for spi pl device using registers
* @author Mihail Chindris ([email protected])
********************************************************************************
* Copyright 2021(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include <xparameters.h>
#ifdef XPAR_XSPI_NUM_INSTANCES
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <xspi.h>
#include <stdlib.h>
#include <stdbool.h>
#include "spi.h"
#include "error.h"
#include "delay.h"
#include "util.h"
/******************************************************************************/
/********************** Macros and Constants Definitions **********************/
/******************************************************************************/
#define XPS_TYPE_WRITE 0x1
#define XPS_TYPE_READ 0x2
#define XSP_DEFAULT_SR_VALUE 0x25
#define XSP_DUMMY_DATA 0xFF
/*
* Used to store current spi device configuration in order to not update it for
* each spi transaction if not needed.
*/
static struct spi_desc g_spi_desc[XPAR_XSPI_NUM_INSTANCES];
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
/* Xilinx PL spi specific data */
struct xspi_desc {
uint32_t base_addr;
uint32_t disable_slaves_mask;
uint32_t fifo_depth;
uint8_t cs_asserted;
};
/* Structure used to iterate over SPI messages */
struct msg_iter {
struct spi_msg *msgs;
uint32_t len;
uint32_t i;
uint32_t buff_i;
uint8_t is_wr;
};
/******************************************************************************/
/************************ Functions Definitions *******************************/
/******************************************************************************/
/* Read device register */
static inline uint32_t _read(struct xspi_desc *xdesc, uint32_t reg)
{
return Xil_In32(xdesc->base_addr + reg);
}
/* Write device register */
static inline void _write(struct xspi_desc *xdesc, uint32_t reg, uint32_t val)
{
Xil_Out32(xdesc->base_addr + reg, val);
}
/* Update device register. Only bits set to 1 in mask will be modified */
static inline void _wr_mask(struct xspi_desc *xdesc, uint32_t reg,
uint32_t val, uint32_t mask)
{
uint32_t tmp;
tmp = _read(xdesc, reg);
tmp &= ~mask;
tmp |= val & mask;
_write(xdesc, reg, tmp);
}
/* Update spi device configuration if needed */
static void _update_mode(struct spi_desc *desc)
{
uint32_t val;
uint32_t mask;
if (desc->mode == g_spi_desc[desc->device_id].mode &&
desc->bit_order == g_spi_desc[desc->device_id].bit_order)
return ;
/* Update mode */
val = desc->mode | SPI_CPOL ? XSP_CR_CLK_POLARITY_MASK : 0;
val |= desc->mode | SPI_CPHA ? XSP_CR_CLK_PHASE_MASK : 0;
mask = XSP_CR_CLK_POLARITY_MASK | XSP_CR_CLK_PHASE_MASK;
val |= desc->bit_order == SPI_BIT_ORDER_LSB_FIRST ?
XSP_CR_LSB_MSB_FIRST_MASK : 0;
mask |= XSP_CR_LSB_MSB_FIRST_MASK;
_wr_mask(desc->extra, XSP_CR_OFFSET, val, mask);
g_spi_desc[desc->device_id] = *desc;
}
/* Configure SPI PL device */
static int32_t _xil_spi_init_dev(struct xspi_desc *xdesc)
{
uint32_t val;
/* Software reset */
_write(xdesc, XSP_SRR_OFFSET, XSP_SRR_RESET_MASK);
mdelay(1);
/* Check if success reset */
val = _read(xdesc, XSP_SR_OFFSET);
if (val != XSP_DEFAULT_SR_VALUE)
return -ENODEV;
/* Disable interrupts. Drivers only works with pooled mode */
_write(xdesc, XSP_IIER_OFFSET, 0);
/* Deasert chip selects */
_write(xdesc, XSP_SSR_OFFSET, 0xFFFFFFFF);
/* Get fifo depth */
while (!(_read(xdesc, XSP_SR_OFFSET) & XSP_SR_TX_FULL_MASK))
_write(xdesc, XSP_DTR_OFFSET, XSP_DUMMY_DATA);
xdesc->fifo_depth = _read(xdesc, XSP_TFO_OFFSET) + 1;
/* Configure spi device */
val = XSP_CR_ENABLE_MASK |
XSP_CR_MANUAL_SS_MASK |
XSP_CR_TXFIFO_RESET_MASK |
XSP_CR_RXFIFO_RESET_MASK |
XSP_CR_MASTER_MODE_MASK |
XSP_CR_TRANS_INHIBIT_MASK;
_write(xdesc, XSP_CR_OFFSET, val);
return SUCCESS;
}
/* Initialize spi_desc structure and device */
static int32_t xil_spi_init_pl(struct spi_desc **desc,
const struct spi_init_param *param)
{
struct spi_desc *ldesc;
struct xspi_desc *xdesc;
int32_t err;
XSpi_Config *cfg;
if (!desc || !param || param->device_id >= XPAR_XSPI_NUM_INSTANCES)
return -EINVAL;
cfg = XSpi_LookupConfig(param->device_id);
if (!cfg)
return -EINVAL;
if (param->chip_select > cfg->NumSlaveBits)
return -EINVAL;
ldesc = (struct spi_desc *)calloc(1, sizeof(*ldesc));
if (!ldesc)
return -ENOMEM;
xdesc = (struct xspi_desc *)calloc(1, sizeof(*xdesc));
if (!xdesc) {
err = -ENOMEM;
goto error;
}
ldesc->bit_order = param->bit_order;
ldesc->chip_select = param->chip_select;
ldesc->mode = param->mode;
xdesc->base_addr = cfg->BaseAddress;
xdesc->disable_slaves_mask = (1 << cfg->NumSlaveBits) - 1;
xdesc->cs_asserted = 0;
err = _xil_spi_init_dev(xdesc);
if (IS_ERR_VALUE(err))
goto error;
ldesc->extra = xdesc;
*desc = ldesc;
return SUCCESS;
error:
free(xdesc);
free(ldesc);
return err;
}
/* Remove allocated resources */
static int32_t xil_spi_remove_pl(struct spi_desc *desc)
{
if (!desc)
return -EINVAL;
free(desc->extra);
free(desc);
return SUCCESS;
}
/*
* Fill fifo until fifo is full or no more data available.
* Return the number of written bytes.
*/
static uint32_t _wr_fifo(struct xspi_desc *xdesc, uint8_t *data,
uint32_t len)
{
uint32_t i;
uint32_t to_write;
uint32_t tx_available;
tx_available = xdesc->fifo_depth - _read(xdesc, XSP_TFO_OFFSET);
to_write = min(tx_available, len);
for (i = 0; i < to_write; ++i)
if (data)
_write(xdesc, XSP_DTR_OFFSET, data[i]);
else
_write(xdesc, XSP_DTR_OFFSET, XSP_DUMMY_DATA);
return to_write;
}
/*
* Read fifo until fifo is empty or no more buffer available to read into
* Returns the number of read bytes
*/
static uint32_t _rd_fifo(struct xspi_desc *xdesc, uint8_t *data,
uint32_t len)
{
uint32_t rx_available;
uint32_t to_read;
uint32_t tmp;
uint32_t i;
tmp = _read(xdesc, XSP_SR_OFFSET);
if (tmp & XSP_SR_RX_EMPTY_MASK)
return 0;
rx_available = _read(xdesc, XSP_RFO_OFFSET) + 1;
to_read = min(rx_available, len);
for (i = 0; i < to_read; ++i) {
tmp = _read(xdesc, XSP_DRR_OFFSET);
if (data)
data[i] = tmp;
}
return to_read;
}
/* If start is 0 stop transfer, else start it.
* CS will be asserted if needed. If different CS othere than the one needed
* is asserted. Deassert it and assert correct one */
static void _xil_spi_start_transfer(struct spi_desc *desc, uint8_t start)
{
struct xspi_desc *xdesc;
xdesc = desc->extra;
if (start) {
if (xdesc->cs_asserted) {
if (desc->chip_select ==
g_spi_desc[desc->device_id].chip_select)
return ;
else
/* Stop transfer to start again with new CS */
_xil_spi_start_transfer(desc, 0);
}
_write(xdesc, XSP_SSR_OFFSET, ~(1 << desc->chip_select));
_wr_mask(xdesc, XSP_CR_OFFSET, 0, XSP_CR_TRANS_INHIBIT_MASK);
} else {
_wr_mask(xdesc, XSP_CR_OFFSET, XSP_CR_TRANS_INHIBIT_MASK,
XSP_CR_TRANS_INHIBIT_MASK);
_write(xdesc, XSP_SSR_OFFSET, xdesc->disable_slaves_mask);
}
xdesc->cs_asserted = start;
}
/* SPI polled transfer */
static int32_t xil_spi_write_and_read_pl(struct spi_desc *desc, uint8_t *data,
uint16_t bytes_number)
{
struct xspi_desc *xdesc;
uint32_t rx;
uint32_t tx;
if (!desc || !desc->extra)
return -EINVAL;
xdesc = desc->extra;
_update_mode(desc);
_xil_spi_start_transfer(desc, 1);
rx = 0;
tx = 0;
while (rx < bytes_number) {
if (tx < bytes_number)
tx += _wr_fifo(xdesc, data + tx, bytes_number - tx);
rx += _rd_fifo(xdesc, data + rx, bytes_number - rx);
}
_xil_spi_start_transfer(desc, 0);
return SUCCESS;
}
/* Get type of message. It can be READ, WRITE or both */
static uint32_t _get_msg_type(struct spi_msg *msg)
{
uint32_t type;
type = 0;
if (msg->tx_buff)
type |= XPS_TYPE_WRITE;
if (msg->rx_buff)
type |= XPS_TYPE_READ;
return type;
}
/* Get information based on current iterator position */
static void _get_data(struct msg_iter *it, uint8_t **buff, uint32_t *len,
uint32_t *type)
{
struct spi_msg *msg;
if (it->i == it->len) {
*len = 0;
return ;
}
msg = it->msgs + it->i;
if (it->is_wr)
*buff = msg->tx_buff;
else
*buff = msg->rx_buff;
if (*buff)
*buff += it->buff_i;
*len = msg->bytes_number - it->buff_i;
if (type)
*type = _get_msg_type(msg);
}
/*
* Increment iterator position with desired length.
* If the new position has a different message type, new_type will be set to 1
* If a CS change is needed, cs_change is set
*/
static void _increment_iter(struct msg_iter *it, uint32_t len,
uint8_t *cs_change, uint8_t *new_type)
{
struct spi_msg *msg;
uint32_t type;
uint32_t extra_len;
if (!len)
return ;
*cs_change = 0;
*new_type = 0;
msg = it->msgs + it->i;
if (it->buff_i + len > msg->bytes_number)
extra_len = it->buff_i + len - msg->bytes_number;
else
extra_len = 0;
len -= extra_len;
it->buff_i += len;
if (it->buff_i == msg->bytes_number) {
type = _get_msg_type(msg);
++it->i;
it->buff_i = 0;
if (cs_change && msg->cs_change)
*cs_change = 1;
if (new_type)
if (it->i == it->len ||
type != _get_msg_type(it->msgs + it->i))
*new_type = 1;
}
if (extra_len)
_increment_iter(it, extra_len, cs_change, new_type);
}
/*
* SPI polling transfer of multiple messages.
*/
static int32_t xil_spi_transfer_pl(struct spi_desc *desc, struct spi_msg *msgs,
uint32_t len)
{
struct xspi_desc *xdesc;
uint8_t cs_change;
uint8_t new_type;
struct msg_iter rx = {.msgs = msgs, .len = len, .is_wr = 0};
struct msg_iter tx = {.msgs = msgs, .len = len, .is_wr = 1};
uint8_t *buff;
uint32_t bytes;
uint32_t type;
/* Bytes to increment rx when only a write transaction is executed */
uint32_t to_inc_rx;
/* Difference between rx and tx iterators in bytes */
uint32_t tx_advance;
/* Save bytes sent during a write loop */
uint32_t tx_sent;
/* Used to loop if need to empty the RX FIFO */
uint32_t loop;
if (!desc || !desc->extra)
return -EINVAL;
xdesc = desc->extra;
_update_mode(desc);
tx_advance = 0;
to_inc_rx = 0;
buff = NULL;
type = 0;
do {
_xil_spi_start_transfer(desc, 1);
tx_sent = 0;
/* Writing loop */
do {
_get_data(&tx, &buff, &bytes, &type);
if (type & XPS_TYPE_READ)
/*
* Do not write more bytes than fifo_depth if
* they haven't been read.
*/
bytes = min(bytes,
xdesc->fifo_depth - tx_advance);
bytes = _wr_fifo(xdesc, buff, bytes);
tx_sent += bytes;
_increment_iter(&tx, bytes, &cs_change, &new_type);
tx_advance += bytes;
} while (!cs_change && !new_type && bytes);
if (type & XPS_TYPE_READ) {
loop = 1;
/*
* Loop only when no more data to write otherwise read
* only available data.
*/
while (loop) {
if (!new_type)
loop = 0;
_get_data(&rx, &buff, &bytes, NULL);
bytes = _rd_fifo(xdesc, buff, bytes);
_increment_iter(&rx, bytes, &cs_change, &new_type);
tx_advance -= bytes;
if (loop && new_type)
break;
}
} else {
/* Clean RX FIFO if it was only a WRITE message */
to_inc_rx += tx_sent;
if (new_type) {
/* Wait for TX to be sent */
while (!(_read(xdesc, XSP_SR_OFFSET) &
XSP_SR_TX_EMPTY_MASK))
;
/* Reset fifo. Only write was performed */
_wr_mask(xdesc, XSP_CR_OFFSET,
XSP_CR_RXFIFO_RESET_MASK,
XSP_CR_RXFIFO_RESET_MASK);
_increment_iter(&rx, to_inc_rx, NULL, NULL);
tx_advance -= to_inc_rx;
to_inc_rx = 0;
}
}
if ((cs_change && rx.i != len) || (!cs_change && rx.i == len))
_xil_spi_start_transfer(desc, 0);
} while (rx.i < len);
return SUCCESS;
}
const struct spi_platform_ops xil_spi_reg_ops_pl = {
.init = xil_spi_init_pl,
.remove = xil_spi_remove_pl,
.write_and_read = xil_spi_write_and_read_pl,
.write_and_read_3wire = NULL, // Not support.
.transfer = xil_spi_transfer_pl
};
#endif // XPAR_XSPI_NUM_INSTANCES
@@ -0,0 +1,151 @@
/***************************************************************************//**
* @file ad9361_reg.c
* @brief Implementation of AD9680 Driver.
* @author DBogdan ([email protected])
********************************************************************************
* Copyright 2014-2016(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include "ad9361_reg.h"
#include <stdlib.h>
#include <stdio.h>
#include "../../../include/error.h"
/***************************************************************************//**
* @brief ad9361_reg_read
*******************************************************************************/
int32_t ad9361_reg_read(struct ad9361_reg_dev *dev,
uint16_t reg_addr,
uint8_t *reg_data)
{
uint8_t tx_buf[2];
uint8_t rx_buf[1];
int32_t ret;
tx_buf[0] = reg_addr >> 8;
tx_buf[1] = reg_addr & 0xFF;
ret = spi_write_and_read_3wire(dev->spi_desc,
tx_buf, rx_buf, 2, 1);
*reg_data = rx_buf[0];
return ret;
}
/***************************************************************************//**
* @brief ad9361_reg_write
*******************************************************************************/
int32_t ad9361_reg_write(struct ad9361_reg_dev *dev,
uint16_t reg_addr,
uint8_t reg_data)
{
uint8_t buf[3];
int32_t ret;
buf[0] = 0x80 | reg_addr >> 8;
buf[1] = reg_addr & 0xFF;
buf[2] = reg_data;
ret = spi_write_and_read_3wire(dev->spi_desc,
buf, NULL, 3, 0);
return ret;
}
/***************************************************************************//**
* @brief ad9361_reg_init
*******************************************************************************/
int32_t ad9361_reg_init(struct ad9361_reg_dev **device,
const struct ad9361_reg_init_param *init_param)
{
int ret = SUCCESS;
struct ad9361_reg_dev *dev;
dev = (struct ad9361_reg_dev *)malloc(sizeof(*dev));
if (!dev)
return FAILURE;
/* SPI */
ret = spi_init(&dev->spi_desc, init_param->spi_init);
ret |= gpio_get(&dev->gpio_desc_resetb, init_param->gpio_resetb);
// gpio_direction_output(dev->gpio_desc_resetb, 0);
//
// ad9361_reg_reset(dev);
*device = dev;
return ret;
}
/**
* AD9361 Device Reset
* @param phy The AD9361 state structure.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad9361_reg_reset(struct ad9361_reg_dev *dev)
{
if (dev->gpio_desc_resetb) {
gpio_set_value(dev->gpio_desc_resetb, 0);
mdelay(10);
gpio_set_value(dev->gpio_desc_resetb, 1);
mdelay(10);
return 0;
}
return 0;
}
/***************************************************************************//**
* @brief Free the resources allocated by ad9361_reg_setup().
*
* @param dev - The device structure.
*
* @return SUCCESS in case of success, negative error code otherwise.
*******************************************************************************/
int32_t ad9361_reg_remove(struct ad9361_reg_dev *dev)
{
int32_t ret;
ret = spi_remove(dev->spi_desc);
free(dev);
return ret;
}
@@ -0,0 +1,104 @@
/***************************************************************************//**
* @file ad9361_reg.h
* @brief Header file of ad9361_reg Driver.
* @author DBogdan ([email protected])
********************************************************************************
* Copyright 2014-2016(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef ad9361_reg_H_
#define ad9361_reg_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdint.h>
#include "../../../include/delay.h"
#include "../../../include/spi.h"
#include "../../../include/gpio.h"
/******************************************************************************/
/********************** Macros and Constants Definitions **********************/
/******************************************************************************/
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
struct ad9361_reg_dev {
/* SPI */
spi_desc *spi_desc;
gpio_desc *gpio_desc_resetb;
};
struct ad9361_reg_init_param {
/* SPI */
spi_init_param *spi_init;
gpio_init_param *gpio_resetb;
};
enum Operation_Type{
AD9361_WRITE,
AD9361_READ,
AD9361_WAIT,
AD9361_WHEN
};
struct ad9361_reg_config {
int operation;
uint16_t val1;
uint16_t val2;
};
/******************************************************************************/
/************************ Functions Declarations ******************************/
/******************************************************************************/
int32_t ad9361_reg_read(struct ad9361_reg_dev *dev,
uint16_t reg_addr,
uint8_t *reg_data);
int32_t ad9361_reg_write(struct ad9361_reg_dev *dev,
uint16_t reg_addr,
uint8_t reg_data);
int32_t ad9361_reg_init(struct ad9361_reg_dev **device,
const struct ad9361_reg_init_param *init_param);
int32_t ad9361_reg_reset(struct ad9361_reg_dev *dev);
int32_t ad9361_reg_remove(struct ad9361_reg_dev *dev);
#endif
@@ -0,0 +1,59 @@
/***************************************************************************//**
* @file axi_io.h
* @brief Header file of AXI IO.
* @author Antoniu Miclaus ([email protected])
********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef AXI_IO_H_
#define AXI_IO_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdint.h>
/******************************************************************************/
/************************ Functions Declarations ******************************/
/******************************************************************************/
/* AXI IO Read data */
int32_t axi_io_read(uint32_t base, uint32_t offset, uint32_t *data);
/* AXI IO Write data */
int32_t axi_io_write(uint32_t base, uint32_t offset, uint32_t data);
#endif // AXI_IO_H_
@@ -0,0 +1,59 @@
/***************************************************************************//**
* @file delay.h
* @brief Header file of Delay functions
* @author DBogdan ([email protected])
********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef DELAY_H_
#define DELAY_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdint.h>
/******************************************************************************/
/************************ Functions Declarations ******************************/
/******************************************************************************/
/* Generate microseconds delay. */
void udelay(uint32_t usecs);
/* Generate miliseconds delay. */
void mdelay(uint32_t msecs);
#endif // DELAY_H_
@@ -0,0 +1,67 @@
/***************************************************************************//**
* @file error.h
* @brief Error codes definition
* @author DBogdan ([email protected])
********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef ERROR_H_
#define ERROR_H_
#include <errno.h>
/******************************************************************************/
/********************** Macros and Constants Definitions **********************/
/******************************************************************************/
#ifdef SUCCESS
#undef SUCCESS
#endif
#define SUCCESS 0
#ifdef FAILURE
#undef FAILURE
#endif
#define FAILURE -1
#ifndef __ELASTERROR
#define __ELASTERROR 2000
#endif
#define EOVERRUN (__ELASTERROR + 1) /* Circular buffer overrun */
#define IS_ERR_VALUE(x) ((x) < 0)
#endif // ERROR_H_
+165
View File
@@ -0,0 +1,165 @@
/***************************************************************************//**
* @file gpio.h
* @brief Header file of GPIO Interface
* @author DBogdan ([email protected])
********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef GPIO_H_
#define GPIO_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdint.h>
/******************************************************************************/
/********************** Macros and Constants Definitions **********************/
/******************************************************************************/
#define GPIO_OUT 0x01
#define GPIO_IN 0x00
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
/**
* @struct gpio_platform_ops
* @brief Structure holding gpio function pointers that point to the platform
* specific function
*/
struct gpio_platform_ops ;
/**
* @struct gpio_init_param
* @brief Structure holding the parameters for GPIO initialization.
*/
typedef struct gpio_init_param {
/** GPIO number */
int32_t number;
/** GPIO platform specific functions */
const struct gpio_platform_ops *platform_ops;
/** GPIO extra parameters (device specific) */
void *extra;
} gpio_init_param;
/**
* @struct gpio_desc
* @brief Structure holding the GPIO descriptor.
*/
typedef struct gpio_desc {
/** GPIO number */
int32_t number;
/** GPIO platform specific functions */
const struct gpio_platform_ops *platform_ops;
/** GPIO extra parameters (device specific) */
void *extra;
} gpio_desc;
/**
* @enum gpio_values
* @brief Enum that holds the possible output states of a GPIO.
*/
enum gpio_values {
/** GPIO logic low */
GPIO_LOW,
/** GPIO logic high */
GPIO_HIGH,
/** GPIO high impedance */
GPIO_HIGH_Z
};
/**
* @struct gpio_platform_ops
* @brief Structure holding gpio function pointers that point to the platform
* specific function
*/
struct gpio_platform_ops {
/** gpio initialization function pointer */
int32_t (*gpio_ops_get)(struct gpio_desc **, const struct gpio_init_param *);
/** gpio optional descriptor function pointer */
int32_t (*gpio_ops_get_optional)(struct gpio_desc **,
const struct gpio_init_param *);
/** gpio remove function pointer */
int32_t (*gpio_ops_remove)(struct gpio_desc *);
/** gpio direction input function pointer */
int32_t (*gpio_ops_direction_input)(struct gpio_desc *);
/** gpio direction output function pointer */
int32_t (*gpio_ops_direction_output)(struct gpio_desc *, uint8_t);
/** gpio get direction function pointer */
int32_t (*gpio_ops_get_direction)(struct gpio_desc *, uint8_t *);
/** gpio set value function pointer */
int32_t (*gpio_ops_set_value)(struct gpio_desc *, uint8_t);
/** gpio get value function pointer */
int32_t (*gpio_ops_get_value)(struct gpio_desc *, uint8_t *);
};
/******************************************************************************/
/************************ Functions Declarations ******************************/
/******************************************************************************/
/* Obtain the GPIO decriptor. */
int32_t gpio_get(struct gpio_desc **desc,
const struct gpio_init_param *param);
/* Obtain optional GPIO descriptor. */
int32_t gpio_get_optional(struct gpio_desc **desc,
const struct gpio_init_param *param);
/* Free the resources allocated by gpio_get() */
int32_t gpio_remove(struct gpio_desc *desc);
/* Enable the input direction of the specified GPIO. */
int32_t gpio_direction_input(struct gpio_desc *desc);
/* Enable the output direction of the specified GPIO. */
int32_t gpio_direction_output(struct gpio_desc *desc,
uint8_t value);
/* Get the direction of the specified GPIO. */
int32_t gpio_get_direction(struct gpio_desc *desc,
uint8_t *direction);
/* Set the value of the specified GPIO. */
int32_t gpio_set_value(struct gpio_desc *desc,
uint8_t value);
/* Get the value of the specified GPIO. */
int32_t gpio_get_value(struct gpio_desc *desc,
uint8_t *value);
#endif // GPIO_H_
+188
View File
@@ -0,0 +1,188 @@
/***************************************************************************//**
* @file irq.h
* @brief Header file of IRQ interface.
* @author Cristian Pop ([email protected])
********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef IRQ_H_
#define IRQ_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdint.h>
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
/**
* @enum irq_uart_event_e
* @brief Possible events for uart interrupt
*/
enum irq_uart_event_e {
/** Write operation finalized */
IRQ_WRITE_DONE,
/** Read operation finalized */
IRQ_READ_DONE,
/** An error occurred */
IRQ_ERROR
};
enum irq_trig_level {
IRQ_LEVEL_LOW,
IRQ_LEVEL_HIGH,
IRQ_EDGE_FALLING,
IRQ_EDGE_RISING,
IRQ_EDGE_BOTH
};
/**
* @struct irq_platform_ops
* @brief Structure holding IRQ function pointers that point to the platform
* specific function
*/
struct irq_platform_ops ;
/**
* @struct irq_init_param
* @brief Structure holding the initial parameters for Interrupt Request.
*/
struct irq_init_param {
/** Interrupt request controller ID. */
uint32_t irq_ctrl_id;
/** Platform specific IRQ platform ops structure. */
const struct irq_platform_ops *platform_ops;
/** IRQ extra parameters (device specific) */
void *extra;
};
/**
* @struct irq_desc
* @brief Structure for Interrupt Request descriptor.
*/
struct irq_ctrl_desc {
/** Interrupt request controller ID. */
uint32_t irq_ctrl_id;
/** Platform specific IRQ platform ops structure. */
const struct irq_platform_ops *platform_ops;
/** IRQ extra parameters (device specific) */
void *extra;
};
/**
* @struct callback_desc
* @brief Structure describing a callback to be registered
*/
struct callback_desc {
/**
* Callback to be called when the event an event occurs
* @param ctx - Same as \ref callback_desc.ctx
* @param event - Event that generated the callback
* @param extra - Platform specific data
*/
void (*callback)(void *ctx, uint32_t event, void *extra);
/** Parameter to be passed when the callback is called */
void *ctx;
/** Platform specific configuration for a callback */
void *config;
};
/**
* @struct irq_platform_ops
* @brief Structure holding IRQ function pointers that point to the platform
* specific function
*/
struct irq_platform_ops {
/** Initialize a interrupt controller peripheral. */
int32_t (*init)(struct irq_ctrl_desc **desc,
const struct irq_init_param *param);
/** Register a callback to handle the irq events */
int32_t (*register_callback)(struct irq_ctrl_desc *desc, uint32_t irq_id,
struct callback_desc *callback_desc);
/** Unregisters a generic IRQ handling function */
int32_t (*unregister)(struct irq_ctrl_desc *desc, uint32_t irq_id);
/** Global interrupt enable */
int32_t (*global_enable)(struct irq_ctrl_desc *desc);
/** Global interrupt disable */
int32_t (*global_disable)(struct irq_ctrl_desc *desc);
/** Set interrupt trigger level. */
int32_t (*trigger_level_set)(struct irq_ctrl_desc *desc, uint32_t irq_id,
enum irq_trig_level trig);
/** Enable specific interrupt */
int32_t (*enable)(struct irq_ctrl_desc *desc, uint32_t irq_id);
/** Disable specific interrupt */
int32_t (*disable)(struct irq_ctrl_desc *desc, uint32_t irq_id);
/** IRQ remove function pointer */
int32_t (*remove)(struct irq_ctrl_desc *desc);
};
/******************************************************************************/
/************************ Functions Declarations ******************************/
/******************************************************************************/
/* Initialize a interrupt controller peripheral. */
int32_t irq_ctrl_init(struct irq_ctrl_desc **desc,
const struct irq_init_param *param);
/* Free the resources allocated by irq_ctrl_init(). */
int32_t irq_ctrl_remove(struct irq_ctrl_desc *desc);
/* Register a callback to handle the irq events */
int32_t irq_register_callback(struct irq_ctrl_desc *desc, uint32_t irq_id,
struct callback_desc *callback_desc);
/* Unregisters a generic IRQ handling function */
int32_t irq_unregister(struct irq_ctrl_desc *desc, uint32_t irq_id);
/* Global interrupt enable */
int32_t irq_global_enable(struct irq_ctrl_desc *desc);
/* Global interrupt disable */
int32_t irq_global_disable(struct irq_ctrl_desc *desc);
/* Set interrupt trigger level. */
int32_t irq_trigger_level_set(struct irq_ctrl_desc *desc, uint32_t irq_id,
enum irq_trig_level trig);
/* Enable specific interrupt */
int32_t irq_enable(struct irq_ctrl_desc *desc, uint32_t irq_id);
/* Disable specific interrupt */
int32_t irq_disable(struct irq_ctrl_desc *desc, uint32_t irq_id);
#endif // IRQ_H_
+194
View File
@@ -0,0 +1,194 @@
/***************************************************************************//**
* @file spi.h
* @brief Header file of SPI Interface
* @author DBogdan ([email protected])
********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef SPI_H_
#define SPI_H_
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdint.h>
/******************************************************************************/
/********************** Macros and Constants Definitions **********************/
/******************************************************************************/
#define SPI_CPHA 0x01
#define SPI_CPOL 0x02
#define SPI_3WIRE 0x04
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
/**
* @enum spi_mode
* @brief SPI configuration for clock phase and polarity.
*/
typedef enum spi_mode {
/** Data on rising, shift out on falling */
SPI_MODE_0 = (0 | 0),
/** Data on falling, shift out on rising */
SPI_MODE_1 = (0 | SPI_CPHA),
/** Data on falling, shift out on rising */
SPI_MODE_2 = (SPI_CPOL | 0),
/** Data on rising, shift out on falling */
SPI_MODE_3 = (SPI_CPOL | SPI_CPHA),
/** Data on rising, shift out on falling */
SPI_MODE_4 = SPI_3WIRE
} spi_mode;
/**
* @enum spi_bit_order
* @brief SPI configuration for bit order (MSB/LSB).
*/
typedef enum spi_bit_order {
/** Most-significant bit (MSB) first */
SPI_BIT_ORDER_MSB_FIRST = 0,
/** Least-significant bit (LSB) first */
SPI_BIT_ORDER_LSB_FIRST = 1,
} spi_bit_order;
/**
* @struct spi_msg_list
* @brief List item describing a SPI transfer
*/
struct spi_msg {
/** Buffer with data to send. If NULL, 0x00 will be sent */
uint8_t *tx_buff;
/** Buffer where to store data. If NULL, incoming data won't be saved */
uint8_t *rx_buff;
/** Length of buffers. Must have equal size. */
uint32_t bytes_number;
/** If set, CS will be deasserted after the transfer */
uint8_t cs_change;
};
/**
* @struct spi_platform_ops
* @brief Structure holding SPI function pointers that point to the platform
* specific function
*/
struct spi_platform_ops ;
/**
* @struct spi_init_param
* @brief Structure holding the parameters for SPI initialization
*/
typedef struct spi_init_param {
/** Device ID */
uint32_t device_id;
/** maximum transfer speed */
uint32_t max_speed_hz;
/** SPI chip select */
uint8_t chip_select;
/** SPI mode */
enum spi_mode mode;
/** SPI bit order */
enum spi_bit_order bit_order;
const struct spi_platform_ops *platform_ops;
/** SPI extra parameters (device specific) */
void *extra;
} spi_init_param;
/**
* @struct spi_desc
* @brief Structure holding SPI descriptor.
*/
typedef struct spi_desc {
/** Device ID */
uint32_t device_id;
/** maximum transfer speed */
uint32_t max_speed_hz;
/** SPI chip select */
uint8_t chip_select;
/** SPI mode */
enum spi_mode mode;
/** SPI bit order */
enum spi_bit_order bit_order;
const struct spi_platform_ops *platform_ops;
/** SPI extra parameters (device specific) */
void *extra;
} spi_desc;
/**
* @struct spi_platform_ops
* @brief Structure holding SPI function pointers that point to the platform
* specific function
*/
struct spi_platform_ops {
/** SPI initialization function pointer */
int32_t (*init)(struct spi_desc **, const struct spi_init_param *);
/** SPI write/read function pointer */
int32_t (*write_and_read)(struct spi_desc *, uint8_t *, uint16_t);
/** SPI write function pointer */
int32_t (*write_and_read_3wire)(struct spi_desc *, uint8_t *,uint8_t *,uint16_t, uint16_t);
/** Iterate over the spi_msg array and send all messages at once */
int32_t (*transfer)(struct spi_desc *, struct spi_msg *, uint32_t);
/** SPI remove function pointer */
int32_t (*remove)(struct spi_desc *);
};
/******************************************************************************/
/************************ Functions Declarations ******************************/
/******************************************************************************/
/* Initialize the SPI communication peripheral. */
int32_t spi_init(struct spi_desc **desc,
const struct spi_init_param *param);
/* Free the resources allocated by spi_init(). */
int32_t spi_remove(struct spi_desc *desc);
/* Write and read data to/from SPI. */
int32_t spi_write_and_read(struct spi_desc *desc,
uint8_t *data,
uint16_t bytes_number);
int32_t spi_write_and_read_3wire(struct spi_desc *desc,
uint8_t *write_data,
uint8_t *read_data,
uint16_t write_bytes_number,
uint16_t read_bytes_number);
/* Iterate over the spi_msg array and send all messages at once */
int32_t spi_transfer(struct spi_desc *desc, struct spi_msg *msgs, uint32_t len);
#endif // SPI_H_
+452
View File
@@ -0,0 +1,452 @@
/*****************************************************************************/
/**
* Description: A simple AXI DMA api.
*
* Author: Fan Hao
* Date: 2022-06-18 16:37
* LastEditors: Fan Hao
* LastEditTime: 2022-06-18 17:38
* Revisions: Rev 0.0
* History:
* [2022-06-18]: Initial version.
*
* Copyright(c) 2022 Beijing Institute of Technology.
* Lab of Communication and Networking
*
******************************************************************************/
/***************************** Include Files *********************************/
#include <stdint.h>
#include <stdbool.h>
#include "xaxidma.h"
// #include "xtime_l.h" //Adjutment for microblaze
#include "xil_cache.h"
#include "axi_dma.h"
#include "../error.h"
#include "../common.h"
/************************** Constant Definitions *****************************/
/***************** Macros (Inline Functions) Definitions *********************/
/************************** Function Prototypes ******************************/
/**************************** Type Definitions *******************************/
/************************** Variable Definitions *****************************/
/*****************************************************************************/
/**
* @brief Initialize the DMA descriptor instance, allocate space for
* descriptor.
*
* @param instPtr a second rank pointer to DMA descriptor instance
* @param configPtr a pointer to DMA descriptor instance configuration
* set.
*
* @return SUCCESS
* ENOMEM memory allocate failed.
* other error codes
*
******************************************************************************/
int32_t Dma_Init(DMA_DESC** instPtr, const DMA_CONFIG* configPtr){
ASSERT(configPtr != NULL);
int32_t Status = SUCCESS;
*instPtr = (DMA_DESC*) malloc(sizeof(DMA_DESC));
if ((*instPtr) == NULL) {
goto err;
}
(*instPtr)->isTxDone = false;
(*instPtr)->isRxDone = false;
(*instPtr)->isError = false;
(*instPtr)->isListening = false;
memcpy(&((*instPtr)->configs), configPtr, sizeof(DMA_CONFIG));
(*instPtr)->axiDmaPtr = (XAxiDma*) malloc(sizeof(XAxiDma));
if ((*instPtr)->axiDmaPtr == NULL) {
free((*instPtr)->axiDmaPtr);
goto err;
}
XAxiDma_Config* damConfigPtr = NULL;
damConfigPtr = XAxiDma_LookupConfig(configPtr->devId);
if (damConfigPtr == NULL) {
DBG_PRINT("No config found for %d\r\n", configPtr->devId);
goto err;
}
/* Initialize DMA engine */
Status = XAxiDma_CfgInitialize((*instPtr)->axiDmaPtr, damConfigPtr);
if (Status != SUCCESS) {
DBG_ERROR("DMA initialize failed. device id: %d\r\n", configPtr->devId);
goto err;
}
if(XAxiDma_HasSg((*instPtr)->axiDmaPtr)){
DBG_ERROR("DMA Device configured as SG mode \r\n");
goto err;
}
/* Clear all interrupts before setup */
XAxiDma_IntrAckIrq((*instPtr)->axiDmaPtr, XAXIDMA_IRQ_ALL_MASK,
XAXIDMA_DMA_TO_DEVICE);
XAxiDma_IntrAckIrq((*instPtr)->axiDmaPtr, XAXIDMA_IRQ_ALL_MASK,
XAXIDMA_DEVICE_TO_DMA);
/* Disable all interrupts before setup */
XAxiDma_IntrDisable((*instPtr)->axiDmaPtr, XAXIDMA_IRQ_ALL_MASK,
XAXIDMA_DMA_TO_DEVICE);
XAxiDma_IntrDisable((*instPtr)->axiDmaPtr, XAXIDMA_IRQ_ALL_MASK,
XAXIDMA_DEVICE_TO_DMA);
(*instPtr)->isInitialized = true;
return SUCCESS;
err:
free(*instPtr);
return Status;
}
/*****************************************************************************/
/**
* @brief Enable DMA IRQs.
*
* @param instPtr a pointer to DMA descriptor instance.
*
* @return SUCCESS
* EDINVAL device not initialized.
*
******************************************************************************/
int32_t Dma_IrqEnable(DMA_DESC* instPtr){
if(instPtr == NULL || instPtr->isInitialized == false){
return EDINVAL;
}
/* Enable all interrupts */
XAxiDma_IntrEnable(instPtr->axiDmaPtr, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DMA_TO_DEVICE);
XAxiDma_IntrEnable(instPtr->axiDmaPtr, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA);
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Enable DMA listening feature and start a receive procedure.
*
* @param instPtr a pointer to DMA descriptor instance.
* @param dataBuff a pointer to data buffer.
*
* @return SUCCESS
* EDINVAL device not initialized.
*
******************************************************************************/
int32_t Dma_ListenEnable(DMA_DESC* instPtr, uint8_t* dataBuff){
if(instPtr == NULL || instPtr->isInitialized == false || dataBuff == NULL){
return EDINVAL;
}
instPtr->isListening = true;
instPtr->listenBuff = dataBuff;
// if(XAxiDma_Busy(instPtr->axiDmaPtr, XAXIDMA_DEVICE_TO_DMA) == false){
return XAxiDma_SimpleTransfer(instPtr->axiDmaPtr,(uintptr_t)instPtr->listenBuff,
instPtr->configs.defaultTransLen, XAXIDMA_DEVICE_TO_DMA);
// }
// else{
// return SUCCESS;
// }
}
/*****************************************************************************/
/**
* @brief Disable DMA listening feature and start a receive procedure.
*
* @param instPtr a pointer to DMA descriptor instance.
*
* @return SUCCESS
* EDINVAL device not initialized.
*
******************************************************************************/
int32_t Dma_ListenDisable(DMA_DESC* instPtr){
if(instPtr == NULL || instPtr->isInitialized == false){
return EDINVAL;
}
instPtr->isListening = false;
instPtr->listenBuff = NULL;
if(XAxiDma_Busy(instPtr->axiDmaPtr, XAXIDMA_DEVICE_TO_DMA) == true){
DBG_WARNING("an unfinished transfer is on going.\r\n");
}
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Transfer a specific length of data (DMA->Device), none-blocking
* transfer.
*
* @param instPtr a pointer to DMA descriptor instance.
* @param dataBuff a pointer to data buffer.
* @param dataLen length of data need to be transfer.
*
* @return SUCCESS
* EDINVAL device not initialized.
*
******************************************************************************/
int32_t Dma_SendData(DMA_DESC* instPtr, uint8_t* dataBuff, int32_t dataLen){
int32_t Status;
if(dataLen > instPtr->configs.transMax){
return FAILURE;
}
// Flush the SrcBuffer before the DMA transfer
// Xil_DCacheFlushRange((uintptr_t)dataBuff, dataLen);
// Set txDone flage to false, before transmission
instPtr->isTxDone = false;
// Assert a send trigger
Status = XAxiDma_SimpleTransfer(instPtr->axiDmaPtr, (uintptr_t)dataBuff,
dataLen, XAXIDMA_DMA_TO_DEVICE);
if (Status != SUCCESS) {
return FAILURE;
}
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Transfer a specific length of data (DMA->Device), blocking transfer.
*
* @param instPtr a pointer to DMA descriptor instance.
* @param dataBuff a pointer to data buffer.
* @param dataLen length of data need to be transfer.
*
* @return SUCCESS
* ETIMEOUT transfer timeout.
* other error codes.
*
******************************************************************************/
int32_t Dma_BlockingSendData(DMA_DESC* instPtr, uint8_t* dataBuff, int32_t dataLen){
int32_t Status;
if(dataLen > instPtr->configs.transMax){
return EINVAL;
}
Status = Dma_SendData(instPtr, dataBuff, dataLen);
if(Status == SUCCESS){
DBG_ERROR("Failed to setup a DMA transfer (DMA->Device).\r\n");
return Status;
}
//Adjutment for microblaze
// XTime tCur = 0;
// XTime tTimeOut = 0;
// XTime_GetTime(&tCur);
// tTimeOut = tCur + instPtr->configs.timeoutTh;
while(instPtr->isTxDone == false && instPtr->isError == false){
//Adjutment for microblaze
// XTime_GetTime(&tCur);
// if(tCur >= tTimeOut){
// return ETIMEOUT;
// }
}
if(instPtr->isError == true){
return FAILURE;
}
// Set txDone flage to false, after transmission
instPtr->isTxDone = false;
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Transfer a specific length of data (Device->DMA), none-blocking
* transfer.
*
* @param instPtr a pointer to DMA descriptor instance.
* @param dataBuff a pointer to data buffer.
* @param dataLen length of data need to be transfer.
*
* @return SUCCESS
* EDINVAL device not initialized.
*
******************************************************************************/
int32_t Dma_RecvData(DMA_DESC* instPtr, uint8_t* dataBuff, int32_t dataLen){
int32_t Status;
if(dataLen > instPtr->configs.transMax){
return FAILURE;
}
// Set txDone flage to false, before transmission
instPtr->isRxDone = false;
// Assert a send trigger
Status = XAxiDma_SimpleTransfer(instPtr->axiDmaPtr,(uintptr_t)dataBuff,
dataLen, XAXIDMA_DEVICE_TO_DMA);
if (Status != SUCCESS) {
return FAILURE;
}
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Transfer a specific length of data (Device->DMA), blocking transfer.
*
* @param instPtr a pointer to DMA descriptor instance.
* @param dataBuff a pointer to data buffer.
* @param dataLen length of data need to be transfer.
*
* @return SUCCESS
* EDINVAL device not initialized.
*
******************************************************************************/
int32_t Dma_BlockingRecvData(DMA_DESC* instPtr, uint8_t* dataBuff, int32_t dataLen){
int32_t Status;
if(dataLen > instPtr->configs.transMax){
return FAILURE;
}
Status = Dma_RecvData(instPtr, dataBuff, dataLen);
if(Status == SUCCESS){
DBG_ERROR("Failed to setup a DMA transfer (Device->DMA).\r\n");
return Status;
}
//Adjutment for microblaze
// XTime tCur = 0;
// XTime tTimeOut = 0;
// XTime_GetTime(&tCur);
// tTimeOut = tCur + instPtr->configs.timeoutTh;
while(instPtr->isTxDone == false && instPtr->isError == false){
//Adjutment for microblaze
// XTime_GetTime(&tCur);
// if(tCur >= tTimeOut){
// return ETIMEOUT;
// }
}
if(instPtr->isError == true){
return FAILURE;
}
// Set txDone flage to false, after transmission
instPtr->isTxDone = false;
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Handler for DMA->Device transfer.
*
* @param instPtr a pointer to DMA descriptor instance.
*
* @return SUCCESS
* error codes
*
******************************************************************************/
int32_t Dma_SendIrqHandler(DMA_DESC* instPtr){
if(instPtr == NULL || instPtr->isInitialized == false){
return FAILURE;
}
int32_t Status = SUCCESS;
uint32_t IrqStatus = 0;
/* Read pending interrupts */
IrqStatus = XAxiDma_IntrGetIrq(instPtr->axiDmaPtr, XAXIDMA_DMA_TO_DEVICE);
/* Acknowledge pending interrupts */
XAxiDma_IntrAckIrq(instPtr->axiDmaPtr, IrqStatus, XAXIDMA_DMA_TO_DEVICE);
/* If no interrupt is asserted, we do not do anything */
if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {
return EIGNORE;
}
/* If error interrupt is asserted, raise error flag, reset the
* hardware to recover from the error, and return with no further
* processing.
*/
if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {
instPtr->isError = true;
/* Reset should never fail for transmit channel */
XAxiDma_Reset(instPtr->axiDmaPtr);
while (XAxiDma_ResetIsDone(instPtr->axiDmaPtr) == false) {
// FIXME: Add time out check
}
return EUNEXP;
}
/* If Completion interrupt is asserted, then set the TxDone flag */
if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK)) {
instPtr->isTxDone = true;
}
return Status;
}
/*****************************************************************************/
/**
* @brief Handler for Device->DMA transfer.
*
* @param instPtr a pointer to DMA descriptor instance.
*
* @return SUCCESS
* error codes
*
******************************************************************************/
int32_t Dma_RecvIrqHandler(DMA_DESC* instPtr){
if(instPtr == NULL || instPtr->isInitialized == false){
return FAILURE;
}
int32_t Status = SUCCESS;
uint32_t IrqStatus = 0;
/* Read pending interrupts */
IrqStatus = XAxiDma_IntrGetIrq(instPtr->axiDmaPtr, XAXIDMA_DEVICE_TO_DMA);
/* Acknowledge pending interrupts */
XAxiDma_IntrAckIrq(instPtr->axiDmaPtr, IrqStatus, XAXIDMA_DEVICE_TO_DMA);
/* If no interrupt is asserted, we do not do anything */
if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {
return EIGNORE;
}
/* If error interrupt is asserted, raise error flag, reset the
* hardware to recover from the error, and return with no further
* processing.
*/
if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {
instPtr->isError = true;
/* Reset should never fail for transmit channel */
XAxiDma_Reset(instPtr->axiDmaPtr);
while (XAxiDma_ResetIsDone(instPtr->axiDmaPtr)) {
// FIXME: Add time out check
}
return EUNEXP;
}
/* If completion interrupt is asserted, then set RxDone flag */
if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK)) {
// // Invalid the DestBuffer after the DMA transfer
// int RingIndex = 0;
// uintptr_t dstAddr;
// uint32_t transLen;
// dstAddr = XAxiDma_ReadReg(instPtr->axiDmaPtr->RxBdRing[RingIndex].ChanBase, XAXIDMA_DESTADDR_OFFSET);
// if (instPtr->axiDmaPtr->AddrWidth > 32){
// dstAddr |= ((uintptr_t)(XAxiDma_ReadReg(instPtr->axiDmaPtr->RxBdRing[RingIndex].ChanBase,
// XAXIDMA_DESTADDR_MSB_OFFSET))<<32);
// }
// transLen = XAxiDma_ReadReg(InstancePtr->RxBdRing[RingIndex].ChanBase, XAXIDMA_BUFFLEN_OFFSET)
// Xil_DCacheInvalidateRange(dstAddr, transLen);
instPtr->isRxDone = true;
}
if(instPtr->isListening == true){
// Continuous receiving
Status = XAxiDma_SimpleTransfer(instPtr->axiDmaPtr,(uintptr_t)instPtr->listenBuff,
instPtr->configs.defaultTransLen, XAXIDMA_DEVICE_TO_DMA);
if(Status != SUCCESS){
DBG_ERROR("Failed to start a new SimpleTransfer in XAXIDMA_DEVICE_TO_DMA channel.\r\n");
}
}
return Status;
}
+62
View File
@@ -0,0 +1,62 @@
/*****************************************************************************/
/**
* Description: A simple AXI DMA api.
* prototypes.
*
* Author: Fan Hao
* Date: 2022-06-18 16:37
* LastEditors: Fan Hao
* LastEditTime: 2022-06-18 17:40
* Revisions: Rev 0.0
* History:
* [2022-06-18]: Initial version.
*
* Copyright(c) 2022 Beijing Institute of Technology.
* Lab of Communication and Networking
*
******************************************************************************/
#ifndef AXI_DMA_H_
#define AXI_DMA_H_
/***************************** Include Files *********************************/
#include <stdint.h>
#include <stdbool.h>
#include "xaxidma.h"
/************************** Constant Definitions *****************************/
/***************** Macros (Inline Functions) Definitions *********************/
/**************************** Type Definitions *******************************/
typedef struct{
uint32_t devId;
uint32_t transMax;
uint32_t defaultTransLen;
uint32_t timeoutTh;
}DMA_CONFIG;
typedef struct{
bool isTxDone;
bool isRxDone;
bool isError;
bool isListening;
bool isInitialized;
uint8_t* listenBuff;
XAxiDma* axiDmaPtr;
DMA_CONFIG configs;
}DMA_DESC;
/************************** Variable Definitions *****************************/
/************************** Function Prototypes ******************************/
int32_t Dma_Init(DMA_DESC** instPtr, const DMA_CONFIG* configPtr);
int32_t Dma_IrqEnable(DMA_DESC* instPtr);
int32_t Dma_ListenEnable(DMA_DESC* instPtr, uint8_t* dataBuff);
int32_t Dma_ListenDisable(DMA_DESC* instPtr);
int32_t Dma_SendData(DMA_DESC* instPtr, uint8_t* dataBuff, int32_t dataLen);
int32_t Dma_BlockingSendData(DMA_DESC* instPtr, uint8_t* dataBuff, int32_t dataLen);
int32_t Dma_RecvData(DMA_DESC* instPtr, uint8_t* dataBuff, int32_t dataLen);
int32_t Dma_BlockingRecvData(DMA_DESC* instPtr, uint8_t* dataBuff, int32_t dataLen);
int32_t Dma_SendIrqHandler(DMA_DESC* instPtr);
int32_t Dma_RecvIrqHandler(DMA_DESC* instPtr);
#endif //AXI_DMA_H_
+211
View File
@@ -0,0 +1,211 @@
/*****************************************************************************/
/**
* Description: Implementations of chip to chip data bridge.
*
* Author: Fan Hao
* Date: 2022-09-02 15:01
* LastEditors: Fan Hao
* LastEditTime: 2022-09-02 15:49
* Revisions: Rev 0.0
* History:
* [2022-09-02]: Initial version
*
* Note:
* Branch from Analog Devices version (by DBogdan [email protected]).
*
* Copyright(c) 2022 Beijing Institute of Technology.
* Lab of Communication and Networking
*
******************************************************************************/
/***************************** Include Files **********************************/
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include "c2c_bridge.h"
#include "xgpio.h"
#include "../axi_dma/axi_dma.h"
#include "../util/util.h"
#include "../error.h"
#include "../common.h"
/************************** Constant Definitions *****************************/
// C2C Configs
#define C2C_GPIO_OUT_CH 1
#define C2C_SEND_TRIGGER BIT(0)
#define C2C_RECV_TRIGGER BIT(1)
/************************** Variable Definitions *****************************/
C2C_DESC* c2cInstPtr = NULL;
/************************** Function Prototypes ******************************/
inline bool C2c_IsSendBusy(C2C_DESC* instPtr){
ASSERT(instPtr != NULL);
return (instPtr->txDone == false);
}
inline bool C2c_IsRecvBusy(C2C_DESC* instPtr){
ASSERT(instPtr != NULL);
return (instPtr->rxDone == false);
}
/*****************************************************************************/
/**
* @brief Initialize c2c bridge descriptor instance.
*
* @param instPtr second rank pointer to c2c instance.
* @param configPtr pointer to c2c instance configuration struct.
*
* @return NONE
*
******************************************************************************/
int32_t C2c_Init(C2C_DESC** instPtr, C2C_CONFIG* configPtr){
ASSERT(configPtr != NULL);
int32_t Status;
(*instPtr) = (C2C_DESC*)malloc(sizeof(C2C_DESC));
if((*instPtr) == NULL){
return EALLOC;
}
memcpy(&(*instPtr)->c2cCofig, configPtr, sizeof(C2C_CONFIG));
Status = Dma_Init(&((*instPtr)->axiDmaInst), &(*instPtr)->c2cCofig.dmaConfig);
if(Status != SUCCESS){
DBG_ERROR("C2C axi DMA init failed, with error code: %d.\r\n", Status);
return Status;
}
(*instPtr)->isInit = true;
(*instPtr)->txDone = true;
(*instPtr)->rxDone = true;
(*instPtr)->lastRxBuff = (uintptr_t)NULL;
(*instPtr)->lastRxBuffSize = 0;
return SUCCESS;
}
int32_t C2c_IrqEnable(C2C_DESC* instPtr){
if(instPtr==NULL || instPtr->isInit == false){
return FAILURE;
}
/* Enable all interrupts */
return Dma_IrqEnable(instPtr->axiDmaInst);
}
/*****************************************************************************/
/**
* @brief Send data through c2c bridge.
*
* @param instPtr second rank pointer to c2c instance.
* @param buff data buffer stores the data needs to be sent
* @param dLen data length needs to be sent
*
* @return NONE
*
******************************************************************************/
int32_t C2c_SendData(C2C_DESC* instPtr, uint8_t* buff, uint32_t dLen){
ASSERT(instPtr != NULL);
ASSERT(buff != NULL);
if(instPtr->isInit == false){
return EDINVAL;
}
if(dLen > instPtr->c2cCofig.capacity){
return EPARAM;
}
IO_Out32((uintptr_t)(buff + C2C_HEAD_OFFSET), C2C_HEADER);
IO_Out32((uintptr_t)(buff + C2C_DLEN_OFFSET), dLen + C2C_HEADER_LEN);
instPtr->txDone = false;
instPtr->lastTxBuff = (uintptr_t)buff;
instPtr->lastTxBuffSize = dLen;
if (SUCCESS == Dma_SendData(instPtr->axiDmaInst, buff, dLen + C2C_HEADER_LEN)){
return SUCCESS;
}
else{
return FAILURE;
}
return SUCCESS;
}
int32_t C2c_BlockingSendData(C2C_DESC* instPtr, uint8_t* buff, uint32_t dLen) {
ASSERT(instPtr != NULL);
ASSERT(buff != NULL);
if(instPtr->isInit == false){
return EDINVAL;
}
if(dLen > instPtr->c2cCofig.capacity){
return EPARAM;
}
IO_Out32((uintptr_t)(buff + C2C_HEAD_OFFSET), C2C_HEADER);
IO_Out32((uintptr_t)(buff + C2C_DLEN_OFFSET), dLen + C2C_HEADER_LEN);
instPtr->txDone = false;
instPtr->lastTxBuff = (uintptr_t)buff;
instPtr->lastTxBuffSize = dLen;
if (SUCCESS == Dma_BlockingSendData(instPtr->axiDmaInst, buff, dLen + C2C_HEADER_LEN)){
return SUCCESS;
}
else{
return FAILURE;
}
}
/*****************************************************************************/
/**
* @brief Receive data from c2c bridge.
*
* @param instPtr second rank pointer to c2c instance.
* @param buff data buffer stores the received data.
* @param dLen data length that received
*
* @return NONE
*
******************************************************************************/
int32_t C2c_RecvData(C2C_DESC* instPtr, uint8_t* buff, uint32_t buffSize){
ASSERT(instPtr != NULL);
ASSERT(buff != NULL);
if(instPtr->isInit == false){
return EDINVAL;
}
instPtr->rxDone = false;
instPtr->lastRxBuff = (uintptr_t)buff;
instPtr->lastRxBuffSize = buffSize;
if (SUCCESS == Dma_RecvData(instPtr->axiDmaInst, buff, buffSize)){
return SUCCESS;
}
else{
return FAILURE;
}
}
int32_t C2c_SendIrqHandler(C2C_DESC* instPtr){
ASSERT(instPtr != NULL);
if(instPtr->isInit == false){
return EDINVAL;
}
instPtr->txDone = true;
if (SUCCESS == Dma_SendIrqHandler(instPtr->axiDmaInst)){
return SUCCESS;
}
else{
return EUNEXP;
}
}
int32_t C2c_RecvIrqHandler(C2C_DESC* instPtr){
ASSERT(instPtr != NULL);
if(instPtr->isInit == false){
return EDINVAL;
}
instPtr->rxDone = true;
if (SUCCESS == Dma_RecvIrqHandler(instPtr->axiDmaInst)){
return SUCCESS;
}
else{
return EUNEXP;
}
if(IO_In32(instPtr->lastRxBuff + C2C_HEAD_OFFSET) != C2C_HEADER){
return EIGNORE;
}
if(IO_In32(instPtr->lastRxBuff + C2C_DLEN_OFFSET) > instPtr->lastRxBuffSize){
return EIGNORE;
}
return SUCCESS;
}
@@ -0,0 +1,62 @@
/*****************************************************************************/
/**
* Description: Chip to chip data bridge.
*
* Author: Fan Hao
* Date: 2022-09-02 15:01
* LastEditors: Fan Hao
* LastEditTime: 2022-09-02 15:49
* Revisions: Rev 0.0
* History:
* [2022-09-02]: Initial version
* [2023-02-23]: DMA version
*
* Note:
* Branch from Analog Devices version (by DBogdan [email protected]).
*
* Copyright(c) 2022 Beijing Institute of Technology.
* Lab of Communication and Networking
*
******************************************************************************/
#include <stdint.h>
#include <stdbool.h>
#include "../axi_dma/axi_dma.h"
/************************** Constant Definitions *****************************/
#define C2C_HEADER_LEN 8 //bytes
#define C2C_HEADER 0x7E7E7E7E
#define C2C_HEAD_OFFSET 0
#define C2C_DLEN_OFFSET 4
#define C2C_PLOAD_OFFSET 8
#define C2C_BUFF_MAX 1024
/**************************** Type Definitions *******************************/
typedef struct {
uint32_t capacity;
DMA_CONFIG dmaConfig;
} C2C_CONFIG;
typedef struct {
C2C_CONFIG c2cCofig;
DMA_DESC* axiDmaInst;
bool isInit;
bool txDone;
bool rxDone;
uintptr_t lastTxBuff;
uint32_t lastTxBuffSize;
uintptr_t lastRxBuff;
uint32_t lastRxBuffSize;
} C2C_DESC;
/************************** Variable Definitions *****************************/
extern C2C_DESC* c2cInstPtr;
/************************** Function Prototypes ******************************/
int32_t C2c_Init(C2C_DESC** instPtr, C2C_CONFIG* configPtr);
int32_t C2c_IrqEnable(C2C_DESC* instPtr);
int32_t C2c_SendData(C2C_DESC* instPtr, uint8_t* buff, uint32_t dLen);
int32_t C2c_RecvData(C2C_DESC* instPtr, uint8_t* buff, uint32_t buffSize);
int32_t C2c_BlockingSendData(C2C_DESC* instPtr, uint8_t* buff, uint32_t dLen);
bool C2c_IsSendBusy(C2C_DESC* instPtr);
bool C2c_IsRecvBusy(C2C_DESC* instPtr);
int32_t C2c_SendIrqHandler(C2C_DESC* instPtr);
int32_t C2c_RecvIrqHandler(C2C_DESC* instPtr);
+158
View File
@@ -0,0 +1,158 @@
/*****************************************************************************/
/**
* Description: A simple circular FIFO bounded queue
*
* Author: Fan Hao
* Date: 2023-02-23 10:29
* LastEditors: Fan Hao
* LastEditTime: 2023-02-23 13:18
* Revisions: Rev 0.0
* History:
* [2023-02-23]: Initial Version.
*
* Copyright(c) 2023 Beijing Institute of Technology.
* Lab of Communication and Networking
* NOTE: Forked from https://github.com/chrismerck/rpa_queue.git
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "circ_queue.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
// uncomment to print debug messages
//#define QUEUE_DEBUG
struct CIRC_QUEUE_S {
void **data;
volatile uint32_t nelts; /**< # elements */
uint32_t in; /**< next empty location */
uint32_t out; /**< next filled location */
uint32_t bounds;/**< max size of queue */
uint32_t full_waiters;
uint32_t empty_waiters;
pthread_mutex_t *one_big_mutex;
pthread_cond_t *not_empty;
pthread_cond_t *not_full;
};
#ifdef QUEUE_DEBUG
static void Q_DBG(const char*msg, CIRC_QUEUE *q) {
printf("#%d in %d out %d\t%s\n",
q->nelts, q->in, q->out,
msg
);
}
#else
#define Q_DBG(x,y)
#endif
void CircQueueFree(CIRC_QUEUE * queue)
{
assert(queue != NULL);
if (queue->data) free(queue->data);
free(queue);
}
/**
* Initialize the CIRC_QUEUE.
*/
bool CircQueueCreate(CIRC_QUEUE **q, uint32_t queueCapacity)
{
assert(q != NULL);
CIRC_QUEUE *queue;
queue = malloc(sizeof(CIRC_QUEUE));
if (!queue) {
return false;
}
*q = queue;
memset(queue, 0, sizeof(CIRC_QUEUE));
/* Set all the data in the queue to NULL */
queue->data = malloc(queueCapacity * sizeof(void*));
if(queue->data == NULL){
goto error;
}
queue->bounds = queueCapacity;
queue->nelts = 0;
queue->in = 0;
queue->out = 0;
return true;
error:
free(queue);
return false;
}
inline bool isCircQueueFull(CIRC_QUEUE *queue){
assert(queue != NULL);
return ((queue)->nelts == (queue)->bounds);
}
inline bool isCircQueueEmpty(CIRC_QUEUE *queue){
assert(queue != NULL);
return ((queue)->nelts == 0);
}
/**
* Push new data onto the queue.
*/
bool CircQueuePush(CIRC_QUEUE *queue, void *data)
{
assert(queue != NULL);
if (isCircQueueFull(queue)) {
return false;
}
queue->data[queue->in] = data;
queue->in++;
if (queue->in >= queue->bounds) {
queue->in -= queue->bounds;
}
queue->nelts++;
return true;
}
/**
* Return current number of element in queue.
*/
inline uint32_t CircQueueSize(CIRC_QUEUE *queue) {
return queue->nelts;
}
/**
* Retrieves the next item from the queue.
*/
bool CircQueuePop(CIRC_QUEUE *queue, void **data)
{
assert(queue != NULL);
if (isCircQueueEmpty(queue)) {
return false;
}
*data = queue->data[queue->out];
queue->nelts--;
queue->out++;
if (queue->out >= queue->bounds) {
queue->out -= queue->bounds;
}
return true;
}
+103
View File
@@ -0,0 +1,103 @@
/*****************************************************************************/
/**
* Description: A simple circular FIFO bounded queue
*
* Author: Fan Hao
* Date: 2023-02-23 10:29
* LastEditors: Fan Hao
* LastEditTime: 2023-02-23 12:53
* Revisions: Rev 0.0
* History:
* [2023-02-23]: Initial Version.
*
* Copyright(c) 2023 Beijing Institute of Technology.
* Lab of Communication and Networking
* NOTE: Forked from https://github.com/chrismerck/rpa_queue.git
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#ifndef CIRC_QUEUE_H
#define CIRC_QUEUE_H
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
/**
* opaque structure
*/
typedef struct CIRC_QUEUE_S CIRC_QUEUE;
/**
* create a FIFO queue
* @param queue The new queue
* @param queue_capacity maximum size of the queue
* @param a pool to allocate queue from
*/
bool CircQueueCreate(CIRC_QUEUE **queue, uint32_t queue_capacity);
/** free queue memory -- call after destroy
* @note we do not free in destroy() to follow pthreads convention
*/
void CircQueueFree(CIRC_QUEUE * queue);
/**
* Detects when the CIRC_QUEUE is full. This utility function is expected
* to be called from within critical sections, and is not threadsafe.
*/
bool isCircQueueFull(CIRC_QUEUE *queue);
/**
* Detects when the CIRC_QUEUE is empty. This utility function is expected
* to be called from within critical sections, and is not threadsafe.
*/
bool isCircQueueEmpty(CIRC_QUEUE *queue);
/**
* push/add an object to the queue, blocking if the queue is already full
*
* @param queue the queue
* @param data the data
* @returns RPA_EINTR the blocking was interrupted (try again)
* @returns RPA_EOF the queue has been terminated
* @returns RPA_SUCCESS on a successful push
*/
bool CircQueuePush(CIRC_QUEUE *queue, void *data);
/**
* pop/get an object from the queue, blocking if the queue is already empty
*
* @param queue the queue
* @param data the data
* @returns RPA_EINTR the blocking was interrupted (try again)
* @returns RPA_EOF if the queue has been terminated
* @returns RPA_SUCCESS on a successful pop
*/
bool CircQueuePop(CIRC_QUEUE *queue, void **data);
/**
* returns the size of the queue.
*
* @warning this is not threadsafe, and is intended for reporting/monitoring
* of the queue.
* @param queue the queue
* @returns the size of the queue
*/
uint32_t CircQueueSize(CIRC_QUEUE *queue);
#endif /* CIRC_QUEUE_H */
+1
View File
@@ -0,0 +1 @@
../../datalink814_ge/src/common.c
+1
View File
@@ -0,0 +1 @@
../../datalink814_ge/src/common.h
+151
View File
@@ -0,0 +1,151 @@
/*****************************************************************************/
/**
* Description: Global configurations.
*
* Date: 2021-04-28 13:19
* Last Edit Time: 2022-05-23 20:32
*
* Revisions: Rev 0.0
* History:
* [2021-04-28]: Initial edition.
*
* Copyright(c) 2021 Beijing Institute of Technology.
* Lab of Communication and Networking
*
******************************************************************************/
#ifndef CONFIG_H_
#define CONFIG_H_
#define XILINX_PLATFORM
#include "xparameters.h"
#include "../util/util.h"
/*********** Indoor Test Mode ************/
/************ Hardware Configs ************/
#define CPU_CLK_HZ XPAR_MICROBLAZE_CORE_CLOCK_FREQ_HZ
#define FCLK_CLK0_HZ XPAR_MICROBLAZE_CORE_CLOCK_FREQ_HZ
/********* Zynq Platform Configs **********/
// Check crc validation by computing crc value and comparing.
#define CRC_COMPARE
//Hardware Parameter
#define SPI_INTERFACE_SPI_ENGINE
#define HAVE_SPLIT_GAIN_TABLE 1 /* only set to 0 in case split_gain_table_mode_enable = 0*/
#define HAVE_TDD_SYNTH_TABLE 1 /* only set to 0 in case split_gain_table_mode_enable = 0*/
#define AD9361_DEVICE 1 /* set it 1 if AD9361 device is used, 0 otherwise */
#define AD9364_DEVICE 0 /* set it 1 if AD9364 device is used, 0 otherwise */
#define AD9363A_DEVICE 0 /* set it 1 if AD9363A device is used, 0 otherwise */
#define HAVE_VERBOSE_MESSAGES /* Recommended during development prints errors and warnings */
//#define HAVE_DEBUG_MESSAGES /* For Debug purposes only */
#define GPIO_DEVICE_ID XPAR_AXI_GPIO_DEVICE_ID
#define GPIO_OFFSET 54
#define GPIO_INPUT 0
#define GPIO_OUTPUT 1
#define GPIO_DISABLE 0
#define GPIO_ENABLE 1
#define AD9516_POWEDOWN_B 0
#define AD9516_RESET_B 1
#define AD9516_SYNC_B 2
#define AD9361_1_TXNRX 3
#define AD9361_1_ENABLE 4
#define AD9361_1_EN_AGC 5
#define AD9361_1_RESET_B 6
#define AD9361_1_CTRL_IN_0 7
#define AD9361_1_CTRL_IN_1 8
#define AD9361_1_CTRL_IN_2 9
#define AD9361_1_CTRL_IN_3 10
#define AD9361_2_TXNRX 11
#define AD9361_2_ENABLE 12
#define AD9361_2_EN_AGC 13
#define AD9361_2_RESET_B 14
#define AD9361_2_CTRL_IN_0 15
#define AD9361_2_CTRL_IN_1 16
#define AD9361_2_CTRL_IN_2 17
#define AD9361_2_CTRL_IN_3 18
#define AD9361_SYNC 19
#define AD9361_RX_FIFO_RST 20
#define AD9361_1_CTRL_OUT_0 0
#define AD9361_1_CTRL_OUT_1 1
#define AD9361_1_CTRL_OUT_2 2
#define AD9361_1_CTRL_OUT_3 3
#define AD9361_1_CTRL_OUT_4 4
#define AD9361_1_CTRL_OUT_5 5
#define AD9361_1_CTRL_OUT_6 6
#define AD9361_1_CTRL_OUT_7 7
#define AD9361_2_CTRL_OUT_0 8
#define AD9361_2_CTRL_OUT_1 9
#define AD9361_2_CTRL_OUT_2 10
#define AD9361_2_CTRL_OUT_3 11
#define AD9361_2_CTRL_OUT_4 12
#define AD9361_2_CTRL_OUT_5 13
#define AD9361_2_CTRL_OUT_6 14
#define AD9361_2_CTRL_OUT_7 15
#define AD9516_REFMON 16
#define AD9516_LOCKDETECT 17
#define AD9516_STARUS 18
#define GPIO_BANK_OUT 1
#define GPIO_BANK_IN 2
#define SPI_DEVICE_ID 0
#define SPI_ENGINE_REF_CLK FCLK_CLK0_HZ
#define SPI_ENGINE_MAX_SPEED 5000000
#define SPI_ENGINE_BASEADDR XPAR_AXI_SPI_ENGINE_AXI_SPI_ENGINE_BASEADDR
#define SPI_ENGINE_DATA_WIDTH 8
#define SPI_ENGINE_CS_DELAY 3
#define SPI_CS_AD9516 0x00
#define SPI_CS_AD9361_1 0x01
#define SPI_CS_AD9361_2 0x02
// Interrupt Configs
#define INTC_DEVICE_ID XPAR_AXI_INTC_DEVICE_ID
#define PHY_INTR_ID XPAR_AXI_INTC_SYSTEM_PHY_IRQ_INTR
#define C2C_TX_INTR_ID XPAR_AXI_INTC_AXI_DMA_C2C_MM2S_INTROUT_INTR
#define C2C_RX_INTR_ID XPAR_AXI_INTC_AXI_DMA_C2C_S2MM_INTROUT_INTR
#define SCUTIMER_INTR_ID XPAR_AXI_INTC_AXI_TIMER_0_INTERRUPT_INTR
// C2C configure
#define C2C_AXI_DMA_DEVICE_ID XPAR_AXI_DMA_C2C_DEVICE_ID
#define C2C_RXBUFF_ADDR_BASE XPAR_C2C_RX_AXI_BRAM_CTRL_S_AXI_BASEADDR
#define C2C_TXBUFF_ADDR_BASE XPAR_C2C_TX_AXI_BRAM_CTRL_S_AXI_BASEADDR
#define C2C_BUFF_NUM 4
#define C2C_BUFF_SIZE 1024
// Physical configure
#define PHY_CTRL_BASEADDR XPAR_PHYC_BASEADDR
#define PHY_RX_BRAM_BUFF_ID XPAR_RX_FRAME_BRAM_CTRL_DEVICE_ID
#define PHY_TX_BRAM_BUFF_ID XPAR_TX_FRAME_BRAM_CTRL_DEVICE_ID
#define PHY_ANT_CONFIG_BRAM_ID XPAR_ANT_CONFIG_BRAM_CTRL_DEVICE_ID
#define PHY_RX_BUFF_BASEADDR XPAR_RX_FRAME_BRAM_CTRL_S_AXI_BASEADDR
#define PHY_TX_BUFF_BASEADDR XPAR_TX_FRAME_BRAM_CTRL_S_AXI_BASEADDR
//Remote Test
#define GLINK_REMOTE_TEST_ENABLE
#define TIMER_COUNT_MAX 150000000
#define SCUTIMER_DEVICE_ID XPAR_AXI_TIMER_0_DEVICE_ID
//ANT ID
#define ANT_DEVICE_ID 0x0000
#if defined(GLINK_REMOTE_TEST_ENABLE) && !defined(TIMER_COUNT_MAX)
#define TIMER_COUNT_MAX 150000000
#warning Must set a remote test interval after enable remote test.
#warning Use default interval 150000000...
#endif
//XADC ID
#define SYSMON_DEVICE_ID XPAR_XADC_WIZ_0_DEVICE_ID
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,89 @@
#include "dev_profile.h"
#include "../config/app_config.h"
#include "../adi_noos/drivers/frequency/ad9516/ad9516.h"
static spi_init_param ad9516_spi_init = {
.device_id = SPI_DEVICE_ID,
.max_speed_hz = SPI_ENGINE_MAX_SPEED,
.mode = SPI_MODE_4,
.chip_select = SPI_CS_AD9516,
.platform_ops = SPI_OPS,
.extra = SPI_PARAM
};
struct ad9516_init_param ad9516_default_init_param = {
/* SPI */
.spi_init = &ad9516_spi_init
};
const uint32_t ad9516_default_config_len = 66;
const struct ad9516_config ad9516_default_config[] = {
{0x0000,0x18}, // 16-bit instruction, MSB first, 3-wire SPI
{0x0004,0x00}, // reads back buffer registers
{0x0010,0x7C},
{0x0011,0x04}, // R divider LSBs, R = 4
{0x0012,0x00}, // R divider MSBs, R = 4
{0x0013,0x08}, // A counter, A = 8
{0x0014,0x09}, // B counter LSBs, B = 9
{0x0015,0x00}, // B counter MSBs, B = 9
{0x0016,0x04}, // Divide-by-8 (8/9 mode)
{0x0017,0x10}, // STATUS pin output: Prescaler output
{0x0018,0x06},
{0x0019,0x80}, // R, A, B counters synchronous reset on SYNCB
{0x001A,0x00}, // LD pin output: Digital lock detect (high = lock, low = unlock)
{0x001B,0xA1}, // enables VCO, REF1 frequency monitor; REFMON pin output: REF1 clock
{0x001C,0x07}, // selects REF1; REF1, REF2 power on; differential reference mode
{0x001D,0x00},
{0x001E,0x00},
{0x00A0,0x01},
{0x00A1,0x00},
{0x00A2,0x00},
{0x00A3,0x01},
{0x00A4,0x00},
{0x00A5,0x00},
{0x00A6,0x01},
{0x00A7,0x00},
{0x00A8,0x00},
{0x00A9,0x01},
{0x00AA,0x00},
{0x00AB,0x00},
{0x00F0,0x08},
{0x00F1,0x08},
{0x00F2,0x08},
{0x00F3,0x08},
{0x00F4,0x08},
{0x00F5,0x08},
{0x0140,0x59},
{0x0141,0x5A},
{0x0142,0x5A},
{0x0143,0x42},
{0x0190,0x33},
{0x0191,0x40},
{0x0192,0x00},
{0x0193,0x33},
{0x0194,0x40},
{0x0195,0x00},
{0x0196,0x44},
{0x0197,0x40},
{0x0198,0x00},
{0x0199,0x99}, // divider 3.1, Low Cycles = 10, High Cycles = 10
{0x019A,0x00},
{0x019B,0x00}, // divider 3.1, Low Cycles = 1, High Cycles = 1
{0x019C,0x00},
{0x019D,0x00},
// {0x019E,0xFF},
{0x019E,0x11},
{0x019F,0x00},
{0x01A0,0x11},
{0x01A1,0x20},
{0x01A2,0x00},
{0x01A3,0x00},
{0x01E0,0x00},
{0x01E1,0x02},
{0x0230,0x00},
{0x0231,0x00},
{0x0232,0x01}, // Update all registers
{0x0018,0x07}, // initiate the VCO calibration
{0x0232,0x01} // Update all registers
};
@@ -0,0 +1,42 @@
#ifndef DEV_PROFILE_H_
#define DEV_PROFILE_H_
#include <stdint.h>
#include "../config/app_config.h"
#include "../adi_noos/include/spi.h"
#include "../adi_noos/include/gpio.h"
#include "../adi_noos/include/delay.h"
#include "../adi_noos/include/irq.h"
#include "../adi_noos/include/error.h"
#include "../adi_noos/drivers/rf-transceiver/ad9361_reg/ad9361_reg.h"
#include "../adi_noos/drivers/frequency/ad9516/ad9516.h"
// Platform includes
#include "../adi_noos/drivers/platform/spi_extra.h"
#include "../adi_noos/drivers/platform/gpio_extra.h"
#include "../adi_noos/drivers/platform/irq_extra.h"
// AXI-Cores includes
#include "../adi_noos/drivers/axi_core/spi_engine/spi_engine.h"
// Declare in mian.c
extern struct spi_engine_init_param spi_engine_param;
extern struct xil_gpio_init_param xil_gpio_param;
#define GPIO_PARAM &xil_gpio_param
#define SPI_PARAM &spi_engine_param
#define GPIO_OPS &xil_gpio_ops
#define SPI_OPS &spi_eng_platform_ops
extern struct ad9516_init_param ad9516_default_init_param;
extern const struct ad9516_config ad9516_default_config[];
extern const uint32_t ad9516_default_config_len;
extern struct ad9361_reg_init_param ad9361_1_reg_default_init_param;
extern struct ad9361_reg_init_param ad9361_2_reg_default_init_param;
uint32_t ad9361_reg_config(struct ad9361_reg_dev *dev);
uint32_t ad9361_1_reg_config(struct ad9361_reg_dev *dev);
uint32_t ad9361_2_reg_config(struct ad9361_reg_dev *dev);
#endif /* SRC_DEV_PROFILE_H_ */
+1
View File
@@ -0,0 +1 @@
../../datalink814_ge/src/error.h
+850
View File
@@ -0,0 +1,850 @@
/*****************************************************************************/
/**
* Description: Inter-Communication protocol implementation.
*
* Date: 2022-06-18 16:37
* LastEditTime: 2023-04-24 17:38
* Revisions: Rev 0.1
* History:
* [2022-06-18]: Initial version.
* [2023-04-24]: Bug fix:
* - Read frame type from PL status register.
*
* Copyright(c) 2022 Beijing Institute of Technology.
* Lab of Communication and Networking
*
******************************************************************************/
/***************************** Include Files *********************************/
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include "inter_comm.h"
#include "../error.h"
#include "../util/util.h"
#include "../phy_ctrl/phy_ctrl.h"
/************************** Constant Definitions *****************************/
/***************** Macros (Inline Functions) Definitions *********************/
/************************** Function Prototypes ******************************/
static uint64_t GetTimeWord(uint8_t* buffPtr);
static uint32_t GetMsgLen(uint8_t msgCode);
static int32_t EvalPhyConfig(INTER_COMM_INST* instPtr, uint8_t* msgPtr);
/**************************** Type Definitions *******************************/
/************************** Variable Definitions *****************************/
/*****************************************************************************/
/**
* @brief Get a 64 bit time word from specified buffer pointer.
*
* @param buffPtr
*
* @return 64bit unsigned timer word
*
******************************************************************************/
static uint64_t GetTimeWord(uint8_t* buffPtr){
ASSERT(buffPtr != NULL);
uint64_t timeWord = 0;
timeWord |= (uint64_t)buffPtr[0];
timeWord |= ((uint64_t)buffPtr[1])<<8;
timeWord |= ((uint64_t)buffPtr[2])<<16;
timeWord |= ((uint64_t)buffPtr[3])<<24;
timeWord |= ((uint64_t)buffPtr[4])<<32;
timeWord |= ((uint64_t)buffPtr[5])<<40;
timeWord |= ((uint64_t)buffPtr[6])<<48;
timeWord |= ((uint64_t)buffPtr[7])<<56;
return timeWord;
}
/*****************************************************************************/
/**
* @brief Invoke a glink message reception process, check data crc, test the
* validation of received data.
*
* @param instPtr a pointer to inter communication instance
* @param frameType
*
* @return SUCCESS
* ECRC crc check failed.
*
******************************************************************************/
static uint32_t GetMsgLen(uint8_t msgCode){
switch(msgCode){
case INTER_MSG_ST_REQ_CODE:
return INTER_MSG_ST_REQ_LEN;
case INTER_MSG_ST_RSP_CODE:
return INTER_MSG_ST_RSP_LEN;
case INTER_MSG_WAKE_REQ_CODE:
return INTER_MSG_WAKE_REQ_LEN;
case INTER_MSG_WAKE_RSP_CODE:
return INTER_MSG_WAKE_RSP_LEN;
case INTER_MSG_MODESW_CODE:
return INTER_MSG_MODESW_LEN;
case INTER_MSG_CTRL_CODE:
return INTER_MSG_CTRL_LEN;
case INTER_MSG_DSEGWR_CODE:
return INTER_MSG_DSEGWR_LEN;
case INTER_MSG_DSEGRD_CODE:
return INTER_MSG_DSEGRD_LEN;
case INTER_MSG_RT_CODE:
return INTER_MSG_RT_LEN;
default:
return INTER_MSG_LEN_NONE;
}
}
/*****************************************************************************/
/**
* @brief Evaluate glink command and get ready to receive/send the required
* frame.
*
* @param instPtr a pointer to inter communication instance
* @param msgPtr a pointer to message buffer
*
* @return SUCCESS
* EPARAM illegal command setting detected.
* EIGNORE unsupported command detected.
*
******************************************************************************/
static int32_t EvalPhyConfig(INTER_COMM_INST* instPtr, uint8_t* msgPtr){
ASSERT(instPtr != NULL);
ASSERT(msgPtr != NULL);
int32_t Status;
PHY_INST* phyRef = instPtr->phyInstPtr;
L1_FRAME_TYPE frameType = L1_NONE_FRAME;
PHY_TOR_TYPE torState = PHY_TOR_SUSPEND;
PHY_ANT_BEAM_WIDTH beamWidth = ANT_BEAM_NONE;
uint32_t beamNo = 0;
uint16_t msg_Recv = 0;
msg_Recv |= (uint16_t)msgPtr[TYPE_CODE_OFFSET];
msg_Recv |= ((uint16_t)msgPtr[TYPE_CODE_OFFSET+1])<<8;
if(msg_Recv != INTER_MSG_CTRL_CODE){
return EIGNORE;
}
if(msgPtr[INTER_MSG_CTRL_TOR_OFFSET] == CTRL_TOR_TX){
torState = PHY_TOR_TX;
}
else if(msgPtr[INTER_MSG_CTRL_TOR_OFFSET] == CTRL_TOR_RX){
torState = PHY_TOR_RX;
}
else{
DBG_ERROR("[PHY Control] Tx/Rx state cannot be recognized...\n\r");
return EIGNORE;
}
instPtr->lastCtrlTimeTag = GetTimeWord(msgPtr+CTRL_TIME_OFFSET);
if(torState == PHY_TOR_TX){
if(instPtr->lastCtrlTimeTag != instPtr->lastDataTimeTag){
return EPARAM;
}
}
switch(msgPtr[CTRL_FRAME_TYPE_OFFSET]){
case CTRL_FRAME_10K10MS:
frameType = L1_10KBPS_10MS_FRAME;
break;
case CTRL_FRAME_10K20MS:
frameType = L1_10KBPS_20MS_FRAME;
break;
case CTRL_FRAME_200K5MS:
frameType = L1_200KBPS_5MS_FRAME;
break;
case CTRL_FRAME_1M25MS:
frameType = L1_1M2BPS_5MS_FRAME;
break;
case CTRL_FRAME_2K20MS:
frameType = L1_2KBPS_20MS_FRAME;
break;
case CTRL_FRAME_2K100MS:
frameType = L1_2KBPS_100MS_FRAME;
break;
case CTRL_FRAME_40K10MS:
frameType = L1_40KBPS_10MS_FRAME;
break;
case CTRL_FRAME_40K20MS:
frameType = L1_40KBPS_20MS_FRAME;
break;
default:
DBG_ERROR("[PHY Control] Frame Type cannot be recognized...\n\r");
return EIGNORE;
break;
}
// FIXME: no extra antenna in current stage
////////////////////////////////////
// Antenna configurations
////////////////////////////////////
// FIXME: no switch control in current stage
////////////////////////////////////
// Switch configurations
////////////////////////////////////
uint16_t hop_msg_Recv = 0;
hop_msg_Recv |= (uint16_t)msgPtr[INTER_MSG_CTRL_HOP_MODE_OFFSET];
hop_msg_Recv |= ((uint16_t)msgPtr[INTER_MSG_CTRL_HOP_MODE_OFFSET+1])<<8;
if(hop_msg_Recv == CTRL_HOP_PRESET){
phyRef->isPresetHop = true;
}
else if(hop_msg_Recv == CTRL_HOP_CONFIG){
phyRef->isPresetHop = false;
}
else{
DBG_ERROR("[PHY Control] Hopping Pattern Configure cannot be recognized...\n\r");
DBG_WARNING("[PHY Control] Using default preset hopping pattern instead...\n\r");
return EIGNORE;
}
if(phyRef->isPresetHop == false){
Status = Phy_SetHopPattern(msgPtr+INTER_MSG_CTRL_HOP_PATTERN_OFFSET,
Phy_GetHopLength(frameType));
if(Status != SUCCESS){
return Status;
}
}
if(msgPtr[INTER_MSG_CTRL_BEAM_MODE_OFFSET] == BEAM_MODE_WIDE){
beamWidth = ANT_BEAM_120;
}
else if(msgPtr[INTER_MSG_CTRL_BEAM_MODE_OFFSET] == BEAM_MODE_SUBNRW){
beamWidth = ANT_BEAM_25;
}
else if(msgPtr[INTER_MSG_CTRL_BEAM_MODE_OFFSET] == BEAM_MODE_NRW){
beamWidth = ANT_BEAM_8;
}
else{
DBG_ERROR("[PHY Control] Beam Width Configure cannot be recognized...\n\r");
DBG_WARNING("[PHY Control] Using default WILD beam (120 deg) instead...\n\r");
return EIGNORE;
}
Status = Phy_SetBeamWidth(phyRef, beamWidth);
if(Status != SUCCESS){
return Status;
}
beamNo = (uint32_t)msgPtr[INTER_MSG_CTRL_BEAM_NO_OFFSET];
if((beamNo<NUM_ANT_SUBNRRW_PATTERN && beamWidth == ANT_BEAM_25)
||(beamNo<NUM_ANT_NRRW_PATTERN && beamWidth == ANT_BEAM_8)
|| (beamNo == 0 && beamWidth == ANT_BEAM_120)){
Phy_SetBeamNo(phyRef, beamNo);
}
else{
if(beamNo != 0x000000FF){
DBG_ERROR("[PHY Control] Beam Number Configure cannot be recognized...\n\r");
DBG_WARNING("[PHY Control] Using Beam Angle configure instead...\n\r");
return EIGNORE;
}
// the angle config is a 16 bit fixed point data
// 1 bit sign 2 bit integer 13 bit fraction
uint16_t offAxAgnel = 0;
uint16_t rndAxAgnel = 0;
offAxAgnel |= (uint16_t)msgPtr[INTER_MSG_CTRL_OFFAX_OFFSET];
offAxAgnel |= ((uint16_t)msgPtr[INTER_MSG_CTRL_OFFAX_OFFSET+1])<<8;
rndAxAgnel |= (uint16_t)msgPtr[INTER_MSG_CTRL_RNDAX_OFFSET];
rndAxAgnel |= ((uint16_t)msgPtr[INTER_MSG_CTRL_RNDAX_OFFSET+1])<<8;
Status = Phy_SetBeamAngle(phyRef, offAxAgnel/10, rndAxAgnel/10);
if(Status != SUCCESS){
return Status;
}
}
TIME_WORD tmWord = {0};
tmWord.int_part = (uint32_t)(instPtr->lastCtrlTimeTag >> 32);
tmWord.frac_part = (uint32_t)(instPtr->lastCtrlTimeTag);
Status = Phy_SetTimeWord(phyRef, &tmWord, TIME_WORD_POLL);
Status = Phy_SetMode(phyRef, PHY_MODE_PULL);
Status = Phy_SetupNextSlot(phyRef, torState, frameType, instPtr->phySendBuff);
if(Status != SUCCESS){
return Status;
}
instPtr->lastCtrlTimeTag = 0;
instPtr->lastDataTimeTag = 0;
return Status;
}
/*****************************************************************************/
/**
* @brief Initialize the inter communication instance, allocate space for
* message buffers.
*
* @param instPtr a second rank pointer to inter communication instance
* @param configPtr a pointer to inter communication instance configuration
* set.
*
* @return SUCCESS
* EALLOC memory allocate failed.
*
******************************************************************************/
int32_t InterComm_Init(INTER_COMM_INST** instPtr, INTER_COMM_CONFIG* configPtr){
int32_t Status;
if (configPtr == NULL) {
return EPARAM;
}
*instPtr = (INTER_COMM_INST*) malloc(sizeof(INTER_COMM_INST));
if ((*instPtr) == NULL) {
return EALLOC;
}
memset(*instPtr, 0x00, sizeof(INTER_COMM_INST));
(*instPtr)->rxRemain = 0;
(*instPtr)->txRemain = 0;
(*instPtr)->lastCtrlTimeTag = 0;
(*instPtr)->lastDataTimeTag = 0;
(*instPtr)->lastPhyTimeTag = 0;
(*instPtr)->phyInstPtr = configPtr->phyInstPtr;
(*instPtr)->data_send = configPtr->data_send;
(*instPtr)->data_recv = configPtr->data_recv;
(*instPtr)->isSleep = false;
// Initial message buffer
(*instPtr)->recvBuff = calloc(INTER_MSG_LEN/sizeof(uint32_t), sizeof(uint32_t));
if ((*instPtr)->recvBuff == NULL) {
Status = EALLOC;
goto init_failed;
}
(*instPtr)->sendBuff = calloc(INTER_MSG_LEN/sizeof(uint32_t), sizeof(uint32_t));
if ((*instPtr)->sendBuff == NULL) {
Status = EALLOC;
goto init_failed;
}
// Initial physical buffer
(*instPtr)->phyRecvBuff = calloc(TXRXDATA_MAX_LEN/sizeof(uint32_t), sizeof(uint32_t));
if ((*instPtr)->phyRecvBuff == NULL) {
Status = EALLOC;
goto init_failed;
}
(*instPtr)->phySendBuff = calloc(TXRXDATA_MAX_LEN/sizeof(uint32_t), sizeof(uint32_t));
if ((*instPtr)->phySendBuff == NULL) {
Status = EALLOC;
goto init_failed;
}
return SUCCESS;
init_failed:
InterComm_Destroy(*instPtr);
return Status;
}
/*****************************************************************************/
/**
* @brief Destroy the inter communication instance, free all allocated memory.
*
* @param instPtr a second rank pointer to inter communication instance
*
* @return NONE
*
******************************************************************************/
void InterComm_Destroy(INTER_COMM_INST* instPtr) {
if(instPtr == NULL) {
return;
}
free(instPtr->sendBuff);
free(instPtr->recvBuff);
free(instPtr->phySendBuff);
free(instPtr->phyRecvBuff);
free(instPtr);
}
/*****************************************************************************/
/**
* @brief Invoke a glink message reception process, check data crc, test the
* validation of received data.
*
* @param instPtr a pointer to inter communication instance
* @param frameType
*
* @return SUCCESS
* ECRC crc check failed.
* FAILURE command code cannot be recognized.
******************************************************************************/
int32_t InterComm_RecvMsg(INTER_COMM_INST* instPtr){
bool ret;
int32_t Status;
uint32_t msgLen = 0;
uint8_t* msgRecvPtr = (uint8_t*)instPtr->recvBuff;
Status = instPtr->data_recv(msgRecvPtr, INTER_MSG_LEN);
msgLen = GetMsgLen(msgRecvPtr[TYPE_CODE_OFFSET]);
if(Status == SUCCESS){
if(msgLen == INTER_MSG_LEN_NONE){
return FAILURE;
}
ret = CrcCheck(msgRecvPtr, msgLen);
if(ret == true){
return SUCCESS;
}
else{
return ECRC;
}
}
return Status;
}
/*****************************************************************************/
/**
* @brief Invoke a data sending process, append crc check ro the send data.
*
* @param instPtr a pointer to inter communication instance
* @param dataLen length of the send data.
*
* @return SUCCESS
* FAILURE data too long, exceeded glink buffer length.
*
******************************************************************************/
int32_t InterComm_SendMsg(INTER_COMM_INST* instPtr, int32_t dataLen, uint16_t subAddr){
int32_t Status;
if(dataLen > INTER_MSG_LEN){
return FAILURE;
}
Status = AppendCrc((uint8_t*)instPtr->sendBuff, dataLen);
if(Status == SUCCESS){
Status = instPtr->data_send((uint16_t*)instPtr->sendBuff, dataLen, subAddr);
}
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief A full function of inter communication message handler, evaluate
* all the protocol command and response properly.
*
* @param instPtr a pointer to inter communication instance
*
* @return SUCCESS
* EDINVAL device in sleep mode, not functional.
* EIGNORE received a command not supported by current protocol.
* IGNORE_COMMAND_ERROR received a dummy command ignored by current protocol.
*
******************************************************************************/
int32_t InterComm_MsgHandler(INTER_COMM_INST* instPtr){
ASSERT(instPtr != NULL);
int32_t Status = SUCCESS;
uint8_t* msgRecvPtr = (uint8_t*) instPtr->recvBuff;
uint8_t* msgSendPtr = (uint8_t*) instPtr->sendBuff;
uint16_t msg_Recv = 0;
msg_Recv |= (uint16_t)msgRecvPtr[TYPE_CODE_OFFSET];
msg_Recv |= ((uint16_t)msgRecvPtr[TYPE_CODE_OFFSET+1])<<8;
if(instPtr->isSleep == true){
if(msg_Recv != INTER_MSG_WAKE_REQ_CODE){
DBG_WARNING("Device is in sleep mode, ignore command...");
return EDINVAL;
}
}
switch(msg_Recv){
case INTER_MSG_ST_REQ_CODE:{
uint16_t cmdCode = 0;
memset(msgSendPtr, 0x00, INTER_MSG_ST_RSP_LEN);
cmdCode |= (uint16_t)msgRecvPtr[ST_CMD_OFFSET];
cmdCode |= ((uint16_t)msgRecvPtr[ST_CMD_OFFSET+1])<<8;
if(cmdCode == ST_CMD){
////////////////////////
// Run a self test...
/////////////////////////
msgSendPtr[TYPE_CODE_OFFSET] = (uint8_t)INTER_MSG_ST_RSP_CODE;
msgSendPtr[TYPE_CODE_OFFSET+1] = (uint8_t)(INTER_MSG_ST_RSP_CODE>>8);
msgSendPtr[ST_RSP_STATE_OFFSET] = (uint8_t)ST_RSP_STATE_OK;
msgSendPtr[ST_RSP_STATE_OFFSET+1] = (uint8_t)(ST_RSP_STATE_OK>>8);
Status = InterComm_SendMsg(instPtr, INTER_MSG_ST_RSP_LEN, INTER_MSG_OTHER_ADDR);
}
else{
return EIGNORE;
}
break;
}
case INTER_MSG_WAKE_REQ_CODE:{
uint16_t cmdCode = 0;
memset(msgSendPtr, 0x00, INTER_MSG_WAKE_RSP_LEN);
cmdCode |= (uint16_t)msgRecvPtr[WAKE_CMD_OFFSET];
cmdCode |= ((uint16_t)msgRecvPtr[WAKE_CMD_OFFSET+1])<<8;
if(cmdCode == WAKE_CMD_UP_LPW){
if(instPtr->isSleep == true){
DBG_WARNING("Device is already in sleep mode...");
msgSendPtr[TYPE_CODE_OFFSET] = (uint8_t)INTER_MSG_WAKE_RSP_CODE;
msgSendPtr[TYPE_CODE_OFFSET+1] = (uint8_t)(INTER_MSG_WAKE_RSP_CODE>>8);
msgSendPtr[WAKE_CMD_OFFSET] = (uint8_t)WAKE_CMD_LPW_LPW;
msgSendPtr[WAKE_CMD_OFFSET+1] = (uint8_t)(WAKE_CMD_LPW_LPW>>8);
}
else{
////////////////////////
// Run a lowpower sleep routine...
/////////////////////////
instPtr->isSleep = true;
msgSendPtr[TYPE_CODE_OFFSET] = (uint8_t)INTER_MSG_WAKE_RSP_CODE;
msgSendPtr[TYPE_CODE_OFFSET+1] = (uint8_t)(INTER_MSG_WAKE_RSP_CODE>>8);
msgSendPtr[WAKE_CMD_OFFSET] = (uint8_t)WAKE_CMD_UP_LPW;
msgSendPtr[WAKE_CMD_OFFSET+1] = (uint8_t)(WAKE_CMD_UP_LPW>>8);
}
}
else if(cmdCode == WAKE_CMD_LPW_UP){
if(instPtr->isSleep == false){
DBG_WARNING("Device is already in wake mode...");
msgSendPtr[TYPE_CODE_OFFSET] = (uint8_t)INTER_MSG_WAKE_RSP_CODE;
msgSendPtr[TYPE_CODE_OFFSET+1] = (uint8_t)(INTER_MSG_WAKE_RSP_CODE>>8);
msgSendPtr[WAKE_CMD_OFFSET] = (uint8_t)WAKE_CMD_UP_UP;
msgSendPtr[WAKE_CMD_OFFSET+1] = (uint8_t)(WAKE_CMD_UP_UP>>8);
}
else{
////////////////////////
// Run a wake up routine...
/////////////////////////
instPtr->isSleep = false;
msgSendPtr[TYPE_CODE_OFFSET] = (uint8_t)INTER_MSG_WAKE_RSP_CODE;
msgSendPtr[TYPE_CODE_OFFSET+1] = (uint8_t)(INTER_MSG_WAKE_RSP_CODE>>8);
msgSendPtr[WAKE_CMD_OFFSET] = (uint8_t)WAKE_CMD_LPW_UP;
msgSendPtr[WAKE_CMD_OFFSET+1] = (uint8_t)(WAKE_CMD_LPW_UP>>8);
}
}
else{
return EIGNORE;
}
Status = InterComm_SendMsg(instPtr, INTER_MSG_WAKE_RSP_LEN,INTER_MSG_OTHER_ADDR);
break;
}
case INTER_MSG_MODESW_CODE:{
if(msgRecvPtr[MODESW_MODE_OFFSET] == MODESW_MODE_NORMAL){
Phy_SetMode(instPtr->phyInstPtr, PHY_MODE_PULL);
}
else if(msgRecvPtr[MODESW_MODE_OFFSET] == MODESW_MODE_NETSET){
uint64_t timeTemp;
TIME_WORD tmWord;
timeTemp = GetTimeWord(msgRecvPtr + MODESW_START_TIME_OFFSET);
tmWord.int_part = (uint32_t)(timeTemp>>32);;
tmWord.frac_part = (uint32_t)(timeTemp);
Status = Phy_SetTimeWord(instPtr->phyInstPtr, &tmWord, TIME_WORD_POLL);
if(Status != SUCCESS){
return EPARAM;
}
timeTemp = GetTimeWord(msgRecvPtr + MODESW_TIMEOUT_OFFSET);
if(timeTemp == 0){
tmWord.frac_part = 0;
tmWord.int_part = 0;
Status = Phy_SetTimeWord(instPtr->phyInstPtr, &tmWord, TIME_WORD_LISTEN_TIMEOUT);
if(Status != SUCCESS){
return EPARAM;
}
}
else{
tmWord.frac_part += (uint32_t)(timeTemp);
tmWord.int_part += (uint32_t)(timeTemp>>32);
tmWord.int_part = (tmWord.frac_part >= TMWORD_FRAC_MAX) ? tmWord.int_part + 1:tmWord.int_part;
tmWord.frac_part %= TMWORD_FRAC_MAX;
Status = Phy_SetTimeWord(instPtr->phyInstPtr, &tmWord, TIME_WORD_LISTEN_TIMEOUT);
if(Status != SUCCESS){
return EPARAM;
}
}
instPtr->phyInstPtr->isPresetHop = true ;
Status = Phy_SetMode(instPtr->phyInstPtr, PHY_MODE_LISTEN);
Status = Phy_SetupNextSlot(instPtr->phyInstPtr, PHY_TOR_RX, L1_10KBPS_20MS_FRAME, NULL);
}
else{
return EPARAM;
}
break;
}
case INTER_MSG_CTRL_CODE:{
Status = EvalPhyConfig(instPtr, msgRecvPtr);
break;
}
case INTER_MSG_DSEGWR_CODE:{
uint16_t subPktLen;
uint8_t* phyTxBuff;
phyTxBuff= (uint8_t*)instPtr->phySendBuff;
subPktLen = (uint16_t)msgRecvPtr[DSEGWR_PDLEN_OFFSET];
subPktLen |= ((uint16_t)msgRecvPtr[DSEGWR_PDLEN_OFFSET+1])<<8;
if(msgRecvPtr[DSEGWR_TYPE_OFFSET] == DSEGWR_TYPE_PKN){
memcpy(phyTxBuff, msgRecvPtr+DSEGWR_PD_OFFSET, (size_t)subPktLen);
}
else if(msgRecvPtr[DSEGWR_TYPE_OFFSET] == DSEGWR_TYPE_PK1){
memcpy(phyTxBuff, msgRecvPtr+DSEGWR_PD_OFFSET, (size_t)subPktLen);
}
else if(msgRecvPtr[DSEGWR_TYPE_OFFSET] == DSEGWR_TYPE_PK2){
memcpy(phyTxBuff+DSEGWR_PD_LEN, msgRecvPtr+DSEGWR_PD_OFFSET, (size_t)subPktLen);
}
else if(msgRecvPtr[DSEGWR_TYPE_OFFSET] == DSEGWR_TYPE_PK3){
memcpy(phyTxBuff+DSEGWR_PD_LEN*2, msgRecvPtr+DSEGWR_PD_OFFSET, (size_t)subPktLen);
}
else{
return EPARAM;
}
// Store time tag last to prevent get a error command time tag
// e.g. if DSEGWR_TYPE not cannot be recognized, function will return
// in earlier stage, interComm instance won't get a time tag in a
// error command.
// FIXME: Check data integrity?
instPtr->lastDataTimeTag = GetTimeWord(msgRecvPtr+DSEGWR_TIME_OFFSET);
////////////////////////
// Invoke a time sync process ...
/////////////////////////
break;
}
default:
return FAILURE;
break;
}
return Status;
}
/*****************************************************************************/
/**
* @brief Invoke a data sending process, append crc check ro the send data.
*
* @param instPtr a pointer to inter communication instance
*
* @return SUCCESS
* FAILURE data too long, exceeded glink buffer length.
*
******************************************************************************/
int32_t InterComm_SendRemotCheck(INTER_COMM_INST* instPtr, XSysMon* SysMonInstPtr, C2C_EXTRA* c2cExtraBuffPtr){
ASSERT(instPtr != NULL);
ASSERT(SysMonInstPtr != NULL);
ASSERT(c2cExtraBuffPtr != NULL);
int32_t Status;
uint8_t* msgTxBuff = (uint8_t*) instPtr->sendBuff;
memset(msgTxBuff, 0x00, INTER_MSG_LEN);
// Set message code
msgTxBuff[TYPE_CODE_OFFSET] = (uint8_t)(INTER_MSG_RT_CODE);
msgTxBuff[TYPE_CODE_OFFSET+1] = (uint8_t)(INTER_MSG_RT_CODE>>8);
msgTxBuff[RT_PHY_OFFSET] = (uint8_t)(0x0003);
msgTxBuff[RT_PHY_OFFSET+1] = (uint8_t)(0x0003>>8);
uint8_t* TimeBuff = (uint8_t*)(&(instPtr->lastPhyTimeTag));
msgTxBuff[RT_TIME_OFFSET] = (uint8_t)(TimeBuff[0]);
msgTxBuff[RT_TIME_OFFSET+1] = (uint8_t)(TimeBuff[1]);
msgTxBuff[RT_TIME_OFFSET+2] = (uint8_t)(TimeBuff[2]);
msgTxBuff[RT_TIME_OFFSET+3] = (uint8_t)(TimeBuff[3]);
msgTxBuff[RT_TIME_OFFSET+4] = (uint8_t)(TimeBuff[4]);
msgTxBuff[RT_TIME_OFFSET+5] = (uint8_t)(TimeBuff[5]);
msgTxBuff[RT_TIME_OFFSET+6] = (uint8_t)(TimeBuff[6]);
msgTxBuff[RT_TIME_OFFSET+7] = (uint8_t)(TimeBuff[7]);
uint32_t VccAuxRawData;
uint16_t VccAuxData;
VccAuxRawData = XSysMon_GetAdcData(SysMonInstPtr,XSM_CH_VCCINT );
VccAuxData = (int16_t)(XSysMon_RawToVoltage(VccAuxRawData)*10);
msgTxBuff[RT_SP_VOLT_OFFSET] = (uint8_t)(VccAuxData);
msgTxBuff[RT_SP_VOLT_OFFSET+1] = (uint8_t)(VccAuxData>>8);
uint32_t TempRawData;
int16_t TempData;
TempRawData = XSysMon_GetAdcData(SysMonInstPtr, XSM_CH_TEMP);
TempData = (int16_t)(XSysMon_RawToTemperature(TempRawData)*10);
msgTxBuff[RT_SP_TEMP_OFFSET] = (uint8_t)(TempData);
msgTxBuff[RT_SP_TEMP_OFFSET+1] = (uint8_t)(TempData>>8);
msgTxBuff[RT_SP_CHIP_OFFSET] = (uint8_t)(0x0001);
msgTxBuff[RT_SP_CHIP_OFFSET+1] = (uint8_t)(0x0001>>8);
uint8_t* ExtraBuff = (uint8_t*)(c2cExtraBuffPtr->extra);
msgTxBuff[RT_ANT_VOLT_OFFSET] = (uint8_t)(ExtraBuff[0]);
msgTxBuff[RT_ANT_VOLT_OFFSET+1] = (uint8_t)(ExtraBuff[1]);
msgTxBuff[RT_ANT_TEMP_OFFSET] = (uint8_t)(ExtraBuff[2]);
msgTxBuff[RT_ANT_TEMP_OFFSET+1] = (uint8_t)(ExtraBuff[3]);
msgTxBuff[RT_ANT_LOCK_OFFSET] = (uint8_t)(0x0001);
msgTxBuff[RT_ANT_LOCK_OFFSET+1] = (uint8_t)(0x0001>>8);
msgTxBuff[RT_ANT_MGC_OFFSET] = (uint8_t)(0x0000);
msgTxBuff[RT_ANT_MGC_OFFSET+1] = (uint8_t)(0x0000>>8);
msgTxBuff[RT_ANT_STATE_OFFSET] = (uint8_t)(0x0001);
msgTxBuff[RT_ANT_STATE_OFFSET+1] = (uint8_t)(0x0001>>8);
Status = InterComm_SendMsg(instPtr, (int32_t)INTER_MSG_RT_LEN, INTER_MSG_RT_ADDR);
return Status;
}
/*****************************************************************************/
/**
* @brief Invoke a data frame upload process, split the received data frame
* to multiple subpackages if needed, and send the send them in a properly
* order defined by inter communication protocol.
*
* @param instPtr a pointer to inter communication instance
*
* @return SUCCESS
* FAILURE frame cannot be recognized.
* EIGNORE received a command not supported by current protocol.
* IGNORE_COMMAND_ERROR received a dummy command ignored by current protocol.
*
******************************************************************************/
// FIXME: only support ONE physical device now.
int32_t InterComm_PhyDataUpload(INTER_COMM_INST* instPtr){
int32_t Status;
uint32_t remainDataLen, numPkt, subPktLen;
uint8_t *txMsgBuff, *phyRxBuff;
L1_FRAME_TYPE lastFrameType;
txMsgBuff = (uint8_t*)instPtr->sendBuff;
phyRxBuff = (uint8_t*)instPtr->phyRecvBuff;
lastFrameType = Phy_GetLastRecvFrameType(instPtr->phyInstPtr);
remainDataLen = Phy_GetFrameLen(lastFrameType);
if(remainDataLen == L1_FRAME_NONE_LEN){
return FAILURE;
}
numPkt = 1 + ((remainDataLen - 1) / DSEGRD_PD_LEN); // dived and round up equals to ceil(x/y)
if(numPkt > MSG_DSEGRD_SUBPKG_MAX){
return FAILURE;
}
txMsgBuff[TYPE_CODE_OFFSET] = (uint8_t)(INTER_MSG_DSEGRD_CODE);
txMsgBuff[TYPE_CODE_OFFSET+1] = (uint8_t)(INTER_MSG_DSEGRD_CODE>>8);
// Time Estimate
uint32_t fsTimeL, fsTimeH;
fsTimeL = PhyRead(instPtr->phyInstPtr, FSTIME_L);
fsTimeH = PhyRead(instPtr->phyInstPtr, FSTIME_H);
instPtr->lastPhyTimeTag = fsTimeL;
instPtr->lastPhyTimeTag |= ((uint64_t)fsTimeH)<<32;
uint32_t timeComp = Phy_GetTimeComp(lastFrameType);
if(timeComp == L1_FRAME_NONE_COMP){
return FAILURE;
}
fsTimeH -= timeComp/TMWORD_FRAC_MAX;
timeComp %= TMWORD_FRAC_MAX;
fsTimeH = (fsTimeL < timeComp)?(fsTimeH - 1):fsTimeH;
fsTimeL = (fsTimeL < timeComp)?(TMWORD_FRAC_MAX + fsTimeL - timeComp) : (fsTimeL - timeComp);
memcpy(txMsgBuff+DSEGRD_TIME_OFFSET, &fsTimeL, DSEGRD_TIME_LEN/2);
memcpy(txMsgBuff+DSEGRD_TIME_OFFSET + DSEGRD_TIME_LEN/2, &fsTimeH, DSEGRD_TIME_LEN/2);
// Doppler Estimate
double doppler = Phy_GetCoarseFreqEst(instPtr->phyInstPtr);
// LSB = 0.001Hz
int64_t dopplerQnt = doppler*1000;
memcpy(txMsgBuff+DSEGRD_DPL_OFFSET, &dopplerQnt, DSEGRD_DPL_LEN);
// Check if last frame is a initial acquisition frame
// L1_2KBPS_20MS_FRAME and L1_10KBPS_10MS_FRAME is initial acquisition frame
// if acquisition frame was received successfully, mark it out.
//
// when physical layer acquisition synchronization procedure is done successfully in
// acquisition frame reception period, initial acquisition is considered as success.
if(lastFrameType == L1_2KBPS_20MS_FRAME || lastFrameType == L1_10KBPS_10MS_FRAME){
txMsgBuff[DSEGRD_IACQ_OFFSET] = (Phy_IsFrameDetected(instPtr->phyInstPtr)) ? 0xAA : 0xFF;
txMsgBuff[DSEGRD_IACQ_BEAM_OFFSET] = (Phy_IsFrameDetected(instPtr->phyInstPtr)) ? (uint8_t)instPtr->phyInstPtr->beamNo.last : 0xFF;
}
else{
txMsgBuff[DSEGRD_IACQ_OFFSET] = 0xFF;
txMsgBuff[DSEGRD_IACQ_BEAM_OFFSET] = 0xFF;
}
if(numPkt == 1){
// Initialize payload segment.
memset(txMsgBuff+DSEGRD_PD_OFFSET, 0x00, (size_t)DSEGRD_PD_LEN);
subPktLen = remainDataLen;
txMsgBuff[DSEGRD_TYPE_OFFSET] = (uint8_t)DSEGRD_TYPE_PKN;
txMsgBuff[DSEGRD_TYPE_OFFSET+1] = (uint8_t)(DSEGRD_TYPE_PKN>>8);
txMsgBuff[DSEGRD_PDLEN_OFFSET] = (uint8_t)subPktLen;
txMsgBuff[DSEGRD_PDLEN_OFFSET+1] = (uint8_t)(subPktLen>>8);
memcpy(txMsgBuff+DSEGRD_PD_OFFSET, phyRxBuff, (size_t)subPktLen);
Status = InterComm_SendMsg(instPtr, (int32_t)INTER_MSG_DSEGWR_LEN, INTER_MSG_DSEGRD_PKN_ADDR);
if(Status != SUCCESS){
return Status;
}
}
else{
for(int32_t i = 0; i < numPkt; i++){
// Initialize payload segment.
memset(txMsgBuff+DSEGRD_PD_OFFSET, 0x00, (size_t)DSEGRD_PD_LEN);
subPktLen = (remainDataLen >= DSEGRD_PD_LEN) ? DSEGRD_PD_LEN : remainDataLen;
remainDataLen = remainDataLen - subPktLen;
txMsgBuff[DSEGRD_PDLEN_OFFSET] = (uint8_t)subPktLen;
txMsgBuff[DSEGRD_PDLEN_OFFSET+1] = (uint8_t)(subPktLen>>8);
if(i == 0){
txMsgBuff[DSEGRD_TYPE_OFFSET] = (uint8_t)DSEGRD_TYPE_PK1;
txMsgBuff[DSEGRD_TYPE_OFFSET+1] = (uint8_t)(DSEGRD_TYPE_PK1>>8);
memcpy(txMsgBuff+DSEGRD_PD_OFFSET, phyRxBuff+i*DSEGRD_PD_LEN, (size_t)subPktLen);
Status = InterComm_SendMsg(instPtr, (int32_t) INTER_MSG_DSEGWR_LEN, INTER_MSG_DSEGRD_PK1_ADDR);
}
else if(i == 1){
txMsgBuff[DSEGRD_TYPE_OFFSET] = (uint8_t)DSEGRD_TYPE_PK2;
txMsgBuff[DSEGRD_TYPE_OFFSET+1] = (uint8_t)(DSEGRD_TYPE_PK2>>8);
memcpy(txMsgBuff+DSEGRD_PD_OFFSET, phyRxBuff+i*DSEGRD_PD_LEN, (size_t)subPktLen);
Status = InterComm_SendMsg(instPtr, (int32_t) INTER_MSG_DSEGWR_LEN, INTER_MSG_DSEGRD_PK2_ADDR);
}
else if(i == 2){
txMsgBuff[DSEGRD_TYPE_OFFSET] = (uint8_t)DSEGRD_TYPE_PK3;
txMsgBuff[DSEGRD_TYPE_OFFSET+1] = (uint8_t)(DSEGRD_TYPE_PK3>>8);
memcpy(txMsgBuff+DSEGRD_PD_OFFSET, phyRxBuff+i*DSEGRD_PD_LEN, (size_t)subPktLen);
Status = InterComm_SendMsg(instPtr, (int32_t) INTER_MSG_DSEGWR_LEN, INTER_MSG_DSEGRD_PK3_ADDR);
}
else{ // should never reached.
return EUNEXP;
}
if(Status != SUCCESS){
return Status;
}
}
}
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Append frame CRC-16 result to frame data buffer.
*
* @param buffPtr
* @param dataLen
*
* @return SUCCESS append successfully
* Other frame cannot be recognized.
*
******************************************************************************/
int AppendCrc(uint8_t* buffPtr, uint32_t dataLen) {
ASSERT(buffPtr != NULL);
int32_t Status = SUCCESS;
if (dataLen == 0) {
return FAILURE;
}
uint16_t crc = 0;
Status = crc16_gen(buffPtr, dataLen - COMMON_CRC_LEN, 0x1021, &crc);
if(Status != SUCCESS){
DBG_ERROR("C2C gernerate failed, error code: %d.\r\n", Status);
}
uint8_t* crcSegPtr = (buffPtr + dataLen - COMMON_CRC_LEN);
#ifdef CRC_COMPARE
*crcSegPtr = (uint8_t) crc & 0x00FF;
*(crcSegPtr + 1) = (uint8_t)((crc & 0xFF00) >> 8);
#else
*crcSegPtr = (uint8_t)((crc & 0xFF00) >> 8); (uint8_t) crc & 0x00FF;
*(crcSegPtr + 1) = (uint8_t) crc & 0x00FF;
#endif
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Check the frame CRC-16, witch can infer the frame should be dump
* or not.
*
* @param frameBuffPtr
* @param frameType
*
* @return true CRC check passed, good frame.
* false CRC check failed, bad frame.
*
******************************************************************************/
bool CrcCheck(uint8_t* buffPtr, uint32_t dataLen){
if (dataLen == 0) {
return false;
}
bool ret = false;
#ifdef CRC_COMPARE
ret = crc16_check(buffPtr, dataLen - COMMON_CRC_LEN, dataLen - COMMON_CRC_LEN, 0x1021);
#else
uint16_t crc = 0;
uint32_t Status = 0;
Status = crc16_gen(buffPtr, dataLen, 0x1021, &crc);
if(Status != SUCCESS){
DBG_ERROR("C2C gernerate failed, error code: %d.\r\n", Status);
}
ret = (crc == 0);
#endif
return ret;
}
+309
View File
@@ -0,0 +1,309 @@
/*****************************************************************************/
/**
* Description: Inter-Communication protocol, definitions and function
* prototypes.
*
* Date: 2022-06-18 16:37
* LastEditTime: 2023-04-24 17:38
* Revisions: Rev 0.2
* History:
* [2022-06-18]: Initial version.
* [2023-04-24]: Bug fix:
* - Read frame type from PL status register.
*
* Copyright(c) 2022 Beijing Institute of Technology.
* Lab of Communication and Networking
*
******************************************************************************/
#ifndef INTER_COMM_H_
#define INTER_COMM_H_
/***************************** Include Files *********************************/
#include <stdint.h>
#include "../phy_ctrl/phy_ctrl.h"
#include "xsysmon.h"
#include "../config/app_config.h"
/************************** Constant Definitions *****************************/
#define COMMON_CRC_LEN 2
#define INTER_MSG_LEN 512 //Byte
#define INTER_MSG_CRC_LEN 2
#define INTER_MSG_LEN_NONE UINT32_MAX
#define TYPE_CODE_OFFSET 0x0000
// self test request
#define INTER_MSG_ST_REQ_LEN 0x00006
#define INTER_MSG_ST_REQ_CODE 0x0011
#define ST_CMD_OFFSET 0x0002
#define ST_CMD_LEN 0x0002
#define ST_CMD 0x1111
// self test response
#define INTER_MSG_ST_RSP_LEN 0x0008
#define INTER_MSG_ST_RSP_CODE 0x0021
#define ST_RSP_STATE_OFFSET 0x0002
#define ST_RSP_STATE_LEN 0x0002
#define ST_RSP_STATE_OK 0xAAAA
#define ST_RSP_STATE_ERR 0x5555
#define ST_RSP_MASK1_OFFSET 0x0004
#define ST_RSP_MASK1_LEN 0x0002
#define ST_RSP_MASK2_OFFSET 0x0006
#define ST_RSP_MASK2_LEN 0x0002
// wake up requirement/response
#define INTER_MSG_WAKE_REQ_LEN 0x0006
#define INTER_MSG_WAKE_REQ_CODE 0x0012
#define INTER_MSG_WAKE_RSP_LEN 0x0006
#define INTER_MSG_WAKE_RSP_CODE 0x0022
#define WAKE_CMD_OFFSET 0x0002
#define WAKE_CMD_LEN 0x0002
#define WAKE_CMD_LPW_LPW 0xFFAA
#define WAKE_CMD_UP_LPW 0xAAAA
#define WAKE_CMD_UP_UP 0xFFCC
#define WAKE_CMD_LPW_UP 0xCCCC
// mode swicth command
#define INTER_MSG_MODESW_LEN 0x0016 // 20byte + crc
#define INTER_MSG_MODESW_CODE 0x0041
#define MODESW_START_TIME_OFFSET 0x0002
#define MODESW_START_TIME_LEN 0x0008
#define MODESW_TIMEOUT_OFFSET 0x000A
#define MODESW_TIMEOUT_LEN 0x0008
#define MODESW_MODE_OFFSET 0x0012
#define MODESW_MODE_LEN 0x0002
#define MODESW_MODE_NORMAL 0x0001
#define MODESW_MODE_NETSET 0x0002
// physical layer control
#define INTER_MSG_CTRL_LEN 0x00BC // 186byte + 2byte crc
#define INTER_MSG_CTRL_CODE 0x0013
#define CTRL_TIME_OFFSET 0x0002
#define CTRL_TIME_LEN 0x0008
#define CTRL_FRAME_TYPE_OFFSET 0x000A
#define CTRL_FRAME_TYPE_LEN 0x0001
#define CTRL_FRAME_10K10MS 0x01
#define CTRL_FRAME_10K20MS 0x02
#define CTRL_FRAME_200K5MS 0x03
#define CTRL_FRAME_1M25MS 0x04
#define CTRL_FRAME_2K20MS 0x05
#define CTRL_FRAME_2K100MS 0x06
#define CTRL_FRAME_40K10MS 0x07
#define CTRL_FRAME_40K20MS 0x08
#define INTER_MSG_CTRL_ANT_OFFSET 0x000B
#define INTER_MSG_CTRL_ANT_LEN 0x0001
#define CTRL_ANT_ALL 0x3F
#define CTRL_ANT_FRONT 0x01
#define CTRL_ANT_3QUAD2 0x02
#define CTRL_ANT_3QUAD4 0x04
#define CTRL_ANT_BOTT 0x08
#define CTRL_ANT_RSV1 0x10
#define CTRL_ANT_RSV2 0x20
#define INTER_MSG_CTRL_TOR_OFFSET 0x000C
#define INTER_MSG_CTRL_TOR_LEN 0x0001
#define CTRL_TOR_TX 0xAA
#define CTRL_TOR_RX 0xCC
#define INTER_MSG_CTRL_SW_OFFSET 0x000D
#define INTER_MSG_CTRL_SW_LEN 0x0001
#define CTRL_SW_PW BIT(0)
#define CTRL_SW_TR BIT(1)
#define CTRL_SW_TOR BIT(2)
#define INTER_MSG_CTRL_HOP_MODE_OFFSET 0x000E
#define INTER_MSG_CTRL_HOP_MODE_LEN 0x0002
#define CTRL_HOP_PRESET 0x2222
#define CTRL_HOP_CONFIG 0x5555
#define INTER_MSG_CTRL_HOP_PATTERN_OFFSET 0x0010
#define INTER_MSG_CTRL_HOP_PATTERN_LEN 0x00A2
#define INTER_MSG_CTRL_BEAM_MODE_OFFSET 0x00B2
#define INTER_MSG_CTRL_BEAM_MODE_LEN 0x0001
#define BEAM_MODE_WIDE 0x51
#define BEAM_MODE_NRW 0x52
#define BEAM_MODE_SUBNRW 0x53
#define INTER_MSG_CTRL_BEAM_NO_OFFSET 0x00B3
#define INTER_MSG_CTRL_BEAM_NO_LEN 0x0001
#define INTER_MSG_CTRL_AMP_WT_OFFSET 0x00B4
#define INTER_MSG_CTRL_AMP_WT_LEN 0x0002
#define INTER_MSG_CTRL_OFFAX_OFFSET 0x00B6
#define INTER_MSG_CTRL_OFFAX_LEN 0x0002
#define INTER_MSG_CTRL_RNDAX_OFFSET 0x00B8
#define INTER_MSG_CTRL_RNDAX_LEN 0x0002
// data segment write
#define MSG_DSEGWR_SUBPKG_MAX 3
#define INTER_MSG_DSEGWR_LEN 0x0200 //510 byte + 2byte crc
#define INTER_MSG_DSEGWR_CODE 0x0014
#define DSEGWR_TYPE_OFFSET 0x0002
#define DSEGWR_TYPE_LEN 0x0002
#define DSEGWR_TYPE_PKN 0x0010
#define DSEGWR_TYPE_PK1 0x0012
#define DSEGWR_TYPE_PK2 0x0013
#define DSEGWR_TYPE_PK3 0x0014
#define DSEGWR_TIME_OFFSET 0x0004
#define DSEGWR_TIME_LEN 0x0008
#define DSEGWR_PDLEN_OFFSET 0x000C
#define DSEGWR_PDLEN_LEN 0x0002
#define DSEGWR_PD_OFFSET 0x000E
#define DSEGWR_PD_LEN 0x01F0
// data segment read
#define MSG_DSEGRD_SUBPKG_MAX 3
#define INTER_MSG_DSEGRD_LEN 0x0200 //510 byte + 2byte crc
#define INTER_MSG_DSEGRD_CODE 0x0023
#define DSEGRD_TYPE_OFFSET 0x0002
#define DSEGRD_TYPE_LEN 0x0001
#define DSEGRD_TYPE_PKN 0x0010
#define DSEGRD_TYPE_PK1 0x0012
#define DSEGRD_TYPE_PK2 0x0013
#define DSEGRD_TYPE_PK3 0x0014
#define DSEGRD_TIME_OFFSET 0x0004
#define DSEGRD_TIME_LEN 0x0008
#define DSEGRD_DPL_OFFSET 0x000C
#define DSEGRD_DPL_LEN 0x0008
#define DSEGRD_PDLEN_OFFSET 0x0016
#define DSEGRD_PDLEN_LEN 0x0002
#define DSEGRD_IACQ_OFFSET 0x0014
#define DSEGRD_IACQ_LEN 0x0001
#define DSEGRD_IACQ_BEAM_OFFSET 0x0015
#define DSEGRD_IACQ_BEAM_LEN 0x0001
#define DSEGRD_PD_OFFSET 0x0018
#define DSEGRD_PD_LEN 0x01E6
// Remote state test.
#define INTER_MSG_RT_LEN 0x0022 // 32 bytes + 2byte crc
#define INTER_MSG_RT_CODE 0x0031 // remote test.
#define RT_PHY_OFFSET 0x0002
#define RT_PHY_LEN 0x0002
#define RT_TIME_OFFSET 0x0004
#define RT_TIME_LEN 0x0008
#define RT_BEAM_OFFSET 0x000C
#define RT_BEAM_LEN 0x0004
#define RT_SP_VOLT_OFFSET 0x0010
#define RT_SP_VOLT_LEN 0x0002
#define RT_SP_TEMP_OFFSET 0x0012
#define RT_SP_TEMP_LEN 0x0002
#define RT_SP_CHIP_OFFSET 0x0014
#define RT_SP_CHIP_LEN 0x0002
#define RT_ANT_VOLT_OFFSET 0x0016
#define RT_ANT_VOLT_LEN 0x0002
#define RT_ANT_TEMP_OFFSET 0x0018
#define RT_ANT_TEMP_LEN 0x0002
#define RT_ANT_LOCK_OFFSET 0x001A
#define RT_ANT_LOCK_LEN 0x0001
#define RT_ANT_MGC_OFFSET 0x001C
#define RT_ANT_MGC_LEN 0x0002
#define RT_ANT_STATE_OFFSET 0x001E
#define RT_ANT_STATE_LEN 0x0001
#ifdef ANT_DEVICE_ID
#if ANT_DEVICE_ID == 0x0000
#define INTER_MSG_DSEGRD_PKN_ADDR 0x0001
#define INTER_MSG_DSEGRD_PK1_ADDR 0x0001
#define INTER_MSG_DSEGRD_PK2_ADDR 0x0002
#define INTER_MSG_DSEGRD_PK3_ADDR 0x0003
#define INTER_MSG_RT_ADDR 0x0004
#define INTER_MSG_OTHER_ADDR 0x0005
#elif ANT_DEVICE_ID == 0x0001
#define INTER_MSG_DSEGRD_PKN_ADDR 0x0006
#define INTER_MSG_DSEGRD_PK1_ADDR 0x0006
#define INTER_MSG_DSEGRD_PK2_ADDR 0x0007
#define INTER_MSG_DSEGRD_PK3_ADDR 0x0008
#define INTER_MSG_RT_ADDR 0x0009
#define INTER_MSG_OTHER_ADDR 0x000A
#elif ANT_DEVICE_ID == 0x0002
#define INTER_MSG_DSEGRD_PKN_ADDR 0x000B
#define INTER_MSG_DSEGRD_PK1_ADDR 0x000B
#define INTER_MSG_DSEGRD_PK2_ADDR 0x000C
#define INTER_MSG_DSEGRD_PK3_ADDR 0x000D
#define INTER_MSG_RT_ADDR 0x000E
#define INTER_MSG_OTHER_ADDR 0x000F
#elif ANT_DEVICE_ID == 0x0003
#define INTER_MSG_DSEGRD_PKN_ADDR 0x0010
#define INTER_MSG_DSEGRD_PK1_ADDR 0x0010
#define INTER_MSG_DSEGRD_PK2_ADDR 0x0011
#define INTER_MSG_DSEGRD_PK3_ADDR 0x0012
#define INTER_MSG_RT_ADDR 0x0013
#define INTER_MSG_OTHER_ADDR 0x0014
#elif ANT_DEVICE_ID == 0x0004
#define INTER_MSG_DSEGRD_PKN_ADDR 0x0015
#define INTER_MSG_DSEGRD_PK1_ADDR 0x0015
#define INTER_MSG_DSEGRD_PK2_ADDR 0x0016
#define INTER_MSG_DSEGRD_PK3_ADDR 0x0017
#define INTER_MSG_RT_ADDR 0x0018
#define INTER_MSG_OTHER_ADDR 0x0019
#elif ANT_DEVICE_ID == 0x0005
#define INTER_MSG_DSEGRD_PKN_ADDR 0x001A
#define INTER_MSG_DSEGRD_PK1_ADDR 0x001A
#define INTER_MSG_DSEGRD_PK2_ADDR 0x001B
#define INTER_MSG_DSEGRD_PK3_ADDR 0x001C
#define INTER_MSG_RT_ADDR 0x001D
#define INTER_MSG_OTHER_ADDR 0x001E
#elif ANT_DEVICE_ID == 0x0006
#else
#error Cannot Eval Antenna ID...
#endif
#else
#error Antenna ID must be specified...
#endif
/***************** Macros (Inline Functions) Definitions *********************/
/**************************** Type Definitions *******************************/
typedef struct{
PHY_INST* phyInstPtr;
int32_t (*data_send) (void* buffPtr, int32_t dataLen, uint16_t subAddr);
int32_t (*data_recv) (void* buffPtr, int32_t dataLen);
}INTER_COMM_CONFIG;
// FIXME: only support ONE physical device now.
typedef struct{
uint8_t* recvBuff;
uint8_t* sendBuff;
bool isSleep;
uint32_t rxRemain;
uint32_t txRemain;
uint64_t lastCtrlTimeTag;
uint64_t lastDataTimeTag;
uint64_t lastPhyTimeTag;
PHY_INST* phyInstPtr;
uint8_t* phyRecvBuff;
uint8_t* phySendBuff;
int32_t (*data_send) (void* buffPtr, int32_t dataLen, uint16_t subAddr);
int32_t (*data_recv) (void* buffPtr, int32_t buffSize);
}INTER_COMM_INST;
typedef struct {
uint16_t glinkSubAddr;
uint8_t extra[14];
} C2C_EXTRA;
/************************** Variable Definitions *****************************/
/************************** Function Prototypes ******************************/
int32_t InterComm_Init(INTER_COMM_INST** instPtr, INTER_COMM_CONFIG* configPtr);
void InterComm_Destroy(INTER_COMM_INST* instPtr);
int32_t InterComm_RecvMsg(INTER_COMM_INST* instPtr);
int32_t InterComm_SendMsg(INTER_COMM_INST* instPtr, int32_t dataLen, uint16_t subAddr);
int32_t InterComm_MsgHandler(INTER_COMM_INST* instPtr);
int32_t InterComm_SendRemotCheck(INTER_COMM_INST* instPtr, XSysMon* SysMonInstPtr, C2C_EXTRA* c2cExtraBuffPtr);
int32_t InterComm_PhyDataUpload(INTER_COMM_INST* instPtr);
// Helper functions
int AppendCrc(uint8_t* buffPtr, uint32_t dataLen);
bool CrcCheck(uint8_t* buffPtr, uint32_t dataLen);
#endif
+217
View File
@@ -0,0 +1,217 @@
/*******************************************************************/
/* */
/* This file is automatically generated by linker script generator.*/
/* */
/* Version: 2019.1.3 */
/* */
/* Copyright (c) 2010-2016 Xilinx, Inc. All rights reserved. */
/* */
/* Description : MicroBlaze Linker Script */
/* */
/*******************************************************************/
_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x4000;
_HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x8000;
/* Define Memories in the system */
MEMORY
{
microblaze_ps_local_memory_ilmb_bram_if_cntlr_Mem_microblaze_ps_local_memory_dlmb_bram_if_cntlr_Mem : ORIGIN = 0x50, LENGTH = 0x3FFB0
ant_config_bram_ctrl_Mem0 : ORIGIN = 0xC0000000, LENGTH = 0x2000
tx_frame_bram_ctrl_Mem0 : ORIGIN = 0xC2000000, LENGTH = 0x1000
rx_frame_bram_ctrl_Mem0 : ORIGIN = 0xC4000000, LENGTH = 0x1000
c2c_rx_axi_bram_ctrl_Mem0 : ORIGIN = 0xC6000000, LENGTH = 0x2000
c2c_tx_axi_bram_ctrl_Mem0 : ORIGIN = 0xC8000000, LENGTH = 0x2000
}
/* Specify the default entry point to the program */
ENTRY(_start)
/* Define the sections, and where they are mapped in memory */
SECTIONS
{
.vectors.reset 0x0 : {
KEEP (*(.vectors.reset))
}
.vectors.sw_exception 0x8 : {
KEEP (*(.vectors.sw_exception))
}
.vectors.interrupt 0x10 : {
KEEP (*(.vectors.interrupt))
}
.vectors.hw_exception 0x20 : {
KEEP (*(.vectors.hw_exception))
}
.text : {
*(.text)
*(.text.*)
*(.gnu.linkonce.t.*)
} > microblaze_ps_local_memory_ilmb_bram_if_cntlr_Mem_microblaze_ps_local_memory_dlmb_bram_if_cntlr_Mem
.init : {
KEEP (*(.init))
} > microblaze_ps_local_memory_ilmb_bram_if_cntlr_Mem_microblaze_ps_local_memory_dlmb_bram_if_cntlr_Mem
.fini : {
KEEP (*(.fini))
} > microblaze_ps_local_memory_ilmb_bram_if_cntlr_Mem_microblaze_ps_local_memory_dlmb_bram_if_cntlr_Mem
.ctors : {
__CTOR_LIST__ = .;
___CTORS_LIST___ = .;
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE(*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
__CTOR_END__ = .;
___CTORS_END___ = .;
} > microblaze_ps_local_memory_ilmb_bram_if_cntlr_Mem_microblaze_ps_local_memory_dlmb_bram_if_cntlr_Mem
.dtors : {
__DTOR_LIST__ = .;
___DTORS_LIST___ = .;
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE(*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
PROVIDE(__DTOR_END__ = .);
PROVIDE(___DTORS_END___ = .);
} > microblaze_ps_local_memory_ilmb_bram_if_cntlr_Mem_microblaze_ps_local_memory_dlmb_bram_if_cntlr_Mem
.rodata : {
__rodata_start = .;
*(.rodata)
*(.rodata.*)
*(.gnu.linkonce.r.*)
__rodata_end = .;
} > microblaze_ps_local_memory_ilmb_bram_if_cntlr_Mem_microblaze_ps_local_memory_dlmb_bram_if_cntlr_Mem
.sdata2 : {
. = ALIGN(8);
__sdata2_start = .;
*(.sdata2)
*(.sdata2.*)
*(.gnu.linkonce.s2.*)
. = ALIGN(8);
__sdata2_end = .;
} > microblaze_ps_local_memory_ilmb_bram_if_cntlr_Mem_microblaze_ps_local_memory_dlmb_bram_if_cntlr_Mem
.sbss2 : {
__sbss2_start = .;
*(.sbss2)
*(.sbss2.*)
*(.gnu.linkonce.sb2.*)
__sbss2_end = .;
} > microblaze_ps_local_memory_ilmb_bram_if_cntlr_Mem_microblaze_ps_local_memory_dlmb_bram_if_cntlr_Mem
.data : {
. = ALIGN(4);
__data_start = .;
*(.data)
*(.data.*)
*(.gnu.linkonce.d.*)
__data_end = .;
} > microblaze_ps_local_memory_ilmb_bram_if_cntlr_Mem_microblaze_ps_local_memory_dlmb_bram_if_cntlr_Mem
.got : {
*(.got)
} > microblaze_ps_local_memory_ilmb_bram_if_cntlr_Mem_microblaze_ps_local_memory_dlmb_bram_if_cntlr_Mem
.got1 : {
*(.got1)
} > microblaze_ps_local_memory_ilmb_bram_if_cntlr_Mem_microblaze_ps_local_memory_dlmb_bram_if_cntlr_Mem
.got2 : {
*(.got2)
} > microblaze_ps_local_memory_ilmb_bram_if_cntlr_Mem_microblaze_ps_local_memory_dlmb_bram_if_cntlr_Mem
.eh_frame : {
*(.eh_frame)
} > microblaze_ps_local_memory_ilmb_bram_if_cntlr_Mem_microblaze_ps_local_memory_dlmb_bram_if_cntlr_Mem
.jcr : {
*(.jcr)
} > microblaze_ps_local_memory_ilmb_bram_if_cntlr_Mem_microblaze_ps_local_memory_dlmb_bram_if_cntlr_Mem
.gcc_except_table : {
*(.gcc_except_table)
} > microblaze_ps_local_memory_ilmb_bram_if_cntlr_Mem_microblaze_ps_local_memory_dlmb_bram_if_cntlr_Mem
.sdata : {
. = ALIGN(8);
__sdata_start = .;
*(.sdata)
*(.sdata.*)
*(.gnu.linkonce.s.*)
__sdata_end = .;
} > microblaze_ps_local_memory_ilmb_bram_if_cntlr_Mem_microblaze_ps_local_memory_dlmb_bram_if_cntlr_Mem
.sbss (NOLOAD) : {
. = ALIGN(4);
__sbss_start = .;
*(.sbss)
*(.sbss.*)
*(.gnu.linkonce.sb.*)
. = ALIGN(8);
__sbss_end = .;
} > microblaze_ps_local_memory_ilmb_bram_if_cntlr_Mem_microblaze_ps_local_memory_dlmb_bram_if_cntlr_Mem
.tdata : {
__tdata_start = .;
*(.tdata)
*(.tdata.*)
*(.gnu.linkonce.td.*)
__tdata_end = .;
} > microblaze_ps_local_memory_ilmb_bram_if_cntlr_Mem_microblaze_ps_local_memory_dlmb_bram_if_cntlr_Mem
.tbss : {
__tbss_start = .;
*(.tbss)
*(.tbss.*)
*(.gnu.linkonce.tb.*)
__tbss_end = .;
} > microblaze_ps_local_memory_ilmb_bram_if_cntlr_Mem_microblaze_ps_local_memory_dlmb_bram_if_cntlr_Mem
.bss (NOLOAD) : {
. = ALIGN(4);
__bss_start = .;
*(.bss)
*(.bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(4);
__bss_end = .;
} > microblaze_ps_local_memory_ilmb_bram_if_cntlr_Mem_microblaze_ps_local_memory_dlmb_bram_if_cntlr_Mem
_SDA_BASE_ = __sdata_start + ((__sbss_end - __sdata_start) / 2 );
_SDA2_BASE_ = __sdata2_start + ((__sbss2_end - __sdata2_start) / 2 );
/* Generate Stack and Heap definitions */
.heap (NOLOAD) : {
. = ALIGN(8);
_heap = .;
_heap_start = .;
. += _HEAP_SIZE;
_heap_end = .;
} > microblaze_ps_local_memory_ilmb_bram_if_cntlr_Mem_microblaze_ps_local_memory_dlmb_bram_if_cntlr_Mem
.stack (NOLOAD) : {
_stack_end = .;
. += _STACK_SIZE;
. = ALIGN(8);
_stack = .;
__stack = _stack;
} > microblaze_ps_local_memory_ilmb_bram_if_cntlr_Mem_microblaze_ps_local_memory_dlmb_bram_if_cntlr_Mem
_end = .;
}
+779
View File
@@ -0,0 +1,779 @@
/*****************************************************************************/
/**
* Description: main.c
*
* Date: 2021-11-13 13:19
* Last Edit Time: [2023-04-23 21:32]
*
* Revisions: Rev 0.0
* History:
* [2021-11-13]: Initial edition.
* [2022-03-28]: Add bit error test mode.
* [2023-04-23]: Bug fixed,
*
* Copyright(c) 2021 Beijing Institute of Technology.
* Lab of Communication and Networking
*
******************************************************************************/
/***************************** Include Files *********************************/
// Standard
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
// Xilinx
#include "xintc.h" // The generic interrupt controller driver component
#include "xil_exception.h" // ARM Cortex A9 specific exception related APIs
#include "sleep.h" // Sleep APIs for Cortex A9
#include "xgpio.h" // GPIO APIs for Cortex A9
#include "xbram.h"
#include "xtmrctr.h"
#include "xsysmon.h"
// ADI Drivers
#include "dev_profile/dev_profile.h"
#include "adi_noos/drivers/axi_core/spi_engine/spi_engine.h"
#include "adi_noos/drivers/platform/gpio_extra.h"
// User
#include "common.h"
#include "error.h"
#include "config/app_config.h"
#include "c2c_bridge/c2c_bridge.h"
#include "phy_ctrl/phy_ctrl.h"
#include "circ_queue/circ_queue.h"
#include "inter_comm/inter_comm.h"
/************************** Function Prototypes ******************************/
int32_t SetupInterruptSystem(XIntc* instPtr, uint32_t devId);
int32_t XADC_Init(XSysMon* instPtr, uint16_t devId);
int32_t ScuTimerInit(XTmrCtr* instPtr, uint16_t devId);
// Utility functions
int32_t Intercom_C2cRecvData(void* buffPtr, int32_t dataLen);
int32_t Intercom_C2cSendData2Addr(void* buffPtr, int32_t dataLen, uint16_t subaddrId);
// IRQ Handlers
void C2c_RxIntrHandler(void* callBackRef);
void C2c_TxIntrHandler(void* callBackRef);
void Timer_IntrHandler(void* CallBackRef);
void PhyIntr_Handler(void *callBackRef);
/************************** Constant Definitions *****************************/
#define C2C_EXTRA_LEN (sizeof(C2C_EXTRA) + COMMON_CRC_LEN)
C2C_CONFIG c2cConfig = {
.capacity = C2C_BUFF_MAX,
.dmaConfig = {
.devId = C2C_AXI_DMA_DEVICE_ID,
.transMax = C2C_BUFF_MAX,
.defaultTransLen = C2C_BUFF_MAX,
.timeoutTh = 500
}
};
INTER_COMM_CONFIG intrCommConfig = {
.data_recv = Intercom_C2cRecvData,
.data_send = Intercom_C2cSendData2Addr,
.phyInstPtr = NULL
};
PHY_CONFIG phyConfig = {
.devId = 0,
.baseAddr = PHY_CTRL_BASEADDR,
.txBramId = PHY_TX_BRAM_BUFF_ID,
.rxBramId = PHY_RX_BRAM_BUFF_ID,
.antBramId = PHY_ANT_CONFIG_BRAM_ID
};
struct spi_engine_init_param spi_engine_param = {
.ref_clk_hz = SPI_ENGINE_REF_CLK,
.type = SPI_ENGINE,
.spi_engine_baseaddr = SPI_ENGINE_BASEADDR,
.cs_delay = SPI_ENGINE_CS_DELAY,
.data_width = SPI_ENGINE_DATA_WIDTH
};
struct xil_gpio_init_param xil_gpio_param = {
.type = GPIO_PS,
.device_id = GPIO_DEVICE_ID
};
/*********************** Driver Instance Definitions **************************/
static XIntc intcInst; // General interrupt controller instance
static XSysMon SysMonInst;
#ifdef GLINK_REMOTE_TEST_ENABLE
static XTmrCtr axiTimeInst; // PS scu timer
static bool isSendRemotCheckAsserted = false;//true when 1s comes
#endif
static bool isPhyUploadAsserted = false;//true when 1s comes
static CIRC_QUEUE *c2cRecvQueue;
static PHY_INST* phyInstPtr = NULL;
static INTER_COMM_INST* intrCommInstPtr = NULL;
static C2C_EXTRA* c2cExtraBuffPtr = NULL;
// For AD9361
struct ad9516_dev *ad9516_inst;
struct ad9361_reg_dev *ad9361_1_reg_inst;
struct ad9361_reg_dev *ad9361_2_reg_inst;
struct ad9361_rf_phy *ad9361_phy;
/* Helper function for AD9361 IO control*/
static int XGpio_WritePin(XGpio *InstPtr, uint32_t Channel, u32 Pin, uint8_t Value){
ASSERT(Pin <= 31 && Pin >=0 );
ASSERT(InstPtr != NULL);
ASSERT(InstPtr->IsReady == XIL_COMPONENT_IS_READY);
ASSERT((Channel == 1) || ((Channel == 2) && (InstPtr->IsDual == TRUE)));
u32 CurrValue = XGpio_DiscreteRead(InstPtr, Channel);
CurrValue = (Value == 0)? (CurrValue & (~(0x00000001 << Pin))) : (CurrValue | (0x00000001 << Pin));
XGpio_DiscreteWrite(InstPtr, Channel, CurrValue);
return SUCCESS;
}// XGpio_WritePin
/****************************************************************************/
/**
* This function dose a hardware initialization.
*
* @param None
*
* @return SUCCESS if initialize successful.
* XST_FAILURE if initialization failed.
*
*****************************************************************************/
static int Hardware_Initialize(void){
int Status;
XGpio Gpio;
Status = XGpio_Initialize(&Gpio, GPIO_DEVICE_ID);
if (Status != SUCCESS)
{
return FAILURE;
}
XGpio_SetDataDirection(&Gpio, GPIO_BANK_OUT, 0x00000000); // Bank 1 output
XGpio_SetDataDirection(&Gpio, GPIO_BANK_IN, 0xFFFFFFFF); // Bank 0 inputT_FAILURE;
/**********************************************************/
/****************** AD9516 Configuration ******************/
/**********************************************************/
Status = ad9516_init(&ad9516_inst, &ad9516_default_init_param);
XGpio_WritePin(&Gpio, GPIO_BANK_OUT, AD9516_POWEDOWN_B, 1);
XGpio_WritePin(&Gpio, GPIO_BANK_OUT, AD9516_SYNC_B, 1);
XGpio_WritePin(&Gpio, GPIO_BANK_OUT, AD9516_RESET_B, 0);
mdelay(200);
XGpio_WritePin(&Gpio, GPIO_BANK_OUT, AD9516_RESET_B, 1);
for(int i = 0; i < ad9516_default_config_len; i++){
Status = ad9516_write(ad9516_inst, ad9516_default_config[i].addr, ad9516_default_config[i].value);
if (ad9516_default_config[i].addr == 0x0000){
mdelay(500);
}
}
uint8_t rd_back;
Status = ad9516_read(ad9516_inst, 0x0003, &rd_back);
do
{
Status = ad9516_read(ad9516_inst, 0x001F, &rd_back);
}
while((rd_back & 0x01) != 0x01);
/**********************************************************/
/***************** AD9361-1 Configuration *****************/
/**********************************************************/
XGpio_WritePin(&Gpio, GPIO_BANK_OUT, AD9361_RX_FIFO_RST, 1);
XGpio_WritePin(&Gpio, GPIO_BANK_OUT, AD9361_SYNC, 0);
ad9361_reg_init(&ad9361_1_reg_inst, &ad9361_1_reg_default_init_param);
XGpio_WritePin(&Gpio, GPIO_BANK_OUT, AD9361_1_RESET_B, 0);
mdelay(200);
XGpio_WritePin(&Gpio, GPIO_BANK_OUT, AD9361_1_RESET_B, 1);
XGpio_WritePin(&Gpio, GPIO_BANK_OUT, AD9361_1_ENABLE, 0);
ad9361_reg_config(ad9361_1_reg_inst);
XGpio_WritePin(&Gpio, GPIO_BANK_OUT, AD9361_1_ENABLE, 1);
/**********************************************************/
/***************** AD9361-2 Configuration *****************/
/**********************************************************/
ad9361_reg_init(&ad9361_2_reg_inst, &ad9361_2_reg_default_init_param);
XGpio_WritePin(&Gpio, GPIO_BANK_OUT, AD9361_2_RESET_B, 0);
mdelay(200);
XGpio_WritePin(&Gpio, GPIO_BANK_OUT, AD9361_2_RESET_B, 1);
XGpio_WritePin(&Gpio, GPIO_BANK_OUT, AD9361_2_ENABLE, 0);
ad9361_reg_config(ad9361_2_reg_inst);
XGpio_WritePin(&Gpio, GPIO_BANK_OUT, AD9361_2_ENABLE, 1);
// sync clock output
XGpio_WritePin(&Gpio, GPIO_BANK_OUT, AD9516_SYNC_B, 0);
mdelay(500);
XGpio_WritePin(&Gpio, GPIO_BANK_OUT, AD9516_SYNC_B, 1);
// SYNC BBPLL and DIGITAL SAMPLING CLOCKS
ad9361_reg_init(&ad9361_1_reg_inst, &ad9361_1_reg_default_init_param);
ad9361_reg_init(&ad9361_2_reg_inst, &ad9361_2_reg_default_init_param);
ad9361_reg_write(ad9361_1_reg_inst, 0x0001, 0x0D); // MCS RF Enable; MCS BBPLL Enable; MCS BB Enable
ad9361_reg_write(ad9361_2_reg_inst, 0x0001, 0x0D);
ad9361_reg_write(ad9361_1_reg_inst, 0x0047, 0x80); // MCS refclk Scale Enable
ad9361_reg_write(ad9361_2_reg_inst, 0x0047, 0x80);
XGpio_WritePin(&Gpio, GPIO_BANK_OUT, AD9361_SYNC, 1); // Input a rising-edge pulse to the SYNC_IN pin
mdelay(500);
XGpio_WritePin(&Gpio, GPIO_BANK_OUT, AD9361_SYNC, 0);
mdelay(2000);
ad9361_reg_write(ad9361_1_reg_inst, 0x0001, 0x0B); // MCS RF Enable; MCS Digital CLK Enable ; MCS BB Enable
ad9361_reg_write(ad9361_2_reg_inst, 0x0001, 0x0B);
XGpio_WritePin(&Gpio, GPIO_BANK_OUT, AD9361_SYNC, 1); // Input another rising-edge pulse to the SYNC_IN pin
mdelay(500);
XGpio_WritePin(&Gpio, GPIO_BANK_OUT, AD9361_SYNC, 0);
ad9361_reg_write(ad9361_1_reg_inst, 0x0001, 0x08); // clear MCS bits
ad9361_reg_write(ad9361_2_reg_inst, 0x0001, 0x08);
XGpio_WritePin(&Gpio, GPIO_BANK_OUT, AD9361_RX_FIFO_RST, 0);
return SUCCESS;
}// Hardware_Initialize
/*****************************************************************************/
/**
* @brief Initialize ScuTimer instance.
*
* @param InstPtr A pointer to QSPI instance
*
* @param DevId ScuTimer instance device ID
*
* @return SUCCESS
* XST_FAILURE
*
******************************************************************************/
int32_t ScuTimerInit(XTmrCtr* instPtr, uint16_t devId) {
int Status = SUCCESS;
XTmrCtr_Config *configPtr;
/*
* Initialize the Scu Private Timer driver.
*/
configPtr = XTmrCtr_LookupConfig(devId);
/*
* This is where the virtual address would be used, this example
* uses physical address.
*/
Status = XTmrCtr_Initialize(instPtr, configPtr->DeviceId);
if (Status != SUCCESS) {
return Status;
}
/*
* Perform a self-test to ensure that the hardware was built correctly.
*/
Status = XTmrCtr_SelfTest(instPtr, XTC_TIMER_0);
return Status;
}// ScuTimerInit
/*****************************************************************************/
/**
* @brief Initialize XADC instance.
*
* @param InstPtr A pointer to QSPI instance
*
* @param DevId ScuTimer instance device ID
*
* @return SUCCESS
* XST_FAILURE
*
******************************************************************************/
int32_t XADC_Init(XSysMon* instPtr, uint16_t devId) {
int Status = SUCCESS;
XSysMon_Config *configPtr;
/*
* Initialize the Scu Private Timer driver.
*/
configPtr = XSysMon_LookupConfig(devId);
if (configPtr == NULL) {
return XST_FAILURE;
}
XSysMon_CfgInitialize(instPtr, configPtr, configPtr->BaseAddress);
//safe mode
XSysMon_SetSequencerMode(instPtr, XSM_SEQ_MODE_SAFE);
//enable channels
XSysMon_SetSeqChEnables(instPtr, XSM_SEQ_CH_TEMP|XSM_SEQ_CH_VCCINT);
/* Set the ADCCLK frequency equal to 1/32 of System clock for the System
* Monitor/ADC in the Configuration Register 2.
*/
XSysMon_SetAdcClkDivisor(instPtr, 32);
//mode
XSysMon_SetSequencerMode(instPtr, XSM_SEQ_MODE_CONTINPASS);
/*
* Wait till the End of Sequence occurs
*/
XSysMon_GetStatus(instPtr); /* Clear the old status */
while ((XSysMon_GetStatus(instPtr) & XSM_SR_EOS_MASK) !=
XSM_SR_EOS_MASK);
return Status;
}// XADC_Init
/****************************************************************************/
/**
* This function is responsible for initializing the SCUGIC instance, looking
* for the device configuration based on the unique device ID, initializing a
* SCUGIC instance, and initialize the interrupt at IRQ_F2P[0:0]
*
* @param deviceID is the XPAR_<GPIO_instance>_DEVICE_ID value from
* "xparameters.h".
* @param XIntc is a reference to the XScuGic driver Instance.
*
* @return SUCCESS if initialize successful.
* XST_FAILURE if initialization failed.
*
*****************************************************************************/
int32_t SetupInterruptSystem(XIntc* instPtr, uint32_t devId){
int Status = SUCCESS;
// Initialize the GIC instance.
Status = XIntc_Initialize(instPtr, devId);
if (Status != SUCCESS) {
return Status;
}
// Perform a self-test to ensure that the hardware was built correctly.
Status = XIntc_SelfTest(instPtr);
if (Status != SUCCESS) {
return Status;
}
/* Hook up interrupt service routine */
Status = XIntc_Connect(instPtr, PHY_INTR_ID,
(XInterruptHandler) PhyIntr_Handler, (void *) instPtr);
if (Status != SUCCESS) {
return Status;
}
/* Enable the interrupt vector at the interrupt controller */
XIntc_Enable(instPtr, PHY_INTR_ID);
/* Hook up interrupt service routine */
Status = XIntc_Connect(instPtr, C2C_TX_INTR_ID,
(XInterruptHandler) C2c_TxIntrHandler, (void *) instPtr);
if (Status != SUCCESS) {
return Status;
}
Status = XIntc_Connect(instPtr, C2C_RX_INTR_ID,
(XInterruptHandler) C2c_RxIntrHandler, (void *) instPtr);
if (Status != SUCCESS) {
return Status;
}
/* Enable the interrupt vector at the interrupt controller */
XIntc_Enable(instPtr, C2C_TX_INTR_ID);
XIntc_Enable(instPtr, C2C_RX_INTR_ID);
#ifdef GLINK_REMOTE_TEST_ENABLE
// ScuTimer interrupt
Status = XIntc_Connect(instPtr, SCUTIMER_INTR_ID,
(Xil_ExceptionHandler) Timer_IntrHandler,
(void *) &axiTimeInst);
if (Status != SUCCESS) {
return Status;
}
XIntc_Enable(instPtr, SCUTIMER_INTR_ID);
#endif
/* Start the interrupt controller such that interrupts are recognized
* and handled by the processor
*/
Status = XIntc_Start(instPtr, XIN_REAL_MODE);
if (Status != SUCCESS) {
return Status;
}
/* Initialize the exception table and register the interrupt controller
* handler with the exception table
*/
Xil_ExceptionInit();
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler) XIntc_InterruptHandler,
(void *) instPtr);
// Enable non-critical exceptions
Xil_ExceptionEnable();
return SUCCESS;
} // SetupInterruptSystem
/****************************************************************************/
/**
* This is a utility function to implement a C2C data transmission.
*
* @param buffPtr a pointer to data buffer, which need to be 2 byte aligned.
* @param dataLen length of data needs to be sent.
*
* @return None.
*
* @note None.
*
*****************************************************************************/
int32_t Intercom_C2cRecvData(void* buffPtr, int32_t buffSize){
int Status;
uint8_t* c2cRecvDataPtr;
if(isCircQueueEmpty(c2cRecvQueue)){
return EIGNORE;
}
else{
Status = CircQueuePop(c2cRecvQueue, (void**)(&c2cRecvDataPtr));
if(Status == false || c2cRecvDataPtr == NULL){
return FAILURE;
}
}
uint32_t recvLen = IO_In32((uintptr_t)(c2cRecvDataPtr + C2C_DLEN_OFFSET)) - C2C_HEADER_LEN;
memcpy(buffPtr, c2cRecvDataPtr + C2C_PLOAD_OFFSET, recvLen);
// Check if buffer is big enough.
if(buffSize < recvLen - C2C_EXTRA_LEN){
DBG_ERROR("Buffer too small.\r\n",);
return FAILURE;
}
// Check CRC
if(CrcCheck(buffPtr + recvLen - C2C_EXTRA_LEN, C2C_EXTRA_LEN) == true){
// Store received data
memcpy(c2cExtraBuffPtr, buffPtr + recvLen - C2C_EXTRA_LEN, sizeof(C2C_EXTRA));
}
else{
DBG_ERROR("C2C extra crc check failed.\r\n");
return ECRC;
}
return SUCCESS;
} //Intercom_C2cRecvData
/****************************************************************************/
/**
* This is a utility function to implement a C2C data transmission.
*
* @param buffPtr a pointer to data buffer, which need to be 2 byte aligned.
* @param dataLen length of data needs to be sent.
* @param subaddrId taget subAddress
*
* @return None.
*
* @note None.
*
*****************************************************************************/
int32_t Intercom_C2cSendData2Addr(void* buffPtr, int32_t dataLen, uint16_t subaddrId){
int Status;
if(dataLen > (C2C_BUFF_MAX - (sizeof(C2C_EXTRA)+COMMON_CRC_LEN))){
return FAILURE;
}
c2cExtraBuffPtr->glinkSubAddr = subaddrId;
memcpy((uint8_t *)(C2C_TXBUFF_ADDR_BASE + C2C_PLOAD_OFFSET), buffPtr, dataLen);
memcpy((uint8_t *)(C2C_TXBUFF_ADDR_BASE + C2C_PLOAD_OFFSET + dataLen), c2cExtraBuffPtr, sizeof(C2C_EXTRA));
Status = AppendCrc((uint8_t *)(C2C_TXBUFF_ADDR_BASE + C2C_PLOAD_OFFSET + dataLen), C2C_EXTRA_LEN);
if(Status != SUCCESS){
DBG_ERROR("C2C extra data crc append error, with error code: %d.\r\n", Status);
return Status;
}
Status = C2c_BlockingSendData(c2cInstPtr, (uint8_t *)C2C_TXBUFF_ADDR_BASE, dataLen + C2C_EXTRA_LEN);
// FIXME
usleep(1);
return Status;
}// Intercom_C2cSendData2Addr
/****************************************************************************/
/**
* This function is a interrupt service routine for IRQ_F2P[1:1], IRQ_F2P[1:1]
* tells CPU that the data in OCM is ready!
*
* @param callBackRef is the SCUGIC instance pointer.
*
* @return None.
*
* @note None.
*
*****************************************************************************/
uint32_t c2cRecvCnt = 0;
void C2c_RxIntrHandler(void *callBackRef) {
int32_t Status;
Status = C2c_RecvIrqHandler(c2cInstPtr);
if(Status != SUCCESS){
_nop_();
}
CircQueuePush(c2cRecvQueue, (void *)c2cInstPtr->lastRxBuff);
uint8_t* nextRxBuff = (c2cInstPtr->lastRxBuff >= C2C_RXBUFF_ADDR_BASE + (C2C_BUFF_NUM-1)*C2C_BUFF_SIZE) ?
(uint8_t*)C2C_RXBUFF_ADDR_BASE : (uint8_t*)(c2cInstPtr->lastRxBuff + C2C_BUFF_SIZE);
C2c_RecvData(c2cInstPtr, nextRxBuff, C2C_BUFF_SIZE);
c2cRecvCnt ++;
return;
} // C2cRxIntr_Handler
/****************************************************************************/
/**
* This function is a interrupt service routine for IRQ_F2P[1:1], IRQ_F2P[1:1]
* tells CPU that the data in OCM is ready!
*
* @param callBackRef is the SCUGIC instance pointer.
*
* @return None.
*
* @note None.
*
*****************************************************************************/
uint32_t c2cSendvCnt = 0;
void C2c_TxIntrHandler(void *callBackRef) {
int32_t Status;
Status = C2c_SendIrqHandler(c2cInstPtr);
if(Status != SUCCESS){
_nop_();
}
c2cSendvCnt ++;
return;
} // C2cTxIntr_Handler
/****************************************************************************/
/**
* This function is a interrupt service routine for IRQ_F2P[1:1], IRQ_F2P[1:1]
* tells CPU that the data in OCM is ready!
*
* @param callBackRef is the SCUGIC instance pointer.
*
* @return None.
*
* @note None.
*
*****************************************************************************/
uint32_t phyIntrCnt = 0;
void PhyIntr_Handler(void *callBackRef) {
phyIntrCnt++;
Phy_UpdateState(phyInstPtr);
// Check last frame.
if (Phy_IsFrameValid(phyInstPtr) == true) {
Phy_RetrieveRecvData(phyInstPtr, intrCommInstPtr->phyRecvBuff);
isPhyUploadAsserted = true;
}
return;
} // PhyIntr_Handler
/*****************************************************************************/
/**
* @brief Handler of ScuTimer interrupt.
*
* @param CallBackRef A pointer to corresponding ScuTimer instance.
*
* @return None.
*
******************************************************************************/
#ifdef GLINK_REMOTE_TEST_ENABLE
void Timer_IntrHandler(void* CallBackRef) {
ASSERT(CallBackRef != NULL);
XTmrCtr *TimerInstPtr = (XTmrCtr *) CallBackRef;
XTmrCtr_InterruptHandler(TimerInstPtr);
isSendRemotCheckAsserted = true;
return;
} //Timer_IntrHandler
#endif
/*****************************************************************************/
/**
* @brief Main function, initialize all the device needed, initialize
* interrupt system, halt in while(1) wait for event interrupt.
*
* @param None.
*
* @return
*
******************************************************************************/
int main(void) {
int Status;
/*** Initialize Hardware AD9361 AD9516 ***/
Status = Hardware_Initialize();
if (Status == SUCCESS) {
DBG_PRINT("Hardware Init SUCCESS! \r\n");
}
else {
DBG_PRINT("Hardware Init FAILED! \r\n");
return Status;
}
#ifdef GLINK_REMOTE_TEST_ENABLE
/*** Initialize Remote Test Updater Module ***/
//-- ScuTimer Initialization
Status = ScuTimerInit(&axiTimeInst, SCUTIMER_DEVICE_ID);
if (Status == SUCCESS) {
DBG_INFO("ScuTimer Init SUCCESS! \r\n");
}
else {
DBG_ERROR("ScuTimer Init FAILED, ErrorCode: 0x%08X\r\n, Status");
return Status;
}
XTmrCtr_InitHw(&axiTimeInst);
//-- XADC Initialization
Status = XADC_Init(&SysMonInst, SYSMON_DEVICE_ID);
if (Status == SUCCESS) {
DBG_INFO("XADC Init SUCCESS! \r\n");
}
else {
DBG_ERROR("XADC Init FAILED, ErrorCode: 0x%08X\r\n, Status");
return Status;
}
#endif
/*** Initialize C2C bridge ***/
//-- Buffer Initialization
Status = CircQueueCreate(&c2cRecvQueue, C2C_BUFF_NUM);
if (Status == true) {
DBG_PRINT("CircQueue Creat SUCCESS! \r\n");
}
else {
DBG_PRINT("CircQueue Creat FAILED! \r\n");
return EUNEXP;
}
c2cExtraBuffPtr = (C2C_EXTRA*) malloc(sizeof(C2C_EXTRA));
if ((c2cExtraBuffPtr) == NULL) {
DBG_PRINT("c2cExtraBuffPtr allocate FAILED! \r\n");
return EALLOC;
}
//-- C2C Hardware Initialization
Status = C2c_Init(&c2cInstPtr, &c2cConfig);
if (Status == SUCCESS) {
DBG_INFO("C2C bridge Init SUCCESS! \r\n");
}
else {
DBG_ERROR("C2C bridge Init FAILED, ErrorCode: %d\r\n, Status");
return Status;
}
//-- C2C Intercommunication Module Initialization
intrCommConfig.phyInstPtr = phyInstPtr;
Status = InterComm_Init(&intrCommInstPtr, &intrCommConfig);
if (Status == SUCCESS) {
DBG_INFO("nterComm Init SUCCESS! \r\n");
}
else {
DBG_ERROR("nterComm Init FAILED, ErrorCode: %d\r\n, Status");
return Status;
}
//-- Start C2C Receiving Process
Status = C2c_RecvData(c2cInstPtr, (uint8_t*)C2C_RXBUFF_ADDR_BASE, C2C_BUFF_SIZE);
if (Status == SUCCESS) {
DBG_PRINT("C2C start listening SUCCESS! \r\n");
}
else {
DBG_PRINT("C2C start listening FAILED! \r\n");
return Status;
}
//-- Enable C2C Interrupts
Status = C2c_IrqEnable(c2cInstPtr);
if (Status == SUCCESS) {
DBG_INFO("Glink interrupts enable SUCCESS!\r\n");
}
else {
DBG_ERROR("Glink interrupts enable FAILED, with error code: %d.\r\n", Status);
return Status;
}
/*** Initialize Physical Layer Control Module ***/
//-- Physical Layer Hardware Initialization
Status = Phy_InstInit(&phyInstPtr, &phyConfig);
if (Status == SUCCESS) {
DBG_PRINT("PhyCtrl Init SUCCESS! \r\n");
}
else {
DBG_PRINT("PhyCtrl Init FAILED! \r\n");
return Status;
}
//-- Set Physical Layer Mode
Status = Phy_SetMode(phyInstPtr, PHY_MODE_PULL);
if (Status == SUCCESS) {
DBG_PRINT("Physical Mode %u Setup SUCCESS! \r\n", PHY_MODE_LISTEN);
}
else {
DBG_PRINT("Physical Mode %u Setup FAILED! \r\n", PHY_MODE_LISTEN);
return Status;
}
/*** Initialize GIC ***/
Status = SetupInterruptSystem(&intcInst, INTC_DEVICE_ID);
if (Status == SUCCESS) {
DBG_INFO("Intc Init SUCCESS! \r\n");
}
else {
DBG_ERROR("Intc Init FAILED, ErrorCode: %d\r\n, Status");
return Status;
}
#ifdef GLINK_REMOTE_TEST_ENABLE
// Start Remote Control Timer
XTmrCtr_SetLoadReg(axiTimeInst.BaseAddress, XTC_TIMER_0, TIMER_COUNT_MAX);
XTmrCtr_SetControlStatusReg(axiTimeInst.BaseAddress, XTC_TIMER_0,
XTC_CSR_ENABLE_TMR_MASK | XTC_CSR_ENABLE_INT_MASK |
XTC_CSR_AUTO_RELOAD_MASK | XTC_CSR_DOWN_COUNT_MASK);
XTmrCtr_Start(&axiTimeInst,XTC_TIMER_0);
XTmrCtr_Start(&axiTimeInst,XTC_TIMER_0);
#endif
DBG_PRINT("Starting Physical Layer...");
Phy_Start(phyInstPtr);
/*** Main Routine - Handling C2C Handshake ***/
while(true){
// Upload physical frame data if new frame received.
if(isPhyUploadAsserted && !C2c_IsSendBusy(c2cInstPtr)){
isPhyUploadAsserted = false;
Status = InterComm_PhyDataUpload(intrCommInstPtr);
if(Status != SUCCESS){
DBG_PRINT("####\tInterComm L1 data upload finished with code: %d", Status);
continue;
}
}
// Handle received intercom frame if received.
else if(isCircQueueEmpty(c2cRecvQueue) == false){
Status = InterComm_RecvMsg(intrCommInstPtr);
if(Status != SUCCESS){
DBG_PRINT("####\tInterComm L1 data upload finished with code: %d.\r\n", Status);
continue;
}
else{
Status = InterComm_MsgHandler(intrCommInstPtr);
if(Status != SUCCESS){
DBG_PRINT("####\tInterComm message handler finished with code: %d\n\r", Status);
continue;
}
}
}
#ifdef GLINK_REMOTE_TEST_ENABLE
// Update remote monitoring info if needed.
else if(isSendRemotCheckAsserted && !C2c_IsSendBusy(c2cInstPtr)){
isSendRemotCheckAsserted = false;
Status = InterComm_SendRemotCheck(intrCommInstPtr, &SysMonInst, c2cExtraBuffPtr);
if(Status != SUCCESS){
DBG_PRINT("####\tInterComm L1 data upload finished with code: %d", Status);
}
}
#endif
}// Waiting for interrupt
// uint8_t * sendBuffPtr = (uint8_t *)C2C_TXBUFF_ADDR_BASE;
// uint32_t cnt = 0;
// while(cnt < 10240){
// if(!C2c_IsSendBusy(c2cInstPtr)){
// for(int i = 0; i < 512; i++){
// sendBuffPtr[i] = i + cnt;
// }
// C2c_BlockingSendData(c2cInstPtr, sendBuffPtr, 512);
// cnt++;
// }
// }
// while(true);
} // main
+1
View File
@@ -0,0 +1 @@
../../datalink814_ge/src/phy_ctrl
+1
View File
@@ -0,0 +1 @@
../../datalink814_ge/src/time_ctrl
+1
View File
@@ -0,0 +1 @@
../../datalink814_ge/src/util