#include "SPI.h" #include "mik32_hal_spi.h" #include "utility/spiElbear.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; } } // ------------------------------------------------------------------ // SPIClass SPI; bool SPIClass::spiInUse = false; uint8_t SPIClass::interruptMode = 0; uint8_t SPIClass::interruptMask = 0; #define PAD_GET_PIN_CONFIG(port, pin) (((PAD_CONFIG->port) & (0b11<<(2*pin))) >> (2*pin)) void SPIClass::begin() { spiElbear_prepareBegin(); 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; // if (direction == 1) // input // GPIO_1->DIRECTION_IN |= (1<DIRECTION_OUT |= (1<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; // GPIO_1->OUTPUT_ &= (~(0b1<OUTPUT_ |= ((state1_4&0b1)< 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) { // ClkPhase ClkPolarity HAL_SPI_Set_Clock_Mode(&hspi, (dataMode&0b00000001), (dataMode&0b00000010)>>1); } void SPIClass::setClockDivider(uint8_t clockDiv) { // 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)) { HAL_SPI_Set_Clock_Divider(&hspi, clockDiv); } else ErrorMsgHandler("SPI.setClockDivider(): Invalid clock devider"); } 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; }