Skip to content

Commit

Permalink
Better SPI functionality - but pauses between bytes...
Browse files Browse the repository at this point in the history
  • Loading branch information
PaulZC committed Apr 10, 2020
1 parent 9f3f693 commit 68b9bfb
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 50 deletions.
55 changes: 38 additions & 17 deletions platforms/apollo3/clockless_apollo3.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,22 @@ FASTLED_NAMESPACE_BEGIN

#if defined(FASTLED_APOLLO3)

//*****************************************************************************
//
// Code taken from Ambiq Micro's am_hal_systick.c
// and converted to inline static for speed
//
//! @brief Get the current count value in the SYSTICK.
//!
//! This function gets the current count value in the systick timer.
//!
//! @return Current count value.
//
//*****************************************************************************
__attribute__ ((always_inline)) inline static uint32_t __am_hal_systick_count() {
return SysTick->VAL;
}

#define FASTLED_HAS_CLOCKLESS 1

template <int DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 50>
Expand All @@ -27,25 +43,25 @@ class ClocklessController : public CPixelLEDController<RGB_ORDER> {
am_hal_clkgen_control(AM_HAL_CLKGEN_CONTROL_SYSCLK_MAX, 0);

// Make sure interrupts are enabled
am_hal_interrupt_master_enable();
//am_hal_interrupt_master_enable();

// Enable SysTick Interrupts in the NVIC
NVIC_EnableIRQ(SysTick_IRQn);
//NVIC_EnableIRQ(SysTick_IRQn);

// SysTick is 24-bit and counts down (not up)

// Stop the SysTick (just in case it is already running).
// This clears the ENABLE bit in the SysTick Control and Status Register (SYST_CSR).
// In Ambiq naming convention: the control register is SysTick->CTRL
// In Ambiq naming convention, the control register is SysTick->CTRL
am_hal_systick_stop();

// Call SysTick_Config
// This is defined in core_cm4.h
// It loads the specified LOAD value into the SysTick Reload Value Register (SYST_RVR)
// In Ambiq naming convention: the reload register is SysTick->LOAD
// In Ambiq naming convention, the reload register is SysTick->LOAD
// It sets the SysTick interrupt priority
// It clears the SysTick Current Value Register (SYST_CVR)
// In Ambiq naming convention: the current value register is SysTick->VAL
// In Ambiq naming convention, the current value register is SysTick->VAL
// Finally it sets these bits in the SysTick Control and Status Register (SYST_CSR):
// CLKSOURCE: SysTick uses the processor clock
// TICKINT: When the count reaches zero, the SysTick exception (interrupt) is changed to pending
Expand All @@ -70,31 +86,35 @@ class ClocklessController : public CPixelLEDController<RGB_ORDER> {
template<int BITS> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register uint8_t & b) {
// SysTick counts down (not up) and is 24-bit
for(register uint32_t i = BITS-1; i > 0; i--) { // We could speed this up by using Bit Banding
while(am_hal_systick_count() > next_mark) { ; } // Wait for the remainder of this cycle to complete
while(__am_hal_systick_count() > next_mark) { ; } // Wait for the remainder of this cycle to complete
// Calculate next_mark (the time of the next DATA_PIN transition) by subtracting T1+T2+T3
// SysTick counts down (not up) and is 24-bit
next_mark = (am_hal_systick_count() - (T1+T2+T3)) & 0xFFFFFFUL;
next_mark = (__am_hal_systick_count() - (T1+T2+T3)) & 0xFFFFFFUL;
FastPin<DATA_PIN>::hi();
if(b&0x80) {
while((am_hal_systick_count() - next_mark) > (T3)) { ; }
// "1 code" = longer pulse width
while((__am_hal_systick_count() - next_mark) > (T3+(3*(F_CPU/24000000)))) { ; }
FastPin<DATA_PIN>::lo();
} else {
while((am_hal_systick_count() - next_mark) > (T2+T3)) { ; }
// "0 code" = shorter pulse width
while((__am_hal_systick_count() - next_mark) > (T2+T3+(4*(F_CPU/24000000)))) { ; }
FastPin<DATA_PIN>::lo();
}
b <<= 1;
}

while(am_hal_systick_count() > next_mark) { ; }// Wait for the remainder of this cycle to complete
while(__am_hal_systick_count() > next_mark) { ; }// Wait for the remainder of this cycle to complete
// Calculate next_mark (the time of the next DATA_PIN transition) by subtracting T1+T2+T3
// SysTick counts down (not up) and is 24-bit
next_mark = (am_hal_systick_count() - (T1+T2+T3)) & 0xFFFFFFUL;
next_mark = (__am_hal_systick_count() - (T1+T2+T3)) & 0xFFFFFFUL;
FastPin<DATA_PIN>::hi();
if(b&0x80) {
while((am_hal_systick_count() - next_mark) > (T3)) { ; }
// "1 code" = longer pulse width
while((__am_hal_systick_count() - next_mark) > (T3+(2*(F_CPU/24000000)))) { ; }
FastPin<DATA_PIN>::lo();
} else {
while((am_hal_systick_count() - next_mark) > (T2+T3)) { ; }
// "0 code" = shorter pulse width
while((__am_hal_systick_count() - next_mark) > (T2+T3+(4*(F_CPU/24000000)))) { ; }
FastPin<DATA_PIN>::lo();
}
}
Expand All @@ -112,7 +132,7 @@ class ClocklessController : public CPixelLEDController<RGB_ORDER> {
// Calculate next_mark (the time of the next DATA_PIN transition) by subtracting T1+T2+T3
// SysTick counts down (not up) and is 24-bit
// The subtraction could underflow (wrap round) so let's mask the result to 24 bits
register uint32_t next_mark = (am_hal_systick_count() - (T1+T2+T3)) & 0xFFFFFFUL;
register uint32_t next_mark = (__am_hal_systick_count() - (T1+T2+T3)) & 0xFFFFFFUL;

while(pixels.has(1)) { // Keep going for as long as we have pixels
pixels.stepDithering();
Expand All @@ -121,9 +141,9 @@ class ClocklessController : public CPixelLEDController<RGB_ORDER> {
cli();

// Have we already missed the next_mark?
if(am_hal_systick_count() < next_mark) {
if(__am_hal_systick_count() < next_mark) {
// If we have exceeded next_mark by an excessive amount, then bail (return 0)
if((next_mark - am_hal_systick_count()) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { sei(); return 0; }
if((next_mark - __am_hal_systick_count()) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { sei(); return 0; }
}
#endif

Expand All @@ -144,7 +164,8 @@ class ClocklessController : public CPixelLEDController<RGB_ORDER> {
#endif
}; // end of while(pixels.has(1))

// Unfortunately SysTick relies on interrupts to reload it once it reaches zero
// Unfortunately SysTick relies on an interrupt to reload it once it reaches zero
// and having interrupts disabled for most of the above means the interrupt doesn't get serviced.
// So we had better reload it here instead...
am_hal_systick_load(0xFFFFFFUL);

Expand Down
53 changes: 36 additions & 17 deletions platforms/apollo3/fastpin_apollo3.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,12 @@ _FL_DEFPIN(15); _FL_DEFPIN(16); _FL_DEFPIN(17); _FL_DEFPIN(18); _FL_DEFPIN(19);
_FL_DEFPIN(20); _FL_DEFPIN(21); _FL_DEFPIN(22); _FL_DEFPIN(23); _FL_DEFPIN(24);
_FL_DEFPIN(25); _FL_DEFPIN(26); _FL_DEFPIN(27); _FL_DEFPIN(28); _FL_DEFPIN(29);
_FL_DEFPIN(30); _FL_DEFPIN(31);
//These two lines are commented out as dedicates SPI support using fastShiftOut produces
//glitchy results that is slower than bit banging. TO DO: implement 'proper' SPI functionality
//#define SPI_DATA MOSI
//#define SPI_CLOCK SCK

//The Artemis RedBoard has 4 SPI ports defined by default
//TO DO: implement multiple SPI functionality
//#define AP3_FASTLED_SPI_IOM 0
#define SPI_DATA MOSI
#define SPI_CLOCK SCK

#define HAS_HARDWARE_PIN_SUPPORT 1

Expand All @@ -98,10 +100,9 @@ _FL_DEFPIN(10); _FL_DEFPIN(11); _FL_DEFPIN(12); _FL_DEFPIN(13); _FL_DEFPIN(14);
_FL_DEFPIN(15); _FL_DEFPIN(16); _FL_DEFPIN(17); _FL_DEFPIN(18); _FL_DEFPIN(19);
_FL_DEFPIN(20); _FL_DEFPIN(21); _FL_DEFPIN(22); _FL_DEFPIN(23);

//These two lines are commented out as dedicates SPI support using fastShiftOut produces
//glitchy results that is slower than bit banging. TO DO: implement 'proper' SPI functionality
//#define SPI_DATA MOSI
//#define SPI_CLOCK SCK
//#define AP3_FASTLED_SPI_IOM 0
#define SPI_DATA MOSI
#define SPI_CLOCK SCK

#define HAS_HARDWARE_PIN_SUPPORT 1

Expand All @@ -115,14 +116,33 @@ _FL_DEFPIN(15); _FL_DEFPIN(16); _FL_DEFPIN(17); _FL_DEFPIN(18); _FL_DEFPIN(19);
_FL_DEFPIN(20); _FL_DEFPIN(21); _FL_DEFPIN(22); _FL_DEFPIN(23); _FL_DEFPIN(24);
_FL_DEFPIN(25); _FL_DEFPIN(26); _FL_DEFPIN(27); _FL_DEFPIN(28);

//These two lines are commented out as dedicates SPI support using fastShiftOut produces
//glitchy results that is slower than bit banging. TO DO: implement 'proper' SPI functionality
//#define SPI_DATA MOSI
//#define SPI_CLOCK SCK
//#define AP3_FASTLED_SPI_IOM 0
#define SPI_DATA MOSI
#define SPI_CLOCK SCK

#define HAS_HARDWARE_PIN_SUPPORT 1

#elif defined(ARDUINO_AM_AP3_SFE_BB_ARTEMIS_ATP)

#define MAX_PIN 50 // AP3_VARIANT_NUM_PINS
_FL_DEFPIN(0); _FL_DEFPIN(1); _FL_DEFPIN(2); _FL_DEFPIN(3); _FL_DEFPIN(4);
_FL_DEFPIN(5); _FL_DEFPIN(6); _FL_DEFPIN(7); _FL_DEFPIN(8); _FL_DEFPIN(9);
_FL_DEFPIN(10); _FL_DEFPIN(11); _FL_DEFPIN(12); _FL_DEFPIN(13); _FL_DEFPIN(14);
_FL_DEFPIN(15); _FL_DEFPIN(16); _FL_DEFPIN(17); _FL_DEFPIN(18); _FL_DEFPIN(19);
_FL_DEFPIN(20); _FL_DEFPIN(21); _FL_DEFPIN(22); _FL_DEFPIN(23); _FL_DEFPIN(24);
_FL_DEFPIN(25); _FL_DEFPIN(26); _FL_DEFPIN(27); _FL_DEFPIN(28); _FL_DEFPIN(29);
_FL_DEFPIN(31); _FL_DEFPIN(32); _FL_DEFPIN(33); _FL_DEFPIN(34);
_FL_DEFPIN(35); _FL_DEFPIN(36); _FL_DEFPIN(37); _FL_DEFPIN(38); _FL_DEFPIN(39);
_FL_DEFPIN(40); _FL_DEFPIN(41); _FL_DEFPIN(42); _FL_DEFPIN(43); _FL_DEFPIN(44);
_FL_DEFPIN(45); _FL_DEFPIN(47); _FL_DEFPIN(48); _FL_DEFPIN(49);

//#define AP3_FASTLED_SPI_IOM 0
#define SPI_DATA MOSI
#define SPI_CLOCK SCK

#define HAS_HARDWARE_PIN_SUPPORT 1

#elif defined(ARDUINO_AM_AP3_SFE_BB_ARTEMIS_ATP) || defined(ARDUINO_SFE_ARTEMIS)
#elif defined(ARDUINO_SFE_ARTEMIS)

#define MAX_PIN 50 // AP3_VARIANT_NUM_PINS
// Pin definitions taken from (e.g.) C:\Users\...\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\1.0.30\variants\redboard_artemis_atp\config\variant.cpp
Expand All @@ -138,10 +158,9 @@ _FL_DEFPIN(35); _FL_DEFPIN(36); _FL_DEFPIN(37); _FL_DEFPIN(38); _FL_DEFPIN(39);
_FL_DEFPIN(40); _FL_DEFPIN(41); _FL_DEFPIN(42); _FL_DEFPIN(43); _FL_DEFPIN(44);
_FL_DEFPIN(45); _FL_DEFPIN(47); _FL_DEFPIN(48); _FL_DEFPIN(49);

//These two lines are commented out as dedicates SPI support using fastShiftOut produces
//glitchy results that is slower than bit banging. TO DO: implement 'proper' SPI functionality
//#define SPI_DATA MOSI
//#define SPI_CLOCK SCK
//The Artemis module has all six SPI ports defined by default _but_
//does not assign pins for them.
//TO DO: implement multiple SPI functionality with correct pin mapping

#define HAS_HARDWARE_PIN_SUPPORT 1

Expand Down
56 changes: 40 additions & 16 deletions platforms/apollo3/fastspi_apollo3.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@

FASTLED_NAMESPACE_BEGIN

template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint32_t SPI_CLOCK_DIVIDER>
#if defined(FASTLED_APOLLO3)

#include <SPI.h>

template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint32_t SPI_CLOCK_SPEED>
class APOLLO3HardwareSPIOutput {
Selectable *m_pSelect;

Expand All @@ -19,21 +23,34 @@ class APOLLO3HardwareSPIOutput {
// initialize the SPI subssytem
void init() {
//enableBurstMode(); //Optional. Go to 96MHz. Roughly doubles the speed of shiftOut and fastShiftOut
enableFastShift(_DATA_PIN, _CLOCK_PIN);
pinMode(_DATA_PIN, OUTPUT);
pinMode(_CLOCK_PIN, OUTPUT);
am_hal_gpio_fastgpio_enable(_DATA_PIN);
am_hal_gpio_fastgpio_enable(_CLOCK_PIN);
SPI.begin();
}

// latch the CS select
void inline select() { /* TODO */ }
void inline select() __attribute__((always_inline)) {
// Begin the SPI transaction
// We want CPOL/CKP to be 0 and CPHA to be 0 so we need SPI Mode 0
SPI.beginTransaction(SPISettings((F_CPU/SPI_CLOCK_SPEED), MSBFIRST, AM_HAL_IOM_SPI_MODE_0));
if(m_pSelect != NULL) { m_pSelect->select(); }
}

// release the CS select
void inline release() { /* TODO */ }
void inline release() {
if(m_pSelect != NULL) { m_pSelect->release(); }
SPI.endTransaction();
}

// wait until all queued up data has been written
static void waitFully() { /* TODO */ }

// write a byte out via SPI (returns immediately on writing register)
static void writeByte(uint8_t b) {
fastShiftOut(_DATA_PIN, _CLOCK_PIN, MSBFIRST, b);
//fastShiftOut(_DATA_PIN, _CLOCK_PIN, MSBFIRST, b);
SPI.transferOut(&b,1);
}

// write a word out via SPI (returns immediately on writing register)
Expand All @@ -49,22 +66,22 @@ class APOLLO3HardwareSPIOutput {

// A full cycle of writing a value for len bytes, including select, release, and waiting
void writeBytesValue(uint8_t value, int len) {
//select();
select();
writeBytesValueRaw(value, len);
//release();
release();
}

// A full cycle of writing a value for len bytes, including select, release, and waiting
template <class D> void writeBytes(register uint8_t *data, int len) {
uint8_t *end = data + len;
//select();
select();
// could be optimized to write 16bit words out instead of 8bit bytes
while(data != end) {
writeByte(D::adjust(*data++));
}
D::postBlock(len);
//waitFully();
//release();
waitFully();
release();
}

// A full cycle of writing a value for len bytes, including select, release, and waiting
Expand All @@ -74,19 +91,24 @@ class APOLLO3HardwareSPIOutput {
template <uint8_t BIT> inline static void writeBit(uint8_t b) {
//waitFully();
if(b & (1 << BIT)) {
FastPin<_DATA_PIN>::hi();
//digitalWrite(_DATA_PIN, HIGH); //FastPin<_DATA_PIN>::hi();
am_hal_gpio_fastgpio_set(_DATA_PIN);
} else {
FastPin<_DATA_PIN>::lo();
//digitalWrite(_DATA_PIN, LOW); //FastPin<_DATA_PIN>::lo();
am_hal_gpio_fastgpio_clr(_DATA_PIN);
}

FastPin<_CLOCK_PIN>::hi();
FastPin<_CLOCK_PIN>::lo();
//digitalWrite(_CLOCK_PIN, HIGH);
//digitalWrite(_CLOCK_PIN, LOW);
am_hal_gpio_fastgpio_set(_CLOCK_PIN);
__NOP();
am_hal_gpio_fastgpio_clr(_CLOCK_PIN);
}

// write a block of uint8_ts out in groups of three. len is the total number of uint8_ts to write out. The template
// parameters indicate how many uint8_ts to skip at the beginning and/or end of each grouping
template <uint8_t FLAGS, class D, EOrder RGB_ORDER> void writePixels(PixelController<RGB_ORDER> pixels) {
//select();
select();

int len = pixels.mLen;

Expand All @@ -108,11 +130,13 @@ class APOLLO3HardwareSPIOutput {
}
D::postBlock(len);
//waitFully();
//release();
release();
}

};

#endif

FASTLED_NAMESPACE_END

#endif

0 comments on commit 68b9bfb

Please sign in to comment.