/* Software Uart For Stm32 By Liyanboy74 https://github.com/liyanboy74 */ #include "softuart.h" // Some internal define #if (SoftUart_PARITY) #define SoftUart_IDEF_LEN_C1 (SoftUart_DATA_LEN + 2) #else #define SoftUart_IDEF_LEN_C1 (SoftUart_DATA_LEN + 1) #endif #define SoftUart_IDEF_LEN_C2 (SoftUart_IDEF_LEN_C1 + SoftUart_STOP_Bit) // All Soft Uart Config and State SoftUart_S SUart; // TX RX Data Buffer SoftUartBuffer_S SUBuffer; // For timing division uint8_t SU_Timer = 0; // Parity var static uint8_t DV, PCount; // Initial Soft Uart SoftUart_S *SoftUartInit() { SUart.TxNComplated = 0; SUart.RxBitCounter = 0; SUart.RxBitShift = 0; SUart.RxIndex = 0; SUart.TxEnable = 0; SUart.RxEnable = 0; SUart.TxBitCounter = 0; SUart.TxBitShift = 0; SUart.TxIndex = 0; SUart.TxSize = 0; SUart.Buffer = &SUBuffer; SUart.RxTimingFlag = 0; SUart.RxBitOffset = 0; return &SUart; } // Send one bit to TX pin void SoftUartTransmitBit(SoftUart_S *SU, uint8_t Bit0_1) { SU->TxPinValue = Bit0_1; } // Enable Soft Uart Receiving SoftUartState_E SoftUartEnableRx() { SUart.RxEnable = 1; return SoftUart_OK; } // Disable Soft Uart Receiving SoftUartState_E SoftUartDisableRx() { SUart.RxEnable = 0; return SoftUart_OK; } // Read Size of Received Data in buffer uint8_t SoftUartRxAlavailable() { return SUart.RxIndex; } // Move Received Data to Another Buffer SoftUartState_E SoftUartReadRxBuffer(uint8_t *Buffer, uint8_t Len) { int i; for (i = 0; i < Len; i++) { Buffer[i] = SUart.Buffer->Rx[i]; } for (i = 0; i < SUart.RxIndex; i++) { SUart.Buffer->Rx[i] = SUart.Buffer->Rx[i + Len]; } SUart.RxIndex -= Len; return SoftUart_OK; } // Soft Uart Transmit Data Process void SoftUartTxProcess(SoftUart_S *SU) { if (SU->TxEnable) { // Start if (SU->TxBitCounter == 0) { SU->TxNComplated = 1; SU->TxBitShift = 0; SoftUartTransmitBit(SU, 0); SU->TxBitCounter++; PCount = 0; } // Data else if (SU->TxBitCounter < (SoftUart_DATA_LEN + 1)) { DV = ((SU->Buffer->Tx[SU->TxIndex]) >> (SU->TxBitShift)) & 0x01; SoftUartTransmitBit(SU, DV); SU->TxBitCounter++; SU->TxBitShift++; if (DV) PCount++; } // Parity else if (SU->TxBitCounter < SoftUart_IDEF_LEN_C1) { // Check Even or Odd DV = PCount % 2; // if Odd Parity if (SoftUart_PARITY == 1) DV = !DV; SoftUartTransmitBit(SU, DV); SU->TxBitCounter++; } // Stop else if (SU->TxBitCounter < SoftUart_IDEF_LEN_C2) { SoftUartTransmitBit(SU, 1); SU->TxBitCounter++; } // Complete else if (SU->TxBitCounter == SoftUart_IDEF_LEN_C2) { // Reset Bit Counter SU->TxBitCounter = 0; // Ready To Send Another Data SU->TxIndex++; // Check Size of Data if (SU->TxSize > SU->TxIndex) { // Continue Sending SU->TxNComplated = 1; SU->TxEnable = 1; } else { // Finish SU->TxNComplated = 0; SU->TxEnable = 0; } } } } // Soft Uart Receive Data Process void SoftUartRxDataBitProcess(SoftUart_S *SU, uint8_t B0_1) { if (SU->RxEnable) { // Start if (SU->RxBitCounter == 0) { // Start Bit is 0 if (B0_1) return; SU->RxBitShift = 0; SU->RxBitCounter++; SU->Buffer->Rx[SU->RxIndex] = 0; } // Data else if (SU->RxBitCounter < (SoftUart_DATA_LEN + 1)) { SU->Buffer->Rx[SU->RxIndex] |= ((B0_1 & 0x01) << SU->RxBitShift); SU->RxBitCounter++; SU->RxBitShift++; } // Parity else if (SU->RxBitCounter < SoftUart_IDEF_LEN_C1) { // Need to be check // B0_1; SU->RxBitCounter++; } // Stop & Complete else if (SU->RxBitCounter < SoftUart_IDEF_LEN_C2) { SU->RxBitCounter = 0; SU->RxTimingFlag = 0; // Stop Bit must be 1 if (B0_1) { // Received successfully // Change RX Buffer Index if ((SU->RxIndex) < (SoftUartRxBufferSize - 1)) (SU->RxIndex)++; } // if not : ERROR -> Overwrite data } } } // Wait Until Transmit Completed // You do not usually need to use this function! void SoftUartWaitUntilTxComplate() { while (SUart.TxNComplated); } // Copy Data to Transmit Buffer and Start Sending SoftUartState_E SoftUartPuts(uint8_t *Data, uint8_t Len) { int i; if (SUart.TxNComplated) return SoftUart_Error; SUart.TxIndex = 0; SUart.TxSize = Len; for (i = 0; i < Len; i++) { SUart.Buffer->Tx[i] = Data[i]; } SUart.TxNComplated = 1; SUart.TxEnable = 1; return SoftUart_OK; } // Capture RX and Get BitOffset uint8_t SoftUartScanRxPorts(SoftUart_S *SU) { uint8_t Buffer = 0x00, Bit; // Read RX GPIO Value Bit = SU->RxPinValue; // Starting conditions if (!SUart.RxBitCounter && !SUart.RxTimingFlag && !Bit) { // Save RX Bit Offset // Calculate middle position of data puls SUart.RxBitOffset = ((SU_Timer + 2) % 5); // Timing Offset is Set SUart.RxTimingFlag = 1; } // Add all RX GPIO State to Buffer Buffer |= (Bit & 0x01); return Buffer; } // SoftUartHandler must call in interrupt every 0.2*(1/BR) // if BR=9600 then 0.2*(1/9600)=20.8333333 uS void SoftUartHandler(void) { uint8_t SU_DBuffer; // Capture RX and Get BitOffset SU_DBuffer = SoftUartScanRxPorts(&SUart); // Receive Data if we in middle data pulse position if (SUart.RxBitOffset == SU_Timer) { SoftUartRxDataBitProcess(&SUart, (SU_DBuffer & 0x01)); } // Sending always happens in the first time slot if (SU_Timer == 0) { // Transmit Data SoftUartTxProcess(&SUart); } // Timing process SU_Timer++; if (SU_Timer >= 5) SU_Timer = 0; }