ready to alpha
подготовка к альфа-тестированию
This commit is contained in:
commit
e36b851783
164 files changed
+27352
No files matched your search
@@ -0,0 +1,339 @@
|
||||
#include "SPI.h"
|
||||
#include "mik32_hal_spi.h"
|
||||
|
||||
SPI_HandleTypeDef hspi;
|
||||
bool newConfig = false;
|
||||
bool isInited = false;
|
||||
uint32_t currentSpeed = 0;
|
||||
int8_t currentDataOrder = -1;
|
||||
int8_t currentDataMode = -1;
|
||||
static uint8_t reverse_bits(uint8_t byte);
|
||||
|
||||
// ------------------------------------------------------------------ //
|
||||
|
||||
void SPISettings::spiUpdateSettings(uint32_t speedMaximum, uint8_t dataOrder, uint8_t dataMode)
|
||||
{
|
||||
// update config only if something has changed
|
||||
if ((currentSpeed != speedMaximum) || (currentDataOrder != dataOrder) ||
|
||||
(currentDataMode != dataMode))
|
||||
{
|
||||
// Find the fastest clock that is less than or equal to the
|
||||
// given clock rate. If nothing is slow enough - use the slowest.
|
||||
// mik32v2 has the set of deviders, that can be calculate as:
|
||||
// div = 2 << (1...7). Value in braсkets is a value for config register
|
||||
uint8_t divRegVal = 0; // start from minimal divider (maximum speed)
|
||||
while(divRegVal < 7)
|
||||
{
|
||||
divRegVal++; // values from 1 to 7
|
||||
if ((F_CPU/(2 << divRegVal)) <= speedMaximum)
|
||||
// find suitable divider
|
||||
break;
|
||||
}
|
||||
// if break didn't call in cycle, it will be the greatest divRegVal (and divider)
|
||||
|
||||
// update config
|
||||
hspi.Instance = SPI_1;
|
||||
hspi.Init.SPI_Mode = HAL_SPI_MODE_MASTER; // only master mode
|
||||
hspi.Init.CLKPhase = dataMode & 0b00000001;
|
||||
hspi.Init.CLKPolarity = (dataMode & 0b00000010)>>1;
|
||||
hspi.Init.ThresholdTX = 4;
|
||||
hspi.Init.BaudRateDiv = divRegVal;
|
||||
hspi.Init.Decoder = SPI_DECODER_NONE;
|
||||
hspi.Init.ManualCS = SPI_MANUALCS_ON;
|
||||
hspi.Init.ChipSelect = SPI_CS_NONE;
|
||||
|
||||
currentSpeed = speedMaximum;
|
||||
currentDataOrder = dataOrder;
|
||||
currentDataMode = dataMode;
|
||||
newConfig = true;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------ //
|
||||
// pins shift in gpio register
|
||||
#define PIN_1_3_GPIO_S 3
|
||||
#define PIN_1_4_GPIO_S 4
|
||||
|
||||
SPIClass SPI;
|
||||
bool SPIClass::spiInUse = false;
|
||||
uint8_t SPIClass::interruptMode = 0;
|
||||
uint8_t SPIClass::interruptMask = 0;
|
||||
|
||||
void SPIClass::begin()
|
||||
{
|
||||
// there is a seller on pin 1.6 which replace D10 from spi NSS pin 1.3 to pin 1.4,
|
||||
// because spi needs pin 1.3 for correct work
|
||||
|
||||
// replace config from 1.3 to 1.4
|
||||
uint8_t config = ((PAD_CONFIG->PORT_1_CFG) & (0b11<<(2*PIN_1_3_GPIO_S))) >> (2*PIN_1_3_GPIO_S);
|
||||
if (config == 0) // common gpio
|
||||
{
|
||||
// pin direction
|
||||
uint8_t direction = ((GPIO_1->DIRECTION_IN) & (1<<PIN_1_3_GPIO_S)) >> PIN_1_3_GPIO_S;
|
||||
if (direction == 1) // input
|
||||
GPIO_1->DIRECTION_IN |= (1<<PIN_1_4_GPIO_S);
|
||||
else // output
|
||||
GPIO_1->DIRECTION_OUT |= (1<<PIN_1_4_GPIO_S);
|
||||
|
||||
// pull up/down
|
||||
uint8_t pupd_1_3 = ((PAD_CONFIG ->PORT_1_PUPD) & (0b11<<(2*PIN_1_3_GPIO_S))) >> (2*PIN_1_3_GPIO_S);
|
||||
PAD_CONFIG ->PORT_1_PUPD &= (~(0b11<<(2*PIN_1_4_GPIO_S))); // clear
|
||||
PAD_CONFIG ->PORT_1_PUPD |= ((pupd_1_3&0b11)<<(2*PIN_1_4_GPIO_S)); // set new
|
||||
|
||||
//current state
|
||||
uint8_t state1_3 = ((GPIO_1->OUTPUT_) & (1<<PIN_1_3_GPIO_S)) >> PIN_1_3_GPIO_S;
|
||||
GPIO_1->OUTPUT_ &= (~(0b1<<PIN_1_4_GPIO_S)); // clear
|
||||
GPIO_1->OUTPUT_ |= ((state1_3&0b1)<<PIN_1_4_GPIO_S); // set new
|
||||
}
|
||||
else if(config == 2) // timer for pwm
|
||||
{
|
||||
// if D10 (spi NSS pin) was used as pwm, we need to stop timer,
|
||||
// because 1.4 don't support timer
|
||||
analogWriteStop(10);
|
||||
ErrorMsgHandler("analogWrite(): D10 cannot be used as PWM pin while SPI is running");
|
||||
}
|
||||
|
||||
// switch seller to pin 1.4
|
||||
HAL_GPIO_PinConfig(GPIO_1, GPIO_PIN_6, HAL_GPIO_MODE_GPIO_OUTPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA);
|
||||
HAL_GPIO_WritePin(GPIO_1, GPIO_PIN_6, GPIO_PIN_HIGH);
|
||||
blockSpiPin();
|
||||
|
||||
spiInUse = true;
|
||||
}
|
||||
|
||||
void SPIClass::end()
|
||||
{
|
||||
if (spiInUse && isInited)
|
||||
{
|
||||
// turn off spi
|
||||
HAL_SPI_Disable(&hspi);
|
||||
|
||||
// deinit spi gpio pins
|
||||
if (hspi.Instance == SPI_1) // only spi1 is using in currunt version
|
||||
{
|
||||
HAL_GPIO_PinConfig(GPIO_1, (HAL_PinsTypeDef)(GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2),
|
||||
HAL_GPIO_MODE_GPIO_INPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA);
|
||||
}
|
||||
|
||||
// return D10 with common gpio config to pin 1.3
|
||||
PAD_CONFIG->PORT_1_CFG &= (~(0b11<<(2*PIN_1_3_GPIO_S))); // set config to 0 - common gpio mode
|
||||
|
||||
// pin direction
|
||||
uint8_t direction = ((GPIO_1->DIRECTION_IN) & (1<<PIN_1_4_GPIO_S)) >> PIN_1_4_GPIO_S;
|
||||
if (direction == 1) // input
|
||||
GPIO_1->DIRECTION_IN |= (1<<PIN_1_3_GPIO_S);
|
||||
else // output
|
||||
GPIO_1->DIRECTION_OUT |= (1<<PIN_1_3_GPIO_S);
|
||||
|
||||
// pull up/down
|
||||
uint8_t pupd_1_4 = ((PAD_CONFIG ->PORT_1_PUPD) & (0b11<<(2*PIN_1_4_GPIO_S))) >> (2*PIN_1_4_GPIO_S);
|
||||
PAD_CONFIG ->PORT_1_PUPD &= (~(0b11<<(2*PIN_1_3_GPIO_S))); // clear
|
||||
PAD_CONFIG ->PORT_1_PUPD |= ((pupd_1_4&0b11)<<(2*PIN_1_3_GPIO_S)); // set new
|
||||
|
||||
// current state
|
||||
uint8_t state1_4 = ((GPIO_1->OUTPUT_) & (1<<PIN_1_4_GPIO_S)) >> PIN_1_4_GPIO_S;
|
||||
GPIO_1->OUTPUT_ &= (~(0b1<<PIN_1_3_GPIO_S)); // clear
|
||||
GPIO_1->OUTPUT_ |= ((state1_4&0b1)<<PIN_1_3_GPIO_S); // set new
|
||||
|
||||
// switch seller back to pin 1.3
|
||||
HAL_GPIO_WritePin(GPIO_1, GPIO_PIN_6, GPIO_PIN_LOW);
|
||||
unblockSpiPin();
|
||||
|
||||
spiInUse = false;
|
||||
isInited = false;
|
||||
interruptMode = 0;
|
||||
interruptMask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SPIClass::usingInterrupt(uint8_t interruptNumber)
|
||||
{
|
||||
if(interruptNumber < EXTERNAL_NUM_INTERRUPTS)
|
||||
{
|
||||
noInterrupts(); // prevent transactionBegin
|
||||
interruptMask |= (1 << interruptNumber); // add new interrupt to mask
|
||||
if (!interruptMode)
|
||||
interruptMode = 1;
|
||||
interrupts();
|
||||
}
|
||||
}
|
||||
|
||||
void SPIClass::notUsingInterrupt(uint8_t interruptNumber)
|
||||
{
|
||||
if(interruptNumber < EXTERNAL_NUM_INTERRUPTS)
|
||||
{
|
||||
noInterrupts(); // prevent transactionBegin
|
||||
interruptMask &= ~(1<<interruptNumber); // delete interrupt from mask
|
||||
if (!interruptMask)
|
||||
interruptMode = 0;
|
||||
interrupts();
|
||||
}
|
||||
}
|
||||
|
||||
void SPIClass::beginTransaction(SPISettings settings)
|
||||
{
|
||||
// disable interrupts in use if necessary
|
||||
if (spiInUse && (interruptMode > 0))
|
||||
{
|
||||
for (uint8_t i = 0; i < EXTERNAL_NUM_INTERRUPTS; i++)
|
||||
{
|
||||
if (interruptMask & (1 << i))
|
||||
// disable every interrupt by it's number
|
||||
disableInterrupt(i);
|
||||
}
|
||||
}
|
||||
|
||||
// initialize spi bus or update config
|
||||
if(spiInUse && ((!isInited) || newConfig))
|
||||
{
|
||||
// initialize spi with given settings
|
||||
if (HAL_SPI_Init(&hspi) != HAL_OK)
|
||||
ErrorMsgHandler("SPI.beginTransaction(): initialization error");
|
||||
else
|
||||
isInited = true;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t SPIClass::transfer(uint8_t data)
|
||||
{
|
||||
uint8_t rxByte = 0;
|
||||
|
||||
if (isInited)
|
||||
{
|
||||
// reverse bits if LSB mode needed
|
||||
if (currentDataOrder == LSBFIRST)
|
||||
data = reverse_bits(data);
|
||||
|
||||
// send and recieve data
|
||||
HAL_StatusTypeDef SPI_Status = HAL_SPI_Exchange(&hspi, &data, &rxByte, 1, SPI_TIMEOUT_DEFAULT*2);
|
||||
if (SPI_Status != HAL_OK)
|
||||
HAL_SPI_ClearError(&hspi);
|
||||
|
||||
// reverse bits again if LSB mode needed
|
||||
if (currentDataOrder == LSBFIRST)
|
||||
rxByte = reverse_bits(rxByte);
|
||||
}
|
||||
return rxByte;
|
||||
}
|
||||
|
||||
uint16_t SPIClass::transfer16(uint16_t data)
|
||||
{
|
||||
uint8_t buf[2];
|
||||
uint16_t rxVal = 0;
|
||||
if (isInited)
|
||||
{
|
||||
// prepare data for send
|
||||
if (currentDataOrder == LSBFIRST)
|
||||
{
|
||||
// least significant byte is forward and reverse bits inside each byte
|
||||
buf[0] = reverse_bits(data&0xFF);
|
||||
buf[1] = reverse_bits((data>>8)&0xFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
// most significant byte is forward
|
||||
buf[0] = (data>>8)&0xFF;
|
||||
buf[1] = data&0xFF;
|
||||
}
|
||||
|
||||
// send and recieve data
|
||||
HAL_StatusTypeDef SPI_Status = HAL_SPI_Exchange(&hspi, buf, buf, 2, SPI_TIMEOUT_DEFAULT*2);
|
||||
if (SPI_Status != HAL_OK)
|
||||
HAL_SPI_ClearError(&hspi);
|
||||
|
||||
// process the received data
|
||||
if (currentDataOrder == LSBFIRST)
|
||||
// reverse bits for LSB mode
|
||||
rxVal = ( ((uint16_t)reverse_bits(buf[1]) ) << 8) | reverse_bits(buf[0]);
|
||||
else
|
||||
rxVal = ( ((uint16_t)buf[0]) << 8) | buf[1];
|
||||
}
|
||||
return rxVal;
|
||||
}
|
||||
|
||||
void SPIClass::transfer(void *buf, size_t count)
|
||||
{
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
if (isInited)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)buf;
|
||||
|
||||
// reverse bits in buffer if LSB mode needed
|
||||
if (currentDataOrder == LSBFIRST)
|
||||
{
|
||||
for (uint32_t i = 0; i < count; i++)
|
||||
*(p+i) = reverse_bits(*(p+i));
|
||||
}
|
||||
|
||||
// send and recieve data using the same buffer
|
||||
HAL_StatusTypeDef SPI_Status = HAL_SPI_Exchange(&hspi, (uint8_t*)buf, (uint8_t*)buf, count, SPI_TIMEOUT_DEFAULT*2);
|
||||
if (SPI_Status != HAL_OK)
|
||||
HAL_SPI_ClearError(&hspi);
|
||||
|
||||
// reverse bits if LSB mode needed
|
||||
if (currentDataOrder == LSBFIRST)
|
||||
{
|
||||
p = (uint8_t *)buf; // return to buf beginning
|
||||
for (uint32_t i = 0; i < count; i++)
|
||||
*(p+i) = reverse_bits(*(p+i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SPIClass::endTransaction(void)
|
||||
{
|
||||
// enable interrupts in use
|
||||
if (spiInUse && (interruptMode > 0))
|
||||
{
|
||||
for (uint8_t i = 0; i < EXTERNAL_NUM_INTERRUPTS; i++)
|
||||
{
|
||||
if (interruptMask & (1 << i))
|
||||
// enable every interrupt in use by it's number
|
||||
enableInterrupt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------ //
|
||||
void SPIClass::setBitOrder(uint8_t bitOrder)
|
||||
{
|
||||
currentDataOrder = bitOrder;
|
||||
}
|
||||
|
||||
void SPIClass::setDataMode(uint8_t dataMode)
|
||||
{
|
||||
uint32_t config = hspi.Instance->CONFIG;
|
||||
HAL_SPI_Disable(&hspi);
|
||||
hspi.Init.CLKPhase = dataMode & 0b00000001;
|
||||
hspi.Init.CLKPolarity = (dataMode & 0b00000010)>>1;
|
||||
config &= ~((1 << SPI_CONFIG_CLK_PH_S) | (1 << SPI_CONFIG_CLK_POL_S)); // clear
|
||||
config |= ((hspi.Init.CLKPhase << SPI_CONFIG_CLK_PH_S) |
|
||||
(hspi.Init.CLKPolarity << SPI_CONFIG_CLK_POL_S)); // set new
|
||||
hspi.Instance->CONFIG = config;
|
||||
HAL_SPI_Enable(&hspi);
|
||||
}
|
||||
|
||||
void SPIClass::setClockDivider(uint8_t clockDiv)
|
||||
{
|
||||
// if divider is in valid range
|
||||
if ((clockDiv >= SPI_CLOCK_DIV4) && (clockDiv <= SPI_CLOCK_DIV256))
|
||||
{
|
||||
uint32_t config = hspi.Instance->CONFIG;
|
||||
HAL_SPI_Disable(&hspi);
|
||||
hspi.Init.BaudRateDiv = clockDiv;
|
||||
config &= ~(0b111 << SPI_CONFIG_BAUD_RATE_DIV_S); // clear
|
||||
config |= (hspi.Init.BaudRateDiv << SPI_CONFIG_BAUD_RATE_DIV_S); // set new
|
||||
hspi.Instance->CONFIG = config;
|
||||
HAL_SPI_Enable(&hspi);
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t reverse_bits(uint8_t byte)
|
||||
{
|
||||
byte = (byte & 0xF0) >> 4 | (byte & 0x0F) << 4;
|
||||
byte = (byte & 0xCC) >> 2 | (byte & 0x33) << 2;
|
||||
byte = (byte & 0xAA) >> 1 | (byte & 0x55) << 1;
|
||||
return byte;
|
||||
}
|
||||
Reference in new issue
Block a user