T4 SPI DMA is a work in progress

pull/9/head
Steve Lascos 5 years ago
parent 5ee7688e5d
commit 699242362c
  1. 11
      keywords.txt
  2. 4
      src/BAAudioControlWM8731.h
  3. 263
      src/BAHardware.h
  4. 28
      src/BAPhysicalControls.h
  5. 32
      src/BASpiMemory.h
  6. 155
      src/DmaSpi.h
  7. 1
      src/LibMemoryManagement.h
  8. 2
      src/common/AudioDelay.cpp
  9. 99
      src/common/BAHardware.cpp
  10. 31
      src/common/ExternalSramManager.cpp
  11. 35
      src/effects/AudioEffectDelayExternal.cpp
  12. 38
      src/peripherals/BAAudioControlWM8731.cpp
  13. 41
      src/peripherals/BAPhysicalControls.cpp
  14. 309
      src/peripherals/BASpiMemory.cpp
  15. 4
      src/peripherals/DmaSpi.cpp

@ -1,5 +1,5 @@
#######################################
# Syntax Coloring Map For ExampleLibrary
# Syntax Coloring Map For BALibrary
#######################################
#######################################
@ -15,11 +15,18 @@ BAAudioEffectDelayExternal KEYWORD1
# Methods and Functions (KEYWORD2)
#######################################
doSomething KEYWORD2
TGA_PRO_REVA KEYWORD2
TGA_PRO_REVB KEYWORD2
TGA_PRO_EXPAND_REV2 KEYWORD2
SPI_MEM0_1M KEYWORD2
SPI_MEM0_4M KEYWORD2
SPI_MEM1_1M KEYWORD2
SPI_MEM1_4M KEYWORD2
#######################################
# Instances (KEYWORD2)
#######################################
BAHardwareConfig KEYWORD1
#######################################
# Constants (LITERAL1)

@ -123,9 +123,13 @@ protected:
private:
// low-level write command
bool write(unsigned int reg, unsigned int val);
// resets the internal shadow register array
void resetInternalReg(void);
// Sets pullups, slew rate and drive strength
void setOutputStrength(void);
bool m_wireStarted = false;
};

@ -32,19 +32,164 @@
*****************************************************************************/
namespace BALibrary {
// uncomment the line that corresponds to your hardware
//#define TGA_PRO_REVA
#if (!defined(TGA_PRO_REVA) && !defined(TGA_PRO_REVB))
#define TGA_PRO_REVA
#endif
// In your Arudino .ino file, use #defines for your TGA Pro revision and options
// to correctly configure your hardware
#define TGA_PRO_REVA(x) BALibrary::BAHardwareConfig.m_tgaBoard = TgaBoard::REV_A ///< Macro for specifying REV A of the TGA Pro
#define TGA_PRO_REVB(x) BALibrary::BAHardwareConfig.m_tgaBoard = TgaBoard::REV_B ///< Macro for specifying REV B of the TGA Pro
#define TGA_PRO_EXPAND_REV2(x) BALibrary::BAHardwareConfig.m_expansionBoard = ExpansionBoard::REV_1 ///< Macro for specifying REV 1 of the Expansion Board
#define SPI_MEM0_1M(x) BALibrary::BAHardwareConfig.m_spiMem0 = SPI_MEMORY_1M ///< Macro for specifying MEM0 is 1Mbit
#define SPI_MEM0_4M(x) BALibrary::BAHardwareConfig.m_spiMem0 = SPI_MEMORY_4M ///< Macro for specifying MEM1 is 4Mbit
#define SPI_MEM1_1M(x) BALibrary::BAHardwareConfig.m_spiMem1 = SPI_MEMORY_1M ///< Macro for specifying MEM0 is 1Mbit
#define SPI_MEM1_4M(x) BALibrary::BAHardwareConfig.m_spiMem1 = SPI_MEMORY_4M ///< Macro for specifying MEM1 is 1Mbit
#if defined(TGA_PRO_REVA) || defined(TGA_PRO_REVB)
/******************************************************************************
* Hardware Configuration
*****************************************************************************/
/// enum to specify the TGA Board revision
enum class TgaBoard : unsigned {
REV_A = 0, ///< indicates using REV A of the TGA Pro
REV_B ///< indicates using REV B of the TGA Pro
};
constexpr uint8_t USR_LED_ID = 16; ///< Teensy IO number for the user LED.
/// enum to specify the TGA Pro Expansion Board revision
enum class ExpansionBoard : unsigned {
NO_EXPANSION = 0, ///< default, indicates no expansion board is present
REV_1, ///< indicates using REV 1 of the Expansion Board
REV_2 ///< indicates using REV 2 of the Expansion Board
};
/// enum to specify SPI memory dize
enum class SpiMemorySize : unsigned {
NO_MEMORY = 0, ///< default, indicates no SPI memory installed
MEM_1M, ///< indicates 1Mbit memory is installed
MEM_4M ///< indicates 4Mbit memory is installed
};
constexpr unsigned NUM_MEM_SLOTS = 2; ///< The TGA Pro has two SPI ports for memory
/// enum to specify MEM0 or MEM1
enum MemSelect : unsigned {
MEM0 = 0, ///< SPI RAM MEM0
MEM1 = 1 ///< SPI RAM MEM1
};
/******************************************************************************
* SPI Memory Definitions
*****************************************************************************/
/// stores Spi memory size information
struct SpiMemoryDefinition {
size_t MEM_SIZE_BYTES;
size_t DIE_BOUNDARY;
};
/// Settings for 4Mbit SPI MEM
constexpr SpiMemoryDefinition SPI_MEMORY_4M = {
.MEM_SIZE_BYTES = 524288,
.DIE_BOUNDARY = 262144
};
/// Settings for 1Mbit SPI MEM
constexpr SpiMemoryDefinition SPI_MEMORY_1M = {
.MEM_SIZE_BYTES = 131072,
.DIE_BOUNDARY = 0
};
/// Settings for No memory
constexpr SpiMemoryDefinition SPI_MEMORY_NONE = {
.MEM_SIZE_BYTES = 0,
.DIE_BOUNDARY = 0
};
/******************************************************************************
* General Purpose SPI Interfaces
*****************************************************************************/
/// enum to specify which SPI port is being used
enum class SpiDeviceId : unsigned {
SPI_DEVICE0 = 0, ///< Arduino SPI device
SPI_DEVICE1 = 1 ///< Arduino SPI1 device
};
/**************************************************************************//**
* GPIOs and Testpoints are accessed via enumerated class constants.
* BAHardware is a global object that holds hardware configuration options for
* board revisions and ordering options. It is created automatically, and only
* one is present. For configuration, the MACROS specified at the top of
* BAHardware.h should be used.
*****************************************************************************/
class BAHardware {
public:
BAHardware() = default; ///< default constructor
/// sets the TGA Pro board revision
/// @param tgaBoard enum to specify board revision
void set(TgaBoard tgaBoard);
/// get the configured TGA Pro board revision
/// @returns enum for the board revision
TgaBoard getTgaBoard(void);
/// sets the Expansion board revision
/// @param expansionBoard enum to specify the expansion board revision
void set(ExpansionBoard expansionBoard);
/// get the configured Expansion Board revision
/// @returns enum for the board revision
ExpansionBoard getExpansionBoard(void);
/// sets the configured size of a SPI memory
/// @param memSelect specifies which memory device you are configuring
/// @param spiMem specifies the memory definition provide (Size, etc.)
void set(MemSelect memSelect, SpiMemoryDefinition spiMem);
/// gets the memory definition for a given memory device
/// @param mem enum to specify memory device to query
SpiMemoryDefinition getSpiMemoryDefinition(MemSelect mem);
/// get the size of the given memory in bytes, defaults to MEM0
/// @param memSelect enum specifies the memory to query
/// @returns size in bytes
size_t getSpiMemSizeBytes(MemSelect memSelect = MemSelect::MEM0);
/// get the size of the given memory in bytes, defaults to MEM0
/// @param memIndex unsigned specifies the memory to query
/// @returns size in bytes
size_t getSpiMemSizeBytes(unsigned memIndex);
/// get the maximum address in a given memory, defaults to MEM0
/// @param memSelect enum specifies the memory to query
/// @returns the last valid address location in the memory
size_t getSpiMemMaxAddr (MemSelect memSelect = MemSelect::MEM0);
/// get the maximum address in a given memory, defaults to MEM0
/// @param memIndex unsigned specifies the memory to query
/// @returns the last valid address location in the memory
size_t getSpiMemMaxAddr (unsigned memIndex);
TgaBoard m_tgaBoard = TgaBoard::REV_B; ///< stores the configured TGA Pro revision
ExpansionBoard m_expansionBoard = ExpansionBoard::NO_EXPANSION; ///< stores the configured Expansion Board revision
SpiMemoryDefinition m_spiMem0 = SPI_MEMORY_NONE; ///< stores the definition for MEM0
SpiMemoryDefinition m_spiMem1 = SPI_MEMORY_NONE; ///< stores the definition for MEM1
};
extern BAHardware BAHardwareConfig; ///< external definition of global configuration class object
/**************************************************************************//**
* Teensy 3.6/3.5 Hardware Pinout
*****************************************************************************/
#if defined(__MK66FX1M0__) || defined(__MK64FX512__) // T3.6 or T3.5
constexpr uint8_t USR_LED_ID = 16; ///< Teensy IO number for the user LED.
// SPI0 and SPI1 pinouts
constexpr uint8_t SPI0_SCK_PIN = 14;
constexpr uint8_t SPI0_CS_PIN = 15;
constexpr uint8_t SPI0_MISO_PIN = 8;
constexpr uint8_t SPI0_MOSI_PIN = 7;
#define SPI1_AVAILABLE
constexpr uint8_t SPI1_SCK_PIN = 20;
constexpr uint8_t SPI1_CS_PIN = 31;
constexpr uint8_t SPI1_MISO_PIN = 5;
constexpr uint8_t SPI1_MOSI_PIN = 21;
// GPIOs and Testpoints are accessed via enumerated class constants.
enum class GPIO : uint8_t {
GPIO0 = 2,
GPIO1 = 3,
@ -61,46 +206,77 @@ enum class GPIO : uint8_t {
};
/**************************************************************************//**
* Optionally installed SPI RAM
* Teensy 4.0 Hardware Settings
*****************************************************************************/
constexpr unsigned NUM_MEM_SLOTS = 2;
enum MemSelect : unsigned {
MEM0 = 0, ///< SPI RAM MEM0
MEM1 = 1 ///< SPI RAM MEM1
};
#elif defined(__IMXRT1062__) // T4.0
constexpr uint8_t USR_LED_ID = 2; ///< Teensy IO number for the user LED.
/**************************************************************************//**
* Set the maximum address (byte-based) in the external SPI memories
*****************************************************************************/
constexpr size_t MEM_MAX_ADDR[NUM_MEM_SLOTS] = { 131071, 131071 };
// SPI0 pinouts
constexpr uint8_t SPI0_SCK_PIN = 13;
constexpr uint8_t SPI0_CS_PIN = 10;
constexpr uint8_t SPI0_MISO_PIN = 12;
constexpr uint8_t SPI0_MOSI_PIN = 11;
// GPIOs and Testpoints are accessed via enumerated class constants.
enum class GPIO : uint8_t {
GPIO0 = 3,
GPIO1 = 4,
GPIO2 = 5,
GPIO3 = 6,
/**************************************************************************//**
* General Purpose SPI Interfaces
*****************************************************************************/
enum class SpiDeviceId : unsigned {
SPI_DEVICE0 = 0, ///< Arduino SPI device
SPI_DEVICE1 = 1 ///< Arduino SPI1 device
};
constexpr int SPI_MAX_ADDR = 131071; ///< Max address size per chip
constexpr size_t SPI_MEM0_SIZE_BYTES = 131072;
constexpr size_t SPI_MEM0_MAX_AUDIO_SAMPLES = SPI_MEM0_SIZE_BYTES/sizeof(int16_t);
GPIO4 = 17,
GPIO5 = 16,
GPIO6 = 15,
GPIO7 = 14,
constexpr size_t SPI_MEM1_SIZE_BYTES = 131072;
constexpr size_t SPI_MEM1_MAX_AUDIO_SAMPLES = SPI_MEM1_SIZE_BYTES/sizeof(int16_t);
TP1 = 9,
TP2 = 22
};
#define SCL_PAD_CTRL IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_00
#define SDA_PAD_CTRL IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_01
constexpr uint32_t SCL_SDA_PAD_CFG = 0xF808;
#define MCLK_PAD_CTRL IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_09
#define BCLK_PAD_CTRL IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_10
#define LRCLK_PAD_CTRL IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_11
#define DAC_PAD_CTRL IOMUXC_SW_PAD_CTL_PAD_GPIO_B1_01
constexpr uint32_t I2S_PAD_CFG = 0x0008;
/**************************************************************************//**
* DEFAULT Teensy 3.2 Hardware Settings
*****************************************************************************/
#else
constexpr uint8_t USR_LED_ID = 16; ///< Teensy IO number for the user LED.
#error "No hardware declared"
// SPI0 and SPI1 pinouts
constexpr uint8_t SPI0_SCK_PIN = 14;
constexpr uint8_t SPI0_CS_PIN = 15;
constexpr uint8_t SPI0_MISO_PIN = 8;
constexpr uint8_t SPI0_MOSI_PIN = 7;
// GPIOs and Testpoints are accessed via enumerated class constants.
enum class GPIO : uint8_t {
GPIO0 = 2,
GPIO1 = 3,
GPIO2 = 4,
GPIO3 = 6,
GPIO4 = 12,
GPIO5 = 32,
GPIO6 = 27,
GPIO7 = 28,
TP1 = 34,
TP2 = 33
};
#endif
#if defined (TGA_PRO_EXPAND_REV2)
/**************************************************************************//**
* Blackaddr Audio Expansion Board
* Blackaddr Audio Expansion Board Pin Configuration
*****************************************************************************/
#if defined(__MK66FX1M0__) || defined(__MK64FX512__) // T3.6 or T3.5
// Teensy 3.6 Pinout
constexpr unsigned BA_EXPAND_NUM_POT = 3;
constexpr unsigned BA_EXPAND_NUM_SW = 2;
constexpr unsigned BA_EXPAND_NUM_LED = 2;
@ -113,9 +289,28 @@ constexpr uint8_t BA_EXPAND_SW1_PIN = 2; // 2)PWM
constexpr uint8_t BA_EXPAND_SW2_PIN = 3; // 3_SCL2_PWM
constexpr uint8_t BA_EXPAND_LED1_PIN = 4; // 4_SDA2_PWM
constexpr uint8_t BA_EXPAND_LED2_PIN = 6; // 6_PWM
#elif defined(__IMXRT1062__)
// Teensy 4.0 pinout
constexpr unsigned BA_EXPAND_NUM_POT = 3;
constexpr unsigned BA_EXPAND_NUM_SW = 2;
constexpr unsigned BA_EXPAND_NUM_LED = 2;
constexpr unsigned BA_EXPAND_NUM_ENC = 0;
constexpr uint8_t BA_EXPAND_POT1_PIN = A0; // 14_A0_TX3_SPDIFOUT
constexpr uint8_t BA_EXPAND_POT2_PIN = A1; // 15_A1_RX3_SPDIFIN
constexpr uint8_t BA_EXPAND_POT3_PIN = A2; // 16_A2_RX4_SCL1
constexpr uint8_t BA_EXPAND_SW1_PIN = 3; // 3_LRCLK2
constexpr uint8_t BA_EXPAND_SW2_PIN = 4; // 4_BCLK2
constexpr uint8_t BA_EXPAND_LED1_PIN = 5; // 5_IN2
constexpr uint8_t BA_EXPAND_LED2_PIN = 6; // 6_OUT1D
#else
#warning Your processor is not yet supported in BALibrary
#endif
} // namespace BALibrary
#endif /* __BALIBRARY_BAHARDWARE_H */

@ -26,6 +26,8 @@
#include <Encoder.h>
#include <Bounce2.h>
#include "Arduino.h"
namespace BALibrary {
constexpr bool SWAP_DIRECTION = true; ///< Use when specifying direction should be swapped
@ -132,12 +134,27 @@ public:
void adjustCalibrationThreshold(float thresholdFactor);
/// Set the amount of feedback in the IIR filter used to smooth the pot readings
/// @details actual filter reponse deptnds on the rate you call getValue()
/// @details actual filter response depends on the rate you call getValue()
/// @param filterValue typical values are 0.80f to 0.95f
void setFeedbackFitlerValue(float fitlerValue);
/// Set the calibration values for the pots
/// @param min analog pot reading for min value
/// @param max analog pot reading for max value
/// @param swapDirection when true min and max are reversed. (Depends on physical pot orientation)
void setCalibrationValues(unsigned min, unsigned max, bool swapDirection);
/// Sets a MINIMUM sampling interval for the pot in milliseconds.
/// @details When making a call to getValue(), if the time since the last reading is
/// less than this interval, a new reading will not be taken.
/// @param intervalMs the desired minimum sampling interval in milliseconds
void setSamplingIntervalMs(unsigned intervalMs);
/// Sets the minimum change between previous reading and new reading to be considered valid.
/// @details Increasing this value will help remove noise. Default is 8.
/// @param changeThreshold new change threshold for ADC
void setChangeThreshold(float changeThreshold);
/// Call this static function before creating the object to obtain calibration data. The sequence
/// involves prompts over the Serial port.
/// @details E.g. call Potentiometer::calibrate(PIN). See BAExpansionCalibrate.ino in the library examples.
@ -151,11 +168,16 @@ private:
unsigned m_minCalibration; ///< stores the min pot value
unsigned m_maxCalibration; ///< stores the max pot value
unsigned m_lastValue = 0; ///< stores previous value
float m_feedbackFitlerValue = 0.9f; ///< feedback value for POT filter
float m_feedbackFitlerValue = 0.8f; ///< feedback value for POT filter
float m_thresholdFactor = 0.05f; ///< threshold factor causes values pot to saturate faster at the limits, default is 5%
unsigned m_minCalibrationThresholded; ///< stores the min pot value after thresholding
unsigned m_maxCalibrationThresholded; ///< stores the max pot value after thresholding
unsigned m_rangeThresholded; ///< stores the range of max - min after thresholding
unsigned m_changeThreshold = 8; ///< a new reading must change by this amount to be valid
unsigned m_lastValidValue = 0; ///< stores previous value
unsigned m_samplingIntervalMs = 20; ///< the sampling interval in milliseconds
elapsedMillis m_timerMs; ///< special Teensy variable that tracks time
};
/// Convenience class for rotary (quadrature) encoders. Uses Arduino Encoder under the hood.
@ -306,8 +328,6 @@ private:
std::vector<DigitalOutput> m_outputs; ///< a vector of all added outputs
};
} // BALibrary
#endif /* __BAPHYSICALCONTROLS_H */

@ -23,6 +23,7 @@
#ifndef __BALIBRARY_BASPIMEMORY_H
#define __BALIBRARY_BASPIMEMORY_H
#include <cstdint>
#include <SPI.h>
#include <DmaSpi.h>
@ -33,7 +34,7 @@ namespace BALibrary {
/**************************************************************************//**
* This wrapper class uses the Arduino SPI (Wire) library to access the SPI ram.
* @details The purpose of this class is primilary for functional testing since
* @details The purpose of this class is primarily for functional testing since
* it currently support single-word access. High performance access should be
* done using DMA techniques in the Teensy library.
*****************************************************************************/
@ -43,7 +44,7 @@ public:
/// Create an object to control either MEM0 (via SPI1) or MEM1 (via SPI2).
/// @details default is 20 Mhz
/// @param memDeviceId specify which MEM to control with SpiDeviceId.
BASpiMemory(SpiDeviceId memDeviceId);
BASpiMemory(SpiDeviceId memDeviceId = SpiDeviceId::SPI_DEVICE0);
/// Create an object to control either MEM0 (via SPI1) or MEM1 (via SPI2)
/// @param memDeviceId specify which MEM to control with SpiDeviceId.
/// @param speedHz specify the desired speed in Hz.
@ -111,16 +112,36 @@ public:
/// @returns true if initialized, false if not yet initialized
bool isStarted() const { return m_started; }
/// Dummy function for non-DMA writes
virtual bool isWriteBusy() const { return false; }
/// Dummy function for non-DMA reads
virtual bool isReadBusy() const { return false; }
protected:
SPIClass *m_spi = nullptr;
SpiDeviceId m_memDeviceId; // the MEM device being control with this instance
uint8_t m_csPin; // the IO pin number for the CS on the controlled SPI device
SPISettings m_settings; // the Wire settings for this SPI port
bool m_started = false;
size_t m_dieBoundary; // the address at which a SPI memory die rollsover
size_t m_bytesToXfer(size_t address, size_t numBytes);
void m_rawWrite (size_t address, uint8_t *src, size_t numBytes); // raw function for writing bytes
void m_rawZero (size_t address, size_t numBytes); // raw function for zeroing memory
void m_rawRead (size_t address, uint8_t *dest, size_t numBytes); // raw function for reading bytes
void m_rawWrite16(size_t address, uint16_t *src, size_t numBytes); // raw function for writing words
void m_rawZero16 (size_t address, size_t numBytes); // raw function for zeroing memory words
void m_rawRead16 (size_t address, uint16_t *dest, size_t numBytes); // raw function for reading words
};
#if !defined (__IMXRT1062__)
/**************************************************************************//**
* This wrapper class uses the Arduino SPI (Wire) library to access the SPI ram
* via DMA.
*****************************************************************************/
class BASpiMemoryDMA : public BASpiMemory {
public:
BASpiMemoryDMA() = delete;
@ -181,11 +202,11 @@ public:
/// Check if a DMA write is in progress
/// @returns true if a write DMA is in progress, else false
bool isWriteBusy() const;
bool isWriteBusy() const override;
/// Check if a DMA read is in progress
/// @returns true if a read DMA is in progress, else false
bool isReadBusy() const;
bool isReadBusy() const override;
/// Readout the 8-bit contents of the DMA storage buffer to the specified destination
/// @param dest pointer to the destination
@ -212,8 +233,9 @@ private:
uint16_t m_txXferCount;
uint16_t m_rxXferCount;
void m_setSpiCmdAddr(int command, size_t address, uint8_t *dest);
void m_setSpiCmdAddr(int command, size_t address, uint8_t *dest);
};
#endif // BASpiMemoryDMA declaration
} /* namespace BALibrary */

@ -12,6 +12,11 @@
#include "DMAChannel.h"
#include <core_pins.h>
//#include <core_cm7.h>
#include <arm_math.h>
//#define DEBUG_DMASPI 1
/** \brief Specifies the desired CS suppression
**/
@ -152,7 +157,6 @@ class ActiveLowChipSelect1 : public AbstractChipSelect
#endif
//#define DEBUG_DMASPI 1
#if defined(DEBUG_DMASPI)
#define DMASPI_PRINT(x) do {Serial.printf x ; Serial.flush();} while (0);
@ -488,8 +492,10 @@ class AbstractDmaSpi
static void post_finishCurrentTransfer() {DMASPI_INSTANCE::post_finishCurrentTransfer_impl();}
// finishCurrentTransfer is called from rxISR_()
static void finishCurrentTransfer()
{
DMASPI_PRINT((" inside finishCurrentTransfer()\n"));
if (m_pCurrentTransfer->m_pSelect != nullptr)
{
m_pCurrentTransfer->m_pSelect->deselect(m_pCurrentTransfer->m_transferType);
@ -581,12 +587,12 @@ class AbstractDmaSpi
{
if (m_pNextTransfer == nullptr)
{
DMASPI_PRINT(("DmaSpi::beginNextTransfer: no pending transfer\n"));
DMASPI_PRINT(("DmaSpi::beginPendingTransfer: no pending transfer\n"));
return;
}
m_pCurrentTransfer = m_pNextTransfer;
DMASPI_PRINT(("DmaSpi::beginNextTransfer: starting transfer @ %p\n", m_pCurrentTransfer));
DMASPI_PRINT(("DmaSpi::beginPendingTransfer: starting transfer @ %p\n", m_pCurrentTransfer));
m_pCurrentTransfer->m_state = Transfer::State::inProgress;
m_pNextTransfer = m_pNextTransfer->m_pNext;
if (m_pNextTransfer == nullptr)
@ -600,6 +606,7 @@ class AbstractDmaSpi
{
// real data sink
DMASPI_PRINT((" real sink\n"));
arm_dcache_flush_delete((void *)m_pCurrentTransfer->m_pDest, m_pCurrentTransfer->m_transferCount);
rxChannel_()->destinationBuffer(m_pCurrentTransfer->m_pDest,
m_pCurrentTransfer->m_transferCount);
}
@ -616,6 +623,7 @@ class AbstractDmaSpi
{
// real data source
DMASPI_PRINT((" real source\n"));
arm_dcache_flush_delete((void *)m_pCurrentTransfer->m_pSource, m_pCurrentTransfer->m_transferCount);
txChannel_()->sourceBuffer(m_pCurrentTransfer->m_pSource,
m_pCurrentTransfer->m_transferCount);
}
@ -627,6 +635,7 @@ class AbstractDmaSpi
txChannel_()->transferCount(m_pCurrentTransfer->m_transferCount);
}
DMASPI_PRINT(("calling pre_cs() "));
pre_cs();
// Select Chip
@ -639,6 +648,7 @@ class AbstractDmaSpi
m_Spi.beginTransaction(SPISettings());
}
DMASPI_PRINT(("calling post_cs() "));
post_cs();
}
@ -669,7 +679,17 @@ typename AbstractDmaSpi<DMASPI_INSTANCE, SPICLASS, m_Spi>::Transfer* volatile Ab
template<typename DMASPI_INSTANCE, typename SPICLASS, SPICLASS& m_Spi>
volatile uint8_t AbstractDmaSpi<DMASPI_INSTANCE, SPICLASS, m_Spi>::m_devNull = 0;
#if defined(KINETISK)
//void dump_dma(DMAChannel *dmabc)
//{
// Serial.printf("%x %x:", (uint32_t)dmabc, (uint32_t)dmabc->TCD);
//
// Serial.printf("SA:%x SO:%d AT:%x NB:%x SL:%d DA:%x DO: %d CI:%x DL:%x CS:%x BI:%x\n", (uint32_t)dmabc->TCD->SADDR,
// dmabc->TCD->SOFF, dmabc->TCD->ATTR, dmabc->TCD->NBYTES, dmabc->TCD->SLAST, (uint32_t)dmabc->TCD->DADDR,
// dmabc->TCD->DOFF, dmabc->TCD->CITER, dmabc->TCD->DLASTSGA, dmabc->TCD->CSR, dmabc->TCD->BITER);
// Serial.flush();
//}
#if defined(__IMXRT1062__) // T4.0
class DmaSpi0 : public AbstractDmaSpi<DmaSpi0, SPIClass, SPI>
{
@ -677,24 +697,136 @@ public:
static void begin_setup_txChannel_impl()
{
txChannel_()->disable();
txChannel_()->destination((volatile uint8_t&)SPI0_PUSHR);
txChannel_()->destination((volatile uint8_t&)IMXRT_LPSPI4_S.TDR);
txChannel_()->disableOnCompletion();
txChannel_()->triggerAtHardwareEvent(DMAMUX_SOURCE_SPI0_TX);
txChannel_()->triggerAtHardwareEvent(DMAMUX_SOURCE_LPSPI4_TX);
//txChannel_()->triggerAtTransfersOf(*rxChannel_);
}
static void begin_setup_rxChannel_impl()
{
rxChannel_()->disable();
rxChannel_()->source((volatile uint8_t&)SPI0_POPR);
rxChannel_()->source((volatile uint8_t&)IMXRT_LPSPI4_S.RDR); // POPR is the receive fifo register for the SPI
rxChannel_()->disableOnCompletion();
rxChannel_()->triggerAtHardwareEvent(DMAMUX_SOURCE_SPI0_RX);
rxChannel_()->triggerAtHardwareEvent(DMAMUX_SOURCE_LPSPI4_RX); // The DMA RX id for MT66 is 14
rxChannel_()->attachInterrupt(rxIsr_);
rxChannel_()->interruptAtCompletion();
}
static void pre_cs_impl()
{
SPI0_SR = 0xFF0F0000;
if (LPSPI4_SR & 0x1800) {
DMASPI_PRINT(("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!ERROR SR reg is %08X\n", LPSPI4_SR));
}
DMASPI_PRINT(("********************************************CHECK SR reg is %08X\n", LPSPI4_SR));
IMXRT_LPSPI4_S.TCR = (IMXRT_LPSPI4_S.TCR & ~(LPSPI_TCR_FRAMESZ(31))) | LPSPI_TCR_FRAMESZ(7);
IMXRT_LPSPI4_S.FCR = 0;
//IMXRT_LPSPI4_S.CR = LPSPI_CR_MEN | LPSPI_CR_RRF | LPSPI_CR_RTF;
IMXRT_LPSPI4_S.CR = LPSPI_CR_MEN; // I had to add the enable otherwise it wont' work
// Lets try to output the first byte to make sure that we are in 8 bit mode...
IMXRT_LPSPI4_S.DER = LPSPI_DER_TDDE | LPSPI_DER_RDDE; //enable DMA on both TX and RX
IMXRT_LPSPI4_S.SR = 0x3f00; // clear out all of the other status...
// if (m_pCurrentTransfer->m_pSource) {
// arm_dcache_flush((void *)m_pCurrentTransfer->m_pSource, m_pCurrentTransfer->m_transferCount);
// }
}
// static void pre_cs_impl()
// {
//
// //LPSPI4_PARAM = LPSPI4_PARAM;
// //LPSPI4_PARAM = 0x0404;
// //DMASPI_PRINT(("!!!!!!!!!!!!!!!!!!!!!PARAM reg is %08X\n", LPSPI4_PARAM));
// txChannel_()->TCD->ATTR_SRC = 0; //Make sure set for 8 bit mode...
// txChannel_()->TCD->SLAST = 0; // Finish with it pointing to next location
// rxChannel_()->TCD->ATTR_DST = 0; //Make sure set for 8 bit mode...
// rxChannel_()->TCD->DLASTSGA = 0;
//
// //DMASPI_PRINT(("STATUS SR reg is %08X\n", LPSPI4_SR));
// if (LPSPI4_SR & 0x1800) {
// DMASPI_PRINT(("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!ERROR SR reg is %08X\n", LPSPI4_SR));
// }
// LPSPI4_SR = 0x3f00; // clear various error and status flags
// DMASPI_PRINT(("********************************************CHECK SR reg is %08X\n", LPSPI4_SR));
//
// LPSPI4_TCR = (LPSPI4_TCR & ~(LPSPI_TCR_FRAMESZ(31))) | LPSPI_TCR_FRAMESZ(7); // Set the FRAMESZ to 7 for 8-bit frame size
// LPSPI4_FCR = 0; // set watermarks to zero, this ensures ready flag is set whenever fifo is not empty
//
// LPSPI4_CR = LPSPI_CR_MEN | LPSPI_CR_RRF | LPSPI_CR_RTF; //enable module and reset both FIFOs
// LPSPI4_DER = LPSPI_DER_TDDE | LPSPI_DER_RDDE; // enable DMA on both TX and RX
// }
static void post_cs_impl()
{
rxChannel_()->enable();
txChannel_()->enable();
DMASPI_PRINT(("Done post_cs_impl()\n"));
}
static void post_finishCurrentTransfer_impl()
{
IMXRT_LPSPI4_S.FCR = LPSPI_FCR_TXWATER(15); // _spi_fcr_save; // restore the FSR status...
IMXRT_LPSPI4_S.DER = 0; // DMA no longer doing TX (or RX)
IMXRT_LPSPI4_S.CR = LPSPI_CR_MEN | LPSPI_CR_RRF | LPSPI_CR_RTF; // actually clear both...
IMXRT_LPSPI4_S.SR = 0x3f00; // clear out all of the other status...
// if (m_pCurrentTransfer->m_pDest) {
// arm_dcache_delete((void *)m_pCurrentTransfer->m_pDest, m_pCurrentTransfer->m_transferCount);
// }
}
// static void post_finishCurrentTransfer_impl()
// {
// //LPSPI4_FCR = LPSPI_FCR_TXWATER(15); // restore FSR status
// LPSPI4_DER = 0; // DMA no longer doing TX or RX
// LPSPI4_CR = LPSPI_CR_MEN | LPSPI_CR_RRF | LPSPI_CR_RTF; //enable module and reset both FIFOs
// LPSPI4_SR = 0x3f00; // clear out all the other statuses
// }
private:
};
extern DmaSpi0 DMASPI0;
#elif defined(KINETISK)
class DmaSpi0 : public AbstractDmaSpi<DmaSpi0, SPIClass, SPI>
{
public:
static void begin_setup_txChannel_impl()
{
txChannel_()->disable();
txChannel_()->destination((volatile uint8_t&)SPI0_PUSHR); // PUSHR is the transmit fifo register for the SPI
txChannel_()->disableOnCompletion();
txChannel_()->triggerAtHardwareEvent(DMAMUX_SOURCE_SPI0_TX); // The DMA TX id for MT66 is 15
}
static void begin_setup_rxChannel_impl()
{
rxChannel_()->disable();
rxChannel_()->source((volatile uint8_t&)SPI0_POPR); // POPR is the receive fifo register for the SPI
rxChannel_()->disableOnCompletion();
rxChannel_()->triggerAtHardwareEvent(DMAMUX_SOURCE_SPI0_RX); // The DMA RX id for MT66 is 14
rxChannel_()->attachInterrupt(rxIsr_);
rxChannel_()->interruptAtCompletion();
}
static void pre_cs_impl()
{
SPI0_SR = 0xFF0F0000; // Clear various flags including Transfer complete, TXRX Status, End of Queue, Transmit FIFO underflow, Transmit FIFO Fill, Rx FIFO overflow, Rx fifo drain
// Request Select Enable Register
// RFDF_RE Rx fifo drain request enable, enables the RFDF flag in SPI0_SR
// RFDF_DIRS Rx fifo drain selects DMA request instead of interrupt request
// TFFF_RE Transmit Fifo fill request enable
// TFFF_DIRS Transmit fifo fill selct DMA instead of interrupt
SPI0_RSER = SPI_RSER_RFDF_RE | SPI_RSER_RFDF_DIRS | SPI_RSER_TFFF_RE | SPI_RSER_TFFF_DIRS;
}
@ -706,8 +838,8 @@ public:
static void post_finishCurrentTransfer_impl()
{
SPI0_RSER = 0;
SPI0_SR = 0xFF0F0000;
SPI0_RSER = 0; //DSPI DMA/Interrupt Request Select and Enable Register
SPI0_SR = 0xFF0F0000; // DSPI status register clear flags, same as above
}
private:
@ -715,6 +847,7 @@ private:
extern DmaSpi0 DMASPI0;
#if defined(__MK66FX1M0__)
class DmaSpi1 : public AbstractDmaSpi<DmaSpi1, SPIClass, SPI1>

@ -203,6 +203,7 @@ public:
private:
static bool m_configured; ///< there should only be one instance of ExternalSramManager in the whole project
static MemConfig m_memConfig[BALibrary::NUM_MEM_SLOTS]; ///< store the configuration information for each external memory
void m_configure(void); ///< configure the memory manager
};

@ -203,7 +203,7 @@ bool AudioDelay::interpolateDelay(int16_t *extendedSourceBuffer, int16_t *destBu
}
/// @todo optimize this later
for (int i=0; i<numSamples; i++) {
for (unsigned i=0; i<numSamples; i++) {
destBuffer[i] = ((frac1*extendedSourceBuffer[i]) >> 16) + ((frac2*extendedSourceBuffer[i+1]) >> 16);
}
return true;

@ -0,0 +1,99 @@
/*
* ParameterAutomation.cpp
*
* Created on: October 23, 2019
* Author: slascos
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "BAHardware.h"
namespace BALibrary {
BAHardware BAHardwareConfig; // create the global configuration struct
void BAHardware::set(TgaBoard tgaBoard)
{
m_tgaBoard = tgaBoard;
}
TgaBoard BAHardware::getTgaBoard(void)
{
return m_tgaBoard;
}
void BAHardware::set(ExpansionBoard expansionBoard)
{
m_expansionBoard = expansionBoard;
}
ExpansionBoard BAHardware::getExpansionBoard(void)
{
return m_expansionBoard;
}
void BAHardware::set(MemSelect memSelect, SpiMemoryDefinition spiMem)
{
switch(memSelect) {
case MemSelect::MEM0 : m_spiMem0 = spiMem; break;
case MemSelect::MEM1 : m_spiMem1 = spiMem; break;
default :
break;
}
}
SpiMemoryDefinition BAHardware::getSpiMemoryDefinition(MemSelect memSelect)
{
switch(memSelect) {
case MemSelect::MEM0 : return m_spiMem0; break;
case MemSelect::MEM1 : return m_spiMem1; break;
default :
return m_spiMem0;
}
}
size_t BAHardware::getSpiMemSizeBytes(unsigned memIndex)
{
size_t sizeBytes = 0;
switch(memIndex) {
case 0 : sizeBytes = m_spiMem0.MEM_SIZE_BYTES; break;
case 1 : sizeBytes = m_spiMem1.MEM_SIZE_BYTES; break;
default : break;
}
return sizeBytes;
}
size_t BAHardware::getSpiMemSizeBytes(MemSelect memSelect)
{
size_t sizeBytes = 0;
unsigned memIndex = static_cast<unsigned>(memSelect);
switch(memIndex) {
case 0 : sizeBytes = m_spiMem0.MEM_SIZE_BYTES; break;
case 1 : sizeBytes = m_spiMem1.MEM_SIZE_BYTES; break;
default : break;
}
return sizeBytes;
}
size_t BAHardware::getSpiMemMaxAddr(unsigned memIndex)
{
return getSpiMemSizeBytes(memIndex)-1;
}
size_t BAHardware::getSpiMemMaxAddr(MemSelect memSelect)
{
return getSpiMemSizeBytes(memSelect)-1;
}
}

@ -34,21 +34,9 @@ MemConfig ExternalSramManager::m_memConfig[BALibrary::NUM_MEM_SLOTS];
ExternalSramManager::ExternalSramManager(unsigned numMemories)
{
// Initialize the static memory configuration structs
if (!m_configured) {
for (unsigned i=0; i < NUM_MEM_SLOTS; i++) {
m_memConfig[i].size = MEM_MAX_ADDR[i]+1;
m_memConfig[i].totalAvailable = MEM_MAX_ADDR[i]+1;
m_memConfig[i].nextAvailable = 0;
m_memConfig[i].m_spi = nullptr;
}
m_configured = true;
}
}
ExternalSramManager::ExternalSramManager()
: ExternalSramManager(1)
{
}
@ -62,11 +50,13 @@ ExternalSramManager::~ExternalSramManager()
size_t ExternalSramManager::availableMemory(BALibrary::MemSelect mem)
{
if (!m_configured) { m_configure(); }
return m_memConfig[mem].totalAvailable;
}
bool ExternalSramManager::requestMemory(ExtMemSlot *slot, float delayMilliseconds, BALibrary::MemSelect mem, bool useDma)
{
if (!m_configured) { m_configure(); }
// convert the time to numer of samples
size_t delayLengthInt = (size_t)((delayMilliseconds*(AUDIO_SAMPLE_RATE_EXACT/1000.0f))+0.5f);
return requestMemory(slot, delayLengthInt * sizeof(int16_t), mem, useDma);
@ -75,6 +65,8 @@ bool ExternalSramManager::requestMemory(ExtMemSlot *slot, float delayMillisecond
bool ExternalSramManager::requestMemory(ExtMemSlot *slot, size_t sizeBytes, BALibrary::MemSelect mem, bool useDma)
{
if (!m_configured) { m_configure(); }
if (m_memConfig[mem].totalAvailable >= sizeBytes) {
Serial.println(String("Configuring a slot for mem ") + mem);
// there is enough available memory for this request
@ -118,5 +110,20 @@ bool ExternalSramManager::requestMemory(ExtMemSlot *slot, size_t sizeBytes, BALi
}
}
void ExternalSramManager::m_configure(void)
{
// Initialize the static memory configuration structs
if (!m_configured) {
for (unsigned i=0; i < NUM_MEM_SLOTS; i++) {
m_memConfig[i].size = BAHardwareConfig.getSpiMemSizeBytes(i);
m_memConfig[i].totalAvailable = BAHardwareConfig.getSpiMemSizeBytes(i);
m_memConfig[i].nextAvailable = 0;
m_memConfig[i].m_spi = nullptr;
}
m_configured = true;
}
}
}

@ -17,7 +17,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "BAHardware.h"
#include "BAAudioEffectDelayExternal.h"
using namespace BALibrary;
@ -26,17 +26,6 @@ namespace BAEffects {
#define SPISETTING SPISettings(20000000, MSBFIRST, SPI_MODE0)
struct MemSpiConfig {
unsigned mosiPin;
unsigned misoPin;
unsigned sckPin;
unsigned csPin;
unsigned memSize;
};
constexpr MemSpiConfig Mem0Config = {7, 8, 14, 15, 65536 };
constexpr MemSpiConfig Mem1Config = {21, 5, 20, 31, 65536 };
unsigned BAAudioEffectDelayExternal::m_usingSPICount[2] = {0,0};
BAAudioEffectDelayExternal::BAAudioEffectDelayExternal()
@ -149,7 +138,7 @@ unsigned BAAudioEffectDelayExternal::m_allocated[2] = {0, 0};
void BAAudioEffectDelayExternal::initialize(MemSelect mem, unsigned delayLength)
{
unsigned samples = 0;
unsigned memsize, avail;
unsigned memsize = 0, avail = 0;
m_activeMask = 0;
m_headOffset = 0;
@ -158,13 +147,13 @@ void BAAudioEffectDelayExternal::initialize(MemSelect mem, unsigned delayLength)
switch (mem) {
case MemSelect::MEM0 :
{
memsize = Mem0Config.memSize;
memsize = BAHardwareConfig.getSpiMemSizeBytes(mem) / sizeof(int16_t);
m_spi = &SPI;
m_spiChannel = 0;
m_misoPin = Mem0Config.misoPin;
m_mosiPin = Mem0Config.mosiPin;
m_sckPin = Mem0Config.sckPin;
m_csPin = Mem0Config.csPin;
m_misoPin = SPI0_MISO_PIN;
m_mosiPin = SPI0_MOSI_PIN;
m_sckPin = SPI0_SCK_PIN;
m_csPin = SPI0_CS_PIN;
m_spi->setMOSI(m_mosiPin);
m_spi->setMISO(m_misoPin);
@ -175,13 +164,13 @@ void BAAudioEffectDelayExternal::initialize(MemSelect mem, unsigned delayLength)
case MemSelect::MEM1 :
{
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
memsize = Mem1Config.memSize;
memsize = BAHardwareConfig.getSpiMemSizeBytes(mem) / sizeof(int16_t);
m_spi = &SPI1;
m_spiChannel = 1;
m_misoPin = Mem1Config.misoPin;
m_mosiPin = Mem1Config.mosiPin;
m_sckPin = Mem1Config.sckPin;
m_csPin = Mem1Config.csPin;
m_misoPin = SPI1_MISO_PIN;
m_mosiPin = SPI1_MOSI_PIN;
m_sckPin = SPI1_SCK_PIN;
m_csPin = SPI1_CS_PIN;
m_spi->setMOSI(m_mosiPin);
m_spi->setMISO(m_misoPin);

@ -19,6 +19,7 @@
*/
#include <Wire.h>
#include "BAHardware.h"
#include "BAAudioControlWM8731.h"
namespace BALibrary {
@ -132,9 +133,12 @@ BAAudioControlWM8731::~BAAudioControlWM8731()
// Powerdown and disable the codec
void BAAudioControlWM8731::disable(void)
{
//Serial.println("Disabling codec");
if (m_wireStarted == false) { Wire.begin(); m_wireStarted = true; }
if (m_wireStarted == false) {
Wire.begin();
m_wireStarted = true;
}
setOutputStrength();
// set OUTPD to '1' (powerdown), which is bit 4
regArray[WM8731_REG_POWERDOWN] |= 0x10;
@ -155,9 +159,13 @@ void BAAudioControlWM8731::enable(void)
disable(); // disable first in case it was already powered up
//Serial.println("Enabling codec");
if (m_wireStarted == false) { Wire.begin(); m_wireStarted = true; }
// Sequence from WAN0111.pdf
if (m_wireStarted == false) {
Wire.begin();
m_wireStarted = true;
}
setOutputStrength();
// Sequence from WAN0111.pdf
// Begin configuring the codec
resetCodec();
delay(100); // wait for reset
@ -199,9 +207,6 @@ void BAAudioControlWM8731::enable(void)
regArray[WM8731_REG_POWERDOWN] = 0x02;
delay(500); // wait for output to power up
//Serial.println("Done codec config");
delay(100); // wait for mute ramp
}
@ -368,9 +373,9 @@ bool BAAudioControlWM8731::write(unsigned int reg, unsigned int val)
Wire.beginTransmission(WM8731_I2C_ADDR);
Wire.write((reg << 1) | ((val >> 8) & 1));
Wire.write(val & 0xFF);
if (byte error = Wire.endTransmission() ) {
(void)error; // supress warning about unused variable
//Serial.println(String("Wire::Error: ") + error + String(" retrying..."));
byte error = Wire.endTransmission();
if (error) {
Serial.println(String("Wire::Error: ") + error + String(" retrying..."));
} else {
done = true;
//Serial.println("Wire::SUCCESS!");
@ -380,4 +385,17 @@ bool BAAudioControlWM8731::write(unsigned int reg, unsigned int val)
return true;
}
void BAAudioControlWM8731::setOutputStrength(void)
{
#if defined(__IMXRT1062__)
// The T4 requires the pads be configured with correct pullups and drive strength
SCL_PAD_CTRL = SCL_SDA_PAD_CFG;
SDA_PAD_CTRL = SCL_SDA_PAD_CFG;
MCLK_PAD_CTRL = I2S_PAD_CFG;
BCLK_PAD_CTRL = I2S_PAD_CFG;
LRCLK_PAD_CTRL = I2S_PAD_CFG;
DAC_PAD_CTRL = I2S_PAD_CFG;
#endif
}
} /* namespace BALibrary */

@ -57,7 +57,6 @@ unsigned BAPhysicalControls::addRotary(uint8_t pin1, uint8_t pin2, bool swapDire
}
unsigned BAPhysicalControls::addSwitch(uint8_t pin, unsigned long intervalMilliseconds) {
//m_switches.emplace_back(pin, intervalMilliseconds);'
m_switches.emplace_back();
m_switches.back().attach(pin);
m_switches.back().interval(10);
@ -240,23 +239,36 @@ void Potentiometer::setFeedbackFitlerValue(float fitlerValue)
bool Potentiometer::getValue(float &value) {
bool newValue = true;
// Check if the minimum sampling time has elapsed
if (m_timerMs < m_samplingIntervalMs) {
return false;
}
m_timerMs = 0; // reset the sampling timer
unsigned val = analogRead(m_pin); // read the raw value
// constrain it within the calibration values, them map it to the desired range.
val = constrain(val, m_minCalibration, m_maxCalibration);
// Use an IIR filter to smooth out the noise in the pot readings
unsigned valFilter = static_cast<unsigned>( (1.0f - m_feedbackFitlerValue)*val + (m_feedbackFitlerValue*m_lastValue));
unsigned valFilter = static_cast<int>( (1.0f - m_feedbackFitlerValue)*val + (m_feedbackFitlerValue*m_lastValue));
m_lastValue = valFilter;
if (valFilter == m_lastValue) {
newValue = false;
// Apply a hysteresis check
if (valFilter == m_lastValidValue) { // check if value hasn't changed
return false;
}
m_lastValue = valFilter;
if (abs((int)valFilter - (int)m_lastValidValue) < m_changeThreshold) {
// The value has not exceeded the change threshold. Suppress the change only if it's not
// near the limits. This is necessary to ensure the limits can be reached.
if ( (valFilter < m_maxCalibrationThresholded) && (valFilter > m_minCalibrationThresholded)) {
return false;
}
}
m_lastValidValue = m_lastValue;
//
if (valFilter < m_minCalibrationThresholded) { value = 0.0f; }
// Convert the integer reading to a float value range 0.0 to 1.0f
if (valFilter < m_minCalibrationThresholded) { value = 0.0f; }
else if (valFilter > m_maxCalibrationThresholded) { value = 1.0f; }
else {
value = static_cast<float>(valFilter - m_minCalibrationThresholded) / static_cast<float>(m_rangeThresholded);
@ -265,7 +277,8 @@ bool Potentiometer::getValue(float &value) {
if (m_swapDirection) {
value = 1.0f - value;
}
return newValue;
return true;
}
int Potentiometer::getRawValue() {
@ -293,6 +306,16 @@ void Potentiometer::setCalibrationValues(unsigned min, unsigned max, bool swapDi
adjustCalibrationThreshold(m_thresholdFactor);
}
void Potentiometer::setSamplingIntervalMs(unsigned intervalMs)
{
m_samplingIntervalMs = intervalMs;
}
void Potentiometer::setChangeThreshold(float changeThreshold)
{
m_changeThreshold = changeThreshold;
}
Potentiometer::Calib Potentiometer::calibrate(uint8_t pin) {
Calib calib;

@ -17,23 +17,24 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Arduino.h"
#include "BASpiMemory.h"
namespace BALibrary {
// MEM0 Settings
constexpr int SPI_CS_MEM0 = 15;
constexpr int SPI_MOSI_MEM0 = 7;
constexpr int SPI_MISO_MEM0 = 8;
constexpr int SPI_SCK_MEM0 = 14;
constexpr int SPI_CS_MEM0 = SPI0_CS_PIN;
constexpr int SPI_MOSI_MEM0 = SPI0_MOSI_PIN;
constexpr int SPI_MISO_MEM0 = SPI0_MISO_PIN;
constexpr int SPI_SCK_MEM0 = SPI0_SCK_PIN;
#if defined(SPI1_AVAILABLE)
// MEM1 Settings
constexpr int SPI_CS_MEM1 = 31;
constexpr int SPI_MOSI_MEM1 = 21;
constexpr int SPI_MISO_MEM1 = 5;
constexpr int SPI_SCK_MEM1 = 20;
constexpr int SPI_CS_MEM1 = SPI1_CS_PIN;
constexpr int SPI_MOSI_MEM1 = SPI1_MOSI_PIN;
constexpr int SPI_MISO_MEM1 = SPI1_MISO_PIN;
constexpr int SPI_SCK_MEM1 = SPI1_SCK_PIN;
#endif
// SPI Constants
constexpr int SPI_WRITE_MODE_REG = 0x1;
@ -48,6 +49,7 @@ constexpr int SPI_ADDR_0_MASK = 0x0000FF;
constexpr int CMD_ADDRESS_SIZE = 4;
constexpr int MAX_DMA_XFER_SIZE = 0x4000;
BASpiMemory::BASpiMemory(SpiDeviceId memDeviceId)
{
m_memDeviceId = memDeviceId;
@ -71,6 +73,7 @@ void BASpiMemory::begin()
m_spi->setMISO(SPI_MISO_MEM0);
m_spi->setSCK(SPI_SCK_MEM0);
m_spi->begin();
m_dieBoundary = BAHardwareConfig.getSpiMemoryDefinition(MemSelect::MEM0).DIE_BOUNDARY;
break;
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
@ -81,6 +84,7 @@ void BASpiMemory::begin()
m_spi->setMISO(SPI_MISO_MEM1);
m_spi->setSCK(SPI_SCK_MEM1);
m_spi->begin();
m_dieBoundary = BAHardwareConfig.getSpiMemoryDefinition(MemSelect::MEM1).DIE_BOUNDARY;
break;
#endif
@ -112,40 +116,28 @@ void BASpiMemory::write(size_t address, uint8_t data)
digitalWrite(m_csPin, HIGH);
}
// Single address write
// Sequential write
void BASpiMemory::write(size_t address, uint8_t *src, size_t numBytes)
{
uint8_t *dataPtr = src;
m_spi->beginTransaction(m_settings);
digitalWrite(m_csPin, LOW);
m_spi->transfer(SPI_WRITE_CMD);
m_spi->transfer((address & SPI_ADDR_2_MASK) >> SPI_ADDR_2_SHIFT);
m_spi->transfer((address & SPI_ADDR_1_MASK) >> SPI_ADDR_1_SHIFT);
m_spi->transfer((address & SPI_ADDR_0_MASK));
for (size_t i=0; i < numBytes; i++) {
m_spi->transfer(*dataPtr++);
}
m_spi->endTransaction();
digitalWrite(m_csPin, HIGH);
// Check if this burst will cross the die boundary
while (numBytes > 0) {
size_t bytesToWrite = m_bytesToXfer(address, numBytes);
m_rawWrite(address, src, bytesToWrite);
address += bytesToWrite;
numBytes -= bytesToWrite;
src += bytesToWrite;
}
}
void BASpiMemory::zero(size_t address, size_t numBytes)
{
m_spi->beginTransaction(m_settings);
digitalWrite(m_csPin, LOW);
m_spi->transfer(SPI_WRITE_CMD);
m_spi->transfer((address & SPI_ADDR_2_MASK) >> SPI_ADDR_2_SHIFT);
m_spi->transfer((address & SPI_ADDR_1_MASK) >> SPI_ADDR_1_SHIFT);
m_spi->transfer((address & SPI_ADDR_0_MASK));
for (size_t i=0; i < numBytes; i++) {
m_spi->transfer(0);
}
m_spi->endTransaction();
digitalWrite(m_csPin, HIGH);
// Check if this burst will cross the die boundary
while (numBytes > 0) {
size_t bytesToWrite = m_bytesToXfer(address, numBytes);
m_rawZero(address, bytesToWrite);
address += bytesToWrite;
numBytes -= bytesToWrite;
}
}
void BASpiMemory::write16(size_t address, uint16_t data)
@ -161,35 +153,29 @@ void BASpiMemory::write16(size_t address, uint16_t data)
void BASpiMemory::write16(size_t address, uint16_t *src, size_t numWords)
{
uint16_t *dataPtr = src;
m_spi->beginTransaction(m_settings);
digitalWrite(m_csPin, LOW);
m_spi->transfer16((SPI_WRITE_CMD << 8) | (address >> 16) );
m_spi->transfer16(address & 0xFFFF);
for (size_t i=0; i<numWords; i++) {
m_spi->transfer16(*dataPtr++);
}
m_spi->endTransaction();
digitalWrite(m_csPin, HIGH);
// Check if this burst will cross the die boundary
size_t numBytes = numWords * sizeof(uint16_t);
while (numBytes > 0) {
size_t bytesToWrite = m_bytesToXfer(address, numBytes);
size_t wordsToWrite = bytesToWrite / sizeof(uint16_t);
m_rawWrite16(address, src, wordsToWrite);
address += bytesToWrite;
numBytes -= bytesToWrite;
src += wordsToWrite;
}
}
void BASpiMemory::zero16(size_t address, size_t numWords)
{
m_spi->beginTransaction(m_settings);
digitalWrite(m_csPin, LOW);
m_spi->transfer16((SPI_WRITE_CMD << 8) | (address >> 16) );
m_spi->transfer16(address & 0xFFFF);
for (size_t i=0; i<numWords; i++) {
m_spi->transfer16(0);
}
m_spi->endTransaction();
digitalWrite(m_csPin, HIGH);
Serial.println("DONE!");
// Check if this burst will cross the die boundary
size_t numBytes = numWords * sizeof(uint16_t);
while (numBytes > 0) {
size_t bytesToWrite = m_bytesToXfer(address, numBytes);
size_t wordsToWrite = bytesToWrite / sizeof(uint16_t);
m_rawZero16(address, wordsToWrite);
address += bytesToWrite;
numBytes -= bytesToWrite;
}
}
// single address read
@ -209,24 +195,16 @@ uint8_t BASpiMemory::read(size_t address)
return data;
}
void BASpiMemory::read(size_t address, uint8_t *dest, size_t numBytes)
{
uint8_t *dataPtr = dest;
m_spi->beginTransaction(m_settings);
digitalWrite(m_csPin, LOW);
m_spi->transfer(SPI_READ_CMD);
m_spi->transfer((address & SPI_ADDR_2_MASK) >> SPI_ADDR_2_SHIFT);
m_spi->transfer((address & SPI_ADDR_1_MASK) >> SPI_ADDR_1_SHIFT);
m_spi->transfer((address & SPI_ADDR_0_MASK));
for (size_t i=0; i<numBytes; i++) {
*dataPtr++ = m_spi->transfer(0);
}
m_spi->endTransaction();
digitalWrite(m_csPin, HIGH);
// Check if this burst will cross the die boundary
while (numBytes > 0) {
size_t bytesToRead = m_bytesToXfer(address, numBytes);
m_rawRead(address, dest, bytesToRead);
address += bytesToRead;
numBytes -= bytesToRead;
dest += bytesToRead;
}
}
uint16_t BASpiMemory::read16(size_t address)
@ -246,21 +224,137 @@ uint16_t BASpiMemory::read16(size_t address)
void BASpiMemory::read16(size_t address, uint16_t *dest, size_t numWords)
{
// Check if this burst will cross the die boundary
size_t numBytes = numWords * sizeof(uint16_t);
while (numBytes > 0) {
size_t bytesToRead = m_bytesToXfer(address, numBytes);
size_t wordsToRead = bytesToRead / sizeof(uint16_t);
m_rawRead16(address, dest, wordsToRead);
address += bytesToRead;
numBytes -= bytesToRead;
dest += wordsToRead;
}
}
uint16_t *dataPtr = dest;
m_spi->beginTransaction(m_settings);
digitalWrite(m_csPin, LOW);
m_spi->transfer16((SPI_READ_CMD << 8) | (address >> 16) );
m_spi->transfer16(address & 0xFFFF);
// PRIVATE FUNCTIONS
size_t BASpiMemory::m_bytesToXfer(size_t address, size_t numBytes)
{
// Check if this burst will cross the die boundary
size_t bytesToXfer = numBytes;
if (m_dieBoundary) {
if ((address < m_dieBoundary) && (address+numBytes > m_dieBoundary)) {
// split into two xfers
bytesToXfer = m_dieBoundary-address;
}
}
return bytesToXfer;
}
for (size_t i=0; i<numWords; i++) {
*dataPtr++ = m_spi->transfer16(0);
}
void BASpiMemory::m_rawWrite(size_t address, uint8_t *src, size_t numBytes)
{
uint8_t *dataPtr = src;
m_spi->beginTransaction(m_settings);
digitalWrite(m_csPin, LOW);
m_spi->transfer(SPI_WRITE_CMD);
m_spi->transfer((address & SPI_ADDR_2_MASK) >> SPI_ADDR_2_SHIFT);
m_spi->transfer((address & SPI_ADDR_1_MASK) >> SPI_ADDR_1_SHIFT);
m_spi->transfer((address & SPI_ADDR_0_MASK));
for (size_t i=0; i < numBytes; i++) {
m_spi->transfer(*dataPtr++);
}
m_spi->endTransaction();
digitalWrite(m_csPin, HIGH);
}
m_spi->endTransaction();
digitalWrite(m_csPin, HIGH);
void BASpiMemory::m_rawWrite16(size_t address, uint16_t *src, size_t numWords)
{
uint16_t *dataPtr = src;
m_spi->beginTransaction(m_settings);
digitalWrite(m_csPin, LOW);
m_spi->transfer16((SPI_WRITE_CMD << 8) | (address >> 16) );
m_spi->transfer16(address & 0xFFFF);
for (size_t i=0; i<numWords; i++) {
m_spi->transfer16(*dataPtr++);
}
m_spi->endTransaction();
digitalWrite(m_csPin, HIGH);
}
void BASpiMemory::m_rawZero(size_t address, size_t numBytes)
{
m_spi->beginTransaction(m_settings);
digitalWrite(m_csPin, LOW);
m_spi->transfer(SPI_WRITE_CMD);
m_spi->transfer((address & SPI_ADDR_2_MASK) >> SPI_ADDR_2_SHIFT);
m_spi->transfer((address & SPI_ADDR_1_MASK) >> SPI_ADDR_1_SHIFT);
m_spi->transfer((address & SPI_ADDR_0_MASK));
for (size_t i=0; i < numBytes; i++) {
m_spi->transfer(0);
}
m_spi->endTransaction();
digitalWrite(m_csPin, HIGH);
}
void BASpiMemory::m_rawZero16(size_t address, size_t numWords)
{
m_spi->beginTransaction(m_settings);
digitalWrite(m_csPin, LOW);
m_spi->transfer16((SPI_WRITE_CMD << 8) | (address >> 16) );
m_spi->transfer16(address & 0xFFFF);
for (size_t i=0; i<numWords; i++) {
m_spi->transfer16(0);
}
m_spi->endTransaction();
digitalWrite(m_csPin, HIGH);
}
void BASpiMemory::m_rawRead(size_t address, uint8_t *dest, size_t numBytes)
{
uint8_t *dataPtr = dest;
m_spi->beginTransaction(m_settings);
digitalWrite(m_csPin, LOW);
m_spi->transfer(SPI_READ_CMD);
m_spi->transfer((address & SPI_ADDR_2_MASK) >> SPI_ADDR_2_SHIFT);
m_spi->transfer((address & SPI_ADDR_1_MASK) >> SPI_ADDR_1_SHIFT);
m_spi->transfer((address & SPI_ADDR_0_MASK));
for (size_t i=0; i<numBytes; i++) {
*dataPtr++ = m_spi->transfer(0);
}
m_spi->endTransaction();
digitalWrite(m_csPin, HIGH);
}
void BASpiMemory::m_rawRead16(size_t address, uint16_t *dest, size_t numWords)
{
uint16_t *dataPtr = dest;
m_spi->beginTransaction(m_settings);
digitalWrite(m_csPin, LOW);
m_spi->transfer16((SPI_READ_CMD << 8) | (address >> 16) );
m_spi->transfer16(address & 0xFFFF);
for (size_t i=0; i<numWords; i++) {
*dataPtr++ = m_spi->transfer16(0);
}
m_spi->endTransaction();
digitalWrite(m_csPin, HIGH);
}
#if defined (__IMXRT1062__)
//#if 0
using BASpiMemoryDMA = BASpiMemory;
#else
/////////////////////////////////////////////////////////////////////////////
// BASpiMemoryDMA
/////////////////////////////////////////////////////////////////////////////
@ -342,8 +436,8 @@ void BASpiMemoryDMA::begin(void)
m_spi->setMISO(SPI_MISO_MEM0);
m_spi->setSCK(SPI_SCK_MEM0);
m_spi->begin();
//m_spiDma = &DMASPI0;
m_spiDma = new DmaSpiGeneric();
m_dieBoundary = BAHardwareConfig.getSpiMemoryDefinition(MemSelect::MEM0).DIE_BOUNDARY;
break;
#if defined(__MK66FX1M0__) // DMA on SPI1 is only supported on T3.6
@ -355,7 +449,7 @@ void BASpiMemoryDMA::begin(void)
m_spi->setSCK(SPI_SCK_MEM1);
m_spi->begin();
m_spiDma = new DmaSpiGeneric(1);
//m_spiDma = &DMASPI1;
m_dieBoundary = BAHardwareConfig.getSpiMemoryDefinition(MemSelect::MEM1).DIE_BOUNDARY;
break;
#endif
@ -366,7 +460,6 @@ void BASpiMemoryDMA::begin(void)
m_spiDma->begin();
m_spiDma->start();
m_started = true;
}
@ -380,14 +473,16 @@ void BASpiMemoryDMA::write(size_t address, uint8_t *src, size_t numBytes)
size_t bytesRemaining = numBytes;
uint8_t *srcPtr = src;
size_t nextAddress = address;
while (bytesRemaining > 0) {
m_txXferCount = min(bytesRemaining, static_cast<size_t>(MAX_DMA_XFER_SIZE));
while ( m_txTransfer[1].busy()) {} // wait until not busy
m_txXferCount = m_bytesToXfer(nextAddress, min(bytesRemaining, static_cast<size_t>(MAX_DMA_XFER_SIZE))); // check for die boundary
while ( m_txTransfer[1].busy() || m_txTransfer[0].busy()) { yield(); } // wait until not busy
m_setSpiCmdAddr(SPI_WRITE_CMD, nextAddress, m_txCommandBuffer);
m_txTransfer[1] = DmaSpi::Transfer(m_txCommandBuffer, CMD_ADDRESS_SIZE, nullptr, 0, m_cs, TransferType::NO_END_CS);
m_spiDma->registerTransfer(m_txTransfer[1]);
while ( m_txTransfer[0].busy()) {} // wait until not busy
while ( m_txTransfer[0].busy() || m_txTransfer[1].busy()) { yield(); } // wait until not busy
m_txTransfer[0] = DmaSpi::Transfer(srcPtr, m_txXferCount, nullptr, 0, m_cs, TransferType::NO_START_CS);
m_spiDma->registerTransfer(m_txTransfer[0]);
bytesRemaining -= m_txXferCount;
@ -401,15 +496,23 @@ void BASpiMemoryDMA::zero(size_t address, size_t numBytes)
{
size_t bytesRemaining = numBytes;
size_t nextAddress = address;
/// TODO: Why can't the T4 zero the memory when a NULLPTR is passed? It seems to write a constant random value.
/// Perhaps there is somewhere we can set a fill value?
uint8_t zeroBuffer[MAX_DMA_XFER_SIZE];
memset(zeroBuffer, 0, MAX_DMA_XFER_SIZE);
while (bytesRemaining > 0) {
m_txXferCount = min(bytesRemaining, static_cast<size_t>(MAX_DMA_XFER_SIZE));
while ( m_txTransfer[1].busy()) {} // wait until not busy
m_txXferCount = m_bytesToXfer(nextAddress, min(bytesRemaining, static_cast<size_t>(MAX_DMA_XFER_SIZE))); // check for die boundary
while ( m_txTransfer[1].busy()) { yield(); } // wait until not busy
m_setSpiCmdAddr(SPI_WRITE_CMD, nextAddress, m_txCommandBuffer);
m_txTransfer[1] = DmaSpi::Transfer(m_txCommandBuffer, CMD_ADDRESS_SIZE, nullptr, 0, m_cs, TransferType::NO_END_CS);
m_spiDma->registerTransfer(m_txTransfer[1]);
while ( m_txTransfer[0].busy()) {} // wait until not busy
m_txTransfer[0] = DmaSpi::Transfer(nullptr, m_txXferCount, nullptr, 0, m_cs, TransferType::NO_START_CS);
while ( m_txTransfer[0].busy()) { yield(); } // wait until not busy
//m_txTransfer[0] = DmaSpi::Transfer(nullptr, m_txXferCount, nullptr, 0, m_cs, TransferType::NO_START_CS);
m_txTransfer[0] = DmaSpi::Transfer(zeroBuffer, m_txXferCount, nullptr, 0, m_cs, TransferType::NO_START_CS);
m_spiDma->registerTransfer(m_txTransfer[0]);
bytesRemaining -= m_txXferCount;
nextAddress += m_txXferCount;
@ -434,14 +537,15 @@ void BASpiMemoryDMA::read(size_t address, uint8_t *dest, size_t numBytes)
uint8_t *destPtr = dest;
size_t nextAddress = address;
while (bytesRemaining > 0) {
m_setSpiCmdAddr(SPI_READ_CMD, nextAddress, m_rxCommandBuffer);
m_rxXferCount = m_bytesToXfer(nextAddress, min(bytesRemaining, static_cast<size_t>(MAX_DMA_XFER_SIZE))); // check for die boundary
while ( m_rxTransfer[1].busy()) {}
m_setSpiCmdAddr(SPI_READ_CMD, nextAddress, m_rxCommandBuffer);
while ( m_rxTransfer[1].busy() || m_rxTransfer[0].busy()) { yield(); }
m_rxTransfer[1] = DmaSpi::Transfer(m_rxCommandBuffer, CMD_ADDRESS_SIZE, nullptr, 0, m_cs, TransferType::NO_END_CS);
m_spiDma->registerTransfer(m_rxTransfer[1]);
m_rxXferCount = min(bytesRemaining, static_cast<size_t>(MAX_DMA_XFER_SIZE));
while ( m_rxTransfer[0].busy()) {}
while ( m_rxTransfer[0].busy() || m_rxTransfer[1].busy()) { yield(); }
m_rxTransfer[0] = DmaSpi::Transfer(nullptr, m_rxXferCount, destPtr, 0, m_cs, TransferType::NO_START_CS);
m_spiDma->registerTransfer(m_rxTransfer[0]);
@ -467,5 +571,6 @@ bool BASpiMemoryDMA::isReadBusy(void) const
{
return (m_rxTransfer[0].busy() or m_rxTransfer[1].busy());
}
#endif // BASpiMemoryDMA definition
} /* namespace BALibrary */

@ -1,6 +1,8 @@
#include "DmaSpi.h"
#if defined(KINETISK)
#if defined(__IMXRT1062__) // T4.0
DmaSpi0 DMASPI0;
#elif defined(KINETISK)
DmaSpi0 DMASPI0;
#if defined(__MK66FX1M0__)
DmaSpi1 DMASPI1;

Loading…
Cancel
Save