commit 9924e704dbf1dade6238b81ae49980d585b45b58 Author: abody Date: Fri Nov 8 11:47:49 2019 +0100 Reorganizing project diff --git a/component.mk b/component.mk new file mode 100644 index 0000000..28874d8 --- /dev/null +++ b/component.mk @@ -0,0 +1,11 @@ +#encoder +SELF_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) +REL_DIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST)))) +ifeq ($(MKDBG), 1) + $(info >>> $(REL_DIR)/component.mk) +endif +$(eval C_INCLUDES += -I$(REL_DIR)/inc) +$(eval CXX_SOURCES += $(wildcard $(REL_DIR)/src/*.cpp)) +ifeq ($(MKDBG), 1) + $(info <<<) +endif diff --git a/inc/f4ll b/inc/f4ll new file mode 120000 index 0000000..945c9b4 --- /dev/null +++ b/inc/f4ll @@ -0,0 +1 @@ +. \ No newline at end of file diff --git a/inc/ll_consolehandler.h b/inc/ll_consolehandler.h new file mode 100644 index 0000000..182f115 --- /dev/null +++ b/inc/ll_consolehandler.h @@ -0,0 +1,43 @@ +/* + * ll_consolehandler.h + * + * Created on: Nov 7, 2019 + * Author: abody + */ + +#ifndef LL_CONSOLEHANDLER_H_ +#define LL_CONSOLEHANDLER_H_ + +#include "f4ll/ll_hsusart.h" +#include "singleton.h" + + +namespace f4ll { + +class LL_ConsoleHandler: public LL_UsartCore, public Singleton +{ + friend class Singleton; + +public: + // LL_UsartCore pure virtual function implementations + virtual void ReceiverIdle(void); + virtual void TransmissionComplete(void); + virtual void RxDmaTransferComplete(void); + virtual void RxDmaHalfTransfer(void); + virtual void RxDmaError(LL_DmaHelper::DmaErrorType reason); + virtual void TxDmaTransferComplete(void); + virtual void TxDmaHalfTransfer(void); + virtual void TxDmaError(LL_DmaHelper::DmaErrorType reason); + + void PrintStats(uint8_t id, LL_HsUsart &usart); + +private: + LL_ConsoleHandler(USART_TypeDef *usart, DMA_TypeDef *dma, uint32_t streamRx, uint32_t streamTx); + + char m_buffer[128]; + uint16_t m_used = 0; +}; + +} /* namespace f4ll */ + +#endif /* LL_CONSOLEHANDLER_H_ */ diff --git a/inc/ll_crchandler.h b/inc/ll_crchandler.h new file mode 100644 index 0000000..d8fd54f --- /dev/null +++ b/inc/ll_crchandler.h @@ -0,0 +1,89 @@ +/* + * ll_crchandler.h + * + * Created on: Oct 26, 2019 + * Author: compi + */ + +#ifndef LL_CRCHANDLER_H_ +#define LL_CRCHANDLER_H_ +#include +#include +#include "f4ll/ll_dmahelper.h" +#include "singleton.h" + +extern "C" void _HandleCrcDmaIrq(void); + +namespace f4ll { + +class LL_CrcHandler : public Singleton +{ + friend class Singleton; + +public: + struct ICallback + { + virtual void CrcSucceeded(uintptr_t callbackParam, uint32_t crc, int prio) = 0; + virtual void CrcFailed(uintptr_t callbackParam, uint32_t crc, int prio) = 0; + }; + + class SlotBase + { + friend class LL_CrcHandler; + public: + struct CrcTask { + void const * volatile m_address; // changed to nullptr when execution starts + uint16_t volatile m_wordCount; + LL_CrcHandler::ICallback *m_callback; + uintptr_t m_callbackParam; + }; + + private: + SlotBase *m_next = nullptr; + uint8_t m_taskCount; + virtual CrcTask& operator[](int index) = 0; + + protected: + SlotBase(unsigned int taskCount) : m_taskCount(taskCount) {} + SlotBase() = delete; + SlotBase(SlotBase const &other) = delete; + }; + + // DON't try this at home! we "extend" LL_CrcHandler::m_tasks this way + template class Slot : public SlotBase + { + public: + Slot() : SlotBase(n) {} + virtual CrcTask& operator[](int index) { return m_tasks[index]; } + + private: + Slot::CrcTask m_tasks[n]; + }; + + void AttachSlot(SlotBase &slot); + bool Enqueue(SlotBase &slot, uint8_t prio, void const *address, uint16_t len, ICallback *cb, uintptr_t cbParam); + uint32_t Compute(SlotBase &slot, uint8_t prio, void const *address, uint16_t len); + + bool IsActive(SlotBase &slot, uint8_t prio) const; + bool IsQueued(SlotBase &slot, uint8_t prio) const; + bool IsRunning(SlotBase &slot, uint8_t prio) const; + + void DmaTransferCompleted(void); + +private: + LL_CrcHandler(DMA_TypeDef *dma, uint32_t stream); + + friend void ::_HandleCrcDmaIrq(void); + void StartNextTask(void); + void WaitResults(SlotBase &slot, uint8_t prio) const; + + LL_DmaHelper m_dma; + SlotBase * volatile m_firstSlot = nullptr; + SlotBase * volatile m_activeSlot = nullptr; + int volatile m_activePrio; +}; + + +} // namespace f4ll + +#endif /* LL_CRCHANDLER_H_ */ diff --git a/inc/ll_dmahelper.h b/inc/ll_dmahelper.h new file mode 100644 index 0000000..345ad64 --- /dev/null +++ b/inc/ll_dmahelper.h @@ -0,0 +1,58 @@ +/* + * ll_dmahelper.h + * + * Created on: Oct 25, 2019 + * Author: abody + */ + +#ifndef LL_DMAHELPER_H_ +#define LL_DMAHELPER_H_ + +#include +#include + +namespace f4ll { + +class LL_DmaHelper { +public: + LL_DmaHelper(DMA_TypeDef *dma, uint32_t stream); + LL_DmaHelper(LL_DmaHelper const &base) = default; + + inline DMA_TypeDef* GetDma() const { return m_dma; } + inline uint32_t GetStream() const { return m_stream; } + inline volatile uint32_t* GetIsReg() const { return m_isReg; } + inline volatile uint32_t* GetIfcReg() const { return m_ifcReg; } + inline uint32_t GetFeMask() const { return m_FEMasks[m_stream]; } + inline uint32_t GetDmeMask() const { return m_DMEMasks[m_stream]; } + inline uint32_t GetTeMask() const { return m_TEMasks[m_stream]; } + inline uint32_t GetHtMask() const { return m_HTMasks[m_stream]; } + inline uint32_t GetTcMask() const { return m_TCMasks[m_stream]; } + + inline bool IsEnabledIt_HT() { return LL_DMA_IsEnabledIT_HT(m_dma, m_stream) != 0; } + inline bool IsEnabledIt_TE() { return LL_DMA_IsEnabledIT_TE(m_dma, m_stream) != 0; } + inline bool IsEnabledIt_TC() { return LL_DMA_IsEnabledIT_TC(m_dma, m_stream) != 0; } + inline bool IsEnabledIt_DME() { return LL_DMA_IsEnabledIT_DME(m_dma, m_stream) != 0; } + inline bool IsEnabledIt_FE() { return LL_DMA_IsEnabledIT_FE(m_dma, m_stream) != 0; } + + enum class DmaErrorType { + Transfer, + DirectMode, + Fifo + }; + +private: + DMA_TypeDef *m_dma; + uint32_t m_stream; + volatile uint32_t *m_isReg; + volatile uint32_t *m_ifcReg; + + static const uint32_t m_FEMasks[8]; + static const uint32_t m_DMEMasks[8]; + static const uint32_t m_TEMasks[8]; + static const uint32_t m_HTMasks[8]; + static const uint32_t m_TCMasks[8]; +}; + +} /* namespace f4ll */ + +#endif /* LL_DMAHELPER_H_ */ diff --git a/inc/ll_hsusart.h b/inc/ll_hsusart.h new file mode 100644 index 0000000..4af8b75 --- /dev/null +++ b/inc/ll_hsusart.h @@ -0,0 +1,111 @@ +/* + * ll_HsUsart.h + * + * Created on: Oct 29, 2019 + * Author: abody + */ + +#ifndef LL_HSUSART_H_ +#define LL_HSUSART_H_ +#include +#include "f4ll/ll_usartcore.h" +#include "f4ll/ll_crchandler.h" + +namespace f4ll { + +struct DMAINFO; + +class LL_HsUsart : public LL_CrcHandler::ICallback, public LL_UsartCore +{ +public: + LL_HsUsart(USART_TypeDef *usart, DMA_TypeDef *dma, uint32_t stream_rx, uint32_t stream_tx); + + struct PacketHeader { // !!! size should be multiple of 4 !!! + uint8_t startByte; + uint8_t serial; + uint8_t payloadLength; + uint8_t hash; + }; + + struct Packet { + PacketHeader header; + uint8_t payload[256+sizeof(uint32_t)]; // extra room for crc32 + } __attribute__((aligned)); + + struct Stats { + uint32_t overrun = 0; + uint32_t hdrError = 0; + uint32_t payloadErrror = 0; + uint32_t pep1 = 0; + uint32_t pep2 = 0; + uint32_t rxDmaError = 0; + uint32_t txDmaError = 0; + uint32_t rcvd = 0; + uint32_t premature_hdr = 0; + uint32_t premature_payload = 0; + uint32_t sent = 0; + uint32_t skiped = 0; + }; + + struct IHsUsartCallback { + virtual bool PacketReceived(LL_HsUsart *caller, uintptr_t userParam, Packet const &packet) = 0; + }; + + // LL_CRCHandler::ICallback interface functions + virtual void CrcSucceeded(uintptr_t callbackParam, uint32_t crc, int prio); + virtual void CrcFailed(uintptr_t callbackParam, uint32_t crc, int prio); + + // LL_UsartCore pure virtual function implementations + virtual void ReceiverIdle(void); + virtual void TransmissionComplete(void); + virtual void RxDmaTransferComplete(void); + virtual void RxDmaHalfTransfer(void); + virtual void RxDmaError(LL_DmaHelper::DmaErrorType reason); + virtual void TxDmaTransferComplete(void); + virtual void TxDmaHalfTransfer(void); + virtual void TxDmaError(LL_DmaHelper::DmaErrorType reason); + + void PostPacket(uint8_t const *payload, uint8_t length, bool waitForCrcQueue = true); + void SetupReceive(void); + + void RxProcessed(bool second); + uint8_t* GetTxPacketBuffer(void); + USART_TypeDef* GetUsart(void); + Stats const & GetStats(void); + bool IsTxBusy(void); + bool IsTxFailed(void); + bool IsRxBusy(bool second); + bool IsRxFailed(bool second); + + void SetCallback(IHsUsartCallback* callback, uintptr_t callbackParam); + +private: + void BuildHeader(Packet &packet, uint8_t serialNo, uint8_t length); + bool CheckHeader(PacketHeader &header); + void SwitchRxBuffers(void); + + struct Buffer { + Packet packet; + //transfer area ends here + volatile bool busy = 0; + volatile bool error = 0; + uint16_t requestedLength = 0; + uint32_t errorInfo = 0; + }; + + static const uint8_t STARTMARKER = 0x95; + + uint8_t m_rxSerialNo = -1; + uint8_t m_txSerialNo = -1; + Stats m_stats; + bool m_rxBufferSelector = false; + + LL_CrcHandler::Slot<2> m_crcSlot; + IHsUsartCallback *m_userCallback = nullptr; + uintptr_t m_userCallbackParam = 0; + Buffer m_txBuffer; + Buffer m_rxBuffers[2]; +}; + +} +#endif /* LL_HSUSART_H_ */ diff --git a/inc/ll_memcpydma.h b/inc/ll_memcpydma.h new file mode 100644 index 0000000..05c725c --- /dev/null +++ b/inc/ll_memcpydma.h @@ -0,0 +1,28 @@ +/* + * llmemcpydma.h + * + * Created on: Nov 4, 2019 + * Author: abody + */ + +#ifndef LL_MEMCPY_DMA_H_ +#define LL_MEMCPY_DMA_H_ +#include "f4ll/ll_dmahelper.h" +#include "singleton.h" + +namespace f4ll { + +class LL_MemcpyDma : public Singleton, private LL_DmaHelper +{ + friend class Singleton; +public: + void* Copy(void *dst, void const *src, uint16_t length); + void DmaTransferCompleted(); +private: + LL_MemcpyDma(DMA_TypeDef *dma, uint32_t stream); + bool volatile m_busy = false; +}; + +} /* namespace f4ll */ + +#endif /* LL_MEMCPY_DMA_H_ */ diff --git a/inc/ll_usartcore.h b/inc/ll_usartcore.h new file mode 100644 index 0000000..86bf92d --- /dev/null +++ b/inc/ll_usartcore.h @@ -0,0 +1,51 @@ +/* + * ll_dmadrivenusartcore.h + * + * Created on: Nov 4, 2019 + * Author: abody + */ + +#ifndef LL_USARTCORE_H_ +#define LL_USARTCORE_H_ +#include + +#include "f4ll/ll_dmahelper.h" + +namespace f4ll { + +class LL_UsartCore +{ +public: + static inline void HandleUsartIrq(LL_UsartCore *_this) { _this->UsartIsr(); } + static inline void HandleRxDmaIrq(LL_UsartCore *_this) { _this->RxDmaIsr(); } + static inline void HandleTxDmaIrq(LL_UsartCore *_this) { _this->TxDmaIsr(); } + +protected: + LL_UsartCore(USART_TypeDef *usart, DMA_TypeDef *dma, uint32_t streamRx, uint32_t streamTx); + + virtual void ReceiverIdle() = 0; + virtual void TransmissionComplete() = 0; + + virtual void RxDmaTransferComplete() = 0; + virtual void RxDmaHalfTransfer() = 0; + virtual void RxDmaError(LL_DmaHelper::DmaErrorType reason) = 0; + + virtual void TxDmaTransferComplete() = 0; + virtual void TxDmaHalfTransfer() = 0; + virtual void TxDmaError(LL_DmaHelper::DmaErrorType reason) = 0; + + void SetupTransmit(void const *buffer, uint16_t length); + void SetupReceive(void *buffer, uint16_t length); + + void UsartIsr(); + void RxDmaIsr(); + void TxDmaIsr(); + + USART_TypeDef *m_usart; + LL_DmaHelper m_rxDma; + LL_DmaHelper m_txDma; +}; + +} /* namespace f4ll */ + +#endif /* LL_USARTCORE_H_ */ diff --git a/src/ll_consolehandler.cpp b/src/ll_consolehandler.cpp new file mode 100644 index 0000000..2eee20a --- /dev/null +++ b/src/ll_consolehandler.cpp @@ -0,0 +1,65 @@ +/* + * ll_consolehandler.cpp + * + * Created on: Nov 7, 2019 + * Author: abody + */ + +#include "f4ll/ll_consolehandler.h" +#include + +namespace f4ll { + +LL_ConsoleHandler::LL_ConsoleHandler(USART_TypeDef *usart, DMA_TypeDef *dma, uint32_t streamRx, uint32_t streamTx) +: LL_UsartCore(usart, dma, streamRx, streamTx) +{ +} + +void LL_ConsoleHandler::ReceiverIdle(void) {} +void LL_ConsoleHandler::TransmissionComplete(void) {} +void LL_ConsoleHandler::RxDmaTransferComplete(void) {} +void LL_ConsoleHandler::RxDmaHalfTransfer(void) {} +void LL_ConsoleHandler::RxDmaError(LL_DmaHelper::DmaErrorType reason) {} +void LL_ConsoleHandler::TxDmaTransferComplete(void) +{ + LL_USART_EnableIT_TC(m_usart); + LL_DMA_DisableStream(m_txDma.GetDma(), m_txDma.GetStream()); +} +void LL_ConsoleHandler::TxDmaHalfTransfer(void) {} +void LL_ConsoleHandler::TxDmaError(LL_DmaHelper::DmaErrorType reason) {} + + +#define ADDINFO(b,s,u) \ + b += strcpy_ex(b,s); \ + b += uitodec(b,u); + +void LL_ConsoleHandler::PrintStats(uint8_t id, LL_HsUsart &usart) +{ + char ids[] = " : "; + char *buffer = m_buffer; + LL_HsUsart::Stats const &stats(usart.GetStats()); + + ids[0] = id + '0'; + buffer += strcpy_ex(buffer, ids); + ADDINFO(buffer, " s: ", stats.sent); + ADDINFO(buffer, " r: ", stats.rcvd); + ADDINFO(buffer, " sk: ", stats.skiped); + ADDINFO(buffer, " or: ", stats.overrun); + ADDINFO(buffer, " he: ", stats.hdrError); + ADDINFO(buffer, " pe: ", stats.payloadErrror); + buffer += strcpy_ex(buffer,",0x"); + buffer += uitohex(buffer, stats.pep1, 8); + buffer += strcpy_ex(buffer,",0x"); + buffer += uitohex(buffer, stats.pep2, 8); + ADDINFO(buffer, " rde: ", stats.rxDmaError); + ADDINFO(buffer, " tde: ", stats.txDmaError); + ADDINFO(buffer, " pmh: ", stats.premature_hdr); + ADDINFO(buffer, " pmp: ", stats.premature_payload); + buffer += strcpy_ex(buffer, "\r\n"); + + SetupTransmit(m_buffer, buffer - m_buffer + 1); +} + + +} /* namespace f4ll */ + diff --git a/src/ll_crchandler.cpp b/src/ll_crchandler.cpp new file mode 100644 index 0000000..c0307ce --- /dev/null +++ b/src/ll_crchandler.cpp @@ -0,0 +1,156 @@ +/* + * ll_crchandler.cpp + * + * Created on: Oct 26, 2019 + * Author: compi + */ +#include "f4ll/ll_crchandler.h" + +namespace f4ll { + +LL_CrcHandler::LL_CrcHandler(DMA_TypeDef *dma, uint32_t stream) +: m_dma(dma, stream) +{ + LL_DMA_EnableIT_TC(dma, stream); + LL_DMA_EnableIT_TE(dma, stream); + LL_DMA_SetM2MDstAddress(dma, stream, (uint32_t)&CRC->DR); +} + + +void LL_CrcHandler::AttachSlot(SlotBase &slot) +{ + for(unsigned int i = 0; i < slot.m_taskCount; ++i ) { + auto &task(slot[i]); + task.m_address = nullptr; + task.m_wordCount = 0; + task.m_callback = nullptr; + task.m_callbackParam = 0; + } + slot.m_next = m_firstSlot; + uint32_t prim = __get_PRIMASK(); + __disable_irq(); + m_firstSlot = &slot; + __set_PRIMASK(prim); +} + + +bool LL_CrcHandler::Enqueue(SlotBase &slot, uint8_t prio, void const *address, uint16_t len, ICallback *cb, uintptr_t cbParam) +{ + uint32_t prim = __get_PRIMASK(); + bool immediate; + + // TODO: do we need sanity check here? (is slot attached, is prio in range, etc...?) + + while(IsActive(slot,prio)); + __disable_irq(); + immediate = m_activeSlot == nullptr; + slot[prio].m_address = (!immediate) ? address : nullptr; + slot[prio].m_wordCount = (len+3)/4; + slot[prio].m_callback = cb; + slot[prio].m_callbackParam = cbParam; + if(immediate) { + m_activeSlot = &slot; + m_activePrio = prio; + } + __set_PRIMASK(prim); + + if(immediate) { + CRC->CR = 1; + LL_DMA_SetM2MSrcAddress(m_dma.GetDma(), m_dma.GetStream(), (uint32_t)address); + LL_DMA_SetDataLength(m_dma.GetDma(), m_dma.GetStream(), (len+3)/4); + LL_DMA_EnableStream(m_dma.GetDma(), m_dma.GetStream()); + } + return immediate; +} + +bool LL_CrcHandler::IsActive(SlotBase &slot, uint8_t prio) const +{ + return prio < slot.m_taskCount && slot[prio].m_wordCount != 0; +} + +bool LL_CrcHandler::IsQueued(SlotBase &slot, uint8_t prio) const +{ + return prio < slot.m_taskCount && slot[prio].m_address != nullptr; +} + +bool LL_CrcHandler::IsRunning(SlotBase &slot, uint8_t prio) const +{ + return prio < slot.m_taskCount && slot[prio].m_wordCount && ! slot[prio].m_address; +} + +void LL_CrcHandler::DmaTransferCompleted(void) +{ + if(* m_dma.GetIsReg() & m_dma.GetTcMask()) { // DMA transfer complete + * m_dma.GetIfcReg() = m_dma.GetTcMask(); + LL_DMA_DisableStream(m_dma.GetDma(), m_dma.GetStream()); + if(m_activeSlot) { + if((*m_activeSlot)[m_activePrio].m_callback) + (*m_activeSlot)[m_activePrio].m_callback->CrcSucceeded((*m_activeSlot)[m_activePrio].m_callbackParam, CRC->DR, m_activePrio); + else if((*m_activeSlot)[m_activePrio].m_callbackParam) + *reinterpret_cast((*m_activeSlot)[m_activePrio].m_callbackParam) = CRC->DR; + } + } + else if(*m_dma.GetIsReg() & m_dma.GetTeMask()) { // DMA transfer error + *m_dma.GetIfcReg() = m_dma.GetTeMask(); + LL_DMA_DisableStream(m_dma.GetDma(), m_dma.GetStream()); + if(m_activeSlot) { + if((*m_activeSlot)[m_activePrio].m_callback) + (*m_activeSlot)[m_activePrio].m_callback->CrcFailed((*m_activeSlot)[m_activePrio].m_callbackParam, CRC->DR, m_activePrio); + else if((*m_activeSlot)[m_activePrio].m_callbackParam) + *reinterpret_cast((*m_activeSlot)[m_activePrio].m_callbackParam) = -1; + } + } + (*m_activeSlot)[m_activePrio].m_callback = nullptr; + (*m_activeSlot)[m_activePrio].m_callbackParam = 0; + (*m_activeSlot)[m_activePrio].m_wordCount = 0; + StartNextTask(); +} + + +void LL_CrcHandler::StartNextTask(void) +{ + bool stillMore; + int index = 0; + do { + SlotBase *slot = m_firstSlot; + stillMore = false; + while(slot) { + if(index < slot->m_taskCount) { + if((*slot)[index].m_address) { + m_activeSlot = slot; + m_activePrio = index; + CRC->CR = 1; + LL_DMA_SetM2MSrcAddress(m_dma.GetDma(), m_dma.GetStream(), reinterpret_cast((*slot)[index].m_address)); + LL_DMA_SetDataLength(m_dma.GetDma(), m_dma.GetStream(), (*slot)[index].m_wordCount); + LL_DMA_EnableStream(m_dma.GetDma(), m_dma.GetStream()); + (*slot)[index].m_address = nullptr; // marking as started + return; + } + if(index + 1 < slot->m_taskCount) + stillMore = true; + } + slot = slot->m_next; + } + ++index; + } while(stillMore); + m_activeSlot = nullptr; +} + + +void LL_CrcHandler::WaitResults(SlotBase &slot, uint8_t prio) const +{ + while(IsQueued(slot, prio)); + while(IsActive(slot, prio)); +} + + +uint32_t LL_CrcHandler::Compute( + SlotBase &slot, uint8_t prio, void const *address, uint16_t len) +{ + uint32_t result; + Enqueue(slot, prio, address, len, nullptr, reinterpret_cast(&result)); + while(IsActive(slot, prio)); + return result; +} + +} // namespace f4ll diff --git a/src/ll_dmahelper.cpp b/src/ll_dmahelper.cpp new file mode 100644 index 0000000..6ee1a98 --- /dev/null +++ b/src/ll_dmahelper.cpp @@ -0,0 +1,26 @@ +/* +q * ll_dmahelper.cpp + * + * Created on: Oct 25, 2019 + * Author: abody + */ + +#include "f4ll/ll_dmahelper.h" + +namespace f4ll { + +const uint32_t LL_DmaHelper::m_FEMasks[8] = {DMA_LISR_FEIF0, DMA_LISR_FEIF1, DMA_LISR_FEIF2, DMA_LISR_FEIF3, DMA_HISR_FEIF4, DMA_HISR_FEIF5, DMA_HISR_FEIF6, DMA_HISR_FEIF7}; +const uint32_t LL_DmaHelper::m_DMEMasks[8] = {DMA_LISR_DMEIF0, DMA_LISR_DMEIF1, DMA_LISR_DMEIF2, DMA_LISR_DMEIF3, DMA_HISR_DMEIF4, DMA_HISR_DMEIF5, DMA_HISR_DMEIF6, DMA_HISR_DMEIF7}; +const uint32_t LL_DmaHelper::m_TEMasks[8] = {DMA_LISR_TEIF0, DMA_LISR_TEIF1, DMA_LISR_TEIF2, DMA_LISR_TEIF3, DMA_HISR_TEIF4, DMA_HISR_TEIF5, DMA_HISR_TEIF6, DMA_HISR_TEIF7}; +const uint32_t LL_DmaHelper::m_HTMasks[8] = {DMA_LISR_HTIF0, DMA_LISR_HTIF1, DMA_LISR_HTIF2, DMA_LISR_HTIF3, DMA_HISR_HTIF4, DMA_HISR_HTIF5, DMA_HISR_HTIF6, DMA_HISR_HTIF7}; +const uint32_t LL_DmaHelper::m_TCMasks[8] = {DMA_LISR_TCIF0, DMA_LISR_TCIF1, DMA_LISR_TCIF2, DMA_LISR_TCIF3, DMA_HISR_TCIF4, DMA_HISR_TCIF5, DMA_HISR_TCIF6, DMA_HISR_TCIF7}; + +LL_DmaHelper::LL_DmaHelper(DMA_TypeDef *dma, uint32_t stream) +: m_dma(dma) +, m_stream(stream) +, m_isReg((dma == DMA1) ? ((m_stream < LL_DMA_STREAM_4) ? &DMA1->LISR : &DMA1->HISR) : ((m_stream < LL_DMA_STREAM_4) ? &DMA2->LISR : &DMA2->HISR)) +, m_ifcReg((dma == DMA1) ? ((m_stream < LL_DMA_STREAM_4) ? &DMA1->LIFCR : &DMA1->HIFCR) : ((m_stream < LL_DMA_STREAM_4) ? &DMA2->LIFCR : &DMA2->HIFCR)) +{ +} + +} /* namespace f4ll */ diff --git a/src/ll_hsusart.cpp b/src/ll_hsusart.cpp new file mode 100644 index 0000000..f96a965 --- /dev/null +++ b/src/ll_hsusart.cpp @@ -0,0 +1,237 @@ +/* + * ll_hsusart_impl.h + * + * Created on: Oct 29, 2019 + * Author: abody + */ +#include +#include "f4ll/ll_hsusart.h" + +namespace f4ll { + +template static inline T RoundUpTo4(T input) +{ + return (input + 3) & (((T)-1) - 3); +} + + +LL_HsUsart::LL_HsUsart(USART_TypeDef *usart, DMA_TypeDef *dma, uint32_t streamRx, uint32_t streamTx) +: LL_UsartCore(usart, dma, streamRx, streamTx) +{ + LL_CrcHandler::Instance().AttachSlot(m_crcSlot); +} + + +uint8_t *LL_HsUsart::GetTxPacketBuffer(void) +{ + return m_txBuffer.packet.payload; +} + + +USART_TypeDef* LL_HsUsart::GetUsart(void) +{ + return m_usart; +} + + +LL_HsUsart::Stats const & LL_HsUsart::GetStats(void) +{ + return m_stats; +} + + +bool LL_HsUsart::IsTxBusy() +{ + return m_txBuffer.busy; +} + + +bool LL_HsUsart::IsTxFailed() +{ + return m_txBuffer.error; +} + + +bool LL_HsUsart::IsRxBusy(bool second) +{ + return m_rxBuffers[second].busy; +} + + +bool LL_HsUsart::IsRxFailed(bool second) +{ + return m_rxBuffers[second].error; + +} + +void LL_HsUsart::RxProcessed(bool second) +{ + m_rxBuffers[second].busy = false; + m_rxBuffers[second].error = false; +} + +void LL_HsUsart::SetCallback(IHsUsartCallback *callback, uintptr_t callbackParam) +{ + m_userCallback = callback; + m_userCallbackParam = callbackParam; +} + +void LL_HsUsart::BuildHeader(Packet &packet, uint8_t serialNo, uint8_t length) +{ + uint8_t hash = STARTMARKER; + + packet.header.startByte = STARTMARKER; + packet.header.serial = serialNo; + hash ^= serialNo; + packet.header.payloadLength = length; + hash ^= length; + packet.header.hash = hash; +} + + +bool LL_HsUsart::CheckHeader(PacketHeader &header) +{ + return header.startByte == STARTMARKER && (header.startByte ^ header.serial ^ header.payloadLength) == header.hash; +} + + +void LL_HsUsart::PostPacket(uint8_t const *payload, uint8_t length, bool waitForCrcQueue) +{ + uint16_t payloadLength = RoundUpTo4((uint16_t)length); + + BuildHeader(m_txBuffer.packet, m_txSerialNo++, length); + if(payload) + memcpy(m_txBuffer.packet.payload, payload, length); + m_txBuffer.requestedLength = sizeof(m_txBuffer.packet.header) + payloadLength + sizeof(uint32_t); + m_txBuffer.busy = true; + m_txBuffer.error = false; + + LL_CrcHandler::Instance().Enqueue(m_crcSlot, 0, &m_txBuffer.packet, sizeof(PacketHeader) + payloadLength, + nullptr, reinterpret_cast(m_txBuffer.packet.payload + payloadLength)); + + while(waitForCrcQueue && LL_CrcHandler::Instance().IsQueued(m_crcSlot, 0)); + + SetupTransmit(&m_txBuffer.packet, m_txBuffer.requestedLength); + + ++m_stats.sent; +} + + +void LL_HsUsart::SetupReceive() +{ + m_rxBuffers[m_rxBufferSelector].requestedLength = sizeof(m_rxBuffers[m_rxBufferSelector].packet); + LL_UsartCore::SetupReceive(&m_rxBuffers[m_rxBufferSelector], sizeof(m_rxBuffers[m_rxBufferSelector].packet)); +} + + +void LL_HsUsart::ReceiverIdle(void) +{ + uint16_t rcvdLen = m_rxBuffers[m_rxBufferSelector].requestedLength - LL_DMA_GetDataLength(m_rxDma.GetDma(), m_rxDma.GetStream()); + if(rcvdLen >= sizeof(PacketHeader)) { + if(CheckHeader(m_rxBuffers[m_rxBufferSelector].packet.header)) { + if(rcvdLen >= sizeof(PacketHeader) + + RoundUpTo4((uint16_t)m_rxBuffers[m_rxBufferSelector].packet.header.payloadLength) + + sizeof(uint32_t)) + LL_DMA_DisableStream(m_rxDma.GetDma(), m_rxDma.GetStream()); + else + ++m_stats.premature_payload; + } else { + m_rxBuffers[m_rxBufferSelector].error = 1; + LL_DMA_DisableStream(m_rxDma.GetDma(), m_rxDma.GetStream()); + } + } else + ++m_stats.premature_hdr; +} + + +void LL_HsUsart::TransmissionComplete(void) +{ + LL_USART_DisableDirectionTx(m_usart); // enforcing an idle frame + LL_USART_EnableDirectionTx(m_usart); + m_txBuffer.busy = 0; +} + + +void LL_HsUsart::RxDmaTransferComplete(void) +{ + if(CheckHeader(m_rxBuffers[m_rxBufferSelector].packet.header)) + LL_CrcHandler::Instance().Enqueue(m_crcSlot, 1, + &m_rxBuffers[m_rxBufferSelector].packet, + sizeof(PacketHeader) + RoundUpTo4((uint16_t)m_rxBuffers[m_rxBufferSelector].packet.header.payloadLength), + this, m_rxBufferSelector); + else { + ++m_stats.hdrError; + m_rxBuffers[m_rxBufferSelector].error = true; + } + SwitchRxBuffers(); +} + +void LL_HsUsart::RxDmaHalfTransfer(void) +{ +} + + +void LL_HsUsart::RxDmaError(LL_DmaHelper::DmaErrorType reason) +{ + m_rxBuffers[m_rxBufferSelector].error = 1; + ++m_stats.rxDmaError; + SwitchRxBuffers(); +} + +void LL_HsUsart::TxDmaTransferComplete(void) +{ + LL_USART_EnableIT_TC(m_usart); + LL_DMA_DisableStream(m_txDma.GetDma(), m_txDma.GetStream()); +} + + +void LL_HsUsart::TxDmaHalfTransfer(void) +{ +} + + +void LL_HsUsart::TxDmaError(LL_DmaHelper::DmaErrorType reason) +{ + m_txBuffer.error = 1; + ++m_stats.txDmaError; +} + + +void LL_HsUsart::SwitchRxBuffers(void) +{ + ++m_stats.rcvd; + m_rxBufferSelector = !m_rxBufferSelector; + + if(m_rxBuffers[m_rxBufferSelector].busy) + ++m_stats.overrun; + SetupReceive(); +} + + +void LL_HsUsart::CrcSucceeded(uintptr_t callbackParam, uint32_t crc, int prio) +{ + Buffer &buf(m_rxBuffers[static_cast(callbackParam)]); + + buf.busy = 1; + if(*(uint32_t*) (buf.packet.payload + RoundUpTo4((uint16_t)buf.packet.header.payloadLength)) != crc) { + buf.error = 1; + buf.errorInfo = crc; + ++m_stats.payloadErrror; + } + if(m_userCallback) + buf.busy = !m_userCallback->PacketReceived(this, m_userCallbackParam, buf.packet); +} + + +void LL_HsUsart::CrcFailed(uintptr_t callbackParam, uint32_t crc, int prio) +{ + Buffer &buf(m_rxBuffers[static_cast(callbackParam)]); + buf.busy = buf.error = true; + buf.errorInfo = 0; + ++m_stats.payloadErrror; + if(m_userCallback) + buf.busy = !m_userCallback->PacketReceived(this, m_userCallbackParam, buf.packet); +} + + +} // namespace f4ll diff --git a/src/ll_memcpydma.cpp b/src/ll_memcpydma.cpp new file mode 100644 index 0000000..cbfcb16 --- /dev/null +++ b/src/ll_memcpydma.cpp @@ -0,0 +1,37 @@ +/* + * llmemcpydma.cpp + * + * Created on: Nov 4, 2019 + * Author: abody + */ + +#include "f4ll/ll_memcpydma.h" + +namespace f4ll { + +LL_MemcpyDma::LL_MemcpyDma(DMA_TypeDef *dma, uint32_t stream) +: LL_DmaHelper(dma, stream) +{ + LL_DMA_EnableIT_TC(dma, stream); +} + +void* LL_MemcpyDma::Copy(void *dst, void const *src, uint16_t length) +{ + LL_DMA_SetM2MSrcAddress(GetDma(), GetStream(), (uint32_t)src); + LL_DMA_SetM2MDstAddress(GetDma(), GetStream(), (uint32_t)dst); + LL_DMA_SetDataLength(GetDma(), GetStream(), (length+3)/4 ); + m_busy = 1; + LL_DMA_EnableStream(GetDma(), GetStream()); + while(m_busy); + return dst; +} + +void LL_MemcpyDma::DmaTransferCompleted() +{ + if(*GetIsReg() & GetTcMask()) { // DMA transfer complete + *GetIfcReg() = GetTcMask(); + LL_DMA_DisableStream(GetDma(), GetStream()); + m_busy = 0; + } +} +} /* namespace f4ll */ diff --git a/src/ll_usartcore.cpp b/src/ll_usartcore.cpp new file mode 100644 index 0000000..121c33c --- /dev/null +++ b/src/ll_usartcore.cpp @@ -0,0 +1,116 @@ +/* + * ll_dmadrivenusartcore.cpp + * + * Created on: Nov 4, 2019 + * Author: abody + */ + +#include "f4ll/ll_usartcore.h" + +namespace f4ll { + +LL_UsartCore::LL_UsartCore(USART_TypeDef *usart, DMA_TypeDef *dma, uint32_t streamRx, uint32_t streamTx) +: m_usart(usart) +, m_rxDma(dma, streamRx) +, m_txDma(dma, streamTx) +{ + LL_DMA_EnableIT_TC(dma, streamRx); + LL_DMA_EnableIT_TE(dma, streamRx); + LL_DMA_EnableIT_TC(dma, streamTx); + LL_DMA_EnableIT_TE(dma, streamTx); + LL_USART_EnableIT_IDLE(usart); +} + +void LL_UsartCore::UsartIsr() +{ + if(LL_USART_IsActiveFlag_IDLE(m_usart) && LL_USART_IsEnabledIT_IDLE(m_usart)) { // receiver idle + LL_USART_ClearFlag_IDLE(m_usart); + ReceiverIdle(); + } else if(LL_USART_IsActiveFlag_TC(m_usart) && LL_USART_IsEnabledIT_TC(m_usart)) { // transmission complete + LL_USART_DisableIT_TC(m_usart); + TransmissionComplete(); + } +} + + +void LL_UsartCore::RxDmaIsr() +{ + if(*m_rxDma.GetIsReg() & m_rxDma.GetTcMask()) { + *m_rxDma.GetIfcReg() = m_rxDma.GetTcMask(); + if(m_rxDma.IsEnabledIt_TC()) + RxDmaTransferComplete(); + } + if(*m_rxDma.GetIsReg() & m_rxDma.GetHtMask()) { + *m_rxDma.GetIfcReg() = m_rxDma.GetHtMask(); + if(m_rxDma.IsEnabledIt_HT()) + RxDmaHalfTransfer(); + } + if(*m_rxDma.GetIsReg() & m_rxDma.GetTeMask()) { + *m_rxDma.GetIfcReg() = m_rxDma.GetTeMask(); + if(m_rxDma.IsEnabledIt_TE()) + RxDmaError(LL_DmaHelper::DmaErrorType::Transfer); + } + if(*m_rxDma.GetIsReg() & m_rxDma.GetFeMask()) { + *m_rxDma.GetIfcReg() = m_rxDma.GetFeMask(); + if(m_rxDma.IsEnabledIt_FE()) + RxDmaError(LL_DmaHelper::DmaErrorType::Fifo); + } + if(*m_rxDma.GetIsReg() & m_rxDma.GetDmeMask()) { + *m_rxDma.GetIfcReg() = m_rxDma.GetDmeMask(); + if(m_rxDma.IsEnabledIt_DME()) + RxDmaError(LL_DmaHelper::DmaErrorType::DirectMode); + } +} + + +void LL_UsartCore::TxDmaIsr() +{ + if(*m_txDma.GetIsReg() & m_txDma.GetTcMask()) { // DMA transfer complete + *m_txDma.GetIfcReg() = m_txDma.GetTcMask(); + if(m_txDma.IsEnabledIt_TC()) + TxDmaTransferComplete(); + } + if(*m_txDma.GetIsReg() & m_txDma.GetHtMask()) { + *m_txDma.GetIfcReg() = m_txDma.GetHtMask(); + if(m_txDma.IsEnabledIt_HT()) + TxDmaHalfTransfer(); + } + if(*m_txDma.GetIsReg() & m_txDma.GetTeMask()) { + *m_txDma.GetIfcReg() = m_txDma.GetTeMask(); + if(m_txDma.IsEnabledIt_TE()) + TxDmaError(LL_DmaHelper::DmaErrorType::Transfer); + } + if(*m_txDma.GetIsReg() & m_txDma.GetFeMask()) { + *m_txDma.GetIfcReg() = m_txDma.GetFeMask(); + if(m_txDma.IsEnabledIt_FE()) + TxDmaError(LL_DmaHelper::DmaErrorType::Fifo); + } + if(*m_txDma.GetIsReg() & m_txDma.GetDmeMask()) { + *m_txDma.GetIfcReg() = m_txDma.GetDmeMask(); + if(m_txDma.IsEnabledIt_DME()) + TxDmaError(LL_DmaHelper::DmaErrorType::DirectMode); + } +} + + +void LL_UsartCore::SetupTransmit(void const *buffer, uint16_t length) +{ + LL_DMA_ConfigAddresses(m_txDma.GetDma(), m_txDma.GetStream(), reinterpret_cast(buffer), + LL_USART_DMA_GetRegAddr(m_usart), LL_DMA_DIRECTION_MEMORY_TO_PERIPH); + LL_DMA_SetDataLength(m_txDma.GetDma(), m_txDma.GetStream(), length); + LL_USART_EnableDMAReq_TX(m_usart); + LL_DMA_EnableStream(m_txDma.GetDma(), m_txDma.GetStream()); +} + + +void LL_UsartCore::SetupReceive(void *buffer, uint16_t length) +{ + LL_DMA_ConfigAddresses(m_rxDma.GetDma(), m_rxDma.GetStream(), LL_USART_DMA_GetRegAddr(m_usart), + reinterpret_cast(buffer), LL_DMA_DIRECTION_PERIPH_TO_MEMORY); + LL_DMA_SetDataLength(m_rxDma.GetDma(), m_rxDma.GetStream(), length); + LL_USART_EnableDMAReq_RX(m_usart); + LL_USART_ClearFlag_ORE(m_usart); + LL_DMA_EnableStream(m_rxDma.GetDma(), m_rxDma.GetStream()); +} + +} /* namespace f4ll */