mirror of
https://github.com/afska/gba-link-connection.git
synced 2026-04-24 23:47:51 -05:00
Adding LinkSPI
This commit is contained in:
parent
bb436d2f9f
commit
d933cd8589
|
|
@ -77,4 +77,10 @@ Name | Return type | Description
|
|||
`getMode(pin)` | **LinkGPIO::Direction** | Returns the direction set at `pin`.
|
||||
`readPin(pin)` | **bool** | Returns whether a `pin` is *HIGH* or not (when set as an input).
|
||||
`writePin(pin, isHigh)` | - | Sets a `pin` to be high or not (when set as an output).
|
||||
`setSIInterrupts(isEnabled)` | - | If it `isEnabled`, a IRQ will be generated when `SI` changes from *HIGH* to *LOW*.
|
||||
`setSIInterrupts(isEnabled)` | - | If it `isEnabled`, a IRQ will be generated when `SI` changes from *HIGH* to *LOW*.
|
||||
|
||||
# LinkSPI
|
||||
|
||||
// TODO: WRITE
|
||||
|
||||

|
||||
|
|
|
|||
|
|
@ -1,18 +1,21 @@
|
|||
#include <tonc.h>
|
||||
#include <string>
|
||||
|
||||
// (0) Include the header
|
||||
#include "../../_lib/LinkGPIO.h"
|
||||
|
||||
void log(std::string text);
|
||||
std::string mode(std::string name, LinkGPIO::Pin pin);
|
||||
std::string value(std::string name, LinkGPIO::Pin pin, bool isHigh);
|
||||
|
||||
// (1) Create a LinkGPIO instance
|
||||
LinkGPIO* linkGPIO = new LinkGPIO();
|
||||
|
||||
void init() {
|
||||
REG_DISPCNT = DCNT_MODE0 | DCNT_BG0;
|
||||
tte_init_se_default(0, BG_CBB(0) | BG_SBB(31));
|
||||
|
||||
// (2) Initialize the library
|
||||
linkGPIO->reset();
|
||||
}
|
||||
|
||||
|
|
|
|||
284
examples/LinkSPI_basic/Makefile
Normal file
284
examples/LinkSPI_basic/Makefile
Normal file
|
|
@ -0,0 +1,284 @@
|
|||
#
|
||||
# Template tonc makefile
|
||||
#
|
||||
# Yoinked mostly from DKP's template
|
||||
#
|
||||
|
||||
# === SETUP ===========================================================
|
||||
|
||||
# --- No implicit rules ---
|
||||
.SUFFIXES:
|
||||
|
||||
# --- Paths ---
|
||||
export TONCLIB := ${DEVKITPRO}/libtonc
|
||||
|
||||
# === TONC RULES ======================================================
|
||||
#
|
||||
# Yes, this is almost, but not quite, completely like to
|
||||
# DKP's base_rules and gba_rules
|
||||
#
|
||||
|
||||
export PATH := $(DEVKITARM)/bin:$(PATH)
|
||||
|
||||
|
||||
# --- Executable names ---
|
||||
|
||||
PREFIX ?= arm-none-eabi-
|
||||
|
||||
export CC := $(PREFIX)gcc
|
||||
export CXX := $(PREFIX)g++
|
||||
export AS := $(PREFIX)as
|
||||
export AR := $(PREFIX)ar
|
||||
export NM := $(PREFIX)nm
|
||||
export OBJCOPY := $(PREFIX)objcopy
|
||||
|
||||
# LD defined in Makefile
|
||||
|
||||
|
||||
# === LINK / TRANSLATE ================================================
|
||||
|
||||
%.gba : %.elf
|
||||
@$(OBJCOPY) -O binary $< $@
|
||||
@echo built ... $(notdir $@)
|
||||
@gbafix $@ -t$(TITLE)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
%.mb.elf :
|
||||
@echo Linking multiboot
|
||||
$(LD) -specs=gba_mb.specs $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
|
||||
$(NM) -Sn $@ > $(basename $(notdir $@)).map
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
%.elf :
|
||||
@echo Linking cartridge
|
||||
$(LD) -specs=gba.specs $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
|
||||
$(NM) -Sn $@ > $(basename $(notdir $@)).map
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
%.a :
|
||||
@echo $(notdir $@)
|
||||
@rm -f $@
|
||||
$(AR) -crs $@ $^
|
||||
|
||||
|
||||
# === OBJECTIFY =======================================================
|
||||
|
||||
%.iwram.o : %.iwram.cpp
|
||||
@echo $(notdir $<)
|
||||
$(CXX) -MMD -MP -MF $(DEPSDIR)/$*.d $(CXXFLAGS) $(IARCH) -c $< -o $@
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
%.iwram.o : %.iwram.c
|
||||
@echo $(notdir $<)
|
||||
$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d $(CFLAGS) $(IARCH) -c $< -o $@
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
%.o : %.cpp
|
||||
@echo $(notdir $<)
|
||||
$(CXX) -MMD -MP -MF $(DEPSDIR)/$*.d $(CXXFLAGS) $(RARCH) -c $< -o $@
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
%.o : %.c
|
||||
@echo $(notdir $<)
|
||||
$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d $(CFLAGS) $(RARCH) -c $< -o $@
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
%.o : %.s
|
||||
@echo $(notdir $<)
|
||||
$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
%.o : %.S
|
||||
@echo $(notdir $<)
|
||||
$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@
|
||||
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# canned command sequence for binary data
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
define bin2o
|
||||
bin2s $< | $(AS) -o $(@)
|
||||
echo "extern const u8" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(<F) | tr . _)`.h
|
||||
echo "extern const u8" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(<F) | tr . _)`.h
|
||||
echo "extern const u32" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(<F) | tr . _)`.h
|
||||
endef
|
||||
# =====================================================================
|
||||
|
||||
# --- Main path ---
|
||||
|
||||
export PATH := $(DEVKITARM)/bin:$(PATH)
|
||||
|
||||
|
||||
# === PROJECT DETAILS =================================================
|
||||
# PROJ : Base project name
|
||||
# TITLE : Title for ROM header (12 characters)
|
||||
# LIBS : Libraries to use, formatted as list for linker flags
|
||||
# BUILD : Directory for build process temporaries. Should NOT be empty!
|
||||
# SRCDIRS : List of source file directories
|
||||
# DATADIRS : List of data file directories
|
||||
# INCDIRS : List of header file directories
|
||||
# LIBDIRS : List of library directories
|
||||
# General note: use `.' for the current dir, don't leave the lists empty.
|
||||
|
||||
export PROJ ?= $(notdir $(CURDIR))
|
||||
TITLE := $(PROJ)
|
||||
|
||||
LIBS := -ltonc -lugba
|
||||
|
||||
BUILD := build
|
||||
SRCDIRS := src ../_lib
|
||||
DATADIRS := data
|
||||
INCDIRS := src
|
||||
LIBDIRS := $(TONCLIB) $(PWD)/../_lib/libugba
|
||||
|
||||
# --- switches ---
|
||||
|
||||
bMB := 0 # Multiboot build
|
||||
bTEMPS := 0 # Save gcc temporaries (.i and .s files)
|
||||
bDEBUG2 := 0 # Generate debug info (bDEBUG2? Not a full DEBUG flag. Yet)
|
||||
|
||||
|
||||
# === BUILD FLAGS =====================================================
|
||||
# This is probably where you can stop editing
|
||||
# NOTE: I've noticed that -fgcse and -ftree-loop-optimize sometimes muck
|
||||
# up things (gcse seems fond of building masks inside a loop instead of
|
||||
# outside them for example). Removing them sometimes helps
|
||||
|
||||
# --- Architecture ---
|
||||
|
||||
ARCH := -mthumb-interwork -mthumb
|
||||
RARCH := -mthumb-interwork -mthumb
|
||||
IARCH := -mthumb-interwork -marm -mlong-calls
|
||||
|
||||
# --- Main flags ---
|
||||
|
||||
CFLAGS := -mcpu=arm7tdmi -mtune=arm7tdmi -O2
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += $(INCLUDE)
|
||||
CFLAGS += -ffast-math -fno-strict-aliasing
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
|
||||
|
||||
ASFLAGS := $(ARCH) $(INCLUDE)
|
||||
LDFLAGS := $(ARCH) -Wl,-Map,$(PROJ).map
|
||||
|
||||
# --- switched additions ----------------------------------------------
|
||||
|
||||
# --- Multiboot ? ---
|
||||
ifeq ($(strip $(bMB)), 1)
|
||||
TARGET := $(PROJ).mb
|
||||
else
|
||||
TARGET := $(PROJ)
|
||||
endif
|
||||
|
||||
# --- Save temporary files ? ---
|
||||
ifeq ($(strip $(bTEMPS)), 1)
|
||||
CFLAGS += -save-temps
|
||||
CXXFLAGS += -save-temps
|
||||
endif
|
||||
|
||||
# --- Debug info ? ---
|
||||
|
||||
ifeq ($(strip $(bDEBUG)), 1)
|
||||
CFLAGS += -DDEBUG -g
|
||||
CXXFLAGS += -DDEBUG -g
|
||||
ASFLAGS += -DDEBUG -g
|
||||
LDFLAGS += -g
|
||||
else
|
||||
CFLAGS += -DNDEBUG
|
||||
CXXFLAGS += -DNDEBUG
|
||||
ASFLAGS += -DNDEBUG
|
||||
endif
|
||||
|
||||
|
||||
# === BUILD PROC ======================================================
|
||||
|
||||
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||
|
||||
# Still in main dir:
|
||||
# * Define/export some extra variables
|
||||
# * Invoke this file again from the build dir
|
||||
# PONDER: what happens if BUILD == "" ?
|
||||
|
||||
export OUTPUT := $(CURDIR)/$(TARGET)
|
||||
export VPATH := \
|
||||
$(foreach dir, $(SRCDIRS) , $(CURDIR)/$(dir)) \
|
||||
$(foreach dir, $(DATADIRS), $(CURDIR)/$(dir))
|
||||
|
||||
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||
|
||||
# --- List source and data files ---
|
||||
|
||||
CFILES := $(foreach dir, $(SRCDIRS) , $(notdir $(wildcard $(dir)/*.c)))
|
||||
CPPFILES := $(foreach dir, $(SRCDIRS) , $(notdir $(wildcard $(dir)/*.cpp)))
|
||||
SFILES := $(foreach dir, $(SRCDIRS) , $(notdir $(wildcard $(dir)/*.s)))
|
||||
BINFILES := $(foreach dir, $(DATADIRS), $(notdir $(wildcard $(dir)/*.*)))
|
||||
|
||||
# --- Set linker depending on C++ file existence ---
|
||||
ifeq ($(strip $(CPPFILES)),)
|
||||
export LD := $(CC)
|
||||
else
|
||||
export LD := $(CXX)
|
||||
endif
|
||||
|
||||
# --- Define object file list ---
|
||||
export OFILES := $(addsuffix .o, $(BINFILES)) \
|
||||
$(CFILES:.c=.o) $(CPPFILES:.cpp=.o) \
|
||||
$(SFILES:.s=.o)
|
||||
|
||||
# --- Create include and library search paths ---
|
||||
export INCLUDE := $(foreach dir,$(INCDIRS),-I$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I$(CURDIR)/$(BUILD)
|
||||
|
||||
export LIBPATHS := -L$(CURDIR) $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||
|
||||
# --- Create BUILD if necessary, and run this makefile from there ---
|
||||
|
||||
$(BUILD):
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
@make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
arm-none-eabi-nm -Sn $(OUTPUT).elf > $(BUILD)/$(TARGET).map
|
||||
|
||||
all : $(BUILD)
|
||||
|
||||
clean:
|
||||
@echo clean ...
|
||||
@rm -rf $(BUILD) $(TARGET).elf $(TARGET).gba $(TARGET).sav
|
||||
|
||||
|
||||
else # If we're here, we should be in the BUILD dir
|
||||
|
||||
DEPENDS := $(OFILES:.o=.d)
|
||||
|
||||
# --- Main targets ----
|
||||
|
||||
$(OUTPUT).gba : $(OUTPUT).elf
|
||||
|
||||
$(OUTPUT).elf : $(OFILES)
|
||||
|
||||
-include $(DEPENDS)
|
||||
|
||||
|
||||
endif # End BUILD switch
|
||||
|
||||
# --- More targets ----------------------------------------------------
|
||||
|
||||
.PHONY: clean rebuild start
|
||||
|
||||
rebuild: clean $(BUILD)
|
||||
|
||||
start:
|
||||
start "$(TARGET).gba"
|
||||
|
||||
restart: rebuild start
|
||||
|
||||
# EOF
|
||||
74
examples/LinkSPI_basic/src/main.cpp
Normal file
74
examples/LinkSPI_basic/src/main.cpp
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
#include <tonc.h>
|
||||
#include <string>
|
||||
|
||||
// (0) Include the header
|
||||
#include "../../_lib/LinkSPI.h"
|
||||
|
||||
#define PLAYERS 2
|
||||
|
||||
void log(std::string text);
|
||||
|
||||
LinkSPI* linkSPI = NULL;
|
||||
|
||||
void init() {
|
||||
REG_DISPCNT = DCNT_MODE0 | DCNT_BG0;
|
||||
tte_init_se_default(0, BG_CBB(0) | BG_SBB(31));
|
||||
}
|
||||
|
||||
int main() {
|
||||
init();
|
||||
|
||||
while (true) {
|
||||
std::string output = "";
|
||||
u16 keys = ~REG_KEYS & KEY_ANY;
|
||||
|
||||
if (linkSPI == NULL) {
|
||||
output += "START: Set as Master\n";
|
||||
output += "SELECT: Set as Slave";
|
||||
|
||||
// (1) Create a LinkSPI instance
|
||||
if (keys & KEY_START)
|
||||
linkSPI = new LinkSPI(LinkSPI::Mode::MASTER_256KBPS);
|
||||
if (keys & KEY_SELECT)
|
||||
linkSPI = new LinkSPI(LinkSPI::Mode::SLAVE);
|
||||
} else {
|
||||
// Title
|
||||
auto modeName =
|
||||
linkSPI->getMode() == LinkSPI::Mode::SLAVE ? "Slave" : "Master";
|
||||
output += std::string("[") + modeName + "]\n";
|
||||
output += "(stop: L+R)\n\n";
|
||||
if (!linkSPI->isActive())
|
||||
log(output + "Waiting...");
|
||||
|
||||
// Transfer
|
||||
u32 remoteKeys = linkSPI->transfer(keys, []() {
|
||||
u16 keys = ~REG_KEYS & KEY_ANY;
|
||||
return (keys & KEY_L) && (keys & KEY_R);
|
||||
});
|
||||
output += "local: " + std::to_string(keys) + "\n";
|
||||
output += "remote: " + std::to_string(remoteKeys) + "\n";
|
||||
|
||||
// Cancel
|
||||
if ((keys & KEY_L) && (keys & KEY_R)) {
|
||||
linkSPI->deactivate();
|
||||
linkSPI = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Print
|
||||
log(output);
|
||||
|
||||
while (REG_VCOUNT >= 160)
|
||||
; // wait till VDraw
|
||||
while (REG_VCOUNT < 160)
|
||||
; // wait till VBlank
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void log(std::string text) {
|
||||
tte_erase_screen();
|
||||
tte_write("#{P:0,0}");
|
||||
tte_write(text.c_str());
|
||||
}
|
||||
1
examples/_lib/LinkSPI.h
Symbolic link
1
examples/_lib/LinkSPI.h
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../lib/LinkSPI.h
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
#define LINK_CABLE_H
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// A Link Cable connection for Multi-player mode.
|
||||
// A Link Cable connection for Multi-Player mode.
|
||||
// --------------------------------------------------------------------------
|
||||
// Usage:
|
||||
// - 1) Include this header in your main.cpp file and add:
|
||||
|
|
@ -31,7 +31,7 @@
|
|||
// (see examples)
|
||||
// --------------------------------------------------------------------------
|
||||
// `data` restrictions:
|
||||
// 0xFFFF and 0x0 are reserved values, so don't use them
|
||||
// 0xFFFF and 0x0 are reserved values, so don't use them!
|
||||
// (they mean 'disconnected' and 'no data' respectively)
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -25,8 +25,9 @@
|
|||
|
||||
#include <tonc_core.h>
|
||||
|
||||
#define LINK_GPIO_MODE 15
|
||||
#define LINK_GPIO_MODE_GENERAL_PURPOSE (1 << 15)
|
||||
#define LINK_GPIO_BIT_SI_INTERRUPT 8
|
||||
#define LINK_GPIO_GET(REG, BIT) ((REG >> BIT) & 1)
|
||||
#define LINK_GPIO_SET(REG, BIT, DATA) \
|
||||
if (DATA) \
|
||||
LINK_GPIO_SET_HIGH(REG, BIT); \
|
||||
|
|
@ -34,7 +35,6 @@
|
|||
LINK_GPIO_SET_LOW(REG, BIT);
|
||||
#define LINK_GPIO_SET_HIGH(REG, BIT) REG |= 1 << BIT
|
||||
#define LINK_GPIO_SET_LOW(REG, BIT) REG &= ~(1 << BIT)
|
||||
#define LINK_GPIO_GET(REG, BIT) ((REG >> BIT) & 1)
|
||||
|
||||
const u8 LINK_GPIO_DATA_BITS[] = {2, 3, 1, 0};
|
||||
const u8 LINK_GPIO_DIRECTION_BITS[] = {6, 7, 5, 4};
|
||||
|
|
@ -45,7 +45,7 @@ class LinkGPIO {
|
|||
enum Direction { INPUT, OUTPUT };
|
||||
|
||||
void reset() {
|
||||
REG_RCNT = 1 << LINK_GPIO_MODE;
|
||||
REG_RCNT = LINK_GPIO_MODE_GENERAL_PURPOSE;
|
||||
REG_SIOCNT = 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
139
lib/LinkSPI.h
Normal file
139
lib/LinkSPI.h
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
#ifndef LINK_SPI_H
|
||||
#define LINK_SPI_H
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// An SPI handler for the Link Port (Normal Mode, 32bits).
|
||||
// --------------------------------------------------------------------------
|
||||
// Usage:
|
||||
// - 1) Include this header in your main.cpp file and add:
|
||||
// LinkSPI* linkSPI = new LinkSPI(LinkSPI::Mode::MASTER_256KBPS);
|
||||
// // (use LinkSPI::Mode::SLAVE on the other end)
|
||||
// - 2) Exchange 32-bit data with the other end:
|
||||
// u32 data = linkGPIO->transfer(0x1234);
|
||||
// // (this blocks the console indefinitely)
|
||||
// - 3) Exchange data with a cancellation callback:
|
||||
// u32 data = linkGPIO->transfer(0x1234, []() {
|
||||
// u16 keys = ~REG_KEYS & KEY_ANY;
|
||||
// return keys & KEY_START;
|
||||
// });
|
||||
// --------------------------------------------------------------------------
|
||||
// considerations:
|
||||
// - when using Normal Mode between two GBAs, use a GBC Link Cable!
|
||||
// - only use the 2Mbps mode with custom hardware (very short wires)!
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
#include <tonc_core.h>
|
||||
|
||||
#define LINK_SPI_MODE_SPI 0
|
||||
#define LINK_SPI_MODE_GENERAL_PURPOSE (1 << 15)
|
||||
#define LINK_SPI_BIT_CLOCK 0
|
||||
#define LINK_SPI_BIT_CLOCK_SPEED 1
|
||||
#define LINK_SPI_BIT_SI 2
|
||||
#define LINK_SPI_BIT_SO 3
|
||||
#define LINK_SPI_BIT_START 7
|
||||
#define LINK_SPI_BIT_LENGTH 12
|
||||
#define LINK_SPI_BIT_IRQ 14
|
||||
#define LINK_SPI_SET_HIGH(REG, BIT) REG |= 1 << BIT
|
||||
#define LINK_SPI_SET_LOW(REG, BIT) REG &= ~(1 << BIT)
|
||||
|
||||
class LinkSPI {
|
||||
public:
|
||||
enum Mode { SLAVE, MASTER_256KBPS, MASTER_2MBPS };
|
||||
|
||||
explicit LinkSPI(Mode mode) { this->mode = mode; }
|
||||
|
||||
bool isActive() { return isEnabled; }
|
||||
|
||||
void activate() {
|
||||
setNormalMode();
|
||||
set32BitPackets();
|
||||
|
||||
if (mode == SLAVE)
|
||||
setSlaveMode();
|
||||
else {
|
||||
setMasterMode();
|
||||
|
||||
if (mode == MASTER_256KBPS)
|
||||
set256KbpsSpeed();
|
||||
else if (mode == MASTER_2MBPS)
|
||||
set2MbpsSpeed();
|
||||
}
|
||||
|
||||
disableTransfer();
|
||||
isEnabled = true;
|
||||
}
|
||||
|
||||
void deactivate() {
|
||||
isEnabled = false;
|
||||
stopTransfer();
|
||||
disableTransfer();
|
||||
setGeneralPurposeMode();
|
||||
}
|
||||
|
||||
u32 transfer(u32 data) {
|
||||
return transfer(data, []() { return false; });
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
u32 transfer(u32 data, F cancel) {
|
||||
if (!isEnabled || isMaster())
|
||||
activate();
|
||||
|
||||
setData(data);
|
||||
enableTransfer();
|
||||
|
||||
while (isMaster() && !isSlaveReady())
|
||||
if (cancel())
|
||||
return 0;
|
||||
|
||||
startTransfer();
|
||||
|
||||
while (!isReady())
|
||||
if (cancel())
|
||||
return 0;
|
||||
|
||||
disableTransfer();
|
||||
return getData();
|
||||
}
|
||||
|
||||
Mode getMode() { return mode; }
|
||||
|
||||
private:
|
||||
Mode mode;
|
||||
bool isEnabled = false;
|
||||
|
||||
void setNormalMode() {
|
||||
REG_RCNT = LINK_SPI_MODE_SPI;
|
||||
REG_SIOCNT = 0;
|
||||
}
|
||||
|
||||
void setGeneralPurposeMode() {
|
||||
REG_RCNT = LINK_SPI_MODE_GENERAL_PURPOSE;
|
||||
REG_SIOCNT = 0;
|
||||
}
|
||||
|
||||
void setData(u32 data) { REG_SIODATA32 = data; }
|
||||
u32 getData() { return REG_SIODATA32; }
|
||||
|
||||
void enableTransfer() { setBitLow(LINK_SPI_BIT_SO); }
|
||||
void disableTransfer() { setBitHigh(LINK_SPI_BIT_SO); }
|
||||
void startTransfer() { setBitHigh(LINK_SPI_BIT_START); }
|
||||
void stopTransfer() { setBitLow(LINK_SPI_BIT_START); }
|
||||
bool isReady() { return !isBitHigh(LINK_SPI_BIT_START); }
|
||||
bool isSlaveReady() { return !isBitHigh(LINK_SPI_BIT_SI); }
|
||||
|
||||
void set32BitPackets() { setBitHigh(LINK_SPI_BIT_LENGTH); }
|
||||
void setMasterMode() { setBitHigh(LINK_SPI_BIT_CLOCK); }
|
||||
void setSlaveMode() { setBitLow(LINK_SPI_BIT_CLOCK); }
|
||||
void set256KbpsSpeed() { setBitLow(LINK_SPI_BIT_CLOCK_SPEED); }
|
||||
void set2MbpsSpeed() { setBitHigh(LINK_SPI_BIT_CLOCK_SPEED); }
|
||||
|
||||
bool isMaster() { return mode != SLAVE; }
|
||||
bool isBitHigh(u8 bit) { return (REG_SIOCNT >> bit) & 1; }
|
||||
void setBitHigh(u8 bit) { LINK_SPI_SET_HIGH(REG_SIOCNT, bit); }
|
||||
void setBitLow(u8 bit) { LINK_SPI_SET_LOW(REG_SIOCNT, bit); }
|
||||
};
|
||||
|
||||
extern LinkSPI* linkSPI;
|
||||
|
||||
#endif // LINK_SPI_H
|
||||
Loading…
Reference in New Issue
Block a user