57#if defined(FL_IS_ARM_LPC_845) && defined(FASTLED_LPC_SPI_DMA)
63#include "platforms/arm/lpc/spi_arm_lpc_dma.h"
78#ifndef FASTLED_LPC_SPI_DMA_HARNESS_DATA_PIN
79#define FASTLED_LPC_SPI_DMA_HARNESS_DATA_PIN 17
81#ifndef FASTLED_LPC_SPI_DMA_HARNESS_CLOCK_PIN
82#define FASTLED_LPC_SPI_DMA_HARNESS_CLOCK_PIN 13
84#ifndef FASTLED_LPC_SPI_DMA_HARNESS_DIVIDER
87#define FASTLED_LPC_SPI_DMA_HARNESS_DIVIDER 6
90using HarnessDriver = fl::ARMHardwareSPIOutputDMA<
91 static_cast<fl::u8>(FASTLED_LPC_SPI_DMA_HARNESS_DATA_PIN),
92 static_cast<fl::u8>(FASTLED_LPC_SPI_DMA_HARNESS_CLOCK_PIN),
93 static_cast<fl::u32
>(FASTLED_LPC_SPI_DMA_HARNESS_DIVIDER)>;
95struct SpiDmaHarnessState {
96 fl::u8 buffer[FASTLED_LPC_SPI_DMA_MAX_BYTES];
100 SpiDmaHarnessState() : initialized(false) {}
103#if FASTLED_LPC_DMA_ISR
104struct SpiDmaStreamState {
105 fl::u8 source[FASTLED_LPC_SPI_DMA_STREAM_BYTES];
108inline SpiDmaStreamState& spiDmaStreamState()
FL_NO_EXCEPT {
113inline SpiDmaHarnessState& spiDmaHarnessState()
FL_NO_EXCEPT {
120 return spiDmaHarnessState().buffer;
125 SpiDmaHarnessState&
state = spiDmaHarnessState();
126 if (!
state.initialized) {
128 state.initialized =
true;
137 if (n <= 0)
return 0;
138 const int cap =
static_cast<int>(FASTLED_LPC_SPI_DMA_MAX_BYTES);
139 return (n > cap) ? cap : n;
143inline fl::string transferOnceHandler(
int byte_count,
int byte_pattern)
FL_NO_EXCEPT {
144 const int len = clampByteCount(byte_count);
145 if (len == 0)
return fl::string(
"0,0,0,0");
146 fl::u8* buf = harnessBuffer();
147 const fl::u8 pat =
static_cast<fl::u8>(byte_pattern & 0xFF);
148 for (
int i = 0; i < len; ++i) buf[i] = pat;
150 HarnessDriver& drv = harnessDriver();
154 const fl::u32 t_start =
micros();
155 HarnessDriver::kickDmaStream(buf,
static_cast<fl::u32
>(len));
165 while (!HarnessDriver::done()) {
166 if (++spins > 2000000u) {
169 << DMA0->COMMON[0].ACTIVE <<
','
170 << DMA0->CHANNEL[FASTLED_LPC_SPI_DMA_CHANNEL].XFERCFG <<
','
171 << DMA0->CHANNEL[FASTLED_LPC_SPI_DMA_CHANNEL].CTLSTAT <<
','
173 << DMA0->COMMON[0].ERRINT;
177 const fl::u32 t_end =
micros();
180 s << 1 <<
',' << t_start <<
',' << t_end <<
',' << 0;
187inline fl::string transferOverlapHandler(
int byte_count,
int byte_pattern)
FL_NO_EXCEPT {
188 const int len = clampByteCount(byte_count);
189 if (len == 0)
return fl::string(
"0,0,0");
190 fl::u8* buf = harnessBuffer();
191 const fl::u8 pat =
static_cast<fl::u8>(byte_pattern & 0xFF);
192 for (
int i = 0; i < len; ++i) buf[i] = pat;
194 HarnessDriver& drv = harnessDriver();
197 const fl::u32 t_start =
micros();
198 HarnessDriver::kickDmaStream(buf,
static_cast<fl::u32
>(len));
203 volatile fl::u32 toggle_count = 0;
204 while (!HarnessDriver::done()) {
207 const fl::u32 t_end =
micros();
208 const fl::u32 total_us = t_end - t_start;
211 s << 1 <<
',' << total_us <<
',' << toggle_count;
219inline fl::string measureSckHandler(
int divider_hint)
FL_NO_EXCEPT {
223 constexpr int kBenchBytes = 512;
224 fl::u8* buf = harnessBuffer();
225 for (
int i = 0; i < kBenchBytes; ++i) buf[i] = 0xA5;
227 HarnessDriver& drv = harnessDriver();
230 const fl::u32 t_start =
micros();
231 HarnessDriver::kickDmaStream(buf,
static_cast<fl::u32
>(kBenchBytes));
232 while (!HarnessDriver::done()) {
240 const fl::u32 t_end =
micros();
241 const fl::u32 total_us = t_end - t_start;
244 s << 1 <<
',' << total_us <<
',' << kBenchBytes;
250#if FASTLED_LPC_DMA_ISR
264#ifndef FASTLED_LPC_SPI_DMA_STREAM_BYTES
265#define FASTLED_LPC_SPI_DMA_STREAM_BYTES 512
267inline fl::string streamOverlapHandler(
int byte_count,
int byte_pattern)
FL_NO_EXCEPT {
268 fl::u8* stream_src = spiDmaStreamState().source;
269 int len = byte_count;
270 if (len <= 0)
return fl::string(
"0,0,0");
271 if (len > FASTLED_LPC_SPI_DMA_STREAM_BYTES)
272 len = FASTLED_LPC_SPI_DMA_STREAM_BYTES;
273 const fl::u8 pat =
static_cast<fl::u8>(byte_pattern & 0xFF);
274 for (
int i = 0; i < len; ++i) stream_src[i] = pat;
276 HarnessDriver& drv = harnessDriver();
279 const fl::u32 t_start =
micros();
280 if (!HarnessDriver::kickDmaStreamAsync(stream_src,
281 static_cast<fl::u32
>(len))) {
282 return fl::string(
"0,kick_refused,0");
284 volatile fl::u32 toggle_count = 0;
286 while (!HarnessDriver::streamDone()) {
288 if (++spins > 4000000u) {
290 d << 0 <<
',' << DMA0->COMMON[0].ACTIVE <<
','
291 << DMA0->CHANNEL[FASTLED_LPC_SPI_DMA_CHANNEL].CTLSTAT <<
','
296 const fl::u32 total_us =
micros() - t_start;
299 s << 1 <<
',' << total_us <<
',' << toggle_count;
309inline int argInt(
const fl::json&
args, fl::size i,
int fallback)
FL_NO_EXCEPT {
310 return static_cast<int>(
args[i].as_int().value_or(fallback));
314 remote.bind(
"dmaSpiTransferOnce",
315 [](
const fl::json&
args) -> fl::string {
316 return transferOnceHandler(argInt(
args, 0, 0), argInt(
args, 1, 0));
318#if FASTLED_LPC_DMA_ISR
319 remote.bind(
"dmaSpiStreamOverlap",
320 [](
const fl::json&
args) -> fl::string {
321 return streamOverlapHandler(argInt(
args, 0, 0), argInt(
args, 1, 0));
324 remote.bind(
"dmaSpiTransferOverlap",
325 [](
const fl::json&
args) -> fl::string {
326 return transferOverlapHandler(argInt(
args, 0, 0), argInt(
args, 1, 0));
328 remote.bind(
"dmaSpiMeasureSck",
329 [](
const fl::json&
args) -> fl::string {
330 return measureSckHandler(argInt(
args, 0, 6));
fl::unique_ptr< fl::Remote > remote
static T & instance() FL_NO_EXCEPT
string str() const FL_NO_EXCEPT
fl::u32 micros()
Universal microsecond timer - returns microseconds since system startup.