Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion extras/board_spec/test/board_spec.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -661,7 +661,7 @@ test("explicit fallback takes precedence over detector candidates", async (t) =>
const selection = /bool board_detected = \(board != board_t::board_unknown\);([\s\S]*?)_board = board;/.exec(source)?.[1];
assert.ok(selection);
const explicit = selection.indexOf("board = cfg.fallback_board;");
const candidate = selection.indexOf("board = Display.getBoardCandidate();");
const candidate = selection.indexOf("board = Display.getCandidateBoard();");
const build = selection.indexOf("board = _default_fallback_board();");
assert.ok(explicit >= 0 && explicit < candidate && candidate < build);
assert.match(selection, /if \(!board_detected\)/);
Expand Down
8 changes: 4 additions & 4 deletions extras/board_spec/test/detect_attempt.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ test("production attempt yields before construction and preserves adoption and r
const compat = body(main, "board_t M5GFX::autodetect(");
const projection = main.slice(main.indexOf(" const auto board = outcome.setup_succeeded"), main.indexOf("#if defined ( ARDUINO_M5STACK_ATOM )", main.indexOf(" const auto board = outcome.setup_succeeded")));
const header = await fs.readFile(path.join(src, "M5GFX.h"), "utf8");
const candidateGetter = body(header, "board_t getBoardCandidate(");
const candidateGetter = body(header, "board_t getCandidateBoard(");
await compileRun(`
#include "board_detect/detect_session.hpp"
#include <cassert>
Expand Down Expand Up @@ -70,7 +70,7 @@ struct holder_t {int* get() {return nullptr;}};
struct M5GFX {
board_t _board=board_t::board_unknown,_board_candidate=board_t::board_unknown;
board_t getBoard() const {return _board;}
board_t getBoardCandidate() const ${candidateGetter}
board_t getCandidateBoard() const ${candidateGetter}
void project(const board_detect::detect_outcome_t& outcome) { ${projection} }
struct {board_t fallback_board=board_t::board_unknown;} _detect_config;
holder_t _panel_last;
Expand All @@ -97,7 +97,7 @@ int main() {
const bool success=failure==0 && !yields;
M5GFX standalone;standalone.project(out);
assert(standalone.getBoard()==(success?board_t::member:board_t::board_unknown));
assert(standalone.getBoardCandidate()==(provisional&&!success?board_t::member:board_t::board_unknown));
assert(standalone.getCandidateBoard()==(provisional&&!success?board_t::member:board_t::board_unknown));
assert(out.setup_succeeded==success);
assert(out.verdict==(provisional ? verdict_t::candidate : verdict_t::confirmed));
assert(out.candidate_kind==(provisional ? candidate_kind_t::provisional : candidate_kind_t::none));
Expand Down Expand Up @@ -133,7 +133,7 @@ int main() {
assert(yielded.attempts==5&&!yielded.setup_succeeded&&yielded.result.candidate==&preferred_desc.def);
assert(yielded.candidate_kind==candidate_kind_t::provisional&&yielded.verdict==verdict_t::candidate);
M5GFX projected;projected.project(yielded);
assert(projected.getBoard()==board_t::board_unknown&&projected.getBoardCandidate()==static_cast<board_t>(2));
assert(projected.getBoard()==board_t::board_unknown&&projected.getCandidateBoard()==static_cast<board_t>(2));
assert(construct_count==0&&adopt_count==0&&rollback_count==5&&commit_count==0);
assert(!should_persist_detection(yielded,0));
refined_member=nullptr;
Expand Down
2 changes: 1 addition & 1 deletion extras/board_spec/test/fixed_board.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ enum class board_t{board_unknown=0,fixed=1,fallback=2,candidate=3,default_board=
int warnings;void Log(int,const char*,unsigned,unsigned){++warnings;}
struct display_t {
board_t fixed,adopted,candidate;
board_t getFixedBoard(){return fixed;}board_t getBoard(){return adopted;}board_t getBoardCandidate(){return candidate;}
board_t getFixedBoard(){return fixed;}board_t getBoard(){return adopted;}board_t getCandidateBoard(){return candidate;}
};
struct unified_t {
display_t Display;struct {board_t fallback_board;} cfg;
Expand Down
2 changes: 1 addition & 1 deletion src/M5GFX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ namespace m5gfx

#if defined ( ESP_PLATFORM )

// 判別 transaction の候補機種 I2C プローブはソフトウェアポートを使う。
// Candidate I2C probes during detection use a software port.
static constexpr int_fast16_t probe_i2c_port = -1;

static constexpr std::uint32_t m5pm1_i2c_freq = 100000;
Expand Down
18 changes: 17 additions & 1 deletion src/M5GFX.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,19 @@ namespace m5gfx
{
using namespace lgfx;

/// Board detection settings. Pass them to M5GFX::setDetectConfig() before the
/// first init(); once a board is set up, init() returns early and does not use them.
struct detect_config_t
{
/// Used when detection identifies the family but not the member. If this board
/// is a possible member it is set up; otherwise detection fails and the member
/// is reported by getCandidateBoard(). Not used when the board is confirmed or
/// nothing is detected.
board_t fallback_board = board_t::board_unknown;
/// Skips detection and sets up this board. init() fails if the board is not
/// supported on this chip (getFixedBoard() stays unknown) or its display setup
/// fails (getFixedBoard() still reports it). Never saved to NVS.
/// On SDL it takes precedence over M5GFX_BOARD.
board_t fixed_board = board_t::board_unknown;
};
//----------------------------------------------------------------------------
Expand Down Expand Up @@ -220,9 +230,15 @@ namespace m5gfx
using LGFXBase::drawBitmap;

static M5GFX* getInstance(void) { return _instance; }
board_t getBoardCandidate(void) const { return _board_candidate; }
/// Weak guess from the last init() when no board was set up; board_unknown otherwise.
/// The guessed board is not set up.
board_t getCandidateBoard(void) const { return _board_candidate; }
/// Board accepted from detect_config_t::fixed_board by the last init(), even if
/// its display setup failed; board_unknown otherwise.
board_t getFixedBoard(void) const { return _fixed_board; }
/// Stores the settings for the next detection. See detect_config_t.
void setDetectConfig(const detect_config_t& config);
/// Returns the stored settings, as requested.
const detect_config_t& getDetectConfig(void) const { return _detect_config; }

void progressBar(int x, int y, int w, int h, uint8_t val);
Expand Down
9 changes: 5 additions & 4 deletions src/lgfx/v1/misc/enum.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -480,10 +480,11 @@ namespace lgfx

enum error_t
{ unknown_err
, invalid_arg // 引数が範囲外等でinvalidな場合のエラー;
, connection_lost // 通信が切断されたり正しく行えない場合のエラー;
, mode_mismatch // I2C通信が書込みモード時に読込みを指示するなど不一致な操作を行った場合のエラー;
, periph_device_err // ペリフェラルが動作していない等のエラー;
, invalid_arg // an argument is out of range or otherwise invalid
, connection_lost // communication was lost or could not be completed (e.g. no ACK)
, mode_mismatch // the call does not match the transaction state: reading while writing (or the reverse),
// a nested beginTransaction, or a call from a task that does not own the I2C transaction
, periph_device_err // the peripheral is not working
};

//----------------------------------------------------------------------------
Expand Down
44 changes: 23 additions & 21 deletions src/lgfx/v1/platforms/esp32/Bus_SPI.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ Original Source:
#elif __has_include(<hal/gdma_channel.h>)
#include <hal/gdma_channel.h>
#endif
// SPI の DMA が AXI 経由のチップ (ESP32-P4) はディスクリプタが 16 バイト (8 バイト境界)。判定は IDF の spi_dma_desc_t と同じ。
// 境界は MALLOC_CAP_DMA の確保で満たされる (IDF がキャッシュ行に揃える)
// On chips whose SPI DMA goes through AXI (ESP32-P4) a descriptor is 16 bytes (8-byte aligned), as IDF's spi_dma_desc_t.
// MALLOC_CAP_DMA allocations satisfy the alignment (IDF aligns them to the cache line).
#if defined ( SOC_GDMA_BUS_AXI ) && defined ( SOC_GDMA_TRIG_PERIPH_SPI2_BUS ) && ( SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AXI )
#define LGFX_SPI_DMA_DESC_ALIGN8
#endif
Expand Down Expand Up @@ -59,21 +59,21 @@ Original Source:
#endif


// Segmented-Configure-Transfer (SCT) を持つチップか。
// SPI の 1 トランザクションは 18 bit 長 (32 KB) が上限で、超える転送はセグメントごとに CPU が完了を待って
// 再起動する必要がある。SCT を持つチップでは CONF バッファを DMA チェーンに挟むことでハードが自力で次の
// セグメントへ進めるので、CPU は開始時の 1 回だけで済む。
// 対象は SCT と GDMA の両方を持つチップ (S3 / C3 / C6 / C2 / H2)。S2 は SCT を持つが DMA が別系統なので対象外。
// この判定はクラスのレイアウトを左右するので SDK のヘッダだけで決める (ユーザー定義マクロで変えると翻訳単位間で
// sizeof(Bus_SPI) が食い違う)。無効化したいときは LGFX_SPI_SCT_DISABLE を Bus_SPI.inl を含む翻訳単位に与える
// (実行時の判定 _sct_ok だけが偽になり、レイアウトは変わらない)
// Whether the chip has Segmented-Configure-Transfer (SCT).
// One SPI transaction is limited to an 18-bit length (32 KB); longer transfers otherwise need the CPU to wait for
// and restart each segment. With SCT a CONF buffer placed in the DMA chain lets the hardware move to the next
// segment by itself, so the CPU starts the transfer only once.
// Targets chips with both SCT and GDMA (S3 / C3 / C6 / C2 / H2). S2 has SCT but a different DMA, so it is excluded.
// This decides the class layout, so only SDK headers are used (a user macro could make sizeof(Bus_SPI) differ
// between translation units). To disable SCT, define LGFX_SPI_SCT_DISABLE for the translation unit that includes
// Bus_SPI.inl (only the runtime flag _sct_ok becomes false; the layout does not change).
#if __has_include(<soc/soc_caps.h>)
#include <soc/soc_caps.h>
#endif
#if __has_include(<esp_idf_version.h>)
#include <esp_idf_version.h>
#endif
#undef LGFX_SPI_SCT // 内部用。外から与えられても SDK の判定で上書きする (再定義警告を避ける)
#undef LGFX_SPI_SCT // Internal. Overridden by the SDK check even if given from outside (avoids a redefinition warning)
#undef LGFX_SPI_SCT_PERIPH // (host): whether that SPI host supports SCT
#if defined ( SOC_GDMA_SUPPORTED )
#if defined ( SOC_SPI_SCT_SUPPORTED ) && SOC_SPI_SCT_SUPPORTED && defined ( SOC_SPI_SCT_SUPPORTED_PERIPH )
Expand Down Expand Up @@ -241,8 +241,8 @@ namespace lgfx
void _setup_dma_desc_links(const uint8_t *data, int32_t len);

#if defined ( LGFX_SPI_SCT )
// Segmented-Configure-Transfer (SCT): 32 KB を超える 1 本の DMA 転送を、セグメントごとの CONF バッファを
// DMA チェーンに挟むことでハードに連続実行させる (CPU は開始時の 1 回だけ)。
// Segmented-Configure-Transfer (SCT): runs a single DMA transfer over 32 KB in hardware by placing a CONF buffer
// per segment in the DMA chain (the CPU starts it only once).
bool _sct_start(const uint8_t* data, uint32_t length);
bool _sct_start_chain(dma_desc_t* first, uint32_t total);
void _sct_put_conf(dma_desc_t*& d, uint32_t*& conf, uint32_t user, uint32_t user1, uint32_t seg, bool last);
Expand All @@ -251,9 +251,9 @@ namespace lgfx
volatile uint32_t* _spi_slave_reg = nullptr;
dma_desc_t* _sct_desc = nullptr;
uint32_t* _sct_conf = nullptr;
uint32_t _sct_desc_capacity = 0; // _sct_desc の確保済み descriptor 数 (_sct_conf はその半分 + 1)
bool _sct_active = false; // SCT で開始した転送が未後始末 (usr_conf を落とす必要がある)
bool _sct_ok = false; // このバスで SCT を使うか (GP-SPI2 のみ、LGFX_SPI_SCT_DISABLE で偽)
uint32_t _sct_desc_capacity = 0; // descriptors allocated for _sct_desc (_sct_conf holds half of that + 1)
bool _sct_active = false; // a transfer started with SCT is not cleaned up yet (usr_conf must be cleared)
bool _sct_ok = false; // whether this bus uses SCT (GP-SPI2 only; false with LGFX_SPI_SCT_DISABLE)
#endif

config_t _cfg;
Expand All @@ -265,13 +265,15 @@ namespace lgfx
volatile uint32_t* _spi_user_reg = nullptr;
volatile uint32_t* _spi_dma_out_link_reg = nullptr;
volatile uint32_t* _spi_dma_out_conf0_reg = nullptr;
// 外部 RAM を転送元にするときに先頭を揃える単位。GDMA の外部メモリブロック幅 (16/32/64 B、IDF の版で異なる) の最大値。
// 揃えるのは転送の先頭 descriptor だけ (後続 descriptor の境界端数は停止しないことを確認済み)
// Alignment of the start of a transfer from external RAM: the largest GDMA external memory block size
// (16/32/64 B, differs by IDF version). Only the first descriptor is aligned (an unaligned tail at later
// descriptor boundaries was confirmed not to stall).
static constexpr uint32_t dma_ext_align = 64;
// 外部 RAM を DMA の転送元にしてよいか (init で決める。偽なら外部 RAM は CPU 経路)
// Whether external RAM may be a DMA source (decided in init; if false, external RAM goes through the CPU).
bool _psram_dma_ok = true;
// 転送開始前に GDMA チャネルをリセットし、前回の異常終了 (underflow 等) の残留データを持ち越さない。
// 残留は転送元を問わず次の転送を壊すので、外部 RAM 対応チップに限らず GDMA を持つ全チップ・全転送で行う
// Reset the GDMA channel before each transfer so leftover data from an earlier abort (underflow etc.) is not carried over.
// Leftovers corrupt the next transfer whatever its source, so this is done on every GDMA chip and every transfer,
// not only on chips that support external RAM.
void dma_channel_reset(void);
// AXI_DMA and the newer AHB_DMA take the descriptor address in a register of its own (unused elsewhere)
volatile uint32_t* _spi_dma_out_link2_reg = nullptr;
Expand Down
Loading
Loading