mirror of
https://github.com/EttusResearch/uhd.git
synced 2026-10-25 17:36:10 +00:00
320 lines
9.0 KiB
C++
320 lines
9.0 KiB
C++
//
|
|
// Copyright 2017 Ettus Research, National Instruments Company
|
|
//
|
|
// SPDX-License-Identifier: GPL-3.0
|
|
//
|
|
|
|
#include "adi/common.h"
|
|
|
|
#include <mpm/ad937x/adi_ctrl.hpp>
|
|
#include <mpm/types/log_buf.hpp>
|
|
#include <uhd/exception.hpp>
|
|
#include <boost/format.hpp>
|
|
|
|
#include <iostream>
|
|
#include <chrono>
|
|
#include <thread>
|
|
#include <sstream>
|
|
|
|
ad9371_spiSettings_t::ad9371_spiSettings_t(
|
|
mpm::types::regs_iface* spi_iface_
|
|
) :
|
|
spi_iface(spi_iface_)
|
|
{
|
|
spi_settings.chipSelectIndex = 0; // set later
|
|
spi_settings.writeBitPolarity = 1; // unused
|
|
spi_settings.longInstructionWord = 1;
|
|
spi_settings.MSBFirst = 1;
|
|
spi_settings.CPHA = 0;
|
|
spi_settings.CPOL = 0;
|
|
spi_settings.enSpiStreaming = 0; // unused
|
|
spi_settings.autoIncAddrUp = 0; // unused
|
|
spi_settings.fourWireMode = 1; // unused
|
|
spi_settings.spiClkFreq_Hz = 250000000; // currently unused
|
|
}
|
|
|
|
// TODO: change // not implemented to meaningful errors
|
|
|
|
// close hardware pointers
|
|
commonErr_t CMB_closeHardware(void)
|
|
{
|
|
// not implemented
|
|
return COMMONERR_FAILED;
|
|
}
|
|
|
|
// GPIO function
|
|
commonErr_t CMB_setGPIO(uint32_t GPIO)
|
|
{
|
|
// not implemented
|
|
return COMMONERR_FAILED;
|
|
}
|
|
|
|
// hardware reset function
|
|
commonErr_t CMB_hardReset(uint8_t spiChipSelectIndex)
|
|
{
|
|
// TODO: implement
|
|
return COMMONERR_OK;
|
|
}
|
|
|
|
//
|
|
// SPI read/write functions
|
|
//
|
|
|
|
// allows the platform HAL to work with devices with various SPI settings
|
|
commonErr_t CMB_setSPIOptions(spiSettings_t *spiSettings)
|
|
{
|
|
// not implemented
|
|
return COMMONERR_OK;
|
|
}
|
|
|
|
// value of 0 deasserts all chip selects
|
|
commonErr_t CMB_setSPIChannel(uint16_t chipSelectIndex)
|
|
{
|
|
// not implemented
|
|
return COMMONERR_OK;
|
|
}
|
|
|
|
// single SPI byte write function
|
|
commonErr_t CMB_SPIWriteByte(spiSettings_t *spiSettings, uint16_t addr, uint8_t data)
|
|
{
|
|
if (spiSettings == nullptr || spiSettings->MSBFirst == 0) {
|
|
return COMMONERR_FAILED;
|
|
}
|
|
|
|
ad9371_spiSettings_t *spi = ad9371_spiSettings_t::make(spiSettings);
|
|
try {
|
|
spi->spi_iface->poke8(addr, data);
|
|
return COMMONERR_OK;
|
|
} catch (const std::exception &e) {
|
|
// TODO: spit out a reasonable error here (that will survive the C API transition)
|
|
std::stringstream ss;
|
|
ss << "Error in CMB_SPIWriteByte: " << e.what();
|
|
CMB_writeToLog(
|
|
ADIHAL_LOG_ERROR,
|
|
spiSettings->chipSelectIndex,
|
|
ad9371_spi_errors_t::SPI_WRITE_ERROR,
|
|
ss.str().c_str());
|
|
}
|
|
return COMMONERR_FAILED;
|
|
}
|
|
|
|
// multi SPI byte write function (address, data pairs)
|
|
commonErr_t CMB_SPIWriteBytes(spiSettings_t *spiSettings, uint16_t *addr, uint8_t *data, uint32_t count)
|
|
{
|
|
if (spiSettings == nullptr ||
|
|
addr == nullptr ||
|
|
data == nullptr ||
|
|
spiSettings->MSBFirst == 0)
|
|
{
|
|
return COMMONERR_FAILED;
|
|
}
|
|
|
|
ad9371_spiSettings_t *spi = ad9371_spiSettings_t::make(spiSettings);
|
|
try {
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
uint32_t data_word = (0) | (addr[i] << 8) | (data[i]);
|
|
|
|
spi->spi_iface->poke8(addr[i], data[i]);
|
|
}
|
|
return COMMONERR_OK;
|
|
} catch (const std::exception &e) {
|
|
// TODO: spit out a reasonable error here (that will survive the C API transition)
|
|
std::stringstream ss;
|
|
ss << "Error in CMB_SPIWriteBytes: " << e.what();
|
|
CMB_writeToLog(
|
|
ADIHAL_LOG_ERROR,
|
|
spiSettings->chipSelectIndex,
|
|
ad9371_spi_errors_t::SPI_WRITE_ERROR,
|
|
ss.str().c_str());
|
|
}
|
|
return COMMONERR_FAILED;
|
|
}
|
|
|
|
// single SPI byte read function
|
|
commonErr_t CMB_SPIReadByte (spiSettings_t *spiSettings, uint16_t addr, uint8_t *readdata)
|
|
{
|
|
if (spiSettings == nullptr ||
|
|
readdata == nullptr ||
|
|
spiSettings->MSBFirst == 0)
|
|
{
|
|
return COMMONERR_FAILED;
|
|
}
|
|
|
|
ad9371_spiSettings_t *spi = ad9371_spiSettings_t::make(spiSettings);
|
|
try {
|
|
*readdata = spi->spi_iface->peek8(addr);
|
|
return COMMONERR_OK;
|
|
} catch (const std::exception &e) {
|
|
// TODO: spit out a reasonable error here (that will survive the C API transition)
|
|
std::stringstream ss;
|
|
ss << "Error in CMB_SPIReadByte: " << e.what();
|
|
CMB_writeToLog(
|
|
ADIHAL_LOG_ERROR,
|
|
spiSettings->chipSelectIndex,
|
|
ad9371_spi_errors_t::SPI_READ_ERROR,
|
|
ss.str().c_str());
|
|
}
|
|
return COMMONERR_FAILED;
|
|
}
|
|
|
|
// write a field in a single register
|
|
commonErr_t CMB_SPIWriteField(
|
|
spiSettings_t *spiSettings,
|
|
uint16_t addr, uint8_t field_val,
|
|
uint8_t mask, uint8_t start_bit
|
|
) {
|
|
ad9371_spiSettings_t *spi = ad9371_spiSettings_t::make(spiSettings);
|
|
|
|
try {
|
|
uint8_t current_value = spi->spi_iface->peek8(addr);
|
|
uint8_t new_value = ((current_value & ~mask) | (field_val << start_bit));
|
|
spi->spi_iface->poke8(addr, new_value);
|
|
return COMMONERR_OK;
|
|
} catch (const std::exception &e) {
|
|
// TODO: spit out a reasonable error here (that will survive the C API transition)
|
|
std::stringstream ss;
|
|
ss << "Error in CMB_SPIWriteField: " << e.what();
|
|
CMB_writeToLog(
|
|
ADIHAL_LOG_ERROR,
|
|
spiSettings->chipSelectIndex,
|
|
ad9371_spi_errors_t::SPI_WRITE_ERROR,
|
|
ss.str().c_str());
|
|
}
|
|
return COMMONERR_FAILED;
|
|
}
|
|
|
|
|
|
// read a field in a single register
|
|
commonErr_t CMB_SPIReadField(
|
|
spiSettings_t *spiSettings,
|
|
uint16_t addr, uint8_t *field_val,
|
|
uint8_t mask, uint8_t start_bit
|
|
) {
|
|
ad9371_spiSettings_t *spi = ad9371_spiSettings_t::make(spiSettings);
|
|
|
|
try {
|
|
uint8_t value = spi->spi_iface->peek8(addr);
|
|
*field_val = static_cast<uint8_t>((value & mask) >> start_bit);
|
|
return COMMONERR_OK;
|
|
} catch (const std::exception &e) {
|
|
// TODO: spit out a reasonable error here (that will survive the C API transition)
|
|
std::stringstream ss;
|
|
ss << "Error in CMB_SPIReadField: " << e.what();
|
|
CMB_writeToLog(
|
|
ADIHAL_LOG_ERROR,
|
|
spiSettings->chipSelectIndex,
|
|
ad9371_spi_errors_t::SPI_READ_ERROR,
|
|
ss.str().c_str());
|
|
}
|
|
return COMMONERR_FAILED;
|
|
}
|
|
|
|
// platform timer functions
|
|
|
|
commonErr_t CMB_wait_ms(uint32_t time_ms)
|
|
{
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(time_ms));
|
|
return COMMONERR_OK;
|
|
}
|
|
commonErr_t CMB_wait_us(uint32_t time_us)
|
|
{
|
|
std::this_thread::sleep_for(std::chrono::microseconds(time_us));
|
|
return COMMONERR_OK;
|
|
}
|
|
|
|
commonErr_t CMB_setTimeout_ms(spiSettings_t *spiSettings, uint32_t timeOut_ms)
|
|
{
|
|
ad9371_spiSettings_t *mpm_spi = ad9371_spiSettings_t::make(spiSettings);
|
|
mpm_spi->timeout_start = std::chrono::steady_clock::now();
|
|
mpm_spi->timeout_duration = std::chrono::milliseconds(timeOut_ms);
|
|
return COMMONERR_OK;
|
|
}
|
|
commonErr_t CMB_setTimeout_us(spiSettings_t *spiSettings, uint32_t timeOut_us)
|
|
{
|
|
ad9371_spiSettings_t *mpm_spi = ad9371_spiSettings_t::make(spiSettings);
|
|
mpm_spi->timeout_start = std::chrono::steady_clock::now();
|
|
mpm_spi->timeout_duration = std::chrono::microseconds(timeOut_us);
|
|
return COMMONERR_OK;
|
|
}
|
|
commonErr_t CMB_hasTimeoutExpired(spiSettings_t *spiSettings)
|
|
{
|
|
ad9371_spiSettings_t *mpm_spi = ad9371_spiSettings_t::make(spiSettings);
|
|
auto current_time = std::chrono::steady_clock::now();
|
|
if ((std::chrono::steady_clock::now() - mpm_spi->timeout_start) > mpm_spi->timeout_duration)
|
|
{
|
|
return COMMONERR_FAILED;
|
|
}
|
|
else {
|
|
return COMMONERR_OK;
|
|
}
|
|
}
|
|
|
|
// platform logging functions
|
|
commonErr_t CMB_openLog(const char *filename)
|
|
{
|
|
// not implemented
|
|
return COMMONERR_FAILED;
|
|
}
|
|
commonErr_t CMB_closeLog(void)
|
|
{
|
|
// not implemented
|
|
return COMMONERR_FAILED;
|
|
}
|
|
|
|
commonErr_t CMB_writeToLog(
|
|
ADI_LOGLEVEL level,
|
|
uint8_t deviceIndex,
|
|
uint32_t errorCode,
|
|
const char *comment
|
|
) {
|
|
mpm::types::log_level_t mpm_log_level;
|
|
if (level & ADIHAL_LOG_ERROR) {
|
|
mpm_log_level = mpm::types::log_level_t::ERROR;
|
|
}
|
|
else if (level & ADIHAL_LOG_WARNING) {
|
|
mpm_log_level = mpm::types::log_level_t::WARNING;
|
|
}
|
|
else {
|
|
mpm_log_level = mpm::types::log_level_t::TRACE;
|
|
}
|
|
|
|
mpm::types::log_buf::make_singleton()->post(
|
|
mpm_log_level,
|
|
"AD937X",
|
|
str(boost::format("[Device ID %d] [Error code: %d] %s")
|
|
% int(deviceIndex) % errorCode % comment)
|
|
);
|
|
|
|
return COMMONERR_OK;
|
|
}
|
|
commonErr_t CMB_flushLog(void)
|
|
{
|
|
// not implemented
|
|
return COMMONERR_FAILED;
|
|
}
|
|
|
|
/* platform FPGA AXI register read/write functions */
|
|
commonErr_t CMB_regRead(uint32_t offset, uint32_t *data)
|
|
{
|
|
// not implemented
|
|
return COMMONERR_FAILED;
|
|
}
|
|
commonErr_t CMB_regWrite(uint32_t offset, uint32_t data)
|
|
{
|
|
// not implemented
|
|
return COMMONERR_FAILED;
|
|
}
|
|
|
|
/* platform DDR3 memory read/write functions */
|
|
commonErr_t CMB_memRead(uint32_t offset, uint32_t *data, uint32_t len)
|
|
{
|
|
// not implemented
|
|
return COMMONERR_FAILED;
|
|
}
|
|
commonErr_t CMB_memWrite(uint32_t offset, uint32_t *data, uint32_t len)
|
|
{
|
|
// not implemented
|
|
return COMMONERR_FAILED;
|
|
}
|