Skip to content

Commit

Permalink
#454, SPI.setClockSpeed, SPI.setClockDividerReference for more po…
Browse files Browse the repository at this point in the history
…rtable SPI clock speeds.
  • Loading branch information
m-mcgowan committed Aug 23, 2015
1 parent 0df1758 commit 035d477
Show file tree
Hide file tree
Showing 10 changed files with 174 additions and 3 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
## v0.4.5

### FEATURES
- `SPI.setClockDividerReference`, `SPI.setClockSpeed` to set clock speed in a more portable manner. [#454]https://github.com/spark/firmware/issues/454

### ENHANCEMENTS
- [Recipes and Tips](docs/build.md#recipes-and-tips) section in the build documentation.
Expand Down
13 changes: 13 additions & 0 deletions hal/inc/core_hal.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,19 @@ uint32_t HAL_Core_Runtime_Info(runtime_info_t* info, void* reserved);

extern void app_setup_and_loop();

typedef enum HAL_SystemClock
{
SYSTEMCLOCK_PRIMARY,
SYSTEMCLOCK_SPI
} HAL_SystemClock;

/**
* Retrieves the
* @param reserved
* @return
*/
unsigned HAL_Core_System_Clock(HAL_SystemClock clock, void* reserved);

#ifdef __cplusplus
}
#endif
Expand Down
2 changes: 1 addition & 1 deletion hal/inc/hal_dynalib_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ DYNALIB_FN(hal_core,HAL_Bootloader_Get_Flag)
DYNALIB_FN(hal_core,HAL_Bootloader_Lock)
DYNALIB_FN(hal_core,HAL_Core_System_Reset_FlagSet)
DYNALIB_FN(hal_core,HAL_Core_Runtime_Info)

DYNALIB_FN(hal_core,HAL_Core_System_Clock)
DYNALIB_END(hal_core)


Expand Down
5 changes: 5 additions & 0 deletions hal/src/core/core_hal.c
Original file line number Diff line number Diff line change
Expand Up @@ -381,4 +381,9 @@ uint32_t HAL_Core_Runtime_Info(runtime_info_t* info, void* reserved)
{
info->freeheap = freeheap();
return 0;
}

unsigned HAL_Core_System_Clock(HAL_SystemClock clock, void* reserved)
{
return SystemCoreClock;
}
5 changes: 5 additions & 0 deletions hal/src/gcc/core_hal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -261,3 +261,8 @@ uint16_t HAL_Bootloader_Get_Flag(BootloaderFlag flag)
void HAL_Core_Enter_Bootloader(bool persist)
{
}

unsigned HAL_Core_System_Clock(HAL_SystemClock clock, void* reserved)
{
return 1;
}
4 changes: 4 additions & 0 deletions hal/src/stm32f2xx/core_hal_stm32f2xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -812,3 +812,7 @@ bool HAL_Core_System_Reset_FlagSet(RESET_TypeDef resetType)
return false;
}

unsigned HAL_Core_System_Clock(HAL_SystemClock clock, void* reserved)
{
return SystemCoreClock;
}
6 changes: 6 additions & 0 deletions hal/src/template/core_hal.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,9 @@ uint16_t HAL_Core_Mode_Button_Pressed_Time()
void HAL_Bootloader_Lock(bool lock)
{
}


unsigned HAL_Core_System_Clock(HAL_SystemClock clock, void* reserved)
{
return 1;
}
32 changes: 32 additions & 0 deletions user/tests/wiring/api/peripherals.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@

#include "testapi.h"
#include "spark_wiring_spi.h"

test(SPI_clock)
{
API_COMPILE(SPI.setClockDivider(SPI_CLOCK_DIV2));
API_COMPILE(SPI.setClockDivider(SPI_CLOCK_DIV256));
API_COMPILE(SPI.setClockSpeed(100, MHZ));
API_COMPILE(SPI.setClockSpeed(100, KHZ));
API_COMPILE(SPI.setClockSpeed(ARDUINO));
API_COMPILE(SPI.setClockSpeed(ARDUINO/4));
API_COMPILE(SPI.setClockDividerReference(ARDUINO));
}

#if Wiring_SPI1
test(SPI1_begin)
{
API_COMPILE(SPI1.begin());
}

test(SPI1_clock)
{
API_COMPILE(SPI1.setClockDivider(SPI_CLOCK_DIV2));
API_COMPILE(SPI1.setClockDivider(SPI_CLOCK_DIV256));
API_COMPILE(SPI1.setClockSpeed(100, MHZ));
API_COMPILE(SPI1.setClockSpeed(100, KHZ));
API_COMPILE(SPI1.setClockSpeed(ARDUINO));
API_COMPILE(SPI1.setClockSpeed(ARDUINO/4));
API_COMPILE(SPI1.setClockDividerReference(ARDUINO));
}
#endif
48 changes: 47 additions & 1 deletion wiring/inc/spark_wiring_spi.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,27 @@

typedef void (*wiring_spi_dma_transfercomplete_callback_t)(void);

enum FrequencyScale
{
HZ = 1,
KHZ = HZ*1000,
MHZ = KHZ*1000,
SYSTEM = 0, // represents the system clock speed
ARDUINO = 16*MHZ,
CORE = 72*MHZ,
PHOTON = 120*MHZ
};

class SPIClass {
private:
HAL_SPI_Interface _spi;

/**
* Set the divider reference clock.
* The default is the system clock.
*/
unsigned dividerReference;

public:
SPIClass(HAL_SPI_Interface spi);
virtual ~SPIClass() {};
Expand All @@ -47,7 +64,36 @@ class SPIClass {

void setBitOrder(uint8_t);
void setDataMode(uint8_t);
void setClockDivider(uint8_t);

/**
* Sets the clock speed that the divider is relative to. This does not change
* the assigned clock speed until the next call to {@link #setClockDivider}
* @param value The clock speed reference value
* @param scale The clock speed reference scalar
*
* E.g.
*
* setClockDividerReference(ARDUINO);
* setClockDividerReference(16, MHZ);
*
* @see #setClockDivider
*/
void setClockDividerReference(unsigned value, unsigned scale=HZ);

/**
* Sets the clock speed as a divider relative to the clock divider reference.
* @param divider SPI_CLOCK_DIVx where x is a power of 2 from 2 to 256.
*/
void setClockDivider(uint8_t divider);

/**
* Sets the absolute clock speed. This will select the clock divider that is no greater than
* {@code value*scale}.
* @param value
* @param scale
* @return the actual clock speed set.
*/
unsigned setClockSpeed(unsigned value, unsigned scale=HZ);

byte transfer(byte _data);
void transfer(void* tx_buffer, void* rx_buffer, size_t length, wiring_spi_dma_transfercomplete_callback_t user_callback);
Expand Down
61 changes: 60 additions & 1 deletion wiring/src/spark_wiring_spi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
*/

#include "spark_wiring_spi.h"
#include "core_hal.h"
#include "spark_macros.h"

#ifndef SPARK_WIRING_NO_SPI
SPIClass SPI(HAL_SPI_INTERFACE1);
Expand All @@ -39,6 +41,7 @@ SPIClass::SPIClass(HAL_SPI_Interface spi)
{
_spi = spi;
HAL_SPI_Init(_spi);
dividerReference = SYSTEM; // 0 indicates the system clock
}

void SPIClass::begin()
Expand Down Expand Up @@ -71,9 +74,65 @@ void SPIClass::setDataMode(uint8_t mode)
HAL_SPI_Set_Data_Mode(_spi, mode);
}

void SPIClass::setClockDividerReference(unsigned value, unsigned scale)
{
dividerReference = value*scale;
}

/**
* The divisors. The index+1 is the power of 2 of the divisor.
*/
static uint8_t clock_divisors[] = {
SPI_CLOCK_DIV2,
SPI_CLOCK_DIV4,
SPI_CLOCK_DIV8,
SPI_CLOCK_DIV16,
SPI_CLOCK_DIV32,
SPI_CLOCK_DIV64,
SPI_CLOCK_DIV128,
SPI_CLOCK_DIV256,
SPI_CLOCK_DIV256 // additional element so no match results in 256 being returned
};

uint8_t divisorShiftScale(uint8_t divider)
{
unsigned result = 0;
for (; result<arraySize(clock_divisors)-1; result++)
{
if (clock_divisors[result]==divider)
break;
}
return result;
}

void SPIClass::setClockDivider(uint8_t rate)
{
HAL_SPI_Set_Clock_Divider(_spi, rate);
if (dividerReference)
{
// determine the clock speed
uint8_t scale = divisorShiftScale(rate);
unsigned targetSpeed = dividerReference>>scale;
setClockSpeed(targetSpeed);
}
else
{
HAL_SPI_Set_Clock_Divider(_spi, rate);
}
}

unsigned SPIClass::setClockSpeed(unsigned value, unsigned value_scale)
{
// actual speed is the system clock divided by some scalar
unsigned targetSpeed = value*value_scale;
unsigned clock = HAL_Core_System_Clock(SYSTEMCLOCK_SPI, NULL);
uint8_t scale = 0;
while (clock > targetSpeed) {
clock >>= 1;
scale++;
}
uint8_t rate = clock_divisors[scale-1];
HAL_SPI_Set_Clock_Divider(_spi, rate);
return clock;
}

byte SPIClass::transfer(byte _data)
Expand Down

0 comments on commit 035d477

Please sign in to comment.