Skip to content

Commit

Permalink
Touched up documentation, added example
Browse files Browse the repository at this point in the history
  • Loading branch information
ahoenerBE committed Jun 28, 2021
1 parent 9345d25 commit 585f998
Show file tree
Hide file tree
Showing 7 changed files with 327 additions and 3 deletions.
10 changes: 10 additions & 0 deletions Adafruit_RA8875_Due.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ typedef volatile union _SADDR_Type {
Word raw;
} SADDR_Type;

/**
* Redef of the LLI as an entry in a row.
* Uses SADDR_Type union for easier debugging of what's in the SADDR field
*/
typedef volatile struct _RowFrame {
SADDR_Type SADDR;
Word DADDR;
Expand All @@ -30,6 +34,12 @@ typedef volatile struct _Row {
}
} Row;

/**
* Gets a chunk of LLIs and treats them like an entire row of pixels. Good for bulk operations
* @param manager The DMA Manager
* @param row Which row to get
* @return The collection of frames as a row pointer, if within range. Nullptr otherwise
*/
static Row *get_row(DMAManager *manager, size_t row) {
if (row * FRAMES_PER_LINE >= LLI_MAX_FRAMES) {
return nullptr;
Expand Down
98 changes: 96 additions & 2 deletions DMAManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,33 @@
* */
/********************************/
#ifndef FRAMES_PER_LINE
/**
* The number of frames required to draw one line to the screen.
*/
#define FRAMES_PER_LINE 16
#endif
#ifndef LINES_PER_DMA
/**
* The number of lines to be created/filled before the transfer starts
*/
#define LINES_PER_DMA 8
#endif
#ifndef WORKING_DATA_PER_LINE
/**
* The number of bytes required to draw a line on the screen
*/
#define WORKING_DATA_PER_LINE 19
#endif

#define LLI_MAX_FRAMES (FRAMES_PER_LINE * LINES_PER_DMA)
#define WORKING_DATA_SIZE (WORKING_DATA_PER_LINE * LINES_PER_DMA)
/**
* The number of bytes needed to set the lower/upper bytes for one coordinate
*/
#define COORD_BUF_SPACE 4
/**
* How long to wait / buffer the CS pin low or high
*/
#define DMA_CS_HIGH_TRANSFERS 8

// Forward Declaration for class
Expand Down Expand Up @@ -66,8 +81,14 @@ typedef union DMAFunctionData {
} DMAFunctionData;

typedef struct DMACallbackData {
/**
* Data for use in the complete_cb function
*/
void *dataPtr;

/**
* Function called when transfers are complete
*/
void (*complete_cb)(void *);
} DMACallbackData;

Expand Down Expand Up @@ -98,12 +119,19 @@ typedef struct DMA_Data {

void volatile (*on_complete)(SpiDriver *spiDriver);


/**
* Resets the working data idx to 0. Doesn't actually clear data, just allows for overwrite
* @param full_clear Resets last_idx if true
*/
inline void clear_working_data(bool full_clear = false) {
last_storage_idx = full_clear ? 0 : storage_idx;
storage_idx = 0;
}

/**
* Completely resets the DMA_Data instance
* @param full_reset Clears the last_data fields
*/
inline void reset(bool full_reset = false) {
clear_working_data(full_reset);
memset_volatile(&functionData, '\0', sizeof(DMAFunctionData));
Expand All @@ -116,10 +144,21 @@ typedef struct DMA_Data {
on_complete = nullptr;
}

/**
* @param size The amount of bytes needed to add
* @return true if there is space to add, false otherwise
*/
inline bool can_add_working_data(size_t size) const {
return ((storage_idx - 1) + size) < WORKING_DATA_SIZE;
}

/**
* Store sensitive data needed for DMA in a buffer for use during the transfers.
* Provides a size check to make sure the data can be added.
* @param buf The data to store
* @param size The number of bytes being added.
* @return uint8_t ptr to the location of the added data in the permanent buffer for future access.
*/
inline volatile uint8_t *add_working_data(const uint8_t *buf, size_t size) {
if (!can_add_working_data(size)) {
return nullptr;
Expand Down Expand Up @@ -165,6 +204,12 @@ class DMAManager {

volatile LLI *get_next_blank_entry();

/**
* Gets an entry from the chain
* @param idx The idx to get.
* @param force If the index is out of 'size' bounds, will return nullptr unless force is true. Will return the index from the array
* @return The entry, if within range (or if force specified). Nullptr otherwise.
*/
volatile LLI *get_entry(size_t idx, bool force = false);

inline volatile LLI *get_last() {
Expand All @@ -179,16 +224,28 @@ class DMAManager {
* until we're done with the entire chain. This way if an element needs to be removed, all the `next` pointers won't need to be
* rewritten.
* This must be called before passing the beginning entry to DMA
* @return Ptr to the head of the list
*/
volatile LLI *finalize();

/**
* Resets the size counter, does not zero memory
*/
void clear_frames();

/**
* Resets frames & working data
* @param full Clears the 'last_data' fields, if true
*/
void reset(bool full = false);

size_t get_size() const;

bool can_add_entries(uint32_t entries) const;
/**
* @param entries The number of entries to check if available
* @return True if space, false otherwise
*/
bool can_add_entries(size_t entries) const;

DMA_Data *get_cur_data() {
return &transaction_data;
Expand All @@ -197,18 +254,55 @@ class DMAManager {
/************************
* General purpose methods for adding SPI Frames, PIO Frames, etc.
************************/

/**
* @param state The state of the pin (Returns SODR for true, CODR for false)
* @param pin The pin to get the register for
* @return The address for the register.
*/
WoReg *get_pio_reg(bool state, uint8_t pin);

/**
* Gets the register for the chipselect pin
* @param state The state for the pin
* @return The address for the register
*/
WoReg *get_cs_pio_reg(bool state) {
return get_pio_reg(state, _csPin);
}

/**
* Adds an entry to toggle a pin high or low
* @param state The new state of the pin
* @param pin The pin number
* @param pin_mask_ptr A pointer to somewhere with the mask for that pin. The g_APinDescriptor will not work for this purpose.
* @param num_transfers How many transfers to send.
* @return Whether or not the entry was added to the buffer
*/
bool add_entry_pin_toggle(bool state, uint8_t pin, const uint32_t *pin_mask_ptr, size_t num_transfers = 2);

/**
* Specifically adds an entry to toggle the CS pin
* @param state The new state for the pin
* @param num_transfers How many transfers to send. The RA chip requires that CS be high for ~5 CLK cycles before going low again.
* @return Whether or not the entry was added to the buffer.
*/
bool add_entry_cs_pin_toggle(bool state, size_t num_transfers = 2);

/**
* Adds a generic SPI transfer to the list
* @param buf The start of the data to transfer.
* @param qty The number of bytes in the buffer.
* @return Whether or not the entry was added to the list
*/
bool add_entry_spi_transfer(volatile uint8_t *buf, size_t qty);

/**
* Adds all the necessary entries to draw a batch of pixels in an area.
* @param buf The buffer of pixels to add
* @param qty The number of pixels drawn
* @return uint8_t ptr to the start of the working data containing the draw commands (RA8875_CMDWRITE, DATAWRITE, etc)
*/
volatile uint8_t *add_entry_spi_draw_pixels(volatile uint8_t *buf, size_t qty);

/**
Expand Down
2 changes: 1 addition & 1 deletion DMAManagerDue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ size_t DMAManager::get_size() const {
return size;
}

bool DMAManager::can_add_entries(uint32_t entries) const {
bool DMAManager::can_add_entries(size_t entries) const {
bool result = size + entries <= LLI_MAX_FRAMES;
return result;
}
Expand Down
7 changes: 7 additions & 0 deletions DMA_LLI.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
#ifndef ADAFRUIT_RA8875_DMA_LLI_H
#define ADAFRUIT_RA8875_DMA_LLI_H

/*******************************************
*
* Add whatever includes necessary to implement your DMA controller logic.
* Currently only supports Arduino Due
*
********************************************/


#if defined(ARDUINO_SAM_DUE)

Expand Down
6 changes: 6 additions & 0 deletions DMA_LLI_Due.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@

typedef uint32_t Word;

/**
* Bitfield for CTRLA register.
*/
typedef volatile union _CTRLA_Field {
_CTRLA_Field() : raw(0) {};

Expand All @@ -25,6 +28,9 @@ typedef volatile union _CTRLA_Field {
Word raw;
} CTRLA_Field;

/**
* Bitfield for CTRLB Register
*/
typedef volatile union _CTRLB_Field {
_CTRLB_Field() : _CTRLB_Field(0) {};

Expand Down
54 changes: 54 additions & 0 deletions SpiDriver.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,26 +36,69 @@ class SpiDriver {
public:
explicit SpiDriver(uint8_t csPin, bool interrupts = false);

/**
* Activates the driver. Similar to SPI.beginTransaction or setting clock div, etc.
*/
void activate();

/**
* Deactivates the driver after activate(). Similar to SPI.endTransaction
*/
void deactivate();

/**
* Starts SPI. Usually wraps SPI.begin()
*/
void begin();

/**
* Ends SPI. Usually wraps SPI.end()
*/
void end();

/**
* Reads 1 byte from SPI
* @return Read data
*/
uint8_t receive();

/**
* Reads 2 bytes
* @return Bytes read
*/
uint16_t receive16();

/**
* Read n bytes
* @param buf buffer to read into
* @param count number of bytes to read
* @return A status code
*/
uint8_t receive(uint8_t *buf, size_t count);

/**
* Sends 1 byte
* @param data Data to send
*/
void send(uint8_t data);

/**
* Sends 2 bytes of data
* @param data The data to send
*/
void send16(uint16_t data);

/**
* Send n bytes
* @param buf The start of the buffer to send
* @param count Number of bytes
*/
void send(uint8_t *buf, size_t count);

/**
* Sets the clock speed for the SPI controller
* @param speed Speed in Hz
*/
inline void setClockSpeed(uint32_t speed) {
#if SPI_HAS_TRANSACTION
_spiSettings = SPISettings(speed, MSBFIRST, SPI_MODE0);
Expand All @@ -64,12 +107,23 @@ class SpiDriver {

#if USE_DMA_INTERRUPT

/**
* Get the underlying DMA manager, if available.
* @return The Manager
*/
DMAManager *getDMAManager() {
return &dmaManager;
}

/**
* Sends a chain of DMA frames, if available
* @param head The start of the chain.
*/
void sendChain(volatile LLI *head);

/**
* Starts the next chain of DMA operations
*/
void nextDMA();

#endif
Expand Down
Loading

0 comments on commit 585f998

Please sign in to comment.