10 changed files with 1151 additions and 2 deletions
@ -0,0 +1,88 @@ |
|||||||
|
/****************************************************************************
|
||||||
|
* |
||||||
|
* Copyright (C) 2020 PX4 Development Team. All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions |
||||||
|
* are met: |
||||||
|
* |
||||||
|
* 1. Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* 2. 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. |
||||||
|
* 3. Neither the name PX4 nor the names of its contributors may be |
||||||
|
* used to endorse or promote products derived from this software |
||||||
|
* without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
||||||
|
* BUT NOT LIMITED TO, 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 <board_config.h> |
||||||
|
#ifndef BOARD_DISABLE_I2C_SPI |
||||||
|
|
||||||
|
#include <px4_platform_common/i2c.h> |
||||||
|
|
||||||
|
#ifndef BOARD_OVERRIDE_I2C_BUS_EXTERNAL |
||||||
|
bool px4_i2c_bus_external(const px4_i2c_bus_t &bus) |
||||||
|
{ |
||||||
|
return bus.is_external; |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
bool I2CBusIterator::next() |
||||||
|
{ |
||||||
|
while (++_index < I2C_BUS_MAX_BUS_ITEMS && px4_i2c_buses[_index].bus != -1) { |
||||||
|
const px4_i2c_bus_t &bus_data = px4_i2c_buses[_index]; |
||||||
|
|
||||||
|
if (!board_has_bus(BOARD_I2C_BUS, bus_data.bus)) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
switch (_filter) { |
||||||
|
case FilterType::All: |
||||||
|
if (_bus == bus_data.bus || _bus == -1) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
break; |
||||||
|
|
||||||
|
case FilterType::InternalBus: |
||||||
|
if (!px4_i2c_bus_external(bus_data)) { |
||||||
|
if (_bus == bus_data.bus || _bus == -1) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
break; |
||||||
|
|
||||||
|
case FilterType::ExternalBus: |
||||||
|
if (px4_i2c_bus_external(bus_data)) { |
||||||
|
++_external_bus_counter; |
||||||
|
|
||||||
|
if (_bus == _external_bus_counter || _bus == -1) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
#endif /* BOARD_DISABLE_I2C_SPI */ |
@ -0,0 +1,393 @@ |
|||||||
|
/****************************************************************************
|
||||||
|
* |
||||||
|
* Copyright (C) 2020 PX4 Development Team. All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions |
||||||
|
* are met: |
||||||
|
* |
||||||
|
* 1. Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* 2. 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. |
||||||
|
* 3. Neither the name PX4 nor the names of its contributors may be |
||||||
|
* used to endorse or promote products derived from this software |
||||||
|
* without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
||||||
|
* BUT NOT LIMITED TO, 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 <board_config.h> |
||||||
|
#ifndef BOARD_DISABLE_I2C_SPI |
||||||
|
|
||||||
|
#ifndef MODULE_NAME |
||||||
|
#define MODULE_NAME "SPI_I2C" |
||||||
|
#endif |
||||||
|
|
||||||
|
#include <lib/drivers/device/Device.hpp> |
||||||
|
#include <px4_platform_common/i2c_spi_buses.h> |
||||||
|
#include <px4_platform_common/log.h> |
||||||
|
|
||||||
|
BusInstanceIterator::BusInstanceIterator(I2CSPIInstance **instances, int max_num_instances, |
||||||
|
const BusCLIArguments &cli_arguments, uint16_t devid_driver_index) |
||||||
|
: _instances(instances), _max_num_instances(max_num_instances), |
||||||
|
_bus_option(cli_arguments.bus_option), |
||||||
|
_spi_bus_iterator(spiFilter(cli_arguments.bus_option), |
||||||
|
cli_arguments.bus_option == I2CSPIBusOption::SPIExternal ? cli_arguments.chipselect_index : devid_driver_index, |
||||||
|
cli_arguments.requested_bus), |
||||||
|
_i2c_bus_iterator(i2cFilter(cli_arguments.bus_option), cli_arguments.requested_bus) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
bool BusInstanceIterator::next() |
||||||
|
{ |
||||||
|
int bus = -1; |
||||||
|
|
||||||
|
if (busType() == BOARD_INVALID_BUS) { |
||||||
|
while (++_current_instance < _max_num_instances && _instances[_current_instance] == nullptr) {} |
||||||
|
|
||||||
|
return _current_instance < _max_num_instances; |
||||||
|
|
||||||
|
} else if (busType() == BOARD_SPI_BUS) { |
||||||
|
if (_spi_bus_iterator.next()) { |
||||||
|
bus = _spi_bus_iterator.bus().bus; |
||||||
|
} |
||||||
|
|
||||||
|
} else { |
||||||
|
if (_i2c_bus_iterator.next()) { |
||||||
|
bus = _i2c_bus_iterator.bus().bus; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (bus != -1) { |
||||||
|
// find matching runtime instance
|
||||||
|
_current_instance = -1; |
||||||
|
|
||||||
|
for (int i = 0; i < _max_num_instances; ++i) { |
||||||
|
if (!_instances[i]) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
if (_bus_option == _instances[i]->_bus_option && bus == _instances[i]->_bus) { |
||||||
|
_current_instance = i; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
int BusInstanceIterator::nextFreeInstance() const |
||||||
|
{ |
||||||
|
for (int i = 0; i < _max_num_instances; ++i) { |
||||||
|
if (_instances[i] == nullptr) { |
||||||
|
return i; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
I2CSPIInstance *BusInstanceIterator::instance() const |
||||||
|
{ |
||||||
|
if (_current_instance < 0 || _current_instance >= _max_num_instances) { |
||||||
|
return nullptr; |
||||||
|
} |
||||||
|
|
||||||
|
return _instances[_current_instance]; |
||||||
|
} |
||||||
|
|
||||||
|
void BusInstanceIterator::resetInstance() |
||||||
|
{ |
||||||
|
if (_current_instance >= 0 && _current_instance < _max_num_instances) { |
||||||
|
_instances[_current_instance] = nullptr; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
board_bus_types BusInstanceIterator::busType() const |
||||||
|
{ |
||||||
|
switch (_bus_option) { |
||||||
|
case I2CSPIBusOption::All: |
||||||
|
return BOARD_INVALID_BUS; |
||||||
|
|
||||||
|
case I2CSPIBusOption::I2CInternal: |
||||||
|
case I2CSPIBusOption::I2CExternal: |
||||||
|
return BOARD_I2C_BUS; |
||||||
|
|
||||||
|
case I2CSPIBusOption::SPIInternal: |
||||||
|
case I2CSPIBusOption::SPIExternal: |
||||||
|
return BOARD_SPI_BUS; |
||||||
|
} |
||||||
|
|
||||||
|
return BOARD_INVALID_BUS; |
||||||
|
} |
||||||
|
|
||||||
|
int BusInstanceIterator::bus() const |
||||||
|
{ |
||||||
|
if (busType() == BOARD_INVALID_BUS) { |
||||||
|
return -1; |
||||||
|
|
||||||
|
} else if (busType() == BOARD_SPI_BUS) { |
||||||
|
return _spi_bus_iterator.bus().bus; |
||||||
|
|
||||||
|
} else { |
||||||
|
return _i2c_bus_iterator.bus().bus; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
uint32_t BusInstanceIterator::devid() const |
||||||
|
{ |
||||||
|
if (busType() == BOARD_INVALID_BUS) { |
||||||
|
return 0; |
||||||
|
|
||||||
|
} else if (busType() == BOARD_SPI_BUS) { |
||||||
|
return _spi_bus_iterator.devid(); |
||||||
|
|
||||||
|
} else { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
uint32_t BusInstanceIterator::DRDYGPIO() const |
||||||
|
{ |
||||||
|
if (busType() == BOARD_INVALID_BUS) { |
||||||
|
return 0; |
||||||
|
|
||||||
|
} else if (busType() == BOARD_SPI_BUS) { |
||||||
|
return _spi_bus_iterator.DRDYGPIO(); |
||||||
|
|
||||||
|
} else { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
bool BusInstanceIterator::external() const |
||||||
|
{ |
||||||
|
if (busType() == BOARD_INVALID_BUS) { |
||||||
|
return false; |
||||||
|
|
||||||
|
} else if (busType() == BOARD_SPI_BUS) { |
||||||
|
return _spi_bus_iterator.external(); |
||||||
|
|
||||||
|
} else { |
||||||
|
return _i2c_bus_iterator.external(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
I2CBusIterator::FilterType BusInstanceIterator::i2cFilter(I2CSPIBusOption bus_option) |
||||||
|
{ |
||||||
|
switch (bus_option) { |
||||||
|
case I2CSPIBusOption::All: return I2CBusIterator::FilterType::All; |
||||||
|
|
||||||
|
case I2CSPIBusOption::I2CExternal: return I2CBusIterator::FilterType::ExternalBus; |
||||||
|
|
||||||
|
case I2CSPIBusOption::I2CInternal: return I2CBusIterator::FilterType::InternalBus; |
||||||
|
|
||||||
|
default: break; |
||||||
|
} |
||||||
|
|
||||||
|
return I2CBusIterator::FilterType::All; |
||||||
|
} |
||||||
|
|
||||||
|
SPIBusIterator::FilterType BusInstanceIterator::spiFilter(I2CSPIBusOption bus_option) |
||||||
|
{ |
||||||
|
switch (bus_option) { |
||||||
|
case I2CSPIBusOption::SPIExternal: return SPIBusIterator::FilterType::ExternalBus; |
||||||
|
|
||||||
|
case I2CSPIBusOption::SPIInternal: return SPIBusIterator::FilterType::InternalBus; |
||||||
|
|
||||||
|
default: break; |
||||||
|
} |
||||||
|
|
||||||
|
return SPIBusIterator::FilterType::InternalBus; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
int I2CSPIDriverBase::module_start(const BusCLIArguments &cli, BusInstanceIterator &iterator, |
||||||
|
void(*print_usage)(), |
||||||
|
instantiate_method instantiate, I2CSPIInstance **instances) |
||||||
|
{ |
||||||
|
if (iterator.configuredBusOption() == I2CSPIBusOption::All) { |
||||||
|
PX4_ERR("need to specify a bus type"); |
||||||
|
print_usage(); |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
bool started = false; |
||||||
|
|
||||||
|
while (iterator.next()) { |
||||||
|
if (iterator.instance()) { |
||||||
|
continue; // already running
|
||||||
|
} |
||||||
|
|
||||||
|
const int free_index = iterator.nextFreeInstance(); |
||||||
|
|
||||||
|
if (free_index < 0) { |
||||||
|
PX4_ERR("Not enough instances"); |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
device::Device::DeviceId device_id{}; |
||||||
|
device_id.devid_s.bus = iterator.bus(); |
||||||
|
|
||||||
|
switch (iterator.busType()) { |
||||||
|
case BOARD_I2C_BUS: device_id.devid_s.bus_type = device::Device::DeviceBusType_I2C; break; |
||||||
|
|
||||||
|
case BOARD_SPI_BUS: device_id.devid_s.bus_type = device::Device::DeviceBusType_SPI; break; |
||||||
|
|
||||||
|
case BOARD_INVALID_BUS: device_id.devid_s.bus_type = device::Device::DeviceBusType_UNKNOWN; break; |
||||||
|
} |
||||||
|
|
||||||
|
// initialize the object and bus on the work queue thread - this will also probe for the device
|
||||||
|
I2CSPIDriverInitializer initializer(px4::device_bus_to_wq(device_id.devid), cli, iterator, instantiate, free_index); |
||||||
|
initializer.ScheduleNow(); |
||||||
|
initializer.wait(); |
||||||
|
I2CSPIDriverBase *instance = initializer.instance(); |
||||||
|
|
||||||
|
if (!instance) { |
||||||
|
PX4_DEBUG("instantiate failed (no device on bus %i (devid 0x%x)?)", iterator.bus(), iterator.devid()); |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
instances[free_index] = instance; |
||||||
|
started = true; |
||||||
|
|
||||||
|
// print some info that we are running
|
||||||
|
switch (iterator.busType()) { |
||||||
|
case BOARD_I2C_BUS: |
||||||
|
PX4_INFO_RAW("%s #%i on I2C bus %d%s\n", |
||||||
|
instance->ItemName(), free_index, iterator.bus(), iterator.external() ? " (external)" : ""); |
||||||
|
break; |
||||||
|
|
||||||
|
case BOARD_SPI_BUS: |
||||||
|
PX4_INFO_RAW("%s #%i on SPI bus %d (devid=0x%x)%s\n", |
||||||
|
instance->ItemName(), free_index, iterator.bus(), PX4_SPI_DEV_ID(iterator.devid()), |
||||||
|
iterator.external() ? " (external)" : ""); |
||||||
|
break; |
||||||
|
|
||||||
|
case BOARD_INVALID_BUS: |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return started ? 0 : -1; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
int I2CSPIDriverBase::module_stop(BusInstanceIterator &iterator) |
||||||
|
{ |
||||||
|
bool is_running = false; |
||||||
|
|
||||||
|
while (iterator.next()) { |
||||||
|
if (iterator.instance()) { |
||||||
|
I2CSPIDriverBase *instance = (I2CSPIDriverBase *)iterator.instance(); |
||||||
|
instance->request_stop_and_wait(); |
||||||
|
delete iterator.instance(); |
||||||
|
iterator.resetInstance(); |
||||||
|
is_running = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (!is_running) { |
||||||
|
PX4_ERR("Not running"); |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
int I2CSPIDriverBase::module_status(BusInstanceIterator &iterator) |
||||||
|
{ |
||||||
|
bool is_running = false; |
||||||
|
|
||||||
|
while (iterator.next()) { |
||||||
|
if (iterator.instance()) { |
||||||
|
I2CSPIDriverBase *instance = (I2CSPIDriverBase *)iterator.instance(); |
||||||
|
instance->print_status(); |
||||||
|
is_running = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (!is_running) { |
||||||
|
PX4_INFO("Not running"); |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
int I2CSPIDriverBase::module_custom_method(const BusCLIArguments &cli, BusInstanceIterator &iterator) |
||||||
|
{ |
||||||
|
while (iterator.next()) { |
||||||
|
if (iterator.instance()) { |
||||||
|
I2CSPIDriverBase *instance = (I2CSPIDriverBase *)iterator.instance(); |
||||||
|
instance->custom_method(cli); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
void I2CSPIDriverBase::print_status() |
||||||
|
{ |
||||||
|
bool is_i2c_bus = _bus_option == I2CSPIBusOption::I2CExternal || _bus_option == I2CSPIBusOption::I2CInternal; |
||||||
|
PX4_INFO("Running on %s Bus %i", is_i2c_bus ? "I2C" : "SPI", _bus); |
||||||
|
} |
||||||
|
|
||||||
|
void I2CSPIDriverBase::request_stop_and_wait() |
||||||
|
{ |
||||||
|
_task_should_exit.store(true); |
||||||
|
ScheduleNow(); // wake up the task (in case it is not scheduled anymore or just to be faster)
|
||||||
|
unsigned int i = 0; |
||||||
|
|
||||||
|
do { |
||||||
|
px4_usleep(20000); // 20 ms
|
||||||
|
// wait at most 2 sec
|
||||||
|
} while (++i < 100 && !_task_exited.load()); |
||||||
|
|
||||||
|
if (i >= 100) { |
||||||
|
PX4_ERR("Module did not respond to stop request"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
I2CSPIDriverInitializer::I2CSPIDriverInitializer(const px4::wq_config_t &config, const BusCLIArguments &cli, |
||||||
|
const BusInstanceIterator &iterator, instantiate_method instantiate, int runtime_instance) |
||||||
|
: px4::WorkItem("<driver_init>", config), |
||||||
|
_cli(cli), _iterator(iterator), _runtime_instance(runtime_instance), _instantiate(instantiate) |
||||||
|
{ |
||||||
|
px4_sem_init(&_sem, 0, 0); |
||||||
|
} |
||||||
|
|
||||||
|
I2CSPIDriverInitializer::~I2CSPIDriverInitializer() |
||||||
|
{ |
||||||
|
px4_sem_destroy(&_sem); |
||||||
|
} |
||||||
|
|
||||||
|
void I2CSPIDriverInitializer::wait() |
||||||
|
{ |
||||||
|
while (px4_sem_wait(&_sem) != 0) {} |
||||||
|
} |
||||||
|
|
||||||
|
void I2CSPIDriverInitializer::Run() |
||||||
|
{ |
||||||
|
_instance = _instantiate(_cli, _iterator, _runtime_instance); |
||||||
|
px4_sem_post(&_sem); |
||||||
|
} |
||||||
|
|
||||||
|
#endif /* BOARD_DISABLE_I2C_SPI */ |
@ -0,0 +1,100 @@ |
|||||||
|
/****************************************************************************
|
||||||
|
* |
||||||
|
* Copyright (c) 2020 PX4 Development Team. All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions |
||||||
|
* are met: |
||||||
|
* |
||||||
|
* 1. Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* 2. 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. |
||||||
|
* 3. Neither the name PX4 nor the names of its contributors may be |
||||||
|
* used to endorse or promote products derived from this software |
||||||
|
* without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
||||||
|
* BUT NOT LIMITED TO, 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. |
||||||
|
* |
||||||
|
****************************************************************************/ |
||||||
|
|
||||||
|
#pragma once |
||||||
|
|
||||||
|
#include <board_config.h> |
||||||
|
|
||||||
|
#define I2C_BUS_MAX_BUS_ITEMS PX4_NUMBER_I2C_BUSES |
||||||
|
|
||||||
|
struct px4_i2c_bus_t { |
||||||
|
int bus{-1}; ///< physical bus number (1, ...) (-1 means this is unused)
|
||||||
|
bool is_external; ///< static external configuration. Use px4_i2c_bus_external() to check if a bus is really external
|
||||||
|
}; |
||||||
|
|
||||||
|
__EXPORT extern const px4_i2c_bus_t px4_i2c_buses[I2C_BUS_MAX_BUS_ITEMS]; ///< board-specific I2C bus configuration
|
||||||
|
|
||||||
|
/**
|
||||||
|
* runtime-check if a board has a specific bus as external. |
||||||
|
* This can be overridden by a board to add run-time checks. |
||||||
|
*/ |
||||||
|
__EXPORT bool px4_i2c_bus_external(const px4_i2c_bus_t &bus); |
||||||
|
|
||||||
|
/**
|
||||||
|
* runtime-check if a board has a specific bus as external. |
||||||
|
*/ |
||||||
|
static inline bool px4_i2c_bus_external(int bus) |
||||||
|
{ |
||||||
|
for (int i = 0; i < I2C_BUS_MAX_BUS_ITEMS; ++i) { |
||||||
|
if (px4_i2c_buses[i].bus == bus) { |
||||||
|
return px4_i2c_bus_external(px4_i2c_buses[i]); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class I2CBusIterator |
||||||
|
* Iterate over configured I2C buses by the board |
||||||
|
*/ |
||||||
|
class I2CBusIterator |
||||||
|
{ |
||||||
|
public: |
||||||
|
enum class FilterType { |
||||||
|
All, ///< specific or all buses
|
||||||
|
InternalBus, ///< specific or all internal buses
|
||||||
|
ExternalBus, ///< specific or all external buses
|
||||||
|
}; |
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bus specify bus: starts with 1, -1=all. Internal: arch-specific bus numbering is used, |
||||||
|
* external: n-th external bus |
||||||
|
*/ |
||||||
|
I2CBusIterator(FilterType filter, int bus = -1) |
||||||
|
: _filter(filter), _bus(bus) {} |
||||||
|
|
||||||
|
bool next(); |
||||||
|
|
||||||
|
const px4_i2c_bus_t &bus() const { return px4_i2c_buses[_index]; } |
||||||
|
|
||||||
|
bool external() const { return px4_i2c_bus_external(bus()); } |
||||||
|
|
||||||
|
private: |
||||||
|
const FilterType _filter; |
||||||
|
const int _bus; |
||||||
|
int _index{-1}; |
||||||
|
int _external_bus_counter{0}; |
||||||
|
}; |
||||||
|
|
@ -0,0 +1,229 @@ |
|||||||
|
/****************************************************************************
|
||||||
|
* |
||||||
|
* Copyright (c) 2020 PX4 Development Team. All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions |
||||||
|
* are met: |
||||||
|
* |
||||||
|
* 1. Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* 2. 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. |
||||||
|
* 3. Neither the name PX4 nor the names of its contributors may be |
||||||
|
* used to endorse or promote products derived from this software |
||||||
|
* without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
||||||
|
* BUT NOT LIMITED TO, 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. |
||||||
|
* |
||||||
|
****************************************************************************/ |
||||||
|
|
||||||
|
#pragma once |
||||||
|
|
||||||
|
#include "i2c.h" |
||||||
|
#include "spi.h" |
||||||
|
|
||||||
|
#include <stdint.h> |
||||||
|
|
||||||
|
#include <lib/conversion/rotation.h> |
||||||
|
#include <px4_platform_common/atomic.h> |
||||||
|
#include <px4_platform_common/px4_work_queue/ScheduledWorkItem.hpp> |
||||||
|
#include <px4_platform_common/sem.h> |
||||||
|
#include <board_config.h> |
||||||
|
|
||||||
|
enum class I2CSPIBusOption : uint8_t { |
||||||
|
All = 0, ///< select all runnning instances
|
||||||
|
I2CInternal, |
||||||
|
I2CExternal, |
||||||
|
SPIInternal, |
||||||
|
SPIExternal, |
||||||
|
}; |
||||||
|
|
||||||
|
/**
|
||||||
|
* @class I2CSPIInstance |
||||||
|
* I2C/SPI driver instance used by BusInstanceIterator to find running instances. |
||||||
|
*/ |
||||||
|
class I2CSPIInstance |
||||||
|
{ |
||||||
|
public: |
||||||
|
I2CSPIInstance(I2CSPIBusOption bus_option, int bus) |
||||||
|
: _bus_option(bus_option), _bus(bus) {} |
||||||
|
|
||||||
|
virtual ~I2CSPIInstance() = default; |
||||||
|
|
||||||
|
private: |
||||||
|
friend class BusInstanceIterator; |
||||||
|
friend class I2CSPIDriverBase; |
||||||
|
|
||||||
|
const I2CSPIBusOption _bus_option; |
||||||
|
const int _bus; |
||||||
|
}; |
||||||
|
|
||||||
|
struct BusCLIArguments { |
||||||
|
I2CSPIBusOption bus_option{I2CSPIBusOption::All}; |
||||||
|
int requested_bus{-1}; |
||||||
|
int chipselect_index{1}; |
||||||
|
Rotation rotation{ROTATION_NONE}; |
||||||
|
int custom1; ///< driver-specific custom argument
|
||||||
|
int custom2; ///< driver-specific custom argument
|
||||||
|
}; |
||||||
|
|
||||||
|
/**
|
||||||
|
* @class BusInstanceIterator |
||||||
|
* Iterate over running instances and/or configured I2C/SPI buses with given filter options. |
||||||
|
*/ |
||||||
|
class BusInstanceIterator |
||||||
|
{ |
||||||
|
public: |
||||||
|
BusInstanceIterator(I2CSPIInstance **instances, int max_num_instances, |
||||||
|
const BusCLIArguments &cli_arguments, uint16_t devid_driver_index); |
||||||
|
~BusInstanceIterator() = default; |
||||||
|
|
||||||
|
I2CSPIBusOption configuredBusOption() const { return _bus_option; } |
||||||
|
|
||||||
|
int nextFreeInstance() const; |
||||||
|
|
||||||
|
bool next(); |
||||||
|
|
||||||
|
I2CSPIInstance *instance() const; |
||||||
|
void resetInstance(); |
||||||
|
board_bus_types busType() const; |
||||||
|
int bus() const; |
||||||
|
uint32_t devid() const; |
||||||
|
uint32_t DRDYGPIO() const; |
||||||
|
bool external() const; |
||||||
|
|
||||||
|
static I2CBusIterator::FilterType i2cFilter(I2CSPIBusOption bus_option); |
||||||
|
static SPIBusIterator::FilterType spiFilter(I2CSPIBusOption bus_option); |
||||||
|
private: |
||||||
|
I2CSPIInstance **_instances; |
||||||
|
const int _max_num_instances; |
||||||
|
const I2CSPIBusOption _bus_option; |
||||||
|
SPIBusIterator _spi_bus_iterator; |
||||||
|
I2CBusIterator _i2c_bus_iterator; |
||||||
|
int _current_instance{-1}; |
||||||
|
}; |
||||||
|
|
||||||
|
/**
|
||||||
|
* @class I2CSPIDriverBase |
||||||
|
* Base class for I2C/SPI driver modules (non-templated, used by I2CSPIDriver) |
||||||
|
*/ |
||||||
|
class I2CSPIDriverBase : public px4::ScheduledWorkItem, public I2CSPIInstance |
||||||
|
{ |
||||||
|
public: |
||||||
|
I2CSPIDriverBase(const char *module_name, const px4::wq_config_t &config, I2CSPIBusOption bus_option, int bus) |
||||||
|
: ScheduledWorkItem(module_name, config), |
||||||
|
I2CSPIInstance(bus_option, bus) {} |
||||||
|
|
||||||
|
static int module_stop(BusInstanceIterator &iterator); |
||||||
|
static int module_status(BusInstanceIterator &iterator); |
||||||
|
static int module_custom_method(const BusCLIArguments &cli, BusInstanceIterator &iterator); |
||||||
|
|
||||||
|
using instantiate_method = I2CSPIDriverBase * (*)(const BusCLIArguments &cli, const BusInstanceIterator &iterator, |
||||||
|
int runtime_instance); |
||||||
|
protected: |
||||||
|
virtual ~I2CSPIDriverBase() = default; |
||||||
|
|
||||||
|
virtual void print_status(); |
||||||
|
|
||||||
|
virtual void custom_method(const BusCLIArguments &cli) {} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Exiting the module. A driver can override this, for example to unregister interrupt callbacks. |
||||||
|
* This will be called from the work queue. |
||||||
|
* A module overriding this, needs to call I2CSPIDriverBase::exit_and_cleanup() as the very last statement. |
||||||
|
*/ |
||||||
|
virtual void exit_and_cleanup() { ScheduleClear(); _task_exited.store(true); } |
||||||
|
|
||||||
|
bool should_exit() const { return _task_should_exit.load(); } |
||||||
|
|
||||||
|
static int module_start(const BusCLIArguments &cli, BusInstanceIterator &iterator, void(*print_usage)(), |
||||||
|
instantiate_method instantiate, I2CSPIInstance **instances); |
||||||
|
|
||||||
|
private: |
||||||
|
void request_stop_and_wait(); |
||||||
|
|
||||||
|
px4::atomic_bool _task_should_exit{false}; |
||||||
|
px4::atomic_bool _task_exited{false}; |
||||||
|
}; |
||||||
|
|
||||||
|
/**
|
||||||
|
* @class I2CSPIDriver |
||||||
|
* Base class for I2C/SPI driver modules |
||||||
|
*/ |
||||||
|
template<class T, int MAX_NUM = 3> |
||||||
|
class I2CSPIDriver : public I2CSPIDriverBase |
||||||
|
{ |
||||||
|
public: |
||||||
|
static constexpr int max_num_instances = MAX_NUM; |
||||||
|
|
||||||
|
static int module_start(const BusCLIArguments &cli, BusInstanceIterator &iterator) |
||||||
|
{ |
||||||
|
return I2CSPIDriverBase::module_start(cli, iterator, &T::print_usage, &T::instantiate, _instances); |
||||||
|
} |
||||||
|
|
||||||
|
static I2CSPIInstance **instances() { return _instances; } |
||||||
|
|
||||||
|
protected: |
||||||
|
I2CSPIDriver(const char *module_name, const px4::wq_config_t &config, I2CSPIBusOption bus_option, int bus) |
||||||
|
: I2CSPIDriverBase(module_name, config, bus_option, bus) {} |
||||||
|
|
||||||
|
virtual ~I2CSPIDriver() = default; |
||||||
|
|
||||||
|
void Run() final { |
||||||
|
static_cast<T *>(this)->RunImpl(); |
||||||
|
|
||||||
|
if (should_exit()) |
||||||
|
{ |
||||||
|
exit_and_cleanup(); |
||||||
|
} |
||||||
|
} |
||||||
|
private: |
||||||
|
static I2CSPIInstance *_instances[MAX_NUM]; |
||||||
|
}; |
||||||
|
|
||||||
|
template<class T, int MAX_NUM> |
||||||
|
I2CSPIInstance *I2CSPIDriver<T, MAX_NUM>::_instances[MAX_NUM] {}; |
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class I2CSPIDriverInitializer |
||||||
|
* Helper class to initialize a driver: it ensures the object is initialzed on |
||||||
|
* the work queue where the driver is running. This is required so that all |
||||||
|
* bus accesses come from the same thread. |
||||||
|
*/ |
||||||
|
class I2CSPIDriverInitializer : public px4::WorkItem |
||||||
|
{ |
||||||
|
public: |
||||||
|
using instantiate_method = I2CSPIDriverBase::instantiate_method; |
||||||
|
|
||||||
|
I2CSPIDriverInitializer(const px4::wq_config_t &config, |
||||||
|
const BusCLIArguments &cli, const BusInstanceIterator &iterator, |
||||||
|
instantiate_method instantiate, int runtime_instance); |
||||||
|
~I2CSPIDriverInitializer(); |
||||||
|
void wait(); |
||||||
|
|
||||||
|
I2CSPIDriverBase *instance() const { return _instance; } |
||||||
|
protected: |
||||||
|
void Run() override; |
||||||
|
private: |
||||||
|
I2CSPIDriverBase *_instance{nullptr}; |
||||||
|
const BusCLIArguments &_cli; |
||||||
|
const BusInstanceIterator &_iterator; |
||||||
|
const int _runtime_instance; |
||||||
|
instantiate_method _instantiate; |
||||||
|
px4_sem_t _sem; |
||||||
|
}; |
@ -0,0 +1,165 @@ |
|||||||
|
/****************************************************************************
|
||||||
|
* |
||||||
|
* Copyright (c) 2020 PX4 Development Team. All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions |
||||||
|
* are met: |
||||||
|
* |
||||||
|
* 1. Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* 2. 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. |
||||||
|
* 3. Neither the name PX4 nor the names of its contributors may be |
||||||
|
* used to endorse or promote products derived from this software |
||||||
|
* without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
||||||
|
* BUT NOT LIMITED TO, 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. |
||||||
|
* |
||||||
|
****************************************************************************/ |
||||||
|
|
||||||
|
#pragma once |
||||||
|
|
||||||
|
#include <stdint.h> |
||||||
|
#include <board_config.h> |
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper macros to handle device ID's. They are used to match drivers against SPI buses and chip-select signals. |
||||||
|
* They match with corresponding definitions in NuttX. |
||||||
|
* 'type' is typically PX4_SPI_DEVICE_ID for PX4 drivers, and 'index' is used for the driver (DRV_*) or chip-select index. |
||||||
|
*/ |
||||||
|
//#define PX4_SPIDEV_ID(type, index) ((((type) & 0xffff) << 16) | ((index) & 0xffff))
|
||||||
|
//#define PX4_SPI_DEVICE_ID (1 << 12)
|
||||||
|
//#define PX4_SPI_DEV_ID(devid) ((devid) & 0xffff)
|
||||||
|
#define PX4_SPIDEVID_TYPE(devid) (((uint32_t)(devid) >> 16) & 0xffff) |
||||||
|
|
||||||
|
#define SPI_BUS_MAX_DEVICES 5 |
||||||
|
struct px4_spi_bus_device_t { |
||||||
|
uint32_t cs_gpio; ///< chip-select GPIO (0 if this device is not used)
|
||||||
|
uint32_t drdy_gpio; ///< data ready GPIO (0 if not set)
|
||||||
|
uint32_t devid; ///< SPIDEV_ID(type,index). For PX4 devices on NuttX: index is the device type, and for external buses the CS index
|
||||||
|
uint16_t devtype_driver; ///< driver device type, e.g. DRV_IMU_DEVTYPE_ICM20689 (on NuttX: PX4_SPI_DEV_ID(devid) == devtype_driver)
|
||||||
|
}; |
||||||
|
|
||||||
|
struct px4_spi_bus_devices_t { |
||||||
|
px4_spi_bus_device_t devices[SPI_BUS_MAX_DEVICES]; |
||||||
|
}; |
||||||
|
|
||||||
|
struct px4_spi_bus_t { |
||||||
|
px4_spi_bus_device_t devices[SPI_BUS_MAX_DEVICES]; |
||||||
|
int bus{-1}; ///< physical bus number (1, ...) (-1 means this is unused)
|
||||||
|
uint32_t power_enable_gpio{0}; ///< GPIO (if non-zero) to control the power of the attached devices on this bus (0 means power is off)
|
||||||
|
bool is_external; ///< static external configuration. Use px4_spi_bus_external() to check if a bus is really external
|
||||||
|
bool requires_locking; ///< whether the bus should be locked during transfers (true if NuttX drivers access the bus)
|
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
struct px4_spi_bus_all_hw_t { |
||||||
|
px4_spi_bus_t buses[SPI_BUS_MAX_BUS_ITEMS]; |
||||||
|
int board_hw_version; ///< 0=default, >0 for a specific revision (see board_get_hw_version)
|
||||||
|
}; |
||||||
|
|
||||||
|
#if BOARD_NUM_SPI_CFG_HW_VERSIONS > 1 |
||||||
|
/**
|
||||||
|
* initialze px4_spi_buses from px4_spi_buses_all_hw and the hardware version. |
||||||
|
* Call this on early boot before anything else accesses px4_spi_buses (e.g. from stm32_spiinitialize). |
||||||
|
*/ |
||||||
|
__EXPORT void px4_set_spi_buses_from_hw_version(); |
||||||
|
|
||||||
|
__EXPORT extern const px4_spi_bus_all_hw_t |
||||||
|
px4_spi_buses_all_hw[BOARD_NUM_SPI_CFG_HW_VERSIONS]; ///< board-specific SPI bus configuration all hw versions
|
||||||
|
|
||||||
|
__EXPORT extern const px4_spi_bus_t *px4_spi_buses; ///< board-specific SPI bus configuration for current board revision
|
||||||
|
#else |
||||||
|
static inline void px4_set_spi_buses_from_hw_version() {} |
||||||
|
__EXPORT extern const px4_spi_bus_t px4_spi_buses[SPI_BUS_MAX_BUS_ITEMS]; ///< board-specific SPI bus configuration
|
||||||
|
#endif |
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a SPI bus given a device ID. Note: only internal buses are checked. |
||||||
|
* @return the bus or -1 |
||||||
|
*/ |
||||||
|
__EXPORT int px4_find_spi_bus(uint32_t devid); |
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a bus requires locking during a SPI transfer (because it is potentially accessed by different threads) |
||||||
|
*/ |
||||||
|
__EXPORT bool px4_spi_bus_requires_locking(int bus); |
||||||
|
|
||||||
|
/**
|
||||||
|
* runtime-check if a board has a specific bus as external. |
||||||
|
* This can be overridden by a board to add run-time checks. |
||||||
|
*/ |
||||||
|
__EXPORT bool px4_spi_bus_external(const px4_spi_bus_t &bus); |
||||||
|
|
||||||
|
/**
|
||||||
|
* runtime-check if a board has a specific bus as external. |
||||||
|
*/ |
||||||
|
static inline bool px4_spi_bus_external(int bus) |
||||||
|
{ |
||||||
|
for (int i = 0; i < SPI_BUS_MAX_BUS_ITEMS; ++i) { |
||||||
|
if (px4_spi_buses[i].bus == bus) { |
||||||
|
return px4_spi_bus_external(px4_spi_buses[i]); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class SPIBusIterator |
||||||
|
* Iterate over configured SPI buses by the board |
||||||
|
*/ |
||||||
|
class SPIBusIterator |
||||||
|
{ |
||||||
|
public: |
||||||
|
enum class FilterType { |
||||||
|
InternalBus, ///< specific or all internal buses
|
||||||
|
ExternalBus, ///< specific external bus + CS index
|
||||||
|
}; |
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor |
||||||
|
* Note: only for devices of type PX4_SPI_DEVICE_ID |
||||||
|
* @param filter |
||||||
|
* @param devid_driver_index DRV_* or chip-select index starting from 1 |
||||||
|
* @param bus starts with 1 (-1=all, but only for internal). Numbering for internal is arch-specific, for external |
||||||
|
* it is the n-th external bus. |
||||||
|
*/ |
||||||
|
SPIBusIterator(FilterType filter, uint16_t devid_driver_index, int bus = -1) |
||||||
|
: _filter(filter), _devid_driver_index(devid_driver_index), |
||||||
|
_bus(filter == FilterType::ExternalBus && bus == -1 ? 1 : bus) {} |
||||||
|
|
||||||
|
bool next(); |
||||||
|
|
||||||
|
const px4_spi_bus_t &bus() const { return px4_spi_buses[_index]; } |
||||||
|
uint32_t DRDYGPIO() const { return px4_spi_buses[_index].devices[_bus_device_index].drdy_gpio; } |
||||||
|
|
||||||
|
uint32_t devid() const { return px4_spi_buses[_index].devices[_bus_device_index].devid; } |
||||||
|
|
||||||
|
bool external() const { return px4_spi_bus_external(bus()); } |
||||||
|
|
||||||
|
private: |
||||||
|
const FilterType _filter; |
||||||
|
const uint16_t _devid_driver_index; |
||||||
|
const int _bus; |
||||||
|
int _index{-1}; |
||||||
|
int _external_bus_counter{0}; |
||||||
|
int _bus_device_index{0}; |
||||||
|
}; |
||||||
|
|
@ -0,0 +1,157 @@ |
|||||||
|
/****************************************************************************
|
||||||
|
* |
||||||
|
* Copyright (C) 2020 PX4 Development Team. All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions |
||||||
|
* are met: |
||||||
|
* |
||||||
|
* 1. Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* 2. 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. |
||||||
|
* 3. Neither the name PX4 nor the names of its contributors may be |
||||||
|
* used to endorse or promote products derived from this software |
||||||
|
* without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
||||||
|
* BUT NOT LIMITED TO, 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 <board_config.h> |
||||||
|
#ifndef BOARD_DISABLE_I2C_SPI |
||||||
|
|
||||||
|
#include <px4_platform_common/spi.h> |
||||||
|
|
||||||
|
#if BOARD_NUM_SPI_CFG_HW_VERSIONS > 1 |
||||||
|
void px4_set_spi_buses_from_hw_version() |
||||||
|
{ |
||||||
|
int hw_version = board_get_hw_version(); |
||||||
|
|
||||||
|
for (int i = 0; i < BOARD_NUM_SPI_CFG_HW_VERSIONS; ++i) { |
||||||
|
if (!px4_spi_buses && px4_spi_buses_all_hw[i].board_hw_version == 0) { |
||||||
|
px4_spi_buses = px4_spi_buses_all_hw[i].buses; |
||||||
|
} |
||||||
|
|
||||||
|
if (px4_spi_buses_all_hw[i].board_hw_version == hw_version) { |
||||||
|
px4_spi_buses = px4_spi_buses_all_hw[i].buses; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (!px4_spi_buses) { // fallback
|
||||||
|
px4_spi_buses = px4_spi_buses_all_hw[0].buses; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const px4_spi_bus_t *px4_spi_buses{}; |
||||||
|
#endif |
||||||
|
|
||||||
|
int px4_find_spi_bus(uint32_t devid) |
||||||
|
{ |
||||||
|
for (int i = 0; i < SPI_BUS_MAX_BUS_ITEMS; ++i) { |
||||||
|
const px4_spi_bus_t &bus_data = px4_spi_buses[i]; |
||||||
|
|
||||||
|
if (bus_data.bus == -1) { |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
if (px4_spi_bus_external(bus_data)) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
for (int j = 0; j < SPI_BUS_MAX_DEVICES; ++j) { |
||||||
|
if (PX4_SPIDEVID_TYPE(devid) == PX4_SPIDEVID_TYPE(bus_data.devices[j].devid) && |
||||||
|
PX4_SPI_DEV_ID(devid) == bus_data.devices[j].devtype_driver) { |
||||||
|
return bus_data.bus; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
bool px4_spi_bus_requires_locking(int bus) |
||||||
|
{ |
||||||
|
for (int i = 0; i < SPI_BUS_MAX_BUS_ITEMS; ++i) { |
||||||
|
const px4_spi_bus_t &bus_data = px4_spi_buses[i]; |
||||||
|
|
||||||
|
if (bus_data.bus == bus) { |
||||||
|
return bus_data.requires_locking; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
bool px4_spi_bus_external(const px4_spi_bus_t &bus) |
||||||
|
{ |
||||||
|
return bus.is_external; |
||||||
|
} |
||||||
|
|
||||||
|
bool SPIBusIterator::next() |
||||||
|
{ |
||||||
|
// we have at most 1 match per bus, so we can directly jump to the next bus
|
||||||
|
while (++_index < SPI_BUS_MAX_BUS_ITEMS && px4_spi_buses[_index].bus != -1) { |
||||||
|
const px4_spi_bus_t &bus_data = px4_spi_buses[_index]; |
||||||
|
|
||||||
|
if (!board_has_bus(BOARD_SPI_BUS, bus_data.bus)) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
// Note: we use bus_data.is_external here instead of px4_spi_bus_external(),
|
||||||
|
// otherwise the chip-select matching does not work if a bus is configured as
|
||||||
|
// external/internal, but at runtime the other way around.
|
||||||
|
// (On boards where a bus can be internal/external at runtime, it should be
|
||||||
|
// configured as external.)
|
||||||
|
switch (_filter) { |
||||||
|
case FilterType::InternalBus: |
||||||
|
if (!bus_data.is_external) { |
||||||
|
if (_bus == bus_data.bus || _bus == -1) { |
||||||
|
// find device id
|
||||||
|
for (int i = 0; i < SPI_BUS_MAX_DEVICES; ++i) { |
||||||
|
if (PX4_SPI_DEVICE_ID == PX4_SPIDEVID_TYPE(bus_data.devices[i].devid) && |
||||||
|
_devid_driver_index == bus_data.devices[i].devtype_driver) { |
||||||
|
_bus_device_index = i; |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
break; |
||||||
|
|
||||||
|
case FilterType::ExternalBus: |
||||||
|
if (bus_data.is_external) { |
||||||
|
++_external_bus_counter; |
||||||
|
uint16_t cs_index = _devid_driver_index - 1; |
||||||
|
|
||||||
|
if (_bus == _external_bus_counter && cs_index < SPI_BUS_MAX_DEVICES && |
||||||
|
bus_data.devices[cs_index].cs_gpio != 0) { |
||||||
|
// we know that bus_data.devices[cs_index].devtype_driver == cs_index
|
||||||
|
_bus_device_index = cs_index; |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
#endif /* BOARD_DISABLE_I2C_SPI */ |
Loading…
Reference in new issue