mirror of
https://github.com/EttusResearch/uhd.git
synced 2026-10-25 17:36:10 +00:00
mpm: Fixed a plethora of SPI-related issues
This commit is contained in:
parent
0cdf67ad33
commit
36365930a6
@ -31,11 +31,13 @@ lmk04828_iface::lmk04828_iface(write_fn_t write_fn, read_fn_t read_fn) : _write_
|
||||
void lmk04828_iface::verify_chip_id()
|
||||
{
|
||||
// Check ID Device Type, ID Prod, and ID Maskrev registers
|
||||
uint8_t id_device_type = _read_fn(3);
|
||||
uint8_t id_device_type = get_chip_id();
|
||||
|
||||
std::cout << "LMK device ID: " << int(id_device_type) << std::endl;
|
||||
|
||||
// assert(id_device_type == 6);
|
||||
if (id_device_type != 6){
|
||||
printf("id_device_type is not 6!");
|
||||
std::cout << "id_device_type is not 6!" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,15 +50,15 @@ void lmk04828_iface::init()
|
||||
{
|
||||
// Configure the LMK to start producing clocks
|
||||
// TODO: Convert to use ic_reg_map fields once values are finalized/working
|
||||
std::vector<uint32_t> write_addrs = {
|
||||
std::vector<uint16_t> write_addrs = {
|
||||
0x000000,0x000000,0x000002,0x000149,0x00014A,0x000100,0x000101,0x000103,0x000104,0x000105,0x000106,0x000107,0x000120,0x000121,0x000123,0x000124,0x000125,0x000126,0x000127,0x000130,0x000131,0x000133,0x000134,0x000135,0x000136,0x000137,0x000128,0x000129,0x00012B,0x00012C,0x00012D,0x00012E,0x00012F,0x000108,0x000109,0x00010B,0x00010C,0x00010D,0x00010E,0x00010F,0x000118,0x000119,0x00011B,0x00011C,0x00011D,0x00011E,0x00011F,0x000138,0x00013F,0x000140,0x000144,0x000146,0x000147,0x00014B,0x00014C,0x000153,0x000154,0x000155,0x000156,0x000157,0x000158,0x000159,0x00015A,0x00015B,0x00015E,0x000160,0x000161,0x000162,0x000163,0x000164,0x000165,0x000166,0x000167,0x000168,0x00016E,0x000173,0x000169,0x00016C,0x00016D};
|
||||
|
||||
std::vector<uint32_t> write_data = {
|
||||
std::vector<uint8_t> write_data = {
|
||||
0x000090,0x000010,0x000000,0x000040,0x000033,0x000078,0x000055,0x000000,0x000020,0x000000,0x0000F1,0x000055,0x000078,0x000055,0x000000,0x000020,0x000000,0x0000F1,0x000055,0x000078,0x000055,0x000000,0x000020,0x000000,0x0000F1,0x000005,0x000078,0x000055,0x000000,0x000000,0x000000,0x0000F0,0x000050,0x00007E,0x000055,0x000000,0x000000,0x000000,0x0000F0,0x000055,0x000078,0x000055,0x000000,0x000020,0x000000,0x0000F1,0x000000,0x000030,0x000009,0x000000,0x000000,0x000010,0x00001A,0x00000D,0x0000F6,0x000000,0x000001,0x000000,0x00000A,0x000000,0x000001,0x000000,0x00007D,0x0000DB,0x000000,0x000000,0x000004,0x0000A0,0x000000,0x000000,0x000019,0x000000,0x000000,0x000019,0x00006B,0x000000,0x000051,0x000000,0x000000};
|
||||
|
||||
std::vector<uint32_t> writes {};
|
||||
for (size_t index = 0; index < write_addrs.size(); index++) {
|
||||
writes.push_back((write_addrs[index] << 11) | write_data[index]);
|
||||
writes.push_back((write_addrs[index] << 8) | write_data[index]);
|
||||
}
|
||||
|
||||
std::cout << "LMK Initialization writes" << std::endl;
|
||||
@ -66,12 +68,14 @@ void lmk04828_iface::init()
|
||||
std::cout << std::endl;
|
||||
|
||||
_write_fn(writes);
|
||||
|
||||
verify_chip_id();
|
||||
}
|
||||
|
||||
void lmk04828_iface::send_sysref_pulse()
|
||||
void lmk04828_iface::enable_sysref_pulse()
|
||||
{
|
||||
// Configure the LMK to issue a single SysRef pulse each time SYNC is asserted
|
||||
|
||||
|
||||
// TODO: Convert to use ic reg map fields once functional
|
||||
// Addr 0x139 Value 0x2
|
||||
// Addr 0x144 Value 0xFF
|
||||
|
||||
@ -46,12 +46,16 @@ public:
|
||||
|
||||
void init();
|
||||
|
||||
void send_sysref_pulse();
|
||||
/*! Enable SYSREF pulses
|
||||
*
|
||||
* After calling this, triggering the sync pin will emit a SYSREF pulse.
|
||||
*/
|
||||
void enable_sysref_pulse();
|
||||
|
||||
private:
|
||||
// use IC Reg Map once values stabilize
|
||||
// lmk04828_regs_t _regs;
|
||||
|
||||
|
||||
write_fn_t _write_fn;
|
||||
read_fn_t _read_fn;
|
||||
};
|
||||
|
||||
@ -177,7 +177,7 @@ void export_mykonos(){
|
||||
.def("get_multichip_sync_status", &ad937x_ctrl::get_multichip_sync_status)
|
||||
.def("get_framer_status", &ad937x_ctrl::get_framer_status)
|
||||
.def("get_deframer_status", &ad937x_ctrl::get_deframer_status)
|
||||
.def("get_deframer_irq", &ad937x_ctrl::get_deframer_irq)
|
||||
//.def("get_deframer_irq", &ad937x_ctrl::get_deframer_irq)
|
||||
.def("get_ilas_config_match", &ad937x_ctrl::get_ilas_config_match)
|
||||
.def("enable_jesd_loopback", &ad937x_ctrl::enable_jesd_loopback)
|
||||
.def("get_rf_freq_range", &ad937x_ctrl::get_rf_freq_range)
|
||||
|
||||
@ -27,12 +27,12 @@ struct ad9371_spiSettings_t
|
||||
return reinterpret_cast<ad9371_spiSettings_t *>(sps);
|
||||
}
|
||||
|
||||
explicit ad9371_spiSettings_t(uhd::spi_iface::sptr uhd_iface);
|
||||
explicit ad9371_spiSettings_t(uhd::spi_iface* uhd_iface);
|
||||
|
||||
// spiSetting_t MUST be the first data member so that the
|
||||
// reintrepret_cast in make() works
|
||||
// reinterpret_cast in make() works
|
||||
spiSettings_t spi_settings;
|
||||
uhd::spi_iface::sptr spi_iface;
|
||||
uhd::spi_iface* spi_iface;
|
||||
std::chrono::time_point<std::chrono::steady_clock> timeout_start;
|
||||
std::chrono::microseconds timeout_duration;
|
||||
};
|
||||
|
||||
@ -35,7 +35,7 @@ void export_lmk(){
|
||||
.def("verify_chip_id", &lmk04828_iface::verify_chip_id)
|
||||
.def("get_chip_id", &lmk04828_iface::get_chip_id)
|
||||
.def("init", &lmk04828_iface::init)
|
||||
.def("send_sysref_pulse", &lmk04828_iface::send_sysref_pulse)
|
||||
.def("enable_sysref_pulse", &lmk04828_iface::enable_sysref_pulse)
|
||||
;
|
||||
}
|
||||
// .def("make", &lmk04828_iface::make)
|
||||
|
||||
@ -30,7 +30,7 @@ uint8_t lmk04828_spi_iface::spi_read(uint32_t addr) {
|
||||
// r/w[23] 0[22:21] addr[20:8] data[7:0] = 24 bits
|
||||
uint32_t transaction = 0;
|
||||
transaction |= LMK_SPI_READ_FLAG << LMK_SPI_READ_FLAG_OFFSET;
|
||||
transaction &= LMK_SPI_RESERVED_FIELD_MASK;
|
||||
//transaction &= LMK_SPI_RESERVED_FIELD_MASK;
|
||||
transaction |= addr << LMK_SPI_READ_ADDR_OFFSET;
|
||||
|
||||
uint32_t data = _spi_iface->read_spi(DEFAULT_SLAVE, config, transaction, LMK_SPI_NUM_BITS);
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
#include <sstream>
|
||||
#include <set>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
|
||||
using namespace mpm::ad937x::device;
|
||||
|
||||
@ -123,9 +124,10 @@ public:
|
||||
uhd::spi_iface::sptr iface,
|
||||
mpm::ad937x::gpio::gain_pins_t gain_pins) :
|
||||
spi_mutex(spi_mutex),
|
||||
device(iface, gain_pins)
|
||||
device(iface.get(), gain_pins),
|
||||
_iface(iface)
|
||||
{
|
||||
|
||||
/* nop */
|
||||
}
|
||||
|
||||
virtual void begin_initialization()
|
||||
@ -379,6 +381,7 @@ public:
|
||||
private:
|
||||
ad937x_device device;
|
||||
std::shared_ptr<std::mutex> spi_mutex;
|
||||
uhd::spi_iface::sptr _iface;
|
||||
};
|
||||
|
||||
ad937x_ctrl::sptr ad937x_ctrl::make(std::shared_ptr<std::mutex> spi_mutex, uhd::spi_iface::sptr iface, mpm::ad937x::gpio::gain_pins_t gain_pins)
|
||||
|
||||
@ -20,6 +20,8 @@
|
||||
#include "adi/mykonos_gpio.h"
|
||||
#include "adi/mykonos_debug/mykonos_dbgjesd.h"
|
||||
|
||||
#include <boost/format.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
|
||||
@ -112,16 +114,16 @@ void ad937x_device::_call_gpio_api_function(std::function<mykonosGpioErr_t()> fu
|
||||
}
|
||||
}
|
||||
|
||||
void ad937x_device::_call_debug_api_function(std::function<mykonosDbgErr_t()> func)
|
||||
{
|
||||
auto error = func();
|
||||
if (error != MYKONOS_ERR_DBG_OK)
|
||||
{
|
||||
std::cout << getDbgJesdMykonosErrorMessage(error);
|
||||
// TODO: make UHD exception
|
||||
//throw std::exception(getMykonosErrorMessage(error));
|
||||
}
|
||||
}
|
||||
//void ad937x_device::_call_debug_api_function(std::function<mykonosDbgErr_t()> func)
|
||||
//{
|
||||
//auto error = func();
|
||||
//if (error != MYKONOS_ERR_DBG_OK)
|
||||
//{
|
||||
//std::cout << getDbgJesdMykonosErrorMessage(error);
|
||||
//// TODO: make UHD exception
|
||||
////throw std::exception(getMykonosErrorMessage(error));
|
||||
//}
|
||||
//}
|
||||
|
||||
// TODO: delete this comment closer to release
|
||||
/*
|
||||
@ -193,14 +195,17 @@ void ad937x_device::begin_initialization()
|
||||
{
|
||||
// TODO: make this reset actually do something (implement CMB_HardReset or replace)
|
||||
_call_api_function(std::bind(MYKONOS_resetDevice, mykonos_config.device));
|
||||
|
||||
if (get_product_id() != AD9371_PRODUCT_ID)
|
||||
{
|
||||
throw runtime_error("AD9371 product ID does not match expected ID!");
|
||||
}
|
||||
|
||||
_call_api_function(std::bind(MYKONOS_initialize, mykonos_config.device));
|
||||
|
||||
uint8_t product_id = get_product_id();
|
||||
if (product_id != AD9371_PRODUCT_ID)
|
||||
{
|
||||
throw runtime_error(str(
|
||||
boost::format("AD9371 product ID does not match expected ID! Read: %X Expected: %X")
|
||||
% int(product_id) % int(AD9371_PRODUCT_ID)
|
||||
));
|
||||
}
|
||||
|
||||
if (!get_pll_lock_status(pll_t::CLK_SYNTH))
|
||||
{
|
||||
throw runtime_error("AD937x CLK_SYNTH PLL failed to lock in initialize()");
|
||||
@ -267,7 +272,7 @@ uint8_t ad937x_device::get_deframer_status()
|
||||
uint8_t ad937x_device::get_deframer_irq()
|
||||
{
|
||||
uint8_t irq_status = 0;
|
||||
_call_debug_api_function(std::bind(MYKONOS_deframerGetIrq, mykonos_config.device, &irq_status));
|
||||
//_call_debug_api_function(std::bind(MYKONOS_deframerGetIrq, mykonos_config.device, &irq_status));
|
||||
return irq_status;
|
||||
}
|
||||
|
||||
@ -284,11 +289,17 @@ void ad937x_device::enable_jesd_loopback(uint8_t enable)
|
||||
_call_api_function(std::bind(MYKONOS_setRxFramerDataSource, mykonos_config.device, enable));
|
||||
}
|
||||
|
||||
ad937x_device::ad937x_device(spi_iface::sptr iface, gain_pins_t gain_pins) :
|
||||
ad937x_device::ad937x_device(spi_iface* iface, gain_pins_t gain_pins) :
|
||||
full_spi_settings(iface),
|
||||
mykonos_config(&full_spi_settings.spi_settings),
|
||||
gain_ctrl(gain_pins)
|
||||
{
|
||||
std::cout << "full spi settings addr " << &full_spi_settings << std::endl;
|
||||
iface->read_spi(0, uhd::spi_config_t::EDGE_RISE, 400, 24);
|
||||
std::cout << "adi spi settings addr " << &(full_spi_settings.spi_settings) << std::endl;
|
||||
std::cout << "iface addr " << std::hex << iface << std::dec << std::endl;
|
||||
|
||||
std::cout << "myk dev addr " << std::hex << mykonos_config.device->spiSettings << std::dec << std::endl;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -39,7 +39,7 @@ public:
|
||||
enum class gain_mode_t { MANUAL, AUTOMATIC, HYBRID };
|
||||
enum class pll_t {CLK_SYNTH, RX_SYNTH, TX_SYNTH, SNIFF_SYNTH, CALPLL_SDM};
|
||||
|
||||
ad937x_device(uhd::spi_iface::sptr iface, mpm::ad937x::gpio::gain_pins_t gain_pins);
|
||||
ad937x_device(uhd::spi_iface* iface, mpm::ad937x::gpio::gain_pins_t gain_pins);
|
||||
|
||||
void begin_initialization();
|
||||
void finish_initialization();
|
||||
@ -96,7 +96,7 @@ private:
|
||||
|
||||
void _call_api_function(std::function<mykonosErr_t()> func);
|
||||
void _call_gpio_api_function(std::function<mykonosGpioErr_t()> func);
|
||||
void _call_debug_api_function(std::function<mykonosDbgErr_t()> func);
|
||||
//void _call_debug_api_function(std::function<mykonosDbgErr_t()> func);
|
||||
|
||||
static uint8_t _convert_rx_gain(double gain);
|
||||
static uint16_t _convert_tx_gain(double gain);
|
||||
|
||||
@ -24,7 +24,9 @@
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
ad9371_spiSettings_t::ad9371_spiSettings_t(uhd::spi_iface::sptr uhd_iface) :
|
||||
static const uint32_t MYKONOS_READ_BIT = (1 << 23);
|
||||
|
||||
ad9371_spiSettings_t::ad9371_spiSettings_t(uhd::spi_iface* uhd_iface) :
|
||||
spi_iface(uhd_iface)
|
||||
{
|
||||
spi_settings.chipSelectIndex = 0; // set later
|
||||
@ -98,7 +100,7 @@ commonErr_t CMB_SPIWriteByte(spiSettings_t *spiSettings, uint16_t addr, uint8_t
|
||||
mpm_spi->spi_iface->write_spi(spiSettings->chipSelectIndex, config, data_word, 24);
|
||||
return COMMONERR_OK;
|
||||
} catch (const std::exception &e) {
|
||||
// ... error handling ...
|
||||
std::cout << "AAAAAAAAAAAAH" << std::endl;
|
||||
}
|
||||
return COMMONERR_FAILED;
|
||||
}
|
||||
@ -124,7 +126,7 @@ commonErr_t CMB_SPIWriteBytes(spiSettings_t *spiSettings, uint16_t *addr, uint8_
|
||||
}
|
||||
return COMMONERR_OK;
|
||||
} catch (const std::exception &e) {
|
||||
// ... error handling ...
|
||||
std::cout << "AAAAAAAAAAAAH" << std::endl;
|
||||
}
|
||||
return COMMONERR_FAILED;
|
||||
}
|
||||
@ -141,13 +143,14 @@ commonErr_t CMB_SPIReadByte (spiSettings_t *spiSettings, uint16_t addr, uint8_t
|
||||
|
||||
ad9371_spiSettings_t *mpm_spi = ad9371_spiSettings_t::make(spiSettings);
|
||||
uhd::spi_config_t config(_get_edge(*spiSettings));
|
||||
uint32_t data_word = (0) | (addr << 8);
|
||||
uint32_t read_word = MYKONOS_READ_BIT | (addr << 8);
|
||||
|
||||
try {
|
||||
*readdata = static_cast<uint8_t>(
|
||||
mpm_spi->spi_iface->read_spi(spiSettings->chipSelectIndex, config, data_word, 24));
|
||||
mpm_spi->spi_iface->read_spi(spiSettings->chipSelectIndex, config, read_word, 24));
|
||||
return COMMONERR_OK;
|
||||
} catch (const std::exception &e) {
|
||||
std::cout << "AAAAAAAAAAAAH READ" << std::endl;
|
||||
// ... error handling ...
|
||||
}
|
||||
return COMMONERR_FAILED;
|
||||
@ -170,6 +173,7 @@ commonErr_t CMB_SPIWriteField(
|
||||
mpm_spi->spi_iface->write_spi(spiSettings->chipSelectIndex, config, write_word, 24);
|
||||
return COMMONERR_OK;
|
||||
} catch (const std::exception &e) {
|
||||
std::cout << "AAAAAAAAAAAAH WRITE FIELD" << std::endl;
|
||||
// ... error handling ...
|
||||
}
|
||||
return COMMONERR_FAILED;
|
||||
@ -184,13 +188,14 @@ commonErr_t CMB_SPIReadField(
|
||||
) {
|
||||
ad9371_spiSettings_t *mpm_spi = ad9371_spiSettings_t::make(spiSettings);
|
||||
uhd::spi_config_t config(_get_edge(*spiSettings));
|
||||
uint32_t read_word = (0) | (addr << 8);
|
||||
uint32_t read_word = MYKONOS_READ_BIT | (addr << 8);
|
||||
|
||||
try {
|
||||
uint32_t value = mpm_spi->spi_iface->read_spi(spiSettings->chipSelectIndex, config, read_word, 24);
|
||||
*field_val = static_cast<uint8_t>((value & mask) >> start_bit);
|
||||
return COMMONERR_OK;
|
||||
} catch (const std::exception &e) {
|
||||
std::cout << "AAAAAAAAAAAAH READ FIELD" << std::endl;
|
||||
/* ... error handling ... */
|
||||
}
|
||||
return COMMONERR_FAILED;
|
||||
@ -250,7 +255,7 @@ commonErr_t CMB_closeLog(void)
|
||||
|
||||
commonErr_t CMB_writeToLog(ADI_LOGLEVEL level, uint8_t deviceIndex, uint32_t errorCode, const char *comment)
|
||||
{
|
||||
std::cout << level << " " << errorCode << " " << comment << std::endl;
|
||||
std::cout << "[CMB_writeToLog] level==" << level << " errorCode==" << errorCode << " " << comment << std::endl;
|
||||
return COMMONERR_OK;
|
||||
}
|
||||
commonErr_t CMB_flushLog(void)
|
||||
|
||||
@ -24,6 +24,8 @@ ad937x_config_t::ad937x_config_t(spiSettings_t* sps)
|
||||
|
||||
_assign_default_configuration();
|
||||
_init_pointers();
|
||||
|
||||
device = &_device;
|
||||
}
|
||||
|
||||
void ad937x_config_t::_assign_default_configuration()
|
||||
@ -70,7 +72,6 @@ void ad937x_config_t::_assign_default_configuration()
|
||||
|
||||
void ad937x_config_t::_init_pointers()
|
||||
{
|
||||
_device.spiSettings = &_spiSettings;
|
||||
_device.rx = &_rx;
|
||||
_device.tx = &_tx;
|
||||
_device.obsRx = &_obsRx;
|
||||
|
||||
@ -28,7 +28,8 @@ class ad937x_config_t : public boost::noncopyable
|
||||
// a user could technically modify the pointers in the structs, but we have no way of preventing that
|
||||
public:
|
||||
ad937x_config_t(spiSettings_t* sps);
|
||||
mykonosDevice_t * const device = &_device;
|
||||
//mykonosDevice_t * const device = &_device;
|
||||
mykonosDevice_t * device;
|
||||
|
||||
ad937x_fir rx_fir_config;
|
||||
ad937x_fir tx_fir_config;
|
||||
@ -40,7 +41,6 @@ private:
|
||||
|
||||
// in general, this organization stinks
|
||||
// TODO: group and make more sense of these fields and pointers
|
||||
spiSettings_t _spiSettings;
|
||||
mykonosRxSettings_t _rx;
|
||||
mykonosTxSettings_t _tx;
|
||||
mykonosObsRxSettings_t _obsRx;
|
||||
|
||||
@ -23,6 +23,8 @@
|
||||
#include <linux/spi/spidev.h>
|
||||
#include <boost/format.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace mpm::spi;
|
||||
|
||||
/******************************************************************************
|
||||
@ -45,34 +47,53 @@ public:
|
||||
));
|
||||
}
|
||||
|
||||
ret = ioctl(_fd, SPI_IOC_WR_MODE32, &_mode);
|
||||
int MODE = 3;
|
||||
ret = ioctl(_fd, SPI_IOC_WR_MODE32, &MODE);
|
||||
if (ret == -1) {
|
||||
throw std::runtime_error("Could not set spidev mode");
|
||||
throw std::runtime_error(str(
|
||||
boost::format("Could not set spidev mode to %X for spidev %s")
|
||||
% uint16_t(_mode) % device
|
||||
));
|
||||
}
|
||||
|
||||
ret = ioctl(_fd, SPI_IOC_RD_MODE32, &_mode);
|
||||
if (ret == -1) {
|
||||
throw std::runtime_error("Could not get spidev mode");
|
||||
throw std::runtime_error(str(
|
||||
boost::format("Could not get spidev mode for spidev %s")
|
||||
% device
|
||||
));
|
||||
}
|
||||
|
||||
ret = ioctl(_fd, SPI_IOC_WR_BITS_PER_WORD, &_bits);
|
||||
if (ret == -1) {
|
||||
throw std::runtime_error("Could not set spidev bits per word");
|
||||
throw std::runtime_error(str(
|
||||
boost::format("Could not set spidev bits per word to %d for spidev %s")
|
||||
% uint16_t(_bits) % device
|
||||
));
|
||||
}
|
||||
|
||||
ret = ioctl(_fd, SPI_IOC_RD_BITS_PER_WORD, &_bits);
|
||||
if (ret == -1) {
|
||||
throw std::runtime_error("Could not get spidev bits per word");
|
||||
throw std::runtime_error(str(
|
||||
boost::format("Could not get spidev bits per word for spidev %s")
|
||||
% device
|
||||
));
|
||||
}
|
||||
|
||||
ret = ioctl(_fd, SPI_IOC_WR_MAX_SPEED_HZ, &_speed);
|
||||
if (ret == -1) {
|
||||
throw std::runtime_error("Could not set spidev max speed");
|
||||
throw std::runtime_error(str(
|
||||
boost::format("Could not set spidev max speed to %d for spidev %s")
|
||||
% _speed % device
|
||||
));
|
||||
}
|
||||
|
||||
ret = ioctl(_fd, SPI_IOC_RD_MAX_SPEED_HZ, &_speed);
|
||||
if (ret == -1) {
|
||||
throw std::runtime_error("Could not get spidev max speed");
|
||||
throw std::runtime_error(str(
|
||||
boost::format("Could not get spidev max speed for spidev %s")
|
||||
% device
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@ -138,7 +159,7 @@ public:
|
||||
|
||||
private:
|
||||
int _fd;
|
||||
uint8_t _mode = SPI_CPHA | SPI_CPOL;
|
||||
uint32_t _mode = SPI_CPHA | SPI_CPOL;
|
||||
uint32_t _speed = 2000000;
|
||||
uint8_t _bits = 8;
|
||||
uint16_t _delay = 0;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user