first commit

This commit is contained in:
stuce-bot 2025-06-30 20:47:33 +02:00
commit 5893b00dd2
1669 changed files with 1982740 additions and 0 deletions

View file

@ -0,0 +1,16 @@
#include "M5HAL.hpp"
#include "m5_hal/bus/bus.inl"
#include "m5_hal/bus/i2c.inl"
#include "m5_hal/bus/spi.inl"
#define M5HAL_STATIC_MACRO_PATH_IMPL M5HAL_STATIC_MACRO_CONCAT(M5HAL_TARGET_PLATFORM_PATH, impl.inl)
#if M5HAL_TARGET_PLATFORM_NUMBER != 0
#include M5HAL_STATIC_MACRO_PATH_IMPL
#endif
// Arduino環境の場合のみ、Arduino用の実装を用意
#if M5HAL_FRAMEWORK_HAS_ARDUINO
#include "./m5_hal/frameworks/arduino/impl.inl"
#endif

View file

@ -0,0 +1,44 @@
#ifndef M5_HAL_HPP
#define M5_HAL_HPP
#include <M5Utility.hpp>
#include "./m5_hal/platform_checker.hpp"
#include "./m5_hal/framework_checker.hpp"
#include "./m5_hal/bus/i2c.hpp"
#include "./m5_hal/bus/spi.hpp"
#include "./m5_hal/bus/bus.hpp"
#include "./m5_hal/interface/gpio.hpp"
#define M5HAL_STATIC_MACRO_STRING(x) #x
// clang-format off
#define M5HAL_STATIC_MACRO_CONCAT(x, y) M5HAL_STATIC_MACRO_STRING(x/y)
// clang-format on
#define M5HAL_STATIC_MACRO_PATH_HEADER M5HAL_STATIC_MACRO_CONCAT(M5HAL_TARGET_PLATFORM_PATH, header.hpp)
#if M5HAL_TARGET_PLATFORM_NUMBER != 0
#include M5HAL_STATIC_MACRO_PATH_HEADER
#endif
#undef M5HAL_STATIC_MACRO_PATH_HEADER
// Arduinoフレームワークがある場合は準備
#if M5HAL_FRAMEWORK_HAS_ARDUINO
#include "./m5_hal/frameworks/arduino/header.hpp"
// 対象プラットフォームが特定されない場合は Arduino経由の実装を利用
#if 1 // M5HAL_TARGET_PLATFORM_NUMBER == 0
namespace m5 {
namespace hal {
using namespace frameworks::arduino;
}
} // namespace m5
#endif
#endif
#endif

View file

@ -0,0 +1,200 @@
#ifndef M5_HAL_BUS_HPP_
#define M5_HAL_BUS_HPP_
#include "../interface/gpio.hpp"
#include "../interface/io.hpp"
#include "../error.hpp"
#include <memory>
/*!
@namespace m5
@brief Toplevel namespace of M5
*/
namespace m5 {
namespace hal {
namespace bus {
struct Bus;
struct AccessConfig;
struct Accessor;
//-------------------------------------------------------------------------
// 通信バスの初期化に必要な条件を記述するため基底インターフェイス
struct BusConfig {
virtual ~BusConfig() = default;
virtual types::bus_type_t getBusType(void) const = 0;
types::periph_t periph;
};
//-------------------------------------------------------------------------
// 実際の通信に必要な条件を記述するための基底インターフェイス
struct AccessConfig {
virtual ~AccessConfig() = default;
virtual types::bus_type_t getBusType(void) const = 0;
void (*callback_begin)(Accessor*) = nullptr; // 通信開始時時に呼び出すコールバック関数
void (*callback_end)(Accessor*) = nullptr; // 通信終了時に呼び出すコールバック関数
};
//-------------------------------------------------------------------------
// 特定の通信相手との各種通信条件を記述するため基底インターフェイス
struct Accessor : public interface::io::Output, public interface::io::Input {
virtual ~Accessor(void) = default;
virtual types::bus_type_t getBusType(void) const = 0;
virtual const AccessConfig& getAccessConfig(void) const = 0;
Accessor(Bus& bus) : _bus{bus}
{
}
Bus& getBus(void) const
{
return _bus;
};
const BusConfig& getBusConfig(void) const;
virtual m5::stl::expected<void, m5::hal::error::error_t> startWrite(void)
{
return {};
}
virtual m5::stl::expected<void, m5::hal::error::error_t> startRead(void)
{
return {};
}
virtual m5::stl::expected<void, m5::hal::error::error_t> stop(void)
{
return {};
}
virtual m5::stl::expected<size_t, m5::hal::error::error_t> readLastNack(uint8_t* data, size_t len)
{
return readWithLastNackFlag(data, len, true);
}
virtual m5::stl::expected<size_t, m5::hal::error::error_t> readWithLastNackFlag(uint8_t* data, size_t len,
bool last_nack = false)
{
return read(data, len);
}
protected:
Bus& _bus;
};
template <typename TBusAccessInterface>
struct DefaultBusExtension {
DefaultBusExtension(TBusAccessInterface&)
{
}
};
template <typename TBus, typename TBusAccessInterface, typename TExtension = DefaultBusExtension<TBusAccessInterface>>
struct BusAccessor {
BusAccessor() = delete;
BusAccessor(TBus& bus, TBusAccessInterface& access) : _bus(bus), _access(access), _extension(access)
{
}
BusAccessor(const BusAccessor&) = delete;
BusAccessor& operator=(const BusAccessor&) = delete;
BusAccessor(BusAccessor&& other)
: _owner(other.owner), _bus(other.bus), _access(other.access), _extension(other.access)
{
other._owner = false;
}
void release()
{
if (this->_owner) {
this->_bus.release();
}
this->_owner = false;
}
BusAccessor& operator=(BusAccessor&& other)
{
this->release();
this->_owner = other._owner;
this->_bus = other._bus;
this->_access = other._access;
this->_extension = TExtension(this->_access);
other._owner = false;
}
/*
void read() { this->_access.read(this->_bus);}
void write() { this->_access.write(this->_bus); }
void transmit() { this->_access.transmit(this->_bus); }
*/
TExtension& extension()
{
return this->_extension;
}
~BusAccessor()
{
this->release();
}
protected:
bool _owner = true;
TBus& _bus;
TBusAccessInterface& _access;
TExtension _extension;
};
//-------------------------------------------------------------------------
// 通信バスの基底インターフェイス
struct Bus {
public:
virtual ~Bus() = default;
virtual types::bus_type_t getBusType(void) const = 0;
// initとreleaseはユーザーは直接呼ばない。 createBus / releaseBus経由で使用する。
virtual const BusConfig& getConfig(void) const = 0;
// バスの初期化
virtual error::error_t init(const BusConfig& config)
{
return error::error_t::NOT_IMPLEMENTED;
}
// バスの解放
virtual error::error_t release(void)
{
return error::error_t::NOT_IMPLEMENTED;
}
/// @note expectedは参照をサポートしていないのでポインタを含める形とした。
virtual m5::stl::expected<Accessor*, m5::hal::error::error_t> beginAccess(const AccessConfig& access_config) = 0;
virtual error::error_t endAccess(Accessor* Accessor)
{
if (Accessor && _Accessor.get() == Accessor) {
_Accessor.reset(nullptr);
return error::error_t::OK;
}
return error::error_t::INVALID_ARGUMENT;
}
// 無条件でバスをロックしたい場合に使用する
virtual m5::stl::expected<void, error::error_t> lock(void)
{
return m5::stl::make_unexpected(error::error_t::NOT_IMPLEMENTED);
}
virtual m5::stl::expected<void, error::error_t> unlock(void)
{
return m5::stl::make_unexpected(error::error_t::NOT_IMPLEMENTED);
}
protected:
std::unique_ptr<Accessor> _Accessor;
};
//-------------------------------------------------------------------------
// error::error_t Bus::beginAccess(const Accessor* Accessor) { return (Accessor->getBusType() != getBusType()) ?
// error::error_t::INVALID_ARGUMENT : error::error_t::OK; }
} // namespace bus
} // namespace hal
} // namespace m5
#endif

View file

@ -0,0 +1,15 @@
#include "bus.hpp"
namespace m5 {
namespace hal {
namespace bus {
const BusConfig& Accessor::getBusConfig(void) const
{
return _bus.getConfig();
}
} // namespace bus
} // namespace hal
} // namespace m5

View file

@ -0,0 +1,108 @@
#ifndef M5_HAL_BUS_I2C_HPP_
#define M5_HAL_BUS_I2C_HPP_
#include "./bus.hpp"
namespace m5 {
namespace hal {
namespace bus {
struct I2CBusConfig : public BusConfig {
types::bus_type_t getBusType(void) const override
{
return types::bus_type_t::I2C;
};
interface::gpio::Pin* pin_scl;
interface::gpio::Pin* pin_sda;
};
struct I2CMasterAccessConfig : public AccessConfig {
types::bus_type_t getBusType(void) const override
{
return types::bus_type_t::I2C;
};
uint32_t freq = 100000;
uint32_t timeout_msec = 1000;
uint16_t i2c_addr;
bool address_is_10bit = false;
};
namespace i2c {
struct I2CMasterAccessor : public Accessor {
I2CMasterAccessor(Bus& bus, const I2CMasterAccessConfig& access_config)
: Accessor{bus}, _access_config{access_config}
{
}
types::bus_type_t getBusType(void) const override
{
return types::bus_type_t::I2C;
};
const AccessConfig& getAccessConfig(void) const override
{
return _access_config;
}
m5::stl::expected<void, m5::hal::error::error_t> startWrite(void) override;
m5::stl::expected<void, m5::hal::error::error_t> startRead(void) override;
m5::stl::expected<void, m5::hal::error::error_t> stop(void) override;
// read with ack
m5::stl::expected<size_t, m5::hal::error::error_t> read(uint8_t* data, size_t len) override
{
return readWithLastNackFlag(data, len, false);
};
// virtual m5::stl::expected<size_t, m5::hal::error::error_t> readLastNack(uint8_t* data, size_t len) { return
// readWithLastNackFlag(data, len, true); } virtual m5::stl::expected<size_t, m5::hal::error::error_t>
// readWithLastNackFlag(uint8_t* data, size_t len, bool last_nack = false) = 0;
protected:
I2CMasterAccessConfig _access_config;
virtual m5::stl::expected<void, m5::hal::error::error_t> sendStartCondition(void);
virtual m5::stl::expected<void, m5::hal::error::error_t> sendStopCondition(void);
virtual m5::stl::expected<void, m5::hal::error::error_t> sendDummyClockWhileSdaLow(size_t count = 9);
virtual m5::stl::expected<void, m5::hal::error::error_t> waitClockStretch(uint_fast16_t msec);
};
class SoftwareI2CMasterAccessor : public I2CMasterAccessor {
public:
SoftwareI2CMasterAccessor(Bus& bus, const I2CMasterAccessConfig& access_config)
: I2CMasterAccessor{bus, access_config}
{
}
m5::stl::expected<size_t, m5::hal::error::error_t> write(const uint8_t* data, size_t len) override;
m5::stl::expected<size_t, m5::hal::error::error_t> readWithLastNackFlag(uint8_t* data, size_t len,
bool last_nack = false) override;
};
//-------------------------------------------------------------------------
struct I2CBus : public Bus {
types::bus_type_t getBusType(void) const override
{
return types::bus_type_t::I2C;
};
const BusConfig& getConfig(void) const override
{
return _config;
}
protected:
I2CBusConfig _config;
};
class SoftwareI2CBus : public I2CBus {
public:
error::error_t init(const BusConfig& config) override;
m5::stl::expected<Accessor*, m5::hal::error::error_t> beginAccess(const AccessConfig& access_config) override;
};
m5::stl::expected<I2CBus*, m5::hal::error::error_t> getBus(const I2CBusConfig& config);
} // namespace i2c
// static inline bus::I2CBus* createI2CBus(const bus::I2CBusConfig& config) { return i2c::createBus(config); }
} // namespace bus
} // namespace hal
} // namespace m5
#endif

View file

@ -0,0 +1,335 @@
#include "i2c.hpp"
#include "../error.hpp"
namespace m5 {
namespace hal {
namespace bus {
namespace i2c {
// constexpr uint32_t DELAY_CYCLE{400};
constexpr uint32_t DELAY_CYCLE{200};
void delayCycle(uint32_t count)
{
for (uint32_t i = count; i > 0; --i) {
__asm__ __volatile__("nop");
}
}
m5::stl::expected<I2CBus*, m5::hal::error::error_t> getBus(const I2CBusConfig& config)
{
// @TODO ソフトウェアSPIの複数のインスタンスを管理できるようにすること。
static SoftwareI2CBus bus;
bus.init(config);
return &bus;
}
error::error_t SoftwareI2CBus::init(const BusConfig& config)
{
if (config.getBusType() != types::bus_type_t::I2C) {
M5_LIB_LOGE("SoftwareI2C::init: error %s", __PRETTY_FUNCTION__);
return error::error_t::INVALID_ARGUMENT;
}
_config = static_cast<const I2CBusConfig&>(config);
if (_config.pin_scl == nullptr || _config.pin_sda == nullptr) {
M5_LIB_LOGE("SoftwareI2C::init: error %s", __PRETTY_FUNCTION__);
return error::error_t::INVALID_ARGUMENT;
}
M5_LIB_LOGV("SoftwareI2C::init: ok %s", __PRETTY_FUNCTION__);
_config.pin_scl->setMode(m5::hal::types::gpio_mode_t::Output_OpenDrain);
_config.pin_scl->writeLow();
_config.pin_sda->setMode(m5::hal::types::gpio_mode_t::Output_OpenDrain);
_config.pin_sda->writeLow();
_config.pin_scl->writeHigh();
delayCycle(128);
_config.pin_sda->writeHigh();
return error::error_t::OK;
}
m5::stl::expected<m5::hal::bus::Accessor*, m5::hal::error::error_t> SoftwareI2CBus::beginAccess(
const m5::hal::bus::AccessConfig& access_config)
{
/// @TODO ここで排他制御&ロック処理を行うこと。
if (_Accessor.get() != nullptr) {
M5_LIB_LOGE("SoftwareI2C::beginAccess: error %s", __PRETTY_FUNCTION__);
return m5::stl::make_unexpected(m5::hal::error::error_t::INVALID_ARGUMENT);
}
if (access_config.getBusType() != getBusType()) {
M5_LIB_LOGE("SoftwareI2C::beginAccess: error %s", __PRETTY_FUNCTION__);
return m5::stl::make_unexpected(m5::hal::error::error_t::INVALID_ARGUMENT);
}
auto result = new SoftwareI2CMasterAccessor(*this, (I2CMasterAccessConfig&)access_config);
_Accessor.reset(result);
M5_LIB_LOGV("SoftwareI2C::beginAccess: ok %s", __PRETTY_FUNCTION__);
return result;
}
m5::stl::expected<void, m5::hal::error::error_t> I2CMasterAccessor::sendDummyClockWhileSdaLow(size_t count)
{
auto bc = static_cast<const I2CBusConfig&>(getBusConfig());
auto sda = bc.pin_sda;
auto scl = bc.pin_scl;
/// SDAがLOWになっている場合は処理
if (!sda->read()) {
/// @TODO:ディレイサイクル数を求める仕組みを作っておくこと。
int delay_cycle = DELAY_CYCLE; //_nop_wait_w >> 1;
scl->writeLow();
sda->writeHigh();
delayCycle(delay_cycle);
// SDAがHIGHになるまでクロック送出しながら待機する。;
while (!(sda->read()) && (--count)) {
scl->writeHigh();
delayCycle(delay_cycle);
scl->writeLow();
delayCycle(delay_cycle);
}
}
if (count == 0) {
return m5::stl::make_unexpected(error::error_t::I2C_BUS_ERROR);
}
return {};
}
m5::stl::expected<void, m5::hal::error::error_t> I2CMasterAccessor::sendStartCondition(void)
{
auto bc = static_cast<const I2CBusConfig&>(getBusConfig());
auto sda = bc.pin_sda;
auto scl = bc.pin_scl;
/// @TODO:ディレイサイクル数を求める仕組みを作っておくこと。
int delay_cycle = DELAY_CYCLE; //_nop_wait_w >> 1;
// start condition
scl->writeHigh();
delayCycle(delay_cycle);
sda->writeLow();
delayCycle(delay_cycle);
scl->writeLow();
return {};
}
m5::stl::expected<void, m5::hal::error::error_t> I2CMasterAccessor::sendStopCondition(void)
{
auto bc = static_cast<const I2CBusConfig&>(getBusConfig());
auto sda = bc.pin_sda;
auto scl = bc.pin_scl;
/// @TODO:ディレイサイクル数を求める仕組みを作っておくこと。
int delay_cycle = DELAY_CYCLE; //_nop_wait_w >> 1;
auto res = sendDummyClockWhileSdaLow();
if (res.has_value()) {
// stop condition
sda->writeLow();
scl->writeHigh();
delayCycle(delay_cycle);
sda->writeHigh();
}
return res;
}
m5::stl::expected<void, m5::hal::error::error_t> I2CMasterAccessor::waitClockStretch(uint_fast16_t msec)
{
auto bc = static_cast<const I2CBusConfig&>(getBusConfig());
auto scl = bc.pin_scl;
auto ms = m5::utility::millis();
do {
std::this_thread::yield();
if (scl->read()) {
return {};
}
} while ((m5::utility::millis() - ms) < msec);
return m5::stl::make_unexpected(error::error_t::I2C_BUS_ERROR);
}
m5::stl::expected<void, m5::hal::error::error_t> I2CMasterAccessor::startWrite(void)
{
auto ac = static_cast<const I2CMasterAccessConfig&>(getAccessConfig());
sendStartCondition();
uint8_t data[] = {(uint8_t)(ac.i2c_addr << 1)};
auto result = write(data, sizeof(data));
if (result.has_value()) return {};
return m5::stl::make_unexpected(result.error());
}
m5::stl::expected<void, m5::hal::error::error_t> I2CMasterAccessor::startRead(void)
{
auto ac = static_cast<const I2CMasterAccessConfig&>(getAccessConfig());
sendStartCondition();
uint8_t data[] = {(uint8_t)(ac.i2c_addr << 1 | 1)};
auto result = write(data, sizeof(data));
if (result.has_value()) return {};
return m5::stl::make_unexpected(result.error());
}
m5::stl::expected<void, m5::hal::error::error_t> I2CMasterAccessor::stop(void)
{
return sendStopCondition();
}
m5::stl::expected<size_t, m5::hal::error::error_t> SoftwareI2CMasterAccessor::write(const uint8_t* data, size_t len)
{
auto bc = static_cast<const I2CBusConfig&>(getBusConfig());
auto ac = static_cast<const I2CMasterAccessConfig&>(getAccessConfig());
auto scl = bc.pin_scl;
auto sda = bc.pin_sda;
/// @TODO:ディレイサイクル数を求める仕組みを作っておくこと。
int delay_cycle = DELAY_CYCLE; //_nop_wait_w >> 1;
int_fast16_t dc0 = (delay_cycle) >> 2;
int_fast16_t dc1 = delay_cycle - dc0;
size_t result = 0;
do {
uint_fast8_t mask = 0x80;
uint_fast8_t d = *data++;
// 最初の1bitの送信
sda->write((bool)(d & mask));
delayCycle(dc0);
scl->writeHigh();
delayCycle(dc1);
// クロックストレッチの判定と待機;
if (!scl->read()) { // タイムアウト時間までクロックストレッチが解除されるのを待つ;
auto result = waitClockStretch(ac.timeout_msec);
if (!result) {
M5_LIB_LOGE("TIMEOUT");
sda->writeHigh();
return m5::stl::make_unexpected(error::error_t::TIMEOUT_ERROR);
}
}
mask >>= 1;
do { // 2bit~8bit目の送信;
scl->writeLow();
sda->write((bool)(d & mask));
delayCycle(dc0);
scl->writeHigh();
delayCycle(dc1);
mask >>= 1;
} while (mask);
// ACK応答チェック;
scl->writeLow(); // SCL lo
sda->writeHigh(); // SDA hi
delayCycle(dc1);
scl->writeHigh(); // hi
delayCycle(dc0);
// クロックストレッチの判定と待機;
if (!scl->read()) { // タイムアウト時間までクロックストレッチが解除されるのを待つ;
auto result = waitClockStretch(ac.timeout_msec);
if (!result) {
M5_LIB_LOGE("TIMEOUT2");
return m5::stl::make_unexpected(error::error_t::TIMEOUT_ERROR);
}
}
if (sda->read()) { // ToDo:ACK応答がない場合の処理;
M5_LIB_LOGE("NO_ACK");
{
// re-init?
scl->writeLow();
sda->writeLow();
scl->writeHigh();
delayCycle(128);
sda->writeHigh();
}
return m5::stl::make_unexpected(error::error_t::I2C_NO_ACK);
}
scl->writeLow();
} while (++result < len);
return result;
}
m5::stl::expected<size_t, m5::hal::error::error_t> SoftwareI2CMasterAccessor::readWithLastNackFlag(uint8_t* data,
size_t len,
bool last_nack)
{
auto bc = static_cast<const I2CBusConfig&>(getBusConfig());
auto ac = static_cast<const I2CMasterAccessConfig&>(getAccessConfig());
auto scl = bc.pin_scl;
auto sda = bc.pin_sda;
/// @TODO:ディレイサイクル数を求める仕組みを作っておくこと。
int delay_cycle = DELAY_CYCLE; //_nop_wait_w;
int_fast16_t dc0 = (delay_cycle) >> 1;
int_fast16_t dc1 = delay_cycle - dc0;
size_t result = 0;
do {
// 最初の1bitの受信
sda->writeHigh();
delayCycle(dc0);
scl->writeHigh();
delayCycle(dc1);
// クロックストレッチの判定と待機;
if (!scl->read()) { // タイムアウト時間までクロックストレッチが解除されるのを待つ;
if (!waitClockStretch(ac.timeout_msec)) {
return m5::stl::make_unexpected(error::error_t::TIMEOUT_ERROR);
}
}
uint_fast8_t mask = 0x80;
uint_fast8_t byte = sda->read() ? mask : 0;
mask >>= 1;
do {
scl->writeLow();
delayCycle(dc0);
scl->writeHigh();
delayCycle(dc1);
if (sda->read()) {
byte |= mask;
}
mask >>= 1;
} while (mask);
scl->writeLow();
/// ACKを返す (ただし、データ末尾かつNACK指定がある場合はACKを返さない);
if ((++result < len) || !last_nack) {
sda->writeLow();
}
delayCycle(dc0);
scl->writeHigh();
delayCycle(dc1);
scl->writeLow();
*data++ = byte;
} while (result < len);
return result;
}
// I2CBus* createBus(const I2CBusConfig& config)
// {
// static SoftwareI2CBus i2c_bus;
// return &i2c_bus;
// }
// error::error_t SoftwareI2CMasterAccessor::init(const interface::bus::BusConfig& config) { return
// error::error_t::NOT_IMPLEMENTED; } error::error_t SoftwareI2CMasterAccessor::release(void) { return
// error::error_t::NOT_IMPLEMENTED; } error::error_t SoftwareI2CMasterAccessor::start(void) { return
// error::error_t::NOT_IMPLEMENTED; } error::error_t SoftwareI2CMasterAccessor::stop(void) { return
// error::error_t::NOT_IMPLEMENTED; } error::error_t SoftwareI2CMasterAccessor::lock(void) { return
// error::error_t::NOT_IMPLEMENTED; } error::error_t SoftwareI2CMasterAccessor::unlock(void) { return
// error::error_t::NOT_IMPLEMENTED; } error::error_t SoftwareI2CMasterAccessor::beginAccess(interface::bus::Accessor*
// Accessor) { return error::error_t::NOT_IMPLEMENTED; } error::error_t SoftwareI2CMasterAccessor::endAccess(void) {
// return error::error_t::NOT_IMPLEMENTED; } error::error_t SoftwareI2CMasterAccessor::setFrequency(uint32_t freq) {
// return error::error_t::NOT_IMPLEMENTED; } error::error_t SoftwareI2CMasterAccessor::read(uint8_t* data, size_t len,
// interface::io::AsyncResult* async) { return error::error_t::NOT_IMPLEMENTED; } error::error_t
// SoftwareI2CMasterAccessor::write(const uint8_t* data, size_t len, interface::io::AsyncResult* async) { return
// error::error_t::NOT_IMPLEMENTED; }
} // namespace i2c
} // namespace bus
} // namespace hal
} // namespace m5

View file

@ -0,0 +1,137 @@
#ifndef M5_HAL_BUS_SPI_HPP_
#define M5_HAL_BUS_SPI_HPP_
#include "./bus.hpp"
namespace m5 {
namespace hal {
namespace bus {
/// @brief SPIバスの設定
/// @details 標準的なSPIだけでなく、QSPI,OSPIの設定も可能となっている
struct SPIBusConfig : public BusConfig {
virtual ~SPIBusConfig() = default;
types::bus_type_t getBusType(void) const override
{
return types::bus_type_t::SPI;
};
union {
interface::gpio::Pin* pins[9];
struct {
interface::gpio::Pin* pin_clk;
interface::gpio::Pin* pin_dc;
interface::gpio::Pin* pin_mosi; // data0
interface::gpio::Pin* pin_miso; // data1
interface::gpio::Pin* pin_d2; // data2
interface::gpio::Pin* pin_d3; // data3
interface::gpio::Pin* pin_d4; // data4
interface::gpio::Pin* pin_d5; // data5
interface::gpio::Pin* pin_d6; // data6
interface::gpio::Pin* pin_d7; // data7
};
};
};
enum class SpiDataMode {
spi_halfduplex, // 半二重通信
spi_fullduplex,
spi_halfduplex_with_dc_pin, // 半二重通信+DCピン
spi_fullduplex_with_dc_pin, // 全二重通信+DCピン
spi_halfduplex_with_dc_bit, // 半二重通信+DCビット(9ビットSPI)
spi_fullduplex_with_dc_bit, // 全二重通信+DCビット(9ビットSPI)
spi_dual_output,
spi_dual_io,
spi_quad_output,
spi_quad_io,
spi_octal_output,
spi_octal_io,
};
typedef SpiDataMode spi_data_mode_t;
struct SPIMasterAccessConfig : public AccessConfig {
virtual ~SPIMasterAccessConfig() = default;
types::bus_type_t getBusType(void) const override
{
return types::bus_type_t::SPI;
};
interface::gpio::Pin* pin_cs;
uint32_t freq;
spi_data_mode_t spi_data_mode;
struct {
uint8_t spi_mode : 2;
uint8_t spi_order : 1;
};
uint8_t spi_command_length = 0; // コマンド部のビット長
uint8_t spi_address_length = 0; // アドレス部のビット長
uint8_t spi_dummy_cycle = 0; // アドレスからデータへ移る際のダミーサイクル数
};
namespace spi {
struct SPIMasterAccessor : public Accessor {
SPIMasterAccessor(Bus& bus, const SPIMasterAccessConfig& access_config)
: Accessor{bus}, _access_config{access_config}
{
}
types::bus_type_t getBusType(void) const override
{
return types::bus_type_t::SPI;
};
const AccessConfig& getAccessConfig(void) const override
{
return _access_config;
}
virtual m5::stl::expected<size_t, m5::hal::error::error_t> writeCommand(const uint8_t* data, size_t len);
virtual m5::stl::expected<size_t, m5::hal::error::error_t> writeCommandData(const uint8_t* data, size_t len);
virtual m5::stl::expected<void, m5::hal::error::error_t> sendDummyClock(size_t count);
virtual m5::stl::expected<void, m5::hal::error::error_t> cs_control(bool cs_level);
protected:
SPIMasterAccessConfig _access_config;
};
class SoftwareSPIMasterAccessor : public SPIMasterAccessor {
public:
SoftwareSPIMasterAccessor(Bus& bus, const SPIMasterAccessConfig& access_config)
: SPIMasterAccessor{bus, access_config}
{
}
m5::stl::expected<size_t, m5::hal::error::error_t> read(uint8_t* data, size_t len) override;
m5::stl::expected<size_t, m5::hal::error::error_t> write(const uint8_t* data, size_t len) override;
};
//-------------------------------------------------------------------------
struct SPIBus : public Bus {
types::bus_type_t getBusType(void) const override
{
return types::bus_type_t::SPI;
};
const BusConfig& getConfig(void) const override
{
return _config;
}
// virtual SPIMasterAccessor* beginAccess(const SPIMasterAccessConfig& access_config) = 0;
// Accessor* beginAccess(const AccessConfig& access_config) override { return beginAccess((const
// SPIMasterAccessConfig&)access_config); }
protected:
SPIBusConfig _config;
};
class SoftwareSPIBus : public SPIBus {
public:
error::error_t init(const BusConfig& config) override;
m5::stl::expected<Accessor*, m5::hal::error::error_t> beginAccess(const AccessConfig& access_config) override;
// SPIMasterAccessor* beginAccess(const SPIMasterAccessConfig& access_config) override;
};
m5::stl::expected<SPIBus*, m5::hal::error::error_t> getBus(const SPIBusConfig& config);
// SPIBus* createBus(const SPIBusConfig& config); // { return spi::createBus(config); }
} // namespace spi
} // namespace bus
} // namespace hal
} // namespace m5
#endif

View file

@ -0,0 +1,145 @@
#include "spi.hpp"
namespace m5 {
namespace hal {
namespace bus {
namespace spi {
m5::stl::expected<SPIBus*, m5::hal::error::error_t> getBus(const SPIBusConfig& config)
{
// @TODO ソフトウェアSPIの複数のインスタンスを管理できるようにすること。
static SoftwareSPIBus spi_bus;
spi_bus.init(config);
return &spi_bus;
}
error::error_t SoftwareSPIBus::init(const BusConfig& config)
{
if (config.getBusType() != types::bus_type_t::SPI) {
M5_LIB_LOGE("SoftwareSPI::init: error %s", __PRETTY_FUNCTION__);
return error::error_t::INVALID_ARGUMENT;
}
_config = static_cast<const SPIBusConfig&>(config);
M5_LIB_LOGV("SoftwareSPI::init: ok %s", __PRETTY_FUNCTION__);
if (_config.pin_clk) {
_config.pin_clk->setMode(m5::hal::types::gpio_mode_t::Output);
}
if (_config.pin_dc) {
_config.pin_dc->setMode(m5::hal::types::gpio_mode_t::Output);
}
if (_config.pin_mosi) {
_config.pin_mosi->setMode(m5::hal::types::gpio_mode_t::Output);
}
if (_config.pin_miso) {
_config.pin_miso->setMode(m5::hal::types::gpio_mode_t::Input);
}
return error::error_t::OK;
}
m5::stl::expected<Accessor*, m5::hal::error::error_t> SoftwareSPIBus::beginAccess(const AccessConfig& access_config)
{
/// @TODO ここで排他制御&ロック処理を行うこと。
if (_Accessor.get() != nullptr) {
M5_LIB_LOGE("SoftwareSPI::beginAccess: error %s", __PRETTY_FUNCTION__);
return nullptr;
}
if (access_config.getBusType() != getBusType()) {
M5_LIB_LOGE("SoftwareSPI::beginAccess: error %s", __PRETTY_FUNCTION__);
return nullptr;
}
auto result = new SoftwareSPIMasterAccessor(*this, (const SPIMasterAccessConfig&)access_config);
_Accessor.reset(result);
M5_LIB_LOGV("SoftwareSPI::beginAccess: ok %s", __PRETTY_FUNCTION__);
return result;
}
m5::stl::expected<void, m5::hal::error::error_t> SPIMasterAccessor::sendDummyClock(size_t count)
{
if (count) {
auto bc = static_cast<const SPIBusConfig&>(getBusConfig());
auto ac = static_cast<const SPIMasterAccessConfig&>(getAccessConfig());
auto cpol = (ac.spi_mode & 2);
auto sclk = bc.pin_clk;
do {
sclk->write(!cpol);
sclk->write(cpol);
} while (--count);
}
return {};
}
m5::stl::expected<size_t, m5::hal::error::error_t> SPIMasterAccessor::writeCommand(const uint8_t* data, size_t len)
{
auto bc = static_cast<const SPIBusConfig&>(getBusConfig());
auto pin_dc = bc.pin_dc;
if (pin_dc) pin_dc->write(false);
auto res = write(data, len);
if (pin_dc) pin_dc->write(true);
return res;
}
m5::stl::expected<size_t, m5::hal::error::error_t> SPIMasterAccessor::writeCommandData(const uint8_t* data, size_t len)
{
auto bc = static_cast<const SPIBusConfig&>(getBusConfig());
auto pin_dc = bc.pin_dc;
auto ac = static_cast<const SPIMasterAccessConfig&>(getAccessConfig());
auto cmd_len = (ac.spi_command_length >> 3);
if (cmd_len) {
if (pin_dc) pin_dc->write(false);
auto res = write(data, cmd_len);
data += cmd_len;
auto datalen = len - cmd_len;
if (pin_dc) pin_dc->write(true);
if (!res || datalen == 0) return res;
res = write(data, datalen);
if (!res) {
return res;
}
return len;
}
return write(data, len);
}
m5::stl::expected<void, m5::hal::error::error_t> SPIMasterAccessor::cs_control(bool cs_level)
{
auto pin_cs = static_cast<const SPIMasterAccessConfig&>(getAccessConfig()).pin_cs;
if (pin_cs) pin_cs->write(cs_level);
return {};
}
m5::stl::expected<size_t, m5::hal::error::error_t> SoftwareSPIMasterAccessor::read(uint8_t* data, size_t len)
{
return m5::stl::make_unexpected(error::error_t::NOT_IMPLEMENTED);
}
m5::stl::expected<size_t, m5::hal::error::error_t> SoftwareSPIMasterAccessor::write(const uint8_t* data, size_t len)
{
auto bc = static_cast<const SPIBusConfig&>(getBusConfig());
auto ac = static_cast<const SPIMasterAccessConfig&>(getAccessConfig());
bool cpol = (ac.spi_mode & 2);
bool cpha = (ac.spi_mode & 1);
bool flip = cpol ^ cpha;
auto sclk = bc.pin_clk;
auto mosi = bc.pin_mosi;
size_t result = 0;
do {
uint_fast8_t mask = 0x80;
uint_fast8_t d = *data++;
do {
mosi->write(d & mask);
sclk->write(flip);
sclk->write(!flip);
} while (mask >>= 1);
} while (++result < len);
sclk->write(cpol);
return result;
}
} // namespace spi
} // namespace bus
} // namespace hal
} // namespace m5

View file

@ -0,0 +1,37 @@
#ifndef M5_HAL_ERROR_HPP
#define M5_HAL_ERROR_HPP
#include <stdint.h>
namespace m5 {
namespace hal {
namespace error {
enum class ErrorType : int8_t {
ASYNC_RUNNING = 1,
OK = 0,
UNKNOWN_ERROR = -1,
TIMEOUT_ERROR = -2,
INVALID_ARGUMENT = -3,
NOT_IMPLEMENTED = -4,
I2C_BUS_ERROR = -5,
I2C_NO_ACK = -6,
// @ TODO エラーコード細分化する
};
using error_t = ErrorType;
constexpr bool isError(const error_t e)
{
return e < error_t::OK;
}
constexpr bool isOk(const error_t e)
{
return e == error_t::OK;
}
} // namespace error
} // namespace hal
} // namespace m5
#endif

View file

@ -0,0 +1,22 @@
#ifndef M5_HAL_FRAMEWORK_CHECKER_HPP
#define M5_HAL_FRAMEWORK_CHECKER_HPP
#if defined(ARDUINO)
#define M5HAL_FRAMEWORK_HAS_ARDUINO 1
#else
#define M5HAL_FRAMEWORK_HAS_ARDUINO 0
#endif
#if __has_include(<FreeRTOS.h>) || __has_include(<freertos/FreeRTOS.h>)
#define M5HAL_FRAMEWORK_HAS_FREERTOS 1
#else
#define M5HAL_FRAMEWORK_HAS_FREERTOS 0
#endif
#if __has_include(<SDL2/SDL.h>) || __has_include(<SDL.h>)
#define M5HAL_FRAMEWORK_HAS_SDL 1
#else
#define M5HAL_FRAMEWORK_HAS_SDL 0
#endif
#endif

View file

@ -0,0 +1,79 @@
#ifndef M5_HAL_FRAMEWORKS_ARDUINO_HEADER_HPP
#define M5_HAL_FRAMEWORKS_ARDUINO_HEADER_HPP
#include "../../interface/gpio.hpp"
#include "../../bus/bus.hpp"
#if __has_include(<Arduino.h>)
#include <Arduino.h>
#include <Wire.h>
#endif
#if defined(ARDUINO)
namespace m5 {
namespace hal {
namespace frameworks {
namespace arduino {
namespace gpio {
// 単一のデジタルピンを表すインターフェイス
class Pin : public interface::gpio::Pin {
public:
void write(bool value) override;
void writeHigh(void) override;
void writeLow(void) override;
bool read(void) override;
void setMode(types::gpio_mode_t mode) override;
types::gpio_number_t getGpioNumber(void) const override
{
return _gpio_number;
}
Pin(void) = default;
Pin(types::gpio_number_t gpio_number) : _gpio_number{gpio_number}
{
}
protected:
types::gpio_number_t _gpio_number; // = (int16_t)-1;
};
// 複数のPinを束ねた概念を表すインターフェイス
class Port : public interface::gpio::Port {
public:
interface::gpio::Pin* getPin(uint8_t pinNumber) override;
// uint8_t getPortNumber(void) const override { return 0; }
// void setDirection(uint8_t mask, bool isOutput);
protected:
};
// ポートを含めてGPIO全体を表すインターフェイス
class GPIO : public interface::gpio::GPIO {
public:
interface::gpio::Port* getPort(uint8_t portNumber) override;
interface::gpio::Pin* getPin(types::gpio_number_t pinNumber) override;
private:
};
interface::gpio::GPIO* getGPIO(void);
interface::gpio::Pin* getPin(types::gpio_number_t pinNumber);
} // namespace gpio
namespace bus {
namespace i2c {
// bus::I2CBus* createBus(TwoWire& _wire);
} // namespace i2c
} // namespace bus
} // namespace arduino
} // namespace frameworks
} // namespace hal
} // namespace m5
#endif
#endif

View file

@ -0,0 +1,119 @@
#ifndef M5_HAL_PLATFORMS_ARDUINO_IMPL_INL
#define M5_HAL_PLATFORMS_ARDUINO_IMPL_INL
#include "../src/m5_hal/bus/bus.hpp"
#include <M5Utility.hpp>
#if __has_include(<Arduino.h>)
#include <Arduino.h>
#include <Wire.h>
#endif
#include <vector>
#include <list>
#if defined(ARDUINO)
namespace m5 {
namespace hal {
namespace frameworks {
namespace arduino {
namespace gpio {
interface::gpio::GPIO* getGPIO(void)
{
M5_LIB_LOGV("getGPIO\n");
static GPIO s_gpio_instance;
return &s_gpio_instance;
}
interface::gpio::Pin* getPin(types::gpio_number_t pinNumber)
{
M5_LIB_LOGV("getPin %d", pinNumber);
return getGPIO()->getPin(pinNumber);
}
interface::gpio::Port* GPIO::getPort(uint8_t portNumber)
{
static Port s_port_instance;
return &s_port_instance;
}
interface::gpio::Pin* GPIO::getPin(types::gpio_number_t pinNumber)
{
M5_LIB_LOGV("GPIO::getPin %d", pinNumber);
return getPort(0)->getPin(pinNumber);
}
interface::gpio::Pin* Port::getPin(uint8_t pinNumber)
{
static std::vector<Pin*> s_pins_pointer;
static std::list<Pin> s_pins_instance;
if (s_pins_pointer.size() <= pinNumber) {
s_pins_pointer.resize(pinNumber + 1);
}
if (s_pins_pointer[pinNumber] == nullptr) {
s_pins_instance.push_back(Pin(pinNumber));
s_pins_pointer[pinNumber] = &s_pins_instance.back();
}
return s_pins_pointer[pinNumber];
}
void Pin::write(bool value)
{
// M5_LIB_LOGV("Pin::write %d [pin %d]", value, _gpio_number);
digitalWrite(_gpio_number, value);
}
bool Pin::read(void)
{
return digitalRead(_gpio_number);
}
void Pin::writeHigh(void)
{
// M5_LIB_LOGV("Pin::setHigh [pin %d]", _gpio_number);
digitalWrite(_gpio_number, true);
}
void Pin::writeLow(void)
{
// M5_LIB_LOGV("Pin::setLow [pin %d]", _gpio_number);
digitalWrite(_gpio_number, false);
}
void Pin::setMode(types::gpio_mode_t mode)
{
switch (mode) {
case types::gpio_mode_t::Input:
pinMode(_gpio_number, INPUT);
break;
case types::gpio_mode_t::Output:
pinMode(_gpio_number, OUTPUT);
break;
case types::gpio_mode_t::Output_OpenDrain:
pinMode(_gpio_number, OUTPUT_OPEN_DRAIN);
break;
default:
break;
}
}
} // namespace gpio
namespace bus {
namespace i2c {
// interface::bus::I2C* createBus(TwoWire& _wire)
// {
// return nullptr;
// }
} // namespace i2c
} // namespace bus
//
} // namespace arduino
} // namespace frameworks
} // namespace hal
} // namespace m5
#endif
#endif

View file

@ -0,0 +1,18 @@
#ifndef M5_HAL_GPIO_GPIO_HPP_
#define M5_HAL_GPIO_GPIO_HPP_
#include "../interface/gpio.hpp"
#include <stdint.h>
#include <stddef.h>
namespace m5 {
namespace hal {
namespace gpio {
class GPIO { /* Empty*/
};
}; // namespace gpio
} // namespace hal
} // namespace m5
#endif

View file

@ -0,0 +1,93 @@
#ifndef M5_HAL_INTERFACE_GPIO_HPP
#define M5_HAL_INTERFACE_GPIO_HPP
#include "../types.hpp"
#include <vector>
/*!
@namespace m5
@brief Toplevel namespace of M5
*/
namespace m5 {
namespace hal {
namespace interface {
// 抽象化されたGPIOインターフェースを置く。これは LowLayerではなく汎用的なもの。
// このGPIOインターフェースを継承してGPIOエキスパンダの実装を作ることもできる。
namespace gpio {
// 単一のデジタルピンを表すインターフェイス
struct Pin {
virtual ~Pin() = default;
virtual void write(bool value) = 0;
virtual bool read(void) = 0;
virtual void writeHigh(void)
{
write(true);
}
virtual void writeLow(void)
{
write(false);
}
virtual types::gpio_number_t getGpioNumber(void) const = 0;
virtual void setMode(types::gpio_mode_t mode) = 0;
};
// 複数のPinを保持する概念を表すインターフェイス
struct Port {
virtual ~Port() = default;
virtual Pin* getPin(uint8_t pinNumber) = 0;
// virtual uint8_t getPortNumber(void) const = 0;
};
// Portを複数含むGPIO全体を表すインターフェイス
struct GPIO {
virtual ~GPIO() = default;
virtual Port* getPort(uint8_t portNumber) = 0;
virtual Pin* getPin(types::gpio_number_t gpioNumber) = 0;
virtual void digitalWrite(types::gpio_number_t gpioNumber, bool value)
{
getPin(gpioNumber)->write(value);
}
virtual bool digitalRead(types::gpio_number_t gpioNumber)
{
return getPin(gpioNumber)->read();
}
virtual int analogRead(types::gpio_number_t gpioNumber)
{
return -1;
}
};
// n個のピンを内包するポート (例: 2個ならGROVEコネクタ、等)
// コンストラクタにてピンの数を指定する。生成後のサイズ変更は不可とする。
// 暫定的に std::vector でポインタを保持するが、将来的にはメモリ効率を考慮して変更する可能性あり。
class MultiPinPort : public Port {
public:
MultiPinPort(size_t size) : _pins{size, nullptr}
{
}
Pin* getPin(uint8_t pinNumber) override
{
return _pins.size() > pinNumber ? _pins[pinNumber] : nullptr;
}
void setPin(uint8_t pinNumber, Pin* pin)
{
if (_pins.size() > pinNumber) _pins[pinNumber] = pin;
}
size_t getPinCount(void) const
{
return _pins.size();
}
protected:
std::vector<Pin*> _pins;
};
} // namespace gpio
} // namespace interface
} // namespace hal
} // namespace m5
#endif

View file

@ -0,0 +1,88 @@
#ifndef M5_HAL_INTERFACE_IO_HPP_
#define M5_HAL_INTERFACE_IO_HPP_
#include "../error.hpp"
#include "../types.hpp"
#include <M5Utility.hpp>
#include <future>
/*!
@namespace m5
@brief Toplevel namespace of M5
*/
namespace m5 {
namespace hal {
namespace interface {
namespace io {
// struct AsyncParam {
// public:
// // タイムアウト時間を設定する変数 (呼び出し側が設定しておく。0なら処理を終えるかエラーになるまで無限待ち)
// uint32_t timeout_ms;
// // read/writeの結果得られた長さを格納する変数
// size_t length;
// // 処理の結果を格納する変数 (ASYNC_RUNNINGの場合はまだ処理中)
// error::error_t error;
// };
struct Input {
public:
virtual ~Input() = default;
// @param data 読み込んだデータを格納するバッファ
// @param len 読み込むデータの長さ
// @return 読み込んだデータの長さ / エラー
virtual m5::stl::expected<size_t, m5::hal::error::error_t> read(uint8_t* data, size_t len) = 0;
// virtual std::future<m5::stl::expected<size_t, m5::hal::error::error_t> > asyncRead(uint8_t* data, size_t len,
// AsyncParam* async = nullptr) = 0;
virtual m5::stl::expected<size_t, m5::hal::error::error_t> availableRead(void) const
{
return m5::stl::make_unexpected(error::error_t::NOT_IMPLEMENTED);
};
};
struct Output {
public:
virtual ~Output() = default;
virtual m5::stl::expected<size_t, m5::hal::error::error_t> write(const uint8_t* data, size_t len) = 0;
// virtual std::future<m5::stl::expected<size_t, m5::hal::error::error_t> > asyncWrite(const uint8_t* data, size_t
// len, AsyncParam* async = nullptr) = 0;
virtual m5::stl::expected<size_t, m5::hal::error::error_t> availableWrite(void) const
{
return m5::stl::make_unexpected(error::error_t::NOT_IMPLEMENTED);
};
};
// Push型の入力はデータが一定量たまったらコールバックが呼ばれ、readで取得する
struct PushInput : public Input {
public:
virtual ~PushInput() = default;
virtual m5::stl::expected<void, m5::hal::error::error_t> setCallbackRead(void (*cb)(PushInput* bus,
size_t available_len,
void* cb_obj)) = 0;
};
// Push型の出力は新しいデータが必要になったらコールバックが呼ばれ、writeで書き込む
struct PushOutput : public Output {
public:
virtual ~PushOutput() = default;
virtual m5::stl::expected<void, m5::hal::error::error_t> setCallbackWrite(void (*cb)(PushOutput* bus,
size_t request_len,
void* cb_obj)) = 0;
};
} // namespace io
} // namespace interface
} // namespace hal
} // namespace m5
#endif

View file

@ -0,0 +1,67 @@
#ifndef M5_HAL_PLATFORM_CHECKER_HPP
#define M5_HAL_PLATFORM_CHECKER_HPP
#define M5HAL_PLATFORM_NUMBER_UNKNOWN 0
#define M5HAL_PLATFORM_NUMBER_WINDOWS 10
#define M5HAL_PLATFORM_NUMBER_MACOS 20
#define M5HAL_PLATFORM_NUMBER_LINUX 30
#define M5HAL_PLATFORM_NUMBER_SDL_MAX 99
#define M5HAL_PLATFORM_NUMBER_AVR 200
#define M5HAL_PLATFORM_NUMBER_ESP8266 300
#define M5HAL_PLATFORM_NUMBER_ESP32_UNKNOWN 310
#define M5HAL_PLATFORM_NUMBER_ESP32_1st 311
#define M5HAL_PLATFORM_NUMBER_ESP32_S2 312
#define M5HAL_PLATFORM_NUMBER_ESP32_S3 313
#define M5HAL_PLATFORM_NUMBER_ESP32_C3 314
#define M5HAL_PLATFORM_NUMBER_ESP32_C6 315
#define M5HAL_PLATFORM_NUMBER_ESP32_P4 316
#define M5HAL_PLATFORM_NUMBER_RP2040 400
#define M5HAL_PLATFORM_NUMBER_SAMD21 500
#define M5HAL_PLATFORM_NUMBER_SAMD51 510
#define M5HAL_PLATFORM_NUMBER_SPRESENSE 600
#define M5HAL_PLATFORM_NUMBER_STM32 700
#define XSTR(x) STR(x)
#define STR(x) #x
#if defined(ESP_PLATFORM)
#if __has_include(<sdkconfig.h>)
#include <sdkconfig.h>
#endif
// clang-format off
#if defined(CONFIG_IDF_TARGET)
#if defined(CONFIG_IDF_TARGET_ESP32C3)
#define M5HAL_TARGET_PLATFORM_NUMBER M5HAL_PLATFORM_NUMBER_ESP32C3
#define M5HAL_TARGET_PLATFORM_PATH m5_hal/platforms/espressif/esp32c3
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
#define M5HAL_TARGET_PLATFORM_NUMBER M5HAL_PLATFORM_NUMBER_ESP32S3
#define M5HAL_TARGET_PLATFORM_PATH m5_hal/platforms/espressif/esp32s3
#elif defined(CONFIG_IDF_TARGET_ESP32)
#define M5HAL_TARGET_PLATFORM_NUMBER M5HAL_PLATFORM_NUMBER_ESP32_1st
#define M5HAL_TARGET_PLATFORM_PATH m5_hal/platforms/espressif/esp32
#elif defined(CONFIG_IDF_TARGET_ESP32C6)
#define M5HAL_TARGET_PLATFORM_NUMBER M5HAL_PLATFORM_NUMBER_ESP32_C6
#define M5HAL_TARGET_PLATFORM_PATH m5_hal/platforms/espressif/esp32c6
#elif defined(CONFIG_IDF_TARGET_ESP32P4)
#define M5HAL_TARGET_PLATFORM_NUMBER M5HAL_PLATFORM_NUMBER_ESP32_P4
#define M5HAL_TARGET_PLATFORM_PATH m5_hal/platforms/espressif/esp32p4
#else
#define M5HAL_TARGET_PLATFORM_NUMBER M5HAL_PLATFORM_NUMBER_ESP32_UNKNOWN
#define M5HAL_TARGET_PLATFORM_PATH m5_hal/platforms/espressif/esp32_unknown
#endif
#endif
#else
#endif
// clang-format on
#undef XSTR
#undef STR
#if !defined(M5HAL_TARGET_PLATFORM_NUMBER)
#define M5HAL_TARGET_PLATFORM_NUMBER M5HAL_PLATFORM_NUMBER_UNKNOWN
#endif
#endif

View file

@ -0,0 +1,39 @@
#ifndef M5_HAL_PLATFORMS_ESPRESSIF_ESP32_HEADER_HPP
#define M5_HAL_PLATFORMS_ESPRESSIF_ESP32_HEADER_HPP
#include "../../../interface/gpio.hpp"
#include "../../../bus/bus.hpp"
namespace m5 {
namespace hal {
namespace platforms {
// namespace esp32 {}
// namespace current_platform {
// using namespace esp32;
// }
namespace esp32 {
namespace types {
enum class PeripheralType : uint8_t {
none = 0,
i2c0,
i2c1,
spi2,
spi3,
};
using periph_t = PeripheralType;
} // namespace types
namespace gpio {
interface::gpio::GPIO* getGPIO(void);
} // namespace gpio
} // namespace esp32
} // namespace platforms
} // namespace hal
} // namespace m5
#endif

View file

@ -0,0 +1,23 @@
#ifndef M5_HAL_PLATFORMS_ESPRESSIF_ESP32C6_HEADER_HPP
#define M5_HAL_PLATFORMS_ESPRESSIF_ESP32C6_HEADER_HPP
#include "../../../interface/gpio.hpp"
// #include "../../../interface/bus.hpp"
namespace m5 {
namespace hal {
namespace platforms {
namespace esp32 {
namespace gpio {
interface::gpio::GPIO* getGPIO(void);
} // namespace gpio
namespace bus {
namespace i2c {
} // namespace i2c
} // namespace bus
} // namespace esp32
} // namespace platforms
} // namespace hal
} // namespace m5
#endif

View file

@ -0,0 +1,23 @@
#ifndef M5_HAL_PLATFORMS_ESPRESSIF_ESP32P4_HEADER_HPP
#define M5_HAL_PLATFORMS_ESPRESSIF_ESP32P4_HEADER_HPP
#include "../../../interface/gpio.hpp"
// #include "../../../interface/bus.hpp"
namespace m5 {
namespace hal {
namespace platforms {
namespace esp32 {
namespace gpio {
interface::gpio::GPIO* getGPIO(void);
} // namespace gpio
namespace bus {
namespace i2c {
} // namespace i2c
} // namespace bus
} // namespace esp32
} // namespace platforms
} // namespace hal
} // namespace m5
#endif

View file

@ -0,0 +1,23 @@
#ifndef M5_HAL_PLATFORMS_ESPRESSIF_ESP32S3_HEADER_HPP
#define M5_HAL_PLATFORMS_ESPRESSIF_ESP32S3_HEADER_HPP
#include "../../../interface/gpio.hpp"
#include "../../../interface/bus.hpp"
namespace m5 {
namespace hal {
namespace platforms {
namespace esp32 {
namespace gpio {
interface::gpio::GPIO* getGPIO(void);
} // namespace gpio
namespace bus {
namespace i2c {
} // namespace i2c
} // namespace bus
} // namespace esp32
} // namespace platforms
} // namespace hal
} // namespace m5
#endif

View file

@ -0,0 +1,65 @@
#ifndef M5_HAL_TYPES_HPP
#define M5_HAL_TYPES_HPP
#include <stdint.h>
#include <stddef.h>
// #include <M5Utility.hpp>
namespace m5 {
namespace hal {
namespace types {
enum class PeripheralType : uint8_t;
using periph_t = PeripheralType;
// GPIOピンの通し番号型
typedef int16_t gpio_number_t;
// typedef m5::utility::BitSegment<3, int16_t> gpio_number_t;
// class gpio_number_t : public m5::utility::BitSegment<3, int16_t> {
// public:
// inline constexpr gpio_number_t() = default;
// inline constexpr gpio_number_t(const base_type v) : BitSegment(v) {
// }
// inline constexpr int16_t port(void) const { return upper(); }
// inline constexpr int16_t pin(void) const { return lower(); }
// inline void port(int16_t v) { upper(v); }
// inline void pin(int16_t v) { lower(v); }
// };
/*
: 3bit (8)
gpio_number_t 3bit 12bit
: 5bit (32)
gpio_number_t 5bit 10bit
*/
enum class GpioMode : uint8_t {
Input = 0,
Output,
Output_OpenDrain,
};
using gpio_mode_t = GpioMode;
enum class BusType : uint8_t {
UNKNOWN = 0,
I2C,
SPI,
I2S,
UART,
PWM,
GPIO,
ADC,
DAC,
};
using bus_type_t = BusType;
} // namespace types
} // namespace hal
} // namespace m5
#endif