From ee097dd80ef9f7c2b4ddbc35f4403c73e46c22ee Mon Sep 17 00:00:00 2001 From: Rodrigo Alfonso Date: Fri, 9 Aug 2024 07:11:49 -0300 Subject: [PATCH] Making SPI receive the DataSize so 8-bit and 32-bit packets can be used in the same project --- README.md | 5 +- examples/LinkSPI_demo/src/main.cpp | 7 ++- lib/LinkRawWireless.hpp | 4 +- lib/LinkSPI.hpp | 98 +++++++++++++++--------------- lib/LinkWireless.hpp | 2 +- 5 files changed, 59 insertions(+), 57 deletions(-) diff --git a/README.md b/README.md index 7a9bb06..0795219 100644 --- a/README.md +++ b/README.md @@ -310,7 +310,7 @@ Name | Return type | Description *(aka Normal Mode)* -This is the GBA's implementation of SPI. You can use this to interact with other GBAs or computers that know SPI. By default, it uses 32-bit packets, but you can switch to 8-bit by enabling the compile-time constant `LINK_SPI_8BIT_MODE`. +This is the GBA's implementation of SPI. You can use this to interact with other GBAs or computers that know SPI. ![screenshot](https://user-images.githubusercontent.com/1631752/213068614-875049f6-bb01-41b6-9e30-98c73cc69b25.png) @@ -319,7 +319,7 @@ This is the GBA's implementation of SPI. You can use this to interact with other Name | Return type | Description --- | --- | --- `isActive()` | **bool** | Returns whether the library is active or not. -`activate(mode)` | - | Activates the library in a specific `mode` (one of `LinkSPI::Mode::SLAVE`, `LinkSPI::Mode::MASTER_256KBPS`, or `LinkSPI::Mode::MASTER_2MBPS`). +`activate(mode, [dataSize])` | - | Activates the library in a specific `mode` (one of `LinkSPI::Mode::SLAVE`, `LinkSPI::Mode::MASTER_256KBPS`, or `LinkSPI::Mode::MASTER_2MBPS`). By default, the `dataSize` is 32-bit, but can be changed to `LinkSPI::DataSize::SIZE_8BIT`. `deactivate()` | - | Deactivates the library. `transfer(data)` | **u32** | Exchanges `data` with the other end. Returns the received data. `transfer(data, cancel)` | **u32** | Like `transfer(data)` but accepts a `cancel()` function. The library will continuously invoke it, and abort the transfer if it returns `true`. @@ -327,6 +327,7 @@ Name | Return type | Description `getAsyncState()` | **LinkSPI::AsyncState** | Returns the state of the last async transfer (one of `LinkSPI::AsyncState::IDLE`, `LinkSPI::AsyncState::WAITING`, or `LinkSPI::AsyncState::READY`). `getAsyncData()` | **u32** | If the async state is `READY`, returns the remote data and switches the state back to `IDLE`. If not, returns an empty response. `getMode()` | **LinkSPI::Mode** | Returns the current `mode`. +`getDataSize()` | **LinkSPI::DataSize** | Returns the current `dataSize`. `setWaitModeActive(isActive)` | - | Enables or disables `waitMode` (*). `isWaitModeActive()` | **bool** | Returns whether `waitMode` (*) is active or not. diff --git a/examples/LinkSPI_demo/src/main.cpp b/examples/LinkSPI_demo/src/main.cpp index c54c07d..23212e3 100644 --- a/examples/LinkSPI_demo/src/main.cpp +++ b/examples/LinkSPI_demo/src/main.cpp @@ -42,14 +42,17 @@ int main() { output += "\n(stop: press L+R)\n"; output += "(hold A on start for async)\n"; output += "(hold B on start for waitMode)\n"; + output += "(hold UP for 8-bit mode)\n"; output += - "\n\n\n\n\n\n\n\n\n\n\n\n[!] to test this demo...\n " + "\n\n\n\n\n\n\n\n\n[!] to test this demo...\n " "...use a GBC Link Cable!"; if ((keys & KEY_START) | (keys & KEY_SELECT)) { // (3) Initialize the library linkSPI->activate((keys & KEY_START) ? LinkSPI::Mode::MASTER_256KBPS - : LinkSPI::Mode::SLAVE); + : LinkSPI::Mode::SLAVE, + (keys & KEY_UP) ? LinkSPI::DataSize::SIZE_8BIT + : LinkSPI::DataSize::SIZE_32BIT); linkSPI->setWaitModeActive(keys & KEY_B); // see `waitMode` in README.md if (keys & KEY_A) diff --git a/lib/LinkRawWireless.hpp b/lib/LinkRawWireless.hpp index 5705a74..e055272 100644 --- a/lib/LinkRawWireless.hpp +++ b/lib/LinkRawWireless.hpp @@ -1014,7 +1014,7 @@ class LinkRawWireless { false, customAck); if (customAck && !acknowledge()) - return LINK_SPI_NO_DATA; + return LINK_SPI_NO_DATA_32; return receivedData; } @@ -1032,7 +1032,7 @@ class LinkRawWireless { false, true); if (!reverseAcknowledgeStart()) - return LINK_SPI_NO_DATA; + return LINK_SPI_NO_DATA_32; return receivedData; } diff --git a/lib/LinkSPI.hpp b/lib/LinkSPI.hpp index c0f40b8..cf61d3a 100644 --- a/lib/LinkSPI.hpp +++ b/lib/LinkSPI.hpp @@ -42,37 +42,14 @@ #include "_link_common.hpp" -/** - * @brief 8-bit mode (uncomment to enable) - */ -// #define LINK_SPI_8BIT_MODE - static volatile char LINK_SPI_VERSION[] = "LinkSPI/v7.0.0"; -#ifdef LINK_SPI_8BIT_MODE -#define LINK_SPI_DATA_TYPE u8 -#endif -#ifndef LINK_SPI_8BIT_MODE -#define LINK_SPI_DATA_TYPE u32 -#endif - -#ifdef LINK_SPI_8BIT_MODE -#define LINK_SPI_DATA_REG Link::_REG_SIODATA8 -#endif -#ifndef LINK_SPI_8BIT_MODE -#define LINK_SPI_DATA_REG Link::_REG_SIODATA32 -#endif - -#ifdef LINK_SPI_8BIT_MODE -#define LINK_SPI_NO_DATA 0xff -#endif -#ifndef LINK_SPI_8BIT_MODE -#define LINK_SPI_NO_DATA 0xffffffff -#endif +#define LINK_SPI_NO_DATA_32 0xffffffff +#define LINK_SPI_NO_DATA_8 0xff +#define LINK_SPI_NO_DATA LINK_SPI_NO_DATA_32 /** * @brief An SPI handler for the Link Port (Normal Mode, either 32 or 8 bits). - * 32-bit transfers by default. Set `LINK_SPI_8BIT_MODE` for 8-bit transfers. */ class LinkSPI { private: @@ -92,6 +69,7 @@ class LinkSPI { public: enum Mode { SLAVE, MASTER_256KBPS, MASTER_2MBPS }; + enum DataSize { SIZE_32BIT, SIZE_8BIT }; enum AsyncState { IDLE, WAITING, READY }; /** @@ -102,9 +80,11 @@ class LinkSPI { /** * @brief Activates the library in a specific `mode`. * @param mode One of the enum values from `LinkSPI::Mode`. + * @param dataSize One of the enum values from `LinkSPI::DataSize`. */ - void activate(Mode mode) { + void activate(Mode mode, DataSize dataSize = SIZE_32BIT) { this->mode = mode; + this->dataSize = dataSize; this->waitMode = false; this->asyncState = IDLE; this->asyncData = 0; @@ -144,7 +124,7 @@ class LinkSPI { * @param data The value to be sent. * \warning Blocks the system until completion. */ - LINK_SPI_DATA_TYPE transfer(LINK_SPI_DATA_TYPE data) { + u32 transfer(u32 data) { return transfer(data, []() { return false; }); } @@ -156,12 +136,12 @@ class LinkSPI { * \warning Blocks the system until completion or cancellation. */ template - LINK_SPI_DATA_TYPE transfer(LINK_SPI_DATA_TYPE data, - F cancel, - bool _async = false, - bool _customAck = false) { + u32 transfer(u32 data, + F cancel, + bool _async = false, + bool _customAck = false) { if (asyncState != IDLE) - return LINK_SPI_NO_DATA; + return noData(); setData(data); @@ -177,20 +157,20 @@ class LinkSPI { disableTransfer(); setInterruptsOff(); asyncState = IDLE; - return LINK_SPI_NO_DATA; + return noData(); } enableTransfer(); startTransfer(); if (_async) - return LINK_SPI_NO_DATA; + return noData(); while (!isReady()) if (cancel()) { stopTransfer(); disableTransfer(); - return LINK_SPI_NO_DATA; + return noData(); } if (!_customAck) @@ -207,7 +187,7 @@ class LinkSPI { * \warning If `waitMode` (*) is active, blocks the system until completion. * See `setWaitModeActive(...)`. */ - void transferAsync(LINK_SPI_DATA_TYPE data) { + void transferAsync(u32 data) { transfer(data, []() { return false; }, true); } @@ -222,7 +202,7 @@ class LinkSPI { * cancellation. See `setWaitModeActive(...)`. */ template - void transferAsync(LINK_SPI_DATA_TYPE data, F cancel) { + void transferAsync(u32 data, F cancel) { transfer(data, cancel, true); } @@ -236,11 +216,11 @@ class LinkSPI { * @brief If the async state is `READY`, returns the remote data and switches * the state back to `IDLE`. If not, returns an empty response. */ - [[nodiscard]] LINK_SPI_DATA_TYPE getAsyncData() { + [[nodiscard]] u32 getAsyncData() { if (asyncState != READY) - return LINK_SPI_NO_DATA; + return noData(); - LINK_SPI_DATA_TYPE data = asyncData; + u32 data = asyncData; asyncState = IDLE; return data; } @@ -250,6 +230,11 @@ class LinkSPI { */ [[nodiscard]] Mode getMode() { return mode; } + /** + * @brief Returns the current `dataSize`. + */ + [[nodiscard]] DataSize getDataSize() { return dataSize; } + /** * @brief Enables or disables `waitMode`: The GBA adds an extra feature over * SPI. When working as master, it can check whether the other terminal is @@ -304,19 +289,19 @@ class LinkSPI { private: Mode mode = Mode::SLAVE; + DataSize dataSize = DataSize::SIZE_32BIT; bool waitMode = false; AsyncState asyncState = IDLE; - LINK_SPI_DATA_TYPE asyncData = 0; + u32 asyncData = 0; volatile bool isEnabled = false; void setNormalMode() { Link::_REG_RCNT = Link::_REG_RCNT & ~(1 << BIT_GENERAL_PURPOSE_HIGH); -#ifdef LINK_SPI_8BIT_MODE - Link::_REG_SIOCNT = 0; -#endif -#ifndef LINK_SPI_8BIT_MODE - Link::_REG_SIOCNT = 1 << BIT_LENGTH; -#endif + + if (dataSize == SIZE_32BIT) + Link::_REG_SIOCNT = 1 << BIT_LENGTH; + else + Link::_REG_SIOCNT = 0; } void setGeneralPurposeMode() { @@ -324,8 +309,21 @@ class LinkSPI { (1 << BIT_GENERAL_PURPOSE_HIGH); } - void setData(LINK_SPI_DATA_TYPE data) { LINK_SPI_DATA_REG = data; } - LINK_SPI_DATA_TYPE getData() { return LINK_SPI_DATA_REG; } + void setData(u32 data) { + if (dataSize == SIZE_32BIT) + Link::_REG_SIODATA32 = data; + else + Link::_REG_SIODATA8 = data & 0xff; + } + + u32 getData() { + return dataSize == SIZE_32BIT ? Link::_REG_SIODATA32 + : Link::_REG_SIODATA8 & 0xff; + } + + u32 noData() { + return dataSize == SIZE_32BIT ? LINK_SPI_NO_DATA_32 : LINK_SPI_NO_DATA_8; + } void enableTransfer() { _setSOLow(); } void disableTransfer() { _setSOHigh(); } diff --git a/lib/LinkWireless.hpp b/lib/LinkWireless.hpp index 0c0cdf0..4dca399 100644 --- a/lib/LinkWireless.hpp +++ b/lib/LinkWireless.hpp @@ -1792,7 +1792,7 @@ class LinkWireless { false, customAck); if (customAck && !acknowledge()) - return LINK_SPI_NO_DATA; + return LINK_SPI_NO_DATA_32; return receivedData; }