#include "SPI.h" #include "mik32_hal_spi.h" SPI_HandleTypeDef hspi; bool newConfig = false; bool isInited = false; uint32_t currentSpeed = 0; int8_t currentDataOrder = MSBFIRST; 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 params in struct hspi.Init.CLKPhase = dataMode & 0b00000001; hspi.Init.CLKPolarity = (dataMode & 0b00000010)>>1; hspi.Init.BaudRateDiv = divRegVal; currentSpeed = speedMaximum; currentDataOrder = dataOrder; currentDataMode = dataMode; newConfig = true; } } // ------------------------------------------------------------------ // SPIClass SPI; bool SPIClass::spiInUse = false; uint8_t SPIClass::interruptMode = 0; uint8_t SPIClass::interruptMask = 0; void SPIClass::begin() { spi_onBegin(); // set constant parameters in spi struct hspi.Instance = SPI_1; hspi.Init.SPI_Mode = HAL_SPI_MODE_MASTER; // only master mode used hspi.Init.ThresholdTX = 4; hspi.Init.Decoder = SPI_DECODER_NONE; hspi.Init.ManualCS = SPI_MANUALCS_ON; hspi.Init.ChipSelect = SPI_CS_NONE; // adjustable parameters default values as in SPISettings() hspi.Init.BaudRateDiv = SPI_CLOCK_DIV8; hspi.Init.CLKPhase = SPI_MODE0 & 0b00000001; hspi.Init.CLKPolarity = (SPI_MODE0 & 0b00000010)>>1; 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); } spi_onEnd(); 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< 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) { if (spiInUse) currentDataOrder = bitOrder; else ErrorMsgHandler("SPI.setBitOrder():SPI.begin() need to be called first"); } void SPIClass::setDataMode(uint8_t dataMode) { if (spiInUse) { hspi.Init.CLKPhase = (dataMode&0b00000001); hspi.Init.CLKPolarity = (dataMode&0b00000010)>>1; HAL_SPI_Set_Clock_Mode(&hspi); currentDataMode = dataMode; } else ErrorMsgHandler("SPI.setDataMode():SPI.begin() need to be called first"); } void SPIClass::setClockDivider(uint8_t clockDiv) { if (spiInUse) { // if divider is valid if ((clockDiv == SPI_CLOCK_DIV4) || (clockDiv == SPI_CLOCK_DIV8) || (clockDiv == SPI_CLOCK_DIV16) || (clockDiv == SPI_CLOCK_DIV32) || (clockDiv == SPI_CLOCK_DIV64) || (clockDiv == SPI_CLOCK_DIV128) || (clockDiv == SPI_CLOCK_DIV256)) { hspi.Init.BaudRateDiv = clockDiv; currentSpeed = F_CPU >> (clockDiv+1); HAL_SPI_Set_Clock_Divider(&hspi); } else ErrorMsgHandler("SPI.setClockDivider(): Invalid clock devider"); } else ErrorMsgHandler("SPI.setClockDivider():SPI.begin() need to be called first"); } 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; }